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

usb_stor_invoke_transport(),540,,,.goto Handle_Abort.

546,,,USB_STOR_TRANSPORT_ERROR,.USB_STOR_TRANSPORT_FAILED,,,,,,,,,FAILED,,,,ERROR.,us->transport_reset(us),us->transport_reset(),us->transport(),U,usb_stor_Bulk_reset().reset,,,,.reset,..,srb->resultDID_ERROR..

554,,USB_STOR_TRANSPORT_NO_SENSE.,scsiSAM_STAT_CHECK_CONDITION.,scsisrb->sense_buffer.SAM_STAT_CHECK_CONDITIONscsi,scsi,scsi,,,,Bulk-Only spec.scsi,scsiphase.phase,bus free phase,selection phase,message phase.(status code).,scsi.include/scsi/scsi.h.

 117 /*

 118 * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft

 119 * T10/1561-D Revision 4 Draft dated 7th November 2002.

 120 */

 121 #define SAM_STAT_GOOD 0x00

 122 #define SAM_STAT_CHECK_CONDITION 0x02

 123 #define SAM_STAT_CONDITION_MET 0x04

 124 #define SAM_STAT_BUSY 0x08

 125 #define SAM_STAT_INTERMEDIATE 0x10

 126 #define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14

 127 #define SAM_STAT_RESERVATION_CONFLICT 0x18

 128 #define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */

 129 #define SAM_STAT_TASK_SET_FULL 0x28

 130 #define SAM_STAT_ACA_ACTIVE 0x30

 131 #define SAM_STAT_TASK_ABORTED 0x40

,SAM_STAT_CHECK_CONDITIONscsiCHECK CONDITION,sense databuffer,scsi coresense buffer.,.

559,,srb->resultSAM_STAT_GOOD,ok.,REQUEST SENSE,srb->result.

566,need_auto_sense,,0.574588,if,need_auot_sense,1.if,,REQUEST SENSE,,USB_STOR_TRANSPORT_FAILED,REQUEST SENSE.flagREQUEST SENSE.if?,,.,CBDPCM,scsisense buffer,sense buffer,?sense buffer,bulk-in pipe,,sense buffer,sense buffersense data,.,,..

594,srb->resid0,,n,n-m.,,INQUIRY,,,,,,,,,,,,pdf,,,pdf.,.US_DEBUGP,,.

,604,713,need_auto_senseREQUEST SENSE.,Bulk,,,Bulk,struct scsi_cmnd,us->transport(us->srb,us),..,struct scsi_cmnd,srb,us->transport,us->transport.:

old_cmndsrb->cmnd;

old_cmd_lensrb->cmd_len;

srb->cmnd,,REQUEST SENSE.

REQUEST SENSE,RBCSCSI,6,,12.

old_sc_data_directionsrb->sc_data_direction,srb->sc_data_directionREQUEST SENSE,DMA_FROM_DEVICE,,REQUEST SENSEsense data,.

old_request_buffersrb->request_buffer,srb->request_buffersrb->sense_buffer,old_request_bufflensrb->request_bufflen,srb->request_bufflen18.

old_sgsrb->use_sg,srb->use_sg0,scatter-gather.

old_serial_numbersrb->serial_number,srb->serial_number.

old_residsrb->resid,srb->resid0.

us->transport(us->srb,us).temp_result.

,659666,.

668,,goto Handle_Abort.

672,temp_result,result,REQUEST SENSEfail.srb->result=DID_ERROR<<16.us->transport_reset(us)reset,REQUEST SENSE,,,!,US_FL_SCM_MULT_TARGflag,flagtarget,reset,REQUEST SENSE,,..targetreset,.

685696temp_result,sense_buffer...

,,692,usb_stor_show_sense().,,,usb_stor_show_command().,drivers/usb/storage/debug.c:

159 void usb_stor_show_sense(
160 unsigned char key,
161 unsigned char asc,
162 unsigned char ascq) {
163
164 const char *what, *keystr;
165
166 keystr = scsi_sense_key_string(key);
167 what = scsi_extd_sense_format(asc, ascq);
168
169 if (keystr == NULL)
170 keystr = "(Unknown Key)";
171 if (what == NULL)
172 what = "(unknown ASC/ASCQ)";
173
174 US_DEBUGP("%s: ", keystr);
175 US_DEBUGPX(what, ascq);
176 US_DEBUGPX("/n");
177 }

这里面又调用了其她函数,scsi_sense_key_stringscsi_extd_sense_format,这两个函数来自driver/scsi/constants.c,暂且不表.先来看对usb_stor_show_sense这个函数的调用.传递给她的实参是srb->sense_buffer中的几个元素,对比咱们前面贴出来的那个sense data的格式,可知sense_buffer[2]的低四位被称为Sense Key,sense_buffer[12]Additional sense code,也称ASC,sense_buffer[13]Additional sense code qulifier,也称ASCQ.这三个冬冬联手为mid level提供了需要的信息,主要也就是错误信息或者异常信息.为什么要三个冬冬呢?实际上就是一个分层的描述方法,比如要描述某个房间就要说某城市某街道某门牌号.这三个冬冬也是起着这么一个作用,Sense Key是第一层,ASC则是对她的补充,ASCQ则又是对ASC的补充,或者说解释.这样我们再来看看usb_stor_show_sense就很清楚了,咱们传递进来的是三个char变量,而实际的信息就像某种编码一样被融入在了这些char变量中,而调用的两个来自scsi核心层的函数scsi_sense_key_stringscsi_extd_sense_format就是起着翻译的作用,也叫解码.解码了就可以打印出来了.Yeah!

699,srb->result设置为SAM_STAT_CHECK_CONDITION.为什么?不为什么,Request Sense执行完之后,scsi规范告诉我们应该把srb->result设为SAM_STAT_CHECK_CONDITION,酱紫mid level就知道去检查sense data.这也是为什么在554,555行会令srb->result也为这个值,只不过那次sense data是咱们自己手工准备的,不是通过命令获得的.

704这个if这一小段,首先咱们需要明白,need_auot_sense这个flag被设为1实际上是有两种可能的,它本身是在usb_stor_invoke_transport()中第一行所定义的一个局部变量,并且在这个函数中特意把它初始化为0. 第一处设置为1的位置是574行当时check us->protocolUS_PR_CB或者US_PR_DPCM_USB,对于这种设备,(如果您只关心u,那么就甭理这种设备了.)第二处设置这个flag的就是我们确实遇到了failure,585,result如果等于USB_STOR_TRANSPORT_FAILED,这种情况当然要设置need_auto_sense.704行这里判断result是否等于USB_STOR_TRANSPORT_GOOD,那么很显然,如果result等于USB_STOR_TRANSPORT_FAILED,那么它就不可能等于USB_STOR_TRANSPORT_GOOD,因此,这里这个判断一定是针对第一种need_auto_sense的情况,正如我们曾经说过的,遵守US_PR_CB/US_PR_DPCM_USB协议的设备是不会自己返回命令执行之后的Status,所以我们不管它执行到底成功与否,我们都会对它来一次REQUEST SENSE,就是为了尽可能多的获取一些信息,这样一旦出了问题,我们至少能多一些辅助信息来帮我们判断问题出在哪.那么对于USB_STOR_TRANSPORT_GOOD的情况,首先这说明命令执行是没有问题的了,我们仔细看一下这个if语句,除了这个条件以外还判断了另外三个条件,(srb->sense_buffer[2]&0xaf)结果为0,那么说明srb->sense_buffer[2]bit0~bit3都为0,bit50,bit7也为0,bit4bit6是什么我们无所谓.(如果这个你还要问为什么那么我只能说你没救了.没办法,这个世界上只有10种人,一种是懂二进制的,一种是不懂二进制的.)虽然我们没有兴趣熟悉每一个SCSI命令的细节,但我们毕竟是共产主义接班人,应该对社会主义建设的方方面面都有所了解,所以让我们来仔细看看这个sense_buffer[2].对照sense data的格式那张图,sense data的第二个字节,bit0~bit3sense key,bit4Reserved,即保留的,不使用的.bit5ILI,全称incorrect length indicator,bit6EOM,全称End of Medium,bit7Filemark,伟大的不朽的金山词霸告诉我们这个词叫做卷标.关于sense key,Scsi协议是这么规定的,如果sense key0h,那么这种情况表示NO SENSE.这种情况通常对应于命令的成功执行或者就是Filemark/EOM/ILI bits中的任一个被设置为了1.需要注意的是,scsi协议里边定义了四样东西,Filemark/EOM/ILI/Sense Key,它们都是为了提供错误信息的,只是前三者只要一个bit就能表达明确的意思了,而最后一个包含很多信息,所以需要用4bits,并且还在后面附有很多额外信息,sense_buffer[12]sense_buffer[13],这里也要求它们为0,即所谓的ASCASCQ都为0,scsi协议里面,这种情况称之为NO ADDITIONAL SENSE INFORMATION.关于这一点scsi协议是这么说的:”The REQUEST SENSE command requests that the target transfer sense data to the initiator. If the target has no other sense data available to return, it shall return a sense key of NO SENSE and an additional sense code of NO ADDITIONAL SENSE INFORMATION.”而这正是我们这里的代码所表达的意思.(什么?你要我翻译这段话?有没有搞错啊,难道你没上过新东方,没听过老罗的课?那么我代表人民代表党义正严辞的告诉你,同志,你真的落伍了耶!)

(filemarkeom都是针对磁带设备的,跟磁盘设备无关.也就是说跟咱们无关.)

最后,满足了这四个条件的情况就表示刚才这次scsi命令的传输确实是圆满完成了.应该说这次检测还是蛮严格的,毕竟开源社区的同志们觉得写代码不像我们开会,每次看新闻,发现凡是会议必然是圆满成功的.这里人家检查了这么多条件都满足然后就设置srb->resultSAM_STAT_GOOD,并且把srb->sense_buffer[0]也置为0.sense databyte 0由两部分组成,ValidError code,如果置为0,首先就说明这整个sense data是无效的, scsi标准的说法叫invalid, 所以scsi core自然没法识别这么一个sense data,而我们既然认定这个命令是成功执行的,当然就没有必然让scsi core 再去理睬这么一个sense data.

以上花了大量笔墨就讲了704712这个if语句段.需要重新强调一点,正如我们已经说过的,对于U,这段代码根本就不可能执行,理由我们已经说过了.但是既然它出现在我们眼前了,我们又有什么理由去逃避呢?写代码,尤其是写这种通用的设备驱动程序,必然要考虑各种情况,不是完全跟着感觉走,也不是纯粹的追求华丽的算法和数据结构,更应该接近实际,华丽的代码堆砌的东西缺乏骨质感.

这样,关于need_auto_sense设置了的这一段就结束了.最后还想重复一点,说起来,REQUEST SENSE这种命令应该由mid level来发,不应该由底层驱动来发,不过通常mid-level并不愿意发这个命令,因为实际上很多SCSI主机适配卡(SCSI host adapter)会自动request the sense.所以为了让事情变得简单,设计上要求底层驱动去对付这个问题.所以要么SCSi host adapters自动获得sense data,要么就是咱们LLD(底层驱动程序)去发送这个命令,对于咱们这个模拟的scsi系统,当然只能是用软件去实现,即咱们必须在LLD中用代码来发送request sense.

再然后,716,如果经过了这么一番折腾,srb->result仍然等于SAM_STAT_GOOD,(我们在559,即进行autosense之前把srb->result设置成了SAM_STAT_GOOD.)那么说明真金不怕火炼,我们再判断最后一个条件,即我们要求传输的数据长度是srb->request_bufflen,而实际上还剩下srb->resid个字节没有被传送,这种情况本身没什么,但是struct scsi_cmnd中有一个成员叫做underflow,其意思是如果传输的数据连这个值都没有达到的话,不管其它条件如何,必须向上层反映,出错了.换句话说,有些scsi命令有一个底线,你至少得达到我这个底线,否则我跟你急!所以这里就是判断这么一个条件是否满足,如果传输的长度小于srb->underflow,那么不用废话,即便你其它条件判断下来都觉得这个命令是成功的,我还是要汇报说你这个命令执行有误.而关于这种情况,我们反馈给scsi coreresultDID_ERROR<<16或上SUGGEST_RETRY<<24.DID_ERROR被定义为0x07,SUGGEST_RETRY0x10.其定义都在include/scsi/scsi.h.所以这里srb->result就最终被设置为0x10070000.还记不记得当初我们贴出来的那个关于US_FL_IGNORE_RESIDUE关于MP3的调试信息了?回过去看一下,没错,当时的result就是0x10070000,也就是这里赋的值.而当时之所以导致执行了这段代码,原因正是设备报虚警,明明读写正常,它偏要瞎写一个residue到状态字节里去.导致我们的代码在这里判断出读写出了错.这个疑案只有到了这里我们才能真正明白,哈哈!

至此,我们的这个故事也快接近尾声了.故事总有结束的时候,Linux所反映的那种人们对自由的追求却是永无止境的.天长地久有时尽,此恨绵绵无绝期!--开源社区追求自由的战士白居易.

720, usb_stor_invoke_transport().goto Handle_Abort,724,srb->resultDID_ABORT<<16,reset.reset,.

usb_stor_invoke_transport()usb_stor_transparent_scsi_command(),,usb_stor_invoke_transport().flag, US_FL_FIX_CAPACITY,bug.,flag,usb_stor_transparent_scsi_command(),usb_stor_control_thread(),375us->proto_handler(us->srb,us)usb_stor_transparent_scsi_command(),375,usb_stor_control_thread(),,,kill,,,,...

US_FL_FIX_CAPACITY,bug,bug,2.6.10,,,,,AppleiPod, 3250,E70,E60,N91,N80,E61,NIKONDSC D70,DSC D70s,DSC D80,P990i,M600i,RAZR V3x,RAZR V3i,.Nokia 6108,AppleiPod20IT,NokiaIntelcustomer,bug.,,Nokia,Apple,,,,,,bug,??,,?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值