1 /* $NetBSD: flashctl.c,v 1.4 2011/05/24 13:01:53 joerg Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 Department of Software Engineering, 5 * University of Szeged, Hungary 6 * Copyright (c) 2010 Adam Hoka <ahoka@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("%s", 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("%s", 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, %ju bytes/page\n", 141 (intmax_t )ip.ip_flash_size / 1024 / 1024, 142 (intmax_t )ip.ip_flash_size / ip.ip_page_size, 143 (intmax_t )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_off_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_off_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("%s", 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