Example #1
0
//------------------------------------------------------------------------------
/// 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;
}
Example #2
0
//------------------------------------------------------------------------------
/// 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;   
}
//------------------------------------------------------------------------------
/// Saves the logical mapping on a FREE, unmapped physical block. Allocates the
/// new block, releases the previous one (if any) and save the mapping.
/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_WRONGSTATUS
/// if the block is not LIVE, or a NandCommon_ERROR code.
/// \param mapped  Pointer to a MappedNandFlash instance.
/// \param physicalBlock  Physical block number.
//------------------------------------------------------------------------------
unsigned char MappedNandFlash_SaveLogicalMapping(
    struct MappedNandFlash *mapped,
    unsigned short physicalBlock)
{
    unsigned char error;
    //unsigned char data[NandCommon_MAXPAGEDATASIZE];
    unsigned short pageDataSize =
                    NandFlashModel_GetPageDataSize(MODEL(mapped));
    unsigned char *pDataBuffer;
    //unsigned short numBlocks =
    //                ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
    unsigned int i;
    unsigned int remainingSize;
    unsigned char *currentBuffer;
    unsigned short currentPage;
    unsigned int writeSize;
    signed short previousPhysicalBlock;

    TRACE_INFO("MappedNandFlash_SaveLogicalMapping(B#%d)\r\n", physicalBlock);

    // If mapping has not been modified, do nothing
    if (!mapped->mappingModified) {
        return 0;
    }
    pDataBuffer =  RawNandFlash_GetDataBuffer(RAW(mapped));

    // Allocate new block
    error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock);
    if (error) {
        goto error;
    }

    // Save mapping
    previousPhysicalBlock = mapped->logicalMappingBlock;
    mapped->logicalMappingBlock = physicalBlock;

    // Save actual mapping in pages #1-#XXX
    currentBuffer = (unsigned char *) mapped->logicalMapping;
    remainingSize = sizeof(mapped->logicalMapping);
    currentPage = 1;
    while (remainingSize > 0) {

        writeSize = min(remainingSize, pageDataSize);
        memset(pDataBuffer, 0xFF, pageDataSize);
        memcpy(pDataBuffer, currentBuffer, writeSize);
        error = ManagedNandFlash_WritePage(MANAGED(mapped),
                                           physicalBlock,
                                           currentPage,
                                           pDataBuffer,
                                           0);
        if (error) {
            TRACE_ERROR(
             "MappedNandFlash_SaveLogicalMapping: Failed to write mapping\r\n");
            goto error;
        }

        currentBuffer += writeSize;
        remainingSize -= writeSize;
        currentPage++;
    }

    // Mark page #0 of block with a distinguishible pattern, so the mapping can
    // be retrieved at startup
    for (i=0; i < pageDataSize; i++) {

        pDataBuffer[i] = PATTERN(i);
    }
    error = ManagedNandFlash_WritePage(MANAGED(mapped),
                                       physicalBlock, 0,
                                       pDataBuffer, 0);
    if (error) {
        TRACE_ERROR(
            "MappedNandFlash_SaveLogicalMapping: Failed to write pattern\r\n");
        goto error;
    }

    // Mapping is not modified anymore
    mapped->mappingModified = 0;

    // Release previous block (if any)
    if (previousPhysicalBlock != -1) {

        TRACE_DEBUG("Previous physical block was #%d\r\n",
                    previousPhysicalBlock);
        error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped),
                                              previousPhysicalBlock);
        if (error) {
            goto error;
        }
    }

    TRACE_INFO("Mapping saved on block #%d\r\n", physicalBlock);

error:
    RawNandFlash_ReleaseDataBuffer(RAW(mapped));
    return 0;
}
//------------------------------------------------------------------------------
/// 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).
/// Returns 0 if mapping has been found; otherwise returns
/// NandCommon_ERROR_NOMAPPING if no mapping exists, or another
/// NandCommon_ERROR_xxx code.
/// \param mapped  Pointer to a MappedNandFlash instance.
/// \param logicalMappingBlock  Pointer to a variable for storing the block
///                             number.
//------------------------------------------------------------------------------
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 *pDataBuffer =  RawNandFlash_GetDataBuffer(RAW(mapped));
    unsigned char error;
    //unsigned char data[NandCommon_MAXPAGEDATASIZE];
    unsigned int i;

    TRACE_INFO("FindLogicalMappingBlock()~%d\r\n", 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\r\n", block);
            error = ManagedNandFlash_ReadPage(MANAGED(mapped), block, 0, pDataBuffer, 0);
            if (!error) {

                // Compare data with logical mapping pattern
                i = 0;
                found = 1;
                while ((i < pageDataSize) && found) {

                    if (pDataBuffer[i] != PATTERN(i)) {

                        found = 0;
                    }
                    i++;
                }

                // If this is the mapping, stop looking
                if (found) {

                    TRACE_WARNING_WP("-I- Logical mapping in block #%d\r\n",
                                     block);
                    if (logicalMappingBlock) {

                        *logicalMappingBlock = block;
                    }
                    RawNandFlash_ReleaseDataBuffer(RAW(mapped));
                    return 0;
                }
            }
            else if (error != NandCommon_ERROR_WRONGSTATUS) {

                TRACE_ERROR(
                          "FindLogicalMappingBlock: Failed to scan block #%d\r\n",
                          block);
                RawNandFlash_ReleaseDataBuffer(RAW(mapped));
                return error;
            }
        }

        block++;
    }

    RawNandFlash_ReleaseDataBuffer(RAW(mapped));
    TRACE_WARNING("No logical mapping found in device\r\n");
    return NandCommon_ERROR_NOMAPPING;
}
//------------------------------------------------------------------------------
/// 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;
}