接下来的时间里我们会接触两个变量,fake_sense和need_auto_sense,sense顾名思义,感觉.所以就让我们跟着感觉走.我们前面提到过,如果设备想发送比期望值更多的数据,那么我们前面就设了fake_sense为1.这里就来看看设为1之后怎么办.这里咱们看到了这个一个冬冬,usb_stor_sense_invalidCDB,她是谁? 

让我们把镜头对准drivers/usb/storage/scsiglue.c,

479 /* To Report "Illegal Request: Invalid Field in CDB */
    480 unsigned char usb_stor_sense_invalidCDB[18] = {
    481         [0]     = 0x70,                     /* current error */
    482         [2]     = ILLEGAL_REQUEST,          /* Illegal Request = 0x05 */
    483         [7]     = 0x0a,                     /* additional length */
    484         [12]    = 0x24                      /* Invalid Field in CDB */
    485 };
    486

这是一个字符数组,共18个元素,初始化的时候其中4个元素被赋了值,为了说明这个数组,下面不得不插播一段scsi广告,广告过后立刻回来.

我们知道SCSI通过命令通信,有一个命令是Request Sense.她是用来获取错误信息的,不知道为什么,那些有文化的人把错误信息唤作sense data.可能老外取名字都喜欢取得很优雅吧,相比之下,我们国内很多东西取名字就有些土,比如某所高校,中文名是沈阳理工,而英文名居然就是Shenyang Ligong University.这样没文化的名字实在让人笑死了.如果一个设备接收到了一个Request Sense命令,那么她将按游戏规则返回一个sense data,我们可以参考scsi协议,找到sense data的格式规定,如下图所示:

标准的sense data是18个bytes的.所以这里准备了一个18个元素的数组,第0个byte的低七位称为error code,0x70表明是出问题的是当前这个命令,第二个byte的低四位成为sense key,0x5h称为Illegal Request,表明命令本身有问题,比如命令的参数不合法.而第七个byte称为additional sense length表明在这个18个元素之后还会有additional sense bytes,而她的长度就在这里被标注了,这些additional sense bytes通常指的是一些命令特有的数据,或者是一些外围设备特有的数据,这里为她赋值为0x0a.而第十二个byte,称为additional sense code,这部分针对sense key提供一些信息,也就是说比如sense key如果是Illegal Request,那么我们知道了是命令有问题,那么究竟有什么问题呢?additional sense code提供更详细的一些信息,scsi规范中对24h的描述是Invalid Field in CDB,正是我们这里注释所说.

所以,这样我们明白了,1073行,就是将usb_stor_sense_invalidCDB数组里边的冬冬copy至srb->sense_buffer里边,然后返回USB_STOR_TRANSPORT_NO_SENSE.struct scsi_cmnd结构体里面是这样定义sense_buffer的,

115 #define SCSI_SENSE_BUFFERSIZE   96
    116         unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];              /* obtained by REQUEST SENSE
    117                                                  * when CHECK CONDITION is
    118                                                  * received on original command
    119                                                  * (auto-sense) */

关于sense_buffer就得从scsi协议以及Linux中的scsi核心层来讲了.scsi协议里边有这么一码子事,当一个scsi命令执行出了错,你可以发送一个REQUEST_SENSE命令给目标设备,然后它会返回给你一些信息,即sense data.不过呢,scsi核心层偷懒,把这一艰巨的任务抛给了底层驱动,即我们作为底层驱动不得不自己发送REQUEST SENSE命令给目标设备.当然了,所谓的scsi core偷懒并不是没有它的道理,因为有些scsi host卡会自动发送这个命令,就是说当设备汇报说命令执行有误,那这时scsi host卡会自动发送REQUEST SENSE命令去了解详情.所以scsi core就干脆把权力下放,让底层驱动自己去处理吧.因此稍后我们会看到一个变量名字叫做need_auto_sense.就是说,REQUEST SENSE这个命令要么就是硬件你自动发出去,要么就让软件自动发出去,总之scsi core这一层是不管你了.只要你最终返回scsi核心层的时候把相关的sense data保存在srb->sense_buffer里,scsi核心层自然就知道该如何处理了.

再回到我们具体的问题中来,我们说了,有些设备就是贱,你明明只期望它返回n个字节,它偏偏要给你捣乱,它想返回n+m个字节,对于这种情况我们怎么处理?老实说,它想多返回的几个字节我们完全可以抛弃,因为我们只关心我们提供的buffer是否装满了,是否达到了我们要求的length个字节,如果达到了,那么剩下的不管也罢,不过写代码的同志们在这个问题上考虑得比我们要周到,他们对这个细节也是体贴入微的.或者说他们对这种傻X的设备也是很关心的.对于这种情况,写代码的同志们考虑,还是应该向上层汇报一下,说明这个命令对这个设备来说,执行起来总有些问题.因为这种情况完全可能就是,比如说,一个命令可以带有一些参数,而可能某个设备并不支持其中的某个参数,而你执行命令的时候去设了这个参数,那么设备的返回值可能就不正常,所谓的比预期的值要多就是一种不正常的表现,所以呢,对于这种情况,我们干脆就告诉上层这个命令有问题,在Linux中,我们就可以通过sense data来向上层汇报.而之所以这里称作fake sense,说的是这个sense data里面的东西是我们自己设置好的,因为我们已经很清楚我们应该在设备里放置什么,不需要向设备发送一个REQUEST SENSE的命令,而更确切的说,我们这个命令的返回结果是US_BULK_STAT_OK,也就是说,从设备那方返回的状态来看,设备认为命令没有问题,但是你说设备的话你能相信吗?老实说,从孙志刚案件开始,我不相信警察!从刘涌案件开始,我不相信法律!从苏秀文案件开始,我不相信政府!从打工受户籍歧视开始,我不相信有公平!从CCTV每天报喜不报忧开始,我不相信有真话!而从我进入复旦微电子系开始学习计算机硬件,我他妈的就没相信过硬件设备.不是这有毛病就是那有毛病,硬件bug到处都是.算了,别跑题了,继续说,因为设备认为传输是成功的,所以你发送REQUEST SENSE根本就没用,因为设备根本就不会为你准备sense data,因为sense data本来就是为了提供错误信息的.因此我们需要自己设一个sense data,放进sense_buffer里去.从而让scsi core那一层知道有这么一回事,别被设备瞒天过海给忽悠了.

讲到这里,usb_stor_Bulk_transport()这个函数就算结束了.返回值一共就是四种情况,USB_STOR_TRANSPORT_GOOD,USB_STOR_TRANSPORT_FAILED,USB_STOR_TRANSPORT_ERROR,以及USB_STOR_TRANSPORT_NO_SENSE.然后上层会去分析这些返回值.让我们结束这个函数,回到调用她的函数中来,即usb_stor_invoke_transport().在回去之前,我们需要记住的就是,对于刚才说的这种情况,即fake_sense为1的情况,我们返回的就是USB_STOR_TRANSPORT_NO_SENSE.一会我们会看到usb_stor_invoke_transport()中是如何应付这种情况的.

Linux那些事儿之我是U盘(49)跟着感觉走(一)相关推荐

  1. Linux那些事儿之我是U盘(50)跟着感觉走(二)

    回到usb_stor_invoke_transport()中来,540行,还是老套路,又问是不是命令被放弃了,放弃了当然下面的就别执行了.goto Handle_Abort去. 546行,如果有错误, ...

  2. linux 那些事儿之我是 u 盘,《Linux那些事儿之我是USB》.PDF

    <Linux 那些事儿之我是 USB> 作者:华清远见 第 1 章 Linux 那些事儿之我是 USB Core 专业始于专注 卓识源于远见 1 .引子 老夫子们痛心疾首地总结说,现代青年 ...

  3. 转载本论坛 (fudan_abc ) :linux那些事儿之我是u盘(16)冰冻三尺非一日之寒

    不是一天建成的 . 在让 U 盘工作之前 , 其实我们的驱动作了很多准备工作 . 我们继续跟着感觉走,storage_probe(),943行至948行,一系列的以init_*命名的函数在此刻被调用, ...

  4. Linux那些事儿之我是U盘(5)外面的世界很精彩

    看代码之前,我曾经认真的思考过这么一个问题,我需要关注的仅仅是drivers/usb/storage/目录下面那相关的3000多行代码吗?就是这样几个文件就能让一个个不同的U盘在Linux下面工作起来 ...

  5. Linux那些事儿之我是U盘(4)想到达明天,现在就要启程

    既然知道了怎么编写一个模块,那么编写设备驱动程序自然也就不难了.我相信,每一个会写模块的人都不会觉得写设备驱动有困难.对自己行不行不确定的话,可以去问一下葛优,他准说:"(神州行),我看行. ...

  6. Linux那些事儿之我是U盘(1)小城故事

    这个故事中使用的是2.6.10的内核代码.Linux内核代码目录中, 所有去设备驱动程序有关的代码都在drivers/目录下面,在这个目录中我们用ls命令可以看到很多子目录. localhost:/u ...

  7. 【转】Linux那些事儿之我是U盘(4)想到达明天,现在就要启程

    既然知道了怎么编写一个模块,那么编写设备驱动程序自然也就不难了.我相信,每一个会写模块的人都不会觉得写设备驱动有困难.对自己行不行不确定的话,可以去问一下葛优,他准说:"(神州行),我看行. ...

  8. Linux那些事儿之我是U盘--引子

    也许是在复旦养成了昼伏夜出的坏习惯,工作之后也总是很晚也不愿意睡.来到北京之后,开始听广播听都市之声的北京不眠夜.这个节目是从23点直到第二天凌晨一点,我常常是听完了才会睡觉.无论是北京还是上海,对我 ...

  9. Linux那些事儿之我是U盘(51)光荣属于苹果,属于诺基亚,属于摩托罗拉,属于索尼爱立信

    这一节我们来分析一个在很多企业的产品中都存在的bug.写设备驱动是一件很实在的事情,你得根据实实在在的硬件来编写你的代码,如果你的硬件存在某种bug,那么你就要去fix它.如果你希望成为通用的驱动程序 ...

最新文章

  1. 从技术到科学,中国AI向何处去?
  2. java迭代器应用 源码探究
  3. 全网最全的Windows下Anaconda2 / Anaconda3里正确下载安装用来定时任务apscheduler库(图文详解)...
  4. 算法设计与分析——贪心算法——活动安排问题
  5. Linux下检测网络状态是否正常
  6. if和switch以及for
  7. python-flask-uwsgi体验
  8. 今天遇到了一个很坑爹的问题....
  9. android animation学习
  10. 文件上传下载——sz和rz
  11. java高级工程师哪些技术要掌握?
  12. 全票通过!数据集成平台 SeaTunnel 成功进入 Apache 孵化器!
  13. CC2430DMA学习
  14. eclipse建web工程的dynamic web module version 具体是什么意思
  15. Kubernetes部署策略:重建、滚动更新、蓝绿部署、金丝雀部署
  16. 每天新老用户,日活,周活,月活的hive计算
  17. Javascript里EQ、NE、GT、LT、GE、LE含义
  18. 奇葩说Cisco router与PC交互(一)
  19. 图解Java多线程设计模式——Java多线程基础
  20. 英语berylite绿宝石BERYLITE绿柱石

热门文章

  1. 各国的手机制式和频率
  2. 王者荣耀服务器维修时间2020,王者荣耀时间限制规则2020
  3. 读书笔记——《红处方》(毕淑敏)
  4. python三维矩阵赋值_Python的多维空数组赋值方法
  5. flex详解以及利用flex进行骰子布局
  6. StudyJams-第06课_篮球记分板
  7. 《贫穷的本质》,我们为什么摆脱不了贫穷
  8. 技术分析-提高显卡效能
  9. 一个好的企业所应具备的企业制度
  10. JavaScript入门到精通