uint8_t SkipBlockNandFlash_CheckBlock( const struct SkipBlockNandFlash *skipBlock, uint16_t block) { #if !defined (OP_BOOTSTRAP_on) uint8_t spare[NandCommon_MAXPAGESPARESIZE]; uint8_t error; uint8_t badBlockMarker; const struct NandSpareScheme *scheme; /* Retrieve model scheme */ scheme = NandFlashModel_GetScheme(MODEL(skipBlock)); /* Read spare area of first page of block */ error = RawNandFlash_ReadPage(RAW(skipBlock), block, 0, 0, spare); if (error) { TRACE_ERROR("CheckBlock: Cannot read page #0 of block #%d\n\r", block); return error; } NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker); if (badBlockMarker != 0xFF) { return BADBLOCK; } /* Read spare area of second page of block */ error = RawNandFlash_ReadPage(RAW(skipBlock), block, 1, 0, spare); if (error) { TRACE_ERROR("CheckBlock: Cannot read page #1 of block #%d\n\r", block); return error; } NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker); if (badBlockMarker != 0xFF) { return BADBLOCK; } #endif return GOODBLOCK; }
//------------------------------------------------------------------------------ /// Returns 1 if a nandflash device is virgin (i.e. has never been used as a /// managed nandflash); otherwise return 0. /// \param managed Pointer to a ManagedNandFlash instance. /// \param spare Pointer to allocated spare area (must be assigned) //------------------------------------------------------------------------------ static unsigned char IsDeviceVirgin(const struct ManagedNandFlash *managed, unsigned char *spare) { struct NandBlockStatus blockStatus; const struct NandSpareScheme *scheme = NandFlashModel_GetScheme(MODEL(managed)); unsigned short baseBlock = managed->baseBlock; unsigned char badBlockMarker; unsigned char error; ASSERT(spare, "ManagedNandFlash_IsDeviceVirgin: spare\n\r"); // Read spare area of page #0 error = RawNandFlash_ReadPage(RAW(managed), baseBlock, 0, 0, spare); ASSERT(!error, "ManagedNandFlash_IsDeviceVirgin: Failed to read page #0\n\r"); // Retrieve bad block marker and block status from spare area NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker); NandSpareScheme_ReadExtra(scheme, spare, &blockStatus, 4, 0); // Check if block is marked as bad if (badBlockMarker != 0xFF) { // Device is not virgin, since page #0 is guaranteed to be good return 0; } // If device is not virgin, then block status will be set to either // FREE, DIRTY or LIVE else if (blockStatus.status != NandBlockStatus_DEFAULT) { // Device is not virgin return 0; } return 1; }
//------------------------------------------------------------------------------ /// Initializes a ManagedNandFlash instance. Scans the device to retrieve or /// create block status information. /// \param managed Pointer to a ManagedNandFlash instance. /// \param model Pointer to the underlying nand chip model. Can be 0. /// \param commandAddress Address at which commands are sent. /// \param addressAddress Address at which addresses are sent. /// \param dataAddress Address at which data is sent. /// \param pinChipEnable Pin controlling the CE signal of the NandFlash. /// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand. /// \param baseBlock Base physical block address of managed area, managed 0. /// \param sizeInBlocks Number of blocks that is managed. //------------------------------------------------------------------------------ unsigned char ManagedNandFlash_Initialize( struct ManagedNandFlash *managed, const struct NandFlashModel *model, unsigned int commandAddress, unsigned int addressAddress, unsigned int dataAddress, const Pin pinChipEnable, const Pin pinReadyBusy, unsigned short baseBlock, unsigned short sizeInBlocks) { unsigned char error; unsigned char spare[NandCommon_MAXPAGESPARESIZE]; unsigned int numBlocks; const struct NandSpareScheme *scheme; unsigned int block, phyBlock; struct NandBlockStatus blockStatus; unsigned char badBlockMarker; unsigned int eraseCount, minEraseCount, maxEraseCount; TRACE_DEBUG("ManagedNandFlash_Initialize()\n\r"); // Initialize EccNandFlash error = EccNandFlash_Initialize(ECC(managed), model, commandAddress, addressAddress, dataAddress, pinChipEnable, pinReadyBusy); if (error) { return error; } // Retrieve model information numBlocks = NandFlashModel_GetDeviceSizeInBlocks(MODEL(managed)); scheme = NandFlashModel_GetScheme(MODEL(managed)); // Initialize base & size if (sizeInBlocks == 0) sizeInBlocks = numBlocks; if (baseBlock > numBlocks) { baseBlock = 0; } else if (baseBlock + sizeInBlocks > numBlocks) { sizeInBlocks = numBlocks - baseBlock; } TRACE_INFO("Managed NF area: %d + %d\n\r", baseBlock, sizeInBlocks); if (sizeInBlocks > NandCommon_MAXNUMBLOCKS) { TRACE_ERROR("Out of Maxmized Managed Size: %d > %d\n\r", sizeInBlocks, NandCommon_MAXNUMBLOCKS); TRACE_INFO("Change NandCommon_MAXNUMBLOCKS or sizeInBlocks\n\r"); return NandCommon_ERROR_OUTOFBOUNDS; } managed->baseBlock = baseBlock; managed->sizeInBlocks = sizeInBlocks; // Initialize block statuses // First, check if device is virgin if (IsDeviceVirgin(managed, spare)) { TRACE_WARNING("Device is virgin, doing initial block scanning ...\n\r"); // Perform initial scan of the device area for (block=0; block < sizeInBlocks; block++) { phyBlock = baseBlock + block; // Check if physical block is bad error = CheckBlock(managed, phyBlock, spare); if (error == BADBLOCK) { // Mark block as bad TRACE_DEBUG("Block #%d is bad\n\r", block); managed->blockStatuses[block].status = NandBlockStatus_BAD; } else if (error == GOODBLOCK) { // Mark block as free with erase count 0 TRACE_DEBUG("Block #%d is free\n\r", block); managed->blockStatuses[block].status = NandBlockStatus_FREE; managed->blockStatuses[block].eraseCount = 0; // Write status in spare of block first page error = WriteBlockStatus(managed, phyBlock, &(managed->blockStatuses[block]), spare); if (error) { TRACE_ERROR("ManagedNandFlash_Initialize: WR spare\n\r"); return error; } } else { TRACE_ERROR("ManagedNandFlash_Initialize: Scan device\n\r"); return error; } } } else { TRACE_INFO("Managed, retrieving information ...\n\r"); // Retrieve block statuses from their first page spare area // (find maximum and minimum wear at the same time) minEraseCount = 0xFFFFFFFF; maxEraseCount = 0; for (block=0; block < sizeInBlocks; block++) { phyBlock = baseBlock + block; // Read spare of first page error = RawNandFlash_ReadPage(RAW(managed), phyBlock, 0, 0, spare); if (error) { TRACE_ERROR("ManagedNandFlash_Initialize: Read block #%d(%d)\n\r", block, phyBlock); } // Retrieve bad block marker and block status NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker); NandSpareScheme_ReadExtra(scheme, spare, &blockStatus, 4, 0); // If they do not match, block must be bad if ( (badBlockMarker != 0xFF) && (blockStatus.status != NandBlockStatus_BAD)) { TRACE_DEBUG("Block #%d(%d) is bad\n\r", block, phyBlock); managed->blockStatuses[block].status = NandBlockStatus_BAD; } // Check that block status is not default // (meaning block is not managed) else if (blockStatus.status == NandBlockStatus_DEFAULT) { TRACE_ERROR("Block #%d(%d) is not managed\n\r", block, phyBlock); return NandCommon_ERROR_NOMAPPING; } // Otherwise block status is accurate else { TRACE_DEBUG("Block #%03d(%d) : status = %2d | eraseCount = %d\n\r", block, phyBlock, blockStatus.status, blockStatus.eraseCount); managed->blockStatuses[block] = blockStatus; // Check for min/max erase counts if (blockStatus.eraseCount < minEraseCount) { minEraseCount = blockStatus.eraseCount; } if (blockStatus.eraseCount > maxEraseCount) { maxEraseCount = blockStatus.eraseCount; } //// Clean block //// Release LIVE blocks //if (managed->blockStatuses[block].status == NandBlockStatus_LIVE) { // // ManagedNandFlash_ReleaseBlock(managed, block); //} //// Erase DIRTY blocks //if (managed->blockStatuses[block].status == NandBlockStatus_DIRTY) { // // ManagedNandFlash_EraseBlock(managed, block); //} } } // Display erase count information TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r"); TRACE_ERROR_WP("| Wear | Count | Free | Live | Dirty |\n\r"); TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r"); for (eraseCount=minEraseCount; eraseCount <= maxEraseCount; eraseCount++) { unsigned int count = 0, live = 0, dirty = 0, free = 0; for (block=0; block < sizeInBlocks; block++) { if ((managed->blockStatuses[block].eraseCount == eraseCount) && (managed->blockStatuses[block].status != NandBlockStatus_BAD)) { count++; switch (managed->blockStatuses[block].status) { case NandBlockStatus_LIVE: live++; break; case NandBlockStatus_DIRTY: dirty++; break; case NandBlockStatus_FREE: free++; break; } } } if (count > 0) { TRACE_ERROR_WP("| %4d | %8d | %4d | %4d | %4d |\n\r", eraseCount, count, free, live, dirty); } } TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r"); } return 0; }