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, as shown in this example:

pkt = scsi_init_pkt(&sdp->sd_address, NULL, bp,

This example creates a new packet along with allocating 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 no resources 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. The example 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. This requirement is defined by SCSI-1. For SCSI-1 devices that require the LUN bits set in the command block, use makecom_g0(9F) or some 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.