xref: /openbsd/sbin/bioctl/bioctl.c (revision 3af9de98)
1*3af9de98Smarco /* $OpenBSD: bioctl.c,v 1.1 2005/03/29 22:04:21 marco Exp $       */
2*3af9de98Smarco /*
3*3af9de98Smarco  * Copyright (c) 2004 Marco Peereboom
4*3af9de98Smarco  * All rights reserved.
5*3af9de98Smarco  *
6*3af9de98Smarco  * Redistribution and use in source and binary forms, with or without
7*3af9de98Smarco  * modification, are permitted provided that the following conditions
8*3af9de98Smarco  * are met:
9*3af9de98Smarco  * 1. Redistributions of source code must retain the above copyright
10*3af9de98Smarco  *    notice, this list of conditions and the following disclaimer.
11*3af9de98Smarco  * 2. Redistributions in binary form must reproduce the above copyright
12*3af9de98Smarco  *    notice, this list of conditions and the following disclaimer in the
13*3af9de98Smarco  *    documentation and/or other materials provided with the distribution.
14*3af9de98Smarco  *
15*3af9de98Smarco  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16*3af9de98Smarco  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*3af9de98Smarco  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*3af9de98Smarco  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
19*3af9de98Smarco  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*3af9de98Smarco  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*3af9de98Smarco  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*3af9de98Smarco  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*3af9de98Smarco  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*3af9de98Smarco  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*3af9de98Smarco  * SUCH DAMAGE.
26*3af9de98Smarco  *
27*3af9de98Smarco  */
28*3af9de98Smarco 
29*3af9de98Smarco #include <sys/ioctl.h>
30*3af9de98Smarco #include <sys/param.h>
31*3af9de98Smarco #include <sys/queue.h>
32*3af9de98Smarco #include <scsi/scsi_disk.h>
33*3af9de98Smarco 
34*3af9de98Smarco #include <fcntl.h>
35*3af9de98Smarco #include <stdio.h>
36*3af9de98Smarco #include <stdlib.h>
37*3af9de98Smarco #include <unistd.h>
38*3af9de98Smarco 
39*3af9de98Smarco #include <dev/biovar.h>
40*3af9de98Smarco 
41*3af9de98Smarco #define READCAP 0x01
42*3af9de98Smarco #define ENUM    0x02
43*3af9de98Smarco #define TUR     0x04
44*3af9de98Smarco #define INQUIRY 0x08
45*3af9de98Smarco 
46*3af9de98Smarco struct read_cap {
47*3af9de98Smarco 	u_int32_t		maxlba;
48*3af9de98Smarco 	u_int32_t		bsize;
49*3af9de98Smarco };
50*3af9de98Smarco 
51*3af9de98Smarco struct dev {
52*3af9de98Smarco 	SLIST_ENTRY(dev)	next;
53*3af9de98Smarco 	u_int16_t		id;
54*3af9de98Smarco 	u_int8_t		channel;
55*3af9de98Smarco 	u_int8_t		target;
56*3af9de98Smarco 	u_int64_t		capacity;
57*3af9de98Smarco };
58*3af9de98Smarco 
59*3af9de98Smarco void		usage(void);
60*3af9de98Smarco void		cleanup(void);
61*3af9de98Smarco u_int64_t	parse_passthru(char *);
62*3af9de98Smarco void		parse_devlist(char *);
63*3af9de98Smarco void		print_sense(u_int8_t *, u_int8_t);
64*3af9de98Smarco 
65*3af9de98Smarco int		bio_get_capabilities(bioc_capabilities *);
66*3af9de98Smarco void		bio_alarm(char *);
67*3af9de98Smarco void		bio_ping(void);
68*3af9de98Smarco void		bio_startstop(char *, u_int8_t, u_int8_t);
69*3af9de98Smarco void		bio_status(void);
70*3af9de98Smarco u_int64_t	bio_pt_readcap(u_int8_t, u_int8_t);
71*3af9de98Smarco u_int32_t	bio_pt_inquire(u_int8_t, u_int8_t, u_int8_t *);
72*3af9de98Smarco u_int32_t	bio_pt_tur(u_int8_t, u_int8_t);
73*3af9de98Smarco void		bio_pt_enum(void);
74*3af9de98Smarco 
75*3af9de98Smarco SLIST_HEAD(dev_list, dev);
76*3af9de98Smarco 
77*3af9de98Smarco /* RAID card device list */
78*3af9de98Smarco struct dev_list devices = SLIST_HEAD_INITIALIZER(dev);
79*3af9de98Smarco /* User provided device list*/
80*3af9de98Smarco struct dev_list ul = SLIST_HEAD_INITIALIZER(dev);
81*3af9de98Smarco 
82*3af9de98Smarco char *bio_device = "/dev/bio";
83*3af9de98Smarco 
84*3af9de98Smarco int devh = -1;
85*3af9de98Smarco int debug = 0;
86*3af9de98Smarco 
87*3af9de98Smarco struct bio_locate bl;
88*3af9de98Smarco 
89*3af9de98Smarco #define PARSELIST (0x8000000000000000llu)
90*3af9de98Smarco int
91*3af9de98Smarco main(int argc, char *argv[])
92*3af9de98Smarco {
93*3af9de98Smarco 	extern char *optarg;
94*3af9de98Smarco 
95*3af9de98Smarco 	bioc_capabilities bc;
96*3af9de98Smarco 	bioc_alarm ba;
97*3af9de98Smarco 
98*3af9de98Smarco 	int ch;
99*3af9de98Smarco 	int rv;
100*3af9de98Smarco 	unsigned char *pl;
101*3af9de98Smarco 
102*3af9de98Smarco 	char *bioc_dev = NULL;
103*3af9de98Smarco 	char *al_arg = NULL; /* argument to alarm */
104*3af9de98Smarco 	char *ss_arg = NULL; /* argument to start/stop */
105*3af9de98Smarco 	char inq[36];
106*3af9de98Smarco 
107*3af9de98Smarco 	struct dev *delm;
108*3af9de98Smarco 
109*3af9de98Smarco 	u_int64_t func = 0, subfunc = 0;
110*3af9de98Smarco 	u_int32_t devlist = 0;
111*3af9de98Smarco 
112*3af9de98Smarco 	if (argc < 2)
113*3af9de98Smarco 		usage();
114*3af9de98Smarco 
115*3af9de98Smarco 	atexit(cleanup);
116*3af9de98Smarco 
117*3af9de98Smarco 	while ((ch = getopt(argc, argv, "a:Dd:ehl:pst:u:")) != -1) {
118*3af9de98Smarco 		switch (ch) {
119*3af9de98Smarco 		case 'a': /* alarm */
120*3af9de98Smarco 			func |= BIOC_ALARM;
121*3af9de98Smarco 			al_arg = optarg;
122*3af9de98Smarco 			break;
123*3af9de98Smarco 
124*3af9de98Smarco 		case 'D': /* enable debug */
125*3af9de98Smarco 			debug = 1;
126*3af9de98Smarco 			break;
127*3af9de98Smarco 
128*3af9de98Smarco 		case 'd': /* device */
129*3af9de98Smarco 			bioc_dev = optarg;
130*3af9de98Smarco 			break;
131*3af9de98Smarco 
132*3af9de98Smarco 		case 'e': /* enumerate */
133*3af9de98Smarco 			func |= BIOC_SCSICMD;
134*3af9de98Smarco 			subfunc |= ENUM;
135*3af9de98Smarco 			break;
136*3af9de98Smarco 
137*3af9de98Smarco 		case 'l': /* device list, separated for now use one dev only*/
138*3af9de98Smarco 			func |= PARSELIST;
139*3af9de98Smarco 			pl = optarg;
140*3af9de98Smarco 			break;
141*3af9de98Smarco 
142*3af9de98Smarco 		case 'p': /* ping */
143*3af9de98Smarco 			func |= BIOC_PING;
144*3af9de98Smarco 			break;
145*3af9de98Smarco 
146*3af9de98Smarco 		case 's': /* status */
147*3af9de98Smarco 			func |= BIOC_STATUS;
148*3af9de98Smarco 			break;
149*3af9de98Smarco 
150*3af9de98Smarco 		case 't':
151*3af9de98Smarco 			func |= BIOC_SCSICMD;
152*3af9de98Smarco 			subfunc |= parse_passthru(optarg);
153*3af9de98Smarco 			break;
154*3af9de98Smarco 
155*3af9de98Smarco 		case 'u': /* start/stop */
156*3af9de98Smarco 			func |= BIOC_STARTSTOP;
157*3af9de98Smarco 			ss_arg = optarg;
158*3af9de98Smarco 			break;
159*3af9de98Smarco 
160*3af9de98Smarco 		case 'h': /* help/usage */
161*3af9de98Smarco 			/* FALLTHROUGH */
162*3af9de98Smarco 		default:
163*3af9de98Smarco 			usage();
164*3af9de98Smarco 			/* NOTREACHED */
165*3af9de98Smarco 		}
166*3af9de98Smarco 	}
167*3af9de98Smarco 
168*3af9de98Smarco 	devh = open(bio_device, O_RDWR);
169*3af9de98Smarco 	if (devh == -1)
170*3af9de98Smarco 		err(1, "Can't open %s", bio_device);
171*3af9de98Smarco 
172*3af9de98Smarco 	bl.name = bioc_dev;
173*3af9de98Smarco 	rv = ioctl(devh, BIOCLOCATE, &bl);
174*3af9de98Smarco 	if (rv == -1)
175*3af9de98Smarco 		errx(1, "Can't locate %s device via %s", bl.name, bio_device);
176*3af9de98Smarco 
177*3af9de98Smarco 	if (debug)
178*3af9de98Smarco 		warnx("cookie = %p", bl.cookie);
179*3af9de98Smarco 
180*3af9de98Smarco 	if (func & PARSELIST)
181*3af9de98Smarco 		parse_devlist(pl);
182*3af9de98Smarco 
183*3af9de98Smarco 	if (!bio_get_capabilities(&bc))
184*3af9de98Smarco 		warnx("could not retrieve capabilities.");
185*3af9de98Smarco 	else {
186*3af9de98Smarco 		/* we should have everything setup by now so get to work */
187*3af9de98Smarco 		if (func & BIOC_ALARM)
188*3af9de98Smarco 			if (bc.ioctls & BIOC_ALARM)
189*3af9de98Smarco 				bio_alarm(al_arg);
190*3af9de98Smarco 			else
191*3af9de98Smarco 				warnx("alarms are not supported.");
192*3af9de98Smarco 
193*3af9de98Smarco 		if (func & BIOC_PING)
194*3af9de98Smarco 			if (bc.ioctls & BIOC_PING)
195*3af9de98Smarco 				bio_ping();
196*3af9de98Smarco 			else
197*3af9de98Smarco 				warnx("ping not supported.");
198*3af9de98Smarco 
199*3af9de98Smarco 		if (func & BIOC_STATUS) {
200*3af9de98Smarco 			if (bc.ioctls & BIOC_STATUS)
201*3af9de98Smarco 				bio_status();
202*3af9de98Smarco 			else
203*3af9de98Smarco 				warnx("status function not supported.");
204*3af9de98Smarco 		}
205*3af9de98Smarco 
206*3af9de98Smarco 		if (func & BIOC_STARTSTOP) {
207*3af9de98Smarco 			if (bc.ioctls & BIOC_STARTSTOP) {
208*3af9de98Smarco 				SLIST_FOREACH(delm, &ul, next) {
209*3af9de98Smarco 					bio_startstop(ss_arg,
210*3af9de98Smarco 					    delm->channel, delm->target);
211*3af9de98Smarco 				}
212*3af9de98Smarco 			} else
213*3af9de98Smarco 				warnx("start/stop unit not supported.");
214*3af9de98Smarco 		}
215*3af9de98Smarco 
216*3af9de98Smarco 		if (func & BIOC_SCSICMD) {
217*3af9de98Smarco 			if (bc.ioctls & BIOC_SCSICMD) {
218*3af9de98Smarco 				if (subfunc & READCAP) {
219*3af9de98Smarco 					SLIST_FOREACH(delm, &ul, next) {
220*3af9de98Smarco 						bio_pt_readcap(delm->channel,
221*3af9de98Smarco 						    delm->target);
222*3af9de98Smarco 					}
223*3af9de98Smarco 				}
224*3af9de98Smarco 
225*3af9de98Smarco 				if (subfunc & INQUIRY) {
226*3af9de98Smarco 					SLIST_FOREACH(delm, &ul, next) {
227*3af9de98Smarco 						bio_pt_inquire(delm->channel,
228*3af9de98Smarco 						    delm->target, &inq[0]);
229*3af9de98Smarco 					}
230*3af9de98Smarco 				}
231*3af9de98Smarco 
232*3af9de98Smarco 				if (subfunc & TUR) {
233*3af9de98Smarco 					SLIST_FOREACH(delm, &ul, next) {
234*3af9de98Smarco 						bio_pt_tur(delm->channel,
235*3af9de98Smarco 						    delm->target);
236*3af9de98Smarco 					}
237*3af9de98Smarco 				}
238*3af9de98Smarco 
239*3af9de98Smarco 				if (subfunc & ENUM)
240*3af9de98Smarco 					bio_pt_enum();
241*3af9de98Smarco 			} else
242*3af9de98Smarco 				warnx("passthrough not supported.");
243*3af9de98Smarco 		}
244*3af9de98Smarco 	}
245*3af9de98Smarco 
246*3af9de98Smarco 	return (0);
247*3af9de98Smarco }
248*3af9de98Smarco 
249*3af9de98Smarco void
250*3af9de98Smarco usage(void)
251*3af9de98Smarco {
252*3af9de98Smarco 	extern char *__progname;
253*3af9de98Smarco 
254*3af9de98Smarco 	fprintf(stderr, "usage: %s [-Dehpt] [-a alarm function] [-s get status]"
255*3af9de98Smarco 	    "[-t passthrough] [-l device list] [-u go/stop function ] "
256*3af9de98Smarco 	    "-d raid device\n", __progname);
257*3af9de98Smarco 
258*3af9de98Smarco 	exit(1);
259*3af9de98Smarco }
260*3af9de98Smarco 
261*3af9de98Smarco void
262*3af9de98Smarco cleanup(void)
263*3af9de98Smarco {
264*3af9de98Smarco 	struct dev *delm;
265*3af9de98Smarco 
266*3af9de98Smarco 	if (debug)
267*3af9de98Smarco 		printf("atexit\n");
268*3af9de98Smarco 
269*3af9de98Smarco 	while (devices.slh_first != NULL) {
270*3af9de98Smarco 		delm = devices.slh_first;
271*3af9de98Smarco 		SLIST_REMOVE_HEAD(&devices, next);
272*3af9de98Smarco 		if (debug)
273*3af9de98Smarco 			printf("free device: %p\n", delm);
274*3af9de98Smarco 		free(delm);
275*3af9de98Smarco 	}
276*3af9de98Smarco 
277*3af9de98Smarco 	while (ul.slh_first != NULL) {
278*3af9de98Smarco 		delm = ul.slh_first;
279*3af9de98Smarco 		SLIST_REMOVE_HEAD(&ul, next);
280*3af9de98Smarco 		if (debug)
281*3af9de98Smarco 			printf("free ul: %p\n", delm);
282*3af9de98Smarco 		free(delm);
283*3af9de98Smarco 	}
284*3af9de98Smarco 
285*3af9de98Smarco 	if (devh != -1)
286*3af9de98Smarco 		close(devh);
287*3af9de98Smarco }
288*3af9de98Smarco 
289*3af9de98Smarco u_int64_t
290*3af9de98Smarco parse_passthru(char *f)
291*3af9de98Smarco {
292*3af9de98Smarco 	if (debug)
293*3af9de98Smarco 		printf("get_subfunc: %s, ", f);
294*3af9de98Smarco 
295*3af9de98Smarco 	switch (f[0]) {
296*3af9de98Smarco 	case 'i': /* INQUIRY */
297*3af9de98Smarco 		if (debug)
298*3af9de98Smarco 			printf("inquiry\n");
299*3af9de98Smarco 		return (INQUIRY);
300*3af9de98Smarco 
301*3af9de98Smarco 	case 'e': /* ENUMERATE, not a pass through hmmm */
302*3af9de98Smarco 		if (debug)
303*3af9de98Smarco 			printf("enumerate\n");
304*3af9de98Smarco 		return (ENUM);
305*3af9de98Smarco 
306*3af9de98Smarco 	case 'r': /* READ CAPACITY */
307*3af9de98Smarco 		if (debug)
308*3af9de98Smarco 			printf("read cap\n");
309*3af9de98Smarco 		return (READCAP);
310*3af9de98Smarco 
311*3af9de98Smarco 	case 't': /* TUR */
312*3af9de98Smarco 		if (debug)
313*3af9de98Smarco 			printf("TUR\n");
314*3af9de98Smarco 		return (TUR);
315*3af9de98Smarco 
316*3af9de98Smarco 	default:
317*3af9de98Smarco 		errx(1, "invalid pass through function");
318*3af9de98Smarco 	}
319*3af9de98Smarco }
320*3af9de98Smarco 
321*3af9de98Smarco void
322*3af9de98Smarco parse_devlist(char *dl)
323*3af9de98Smarco {
324*3af9de98Smarco 	u_int8_t c , t, done = 0;
325*3af9de98Smarco 	char *es, *s;
326*3af9de98Smarco 	struct dev *delm;
327*3af9de98Smarco 
328*3af9de98Smarco 	es = NULL;
329*3af9de98Smarco 	s = dl;
330*3af9de98Smarco 
331*3af9de98Smarco 	if (debug)
332*3af9de98Smarco 		printf("parse: %s\n", dl);
333*3af9de98Smarco 
334*3af9de98Smarco 	while (!done) {
335*3af9de98Smarco 		c = strtol(s, &es, 10);
336*3af9de98Smarco 		if (debug)
337*3af9de98Smarco 			printf("%p %p %u %c\n", s, es, c, es[0]);
338*3af9de98Smarco 		s = es;
339*3af9de98Smarco 		if (es[0] == ':') {
340*3af9de98Smarco 			s++;
341*3af9de98Smarco 			t = strtol(s, &es, 10);
342*3af9de98Smarco 			if (debug)
343*3af9de98Smarco 				printf("%p %p %u %c\n", s, es, t, es[0]);
344*3af9de98Smarco 			s = es;
345*3af9de98Smarco 
346*3af9de98Smarco 			if (c > 4)
347*3af9de98Smarco 				errx(1, "invalid channel number");
348*3af9de98Smarco 			if (t > 16)
349*3af9de98Smarco 				errx(1, "invalid target number");
350*3af9de98Smarco 
351*3af9de98Smarco 			delm = malloc(sizeof(struct dev));
352*3af9de98Smarco 			if (!delm)
353*3af9de98Smarco 				errx(1, "not enough memory");
354*3af9de98Smarco 
355*3af9de98Smarco 			delm->target = t;
356*3af9de98Smarco 			delm->channel = c;
357*3af9de98Smarco 			SLIST_INSERT_HEAD(&ul, delm, next);
358*3af9de98Smarco 		}
359*3af9de98Smarco 		if (es[0] == ',') {
360*3af9de98Smarco 			s++;
361*3af9de98Smarco 			continue;
362*3af9de98Smarco 		}
363*3af9de98Smarco 		if (es[0] == '\0') {
364*3af9de98Smarco 			done = 1;
365*3af9de98Smarco 			continue;
366*3af9de98Smarco 		}
367*3af9de98Smarco 		done = 2;
368*3af9de98Smarco 	}
369*3af9de98Smarco 
370*3af9de98Smarco 	if (done == 2) {
371*3af9de98Smarco 		/* boink */
372*3af9de98Smarco 		errx(1, "invalid device list.");
373*3af9de98Smarco 	}
374*3af9de98Smarco }
375*3af9de98Smarco 
376*3af9de98Smarco int
377*3af9de98Smarco bio_get_capabilities(bioc_capabilities *bc)
378*3af9de98Smarco {
379*3af9de98Smarco 	int rv;
380*3af9de98Smarco 
381*3af9de98Smarco 	bc->cookie = bl.cookie;
382*3af9de98Smarco 	rv = ioctl(devh, BIOCCAPABILITIES, bc);
383*3af9de98Smarco 	if (rv == -1) {
384*3af9de98Smarco 		warnx("Error calling bioc_ioctl() via bio_ioctl()");
385*3af9de98Smarco 		return 0;
386*3af9de98Smarco 	}
387*3af9de98Smarco 
388*3af9de98Smarco 	if (debug) {
389*3af9de98Smarco 		printf("ioctls = %016llx\n", bc->ioctls);
390*3af9de98Smarco 		printf("raid_types = %08lx\n", bc->raid_types);
391*3af9de98Smarco 	}
392*3af9de98Smarco 
393*3af9de98Smarco 	return (1);
394*3af9de98Smarco }
395*3af9de98Smarco 
396*3af9de98Smarco void
397*3af9de98Smarco bio_alarm(char *arg)
398*3af9de98Smarco {
399*3af9de98Smarco 	int rv;
400*3af9de98Smarco 	bioc_alarm ba;
401*3af9de98Smarco 
402*3af9de98Smarco 	if (debug)
403*3af9de98Smarco 		printf("alarm in: %s, ", arg);
404*3af9de98Smarco 
405*3af9de98Smarco 	ba.cookie = bl.cookie;
406*3af9de98Smarco 
407*3af9de98Smarco 	switch (arg[0]) {
408*3af9de98Smarco 	case 'q': /* silence alarm */
409*3af9de98Smarco 		/* FALLTHROUGH */
410*3af9de98Smarco 	case 's':
411*3af9de98Smarco 		if (debug)
412*3af9de98Smarco 			printf("silence\n");
413*3af9de98Smarco 		ba.opcode = BIOCSALARM_SILENCE;
414*3af9de98Smarco 		break;
415*3af9de98Smarco 
416*3af9de98Smarco 	case 'e': /* enable alarm */
417*3af9de98Smarco 		if (debug)
418*3af9de98Smarco 			printf("enable\n");
419*3af9de98Smarco 		ba.opcode = BIOCSALARM_ENABLE;
420*3af9de98Smarco 		break;
421*3af9de98Smarco 
422*3af9de98Smarco 	case 'd': /* disable alarm */
423*3af9de98Smarco 		if (debug)
424*3af9de98Smarco 			printf("disable\n");
425*3af9de98Smarco 		ba.opcode = BIOCSALARM_DISABLE;
426*3af9de98Smarco 		break;
427*3af9de98Smarco 
428*3af9de98Smarco 	case 't': /* test alarm */
429*3af9de98Smarco 		if (debug)
430*3af9de98Smarco 			printf("test\n");
431*3af9de98Smarco 		ba.opcode = BIOCSALARM_TEST;
432*3af9de98Smarco 		break;
433*3af9de98Smarco 
434*3af9de98Smarco 	case 'g': /* get alarm state */
435*3af9de98Smarco 		if (debug)
436*3af9de98Smarco 			printf("get state\n");
437*3af9de98Smarco 		ba.opcode = BIOCGALARM_STATE;
438*3af9de98Smarco 		break;
439*3af9de98Smarco 
440*3af9de98Smarco 	default:
441*3af9de98Smarco 		warnx("invalid alarm function: %s", arg);
442*3af9de98Smarco 		return;
443*3af9de98Smarco 	}
444*3af9de98Smarco 
445*3af9de98Smarco 	rv = ioctl(devh, BIOCALARM, &ba);
446*3af9de98Smarco 	if (rv == -1) {
447*3af9de98Smarco 		warnx("bioc_ioctl() call failed");
448*3af9de98Smarco 		return;
449*3af9de98Smarco 	}
450*3af9de98Smarco 
451*3af9de98Smarco 	if (arg[0] == 'g') {
452*3af9de98Smarco 		printf("alarm is currently %s\n",
453*3af9de98Smarco 		    ba.state ? "enabled" : "disabled");
454*3af9de98Smarco 	}
455*3af9de98Smarco }
456*3af9de98Smarco 
457*3af9de98Smarco void
458*3af9de98Smarco bio_ping(void)
459*3af9de98Smarco {
460*3af9de98Smarco 	int rv;
461*3af9de98Smarco 	bioc_ping bp;
462*3af9de98Smarco 
463*3af9de98Smarco 	bp.cookie = bl.cookie;
464*3af9de98Smarco 	bp.x = 0;
465*3af9de98Smarco 	rv = ioctl(devh, BIOCPING, &bp);
466*3af9de98Smarco 	if (rv == -1) {
467*3af9de98Smarco 		warnx("Error calling bioc_ioctl() via bio_ioctl()");
468*3af9de98Smarco 		return;
469*3af9de98Smarco 	}
470*3af9de98Smarco 
471*3af9de98Smarco 	printf("x after ioctl() = %i\n", bp.x);
472*3af9de98Smarco }
473*3af9de98Smarco 
474*3af9de98Smarco void
475*3af9de98Smarco bio_startstop(char *arg, u_int8_t c, u_int8_t t)
476*3af9de98Smarco {
477*3af9de98Smarco 	int rv;
478*3af9de98Smarco 	bioc_startstop bs;
479*3af9de98Smarco 
480*3af9de98Smarco 	if (debug)
481*3af9de98Smarco 		printf("startstop in: %s, ", arg);
482*3af9de98Smarco 
483*3af9de98Smarco 	bs.cookie = bl.cookie;
484*3af9de98Smarco 
485*3af9de98Smarco 	switch (arg[0]) {
486*3af9de98Smarco 	case 's': /* stop unit */
487*3af9de98Smarco 		if (debug)
488*3af9de98Smarco 			printf("stop\n");
489*3af9de98Smarco 		bs.opcode = BIOCSUNIT_STOP;
490*3af9de98Smarco 		break;
491*3af9de98Smarco 
492*3af9de98Smarco 	case 'g': /* start or go unit */
493*3af9de98Smarco 		if (debug)
494*3af9de98Smarco 			printf("start\n");
495*3af9de98Smarco 		bs.opcode = BIOCSUNIT_START;
496*3af9de98Smarco 		break;
497*3af9de98Smarco 
498*3af9de98Smarco 	default:
499*3af9de98Smarco 		warnx("invalid start/stop function: %s", arg);
500*3af9de98Smarco 		return;
501*3af9de98Smarco 	}
502*3af9de98Smarco 
503*3af9de98Smarco 	bs.channel = c;
504*3af9de98Smarco 	bs.target = t;
505*3af9de98Smarco 
506*3af9de98Smarco 	rv = ioctl(devh, BIOCSTARTSTOP, &bs);
507*3af9de98Smarco 	if (rv == -1) {
508*3af9de98Smarco 		warnx("bioc_ioctl() call failed");
509*3af9de98Smarco 		return;
510*3af9de98Smarco 	}
511*3af9de98Smarco 
512*3af9de98Smarco 	if (debug)
513*3af9de98Smarco 		printf("startstop done\n");
514*3af9de98Smarco }
515*3af9de98Smarco 
516*3af9de98Smarco /* get status, for now only do all */
517*3af9de98Smarco void
518*3af9de98Smarco bio_status(void)
519*3af9de98Smarco {
520*3af9de98Smarco 	int rv;
521*3af9de98Smarco 	bioc_status bs;
522*3af9de98Smarco 
523*3af9de98Smarco 	if (debug)
524*3af9de98Smarco 		printf("status()\n");
525*3af9de98Smarco 
526*3af9de98Smarco 	bs.cookie = bl.cookie;
527*3af9de98Smarco 	bs.opcode = BIOCGSTAT_ALL;
528*3af9de98Smarco 
529*3af9de98Smarco 	rv = ioctl(devh, BIOCSTATUS, &bs);
530*3af9de98Smarco 	if (rv == -1) {
531*3af9de98Smarco 		warnx("bioc_ioctl() call failed");
532*3af9de98Smarco 		return;
533*3af9de98Smarco 	}
534*3af9de98Smarco 
535*3af9de98Smarco 	if (debug)
536*3af9de98Smarco 		printf("status done\n");
537*3af9de98Smarco }
538*3af9de98Smarco 
539*3af9de98Smarco /* read capacity for disk c,t */
540*3af9de98Smarco u_int64_t
541*3af9de98Smarco bio_pt_readcap(u_int8_t c, u_int8_t t)
542*3af9de98Smarco {
543*3af9de98Smarco 	bioc_scsicmd bpt;
544*3af9de98Smarco 	struct read_cap rc;
545*3af9de98Smarco 	int rv;
546*3af9de98Smarco 	u_int64_t size;
547*3af9de98Smarco 
548*3af9de98Smarco 	memset(&bpt, 0, sizeof(bpt));
549*3af9de98Smarco 	bpt.cookie = bl.cookie;
550*3af9de98Smarco 	bpt.channel = c;
551*3af9de98Smarco 	bpt.target = t;
552*3af9de98Smarco 	bpt.cdblen = 10;
553*3af9de98Smarco 	bpt.cdb[0] = READ_CAPACITY;
554*3af9de98Smarco 	bpt.data = &rc;    /* set up return data pointer */
555*3af9de98Smarco 	bpt.datalen = sizeof(rc);
556*3af9de98Smarco 	bpt.direction = BIOC_DIRIN;
557*3af9de98Smarco 	bpt.senselen = 32; /* silly since the kernel overrides it */
558*3af9de98Smarco 
559*3af9de98Smarco 	rv = ioctl(devh, BIOCSCSICMD, &bpt);
560*3af9de98Smarco 	if (rv == -1) {
561*3af9de98Smarco 		warnx("READ CAPACITY failed %x", bpt.status);
562*3af9de98Smarco 		return (0);
563*3af9de98Smarco 	}
564*3af9de98Smarco 	else if (bpt.status) {
565*3af9de98Smarco 		if (bpt.sensebuf[0] == 0x70 || bpt.sensebuf[0] == 0x71)
566*3af9de98Smarco 			print_sense(&bpt.sensebuf[0], bpt.senselen);
567*3af9de98Smarco 		return (0);
568*3af9de98Smarco 	}
569*3af9de98Smarco 
570*3af9de98Smarco 	rc.maxlba = betoh32(rc.maxlba);
571*3af9de98Smarco 	rc.bsize = betoh32(rc.bsize);
572*3af9de98Smarco 
573*3af9de98Smarco 	size = (u_int64_t)rc.maxlba * (u_int64_t)rc.bsize;
574*3af9de98Smarco 
575*3af9de98Smarco 	if (debug)
576*3af9de98Smarco 		printf("READ CAPACITY: %lu * %lu = %llu\n",
577*3af9de98Smarco 		    rc.maxlba, rc.bsize, size);
578*3af9de98Smarco 
579*3af9de98Smarco 	return (size);
580*3af9de98Smarco }
581*3af9de98Smarco 
582*3af9de98Smarco 
583*3af9de98Smarco /* inquire device */
584*3af9de98Smarco u_int32_t
585*3af9de98Smarco bio_pt_inquire(u_int8_t c, u_int8_t t, u_int8_t *inq)
586*3af9de98Smarco {
587*3af9de98Smarco 	bioc_scsicmd bpt;
588*3af9de98Smarco 	int rv, i;
589*3af9de98Smarco 
590*3af9de98Smarco 	memset(&bpt, 0, sizeof(bpt));
591*3af9de98Smarco 	bpt.cookie = bl.cookie;
592*3af9de98Smarco 	bpt.channel = c;
593*3af9de98Smarco 	bpt.target = t;
594*3af9de98Smarco 	bpt.cdblen = 6;
595*3af9de98Smarco 	bpt.cdb[0] = INQUIRY;
596*3af9de98Smarco 	bpt.cdb[4] = 36;   /* LENGTH  */
597*3af9de98Smarco 	bpt.data = inq;    /* set up return data pointer */
598*3af9de98Smarco 	bpt.datalen = 36;  /* minimum INQ size */
599*3af9de98Smarco 	bpt.direction = BIOC_DIRIN;
600*3af9de98Smarco 	bpt.senselen = 32; /* silly since the kernel overrides it */
601*3af9de98Smarco 
602*3af9de98Smarco 	rv = ioctl(devh, BIOCSCSICMD, &bpt);
603*3af9de98Smarco 	if (rv == -1) {
604*3af9de98Smarco 		warnx("INQUIRY failed %x", bpt.status);
605*3af9de98Smarco 		return 0;
606*3af9de98Smarco 	}
607*3af9de98Smarco 	else if (bpt.status) {
608*3af9de98Smarco 		if (bpt.sensebuf[0] == 0x70 || bpt.sensebuf[0] == 0x71)
609*3af9de98Smarco 			print_sense(&bpt.sensebuf[0], bpt.senselen);
610*3af9de98Smarco 
611*3af9de98Smarco 		return 0;
612*3af9de98Smarco 	}
613*3af9de98Smarco 
614*3af9de98Smarco 	if (debug) {
615*3af9de98Smarco 		printf("INQUIRY: ");
616*3af9de98Smarco 		printf("c: %u t: %u INQUIRY:", c, t);
617*3af9de98Smarco 		for (i = 0;  i < bpt.datalen; i++) {
618*3af9de98Smarco 			if (i < 8)
619*3af9de98Smarco 				printf("%0x ", inq[i]);
620*3af9de98Smarco 			else
621*3af9de98Smarco 				printf("%c", inq[i] < ' ' ? ' ' : inq[i]);
622*3af9de98Smarco 		}
623*3af9de98Smarco 		printf("\n");
624*3af9de98Smarco 	}
625*3af9de98Smarco 
626*3af9de98Smarco 	return 1;
627*3af9de98Smarco }
628*3af9de98Smarco 
629*3af9de98Smarco /* TUR for disk c,t */
630*3af9de98Smarco u_int32_t
631*3af9de98Smarco bio_pt_tur(u_int8_t c, u_int8_t t)
632*3af9de98Smarco {
633*3af9de98Smarco 	bioc_scsicmd bpt;
634*3af9de98Smarco 	int rv;
635*3af9de98Smarco 
636*3af9de98Smarco 	if (debug)
637*3af9de98Smarco 		printf("tur\n");
638*3af9de98Smarco 
639*3af9de98Smarco 	memset(&bpt, 0, sizeof(bpt));
640*3af9de98Smarco 	bpt.cookie = bl.cookie;
641*3af9de98Smarco 	bpt.channel = c;
642*3af9de98Smarco 	bpt.target = t;
643*3af9de98Smarco 	bpt.cdblen = 6;
644*3af9de98Smarco 	bpt.direction = BIOC_DIRNONE;
645*3af9de98Smarco 	rv = ioctl(devh, BIOCSCSICMD, &bpt);
646*3af9de98Smarco 	if (rv == -1) {
647*3af9de98Smarco 		warnx("passthrough failed");
648*3af9de98Smarco 		return (0);
649*3af9de98Smarco 	}
650*3af9de98Smarco 
651*3af9de98Smarco 	if (bpt.status) {
652*3af9de98Smarco 		if (bpt.sensebuf[0] == 0x70 || bpt.sensebuf[0] == 0x71)
653*3af9de98Smarco 			print_sense(&bpt.sensebuf[0], bpt.senselen);
654*3af9de98Smarco 
655*3af9de98Smarco 		return (0);
656*3af9de98Smarco 	}
657*3af9de98Smarco 
658*3af9de98Smarco 	if (debug)
659*3af9de98Smarco 		printf("tur completed\n");
660*3af9de98Smarco 
661*3af9de98Smarco 	return (1);
662*3af9de98Smarco }
663*3af9de98Smarco 
664*3af9de98Smarco 
665*3af9de98Smarco /* enumerate all disks */
666*3af9de98Smarco void
667*3af9de98Smarco bio_pt_enum(void)
668*3af9de98Smarco {
669*3af9de98Smarco 	bioc_scsicmd bpt;
670*3af9de98Smarco 	u_int32_t c, t, i, d;
671*3af9de98Smarco 	int rv;
672*3af9de98Smarco 	unsigned char inq[36];
673*3af9de98Smarco 
674*3af9de98Smarco 	struct dev *delm;
675*3af9de98Smarco 
676*3af9de98Smarco 	d = 0;
677*3af9de98Smarco 	for (c = 0; c < 2 /* FIXME */; c++) {
678*3af9de98Smarco 		for (t = 0; t < 16 /* FIXME */; t++) {
679*3af9de98Smarco 			if (bio_pt_inquire(c, t, &inq[0])) {
680*3af9de98Smarco 				printf("disk %u: c: %u t: %u\n", d, c, t);
681*3af9de98Smarco 				delm = malloc(sizeof(struct dev));
682*3af9de98Smarco 				if (delm == NULL)
683*3af9de98Smarco 					errx(1, "not enough memory");
684*3af9de98Smarco 				delm->id = d++;
685*3af9de98Smarco 				delm->target = t;
686*3af9de98Smarco 				delm->channel = c;
687*3af9de98Smarco 				SLIST_INSERT_HEAD(&devices, delm, next);
688*3af9de98Smarco 			}
689*3af9de98Smarco 		}
690*3af9de98Smarco 	}
691*3af9de98Smarco 
692*3af9de98Smarco 	/* silly to do this here instead of in the for loop */
693*3af9de98Smarco 	SLIST_FOREACH(delm, &devices, next) {
694*3af9de98Smarco 		/* FIXME check the return value */
695*3af9de98Smarco 		delm->capacity = bio_pt_readcap(delm->channel, delm->target);
696*3af9de98Smarco 		if (debug)
697*3af9de98Smarco 			printf("%p: %u %u %u %llu\n", delm, delm->id,
698*3af9de98Smarco 			    delm->channel, delm->target, delm->capacity);
699*3af9de98Smarco 	}
700*3af9de98Smarco }
701*3af9de98Smarco 
702*3af9de98Smarco /* printf sense data */
703*3af9de98Smarco void
704*3af9de98Smarco print_sense(u_int8_t *sensebuf, u_int8_t sensebuflen)
705*3af9de98Smarco {
706*3af9de98Smarco 	u_int8_t i;
707*3af9de98Smarco 
708*3af9de98Smarco 	if (debug)
709*3af9de98Smarco 		printf("print_sense() %p, %u\n", sensebuf, sensebuflen);
710*3af9de98Smarco 
711*3af9de98Smarco 	for (i = 0; i < sensebuflen; i++) {
712*3af9de98Smarco 		printf("%02x ", sensebuf[i]);
713*3af9de98Smarco 	}
714*3af9de98Smarco 	printf("\n");
715*3af9de98Smarco 
716*3af9de98Smarco 	/* FIXME add some pretty decoding here */
717*3af9de98Smarco }
718