各デバイスドライバには dev_ops (9S) 構造体 (これにより、カーネルはドライバの自動構成エントリポイントを見つけることができる) が関連付けられています。これらの自動構成ルーチンについては、Chapter 6, Driver Autoconfigurationに詳しく説明されています。このセクションでは、そのようなエントリポイントのうち、SCSI HBA ドライバで実行される操作に関連付けられたものについてのみ説明します。このようなエントリポイントには、 attach(9E) とdetach (9E) があります。
SCSI HBA ドライバの attach(9E) エントリポイントは、デバイスに対してこのドライバのインスタンスを構成および接続するときにいくつかのタスクを実行します。実際のデバイスの一般的なドライバでは、次のオペレーティングシステムとハードウェアに関する問題に対処する必要があります。
ソフト状態構造体
DMA
トランスポート構造体
HBA ドライバの接続
レジスタマッピング
割り込み仕様
割り込み処理
電源管理可能なコンポーネントの作成
接続ステータスのレポート
デバイスインスタンスごとのソフト状態構造体を割り当てる際にエラーが発生した場合、ドライバは慎重にクリーンアップを行う必要があります。
HBA ドライバは、ddi_dma_attr_t 構造体を正しく初期化することで、その DMA エンジンの属性を記述する必要があります。
static ddi_dma_attr_t isp_dma_attr = { DMA_ATTR_V0, /* ddi_dma_attr version */ 0, /* low address */ 0xffffffff, /* high address */ 0x00ffffff, /* counter upper bound */ 1, /* alignment requirements */ 0x3f, /* burst sizes */ 1, /* minimum DMA access */ 0xffffffff, /* maximum DMA access */ (1<<24)-1, /* segment boundary restrictions */ 1, /* scatter-gather list length */ 512, /* device granularity */ 0 /* DMA flags */ };
また、DMA を提供する場合は、そのハードウェアが DMA 対応スロットに取り付けられていることも確認するべきです。
if (ddi_slaveonly(dip) == DDI_SUCCESS) { return (DDI_FAILURE); }
HBA ドライバは、このインスタンスにさらにトランスポート構造体を割り当て、初期化します。tran_hba_private フィールドは、このインスタンスのソフト状態構造体を指すように設定します。特別なプローブカスタマイズが必要ない場合は、tran_tgt_probe フィールドを NULL に設定して、デフォルトの動作を実行できます。
tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP); isp->isp_tran = tran; isp->isp_dip = dip; tran->tran_hba_private = isp; tran->tran_tgt_private = NULL; tran->tran_tgt_init = isp_tran_tgt_init; tran->tran_tgt_probe = scsi_hba_probe; tran->tran_tgt_free = (void (*)())NULL; tran->tran_start = isp_scsi_start; tran->tran_abort = isp_scsi_abort; tran->tran_reset = isp_scsi_reset; tran->tran_getcap = isp_scsi_getcap; tran->tran_setcap = isp_scsi_setcap; tran->tran_init_pkt = isp_scsi_init_pkt; tran->tran_destroy_pkt = isp_scsi_destroy_pkt; tran->tran_dmafree = isp_scsi_dmafree; tran->tran_sync_pkt = isp_scsi_sync_pkt; tran->tran_reset_notify = isp_scsi_reset_notify; tran->tran_bus_quiesce = isp_tran_bus_quiesce tran->tran_bus_unquiesce = isp_tran_bus_unquiesce tran->tran_bus_reset = isp_tran_bus_reset tran->tran_interconnect_type = isp_tran_interconnect_type
HBA ドライバは、デバイスのこのインスタンスを接続し、必要があれば、エラーのクリーンアップを実行します。
i = scsi_hba_attach_setup(dip, &isp_dma_attr, tran, 0); if (i != DDI_SUCCESS) { /* do error recovery */ return (DDI_FAILURE); }
HBA ドライバは、そのデバイスのレジスタをマップします。ドライバでは次の項目を指定する必要があります。
レジスタセットインデックス
デバイスのデータアクセス特性
マップされるレジスタのサイズ
ddi_device_acc_attr_t dev_attributes; dev_attributes.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_attributes.devacc_attr_dataorder = DDI_STRICTORDER_ACC; dev_attributes.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; if (ddi_regs_map_setup(dip, 0, (caddr_t *)&isp->isp_reg, 0, sizeof (struct ispregs), &dev_attributes, &isp->isp_acc_handle) != DDI_SUCCESS) { /* do error recovery */ return (DDI_FAILURE); }
ドライバはまず、iblock cookie を取得して、ドライバハンドラで使用される mutex をすべて初期化する必要があります。それらの mutex の初期化が完了している場合にのみ、割り込みハンドラを追加できます。
i = ddi_get_iblock_cookie(dip, 0, &isp->iblock_cookie}; if (i != DDI_SUCCESS) { /* do error recovery */ return (DDI_FAILURE); } mutex_init(&isp->mutex, "isp_mutex", MUTEX_DRIVER, (void *)isp->iblock_cookie); i = ddi_add_intr(dip, 0, &isp->iblock_cookie, 0, isp_intr, (caddr_t)isp); if (i != DDI_SUCCESS) { /* do error recovery */ return (DDI_FAILURE); }
高レベルのハンドラが必要な場合、そのようなハンドラを提供するようにドライバをコーディングします。それ以外の場合、ドライバはその接続に失敗できる必要があります。高レベルの割り込み処理については、Handling High-Level Interruptsを参照してください。
電源管理を使用すると、すべてのターゲットアダプタの電源レベルが 0 のときにホストバスアダプタの電源のみを切る必要がある場合、HBA ドライバは power(9E) エントリポイントを提供するだけで済みます。Chapter 12, Power Managementを参照してください。HBA ドライバは、デバイスが実装するコンポーネントについて記述するためのpm-components (9P) プロパティーも作成する必要があります。
これ以上は何も必要ありません。コンポーネントがデフォルトでアイドル状態になり、電源管理フレームワークのデフォルトの依存性処理によって、ターゲットアダプタの電源が入ると、ホストバスアダプタの電源も確実に入るようになるためです。自動電源管理が自動的に使用可能になる場合、この処理では、すべてのターゲットアダプタの電源が切れると、ホストバスアダプタの電源も切れます。
最後に、HBA ドライバは、デバイスのこのインスタンスが接続され、成功を返すことをレポートします。
ddi_report_dev(dip); return (DDI_SUCCESS);
HBA ドライバは、 scsi_hba_detach(9F) の呼び出しなど、標準的な切り離し操作を実行します。