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

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)