--- zzzz-none-000/linux-2.6.28.10/drivers/mtd/nand/nand_base.c 2009-05-02 18:54:43.000000000 +0000 +++ fusiv-7390-686/linux-2.6.28.10/drivers/mtd/nand/nand_base.c 2015-06-04 10:55:13.000000000 +0000 @@ -346,7 +346,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *chip = mtd->priv; - uint8_t buf[2] = { 0, 0 }; + uint8_t buf[2] = { 2, 2 }; // hbl: 2 == user bad marked (kernel, urlader nimmt die 1) int block, ret; /* Get block number */ @@ -622,6 +622,7 @@ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; + return; case NAND_CMD_RNDOUT: @@ -655,6 +656,38 @@ ndelay(100); nand_wait_ready(mtd); + + if(chip->options & NAND_FLASH_HWECC) { + switch (command) { + case NAND_CMD_READ0: + case NAND_CMD_READ1: + { + unsigned int status; + + /*--- printk(KERN_ERR "[%s:%d] was here\n", __func__, __LINE__); ---*/ + + nand_command(mtd, NAND_CMD_STATUS, 0, 0); + status = chip->read_byte(mtd); + if(status & NAND_STATUS_FAIL) { + printk(KERN_ERR "[%s] read block failed (status: 0x%x, column: 0x%x page: 0x%x)\n", __FUNCTION__, status, column, page_addr); + + mtd->ecc_stats.failed++; + } + if(status & NAND_STATUS_CRITICAL_BLOCK) { + printk(KERN_ERR "[%s] read block is critical (status: 0x%x, column: 0x%x page: 0x%x)\n", __FUNCTION__, status, column, page_addr); + mtd->ecc_stats.corrected++; + } + + chip->cmd_ctrl(mtd, command, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + } + break; + default: + break; + } + } } /** @@ -740,6 +773,7 @@ led_trigger_event(nand_led_trigger, LED_OFF); status = (int)chip->read_byte(mtd); + return status; } @@ -752,9 +786,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; } /** @@ -1023,6 +1059,101 @@ } return NULL; } +#if defined(CONFIG_FUSIV_VX180) +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; +} +#endif // !defined(CONFIG_FUSIV_VX180) /** * nand_do_read_ops - [Internal] Read data with ECC @@ -1072,16 +1203,70 @@ sndcmd = 0; } +#if !defined(CONFIG_FUSIV_VX180) /* 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 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; +#else // + /* Now read the page into the buffer */ + { + 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; + } +#endif // defined(CONFIG_FUSIV_VX180) /* Transfer not aligned data */ if (!aligned) { if (!NAND_SUBPAGE_READ(chip) && !oob) @@ -1273,7 +1458,6 @@ chip->write_buf(mtd, buf, length); /* Send command to program the OOB data */ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); return status & NAND_STATUS_FAIL ? -EIO : 0; @@ -1602,6 +1786,12 @@ { int status; +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE + unsigned char no_of_verify_retries = 0; + +verify_retry: +#endif /*--- #ifdef CONFIG_MTD_NAND_VERIFY_WRITE ---*/ + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) @@ -1618,6 +1808,7 @@ if (!cached || !(chip->options & NAND_CACHEPRG)) { chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); /* * See if operation failed and additional status checks are @@ -1635,11 +1826,43 @@ } #ifdef CONFIG_MTD_NAND_VERIFY_WRITE - /* Send command to read back the data */ - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - if (chip->verify_buf(mtd, buf, mtd->writesize)) - return -EIO; + { + // 1. Durchlauf + // .Korrigierbarer Fehler erkannt? + // -> Chip resetten (es wird nichts gelesen) + // -> erneutes Schreiben auf die selbe Page (ohne Löschen) + // + // 2. Durchlauf + // .korrigierbare Fehler sind egal + // .'verify_buf' entscheidet, ob Schreiben funktioniert hat + // + struct mtd_ecc_stats stats = mtd->ecc_stats; + + /* Send command to read back the data */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + if(chip->options & NAND_FLASH_HWECC) { + /*--- printk(KERN_ERR "[%s:%d] was here\n", __func__, __LINE__); ---*/ + + if ( (no_of_verify_retries == 0) + && (mtd->ecc_stats.corrected - stats.corrected)) { + printk(KERN_ERR "VERIFY-ERROR on page: %d: rewrite...\n", page); + + no_of_verify_retries++; + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + goto verify_retry; + } else if(mtd->ecc_stats.corrected - stats.corrected) { + printk(KERN_ERR "VERIFY-ERROR on page: %d: rewrite also results in a correctable error\n", page); + } else if(mtd->ecc_stats.failed - stats.failed) { + printk(KERN_ERR "VERIFY-ERROR on page: %d: non correctable error detected\n", page); + return -EIO; + } + } + + if (chip->verify_buf(mtd, buf, mtd->writesize)) + return -EIO; + } #endif return 0; } @@ -2083,13 +2306,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 @@ -2343,7 +2568,6 @@ tmp_manf = chip->read_byte(mtd); tmp_id = chip->read_byte(mtd); - if (tmp_manf != *maf_id || tmp_id != dev_id) { printk(KERN_INFO "%s: second ID read did not match " "%02x,%02x against %02x,%02x\n", __func__,