summaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage/scm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/storage/scm.c')
-rw-r--r--drivers/usb/storage/scm.c461
1 files changed, 319 insertions, 142 deletions
diff --git a/drivers/usb/storage/scm.c b/drivers/usb/storage/scm.c
index 2d3ca7051..7bae5e623 100644
--- a/drivers/usb/storage/scm.c
+++ b/drivers/usb/storage/scm.c
@@ -1,6 +1,18 @@
/* Driver for SCM Microsystems USB-ATAPI cable
*
- * SCM driver v0.1
+ * $Id: scm.c,v 1.4 2000/07/24 19:19:52 mdharm Exp $
+ *
+ * SCM driver v0.2:
+ *
+ * Removed any reference to maxlen for bulk transfers.
+ * Changed scm_bulk_transport to allow for transfers without commands.
+ * Changed hp8200e transport to use the request_bufflen field in the
+ * SCSI command for the length of the transfer, rather than calculating
+ * it ourselves based on the command.
+ *
+ * SCM driver v0.1:
+ *
+ * First release - hp8200e.
*
* Current development and maintainance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
@@ -143,148 +155,118 @@ static int scm_send_control(struct us_data *us,
}
static int scm_raw_bulk(struct us_data *us,
- int pipe, int maxlen,
+ int direction,
unsigned char *data,
unsigned short len) {
- int transferred = 0;
int result;
int act_len;
- int partial_len;
- unsigned char status;
-
- maxlen = len;
-
- // while (transferred < len) {
-
- // We want to transfer up to maxlen bytes
-
- partial_len = len-transferred > maxlen ?
- maxlen :
- len-transferred;
-
- result = usb_stor_bulk_msg(us,
- data+transferred,
- pipe,
- partial_len,
- &act_len);
+ int pipe;
- /* if we stall, we need to clear it before we go on */
- if (result == -EPIPE) {
- US_DEBUGP("EPIPE: clearing endpoint halt for"
- " pipe 0x%x, stalled at %d bytes\n",
- pipe, act_len);
- usb_clear_halt(us->pusb_dev, pipe);
+ if (direction == SCSI_DATA_READ)
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
- // What the hey is goin' on?
+ result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
- /* US_DEBUGP("EPIPE: Trying to retransmit bulk data...\n");
+ /* if we stall, we need to clear it before we go on */
+ if (result == -EPIPE) {
+ US_DEBUGP("EPIPE: clearing endpoint halt for"
+ " pipe 0x%x, stalled at %d bytes\n",
+ pipe, act_len);
+ usb_clear_halt(us->pusb_dev, pipe);
+ }
- wait_ms(10);
-
- result = usb_stor_bulk_msg(us, data+act_len,
- pipe, len-act_len, &act_len);
+ if (result) {
- if (result==0)
- US_DEBUGP("EPIPE: Retransmit successful\n"); */
+ /* NAK - that means we've retried a few times already */
+ if (result == -ETIMEDOUT) {
+ US_DEBUGP("scm_raw_bulk():"
+ " device NAKed\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
- wait_ms(1000);
- US_DEBUGP("Trying to get status\n");
- result = scm_read(us, SCM_ATA, 0x17, &status);
- US_DEBUGP("SCM: Write ATA data status is %02X\n",
- status);
-
- result = -EPIPE;
- }
-
- if (result) {
-
- /* NAK - that means we've retried a few times already */
- if (result == -ETIMEDOUT) {
- US_DEBUGP("scm_raw_bulk():"
- " device NAKed\n");
- return US_BULK_TRANSFER_FAILED;
- }
-
- /* -ENOENT -- we canceled this transfer */
- if (result == -ENOENT) {
- US_DEBUGP("scm_raw_bulk():"
- " transfer aborted\n");
- return US_BULK_TRANSFER_ABORTED;
- }
-
- if (result == -EPIPE) {
- US_DEBUGP("scm_raw_bulk():"
- " output pipe stalled\n");
- return USB_STOR_TRANSPORT_FAILED;
- }
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("scm_raw_bulk():"
+ " transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
- /* the catch-all case */
- US_DEBUGP("us_transfer_partial(): unknown error\n");
- return US_BULK_TRANSFER_FAILED;
- }
-
- if (act_len != partial_len) {
- US_DEBUGP("Warning: Transferred only %d bytes\n",
- act_len);
- return US_BULK_TRANSFER_SHORT;
+ if (result == -EPIPE) {
+ US_DEBUGP("scm_raw_bulk():"
+ " output pipe stalled\n");
+ return USB_STOR_TRANSPORT_FAILED;
}
- US_DEBUGP("Transfered %d of %d bytes\n", act_len, partial_len);
+ /* the catch-all case */
+ US_DEBUGP("us_transfer_partial(): unknown error\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
+
+ if (act_len != len) {
+ US_DEBUGP("Warning: Transferred only %d bytes\n",
+ act_len);
+ return US_BULK_TRANSFER_SHORT;
+ }
- transferred += act_len;
- // } // while transferred < len
+ US_DEBUGP("Transfered %d of %d bytes\n", act_len, len);
return US_BULK_TRANSFER_GOOD;
}
+/*
+ * Note: direction must be set if command_len == 0.
+ */
+
static int scm_bulk_transport(struct us_data *us,
unsigned char *command,
unsigned short command_len,
+ int direction,
unsigned char *data,
unsigned short len,
int use_sg) {
- int result;
+ int result = USB_STOR_TRANSPORT_GOOD;
int transferred = 0;
- int maxlen;
unsigned char execute[8] = {
0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
int i;
- int pipe;
struct scatterlist *sg;
char string[64];
- maxlen = us->pusb_dev->actconfig->
- interface[0].altsetting[0].endpoint[
- ( (command[0]&0x80) ? us->ep_in : us->ep_out)-1].
- wMaxPacketSize;
+ if (command_len != 0) {
- /* Fix up the command's data length */
+ /* Fix up the command's data length */
- command[6] = len&0xFF;
- command[7] = (len>>8)&0xFF;
+ command[6] = len&0xFF;
+ command[7] = (len>>8)&0xFF;
- result = scm_send_control(us,
- execute,
- command,
- command_len);
+ result = scm_send_control(us,
+ execute,
+ command,
+ command_len);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+ }
if (len==0)
- return result;
+ return USB_STOR_TRANSPORT_GOOD;
+
/* transfer the data payload for the command, if there is any */
- if (command[0]&0x80)
- pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
- else {
- pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
- /* Debug-print the first 48 bytes of the transfer */
+ if (command_len != 0)
+ direction = (command[0]&0x80) ? SCSI_DATA_READ :
+ SCSI_DATA_WRITE;
+
+ if (direction == SCSI_DATA_WRITE) {
+
+ /* Debug-print the first 48 bytes of the write transfer */
if (!use_sg) {
string[0] = 0;
@@ -302,17 +284,16 @@ static int scm_bulk_transport(struct us_data *us,
}
- US_DEBUGP("HP 8200e data %s maxlen %d transfer %d sg buffers %d\n",
- ( (command[0]&0x80) ? "in" : "out"),
- maxlen, len, use_sg);
+ US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",
+ ( direction==SCSI_DATA_READ ? "in" : "out"),
+ len, use_sg);
if (!use_sg)
- result = scm_raw_bulk(us, pipe, maxlen,
- data, len);
+ result = scm_raw_bulk(us, direction, data, len);
else {
sg = (struct scatterlist *)data;
for (i=0; i<use_sg && transferred<len; i++) {
- result = scm_raw_bulk(us, pipe, maxlen,
+ result = scm_raw_bulk(us, direction,
sg[i].address,
len-transferred > sg[i].length ?
sg[i].length : len-transferred);
@@ -379,7 +360,7 @@ int scm_set_shuttle_features(struct us_data *us,
test_pattern, mask_byte, subcountL, subcountH
};
- result = scm_bulk_transport(us, command, 8, NULL, 0, 0);
+ result = scm_bulk_transport(us, command, 8, 0, NULL, 0, 0);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
@@ -400,7 +381,7 @@ int scm_read_block(struct us_data *us,
};
result = scm_bulk_transport(us,
- command, 8, content, len, use_sg);
+ command, 8, 0, content, len, use_sg);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
@@ -431,6 +412,8 @@ int scm_wait_not_busy(struct us_data *us) {
return result;
if (status&0x01) // check condition
return USB_STOR_TRANSPORT_FAILED;
+ if (status&0x20) // device fault
+ return USB_STOR_TRANSPORT_FAILED;
if ((status&0x80)!=0x80) // not busy
break;
if (i<5)
@@ -460,11 +443,9 @@ int scm_write_block(struct us_data *us,
unsigned char command[8] = {
0x40, access|0x03, reg, 0x00, 0x00, 0x00, 0x00, 0x00
};
- int i;
- unsigned char status;
result = scm_bulk_transport(us,
- command, 8, content, len, use_sg);
+ command, 8, 0, content, len, use_sg);
if (result!=USB_STOR_TRANSPORT_GOOD)
return result;
@@ -492,11 +473,8 @@ int scm_write_block_test(struct us_data *us,
qualifier, timeout, 0x00, 0x00
};
int i;
- unsigned char status;
unsigned char data[num_registers*2];
- int maxlen;
int transferred;
- int pipe;
struct scatterlist *sg;
char string[64];
@@ -509,16 +487,11 @@ int scm_write_block_test(struct us_data *us,
}
result = scm_bulk_transport(us,
- command, 16, data, num_registers*2, 0);
+ command, 16, 0, data, num_registers*2, 0);
if (result!=USB_STOR_TRANSPORT_GOOD)
return result;
- maxlen = us->pusb_dev->actconfig->
- interface[0].altsetting[0].endpoint[us->ep_out-1].
- wMaxPacketSize;
-
- pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
transferred = 0;
US_DEBUGP("Transfer out %d bytes, sg buffers %d\n",
@@ -528,28 +501,25 @@ int scm_write_block_test(struct us_data *us,
/* Debug-print the first 48 bytes of the transfer */
- if (!use_sg) {
- string[0] = 0;
- for (i=0; i<len && i<48; i++) {
- sprintf(string+strlen(string), "%02X ",
- content[i]);
- if ((i%16)==15) {
- US_DEBUGP("%s\n", string);
- string[0] = 0;
- }
- }
- if (string[0]!=0)
+ string[0] = 0;
+ for (i=0; i<len && i<48; i++) {
+ sprintf(string+strlen(string), "%02X ",
+ content[i]);
+ if ((i%16)==15) {
US_DEBUGP("%s\n", string);
+ string[0] = 0;
+ }
}
+ if (string[0]!=0)
+ US_DEBUGP("%s\n", string);
- result = scm_raw_bulk(us, pipe, maxlen,
- content, len);
+ result = scm_raw_bulk(us, SCSI_DATA_WRITE, content, len);
} else {
sg = (struct scatterlist *)content;
for (i=0; i<use_sg && transferred<len; i++) {
- result = scm_raw_bulk(us, pipe, maxlen,
+ result = scm_raw_bulk(us, SCSI_DATA_WRITE,
sg[i].address,
len-transferred > sg[i].length ?
sg[i].length : len-transferred);
@@ -577,14 +547,13 @@ int scm_multiple_write(struct us_data *us,
unsigned char cmd[8] = {
0x40, access|0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
- unsigned char status;
for (i=0; i<num_registers; i++) {
data[i<<1] = registers[i];
data[1+(i<<1)] = data_out[i];
}
- result = scm_bulk_transport(us, cmd, 8, data, num_registers*2, 0);
+ result = scm_bulk_transport(us, cmd, 8, 0, data, num_registers*2, 0);
if (result!=USB_STOR_TRANSPORT_GOOD)
return result;
@@ -679,6 +648,52 @@ int scm_write_user_io(struct us_data *us,
return result;
}
+static int init_sddr09(struct us_data *us) {
+
+ int result;
+ unsigned char data[14];
+ unsigned char command[8] = {
+ 0xc1, 0x01, 0, 0, 0, 0, 0, 0
+ };
+ unsigned char command2[8] = {
+ 0x41, 0, 0, 0, 0, 0, 0, 0
+ };
+ unsigned char tur[12] = {
+ 0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ if ( (result = scm_send_control(us, command, data, 2)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
+
+ command[1] = 0x08;
+
+ if ( (result = scm_send_control(us, command, data, 2)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
+/*
+ if ( (result = scm_send_control(us, command2, tur, 12)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ US_DEBUGP("SDDR09: request sense failed\n");
+ return result;
+ }
+
+ if ( (result = scm_raw_bulk(
+ us, SCSI_DATA_READ, data, 14)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ US_DEBUGP("SDDR09: request sense bulk in failed\n");
+ return result;
+ }
+
+ US_DEBUGP("SDDR09: request sense worked\n");
+*/
+ return result;
+}
+
static int init_8200e(struct us_data *us) {
int result;
@@ -810,18 +825,15 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us)
"XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */
"XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
- /* FIXME: B9 (READ CD MSF) has unknown length! */
-
- /* US_DEBUGP("XXXXXXXX 8200e transport called, tid %08X\n",
- current->pid); */
-
if (us->flags & US_FL_NEED_INIT) {
US_DEBUGP("8200e: initializing\n");
init_8200e(us);
us->flags &= ~US_FL_NEED_INIT;
}
- if (srb->sc_data_direction == SCSI_DATA_WRITE)
+ len = srb->request_bufflen;
+
+/* if (srb->sc_data_direction == SCSI_DATA_WRITE)
len = srb->request_bufflen;
else {
@@ -863,12 +875,17 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us)
case 'W':
len = 24;
break;
+ case 'B':
+ // Let's try using the command structure's
+ // request_bufflen here
+ len = srb->request_bufflen;
+ break;
default:
US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
srb->cmnd[0]);
return USB_STOR_TRANSPORT_ERROR;
}
- }
+ } */
if (len > 0xFFFF) {
US_DEBUGP("Error: len = %08X... what do I do now?\n",
@@ -977,3 +994,163 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us)
return result;
}
+
+
+/*
+ * Transport for the Sandisk SDDR-09
+ */
+int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+ unsigned int len;
+ unsigned char send_scsi_command[8] = {
+ 0x41, 0, 0, 0, 0, 0, 0, 0
+ };
+ int i;
+ char string[64];
+ unsigned char *ptr;
+ unsigned char inquiry_response[36] = {
+ 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00,
+ 'S', 'a', 'n', 'D', 'i', 's', 'k', ' ',
+ 'I', 'm', 'a', 'g', 'e', 'M', 'a', 't',
+ 'e', ' ', 'S', 'D', 'D', 'R', '0', '9',
+ ' ', ' ', ' ', ' '
+ };
+
+ /* This table tells us:
+ X = command not supported
+ L = return length in cmnd[4] (8 bits).
+ H = return length in cmnd[7] and cmnd[8] (16 bits).
+ D = return length in cmnd[6] to cmnd[9] (32 bits).
+ B = return length/blocksize in cmnd[6] to cmnd[8].
+ T = return length in cmnd[6] to cmnd[8] (24 bits).
+ 0-9 = fixed return length
+ W = 24 bytes
+ h = return length/2048 in cmnd[7-8].
+ */
+
+ static char *lengths =
+
+ /* 0123456789ABCDEF 0123456789ABCDEF */
+
+ "0XXL0XXXXXXXXXXX" "XXLXXXXXXXX0XX0X" /* 00-1F */
+ "XXXXX8XXhXH0XXX0" "XXXXX0XXXXXXXXXX" /* 20-3F */
+ "XXHHL0X0XXH0XX0X" "XHH00HXX0TH0H0XX" /* 40-5F */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */
+ "X0XXX0XXDXDXXXXX" "XXXXXXXXX000XHBX" /* A0-BF */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */
+ "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
+
+ if (us->flags & US_FL_NEED_INIT) {
+ US_DEBUGP("SDDR-09: initializing\n");
+ init_sddr09(us);
+ us->flags &= ~US_FL_NEED_INIT;
+ }
+
+ /* if (srb->sc_data_direction == SCSI_DATA_WRITE) */
+ len = srb->request_bufflen;
+ /* else {
+
+ switch (lengths[srb->cmnd[0]]) {
+
+ case 'L':
+ len = srb->cmnd[4];
+ 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 'H':
+ len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
+ break;
+ case 'h':
+ len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
+ len <<= 11; // *2048
+ break;
+ case 'T':
+ len = (((unsigned int)srb->cmnd[6])<<16) |
+ (((unsigned int)srb->cmnd[7])<<8) |
+ srb->cmnd[8];
+ 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 'W':
+ len = 24;
+ break;
+ case 'B':
+ // Let's try using the command structure's
+ // request_bufflen here
+ len = srb->request_bufflen;
+ break;
+ default:
+ US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
+ srb->cmnd[0]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ } */
+
+ if (srb->request_bufflen > 0xFFFF) {
+ US_DEBUGP("Error: len = %08X... what do I do now?\n",
+ len);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* Dummy up a response for INQUIRY since SDDR09 doesn't
+ respond to INQUIRY commands */
+
+ if (srb->cmnd[0] == INQUIRY) {
+ memcpy(srb->request_buffer, inquiry_response, 36);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ for (; srb->cmd_len<12; srb->cmd_len++)
+ srb->cmnd[srb->cmd_len] = 0;
+
+ srb->cmnd[1] = 0x20;
+
+ string[0] = 0;
+ for (i=0; i<12; i++)
+ sprintf(string+strlen(string), "%02X ", srb->cmnd[i]);
+
+ US_DEBUGP("SDDR09: Send control for command %s\n",
+ string);
+
+ if ( (result = scm_send_control(us, send_scsi_command,
+ srb->cmnd, 12)) != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("SDDR09: Control for command OK\n");
+
+ if (srb->sc_data_direction == SCSI_DATA_WRITE ||
+ srb->sc_data_direction == SCSI_DATA_READ) {
+
+ US_DEBUGP("SDDR09: %s %d bytes\n",
+ srb->sc_data_direction==SCSI_DATA_WRITE ?
+ "sending" : "receiving",
+ len);
+
+ result = scm_bulk_transport(us,
+ NULL, 0, srb->sc_data_direction,
+ srb->request_buffer,
+ len, srb->use_sg);
+
+ return result;
+
+ }
+
+ return result;
+}
+