/**
 * \brief Writes the data and/or spare area of a page on a SkipBlock NandFlash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of the block to write.
 * \param page  Number of the page to write inside the given block.
 * \param data  Data area buffer.
 * \param spare  Spare area buffer.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
 */
uint8_t SkipBlockNandFlash_WritePage(
    const struct SkipBlockNandFlash *skipBlock,
    uint16_t block,
    uint16_t page,
    void *data,
    void *spare)
{
    /* Check that the block is LIVE */
    if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {

        TRACE_ERROR("SkipBlockNandFlash_WritePage: Block is BAD.\n\r");
        return NandCommon_ERROR_BADBLOCK;
    }

    /* Write data with ECC calculation */
    return EccNandFlash_WritePage(ECC(skipBlock), block, page, data, spare);
}
示例#2
0
//------------------------------------------------------------------------------
/// Writes the data and/or spare area of a LIVE page on a managed NandFlash.
/// Returns NandCommon_ERROR_WRONGSTATUS if the page is not LIVE; otherwise,
/// returns EccNandFlash_WritePage().
/// \param managed  Pointer to a ManagedNandFlash instance.
/// \param block  The block to write, in managed area.
/// \param page  Number of the page to write inside the given block.
/// \param data  Data area buffer.
/// \param spare  Spare area buffer.
//------------------------------------------------------------------------------
unsigned char ManagedNandFlash_WritePage(
    const struct ManagedNandFlash *managed,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    // Check that the block is LIVE
    if (managed->blockStatuses[block].status != NandBlockStatus_LIVE) {

        TRACE_ERROR("ManagedNandFlash_WritePage: Block must be LIVE.\n\r");
        return NandCommon_ERROR_WRONGSTATUS;
    }

    // Write data with ECC calculation
    return EccNandFlash_WritePage(ECC(managed),
                                  managed->baseBlock + block,
                                  page, data, spare);
}
示例#3
0
//------------------------------------------------------------------------------
/// Reads the data and/or the spare area of a page on a managed nandflash. If
/// the data pointer is not 0, then the block MUST be LIVE.
/// Returns NandCommon_ERROR_WRONGSTATUS if the block is not LIVE and the data
/// pointer is not null; Otherwise, returns EccNandFlash_ReadPage().
/// \param managed  Pointer to a ManagedNandFlash instance.
/// \param block  Block to read page from, based on managed area.
/// \param page  Number of page to read inside the given block.
/// \param data  Data area buffer, can be 0.
/// \param spare  Spare area buffer, can be 0.
//------------------------------------------------------------------------------
unsigned char ManagedNandFlash_ReadPage(
    const struct ManagedNandFlash *managed,
    unsigned short block,
    unsigned short page,
    void *data,
    void *spare)
{
    // Check that the block is LIVE if data is requested
    if ((managed->blockStatuses[block].status != NandBlockStatus_LIVE)
        && (managed->blockStatuses[block].status != NandBlockStatus_DIRTY)) {

        TRACE_ERROR("ManagedNandFlash_ReadPage: Block must be LIVE or DIRTY.\n\r");
        return NandCommon_ERROR_WRONGSTATUS;
    }

    // Read data with ECC verification
    return EccNandFlash_ReadPage(ECC(managed),
                                 managed->baseBlock + block,
                                 page, data, spare);
}
/**
 * \brief Reads the data and/or the spare area of a page on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of block to read page from.
 * \param page  Number of page to read inside the given block.
 * \param data  Data area buffer, can be 0.
 * \param spare  Spare area buffer, can be 0.
 * \note If one of the buffer pointer is 0, then the block MUST not be BAD.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_ReadPage().
 */
uint8_t SkipBlockNandFlash_ReadPage(
    const struct SkipBlockNandFlash *skipBlock,
    uint16_t block,
    uint16_t page,
    void *data,
    void *spare)
{
    #if !defined(OP_BOOTSTRAP_on)
    /* Check that the block is not BAD if data is requested */
    if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {

        TRACE_ERROR("SkipBlockNandFlash_ReadPage: Block is BAD.\n\r");
        return NandCommon_ERROR_BADBLOCK;
    }

    /* Read data with ECC verification */
    return EccNandFlash_ReadPage(ECC(skipBlock), block, page, data, spare);
    #else
	return RawNandFlash_ReadPage(RAW(skipBlock), block, page, data, spare);
    #endif
}
/**
 * \brief Writes the data of a whole block on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of the block to write.
 * \param data  Data area buffer.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_WritePage().
 */
uint8_t SkipBlockNandFlash_WriteBlock(
    const struct SkipBlockNandFlash *skipBlock,
    uint16_t block,
    void *data)
{
    /* Number of pages per block */
    uint32_t numPagesPerBlock;
    /* Page size */
    uint32_t pageSize;
    /* Page index*/
    uint16_t i;
    /* Error returned by SkipBlockNandFlash_WritePage*/
    uint8_t error = 0;

    /* Retrieve model information*/
    pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
    numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));

    /* Check that the block is LIVE*/
    if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {

        TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Block is BAD.\n\r");
        return NandCommon_ERROR_BADBLOCK;
    }

    for (i = 0; i < numPagesPerBlock; i++) {
        error = EccNandFlash_WritePage(ECC(skipBlock), block, i, data, 0);
        if (error) {

            TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block);
            return NandCommon_ERROR_CANNOTWRITE;
        }
        data = (void *) ((uint8_t *) data + pageSize);
    }

    return 0;
}
/**
 * \brief Reads the data of a whole block on a SkipBlock nandflash.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash instance.
 * \param block  Number of block to read page from.
 * \param page  Number of page to read inside the given block.
 * \param data  Data area buffer, can be 0.
 * \param spare  Spare area buffer, can be 0.
 * \return NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns EccNandFlash_ReadPage().
 */
unsigned char SkipBlockNandFlash_ReadBlock(
    const struct SkipBlockNandFlash *skipBlock,
    unsigned short block,
    void *data)
{
    /* Number of pages per block */
    unsigned int numPagesPerBlock, pageSize;
    /* Page index */
    unsigned short i;
    /* Error returned by SkipBlockNandFlash_WritePage */
    unsigned char error = 0;

    /* Retrieve model information */
    pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
    numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));

    /* Check that the block is not BAD if data is requested */
    if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {

        TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r");
        return NandCommon_ERROR_BADBLOCK;
    }

    /* Read all the pages of the block */
    for (i = 0; i < numPagesPerBlock; i++) {
        error = EccNandFlash_ReadPage(ECC(skipBlock), block, i, data, 0);
        if (error) {

            TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block);
            return error;
        }
        data = (void *) ((unsigned char *) data + pageSize);
    }

    return 0;
}
示例#7
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;
}
示例#8
0
//------------------------------------------------------------------------------
/// 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;
}
/**
 * \brief Initializes a SkipBlockNandFlash instance. Scans the device to retrieve or
 * create block status information.
 *
 * \param skipBlock  Pointer to a SkipBlockNandFlash 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.
 */
uint8_t SkipBlockNandFlash_Initialize(
    struct SkipBlockNandFlash *skipBlock,
    const struct NandFlashModel *model,
    uint32_t commandAddress,
    uint32_t addressAddress,
    uint32_t dataAddress,
    const Pin pinChipEnable,
    const Pin pinReadyBusy)
{
    uint8_t error;
    #if !defined(OP_BOOTSTRAP_on)
    uint32_t numBlocks;
    uint32_t block;
    #endif

    TRACE_DEBUG("SkipBlockNandFlash_Initialize()\n\r");

    /* Initialize SkipBlockNandFlash */
    #if !defined(OP_BOOTSTRAP_on)
    error = EccNandFlash_Initialize(ECC(skipBlock),
                                    model,
                                    commandAddress,
                                    addressAddress,
                                    dataAddress,
                                    pinChipEnable,
                                    pinReadyBusy);
    #else
    error = RawNandFlash_Initialize(RAW(skipBlock),
                                    model,
                                    commandAddress,
                                    addressAddress,
                                    dataAddress,
                                    pinChipEnable,
                                    pinReadyBusy);
    #endif

    #if !defined(OP_BOOTSTRAP_on)
    if (error) {

        return error;
    }

    /* Retrieve model information */
    numBlocks = NandFlashModel_GetDeviceSizeInBlocks(MODEL(skipBlock));

    /* Initialize block statuses */
    TRACE_DEBUG("Retrieving bad block information ...\n\r");

    /* Retrieve block status from their first page spare area */
    for (block = 0; block < numBlocks; block++) {

        /* Read spare of first page */
        error = SkipBlockNandFlash_CheckBlock(skipBlock, block);

        if (error != GOODBLOCK) {

            if (error == BADBLOCK) {

                TRACE_DEBUG("Block #%d is bad\n\r", (unsigned int)block);
            }
            else {

                TRACE_ERROR(
                "SkipBlockNandFlash_Initialize: Cannot retrieve info from block #%u\n\r",(unsigned int) block);
            }
        }
    }
    #endif

    return 0;
}