Linux那些事儿之我是U盘(48)迷雾重重的Bulk传输(六)

接下来咱们该看看如何处理CSW.1018,usb_stor_bulk_transfer_buf()函数再一次被调用,这次是获得CSW,期望长度是US_BULK_CS_WRAP_LEN,这个宏来自drivers/usb/storage/transport.h:

109 #define US_BULK_CS_WRAP_LEN 13

13对应CSW的长度,13bytes.cswlen记录了实际传输的长度.1025,如果返回值是USB_STOR_XFER_SHORT,表明数据传少了,没有达到我们期望的那么多,而假如cswlen又等于0,那么说明没有获得真正的CSW,正如注释所说,有些变态的设备会在数据阶段末尾多加一些0长度的包进来,这就意味着咱们并没有获得CSW,于是重新执行一次usb_stor_bulk_transfer_buf(),再获得一次.(旁白:数据传输失败了可以重来一次,你我失去的青春能重来一次么?,人生没有彩排,天天都是现场直播.)

1032,如果result等于USB_STOR_XFER_STALLED,interpret_urb_result中查找一下,USB_STOR_XFER_STALLED对应于usb core传回来的是-EPIPE,这种情况说明管道不通,就相当于您家里的下水管道堵塞,当然这也说明get CSW再次失败了...,这种情况很简单,直接retry,为什么要retry?我们看一下interpret_urb_result()函数,最重要的就是310314,这里判断了,因为我们曾经讲过,bulk端点可能会设置了halt条件,设置了这种条件的端点必然会堵塞管道,所以这里就不管如何,试一试看,看清掉这个flag是否会有好转.所以对于这种情况,我们可以重试一次.我们抱着试一试的心态去retry,应该说这种心态是正确的,我再重申一次,这里实际上反映的就是Linux代码背后的哲学,反映的是一种勇敢面对挫折的人生态度,一枚贝壳要用一生的时间才能将无数的沙粒转化成一粒并不规则的珍珠,雨后的彩虹绽放刹那的美丽却要积聚无数的水汽.如果把这些都看成是一次又一次挫折,那么是挫折成就了光彩夺目的珍珠和美丽的彩虹.我们要相信,失败并不可怕,失败是通往成功的道路.

如果您不是像李白一样近视的话,(床前明月光都能看成地上霜的人,还不是近视吗?)您应该会看见这次传递给usb_stor_bulk_transfer_buf()函数的最后一个参数不是像之前那样,这次是NULL,这是因为实际上cswlen作为一个临时变量,表征的是状态阶段的实际传输长度,但是在眼下这种情况我们已经不需要使用这个临时变量了.

1042,好家伙,如果都这么重新获取了还不成功的话,不用再瞎耽误工夫了,直接返回吧,向领导汇报这设备无药可救了.没办法,返回USB_STOR_TRANSPORT_ERROR,到这里还不成功那真的就是让人绝望了.什么?你说失败是成功之母?对于这句话我没有异议,问题是失败在遇上我之前已经结扎了...

而从1046行开始,正式分析CSW.结合我们从usb mass storage bulk only协议中抓出来的那幅图,那幅介绍CSW的格式的图,bcs->Residue对应于CSWdCSWDataResidue,她表示的是实际传输的数据和期望传输的数据的差值.bcs->Signature对应于CSW中的dCSWSignature,bcs->Tag对应于CSW中的dCSWTag,bcs->Status对应于bCSWStatus.我们有些事情没道理的,有人很抢手,有人没资格,路是人走的.bcs中成员的存储格式居然还有区别,有的是little endian,有些却不是.对于那些little endian,咱们需要调用像cpu_to_le32这样的宏来转换,而其她的却不需要转换,对于bcs来说,其成员ResidueSignature就需要这样转换.这些规矩仿佛是没有道理的.

1050,和之前bcb中使用US_BULK_CB_SIGN一样,US_BULK_CS_SIGN这个宏用来标志这个数据包是一个CSW.US_BULK_CS_OLYMPUS_SIGN也是一个宏,不过她是专为某种变态设备专门准备的.这两个宏和接下来将提到的一些宏依然来自drivers/usb/storage/transport.h,

110 #define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
111 /* This is for Olympus Camedia digital cameras */
112 #define US_BULK_CS_OLYMPUS_SIGN 0x55425355 /* spells out 'USBU' */
113 #define US_BULK_STAT_OK 0
114 #define US_BULK_STAT_FAIL 1
115 #define US_BULK_STAT_PHASE 2

对大多数普通的设备来说,如果要标志一个CSW,Signature会是53425355h.但是Olympus Camedia这种数码相机偏偏要标新立异,她愣是跟您换个数字,那咱也没办法.敢情人家设计者是穿美特斯邦威长大的,就是不走寻常路.

Tag就是和CBW相对应的,两个Tag应该相同.要不然也就不叫接头暗号了.前面为Tag赋值为srb->serial_number,这回自然也应该等于这个值.

bcs->Status,标志命令执行是成功还是失败,当她是0表明命令是成功的,当她是非0,嘿嘿,肯定有问题.目前的spec规定,她只能是00h,01h,02h,03hFFh都是保留的,不能用,所以这里会判断她是否是大于US_BULK_STAT_PHASE,也就是说是否会大于02h,大于了当然就不行.,这样子,就是说这些条件如果不满足的话,那么一定是有问题的.返回错误值吧.

1060行至1066,如果residue不为0,那么说明数据没传完,或者说和预期的不一样,那么来细看一下,首先该设备应该没有设置US_FL_IGNORE_RESIDUE这个flag,老规矩,让我们看一下什么样的设备设置了这个flag,

269 /* Yakumo Mega Image 37

270 * Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */

271 UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100,

272 "Tekom Technologies, Inc",

273 "300_CAMERA",

274 US_SC_DEVICE, US_PR_DEVICE, NULL,

275 US_FL_IGNORE_RESIDUE ),

276

277 /* Another Yakumo camera.

278 * Reported by Michele Alzetta <michele.alzetta@aliceposta.it> */

279 UNUSUAL_DEV( 0x052b, 0x1804, 0x0100, 0x0100,

280 "Tekom Technologies, Inc",

281 "300_CAMERA",

282 US_SC_DEVICE, US_PR_DEVICE, NULL,

283 US_FL_IGNORE_RESIDUE ),

284

285 /* Reported by Iacopo Spalletti <avvisi@spalletti.it> */

286 UNUSUAL_DEV( 0x052b, 0x1807, 0x0100, 0x0100,

287 "Tekom Technologies, Inc",

288 "300_CAMERA",

289 US_SC_DEVICE, US_PR_DEVICE, NULL,

290 US_FL_IGNORE_RESIDUE ),

291

292 /* Yakumo Mega Image 47

293 * Reported by Bjoern Paetzel <kolrabi@kolrabi.de> */

294 UNUSUAL_DEV( 0x052b, 0x1905, 0x0100, 0x0100,

295 "Tekom Technologies, Inc",

296 "400_CAMERA",

297 US_SC_DEVICE, US_PR_DEVICE, NULL,

298 US_FL_IGNORE_RESIDUE ),

299

300 /* Reported by Paul Ortyl <ortylp@3miasto.net>

301 * Note that it's similar to the device above, only different prodID */

302 UNUSUAL_DEV( 0x052b, 0x1911, 0x0100, 0x0100,

303 "Tekom Technologies, Inc",

304 "400_CAMERA",

305 US_SC_DEVICE, US_PR_DEVICE, NULL,

306 US_FL_IGNORE_RESIDUE ),

一般的设备是不会设置这个flag,但是确实有那么一些设备是设了这个flag,查一查drivers/usb/storage/unusual_devs.h,发现Tekom公司的数码相机全都有这么一个问题.这个flag的意思很明确,对于这类设备不需要管在乎CSW中的那个dCSWDataResidue,因为十有八九这个字节汇报的东西是错的,是不准的,当然这也就是有一个硬件bug的例子了.所以这里判断的就是这个flag没有设,或者srb->sc_data_direction等于DMA_TO_DEVICE,这种情况下,发送给设备的数据长度不应该超过transfer_length.1064srb->resid本来是我们传递给usb_stor_bulk_transfer_sg的参数,记录的就是剩下的数据长度,(比如期待值是10,传递了8,那么剩余就是2.白痴都知道.),residue刚刚被再次赋值了,不是原来的residue就是transfer_length,要知道原来的residue等于dCSWDataResidue,这是设备传递过来的,换言之,是硬件传来的数据,它未必就和我们软件得来的相同.所以srb->resid这时候就等于residue,以硬件的为准呗.不过我想说的是,这几行代码实际上涉及到一个鲜为人知的花絮,如今这个世界每天都有人爆料,每天都有人炮轰别人,以至于我们常说生活就像宋祖德的嘴,你永远都不知道下一个倒霉的会是谁.不过这里我只爆料不炮轰.首先你看这段代码的时候,一定不明白为什么要判断传输方向是不是DMA_TO_DEVICE对吧,其实这里又是一个硬件的bug,开发设备驱动这东西,最讲究的就是实战,尤其是像usb-storage这么一个通用的模块,它要支持各种各样的设备,不管你是三星家的还是索尼家的,只要你生产的是usb mass storage设备,而且你又不准备自己专门写一个设备驱动,那么我们这个usb-storage就应该支持你这个设备.,在实战中,我们发现,有些设备,他们在执行读操作的时候,经常会在状态阶段汇报一个错误的dCSWDataResidue,就是说比如本来没有传输完全顺利,该传几个字节就传了几个字节,按理说这种情况,dCSWDataResidue应该是记录着0,可是实际上这些设备却把这个值设成了某个正数,你说这不是胡来吗?而如果我们发现这个值是正数,那么当我们向scsi核心层反映我们我们这个命令的结果的时候就会说这个命令执行失败了.但事实上这些设备执行读操作并没有问题,这种情况属于谎报军情,罪该论斩.所以我们这里就加入这么一个标志,对于读操作,即方向为DMA_FROM_DEVICE的情况,咱们就忽略这个dCSWDataResidue,换言之,也就是忽略residue,我们直接返回给scsi那边srb->resid就可以了.反之,对于写操作,即方向为DMA_TO_DEVICE的操作,我们当然不愿意无缘无故的抛弃有效的dCSWDataResidue.所以对于DMA_TO_DEVICE的情况,我们最终返回给scsi核心层的srb->resid是以srb->residresidue中那个大一点的为准.这就是为什么我们这里要判断或者我们设置了US_FL_IGNORE_RESIDUE这么一个flag,或者我们执行的是读操作,对于这两种情况我们要忽略掉residue,反之我们就不忽略.不过有趣的是,三年前,某个老外去开源社区抱怨,说他买了一个中国厂商生产的MP3,该设备在写操作的时候老是莫名其妙的报错,但是在Windows下却用得好好的.最后大家一分析,发现问题就是在这里,即这个设备在写的时候会误报dCSWDataResidue,用社区里面那些伙计的话说就是,这种设备在执行写命令的时候,会往dCSWDataResidue填写垃圾信息.本来写操作是正确的执行了,可是偏偏要让scsi那边以为操作没有执行成功.所以,某位帅哥就提交了一个patch,把这个判断方向的代码去掉了,因为反正读写都有可能出问题,那么干脆甭判断了,都给忽略掉得了,也因此,对于这种有问题的设备,就必须设置US_FL_IGNORE_RESIDUE这个flag.当时那个patch是这样的:

===== drivers/usb/storage/transport.c 1.151 vs edited =====

--- 1.151/drivers/usb/storage/transport.c 2004-10-20 12:38:15 -04:00

+++ edited/drivers/usb/storage/transport.c 2004-10-28 10:50:42 -04:00

@@ -1058,8 +1058,7 @@

  /* try to compute the actual residue, based on how much data

  * was really transferred and what the device tells us */

  if (residue) {

- if (!(us->flags & US_FL_IGNORE_RESIDUE) ||

- srb->sc_data_direction == DMA_TO_DEVICE) {

+ if (!(us->flags & US_FL_IGNORE_RESIDUE)) {

  residue = min(residue, transfer_length);

  srb->resid = max(srb->resid, (int) residue);

  }

:

 usb-storage: Command WRITE_10 (10 bytes)

 usb-storage: 2a 00 00 00 01 37 00 00 08 00

 usb-storage: Bulk Command S 0x43425355 T 0x82 L 4096 F 0 Trg 0 LUN 0 CL 10

 usb-storage: usb_stor_bulk_transfer_buf: xfer 31 bytes

 usb-storage: Status code 0; transferred 31/31

 usb-storage: -- transfer complete

 usb-storage: Bulk command transfer result=0

 usb-storage: usb_stor_bulk_transfer_sglist: xfer 4096 bytes, 2 entries

 usb-storage: Status code 0; transferred 4096/4096

 usb-storage: -- transfer complete

 usb-storage: Bulk data transfer result 0x0

 usb-storage: Attempting to get CSW...

 usb-storage: usb_stor_bulk_transfer_buf: xfer 13 bytes

 usb-storage: Status code 0; transferred 13/13

 usb-storage: -- transfer complete

 usb-storage: Bulk status result = 0

 usb-storage: Bulk Status S 0x53425355 T 0x82 R 3072 Stat 0x0

 usb-storage: -- unexpectedly short transfer

 usb-storage: scsi cmd done, result=0x10070000

 SCSI error : <0 0 0 0> return code = 0x10070000

 end_request: I/O error, dev sda, sector 311

 Bulk.,Command/Data/Status,WRITE_10,,result0,0x10070000,0x10070000,.scsi core,,scsisrb->result.scsireture code,result.srb->result.,srbusb-storagescsi,.

Ok,.1068CSW,.bcs->Status.0,.bcs->Status,usb mass storage bulk only spec,

<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 415.5pt; HEIGHT: 110.25pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image001.emz"></imagedata></shape>

,US_BULK_STAT_OK / US_BULK_STAT_FAIL / US_BULK_STAT_PHASE ,00h,01h,02h..,US_BULK_STAT_FAIL,USB_STOR_TRANSPORT_FAILED,US_BULK_STAT_PHASE,USB_STOR_TRANSPORT_ERROR.,drivers/usb/storage/transport.h:

 131 /*

 132 * Transport return codes

 133 */

 134

 135 #define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */

 136 #define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */

 137 #define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */

 138 #define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */

,...,FAILEDERROR,,,.

US_BULK_STAT_OK,,.fake_sense.fake_sense?,,returnusb_stor_Bulk_transport()(,return,1094,,,USB_STOR_TRANSPORT_ERROR).usb_stor_invoke_transport(),Bulk.Bulk.usb_stor_invoke_transport(),.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值