patch-2.4.19 linux-2.4.19/drivers/usb/storage/transport.c
Next file: linux-2.4.19/drivers/usb/storage/transport.h
Previous file: linux-2.4.19/drivers/usb/storage/shuttle_usbat.c
Back to the patch index
Back to the overall index
- Lines: 443
- Date:
Fri Aug 2 17:39:45 2002
- Orig file:
linux-2.4.18/drivers/usb/storage/transport.c
- Orig date:
Mon Feb 25 11:38:07 2002
diff -urN linux-2.4.18/drivers/usb/storage/transport.c linux-2.4.19/drivers/usb/storage/transport.c
@@ -1,13 +1,14 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.42 2001/12/08 23:32:48 mdharm Exp $
+ * $Id: transport.c,v 1.44 2002/02/25 00:43:41 mdharm Exp $
*
* Current development and maintenance by:
- * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
* (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
+ * (c) 2002 Alan Stern <stern@rowland.org>
*
* Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com)
@@ -335,31 +336,7 @@
len = srb->request_bufflen;
}
-return len;
-}
-
-/* This is a version of usb_clear_halt() that doesn't read the status from
- * the device -- this is because some devices crash their internal firmware
- * when the status is requested after a halt
- */
-int usb_stor_clear_halt(struct usb_device *dev, int pipe)
-{
- int result;
- int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);
-
- result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
- endp, NULL, 0, HZ * 3);
-
- /* this is a failure case */
- if (result < 0)
- return result;
-
- /* reset the toggles and endpoint flags */
- usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
- usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
-
- return 0;
+ return len;
}
/***********************************************************************
@@ -481,6 +458,34 @@
return us->current_urb->status;
}
+/* This is a version of usb_clear_halt() that doesn't read the status from
+ * the device -- this is because some devices crash their internal firmware
+ * when the status is requested after a halt
+ */
+int usb_stor_clear_halt(struct us_data *us, int pipe)
+{
+ int result;
+ int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);
+
+ result = usb_stor_control_msg(us,
+ usb_sndctrlpipe(us->pusb_dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
+ endp, NULL, 0); /* note: no 3*HZ timeout */
+ US_DEBUGP("usb_stor_clear_halt: result=%d\n", result);
+
+ /* this is a failure case */
+ if (result < 0)
+ return result;
+
+ /* reset the toggles and endpoint flags */
+ usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe));
+ usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe), 0);
+
+ return 0;
+}
+
/*
* Transfer one SCSI scatter-gather buffer via bulk transfer
*
@@ -513,7 +518,13 @@
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_stor_clear_halt(us->pusb_dev, pipe);
+ usb_stor_clear_halt(us, pipe);
+ }
+
+ /* did we abort this command? */
+ if (result == -ENOENT) {
+ US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
}
/* did we send all the data? */
@@ -522,21 +533,14 @@
return US_BULK_TRANSFER_GOOD;
}
- /* uh oh... we have an error code, so something went wrong. */
- if (result) {
- /* NAK - that means we've retried a few times already */
- if (result == -ETIMEDOUT) {
- US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
- return US_BULK_TRANSFER_FAILED;
- }
-
- /* -ENOENT -- we canceled this transfer */
- if (result == -ENOENT) {
- US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");
- return US_BULK_TRANSFER_ABORTED;
- }
+ /* NAK - that means we've retried a few times already */
+ if (result == -ETIMEDOUT) {
+ US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
- /* the catch-all case */
+ /* the catch-all error case */
+ if (result) {
US_DEBUGP("usb_stor_transfer_partial(): unknown error\n");
return US_BULK_TRANSFER_FAILED;
}
@@ -550,7 +554,7 @@
* Transfer an entire SCSI command's worth of data payload over the bulk
* pipe.
*
- * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this
+ * Note that this uses usb_stor_transfer_partial to achieve its goals -- this
* function simply determines if we're going to use scatter-gather or not,
* and acts appropriately. For now, it also re-interprets the error codes.
*/
@@ -612,7 +616,7 @@
/* Invoke the transport and basic error-handling/recovery methods
*
* This is used by the protocol layers to actually send the message to
- * the device and recieve the response.
+ * the device and receive the response.
*/
void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
{
@@ -631,6 +635,14 @@
return;
}
+ /* if there is a transport error, reset and don't auto-sense */
+ if (result == USB_STOR_TRANSPORT_ERROR) {
+ US_DEBUGP("-- transport indicates error, resetting\n");
+ us->transport_reset(us);
+ srb->result = DID_ERROR << 16;
+ return;
+ }
+
/* Determine if we need to auto-sense
*
* I normally don't use a flag like this, but it's almost impossible
@@ -660,7 +672,7 @@
}
/*
- * If we have an error, we're going to do a REQUEST_SENSE
+ * If we have a failure, we're going to do a REQUEST_SENSE
* automatically. Note that we differentiate between a command
* "failure" and an "error" in the transport mechanism.
*/
@@ -668,13 +680,6 @@
US_DEBUGP("-- transport indicates command failure\n");
need_auto_sense = 1;
}
- if (result == USB_STOR_TRANSPORT_ERROR) {
- us->transport_reset(us);
- US_DEBUGP("-- transport indicates transport failure\n");
- need_auto_sense = 0;
- srb->result = DID_ERROR << 16;
- return;
- }
/*
* Also, if we have a short transfer on a command that can't have
@@ -730,6 +735,19 @@
/* issue the auto-sense command */
temp_result = us->transport(us->srb, us);
+
+ /* let's clean up right away */
+ srb->request_buffer = old_request_buffer;
+ srb->request_bufflen = old_request_bufflen;
+ srb->use_sg = old_sg;
+ srb->sc_data_direction = old_sc_data_direction;
+ memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
+
+ if (temp_result == USB_STOR_TRANSPORT_ABORTED) {
+ US_DEBUGP("-- auto-sense aborted\n");
+ srb->result = DID_ABORT << 16;
+ return;
+ }
if (temp_result != USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("-- auto-sense failure\n");
@@ -760,13 +778,6 @@
/* set the result so the higher layers expect this data */
srb->result = CHECK_CONDITION << 1;
- /* we're done here, let's clean up */
- srb->request_buffer = old_request_buffer;
- srb->request_bufflen = old_request_bufflen;
- srb->use_sg = old_sg;
- srb->sc_data_direction = old_sc_data_direction;
- memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
-
/* If things are really okay, then let's show that */
if ((srb->sense_buffer[2] & 0xf) == 0x0)
srb->result = GOOD << 1;
@@ -798,7 +809,7 @@
{
struct us_data *us = (struct us_data *)urb->context;
- US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+ US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no);
US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
US_DEBUGP("-- IRQ state is %d\n", urb->status);
US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
@@ -864,21 +875,25 @@
if (result < 0) {
/* Reset flag for status notification */
atomic_set(us->ip_wanted, 0);
+ }
+
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
+ /* STALL must be cleared when it is detected */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_stor_clear_halt(us,
+ usb_sndctrlpipe(us->pusb_dev, 0));
/* if the command was aborted, indicate that */
if (result == -ENOENT)
return USB_STOR_TRANSPORT_ABORTED;
+ return USB_STOR_TRANSPORT_FAILED;
+ }
- /* STALL must be cleared when they are detected */
- if (result == -EPIPE) {
- US_DEBUGP("-- Stall on control pipe. Clearing\n");
- result = usb_stor_clear_halt(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,
- 0));
- US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
- return USB_STOR_TRANSPORT_FAILED;
- }
-
+ if (result < 0) {
/* Uh oh... serious problem here */
return USB_STOR_TRANSPORT_ERROR;
}
@@ -887,12 +902,18 @@
/* transfer the data payload for this command, if one exists*/
if (usb_stor_transfer_length(srb)) {
usb_stor_transfer(srb, us);
- US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
+ result = srb->result;
+ US_DEBUGP("CBI data stage result is 0x%x\n", result);
- /* if it was aborted, we need to indicate that */
- if (srb->result == USB_STOR_TRANSPORT_ABORTED) {
+ /* report any errors */
+ if (result == US_BULK_TRANSFER_ABORTED) {
+ atomic_set(us->ip_wanted, 0);
return USB_STOR_TRANSPORT_ABORTED;
}
+ if (result == US_BULK_TRANSFER_FAILED) {
+ atomic_set(us->ip_wanted, 0);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
}
/* STATUS STAGE */
@@ -976,10 +997,12 @@
/* a stall is a fatal condition from the device */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n");
- result = usb_stor_clear_halt(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,
- 0));
- US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
+ result = usb_stor_clear_halt(us,
+ usb_sndctrlpipe(us->pusb_dev, 0));
+
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
return USB_STOR_TRANSPORT_FAILED;
}
@@ -991,11 +1014,16 @@
/* transfer the data payload for this command, if one exists*/
if (usb_stor_transfer_length(srb)) {
usb_stor_transfer(srb, us);
- US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
+ result = srb->result;
+ US_DEBUGP("CB data stage result is 0x%x\n", result);
- /* if it was aborted, we need to indicate that */
- if (srb->result == USB_STOR_TRANSPORT_ABORTED)
+ /* report any errors */
+ if (result == US_BULK_TRANSFER_ABORTED) {
return USB_STOR_TRANSPORT_ABORTED;
+ }
+ if (result == US_BULK_TRANSFER_FAILED) {
+ return USB_STOR_TRANSPORT_FAILED;
+ }
}
/* STATUS STAGE */
@@ -1016,7 +1044,8 @@
int result;
int pipe;
- /* issue the command */
+ /* issue the command -- use usb_control_msg() because
+ * the state machine is not yet alive */
pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
result = usb_control_msg(us->pusb_dev, pipe,
US_BULK_GET_MAX_LUN,
@@ -1034,7 +1063,10 @@
/* if we get a STALL, clear the stall */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_stor_clear_halt(us->pusb_dev, pipe);
+
+ /* Use usb_clear_halt() because the state machine
+ * is not yet alive */
+ usb_clear_halt(us->pusb_dev, pipe);
}
/* return the default -- no LUNs */
@@ -1051,10 +1083,6 @@
int pipe;
int partial;
- /* if the device was removed, then we're already reset */
- if (!us->pusb_dev)
- return SUCCESS;
-
/* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb));
@@ -1088,7 +1116,12 @@
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_stor_clear_halt(us->pusb_dev, pipe);
+ result = usb_stor_clear_halt(us, pipe);
+
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+ result = -EPIPE;
} else if (result) {
/* unknown error -- we've got a problem */
return USB_STOR_TRANSPORT_ERROR;
@@ -1099,11 +1132,11 @@
/* send/receive data payload, if there is any */
if (bcb.DataTransferLength) {
usb_stor_transfer(srb, us);
- US_DEBUGP("Bulk data transfer result 0x%x\n",
- srb->result);
+ result = srb->result;
+ US_DEBUGP("Bulk data transfer result 0x%x\n", result);
/* if it was aborted, we need to indicate that */
- if (srb->result == USB_STOR_TRANSPORT_ABORTED)
+ if (result == US_BULK_TRANSFER_ABORTED)
return USB_STOR_TRANSPORT_ABORTED;
}
}
@@ -1127,8 +1160,12 @@
/* did the attempt to read the CSW fail? */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_stor_clear_halt(us->pusb_dev, pipe);
-
+ result = usb_stor_clear_halt(us, pipe);
+
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
/* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_msg(us, &bcs, pipe,
@@ -1141,7 +1178,11 @@
/* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) {
US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
- usb_stor_clear_halt(us->pusb_dev, pipe);
+ result = usb_stor_clear_halt(us, pipe);
+
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
return USB_STOR_TRANSPORT_ERROR;
}
}
@@ -1220,10 +1261,10 @@
set_current_state(TASK_RUNNING);
US_DEBUGP("CB_reset: clearing endpoint halt\n");
- usb_stor_clear_halt(us->pusb_dev,
- usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
- usb_stor_clear_halt(us->pusb_dev,
- usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+ usb_stor_clear_halt(us,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ usb_stor_clear_halt(us,
+ usb_sndbulkpipe(us->pusb_dev, us->ep_out));
US_DEBUGP("CB_reset done\n");
/* return a result code based on the result of the control message */
@@ -1259,10 +1300,10 @@
schedule_timeout(HZ*6);
set_current_state(TASK_RUNNING);
- usb_stor_clear_halt(us->pusb_dev,
- usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
- usb_stor_clear_halt(us->pusb_dev,
- usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+ usb_stor_clear_halt(us,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ usb_stor_clear_halt(us,
+ usb_sndbulkpipe(us->pusb_dev, us->ep_out));
US_DEBUGP("Bulk soft reset completed\n");
return SUCCESS;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)