您的位置:首页 > 其它

SCSI work flow

2016-05-03 16:11 417 查看
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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: