
When accessing nand any bad blocks encountered are skipped, with no indication about the amount of bad blocks encountered. While this is normally fine, when you have to write a large amount of data in chunks, you need to account for the skipped amount due to the presence of the bad blocks.
nand_extend_skip_bad() returns the offset where the next access should occur.
Signed-off-by: Pantelis Antoniou panto@antoniou-consulting.com --- drivers/mtd/nand/nand_util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ include/nand.h | 2 ++ 2 files changed, 52 insertions(+)
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 2ba0c5e..a25a4cb 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -684,6 +684,56 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, return 0; }
+/** + * nand_extent_skip_bad: + * + * Find the extent of a chunk, return the offset where it ends + * Blocks that are marked bad are skipped and the next block is examined + * instead as long as the extend is short enough to fit even after skipping the + * bad blocks. + * + * @param nand NAND device + * @param offset offset in flash + * @param length extend length + * @return next offset in case of success (loff_t)-1 on error + */ +loff_t nand_extent_skip_bad(nand_info_t *nand, loff_t offset, size_t length) +{ + size_t block_len, block_off; + loff_t block_start; + + if ((offset & (nand->writesize - 1)) != 0) { + printf ("%s: Attempt to check extend non page aligned data\n", + __func__); + return (loff_t)-1; + } + + while (length > 0) { + + if (offset >= nand->size) { + printf("%s: offset >= nand->size (%llx >= %llx)\n", + __func__, offset, nand->size); + return (loff_t)-1; + } + + block_start = offset & ~(loff_t)(nand->erasesize - 1); + block_off = offset & (nand->erasesize - 1); + block_len = nand->erasesize - block_off; + if (block_len > length) /* left over */ + block_len = length; + + if (!nand_block_isbad(nand, block_start)) + length -= block_len; + else + debug("%s: bad block at %llx (left %x)\n", + __func__, block_start, length); + + offset += block_len; + } + + return offset; +} + #ifdef CONFIG_CMD_NAND_TORTURE
/** diff --git a/include/nand.h b/include/nand.h index dded4e2..710c11a 100644 --- a/include/nand.h +++ b/include/nand.h @@ -168,3 +168,5 @@ __attribute__((noreturn)) void nand_boot(void); #define ENV_OFFSET_SIZE 8 int get_nand_env_oob(nand_info_t *nand, unsigned long *result); #endif + +loff_t nand_extent_skip_bad(nand_info_t *nand, loff_t offset, size_t length);