This is an automated email from Gerrit.

Ivo Manca ([email protected]) just uploaded a new patch set to Gerrit, which you 
can find at http://openocd.zylin.com/3506

-- gerrit

commit 82f413241fb33c6349ba8a24c7beeb4672bf323f
Author: Ivo Manca <[email protected]>
Date:   Fri May 20 08:37:02 2016 +0200

    nand: Add basic support for skipping bad blocks
    
    When programming data to NAND flash OpenOCD currently writes and
    erases to blocks which contain a (factory default) bad block marker.
    Not only can this result in loss bad block markers, but it can also
    lead to non-function programs or data loss.
    
    This can be inconvenient in various cases, but in this example the
    NAND chip contains bad blocks in the section where the bootloader
    should be placed. Currently this requires manual programming/ erasing
    or scripts to mitigate the problem.
    
    Various microprocessors and programs have support for reading the bad
    block markers and skipping these blocks while reading data.
    
    The following patchset adds support for skipping bad blocks while
    reading/writing/erasing or verifying data. Per default this behavior
    is off, since it can also introduce possible unwanted side effects.
    
    Change-Id: Ib2e4acf87c9ddc9a042adb70da13a2565b8fcd38
    Signed-off-by: Ivo Manca <[email protected]>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index ae92697..78a8b1e 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -6190,6 +6190,9 @@ The @var{offset} and @var{length} must be exact multiples 
of the
 device's page size. They describe a data region; the OOB data
 associated with each such page may also be accessed.
 
+When @command{nand skip_bad_blocks} is enabled, all bad blocks will
+be skipped to be fully compatible with @command{nand write}.
+
 @b{NOTE:} At the time this text was written, no error correction
 was done on the data that's read, unless raw access was disabled
 and the underlying NAND controller driver had a @code{read_page}
@@ -6225,9 +6228,9 @@ If those parameters are not specified,
 the whole NAND chip will be erased.
 The @var{num} parameter is the value shown by @command{nand list}.
 
-@b{NOTE:} This command will try to erase bad blocks, when told
+@b{NOTE:} Per default this command will try to erase bad blocks, when told
 to do so, which will probably invalidate the manufacturer's bad
-block marker.
+block marker. To modify this behavior, use @command{nand skip_bad_blocks}.
 For the remainder of the current server session, @command{nand info}
 will still report that the block ``is'' bad.
 @end deffn
@@ -6250,9 +6253,11 @@ Only full pages are written, and any extra space in the 
last
 page will be filled with 0xff bytes. (That includes OOB data,
 if that's being written.)
 
-@b{NOTE:} At the time this text was written, bad blocks are
-ignored. That is, this routine will not skip bad blocks,
-but will instead try to write them. This can cause problems.
+@b{NOTE:} Per default, bad blocks are ignored. That is, this routine
+will not skip bad blocks, but will instead try to write them. This
+can cause problems. This behavior can be modified with
+@command{skip_bad_blocks}. When bad block skipping is enabled, the
+data may be written beyond @var{offset} + file size.
 
 Provide at most one @var{option} parameter. With some
 NAND drivers, the meanings of these parameters may change
@@ -6311,6 +6316,9 @@ The same @var{options} accepted by @command{nand write},
 and the file will be processed similarly to produce the buffers that
 can be compared against the contents produced from @command{nand dump}.
 
+When @command{nand skip_bad_blocks} is enabled, all bad blocks will
+be skipped to be fully compatible with @command{nand write}.
+
 @b{NOTE:} This will not work when the underlying NAND controller
 driver's @code{write_page} routine must update the OOB with a
 hardward-computed ECC before the data is written. This limitation may
@@ -6360,6 +6368,25 @@ bypassing hardware ECC logic.
 with the wrong ECC data can cause them to be marked as bad.
 @end deffn
 
+@deffn Command {nand skip_bad_blocks} num (@option{enable}|@option{disable})
+Sets or clears an flag affecting how page I/O is done.
+The @var{num} parameter is the value shown by @command{nand list}.
+
+This flag is cleared (disabled) by default, resulting in the commands
+@command{nand write} and @command{nand erase} to ignore bad block markers.
+
+When the flag is enabled, bad blocks are skipped completely. See also
+@command{nand write}, @command{nand erase}, @command{nand dump} and
+@command{nand verify} for more information.
+
+@i{This can be a dangerous option}, since writing and erasing bad blocks
+can cause corruption of data and invalidating the manufacturer's bad block
+markers. Skipping bad blocks can cause data to be written outside of the
+expected data range and may or may not work as intended, depending on the
+used processor, bootloader and operating system.
+
+@end deffn
+
 @anchor{nanddriverlist}
 @subsection NAND Driver List
 As noted above, the @command{nand device} command allows
diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c
index 815c766..ee85fc0 100644
--- a/src/flash/nand/core.c
+++ b/src/flash/nand/core.c
@@ -259,6 +259,15 @@ int nand_build_bbt(struct nand_device *nand, int first, 
int last)
        return ERROR_OK;
 }
 
+bool nand_check_block_is_bad(struct nand_device *nand, int block)
+{
+       // Retrieve data from flash only once
+       if (nand->blocks[block].is_bad == -1)
+               nand_build_bbt(nand, block, block);
+
+       return (nand->blocks[block].is_bad == 1);
+}
+
 int nand_read_status(struct nand_device *nand, uint8_t *status)
 {
        if (!nand->device)
@@ -508,15 +517,17 @@ int nand_erase(struct nand_device *nand, int first_block, 
int last_block)
        if ((first_block < 0) || (last_block >= nand->num_blocks))
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       /* make sure we know if a block is bad before erasing it */
        for (i = first_block; i <= last_block; i++) {
-               if (nand->blocks[i].is_bad == -1) {
-                       nand_build_bbt(nand, i, last_block);
-                       break;
+               /* make sure we know if a block is bad before erasing it */
+               const bool bad_block = nand_check_block_is_bad(nand, i);
+               if (bad_block) {
+                       if (nand->skip_bad_blocks == 1) {
+                               LOG_INFO("Skipped erasing bad block %d", i);
+                               continue;
+                       } else {
+                               LOG_WARNING("Erasing bad block %d (will also 
erase bad block marker)", i);
+                       }
                }
-       }
-
-       for (i = first_block; i <= last_block; i++) {
                /* Send erase setup command */
                nand->controller->command(nand, NAND_CMD_ERASE1);
 
@@ -564,7 +575,7 @@ int nand_erase(struct nand_device *nand, int first_block, 
int last_block)
 
                if (status & 0x1) {
                        LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
-                               (nand->blocks[i].is_bad == 1)
+                               bad_block
                                ? "bad " : "",
                                i, status);
                        /* continue; other blocks might still be erasable */
diff --git a/src/flash/nand/core.h b/src/flash/nand/core.h
index f0e72f2..3605e76 100644
--- a/src/flash/nand/core.h
+++ b/src/flash/nand/core.h
@@ -69,6 +69,7 @@ struct nand_device {
        int page_size;
        int erase_size;
        bool use_raw;
+       bool skip_bad_blocks;
        int num_blocks;
        struct nand_block *blocks;
        struct nand_device *next;
diff --git a/src/flash/nand/imp.h b/src/flash/nand/imp.h
index dde17cb..003c469 100644
--- a/src/flash/nand/imp.h
+++ b/src/flash/nand/imp.h
@@ -36,5 +36,6 @@ int nand_read_page(struct nand_device *nand, uint32_t page,
 int nand_probe(struct nand_device *nand);
 int nand_erase(struct nand_device *nand, int first_block, int last_block);
 int nand_build_bbt(struct nand_device *nand, int first, int last);
+bool nand_check_block_is_bad(struct nand_device *nand, int block);
 
 #endif /* FLASH_NAND_IMP_H */
diff --git a/src/flash/nand/tcl.c b/src/flash/nand/tcl.c
index 5db29ab..c2628ca 100644
--- a/src/flash/nand/tcl.c
+++ b/src/flash/nand/tcl.c
@@ -252,14 +252,26 @@ COMMAND_HANDLER(handle_nand_write_command)
                return retval;
 
        uint32_t total_bytes = s.size;
+
        while (s.size > 0) {
+               const uint32_t block = (s.address / nand->erase_size);
+
+               if (nand_check_block_is_bad(nand, block)) {
+                       if (nand->skip_bad_blocks) {
+                               LOG_WARNING("Skipping bad block %u", block);
+                               s.address += nand->blocks->size;
+                               continue;
+                       } else {
+                               LOG_WARNING("Writing to bad block %u", block);
+                       }
+               }
+
                int bytes_read = nand_fileio_read(nand, &s);
                if (bytes_read <= 0) {
                        command_print(CMD_CTX, "error while reading file");
                        return nand_fileio_cleanup(&s);
                }
                s.size -= bytes_read;
-
                retval = nand_write_page(nand, s.address / nand->page_size,
                                s.page, s.page_size, s.oob, s.oob_size);
                if (ERROR_OK != retval) {
@@ -299,6 +311,17 @@ COMMAND_HANDLER(handle_nand_verify_command)
                return retval;
 
        while (file.size > 0) {
+               if (nand->skip_bad_blocks) {
+                       const uint32_t block = (dev.address  / 
nand->erase_size);
+
+                       // make sure we know if a block is bad before reading 
from it
+                       if (nand_check_block_is_bad(nand, block)) {
+                               LOG_WARNING("Skipping bad block %u", block);
+                               dev.address += nand->blocks->size;
+                               continue;
+                       }
+               }
+
                retval = nand_read_page(nand, dev.address / dev.page_size,
                                dev.page, dev.page_size, dev.oob, dev.oob_size);
                if (ERROR_OK != retval) {
@@ -350,6 +373,15 @@ COMMAND_HANDLER(handle_nand_dump_command)
                return retval;
 
        while (s.size > 0) {
+               if (nand->skip_bad_blocks) {
+                       const uint32_t block = (s.address  / nand->erase_size);
+                       if (nand_check_block_is_bad(nand, block)) {
+                               LOG_WARNING("Skipping bad block %u", block);
+                               s.address += nand->blocks->size;
+                               continue;
+                       }
+               }
+
                size_t size_written;
                retval = nand_read_page(nand, s.address / nand->page_size,
                                s.page, s.page_size, s.oob, s.oob_size);
@@ -405,6 +437,30 @@ COMMAND_HANDLER(handle_nand_raw_access_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_nand_skip_bad_blocks_command)
+{
+       if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct nand_device *p;
+       int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (NULL == p->device) {
+               command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
+               return ERROR_OK;
+       }
+
+       if (CMD_ARGC == 2)
+               COMMAND_PARSE_ENABLE(CMD_ARGV[1], p->skip_bad_blocks);
+
+       const char *msg = p->skip_bad_blocks ? "enabled" : "disabled";
+       command_print(CMD_CTX, "skipping bad blocks is %s", msg);
+
+       return ERROR_OK;
+}
+
 static const struct command_registration nand_exec_command_handlers[] = {
        {
                .name = "list",
@@ -471,6 +527,13 @@ static const struct command_registration 
nand_exec_command_handlers[] = {
                .usage = "bank_id ['enable'|'disable']",
                .help = "raw access to NAND flash device",
        },
+       {
+               .name = "skip_bad_blocks",
+               .handler = handle_nand_skip_bad_blocks_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id ['enable'|'disable']",
+               .help = "skip bad blocks when writing/erasing",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -548,6 +611,7 @@ static COMMAND_HELPER(create_nand_device, const char 
*bank_name,
        c->address_cycles = 0;
        c->page_size = 0;
        c->use_raw = false;
+       c->skip_bad_blocks = false;
        c->next = NULL;
 
        retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);

-- 

------------------------------------------------------------------------------
Mobile security can be enabling, not merely restricting. Employees who
bring their own devices (BYOD) to work are irked by the imposition of MDM
restrictions. Mobile Device Manager Plus allows you to control only the
apps on BYO-devices by containerizing them, leaving personal data untouched!
https://ad.doubleclick.net/ddm/clk/304595813;131938128;j
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to