flashctl.c revision 1.2 1 /* $NetBSD: flashctl.c,v 1.2 2011/03/20 06:10:27 ahoka 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 exit(1);
63 }
64
65 device = argv[1];
66 command = argv[2];
67 argc -= 3;
68 argv += 3;
69
70 fd = open(device, O_RDWR, 0);
71 if (fd == -1) {
72 err(EXIT_FAILURE, "can't open flash device");
73 }
74
75 if (!strcmp("erase", command)) {
76 struct flash_info_params ip;
77 struct flash_erase_params ep;
78
79 error = ioctl(fd, FLASH_GET_INFO, &ip);
80 if (error) {
81 warn("ioctl: FLASH_GET_INFO");
82 goto out;
83 }
84
85 if (argc == 2) {
86 error = to_intmax(&n, argv[0]);
87 if (error) {
88 warnx(strerror(error));
89 goto out;
90 }
91 ep.ep_addr = n;
92
93 if (!strcmp("all", argv[1])) {
94 ep.ep_len = ip.ip_flash_size;
95 } else {
96 error = to_intmax(&n, argv[1]);
97 if (error) {
98 warnx(strerror(error));
99 goto out;
100 }
101 ep.ep_len = n;
102 }
103 } else {
104 warnx("invalid number of arguments");
105 error = 1;
106 goto out;
107 }
108
109 printf("Erasing %jx bytes starting from %jx\n",
110 (uintmax_t )ep.ep_len, (uintmax_t )ep.ep_addr);
111
112 error = ioctl(fd, FLASH_ERASE_BLOCK, &ep);
113 if (error) {
114 warn("ioctl: FLASH_ERASE_BLOCK");
115 goto out;
116 }
117 } else if (!strcmp("identify", command)) {
118 struct flash_info_params ip;
119
120 error = ioctl(fd, FLASH_GET_INFO, &ip);
121 if (error) {
122 warn("ioctl: FLASH_GET_INFO");
123 goto out;
124 }
125
126 printf("Device type: ");
127 switch (ip.ip_flash_type) {
128 case FLASH_TYPE_NOR:
129 printf("NOR flash");
130 break;
131 case FLASH_TYPE_NAND:
132 printf("NAND flash");
133 break;
134 default:
135 printf("unknown (%d)", ip.ip_flash_type);
136 }
137 printf("\n");
138
139 /* TODO: humanize */
140 printf("Capacity %jd Mbytes, %jd pages, %zu bytes/page\n",
141 (intmax_t )ip.ip_flash_size / 1024 / 1024,
142 (intmax_t )ip.ip_flash_size / ip.ip_page_size,
143 ip.ip_page_size);
144
145 if (ip.ip_flash_type == FLASH_TYPE_NAND) {
146 printf("Block size %jd Kbytes, %jd pages/block\n",
147 (intmax_t )ip.ip_erase_size / 1024,
148 (intmax_t )ip.ip_erase_size / ip.ip_page_size);
149 }
150 } else if (!strcmp("badblocks", command)) {
151 struct flash_info_params ip;
152 struct flash_badblock_params bbp;
153 flash_addr_t addr;
154 bool hasbad = false;
155
156 error = ioctl(fd, FLASH_GET_INFO, &ip);
157 if (error) {
158 warn("ioctl: FLASH_GET_INFO");
159 goto out;
160 }
161
162 printf("Scanning for bad blocks: ");
163
164 addr = 0;
165 while (addr < ip.ip_flash_size) {
166 bbp.bbp_addr = addr;
167
168 error = ioctl(fd, FLASH_BLOCK_ISBAD, &bbp);
169 if (error) {
170 warn("ioctl: FLASH_BLOCK_ISBAD");
171 goto out;
172 }
173
174 if (bbp.bbp_isbad) {
175 hasbad = true;
176 printf("0x%jx ", addr);
177 }
178
179 addr += ip.ip_erase_size;
180 }
181
182 if (hasbad) {
183 printf("Done.\n");
184 } else {
185 printf("No bad blocks found.\n");
186 }
187 } else if (!strcmp("markbad", command)) {
188 flash_addr_t address;
189
190 /* TODO: maybe we should let the user specify
191 * multiple blocks?
192 */
193 if (argc != 1) {
194 warnx("invalid number of arguments");
195 error = 1;
196 goto out;
197 }
198
199 error = to_intmax(&n, argv[0]);
200 if (error) {
201 warnx(strerror(error));
202 goto out;
203 }
204
205 address = n;
206
207 printf("Marking block 0x%jx as bad.\n",
208 (intmax_t )address);
209
210 error = ioctl(fd, FLASH_BLOCK_MARKBAD, &address);
211 if (error) {
212 warn("ioctl: FLASH_BLOCK_MARKBAD");
213 goto out;
214 }
215 } else {
216 warnx("Unknown command");
217 error = 1;
218 goto out;
219 }
220
221 out:
222 close(fd);
223 return error;
224 }
225
226 int
227 to_intmax(intmax_t *num, const char *str)
228 {
229 char *endptr;
230
231 errno = 0;
232 if (str[0] == '0' && tolower((int )str[1]) == 'x') {
233 if (!isxdigit((int )str[0]))
234 return EINVAL;
235 *num = strtoimax(str, &endptr, 16);
236 } else {
237 if (!isdigit((int )str[0]))
238 return EINVAL;
239 *num = strtoimax(str, &endptr, 10);
240 }
241
242 if (errno == ERANGE && (*num == INTMAX_MIN || *num == INTMAX_MAX)) {
243 return ERANGE;
244 }
245
246 return 0;
247 }
248
249 void
250 usage(void)
251 {
252 fprintf(stderr, "usage: %s device identify\n",
253 getprogname());
254 fprintf(stderr, " %s device erase <start address> <size>|all\n",
255 getprogname());
256 fprintf(stderr, " %s device badblocks\n",
257 getprogname());
258 fprintf(stderr, " %s device markbad <address>\n",
259 getprogname());
260 }
261