linux 3.10 驱动,Linux3.10.0块IO子系统流程(6)-- 派发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 be6 * plugged.7 */

8 int scsi_dispatch_cmd(struct scsi_cmnd *cmd)9 {10 struct Scsi_Host *host = cmd->device->host;11 unsigned longtimeout;12 int rtn = 0;13

14 //递增SCSI设备的IO请求统计数

15 atomic_inc(&cmd->device->iorequest_cnt);16

17 /*

18 * check if the device is still usable19 * 检测设备是否还可用。在此时,可能别的地方已经将设备状态置为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_CONNECT23 * returns an immediate error upwards, and signals24 * 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 on35 * the device queue. The suspend state has already36 * blocked the queue so future requests should not37 * occur until the device transitions out of the38 * suspend state.39 */

40

41 scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);42

43 SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));44

45 /*

46 * NOTE: rtn is still zero here because we don't need the47 * 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 interrupt72 * handler! This is bad, but for now, it'll do. The irq73 * level of the interrupt handler has been masked out by the74 * platform dependent interrupt handling code already, so the75 * sti() here will not cause another call to the SCSI host's76 * interrupt handler (assuming there is one irq-level per77 * 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\n",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\n"));122 }123

124 out:125 SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));126 returnrtn;127 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值