diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-08-08 18:02:00 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-08-08 18:02:00 +0000 |
commit | 02f8110d6a247d53b489b29eec8a35c85e713c6b (patch) | |
tree | 9cb65032a35c2d1af581deaac73dfa2540b2fbdd /drivers/usb/storage | |
parent | b62a3d8e8a9d02ff6f9103358b7a9c2c3d56c653 (diff) |
Merge with Linux 2.4.0-test6-pre2.
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r-- | drivers/usb/storage/protocol.c | 75 | ||||
-rw-r--r-- | drivers/usb/storage/protocol.h | 3 | ||||
-rw-r--r-- | drivers/usb/storage/scsiglue.c | 3 | ||||
-rw-r--r-- | drivers/usb/storage/sddr09.c | 534 | ||||
-rw-r--r-- | drivers/usb/storage/sddr09.h | 7 | ||||
-rw-r--r-- | drivers/usb/storage/transport.c | 13 | ||||
-rw-r--r-- | drivers/usb/storage/usb.c | 20 | ||||
-rw-r--r-- | drivers/usb/storage/usb.h | 4 |
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 */ |