static int usb_stor_control_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
for (;;) {
usb_stor_dbg(us, "*** thread sleeping\n");
if (wait_for_completion_interruptible(&us->cmnd_ready))
break;
usb_stor_dbg(us, "*** thread awakened\n");
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
/* lock access to the state */
scsi_lock(host);
/* When we are called with no command pending, we're done */
if (us->srb == NULL) {
scsi_unlock(host);
mutex_unlock(&us->dev_mutex);
usb_stor_dbg(us, "-- exiting\n");
break;
}
/* has the command timed out *already* ? */
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { //判断flag,US_FLDX_TIMED_OUT这个flag的含义超时了。
us->srb->result = DID_ABORT << 16;
goto SkipForAbort;
}
scsi_unlock(host);
/* reject the command if the direction indicator
* is UNKNOWN
*/
if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { //这个宏表示数据阶段数据传输是双向,srb的sc_data_direction是DMA_BIDIRECTIONAL时,自然就当做出错了。因为不确定方向的话也就没法传输数据了。
usb_stor_dbg(us, "UNKNOWN data direction\n");
us->srb->result = DID_ERROR << 16;
}
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
else if (us->srb->device->id &&
!(us->fflags & US_FL_SCM_MULT_TARG)) {
usb_stor_dbg(us, "Bad target number (%d:%d)\n",
us->srb->device->id, us->srb->device->lun);
us->srb->result = DID_BAD_TARGET << 16;
}
//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,描述一个SCSI设备,就像过去的struct usb_device用来描述USB设备一样。
else if (us->srb->device->lun > us->max_lun) {
usb_stor_dbg(us, "Bad LUN (%d:%d)\n",
us->srb->device->id, us->srb->device->lun);
us->srb->result = DID_BAD_TARGET << 16;
}
//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。
/* Handle those devices which need us to fake
* their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) &&
(us->fflags & US_FL_FIX_INQUIRY)) {
unsigned char data_ptr[36] = {
0x00, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
usb_stor_dbg(us, "Faking INQUIRY command\n");
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = SAM_STAT_GOOD;
}
//flag-US_FL_FIX_INQUIRY,这又是us->flags中众多flag中的一个,一些定义于drivers/usb/storage/unusal_devs.h中的设备有这个flag。事实上,通常大多数设备的厂商名(Vendor Name)和产品名(Product Name)是通过INQUIRY命令来获得的,而这个flag表明,这些设备的厂商名和产品名不需要查询,或者根本就不支持查询,它们的厂商名和产品名直接就定义好了,在unusal_devs.h中就设好了。
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us, us->srb));
us->proto_handler(us->srb, us);
usb_mark_last_busy(us->pusb_dev);
}
/* lock access to the state */
scsi_lock(host);
/* indicate that the command is done */
if (us->srb->result != DID_ABORT << 16) {
usb_stor_dbg(us, "scsi cmd done, result=0x%x\n",
us->srb->result);
us->srb->scsi_done(us->srb);
} else {
SkipForAbort:
usb_stor_dbg(us, "scsi command aborted\n");
}
/* If an abort request was received we need to signal that
* the abort has finished. The proper test for this is
* the TIMED_OUT flag, not srb->result == DID_ABORT, because
* the timeout might have occurred after the command had
* already completed with a different result code. */
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
complete(&(us->notify));
/* Allow USB transfers to resume */
clear_bit(US_FLIDX_ABORTING, &us->dflags);
clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
}
/* finished working on this command */
us->srb = NULL;
scsi_unlock(host);
/* unlock the device pointers */
mutex_unlock(&us->dev_mutex);
} /* for (;;) */
/* Wait until we are told to stop */
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
break;
schedule();
}
__set_current_state(TASK_RUNNING);
return 0;
}
}
enum dma_data_direction {
DMA_BIDIRECTIONAL = 0, //DMA_BIDIRECTIONAL表示两个方向都有可能,不知道究竟是哪个方向
DMA_TO_DEVICE = 1,
DMA_FROM_DEVICE = 2,
DMA_NONE = 3,
};
这些代码被用来表示数据阶段数据传输的方向。DMA_TO_DEVICE表示从主存到设备,DMA_FROM_DEVICE表示从设备到主存。DMA_NONE则只被用于调试,一般不能使用否则将有可能导致内核崩溃。USB Mass Storage协议中边规定了双向传输是非法的,而一个命令传输零数据是合法的,比如TEST_UNIT_READY命令就不用传输数据。
struct scsi_device {
unsigned int id, lun, channel;
}
//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.