xref: /openbsd/sbin/bioctl/bioctl.c (revision abe9d68e)
1*abe9d68eSderaadt /* $OpenBSD: bioctl.c,v 1.27 2005/08/09 01:43:33 deraadt 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;
58*abe9d68eSderaadt int debug;
59*abe9d68eSderaadt int human;
60*abe9d68eSderaadt 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 
77*abe9d68eSderaadt 	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;
92*abe9d68eSderaadt 		case 'v':
93*abe9d68eSderaadt 			verbose = 1;
94*abe9d68eSderaadt 			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,
151*abe9d68eSderaadt 	    "usage: %s [-Dhiv] [-a alarm-function] device\n", __progname);
1523af9de98Smarco 	exit(1);
1533af9de98Smarco }
1543af9de98Smarco 
1553af9de98Smarco void
1568ccdd032Sderaadt bio_inq(char *name)
157d4546a56Sdlg {
158*abe9d68eSderaadt 	char *status, size[64], scsiname[16], encname[16], serial[32];
1598ccdd032Sderaadt 	int rv, i, d, volheader;
1608ccdd032Sderaadt 	struct bioc_disk bd;
1618ccdd032Sderaadt 	struct bioc_inq bi;
1628ccdd032Sderaadt 	struct bioc_vol bv;
163db2730c1Smarco 
164db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
1653af9de98Smarco 
1663af9de98Smarco 	if (debug)
167db2730c1Smarco 		printf("bio_inq\n");
1683af9de98Smarco 
1698ccdd032Sderaadt 	bi.bi_cookie = bl.bl_cookie;
1703af9de98Smarco 
171db2730c1Smarco 	rv = ioctl(devh, BIOCINQ, &bi);
1723af9de98Smarco 	if (rv == -1) {
1733af9de98Smarco 		warnx("bioc_ioctl() call failed");
1743af9de98Smarco 		return;
1753af9de98Smarco 	}
1763af9de98Smarco 
1778ccdd032Sderaadt 	volheader = 0;
1788ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
179db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
1808ccdd032Sderaadt 		bv.bv_cookie = bl.bl_cookie;
1818ccdd032Sderaadt 		bv.bv_volid = i;
18270a2ae7bSmarco 
183db2730c1Smarco 		rv = ioctl(devh, BIOCVOL, &bv);
1843af9de98Smarco 		if (rv == -1) {
1853af9de98Smarco 			warnx("bioc_ioctl() call failed");
1863af9de98Smarco 			return;
1873af9de98Smarco 		}
1883af9de98Smarco 
1898ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
1908ccdd032Sderaadt 			continue;
1918ccdd032Sderaadt 
1928ccdd032Sderaadt 		if (!volheader) {
1938ccdd032Sderaadt 			volheader = 1;
1948ccdd032Sderaadt 			printf("%-7s %-10s %-14s %-8s\n",
1958ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
1968ccdd032Sderaadt 		}
1978ccdd032Sderaadt 
1988ccdd032Sderaadt 		switch (bv.bv_status) {
199db2730c1Smarco 		case BIOC_SVONLINE:
2008ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
201db2730c1Smarco 			break;
202db2730c1Smarco 		case BIOC_SVOFFLINE:
2038ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
204db2730c1Smarco 			break;
205db2730c1Smarco 		case BIOC_SVDEGRADED:
2068ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
207db2730c1Smarco 			break;
208db2730c1Smarco 		case BIOC_SVINVALID:
209db2730c1Smarco 		default:
2108ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
211d4546a56Sdlg 		}
2123af9de98Smarco 
2138ccdd032Sderaadt 		snprintf(scsiname, sizeof scsiname, "%s %u",
2148ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
2158ccdd032Sderaadt 		if (human)
2168ccdd032Sderaadt 			fmt_scaled(bv.bv_size, size);
2178ccdd032Sderaadt 		else
2188ccdd032Sderaadt 			snprintf(size, sizeof size, "%14llu",
2198ccdd032Sderaadt 			    bv.bv_size);
2208ccdd032Sderaadt 		printf("%7s %-10s %14s %-8s RAID%u\n",
2218ccdd032Sderaadt 		    scsiname, status, size, bv.bv_dev, bv.bv_level);
2228ccdd032Sderaadt 
2238ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
224db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
2258ccdd032Sderaadt 			bd.bd_cookie = bl.bl_cookie;
2268ccdd032Sderaadt 			bd.bd_diskid = d;
2278ccdd032Sderaadt 			bd.bd_volid = i;
2283af9de98Smarco 
229db2730c1Smarco 			rv = ioctl(devh, BIOCDISK, &bd);
2303af9de98Smarco 			if (rv == -1) {
2313af9de98Smarco 				warnx("bioc_ioctl() call failed");
2323af9de98Smarco 				return;
2333af9de98Smarco 			}
2343af9de98Smarco 
2358ccdd032Sderaadt 			switch (bd.bd_status) {
236db2730c1Smarco 			case BIOC_SDONLINE:
2378ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
238d4546a56Sdlg 				break;
239db2730c1Smarco 			case BIOC_SDOFFLINE:
2408ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
241d4546a56Sdlg 				break;
242db2730c1Smarco 			case BIOC_SDFAILED:
2438ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
244db2730c1Smarco 				break;
245db2730c1Smarco 			case BIOC_SDREBUILD:
2468ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
247db2730c1Smarco 				break;
248db2730c1Smarco 			case BIOC_SDHOTSPARE:
2498ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
250db2730c1Smarco 				break;
251db2730c1Smarco 			case BIOC_SDUNUSED:
2528ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
253db2730c1Smarco 				break;
254db2730c1Smarco 			case BIOC_SDINVALID:
255d4546a56Sdlg 			default:
2568ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
257d4546a56Sdlg 			}
2588ccdd032Sderaadt 			if (human)
2598ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
2608ccdd032Sderaadt 			else
2618ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
2628ccdd032Sderaadt 				    bd.bd_size);
2638ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
26443d61178Sderaadt 			    "%u:%u.%u",
26543d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
2665978b28dSderaadt 			if (bd.bd_procdev[0])
267*abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
2685978b28dSderaadt 			else
269*abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
270*abe9d68eSderaadt 			if (bd.bd_serial[0])
271*abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
272*abe9d68eSderaadt 			else
273*abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
2748ccdd032Sderaadt 
2758ccdd032Sderaadt 			printf("    %3u %-10s %14s %-7s %-6s <%s>\n",
2768ccdd032Sderaadt 			    bd.bd_diskid, status, size, scsiname, encname,
2778ccdd032Sderaadt 			    bd.bd_vendor);
278*abe9d68eSderaadt 			if (verbose)
279*abe9d68eSderaadt 				printf("    %3s %-10s %14s %-7s %-6s '%s'\n",
280*abe9d68eSderaadt 				    "", "", "", "", "", serial);
281d4546a56Sdlg 		}
282d4546a56Sdlg 	}
2838ccdd032Sderaadt 	/* printf("where are my spares?\n"); */
284d4546a56Sdlg }
285edfd9792Smarco 
286edfd9792Smarco void
287edfd9792Smarco bio_alarm(char *arg)
288edfd9792Smarco {
289edfd9792Smarco 	int rv;
2908ccdd032Sderaadt 	struct bioc_alarm ba;
291edfd9792Smarco 
2928ccdd032Sderaadt 	ba.ba_cookie = bl.bl_cookie;
293edfd9792Smarco 
294edfd9792Smarco 	switch (arg[0]) {
295edfd9792Smarco 	case 'q': /* silence alarm */
296edfd9792Smarco 		/* FALLTHROUGH */
297edfd9792Smarco 	case 's':
2988ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
299edfd9792Smarco 		break;
300edfd9792Smarco 
301edfd9792Smarco 	case 'e': /* enable alarm */
3028ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
303edfd9792Smarco 		break;
304edfd9792Smarco 
305edfd9792Smarco 	case 'd': /* disable alarm */
3068ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
307edfd9792Smarco 		break;
308edfd9792Smarco 
309edfd9792Smarco 	case 't': /* test alarm */
3108ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
311edfd9792Smarco 		break;
312edfd9792Smarco 
313edfd9792Smarco 	case 'g': /* get alarm state */
3148ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
315edfd9792Smarco 		break;
316edfd9792Smarco 
317edfd9792Smarco 	default:
318edfd9792Smarco 		warnx("invalid alarm function: %s", arg);
319edfd9792Smarco 		return;
320edfd9792Smarco 	}
321edfd9792Smarco 
322edfd9792Smarco 	rv = ioctl(devh, BIOCALARM, &ba);
323edfd9792Smarco 	if (rv == -1) {
324edfd9792Smarco 		warnx("bioc_ioctl() call failed");
325edfd9792Smarco 		return;
326edfd9792Smarco 	}
327edfd9792Smarco 
328edfd9792Smarco 	if (arg[0] == 'g') {
329edfd9792Smarco 		printf("alarm is currently %s\n",
3308ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
3318ccdd032Sderaadt 
332edfd9792Smarco 	}
333edfd9792Smarco }
334