blob: 96449730975e7f65d1660c8615fce6d3fc8b371e [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
Arve Hjønnevågb6b87932010-03-03 16:48:38 -080011static int test_empty(const char *buf, size_t size)
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -070012{
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;
Arve Hjønnevågb6b87932010-03-03 16:48:38 -080032 loff_t pos, opos, end, bpos;
33 loff_t start = 0, len = 0;
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -070034 int c;
35 int i;
36 int empty_pages = 0;
37 int page_count = 0;
38 int bad_block;
Arve Hjønnevågb6b87932010-03-03 16:48:38 -080039 int rawmode = 0;
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -070040 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 {
Arve Hjønnevågb6b87932010-03-03 16:48:38 -080049 c = getopt(argc, argv, "d:f:s:S:L:Rhv");
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -070050 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;
Arve Hjønnevågb6b87932010-03-03 16:48:38 -080062 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;
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -070071 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"
Arve Hjønnevågb6b87932010-03-03 16:48:38 -080079 " -R Raw mode\n"
80 " -S <start> Start offset (default 0)\n"
81 " -L <len> Length (default 0)\n"
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -070082 " -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);
Arve Hjønnevågb6b87932010-03-03 16:48:38 -0800146 memset(oob_data, 0xff, mtdinfo.oobsize + spare_size);
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -0700147 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
Arve Hjønnevågb6b87932010-03-03 16:48:38 -0800177 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) {
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -0700189 bad_block = 0;
190 if (verbose > 3)
191 printf("reading at %llx\n", pos);
192 lseek64(fd, pos, SEEK_SET);
Arve Hjønnevågb6b87932010-03-03 16:48:38 -0800193 ret = read(fd, buffer, mtdinfo.writesize + rawmode);
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -0700194 if (ret < (int)mtdinfo.writesize) {
195 fprintf(stderr, "short read at %llx, %d\n", pos, ret);
196 bad_block = 2;
197 }
Arve Hjønnevågb6b87932010-03-03 16:48:38 -0800198 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 }
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -0700205 }
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 }
Arve Hjønnevågb6b87932010-03-03 16:48:38 -0800212 bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
213 ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -0700214 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
Arve Hjønnevågb6b87932010-03-03 16:48:38 -0800227 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 }
Arve Hjønnevåg7c953d02009-09-17 17:30:55 -0700237 }
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