《Linux那些事儿之我是USB》我是U盘(36)迷雾重重的批量传输(五)
发布时间:2014-09-05 16:27:17作者:知识屋
在讲数据传输阶段之前,先解决刚才的历史遗留问题。usb_stor_bulk_transfer_buf()中,406行,有一个很有趣的函数interpret_urb_result()被调用。这个函数同样来自drivers/usb/storage/transport.c中:
265 static int interpret_urb_result(struct us_data*us, unsigned int pipe,
266 unsigned int length, int result, unsigned int partial)
267 {
268 US_DEBUGP("Status code %d; transferred%u/%u/n",
269 result, partial,length);
270 switch (result) {
271
272 /* no error code; did we send all the data? */
273 case 0:
274 if (partial != length) {
275 US_DEBUGP("-- shorttransfer/n");
276 return USB_STOR_XFER_SHORT;
277 }
278
279 US_DEBUGP("-- transfer complete/n");
280 return USB_STOR_XFER_GOOD;
281
282 /* stalled */
283 case -EPIPE:
284 /* for control endpoints, (used by CB[I]) astall indicates
285 * afailed command */
286 if (usb_pipecontrol(pipe)) {
287 US_DEBUGP("-- stall oncontrol pipe/n");
288 return USB_STOR_XFER_STALLED;
289 }
290
291 /* for other sorts of endpoint, clear thestall */
292 US_DEBUGP("clearing endpoint halt forpipe 0x%x/n", pipe);
293 if (usb_stor_clear_halt(us, pipe) < 0)
294 return USB_STOR_XFER_ERROR;
295 return USB_STOR_XFER_STALLED;
296
297 /* babble - the device tried to send morethan we wanted to read */
298 case -EOVERFLOW:
299 US_DEBUGP("-- babble/n");
300 return USB_STOR_XFER_LONG;
301
302 /* the transfer was cancelled by abort, disconnect,or timeout */
303 case -ECONNRESET:
304 US_DEBUGP("-- transfercancelled/n");
305 return USB_STOR_XFER_ERROR;
306
307 /* short scatter-gather read transfer */
308 case -EREMOTEIO:
309 US_DEBUGP("-- short readtransfer/n");
310 return USB_STOR_XFER_SHORT;
311
312 /* abort or disconnect in progress */
313 case -EIO:
314 US_DEBUGP("-- abort or disconnect inprogress/n");
315 return USB_STOR_XFER_ERROR;
316
317 /* the catch-all error case */
318 default:
319 US_DEBUGP("-- unknown error/n");
320 return USB_STOR_XFER_ERROR;
321 }
322 }
应该说这个函数的作用是一目了然,就是根据传进来的参数result进行判断,从而采取相应的行动。partial是实际传输的长度,而length是期望传输的长度,传输结束了当然要比较这两者,因为有所期待,才会失望。result是usb_stor_ msg_common()函数的返回值,其实就是状态代码。如果为0说明一切都很顺利,结果也是成功的。268这行,打印结果,同时打印出partial和length的比,注意两个%u中间那个“/”,就是除号,或者说分割分子和分母的符号。
然后通过一个switch语句判断result,为0,说明至少数据有传输。然后有两种情况,于是返回不同的值,USB_STOR_XFER_SHORT和USB_STOR_XFER_GOOD。至于返回这些值之后会得到什么反应,让我们边走边看。目前只需要知道的是,对于真正传输完全令人满意的情况,返回值只能是USB_STOR_XFER_GOOD。返回其他值都说明有问题。而这里作为传递给switch的result,实际上是USB Core那一层传过来的值。
而我们注意到,interpret_urb_result这个函数整个是被作为一个返回值出现在usb_stor_bulk_transfer_buf()中的。换而言之,前者返回之后,后者也马上就返回了,即再次返回到了usb_stor_Bulk_transport()中。因此,我们把视线拉回usb_stor_Bulk_transport(),981行,如果result不为USB_STOR_XFER_GOOD,就说明有一些问题,于是索性usb_stor_Bulk_transport()也返回,没必要再进行下一阶段的传输了。否则,才可以进行下一阶段。
下一个阶段是所谓的Bulk-only传输,总共就是三个阶段,即命令传输阶段、数据传输阶段、状态传输阶段。很显然,真正最有意义的阶段就是数据传输阶段,而在此之前,我们已经讲了第一阶段,即命令传输阶段。下面我们可以来看一下数据阶段。
989行,990行,实在没话可说,某些公司的产品在命令阶段和数据阶段居然还得延时100μs,最早时只发现了Genesys Logic公司的产品有这个问题,后来又发现更多的产品也有同样的问题。所以使用了US_FL_GO_SLOW这个flag,如果你有兴趣看一下早期的Linux Kernel,你会发现那时候其实没有这个flag,那时候定义了一个USB_VENDOR_ID_GENESYS,直接比较这个产品是不是Genesys Logic公司的,如果是的,那就考虑这个延时,否则就不用。
993行,transfer_length可能为0,因为有的命令并不需要您传输数据,所以它没有数据阶段。而对于那些有数据阶段的情况,我们进入if这一段。
994行,没什么可说的,就是根据数据传输方向确定用接收管道还是发送管道。
然后,996行,usb_stor_bulk_transfer_sg()函数真正地执行批量数据传输。这个函数来自drivers/usb/storage/transport.c中:
470 int usb_stor_bulk_transfer_sg(struct us_data*us, unsigned int pipe,
471 void *buf, unsigned int length_left, int use_sg, int *residual)
472 {
473 int result;
474 unsigned int partial;
475
476 /* are we scatter-gathering? */
477 if (use_sg) {
478 /* use the usb core scatter-gather primitives*/
479 result = usb_stor_bulk_transfer_sglist(us,pipe,
480 (structscatterlist *) buf, use_sg,
481 length_left,&partial);
482 length_left -= partial;
483 } else {
484 /* no scatter-gather, just make the request */
485 result = usb_stor_bulk_transfer_buf(us, pipe,buf,
486 length_left,&partial);
487 length_left -= partial;
488 }
489
490 /* store the residual and return the error code*/
491 if (residual)
492 *residual = length_left;
493 return result;
494 }
注释说得很清楚,这个函数是一个壳,真正干活的是它所调用或者说利用的那两个函数:usb_stor_bulk_transfer_sglist()和usb_stor_bulk_transfer_buf()。后者刚才已经遇到过了,而前者是专门为scatter-gather传输准备的函数,它也来自drivers/usb/storage/transport.c中:
416 static int usb_stor_bulk_transfer_sglist(structus_data *us, unsigned int pipe,
417 struct scatterlist *sg, int num_sg, unsigned int length,
418 unsigned int *act_len)
419 {
420 int result;
421
422 /*don't submit s-g requests during abort/disconnect processing */
423 if (us->flags &ABORTING_OR_DISCONNECTING)
424 return USB_STOR_XFER_ERROR;
425
426 /* initialize the scatter-gather request block*/
427 US_DEBUGP("%s: xfer %u Bytes, %dentries/n", __FUNCTION__,
428 length, num_sg);
429 result = usb_sg_init(&us->current_sg,us->pusb_dev, pipe, 0,
430 sg, num_sg, length,GFP_NOIO);
431 if (result) {
432 US_DEBUGP("usb_sg_init returned%d/n", result);
433 return USB_STOR_XFER_ERROR;
434 }
435
436 /* since the block has been initializedsuccessfully, it's now
437 * okayto cancel it */
438 set_bit(US_FLIDX_SG_ACTIVE,&us->flags);
439
440 /* did an abort/disconnect occur during thesubmission? */
441 if (us->flags &ABORTING_OR_DISCONNECTING) {
442
443 /* cancel the request, if it hasn't beencancelled already */
444 if (test_and_clear_bit(US_FLIDX_SG_ACTIVE,&us->flags)) {
445 US_DEBUGP("--cancelling sg request/n");
446 usb_sg_cancel(&us->current_sg);
447 }
448 }
449
450 /* wait for the completion of the transfer */
451 usb_sg_wait(&us->current_sg);
452 clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);
453
454 result = us->current_sg.status;
455 if (act_len)
456 *act_len = us->current_sg.Bytes;
457 return interpret_urb_result(us, pipe, length,result,
458 us->current_sg.Bytes);
459 }
在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()函数被调用。我们来看这个函数 (免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)