flashctl.c revision 1.1.2.2 1 /* $NetBSD: flashctl.c,v 1.1.2.2 2011/03/05 15:11:02 bouyer Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (c) 2010 Adam Hoka <ahoka (at) NetBSD.org>
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by the Department of Software Engineering, University of Szeged, Hungary
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/ioctl.h>
35 #include <sys/flashio.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <err.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <limits.h>
43 #include <inttypes.h>
44 #include <ctype.h>
45 #include <errno.h>
46
47
48 void usage(void);
49 int to_intmax(intmax_t *, const char *);
50
51 int
52 main(int argc, char **argv)
53 {
54 char *device, *command;
55 int fd, error = 0;
56 intmax_t n = -1;
57
58 setprogname(argv[0]);
59
60 if (argc < 3)
61 usage();
62
63 device = argv[1];
64 command = argv[2];
65 argc -= 3;
66 argv += 3;
67
68 fd = open(device, O_RDWR, 0);
69 if (fd == -1)
70 err(EXIT_FAILURE, "can't open flash device");
71
72 if (!strcmp("erase", command)) {
73 struct flash_info_params ip;
74 struct flash_erase_params ep;
75
76 error = ioctl(fd, FLASH_GET_INFO, &ip);
77 if (error) {
78 warn("ioctl: FLASH_GET_INFO");
79 goto out;
80 }
81
82 if (argc == 2) {
83 error = to_intmax(&n, argv[0]);
84 if (error) {
85 warnx(strerror(error));
86 goto out;
87 }
88 ep.ep_addr = n;
89
90 if (!strcmp("all", argv[1])) {
91 ep.ep_len = ip.ip_flash_size;
92 } else {
93 error = to_intmax(&n, argv[1]);
94 if (error) {
95 warnx(strerror(error));
96 goto out;
97 }
98 ep.ep_len = n;
99 }
100 } else {
101 warnx("invalid number of arguments");
102 error = 1;
103 goto out;
104 }
105
106 printf("Erasing %jx bytes starting from %jx\n",
107 (uintmax_t )ep.ep_len, (uintmax_t )ep.ep_addr);
108
109 error = ioctl(fd, FLASH_ERASE_BLOCK, &ep);
110 if (error) {
111 warn("ioctl: FLASH_ERASE_BLOCK");
112 goto out;
113 }
114 } else if (!strcmp("identify", command)) {
115 struct flash_info_params ip;
116
117 error = ioctl(fd, FLASH_GET_INFO, &ip);
118 if (error) {
119 warn("ioctl: FLASH_GET_INFO");
120 goto out;
121 }
122
123 printf("Device type: ");
124 switch (ip.ip_flash_type) {
125 case FLASH_TYPE_NOR:
126 printf("NOR flash");
127 break;
128 case FLASH_TYPE_NAND:
129 printf("NAND flash");
130 break;
131 default:
132 printf("unknown (%d)", ip.ip_flash_type);
133 }
134 printf("\n");
135
136 /* TODO: humanize */
137 printf("Capacity %jd Mbytes, %jd pages, %zu bytes/page\n",
138 (intmax_t )ip.ip_flash_size / 1024 / 1024,
139 (intmax_t )ip.ip_flash_size / ip.ip_page_size,
140 ip.ip_page_size);
141
142 if (ip.ip_flash_type == FLASH_TYPE_NAND) {
143 printf("Block size %jd Kbytes, %jd pages/block\n",
144 (intmax_t )ip.ip_erase_size / 1024,
145 (intmax_t )ip.ip_erase_size / ip.ip_page_size);
146 }
147 } else if (!strcmp("badblocks", command)) {
148 struct flash_info_params ip;
149 struct flash_badblock_params bbp;
150 flash_addr_t addr;
151 bool hasbad = false;
152
153 error = ioctl(fd, FLASH_GET_INFO, &ip);
154 if (error) {
155 warn("ioctl: FLASH_GET_INFO");
156 goto out;
157 }
158
159 printf("Scanning for bad blocks: ");
160
161 addr = 0;
162 while (addr < ip.ip_flash_size) {
163 bbp.bbp_addr = addr;
164
165 error = ioctl(fd, FLASH_BLOCK_ISBAD, &bbp);
166 if (error) {
167 warn("ioctl: FLASH_BLOCK_ISBAD");
168 goto out;
169 }
170
171 if (bbp.bbp_isbad) {
172 hasbad = true;
173 printf("0x%jx ", addr);
174 }
175
176 addr += ip.ip_erase_size;
177 }
178
179 if (hasbad)
180 printf("Done.\n");
181 else
182 printf("No bad blocks found.\n");
183 } else if (!strcmp("markbad", command)) {
184 flash_addr_t address;
185
186 error = to_intmax(&n, argv[1]);
187 if (error) {
188 warnx(strerror(error));
189 goto out;
190 }
191
192 address = n;
193
194 printf("Marking block 0x%jx as bad.\n",
195 (intmax_t )address);
196
197 error = ioctl(fd, FLASH_BLOCK_MARKBAD, &address);
198 if (error) {
199 warn("ioctl: FLASH_BLOCK_MARKBAD");
200 goto out;
201 }
202 } else {
203 warnx("Unknown command");
204 error = 1;
205 goto out;
206 }
207
208 out:
209 close(fd);
210 return error;
211 }
212
213 int
214 to_intmax(intmax_t *num, const char *str)
215 {
216 char *endptr;
217
218 errno = 0;
219 if (str[0] == '0' && tolower((int )str[1]) == 'x') {
220 if (!isxdigit((int )str[0]))
221 return EINVAL;
222 *num = strtoimax(str, &endptr, 16);
223 } else {
224 if (!isdigit((int )str[0]))
225 return EINVAL;
226 *num = strtoimax(str, &endptr, 10);
227 }
228
229 if (errno == ERANGE && (*num == INTMAX_MIN || *num == INTMAX_MAX)) {
230 return ERANGE;
231 }
232
233 return 0;
234 }
235
236 void
237 usage(void)
238 {
239 fprintf(stderr, "usage: %s device identify\n",
240 getprogname());
241 fprintf(stderr, " %s device erase <start address> <size>|all\n",
242 getprogname());
243 fprintf(stderr, " %s device badblocks\n",
244 getprogname());
245 fprintf(stderr, " %s device markbad <address>\n",
246 getprogname());
247
248 exit(1);
249 }
250