Writing Device Drivers

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 13-5 presents a very simple completion callback routine. This code checks for transport failures and gives up rather than retry 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 not been enabled.


Note -

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



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

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 may resubmit the packet using scsi_transport(9E). There is no need to change any values in the packet prior to resubmitting.

This example does not attempt to retry incomplete commands. See Appendix G, Advanced Topics, for further information.