ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
デバイスドライバの記述 Oracle Solaris 10 8/11 Information Library (日本語) |
パート I Solaris プラットフォーム用デバイスドライバの設計
_init() エントリポイント (SCSI HBA ドライバ)
_fini() エントリポイント (SCSI HBA ドライバ)
attach() エントリポイント (SCSI HBA ドライバ)
detach() エントリポイント (SCSI HBA ドライバ)
21. ドライバのコンパイル、ロード、パッケージ化、およびテスト
SCSA HBA インタフェースには、HBA エントリポイント、HBA データ構造体、および HBA フレームワークが含まれています。
SCSA では、HBA ドライバのエントリポイントをいくつか定義しています。次の表に、これらのエントリポイントを示します。このエントリポイントは、HBA ドライバに接続されたターゲットドライバインスタンスが設定されるときにシステムから呼び出されます。また、ターゲットドライバが SCSA 要求を出したときにも呼び出されます。詳細については、「SCSA HBA ドライバのエントリポイント」を参照してください。
表 18-1 SCSA HBA エントリポイントの概要
|
SCSA では、データ構造体を定義して、ターゲットドライバと HBA ドライバ間で情報交換ができるようにしています。含まれているデータ構造体は次のとおりです。
HBA ドライバの各インスタンスでは、attach(9E) エントリポイントで scsi_hba_tran_alloc(9F) 関数を使用して scsi_hba_tran(9S) 構造体を割り当てる必要があります。scsi_hba_tran_alloc() 関数は、scsi_hba_tran 構造体を初期化します。HBA ドライバは、HBA ドライバ内のエントリポイントを指すように、トランスポート構造体にある特定のベクトルを初期化する必要があります。scsi_hba_tran 構造体が初期化されたあとで、HBA ドライバは scsi_hba_attach_setup(9F) 関数を呼び出して、このトランスポート構造体を SCSA にエクスポートします。
注意 - SCSA ではトランスポート構造体を指すポインタを devinfo ノード上のドライバの非公開フィールドに保持するため、HBA ドライバは ddi_set_driver_private(9F) を使用してはいけません。ただし、ddi_get_driver_private(9F) を使用して、トランスポート構造体を指すポインタを検出することはできます。 |
SCSA インタフェースでは、HBA ドライバは scsi_hba_tran 構造体を介して呼び出し可能ないくつかのエントリポイントを提供する必要があります。詳細については、「SCSA HBA ドライバのエントリポイント」を参照してください。
scsi_hba_tran 構造体には、次のフィールドがあります。
struct scsi_hba_tran { dev_info_t *tran_hba_dip; /* HBAs dev_info pointer */ void *tran_hba_private; /* HBA softstate */ void *tran_tgt_private; /* HBA target private pointer */ struct scsi_device *tran_sd; /* scsi_device */ int (*tran_tgt_init)(); /* Transport target */ /* Initialization */ int (*tran_tgt_probe)(); /* Transport target probe */ void (*tran_tgt_free)(); /* Transport target free */ int (*tran_start)(); /* Transport start */ int (*tran_reset)(); /* Transport reset */ int (*tran_abort)(); /* Transport abort */ int (*tran_getcap)(); /* Capability retrieval */ int (*tran_setcap)(); /* Capability establishment */ struct scsi_pkt *(*tran_init_pkt)(); /* Packet and DMA allocation */ void (*tran_destroy_pkt)(); /* Packet and DMA */ /* Deallocation */ void (*tran_dmafree)(); /* DMA deallocation */ void (*tran_sync_pkt)(); /* Sync DMA */ void (*tran_reset_notify)(); /* Bus reset notification */ int (*tran_bus_reset)(); /* Reset bus only */ int (*tran_quiesce)(); /* Quiesce a bus */ int (*tran_unquiesce)(); /* Unquiesce a bus */ int tran_interconnect_type; /* transport interconnect */ };
次に、scsi_hba_tran 構造体の各フィールドについて詳しく説明します。
HBA デバイスインスタンスの dev_info 構造体を指すポインタです。このフィールドは、scsi_hba_attach_setup(9F) 関数によって設定されます。
HBA ドライバによって保持される非公開データを指すポインタです。通常、tran_hba_private には、HBA ドライバの状態構造体を指すポインタが入ります。
複製の使用時に HBA ドライバによって保持される非公開データを指すポインタです。scsi_hba_attach_setup(9F) の呼び出し時に SCSI_HBA_TRAN_CLONE を指定することにより、scsi_hba_tran(9S) 構造体が 1 つのターゲットにつき 1 度だけ複製されます。この方法により、HBA は tran_tgt_init(9E) エントリポイントでターゲットインスタンスごとのデータ構造体を指すようにこのフィールドを初期化できます。SCSI_HBA_TRAN_CLONE を指定しない場合、tran_tgt_private は NULL となり、tran_tgt_private が参照されることはありません。詳細については、「トランスポート構造体の複製」を参照してください。
複製時に使用されるターゲットインスタンスごとの scsi_device(9S) 構造体を指すポインタです。SCSI_HBA_TRAN_CLONE が scsi_hba_attach_setup(9F) に渡された場合、tran_sd はターゲットごとの scsi_device 構造体を指すように初期化されます。この初期化は、そのターゲットに代わって HBA 関数が呼び出される前に行われます。SCSI_HBA_TRAN_CLONE を指定しない場合、tran_sd は NULL となり、tran_sd が参照されることはありません。詳細については、「トランスポート構造体の複製」を参照してください。
ターゲットデバイスインスタンスの初期化時に呼び出される HBA ドライバのエントリポイントを指すポインタです。ターゲットごとの初期化が必要ない場合、HBA は tran_tgt_init を NULL に設定しておくことができます。
ターゲットドライバインスタンスが scsi_probe(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。このルーチンは、ターゲットデバイスの存在を調べるために呼び出されます。この HBA にターゲットのプローブカスタマイズが必要ない場合、HBA は tran_tgt_probe を scsi_hba_probe(9F) に設定します。
ターゲットデバイスのインスタンスが破棄されるときに呼び出される HBA ドライバのエントリポイントを指すポインタです。ターゲットごとの解放が必要ない場合、HBA は tran_tgt_free を NULL に設定しておくことができます。
ターゲットドライバが scsi_transport(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが scsi_reset(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが scsi_abort(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが scsi_ifgetcap(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが scsi_ifsetcap(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが scsi_init_pkt(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが scsi_destroy_pkt(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが scsi_dmafree(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが scsi_sync_pkt(9F) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットドライバが tran_reset_notify(9E) を呼び出したときに呼び出される HBA ドライバのエントリポイントを指すポインタです。
ターゲットをリセットしないで SCSI バスをリセットする関数エントリです。
未処理のコマンドが完了するのを待ち、発行されたすべての入出力要求をブロックする (またはキューに入れる) 関数エントリです。
入出力動作が SCSI バス上で再開できるようにする関数エントリです。
services.h ヘッダーファイルに定義されたとおりにトランスポートの相互接続タイプを示す整数値です。
scsi_address(9S) 構造体は、ターゲットドライバのインスタンスによって割り当てられ、トランスポートされる各 SCSI コマンドのトランスポートとアドレス指定の情報を提供します。
scsi_address 構造体には、次のフィールドがあります。
struct scsi_address { struct scsi_hba_tran *a_hba_tran; /* Transport vectors */ ushort_t a_target; /* Target identifier */ uchar_t a_lun; /* LUN on that target */ uchar_t a_sublun; /* Sub LUN on that LUN */ /* Not used */ };
HBA ドライバによって割り当てられ、初期化されたときの scsi_hba_tran(9S) 構造体を指すポインタです。scsi_hba_attach_setup(9F) のフラグとして SCSI_HBA_TRAN_CLONE を指定した場合、a_hba_tran はその構造体のコピーを指します。
SCSI バス上の SCSI ターゲットを識別します。
SCSI ターゲット上の SCSI 論理ユニットを識別します。
HBA フレームワークでは、ターゲットデバイスのインスタンスごとに scsi_device(9S) 構造体を割り当て、初期化します。この割り当てと初期化は、フレームワークで HBA ドライバの tran_tgt_init(9E) エントリポイントを呼び出す前に行われます。この構造体には、一般的な情報とデバイス固有の情報を含む情報領域を指すポインタなど、各 SCSI 論理ユニットに関する情報が格納されます。システムに接続されているターゲットデバイスインスタンスごとに 1 つの scsi_device(9S) 構造体が存在します。
ターゲットごとの初期化が正常に行われると、HBA フレームワークは ddi_set_driver_private(9F) を使用して、ターゲットドライバのインスタンスごとの非公開データが scsi_device(9S) 構造体を指すように設定します。初期化が正常に行われるのは、tran_tgt_init() が成功を返した場合またはベクトルが null の場合です。
scsi_device(9S) 構造体には、次のフィールドがあります。
struct scsi_device { struct scsi_address sd_address; /* routing information */ dev_info_t *sd_dev; /* device dev_info node */ kmutex_t sd_mutex; /* mutex used by device */ void *sd_reserved; struct scsi_inquiry *sd_inq; struct scsi_extended_sense *sd_sense; caddr_t sd_private; /* for driver's use */ };
各表記の意味は次のとおりです。
SCSI 資源の割り当てのためのルーチンに渡されるデータ構造体です。
ターゲットの dev_info 構造体を指すポインタです。
ターゲットドライバが使用する mutex です。この mutex は、HBA フレームワークによって初期化されます。ターゲットドライバは、この mutex をデバイスごとの mutex として使用できます。この mutex は、scsi_transport(9F) または scsi_poll(9F) が呼び出されると保持されません。mutex の詳細については、第 3 章マルチスレッドを参照してください。
ターゲットデバイスの SCSI 照会データへのポインタです。scsi_probe(9F) ルーチンは、バッファーを割り当て、そのバッファーを満たして、このフィールドに追加します。
デバイスから送られた要求検知データを収めるバッファーを指すポインタです。ターゲットドライバは、このバッファーそのものを割り当てて管理する必要があります。詳細については、「attach() エントリポイント」 に記載されたターゲットドライバの attach(9E) ルーチンを参照してください。
ターゲットドライバが使用するポインタフィールドです。このフィールドは、ターゲットドライバの非公開の状態構造体を指すポインタの格納によく使われます。
SCSI コマンドを実行するには、ターゲットドライバはまずそのコマンドに scsi_pkt(9S) 構造体を割り当てる必要があります。次に、そのターゲットドライバ専用の非公開データ領域の大きさ、コマンドの状態、およびコマンドの長さを指定する必要があります。HBA ドライバは、tran_init_pkt(9E) エントリポイントでパケット割り当てを実装します。また、その tran_destroy_pkt(9E) エントリポイントでパケットの解放を行います。詳細については、「scsi_pkt 構造体 (ターゲットドライバ)」を参照してください。
scsi_pkt(9S) 構造体には、次のフィールドがあります。
struct scsi_pkt { opaque_t pkt_ha_private; /* private data for host adapter */ struct scsi_address pkt_address; /* destination address */ opaque_t pkt_private; /* private data for target driver */ void (*pkt_comp)(struct scsi_pkt *); /* completion routine */ uint_t pkt_flags; /* flags */ int pkt_time; /* time allotted to complete command */ uchar_t *pkt_scbp; /* pointer to status block */ uchar_t *pkt_cdbp; /* pointer to command block */ ssize_t pkt_resid; /* data bytes not transferred */ uint_t pkt_state; /* state of command */ uint_t pkt_statistics; /* statistics */ uchar_t pkt_reason; /* reason completion called */ };
各表記の意味は次のとおりです。
コマンドごとの HBA ドライバの非公開データを指すポインタです。
このコマンドのアドレス情報を提供する scsi_address(9S) 構造体を指すポインタです。
パケットごとのターゲットドライバの非公開データを指すポインタです。
トランスポート層でこのコマンドが実行されたときに HBA ドライバによって呼び出されるターゲットドライバ完了ルーチンを指すポインタです。
コマンドのフラグです。
コマンドの完了タイムアウトを秒単位で指定します。
コマンドの状態完了ブロックを指すポインタです。
コマンドのコマンド記述子ブロック (CDB) を指すポインタです。
コマンドが完了したときに転送されなかったデータバイト数です。このフィールドを使用すると、資源が割り当てられなかったデータの量も指定できます。HBA は、トランスポート時にこのフィールドを変更する必要があります。
コマンドの状態です。HBA は、トランスポート時にこのフィールドを変更する必要があります。
トランスポート層に存在している間に、コマンドが検出したイベントの履歴を提供します。HBA は、トランスポート時にこのフィールドを変更する必要があります。
コマンド完了の理由です。HBA は、トランスポート時にこのフィールドを変更する必要があります。
HBA ドライバは、attach(9E) の実行中に scsi_hba_tran(9S) 構造体を割り当てる必要があります。次に、HBA ドライバは、HBA ドライバの必須のエントリポイントを指すように、このトランスポート構造体にあるベクトルを初期化する必要があります。その後、この scsi_hba_tran 構造体は scsi_hba_attach_setup(9F) に渡されます。
scsi_hba_tran 構造体には tran_hba_private フィールドがあり、HBA ドライバのインスタンスごとの状態を参照するために使用できます。
各 scsi_address(9S) 構造体には、scsi_hba_tran 構造体を指すポインタが含まれています。また、scsi_address 構造体には、特定のターゲットデバイスのターゲット (a_target) と論理ユニット (a_lun) のアドレスもあります。HBA ドライバの各エントリポイントには、scsi_address 構造体を指すポインタが直接渡されるか、scsi_device(9S) 構造体を経由して間接的に渡されます。その結果、HBA ドライバは自身の状態を参照できます。HBA ドライバは、アドレス指定されているターゲットデバイスを識別することもできます。
次の図は、トランスポート操作のための HBA データ構造体を示しています。
図 18-3 HBA トランスポート構造体
HBA ドライバが scsi_hba_tran(9S) 構造体でターゲットごとの非公開データを保持する必要がある場合は、複製が役立つことがあります。複製は、scsi_address(9S) 構造体で提供されるアドレスよりも複雑なアドレスを保持するためにも使用できます。
複製プロセスでは、HBA ドライバは引き続き attach(9E) の実行時に scsi_hba_tran 構造体を割り当てる必要があります。また、HBA ドライバの tran_hba_private ソフト状態ポインタとエントリポイントベクトルを初期化する必要もあります。違いが生じるのは、フレームワークがターゲットドライバのインスタンスを HBA ドライバに接続開始するときです。HBA ドライバの tran_tgt_init(9E) エントリポイントを呼び出す前に、フレームワークでは HBA のそのインスタンスに関連付けられている scsi_hba_tran 構造体を複製します。その結果、特定のターゲットデバイスインスタンスに割り当てられ、初期化された各 scsi_address 構造体は、scsi_hba_tran 構造体のターゲットインスタンスごとのコピーを指します。scsi_address 構造体は、attach() の実行時に HBA ドライバによって割り当てられた scsi_hba_tran 構造体を指しません。
複製の指定時には、HBA ドライバは 2 つの重要なポインタを使用できます。これらのポインタは、scsi_hba_tran 構造体に含まれています。最初のポインタは tran_tgt_private フィールドであり、ドライバがターゲットごとの HBA 非公開データを指すために使用できます。 tran_tgt_private ポインタは、HBA ドライバが a_target や a_lun で提供されるアドレスよりも複雑なアドレスを保持する必要がある場合などに役立ちします。2 番目のポインタは tran_sd フィールドであり、これは特定のターゲットデバイスを参照する scsi_device(9S) 構造体を指すポインタです。
複製の指定時は、HBA ドライバはターゲットごとのデータを割り当て、初期化する必要があります。次に、HBA ドライバは、その tran_tgt_init(9E) エントリポイントの実行中にこのデータを指すように tran_tgt_private フィールドを初期化する必要があります。HBA ドライバは、その tran_tgt_free(9E) エントリポイントの実行中に、このターゲットごとのデータを解放する必要があります。
複製時にフレームワークでは、HBA ドライバの tran_tgt_init() エントリポイントが呼び出される前に、scsi_device 構造体を指すように tran_sd フィールドを初期化します。ドライバが複製を要求するときは、SCSI_HBA_TRAN_CLONE フラグを scsi_hba_attach_setup(9F) に渡します。次の図は、トランスポート操作を複製するための HBA データ構造体を示しています。
図 18-4 トランスポート操作の複製
SCSA では、いくつかの関数も提供しています。これらの関数は次の表に一覧表示されており、HBA ドライバで使用されます。
表 18-2 SCSA HBA 関数
|