RHL9/FC1 USB storage 3 (110872)

Pete Zaitcev zaitcev at redhat.com
Tue Dec 16 22:08:06 UTC 2003


This was prompted by an IHV who shipped a lot of USB storage
attached to SMPs and is mad as hell that it doesn't work.
Ask ootpa about the fireworks :-)

I am guilty somewhat here. When I and Arjan fixed the last hoopla
with USB CD-ROM on Bladecenters & Dells, we were so distraught
by general misdesign of the code that we didn't go far enough.

It is not in upstream, although it seems clear like day to me.
In fact, I ask you to take it regardless of Matt Dharm's approval.

-- Pete

diff -urN -X dontdiff linux-2.4.22-1.2130.nptl/drivers/usb/storage/scsiglue.c linux-2.4.22-1.2130.nptl-usbstor3/drivers/usb/storage/scsiglue.c
--- linux-2.4.22-1.2130.nptl/drivers/usb/storage/scsiglue.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-1.2130.nptl-usbstor3/drivers/usb/storage/scsiglue.c	2003-12-16 14:04:15.000000000 -0800
@@ -213,9 +213,20 @@
 static int device_reset( Scsi_Cmnd *srb )
 {
 	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+	int rc;
 
 	US_DEBUGP("device_reset() called\n" );
-	return us->transport_reset(us);
+	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;
 }
 
 /* This resets the device port, and simulates the device
@@ -230,27 +241,32 @@
 	/* 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);
-
 	/* 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
@@ -281,17 +297,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.22-1.2130.nptl/drivers/usb/storage/usb.c linux-2.4.22-1.2130.nptl-usbstor3/drivers/usb/storage/usb.c
--- linux-2.4.22-1.2130.nptl/drivers/usb/storage/usb.c	2003-12-08 15:50:01.000000000 -0800
+++ linux-2.4.22-1.2130.nptl-usbstor3/drivers/usb/storage/usb.c	2003-12-16 14:01:41.000000000 -0800
@@ -513,6 +513,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)
 {
@@ -522,13 +525,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;
 	}
@@ -549,12 +548,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;
 }
 
@@ -782,7 +778,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));
 
@@ -1079,7 +1074,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);
@@ -1087,7 +1081,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.22-1.2130.nptl/drivers/usb/storage/usb.h linux-2.4.22-1.2130.nptl-usbstor3/drivers/usb/storage/usb.h
--- linux-2.4.22-1.2130.nptl/drivers/usb/storage/usb.h	2003-12-08 15:50:01.000000000 -0800
+++ linux-2.4.22-1.2130.nptl-usbstor3/drivers/usb/storage/usb.h	2003-12-16 14:01:41.000000000 -0800
@@ -118,7 +118,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 */
@@ -164,7 +164,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	 */





More information about the devel mailing list