Eraseblocks torture: OneNAND results

Kyungmin Park kyungmin.park at samsung.com
Fri Dec 15 00:02:23 EST 2006


Hi, Artem

> FYI: now I see that the tortured eraseblocks do not contain all 0xFFs
> after erase which is strange - the driver must have returned an error.
> But mtd->erase is totally silent about this. Most probably it is a bug
> in the OneNAND driver.
>
> May you please take a look at onenand_wait() from
> drivers/mtd/onenand/onenand_base.c in mtd-2.6.git. I see the following
> code there:
>
> -----------------------------------------------------------------------
> ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
> 
> if (ctrl & ONENAND_CTRL_ERROR) {
>     /* It maybe occur at initial bad block */
>     DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n",
> ctrl);
>     /* Clear other interrupt bits for preventing ECC error */
>     interrupt &= ONENAND_INT_MASTER;
> }

> AFAIU, this is exactly the place when we should catch erase errors. But
> what we do - we only change local 'interrupt' variable and later return
> 0. So we do not report about errors. This looks suspiciously. May you
> comment on this?

Yes, you're right. onenand_wait has a bug. It don't report the any error. it's my falut.
And also it don't check the locked block error.

The below patch fix the onenand_wait bug. (This is temporary one. I also try to fix another things)

please test this one.
(You may have some parts already. please ignore it)

In my opition, if the block goes worn-out. it occurs as following.
First, 2-bit ecc read error occurs. (bit error)
Second, Write failed. (page error)
Finally, Erase failed. (block error)

Thank you,
Kyungmin Park

P.S., In target environment, it still can't report any error. I'm also surpise with the OneNAND which has good erase guarantee.


--

Index: drivers/mtd/onenand/onenand_base.c
===================================================================
RCS file: /cvsroot/linux-2.6.18-omap/drivers/mtd/onenand/onenand_base.c,v
retrieving revision 1.2
diff -u -p -r1.2 onenand_base.c
--- drivers/mtd/onenand/onenand_base.c	12 Oct 2006 06:59:27 -0000	1.2
+++ drivers/mtd/onenand/onenand_base.c	15 Dec 2006 04:36:02 -0000
@@ -316,22 +316,20 @@ static int onenand_wait(struct mtd_info 
 	ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
 
 	if (ctrl & ONENAND_CTRL_ERROR) {
-		/* It maybe occur at initial bad block */
 		DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl);
-		/* Clear other interrupt bits for preventing ECC error */
-		interrupt &= ONENAND_INT_MASTER;
-	}
-
-	if (ctrl & ONENAND_CTRL_LOCK) {
-		DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x\n", ctrl);
-		return -EACCES;
+		if (ctrl & ONENAND_CTRL_LOCK)
+			DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n");
+		return ctrl;
 	}
 
 	if (interrupt & ONENAND_INT_READ) {
 		ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
-		if (ecc & ONENAND_ECC_2BIT_ALL) {
+		if (ecc) {
 			DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc);
-			return -EBADMSG;
+			if (ecc & ONENAND_ECC_2BIT_ALL)
+				mtd->ecc_stats.failed++;
+			else if (ecc & ONENAND_ECC_1BIT_ALL)
+				mtd->ecc_stats.corrected++;
 		}
 	}
 
@@ -608,6 +606,7 @@ static int onenand_read(struct mtd_info 
 	size_t *retlen, u_char *buf)
 {
 	struct onenand_chip *this = mtd->priv;
+	struct mtd_ecc_stats stats;
 	int read = 0, column;
 	int thislen;
 	int ret = 0;
@@ -626,6 +625,7 @@ static int onenand_read(struct mtd_info 
 
 	/* TODO handling oob */
 
+	stats = mtd->ecc_stats;
 	while (read < len) {
 		thislen = min_t(int, mtd->writesize, len - read);
 
@@ -643,16 +643,16 @@ static int onenand_read(struct mtd_info 
 
 		this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
 
-		read += thislen;
-
-		if (read == len)
-			break;
-
 		if (ret) {
 			DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret);
 			goto out;
 		}
 
+		read += thislen;
+
+		if (read == len)
+			break;
+
 		from += thislen;
 		buf += thislen;
 	}
@@ -667,7 +667,10 @@ out:
 	 * retlen == desired len and result == -EBADMSG
 	 */
 	*retlen = read;
-	return ret;
+	if (mtd->ecc_stats.failed - stats.failed)
+		return -EBADMSG;
+
+	return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
 /**
@@ -716,15 +719,16 @@ 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);
+			goto out;
+		}
+
 		read += thislen;
 
 		if (read == len)
 			break;
 
-		if (ret) {
-			DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret);
-			goto out;
-		}
 
 		buf += thislen;
 
@@ -1083,10 +1087,7 @@ static int onenand_erase(struct mtd_info
 		ret = this->wait(mtd, FL_ERASING);
 		/* Check, if it is write protected */
 		if (ret) {
-			if (ret == -EPERM)
-				DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n");
-			else
-				DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
+			DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
 			instr->state = MTD_ERASE_FAILED;
 			instr->fail_addr = addr;
 			goto erase_exit;
Index: drivers/mtd/onenand/onenand_bbt.c
===================================================================
RCS file: /cvsroot/linux-2.6.18-omap/drivers/mtd/onenand/onenand_bbt.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 onenand_bbt.c
--- drivers/mtd/onenand/onenand_bbt.c	12 Oct 2006 05:49:24 -0000	1.1.1.1
+++ drivers/mtd/onenand/onenand_bbt.c	15 Dec 2006 04:36:02 -0000
@@ -93,7 +93,8 @@ static int create_bbt(struct mtd_info *m
 			ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
 						  readlen, &retlen, &buf[0]);
 
-			if (ret)
+			/* Handle initial bad block */
+			if (ret && !(ret & ONENAND_CTRL_LOAD))
 				return ret;
 
 			if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {



More information about the linux-mtd mailing list