This is what I cooked for lockups in Fedora. Seems to work fine there.

It also makes storage not to reset devices with several interfaces.
This innovation comes from 2.6.

[I cannot figure if Matt Dharm approves or not, he was kinda quiet lately,
but I think it's a good patch and it has some testing on it, so no offense
hopefuly.]

-- Pete

diff -urN -X dontdiff linux-2.4.26/drivers/usb/storage/scsiglue.c 
linux-2.4.26-nip/drivers/usb/storage/scsiglue.c
--- linux-2.4.26/drivers/usb/storage/scsiglue.c 2004-04-14 17:33:16.000000000 -0700
+++ linux-2.4.26-nip/drivers/usb/storage/scsiglue.c     2004-04-18 20:30:27.000000000 
-0700
@@ -218,7 +218,14 @@
        US_DEBUGP("device_reset() called\n" );
 
        spin_unlock_irq(&io_request_lock);
+       down(&(us->dev_semaphore));
+       if (!us->pusb_dev) {
+               up(&(us->dev_semaphore));
+               spin_lock_irq(&io_request_lock);
+               return SUCCESS;
+       }
        rc = us->transport_reset(us);
+       up(&(us->dev_semaphore));
        spin_lock_irq(&io_request_lock);
        return rc;
 }
@@ -235,27 +242,44 @@
        /* we use the usb_reset_device() function to handle this for us */
        US_DEBUGP("bus_reset() called\n");
 
+       spin_unlock_irq(&io_request_lock);
+
+       down(&(us->dev_semaphore));
+
        /* if the device has been removed, this worked */
        if (!us->pusb_dev) {
                US_DEBUGP("-- device removed already\n");
+               up(&(us->dev_semaphore));
+               spin_lock_irq(&io_request_lock);
                return SUCCESS;
        }
 
-       spin_unlock_irq(&io_request_lock);
+       /* The USB subsystem doesn't handle synchronisation between
+        * a device's several drivers. Therefore we reset only devices
+        * with just one interface, which we of course own. */
+       if (us->pusb_dev->actconfig->bNumInterfaces != 1) {
+               printk(KERN_NOTICE "usb-storage: "
+                   "Refusing to reset a multi-interface device\n");
+               up(&(us->dev_semaphore));
+               spin_lock_irq(&io_request_lock);
+               /* XXX Don't just return success, make sure current cmd fails */
+               return SUCCESS;
+       }
 
        /* release the IRQ, if we have one */
-       down(&(us->irq_urb_sem));
        if (us->irq_urb) {
                US_DEBUGP("-- releasing irq URB\n");
                result = usb_unlink_urb(us->irq_urb);
                US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
        }
-       up(&(us->irq_urb_sem));
 
        /* attempt to reset the port */
        if (usb_reset_device(us->pusb_dev) < 0) {
-               spin_lock_irq(&io_request_lock);
-               return FAILED;
+               /*
+                * Do not return errors, or else the error handler might
+                * invoke host_reset, which is not implemented.
+                */
+               goto bail_out;
        }
 
        /* FIXME: This needs to lock out driver probing while it's working
@@ -286,17 +310,18 @@
                up(&intf->driver->serialize);
        }
 
+bail_out:
        /* re-allocate the IRQ URB and submit it to restore connectivity
         * for CBI devices
         */
        if (us->protocol == US_PR_CBI) {
-               down(&(us->irq_urb_sem));
                us->irq_urb->dev = us->pusb_dev;
                result = usb_submit_urb(us->irq_urb);
                US_DEBUGP("usb_submit_urb() returns %d\n", result);
-               up(&(us->irq_urb_sem));
        }
-       
+
+       up(&(us->dev_semaphore));
+
        spin_lock_irq(&io_request_lock);
 
        US_DEBUGP("bus_reset() complete\n");

diff -urN -X dontdiff linux-2.4.26/drivers/usb/storage/usb.c 
linux-2.4.26-nip/drivers/usb/storage/usb.c
--- linux-2.4.26/drivers/usb/storage/usb.c      2004-02-26 14:09:59.000000000 -0800
+++ linux-2.4.26-nip/drivers/usb/storage/usb.c  2004-04-14 18:13:39.000000000 -0700
@@ -501,6 +501,9 @@
  * strucuture is current.  This includes the ep_int field, which gives us
  * the endpoint for the interrupt.
  * Returns non-zero on failure, zero on success
+ *
+ * ss->dev_semaphore is expected taken, except for a newly minted,
+ * unregistered device.
  */ 
 static int usb_stor_allocate_irq(struct us_data *ss)
 {
@@ -510,13 +513,9 @@
 
        US_DEBUGP("Allocating IRQ for CBI transport\n");
 
-       /* lock access to the data structure */
-       down(&(ss->irq_urb_sem));
-
        /* allocate the URB */
        ss->irq_urb = usb_alloc_urb(0);
        if (!ss->irq_urb) {
-               up(&(ss->irq_urb_sem));
                US_DEBUGP("couldn't allocate interrupt URB");
                return 1;
        }
@@ -537,12 +536,9 @@
        US_DEBUGP("usb_submit_urb() returns %d\n", result);
        if (result) {
                usb_free_urb(ss->irq_urb);
-               up(&(ss->irq_urb_sem));
                return 2;
        }
 
-       /* unlock the data structure and return success */
-       up(&(ss->irq_urb_sem));
        return 0;
 }
 
@@ -772,7 +768,6 @@
                init_completion(&(ss->notify));
                init_MUTEX_LOCKED(&(ss->ip_waitq));
                spin_lock_init(&(ss->queue_exclusion));
-               init_MUTEX(&(ss->irq_urb_sem));
                init_MUTEX(&(ss->current_urb_sem));
                init_MUTEX(&(ss->dev_semaphore));
 
@@ -1063,7 +1058,6 @@
        down(&(ss->dev_semaphore));
 
        /* release the IRQ, if we have one */
-       down(&(ss->irq_urb_sem));
        if (ss->irq_urb) {
                US_DEBUGP("-- releasing irq URB\n");
                result = usb_unlink_urb(ss->irq_urb);
@@ -1071,7 +1065,6 @@
                usb_free_urb(ss->irq_urb);
                ss->irq_urb = NULL;
        }
-       up(&(ss->irq_urb_sem));
 
        /* free up the main URB for this device */
        US_DEBUGP("-- releasing main URB\n");
diff -urN -X dontdiff linux-2.4.26/drivers/usb/storage/usb.h 
linux-2.4.26-nip/drivers/usb/storage/usb.h
--- linux-2.4.26/drivers/usb/storage/usb.h      2003-11-29 19:23:15.000000000 -0800
+++ linux-2.4.26-nip/drivers/usb/storage/usb.h  2004-04-18 17:25:19.000000000 -0700
@@ -116,7 +116,7 @@
        struct us_data          *next;           /* next device */
 
        /* the device we're working with */
-       struct semaphore        dev_semaphore;   /* protect pusb_dev */
+       struct semaphore        dev_semaphore;   /* protect many things */
        struct usb_device       *pusb_dev;       /* this usb_device */
 
        unsigned int            flags;           /* from filter initially */
@@ -162,7 +162,6 @@
        atomic_t                ip_wanted[1];    /* is an IRQ expected?  */
 
        /* interrupt communications data */
-       struct semaphore        irq_urb_sem;     /* to protect irq_urb   */
        struct urb              *irq_urb;        /* for USB int requests */
        unsigned char           irqbuf[2];       /* buffer for USB IRQ   */
        unsigned char           irqdata[2];      /* data from USB IRQ    */


-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to