static int queuecommand_lck(structscsi_cmnd *srb,
void(*done)(struct scsi_cmnd *))
{
structus_data *us = host_to_us(srb->device->host);
/*check for state-transition errors */
if(us->srb != NULL) {
printk(KERN_ERRUSB_STORAGE "Error in %s: us->srb = %p\n",
__func__,us->srb);
returnSCSI_MLQUEUE_HOST_BUSY;
}
/*fail the command if we are disconnecting */
if(test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
usb_stor_dbg(us,"Fail command during disconnect\n");
srb->result= DID_NO_CONNECT << 16;
done(srb);
return0;
}
/*enqueue the command and wake up the control thread */
srb->scsi_done= done;
us->srb= srb;
complete(&us->cmnd_ready);
return0;
}
SCSI 有一个单独的thread来处理所收到的SCSIcommand, 这一个thread 处于sleep状态, 只到有收到新的command或者移除SCSI module才会被wakeup.
有新的command进来时, queuecommand_lck() function调用complete()function来trigger 该thread.
/* Second part of general USB mass-storageprobing */
int usb_stor_probe2(struct us_data *us)
{
……
/*Acquire all the other resources and add the host */
result= usb_stor_acquire_resources(us);
……
}
/* Initialize all the dynamic resources weneed */
static int usb_stor_acquire_resources(structus_data *us)
{
intp;
structtask_struct *th;
us->current_urb= usb_alloc_urb(0, GFP_KERNEL);
if(!us->current_urb) {
usb_stor_dbg(us,"URB allocation failed\n");
return-ENOMEM;
}
/*Just before we start our control thread, initialize
* the device if it needs initialization */
if(us->unusual_dev->initFunction) {
p= us->unusual_dev->initFunction(us);
if(p)
returnp;
}
/*Start up our control thread */
th= kthread_run(usb_stor_control_thread, us,"usb-storage");
if(IS_ERR(th)) {
dev_warn(&us->pusb_intf->dev,
"Unableto start control thread\n");
returnPTR_ERR(th);
}
us->ctl_thread= th;
return0;
}
static int usb_stor_control_thread(void *__us)
{
structus_data *us = (struct us_data *)__us;
structScsi_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));
……
}
……
/*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);
}
……
}
void usb_stor_transparent_scsi_command(structscsi_cmnd *srb,
struct us_data *us)
{
/*send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
}
/* Invoke the transport and basicerror-handling/recovery methods
*
*This is used by the protocol layers to actually send the message to
*the device and receive the response.
*/
void usb_stor_invoke_transport(structscsi_cmnd *srb, struct us_data *us)
{
intneed_auto_sense;
intresult;
/*send the command to the transport layer */
scsi_set_resid(srb,0);
result= us->transport(srb, us);
……
}
int usb_stor_Bulk_transport(structscsi_cmnd *srb, struct us_data *us)
{
structbulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
structbulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
unsignedint transfer_length = scsi_bufflen(srb);
unsignedint residue;
intresult;
intfake_sense = 0;
unsignedint cswlen;
unsignedint cbwlen = US_BULK_CB_WRAP_LEN;
……
/*See flow chart on pg 15 of the Bulk Only Transport spec for
* an explanation of how this code works.
*/
/*get CSW for device status */
usb_stor_dbg(us,"Attempting to get CSW...\n");
result= usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs,US_BULK_CS_WRAP_LEN, &cswlen);
/*Some broken devices add unnecessary zero-length packets to the
* end of their data transfers. Such packets show up as 0-length
* CSWs. If we encounter such a thing, try to read the CSW again.
*/
if(result == USB_STOR_XFER_SHORT && cswlen == 0) {
usb_stor_dbg(us,"Received 0-length CSW; retrying...\n");
result= usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs,US_BULK_CS_WRAP_LEN, &cswlen);
}
……
/*based on the status code, we report good or bad */
switch(bcs->Status) {
caseUS_BULK_STAT_OK:
/*device babbled -- return fake sense data */
if(fake_sense) {
memcpy(srb->sense_buffer,
usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB));
returnUSB_STOR_TRANSPORT_NO_SENSE;
}
/*command good -- note that data could be short */
returnUSB_STOR_TRANSPORT_GOOD;
caseUS_BULK_STAT_FAIL:
/*command failed */
returnUSB_STOR_TRANSPORT_FAILED;
caseUS_BULK_STAT_PHASE:
/*phase error -- note that a transport reset will be
* invoked by the invoke_transport() function
*/
returnUSB_STOR_TRANSPORT_ERROR;
}
/*we should never get here, but if we do, we're in trouble */
returnUSB_STOR_TRANSPORT_ERROR;
}