`
javatome
  • 浏览: 845218 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

2006年的最后一个星期,来到了北京,开始了北漂的生活.和上海不同的是,在这里待了三个月之后,发现竟然没有下过一次雨,难怪日本小孩说:”你们北京小孩真幸福,城外就是大沙漠,出了城就可以骑骆驼看日落了.”不过,今天下雨了,下了大雨,好大好大,一阵阵的闪电,回家的时候下半身都湿了(天哪,怎么写着写着又往那个方向走去了算了,我承认我只是一个用下半身思考的男青年.)

很累,但是听着北京不眠夜,又不想入睡,听着刘杨的声音,心里感到特别温暖,这些年里,从长沙,到上海,再到北京,每每只有在夜深人静的时候,听着广播,才能忘却一些绝望.于是继续写吧,既然人生的幕布已经拉开,就一定要积极的演出;既然脚步已经跨出,风雨坎坷也不能退步;既然我已把希望播在这里,就一定要坚持到胜利的谢幕.

375,us->proto_handler()其实是一个函数指针,知道它指向什么吗?不要说你不知道,早年我们在storage_probe(),确切的说,get_protocol()就赋了值,当时只知道是get protocol,却不知道究竟干什么用,现在该用上了,别以为写代码的都是傻子,一个指针要是没什么用人家才不会为它赋值呢.当初我们就讲了,对于U,proto_handler被赋值为usb_stor_transparent_scsi_command,所以我们来看后者吧. 后者定义于drivers/usb/storage/protocol.c:

172 void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
173 struct us_data *us)
174 {
175 /* send the command to the transport layer */
176 usb_stor_invoke_transport(srb, us);
177
178 if (srb->result == SAM_STAT_GOOD) {
179 /* Fix the READ CAPACITY result if necessary */
180 if (us->flags & US_FL_FIX_CAPACITY)
181 fix_read_capacity(srb);
182 }
183 }

首先注意到的是usb_stor_invoke_transport()函数这个函数可不简单.咱们先做好思想准备, 接下来就去见识一下她的庐山真面目. 她来自drivers/usb/storage/transport.c:

519 /***********************************************************************
520 * Transport routines
521 ***********************************************************************/
522
523 /* Invoke the transport and basic error-handling/recovery methods
524 *
525 * This is used by the protocol layers to actually send the message to
526 * the device and receive the response.
527 */
528 void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
529 {
530 int need_auto_sense;
531 int result;
532
533 /* send the command to the transport layer */
534 srb->resid = 0;
535 result = us->transport(srb, us);
536
537 /* if the command gets aborted by the higher layers, we need to
538 * short-circuit all other processing
539 */
540 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
541 US_DEBUGP("-- command was aborted/n");
542 goto Handle_Abort;
543 }
544
545 /* if there is a transport error, reset and don't auto-sense */
546 if (result == USB_STOR_TRANSPORT_ERROR) {
547 US_DEBUGP("-- transport indicates error, resetting/n");
548 us->transport_reset(us);
549 srb->result = DID_ERROR << 16;
550 return;
551 }
552
553 /* if the transport provided its own sense data, don't auto-sense */
554 if (result == USB_STOR_TRANSPORT_NO_SENSE) {
555 srb->result = SAM_STAT_CHECK_CONDITION;
556 return;
557 }
558
559 srb->result = SAM_STAT_GOOD;
560
561 /* Determine if we need to auto-sense
562 *
563 * I normally don't use a flag like this, but it's almost impossible
564 * to understand what's going on here if I don't.
565 */
566 need_auto_sense = 0;
567
568 /*
569 * If we're running the CB transport, which is incapable
570 * of determining status on its own, we will auto-sense
571 * unless the operation involved a data-in transfer. Devices
572 * can signal most data-in errors by stalling the bulk-in pipe.
573 */
574 if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
575 srb->sc_data_direction != DMA_FROM_DEVICE) {
576 US_DEBUGP("-- CB transport device requiring auto-sense/n");
577 need_auto_sense = 1;
578 }
579
580 /*
581 * If we have a failure, we're going to do a REQUEST_SENSE
582 * automatically. Note that we differentiate between a command
583 * "failure" and an "error" in the transport mechanism.
584 */
585 if (result == USB_STOR_TRANSPORT_FAILED) {
586 US_DEBUGP("-- transport indicates command failure/n");
587 need_auto_sense = 1;
588 }
589
590 /*
591 * A short transfer on a command where we don't expect it
592 * is unusual, but it doesn't mean we need to auto-sense.
593 */
594 if ((srb->resid > 0) &&
595 !((srb->cmnd[0] == REQUEST_SENSE) ||
596 (srb->cmnd[0] == INQUIRY) ||
597 (srb->cmnd[0] == MODE_SENSE) ||
598 (srb->cmnd[0] == LOG_SENSE) ||
599 (srb->cmnd[0] == MODE_SENSE_10))) {
600 US_DEBUGP("-- unexpectedly short transfer/n");
601 }
602
603 /* Now, if we need to do the auto-sense, let's do it */
604 if (need_auto_sense) {
605 int temp_result;
606 void* old_request_buffer;
607 unsigned short old_sg;
608 unsigned old_request_bufflen;
609 unsigned char old_sc_data_direction;
610 unsigned char old_cmd_len;
611 unsigned char old_cmnd[MAX_COMMAND_SIZE];
612 unsigned long old_serial_number;
613 int old_resid;
614
615 US_DEBUGP("Issuing auto-REQUEST_SENSE/n");
616
617 /* save the old command */
618 memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
619 old_cmd_len = srb->cmd_len;
620
621 /* set the command and the LUN */
622 memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
623 srb->cmnd[0] = REQUEST_SENSE;
624 srb->cmnd[1] = old_cmnd[1] & 0xE0;
625 srb->cmnd[4] = 18;
626
627 /* FIXME: we must do the protocol translation here */
628 if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
629 srb->cmd_len = 6;
630 else
631 srb->cmd_len = 12;
632
633 /* set the transfer direction */
634 old_sc_data_direction = srb->sc_data_direction;
635 srb->sc_data_direction = DMA_FROM_DEVICE;
636
637 /* use the new buffer we have */
638 old_request_buffer = srb->request_buffer;
639 srb->request_buffer = srb->sense_buffer;
640
641 /* set the buffer length for transfer */
642 old_request_bufflen = srb->request_bufflen;
643 srb->request_bufflen = 18;
644
645 /* set up for no scatter-gather use */
646 old_sg = srb->use_sg;
647 srb->use_sg = 0;
648
649 /* change the serial number -- toggle the high bit*/
650 old_serial_number = srb->serial_number;
651 srb->serial_number ^= 0x80000000;
652
653 /* issue the auto-sense command */
654 old_resid = srb->resid;
655 srb->resid = 0;
656 temp_result = us->transport(us->srb, us);
657
658 /* let's clean up right away */
659 srb->resid = old_resid;
660 srb->request_buffer = old_request_buffer;
661 srb->request_bufflen = old_request_bufflen;
662 srb->use_sg = old_sg;
663 srb->serial_number = old_serial_number;
664 srb->sc_data_direction = old_sc_data_direction;
665 srb->cmd_len = old_cmd_len;
666 memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
667
668 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
669 US_DEBUGP("-- auto-sense aborted/n");
670 goto Handle_Abort;
671 }
672 if (temp_result != USB_STOR_TRANSPORT_GOOD) {
673 US_DEBUGP("-- auto-sense failure/n");
674
675 /* we skip the reset if this happens to be a
676 * multi-target device, since failure of an
677 * auto-sense is perfectly valid
678 */
679 if (!(us->flags & US_FL_SCM_MULT_TARG))
680 us->transport_reset(us);
681 srb->result = DID_ERROR << 16;
682 return;
683 }
684
685 US_DEBUGP("-- Result from auto-sense is %d/n", temp_result);
686 US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x/n",
687 srb->sense_buffer[0],
688 srb->sense_buffer[2] & 0xf,
689 srb->sense_buffer[12],
690 srb->sense_buffer[13]);
691 #ifdef CONFIG_USB_STORAGE_DEBUG
692 usb_stor_show_sense(
693 srb->sense_buffer[2] & 0xf,
694 srb->sense_buffer[12],
695 srb->sense_buffer[13]);
696 #endif
697
698 /* set the result so the higher layers expect this data */
699 srb->result = SAM_STAT_CHECK_CONDITION;
700
701 /* If things are really okay, then let's show that. Zero
702 * out the sense buffer so the higher layers won't realize
703 * we did an unsolicited auto-sense. */
704 if (result == USB_STOR_TRANSPORT_GOOD &&
705 /* Filemark 0, ignore EOM, ILI 0, no sense */
706 (srb->sense_buffer[2] & 0xaf) == 0 &&
707 /* No ASC or ASCQ */
708 srb->sense_buffer[12] == 0 &&
709 srb->sense_buffer[13] == 0) {
710 srb->result = SAM_STAT_GOOD;
711 srb->sense_buffer[0] = 0x0;
712 }
713 }
714
715 /* Did we transfer less than the minimum amount required? */
716 if (srb->result == SAM_STAT_GOOD &&
717 srb->request_bufflen - srb->resid < srb->underflow)
718 srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
719
720 return;
721
722 /* abort processing: the bulk-only transport requires a reset
723 * following an abort */
724 Handle_Abort:
725 srb->result = DID_ABORT << 16;
726 if (us->protocol == US_PR_BULK)
727 us->transport_reset(us);
728 }

好家伙,洋洋洒洒两百余行的一个函数,怎一个壮观二字了得! 欧阳修大哥曾经的一首蝶恋花把这个复杂的函数可谓描绘的淋漓尽致.

庭院深深深几许?杨柳堆烟,帘幕无重数.

玉勒雕鞍游冶处,楼高不见章台路.

雨横风狂三月暮,门掩黄昏,无计留春住.

泪眼问花花不语,乱红飞过秋千去.

上片深几许,无重数,不见章台路正是写的这段代码的复杂,调用关系一层又一层,让很多新手看了感觉无可奈何,如果没有高人的指导,盲目的去阅读代码或者去看那些很垃圾的书,那么无异于对美好生命的戕害.下片狂风暴雨正是比喻这种盲目的学习的害处,词中以花被摧残喻读代码者自己青春被毁.韶华空逝,人生易老.何必呢?

分享到:
评论

相关推荐

    Linux那些事儿之我是U盘

    根据给定的信息,“Linux那些事儿之我是U盘”这一标题及描述主要聚焦于USB技术在Linux环境下的工作原理和技术细节。接下来,我们将基于这个主题展开深入探讨,涵盖USB技术的基本概念、USB在Linux系统中的实现机制...

    Linux那些事儿

    Linux那些事儿之我是U盘 Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是...

    Linux那些事儿之我是USB(第2版)

    ### Linux那些事儿之我是USB(第2版)关键知识点概览 #### 一、书籍概述 - **核心主题**:本书主要围绕Linux内核中的USB子系统展开,深入剖析其工作原理和技术细节。 - **目标读者**:面向Linux初学者、驱动开发者...

    Linux那些事儿1-9合集

    读过《linux那些事儿之我是U盘》的人,都知道其风格,我就不多说了。 导读: linux那些事儿之我是U盘 linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制...

    linux那些事儿之我是USB.zip

    本压缩包文件"linux那些事儿之我是USB.zip"包含了深入理解Linux USB驱动及内核相关知识的九个文档,包括Block层、EHCI主机控制器、HUB、PCI、SCSI硬盘、Sysfs、UHCI、USB core以及U盘。这些文档旨在提供一个系统性的...

    LINUX\Linux那些事儿系列

    3. **Linux那些事儿之我是U盘.pdf**: USB闪存驱动器,通常称为U盘,是常见的便携式存储设备。这部分可能讲述Linux如何识别、挂载和管理U盘,包括使用ums(USB Mass Storage)驱动程序,以及如何处理文件系统的读写...

    linux那些事儿之我是U盘

    本文基于一篇幽默且深入的教程《Linux那些事儿之我是U盘》,该文章通过作者的亲身经历和深入浅出的讲解,介绍了Linux操作系统中USB存储设备的工作原理及相关技术细节。以下是对该文中涉及的重要知识点的梳理。 ####...

    Linux那些事儿之全集

    导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了

    Linux那些事儿系列.rar

    》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...

    linux 那些事儿全集

    “Linux那些事儿之我是U盘.pdf”将关注通用串行总线(USB)闪存驱动器。这部分会解释Linux如何识别和处理USB闪存设备,包括文件系统的挂载和数据交换过程。 “Linux那些事儿之我是USB Core.pdf”涉及Linux内核的USB...

    1.Linux那些事儿之我是U盘1

    【Linux那些事儿之我是U盘1】这篇文章是一个关于Linux内核和USB设备驱动程序的系列教程,作者通过个人经历引入,讲述了自己如何接触并学习Linux技术。文章详细讲解了Linux内核中的USB总线、设备驱动和USB存储设备的...

    linux的那些事儿全集

    Linux那些事儿之我是Block层 Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs ...Linux那些事儿之我是U盘

Global site tag (gtag.js) - Google Analytics