電源連動 USB HDD の切断・再接続を CLI で
さいきんの外付けハードディスクは電源連動機能とかついてたりしますね。んで,たとえば REGZA とかにつなぐと,テレビの電源を on にしたときだけハードディスクの電源が on になったりします。
同じようなことを Linux からもやってみたい。
といっても PC の電源を切ったらハードディスクの電源が切れるのは当たり前。PC の電源を入れっぱなし HDD 接続しっぱなしで,ソフトウェア的に HDD の電源を入れたり切ったりできたらいいなぁと思いやってみました。
もしうまくできれば,たとえば定時バックアップの際だけハードディスクの電源を入れて,バックアップが終わったら電源を切るとかできそう。かえって寿命が落ちるかもしんないけど。
調べてみたら,またたびりなっくす UbuntuでのUSBメディアの安全な取り外し とかその元ネタの Yan Li's Words: Safely remove an USB hard drive in Linux とかですでにやられてました。再接続までコミでやってるのはなかったので一応記事におこしておきます。
実験環境は下記の通り。
- OS: Ubuntu 10.04 (Lucid Lynx) Kernel 2.6.32(-23) i386 pae
- PC: Dell Inspiron mini10v
- USB HDD: IO-DATA HDCR-U シリーズ
切断編
前提として,アンマウント済みになってるとする。
1. 下調べ
いくつか知っておく必要のある ID がある。
udevadm
というコマンドを使うと,デバイスノードパスからこれらの情報を取得することができる。今回の例だと HDD が /dev/sdc
にぶらさがっているとする。
$ sudo udevadm info --query=path --name=/dev/sdc /devices/pci0000:00/0000:00:1d.7/usb1/1-8/1-8:1.0/host3/target3:0:0/3:0:0:0/block/sdc
出力結果のうち
1-8
ってところが,USB のバス ID = 1, デバイス ID = 8 であることを示している3:0:0:0
ってところが SCSI のホスト ID = 3, チャネル = 0, デバイス ID = 0, LUN = 0 であることを示している
ちなみに,SCSI デバイスとしての各種 ID を知りたいだけなら /proc/scsi/scsi
の中身を見てもわかる。
$ cat /proc/scsi/scsi Attached devices: Host: scsi0 Channel: 00 Id: 00 Lun: 00 Vendor: ATA Model: WDC WD1600BEVT-7 Rev: 11.0 Type: Direct-Access ANSI SCSI revision: 05 Host: scsi2 Channel: 00 Id: 00 Lun: 00 Vendor: Generic- Model: Multi-Card Rev: 1.00 Type: Direct-Access ANSI SCSI revision: 00 Host: scsi3 Channel: 00 Id: 00 Lun: 00 Vendor: I-O DATA Model: HDCR-U Rev: Type: Direct-Access ANSI SCSI revision: 02
2. HDD へのフラッシュ(強制書込)
OS 側がアンマウントしていても,HDD 内部のキャッシュ内容がフラッシュされていない可能性がある(らしい)ので強制的にフラッシュする。非標準コマンドの sdparm
というコマンドを使うので apt-get などでインストールしておくこと。
$ sudo sdparm --command=sync /dev/sdc /dev/sdc: I-O DATA HDCR-U
んー。非同期で実行されている気もする。フラッシュが終了してるという確証はどうやったら得られるのだろう。
ちなみにたいていのディストリビューションで標準的にインストールされてる hdparm
の -f
コマンドも同じようなことができそうだけど,man 読んだ感じだと,あれは OS 側のバッファキャッシュをフラッシュするためのコマンドのような気がする。
さらに,同じコマンドを使ってデバイス(HDD)のスピンダウンを行うこともできるらしい。
$ sudo sdparm --command=stop /dev/sdc
だけど,手持ちの IO-DATA の HDCR-U だと,一度スピンダウンするもののそのあと再びすぐにスピンアップしてしまい意味がなかった。逆に壊れるんじゃないかと怖くなった。
3. SCSI サブシステムから切り離し
んで,いままでのコマンドはデバイスノードパス対象のコマンドだったんだけど,もう必要ない,というかデバイスノード経由でアクセスできると危ないので,切り離す。
切り離す前。
$ ls /dev/sd* /dev/sda /dev/sda1 /dev/sda2 /dev/sda3 /dev/sdb /dev/sdc /dev/sdc1
いままでの実行例でわかるとおり,USB HDD のデバイス名は /dev/sdc*
。
さきほど調べた SCSI デバイスとしてのホスト ID 等をパラメータとして指定しつつ /proc
ファイルシステムに下記のようなテキストを書き込む。
$ echo 'scsi remove-single-device 3 0 0 0' | sudo tee /proc/scsi/scsi
あ,tee
コマンドを使っているのは,今回の環境例が Ubuntu であり root 権限でコマンドを実行するには sudo 使うから。簡単に言うと,root 権限で
# echo 'scsi remove-single-device 3 0 0 0' > /proc/scsi/scsi
というのを実行しているのとほぼ同義。これをそのまま sudo でラップしてもリダイレクトしているのは一般ユーザ権限になってしまいうまくいかないので,tee コマンドを利用して root 権限でパイプ書込をしている。
ともかく,このようにすると,
$ ls /dev/sd* /dev/sda /dev/sda1 /dev/sda2 /dev/sda3 /dev/sdb
見事 /dev/sdc*
のデバイスノードが消えた。
4. USB パワーを落とす
いよいよ USB デバイスのパワーを落とす。
$ echo 'suspend' | sudo tee /sys/bus/usb/devices/1-8/power/level
これを実行したしばらくのち((IO-DATA の USB HDD の場合,だからかと思ったんだけど,ひょっとすると /sys/bus/usb/devices/*/power/autosuspend
のデフォルト値 2 が影響したのかもしれない。ちょっと未検証でわからん。see Manual driver binding and unbinding [LWN.net]))に実際にパワーが切れた。感動。
一番最初にあげた文献の例だとこれを行うまえに次で例示してある「USB サブシステムからの切り離し」をおこなっているんだけど,実際にはこの順序にしないと,後述する再接続ができなかった。
あと,この suspend
というコマンドトークンで USB 電源を切るのは,カーネルバージョン 2.6.32(つまり Ubuntu Lucid のカーネルバージョンだ)以下でしか使えないらしい。
2.6.33 以上だと /sys/bus/usb/devices/*/remove
というノードが新設されたのかな*1。ちょっとよくわからんです。
5. USB サブシステムから切り離し
OS の USB サブシステムから切り離す(ってこういう表現で合っているかもわかんないけど)。
$ echo -n '1-8' | sudo tee /sys/bus/usb/drivers/usb/unbind
再接続編
以上のようにして切断した USB HDD をつないだまま再接続(パワー on)するには,いままでの過程の逆をおこなえばよい。
まず USB サブシステムへの再接続(再登録)を行う。
$ echo -n '1-8' | sudo tee /sys/bus/usb/drivers/usb/bind
このとき以下のようなカーネルメッセージを吐くことがある。
usb 1-8: configuration #1 chosen from 1 choice usb 1-8: can't set config #1, error -1
対処方法がわかんないので無視する。IO-DATA の USB HDD だから出たってこともないみたい。たしか USB メモリスティックでも出力された気がする。
次に USB パワーを上げる。
$ echo 'on' | sudo tee /sys/bus/usb/devices/1-8/power/level
なおいままでのシーケンスの順序(USB サブシステムからの切断とパワーオフの順序とか)がよくないと下記のようなカーネルメッセージを吐いてうまくいかないことがある。
/sys/bus/usb/devices/1-8/power/level: Transport endpoint is not connected
そんなときは物理的に USB から外して再接続してやり直してみること。
SCSI サブシステムへ再接続する。
$ echo 'scsi add-single-device 3 0 0 0' | sudo tee /proc/scsi/scsi
すると(通常 HDD を USB で接続したときのように)下記のようなカーネルメッセージが表示される。
scsi 3:0:0:0: Direct-Access I-O DATA HDCR-U PQ: 0 ANSI: 2 CCS sd 3:0:0:0: Attached scsi generic sg2 type 0 sd 3:0:0:0: [sdc] 1953525168 512-byte logical blocks: (1.00 TB/931 GiB) sd 3:0:0:0: [sdc] Write Protect is off sd 3:0:0:0: [sdc] Mode Sense: 3c 00 00 00 sd 3:0:0:0: [sdc] Assuming drive cache: write through sd 3:0:0:0: [sdc] Assuming drive cache: write through sdc: sdc1 sd 3:0:0:0: [sdc] Assuming drive cache: write through sd 3:0:0:0: [sdc] Attached SCSI disk
で,実際にデバイスノードも生成される。
$ ls /dev/sd* /dev/sda /dev/sda1 /dev/sda2 /dev/sda3 /dev/sdb /dev/sdc /dev/sdc1
あとはマウントするなりなんなり。めでたしめでたし。
課題
再接続編を見ればわかるとおり,再接続時においてもともと接続されていたときの SCSI サブシステム上のバス ID や USB サブシステム上のバス ID とかがわかっていることが前提となっている。これらをなんとか sysfs や procfs 経由で取得できればなぁと思う。
今回使った USB HDD。ファンレスなのはうれしいけど,電源投入後スピンアップするまでがちょっと遅いのとうるさい(ゴゴゴゴっていう)気がする。採用ドライブの個性で個体差ありそうだけど。
本文と関係ないけど,センチュリーの裸族のお立ち台って電源連動機能なかったなぁ(実際にはクーリングファンつきの eSATA プラスには電源連動機能がついてる),電源連動機能つきのああいうのがあれば REGZA 用に使いたいなぁ,と思ってたら,玄人志向のやつは電源連動があるっぽい。レビューがほとんどないのが不安。あと,HDD にアダプタつける形になるのかな?よくわからん。