Merge branch 'master' of /home/tglx/work/kernel/git/mtd-2.6/
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>
Tue, 23 May 2006 10:37:31 +0000 (12:37 +0200)
committerThomas Gleixner <tglx@cruncher.tec.linutronix.de>
Tue, 23 May 2006 10:37:31 +0000 (12:37 +0200)
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
1  2 
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/rtc_from4.c
fs/jffs2/wbuf.c

@@@ -356,9 -356,9 +356,9 @@@ static void au1550_command(struct mtd_i
        if (command == NAND_CMD_SEQIN) {
                int readcmd;
  
-               if (column >= mtd->oobblock) {
+               if (column >= mtd->writesize) {
                        /* OOB area */
-                       column -= mtd->oobblock;
+                       column -= mtd->writesize;
                        readcmd = NAND_CMD_READOOB;
                } else if (column < 256) {
                        /* First 256 bytes --> READ0 */
@@@ -578,7 -578,7 +578,7 @@@ static int __init au1xxx_nand_init(void
  
        /* 30 us command delay time */
        this->chip_delay = 30;
 -      this->eccmode = NAND_ECC_SOFT;
 +      this->ecc.mode = NAND_ECC_SOFT;
  
        this->options = NAND_NO_AUTOINCR;
  
@@@ -761,9 -761,9 +761,9 @@@ static void doc2001plus_command(struct 
        if (command == NAND_CMD_SEQIN) {
                int readcmd;
  
-               if (column >= mtd->oobblock) {
+               if (column >= mtd->writesize) {
                        /* OOB area */
-                       column -= mtd->oobblock;
+                       column -= mtd->writesize;
                        readcmd = NAND_CMD_READOOB;
                } else if (column < 256) {
                        /* First 256 bytes --> READ0 */
@@@ -1093,8 -1093,8 +1093,8 @@@ static int __init find_media_headers(st
        size_t retlen;
  
        for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
-               ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
-               if (retlen != mtd->oobblock)
+               ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
+               if (retlen != mtd->writesize)
                        continue;
                if (ret) {
                        printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);
        /* Only one mediaheader was found.  We want buf to contain a
           mediaheader on return, so we'll have to re-read the one we found. */
        offs = doc->mh0_page << this->page_shift;
-       ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
-       if (retlen != mtd->oobblock) {
+       ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
+       if (retlen != mtd->writesize) {
                /* Insanity.  Give up. */
                printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
                return 0;
@@@ -1139,7 -1139,7 +1139,7 @@@ static inline int __init nftl_partscan(
        unsigned blocks, maxblocks;
        int offs, numheaders;
  
-       buf = kmalloc(mtd->oobblock, GFP_KERNEL);
+       buf = kmalloc(mtd->writesize, GFP_KERNEL);
        if (!buf) {
                printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
                return 0;
@@@ -1247,7 -1247,7 +1247,7 @@@ static inline int __init inftl_partscan
        if (inftl_bbt_write)
                end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
  
-       buf = kmalloc(mtd->oobblock, GFP_KERNEL);
+       buf = kmalloc(mtd->writesize, GFP_KERNEL);
        if (!buf) {
                printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
                return 0;
@@@ -1674,14 -1674,12 +1674,14 @@@ static int __init doc_probe(unsigned lo
        nand->dev_ready         = doc200x_dev_ready;
        nand->waitfunc          = doc200x_wait;
        nand->block_bad         = doc200x_block_bad;
 -      nand->enable_hwecc      = doc200x_enable_hwecc;
 -      nand->calculate_ecc     = doc200x_calculate_ecc;
 -      nand->correct_data      = doc200x_correct_data;
 +      nand->ecc.hwctl         = doc200x_enable_hwecc;
 +      nand->ecc.calculate     = doc200x_calculate_ecc;
 +      nand->ecc.correct       = doc200x_correct_data;
  
        nand->autooob           = &doc200x_oobinfo;
 -      nand->eccmode           = NAND_ECC_HW6_512;
 +      nand->ecc.mode          = NAND_ECC_HW_SYNDROME;
 +      nand->ecc.size          = 512;
 +      nand->ecc.bytes         = 6;
        nand->options           = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
  
        doc->physadr            = physadr;
@@@ -10,7 -10,7 +10,7 @@@
   *    http://www.linux-mtd.infradead.org/tech/nand.html
   *
   *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
 - *              2002 Thomas Gleixner (tglx@linutronix.de)
 + *              2002 Thomas Gleixner (tglx@linutronix.de)
   *
   *  02-08-2004  tglx: support for strange chips, which cannot auto increment
   *            pages on read / read_oob
   *  05-19-2004  tglx: Basic support for Renesas AG-AND chips
   *
   *  09-24-2004  tglx: add support for hardware controllers (e.g. ECC) shared
 - *            among multiple independend devices. Suggestions and initial patch
 - *            from Ben Dooks <ben-mtd@fluff.org>
 - *
 - *  12-05-2004        dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
 - *            Basically, any block not rewritten may lose data when surrounding blocks
 - *            are rewritten many times.  JFFS2 ensures this doesn't happen for blocks
 - *            it uses, but the Bad Block Table(s) may not be rewritten.  To ensure they
 - *            do not lose data, force them to be rewritten when some of the surrounding
 - *            blocks are erased.  Rather than tracking a specific nearby block (which
 - *            could itself go bad), use a page address 'mask' to select several blocks
 - *            in the same area, and rewrite the BBT when any of them are erased.
 - *
 - *  01-03-2005        dmarlin: added support for the device recovery command sequence for Renesas
 - *            AG-AND chips.  If there was a sudden loss of power during an erase operation,
 - *            a "device recovery" operation must be performed when power is restored
 - *            to ensure correct operation.
 - *
 - *  01-20-2005        dmarlin: added support for optional hardware specific callback routine to
 - *            perform extra error status checks on erase and write failures.  This required
 - *            adding a wrapper function for nand_read_ecc.
 + *            among multiple independend devices. Suggestions and initial
 + *            patch from Ben Dooks <ben-mtd@fluff.org>
 + *
 + *  12-05-2004        dmarlin: add workaround for Renesas AG-AND chips "disturb"
 + *            issue. Basically, any block not rewritten may lose data when
 + *            surrounding blocks are rewritten many times.  JFFS2 ensures
 + *            this doesn't happen for blocks it uses, but the Bad Block
 + *            Table(s) may not be rewritten.  To ensure they do not lose
 + *            data, force them to be rewritten when some of the surrounding
 + *            blocks are erased.  Rather than tracking a specific nearby
 + *            block (which could itself go bad), use a page address 'mask' to
 + *            select several blocks in the same area, and rewrite the BBT
 + *            when any of them are erased.
 + *
 + *  01-03-2005        dmarlin: added support for the device recovery command sequence
 + *            for Renesas AG-AND chips.  If there was a sudden loss of power
 + *            during an erase operation, a "device recovery" operation must
 + *            be performed when power is restored to ensure correct
 + *            operation.
 + *
 + *  01-20-2005        dmarlin: added support for optional hardware specific callback
 + *            routine to perform extra error status checks on erase and write
 + *            failures.  This required adding a wrapper function for
 + *            nand_read_ecc.
   *
   * 08-20-2005 vwool: suspend/resume added
   *
@@@ -76,7 -72,6 +76,7 @@@
  #include <linux/module.h>
  #include <linux/delay.h>
  #include <linux/errno.h>
 +#include <linux/err.h>
  #include <linux/sched.h>
  #include <linux/slab.h>
  #include <linux/types.h>
@@@ -119,7 -114,7 +119,7 @@@ static struct nand_oobinfo nand_oob_64 
  };
  
  /* This is used for padding purposes in nand_write_oob */
 -static u_char ffchars[] = {
 +static uint8_t ffchars[] = {
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  /*
   * NAND low-level MTD interface functions
   */
 -static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
 -static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
 -static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
 +static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
 +static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
 +static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
  
 -static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 +static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
 +                   size_t *retlen, uint8_t *buf);
  static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
 -                       size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
 -static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 -static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 +                       size_t *retlen, uint8_t *buf, uint8_t *eccbuf,
 +                       struct nand_oobinfo *oobsel);
 +static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
 +                       size_t *retlen, uint8_t *buf);
 +static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
 +                    size_t *retlen, const uint8_t *buf);
  static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
 -                        size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
 -static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 -static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
 +                        size_t *retlen, const uint8_t *buf, uint8_t *eccbuf,
 +                        struct nand_oobinfo *oobsel);
 +static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
 +                        size_t *retlen, const uint8_t *buf);
 +static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs,
 +                     unsigned long count, loff_t to, size_t *retlen);
  static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
 -                         unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf,
 -                         struct nand_oobinfo *oobsel);
 +                         unsigned long count, loff_t to, size_t *retlen,
 +                         uint8_t *eccbuf, struct nand_oobinfo *oobsel);
  static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
  static void nand_sync(struct mtd_info *mtd);
  
  /* Some internal functions */
 -static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page, u_char * oob_buf,
 +static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this,
 +                         int page, uint8_t * oob_buf,
                           struct nand_oobinfo *oobsel, int mode);
  #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
 -static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
 -                           u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);
 +static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this,
 +                           int page, int numpages, uint8_t *oob_buf,
 +                           struct nand_oobinfo *oobsel, int chipnr,
 +                           int oobmode);
  #else
  #define nand_verify_pages(...) (0)
  #endif
  
 -static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state);
 +static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd,
 +                         int new_state);
  
  /**
   * nand_release_device - [GENERIC] release chip
@@@ -188,12 -172,20 +188,12 @@@ static void nand_release_device(struct 
        /* De-select the NAND device */
        this->select_chip(mtd, -1);
  
 -      if (this->controller) {
 -              /* Release the controller and the chip */
 -              spin_lock(&this->controller->lock);
 -              this->controller->active = NULL;
 -              this->state = FL_READY;
 -              wake_up(&this->controller->wq);
 -              spin_unlock(&this->controller->lock);
 -      } else {
 -              /* Release the chip */
 -              spin_lock(&this->chip_lock);
 -              this->state = FL_READY;
 -              wake_up(&this->wq);
 -              spin_unlock(&this->chip_lock);
 -      }
 +      /* Release the controller and the chip */
 +      spin_lock(&this->controller->lock);
 +      this->controller->active = NULL;
 +      this->state = FL_READY;
 +      wake_up(&this->controller->wq);
 +      spin_unlock(&this->controller->lock);
  }
  
  /**
   *
   * Default read function for 8bit buswith
   */
 -static u_char nand_read_byte(struct mtd_info *mtd)
 +static uint8_t nand_read_byte(struct mtd_info *mtd)
  {
        struct nand_chip *this = mtd->priv;
        return readb(this->IO_ADDR_R);
   *
   * Default write function for 8it buswith
   */
 -static void nand_write_byte(struct mtd_info *mtd, u_char byte)
 +static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
  {
        struct nand_chip *this = mtd->priv;
        writeb(byte, this->IO_ADDR_W);
   * Default read function for 16bit buswith with
   * endianess conversion
   */
 -static u_char nand_read_byte16(struct mtd_info *mtd)
 +static uint8_t nand_read_byte16(struct mtd_info *mtd)
  {
        struct nand_chip *this = mtd->priv;
 -      return (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
 +      return (uint8_t) cpu_to_le16(readw(this->IO_ADDR_R));
  }
  
  /**
   * Default write function for 16bit buswith with
   * endianess conversion
   */
 -static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
 +static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
  {
        struct nand_chip *this = mtd->priv;
        writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
@@@ -306,7 -298,7 +306,7 @@@ static void nand_select_chip(struct mtd
   *
   * Default write function for 8bit buswith
   */
 -static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 +static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
  {
        int i;
        struct nand_chip *this = mtd->priv;
   *
   * Default read function for 8bit buswith
   */
 -static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 +static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
  {
        int i;
        struct nand_chip *this = mtd->priv;
   *
   * Default verify function for 8bit buswith
   */
 -static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
 +static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
  {
        int i;
        struct nand_chip *this = mtd->priv;
   *
   * Default write function for 16bit buswith
   */
 -static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
 +static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  {
        int i;
        struct nand_chip *this = mtd->priv;
   *
   * Default read function for 16bit buswith
   */
 -static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
 +static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  {
        int i;
        struct nand_chip *this = mtd->priv;
   *
   * Default verify function for 16bit buswith
   */
 -static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
 +static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  {
        int i;
        struct nand_chip *this = mtd->priv;
@@@ -440,16 -432,14 +440,16 @@@ static int nand_block_bad(struct mtd_in
                page = (int)ofs;
  
        if (this->options & NAND_BUSWIDTH_16) {
 -              this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
 +              this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE,
 +                            page & this->pagemask);
                bad = cpu_to_le16(this->read_word(mtd));
                if (this->badblockpos & 0x1)
                        bad >>= 8;
                if ((bad & 0xFF) != 0xff)
                        res = 1;
        } else {
 -              this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask);
 +              this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos,
 +                            page & this->pagemask);
                if (this->read_byte(mtd) != 0xff)
                        res = 1;
        }
  static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
  {
        struct nand_chip *this = mtd->priv;
 -      u_char buf[2] = { 0, 0 };
 +      uint8_t buf[2] = { 0, 0 };
        size_t retlen;
        int block;
  
@@@ -516,8 -506,7 +516,8 @@@ static int nand_check_wp(struct mtd_inf
   * Check, if the block is bad. Either by reading the bad block table or
   * calling of the scan function.
   */
 -static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
 +static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
 +                             int allowbbt)
  {
        struct nand_chip *this = mtd->priv;
  
@@@ -559,8 -548,7 +559,8 @@@ static void nand_wait_ready(struct mtd_
   * Send command to NAND device. This function is used for small page
   * devices (256/512 Bytes per page)
   */
 -static void nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
 +static void nand_command(struct mtd_info *mtd, unsigned command, int column,
 +                       int page_addr)
  {
        register struct nand_chip *this = mtd->priv;
  
        if (command == NAND_CMD_SEQIN) {
                int readcmd;
  
-               if (column >= mtd->oobblock) {
+               if (column >= mtd->writesize) {
                        /* OOB area */
-                       column -= mtd->oobblock;
+                       column -= mtd->writesize;
                        readcmd = NAND_CMD_READOOB;
                } else if (column < 256) {
                        /* First 256 bytes --> READ0 */
                        this->write_byte(mtd, column);
                }
                if (page_addr != -1) {
 -                      this->write_byte(mtd, (unsigned char)(page_addr & 0xff));
 -                      this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff));
 +                      this->write_byte(mtd, (uint8_t)(page_addr & 0xff));
 +                      this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff));
                        /* One more address cycle for devices > 32MiB */
                        if (this->chipsize > (32 << 20))
 -                              this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0x0f));
 +                              this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0x0f));
                }
                /* Latch in address */
                this->hwcontrol(mtd, NAND_CTL_CLRALE);
@@@ -670,7 -658,7 +670,7 @@@ static void nand_command_lp(struct mtd_
  
        /* Emulate NAND_CMD_READOOB */
        if (command == NAND_CMD_READOOB) {
-               column += mtd->oobblock;
+               column += mtd->writesize;
                command = NAND_CMD_READ0;
        }
  
                        this->write_byte(mtd, column >> 8);
                }
                if (page_addr != -1) {
 -                      this->write_byte(mtd, (unsigned char)(page_addr & 0xff));
 -                      this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff));
 +                      this->write_byte(mtd, (uint8_t)(page_addr & 0xff));
 +                      this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff));
                        /* One more address cycle for devices > 128MiB */
                        if (this->chipsize > (128 << 20))
 -                              this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0xff));
 +                              this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0xff));
                }
                /* Latch in address */
                this->hwcontrol(mtd, NAND_CTL_CLRALE);
   *
   * Get the device and lock it for exclusive access
   */
 -static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
 +static int
 +nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state)
  {
 -      struct nand_chip *active;
 -      spinlock_t *lock;
 -      wait_queue_head_t *wq;
 +      spinlock_t *lock = &this->controller->lock;
 +      wait_queue_head_t *wq = &this->controller->wq;
        DECLARE_WAITQUEUE(wait, current);
 -
 -      lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
 -      wq = (this->controller) ? &this->controller->wq : &this->wq;
   retry:
 -      active = this;
        spin_lock(lock);
  
        /* Hardware controller shared among independend devices */
 -      if (this->controller) {
 -              if (this->controller->active)
 -                      active = this->controller->active;
 -              else
 -                      this->controller->active = this;
 -      }
 -      if (active == this && this->state == FL_READY) {
 +      /* Hardware controller shared among independend devices */
 +      if (!this->controller->active)
 +              this->controller->active = this;
 +
 +      if (this->controller->active == this && this->state == FL_READY) {
                this->state = new_state;
                spin_unlock(lock);
                return 0;
@@@ -875,13 -869,13 +875,13 @@@ static int nand_wait(struct mtd_info *m
   * Cached programming is not supported yet.
   */
  static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page,
 -                         u_char *oob_buf, struct nand_oobinfo *oobsel, int cached)
 +                         uint8_t *oob_buf, struct nand_oobinfo *oobsel, int cached)
  {
        int i, status;
 -      u_char ecc_code[32];
 -      int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
 +      uint8_t ecc_code[32];
 +      int eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
        int *oob_config = oobsel->eccpos;
 -      int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
 +      int datidx = 0, eccidx = 0, eccsteps = this->ecc.steps;
        int eccbytes = 0;
  
        /* FIXME: Enable cached programming */
                /* No ecc, write all */
        case NAND_ECC_NONE:
                printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
-               this->write_buf(mtd, this->data_poi, mtd->oobblock);
+               this->write_buf(mtd, this->data_poi, mtd->writesize);
                break;
  
                /* Software ecc 3/256, write all */
        case NAND_ECC_SOFT:
                for (; eccsteps; eccsteps--) {
 -                      this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
 +                      this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
                        for (i = 0; i < 3; i++, eccidx++)
                                oob_buf[oob_config[eccidx]] = ecc_code[i];
 -                      datidx += this->eccsize;
 +                      datidx += this->ecc.size;
                }
-               this->write_buf(mtd, this->data_poi, mtd->oobblock);
+               this->write_buf(mtd, this->data_poi, mtd->writesize);
                break;
        default:
 -              eccbytes = this->eccbytes;
 +              eccbytes = this->ecc.bytes;
                for (; eccsteps; eccsteps--) {
                        /* enable hardware ecc logic for write */
 -                      this->enable_hwecc(mtd, NAND_ECC_WRITE);
 -                      this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
 -                      this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
 +                      this->ecc.hwctl(mtd, NAND_ECC_WRITE);
 +                      this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size);
 +                      this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
                        for (i = 0; i < eccbytes; i++, eccidx++)
                                oob_buf[oob_config[eccidx]] = ecc_code[i];
                        /* If the hardware ecc provides syndromes then
                         * the data bytes (words) */
                        if (this->options & NAND_HWECC_SYNDROME)
                                this->write_buf(mtd, ecc_code, eccbytes);
 -                      datidx += this->eccsize;
 +                      datidx += this->ecc.size;
                }
                break;
        }
   * nand_verify_pages - [GENERIC] verify the chip contents after a write
   * @mtd:      MTD device structure
   * @this:     NAND chip structure
 - * @page:     startpage inside the chip, must be called with (page & this->pagemask)
 + * @page:     startpage inside the chip, must be called with (page & this->pagemask)
   * @numpages: number of pages to verify
   * @oob_buf:  out of band data buffer
   * @oobsel:   out of band selecttion structre
   * it early in the page write stage. Better to write no data than invalid data.
   */
  static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
 -                           u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
 +                           uint8_t *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
  {
        int i, j, datidx = 0, oobofs = 0, res = -EIO;
        int eccsteps = this->eccsteps;
        int hweccbytes;
 -      u_char oobdata[64];
 +      uint8_t oobdata[64];
  
        hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
  
   * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
   * and flags = 0xff
   */
 -static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
 +static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf)
  {
        return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
  }
   * This function simply calls nand_do_read_ecc with flags = 0xff
   */
  static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
 -                       size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel)
 +                       size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel)
  {
        /* use userspace supplied oobinfo, if zero */
        if (oobsel == NULL)
   * NAND read with ECC
   */
  int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
 -                   size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel, int flags)
 +                   size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel, int flags)
  {
  
        int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
        int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
        struct nand_chip *this = mtd->priv;
 -      u_char *data_poi, *oob_data = oob_buf;
 -      u_char ecc_calc[32];
 -      u_char ecc_code[32];
 +      uint8_t *data_poi, *oob_data = oob_buf;
 +      uint8_t ecc_calc[32];
 +      uint8_t ecc_code[32];
        int eccmode, eccsteps;
        int *oob_config, datidx;
        int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
                oobsel = this->autooob;
  
 -      eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
 +      eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
        oob_config = oobsel->eccpos;
  
        /* Select the NAND device */
        page = realpage & this->pagemask;
  
        /* Get raw starting column */
-       col = from & (mtd->oobblock - 1);
+       col = from & (mtd->writesize - 1);
  
-       end = mtd->oobblock;
+       end = mtd->writesize;
 -      ecc = this->eccsize;
 -      eccbytes = this->eccbytes;
 +      ecc = this->ecc.size;
 +      eccbytes = this->ecc.bytes;
  
        if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
                compareecc = 0;
                        oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                        oob_data = &this->data_buf[end];
  
 -              eccsteps = this->eccsteps;
 +              eccsteps = this->ecc.steps;
  
                switch (eccmode) {
                case NAND_ECC_NONE:{
                case NAND_ECC_SOFT:     /* Software ECC 3/256: Read in a page + oob data */
                        this->read_buf(mtd, data_poi, end);
                        for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
 -                              this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
 +                              this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
                        break;
  
                default:
                        for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
 -                              this->enable_hwecc(mtd, NAND_ECC_READ);
 +                              this->ecc.hwctl(mtd, NAND_ECC_READ);
                                this->read_buf(mtd, &data_poi[datidx], ecc);
  
                                /* HW ecc with syndrome calculation must read the
                                if (!compareecc) {
                                        /* Some hw ecc generators need to know when the
                                         * syndrome is read from flash */
 -                                      this->enable_hwecc(mtd, NAND_ECC_READSYN);
 +                                      this->ecc.hwctl(mtd, NAND_ECC_READSYN);
                                        this->read_buf(mtd, &oob_data[i], eccbytes);
                                        /* We calc error correction directly, it checks the hw
                                         * generator for an error, reads back the syndrome and
                                         * does the error correction on the fly */
 -                                      ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
 +                                      ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
                                        if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
                                                DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
                                                      "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
                                                ecc_failed++;
                                        }
                                } else {
 -                                      this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
 +                                      this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
                                }
                        }
                        break;
                        ecc_code[j] = oob_data[oob_config[j]];
  
                /* correct data, if necessary */
 -              for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
 -                      ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
 +              for (i = 0, j = 0, datidx = 0; i < this->ecc.steps; i++, datidx += ecc) {
 +                      ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
  
                        /* Get next chunk of ecc bytes */
                        j += eccbytes;
                                break;
                        case MTD_NANDECC_PLACE:
                                /* YAFFS1 legacy mode */
 -                              oob_data += this->eccsteps * sizeof(int);
 +                              oob_data += this->ecc.steps * sizeof(int);
                        default:
                                oob_data += mtd->oobsize;
                        }
                                buf[read++] = data_poi[j];
                        this->pagebuf = realpage;
                } else
-                       read += mtd->oobblock;
+                       read += mtd->writesize;
  
                /* Apply delay or wait for ready/busy pin
                 * Do this before the AUTOINCR check, so no problems
   *
   * NAND read out-of-band data from the spare area
   */
 -static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
 +static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf)
  {
        int i, col, page, chipnr;
        struct nand_chip *this = mtd->priv;
@@@ -1485,7 -1479,7 +1485,7 @@@ int nand_read_raw(struct mtd_info *mtd
        int chip = (int)(from >> this->chip_shift);
        int sndcmd = 1;
        int cnt = 0;
-       int pagesize = mtd->oobblock + mtd->oobsize;
+       int pagesize = mtd->writesize + mtd->oobsize;
        int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
  
        /* Do not allow reads past end of device */
   * forces the 0xff fill before using the buffer again.
   *
  */
 -static u_char *nand_prepare_oobbuf(struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel,
 +static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct nand_oobinfo *oobsel,
                                   int autoplace, int numpages)
  {
        struct nand_chip *this = mtd->priv;
        return this->oob_buf;
  }
  
- #define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
+ #define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
  
  /**
   * nand_write - [MTD Interface] compability function for nand_write_ecc
   * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
   *
  */
 -static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
 +static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf)
  {
        return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL));
  }
   * NAND write with ECC
   */
  static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
 -                        size_t *retlen, const u_char *buf, u_char *eccbuf,
 +                        size_t *retlen, const uint8_t *buf, uint8_t *eccbuf,
                          struct nand_oobinfo *oobsel)
  {
        int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
        int autoplace = 0, numpages, totalpages;
        struct nand_chip *this = mtd->priv;
 -      u_char *oobbuf, *bufstart;
 +      uint8_t *oobbuf, *bufstart;
        int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
  
        DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
        /* Calc number of pages we can write in one go */
        numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages);
        oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages);
 -      bufstart = (u_char *) buf;
 +      bufstart = (uint8_t *) buf;
  
        /* Loop until all data is written */
        while (written < len) {
  
 -              this->data_poi = (u_char *) &buf[written];
 +              this->data_poi = (uint8_t *) &buf[written];
                /* Write one page. If this is the last page to write
                 * or the last page in this block, then use the
                 * real pageprogram command, else select cached programming
                /* Next oob page */
                oob += mtd->oobsize;
                /* Update written bytes count */
-               written += mtd->oobblock;
+               written += mtd->writesize;
                if (written == len)
                        goto cmp;
  
   *
   * NAND write out-of-band
   */
 -static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
 +static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf)
  {
        int column, page, status, ret = -EIO, chipnr;
        struct nand_chip *this = mtd->priv;
  
        if (NAND_MUST_PAD(this)) {
                /* Write out desired data */
-               this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
+               this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page & this->pagemask);
                /* prepad 0xff for partial programming */
                this->write_buf(mtd, ffchars, column);
                /* write data */
                this->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
        } else {
                /* Write out desired data */
-               this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask);
+               this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column, page & this->pagemask);
                /* write data */
                this->write_buf(mtd, buf, len);
        }
@@@ -1885,13 -1879,13 +1885,13 @@@ static int nand_writev(struct mtd_info 
   * NAND write with iovec with ecc
   */
  static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
 -                         loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
 +                         loff_t to, size_t *retlen, uint8_t *eccbuf, struct nand_oobinfo *oobsel)
  {
        int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
        int oob, numpages, autoplace = 0, startpage;
        struct nand_chip *this = mtd->priv;
        int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
 -      u_char *oobbuf, *bufstart;
 +      uint8_t *oobbuf, *bufstart;
  
        /* Preset written len for early exit */
        *retlen = 0;
                /* If the given tuple is >= pagesize then
                 * write it out from the iov
                 */
-               if ((vecs->iov_len - len) >= mtd->oobblock) {
+               if ((vecs->iov_len - len) >= mtd->writesize) {
                        /* Calc number of pages we can write
                         * out of this iov in one go */
                        numpages = (vecs->iov_len - len) >> this->page_shift;
                        /* Do not cross block boundaries */
                        numpages = min(ppblock - (startpage & (ppblock - 1)), numpages);
                        oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
 -                      bufstart = (u_char *) vecs->iov_base;
 +                      bufstart = (uint8_t *) vecs->iov_base;
                        bufstart += len;
                        this->data_poi = bufstart;
                        oob = 0;
                                                      &oobbuf[oob], oobsel, i != numpages);
                                if (ret)
                                        goto out;
-                               this->data_poi += mtd->oobblock;
-                               len += mtd->oobblock;
+                               this->data_poi += mtd->writesize;
+                               len += mtd->writesize;
                                oob += mtd->oobsize;
                                page++;
                        }
                         * tuple until we have a full page to write
                         */
                        int cnt = 0;
-                       while (cnt < mtd->oobblock) {
+                       while (cnt < mtd->writesize) {
                                if (vecs->iov_base != NULL && vecs->iov_len)
 -                                      this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
 +                                      this->data_buf[cnt++] = ((uint8_t *) vecs->iov_base)[len++];
                                /* Check, if we have to switch to the next tuple */
                                if (len >= (int)vecs->iov_len) {
                                        vecs++;
                if (ret)
                        goto out;
  
-               written += mtd->oobblock * numpages;
+               written += mtd->writesize * numpages;
                /* All done ? */
                if (!count)
                        break;
@@@ -2314,70 -2308,46 +2314,70 @@@ static void nand_resume(struct mtd_inf
        if (this->state == FL_PM_SUSPENDED)
                nand_release_device(mtd);
        else
 -              printk(KERN_ERR "resume() called for the chip which is not in suspended state\n");
 -
 +              printk(KERN_ERR "nand_resume() called for a chip which is not "
 +                     "in suspended state\n");
  }
  
 -/* 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
 +/*
 + * Free allocated data structures
 + */
 +static void nand_free_kmem(struct nand_chip *this)
 +{
 +      /* Buffer allocated by nand_scan ? */
 +      if (this->options & NAND_OOBBUF_ALLOC)
 +              kfree(this->oob_buf);
 +      /* Buffer allocated by nand_scan ? */
 +      if (this->options & NAND_DATABUF_ALLOC)
 +              kfree(this->data_buf);
 +      /* Controller allocated by nand_scan ? */
 +      if (this->options & NAND_CONTROLLER_ALLOC)
 +              kfree(this->controller);
 +}
  
 -/**
 - * 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. Buffers are allocated if
 - * they are not provided by the board driver
 - * The mtd->owner field must be set to the module of the caller
 - *
 +/*
 + * Allocate buffers and data structures
   */
 -int nand_scan(struct mtd_info *mtd, int maxchips)
 +static int nand_allocate_kmem(struct mtd_info *mtd, struct nand_chip *this)
  {
 -      int i, nand_maf_id, nand_dev_id, busw, maf_id;
 -      struct nand_chip *this = mtd->priv;
 +      size_t len;
  
 -      /* 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();
 +      if (!this->oob_buf) {
 +              len = mtd->oobsize <<
 +                      (this->phys_erase_shift - this->page_shift);
 +              this->oob_buf = kmalloc(len, GFP_KERNEL);
 +              if (!this->oob_buf)
 +                      goto outerr;
 +              this->options |= NAND_OOBBUF_ALLOC;
        }
  
 -      /* Get buswidth to select the correct functions */
 -      busw = this->options & NAND_BUSWIDTH_16;
 +      if (!this->data_buf) {
-               len = mtd->oobblock + mtd->oobsize;
++              len = mtd->writesize + mtd->oobsize;
 +              this->data_buf = kmalloc(len, GFP_KERNEL);
 +              if (!this->data_buf)
 +                      goto outerr;
 +              this->options |= NAND_DATABUF_ALLOC;
 +      }
 +
 +      if (!this->controller) {
 +              this->controller = kzalloc(sizeof(struct nand_hw_control),
 +                                         GFP_KERNEL);
 +              if (!this->controller)
 +                      goto outerr;
 +              this->options |= NAND_CONTROLLER_ALLOC;
 +      }
 +      return 0;
 +
 + outerr:
 +      printk(KERN_ERR "nand_scan(): Cannot allocate buffers\n");
 +      nand_free_kmem(this);
 +      return -ENOMEM;
 +}
  
 +/*
 + * Set default functions
 + */
 +static void nand_set_defaults(struct nand_chip *this, int busw)
 +{
        /* check for proper chip_delay setup, set 20us if not */
        if (!this->chip_delay)
                this->chip_delay = 20;
                this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
        if (!this->scan_bbt)
                this->scan_bbt = nand_default_bbt;
 +}
 +
 +/*
 + * Get the flash and manufacturer id and lookup if the typ is supported
 + */
 +static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 +                                                struct nand_chip *this,
 +                                                int busw, int *maf_id)
 +{
 +      struct nand_flash_dev *type = NULL;
 +      int i, dev_id, maf_idx;
  
        /* Select the device */
        this->select_chip(mtd, 0);
        this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
  
        /* Read manufacturer and device IDs */
 -      nand_maf_id = this->read_byte(mtd);
 -      nand_dev_id = this->read_byte(mtd);
 +      *maf_id = this->read_byte(mtd);
 +      dev_id = this->read_byte(mtd);
  
 -      /* Print and store flash device information */
 +      /* Lookup the flash id */
        for (i = 0; nand_flash_ids[i].name != NULL; i++) {
 +              if (dev_id == nand_flash_ids[i].id) {
 +                      type =  &nand_flash_ids[i];
 +                      break;
 +              }
 +      }
  
 -              if (nand_dev_id != nand_flash_ids[i].id)
 -                      continue;
 -
 -              if (!mtd->name)
 -                      mtd->name = nand_flash_ids[i].name;
 -              this->chipsize = nand_flash_ids[i].chipsize << 20;
 -
 -              /* New devices have all the information in additional id bytes */
 -              if (!nand_flash_ids[i].pagesize) {
 -                      int extid;
 -                      /* The 3rd id byte contains non relevant data ATM */
 -                      extid = this->read_byte(mtd);
 -                      /* The 4th id byte is the important one */
 -                      extid = this->read_byte(mtd);
 -                      /* Calc pagesize */
 -                      mtd->writesize = 1024 << (extid & 0x3);
 -                      extid >>= 2;
 -                      /* Calc oobsize */
 -                      mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
 -                      extid >>= 2;
 -                      /* Calc blocksize. Blocksize is multiples of 64KiB */
 -                      mtd->erasesize = (64 * 1024) << (extid & 0x03);
 -                      extid >>= 2;
 -                      /* Get buswidth information */
 -                      busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
 +      if (!type)
 +              return ERR_PTR(-ENODEV);
 +
 +      this->chipsize = nand_flash_ids[i].chipsize << 20;
 +
 +      /* Newer devices have all the information in additional id bytes */
 +      if (!nand_flash_ids[i].pagesize) {
 +              int extid;
 +              /* The 3rd id byte contains non relevant data ATM */
 +              extid = this->read_byte(mtd);
 +              /* The 4th id byte is the important one */
 +              extid = this->read_byte(mtd);
 +              /* Calc pagesize */
-               mtd->oobblock = 1024 << (extid & 0x3);
++              mtd->writesize = 1024 << (extid & 0x3);
 +              extid >>= 2;
 +              /* Calc oobsize */
-               mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
++              mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
 +              extid >>= 2;
 +              /* Calc blocksize. Blocksize is multiples of 64KiB */
 +              mtd->erasesize = (64 * 1024) << (extid & 0x03);
 +              extid >>= 2;
 +              /* Get buswidth information */
 +              busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
  
 -              } else {
 -                      /* Old devices have this data hardcoded in the
 -                       * device id table */
 -                      mtd->erasesize = nand_flash_ids[i].erasesize;
 -                      mtd->writesize = nand_flash_ids[i].pagesize;
 -                      mtd->oobsize = mtd->writesize / 32;
 -                      busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
 -              }
 +      } else {
 +              /*
 +               * Old devices have this data hardcoded in the device id table
 +               */
 +              mtd->erasesize = nand_flash_ids[i].erasesize;
-               mtd->oobblock = nand_flash_ids[i].pagesize;
-               mtd->oobsize = mtd->oobblock / 32;
++              mtd->writesize = nand_flash_ids[i].pagesize;
++              mtd->oobsize = mtd->writesize / 32;
 +              busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
 +      }
  
 -              /* Try to identify manufacturer */
 -              for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
 -                      if (nand_manuf_ids[maf_id].id == nand_maf_id)
 -                              break;
 -              }
 +      /* Try to identify manufacturer */
 +      for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
 +              if (nand_manuf_ids[maf_idx].id == *maf_id)
 +                      break;
 +      }
  
 -              /* Check, if buswidth is correct. Hardware drivers should set
 -               * this correct ! */
 -              if (busw != (this->options & NAND_BUSWIDTH_16)) {
 -                      printk(KERN_INFO "NAND device: Manufacturer ID:"
 -                             " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
 -                             nand_manuf_ids[maf_id].name, mtd->name);
 -                      printk(KERN_WARNING
 -                             "NAND bus width %d instead %d bit\n",
 -                             (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8);
 -                      this->select_chip(mtd, -1);
 -                      return 1;
 -              }
 +      /*
 +       * Check, if buswidth is correct. Hardware drivers should set
 +       * this correct !
 +       */
 +      if (busw != (this->options & NAND_BUSWIDTH_16)) {
 +              printk(KERN_INFO "NAND device: Manufacturer ID:"
 +                     " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
 +                     dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
 +              printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
 +                     (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
 +                     busw ? 16 : 8);
 +              return ERR_PTR(-EINVAL);
 +      }
  
 -              /* Calculate the address shift from the page size */
 -              this->page_shift = ffs(mtd->writesize) - 1;
 -              this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
 -              this->chip_shift = ffs(this->chipsize) - 1;
 -
 -              /* Set the bad block position */
 -              this->badblockpos = mtd->writesize > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
 -
 -              /* Get chip options, preserve non chip based options */
 -              this->options &= ~NAND_CHIPOPTIONS_MSK;
 -              this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
 -              /* Set this as a default. Board drivers can override it, if necessary */
 -              this->options |= NAND_NO_AUTOINCR;
 -              /* Check if this is a not a samsung device. Do not clear the options
 -               * for chips which are not having an extended id.
 -               */
 -              if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
 -                      this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
 +      /* Calculate the address shift from the page size */
-       this->page_shift = ffs(mtd->oobblock) - 1;
++      this->page_shift = ffs(mtd->writesize) - 1;
 +      /* Convert chipsize to number of pages per chip -1. */
 +      this->pagemask = (this->chipsize >> this->page_shift) - 1;
  
 -              /* Check for AND chips with 4 page planes */
 -              if (this->options & NAND_4PAGE_ARRAY)
 -                      this->erase_cmd = multi_erase_cmd;
 -              else
 -                      this->erase_cmd = single_erase_cmd;
 +      this->bbt_erase_shift = this->phys_erase_shift =
 +              ffs(mtd->erasesize) - 1;
 +      this->chip_shift = ffs(this->chipsize) - 1;
  
 -              /* Do not replace user supplied command function ! */
 -              if (mtd->writesize > 512 && this->cmdfunc == nand_command)
 -                      this->cmdfunc = nand_command_lp;
 +      /* Set the bad block position */
-       this->badblockpos = mtd->oobblock > 512 ?
++      this->badblockpos = mtd->writesize > 512 ?
 +              NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
  
 -              printk(KERN_INFO "NAND device: Manufacturer ID:"
 -                     " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
 -                     nand_manuf_ids[maf_id].name, nand_flash_ids[i].name);
 -              break;
 +      /* Get chip options, preserve non chip based options */
 +      this->options &= ~NAND_CHIPOPTIONS_MSK;
 +      this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
 +
 +      /*
 +       * Set this as a default. Board drivers can override it, if necessary
 +       */
 +      this->options |= NAND_NO_AUTOINCR;
 +
 +      /* Check if this is a not a samsung device. Do not clear the
 +       * options for chips which are not having an extended id.
 +       */
 +      if (*maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
 +              this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
 +
 +      /* Check for AND chips with 4 page planes */
 +      if (this->options & NAND_4PAGE_ARRAY)
 +              this->erase_cmd = multi_erase_cmd;
 +      else
 +              this->erase_cmd = single_erase_cmd;
 +
 +      /* Do not replace user supplied command function ! */
-       if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
++      if (mtd->writesize > 512 && this->cmdfunc == nand_command)
 +              this->cmdfunc = nand_command_lp;
 +
 +      printk(KERN_INFO "NAND device: Manufacturer ID:"
 +             " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
 +             nand_manuf_ids[maf_idx].name, type->name);
 +
 +      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
 + *
 + * 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. Buffers are allocated if
 + * they are not provided by the board driver
 + * The mtd->owner field must be set to the module of the caller
 + *
 + */
 +int nand_scan(struct mtd_info *mtd, int maxchips)
 +{
 +      int i, busw, nand_maf_id;
 +      struct nand_chip *this = 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();
        }
  
 -      if (!nand_flash_ids[i].name) {
 +      /* Get buswidth to select the correct functions */
 +      busw = this->options & NAND_BUSWIDTH_16;
 +      /* Set the default functions */
 +      nand_set_defaults(this, busw);
 +
 +      /* Read the flash type */
 +      type = nand_get_flash_type(mtd, this, busw, &nand_maf_id);
 +
 +      if (IS_ERR(type)) {
                printk(KERN_WARNING "No NAND device found!!!\n");
                this->select_chip(mtd, -1);
 -              return 1;
 +              return PTR_ERR(type);
        }
  
 +      /* Check for a chip array */
        for (i = 1; i < maxchips; i++) {
                this->select_chip(mtd, i);
 -
                /* Send the command for reading device ID */
                this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
 -
                /* Read manufacturer and device IDs */
                if (nand_maf_id != this->read_byte(mtd) ||
 -                  nand_dev_id != this->read_byte(mtd))
 +                  type->id != this->read_byte(mtd))
                        break;
        }
        if (i > 1)
                printk(KERN_INFO "%d NAND chips detected\n", i);
  
 -      /* Allocate buffers, if necessary */
 -      if (!this->oob_buf) {
 -              size_t len;
 -              len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
 -              this->oob_buf = kmalloc(len, GFP_KERNEL);
 -              if (!this->oob_buf) {
 -                      printk(KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
 -                      return -ENOMEM;
 -              }
 -              this->options |= NAND_OOBBUF_ALLOC;
 -      }
 -
 -      if (!this->data_buf) {
 -              size_t len;
 -              len = mtd->writesize + mtd->oobsize;
 -              this->data_buf = kmalloc(len, GFP_KERNEL);
 -              if (!this->data_buf) {
 -                      if (this->options & NAND_OOBBUF_ALLOC)
 -                              kfree(this->oob_buf);
 -                      printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
 -                      return -ENOMEM;
 -              }
 -              this->options |= NAND_DATABUF_ALLOC;
 -      }
 -
        /* Store the number of chips and calc total size for mtd */
        this->numchips = i;
        mtd->size = i * this->chipsize;
 -      /* Convert chipsize to number of pages per chip -1. */
 -      this->pagemask = (this->chipsize >> this->page_shift) - 1;
 +
 +      /* Allocate buffers and data structures */
 +      if (nand_allocate_kmem(mtd, this))
 +              return -ENOMEM;
 +
        /* Preset the internal oob buffer */
 -      memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
 +      memset(this->oob_buf, 0xff,
 +             mtd->oobsize << (this->phys_erase_shift - this->page_shift));
  
 -      /* If no default placement scheme is given, select an
 -       * appropriate one */
 +      /*
 +       * If no default placement scheme is given, select an appropriate one
 +       */
        if (!this->autooob) {
 -              /* Select the appropriate default oob placement scheme for
 -               * placement agnostic filesystems */
                switch (mtd->oobsize) {
                case 8:
                        this->autooob = &nand_oob_8;
                        this->autooob = &nand_oob_64;
                        break;
                default:
 -                      printk(KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize);
 +                      printk(KERN_WARNING "No oob scheme defined for "
 +                             "oobsize %d\n", mtd->oobsize);
                        BUG();
                }
        }
  
 -      /* The number of bytes available for the filesystem to place fs dependend
 -       * oob data */
 +      /*
 +       * The number of bytes available for the filesystem to place fs
 +       * dependend oob data
 +       */
        mtd->oobavail = 0;
        for (i = 0; this->autooob->oobfree[i][1]; i++)
                mtd->oobavail += this->autooob->oobfree[i][1];
  
        /*
 -       * check ECC mode, default to software
 -       * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
 -       * fallback to software ECC
 +       * check ECC mode, default to software if 3byte/512byte hardware ECC is
 +       * selected and we have 256 byte pagesize fallback to software ECC
         */
 -      this->eccsize = 256;    /* set default eccsize */
 -      this->eccbytes = 3;
 -
 -      switch (this->eccmode) {
 -      case NAND_ECC_HW12_2048:
 -              if (mtd->writesize < 2048) {
 -                      printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
 -                             mtd->writesize);
 -                      this->eccmode = NAND_ECC_SOFT;
 -                      this->calculate_ecc = nand_calculate_ecc;
 -                      this->correct_data = nand_correct_data;
 -              } else
 -                      this->eccsize = 2048;
 -              break;
 -
 -      case NAND_ECC_HW3_512:
 -      case NAND_ECC_HW6_512:
 -      case NAND_ECC_HW8_512:
 -              if (mtd->writesize == 256) {
 -                      printk(KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
 -                      this->eccmode = NAND_ECC_SOFT;
 -                      this->calculate_ecc = nand_calculate_ecc;
 -                      this->correct_data = nand_correct_data;
 -              } else
 -                      this->eccsize = 512;    /* set eccsize to 512 */
 -              break;
 +      switch (this->ecc.mode) {
 +      case NAND_ECC_HW:
 +      case NAND_ECC_HW_SYNDROME:
 +              if (!this->ecc.calculate || !this->ecc.correct ||
 +                  !this->ecc.hwctl) {
 +                      printk(KERN_WARNING "No ECC functions supplied, "
 +                             "Hardware ECC not possible\n");
 +                      BUG();
 +              }
-               if (mtd->oobblock >= this->ecc.size)
++              if (mtd->writesize >= this->ecc.size)
 +                      break;
 +              printk(KERN_WARNING "%d byte HW ECC not possible on "
 +                     "%d byte page size, fallback to SW ECC\n",
-                      this->ecc.size, mtd->oobblock);
++                     this->ecc.size, mtd->writesize);
 +              this->ecc.mode = NAND_ECC_SOFT;
  
 -      case NAND_ECC_HW3_256:
 +      case NAND_ECC_SOFT:
 +              this->ecc.calculate = nand_calculate_ecc;
 +              this->ecc.correct = nand_correct_data;
 +              this->ecc.size = 256;
 +              this->ecc.bytes = 3;
                break;
  
        case NAND_ECC_NONE:
 -              printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
 -              this->eccmode = NAND_ECC_NONE;
 -              break;
 -
 -      case NAND_ECC_SOFT:
 -              this->calculate_ecc = nand_calculate_ecc;
 -              this->correct_data = nand_correct_data;
 +              printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
 +                     "This is not recommended !!\n");
-               this->ecc.size = mtd->oobblock;
++              this->ecc.size = mtd->writesize;
 +              this->ecc.bytes = 0;
                break;
 -
        default:
 -              printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
 +              printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
 +                     this->ecc.mode);
                BUG();
        }
  
 -      /* Check hardware ecc function availability and adjust number of ecc bytes per
 -       * calculation step
 +      /*
 +       * Set the number of read / write steps for one page depending on ECC
 +       * mode
         */
-       this->ecc.steps = mtd->oobblock / this->ecc.size;
-       if(this->ecc.steps * this->ecc.size != mtd->oobblock) {
 -      switch (this->eccmode) {
 -      case NAND_ECC_HW12_2048:
 -              this->eccbytes += 4;
 -      case NAND_ECC_HW8_512:
 -              this->eccbytes += 2;
 -      case NAND_ECC_HW6_512:
 -              this->eccbytes += 3;
 -      case NAND_ECC_HW3_512:
 -      case NAND_ECC_HW3_256:
 -              if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
 -                      break;
 -              printk(KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
++      this->ecc.steps = mtd->writesize / this->ecc.size;
++      if(this->ecc.steps * this->ecc.size != mtd->writesize) {
 +              printk(KERN_WARNING "Invalid ecc parameters\n");
                BUG();
        }
  
 -      mtd->eccsize = this->eccsize;
 -
 -      /* Set the number of read / write steps for one page to ensure ECC generation */
 -      switch (this->eccmode) {
 -      case NAND_ECC_HW12_2048:
 -              this->eccsteps = mtd->writesize / 2048;
 -              break;
 -      case NAND_ECC_HW3_512:
 -      case NAND_ECC_HW6_512:
 -      case NAND_ECC_HW8_512:
 -              this->eccsteps = mtd->writesize / 512;
 -              break;
 -      case NAND_ECC_HW3_256:
 -      case NAND_ECC_SOFT:
 -              this->eccsteps = mtd->writesize / 256;
 -              break;
 -
 -      case NAND_ECC_NONE:
 -              this->eccsteps = 1;
 -              break;
 -      }
 -
        /* Initialize state, waitqueue and spinlock */
        this->state = FL_READY;
 -      init_waitqueue_head(&this->wq);
 -      spin_lock_init(&this->chip_lock);
 +      init_waitqueue_head(&this->controller->wq);
 +      spin_lock_init(&this->controller->lock);
  
        /* De-select the device */
        this->select_chip(mtd, -1);
  
        /* Fill in remaining MTD driver data */
        mtd->type = MTD_NANDFLASH;
-       mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
+       mtd->flags = MTD_CAP_NANDFLASH;
        mtd->ecctype = MTD_ECC_SW;
        mtd->erase = nand_erase;
        mtd->point = NULL;
@@@ -2756,8 -2718,12 +2756,8 @@@ void nand_release(struct mtd_info *mtd
  
        /* Free bad block table memory */
        kfree(this->bbt);
 -      /* Buffer allocated by nand_scan ? */
 -      if (this->options & NAND_OOBBUF_ALLOC)
 -              kfree(this->oob_buf);
 -      /* Buffer allocated by nand_scan ? */
 -      if (this->options & NAND_DATABUF_ALLOC)
 -              kfree(this->data_buf);
 +      /* Free buffers */
 +      nand_free_kmem(this);
  }
  
  EXPORT_SYMBOL_GPL(nand_scan);
@@@ -369,7 -369,7 +369,7 @@@ init_nandsim(struct mtd_info *mtd
        /* Initialize the NAND flash parameters */
        ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
        ns->geom.totsz    = mtd->size;
-       ns->geom.pgsz     = mtd->oobblock;
+       ns->geom.pgsz     = mtd->writesize;
        ns->geom.oobsz    = mtd->oobsize;
        ns->geom.secsz    = mtd->erasesize;
        ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
@@@ -1523,7 -1523,7 +1523,7 @@@ static int __init ns_init_module(void
        chip->verify_buf = ns_nand_verify_buf;
        chip->write_word = ns_nand_write_word;
        chip->read_word  = ns_nand_read_word;
 -      chip->eccmode    = NAND_ECC_SOFT;
 +      chip->ecc.mode   = NAND_ECC_SOFT;
        chip->options   |= NAND_SKIP_BBTSCAN;
  
        /*
@@@ -487,7 -487,7 +487,7 @@@ static int rtc_from4_errstat(struct mtd
                if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
                        er_stat |= 1 << 1;      /* err_ecc_not_avail */
                } else {
-                       len = mtd->oobblock;
+                       len = mtd->writesize;
                        buf = kmalloc(len, GFP_KERNEL);
                        if (!buf) {
                                printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n");
@@@ -570,21 -570,19 +570,21 @@@ static int __init rtc_from4_init(void
  #ifdef RTC_FROM4_HWECC
        printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n");
  
 -      this->eccmode = NAND_ECC_HW8_512;
 +      this->ecc.mode = NAND_ECC_HW_SYNDROME;
 +      this->ecc.size = 512;
 +      this->ecc.bytes = 8;
        this->options |= NAND_HWECC_SYNDROME;
        /* return the status of extra status and ECC checks */
        this->errstat = rtc_from4_errstat;
        /* set the nand_oobinfo to support FPGA H/W error detection */
        this->autooob = &rtc_from4_nand_oobinfo;
 -      this->enable_hwecc = rtc_from4_enable_hwecc;
 -      this->calculate_ecc = rtc_from4_calculate_ecc;
 -      this->correct_data = rtc_from4_correct_data;
 +      this->ecc.hwctl = rtc_from4_enable_hwecc;
 +      this->ecc.calculate = rtc_from4_calculate_ecc;
 +      this->ecc.correct = rtc_from4_correct_data;
  #else
        printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
  
 -      this->eccmode = NAND_ECC_SOFT;
 +      this->ecc.mode = NAND_ECC_SOFT;
  #endif
  
        /* set the bad block tables to support debugging */
diff --combined fs/jffs2/wbuf.c
@@@ -265,12 -265,14 +265,14 @@@ static void jffs2_wbuf_recover(struct j
  
  
        /* ... and get an allocation of space from a shiny new block instead */
-       ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE);
+       ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE);
        if (ret) {
                printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
                kfree(buf);
                return;
        }
+       ofs = write_ofs(c);
        if (end-start >= c->wbuf_pagesize) {
                /* Need to do another write immediately, but it's possible
                   that this is just because the wbuf itself is completely
                                        return;
  
                                raw2->flash_offset = ofs | REF_OBSOLETE;
-                               raw2->next_in_ino = NULL;
  
-                               jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw));
+                               jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw), NULL);
                        }
                        return;
                }
@@@ -507,11 -508,10 +508,10 @@@ static int __jffs2_flush_wbuf(struct jf
                        return -ENOMEM;
                ref->flash_offset = c->wbuf_ofs + c->wbuf_len;
                ref->flash_offset |= REF_OBSOLETE;
-               ref->next_in_ino = NULL;
  
                spin_lock(&c->erase_completion_lock);
  
-               jffs2_link_node_ref(c, jeb, ref, waste);
+               jffs2_link_node_ref(c, jeb, ref, waste, NULL);
                /* FIXME: that made it count as dirty. Convert to wasted */
                jeb->dirty_size -= waste;
                c->dirty_size -= waste;
@@@ -613,30 -613,20 +613,30 @@@ int jffs2_flush_wbuf_pad(struct jffs2_s
  
        return ret;
  }
 -int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
 +
 +static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf,
 +                            size_t len)
  {
 -      struct kvec outvecs[3];
 -      uint32_t totlen = 0;
 -      uint32_t split_ofs = 0;
 -      uint32_t old_totlen;
 -      int ret, splitvec = -1;
 -      int invec, outvec;
 -      size_t wbuf_retlen;
 -      unsigned char *wbuf_ptr;
 -      size_t donelen = 0;
 +      if (len && !c->wbuf_len && (len >= c->wbuf_pagesize))
 +              return 0;
 +
 +      if (len > (c->wbuf_pagesize - c->wbuf_len))
 +              len = c->wbuf_pagesize - c->wbuf_len;
 +      memcpy(c->wbuf + c->wbuf_len, buf, len);
 +      c->wbuf_len += (uint32_t) len;
 +      return len;
 +}
 +
 +int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
 +                     unsigned long count, loff_t to, size_t *retlen,
 +                     uint32_t ino)
 +{
 +      struct jffs2_eraseblock *jeb;
 +      size_t wbuf_retlen, donelen = 0;
        uint32_t outvec_to = to;
 +      int ret, invec;
  
 -      /* If not NAND flash, don't bother */
 +      /* If not writebuffered flash, don't bother */
        if (!jffs2_is_writebuffered(c))
                return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
  
                memset(c->wbuf,0xff,c->wbuf_pagesize);
        }
  
-       /*
-        * Fixup the wbuf if we are moving to a new eraseblock. The
-        * checks below fail for ECC'd NOR because cleanmarker == 16,
-        * so a block starts at xxx0010.
-        */
-       if (jffs2_nor_ecc(c)) {
-               if (((c->wbuf_ofs % c->sector_size) == 0) && !c->wbuf_len) {
-                       c->wbuf_ofs = PAGE_DIV(to);
-                       c->wbuf_len = PAGE_MOD(to);
-                       memset(c->wbuf,0xff,c->wbuf_pagesize);
-               }
-       }
 -      /* Sanity checks on target address.
 -         It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs),
 -         and it's permitted to write at the beginning of a new
 -         erase block. Anything else, and you die.
 -         New block starts at xxx000c (0-b = block header)
 -      */
 +      /*
 +       * Sanity checks on target address.  It's permitted to write
 +       * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to
 +       * write at the beginning of a new erase block. Anything else,
 +       * and you die.  New block starts at xxx000c (0-b = block
 +       * header)
 +       */
        if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
                /* It's a write to a new block */
                if (c->wbuf_len) {
 -                      D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
 +                      D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx "
 +                                "causes flush of wbuf at 0x%08x\n",
 +                                (unsigned long)to, c->wbuf_ofs));
                        ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
 -                      if (ret) {
 -                              /* the underlying layer has to check wbuf_len to do the cleanup */
 -                              D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
 -                              *retlen = 0;
 -                              goto exit;
 -                      }
 +                      if (ret)
 +                              goto outerr;
                }
                /* set pointer to new block */
                c->wbuf_ofs = PAGE_DIV(to);
  
        if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
                /* We're not writing immediately after the writebuffer. Bad. */
 -              printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lx\n", (unsigned long)to);
 +              printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write "
 +                     "to %08lx\n", (unsigned long)to);
                if (c->wbuf_len)
                        printk(KERN_CRIT "wbuf was previously %08x-%08x\n",
 -                                        c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
 +                             c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
                BUG();
        }
  
 -      /* Note outvecs[3] above. We know count is never greater than 2 */
 -      if (count > 2) {
 -              printk(KERN_CRIT "jffs2_flash_writev(): count is %ld\n", count);
 -              BUG();
 -      }
 -
 -      invec = 0;
 -      outvec = 0;
 -
 -      /* Fill writebuffer first, if already in use */
 -      if (c->wbuf_len) {
 -              uint32_t invec_ofs = 0;
 -
 -              /* adjust alignment offset */
 -              if (c->wbuf_len != PAGE_MOD(to)) {
 -                      c->wbuf_len = PAGE_MOD(to);
 -                      /* take care of alignment to next page */
 -                      if (!c->wbuf_len)
 -                              c->wbuf_len = c->wbuf_pagesize;
 -              }
 -
 -              while(c->wbuf_len < c->wbuf_pagesize) {
 -                      uint32_t thislen;
 -
 -                      if (invec == count)
 -                              goto alldone;
 -
 -                      thislen = c->wbuf_pagesize - c->wbuf_len;
 -
 -                      if (thislen >= invecs[invec].iov_len)
 -                              thislen = invecs[invec].iov_len;
 -
 -                      invec_ofs = thislen;
 -
 -                      memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen);
 -                      c->wbuf_len += thislen;
 -                      donelen += thislen;
 -                      /* Get next invec, if actual did not fill the buffer */
 -                      if (c->wbuf_len < c->wbuf_pagesize)
 -                              invec++;
 -              }
 -
 -              /* write buffer is full, flush buffer */
 -              ret = __jffs2_flush_wbuf(c, NOPAD);
 -              if (ret) {
 -                      /* the underlying layer has to check wbuf_len to do the cleanup */
 -                      D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
 -                      /* Retlen zero to make sure our caller doesn't mark the space dirty.
 -                         We've already done everything that's necessary */
 -                      *retlen = 0;
 -                      goto exit;
 -              }
 -              outvec_to += donelen;
 -              c->wbuf_ofs = outvec_to;
 -
 -              /* All invecs done ? */
 -              if (invec == count)
 -                      goto alldone;
 -
 -              /* Set up the first outvec, containing the remainder of the
 -                 invec we partially used */
 -              if (invecs[invec].iov_len > invec_ofs) {
 -                      outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs;
 -                      totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs;
 -                      if (totlen > c->wbuf_pagesize) {
 -                              splitvec = outvec;
 -                              split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen);
 -                      }
 -                      outvec++;
 -              }
 -              invec++;
 -      }
 -
 -      /* OK, now we've flushed the wbuf and the start of the bits
 -         we have been asked to write, now to write the rest.... */
 -
 -      /* totlen holds the amount of data still to be written */
 -      old_totlen = totlen;
 -      for ( ; invec < count; invec++,outvec++ ) {
 -              outvecs[outvec].iov_base = invecs[invec].iov_base;
 -              totlen += outvecs[outvec].iov_len = invecs[invec].iov_len;
 -              if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) {
 -                      splitvec = outvec;
 -                      split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen);
 -                      old_totlen = totlen;
 +      /* adjust alignment offset */
 +      if (c->wbuf_len != PAGE_MOD(to)) {
 +              c->wbuf_len = PAGE_MOD(to);
 +              /* take care of alignment to next page */
 +              if (!c->wbuf_len) {
 +                      c->wbuf_len = c->wbuf_pagesize;
 +                      ret = __jffs2_flush_wbuf(c, NOPAD);
 +                      if (ret)
 +                              goto outerr;
                }
        }
  
 -      /* Now the outvecs array holds all the remaining data to write */
 -      /* Up to splitvec,split_ofs is to be written immediately. The rest
 -         goes into the (now-empty) wbuf */
 -
 -      if (splitvec != -1) {
 -              uint32_t remainder;
 -
 -              remainder = outvecs[splitvec].iov_len - split_ofs;
 -              outvecs[splitvec].iov_len = split_ofs;
 -
 -              /* We did cross a page boundary, so we write some now */
 -              if (jffs2_cleanmarker_oob(c))
 -                      ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo);
 -              else
 -                      ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen);
 -
 -              if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
 -                      /* At this point we have no problem,
 -                         c->wbuf is empty. However refile nextblock to avoid
 -                         writing again to same address.
 -                      */
 -                      struct jffs2_eraseblock *jeb;
 +      for (invec = 0; invec < count; invec++) {
 +              int vlen = invecs[invec].iov_len;
 +              uint8_t *v = invecs[invec].iov_base;
  
 -                      spin_lock(&c->erase_completion_lock);
 +              wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);
  
 -                      jeb = &c->blocks[outvec_to / c->sector_size];
 -                      jffs2_block_refile(c, jeb, REFILE_ANYWAY);
 -
 -                      *retlen = 0;
 -                      spin_unlock(&c->erase_completion_lock);
 -                      goto exit;
 +              if (c->wbuf_len == c->wbuf_pagesize) {
 +                      ret = __jffs2_flush_wbuf(c, NOPAD);
 +                      if (ret)
 +                              goto outerr;
                }
 -
 +              vlen -= wbuf_retlen;
 +              outvec_to += wbuf_retlen;
                donelen += wbuf_retlen;
 -              c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen);
 -
 -              if (remainder) {
 -                      outvecs[splitvec].iov_base += split_ofs;
 -                      outvecs[splitvec].iov_len = remainder;
 -              } else {
 -                      splitvec++;
 +              v += wbuf_retlen;
 +
 +              if (vlen >= c->wbuf_pagesize) {
 +                      ret = c->mtd->write(c->mtd, outvec_to, PAGE_DIV(vlen),
 +                                          &wbuf_retlen, v);
 +                      if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen))
 +                              goto outfile;
 +
 +                      vlen -= wbuf_retlen;
 +                      outvec_to += wbuf_retlen;
 +                      c->wbuf_ofs = outvec_to;
 +                      donelen += wbuf_retlen;
 +                      v += wbuf_retlen;
                }
  
 -      } else {
 -              splitvec = 0;
 -      }
 +              wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);
 +              if (c->wbuf_len == c->wbuf_pagesize) {
 +                      ret = __jffs2_flush_wbuf(c, NOPAD);
 +                      if (ret)
 +                              goto outerr;
 +              }
  
 -      /* Now splitvec points to the start of the bits we have to copy
 -         into the wbuf */
 -      wbuf_ptr = c->wbuf;
 -
 -      for ( ; splitvec < outvec; splitvec++) {
 -              /* Don't copy the wbuf into itself */
 -              if (outvecs[splitvec].iov_base == c->wbuf)
 -                      continue;
 -              memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len);
 -              wbuf_ptr += outvecs[splitvec].iov_len;
 -              donelen += outvecs[splitvec].iov_len;
 +              outvec_to += wbuf_retlen;
 +              donelen += wbuf_retlen;
        }
 -      c->wbuf_len = wbuf_ptr - c->wbuf;
  
 -      /* If there's a remainder in the wbuf and it's a non-GC write,
 -         remember that the wbuf affects this ino */
 -alldone:
 +      /*
 +       * If there's a remainder in the wbuf and it's a non-GC write,
 +       * remember that the wbuf affects this ino
 +       */
        *retlen = donelen;
  
        if (jffs2_sum_active()) {
                jffs2_wbuf_dirties_inode(c, ino);
  
        ret = 0;
 +      up_write(&c->wbuf_sem);
 +      return ret;
 +
 +outfile:
 +      /*
 +       * At this point we have no problem, c->wbuf is empty. However
 +       * refile nextblock to avoid writing again to same address.
 +       */
 +
 +      spin_lock(&c->erase_completion_lock);
 +
 +      jeb = &c->blocks[outvec_to / c->sector_size];
 +      jffs2_block_refile(c, jeb, REFILE_ANYWAY);
 +
 +      spin_unlock(&c->erase_completion_lock);
  
 -exit:
 +outerr:
 +      *retlen = 0;
        up_write(&c->wbuf_sem);
        return ret;
  }
@@@ -1107,7 -1164,7 +1094,7 @@@ int jffs2_nand_flash_setup(struct jffs2
  
        /* Initialise write buffer */
        init_rwsem(&c->wbuf_sem);
-       c->wbuf_pagesize = c->mtd->oobblock;
+       c->wbuf_pagesize = c->mtd->writesize;
        c->wbuf_ofs = 0xFFFFFFFF;
  
        c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
@@@ -1178,33 -1235,14 +1165,14 @@@ void jffs2_dataflash_cleanup(struct jff
        kfree(c->wbuf);
  }
  
- int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
-       /* Cleanmarker is actually larger on the flashes */
-       c->cleanmarker_size = 16;
-       /* Initialize write buffer */
-       init_rwsem(&c->wbuf_sem);
-       c->wbuf_pagesize = c->mtd->eccsize;
-       c->wbuf_ofs = 0xFFFFFFFF;
-       c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
-       if (!c->wbuf)
-               return -ENOMEM;
-       return 0;
- }
- void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) {
-       kfree(c->wbuf);
- }
  int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
-       /* Cleanmarker currently occupies a whole programming region */
-       c->cleanmarker_size = MTD_PROGREGION_SIZE(c->mtd);
+       /* Cleanmarker currently occupies whole programming regions,
+        * either one or 2 for 8Byte STMicro flashes. */
+       c->cleanmarker_size = max(16u, c->mtd->writesize);
  
        /* Initialize write buffer */
        init_rwsem(&c->wbuf_sem);
-       c->wbuf_pagesize = MTD_PROGREGION_SIZE(c->mtd);
+       c->wbuf_pagesize = c->mtd->writesize;
        c->wbuf_ofs = 0xFFFFFFFF;
  
        c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);