xref: /openbsd/sbin/bioctl/bioctl.c (revision c55617f1)
1*c55617f1Sdlg /* $OpenBSD: bioctl.c,v 1.32 2005/08/18 12:19:08 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 #define CT_SEP	':'
496de960dcSmarco #define TL_SEP	'.'
506de960dcSmarco 
516de960dcSmarco struct locator {
526de960dcSmarco 	int channel;
536de960dcSmarco 	int target;
546de960dcSmarco 	int lun;
556de960dcSmarco };
566de960dcSmarco 
578ccdd032Sderaadt void usage(void);
586de960dcSmarco int str2locator(const char *, struct locator *);
598ccdd032Sderaadt void cleanup(void);
608ccdd032Sderaadt 
618ccdd032Sderaadt void bio_inq(char *);
628ccdd032Sderaadt void bio_alarm(char *);
636de960dcSmarco void bio_setstate(char *);
64*c55617f1Sdlg void bio_blink(char *);
653af9de98Smarco 
66c2126c9aSmarco /* globals */
67c2126c9aSmarco const char *bio_device = "/dev/bio";
683af9de98Smarco 
693af9de98Smarco int devh = -1;
70abe9d68eSderaadt int debug;
71abe9d68eSderaadt int human;
72abe9d68eSderaadt int verbose;
733af9de98Smarco 
743af9de98Smarco struct bio_locate bl;
753af9de98Smarco 
763af9de98Smarco int
773af9de98Smarco main(int argc, char *argv[])
783af9de98Smarco {
793af9de98Smarco 	extern char *optarg;
80db2730c1Smarco 	u_int64_t func = 0;
81db2730c1Smarco 	/* u_int64_t subfunc = 0; */
82cf6503d7Sderaadt 	char *bioc_dev = NULL, *sd_dev = NULL;
83cf6503d7Sderaadt 	char *realname = NULL, *al_arg = NULL;
84*c55617f1Sdlg 	char *bl_arg = NULL;
85cf6503d7Sderaadt 	int ch, rv;
863af9de98Smarco 
873af9de98Smarco 	if (argc < 2)
883af9de98Smarco 		usage();
893af9de98Smarco 
90*c55617f1Sdlg 	while ((ch = getopt(argc, argv, "b:H:ha:Div")) != -1) {
913af9de98Smarco 		switch (ch) {
92edfd9792Smarco 		case 'a': /* alarm */
93edfd9792Smarco 			func |= BIOC_ALARM;
94edfd9792Smarco 			al_arg = optarg;
95edfd9792Smarco 			break;
96*c55617f1Sdlg 		case 'b': /* blink */
97*c55617f1Sdlg 			func |= BIOC_BLINK;
98*c55617f1Sdlg 			bl_arg = optarg;
99*c55617f1Sdlg 			break;
100db2730c1Smarco 		case 'D': /* debug */
1013af9de98Smarco 			debug = 1;
1023af9de98Smarco 			break;
1036de960dcSmarco 		case 'H': /* set hotspare */
1046de960dcSmarco 			func |= BIOC_SETSTATE;
1056de960dcSmarco 			al_arg = optarg;
1066de960dcSmarco 			break;
1078ccdd032Sderaadt 		case 'h':
1088ccdd032Sderaadt 			human = 1;
1098ccdd032Sderaadt 			break;
110db2730c1Smarco 		case 'i': /* inquiry */
111db2730c1Smarco 			func |= BIOC_INQ;
1123af9de98Smarco 			break;
113abe9d68eSderaadt 		case 'v':
114abe9d68eSderaadt 			verbose = 1;
115abe9d68eSderaadt 			break;
1163af9de98Smarco 		default:
1173af9de98Smarco 			usage();
1183af9de98Smarco 			/* NOTREACHED */
1193af9de98Smarco 		}
1203af9de98Smarco 	}
121cf6503d7Sderaadt 	argc -= optind;
122cf6503d7Sderaadt 	argv += optind;
1233af9de98Smarco 
1248ccdd032Sderaadt 	if (argc != 1)
125cf6503d7Sderaadt 		usage();
126cf6503d7Sderaadt 
127dcbaf4c8Sderaadt 	if (func == 0)
128dcbaf4c8Sderaadt 		func |= BIOC_INQ;
129dcbaf4c8Sderaadt 
130e4e14ad7Sderaadt 	/* if at least glob sd[0-9]*, it is a drive identifier */
131e4e14ad7Sderaadt 	if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
132e4e14ad7Sderaadt 	    isdigit(argv[0][2]))
133cf6503d7Sderaadt 		sd_dev = argv[0];
134cf6503d7Sderaadt 	else
135cf6503d7Sderaadt 		bioc_dev = argv[0];
13610b411a7Smarco 
13710b411a7Smarco 	if (bioc_dev) {
1383af9de98Smarco 		devh = open(bio_device, O_RDWR);
1393af9de98Smarco 		if (devh == -1)
1403af9de98Smarco 			err(1, "Can't open %s", bio_device);
1413af9de98Smarco 
1428ccdd032Sderaadt 		bl.bl_name = bioc_dev;
1433af9de98Smarco 		rv = ioctl(devh, BIOCLOCATE, &bl);
1443af9de98Smarco 		if (rv == -1)
14510b411a7Smarco 			errx(1, "Can't locate %s device via %s",
1468ccdd032Sderaadt 			    bl.bl_name, bio_device);
147db2730c1Smarco 	} else if (sd_dev) {
14810b411a7Smarco 		devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
14910b411a7Smarco 		if (devh == -1)
15010b411a7Smarco 			err(1, "Can't open %s", sd_dev);
151db2730c1Smarco 	} else
15210b411a7Smarco 		errx(1, "need -d or -f parameter");
1533af9de98Smarco 
1543af9de98Smarco 	if (debug)
1558ccdd032Sderaadt 		warnx("cookie = %p", bl.bl_cookie);
1563af9de98Smarco 
157db2730c1Smarco 	if (func & BIOC_INQ) {
1588ccdd032Sderaadt 		bio_inq(sd_dev);
159edfd9792Smarco 	} else if (func == BIOC_ALARM) {
160edfd9792Smarco 		bio_alarm(al_arg);
161*c55617f1Sdlg 	} else if (func == BIOC_BLINK) {
162*c55617f1Sdlg 		bio_blink(bl_arg);
1636de960dcSmarco 	} else if (func == BIOC_SETSTATE) {
1646de960dcSmarco 		bio_setstate(al_arg);
1653af9de98Smarco 	}
1663af9de98Smarco 
1673af9de98Smarco 	return (0);
1683af9de98Smarco }
1693af9de98Smarco 
1703af9de98Smarco void
1713af9de98Smarco usage(void)
1723af9de98Smarco {
1733af9de98Smarco 	extern char *__progname;
1743af9de98Smarco 
175*c55617f1Sdlg 	fprintf(stderr, "usage: %s [-Dhiv] [-a alarm-function] [-b targ]"
176*c55617f1Sdlg 	    " [-H chan:targ[.lun]] device\n", __progname);
1773af9de98Smarco 	exit(1);
1783af9de98Smarco }
1793af9de98Smarco 
1806de960dcSmarco int
1816de960dcSmarco str2locator(const char *string, struct locator *location)
1826de960dcSmarco {
1836de960dcSmarco 	char *targ, *lun;
1846de960dcSmarco 
1856de960dcSmarco 	targ = strchr(string, CT_SEP);
1866de960dcSmarco 	if (targ == NULL)
1876de960dcSmarco 		return (-1);
1886de960dcSmarco 
1896de960dcSmarco 	*targ++ = '\0';
1906de960dcSmarco 
1916de960dcSmarco 	lun = strchr(targ, TL_SEP);
1926de960dcSmarco 	if (lun != NULL) {
1936de960dcSmarco 		*lun++ = '\0';
1946de960dcSmarco 		location->lun = strtonum(lun, 0, 256 /* XXX */, NULL);
1956de960dcSmarco 		if (errno)
1966de960dcSmarco 			return (-1);
1976de960dcSmarco 	} else
1986de960dcSmarco 		location->lun = 0;
1996de960dcSmarco 
2006de960dcSmarco 	location->target = strtonum(targ, 0, 256 /* XXX */, NULL);
2016de960dcSmarco 	if (errno)
2026de960dcSmarco 		return (-1);
2036de960dcSmarco 
2046de960dcSmarco 	location->channel = strtonum(string, 0, 256 /* XXX */, NULL);
2056de960dcSmarco 	if (errno)
2066de960dcSmarco 		return (-1);
2076de960dcSmarco 
2086de960dcSmarco 	return (0);
2096de960dcSmarco }
2106de960dcSmarco 
2113af9de98Smarco void
2128ccdd032Sderaadt bio_inq(char *name)
213d4546a56Sdlg {
214aa65acf1Sderaadt 	char *status, size[64], scsiname[16], volname[32];
215b9950701Smarco 	int rv, i, d, volheader, hotspare, unused;
216aa65acf1Sderaadt 	char encname[16], serial[32];
2178ccdd032Sderaadt 	struct bioc_disk bd;
2188ccdd032Sderaadt 	struct bioc_inq bi;
2198ccdd032Sderaadt 	struct bioc_vol bv;
220db2730c1Smarco 
221db2730c1Smarco 	memset(&bi, 0, sizeof(bi));
2223af9de98Smarco 
2233af9de98Smarco 	if (debug)
224db2730c1Smarco 		printf("bio_inq\n");
2253af9de98Smarco 
2268ccdd032Sderaadt 	bi.bi_cookie = bl.bl_cookie;
2273af9de98Smarco 
228db2730c1Smarco 	rv = ioctl(devh, BIOCINQ, &bi);
2293af9de98Smarco 	if (rv == -1) {
230b9950701Smarco 		warnx("bioc_ioctl(BIOCINQ) call failed");
2313af9de98Smarco 		return;
2323af9de98Smarco 	}
2333af9de98Smarco 
2348ccdd032Sderaadt 	volheader = 0;
2358ccdd032Sderaadt 	for (i = 0; i < bi.bi_novol; i++) {
236db2730c1Smarco 		memset(&bv, 0, sizeof(bv));
2378ccdd032Sderaadt 		bv.bv_cookie = bl.bl_cookie;
2388ccdd032Sderaadt 		bv.bv_volid = i;
23970a2ae7bSmarco 
240db2730c1Smarco 		rv = ioctl(devh, BIOCVOL, &bv);
2413af9de98Smarco 		if (rv == -1) {
242b9950701Smarco 			warnx("bioc_ioctl(BIOCVOL) call failed");
2433af9de98Smarco 			return;
2443af9de98Smarco 		}
2453af9de98Smarco 
2468ccdd032Sderaadt 		if (name && strcmp(name, bv.bv_dev) != 0)
2478ccdd032Sderaadt 			continue;
2488ccdd032Sderaadt 
2498ccdd032Sderaadt 		if (!volheader) {
2508ccdd032Sderaadt 			volheader = 1;
2518ccdd032Sderaadt 			printf("%-7s %-10s %-14s %-8s\n",
2528ccdd032Sderaadt 			    "Volume", "Status", "Size", "Device");
2538ccdd032Sderaadt 		}
2548ccdd032Sderaadt 
2558ccdd032Sderaadt 		switch (bv.bv_status) {
256db2730c1Smarco 		case BIOC_SVONLINE:
2578ccdd032Sderaadt 			status = BIOC_SVONLINE_S;
258db2730c1Smarco 			break;
259db2730c1Smarco 		case BIOC_SVOFFLINE:
2608ccdd032Sderaadt 			status = BIOC_SVOFFLINE_S;
261db2730c1Smarco 			break;
262db2730c1Smarco 		case BIOC_SVDEGRADED:
2638ccdd032Sderaadt 			status = BIOC_SVDEGRADED_S;
264db2730c1Smarco 			break;
265db2730c1Smarco 		case BIOC_SVINVALID:
266db2730c1Smarco 		default:
2678ccdd032Sderaadt 			status = BIOC_SVINVALID_S;
268d4546a56Sdlg 		}
2693af9de98Smarco 
270aa65acf1Sderaadt 		snprintf(volname, sizeof volname, "%s %u",
2718ccdd032Sderaadt 		    bi.bi_dev, bv.bv_volid);
272b9950701Smarco 
273aa65acf1Sderaadt 		if (bv.bv_level == -1 && bv.bv_nodisk == 1)
274aa65acf1Sderaadt 			hotspare = 1;
275b9950701Smarco 		else if (bv.bv_level == -2 && bv.bv_nodisk == 1)
276b9950701Smarco 			unused = 1;
277aa65acf1Sderaadt 		else {
278b9950701Smarco 			unused = 0;
279aa65acf1Sderaadt 			hotspare = 0;
280aa65acf1Sderaadt 
2818ccdd032Sderaadt 			if (human)
2828ccdd032Sderaadt 				fmt_scaled(bv.bv_size, size);
2838ccdd032Sderaadt 			else
2848ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
2858ccdd032Sderaadt 				    bv.bv_size);
286813b6523Sderaadt 			printf("%7s %-10s %14s %-7s RAID%u\n",
287aa65acf1Sderaadt 			    volname, status, size, bv.bv_dev, bv.bv_level);
288aa65acf1Sderaadt 		}
2898ccdd032Sderaadt 
2908ccdd032Sderaadt 		for (d = 0; d < bv.bv_nodisk; d++) {
291db2730c1Smarco 			memset(&bd, 0, sizeof(bd));
2928ccdd032Sderaadt 			bd.bd_cookie = bl.bl_cookie;
2938ccdd032Sderaadt 			bd.bd_diskid = d;
2948ccdd032Sderaadt 			bd.bd_volid = i;
2953af9de98Smarco 
296db2730c1Smarco 			rv = ioctl(devh, BIOCDISK, &bd);
2973af9de98Smarco 			if (rv == -1) {
298b9950701Smarco 				warnx("bioc_ioctl(BIOCDISK) call failed");
2993af9de98Smarco 				return;
3003af9de98Smarco 			}
3013af9de98Smarco 
3028ccdd032Sderaadt 			switch (bd.bd_status) {
303db2730c1Smarco 			case BIOC_SDONLINE:
3048ccdd032Sderaadt 				status = BIOC_SDONLINE_S;
305d4546a56Sdlg 				break;
306db2730c1Smarco 			case BIOC_SDOFFLINE:
3078ccdd032Sderaadt 				status = BIOC_SDOFFLINE_S;
308d4546a56Sdlg 				break;
309db2730c1Smarco 			case BIOC_SDFAILED:
3108ccdd032Sderaadt 				status = BIOC_SDFAILED_S;
311db2730c1Smarco 				break;
312db2730c1Smarco 			case BIOC_SDREBUILD:
3138ccdd032Sderaadt 				status = BIOC_SDREBUILD_S;
314db2730c1Smarco 				break;
315db2730c1Smarco 			case BIOC_SDHOTSPARE:
3168ccdd032Sderaadt 				status = BIOC_SDHOTSPARE_S;
317db2730c1Smarco 				break;
318db2730c1Smarco 			case BIOC_SDUNUSED:
3198ccdd032Sderaadt 				status = BIOC_SDUNUSED_S;
320db2730c1Smarco 				break;
321db2730c1Smarco 			case BIOC_SDINVALID:
322d4546a56Sdlg 			default:
3238ccdd032Sderaadt 				status = BIOC_SDINVALID_S;
324d4546a56Sdlg 			}
325aa65acf1Sderaadt 
326b9950701Smarco 			if (hotspare || unused)
327aa65acf1Sderaadt 				;	/* use volname from parent volume */
328aa65acf1Sderaadt 			else
329aa65acf1Sderaadt 				snprintf(volname, sizeof volname, "    %3u",
330aa65acf1Sderaadt 				    bd.bd_diskid);
331aa65acf1Sderaadt 
3328ccdd032Sderaadt 			if (human)
3338ccdd032Sderaadt 				fmt_scaled(bd.bd_size, size);
3348ccdd032Sderaadt 			else
3358ccdd032Sderaadt 				snprintf(size, sizeof size, "%14llu",
3368ccdd032Sderaadt 				    bd.bd_size);
3378ccdd032Sderaadt 			snprintf(scsiname, sizeof scsiname,
33843d61178Sderaadt 			    "%u:%u.%u",
33943d61178Sderaadt 			    bd.bd_channel, bd.bd_target, bd.bd_lun);
3405978b28dSderaadt 			if (bd.bd_procdev[0])
341abe9d68eSderaadt 				strlcpy(encname, bd.bd_procdev, sizeof encname);
3425978b28dSderaadt 			else
343abe9d68eSderaadt 				strlcpy(encname, "noencl", sizeof encname);
344abe9d68eSderaadt 			if (bd.bd_serial[0])
345abe9d68eSderaadt 				strlcpy(serial, bd.bd_serial, sizeof serial);
346abe9d68eSderaadt 			else
347abe9d68eSderaadt 				strlcpy(serial, "unknown serial", sizeof serial);
3488ccdd032Sderaadt 
349aa65acf1Sderaadt 			printf("%7s %-10s %14s %-7s %-6s <%s>\n",
350aa65acf1Sderaadt 			    volname, status, size, scsiname, encname,
3518ccdd032Sderaadt 			    bd.bd_vendor);
352abe9d68eSderaadt 			if (verbose)
353aa65acf1Sderaadt 				printf("%7s %-10s %14s %-7s %-6s '%s'\n",
354abe9d68eSderaadt 				    "", "", "", "", "", serial);
355d4546a56Sdlg 		}
356d4546a56Sdlg 	}
357d4546a56Sdlg }
358edfd9792Smarco 
359edfd9792Smarco void
360edfd9792Smarco bio_alarm(char *arg)
361edfd9792Smarco {
362edfd9792Smarco 	int rv;
3638ccdd032Sderaadt 	struct bioc_alarm ba;
364edfd9792Smarco 
3658ccdd032Sderaadt 	ba.ba_cookie = bl.bl_cookie;
366edfd9792Smarco 
367edfd9792Smarco 	switch (arg[0]) {
368edfd9792Smarco 	case 'q': /* silence alarm */
369edfd9792Smarco 		/* FALLTHROUGH */
370edfd9792Smarco 	case 's':
3718ccdd032Sderaadt 		ba.ba_opcode = BIOC_SASILENCE;
372edfd9792Smarco 		break;
373edfd9792Smarco 
374edfd9792Smarco 	case 'e': /* enable alarm */
3758ccdd032Sderaadt 		ba.ba_opcode = BIOC_SAENABLE;
376edfd9792Smarco 		break;
377edfd9792Smarco 
378edfd9792Smarco 	case 'd': /* disable alarm */
3798ccdd032Sderaadt 		ba.ba_opcode = BIOC_SADISABLE;
380edfd9792Smarco 		break;
381edfd9792Smarco 
382edfd9792Smarco 	case 't': /* test alarm */
3838ccdd032Sderaadt 		ba.ba_opcode = BIOC_SATEST;
384edfd9792Smarco 		break;
385edfd9792Smarco 
386edfd9792Smarco 	case 'g': /* get alarm state */
3878ccdd032Sderaadt 		ba.ba_opcode = BIOC_GASTATUS;
388edfd9792Smarco 		break;
389edfd9792Smarco 
390edfd9792Smarco 	default:
391edfd9792Smarco 		warnx("invalid alarm function: %s", arg);
392edfd9792Smarco 		return;
393edfd9792Smarco 	}
394edfd9792Smarco 
395edfd9792Smarco 	rv = ioctl(devh, BIOCALARM, &ba);
396edfd9792Smarco 	if (rv == -1) {
3976de960dcSmarco 		warnx("bioc_ioctl(ALARM) call failed");
398edfd9792Smarco 		return;
399edfd9792Smarco 	}
400edfd9792Smarco 
401edfd9792Smarco 	if (arg[0] == 'g') {
402edfd9792Smarco 		printf("alarm is currently %s\n",
4038ccdd032Sderaadt 		    ba.ba_status ? "enabled" : "disabled");
4048ccdd032Sderaadt 
405edfd9792Smarco 	}
406edfd9792Smarco }
4076de960dcSmarco 
4086de960dcSmarco void bio_setstate(char *arg)
4096de960dcSmarco {
4106de960dcSmarco 	int rv;
4116de960dcSmarco 	struct bioc_setstate bs;
4126de960dcSmarco 	struct locator location;
4136de960dcSmarco 
4146de960dcSmarco 	if (str2locator(arg, &location) != 0)
4156de960dcSmarco 		errx(1, "invalid channel:target[.lun]");
4166de960dcSmarco 
4176de960dcSmarco 
4186de960dcSmarco 	bs.bs_cookie = bl.bl_cookie;
4196de960dcSmarco 	bs.bs_status = BIOC_SSHOTSPARE;
4206de960dcSmarco 	bs.bs_channel = location.channel;
4216de960dcSmarco 	bs.bs_target = location.target;
4226de960dcSmarco 	bs.bs_lun = location.lun;
4236de960dcSmarco 
4246de960dcSmarco 	rv = ioctl(devh, BIOCSETSTATE, &bs);
4256de960dcSmarco 	if (rv == -1) {
4266de960dcSmarco 		warnx("bioc_ioctl(BIOCSETSTATE) call failed");
4276de960dcSmarco 		return;
4286de960dcSmarco 	}
4296de960dcSmarco }
430*c55617f1Sdlg 
431*c55617f1Sdlg void
432*c55617f1Sdlg bio_blink(char *arg)
433*c55617f1Sdlg {
434*c55617f1Sdlg 	struct bioc_blink blink;
435*c55617f1Sdlg 	int target, rv;
436*c55617f1Sdlg 	const char *errstr;
437*c55617f1Sdlg 
438*c55617f1Sdlg 	target = strtonum(arg, 0, 255, &errstr);
439*c55617f1Sdlg 	if (errstr != NULL)
440*c55617f1Sdlg 		errx(1, "target is %s", errstr);
441*c55617f1Sdlg 
442*c55617f1Sdlg 	memset(&blink, 0, sizeof(blink));
443*c55617f1Sdlg 	blink.bb_cookie = bl.bl_cookie;
444*c55617f1Sdlg 	blink.bb_status = BIOC_SBBLINK;
445*c55617f1Sdlg 	blink.bb_target = target;
446*c55617f1Sdlg 
447*c55617f1Sdlg 	rv = ioctl(devh, BIOCBLINK, &blink);
448*c55617f1Sdlg 	if (rv == -1)
449*c55617f1Sdlg 		err(1, "blink unable to be set");
450*c55617f1Sdlg }
451