public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* [RFC PATCH] [MTD] OneNAND: Error message printing and bad block scan errors
@ 2007-01-19 16:43 Adrian Hunter
  2007-02-02 13:51 ` Adrian Hunter
  0 siblings, 1 reply; 5+ messages in thread
From: Adrian Hunter @ 2007-01-19 16:43 UTC (permalink / raw)
  To: ext Kyungmin Park, linux-mtd@lists.infradead.org


Provide the bad block scan with its own read function
so that important error messages that are not from the
the bad block scan, can always be printed.

Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
---
 drivers/mtd/onenand/onenand_base.c |  155 +++++++++++++++++++++++++++++++----
 drivers/mtd/onenand/onenand_bbt.c  |   11 +--
 include/linux/mtd/onenand.h        |    6 ++
 3 files changed, 148 insertions(+), 24 deletions(-)

diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 38aa019..61c9433 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -304,16 +304,16 @@ static int onenand_wait(struct mtd_info 
 	ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
 
 	if (ctrl & ONENAND_CTRL_ERROR) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl);
+		printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
 		if (ctrl & ONENAND_CTRL_LOCK)
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error.\n");
+			printk(KERN_ERR "onenand_wait: it's locked error.\n");
 		return ctrl;
 	}
 
 	if (interrupt & ONENAND_INT_READ) {
 		int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
 		if (ecc) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc);
+			printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
 			if (ecc & ONENAND_ECC_2BIT_ALL) {
 				mtd->ecc_stats.failed++;
 				return ecc;
@@ -704,7 +704,7 @@ static int onenand_read(struct mtd_info 
 
 	/* Do not allow reads past end of device */
 	if ((from + len) > mtd->size) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n");
+		printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n");
 		*retlen = 0;
 		return -EINVAL;
 	}
@@ -796,7 +796,7 @@ static int onenand_read(struct mtd_info 
  *
  * OneNAND read out-of-band data from the spare area
  */
-int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
 			size_t *retlen, u_char *buf)
 {
 	struct onenand_chip *this = mtd->priv;
@@ -810,7 +810,7 @@ int onenand_do_read_oob(struct mtd_info 
 
 	/* Do not allow reads past end of device */
 	if (unlikely((from + len) > mtd->size)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n");
+		printk(KERN_ERR "onenand_read_oob: Attempt read beyond end of device\n");
 		return -EINVAL;
 	}
 
@@ -835,7 +835,7 @@ int onenand_do_read_oob(struct mtd_info 
 		this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
 
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = 0x%x\n", ret);
+			printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret);
 			goto out;
 		}
 
@@ -863,6 +863,125 @@ out:
 }
 
 /**
+ * onenand_bbt_wait - wait until the command is done
+ * @param mtd		MTD device structure
+ *
+ * Wait for command done.
+ */
+static int onenand_bbt_wait(struct mtd_info *mtd)
+{
+	struct onenand_chip * this = mtd->priv;
+	unsigned long timeout;
+	unsigned int interrupt = 0;
+	unsigned int ctrl;
+
+	/* The 20 msec is enough */
+	timeout = jiffies + msecs_to_jiffies(20);
+	while (time_before(jiffies, timeout)) {
+		interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+
+		if (interrupt & ONENAND_INT_MASTER)
+			break;
+	}
+	/* To get correct interrupt status in timeout case */
+	interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+	ctrl      = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+
+	if (ctrl & ONENAND_CTRL_ERROR) {
+		if (ctrl & ONENAND_CTRL_LOAD)
+			return ONENAND_BBT_READ_ERROR;
+		printk(KERN_ERR "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
+		return ONENAND_BBT_READ_FATAL_ERROR;
+	}
+
+	if (interrupt & ONENAND_INT_READ) {
+		int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+		if (ecc & ONENAND_ECC_2BIT_ALL)
+			return ONENAND_BBT_READ_ERROR;
+	} else {
+		printk(KERN_ERR "onenand_bbt_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+		return ONENAND_BBT_READ_FATAL_ERROR;
+	}
+
+	return 0;
+}
+
+/**
+ * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
+ * @param mtd		MTD device structure
+ * @param from		offset to read from
+ * @param len		number of bytes to read
+ * @param retlen	pointer to variable to store the number of read bytes
+ * @param buf		the databuffer to put data
+ *
+ * OneNAND read out-of-band data from the spare area for bbt scan
+ */
+int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u_char *buf)
+{
+	struct onenand_chip *this = mtd->priv;
+	int read = 0, thislen, column;
+	int ret = 0;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+
+	/* Initialize return length value */
+	*retlen = 0;
+
+	/* Do not allow reads past end of device */
+	if (unlikely((from + len) > mtd->size)) {
+		printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
+		return ONENAND_BBT_READ_FATAL_ERROR;
+	}
+
+	/* Grab the lock and see if the device is available */
+	onenand_get_device(mtd, FL_READING);
+
+	column = from & (mtd->oobsize - 1);
+
+	while (read < len) {
+		cond_resched();
+
+		thislen = mtd->oobsize - column;
+		thislen = min_t(int, thislen, len);
+
+		this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+
+		onenand_update_bufferram(mtd, from, 0);
+
+		ret = onenand_bbt_wait(mtd);
+
+		if (ret)
+			goto out;
+
+		/* First copy data and check return value for ECC handling */
+
+		this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
+
+		read += thislen;
+
+		if (read == len)
+			break;
+
+		buf += thislen;
+
+		/* Read more? */
+		if (read < len) {
+			/* Page size */
+			from += mtd->writesize;
+			column = 0;
+		}
+	}
+
+out:
+	/* Deselect and wake up anyone waiting on the device */
+	onenand_release_device(mtd);
+
+	*retlen = read;
+	return ret;
+}
+
+/**
  * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
  * @mtd:	MTD device structure
  * @from:	offset to read from
@@ -974,13 +1093,13 @@ static int onenand_write(struct mtd_info
 
 	/* Do not allow writes past end of device */
 	if (unlikely((to + len) > mtd->size)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n");
+		printk(KERN_ERR "onenand_write: Attempt write to past end of device\n");
 		return -EINVAL;
 	}
 
 	/* Reject writes, which are not page aligned */
         if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
-                DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n");
+                printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n");
                 return -EINVAL;
         }
 
@@ -1020,14 +1139,14 @@ static int onenand_write(struct mtd_info
 
 		ret = this->wait(mtd, FL_WRITING);
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret);
+			printk(KERN_ERR "onenand_write: write failed %d\n", ret);
 			break;
 		}
 
 		/* Only check verify write turn on */
 		ret = onenand_verify_page(mtd, (u_char *) wbuf, to);
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret);
+			printk(KERN_ERR "onenand_write: verify failed %d\n", ret);
 			break;
 		}
 
@@ -1073,7 +1192,7 @@ static int onenand_do_write_oob(struct m
 
 	/* Do not allow writes past end of device */
 	if (unlikely((to + len) > mtd->size)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n");
+		printk(KERN_ERR "onenand_write_oob: Attempt write to past end of device\n");
 		return -EINVAL;
 	}
 
@@ -1102,13 +1221,13 @@ static int onenand_do_write_oob(struct m
 
 		ret = this->wait(mtd, FL_WRITING);
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write filaed %d\n", ret);
+			printk(KERN_ERR "onenand_write_oob: write filaed %d\n", ret);
 			goto out;
 		}
 
 		ret = onenand_verify_oob(mtd, buf, to, thislen);
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret);
+			printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret);
 			goto out;
 		}
 
@@ -1185,19 +1304,19 @@ static int onenand_erase(struct mtd_info
 
 	/* Start address must align on block boundary */
 	if (unlikely(instr->addr & (block_size - 1))) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");
+		printk(KERN_ERR "onenand_erase: Unaligned address\n");
 		return -EINVAL;
 	}
 
 	/* Length must align on block boundary */
 	if (unlikely(instr->len & (block_size - 1))) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block aligned\n");
+		printk(KERN_ERR "onenand_erase: Length not block aligned\n");
 		return -EINVAL;
 	}
 
 	/* Do not allow erase past end of device */
 	if (unlikely((instr->len + instr->addr) > mtd->size)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n");
+		printk(KERN_ERR "onenand_erase: Erase past end of device\n");
 		return -EINVAL;
 	}
 
@@ -1227,7 +1346,7 @@ static int onenand_erase(struct mtd_info
 		ret = this->wait(mtd, FL_ERASING);
 		/* Check, if it is write protected */
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
+			printk(KERN_ERR "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
 			instr->state = MTD_ERASE_FAILED;
 			instr->fail_addr = addr;
 			goto erase_exit;
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index aa46b7f..610723c 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -17,7 +17,7 @@ #include <linux/mtd/mtd.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/compatmac.h>
 
-extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
 			       size_t *retlen, u_char *buf);
 
 /**
@@ -90,14 +90,13 @@ static int create_bbt(struct mtd_info *m
 
 			/* No need to read pages fully,
 			 * just read required OOB bytes */
-			ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
+			ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs,
 						  readlen, &retlen, &buf[0]);
 
-			/* If it is a initial bad block, just ignore it */
-			if (ret && !(ret & ONENAND_CTRL_LOAD))
-				return ret;
+			if (ret == ONENAND_BBT_READ_FATAL_ERROR)
+				return -1;
 
-			if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
+			if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
 				bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
 				printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
 					i >> 1, (unsigned int) from);
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 60b3534..bb8cf8c 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -164,6 +164,12 @@ #define ONENAND_HAS_UNLOCK_ALL		(0x0002)
 #define ONENAND_PAGEBUF_ALLOC		(0x1000)
 
 /*
+ * Bad block scanning errors
+ */
+#define ONENAND_BBT_READ_ERROR			1
+#define ONENAND_BBT_READ_FATAL_ERROR		2
+
+/*
  * OneNAND Flash Manufacturer ID Codes
  */
 #define ONENAND_MFR_SAMSUNG	0xec
-- 
1.4.3

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [RFC PATCH] [MTD] OneNAND: Error message printing and bad block scan errors
  2007-01-19 16:43 [RFC PATCH] [MTD] OneNAND: Error message printing and bad block scan errors Adrian Hunter
@ 2007-02-02 13:51 ` Adrian Hunter
  2007-02-05  7:36   ` [RFC PATCH] [MTD] OneNAND: Error message printing and bad blockscan errors Kyungmin Park
  0 siblings, 1 reply; 5+ messages in thread
From: Adrian Hunter @ 2007-02-02 13:51 UTC (permalink / raw)
  To: linux-mtd

What is the status of this?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [RFC PATCH] [MTD] OneNAND: Error message printing and bad blockscan errors
  2007-02-02 13:51 ` Adrian Hunter
@ 2007-02-05  7:36   ` Kyungmin Park
  2007-02-05  8:35     ` Artem Bityutskiy
  0 siblings, 1 reply; 5+ messages in thread
From: Kyungmin Park @ 2007-02-05  7:36 UTC (permalink / raw)
  To: 'Adrian Hunter', linux-mtd

Hi,

> 
> What is the status of this?
> 

I'm not determine how to handle this one.
As your opinion, It is one approach which separate the wait function for
normal and bbt.
Basically, you want to see what is happen when error occurs. however it's
not useless for normal users

Another approaches are adding new ioctl as "ERRORGETSTATS" or sysfs
interface.
The former is more simple and latter needs more works.

Please give your opinions

Thank you,
Kyungmin Park.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [RFC PATCH] [MTD] OneNAND: Error message printing and bad blockscan errors
  2007-02-05  7:36   ` [RFC PATCH] [MTD] OneNAND: Error message printing and bad blockscan errors Kyungmin Park
@ 2007-02-05  8:35     ` Artem Bityutskiy
  2007-02-06  8:13       ` [RFC PATCH] [MTD] OneNAND: Error message printing and badblockscan errors Kyungmin Park
  0 siblings, 1 reply; 5+ messages in thread
From: Artem Bityutskiy @ 2007-02-05  8:35 UTC (permalink / raw)
  To: kmpark; +Cc: linux-mtd, 'Adrian Hunter'

Hello Kyungmin,

On Mon, 2007-02-05 at 16:36 +0900, Kyungmin Park wrote:
> > What is the status of this?
> 
> I'm not determine how to handle this one.
> As your opinion, It is one approach which separate the wait function for
> normal and bbt.
> Basically, you want to see what is happen when error occurs. however it's
> not useless for normal users
> 
> Another approaches are adding new ioctl as "ERRORGETSTATS" or sysfs
> interface.
> The former is more simple and latter needs more works.

All we wanted is not to be silent in case of sever errors. We hit this
in practice, so the demand in the patch is quite practical.

If you do not want to print errors on scanning phase, looks fair enough,
just add an if there. But Adrian found out that there are more
difference between the wait functions in case of scanning and normal
operations - at least because they react on errors differently. It is a
good reason to have 2 separate function, what he did.

-- 
Best regards,
Artem Bityutskiy (Битюцкий Артём)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [RFC PATCH] [MTD] OneNAND: Error message printing and badblockscan errors
  2007-02-05  8:35     ` Artem Bityutskiy
@ 2007-02-06  8:13       ` Kyungmin Park
  0 siblings, 0 replies; 5+ messages in thread
From: Kyungmin Park @ 2007-02-06  8:13 UTC (permalink / raw)
  To: 'Adrian Hunter', dedekind; +Cc: linux-mtd

Hi Adrian,

> 
> All we wanted is not to be silent in case of sever errors. We 
> hit this in practice, so the demand in the patch is quite practical.
> 
> If you do not want to print errors on scanning phase, looks 
> fair enough, just add an if there. But Adrian found out that 
> there are more difference between the wait functions in case 
> of scanning and normal operations - at least because they 
> react on errors differently. It is a good reason to have 2 
> separate function, what he did.
> 

Please check thie one
As you mentions, we separate the wait function and read oob for bbt

Thank you,
Kyungmin Park

--

diff --git a/drivers/mtd/onenand/onenand_base.c
b/drivers/mtd/onenand/onenand_base.c
index 553b24d..66e1c08 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -304,16 +304,16 @@ static int onenand_wait(struct mtd_info *mtd, int
state)
 	ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
 
 	if (ctrl & ONENAND_CTRL_ERROR) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error =
0x%04x\n", ctrl);
+		printk(KERN_ERR "onenand_wait: controller error =
0x%04x\n", ctrl);
 		if (ctrl & ONENAND_CTRL_LOCK)
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked
error.\n");
+			printk(KERN_ERR "onenand_wait: it's locked
error.\n");
 		return ctrl;
 	}
 
 	if (interrupt & ONENAND_INT_READ) {
 		int ecc = this->read_word(this->base +
ONENAND_REG_ECC_STATUS);
 		if (ecc) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error =
0x%04x\n", ecc);
+			printk(KERN_ERR "onenand_wait: ECC error =
0x%04x\n", ecc);
 			if (ecc & ONENAND_ECC_2BIT_ALL) {
 				mtd->ecc_stats.failed++;
 				return ecc;
@@ -703,7 +703,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t
from, size_t len,
 
 	/* Do not allow reads past end of device */
 	if ((from + len) > mtd->size) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond
end of device\n");
+		printk(KERN_ERR "onenand_read: Attempt read beyond end of
device\n");
 		*retlen = 0;
 		return -EINVAL;
 	}
@@ -834,7 +834,7 @@ static int onenand_transfer_auto_oob(struct mtd_info
*mtd, uint8_t *buf, int col
  *
  * OneNAND read out-of-band data from the spare area
  */
-int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t
len,
 			size_t *retlen, u_char *buf, mtd_oob_mode_t mode)
 {
 	struct onenand_chip *this = mtd->priv;
@@ -854,7 +854,7 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t
from, size_t len,
 	column = from & (mtd->oobsize - 1);
 
 	if (unlikely(column >= oobsize)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempted to
start read outside oob\n");
+		printk(KERN_ERR "onenand_read_oob: Attempted to start read
outside oob\n");
 		return -EINVAL;
 	}
 
@@ -862,7 +862,7 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t
from, size_t len,
 	if (unlikely(from >= mtd->size ||
 		     column + len > ((mtd->size >> this->page_shift) -
 				     (from >> this->page_shift)) *
oobsize)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempted to
read beyond end of device\n");
+		printk(KERN_ERR "onenand_read_oob: Attempted to read beyond
end of device\n");
 		return -EINVAL;
 	}
 
@@ -888,7 +888,7 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t
from, size_t len,
 			this->read_bufferram(mtd, ONENAND_SPARERAM, buf,
column, thislen);
 
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read
failed = 0x%x\n", ret);
+			printk(KERN_ERR "onenand_read_oob: read failed =
0x%x\n", ret);
 			break;
 		}
 
@@ -936,6 +936,121 @@ static int onenand_read_oob(struct mtd_info *mtd,
loff_t from,
 				   &ops->oobretlen, ops->oobbuf, ops->mode);
 }
 
+/**
+ * onenand_bbt_wait - [DEFAULT] wait until the command is done
+ * @param mtd		MTD device structure
+ * @param state		state to select the max. timeout value
+ *
+ * Wait for command done.
+ */
+static int onenand_bbt_wait(struct mtd_info *mtd, int state)
+{
+	struct onenand_chip *this = mtd->priv;
+	unsigned long timeout;
+	unsigned int interrupt;
+	unsigned int ctrl;
+
+	/* The 20 msec is enough */
+	timeout = jiffies + msecs_to_jiffies(20);
+	while (time_before(jiffies, timeout)) {
+		interrupt = this->read_word(this->base +
ONENAND_REG_INTERRUPT);
+		if (interrupt & ONENAND_INT_MASTER)
+			break;
+	}
+	/* To get correct interrupt status in timeout case */
+	interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+	ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+
+	if (ctrl & ONENAND_CTRL_ERROR) {
+		printk(KERN_DEBUG "onenand_bbt_wait: controller error =
0x%04x\n", ctrl);
+		/* Initial bad block case */
+		if (ctrl & ONENAND_CTRL_LOAD)
+			return ONENAND_BBT_READ_ERROR;
+		return ONENAND_BBT_READ_FATAL_ERROR;
+	}
+
+	if (interrupt & ONENAND_INT_READ) {
+		int ecc = this->read_word(this->base +
ONENAND_REG_ECC_STATUS);
+		if (ecc & ONENAND_ECC_2BIT_ALL)
+			return ONENAND_BBT_READ_ERROR;
+	} else {
+		printk(KERN_ERR "onenand_bbt_wait: read timeout!"
+			"ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+		return ONENAND_BBT_READ_FATAL_ERROR;
+	}
+
+	return 0;
+}
+
+/**
+ * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt
scan
+ * @param mtd		MTD device structure
+ * @param from		offset to read from
+ * @param @ops		oob operation description structure
+ *
+ * OneNAND read out-of-band data from the spare area for bbt scan
+ */
+int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, 
+			    struct mtd_oob_ops *ops)
+{
+	struct onenand_chip *this = mtd->priv;
+	int read = 0, thislen, column;
+	int ret = 0;
+	size_t len = ops->ooblen;
+	u_char *buf = ops->oobbuf;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len =
%i\n", (unsigned int) from, len);
+
+	/* Initialize return value */
+	ops->oobretlen = 0;
+
+	/* Do not allow reads past end of device */
+	if (unlikely((from + len) > mtd->size)) {
+		printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond
end of device\n");
+		return ONENAND_BBT_READ_FATAL_ERROR;
+	}
+
+	/* Grab the lock and see if the device is available */
+	onenand_get_device(mtd, FL_READING);
+
+	column = from & (mtd->oobsize - 1);
+
+	while (read < len) {
+		cond_resched();
+
+		thislen = mtd->oobsize - column;
+		thislen = min_t(int, thislen, len);
+
+		this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+
+		onenand_update_bufferram(mtd, from, 0);
+
+		ret = onenand_bbt_wait(mtd, FL_READING);
+		if (ret)
+			break;
+
+		this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column,
thislen);
+		read += thislen;
+		if (read == len)
+			break;
+
+		buf += thislen;
+
+		/* Read more? */
+		if (read < len) {
+			/* Update Page size */
+			from += mtd->writesize;
+			column = 0;
+		}
+	}
+
+	/* Deselect and wake up anyone waiting on the device */
+	onenand_release_device(mtd);
+
+	ops->oobretlen = read;
+	return ret;
+}
+
 #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
 /**
  * onenand_verify_oob - [GENERIC] verify the oob contents after a write
@@ -1040,13 +1155,13 @@ static int onenand_write(struct mtd_info *mtd,
loff_t to, size_t len,
 
 	/* Do not allow writes past end of device */
 	if (unlikely((to + len) > mtd->size)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to
past end of device\n");
+		printk(KERN_ERR "onenand_write: Attempt write to past end
of device\n");
 		return -EINVAL;
 	}
 
 	/* Reject writes, which are not page aligned */
         if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
-                DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write
not page aligned data\n");
+                printk(KERN_ERR "onenand_write: Attempt to write not page
aligned data\n");
                 return -EINVAL;
         }
 
@@ -1086,14 +1201,14 @@ static int onenand_write(struct mtd_info *mtd,
loff_t to, size_t len,
 
 		ret = this->wait(mtd, FL_WRITING);
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write
filaed %d\n", ret);
+			printk(KERN_ERR "onenand_write: write filaed %d\n",
ret);
 			break;
 		}
 
 		/* Only check verify write turn on */
 		ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify
failed %d\n", ret);
+			printk(KERN_ERR "onenand_write: verify failed
%d\n", ret);
 			break;
 		}
 
@@ -1182,13 +1297,13 @@ static int onenand_do_write_oob(struct mtd_info
*mtd, loff_t to, size_t len,
 	column = to & (mtd->oobsize - 1);
 
 	if (unlikely(column >= oobsize)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempted to
start write outside oob\n");
+		printk(KERN_ERR "onenand_write_oob: Attempted to start
write outside oob\n");
 		return -EINVAL;
 	}
 
 	/* For compatibility with NAND: Do not allow write past end of page
*/
 	if (column + len > oobsize) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: "
+		printk(KERN_ERR "onenand_write_oob: "
 		      "Attempt to write past end of page\n");
 		return -EINVAL;
 	}
@@ -1197,7 +1312,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd,
loff_t to, size_t len,
 	if (unlikely(to >= mtd->size ||
 		     column + len > ((mtd->size >> this->page_shift) -
 				     (to >> this->page_shift)) * oobsize)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempted to
write past end of device\n");
+		printk(KERN_ERR "onenand_write_oob: Attempted to write past
end of device\n");
 		return -EINVAL;
 	}
 
@@ -1227,13 +1342,13 @@ static int onenand_do_write_oob(struct mtd_info
*mtd, loff_t to, size_t len,
 
 		ret = this->wait(mtd, FL_WRITING);
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write
failed %d\n", ret);
+			printk(KERN_ERR "onenand_write_oob: write failed
%d\n", ret);
 			break;
 		}
 
 		ret = onenand_verify_oob(mtd, this->page_buf, to);
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify
failed %d\n", ret);
+			printk(KERN_ERR "onenand_write_oob: verify failed
%d\n", ret);
 			break;
 		}
 
@@ -1316,19 +1431,19 @@ static int onenand_erase(struct mtd_info *mtd,
struct erase_info *instr)
 
 	/* Start address must align on block boundary */
 	if (unlikely(instr->addr & (block_size - 1))) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned
address\n");
+		printk(KERN_ERR "onenand_erase: Unaligned address\n");
 		return -EINVAL;
 	}
 
 	/* Length must align on block boundary */
 	if (unlikely(instr->len & (block_size - 1))) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block
aligned\n");
+		printk(KERN_ERR "onenand_erase: Length not block
aligned\n");
 		return -EINVAL;
 	}
 
 	/* Do not allow erase past end of device */
 	if (unlikely((instr->len + instr->addr) > mtd->size)) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of
device\n");
+		printk(KERN_ERR "onenand_erase: Erase past end of
device\n");
 		return -EINVAL;
 	}
 
@@ -1358,7 +1473,7 @@ static int onenand_erase(struct mtd_info *mtd, struct
erase_info *instr)
 		ret = this->wait(mtd, FL_ERASING);
 		/* Check, if it is write protected */
 		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed
erase, block %d\n", (unsigned) (addr >> this->erase_shift));
+			printk(KERN_ERR "onenand_erase: Failed erase, block
%d\n", (unsigned) (addr >> this->erase_shift));
 			instr->state = MTD_ERASE_FAILED;
 			instr->fail_addr = addr;
 			goto erase_exit;
diff --git a/drivers/mtd/onenand/onenand_bbt.c
b/drivers/mtd/onenand/onenand_bbt.c
index acea9a1..aecdd50 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -17,8 +17,8 @@
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/compatmac.h>
 
-extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t
len,
-			       size_t *retlen, u_char *buf, mtd_oob_mode_t
mode);
+extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
+				struct mtd_oob_ops *ops);
 
 /**
  * check_short_pattern - [GENERIC] check if a pattern is in the buffer
@@ -65,6 +65,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr
 	int startblock;
 	loff_t from;
 	size_t readlen, ooblen;
+	struct mtd_oob_ops ops;
 
 	printk(KERN_INFO "Scanning device for bad blocks\n");
 
@@ -82,22 +83,24 @@ static int create_bbt(struct mtd_info *mtd, uint8_t
*buf, struct nand_bbt_descr
 	startblock = 0;
 	from = 0;
 
+	ops.mode = MTD_OOB_PLACE;
+	ops.ooblen = readlen;
+	ops.oobbuf = buf;
+	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
+
 	for (i = startblock; i < numblocks; ) {
 		int ret;
 
 		for (j = 0; j < len; j++) {
-			size_t retlen;
-
 			/* No need to read pages fully,
 			 * just read required OOB bytes */
-			ret = onenand_do_read_oob(mtd, from + j * mtd-
>writesize + bd->offs,
-						  readlen, &retlen,
&buf[0], MTD_OOB_PLACE);
+			ret = onenand_bbt_read_oob(mtd, from + j * mtd-
>writesize + bd->offs, &ops);
 
 			/* If it is a initial bad block, just ignore it */
-			if (ret && !(ret & ONENAND_CTRL_LOAD))
-				return ret;
+			if (ret == ONENAND_BBT_READ_FATAL_ERROR)
+				return -EIO;
 
-			if (check_short_pattern(&buf[j * scanlen], scanlen,
mtd->writesize, bd)) {
+			if (ret || check_short_pattern(&buf[j * scanlen],
scanlen, mtd->writesize, bd)) {
 				bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
 				printk(KERN_WARNING "Bad eraseblock %d at
0x%08x\n",
 					i >> 1, (unsigned int) from);
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 1221b7c..fff8c53 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -92,6 +92,13 @@ struct nand_bbt_descr {
  */
 #define ONENAND_BADBLOCK_POS	0
 
+/*
+ * Bad block scanning errors
+ */
+#define ONENAND_BBT_READ_ERROR		1
+#define ONENAND_BBT_READ_ECC_ERROR	2
+#define ONENAND_BBT_READ_FATAL_ERROR	4
+
 /**
  * struct bbm_info - [GENERIC] Bad Block Table data structure
  * @bbt_erase_shift:	[INTERN] number of address bits in a bbt entry

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-02-06  8:13 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-01-19 16:43 [RFC PATCH] [MTD] OneNAND: Error message printing and bad block scan errors Adrian Hunter
2007-02-02 13:51 ` Adrian Hunter
2007-02-05  7:36   ` [RFC PATCH] [MTD] OneNAND: Error message printing and bad blockscan errors Kyungmin Park
2007-02-05  8:35     ` Artem Bityutskiy
2007-02-06  8:13       ` [RFC PATCH] [MTD] OneNAND: Error message printing and badblockscan errors Kyungmin Park

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox