• 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  
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