changeset 2966:c6ce6b63dcb5

NAND: app interface change: read_page does only whole page, read_part_page does part pages
author Ross Younger <wry@ecoscentric.com>
date Mon, 09 Nov 2009 15:06:11 +0000
parents 9f3e6c0c9aab
children 46c738b81b70
files packages/io/nand/current/ChangeLog packages/io/nand/current/include/nand.h packages/io/nand/current/src/nand.c packages/io/nand/current/src/nand_bbt.c packages/io/nand/current/src/nand_bbt.h packages/io/nand/current/src/nand_ecc_mtd_fast.c packages/io/nand/current/tests/readlimits.c packages/io/nand/current/tests/readwrite.c packages/io/nand/current/tests/rwbenchmark.c
diffstat 9 files changed, 208 insertions(+), 149 deletions(-) [+]
line wrap: on
line diff
--- a/packages/io/nand/current/ChangeLog
+++ b/packages/io/nand/current/ChangeLog
@@ -1,3 +1,12 @@
+2009-11-09  Ross Younger  <wry@eCosCentric.com>
+
+	* nand.h: Rationalise interface:
+	  * read_page: now only reads a whole page and/or its spare.
+	  * read_part_page: Created.  Allows part-pages and optionally
+	    not checking ECC.
+	  * write_page: now only writes a whole page and/or its spare.
+	* tests: Update for interface tweak.
+
 2009-11-06  Ross Younger  <wry@eCosCentric.com>
 
 	* nand_ecc_mtd_fast.c: Created. Complete rewrite of software 
--- a/packages/io/nand/current/include/nand.h
+++ b/packages/io/nand/current/include/nand.h
@@ -105,21 +105,17 @@ cyg_nand_partition* cyg_nand_get_partiti
 
 /* NAND access functions ============================================= */
 
-/* Reads (at most) a single page and/or its spare area from the device.
+/* Reads a single page and/or its spare area from the device.
  * @page@ specifies the page to be read.
- * If @dest@ is not NULL, it will be used to store the page contents (the
- * lesser of @size@ bytes and the actual page size).
+ * If @dest@ is not NULL, it will be used to store the page contents.
+ * Exactly NAND_BYTES_PER_PAGE(dev) will be written to @dest@.
  * If @spare@ is not NULL, it will be used to store the contents of the 
  * page's spare area (the lesser of @spare_size@ bytes and
  * NAND_APPSPARE_PER_PAGE(dev)).
  *
- * The data read from the chip will, as far as possible, be ECC-checked
+ * If the page data is read from the chip, it will be ECC-checked
  * and repaired if necessary.
  *
- * It is possible to request less than a whole page, but not all NAND
- * chips can cope with this; nor do some ECC implementations. In such
- * a case, this call returns -ENOSYS.
- *
  * Returns 0 for success, otherwise a negative error code.
  * -EIO : The block could not be successfully read due to an I/O error
  *    which the ECC (if configured) was not able to repair.
@@ -130,29 +126,55 @@ cyg_nand_partition* cyg_nand_get_partiti
  *
  * -ENOENT : The page address was not valid.
  * -EINVAL : The page address is within a block that is marked bad.
- * -ENOSYS : You have asked for a part-page read, but this is not
- *  supported by an underlying layer (the NAND chip, or the ECC
- *  implementation).
+ * -EFBIG  : You asked for more data from the spare-area than is present
+ *    in the current chip layout.
  */
 __externC
 int cyg_nand_read_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, 
-        void * dest, size_t size, void * spare, size_t spare_size);
+        void * dest, void * spare, size_t spare_size);
+
+/* Reads a partial page from the device, to @dest@.
+ * @page@ specifies the page to be read, @offset@ the address within the
+ * page (the column address) to start from, and @length@ the number of
+ * bytes.
+ *
+ * If @check_ecc@ is zero, no attempt will be made to check or repair ECC;
+ * the caller accepts responsibility for error detection and correction!
+ *
+ * Where the device driver supports it, the underlying device may use
+ * relevant chip commands to avoid reading the whole page. However,
+ * this is not usually compatible with checking the ECC, which requires
+ * the whole page to be read; in other words, setting @check_ecc@ tends
+ * to not give you the speedup you might otherwise have hoped for by
+ * making a part-page read.
+ *
+ * Returns 0 for success, otherwise a negative error code.
+ * -EIO : You requested ECC checking, but an error was found which
+ *    the ECC was not able to repair.
+ *    *dest and *spare contain the best-effort data read from the chip
+ *    but should not be relied upon; the application should take
+ *    steps to save as much data as needed and erase the block as
+ *    soon as possible.
+ *
+ * -ENOENT : The page address was not valid.
+ * -EINVAL : The page address is within a block that is marked bad.
+ * -EFBIG  : You have asked for too much data: offset+length extends
+ *    past the end of the page.
+ */
+__externC
+int cyg_nand_read_part_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, 
+        void * dest, size_t offset, size_t length, int check_ecc);
 
 /* Writes a single page and/or its spare area to the device.
  * ECC will be automatically computed and written.
  *
  * @page@ specifies the page to be written.
- * If @src@ is not NULL, the page contents (the lesser of @size@ bytes
- * and the actual page size) will be read from it.
+ * If @src@ is not NULL, the page contents - a whole page - will be
+ * read from it.
  * If @spare@ is not NULL, the spare area contents 
  * (the lesser of @spare_size@ bytes and NAND_APPSPARE_PER_PAGE(dev))
  * will be read from it.
  *
- * It is possible to write less than a whole page, but not all NAND
- * chips can cope with this; nor do some ECC implementations. In such
- * a case, this call returns -ENOSYS. (If successful, the write is
- * made up to a whole page by padding with 0xFF.)
- *
  * Returns 0 for success, otherwise a negative error code.
  * -EIO : The page could not be successfully written due to an I/O error.
  *   In this case, the application should copy out data from the preceding 
@@ -161,12 +183,10 @@ int cyg_nand_read_page(cyg_nand_partitio
  *
  * -ENOENT : The page address was not valid.
  * -EINVAL : The page address is within a block that is marked bad.
- * -ENOSYS : You have asked for a part-page write, but this is not
- *  supported by an underlying layer.
  */
 __externC
 int cyg_nand_write_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, 
-        const void * src, size_t size, const void * spare, size_t spare_size);
+        const void * src, const void * spare, size_t spare_size);
 
 /* Erases an eraseblock.
  * @blk@ specifies the block to be erased.
--- a/packages/io/nand/current/src/nand.c
+++ b/packages/io/nand/current/src/nand.c
@@ -260,14 +260,13 @@ static int valid_page_addr(cyg_nand_part
 
 __externC
 int cyg_nand_read_page(cyg_nand_partition *prt, cyg_nand_page_addr page,
-                void * dest, size_t size, void * spare, size_t spare_size)
+                void * dest, void * spare, size_t spare_size)
 {
     int rv;
     PARTITION_CHECK(prt);
     cyg_nand_device *dev = prt->dev;
     DEV_INIT_CHECK(dev);
 
-    if (size > (1<<dev->page_bits)) return -EFBIG;
     if (spare_size > dev->spare_per_page) return -EFBIG;
 
     EG(valid_page_addr(prt, page));
@@ -280,16 +279,53 @@ int cyg_nand_read_page(cyg_nand_partitio
     }
 #endif
 
-    EG(nandi_read_page_raw(dev, page, dest, size, spare, spare_size));
+    EG(nandi_read_whole_page_raw(dev, page, dest, spare, spare_size, 1));
 
 err_exit:
     return rv;
 }
 
 
+
+__externC
+int cyg_nand_read_part_page(cyg_nand_partition *prt, cyg_nand_page_addr page,
+                void * dest, size_t offset, size_t length, int check_ecc)
+
+{
+    int rv;
+    PARTITION_CHECK(prt);
+    cyg_nand_device *dev = prt->dev;
+    DEV_INIT_CHECK(dev);
+    CYG_BYTE *pagebuffer;
+
+    if (offset + length > NAND_BYTES_PER_PAGE(dev)) return -EFBIG;
+
+    EG(valid_page_addr(prt, page));
+
+#ifdef CYGSEM_IO_NAND_USE_BBT
+    cyg_nand_block_addr blk = CYG_NAND_PAGE2BLOCKADDR(dev,page);
+    if (cyg_nand_bbti_query(dev, blk) != CYG_NAND_BBT_OK) {
+        NAND_CHATTER(1,dev,"Asked to read page %u in bad block %u\n", page, blk);
+        EG(-EINVAL);
+    }
+#endif
+
+    // XXX TODO: use device support.
+    pagebuffer = nandi_grab_pagebuf();
+    EG(nandi_read_whole_page_raw(dev, page, pagebuffer, 0, 0, check_ecc));
+    if (dest)
+        memcpy(dest, &pagebuffer[offset], length);
+
+err_exit:
+    nandi_release_pagebuf();
+    return rv;
+}
+
+
 /* Internal, mostly-unchecked interface to read a page. */
-int nandi_read_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
-            CYG_BYTE * dest, const size_t sizex, CYG_BYTE * spare, size_t spare_size)
+int nandi_read_whole_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
+            CYG_BYTE * dest, CYG_BYTE * spare, size_t spare_size,
+            int check_ecc)
 {
     CYG_BYTE ecc_read[CYG_NAND_ECCPERPAGE(dev)],
              ecc_calc[CYG_NAND_ECCPERPAGE(dev)];
@@ -298,10 +334,10 @@ int nandi_read_page_raw(cyg_nand_device 
     CYG_BYTE oob_buf[dev->spare_per_page];
     int rv=0,tries=0;
     size_t remain;
-    const int ecc_is_hw = (dev->ecc->flags & NAND_ECC_FLAG_IS_HARDWARE);
+    const int do_hw_ecc = (dev->ecc->flags & NAND_ECC_FLAG_IS_HARDWARE) && check_ecc;
 
     // Stride for reading from device:
-    const unsigned read_data_stride = ecc_is_hw ? dev->ecc->data_size : NAND_BYTES_PER_PAGE(dev);
+    const unsigned read_data_stride = do_hw_ecc ? dev->ecc->data_size : NAND_BYTES_PER_PAGE(dev);
     // Stride for calculating/checking/repairing ECC:
     const unsigned ecc_data_stride = dev->ecc->data_size;
     // Stride within the ECC data
@@ -310,11 +346,7 @@ int nandi_read_page_raw(cyg_nand_device 
     if (dest)  CYG_CHECK_DATA_PTRC(dest);
     if (spare) CYG_CHECK_DATA_PTRC(spare);
 
-    if (!ecc_is_hw) {
-        // if s/w ecc, part-stride reads are not yet supported
-        if (sizex % ecc_data_stride != 0)
-            EG(-ENOSYS);
-    }
+    CYG_ASSERTC(NAND_BYTES_PER_PAGE(dev) % ecc_data_stride == 0);
 
     LOCK_DEV(dev);
 
@@ -323,7 +355,7 @@ int nandi_read_page_raw(cyg_nand_device 
         CYG_BYTE *ecc_dest = ecc_calc;
 
         ++tries;
-        remain = sizex;
+        remain = NAND_BYTES_PER_PAGE(dev);
 
         EG(dev->fns->read_begin(dev, page));
 
@@ -331,73 +363,70 @@ int nandi_read_page_raw(cyg_nand_device 
             int step;
             while (remain) {
                 step = read_data_stride;
-
-                if (ecc_is_hw && dev->ecc->init) dev->ecc->init(dev);
+                CYG_ASSERTC(remain >= read_data_stride);
 
-                if (step > remain) {
-                    step = remain;
-                    EG(dev->fns->read_stride(dev, data_dest, step));
-                    EG(dev->fns->read_stride(dev, 0, read_data_stride - step));
-                } else {
-                    EG(dev->fns->read_stride(dev, data_dest, step));
-                }
-                if (ecc_is_hw) {
+                if (do_hw_ecc && dev->ecc->init) dev->ecc->init(dev);
+                EG(dev->fns->read_stride(dev, data_dest, read_data_stride));
+
+                if (do_hw_ecc) {
                     dev->ecc->calc(dev, 0, 0, ecc_dest);
                     ecc_dest += ecc_stride;
                 }
-                data_dest += step;
-                remain -= step;
-            }
-        }
 
-        EG(dev->fns->read_finish(dev, oob_buf, dev->spare_per_page));
-
-        nand_oob_unpack(dev, spare, spare_size, ecc_read, oob_buf);
-
-        if (dest && !ecc_is_hw) {
-            // Calculate software ECC in one go to try and take advantage
-            // of the instruction cache.
-            int step = ecc_data_stride;
-            data_dest = dest;
-            remain = sizex;
-            ecc_calc_p = ecc_calc;
-
-            while (remain) {
-                // We have already checked above that we're not doing any part-strides.
-                if (dev->ecc->init) dev->ecc->init(dev);
-                dev->ecc->calc(dev, data_dest, step, ecc_calc_p);
-
-                remain -= step;
-                data_dest += step;
-                ecc_calc_p += ecc_stride;
+                data_dest += read_data_stride;
+                remain -= read_data_stride;
             }
-        }
+
+            EG(dev->fns->read_finish(dev, oob_buf, dev->spare_per_page));
+            nand_oob_unpack(dev, spare, spare_size, ecc_read, oob_buf);
 
-        rv = 0;
-        if (dest) {
-            int step = ecc_data_stride;
-            int step_rv;
-            remain = sizex;
-            data_dest = dest;
+            if (check_ecc) {
+                if (!do_hw_ecc) {
+                    // Calculate software ECC in one go to try and take
+                    // advantage of the cache.
+                    data_dest = dest;
+                    remain = NAND_BYTES_PER_PAGE(dev);
+                    ecc_calc_p = ecc_calc;
 
-            ecc_calc_p = ecc_calc;
-            ecc_read_p = ecc_read;
+                    while (remain) {
+                        if (dev->ecc->init) dev->ecc->init(dev);
+                        dev->ecc->calc(dev, data_dest, ecc_data_stride, ecc_calc_p);
+
+                        remain -= ecc_data_stride;
+                        data_dest += ecc_data_stride;
+                        ecc_calc_p += ecc_stride;
+                    }
+                }
 
-            while (remain) {
-                if (step > remain) step = remain;
+                // Now repair ...
+                rv = 0;
+                int step_rv;
+                remain = NAND_BYTES_PER_PAGE(dev);
+                data_dest = dest;
+
+                ecc_calc_p = ecc_calc;
+                ecc_read_p = ecc_read;
+
+                while (remain) {
+                    CYG_ASSERTC(remain >= ecc_data_stride);
 
-                step_rv = dev->ecc->repair(dev,data_dest,step,ecc_read_p,ecc_calc_p);
-                if (step_rv == -1) {
-                    rv = -1;
-                    break;
+                    step_rv = dev->ecc->repair(dev,data_dest,ecc_data_stride,ecc_read_p,ecc_calc_p);
+                    if (step_rv == -1) {
+                        rv = -1;
+                        break;
+                    }
+                    rv |= step_rv;
+
+                    data_dest += ecc_data_stride;
+                    ecc_read_p += ecc_stride;
+                    ecc_calc_p += ecc_stride;
+                    remain -= ecc_data_stride;
                 }
-                rv |= step_rv;
-
-                data_dest += step;
-                ecc_read_p += ecc_stride;
-                ecc_calc_p += ecc_stride;
-                remain -= step;
             }
+        } else { // !dest: very simple case
+            EG(dev->fns->read_finish(dev, oob_buf, dev->spare_per_page));
+            rv = 0;
+            nand_oob_unpack(dev, spare, spare_size, ecc_read, oob_buf);
         }
 
         if (rv==-1 && (tries < CYGNUM_NAND_MAX_READ_RETRIES) ) {
@@ -429,7 +458,7 @@ err_exit:
 /* Internal, mostly-unchecked interface to write a page. */
 __externC
 int cyg_nand_write_page(cyg_nand_partition *prt, cyg_nand_page_addr page,
-        const void * src, size_t size, const void * spare, size_t spare_size)
+        const void * src, const void * spare, size_t spare_size)
 {
     int rv;
     PARTITION_CHECK(prt);
@@ -445,7 +474,7 @@ int cyg_nand_write_page(cyg_nand_partiti
         EG(-EINVAL);
     }
 #endif
-    EG(nandi_write_page_raw(dev, page, src, size, spare, spare_size));
+    EG(nandi_write_page_raw(dev, page, src, spare, spare_size));
 
 err_exit:
     return rv;
@@ -453,7 +482,7 @@ err_exit:
 
 __externC
 int nandi_write_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
-        const CYG_BYTE * src, const size_t sizex, const CYG_BYTE * spare, size_t spare_size)
+        const CYG_BYTE * src, const CYG_BYTE * spare, size_t spare_size)
 {
 #ifdef CYGSEM_IO_NAND_READONLY
     return -EROFS;
@@ -462,8 +491,8 @@ int nandi_write_page_raw(cyg_nand_device
     CYG_BYTE oob_packed[dev->spare_per_page];
     CYG_BYTE ecc[CYG_NAND_ECCPERPAGE(dev)];
 
-    const int ecc_is_hw = (dev->ecc->flags & NAND_ECC_FLAG_IS_HARDWARE);
-    const unsigned write_data_stride = ecc_is_hw ? dev->ecc->data_size : NAND_BYTES_PER_PAGE(dev);
+    const int do_hw_ecc = (dev->ecc->flags & NAND_ECC_FLAG_IS_HARDWARE);
+    const unsigned write_data_stride = do_hw_ecc ? dev->ecc->data_size : NAND_BYTES_PER_PAGE(dev);
     const unsigned ecc_data_stride = dev->ecc->data_size;
     const unsigned ecc_stride = dev->ecc->ecc_size;
     size_t remain;
@@ -473,19 +502,16 @@ int nandi_write_page_raw(cyg_nand_device
 
     if (src)   CYG_CHECK_DATA_PTRC(src);
     if (spare) CYG_CHECK_DATA_PTRC(spare);
+    CYG_ASSERTC(NAND_BYTES_PER_PAGE(dev) % ecc_data_stride == 0);
 
     // If we're doing software ECC, do it all in one go now.
-    if (src && !ecc_is_hw) {
+    if (src && !do_hw_ecc) {
         int step = ecc_data_stride;
         const CYG_BYTE *data_src = src;
-        remain = sizex;
-
-        // if s/w ecc, part-stride writes are not yet supported
-        if (remain % ecc_data_stride != 0)
-            EG(-ENOSYS);
+        remain = NAND_BYTES_PER_PAGE(dev);
 
         while (remain) {
-            //if (step > remain) step = remain; // NYI
+            CYG_ASSERTC(remain >= step);
             if (dev->ecc->init) dev->ecc->init(dev);
             dev->ecc->calc(dev, data_src, step, ecc_dest);
 
@@ -499,21 +525,13 @@ int nandi_write_page_raw(cyg_nand_device
     EG(dev->fns->write_begin(dev, page));
     if (src) {
         int step = write_data_stride;
-        remain = sizex;
+        remain = NAND_BYTES_PER_PAGE(dev);
         while (remain) {
-            if (ecc_is_hw && dev->ecc->init) dev->ecc->init(dev);
+            CYG_ASSERTC(remain >= step);
+            if (do_hw_ecc && dev->ecc->init) dev->ecc->init(dev);
 
-            if (step > remain) {
-                step = remain;
-                // We can only support part-stride writes by assuming
-                // that the rest of the stride is 0xFF.
-                // (Woe betide the caller if it isn't.)
-                EG(dev->fns->write_stride(dev, src, step));
-                EG(dev->fns->write_stride(dev, 0, write_data_stride - step));
-            } else {
-                EG(dev->fns->write_stride(dev, src, step));
-            }
-            if (ecc_is_hw) {
+            EG(dev->fns->write_stride(dev, src, step));
+            if (do_hw_ecc) {
                 dev->ecc->calc(dev, 0, 0, ecc_dest);
                 ecc_dest += ecc_stride;
             }
--- a/packages/io/nand/current/src/nand_bbt.c
+++ b/packages/io/nand/current/src/nand_bbt.c
@@ -59,12 +59,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#ifdef CYGSEM_IO_NAND_USE_BBT
-
-#ifndef CYGSEM_IO_NAND_READONLY
-static int cyg_nand_bbti_write_tables(cyg_nand_device *dev);
-#endif
-
 /* ============================================================ */
 // We need a global page buffer so we can manipulate the
 // Bad Block Table. This has to be big enough for the largest
@@ -84,7 +78,7 @@ static int cyg_nand_bbti_write_tables(cy
 static unsigned char bbt_pagebuf[CYGNUM_NAND_PAGEBUFFER];
 
 
-cyg_drv_mutex_t nand_bbt_pagebuf_lock; // Init'ed in nand.c
+cyg_drv_mutex_t nand_bbt_pagebuf_lock;
 
 __externC void cyg_nand_bbt_initx(void)
 {
@@ -101,6 +95,23 @@ cyg_drv_mutex_t nand_bbt_pagebuf_lock; /
     i_locked = 0;                                   \
 } while(0)
 
+CYG_BYTE* nandi_grab_pagebuf(void)
+{
+    cyg_drv_mutex_lock(&nand_bbt_pagebuf_lock);
+    return &bbt_pagebuf[0];
+}
+
+void nandi_release_pagebuf(void)
+{
+    cyg_drv_mutex_unlock(&nand_bbt_pagebuf_lock);
+}
+
+#ifdef CYGSEM_IO_NAND_USE_BBT
+
+#ifndef CYGSEM_IO_NAND_READONLY
+static int cyg_nand_bbti_write_tables(cyg_nand_device *dev);
+#endif
+
 /* Mapping between on-chip and in-ram statuses ===================== */
 static inline cyg_nand_bbt_status_t chip_2_ram(nand_bbti_onchip_status_t in)
 {
@@ -248,7 +259,7 @@ static int bbti_incorporate_one(cyg_nand
 
     int blks_to_read = 1 << dev->blockcount_bits;
     while (blks_to_read>0) {
-        rv = nandi_read_page_raw(dev, pg, bbt_pagebuf, 1<<dev->page_bits, 0, 0);
+        rv = nandi_read_whole_page_raw(dev, pg, bbt_pagebuf, 0, 0, 1);
         // read_page_raw does the ecc for us, and we don't care about the OOB here as we already know it's one of ours.
         if (rv<0) {
             // This is bad.
@@ -391,7 +402,7 @@ int cyg_nand_bbti_find_tables(cyg_nand_d
 
         CYG_BYTE oobbuf[NAND_APPSPARE_PER_PAGE(dev)];
 
-        rv = nandi_read_page_raw(dev, pg, 0, 0, oobbuf, sizeof oobbuf);
+        rv = nandi_read_whole_page_raw(dev, pg, 0, oobbuf, sizeof oobbuf, 1);
         if (rv<0) {
             NAND_CHATTER(1,dev, "bbti_find_tables: Error %d reading OOB of page %u (block %u)\n", -rv, pg, blk);
             EG(-EIO);
@@ -605,7 +616,7 @@ static int bbti_write_one_table(cyg_nand
         rv = nand_oob_packed_write(dev, NAND_VERSION_OFFSET, NAND_VERSION_SIZE, appspare, &dev->bbt.version);
         if (rv != 0) EG(-EIO); // Should never fail, we've passed the startup sanity check.
 
-        rv = nandi_write_page_raw(dev, pg, bbt_pagebuf, pagesize, appspare, sizeof appspare);
+        rv = nandi_write_page_raw(dev, pg, bbt_pagebuf, appspare, sizeof appspare);
         if (rv==-EIO) {
             /* Ouch. Our BBT block has failed. We cannot write another, 
              * as we might trample app data. We'll mark bad, and hope
@@ -655,8 +666,4 @@ top:
 }
 #endif
 
-#else
-__externC void cyg_nand_bbt_initx(void)
-{
-}
 #endif
--- a/packages/io/nand/current/src/nand_bbt.h
+++ b/packages/io/nand/current/src/nand_bbt.h
@@ -116,14 +116,19 @@ int cyg_nand_bbti_build_tables(cyg_nand_
 
 /* Raw unchecked NAND access, for use by the BBT ===================== */
 
-int nandi_read_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
-                        CYG_BYTE * dest, size_t size,
-                        CYG_BYTE * spare, size_t spare_size);
+int nandi_read_whole_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
+                              CYG_BYTE * dest,
+                              CYG_BYTE * spare, size_t spare_size,
+                              int check_ecc);
 
 int nandi_write_page_raw(cyg_nand_device *dev, cyg_nand_page_addr page,
-                         const CYG_BYTE * src, size_t size,
+                         const CYG_BYTE * src,
                          const CYG_BYTE * spare, size_t spare_size);
 
+/* Code outside of the BBT can use the pagebuffer ==================== */
+CYG_BYTE* nandi_grab_pagebuf(void);
+void nandi_release_pagebuf(void);
+
 /* =================================================================== */
 
 #endif
--- a/packages/io/nand/current/src/nand_ecc_mtd_fast.c
+++ b/packages/io/nand/current/src/nand_ecc_mtd_fast.c
@@ -82,8 +82,8 @@ static const CYG_BYTE ParityTable256[256
 };
 #define BYTEPAR(i) ParityTable256[(unsigned char)(i)]
 
-#ifdef SUPPORT_SUB_BLOCK
-// TODO decide whether we need sub-block support.
+#ifdef SUBSTRIDE_SUPPORT
+// This is not needed?
 #define BLOCKSIZE 256
 static CYG_BYTE databuf[BLOCKSIZE];
 #endif
@@ -100,7 +100,7 @@ static void ecc256_fast(struct _cyg_nand
     unsigned i;
     cyg_uint32 *d = (cyg_uint32*)data;
 
-#ifdef SUPPORT_SUB_BLOCK
+#ifdef SUBSTRIDE_SUPPORT
     if (nbytes < BLOCKSIZE) {
         // Slightly horrid kludge to support sub-block reads. This might be removed later.
         memcpy(databuf, data, nbytes);
--- a/packages/io/nand/current/tests/readlimits.c
+++ b/packages/io/nand/current/tests/readlimits.c
@@ -81,7 +81,7 @@ int tryread(cyg_nand_partition *prt, cyg
 #if 0
     printf("Trying %d...\n",pg);
 #endif
-    int rv = cyg_nand_read_page(prt, pg, buf, sizeof(buf), NULL, 0);
+    int rv = cyg_nand_read_page(prt, pg, buf, NULL, 0);
 
     if (!shouldwork) ++tried_bad;
     if (rv==0)
--- a/packages/io/nand/current/tests/readwrite.c
+++ b/packages/io/nand/current/tests/readwrite.c
@@ -130,20 +130,20 @@ int cyg_user_start(void)
     ar4prng_many(&rnd, buf, datasize);
 
     diag_printf("Read/write to page %d (block %d)\n", pg, blk);
-    MUST(0==cyg_nand_write_page(prt, pg, buf, datasize, 0, 0));
-    MUST(0==cyg_nand_read_page (prt, pg, buf2,datasize, 0, 0));
+    MUST(0==cyg_nand_write_page(prt, pg, buf, 0, 0));
+    MUST(0==cyg_nand_read_page (prt, pg, buf2, 0, 0));
     MUST(0==memcmp(buf, buf2, datasize));
 
     diag_printf("Erasing adjacent block %d\n", blk+1);
     MUST(0==cyg_nand_erase_block(prt, blk+1));
     diag_printf("Re-read check..\n");
-    MUST(0==cyg_nand_read_page (prt, pg, buf2,datasize, 0, 0));
+    MUST(0==cyg_nand_read_page (prt, pg, buf2, 0, 0));
     MUST(0==memcmp(buf, buf2, datasize));
 
     diag_printf("Re-erase %d\n", blk);
     MUST(0==cyg_nand_erase_block(prt, blk));
     diag_printf("Read-back page %d to confirm erase\n", pg);
-    MUST(0==cyg_nand_read_page (prt, pg, buf2,datasize, 0, 0));
+    MUST(0==cyg_nand_read_page (prt, pg, buf2, 0, 0));
     for (i=0; i<datasize; i++)
         MUST(buf2[i]==0xff);
 
--- a/packages/io/nand/current/tests/rwbenchmark.c
+++ b/packages/io/nand/current/tests/rwbenchmark.c
@@ -318,7 +318,7 @@ cyg_nand_block_addr find_spare_block(cyg
 
     for (b=part->last; b>=part->first; b--) {
         cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, b);
-        rv = cyg_nand_read_page(part, pg, 0, 0, oob, oobz);
+        rv = cyg_nand_read_page(part, pg, 0, oob, oobz);
         if (rv != 0) continue; // bad block?
 
         for (i=0; i<oobz; i++)
@@ -355,7 +355,7 @@ void test_reads(cyg_nand_partition *part
     cyg_nand_erase_block(part, b);
     memcpy(oob, databuf, oobz);
     for (i=pgstart; i <= pgend; i++) {
-        rv = cyg_nand_write_page(part, i, databuf, sizeof databuf, oob, oobz);
+        rv = cyg_nand_write_page(part, i, databuf, oob, oobz);
         switch (rv) {
             case 0: break;
             case -EIO:
@@ -387,7 +387,7 @@ void test_reads(cyg_nand_partition *part
         CLEARDATA();
         wait_for_tick();
         get_timestamp(&ft[i].start);
-        cyg_nand_read_page(part, pg, testbuf, sizeof testbuf, 0, 0);
+        cyg_nand_read_page(part, pg, testbuf, 0, 0);
         get_timestamp(&ft[i].end);
         CHECKDATA();
         ++pg;
@@ -399,7 +399,7 @@ void test_reads(cyg_nand_partition *part
         CLEAROOB();
         wait_for_tick();
         get_timestamp(&ft[i].start);
-        cyg_nand_read_page(part, pg, 0, 0, oob, oobz);
+        cyg_nand_read_page(part, pg, 0, oob, oobz);
         get_timestamp(&ft[i].end);
         CHECKOOB();
         ++pg;
@@ -412,7 +412,7 @@ void test_reads(cyg_nand_partition *part
         CLEAROOB();
         wait_for_tick();
         get_timestamp(&ft[i].start);
-        cyg_nand_read_page(part, pg, testbuf, sizeof testbuf, oob, oobz);
+        cyg_nand_read_page(part, pg, testbuf, oob, oobz);
         get_timestamp(&ft[i].end);
         CHECKDATA();
         CHECKOOB();
@@ -439,13 +439,13 @@ void test_writes(cyg_nand_partition *par
     for (i=0; i < NWRITES; i++) {
         wait_for_tick();
         get_timestamp(&ft[i].start);
-        cyg_nand_write_page(part, pg, databuf, sizeof databuf, databuf, oobz);
+        cyg_nand_write_page(part, pg, databuf, databuf, oobz);
         get_timestamp(&ft[i].end);
 
         // Read it back to confirm
         CLEARDATA();
         CLEAROOB();
-        cyg_nand_read_page(part, pg, testbuf, sizeof testbuf, oob, oobz);
+        cyg_nand_read_page(part, pg, testbuf, oob, oobz);
         CHECKDATA();
         CHECKOOB();
 
@@ -481,7 +481,7 @@ void test_erases(cyg_nand_partition *par
             // to try writing out more dummy data each time.
             CLEARDATA();
             CLEAROOB();
-            cyg_nand_read_page(part, pg, testbuf, sizeof testbuf, oob, oobz);
+            cyg_nand_read_page(part, pg, testbuf, oob, oobz);
             for (j=0; j < sizeof testbuf; j++) {
                 if (testbuf[j] != 0xff) {
                     CYG_TEST_FAIL("readback check failed");