EN JA
CAM_CDBPARSE(3)
CAM_CDBPARSE(3) FreeBSD Library Functions Manual 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_visitCAM ユーザライブラリ SCSI バッファ解析ルーチン

ライブラリ

Common Access Method User Library (libcam, -lcam)

書式

#include < stdio.h>
#include < camlib.h>

int
csio_build( struct ccb_scsiio *csio, uint8_t *data_ptr, uint32_t dxfer_len, uint32_t flags, int retry_count, int timeout, const char *cmd_spec, ...);

int
csio_build_visit( struct ccb_scsiio *csio, uint8_t *data_ptr, uint32_t dxfer_len, uint32_t flags, int retry_count, int timeout, const char *cmd_spec, int (*arg_get)(void *hook, char *field_name), void *gethook);

int
csio_decode( struct ccb_scsiio *csio, const char *fmt, ...);

int
csio_decode_visit( struct ccb_scsiio *csio, const char *fmt, void (*arg_put)(void *hook, int letter, void *val, int count, char *name), void *puthook);

int
buff_decode( uint8_t *buff, size_t len, const char *fmt, ...);

int
buff_decode_visit( uint8_t *buff, size_t len, const char *fmt, void (*arg_put)(void *, int, void *, int, char *), void *puthook);

int
csio_encode( struct ccb_scsiio *csio, const char *fmt, ...);

int
csio_encode_visit( struct ccb_scsiio *csio, const char *fmt, int (*arg_get)(void *hook, char *field_name), void *gethook);

int
buff_encode_visit( uint8_t *buff, size_t len, const 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(), scsi_read_write() です)。

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

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_spec は、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 マニュアルページに属します。そのマニュアルページは、まだ書かれていないので、ここでの短い説明で間に合わせざるを得ません。

October 13, 1998 FreeBSD