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