ChangeSet 1.1504.2.16, 2003/12/08 17:45:52-08:00, [EMAIL PROTECTED]

[PATCH] USB storage: Change sddr09 to use the new s-g access routine

This patch updates the sddr09 driver to use the new scatter-gather access
routine.  After installing it, the user who experienced memory access
violations says everything is now working properly.


 drivers/usb/storage/sddr09.c |  125 ++++++++++++++++++++++++-------------------
 1 files changed, 70 insertions(+), 55 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:16 2003
+++ b/drivers/usb/storage/sddr09.c      Mon Dec 29 14:25:16 2003
@@ -28,7 +28,6 @@
  */
 
 #include "transport.h"
-#include "raw_bulk.h"
 #include "protocol.h"
 #include "usb.h"
 #include "debug.h"
@@ -664,30 +663,27 @@
 sddr09_read_data(struct us_data *us,
                 unsigned long address,
                 unsigned int sectors,
-                unsigned char *content,
+                unsigned char *buffer,
                 int use_sg) {
 
        struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
        unsigned int lba, maxlba, pba;
        unsigned int page, pages;
-       unsigned char *buffer = NULL;
-       unsigned char *ptr;
-       int result, len;
-
-       // 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;
+       unsigned int len, index, offset;
+       int result;
 
-       buffer = (use_sg ? kmalloc(len, GFP_NOIO) : content);
-       if (buffer == NULL)
-               return USB_STOR_TRANSPORT_ERROR;
+       // Since we only read in one block at a time, we have to create
+       // a bounce buffer if the transfer uses scatter-gather.
 
-       ptr = buffer;
+       if (use_sg) {
+               len = min(sectors, (unsigned int) info->blocksize) *
+                               info->pagesize;
+               buffer = kmalloc(len, GFP_NOIO);
+               if (buffer == NULL) {
+                       printk("sddr09_read_data: Out of memory\n");
+                       return USB_STOR_TRANSPORT_ERROR;
+               }
+       }
 
        // Figure out the initial LBA and page
        lba = address >> info->blockshift;
@@ -698,13 +694,13 @@
        // contiguous LBA's. Another exercise left to the student.
 
        result = USB_STOR_TRANSPORT_GOOD;
+       index = offset = 0;
 
        while (sectors > 0) {
 
                /* Find number of pages we can read in this block */
-               pages = info->blocksize - page;
-               if (pages > sectors)
-                       pages = sectors;
+               pages = min(sectors, info->blocksize - page);
+               len = pages << info->pageshift;
 
                /* Not overflowing capacity? */
                if (lba >= maxlba) {
@@ -727,7 +723,7 @@
                           Instead of returning USB_STOR_TRANSPORT_ERROR
                           it is better to return all zero data. */
 
-                       memset(ptr, 0, pages << info->pageshift);
+                       memset(buffer, 0, len);
 
                } else {
                        US_DEBUGP("Read %d pages, from PBA %d"
@@ -738,20 +734,21 @@
                                info->pageshift;
 
                        result = sddr09_read20(us, address>>1,
-                                              pages, info->pageshift, ptr, 0);
+                                       pages, info->pageshift, buffer, 0);
                        if (result != USB_STOR_TRANSPORT_GOOD)
                                break;
                }
+               if (use_sg)
+                       usb_stor_access_xfer_buf(buffer, len, us->srb,
+                                       &index, &offset, TO_XFER_BUF);
+               else
+                       buffer += len;
 
                page = 0;
                lba++;
                sectors -= pages;
-               ptr += (pages << info->pageshift);
        }
 
-       if (use_sg && result == USB_STOR_TRANSPORT_GOOD)
-               us_copy_to_sgbuf_all(buffer, len, content, use_sg);
-
        if (use_sg)
                kfree(buffer);
 
@@ -787,13 +784,13 @@
 static int
 sddr09_write_lba(struct us_data *us, unsigned int lba,
                 unsigned int page, unsigned int pages,
-                unsigned char *ptr) {
+                unsigned char *ptr, unsigned char *blockbuffer) {
 
        struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
        unsigned long address;
        unsigned int pba, lbap;
-       unsigned int pagelen, blocklen;
-       unsigned char *blockbuffer, *bptr, *cptr, *xptr;
+       unsigned int pagelen;
+       unsigned char *bptr, *cptr, *xptr;
        unsigned char ecc[3];
        int i, result, isnew;
 
@@ -822,19 +819,13 @@
        }
 
        pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
-       blocklen = (pagelen << info->blockshift);
-       blockbuffer = kmalloc(blocklen, GFP_NOIO);
-       if (!blockbuffer) {
-               printk("sddr09_write_lba: Out of memory\n");
-               return USB_STOR_TRANSPORT_ERROR;
-       }
 
        /* read old contents */
        address = (pba << (info->pageshift + info->blockshift));
        result = sddr09_read22(us, address>>1, info->blocksize,
                               info->pageshift, blockbuffer, 0);
        if (result != USB_STOR_TRANSPORT_GOOD)
-               goto err;
+               return result;
 
        /* check old contents and fill lba */
        for (i = 0; i < info->blocksize; i++) {
@@ -893,11 +884,6 @@
                int result2 = sddr09_test_unit_ready(us);
        }
 #endif
- err:
-       kfree(blockbuffer);
-
-       /* TODO: instead of doing kmalloc/kfree for each block,
-          add a bufferpointer to the info structure */
 
        return result;
 }
@@ -906,49 +892,77 @@
 sddr09_write_data(struct us_data *us,
                  unsigned long address,
                  unsigned int sectors,
-                 unsigned char *content,
+                 unsigned char *buffer,
                  int use_sg) {
 
        struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
        unsigned int lba, page, pages;
-       unsigned char *buffer = NULL;
-       unsigned char *ptr;
-       int result, len;
+       unsigned int pagelen, blocklen;
+       unsigned char *blockbuffer;
+       unsigned int len, index, offset;
+       int result;
+
+       // blockbuffer is used for reading in the old data, overwriting
+       // with the new data, and performing ECC calculations
 
-       len = sectors*info->pagesize;
+       /* TODO: instead of doing kmalloc/kfree for each write,
+          add a bufferpointer to the info structure */
 
-       buffer = us_copy_from_sgbuf_all(content, len, use_sg);
-       if (buffer == NULL)
+       pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
+       blocklen = (pagelen << info->blockshift);
+       blockbuffer = kmalloc(blocklen, GFP_NOIO);
+       if (!blockbuffer) {
+               printk("sddr09_write_data: Out of memory\n");
                return USB_STOR_TRANSPORT_ERROR;
+       }
 
-       ptr = buffer;
+       // Since we don't write the user data directly to the device,
+       // we have to create a bounce buffer if the transfer uses
+       // scatter-gather.
+
+       if (use_sg) {
+               len = min(sectors, (unsigned int) info->blocksize) *
+                               info->pagesize;
+               buffer = kmalloc(len, GFP_NOIO);
+               if (buffer == NULL) {
+                       printk("sddr09_write_data: Out of memory\n");
+                       kfree(blockbuffer);
+                       return USB_STOR_TRANSPORT_ERROR;
+               }
+       }
 
        // Figure out the initial LBA and page
        lba = address >> info->blockshift;
        page = (address & info->blockmask);
 
        result = USB_STOR_TRANSPORT_GOOD;
+       index = offset = 0;
 
        while (sectors > 0) {
 
                // Write as many sectors as possible in this block
 
-               pages = info->blocksize - page;
-               if (pages > sectors)
-                       pages = sectors;
+               pages = min(sectors, info->blocksize - page);
+               len = (pages << info->pageshift);
+               if (use_sg)
+                       usb_stor_access_xfer_buf(buffer, len, us->srb,
+                                       &index, &offset, FROM_XFER_BUF);
 
-               result = sddr09_write_lba(us, lba, page, pages, ptr);
+               result = sddr09_write_lba(us, lba, page, pages,
+                               buffer, blockbuffer);
                if (result != USB_STOR_TRANSPORT_GOOD)
                        break;
+               if (!use_sg)
+                       buffer += len;
 
                page = 0;
                lba++;
                sectors -= pages;
-               ptr += (pages << info->pageshift);
        }
 
        if (use_sg)
                kfree(buffer);
+       kfree(blockbuffer);
 
        return result;
 }
@@ -1143,6 +1157,7 @@
        info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
 
        if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
+               printk("sddr09_read_map: out of memory\n");
                result = -1;
                goto done;
        }



-------------------------------------------------------
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