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