Condition out most of the recent NXFFS changes for NAND. NXFFS will never be able to support NAND

This commit is contained in:
Gregory Nutt
2013-12-03 13:11:11 -06:00
parent 59c4739312
commit 2318531d93
10 changed files with 324 additions and 73 deletions
+27
View File
@@ -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
+78 -5
View File
@@ -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;
}
+7
View File
@@ -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);
+8 -1
View File
@@ -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
{
-2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}