xref: /openbsd/sbin/bioctl/bioctl.c (revision 7195049b)
1*7195049bSmarco /* $OpenBSD: bioctl.c,v 1.49 2007/03/19 03:02:09 marco 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>
31c2126c9aSmarco #include <sys/param.h>
32c2126c9aSmarco #include <sys/queue.h>
33c2126c9aSmarco #include <scsi/scsi_disk.h>
342b69df39Smarco #include <scsi/scsi_all.h>
353af9de98Smarco #include <dev/biovar.h>
363af9de98Smarco 
37db2730c1Smarco #include <errno.h>
38db2730c1Smarco #include <err.h>
39db2730c1Smarco #include <fcntl.h>
408ccdd032Sderaadt #include <util.h>
41db2730c1Smarco #include <stdio.h>
42db2730c1Smarco #include <stdlib.h>
43db2730c1Smarco #include <string.h>
44db2730c1Smarco #include <unistd.h>
45e4e14ad7Sderaadt #include <ctype.h>
46db2730c1Smarco #include <util.h>
47db2730c1Smarco 
486de960dcSmarco struct locator {
496de960dcSmarco 	int channel;
506de960dcSmarco 	int target;
516de960dcSmarco 	int lun;
526de960dcSmarco };
536de960dcSmarco 
548ccdd032Sderaadt void usage(void);
5541eccc89Sderaadt const char *str2locator(const char *, struct locator *);
568ccdd032Sderaadt void cleanup(void);
578ccdd032Sderaadt 
588ccdd032Sderaadt void bio_inq(char *);
598ccdd032Sderaadt void bio_alarm(char *);
606de960dcSmarco void bio_setstate(char *);
61a928c459Sderaadt void bio_setblink(char *, char *, int);
62a928c459Sderaadt void bio_blink(char *, int, int);
63*7195049bSmarco void bio_createraid(u_int16_t, char *);
643af9de98Smarco 
653af9de98Smarco int devh = -1;
66abe9d68eSderaadt int debug;
67abe9d68eSderaadt int human;
68abe9d68eSderaadt int verbose;
693af9de98Smarco 
703af9de98Smarco struct bio_locate bl;
713af9de98Smarco 
723af9de98Smarco int
733af9de98Smarco main(int argc, char *argv[])
743af9de98Smarco {
753af9de98Smarco 	extern char *optarg;
76db2730c1Smarco 	u_int64_t func = 0;
77db2730c1Smarco 	/* u_int64_t subfunc = 0; */
78cf6503d7Sderaadt 	char *bioc_dev = NULL, *sd_dev = NULL;
79cf6503d7Sderaadt 	char *realname = NULL, *al_arg = NULL;
80*7195049bSmarco 	char *bl_arg = NULL, *dev_list = NULL;
81a928c459Sderaadt 	int ch, rv, blink;
82*7195049bSmarco 	u_int16_t cr_level;
833af9de98Smarco 
843af9de98Smarco 	if (argc < 2)
853af9de98Smarco 		usage();
863af9de98Smarco 
87*7195049bSmarco 	while ((ch = getopt(argc, argv, "b:c:l:u:H:ha:Div")) != -1) {
883af9de98Smarco 		switch (ch) {
89edfd9792Smarco 		case 'a': /* alarm */
90edfd9792Smarco 			func |= BIOC_ALARM;
91edfd9792Smarco 			al_arg = optarg;
92edfd9792Smarco 			break;
93c55617f1Sdlg 		case 'b': /* blink */
94c55617f1Sdlg 			func |= BIOC_BLINK;
95a928c459Sderaadt 			blink = BIOC_SBBLINK;
96a928c459Sderaadt 			bl_arg = optarg;
97a928c459Sderaadt 			break;
98*7195049bSmarco 		case 'c': /* create */
99*7195049bSmarco 			func |= BIOC_CREATERAID;
100*7195049bSmarco 			cr_level = atoi(optarg);
101*7195049bSmarco 			break;
102a928c459Sderaadt 		case 'u': /* unblink */
103a928c459Sderaadt 			func |= BIOC_BLINK;
104a928c459Sderaadt 			blink = BIOC_SBUNBLINK;
105c55617f1Sdlg 			bl_arg = optarg;
106c55617f1Sdlg 			break;
107db2730c1Smarco 		case 'D': /* debug */
1083af9de98Smarco 			debug = 1;
1093af9de98Smarco 			break;
1106de960dcSmarco 		case 'H': /* set hotspare */
1116de960dcSmarco 			func |= BIOC_SETSTATE;
1126de960dcSmarco 			al_arg = optarg;
1136de960dcSmarco 			break;
1148ccdd032Sderaadt 		case 'h':
1158ccdd032Sderaadt 			human = 1;
1168ccdd032Sderaadt 			break;
117db2730c1Smarco 		case 'i': /* inquiry */
118db2730c1Smarco 			func |= BIOC_INQ;
1193af9de98Smarco 			break;
120*7195049bSmarco 		case 'l': /* device list */
121*7195049bSmarco 			func |= BIOC_DEVLIST;
122*7195049bSmarco 			dev_list = optarg;
123*7195049bSmarco 			break;
124abe9d68eSderaadt 		case 'v':
125abe9d68eSderaadt 			verbose = 1;
126abe9d68eSderaadt 			break;
1273af9de98Smarco 		default:
1283af9de98Smarco 			usage();
1293af9de98Smarco 			/* NOTREACHED */
1303af9de98Smarco 		}
1313af9de98Smarco 	}
132cf6503d7Sderaadt 	argc -= optind;
133cf6503d7Sderaadt 	argv += optind;
1343af9de98Smarco 
1358ccdd032Sderaadt 	if (argc != 1)
136cf6503d7Sderaadt 		usage();
137cf6503d7Sderaadt 
138dcbaf4c8Sderaadt 	if (func == 0)
139dcbaf4c8Sderaadt 		func |= BIOC_INQ;
140dcbaf4c8Sderaadt 
141e4e14ad7Sderaadt 	/* if at least glob sd[0-9]*, it is a drive identifier */
142e4e14ad7Sderaadt 	if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
143e4e14ad7Sderaadt 	    isdigit(argv[0][2]))
144cf6503d7Sderaadt 		sd_dev = argv[0];
145cf6503d7Sderaadt 	else
146cf6503d7Sderaadt 		bioc_dev = argv[0];
14710b411a7Smarco 
14810b411a7Smarco 	if (bioc_dev) {
14941eccc89Sderaadt 		devh = open("/dev/bio", O_RDWR);
1503af9de98Smarco 		if (devh == -1)
15141eccc89Sderaadt 			err(1, "Can't open %s", "/dev/bio");
1523af9de98Smarco 
1538ccdd032Sderaadt 		bl.bl_name = bioc_dev;
1543af9de98Smarco 		rv = ioctl(devh, BIOCLOCATE, &bl);
1553af9de98Smarco 		if (rv == -1)
15610b411a7Smarco 			errx(1, "Can't locate %s device via %s",
15741eccc89Sderaadt 			    bl.bl_name, "/dev/bio");
158db2730c1Smarco 	} else if (sd_dev) {
15910b411a7Smarco 		devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
16010b411a7Smarco 		if (devh == -1)
16110b411a7Smarco 			err(1, "Can't open %s", sd_dev);
162db2730c1Smarco 	} else
16310b411a7Smarco 		errx(1, "need -d or -f parameter");
1643af9de98Smarco 
1653af9de98Smarco 	if (debug)
1668ccdd032Sderaadt 		warnx("cookie = %p", bl.bl_cookie);
1673af9de98Smarco 
168db2730c1Smarco 	if (func & BIOC_INQ) {
1698ccdd032Sderaadt 		bio_inq(sd_dev);
170edfd9792Smarco 	} else if (func == BIOC_ALARM) {
171edfd9792Smarco 		bio_alarm(al_arg);
172c55617f1Sdlg 	} else if (func == BIOC_BLINK) {
173a928c459Sderaadt 		bio_setblink(sd_dev, bl_arg, blink);
1746de960dcSmarco 	} else if (func == BIOC_SETSTATE) {
1756de960dcSmarco 		bio_setstate(al_arg);
176*7195049bSmarco 	} else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
177*7195049bSmarco 		if (!(func & BIOC_CREATERAID))
178*7195049bSmarco 			errx(1, "need -c parameter");
179*7195049bSmarco 		if (!(func & BIOC_DEVLIST))
180*7195049bSmarco 			errx(1, "need -l parameter");
181*7195049bSmarco 		if (sd_dev)
182*7195049bSmarco 			errx(1, "can't use sd device");
183*7195049bSmarco 		bio_createraid(cr_level, dev_list);
1843af9de98Smarco 	}
1853af9de98Smarco 
1863af9de98Smarco 	return (0);
1873af9de98Smarco }
1883af9de98Smarco 
1893af9de98Smarco void
1903af9de98Smarco usage(void)
1913af9de98Smarco {
1923af9de98Smarco 	extern char *__progname;
1933af9de98Smarco 
194ebaf584eSderaadt 	fprintf(stderr, "usage: %s [-Dhiv] [-a alarm-function]"
19569e80e10Sderaadt 	    " [[-bHu] chan:targ[.lun]] device\n", __progname);
1963af9de98Smarco 	exit(1);
1973af9de98Smarco }
1983af9de98Smarco 
19941eccc89Sderaadt const char *
2006de960dcSmarco str2locator(const char *string, struct locator *location)
2016de960dcSmarco {
20250d3c4dcSdlg 	const char *errstr;
20341eccc89Sderaadt 	char parse[80], *targ, *lun;
2046de960dcSmarco 
20541eccc89Sderaadt 	strlcpy(parse, string, sizeof parse);
20641eccc89Sderaadt 	targ = strchr(parse, ':');
2076de960dcSmarco 	if (targ == NULL)
20841eccc89Sderaadt 		return ("target not specified");
2096de960dcSmarco 	*targ++ = '\0';
2106de960dcSmarco 
21150d3c4dcSdlg 	lun = strchr(targ, '.');
2126de960dcSmarco 	if (lun != NULL) {
2136de960dcSmarco 		*lun++ = '\0';
21450d3c4dcSdlg 		location->lun = strtonum(lun, 0, 256, &errstr);
21550d3c4dcSdlg 		if (errstr)
21641eccc89Sderaadt 			return (errstr);
2176de960dcSmarco 	} else
2186de960dcSmarco 		location->lun = 0;
2196de960dcSmarco 
22050d3c4dcSdlg 	location->target = strtonum(targ, 0, 256, &errstr);
22150d3c4dcSdlg 	if (errstr)
22241eccc89Sderaadt 		return (errstr);
22341eccc89Sderaadt 	location->channel = strtonum(parse, 0, 256, &errstr);
22450d3c4dcSdlg 	if (errstr)
22541eccc89Sderaadt 		return (errstr);
22641eccc89Sderaadt 	return (NULL);
2276de960dcSmarco }
2286de960dcSmarco 
2293af9de98Smarco void
2308ccdd032Sderaadt bio_inq(char *name)
231d4546a56Sdlg {
2329017fb97Sderaadt 	char *status, size[64], scsiname[16], volname[32];
233a4d3c4a2Sderaadt 	char percent[10], seconds[20];
234b9950701Smarco 	int rv, i, d, volheader, hotspare, unused;
235aa65acf1Sderaadt 	char encname[16], serial[32];
2368ccdd032Sderaadt 	struct bioc_disk bd;
2378ccdd032Sderaadt 	struct bioc_inq bi;
2388ccdd032Sderaadt 	struct bioc_vol bv;
239db2730c1Smarco 
240db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
2413af9de98Smarco 
2423af9de98Smarco 	if (debug)
243db2730c1Smarco 		printf("bio_inq\n");
2443af9de98Smarco 
2458ccdd032Sderaadt 	bi.bi_cookie = bl.bl_cookie;
2463af9de98Smarco 
247db2730c1Smarco 	rv = ioctl(devh, BIOCINQ, &bi);
2483af9de98Smarco 	if (rv == -1) {
2497f33fb8fSderaadt 		warn("BIOCINQ");
2503af9de98Smarco 		return;
2513af9de98Smarco 	}
2523af9de98Smarco 
253a63b0c80Smarco 	if (debug)
254a63b0c80Smarco 		printf("bio_inq { %p, %s, %d, %d }\n",
255a63b0c80Smarco 		    bi.bi_cookie,
256a63b0c80Smarco 		    bi.bi_dev,
257a63b0c80Smarco 		    bi.bi_novol,
258a63b0c80Smarco 		    bi.bi_nodisk);
259a63b0c80Smarco 
2608ccdd032Sderaadt 	volheader = 0;
2618ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
262db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
2638ccdd032Sderaadt 		bv.bv_cookie = bl.bl_cookie;
2648ccdd032Sderaadt 		bv.bv_volid = i;
2650a92ff65Sderaadt 		bv.bv_percent = -1;
2669017fb97Sderaadt 		bv.bv_seconds = 0;
26770a2ae7bSmarco 
268db2730c1Smarco 		rv = ioctl(devh, BIOCVOL, &bv);
2693af9de98Smarco 		if (rv == -1) {
2707f33fb8fSderaadt 			warn("BIOCVOL");
2713af9de98Smarco 			return;
2723af9de98Smarco 		}
2733af9de98Smarco 
2748ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
2758ccdd032Sderaadt 			continue;
2768ccdd032Sderaadt 
2778ccdd032Sderaadt 		if (!volheader) {
2788ccdd032Sderaadt 			volheader = 1;
279c9377e3bSmickey 			printf("%-7s %-10s %14s %-8s\n",
2808ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
2818ccdd032Sderaadt 		}
2828ccdd032Sderaadt 
2830a92ff65Sderaadt 		percent[0] = '\0';
2849017fb97Sderaadt 		seconds[0] = '\0';
2850a92ff65Sderaadt 		if (bv.bv_percent != -1)
2860a92ff65Sderaadt 			snprintf(percent, sizeof percent,
2870a92ff65Sderaadt 			    " %d%% done", bv.bv_percent);
2889017fb97Sderaadt 		if (bv.bv_seconds)
2899017fb97Sderaadt 			snprintf(seconds, sizeof seconds,
2909017fb97Sderaadt 			    " %u seconds", bv.bv_seconds);
2918ccdd032Sderaadt 		switch (bv.bv_status) {
292db2730c1Smarco 		case BIOC_SVONLINE:
2938ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
294db2730c1Smarco 			break;
295db2730c1Smarco 		case BIOC_SVOFFLINE:
2968ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
297db2730c1Smarco 			break;
298db2730c1Smarco 		case BIOC_SVDEGRADED:
2998ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
300db2730c1Smarco 			break;
3010a92ff65Sderaadt 		case BIOC_SVBUILDING:
3020a92ff65Sderaadt 			status = BIOC_SVBUILDING_S;
3030a92ff65Sderaadt 			break;
3040a92ff65Sderaadt 		case BIOC_SVREBUILD:
3050a92ff65Sderaadt 			status = BIOC_SVREBUILD_S;
3060a92ff65Sderaadt 			break;
3070a92ff65Sderaadt 		case BIOC_SVSCRUB:
3080a92ff65Sderaadt 			status = BIOC_SVSCRUB_S;
3090a92ff65Sderaadt 			break;
310db2730c1Smarco 		case BIOC_SVINVALID:
311db2730c1Smarco 		default:
3128ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
313d4546a56Sdlg 		}
3143af9de98Smarco 
315aa65acf1Sderaadt 		snprintf(volname, sizeof volname, "%s %u",
3168ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
317b9950701Smarco 
318aa65acf1Sderaadt 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
319aa65acf1Sderaadt 			hotspare = 1;
320b9950701Smarco 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
321b9950701Smarco 			unused = 1;
322aa65acf1Sderaadt 		else {
323b9950701Smarco 			unused = 0;
324aa65acf1Sderaadt 			hotspare = 0;
325aa65acf1Sderaadt 
3268ccdd032Sderaadt 			if (human)
3278ccdd032Sderaadt 				fmt_scaled(bv.bv_size, size);
3288ccdd032Sderaadt 			else
3298ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
3308ccdd032Sderaadt 				    bv.bv_size);
3319017fb97Sderaadt 			printf("%7s %-10s %14s %-7s RAID%u%s%s\n",
3320a92ff65Sderaadt 			    volname, status, size, bv.bv_dev,
3339017fb97Sderaadt 			    bv.bv_level, percent, seconds);
334aa65acf1Sderaadt 		}
3358ccdd032Sderaadt 
3368ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
337db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
3388ccdd032Sderaadt 			bd.bd_cookie = bl.bl_cookie;
3398ccdd032Sderaadt 			bd.bd_diskid = d;
3408ccdd032Sderaadt 			bd.bd_volid = i;
3413af9de98Smarco 
342db2730c1Smarco 			rv = ioctl(devh, BIOCDISK, &bd);
3433af9de98Smarco 			if (rv == -1) {
3447f33fb8fSderaadt 				warn("BIOCDISK");
3453af9de98Smarco 				return;
3463af9de98Smarco 			}
3473af9de98Smarco 
3488ccdd032Sderaadt 			switch (bd.bd_status) {
349db2730c1Smarco 			case BIOC_SDONLINE:
3508ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
351d4546a56Sdlg 				break;
352db2730c1Smarco 			case BIOC_SDOFFLINE:
3538ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
354d4546a56Sdlg 				break;
355db2730c1Smarco 			case BIOC_SDFAILED:
3568ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
357db2730c1Smarco 				break;
358db2730c1Smarco 			case BIOC_SDREBUILD:
3598ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
360db2730c1Smarco 				break;
361db2730c1Smarco 			case BIOC_SDHOTSPARE:
3628ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
363db2730c1Smarco 				break;
364db2730c1Smarco 			case BIOC_SDUNUSED:
3658ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
366db2730c1Smarco 				break;
367e1dfb373Sderaadt 			case BIOC_SDSCRUB:
368e1dfb373Sderaadt 				status = BIOC_SDSCRUB_S;
369e1dfb373Sderaadt 				break;
370db2730c1Smarco 			case BIOC_SDINVALID:
371d4546a56Sdlg 			default:
3728ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
373d4546a56Sdlg 			}
374aa65acf1Sderaadt 
375b9950701Smarco 			if (hotspare || unused)
376aa65acf1Sderaadt 				;	/* use volname from parent volume */
377aa65acf1Sderaadt 			else
378aa65acf1Sderaadt 				snprintf(volname, sizeof volname, "    %3u",
379aa65acf1Sderaadt 				    bd.bd_diskid);
380aa65acf1Sderaadt 
3818ccdd032Sderaadt 			if (human)
3828ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
3838ccdd032Sderaadt 			else
3848ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
3858ccdd032Sderaadt 				    bd.bd_size);
3868ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
38743d61178Sderaadt 			    "%u:%u.%u",
38843d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
3895978b28dSderaadt 			if (bd.bd_procdev[0])
390abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
3915978b28dSderaadt 			else
392abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
393abe9d68eSderaadt 			if (bd.bd_serial[0])
394abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
395abe9d68eSderaadt 			else
396abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
3978ccdd032Sderaadt 
398aa65acf1Sderaadt 			printf("%7s %-10s %14s %-7s %-6s <%s>\n",
399aa65acf1Sderaadt 			    volname, status, size, scsiname, encname,
4008ccdd032Sderaadt 			    bd.bd_vendor);
401abe9d68eSderaadt 			if (verbose)
402aa65acf1Sderaadt 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
403abe9d68eSderaadt 				    "", "", "", "", "", serial);
404d4546a56Sdlg 		}
405d4546a56Sdlg 	}
406d4546a56Sdlg }
407edfd9792Smarco 
408edfd9792Smarco void
409edfd9792Smarco bio_alarm(char *arg)
410edfd9792Smarco {
411edfd9792Smarco 	int rv;
4128ccdd032Sderaadt 	struct bioc_alarm ba;
413edfd9792Smarco 
4148ccdd032Sderaadt 	ba.ba_cookie = bl.bl_cookie;
415edfd9792Smarco 
416edfd9792Smarco 	switch (arg[0]) {
417edfd9792Smarco 	case 'q': /* silence alarm */
418edfd9792Smarco 		/* FALLTHROUGH */
419edfd9792Smarco 	case 's':
4208ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
421edfd9792Smarco 		break;
422edfd9792Smarco 
423edfd9792Smarco 	case 'e': /* enable alarm */
4248ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
425edfd9792Smarco 		break;
426edfd9792Smarco 
427edfd9792Smarco 	case 'd': /* disable alarm */
4288ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
429edfd9792Smarco 		break;
430edfd9792Smarco 
431edfd9792Smarco 	case 't': /* test alarm */
4328ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
433edfd9792Smarco 		break;
434edfd9792Smarco 
435edfd9792Smarco 	case 'g': /* get alarm state */
4368ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
437edfd9792Smarco 		break;
438edfd9792Smarco 
439edfd9792Smarco 	default:
440edfd9792Smarco 		warnx("invalid alarm function: %s", arg);
441edfd9792Smarco 		return;
442edfd9792Smarco 	}
443edfd9792Smarco 
444edfd9792Smarco 	rv = ioctl(devh, BIOCALARM, &ba);
445edfd9792Smarco 	if (rv == -1) {
4467f33fb8fSderaadt 		warn("BIOCALARM");
447edfd9792Smarco 		return;
448edfd9792Smarco 	}
449edfd9792Smarco 
450edfd9792Smarco 	if (arg[0] == 'g') {
451edfd9792Smarco 		printf("alarm is currently %s\n",
4528ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
4538ccdd032Sderaadt 
454edfd9792Smarco 	}
455edfd9792Smarco }
4566de960dcSmarco 
457ebaf584eSderaadt void
458ebaf584eSderaadt bio_setstate(char *arg)
4596de960dcSmarco {
4606de960dcSmarco 	struct bioc_setstate	bs;
4616de960dcSmarco 	struct locator		location;
46241eccc89Sderaadt 	const char		*errstr;
463ebaf584eSderaadt 	int			rv;
4646de960dcSmarco 
46541eccc89Sderaadt 	errstr = str2locator(arg, &location);
46641eccc89Sderaadt 	if (errstr)
46741eccc89Sderaadt 		errx(1, "Target %s: %s", arg, errstr);
4686de960dcSmarco 
4696de960dcSmarco 	bs.bs_cookie = bl.bl_cookie;
4706de960dcSmarco 	bs.bs_status = BIOC_SSHOTSPARE;
4716de960dcSmarco 	bs.bs_channel = location.channel;
4726de960dcSmarco 	bs.bs_target = location.target;
4736de960dcSmarco 	bs.bs_lun = location.lun;
4746de960dcSmarco 
4756de960dcSmarco 	rv = ioctl(devh, BIOCSETSTATE, &bs);
4766de960dcSmarco 	if (rv == -1) {
4777f33fb8fSderaadt 		warn("BIOCSETSTATE");
4786de960dcSmarco 		return;
4796de960dcSmarco 	}
4806de960dcSmarco }
481c55617f1Sdlg 
482c55617f1Sdlg void
483a928c459Sderaadt bio_setblink(char *name, char *arg, int blink)
484c55617f1Sdlg {
48550d3c4dcSdlg 	struct locator		location;
48650d3c4dcSdlg 	struct bioc_inq		bi;
48750d3c4dcSdlg 	struct bioc_vol		bv;
48850d3c4dcSdlg 	struct bioc_disk	bd;
4890505205bSdlg 	struct bioc_blink	bb;
49041eccc89Sderaadt 	const char		*errstr;
49150d3c4dcSdlg 	int			v, d, rv;
492c55617f1Sdlg 
49341eccc89Sderaadt 	errstr = str2locator(arg, &location);
49441eccc89Sderaadt 	if (errstr)
49541eccc89Sderaadt 		errx(1, "Target %s: %s", arg, errstr);
49650d3c4dcSdlg 
4970505205bSdlg 	/* try setting blink on the device directly */
4980505205bSdlg 	memset(&bb, 0, sizeof(bb));
4990505205bSdlg 	bb.bb_cookie = bl.bl_cookie;
5000505205bSdlg 	bb.bb_status = blink;
5010505205bSdlg 	bb.bb_target = location.target;
502649724a4Smarco 	bb.bb_channel = location.channel;
5030505205bSdlg 	rv = ioctl(devh, BIOCBLINK, &bb);
5040505205bSdlg 	if (rv == 0)
5050505205bSdlg 		return;
5060505205bSdlg 
5070505205bSdlg 	/* if the blink didnt work, try to find something that will */
5080505205bSdlg 
50950d3c4dcSdlg 	memset(&bi, 0, sizeof(bi));
51050d3c4dcSdlg 	bi.bi_cookie = bl.bl_cookie;
51150d3c4dcSdlg 	rv = ioctl(devh, BIOCINQ, &bi);
51250d3c4dcSdlg 	if (rv == -1) {
5137f33fb8fSderaadt 		warn("BIOCINQ");
51450d3c4dcSdlg 		return;
51550d3c4dcSdlg 	}
51650d3c4dcSdlg 
51750d3c4dcSdlg 	for (v = 0; v < bi.bi_novol; v++) {
51850d3c4dcSdlg 		memset(&bv, 0, sizeof(bv));
51950d3c4dcSdlg 		bv.bv_cookie = bl.bl_cookie;
52050d3c4dcSdlg 		bv.bv_volid = v;
52150d3c4dcSdlg 		rv = ioctl(devh, BIOCVOL, &bv);
52250d3c4dcSdlg 		if (rv == -1) {
5237f33fb8fSderaadt 			warn("BIOCVOL");
52450d3c4dcSdlg 			return;
52550d3c4dcSdlg 		}
52650d3c4dcSdlg 
52750d3c4dcSdlg 		if (name && strcmp(name, bv.bv_dev) != 0)
52850d3c4dcSdlg 			continue;
52950d3c4dcSdlg 
53050d3c4dcSdlg 		for (d = 0; d < bv.bv_nodisk; d++) {
53150d3c4dcSdlg 			memset(&bd, 0, sizeof(bd));
53250d3c4dcSdlg 			bd.bd_cookie = bl.bl_cookie;
53350d3c4dcSdlg 			bd.bd_volid = v;
53450d3c4dcSdlg 			bd.bd_diskid = d;
53550d3c4dcSdlg 
53650d3c4dcSdlg 			rv = ioctl(devh, BIOCDISK, &bd);
53750d3c4dcSdlg 			if (rv == -1) {
5387f33fb8fSderaadt 				warn("BIOCDISK");
53950d3c4dcSdlg 				return;
54050d3c4dcSdlg 			}
54150d3c4dcSdlg 
54250d3c4dcSdlg 			if (bd.bd_channel == location.channel &&
54350d3c4dcSdlg 			    bd.bd_target == location.target &&
54450d3c4dcSdlg 			    bd.bd_lun == location.lun) {
54550d3c4dcSdlg 				if (bd.bd_procdev[0] != '\0') {
54650d3c4dcSdlg 					bio_blink(bd.bd_procdev,
547a928c459Sderaadt 					    location.target, blink);
54850d3c4dcSdlg 				} else
54941eccc89Sderaadt 					warnx("Disk %s is not in an enclosure", arg);
55050d3c4dcSdlg 				return;
55150d3c4dcSdlg 			}
55250d3c4dcSdlg 		}
55350d3c4dcSdlg 	}
55450d3c4dcSdlg 
55541eccc89Sderaadt 	warnx("Disk %s does not exist", arg);
55650d3c4dcSdlg 	return;
55750d3c4dcSdlg }
55850d3c4dcSdlg 
55950d3c4dcSdlg void
560a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype)
56150d3c4dcSdlg {
56250d3c4dcSdlg 	int			bioh;
56350d3c4dcSdlg 	struct bio_locate	bio;
56450d3c4dcSdlg 	struct bioc_blink	blink;
56550d3c4dcSdlg 	int			rv;
56650d3c4dcSdlg 
56741eccc89Sderaadt 	bioh = open("/dev/bio", O_RDWR);
56850d3c4dcSdlg 	if (bioh == -1)
56941eccc89Sderaadt 		err(1, "Can't open %s", "/dev/bio");
57050d3c4dcSdlg 
57150d3c4dcSdlg 	bio.bl_name = enclosure;
57250d3c4dcSdlg 	rv = ioctl(bioh, BIOCLOCATE, &bio);
57350d3c4dcSdlg 	if (rv == -1)
57441eccc89Sderaadt 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
575c55617f1Sdlg 
576c55617f1Sdlg 	memset(&blink, 0, sizeof(blink));
57750d3c4dcSdlg 	blink.bb_cookie = bio.bl_cookie;
578a928c459Sderaadt 	blink.bb_status = blinktype;
579c55617f1Sdlg 	blink.bb_target = target;
580c55617f1Sdlg 
58150d3c4dcSdlg 	rv = ioctl(bioh, BIOCBLINK, &blink);
582c55617f1Sdlg 	if (rv == -1)
5837f33fb8fSderaadt 		warn("BIOCBLINK");
58450d3c4dcSdlg 
58550d3c4dcSdlg 	close(bioh);
586c55617f1Sdlg }
587*7195049bSmarco 
588*7195049bSmarco void
589*7195049bSmarco bio_createraid(u_int16_t level, char *dev_list)
590*7195049bSmarco {
591*7195049bSmarco 	struct bio_locate	bio;
592*7195049bSmarco 	struct bioc_createraid	create;
593*7195049bSmarco 	int			rv;
594*7195049bSmarco 	u_int16_t		min_disks = 0;
595*7195049bSmarco 
596*7195049bSmarco 	if (debug)
597*7195049bSmarco 		printf("bio_createraid\n");
598*7195049bSmarco 
599*7195049bSmarco 	if (!dev_list)
600*7195049bSmarco 		errx(1, "no devices specified");
601*7195049bSmarco 
602*7195049bSmarco 	switch (level) {
603*7195049bSmarco 	case 0:
604*7195049bSmarco 		min_disks = 1;
605*7195049bSmarco 		break;
606*7195049bSmarco 	case 1:
607*7195049bSmarco 		min_disks = 2;
608*7195049bSmarco 		break;
609*7195049bSmarco 	default:
610*7195049bSmarco 		errx(1, "unsuported raid level");
611*7195049bSmarco 	}
612*7195049bSmarco 
613*7195049bSmarco 	/* XXX validate device list for real */
614*7195049bSmarco #if 0
615*7195049bSmarco 	if (strncmp(dev_list, "sd", 2) == 0 && strlen(dev_list) > 2 &&
616*7195049bSmarco 	    isdigit(dev_list[2])) {
617*7195049bSmarco 	    	if (strlen(dev_list) != 3)
618*7195049bSmarco 			errx(1, "only one device supported");
619*7195049bSmarco 
620*7195049bSmarco 		if (debug)
621*7195049bSmarco 			printf("bio_createraid: dev_list: %s\n", dev_list);
622*7195049bSmarco 	}
623*7195049bSmarco 	else
624*7195049bSmarco 		errx(1, "no sd device specified");
625*7195049bSmarco #endif
626*7195049bSmarco 
627*7195049bSmarco 	memset(&create, 0, sizeof(create));
628*7195049bSmarco 	create.bc_cookie = bl.bl_cookie;
629*7195049bSmarco 	create.bc_level = level;
630*7195049bSmarco 	create.bc_dev_list_len = strlen(dev_list);
631*7195049bSmarco 	create.bc_dev_list = dev_list;
632*7195049bSmarco 
633*7195049bSmarco 	rv = ioctl(devh, BIOCCREATERAID, &create);
634*7195049bSmarco 	if (rv == -1) {
635*7195049bSmarco 		warn("BIOCCREATERAID");
636*7195049bSmarco 		return;
637*7195049bSmarco 	}
638*7195049bSmarco }
639