aboutsummaryrefslogtreecommitdiff
path: root/nand-utils
diff options
context:
space:
mode:
Diffstat (limited to 'nand-utils')
-rw-r--r--nand-utils/nanddump.c39
-rw-r--r--nand-utils/nandflipbits.c5
-rw-r--r--nand-utils/nandtest.c49
3 files changed, 70 insertions, 23 deletions
diff --git a/nand-utils/nanddump.c b/nand-utils/nanddump.c
index 47539f5..b4de05e 100644
--- a/nand-utils/nanddump.c
+++ b/nand-utils/nanddump.c
@@ -54,6 +54,7 @@ static void display_help(int status)
"-s addr --startaddress=addr Start address\n"
" --skip-bad-blocks-to-start\n"
" Skip bad blocks when seeking to the start address\n"
+"-C --continuous Continuous read up to a block of data at a time\n"
"\n"
"--bb=METHOD, where METHOD can be `padbad', `dumpbad', or `skipbad':\n"
" padbad: dump flash data, substituting 0xFF for any bad blocks\n"
@@ -89,6 +90,7 @@ static bool quiet = false; // suppress diagnostic output
static bool canonical = false; // print nice + ascii
static bool forcebinary = false; // force printing binary to tty
static bool skip_bad_blocks_to_start = false;
+static bool continuous = false; // leverage continuous reads
static enum {
padbad, // dump flash data, substituting 0xFF for any bad blocks
@@ -100,10 +102,11 @@ static void process_options(int argc, char * const argv[])
{
int error = 0;
bool oob_default = true;
+ char *dumpfile_tmp = NULL;
for (;;) {
int option_index = 0;
- static const char short_options[] = "hs:f:l:opqncaV";
+ static const char short_options[] = "hs:f:l:opqncaVC";
static const struct option long_options[] = {
{"version", no_argument, 0, 'V'},
{"bb", required_argument, 0, 0},
@@ -119,6 +122,7 @@ static void process_options(int argc, char * const argv[])
{"length", required_argument, 0, 'l'},
{"noecc", no_argument, 0, 'n'},
{"quiet", no_argument, 0, 'q'},
+ {"continuous", no_argument, 0, 'C'},
{0, 0, 0, 0},
};
@@ -162,8 +166,8 @@ static void process_options(int argc, char * const argv[])
start_addr = simple_strtoll(optarg, &error);
break;
case 'f':
- free(dumpfile);
- dumpfile = xstrdup(optarg);
+ free(dumpfile_tmp);
+ dumpfile = dumpfile_tmp = xstrdup(optarg);
break;
case 'l':
length = simple_strtoll(optarg, &error);
@@ -191,6 +195,9 @@ static void process_options(int argc, char * const argv[])
case 'n':
noecc = true;
break;
+ case 'C':
+ continuous = true;
+ break;
case 'h':
display_help(EXIT_SUCCESS);
break;
@@ -220,6 +227,13 @@ static void process_options(int argc, char * const argv[])
exit(EXIT_FAILURE);
}
+ if (continuous && !omitoob) {
+ fprintf(stderr, "Sequential/continuous reads (when available) will\n"
+ "always skip OOB data, so it is not possible to \n"
+ "request both at the same time.\n");
+ exit(EXIT_FAILURE);
+ }
+
if ((argc - optind) != 1 || error)
display_help(EXIT_FAILURE);
@@ -332,7 +346,7 @@ static int ofd_write(int ofd, const void *buf, size_t nbyte)
*/
int main(int argc, char * const argv[])
{
- long long ofs, end_addr = 0;
+ long long ofs, end_addr = 0, readbuf_sz;
long long blockstart = 1;
int i, fd, ofd = 0, bs, badblock = 0;
struct mtd_dev_info mtd;
@@ -362,8 +376,9 @@ int main(int argc, char * const argv[])
return errmsg("mtd_get_dev_info failed");
/* Allocate buffers */
+ readbuf_sz = mtd.eb_size;
oobbuf = xmalloc(mtd.oob_size);
- readbuf = xmalloc(mtd.min_io_size);
+ readbuf = xmalloc(readbuf_sz);
if (noecc) {
if (ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW) != 0) {
@@ -427,8 +442,6 @@ int main(int argc, char * const argv[])
if (!length || end_addr > mtd.size)
end_addr = mtd.size;
- bs = mtd.min_io_size;
-
/* Print informative message */
if (!quiet) {
fprintf(stderr, "Block size %d, page size %d, OOB size %d\n",
@@ -440,6 +453,8 @@ int main(int argc, char * const argv[])
/* Dump the flash contents */
for (ofs = start_addr; ofs < end_addr; ofs += bs) {
+ long long size_left = end_addr - ofs;
+
/* Check for bad block */
if (bb_method == dumpbad) {
badblock = 0;
@@ -453,16 +468,21 @@ int main(int argc, char * const argv[])
}
}
+ if (continuous)
+ bs = MIN(size_left, mtd.eb_size);
+ else
+ bs = mtd.min_io_size;
+
if (badblock) {
/* skip bad block, increase end_addr */
if (bb_method == skipbad) {
end_addr += mtd.eb_size;
- ofs += mtd.eb_size - bs;
+ ofs += mtd.eb_size - mtd.min_io_size;
if (end_addr > mtd.size)
end_addr = mtd.size;
continue;
}
- memset(readbuf, 0xff, bs);
+ memset(readbuf, 0xff, readbuf_sz);
} else {
/* Read page data and exit on failure */
if (mtd_read(&mtd, fd, ofs / mtd.eb_size, ofs % mtd.eb_size, readbuf, bs)) {
@@ -499,7 +519,6 @@ int main(int argc, char * const argv[])
}
} else {
/* Write requested length if oob is omitted */
- long long size_left = end_addr - ofs;
if (omitoob && (size_left < bs))
err = ofd_write(ofd, readbuf, size_left);
else
diff --git a/nand-utils/nandflipbits.c b/nand-utils/nandflipbits.c
index cd66d0b..a417189 100644
--- a/nand-utils/nandflipbits.c
+++ b/nand-utils/nandflipbits.c
@@ -203,7 +203,8 @@ int main(int argc, char **argv)
int page;
if (bits_to_flip[i].offset >= mtdlen) {
- fprintf(stderr, "Invalid byte offset %lld (max %lld)\n",
+ fprintf(stderr, "Invalid byte offset %" PRId64
+ " (max %" PRId64 ")\n",
bits_to_flip[i].offset, mtdlen);
ret = EXIT_FAILURE;
goto free_buf;
@@ -250,7 +251,7 @@ int main(int argc, char **argv)
bufoffs += mtd.min_io_size;
ret = mtd_read_oob(mtd_desc, &mtd, fd,
- bit_to_flip->block * mtd.eb_size +
+ (unsigned long long)bit_to_flip->block * mtd.eb_size +
blkoffs,
mtd.oob_size, buffer + bufoffs);
if (ret) {
diff --git a/nand-utils/nandtest.c b/nand-utils/nandtest.c
index 06dec25..cac0dde 100644
--- a/nand-utils/nandtest.c
+++ b/nand-utils/nandtest.c
@@ -8,6 +8,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <limits.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
@@ -144,6 +145,26 @@ static int erase_and_write(loff_t ofs, unsigned char *data, unsigned char *rbuf,
return 0;
}
+static uint64_t get_mem_size(const char* device)
+{
+ const char* p = strrchr(device, '/');
+ char path[PATH_MAX];
+ int fd;
+
+ snprintf(path, sizeof(path), "/sys/class/mtd/%s/size", p);
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ char buffer[32];
+ ssize_t n = read(fd, buffer, sizeof(buffer));
+ close(fd);
+ if (n > 0) {
+ return strtoull(buffer, NULL, 0);
+ }
+ }
+
+ fprintf(stderr, "Can't read size from %s\n", path);
+ exit(1);
+}
/*
* Main program
@@ -156,8 +177,9 @@ int main(int argc, char **argv)
int nr_passes = 1;
int nr_reads = 4;
int keep_contents = 0;
- uint32_t offset = 0;
- uint32_t length = -1;
+ uint64_t offset = 0;
+ uint64_t length = -1;
+ uint64_t mem_size = 0;
int error = 0;
seed = time(NULL);
@@ -212,11 +234,11 @@ int main(int argc, char **argv)
break;
case 'o':
- offset = simple_strtoul(optarg, &error);
+ offset = simple_strtoull(optarg, &error);
break;
case 'l':
- length = simple_strtoul(optarg, &error);
+ length = simple_strtoull(optarg, &error);
break;
}
@@ -238,29 +260,34 @@ int main(int argc, char **argv)
exit(1);
}
+ mem_size = get_mem_size(argv[optind]);
+
if (length == -1)
- length = meminfo.size;
+ length = mem_size;
if (offset % meminfo.erasesize) {
- fprintf(stderr, "Offset %x not multiple of erase size %x\n",
+ fprintf(stderr, "Offset %" PRIx64
+ " not multiple of erase size %x\n",
offset, meminfo.erasesize);
exit(1);
}
if (length % meminfo.erasesize) {
- fprintf(stderr, "Length %x not multiple of erase size %x\n",
+ fprintf(stderr, "Length %" PRIx64
+ " not multiple of erase size %x\n",
length, meminfo.erasesize);
exit(1);
}
- if (length + offset > meminfo.size) {
- fprintf(stderr, "Length %x + offset %x exceeds device size %x\n",
- length, offset, meminfo.size);
+ if (length + offset > mem_size) {
+ fprintf(stderr, "Length %" PRIx64 " + offset %" PRIx64
+ " exceeds device size %" PRIx64 "\n",
+ length, offset, mem_size);
exit(1);
}
wbuf = malloc(meminfo.erasesize * 3);
if (!wbuf) {
fprintf(stderr, "Could not allocate %d bytes for buffer\n",
- meminfo.erasesize * 2);
+ meminfo.erasesize * 3);
exit(1);
}
rbuf = wbuf + meminfo.erasesize;