Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
15.  SCSI Host Bus Adapter Drivers SCSA HBA Entry Points  Previous   Contents   Next 
   
 

Table 15-3 lists the SCSA HBA entry points arranged by function groups.

Table 15-3 SCSA Entry Points

Function Groups

Entry Points Within Group

Description

Target Driver Instance Initialization

tran_tgt_init(9E)

Performs per-target initialization (optional)

 

tran_tgt_probe(9E)

Probes SCSI bus for existence of a target (optional)

 

tran_tgt_free(9E)

Performs per-target deallocation (optional)

Resource Allocation

tran_init_pkt(9E)

Allocates SCSI packet and DMA resources

 

tran_destroy_pkt(9E)

Frees SCSI packet and DMA resources

 

tran_sync_pkt(9E)

Synchronizes memory before and after DMA

 

tran_dmafree(9E)

Frees DMA resources

Command Transport

tran_start(9E)

Transports a SCSI command

Capability Management

tran_getcap(9E)

Inquires about a capability's value

 

tran_setcap(9E)

Sets a capability's value

Abort and Reset

tran_abort(9E)

Aborts one or all outstanding SCSI commands

 

tran_reset(9E)

Resets a target device or the SCSI bus

 

tran_bus_reset(9E)

Resets the SCSI bus

 

tran_reset_notify(9E)

Request to notify target of bus reset (optional)

Dynamic Reconfiguration

tran_quiesce(9E)

Stops activity on the bus

 

tran_unquiesce(9E)

Resume activity on the bus

Target Driver Instance Initialization

The following sections explain target entry points.

tran_tgt_init() Entry Point

The tran_tgt_init(9E) entry point enables the HBA to allocate and/or initialize any per-target resources. It also enables the HBA to qualify the device's address as valid and supportable for that particular HBA. By returning DDI_FAILURE, the instance of the target driver for that device will not be probed or attached.

This entry point is not required, and if none is supplied, the framework will attempt to probe and attach all possible instances of the appropriate target drivers.

static int
isp_tran_tgt_init(
     dev_info_t                 *hba_dip,
     dev_info_t                 *tgt_dip,
     scsi_hba_tran_t            *tran,
     struct scsi_device         *sd)
 {
     return ((sd->sd_address.a_target < N_ISP_TARGETS_WIDE &&
             sd->sd_address.a_lun < 8) ? DDI_SUCCESS : DDI_FAILURE);
 }

tran_tgt_probe() Entry Point

The tran_tgt_probe(9E) entry point enables the HBA to customize the operation of scsi_probe(9F), if necessary. This entry point is called only when the target driver calls scsi_probe(9F).

The HBA driver can retain the normal operation of scsi_probe(9F) by calling scsi_hba_probe(9F) and returning its return value.

This entry point is not required, and if not needed, the HBA driver should set the tran_tgt_probe vector in the scsi_hba_tran(9S) structure to point to scsi_hba_probe(9F).

scsi_probe(9F) allocates a scsi_inquiry(9S) structure and sets the sd_inq field of the scsi_device(9S) structure to point to the data in scsi_inquiry(9S). scsi_hba_probe(9F) handles this automatically. scsi_unprobe(9F) then frees the scsi_inquiry(9S) data.

Other than during the allocation of scsi_inquiry(9S) data, normally handled by scsi_hba_probe(9F), tran_tgt_probe(9E) must be stateless, as the same SCSI device might call it multiple times.


Note - The allocation of the scsi_inquiry(9S) structure is handled automatically by scsi_hba_probe(9F). This is only of concern if you want custom scsi_probe(9F) handling.


static int
 isp_tran_tgt_probe(
     struct scsi_device    *sd,
     int            (*callback)())
 {
     Perform any special probe customization needed.
     /*
      * Normal probe handling
      */
     return (scsi_hba_probe(sd, callback));
 }

tran_tgt_free() Entry Point

The tran_tgt_free(9E) entry point enables the HBA to perform any deallocation or clean-up procedures for an instance of a target. This entry point is optional.

static void
isp_tran_tgt_free(
     dev_info_t                  *hba_dip,
     dev_info_t                  *tgt_dip,
     scsi_hba_tran_t             *hba_tran,
     struct scsi_device          *sd)
 {
     Undo any special per-target initialization done
     earlier in tran_tgt_init(9F) and tran_tgt_probe(9F)
 }

Resource Allocation

The following sections discuss resource allocation.

tran_tgt_pkt() Entry Point

The tran_init_pkt(9E) entry point is the HBA driver function that allocates and initializes, on behalf of the target driver, a scsi_pkt(9S) structure and DMA resources for a target driver request.

The tran_init_pkt(9E) entry point is called when the target driver calls the SCSA function scsi_init_pkt(9F).

Each call of the tran_init_pkt(9E) entry point is a request to perform one or more of three possible services:

  • Allocation and initialization of a scsi_pkt(9S) structure

  • Allocation of DMA resources for data transfer

  • Reallocation of DMA resources for the next portion of the data transfer

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:

  • scsi_pkt(9S)

  • SCSI CDB of length cmdlen

  • SCSI status completion area of length statuslen

  • Per-packet target driver private data area of length tgtlen

  • Per-packet HBA driver private data area of length hbalen

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

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);
}

 
 
 
  Previous   Contents   Next