Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
14.  SCSI Target Drivers Building and Transporting a Command Transporting a Command  Previous   Contents   Next 
   
 

Synchronous scsi_transport() Function

If FLAG_NOINTR is set in the packet, then scsi_transport(9F) will not return until the command is complete, and no callback will be performed.


Note - Do not use FLAG_NOINTR in interrupt context.


Command Completion

Once the host bus adapter driver has done all it can with the command, it invokes the packet's completion callback routine, passing a pointer to the scsi_pkt(9S) structure as a parameter. The completion routine decodes the packet and takes the appropriate action.

Example 14-5 presents a simple completion callback routine. This code checks for transport failures and gives up rather than retrying the command. If the target is busy, extra code is required to resubmit the command at a later time.

If the command results in a check condition, the target driver needs to send a request sense command unless auto request sense has been enabled.

Otherwise, the command succeeded. If this is the end of processing for the command, it destroys the packet and calls biodone(9F).

In the event of a transport error (such as a bus reset or parity problem), the target driver can resubmit the packet using scsi_transport(9F). There is no need to change any values in the packet prior to resubmitting.

Example 14-5 does not attempt to retry incomplete commands.


Note - Normally, the target driver's callback function is called in interrupt context. Consequently, the callback function should never sleep.



Example 14-5 SCSI Driver Completion Routine

static void
xxcallback(struct scsi_pkt *pkt)
{
    struct buf            *bp;
    struct xxstate        *xsp;
    minor_t               instance;
    struct scsi_status *ssp;
    /*
     * Get a pointer to the buf(9S) structure for the command
     * and to the per-instance data structure.
     */
    bp = (struct buf *)pkt->pkt_private;
    instance = getminor(bp->b_edev);
    xsp = ddi_get_soft_state(statep, instance);
    /*
     * Figure out why this callback routine was called
     */
    if (pkt->pkt_reason != CMP_CMPLT) {
           bp->b_resid = bp->b_bcount;
           bioerror(bp, EIO);
           scsi_destroy_pkt(pkt);          /* release resources */
           biodone(bp);                    /* notify waiting threads */ ;
    } else {
           /*
            * Command completed, check status.
            * See scsi_status(9S)
            */
           ssp = (struct scsi_status *)pkt->pkt_scbp;
           if (ssp->sts_busy) {
               error, target busy or reserved
           } else if (ssp->sts_chk) {
               send a request sense command 
           } else {
                bp->b_resid = pkt->pkt_resid; /*packet completed OK */
                scsi_destroy_pkt(pkt);
                biodone(bp);
           }
    }
}

Reuse of Packets

A target driver can reuse packets in the following ways:

  • Resubmit the packet unchanged.

  • Use scsi_sync_pkt(9F) to synchronize the data, then process the data in the driver and resubmit.

  • Free DMA resources, using scsi_dmafree(9F), and pass the pkt pointer to scsi_init_pkt(9F) for binding to a new bp. The target driver is responsible for reinitializing the packet. The CDB has to have the same length as the previous CDB.

  • If partial DMA was allocated during the first call to scsi_init_pkt(9F), subsequent calls to scsi_init_pkt(9F) can be made for the same packet and bp to adjust the DMA resources to the next portion of the transfer.

Auto-Request Sense Mode

Auto-request sense mode is most desirable if tagged or untagged queuing is used. A contingent allegiance condition is cleared by any subsequent command and, consequently, the sense data is lost. Most HBA drivers will start the next command before performing the target driver callback. Other HBA drivers can use a separate and lower-priority thread to perform the callbacks, which might increase the time needed to notify the target driver that the packet completed with a check condition. In this case, the target driver might not be able to submit a request sense command in time to retrieve the sense data.

To avoid this loss of sense data, the HBA driver, or controller, should issue a request sense command as soon as a check condition has been detected; this mode is known as auto-request sense mode. Note that not all HBA drivers are capable of auto-request sense mode, and some can only operate with auto-request sense mode enabled.

A target driver enables auto-request-sense mode by using scsi_ifsetcap(9F). Example 14-6 shows enabling auto request sense.


Example 14-6 Enabling Auto Request Sense

static int
xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
    struct xxstate *xsp;
    struct scsi_device *sdp = (struct scsi_device *)
        ddi_get_driver_private(dip);
    ...
    /*
     * enable auto-request-sense; an auto-request-sense cmd may
     * fail due to a BUSY condition or transport error. Therefore,
     * it is recommended to allocate a separate request sense
     * packet as well.
     * Note that scsi_ifsetcap(9F) may return -1, 0, or 1
     */
    xsp->sdp_arq_enabled =
        ((scsi_ifsetcap(ROUTE, "auto-rqsense", 1, 1) == 1) ? 1 :
0);
    /*
     * if the HBA driver supports auto request sense then the
     * status blocks should be sizeof (struct scsi_arq_status);
else
     * one byte is sufficient
     */
    xsp->sdp_cmd_stat_size =  (xsp->sdp_arq_enabled ?
        sizeof (struct scsi_arq_status) : 1);
    ...
}

When a packet is allocated using scsi_init_pkt(9F) and auto request sense is desired on this packet, then the target driver must request additional space for the status block to hold the auto request sense structure. The sense length used in the request sense command is sizeof (struct scsi_extended_sense). Auto request sense can be disabled per individual packet by just allocating sizeof (struct scsi_status) for the status block.

The packet is submitted using scsi_transport(9F) as usual. When a check condition occurs on this packet, the host adapter driver takes the following steps:

  • Issues a request sense command if the controller doesn't have auto-request-sense capability

  • Obtains the sense data

  • Fills in the scsi_arq_status information in the packet's status block

  • Sets STATE_ARQ_DONE in the packet's pkt_state field

  • Calls the packet's callback handler (pkt_comp())

 
 
 
  Previous   Contents   Next