Home | History | Annotate | Line # | Download | only in flashctl
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