• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
test_empty(const char * buf,size_t size)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 
nandread_main(int argc,char ** argv)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