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