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

Graphic

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


Example 15-3 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);
}