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: [EMAIL PROTECTED] 
Maintainer, Linux USB Mass Storage Driver

Why am I talking to a toilet brush?
                                        -- CEO
User Friendly, 4/30/1998
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 ([EMAIL PROTECTED])
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 ([EMAIL PROTECTED])
@@ -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 ([EMAIL PROTECTED])
@@ -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: msg05421/pgp00000.pgp
Description: PGP signature

Reply via email to