//------------------------------------------------------------------------------ /// Loads the logical mapping contained in the given physical block. /// Returns 0 if successful; otherwise, returns a NandCommon_ERROR code. /// \param mapped Pointer to a MappedNandFlash instance. /// \param physicalBlock Physical block number. //------------------------------------------------------------------------------ static unsigned char LoadLogicalMapping( struct MappedNandFlash *mapped, unsigned short physicalBlock) { unsigned char error; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped)); unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); unsigned char *pDataBuffer = RawNandFlash_GetDataBuffer(RAW(mapped)); unsigned int remainingSize; unsigned char *currentBuffer; unsigned short currentPage; unsigned int readSize; unsigned int i; unsigned char status; signed short logicalBlock; //signed short firstBlock, lastBlock; TRACE_INFO("LoadLogicalMapping(B#%d)\r\n", physicalBlock); // Load mapping from pages #1 - #XXX of block currentBuffer = (unsigned char *) mapped->logicalMapping; remainingSize = sizeof(mapped->logicalMapping); currentPage = 1; while (remainingSize > 0) { // Read page readSize = min(remainingSize, pageDataSize); error = ManagedNandFlash_ReadPage(MANAGED(mapped), physicalBlock, currentPage, pDataBuffer, 0); if (error) { RawNandFlash_ReleaseDataBuffer(RAW(mapped)); TRACE_ERROR( "LoadLogicalMapping: Failed to load mapping\r\n"); return error; } // Copy page info memcpy(currentBuffer, pDataBuffer, readSize); currentBuffer += readSize; remainingSize -= readSize; currentPage++; } // Store mapping block index mapped->logicalMappingBlock = physicalBlock; // Power-loss recovery for (i=0; i < numBlocks; i++) { // Check that this is not the logical mapping block if (i != physicalBlock) { status = mapped->managed.blockStatuses[i].status; logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i); // Block is LIVE if (status == NandBlockStatus_LIVE) { // Block is not mapped -> release it if (logicalBlock == -1) { TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\r\n", i); ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i); } } // Block is DIRTY else if (status == NandBlockStatus_DIRTY) { // Block is mapped -> fake it as live if (logicalBlock != -1) { TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\r\n", i); mapped->managed.blockStatuses[i].status = NandBlockStatus_LIVE; } } // Block is FREE or BAD else { // Block is mapped -> remove it from mapping if (logicalBlock != -1) { TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\r\n", i); mapped->logicalMapping[logicalBlock] = -1; } } } } RawNandFlash_ReleaseDataBuffer(RAW(mapped)); TRACE_WARNING_WP("-I- Mapping loaded from block #%d\r\n", physicalBlock); return 0; }
/** * \brief Loads the logical mapping contained in the given physical block. * block contains the mapping, its index is stored in the provided variable (if * pointer is not 0). * * \param mapped Pointer to a MappedNandFlash instance. * \param physicalBlock Physical block number. * \return 0 if successful; otherwise, returns a NandCommon_ERROR code. */ static unsigned char LoadLogicalMapping( struct MappedNandFlash *mapped, unsigned short physicalBlock) { unsigned char error; unsigned char data[NandCommon_MAXPAGEDATASIZE]; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped)); unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); unsigned int remainingSize; unsigned char *currentBuffer; unsigned short currentPage; unsigned int readSize; unsigned int i; unsigned char status; signed short logicalBlock; /*signed short firstBlock, lastBlock;*/ TRACE_INFO("LoadLogicalMapping(B#%d)\n\r", physicalBlock); /* Load mapping from pages #1 - #XXX of block*/ currentBuffer = (unsigned char *) mapped->logicalMapping; remainingSize = sizeof(mapped->logicalMapping); currentPage = 1; while (remainingSize > 0) { /* Read page*/ readSize = min(remainingSize, pageDataSize); error = ManagedNandFlash_ReadPage(MANAGED(mapped), physicalBlock, currentPage, data, 0); if (error) { TRACE_ERROR( "LoadLogicalMapping: Failed to load mapping\n\r"); return error; } /* Copy page info*/ memcpy(currentBuffer, data, readSize); currentBuffer += readSize; remainingSize -= readSize; currentPage++; } /* Store mapping block index*/ mapped->logicalMappingBlock = physicalBlock; /* Power-loss recovery*/ for (i=0; i < numBlocks; i++) { /* Check that this is not the logical mapping block*/ if (i != physicalBlock) { status = mapped->managed.blockStatuses[i].status; logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i); /* Block is LIVE*/ if (status == NandBlockStatus_LIVE) { /* Block is not mapped -> release it*/ if (logicalBlock == -1) { TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\n\r", i); ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i); } } /* Block is DIRTY*/ else if (status == NandBlockStatus_DIRTY) { /* Block is mapped -> fake it as live*/ if (logicalBlock != -1) { TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\n\r", i); mapped->managed.blockStatuses[i].status = NandBlockStatus_LIVE; } } /* Block is FREE or BAD*/ else { /* Block is mapped -> remove it from mapping*/ if (logicalBlock != -1) { TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\n\r", i); mapped->logicalMapping[logicalBlock] = -1; } } } } TRACE_WARNING_WP("-I- Mapping loaded from block #%d\n\r", physicalBlock); return 0; }
/** * \brief Allocates the best-fitting physical block for the given logical block. * * \param translated Pointer to a TranslatedNandFlash instance. * \param block Logical block number. * \return 0 if successful; otherwise returns NandCommon_ERROR_NOBLOCKFOUND if * there are no more free blocks, or a NandCommon_ERROR code. */ static unsigned char AllocateBlock( struct TranslatedNandFlash *translated, unsigned short block) { unsigned short freeBlock, liveBlock; unsigned char error; signed int eraseDifference; TRACE_DEBUG("Allocating a new block\n\r"); /* Find youngest free block and youngest live block*/ if (ManagedNandFlash_FindYoungestBlock(MANAGED(translated), NandBlockStatus_FREE, &freeBlock)) { TRACE_ERROR("AllocateBlock: Could not find a free block\n\r"); return NandCommon_ERROR_NOBLOCKFOUND; } /* If this is the last free block, save the logical mapping in it and clean dirty blocks */ TRACE_DEBUG("Number of FREE blocks: %d\n\r", ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE)); if (ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE) == 1) { /* Save mapping and clean dirty blocks*/ TRACE_DEBUG("Last FREE block, cleaning up ...\n\r"); error = MappedNandFlash_SaveLogicalMapping(MAPPED(translated), freeBlock); if (error) { TRACE_ERROR("AllocateBlock: Failed to save mapping\n\r"); return error; } error = ManagedNandFlash_EraseDirtyBlocks(MANAGED(translated)); if (error) { TRACE_ERROR("AllocatedBlock: Failed to erase dirty blocks\n\r"); return error; } /* Allocate new block*/ return AllocateBlock(translated, block); } /* Find youngest LIVE block to check the erase count difference*/ if (!ManagedNandFlash_FindYoungestBlock(MANAGED(translated), NandBlockStatus_LIVE, &liveBlock)) { /* Calculate erase count difference*/ TRACE_DEBUG("Free block erase count = %d\n\r", MANAGED(translated)->blockStatuses[freeBlock].eraseCount); TRACE_DEBUG("Live block erase count = %d\n\r", MANAGED(translated)->blockStatuses[liveBlock].eraseCount); eraseDifference = abs(MANAGED(translated)->blockStatuses[freeBlock].eraseCount - MANAGED(translated)->blockStatuses[liveBlock].eraseCount); /* Check if it is too big*/ if (eraseDifference > MAXERASEDIFFERENCE) { TRACE_WARNING("Erase difference too big, switching blocks\n\r"); MappedNandFlash_Map( MAPPED(translated), MappedNandFlash_PhysicalToLogical( MAPPED(translated), liveBlock), freeBlock); ManagedNandFlash_CopyBlock(MANAGED(translated), liveBlock, freeBlock); /* Allocate a new block*/ return AllocateBlock(translated, block); } } /* Map block*/ TRACE_DEBUG("Allocating PB#%d for LB#%d\n\r", freeBlock, block); MappedNandFlash_Map(MAPPED(translated), block, freeBlock); return 0; }