flash_erase.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* flash_erase.c -- erase MTD devices
  2. Copyright (C) 2000 Arcom Control System Ltd
  3. Copyright (C) 2010 Mike Frysinger <vapier@gentoo.org>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  15. */
  16. #define PROGRAM_NAME "flash_erase"
  17. #include <inttypes.h>
  18. #include <stdbool.h>
  19. #include <stdio.h>
  20. #include <unistd.h>
  21. #include <fcntl.h>
  22. #include <stdlib.h>
  23. #include <errno.h>
  24. #include <string.h>
  25. #include <stdint.h>
  26. #include <getopt.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/types.h>
  29. #include <common.h>
  30. #include <crc32.h>
  31. #include <libmtd.h>
  32. #include <mtd/mtd-user.h>
  33. #include <mtd/jffs2-user.h>
  34. static const char *mtd_device;
  35. static int quiet; /* true -- don't output progress */
  36. static int jffs2; /* format for jffs2 usage */
  37. static int noskipbad; /* do not skip bad blocks */
  38. static int unlock; /* unlock sectors before erasing */
  39. static struct jffs2_unknown_node cleanmarker;
  40. int target_endian = __BYTE_ORDER;
  41. static void show_progress(struct mtd_dev_info *mtd, off_t start, int eb,
  42. int eb_start, int eb_cnt)
  43. {
  44. bareverbose(!quiet, "\rErasing %d Kibyte @ %llx -- %2i %% complete ",
  45. mtd->eb_size / 1024, (unsigned long long)start, ((eb - eb_start) * 100) / eb_cnt);
  46. fflush(stdout);
  47. }
  48. static void display_help (void)
  49. {
  50. printf("Usage: %s [options] MTD_DEVICE <start offset> <block count>\n"
  51. "Erase blocks of the specified MTD device.\n"
  52. "Specify a count of 0 to erase to end of device.\n"
  53. "\n"
  54. " -j, --jffs2 format the device for jffs2\n"
  55. " -N, --noskipbad don't skip bad blocks\n"
  56. " -u, --unlock unlock sectors before erasing\n"
  57. " -q, --quiet do not display progress messages\n"
  58. " --silent same as --quiet\n"
  59. " --help display this help and exit\n"
  60. " --version output version information and exit\n",
  61. PROGRAM_NAME);
  62. }
  63. static void display_version (void)
  64. {
  65. common_print_version();
  66. printf("Copyright (C) 2000 Arcom Control Systems Ltd\n"
  67. "\n"
  68. "%1$s comes with NO WARRANTY\n"
  69. "to the extent permitted by law.\n"
  70. "\n"
  71. "You may redistribute copies of %1$s\n"
  72. "under the terms of the GNU General Public Licence.\n"
  73. "See the file `COPYING' for more information.\n",
  74. PROGRAM_NAME);
  75. }
  76. int main(int argc, char *argv[])
  77. {
  78. libmtd_t mtd_desc;
  79. struct mtd_dev_info mtd;
  80. int fd, cmlen = 8;
  81. unsigned long long start;
  82. unsigned int eb, eb_start, eb_cnt;
  83. bool isNAND;
  84. int error = 0;
  85. off_t offset = 0;
  86. /*
  87. * Process user arguments
  88. */
  89. for (;;) {
  90. int option_index = 0;
  91. static const char *short_options = "jNquVh";
  92. static const struct option long_options[] = {
  93. {"help", no_argument, 0, 'h'},
  94. {"version", no_argument, 0, 'V'},
  95. {"jffs2", no_argument, 0, 'j'},
  96. {"noskipbad", no_argument, 0, 'N'},
  97. {"quiet", no_argument, 0, 'q'},
  98. {"silent", no_argument, 0, 'q'},
  99. {"unlock", no_argument, 0, 'u'},
  100. {0, 0, 0, 0},
  101. };
  102. int c = getopt_long(argc, argv, short_options,
  103. long_options, &option_index);
  104. if (c == EOF)
  105. break;
  106. switch (c) {
  107. case 'h':
  108. display_help();
  109. return EXIT_SUCCESS;
  110. case 'V':
  111. display_version();
  112. return EXIT_SUCCESS;
  113. case 'j':
  114. jffs2 = 1;
  115. break;
  116. case 'N':
  117. noskipbad = 1;
  118. break;
  119. case 'q':
  120. quiet = 1;
  121. break;
  122. case 'u':
  123. unlock = 1;
  124. break;
  125. case '?':
  126. error = 1;
  127. break;
  128. }
  129. }
  130. switch (argc - optind) {
  131. case 3:
  132. mtd_device = argv[optind];
  133. start = simple_strtoull(argv[optind + 1], &error);
  134. eb_cnt = simple_strtoul(argv[optind + 2], &error);
  135. break;
  136. default:
  137. case 0:
  138. errmsg("no MTD device specified");
  139. /* fall-through */
  140. case 1:
  141. errmsg("no start erase block specified");
  142. /* fall-through */
  143. case 2:
  144. errmsg("no erase block count specified");
  145. error = 1;
  146. break;
  147. }
  148. if (error)
  149. return errmsg("Try `--help' for more information");
  150. /*
  151. * Locate MTD and prepare for erasure
  152. */
  153. mtd_desc = libmtd_open();
  154. if (mtd_desc == NULL)
  155. return errmsg("can't initialize libmtd");
  156. if ((fd = open(mtd_device, O_RDWR)) < 0)
  157. return sys_errmsg("%s", mtd_device);
  158. if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
  159. return errmsg("mtd_get_dev_info failed");
  160. if (jffs2 && mtd.type == MTD_MLCNANDFLASH)
  161. return errmsg("JFFS2 cannot support MLC NAND.");
  162. eb_start = start / mtd.eb_size;
  163. isNAND = mtd.type == MTD_NANDFLASH || mtd.type == MTD_MLCNANDFLASH;
  164. if (jffs2) {
  165. cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
  166. cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
  167. if (!isNAND) {
  168. cleanmarker.totlen = cpu_to_je32(sizeof(cleanmarker));
  169. } else {
  170. cleanmarker.totlen = cpu_to_je32(8);
  171. cmlen = min(mtd.oobavail, 8);
  172. }
  173. cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(cleanmarker) - 4));
  174. }
  175. /*
  176. * Now do the actual erasing of the MTD device
  177. */
  178. if (eb_cnt == 0)
  179. eb_cnt = (mtd.size / mtd.eb_size) - eb_start;
  180. for (eb = eb_start; eb < eb_start + eb_cnt; eb++) {
  181. offset = (off_t)eb * mtd.eb_size;
  182. if (!noskipbad) {
  183. int ret = mtd_is_bad(&mtd, fd, eb);
  184. if (ret > 0) {
  185. verbose(!quiet, "Skipping bad block at %08llx", (unsigned long long)offset);
  186. continue;
  187. } else if (ret < 0) {
  188. if (errno == EOPNOTSUPP) {
  189. noskipbad = 1;
  190. if (isNAND)
  191. return errmsg("%s: Bad block check not available", mtd_device);
  192. } else
  193. return sys_errmsg("%s: MTD get bad block failed", mtd_device);
  194. }
  195. }
  196. show_progress(&mtd, offset, eb, eb_start, eb_cnt);
  197. if (unlock) {
  198. if (mtd_unlock(&mtd, fd, eb) != 0) {
  199. sys_errmsg("%s: MTD unlock failure", mtd_device);
  200. continue;
  201. }
  202. }
  203. if (mtd_erase(mtd_desc, &mtd, fd, eb) != 0) {
  204. sys_errmsg("%s: MTD Erase failure", mtd_device);
  205. continue;
  206. }
  207. /* format for JFFS2 ? */
  208. if (!jffs2)
  209. continue;
  210. /* write cleanmarker */
  211. if (isNAND) {
  212. if (mtd_write(mtd_desc, &mtd, fd, eb, 0, NULL, 0, &cleanmarker, cmlen,
  213. MTD_OPS_AUTO_OOB) != 0) {
  214. sys_errmsg("%s: MTD writeoob failure", mtd_device);
  215. continue;
  216. }
  217. } else {
  218. if (pwrite(fd, &cleanmarker, sizeof(cleanmarker), (loff_t)offset) != sizeof(cleanmarker)) {
  219. sys_errmsg("%s: MTD write failure", mtd_device);
  220. continue;
  221. }
  222. }
  223. verbose(!quiet, " Cleanmarker Updated.");
  224. }
  225. show_progress(&mtd, offset, eb, eb_start, eb_cnt);
  226. bareverbose(!quiet, "\n");
  227. return 0;
  228. }