下面讲一下usb_stor_control_thread()函数。唤醒它的是来自queuecommand的up(&(us->sema)),us->srb被赋值为srb,而srb是来自SCSI核心层在调用queuecommand时候传递进来的参数。聚焦usb_stor_control_thread()。314行,前面说过,关于dev_mutex这把锁我们必须在看完整个模块之后再来从较高的角度来看。
312行,如果设了US_FLIDX_DISCONNECTING,这个不用多说了,是判断设备有没有被拔出,要是你的U盘插进去了永远不拔出来,那么你可以把这个flag相关的代码都删了,当然事实上是你不可能不拔出来,热插拔本来就是USB设备的一大特性。
324行,host也是一把锁,这把锁我们也到最后再来看。
326行到330行,又是判断另一个flag有没有被设置,US_FLDX_TIMED_OUT这个flag的含义也如其字面意义一样,即超时了。超时的概念在计算机的世界里比比皆是。不过对于这个flag,设置它的函数是command_abort,这个函数也是咱们提供的,由SCSI核心层去调用,由它那边负责计时,到了超时的时间它就调用command_abort。我们稍后会看,先不急。
337行,判断srb的一个成员sc_data_direction,先看DMA_BIDIRECTIONAL这个宏。这个宏定义于include/linux/dma-mapping.h中:
7 /* These definitions mirror those in pci.h, sothey can be used
8 *interchangeably with their PCI_ counterparts */
9 enum dma_data_direction {
10 DMA_BIDIRECTIONAL= 0,
11 DMA_TO_DEVICE= 1,
12 DMA_FROM_DEVICE = 2,
13 DMA_NONE= 3,
14 };
这些代码被用来表示数据阶段数据传输的方向。DMA_TO_DEVICE表示从主存到设备,DMA_FROM_DEVICE表示从设备到主存。有传闻说,DMA_NONE则只被用于调试,一般不能使用否则将有可能导致内核崩溃。不过更准确一点的是,USB Mass Storage协议中边规定了双向传输是非法的,而一个命令传输零数据是合法的,比如TEST_UNIT_READY命令就不用传输数据。
DMA_BIDIRECTIONAL表示两个方向都有可能,换而言之也就是不知道究竟是哪个方向。同理,338行看到srb的sc_data_direction是DMA_BIDIRECTIONAL时,自然就当做出错了。因为不确定方向的话也就没法传输数据了。
345行,US_FL_SCM_MULT_TARG这个flag,表示设备支持多个target,这里的意思很明显,对于那些不支持多个target的设备,其us->srb->device->id必须为0,否则就有问题了。struct us_data结构体中的成员struct scsi_cmnd * srb,struct scsi_cmnd结构体中有一成员struct scsi_device * device,而struct scsi_device顾名思义,描述一个SCSI设备,就像过去的struct usb_device用来描述USB设备一样。struct
scsi_device来自include/scsi/scsi_device.h中:
49struct scsi_device {
50 struct Scsi_Host *host;
51 struct request_queue *request_queue;
52
53 /* the next two are protected by thehost->host_lock */
54 struct list_head siblings;/* list of all devices on this host*/
55 struct list_head same_target_siblings;
56
57 /* this is now protected by therequest_queue->queue_lock */
58 unsigned int device_busy; /* commands actually active on
59 *low-level. protected by queue_lock.*/
60 spinlock_t list_lock;
61 struct list_head cmd_list; /* queue of in useSCSI Command structures*/
62 struct list_head starved_entry;
63 struct scsi_cmnd *current_cmnd; /* currentlyactive command */
64 unsigned short queue_depth; /* How deep of aqueue we want */
65 unsigned short last_queue_full_depth; /* Thesetwo are used by */
66 unsigned short last_queue_full_count; /*scsi_track_queue_full() */
67unsigned long last_queue_full_time;/*don't let QUEUE_FULLs on the same
68jiffie count on our counter, they
69could all be from the same event.*/
70
71 unsigned int id, lun, channel;
72
73 unsigned int manufacturer; /* Manufacturerof device, for using
74*vendor-specific cmd's */
75 unsigned sector_size; /* size in Bytes */
76
77 void *hostdata;/* available to low-level driver */
78 char type;
79 char scsi_level;
80 char inq_periph_qual; /* PQ from INQUIRY data */
81 unsigned char inquiry_len; /* valid Bytesin 'inquiry' */
82 unsigned char * inquiry; /*INQUIRY response data */
83 const char * vendor; /* [back_compat] point into 'inquiry' ... */
84 const char * model; /* ... after scan; point to static string*/
85 const char * rev; /* ..."nullnullnullnull" before scan */
86 unsigned char current_tag; /* current tag*/
87 struct scsi_target *sdev_target;/* used only forsingle_lun*/
88
89 unsigned int sdev_bflags; /* black/white flags as also foundin
90* scsi_devinfo.[hc]. For now used only to
91* pass settings from slave_alloc to scsi
92*core. */
93 unsigned writeable:1;
94 unsigned removable:1;
95 unsigned changed:1; /* Data invalid due to media change */
96 unsigned busy:1; /* Used to prevent races*/
97 unsigned lockable:1; /* Able to prevent media removal */
98 unsigned locked:1; /* Media removal disabled */
99 unsigned borken:1; /* Tell the Seagate driver to be
100* painfully slow on this device */
101 unsigned disconnect:1; /* can disconnect */
102 unsignedsoft_reset:1; /* Uses soft resetoption */
103 unsigned sdtr:1; /*Device supports SDTR messages */
104 unsignedwdtr:1; /* Device supports WDTRmessages */
105 unsigned ppr:1;/* Device supports PPR messages */
106 unsignedtagged_supported:1;/* Supports SCSI-II tagged queuing */
107 unsignedsimple_tags:1; /* simple queue tag messages are enabled*/
108 unsignedordered_tags:1;/* ordered queue tag messages are enabled */
109 unsigned single_lun:1;/* Indicates we should only allow I/O to
110* one of the luns for the device at a
111* time. */
112 unsignedwas_reset:1; /* There was abus reset on the bus for
113* this device */
114 unsigned expecting_cc_ua:1; /* Expecting aCHECK_CONDITION/UNIT_ATTN
115* because we did a bus reset. */
116 unsigneduse_10_for_rw:1; /* first try 10-Byte read / write */
117 unsigneduse_10_for_ ms:1; /* first try 10-Byte mode sense/select*/
118 unsignedskip_ ms_page_8:1; /* do not use MODE SENSE page 0x08*/
119 unsignedskip_ ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
120 unsigneduse_192_Bytes_for_3f:1;/* ask for 192 Bytes from page 0x3f*/
121 unsigned no_start_on_add:1; /* do not issue starton add */
122 unsignedallow_restart:1; /* issue START_UNIT in error handler */
123 unsignedmanage_start_stop:1;/* Let HLD (sd) manage start/stop */
124 unsigned no_uld_attach:1;/*disable connecting toupper level drivers*/
125 unsigned select_no_atn:1;
126 unsignedfix_capacity:1; /*READ_CAPACITY is too high by 1 */
127 unsignedguess_capacity:1;/* READ_CAPACITY might be too high by 1 */
128 unsignedretry_hwerror:1; /* Retry HARDWARE_ERROR */
129
130 unsigned int device_blocked; /* Device returnedQUEUE_FULL. */
131
132 unsigned int max_device_blocked;
133 #define SCSI_DEFAULT_DEVICE_BLOCKED 3
134
135 atomic_t iorequest_cnt;
136 atomic_t iodone_cnt;
137 atomic_tioerr_cnt;
138
139 inttimeout;
140
141 struct devicesdev_gendev;
142 structclass_devicesdev_classdev;
143
144 struct execute_work ew; /* used to getprocess context on put*/
145
146 enumscsi_device_state sdev_state;
147 unsigned longsdev_data[0];
148 } __attribute__((aligned(sizeof(unsignedlong))));
这个结构体将在后面多次被提到。当然,此刻,我们只需要注意到unsigned int id,lun,channel这三个成员,这正是定位一个SCSI设备必要的三个成员,一个SCSI卡所控制的设备被划分为几层,先是若干个channel,然后每个channel上有若干个target,每个target用一个target id来表示,然后一个target可以有若干个lun,而这里判断的是target id。对于不支持多个target的设备,必须为0。对于绝大多数USB Mass Storage设备来说,它们的target
id肯定为0。有些设备厂家就是要标新立异,它就是要让设备支持多个target,于是它就可以设置US_FL_SCM_MULT_TARG这么一个flag,比如我们可以在drivers/usb/storage/unusual_devs.h中看到如下的定义:
416 UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100,
417"Shuttle",
418"eUSCSI Bridge",
419US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
420US_FL_SCM_MULT_TARG ),
然后352行,us->srb->device->lun不应该大于us->max_lun,这两个东西是什么区别?us->max_lun是咱们早期在usb_stor_scan_thread()中调用usb_stor_Bulk_max_lun()函数来向usb mass storage设备获得的最大LUN,比如MAX LUN等于3,那么这个设备支持的就是4个LUN,即0,1,2,3。而us->srb->device->lun则可以是这四个值中的任意一个,看传递进来的命令是要访问谁了。但它显然不可能超过MAX
LUN。
然后就是358行了。看到这么一个flag-US_FL_FIX_INQUIRY,这又是us->flags中众多flag中的一个,我们前面已经介绍过这个flag,一些定义于drivers/usb/storage/unusal_devs.h中的设备有这个flag。事实上,通常大多数设备的厂商名(Vendor Name)和产品名(Product Name)是通过INQUIRY命令来获得的,而这个flag表明,这些设备的厂商名和产品名不需要查询,或者根本就不支持查询,它们的厂商名和产品名直接就定义好了,在unusal_devs.h中就设好了。那么358行这里这个cmnd[0]是什么?struct
scsi_cmnd里边有这么一个成员,
65 #define MAX_COMMAND_SIZE 16
66 unsigned charcmnd[MAX_COMMAND_SIZE];
这个数组16个元素,它包含的就是SCSI命令,要看懂这个条件判断,得先看下边那句fill_inquiry_response()函数调用。
最后“贴”几个设了US_FL_FIX_INQUIRY这个flag的设备,这几个都是Sony的PEG记忆棒,或者叫记忆卡,可以用在PDA里边。drivers/usb/storage/unusual_devs.h中:
635 /* Submitted by Nathan Babb<nathan@lexi.com> */
636 UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999,
637"Sony",
638 "PEGMass Storage",
639US_SC_DEVICE, US_PR_DEVICE, NULL,
640US_FL_FIX_INQUIRY ),
641
642 /* Submitted by Mike Alborn<malborn@deandra.homeip.net> */
643 UNUSUAL_DEV( 0x054c, 0x016a, 0x0000, 0x9999,
644 "Sony",
645"PEG Mass Storage",
646US_SC_DEVICE, US_PR_DEVICE, NULL,
647US_FL_FIX_INQUIRY ),
648
649 /* Submitted by Frank Engel<frankie@cse.unsw.edu.au> */
650 UNUSUAL_DEV( 0x054c, 0x0099, 0x0000, 0x9999,
651"Sony",
652"PEG Mass Storage",
653US_SC_DEVICE, US_PR_DEVICE, NULL,
654US_FL_FIX_INQUIRY ),
655
分享到:
相关推荐
### Linux那些事儿之我是USB(第2版)关键知识点概览 #### 一、书籍概述 - **核心主题**:本书主要围绕Linux内核中的USB子系统展开,深入剖析其工作原理和技术细节。 - **目标读者**:面向Linux初学者、驱动开发者...
本压缩包文件"linux那些事儿之我是USB.zip"包含了深入理解Linux USB驱动及内核相关知识的九个文档,包括Block层、EHCI主机控制器、HUB、PCI、SCSI硬盘、Sysfs、UHCI、USB core以及U盘。这些文档旨在提供一个系统性的...
### Linux那些事儿之我是USB —— USB技术在Linux下的实现与探索 #### 引言 在探讨《Linux那些事儿之我是USB》这篇文章之前,我们先简单回顾一下文章的背景及主要内容。该文由一位自称对Linux并无太多好感的作者...
Linux那些事儿之我是U盘 Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是...
Linux那些事儿之我是U盘-有书签版.pdf
在《Linux那些事儿之我是U盘》这篇诙谐幽默的技术文章中,作者以独特的视角介绍了Linux内核2.6版本中USB驱动的相关知识。通过轻松的叙述方式,让读者在轻松愉快的氛围中理解复杂的USB驱动原理及其在Linux系统中的...
读过《linux那些事儿之我是U盘》的人,都知道其风格,我就不多说了。 导读: linux那些事儿之我是U盘 linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制...
根据给定的信息,“Linux那些事儿之我是U盘”这一标题及描述主要聚焦于USB技术在Linux环境下的工作原理和技术细节。接下来,我们将基于这个主题展开深入探讨,涵盖USB技术的基本概念、USB在Linux系统中的实现机制...
3. **Linux那些事儿之我是U盘.pdf**: USB闪存驱动器,通常称为U盘,是常见的便携式存储设备。这部分可能讲述Linux如何识别、挂载和管理U盘,包括使用ums(USB Mass Storage)驱动程序,以及如何处理文件系统的读写...
导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了
》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...
“Linux那些事儿之我是U盘.pdf”将关注通用串行总线(USB)闪存驱动器。这部分会解释Linux如何识别和处理USB闪存设备,包括文件系统的挂载和数据交换过程。 “Linux那些事儿之我是USB Core.pdf”涉及Linux内核的USB...
Linux那些事儿之我是Block层 Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs ...Linux那些事儿之我是U盘
"Linux那些事儿之我是XXX全集"这个资源集合,旨在深入剖析Linux内核中的关键组件,特别是与USB(通用串行总线)相关的部分,包括USB core、U盘、UHCI、PCI、SCSI硬盘、Block层和Hub等核心概念。这些文件将通过源代码...
### Linux与USB存储设备——《Linux那些事儿之我是U盘》知识点提炼 #### 引言 本文基于一篇幽默且深入的教程《Linux那些事儿之我是U盘》,该文章通过作者的亲身经历和深入浅出的讲解,介绍了Linux操作系统中USB存储...