//------------------------------------------------------------------------------ /// Unmaps a logical block by releasing the corresponding physical block (if /// any). /// Returns 0 if successful; otherwise returns a NandCommon_ERROR code. /// \param mapped Pointer to a MappedNandFlash instance. /// \param logicalBlock Number of logical block to unmap. //------------------------------------------------------------------------------ unsigned char MappedNandFlash_Unmap( struct MappedNandFlash *mapped, unsigned short logicalBlock) { signed short physicalBlock = mapped->logicalMapping[logicalBlock]; unsigned char error; TRACE_INFO("MappedNandFlash_Unmap(LB#%d)\r\n", logicalBlock); ASSERT( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), "MappedNandFlash_Unmap: logicalBlock out-of-range\r\n"); if (physicalBlock != -1) { error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), physicalBlock); if (error) { return error; } } mapped->logicalMapping[logicalBlock] = -1; mapped->mappingModified = 1; return 0; }
/** * \brief Initializes a MappedNandFlash instance. Scans the device to look for and * existing logical block mapping; otherwise starts from scratch (no block * mapped). * * \param mapped Pointer to a MappedNandFlash 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. * \return 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. */ unsigned char MappedNandFlash_Initialize( struct MappedNandFlash *mapped, 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 short numBlocks; unsigned short block; signed short logicalMappingBlock = 0; TRACE_INFO("MappedNandFlash_Initialize()\n\r"); /* Initialize ManagedNandFlash*/ error = ManagedNandFlash_Initialize(MANAGED(mapped), model, commandAddress, addressAddress, dataAddress, pinChipEnable, pinReadyBusy, baseBlock, sizeInBlocks); if (error) { return error; } /* Scan to find logical mapping*/ mapped->mappingModified = 0; error = FindLogicalMappingBlock(mapped, &logicalMappingBlock); if (!error) { /* Extract mapping from block*/ mapped->logicalMappingBlock = logicalMappingBlock; return LoadLogicalMapping(mapped, logicalMappingBlock); } else if (error == NandCommon_ERROR_NOMAPPING) { /* Start with no block mapped*/ mapped->logicalMappingBlock = -1; numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); for (block=0; block < numBlocks; block++) { mapped->logicalMapping[block] = -1; } } else { TRACE_ERROR("MappedNandFlash_Initialize: Initialize device\n\r"); return error; } return 0; }
/** * \brief Returns the physical block mapped with the given logical block, or -1 if it * is not mapped. * \param mapped Pointer to a MappedNandFlash instance. * \param logicalBlock Logical block number. * \return the physical block, or -1 if it is not mapped. */ signed short MappedNandFlash_LogicalToPhysical( const struct MappedNandFlash *mapped, unsigned short logicalBlock) { assert( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)) ) ; /* "MappedNandFlash_LogicalToPhysical: logicalBlock out-of-range\n\r" */ return mapped->logicalMapping[logicalBlock]; }
/** * \brief Returns the number of available blocks in a translated nandflash. * * \param translated Pointer to a TranslatedNandFlash instance. * \return the number of available blocks in a translated nandflash. */ unsigned short TranslatedNandFlash_GetDeviceSizeInBlocks( const struct TranslatedNandFlash *translated) { return ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(translated)) - MINNUMUNALLOCATEDBLOCKS - ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_BAD) - 1; /* Logical mapping block*/ }
//------------------------------------------------------------------------------ /// Returns the physical block mapped with the given logical block, or -1 if it /// is not mapped. /// \param mapped Pointer to a MappedNandFlash instance. /// \param logicalBlock Logical block number. //------------------------------------------------------------------------------ signed short MappedNandFlash_LogicalToPhysical( const struct MappedNandFlash *mapped, unsigned short logicalBlock) { ASSERT( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), "MappedNandFlash_LogicalToPhysical: logicalBlock out-of-range\r\n"); return mapped->logicalMapping[logicalBlock]; }
//------------------------------------------------------------------------------ /// Maps a logical block number to an actual physical block. This allocates /// the physical block (meaning it must be FREE), and releases the previous /// block being replaced (if any). /// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. /// \param mapped Pointer to a MappedNandFlash instance. /// \param logicalBlock Logical block number to map. /// \param physicalBlock Physical block to map to the logical one. //------------------------------------------------------------------------------ unsigned char MappedNandFlash_Map( struct MappedNandFlash *mapped, unsigned short logicalBlock, unsigned short physicalBlock) { unsigned char error; signed short oldPhysicalBlock; TRACE_INFO("MappedNandFlash_Map(LB#%d -> PB#%d)\r\n", logicalBlock, physicalBlock); ASSERT( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), "MappedNandFlash_Map: logicalBlock out-of-range\r\n"); ASSERT( physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), "MappedNandFlash_Map: physicalBlock out-of-range\r\n"); // Allocate physical block error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock); if (error) { return error; } // Release currently mapped block (if any) oldPhysicalBlock = mapped->logicalMapping[logicalBlock]; if (oldPhysicalBlock != -1) { error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), oldPhysicalBlock); if (error) { return error; } } // Set mapping mapped->logicalMapping[logicalBlock] = physicalBlock; mapped->mappingModified = 1; return 0; }
/** * \brief Returns the logical block mapped with the given logical block, or -1 if it * is not mapped. * \param mapped Pointer to a MappedNandFlash instance. * \param physicalBlock Physical block number. * \return the logical block, or -1 if it is not mapped. */ signed short MappedNandFlash_PhysicalToLogical( const struct MappedNandFlash *mapped, unsigned short physicalBlock) { unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); signed short logicalBlock; assert( physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)) ) ; /* "MappedNandFlash_PhysicalToLogical: physicalBlock out-of-range\n\r" */ /* Search the mapping for the desired physical block*/ for ( logicalBlock=0; logicalBlock < numBlocks; logicalBlock++ ) { if ( mapped->logicalMapping[logicalBlock] == physicalBlock ) { return logicalBlock ; } } return -1; }
/** * \brief Maps a logical block number to an actual physical block. This allocates * the physical block (meaning it must be FREE), and releases the previous * block being replaced (if any). * \param mapped Pointer to a MappedNandFlash instance. * \param logicalBlock Logical block number to map. * \param physicalBlock Physical block to map to the logical one. * \return 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. */ unsigned char MappedNandFlash_Map( struct MappedNandFlash *mapped, unsigned short logicalBlock, unsigned short physicalBlock) { unsigned char error; signed short oldPhysicalBlock; TRACE_INFO("MappedNandFlash_Map(LB#%d -> PB#%d)\n\r", logicalBlock, physicalBlock); assert( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)) ) ; /* "MappedNandFlash_Map: logicalBlock out-of-range\n\r" */ assert( physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)) ) ; /* "MappedNandFlash_Map: physicalBlock out-of-range\n\r" */ /* Allocate physical block*/ error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock); if ( error ) { return error; } /* Release currently mapped block (if any)*/ oldPhysicalBlock = mapped->logicalMapping[logicalBlock]; if (oldPhysicalBlock != -1) { error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), oldPhysicalBlock); if ( error ) { return error; } } /* Set mapping*/ mapped->logicalMapping[logicalBlock] = physicalBlock; mapped->mappingModified = 1; return 0; }
/** * \brief Erase all blocks in the mapped area of nand flash. * * \param mapped Pointer to a MappedNandFlash instance. * \param level Erase level. * \return 0. */ unsigned char MappedNandFlash_EraseAll( struct MappedNandFlash *mapped, unsigned char level) { unsigned int block; ManagedNandFlash_EraseAll(MANAGED(mapped), level); /* Reset to no block mapped*/ if (level > NandEraseDIRTY) { mapped->logicalMappingBlock = -1; mapped->mappingModified = 0; for (block=0; block < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); block++) { mapped->logicalMapping[block] = -1; } } return 0; }
/** * \brief Scans a mapped nandflash to find an existing logical block mapping. If a * 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 logicalMappingBlock Pointer to a variable for storing the block number. * \return 0 if mapping has been found; otherwise returns * NandCommon_ERROR_NOMAPPING if no mapping exists, or another NandCommon_ERROR_xxx code. */ static unsigned char FindLogicalMappingBlock( const struct MappedNandFlash *mapped, signed short *logicalMappingBlock) { unsigned short block; unsigned char found; unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped)); unsigned char error; unsigned char data[NandCommon_MAXPAGEDATASIZE]; unsigned int i; //TRACE_INFO("FindLogicalMappingBlock ~%d\n\r", numBlocks); /* Search each LIVE block */ found = 0; block = 0; while (!found && (block < numBlocks)) { /* Check that block is LIVE*/ if (MANAGED(mapped)->blockStatuses[block].status == NandBlockStatus_LIVE) { /* Read block*/ TRACE_INFO("Checking LIVE block #%d\n\r", block); error = ManagedNandFlash_ReadPage(MANAGED(mapped), block, 0, data, 0); if (!error) { /* Compare data with logical mapping pattern*/ i = 0; found = 1; while ((i < pageDataSize) && found) { if (data[i] != PATTERN(i)) { found = 0; } i++; } /* If this is the mapping, stop looking*/ if (found) { TRACE_WARNING_WP("-I- Logical mapping in block #%d\n\r", block); if (logicalMappingBlock) { *logicalMappingBlock = block; } return 0; } } else if (error != NandCommon_ERROR_WRONGSTATUS) { TRACE_ERROR( "FindLogicalMappingBlock: Failed to scan block #%d\n\r", block); return error; } } block++; } TRACE_WARNING("No logical mapping found in device\n\r"); return NandCommon_ERROR_NOMAPPING; }
/** * \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; }
//------------------------------------------------------------------------------ /// 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; }