 drivers/mtd/mtdchar.c        |   38 +---
 drivers/mtd/nand/nand_base.c |  377 ++++++++++++++++++++++++++-----------------
 drivers/mtd/nand/nand_bbt.c  |  189 ++++++---------------
 fs/jffs2/wbuf.c              |   87 +++++----
 include/linux/mtd/nand.h     |    8 
 5 files changed, 358 insertions(+), 341 deletions(-)

Index: git/drivers/mtd/mtdchar.c
===================================================================
--- git.orig/drivers/mtd/mtdchar.c	2006-08-07 17:41:00.000000000 +0100
+++ git/drivers/mtd/mtdchar.c	2006-08-17 20:22:29.000000000 +0100
@@ -490,7 +490,7 @@ static int mtd_ioctl(struct inode *inode
 		if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
 			return -EFAULT;
 
-		if (buf.length > 4096)
+		if (buf.length > 0x4096)
 			return -EINVAL;
 
 		if (!mtd->write_oob)
@@ -508,26 +508,21 @@ static int mtd_ioctl(struct inode *inode
 		ops.datbuf = NULL;
 		ops.mode = MTD_OOB_PLACE;
 
-		if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
-			return -EINVAL;
-
-		ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
-		if (!ops.oobbuf)
+		ops.datbuf = kmalloc(buf.length, GFP_KERNEL);
+		if (!ops.datbuf)
 			return -ENOMEM;
 
-		if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) {
-			kfree(ops.oobbuf);
+		if (copy_from_user(ops.datbuf, buf.ptr, buf.length)) {
+			kfree(ops.datbuf);
 			return -EFAULT;
 		}
 
-		buf.start &= ~(mtd->oobsize - 1);
-		ret = mtd->write_oob(mtd, buf.start, &ops);
+		ret = (mtd->write_oob)(mtd, buf.start, &ops);
 
-		if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen,
-				 sizeof(uint32_t)))
+		if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen, sizeof(uint32_t)))
 			ret = -EFAULT;
 
-		kfree(ops.oobbuf);
+		kfree(ops.datbuf);
 		break;
 
 	}
@@ -540,7 +535,7 @@ static int mtd_ioctl(struct inode *inode
 		if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
 			return -EFAULT;
 
-		if (buf.length > 4096)
+		if (buf.length > 0x4096)
 			return -EINVAL;
 
 		if (!mtd->read_oob)
@@ -557,23 +552,18 @@ static int mtd_ioctl(struct inode *inode
 		ops.datbuf = NULL;
 		ops.mode = MTD_OOB_PLACE;
 
-		if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
-			return -EINVAL;
-
-		ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
-		if (!ops.oobbuf)
+		ops.datbuf = kmalloc(buf.length, GFP_KERNEL);
+		if (!ops.datbuf)
 			return -ENOMEM;
 
-		buf.start &= ~(mtd->oobsize - 1);
-		ret = mtd->read_oob(mtd, buf.start, &ops);
+		ret = (mtd->read_oob)(mtd, buf.start, &ops);
 
 		if (put_user(ops.retlen, (uint32_t __user *)argp))
 			ret = -EFAULT;
-		else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf,
-						    ops.retlen))
+		else if (ops.retlen && copy_to_user(buf.ptr, ops.datbuf, ops.retlen))
 			ret = -EFAULT;
 
-		kfree(ops.oobbuf);
+		kfree(ops.datbuf);
 		break;
 	}
 
Index: git/drivers/mtd/nand/nand_base.c
===================================================================
--- git.orig/drivers/mtd/nand/nand_base.c	2006-08-07 17:41:00.000000000 +0100
+++ git/drivers/mtd/nand/nand_base.c	2006-08-17 22:40:21.000000000 +0100
@@ -81,10 +81,22 @@ static struct nand_ecclayout nand_oob_64
 		 .length = 38}}
 };
 
+/* This is used for padding purposes in nand_write_oob */
+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,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
 static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
 			   int new_state);
 
-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);
 
 /*
@@ -348,6 +360,7 @@ static int nand_default_block_markbad(st
 	struct nand_chip *chip = mtd->priv;
 	uint8_t buf[2] = { 0, 0 };
 	int block, ret;
+	struct mtd_oob_ops ops;
 
 	/* Get block number */
 	block = ((int)ofs) >> chip->bbt_erase_shift;
@@ -358,16 +371,10 @@ static int nand_default_block_markbad(st
 	if (chip->options & NAND_USE_FLASH_BBT)
 		ret = nand_update_bbt(mtd, ofs);
 	else {
-		/* We write two bytes, so we dont have to mess with 16 bit
-		 * access
-		 */
-		ofs += mtd->oobsize;
-		chip->ops.len = 2;
-		chip->ops.datbuf = NULL;
-		chip->ops.oobbuf = buf;
-		chip->ops.ooboffs = chip->badblockpos & ~0x01;
-
-		ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+		ops.len = 2;
+		ops.datbuf = buf;
+		ofs += mtd->oobsize + (chip->badblockpos & ~0x01);
+		ret = nand_write_oob(mtd, ofs, &ops);
 	}
 	if (!ret)
 		mtd->ecc_stats.badblocks++;
@@ -980,7 +987,7 @@ static int nand_do_read_ops(struct mtd_i
 		aligned = (bytes == mtd->writesize);
 
 		/* Is the current page in the buffer ? */
-		if (realpage != chip->pagebuf || oob) {
+		if (realpage != chip->pagebuf) {
 			bufpoi = aligned ? buf : chip->buffers.databuf;
 
 			if (likely(sndcmd)) {
@@ -1001,14 +1008,6 @@ static int nand_do_read_ops(struct mtd_i
 
 			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 (!(chip->options & NAND_NO_READRDY)) {
 				/*
 				 * Apply delay or wait for ready/busy pin. Do
@@ -1023,7 +1022,7 @@ static int nand_do_read_ops(struct mtd_i
 					nand_wait_ready(mtd);
 			}
 		} else {
-			memcpy(buf, chip->buffers.databuf + col, bytes);
+ 			memcpy(buf, chip->buffers.databuf + col, bytes);
 			buf += bytes;
 		}
 
@@ -1078,6 +1077,7 @@ static int nand_read(struct mtd_info *mt
 {
 	struct nand_chip *chip = mtd->priv;
 	int ret;
+	struct mtd_oob_ops ops1;
 
 	/* Do not allow reads past end of device */
 	if ((from + len) > mtd->size)
@@ -1086,17 +1086,17 @@ static int nand_read(struct mtd_info *mt
 		return 0;
 
 	nand_get_device(chip, mtd, FL_READING);
-
-	chip->ops.len = len;
-	chip->ops.datbuf = buf;
-	chip->ops.oobbuf = NULL;
-
-	ret = nand_do_read_ops(mtd, from, &chip->ops);
-
-	nand_release_device(mtd);
-
-	*retlen = chip->ops.retlen;
-	return ret;
+ 
+	ops1.len = len;
+	ops1.datbuf = buf;
+	ops1.oobbuf = NULL;
+ 
+	ret = nand_do_read_ops(mtd, from, &ops1);
+ 
+ 	nand_release_device(mtd);
+ 
+	*retlen = ops1.retlen;
+ 	return ret;
 }
 
 /**
@@ -1239,7 +1239,7 @@ static int nand_write_oob_syndrome(struc
 }
 
 /**
- * nand_do_read_oob - [Intern] NAND read out-of-band
+ * nand_do_read_oob - [MTD Interface] NAND read out-of-band
  * @mtd:	MTD device structure
  * @from:	offset to read from
  * @ops:	oob operations description structure
@@ -1249,11 +1249,11 @@ static int nand_write_oob_syndrome(struc
 static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 			    struct mtd_oob_ops *ops)
 {
-	int page, realpage, chipnr, sndcmd = 1;
+	int col, page, realpage, chipnr, sndcmd = 1;
 	struct nand_chip *chip = mtd->priv;
 	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
+        uint8_t *buf;
 	int readlen = ops->len;
-	uint8_t *buf = ops->oobbuf;
 
 	DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
 	      (unsigned long long)from, readlen);
@@ -1265,11 +1265,24 @@ static int nand_do_read_oob(struct mtd_i
 	realpage = (int)(from >> chip->page_shift);
 	page = realpage & chip->pagemask;
 
-	chip->oob_poi = chip->buffers.oobrbuf;
+	/* Mask to get column */
+	col = from & (mtd->oobsize - 1);
+
+        buf = ops->datbuf;
 
 	while(1) {
-		sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
-		buf = nand_transfer_oob(chip, buf, ops);
+		int bytes = min((int)(mtd->oobsize - col), readlen);
+
+		if (likely(sndcmd)) {
+			chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page);
+			sndcmd = 0;
+		}
+
+		chip->read_buf(mtd, buf, bytes);
+
+		readlen -= bytes;
+		if (!readlen)
+			break;
 
 		if (!(chip->options & NAND_NO_READRDY)) {
 			/*
@@ -1284,9 +1297,9 @@ static int nand_do_read_oob(struct mtd_i
 				nand_wait_ready(mtd);
 		}
 
-		readlen -= ops->ooblen;
-		if (!readlen)
-			break;
+		buf += bytes;
+		bytes = mtd->oobsize;
+		col = 0;
 
 		/* Increment page address */
 		realpage++;
@@ -1352,13 +1365,8 @@ static int nand_read_oob(struct mtd_info
 		goto out;
 	}
 
-	if (!ops->datbuf)
-		ret = nand_do_read_oob(mtd, from, ops);
-	else
-		ret = nand_do_read_ops(mtd, from, ops);
+	ret = nand_do_read_oob(mtd, from, ops);
 
-	if (unlikely(ops->mode == MTD_OOB_RAW))
-		chip->ecc.read_page = read_page;
  out:
 	nand_release_device(mtd);
 	return ret;
@@ -1366,6 +1374,76 @@ static int nand_read_oob(struct mtd_info
 
 
 /**
+ * nand_read_raw - [GENERIC] Read raw data including oob into buffer
+ * @mtd:	MTD device structure
+ * @buf:	temporary buffer
+ * @from:	offset to read from
+ * @len:	number of bytes to read
+ * @ooblen:	number of oob data bytes to read
+ *
+ * Read raw data including oob into buffer
+ */
+int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
+		  size_t ooblen)
+{
+	struct nand_chip *chip = mtd->priv;
+	int page = (int)(from >> chip->page_shift);
+	int chipnr = (int)(from >> chip->chip_shift);
+	int sndcmd = 1;
+	int cnt = 0;
+	int pagesize = mtd->writesize + mtd->oobsize;
+	int blockcheck;
+
+	/* Do not allow reads past end of device */
+	if ((from + len) > mtd->size) {
+		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: "
+		      "Attempt read beyond end of device\n");
+		return -EINVAL;
+	}
+
+	/* Grab the lock and see if the device is available */
+	nand_get_device(chip, mtd, FL_READING);
+
+	chip->select_chip(mtd, chipnr);
+
+	/* Add requested oob length */
+	len += ooblen;
+	blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
+
+	while (len) {
+		if (likely(sndcmd)) {
+			chip->cmdfunc(mtd, NAND_CMD_READ0, 0,
+				      page & chip->pagemask);
+			sndcmd = 0;
+		}
+
+		chip->read_buf(mtd, &buf[cnt], pagesize);
+
+		len -= pagesize;
+		cnt += pagesize;
+		page++;
+
+		if (!(chip->options & NAND_NO_READRDY)) {
+			if (!chip->dev_ready)
+				udelay(chip->chip_delay);
+			else
+				nand_wait_ready(mtd);
+		}
+
+		/*
+		 * Check, if the chip supports auto page increment or if we
+		 * cross a block boundary.
+		 */
+		if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck))
+			sndcmd = 1;
+	}
+
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_device(mtd);
+	return 0;
+}
+
+/**
  * nand_write_page_raw - [Intern] raw page write function
  * @mtd:	mtd info structure
  * @chip:	nand chip info structure
@@ -1394,12 +1472,14 @@ static void nand_write_page_swecc(struct
 	const uint8_t *p = buf;
 	int *eccpos = chip->ecc.layout->eccpos;
 
-	/* Software ecc calculation */
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+	if (chip->ecc.mode != NAND_ECC_NONE) {
+		/* Software ecc calculation */
+		for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+			chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 
-	for (i = 0; i < chip->ecc.total; i++)
-		chip->oob_poi[eccpos[i]] = ecc_calc[i];
+		for (i = 0; i < chip->ecc.total; i++)
+			chip->oob_poi[eccpos[i]] = ecc_calc[i];
+	}
 
 	nand_write_page_raw(mtd, chip, buf);
 }
@@ -1528,55 +1608,6 @@ static int nand_write_page(struct mtd_in
 	return 0;
 }
 
-/**
- * nand_fill_oob - [Internal] Transfer client buffer to oob
- * @chip:	nand chip structure
- * @oob:	oob data buffer
- * @ops:	oob ops structure
- */
-static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
-				  struct mtd_oob_ops *ops)
-{
-	size_t len = ops->ooblen;
-
-	switch(ops->mode) {
-
-	case MTD_OOB_PLACE:
-	case MTD_OOB_RAW:
-		memcpy(chip->oob_poi + ops->ooboffs, oob, len);
-		return oob + len;
-
-	case MTD_OOB_AUTO: {
-		struct nand_oobfree *free = chip->ecc.layout->oobfree;
-		uint32_t boffs = 0, woffs = ops->ooboffs;
-		size_t bytes = 0;
-
-		for(; free->length && len; free++, len -= bytes) {
-			/* Write request not from offset 0 ? */
-			if (unlikely(woffs)) {
-				if (woffs >= free->length) {
-					woffs -= free->length;
-					continue;
-				}
-				boffs = free->offset + woffs;
-				bytes = min_t(size_t, len,
-					      (free->length - woffs));
-				woffs = 0;
-			} else {
-				bytes = min_t(size_t, len, free->length);
-				boffs = free->offset;
-			}
-			memcpy(chip->oob_poi + woffs, oob, bytes);
-			oob += bytes;
-		}
-		return oob;
-	}
-	default:
-		BUG();
-	}
-	return NULL;
-}
-
 #define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
 
 /**
@@ -1596,7 +1627,7 @@ static int nand_do_write_ops(struct mtd_
 	uint8_t *oob = ops->oobbuf;
 	uint8_t *buf = ops->datbuf;
 	int bytes = mtd->writesize;
-	int ret;
+	int ret = -EIO;
 
 	ops->retlen = 0;
 
@@ -1631,9 +1662,6 @@ static int nand_do_write_ops(struct mtd_
 	while(1) {
 		int cached = writelen > bytes && page != blockmask;
 
-		if (unlikely(oob))
-			oob = nand_fill_oob(chip, oob, ops);
-
 		ret = nand_write_page(mtd, chip, buf, page, cached);
 		if (ret)
 			break;
@@ -1654,13 +1682,11 @@ static int nand_do_write_ops(struct mtd_
 		}
 	}
 
-	if (unlikely(oob))
-		memset(chip->oob_poi, 0xff, mtd->oobsize);
-
 	ops->retlen = ops->len - writelen;
 	return ret;
 }
 
+
 /**
  * nand_write - [MTD Interface] NAND write with ECC
  * @mtd:	MTD device structure
@@ -1698,6 +1724,57 @@ static int nand_write(struct mtd_info *m
 }
 
 /**
+ * nand_write_raw - [GENERIC] Write raw data including oob
+ * @mtd:	MTD device structure
+ * @buf:	source buffer
+ * @to:		offset to write to
+ * @len:	number of bytes to write
+ * @buf:	source buffer
+ * @oob:	oob buffer
+ *
+ * Write raw data including oob
+ */
+int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+		   const uint8_t *buf, uint8_t *oob)
+{
+	struct nand_chip *chip = mtd->priv;
+	int page = (int)(to >> chip->page_shift);
+	int chipnr = (int)(to >> chip->chip_shift);
+	int ret;
+
+	*retlen = 0;
+
+	/* Do not allow writes past end of device */
+	if ((to + len) > mtd->size) {
+		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write "
+		      "beyond end of device\n");
+		return -EINVAL;
+	}
+
+	/* Grab the lock and see if the device is available */
+	nand_get_device(chip, mtd, FL_WRITING);
+
+	chip->select_chip(mtd, chipnr);
+	chip->oob_poi = oob;
+
+	while (len != *retlen) {
+		ret = nand_write_page(mtd, chip, buf, page, 0);
+		if (ret)
+			return ret;
+		page++;
+		*retlen += mtd->writesize;
+		buf += mtd->writesize;
+		chip->oob_poi += mtd->oobsize;
+	}
+
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_device(mtd);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(nand_write_raw);
+
+/**
  * nand_do_write_oob - [MTD Interface] NAND write out-of-band
  * @mtd:	MTD device structure
  * @to:		offset to write to
@@ -1708,19 +1785,23 @@ static int nand_write(struct mtd_info *m
 static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 			     struct mtd_oob_ops *ops)
 {
-	int chipnr, page, status;
+	int column, page, status, ret = -EIO, chipnr;
 	struct nand_chip *chip = mtd->priv;
+	uint8_t *buf = ops->datbuf;
 
 	DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
 	      (unsigned int)to, (int)ops->len);
 
 	/* Do not allow write past end of page */
-	if ((ops->ooboffs + ops->len) > mtd->oobsize) {
+	column = to & (mtd->oobsize - 1);
+	if ((column + ops->len) > mtd->oobsize) {
 		DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
 		      "Attempt to write past end of page\n");
 		return -EINVAL;
 	}
 
+	nand_get_device(chip, mtd, FL_WRITING);
+
 	chipnr = (int)(to >> chip->chip_shift);
 	chip->select_chip(mtd, chipnr);
 
@@ -1737,24 +1818,57 @@ static int nand_do_write_oob(struct mtd_
 
 	/* Check, if it is write protected */
 	if (nand_check_wp(mtd))
-		return -EROFS;
+		goto out;
 
 	/* Invalidate the page cache, if we write to the cached page */
 	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);
-	memset(chip->oob_poi, 0xff, mtd->oobsize);
+	if (NAND_MUST_PAD(chip)) {
+		chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize,
+			      page & chip->pagemask);
+		/* prepad 0xff for partial programming */
+		chip->write_buf(mtd, ffchars, column);
+		/* write data */
+		chip->write_buf(mtd, buf, ops->len);
+		/* postpad 0xff for partial programming */
+		chip->write_buf(mtd, ffchars, mtd->oobsize - (ops->len + column));
+	} else {
+		chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column,
+			      page & chip->pagemask);
+		chip->write_buf(mtd, buf, ops->len);
+	}
+	/* Send command to program the OOB data */
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 
-	if (status)
-		return status;
+	status = chip->waitfunc(mtd, chip);
 
+	/* See if device thinks it succeeded */
+	if (status & NAND_STATUS_FAIL) {
+		DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
+		      "Failed write, page 0x%08x\n", page);
+		ret = -EIO;
+		goto out;
+	}
 	ops->retlen = ops->len;
 
-	return 0;
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+	/* Send command to read back the data */
+	chip->cmdfunc(mtd, NAND_CMD_READOOB, column, page & chip->pagemask);
+
+	if (chip->verify_buf(mtd, buf, ops->len)) {
+		DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
+		      "Failed write verify, page 0x%08x\n", page);
+		ret = -EIO;
+		goto out;
+	}
+#endif
+	ret = 0;
+ out:
+	/* Deselect and wake up anyone waiting on the device */
+	nand_release_device(mtd);
+
+	return ret;
 }
 
 /**
@@ -1780,32 +1894,9 @@ static int nand_write_oob(struct mtd_inf
 		return -EINVAL;
 	}
 
-	nand_get_device(chip, mtd, FL_WRITING);
-
-	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:
-		goto out;
-	}
-
-	if (!ops->datbuf)
-		ret = nand_do_write_oob(mtd, to, ops);
-	else
-		ret = nand_do_write_ops(mtd, to, ops);
+	ret = nand_do_write_oob(mtd, to, ops);
 
-	if (unlikely(ops->mode == MTD_OOB_RAW))
-		chip->ecc.write_page = write_page;
  out:
-	nand_release_device(mtd);
 	return ret;
 }
 
Index: git/drivers/mtd/nand/nand_bbt.c
===================================================================
--- git.orig/drivers/mtd/nand/nand_bbt.c	2006-08-07 17:41:00.000000000 +0100
+++ git/drivers/mtd/nand/nand_bbt.c	2006-08-17 21:45:08.000000000 +0100
@@ -232,42 +232,6 @@ static int read_abs_bbt(struct mtd_info 
 	return 0;
 }
 
-/*
- * Scan read raw data from flash
- */
-static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
-			 size_t len)
-{
-	struct mtd_oob_ops ops;
-
-	ops.mode = MTD_OOB_RAW;
-	ops.ooboffs = 0;
-	ops.ooblen = mtd->oobsize;
-	ops.oobbuf = buf;
-	ops.datbuf = buf;
-	ops.len = len;
-
-	return mtd->read_oob(mtd, offs, &ops);
-}
-
-/*
- * Scan write data with oob to flash
- */
-static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
-			  uint8_t *buf, uint8_t *oob)
-{
-	struct mtd_oob_ops ops;
-
-	ops.mode = MTD_OOB_PLACE;
-	ops.ooboffs = 0;
-	ops.ooblen = mtd->oobsize;
-	ops.datbuf = buf;
-	ops.oobbuf = oob;
-	ops.len = len;
-
-	return mtd->write_oob(mtd, offs, &ops);
-}
-
 /**
  * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
  * @mtd:	MTD device structure
@@ -279,83 +243,25 @@ static int scan_write_bbt(struct mtd_inf
  * We assume that the bbt bits are in consecutive order.
  *
 */
-static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
-			 struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
 {
 	struct nand_chip *this = mtd->priv;
 
 	/* Read the primary version, if available */
 	if (td->options & NAND_BBT_VERSION) {
-		scan_read_raw(mtd, buf, td->pages[0] << this->page_shift,
-			      mtd->writesize);
+		nand_read_raw(mtd, buf, td->pages[0] << this->page_shift, mtd->writesize, mtd->oobsize);
 		td->version[0] = buf[mtd->writesize + td->veroffs];
-		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
-		       td->pages[0], td->version[0]);
+		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]);
 	}
 
 	/* Read the mirror version, if available */
 	if (md && (md->options & NAND_BBT_VERSION)) {
-		scan_read_raw(mtd, buf, md->pages[0] << this->page_shift,
-			      mtd->writesize);
+		nand_read_raw(mtd, buf, md->pages[0] << this->page_shift, mtd->writesize, mtd->oobsize);
 		md->version[0] = buf[mtd->writesize + md->veroffs];
-		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
-		       md->pages[0], md->version[0]);
+		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
 	}
-	return 1;
-}
-
-/*
- * Scan a given block full
- */
-static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
-			   loff_t offs, uint8_t *buf, size_t readlen,
-			   int scanlen, int len)
-{
-	int ret, j;
-
-	ret = scan_read_raw(mtd, buf, offs, readlen);
-	if (ret)
-		return ret;
 
-	for (j = 0; j < len; j++, buf += scanlen) {
-		if (check_pattern(buf, scanlen, mtd->writesize, bd))
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * Scan a given block partially
- */
-static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
-			   loff_t offs, uint8_t *buf, int len)
-{
-	struct mtd_oob_ops ops;
-	int j, ret;
-
-	ops.len = mtd->oobsize;
-	ops.ooblen = mtd->oobsize;
-	ops.oobbuf = buf;
-	ops.ooboffs = 0;
-	ops.datbuf = NULL;
-	ops.mode = MTD_OOB_PLACE;
-
-	for (j = 0; j < len; j++) {
-		/*
-		 * Read the full oob until read_oob is fixed to
-		 * handle single byte reads for 16 bit
-		 * buswidth
-		 */
-		ret = mtd->read_oob(mtd, offs, &ops);
-		if (ret)
-			return ret;
-
-		if (check_short_pattern(buf, bd))
-			return 1;
-
-		offs += mtd->writesize;
-	}
-	return 0;
+	return 1;
 }
 
 /**
@@ -369,14 +275,14 @@ static int scan_block_fast(struct mtd_in
  * Create a bad block table by scanning the device
  * for the given good/bad block identify pattern
  */
-static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
-	struct nand_bbt_descr *bd, int chip)
+static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
 {
 	struct nand_chip *this = mtd->priv;
-	int i, numblocks, len, scanlen;
+	int i, j, numblocks, len, scanlen;
 	int startblock;
 	loff_t from;
-	size_t readlen;
+	size_t readlen, ooblen;
+	struct mtd_oob_ops ops;
 
 	printk(KERN_INFO "Scanning device for bad blocks\n");
 
@@ -391,17 +297,18 @@ static int create_bbt(struct mtd_info *m
 
 	if (!(bd->options & NAND_BBT_SCANEMPTY)) {
 		/* We need only read few bytes from the OOB area */
-		scanlen = 0;
+		scanlen = ooblen = 0;
 		readlen = bd->len;
 	} else {
 		/* Full page content should be read */
 		scanlen = mtd->writesize + mtd->oobsize;
 		readlen = len * mtd->writesize;
+		ooblen = len * mtd->oobsize;
 	}
 
 	if (chip == -1) {
-		/* Note that numblocks is 2 * (real numblocks) here, see i+=2
-		 * below as it makes shifting and masking less painful */
+		/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
+		 * makes shifting and masking less painful */
 		numblocks = mtd->size >> (this->bbt_erase_shift - 1);
 		startblock = 0;
 		from = 0;
@@ -420,20 +327,37 @@ static int create_bbt(struct mtd_info *m
 	for (i = startblock; i < numblocks;) {
 		int ret;
 
-		if (bd->options & NAND_BBT_SCANALLPAGES)
-			ret = scan_block_full(mtd, bd, from, buf, readlen,
-					      scanlen, len);
-		else
-			ret = scan_block_fast(mtd, bd, from, buf, len);
+		if (bd->options & NAND_BBT_SCANEMPTY)
+			if ((ret = nand_read_raw(mtd, buf, from, readlen, ooblen)))
+				return ret;
 
-		if (ret < 0)
-			return ret;
+		for (j = 0; j < len; j++) {
+			if (!(bd->options & NAND_BBT_SCANEMPTY)) {
 
-		if (ret) {
-			this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-			printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
-			       i >> 1, (unsigned int)from);
-			mtd->ecc_stats.badblocks++;
+				ops.len = mtd->oobsize;
+				ops.datbuf = buf;
+				ops.mode = MTD_OOB_PLACE;
+
+				/* Read the full oob until read_oob is fixed to
+				 * handle single byte reads for 16 bit buswidth */
+				ret = mtd->read_oob(mtd, from + j * mtd->writesize, &ops);
+				if (ret)
+					return ret;
+
+				if (check_short_pattern(buf, bd)) {
+					this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+					printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
+					       i >> 1, (unsigned int)from);
+					break;
+				}
+			} else {
+				if (check_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
+					this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+					printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
+					       i >> 1, (unsigned int)from);
+					break;
+				}
+			}
 		}
 
 		i += 2;
@@ -466,7 +390,6 @@ static int search_bbt(struct mtd_info *m
 	int bits, startblock, block, dir;
 	int scanlen = mtd->writesize + mtd->oobsize;
 	int bbtblocks;
-	int blocktopage = this->bbt_erase_shift - this->page_shift;
 
 	/* Search direction top -> down ? */
 	if (td->options & NAND_BBT_LASTBLOCK) {
@@ -496,14 +419,11 @@ static int search_bbt(struct mtd_info *m
 		td->pages[i] = -1;
 		/* Scan the maximum number of blocks */
 		for (block = 0; block < td->maxblocks; block++) {
-
 			int actblock = startblock + dir * block;
-			loff_t offs = actblock << this->bbt_erase_shift;
-
 			/* Read first page */
-			scan_read_raw(mtd, buf, offs, mtd->writesize);
+			nand_read_raw(mtd, buf, actblock << this->bbt_erase_shift, mtd->writesize, mtd->oobsize);
 			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
-				td->pages[i] = actblock << blocktopage;
+				td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
 				if (td->options & NAND_BBT_VERSION) {
 					td->version[i] = buf[mtd->writesize + td->veroffs];
 				}
@@ -568,14 +488,9 @@ static int write_bbt(struct mtd_info *mt
 	int nrchips, bbtoffs, pageoffs, ooboffs;
 	uint8_t msk[4];
 	uint8_t rcode = td->reserved_block_code;
-	size_t retlen, len = 0;
-	loff_t to;
+	size_t retlen, len = 0, ooblen;
 	struct mtd_oob_ops ops;
-
-	ops.ooblen = mtd->oobsize;
-	ops.ooboffs = 0;
-	ops.datbuf = NULL;
-	ops.mode = MTD_OOB_PLACE;
+	loff_t to;
 
 	if (!rcode)
 		rcode = 0xff;
@@ -675,11 +590,13 @@ static int write_bbt(struct mtd_info *mt
 				       "while reading block for writing "
 				       "bad block table\n");
 			}
+			ops.len = ooblen;
+			ops.datbuf = &buf[len];
+			ops.mode = MTD_OOB_PLACE;
 			/* Read oob data */
-			ops.len = (len >> this->page_shift) * mtd->oobsize;
-			ops.oobbuf = &buf[len];
+			ooblen = (len >> this->page_shift) * mtd->oobsize;
 			res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
-			if (res < 0 || ops.retlen != ops.len)
+			if (res < 0 || ops.retlen != ooblen)
 				goto outerr;
 
 			/* Calc the byte offset in the buffer */
@@ -728,7 +645,7 @@ static int write_bbt(struct mtd_info *mt
 		if (res < 0)
 			goto outerr;
 
-		res = scan_write_bbt(mtd, to, len, buf, &buf[len]);
+		res = nand_write_raw(mtd, to, len, &retlen, buf, &buf[len]);
 		if (res < 0)
 			goto outerr;
 
Index: git/fs/jffs2/wbuf.c
===================================================================
--- git.orig/fs/jffs2/wbuf.c	2006-08-07 17:41:08.000000000 +0100
+++ git/fs/jffs2/wbuf.c	2006-08-17 20:45:00.000000000 +0100
@@ -972,7 +972,7 @@ int jffs2_check_oob_empty(struct jffs2_s
 	ops.ooblen = oobsize;
 	ops.oobbuf = c->oobbuf;
 	ops.ooboffs = 0;
-	ops.datbuf = NULL;
+	ops.datbuf = c->oobbuf;
 	ops.mode = MTD_OOB_PLACE;
 
 	ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);
@@ -1023,6 +1023,7 @@ int jffs2_check_nand_cleanmarker (struct
 	int oobsize = c->mtd->oobsize;
 	unsigned char *p,*b;
 	int i, ret;
+	int cnt, retval = 0;
 	size_t offset = jeb->offset;
 
 	/* Check first if the block is bad. */
@@ -1032,50 +1033,60 @@ int jffs2_check_nand_cleanmarker (struct
 		return 2;
 	}
 
-	ops.len = oobsize;
+	ops.len = oobsize << 1;
 	ops.ooblen = oobsize;
 	ops.oobbuf = c->oobbuf;
 	ops.ooboffs = 0;
-	ops.datbuf = NULL;
+	ops.datbuf = c->oobbuf;
 	ops.mode = MTD_OOB_PLACE;
 
-	ret = c->mtd->read_oob(c->mtd, offset, &ops);
-	if (ret) {
-		D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): "
-			   "Read OOB failed %d for block at %08x\n",
-			   ret, jeb->offset));
-		return ret;
-	}
+	/* Loop through the physical blocks */
+	for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
+		/* Check first if the block is bad. */
+		if (c->mtd->block_isbad (c->mtd, offset)) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
+			return 2;
+		}
+		/*
+		   *    We read oob data from page 0 and 1 of the block.
+		   *    page 0 contains cleanmarker and badblock info
+		   *    page 1 contains failure count of this block
+		 */
+		ret = c->mtd->read_oob(c->mtd, offset, &ops);
 
-	if (ops.retlen < ops.len) {
-		D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): "
-			    "Read OOB return short read (%zd bytes not %d) "
-			    "for block at %08x\n", ops.retlen, ops.len,
-			    jeb->offset));
-		return -EIO;
-	}
+		if (ret) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
+			return ret;
+		}
+		if (ops.retlen < (oobsize << 1)) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset));
+			return -EIO;
+		}
 
-	n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
-	n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
-	n.totlen = cpu_to_je32 (8);
-	p = (unsigned char *) &n;
-	b = c->oobbuf + c->fsdata_pos;
+		/* Check cleanmarker only on the first physical block */
+		if (!cnt) {
+			n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
+			n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
+			n.totlen = cpu_to_je32 (8);
+			p = (unsigned char *) &n;
 
-	for (i = c->fsdata_len; i; i--) {
-		if (*b++ != *p++)
-			ret = 1;
+			for (i = 0; i < c->fsdata_len; i++) {
+				if (c->oobbuf[c->fsdata_pos + i] != p[i]) {
+					retval = 1;
+				}
+			}
+			D1(if (retval == 1) {
+				printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset);
+				printk(KERN_WARNING "OOB at %08zx was ", offset);
+				for (i=0; i < oobsize; i++) {
+					printk("%02x ", c->oobbuf[i]);
+				}
+				printk("\n");
+			})
+		}
+		offset += c->mtd->erasesize;
 	}
-
-	D1(if (ret == 1) {
-		printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): "
-		       "Cleanmarker node not detected in block at %08x\n",
-		       offset);
-		printk(KERN_WARNING "OOB at %08zx was ", offset);
-		for (i=0; i < oobsize; i++)
-			printk("%02x ", c->oobbuf[i]);
-		printk("\n");
-	});
-	return ret;
+	return retval;
 }
 
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
@@ -1093,10 +1104,10 @@ int jffs2_write_nand_cleanmarker(struct 
 	ops.ooblen = c->fsdata_len;;
 	ops.oobbuf = (uint8_t *)&n;
 	ops.ooboffs = c->fsdata_pos;
-	ops.datbuf = NULL;
+	ops.datbuf = (unsigned char *)&n;
 	ops.mode = MTD_OOB_PLACE;
 
-	ret = c->mtd->write_oob(c->mtd, jeb->offset, &ops);
+	ret = c->mtd->write_oob(c->mtd, jeb->offset + c->fsdata_pos, &ops);
 
 	if (ret) {
 		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): "
Index: git/include/linux/mtd/nand.h
===================================================================
--- git.orig/include/linux/mtd/nand.h	2006-08-07 17:41:13.000000000 +0100
+++ git/include/linux/mtd/nand.h	2006-08-17 22:00:52.000000000 +0100
@@ -30,6 +30,14 @@ extern int nand_scan (struct mtd_info *m
 /* Free resources held by the NAND device */
 extern void nand_release (struct mtd_info *mtd);
 
+/* Read raw data from the device without ECC */
+extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from,
+			  size_t len, size_t ooblen);
+
+
+extern int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len,
+			  size_t *retlen, const uint8_t *buf, uint8_t *oob);
+
 /* The maximum number of NAND chips in an array */
 #define NAND_MAX_CHIPS		8
 

