--- zzzz-none-000/linux-2.6.28.10/drivers/mtd/nand/nand_base.c 2009-05-02 18:54:43.000000000 +0000 +++ puma5-6360-529/linux-2.6.28.10/drivers/mtd/nand/nand_base.c 2012-05-14 10:10:55.000000000 +0000 @@ -752,9 +752,11 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf) { + int ret = 0; + chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; + return ret; } /** @@ -1024,6 +1026,100 @@ return NULL; } +static int avmCorrectNotWrittenECC(struct mtd_info *mtd, struct nand_chip *chip, int page) { + // copy buf for compare + static uint8_t buf[2048]; // maximale Größe einer Page + static uint8_t compareBuf[2048]; // maximale Größe einer Page + uint8_t *p = buf; + + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + int eccsteps = chip->ecc.steps; + char isECCEqual = 1; + char noECC_0xFF = 0; + int i; + + // 0.1 Einmal UNKORRIGIERTE Daten lesen. + // buf wurde doch schon ecc behandelt. + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + chip->ecc.read_page_raw(mtd, chip, buf); + // 0.2. ECC berechnen + for (i = 0; eccsteps; eccsteps--, i += chip->ecc.bytes, p += chip->ecc.size) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + // 1. ECC-Fehler? + for (i = 0; i < chip->ecc.total; i++) { + if(unlikely(ecc_code[i] != 0xFF)) + noECC_0xFF++; + + if(likely(ecc_code[i] != ecc_calc[i])) + isECCEqual = 0; + } + // 2. ECC-Bytes == 0xFF + if(!isECCEqual && !noECC_0xFF) { +#define AVM_NAND_MAX_RETRIES 3 + int retry = 0; + int dataLen = mtd->writesize; + int areDataEqual; + + if(unlikely(dataLen > 2048)) { + printk(KERN_ERR "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + printk(KERN_ERR "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + printk(KERN_ERR " Patch um ohne ECC geschriebene Daten zu korrigieren wird nicht ausgeführt.\n"); + printk(KERN_ERR " Eine NAND-Page ist größer als 2048 Byte -> Wer hat das freigegeben?\n"); + printk(KERN_ERR " Mein statischer Buffer ist nicht ausreichend groß.\n"); + printk(KERN_ERR "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + printk(KERN_ERR "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + } else { +reRun: + areDataEqual = 1; + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + chip->ecc.read_page_raw(mtd, chip, compareBuf); + for (i = 0; i < dataLen; i++) { + if(unlikely(compareBuf[i] != buf[i])) { + areDataEqual = 0; + break; + } + } + + retry++; + if( (retry <= AVM_NAND_MAX_RETRIES) + && areDataEqual) + goto reRun; + + // 3. wiederholt korrekt gelesen? + if(areDataEqual) { + for (i = 0; i < chip->ecc.total; i++) { + // 1. richtigen ECC kopieren + ecc_code[i] = ecc_calc[i]; + // 2. OOB in Struktur kopieren + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + } + + // 3. ECC in NAND schreiben + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + chip->waitfunc(mtd, chip); + + printk(KERN_ERR "ECC of page: %d corrected\n", page); + + return 0; + } else { + printk(KERN_ERR "ECC stimmt nicht, da er nicht vorhanden ist.\n"); + printk(KERN_ERR "Auch mehrmaliges Lesen der Daten ergab immer Unterschiede.\n"); + printk(KERN_ERR "-> ECC ist nicht korrigierbar: ECC-Fehler nach oben melden.\n"); + } + } + } else if(!isECCEqual) { + // nicht durch uns korrigierbar + //printk(KERN_ERR "ECC stimmt nicht, ist aber anscheined vorhanden. eccBytes=%d\n", noECC_0xFF); + } + + return -1; +} + /** * nand_do_read_ops - [Internal] Read data with ECC * @@ -1073,14 +1169,56 @@ } /* Now read the page into the buffer */ - if (unlikely(ops->mode == MTD_OOB_RAW)) - ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); - else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) - ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); - else - ret = chip->ecc.read_page(mtd, chip, bufpoi); - if (ret < 0) - break; + { + if (unlikely(ops->mode == MTD_OOB_RAW)) + ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); + else { + struct mtd_ecc_stats tmpEccStats = mtd->ecc_stats; + + if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) + ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); + else + ret = chip->ecc.read_page(mtd, chip, bufpoi); + + // Trat ein ecc-Fehler auf? + if(unlikely( (tmpEccStats.failed != mtd->ecc_stats.failed) + || (tmpEccStats.corrected != mtd->ecc_stats.corrected))) { + int isFalseECC = 1; + int i; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + // oob einer Subpage-Anforderung lesen + if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + } + // Vergleichen, ob alle oob-Bytes 0xFF sind + for (i = 0; i < chip->ecc.total; i++) { + if(unlikely(chip->oob_poi[eccpos[i]] != 0xFF)) + isFalseECC = 0; + break; + } + + if(isFalseECC) { + // Konnte der Fehler korrigiert werden? + if(likely(!avmCorrectNotWrittenECC(mtd, chip, page))) { + mtd->ecc_stats.failed = tmpEccStats.failed; + mtd->ecc_stats.corrected = tmpEccStats.corrected; + + // Daten nochmal lesen, da die ersten falsch korrigiert wurden + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) + ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); + else + ret = chip->ecc.read_page(mtd, chip, bufpoi); + } + } + } + } + + if (ret < 0) + break; + } /* Transfer not aligned data */ if (!aligned) { @@ -2083,13 +2221,15 @@ /* * heck if we have a bad block, we do not erase bad blocks ! */ - if (nand_block_checkbad(mtd, ((loff_t) page) << - chip->page_shift, 0, allowbbt)) { - printk(KERN_WARNING "nand_erase: attempt to erase a " - "bad block at page 0x%08x\n", page); - instr->state = MTD_ERASE_FAILED; - goto erase_exit; - } + if (instr->priv != 1) { /*--- 1 signals force to mtd->erase ---*/ + if (nand_block_checkbad(mtd, ((loff_t) page) << + chip->page_shift, 0, allowbbt)) { + printk(KERN_WARNING "nand_erase: attempt to erase a " + "bad block at page 0x%08x\n", page); + instr->state = MTD_ERASE_FAILED; + goto erase_exit; + } + } /* * Invalidate the page cache, if we erase the block which