[MTD] NAND Add optional ECC status check callback

Add optional hardware specific callback routine to perform extra error
status checks on erase and write failures for devices with hardware ECC.

Signed-off-by: David A. Marlin <dmarlin@redhat.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
David A. Marlin
2005-01-24 03:07:46 +00:00
committed by Thomas Gleixner
parent 99f2a8aea1
commit 068e3c0a00
2 changed files with 68 additions and 13 deletions

View File

@@ -42,6 +42,10 @@
* 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.
*
* Credits:
* David Woodhouse for adding multichip support
*
@@ -55,7 +59,7 @@
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
*
* $Id: nand_base.c,v 1.129 2005/01/23 18:30:50 dmarlin Exp $
* $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -896,6 +900,12 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
if (!cached) {
/* call wait ready function */
status = this->waitfunc (mtd, this, FL_WRITING);
/* See if operation failed and additional status checks are available */
if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
status = this->errstat(mtd, this, FL_WRITING, status, page);
}
/* See if device thinks it succeeded */
if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
@@ -1022,23 +1032,24 @@ out:
#endif
/**
* nand_read - [MTD Interface] MTD compability function for nand_read_ecc
* nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
*
* This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
*/
* 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)
{
return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
}
/**
* nand_read_ecc - [MTD Interface] Read data with ECC
* nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
@@ -1047,10 +1058,34 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
* @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
*
* NAND read with ECC
* 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)
{
return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
}
/**
* nand_do_read_ecc - [MTD Interface] Read data with ECC
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
* @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
* @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
* and how many corrected error bits are acceptable:
* bits 0..7 - number of tolerable errors
* bit 8 - 0 == do not get/release chip, 1 == get/release chip
*
* 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)
{
int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
@@ -1076,7 +1111,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
/* Grab the lock and see if the device is available */
nand_get_device (this, mtd, FL_READING);
if (flags & NAND_GET_DEVICE)
nand_get_device (this, mtd, FL_READING);
/* use userspace supplied oobinfo, if zero */
if (oobsel == NULL)
@@ -1180,7 +1216,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
/* 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 */
if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
ecc_status = this->correct_data(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++;
@@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
p[i] = ecc_status;
}
if (ecc_status == -1) {
if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
ecc_failed++;
}
@@ -1289,7 +1326,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
if (flags & NAND_GET_DEVICE)
nand_release_device(mtd);
/*
* Return success, if no ECC failures, else -EBADMSG
@@ -2103,6 +2141,11 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
status = this->waitfunc (mtd, this, FL_ERASING);
/* See if operation failed and additional status checks are available */
if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
status = this->errstat(mtd, this, FL_ERASING, status, page);
}
/* See if block erase succeeded */
if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);