patch-2.4.0-test12 linux/drivers/usb/storage/transport.c
Next file: linux/drivers/usb/storage/usb.c
Previous file: linux/drivers/usb/storage/shuttle_usbat.c
Back to the patch index
Back to the overall index
- Lines: 539
- Date:
Tue Nov 28 21:50:07 2000
- Orig file:
v2.4.0-test11/linux/drivers/usb/storage/transport.c
- Orig date:
Sun Nov 19 18:44:17 2000
diff -u --recursive --new-file v2.4.0-test11/linux/drivers/usb/storage/transport.c linux/drivers/usb/storage/transport.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.32 2000/11/03 00:18:04 mdharm Exp $
+ * $Id: transport.c,v 1.38 2000/11/21 00:52:10 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -90,9 +90,9 @@
*/
static char *lengths =
-
+
/* 0123456789ABCDEF 0123456789ABCDEF */
-
+
"00XLZ6XZBXBBXXXB" "00LBBLG0R0L0GG0X" /* 00-1F */
"XXXXT8XXB4B0BBBB" "ZZZ0B00HCSSZTBHH" /* 20-3F */
"M0HHB0X000H0HH0X" "XHH0HHXX0TH0H0XX" /* 40-5F */
@@ -213,129 +213,129 @@
*/
if (srb->sc_data_direction == SCSI_DATA_WRITE) {
- doDefault = 1;
+ doDefault = 1;
}
else
switch (lengths[srb->cmnd[0]]) {
- case 'L':
- len = srb->cmnd[4];
- break;
-
- case 'M':
- len = srb->cmnd[8];
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- len = lengths[srb->cmnd[0]]-'0';
- break;
-
- case 'G':
- len = (((unsigned int)srb->cmnd[3])<<8) |
- srb->cmnd[4];
- break;
-
- case 'H':
- len = (((unsigned int)srb->cmnd[7])<<8) |
- srb->cmnd[8];
- break;
-
- case 'I':
- len = (((unsigned int)srb->cmnd[8])<<8) |
- srb->cmnd[9];
- break;
-
- case 'R':
- len = (((unsigned int)srb->cmnd[2])<<16) |
- (((unsigned int)srb->cmnd[3])<<8) |
- srb->cmnd[4];
- break;
-
- case 'S':
- len = (((unsigned int)srb->cmnd[3])<<16) |
- (((unsigned int)srb->cmnd[4])<<8) |
- srb->cmnd[5];
- break;
-
- case 'T':
- len = (((unsigned int)srb->cmnd[6])<<16) |
- (((unsigned int)srb->cmnd[7])<<8) |
- srb->cmnd[8];
- break;
-
- case 'U':
- len = (((unsigned int)srb->cmnd[7])<<16) |
- (((unsigned int)srb->cmnd[8])<<8) |
- srb->cmnd[9];
- break;
-
- case 'C':
- len = (((unsigned int)srb->cmnd[2])<<24) |
- (((unsigned int)srb->cmnd[3])<<16) |
- (((unsigned int)srb->cmnd[4])<<8) |
- srb->cmnd[5];
- break;
-
- case 'D':
- len = (((unsigned int)srb->cmnd[6])<<24) |
- (((unsigned int)srb->cmnd[7])<<16) |
- (((unsigned int)srb->cmnd[8])<<8) |
- srb->cmnd[9];
- break;
-
- case 'V':
- len = 20;
- break;
-
- case 'W':
- len = 24;
- break;
-
- case 'B':
- /* Use buffer size due to different block sizes */
- doDefault = 1;
- break;
-
- case 'X':
- US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
- srb->cmnd[0]);
- doDefault = 1;
- break;
-
- case 'Z':
- /* Use buffer size due to mode dependence */
- doDefault = 1;
- break;
-
- default:
- US_DEBUGP("Error: COMMAND %02X out of range or table inconsistent (%c).\n",
- srb->cmnd[0], lengths[srb->cmnd[0]] );
- doDefault = 1;
+ case 'L':
+ len = srb->cmnd[4];
+ break;
+
+ case 'M':
+ len = srb->cmnd[8];
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ len = lengths[srb->cmnd[0]]-'0';
+ break;
+
+ case 'G':
+ len = (((unsigned int)srb->cmnd[3])<<8) |
+ srb->cmnd[4];
+ break;
+
+ case 'H':
+ len = (((unsigned int)srb->cmnd[7])<<8) |
+ srb->cmnd[8];
+ break;
+
+ case 'I':
+ len = (((unsigned int)srb->cmnd[8])<<8) |
+ srb->cmnd[9];
+ break;
+
+ case 'R':
+ len = (((unsigned int)srb->cmnd[2])<<16) |
+ (((unsigned int)srb->cmnd[3])<<8) |
+ srb->cmnd[4];
+ break;
+
+ case 'S':
+ len = (((unsigned int)srb->cmnd[3])<<16) |
+ (((unsigned int)srb->cmnd[4])<<8) |
+ srb->cmnd[5];
+ break;
+
+ case 'T':
+ len = (((unsigned int)srb->cmnd[6])<<16) |
+ (((unsigned int)srb->cmnd[7])<<8) |
+ srb->cmnd[8];
+ break;
+
+ case 'U':
+ len = (((unsigned int)srb->cmnd[7])<<16) |
+ (((unsigned int)srb->cmnd[8])<<8) |
+ srb->cmnd[9];
+ break;
+
+ case 'C':
+ len = (((unsigned int)srb->cmnd[2])<<24) |
+ (((unsigned int)srb->cmnd[3])<<16) |
+ (((unsigned int)srb->cmnd[4])<<8) |
+ srb->cmnd[5];
+ break;
+
+ case 'D':
+ len = (((unsigned int)srb->cmnd[6])<<24) |
+ (((unsigned int)srb->cmnd[7])<<16) |
+ (((unsigned int)srb->cmnd[8])<<8) |
+ srb->cmnd[9];
+ break;
+
+ case 'V':
+ len = 20;
+ break;
+
+ case 'W':
+ len = 24;
+ break;
+
+ case 'B':
+ /* Use buffer size due to different block sizes */
+ doDefault = 1;
+ break;
+
+ case 'X':
+ US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
+ srb->cmnd[0]);
+ doDefault = 1;
+ break;
+
+ case 'Z':
+ /* Use buffer size due to mode dependence */
+ doDefault = 1;
+ break;
+
+ default:
+ US_DEBUGP("Error: COMMAND %02X out of range or table inconsistent (%c).\n",
+ srb->cmnd[0], lengths[srb->cmnd[0]] );
+ doDefault = 1;
}
- if ( doDefault == 1 ) {
- /* Are we going to scatter gather? */
- if (srb->use_sg) {
- /* Add up the sizes of all the sg segments */
- sg = (struct scatterlist *) srb->request_buffer;
- for (i = 0; i < srb->use_sg; i++)
- total += sg[i].length;
- len = total;
- }
- else
- /* Just return the length of the buffer */
- len = srb->request_bufflen;
- }
+ if ( doDefault == 1 ) {
+ /* Are we going to scatter gather? */
+ if (srb->use_sg) {
+ /* Add up the sizes of all the sg segments */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ total += sg[i].length;
+ len = total;
+ }
+ else
+ /* Just return the length of the buffer */
+ len = srb->request_bufflen;
+ }
- return len;
+return len;
}
/* This is a version of usb_clear_halt() that doesn't read the status from
@@ -423,7 +423,7 @@
if (status) {
/* something went wrong */
up(&(us->current_urb_sem));
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&wqh, &wait);
kfree(dr);
return status;
@@ -481,7 +481,7 @@
if (status) {
/* something went wrong */
up(&(us->current_urb_sem));
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&wqh, &wait);
return status;
}
@@ -538,7 +538,7 @@
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
clear_halt(us->pusb_dev, pipe);
}
-
+
/* did we send all the data? */
if (partial == length) {
US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n");
@@ -824,24 +824,44 @@
US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
US_DEBUGP("-- IRQ state is %d\n", urb->status);
+ US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
+ us->irqbuf[0], us->irqbuf[1]);
+
+ /* reject improper IRQs */
+ if (urb->actual_length != 2) {
+ US_DEBUGP("-- IRQ too short\n");
+ return;
+ }
/* is the device removed? */
- if (urb->status != -ENOENT) {
- /* save the data for interpretation later */
- US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
- ((unsigned char*)urb->transfer_buffer)[0],
- ((unsigned char*)urb->transfer_buffer)[1]);
+ if (urb->status == -ENOENT) {
+ US_DEBUGP("-- device has been removed\n");
+ return;
+ }
+ /* was this a command-completion interrupt? */
+ if (us->irqbuf[0] && (us->subclass != US_SC_UFI)) {
+ US_DEBUGP("-- not a command-completion IRQ\n");
+ return;
+ }
- /* was this a wanted interrupt? */
- if (atomic_read(us->ip_wanted)) {
- atomic_set(us->ip_wanted, 0);
- US_DEBUGP("-- Current value of ip_waitq is: %d\n", atomic_read(&us->ip_waitq.count));
- up(&(us->ip_waitq));
- } else
- US_DEBUGP("ERROR: Unwanted interrupt received!\n");
- } else
- US_DEBUGP("-- device has been removed\n");
+ /* was this a wanted interrupt? */
+ if (!atomic_read(us->ip_wanted)) {
+ US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+ return;
+ }
+
+ /* adjust the flag */
+ atomic_set(us->ip_wanted, 0);
+
+ /* copy the valid data */
+ us->irqdata[0] = us->irqbuf[0];
+ us->irqdata[1] = us->irqbuf[1];
+
+ /* wake up the command thread */
+ US_DEBUGP("-- Current value of ip_waitq is: %d\n",
+ atomic_read(&us->ip_waitq.count));
+ up(&(us->ip_waitq));
}
int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
@@ -903,18 +923,17 @@
/* go to sleep until we get this interrupt */
US_DEBUGP("Current value of ip_waitq is: %d\n", atomic_read(&us->ip_waitq.count));
down(&(us->ip_waitq));
-
+
/* if we were woken up by an abort instead of the actual interrupt */
if (atomic_read(us->ip_wanted)) {
US_DEBUGP("Did not get interrupt on CBI\n");
atomic_set(us->ip_wanted, 0);
return USB_STOR_TRANSPORT_ABORTED;
}
-
+
US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
- ((unsigned char*)us->irq_urb->transfer_buffer)[0],
- ((unsigned char*)us->irq_urb->transfer_buffer)[1]);
-
+ us->irqdata[0], us->irqdata[1]);
+
/* UFI gives us ASC and ASCQ, like a request sense
*
* REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
@@ -932,22 +951,24 @@
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
*/
- if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) {
- US_DEBUGP("CBI IRQ data showed reserved bType\n");
+ if (us->irqdata[0]) {
+ US_DEBUGP("CBI IRQ data showed reserved bType %d\n",
+ us->irqdata[0]);
return USB_STOR_TRANSPORT_ERROR;
}
- switch (((unsigned char*)us->irq_urb->transfer_buffer)[1] & 0x0F) {
- case 0x00:
- return USB_STOR_TRANSPORT_GOOD;
- case 0x01:
- return USB_STOR_TRANSPORT_FAILED;
- default:
- return USB_STOR_TRANSPORT_ERROR;
+
+ switch (us->irqdata[1] & 0x0F) {
+ case 0x00:
+ return USB_STOR_TRANSPORT_GOOD;
+ case 0x01:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
}
/* we should never get here, but if we do, we're in trouble */
@@ -1056,7 +1077,7 @@
/* if the device was removed, then we're already reset */
if (!us->pusb_dev)
return SUCCESS;
-
+
/* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb));
@@ -1066,14 +1087,14 @@
if (us->flags & US_FL_SCM_MULT_TARG)
bcb.Lun |= srb->target << 4;
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 Trg %d LUN %d L %d F %d CL %d\n",
le32_to_cpu(bcb.Signature), bcb.Tag,
@@ -1082,7 +1103,7 @@
result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN,
&partial);
US_DEBUGP("Bulk command transfer result=%d\n", result);
-
+
/* if the command was aborted, indicate that */
if (result == -ENOENT)
return USB_STOR_TRANSPORT_ABORTED;
@@ -1095,7 +1116,7 @@
/* unknown error -- we've got a problem */
return USB_STOR_TRANSPORT_ERROR;
}
-
+
/* if the command transfered well, then we go to the data stage */
if (result == 0) {
/* send/receive data payload, if there is any */
@@ -1109,14 +1130,14 @@
return USB_STOR_TRANSPORT_ABORTED;
}
}
-
+
/* 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 */
US_DEBUGP("Attempting to get CSW...\n");
result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN,
@@ -1139,7 +1160,7 @@
/* if the command was aborted, indicate that */
if (result == -ENOENT)
return USB_STOR_TRANSPORT_ABORTED;
-
+
/* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) {
US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
@@ -1147,13 +1168,13 @@
return USB_STOR_TRANSPORT_ERROR;
}
}
-
+
/* if we still have a failure at this point, we're in trouble */
US_DEBUGP("Bulk status result = %d\n", result);
if (result) {
return USB_STOR_TRANSPORT_ERROR;
}
-
+
/* check bulk status */
US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
le32_to_cpu(bcs.Signature), bcs.Tag,
@@ -1164,24 +1185,24 @@
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 -- note that a transport reset will be
- * invoked by the invoke_transport() function
- */
- return USB_STOR_TRANSPORT_ERROR;
+ case US_BULK_STAT_OK:
+ /* command good -- note that data could be short */
+ return USB_STOR_TRANSPORT_GOOD;
+
+ case US_BULK_STAT_FAIL:
+ /* command failed */
+ return USB_STOR_TRANSPORT_FAILED;
+
+ case US_BULK_STAT_PHASE:
+ /* phase error -- note that a transport reset will be
+ * invoked by the invoke_transport() function
+ */
+ return USB_STOR_TRANSPORT_ERROR;
}
-
+
/* we should never get here, but if we do, we're in trouble */
return USB_STOR_TRANSPORT_ERROR;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)