xref: /openbsd/sbin/bioctl/bioctl.c (revision 2b5fc845)
1*2b5fc845Sjsing /* $OpenBSD: bioctl.c,v 1.104 2011/12/31 17:06:09 jsing Exp $       */
2cf6503d7Sderaadt 
33af9de98Smarco /*
42f39728eSdlg  * Copyright (c) 2004, 2005 Marco Peereboom
53af9de98Smarco  * All rights reserved.
63af9de98Smarco  *
73af9de98Smarco  * Redistribution and use in source and binary forms, with or without
83af9de98Smarco  * modification, are permitted provided that the following conditions
93af9de98Smarco  * are met:
103af9de98Smarco  * 1. Redistributions of source code must retain the above copyright
113af9de98Smarco  *    notice, this list of conditions and the following disclaimer.
123af9de98Smarco  * 2. Redistributions in binary form must reproduce the above copyright
133af9de98Smarco  *    notice, this list of conditions and the following disclaimer in the
143af9de98Smarco  *    documentation and/or other materials provided with the distribution.
153af9de98Smarco  *
163af9de98Smarco  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
173af9de98Smarco  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183af9de98Smarco  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193af9de98Smarco  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
203af9de98Smarco  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213af9de98Smarco  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223af9de98Smarco  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233af9de98Smarco  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243af9de98Smarco  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253af9de98Smarco  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263af9de98Smarco  * SUCH DAMAGE.
273af9de98Smarco  *
283af9de98Smarco  */
293af9de98Smarco 
30c2126c9aSmarco #include <sys/ioctl.h>
3191f4f7d8Sdlg #include <sys/dkio.h>
32c2126c9aSmarco #include <sys/param.h>
3346bc198bSmarco #include <sys/types.h>
3446bc198bSmarco #include <sys/stat.h>
353af9de98Smarco #include <dev/biovar.h>
36aef7fe28Shshoexer #include <dev/softraidvar.h>
373af9de98Smarco 
38db2730c1Smarco #include <errno.h>
39db2730c1Smarco #include <err.h>
40db2730c1Smarco #include <fcntl.h>
418ccdd032Sderaadt #include <util.h>
42db2730c1Smarco #include <stdio.h>
43db2730c1Smarco #include <stdlib.h>
44db2730c1Smarco #include <string.h>
45db2730c1Smarco #include <unistd.h>
46e4e14ad7Sderaadt #include <ctype.h>
4703b2dfbfShenning #include <vis.h>
489e8c6f5bShshoexer #include <readpassphrase.h>
49db2730c1Smarco 
505c1f8f6bSdjm #include "pbkdf2.h"
51aef7fe28Shshoexer 
526de960dcSmarco struct locator {
536de960dcSmarco 	int		channel;
546de960dcSmarco 	int		target;
556de960dcSmarco 	int		lun;
566de960dcSmarco };
576de960dcSmarco 
588ccdd032Sderaadt void			usage(void);
5941eccc89Sderaadt const char 		*str2locator(const char *, struct locator *);
608ccdd032Sderaadt void			cleanup(void);
6146bc198bSmarco int			bio_parse_devlist(char *, dev_t *);
62aef7fe28Shshoexer void			bio_kdf_derive(struct sr_crypto_kdfinfo *,
63c6446370Sjsing 			    struct sr_crypto_kdf_pbkdf2 *, char *, int);
64aef7fe28Shshoexer void			bio_kdf_generate(struct sr_crypto_kdfinfo *);
659e8c6f5bShshoexer void			derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *,
66c6446370Sjsing 			    size_t, char *, int);
678ccdd032Sderaadt 
688ccdd032Sderaadt void			bio_inq(char *);
698ccdd032Sderaadt void			bio_alarm(char *);
70a15048bbSmarco int			bio_getvolbyname(char *);
71a15048bbSmarco void			bio_setstate(char *, int, char *);
72a928c459Sderaadt void			bio_setblink(char *, char *, int);
73a928c459Sderaadt void			bio_blink(char *, int, int);
74d4722c44Snicm struct sr_aoe_config 	*create_aoe(u_int16_t, char *);
750054cd36Sjsing void			bio_createraid(u_int16_t, char *, char *);
76c7c3e8aaSmarco void			bio_deleteraid(char *);
77c6446370Sjsing void			bio_changepass(char *);
78e8a57fdeSmarco u_int32_t		bio_createflags(char *);
7903b2dfbfShenning char			*bio_vis(char *);
8003b2dfbfShenning void			bio_diskinq(char *);
813af9de98Smarco 
823af9de98Smarco int			devh = -1;
83abe9d68eSderaadt int			human;
84abe9d68eSderaadt int			verbose;
85e8a57fdeSmarco u_int32_t		cflags = 0;
86aedd4f07Sdjm int			rflag = 8192;
8786735da2Smarco char			*password;
883af9de98Smarco 
893af9de98Smarco struct bio_locate	bl;
90b96c6ce2Sckuethe int rpp_flag = RPP_REQUIRE_TTY;
913af9de98Smarco 
923af9de98Smarco int
933af9de98Smarco main(int argc, char *argv[])
943af9de98Smarco {
953af9de98Smarco 	extern char		*optarg;
96db2730c1Smarco 	u_int64_t		func = 0;
97db2730c1Smarco 	/* u_int64_t subfunc = 0; */
98e63d8b1dSdtucker 	char			*devicename = NULL;
99cf6503d7Sderaadt 	char			*realname = NULL, *al_arg = NULL;
1007195049bSmarco 	char			*bl_arg = NULL, *dev_list = NULL;
1010054cd36Sjsing 	char			*key_disk = NULL;
102aedd4f07Sdjm 	const char		*errstr;
103c6446370Sjsing 	int			ch, rv, blink = 0, changepass = 0, diskinq = 0;
104c6446370Sjsing 	int			ss_func = 0;
1059ecba717Sderaadt 	u_int16_t		cr_level = 0;
106e37c64dbSjsing 	int			biodev = 0;
1073af9de98Smarco 
1083af9de98Smarco 	if (argc < 2)
1093af9de98Smarco 		usage();
1103af9de98Smarco 
111b96c6ce2Sckuethe 	while ((ch = getopt(argc, argv, "a:b:C:c:dH:hik:l:Pp:qr:R:svu:")) !=
112c6446370Sjsing 	    -1) {
1133af9de98Smarco 		switch (ch) {
114edfd9792Smarco 		case 'a': /* alarm */
115edfd9792Smarco 			func |= BIOC_ALARM;
116edfd9792Smarco 			al_arg = optarg;
117edfd9792Smarco 			break;
118c55617f1Sdlg 		case 'b': /* blink */
119c55617f1Sdlg 			func |= BIOC_BLINK;
120a928c459Sderaadt 			blink = BIOC_SBBLINK;
121a928c459Sderaadt 			bl_arg = optarg;
122a928c459Sderaadt 			break;
123e8a57fdeSmarco 		case 'C': /* creation flags */
124e8a57fdeSmarco 			cflags = bio_createflags(optarg);
125e8a57fdeSmarco 			break;
1267195049bSmarco 		case 'c': /* create */
1277195049bSmarco 			func |= BIOC_CREATERAID;
12892d21b5cStedu 			if (isdigit(*optarg)) {
12992d21b5cStedu 				cr_level = strtonum(optarg, 0, 10, &errstr);
13092d21b5cStedu 				if (errstr != NULL)
13192d21b5cStedu 					errx(1, "Invalid RAID level");
13292d21b5cStedu 			} else
13398b750e4Stedu 				cr_level = *optarg;
1347195049bSmarco 			break;
135c7c3e8aaSmarco 		case 'd':
136c7c3e8aaSmarco 			/* delete volume */
137c7c3e8aaSmarco 			func |= BIOC_DELETERAID;
138c7c3e8aaSmarco 			break;
139a928c459Sderaadt 		case 'u': /* unblink */
140a928c459Sderaadt 			func |= BIOC_BLINK;
141a928c459Sderaadt 			blink = BIOC_SBUNBLINK;
142c55617f1Sdlg 			bl_arg = optarg;
143c55617f1Sdlg 			break;
1446de960dcSmarco 		case 'H': /* set hotspare */
1456de960dcSmarco 			func |= BIOC_SETSTATE;
146a15048bbSmarco 			ss_func = BIOC_SSHOTSPARE;
1476de960dcSmarco 			al_arg = optarg;
1486de960dcSmarco 			break;
1498ccdd032Sderaadt 		case 'h':
1508ccdd032Sderaadt 			human = 1;
1518ccdd032Sderaadt 			break;
152db2730c1Smarco 		case 'i': /* inquiry */
153db2730c1Smarco 			func |= BIOC_INQ;
1543af9de98Smarco 			break;
1550054cd36Sjsing 		case 'k': /* Key disk. */
1560054cd36Sjsing 			key_disk = optarg;
1570054cd36Sjsing 			break;
1587195049bSmarco 		case 'l': /* device list */
1597195049bSmarco 			func |= BIOC_DEVLIST;
1607195049bSmarco 			dev_list = optarg;
1617195049bSmarco 			break;
162c6446370Sjsing 		case 'P':
163c6446370Sjsing 			/* Change passphrase. */
164c6446370Sjsing 			changepass = 1;
165c6446370Sjsing 			break;
16686735da2Smarco 		case 'p':
16786735da2Smarco 			password = optarg;
16886735da2Smarco 			break;
169aedd4f07Sdjm 		case 'r':
170aedd4f07Sdjm 			rflag = strtonum(optarg, 1000, 1<<30, &errstr);
171aedd4f07Sdjm 			if (errstr != NULL)
172aedd4f07Sdjm 				errx(1, "Number of rounds is %s: %s",
173aedd4f07Sdjm 				    errstr, optarg);
174aedd4f07Sdjm 			break;
175a15048bbSmarco 		case 'R':
176a15048bbSmarco 			/* rebuild to provided chunk/CTL */
177a15048bbSmarco 			func |= BIOC_SETSTATE;
178a15048bbSmarco 			ss_func = BIOC_SSREBUILD;
179a15048bbSmarco 			al_arg = optarg;
180a15048bbSmarco 			break;
181b96c6ce2Sckuethe 		case 's':
182b96c6ce2Sckuethe 			rpp_flag = RPP_STDIN;
183b96c6ce2Sckuethe 			break;
184abe9d68eSderaadt 		case 'v':
185abe9d68eSderaadt 			verbose = 1;
186abe9d68eSderaadt 			break;
18703b2dfbfShenning 		case 'q':
18803b2dfbfShenning 			diskinq = 1;
18903b2dfbfShenning 			break;
1903af9de98Smarco 		default:
1913af9de98Smarco 			usage();
1923af9de98Smarco 			/* NOTREACHED */
1933af9de98Smarco 		}
1943af9de98Smarco 	}
195cf6503d7Sderaadt 	argc -= optind;
196cf6503d7Sderaadt 	argv += optind;
1973af9de98Smarco 
198c6446370Sjsing 	if (argc != 1 || (changepass && func != 0))
199cf6503d7Sderaadt 		usage();
200cf6503d7Sderaadt 
201dcbaf4c8Sderaadt 	if (func == 0)
202dcbaf4c8Sderaadt 		func |= BIOC_INQ;
203dcbaf4c8Sderaadt 
204e63d8b1dSdtucker 	devicename = argv[0];
205e63d8b1dSdtucker 	if (devicename == NULL)
206e37c64dbSjsing 		errx(1, "need device");
20710b411a7Smarco 
208e63d8b1dSdtucker 	devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname);
209e37c64dbSjsing 	if (devh == -1) {
21041eccc89Sderaadt 		devh = open("/dev/bio", O_RDWR);
2113af9de98Smarco 		if (devh == -1)
21241eccc89Sderaadt 			err(1, "Can't open %s", "/dev/bio");
2133af9de98Smarco 
214e63d8b1dSdtucker 		bl.bl_name = devicename;
2153af9de98Smarco 		rv = ioctl(devh, BIOCLOCATE, &bl);
2163af9de98Smarco 		if (rv == -1)
21710b411a7Smarco 			errx(1, "Can't locate %s device via %s",
21841eccc89Sderaadt 			    bl.bl_name, "/dev/bio");
219e37c64dbSjsing 		biodev = 1;
220e63d8b1dSdtucker 		devicename = NULL;
221e37c64dbSjsing 	}
2223af9de98Smarco 
22303b2dfbfShenning 	if (diskinq) {
224e63d8b1dSdtucker 		bio_diskinq(devicename);
225e37c64dbSjsing 	} else if (changepass && !biodev) {
226e63d8b1dSdtucker 		bio_changepass(devicename);
22703b2dfbfShenning 	} else if (func & BIOC_INQ) {
228e63d8b1dSdtucker 		bio_inq(devicename);
229edfd9792Smarco 	} else if (func == BIOC_ALARM) {
230edfd9792Smarco 		bio_alarm(al_arg);
231c55617f1Sdlg 	} else if (func == BIOC_BLINK) {
232e63d8b1dSdtucker 		bio_setblink(devicename, bl_arg, blink);
2336de960dcSmarco 	} else if (func == BIOC_SETSTATE) {
234a15048bbSmarco 		bio_setstate(al_arg, ss_func, argv[0]);
235e37c64dbSjsing 	} else if (func == BIOC_DELETERAID && !biodev) {
236e63d8b1dSdtucker 		bio_deleteraid(devicename);
2377195049bSmarco 	} else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
2387195049bSmarco 		if (!(func & BIOC_CREATERAID))
2397195049bSmarco 			errx(1, "need -c parameter");
2407195049bSmarco 		if (!(func & BIOC_DEVLIST))
2417195049bSmarco 			errx(1, "need -l parameter");
242e37c64dbSjsing 		if (!biodev)
243e37c64dbSjsing 			errx(1, "must use bio device");
2440054cd36Sjsing 		bio_createraid(cr_level, dev_list, key_disk);
2453af9de98Smarco 	}
2463af9de98Smarco 
2473af9de98Smarco 	return (0);
2483af9de98Smarco }
2493af9de98Smarco 
2503af9de98Smarco void
2513af9de98Smarco usage(void)
2523af9de98Smarco {
2533af9de98Smarco 	extern char		*__progname;
2543af9de98Smarco 
255d90b5d8bSjmc 	fprintf(stderr,
256d0b772c8Sjmc 		"usage: %s [-hiqv] [-a alarm-function] "
257d90b5d8bSjmc 		"[-b channel:target[.lun]]\n"
258d0b772c8Sjmc 		"\t[-H channel:target[.lun]] "
259af56bbe7Smatthieu 		"[-R device | channel:target[.lun]]\n"
260d0b772c8Sjmc 		"\t[-u channel:target[.lun]] "
261d0b772c8Sjmc 		"device\n"
262b96c6ce2Sckuethe 		"       %s [-dhiPqsv] "
263b90fdff5Sjmc 		"[-C flag[,flag,...]] [-c raidlevel] [-k keydisk]\n"
26478702060Sjmc 		"\t[-l special[,special,...]] [-p passfile]\n"
265af56bbe7Smatthieu 		"\t[-R device | channel:target[.lun]] [-r rounds] "
266d0b772c8Sjmc 		"device\n", __progname, __progname);
267d90b5d8bSjmc 
2683af9de98Smarco 	exit(1);
2693af9de98Smarco }
2703af9de98Smarco 
27141eccc89Sderaadt const char *
2726de960dcSmarco str2locator(const char *string, struct locator *location)
2736de960dcSmarco {
27450d3c4dcSdlg 	const char		*errstr;
27541eccc89Sderaadt 	char			parse[80], *targ, *lun;
2766de960dcSmarco 
27741eccc89Sderaadt 	strlcpy(parse, string, sizeof parse);
27841eccc89Sderaadt 	targ = strchr(parse, ':');
2796de960dcSmarco 	if (targ == NULL)
28041eccc89Sderaadt 		return ("target not specified");
2816de960dcSmarco 	*targ++ = '\0';
2826de960dcSmarco 
28350d3c4dcSdlg 	lun = strchr(targ, '.');
2846de960dcSmarco 	if (lun != NULL) {
2856de960dcSmarco 		*lun++ = '\0';
28650d3c4dcSdlg 		location->lun = strtonum(lun, 0, 256, &errstr);
28750d3c4dcSdlg 		if (errstr)
28841eccc89Sderaadt 			return (errstr);
2896de960dcSmarco 	} else
2906de960dcSmarco 		location->lun = 0;
2916de960dcSmarco 
29250d3c4dcSdlg 	location->target = strtonum(targ, 0, 256, &errstr);
29350d3c4dcSdlg 	if (errstr)
29441eccc89Sderaadt 		return (errstr);
29541eccc89Sderaadt 	location->channel = strtonum(parse, 0, 256, &errstr);
29650d3c4dcSdlg 	if (errstr)
29741eccc89Sderaadt 		return (errstr);
29841eccc89Sderaadt 	return (NULL);
2996de960dcSmarco }
3006de960dcSmarco 
3013af9de98Smarco void
3028ccdd032Sderaadt bio_inq(char *name)
303d4546a56Sdlg {
3049017fb97Sderaadt 	char 			*status, size[64], scsiname[16], volname[32];
305a4d3c4a2Sderaadt 	char			percent[10], seconds[20];
306b9950701Smarco 	int			rv, i, d, volheader, hotspare, unused;
307aa65acf1Sderaadt 	char			encname[16], serial[32];
3088ccdd032Sderaadt 	struct bioc_disk	bd;
3098ccdd032Sderaadt 	struct bioc_inq		bi;
3108ccdd032Sderaadt 	struct bioc_vol		bv;
311db2730c1Smarco 
312db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
3133af9de98Smarco 
3148ccdd032Sderaadt 	bi.bi_cookie = bl.bl_cookie;
3153af9de98Smarco 
316db2730c1Smarco 	rv = ioctl(devh, BIOCINQ, &bi);
3173af9de98Smarco 	if (rv == -1) {
31803b2dfbfShenning 		if (errno == ENOTTY)
31903b2dfbfShenning 			bio_diskinq(name);
32003b2dfbfShenning 		else
321da3b0664Shenning 			err(1, "BIOCINQ");
3223af9de98Smarco 		return;
3233af9de98Smarco 	}
3243af9de98Smarco 
3258ccdd032Sderaadt 	volheader = 0;
3268ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
327db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
3288ccdd032Sderaadt 		bv.bv_cookie = bl.bl_cookie;
3298ccdd032Sderaadt 		bv.bv_volid = i;
3300a92ff65Sderaadt 		bv.bv_percent = -1;
3319017fb97Sderaadt 		bv.bv_seconds = 0;
33270a2ae7bSmarco 
333db2730c1Smarco 		rv = ioctl(devh, BIOCVOL, &bv);
334da3b0664Shenning 		if (rv == -1)
335da3b0664Shenning 			err(1, "BIOCVOL");
3363af9de98Smarco 
3378ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
3388ccdd032Sderaadt 			continue;
3398ccdd032Sderaadt 
3408ccdd032Sderaadt 		if (!volheader) {
3418ccdd032Sderaadt 			volheader = 1;
342150c22bbSjcs 			printf("%-11s %-10s %14s %-8s\n",
3438ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
3448ccdd032Sderaadt 		}
3458ccdd032Sderaadt 
3460a92ff65Sderaadt 		percent[0] = '\0';
3479017fb97Sderaadt 		seconds[0] = '\0';
3480a92ff65Sderaadt 		if (bv.bv_percent != -1)
3490a92ff65Sderaadt 			snprintf(percent, sizeof percent,
3500a92ff65Sderaadt 			    " %d%% done", bv.bv_percent);
3519017fb97Sderaadt 		if (bv.bv_seconds)
3529017fb97Sderaadt 			snprintf(seconds, sizeof seconds,
3539017fb97Sderaadt 			    " %u seconds", bv.bv_seconds);
3548ccdd032Sderaadt 		switch (bv.bv_status) {
355db2730c1Smarco 		case BIOC_SVONLINE:
3568ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
357db2730c1Smarco 			break;
358db2730c1Smarco 		case BIOC_SVOFFLINE:
3598ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
360db2730c1Smarco 			break;
361db2730c1Smarco 		case BIOC_SVDEGRADED:
3628ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
363db2730c1Smarco 			break;
3640a92ff65Sderaadt 		case BIOC_SVBUILDING:
3650a92ff65Sderaadt 			status = BIOC_SVBUILDING_S;
3660a92ff65Sderaadt 			break;
3670a92ff65Sderaadt 		case BIOC_SVREBUILD:
3680a92ff65Sderaadt 			status = BIOC_SVREBUILD_S;
3690a92ff65Sderaadt 			break;
3700a92ff65Sderaadt 		case BIOC_SVSCRUB:
3710a92ff65Sderaadt 			status = BIOC_SVSCRUB_S;
3720a92ff65Sderaadt 			break;
373db2730c1Smarco 		case BIOC_SVINVALID:
374db2730c1Smarco 		default:
3758ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
376d4546a56Sdlg 		}
3773af9de98Smarco 
378aa65acf1Sderaadt 		snprintf(volname, sizeof volname, "%s %u",
3798ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
380b9950701Smarco 
3819ecba717Sderaadt 		unused = 0;
3829ecba717Sderaadt 		hotspare = 0;
383aa65acf1Sderaadt 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
384aa65acf1Sderaadt 			hotspare = 1;
385b9950701Smarco 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
386b9950701Smarco 			unused = 1;
387aa65acf1Sderaadt 		else {
3888ccdd032Sderaadt 			if (human)
3898ccdd032Sderaadt 				fmt_scaled(bv.bv_size, size);
3908ccdd032Sderaadt 			else
3918ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
3928ccdd032Sderaadt 				    bv.bv_size);
393da935596Stodd 			switch (bv.bv_level) {
394da935596Stodd 			case 'C':
395150c22bbSjcs 				printf("%11s %-10s %14s %-7s CRYPTO%s%s\n",
396da935596Stodd 				    volname, status, size, bv.bv_dev,
397da935596Stodd 				    percent, seconds);
398da935596Stodd 				break;
399*2b5fc845Sjsing 			case 'c':
400*2b5fc845Sjsing 				printf("%11s %-10s %14s %-7s CONCAT%s%s\n",
401*2b5fc845Sjsing 				    volname, status, size, bv.bv_dev,
402*2b5fc845Sjsing 				    percent, seconds);
403*2b5fc845Sjsing 				break;
404da935596Stodd 			default:
405150c22bbSjcs 				printf("%11s %-10s %14s %-7s RAID%u%s%s\n",
4060a92ff65Sderaadt 				    volname, status, size, bv.bv_dev,
4079017fb97Sderaadt 				    bv.bv_level, percent, seconds);
408da935596Stodd 				break;
409da935596Stodd 			}
410da935596Stodd 
411aa65acf1Sderaadt 		}
4128ccdd032Sderaadt 
4138ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
414db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
4158ccdd032Sderaadt 			bd.bd_cookie = bl.bl_cookie;
4168ccdd032Sderaadt 			bd.bd_diskid = d;
4178ccdd032Sderaadt 			bd.bd_volid = i;
4183af9de98Smarco 
419db2730c1Smarco 			rv = ioctl(devh, BIOCDISK, &bd);
420da3b0664Shenning 			if (rv == -1)
421da3b0664Shenning 				err(1, "BIOCDISK");
4223af9de98Smarco 
4238ccdd032Sderaadt 			switch (bd.bd_status) {
424db2730c1Smarco 			case BIOC_SDONLINE:
4258ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
426d4546a56Sdlg 				break;
427db2730c1Smarco 			case BIOC_SDOFFLINE:
4288ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
429d4546a56Sdlg 				break;
430db2730c1Smarco 			case BIOC_SDFAILED:
4318ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
432db2730c1Smarco 				break;
433db2730c1Smarco 			case BIOC_SDREBUILD:
4348ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
435db2730c1Smarco 				break;
436db2730c1Smarco 			case BIOC_SDHOTSPARE:
4378ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
438db2730c1Smarco 				break;
439db2730c1Smarco 			case BIOC_SDUNUSED:
4408ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
441db2730c1Smarco 				break;
442e1dfb373Sderaadt 			case BIOC_SDSCRUB:
443e1dfb373Sderaadt 				status = BIOC_SDSCRUB_S;
444e1dfb373Sderaadt 				break;
445db2730c1Smarco 			case BIOC_SDINVALID:
446d4546a56Sdlg 			default:
4478ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
448d4546a56Sdlg 			}
449aa65acf1Sderaadt 
450b9950701Smarco 			if (hotspare || unused)
451aa65acf1Sderaadt 				;	/* use volname from parent volume */
452aa65acf1Sderaadt 			else
453aa65acf1Sderaadt 				snprintf(volname, sizeof volname, "    %3u",
454aa65acf1Sderaadt 				    bd.bd_diskid);
455aa65acf1Sderaadt 
4560054cd36Sjsing 			if (bv.bv_level == 'C' && bd.bd_size == 0)
4570054cd36Sjsing 				snprintf(size, sizeof size, "%14s", "key disk");
4580054cd36Sjsing 			else if (human)
4598ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
4608ccdd032Sderaadt 			else
4618ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
4628ccdd032Sderaadt 				    bd.bd_size);
4638ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
46443d61178Sderaadt 			    "%u:%u.%u",
46543d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
4665978b28dSderaadt 			if (bd.bd_procdev[0])
467abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
4685978b28dSderaadt 			else
469abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
470abe9d68eSderaadt 			if (bd.bd_serial[0])
471abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
472abe9d68eSderaadt 			else
473abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
4748ccdd032Sderaadt 
475150c22bbSjcs 			printf("%11s %-10s %14s %-7s %-6s <%s>\n",
476aa65acf1Sderaadt 			    volname, status, size, scsiname, encname,
4778ccdd032Sderaadt 			    bd.bd_vendor);
478abe9d68eSderaadt 			if (verbose)
479aa65acf1Sderaadt 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
480abe9d68eSderaadt 				    "", "", "", "", "", serial);
481d4546a56Sdlg 		}
482d4546a56Sdlg 	}
483d4546a56Sdlg }
484edfd9792Smarco 
485edfd9792Smarco void
486edfd9792Smarco bio_alarm(char *arg)
487edfd9792Smarco {
488edfd9792Smarco 	int			rv;
4898ccdd032Sderaadt 	struct bioc_alarm	ba;
490edfd9792Smarco 
4918ccdd032Sderaadt 	ba.ba_cookie = bl.bl_cookie;
492edfd9792Smarco 
493edfd9792Smarco 	switch (arg[0]) {
494edfd9792Smarco 	case 'q': /* silence alarm */
495edfd9792Smarco 		/* FALLTHROUGH */
496edfd9792Smarco 	case 's':
4978ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
498edfd9792Smarco 		break;
499edfd9792Smarco 
500edfd9792Smarco 	case 'e': /* enable alarm */
5018ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
502edfd9792Smarco 		break;
503edfd9792Smarco 
504edfd9792Smarco 	case 'd': /* disable alarm */
5058ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
506edfd9792Smarco 		break;
507edfd9792Smarco 
508edfd9792Smarco 	case 't': /* test alarm */
5098ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
510edfd9792Smarco 		break;
511edfd9792Smarco 
512edfd9792Smarco 	case 'g': /* get alarm state */
5138ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
514edfd9792Smarco 		break;
515edfd9792Smarco 
516edfd9792Smarco 	default:
517da3b0664Shenning 		errx(1, "invalid alarm function: %s", arg);
518edfd9792Smarco 	}
519edfd9792Smarco 
520edfd9792Smarco 	rv = ioctl(devh, BIOCALARM, &ba);
521da3b0664Shenning 	if (rv == -1)
522da3b0664Shenning 		err(1, "BIOCALARM");
523edfd9792Smarco 
524edfd9792Smarco 	if (arg[0] == 'g') {
525edfd9792Smarco 		printf("alarm is currently %s\n",
5268ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
5278ccdd032Sderaadt 
528edfd9792Smarco 	}
529edfd9792Smarco }
5306de960dcSmarco 
531a15048bbSmarco int
532a15048bbSmarco bio_getvolbyname(char *name)
533a15048bbSmarco {
534a15048bbSmarco 	int			id = -1, i, rv;
535a15048bbSmarco 	struct bioc_inq		bi;
536a15048bbSmarco 	struct bioc_vol		bv;
537a15048bbSmarco 
538a15048bbSmarco 	memset(&bi, 0, sizeof(bi));
539a15048bbSmarco 	bi.bi_cookie = bl.bl_cookie;
540a15048bbSmarco 	rv = ioctl(devh, BIOCINQ, &bi);
541a15048bbSmarco 	if (rv == -1)
542a15048bbSmarco 		err(1, "BIOCINQ");
543a15048bbSmarco 
544a15048bbSmarco 	for (i = 0; i < bi.bi_novol; i++) {
545a15048bbSmarco 		memset(&bv, 0, sizeof(bv));
546a15048bbSmarco 		bv.bv_cookie = bl.bl_cookie;
547a15048bbSmarco 		bv.bv_volid = i;
548a15048bbSmarco 		rv = ioctl(devh, BIOCVOL, &bv);
549a15048bbSmarco 		if (rv == -1)
550a15048bbSmarco 			err(1, "BIOCVOL");
551a15048bbSmarco 
552a15048bbSmarco 		if (name && strcmp(name, bv.bv_dev) != 0)
553a15048bbSmarco 			continue;
554a15048bbSmarco 		id = i;
555a15048bbSmarco 		break;
556a15048bbSmarco 	}
557a15048bbSmarco 
558a15048bbSmarco 	return (id);
559a15048bbSmarco }
560a15048bbSmarco 
561ebaf584eSderaadt void
5628d8693a2Sdtucker bio_setstate(char *arg, int status, char *devicename)
5636de960dcSmarco {
5646de960dcSmarco 	struct bioc_setstate	bs;
5656de960dcSmarco 	struct locator		location;
566a15048bbSmarco 	struct stat		sb;
56741eccc89Sderaadt 	const char		*errstr;
568ebaf584eSderaadt 	int			rv;
5696de960dcSmarco 
570a15048bbSmarco 	memset(&bs, 0, sizeof(bs));
571a15048bbSmarco 	if (stat(arg, &sb) == -1) {
572a15048bbSmarco 		/* use CTL */
57341eccc89Sderaadt 		errstr = str2locator(arg, &location);
57441eccc89Sderaadt 		if (errstr)
57541eccc89Sderaadt 			errx(1, "Target %s: %s", arg, errstr);
5766de960dcSmarco 		bs.bs_channel = location.channel;
5776de960dcSmarco 		bs.bs_target = location.target;
5786de960dcSmarco 		bs.bs_lun = location.lun;
579a15048bbSmarco 	} else {
580a15048bbSmarco 		/* use other id */
581a15048bbSmarco 		bs.bs_other_id = sb.st_rdev;
582a15048bbSmarco 		bs.bs_other_id_type = BIOC_SSOTHER_DEVT;
583a15048bbSmarco 	}
584a15048bbSmarco 
585a15048bbSmarco 	bs.bs_cookie = bl.bl_cookie;
586a15048bbSmarco 	bs.bs_status = status;
587a15048bbSmarco 
588d2647ac1Sjsing 	if (status != BIOC_SSHOTSPARE) {
589a15048bbSmarco 		/* make sure user supplied a sd device */
5908d8693a2Sdtucker 		bs.bs_volid = bio_getvolbyname(devicename);
591a15048bbSmarco 		if (bs.bs_volid == -1)
5928d8693a2Sdtucker 			errx(1, "invalid device %s", devicename);
593d2647ac1Sjsing 	}
5946de960dcSmarco 
5956de960dcSmarco 	rv = ioctl(devh, BIOCSETSTATE, &bs);
596da3b0664Shenning 	if (rv == -1)
597da3b0664Shenning 		err(1, "BIOCSETSTATE");
5986de960dcSmarco }
599c55617f1Sdlg 
600c55617f1Sdlg void
601a928c459Sderaadt bio_setblink(char *name, char *arg, int blink)
602c55617f1Sdlg {
60350d3c4dcSdlg 	struct locator		location;
60450d3c4dcSdlg 	struct bioc_inq		bi;
60550d3c4dcSdlg 	struct bioc_vol		bv;
60650d3c4dcSdlg 	struct bioc_disk	bd;
6070505205bSdlg 	struct bioc_blink	bb;
60841eccc89Sderaadt 	const char		*errstr;
60950d3c4dcSdlg 	int			v, d, rv;
610c55617f1Sdlg 
61141eccc89Sderaadt 	errstr = str2locator(arg, &location);
61241eccc89Sderaadt 	if (errstr)
61341eccc89Sderaadt 		errx(1, "Target %s: %s", arg, errstr);
61450d3c4dcSdlg 
6150505205bSdlg 	/* try setting blink on the device directly */
6160505205bSdlg 	memset(&bb, 0, sizeof(bb));
6170505205bSdlg 	bb.bb_cookie = bl.bl_cookie;
6180505205bSdlg 	bb.bb_status = blink;
6190505205bSdlg 	bb.bb_target = location.target;
620649724a4Smarco 	bb.bb_channel = location.channel;
6210505205bSdlg 	rv = ioctl(devh, BIOCBLINK, &bb);
6220505205bSdlg 	if (rv == 0)
6230505205bSdlg 		return;
6240505205bSdlg 
625855d4e83Ssobrado 	/* if the blink didn't work, try to find something that will */
6260505205bSdlg 
62750d3c4dcSdlg 	memset(&bi, 0, sizeof(bi));
62850d3c4dcSdlg 	bi.bi_cookie = bl.bl_cookie;
62950d3c4dcSdlg 	rv = ioctl(devh, BIOCINQ, &bi);
630da3b0664Shenning 	if (rv == -1)
631da3b0664Shenning 		err(1, "BIOCINQ");
63250d3c4dcSdlg 
63350d3c4dcSdlg 	for (v = 0; v < bi.bi_novol; v++) {
63450d3c4dcSdlg 		memset(&bv, 0, sizeof(bv));
63550d3c4dcSdlg 		bv.bv_cookie = bl.bl_cookie;
63650d3c4dcSdlg 		bv.bv_volid = v;
63750d3c4dcSdlg 		rv = ioctl(devh, BIOCVOL, &bv);
638da3b0664Shenning 		if (rv == -1)
639da3b0664Shenning 			err(1, "BIOCVOL");
64050d3c4dcSdlg 
64150d3c4dcSdlg 		if (name && strcmp(name, bv.bv_dev) != 0)
64250d3c4dcSdlg 			continue;
64350d3c4dcSdlg 
64450d3c4dcSdlg 		for (d = 0; d < bv.bv_nodisk; d++) {
64550d3c4dcSdlg 			memset(&bd, 0, sizeof(bd));
64650d3c4dcSdlg 			bd.bd_cookie = bl.bl_cookie;
64750d3c4dcSdlg 			bd.bd_volid = v;
64850d3c4dcSdlg 			bd.bd_diskid = d;
64950d3c4dcSdlg 
65050d3c4dcSdlg 			rv = ioctl(devh, BIOCDISK, &bd);
651da3b0664Shenning 			if (rv == -1)
652da3b0664Shenning 				err(1, "BIOCDISK");
65350d3c4dcSdlg 
65450d3c4dcSdlg 			if (bd.bd_channel == location.channel &&
65550d3c4dcSdlg 			    bd.bd_target == location.target &&
65650d3c4dcSdlg 			    bd.bd_lun == location.lun) {
65750d3c4dcSdlg 				if (bd.bd_procdev[0] != '\0') {
65850d3c4dcSdlg 					bio_blink(bd.bd_procdev,
659a928c459Sderaadt 					    location.target, blink);
66050d3c4dcSdlg 				} else
66141eccc89Sderaadt 					warnx("Disk %s is not in an enclosure", arg);
66250d3c4dcSdlg 				return;
66350d3c4dcSdlg 			}
66450d3c4dcSdlg 		}
66550d3c4dcSdlg 	}
66650d3c4dcSdlg 
66741eccc89Sderaadt 	warnx("Disk %s does not exist", arg);
66850d3c4dcSdlg 	return;
66950d3c4dcSdlg }
67050d3c4dcSdlg 
67150d3c4dcSdlg void
672a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype)
67350d3c4dcSdlg {
67450d3c4dcSdlg 	int			bioh;
67550d3c4dcSdlg 	struct bio_locate	bio;
67650d3c4dcSdlg 	struct bioc_blink	blink;
67750d3c4dcSdlg 	int			rv;
67850d3c4dcSdlg 
67941eccc89Sderaadt 	bioh = open("/dev/bio", O_RDWR);
68050d3c4dcSdlg 	if (bioh == -1)
68141eccc89Sderaadt 		err(1, "Can't open %s", "/dev/bio");
68250d3c4dcSdlg 
68350d3c4dcSdlg 	bio.bl_name = enclosure;
68450d3c4dcSdlg 	rv = ioctl(bioh, BIOCLOCATE, &bio);
68550d3c4dcSdlg 	if (rv == -1)
68641eccc89Sderaadt 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
687c55617f1Sdlg 
688c55617f1Sdlg 	memset(&blink, 0, sizeof(blink));
68950d3c4dcSdlg 	blink.bb_cookie = bio.bl_cookie;
690a928c459Sderaadt 	blink.bb_status = blinktype;
691c55617f1Sdlg 	blink.bb_target = target;
692c55617f1Sdlg 
69350d3c4dcSdlg 	rv = ioctl(bioh, BIOCBLINK, &blink);
694c55617f1Sdlg 	if (rv == -1)
695da3b0664Shenning 		err(1, "BIOCBLINK");
69650d3c4dcSdlg 
69750d3c4dcSdlg 	close(bioh);
698c55617f1Sdlg }
6997195049bSmarco 
700a2fc2d65Stedu struct sr_aoe_config *
701a2fc2d65Stedu create_aoe(u_int16_t level, char *dev_list)
702a2fc2d65Stedu {
703a2fc2d65Stedu 	static struct sr_aoe_config sac;
704a2fc2d65Stedu 	char *nic;
705a2fc2d65Stedu 	char *dsteaddr;
706a2fc2d65Stedu 	char *shelf;
707a2fc2d65Stedu 	char *slot;
708a2fc2d65Stedu 	struct ether_addr *eaddr;
709a2fc2d65Stedu 	const char *errstr;
710a2fc2d65Stedu 
711a2fc2d65Stedu 	nic = dsteaddr = slot = shelf = 0;
712a2fc2d65Stedu 
713a2fc2d65Stedu 	memset(&sac, 0, sizeof(sac));
714a2fc2d65Stedu 	nic = dev_list;
715a2fc2d65Stedu 	dsteaddr = strchr(nic, ',');
716a2fc2d65Stedu 	if (!dsteaddr)
717a2fc2d65Stedu 		goto invalid;
718a2fc2d65Stedu 	*dsteaddr++ = '\0';
719a2fc2d65Stedu 	shelf = strchr(dsteaddr, ',');
720a2fc2d65Stedu 	if (!shelf)
721a2fc2d65Stedu 		goto invalid;
722a2fc2d65Stedu 	*shelf++ = '\0';
723a2fc2d65Stedu 	slot = strchr(shelf, ',');
724a2fc2d65Stedu 	if (!slot)
725a2fc2d65Stedu 		goto invalid;
726a2fc2d65Stedu 	*slot++ = '\0';
727a2fc2d65Stedu 	strlcpy(sac.nic, nic, sizeof(sac.nic));
728a2fc2d65Stedu 	eaddr = ether_aton(dsteaddr);
729a2fc2d65Stedu 	if (!eaddr)
730a2fc2d65Stedu 		goto invalid;
731a2fc2d65Stedu 	sac.dsteaddr = *eaddr;
732a2fc2d65Stedu 	sac.shelf = htons(strtonum(shelf, 0, 0xfffe, &errstr));
733a2fc2d65Stedu 	if (errstr)
734a2fc2d65Stedu 		goto invalid;
735a2fc2d65Stedu 	sac.slot = strtonum(slot, 0, 0xfe, &errstr);
736a2fc2d65Stedu 	if (errstr)
737a2fc2d65Stedu 		goto invalid;
738a2fc2d65Stedu 
739a2fc2d65Stedu 	return &sac;
740a2fc2d65Stedu invalid:
741a2fc2d65Stedu 	errx(1, "invalid AOE dev list: use nic,dsteaddr,shelf,slot");
742a2fc2d65Stedu }
743a2fc2d65Stedu 
7447195049bSmarco void
7450054cd36Sjsing bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
7467195049bSmarco {
7477195049bSmarco 	struct bioc_createraid	create;
748aef7fe28Shshoexer 	struct sr_crypto_kdfinfo kdfinfo;
749aef7fe28Shshoexer 	struct sr_crypto_kdf_pbkdf2 kdfhint;
750a2fc2d65Stedu 	struct sr_aoe_config	*sac;
7510054cd36Sjsing 	struct stat		sb;
7528b0d0f28Sjsing 	int			rv, no_dev, fd;
7537f8eae2bSnicm 	dev_t			*dt;
7547195049bSmarco 	u_int16_t		min_disks = 0;
7557195049bSmarco 
7567195049bSmarco 	if (!dev_list)
7577195049bSmarco 		errx(1, "no devices specified");
7587195049bSmarco 
759a2fc2d65Stedu 	if (level == 'a') {
760a2fc2d65Stedu 		sac = create_aoe(level, dev_list);
761a2fc2d65Stedu 		no_dev = 0;
762a2fc2d65Stedu 		dt = NULL;
763a2fc2d65Stedu 	} else  {
76446bc198bSmarco 		dt = (dev_t *)malloc(BIOC_CRMAXLEN);
76546bc198bSmarco 		if (!dt)
76646bc198bSmarco 			err(1, "not enough memory for dev_t list");
76746bc198bSmarco 		memset(dt, 0, BIOC_CRMAXLEN);
76846bc198bSmarco 
76946bc198bSmarco 		no_dev = bio_parse_devlist(dev_list, dt);
770a2fc2d65Stedu 	}
77146bc198bSmarco 
7727195049bSmarco 	switch (level) {
7737195049bSmarco 	case 0:
77484e48fabSmarco 		min_disks = 2;
7757195049bSmarco 		break;
7767195049bSmarco 	case 1:
7777195049bSmarco 		min_disks = 2;
7787195049bSmarco 		break;
779e717853eSmarco 	case 4:
780e717853eSmarco 	case 5:
781e717853eSmarco 		min_disks = 3;
782e717853eSmarco 		break;
78384e48fabSmarco 	case 'C':
784aef7fe28Shshoexer 		min_disks = 1;
78584e48fabSmarco 		break;
78698b750e4Stedu 	case 'c':
78798b750e4Stedu 		min_disks = 1;
78898b750e4Stedu 		break;
789a2fc2d65Stedu 	case 'a':
790a2fc2d65Stedu 		break;
7917195049bSmarco 	default:
79223afedbfSgrunk 		errx(1, "unsupported raid level");
7937195049bSmarco 	}
7947195049bSmarco 
79584e48fabSmarco 	if (no_dev < min_disks)
79684e48fabSmarco 		errx(1, "not enough disks");
79784e48fabSmarco 
798aef7fe28Shshoexer 	/* for crypto raid we only allow one single chunk */
799aef7fe28Shshoexer 	if (level == 'C' && no_dev != min_disks)
800818b0595Shalex 		errx(1, "not exactly one partition");
801aef7fe28Shshoexer 
8027195049bSmarco 	memset(&create, 0, sizeof(create));
8037195049bSmarco 	create.bc_cookie = bl.bl_cookie;
8047195049bSmarco 	create.bc_level = level;
80546bc198bSmarco 	create.bc_dev_list_len = no_dev * sizeof(dev_t);
80646bc198bSmarco 	create.bc_dev_list = dt;
807e8a57fdeSmarco 	create.bc_flags = BIOC_SCDEVT | cflags;
8080054cd36Sjsing 	create.bc_key_disk = NODEV;
8097195049bSmarco 
810a2fc2d65Stedu 	if (level == 'a') {
811a2fc2d65Stedu 		create.bc_opaque = sac;
812a2fc2d65Stedu 		create.bc_opaque_size = sizeof(*sac);
813a2fc2d65Stedu 		create.bc_opaque_flags = BIOC_SOIN;
814a2fc2d65Stedu 	} else if (level == 'C' && key_disk == NULL) {
8150054cd36Sjsing 
816aef7fe28Shshoexer 		memset(&kdfinfo, 0, sizeof(kdfinfo));
817aef7fe28Shshoexer 		memset(&kdfhint, 0, sizeof(kdfhint));
818aef7fe28Shshoexer 
8190054cd36Sjsing 		create.bc_flags |= BIOC_SCNOAUTOASSEMBLE;
8200054cd36Sjsing 
821aef7fe28Shshoexer 		create.bc_opaque = &kdfhint;
822aef7fe28Shshoexer 		create.bc_opaque_size = sizeof(kdfhint);
823aef7fe28Shshoexer 		create.bc_opaque_flags = BIOC_SOOUT;
824aef7fe28Shshoexer 
825aef7fe28Shshoexer 		/* try to get KDF hint */
82683e979edShshoexer 		if (ioctl(devh, BIOCCREATERAID, &create) == -1)
82783e979edShshoexer 			err(1, "ioctl");
82883e979edShshoexer 
82983e979edShshoexer 		if (create.bc_opaque_status == BIOC_SOINOUT_OK) {
830c6446370Sjsing 			bio_kdf_derive(&kdfinfo, &kdfhint, "Passphrase: ", 0);
831aef7fe28Shshoexer 			memset(&kdfhint, 0, sizeof(kdfhint));
832aef7fe28Shshoexer 		} else  {
833aef7fe28Shshoexer 			bio_kdf_generate(&kdfinfo);
834aef7fe28Shshoexer 		}
835aef7fe28Shshoexer 
836aef7fe28Shshoexer 		create.bc_opaque = &kdfinfo;
837aef7fe28Shshoexer 		create.bc_opaque_size = sizeof(kdfinfo);
838aef7fe28Shshoexer 		create.bc_opaque_flags = BIOC_SOIN;
8390054cd36Sjsing 
8400054cd36Sjsing 	} else if (level == 'C' && key_disk != NULL) {
8410054cd36Sjsing 
8428b0d0f28Sjsing 		/* Get device number for key disk. */
8438b0d0f28Sjsing 		fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL);
8448b0d0f28Sjsing 		if (fd == -1)
8458b0d0f28Sjsing 			err(1, "could not open %s", key_disk);
8468b0d0f28Sjsing 		if (fstat(fd, &sb) == -1) {
8478b0d0f28Sjsing 			close(fd);
8480054cd36Sjsing 			err(1, "could not stat %s", key_disk);
8498b0d0f28Sjsing 		}
8508b0d0f28Sjsing 		close(fd);
8510054cd36Sjsing 		create.bc_key_disk = sb.st_rdev;
8520054cd36Sjsing 
8530054cd36Sjsing 		memset(&kdfinfo, 0, sizeof(kdfinfo));
8540054cd36Sjsing 
8550054cd36Sjsing 		kdfinfo.genkdf.len = sizeof(kdfinfo.genkdf);
8560054cd36Sjsing 		kdfinfo.genkdf.type = SR_CRYPTOKDFT_KEYDISK;
8570054cd36Sjsing 		kdfinfo.len = sizeof(kdfinfo);
8580054cd36Sjsing 		kdfinfo.flags = SR_CRYPTOKDF_HINT;
8590054cd36Sjsing 
8600054cd36Sjsing 		create.bc_opaque = &kdfinfo;
8610054cd36Sjsing 		create.bc_opaque_size = sizeof(kdfinfo);
8620054cd36Sjsing 		create.bc_opaque_flags = BIOC_SOIN;
8630054cd36Sjsing 
864aef7fe28Shshoexer 	}
865aef7fe28Shshoexer 
8667195049bSmarco 	rv = ioctl(devh, BIOCCREATERAID, &create);
867aef7fe28Shshoexer 	memset(&kdfinfo, 0, sizeof(kdfinfo));
86883e979edShshoexer 	memset(&create, 0, sizeof(create));
869a83e4577Sdjm 	if (rv == -1) {
870a83e4577Sdjm 		if (errno == EPERM)
871a83e4577Sdjm 			errx(1, "Incorrect passphrase");
872da3b0664Shenning 		err(1, "BIOCCREATERAID");
873a83e4577Sdjm 	}
87446bc198bSmarco 
87546bc198bSmarco 	free(dt);
87646bc198bSmarco }
87746bc198bSmarco 
878aef7fe28Shshoexer void
879aef7fe28Shshoexer bio_kdf_derive(struct sr_crypto_kdfinfo *kdfinfo, struct sr_crypto_kdf_pbkdf2
880c6446370Sjsing     *kdfhint, char* prompt, int verify)
881aef7fe28Shshoexer {
882aef7fe28Shshoexer 	if (!kdfinfo)
883aef7fe28Shshoexer 		errx(1, "invalid KDF info");
884aef7fe28Shshoexer 	if (!kdfhint)
885aef7fe28Shshoexer 		errx(1, "invalid KDF hint");
886aef7fe28Shshoexer 
887aef7fe28Shshoexer 	if (kdfhint->len != sizeof(*kdfhint))
888aef7fe28Shshoexer 		errx(1, "KDF hint has invalid size");
889aef7fe28Shshoexer 	if (kdfhint->type != SR_CRYPTOKDFT_PBKDF2)
890aef7fe28Shshoexer 		errx(1, "unknown KDF type %d", kdfhint->type);
891aef7fe28Shshoexer 	if (kdfhint->rounds < 1000)
892aef7fe28Shshoexer 		errx(1, "number of KDF rounds too low: %d", kdfhint->rounds);
893aef7fe28Shshoexer 
894aef7fe28Shshoexer 	kdfinfo->flags = SR_CRYPTOKDF_KEY;
895aef7fe28Shshoexer 	kdfinfo->len = sizeof(*kdfinfo);
896aef7fe28Shshoexer 
8979e8c6f5bShshoexer 	derive_key_pkcs(kdfhint->rounds,
898aef7fe28Shshoexer 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
899c6446370Sjsing 	    kdfhint->salt, sizeof(kdfhint->salt), prompt, verify);
900aef7fe28Shshoexer }
901aef7fe28Shshoexer 
902aef7fe28Shshoexer void
903aef7fe28Shshoexer bio_kdf_generate(struct sr_crypto_kdfinfo *kdfinfo)
904aef7fe28Shshoexer {
905aef7fe28Shshoexer 	if (!kdfinfo)
906aef7fe28Shshoexer 		errx(1, "invalid KDF info");
907aef7fe28Shshoexer 
908aef7fe28Shshoexer 	kdfinfo->pbkdf2.len = sizeof(kdfinfo->pbkdf2);
909aef7fe28Shshoexer 	kdfinfo->pbkdf2.type = SR_CRYPTOKDFT_PBKDF2;
910aedd4f07Sdjm 	kdfinfo->pbkdf2.rounds = rflag;
911aef7fe28Shshoexer 	kdfinfo->len = sizeof(*kdfinfo);
9120054cd36Sjsing 	kdfinfo->flags = SR_CRYPTOKDF_KEY | SR_CRYPTOKDF_HINT;
913aef7fe28Shshoexer 
914aef7fe28Shshoexer 	/* generate salt */
915aef7fe28Shshoexer 	arc4random_buf(kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt));
916aef7fe28Shshoexer 
9179e8c6f5bShshoexer 	derive_key_pkcs(kdfinfo->pbkdf2.rounds,
918aef7fe28Shshoexer 	    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
919c6446370Sjsing 	    kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt),
920c6446370Sjsing 	    "New passphrase: ", 1);
921aef7fe28Shshoexer }
922aef7fe28Shshoexer 
92346bc198bSmarco int
92446bc198bSmarco bio_parse_devlist(char *lst, dev_t *dt)
92546bc198bSmarco {
92646bc198bSmarco 	char			*s, *e;
92746bc198bSmarco 	u_int32_t		sz = 0;
92846bc198bSmarco 	int			no_dev = 0, i, x;
92946bc198bSmarco 	struct stat		sb;
9305c1f8f6bSdjm 	char			dev[MAXPATHLEN];
931e37c64dbSjsing 	int			fd;
93246bc198bSmarco 
93346bc198bSmarco 	if (!lst)
93446bc198bSmarco 		errx(1, "invalid device list");
93546bc198bSmarco 
93646bc198bSmarco 	s = e = lst;
93746bc198bSmarco 	/* make sure we have a valid device list like /dev/sdNa,/dev/sdNNa */
93846bc198bSmarco 	while (*e != '\0') {
93946bc198bSmarco 		if (*e == ',')
94046bc198bSmarco 			s = e + 1;
94146bc198bSmarco 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
94246bc198bSmarco 			/* got one */
94346bc198bSmarco 			sz = e - s + 1;
9445c1f8f6bSdjm 			strlcpy(dev, s, sz + 1);
945e37c64dbSjsing 			fd = opendev(dev, O_RDONLY, OPENDEV_BLCK, NULL);
946e37c64dbSjsing 			if (fd == -1)
947e37c64dbSjsing 				err(1, "could not open %s", dev);
948e37c64dbSjsing 			if (fstat(fd, &sb) == -1) {
949e37c64dbSjsing 				close(fd);
9505c1f8f6bSdjm 				err(1, "could not stat %s", dev);
951e37c64dbSjsing 			}
952e37c64dbSjsing 			close(fd);
95346bc198bSmarco 			dt[no_dev] = sb.st_rdev;
95446bc198bSmarco 			no_dev++;
9555c1f8f6bSdjm 			if (no_dev > (int)(BIOC_CRMAXLEN / sizeof(dev_t)))
95646bc198bSmarco 				errx(1, "too many devices on device list");
95746bc198bSmarco 		}
95846bc198bSmarco 		e++;
95946bc198bSmarco 	}
96046bc198bSmarco 
96146bc198bSmarco 	for (i = 0; i < no_dev; i++)
96246bc198bSmarco 		for (x = 0; x < no_dev; x++)
96346bc198bSmarco 			if (dt[i] == dt[x] && x != i)
96446bc198bSmarco 				errx(1, "duplicate device in list");
96546bc198bSmarco 
96646bc198bSmarco 	return (no_dev);
9677195049bSmarco }
968e8a57fdeSmarco 
969e8a57fdeSmarco u_int32_t
970e8a57fdeSmarco bio_createflags(char *lst)
971e8a57fdeSmarco {
972e8a57fdeSmarco 	char			*s, *e, fs[32];
973e8a57fdeSmarco 	u_int32_t		sz = 0;
974e8a57fdeSmarco 	u_int32_t		flags = 0;
975e8a57fdeSmarco 
976e8a57fdeSmarco 	if (!lst)
977e8a57fdeSmarco 		errx(1, "invalid flags list");
978e8a57fdeSmarco 
979e8a57fdeSmarco 	s = e = lst;
980e8a57fdeSmarco 	/* make sure we have a valid flags list like force,noassemeble */
981e8a57fdeSmarco 	while (*e != '\0') {
982e8a57fdeSmarco 		if (*e == ',')
983e8a57fdeSmarco 			s = e + 1;
984e8a57fdeSmarco 		else if (*(e + 1) == '\0' || *(e + 1) == ',') {
985e8a57fdeSmarco 			/* got one */
986e8a57fdeSmarco 			sz = e - s + 1;
987e8a57fdeSmarco 			switch (s[0]) {
988e8a57fdeSmarco 			case 'f':
989e8a57fdeSmarco 				flags |= BIOC_SCFORCE;
990e8a57fdeSmarco 				break;
991e8a57fdeSmarco 			case 'n':
992e8a57fdeSmarco 				flags |= BIOC_SCNOAUTOASSEMBLE;
993e8a57fdeSmarco 				break;
994e8a57fdeSmarco 			default:
995e8a57fdeSmarco 				strlcpy(fs, s, sz + 1);
996e8a57fdeSmarco 				errx(1, "invalid flag %s", fs);
997e8a57fdeSmarco 			}
998e8a57fdeSmarco 		}
999e8a57fdeSmarco 		e++;
1000e8a57fdeSmarco 	}
1001e8a57fdeSmarco 
1002e8a57fdeSmarco 	return (flags);
1003e8a57fdeSmarco }
100403b2dfbfShenning 
1005c7c3e8aaSmarco void
1006c7c3e8aaSmarco bio_deleteraid(char *dev)
1007c7c3e8aaSmarco {
1008c7c3e8aaSmarco 	struct bioc_deleteraid	bd;
1009c7c3e8aaSmarco 	memset(&bd, 0, sizeof(bd));
1010c7c3e8aaSmarco 
1011c7c3e8aaSmarco 	bd.bd_cookie = bd.bd_cookie;
1012a15048bbSmarco 	/* XXX make this a dev_t instead of a string */
1013c7c3e8aaSmarco 	strlcpy(bd.bd_dev, dev, sizeof bd.bd_dev);
1014c7c3e8aaSmarco 	if (ioctl(devh, BIOCDELETERAID, &bd))
1015c7c3e8aaSmarco 		errx(1, "delete volume %s failed", dev);
1016c7c3e8aaSmarco }
1017c7c3e8aaSmarco 
1018c6446370Sjsing void
1019c6446370Sjsing bio_changepass(char *dev)
1020c6446370Sjsing {
1021c6446370Sjsing 	struct bioc_discipline bd;
1022c6446370Sjsing 	struct sr_crypto_kdfpair kdfpair;
1023c6446370Sjsing 	struct sr_crypto_kdfinfo kdfinfo1, kdfinfo2;
1024c6446370Sjsing 	struct sr_crypto_kdf_pbkdf2 kdfhint;
1025c6446370Sjsing 	int rv;
1026c6446370Sjsing 
1027c6446370Sjsing 	memset(&bd, 0, sizeof(bd));
1028c6446370Sjsing 	memset(&kdfhint, 0, sizeof(kdfhint));
1029c6446370Sjsing 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1030c6446370Sjsing 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1031c6446370Sjsing 
1032c6446370Sjsing 	/* XXX use dev_t instead of string. */
1033c6446370Sjsing 	strlcpy(bd.bd_dev, dev, sizeof(bd.bd_dev));
1034c6446370Sjsing 	bd.bd_cmd = SR_IOCTL_GET_KDFHINT;
1035c6446370Sjsing 	bd.bd_size = sizeof(kdfhint);
1036c6446370Sjsing 	bd.bd_data = &kdfhint;
1037c6446370Sjsing 
1038c6446370Sjsing 	if (ioctl(devh, BIOCDISCIPLINE, &bd))
1039c6446370Sjsing 		errx(1, "%s: failed to get KDF hint", dev);
1040c6446370Sjsing 
1041c6446370Sjsing 	/* Current passphrase. */
1042c6446370Sjsing 	bio_kdf_derive(&kdfinfo1, &kdfhint, "Old passphrase: ", 0);
1043c6446370Sjsing 
1044c6446370Sjsing 	/* New passphrase. */
1045c6446370Sjsing 	bio_kdf_derive(&kdfinfo2, &kdfhint, "New passphrase: ", 1);
1046c6446370Sjsing 
1047c6446370Sjsing 	kdfpair.kdfinfo1 = &kdfinfo1;
1048c6446370Sjsing 	kdfpair.kdfsize1 = sizeof(kdfinfo1);
1049c6446370Sjsing 	kdfpair.kdfinfo2 = &kdfinfo2;
1050c6446370Sjsing 	kdfpair.kdfsize2 = sizeof(kdfinfo2);
1051c6446370Sjsing 
1052c6446370Sjsing 	bd.bd_cmd = SR_IOCTL_CHANGE_PASSPHRASE;
1053c6446370Sjsing 	bd.bd_size = sizeof(kdfpair);
1054c6446370Sjsing 	bd.bd_data = &kdfpair;
1055c6446370Sjsing 
1056c6446370Sjsing 	rv = ioctl(devh, BIOCDISCIPLINE, &bd);
1057c6446370Sjsing 
1058c6446370Sjsing 	memset(&kdfhint, 0, sizeof(kdfhint));
1059c6446370Sjsing 	memset(&kdfinfo1, 0, sizeof(kdfinfo1));
1060c6446370Sjsing 	memset(&kdfinfo2, 0, sizeof(kdfinfo2));
1061c6446370Sjsing 
1062c6446370Sjsing 	if (rv) {
1063c6446370Sjsing 		if (errno == EPERM)
1064c6446370Sjsing 			errx(1, "%s: incorrect passphrase", dev);
1065c6446370Sjsing 		else
1066c6446370Sjsing 			errx(1, "%s: failed to change passphrase", dev);
1067c6446370Sjsing 	}
1068c6446370Sjsing }
1069c6446370Sjsing 
107003b2dfbfShenning #define BIOCTL_VIS_NBUF		4
107103b2dfbfShenning #define BIOCTL_VIS_BUFLEN	80
107203b2dfbfShenning 
107303b2dfbfShenning char *
107403b2dfbfShenning bio_vis(char *s)
107503b2dfbfShenning {
107603b2dfbfShenning 	static char	 rbuf[BIOCTL_VIS_NBUF][BIOCTL_VIS_BUFLEN];
107703b2dfbfShenning 	static uint	 idx = 0;
107803b2dfbfShenning 	char		*buf;
107903b2dfbfShenning 
108003b2dfbfShenning 	buf = rbuf[idx++];
108103b2dfbfShenning 	if (idx == BIOCTL_VIS_NBUF)
108203b2dfbfShenning 		idx = 0;
108303b2dfbfShenning 
108403b2dfbfShenning 	strnvis(buf, s, BIOCTL_VIS_BUFLEN, VIS_NL|VIS_CSTYLE);
108503b2dfbfShenning 	return (buf);
108603b2dfbfShenning }
108703b2dfbfShenning 
108803b2dfbfShenning void
108903b2dfbfShenning bio_diskinq(char *sd_dev)
109003b2dfbfShenning {
109103b2dfbfShenning 	struct dk_inquiry	di;
109203b2dfbfShenning 
1093da3b0664Shenning 	if (ioctl(devh, DIOCINQ, &di) == -1)
1094da3b0664Shenning 		err(1, "DIOCINQ");
109503b2dfbfShenning 
109603b2dfbfShenning 	printf("%s: <%s, %s, %s>, serial %s\n", sd_dev, bio_vis(di.vendor),
109703b2dfbfShenning 	    bio_vis(di.product), bio_vis(di.revision), bio_vis(di.serial));
109803b2dfbfShenning }
1099aef7fe28Shshoexer 
1100aef7fe28Shshoexer void
11019e8c6f5bShshoexer derive_key_pkcs(int rounds, u_int8_t *key, size_t keysz, u_int8_t *salt,
1102c6446370Sjsing     size_t saltsz, char *prompt, int verify)
1103aef7fe28Shshoexer {
110486735da2Smarco 	FILE		*f;
110586735da2Smarco 	size_t		pl;
110686735da2Smarco 	struct stat	sb;
11079e8c6f5bShshoexer 	char		passphrase[1024], verifybuf[1024];
1108aef7fe28Shshoexer 
1109aef7fe28Shshoexer 	if (!key)
1110aef7fe28Shshoexer 		errx(1, "Invalid key");
1111aef7fe28Shshoexer 	if (!salt)
1112aef7fe28Shshoexer 		errx(1, "Invalid salt");
1113aef7fe28Shshoexer 	if (rounds < 1000)
1114b4604b5cShalex 		errx(1, "Too few rounds: %d", rounds);
1115aef7fe28Shshoexer 
1116aef7fe28Shshoexer 	/* get passphrase */
1117ba3d8661Smarco 	if (password && verify)
1118ba3d8661Smarco 		errx(1, "can't specify passphrase file during initial "
1119ba3d8661Smarco 		    "creation of crypto volume");
1120ba3d8661Smarco 	if (password) {
112186735da2Smarco 		if ((f = fopen(password, "r")) == NULL)
112286735da2Smarco 			err(1, "invalid passphrase file");
112386735da2Smarco 
112486735da2Smarco 		if (fstat(fileno(f), &sb) == -1)
112586735da2Smarco 			err(1, "can't stat passphrase file");
112686735da2Smarco 		if (sb.st_uid != 0)
112786735da2Smarco 			errx(1, "passphrase file must be owned by root");
112886735da2Smarco 		if ((sb.st_mode & ~S_IFMT) != (S_IRUSR | S_IWUSR))
112986735da2Smarco 			errx(1, "passphrase file has the wrong permissions");
113086735da2Smarco 
113186735da2Smarco 		if (fgets(passphrase, sizeof(passphrase), f) == NULL)
113286735da2Smarco 			err(1, "can't read passphrase file");
113386735da2Smarco 		pl = strlen(passphrase);
113486735da2Smarco 		if (pl > 0 && passphrase[pl - 1] == '\n')
113586735da2Smarco 			passphrase[pl - 1] = '\0';
113686735da2Smarco 		else
113786735da2Smarco 			errx(1, "invalid passphrase length");
113886735da2Smarco 
113986735da2Smarco 		fclose(f);
1140ba3d8661Smarco 	} else {
1141c6446370Sjsing 		if (readpassphrase(prompt, passphrase, sizeof(passphrase),
1142b96c6ce2Sckuethe 		    rpp_flag) == NULL)
11439e8c6f5bShshoexer 			errx(1, "unable to read passphrase");
1144ba3d8661Smarco 	}
11459e8c6f5bShshoexer 
11469e8c6f5bShshoexer 	if (verify) {
11479e8c6f5bShshoexer 		/* request user to re-type it */
11489e8c6f5bShshoexer 		if (readpassphrase("Re-type passphrase: ", verifybuf,
1149b96c6ce2Sckuethe 		    sizeof(verifybuf), rpp_flag) == NULL) {
11509e8c6f5bShshoexer 			memset(passphrase, 0, sizeof(passphrase));
11519e8c6f5bShshoexer 			errx(1, "unable to read passphrase");
11529e8c6f5bShshoexer 		}
11539e8c6f5bShshoexer 		if ((strlen(passphrase) != strlen(verifybuf)) ||
11549e8c6f5bShshoexer 		    (strcmp(passphrase, verifybuf) != 0)) {
11559e8c6f5bShshoexer 			memset(passphrase, 0, sizeof(passphrase));
11569e8c6f5bShshoexer 			memset(verifybuf, 0, sizeof(verifybuf));
11579e8c6f5bShshoexer 			errx(1, "Passphrases did not match");
11589e8c6f5bShshoexer 		}
11599e8c6f5bShshoexer 		/* forget the re-typed one */
11609e8c6f5bShshoexer 		memset(verifybuf, 0, strlen(verifybuf));
11619e8c6f5bShshoexer 	}
1162aef7fe28Shshoexer 
1163aef7fe28Shshoexer 	/* derive key from passphrase */
11645c1f8f6bSdjm 	if (pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltsz,
11655c1f8f6bSdjm 	    key, keysz, rounds) != 0)
11665c1f8f6bSdjm 		errx(1, "pbkdf2 failed");
1167aef7fe28Shshoexer 
1168aef7fe28Shshoexer 	/* forget passphrase */
11699e8c6f5bShshoexer 	memset(passphrase, 0, sizeof(passphrase));
1170aef7fe28Shshoexer 
1171aef7fe28Shshoexer 	return;
1172aef7fe28Shshoexer }
1173