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]