Writing Device Drivers

Building a Command

The routine scsi_init_pkt(9F) allocates space for a SCSI CDB, allocates DMA resources if necessary, and sets the pkt_flags field:

	pkt = scsi_init_pkt(&sdp->sd_address, NULL, bp,
 		CDB_GROUP0, 1, 0, 0, SLEEP_FUNC, NULL);

This example creates a new packet and allocates DMA resources as specified in the passed buf(9S) structure pointer. A SCSI CDB is allocated for a Group 0 (6-byte) command, the pkt_flags field is set to zero, but no space is allocated for the pkt_private field. This call to scsi_init_pkt(9F), because of the SLEEP_FUNC parameter, waits indefinitely for resources if none are currently available.

The next step is to initialize the SCSI CDB, using the scsi_setup_cdb(9F) function:

	if (scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
 		SCMD_READ, bp->b_blkno, bp->b_bcount >> DEV_BSHIFT, 0) == 0)
 		goto failed;

This example builds a Group 0 command descriptor block and fills in the pkt_cdbp field as follows:

Note -

scsi_setup_cdb(9F) does not support setting a target device's logical unit number (LUN) in bits 5-7 of byte 1 of the SCSI command block, as defined by SCSI-1. For SCSI-1 devices requiring the LUN bits set in the command block, use makecom_g0(9F) (or equivalent) rather than scsi_setup_cdb(9F).

After initializing the SCSI CDB, initialize three other fields in the packet and store as a pointer to the packet in the state structure.

	pkt->pkt_private = (opaque_t)bp;
 	pkt->pkt_comp = xxcallback;
 	pkt->pkt_time = 30;
 	xsp->pkt = pkt;

The buf(9S) pointer is saved in the pkt_private field for later use in the completion routine.