mtd: nand: return consistent error codes in ecc.correct() implementations
authorBoris BREZILLON <boris.brezillon@free-electrons.com>
Wed, 30 Dec 2015 19:32:03 +0000 (20:32 +0100)
committerBrian Norris <computersforpeace@gmail.com>
Thu, 7 Jan 2016 02:45:46 +0000 (18:45 -0800)
The error code returned by the ecc.correct() are not consistent over the
all implementations.

Document the expected behavior in include/linux/mtd/nand.h and fix
offending implementations.

[Brian: this looks like a bugfix for the ECC reporting in the bf5xx_nand
driver, but we haven't seen any testing results for it]

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Tested-by: Franklin S Cooper Jr. <fcooper@ti.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_bch.c
drivers/mtd/nand/nand_ecc.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/r852.c
include/linux/mtd/nand.h
include/linux/mtd/nand_bch.h

index 18c4e14ec29f619bc0bd75c880054461b463eb3d..b216bf5213493063a80e871409cfa021ce7b3a78 100644 (file)
@@ -1445,7 +1445,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
                 * We can't correct so many errors */
                dev_dbg(host->dev, "atmel_nand : multiple errors detected."
                                " Unable to correct.\n");
-               return -EIO;
+               return -EBADMSG;
        }
 
        /* if there's a single bit error : we can correct it */
index 9514e136542ff5eaae25b17df3f13d5b73e02014..89d9414c5593bd4cfaec5959c7015d82f3a69e8d 100644 (file)
@@ -252,7 +252,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
         */
        if (hweight32(syndrome[0]) == 1) {
                dev_err(info->device, "ECC data was incorrect!\n");
-               return 1;
+               return -EBADMSG;
        }
 
        syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
@@ -285,7 +285,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
                data = data ^ (0x1 << failing_bit);
                *(dat + failing_byte) = data;
 
-               return 0;
+               return 1;
        }
 
        /*
@@ -298,26 +298,34 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
        dev_err(info->device,
                "Please discard data, mark bad block\n");
 
-       return 1;
+       return -EBADMSG;
 }
 
 static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
                                        u_char *read_ecc, u_char *calc_ecc)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
-       int ret;
+       int ret, bitflips = 0;
 
        ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+       if (ret < 0)
+               return ret;
+
+       bitflips = ret;
 
        /* If ecc size is 512, correct second 256 bytes */
        if (chip->ecc.size == 512) {
                dat += 256;
                read_ecc += 3;
                calc_ecc += 3;
-               ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+               ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+               if (ret < 0)
+                       return ret;
+
+               bitflips += ret;
        }
 
-       return ret;
+       return bitflips;
 }
 
 static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
index 3b49fe86625d2e02acbb0974ea7ddc9b4041e13d..ddb73c33193646c7bcfc318f16d0e5af74fcd9bf 100644 (file)
@@ -207,7 +207,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
                                dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
                                return 1;
                        } else {
-                               return -1;
+                               return -EBADMSG;
                        }
                } else if (!(diff & (diff - 1))) {
                        /* Single bit ECC error in the ECC itself,
@@ -215,7 +215,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
                        return 1;
                } else {
                        /* Uncorrectable error */
-                       return -1;
+                       return -EBADMSG;
                }
 
        }
@@ -391,7 +391,7 @@ compare:
                        return 0;
                case 1:         /* five or more errors detected */
                        davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
-                       return -EIO;
+                       return -EBADMSG;
                case 2:         /* error addresses computed */
                case 3:
                        num_errors = 1 + ((fsr >> 16) & 0x03);
index a2363d33cecc56f5aedd1633b3342ad92dbde21e..adccae3da12072aeb0f886ed25bfbe6241dfbd71 100644 (file)
@@ -254,7 +254,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
        } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
 
        if (timeout == 0)
-           return -1;
+               return -ETIMEDOUT;
 
        reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
        reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
@@ -262,7 +262,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
 
        if (status & JZ_NAND_STATUS_ERROR) {
                if (status & JZ_NAND_STATUS_UNCOR_ERROR)
-                       return -1;
+                       return -EBADMSG;
 
                error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
 
index 95400992c3e9e30d7d6e6c69bac88e893d113312..66e56bb22c0fb50c5945155b63c938a37a33cba2 100644 (file)
@@ -674,7 +674,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
 
        if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
                pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
-               return -1;
+               return -EBADMSG;
        }
 
        return 0;
@@ -701,7 +701,7 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
                err = ecc_stat & ecc_bit_mask;
                if (err > err_limit) {
                        printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
-                       return -1;
+                       return -EBADMSG;
                } else {
                        ret += err;
                }
index e5758d885943ec53f321d02ae99b3d45c9dd192a..a87c1b628dfc5e21b19b40a73e1cebccf6538519 100644 (file)
@@ -98,7 +98,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
                }
        } else if (count < 0) {
                printk(KERN_ERR "ecc unrecoverable error\n");
-               count = -1;
+               count = -EBADMSG;
        }
        return count;
 }
index e6129851bfd8994e24302b093a092eb894856bfb..d1770b06639676e2b1da9286faee20abc00db939 100644 (file)
@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf,
                return 1;       /* error in ECC data; no action needed */
 
        pr_err("%s: uncorrectable ECC error\n", __func__);
-       return -1;
+       return -EBADMSG;
 }
 EXPORT_SYMBOL(__nand_correct_data);
 
index e9cbbc63c566fdcad99e9303bcc1aa68edfdbc45..c553f78ab83f9a7f555f05feff2784146d53a194 100644 (file)
@@ -826,12 +826,12 @@ static int omap_compare_ecc(u8 *ecc_data1,        /* read from NAND memory */
        case 1:
                /* Uncorrectable error */
                pr_debug("ECC UNCORRECTED_ERROR 1\n");
-               return -1;
+               return -EBADMSG;
 
        case 11:
                /* UN-Correctable error */
                pr_debug("ECC UNCORRECTED_ERROR B\n");
-               return -1;
+               return -EBADMSG;
 
        case 12:
                /* Correctable error */
@@ -861,7 +861,7 @@ static int omap_compare_ecc(u8 *ecc_data1,  /* read from NAND memory */
                                return 0;
                }
                pr_debug("UNCORRECTED_ERROR default\n");
-               return -1;
+               return -EBADMSG;
        }
 }
 
index cb0bf09214d5cd29e6077917b2901c16e69b9de8..5b15f2faee38d7419bd2a9618364e8cb489e7168 100644 (file)
@@ -477,7 +477,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
 
        if (dev->dma_error) {
                dev->dma_error = 0;
-               return -1;
+               return -EIO;
        }
 
        r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
@@ -491,7 +491,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
                /* ecc uncorrectable error */
                if (ecc_status & R852_ECC_FAIL) {
                        dbg("ecc: unrecoverable error, in half %d", i);
-                       error = -1;
+                       error = -EBADMSG;
                        goto exit;
                }
 
index 3e92be1d2d439b24798037ea7a9d4b0677de4b2c..5189581151826134bab740a8c27e19ce52327210 100644 (file)
@@ -456,7 +456,13 @@ struct nand_hw_control {
  * @hwctl:     function to control hardware ECC generator. Must only
  *             be provided if an hardware ECC is available
  * @calculate: function for ECC calculation or readback from ECC hardware
- * @correct:   function for ECC correction, matching to ECC generator (sw/hw)
+ * @correct:   function for ECC correction, matching to ECC generator (sw/hw).
+ *             Should return a positive number representing the number of
+ *             corrected bitflips, -EBADMSG if the number of bitflips exceed
+ *             ECC strength, or any other error code if the error is not
+ *             directly related to correction.
+ *             If -EBADMSG is returned the input buffers should be left
+ *             untouched.
  * @read_page_raw:     function to read a raw page without ECC. This function
  *                     should hide the specific layout used by the ECC
  *                     controller and always return contiguous in-band and
index 74acf5367556e9dfde34eb882e117a1a9facf10f..fb0bc3420a10c44c225b4c98839c191f0c89b185 100644 (file)
@@ -55,7 +55,7 @@ static inline int
 nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
                      unsigned char *read_ecc, unsigned char *calc_ecc)
 {
-       return -1;
+       return -ENOTSUPP;
 }
 
 static inline struct nand_bch_control *