patch-2.3.99-pre4 linux/drivers/usb/usb-storage.c
Next file: linux/drivers/usb/usb-storage.h
Previous file: linux/drivers/usb/usb-ohci.c
Back to the patch index
Back to the overall index
- Lines: 1996
- Date:
Wed Apr 5 17:01:25 2000
- Orig file:
v2.3.99-pre3/linux/drivers/usb/usb-storage.c
- Orig date:
Mon Mar 27 08:08:28 2000
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c
@@ -27,7 +27,6 @@
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
-#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
@@ -39,14 +38,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
*/
@@ -76,7 +67,11 @@
/* 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 semaphore dev_semaphore; /* protect pusb_dev */
struct usb_device *pusb_dev; /* this usb_device */
+
unsigned int flags; /* from filter initially */
/* information about the device -- only good if device is attached */
@@ -113,7 +108,7 @@
unsigned int irqpipe; /* pipe for release_irq */
/* mutual exclusion structures */
- struct semaphore notify; /* wait for thread to begin */
+ struct semaphore notify; /* thread begin/end */
struct semaphore sleeper; /* to sleep on */
struct semaphore queue_exclusion; /* to protect data structs */
};
@@ -131,7 +126,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;
+struct semaphore us_list_semaphore;
static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
static void storage_disconnect(struct usb_device *dev, void *ptr);
@@ -249,547 +244,267 @@
{
int i;
unsigned int total = 0;
+ struct scatterlist *sg;
- /* always zero for some commands */
- switch (srb->cmnd[0]) {
- case SEEK_6:
- case SEEK_10:
- case REZERO_UNIT:
- case ALLOW_MEDIUM_REMOVAL:
- case START_STOP:
- case TEST_UNIT_READY:
- return 0;
-
- /* FIXME: these should be removed and tested */
- case REQUEST_SENSE:
- case INQUIRY:
- case MODE_SENSE:
- return srb->cmnd[4];
-
- /* FIXME: these should be removed and tested */
- case LOG_SENSE:
- case MODE_SENSE_10:
- return (srb->cmnd[7] << 8) + srb->cmnd[8];
-
- default:
- break;
- }
-
+ /* Are we going to scatter gather? */
if (srb->use_sg) {
- struct scatterlist *sg;
-
+ /* Add up the sizes of all the scatter-gather segments */
sg = (struct scatterlist *) srb->request_buffer;
- for (i = 0; i < srb->use_sg; i++) {
+ for (i = 0; i < srb->use_sg; i++)
total += sg[i].length;
- }
+
return total;
}
else
+ /* Just return the length of the buffer */
return srb->request_bufflen;
}
/***********************************************************************
- * Protocol routines
+ * Transport routines
***********************************************************************/
-static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
+/* Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and recieve the response.
+ */
+static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
{
- int old_cmnd = 0;
+ int need_auto_sense;
int result;
-
- /* Fix some commands -- this is a form of mode translation
- * ATAPI devices only accept 12 byte long commands
- *
- * NOTE: This only works because a Scsi_Cmnd struct field contains
- * a unsigned char cmnd[12], so we know we have storage available
- */
-
- /* set command length to 12 bytes */
- srb->cmd_len = 12;
-
- /* determine the correct (or minimum) data length for these commands */
- switch (us->srb->cmnd[0]) {
-
- /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
- case MODE_SENSE:
- case MODE_SELECT:
- /* save the command so we can tell what it was */
- old_cmnd = srb->cmnd[0];
-
- srb->cmnd[11] = 0;
- srb->cmnd[10] = 0;
- srb->cmnd[9] = 0;
- srb->cmnd[8] = srb->cmnd[4];
- srb->cmnd[7] = 0;
- srb->cmnd[6] = 0;
- srb->cmnd[5] = 0;
- srb->cmnd[4] = 0;
- srb->cmnd[3] = 0;
- srb->cmnd[2] = srb->cmnd[2];
- srb->cmnd[1] = srb->cmnd[1];
- srb->cmnd[0] = srb->cmnd[0] | 0x40;
- break;
- /* change READ_6/WRITE_6 to READ_10/WRITE_10, which
- * are ATAPI commands */
- case WRITE_6:
- case READ_6:
- srb->cmnd[11] = 0;
- srb->cmnd[10] = 0;
- srb->cmnd[9] = 0;
- srb->cmnd[8] = srb->cmnd[4];
- srb->cmnd[7] = 0;
- srb->cmnd[6] = 0;
- srb->cmnd[5] = srb->cmnd[3];
- srb->cmnd[4] = srb->cmnd[2];
- srb->cmnd[3] = srb->cmnd[1] & 0x1F;
- srb->cmnd[2] = 0;
- srb->cmnd[1] = srb->cmnd[1] & 0xE0;
- srb->cmnd[0] = srb->cmnd[0] | 0x20;
- break;
- } /* end switch on cmnd[0] */
-
/* send the command to the transport layer */
result = us->transport(srb, us);
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
+ /* Determine if we need to auto-sense
+ *
+ * I normally don't use a flag like this, but it's almost impossible
+ * to understand what's going on here if I don't.
*/
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
+ need_auto_sense = 0;
+
+ /*
+ * If we're running the CB transport, which is incapable
+ * of determining status on it's own, we need to auto-sense almost
+ * every time.
+ */
+ if (us->protocol == US_PR_CB) {
+ US_DEBUGP("-- CB transport device requiring auto-sense\n");
+ need_auto_sense = 1;
+
+ /* There are some exceptions to this. Notably, if this is
+ * a UFI device and the command is REQUEST_SENSE or INQUIRY,
+ * then it is impossible to truly determine status.
+ */
+ if (us->subclass == US_SC_UFI &&
+ ((srb->cmnd[0] == REQUEST_SENSE) ||
+ (srb->cmnd[0] == INQUIRY)))
+ need_auto_sense = 0;
+ }
+
+ /*
+ * If we have an error, we're going to do a REQUEST_SENSE
+ * automatically. Note that we differentiate between a command
+ * "failure" and an "error" in the transport mechanism.
+ */
+ if (result == USB_STOR_TRANSPORT_FAILED) {
+ US_DEBUGP("-- transport indicates command failure\n");
+ need_auto_sense = 1;
+ }
+ if (result == USB_STOR_TRANSPORT_ERROR) {
+ /* FIXME: we need to invoke a transport reset here */
+ US_DEBUGP("-- transport indicates transport failure\n");
+ need_auto_sense = 0;
+ srb->result = DID_ERROR << 16;
+ return;
}
/*
- * If we have an error, we're going to do a
- * REQUEST_SENSE automatically
+ * Also, if we have a short transfer on a command that can't have
+ * a short transfer, we're going to do this.
*/
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if ((srb->result == US_BULK_TRANSFER_SHORT) &&
+ !((srb->cmnd[0] == REQUEST_SENSE) ||
+ (srb->cmnd[0] == INQUIRY) ||
+ (srb->cmnd[0] == MODE_SENSE) ||
+ (srb->cmnd[0] == LOG_SENSE) ||
+ (srb->cmnd[0] == MODE_SENSE_10))) {
+ US_DEBUGP("-- unexpectedly short transfer\n");
+ need_auto_sense = 1;
+ }
+
+ /* Now, if we need to do the auto-sense, let's do it */
+ if (need_auto_sense) {
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;
+ srb->cmnd[0] = REQUEST_SENSE;
+ srb->cmnd[1] = 0;
+ srb->cmnd[2] = 0;
+ srb->cmnd[3] = 0;
+ srb->cmnd[4] = 18;
+ 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;
+ old_request_buffer = srb->request_buffer;
+ old_sg = srb->use_sg;
+ srb->request_bufflen = 18;
+ 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]);
+ srb->sense_buffer[2] & 0xf,
+ srb->sense_buffer[12],
+ srb->sense_buffer[13]);
/* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
+ srb->result = CHECK_CONDITION;
/* we're done here */
- us->srb->request_buffer = old_request_buffer;
- us->srb->use_sg = old_sg;
- return;
- }
-
- /* Fix the MODE_SENSE data if we translated the command
- */
- if (old_cmnd == MODE_SENSE) {
- unsigned char *dta = (unsigned char *)us->srb->request_buffer;
-
- /* FIXME: we need to compress the entire data structure here
- */
- dta[0] = dta[1]; /* data len */
- dta[1] = dta[2]; /* med type */
- dta[2] = dta[3]; /* dev-spec prm */
- dta[3] = dta[7]; /* block desc len */
- printk (KERN_DEBUG USB_STORAGE
- "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
- dta[0], dta[1], dta[2], dta[3]);
+ srb->request_buffer = old_request_buffer;
+ srb->use_sg = old_sg;
}
- /* Fix-up the return data from an INQUIRY command to show
- * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
- */
- if (us->srb->cmnd[0] == INQUIRY) {
- ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
- }
+ /* Set return code, if necessary */
+ if (need_auto_sense && (srb->sense_buffer[0] == 0x0))
+ srb->result = GOOD;
+ if (!need_auto_sense)
+ srb->result = GOOD;
}
-
-static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
+/*
+ * Control/Bulk/Interrupt transport
+ */
+static int CBI_irq(int state, void *buffer, int len, void *dev_id)
{
- int old_cmnd = 0;
- int result;
-
- /* fix some commands -- this is a form of mode translation
- * UFI devices only accept 12 byte long commands
- *
- * NOTE: This only works because a Scsi_Cmnd struct field contains
- * a unsigned char cmnd[12], so we know we have storage available
- */
-
- /* set command length to 12 bytes (this affects the transport layer) */
- srb->cmd_len = 12;
-
- /* determine the correct (or minimum) data length for these commands */
- switch (us->srb->cmnd[0]) {
-
- /* for INQUIRY, UFI devices only ever return 36 bytes */
- case INQUIRY:
- us->srb->cmnd[4] = 36;
- break;
-
- /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
- case MODE_SENSE:
- case MODE_SELECT:
- /* save the command so we can tell what it was */
- old_cmnd = srb->cmnd[0];
-
- 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;
-
- srb->cmnd[7] = 0;
- srb->cmnd[6] = 0;
- srb->cmnd[5] = 0;
- srb->cmnd[4] = 0;
- srb->cmnd[3] = 0;
- srb->cmnd[2] = srb->cmnd[2];
- srb->cmnd[1] = srb->cmnd[1];
- srb->cmnd[0] = srb->cmnd[0] | 0x40;
- break;
+ struct us_data *us = (struct us_data *)dev_id;
- /* again, for MODE_SENSE_10, we get the minimum (8) */
- case MODE_SENSE_10:
- us->srb->cmnd[7] = 0;
- us->srb->cmnd[8] = 8;
- break;
-
- /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
- case REQUEST_SENSE:
- us->srb->cmnd[4] = 18;
- break;
+ US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+ US_DEBUGP("-- IRQ data length is %d\n", len);
+ US_DEBUGP("-- IRQ state is %d\n", state);
- /* change READ_6/WRITE_6 to READ_10/WRITE_10, which
- * are UFI commands */
- case WRITE_6:
- case READ_6:
- srb->cmnd[11] = 0;
- srb->cmnd[10] = 0;
- srb->cmnd[9] = 0;
- srb->cmnd[8] = srb->cmnd[4];
- srb->cmnd[7] = 0;
- srb->cmnd[6] = 0;
- srb->cmnd[5] = srb->cmnd[3];
- srb->cmnd[4] = srb->cmnd[2];
- srb->cmnd[3] = srb->cmnd[1] & 0x1F;
- srb->cmnd[2] = 0;
- srb->cmnd[1] = srb->cmnd[1] & 0xE0;
- srb->cmnd[0] = srb->cmnd[0] | 0x20;
- break;
- } /* end switch on cmnd[0] */
+ /* is the device removed? */
+ if (state != -ENOENT) {
+ /* save the data for interpretation later */
+ us->ip_data = le16_to_cpup((__u16 *)buffer);
+ US_DEBUGP("-- Interrupt Status 0x%x\n", us->ip_data);
- /* send the command to the transport layer */
- result = us->transport(srb, us);
+ /* was this a wanted interrupt? */
+ if (us->ip_wanted) {
+ us->ip_wanted = 0;
+ up(&(us->ip_waitq));
+ } else
+ US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+ } else
+ US_DEBUGP("-- device has been removed\n");
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
+ /* This return code is truly meaningless -- and I mean truly. It gets
+ * ignored by other layers. It used to indicate if we wanted to get
+ * another interrupt or disable the interrupt callback
*/
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
- }
+ return 0;
+}
- /*
- * 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;
+static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
- US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
+ /* COMMAND STAGE */
+ /* let's send the command via the control pipe */
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
- 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;
+ /* check the return code for the command */
+ US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
+ if (result < 0) {
+ /* STALL must be cleared when they are detected */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
- /* 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]);
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
+ /* Set up for status notification */
+ us->ip_wanted = 1;
- /* we're done here */
- us->srb->request_buffer = old_request_buffer;
- us->srb->use_sg = old_sg;
- return;
+ /* DATA STAGE */
+ /* 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", srb->result);
}
-
- /* Fix the MODE_SENSE data here if we had to translate the command
- */
- if (old_cmnd == MODE_SENSE) {
- unsigned char *dta = (unsigned char *)us->srb->request_buffer;
- /* FIXME: we need to compress the entire data structure here
- */
- dta[0] = dta[1]; /* data len */
- dta[1] = dta[2]; /* med type */
- dta[2] = dta[3]; /* dev-spec prm */
- dta[3] = dta[7]; /* block desc len */
- printk (KERN_DEBUG USB_STORAGE
- "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
- dta[0], dta[1], dta[2], dta[3]);
- }
+ /* STATUS STAGE */
- /* Fix-up the return data from an INQUIRY command to show
- * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
- */
- if (us->srb->cmnd[0] == INQUIRY) {
- ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
- }
-}
-
-static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
-{
- unsigned int result = 0;
-
- /* This code supports devices which do not support {READ|WRITE}_6
- * Apparently, neither Windows or MacOS will use these commands,
- * so some devices do not support them
- */
- if (us->flags & US_FL_MODE_XLATE) {
-
- /* translate READ_6 to READ_10 */
- if (us->srb->cmnd[0] == 0x08) {
-
- /* get the control */
- us->srb->cmnd[9] = us->srb->cmnd[5];
-
- /* get the length */
- us->srb->cmnd[8] = us->srb->cmnd[6];
- us->srb->cmnd[7] = 0;
-
- /* set the reserved area to 0 */
- us->srb->cmnd[6] = 0;
-
- /* get LBA */
- us->srb->cmnd[5] = us->srb->cmnd[3];
- us->srb->cmnd[4] = us->srb->cmnd[2];
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[2] = 0;
-
- /* LUN and other info in cmnd[1] can stay */
-
- /* fix command code */
- us->srb->cmnd[0] = 0x28;
-
- US_DEBUGP("Changing READ_6 to READ_10\n");
- US_DEBUG(us_show_command(us->srb));
- }
-
- /* translate WRITE_6 to WRITE_10 */
- if (us->srb->cmnd[0] == 0x0A) {
-
- /* get the control */
- us->srb->cmnd[9] = us->srb->cmnd[5];
-
- /* get the length */
- us->srb->cmnd[8] = us->srb->cmnd[4];
- us->srb->cmnd[7] = 0;
-
- /* set the reserved area to 0 */
- us->srb->cmnd[6] = 0;
-
- /* get LBA */
- us->srb->cmnd[5] = us->srb->cmnd[3];
- us->srb->cmnd[4] = us->srb->cmnd[2];
- us->srb->cmnd[3] = 0;
- us->srb->cmnd[2] = 0;
-
- /* LUN and other info in cmnd[1] can stay */
-
- /* fix command code */
- us->srb->cmnd[0] = 0x2A;
-
- US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
- US_DEBUG(us_show_command(us->srb));
- }
- } /* if (us->flags & US_FL_MODE_XLATE) */
-
- /* send the command to the transport layer */
- result = us->transport(us->srb, us);
-
- /* If we got a short transfer, but it was for a command that
- * can have short transfers, we're actually okay
- */
- if ((us->srb->result == US_BULK_TRANSFER_SHORT) &&
- ((us->srb->cmnd[0] == REQUEST_SENSE) ||
- (us->srb->cmnd[0] == INQUIRY) ||
- (us->srb->cmnd[0] == MODE_SENSE) ||
- (us->srb->cmnd[0] == LOG_SENSE) ||
- (us->srb->cmnd[0] == MODE_SENSE_10))) {
- us->srb->result = DID_OK;
- }
-
- /* 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;
- }
-
- /* fix the results of an INQUIRY */
- if (us->srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
- ((unsigned char*)us->srb->request_buffer)[2] |= 2;
- }
-}
-
-/***********************************************************************
- * Transport routines
- ***********************************************************************/
-
-static int CBI_irq(int state, void *buffer, int len, void *dev_id)
-{
- struct us_data *us = (struct us_data *)dev_id;
-
- US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
-
- /* save the data for interpretation later */
- if (state != USB_ST_REMOVED) {
- us->ip_data = le16_to_cpup((__u16 *)buffer);
- US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data);
- }
-
- /* was this a wanted interrupt? */
+ /* go to sleep until we get this interrupt */
+ down(&(us->ip_waitq));
+
+ /* if we were woken up by a reset instead of the actual interrupt */
if (us->ip_wanted) {
+ US_DEBUGP("Did not get interrupt on CBI\n");
us->ip_wanted = 0;
- up(&(us->ip_waitq));
- } else {
- US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+ return USB_STOR_TRANSPORT_ERROR;
}
-
- /* This return code is truly meaningless -- and I mean truly. It gets
- * ignored by other layers. It used to indicate if we wanted to get
- * another interrupt or disable the interrupt callback
+
+ US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+
+ /* UFI gives us ASC and ASCQ, like a request sense
+ *
+ * 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.
*/
- return 0;
-}
-
-/* This issues a CB[I] Reset to the device in question
- */
-static int CB_reset(struct us_data *us)
-{
- unsigned char cmd[12];
- int result;
-
- US_DEBUGP("CB_reset\n");
-
- memset(cmd, 0xFF, sizeof(cmd));
- cmd[0] = SEND_DIAGNOSTIC;
- cmd[1] = 4;
- result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
-
- /* long wait for reset */
- schedule_timeout(HZ*6);
-
- 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));
+ if (us->subclass == US_SC_UFI) {
+ if (srb->cmnd[0] == REQUEST_SENSE ||
+ srb->cmnd[0] == INQUIRY)
+ return USB_STOR_TRANSPORT_GOOD;
+ else
+ if (us->ip_data)
+ return USB_STOR_TRANSPORT_FAILED;
+ else
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ /* 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 0x0001:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+ }
- US_DEBUGP("CB_reset done\n");
- return 0;
+ US_DEBUGP("CBI_transport() reached end of function\n");
+ return USB_STOR_TRANSPORT_ERROR;
}
/*
- * Control/Bulk/Interrupt transport
+ * Control/Bulk transport
*/
-static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
+static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
{
int result;
- US_DEBUGP("CBI gets a command:\n");
- US_DEBUG(us_show_command(srb));
-
/* COMMAND STAGE */
/* let's send the command via the control pipe */
result = usb_control_msg(us->pusb_dev,
@@ -798,142 +513,449 @@
us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
/* check the return code for the command */
- US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
if (result < 0) {
+ US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
+
/* 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)));
- return USB_STOR_TRANSPORT_ERROR;
+ result = usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
}
- /* FIXME: we need to handle NAKs here */
+ /* Uh oh... serious problem here */
return USB_STOR_TRANSPORT_ERROR;
}
- /* Set up for status notification */
- us->ip_wanted = 1;
-
/* DATA STAGE */
/* 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("CB data stage result is 0x%x\n", srb->result);
}
-
+
+
/* STATUS STAGE */
+ /* NOTE: CB does not have a status stage. Silly, I know. So
+ * we have to catch this at a higher level.
+ */
+ return USB_STOR_TRANSPORT_GOOD;
+}
- /* go to sleep until we get this interrupt */
- down(&(us->ip_waitq));
+/*
+ * Bulk only transport
+ */
+static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ struct bulk_cb_wrap bcb;
+ struct bulk_cs_wrap bcs;
+ int result;
+ int pipe;
+ int partial;
- /* if we were woken up by a reset instead of the actual interrupt */
- if (us->ip_wanted) {
- US_DEBUGP("Did not get interrupt on CBI\n");
- us->ip_wanted = 0;
- return USB_STOR_TRANSPORT_ERROR;
+ /* set up the command wrapper */
+ bcb.Signature = US_BULK_CB_SIGN;
+ bcb.DataTransferLength = us_transfer_length(srb);
+ bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
+ bcb.Tag = srb->serial_number;
+ bcb.Lun = srb->cmnd[1] >> 5;
+ bcb.Length = srb->cmd_len;
+
+ /* construct the pipe handle */
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ /* copy the command payload */
+ memset(bcb.CDB, 0, sizeof(bcb.CDB));
+ memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+
+ /* send it to out endpoint */
+ US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
+ bcb.Signature, bcb.Tag, bcb.Lun, 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);
+
+ /* if we stall, we need to clear it before we go on */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
}
- US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+ /* if the command transfered well, then we go to the data stage */
+ if (result == 0) {
+ /* send/receive data payload, if there is any */
+ if (bcb.DataTransferLength) {
+ us_transfer(srb, bcb.Flags);
+ US_DEBUGP("Bulk data transfer result 0x%x\n",
+ srb->result);
+ }
+ }
- /* 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
+ /* See flow chart on pg 15 of the Bulk Only Transport spec for
+ * an explanation of how this code works.
*/
- if (us->subclass == US_SC_UFI) {
- if (srb->cmnd[0] == REQUEST_SENSE ||
- srb->cmnd[0] == INQUIRY)
- return USB_STOR_TRANSPORT_GOOD;
- else
- if (us->ip_data)
- return USB_STOR_TRANSPORT_FAILED;
- else
- return USB_STOR_TRANSPORT_GOOD;
+
+ /* construct the pipe handle */
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+
+ /* get CSW for device status */
+ result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+ US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+
+ /* did the attempt to read the CSW fail? */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+
+ /* get the status again */
+ result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
+ US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+
+ /* if it fails again, we need a reset and return an error*/
+ if (result == -EPIPE) {
+ return USB_STOR_TRANSPORT_ERROR;
+ }
}
- /* otherwise, we interpret the data normally */
- switch (us->ip_data) {
- case 0x0001:
+ /* if we still have a failure at this point, we're in trouble */
+ if (result) {
+ US_DEBUGP("Bulk status result = %d\n", result);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* check bulk status */
+ US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+ bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
+ if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
+ bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+ US_DEBUGP("Bulk logical error\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* based on the status code, we report good or bad */
+ switch (bcs.Status) {
+ case US_BULK_STAT_OK:
+ /* command good -- note that we could be short on data */
return USB_STOR_TRANSPORT_GOOD;
- case 0x0002:
+
+ case US_BULK_STAT_FAIL:
+ /* command failed */
return USB_STOR_TRANSPORT_FAILED;
- default:
+
+ case US_BULK_STAT_PHASE:
+ /* phase error */
return USB_STOR_TRANSPORT_ERROR;
}
+
+ /* we should never get here, but if we do, we're in trouble */
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+/***********************************************************************
+ * Protocol routines
+ ***********************************************************************/
+
+static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int old_cmnd = 0;
+
+ /* Fix some commands -- this is a form of mode translation
+ * ATAPI devices only accept 12 byte long commands
+ *
+ * NOTE: This only works because a Scsi_Cmnd struct field contains
+ * a unsigned char cmnd[12], so we know we have storage available
+ */
+
+ /* set command length to 12 bytes */
+ srb->cmd_len = 12;
+
+ /* determine the correct (or minimum) data length for these commands */
+ switch (srb->cmnd[0]) {
+
+ /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+ case MODE_SENSE:
+ case MODE_SELECT:
+ /* save the command so we can tell what it was */
+ old_cmnd = srb->cmnd[0];
+
+ srb->cmnd[11] = 0;
+ srb->cmnd[10] = 0;
+ srb->cmnd[9] = 0;
+ srb->cmnd[8] = srb->cmnd[4];
+ srb->cmnd[7] = 0;
+ srb->cmnd[6] = 0;
+ srb->cmnd[5] = 0;
+ srb->cmnd[4] = 0;
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = srb->cmnd[2];
+ srb->cmnd[1] = srb->cmnd[1];
+ srb->cmnd[0] = srb->cmnd[0] | 0x40;
+ break;
+
+ /* change READ_6/WRITE_6 to READ_10/WRITE_10, which
+ * are ATAPI commands */
+ case WRITE_6:
+ case READ_6:
+ srb->cmnd[11] = 0;
+ srb->cmnd[10] = 0;
+ srb->cmnd[9] = 0;
+ srb->cmnd[8] = srb->cmnd[4];
+ srb->cmnd[7] = 0;
+ srb->cmnd[6] = 0;
+ srb->cmnd[5] = srb->cmnd[3];
+ srb->cmnd[4] = srb->cmnd[2];
+ srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+ srb->cmnd[2] = 0;
+ srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+ srb->cmnd[0] = srb->cmnd[0] | 0x20;
+ break;
+ } /* end switch on cmnd[0] */
+
+ /* send the command to the transport layer */
+ invoke_transport(srb, us);
+
+ /* Fix the MODE_SENSE data if we translated the command
+ */
+ if (old_cmnd == MODE_SENSE) {
+ unsigned char *dta = (unsigned char *)us->srb->request_buffer;
+
+ /* FIXME: we need to compress the entire data structure here
+ */
+ dta[0] = dta[1]; /* data len */
+ dta[1] = dta[2]; /* med type */
+ dta[2] = dta[3]; /* dev-spec prm */
+ dta[3] = dta[7]; /* block desc len */
+ printk (KERN_DEBUG USB_STORAGE
+ "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
+ dta[0], dta[1], dta[2], dta[3]);
+ }
+
+ /* Fix-up the return data from an INQUIRY command to show
+ * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+ */
+ if (srb->cmnd[0] == INQUIRY) {
+ ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
+ }
+}
+
+
+static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int old_cmnd = 0;
+
+ /* fix some commands -- this is a form of mode translation
+ * UFI devices only accept 12 byte long commands
+ *
+ * NOTE: This only works because a Scsi_Cmnd struct field contains
+ * a unsigned char cmnd[12], so we know we have storage available
+ */
+
+ /* set command length to 12 bytes (this affects the transport layer) */
+ srb->cmd_len = 12;
+
+ /* determine the correct (or minimum) data length for these commands */
+ switch (srb->cmnd[0]) {
+
+ /* for INQUIRY, UFI devices only ever return 36 bytes */
+ case INQUIRY:
+ srb->cmnd[4] = 36;
+ break;
+
+ /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+ case MODE_SENSE:
+ case MODE_SELECT:
+ /* save the command so we can tell what it was */
+ old_cmnd = srb->cmnd[0];
+
+ 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;
+
+ srb->cmnd[7] = 0;
+ srb->cmnd[6] = 0;
+ srb->cmnd[5] = 0;
+ srb->cmnd[4] = 0;
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = srb->cmnd[2];
+ srb->cmnd[1] = srb->cmnd[1];
+ srb->cmnd[0] = srb->cmnd[0] | 0x40;
+ break;
+
+ /* again, for MODE_SENSE_10, we get the minimum (8) */
+ case MODE_SENSE_10:
+ srb->cmnd[7] = 0;
+ srb->cmnd[8] = 8;
+ break;
+
+ /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
+ case REQUEST_SENSE:
+ srb->cmnd[4] = 18;
+ break;
+
+ /* change READ_6/WRITE_6 to READ_10/WRITE_10, which
+ * are UFI commands */
+ case WRITE_6:
+ case READ_6:
+ srb->cmnd[11] = 0;
+ srb->cmnd[10] = 0;
+ srb->cmnd[9] = 0;
+ srb->cmnd[8] = srb->cmnd[4];
+ srb->cmnd[7] = 0;
+ srb->cmnd[6] = 0;
+ srb->cmnd[5] = srb->cmnd[3];
+ srb->cmnd[4] = srb->cmnd[2];
+ srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+ srb->cmnd[2] = 0;
+ srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+ srb->cmnd[0] = srb->cmnd[0] | 0x20;
+ break;
+ } /* end switch on cmnd[0] */
+
+ /* send the command to the transport layer */
+ invoke_transport(srb, us);
+
+ /* Fix the MODE_SENSE data here if we had to translate the command
+ */
+ if (old_cmnd == MODE_SENSE) {
+ unsigned char *dta = (unsigned char *)us->srb->request_buffer;
+
+ /* FIXME: we need to compress the entire data structure here
+ */
+ dta[0] = dta[1]; /* data len */
+ dta[1] = dta[2]; /* med type */
+ dta[2] = dta[3]; /* dev-spec prm */
+ dta[3] = dta[7]; /* block desc len */
+ printk (KERN_DEBUG USB_STORAGE
+ "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
+ dta[0], dta[1], dta[2], dta[3]);
+ }
+
+ /* Fix-up the return data from an INQUIRY command to show
+ * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+ */
+ if (srb->cmnd[0] == INQUIRY) {
+ ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
+ }
+}
+
+static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ /* This code supports devices which do not support {READ|WRITE}_6
+ * Apparently, neither Windows or MacOS will use these commands,
+ * so some devices do not support them
+ */
+ if (us->flags & US_FL_MODE_XLATE) {
+
+ /* translate READ_6 to READ_10 */
+ if (srb->cmnd[0] == 0x08) {
+
+ /* get the control */
+ srb->cmnd[9] = us->srb->cmnd[5];
+
+ /* get the length */
+ srb->cmnd[8] = us->srb->cmnd[6];
+ srb->cmnd[7] = 0;
+
+ /* set the reserved area to 0 */
+ srb->cmnd[6] = 0;
+
+ /* get LBA */
+ srb->cmnd[5] = us->srb->cmnd[3];
+ srb->cmnd[4] = us->srb->cmnd[2];
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = 0;
+
+ /* LUN and other info in cmnd[1] can stay */
+
+ /* fix command code */
+ srb->cmnd[0] = 0x28;
+
+ US_DEBUGP("Changing READ_6 to READ_10\n");
+ US_DEBUG(us_show_command(srb));
+ }
+
+ /* translate WRITE_6 to WRITE_10 */
+ if (srb->cmnd[0] == 0x0A) {
+
+ /* get the control */
+ srb->cmnd[9] = us->srb->cmnd[5];
+
+ /* get the length */
+ srb->cmnd[8] = us->srb->cmnd[4];
+ srb->cmnd[7] = 0;
+
+ /* set the reserved area to 0 */
+ srb->cmnd[6] = 0;
+
+ /* get LBA */
+ srb->cmnd[5] = us->srb->cmnd[3];
+ srb->cmnd[4] = us->srb->cmnd[2];
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = 0;
+
+ /* LUN and other info in cmnd[1] can stay */
+
+ /* fix command code */
+ srb->cmnd[0] = 0x2A;
- US_DEBUGP("CBI_transport() reached end of function\n");
- return USB_STOR_TRANSPORT_ERROR;
+ US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
+ US_DEBUG(us_show_command(us->srb));
+ }
+ } /* if (us->flags & US_FL_MODE_XLATE) */
+
+ /* send the command to the transport layer */
+ invoke_transport(srb, us);
+
+ /* fix the results of an INQUIRY */
+ if (srb->cmnd[0] == INQUIRY) {
+ US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
+ ((unsigned char*)us->srb->request_buffer)[2] |= 2;
+ }
}
-/*
- * Control/Bulk transport
+/***********************************************************************
+ * Reset routines
+ ***********************************************************************/
+
+/* This issues a CB[I] Reset to the device in question
*/
-static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
+static int CB_reset(struct us_data *us)
{
+ unsigned char cmd[12];
int result;
- __u8 status[2];
-
- US_DEBUGP("CBC gets a command:\n");
- US_DEBUG(us_show_command(srb));
-
- /* COMMAND STAGE */
- /* let's send the command via the control pipe */
- result = usb_control_msg(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
-
- /* check the return code for the command */
- if (result < 0) {
- US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
- /* 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)));
- return USB_STOR_TRANSPORT_ERROR;
- }
+ US_DEBUGP("CB_reset() called\n");
- /* FIXME: we need to handle NAKs here */
- return USB_STOR_TRANSPORT_ERROR;
- }
+ memset(cmd, 0xFF, sizeof(cmd));
+ cmd[0] = SEND_DIAGNOSTIC;
+ cmd[1] = 4;
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
- /* DATA STAGE */
- /* 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);
- }
-
-
- /* STATUS STAGE */
- /* FIXME: this is wrong */
- result = usb_control_msg(us->pusb_dev,
- usb_rcvctrlpipe(us->pusb_dev,0),
- USB_REQ_GET_STATUS, USB_DIR_IN |
- USB_TYPE_STANDARD | USB_RECIP_DEVICE,
- 0, us->ifnum, status, sizeof(status), HZ*5);
+ /* long wait for reset */
+ schedule_timeout(HZ*6);
- if (result < 0) {
- US_DEBUGP("CBC Status stage returns %d\n", result);
- return USB_STOR_TRANSPORT_ERROR;
- }
+ 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));
- US_DEBUGP("Got CB status 0x%x 0x%x\n", status[0], status[1]);
- if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY &&
- ( (status[0] & ~3) || status[1]))
- return USB_STOR_TRANSPORT_FAILED;
- else
- return USB_STOR_TRANSPORT_GOOD;
-
- US_DEBUGP("CB_transport() reached end of function\n");
- return USB_STOR_TRANSPORT_ERROR;
+ US_DEBUGP("CB_reset done\n");
+ return 0;
}
/* FIXME: Does this work? */
@@ -961,135 +983,31 @@
return result;
}
-/*
- * Bulk only transport
- */
-static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- struct bulk_cb_wrap bcb;
- struct bulk_cs_wrap bcs;
- int result;
- int pipe;
- int partial;
-
- /* set up the command wrapper */
- bcb.Signature = US_BULK_CB_SIGN;
- bcb.DataTransferLength = us_transfer_length(srb);
- bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 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);
-
- /* copy the command payload */
- memset(bcb.CDB, 0, sizeof(bcb.CDB));
- memcpy(bcb.CDB, srb->cmnd, bcb.Length);
-
- /* send it to out endpoint */
- 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);
-
- /* if we stall, we need to clear it before we go on */
- if (result == -EPIPE) {
- US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
- }
-
- /* if the command transfered well, then we go to the data stage */
- if (result == 0) {
- /* send/receive data payload, if there is any */
- if (bcb.DataTransferLength) {
- us_transfer(srb, bcb.Flags);
- US_DEBUGP("Bulk data transfer result 0x%x\n",
- srb->result);
- }
- }
-
- /* See flow chart on pg 15 of the Bulk Only Transport spec for
- * an explanation of how this code works.
- */
-
- /* construct the pipe handle */
- pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-
- /* get CSW for device status */
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-
- /* did the attempt to read the CSW fail? */
- if (result == -EPIPE) {
- US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
-
- /* get the status again */
- result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
- US_BULK_CS_WRAP_LEN, &partial, HZ*5);
-
- /* if it fails again, we need a reset and return an error*/
- if (result == -EPIPE) {
- Bulk_reset(us);
- return USB_STOR_TRANSPORT_ERROR;
- }
- }
-
- /* if we still have a failure at this point, we're in trouble */
- if (result) {
- US_DEBUGP("Bulk status result = %d\n", result);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* check bulk status */
- US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
- bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status);
- if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag ||
- bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
- US_DEBUGP("Bulk logical error\n");
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* based on the status code, we report good or bad */
- switch (bcs.Status) {
- case US_BULK_STAT_OK:
- /* command good -- note that we could be short on data */
- return USB_STOR_TRANSPORT_GOOD;
-
- case US_BULK_STAT_FAIL:
- /* command failed */
- return USB_STOR_TRANSPORT_FAILED;
-
- case US_BULK_STAT_PHASE:
- /* phase error */
- Bulk_reset(us);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* we should never get here, but if we do, we're in trouble */
- return USB_STOR_TRANSPORT_ERROR;
-}
-
/***********************************************************************
* Host functions
***********************************************************************/
-/* detect adapter (always true ) */
+static const char* us_info(struct Scsi_Host *host)
+{
+ return "SCSI emulation for USB Mass Storage devices\n";
+}
+
+/* detect a virtual adapter (always works) */
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];
-
- /* set up our name */
- sprintf(name, "usbscsi%d", us->host_number);
- sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL);
+ struct us_data *us;
+ char local_name[32];
+
+ /* This is not nice at all, but how else are we to get the
+ * data here? */
+ us = (struct us_data *)sht->proc_dir;
+
+ /* 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,36 +1023,34 @@
/* 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);
- /* release the interrupt handler, if necessary */
- if (us->irq_handle) {
- US_DEBUGP("-- releasing irq\n");
- result = usb_release_irq(us->pusb_dev, us->irq_handle,
- us->irqpipe);
- US_DEBUGP("-- usb_release_irq() returned %d\n", result);
- us->irq_handle = NULL;
- }
-
- /* lock the data structures */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ /* Kill the control threads
+ *
+ * Enqueue the command, wake up the thread, and wait for
+ * notification that it's exited.
+ */
+ US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
+ us->action = US_ACT_EXIT;
+ up(&(us->sleeper));
+ down(&(us->notify));
+
+ /* free the data structure we were using */
+ US_DEBUGP("-- freeing private host data structure\n");
+ kfree(us);
+ (struct us_data*)psh->hostdata[0] = NULL;
/* we always have a successful release */
return 0;
@@ -1171,20 +1087,38 @@
return 0;
}
-/* FIXME: This doesn't actually abort anything */
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command abort
+ *
+ * Note that this is really only meaningful right now for CBI transport
+ * devices which have failed to give us the command completion interrupt
+ */
static int us_abort( Scsi_Cmnd *srb )
{
- return 0;
+ struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+ US_DEBUGP("us_abort() called\n");
+
+ /* if we're stuck waiting for an IRQ, simulate it */
+ if (us->ip_wanted) {
+ US_DEBUGP("-- simulating missing IRQ\n");
+ up(&(us->ip_waitq));
+ return SUCCESS;
+ }
+
+ return FAILED;
}
/* FIXME: this doesn't do anything right now */
static int us_bus_reset( Scsi_Cmnd *srb )
{
- struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+ // 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));
// us->transport_reset(us);
return SUCCESS;
}
@@ -1192,6 +1126,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;
}
@@ -1209,14 +1144,13 @@
struct us_data *us;
char *pos = buffer;
char *tmp_ptr;
- unsigned long flags;
/* if someone is sending us data, just throw it away */
if (inout)
return length;
/* lock the data structures */
- spin_lock_irqsave(&us_list_spinlock, flags);
+ down(&us_list_semaphore);
/* find our data from hostno */
us = us_list;
@@ -1228,7 +1162,7 @@
/* if we couldn't find it, we return an error */
if (!us) {
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
return -ESRCH;
}
@@ -1274,11 +1208,42 @@
break;
}
+ SPRINTF(" Transport: ");
+ switch (us->subclass) {
+ case US_SC_RBC:
+ SPRINTF("Reduced Block Commands\n");
+ break;
+
+ case US_SC_8020:
+ SPRINTF("8020i\n");
+ break;
+
+ case US_SC_QIC:
+ SPRINTF("QIC-157\n");
+ break;
+
+ case US_SC_8070:
+ SPRINTF("8070i\n");
+ break;
+
+ case US_SC_SCSI:
+ SPRINTF("Transparent SCSI\n");
+ break;
+
+ case US_SC_UFI:
+ SPRINTF("Uniform Floppy Interface\n");
+ break;
+
+ default:
+ SPRINTF("Unknown Transport\n");
+ break;
+ }
+
/* show the GUID of the device */
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_semaphore);
/*
* Calculate start of next buffer, and return value.
@@ -1298,36 +1263,30 @@
*/
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 */
+ name: "usb-storage",
+ proc_info: usb_stor_proc_info,
+ info: us_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[] = {
@@ -1362,10 +1321,11 @@
*/
daemonize();
- sprintf(current->comm, "usbscsi%d", us->host_number);
+ sprintf(current->comm, "usb-storage-%d", us->host_number);
unlock_kernel();
+ /* signal that we've started the thread */
up(&(us->notify));
for(;;) {
@@ -1382,14 +1342,10 @@
/* release the queue lock as fast as possible */
up(&(us->queue_exclusion));
- /* FIXME: we need to examine placment of break; and
- * scsi_done() calls */
-
switch (action) {
case US_ACT_COMMAND:
/* bad device */
- /* FIXME: we need to enable and test multiple LUNs */
- if (us->srb->target || us->srb->lun) {
+ if (us->srb->target) {
US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
us->srb->result = DID_BAD_TARGET << 16;
@@ -1399,6 +1355,9 @@
break;
}
+ /* lock the device pointers */
+ down(&(us->dev_semaphore));
+
/* our device has gone - pretend not ready */
/* FIXME: we also need to handle INQUIRY here,
* probably */
@@ -1414,6 +1373,10 @@
us->srb->result = (DID_OK << 16) | 2;
}
+ /* unlock the device pointers */
+ up(&(us->dev_semaphore));
+
+ /* indicate that the command is done */
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
@@ -1434,6 +1397,11 @@
US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
+
+ /* unlock the device pointers */
+ up(&(us->dev_semaphore));
+
+ /* indicate that the command is done */
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
@@ -1453,11 +1421,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;
}
@@ -1471,7 +1443,6 @@
struct us_data *ss = NULL;
GUID(guid); /* Global Unique Identifier */
int result;
- unsigned long flags;
/* these are temporary copies -- we test on these, then put them
* in the us-data structure
@@ -1531,9 +1502,6 @@
&ss->irq_handle);
if (result < 0)
return NULL;
-
- /* FIXME: what is this?? */
- down(&(ss->ip_waitq));
}
/*
@@ -1613,7 +1581,7 @@
}
/* lock access to the data structures */
- spin_lock_irqsave(&us_list_spinlock, flags);
+ down(&us_list_semaphore);
/*
* Now check if we have seen this GUID before
@@ -1655,7 +1623,7 @@
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);
+ up(&us_list_semaphore);
return NULL;
}
memset(ss, 0, sizeof(struct us_data));
@@ -1664,6 +1632,7 @@
init_MUTEX_LOCKED(&(ss->sleeper));
init_MUTEX_LOCKED(&(ss->notify));
init_MUTEX(&(ss->queue_exclusion));
+ init_MUTEX(&(ss->dev_semaphore));
/* copy over the subclass and protocol data */
ss->subclass = subclass;
@@ -1725,7 +1694,7 @@
break;
case US_SC_QIC:
- US_DEBUGPX("QIC157\n");
+ US_DEBUGPX("QIC-157\n");
break;
case US_SC_8070:
@@ -1774,9 +1743,9 @@
/* Grab the next host number */
ss->host_number = my_host_number++;
- /* FIXME: this is bad. We abuse this pointer so we
- * can pass the ss pointer to the host controler thread
- * in us_detect
+ /* We abuse this pointer so we can pass the ss pointer to
+ * the host controler thread in us_detect. But how else are
+ * we to do it?
*/
(struct us_data *)ss->htmplt.proc_dir = ss;
@@ -1795,7 +1764,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 */
@@ -1804,7 +1773,7 @@
}
/* release the data structure lock */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
printk(KERN_DEBUG
"WARNING: USB Mass Storage data integrity not assured\n");
@@ -1829,6 +1798,9 @@
return;
}
+ /* lock access to the device data structure */
+ down(&(ss->dev_semaphore));
+
/* release the IRQ, if we have one */
if (ss->irq_handle) {
US_DEBUGP("-- releasing irq handle\n");
@@ -1840,6 +1812,9 @@
/* mark the device as gone */
ss->pusb_dev = NULL;
+
+ /* lock access to the device data structure */
+ up(&(ss->dev_semaphore));
}
@@ -1849,18 +1824,10 @@
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 ;
- }
+ /* initialize internal global data elements */
+ us_list = NULL;
+ init_MUTEX(&us_list_semaphore);
+ my_host_number = 0;
/* register the driver, return -1 if error */
if (usb_register(&storage_driver) < 0)
@@ -1873,36 +1840,38 @@
void __exit usb_stor_exit(void)
{
- static struct us_data *ptr;
- static struct us_data *next;
- unsigned long flags;
+ struct us_data *next;
- /*
- * deregister the driver -- this eliminates races with probes and
- * disconnects
+ 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);
-
- /* unregister all the virtual hosts */
- for (ptr = us_list; ptr != NULL; ptr = ptr->next)
- scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
-
- /* 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 */
- while (ptr) {
- next = ptr->next;
- kfree(ptr);
- ptr = next;
+ down(&us_list_semaphore);
+
+ /* While there are still virtual hosts, unregister them
+ *
+ * Note that the us_release() routine will destroy the local data
+ * structure. So we have to peel these off the top of the list
+ * and keep updating the head pointer as we go.
+ */
+ while (us_list) {
+ /* keep track of where the next one is */
+ next = us_list->next;
+
+ US_DEBUGP("-- calling scsi_unregister_module()\n");
+ scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt));
+
+ /* advance the list pointer */
+ us_list = next;
}
/* unlock the data structures */
- spin_unlock_irqrestore(&us_list_spinlock, flags);
+ up(&us_list_semaphore);
}
module_init(usb_stor_init) ;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)