ChangeSet 1.1504.2.13, 2003/12/08 17:44:49-08:00, stern@rowland.harvard.edu [PATCH] USB storage: Enhance sddr09 to work with 64 MB SmartMedia cards This patch was written by Andries Brouwer. It adds to sddr09 the ability to use 64 MB SmartMedia cards. I have added a few minor alterations to make it fit in with my sequence of other patches. drivers/usb/storage/sddr09.c | 133 ++++++++++++++++++++++++------------------- 1 files changed, 77 insertions(+), 56 deletions(-) diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c Mon Dec 29 14:25:36 2003 +++ b/drivers/usb/storage/sddr09.c Mon Dec 29 14:25:36 2003 @@ -66,7 +66,7 @@ * NAND Flash Manufacturer ID Codes */ #define NAND_MFR_AMD 0x01 -#define NAND_MFR_NS 0x8f +#define NAND_MFR_NATSEMI 0x8f #define NAND_MFR_TOSHIBA 0x98 #define NAND_MFR_SAMSUNG 0xec @@ -74,8 +74,8 @@ switch(manuf_id) { case NAND_MFR_AMD: return "AMD"; - case NAND_MFR_NS: - return "NS"; + case NAND_MFR_NATSEMI: + return "NATSEMI"; case NAND_MFR_TOSHIBA: return "Toshiba"; case NAND_MFR_SAMSUNG: @@ -302,8 +302,7 @@ if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("request sense bulk in failed\n"); return USB_STOR_TRANSPORT_ERROR; - } - else { + } else { US_DEBUGP("request sense worked\n"); return USB_STOR_TRANSPORT_GOOD; } @@ -469,6 +468,8 @@ unsigned char *command = us->iobuf; int result; + US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress); + memset(command, 0, 12); command[0] = 0xEA; command[1] = LUNBITS; @@ -757,17 +758,27 @@ return result; } -/* we never free blocks, so lastpba can only increase */ static unsigned int -sddr09_find_unused_pba(struct sddr09_card_info *info) { +sddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) { static unsigned int lastpba = 1; - int numblocks = info->capacity >> (info->blockshift + info->pageshift); - int i; + int zonestart, end, i; + + zonestart = (lba/1000) << 10; + end = info->capacity >> (info->blockshift + info->pageshift); + end -= zonestart; + if (end > 1024) + end = 1024; - for (i = lastpba+1; i < numblocks; i++) { - if (info->pba_to_lba[i] == UNDEF) { + for (i = lastpba+1; i < end; i++) { + if (info->pba_to_lba[zonestart+i] == UNDEF) { lastpba = i; - return i; + return zonestart+i; + } + } + for (i = 0; i <= lastpba; i++) { + if (info->pba_to_lba[zonestart+i] == UNDEF) { + lastpba = i; + return zonestart+i; } } return 0; @@ -784,21 +795,23 @@ unsigned int pagelen, blocklen; unsigned char *blockbuffer, *bptr, *cptr, *xptr; unsigned char ecc[3]; - int i, result; + int i, result, isnew; - lbap = ((lba & 0x3ff) << 1) | 0x1000; + lbap = ((lba % 1000) << 1) | 0x1000; if (parity[MSB_of(lbap) ^ LSB_of(lbap)]) lbap ^= 1; pba = info->lba_to_pba[lba]; + isnew = 0; if (pba == UNDEF) { - pba = sddr09_find_unused_pba(info); + pba = sddr09_find_unused_pba(info, lba); if (!pba) { printk("sddr09_write_lba: Out of unused blocks\n"); return USB_STOR_TRANSPORT_ERROR; } info->pba_to_lba[pba] = lba; info->lba_to_pba[lba] = pba; + isnew = 1; } if (pba == 1) { @@ -823,8 +836,8 @@ if (result != USB_STOR_TRANSPORT_GOOD) goto err; - /* check old contents */ - for (i = 0; i < info->blockshift; i++) { + /* check old contents and fill lba */ + for (i = 0; i < info->blocksize; i++) { bptr = blockbuffer + i*pagelen; cptr = bptr + info->pagesize; nand_compute_ecc(bptr, ecc); @@ -839,6 +852,8 @@ i, pba); nand_store_ecc(cptr+8, ecc); } + cptr[6] = cptr[11] = MSB_of(lbap); + cptr[7] = cptr[12] = LSB_of(lbap); } /* copy in new stuff and compute ECC */ @@ -852,8 +867,6 @@ nand_store_ecc(cptr+13, ecc); nand_compute_ecc(bptr+(info->pagesize / 2), ecc); nand_store_ecc(cptr+8, ecc); - cptr[6] = cptr[11] = MSB_of(lbap); - cptr[7] = cptr[12] = LSB_of(lbap); } US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba); @@ -947,10 +960,11 @@ unsigned char *content, int use_sg) { - US_DEBUGP("Read control address %08lX blocks %04X\n", + US_DEBUGP("Read control address %lu, blocks %d\n", address, blocks); - return sddr09_read21(us, address, blocks, CONTROL_SHIFT, content, use_sg); + return sddr09_read21(us, address, blocks, + CONTROL_SHIFT, content, use_sg); } /* @@ -997,7 +1011,7 @@ US_DEBUGP("sddr09_get_wp: read_status fails\n"); return result; } - US_DEBUGP("sddr09_get_wp: status %02X", status); + US_DEBUGP("sddr09_get_wp: status 0x%02X", status); if ((status & 0x80) == 0) { info->flags |= SDDR09_WP; /* write protected */ US_DEBUGP(" WP"); @@ -1114,8 +1128,11 @@ alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT); alloc_len = (alloc_blocks << CONTROL_SHIFT); buffer = kmalloc(alloc_len, GFP_NOIO); - if (buffer == NULL) - return 0; + if (buffer == NULL) { + printk("sddr09_read_map: out of memory\n"); + result = -1; + goto done; + } buffer_end = buffer + alloc_len; #undef SDDR09_READ_MAP_BUFSZ @@ -1141,15 +1158,18 @@ for (i = 0; i < numblocks; i++) { ptr += (1 << CONTROL_SHIFT); if (ptr >= buffer_end) { - ptr = buffer; + unsigned long address; + + address = i << (info->pageshift + info->blockshift); result = sddr09_read_control( - us, i << (info->blockshift + 8), + us, address>>1, min(alloc_blocks, numblocks - i), buffer, 0); if (result != USB_STOR_TRANSPORT_GOOD) { result = -1; goto done; } + ptr = buffer; } if (i == 0 || i == 1) { @@ -1162,7 +1182,7 @@ if (ptr[j] != 0) goto nonz; info->pba_to_lba[i] = UNUSABLE; - printk("sddr09: PBA %04X has no logical mapping\n", i); + printk("sddr09: PBA %d has no logical mapping\n", i); continue; nonz: @@ -1175,7 +1195,7 @@ nonff: /* normal PBAs start with six FFs */ if (j < 6) { - printk("sddr09: PBA %04X has no logical mapping: " + printk("sddr09: PBA %d has no logical mapping: " "reserved area = %02X%02X%02X%02X " "data status %02X block status %02X\n", i, ptr[0], ptr[1], ptr[2], ptr[3], @@ -1185,7 +1205,7 @@ } if ((ptr[6] >> 4) != 0x01) { - printk("sddr09: PBA %04X has invalid address field " + printk("sddr09: PBA %d has invalid address field " "%02X%02X/%02X%02X\n", i, ptr[6], ptr[7], ptr[11], ptr[12]); info->pba_to_lba[i] = UNUSABLE; @@ -1194,7 +1214,7 @@ /* check even parity */ if (parity[ptr[6] ^ ptr[7]]) { - printk("sddr09: Bad parity in LBA for block %04X" + printk("sddr09: Bad parity in LBA for block %d" " (%02X %02X)\n", i, ptr[6], ptr[7]); info->pba_to_lba[i] = UNUSABLE; continue; @@ -1213,27 +1233,32 @@ */ if (lba >= 1000) { - unsigned long address; - - printk("sddr09: Bad LBA %04X for block %04X\n", + printk("sddr09: Bad low LBA %d for block %d\n", lba, i); - info->pba_to_lba[i] = UNDEF /* UNUSABLE */; - if (erase_bad_lba_entries) { - /* some cameras cannot erase a card if it has - bad entries, so we supply this function */ - address = (i << (info->pageshift + info->blockshift)); - sddr09_erase(us, address>>1); - } - continue; + goto possibly_erase; } lba += 1000*(i/0x400); - if (lba<0x10 || (lba >= 0x3E0 && lba < 0x3EF)) - US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i); + if (info->lba_to_pba[lba] != UNDEF) { + printk("sddr09: LBA %d seen for PBA %d and %d\n", + lba, info->lba_to_pba[lba], i); + goto possibly_erase; + } info->pba_to_lba[i] = lba; info->lba_to_pba[lba] = i; + continue; + + possibly_erase: + if (erase_bad_lba_entries) { + unsigned long address; + + address = (i << (info->pageshift + info->blockshift)); + sddr09_erase(us, address>>1); + info->pba_to_lba[i] = UNDEF; + } else + info->pba_to_lba[i] = UNUSABLE; } /* @@ -1410,6 +1435,7 @@ cardinfo = sddr09_get_cardinfo(us, info->flags); if (!cardinfo) { /* probably no media */ + init_error: sensekey = 0x02; /* not ready */ sensecode = 0x3a; /* medium not present */ return USB_STOR_TRANSPORT_FAILED; @@ -1423,7 +1449,10 @@ info->blockmask = info->blocksize - 1; // map initialization, must follow get_cardinfo() - sddr09_read_map(us); + if (sddr09_read_map(us)) { + /* probably out of memory */ + goto init_error; + } // Report capacity @@ -1444,12 +1473,13 @@ return USB_STOR_TRANSPORT_GOOD; } - if (srb->cmnd[0] == MODE_SENSE) { + if (srb->cmnd[0] == MODE_SENSE || srb->cmnd[0] == MODE_SENSE_10) { int modepage = (srb->cmnd[2] & 0x3F); int len; /* They ask for the Read/Write error recovery page, or for all pages. Give as much as they have room for. */ + /* %% We should check DBD %% */ if (modepage == 0x01 || modepage == 0x3F) { US_DEBUGP("SDDR09: Dummy up request for " @@ -1473,17 +1503,9 @@ return USB_STOR_TRANSPORT_FAILED; } - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - - US_DEBUGP( - "SDDR09: %s medium removal. Not that I can do" - " anything about it...\n", - (srb->cmnd[4]&0x03) ? "Prevent" : "Allow"); - + if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) return USB_STOR_TRANSPORT_GOOD; - } - havefakesense = 0; if (srb->cmnd[0] == READ_10) { @@ -1531,8 +1553,7 @@ for (i=0; i<12; i++) sprintf(string+strlen(string), "%02X ", srb->cmnd[i]); - US_DEBUGP("SDDR09: Send control for command %s\n", - string); + US_DEBUGP("SDDR09: Send control for command %s\n", string); result = sddr09_send_scsi_command(us, srb->cmnd, 12); if (result != USB_STOR_TRANSPORT_GOOD) {