在SCSI策略例程中最后调用scsi_dispatch_cmd将SCSI命令描述符派发给低层驱动进行处理
1 /** 2 * scsi_dispatch_command - Dispatch a command to the low-level driver. 3 * @cmd: command block we are dispatching. 4 * 5 * Return: nonzero return request was rejected and device's queue needs to be 6 * plugged. 7 */ 8 int scsi_dispatch_cmd(struct scsi_cmnd *cmd) 9 { 10 struct Scsi_Host *host = cmd->device->host; 11 unsigned long timeout; 12 int rtn = 0; 13 14 // 递增SCSI设备的IO请求统计数 15 atomic_inc(&cmd->device->iorequest_cnt); 16 17 /* 18 * check if the device is still usable 19 * 检测设备是否还可用。在此时,可能别的地方已经将设备状态置为SDEV_DEL,如果这样,我们将所有命令出错,将命令的结果标记为DID_NO_CONNECT,调用scsi_done结束 20 */ 21 if (unlikely(cmd->device->sdev_state == SDEV_DEL)) { 22 /* in SDEV_DEL we error all commands. DID_NO_CONNECT 23 * returns an immediate error upwards, and signals 24 * that the device is no longer present */ 25 cmd->result = DID_NO_CONNECT << 16; 26 scsi_done(cmd); 27 /* return 0 (because the command has been processed) */ 28 goto out; 29 } 30 31 /* Check to see if the scsi lld made this device blocked. 检查SCSI低层驱动是否已经阻塞了这个设备*/ 32 if (unlikely(scsi_device_blocked(cmd->device))) { 33 /* 34 * in blocked state, the command is just put back on 35 * the device queue. The suspend state has already 36 * blocked the queue so future requests should not 37 * occur until the device transitions out of the 38 * suspend state. 39 */ 40 41 scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); 42 43 SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked ")); 44 45 /* 46 * NOTE: rtn is still zero here because we don't need the 47 * queue to be plugged on return (it's already stopped) 48 */ 49 goto out; 50 } 51 52 /* 53 * If SCSI-2 or lower, store the LUN value in cmnd. 54 */ 55 if (cmd->device->scsi_level <= SCSI_2 && 56 cmd->device->scsi_level != SCSI_UNKNOWN) { 57 cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | 58 (cmd->device->lun << 5 & 0xe0); 59 } 60 61 /* 62 * We will wait MIN_RESET_DELAY clock ticks after the last reset so we can avoid the drive not being ready. 63 * 如果主机适配器的resetting被设置为1,表示其last_Reset域有效。也就是说,后者记录了主机适配器上次复位的时间。 64 * 在复位后必须有2秒钟的延时,才能向这个主机适配器发送命令。 65 */ 66 timeout = host->last_reset + MIN_RESET_DELAY; 67 68 if (host->resetting && time_before(jiffies, timeout)) { 69 int ticks_remaining = timeout - jiffies; 70 /* 71 * NOTE: This may be executed from within an interrupt 72 * handler! This is bad, but for now, it'll do. The irq 73 * level of the interrupt handler has been masked out by the 74 * platform dependent interrupt handling code already, so the 75 * sti() here will not cause another call to the SCSI host's 76 * interrupt handler (assuming there is one irq-level per 77 * host). 78 */ 79 while (--ticks_remaining >= 0) 80 mdelay(1 + 999 / HZ); 81 host->resetting = 0; 82 } 83 84 // 在提交SCSI命令之前输出信息 85 scsi_log_send(cmd); 86 87 /* 88 * Before we queue this command, check if the command length exceeds what the host adapter can handle. 89 * 在将命令排入队列之前,检查命令长度是否超过了主机适配器可以处理的最大长度,如果这样,将命令结果标记为DID_ABORT并返回 90 */ 91 if (cmd->cmd_len > cmd->device->host->max_cmd_len) { 92 SCSI_LOG_MLQUEUE(3, 93 printk("queuecommand : command too long. " 94 "cdb_size=%d host->max_cmd_len=%d ", 95 cmd->cmd_len, cmd->device->host->max_cmd_len)); 96 cmd->result = (DID_ABORT << 16); 97 98 scsi_done(cmd); 99 goto out; 100 } 101 102 /* 在获取锁的过程中,可能别的地方已经将主机适配器的状态设置为“删除”。如果这样,标记为DID_NO_CONNECT并返回*/ 103 if (unlikely(host->shost_state == SHOST_DEL)) { 104 cmd->result = (DID_NO_CONNECT << 16); 105 scsi_done(cmd); 106 } else { 107 trace_scsi_dispatch_cmd_start(cmd); 108 cmd->scsi_done = scsi_done; 109 rtn = host->hostt->queuecommand(host, cmd); // 调用主机适配器模板的queuecommand回调,将SCSI命令排入低层设备驱动的队列,调用时传入scsi_done,以便低层驱动完成后回调 110 } 111 112 if (rtn) { 113 trace_scsi_dispatch_cmd_error(cmd, rtn); 114 if (rtn != SCSI_MLQUEUE_DEVICE_BUSY && 115 rtn != SCSI_MLQUEUE_TARGET_BUSY) 116 rtn = SCSI_MLQUEUE_HOST_BUSY; 117 118 scsi_queue_insert(cmd, rtn); 119 120 SCSI_LOG_MLQUEUE(3, 121 printk("queuecommand : request rejected ")); 122 } 123 124 out: 125 SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd() ")); 126 return rtn; 127 }