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