编写适用于 Oracle® Solaris 11.2 的设备驱动程序

退出打印视图

更新时间: 2014 年 9 月
 
 

命令完成

当主机总线适配器驱动程序完成命令后,将调用包的完成回调例程。然后,驱动程序会将指向 scsi_pkt(9S) 结构的指针作为参数传递。对包进行解码后,完成例程将执行相应的操作。

Example 17–5 显示了一个简单的完成回调例程。该代码检查传输是否失败。如果存在失败情况,该例程将放弃运行,而不会重试命令。如果目标繁忙,则需要额外的代码以便在以后重新提交命令。

如果命令产生检查条件,则目标驱动程序需要发送请求检测命令,除非启用了自动请求检测。

否则,命令成功。在结束命令处理时,命令将销毁包并调用 biodone(9F)

如果发生传输错误(如总线重置或奇偶校验问题),则目标驱动程序可以使用 scsi_transport(9F) 重新提交该包。重新提交之前,无需更改包中的任何值。

以下示例不会尝试重试未完成的命令。


注 - 通常,在中断上下文中会调用目标驱动程序的回调函数。因此,回调函数绝不应处于休眠状态。
示例 17-5  SCSI 驱动程序的完成例程
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);
       }
    }
}