Writing Device Drivers

Allocation and Initialization of a scsi_pkt(9S) Structure

The tran_init_pkt(9E) entry point must allocate a scsi_pkt(9S) structure if pkt is NULL through scsi_hba_pkt_alloc(9F).

scsi_hba_pkt_alloc(9F) allocates the following:

The scsi_pkt(9S) structure members, as well as pkt itself, must be initialized to zero except for the following members: pkt_scbp (status completion), pkt_cdbp (CDB), pkt_ha_private (HBA driver private data), pkt_private (target driver private data). These members are pointers to memory space where the values of the fields are stored, as illustrated in Figure 15–5. For more information, refer to scsi_pkt Structure.

Figure 15–5 scsi_pkt(9S) Structure Pointers

Diagram shows the scsi_pkt structure with those members that point to values rather than being initialized to zero.

Example 15–2 provides an example of allocation and initialization of a scsi_pkt(9S) structure.


Example 15–2 HBA Driver Initialization of a SCSI Packet Structure

static struct scsi_pkt                             *
isp_scsi_init_pkt(
    struct scsi_address        *ap,
    struct scsi_pkt            *pkt,
    struct buf                 *bp,
    int                        cmdlen,
    int                        statuslen,
    int                        tgtlen,
    int                        flags,
    int                        (*callback)(),
    caddr_t                    arg)
{
    struct isp_cmd             *sp;
    struct isp                 *isp;
    struct scsi_pkt            *new_pkt;

    ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);

    isp = (struct isp *)ap->a_hba_tran->tran_hba_private;

    /*
     * First step of isp_scsi_init_pkt:  pkt allocation
     */
    if (pkt == NULL) {
           pkt = scsi_hba_pkt_alloc(isp->isp_dip, ap, cmdlen,
                statuslen, tgtlen, sizeof (struct isp_cmd),
                callback, arg);
           if (pkt == NULL) {
                return (NULL);
           }

           sp = (struct isp_cmd *)pkt->pkt_ha_private;

           /*
            * Initialize the new pkt
            */
           sp->cmd_pkt             = pkt;
           sp->cmd_flags           = 0;
           sp->cmd_scblen          = statuslen;
           sp->cmd_cdblen          = cmdlen;
           sp->cmd_dmahandle       = NULL;
           sp->cmd_ncookies        = 0;
           sp->cmd_cookie          = 0; 
           sp->cmd_cookiecnt       = 0;
           sp->cmd_nwin            = 0;
           pkt->pkt_address        = *ap;
           pkt->pkt_comp           = (void (*)())NULL;
           pkt->pkt_flags          = 0;
           pkt->pkt_time           = 0;
           pkt->pkt_resid          = 0;
           pkt->pkt_statistics     = 0;
           pkt->pkt_reason         = 0;

           new_pkt = pkt;
    } else {
           sp = (struct isp_cmd *)pkt->pkt_ha_private;
           new_pkt = NULL;
    }

    /*
     * Second step of isp_scsi_init_pkt:  dma allocation/move
     */
    if (bp && bp->b_bcount != 0) {
           if (sp->cmd_dmahandle == NULL) {
               if (isp_i_dma_alloc(isp, pkt, bp,
                   flags, callback) == 0) {
                   if (new_pkt) {
                           scsi_hba_pkt_free(ap, new_pkt);
                   }
                   return ((struct scsi_pkt *)NULL);
                }
           } else {
               ASSERT(new_pkt == NULL);
               if (isp_i_dma_move(isp, pkt, bp) == 0) {
                   return ((struct scsi_pkt *)NULL);
               }
           }
    }

    return (pkt);
}