You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
storage 协议,还需遵守transparent scsi 规范.从驱动程序的角度来看,它和一般的scsi 磁盘差不多.正<br />
是<br />
因为如此,所以U 盘的工作真正需要的是四个模块,usbcore,scsi_mod,sd_mod,以及咱们这里的<br />
usb-storage,其中sd_mod 恰恰就是scsi disk 的驱动程序.没有它,你的scsi 硬盘就别想在Linux 下面<br />
转起来.看看它的代码,你就可以去电脑报投稿,发一篇”玩转Linux 下的scsi 硬盘”这样的文章.<br />
那么我们从哪里开始去接触这些scsi 命令呢?别忘了我们现在的主题,内核守护进程,别忘了我们曾经有<br />
一段代码只讲到一半就没讲了.没错,那就是usb_stor_control_thread(),当初我们用kernel_thread 创<br />
建它的时候就说了,从此以后一个进程变成两个进程,而我们刚才沿着storage_probe 讲完的是父进程,父<br />
进程最终返回了,而子进程则没有那么简单,我们已经说过,usb_stor_control_thread()中的死循环注定<br />
了这个子进程是一个永恒的进程,只要这个模块还没有被卸载,或者说还没有被要求卸载,这个子进程就必将<br />
永垂不朽的战斗下去.于是让我们推开记忆的门,回过来看这个函数,当初我们讲到了303 行,由于<br />
us->sema 一开始就是锁着的,所以down_interruptible 这里一开始就进入睡眠了,只有在接到唤醒的<br />
信<br />
号或者锁被释放了释放锁的进程来唤醒它它才会醒过来.那么谁来释放这把锁呢?<br />
有两个地方,一个是这个模块要卸载了,这个我们稍后来看.另一个就是有scsi 命令发过来了.scsi 命令从<br />
哪里发过来?很简单,scsi 核心层,硬件上来说,scsi 命令就是scsi 主机到scsi 设备,而从代码的角度来<br />
说,scsi 核心层要求为每一个scsi host 实现一个queuecommand 命令,每一次应用层发送来了scsi 命<br />
令<br />
了,比如你去读写/dev/sda,最终scsi 核心层就会调用与该host 相对应queuecommand,(确切地说是<br />
struct <strong>Scsi</strong>_Host 结构体中的成员struct scsi_host_template 中的成员指针queuecommand,这是<br />
一<br />
个函数指针.)那么我们来看,当初我们定义的struct scsi_host_template usb_stor_host_template,<br />
其中的确有一个queuecommand,我们赋给它的值也是queuecommand,即我们让queuecommand<br />
指向一个叫做queuecommand 的函数,在struct scsi_host_template 的定义中,函数指针的原型为:<br />
107 int (* queuecommand)(struct scsi_cmnd *,<br />
108 void (*done)(struct scsi_cmnd *));<br />
而我们所定义的queuecommand()函数又在哪里呢?在drivers/usb/storage/scsiglue.c 中:<br />
165 /* queue a command */<br />
166 /* This is always called with scsi_lock(srb->host) held */<br />
167 static int queuecommand(struct scsi_cmnd *srb,<br />
168 void (*done)(struct scsi_cmnd *))<br />
169 {<br />
170 struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];<br />
171<br />
172 US_DEBUGP("%s called\n", __FUNCTION__);<br />
173 srb->host_scribble = (unsigned char *)us;<br />
174<br />
175 /* check for state-transition errors */<br />
176 if (us->srb != NULL) {<br />
177 printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",<br />
178 __FUNCTION__, us->srb);<br />
179 return SCSI_MLQUEUE_HOST_BUSY;<br />
119<br />
180 }