aboutsummaryrefslogtreecommitdiff
path: root/ubi-utils
diff options
context:
space:
mode:
authorFrank Haverkamp <haver@vnet.ibm.com>2008-01-07 14:05:00 +0100
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-01-15 12:47:00 +0200
commit4bf037f3a2aea4328e10422379f751370d288d46 (patch)
tree68a24f007e8b89609d14d44165a8bcd669629e7a /ubi-utils
parent07e6203fd3078d6855e7d33597bdbbae10e555fd (diff)
ubi-utils: bin2nand, nand2bin add support of different ecc layouts
Both tools were lacking support of alternate ECC layouts. Only our intitial format was supported. With this change, it should be very easy to add more layouts in addtion to the already supported ones, which are: IBM (our format), and the MTD default layout. NAND OOB sizes of 512 and 2048 are currently supported. In contrast to the old version of bin2nand, the holes inbetween the ECC data is now not filled with 0x00 anymore but instead 0xff (like deleted flash) is used. This should not cause any difference. The testcase reflects the different layouts too. Signed-off-by: Frank Haverkamp <haver@vnet.ibm.com>
Diffstat (limited to 'ubi-utils')
-rw-r--r--ubi-utils/TODO7
-rw-r--r--ubi-utils/scripts/bin2nand2bin_test.sh43
-rw-r--r--ubi-utils/src/bin2nand.c156
-rw-r--r--ubi-utils/src/ecclayouts.h66
-rw-r--r--ubi-utils/src/nand2bin.c212
5 files changed, 304 insertions, 180 deletions
diff --git a/ubi-utils/TODO b/ubi-utils/TODO
index a604170..4683bd7 100644
--- a/ubi-utils/TODO
+++ b/ubi-utils/TODO
@@ -3,12 +3,15 @@ TODO
* Range checking is broken, reserving 2M and offering 3M binary data
... works!? No!
- * Remove the above misterious statement or make it understandable
+ * Remove the above mysterious statement or make it understandable
* doc/ directory contains a file which refers images from /home/frank/
- please fix this or remove the whole doc/ altogether.
* the tests from the scripts/ directory should live in
- mit-utils/tests/ubi-tests/ and it would be nice to have a short
+ mtd-utils/tests/ubi-tests/ and it would be nice to have a short
description of the tests
* the stuff from the perl/ directory should go to the scripts/
* May we pleas split UBI-related stuff and pure NAND-related stuff and
not to keep this all in one.
+
+ * nand2bin and bin2nand need more flexibility to influence the ECC
+ data placement.
diff --git a/ubi-utils/scripts/bin2nand2bin_test.sh b/ubi-utils/scripts/bin2nand2bin_test.sh
index a17c91b..2192f02 100644
--- a/ubi-utils/scripts/bin2nand2bin_test.sh
+++ b/ubi-utils/scripts/bin2nand2bin_test.sh
@@ -1,5 +1,8 @@
#!/bin/sh
#
+# Version: 1.1
+# Author: Frank Haverkamp <haver@vnet.ibm.com>
+#
# Testcase for nand2bin and bin2nand. Generate testdata and inject
# biterrors. Convert data back and compare with original data.
#
@@ -8,14 +11,44 @@
#
inject_biterror=./scripts/inject_biterror.pl
-
pagesize=2048
oobsize=64
# Create test data
dd if=/dev/urandom of=testblock.bin bs=131072 count=1
-echo "Test conversion without bitflips ..."
+for layout in IBM MTD ; do
+ echo "*** Simple test with $layout layout ..."
+
+ echo -n "Convert bin to mif ... "
+ bin2nand -l$layout --pagesize=${pagesize} -o testblock.mif testblock.bin
+ if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+
+ echo -n "Convert mif to bin ... "
+ nand2bin -l$layout --pagesize=${pagesize} -o testblock.img testblock.mif
+ if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+
+ echo -n "Comparing data ... "
+ diff testblock.bin testblock.img
+ if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+done
+
+echo "*** Test conversion without bitflips ..."
echo -n "Convert bin to mif ... "
bin2nand --pagesize=${pagesize} -o testblock.mif testblock.bin
@@ -44,7 +77,7 @@ else
echo "ok"
fi
-echo "Test conversion with uncorrectable ECC erors ..."
+echo "*** Test conversion with uncorrectable ECC erors ..."
echo -n "Inject biterror at offset $ioffs ... "
${inject_biterror} --offset=0 --bitmask=0x81 \
--input=testblock.mif \
@@ -76,7 +109,7 @@ else
exit 1
fi
-echo "Test bitflips in data ... "
+echo "*** Test bitflips in data ... "
for offs in `seq 0 255` ; do
cp testblock.mif testblock_bitflip.mif
@@ -142,7 +175,7 @@ for offs in `seq 0 255` ; do
fi
done
-echo "Test bitflips in OOB data ... "
+echo "*** Test bitflips in OOB data ... "
for offs in `seq 0 $oobsize` ; do
let ioffs=$pagesize+$offs
diff --git a/ubi-utils/src/bin2nand.c b/ubi-utils/src/bin2nand.c
index c7c7ccc..83f50cc 100644
--- a/ubi-utils/src/bin2nand.c
+++ b/ubi-utils/src/bin2nand.c
@@ -28,7 +28,8 @@
* 1.3 Padds data/oob to a given size. (oloh)
* 1.4 Removed argp because we want to use uClibc.
* 1.5 Minor cleanup
- * 1.6 written variable not initialized (-j did not work) (haver)
+ * 1.6 Written variable not initialized (-j did not work) (haver)
+ * 1.7 Made NAND ECC layout configurable (haver)
*/
#include <unistd.h>
@@ -46,8 +47,11 @@
#include "error.h"
#include "config.h"
#include "nandecc.h"
+#include "ecclayouts.h"
-#define PROGRAM_VERSION "1.6"
+#define PROGRAM_VERSION "1.7"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define CHECK_ENDP(option, endp) do { \
if (*endp) { \
@@ -74,8 +78,9 @@ static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
static const char *optionsstr =
" -c, --copyright Print copyright informatoin.\n"
" -j, --padding=<num> Padding in Byte/Mi/ki. Default = no padding\n"
+" -l, --ecc-placement=<MTD,IBM> OOB placement scheme (default is IBM).\n"
" -p, --pagesize=<num> Pagesize in Byte/Mi/ki. Default = 2048\n"
-" -o, --output=<fname> Output filename. Interleaved Data/OOB if\n"
+" -o, --output=<fname> Output filename. Interleaved Data/OOB if\n"
" output-oob not specified.\n"
" -q, --output-oob=<fname> Write OOB data in separate file.\n"
" -?, --help Give this help list\n"
@@ -94,30 +99,33 @@ struct option long_options[] = {
{ .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' },
{ .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
{ .name = "output-oob", .has_arg = 1, .flag = NULL, .val = 'q' },
+ { .name = "ecc-layout", .has_arg = 1, .flag = NULL, .val = 'l' },
{ .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
{ .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
{ .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
{ NULL, 0, NULL, 0}
};
-static const char copyright [] __attribute__((unused)) =
- "Copyright IBM Corp. 2006";
+#define __unused __attribute__((unused))
+static const char copyright [] __unused = "Copyright IBM Corp. 2007";
-typedef struct myargs {
+struct args {
action_t action;
size_t pagesize;
+ size_t oobsize;
size_t padding;
FILE* fp_in;
- char *file_out_data; /* Either: Data and OOB interleaved
- or plain data */
- char *file_out_oob; /* OOB Data only. */
+ const char *file_out_data; /* Either: Data and OOB interleaved
+ or plain data */
+ const char *file_out_oob; /* OOB Data only. */
+ struct nand_ecclayout *nand_oob;
/* special stuff needed to get additional arguments */
char *arg1;
char **options; /* [STRING...] */
-} myargs;
+};
static int ustrtoull(const char *cp, char **endp, unsigned int base)
@@ -140,49 +148,53 @@ static int ustrtoull(const char *cp, char **endp, unsigned int base)
}
static int
-parse_opt(int argc, char **argv, myargs *args)
+parse_opt(int argc, char **argv, struct args *args)
{
+ const char *ecc_layout = NULL;
+ unsigned int i, oob_idx = 0;
char* endp;
while (1) {
int key;
- key = getopt_long(argc, argv, "cj:p:o:q:?V", long_options, NULL);
+ key = getopt_long(argc, argv, "cj:l:p:o:q:?V", long_options, NULL);
if (key == -1)
break;
switch (key) {
- case 'p': /* pagesize */
- args->pagesize = (size_t)
- ustrtoull(optarg, &endp, 0);
- CHECK_ENDP("p", endp);
- break;
- case 'j': /* padding */
- args->padding = (size_t)
- ustrtoull(optarg, &endp, 0);
- CHECK_ENDP("j", endp);
- break;
- case 'o': /* output */
- args->file_out_data = optarg;
- break;
- case 'q': /* output oob */
- args->file_out_oob = optarg;
- break;
- case '?': /* help */
- printf("%s", doc);
- printf("%s", optionsstr);
- exit(0);
- break;
- case 'V':
- printf("%s\n", PROGRAM_VERSION);
- exit(0);
- break;
- case 'c':
- printf("%s\n", copyright);
- exit(0);
- default:
- printf("%s", usage);
- exit(-1);
+ case 'p': /* pagesize */
+ args->pagesize = (size_t)
+ ustrtoull(optarg, &endp, 0);
+ CHECK_ENDP("p", endp);
+ break;
+ case 'j': /* padding */
+ args->padding = (size_t)
+ ustrtoull(optarg, &endp, 0);
+ CHECK_ENDP("j", endp);
+ break;
+ case 'o': /* output */
+ args->file_out_data = optarg;
+ break;
+ case 'q': /* output oob */
+ args->file_out_oob = optarg;
+ break;
+ case 'l': /* --ecc-layout=<...> */
+ ecc_layout = optarg;
+ break;
+ case '?': /* help */
+ printf("%s%s", doc, optionsstr);
+ exit(0);
+ break;
+ case 'V':
+ printf("%s\n", PROGRAM_VERSION);
+ exit(0);
+ break;
+ case 'c':
+ printf("%s\n", copyright);
+ exit(0);
+ default:
+ printf("%s", usage);
+ exit(-1);
}
}
@@ -194,46 +206,55 @@ parse_opt(int argc, char **argv, myargs *args)
}
}
+ switch (args->pagesize) {
+ case 512: args->oobsize = 16; oob_idx = 0; break;
+ case 2048: args->oobsize = 64; oob_idx = 1; break;
+ default:
+ err_msg("Unsupported page size: %d\n", args->pagesize);
+ return -EINVAL;
+ }
+
+ /* Figure out correct oob layout if it differs from default */
+ if (ecc_layout) {
+ for (i = 0; i < ARRAY_SIZE(oob_placement); i++)
+ if (strcmp(ecc_layout, oob_placement[i].name) == 0)
+ args->nand_oob =
+ oob_placement[i].nand_oob[oob_idx];
+ }
return 0;
}
static int
-process_page(uint8_t* buf, size_t pagesize,
- FILE *fp_data, FILE* fp_oob, size_t* written)
+process_page(struct args *args, uint8_t *buf, FILE *fp_data, FILE *fp_oob,
+ size_t *written)
{
- int eccpoi, oobsize;
+ int eccpoi;
size_t i;
uint8_t oobbuf[64];
+ uint8_t ecc_code[3] = { 0, }; /* temp */
+ /* Calculate ECC for each subpage of 256 bytes */
memset(oobbuf, 0xff, sizeof(oobbuf));
-
- switch(pagesize) {
- case 2048: oobsize = 64; eccpoi = 64 / 2; break;
- case 512: oobsize = 16; eccpoi = 16 / 2; break;
- default:
- err_msg("Unsupported page size: %d\n", pagesize);
- return -EINVAL;
- }
-
- for (i = 0; i < pagesize; i += 256, eccpoi += 3) {
- oobbuf[eccpoi++] = 0x0;
- /* Calculate ECC */
- nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]);
+ for (eccpoi = 0, i = 0; i < args->pagesize; i += 256, eccpoi += 3) {
+ int j;
+ nand_calculate_ecc(&buf[i], ecc_code);
+ for (j = 0; j < 3; j++)
+ oobbuf[args->nand_oob->eccpos[eccpoi + j]] = ecc_code[j];
}
/* write data */
- *written += fwrite(buf, 1, pagesize, fp_data);
+ *written += fwrite(buf, 1, args->pagesize, fp_data);
/* either separate oob or interleave with data */
if (fp_oob) {
- i = fwrite(oobbuf, 1, oobsize, fp_oob);
+ i = fwrite(oobbuf, 1, args->oobsize, fp_oob);
if (ferror(fp_oob)) {
err_msg("IO error\n");
return -EIO;
}
}
else {
- i = fwrite(oobbuf, 1, oobsize, fp_data);
+ i = fwrite(oobbuf, 1, args->oobsize, fp_data);
if (ferror(fp_data)) {
err_msg("IO error\n");
return -EIO;
@@ -248,13 +269,14 @@ int main (int argc, char** argv)
int rc = -1;
int res = 0;
size_t written = 0, read;
- myargs args = {
+ struct args args = {
.action = ACT_NORMAL,
.pagesize = PAGESIZE,
.padding = PADDING,
.fp_in = NULL,
.file_out_data = NULL,
.file_out_oob = NULL,
+ .nand_oob = &ibm_nand_oob_64,
};
FILE* fp_out_data = stdout;
@@ -306,16 +328,16 @@ int main (int argc, char** argv)
goto err;
}
- res = process_page(buf, args.pagesize, fp_out_data,
- fp_out_oob, &written);
+ res = process_page(&args, buf, fp_out_data, fp_out_oob,
+ &written);
if (res != 0)
goto err;
}
while (written < args.padding) {
memset(buf, 0xff, args.pagesize);
- res = process_page(buf, args.pagesize, fp_out_data,
- fp_out_oob, &written);
+ res = process_page(&args, buf, fp_out_data, fp_out_oob,
+ &written);
if (res != 0)
goto err;
}
diff --git a/ubi-utils/src/ecclayouts.h b/ubi-utils/src/ecclayouts.h
new file mode 100644
index 0000000..a1c7823
--- /dev/null
+++ b/ubi-utils/src/ecclayouts.h
@@ -0,0 +1,66 @@
+#ifndef __ECCLAYOUTS_H__
+#define __ECCLAYOUTS_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <mtd/mtd-abi.h>
+
+/* Define default oob placement schemes for large and small page devices */
+static struct nand_ecclayout mtd_nand_oob_16 = {
+ .eccbytes = 6,
+ .eccpos = { 0, 1, 2, 3, 6, 7 },
+ .oobfree = {{ .offset = 8, .length = 8 }}
+};
+
+static struct nand_ecclayout mtd_nand_oob_64 = {
+ .eccbytes = 24,
+ .eccpos = { 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63 },
+ .oobfree = {{ .offset = 2, .length = 38 }}
+};
+
+/* Define IBM oob placement schemes */
+static struct nand_ecclayout ibm_nand_oob_16 = {
+ .eccbytes = 6,
+ .eccpos = { 9, 10, 11, 13, 14, 15 },
+ .oobfree = {{ .offset = 8, .length = 8 }}
+};
+
+static struct nand_ecclayout ibm_nand_oob_64 = {
+ .eccbytes = 24,
+ .eccpos = { 33, 34, 35, 37, 38, 39, 41, 42,
+ 43, 45, 46, 47, 49, 50, 51, 53,
+ 54, 55, 57, 58, 59, 61, 62, 63 },
+ .oobfree = {{ .offset = 2, .length = 30 }}
+};
+
+struct oob_placement {
+ const char *name;
+ struct nand_ecclayout *nand_oob[2];
+};
+
+static struct oob_placement oob_placement[] = {
+ { .name = "IBM",
+ .nand_oob = { &ibm_nand_oob_16, &ibm_nand_oob_64 }},
+ { .name = "MTD",
+ .nand_oob = { &mtd_nand_oob_16, &mtd_nand_oob_64 }},
+};
+
+#endif
diff --git a/ubi-utils/src/nand2bin.c b/ubi-utils/src/nand2bin.c
index be62e30..8c95b27 100644
--- a/ubi-utils/src/nand2bin.c
+++ b/ubi-utils/src/nand2bin.c
@@ -25,6 +25,9 @@
* 1.5 Added verbose output and option to set blocksize.
* Added split block mode for more convenient analysis.
* 1.6 Fixed ECC error detection and correction.
+ * 1.7 Made NAND ECC layout configurable, the holes which were previously
+ * filled with 0x00 are untouched now and will be 0xff just like MTD
+ * behaves when writing the oob (haver)
*/
#include <config.h>
@@ -43,9 +46,11 @@
#include "config.h"
#include "nandecc.h"
+#include "ecclayouts.h"
-#define PROGRAM_VERSION "1.6"
+#define PROGRAM_VERSION "1.7"
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define MAXPATH 1024
#define MIN(x,y) ((x)<(y)?(x):(y))
@@ -53,10 +58,13 @@ struct args {
const char *oob_file;
const char *output_file;
size_t pagesize;
+ size_t oobsize;
+ int bad_marker_offs_in_oob;
size_t blocksize;
int split_blocks;
size_t in_len; /* size of input file */
int correct_ecc;
+ struct nand_ecclayout *nand_oob;
/* special stuff needed to get additional arguments */
char *arg1;
@@ -68,6 +76,7 @@ static struct args myargs = {
.oob_file = "oob.bin",
.pagesize = 2048,
.blocksize = 128 * 1024,
+ .nand_oob = &ibm_nand_oob_64,
.in_len = 0,
.split_blocks = 0,
.correct_ecc = 0,
@@ -79,6 +88,7 @@ static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
"nand2bin - split data and OOB.\n";
static const char *optionsstr =
+" -l, --ecc-placement=<MTD,IBM> OOB placement scheme (default is IBM).\n"
" -o, --output=<output> Data output file\n"
" -O, --oob=<oob> OOB output file\n"
" -p, --pagesize=<pagesize> NAND pagesize\n"
@@ -97,6 +107,7 @@ static const char *usage =
static int verbose = 0;
static struct option long_options[] = {
+ { .name = "ecc-layout", .has_arg = 1, .flag = NULL, .val = 'l' },
{ .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
{ .name = "oob", .has_arg = 1, .flag = NULL, .val = 'O' },
{ .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' },
@@ -144,56 +155,52 @@ static uint32_t str_to_num(char *str)
*/
static int parse_opt(int argc, char **argv, struct args *args)
{
+ unsigned int i, oob_idx = 0;
+ const char *ecc_layout = NULL;
+
while (1) {
int key;
- key = getopt_long(argc, argv, "b:eo:O:p:sv?", long_options, NULL);
+ key = getopt_long(argc, argv, "b:el:o:O:p:sv?", long_options, NULL);
if (key == -1)
break;
switch (key) {
- case 'p': /* --pagesize<pagesize> */
- args->pagesize = str_to_num(optarg);
- break;
-
case 'b': /* --blocksize<blocksize> */
args->blocksize = str_to_num(optarg);
break;
-
- case 'v': /* --verbose */
- verbose++;
- break;
-
- case 's': /* --split-blocks */
- args->split_blocks = 1;
- break;
-
case 'e': /* --correct-ecc */
args->correct_ecc = 1;
break;
-
+ case 'l': /* --ecc-layout=<...> */
+ ecc_layout = optarg;
+ break;
case 'o': /* --output=<output.bin> */
args->output_file = optarg;
break;
-
case 'O': /* --oob=<oob.bin> */
args->oob_file = optarg;
break;
-
+ case 'p': /* --pagesize<pagesize> */
+ args->pagesize = str_to_num(optarg);
+ break;
+ case 's': /* --split-blocks */
+ args->split_blocks = 1;
+ break;
+ case 'v': /* --verbose */
+ verbose++;
+ break;
+ case 'V':
+ printf("%s\n", PROGRAM_VERSION);
+ exit(0);
+ break;
case '?': /* help */
printf("Usage: nand2bin [OPTION...] input.mif\n");
- printf("%s", doc);
- printf("%s", optionsstr);
+ printf("%s%s", doc, optionsstr);
printf("\nReport bugs to %s\n",
PACKAGE_BUGREPORT);
exit(0);
break;
-
- case 'V':
- printf("%s\n", PROGRAM_VERSION);
- exit(0);
- break;
-
default:
printf("%s", usage);
exit(-1);
@@ -203,17 +210,44 @@ static int parse_opt(int argc, char **argv, struct args *args)
if (optind < argc)
args->arg1 = argv[optind++];
+ switch (args->pagesize) {
+ case 512:
+ args->oobsize = 16;
+ args->bad_marker_offs_in_oob = 5;
+ oob_idx = 0;
+ break;
+ case 2048:
+ args->oobsize = 64;
+ args->bad_marker_offs_in_oob = 0;
+ oob_idx = 1;
+ break;
+ default:
+ fprintf(stderr, "Unsupported page size: %d\n", args->pagesize);
+ return -EINVAL;
+ }
+
+ /* Figure out correct oob layout if it differs from default */
+ if (ecc_layout) {
+ for (i = 0; i < ARRAY_SIZE(oob_placement); i++)
+ if (strcmp(ecc_layout, oob_placement[i].name) == 0)
+ args->nand_oob =
+ oob_placement[i].nand_oob[oob_idx];
+ }
return 0;
}
-static int calc_oobsize(size_t pagesize)
+/*
+ * We must only compare the relevant bytes in the OOB area. All other
+ * bytes can be ignored. The information we need to do this is in
+ * nand_oob.
+ */
+static int oob_cmp(struct nand_ecclayout *nand_oob, uint8_t *oob,
+ uint8_t *calc_oob)
{
- switch (pagesize) {
- case 512: return 16;
- case 2048: return 64;
- default:
- exit(EXIT_FAILURE);
- }
+ unsigned int i;
+ for (i = 0; i < nand_oob->eccbytes; i++)
+ if (oob[nand_oob->eccpos[i]] != calc_oob[nand_oob->eccpos[i]])
+ return 1;
return 0;
}
@@ -228,65 +262,38 @@ static inline void hexdump(FILE *fp, const uint8_t *buf, ssize_t size)
}
}
-static int process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize)
+static int process_page(struct args *args, uint8_t *buf, uint8_t *oobbuf)
{
- int eccpoi, oobsize;
- size_t i;
-
- switch (pagesize) {
- case 2048: oobsize = 64; eccpoi = 64 / 2; break;
- case 512: oobsize = 16; eccpoi = 16 / 2; break;
- default:
- fprintf(stderr, "Unsupported page size: %zd\n", pagesize);
- return -EINVAL;
- }
- memset(oobbuf, 0xff, oobsize);
-
- for (i = 0; i < pagesize; i += 256, eccpoi += 3) {
- oobbuf[eccpoi++] = 0x0;
- /* Calculate ECC */
- nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]);
+ size_t i, j;
+ int eccpoi;
+ uint8_t ecc_code[3] = { 0, }; /* temp */
+
+ /* Calculate ECC */
+ memset(oobbuf, 0xff, args->oobsize);
+ for (eccpoi = 0, i = 0; i < args->pagesize; i += 256, eccpoi += 3) {
+ nand_calculate_ecc(&buf[i], ecc_code);
+ for (j = 0; j < 3; j++)
+ oobbuf[args->nand_oob->eccpos[eccpoi + j]] = ecc_code[j];
}
return 0;
}
-static int bad_marker_offs_in_oob(int pagesize)
-{
- switch (pagesize) {
- case 2048: return 0;
- case 512: return 5;
- }
- return -EINVAL;
-}
-
static int decompose_image(struct args *args, FILE *in_fp,
FILE *bin_fp, FILE *oob_fp)
{
+ unsigned int i, eccpoi;
int read, rc, page = 0;
- size_t oobsize = calc_oobsize(args->pagesize);
uint8_t *buf = malloc(args->pagesize);
- uint8_t *oob = malloc(oobsize);
- uint8_t *calc_oob = malloc(oobsize);
+ uint8_t *oob = malloc(args->oobsize);
+ uint8_t *calc_oob = malloc(args->oobsize);
uint8_t *calc_buf = malloc(args->pagesize);
uint8_t *page_buf;
int pages_per_block = args->blocksize / args->pagesize;
- int eccpoi = 0, eccpoi_start;
- unsigned int i;
- int badpos = bad_marker_offs_in_oob(args->pagesize);
-
- switch (args->pagesize) {
- case 2048: eccpoi_start = 64 / 2; break;
- case 512: eccpoi_start = 16 / 2; break;
- default: exit(EXIT_FAILURE);
- }
+ int badpos = args->bad_marker_offs_in_oob;
+ uint8_t ecc_code[3] = { 0, }; /* temp */
+ uint8_t calc_ecc_code[3] = { 0, }; /* temp */
- if (!buf)
- exit(EXIT_FAILURE);
- if (!oob)
- exit(EXIT_FAILURE);
- if (!calc_oob)
- exit(EXIT_FAILURE);
- if (!calc_buf)
+ if (!buf || !oob || !calc_oob || !calc_buf)
exit(EXIT_FAILURE);
while (!feof(in_fp)) {
@@ -299,7 +306,7 @@ static int decompose_image(struct args *args, FILE *in_fp,
if (read != (ssize_t)args->pagesize)
break;
- read = fread(oob, 1, oobsize, in_fp);
+ read = fread(oob, 1, args->oobsize, in_fp);
if (ferror(in_fp)) {
fprintf(stderr, "I/O Error.");
exit(EXIT_FAILURE);
@@ -316,37 +323,31 @@ static int decompose_image(struct args *args, FILE *in_fp,
if (args->correct_ecc)
page_buf = calc_buf;
- process_page(buf, calc_oob, args->pagesize);
+ process_page(args, buf, calc_oob);
memcpy(calc_buf, buf, args->pagesize);
- /*
- * Our oob format uses only the last 3 bytes out of 4.
- * The first byte is 0x00 when the ECC is generated by
- * our toolset and 0xff when generated by Linux. This
- * is to be fixed when we want nand2bin work for other
- * ECC layouts too.
- */
- for (i = 0, eccpoi = eccpoi_start; i < args->pagesize;
- i += 256, eccpoi += 4)
- oob[eccpoi] = calc_oob[eccpoi] = 0xff;
-
- if (verbose && memcmp(oob, calc_oob, oobsize) != 0) {
+ if (verbose && oob_cmp(args->nand_oob, oob, calc_oob) != 0) {
printf("\nECC compare mismatch found at block %d page %d!\n",
page / pages_per_block, page % pages_per_block);
printf("Read out OOB Data:\n");
- hexdump(stdout, oob, oobsize);
+ hexdump(stdout, oob, args->oobsize);
printf("Calculated OOB Data:\n");
- hexdump(stdout, calc_oob, oobsize);
+ hexdump(stdout, calc_oob, args->oobsize);
}
/* Do correction on subpage base */
- for (i = 0, eccpoi = eccpoi_start; i < args->pagesize;
- i += 256, eccpoi += 4) {
- rc = nand_correct_data(calc_buf + i, &oob[eccpoi + 1],
- &calc_oob[eccpoi + 1]);
-
+ for (i = 0, eccpoi = 0; i < args->pagesize; i += 256, eccpoi += 3) {
+ int j;
+
+ for (j = 0; j < 3; j++) {
+ ecc_code[j] = oob[args->nand_oob->eccpos[eccpoi + j]];
+ calc_ecc_code[j] =
+ calc_oob[args->nand_oob->eccpos[eccpoi + j]];
+ }
+ rc = nand_correct_data(calc_buf + i, ecc_code,
+ calc_ecc_code);
if (rc == -1)
fprintf(stdout, "Uncorrectable ECC error at "
"block %d page %d/%d\n",
@@ -365,7 +366,7 @@ static int decompose_image(struct args *args, FILE *in_fp,
fprintf(stderr, "I/O Error.");
exit(EXIT_FAILURE);
}
- rc = fwrite(oob, 1, oobsize, oob_fp);
+ rc = fwrite(oob, 1, args->oobsize, oob_fp);
if (ferror(bin_fp)) {
fprintf(stderr, "I/O Error.");
exit(EXIT_FAILURE);
@@ -383,12 +384,11 @@ static int decompose_image(struct args *args, FILE *in_fp,
static int split_blocks(struct args *args, FILE *in_fp)
{
uint8_t *buf;
- size_t oobsize = calc_oobsize(args->pagesize);
int pages_per_block = args->blocksize / args->pagesize;
- int block_len = pages_per_block * (args->pagesize + oobsize);
+ int block_len = pages_per_block * (args->pagesize + args->oobsize);
int blocks = args->in_len / block_len;
char bname[256] = { 0, };
- int badpos = bad_marker_offs_in_oob(args->pagesize);
+ int badpos = args->bad_marker_offs_in_oob;
int bad_blocks = 0, i, bad_block = 0;
ssize_t rc;
FILE *b;
@@ -409,16 +409,16 @@ static int split_blocks(struct args *args, FILE *in_fp)
/* do block analysis */
bad_block = 0;
if ((buf[args->pagesize + badpos] != 0xff) ||
- (buf[2 * args->pagesize + oobsize + badpos] != 0xff)) {
+ (buf[2 * args->pagesize + args->oobsize + badpos] != 0xff)) {
bad_blocks++;
bad_block = 1;
}
if ((verbose && bad_block) || (verbose > 1)) {
printf("-- (block %d oob of page 0 and 1)\n", i);
- hexdump(stdout, buf + args->pagesize, oobsize);
+ hexdump(stdout, buf + args->pagesize, args->oobsize);
printf("--\n");
hexdump(stdout, buf + 2 * args->pagesize +
- oobsize, oobsize);
+ args->oobsize, args->oobsize);
}
/* write complete block out */