xref: /openbsd/sbin/bioctl/bioctl.c (revision b9950701)
1*b9950701Smarco /* $OpenBSD: bioctl.c,v 1.30 2005/08/17 06:31:01 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 
488ccdd032Sderaadt void usage(void);
498ccdd032Sderaadt void cleanup(void);
508ccdd032Sderaadt 
518ccdd032Sderaadt void bio_inq(char *);
528ccdd032Sderaadt void bio_alarm(char *);
533af9de98Smarco 
54c2126c9aSmarco /* globals */
55c2126c9aSmarco const char *bio_device = "/dev/bio";
563af9de98Smarco 
573af9de98Smarco int devh = -1;
58abe9d68eSderaadt int debug;
59abe9d68eSderaadt int human;
60abe9d68eSderaadt int verbose;
613af9de98Smarco 
623af9de98Smarco struct bio_locate bl;
633af9de98Smarco 
643af9de98Smarco int
653af9de98Smarco main(int argc, char *argv[])
663af9de98Smarco {
673af9de98Smarco 	extern char *optarg;
68db2730c1Smarco 	u_int64_t func = 0;
69db2730c1Smarco 	/* u_int64_t subfunc = 0; */
70cf6503d7Sderaadt 	char *bioc_dev = NULL, *sd_dev = NULL;
71cf6503d7Sderaadt 	char *realname = NULL, *al_arg = NULL;
72cf6503d7Sderaadt 	int ch, rv;
733af9de98Smarco 
743af9de98Smarco 	if (argc < 2)
753af9de98Smarco 		usage();
763af9de98Smarco 
77abe9d68eSderaadt 	while ((ch = getopt(argc, argv, "ha:Div")) != -1) {
783af9de98Smarco 		switch (ch) {
79edfd9792Smarco 		case 'a': /* alarm */
80edfd9792Smarco 			func |= BIOC_ALARM;
81edfd9792Smarco 			al_arg = optarg;
82edfd9792Smarco 			break;
83db2730c1Smarco 		case 'D': /* debug */
843af9de98Smarco 			debug = 1;
853af9de98Smarco 			break;
868ccdd032Sderaadt 		case 'h':
878ccdd032Sderaadt 			human = 1;
888ccdd032Sderaadt 			break;
89db2730c1Smarco 		case 'i': /* inquiry */
90db2730c1Smarco 			func |= BIOC_INQ;
913af9de98Smarco 			break;
92abe9d68eSderaadt 		case 'v':
93abe9d68eSderaadt 			verbose = 1;
94abe9d68eSderaadt 			break;
953af9de98Smarco 		default:
963af9de98Smarco 			usage();
973af9de98Smarco 			/* NOTREACHED */
983af9de98Smarco 		}
993af9de98Smarco 	}
100cf6503d7Sderaadt 	argc -= optind;
101cf6503d7Sderaadt 	argv += optind;
1023af9de98Smarco 
1038ccdd032Sderaadt 	if (argc != 1)
104cf6503d7Sderaadt 		usage();
105cf6503d7Sderaadt 
106dcbaf4c8Sderaadt 	if (func == 0)
107dcbaf4c8Sderaadt 		func |= BIOC_INQ;
108dcbaf4c8Sderaadt 
109e4e14ad7Sderaadt 	/* if at least glob sd[0-9]*, it is a drive identifier */
110e4e14ad7Sderaadt 	if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
111e4e14ad7Sderaadt 	    isdigit(argv[0][2]))
112cf6503d7Sderaadt 		sd_dev = argv[0];
113cf6503d7Sderaadt 	else
114cf6503d7Sderaadt 		bioc_dev = argv[0];
11510b411a7Smarco 
11610b411a7Smarco 	if (bioc_dev) {
1173af9de98Smarco 		devh = open(bio_device, O_RDWR);
1183af9de98Smarco 		if (devh == -1)
1193af9de98Smarco 			err(1, "Can't open %s", bio_device);
1203af9de98Smarco 
1218ccdd032Sderaadt 		bl.bl_name = bioc_dev;
1223af9de98Smarco 		rv = ioctl(devh, BIOCLOCATE, &bl);
1233af9de98Smarco 		if (rv == -1)
12410b411a7Smarco 			errx(1, "Can't locate %s device via %s",
1258ccdd032Sderaadt 			    bl.bl_name, bio_device);
126db2730c1Smarco 	} else if (sd_dev) {
12710b411a7Smarco 		devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
12810b411a7Smarco 		if (devh == -1)
12910b411a7Smarco 			err(1, "Can't open %s", sd_dev);
130db2730c1Smarco 	} else
13110b411a7Smarco 		errx(1, "need -d or -f parameter");
1323af9de98Smarco 
1333af9de98Smarco 	if (debug)
1348ccdd032Sderaadt 		warnx("cookie = %p", bl.bl_cookie);
1353af9de98Smarco 
136db2730c1Smarco 	if (func & BIOC_INQ) {
1378ccdd032Sderaadt 		bio_inq(sd_dev);
138edfd9792Smarco 	} else if (func == BIOC_ALARM) {
139edfd9792Smarco 		bio_alarm(al_arg);
1403af9de98Smarco 	}
1413af9de98Smarco 
1423af9de98Smarco 	return (0);
1433af9de98Smarco }
1443af9de98Smarco 
1453af9de98Smarco void
1463af9de98Smarco usage(void)
1473af9de98Smarco {
1483af9de98Smarco 	extern char *__progname;
1493af9de98Smarco 
150cf6503d7Sderaadt 	fprintf(stderr,
151abe9d68eSderaadt 	    "usage: %s [-Dhiv] [-a alarm-function] device\n", __progname);
1523af9de98Smarco 	exit(1);
1533af9de98Smarco }
1543af9de98Smarco 
1553af9de98Smarco void
1568ccdd032Sderaadt bio_inq(char *name)
157d4546a56Sdlg {
158aa65acf1Sderaadt 	char *status, size[64], scsiname[16], volname[32];
159*b9950701Smarco 	int rv, i, d, volheader, hotspare, unused;
160aa65acf1Sderaadt 	char encname[16], serial[32];
1618ccdd032Sderaadt 	struct bioc_disk bd;
1628ccdd032Sderaadt 	struct bioc_inq bi;
1638ccdd032Sderaadt 	struct bioc_vol bv;
164db2730c1Smarco 
165db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
1663af9de98Smarco 
1673af9de98Smarco 	if (debug)
168db2730c1Smarco 		printf("bio_inq\n");
1693af9de98Smarco 
1708ccdd032Sderaadt 	bi.bi_cookie = bl.bl_cookie;
1713af9de98Smarco 
172db2730c1Smarco 	rv = ioctl(devh, BIOCINQ, &bi);
1733af9de98Smarco 	if (rv == -1) {
174*b9950701Smarco 		warnx("bioc_ioctl(BIOCINQ) call failed");
1753af9de98Smarco 		return;
1763af9de98Smarco 	}
1773af9de98Smarco 
1788ccdd032Sderaadt 	volheader = 0;
1798ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
180db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
1818ccdd032Sderaadt 		bv.bv_cookie = bl.bl_cookie;
1828ccdd032Sderaadt 		bv.bv_volid = i;
18370a2ae7bSmarco 
184db2730c1Smarco 		rv = ioctl(devh, BIOCVOL, &bv);
1853af9de98Smarco 		if (rv == -1) {
186*b9950701Smarco 			warnx("bioc_ioctl(BIOCVOL) call failed");
1873af9de98Smarco 			return;
1883af9de98Smarco 		}
1893af9de98Smarco 
1908ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
1918ccdd032Sderaadt 			continue;
1928ccdd032Sderaadt 
1938ccdd032Sderaadt 		if (!volheader) {
1948ccdd032Sderaadt 			volheader = 1;
1958ccdd032Sderaadt 			printf("%-7s %-10s %-14s %-8s\n",
1968ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
1978ccdd032Sderaadt 		}
1988ccdd032Sderaadt 
1998ccdd032Sderaadt 		switch (bv.bv_status) {
200db2730c1Smarco 		case BIOC_SVONLINE:
2018ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
202db2730c1Smarco 			break;
203db2730c1Smarco 		case BIOC_SVOFFLINE:
2048ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
205db2730c1Smarco 			break;
206db2730c1Smarco 		case BIOC_SVDEGRADED:
2078ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
208db2730c1Smarco 			break;
209db2730c1Smarco 		case BIOC_SVINVALID:
210db2730c1Smarco 		default:
2118ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
212d4546a56Sdlg 		}
2133af9de98Smarco 
214aa65acf1Sderaadt 		snprintf(volname, sizeof volname, "%s %u",
2158ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
216*b9950701Smarco 
217aa65acf1Sderaadt 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
218aa65acf1Sderaadt 			hotspare = 1;
219*b9950701Smarco 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
220*b9950701Smarco 			unused = 1;
221aa65acf1Sderaadt 		else {
222*b9950701Smarco 			unused = 0;
223aa65acf1Sderaadt 			hotspare = 0;
224aa65acf1Sderaadt 
2258ccdd032Sderaadt 			if (human)
2268ccdd032Sderaadt 				fmt_scaled(bv.bv_size, size);
2278ccdd032Sderaadt 			else
2288ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
2298ccdd032Sderaadt 				    bv.bv_size);
230813b6523Sderaadt 			printf("%7s %-10s %14s %-7s RAID%u\n",
231aa65acf1Sderaadt 			    volname, status, size, bv.bv_dev, bv.bv_level);
232aa65acf1Sderaadt 		}
2338ccdd032Sderaadt 
2348ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
235db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
2368ccdd032Sderaadt 			bd.bd_cookie = bl.bl_cookie;
2378ccdd032Sderaadt 			bd.bd_diskid = d;
2388ccdd032Sderaadt 			bd.bd_volid = i;
2393af9de98Smarco 
240db2730c1Smarco 			rv = ioctl(devh, BIOCDISK, &bd);
2413af9de98Smarco 			if (rv == -1) {
242*b9950701Smarco 				warnx("bioc_ioctl(BIOCDISK) call failed");
2433af9de98Smarco 				return;
2443af9de98Smarco 			}
2453af9de98Smarco 
2468ccdd032Sderaadt 			switch (bd.bd_status) {
247db2730c1Smarco 			case BIOC_SDONLINE:
2488ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
249d4546a56Sdlg 				break;
250db2730c1Smarco 			case BIOC_SDOFFLINE:
2518ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
252d4546a56Sdlg 				break;
253db2730c1Smarco 			case BIOC_SDFAILED:
2548ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
255db2730c1Smarco 				break;
256db2730c1Smarco 			case BIOC_SDREBUILD:
2578ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
258db2730c1Smarco 				break;
259db2730c1Smarco 			case BIOC_SDHOTSPARE:
2608ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
261db2730c1Smarco 				break;
262db2730c1Smarco 			case BIOC_SDUNUSED:
2638ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
264db2730c1Smarco 				break;
265db2730c1Smarco 			case BIOC_SDINVALID:
266d4546a56Sdlg 			default:
2678ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
268d4546a56Sdlg 			}
269aa65acf1Sderaadt 
270*b9950701Smarco 			if (hotspare || unused)
271aa65acf1Sderaadt 				;	/* use volname from parent volume */
272aa65acf1Sderaadt 			else
273aa65acf1Sderaadt 				snprintf(volname, sizeof volname, "    %3u",
274aa65acf1Sderaadt 				    bd.bd_diskid);
275aa65acf1Sderaadt 
2768ccdd032Sderaadt 			if (human)
2778ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
2788ccdd032Sderaadt 			else
2798ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
2808ccdd032Sderaadt 				    bd.bd_size);
2818ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
28243d61178Sderaadt 			    "%u:%u.%u",
28343d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
2845978b28dSderaadt 			if (bd.bd_procdev[0])
285abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
2865978b28dSderaadt 			else
287abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
288abe9d68eSderaadt 			if (bd.bd_serial[0])
289abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
290abe9d68eSderaadt 			else
291abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
2928ccdd032Sderaadt 
293aa65acf1Sderaadt 			printf("%7s %-10s %14s %-7s %-6s <%s>\n",
294aa65acf1Sderaadt 			    volname, status, size, scsiname, encname,
2958ccdd032Sderaadt 			    bd.bd_vendor);
296abe9d68eSderaadt 			if (verbose)
297aa65acf1Sderaadt 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
298abe9d68eSderaadt 				    "", "", "", "", "", serial);
299d4546a56Sdlg 		}
300d4546a56Sdlg 	}
301d4546a56Sdlg }
302edfd9792Smarco 
303edfd9792Smarco void
304edfd9792Smarco bio_alarm(char *arg)
305edfd9792Smarco {
306edfd9792Smarco 	int rv;
3078ccdd032Sderaadt 	struct bioc_alarm ba;
308edfd9792Smarco 
3098ccdd032Sderaadt 	ba.ba_cookie = bl.bl_cookie;
310edfd9792Smarco 
311edfd9792Smarco 	switch (arg[0]) {
312edfd9792Smarco 	case 'q': /* silence alarm */
313edfd9792Smarco 		/* FALLTHROUGH */
314edfd9792Smarco 	case 's':
3158ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
316edfd9792Smarco 		break;
317edfd9792Smarco 
318edfd9792Smarco 	case 'e': /* enable alarm */
3198ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
320edfd9792Smarco 		break;
321edfd9792Smarco 
322edfd9792Smarco 	case 'd': /* disable alarm */
3238ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
324edfd9792Smarco 		break;
325edfd9792Smarco 
326edfd9792Smarco 	case 't': /* test alarm */
3278ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
328edfd9792Smarco 		break;
329edfd9792Smarco 
330edfd9792Smarco 	case 'g': /* get alarm state */
3318ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
332edfd9792Smarco 		break;
333edfd9792Smarco 
334edfd9792Smarco 	default:
335edfd9792Smarco 		warnx("invalid alarm function: %s", arg);
336edfd9792Smarco 		return;
337edfd9792Smarco 	}
338edfd9792Smarco 
339edfd9792Smarco 	rv = ioctl(devh, BIOCALARM, &ba);
340edfd9792Smarco 	if (rv == -1) {
341edfd9792Smarco 		warnx("bioc_ioctl() call failed");
342edfd9792Smarco 		return;
343edfd9792Smarco 	}
344edfd9792Smarco 
345edfd9792Smarco 	if (arg[0] == 'g') {
346edfd9792Smarco 		printf("alarm is currently %s\n",
3478ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
3488ccdd032Sderaadt 
349edfd9792Smarco 	}
350edfd9792Smarco }
351