发布时间:2014-09-05 16:43:16作者:知识屋
下面讲一下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() */
67 unsigned long last_queue_full_time;/*don't let QUEUE_FULLs on the same
68 jiffie count on our counter, they
69 could 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 device sdev_gendev;
142 structclass_device sdev_classdev;
143
144 struct execute_work ew; /* used to getprocess context on put*/
145
146 enumscsi_device_state sdev_state;
147 unsigned long sdev_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",
419 US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
420 US_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",
639 US_SC_DEVICE, US_PR_DEVICE, NULL,
640 US_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",
646 US_SC_DEVICE, US_PR_DEVICE, NULL,
647 US_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",
653 US_SC_DEVICE, US_PR_DEVICE, NULL,
654 US_FL_FIX_INQUIRY ),
655
linux一键安装web环境全攻略 在linux系统中怎么一键安装web环境方法
Linux网络基本网络配置方法介绍 如何配置Linux系统的网络方法
Linux下DNS服务器搭建详解 Linux下搭建DNS服务器和配置文件
对Linux进行详细的性能监控的方法 Linux 系统性能监控命令详解
linux系统root密码忘了怎么办 linux忘记root密码后找回密码的方法
Linux基本命令有哪些 Linux系统常用操作命令有哪些
Linux必学的网络操作命令 linux网络操作相关命令汇总
linux系统从入侵到提权的详细过程 linux入侵提权服务器方法技巧
linux系统怎么用命令切换用户登录 Linux切换用户的命令是什么
在linux中添加普通新用户登录 如何在Linux中添加一个新的用户
2012-07-10
CentOS 6.3安装(详细图解教程)
Linux怎么查看网卡驱动?Linux下查看网卡的驱动程序
centos修改主机名命令
Ubuntu或UbuntuKyKin14.04Unity桌面风格与Gnome桌面风格的切换
FEDORA 17中设置TIGERVNC远程访问
StartOS 5.0相关介绍,新型的Linux系统!
解决vSphere Client登录linux版vCenter失败
LINUX最新提权 Exploits Linux Kernel <= 2.6.37
nginx在网站中的7层转发功能