Linux3.10.0块IO子系统流程(6)-- 派发SCSI命令到低层驱动
在SCSI策略例程中最后调用scsi_dispatch_cmd将SCSI命令描述符派发给低层驱动进行处理
/**
* scsi_dispatch_command - Dispatch a command to the low-level driver.
* @cmd: command block we are dispatching.
*
* Return: nonzero return request was rejected and device's queue needs to be
* plugged.
*/
int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
{
struct Scsi_Host *host = cmd->device->host;
unsigned long timeout;
int rtn = ; // 递增SCSI设备的IO请求统计数
atomic_inc(&cmd->device->iorequest_cnt); /*
* check if the device is still usable
* 检测设备是否还可用。在此时,可能别的地方已经将设备状态置为SDEV_DEL,如果这样,我们将所有命令出错,将命令的结果标记为DID_NO_CONNECT,调用scsi_done结束
*/
if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
/* in SDEV_DEL we error all commands. DID_NO_CONNECT
* returns an immediate error upwards, and signals
* that the device is no longer present */
cmd->result = DID_NO_CONNECT << ;
scsi_done(cmd);
/* return 0 (because the command has been processed) */
goto out;
} /* Check to see if the scsi lld made this device blocked. 检查SCSI低层驱动是否已经阻塞了这个设备*/
if (unlikely(scsi_device_blocked(cmd->device))) {
/*
* in blocked state, the command is just put back on
* the device queue. The suspend state has already
* blocked the queue so future requests should not
* occur until the device transitions out of the
* suspend state.
*/ scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); SCSI_LOG_MLQUEUE(, printk("queuecommand : device blocked \n")); /*
* NOTE: rtn is still zero here because we don't need the
* queue to be plugged on return (it's already stopped)
*/
goto out;
} /*
* If SCSI-2 or lower, store the LUN value in cmnd.
*/
if (cmd->device->scsi_level <= SCSI_2 &&
cmd->device->scsi_level != SCSI_UNKNOWN) {
cmd->cmnd[] = (cmd->cmnd[] & 0x1f) |
(cmd->device->lun << & 0xe0);
} /*
* We will wait MIN_RESET_DELAY clock ticks after the last reset so we can avoid the drive not being ready.
* 如果主机适配器的resetting被设置为1,表示其last_Reset域有效。也就是说,后者记录了主机适配器上次复位的时间。
* 在复位后必须有2秒钟的延时,才能向这个主机适配器发送命令。
*/
timeout = host->last_reset + MIN_RESET_DELAY; if (host->resetting && time_before(jiffies, timeout)) {
int ticks_remaining = timeout - jiffies;
/*
* NOTE: This may be executed from within an interrupt
* handler! This is bad, but for now, it'll do. The irq
* level of the interrupt handler has been masked out by the
* platform dependent interrupt handling code already, so the
* sti() here will not cause another call to the SCSI host's
* interrupt handler (assuming there is one irq-level per
* host).
*/
while (--ticks_remaining >= )
mdelay( + / HZ);
host->resetting = ;
} // 在提交SCSI命令之前输出信息
scsi_log_send(cmd); /*
* Before we queue this command, check if the command length exceeds what the host adapter can handle.
* 在将命令排入队列之前,检查命令长度是否超过了主机适配器可以处理的最大长度,如果这样,将命令结果标记为DID_ABORT并返回
*/
if (cmd->cmd_len > cmd->device->host->max_cmd_len) {
SCSI_LOG_MLQUEUE(,
printk("queuecommand : command too long. "
"cdb_size=%d host->max_cmd_len=%d\n",
cmd->cmd_len, cmd->device->host->max_cmd_len));
cmd->result = (DID_ABORT << ); scsi_done(cmd);
goto out;
} /* 在获取锁的过程中,可能别的地方已经将主机适配器的状态设置为“删除”。如果这样,标记为DID_NO_CONNECT并返回*/
if (unlikely(host->shost_state == SHOST_DEL)) {
cmd->result = (DID_NO_CONNECT << );
scsi_done(cmd);
} else {
trace_scsi_dispatch_cmd_start(cmd);
cmd->scsi_done = scsi_done;
rtn = host->hostt->queuecommand(host, cmd); // 调用主机适配器模板的queuecommand回调,将SCSI命令排入低层设备驱动的队列,调用时传入scsi_done,以便低层驱动完成后回调
} if (rtn) {
trace_scsi_dispatch_cmd_error(cmd, rtn);
if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
rtn != SCSI_MLQUEUE_TARGET_BUSY)
rtn = SCSI_MLQUEUE_HOST_BUSY; scsi_queue_insert(cmd, rtn); SCSI_LOG_MLQUEUE(,
printk("queuecommand : request rejected\n"));
} out:
SCSI_LOG_MLQUEUE(, printk("leaving scsi_dispatch_cmnd()\n"));
return rtn;
}
Linux3.10.0块IO子系统流程(6)-- 派发SCSI命令到低层驱动的更多相关文章
- Linux3.10.0块IO子系统流程(0)-- 块IO子系统概述
前言:这个系列主要是记录自己学习Linux块IO子系统的过程,其中代码分析皆基于Linux3.10.0版本,如有描述错误或不妥之处,敬请指出! 参考书籍:存储技术原理分析--基于Linux 2.6内核 ...
- Linux3.10.0块IO子系统流程(7)-- 请求处理完成
和提交请求相反,完成请求的过程是从低层驱动开始的.请求处理完成分为两个部分:上半部和下半部.开始时,请求处理完成总是处在中断上下文,在这里的主要任务是将已完成的请求放到某个队列中,然后引发软终端让中断 ...
- Linux3.10.0块IO子系统流程(5)-- 为SCSI命令准备聚散列表
SCSI数据缓冲区组织成聚散列表的形式.Linux内核中表示聚散列表的基本数据结构是scatterlist,虽然名字中有list,但它只对应一个内存缓冲区,聚散列表就是多个scatterlist的组合 ...
- Linux3.10.0块IO子系统流程(3)-- SCSI策略例程
很长时间以来,Linux块设备使用了一种称为“蓄流/泄流”(plugging/unplugging)的技术来改进吞吐率.简单而言,这种工作方式类似浴盆排水系统的塞子.当IO被提交时,它被储存在一个队列 ...
- Linux3.10.0块IO子系统流程(2)-- 构造、排序、合并请求
Linux块设备可以分为三类.分别针对顺序访问物理设备.随机访问物理设备和逻辑设备(即“栈式设备”) 类型 make_request_fn request_fn 备注 SCSI 设备等 从bio构 ...
- Linux3.10.0块IO子系统流程(4)-- 为请求构造SCSI命令
首先来看scsi_prep_fn int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device ...
- Linux3.10.0块IO子系统流程(1)-- 上层提交请求
Linux通用块层提供给上层的接口函数是submit_bio.上层在构造好bio之后,调用submit_bio提交给通用块层处理. submit_bio函数如下: void submit_bi ...
- DPA 9.1.85 升级到DPA 10.0.352流程
SolarWinds DPA的升级其实是一件非常简单的事情,这里介绍一下从DPA 9.1.95升级到 DPA 10.0.352版本的流程.为什么要升级呢? DPA给用户发的邮件已经写的非常清楚了(如下 ...
- 【转】linux IO子系统和文件系统读写流程
原文地址:linux IO子系统和文件系统读写流程 我们含有分析的,是基于2.6.32及其后的内核. 我们在linux上总是要保存数据,数据要么保存在文件系统里(如ext3),要么就保存在裸设备里.我 ...
随机推荐
- 转载 Unity Text 插入超链接
using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressi ...
- Go 初体验 - 令人惊叹的语法 - defer.2 - 如何提前执行?
上一文中讲到 defer 会在宿主函数 return 之前调用,那么我们就是想在宿主函数执行到中间调用,怎么办呢? 1. 改变宿主函数逻辑,分成多个函数,需要的那个函数里 defer . 2. 使用匿 ...
- 如何在java List中进行模糊查询
比如我有下面这样一个List,里面存放的是多个Employee对象.然后我想对这个List进行按照Employee对象的名字进行模糊查询.有什么好的解决方案么? 比如我输入的查询条件为“wang”,那 ...
- Session, Token and SSO 有什么区别
Session, Token and SSO 有什么区别 Basic Compareation Session-based Authentication In Session-based Authen ...
- [openjudge-贪心]装箱问题
题目描述 描述 一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为1*1, 2*2, 3*3, 4*4, 5*5, 6*6.这些产品通常使用一个 6*6 ...
- DRF之视图类(mixin)源码解析
同样的增删改查操作,如果我们还像之前序列化组件那样做,代码重复率过多,所以我们用视图表示: 具体源码实现:首先定义一个视图类,然后根据mixin点进去有五个封装好的方法,这五个方法共有的属性就是都需 ...
- ajax跨域问题及相关解决方案
1 什么是跨域 所谓的跨域是指浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器施加的安全限制. 所谓同源是指,域名,协议,端口均相同: 2 什么时候会存在跨域的问题 页面访问不同源 ...
- Codeforces Round #505 (Div 1 + Div 2 Combined) Solution
从这里开始 题目列表 瞎扯 Problem A Doggo Recoloring Problem B Weakened Common Divisor Problem C Plasticine zebr ...
- luogu[愚人节题目3]现代妖怪殖民地 NTT
U34272 [愚人节题目3]现代妖怪殖民地 fft 题目链接 https://www.luogu.org/problemnew/show/U34272 思路 虽然是个py题. ntt(或者fft)模 ...
- python 基础知识点二
深浅copy 1对于赋值运算来说,l1与l2指向的是同一个内存地址,所以他们是完全一样的. l1 = [1,2,3,['barry','alex']] l2 = l1 l1[0] = 111 prin ...