summaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage/transport.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/storage/transport.c')
-rw-r--r--drivers/usb/storage/transport.c98
1 files changed, 54 insertions, 44 deletions
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 6610d2dd1e7..3523a0bfa0f 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1,7 +1,5 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.47 2002/04/22 03:39:43 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -75,14 +73,14 @@
* by a separate code path.)
*
* The abort function (usb_storage_command_abort() in scsiglue.c) first
- * sets the machine state and the ABORTING bit in us->flags to prevent
+ * sets the machine state and the ABORTING bit in us->dflags to prevent
* new URBs from being submitted. It then calls usb_stor_stop_transport()
- * below, which atomically tests-and-clears the URB_ACTIVE bit in us->flags
+ * below, which atomically tests-and-clears the URB_ACTIVE bit in us->dflags
* to see if the current_urb needs to be stopped. Likewise, the SG_ACTIVE
* bit is tested to see if the current_sg scatter-gather request needs to be
* stopped. The timeout callback routine does much the same thing.
*
- * When a disconnect occurs, the DISCONNECTING bit in us->flags is set to
+ * When a disconnect occurs, the DISCONNECTING bit in us->dflags is set to
* prevent new URBs from being submitted, and usb_stor_stop_transport() is
* called to stop any ongoing requests.
*
@@ -127,8 +125,8 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
long timeleft;
int status;
- /* don't submit URBs during abort/disconnect processing */
- if (us->flags & ABORTING_OR_DISCONNECTING)
+ /* don't submit URBs during abort processing */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags))
return -EIO;
/* set up data structures for the wakeup system */
@@ -159,13 +157,13 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
/* since the URB has been submitted successfully, it's now okay
* to cancel it */
- set_bit(US_FLIDX_URB_ACTIVE, &us->flags);
+ set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
- /* did an abort/disconnect occur during the submission? */
- if (us->flags & ABORTING_OR_DISCONNECTING) {
+ /* did an abort occur during the submission? */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
/* cancel the URB, if it hasn't been cancelled already */
- if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
+ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
US_DEBUGP("-- cancelling URB\n");
usb_unlink_urb(us->current_urb);
}
@@ -175,7 +173,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
timeleft = wait_for_completion_interruptible_timeout(
&urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT);
- clear_bit(US_FLIDX_URB_ACTIVE, &us->flags);
+ clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
if (timeleft <= 0) {
US_DEBUGP("%s -- cancelling URB\n",
@@ -419,8 +417,8 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
{
int result;
- /* don't submit s-g requests during abort/disconnect processing */
- if (us->flags & ABORTING_OR_DISCONNECTING)
+ /* don't submit s-g requests during abort processing */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags))
return USB_STOR_XFER_ERROR;
/* initialize the scatter-gather request block */
@@ -435,13 +433,13 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
/* since the block has been initialized successfully, it's now
* okay to cancel it */
- set_bit(US_FLIDX_SG_ACTIVE, &us->flags);
+ set_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
- /* did an abort/disconnect occur during the submission? */
- if (us->flags & ABORTING_OR_DISCONNECTING) {
+ /* did an abort 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->flags)) {
+ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
US_DEBUGP("-- cancelling sg request\n");
usb_sg_cancel(&us->current_sg);
}
@@ -449,7 +447,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
/* wait for the completion of the transfer */
usb_sg_wait(&us->current_sg);
- clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);
+ clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
result = us->current_sg.status;
if (act_len)
@@ -530,7 +528,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* 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->flags)) {
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
US_DEBUGP("-- command was aborted\n");
srb->result = DID_ABORT << 16;
goto Handle_Errors;
@@ -616,7 +614,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* let's clean up right away */
scsi_eh_restore_cmnd(srb, &ses);
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
US_DEBUGP("-- auto-sense aborted\n");
srb->result = DID_ABORT << 16;
goto Handle_Errors;
@@ -629,7 +627,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* auto-sense is perfectly valid
*/
srb->result = DID_ERROR << 16;
- if (!(us->flags & US_FL_SCM_MULT_TARG))
+ if (!(us->fflags & US_FL_SCM_MULT_TARG))
goto Handle_Errors;
return;
}
@@ -679,8 +677,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* Set the RESETTING bit, and clear the ABORTING bit so that
* the reset may proceed. */
scsi_lock(us_to_host(us));
- set_bit(US_FLIDX_RESETTING, &us->flags);
- clear_bit(US_FLIDX_ABORTING, &us->flags);
+ set_bit(US_FLIDX_RESETTING, &us->dflags);
+ clear_bit(US_FLIDX_ABORTING, &us->dflags);
scsi_unlock(us_to_host(us));
/* We must release the device lock because the pre_reset routine
@@ -695,7 +693,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
scsi_unlock(us_to_host(us));
us->transport_reset(us);
}
- clear_bit(US_FLIDX_RESETTING, &us->flags);
+ clear_bit(US_FLIDX_RESETTING, &us->dflags);
}
/* Stop the current URB transfer */
@@ -707,13 +705,13 @@ void usb_stor_stop_transport(struct us_data *us)
* let's wake it up. The test_and_clear_bit() call
* guarantees that if a URB has just been submitted,
* it won't be cancelled more than once. */
- if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
+ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
US_DEBUGP("-- cancelling URB\n");
usb_unlink_urb(us->current_urb);
}
/* If we are waiting for a scatter-gather operation, cancel it. */
- if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
+ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
US_DEBUGP("-- cancelling sg request\n");
usb_sg_cancel(&us->current_sg);
}
@@ -914,7 +912,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
/* Take care of BULK32 devices; set extra byte to 0 */
- if ( unlikely(us->flags & US_FL_BULK32)) {
+ if (unlikely(us->fflags & US_FL_BULK32)) {
cbwlen = 32;
us->iobuf[31] = 0;
}
@@ -925,7 +923,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
bcb->Tag = ++us->tag;
bcb->Lun = srb->device->lun;
- if (us->flags & US_FL_SCM_MULT_TARG)
+ if (us->fflags & US_FL_SCM_MULT_TARG)
bcb->Lun |= srb->device->id << 4;
bcb->Length = srb->cmd_len;
@@ -951,7 +949,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
/* Some USB-IDE converter chips need a 100us delay between the
* command phase and the data phase. Some devices need a little
* more than that, probably because of clock rate inaccuracies. */
- if (unlikely(us->flags & US_FL_GO_SLOW))
+ if (unlikely(us->fflags & US_FL_GO_SLOW))
udelay(125);
if (transfer_length) {
@@ -1010,7 +1008,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
US_DEBUGP("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->flags & US_FL_BULK_IGNORE_TAG)) ||
+ if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG)) ||
bcs->Status > US_BULK_STAT_PHASE) {
US_DEBUGP("Bulk logical error\n");
return USB_STOR_TRANSPORT_ERROR;
@@ -1034,8 +1032,21 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
/* try to compute the actual residue, based on how much data
* was really transferred and what the device tells us */
- if (residue) {
- if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
+ 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));
@@ -1090,7 +1101,7 @@ static int usb_stor_reset_common(struct us_data *us,
int result;
int result2;
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
US_DEBUGP("No reset during disconnect\n");
return -EIO;
}
@@ -1103,12 +1114,12 @@ static int usb_stor_reset_common(struct us_data *us,
return result;
}
- /* Give the device some time to recover from the reset,
- * but don't delay disconnect processing. */
- wait_event_interruptible_timeout(us->delay_wait,
- test_bit(US_FLIDX_DISCONNECTING, &us->flags),
- HZ*6);
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+ /* Give the device some time to recover from the reset,
+ * but don't delay disconnect processing. */
+ wait_event_interruptible_timeout(us->delay_wait,
+ test_bit(US_FLIDX_DISCONNECTING, &us->dflags),
+ HZ*6);
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
US_DEBUGP("Reset interrupted by disconnect\n");
return -EIO;
}
@@ -1170,13 +1181,12 @@ int usb_stor_port_reset(struct us_data *us)
US_DEBUGP("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->flags)) {
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
result = -EIO;
US_DEBUGP("No reset during disconnect\n");
} else {
- result = usb_reset_composite_device(
- us->pusb_dev, us->pusb_intf);
- US_DEBUGP("usb_reset_composite_device returns %d\n",
+ result = usb_reset_device(us->pusb_dev);
+ US_DEBUGP("usb_reset_device returns %d\n",
result);
}
if (rc_lock)