免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
91 [报告]
发表于 2008-06-06 14:23 |只看该作者
呢?先不说可不可以这样,事实情况是,没有这样,所有的冬冬都一股脑儿堆在drivers/scsi/ 目录下面,有朝
一日你要是混入了开发队伍中,你不妨提议把这个目录整理一下,别像现在这样,至少看上去整齐一点,乱七
八糟不象话.不过也许开发者们有他们自己的理由吧,他们也许没有时间,那么你可以告诉他们雷锋同志是如
何说的.开发者们把scsi 设备分成了四类,于是他们写了四个模块来为这些设备做驱动程序.这四个模块是
sd_mod.ko,sr_mod.ko,st.ko,sg.ko.如果你正在Linux 下使用U 盘,那么用lsmod 查看一下当前安装
的模块,你一定会看到一个叫做sd_mod 的模块,一定会看到一个叫做scsi_mod 的模块,scsi_mod.ko 正
是scsi 的核心模块,即所谓的scsi core. 那么scsi host 呢?host 同样也有一个模块,这就得看你具体用的
是什么host 了,行话管这个叫HBA,即host bus adapter. 而相应的驱动程序就叫Host Bus Adapter
driver 了.正如在usb 系统中,所有的总线上的活动都是以host 为主的,而scsi 也是如此,所有的设备也都
是围着host 转.即使地球不自转了,设备仍然要围着host 转.不过你会很奇怪,即使你的机器里没有一个叫
做HBA 的冬冬,可是你的U 盘还是能用啊,这是怎么回事?没错,怪事年年有,今年特别多,Linux 内核代码虽
然繁华美丽,对我们来说,却常是朦胧不真实.设计者们是如何处理usb-storage 和scsi 的接口的呢?他们用
代码虚拟了一个scsi host. 所以,如果你用cat /proc/scsi/scsi 命令,就可以看看scsi 设备中U 盘是怎么
被描述的.

下面是没有插U 盘的一个例子:

localhost:~ # cat /proc/scsi/scsi
Attached devices:
Host: scsi0 Channel: 00 Id: 08 Lun: 00
Vendor: DP Model: BACKPLANE Rev: 1.00
Type: Enclosure ANSI SCSI revision: 05
Host: scsi0 Channel: 02 Id: 00 Lun: 00
Vendor: DELL Model: PERC 5/i Rev: 1.00
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi1 Channel: 00 Id: 00 Lun: 00

Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Enclosure ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 00
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 01
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 02
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 03
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 04
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 05
Vendor: SUN Model: StorEdge 3510 Rev: 415F

论坛徽章:
0
92 [报告]
发表于 2008-06-06 14:24 |只看该作者
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 06
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 07
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

而下面第二条是机器里有U 盘的情况:

localhost:~ # cat /proc/scsi/scsi
Attached devices:
Host: scsi0 Channel: 00 Id: 08 Lun: 00

Vendor: DP Model: BACKPLANE Rev: 1.00
Type: Enclosure ANSI SCSI revision: 05

Host: scsi0 Channel: 02 Id: 00 Lun: 00
Vendor: DELL Model: PERC 5/i Rev: 1.00
Type: Direct-Access ANSI SCSI revision: 05

Host: scsi1 Channel: 00 Id: 00 Lun: 00
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Enclosure ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 00
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 01
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 02
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 03
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 04
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 05
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 06
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

Host: scsi1 Channel: 00 Id: 01 Lun: 07
Vendor: SUN Model: StorEdge 3510 Rev: 415F
Type: Direct-Access ANSI SCSI revision: 03

论坛徽章:
0
93 [报告]
发表于 2008-06-06 14:24 |只看该作者
Host: scsi3 Channel: 00 Id: 00 Lun: 00

Vendor: Leidisk Model: USB Flash Drive Rev:

Type: Direct-Access ANSI SCSI revision: 02

看出区别了吗?没错,最下面多了一项,这是一个Leidisk 生产的U 盘.这里本没有一个真实的host,但是写
代码的高手们却让你觉得也许似乎大概有,甚至连scsi core 都被欺骗了一样.那么这些高手们是如何实现
的呢?让我们来慢慢的看,让我们来看看这个神奇的host 究竟是如何出现的,看看它是否像如今的房价一样,
是否像林志玲的胸一样,看着坚挺,实际里面全是泡沫...

谁是最变态的结构体

scsi 子系统里的设备使用scsi 命令来通信,scsi spec 定义了一大堆的命令,spec 里称这个为命令集,即
所谓的command set.其中一些命令是每一个scsi 设备都必须支持的,另一些命令则是可选的.而作为U
盘,它所支持的是scsi transparent command set, 所以它基本上就是支持所有的scsi 命令了,不过我们
其实并不关心任何一个具体的命令,只需要了解一些最基本的命令就是了.比如我们需要知道,所有的scsi
设备都至少需要支持以下这四个scsi 命令:INQUIRY,REQUEST SENSE,SEND DIAGNOSTIC,TEST
UNIT READY.一会我们在代码中会遇见其中的几个,暂且不表.另外对于磁盘设备,它还需要支持另外一些
命令,比如读方面的READ 命令,写方面的WRITE 命令,又比如我们经常做的格式化操作,它就对应
FORMAT UNIT 命令.对于磁盘这样的设备,SCSI 协议里边称它为direct-access devices. 这就是为什么
你刚才在cat /proc/scsi/scsi 的输出中能看到一个”Typeirect-Access” 这么一项.

知道了scsi 总线上使用scsi 命令来通信,那么我们下一步需要知道scsi host 的作用,它主要就是负责发
送命令给设备,然后设备就去执行命令.所以scsi host 也被称为initiator( 发起者),而scsi 设备被称为
target(目的地).

那么我们就知道,如果我们没有scsi host, 但是我们有遵守scsi 协议接受scsi 命令的device, 那怎么办?
谁来发起命令?没有硬件我们用软件,命令是谁传递过来的?应用层?或者scsi core? 不管是谁,只要我们能
够把上层的命令传递给设备,那就Ok 了对不对?scsi 核心层把一切都做好了,我们只要为一个scsi host 申
请相应的数据结构,让命令来了能够发送给设备,能够让设备接收到命令,那就万事大吉了对不对?或者说整
个usb-storage 的真正的功能也就实现了对不对?到这里我们就可以开始继续来看我们的代码了.别忘了
我们还在usb_stor_acquire_resources() 函数中,只不过刚刚讲完usb_stor_Bulk_max_lun() 函数而
已.

781 行,us->unusual_dev->initFunction 是什么?不要说你一点印象也没有.在分析
unusual_devs.h 文件的时候曾经专门举过例子的,说有些设备需要一些初始化函数,它就定义在
unusual_devs.h 文件中,而我们通过UNUSUAL_DEV 的定义已经把这些初始化函数给赋给了
us->unusual_dev 的initFunction 指针了.所以这时候,在传输开始之前,我们判断,是不是有这样一个函
数,即这个函数指针是否为空,如果不为空,很好办,执行这个函数就是了.比如当时我们举例子的时候说的那
两个惠普的CD 刻录机就有个初始化函数init_8200e, 那么就让它执行好了.当然,一般的设备肯定不需要
这么一个函数.至于传递给这个函数的参数,在struct us_unusual_dev 结构体定义的时候,就把这个函数
需要什么样的参数定义好了,需要的就是一个struct us_data *, 那么很自然,传递的就是us.

然后790 行,scsi_host_alloc 就是scsi 子系统提供的函数,它的作用就是申请一个scsi host 相应的数
据结构.不过我们要注意的是它的参数,尤其是第一个参数, &usb_stor_host_template, 其实这是一个

论坛徽章:
0
94 [报告]
发表于 2008-06-06 14:25 |只看该作者
struct scsi_host_template 的结构体指针,从这一刻开始,我们需要开始了解
drivers/usb/storage/scsiglue.c 这个文件了,glue 就是胶水的意思,与scsi 相关联的代码我们就都准备
在这个文件里了.

usb_stor_host_template 的定义就在drivers/usb/storage/scsiglue.c 中,

416 /
*
417 * this defines our host template, with which we'll allocate hosts
418 *
/
419
420 struct scsi_host_template usb_stor_host_template =
{
421 /* basic userland interface stuff *
/
422 .name = "usb-storage"
,
423 .proc_name = "usb-storage"
,
424 .proc_info = proc_info,
425 .info = host_info,
426
427 /* command interface -- queued only *
/
428 .queuecommand = queuecommand,
429
430 /* error and abort handlers *
/
431 .eh_abort_handler = command_abort,
432 .eh_device_reset_handler = device_reset,
433 .eh_bus_reset_handler = bus_reset,
434
435 /* queue commands only, only one command per LUN *
/
436 .can_queue = 1,
437 .cmd_per_lun = 1,
438
439 /* unknown initiator id *
/
440 .this_id = -1,
441
442 .slave_alloc = slave_alloc,
443 .slave_configure = slave_configure,
444
445 /* lots of sg segments can be handled *
/
446 .sg_tablesize = SG_ALL,
447
448


/* limit the total size of a transfer to 120 KB *
/
449 .max_sectors = 240,
450
451


/* merge commands... this seems to help performance, but
452


* periodically someone should test to see which setting is more
453 * optimal.
454 *
/

论坛徽章:
0
95 [报告]
发表于 2008-06-06 14:25 |只看该作者
455 .use_clustering = 1,
456
456
457


/* emulated HBA *
/
458 .emulated = 1,
459
460


/* we do our own delay after a device or bus reset *
/
461 .skip_settle_delay = 1,
462
463 /* sysfs device attributes *
/
464 .sdev_attrs = sysfs_device_attr_list,
465
466 /* module management *
/
467 .module = THIS_MODULE
468 }
;


如果您觉得眼前这个结构体变量的定义或者说初始化很复杂,那么您错了.因为下面您将看到一个更变态
的数据结构的定义,她就是传说中的struct scsi_host_template, 她是scsi 子系统定义的结构体,来自
include/scsi/scsi_host.h 文件:

40 struct scsi_host_template
{
41 struct module *module;
42 const char *name;
43
44 /
*
45 * Used to initialize old-style drivers. For new-style drivers
46 * just perform all work in your module initialization function.
47
*
48 * Status: OBSOLETE
49 *
/
50 int (* detect)(struct scsi_host_template *)
;
51
52 /
*
53 * Used as unload callback for hosts with old-style drivers.
54
*
55 * Status: OBSOLETE
56 *
/
57


int (* release)(struct Scsi_Host *)
;
58
59 /
*
60


* The info function will return whatever useful information the
61
* developer sees fit. If not provided, then the name field will
62
* be used instead.
63
*
64
* Status: OPTIONAL

论坛徽章:
0
96 [报告]
发表于 2008-06-06 14:26 |只看该作者
65 *
/
66 const char *(* info)(struct Scsi_Host *)
;
67
68 /
*
69 * Ioctl interface
70
*
71 * Status: OPTIONAL
72 *
/
73 int (* ioctl)(struct scsi_device *dev, int cmd, void __user *arg)
;
74
75 /
*
76 * The queuecommand function is used to queue up a scsi
77 * command block to the LLDD. When the driver finished
78 * processing the command the done callback is invoked.
79
*
80 * If queuecommand returns 0, then the HBA has accepted the
81 * command. The done() function must be called on the command
82 * when the driver has finished with it. (you may call done on the
83 * command before queuecommand returns, but in this case you
84 * *must* return 0 from queuecommand)
.
85
*
86 * Queuecommand may also reject the command, in which case it may
87 * not touch the command and must not call done() for it.
88
*
89 * There are two possible rejection returns:
90
*
91 * SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but
92 * allow commands to other devices serviced by this host.
93
*
94 * SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this
95 * host temporarily.
96
*
97 * For compatibility, any other non-zero return is treated the
98 * same as SCSI_MLQUEUE_HOST_BUSY.
99
*


100 * NOTE: "temporarily" means either until the next command for#
101 * this device/host completes, or a period of time determined by
102 * I/O pressure in the system if there are no other outstanding
103 * commands.
104
*
105 * STATUS: REQUIRED
106 *
/
107 int (* queuecommand)(struct scsi_cmnd *
,
108 void (*done)(struct scsi_cmnd *))
;

论坛徽章:
0
97 [报告]
发表于 2008-06-06 14:26 |只看该作者
109
110 /*
111 * This is an error handling strategy routine. You don't need to
112 * define one of these if you don't want to - there is a default
113 * routine that is present that should work in most cases. For those
114 * driver authors that have the inclination and ability to write their
115 * own strategy routine, this is where it is specified. Note - the
116 * strategy routine is *ALWAYS* run in the context of the kernel eh
117 * thread. Thus you are guaranteed to *NOT* be in an interrupt
118 * handler when you execute this, and you are also guaranteed to
119 * *NOT* have any other commands being queued while you are in the
120 * strategy routine. When you return from this function, operations
121 * return to normal.
122 *
123 * See scsi_error.c scsi_unjam_host for additional comments about
124 * what this function should and should not be attempting to do.
125 *
126 * Status: REQUIRED (at least one of them)
127 */
128 int (* eh_strategy_handler)(struct Scsi_Host *);
129 int (* eh_abort_handler)(struct scsi_cmnd *);
130 int (* eh_device_reset_handler)(struct scsi_cmnd *);
131 int (* eh_bus_reset_handler)(struct scsi_cmnd *);
132 int (* eh_host_reset_handler)(struct scsi_cmnd *);
133
134 /*
135 * This is an optional routine to notify the host that the scsi
136 * timer just fired. The returns tell the timer routine what to

137 * do about this:
138 *
139 * EH_HANDLED:
140 * EH_RESET_TIMER:
141 *
142 * EH_NOT_HANDLED
143 *
144 * Status: OPTIONAL
145 */

I fixed the error, please complete the command
I need more time, reset the timer and
begin counting again
Begin normal error recovery

146 enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);

148 /*
149 * Before the mid layer attempts to scan for a new device where none
150 * currently exists, it will call this entry in your driver. Should
151 * your driver need to allocate any structs or perform any other init
152 * items in order to send commands to a currently unused target/lun

论坛徽章:
0
98 [报告]
发表于 2008-06-06 14:27 |只看该作者
153 * combo, then this is where you can perform those allocations. This
154 * is specifically so that drivers won't have to perform any kind of
155 * "is this a new device" checks in their queuecommand routine,
156 * thereby making the hot path a bit quicker.
157
*
158 * Return values: 0 on success, non-0 on failure
159
*
160 * Deallocation: If we didn't find any devices at this ID, you will
161 * get an immediate call to slave_destroy(). If we find something
162 * here then you will get a call to slave_configure(), then the
163 * device will be used for however long it is kept around, then when
164 * the device is removed from the system (or * possibly at reboot
165 * time), you will then get a call to slave_destroy(). This is
166 * assuming you implement slave_configure and slave_destroy.
167 * However, if you allocate memory and hang it off the device struct,
168 * then you must implement the slave_destroy() routine at a minimum
169 * in order to avoid leaking memory
170 * each time a device is tore down.
171
*
172 * Status: OPTIONAL
173 *
/
174 int (* slave_alloc)(struct scsi_device *)
;


176 /
*
177 * Once the device has responded to an INQUIRY and we know the
178 * device is online, we call into the low level driver with the
179 * struct scsi_device *. If the low level device driver implements
180 * this function, it *must* perform the task of setting the queue
181 * depth on the device. All other tasks are optional and depend
182 * on what the driver supports and various implementation details.
183
*
184 * Things currently recommended to be handled at this time include:
185
*
186 * 1. Setting the device queue depth. Proper setting of this is
187 * described in the comments for scsi_adjust_queue_depth.
188 * 2. Determining if the device supports the various synchronous
189 * negotiation protocols. The device struct will already have
190 * responded to INQUIRY and the results of the standard items
191 * will have been shoved into the various device flag bits, eg.
192 * device->sdtr will be true if the device supports SDTR messages.
193 * 3. Allocating command structs that the device will need.
194 * 4. Setting the default timeout on this device (if needed)
.
195 * 5. Anything else the low level driver might want to do on a device
196 * specific setup basis..
.

论坛徽章:
0
99 [报告]
发表于 2008-06-06 14:27 |只看该作者
197 * 6. Return 0 on success, non-0 on error. The device will be marked
198 * as offline on error so that no access will occur. If you return
199 * non-0, your slave_destroy routine will never get called for this
200 * device, so don't leave any loose memory hanging around, clean
201 * up after yourself before returning non-
0
202
*
203 * Status: OPTIONAL
204 *
/
205 int (* slave_configure)(struct scsi_device *)
;
206
207 /
*
208 * Immediately prior to deallocating the device and after all activity
209 * has ceased the mid layer calls this point so that the low level
210 * driver may completely detach itself from the scsi device and vice
211 * versa. The low level driver is responsible for freeing any memory
212 * it allocated in the slave_alloc or slave_configure calls.
213
*
214 * Status: OPTIONAL
215 *
/
216 void (* slave_destroy)(struct scsi_device *)
;
217
218 /
*
219 * This function determines the bios parameters for a given
220 * harddisk. These tend to be numbers that are made up by
221 * the host adapter. Parameters:
222 * size, device, list (heads, sectors, cylinders)
223
*
224 * Status: OPTIONAL
225 *
/
226 int (* bios_param)(struct scsi_device *, struct block_device *
,
227 sector_t, int [])
;
228
229 /
*
230 * Can be used to export driver statistics and other infos to the
231 * world outside the kernel ie. userspace and it also provides an
232 * interface to feed the driver with information.
233
*
234 * Status: OBSOLETE
235 *
/
236 int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int)
;
237
238 /
*
239 * Name of proc directory
240 *
/

论坛徽章:
0
100 [报告]
发表于 2008-06-06 14:28 |只看该作者
241 char *proc_name;
242
243 /
*
244 * Used to store the procfs directory if a driver implements the
245 * proc_info method.
246 *
/
247 struct proc_dir_entry *proc_dir;
248
249 /
*
250 * This determines if we will use a non-interrupt driven
251 * or an interrupt driven scheme, It is set to the maximum number
252 * of simultaneous commands a given host adapter will accept.
253 *
/
254 int can_queue;
255
256 /
*
257 * In many instances, especially where disconnect / reconnect are
258 * supported, our host also has an ID on the SCSI bus. If this is
259 * the case, then it must be reserved. Please set this_id to -1 if
260 * your setup is in single initiator mode, and the host lacks an
261 * ID.
262 *
/
263 int this_id;
264
265 /
*
266 * This determines the degree to which the host adapter is capable
267 * of scatter-gather.
268 *
/
269 unsigned short sg_tablesize;
270
271 /
*
272 * If the host adapter has limitations beside segment count
273 *
/
274 unsigned short max_sectors;
275
276 /
*
277 * dma scatter gather segment boundary limit. a segment crossing this
278 * boundary will be split in two.
279 *
/
280 unsigned long dma_boundary;
281
282 /
*
283 * This specifies "machine infinity" for host templates which don't
284 * limit the transfer size. Note this limit represents an absolute
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP