]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/keucr/transport.c
Merge tag 'v2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / staging / keucr / transport.c
diff --git a/drivers/staging/keucr/transport.c b/drivers/staging/keucr/transport.c
new file mode 100644 (file)
index 0000000..111160c
--- /dev/null
@@ -0,0 +1,783 @@
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+//----- usb_stor_blocking_completion() ---------------------
+static void usb_stor_blocking_completion(struct urb *urb)
+{
+       struct completion *urb_done_ptr = urb->context;
+
+       //printk("transport --- usb_stor_blocking_completion\n");
+       complete(urb_done_ptr);
+}
+
+//----- usb_stor_msg_common() ---------------------
+static int usb_stor_msg_common(struct us_data *us, int timeout)
+{
+       struct completion urb_done;
+       long timeleft;
+       int status;
+
+       //printk("transport --- usb_stor_msg_common\n");
+       if (test_bit(US_FLIDX_ABORTING, &us->dflags))
+               return -EIO;
+
+       init_completion(&urb_done);
+
+       us->current_urb->context = &urb_done;
+       us->current_urb->actual_length = 0;
+       us->current_urb->error_count = 0;
+       us->current_urb->status = 0;
+
+       us->current_urb->transfer_flags = 0;
+       if (us->current_urb->transfer_buffer == us->iobuf)
+               us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+       us->current_urb->transfer_dma = us->iobuf_dma;
+       us->current_urb->setup_dma = us->cr_dma;
+
+       status = usb_submit_urb(us->current_urb, GFP_NOIO);
+       if (status)
+               return status;
+
+       set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
+
+       if (test_bit(US_FLIDX_ABORTING, &us->dflags))
+       {
+               if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags))
+               {
+                       //printk("-- cancelling URB\n");
+                       usb_unlink_urb(us->current_urb);
+               }
+       }
+
+       timeleft = wait_for_completion_interruptible_timeout(&urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT);
+       clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
+
+       if (timeleft <= 0)
+       {
+               //printk("%s -- cancelling URB\n", timeleft == 0 ? "Timeout" : "Signal");
+               usb_kill_urb(us->current_urb);
+       }
+
+       return us->current_urb->status;
+}
+
+//----- usb_stor_control_msg() ---------------------
+int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+                u8 request, u8 requesttype, u16 value, u16 index,
+                void *data, u16 size, int timeout)
+{
+       int status;
+
+       //printk("transport --- usb_stor_control_msg\n");
+
+       /* fill in the devrequest structure */
+       us->cr->bRequestType = requesttype;
+       us->cr->bRequest = request;
+       us->cr->wValue = cpu_to_le16(value);
+       us->cr->wIndex = cpu_to_le16(index);
+       us->cr->wLength = cpu_to_le16(size);
+
+       /* fill and submit the URB */
+       usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe,
+                        (unsigned char*) us->cr, data, size,
+                        usb_stor_blocking_completion, NULL);
+       status = usb_stor_msg_common(us, timeout);
+
+       /* return the actual length of the data transferred if no error */
+       if (status == 0)
+               status = us->current_urb->actual_length;
+       return status;
+}
+
+//----- usb_stor_clear_halt() ---------------------
+int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
+{
+       int result;
+       int endp = usb_pipeendpoint(pipe);
+
+       //printk("transport --- usb_stor_clear_halt\n");
+       if (usb_pipein (pipe))
+               endp |= USB_DIR_IN;
+
+       result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+               USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
+               USB_ENDPOINT_HALT, endp,
+               NULL, 0, 3*HZ);
+
+       /* reset the endpoint toggle */
+       if (result >= 0)
+               //usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
+                usb_reset_endpoint(us->pusb_dev, endp);
+
+       return result;
+}
+
+//----- interpret_urb_result() ---------------------
+static int interpret_urb_result(struct us_data *us, unsigned int pipe,
+               unsigned int length, int result, unsigned int partial)
+{
+       //printk("transport --- interpret_urb_result\n");
+       switch (result) {
+       /* no error code; did we send all the data? */
+       case 0:
+               if (partial != length)
+               {
+                       //printk("-- short transfer\n");
+                       return USB_STOR_XFER_SHORT;
+               }
+               //printk("-- transfer complete\n");
+               return USB_STOR_XFER_GOOD;
+       case -EPIPE:
+               if (usb_pipecontrol(pipe))
+               {
+                       //printk("-- stall on control pipe\n");
+                       return USB_STOR_XFER_STALLED;
+               }
+               //printk("clearing endpoint halt for pipe 0x%x\n", pipe);
+               if (usb_stor_clear_halt(us, pipe) < 0)
+                       return USB_STOR_XFER_ERROR;
+               return USB_STOR_XFER_STALLED;
+       case -EOVERFLOW:
+               //printk("-- babble\n");
+               return USB_STOR_XFER_LONG;
+       case -ECONNRESET:
+               //printk("-- transfer cancelled\n");
+               return USB_STOR_XFER_ERROR;
+       case -EREMOTEIO:
+               //printk("-- short read transfer\n");
+               return USB_STOR_XFER_SHORT;
+       case -EIO:
+               //printk("-- abort or disconnect in progress\n");
+               return USB_STOR_XFER_ERROR;
+       default:
+               //printk("-- unknown error\n");
+               return USB_STOR_XFER_ERROR;
+       }
+}
+
+//----- usb_stor_bulk_transfer_buf() ---------------------
+int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+       void *buf, unsigned int length, unsigned int *act_len)
+{
+       int result;
+
+       //printk("transport --- usb_stor_bulk_transfer_buf\n");
+
+       /* fill and submit the URB */
+       usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length, usb_stor_blocking_completion, NULL);
+       result = usb_stor_msg_common(us, 0);
+
+       /* store the actual length of the data transferred */
+       if (act_len)
+               *act_len = us->current_urb->actual_length;
+
+       return interpret_urb_result(us, pipe, length, result, us->current_urb->actual_length);
+}
+
+//----- usb_stor_bulk_transfer_sglist() ---------------------
+static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
+               struct scatterlist *sg, int num_sg, unsigned int length,
+               unsigned int *act_len)
+{
+       int result;
+
+       //printk("transport --- usb_stor_bulk_transfer_sglist\n");
+       if (test_bit(US_FLIDX_ABORTING, &us->dflags))
+               return USB_STOR_XFER_ERROR;
+
+       /* initialize the scatter-gather request block */
+       result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0, sg, num_sg, length, GFP_NOIO);
+       if (result)
+       {
+               //printk("usb_sg_init returned %d\n", result);
+               return USB_STOR_XFER_ERROR;
+       }
+
+       /* since the block has been initialized successfully, it's now okay to cancel it */
+       set_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
+
+       /* did an abort/disconnect occur during the submission? */
+       if (test_bit(US_FLIDX_ABORTING, &us->dflags))
+       {
+               /* cancel the request, if it hasn't been cancelled already */
+               if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags))
+               {
+                       //printk("-- cancelling sg request\n");
+                       usb_sg_cancel(&us->current_sg);
+               }
+       }
+
+       /* wait for the completion of the transfer */
+       usb_sg_wait(&us->current_sg);
+       clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
+
+       result = us->current_sg.status;
+       if (act_len)
+               *act_len = us->current_sg.bytes;
+
+       return interpret_urb_result(us, pipe, length, result, us->current_sg.bytes);
+}
+
+//----- usb_stor_bulk_srb() ---------------------
+int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe, struct scsi_cmnd* srb)
+{
+       unsigned int partial;
+       int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
+                                     scsi_sg_count(srb), scsi_bufflen(srb),
+                                     &partial);
+
+       scsi_set_resid(srb, scsi_bufflen(srb) - partial);
+       return result;
+}
+
+//----- usb_stor_bulk_transfer_sg() ---------------------
+int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
+               void *buf, unsigned int length_left, int use_sg, int *residual)
+{
+       int result;
+       unsigned int partial;
+
+       //printk("transport --- usb_stor_bulk_transfer_sg\n");
+       /* are we scatter-gathering? */
+       if (use_sg)
+       {
+               /* use the usb core scatter-gather primitives */
+               result = usb_stor_bulk_transfer_sglist(us, pipe,
+                               (struct scatterlist *) buf, use_sg,
+                               length_left, &partial);
+               length_left -= partial;
+       }
+       else
+       {
+               /* no scatter-gather, just make the request */
+               result = usb_stor_bulk_transfer_buf(us, pipe, buf, length_left, &partial);
+               length_left -= partial;
+       }
+
+       /* store the residual and return the error code */
+       if (residual)
+               *residual = length_left;
+       return result;
+}
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+//----- usb_stor_invoke_transport() ---------------------
+void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+       int need_auto_sense;
+       int result;
+
+       //printk("transport --- usb_stor_invoke_transport\n");
+       usb_stor_print_cmd(srb);
+       /* send the command to the transport layer */
+       scsi_set_resid(srb, 0);
+       result = us->transport(srb, us); //usb_stor_Bulk_transport;
+       
+       /* if the command gets aborted by the higher layers, we need to short-circuit all other processing */
+       if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags))
+       {
+               //printk("-- command was aborted\n");
+               srb->result = DID_ABORT << 16;
+               goto Handle_Errors;
+       }
+
+       /* if there is a transport error, reset and don't auto-sense */
+       if (result == USB_STOR_TRANSPORT_ERROR)
+       {
+               //printk("-- transport indicates error, resetting\n");
+               srb->result = DID_ERROR << 16;
+               goto Handle_Errors;
+       }
+
+       /* if the transport provided its own sense data, don't auto-sense */
+       if (result == USB_STOR_TRANSPORT_NO_SENSE)
+       {
+               srb->result = SAM_STAT_CHECK_CONDITION;
+               return;
+       }
+
+       srb->result = SAM_STAT_GOOD;
+
+       /* Determine if we need to auto-sense */
+       need_auto_sense = 0;
+
+       if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE)
+       {
+               //printk("-- CB transport device requiring auto-sense\n");
+               need_auto_sense = 1;
+       }
+
+       if (result == USB_STOR_TRANSPORT_FAILED)
+       {
+               //printk("-- transport indicates command failure\n");
+               need_auto_sense = 1;
+       }
+
+       /* Now, if we need to do the auto-sense, let's do it */
+       if (need_auto_sense)
+       {
+               int temp_result;
+               struct scsi_eh_save ses;
+
+               printk("Issuing auto-REQUEST_SENSE\n");
+
+               scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
+
+               /* we must do the protocol translation here */
+               if (us->subclass == USB_SC_RBC || us->subclass == USB_SC_SCSI || us->subclass == USB_SC_CYP_ATACB)
+                       srb->cmd_len = 6;
+               else
+                       srb->cmd_len = 12;
+
+               /* issue the auto-sense command */
+               scsi_set_resid(srb, 0);
+               temp_result = us->transport(us->srb, us);
+
+               /* let's clean up right away */
+               scsi_eh_restore_cmnd(srb, &ses);
+
+               if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags))
+               {
+                       //printk("-- auto-sense aborted\n");
+                       srb->result = DID_ABORT << 16;
+                       goto Handle_Errors;
+               }
+               if (temp_result != USB_STOR_TRANSPORT_GOOD)
+               {
+                       //printk("-- auto-sense failure\n");
+                       srb->result = DID_ERROR << 16;
+                       if (!(us->fflags & US_FL_SCM_MULT_TARG))
+                               goto Handle_Errors;
+                       return;
+               }
+
+               /* set the result so the higher layers expect this data */
+               srb->result = SAM_STAT_CHECK_CONDITION;
+
+               if (result == USB_STOR_TRANSPORT_GOOD &&
+                       (srb->sense_buffer[2] & 0xaf) == 0 &&
+                       srb->sense_buffer[12] == 0 &&
+                       srb->sense_buffer[13] == 0)
+               {
+                       srb->result = SAM_STAT_GOOD;
+                       srb->sense_buffer[0] = 0x0;
+               }
+       }
+
+       /* Did we transfer less than the minimum amount required? */
+       if (srb->result == SAM_STAT_GOOD &&     scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
+               srb->result = (DID_ERROR << 16);//v02 | (SUGGEST_RETRY << 24);
+
+       return;
+
+Handle_Errors:
+       scsi_lock(us_to_host(us));
+       set_bit(US_FLIDX_RESETTING, &us->dflags);
+       clear_bit(US_FLIDX_ABORTING, &us->dflags);
+       scsi_unlock(us_to_host(us));
+
+       mutex_unlock(&us->dev_mutex);
+       result = usb_stor_port_reset(us);
+       mutex_lock(&us->dev_mutex);
+
+       if (result < 0)
+       {
+               scsi_lock(us_to_host(us));
+               usb_stor_report_device_reset(us);
+               scsi_unlock(us_to_host(us));
+               us->transport_reset(us);
+       }
+       clear_bit(US_FLIDX_RESETTING, &us->dflags);
+}
+
+//----- ENE_stor_invoke_transport() ---------------------
+void ENE_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+       int result=0;
+
+       //printk("transport --- ENE_stor_invoke_transport\n");
+       usb_stor_print_cmd(srb);
+       /* send the command to the transport layer */
+       scsi_set_resid(srb, 0);
+       if ( !(us->SD_Status.Ready || us->MS_Status.Ready || us->SM_Status.Ready) )
+               result = ENE_InitMedia(us);
+       
+       if (us->Power_IsResum == true) {
+               result = ENE_InitMedia(us);
+               us->Power_IsResum = false;              
+       }       
+       
+       if (us->SD_Status.Ready)        result = SD_SCSIIrp(us, srb);
+       if (us->MS_Status.Ready)        result = MS_SCSIIrp(us, srb);
+       if (us->SM_Status.Ready)        result = SM_SCSIIrp(us, srb);
+
+       /* if the command gets aborted by the higher layers, we need to short-circuit all other processing */
+       if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags))
+       {
+               //printk("-- command was aborted\n");
+               srb->result = DID_ABORT << 16;
+               goto Handle_Errors;
+       }
+
+       /* if there is a transport error, reset and don't auto-sense */
+       if (result == USB_STOR_TRANSPORT_ERROR)
+       {
+               //printk("-- transport indicates error, resetting\n");
+               srb->result = DID_ERROR << 16;
+               goto Handle_Errors;
+       }
+
+       /* if the transport provided its own sense data, don't auto-sense */
+       if (result == USB_STOR_TRANSPORT_NO_SENSE)
+       {
+               srb->result = SAM_STAT_CHECK_CONDITION;
+               return;
+       }
+
+       srb->result = SAM_STAT_GOOD;
+       if (result == USB_STOR_TRANSPORT_FAILED)
+       {
+               //printk("-- transport indicates command failure\n");
+               //need_auto_sense = 1;
+               BuildSenseBuffer(srb, us->SrbStatus);
+               srb->result = SAM_STAT_CHECK_CONDITION;
+       }
+
+       /* Did we transfer less than the minimum amount required? */
+       if (srb->result == SAM_STAT_GOOD && scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
+               srb->result = (DID_ERROR << 16);//v02 | (SUGGEST_RETRY << 24);
+
+       return;
+
+Handle_Errors:
+       scsi_lock(us_to_host(us));
+       set_bit(US_FLIDX_RESETTING, &us->dflags);
+       clear_bit(US_FLIDX_ABORTING, &us->dflags);
+       scsi_unlock(us_to_host(us));
+
+       mutex_unlock(&us->dev_mutex);
+       result = usb_stor_port_reset(us);
+       mutex_lock(&us->dev_mutex);
+
+       if (result < 0)
+       {
+               scsi_lock(us_to_host(us));
+               usb_stor_report_device_reset(us);
+               scsi_unlock(us_to_host(us));
+               us->transport_reset(us);
+       }
+       clear_bit(US_FLIDX_RESETTING, &us->dflags);
+}
+
+//----- BuildSenseBuffer() -------------------------------------------
+void BuildSenseBuffer(struct scsi_cmnd *srb, int SrbStatus)
+{
+    BYTE    *buf = srb->sense_buffer;
+    BYTE    asc;
+
+    printk("transport --- BuildSenseBuffer\n");
+    switch (SrbStatus)
+    {
+        case SS_NOT_READY:        asc = 0x3a;    break;  // sense key = 0x02
+        case SS_MEDIUM_ERR:       asc = 0x0c;    break;  // sense key = 0x03
+        case SS_ILLEGAL_REQUEST:  asc = 0x20;    break;  // sense key = 0x05
+        default:                  asc = 0x00;    break;  // ??
+    }
+
+    memset(buf, 0, 18);
+    buf[0x00] = 0xf0;
+    buf[0x02] = SrbStatus;
+    buf[0x07] = 0x0b;
+    buf[0x0c] = asc;
+}
+
+//----- usb_stor_stop_transport() ---------------------
+void usb_stor_stop_transport(struct us_data *us)
+{
+       //printk("transport --- usb_stor_stop_transport\n");
+
+       if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags))
+       {
+               //printk("-- cancelling URB\n");
+               usb_unlink_urb(us->current_urb);
+       }
+
+       if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags))
+       {
+               //printk("-- cancelling sg request\n");
+               usb_sg_cancel(&us->current_sg);
+       }
+}
+
+//----- usb_stor_Bulk_max_lun() ---------------------
+int usb_stor_Bulk_max_lun(struct us_data *us)
+{
+       int result;
+
+       //printk("transport --- usb_stor_Bulk_max_lun\n");
+       /* issue the command */
+       us->iobuf[0] = 0;
+       result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+                                US_BULK_GET_MAX_LUN,
+                                USB_DIR_IN | USB_TYPE_CLASS |
+                                USB_RECIP_INTERFACE,
+                                0, us->ifnum, us->iobuf, 1, HZ);
+
+       //printk("GetMaxLUN command result is %d, data is %d\n", result, us->iobuf[0]);
+
+       /* if we have a successful request, return the result */
+       if (result > 0)
+               return us->iobuf[0];
+
+       return 0;
+}
+
+//----- usb_stor_Bulk_transport() ---------------------
+int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+       struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+       struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+       unsigned int transfer_length = scsi_bufflen(srb);
+       unsigned int residue;
+       int result;
+       int fake_sense = 0;
+       unsigned int cswlen;
+       unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+       //printk("transport --- usb_stor_Bulk_transport\n");
+       /* Take care of BULK32 devices; set extra byte to 0 */
+       if (unlikely(us->fflags & US_FL_BULK32))
+       {
+               cbwlen = 32;
+               us->iobuf[31] = 0;
+       }
+
+       /* set up the command wrapper */
+       bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+       bcb->DataTransferLength = cpu_to_le32(transfer_length);
+       bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
+       bcb->Tag = ++us->tag;
+       bcb->Lun = srb->device->lun;
+       if (us->fflags & US_FL_SCM_MULT_TARG)
+               bcb->Lun |= srb->device->id << 4;
+       bcb->Length = srb->cmd_len;
+
+       /* copy the command payload */
+       memset(bcb->CDB, 0, sizeof(bcb->CDB));
+       memcpy(bcb->CDB, srb->cmnd, bcb->Length);
+
+       // send command
+       /* send it to out endpoint */
+       /*printk("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
+                       le32_to_cpu(bcb->Signature), bcb->Tag,
+                       le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
+                       (bcb->Lun >> 4), (bcb->Lun & 0x0F),
+                       bcb->Length);*/
+       result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, cbwlen, NULL);
+       //printk("Bulk command transfer result=%d\n", result);
+       if (result != USB_STOR_XFER_GOOD)
+               return USB_STOR_TRANSPORT_ERROR;
+
+       if (unlikely(us->fflags & US_FL_GO_SLOW))
+               udelay(125);
+
+       // R/W data
+       if (transfer_length)
+       {
+               unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe;
+               result = usb_stor_bulk_srb(us, pipe, srb);
+               //printk("Bulk data transfer result 0x%x\n", result);
+               if (result == USB_STOR_XFER_ERROR)
+                       return USB_STOR_TRANSPORT_ERROR;
+
+               if (result == USB_STOR_XFER_LONG)
+                       fake_sense = 1;
+       }
+
+       /* get CSW for device status */
+       //printk("Attempting to get CSW...\n");
+       result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+
+       if (result == USB_STOR_XFER_SHORT && cswlen == 0)
+       {
+               //printk("Received 0-length CSW; retrying...\n");
+               result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+       }
+
+       /* did the attempt to read the CSW fail? */
+       if (result == USB_STOR_XFER_STALLED)
+       {
+               /* get the status again */
+               //printk("Attempting to get CSW (2nd try)...\n");
+               result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL);
+       }
+
+       /* if we still have a failure at this point, we're in trouble */
+       //printk("Bulk status result = %d\n", result);
+       if (result != USB_STOR_XFER_GOOD)
+               return USB_STOR_TRANSPORT_ERROR;
+
+       /* check bulk status */
+       residue = le32_to_cpu(bcs->Residue);
+       //printk("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", le32_to_cpu(bcs->Signature), bcs->Tag, residue, bcs->Status);
+       if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG)) || bcs->Status > US_BULK_STAT_PHASE)
+       {
+               //printk("Bulk logical error\n");
+               return USB_STOR_TRANSPORT_ERROR;
+       }
+
+       if (!us->bcs_signature)
+       {
+               us->bcs_signature = bcs->Signature;
+               //if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN))
+               //      printk("Learnt BCS signature 0x%08X\n", le32_to_cpu(us->bcs_signature));
+       }
+       else if (bcs->Signature != us->bcs_signature)
+       {
+               /*printk("Signature mismatch: got %08X, expecting %08X\n",
+                         le32_to_cpu(bcs->Signature),
+                         le32_to_cpu(us->bcs_signature));*/
+               return USB_STOR_TRANSPORT_ERROR;
+       }
+
+       /* try to compute the actual residue, based on how much data
+        * was really transferred and what the device tells us */
+       if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE))
+       {
+
+               /* Heuristically detect devices that generate bogus residues
+                * by seeing what happens with INQUIRY and READ CAPACITY
+                * commands.
+                */
+               if (bcs->Status == US_BULK_STAT_OK &&
+                               scsi_get_resid(srb) == 0 &&
+                                       ((srb->cmnd[0] == INQUIRY &&
+                                               transfer_length == 36) ||
+                                       (srb->cmnd[0] == READ_CAPACITY &&
+                                               transfer_length == 8)))
+               {
+                       us->fflags |= US_FL_IGNORE_RESIDUE;
+
+               }
+               else
+               {
+                       residue = min(residue, transfer_length);
+                       scsi_set_resid(srb, max(scsi_get_resid(srb), (int) residue));
+               }
+       }
+
+       /* based on the status code, we report good or bad */
+       switch (bcs->Status)
+       {
+               case US_BULK_STAT_OK:
+                       if (fake_sense)
+                       {
+                               memcpy(srb->sense_buffer, usb_stor_sense_invalidCDB, sizeof(usb_stor_sense_invalidCDB));
+                               return USB_STOR_TRANSPORT_NO_SENSE;
+                       }
+                       return USB_STOR_TRANSPORT_GOOD;
+
+               case US_BULK_STAT_FAIL:
+                       return USB_STOR_TRANSPORT_FAILED;
+
+               case US_BULK_STAT_PHASE:
+                       return USB_STOR_TRANSPORT_ERROR;
+       }
+       return USB_STOR_TRANSPORT_ERROR;
+}
+
+/***********************************************************************
+ * Reset routines
+ ***********************************************************************/
+//----- usb_stor_reset_common() ---------------------
+static int usb_stor_reset_common(struct us_data *us,
+               u8 request, u8 requesttype,
+               u16 value, u16 index, void *data, u16 size)
+{
+       int result;
+       int result2;
+
+       //printk("transport --- usb_stor_reset_common\n");
+       if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags))
+       {
+               //printk("No reset during disconnect\n");
+               return -EIO;
+       }
+
+       result = usb_stor_control_msg(us, us->send_ctrl_pipe, request, requesttype, value, index, data, size,   5*HZ);
+       if (result < 0)
+       {
+               //printk("Soft reset failed: %d\n", result);
+               return result;
+       }
+
+       wait_event_interruptible_timeout(us->delay_wait, test_bit(US_FLIDX_DISCONNECTING, &us->dflags), HZ*6);
+       if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags))
+       {
+               //printk("Reset interrupted by disconnect\n");
+               return -EIO;
+       }
+
+       //printk("Soft reset: clearing bulk-in endpoint halt\n");
+       result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
+
+       //printk("Soft reset: clearing bulk-out endpoint halt\n");
+       result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
+
+       /* return a result code based on the result of the clear-halts */
+       if (result >= 0)
+               result = result2;
+       //if (result < 0)
+       //      printk("Soft reset failed\n");
+       //else
+       //      printk("Soft reset done\n");
+       return result;
+}
+
+//----- usb_stor_Bulk_reset() ---------------------
+int usb_stor_Bulk_reset(struct us_data *us)
+{
+       //printk("transport --- usb_stor_Bulk_reset\n");
+       return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
+                                USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                                0, us->ifnum, NULL, 0);
+}
+
+//----- usb_stor_port_reset() ---------------------
+int usb_stor_port_reset(struct us_data *us)
+{
+       int result;
+
+       //printk("transport --- usb_stor_port_reset\n");
+       result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+       if (result < 0)
+               printk("unable to lock device for reset: %d\n", result);
+       else {
+               /* Were we disconnected while waiting for the lock? */
+               if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+                       result = -EIO;
+                       //printk("No reset during disconnect\n");
+               } else {
+                       result = usb_reset_device(us->pusb_dev);
+                       //printk("usb_reset_composite_device returns %d\n", result);
+               }
+               usb_unlock_device(us->pusb_dev);
+       }
+       return result;
+}
+
+