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