[U-Boot] [PATCH] [nand] Implement nand_extent_skip_bad

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);

On 12/10/2012 09:24:24 AM, Pantelis Antoniou wrote:
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.
s/extend/extent/
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
- */
Would it be better to return this information from existing read/write functions -- either instead of or in addition to exporting this functionality?
+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;
+}
This seems duplicative of check_skip_len().
-Scott

Hi Scott,
On Dec 11, 2012, at 12:53 AM, Scott Wood wrote:
On 12/10/2012 09:24:24 AM, Pantelis Antoniou wrote:
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.
s/extend/extent/
Yeah.
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
- */
Would it be better to return this information from existing read/write functions -- either instead of or in addition to exporting this functionality?
Yes it would. However that would require modifying all callers, which would be a hard sell when there's only one user of it.
+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;
+}
This seems duplicative of check_skip_len().
It is. check_skip_len doesn't return the information I need. I could modify check_skip_len with an extra parameter if that's going to be OK with you.
-Scott
Regards
-- Pantelis

On 12/11/2012 03:40:53 AM, Pantelis Antoniou wrote:
Hi Scott,
On Dec 11, 2012, at 12:53 AM, Scott Wood wrote:
+/**
- 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
- */
Would it be better to return this information from existing
read/write functions -- either instead of or in addition to exporting this functionality?
Yes it would. However that would require modifying all callers, which would be a hard sell when there's only one user of it.
There aren't that many callers, and it's all common code (so no issue with testing on obscure hardware).
This seems duplicative of check_skip_len().
It is. check_skip_len doesn't return the information I need. I could modify check_skip_len with an extra parameter if that's going to be OK with you.
Yes, please modify check_skip_len() instead.
-Scott

Hi Scott,
On Dec 11, 2012, at 7:13 PM, Scott Wood wrote:
On 12/11/2012 03:40:53 AM, Pantelis Antoniou wrote:
Hi Scott, On Dec 11, 2012, at 12:53 AM, Scott Wood wrote:
+/**
- 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
- */
Would it be better to return this information from existing read/write functions -- either instead of or in addition to exporting this functionality?
Yes it would. However that would require modifying all callers, which would be a hard sell when there's only one user of it.
There aren't that many callers, and it's all common code (so no issue with testing on obscure hardware).
This seems duplicative of check_skip_len().
It is. check_skip_len doesn't return the information I need. I could modify check_skip_len with an extra parameter if that's going to be OK with you.
Yes, please modify check_skip_len() instead.
-Scott
Nice, hope I'll get around doing it today or tomorrow.
Regards
-- Pantelis
participants (2)
-
Pantelis Antoniou
-
Scott Wood