1#include <ctype.h> 2#include <errno.h> 3#include <fcntl.h> 4#include <inttypes.h> 5#include <stdio.h> 6#include <stdlib.h> 7#include <string.h> 8#include <unistd.h> 9 10#include <mtd/mtd-user.h> 11#include <sys/ioctl.h> 12 13static int test_empty(const char *buf, size_t size) 14{ 15 while(size--) { 16 if (*buf++ != (char) 0xff) 17 return 0; 18 } 19 return 1; 20} 21 22int nandread_main(int argc, char **argv) 23{ 24 char *devname = NULL; 25 char *filename = NULL; 26 char *statusfilename = NULL; 27 char *statusext = ".stat"; 28 int fd; 29 int outfd = -1; 30 FILE *statusfile = NULL; 31 int ret; 32 int verbose = 0; 33 void *buffer; 34 loff_t pos, opos, end, bpos; 35 loff_t start = 0, len = 0; 36 int c; 37 int i; 38 int empty_pages = 0; 39 int page_count = 0; 40 int bad_block; 41 int rawmode = 0; 42 uint32_t *oob_data; 43 uint8_t *oob_fixed; 44 size_t spare_size = 64; 45 struct mtd_info_user mtdinfo; 46 struct mtd_ecc_stats initial_ecc, last_ecc, ecc; 47 struct mtd_oob_buf oobbuf; 48 nand_ecclayout_t ecclayout; 49 50 do { 51 c = getopt(argc, argv, "d:f:s:S:L:Rhv"); 52 if (c == EOF) 53 break; 54 switch (c) { 55 case 'd': 56 devname = optarg; 57 break; 58 case 'f': 59 filename = optarg; 60 break; 61 case 's': 62 spare_size = atoi(optarg); 63 break; 64 case 'S': 65 start = strtoll(optarg, NULL, 0); 66 break; 67 case 'L': 68 len = strtoll(optarg, NULL, 0); 69 break; 70 case 'R': 71 rawmode = 1; 72 break; 73 case 'v': 74 verbose++; 75 break; 76 case 'h': 77 fprintf(stderr, "%s [-d <dev>] [-f file] [-s sparesize] [-vh]\n" 78 " -d <dev> Read from <dev>\n" 79 " -f <file> Write to <file>\n" 80 " -s <size> Number of spare bytes in file (default 64)\n" 81 " -R Raw mode\n" 82 " -S <start> Start offset (default 0)\n" 83 " -L <len> Length (default 0)\n" 84 " -v Print info\n" 85 " -h Print help\n", argv[0]); 86 return -1; 87 case '?': 88 fprintf(stderr, "%s: invalid option -%c\n", 89 argv[0], optopt); 90 exit(1); 91 } 92 } while (1); 93 94 if (optind < argc) { 95 fprintf(stderr, "%s: extra arguments\n", argv[0]); 96 return 1; 97 } 98 if (!devname) { 99 fprintf(stderr, "%s: specify device name\n", argv[0]); 100 return 1; 101 } 102 103 fd = open(devname, O_RDONLY); 104 if (fd < 0) { 105 fprintf(stderr, "cannot open %s, %s\n", devname, strerror(errno)); 106 return 1; 107 } 108 109 if (filename) { 110 outfd = creat(filename, 0666); 111 if (outfd < 0) { 112 fprintf(stderr, "cannot open %s, %s\n", filename, strerror(errno)); 113 return 1; 114 } 115 statusfilename = malloc(strlen(filename) + strlen(statusext) + 1); 116 strcpy(statusfilename, filename); 117 strcat(statusfilename, statusext); 118 statusfile = fopen(statusfilename, "w+"); 119 if (!statusfile) { 120 fprintf(stderr, "cannot open %s, %s\n", statusfilename, strerror(errno)); 121 return 1; 122 } 123 } 124 125 ret = ioctl(fd, MEMGETINFO, &mtdinfo); 126 if (ret) { 127 fprintf(stderr, "failed get mtd info for %s, %s\n", 128 devname, strerror(errno)); 129 return 1; 130 } 131 132 if (verbose) { 133 printf("size: %u\n", mtdinfo.size); 134 printf("erase size: %u\n", mtdinfo.erasesize); 135 printf("write size: %u\n", mtdinfo.writesize); 136 printf("oob size: %u\n", mtdinfo.oobsize); 137 } 138 139 buffer = malloc(mtdinfo.writesize + mtdinfo.oobsize + spare_size); 140 if (!buffer) { 141 fprintf(stderr, "failed allocate readbuffer size %u\n", 142 mtdinfo.writesize + mtdinfo.oobsize); 143 return 1; 144 } 145 146 oobbuf.length = mtdinfo.oobsize; 147 oob_data = (uint32_t *)((uint8_t *)buffer + mtdinfo.writesize); 148 memset(oob_data, 0xff, mtdinfo.oobsize + spare_size); 149 oobbuf.ptr = (uint8_t *)oob_data + spare_size; 150 151 ret = ioctl(fd, ECCGETLAYOUT, &ecclayout); 152 if (ret) { 153 fprintf(stderr, "failed get ecc layout for %s, %s\n", 154 devname, strerror(errno)); 155 return 1; 156 } 157 if (verbose) { 158 printf("ecc bytes: %u\n", ecclayout.eccbytes); 159 printf("oobavail: %u\n", ecclayout.oobavail); 160 } 161 if (ecclayout.oobavail > spare_size) 162 printf("oobavail, %d > image spare size, %zu\n", ecclayout.oobavail, spare_size); 163 164 ret = ioctl(fd, ECCGETSTATS, &initial_ecc); 165 if (ret) { 166 fprintf(stderr, "failed get ecc stats for %s, %s\n", 167 devname, strerror(errno)); 168 return 1; 169 } 170 last_ecc = initial_ecc; 171 172 if (verbose) { 173 printf("initial ecc corrected: %u\n", initial_ecc.corrected); 174 printf("initial ecc failed: %u\n", initial_ecc.failed); 175 printf("initial ecc badblocks: %u\n", initial_ecc.badblocks); 176 printf("initial ecc bbtblocks: %u\n", initial_ecc.bbtblocks); 177 } 178 179 if (rawmode) { 180 rawmode = mtdinfo.oobsize; 181 ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW); 182 if (ret) { 183 fprintf(stderr, "failed set raw mode for %s, %s\n", 184 devname, strerror(errno)); 185 return 1; 186 } 187 } 188 189 end = len ? (start + len) : mtdinfo.size; 190 for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) { 191 bad_block = 0; 192 if (verbose > 3) 193 printf("reading at %" PRIx64 "\n", pos); 194 lseek64(fd, pos, SEEK_SET); 195 ret = read(fd, buffer, mtdinfo.writesize + rawmode); 196 if (ret < (int)mtdinfo.writesize) { 197 fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret); 198 bad_block = 2; 199 } 200 if (!rawmode) { 201 oobbuf.start = pos; 202 ret = ioctl(fd, MEMREADOOB, &oobbuf); 203 if (ret) { 204 fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret); 205 bad_block = 2; 206 } 207 } 208 ret = ioctl(fd, ECCGETSTATS, &ecc); 209 if (ret) { 210 fprintf(stderr, "failed get ecc stats for %s, %s\n", 211 devname, strerror(errno)); 212 return 1; 213 } 214 bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize; 215 ret = ioctl(fd, MEMGETBADBLOCK, &bpos); 216 if (ret && errno != EOPNOTSUPP) { 217 printf("badblock at %" PRIx64 "\n", pos); 218 bad_block = 1; 219 } 220 if (ecc.corrected != last_ecc.corrected) 221 printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos); 222 if (ecc.failed != last_ecc.failed) 223 printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos); 224 if (ecc.badblocks != last_ecc.badblocks) 225 printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos); 226 if (ecc.bbtblocks != last_ecc.bbtblocks) 227 printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos); 228 229 if (!rawmode) { 230 oob_fixed = (uint8_t *)oob_data; 231 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) { 232 int len = ecclayout.oobfree[i].length; 233 if (oob_fixed + len > oobbuf.ptr) 234 len = oobbuf.ptr - oob_fixed; 235 if (len) { 236 memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len); 237 oob_fixed += len; 238 } 239 } 240 } 241 242 if (outfd >= 0) { 243 ret = write(outfd, buffer, mtdinfo.writesize + spare_size); 244 if (ret < (int)(mtdinfo.writesize + spare_size)) { 245 fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret); 246 close(outfd); 247 outfd = -1; 248 } 249 if (ecc.corrected != last_ecc.corrected) 250 fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos); 251 if (ecc.failed != last_ecc.failed) 252 fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos); 253 if (bad_block == 1) 254 fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos); 255 if (bad_block == 2) 256 fprintf(statusfile, "%08" PRIx64 ": read error\n", opos); 257 opos += mtdinfo.writesize + spare_size; 258 } 259 260 last_ecc = ecc; 261 page_count++; 262 if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size)) 263 empty_pages++; 264 else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1)))) 265 printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x " 266 "%08x %08x %08x %08x\n", pos, oobbuf.start, 267 oob_data[0], oob_data[1], oob_data[2], oob_data[3], 268 oob_data[4], oob_data[5], oob_data[6], oob_data[7]); 269 } 270 271 if (outfd >= 0) { 272 fprintf(statusfile, "read %d pages, %d empty\n", page_count, empty_pages); 273 fprintf(statusfile, "total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected); 274 fprintf(statusfile, "total ecc failed, %u\n", ecc.failed - initial_ecc.failed); 275 fprintf(statusfile, "total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks); 276 fprintf(statusfile, "total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks); 277 } 278 if (verbose) { 279 printf("total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected); 280 printf("total ecc failed, %u\n", ecc.failed - initial_ecc.failed); 281 printf("total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks); 282 printf("total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks); 283 } 284 printf("read %d pages, %d empty\n", page_count, empty_pages); 285 286 return 0; 287} 288