probe(9E) ルーチンで、予期されるデバイスが存在することを確認したら、attach (9E) が呼び出されます。attach() は次のタスクを実行します。
インタンスごとのデータを割り当てて初期化する。
マイナーデバイスノード情報を作成する。
デバイスまたはシステムの一時停止後にハードウェアの状態を復元する。詳細については、attach() Entry Pointを参照してください。
SCSI ターゲットドライバは scsi_probe (9F) をもう一度呼び出して、デバイスの照会データを取得する必要があります。ドライバは、SCSI 要求検知パケットを作成する必要もあります。アタッチが成功した場合、attach() 関数はscsi_unprobe(9F) を呼び出してはいけません。
要求検知パケットを作成するには、scsi_alloc_consistent_buf(9F)、scsi_init_pkt(9F)、およびscsi_setup_cdb (9F) の 3 つのルーチンが使用されます。scsi_alloc_consistent_buf(9F) は、安定した DMA に適したバッファーを割り当てます。次に scsi_alloc_consistent_buf () がbuf(9S) 構造体へのポインタを返します。変化しないバッファーの利点は、データを明示的に同期する必要がない点です。つまり、ターゲットドライバはコールバック後にデータにアクセスできます。検知バッファーのアドレスを使用して、デバイスのscsi_device(9S) 構造体の sd_sense 要素を初期化する必要があります。scsi_init_pkt (9F) は scsi_pkt(9S) 構造体を作成し、部分的に初期化します。scsi_setup_cdb(9F) は SCSI コマンド記述子ブロックを作成します (この場合は、SCSI 要求検知コマンドを作成することで、それを行なっています)。
SCSI デバイスは自己識別しないため、reg プロパティーを持っていません。結果として、ドライバで pm-hardware-state プロパティーを設定する必要が生じます。pm-hardware-state を設定することで、このデバイスは一時停止してから再開する必要があることをフレームワークに通知します。
次の例では、SCSI ターゲットドライバの attach() ルーチンを示します。
使用例 17-2 SCSI ターゲットドライバの attach (9E) ルーチンstatic int xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd) { struct xxstate *xsp; struct scsi_pkt *rqpkt = NULL; struct scsi_device *sdp; struct buf *bp = NULL; int instance; instance = ddi_get_instance(dip); switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: /* For information, see the "Directory Memory Access (DMA)" */ /* chapter in this book. */ default: return (DDI_FAILURE); } /* * Allocate a state structure and initialize it. */ xsp = ddi_get_soft_state(statep, instance); sdp = (struct scsi_device *)ddi_get_driver_private(dip); /* * Cross-link the state and scsi_device(9S) structures. */ sdp->sd_private = (caddr_t)xsp; xsp->sdp = sdp; /* * Call scsi_probe(9F) again to get and validate inquiry data. * Allocate a request sense buffer. The buf(9S) structure * is set to NULL to tell the routine to allocate a new one. * The callback function is set to NULL_FUNC to tell the * routine to return failure immediately if no * resources are available. */ bp = scsi_alloc_consistent_buf(&sdp->sd_address, NULL, SENSE_LENGTH, B_READ, NULL_FUNC, NULL); if (bp == NULL) goto failed; /* * Create a Request Sense scsi_pkt(9S) structure. */ rqpkt = scsi_init_pkt(&sdp->sd_address, NULL, bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, NULL_FUNC, NULL); if (rqpkt == NULL) goto failed; /* * scsi_alloc_consistent_buf(9F) returned a buf(9S) structure. * The actual buffer address is in b_un.b_addr. */ sdp->sd_sense = (struct scsi_extended_sense *)bp->b_un.b_addr; /* * Create a Group0 CDB for the Request Sense command */ if (scsi_setup_cdb((union scsi_cdb *)rqpkt->pkt_cdbp, SCMD_REQUEST_SENSE, 0, SENSE__LENGTH, 0) == 0) goto failed;; /* * Fill in the rest of the scsi_pkt structure. * xxcallback() is the private command completion routine. */ rqpkt->pkt_comp = xxcallback; rqpkt->pkt_time = 30; /* 30 second command timeout */ rqpkt->pkt_flags |= FLAG_SENSING; xsp->rqs = rqpkt; xsp->rqsbuf = bp; /* * Create minor nodes, report device, and do any other initialization. */ * Since the device does not have the 'reg' property, * cpr will not call its DDI_SUSPEND/DDI_RESUME entries. * The following code is to tell cpr that this device * needs to be suspended and resumed. */ (void) ddi_prop_update_string(device, dip, "pm-hardware-state", "needs-suspend-resume"); xsp->open = 0; return (DDI_SUCCESS); failed: if (bp) scsi_free_consistent_buf(bp); if (rqpkt) scsi_destroy_pkt(rqpkt); sdp->sd_private = (caddr_t)NULL; sdp->sd_sense = NULL; scsi_unprobe(sdp); /* Free any other resources, such as the state structure. */ return (DDI_FAILURE); }