mirror of
https://github.com/apache/nuttx.git
synced 2026-06-06 08:36:24 +08:00
Condition out most of the recent NXFFS changes for NAND. NXFFS will never be able to support NAND
This commit is contained in:
@@ -34,6 +34,33 @@ config NXFFS_SCAN_VOLUME
|
||||
reboot in these cases. That can be done with
|
||||
apps/system/flash_eraseall.
|
||||
|
||||
config NXFFS_NAND
|
||||
bool "Enable NAND support"
|
||||
default n
|
||||
depends on EXPERIMENTAL
|
||||
---help---
|
||||
NAND differs from other other FLASH types several ways. For one
|
||||
thing, NAND requires error correction (ECC) bytes that must be set
|
||||
in order to work around bit failures. This affects NXFFS in two
|
||||
ways:
|
||||
|
||||
First, write failures are not fatal. Rather, they should be tried by
|
||||
bad blocks and simply ignored. This is because unrecoverable bit
|
||||
failures will cause read failures when reading from NAND. Setting
|
||||
this option will enable this behavior.
|
||||
|
||||
Secondly, NXFFS will write a block many times. It tries to keep
|
||||
bits in the erased state and assumes that it can overwrite those
|
||||
bits to change them from the erased to the non-erased state. This
|
||||
works will with NOR-like FLASH. NAND behaves this way too. But the
|
||||
problem with NAND is that the ECC bits cannot be re-written in this
|
||||
way. So once a block has been written, it cannot be modified. This
|
||||
behavior has NOT been fixed in NXFFS. Currently, NXFFS will attempt
|
||||
to re-write the ECC bits causing the ECC to become corrupted because
|
||||
the ECC bits cannot be overwritten without erasing the entire block.
|
||||
|
||||
This may prohibit NXFFS from ever being used with NAND.
|
||||
|
||||
config NXFFS_REFORMAT_THRESH
|
||||
int "Reformat percentage"
|
||||
default 20
|
||||
|
||||
@@ -91,14 +91,85 @@
|
||||
int nxffs_blockstats(FAR struct nxffs_volume_s *volume,
|
||||
FAR struct nxffs_blkstats_s *stats)
|
||||
{
|
||||
FAR struct nxffs_block_s *blkhdr; /* Pointer to FLASH block header */
|
||||
off_t ioblock; /* I/O block number */
|
||||
#ifndef CONFIG_NXFFS_NAND
|
||||
FAR uint8_t *bptr; /* Pointer to next block data */
|
||||
int lblock; /* Logical block index */
|
||||
#endif
|
||||
off_t ioblock; /* I/O block number */
|
||||
int ret;
|
||||
|
||||
/* Process each erase block */
|
||||
|
||||
memset(stats, 0, sizeof(struct nxffs_blkstats_s));
|
||||
|
||||
#ifndef CONFIG_NXFFS_NAND
|
||||
for (ioblock = 0; ioblock < volume->nblocks; ioblock += volume->blkper)
|
||||
{
|
||||
/* Read the full erase block */
|
||||
|
||||
ret = MTD_BREAD(volume->mtd, ioblock, volume->blkper, volume->pack);
|
||||
if (ret < volume->blkper)
|
||||
{
|
||||
fdbg("ERROR: Failed to read erase block %d: %d\n",
|
||||
ioblock / volume->blkper, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Then examine each logical block in the erase block */
|
||||
|
||||
for (bptr = volume->pack, lblock = 0;
|
||||
lblock < volume->blkper;
|
||||
bptr += volume->geo.blocksize, lblock++)
|
||||
{
|
||||
/* We read the block successfully, now check for errors tagged
|
||||
* in the NXFFS data.
|
||||
*/
|
||||
|
||||
FAR struct nxffs_block_s *blkhdr = (FAR struct nxffs_block_s*)bptr;
|
||||
|
||||
/* Increment the total count of blocks examined */
|
||||
|
||||
stats->nblocks++;
|
||||
|
||||
/* Collect statistics */
|
||||
/* Check if this is a block that should be recognized by NXFFS */
|
||||
|
||||
if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0)
|
||||
{
|
||||
/* Nope.. block must not be formatted */
|
||||
|
||||
stats->nunformat++;
|
||||
}
|
||||
else if (blkhdr->state == BLOCK_STATE_BAD)
|
||||
{
|
||||
/* The block is marked as bad */
|
||||
|
||||
stats->nbad++;
|
||||
}
|
||||
else if (blkhdr->state == BLOCK_STATE_GOOD)
|
||||
{
|
||||
/* The block is marked as good */
|
||||
|
||||
stats-> ngood++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The good/bad mark is not recognized. Let's call this
|
||||
* corrupt (vs. unformatted).
|
||||
*/
|
||||
|
||||
stats->ncorrupt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fdbg("Number blocks: %d\n", stats->nblocks);
|
||||
fdbg(" Good blocks: %d\n", stats->ngood);
|
||||
fdbg(" Bad blocks: %d\n", stats->nbad);
|
||||
fdbg(" Unformatted blocks: %d\n", stats->nunformat);
|
||||
fdbg(" Corrupt blocks: %d\n", stats->ncorrupt);
|
||||
|
||||
#else
|
||||
for (ioblock = 0; ioblock < volume->nblocks; ioblock++)
|
||||
{
|
||||
/* Increment the total count of blocks examined */
|
||||
@@ -132,7 +203,7 @@ int nxffs_blockstats(FAR struct nxffs_volume_s *volume,
|
||||
* in the NXFFS data.
|
||||
*/
|
||||
|
||||
blkhdr = (FAR struct nxffs_block_s*)volume->pack;
|
||||
FAR struct nxffs_block_s *blkhdr = (FAR struct nxffs_block_s*)volume->pack;
|
||||
|
||||
/* Collect statistics */
|
||||
/* Check if this is a block that should be recognized by NXFFS */
|
||||
@@ -151,9 +222,9 @@ int nxffs_blockstats(FAR struct nxffs_volume_s *volume,
|
||||
}
|
||||
else if (blkhdr->state == BLOCK_STATE_GOOD)
|
||||
{
|
||||
/* The block is marked as good */
|
||||
/* The block is marked as good */
|
||||
|
||||
stats-> ngood++;
|
||||
stats-> ngood++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -172,5 +243,7 @@ int nxffs_blockstats(FAR struct nxffs_volume_s *volume,
|
||||
fdbg(" Unformatted blocks: %d\n", stats->nunformat);
|
||||
fdbg(" Corrupt blocks: %d\n", stats->ncorrupt);
|
||||
fdbg(" Unreadable blocks: %d\n", stats->nbadread);
|
||||
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -246,6 +246,12 @@ int nxffs_getc(FAR struct nxffs_volume_s *volume, uint16_t reserve)
|
||||
ret = nxffs_verifyblock(volume, volume->ioblock);
|
||||
if (ret < 0 && ret != -ENOENT)
|
||||
{
|
||||
#ifndef CONFIG_NXFFS_NAND
|
||||
/* Read errors are fatal */
|
||||
|
||||
fdbg("ERROR: Failed to read valid data into cache: %d\n", ret);
|
||||
return ret;
|
||||
#else
|
||||
/* A read error occurred. This probably means that we are
|
||||
* using NAND memory this block has an uncorrectable bit error.
|
||||
* Ignore the error (after complaining) and try the next
|
||||
@@ -253,6 +259,7 @@ int nxffs_getc(FAR struct nxffs_volume_s *volume, uint16_t reserve)
|
||||
*/
|
||||
|
||||
fdbg("ERROR: Failed to read valid data into cache: %d\n", ret);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
while (ret != OK);
|
||||
|
||||
@@ -389,7 +389,6 @@ static inline void nxffs_analyze(FAR struct nxffs_blkinfo_s *blkinfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -462,6 +461,13 @@ int nxffs_dump(FAR struct mtd_dev_s *mtd, bool verbose)
|
||||
ret = MTD_BREAD(mtd, blkinfo.block, 1, blkinfo.buffer);
|
||||
if (ret < 0)
|
||||
{
|
||||
#ifndef CONFIG_NXFFS_NAND
|
||||
/* Read errors are fatal */
|
||||
|
||||
fdbg("ERROR: Failed to read block %d\n", blkinfo.block);
|
||||
kfree(blkinfo.buffer);
|
||||
return ret;
|
||||
#else
|
||||
/* A read error is probably fatal on all media but NAND.
|
||||
* On NAND, the read error probably just signifies a block
|
||||
* with an uncorrectable ECC failure. So, to handle NAND,
|
||||
@@ -470,6 +476,7 @@ int nxffs_dump(FAR struct mtd_dev_s *mtd, bool verbose)
|
||||
|
||||
fdbg(g_format, blkinfo.block, 0, "BLOCK", "RD FAIL",
|
||||
blkinfo.geo.blocksize);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -85,8 +85,6 @@
|
||||
* Zero on success. Otherwise, a negated errno value is returned
|
||||
* indicating the nature of the failure.
|
||||
*
|
||||
* On return, the
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int nxffs_rdentry(FAR struct nxffs_volume_s *volume, off_t offset,
|
||||
|
||||
+16
-1
@@ -1413,6 +1413,20 @@ start_pack:
|
||||
|
||||
pack.block0 = eblock * volume->blkper;
|
||||
|
||||
#ifndef CONFIG_NXFFS_NAND
|
||||
/* Read the erase block into the pack buffer. We need to do this even
|
||||
* if we are overwriting the entire block so that we skip over
|
||||
* previously marked bad blocks.
|
||||
*/
|
||||
|
||||
ret = MTD_BREAD(volume->mtd, pack.block0, volume->blkper, volume->pack);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("ERROR: Failed to read erase block %d: %d\n", eblock,-ret);
|
||||
goto errout_with_pack;
|
||||
}
|
||||
|
||||
#else
|
||||
/* Read the entire erase block into the pack buffer, one-block-at-a-
|
||||
* time. We need to do this even if we are overwriting the entire
|
||||
* block so that (1) we skip over previously marked bad blocks, and
|
||||
@@ -1440,6 +1454,7 @@ start_pack:
|
||||
nxffs_blkinit(volume, pack.iobuffer, BLOCK_STATE_BAD);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now pack each I/O block */
|
||||
|
||||
@@ -1579,7 +1594,7 @@ start_pack:
|
||||
ret = MTD_BWRITE(volume->mtd, pack.block0, volume->blkper, volume->pack);
|
||||
if (ret < 0)
|
||||
{
|
||||
fdbg("ERROR: Failed to write erase block %d [%]: %d\n",
|
||||
fdbg("ERROR: Failed to write erase block %d [%d]: %d\n",
|
||||
eblock, pack.block0, -ret);
|
||||
goto errout_with_pack;
|
||||
}
|
||||
|
||||
+36
-14
@@ -147,7 +147,9 @@ static int nxffs_badblocks(FAR struct nxffs_volume_s *volume)
|
||||
FAR uint8_t *blkptr; /* Pointer to next block data */
|
||||
off_t eblock; /* Erase block number */
|
||||
off_t lblock; /* Logical block number of the erase block */
|
||||
#ifdef CONFIG_NXFFS_NAND
|
||||
off_t block; /* Working block number */
|
||||
#endif
|
||||
ssize_t nxfrd; /* Number of blocks transferred */
|
||||
bool good; /* TRUE: block is good */
|
||||
bool modified; /* TRUE: The erase block has been modified */
|
||||
@@ -161,24 +163,43 @@ static int nxffs_badblocks(FAR struct nxffs_volume_s *volume)
|
||||
|
||||
lblock = eblock * volume->blkper;
|
||||
|
||||
/* Read the entire erase block into memory, processing each block one-
|
||||
* at-a-time. We could read the entire erase block at once. That
|
||||
* would be more efficient. However, for the case of NAND FLASH, each
|
||||
* individual block can fail independently due to uncorrectable bit
|
||||
* errors in that block.
|
||||
*/
|
||||
#ifndef CONFIG_NXFFS_NAND
|
||||
/* Read the entire erase block */
|
||||
|
||||
modified = false;
|
||||
nxfrd = MTD_BREAD(volume->mtd, lblock, volume->blkper, volume->pack);
|
||||
if (nxfrd != volume->blkper)
|
||||
{
|
||||
fdbg("ERROR: Read erase block %d failed: %d\n", lblock, nxfrd);
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Keep track if any part of the erase block gets modified */
|
||||
|
||||
modified = false;
|
||||
|
||||
/* Process each logical block */
|
||||
|
||||
#ifndef CONFIG_NXFFS_NAND
|
||||
for (blkptr = volume->pack, i = 0;
|
||||
i < volume->blkper;
|
||||
blkptr += volume->geo.blocksize, i++)
|
||||
#else
|
||||
for (i = 0, block = lblock, blkptr = volume->pack;
|
||||
i < volume->blkper;
|
||||
i++, block++, blkptr += volume->geo.blocksize)
|
||||
#endif
|
||||
{
|
||||
FAR struct nxffs_block_s *blkhdr = (FAR struct nxffs_block_s*)blkptr;
|
||||
|
||||
/* Assume that this is a good block until we learn otherwise */
|
||||
|
||||
good = true;
|
||||
|
||||
#ifdef CONFIG_NXFFS_NAND
|
||||
/* Read the next block in the erase block */
|
||||
|
||||
good = true;
|
||||
nxfrd = MTD_BREAD(volume->mtd, block, i, blkptr);
|
||||
nxfrd = MTD_BREAD(volume->mtd, block, 1, blkptr);
|
||||
if (nxfrd < 0)
|
||||
{
|
||||
/* Failed to read the block. This should never happen with
|
||||
@@ -191,11 +212,12 @@ static int nxffs_badblocks(FAR struct nxffs_volume_s *volume)
|
||||
|
||||
good = false;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* Check block header */
|
||||
|
||||
/* Check the block header */
|
||||
|
||||
else if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0 ||
|
||||
blkhdr->state != BLOCK_STATE_GOOD)
|
||||
if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0 ||
|
||||
blkhdr->state != BLOCK_STATE_GOOD)
|
||||
{
|
||||
/* The block is not formated with the NXFFS magic bytes or else
|
||||
* the block is specifically marked bad.
|
||||
@@ -313,4 +335,4 @@ void nxffs_blkinit(FAR struct nxffs_volume_s *volume, FAR uint8_t *blkptr,
|
||||
memset(blkptr, CONFIG_NXFFS_ERASEDSTATE, volume->geo.blocksize);
|
||||
memcpy(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE);
|
||||
blkhdr->state = state;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user