免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: projl
打印 上一主题 下一主题

《Linux 那些事儿之我是U盘》 [复制链接]

论坛徽章:
0
161 [报告]
发表于 2008-06-06 15:03 |只看该作者
种胭脂能涂抹时间,没有哪一件服装能掩饰灵魂,没有哪一套古籍能装潢空虚,没有哪一家公司能说自己的产
品是完美的,是没有缺陷的.

992行,transfer_length 可能为0,因为有的命令她并不需要您传输数据,所以她没有数据阶段.而对于那
些有数据阶段的情况,咱们进入if 这一段.

993 行,没什么可说的,就是根据数据传输方向确定用接收pipe 还是发送pipe.

然后,995 行,usb_stor_bulk_transfer_sg() 这个函数是真正的执行bulk 数据传输了.这个函数来自
drivers/usb/storage/transport.c 中:

484 /
*
485 * Transfer an entire SCSI command's worth of data payload over the bulk
486 * pipe.
487
*
488 * Note that this uses usb_stor_bulk_transfer_buf() and
489 * usb_stor_bulk_transfer_sglist() to achieve its goals -
-
490 * this function simply determines whether we're going to use
491 * scatter-gather or not, and acts appropriately.
492 *
/
493 int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
494 void *buf, unsigned int length_left, int use_sg, int *residual)
495
{
496 int result;
497 unsigned int partial;
498
499 /* are we scatter-gathering? *
/
500 if (use_sg)
{
501 /* use the usb core scatter-gather primitives *
/
502 result = usb_stor_bulk_transfer_sglist(us, pipe,
503 (struct scatterlist *) buf, use_sg,
504 length_left, &partial)
;
505 length_left -= partial;
506 } else
{
507 /* no scatter-gather, just make the request *
/
508 result = usb_stor_bulk_transfer_buf(us, pipe, buf,
509


length_left, &partial)
;
510


length_left -= partial;
511
}
512
513


/* store the residual and return the error code *
/
514 if (residual)
515


*residual = length_left;
516 return result;
517
}

论坛徽章:
0
162 [报告]
发表于 2008-06-06 15:04 |只看该作者
注释说得很清楚,这个函数是一个壳,真正干活的是她所调用或者说利用的那两个函
数.usb_stor_bulk_transfer_sglist() 和usb_stor_bulk_transfer_buf(). 后者咱们刚才已经遇到过了,
而前者是专门为scatter-gather 传输准备的函数,她也来自drivers/usb/storage/transport.c 中:

433 /
*
434 * Transfer a scatter-gather list via bulk transfer
435
*
436 * This function does basically the same thing as usb_stor_bulk_transfer_buf(
)
437 * above, but it uses the usbcore scatter-gather library.
438 *
/
439 int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
440 struct scatterlist *sg, int num_sg, unsigned int length,
441 unsigned int *act_len)
442
{
443 int result;
444
445 /* don't submit s-g requests during abort/disconnect processing *
/
446 if (us->flags & ABORTING_OR_DISCONNECTING)
447 return USB_STOR_XFER_ERROR;
448
449 /* initialize the scatter-gather request block *
/
450 US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__
,
451 length, num_sg)
;
452 result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
453 sg, num_sg, length, SLAB_NOIO)
;
454 if (result)
{
455 US_DEBUGP("usb_sg_init returned %d\n", result)
;
456 return USB_STOR_XFER_ERROR;
457
}
458
459 /* since the block has been initialized successfully, it's now
460 * okay to cancel it *
/
461 set_bit(US_FLIDX_SG_ACTIVE, &us->flags)
;
462
463 /* did an abort/disconnect occur during the submission? *
/
464 if (us->flags & ABORTING_OR_DISCONNECTING)
{
465
466


/* cancel the request, if it hasn't been cancelled already */
467

if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
468

US_DEBUGP("-- cancelling sg request\n")
;
469


usb_sg_cancel(&us->current_sg)
;
470
}
471
}
472

论坛徽章:
0
163 [报告]
发表于 2008-06-06 15:04 |只看该作者
473

/* wait for the completion of the transfer *
/
474


usb_sg_wait(&us->current_sg)
;
475


clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)
;
476
477


result = us->current_sg.status;
478 if (act_len)
479


*act_len = us->current_sg.bytes;
480


return interpret_urb_result(us, pipe, length, result,
481


us->current_sg.bytes);

482 }

usb_stor_bulk_transfer_sg() 函数中,判断use_sg 是否为0,从而确定是否用scatter-gather. 对于
use_sg 等于0 的情况,表示不用scatter-gather, 那么调用usb_stor_bulk_transfer_buf() 发送scsi
命令.实际传递的数据长度用partial 记录,然后length_left 就记录还剩下多少没传递,初值当然就是期望
传递的那个长度.每次减去实际传递的长度即可.对于use_sg 不等于0 的情
况,usb_stor_bulk_transfer_sglist() 函数被调用.我们来看这个函数.

迷雾重重的Bulk 传输(五)

usb_stor_bulk_transfer_sglist() 这个函数有一定的蛊惑性,我们前面说过,之所以采用sglist, 就是为
了提高传输效率.我们更知道,sg 的目的就是让一堆不连续的buffers 一次DMA 操作就都传输出去.其实在
usb 的故事中,事情并非如此.不过如果你对usb core 里边的行为不关心的话,那就无所谓了.有些事情,你
不知道也好.

446 行,447 行,aborting 了或者disconnecting 了,就不要传递数据了.

然后452 行,usb_sg_init() 函数被调用,这个函数来自drivers/usb/core/message.c, 也就是说,她是
usb 核心层提供的函数,干嘛用的?初始化sg 请求.其第一个参数是struct usb_sg_request 结构体的指
针.这里咱们传递了us->current_sg 的地址给她,这里us->current_sg 第一次派上用场,所以咱们需要
隆重的介绍一下.在struct us_data 中,定义了这么一个成员,struct usb_sg_request current_sg.
曾几何时咱们见到过current_urb,这里又来了一个current_sg.也许你感觉很困惑,这很正常,色彩容易让
人炫目,文字容易让人迷惑,只有张爱玲对现实的认识是清醒的.其实可以这样理解,之前我们知道struct
urb 表征的是一个usb request, 而这里struct usb_sg_request 实际上表示的是一个scatter gather
request,从我们非usb 核心层的人来看,这两个结构体的用法是一样的.对于每次urb 请求,我们所作的只
是申请一个结构体变量或者说申请指针然后申请内存,第二步就是提交urb,即调用usb_submit_urb(),
剩下的事情usb core 就会去帮我们处理了,Linux 中的模块机制酷就酷在这里,每个模块都给别人服务,也
同时享受着别人提供的服务.就像我们常说的,你站在桥上看风景,看风景的人在楼上看你.明月装饰了你的
窗子,你装饰了别人的梦.你要想跟别人协同工作,你只要按照人家提供的函数去调用,把你的指针你的变量
传递给别人,其它的你根本不用管,事成之后你人家自然会通知你.同样对于sg request,usb core 也实现了
这些,我们只需要申请并初始化一个struct usb_sg_request 的结构体,然后提交,然后usb core 那边自然
就知道该怎么处理了.闲话少说,先来看struct usb_sg_request 结构体.她来自include/linux/usb.h:

988 /**

989 * struct usb_sg_request - support for scatter/gather I/O

990 * @status: zero indicates success, else negative errno

论坛徽章:
0
164 [报告]
发表于 2008-06-06 15:05 |只看该作者
991 * @bytes: counts bytes transferred.
992
*
993 * These requests are initialized using usb_sg_init(), and then are used
994 * as request handles passed to usb_sg_wait() or usb_sg_cancel(). Most
995 * members of the request object aren't for driver access.
996
*
997 * The status and bytecount values are valid only after usb_sg_wait(
)
998 * returns. If the status is zero, then the bytecount matches the total
999 * from the request.


1000
*
1001 * After an error completion, drivers may need to clear a halt condition
1002 * on the endpoint.
1003 *
/
1004 struct usb_sg_request
{
1005 int status;
1006 size_t bytes;
1007
1008 /
*
1009 * members below are private to usbcore,
1010 * and are not provided for driver access!
1011 *
/
1012 spinlock_t lock;
1013
1014 struct usb_device *dev;
1015 int pipe;
1016 struct scatterlist *sg;
1017 int nents;
1018
1019 int entries;
1020 struct urb **urbs;
1021
1022 int count;
1023 struct completion complete;
1024 }
;


整个usb 系统都会使用这个数据结构,如果我们希望使用scatter gather 方式的话.usb core 已经为
我们准备好了数据结构和相应的函数,我们只需要调用即可.一共有三个函数,她们是
usb_sg_init,usb_sg_wait,usb_sg_cancel. 我们要提交一个sg 请求,需要做的是,先用usb_sg_init 来
初始化请求,然后usb_sg_wait() 正式提交,然后我们该做的就都做了.如果想撤销一个sg 请求,那么调用
usb_sg_cancel 即可.

咱们虽说不用仔细去看着三个函数内部是如何实现的,但至少得知道该传递什么参数吧.不妨来仔细看一
下usb_sg_init() 被调用时传递给她的参数.头一个刚才已经说了,就是sg request,第二个,需要告诉她是
哪个usb设备要发送或接收数据,咱们给她传递的是us->pusb_dev,第三个,是哪个pipe,这个没什么好说
的,pipe 是上面一路传下来的.第四个参数,这是专门适用于中断传输的,被传输中断端点的轮询率,对于

论坛徽章:
0
165 [报告]
发表于 2008-06-06 15:06 |只看该作者
bulk 传输,直接忽略,所以咱们传递了0.第五个和第六个参数就分别是sg 数组和sg 数组中元素的个数.然
后第七个参数,length, 传递的就是咱们希望传输的数据长度,最后一个是SLAB flag, 内存申请相关的一个
flag.如果驱动程序处于block I/O 路径中应该使用GFP_NOIO, 咱们这里SLAB_NOIO 实际上是一个宏,
实际上就是GFP_NOIO. 不要问我为什么用SLAB_NOIO 或者说GFP_NOIO, 无可奉告.(如果你真的想知
道为什么的话,回去看当初我们是如何调用usb_submit_urb() 的,理由当时就已经讲过了.)这个函数成功
返回值为0,否则返回负的错误码.初始化好了之后就可以为us->flags 设置US_FLIDX_SG_ACTIVE 了,
对这个flag 陌生吗?还是回去看usb_submit_urb(), 当时我们也为urb 设置了这么一个
flag,US_FLDX_URB_ACTIVE, 其实历史总是惊人的相似.当初我们对待urb 的方式和如今对待sg
request 的方式几乎一样.所以其实是很好理解的.

对比一下当初调用usb_submit_urb() 的代码,就会发现464 到471 这一段我们不会陌生,当年咱们提
交urb 之前就有这么一段,usb_stor_msg_common() 函数中,只不过那时候是urb 而不是sg,这两段代
码之间何其的相似!只是年年岁岁花相似,岁岁年年人不同啊!然后474 行,usb_sg_wait() 函数得到调用.
她所需要的参数就是sg request 的地址,咱们传递了us->current_sg 的地址给她.这个函数结
束,US_FLIDX_SG_ACTIVE 这个flag 就可以clear 掉了.返回值被保存在us->current_sg.status 中,
然后把她赋给了result. 而us->current_sg.bytes 保存了实际传输的长度,把她赋给*act_len, 然后返回
之前,once more, 调用interpret_urb_result() 转换一下结果.

最后,usb_stor_bulk_transfer_sg() 函数返回之前还做了一件事,将剩下的长度赋值给了

*residual.*residual 是形参,实参是&srb->resid. 而最终usb_stor_bulk_transfer_sg() 返回的值就是
interpret_urb_result() 翻译过来的值.但是需要明白的一点是,这个函数的返回就意味着Bulk 传输中的
关键阶段,即数据阶段的结束.剩下一个阶段就是状态阶段了,要传递的是CSW,就像当初传递CBW 一样.
回到usb_stor_Bulk_transport() 函数中来,判断结果是否为USB_STOR_XFER_ERROR 或者
USB_STOR_XFER_LONG,前者表示出错,这没啥好说的.而后者表示设备试图发送的数据比咱们需要的
数据要多,这种情况咱们使用一个fake sense data 来向上层汇报,出错了,但是和一般的出错不一样的是,
告诉上层,这个命令别再重发了.fake_sense 刚开始初始化为0,这里设置为1,后面将会用到.到时候再看.
目前只需要知道的是,这种情况并不是不存在,实际上usb mass storage bulk-only spec 里边就定义了
这种情况,spec 说了对这种情况,下一个阶段还是要照样进行.至于设备干嘛要这样做,那就只有天知道了,
就是说你明明只是对他说,”给我十块钱”,他却硬塞给你一百块钱.(我只是打个比方,别做梦了.)文雅一点说,
这叫,原想采撷一枚红叶,你却给了我整个的枫林.

最后, 解释一点,USB_STOR_XFER_LONG 只是我们自己定义的一个宏, 实际上是由
interpret_urb_result() 翻译过来的,真正的从usb core 那一层传递过来的结果是叫做-EOVERFLOW,
这一点在interpret_urb_result 函数中能找到对应关系.-EOVERFLOW 我们就常见了,顾名思义,就是溢
出.

最后的最后,再解释一点,实际上usb core 这一层做的最人性化的一点就是对urb 和对sg 的处理了.写
代码的人喜欢把数据传输具体化为request,urb 和sg 都被化作request, 即请求.而usb core 的能耐就是
让你写设备驱动的人能够只要申请一个请求,调用usb core 提供的函数进行初始化,然后调用usb core 提
供的函数进行提交,这些步骤都是固定的,完全就像使用傻瓜照相机一样,然后进程可以睡眠,或者可以干别
的事情,完事之后usb core 会通知你.然后你就可以接下来干别的事情了.我做一个比方,就好比你考四六级,
找了一个枪手,让他去给你考,你只要告诉他你的基本信息,把你的准考证给他,然后你就不用管别的什么了,
剩下的事情他会去处理,然后你也不用担心完事之后他不会通知你,这简直是不容置疑的,因为你还没给钱呢.
明白了不,小朋友?

论坛徽章:
0
166 [报告]
发表于 2008-06-06 15:06 |只看该作者
迷雾重重的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 的长度,13 个bytes.而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() 函数,最重要的就是310 到314 行,这里判断了,因为我们曾经
讲过,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 对应于CSW 的dCSWDataResidue, 她表示的是实际传输
的数据和期望传输的数据的差值.bcs->Signature 对应于CSW 中的dCSWSignature,bcs->Tag 对应
于CSW 中的dCSWTag, 而bcs->Status 对应于bCSWStatus. 我们有些事情没道理的,有人很抢手,有人
没资格,路是人走的.在bcs 中成员的存储格式居然还有区别,有的是little endian 的,有些却不是.对于那些
little endian 的,咱们需要调用像cpu_to_le32 这样的宏来转换,而其她的却不需要转换,对于bcs 来说,
其成员Residue 和Signature 就需要这样转换.这些规矩仿佛是没有道理的.

论坛徽章:
0
167 [报告]
发表于 2008-06-06 15:07 |只看该作者
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, 而03h 到FFh 都是保留的,不能用,所以这里会判断她是否
是大于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> *
/

论坛徽章:
0
168 [报告]
发表于 2008-06-06 15:07 |只看该作者
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. 而1064 行srb->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 那边

论坛徽章:
0
169 [报告]
发表于 2008-06-06 15:08 |只看该作者
srb->resid 就可以了.反之,对于写操作,即方向为DMA_TO_DEVICE 的操作,我们当然不愿意无缘无故的
抛弃有效的dCSWDataResidue 啦.所以对于DMA_TO_DEVICE 的情况,我们最终返回给scsi 核心层的
srb->resid 是以srb->resid 和residue 中那个大一点的为准.这就是为什么我们这里要判断或者我们设
置了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

论坛徽章:
0
170 [报告]
发表于 2008-06-06 15:08 |只看该作者
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, 本来这是一次成功的传输,但是最后返回值result 却不为0,而是
0x10070000, 关于这个0x10070000 如何出来的,我们稍候会知道.最后两行是scsi core 那边的代码打
印出来的,我们不用管,只是需要知道我们最终返回给scsi 核心层的一个有用信息就是srb->result. 所以我
们看到scsi 那边打印了一个reture code,和我们这里的result 是一样的.其实打印的都是srb->result.
很显然,srb 这个东西相当于usb-storage 和scsi 那边的桥梁,连接了两个模块.

Ok,继续往下走.1068 行开始基于CSW 返回的状态,来判断结果了.判断的值就是bcs->Status.如果是
0,那么表明命令执行成功了.关于bcs->Status 的取值,usb mass storage bulk only spec 里面规定的
很清楚,参考下面这幅图


我们前面看到,我们定义了三个宏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)
*/
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP