xref: /openbsd/sbin/bioctl/bioctl.c (revision 0505205b)
1*0505205bSdlg /* $OpenBSD: bioctl.c,v 1.37 2005/08/21 23:37:24 dlg 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);
633af9de98Smarco 
643af9de98Smarco int devh = -1;
65abe9d68eSderaadt int debug;
66abe9d68eSderaadt int human;
67abe9d68eSderaadt int verbose;
683af9de98Smarco 
693af9de98Smarco struct bio_locate bl;
703af9de98Smarco 
713af9de98Smarco int
723af9de98Smarco main(int argc, char *argv[])
733af9de98Smarco {
743af9de98Smarco 	extern char *optarg;
75db2730c1Smarco 	u_int64_t func = 0;
76db2730c1Smarco 	/* u_int64_t subfunc = 0; */
77cf6503d7Sderaadt 	char *bioc_dev = NULL, *sd_dev = NULL;
78cf6503d7Sderaadt 	char *realname = NULL, *al_arg = NULL;
79c55617f1Sdlg 	char *bl_arg = NULL;
80a928c459Sderaadt 	int ch, rv, blink;
813af9de98Smarco 
823af9de98Smarco 	if (argc < 2)
833af9de98Smarco 		usage();
843af9de98Smarco 
85a928c459Sderaadt 	while ((ch = getopt(argc, argv, "b:B:u:H:ha:Div")) != -1) {
863af9de98Smarco 		switch (ch) {
87edfd9792Smarco 		case 'a': /* alarm */
88edfd9792Smarco 			func |= BIOC_ALARM;
89edfd9792Smarco 			al_arg = optarg;
90edfd9792Smarco 			break;
91c55617f1Sdlg 		case 'b': /* blink */
92c55617f1Sdlg 			func |= BIOC_BLINK;
93a928c459Sderaadt 			blink = BIOC_SBBLINK;
94a928c459Sderaadt 			bl_arg = optarg;
95a928c459Sderaadt 			break;
96a928c459Sderaadt 		case 'B': /* alarm blink */
97a928c459Sderaadt 			func |= BIOC_BLINK;
98a928c459Sderaadt 			blink = BIOC_SBALARM;
99a928c459Sderaadt 			bl_arg = optarg;
100a928c459Sderaadt 			break;
101a928c459Sderaadt 		case 'u': /* unblink */
102a928c459Sderaadt 			func |= BIOC_BLINK;
103a928c459Sderaadt 			blink = BIOC_SBUNBLINK;
104c55617f1Sdlg 			bl_arg = optarg;
105c55617f1Sdlg 			break;
106db2730c1Smarco 		case 'D': /* debug */
1073af9de98Smarco 			debug = 1;
1083af9de98Smarco 			break;
1096de960dcSmarco 		case 'H': /* set hotspare */
1106de960dcSmarco 			func |= BIOC_SETSTATE;
1116de960dcSmarco 			al_arg = optarg;
1126de960dcSmarco 			break;
1138ccdd032Sderaadt 		case 'h':
1148ccdd032Sderaadt 			human = 1;
1158ccdd032Sderaadt 			break;
116db2730c1Smarco 		case 'i': /* inquiry */
117db2730c1Smarco 			func |= BIOC_INQ;
1183af9de98Smarco 			break;
119abe9d68eSderaadt 		case 'v':
120abe9d68eSderaadt 			verbose = 1;
121abe9d68eSderaadt 			break;
1223af9de98Smarco 		default:
1233af9de98Smarco 			usage();
1243af9de98Smarco 			/* NOTREACHED */
1253af9de98Smarco 		}
1263af9de98Smarco 	}
127cf6503d7Sderaadt 	argc -= optind;
128cf6503d7Sderaadt 	argv += optind;
1293af9de98Smarco 
1308ccdd032Sderaadt 	if (argc != 1)
131cf6503d7Sderaadt 		usage();
132cf6503d7Sderaadt 
133dcbaf4c8Sderaadt 	if (func == 0)
134dcbaf4c8Sderaadt 		func |= BIOC_INQ;
135dcbaf4c8Sderaadt 
136e4e14ad7Sderaadt 	/* if at least glob sd[0-9]*, it is a drive identifier */
137e4e14ad7Sderaadt 	if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
138e4e14ad7Sderaadt 	    isdigit(argv[0][2]))
139cf6503d7Sderaadt 		sd_dev = argv[0];
140cf6503d7Sderaadt 	else
141cf6503d7Sderaadt 		bioc_dev = argv[0];
14210b411a7Smarco 
14310b411a7Smarco 	if (bioc_dev) {
14441eccc89Sderaadt 		devh = open("/dev/bio", O_RDWR);
1453af9de98Smarco 		if (devh == -1)
14641eccc89Sderaadt 			err(1, "Can't open %s", "/dev/bio");
1473af9de98Smarco 
1488ccdd032Sderaadt 		bl.bl_name = bioc_dev;
1493af9de98Smarco 		rv = ioctl(devh, BIOCLOCATE, &bl);
1503af9de98Smarco 		if (rv == -1)
15110b411a7Smarco 			errx(1, "Can't locate %s device via %s",
15241eccc89Sderaadt 			    bl.bl_name, "/dev/bio");
153db2730c1Smarco 	} else if (sd_dev) {
15410b411a7Smarco 		devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
15510b411a7Smarco 		if (devh == -1)
15610b411a7Smarco 			err(1, "Can't open %s", sd_dev);
157db2730c1Smarco 	} else
15810b411a7Smarco 		errx(1, "need -d or -f parameter");
1593af9de98Smarco 
1603af9de98Smarco 	if (debug)
1618ccdd032Sderaadt 		warnx("cookie = %p", bl.bl_cookie);
1623af9de98Smarco 
163db2730c1Smarco 	if (func & BIOC_INQ) {
1648ccdd032Sderaadt 		bio_inq(sd_dev);
165edfd9792Smarco 	} else if (func == BIOC_ALARM) {
166edfd9792Smarco 		bio_alarm(al_arg);
167c55617f1Sdlg 	} else if (func == BIOC_BLINK) {
168a928c459Sderaadt 		bio_setblink(sd_dev, bl_arg, blink);
1696de960dcSmarco 	} else if (func == BIOC_SETSTATE) {
1706de960dcSmarco 		bio_setstate(al_arg);
1713af9de98Smarco 	}
1723af9de98Smarco 
1733af9de98Smarco 	return (0);
1743af9de98Smarco }
1753af9de98Smarco 
1763af9de98Smarco void
1773af9de98Smarco usage(void)
1783af9de98Smarco {
1793af9de98Smarco 	extern char *__progname;
1803af9de98Smarco 
181ebaf584eSderaadt 	fprintf(stderr, "usage: %s [-Dhiv] [-a alarm-function]"
182a928c459Sderaadt 	    " [[-bBHu] chan:targ[.lun]] device\n", __progname);
1833af9de98Smarco 	exit(1);
1843af9de98Smarco }
1853af9de98Smarco 
18641eccc89Sderaadt const char *
1876de960dcSmarco str2locator(const char *string, struct locator *location)
1886de960dcSmarco {
18950d3c4dcSdlg 	const char *errstr;
19041eccc89Sderaadt 	char parse[80], *targ, *lun;
1916de960dcSmarco 
19241eccc89Sderaadt 	strlcpy(parse, string, sizeof parse);
19341eccc89Sderaadt 	targ = strchr(parse, ':');
1946de960dcSmarco 	if (targ == NULL)
19541eccc89Sderaadt 		return ("target not specified");
1966de960dcSmarco 	*targ++ = '\0';
1976de960dcSmarco 
19850d3c4dcSdlg 	lun = strchr(targ, '.');
1996de960dcSmarco 	if (lun != NULL) {
2006de960dcSmarco 		*lun++ = '\0';
20150d3c4dcSdlg 		location->lun = strtonum(lun, 0, 256, &errstr);
20250d3c4dcSdlg 		if (errstr)
20341eccc89Sderaadt 			return (errstr);
2046de960dcSmarco 	} else
2056de960dcSmarco 		location->lun = 0;
2066de960dcSmarco 
20750d3c4dcSdlg 	location->target = strtonum(targ, 0, 256, &errstr);
20850d3c4dcSdlg 	if (errstr)
20941eccc89Sderaadt 		return (errstr);
21041eccc89Sderaadt 	location->channel = strtonum(parse, 0, 256, &errstr);
21150d3c4dcSdlg 	if (errstr)
21241eccc89Sderaadt 		return (errstr);
21341eccc89Sderaadt 	return (NULL);
2146de960dcSmarco }
2156de960dcSmarco 
2163af9de98Smarco void
2178ccdd032Sderaadt bio_inq(char *name)
218d4546a56Sdlg {
219aa65acf1Sderaadt 	char *status, size[64], scsiname[16], volname[32];
220b9950701Smarco 	int rv, i, d, volheader, hotspare, unused;
221aa65acf1Sderaadt 	char encname[16], serial[32];
2228ccdd032Sderaadt 	struct bioc_disk bd;
2238ccdd032Sderaadt 	struct bioc_inq bi;
2248ccdd032Sderaadt 	struct bioc_vol bv;
225db2730c1Smarco 
226db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
2273af9de98Smarco 
2283af9de98Smarco 	if (debug)
229db2730c1Smarco 		printf("bio_inq\n");
2303af9de98Smarco 
2318ccdd032Sderaadt 	bi.bi_cookie = bl.bl_cookie;
2323af9de98Smarco 
233db2730c1Smarco 	rv = ioctl(devh, BIOCINQ, &bi);
2343af9de98Smarco 	if (rv == -1) {
235b9950701Smarco 		warnx("bioc_ioctl(BIOCINQ) call failed");
2363af9de98Smarco 		return;
2373af9de98Smarco 	}
2383af9de98Smarco 
2398ccdd032Sderaadt 	volheader = 0;
2408ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
241db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
2428ccdd032Sderaadt 		bv.bv_cookie = bl.bl_cookie;
2438ccdd032Sderaadt 		bv.bv_volid = i;
24470a2ae7bSmarco 
245db2730c1Smarco 		rv = ioctl(devh, BIOCVOL, &bv);
2463af9de98Smarco 		if (rv == -1) {
247b9950701Smarco 			warnx("bioc_ioctl(BIOCVOL) call failed");
2483af9de98Smarco 			return;
2493af9de98Smarco 		}
2503af9de98Smarco 
2518ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
2528ccdd032Sderaadt 			continue;
2538ccdd032Sderaadt 
2548ccdd032Sderaadt 		if (!volheader) {
2558ccdd032Sderaadt 			volheader = 1;
2568ccdd032Sderaadt 			printf("%-7s %-10s %-14s %-8s\n",
2578ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
2588ccdd032Sderaadt 		}
2598ccdd032Sderaadt 
2608ccdd032Sderaadt 		switch (bv.bv_status) {
261db2730c1Smarco 		case BIOC_SVONLINE:
2628ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
263db2730c1Smarco 			break;
264db2730c1Smarco 		case BIOC_SVOFFLINE:
2658ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
266db2730c1Smarco 			break;
267db2730c1Smarco 		case BIOC_SVDEGRADED:
2688ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
269db2730c1Smarco 			break;
270db2730c1Smarco 		case BIOC_SVINVALID:
271db2730c1Smarco 		default:
2728ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
273d4546a56Sdlg 		}
2743af9de98Smarco 
275aa65acf1Sderaadt 		snprintf(volname, sizeof volname, "%s %u",
2768ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
277b9950701Smarco 
278aa65acf1Sderaadt 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
279aa65acf1Sderaadt 			hotspare = 1;
280b9950701Smarco 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
281b9950701Smarco 			unused = 1;
282aa65acf1Sderaadt 		else {
283b9950701Smarco 			unused = 0;
284aa65acf1Sderaadt 			hotspare = 0;
285aa65acf1Sderaadt 
2868ccdd032Sderaadt 			if (human)
2878ccdd032Sderaadt 				fmt_scaled(bv.bv_size, size);
2888ccdd032Sderaadt 			else
2898ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
2908ccdd032Sderaadt 				    bv.bv_size);
291813b6523Sderaadt 			printf("%7s %-10s %14s %-7s RAID%u\n",
292aa65acf1Sderaadt 			    volname, status, size, bv.bv_dev, bv.bv_level);
293aa65acf1Sderaadt 		}
2948ccdd032Sderaadt 
2958ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
296db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
2978ccdd032Sderaadt 			bd.bd_cookie = bl.bl_cookie;
2988ccdd032Sderaadt 			bd.bd_diskid = d;
2998ccdd032Sderaadt 			bd.bd_volid = i;
3003af9de98Smarco 
301db2730c1Smarco 			rv = ioctl(devh, BIOCDISK, &bd);
3023af9de98Smarco 			if (rv == -1) {
303b9950701Smarco 				warnx("bioc_ioctl(BIOCDISK) call failed");
3043af9de98Smarco 				return;
3053af9de98Smarco 			}
3063af9de98Smarco 
3078ccdd032Sderaadt 			switch (bd.bd_status) {
308db2730c1Smarco 			case BIOC_SDONLINE:
3098ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
310d4546a56Sdlg 				break;
311db2730c1Smarco 			case BIOC_SDOFFLINE:
3128ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
313d4546a56Sdlg 				break;
314db2730c1Smarco 			case BIOC_SDFAILED:
3158ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
316db2730c1Smarco 				break;
317db2730c1Smarco 			case BIOC_SDREBUILD:
3188ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
319db2730c1Smarco 				break;
320db2730c1Smarco 			case BIOC_SDHOTSPARE:
3218ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
322db2730c1Smarco 				break;
323db2730c1Smarco 			case BIOC_SDUNUSED:
3248ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
325db2730c1Smarco 				break;
326db2730c1Smarco 			case BIOC_SDINVALID:
327d4546a56Sdlg 			default:
3288ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
329d4546a56Sdlg 			}
330aa65acf1Sderaadt 
331b9950701Smarco 			if (hotspare || unused)
332aa65acf1Sderaadt 				;	/* use volname from parent volume */
333aa65acf1Sderaadt 			else
334aa65acf1Sderaadt 				snprintf(volname, sizeof volname, "    %3u",
335aa65acf1Sderaadt 				    bd.bd_diskid);
336aa65acf1Sderaadt 
3378ccdd032Sderaadt 			if (human)
3388ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
3398ccdd032Sderaadt 			else
3408ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
3418ccdd032Sderaadt 				    bd.bd_size);
3428ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
34343d61178Sderaadt 			    "%u:%u.%u",
34443d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
3455978b28dSderaadt 			if (bd.bd_procdev[0])
346abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
3475978b28dSderaadt 			else
348abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
349abe9d68eSderaadt 			if (bd.bd_serial[0])
350abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
351abe9d68eSderaadt 			else
352abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
3538ccdd032Sderaadt 
354aa65acf1Sderaadt 			printf("%7s %-10s %14s %-7s %-6s <%s>\n",
355aa65acf1Sderaadt 			    volname, status, size, scsiname, encname,
3568ccdd032Sderaadt 			    bd.bd_vendor);
357abe9d68eSderaadt 			if (verbose)
358aa65acf1Sderaadt 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
359abe9d68eSderaadt 				    "", "", "", "", "", serial);
360d4546a56Sdlg 		}
361d4546a56Sdlg 	}
362d4546a56Sdlg }
363edfd9792Smarco 
364edfd9792Smarco void
365edfd9792Smarco bio_alarm(char *arg)
366edfd9792Smarco {
367edfd9792Smarco 	int rv;
3688ccdd032Sderaadt 	struct bioc_alarm ba;
369edfd9792Smarco 
3708ccdd032Sderaadt 	ba.ba_cookie = bl.bl_cookie;
371edfd9792Smarco 
372edfd9792Smarco 	switch (arg[0]) {
373edfd9792Smarco 	case 'q': /* silence alarm */
374edfd9792Smarco 		/* FALLTHROUGH */
375edfd9792Smarco 	case 's':
3768ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
377edfd9792Smarco 		break;
378edfd9792Smarco 
379edfd9792Smarco 	case 'e': /* enable alarm */
3808ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
381edfd9792Smarco 		break;
382edfd9792Smarco 
383edfd9792Smarco 	case 'd': /* disable alarm */
3848ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
385edfd9792Smarco 		break;
386edfd9792Smarco 
387edfd9792Smarco 	case 't': /* test alarm */
3888ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
389edfd9792Smarco 		break;
390edfd9792Smarco 
391edfd9792Smarco 	case 'g': /* get alarm state */
3928ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
393edfd9792Smarco 		break;
394edfd9792Smarco 
395edfd9792Smarco 	default:
396edfd9792Smarco 		warnx("invalid alarm function: %s", arg);
397edfd9792Smarco 		return;
398edfd9792Smarco 	}
399edfd9792Smarco 
400edfd9792Smarco 	rv = ioctl(devh, BIOCALARM, &ba);
401edfd9792Smarco 	if (rv == -1) {
4026de960dcSmarco 		warnx("bioc_ioctl(ALARM) call failed");
403edfd9792Smarco 		return;
404edfd9792Smarco 	}
405edfd9792Smarco 
406edfd9792Smarco 	if (arg[0] == 'g') {
407edfd9792Smarco 		printf("alarm is currently %s\n",
4088ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
4098ccdd032Sderaadt 
410edfd9792Smarco 	}
411edfd9792Smarco }
4126de960dcSmarco 
413ebaf584eSderaadt void
414ebaf584eSderaadt bio_setstate(char *arg)
4156de960dcSmarco {
4166de960dcSmarco 	struct bioc_setstate	bs;
4176de960dcSmarco 	struct locator		location;
41841eccc89Sderaadt 	const char		*errstr;
419ebaf584eSderaadt 	int			rv;
4206de960dcSmarco 
42141eccc89Sderaadt 	errstr = str2locator(arg, &location);
42241eccc89Sderaadt 	if (errstr)
42341eccc89Sderaadt 		errx(1, "Target %s: %s", arg, errstr);
4246de960dcSmarco 
4256de960dcSmarco 	bs.bs_cookie = bl.bl_cookie;
4266de960dcSmarco 	bs.bs_status = BIOC_SSHOTSPARE;
4276de960dcSmarco 	bs.bs_channel = location.channel;
4286de960dcSmarco 	bs.bs_target = location.target;
4296de960dcSmarco 	bs.bs_lun = location.lun;
4306de960dcSmarco 
4316de960dcSmarco 	rv = ioctl(devh, BIOCSETSTATE, &bs);
4326de960dcSmarco 	if (rv == -1) {
4336de960dcSmarco 		warnx("bioc_ioctl(BIOCSETSTATE) call failed");
4346de960dcSmarco 		return;
4356de960dcSmarco 	}
4366de960dcSmarco }
437c55617f1Sdlg 
438c55617f1Sdlg void
439a928c459Sderaadt bio_setblink(char *name, char *arg, int blink)
440c55617f1Sdlg {
44150d3c4dcSdlg 	struct locator		location;
44250d3c4dcSdlg 	struct bioc_inq		bi;
44350d3c4dcSdlg 	struct bioc_vol		bv;
44450d3c4dcSdlg 	struct bioc_disk	bd;
445*0505205bSdlg 	struct bioc_blink	bb;
44641eccc89Sderaadt 	const char		*errstr;
44750d3c4dcSdlg 	int			v, d, rv;
448c55617f1Sdlg 
44941eccc89Sderaadt 	errstr = str2locator(arg, &location);
45041eccc89Sderaadt 	if (errstr)
45141eccc89Sderaadt 		errx(1, "Target %s: %s", arg, errstr);
45250d3c4dcSdlg 
453*0505205bSdlg 	/* try setting blink on the device directly */
454*0505205bSdlg 	memset(&bb, 0, sizeof(bb));
455*0505205bSdlg 	bb.bb_cookie = bl.bl_cookie;
456*0505205bSdlg 	bb.bb_status = blink;
457*0505205bSdlg 	bb.bb_target = location.target;
458*0505205bSdlg 	rv = ioctl(devh, BIOCBLINK, &bb);
459*0505205bSdlg 	if (rv == 0)
460*0505205bSdlg 		return;
461*0505205bSdlg 
462*0505205bSdlg 	/* if the blink didnt work, try to find something that will */
463*0505205bSdlg 
46450d3c4dcSdlg 	memset(&bi, 0, sizeof(bi));
46550d3c4dcSdlg 	bi.bi_cookie = bl.bl_cookie;
46650d3c4dcSdlg 	rv = ioctl(devh, BIOCINQ, &bi);
46750d3c4dcSdlg 	if (rv == -1) {
46850d3c4dcSdlg 		warn("bio ioctl(BIOCINQ) call failed");
46950d3c4dcSdlg 		return;
47050d3c4dcSdlg 	}
47150d3c4dcSdlg 
47250d3c4dcSdlg 	for (v = 0; v < bi.bi_novol; v++) {
47350d3c4dcSdlg 		memset(&bv, 0, sizeof(bv));
47450d3c4dcSdlg 		bv.bv_cookie = bl.bl_cookie;
47550d3c4dcSdlg 		bv.bv_volid = v;
47650d3c4dcSdlg 		rv = ioctl(devh, BIOCVOL, &bv);
47750d3c4dcSdlg 		if (rv == -1) {
47850d3c4dcSdlg 			warn("bio ioctl(BIOCVOL) call failed");
47950d3c4dcSdlg 			return;
48050d3c4dcSdlg 		}
48150d3c4dcSdlg 
48250d3c4dcSdlg 		if (name && strcmp(name, bv.bv_dev) != 0)
48350d3c4dcSdlg 			continue;
48450d3c4dcSdlg 
48550d3c4dcSdlg 		for (d = 0; d < bv.bv_nodisk; d++) {
48650d3c4dcSdlg 			memset(&bd, 0, sizeof(bd));
48750d3c4dcSdlg 			bd.bd_cookie = bl.bl_cookie;
48850d3c4dcSdlg 			bd.bd_volid = v;
48950d3c4dcSdlg 			bd.bd_diskid = d;
49050d3c4dcSdlg 
49150d3c4dcSdlg 			rv = ioctl(devh, BIOCDISK, &bd);
49250d3c4dcSdlg 			if (rv == -1) {
49350d3c4dcSdlg 				warn("bio ioctl(BIOCDISK) call failed");
49450d3c4dcSdlg 				return;
49550d3c4dcSdlg 			}
49650d3c4dcSdlg 
49750d3c4dcSdlg 			if (bd.bd_channel == location.channel &&
49850d3c4dcSdlg 			    bd.bd_target == location.target &&
49950d3c4dcSdlg 			    bd.bd_lun == location.lun) {
50050d3c4dcSdlg 				if (bd.bd_procdev[0] != '\0') {
50150d3c4dcSdlg 					bio_blink(bd.bd_procdev,
502a928c459Sderaadt 					    location.target, blink);
50350d3c4dcSdlg 				} else
50441eccc89Sderaadt 					warnx("Disk %s is not in an enclosure", arg);
50550d3c4dcSdlg 				return;
50650d3c4dcSdlg 			}
50750d3c4dcSdlg 		}
50850d3c4dcSdlg 	}
50950d3c4dcSdlg 
51041eccc89Sderaadt 	warnx("Disk %s does not exist", arg);
51150d3c4dcSdlg 	return;
51250d3c4dcSdlg }
51350d3c4dcSdlg 
51450d3c4dcSdlg void
515a928c459Sderaadt bio_blink(char *enclosure, int target, int blinktype)
51650d3c4dcSdlg {
51750d3c4dcSdlg 	int			bioh;
51850d3c4dcSdlg 	struct bio_locate	bio;
51950d3c4dcSdlg 	struct bioc_blink	blink;
52050d3c4dcSdlg 	int			rv;
52150d3c4dcSdlg 
52241eccc89Sderaadt 	bioh = open("/dev/bio", O_RDWR);
52350d3c4dcSdlg 	if (bioh == -1)
52441eccc89Sderaadt 		err(1, "Can't open %s", "/dev/bio");
52550d3c4dcSdlg 
52650d3c4dcSdlg 	bio.bl_name = enclosure;
52750d3c4dcSdlg 	rv = ioctl(bioh, BIOCLOCATE, &bio);
52850d3c4dcSdlg 	if (rv == -1)
52941eccc89Sderaadt 		errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
530c55617f1Sdlg 
531c55617f1Sdlg 	memset(&blink, 0, sizeof(blink));
53250d3c4dcSdlg 	blink.bb_cookie = bio.bl_cookie;
533a928c459Sderaadt 	blink.bb_status = blinktype;
534c55617f1Sdlg 	blink.bb_target = target;
535c55617f1Sdlg 
53650d3c4dcSdlg 	rv = ioctl(bioh, BIOCBLINK, &blink);
537c55617f1Sdlg 	if (rv == -1)
53850d3c4dcSdlg 		warn("bio ioctl(BIOCBLINK) call failed");
53950d3c4dcSdlg 
54050d3c4dcSdlg 	close(bioh);
541c55617f1Sdlg }
542