CAM_CDBPARSE(3)

名称
csio_build, csio_build_visit, csio_decode, csio_decode_visit, buff_decode, buff_decode_visit, csio_encode, csio_encode_visit, buff_encode_visit - CAM ユーザライブラリ SCSI バッファパーズルーチン

ライブラリ
libcam

書式
<stdio.h> <camlib.h> int csio_build(struct ccb_scsiio *csio, u_int8_t *data_ptr, u_int32_t dxfer_len, u_int32_t flags, int retry_count, int timeout, char *cmd_spec, ...) int csio_build_visit(struct ccb_scsiio *csio, u_int8_t *data_ptr, u_int32_t dxfer_len, u_int32_t flags, int retry_count, int timeout, char *cmd_spec, int (*arg_get)(void *hook, char *field_name), void *gethook) int csio_decode(struct ccb_scsiio *csio, char *fmt, ...) int csio_decode_visit(struct ccb_scsiio *csio, char *fmt, void (*arg_put)(void *hook, int letter, void *val, int count, char *name), void *puthook) int buff_decode(u_int8_t *buff, size_t len, char *fmt, ...) int buff_decode_visit(u_int8_t *buff, size_t len, char *fmt, void (*arg_put)(void *, int, void *, int, char *), void *puthook) int csio_encode(struct ccb_scsiio *csio, char *fmt, ...) int csio_encode_visit(struct ccb_scsiio *csio, char *fmt, int (*arg_get)(void *hook, char *field_name), void *gethook) int buff_encode_visit(u_int8_t *buff, size_t len, char *fmt, int (*arg_get)(void *hook, char *field_name), void *gethook)

解説
CAM バッファ /CDB エンコードおよびデコードルーチンは、古い FreeBSD SCSI レイヤの、類似した名前の scsireq_* 関数で書かれたユーザランド SCSI アプリケーションに対し、比較的簡単に新しいインタフェースへの 移行できる道筋を提供します。

これらの関数は、新しいアプリケーションで使っても構いませんが、 ユーザは、 cam(3) ライブラリに組み入れられた関数を構築する各種 SCSI CCB 構築関数を 使用する方が簡単だということに気づくでしょう ( たとえば、 cam_fill_csio(), scsi_start_stop(), csi_read_write() です)。

csio_build() は、変数引数リストに提供された情報をもとにして ccb_scsiio 構造体を構築します。この関数は、この関数に渡される NULL の data_ptrt 引数を整然と処理します。

dxfer_len は、データフェーズの長さです。データ転送の方向は flags 引数によって決まります。

data_ptr は、 SCSI データフェーズの間に使用されるデータバッファです。問題の SCSI コマンドについてデータが転送されない場合は、これを NULL に設定する 必要があります。コマンドについて転送するデータがある場合は、このバッファは 少なくとも dxfer_len の長さでなければなりません。

flags は <cam/cam_ccb.h> に定義されたフラグでなければなりません。

    /* 共通の CCB ヘッダ */
    /* CAM CCB フラグ */
    typedef enum {
         CAM_CDB_POINTER       = 0x00000001,/* CDB フィールドはポインタである */
         CAM_QUEUE_ENABLE      = 0x00000002,/* SIM 待ち行列処置は有効である */
         CAM_CDB_LINKED        = 0x00000004,/* CCB はリンクした CDB を含む */
         CAM_SCATTER_VALID     = 0x00000010,/* 分散/収集リストは有効である */
         CAM_DIS_AUTOSENSE     = 0x00000020,/* 自動探知機能を無効にする */
         CAM_DIR_RESV          = 0x00000000,/* データ方向 (00:予約済み) */
         CAM_DIR_IN            = 0x00000040,/* データ方向 (01:DATA IN) */
         CAM_DIR_OUT           = 0x00000080,/* データ方向 (10:DATA OUT) */
         CAM_DIR_NONE          = 0x000000C0,/* データ方向 (11:データなし) */
         CAM_DIR_MASK          = 0x000000C0,/* データ方向マスク */
         CAM_SOFT_RST_OP       = 0x00000100,/* 代わりにソフトリセットを使用する */
         CAM_ENG_SYNC          = 0x00000200,/* 完了時に剰余バイトをフラッシュする */
         CAM_DEV_QFRZDIS       = 0x00000400,/* DEV Q 凍結を無効にする */
         CAM_DEV_QFREEZE       = 0x00000800,/* 実行時に DEV Q を凍結する */
         CAM_HIGH_POWER        = 0x00001000,/* コマンドは大量の能力を得る */
         CAM_SENSE_PTR         = 0x00002000,/* センスデータはポインタである */
         CAM_SENSE_PHYS        = 0x00004000,/* センスポインタは物理的なアドレス */
         CAM_TAG_ACTION_VALID  = 0x00008000,/* この ccb 内ではタグ処置を使用する */
         CAM_PASS_ERR_RECOVER  = 0x00010000,/* 受け渡しドライバエラー。回復 */
         CAM_DIS_DISCONNECT    = 0x00020000,/* 切断を無効にする */
         CAM_SG_LIST_PHYS      = 0x00040000,/* SG リストに物理アドレスがある */
         CAM_MSG_BUF_PHYS      = 0x00080000,/* メッセージバッファ ptr が物理的である */
         CAM_SNS_BUF_PHYS      = 0x00100000,/* 自動探知データ ptr が物理的である */
         CAM_DATA_PHYS         = 0x00200000,/* SG/バッファデータ ptr が物理的である */
         CAM_CDB_PHYS          = 0x00400000,/* CDBポインタが物理的である */
         CAM_ENG_SGLIST        = 0x00800000,/* SG リストは HBA エンジン用である */
    /* フェーズ認識モードフラグ */
         CAM_DIS_AUTOSRP       = 0x01000000,/* 自動保存/復元ポインタを無効にする */
         CAM_DIS_AUTODISC      = 0x02000000,/* 自動切断を無効にする */
         CAM_TGT_CCB_AVAIL     = 0x04000000,/* ターゲットの CCB が利用可能 */
         CAM_TGT_PHASE_MODE    = 0x08000000,/* SIM がフェーズモードで実行される */
         CAM_MSGB_VALID        = 0x20000000,/* メッセージバッファが有効 */
         CAM_STATUS_VALID      = 0x40000000,/* ステータスバッファが有効 */
         CAM_DATAB_VALID       = 0x80000000,/* データバッファが有効 */
    /* ホストターゲットモードフラグ */
         CAM_TERM_IO           = 0x20000000,/* 入出力メッセージ補充を終了 */
         CAM_DISCONNECT        = 0x40000000,/* 切断は必須である */
         CAM_SEND_STATUS       = 0x80000000,/* データフェーズの後にステータスを送信 */
    } ccb_flags;

複数のフラグを指定する場合、OR (論理和) を取る必要があります。 どの CCB フラグを使用することもできます。 以降の重要ないくつかのフラグについては特に説明しておく価値が あります。

CAM_DIR_IN
    問題の操作が読み取り操作であることを示します。すなわち、データは SCSI デバイスからユーザ指定バッファに読み取られています。

CAM_DIR_OUT
    操作が書き込み操作であることを示します。すなわち、データは ユーザ指定バッファからデバイスに書き込まれています。

CAM_DIR_NONE
    このコマンドについて転送されるデータはないことを示します。

CAM_DEV_QFRZDIS
    デバイス待ち行列の、エラー回復メカニズムとしての凍結を 無効にします。

CAM_PASS_ERR_RECOVER
    pass(4) ドライバにエラー回復を有効にするように 通知します。デフォルトではエラー回復を実行されません。すなわち、このフラグ がない場合は再試行カウントは意味を持ちません。

CAM_DATA_PHYS
    data_ptr に入っているアドレスが、仮想アドレスではなく物理 アドレスであることを示します。

retry_count は、問題のコマンドを何回再試行するかをカーネルに通知します。 pass(4) ドライバが CAM_PASS_ERR_RECOVER フラグによって回復を有効にするよう 指示されていない限り、再試行カウントは無視されます。

timeout は、指定のコマンドが完了するまでどのくらい待機するかをカーネルに 通知します。時間が切れ、しかもコマンドが完了していないと、 CCB は、該当する エラーステータスでカーネルから帰ります。

cmd_specis は SCSI CDB を構築するのに使用される CDB 形式指示子です。 このテキストストリングは、フィールド指示子のリストで構成されます。 フィールド指示子は、 各 CDB フィールド用の値 (値を変数引数リスト内の次の引数から取るべきことを示すことも含む)、 フィールドの幅 (ビット単位またはバイト単位)、 およびオプションの名前を指定します。 スペースは無視され、 シャープ記号 ('#') は、現在の行の末尾で終了するコメントの先頭を示します。

オプションの名前は、フィールド指定子の最初の部分であり、中括弧で 囲まれます。次の例で中括弧で囲まれたテキストは名前です。
    {PS} v:b1 {Reserved} 0:b1 {Page Code} v:b6 # Mode select page

このフィールド指定子には、3 つのフィールドがあります。 1 ビットのフィールドが 2 つと 6 ビットのフィールドが 1 つです。 2 番めの 1 ビットフィールドは 定数値 0 であり、最初の 1 ビットフィールドと 6 ビットフィールドは、 変数引数リストから取られます。 複数バイトのフィールドは SCSI のバイト順序で CDB 内にスワップされ、スペースは無視されます。

フィールドが 16 進数値または文字 v のとき ( たとえば、 1A または v) 、 1 バイト値が CDB 中の次の未使用バイトにコピーされます。文字 v が 使用されているとき、次の整数引数が変数引数リストから取られ、その値が 使用されます。

定数の 16 進数値にフィールド幅の指定子、または文字 v にフィールド幅指定子 フィールドが続いたもの ( たとえば、 3:4, 3:b4, 3:i3, v:i3) は、指定のビットまたは バイト幅のフィールドを指定します。定数値、または (V 指定子の場合) 可変引数リストの次の整数値が、 CDB の次の未使用ビットまたはバイトにコピーされます。

10 進数または文字 b に 10 進数フィールド幅が続いたものは、その幅の ビットフィールドを示します。ビットフィールドは、可能な限り緊密にパック され、上位ビットで開始し (SCSI 仕様と同じものを読み取られるようにです ) 、 1 バイトが完全に一杯になるときはいつでも、または i フィールドが 検出されたときは、 CDB の新しいバイトが開始されます。

文字 i の後に 1, 2, 3, または 4 が続いたフィールド幅指示子は、 SCSI バイト順 (MSB が先頭) に スワップしなければならない 1, 2, 3, または 4 バイトの 整数値を示します。

v フィールド指示子については、次の整数引数が、変数引数リストから取られ、 その値が SCSI 順にスワップするのに使用されます。

csio_build_visit() は csio_build() と動作が類似していますが、 cmd_spec 内の 変数引数に置き換わる値が、 stdarg(3) によってではなく、 csio_build_visit() に 渡される arg_get() 関数によって取り出される点が異なります。 arg_get() 関数は 次の 2 つの引数を取ります。

gethook
    は関数呼び出しのたびに arg_get() 関数に渡されます。これによって、 arg_get() 関数は、グローバル変数または静的変数を使用せずに、間の呼び出しの間に 状態のいくらかを保持することができます。

field_name
    は、 fmt がある場合はそれによって与えられる名前です。

csio_decode() は、 SCSI 転送のフェーズでデータの情報をデコードするのに 使用されます。

デコードは、 csio_build() のコマンド指示子処理に類似していますが、 csio->data_ptr によって指されるデータからデータを取り出す点が異なります。 stdarg リストは、整数値ではなく整数を指すポインタです。 シークフィールドタイプと抑制修飾子が追加されます。 * 抑制修飾子 ( たとえば、 *i3 または *b4) は、フィールドからの割り当てを抑制し、データ内のバイトまたは ビットをスキップするのに使用できます。これにより arg リスト内のダミー変数に コピーする必要がなくなります。

シークフィールドタイプ s によって、データをスキップできます。 これは、'+' 符号の存在の有無に基づき、 データ内の絶対位置 (s3) または 相対位置 (s+3) を探します。 シーク値は v として指定することができ、引数リスト の次の整数値がシーク値として使用されます。

csio_decode_visit() は、 csio_decode() と同じように動作しますが、デコード したバッファの内容を 可変長引数に配置する代わりに、デコードしたバッファ の内容は、渡された arg_put() 関数を通じてユーザに返される点が異なります。 arg_put() 関数は、次のいくつかの引数を取ります。

hook
    "hook" は、 arg_put() 関数が呼び出しの間で状態を保存できるようにする メカニズムです。

letter
    関数に渡される引数の形式を記述する文字です。

val 関数に渡される値を指す void ポインタです。

count
    arg_put() 関数に渡される値のサイズです。 引数のフォーマットにより大きさの単位が決まります。

name
    フィールドのテキスト記述です。ただし fmt 内にそれが準備されている 場合です。

buff_decode() は、 csio_decode() について前述した方式を使用して任意の データバッファをデコードします。

buff_decode_visit() は、 csio_decode_visit() について前述した方式を使用して 任意のデータバッファをデコードします。

csio_encode() は、 csio_build() について前述した方式を使用して、 ccb_scsiio の構造 data_ptr 部分 (CDB ではない ) をエンコードします。

csio_encode_visit() は、 csio_build_visit() について前述した方式を使用して、 ccb_scsiio 構造の data_ptr 部分 (CDB ではない ) をエンコードします。

buff_encode_visit() は、 csio_build_visit() について前述した方式を使用して、 任意のデータポインタをエンコードします。

戻り値
csio_build(), csio_build_visit(), csio_encode(), csio_encode_visit() および buff_encode_visit() は、処理済みのフィールドの数を返します。

csio_decode(), csio_decode_visit(), buff_decode() および buff_decode_visit() は、実行された割り当ての数を返します。

関連項目
cam(3), pass(4), camcontrol(8)

歴史
これらの関数の CAM バージョンは、 古い FreeBSD の SCSI レイヤ用に実現された類似の関数を基礎にしています。 SCSI の古いコード内のエンコード/デコード関数は Peter Dufault が作成したものです。

多数のシステムに、ユーザ空間で SCSI コマンドをユーザが構築できる、 これと匹敵するインタフェースがあります。

古い scsireq データ構造は、SGI の /dev/scsi データ構造とほとんど同じでした。 作者の名前を知っている人はここに連絡してください。 Peter Dufault は、 1989 年の『Sun Expert』誌で、 最初にこれについて読みました。

新しい CCB データ構造は、 CAM-2 および CAM-3 仕様に由来しています。

Peter Dufault は、 386BSD で SGI のインタフェースのクローンを実現しました。 これがオリジナルの FreeBSD SCSI ライブラリと関連カーネル ioctl に至るものになりました。 互換性の必要がある場合は、dufault@hda.com に連絡してください。

作者
Kenneth Merry が、これらのエンコードおよびデコードの関数の CAM バージョンを実現しました。 この現在の作業は、Peter Dufault による以前の作業を基礎にしています。

バグ
CDB および SCSI CCB のデータバッファ部分の両方をエンコードする関数はおそらく 必要でしょう。 camcontrol(8) で任意のコマンド実行コードを実現している間に私はこの必要性に 気づきましたが、 そのような関数を実現する時間がまだありません。

CCB フラグの説明には本当はここに属さないものがあります。 それらは一般の CCB マニュアルページに属します。 そのマニュアルページはまだ書かれていないので、 ここでの短い説明で間に合わせざるを得ません。