mtd/drivers/mtd/nand diskonchip.c,1.13,1.14

dbrown at infradead.org dbrown at infradead.org
Fri Jun 18 18:56:51 EDT 2004


Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv16605

Modified Files:
	diskonchip.c 
Log Message:
Fix problems caused because ECC bytes of an erased page != computed ECC over all 0xff data.  Add an option to supress uncorrectable ECC errors for debugging.


Index: diskonchip.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/diskonchip.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- diskonchip.c	18 Jun 2004 00:51:39 -0000	1.13
+++ diskonchip.c	18 Jun 2004 22:56:48 -0000	1.14
@@ -33,6 +33,13 @@
 	int curchip;
 };
 
+/* This is the syndrome computed by the HW ecc generator upon reading an empty
+   page, one with all 0xff for data and stored ecc code. */
+static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
+/* This is the ecc value computed by the HW ecc generator upon writing an empty
+   page, one with all 0xff for data. */
+static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
+
 static char inftl_bbt_pattern[] = "MSYS_BBT";
 
 static struct nand_bbt_descr inftl_bbt_descr = {
@@ -55,6 +62,9 @@
 static int try_dword=1;
 MODULE_PARM(try_dword, "i");
 
+static int no_ecc_failures=0;
+MODULE_PARM(no_ecc_failures, "i");
+
 static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
 {
 	volatile char dummy;
@@ -470,6 +480,7 @@
 	struct doc_priv *doc = (void *)this->priv;
 	unsigned long docptr = doc->virtadr;
 	int i;
+	int emptymatch = 1;
 
 	/* flush the pipeline */
 	if (DoC_is_2000(doc)) {
@@ -484,9 +495,24 @@
 		WriteDOC(0, docptr, NOP);
 	}
 
-	for (i = 0; i < 6; i++)
+	for (i = 0; i < 6; i++) {
 		ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+		if (ecc_code[i] != empty_write_ecc[i])
+			emptymatch = 0;
+	}
 	WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+	/* If emptymatch=1, we might have an all-0xff data buffer.  Check. */
+	if (emptymatch) {
+		for (i = 0; i < 512; i++) {
+			if (dat[i] == 0xff) continue;
+			emptymatch = 0;
+			break;
+		}
+		/* If emptymatch=1 still, we do have an all-0xff data buffer.
+		   Return all-0xff ecc value instead of the computed one, so
+		   it'll look just like a freshly-erased page. */
+		if (emptymatch) memset(ecc_code, 0xff, 6);
+	}
 	return 0;
 }
 
@@ -496,7 +522,8 @@
 	struct nand_chip *this = mtd->priv;
 	struct doc_priv *doc = (void *)this->priv;
 	unsigned long docptr = doc->virtadr;
-	volatile char dummy;
+	volatile u_char dummy;
+	int emptymatch = 1;
 	
 	/* flush the pipeline */
 	if (DoC_is_2000(doc)) {
@@ -511,13 +538,31 @@
 	
 	/* Error occured ? */
 	if (dummy & 0x80) {
-		for (i = 0; i < 6; i++)
+		for (i = 0; i < 6; i++) {
 			calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
-		ret = doc_decode_ecc (dat, calc_ecc);
+			if (calc_ecc[i] != empty_read_syndrome[i])
+				emptymatch = 0;
+		}
+		if (emptymatch) {
+			for (i = 0; i < 6; i++) {
+				if (read_ecc[i] == 0xff) continue;
+				emptymatch = 0;
+				break;
+			}
+		}
+		/* If emptymatch == 1, this is almost certainly a freshly-
+		   erased block, in which case the ECC will not come out right.
+		   We'll suppress the error and tell the caller everything's
+		   OK.  Because it is. */
+		if (!emptymatch) ret = doc_decode_ecc (dat, calc_ecc);
 		if (ret > 0)
 			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
 	}	
 	WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+	if (no_ecc_failures && (ret == -1)) {
+		printk(KERN_ERR "suppressing ECC failure\n");
+		ret = 0;
+	}
 	return ret;
 }
 		





More information about the linux-mtd-cvs mailing list