17c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg#include <stdio.h>
27c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg#include <stdlib.h>
37c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg#include <string.h>
47c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg#include <ctype.h>
57c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg#include <errno.h>
67c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg#include <fcntl.h>
7b93e5812faffd3b6c5fb349072413aace31918d8Olivier Bailly#include <unistd.h>
87c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
97c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg#include <mtd/mtd-user.h>
107c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg#include <sys/ioctl.h>
117c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
12b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevågstatic int test_empty(const char *buf, size_t size)
137c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg{
147c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    while(size--) {
157c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (*buf++ != 0xff)
167c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            return 0;
177c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
187c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    return 1;
197c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg}
207c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
217c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevågint nandread_main(int argc, char **argv)
227c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg{
237c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    char *devname = NULL;
247c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    char *filename = NULL;
257c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    char *statusfilename = NULL;
267c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    char *statusext = ".stat";
277c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int fd;
287c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int outfd = -1;
297c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    FILE *statusfile = NULL;
307c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int ret;
317c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int verbose = 0;
327c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    void *buffer;
33b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg    loff_t pos, opos, end, bpos;
34b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg    loff_t start = 0, len = 0;
357c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int c;
367c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int i;
377c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int empty_pages = 0;
387c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int page_count = 0;
397c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    int bad_block;
40b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg    int rawmode = 0;
417c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    uint32_t *oob_data;
427c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    uint8_t *oob_fixed;
437c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    size_t spare_size = 64;
447c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    struct mtd_info_user mtdinfo;
457c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    struct mtd_ecc_stats initial_ecc, last_ecc, ecc;
467c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    struct mtd_oob_buf oobbuf;
477c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    struct nand_ecclayout ecclayout;
487c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
497c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    do {
50b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        c = getopt(argc, argv, "d:f:s:S:L:Rhv");
517c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (c == EOF)
527c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            break;
537c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        switch (c) {
547c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        case 'd':
557c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            devname = optarg;
567c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            break;
577c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        case 'f':
587c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            filename = optarg;
597c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            break;
607c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        case 's':
617c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            spare_size = atoi(optarg);
627c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            break;
63b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        case 'S':
64b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            start = strtoll(optarg, NULL, 0);
65b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            break;
66b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        case 'L':
67b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            len = strtoll(optarg, NULL, 0);
68b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            break;
69b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        case 'R':
70b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            rawmode = 1;
71b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            break;
727c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        case 'v':
737c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            verbose++;
747c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            break;
757c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        case 'h':
767c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            fprintf(stderr, "%s [-d <dev>] [-f file] [-s sparesize] [-vh]\n"
777c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                    "  -d <dev>   Read from <dev>\n"
787c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                    "  -f <file>  Write to <file>\n"
797c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                    "  -s <size>  Number of spare bytes in file (default 64)\n"
80b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                    "  -R         Raw mode\n"
81b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                    "  -S <start> Start offset (default 0)\n"
82b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                    "  -L <len>   Length (default 0)\n"
837c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                    "  -v         Print info\n"
847c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                    "  -h         Print help\n", argv[0]);
857c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            return -1;
867c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        case '?':
877c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            fprintf(stderr, "%s: invalid option -%c\n",
887c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                argv[0], optopt);
897c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            exit(1);
907c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
917c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    } while (1);
927c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
937c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (optind < argc) {
947c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(stderr, "%s: extra arguments\n", argv[0]);
957c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        return 1;
967c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
977c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (!devname) {
987c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(stderr, "%s: specify device name\n", argv[0]);
997c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        return 1;
1007c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1017c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1027c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    fd = open(devname, O_RDONLY);
1037c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (fd < 0) {
1047c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(stderr, "cannot open %s, %s\n", devname, strerror(errno));
1057c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        return 1;
1067c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1077c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1087c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (filename) {
1097c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        outfd = creat(filename, 0666);
1107c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (outfd < 0) {
1117c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            fprintf(stderr, "cannot open %s, %s\n", filename, strerror(errno));
1127c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            return 1;
1137c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
1147c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        statusfilename = malloc(strlen(filename) + strlen(statusext) + 1);
1157c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        strcpy(statusfilename, filename);
1167c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        strcat(statusfilename, statusext);
1177c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        statusfile = fopen(statusfilename, "w+");
1187c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (!statusfile) {
1197c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            fprintf(stderr, "cannot open %s, %s\n", statusfilename, strerror(errno));
1207c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            return 1;
1217c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
1227c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1237c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1247c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    ret = ioctl(fd, MEMGETINFO, &mtdinfo);
1257c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (ret) {
1267c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(stderr, "failed get mtd info for %s, %s\n",
1277c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                devname, strerror(errno));
1287c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        return 1;
1297c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1307c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1317c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (verbose) {
1327c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("size: %u\n", mtdinfo.size);
1337c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("erase size: %u\n", mtdinfo.erasesize);
1347c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("write size: %u\n", mtdinfo.writesize);
1357c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("oob size: %u\n", mtdinfo.oobsize);
1367c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1377c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1387c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    buffer = malloc(mtdinfo.writesize + mtdinfo.oobsize + spare_size);
1397c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (!buffer) {
1407c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(stderr, "failed allocate readbuffer size %u\n",
1417c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                mtdinfo.writesize + mtdinfo.oobsize);
1427c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        return 1;
1437c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1447c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1457c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    oobbuf.length = mtdinfo.oobsize;
1467c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    oob_data = (uint32_t *)((uint8_t *)buffer + mtdinfo.writesize);
147b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg    memset(oob_data, 0xff, mtdinfo.oobsize + spare_size);
1487c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    oobbuf.ptr = (uint8_t *)oob_data + spare_size;
1497c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1507c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    ret = ioctl(fd, ECCGETLAYOUT, &ecclayout);
1517c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (ret) {
1527c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(stderr, "failed get ecc layout for %s, %s\n",
1537c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                devname, strerror(errno));
1547c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        return 1;
1557c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1567c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (verbose) {
1577c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("ecc bytes: %u\n", ecclayout.eccbytes);
1587c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("oobavail: %u\n", ecclayout.oobavail);
1597c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1607c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (ecclayout.oobavail > spare_size)
1617c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("oobavail, %d > image spare size, %d\n", ecclayout.oobavail, spare_size);
1627c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1637c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    ret = ioctl(fd, ECCGETSTATS, &initial_ecc);
1647c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (ret) {
1657c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(stderr, "failed get ecc stats for %s, %s\n",
1667c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                devname, strerror(errno));
1677c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        return 1;
1687c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1697c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    last_ecc = initial_ecc;
1707c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
1717c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (verbose) {
1727c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("initial ecc corrected: %u\n", initial_ecc.corrected);
1737c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("initial ecc failed: %u\n", initial_ecc.failed);
1747c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("initial ecc badblocks: %u\n", initial_ecc.badblocks);
1757c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("initial ecc bbtblocks: %u\n", initial_ecc.bbtblocks);
1767c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
1777c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
178b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg    if (rawmode) {
179b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        rawmode = mtdinfo.oobsize;
180b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW);
181b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        if (ret) {
182b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            fprintf(stderr, "failed set raw mode for %s, %s\n",
183b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                    devname, strerror(errno));
184b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            return 1;
185b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        }
186b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg    }
187b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg
188b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg    end = len ? (start + len) : mtdinfo.size;
189b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg    for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
1907c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        bad_block = 0;
1917c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (verbose > 3)
1927c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            printf("reading at %llx\n", pos);
1937c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        lseek64(fd, pos, SEEK_SET);
194b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        ret = read(fd, buffer, mtdinfo.writesize + rawmode);
1957c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (ret < (int)mtdinfo.writesize) {
1967c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            fprintf(stderr, "short read at %llx, %d\n", pos, ret);
1977c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            bad_block = 2;
1987c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
199b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        if (!rawmode) {
200b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            oobbuf.start = pos;
201b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            ret = ioctl(fd, MEMREADOOB, &oobbuf);
202b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            if (ret) {
203b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
204b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                bad_block = 2;
205b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            }
2067c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
2077c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        ret = ioctl(fd, ECCGETSTATS, &ecc);
2087c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (ret) {
2097c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            fprintf(stderr, "failed get ecc stats for %s, %s\n",
2107c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                    devname, strerror(errno));
2117c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            return 1;
2127c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
213b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
214b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
2157c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (ret && errno != EOPNOTSUPP) {
2167c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            printf("badblock at %llx\n", pos);
2177c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            bad_block = 1;
2187c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
2197c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (ecc.corrected != last_ecc.corrected)
2207c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            printf("ecc corrected, %u, at %llx\n", ecc.corrected - last_ecc.corrected, pos);
2217c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (ecc.failed != last_ecc.failed)
2227c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            printf("ecc failed, %u, at %llx\n", ecc.failed - last_ecc.failed, pos);
2237c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (ecc.badblocks != last_ecc.badblocks)
2247c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            printf("ecc badblocks, %u, at %llx\n", ecc.badblocks - last_ecc.badblocks, pos);
2257c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (ecc.bbtblocks != last_ecc.bbtblocks)
2267c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
2277c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
228b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg        if (!rawmode) {
229b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            oob_fixed = (uint8_t *)oob_data;
230b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg            for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
231b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                int len = ecclayout.oobfree[i].length;
232b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                if (oob_fixed + len > oobbuf.ptr)
233b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                    len = oobbuf.ptr - oob_fixed;
234b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                if (len) {
235b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                    memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len);
236b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                    oob_fixed += len;
237b6b8793b8b6dad500f6884539e47efb4c161576aArve Hjønnevåg                }
2387c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            }
2397c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
2407c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
2417c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (outfd >= 0) {
2427c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
2437c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            if (ret < (int)(mtdinfo.writesize + spare_size)) {
2447c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                fprintf(stderr, "short write at %llx, %d\n", pos, ret);
2457c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                close(outfd);
2467c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                outfd = -1;
2477c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            }
2487c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            if (ecc.corrected != last_ecc.corrected)
2497c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                fprintf(statusfile, "%08llx: ecc corrected\n", opos);
2507c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            if (ecc.failed != last_ecc.failed)
2517c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                fprintf(statusfile, "%08llx: ecc failed\n", opos);
2527c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            if (bad_block == 1)
2537c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                fprintf(statusfile, "%08llx: badblock\n", opos);
2547c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            if (bad_block == 2)
2557c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                fprintf(statusfile, "%08llx: read error\n", opos);
2567c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            opos += mtdinfo.writesize + spare_size;
2577c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        }
2587c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
2597c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        last_ecc = ecc;
2607c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        page_count++;
2617c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
2627c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            empty_pages++;
2637c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
2647c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg            printf("page at %llx (%d oobbytes): %08x %08x %08x %08x "
2657c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                   "%08x %08x %08x %08x\n", pos, oobbuf.start,
2667c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                   oob_data[0], oob_data[1], oob_data[2], oob_data[3],
2677c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg                   oob_data[4], oob_data[5], oob_data[6], oob_data[7]);
2687c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
2697c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
2707c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (outfd >= 0) {
2717c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(statusfile, "read %d pages, %d empty\n", page_count, empty_pages);
2727c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(statusfile, "total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected);
2737c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(statusfile, "total ecc failed, %u\n", ecc.failed - initial_ecc.failed);
2747c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(statusfile, "total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks);
2757c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        fprintf(statusfile, "total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks);
2767c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
2777c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    if (verbose) {
2787c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected);
2797c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("total ecc failed, %u\n", ecc.failed - initial_ecc.failed);
2807c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks);
2817c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg        printf("total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks);
2827c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    }
2837c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    printf("read %d pages, %d empty\n", page_count, empty_pages);
2847c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg
2857c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg    return 0;
2867c953d04bcc9070a1bce171e979c5201dd39325bArve Hjønnevåg}
287