[prev in list] [next in list] [prev in thread] [next in thread]
List: linux-usb-devel
Subject: [linux-usb-devel] PATCH: usb-storage: code consolidation
From: Matthew Dharm <mdharm-usb () one-eyed-alien ! net>
Date: 2002-03-31 3:38:09
[Download RAW message or body]
[Attachment #2 (multipart/mixed)]
Attached is a patch to usb-storage against 2.4.19-pre5. Greg, please send
to Marcello for inclusion.
This patch consolidates a great deal of common code in the URB submission
paths, and in the reset paths. This is in preparation for the new
error-handling state machine.
These changes are courtsey of Rowland Stern. I've tested them, and they
look good. More changes will follow shortly.
Matt
--
Matthew Dharm Home: mdharm-usb@one-eyed-alien.net
Maintainer, Linux USB Mass Storage Driver
Why am I talking to a toilet brush?
-- CEO
User Friendly, 4/30/1998
["patch20020330" (text/plain)]
diff -u -X dontdiff linux-2.4.19-pre5/drivers/usb/storage.old/isd200.c \
linux-2.4.19-pre5/drivers/usb/storage/isd200.c
--- linux-2.4.19-pre5/drivers/usb/storage.old/isd200.c Sat Mar 30 16:35:49 2002
+++ linux-2.4.19-pre5/drivers/usb/storage/isd200.c Sat Mar 30 16:40:00 2002
@@ -1,6 +1,6 @@
/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC
*
- * $Id: isd200.c,v 1.14 2002/02/25 00:40:13 mdharm Exp $
+ * $Id: isd200.c,v 1.15 2002/03/31 00:40:00 mdharm Exp $
*
* Current development and maintenance:
* (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
diff -u -X dontdiff linux-2.4.19-pre5/drivers/usb/storage.old/transport.c \
linux-2.4.19-pre5/drivers/usb/storage/transport.c
--- linux-2.4.19-pre5/drivers/usb/storage.old/transport.c Sat Mar 30 16:35:49 2002
+++ linux-2.4.19-pre5/drivers/usb/storage/transport.c Sat Mar 30 15:47:28 2002
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.44 2002/02/25 00:43:41 mdharm Exp $
+ * $Id: transport.c,v 1.45 2002/03/30 23:47:28 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -353,39 +353,19 @@
complete(urb_done_ptr);
}
-/* This is our function to emulate usb_control_msg() but give us enough
- * access to make aborts/resets work
+/* This is the common part of the URB message submission code
+ * This function expects the current_urb_sem to be held upon entry.
*/
-int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
- u8 request, u8 requesttype, u16 value, u16 index,
- void *data, u16 size)
+static int usb_stor_msg_common(struct us_data *us)
{
struct completion urb_done;
int status;
- devrequest *dr;
-
- /* allocate the device request structure */
- dr = kmalloc(sizeof(devrequest), GFP_NOIO);
- if (!dr)
- return -ENOMEM;
-
- /* fill in the structure */
- dr->requesttype = requesttype;
- dr->request = request;
- dr->value = cpu_to_le16(value);
- dr->index = cpu_to_le16(index);
- dr->length = cpu_to_le16(size);
/* set up data structures for the wakeup system */
init_completion(&urb_done);
- /* lock the URB */
- down(&(us->current_urb_sem));
-
- /* fill the URB */
- FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe,
- (unsigned char*) dr, data, size,
- usb_stor_blocking_completion, &urb_done);
+ /* fill the common fields in the URB */
+ us->current_urb->context = &urb_done;
us->current_urb->actual_length = 0;
us->current_urb->error_count = 0;
us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
@@ -394,8 +374,6 @@
status = usb_submit_urb(us->current_urb);
if (status) {
/* something went wrong */
- up(&(us->current_urb_sem));
- kfree(dr);
return status;
}
@@ -404,58 +382,74 @@
wait_for_completion(&urb_done);
down(&(us->current_urb_sem));
+ /* return the URB status */
+ return us->current_urb->status;
+}
+
+/* This is our function to emulate usb_control_msg() with enough control
+ * to make aborts/resets/timeouts work
+ *
+ * FIXME: devrequest is allocated on the kernel stack, which is not always
+ * DMA-capable memory.
+ */
+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 status;
+ devrequest dr;
+
+ /* fill in the devrequest structure */
+ dr.requesttype = requesttype;
+ dr.request = request;
+ dr.value = cpu_to_le16(value);
+ dr.index = cpu_to_le16(index);
+ dr.length = cpu_to_le16(size);
+
+ /* lock the URB */
+ down(&(us->current_urb_sem));
+
+ /* fill the URB */
+ FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe,
+ (unsigned char*) &dr, data, size,
+ usb_stor_blocking_completion, NULL);
+
+ /* submit the URB */
+ status = usb_stor_msg_common(us);
+
/* return the actual length of the data transferred if no error*/
- status = us->current_urb->status;
if (status >= 0)
status = us->current_urb->actual_length;
/* release the lock and return status */
up(&(us->current_urb_sem));
- kfree(dr);
- return status;
+ return status;
}
-/* This is our function to emulate usb_bulk_msg() but give us enough
- * access to make aborts/resets work
+/* This is our function to emulate usb_bulk_msg() with enough control
+ * to make aborts/resets/timeouts work
*/
int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
unsigned int len, unsigned int *act_len)
{
- struct completion urb_done;
int status;
- /* set up data structures for the wakeup system */
- init_completion(&urb_done);
-
/* lock the URB */
down(&(us->current_urb_sem));
/* fill the URB */
FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
- usb_stor_blocking_completion, &urb_done);
- us->current_urb->actual_length = 0;
- us->current_urb->error_count = 0;
- us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
+ usb_stor_blocking_completion, NULL);
/* submit the URB */
- status = usb_submit_urb(us->current_urb);
- if (status) {
- /* something went wrong */
- up(&(us->current_urb_sem));
- return status;
- }
-
- /* wait for the completion of the URB */
- up(&(us->current_urb_sem));
- wait_for_completion(&urb_done);
- down(&(us->current_urb_sem));
+ status = usb_stor_msg_common(us);
/* return the actual length of the data transferred */
*act_len = us->current_urb->actual_length;
/* release the lock and return status */
up(&(us->current_urb_sem));
- return us->current_urb->status;
+ return status;
}
/* This is a version of usb_clear_halt() that doesn't read the status from
@@ -616,7 +610,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 receive the response.
+ * the device and recieve the response.
*/
void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
{
@@ -1073,8 +1067,6 @@
return 0;
}
-int usb_stor_Bulk_reset(struct us_data *us);
-
int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
{
struct bulk_cb_wrap bcb;
@@ -1229,12 +1221,108 @@
* Reset routines
***********************************************************************/
+struct us_timeout {
+ struct us_data *us;
+ spinlock_t timer_lock;
+};
+
+/* The timeout event handler
+ */
+static void usb_stor_timeout_handler(unsigned long to__)
+{
+ struct us_timeout *to = (struct us_timeout *) to__;
+ struct us_data *us = to->us;
+
+ US_DEBUGP("Timeout occurred\n");
+
+ /* abort the current request */
+ if (us->current_urb->status == -EINPROGRESS)
+ usb_unlink_urb(us->current_urb);
+
+ /* let the reset routine know we have finished */
+ spin_unlock(&to->timer_lock);
+}
+
+/* This is the common part of the device reset code.
+ *
+ * It's handy that every transport mechanism uses the control endpoint for
+ * resets.
+ *
+ * Basically, we send a reset with a 20-second timeout, so we don't get
+ * jammed attempting to do the reset.
+ */
+void usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype,
+ u16 value, u16 index, void *data, u16 size)
+{
+ int result;
+ struct us_timeout timeout_data = {us, SPIN_LOCK_UNLOCKED};
+ struct timer_list timeout_list;
+
+ /* prepare the timeout handler */
+ spin_lock(&timeout_data.timer_lock);
+ init_timer(&timeout_list);
+
+ /* A 20-second timeout may seem rather long, but a LaCie
+ * StudioDrive USB2 device takes 16+ seconds to get going
+ * following a powerup or USB attach event. */
+
+ timeout_list.expires = jiffies + 20 * HZ;
+ timeout_list.data = (unsigned long) &timeout_data;
+ timeout_list.function = usb_stor_timeout_handler;
+ add_timer(&timeout_list);
+
+ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+ request, requesttype, value, index, data, size);
+ if (result < 0)
+ goto Done;
+
+ /* long wait for reset */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ*6);
+ set_current_state(TASK_RUNNING);
+
+ US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
+ result = usb_stor_clear_halt(us,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ if (result < 0)
+ goto Done;
+
+ US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
+ result = usb_stor_clear_halt(us,
+ usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+
+ Done:
+
+ /* prevent the timer from coming back to haunt us */
+ if (!del_timer(&timeout_list)) {
+ /* the handler has already started; wait for it to finish */
+ spin_lock(&timeout_data.timer_lock);
+ /* change the abort into a timeout */
+ if (result == -ENOENT)
+ result = -ETIMEDOUT;
+ }
+
+ /* return a result code based on the result of the control message */
+ if (result >= 0)
+ US_DEBUGP("Soft reset done\n");
+ else
+ US_DEBUGP("Soft reset failed: %d\n", result);
+
+ if (result == -ETIMEDOUT)
+ us->srb->result = DID_TIME_OUT << 16;
+ else if (result == -ENOENT)
+ us->srb->result = DID_ABORT << 16;
+ else if (result < 0)
+ us->srb->result = DID_ERROR << 16;
+ else
+ us->srb->result = GOOD << 1;
+}
+
/* This issues a CB[I] Reset to the device in question
*/
int usb_stor_CB_reset(struct us_data *us)
{
unsigned char cmd[12];
- int result;
US_DEBUGP("CB_reset() called\n");
@@ -1245,30 +1333,10 @@
memset(cmd, 0xFF, sizeof(cmd));
cmd[0] = SEND_DIAGNOSTIC;
cmd[1] = 4;
- result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_CBI_ADSC,
+ usb_stor_reset_common(us, US_CBI_ADSC,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
-
- if (result < 0) {
- US_DEBUGP("CB[I] soft reset failed %d\n", result);
- return FAILED;
- }
-
- /* long wait for reset */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ*6);
- set_current_state(TASK_RUNNING);
-
- US_DEBUGP("CB_reset: clearing endpoint halt\n");
- 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 */
- return SUCCESS;
+ 0, us->ifnum, cmd, sizeof(cmd));
+ return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
}
/* This issues a Bulk-only Reset to the device in question, including
@@ -1276,34 +1344,14 @@
*/
int usb_stor_Bulk_reset(struct us_data *us)
{
- int result;
-
US_DEBUGP("Bulk reset requested\n");
/* if the device was removed, then we're already reset */
if (!us->pusb_dev)
return SUCCESS;
- result = usb_control_msg(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,0),
- US_BULK_RESET_REQUEST,
+ usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, us->ifnum, NULL, 0, HZ*5);
-
- if (result < 0) {
- US_DEBUGP("Bulk soft reset failed %d\n", result);
- return FAILED;
- }
-
- /* long wait for reset */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ*6);
- set_current_state(TASK_RUNNING);
-
- 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;
+ 0, us->ifnum, NULL, 0);
+ return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
}
diff -u -X dontdiff linux-2.4.19-pre5/drivers/usb/storage.old/usb.h \
linux-2.4.19-pre5/drivers/usb/storage/usb.h
--- linux-2.4.19-pre5/drivers/usb/storage.old/usb.h Thu Nov 22 11:49:34 2001
+++ linux-2.4.19-pre5/drivers/usb/storage/usb.h Sat Mar 30 17:02:59 2002
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* Main Header File
*
- * $Id: usb.h,v 1.18 2001/07/30 00:27:59 mdharm Exp $
+ * $Id: usb.h,v 1.20 2002/03/31 00:40:00 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -188,4 +188,5 @@
/* Function to fill an inquiry response. See usb.c for details */
extern void fill_inquiry_response(struct us_data *us,
unsigned char *data, unsigned int data_len);
+
#endif
[Attachment #6 (application/pgp-signature)]
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic