- add flash_eraseall
[oweals/busybox.git] / miscutils / flash_eraseall.c
1 /* eraseall.c -- erase the whole of a MTD device
2
3    Ported to busybox from mtd-utils.
4
5    Copyright (C) 2000 Arcom Control System Ltd
6
7    Renamed to flash_eraseall.c
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
22  */
23
24 #include "libbb.h"
25
26 #include <mtd/mtd-user.h>
27 #include <mtd/jffs2-user.h>
28
29 #define OPTION_J        (1 << 0)
30 #define OPTION_Q        (1 << 1)
31
32 int target_endian = __BYTE_ORDER;
33
34 static uint32_t crc32(uint32_t val, const void *ss, int len,
35                 uint32_t *crc32_table)
36 {
37         const unsigned char *s = ss;
38         while (--len >= 0)
39                 val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
40         return val;
41 }
42
43 static void show_progress(mtd_info_t *meminfo, erase_info_t *erase)
44 {
45         printf("\rErasing %d Kibyte @ %x -- %2llu %% complete.",
46                 meminfo->erasesize / 1024, erase->start,
47                 (unsigned long long) erase->start * 100 / meminfo->size);
48         fflush(stdout);
49 }
50
51 int flash_eraseall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
52 int flash_eraseall_main(int argc, char **argv)
53 {
54         struct jffs2_unknown_node cleanmarker;
55         mtd_info_t meminfo;
56         int fd, clmpos = 0, clmlen = 8;
57         erase_info_t erase;
58         struct stat st;
59         int isNAND, bbtest = 1;
60         unsigned int flags;
61         char *mtd_name;
62
63         opt_complementary = "=1";
64         flags = getopt32(argv, "jq");
65
66         mtd_name = *(argv + optind);
67         xstat(mtd_name, &st);
68         if (!S_ISCHR(st.st_mode))
69                 bb_error_msg_and_die("%s: not a char device", mtd_name);
70
71         fd = xopen(mtd_name, O_RDWR);
72
73         xioctl(fd, MEMGETINFO, &meminfo);
74
75         erase.length = meminfo.erasesize;
76         isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0;
77
78         if (flags & OPTION_J) {
79                 uint32_t *crc32_table;
80
81                 crc32_table = crc32_filltable(NULL, 0);
82
83                 cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
84                 cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
85                 if (!isNAND)
86                         cleanmarker.totlen = cpu_to_je32 (sizeof (struct jffs2_unknown_node));
87                 else {
88                         struct nand_oobinfo oobinfo;
89
90                         xioctl(fd, MEMGETOOBSEL, &oobinfo);
91
92                         /* Check for autoplacement */
93                         if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
94                                 /* Get the position of the free bytes */
95                                 if (!oobinfo.oobfree[0][1])
96                                         bb_error_msg_and_die("Autoplacement selected and no empty space in oob");
97
98                                 clmpos = oobinfo.oobfree[0][0];
99                                 clmlen = oobinfo.oobfree[0][1];
100                                 if (clmlen > 8)
101                                         clmlen = 8;
102                         } else {
103                                 /* Legacy mode */
104                                 switch (meminfo.oobsize) {
105                                 case 8:
106                                         clmpos = 6;
107                                         clmlen = 2;
108                                         break;
109                                 case 16:
110                                         clmpos = 8;
111                                         clmlen = 8;
112                                         break;
113                                 case 64:
114                                         clmpos = 16;
115                                         clmlen = 8;
116                                         break;
117                                 }
118                         }
119                         cleanmarker.totlen = cpu_to_je32(8);
120                 }
121
122                 cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker,  sizeof(struct jffs2_unknown_node) - 4,
123                                         crc32_table));
124         }
125
126         for (erase.start = 0; erase.start < meminfo.size;
127              erase.start += meminfo.erasesize) {
128                 if (bbtest) {
129                         int ret;
130
131                         loff_t offset = erase.start;
132                         ret = ioctl(fd, MEMGETBADBLOCK, &offset);
133                         if (ret > 0) {
134                                 if (!(flags & OPTION_Q))
135                                         bb_info_msg("\nSkipping bad block at 0x%08x", erase.start);
136                                 continue;
137                         } else if (ret < 0) {
138                                 /* Black block table is not available on certain flash
139                                  * types e.g. NOR
140                                  */
141                                 if (errno == EOPNOTSUPP) {
142                                         bbtest = 0;
143                                         if (isNAND)
144                                                 bb_error_msg_and_die("%s: Bad block check not available",
145                                                                 mtd_name);
146                                 } else {
147                                         bb_error_msg_and_die("\n%s: MTD get bad block failed: %s",
148                                                         mtd_name, strerror(errno));
149                                 }
150                         }
151                 }
152
153                 if (!(flags & OPTION_Q))
154                         show_progress(&meminfo, &erase);
155
156                 xioctl(fd, MEMERASE, &erase);
157
158                 /* format for JFFS2 ? */
159                 if (!(flags & OPTION_J))
160                         continue;
161
162                 /* write cleanmarker */
163                 if (isNAND) {
164                         struct mtd_oob_buf oob;
165                         oob.ptr = (unsigned char *) &cleanmarker;
166                         oob.start = erase.start + clmpos;
167                         oob.length = clmlen;
168                         xioctl (fd, MEMWRITEOOB, &oob);
169                 } else {
170                         if (lseek (fd, erase.start, SEEK_SET) < 0) {
171                                 bb_error_msg("\n%s: MTD lseek failure: %s", mtd_name, strerror(errno));
172                                 continue;
173                         }
174                         if (write (fd , &cleanmarker, sizeof (cleanmarker)) != sizeof (cleanmarker)) {
175                                 bb_error_msg("\n%s: MTD write failure: %s", mtd_name, strerror(errno));
176                                 continue;
177                         }
178                 }
179                 if (!(flags & OPTION_Q))
180                         printf(" Cleanmarker written at %x.", erase.start);
181         }
182         if (!(flags & OPTION_Q)) {
183                 show_progress(&meminfo, &erase);
184                 printf("\n");
185         }
186
187         return EXIT_SUCCESS;
188 }