Merge ../linux-2.6-watchdog-mm
[pandora-kernel.git] / drivers / mtd / nand / nand_base.c
index 975b2ef..dfe56e0 100644 (file)
@@ -362,7 +362,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
                 * access
                 */
                ofs += mtd->oobsize;
-               chip->ops.len = 2;
+               chip->ops.len = chip->ops.ooblen = 2;
                chip->ops.datbuf = NULL;
                chip->ops.oobbuf = buf;
                chip->ops.ooboffs = chip->badblockpos & ~0x01;
@@ -415,7 +415,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
  * Wait for the ready pin, after a command
  * The timeout is catched later.
  */
-static void nand_wait_ready(struct mtd_info *mtd)
+void nand_wait_ready(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
        unsigned long timeo = jiffies + 2;
@@ -429,6 +429,7 @@ static void nand_wait_ready(struct mtd_info *mtd)
        } while (time_before(jiffies, timeo));
        led_trigger_event(nand_led_trigger, LED_OFF);
 }
+EXPORT_SYMBOL_GPL(nand_wait_ready);
 
 /**
  * nand_command - [DEFAULT] Send command to NAND device
@@ -754,7 +755,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_page_swecc - {REPLACABLE] software ecc based page read function
+ * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
@@ -766,8 +767,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
        uint8_t *p = buf;
-       uint8_t *ecc_calc = chip->buffers.ecccalc;
-       uint8_t *ecc_code = chip->buffers.ecccode;
+       uint8_t *ecc_calc = chip->buffers->ecccalc;
+       uint8_t *ecc_code = chip->buffers->ecccode;
        int *eccpos = chip->ecc.layout->eccpos;
 
        nand_read_page_raw(mtd, chip, buf);
@@ -794,7 +795,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function
+ * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
@@ -808,8 +809,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
        uint8_t *p = buf;
-       uint8_t *ecc_calc = chip->buffers.ecccalc;
-       uint8_t *ecc_code = chip->buffers.ecccode;
+       uint8_t *ecc_calc = chip->buffers->ecccalc;
+       uint8_t *ecc_code = chip->buffers->ecccode;
        int *eccpos = chip->ecc.layout->eccpos;
 
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
@@ -838,7 +839,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
+ * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
@@ -896,12 +897,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
  * @chip:      nand chip structure
  * @oob:       oob destination address
  * @ops:       oob ops structure
+ * @len:       size of oob to transfer
  */
 static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
-                                 struct mtd_oob_ops *ops)
+                                 struct mtd_oob_ops *ops, size_t len)
 {
-       size_t len = ops->ooblen;
-
        switch(ops->mode) {
 
        case MTD_OOB_PLACE:
@@ -959,6 +959,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        int sndcmd = 1;
        int ret = 0;
        uint32_t readlen = ops->len;
+       uint32_t oobreadlen = ops->ooblen;
        uint8_t *bufpoi, *oob, *buf;
 
        stats = mtd->ecc_stats;
@@ -970,7 +971,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        page = realpage & chip->pagemask;
 
        col = (int)(from & (mtd->writesize - 1));
-       chip->oob_poi = chip->buffers.oobrbuf;
 
        buf = ops->datbuf;
        oob = ops->oobbuf;
@@ -981,7 +981,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
                /* Is the current page in the buffer ? */
                if (realpage != chip->pagebuf || oob) {
-                       bufpoi = aligned ? buf : chip->buffers.databuf;
+                       bufpoi = aligned ? buf : chip->buffers->databuf;
 
                        if (likely(sndcmd)) {
                                chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
@@ -989,24 +989,34 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                        }
 
                        /* Now read the page into the buffer */
-                       ret = chip->ecc.read_page(mtd, chip, bufpoi);
+                       if (unlikely(ops->mode == MTD_OOB_RAW))
+                               ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);
+                       else
+                               ret = chip->ecc.read_page(mtd, chip, bufpoi);
                        if (ret < 0)
                                break;
 
                        /* Transfer not aligned data */
                        if (!aligned) {
                                chip->pagebuf = realpage;
-                               memcpy(buf, chip->buffers.databuf + col, bytes);
+                               memcpy(buf, chip->buffers->databuf + col, bytes);
                        }
 
                        buf += bytes;
 
                        if (unlikely(oob)) {
                                /* Raw mode does data:oob:data:oob */
-                               if (ops->mode != MTD_OOB_RAW)
-                                       oob = nand_transfer_oob(chip, oob, ops);
-                               else
-                                       buf = nand_transfer_oob(chip, buf, ops);
+                               if (ops->mode != MTD_OOB_RAW) {
+                                       int toread = min(oobreadlen,
+                                               chip->ecc.layout->oobavail);
+                                       if (toread) {
+                                               oob = nand_transfer_oob(chip,
+                                                       oob, ops, toread);
+                                               oobreadlen -= toread;
+                                       }
+                               } else
+                                       buf = nand_transfer_oob(chip,
+                                               buf, ops, mtd->oobsize);
                        }
 
                        if (!(chip->options & NAND_NO_READRDY)) {
@@ -1023,7 +1033,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                        nand_wait_ready(mtd);
                        }
                } else {
-                       memcpy(buf, chip->buffers.databuf + col, bytes);
+                       memcpy(buf, chip->buffers->databuf + col, bytes);
                        buf += bytes;
                }
 
@@ -1053,6 +1063,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        }
 
        ops->retlen = ops->len - (size_t) readlen;
+       if (oob)
+               ops->oobretlen = ops->ooblen - oobreadlen;
 
        if (ret)
                return ret;
@@ -1253,12 +1265,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
        int page, realpage, chipnr, sndcmd = 1;
        struct nand_chip *chip = mtd->priv;
        int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
-       int readlen = ops->len;
+       int readlen = ops->ooblen;
+       int len;
        uint8_t *buf = ops->oobbuf;
 
        DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
              (unsigned long long)from, readlen);
 
+       if (ops->mode == MTD_OOB_RAW)
+               len = mtd->oobsize;
+       else
+               len = chip->ecc.layout->oobavail;
+
        chipnr = (int)(from >> chip->chip_shift);
        chip->select_chip(mtd, chipnr);
 
@@ -1266,11 +1284,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
        realpage = (int)(from >> chip->page_shift);
        page = realpage & chip->pagemask;
 
-       chip->oob_poi = chip->buffers.oobrbuf;
-
        while(1) {
                sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
-               buf = nand_transfer_oob(chip, buf, ops);
+
+               len = min(len, readlen);
+               buf = nand_transfer_oob(chip, buf, ops, len);
 
                if (!(chip->options & NAND_NO_READRDY)) {
                        /*
@@ -1285,7 +1303,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                                nand_wait_ready(mtd);
                }
 
-               readlen -= ops->ooblen;
+               readlen -= len;
                if (!readlen)
                        break;
 
@@ -1307,7 +1325,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                        sndcmd = 1;
        }
 
-       ops->retlen = ops->len;
+       ops->oobretlen = ops->ooblen;
        return 0;
 }
 
@@ -1322,15 +1340,13 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                         struct mtd_oob_ops *ops)
 {
-       int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
-                        uint8_t *buf) = NULL;
        struct nand_chip *chip = mtd->priv;
        int ret = -ENOTSUPP;
 
        ops->retlen = 0;
 
        /* Do not allow reads past end of device */
-       if ((from + ops->len) > mtd->size) {
+       if (ops->datbuf && (from + ops->len) > mtd->size) {
                DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
                      "Attempt read beyond end of device\n");
                return -EINVAL;
@@ -1341,12 +1357,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
        switch(ops->mode) {
        case MTD_OOB_PLACE:
        case MTD_OOB_AUTO:
-               break;
-
        case MTD_OOB_RAW:
-               /* Replace the read_page algorithm temporary */
-               read_page = chip->ecc.read_page;
-               chip->ecc.read_page = nand_read_page_raw;
                break;
 
        default:
@@ -1358,8 +1369,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
        else
                ret = nand_do_read_ops(mtd, from, ops);
 
-       if (unlikely(ops->mode == MTD_OOB_RAW))
-               chip->ecc.read_page = read_page;
  out:
        nand_release_device(mtd);
        return ret;
@@ -1380,7 +1389,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_write_page_swecc - {REPLACABLE] software ecc based page write function
+ * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       data buffer
@@ -1391,7 +1400,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
-       uint8_t *ecc_calc = chip->buffers.ecccalc;
+       uint8_t *ecc_calc = chip->buffers->ecccalc;
        const uint8_t *p = buf;
        int *eccpos = chip->ecc.layout->eccpos;
 
@@ -1406,7 +1415,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_write_page_hwecc - {REPLACABLE] hardware ecc based page write function
+ * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       data buffer
@@ -1417,7 +1426,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
-       uint8_t *ecc_calc = chip->buffers.ecccalc;
+       uint8_t *ecc_calc = chip->buffers->ecccalc;
        const uint8_t *p = buf;
        int *eccpos = chip->ecc.layout->eccpos;
 
@@ -1434,7 +1443,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_write_page_syndrome - {REPLACABLE] hardware ecc syndrom based page write
+ * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       data buffer
@@ -1478,21 +1487,25 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
 }
 
 /**
- * nand_write_page - [INTERNAL] write one page
+ * nand_write_page - [REPLACEABLE] write one page
  * @mtd:       MTD device structure
  * @chip:      NAND chip descriptor
  * @buf:       the data to write
  * @page:      page number to write
  * @cached:    cached programming
+ * @raw:       use _raw version of write_page
  */
 static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                          const uint8_t *buf, int page, int cached)
+                          const uint8_t *buf, int page, int cached, int raw)
 {
        int status;
 
        chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
-       chip->ecc.write_page(mtd, chip, buf);
+       if (unlikely(raw))
+               chip->ecc.write_page_raw(mtd, chip, buf);
+       else
+               chip->ecc.write_page(mtd, chip, buf);
 
        /*
         * Cached progamming disabled for now, Not sure if its worth the
@@ -1578,7 +1591,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
        return NULL;
 }
 
-#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
+#define NOTALIGNED(x)  (x & (chip->subpagesize - 1)) != 0
 
 /**
  * nand_do_write_ops - [Internal] NAND write with ECC
@@ -1591,15 +1604,16 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
 static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops)
 {
-       int chipnr, realpage, page, blockmask;
+       int chipnr, realpage, page, blockmask, column;
        struct nand_chip *chip = mtd->priv;
        uint32_t writelen = ops->len;
        uint8_t *oob = ops->oobbuf;
        uint8_t *buf = ops->datbuf;
-       int bytes = mtd->writesize;
-       int ret;
+       int ret, subpage;
 
        ops->retlen = 0;
+       if (!writelen)
+               return 0;
 
        /* reject writes, which are not page aligned */
        if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
@@ -1608,8 +1622,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                return -EINVAL;
        }
 
-       if (!writelen)
-               return 0;
+       column = to & (mtd->writesize - 1);
+       subpage = column || (writelen & (mtd->writesize - 1));
+
+       if (subpage && oob)
+               return -EINVAL;
 
        chipnr = (int)(to >> chip->chip_shift);
        chip->select_chip(mtd, chipnr);
@@ -1627,15 +1644,30 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
            (chip->pagebuf << chip->page_shift) < (to + ops->len))
                chip->pagebuf = -1;
 
-       chip->oob_poi = chip->buffers.oobwbuf;
+       /* If we're not given explicit OOB data, let it be 0xFF */
+       if (likely(!oob))
+               memset(chip->oob_poi, 0xff, mtd->oobsize);
 
        while(1) {
+               int bytes = mtd->writesize;
                int cached = writelen > bytes && page != blockmask;
+               uint8_t *wbuf = buf;
+
+               /* Partial page write ? */
+               if (unlikely(column || writelen < (mtd->writesize - 1))) {
+                       cached = 0;
+                       bytes = min_t(int, bytes - column, (int) writelen);
+                       chip->pagebuf = -1;
+                       memset(chip->buffers->databuf, 0xff, mtd->writesize);
+                       memcpy(&chip->buffers->databuf[column], buf, bytes);
+                       wbuf = chip->buffers->databuf;
+               }
 
                if (unlikely(oob))
                        oob = nand_fill_oob(chip, oob, ops);
 
-               ret = nand_write_page(mtd, chip, buf, page, cached);
+               ret = chip->write_page(mtd, chip, wbuf, page, cached,
+                                      (ops->mode == MTD_OOB_RAW));
                if (ret)
                        break;
 
@@ -1643,6 +1675,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                if (!writelen)
                        break;
 
+               column = 0;
                buf += bytes;
                realpage++;
 
@@ -1655,10 +1688,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                }
        }
 
-       if (unlikely(oob))
-               memset(chip->oob_poi, 0xff, mtd->oobsize);
-
        ops->retlen = ops->len - writelen;
+       if (unlikely(oob))
+               ops->oobretlen = ops->ooblen;
        return ret;
 }
 
@@ -1714,10 +1746,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        struct nand_chip *chip = mtd->priv;
 
        DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
-             (unsigned int)to, (int)ops->len);
+             (unsigned int)to, (int)ops->ooblen);
 
        /* Do not allow write past end of page */
-       if ((ops->ooboffs + ops->len) > mtd->oobsize) {
+       if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) {
                DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
                      "Attempt to write past end of page\n");
                return -EINVAL;
@@ -1745,7 +1777,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        if (page == chip->pagebuf)
                chip->pagebuf = -1;
 
-       chip->oob_poi = chip->buffers.oobwbuf;
        memset(chip->oob_poi, 0xff, mtd->oobsize);
        nand_fill_oob(chip, ops->oobbuf, ops);
        status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
@@ -1754,7 +1785,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        if (status)
                return status;
 
-       ops->retlen = ops->len;
+       ops->oobretlen = ops->ooblen;
 
        return 0;
 }
@@ -1768,15 +1799,13 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 static int nand_write_oob(struct mtd_info *mtd, loff_t to,
                          struct mtd_oob_ops *ops)
 {
-       void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
-                         const uint8_t *buf) = NULL;
        struct nand_chip *chip = mtd->priv;
        int ret = -ENOTSUPP;
 
        ops->retlen = 0;
 
        /* Do not allow writes past end of device */
-       if ((to + ops->len) > mtd->size) {
+       if (ops->datbuf && (to + ops->len) > mtd->size) {
                DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
                      "Attempt read beyond end of device\n");
                return -EINVAL;
@@ -1787,12 +1816,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
        switch(ops->mode) {
        case MTD_OOB_PLACE:
        case MTD_OOB_AUTO:
-               break;
-
        case MTD_OOB_RAW:
-               /* Replace the write_page algorithm temporary */
-               write_page = chip->ecc.write_page;
-               chip->ecc.write_page = nand_write_page_raw;
                break;
 
        default:
@@ -1804,8 +1828,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
        else
                ret = nand_do_write_ops(mtd, to, ops);
 
-       if (unlikely(ops->mode == MTD_OOB_RAW))
-               chip->ecc.write_page = write_page;
  out:
        nand_release_device(mtd);
        return ret;
@@ -2197,8 +2219,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        /* Newer devices have all the information in additional id bytes */
        if (!type->pagesize) {
                int extid;
-               /* The 3rd id byte contains non relevant data ATM */
-               extid = chip->read_byte(mtd);
+               /* The 3rd id byte holds MLC / multichip data */
+               chip->cellinfo = chip->read_byte(mtd);
                /* The 4th id byte is the important one */
                extid = chip->read_byte(mtd);
                /* Calc pagesize */
@@ -2288,40 +2310,22 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        return type;
 }
 
-/* module_text_address() isn't exported, and it's mostly a pointless
-   test if this is a module _anyway_ -- they'd have to try _really_ hard
-   to call us from in-kernel code if the core NAND support is modular. */
-#ifdef MODULE
-#define caller_is_module() (1)
-#else
-#define caller_is_module() \
-       module_text_address((unsigned long)__builtin_return_address(0))
-#endif
-
 /**
- * nand_scan - [NAND Interface] Scan for the NAND device
- * @mtd:       MTD device structure
- * @maxchips:  Number of chips to scan for
+ * nand_scan_ident - [NAND Interface] Scan for the NAND device
+ * @mtd:            MTD device structure
+ * @maxchips:       Number of chips to scan for
  *
- * This fills out all the uninitialized function pointers
- * with the defaults.
- * The flash ID is read and the mtd/chip structures are
- * filled with the appropriate values.
- * The mtd->owner field must be set to the module of the caller
+ * This is the first phase of the normal nand_scan() function. It
+ * reads the flash ID and sets up MTD fields accordingly.
  *
+ * The mtd->owner field must be set to the module of the caller.
  */
-int nand_scan(struct mtd_info *mtd, int maxchips)
+int nand_scan_ident(struct mtd_info *mtd, int maxchips)
 {
        int i, busw, nand_maf_id;
        struct nand_chip *chip = mtd->priv;
        struct nand_flash_dev *type;
 
-       /* Many callers got this wrong, so check for it for a while... */
-       if (!mtd->owner && caller_is_module()) {
-               printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
-               BUG();
-       }
-
        /* Get buswidth to select the correct functions */
        busw = chip->options & NAND_BUSWIDTH_16;
        /* Set the default functions */
@@ -2353,8 +2357,31 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
        chip->numchips = i;
        mtd->size = i * chip->chipsize;
 
-       /* Preset the internal oob write buffer */
-       memset(chip->buffers.oobwbuf, 0xff, mtd->oobsize);
+       return 0;
+}
+
+
+/**
+ * nand_scan_tail - [NAND Interface] Scan for the NAND device
+ * @mtd:           MTD device structure
+ * @maxchips:      Number of chips to scan for
+ *
+ * This is the second phase of the normal nand_scan() function. It
+ * fills out all the uninitialized function pointers with the defaults
+ * and scans for a bad block table if appropriate.
+ */
+int nand_scan_tail(struct mtd_info *mtd)
+{
+       int i;
+       struct nand_chip *chip = mtd->priv;
+
+       if (!(chip->options & NAND_OWN_BUFFERS))
+               chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
+       if (!chip->buffers)
+               return -ENOMEM;
+
+       /* Set the internal oob buffer location, just after the page data */
+       chip->oob_poi = chip->buffers->databuf + mtd->writesize;
 
        /*
         * If no default placement scheme is given, select an appropriate one
@@ -2377,10 +2404,18 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
                }
        }
 
+       if (!chip->write_page)
+               chip->write_page = nand_write_page;
+
        /*
         * check ECC mode, default to software if 3byte/512byte hardware ECC is
         * selected and we have 256 byte pagesize fallback to software ECC
         */
+       if (!chip->ecc.read_page_raw)
+               chip->ecc.read_page_raw = nand_read_page_raw;
+       if (!chip->ecc.write_page_raw)
+               chip->ecc.write_page_raw = nand_write_page_raw;
+
        switch (chip->ecc.mode) {
        case NAND_ECC_HW:
                /* Use standard hwecc read page function ? */
@@ -2438,6 +2473,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
                chip->ecc.size = mtd->writesize;
                chip->ecc.bytes = 0;
                break;
+
        default:
                printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
                       chip->ecc.mode);
@@ -2464,6 +2500,24 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
        }
        chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
 
+       /*
+        * Allow subpage writes up to ecc.steps. Not possible for MLC
+        * FLASH.
+        */
+       if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
+           !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+               switch(chip->ecc.steps) {
+               case 2:
+                       mtd->subpage_sft = 1;
+                       break;
+               case 4:
+               case 8:
+                       mtd->subpage_sft = 2;
+                       break;
+               }
+       }
+       chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
+
        /* Initialize state */
        chip->state = FL_READY;
 
@@ -2503,6 +2557,44 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
        return chip->scan_bbt(mtd);
 }
 
+/* module_text_address() isn't exported, and it's mostly a pointless
+   test if this is a module _anyway_ -- they'd have to try _really_ hard
+   to call us from in-kernel code if the core NAND support is modular. */
+#ifdef MODULE
+#define caller_is_module() (1)
+#else
+#define caller_is_module() \
+       module_text_address((unsigned long)__builtin_return_address(0))
+#endif
+
+/**
+ * nand_scan - [NAND Interface] Scan for the NAND device
+ * @mtd:       MTD device structure
+ * @maxchips:  Number of chips to scan for
+ *
+ * This fills out all the uninitialized function pointers
+ * with the defaults.
+ * The flash ID is read and the mtd/chip structures are
+ * filled with the appropriate values.
+ * The mtd->owner field must be set to the module of the caller
+ *
+ */
+int nand_scan(struct mtd_info *mtd, int maxchips)
+{
+       int ret;
+
+       /* Many callers got this wrong, so check for it for a while... */
+       if (!mtd->owner && caller_is_module()) {
+               printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
+               BUG();
+       }
+
+       ret = nand_scan_ident(mtd, maxchips);
+       if (!ret)
+               ret = nand_scan_tail(mtd);
+       return ret;
+}
+
 /**
  * nand_release - [NAND Interface] Free resources held by the NAND device
  * @mtd:       MTD device structure
@@ -2520,9 +2612,13 @@ void nand_release(struct mtd_info *mtd)
 
        /* Free bad block table memory */
        kfree(chip->bbt);
+       if (!(chip->options & NAND_OWN_BUFFERS))
+               kfree(chip->buffers);
 }
 
 EXPORT_SYMBOL_GPL(nand_scan);
+EXPORT_SYMBOL_GPL(nand_scan_ident);
+EXPORT_SYMBOL_GPL(nand_scan_tail);
 EXPORT_SYMBOL_GPL(nand_release);
 
 static int __init nand_base_init(void)