2012年12月23日日曜日

Excel罫線のオートフィルタの問題点

Excel VBA で描いた罫線で オートフィルタ を使ったとき。フィルタ結果の一部に「 本来表示されるべきではない罫線が表示される現象 」が発生していました。

なかなか解決策が見つからず、この対策としては「 フィルタ結果に対して罫線を再描画する 」といった、場当たり的な方法でやり繰りしていたのですが、ようやく解決策が見つかりました。



「 本来表示されるべきではない罫線、が表示される現象 」とは

ここで改めて、この現象の説明をしておきます。下の図は VBA で罫線を描いた表のオートフィルタ前の状態です。表中で LineColor 列の red 行のデータ red を赤い下罫線、 blue 行のデータ blue を青い下罫線で描いています。

つぎに、オートフィルタを使って LineColor 列の、 red を選択した場合のフィルタ結果が下図です。期待する正しい結果は、赤い下罫線だけの表示なのですが、この表示結果では関係のない所に青い罫線が表示されていたり、赤い罫線のはずの red の所が青い罫線になっており、フィルタ結果がみっともない状態です。

オートフィルタで LineColor 列の、 blue を選択した場合も同様です。


スタイル設定を調べたときにヒントが!

Excel VBA の HELP で、 Bordersオブジェクト を調べると、こんな説明になっています。

このことから下罫線を描く場合には、 Bordersオブジェクト に指定する XlBordersIndex クラス の定数から、 xlEdgeBottom を使って描いていました。

以前、「 スタイル設定をシートに出力する VBA マクロ 」を作りました。このとき Stylesコレクション から取得した、 Bordersプロパティ indexの値 は以下のものでした。

xlLeft, xlRight, xlTop, xlBottom, xlDiagonalDown, xlDiagonalUp

Excel VBA の HELP、 Stylesコレクション のサンプルコードにも xlTop が使われていました。

HELP の Itemプロパティ では、「 xlEdgeXXX 」を使うように書かれています。

さて、ここで疑問が湧き出します。上下左右の罫線にある、「 xlEdgeXXX 」と「 xlXXX 」の定数の違いは何なのでしょうか?



「 xlEdgeBottom 」と「 xlBottom 」を比較してみる

両者の違いを探るため、比較用の VBA マクロを作り調べてみました。(この VBA マクロは文末に記載しています。)

テスト環境は、Excel 2003 SP3・Windows XP SP3 です。

下図左側の下罫線は「 xlEdgeBottom 」、下図右側の下罫線は「 xlBottom 」を使って描いています。その他は同一内容です。

オートフィルタで LineColor 列の、 red を選択したものです。下図右側の「 xlBottom 」の表示が良い感じです。

オートフィルタで LineColor 列の、 blue を選択。こちらの表示結果でも、下図右側の「 xlBottom 」で描いたほうは、正しくフィルタ表示できています。


オートフィルタでは「 xlBottom 」なら OK なの?

そこで、他のバージョンの Excel でも大丈夫なのか調べてみました。

他に使用できる Excel は、

  • Excel 2000 SP3
  • Excel 2010 評価版 (Office Professional 2010 Trial)
  • Excel 2013 Preview (Microsoft Office Professional 2013 Preview)
の 3 種類です。

まずはじめに Excel 2000 SP3・Windows XP SP3 から試してみました。

オートフィルタ項目 red

オートフィルタ項目 blue


つづいて、Excel 2010 評価版・Windows 7 Enterprise 評価版です。

オートフィルタ項目 red

オートフィルタ項目 blue


最後は Excel 2013 Preview・Windows 8 Release Previewです。

オートフィルタ項目 red

オートフィルタ項目 blue


結論、オートフィルタでは「 xlBottom 」を使えば OK

下罫線に「 xlBottom 」を使ったほうでは、いずれの結果もうまく動作しています。これでオートフィルタには「 xlBottom 」を使うことで正しく表示できることがわかりました。

今回調査した結果と、 Web で調べた結果から xlEdgeXXX と xlXXX の違いについて纏めてみると。(内容には未確認部分も含んでいます。)

  • ひとつのセルの上・下・左・右の罫線指定には、それぞれ 「 xlTop 」, 「 xlBottom 」, 「 xlLeft 」, 「 xlRight 」の定数を使う。
  • セル範囲(外周)の上・下・左・右の罫線指定には、それぞれ 「 xlEdgeTop 」, 「 xlEdgeBottom 」, 「 xlEdgeLeft 」, 「 xlEdgeRight 」 の定数を使う。

オートフィルタを使わなければ、どちらの方法で描いても大して変わらないのですが、オートフィルタを使うと挙動が違ってくるという訳です。これがオートフィルタの仕様なのか、バグなのか良く判りませんが、今まで懸案だった問題が少しスッキリした感じです。

今回の調査に使った VBA マクロを以下に記載します

Option Explicit
'/////  罫線のオートフィルタ動作テスト、メイン  /////
Sub Test_Borders()
    Dim mysheet As Worksheet
    Dim rTable_tmp As Range, rTable_left As Range, rTable_right As Range
    Dim xVal As Long
    Const xTable_Width As Integer = 6
    Const xTable_Height As Integer = 19
    Dim sTable_tmp As Variant

On Error GoTo ERR
    '表示データセット
    sTable_tmp = Array(Array("LineColor", "    ", "    ", "    ", "    ", "    "), _
                            Array("red ", "red ", "red ", "    ", "    ", "    "), _
                            Array("blue", "    ", "    ", "    ", "blue", "blue"), _
                            Array("red ", "    ", "red ", "red ", "    ", "    "), _
                            Array("blue", "    ", "    ", "blue", "blue", "    "), _
                            Array("red ", "    ", "    ", "red ", "red ", "    "), _
                            Array("red ", "    ", "    ", "    ", "red ", "red "), _
                            Array("blue", "    ", "blue", "blue", "    ", "    "), _
                            Array("blue", "blue", "blue", "    ", "    ", "    "), _
                            Array("red ", "red ", "red ", "red ", "    ", "    "), _
                            Array("red ", "    ", "red ", "red ", "red ", "    "), _
                            Array("red ", "    ", "    ", "red ", "red ", "red "), _
                            Array("blue", "blue", "blue", "blue", "    ", "    "), _
                            Array("blue", "    ", "blue", "blue", "blue", "    "), _
                            Array("blue", "    ", "    ", "blue", "blue", "blue"), _
                            Array("red ", "red ", "red ", "red ", "red ", "    "), _
                            Array("blue", "    ", "blue", "blue", "blue", "blue"), _
                            Array("red ", "    ", "red ", "red ", "red ", "red "), _
                            Array("blue", "blue", "blue", "blue", "blue", "    "))
    Set mysheet = ActiveSheet
    Set rTable_left = mysheet.Range("A2")
    Set rTable_right = mysheet.Range("H2")
    
    'オートフィルタ解除
    If mysheet.AutoFilterMode = True Then
        mysheet.AutoFilterMode = False
    End If
    
    '領域を消去
    Call DeleteTable(Range("A1:M20"))
    
    'テーブル作成 (失敗する罫線 xlEdgeBottom)
    rTable_left.Offset(-1, 0).Value = "失敗する罫線"
    Call Write_Table(rTable_left, sTable_tmp, xTable_Height, xTable_Width)
    xVal = xlEdgeBottom
    Set rTable_tmp = rTable_left.Offset(1, 1).Resize(xTable_Height - 1, xTable_Width - 1)
    Call Draw_Borders(rTable_tmp, xVal)
    
    'テーブル作成 (成功する罫線 xlBottom)
    rTable_right.Offset(-1, 0).Value = "成功する罫線"
    Call Write_Table(rTable_right, sTable_tmp, xTable_Height, xTable_Width)
    xVal = xlBottom
    Set rTable_tmp = rTable_right.Offset(1, 1).Resize(xTable_Height - 1, xTable_Width - 1)
    Call Draw_Borders(rTable_tmp, xVal)

    'オートフィルタ オン
    If mysheet.AutoFilterMode = True Then
        mysheet.AutoFilterMode = False
    End If
    
    mysheet.Range("A2:M2").AutoFilter
    mysheet.Columns("A:M").AutoFit

ERR:
    Set rTable_right = Nothing
    Set rTable_left = Nothing
    Set rTable_tmp = Nothing
    Set mysheet = Nothing
End Sub
'/////  テーブルデータを表示  /////
Sub Write_Table(ByVal rTable_in As Range, ByVal sTable_in As Variant, nRow As Integer, nCol As Integer)
    Dim nCount As Integer, rTable As Range
    Set rTable = rTable_in.Resize(, nCol)
    
    For nCount = 0 To nRow - 1
        rTable.Offset(rowOffset:=nCount).Value = sTable_in(nCount)
    Next nCount

    Set rTable = Nothing
End Sub
'/////  テーブルに下罫線を描画  /////
Sub Draw_Borders(rTable As Range, xVal As Long)
    Dim r As Range

    '下罫線を描画
    For Each r In rTable
        With r.Borders(xVal)
            Select Case r.Text
            Case "red "
                .LineStyle = xlContinuous
                .Weight = xlThick
                .ColorIndex = 3
            Case "blue"
                .LineStyle = xlContinuous
                .Weight = xlThick
                .ColorIndex = 5
            Case Else
                .LineStyle = xlNone
            End Select
        End With
    Next r

    Set r = Nothing
End Sub

'/////  テーブルを消去  /////
Sub DeleteTable(rTable_range As Range)
    Dim r As Range
    rTable_range.Clear
    
    '下罫線を消去(消去は xlEdgeBottom を使う。)
    For Each r In rTable_range
        r.Borders(xlEdgeBottom).LineStyle = xlLineStyleNone
    Next r

    Set r = Nothing
End Sub

2012年12月4日火曜日

HDL-GS500を、1.0TBに換装して再初期化する。

今まで3回にわたって、HDL-GS500の故障からデータ救出までを書きました。

  1. HDL-GS500が故障。
  2. 壊れたHDDを、Advanced FormatのHDDに交換。
  3. GNU ddrescueを使って、壊れたHDDからデーターを救出。
救出データのバックアップが終わりましたので、今回はHDL-GS500を再初期化しました。
これで1.0TBのHDL-GS500になりました。


再初期化の前にtar2diskを一部修正

データ救出用として暫定修正していたtar2diskを、通常使用できるように修正しました。

  • disk2cyl( )は、データ救出のために500GBに固定していた設定を解除。ディスクのセクター数からモデルを自動識別するように修正。セクターの計算式を見直し、遠回りしていた計算をシンプルにしました。
  • partition( )は、全てのパーティションの開始位置を、アライメント調整した値に修正しました。

修正版tar2disk再初期化用

#!/bin/sh
#
# tar2disk: tar ball をディスクに展開
#
# usage: tar2disk sda
#///// 2012/10/01   sfdiskをシリンダ指定から、セクタ指定へ変更。/////
#///// 2012/11/06   全パーティションのアライメント調整。/////
mnt=./mnt
sddev=/dev/hdb   # ##### 初期化する環境に合わせて変更してください #####

PATH=$PATH:/sbin

#
# 16進->10進変換
#
hex2dec() {
    expr 1 + `printf "%d" $1`
}

#
# モデルごとの制限セクタ数
#
sector160=`hex2dec 0x12A05FBF`
sector250=`hex2dec 0x1D1A9C7F`
sector300=`hex2dec 0x22ECB57F`
sector320=`hex2dec 0x2540BF7F`
sector400=`hex2dec 0x2E90F73F`
sector500=`hex2dec 0x3A353900`
sector750=`hex2dec 0x574FCD9F`
sector1000=`hex2dec 0x74706DAF`

#cyl_end=379        # sda5 の終了セクタ
cyl_end=6088641     #/////シリンダ値をセクタ値に変更/////

#
# ディスク名からモデルで丸められたセクタ数を得る
#///// 2012/10/01   セクタ数を返すように修正 /////
#///// 2012/11/06   修復時の500GB固定を解除、計算式最適化。/////
disk2cyl() {
    local disk=$1
    local sector=`cat /sys/block/$disk/size`
#/////    local sector=976566529    /////
    if [ $sector -lt $sector160 ]; then
        echo -n error
        exit 1
    elif [ $sector -lt $sector250 ]; then
        expr $sector160 - $cyl_end
    elif [ $sector -lt $sector300 ]; then
        expr $sector250 - $cyl_end
    elif [ $sector -lt $sector320 ]; then
        expr $sector300 - $cyl_end
    elif [ $sector -lt $sector400 ]; then
        expr $sector320 - $cyl_end
    elif [ $sector -lt $sector500 ]; then
        expr $sector400 - $cyl_end
    elif [ $sector -lt $sector750 ]; then
        expr $sector500 - $cyl_end
    elif [ $sector -lt $sector1000 ]; then
        expr $sector750 - $cyl_end
    else
        expr $sector1000 - $cyl_end
    fi
    return 0
}

#
# パーティションを切る
#///// 2012/10/01   シリンダ指定からセクタ指定へ変更 sda6の開始セクタは暫定値/////
#///// 2012/11/06   全パーティションのアライメント調整。/////
partition() {
 local disk=$1
 local c5=417687    # 26*255*63-2
 local cyl=`disk2cyl $disk`
 local ext=`expr $cyl + $c5 + 10`

 dd if=/dev/zero of=/dev/$disk bs=512 count=2 || exit 1
 sfdisk -f -uS /dev/$disk <<EOF || exit 1
2048,626536,L
628584,833328,L
1461912,4209032,S
5670944,$ext,E
5670952,$c5,L
6088640,$cyl,L
EOF
}


#
# format
#///// 2012/10/01 ブロックサイズを4096バイトに変更。/////
format() {
 local i=$1

 if [ $i -eq 1 ]; then
  [ $flag_reset -eq 1 ] && return 0
  mke2fs -b 4096 -j -m1 $sddev$i || return 1
 elif [ $i -eq 2 ]; then
  mke2fs -b 4096 -j -m1 $sddev$i || return 1
 elif [ $i -eq 5 ]; then
  mke2fs -b 4096 -j -N 100000 \
   -O dir_index,filetype,sparse_super $sddev$i || return 1
 else
  [ ! -f /sbin/mkfs.xfs ] && cp -a ${SCRIPT_PATH}/mkfs.xfs /sbin/
  mkfs.xfs -f $sddev$i || return 1
 fi
 return 0
}


#
# fw_install
#
fw_install() {
 touch verify_on_boot
 cp -a ../sd?.tgz ../tar2disk ./.landisk/
 mkdir ./.landisk/mnt
}


#
# 初期化後updateの為にflag fileをtouchする
#
set_reset_flag() {
 touch ./.landisk/reset_ok
}


#
# ディスクを 0 クリアする
#
sanitize_disk() {
 local i=$1
 echo "--- sanitize disk"
 dd if=/dev/zero of=$sddev$i bs=1M || return 1
}


#
# install_logを 作成する
#
set_install_log() {
 local end_time
 local j
 local mac_addr=`/sbin/ifconfig eth0 | sed -n 's/^.*HWaddr \([0-9A-F:]*\)[ ]*$/\1/p'`
 local log_dir="$mnt/factory_log"
 local install_log="$log_dir/install.log"

 mount ${sddev}5 $mnt || return 1
 if [ ! -d $log_dir ]; then
  mkdir $log_dir || return 1
 fi
 end_time=`date`
 echo "Mac Address: $mac_addr" > $install_log
 echo "Install Start: $START_TIME" >> $install_log
 echo "Install End: $end_time" >> $install_log
 for j in 1 2 3 4 5 6 7 8 9 10; do
  sync
  umount $mnt && break || sleep 1
 done
}

#
# factorylogの退避
#
bk_factory_log() {
 local factory_tgz=$topdir/factory_log.tar.gz
 if [ ! -f $factory_tgz ]; then
  mount ${sddev}5 $mnt || return 1
  tar cpzf $factory_tgz -C $mnt factory_log
  umount $mnt
 fi
}

#
# factorylogの書き戻し
#
restore_factory_log() {
 local factory_tgz=$topdir/factory_log.tar.gz
 if [ -f $factory_tgz ]; then
  tar xpzf $factory_tgz
  echo `LANG=C date`: reset_script: >> factory_log/powerlog
  rm -f $factory_tgz
 fi
}


#
# smartチェックを行う
#
smart_check() {
 local disk=$1
 local RESULT_SMARTCTL=0
 local RESULT_SMARTCTL_BIT0=0
 local RESULT_SMARTCTL_BIT1=0
 local RESULT_SMARTCTL_BIT2=0
 local RESULT_SMARTCTL_BIT3=0
 [ ! -f /usr/sbin/smartctl ] && cp -a ${SCRIPT_PATH}/smartctl /usr/sbin/

 /usr/sbin/smartctl --smart=on --offlineauto=on --saveauto=on \
     /dev/${disk}
 /usr/sbin/smartctl -a /dev/${disk}
 RESULT_SMARTCTL=$?
 RESULT_SMARTCTL_BIT0=$((${RESULT_SMARTCTL} & 1))
 RESULT_SMARTCTL_BIT1=$((${RESULT_SMARTCTL} & 2))
 RESULT_SMARTCTL_BIT2=$((${RESULT_SMARTCTL} & 4))
 RESULT_SMARTCTL_BIT3=$((${RESULT_SMARTCTL} & 8))

 if [ ${RESULT_SMARTCTL_BIT0} -ne 0 ]; then
     echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
     echo "*** COMMAND LINE PARSE ERROR ***"
     return 1
 fi
 if [ ${RESULT_SMARTCTL_BIT1} -ne 0 ]; then
     echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
     echo "*** DEVICE OPEN FAILED ***"
     return 1
 fi
 if [ ${RESULT_SMARTCTL_BIT2} -ne 0 ]; then
     echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
     echo "*** S.M.A.R.T. COMMAND FAILED ***"
     return 1
 fi
 if [ ${RESULT_SMARTCTL_BIT3} -ne 0 ]; then
     echo "*** S.M.A.R.T ERROR DETECTED DISK=${disk} ***"
     echo "*** STATUS: DISK FAILING ***"
     return 1
 fi
 return 0
}


#
# メイン
#
disk=$1
mode=$2
topdir=`pwd`

if [ "$disk" = "" ]; then
 echo usage: tar2disk sda 1>&2
 exit -1
fi

if [ "x$mode" == "xreset" ]; then
 flag_install=0
 flag_reset=1
 flag_reset_full=0
elif [ "x$mode" == "xreset_full" ]; then
 flag_install=0
 flag_reset=1
 flag_reset_full=1
else
 flag_install=1
 flag_reset=0
 flag_reset_full=0
fi

for i in 1 2 5 6; do
 umount $sddev$i
done

if [ $flag_install -eq 1 ]; then
 smart_check $disk || exit 1
 partition $disk
fi

mkswap /dev/${disk}3
swapon /dev/${disk}3
trap "swapoff /dev/${disk}3" 0

for i in 1 2 5 6; do
 cd $topdir
    
 echo --- partitioning $i
 [ $i -eq 6 -a $flag_reset_full -eq 1 ] && sanitize_disk $i
 [ $i -eq 5 -a $flag_reset -eq 1 ] && bk_factory_log
 echo --- format partition
 format $i || exit 1
 mount $sddev$i $mnt || exit 1

 echo --- extracting tar ball
 cd $mnt || exit 1
 tar zxf ../sd$i.tgz || exit 1
 [ $i -eq 1 -a $flag_install -eq 1 ] && fw_install
 [ $i -eq 1 -a $flag_reset -eq 1 ] && set_reset_flag
 [ $i -eq 5 -a $flag_reset -eq 1 ] && restore_factory_log
 cd $topdir || exit 1
    
 echo --- unmounting
 for j in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
  sync
  umount $mnt && break || sleep 1
 done
 [ "$?" -ne 0 ] && exit 1
done

[ $flag_install -eq 1 ] && set_install_log
exit 0


作業の準備

バックアップが終わったHDL-GS500からHDDを取り出し、USB-SATA変換アダプタ経由でPCに接続しました。このとき間違いを避けるために、元々PCに搭載しているHDDの接続を取り外しておくと、とても安全に作業できます。

  • はじめる前にtar2diskの9行目は、初期化する環境に合わせて変更が必要です。
  • sddev=/dev/hdb   # ##### 初期化する環境に合わせて変更してください #####
    
  • 初期化するHDDのデバイス・ノードは、dmesgなどで確認します。
    例えば、/dev/sdcなら、9行目をsddev=/dev/sdcに変更します。
  • 再セットアップ用ファイルsd1.tgz, sd2.tgz, sd5.tgz, sd6.tgz, tar2diskが入ったUSBメモリ(1回目のときに保存したもの)は、tar2diskの内容を今回の修正版に変更しておきます。

HDDの再初期化

knoppix DVDを起動して端末を立ち上げsu -rootになります。

最初の状態として、

/dev/sdcには、再初期化するHDDが
/dev/sddには、USBメモリが
接続されている状態とします。

USBメモリを、マウントポイントを作成してマウントします。

# mkdir /media/usb
# mount /dev/sdd1 /media/usb

USBメモリのtar2diskを実行します。

# cd /media/usb/hdd1/.landisk
# ./tar2disk sdc
これでHDDが初期化されます。

シリアルコンソールから、sfdiskした結果です。HDDのセクターサイズをtar2diskが自動認識して、計算どおり1.0TBでパーティショニングできました。

# sfdisk -uS -l /dev/hdb

Disk /dev/hdb: 121601 cylinders, 255 heads, 63 sectors/track
Warning: extended partition does not start at a cylinder boundary.
DOS and Linux will interpret the contents differently.
Units = sectors of 512 bytes, counting from 0

   Device Boot    Start       End   #sectors  Id  System
/dev/hdb1          2048    628583     626536  83  Linux
/dev/hdb2        628584   1461911     833328  83  Linux
/dev/hdb3       1461912   5670943    4209032  82  Linux swap / Solaris
/dev/hdb4       5670944 1953525167 1947854224   5  Extended
/dev/hdb5       5670952   6088638     417687  83  Linux
/dev/hdb6       6088640 1953525166 1947436527  83  Linux

再初期化後にHDDに書き込まれたtar2diskは、9行目の修正部分を元のsddev=/dev/hdbに戻しておきます。HDL-GS500の内部から見たHDDのデバイス・ノードは/dev/hdbになっています。

sddev=/dev/hdb   # ##### 初期化する環境に合わせて変更してください #####
この作業を忘れると、Webメニューのシステム初期化を実行する場合に失敗します。

再初期化したHDDでは、第1パーティション(今回の状態ならsdc1)の.landiskディレクトリが、tar2diskの保存場所です。


作業完了

修正後にHDL-GS500を再組立すると作業完了です。

HDL-GS500の、1.0TB化が完了しました。



tar2diskのオプションについて

Webメニューのシステム初期化では、tar2diskに以下のオプションをつけて実行しているようです。

通常の初期化を行う場合

# ./tar2disk hdb reset

内蔵HDDの完全消去を行う場合は

# ./tar2disk hdb reset_full



最後に今回のトラブル談

HDL-GS500のトラブルが解決した後、作業用PCにトラブル発生。

.
.

その日の夜、言いようのない睡魔に襲われながら、再初期化の作業を始めていました。

エラーを出して途中で止まるtar2disk。

「何でやろぅ?おかしいなぁ…」

あまりにも眠たくて、考えようとしても全く頭が働かない。

何度も深い眠りの淵に引き込まれそうになりながら、作業を続けようとしていました。

「もうあかん、今日は無理や…」

とうとう睡魔に勝てず、その夜の作業は諦めて早々に寝ることに。


翌日の夕食後、おもむろに作業を再開。

原因を探るために、前日の作業ログを、以前のログと見比べる。

「何故だかpartitioning 1のinodesの数値が大きい?
Superblock backups stored on blocks:のブロックも多い???」

嫌な予感が…

--- partitioning 1
--- format partition
mke2fs 1.42.2 (9-Apr-2012)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
6561792 inodes, 26216064 blocks
262160 blocks (1.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=0
801 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
 4096000, 7962624, 11239424, 20480000, 23887872

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

--- extracting tar ball
--- unmounting
--- partitioning 2
--- format partition
mke2fs 1.42.2 (9-Apr-2012)
mke2fs: Device size reported to be zero.  Invalid partition specified, or
 partition table wasn't reread after running fdisk, due to
 a modified partition being busy and in use.  You may need to reboot
 to re-read your partition table.

tar2diskを見直して、ようやく原因に気づく。

「えぇ~っ、」

「やってしもた~」

諦めの妖精と、執着の妖精たちが、頭の中で踊りだしていました。



少し時間をおいてから、昨晩の様子を思い返すと。

作業PCのHDDを取り外さずに、USB-SATA変換アダプタ経由で、再初期化用のHDDをPCに接続していました。

そして、9行目の修正を忘れて、前の作業のときに設定していたsdaのままで実行。

sddev=/dev/sda   # ##### 初期化する環境に合わせて変更してください #####

つまり、USB-HDDではなく作業用PC のCドライブに書き込んでいたのです。

シェルスクリプトは、指示されたとおりにCドライブをext3でフォーマット後、tarボールを展開していました。その結果、作業PC のCドライブを飛ばしてしまったのでした。

「Windowsが立ち上がらない。困った!」

もう後の祭りです。


ほとんどのファイルは、別ドライブにバックアップを取ったつもりでしたが。マイドキュメントのバックアップが、あまり出来ていなかったことがわかりました。

そのため、データ救出、WindowsXPの再インストール、アプリケーションのインストール、嵐のようなアップデートと再起動の繰り返し等。余計な用事がいっぱい増えてしまい、今まで手間取っていました。

データの救出にはTestDiskPhotoRecを使いました。ほとんどのデジカメ画像が救出できましたが、長年可愛がってきたExcelファイルを幾つか失いました。 残念 X(

「気をつけよう、眠たい時のPC作業」

2012年11月6日火曜日

GNU ddrescueを使って、壊れたHDDからデーターを救出。

の続きです。

前回のブログでは、初期化用シェルスクリプトの 修正版 tar2disk を利用して、新しい 1.0 TB HDD を初期化。その HDD を HDL-GS500 に組み込み、正常に起動できることを確認しました。

これで、壊れた HDL-GS500 の HDD から救出したデータを、新しい HDD に受け入れる準備が整いました。今回はデータの救出作業にとりかかります。


I/O エラーで見えなくなる HDD への対策

ここでもう一度、壊れた HDD の状態を整理しておきます。

パーティションテーブル
読み出し可能。バックアップ済み。
sda1:ブート
読み出し可能。バックアップ済み。
sda2:システム
読み出し失敗。読み出し途中でエラー発生。
sda3:スワップ
swap領域につき未確認。
sda4:拡張領域
拡張領域につき未確認。
sda5:アプリケーション等の領域
読み出し失敗。読み出し途中でエラー発生。
sda6:保存データ領域
今回の作業対象領域。

作業を進めるにあたり、この HDD に起こっている厄介な問題がありました。それは I/O エラー です。

HDD の読み込み時に、いちど I/O エラー が発生すると、それ以降は HDD が見えなくなり、その HDD にアクセスできない状態になってしまいました。

そのための対応策は PC の再起動でした。当たり前のような方法ですが、これで再び HDD にアクセスできるようになりました。言い換えると、 I/O エラー が発生する都度に、PC を再起動する必要があるということになります。

はじめは、SATA 経由で高速に処理できることを期待して、両方の HDD をデスクトップ PC の SATA に接続して作業しようと考えていました。しかし、作業途中で I/O エラー が発生して中断することが頻繁に起こり。さらに、エラーの監視や再起動操作のために、作業中は PC の前から離れることができない状態でした。

PC の再起動を何十回と繰り返しながらの作業では、まるで PC 本体の連続再起動耐久試験 のようになってしまい、このままでは PC が壊れてしまいそうに思えてきました。(このときの dd を使った救出作業※1は、結果としては無駄に終わりました。)


電源再投入の対策として、壊れた HDD を USB 変換アダプタ経由で接続する

試行錯誤を繰り返した結果、この方法に落ち着きました。 I/O エラー が発生して HDD が見えなくなったときには、この USB 変換アダプタの電源を再投入することで、再び HDD を認識できるようになります。転送速度が低下するデメリットが有りますが、これで PC 本体を再起動する必要が無くなりました。

もう一つの問題の I/O エラーの監視と USB-HDD の再起動 については、GNU ddrescue と I/O エラーを監視するシェルスクリプト※2で行うことにしました。ただし、 USB アダプタの電源再投入だけは、手動で操作する必要があります。


困った時の強い味方、GNU ddrescue

エラーで読めない、壊れた HDD からデータを救出したい! こんなときに便利なツールが GNU ddrescue です。 今回は、この GNU ddrescue を使って作業しました。

GNU ddrescue の特徴は、

  • 正常に読み込めるブロックを優先して救出処理を行います。読み込みエラーのブロックを読み飛ばし、そのときのエラーブロックをログファイルに記録していきます。
  • 1 回目の救出処理が最終ブロックまで終わると、今度は逆方向に走査を開始して、ログファイルに記録したエラー・ブロックからの救出処理に再挑戦します。以降は、救出できるデータがある間は、エラー・ブロックが無くなるまで、この処理を繰り返していきます。
  • 繰り返し回数が進む都度に、読み込むブロック・サイズをセクター単位まで小さくしていくことで、できる限りデータ救出を行う努力をします。

また、作業途中でCtrl + Cで中断しても、ログファイルがあれば再び中断したブロックから処理を再開することができます。

書式

# ddrescue オプション 入力元 出力先 ログファイル 

今回使用したオプションは

-d   キャッシュをバイパスして、直接ディスクにアクセスする。
-f   出力先へ強制的に上書きする。(出力先がファイルで無い場合に必要なようです。)
-r1  リトライ回数を1回に指定。
-v   経過を詳細に表示する。
書式のサンプル:(ログファイル名の指定はありませんので、ファイル名は任意です。)
# ddrescue -d -f -r1 -v /dev/sdb6 /dev/sda6 /mnt/usb/dd.log


作業環境は、SystemRescueCd で

knoppix でも GNU ddrescue を使うことができますがインストール作業が必要です。※3
今回は SystemRescueCd を使いました。はじめから GNU ddrescue がインストール済みなので、起動して直ぐに使うことができます。(前述の、 PC 再起動無限ループになったときに knoppix から切り替えました。)

SystemRescueCd のダウンロード
http://www.sysresccd.org/Download

SystemRescueCd の起動メニュー 7 を選択すると、グラフィカル環境で起動します。

キーマップを質問してくるので、日本語キーボードなら 22 を入力します。このとき、何も操作しないと、20 秒後にはデフォルトの us キーボードが選択されてしまいます。

グラフィカル環境が起動します。

GNU ddrescue のバージョンは 1.16 でした。


作業の準備

再初期化後の動作確認(前回に確認済み)が終わった HDL-GS500 から、新しい HDD を取り出してデスクトップ PC の SATA に接続しました。このとき間違いを避けるために、元々 PC に搭載している HDD の接続を取り外しておくと安全に作業できます。後で困らないために、元の配線がどこに繋がっていたのかは忘れないようにします。

続いて、救出するデータが入っている 壊れた HDD を、USB-SATA 変換アダプタ経由で PC に接続しました。今回使用した USB-SATA 変換アダプタは 玄人志向の USB-PSATA です。電源スイッチが付いていれば、他の機種でも使えるかもしれません。それから、 HDD には状態が区別できるように、それぞれ何か目印をつけておくといいかもしれません。


※2 I/O エラー監視用シェルスクリプト

壊れた HDD からのデータ救出中に I/O エラーが発生すると、 HDD が見えなくなってしまいます。このとき GNU ddrescue は HDD が見えなくなったことが判断できないようです。そして、読み込めないエラーブロックとして次々とログファイルに記録し続けます。このままでは残りすべてがエラーブロックになってしまい、残された読み込み可能なデータさえも、救出することができません。

このシェルスクリプトを使えば、 I/O エラー時には GNU ddrescue を停止させるので、ログファイルに無意味なエラーブロックを記録し続けることを防げます。そして、エラー発生を知らせるビープ音が鳴ったときだけ、 USB-SATA アダプタの電源を再投入操作をすれば良く、 PC 画面を常時注視しながら待機する必要もなくなります。

このシェルスクリプト ddrescue_auto.sh は、 GNU ddrescue の自動停止と自動再開を行います。

  • 自動停止
    /var/log/messagesを監視して、I/O エラーのメッセージ "end_request: I/O error" を検出すると、 GNU ddrescue にシグナルを送り処理を中断します。そして中断したことをビープ音で知らせます。
  • 自動再開
    USB-SATA アダプタの電源を再投入した後、 HDD の接続メッセージ "Attached SCSI disk" を検出すると、 GNU ddrescue を開始します。

I/O エラーと USB-HDD 監視用シェルスクリプト ddrescue_auto.sh は、あらかじめ USB メモリーに保存しておきます。

# cp ddrescue_auto.sh /mnt/usb


ddrescue_auto.sh

#!/bin/bash
#
# ddrescue auto control program
#
# source disk = /dev/sdb
# dist disk   = /dev/sda
# ddrescue logfile = /mnt/usb/dd.log
#
# source disk drive is connected by USB-SATA.
#
MESSAGE_LOG="/var/log/messages"

ERROR_MESSAGE="end_request: I/O error"
COMMAND_NAME="ddrescue"
RESTART_MESSAGE="Detected I/O ERROR! Please RESTART USB Disk drive."

ATTACH_MESSAGE="Attached SCSI disk"
EXEC_COMMAND="ddrescue -d -f -r1 -v /dev/sdb6 /dev/sda6 /mnt/usb/dd.log"

error_detection()
{
while read line1
do
 echo "$line1" | grep "$ERROR_MESSAGE" > /dev/null
 if [ $? -eq "0" ]; then
  COMMAND_PID=`pidof $COMMAND_NAME`
  if [ $? -eq "0" ]; then
   kill -INT $COMMAND_PID
   beep -l 200 -D 100 -n -l 100 -D 100 -n -l 200
  fi
  echo $RESTART_MESSAGE
 fi
done
}

attached_disk_detection()
{
while read line2
do
 echo "$line2" | grep "$ATTACH_MESSAGE" > /dev/null
 if [ $? -eq "0" ]; then
  echo "$ATTACH_MESSAGE! START $COMMAND_NAME"
  sleep 1; beep -f 2000 -l 120 -n -f 1000 -l 120
  $EXEC_COMMAND
 fi
done
}

echo "Waiting! USB Disk drive"
tail -n 1 -f $MESSAGE_LOG | attached_disk_detection &
tail -n 1 -f $MESSAGE_LOG | error_detection


SystemRescueCd で作業開始

PC の電源を入れて SystemRescueCd を起動すると、はじめから root で作業できます。

はじめに、 HDD の取り違いを起こさないために、接続した HDD のそれぞれのデバイス・ノードを、 dmesg などを使って確認しておきます。 HDD を間違えると、救出すべきデータを消してしまうことになるので注意します。

最初の状態としては

/dev/sda には、前回初期化済みの新しいHDD。
/dev/sdb には、救出するデータが入っている壊れたHDD
が接続されている状態とします。

ログファイルの保存用に、USB メモリーをマウントしておきます。

root@sysresccd /root % mkdir /mnt/usb
root@sysresccd /root % mount /dev/sdc1 /mnt/usb

GNU ddrescue の起動は、先ほど USB メモリーに保存しておいたシェルスクリプト ddrescue_auto.sh から行います。

root@sysresccd /root % cd /mnt/usb 
root@sysresccd /root % ./ddrescue_auto.sh
で起動します。

起動すると Waiting! USB Disk drive メッセージを表示して待機します。
USB-SATA アダプタの電源が入ると、 Attached SCSI disk! START ddrescue のメッセージを表示後 GNU ddrescue を実行します。端末画面には GNU ddrescue の作業状態が表示されます。

root@sysresccd /root % ./mnt/usb/ddrescue_auto.sh
Waiting! USB Diskdrive
Attached SCSI disk! START ddrescue


GNU ddrescue 1.16
About to copy 496880 MBytes from /dev/sdb6 to /dev/sda6
    Starting positions: infile = 0 B,  outfile = 0 B
    Copy block size: 128 sectors       Initial skip size: 128 sectors
Sector size: 512 Bytes

Press Ctrl-C to interrupt
Initial status (read from logfile)
rescued:   496531 MB,  errsize:    348 MB,  errors:   46721
Current status
rescued:   496535 MB,  errsize:    345 MB,  current rate:        0 B/s
   ipos:    23009 MB,   errors:   46579,    average rate:     347 kB/s
   opos:    23009 MB,     time since last successful read:       1 s
Retrying bad sectors... Retry 1

救出処理の途中で、HDD の I/O エラー "end_request: I/O error"

Oct 16 01:18:45 sysresccd kernel: [98220.549082] sd 286:0:0:0: [sdb] Unhandled sense code
Oct 16 01:18:45 sysresccd kernel: [98220.549085] sd 286:0:0:0: [sdb]  Result: hostbyte=DID_ERROR driverbyte=DRIVER_SENSE
Oct 16 01:18:45 sysresccd kernel: [98220.549088] sd 286:0:0:0: [sdb]  Sense Key : Hardware Error [current] 
Oct 16 01:18:45 sysresccd kernel: [98220.549091] sd 286:0:0:0: [sdb]  Add. Sense: No additional sense information
Oct 16 01:18:45 sysresccd kernel: [98220.549094] sd 286:0:0:0: [sdb] CDB: Read(10): 28 00 00 dd 64 1f 00 00 01 00
Oct 16 01:18:45 sysresccd kernel: [98220.549101] end_request: I/O error, dev sdb, sector 14509087
メッセージを検出すると、 GNU ddrescue を自動停止します。その時はビープ音で知らせます。
次のメッセージを表示して、 USB-SATA アダプタの電源再投入まで待機します。
Interrupted by user
Detected I/O ERROR! Please RESTART USB Disk drive.
^C

ここで、 手動操作により USB-HDD の電源を再投入 します。

USB-HDD の電源を手動操作で再投入し "Attached SCSI disk"

Oct 16 01:11:27 sysresccd kernel: [97782.514026] usb 1-1: new high-speed USB device number 30 using ehci_hcd
Oct 16 01:11:27 sysresccd kernel: [97782.629756] usb 1-1: New USB device found, idVendor=152d, idProduct=2338
Oct 16 01:11:27 sysresccd kernel: [97782.629759] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=5
Oct 16 01:11:27 sysresccd kernel: [97782.629762] usb 1-1: Product: USB to ATA/ATAPI Bridge
Oct 16 01:11:27 sysresccd kernel: [97782.629765] usb 1-1: Manufacturer: JMicron
Oct 16 01:11:27 sysresccd kernel: [97782.629767] usb 1-1: SerialNumber: XXXXXXXXXXXX
Oct 16 01:11:27 sysresccd kernel: [97782.631108] scsi286 : usb-storage 1-1:1.0
Oct 16 01:11:28 sysresccd kernel: [97783.633178] scsi 286:0:0:0: Direct-Access     ST350082 0AS                   PQ: 0 ANSI: 2 CCS
Oct 16 01:11:28 sysresccd kernel: [97783.633959] sd 286:0:0:0: Attached scsi generic sg2 type 0
Oct 16 01:11:28 sysresccd kernel: [97783.634764] sd 286:0:0:0: [sdb] 976773168 512-byte logical blocks: (500 GB/465 GiB)
Oct 16 01:11:28 sysresccd kernel: [97783.635508] sd 286:0:0:0: [sdb] Write Protect is off
Oct 16 01:11:28 sysresccd kernel: [97783.635511] sd 286:0:0:0: [sdb] Mode Sense: 00 38 00 00
Oct 16 01:11:28 sysresccd kernel: [97783.636258] sd 286:0:0:0: [sdb] Asking for cache data failed
Oct 16 01:11:28 sysresccd kernel: [97783.636260] sd 286:0:0:0: [sdb] Assuming drive cache: write through
Oct 16 01:11:28 sysresccd kernel: [97783.638513] sd 286:0:0:0: [sdb] Asking for cache data failed
Oct 16 01:11:28 sysresccd kernel: [97783.638516] sd 286:0:0:0: [sdb] Assuming drive cache: write through
Oct 16 01:11:28 sysresccd kernel: [97783.684756]  sdb: sdb1 sdb2 sdb3 sdb4 < sdb5 sdb6 >
Oct 16 01:11:28 sysresccd kernel: [97783.687637] sd 286:0:0:0: [sdb] Asking for cache data failed
Oct 16 01:11:28 sysresccd kernel: [97783.687640] sd 286:0:0:0: [sdb] Assuming drive cache: write through
Oct 16 01:11:28 sysresccd kernel: [97783.687642] sd 286:0:0:0: [sdb] Attached SCSI disk
を検出すると、検出音と共にメッセージを表示後、再び GNU ddrescue を起動します。
root@sysresccd /root % sh /mnt/usb/ddrescue_auto_exec2.sh
Waiting! USB Diskdrive
Attached SCSI disk! START ddrescue

この後は、壊れた HDD からデータを読み出せる限りの間、

  1. I/O エラー検出、 ddrescue を自動停止。
  2. ビープ音で知らせて待機。
  3. 手動操作で USB-HDD の電源を再投入する。
  4. HDD 接続を検出、 ddrescue を自動起動。
この作業を忍耐強く繰り返すことになります。


そして 1 ヶ月後、データ救出完了

sda6 のデータ救出作業を続けること約 1 ヶ月、ようやく終了しました。これで全てのデータを、無事に救出することができました。

I/O エラーの HDD から、無事にデータを救出することができたのは幸運でした。 GNU ddrescue は、 HDD のデータ救出には大変強力なツールだと実感しました。

完了時の端末画面は、このような表示になりました。

GNU ddrescue 1.16
About to copy 496880 MBytes from /dev/sdb6 to /dev/sda6
    Starting positions: infile = 0 B,  outfile = 0 B
    Copy block size: 128 sectors       Initial skip size: 128 sectors
Sector size: 512 Bytes

Press Ctrl-C to interrupt
Initial status (read from logfile)
rescued:   496880 MB,  errsize:    1024 B,  errors:       2
Current status
rescued:   496880 MB,  errsize:       0 B,  current rate:      512 B/s
   ipos:    14948 MB,   errors:       0,    average rate:      341 B/s
   opos:    14948 MB,     time since last successful read:       0 s
Finished                       
^C

この後、この HDD を HDL-GS500 に再組み込みした後で、 sda6 のデータ保存用フォルダの内容を確認しました。いくつかのファイルを試しましたが、いずれも正常に読み込めているようでした。

今回はデータ救出のために 1.0TB の HDD を 500GB として初期化していました。
次回は、救出したデータのバックアップ完了後に、前回修正した tar2disk に少し手を加えたものを使い、 HDL-GS500 を 1.0TB の HDL-GS500 として再初期化します。

づづきは

HDL-GS500 を、1.0 TB に換装して再初期化する。



※1 失敗編: dd で sda6 パーティションをコピーする

SATA 接続した sda6 のパーティションを、 dd で一括コピーします(する予定でした)。

# dd if=/dev/sdb6 of=/dev/sda6 bs=512 conv=noerror,sync
しかし、途中で I/O エラー になって中断してしまいました。

いちど I/O エラー が発生すると、 壊れた HDD が見えなくなってしまいます。この 壊れた HDD を再認識するためには、再起動しなければなりませんでした。

さらに困ったことに dd は、どのセクターまで正常にコピーできたのか? エラーで読み取れなかったセクターは? 次はどこのセクターから再開すればいいのか? の状態に陥りました。

普段は便利な dd なのですが、今回のような I/O エラー が起きる HDD での使用にはあまり向いていないようです。



※3 GNU ddrescue を knoppix で使う場合

knoppix には入っていないようなので、 aptitude でインストールしてから使います。

knoppix DVD を起動したら、端末を立ち上げてsu - root になります。

先ず初めにパッケージを更新します。

# aptitude update

続いて GNU ddrescue のインストールを行います。

# aptitude install gddrescue
以下の新規パッケージがインストールされます:
  gddrescue 
更新: 0 個、新規インストール: 1 個、削除: 0 個、保留: 1866 個。
96.9 k バイトのアーカイブを取得する必要があります。展開後に 208 k バイトのディスク領域が新たに消費されます。
取得: 1 http://ftp.jp.debian.org/debian/ testing/main gddrescue i386 1.16-1 [96.9 kB]
Fetched 96.9 kB in 0秒 (148 kB/s)
Selecting previously unselected package gddrescue.
(データベースを読み込んでいます ... 現在 432445 個のファイルとディレクトリがインストールされています。)
(.../gddrescue_1.16-1_i386.deb から) gddrescue を展開しています...
install-info のトリガを処理しています ...
man-db のトリガを処理しています ...
gddrescue (1.16-1) を設定しています ...
これでインストールが完了しました。

コマンドが起動できるか、バージョン表示で確認しておきます。

# ddrescue -V
GNU ddrescue 1.16
Copyright (C) 2012 Antonio Diaz Diaz.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

2012年10月30日火曜日

壊れたHDDを、Advanced FormatのHDDに交換。

前ブログ、 HDL-GS500が故障の続きです。

壊れたHDL-GS500のHDDを交換するために、新しいHDDを買いました。そのときの店員さんの話では、今販売しているHDDのほとんどがAdvanced Formatということでした。

今後、修理や交換のために入手できるHDDは、Advanced Formatの選択肢しか残らないようですね。

今回買ったのは、HITACHI HDS721010DLE630 1.0TB Advanced Formatです。


Advanced Format のHDDとは

近年に登場した4096バイト・セクターのHDDには、内部のファームウェアで、4096バイトの物理セクターを、512バイト単位の8個の論理セクターに分割するしくみ (512バイト・セクター・エミュレーション)をもったものがあります。これらのHDDは4kセクターHDDや、Advanced FormatのHDDと呼ばれています。

セクターサイズを512バイトから、4096バイトへ拡大する理由や課題について、以下に簡単に纏めてみました。詳細については後述する参考Webサイトを参照ください。

  • HDDの大容量化に伴って、512バイト・セクターの抱える課題が顕著になってきた。
    • ディスクの総容量に対するセクター・サイズとの比率が大きくなることで、エラー修正が煩雑になり効率が低下してしまう。
    • 面密度の増加に伴って、1セクターあたりの表面積が縮小していくことになり、メディア欠損時のエラー修正がより困難になってきた。
    • セクター・サイズの拡大による利点として、エラー修正機能の改善、フォーマット効率の向上が挙げられている。
  • 512バイト・セクター・エミュレーション。
    • 従来の512バイト・セクターを対象にした機器との互換を保ちながら、4096バイト・セクターへの移行をスムーズに進めるためのしくみ。
    • HDD内部のファームウェアにより、4096バイトの物理セクターを、512バイト単位の8個の論理セクターに分割してデータ処理を行う。
    • このしくみを使うことでPCから見たHDDは、今まで同様に512バイト・セクターのHDDように振る舞う。
  • ユーザー側で回避すべき重要な課題
    • 512バイト・セクター・エミュレーションが、パフォーマンスに与える影響を最小限にするため、HDDへの書き込み時の、読み出し・修正・書き込みプロセスの発生頻度を最小限に抑えることが重要。
    • ファイルシステムのデータ構造と、パーティションのアライメント・マッチングが必須。
    • 適切なブロックサイズの選択が重要。
  • 適切なパーティショニング・ツールの選択。
    • 各パーティションの開始位置を、アライメント0の状態に設定できるツールを使用する。
    • アライメント0の位置とは、セクター位置が8の倍数になる位置のことを言う。
      (4096 バイト/セクター = 512 バイト/セクター ×
    • 従来のパーティショニング・ツールでは、シリンダ境界をパーティション境界に設定するようになっているので、そのまま使用するとアライメントがズレてしまうことになる。
      この場合、デフォルトの操作単位を、シリンダーからセクターに変更する機能があれば、アライメント0のパーティションを作成できる場合がある。
    • HDDの開始セクターの位置は、クロスプラットフォームの観点から見た場合は2048が無難。

Linuxでの、Advanced Formatの使用については、以下のWebサイトが参考になりました。

IBM developerWorks 4KB セクター・ディスクで Linux を使用する: 実用的なアドバイス
Seagate アドバンスド・フォーマット4Kセクター・ハードディスク・ドライブへの移行


HDL-GS500修復用HDDの、パーティショニングの考察

今回の修復作業におけるLinux使用時の注意点は、以下の内容が考えられます。

  • HDDの開始セクター位置を 2048 に設定する。
  • 各パーティションの開始位置を、アライメント0の状態にする。
  • ただし、sda6のアライメントは調整しない。
  • ファイルシステムのブロックサイズを、4096バイトにする。

このあたりを考慮しながら、進めていくことにしました。

先日確認したときの、壊れたHDDのパーティション構成は以下のようになっていました。

~# fdisk -l /dev/sda

Disk /dev/sda: 500.1 GB, 500107862016 bytes
255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xee4739c6

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1           16065      642599      313267+  83  Linux
/dev/sda2          642600     1461914      409657+  83  Linux
/dev/sda3         1461915     5670944     2104515   82  Linux swap / Solaris
/dev/sda4         5670945   976559219   485444137+   5  Extended
/dev/sda5         5670946     6088634      208844+  83  Linux
/dev/sda6         6088636   976559219   485235292   83  Linux
それぞれのパーティション先頭セクターの値を、8の倍数に調整した結果、各パーティションの開始セクターの位置を以下の値に決めました。
  • sda1の開始セクタ 2048、
  • sda2の開始セクタ 628584、
  • sda3の開始セクタ 1461912、
  • sda5の開始セクタ 5670944、

拡張領域sda4の開始セクターはsda5の開始セクター-1としました。いまのところ、この領域の開始セクター位置も、アライメント0にする必要があるのかは良くわかっていません。入れ子になっている論理領域sda5やsda6の外側の領域なので、あまり影響が無いと考えています。

sda6の開始セクターは、今回のデータの修復のために、パーティション全体をコピーするので、あえて変更しないことにします。ここを変更するとセクター位置がズレてしまい、xfsファイルシステムにアクセスできなくなる心配があります。そのため、この部分のアライメントのズレはやむおえません。 データ修復後に改めて、sda6のアライメント調整をすることにしました。


初期化用シェルスクリプト tar2disk を利用する

先日USBメモリに保存することができた初期化シェルスクリプト、tar2diskの9行目の内容を、こちら のWebサイトの情報を元にして、

sddev=/dev/hdb を sddev=/dev/sda に。
修正してtar2disk実行したところ、この新しいHDDのサイズを正常に1.0GBと認識して、初期化することができました。ただし、この時点では、まだアライメント調整はできていません。

次に、tar2diskで初期化した1.0TB HDDのマスターブートレコード(MBR)と、拡張パーティションブートレコード(Extended Partition Boot Record)を 調べてみました。

オリジナルの、HDDのパーティションと比べたところ、各パーティション開始セクターの位置が、両方とも同じでした。

さらに、初期化用シェルスクリプトtar2diskを調べてみると、各パーティションの先頭位置は、あらかじめ決められた値に固定されており。

cat /sys/block/$disk/size
で、取得したHDDの総セクター数を元にして、拡張領域sda4のサイズと、論理領域sda5,sda6のサイズを計算しているようだ、ということがわかりました。

そこで、このシェルスクリプトを少し修正してみることにしました。修正点はパーティショニングと、ext3のブロックサイズの変更です。

disk2cyl( )を、HDDから取得した総セクター数を元にして、データ保存領域に使用するシリンダ数を計算している部分を、セクター数で返すようにに変更しました。

partition( )は、sfdiskコマンドを使い、一括してパーティショニングを行っています。この部分のシリンダ単位で指定している部分を、セクター単位で指定するように変更しました。

format( )は、 ext3のブロックサイズを4096バイトに修正しました。

現時点では、壊れた500GBのHDD修復が目的なので、sda6の開始セクター位置のアライメントを調整していません。これは、データの修復のためにパーティション全体をコピーする必要があるからです。 また、新しいHDDには1.0TBを使用していますが、修復の都合上HDDサイズを500GBで初期化するようにしています。

シェルスクリプト中の下に示す行は、初期化する環境に合わせて変更が必要です。

sddev=/dev/hdb   # ##### 初期化する環境に合わせて変更してください #####
例えば、初期化するHDDが/dev/sdaなら、sddev=/dev/sdaに変更します。

HDDサイズは500GBに固定、アライメント調整適用済みtar2disk 修復用暫定版、

#!/bin/sh
#
# tar2disk: tar ball をディスクに展開
#
# usage: tar2disk sda
# ##### 2012/10/01 sfdiskをシリンダ指定から、セクタ指定へ変更。#####

mnt=./mnt
sddev=/dev/hdb   # ##### 初期化する環境に合わせて変更してください #####

PATH=$PATH:/sbin

#
# 16進->10進変換
#
hex2dec() {
    expr 1 + `printf "%d" $1`
}

#
# モデルごとの制限セクタ数
#
sector160=`hex2dec 0x12A05FBF`
sector250=`hex2dec 0x1D1A9C7F`
sector300=`hex2dec 0x22ECB57F`
sector320=`hex2dec 0x2540BF7F`
sector400=`hex2dec 0x2E90F73F`
sector500=`hex2dec 0x3A353900`
sector750=`hex2dec 0x574FCD9F`
sector1000=`hex2dec 0x74706DAF`

#cyl_end=379   # sda5 の終了セクタ
cyl_end=6088636   # ##### シリンダ値をセクタ値に変更 #####


#
# ディスク名からモデルで丸められたセクタ数を得る
# ##### 2012/10/01 セクタ数を返すように修正 #####
disk2cyl() {
    local disk=$1
#local sector=`cat /sys/block/$disk/size`
local sector=976566529  # ##### 修復のため、HDDサイズを500GBに固定。 #####
    if [ $sector -lt $sector160 ]; then
 echo -n error
 exit 1
    elif [ $sector -lt $sector250 ]; then
 expr \( \( $sector160 / 255 / 63 \) \* 16065 \) - $cyl_end
    elif [ $sector -lt $sector300 ]; then
 expr \( \( $sector250 / 255 / 63 \) \* 16065 \) - $cyl_end
    elif [ $sector -lt $sector320 ]; then
 expr \( \( $sector300 / 255 / 63 \) \* 16065 \) - $cyl_end
    elif [ $sector -lt $sector400 ]; then
 expr \( \( $sector320 / 255 / 63 \) \* 16065 \) - $cyl_end
    elif [ $sector -lt $sector500 ]; then
 expr \( \( $sector400 / 255 / 63 \) \* 16065 \) - $cyl_end
    elif [ $sector -lt $sector750 ]; then
 expr \( \( $sector500 / 255 / 63 \) \* 16065 \) - $cyl_end
    elif [ $sector -lt $sector1000 ]; then
 expr \( \( $sector750 / 255 / 63 \) \* 16065 \) - $cyl_end
    else
 expr \( \( $sector1000 / 255 / 63 \) \* 16065 \) - $cyl_end
    fi
    return 0
}


#
# パーティションを切る
# ##### 2012/10/01 シリンダ指定からセクタ指定へ変更 sda6の開始セクタは暫定値 #####
partition() {
 local disk=$1
 local c5=417689               # ##### 26*255*63-1 #####
 local cyl=`disk2cyl $disk`
 local ext=`expr $cyl + $c5 + 4`

 dd if=/dev/zero of=/dev/$disk bs=512 count=2 || exit 1
 sfdisk -f -u S /dev/$disk <<EOF || exit 1
2048,626535,L
628584,833327,L
1461912,4209030,S
5670943,$ext,E
5670944,$c5,L
6088636,$cyl,L
EOF
}


#
# format
# ##### 2012/10/01 ブロックサイズを4096バイトに変更。#####
format() {
 local i=$1

 if [ $i -eq 1 ]; then
  [ $flag_reset -eq 1 ] && return 0
  mke2fs -b 4096 -j -m1 $sddev$i || return 1
 elif [ $i -eq 2 ]; then
  mke2fs -b 4096 -j -m1 $sddev$i || return 1
 elif [ $i -eq 5 ]; then
  mke2fs -b 4096 -j -N 100000 \
   -O dir_index,filetype,sparse_super $sddev$i || return 1
 else
  [ ! -f /sbin/mkfs.xfs ] && cp -a ${SCRIPT_PATH}/mkfs.xfs /sbin/
  mkfs.xfs -f $sddev$i || return 1
 fi
 return 0
}


#
# fw_install
#
fw_install() {
 touch verify_on_boot
 cp -a ../sd?.tgz ../tar2disk ./.landisk/
 mkdir ./.landisk/mnt
}


#
# 初期化後updateの為にflag fileをtouchする
#
set_reset_flag() {
 touch ./.landisk/reset_ok
}


#
# ディスクを 0 クリアする
#
sanitize_disk() {
 local i=$1
 echo "--- sanitize disk"
 dd if=/dev/zero of=$sddev$i bs=1M || return 1
}


#
# install_logを 作成する
#
set_install_log() {
 local end_time
 local j
 local mac_addr=`/sbin/ifconfig eth0 | sed -n 's/^.*HWaddr \([0-9A-F:]*\)[ ]*$/\1/p'`
 local log_dir="$mnt/factory_log"
 local install_log="$log_dir/install.log"

 mount ${sddev}5 $mnt || return 1
 if [ ! -d $log_dir ]; then
  mkdir $log_dir || return 1
 fi
 end_time=`date`
 echo "Mac Address: $mac_addr" > $install_log
 echo "Install Start: $START_TIME" >> $install_log
 echo "Install End: $end_time" >> $install_log
 for j in 1 2 3 4 5 6 7 8 9 10; do
  sync
  umount $mnt && break || sleep 1
 done
}

#
# factorylogの退避
#
bk_factory_log() {
 local factory_tgz=$topdir/factory_log.tar.gz
 if [ ! -f $factory_tgz ]; then
  mount ${sddev}5 $mnt || return 1
  tar cpzf $factory_tgz -C $mnt factory_log
  umount $mnt
 fi
}

#
# factorylogの書き戻し
#
restore_factory_log() {
 local factory_tgz=$topdir/factory_log.tar.gz
 if [ -f $factory_tgz ]; then
  tar xpzf $factory_tgz
  echo `LANG=C date`: reset_script: >> factory_log/powerlog
  rm -f $factory_tgz
 fi
}


#
# smartチェックを行う
#
smart_check() {
 local disk=$1
 local RESULT_SMARTCTL=0
 local RESULT_SMARTCTL_BIT0=0
 local RESULT_SMARTCTL_BIT1=0
 local RESULT_SMARTCTL_BIT2=0
 local RESULT_SMARTCTL_BIT3=0
 [ ! -f /usr/sbin/smartctl ] && cp -a ${SCRIPT_PATH}/smartctl /usr/sbin/

 /usr/sbin/smartctl --smart=on --offlineauto=on --saveauto=on \
     /dev/${disk}
 /usr/sbin/smartctl -a /dev/${disk}
 RESULT_SMARTCTL=$?
 RESULT_SMARTCTL_BIT0=$((${RESULT_SMARTCTL} & 1))
 RESULT_SMARTCTL_BIT1=$((${RESULT_SMARTCTL} & 2))
 RESULT_SMARTCTL_BIT2=$((${RESULT_SMARTCTL} & 4))
 RESULT_SMARTCTL_BIT3=$((${RESULT_SMARTCTL} & 8))

 if [ ${RESULT_SMARTCTL_BIT0} -ne 0 ]; then
     echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
     echo "*** COMMAND LINE PARSE ERROR ***"
     return 1
 fi
 if [ ${RESULT_SMARTCTL_BIT1} -ne 0 ]; then
     echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
     echo "*** DEVICE OPEN FAILED ***"
     return 1
 fi
 if [ ${RESULT_SMARTCTL_BIT2} -ne 0 ]; then
     echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
     echo "*** S.M.A.R.T. COMMAND FAILED ***"
     return 1
 fi
 if [ ${RESULT_SMARTCTL_BIT3} -ne 0 ]; then
     echo "*** S.M.A.R.T ERROR DETECTED DISK=${disk} ***"
     echo "*** STATUS: DISK FAILING ***"
     return 1
 fi
 return 0
}


#
# メイン
#
disk=$1
mode=$2
topdir=`pwd`

if [ "$disk" = "" ]; then
 echo usage: tar2disk sda 1>&2
 exit -1
fi

if [ "x$mode" == "xreset" ]; then
 flag_install=0
 flag_reset=1
 flag_reset_full=0
elif [ "x$mode" == "xreset_full" ]; then
 flag_install=0
 flag_reset=1
 flag_reset_full=1
else
 flag_install=1
 flag_reset=0
 flag_reset_full=0
fi

for i in 1 2 5 6; do
 umount $sddev$i
done

if [ $flag_install -eq 1 ]; then
 smart_check $disk || exit 1
 partition $disk
fi

mkswap /dev/${disk}3
swapon /dev/${disk}3
trap "swapoff /dev/${disk}3" 0

for i in 1 2 5 6; do
 cd $topdir
    
 echo --- partitioning $i
 [ $i -eq 6 -a $flag_reset_full -eq 1 ] && sanitize_disk $i
 [ $i -eq 5 -a $flag_reset -eq 1 ] && bk_factory_log
 echo --- format partition
 format $i || exit 1
 mount $sddev$i $mnt || exit 1

 echo --- extracting tar ball
 cd $mnt || exit 1
 tar zxf ../sd$i.tgz || exit 1
 [ $i -eq 1 -a $flag_install -eq 1 ] && fw_install
 [ $i -eq 1 -a $flag_reset -eq 1 ] && set_reset_flag
 [ $i -eq 5 -a $flag_reset -eq 1 ] && restore_factory_log
 cd $topdir || exit 1
    
 echo --- unmounting
 for j in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
  sync
  umount $mnt && break || sleep 1
 done
 [ "$?" -ne 0 ] && exit 1
done

[ $flag_install -eq 1 ] && set_install_log
exit 0

修正したシェルスクリプトを使って初期化した後のパーティション構成です。拡張領域sda4の、開始セクター位置のアライメントがズレているとメッセージが出ています。やっぱりここの位置合わせも行ったほうがいいのでしょうか?

root@Microknoppix:~# fdisk -l /dev/sda

Disk /dev/sda: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders, total 1953525168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1            2048      628582      313267+  83  Linux
/dev/sda2          628584     1461910      416663+  83  Linux
/dev/sda3         1461912     5670941     2104515   82  Linux swap / Solaris
/dev/sda4         5670943   976559219   485444138+   5  Extended
Partition 4 does not start on physical sector boundary.
/dev/sda5         5670944     6088632      208844+  83  Linux
/dev/sda6         6088636   976559219   485235292   83  Linux
Partition 6 does not start on physical sector boundary.

さらに念のため、この1.0TB HDDのマスターブートレコード(MBR)と、拡張パーティションブートレコード(Extended Partition Boot Record)を調べてみました。

sda6の開始セクター位置を計算すると 5670943 + 417690 + 3 = 6088636 になるので、たぶんこれで大丈夫そうです。

この後、このHDDでHDL-GS500を組み立てなおし、正常に動作できることが確認できました。さらに一歩前進できました。


この後の計画

いろいろと試行錯誤しながらでしたが、前回計画したstep5まで、なんとか進めることができました。

この後、計画step6から、
GNU ddrescueを使って、壊れたHDDからデーターを救出。
へ続きます。

  1. 新HDDを取出し、旧HDDと共にPCへSATA接続。
  2. 旧HDDのsda6を、新HDDのsda6にコピーする。
  3. 新HDDで再組立て。
  4. HDL-GS500を起動して、保存しているデータのバックアップを取る。

2012年10月25日木曜日

HDL-GS500が故障。

既にひと月も前の事になりますが、ファイル保存に使用しているネットワーク・ハードディスクHDL-GS500が故障してしまいました。その後、復旧まで時間がかかりましたが、試行錯誤の後にデータを救出することができ、HDL-GS500を再セットアップする目処が立ちましたので、忘れないうちに修復の記録を書いていきます。


故障時の症状

9月の中旬ごろのことでした。前日まで普通に使えていたのですが、その日は電源を入れて暫く経っても緑ランプの点滅状態が続き、そのまま待っていても起動完了状態になりませんでした。

マニュアルを読んでみると、緑点滅中はシステム処理中のため、電源を切ったり、リセットしないようにと書かれているので、そのままにして翌日まで様子を見ることに。

しかし翌日になっても緑ランプの点滅状態が続いており、接続できない状態に変化は無く。しかたがないのでリセットボタンを押してみましたが、リセットもできない状態になっており、やむなくコンセントを抜きました。

その後、再び電源を入れてみましたが同じ症状のままで、起動完了できない状態に変化はありませんでした。とうとう壊れてしまったか…と、がっかりしてしまいました。

幸いにも、保存データのうちのほとんどは、別のハードディスクにバックアップを取っていたので助かったのですが、このHDL-GS500の中には、まだバックアップできていないデータが残ってしまいました。

(昨今の電力事情により、ふだん使用しないときには、本体の電源を切るようにしていました。)


HDD修復のための情報収集

壊れてしまったHDL-GS500の修理と、HDDのデータ救出について、どんな方法があるか調べてみました。

わかったことは、

  • HDDの中にHDL-GS500自身のシステム領域があるので、HDDの交換だけでは復旧できない。
  • データ領域のファイルシステムはxfs。しかしx86のLinuxマシンにmountして読みだすことができない。エンディアンの違いらしい。
  • 第1パーティションの中に、初期化用のファイルがある。
  • 内部の基板には、シリアルコンソール用の空パターンがある。
といった内容でした。

現状でHDDのデータを読み出すためには、HDL-GS500のシステムを修復して正常に起動できれば、保存データを読み出すことができるようになる、というのが結論でした。なんだかなぁ…ですが、考えてみれば確かにそのとおりです。

システム修復のためには二つの選択肢が考えられました。一つは、正常動作している同機種を入手して、HDDのシステム領域をまるごとコピーする方法。 もう一つは、壊れたHDDの中から, 修復に必要な初期化用のファイルを取り出方法です。

うまくいくかは、とにかくやってみないと判らない状態でしたが、先ずは後者の方法で進めることにしました。


HDL-GS500のパーティション構成

これまで調べた情報から、HDL-GS500内部HDDのパーティション構成は、6個のパーティションに分割されていることが分かりました。また、内部のシステム上ではHDDドライブをhdbとして認識しています。

それぞれのパーティション構成は、以下のようになっているようです。

 hdb1 bootイメージ            ext3 基本領域
 hdb2 システムファイル        ext3 基本領域
 hdb3 swap                    swap 基本領域
 hdb4 Extended                     拡張領域
 hdb5 アプリケーション用      ext3 論理領域
 hdb6 データ用領域            xfs  論理領域
HDL-GS500に保存したデータは、hdb6の領域に入っています。初期化に必要なファイルは、hdb1.landiskディレクトリの中にある、sd1.tgz, sd2.tgz, sd5.tgz, sd6.tgz, tar2diskのファイルということがわかりました。


シリアルコンソールから接続してみる

はじめに動作状態を見るために、HDL-GS500を分解して、シリアルコンソール接続用のコネクタを取り付けました。まずは、問題が起こっているところの状況確認がしたい、といった目的です。

Webの情報によると、HDL-GS500のシリアル信号レベルが3.3Vらしいので、レベル変換回路を経由してUSB-シリアル変換ケーブルでPCに接続しました。使ったレベル変換回路は数年前のトラ技の付録基板です、レベル変換にADM3202ANを実装しています。トラ技のいろいろな付録基板の中で、この付録基板はとても役に立っています。

シリアルコンソールへの接続はTeraTermProで行いました。

 ボーレート    115200
 データ         8 bit
 パリティ       none
 ストップビット 1 bit
 フロー制御     none
この設定で接続できました。ログインパスワードはログイン名と同じでした。

電源ボタンを押し、起動中の状態をシリアルコンソールから観察してみると、起動途中でエラーが発生しているようでログインすることができませんでした。電源を入れ直し何回か再起動するうちに、ようやくログインまで辿り着いたと思うと、しばらく操作しているうちにエラーが発生し、それ以降は操作不能状態になってしまいました。

end_request: I/O error, dev hdb, sector 871610
等のエラーメッセージが出ているので、やはりディスクに問題があるようでした。

下はシリアルコンソールに出力されたメッセージです。

Storlink CIR Initialization...




SL-Boot Loader for IO-Data HDL-GS [Linux], version 1.0.9.05_sata_bootp
Built by linux, 14:01:37, Oct 31 2007

Processor: SL3516c2
CPU Rate: 300000000
AHB Bus Clock:150MHz    Ratio:2/1
MAC 1 Address: XX:XX:XX:XX:XX:XX
MAC 2 Address: XX:XX:XX:XX:XX:XX
inet addr: 192.168.0.200/255.255.255.0
Kernel RAM Location: 0x01600000  Filename: zImage.gs
Initrd RAM Location: 0x00800000  Filename: rd.gz.gs
Waiting for disk ready & detect ...
Sending Reset...
IDE 0 Detect disk 0
Disk Drive: IDE-0, Device-0, 976773168 Sectors 500 GB 139 MB
Partition 1: Linux 626535 Sectors 320 MB
==> enter ^C to abort booting within 3 seconds ...... 
Load rd.gz.gs size 2049090...OK.
Load zImage.gs size 1828248...OK.
Uncompressing Linux................................................................................................................ done, booting the kernel.
Linux version 2.6.15 (root@devsrv) (gcc version 3.4.4 20041218 (prerelease) (Debian 3.4.3-1)) #2 Thu May 14 13:19:40 JST 2009
CPU: FA526id(wb) [66015261] revision 1 (ARMv4)
Machine: GeminiA
Ignoring unrecognised tag 0x00000000
Memory policy: ECC disabled, Data cache writeback
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 2, 16 byte lines, 512 sets
CPU0: D cache: 8192 bytes, associativity 2, 16 byte lines, 256 sets
Built 1 zonelists
Kernel command line: root=/dev/hdb2 ro mem=64M console=ttySL0,115200 initrd=0x00800000,16M
PID hash table entries: 512 (order: 9, 8192 bytes)
Bus: 150MHz(2/1)
Console: colour dummy device 80x30
sl2312 console setup : 
Disable IDE...config to SATA mode
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 64MB = 64MB total
Memory: 44288KB available (2761K code, 1241K data, 100K init)
Mount-cache hash table entries: 512
*** Page_chain_cachep Init!***
CPU: Testing write buffer coherency: ok
checking if image is initramfs...it isn't (no cpio magic); looks like an initrd
Freeing initrd memory: 16384K
NET: Registered protocol family 16
PCI: bus0: Fast back to back transfers disabled
sl2312_pci_map_irq : slot = 0  pin = 1 
SCSI subsystem initialized
usbcore: registered new driver usbfs
usbcore: registered new driver hub
NetWinder Floating Point Emulator V0.97 (double precision)
VFS: Disk quotas dquot_6.5.1
Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
NTFS driver 2.1.25 [Flags: R/O].
fuse init (API version 7.3)
SGI XFS with large block numbers, no debug enabled
SGI XFS Quota Management subsystem
Initializing Cryptographic API
io scheduler noop registered
io scheduler cfq registered
Real Time Clock Driver v0.10
Gemini Gpio init
Register Gemini Power control
Power event by Unknow Source 
Watchdog Timer Initialized
Storm crypto Initialization
ttySL0 at MMIO 0x42000000 (irq = 18) is a SL2312
RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize
loop: loaded (max 8 devices)
ipddp.c:v0.01 8/28/97 Bradford W. Johnson 
ipddp0: Appletalk-IP Encap. mode by Bradford W. Johnson 
VSC-switch not found
Storm Semiconductors,Inc. SL351x Giga Ethernet driver 0.1.7 built at May 14 2009 11:43:02
Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
ide: Assuming 33MHz system bus speed for PIO modes; override with idebus=xx
ide 1: physical = 63400000, virtual = c4800000, irq = 5
ide0: MMIO-DMA , BIOS settings: hda:pio, hdb:pio
MASTER not exist
hdb: ST3500820AS, ATA DISK drive
hdb speed:U6 (66MHz)(0x46)
ide0 at 0xc4800020-0xc4800027,0xc4800036 on irq 5
hdb: max request size: 1024KiB
hdb: 976773168 sectors (500107 MB) w/8192KiB Cache, CHS=60801/255/63
hdb: cache flushes supported
hdb: hdb1 hdb2 hdb3 hdb4 < hdb5 hdb6 >
SL2312 MTD Driver Init.......
sl2312flash_init: value=0x82c22035
sl2312flash_init: value=0x82c22025 after mask
SL2312 CFI Flash: Found 1 x16 devices at 0x0 in 16-bit bank
Amd/Fujitsu Extended Query Table at 0x0040
SL2312 CFI Flash: CFI does not contain boot bank location. Assuming top.
number of CFI chips: 1
cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.
Creating 2 MTD partitions on "SL2312 CFI Flash":
0x00000000-0x00070000 : "SL boot"
0x00070000-0x00080000 : "VCTL"
SL2312 MTD Driver Init Success ......
FTC_FOTG2XX_1 : Init FOTG2XX Driver
Init FOTG2xx driver 
FTC_FOTG2XX_1 : >>> Found FOTG2XX ...
pFTC_OTG_1 c16212a0
hcd->self.controller c16b3c00
hcd end
hcd_buffer_create
ehci-hcd-FOTG2XX-1 ehci-hcd-FOTG2XX-1: new USB bus registered, assigned bus number 1
usb_register_bus
ghcd_FOTG2XX_1 hcd c16b3c00
hcd_irq_For_OTG_1
ehci->caps->length 10, hcd->regs f6900000 , ehci->regs f6900010 
udev->state 1 
drivers/usb/host/ehci-hcd-FOTG2XX-1.c: USB support enabled, EHCI rev 101. 0
Timing on EOF1(0xf6900040) = 0xd
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
FTC_FOTG2XX_1 : >>> +FOTG2XX_get_otg_transceiver_1
FTC_FOTG2XX_1 : registered host c16b3c00
OTG2XX act as HOST only (don't need to wait gadget driver)
+(OTGC_Init_1)
pFTC_OTG_1->otg.default_a=1 
+(OTGC_Init_1)
pFTC_OTG_1->otg.default_a=1 
OTG_enable_VBUS 
FTC_FOTG2XX_1 : >>> Drive VBUS ok...
+OTGP_Close_1()
OTG2XX act as HOST only (remove gadget function)
+OTGH_Open_1()(0x30=0x0)
OTG_enable_VBUS 
mdwOTGC_Control_A_VBUS_VLD_Rd 80000
+OTGP_Close_1()
OTG2XX act as HOST only (remove gadget function)
+OTGH_Open_1()(0x30=0x0)
ehci otg_set_host status 0 
connect_change 1 
clear_bit 
return set_bit
usbcore: registered new driver usblp
drivers/usb/class/usblp.c: v0.13: USB Printer Device Class driver
Initializing USB Mass Storage driver...
usbcore: registered new driver usb-storage
USB Mass Storage support registered.
FTC_FOTG200_udc : Init USB device Lower driver
FOTG200_BASE_ADDRESS = 0xf6800000
******reg_val = a2822025 
FTC_FOTG200_udc : ***** FOTG200 Peripheral 2.0 Test program *****
FTC_FOTG200_udc : L0: System initial, Please wait...
FTC_FOTG200_udc : L1: System is ready(dev->EPUseDMA=0xff)...
FTC_usb_probe end
mice: PS/2 mouse device common for all mice
ipsec_init : cryptographic accelerator 
ipsec tx_desc = ffc10000
ipsec rx_desc = ffc11000
ipsec tx_desc_dma = 016d9000
ipsec rx_desc_dma = 016da000
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 2, 16384 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
TCP bic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
NET: Registered protocol family 5
RAMDISK: Compressed image found at block 0
EXT2-fs warning: checktime reached, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem).
/initrd/linuxrc
=====
SoC arch is FA526id
root device is /dev/hdb2
=====
kjournald starting.  Commit interval 5 seconds
EXT3-fs warning: maximal mount count reached, running e2fsck is recommended
EXT3 FS on hdb5, internal journal
EXT3-fs: mounted filesystem with ordered data mode.
modprobe: cannot parse modules.dep
mount: mounting /dev/sdz1 on /mnt/usb1 failed
mount: mounting /dev/sdz on /mnt/usb1 failed
mount: mounting /dev/scd0 on /mnt/usb1 failed
kjournald starting.  Commit interval 5 seconds
EXT3-fs: mounted filesystem with ordered data mode.
kjournald starting.  Commit interval 5 seconds
EXT3-fs warning: maximal mount count reached, running e2fsck is recommended
EXT3 FS on hdb5, internal journal
EXT3-fs: mounted filesystem with ordered data mode.
mke2fs 1.40-WIP (14-Nov-2006)
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
1280 inodes, 10240 blocks
512 blocks (5.00%) reserved for the super user
First data block=1
2 block groups
8192 blocks per group, 8192 fragments per group
640 inodes per group
Superblock backups stored on blocks: 
 8193

Writing inode tables: 0/21/2done                            
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 25 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

Model Number : ST3500820AS                             
Firmware Rev.: SD3A    
Serial No.   :             XXXXXXXX
This is not Target(S.M.A.R.T. Error)
*** This is not Target ***
*** sghddchk_check : Not Target HDD ***
*** hdb5: hddupstart is not found ***
rmmod: sr_mod: No such file or directory
rmmod: cdrom: No such file or directory
=== linuxrc end
kjournald starting.  Commit interval 5 seconds
EXT3-fs: mounted filesystem with ordered data mode.
VFS: Mounted root (ext3 filesystem) readonly.
Trying to move old root to /initrd ... okay
Freeing init memory: 100K
INIT: version 2.86 booting
Setting parameters of disc: (none).
Activating swap...Adding 2104504k swap on /dev/hdb3.  Priority:-1 extents:1 across:2104504k
done.
Checking root file system...fsck 1.40-WIP (14-Nov-2006)
e2fsck 1.40-WIP (14-Nov-2006)
/dev/hdb2 has been mounted 71 times without being checked, check forced.
Pass 1: Checking inodes, blocks, and sizes
/dev/hdb2: |=                                                       |  1.4%   
/dev/hdb2: |==                                                      /  4.2%   
/dev/hdb2: |=====                                                   -  9.8%   
/dev/hdb2: |=======                                                 \ 12.6%   
/dev/hdb2: |=========                                               | 16.8%   
/dev/hdb2: |=============                                           / 22.4%   
/dev/hdb2: |================                                        - 28.0%   
/dev/hdb2: |================                                        \ 29.4%   
/dev/hdb2: |===================                                     | 33.6%   
/dev/hdb2: |====================                                    / 36.4%   
/dev/hdb2: |======================                                  - 39.2%   
/dev/hdb2: |=======================                                 \ 40.6%   
/dev/hdb2: |========================                                | 43.4%   
/dev/hdb2: |=========================                               / 44.8%   
/dev/hdb2: |==========================                              - 46.2%   
/dev/hdb2: |===========================                             \ 47.6%   
/dev/hdb2: |===========================                             | 49.0%   
/dev/hdb2: |============================                            / 50.4%   
/dev/hdb2: |==============================                          - 53.2%   
/dev/hdb2: |===============================                         \ 54.6%   
/dev/hdb2: |===============================                         | 56.0%   
/dev/hdb2: |================================                        / 57.4%   
/dev/hdb2: |=================================                       - 58.8%   
/dev/hdb2: |===================================                     \ 63.0%   
/dev/hdb2: |=====================================                   | 65.8%   
/dev/hdb2: |======================================                  / 67.2%   
Pass 2: Checking directory structure
/dev/hdb2: |=======================================                 - 70.4%   
/dev/hdb2: |========================================                \ 71.1%   
/dev/hdb2: |========================================                | 71.7%   
/dev/hdb2: |=========================================               / 73.2%   
/dev/hdb2: |=========================================               - 74.1%   
/dev/hdb2: |==========================================              \ 75.3%   
/dev/hdb2: |===========================================             | 76.5%   
/dev/hdb2: |============================================            / 77.8%   
/dev/hdb2: |============================================            - 78.0%   
/dev/hdb2: |============================================            \ 78.1%   
/dev/hdb2: |============================================            | 79.3%   
/dev/hdb2: |=============================================           / 79.7%   
/dev/hdb2: |=============================================           - 79.8%   
/dev/hdb2: |=============================================           \ 80.5%   
/dev/hdb2: |=============================================           | 80.6%   
/dev/hdb2: |=============================================           / 80.8%   
/dev/hdb2: |=============================================           - 80.9%   
/dev/hdb2: |=============================================           \ 81.0%   
/dev/hdb2: |=============================================           | 81.1%   
/dev/hdb2: |==============================================          / 81.3%   
/dev/hdb2: |==============================================          - 82.1%   
/dev/hdb2: |==============================================          \ 82.8%   
/dev/hdb2: |===============================================         | 83.1%   
/dev/hdb2: |===============================================         / 83.3%   
/dev/hdb2: |===============================================         - 83.6%   
/dev/hdb2: |===============================================         \ 83.9%   
/dev/hdb2: |===============================================         | 84.0%   
/dev/hdb2: |===============================================         / 84.2%   
/dev/hdb2: |===============================================         - 84.4%   
/dev/hdb2: |===============================================         \ 84.5%   
/dev/hdb2: |===============================================         | 84.8%   
/dev/hdb2: |================================================        / 85.0%   
/dev/hdb2: |================================================        - 85.1%   
/dev/hdb2: |================================================        \ 85.2%   
/dev/hdb2: |================================================        | 85.3%   
/dev/hdb2: |================================================        / 86.1%   
/dev/hdb2: |================================================        - 86.6%   
/dev/hdb2: |=================================================       \ 86.8%   
/dev/hdb2: |=================================================       | 87.5%   
/dev/hdb2: |=================================================       / 88.4%   
/dev/hdb2: |==================================================       -89.5%   
Pass 3: Checking directory connectivity
/dev/hdb2: |===================================================\92.0%   
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/hdb2: |======================================================   | 97.1%   
/dev/hdb2: |======================================================== | 99.9%   
/dev/hdb2: 10912/51600 files (1.5% non-contiguous), 219403/409601 blocks
done.
EXT3 FS on hdb2, internal journal
Setting the system clock..
Cleaning up ifupdown....
Loading kernel modules...done.
Loading device-mapper support.
Checking file systems...fsck 1.40-WIP (14-Nov-2006)
done.
Setting kernel variables...done.
Mounting local filesystems...kjournald starting.  Commit interval 5 seconds
EXT3-fs: mounted filesystem with ordered data mode.
kjournald starting.  Commit interval 5 seconds
EXT3-fs warning: maximal mount count reached, running e2fsck is recommended
EXT3 FS on hdb5, internal journal
EXT3-fs: mounted filesystem with ordered data mode.
XFS mounting filesystem hdb6
Starting XFS recovery on filesystem: hdb6 (logdev: internal)
Ending XFS recovery on filesystem: hdb6 (logdev: internal)
Using fallback suid method
done.
Activating swapfile swap...done.
Setting up networking....
Starting hotplug subsystem:
pci     
pci      [success]
usb     
usb      [success]
isapnp  
isapnp   [success]
ide     
ide      [success]
input   
input    [success]
scsi    
scsi     [success]
done.
Configuring network interfaces...GMAC-0 Addr 1 Vendor ID: XXXXXXXXXX
mii_write: phy_addr=0x1 reg_addr=0x4 value=0x5e1 
mii_write: phy_addr=0x1 reg_addr=0x9 value=0x300 
mii_write: phy_addr=0x1 reg_addr=0x18 value=0x41 
mii_write: phy_addr=0x1 reg_addr=0x0 value=0x9200 
mii_write: phy_addr=0x1 reg_addr=0x0 value=0x1200 
Link Up (0x796d) MII REG 10 = 0x2800
1000M/Full 
Flow Control Enable.
Storlink eth0 address = XXXXXXXXXXXX
Enable MAC Flow Control...
Using fallback suid method
info, udhcpc (v0.9.9-pre+autoip) started
SIOCSIFFLAGS: Cannot assign requested address
SIOCSIFADDR: File exists
SIOCSIFFLAGS: Cannot assign requested address
SIOCSIFFLAGS: Cannot assign requested address
debug, Sending discover...
debug, Sending select for 192.168.XXX.XXX..
info, Lease of 192.168.XXX.XXX obtained, lease time 3600
SIOCSIFFLAGS: Cannot assign requested address
deleting routers
SIOCDELRT: No such process
adding dns 192.168.XXX.XXX
done.
hdb: dma_timer_expiry: dma status == 0x41
hdb: dma_intr: status=0x71 { DriveReady DeviceFault SeekComplete Error }
hdb: dma_intr: error=0x04 { DriveStatusError }
ide: failed opcode was: unknown
hda: DMA disabled
hdb: DMA disabled
ide0: reset timed-out, status=0xb0
hdb: status timeout: status=0xb0 { Busy }
ide: failed opcode was: unknown
hdb: drive not ready for command
ide0: reset timed-out, status=0xb0
end_request: I/O error, dev hdb, sector 871610
end_request: I/O error, dev hdb, sector 5671944
Buffer I/O error on device hdb5, logical block 499
lost page write due to I/O error on hdb5
end_request: I/O error, dev hdb, sector 643436
end_request: I/O error, dev hdb, sector 5671946
end_request: I/O error, dev hdb, sector 5671948
end_request: I/O error, dev hdb, sector 5671950
journal_bmap: journal block not found at offset 268 on hdb2
Aborting journal on device hdb2.
end_request: I/O error, dev hdb, sector 642896
Buffer I/O error on device hdb2, logical block 148
lost page write due to I/O error on hdb2
end_request: I/O error, dev hdb, sector 5671952
Buffer I/O error on device hdb5, logical block 503
lost page write due to I/O error on hdb5
end_request: I/O error, dev hdb, sector 643426
end_request: I/O error, dev hdb, sector 643428
end_request: I/O error, dev hdb, sector 643430
end_request: I/O error, dev hdb, sector 643432
Aborting journal on device hdb5.
end_request: I/O error, dev hdb, sector 871610
do_generic_mapping_read page not uptodate twice, error=--EIO!!!
ext3_abort called.
EXT3-fs error (device hdb2): ext3_journal_start_sb: Detected aborted journal
Remounting filesystem read-only
journal commit I/O error
/etc/rcS.d/S46mountnfs-bootclean.sh: /etc/rcS.d/S46mountnfs-bootclean.sh: Input/output error
end_request: I/O error, dev hdb, sector 1314360
Buffer I/O error on device hdb2, logical block 335880
lost page write due to I/O error on hdb2
end_request: I/O error, dev hdb, sector 822832
Buffer I/O error on device hdb2, logical block 90116
lost page write due to I/O error on hdb2
end_request: I/O error, dev hdb, sector 839256
Buffer I/O error on device hdb2, logical block 98328
lost page write due to I/O error on hdb2
end_request: I/O error, dev hdb, sector 839306
Buffer I/O error on device hdb2, logical block 98353
lost page write due to I/O error on hdb2
end_request: I/O error, dev hdb, sector 1314398
Buffer I/O error on device hdb2, logical block 335899
lost page write due to I/O error on hdb2
ext3_abort called.
EXT3-fs error (device hdb2): ext3_remount: Abort forced by user
ext3_abort called.
EXT3-fs error (device hdb2): ext3_remount: Abort forced by user
end_request: I/O error, dev hdb, sector 1200314
end_request: I/O error, dev hdb, sector 1200314
do_generic_mapping_read page not uptodate twice, error=--EIO!!!
end_request: I/O error, dev hdb, sector 871414
end_request: I/O error, dev hdb, sector 871414
do_generic_mapping_read page not uptodate twice, error=--EIO!!!
/etc/rcS.d/S55bootmisc.sh: /etc/rcS.d/S55bootmisc.sh: Input/output error
end_request: I/O error, dev hdb, sector 871398
end_request: I/O error, dev hdb, sector 871398
do_generic_mapping_read page not uptodate twice, error=--EIO!!!
end_request: I/O error, dev hdb, sector 871398
do_generic_mapping_read page not uptodate twice, error=--EIO!!!
/etc/init.d/rc: line 78: /etc/rcS.d/S55urandom: Input/output error
end_request: I/O error, dev hdb, sector 5972010
EXT3-fs error (device hdb5): ext3_find_entry: reading directory #69268 offset 0
end_request: I/O error, dev hdb, sector 5670948
Buffer I/O error on device hdb5, logical block 1
lost page write due to I/O error on hdb5
ext3_abort called.

結果としては、システムの動作が非常に不安定な状態のため、シリアルコンソールからのアクセスも困難な状態でした。ここは諦めて別の方法を検討することにしました。


デスクトップPCを使って、ファイルを取り出す

knoppix DVDを使って必要なファイルを取り出すために、HDL-GS500からHDDを取り出して、デスクトップPCのSATAに接続しました。このときHDDの間違いを避けるために、デスクトップPCに搭載しているHDDの接続は取り外しておきました

knoppixを起動したら端末を立ち上げて、あらかじめsu -rootになっておきます。またファイルの保存先としてUSBメモリを接続しておきます。

最初の状態としては

/dev/sda にHDL-GS500のHDD
/dev/sdb にUSBメモリ 
が接続されている状態です。

USBメモリのマウントポイントを作成して、マウントします。

# mkdir /media/usb
# mount /dev/sdb1 /media/usb

HDDをマウントします。マウントポイントは既にあったものを使いました。

# mount /dev/sda1 /media/sda1
# mount /dev/sda2 /media/sda2
# mount /dev/sda5 /media/sda5

HDDのパーティションの状態を調べます。

~# fdisk -l /dev/sda

Disk /dev/sda: 500.1 GB, 500107862016 bytes
255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xee4739c6

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1           16065      642599      313267+  83  Linux
/dev/sda2          642600     1461914      409657+  83  Linux
/dev/sda3         1461915     5670944     2104515   82  Linux swap / Solaris
/dev/sda4         5670945   976559219   485444137+   5  Extended
/dev/sda5         5670946     6088634      208844+  83  Linux
/dev/sda6         6088636   976559219   485235292   83  Linux
パーティション情報はうまく読み出すことができました。

続いて、マスターブートレコード(MBR)と、拡張パーティションブートレコード(Extended Partition Boot Record)をUSBメモリに保存しておきます。ddコマンドを使います。

# dd if=/dev/sda of=/media/usb/mbr1.bin bs=512 count=1
# dd if=/dev/sda of=/media/usb/mbr2.bin bs=512 count=1 skip=5670945
# dd if=/dev/sda of=/media/usb/mbr3.bin bs=512 count=1 skip=6088635
  • mbr1.bin には sda1,sda2,sda3,sda4
  • mbr2.bin には sda5
  • mbr3.bin には sda6
のパーティション情報が保存されます。

引き続き、各パーティションの内容を保存します。ここでうまくいけば、新しいHDDをパーティショニング後にファイルシステムを作成して、このファイルを展開すれば、システムを復元することができそうです。

# cd /media/sda1
# tar cvf /media/usb/hdd1.tar ./
 
# cd /media/sda2
# tar cvf /media/usb/hdd2.tar ./
 
# cd /media/sda5
# tar cvf /media/usb/hdd5.tar ./
結果は、sda1の保存には成功しましたが、sda2、sda5は途中でエラーが出てしまい、読み出すことができませんでした。

だんだん選択肢が消えていきます。この後は、保存に成功したsda1の初期化用のファイルを使ってシステムの修復を進めることにしました。

USBメモリに保存できたhdd1.tarを展開してみたところ、.landiskディレクトリの中に、再セットアップに必要な初期化用のファイル、sd1.tgz, sd2.tgz, sd5.tgz, sd6.tgz, tar2diskがありました。更にsd1.tgz, sd2.tgz, sd5.tgz, sd6.tgzの中身も無事に展開できました。

以降の修復作業には、この初期化用ファイルを使って進めることができるようになりました。これで一歩前進となりました。


この後の計画

ここまでの結果から、今後の計画を考えました。

  1. 新しいHDDを買ってくる。
  2. 新しいHDDをパーティショニング。
  3. 新しいHDDにファイルシステムを作成、フォーマット。
  4. 初期化ファイルを使い、新しいHDDにsda1, sda2, sda5, sda6を再構築。
  5. 新HDDで組立て。HDL-GS500が起動できることを確認する。
  6. 新HDDを取出し、旧HDDと共にPCへSATA接続。
  7. 旧HDDのsda6を、新HDDのsda6にコピーする。
  8. 新HDDで再組立て。
  9. HDL-GS500を起動して、保存しているデータのバックアップを取る。
これでうまくいけばいいのですが…

この後は、その2へ続きます。

その2
壊れたHDDを、Advanced FormatのHDDに交換。
その3
GNU ddrescueを使って、壊れたHDDからデーターを救出。
その4
HDL-GS500を、1.0TBに換装して再初期化する。



ここまでに参考にさせていただいたWebサイトです。とても参考になりました,ありがとうございます。

洗脳電波発信装置 換装なの☆です
digital西行庵 wiki HDL-GS petit hack

2012年8月23日木曜日

アンテナ・アンプを製作

に続いて、WSMLアンテナのアンテナ・アンプ・ユニットを作りました。

アンテナ・アンプへの電源供給方法は同軸重畳です。この部分に前回製作した DC 重畳ユニットを使います。 トランジスタは手持ち品の PN2222A の中から hFE を選別して値を揃えたものを使用しました。 出力トランスは FT50-#77 の 5 回巻きを使っています。 また、オリジナルの回路図に入っている、入力部の FM 放送対策用 LPF は省略しました。アンプ部の部品配置はバランスを考慮して対象配置を心がけました。汎用の穴あき基板を使用しているので、べたグラウンドの部分は銅箔テープを使っています。



差動部分のバランス調整

拙宅のロケーションでは、そこそこの強電界のため WSML アンテナを IC-R75 に接続すると下記のような受信レベルになります。

  • KBS京都    1143kHz   10kW S9+50dB
  • NHK京都第1 621kHz    1kW S9+40dB
  • NHK大阪第1 666kHz 100kW S9+40dB
  • NHK大阪第2 828kHz 300kW S9+40dB

このような状態では相互変調ひずみによって、あちらこちらにオバケが出現します。そこで、アンテナ・アンプのバランス調整を行い、この相互変調ひずみを可能な限り小さくする必要があります。

この調整は、おじさん工房の汎用実験基板APB-1のアプリケーションのひとつの、信号発生器を使った DSB 変調出力によって行ないました。

元々この DSB 変調出力は 2 信号特性を測定するものでは無いため、ある程度のスプリアスを含んでいます。今回の調整作業は IM3 の測定が目的で無いことと、手持ちの環境内で可能な範囲と割り切って IM3 のレベル調整ができればよいと考えました。

APB-1 の DSB 変調出力では出力レベルの調整ができません。この場合は外付けアッテネータを使用します。次の図は 20dB アッテネータを経由した出力です。

この出力を使って 3 次相互変調ひずみ(IM3)を調整していきます。

SG 出力を、即席の 20dB アッテネータとトランスを経由して WSML アンテナ・アンプに接続しています。

基板上のバランス調整用の VR を調整して、IM3 が最小になるポイントに調整します。

上記 4 局の放送周波数に対する相互変調の組み合わせと高調波周波数の表を作り、それぞれの受信レベルを IC-R75 を使って調べてみました。

バランス調整を行なった結果では IM3 は概ね低減できているようです。今のところ地元局の 2 次高調波がまだ大きい状態です。特に 1143kHz の KBS 京都はスーパーローカルなのでとても強力です。これは今後の課題です。



アンテナの設置状況

ループ・アンテナとアンテナ・アンプは、このように設置しています。アンプ部の雨除け用として 100 円タッパーを被せました。



参考