//------------------------------------------------------------------------------ /// Writes the data and/or spare area of a nandflash page, after calculating an /// ECC for the data area and storing it in the spare. If no data buffer is /// provided, the ECC is read from the existing page spare. If no spare buffer /// is provided, the spare area is still written with the ECC information /// calculated on the data buffer. /// Returns 0 if successful; otherwise returns an error code. /// \param ecc Pointer to an EccNandFlash instance. /// \param block Number of the block to write in. /// \param page Number of the page to write inside the given block. /// \param data Data area buffer, can be 0. /// \param spare Spare area buffer, can be 0. //------------------------------------------------------------------------------ unsigned char EccNandFlash_WritePage( struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char error; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); unsigned char *pSpareBuffer = RawNandFlash_GetSpareBuffer(RAW(ecc)); ASSERT(data || spare, "EccNandFlash_WritePage: At least one area must be written\n\r"); TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page); #ifndef HARDWARE_ECC // Compute ECC on the new data, if provided // If not provided, hamming code set to 0xFFFF.. to keep existing bytes memset(ecc->hamming, 0xFF, NandCommon_MAXSPAREECCBYTES); if (data) { // Compute hamming code on data Hamming_Compute256x(data, pageDataSize, ecc->hamming); } // Store code in spare buffer (if no buffer provided, use a temp. one) if (!spare) { spare = pSpareBuffer; memset(spare, 0xFF, pageSpareSize); } NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, ecc->hamming); // Perform write operation error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare); if (error) goto error; #else // Store code in spare buffer (if no buffer provided, use a temp. one) if (!spare) { spare = pSpareBuffer; memset(spare, 0xFF, pageSpareSize); } // Perform write operation error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare); if (error) goto error; HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); // Perform write operation NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hsiao); error = RawNandFlash_WritePage(RAW(ecc), block, page, 0, spare); if (error) goto error; #endif RawNandFlash_ReleaseSpareBuffer(RAW(ecc)); return 0; error: RawNandFlash_ReleaseSpareBuffer(RAW(ecc)); TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r"); return error; }
//------------------------------------------------------------------------------ /// Copy the data & spare area of one page to another page. The source block /// can be either LIVE or DIRTY, and the destination block must be LIVE; they /// must both have the same parity. /// Returns 0 if successful; NandCommon_ERROR_WRONGSTATUS if one or more page /// is not live; otherwise returns an NandCommon_ERROR_xxx code. /// \param managed Pointer to a ManagedNandFlash instance. /// \param sourceBlock Source block number based on managed area. /// \param sourcePage Number of source page inside the source block. /// \param destBlock Destination block number based on managed area. /// \param destPage Number of destination page inside the dest block. //------------------------------------------------------------------------------ unsigned char ManagedNandFlash_CopyPage( const struct ManagedNandFlash *managed, unsigned short sourceBlock, unsigned short sourcePage, unsigned short destBlock, unsigned short destPage) { unsigned char *pDataBuffer = RawNandFlash_GetDataBuffer(RAW(managed)); unsigned char *pSpareBuffer = RawNandFlash_GetSpareBuffer(RAW(managed)); unsigned char error; ASSERT((sourcePage & 1) == (destPage & 1), "ManagedNandFlash_CopyPage: source & dest pages must have the same parity\n\r"); TRACE_INFO("ManagedNandFlash_CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r", sourceBlock, sourcePage, destBlock, destPage); // Check block statuses if ((managed->blockStatuses[sourceBlock].status != NandBlockStatus_LIVE) && (managed->blockStatuses[sourceBlock].status != NandBlockStatus_DIRTY)) { TRACE_ERROR("ManagedNandFlash_CopyPage: Source block must be LIVE or DIRTY.\n\r"); return NandCommon_ERROR_WRONGSTATUS; } if (managed->blockStatuses[destBlock].status != NandBlockStatus_LIVE) { TRACE_ERROR("ManagedNandFlash_CopyPage: Destination block must be LIVE.\n\r"); return NandCommon_ERROR_WRONGSTATUS; } // If destination page is page #0, block status information must not be // overwritten if (destPage == 0) { // Read data & spare to copy error = EccNandFlash_ReadPage(ECC(managed), managed->baseBlock + sourceBlock, sourcePage, pDataBuffer, pSpareBuffer); if (error) goto error; // Write destination block status information in spare NandSpareScheme_WriteExtra(NandFlashModel_GetScheme(MODEL(managed)), pSpareBuffer, &(managed->blockStatuses[destBlock]), 4, 0); // Write page error = RawNandFlash_WritePage(RAW(managed), managed->baseBlock + destBlock, destPage, pDataBuffer, pSpareBuffer); if (error) goto error; } // Otherwise, a normal copy can be done else { error = RawNandFlash_CopyPage(RAW(managed), managed->baseBlock + sourceBlock, sourcePage, managed->baseBlock + destBlock, destPage); } error: RawNandFlash_ReleaseDataBuffer(RAW(managed)); RawNandFlash_ReleaseSpareBuffer(RAW(managed)); return error; }
//------------------------------------------------------------------------------ /// Reads the data and/or spare of a page of a nandflash chip, and verify that /// the data is valid using the ECC information contained in the spare. If one /// buffer pointer is 0, the corresponding area is not saved. /// Returns 0 if the data has been read and is valid; otherwise returns either /// NandCommon_ERROR_CORRUPTEDDATA or ... /// \param ecc Pointer to an EccNandFlash instance. /// \param block Number of block to read from. /// \param page Number of page to read inside given block. /// \param data Data area buffer. /// \param spare Spare area buffer. //------------------------------------------------------------------------------ unsigned char EccNandFlash_ReadPage( struct EccNandFlash *ecc, unsigned short block, unsigned short page, void *data, void *spare) { unsigned char error; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc)); unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc)); unsigned char *pDataBuffer; unsigned char *pSpareBuffer; TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page); pDataBuffer = (data) ? data : RawNandFlash_GetDataBuffer(RAW(ecc)); pSpareBuffer = (spare) ? spare : RawNandFlash_GetSpareBuffer(RAW(ecc)); #ifndef HARDWARE_ECC // Start by reading the spare and the data error = RawNandFlash_ReadPage(RAW(ecc), block, page, pDataBuffer, pSpareBuffer); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); goto error; } // Retrieve ECC information from page and verify the data NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), pSpareBuffer, ecc->hamming); error = Hamming_Verify256x(pDataBuffer, pageDataSize, ecc->hamming); #else error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, tmpSpare); if (error) { TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); goto error; } // Retrieve ECC information from page NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, ecc->hsiaoInSpare); HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); // Verify the data error = HSMC4_VerifyHsiao((unsigned char*) data, pageDataSize, ecc->hsiaoInSpare, ecc->hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc))); #endif if (error && (error != Hamming_ERROR_SINGLEBIT)) { error = NandCommon_ERROR_CORRUPTEDDATA; TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r", block, page); goto error; } #ifndef HARDWARE_ECC #else if (spare) { memcpy(spare, pSpareBuffer, pageSpareSize); } #endif error: if (data == (unsigned char *) 0) RawNandFlash_ReleaseDataBuffer(RAW(ecc)); if (spare == (unsigned char *) 0) RawNandFlash_ReleaseSpareBuffer(RAW(ecc)); return error; }