patch-2.3.99-pre1 linux/drivers/usb/usb-storage.c
Next file: linux/drivers/usb/usb-storage.h
Previous file: linux/drivers/usb/usb-core.c
Back to the patch index
Back to the overall index
- Lines: 1673
- Date:
Tue Mar 14 17:54:42 2000
- Orig file:
v2.3.51/linux/drivers/usb/usb-storage.c
- Orig date:
Fri Mar 10 16:40:45 2000
diff -u --recursive --new-file v2.3.51/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c
@@ -6,9 +6,9 @@
* Further reference:
* This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such
- * devices. Clearly, the designers had SCSI commands in mind when they
- * created this document. The commands are all similar to commands
- * in the SCSI-II specification.
+ * devices. Clearly, the designers had SCSI and ATAPI commands in mind
+ * when they created this document. The commands are all very similar
+ * to commands in the SCSI-II and ATAPI specifications.
*
* It is important to note that in a number of cases this class exhibits
* class-specific exemptions from the USB specification. Notably the
@@ -65,8 +65,6 @@
static int my_host_number;
-int usb_stor_debug = 1;
-
struct us_data;
typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
@@ -74,7 +72,7 @@
typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
struct us_data {
- struct us_data *next; /* next device */
+ struct us_data *next; /* next device */
struct usb_device *pusb_dev; /* this usb_device */
unsigned int flags; /* from filter initially */
__u8 ifnum; /* interface number */
@@ -93,15 +91,17 @@
int host_number; /* to find us */
int host_no; /* allocated by scsi */
Scsi_Cmnd *srb; /* current srb */
+ Scsi_Cmnd *queue_srb; /* the single queue slot */
int action; /* what to do */
- wait_queue_head_t waitq; /* thread waits */
- wait_queue_head_t ip_waitq; /* for CBI interrupts */
+ struct semaphore ip_waitq; /* for CBI interrupts */
__u16 ip_data; /* interrupt data */
int ip_wanted; /* needed */
int pid; /* control thread */
struct semaphore *notify; /* wait for thread to begin */
void *irq_handle; /* for USB int requests */
unsigned int irqpipe; /* pipe for release_irq */
+ struct semaphore sleeper; /* to sleep on */
+ struct semaphore queue_exclusion; /* to protect data structs */
};
/*
@@ -129,117 +129,100 @@
* Data transfer routines
***********************************************************************/
-/* Transfer one buffer (breaking into packets if necessary)
- * Note that this function is necessary because if the device NAKs, we
- * need to know that information directly
+/* FIXME: the names of these functions are poorly choosen. */
+
+/*
+ * Transfer one SCSI scatter-gather buffer via bulk transfer
+ *
+ * Note that this function is necessary because we want the ability to
+ * use scatter-gather memory. Good performance is achived by a combination
+ * of scatter-gather and clustering (which makes each chunk bigger).
*
- * FIXME: is the above true? Or will the URB status show ETIMEDOUT after
- * retrying several times allready? Perhaps this is the way we should
- * be going anyway?
+ * Note that the lower layer will always retry when a NAK occurs, up to the
+ * timeout limit. Thus we don't have to worry about it for individual
+ * packets.
*/
-static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
+static int us_bulk_transfer(struct us_data *us, int pipe,
+ char *buf, int length)
{
- int max_size;
- int this_xfer;
int result;
int partial;
- int maxtry;
-
- /* determine the maximum packet size for these transfers */
- max_size = usb_maxpacket(us->pusb_dev,
- pipe, usb_pipeout(pipe)) * 16;
-
- /* while we have data left to transfer */
- while (length) {
-
- /* calculate how long this will be -- maximum or a remainder */
- this_xfer = length > max_size ? max_size : length;
- length -= this_xfer;
-
- /* FIXME: this number is totally outrageous. We need to pick
- * a better (smaller) number).
- */
-
- /* setup the retry counter */
- maxtry = 100;
-
- /* set up the transfer loop */
- do {
- /* transfer the data */
- US_DEBUGP("Bulk xfer 0x%x(%d) try #%d\n",
- (unsigned int)buf, this_xfer, 101 - maxtry);
- result = usb_bulk_msg(us->pusb_dev, pipe, buf,
- this_xfer, &partial, HZ*5);
- US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
- result, partial, this_xfer);
-
- /* 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);
- }
-
- /* update to show what data was transferred */
- this_xfer -= partial;
- buf += partial;
- /* NAK - we retry a few times */
- if (result == -ETIMEDOUT) {
-
- US_DEBUGP("us_one_transfer: device NAKed\n");
-
- /* if our try counter reaches 0, bail out */
- if (!maxtry--)
- return -ETIMEDOUT;
+ /* transfer the data */
+ US_DEBUGP("Bulk xfer 0x%x(%d)\n", (unsigned int)buf, length);
+ result = usb_bulk_msg(us->pusb_dev, pipe, buf, length, &partial, HZ*5);
+ US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",
+ result, partial, length);
+
+ /* 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);
+ }
- /* just continue the while loop */
- continue;
- }
-
- /* other errors (besides NAK) -- we just bail out*/
- if (result != 0) {
- US_DEBUGP("us_one_transfer: device returned error %d\n", result);
- return result;
- }
+ /* did we send all the data? */
+ if (partial == length) {
+ return US_BULK_TRANSFER_GOOD;
+ }
- /* continue until this transfer is done */
- } while ( this_xfer );
+ /* 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) {
+ US_DEBUGP("us_bulk_transfer: device NAKed\n");
+ }
+ return US_BULK_TRANSFER_FAILED;
}
- /* if we get here, we're done and successful */
- return 0;
+ /* no error code, so we must have transferred some data,
+ * just not all of it */
+ return US_BULK_TRANSFER_SHORT;
}
-static unsigned int us_transfer_length(Scsi_Cmnd *srb);
-
-/* transfer one SCSI command, using scatter-gather if requested */
-/* FIXME: what do the return codes here mean? */
-static int us_transfer(Scsi_Cmnd *srb, int dir_in)
+/*
+ * Transfer an entire SCSI command's worth of data payload over the bulk
+ * pipe.
+ *
+ * Note that this uses us_bulk_transfer to achive it's goals -- this
+ * function simply determines if we're going to use scatter-gather or not,
+ * and acts appropriately. For now, it also re-interprets the error codes.
+ */
+static void us_transfer(Scsi_Cmnd *srb, int dir_in)
{
- struct us_data *us = (struct us_data *)srb->host_scribble;
+ struct us_data *us;
int i;
int result = -1;
- unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
- usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+ unsigned int pipe;
+ struct scatterlist *sg;
- /* FIXME: stop transferring data at us_transfer_length(), not
- * bufflen */
+ /* calculate the appropriate pipe information */
+ us = (struct us_data*) srb->host_scribble;
+ if (dir_in)
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ /* are we scatter-gathering? */
if (srb->use_sg) {
- struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
+ /* loop over all the scatter gather structures and
+ * make the appropriate requests for each, until done
+ */
+ sg = (struct scatterlist *) srb->request_buffer;
for (i = 0; i < srb->use_sg; i++) {
- result = us_one_transfer(us, pipe, sg[i].address, sg[i].length);
+ result = us_bulk_transfer(us, pipe, sg[i].address,
+ sg[i].length);
if (result)
break;
}
}
else
- result = us_one_transfer(us, pipe, srb->request_buffer,
- us_transfer_length(srb));
+ /* no scatter-gather, just make the request */
+ result = us_bulk_transfer(us, pipe, srb->request_buffer,
+ srb->request_bufflen);
- if (result < 0)
- US_DEBUGP("us_transfer returning error %d\n", result);
- return result;
+ /* return the result in the data structure itself */
+ srb->result = result;
}
/* calculate the length of the data transfer (not the command) for any
@@ -265,6 +248,9 @@
case MODE_SENSE:
return srb->cmnd[4];
+ case READ_CAPACITY:
+ return 8;
+
case LOG_SENSE:
case MODE_SENSE_10:
return (srb->cmnd[7] << 8) + srb->cmnd[8];
@@ -274,8 +260,9 @@
}
if (srb->use_sg) {
- struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
+ struct scatterlist *sg;
+ sg = (struct scatterlist *) srb->request_buffer;
for (i = 0; i < srb->use_sg; i++) {
total += sg[i].length;
}
@@ -289,12 +276,148 @@
* Protocol routines
***********************************************************************/
-static int CB_transport(Scsi_Cmnd *srb, struct us_data *us);
-static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us);
+static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int old_cmnd = 0;
+ 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
+ */
+ 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;
+ 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;
+ }
+
+ /* 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 (us->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;
+ int result;
/* fix some commands -- this is a form of mode translation
* UFI devices only accept 12 byte long commands
@@ -372,23 +495,31 @@
} /* end switch on cmnd[0] */
/* send the command to the transport layer */
- us->srb->result = us->transport(srb, us);
+ result = us->transport(srb, us);
- /* if we have an error, we're going to do a
- * REQUEST_SENSE automatically */
+ /* 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;
+ }
- /* FIXME: we should only do this for device
- * errors, not system errors */
- if (us->srb->result) {
+ /*
+ * If we have an error, we're going to do a
+ * REQUEST_SENSE automatically
+ */
+ if (result != USB_STOR_TRANSPORT_GOOD) {
int temp_result;
- int count;
void* old_request_buffer;
+ int old_sg;
US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
-
us->srb->cmnd[0] = REQUEST_SENSE;
us->srb->cmnd[1] = 0;
us->srb->cmnd[2] = 0;
@@ -398,49 +529,34 @@
/* 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 = kmalloc(18, GFP_KERNEL);
+ 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);
-
- /* copy the data from the request buffer to the sense buffer */
- for(count = 0; count < 18; count++)
- us->srb->sense_buffer[count] =
- ((unsigned char *)(us->srb->request_buffer))[count];
-
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]);
+ 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 */
- kfree(us->srb->request_buffer);
us->srb->request_buffer = old_request_buffer;
+ us->srb->use_sg = old_sg;
return;
}
- /* FIXME: if we need to send more data, or recieve data, we should
- * do it here. Then, we can do status handling here also.
- *
- * This includes MODE_SENSE from above
+ /* 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;
- /* calculate the new length */
- int length = (dta[0] << 8) + dta[1] + 2;
-
- /* copy the available data length into the structure */
- us->srb->cmnd[7] = length >> 8;
- us->srb->cmnd[8] = length & 0xFF;
-
- /* send the command to the transport layer */
- us->srb->result = us->transport(srb, us);
-
- /* FIXME: this assumes that the 2nd attempt is always
- * successful convert MODE_SENSE_10 return data format
- * to MODE_SENSE_6 format */
+ /* 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 */
@@ -450,126 +566,18 @@
dta[0], dta[1], dta[2], dta[3]);
}
- /* FIXME: if this was a TEST_UNIT_READY, and we get a NOT READY/
- * LOGICAL DRIVE NOT READY then we do a START_STOP, and retry
+ /* 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
*/
-
- /* FIXME: here is where we need to fix-up the return data from
- * an INQUIRY command to show ANSI SCSI rev 2
- */
-
- /* FIXME: The rest of this is bogus. usb_control_msg() will only
- * return an error if we've really honked things up. If it just
- * needs a START_STOP, then we'll get some data back via
- * REQUEST_SENSE -- either way, this belongs at a higher level
- */
-
-#if 0
- /* For UFI, if this is the first time we've sent this TEST_UNIT_READY
- * command, we can try again
- */
- if (!done_start && (us->subclass == US_SC_UFI)
- && (cmd[0] == TEST_UNIT_READY) && (result < 0)) {
-
- /* as per spec try a start command, wait and retry */
- wait_ms(100);
-
- done_start++;
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = START_STOP;
- cmd[4] = 1; /* start */
-
- 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, 12, HZ*5);
- US_DEBUGP("Next usb_control_msg returns %d\n", result);
-
- /* allow another retry */
- retry++;
- continue;
+ if (us->srb->cmnd[0] == INQUIRY) {
+ ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
}
-#endif
}
static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
{
- unsigned int savelen = us->srb->request_bufflen;
- unsigned int saveallocation = 0;
-
-#if 0
- /* force attention on first command */
- if (!us->attention_done) {
- if (us->srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("forcing unit attention\n");
- us->attention_done = 1;
-
- if (us->srb->result == USB_STOR_TRANSPORT_GOOD) {
- unsigned char *p = (unsigned char *)us->srb->request_buffer;
-
- if ((p[2] & 0x0f) != UNIT_ATTENTION) {
- p[2] = UNIT_ATTENTION;
- p[12] = 0x29; /* power on, reset or bus-reset */
- p[13] = 0;
- } /* if ((p[2] & 0x0f) != UNIT_ATTENTION) */
- } /* if (us->srb->result == USB_STORE_TRANSPORT_GOOD) */
- }
- } /* if (!us->attention_done) */
-#endif
+ unsigned int result = 0;
- /* If the command has a variable-length payload, then we do them
- * in two steps -- first we do the minimum, then we recalculate
- * then length, and re-issue the command
- *
- * we use savelen to remember how much buffer we really have
- * we use savealloction to remember how much was really requested
- */
-
- /* FIXME: remove savelen based on mods to us_transfer_length() */
- switch (us->srb->cmnd[0]) {
- case REQUEST_SENSE:
- if (us->srb->request_bufflen > 18)
- us->srb->request_bufflen = 18;
- else
- break;
- saveallocation = us->srb->cmnd[4];
- us->srb->cmnd[4] = 18;
- break;
-
- case INQUIRY:
- if (us->srb->request_bufflen > 36)
- us->srb->request_bufflen = 36;
- else
- break;
- saveallocation = us->srb->cmnd[4];
- us->srb->cmnd[4] = 36;
- break;
-
- case MODE_SENSE:
- if (us->srb->request_bufflen > 4)
- us->srb->request_bufflen = 4;
- else
- break;
- saveallocation = us->srb->cmnd[4];
- us->srb->cmnd[4] = 4;
- break;
-
- case LOG_SENSE:
- case MODE_SENSE_10:
- if (us->srb->request_bufflen > 8)
- us->srb->request_bufflen = 8;
- else
- break;
- saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8];
- us->srb->cmnd[7] = 0;
- us->srb->cmnd[8] = 8;
- break;
-
- default:
- break;
- } /* end switch on cmnd[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
@@ -631,25 +639,33 @@
US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
US_DEBUG(us_show_command(us->srb));
}
- } /* end if (us->flags & US_FL_MODE_XLATE) */
+ } /* if (us->flags & US_FL_MODE_XLATE) */
/* send the command to the transport layer */
- us->srb->result = us->transport(us->srb, us);
+ 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 */
- /* FIXME: we should only do this for device errors, not
- * system errors */
- if (us->srb->result) {
+ if (result != USB_STOR_TRANSPORT_GOOD) {
int temp_result;
- int count;
+ int old_sg;
void* old_request_buffer;
US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");
- /* set the result so the higher layers expect this data */
- us->srb->result = CHECK_CONDITION;
-
+ /* set up the REQUEST_SENSE command and parameters */
us->srb->cmnd[0] = REQUEST_SENSE;
us->srb->cmnd[1] = 0;
us->srb->cmnd[2] = 0;
@@ -659,115 +675,32 @@
/* 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 = kmalloc(18, GFP_KERNEL);
+ 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);
-
- /* copy the data from the request buffer to the sense buffer */
- for(count = 0; count < 18; count++)
- us->srb->sense_buffer[count] =
- ((unsigned char *)(us->srb->request_buffer))[count];
-
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]);
+ 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 */
- kfree(us->srb->request_buffer);
+ us->srb->use_sg = old_sg;
us->srb->request_buffer = old_request_buffer;
return;
}
- if (savelen != us->srb->request_bufflen) {
- unsigned char *p = (unsigned char *)us->srb->request_buffer;
- unsigned int length = 0;
-
- /* set correct length and retry */
- switch (us->srb->cmnd[0]) {
-
- /* FIXME: we should try to get all the sense data */
- case REQUEST_SENSE:
- /* simply return 18 bytes */
- p[7] = 10;
- length = us->srb->request_bufflen;
- break;
-
- case INQUIRY:
- length = p[4] + 5 > savelen ? savelen : p[4] + 5;
- us->srb->cmnd[4] = length;
- break;
-
- case MODE_SENSE:
- US_DEBUGP("MODE_SENSE Mode data length is %d\n", p[0]);
- length = p[0] + 1 > savelen ? savelen : p[0] + 1;
- us->srb->cmnd[4] = length;
- break;
-
- case LOG_SENSE:
- length = ((p[2] << 8) + p[3]) + 4 > savelen ? savelen : ((p[2] << 8) + p[3]) + 4;
- us->srb->cmnd[7] = length >> 8;
- us->srb->cmnd[8] = length;
- break;
-
- case MODE_SENSE_10:
- US_DEBUGP("MODE_SENSE_10 Mode data length is %d\n",
- (p[0] << 8) + p[1]);
- length = ((p[0] << 8) + p[1]) + 6 > savelen ? savelen : ((p[0] << 8) + p[1]) + 6;
- us->srb->cmnd[7] = length >> 8;
- us->srb->cmnd[8] = length;
- break;
- } /* end switch on cmnd[0] */
-
- US_DEBUGP("Old/New length = %d/%d\n",
- savelen, length);
-
- /* issue the new command */
- /* FIXME: this assumes that the second attempt is
- * always successful */
- if (us->srb->request_bufflen != length) {
- US_DEBUGP("redoing cmd with len=%d\n", length);
- us->srb->request_bufflen = length;
- us->srb->result = us->transport(us->srb, us);
- }
-
- /* reset back to original values */
- us->srb->request_bufflen = savelen;
-
- /* fix data as necessary */
- switch (us->srb->cmnd[0]) {
- case INQUIRY:
- if ((((unsigned char*)us->srb->request_buffer)[2] & 0x7) == 0) {
- US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
- ((unsigned char*)us->srb->request_buffer)[2] |= 2;
- }
- /* FALL THROUGH */
- case REQUEST_SENSE:
- case MODE_SENSE:
- if (us->srb->use_sg == 0 && length > 0) {
- int i;
- printk(KERN_DEBUG "Data is");
- for (i = 0; i < 32 && i < length; ++i)
- printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]);
- if (i < length)
- printk(" ...");
- printk("\n");
- }
-
- /* FIXME: is this really necessary? */
- us->srb->cmnd[4] = saveallocation;
- break;
-
- case LOG_SENSE:
- case MODE_SENSE_10:
- /* FIXME: is this really necessary? */
- us->srb->cmnd[7] = saveallocation >> 8;
- us->srb->cmnd[8] = saveallocation;
- break;
- } /* end switch on cmnd[0] */
- } /* if good command */
+ /* 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;
+ }
}
/***********************************************************************
@@ -789,7 +722,7 @@
/* was this a wanted interrupt? */
if (us->ip_wanted) {
us->ip_wanted = 0;
- wake_up(&us->ip_waitq);
+ up(&(us->ip_waitq));
} else {
US_DEBUGP("ERROR: Unwanted interrupt received!\n");
}
@@ -801,9 +734,7 @@
return 0;
}
-/* FIXME: this reset function doesn't really reset the port, and it
- * should. Actually it should probably do what it's doing here, and
- * reset the port physically
+/* This issues a CB[I] Reset to the device in question
*/
static int CB_reset(struct us_data *us)
{
@@ -816,41 +747,39 @@
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,
+ 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));
+ 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;
}
-static int pop_CB_status(Scsi_Cmnd *srb);
-
-/* FIXME: we also need a CBI_command which sets up the completion
- * interrupt, and waits for it
+/*
+ * Control/Bulk/Interrupt transport
*/
-static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
+static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
{
int result;
US_DEBUGP("CBI gets a command:\n");
US_DEBUG(us_show_command(srb));
- /* FIXME: we aren't setting the ip_wanted indicator early enough, which
- * causes some commands to never complete. This hangs the driver.
- */
-
+ /* 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);
+ 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) {
@@ -858,131 +787,160 @@
/* a stall is a fatal condition from the device */
if (result == -EPIPE) {
- US_DEBUGP("-- Stall on control pipe detected. Clearing\n");
-
+ 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)));
+ usb_sndctrlpipe(us->pusb_dev,
+ 0)));
return USB_STOR_TRANSPORT_ERROR;
}
- /* FIXME: we need to handle NAKs here */
+ /* FIXME: we need to handle NAKs 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)) {
- result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
- US_DEBUGP("CBI attempted to transfer data, result is 0x%x\n", result);
+ us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ US_DEBUGP("CBI data stage result is 0x%x\n", result);
+ }
- /* FIXME: what do the return codes from us_transfer mean? */
- if ((result < 0) &&
- (result != USB_ST_DATAUNDERRUN) &&
- (result != USB_ST_STALL)) {
- return DID_ERROR << 16;
- }
- } /* if (us_transfer_length(srb)) */
+ /* STATUS STAGE */
- /* get status and return it */
- return pop_CB_status(srb);
+ /* go to sleep until we get this interrup */
+ /* FIXME: this should be changed to use a timeout */
+ down(&(us->ip_waitq));
+
+ /* FIXME: currently this code is unreachable, but the idea is
+ * necessary. See above comment.
+ */
+ if (us->ip_wanted) {
+ US_DEBUGP("Did not get interrupt on CBI\n");
+ us->ip_wanted = 0;
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
+
+ /* UFI gives us ASC and ASCQ, like a request sense */
+ /* FIXME: is this right? Do REQUEST_SENSE and INQUIRY need special
+ * case handling?
+ */
+ 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;
+ }
+
+ /* otherwise, we interpret the data normally */
+ switch (us->ip_data) {
+ case 0x0001:
+ return USB_STOR_TRANSPORT_GOOD;
+ case 0x0002:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ US_DEBUGP("CBI_transport() reached end of function\n");
+ return USB_STOR_TRANSPORT_ERROR;
}
/*
- * Control/Bulk status handler
+ * Control/Bulk transport
*/
-
-static int pop_CB_status(Scsi_Cmnd *srb)
+static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
{
- struct us_data *us = (struct us_data *)srb->host_scribble;
- int result = 0;
+ int result;
__u8 status[2];
- int retry = 5;
-
- US_DEBUGP("pop_CB_status, proto=0x%x\n", us->protocol);
- switch (us->protocol) {
- case US_PR_CB:
- /* get from control */
- while (retry--) {
- 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);
- if (result != USB_ST_TIMEOUT)
- break;
- }
- if (result) {
- US_DEBUGP("Bad AP status request %d\n", result);
- return DID_ABORT << 16;
- }
- US_DEBUGP("Got AP 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 (DID_OK << 16) | 2;
- else
- return USB_STOR_TRANSPORT_GOOD;
- break;
+ US_DEBUGP("CBC gets a command:\n");
+ US_DEBUG(us_show_command(srb));
- /* FIXME: this should be in a separate function */
- case US_PR_CBI:
- /* get from interrupt pipe */
+ /* 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);
- /* add interrupt transfer, marked for removal */
- us->ip_wanted = 1;
+ /* check the return code for the command */
+ if (result < 0) {
+ US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
- /* go to sleep until we get this interrup */
- /* FIXME: this should be changed to use a timeout */
- sleep_on(&us->ip_waitq);
-
- if (us->ip_wanted) {
- US_DEBUGP("Did not get interrupt on CBI\n");
- us->ip_wanted = 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)));
return USB_STOR_TRANSPORT_ERROR;
}
-
- US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
- /* UFI gives us ASC and ASCQ, like a request sense */
- /* FIXME: is this right? do REQUEST_SENSE and INQUIRY need special
- * case handling?
- */
- 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;
- }
+ /* FIXME: we need to handle NAKs here */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
- /* otherwise, we interpret the data normally */
- switch (us->ip_data) {
- case 0x0001:
- return USB_STOR_TRANSPORT_GOOD;
- case 0x0002:
- return USB_STOR_TRANSPORT_FAILED;
- default:
- return USB_STOR_TRANSPORT_ERROR;
- }
+ /* 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);
}
- US_DEBUGP("pop_CB_status, reached end of function\n");
+
+
+ /* 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);
+
+ if (result < 0) {
+ US_DEBUGP("CBC Status stage returns %d\n", result);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ 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;
}
+/* FIXME: Does this work? */
static int Bulk_reset(struct us_data *us)
{
int result;
- result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_BULK_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- US_BULK_RESET_HARD, us->ifnum,
- NULL, 0, HZ*5);
- if (result)
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ US_BULK_RESET,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ US_BULK_RESET_HARD, us->ifnum, NULL, 0, HZ*5);
+
+ 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));
+
+ 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);
@@ -991,8 +949,7 @@
}
/*
- * The bulk only protocol handler.
- * Uses the in and out endpoints to transfer commands and data
+ * Bulk only transport
*/
static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
{
@@ -1001,7 +958,7 @@
int result;
int pipe;
int partial;
-
+
/* set up the command wrapper */
bcb.Signature = US_BULK_CB_SIGN;
bcb.DataTransferLength = us_transfer_length(srb);
@@ -1009,14 +966,14 @@
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,
@@ -1024,94 +981,83 @@
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 */
- /* FIXME: Regardless of the status of the data stage, we go on to the
- * status stage. Note that this implies that if a command is
- * partially successful, we rely on the device reporting an error
- * the CSW. The spec says that the device may just decide to short us.
- */
if (result == 0) {
/* send/receive data payload, if there is any */
if (bcb.DataTransferLength) {
- result = us_transfer(srb, bcb.Flags);
- US_DEBUGP("Bulk data transfer result 0x%x\n", result);
-#if 0
- if ((result < 0) && (result != USB_ST_DATAUNDERRUN)
- && (result != USB_ST_STALL)) {
- US_DEBUGP("Bulk data transfer result 0x%x\n", result);
- return DID_ABORT << 16;
- }
-#endif
+ 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 (DID_ABORT << 16);
+ 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 = 0x%x\n", result);
- return DID_ABORT << 16;
+ 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 DID_ABORT << 16;
+ return USB_STOR_TRANSPORT_ERROR;
}
-
+
/* based on the status code, we report good or bad */
switch (bcs.Status) {
case US_BULK_STAT_OK:
- /* if there is residue, we really didn't finish the command */
- if (bcs.Residue)
- return DID_ERROR << 16;
- else
- return DID_OK << 16;
+ /* command good -- note that we could be short on data */
+ return USB_STOR_TRANSPORT_GOOD;
case US_BULK_STAT_FAIL:
- return DID_ERROR << 16;
-
+ /* command failed */
+ return USB_STOR_TRANSPORT_FAILED;
+
case US_BULK_STAT_PHASE:
+ /* phase error */
Bulk_reset(us);
- return DID_ERROR << 16;
+ return USB_STOR_TRANSPORT_ERROR;
}
-
- return DID_OK << 16; /* check sense required */
+
+ /* we should never get here, but if we do, we're in trouble */
+ return USB_STOR_TRANSPORT_ERROR;
}
/***********************************************************************
@@ -1163,14 +1109,20 @@
usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
us->irq_handle = NULL;
}
- if (us->pusb_dev)
- usb_deregister(&storage_driver);
+
+ /* FIXME: release the interface claim here? */
+ // if (us->pusb_dev)
+ // usb_deregister(&storage_driver);
/* FIXME - leaves hanging host template copy */
/* (because scsi layer uses it after removal !!!) */
- while (prev->next != us)
- prev = prev->next;
- prev->next = us->next;
+ if (us_list == us)
+ us_list = us->next;
+ else {
+ while (prev->next != us)
+ prev = prev->next;
+ prev->next = us->next;
+ }
return 0;
}
@@ -1188,17 +1140,19 @@
struct us_data *us = (struct us_data *)srb->host->hostdata[0];
US_DEBUGP("Command wakeup\n");
- if (us->srb) {
- /* busy */
- }
srb->host_scribble = (unsigned char *)us;
- us->srb = srb;
+
+ /* get exclusive access to the structures we want */
+ down(&(us->queue_exclusion));
+
+ /* enqueue the command */
+ us->queue_srb = srb;
srb->scsi_done = done;
us->action = US_ACT_COMMAND;
/* wake up the process task */
-
- wake_up_interruptible(&us->waitq);
+ up(&(us->queue_exclusion));
+ up(&(us->sleeper));
return 0;
}
@@ -1209,6 +1163,7 @@
return 0;
}
+/* 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];
@@ -1340,11 +1295,11 @@
NULL, /* select_queue_depths */
1, /* can_queue */
-1, /* this_id */
- SG_ALL, /* sg_tablesize */
+ SG_ALL, /* sg_tablesize */
1, /* cmd_per_lun */
0, /* present */
- FALSE, /* unchecked_isa_dma */
- FALSE, /* use_clustering */
+ FALSE, /* unchecked_isa_dma */
+ TRUE, /* use_clustering */
TRUE, /* use_new_eh_code */
TRUE /* emulated */
};
@@ -1391,10 +1346,18 @@
siginfo_t info;
int unsigned long signr;
- interruptible_sleep_on(&us->waitq);
+ US_DEBUGP("*** thread sleeping.\n");
+ down(&(us->sleeper));
+ down(&(us->queue_exclusion));
+ US_DEBUGP("*** thread awakened.\n");
+ /* take the command off the queue */
action = us->action;
us->action = 0;
+ us->srb = us-> queue_srb;
+
+ /* release the queue lock as fast as possible */
+ up(&(us->queue_exclusion));
/* FIXME: we need to examine placment of break; and
* scsi_done() calls */
@@ -1460,29 +1423,20 @@
break;
} /* end switch on action */
-
+
+ /* FIXME: we ignore TERM and KILL... is this right? */
if (signal_pending(current)) {
/* sending SIGUSR1 makes us print out some info */
spin_lock_irq(¤t->sigmask_lock);
signr = dequeue_signal(¤t->blocked, &info);
spin_unlock_irq(¤t->sigmask_lock);
-
- if (signr == SIGUSR2) {
- usb_stor_debug = !usb_stor_debug;
- printk(USB_STORAGE "debug toggle = %d\n", usb_stor_debug);
- } else {
- break; /* exit the loop on any other signal */
- }
- }
- }
+ } /* if (singal_pending(current)) */
+ } /* for (;;) */
// MOD_DEC_USE_COUNT;
printk("usb_stor_control_thread exiting\n");
- /* FIXME: this is a hack to allow for debugging */
- // scsi_unregister_module(MODULE_SCSI_HA, us->htmplt);
-
return 0;
}
@@ -1498,7 +1452,6 @@
unsigned int flags = 0;
GUID(guid); /* Global Unique Identifier */
struct us_data *prev;
- Scsi_Host_Template *htmplt;
int protocol = 0;
int subclass = 0;
struct usb_interface_descriptor *altsetting =
@@ -1565,14 +1518,18 @@
return NULL;
}
memset(ss, 0, sizeof(struct us_data));
+
+ /* Initialize the mutexes only when the struct is new */
+ init_MUTEX_LOCKED(&(ss->sleeper));
+ init_MUTEX(&(ss->queue_exclusion));
}
- /* Initialize the us_data structure with some useful info */
+ /* establish the connection to the new device */
interface = altsetting;
ss->flags = flags;
ss->ifnum = ifnum;
- ss->pusb_dev = dev;
ss->attention_done = 0;
+ ss->pusb_dev = dev;
/* If the device has subclass and protocol, then use that. Otherwise,
* take data from the specific interface.
@@ -1596,7 +1553,7 @@
case US_PR_CBI:
US_DEBUGPX("Control/Bulk/Interrupt\n");
- ss->transport = CB_transport;
+ ss->transport = CBI_transport;
ss->transport_reset = CB_reset;
break;
@@ -1620,7 +1577,7 @@
*/
for (i = 0; i < interface->bNumEndpoints; i++) {
/* is it an BULK endpoint? */
- if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK) {
if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN)
ss->ep_in = interface->endpoint[i].bEndpointAddress &
@@ -1646,7 +1603,6 @@
(ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
US_DEBUGP("Problems with device\n");
if (ss->host) {
- scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt);
kfree(ss->htmplt->name);
kfree(ss->htmplt);
}
@@ -1667,11 +1623,13 @@
US_DEBUGP("Protocol: ");
switch (ss->subclass) {
case US_SC_RBC:
- US_DEBUGPX("Reduced Block Commands\n");
+ US_DEBUGPX("Reduced Block Commands (RBC)\n");
+ ss->proto_handler = transparent_scsi_command;
break;
case US_SC_8020:
- US_DEBUGPX("8020\n");
+ US_DEBUGPX("8020i\n");
+ ss->proto_handler = ATAPI_command;
break;
case US_SC_QIC:
@@ -1679,7 +1637,8 @@
break;
case US_SC_8070:
- US_DEBUGPX("8070\n");
+ US_DEBUGPX("8070i\n");
+ ss->proto_handler = ATAPI_command;
break;
case US_SC_SCSI:
@@ -1697,22 +1656,9 @@
break;
}
- /* We only handle certain protocols. Currently, these are
- *the only ones that devices use.
- */
- if ((ss->subclass != US_SC_SCSI) && (ss->subclass != US_SC_UFI)) {
- US_DEBUGP("Sorry, we do not support that protocol yet.\n");
- US_DEBUGP("If you have a device which uses one of the unsupported\n");
- US_DEBUGP("protocols, please contact mdharm-usb@one-eyed-alien.net\n");
-
- kfree(ss);
- return NULL;
- }
-
/* Allocate memory for the SCSI Host Template */
- if ((htmplt = (Scsi_Host_Template *)
- kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) {
-
+ if ((ss->htmplt = (Scsi_Host_Template *)
+ kmalloc(sizeof(Scsi_Host_Template),GFP_KERNEL))==NULL ) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
kfree(ss);
@@ -1720,7 +1666,7 @@
}
/* Initialize the host template based on the default one */
- memcpy(htmplt, &my_host_template, sizeof(my_host_template));
+ memcpy(ss->htmplt, &my_host_template, sizeof(my_host_template));
/* Grab the next host number */
ss->host_number = my_host_number++;
@@ -1729,32 +1675,34 @@
* can pass the ss pointer to the host controler thread
* in us_detect
*/
- (struct us_data *)htmplt->proc_dir = ss;
+ (struct us_data *)ss->htmplt->proc_dir = ss;
/* shuttle E-USB */
if (dev->descriptor.idVendor == 0x04e6 &&
dev->descriptor.idProduct == 0x0001) {
__u8 qstat[2];
int result;
-
- result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0),
+
+ result = usb_control_msg(ss->pusb_dev,
+ usb_rcvctrlpipe(dev,0),
1, 0xC0,
0, ss->ifnum,
qstat, 2, HZ*5);
US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
- init_waitqueue_head(&ss->ip_waitq);
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq,
- 255, (void *)ss, &ss->irq_handle);
- if (result)
+ result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
+ CBI_irq, 255, (void *)ss,
+ &ss->irq_handle);
+ if (result < 0)
return NULL;
-
- interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6);
- } else if (ss->protocol == US_PR_CBI)
- {
+ /* FIXME: what is this?? */
+ down(&(ss->ip_waitq));
+ } else if (ss->protocol == US_PR_CBI) {
int result;
-
- init_waitqueue_head(&ss->ip_waitq);
+
+ /* set up so we'll wait for notification */
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
/* set up the IRQ pipe and handler */
/* FIXME: This needs to get the period from the device */
@@ -1768,18 +1716,16 @@
}
- /* start up our thread */
+ /* start up our thread */
{
DECLARE_MUTEX_LOCKED(sem);
- init_waitqueue_head(&ss->waitq);
-
ss->notify = &sem;
ss->pid = kernel_thread(usb_stor_control_thread, ss,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (ss->pid < 0) {
printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n");
- kfree(htmplt);
+ kfree(ss->htmplt);
kfree(ss);
return NULL;
@@ -1790,17 +1736,16 @@
}
/* now register - our detect function will be called */
- scsi_register_module(MODULE_SCSI_HA, htmplt);
+ ss->htmplt->module = &__this_module;
+ scsi_register_module(MODULE_SCSI_HA, ss->htmplt);
/* put us in the list */
- prev = (struct us_data *)&us_list;
- while (prev->next)
- prev = prev->next;
- prev->next = ss;
+ ss->next = us_list;
+ us_list = ss;
}
- printk(KERN_INFO "WARNING: USB Mass Storage data integrity not assured\n");
- printk(KERN_INFO "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 ss;
}
@@ -1814,7 +1759,6 @@
return;
ss->pusb_dev = NULL;
- // MOD_DEC_USE_COUNT;
}
@@ -1824,8 +1768,6 @@
int __init usb_stor_init(void)
{
- // MOD_INC_USE_COUNT;
-
if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ;
printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n",
@@ -1844,6 +1786,14 @@
void __exit usb_stor_exit(void)
{
+ static struct us_data *ptr;
+
+ // FIXME: this needs to be put back to free _all_ the hosts
+ // for (ptr = us_list; ptr != NULL; ptr = ptr->next)
+ // scsi_unregister_module(MODULE_SCSI_HA, ptr->htmplt);
+ printk("MDD: us_list->htmplt is 0x%x\n", (unsigned int)(us_list->htmplt));
+ scsi_unregister_module(MODULE_SCSI_HA, us_list->htmplt);
+
usb_deregister(&storage_driver) ;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)