ぶっちゃけた話、SBP-2はIEEE1394バスにSCSIコマンドを流す規格と考えると気分が楽です。もともとはSCSIにべったりだった、Serial Bus Protocol (SBP)というのがあって、その後「SCSIなど」もっと一般のコマンドセットに対応(拡張ではない)したSerial Bus Protocol 2 (SBP-2)が規格化され、現在世の中に出回っているのは後者です。SBPとSBP-2とは別物として捉えて規格書にはあたるべきです。基本構造が全然違うことを反映するごとく、たとえばCDSとORBのように、用語からしてだいぶ違います。厳密には「SCSIコマンドセットを用いるSBP-2デバイス」⊂「SBP-2デバイス」なのであって、「前者」=「後者」ではありません。では特定のノードがSBP-2デバイスであるか判断するにはどうすればよいかというと、Configuration ROMのUnit directoryを見れば良い訳です(SBP-2仕様書chanpter7 & Annex D参照)。Configuration ROMの読み方についてはSBP-2デバイスのConfiguration ROMを参照してください。
Key 14hはあったり無かったりしますが
規格上はSCSI同様、ノード間は対等なのですが、通常は1394OHCIの挿さったPCとSBP-2デバイスがあって、アプリケーション上は前者が後者を制御する形となっています。そこで、以下では前者を(1394)OHCI側、後者をSBP-2デバイス側と表記します。1394OHCIとSBP-2デバイスとのニゴシエーションはOHCI側に作成したORBの所在を知らせることで行います。ORBとは、Operation request blockの頭字語で、SBP-2でのノード間のやり取りに必要な情報を含んだ構造体をいいます。たとえばSCSIコマンドはCommand ORBに記載します。
ノードIDがPC、ドライブに振られた時点では、ソフトウェアはSBP-2デバイスのどのメモリアドレスに、OHCI側に作成したCommand ORBの所在を送ればSCSIコマンドとして実行してもらえるかわかりません。そのためにいわばSBP-2デバイス側の窓口の所在を得る作業がLoginです。Login ORBをOHCI側のメモリ中に作成し、SBP-2デバイス側にとってきてもらいます。IEEE1394共通の仕様で定められたConfiguration ROMのUnit directoryのkey 54h(csr_offset)にはManagement Registerの所在が記されています。例えば、キー54hの値が004000hだったとすると、quadlet単位でのオフセットなので、4倍して10000hとなり、レジスタ空間でのオフセットだからFFFF F001 0000hからになります。ここにLogin ORBが存在するOHCI側のメモリアドレスが書かれた8byteきっかりを出力します。(この際、OHCIのnode IDはパケットのヘッダから分かるので、書く必要はありません。)そうするとSBP-2デバイスがLogin ORBを取りにきて、Command BlockのアドレスやLogin IDなどを返してきます。Command Blockはいくつかのレジスタがあり、その中にSCSIコマンドを送るためのレジスタがあるわけです。なんでこう言うややこしい作業を経るのかは、想像するに、IEEE1394の広大なネットワークが出来たときに、間違ったコマンドとかに応答しないようにするためではないかと。
Login時には他にOHCI側、つまりPCのメモリに確保したSTATUS FIFOのアドレスも指定します。これはLogin時のstatusだけではなくて、Command ORB実行後など、当該Loginがあって始めて可能となった命令により起こった状態をSBP-2デバイスが書きこむ、OHCI側の窓口となります。なお、STATUS_FIFOにはCommand ORBでSCSIコマンドを実行させた場合はRequest Senceの実行結果を弄くったものが返ってきます。ちなみに、この直後にRequest Senceを発行するとどうなるか?OXFW911の場合、実はRequest Sence発行済みという扱いで無内容なデータが返ってきます。STATUS FIFOにRequest Senceの結果が返ってくるのは余計なお世話とも取れますが、デバイス制御の手間が減るので親切だと受けとめておいてもいいんじゃないでしょうか。ASPIの場合わざわざRequest Senceを発行しないと行けないんですからね。ただ、Request Senceの結果を弄くらないでそのまま返してくれるような事は出来なかったんですかね。
まず、先ほどLoginで得たSBP-2デバイス側のCommand Blockのオフセット+04hにあるAGENT_RESETに適当な値をQuadlet Writeで書きこんでFetch Agentをリセットしてあげます。つぎに、ソフトウェアはメモリ中にSCSIコマンド、転送先などの必要な情報が含まれるCommand ORBを作成します。SBP-2デバイス側のCommand Blockのオフセット+08hにあるORB PointerにORBのアドレスを8バイトきっかりで書きこみます。そうすると後は勝手に事が進みます。2回目以降のCommand ORBからはアドレスを知らせる方法が2つあります。まず、直接ORB Pointerに1回目のCommand ORBと同様にORBのアドレスを送りつける方法がシンプルです。他には、Fetch Agentは最後に実行したORB、つまりNext ORB PointerがNull PointerであったORBのアドレスを記憶しているので、当該ORBのNext ORB Pointerを更新して、それが指すメモリアドレスに別のORBを作成し、+10hにあるDoorbellを鳴らす(何か適当なQuadletを書きこむ)方法があります。後者の場合は、元のORBはORB Pointerとしての機能のみを担い、元のORBのコマンドが再度実行されるわけではありません。
バスリセット後、現在のLoginの状態を回復します。バスリセットの直後はノードIDが変わるという大変動があり、各ノードはいわば大震災直後の迷子のようになり、相手方はどこへ行ったのかという大混乱状態になります。ただ、Login時にはSBP-2デバイスはOHCIのConfigration ROMを読みこんでOHCIのEUI64を記録しておくこととなっています。また、Login時にはOHCI側はSBP-2デバイスに対し、バスリセット後何秒かはLoginの状態を記憶してReconnect要求に応えられるようにしておくように要求しておきます。特に、eXclusive bitを立てていた場合は、正常な排他Loginの意味だけでなく、バスリセット後Reconnect待ちの間、他のLoginに応答しないようにという要求も含みます。震災の例で行くと、「離れ離れになった後1年間は結婚しないで待っていてくれ」というようなものです。しかしバスリセット前にLoginしていたという証明をしないと駄目で、最低限Login IDというLoginの時にもらったデータをReconnect ORBに記述しないと駄目なんです。要するに、待っててくれという要求をした相手の顔までは覚えてくれていないという。(^^;;;SBP-2デバイスの (Loginの時と同じように) Management registerにそうして作成したReconnect ORBのアドレスを送りつけます。
これまた困った話で、コンピュータ本体のリセット時に再起動前のLogin IDなんぞ知りようが無いわけです。コンピュータ本体はリセットしても、1394バスはリセットされないので、Login IDが分からない以上、ASPIなり、ドライバが読みこまれた直後、期限切れになるまで待たないと行けないわけです。しかし、その期限切れも実はLogin時に長くも短くも出来るため、いつまで待てば良いのか分かりません。こう言う意味で面倒くさいので、期限切れを待たずにLoginをしようとするとどうか。実はSBP-2の規格書にはそれなりに書いてあるのですが、OXFW911では受けつけてしまったり、S1R72805F00A1ではリジェクトしつつもLogin Responseを返して来たりします。しかし、応答はResource unavailableとするところを09h(Reject)として来たりしてまちまちです。各ノードが内部リセット時にはリセットしたぞとバスにパケットをブロードキャストしておくような仕様であったなら、良かったんではないか。震災の例で行くと死亡通知見たいのをよこすということです。もう一つ、ノードIDが変わってしまうのだから、SBP-2に限らず、Login IDとともにEUI64をLoginしていたOHCIが指定してブロードキャストしてReconnectできる仕様にしておく方が従来の接続状態の維持という観点からは望ましかったのではないかと思うわけですけど。(Reconnect時にノードIDを取得するように)