ChangeSet 1.1504.2.13, 2003/12/08 17:44:49-08:00, [EMAIL PROTECTED]

[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) {



-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id78&alloc_id371&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to