Hi!

Fortunately for us, disconnect can only happen inside usb_*_msg() or
when we are sleeping [am I right?], so we need no spinlocks. (And,
actually, spinlock usage was seriously broken: you may _not_ sleep
while holding spinlock!

It contains _lots_ of cleanups. I tried to make code shorter, which
means longer lines, sometimes; but I also killed some code duplication
etc. I hope I did not break anything.

Here is my diff against 2.3.99-pre3 (I can not easily generate diff
against CURRENT). Could you please take a look, rediff, and submit it
to randy if it looks fine? [Or mail me your current version, and I'll
do rediffing myself.]
                                                                Pavel

--- clean/drivers/usb/usb-storage.c     Sat Mar 25 22:47:36 2000
+++ linux/drivers/usb/usb-storage.c     Sat Apr  1 23:06:49 2000
@@ -1,7 +1,10 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * (c) 1999 Michael Gee ([EMAIL PROTECTED])
- * (c) 1999, 2000 Matthew Dharm ([EMAIL PROTECTED])
+ * Copyright 1999 Michael Gee <[EMAIL PROTECTED]>
+ * Copyright 1999, 2000 Matthew Dharm <[EMAIL PROTECTED]>
+ * Copyright 2000 Pavel Machek <[EMAIL PROTECTED]>
+ *
+ * Distribute under GPL version 2 or later, as in file ../../COPYING.
  *
  * This driver is based on the 'USB Mass Storage Class' document. This
  * describes in detail the protocol used to communicate with such
@@ -39,14 +42,6 @@
 #include "usb-storage.h"
 #include "usb-storage-debug.h"
 
-/*
- * This is the size of the structure Scsi_Host_Template.  We create
- * an instance of this structure in this file and this is a check
- * to see if this structure may have changed within the SCSI module.
- * This is by no means foolproof, but it does help us some.
- */
-#define SCSI_HOST_TEMPLATE_SIZE                        (104)
-
 /* direction table -- this indicates the direction of the data
  * transfer for each command code -- a 1 indicates input
  */
@@ -61,22 +56,19 @@
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
+static int my_host_number = 0;
+
 /*
  * Per device data
  */
 
-static int my_host_number;
-
-struct us_data;
-
-typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
-typedef int (*trans_reset)(struct us_data*);
-typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
-
 /* we allocate one of these for every device that we remember */
 struct us_data {
        struct us_data          *next;           /* next device */
+
+       /* the device we're working with */
        struct usb_device       *pusb_dev;       /* this usb_device */
+
        unsigned int            flags;           /* from filter initially */
 
        /* information about the device -- only good if device is attached */
@@ -88,9 +80,11 @@
        __u8                    protocol;
 
        /* function pointers for this device */
-       trans_cmnd              transport;       /* transport function */
-       trans_reset             transport_reset; /* transport device reset */
-       proto_cmnd              proto_handler;   /* protocol handler */
+       int                     (*transport)(Scsi_Cmnd*, struct us_data*);      /* 
+transport function */
+       char                    *transport_name;
+       int                     (*transport_reset)(struct us_data*);            /* 
+transport device reset */
+       int                     (*proto_handler)(Scsi_Cmnd*, struct us_data*);  /* 
+protocol handler */
+       char                    *proto_name;
 
        /* SCSI interfaces */
        GUID(guid);                              /* unique dev id */
@@ -131,16 +125,7 @@
 
 /* The list of structures and the protective lock for them */
 static struct us_data *us_list;
-spinlock_t us_list_spinlock = SPIN_LOCK_UNLOCKED;
-
-static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
-static void storage_disconnect(struct usb_device *dev, void *ptr);
-static struct usb_driver storage_driver = {
-       "usb-storage",
-       storage_probe,
-       storage_disconnect,
-       { NULL, NULL }
-};
+static struct semaphore us_list_sem;
 
 /***********************************************************************
  * Data transfer routines
@@ -178,16 +163,14 @@
        }
 
        /* did we send all the data? */
-       if (partial == length) {
+       if (partial == length)
                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 allready */
-               if (result == -ETIMEDOUT) {
+               if (result == -ETIMEDOUT)
                        US_DEBUGP("us_bulk_transfer: device NAKed\n");
-               }
                return US_BULK_TRANSFER_FAILED;
        }
 
@@ -214,6 +197,10 @@
 
        /* calculate the appropriate pipe information */
        us = (struct us_data*) srb->host_scribble;
+       if (!us->pusb_dev) {
+               printk( KERN_CRIT "Device killed in us_transfer?\n" );
+               return;
+       }
        if (dir_in)
                pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
        else
@@ -290,9 +277,48 @@
 
 /***********************************************************************
  * Protocol routines
+ *
+ * FIXME: protocol routines call transport routines, so they belong _after_
+ * them in source. I'll do the move once sources are a bit more stable.
  ***********************************************************************/
 
-static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
+/* Sense is common for all protocols? */
+void auto_sense(struct us_data *us)
+{
+       int temp_result;
+       void* old_request_buffer;
+       int old_sg;
+
+       US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+
+       memset(us->srb->cmnd, 0, 6);
+       us->srb->cmnd[0] = REQUEST_SENSE;
+       us->srb->cmnd[4] = 18;
+    
+       /* set the buffer length for transfer */
+       old_request_buffer = us->srb->request_buffer;
+       old_sg = us->srb->use_sg;
+       us->srb->request_bufflen = 18;
+       us->srb->request_buffer = us->srb->sense_buffer;
+
+       /* FIXME: what if this command fails? */
+       temp_result = us->transport(us->srb, us);
+       US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
+       US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+                 us->srb->sense_buffer[2] & 0xf,
+                 us->srb->sense_buffer[12], 
+                 us->srb->sense_buffer[13]);
+
+       /* set the result so the higher layers expect this data */
+       us->srb->result = CHECK_CONDITION;
+
+       /* we're done here */
+       us->srb->request_buffer = old_request_buffer;
+       us->srb->use_sg = old_sg;
+       return;
+}
+
+static void ATAPI_proto(Scsi_Cmnd *srb, struct us_data *us)
 {
        int old_cmnd = 0;
        int result;
@@ -351,6 +377,7 @@
   
        /* send the command to the transport layer */
        result = us->transport(srb, us);
+       US_DEBUGP("return code from transport is 0x%x\n", result);
 
        /* If we got a short transfer, but it was for a command that
         * can have short transfers, we're actually okay
@@ -368,42 +395,8 @@
         * If we have an error, we're going to do a 
         * REQUEST_SENSE automatically
         */
-       if (result != USB_STOR_TRANSPORT_GOOD) {
-               int temp_result;
-               void* old_request_buffer;
-               int old_sg;
-
-               US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
-               us->srb->cmnd[0] = REQUEST_SENSE;
-               us->srb->cmnd[1] = 0;
-               us->srb->cmnd[2] = 0;
-               us->srb->cmnd[3] = 0;
-               us->srb->cmnd[4] = 18;
-               us->srb->cmnd[5] = 0;
-    
-               /* set the buffer length for transfer */
-               old_request_buffer = us->srb->request_buffer;
-               old_sg = us->srb->use_sg;
-               us->srb->request_bufflen = 18;
-               us->srb->request_buffer = us->srb->sense_buffer;
-
-               /* FIXME: what if this command fails? */
-               temp_result = us->transport(us->srb, us);
-               US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
-               US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-                         us->srb->sense_buffer[2] & 0xf,
-                         us->srb->sense_buffer[12], 
-                         us->srb->sense_buffer[13]);
-
-               /* set the result so the higher layers expect this data */
-               us->srb->result = CHECK_CONDITION;
-
-               /* we're done here */
-               us->srb->request_buffer = old_request_buffer;
-               us->srb->use_sg = old_sg;
-               return;
-       }
+       if (result != USB_STOR_TRANSPORT_GOOD)
+               auto_sense(us);
   
        /* Fix the MODE_SENSE data if we translated the command
         */
@@ -430,7 +423,7 @@
 }
 
 
-static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
+static void ufi_proto(Scsi_Cmnd *srb, struct us_data *us)
 {
        int old_cmnd = 0;
        int result;
@@ -462,14 +455,8 @@
                srb->cmnd[11] = 0;
                srb->cmnd[10] = 0;
                srb->cmnd[9] = 0;
-
-               /* if we're sending data, we send all.  If getting data, 
-                * get the minimum */
-               if (srb->cmnd[0] == MODE_SELECT)
-                       srb->cmnd[8] = srb->cmnd[4];
-               else
-                       srb->cmnd[8] = 8;
-
+               /* if we're sending data, we send all.  If getting data, get the 
+minimum */
+               srb->cmnd[8] = (srb->cmnd[0] == MODE_SELECT) ? srb->cmnd[4] : 8; 
                srb->cmnd[7] = 0;
                srb->cmnd[6] = 0;
                srb->cmnd[5] = 0;
@@ -529,42 +516,8 @@
         * If we have an error, we're going to do a 
         * REQUEST_SENSE automatically
         */
-       if (result != USB_STOR_TRANSPORT_GOOD) {
-               int temp_result;
-               void* old_request_buffer;
-               int old_sg;
-
-               US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
-               us->srb->cmnd[0] = REQUEST_SENSE;
-               us->srb->cmnd[1] = 0;
-               us->srb->cmnd[2] = 0;
-               us->srb->cmnd[3] = 0;
-               us->srb->cmnd[4] = 18;
-               us->srb->cmnd[5] = 0;
-    
-               /* set the buffer length for transfer */
-               old_request_buffer = us->srb->request_buffer;
-               old_sg = us->srb->use_sg;
-               us->srb->request_bufflen = 18;
-               us->srb->request_buffer = us->srb->sense_buffer;
-
-               /* FIXME: what if this command fails? */
-               temp_result = us->transport(us->srb, us);
-               US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
-               US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-                         us->srb->sense_buffer[2] & 0xf,
-                         us->srb->sense_buffer[12], 
-                         us->srb->sense_buffer[13]);
-
-               /* set the result so the higher layers expect this data */
-               us->srb->result = CHECK_CONDITION;
-
-               /* we're done here */
-               us->srb->request_buffer = old_request_buffer;
-               us->srb->use_sg = old_sg;
-               return;
-       }
+       if (result != USB_STOR_TRANSPORT_GOOD)
+               auto_sense(us);
   
        /* Fix the MODE_SENSE data here if we had to translate the command
         */
@@ -590,7 +543,7 @@
        }
 }
 
-static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
+static void scsi_proto(Scsi_Cmnd *srb, struct us_data *us)
 {
        unsigned int result = 0;
 
@@ -674,43 +627,8 @@
 
        /* if we have an error, we're going to do a REQUEST_SENSE 
         * automatically */
-       if (result != USB_STOR_TRANSPORT_GOOD) {
-               int temp_result;
-               int old_sg;
-               void* old_request_buffer;
-
-               US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
-
-               /* set up the REQUEST_SENSE command and parameters */
-               us->srb->cmnd[0] = REQUEST_SENSE;
-               us->srb->cmnd[1] = 0;
-               us->srb->cmnd[2] = 0;
-               us->srb->cmnd[3] = 0;
-               us->srb->cmnd[4] = 18;
-               us->srb->cmnd[5] = 0;
-    
-               /* set the buffer length for transfer */
-               old_request_buffer = us->srb->request_buffer;
-               old_sg = us->srb->use_sg;
-               us->srb->request_bufflen = 18;
-               us->srb->request_buffer = us->srb->sense_buffer;
-
-               /* FIXME: what if this command fails? */
-               temp_result = us->transport(us->srb, us);
-               US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
-               US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
-                         us->srb->sense_buffer[2] & 0xf,
-                         us->srb->sense_buffer[12], 
-                         us->srb->sense_buffer[13]);
-
-               /* set the result so the higher layers expect this data */
-               us->srb->result = CHECK_CONDITION;
-
-               /* we're done here */
-               us->srb->use_sg = old_sg;
-               us->srb->request_buffer = old_request_buffer;
-               return;
-       }
+       if (result != USB_STOR_TRANSPORT_GOOD)
+               auto_sense(us);
 
        /* fix the results of an INQUIRY */
        if (us->srb->cmnd[0] == INQUIRY) {
@@ -770,11 +688,12 @@
        /* long wait for reset */
        schedule_timeout(HZ*6);
 
+       if (!us->pusb_dev)
+               return -EPERM;
+
        US_DEBUGP("CB_reset: clearing endpoint halt\n");
-       usb_clear_halt(us->pusb_dev, 
-                      usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-       usb_clear_halt(us->pusb_dev, 
-                      usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+       usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+       usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
 
        US_DEBUGP("CB_reset done\n");
        return 0;
@@ -802,11 +721,13 @@
        if (result < 0) {
                /* a stall is a fatal condition from the device */
                if (result == -EPIPE) {
-                       US_DEBUGP("-- Stall on control pipe. Clearing\n");
-                       US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
-                                 usb_clear_halt(us->pusb_dev, 
-                                                usb_sndctrlpipe(us->pusb_dev,
-                                                                0)));
+                       int res;
+                       printk (KERN_ERR USB_STORAGE "Got stall on control pipe from 
+CBI device\n" );
+                       if (us->pusb_dev)
+                               res = usb_clear_halt(us->pusb_dev, 
+usb_sndctrlpipe(us->pusb_dev, 0));
+                       else
+                               res = -EPERM;
+                       US_DEBUGP("-- Return from usb_clear_halt() is %d\n", res);
                        return USB_STOR_TRANSPORT_ERROR;
                }
 
@@ -821,7 +742,7 @@
        /* transfer the data payload for this command, if one exists*/
        if (us_transfer_length(srb)) {
                us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-               US_DEBUGP("CBI data stage result is 0x%x\n", result);
+               US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
        }
 
        /* STATUS STAGE */
@@ -840,8 +761,10 @@
        
        /* UFI gives us ASC and ASCQ, like a request sense
         *
-        * REQUEST_SENSE and INQUIRY don't affect the sense data, so we
-        * ignore the information for those commands
+        * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
+        * devices, so we ignore the information for those commands.  Note
+        * that this means we could be ignoring a real error on these
+        * commands, but that can't be helped.
         */
        if (us->subclass == US_SC_UFI) {
                if (srb->cmnd[0] == REQUEST_SENSE ||
@@ -854,11 +777,14 @@
                                return USB_STOR_TRANSPORT_GOOD;
        }
        
-       /* otherwise, we interpret the data normally */
-       switch (us->ip_data) {
-       case 0x0001: 
+       /* If not UFI, we interpret the data as a result code 
+        * The first byte should always be a 0x0
+        * The second byte & 0x0F should be 0x0 for good, otherwise error 
+        */
+       switch ((us->ip_data & 0xFF0F)) {
+       case 0x0000: 
                return USB_STOR_TRANSPORT_GOOD;
-       case 0x0002: 
+       case 0x0001: 
                return USB_STOR_TRANSPORT_FAILED;
        default: 
                return USB_STOR_TRANSPORT_ERROR;
@@ -876,7 +802,7 @@
        int result;
        __u8 status[2];
 
-       US_DEBUGP("CBC gets a command:\n");
+       US_DEBUGP("CB gets a command:\n");
        US_DEBUG(us_show_command(srb));
 
        /* COMMAND STAGE */
@@ -892,11 +818,13 @@
 
                /* a stall is a fatal condition from the device */
                if (result == -EPIPE) {
-                       US_DEBUGP("-- Stall on control pipe. Clearing\n");
-                       US_DEBUGP("-- Return from usb_clear_halt() is %d\n",
-                                 usb_clear_halt(us->pusb_dev, 
-                                                usb_sndctrlpipe(us->pusb_dev,
-                                                                0)));
+                       int res;
+                       printk (KERN_ERR USB_STORAGE "Got stall on control pipe from 
+CBI device\n" );
+                       if (us->pusb_dev)
+                               res = usb_clear_halt(us->pusb_dev, 
+usb_sndctrlpipe(us->pusb_dev, 0));
+                       else
+                               res = -EPERM;
+                       US_DEBUGP("-- Return from usb_clear_halt() is %d\n", res);
                        return USB_STOR_TRANSPORT_ERROR;
                }
 
@@ -908,9 +836,11 @@
        /* transfer the data payload for this command, if one exists*/
        if (us_transfer_length(srb)) {
                us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-               US_DEBUGP("CBC data stage result is 0x%x\n", result);
+               US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
        }
        
+       if (!us->pusb_dev)
+               return USB_STOR_TRANSPORT_ERROR;
        
        /* STATUS STAGE */
        /* FIXME: this is wrong */
@@ -941,6 +871,8 @@
 {
        int result;
 
+       if (!us->pusb_dev) 
+               return -EPERM;
        result = usb_control_msg(us->pusb_dev, 
                                 usb_sndctrlpipe(us->pusb_dev,0), 
                                 US_BULK_RESET, 
@@ -950,10 +882,10 @@
        if (result < 0)
                US_DEBUGP("Bulk hard reset failed %d\n", result);
 
-       usb_clear_halt(us->pusb_dev, 
-                      usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-       usb_clear_halt(us->pusb_dev, 
-                      usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+       if (!us->pusb_dev) 
+               return -EPERM;
+       usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+       usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out));
 
        /* long wait for reset */
        schedule_timeout(HZ*6);
@@ -979,7 +911,7 @@
        bcb.Tag = srb->serial_number;
        bcb.Lun = 0;
        bcb.Length = srb->cmd_len;
-       
+
        /* construct the pipe handle */
        pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
        
@@ -991,6 +923,7 @@
        US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n",
                  bcb.Signature, bcb.Tag, bcb.DataTransferLength,
                  bcb.Flags, bcb.Length);
+
        result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
                              US_BULK_CB_WRAP_LEN, &partial, HZ*5);
        US_DEBUGP("Bulk command transfer result=%d\n", result);
@@ -1014,6 +947,9 @@
        /* See flow chart on pg 15 of the Bulk Only Transport spec for
         * an explanation of how this code works.
         */
+
+       if (!us->pusb_dev)
+               return USB_STOR_TRANSPORT_ERROR;
        
        /* construct the pipe handle */
        pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
@@ -1077,19 +1013,24 @@
  * Host functions 
  ***********************************************************************/
 
+static const char* us_info(struct Scsi_Host *host)
+{
+       return "SCSI emulation for USB Mass Storage devices\n";
+}
+
 /* detect adapter (always true ) */
 static int us_detect(struct SHT *sht)
 {
        /* FIXME - not nice at all, but how else ? */
        struct us_data *us = (struct us_data *)sht->proc_dir;
-       char name[32];
+       char local_name[32];
 
-       /* set up our name */
-       sprintf(name, "usbscsi%d", us->host_number);
-       sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL);
+       /* set up the name of our subdirectory under /proc/scsi/ */
+       sprintf(local_name, "usb-storage-%d", us->host_number);
+       sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
        if (!sht->proc_name)
                return 0;
-       strcpy(sht->proc_name, name);
+       strcpy(sht->proc_name, local_name);
 
        /* we start with no /proc directory entry */
        sht->proc_dir = NULL;
@@ -1105,25 +1046,23 @@
        /* odd... didn't register properly.  Abort and free pointers */
        kfree(sht->proc_name);
        sht->proc_name = NULL;
-       sht->name = NULL;
        return 0;
 }
 
-/* release - must be here to stop scsi
- *     from trying to release IRQ etc.
- *     Kill off our data
+/* Release all resources used by the virtual host
+ *
+ * NOTE: There is no contention here, because we're allready deregistered
+ * the driver and we're doing each virtual host in turn, not in parallel
  */
 static int us_release(struct Scsi_Host *psh)
 {
        struct us_data *us = (struct us_data *)psh->hostdata[0];
-       unsigned long flags;
        int result;
 
-       /* lock the data structures */
-       spin_lock_irqsave(&us_list_spinlock, flags);
-
        US_DEBUGP("us_release() called for host %s\n", us->htmplt.name);
 
+       /* FIXME: I don't think this is necessary, becuase we've allready
+        * deregistered, which causes us to disconnect() */
        /* release the interrupt handler, if necessary */
        if (us->irq_handle) {
                US_DEBUGP("-- releasing irq\n");
@@ -1133,9 +1072,6 @@
                us->irq_handle = NULL;
        }
 
-       /* lock the data structures */
-       spin_unlock_irqrestore(&us_list_spinlock, flags);
-
        /* we always have a successful release */
        return 0;
 }
@@ -1168,12 +1104,15 @@
        up(&(us->queue_exclusion));
        up(&(us->sleeper));
 
+       /* FIXME: when we may sleep here (we may) why don't we just do everything here 
+and require kernel thread? */
+
        return 0;
 }
 
 /* FIXME: This doesn't actually abort anything */
 static int us_abort( Scsi_Cmnd *srb )
 {
+       printk(KERN_CRIT "usb-storage: abort() requested but not implemented\n" );
        return 0;
 }
 
@@ -1182,6 +1121,7 @@
 {
        struct us_data *us = (struct us_data *)srb->host->hostdata[0];
 
+       printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
        US_DEBUGP("Bus reset requested\n");
        if (us->ip_wanted)
                up(&(us->ip_waitq));
@@ -1192,6 +1132,7 @@
 /* FIXME: This doesn't actually reset anything */
 static int us_host_reset( Scsi_Cmnd *srb )
 {
+       printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
        return 0;
 }
 
@@ -1216,7 +1157,7 @@
                return length;
 
        /* lock the data structures */
-       spin_lock_irqsave(&us_list_spinlock, flags);
+       down(&us_list_sem);
 
        /* find our data from hostno */
        us = us_list;
@@ -1228,7 +1169,7 @@
 
        /* if we couldn't find it, we return an error */
        if (!us) {
-               spin_unlock_irqrestore(&us_list_spinlock, flags);
+               up(&us_list_sem);
                return -ESRCH;
        }
        
@@ -1238,47 +1179,25 @@
        /* print product and vendor strings */
        tmp_ptr = kmalloc(256, GFP_KERNEL);
        if (!us->pusb_dev || !tmp_ptr) {
-               SPRINTF("    Vendor: Unknown Vendor\n");
-               SPRINTF("   Product: Unknown Product\n");
+               SPRINTF("     Error: Out of memory or device removed at this point\n");
        } else {
                SPRINTF("    Vendor: ");
                if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, 
tmp_ptr, 256) > 0)
                        SPRINTF("%s\n", tmp_ptr);
-               else
-                       SPRINTF("Unknown Vendor\n");
+               else    SPRINTF("Unknown Vendor\n");
     
                SPRINTF("   Product: ");
                if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, 
tmp_ptr, 256) > 0)
                        SPRINTF("%s\n", tmp_ptr);
-               else
-                       SPRINTF("Unknown Product\n");
+               else    SPRINTF("Unknown Product\n");
                kfree(tmp_ptr);
        }
 
-       SPRINTF("  Protocol: ");
-       switch (us->protocol) {
-       case US_PR_CB:
-               SPRINTF("Control/Bulk\n");
-               break;
-    
-       case US_PR_CBI:
-               SPRINTF("Control/Bulk/Interrupt\n");
-               break;
-    
-       case US_PR_BULK:
-               SPRINTF("Bulk only\n");
-               break;
-    
-       default:
-               SPRINTF("Unknown Protocol\n");
-               break;
-       }
-
-       /* show the GUID of the device */
+       SPRINTF(" Transport: %s\n", us->transport_name);
+       SPRINTF("  Protocol: %s\n", us->proto_name);
        SPRINTF("      GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
 
-       /* release our lock on the data structures */
-       spin_unlock_irqrestore(&us_list_spinlock, flags);
+       up(&us_list_sem);
 
        /*
         * Calculate start of next buffer, and return value.
@@ -1298,75 +1217,91 @@
  */
 
 static Scsi_Host_Template my_host_template = {
-       NULL,                       /* next */
-       NULL,                       /* module */
-       NULL,                       /* proc_dir */
-       usb_stor_proc_info,
-       NULL,                       /* name - points to unique */
-       us_detect,
-       us_release,
-       NULL,                       /* info */
-       NULL,                       /* ioctl */
-       us_command,
-       us_queuecommand,
-       NULL,                       /* eh_strategy */
-       us_abort,
-       us_bus_reset,
-       us_bus_reset,
-       us_host_reset,
-       NULL,                       /* abort */
-       NULL,                       /* reset */
-       NULL,                       /* slave_attach */
-       NULL,                       /* bios_param */
-       NULL,                       /* select_queue_depths */
-       1,                          /* can_queue */
-       -1,                         /* this_id */
-       SG_ALL,                     /* sg_tablesize */
-       1,                          /* cmd_per_lun */
-       0,                          /* present */
-       FALSE,                      /* unchecked_isa_dma */
-       TRUE,                       /* use_clustering */
-       TRUE,                       /* use_new_eh_code */
-       TRUE                        /* emulated */
+       proc_info:      usb_stor_proc_info,
+       detect:         us_detect,
+       release:        us_release,
+       command:        us_command,
+       queuecommand:   us_queuecommand,
+
+       eh_abort_handler:       us_abort,
+       eh_device_reset_handler:us_bus_reset,
+       eh_bus_reset_handler:   us_bus_reset,
+       eh_host_reset_handler:  us_host_reset,
+
+       can_queue:      1,
+       this_id:        -1,
+
+       sg_tablesize:      SG_ALL,
+       cmd_per_lun:       1,
+       present:           0,
+       unchecked_isa_dma: FALSE,
+       use_clustering:    TRUE,
+       use_new_eh_code:   TRUE,
+       emulated:          TRUE,
 };
 
 static unsigned char sense_notready[] = {
-       0x70,                       /* current error */
-       0x00,
-       0x02,                       /* not ready */
-       0x00,
-       0x00,
-       0x0a,                       /* additional length */
-       0x00,
-       0x00,
-       0x00,
-       0x00,
-       0x04,                       /* not ready */
-       0x03,                       /* manual intervention */
-       0x00,
-       0x00,
-       0x00,
-       0x00
+       /* 0: current error */     0x70, 0x00, 
+        /* 2: not ready */         0x02, 0x00, 0x00,
+        /* 5: additional length */ 0x0a, 0x00, 0x00, 0x00, 0x00,
+       /* 10:not ready */         0x04,
+       /* 11:manual intervention*/0x03, 0x00, 0x00, 0x00, 0x00
 };
 
+static void stor_act_command(struct us_data *us)
+{
+       unsigned long flags;
+
+       /* our device has gone - pretend not ready */
+       /* FIXME: we also need to handle INQUIRY here, probably */
+       /* FIXME: fix return codes and sense buffer handling */
+
+       if (!us->pusb_dev) {
+               US_DEBUGP("Request is for removed device\n");
+               if (us->srb->cmnd[0] == REQUEST_SENSE) {
+                       memcpy(us->srb->request_buffer, sense_notready, 
+sizeof(sense_notready));
+                       us->srb->result = DID_OK << 16;
+               } else {
+                       us->srb->result = (DID_OK << 16) | 2;
+               }
+
+               /* indicate that the command is done */
+               us->srb->scsi_done(us->srb);
+               us->srb = NULL;
+               return;
+       }
+
+       /* we've got a command, let's do it! */
+       US_DEBUG(us_show_command(us->srb));
+
+       /* FIXME: this is to support Shuttle E-USB bridges, it  appears */
+       if (us->srb->cmnd[0] == START_STOP &&
+           us->pusb_dev->descriptor.idProduct == 0x0001 &&
+           us->pusb_dev->descriptor.idVendor == 0x04e6)
+               us->srb->result = DID_OK << 16;
+       else {
+               us->proto_handler(us->srb, us);
+       }
+
+       US_DEBUGP("scsi cmd done, result=0x%x\n", 
+                 us->srb->result);
+
+       /* indicate that the command is done */
+       us->srb->scsi_done(us->srb);
+       us->srb = NULL;
+}
+
 static int usb_stor_control_thread(void * __us)
 {
        struct us_data *us = (struct us_data *)__us;
        int action;
 
        lock_kernel();
-
-       /*
-        * This thread doesn't need any user-level access,
-        * so get rid of all our resources..
-        */
-       daemonize();
-
-       sprintf(current->comm, "usbscsi%d", us->host_number);
-
+       daemonize(); /* We need no user-level access */
+       sprintf(current->comm, "usb-storage-%d", us->host_number);
        unlock_kernel();
 
-       up(&(us->notify));
+       up(&(us->notify));      /* signal that we've started the thread */
 
        for(;;) {
                US_DEBUGP("*** thread sleeping.\n");
@@ -1399,43 +1334,7 @@
                                break;
                        }
 
-                       /* our device has gone - pretend not ready */
-                       /* FIXME: we also need to handle INQUIRY here, 
-                        * probably */
-                       /* FIXME: fix return codes and sense buffer handling */
-                       if (!us->pusb_dev) {
-                               US_DEBUGP("Request is for removed device\n");
-                               if (us->srb->cmnd[0] == REQUEST_SENSE) {
-                                       memcpy(us->srb->request_buffer, 
-                                              sense_notready, 
-                                              sizeof(sense_notready));
-                                       us->srb->result = DID_OK << 16;
-                               } else {
-                                       us->srb->result = (DID_OK << 16) | 2;
-                               }
-
-                               us->srb->scsi_done(us->srb);
-                               us->srb = NULL;
-                               break;
-                       }
-
-                       /* we've got a command, let's do it! */
-                       US_DEBUG(us_show_command(us->srb));
-
-                       /* FIXME: this is to support Shuttle E-USB bridges, it 
-                        * appears */
-                       if (us->srb->cmnd[0] == START_STOP &&
-                           us->pusb_dev->descriptor.idProduct == 0x0001 &&
-                           us->pusb_dev->descriptor.idVendor == 0x04e6)
-                               us->srb->result = DID_OK << 16;
-                       else {
-                               us->proto_handler(us->srb, us);
-                       }
-      
-                       US_DEBUGP("scsi cmd done, result=0x%x\n", 
-                                 us->srb->result);
-                       us->srb->scsi_done(us->srb);
-                       us->srb = NULL;
+                       stor_act_command(us);
                        break;
       
                case US_ACT_ABORT:
@@ -1453,11 +1352,15 @@
                } /* end switch on action */
 
                /* exit if we get a signal to exit */
-               if (action == US_ACT_EXIT)
+               if (action == US_ACT_EXIT) {
+                       US_DEBUGP("-- US_ACT_EXIT command recieved\n");
                        break;
+               }
        } /* for (;;) */
   
-       printk("usb_stor_control_thread exiting\n");
+       /* notify the exit routine that we're actually exiting now */
+       up(&(us->notify));
+
        return 0;
 }      
 
@@ -1518,6 +1421,7 @@
            dev->descriptor.idProduct == 0x0001) {
                __u8 qstat[2];
                
+               if (!ss->pusb_dev) return NULL;
                result = usb_control_msg(ss->pusb_dev, 
                                         usb_rcvctrlpipe(dev,0),
                                         1, 0xC0,
@@ -1525,6 +1429,7 @@
                                         qstat, 2, HZ*5);
                US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
                init_MUTEX_LOCKED(&(ss->ip_waitq));
+               if (!ss->pusb_dev) return NULL;
                ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
                result = usb_request_irq(ss->pusb_dev, ss->irqpipe, 
                                         CBI_irq, 255, (void *)ss, 
@@ -1592,14 +1497,11 @@
        memset(prod, 0, sizeof(prod));
        memset(serial, 0, sizeof(serial));
        if (dev->descriptor.iManufacturer)
-               usb_string(dev, dev->descriptor.iManufacturer, mf, 
-                          sizeof(mf));
+               usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf));
        if (dev->descriptor.iProduct)
-               usb_string(dev, dev->descriptor.iProduct, prod, 
-                          sizeof(prod));
+               usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod));
        if (dev->descriptor.iSerialNumber)
-               usb_string(dev, dev->descriptor.iSerialNumber, serial, 
-                          sizeof(serial));
+               usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial));
        
        /* Create a GUID for this device */
        if (dev->descriptor.iSerialNumber && serial[0]) {
@@ -1613,7 +1515,7 @@
        }
 
        /* lock access to the data structures */
-       spin_lock_irqsave(&us_list_spinlock, flags);
+       down(&us_list_sem); /* I hope probe routine may block */
 
        /*
         * Now check if we have seen this GUID before
@@ -1654,8 +1556,8 @@
        
                if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data), 
                                                    GFP_KERNEL)) == NULL) {
-                       printk(KERN_WARNING USB_STORAGE "Out of memory\n");
-                       spin_unlock_irqrestore(&us_list_spinlock, flags);
+                       printk(KERN_ERR USB_STORAGE "Out of memory\n");
+                       up(&us_list_sem);
                        return NULL;
                }
                memset(ss, 0, sizeof(struct us_data));
@@ -1685,67 +1587,32 @@
                 * Set the handler pointers based on the protocol
                 * Again, this data is persistant across reattachments
                 */
-               US_DEBUGP("Transport: ");
                switch (ss->protocol) {
-               case US_PR_CB:
-                       US_DEBUGPX("Control/Bulk\n");
-                       ss->transport = CB_transport;
-                       ss->transport_reset = CB_reset;
-                       break;
-                       
-               case US_PR_CBI:
-                       US_DEBUGPX("Control/Bulk/Interrupt\n");
-                       ss->transport = CBI_transport;
-                       ss->transport_reset = CB_reset;
-                       break;
-                       
-               case US_PR_BULK:
-                       US_DEBUGPX("Bulk\n");
-                       ss->transport = Bulk_transport;
-                       ss->transport_reset = Bulk_reset;
-                       break;
-                       
-               default:
-                       US_DEBUGPX("Unknown\n");    
-                       kfree(ss);
-                       return NULL;
-                       break;
+               case US_PR_CB: ss->transport_name = "Control/Bulk"; 
+                       ss->transport = CB_transport;  ss->transport_reset = CB_reset; 
+break;
+               case US_PR_CBI: ss->transport_name = "Control/Bulk/Interrupt";
+                       ss->transport = CBI_transport; ss->transport_reset = CB_reset; 
+break;
+               case US_PR_BULK: ss->transport_name = "Bulk only";
+                       ss->transport = Bulk_transport;ss->transport_reset = 
+Bulk_reset; break;
+               default: ss->transport_name = "Unknown";
+                       ss->transport = NULL;
                }
+               printk(KERN_INFO "Transport: %s\n", ss->transport_name);
 
-               US_DEBUGP("Protocol: ");
                switch (ss->subclass) {
-               case US_SC_RBC:
-                       US_DEBUGPX("Reduced Block Commands (RBC)\n");
-                       ss->proto_handler = transparent_scsi_command;
-                       break;
-
-               case US_SC_8020:
-                       US_DEBUGPX("8020i\n");
-                       ss->proto_handler = ATAPI_command;
-                       break;
-
-               case US_SC_QIC:
-                       US_DEBUGPX("QIC157\n");
-                       break;
-
-               case US_SC_8070:
-                       US_DEBUGPX("8070i\n");
-                       ss->proto_handler = ATAPI_command;
-                       break;
-
-               case US_SC_SCSI:
-                       US_DEBUGPX("Transparent SCSI\n");
-                       ss->proto_handler = transparent_scsi_command;
-                       break;
-
-               case US_SC_UFI:
-                       US_DEBUGPX("UFI\n");
-                       ss->proto_handler = ufi_command;
-                       break;
-
-               default:
-                       US_DEBUGPX("Unknown\n");
-                       break;
+               case US_SC_RBC:  ss->proto_name="Reduced Block Commands"; 
+ss->proto_handler = scsi_proto;  break;
+               case US_SC_8020: ss->proto_name="8020i";                  
+ss->proto_handler = ATAPI_proto; break;
+               case US_SC_QIC:  ss->proto_name="QIC157";                 
+ss->proto_handler = NULL;        break;
+               case US_SC_8070: ss->proto_name="8070i";                  
+ss->proto_handler = ATAPI_proto; break;
+               case US_SC_SCSI: ss->proto_name="Transparent SCSI";       
+ss->proto_handler = scsi_proto;  break;
+               case US_SC_UFI:  ss->proto_name="UFI";                    
+ss->proto_handler = ufi_proto;   break;
+               default:         ss->proto_name="Unknown";                
+ss->proto_handler = NULL;        break;
+               }
+               printk(KERN_INFO "Protocol: %s\n", ss->proto_name);
+               if ((!ss->proto_handler) || (!ss->transport)) {
+                       printk( KERN_ERR USB_STORAGE "Unknown transport or 
+protocol!\n" );
+                       kfree(ss);
+                       return NULL;
                }
 
                if (ss->protocol == US_PR_CBI) {
@@ -1785,8 +1652,7 @@
                                        CLONE_FS | CLONE_FILES |
                                        CLONE_SIGHAND);
                if (ss->pid < 0) {
-                       printk(KERN_WARNING USB_STORAGE 
-                              "Unable to start control thread\n");
+                       printk(KERN_ERR USB_STORAGE "Unable to start control 
+thread\n");
                        kfree(ss);
                        return NULL;
                }
@@ -1795,7 +1661,7 @@
                down(&(ss->notify));
                        
                /* now register - our detect function will be called */
-               ss->htmplt.module = &__this_module;
+               ss->htmplt.module = THIS_MODULE;
                scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
                
                /* put us in the list */
@@ -1803,23 +1669,25 @@
                us_list = ss;
        }
 
-       /* release the data structure lock */
-       spin_unlock_irqrestore(&us_list_spinlock, flags);
+       up(&us_list_sem);
 
-       printk(KERN_DEBUG 
-              "WARNING: USB Mass Storage data integrity not assured\n");
-       printk(KERN_DEBUG 
-              "USB Mass Storage device found at %d\n", dev->devnum);
+       printk(KERN_DEBUG "WARNING: USB Mass Storage data integrity not assured\n");
+       printk(KERN_DEBUG "USB Mass Storage device found at %d\n", dev->devnum);
 
        /* return a pointer for the disconnect function */
        return ss;
 }
 
-/* Handle a disconnect event from the USB core */
+/* Handle a disconnect event from the USB core
+ *
+ * This can only happen why we are calling usb_control_msg() or
+ * similar, thus we don't need spinlocks.
+ */
 static void storage_disconnect(struct usb_device *dev, void *ptr)
 {
        struct us_data *ss = ptr;
        int result;
+       unsigned long flags;
 
        US_DEBUGP("storage_disconnect() called\n");
  
@@ -1842,6 +1710,12 @@
        ss->pusb_dev = NULL;
 }
 
+static struct usb_driver storage_driver = {
+       "usb-storage",
+       storage_probe,
+       storage_disconnect,
+       { NULL, NULL }
+};
 
 /***********************************************************************
  * Initialization and registration
@@ -1849,18 +1723,7 @@
 
 int __init usb_stor_init(void)
 {
-       /* 
-        * Check to see if the host template is a different size from
-        * what we're expected -- people have updated this in the past
-        * and forgotten about this driver.
-        */
-       if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
-               printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE bad\n");
-               printk(KERN_ERR 
-                      "usb-storage: expected %d bytes, got %d bytes\n", 
-                      SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
-               return -1 ;
-       }
+       init_MUTEX(&us_list_sem);
 
        /* register the driver, return -1 if error */
        if (usb_register(&storage_driver) < 0)
@@ -1877,32 +1740,59 @@
        static struct us_data *next;
        unsigned long flags;
        
+       US_DEBUGP("usb_stor_exit() called\n");
+
        /*
         * deregister the driver -- this eliminates races with probes and
         * disconnects 
         */
+       US_DEBUGP("-- calling usb_deregister()\n");
        usb_deregister(&storage_driver) ;
        
-       /* lock access to the data structures */
-       spin_lock_irqsave(&us_list_spinlock, flags);
-       
+       down(&us_list_sem);
+
        /* unregister all the virtual hosts */
        for (ptr = us_list; ptr != NULL; ptr = ptr->next)
+       {
+               US_DEBUGP("-- calling scsi_unregister_module()\n");
                scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
+       }
+       
+       /* Kill the control threads
+        *
+        * NOTE: there is no contention at this point, so full mutual 
+        * exclusion is not necessary
+        */
+       for (ptr = us_list; ptr != NULL; ptr = ptr->next)
+       {
+               US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
+
+               /* enqueue the command */
+               ptr->action = US_ACT_EXIT;
+               
+               /* wake up the process task */
+               up(&(ptr->sleeper));
+
+               /* wait for the task to confirm that it's exited */
+               down(&(ptr->notify));
+       }
        
-       /* kill the threads */
-       /* FIXME: we can do this by sending them a signal to die */
 
        /* free up the data structures */
        /* FIXME: we need to eliminate the host structure also */
+       US_DEBUGP("-- freeing data structures\n");
        while (ptr) {
+               /* free the directory name */
+               kfree(ptr->htmplt.proc_dir);
+
+               /* free the us_data structure */
                next = ptr->next;
                kfree(ptr);
                ptr = next;
        }
        
        /* unlock the data structures */
-       spin_unlock_irqrestore(&us_list_spinlock, flags);
+       up(&us_list_sem);
 }
 
 module_init(usb_stor_init) ;

-- 
I'm [EMAIL PROTECTED] "In my country we have almost anarchy and I don't care."
Panos Katsaloulis describing me w.r.t. patents me at [EMAIL PROTECTED]

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to