ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
                                (block * SECTORSIZE), SECTORSIZE, &retlen,
                                movebuf);
-               if (ret < 0) {
+               if (ret < 0 && ret != -EUCLEAN) {
                        ret = mtd->read(mtd,
                                        (inftl->EraseSize * BlockMap[block]) +
                                        (block * SECTORSIZE), SECTORSIZE,
        } else {
                size_t retlen;
                loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
-               if (mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer))
+               int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);
+
+               /* Handle corrected bit flips gracefully */
+               if (ret < 0 && ret != -EUCLEAN)
                        return -EIO;
        }
        return 0;
 
                /* Nand returns -EBADMSG on ecc errors, but it returns
                 * the data. For our userspace tools it is important
                 * to dump areas with ecc errors !
+                * For kernel internal usage it also might return -EUCLEAN
+                * to signal the caller that a bitflip has occured and has
+                * been corrected by the ECC algorithm.
                 * Userspace software which accesses NAND this way
                 * must be aware of the fact that it deals with NAND
                 */
-               if (!ret || (ret == -EBADMSG)) {
+               if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) {
                        *ppos += retlen;
                        if (copy_to_user(buf, kbuf, retlen)) {
                                kfree(kbuf);
 
            size_t * retlen, u_char * buf)
 {
        struct mtd_concat *concat = CONCAT(mtd);
-       int err = -EINVAL;
+       int ret = 0, err = -EINVAL;
        int i;
 
        *retlen = 0;
 
                err = subdev->read(subdev, from, size, &retsize, buf);
 
-               if (err)
+               if (err && (err != -EBADMSG) && (err != -EUCLEAN))
                        break;
 
+               /* Save information about bitflips! */
+               if (err) {
+                       if (err == -EBADMSG)
+                               ret = err;
+                       else if (!ret)
+                               ret = err;
+                       err = 0;
+               }
+
                *retlen += retsize;
                len -= size;
                if (len == 0)
                buf += size;
                from = 0;
        }
-       return err;
+       return err ? err : ret;
 }
 
 static int
 
        if (ret)
                return ret;
 
-       return mtd->ecc_stats.failed - stats.failed ? -EBADMSG : 0;
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
+       return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
 /**
 
 
                ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
                                512, &retlen, movebuf);
-               if (ret < 0) {
+               if (ret < 0 && ret != -EUCLEAN) {
                        ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
                                        + (block * 512), 512, &retlen,
                                        movebuf);
        } else {
                loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
                size_t retlen;
-               if (mtd->read(mtd, ptr, 512, &retlen, buffer))
+               int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
+
+               if (res < 0 && res != -EUCLEAN)
                        return -EIO;
        }
        return 0;
 
                /* Do the read... */
                ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
 
-               if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) {
-                       /* ECC recovered */
+               /* ECC recovered ? */
+               if ((ret == -EUCLEAN || ret == -EBADMSG) &&
+                   (retlen == c->wbuf_ofs - start))
                        ret = 0;
-               }
+
                if (ret || retlen != c->wbuf_ofs - start) {
                        printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
 
        down_read(&c->wbuf_sem);
        ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
 
-       if ( (ret == -EBADMSG) && (*retlen == len) ) {
-               printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
-                      len, ofs);
+       if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) {
+               if (ret == -EBADMSG)
+                       printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx)"
+                              " returned ECC error\n", len, ofs);
                /*
-                * We have the raw data without ECC correction in the buffer, maybe
-                * we are lucky and all data or parts are correct. We check the node.
-                * If data are corrupted node check will sort it out.
-                * We keep this block, it will fail on write or erase and the we
-                * mark it bad. Or should we do that now? But we should give him a chance.
-                * Maybe we had a system crash or power loss before the ecc write or
-                * a erase was completed.
+                * We have the raw data without ECC correction in the buffer,
+                * maybe we are lucky and all data or parts are correct. We
+                * check the node.  If data are corrupted node check will sort
+                * it out.  We keep this block, it will fail on write or erase
+                * and the we mark it bad. Or should we do that now? But we
+                * should give him a chance.  Maybe we had a system crash or
+                * power loss before the ecc write or a erase was completed.
                 * So we return success. :)
                 */
-               ret = 0;
+               ret = 0;
        }
 
        /* if no writebuffer available or write buffer empty, return */
                orbf = (c->wbuf_ofs - ofs);     /* offset in read buffer */
                if (orbf > len)                 /* is write beyond write buffer ? */
                        goto exit;
-               lwbf = len - orbf;              /* number of bytes to copy */
+               lwbf = len - orbf;              /* number of bytes to copy */
                if (lwbf > c->wbuf_len)
                        lwbf = c->wbuf_len;
        }