summaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-08-08 18:02:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-08-08 18:02:00 +0000
commit02f8110d6a247d53b489b29eec8a35c85e713c6b (patch)
tree9cb65032a35c2d1af581deaac73dfa2540b2fbdd /drivers/usb/storage
parentb62a3d8e8a9d02ff6f9103358b7a9c2c3d56c653 (diff)
Merge with Linux 2.4.0-test6-pre2.
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/protocol.c75
-rw-r--r--drivers/usb/storage/protocol.h3
-rw-r--r--drivers/usb/storage/scsiglue.c3
-rw-r--r--drivers/usb/storage/sddr09.c534
-rw-r--r--drivers/usb/storage/sddr09.h7
-rw-r--r--drivers/usb/storage/transport.c13
-rw-r--r--drivers/usb/storage/usb.c20
-rw-r--r--drivers/usb/storage/usb.h4
8 files changed, 504 insertions, 155 deletions
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 5e7a5a23b..aee6b420e 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: protocol.c,v 1.2 2000/07/19 17:21:39 groovyjava Exp $
+ * $Id: protocol.c,v 1.4 2000/08/01 22:01:19 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -50,9 +50,58 @@
#include "transport.h"
/***********************************************************************
+ * Helper routines
+ ***********************************************************************/
+
+/* 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
+ */
+void fix_inquiry_data(Scsi_Cmnd *srb)
+{
+ unsigned char *data_ptr;
+
+ /* verify that it's an INQUIRY command */
+ if (srb->cmnd[0] != INQUIRY)
+ return;
+
+ US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n");
+
+ /* find the location of the data */
+ if (srb->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) srb->request_buffer;
+ data_ptr = (unsigned char *) sg[0].address;
+ } else
+ data_ptr = (unsigned char *)srb->request_buffer;
+
+ /* Change the SCSI revision number */
+ data_ptr[2] |= 0x2;
+}
+
+/***********************************************************************
* Protocol routines
***********************************************************************/
+void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ /* Pad the ATAPI command with zeros
+ * NOTE: This only works because a Scsi_Cmnd struct field contains
+ * a unsigned char cmnd[12], so we know we have storage available
+ */
+ for (; srb->cmd_len<12; srb->cmd_len++)
+ srb->cmnd[srb->cmd_len] = 0;
+
+ /* set command length to 12 bytes */
+ srb->cmd_len = 12;
+
+ /* send the command to the transport layer */
+ usb_stor_invoke_transport(srb, us);
+
+ /* fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
+}
+
void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
{
int old_cmnd = 0;
@@ -65,7 +114,6 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
*/
/* Pad the ATAPI command with zeros */
-
for (; srb->cmd_len<12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
@@ -125,12 +173,8 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
usb_stor_scsiSense10to6(srb);
- /* 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;
- }
+ /* fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
}
@@ -224,12 +268,8 @@ void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us)
if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
usb_stor_scsiSense10to6(srb);
- /* 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;
- }
+ /* Fix the data for an INQUIRY, if necessary */
+ fix_inquiry_data(srb);
}
void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
@@ -300,10 +340,7 @@ void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
/* send the command to the transport layer */
usb_stor_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;
- }
+ /* fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
}
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
index 1a343af41..239d37983 100644
--- a/drivers/usb/storage/protocol.h
+++ b/drivers/usb/storage/protocol.h
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* Protocol Functions Header File
*
- * $Id: protocol.h,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ * $Id: protocol.h,v 1.2 2000/08/01 22:01:19 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -57,6 +57,7 @@
#define US_SC_MAX US_SC_SCSI
extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*);
+extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 25328669b..7517d63bc 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -1,13 +1,14 @@
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
- * $Id: scsiglue.c,v 1.6 2000/07/25 23:04:47 mdharm Exp $
+ * $Id: scsiglue.c,v 1.7 2000/07/28 20:33:18 gowdy Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
*
* Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com)
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 275712961..6bf9f1477 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -44,7 +44,7 @@ extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
unsigned int len, unsigned int *act_len);
-#define short_pack(b1,b2) ( ((u16)(b1)) | ( ((u16)(b2))<<8 ) )
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)
@@ -132,7 +132,7 @@ static int sddr09_send_control(struct us_data *us,
static int sddr09_raw_bulk(struct us_data *us,
int direction,
unsigned char *data,
- unsigned short len) {
+ unsigned int len) {
int result;
int act_len;
@@ -196,64 +196,38 @@ static int sddr09_raw_bulk(struct us_data *us,
*/
static int sddr09_bulk_transport(struct us_data *us,
- unsigned char *command,
- unsigned short command_len,
int direction,
unsigned char *data,
- unsigned short len,
+ unsigned int len,
int use_sg) {
int result = USB_STOR_TRANSPORT_GOOD;
int transferred = 0;
- unsigned char execute[8] = {
- 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
int i;
struct scatterlist *sg;
char string[64];
-/*
- if (command_len != 0) {
-
- // Fix up the command's data length
- command[6] = len&0xFF;
- command[7] = (len>>8)&0xFF;
-
- result = sddr09_send_control(us,
- execute,
- command,
- command_len);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
- }
-*/
if (len==0)
return USB_STOR_TRANSPORT_GOOD;
- /* transfer the data payload for the command, if there is any */
-
-
- if (command_len != 0)
- direction = (command[0]&0x80) ? SCSI_DATA_READ :
- SCSI_DATA_WRITE;
+ /* transfer the data */
if (direction == SCSI_DATA_WRITE) {
/* Debug-print the first 48 bytes of the write transfer */
if (!use_sg) {
- string[0] = 0;
+ strcpy(string, "wr: ");
for (i=0; i<len && i<48; i++) {
sprintf(string+strlen(string), "%02X ",
data[i]);
if ((i%16)==15) {
US_DEBUGP("%s\n", string);
- string[0] = 0;
+ strcpy(string, "wr: ");
}
}
- if (string[0]!=0)
+ if ((i%16)!=0)
US_DEBUGP("%s\n", string);
}
}
@@ -278,6 +252,25 @@ static int sddr09_bulk_transport(struct us_data *us,
}
}
+ if (direction == SCSI_DATA_READ) {
+
+ /* Debug-print the first 48 bytes of the read transfer */
+
+ if (!use_sg) {
+ strcpy(string, "rd: ");
+ for (i=0; i<len && i<48; i++) {
+ sprintf(string+strlen(string), "%02X ",
+ data[i]);
+ if ((i%16)==15) {
+ US_DEBUGP("%s\n", string);
+ strcpy(string, "rd: ");
+ }
+ }
+ if ((i%16)!=0)
+ US_DEBUGP("%s\n", string);
+ }
+ }
+
return result;
}
@@ -289,45 +282,142 @@ int sddr09_read_data(struct us_data *us,
int result;
unsigned char command[12] = {
- 0xe8, 0x20, MSB_of(address>>16),
- LSB_of(address>>16), MSB_of(address&0xFFFF),
- LSB_of(address&0xFFFF), 0, 0, 0, 0,
- MSB_of(sectors), LSB_of(sectors)
+ 0xe8, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
+ struct sddr09_card_info *info = (struct sddr09_card_info *)us->extra;
+ unsigned int lba;
+ unsigned int pba;
+ unsigned short page;
+ unsigned short pages;
+ unsigned char *buffer = NULL;
+ unsigned char *ptr;
+ struct scatterlist *sg = NULL;
+ int i;
+ int len;
+ int transferred;
- result = sddr09_send_control(us,
- usb_sndctrlpipe(us->pusb_dev,0),
- 0,
- 0x41,
- 0,
- 0,
- command,
- 12);
+ // If we're using scatter-gather, we have to create a new
+ // buffer to read all of the data in first, since a
+ // scatter-gather buffer could in theory start in the middle
+ // of a page, which would be bad. A developer who wants a
+ // challenge might want to write a limited-buffer
+ // version of this code.
+
+ len = sectors*info->pagesize;
+
+ if (use_sg) {
+ sg = (struct scatterlist *)content;
+ buffer = kmalloc(len, GFP_KERNEL);
+ if (buffer == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+ ptr = buffer;
+ } else
+ ptr = content;
+
+ // Figure out the initial LBA and page
+
+ pba = (address/info->pagesize)>>4;
+ lba = info->pba_to_lba[pba];
+ page = (address/info->pagesize)&0x0F;
+
+ // This could be made much more efficient by checking for
+ // contiguous LBA's. Another exercise left to the student.
+
+ while (sectors>0) {
+
+ pba = info->lba_to_pba[lba];
+
+ // Read as many sectors as possible in this block
+
+ pages = 0x10-page;
+ if (pages > sectors)
+ pages = sectors;
+
+ US_DEBUGP("Read %01X pages, from PBA %04X"
+ " (LBA %04X) page %01X\n",
+ pages, pba, lba, page);
+
+ address = ((pba<<4)+page)*info->pagesize;
+
+ // Unlike in the documentation, the address is in
+ // words of 2 bytes.
+
+ command[2] = MSB_of(address>>17);
+ command[3] = LSB_of(address>>17);
+ command[4] = MSB_of((address>>1)&0xFFFF);
+ command[5] = LSB_of((address>>1)&0xFFFF);
+
+ command[10] = MSB_of(pages);
+ command[11] = LSB_of(pages);
+
+ result = sddr09_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0,
+ 0x41,
+ 0,
+ 0,
+ command,
+ 12);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
+ US_DEBUGP("Result for send_control in read_data %d\n",
+ result);
+
+ if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (use_sg)
+ kfree(buffer);
+ return result;
+ }
- result = sddr09_bulk_transport(us,
- NULL, 0, SCSI_DATA_READ, content,
- sectors*512, use_sg);
+ result = sddr09_bulk_transport(us,
+ SCSI_DATA_READ, ptr,
+ pages*info->pagesize, 0);
- return result;
+ if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (use_sg)
+ kfree(buffer);
+ return result;
+ }
+
+ page = 0;
+ lba++;
+ sectors -= pages;
+ ptr += pages*info->pagesize;
+ }
+
+ if (use_sg) {
+ transferred = 0;
+ for (i=0; i<use_sg && transferred<len; i++) {
+ memcpy(sg[i].address, buffer+transferred,
+ len-transferred > sg[i].length ?
+ sg[i].length : len-transferred);
+ transferred += sg[i].length;
+ }
+ kfree(buffer);
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
}
int sddr09_read_control(struct us_data *us,
unsigned long address,
- unsigned short sectors,
+ unsigned short blocks,
unsigned char *content,
int use_sg) {
+ // Unlike in the documentation, the last two bytes are the
+ // number of blocks, not sectors.
+
int result;
unsigned char command[12] = {
0xe8, 0x21, MSB_of(address>>16),
LSB_of(address>>16), MSB_of(address&0xFFFF),
LSB_of(address&0xFFFF), 0, 0, 0, 0,
- MSB_of(sectors), LSB_of(sectors)
+ MSB_of(blocks), LSB_of(blocks)
};
+ US_DEBUGP("Read control address %08X blocks %04X\n",
+ address, blocks);
+
result = sddr09_send_control(us,
usb_sndctrlpipe(us->pusb_dev,0),
0,
@@ -336,13 +426,19 @@ int sddr09_read_control(struct us_data *us,
0,
command,
12);
+
+ US_DEBUGP("Result for send_control in read_control %d\n",
+ result);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
result = sddr09_bulk_transport(us,
- NULL, 0, SCSI_DATA_READ, content,
- sectors*64, use_sg);
+ SCSI_DATA_READ, content,
+ blocks*0x40, use_sg);
+
+ US_DEBUGP("Result for bulk read in read_control %d\n",
+ result);
return result;
}
@@ -373,7 +469,7 @@ int sddr09_read_deviceID(struct us_data *us,
return result;
result = sddr09_bulk_transport(us,
- NULL, 0, SCSI_DATA_READ, content,
+ SCSI_DATA_READ, content,
64, 0);
*manufacturerID = content[0];
@@ -389,7 +485,6 @@ int sddr09_read_status(struct us_data *us,
unsigned char command[12] = {
0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
- unsigned char content[2];
result = sddr09_send_control(us,
usb_sndctrlpipe(us->pusb_dev,0),
@@ -404,7 +499,7 @@ int sddr09_read_status(struct us_data *us,
return result;
result = sddr09_bulk_transport(us,
- NULL, 0, SCSI_DATA_READ, status,
+ SCSI_DATA_READ, status,
1, 0);
return result;
@@ -429,6 +524,154 @@ int sddr09_reset(struct us_data *us) {
return result;
}
+unsigned long sddr09_get_capacity(struct us_data *us,
+ unsigned int *pagesize) {
+
+ unsigned char manufacturerID;
+ unsigned char deviceID;
+ int result;
+
+ US_DEBUGP("Reading capacity...\n");
+
+ result = sddr09_read_deviceID(us,
+ &manufacturerID,
+ &deviceID);
+
+ US_DEBUGP("Result of read_deviceID is %d\n",
+ result);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return 0;
+
+ US_DEBUGP("Device ID = %02X\n", deviceID);
+ US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
+
+ *pagesize = 512;
+
+ switch (deviceID) {
+
+ case 0x6e: // 1MB
+ case 0xe8:
+ case 0xec:
+ *pagesize = 256;
+ return 0x00100000;
+
+ case 0x5d: // 2MB
+ case 0xea:
+ case 0x64:
+ if (deviceID!=0x5D)
+ *pagesize = 256;
+ return 0x00200000;
+
+ case 0xe3: // 4MB
+ case 0xe5:
+ case 0x6b:
+ case 0xd5:
+ return 0x00400000;
+
+ case 0xe6: // 8MB
+ case 0xd6:
+ return 0x00800000;
+
+ case 0x73: // 16MB
+ return 0x01000000;
+
+ case 0x75: // 32MB
+ return 0x02000000;
+
+ default: // unknown
+ return 0;
+
+ }
+}
+
+int sddr09_read_map(struct us_data *us) {
+
+ unsigned char *control;
+ struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
+ int numblocks;
+ int i;
+ unsigned char *ptr;
+ unsigned short lba;
+ unsigned char parity;
+ unsigned char fast_parity[16] = {
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0
+ };
+ int result;
+
+ if (!info->capacity)
+ return -1;
+
+ /* read 64 (2^6) bytes for every block (8192 (2^13) bytes)
+ of capacity:
+ 64*(capacity/8192) = capacity*(2^6)*(2^-13) =
+ capacity*2^(6-13) = capacity*(2^-7)
+ */
+
+ control = kmalloc(info->capacity>>7, GFP_KERNEL);
+
+
+ numblocks = info->capacity>>13;
+
+ if ( (result = sddr09_read_control(us, 0, numblocks,
+ control, 0)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ kfree(control);
+ return -1;
+ }
+
+
+
+ if (info->lba_to_pba)
+ kfree(info->lba_to_pba);
+ if (info->pba_to_lba)
+ kfree(info->pba_to_lba);
+ info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+ info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+ memset(info->lba_to_pba, 0, numblocks*sizeof(int));
+ memset(info->pba_to_lba, 0, numblocks*sizeof(int));
+
+ for (i=0; i<numblocks; i++) {
+ ptr = control+64*i;
+ if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF ||
+ ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF)
+ continue;
+ if ((ptr[6]>>4)!=0x01)
+ continue;
+
+ /* ensure even parity */
+
+ lba = short_pack(ptr[7], ptr[6]);
+ parity = 1; // the parity of 0x1000
+ parity ^= fast_parity[lba & 0x000F];
+ parity ^= fast_parity[(lba>>4) & 0x000F];
+ parity ^= fast_parity[(lba>>8) & 0x000F];
+
+ if (parity) { /* bad parity bit */
+ US_DEBUGP("Bad parity in LBA for block %04X\n", i);
+ continue;
+ }
+
+ lba = (lba&0x07FF)>>1;
+
+ if (lba>=numblocks) {
+ US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i);
+ continue;
+ }
+
+ if (i<0x10)
+ US_DEBUGP("LBA %04X <-> PBA %04X\n",
+ lba, i);
+
+ info->pba_to_lba[i] = lba;
+ info->lba_to_pba[lba] = i;
+ }
+
+ kfree(control);
+ return 0;
+}
+
/*
static int init_sddr09(struct us_data *us) {
@@ -477,15 +720,24 @@ static int init_sddr09(struct us_data *us) {
}
*/
+void sddr09_card_info_destructor(void *extra) {
+ struct sddr09_card_info *info = (struct sddr09_card_info *)extra;
+
+ if (!extra)
+ return;
+
+ if (info->lba_to_pba)
+ kfree(info->lba_to_pba);
+ if (info->pba_to_lba)
+ kfree(info->pba_to_lba);
+}
+
/*
* Transport for the Sandisk SDDR-09
*/
int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
{
int result;
- unsigned char send_scsi_command[8] = {
- 0x41, 0, 0, 0, 0, 0, 0, 0
- };
int i;
char string[64];
unsigned char inquiry_response[36] = {
@@ -495,9 +747,16 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
'e', ' ', 'S', 'D', 'D', 'R', '0', '9',
' ', ' ', ' ', ' '
};
- unsigned char deviceID;
- unsigned char manufacturerID;
+ unsigned char mode_page_01[12] = {
+ 0x01, 0x0a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
unsigned char *ptr;
+ unsigned long capacity;
+ unsigned int lba;
+ unsigned int pba;
+ unsigned int page;
+ unsigned short pages;
+ struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
/*
if (us->flags & US_FL_NEED_INIT) {
@@ -507,85 +766,116 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
}
*/
+ if (!us->extra) {
+ us->extra = kmalloc(
+ sizeof(struct sddr09_card_info), GFP_KERNEL);
+ memset(us->extra, 0, sizeof(struct sddr09_card_info));
+ us->extra_destructor = sddr09_card_info_destructor;
+ }
+
ptr = (unsigned char *)srb->request_buffer;
/* 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);
+ memcpy(ptr, inquiry_response, 36);
return USB_STOR_TRANSPORT_GOOD;
}
if (srb->cmnd[0] == READ_CAPACITY) {
- US_DEBUGP("Reading capacity...\n");
+ capacity = sddr09_get_capacity(us, &info->pagesize);
+ info->capacity = capacity;
- result = sddr09_read_deviceID(us,
- &manufacturerID,
- &deviceID);
+ // Last page in the card
- US_DEBUGP("Result of read_deviceID is %d\n",
- result);
+ capacity /= info->pagesize;
+ capacity--;
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
+ ptr[0] = MSB_of(capacity>>16);
+ ptr[1] = LSB_of(capacity>>16);
+ ptr[2] = MSB_of(capacity&0xFFFF);
+ ptr[3] = LSB_of(capacity&0xFFFF);
- US_DEBUGP("Device ID = %02X\n", deviceID);
- US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
-
- ptr[0] = 0;
- ptr[1] = 0;
- ptr[2] = 0;
- ptr[3] = 0;
-
- switch (deviceID) {
-
- case 0x6e: // 1MB
- case 0xe8:
- case 0xec:
- ptr[4] = 0;
- ptr[5] = 0x10;
- break;
-
- case 0xea: // 2MB
- case 0x64:
- case 0x5d:
- ptr[4] = 0;
- ptr[5] = 0x20;
- break;
-
- case 0xe3: // 4MB
- case 0xe5:
- case 0x6b:
- case 0xd5:
- ptr[4] = 0;
- ptr[5] = 0x40;
- break;
-
- case 0xe6: // 8MB
- case 0xd6:
- ptr[4] = 0;
- ptr[5] = 0x80;
- break;
-
- case 0x75: // 32MB
- ptr[4] = 0x02;
- ptr[5] = 0;
- break;
-
- default: // unknown
- ptr[4] = 0;
- ptr[5] = 0;
+ // The page size
- }
+ ptr[4] = MSB_of(info->pagesize>>16);
+ ptr[5] = LSB_of(info->pagesize>>16);
+ ptr[6] = MSB_of(info->pagesize&0xFFFF);
+ ptr[7] = LSB_of(info->pagesize&0xFFFF);
- ptr[6] = 0;
- ptr[7] = 0;
+ sddr09_read_map(us);
return USB_STOR_TRANSPORT_GOOD;
}
+ if (srb->cmnd[0] == MODE_SENSE) {
+
+ // Read-write error recovery page: there needs to
+ // be a check for write-protect here
+
+ if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
+ if (ptr==NULL || srb->request_bufflen<12)
+ return USB_STOR_TRANSPORT_ERROR;
+ memcpy(ptr, mode_page_01, 12);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ // FIXME: sense buffer?
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (srb->cmnd[0] == READ_10) {
+
+ page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+ page <<= 16;
+ page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+ pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+ // convert page to block and page-within-block
+
+ lba = page>>4;
+ page = page&0x0F;
+
+ // locate physical block corresponding to logical block
+
+ if (lba>=(info->capacity>>13)) {
+
+ // FIXME: sense buffer?
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ pba = info->lba_to_pba[lba];
+
+ // if pba is 0, either it's really 0, in which case
+ // the pba-to-lba map for pba 0 will be the lba,
+ // or that lba doesn't exist.
+
+ if (pba==0 && info->pba_to_lba[0] != lba) {
+
+ // FIXME: sense buffer?
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
+ " pages %d\n",
+ pba, lba, page, pages);
+
+ return sddr09_read_data(us,
+ ((pba<<4)+page)*info->pagesize, pages,
+ ptr, srb->use_sg);
+ }
+
+ // Pass TEST_UNIT_READY and REQUEST_SENSE through
+
+ if (srb->cmnd[0] != TEST_UNIT_READY &&
+ srb->cmnd[0] != REQUEST_SENSE)
+ return USB_STOR_TRANSPORT_ERROR; // FIXME: sense buffer?
+
for (; srb->cmd_len<12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
@@ -622,7 +912,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_bufflen);
result = sddr09_bulk_transport(us,
- NULL, 0, srb->sc_data_direction,
+ srb->sc_data_direction,
srb->request_buffer,
srb->request_bufflen, srb->use_sg);
diff --git a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h
index 76a749528..ecd9b7611 100644
--- a/drivers/usb/storage/sddr09.h
+++ b/drivers/usb/storage/sddr09.h
@@ -28,4 +28,11 @@
extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us);
+struct sddr09_card_info {
+ unsigned long capacity; /* Size of card in bytes */
+ int pagesize; /* Size of page in bytes */
+ int *lba_to_pba; /* logical to physical map */
+ int *pba_to_lba; /* physical to logical map */
+};
+
#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 69dfcfde8..a0fb2407c 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.4 2000/07/25 23:04:47 mdharm Exp $
+ * $Id: transport.c,v 1.5 2000/07/28 22:40:20 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -717,6 +717,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
return 0;
}
+int usb_stor_Bulk_reset(struct us_data *us);
+
int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
{
struct bulk_cb_wrap bcb;
@@ -820,7 +822,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
}
/* check bulk status */
- US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+ US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
le32_to_cpu(bcs.Signature), bcs.Tag,
bcs.Residue, bcs.Status);
if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
@@ -842,6 +844,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
case US_BULK_STAT_PHASE:
/* phase error */
+ usb_stor_Bulk_reset(us);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -883,11 +886,15 @@ int usb_stor_CB_reset(struct us_data *us)
return 0;
}
-/* FIXME: Does this work? */
+/* This issues a Bulk-only Reset to the device in question, including
+ * clearing the subsequent endpoint halts that may occur.
+ */
int usb_stor_Bulk_reset(struct us_data *us)
{
int result;
+ US_DEBUGP("Bulk reset requested\n");
+
result = usb_control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
US_BULK_RESET_REQUEST,
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index c82d7e914..fc70bc72a 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: usb.c,v 1.14 2000/07/27 14:42:43 groovyjava Exp $
+ * $Id: usb.c,v 1.16 2000/08/01 22:01:19 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -685,13 +685,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
case US_SC_QIC:
ss->protocol_name = "QIC-157";
- US_DEBUGP("Sorry, device not supported. Please\n");
- US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n");
- US_DEBUGP("if you see this message.\n");
- up(&us_list_semaphore);
- kfree(ss->current_urb);
- kfree(ss);
- return NULL;
+ ss->proto_handler = usb_stor_qic157_command;
break;
case US_SC_8070:
@@ -862,6 +856,16 @@ void __exit usb_stor_exit(void)
/* Now that scsi_unregister_module is done with the host
* template, we can free the us_data structure (the host
* template is inline in this structure). */
+
+ /* If there's extra data in the us_data structure then
+ * free that first */
+
+ if (us_list->extra) {
+ if (us_list->extra_destructor)
+ (*us_list->extra_destructor)(
+ us_list->extra);
+ kfree(us_list->extra);
+ }
kfree (us_list);
/* advance the list pointer */
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 8c7008fa9..b376d39ee 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* Main Header File
*
- * $Id: usb.h,v 1.3 2000/07/20 01:14:56 mdharm Exp $
+ * $Id: usb.h,v 1.4 2000/07/28 20:14:49 groovyjava Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -176,6 +176,8 @@ struct us_data {
/* mutual exclusion structures */
struct semaphore notify; /* thread begin/end */
struct semaphore queue_exclusion; /* to protect data structs */
+ void *extra; /* Any extra data */
+ void (*extra_destructor)(void *); /* extra data destructor */
};
/* The list of structures and the protective lock for them */