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