bioctl.c revision 1.1.8.2 1 /* $NetBSD: bioctl.c,v 1.1.8.2 2007/10/15 05:09:51 riz Exp $ */
2 /* $OpenBSD: bioctl.c,v 1.52 2007/03/20 15:26:06 jmc Exp $ */
3
4 /*
5 * Copyright (c) 2004, 2005 Marco Peereboom
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30 #include <sys/cdefs.h>
31
32 #ifndef lint
33 __RCSID("$NetBSD: bioctl.c,v 1.1.8.2 2007/10/15 05:09:51 riz Exp $");
34 #endif
35
36 #include <sys/ioctl.h>
37 #include <sys/param.h>
38 #include <sys/queue.h>
39 // #include <scsi/scsipi_disk.h>
40 // #include <scsi/scsipi_all.h>
41 #include <dev/biovar.h>
42
43 #include <errno.h>
44 #include <err.h>
45 #include <fcntl.h>
46 #include <util.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <ctype.h>
52 #include <util.h>
53 #include "strtonum.h"
54
55 struct locator {
56 int channel;
57 int target;
58 int lun;
59 };
60
61 void usage(void);
62 const char *str2locator(const char *, struct locator *);
63 void cleanup(void);
64
65 void bio_inq(char *);
66 void bio_alarm(char *);
67 void bio_setstate(char *);
68 void bio_setblink(char *, char *, int);
69 void bio_blink(char *, int, int);
70 void bio_createraid(u_int16_t, char *);
71
72 int devh = -1;
73 int debug;
74 int human;
75 int verbose;
76
77 struct bio_locate bl;
78
79 int
80 main(int argc, char *argv[])
81 {
82 extern char *optarg;
83 u_int64_t func = 0;
84 /* u_int64_t subfunc = 0; XXX */
85 char *bioc_dev = NULL, *sd_dev = NULL;
86 char /* *realname = NULL, XXX */ *al_arg = NULL;
87 char *bl_arg = NULL, *dev_list = NULL;
88 int ch, rv, blink = 0; /* XXX GCC */
89 u_int16_t cr_level = 0; /* XXX GCC */
90
91 if (argc < 2)
92 usage();
93
94 while ((ch = getopt(argc, argv, "b:c:l:u:H:ha:Div")) != -1) {
95 switch (ch) {
96 case 'a': /* alarm */
97 func |= BIOC_ALARM;
98 al_arg = optarg;
99 break;
100 case 'b': /* blink */
101 func |= BIOC_BLINK;
102 blink = BIOC_SBBLINK;
103 bl_arg = optarg;
104 break;
105 case 'c': /* create */
106 func |= BIOC_CREATERAID;
107 cr_level = atoi(optarg);
108 break;
109 case 'u': /* unblink */
110 func |= BIOC_BLINK;
111 blink = BIOC_SBUNBLINK;
112 bl_arg = optarg;
113 break;
114 case 'D': /* debug */
115 debug = 1;
116 break;
117 case 'H': /* set hotspare */
118 func |= BIOC_SETSTATE;
119 al_arg = optarg;
120 break;
121 case 'h':
122 human = 1;
123 break;
124 case 'i': /* inquiry */
125 func |= BIOC_INQ;
126 break;
127 case 'l': /* device list */
128 func |= BIOC_DEVLIST;
129 dev_list = optarg;
130 break;
131 case 'v':
132 verbose = 1;
133 break;
134 default:
135 usage();
136 /* NOTREACHED */
137 }
138 }
139 argc -= optind;
140 argv += optind;
141
142 if (argc != 1)
143 usage();
144
145 if (func == 0)
146 func |= BIOC_INQ;
147 #if 0
148 /* if at least glob sd[0-9]*, it is a drive identifier */
149 if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
150 isdigit((int)argv[0][2]))
151 sd_dev = argv[0];
152 else
153 #endif
154 bioc_dev = argv[0];
155
156 if (bioc_dev) {
157 devh = open("/dev/bio", O_RDWR);
158 if (devh == -1)
159 err(1, "Can't open %s", "/dev/bio");
160
161 bl.bl_name = bioc_dev;
162 rv = ioctl(devh, BIOCLOCATE, &bl);
163 if (rv == -1)
164 errx(1, "Can't locate %s device via %s",
165 bl.bl_name, "/dev/bio");
166 }
167 #if 0
168 else if (sd_dev) {
169 devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
170 if (devh == -1)
171 err(1, "Can't open %s", sd_dev);
172 }
173 #endif
174 else
175 errx(1, "need -d or -f parameter");
176
177 if (debug)
178 warnx("cookie = %p", bl.bl_cookie);
179
180 if (func & BIOC_INQ) {
181 bio_inq(sd_dev);
182 } else if (func == BIOC_ALARM) {
183 bio_alarm(al_arg);
184 } else if (func == BIOC_BLINK) {
185 bio_setblink(sd_dev, bl_arg, blink);
186 } else if (func == BIOC_SETSTATE) {
187 bio_setstate(al_arg);
188 } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
189 if (!(func & BIOC_CREATERAID))
190 errx(1, "need -c parameter");
191 if (!(func & BIOC_DEVLIST))
192 errx(1, "need -l parameter");
193 if (sd_dev)
194 errx(1, "can't use sd device");
195 bio_createraid(cr_level, dev_list);
196 }
197
198 return (0);
199 }
200
201 void
202 usage(void)
203 {
204 extern char *__progname;
205
206 fprintf(stderr,
207 "usage: %s [-Dhiv] [-a alarm-function] "
208 "[-b channel:target[.lun]]\n"
209 "\t[-c raidlevel] [-H channel:target[.lun]]\n"
210 "\t[-l special[,special[,...]]] "
211 "[-u channel:target[.lun]] device\n", __progname);
212
213 exit(1);
214 }
215
216 const char *
217 str2locator(const char *string, struct locator *location)
218 {
219 const char *errstr;
220 char parse[80], *targ, *lun;
221
222 strlcpy(parse, string, sizeof parse);
223 targ = strchr(parse, ':');
224 if (targ == NULL)
225 return ("target not specified");
226 *targ++ = '\0';
227
228 lun = strchr(targ, '.');
229 if (lun != NULL) {
230 *lun++ = '\0';
231 location->lun = strtonum(lun, 0, 256, &errstr);
232 if (errstr)
233 return (errstr);
234 } else
235 location->lun = 0;
236
237 location->target = strtonum(targ, 0, 256, &errstr);
238 if (errstr)
239 return (errstr);
240 location->channel = strtonum(parse, 0, 256, &errstr);
241 if (errstr)
242 return (errstr);
243 return (NULL);
244 }
245
246 void
247 bio_inq(char *name)
248 {
249 const char *status;
250 char size[64], scsiname[16], volname[32];
251 char percent[10], seconds[20];
252 int rv, i, d, volheader, hotspare, unused;
253 char encname[16], serial[32];
254 struct bioc_disk bd;
255 struct bioc_inq bi;
256 struct bioc_vol bv;
257
258 memset(&bi, 0, sizeof(bi));
259
260 if (debug)
261 printf("bio_inq\n");
262
263 bi.bi_cookie = bl.bl_cookie;
264
265 rv = ioctl(devh, BIOCINQ, &bi);
266 if (rv == -1) {
267 warn("BIOCINQ");
268 return;
269 }
270
271 if (debug)
272 printf("bio_inq { %p, %s, %d, %d }\n",
273 bi.bi_cookie,
274 bi.bi_dev,
275 bi.bi_novol,
276 bi.bi_nodisk);
277
278 volheader = 0;
279 for (i = 0; i < bi.bi_novol; i++) {
280 memset(&bv, 0, sizeof(bv));
281 bv.bv_cookie = bl.bl_cookie;
282 bv.bv_volid = i;
283 bv.bv_percent = -1;
284 bv.bv_seconds = 0;
285
286 rv = ioctl(devh, BIOCVOL, &bv);
287 if (rv == -1) {
288 warn("BIOCVOL");
289 return;
290 }
291
292 if (name && strcmp(name, bv.bv_dev) != 0)
293 continue;
294
295 if (!volheader) {
296 volheader = 1;
297 printf("%-7s %-10s %14s %-8s\n",
298 "Volume", "Status", "Size", "Device");
299 }
300
301 percent[0] = '\0';
302 seconds[0] = '\0';
303 if (bv.bv_percent != -1)
304 snprintf(percent, sizeof percent,
305 " %d%% done", bv.bv_percent);
306 if (bv.bv_seconds)
307 snprintf(seconds, sizeof seconds,
308 " %u seconds", bv.bv_seconds);
309 switch (bv.bv_status) {
310 case BIOC_SVONLINE:
311 status = BIOC_SVONLINE_S;
312 break;
313 case BIOC_SVOFFLINE:
314 status = BIOC_SVOFFLINE_S;
315 break;
316 case BIOC_SVDEGRADED:
317 status = BIOC_SVDEGRADED_S;
318 break;
319 case BIOC_SVBUILDING:
320 status = BIOC_SVBUILDING_S;
321 break;
322 case BIOC_SVREBUILD:
323 status = BIOC_SVREBUILD_S;
324 break;
325 case BIOC_SVSCRUB:
326 status = BIOC_SVSCRUB_S;
327 break;
328 case BIOC_SVINVALID:
329 default:
330 status = BIOC_SVINVALID_S;
331 }
332
333 snprintf(volname, sizeof volname, "%s %u",
334 bi.bi_dev, bv.bv_volid);
335
336 if (bv.bv_level == -1 && bv.bv_nodisk == 1) {
337 hotspare = 1;
338 unused = 0;
339 } else if (bv.bv_level == -2 && bv.bv_nodisk == 1) {
340 unused = 1;
341 hotspare = 0;
342 } else {
343 unused = 0;
344 hotspare = 0;
345
346 if (human)
347 humanize_number(size, 5,
348 (int64_t)bv.bv_size, "", HN_AUTOSCALE,
349 HN_B | HN_NOSPACE | HN_DECIMAL);
350 else
351 snprintf(size, sizeof size, "%14llu",
352 (long long unsigned int)bv.bv_size);
353 printf("%7s %-10s %14s %-7s RAID%u%s%s\n",
354 volname, status, size, bv.bv_dev,
355 bv.bv_level, percent, seconds);
356 }
357
358 for (d = 0; d < bv.bv_nodisk; d++) {
359 memset(&bd, 0, sizeof(bd));
360 bd.bd_cookie = bl.bl_cookie;
361 bd.bd_diskid = d;
362 bd.bd_volid = i;
363
364 rv = ioctl(devh, BIOCDISK, &bd);
365 if (rv == -1) {
366 warn("BIOCDISK");
367 return;
368 }
369
370 switch (bd.bd_status) {
371 case BIOC_SDONLINE:
372 status = BIOC_SDONLINE_S;
373 break;
374 case BIOC_SDOFFLINE:
375 status = BIOC_SDOFFLINE_S;
376 break;
377 case BIOC_SDFAILED:
378 status = BIOC_SDFAILED_S;
379 break;
380 case BIOC_SDREBUILD:
381 status = BIOC_SDREBUILD_S;
382 break;
383 case BIOC_SDHOTSPARE:
384 status = BIOC_SDHOTSPARE_S;
385 break;
386 case BIOC_SDUNUSED:
387 status = BIOC_SDUNUSED_S;
388 break;
389 case BIOC_SDSCRUB:
390 status = BIOC_SDSCRUB_S;
391 break;
392 case BIOC_SDINVALID:
393 default:
394 status = BIOC_SDINVALID_S;
395 }
396
397 if (hotspare || unused)
398 ; /* use volname from parent volume */
399 else
400 snprintf(volname, sizeof volname, " %3u",
401 bd.bd_diskid);
402
403 if (human)
404 humanize_number(size, 5,
405 bd.bd_size, "", HN_AUTOSCALE,
406 HN_B | HN_NOSPACE | HN_DECIMAL);
407 else
408 snprintf(size, sizeof size, "%14llu",
409 (long long unsigned int)bd.bd_size);
410 snprintf(scsiname, sizeof scsiname,
411 "%u:%u.%u",
412 bd.bd_channel, bd.bd_target, bd.bd_lun);
413 if (bd.bd_procdev[0])
414 strlcpy(encname, bd.bd_procdev, sizeof encname);
415 else
416 strlcpy(encname, "noencl", sizeof encname);
417 if (bd.bd_serial[0])
418 strlcpy(serial, bd.bd_serial, sizeof serial);
419 else
420 strlcpy(serial, "unknown serial", sizeof serial);
421
422 printf("%7s %-10s %14s %-7s %-6s <%s>\n",
423 volname, status, size, scsiname, encname,
424 bd.bd_vendor);
425 if (verbose)
426 printf("%7s %-10s %14s %-7s %-6s '%s'\n",
427 "", "", "", "", "", serial);
428 }
429 }
430 }
431
432 void
433 bio_alarm(char *arg)
434 {
435 int rv;
436 struct bioc_alarm ba;
437
438 ba.ba_cookie = bl.bl_cookie;
439
440 switch (arg[0]) {
441 case 'q': /* silence alarm */
442 /* FALLTHROUGH */
443 case 's':
444 ba.ba_opcode = BIOC_SASILENCE;
445 break;
446
447 case 'e': /* enable alarm */
448 ba.ba_opcode = BIOC_SAENABLE;
449 break;
450
451 case 'd': /* disable alarm */
452 ba.ba_opcode = BIOC_SADISABLE;
453 break;
454
455 case 't': /* test alarm */
456 ba.ba_opcode = BIOC_SATEST;
457 break;
458
459 case 'g': /* get alarm state */
460 ba.ba_opcode = BIOC_GASTATUS;
461 break;
462
463 default:
464 warnx("invalid alarm function: %s", arg);
465 return;
466 }
467
468 rv = ioctl(devh, BIOCALARM, &ba);
469 if (rv == -1) {
470 warn("BIOCALARM");
471 return;
472 }
473
474 if (arg[0] == 'g') {
475 printf("alarm is currently %s\n",
476 ba.ba_status ? "enabled" : "disabled");
477
478 }
479 }
480
481 void
482 bio_setstate(char *arg)
483 {
484 struct bioc_setstate bs;
485 struct locator location;
486 const char *errstr;
487 int rv;
488
489 errstr = str2locator(arg, &location);
490 if (errstr)
491 errx(1, "Target %s: %s", arg, errstr);
492
493 bs.bs_cookie = bl.bl_cookie;
494 bs.bs_status = BIOC_SSHOTSPARE;
495 bs.bs_channel = location.channel;
496 bs.bs_target = location.target;
497 bs.bs_lun = location.lun;
498
499 rv = ioctl(devh, BIOCSETSTATE, &bs);
500 if (rv == -1) {
501 warn("BIOCSETSTATE");
502 return;
503 }
504 }
505
506 void
507 bio_setblink(char *name, char *arg, int blink)
508 {
509 struct locator location;
510 struct bioc_inq bi;
511 struct bioc_vol bv;
512 struct bioc_disk bd;
513 struct bioc_blink bb;
514 const char *errstr;
515 int v, d, rv;
516
517 errstr = str2locator(arg, &location);
518 if (errstr)
519 errx(1, "Target %s: %s", arg, errstr);
520
521 /* try setting blink on the device directly */
522 memset(&bb, 0, sizeof(bb));
523 bb.bb_cookie = bl.bl_cookie;
524 bb.bb_status = blink;
525 bb.bb_target = location.target;
526 bb.bb_channel = location.channel;
527 rv = ioctl(devh, BIOCBLINK, &bb);
528 if (rv == 0)
529 return;
530
531 /* if the blink didnt work, try to find something that will */
532
533 memset(&bi, 0, sizeof(bi));
534 bi.bi_cookie = bl.bl_cookie;
535 rv = ioctl(devh, BIOCINQ, &bi);
536 if (rv == -1) {
537 warn("BIOCINQ");
538 return;
539 }
540
541 for (v = 0; v < bi.bi_novol; v++) {
542 memset(&bv, 0, sizeof(bv));
543 bv.bv_cookie = bl.bl_cookie;
544 bv.bv_volid = v;
545 rv = ioctl(devh, BIOCVOL, &bv);
546 if (rv == -1) {
547 warn("BIOCVOL");
548 return;
549 }
550
551 if (name && strcmp(name, bv.bv_dev) != 0)
552 continue;
553
554 for (d = 0; d < bv.bv_nodisk; d++) {
555 memset(&bd, 0, sizeof(bd));
556 bd.bd_cookie = bl.bl_cookie;
557 bd.bd_volid = v;
558 bd.bd_diskid = d;
559
560 rv = ioctl(devh, BIOCDISK, &bd);
561 if (rv == -1) {
562 warn("BIOCDISK");
563 return;
564 }
565
566 if (bd.bd_channel == location.channel &&
567 bd.bd_target == location.target &&
568 bd.bd_lun == location.lun) {
569 if (bd.bd_procdev[0] != '\0') {
570 bio_blink(bd.bd_procdev,
571 location.target, blink);
572 } else
573 warnx("Disk %s is not in an enclosure", arg);
574 return;
575 }
576 }
577 }
578
579 warnx("Disk %s does not exist", arg);
580 return;
581 }
582
583 void
584 bio_blink(char *enclosure, int target, int blinktype)
585 {
586 int bioh;
587 struct bio_locate bio;
588 struct bioc_blink blink;
589 int rv;
590
591 bioh = open("/dev/bio", O_RDWR);
592 if (bioh == -1)
593 err(1, "Can't open %s", "/dev/bio");
594
595 bio.bl_name = enclosure;
596 rv = ioctl(bioh, BIOCLOCATE, &bio);
597 if (rv == -1)
598 errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
599
600 memset(&blink, 0, sizeof(blink));
601 blink.bb_cookie = bio.bl_cookie;
602 blink.bb_status = blinktype;
603 blink.bb_target = target;
604
605 rv = ioctl(bioh, BIOCBLINK, &blink);
606 if (rv == -1)
607 warn("BIOCBLINK");
608
609 close(bioh);
610 }
611
612 void
613 bio_createraid(u_int16_t level, char *dev_list)
614 {
615 struct bioc_createraid create;
616 int rv;
617 u_int16_t min_disks = 0;
618
619 if (debug)
620 printf("bio_createraid\n");
621
622 if (!dev_list)
623 errx(1, "no devices specified");
624
625 switch (level) {
626 case 0:
627 min_disks = 1;
628 break;
629 case 1:
630 min_disks = 2;
631 break;
632 default:
633 errx(1, "unsuported raid level");
634 }
635
636 /* XXX validate device list for real */
637 #if 0
638 if (strncmp(dev_list, "sd", 2) == 0 && strlen(dev_list) > 2 &&
639 isdigit(dev_list[2])) {
640 if (strlen(dev_list) != 3)
641 errx(1, "only one device supported");
642
643 if (debug)
644 printf("bio_createraid: dev_list: %s\n", dev_list);
645 }
646 else
647 errx(1, "no sd device specified");
648 #endif
649
650 memset(&create, 0, sizeof(create));
651 create.bc_cookie = bl.bl_cookie;
652 create.bc_level = level;
653 create.bc_dev_list_len = strlen(dev_list);
654 create.bc_dev_list = dev_list;
655
656 rv = ioctl(devh, BIOCCREATERAID, &create);
657 if (rv == -1) {
658 warn("BIOCCREATERAID");
659 return;
660 }
661 }
662 /* $NetBSD: bioctl.c,v 1.1.8.2 2007/10/15 05:09:51 riz Exp $ */
663 /* $OpenBSD: bioctl.c,v 1.52 2007/03/20 15:26:06 jmc Exp $ */
664
665 /*
666 * Copyright (c) 2004, 2005 Marco Peereboom
667 * All rights reserved.
668 *
669 * Redistribution and use in source and binary forms, with or without
670 * modification, are permitted provided that the following conditions
671 * are met:
672 * 1. Redistributions of source code must retain the above copyright
673 * notice, this list of conditions and the following disclaimer.
674 * 2. Redistributions in binary form must reproduce the above copyright
675 * notice, this list of conditions and the following disclaimer in the
676 * documentation and/or other materials provided with the distribution.
677 *
678 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
679 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
680 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
681 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
682 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
683 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
684 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
685 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
686 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
687 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
688 * SUCH DAMAGE.
689 *
690 */
691 #include <sys/cdefs.h>
692
693 #ifndef lint
694 __RCSID("$NetBSD: bioctl.c,v 1.1.8.2 2007/10/15 05:09:51 riz Exp $");
695 #endif
696
697 #include <sys/ioctl.h>
698 #include <sys/param.h>
699 #include <sys/queue.h>
700 // #include <scsi/scsipi_disk.h>
701 // #include <scsi/scsipi_all.h>
702 #include <dev/biovar.h>
703
704 #include <errno.h>
705 #include <err.h>
706 #include <fcntl.h>
707 #include <util.h>
708 #include <stdio.h>
709 #include <stdlib.h>
710 #include <string.h>
711 #include <unistd.h>
712 #include <ctype.h>
713 #include <util.h>
714 #include "strtonum.h"
715
716 struct locator {
717 int channel;
718 int target;
719 int lun;
720 };
721
722 void usage(void);
723 const char *str2locator(const char *, struct locator *);
724 void cleanup(void);
725
726 void bio_inq(char *);
727 void bio_alarm(char *);
728 void bio_setstate(char *);
729 void bio_setblink(char *, char *, int);
730 void bio_blink(char *, int, int);
731 void bio_createraid(u_int16_t, char *);
732
733 int devh = -1;
734 int debug;
735 int human;
736 int verbose;
737
738 struct bio_locate bl;
739
740 int
741 main(int argc, char *argv[])
742 {
743 extern char *optarg;
744 u_int64_t func = 0;
745 /* u_int64_t subfunc = 0; XXX */
746 char *bioc_dev = NULL, *sd_dev = NULL;
747 char /* *realname = NULL, XXX */ *al_arg = NULL;
748 char *bl_arg = NULL, *dev_list = NULL;
749 int ch, rv, blink = 0; /* XXX GCC */
750 u_int16_t cr_level = 0; /* XXX GCC */
751
752 if (argc < 2)
753 usage();
754
755 while ((ch = getopt(argc, argv, "b:c:l:u:H:ha:Div")) != -1) {
756 switch (ch) {
757 case 'a': /* alarm */
758 func |= BIOC_ALARM;
759 al_arg = optarg;
760 break;
761 case 'b': /* blink */
762 func |= BIOC_BLINK;
763 blink = BIOC_SBBLINK;
764 bl_arg = optarg;
765 break;
766 case 'c': /* create */
767 func |= BIOC_CREATERAID;
768 cr_level = atoi(optarg);
769 break;
770 case 'u': /* unblink */
771 func |= BIOC_BLINK;
772 blink = BIOC_SBUNBLINK;
773 bl_arg = optarg;
774 break;
775 case 'D': /* debug */
776 debug = 1;
777 break;
778 case 'H': /* set hotspare */
779 func |= BIOC_SETSTATE;
780 al_arg = optarg;
781 break;
782 case 'h':
783 human = 1;
784 break;
785 case 'i': /* inquiry */
786 func |= BIOC_INQ;
787 break;
788 case 'l': /* device list */
789 func |= BIOC_DEVLIST;
790 dev_list = optarg;
791 break;
792 case 'v':
793 verbose = 1;
794 break;
795 default:
796 usage();
797 /* NOTREACHED */
798 }
799 }
800 argc -= optind;
801 argv += optind;
802
803 if (argc != 1)
804 usage();
805
806 if (func == 0)
807 func |= BIOC_INQ;
808 #if 0
809 /* if at least glob sd[0-9]*, it is a drive identifier */
810 if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
811 isdigit((int)argv[0][2]))
812 sd_dev = argv[0];
813 else
814 #endif
815 bioc_dev = argv[0];
816
817 if (bioc_dev) {
818 devh = open("/dev/bio", O_RDWR);
819 if (devh == -1)
820 err(1, "Can't open %s", "/dev/bio");
821
822 bl.bl_name = bioc_dev;
823 rv = ioctl(devh, BIOCLOCATE, &bl);
824 if (rv == -1)
825 errx(1, "Can't locate %s device via %s",
826 bl.bl_name, "/dev/bio");
827 }
828 #if 0
829 else if (sd_dev) {
830 devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
831 if (devh == -1)
832 err(1, "Can't open %s", sd_dev);
833 }
834 #endif
835 else
836 errx(1, "need -d or -f parameter");
837
838 if (debug)
839 warnx("cookie = %p", bl.bl_cookie);
840
841 if (func & BIOC_INQ) {
842 bio_inq(sd_dev);
843 } else if (func == BIOC_ALARM) {
844 bio_alarm(al_arg);
845 } else if (func == BIOC_BLINK) {
846 bio_setblink(sd_dev, bl_arg, blink);
847 } else if (func == BIOC_SETSTATE) {
848 bio_setstate(al_arg);
849 } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
850 if (!(func & BIOC_CREATERAID))
851 errx(1, "need -c parameter");
852 if (!(func & BIOC_DEVLIST))
853 errx(1, "need -l parameter");
854 if (sd_dev)
855 errx(1, "can't use sd device");
856 bio_createraid(cr_level, dev_list);
857 }
858
859 return (0);
860 }
861
862 void
863 usage(void)
864 {
865 extern char *__progname;
866
867 fprintf(stderr,
868 "usage: %s [-Dhiv] [-a alarm-function] "
869 "[-b channel:target[.lun]]\n"
870 "\t[-c raidlevel] [-H channel:target[.lun]]\n"
871 "\t[-l special[,special[,...]]] "
872 "[-u channel:target[.lun]] device\n", __progname);
873
874 exit(1);
875 }
876
877 const char *
878 str2locator(const char *string, struct locator *location)
879 {
880 const char *errstr;
881 char parse[80], *targ, *lun;
882
883 strlcpy(parse, string, sizeof parse);
884 targ = strchr(parse, ':');
885 if (targ == NULL)
886 return ("target not specified");
887 *targ++ = '\0';
888
889 lun = strchr(targ, '.');
890 if (lun != NULL) {
891 *lun++ = '\0';
892 location->lun = strtonum(lun, 0, 256, &errstr);
893 if (errstr)
894 return (errstr);
895 } else
896 location->lun = 0;
897
898 location->target = strtonum(targ, 0, 256, &errstr);
899 if (errstr)
900 return (errstr);
901 location->channel = strtonum(parse, 0, 256, &errstr);
902 if (errstr)
903 return (errstr);
904 return (NULL);
905 }
906
907 void
908 bio_inq(char *name)
909 {
910 const char *status;
911 char size[64], scsiname[16], volname[32];
912 char percent[10], seconds[20];
913 int rv, i, d, volheader, hotspare, unused;
914 char encname[16], serial[32];
915 struct bioc_disk bd;
916 struct bioc_inq bi;
917 struct bioc_vol bv;
918
919 memset(&bi, 0, sizeof(bi));
920
921 if (debug)
922 printf("bio_inq\n");
923
924 bi.bi_cookie = bl.bl_cookie;
925
926 rv = ioctl(devh, BIOCINQ, &bi);
927 if (rv == -1) {
928 warn("BIOCINQ");
929 return;
930 }
931
932 if (debug)
933 printf("bio_inq { %p, %s, %d, %d }\n",
934 bi.bi_cookie,
935 bi.bi_dev,
936 bi.bi_novol,
937 bi.bi_nodisk);
938
939 volheader = 0;
940 for (i = 0; i < bi.bi_novol; i++) {
941 memset(&bv, 0, sizeof(bv));
942 bv.bv_cookie = bl.bl_cookie;
943 bv.bv_volid = i;
944 bv.bv_percent = -1;
945 bv.bv_seconds = 0;
946
947 rv = ioctl(devh, BIOCVOL, &bv);
948 if (rv == -1) {
949 warn("BIOCVOL");
950 return;
951 }
952
953 if (name && strcmp(name, bv.bv_dev) != 0)
954 continue;
955
956 if (!volheader) {
957 volheader = 1;
958 printf("%-7s %-10s %14s %-8s\n",
959 "Volume", "Status", "Size", "Device");
960 }
961
962 percent[0] = '\0';
963 seconds[0] = '\0';
964 if (bv.bv_percent != -1)
965 snprintf(percent, sizeof percent,
966 " %d%% done", bv.bv_percent);
967 if (bv.bv_seconds)
968 snprintf(seconds, sizeof seconds,
969 " %u seconds", bv.bv_seconds);
970 switch (bv.bv_status) {
971 case BIOC_SVONLINE:
972 status = BIOC_SVONLINE_S;
973 break;
974 case BIOC_SVOFFLINE:
975 status = BIOC_SVOFFLINE_S;
976 break;
977 case BIOC_SVDEGRADED:
978 status = BIOC_SVDEGRADED_S;
979 break;
980 case BIOC_SVBUILDING:
981 status = BIOC_SVBUILDING_S;
982 break;
983 case BIOC_SVREBUILD:
984 status = BIOC_SVREBUILD_S;
985 break;
986 case BIOC_SVSCRUB:
987 status = BIOC_SVSCRUB_S;
988 break;
989 case BIOC_SVINVALID:
990 default:
991 status = BIOC_SVINVALID_S;
992 }
993
994 snprintf(volname, sizeof volname, "%s %u",
995 bi.bi_dev, bv.bv_volid);
996
997 if (bv.bv_level == -1 && bv.bv_nodisk == 1) {
998 hotspare = 1;
999 unused = 0;
1000 } else if (bv.bv_level == -2 && bv.bv_nodisk == 1) {
1001 unused = 1;
1002 hotspare = 0;
1003 } else {
1004 unused = 0;
1005 hotspare = 0;
1006
1007 if (human)
1008 humanize_number(size, 5,
1009 (int64_t)bv.bv_size, "", HN_AUTOSCALE,
1010 HN_B | HN_NOSPACE | HN_DECIMAL);
1011 else
1012 snprintf(size, sizeof size, "%14llu",
1013 (long long unsigned int)bv.bv_size);
1014 printf("%7s %-10s %14s %-7s RAID%u%s%s\n",
1015 volname, status, size, bv.bv_dev,
1016 bv.bv_level, percent, seconds);
1017 }
1018
1019 for (d = 0; d < bv.bv_nodisk; d++) {
1020 memset(&bd, 0, sizeof(bd));
1021 bd.bd_cookie = bl.bl_cookie;
1022 bd.bd_diskid = d;
1023 bd.bd_volid = i;
1024
1025 rv = ioctl(devh, BIOCDISK, &bd);
1026 if (rv == -1) {
1027 warn("BIOCDISK");
1028 return;
1029 }
1030
1031 switch (bd.bd_status) {
1032 case BIOC_SDONLINE:
1033 status = BIOC_SDONLINE_S;
1034 break;
1035 case BIOC_SDOFFLINE:
1036 status = BIOC_SDOFFLINE_S;
1037 break;
1038 case BIOC_SDFAILED:
1039 status = BIOC_SDFAILED_S;
1040 break;
1041 case BIOC_SDREBUILD:
1042 status = BIOC_SDREBUILD_S;
1043 break;
1044 case BIOC_SDHOTSPARE:
1045 status = BIOC_SDHOTSPARE_S;
1046 break;
1047 case BIOC_SDUNUSED:
1048 status = BIOC_SDUNUSED_S;
1049 break;
1050 case BIOC_SDSCRUB:
1051 status = BIOC_SDSCRUB_S;
1052 break;
1053 case BIOC_SDINVALID:
1054 default:
1055 status = BIOC_SDINVALID_S;
1056 }
1057
1058 if (hotspare || unused)
1059 ; /* use volname from parent volume */
1060 else
1061 snprintf(volname, sizeof volname, " %3u",
1062 bd.bd_diskid);
1063
1064 if (human)
1065 humanize_number(size, 5,
1066 bd.bd_size, "", HN_AUTOSCALE,
1067 HN_B | HN_NOSPACE | HN_DECIMAL);
1068 else
1069 snprintf(size, sizeof size, "%14llu",
1070 (long long unsigned int)bd.bd_size);
1071 snprintf(scsiname, sizeof scsiname,
1072 "%u:%u.%u",
1073 bd.bd_channel, bd.bd_target, bd.bd_lun);
1074 if (bd.bd_procdev[0])
1075 strlcpy(encname, bd.bd_procdev, sizeof encname);
1076 else
1077 strlcpy(encname, "noencl", sizeof encname);
1078 if (bd.bd_serial[0])
1079 strlcpy(serial, bd.bd_serial, sizeof serial);
1080 else
1081 strlcpy(serial, "unknown serial", sizeof serial);
1082
1083 printf("%7s %-10s %14s %-7s %-6s <%s>\n",
1084 volname, status, size, scsiname, encname,
1085 bd.bd_vendor);
1086 if (verbose)
1087 printf("%7s %-10s %14s %-7s %-6s '%s'\n",
1088 "", "", "", "", "", serial);
1089 }
1090 }
1091 }
1092
1093 void
1094 bio_alarm(char *arg)
1095 {
1096 int rv;
1097 struct bioc_alarm ba;
1098
1099 ba.ba_cookie = bl.bl_cookie;
1100
1101 switch (arg[0]) {
1102 case 'q': /* silence alarm */
1103 /* FALLTHROUGH */
1104 case 's':
1105 ba.ba_opcode = BIOC_SASILENCE;
1106 break;
1107
1108 case 'e': /* enable alarm */
1109 ba.ba_opcode = BIOC_SAENABLE;
1110 break;
1111
1112 case 'd': /* disable alarm */
1113 ba.ba_opcode = BIOC_SADISABLE;
1114 break;
1115
1116 case 't': /* test alarm */
1117 ba.ba_opcode = BIOC_SATEST;
1118 break;
1119
1120 case 'g': /* get alarm state */
1121 ba.ba_opcode = BIOC_GASTATUS;
1122 break;
1123
1124 default:
1125 warnx("invalid alarm function: %s", arg);
1126 return;
1127 }
1128
1129 rv = ioctl(devh, BIOCALARM, &ba);
1130 if (rv == -1) {
1131 warn("BIOCALARM");
1132 return;
1133 }
1134
1135 if (arg[0] == 'g') {
1136 printf("alarm is currently %s\n",
1137 ba.ba_status ? "enabled" : "disabled");
1138
1139 }
1140 }
1141
1142 void
1143 bio_setstate(char *arg)
1144 {
1145 struct bioc_setstate bs;
1146 struct locator location;
1147 const char *errstr;
1148 int rv;
1149
1150 errstr = str2locator(arg, &location);
1151 if (errstr)
1152 errx(1, "Target %s: %s", arg, errstr);
1153
1154 bs.bs_cookie = bl.bl_cookie;
1155 bs.bs_status = BIOC_SSHOTSPARE;
1156 bs.bs_channel = location.channel;
1157 bs.bs_target = location.target;
1158 bs.bs_lun = location.lun;
1159
1160 rv = ioctl(devh, BIOCSETSTATE, &bs);
1161 if (rv == -1) {
1162 warn("BIOCSETSTATE");
1163 return;
1164 }
1165 }
1166
1167 void
1168 bio_setblink(char *name, char *arg, int blink)
1169 {
1170 struct locator location;
1171 struct bioc_inq bi;
1172 struct bioc_vol bv;
1173 struct bioc_disk bd;
1174 struct bioc_blink bb;
1175 const char *errstr;
1176 int v, d, rv;
1177
1178 errstr = str2locator(arg, &location);
1179 if (errstr)
1180 errx(1, "Target %s: %s", arg, errstr);
1181
1182 /* try setting blink on the device directly */
1183 memset(&bb, 0, sizeof(bb));
1184 bb.bb_cookie = bl.bl_cookie;
1185 bb.bb_status = blink;
1186 bb.bb_target = location.target;
1187 bb.bb_channel = location.channel;
1188 rv = ioctl(devh, BIOCBLINK, &bb);
1189 if (rv == 0)
1190 return;
1191
1192 /* if the blink didnt work, try to find something that will */
1193
1194 memset(&bi, 0, sizeof(bi));
1195 bi.bi_cookie = bl.bl_cookie;
1196 rv = ioctl(devh, BIOCINQ, &bi);
1197 if (rv == -1) {
1198 warn("BIOCINQ");
1199 return;
1200 }
1201
1202 for (v = 0; v < bi.bi_novol; v++) {
1203 memset(&bv, 0, sizeof(bv));
1204 bv.bv_cookie = bl.bl_cookie;
1205 bv.bv_volid = v;
1206 rv = ioctl(devh, BIOCVOL, &bv);
1207 if (rv == -1) {
1208 warn("BIOCVOL");
1209 return;
1210 }
1211
1212 if (name && strcmp(name, bv.bv_dev) != 0)
1213 continue;
1214
1215 for (d = 0; d < bv.bv_nodisk; d++) {
1216 memset(&bd, 0, sizeof(bd));
1217 bd.bd_cookie = bl.bl_cookie;
1218 bd.bd_volid = v;
1219 bd.bd_diskid = d;
1220
1221 rv = ioctl(devh, BIOCDISK, &bd);
1222 if (rv == -1) {
1223 warn("BIOCDISK");
1224 return;
1225 }
1226
1227 if (bd.bd_channel == location.channel &&
1228 bd.bd_target == location.target &&
1229 bd.bd_lun == location.lun) {
1230 if (bd.bd_procdev[0] != '\0') {
1231 bio_blink(bd.bd_procdev,
1232 location.target, blink);
1233 } else
1234 warnx("Disk %s is not in an enclosure", arg);
1235 return;
1236 }
1237 }
1238 }
1239
1240 warnx("Disk %s does not exist", arg);
1241 return;
1242 }
1243
1244 void
1245 bio_blink(char *enclosure, int target, int blinktype)
1246 {
1247 int bioh;
1248 struct bio_locate bio;
1249 struct bioc_blink blink;
1250 int rv;
1251
1252 bioh = open("/dev/bio", O_RDWR);
1253 if (bioh == -1)
1254 err(1, "Can't open %s", "/dev/bio");
1255
1256 bio.bl_name = enclosure;
1257 rv = ioctl(bioh, BIOCLOCATE, &bio);
1258 if (rv == -1)
1259 errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
1260
1261 memset(&blink, 0, sizeof(blink));
1262 blink.bb_cookie = bio.bl_cookie;
1263 blink.bb_status = blinktype;
1264 blink.bb_target = target;
1265
1266 rv = ioctl(bioh, BIOCBLINK, &blink);
1267 if (rv == -1)
1268 warn("BIOCBLINK");
1269
1270 close(bioh);
1271 }
1272
1273 void
1274 bio_createraid(u_int16_t level, char *dev_list)
1275 {
1276 struct bioc_createraid create;
1277 int rv;
1278 u_int16_t min_disks = 0;
1279
1280 if (debug)
1281 printf("bio_createraid\n");
1282
1283 if (!dev_list)
1284 errx(1, "no devices specified");
1285
1286 switch (level) {
1287 case 0:
1288 min_disks = 1;
1289 break;
1290 case 1:
1291 min_disks = 2;
1292 break;
1293 default:
1294 errx(1, "unsuported raid level");
1295 }
1296
1297 /* XXX validate device list for real */
1298 #if 0
1299 if (strncmp(dev_list, "sd", 2) == 0 && strlen(dev_list) > 2 &&
1300 isdigit(dev_list[2])) {
1301 if (strlen(dev_list) != 3)
1302 errx(1, "only one device supported");
1303
1304 if (debug)
1305 printf("bio_createraid: dev_list: %s\n", dev_list);
1306 }
1307 else
1308 errx(1, "no sd device specified");
1309 #endif
1310
1311 memset(&create, 0, sizeof(create));
1312 create.bc_cookie = bl.bl_cookie;
1313 create.bc_level = level;
1314 create.bc_dev_list_len = strlen(dev_list);
1315 create.bc_dev_list = dev_list;
1316
1317 rv = ioctl(devh, BIOCCREATERAID, &create);
1318 if (rv == -1) {
1319 warn("BIOCCREATERAID");
1320 return;
1321 }
1322 }
1323 /* $NetBSD: bioctl.c,v 1.1.8.2 2007/10/15 05:09:51 riz Exp $ */
1324 /* $OpenBSD: bioctl.c,v 1.52 2007/03/20 15:26:06 jmc Exp $ */
1325
1326 /*
1327 * Copyright (c) 2004, 2005 Marco Peereboom
1328 * All rights reserved.
1329 *
1330 * Redistribution and use in source and binary forms, with or without
1331 * modification, are permitted provided that the following conditions
1332 * are met:
1333 * 1. Redistributions of source code must retain the above copyright
1334 * notice, this list of conditions and the following disclaimer.
1335 * 2. Redistributions in binary form must reproduce the above copyright
1336 * notice, this list of conditions and the following disclaimer in the
1337 * documentation and/or other materials provided with the distribution.
1338 *
1339 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1340 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1341 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1342 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
1343 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1344 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1345 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1346 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1347 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1348 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1349 * SUCH DAMAGE.
1350 *
1351 */
1352 #include <sys/cdefs.h>
1353
1354 #ifndef lint
1355 __RCSID("$NetBSD: bioctl.c,v 1.1.8.2 2007/10/15 05:09:51 riz Exp $");
1356 #endif
1357
1358 #include <sys/ioctl.h>
1359 #include <sys/param.h>
1360 #include <sys/queue.h>
1361 // #include <scsi/scsipi_disk.h>
1362 // #include <scsi/scsipi_all.h>
1363 #include <dev/biovar.h>
1364
1365 #include <errno.h>
1366 #include <err.h>
1367 #include <fcntl.h>
1368 #include <util.h>
1369 #include <stdio.h>
1370 #include <stdlib.h>
1371 #include <string.h>
1372 #include <unistd.h>
1373 #include <ctype.h>
1374 #include <util.h>
1375 #include "strtonum.h"
1376
1377 struct locator {
1378 int channel;
1379 int target;
1380 int lun;
1381 };
1382
1383 void usage(void);
1384 const char *str2locator(const char *, struct locator *);
1385 void cleanup(void);
1386
1387 void bio_inq(char *);
1388 void bio_alarm(char *);
1389 void bio_setstate(char *);
1390 void bio_setblink(char *, char *, int);
1391 void bio_blink(char *, int, int);
1392 void bio_createraid(u_int16_t, char *);
1393
1394 int devh = -1;
1395 int debug;
1396 int human;
1397 int verbose;
1398
1399 struct bio_locate bl;
1400
1401 int
1402 main(int argc, char *argv[])
1403 {
1404 extern char *optarg;
1405 u_int64_t func = 0;
1406 /* u_int64_t subfunc = 0; XXX */
1407 char *bioc_dev = NULL, *sd_dev = NULL;
1408 char /* *realname = NULL, XXX */ *al_arg = NULL;
1409 char *bl_arg = NULL, *dev_list = NULL;
1410 int ch, rv, blink = 0; /* XXX GCC */
1411 u_int16_t cr_level = 0; /* XXX GCC */
1412
1413 if (argc < 2)
1414 usage();
1415
1416 while ((ch = getopt(argc, argv, "b:c:l:u:H:ha:Div")) != -1) {
1417 switch (ch) {
1418 case 'a': /* alarm */
1419 func |= BIOC_ALARM;
1420 al_arg = optarg;
1421 break;
1422 case 'b': /* blink */
1423 func |= BIOC_BLINK;
1424 blink = BIOC_SBBLINK;
1425 bl_arg = optarg;
1426 break;
1427 case 'c': /* create */
1428 func |= BIOC_CREATERAID;
1429 cr_level = atoi(optarg);
1430 break;
1431 case 'u': /* unblink */
1432 func |= BIOC_BLINK;
1433 blink = BIOC_SBUNBLINK;
1434 bl_arg = optarg;
1435 break;
1436 case 'D': /* debug */
1437 debug = 1;
1438 break;
1439 case 'H': /* set hotspare */
1440 func |= BIOC_SETSTATE;
1441 al_arg = optarg;
1442 break;
1443 case 'h':
1444 human = 1;
1445 break;
1446 case 'i': /* inquiry */
1447 func |= BIOC_INQ;
1448 break;
1449 case 'l': /* device list */
1450 func |= BIOC_DEVLIST;
1451 dev_list = optarg;
1452 break;
1453 case 'v':
1454 verbose = 1;
1455 break;
1456 default:
1457 usage();
1458 /* NOTREACHED */
1459 }
1460 }
1461 argc -= optind;
1462 argv += optind;
1463
1464 if (argc != 1)
1465 usage();
1466
1467 if (func == 0)
1468 func |= BIOC_INQ;
1469 #if 0
1470 /* if at least glob sd[0-9]*, it is a drive identifier */
1471 if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
1472 isdigit((int)argv[0][2]))
1473 sd_dev = argv[0];
1474 else
1475 #endif
1476 bioc_dev = argv[0];
1477
1478 if (bioc_dev) {
1479 devh = open("/dev/bio", O_RDWR);
1480 if (devh == -1)
1481 err(1, "Can't open %s", "/dev/bio");
1482
1483 bl.bl_name = bioc_dev;
1484 rv = ioctl(devh, BIOCLOCATE, &bl);
1485 if (rv == -1)
1486 errx(1, "Can't locate %s device via %s",
1487 bl.bl_name, "/dev/bio");
1488 }
1489 #if 0
1490 else if (sd_dev) {
1491 devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
1492 if (devh == -1)
1493 err(1, "Can't open %s", sd_dev);
1494 }
1495 #endif
1496 else
1497 errx(1, "need -d or -f parameter");
1498
1499 if (debug)
1500 warnx("cookie = %p", bl.bl_cookie);
1501
1502 if (func & BIOC_INQ) {
1503 bio_inq(sd_dev);
1504 } else if (func == BIOC_ALARM) {
1505 bio_alarm(al_arg);
1506 } else if (func == BIOC_BLINK) {
1507 bio_setblink(sd_dev, bl_arg, blink);
1508 } else if (func == BIOC_SETSTATE) {
1509 bio_setstate(al_arg);
1510 } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
1511 if (!(func & BIOC_CREATERAID))
1512 errx(1, "need -c parameter");
1513 if (!(func & BIOC_DEVLIST))
1514 errx(1, "need -l parameter");
1515 if (sd_dev)
1516 errx(1, "can't use sd device");
1517 bio_createraid(cr_level, dev_list);
1518 }
1519
1520 return (0);
1521 }
1522
1523 void
1524 usage(void)
1525 {
1526 extern char *__progname;
1527
1528 fprintf(stderr,
1529 "usage: %s [-Dhiv] [-a alarm-function] "
1530 "[-b channel:target[.lun]]\n"
1531 "\t[-c raidlevel] [-H channel:target[.lun]]\n"
1532 "\t[-l special[,special[,...]]] "
1533 "[-u channel:target[.lun]] device\n", __progname);
1534
1535 exit(1);
1536 }
1537
1538 const char *
1539 str2locator(const char *string, struct locator *location)
1540 {
1541 const char *errstr;
1542 char parse[80], *targ, *lun;
1543
1544 strlcpy(parse, string, sizeof parse);
1545 targ = strchr(parse, ':');
1546 if (targ == NULL)
1547 return ("target not specified");
1548 *targ++ = '\0';
1549
1550 lun = strchr(targ, '.');
1551 if (lun != NULL) {
1552 *lun++ = '\0';
1553 location->lun = strtonum(lun, 0, 256, &errstr);
1554 if (errstr)
1555 return (errstr);
1556 } else
1557 location->lun = 0;
1558
1559 location->target = strtonum(targ, 0, 256, &errstr);
1560 if (errstr)
1561 return (errstr);
1562 location->channel = strtonum(parse, 0, 256, &errstr);
1563 if (errstr)
1564 return (errstr);
1565 return (NULL);
1566 }
1567
1568 void
1569 bio_inq(char *name)
1570 {
1571 const char *status;
1572 char size[64], scsiname[16], volname[32];
1573 char percent[10], seconds[20];
1574 int rv, i, d, volheader, hotspare, unused;
1575 char encname[16], serial[32];
1576 struct bioc_disk bd;
1577 struct bioc_inq bi;
1578 struct bioc_vol bv;
1579
1580 memset(&bi, 0, sizeof(bi));
1581
1582 if (debug)
1583 printf("bio_inq\n");
1584
1585 bi.bi_cookie = bl.bl_cookie;
1586
1587 rv = ioctl(devh, BIOCINQ, &bi);
1588 if (rv == -1) {
1589 warn("BIOCINQ");
1590 return;
1591 }
1592
1593 if (debug)
1594 printf("bio_inq { %p, %s, %d, %d }\n",
1595 bi.bi_cookie,
1596 bi.bi_dev,
1597 bi.bi_novol,
1598 bi.bi_nodisk);
1599
1600 volheader = 0;
1601 for (i = 0; i < bi.bi_novol; i++) {
1602 memset(&bv, 0, sizeof(bv));
1603 bv.bv_cookie = bl.bl_cookie;
1604 bv.bv_volid = i;
1605 bv.bv_percent = -1;
1606 bv.bv_seconds = 0;
1607
1608 rv = ioctl(devh, BIOCVOL, &bv);
1609 if (rv == -1) {
1610 warn("BIOCVOL");
1611 return;
1612 }
1613
1614 if (name && strcmp(name, bv.bv_dev) != 0)
1615 continue;
1616
1617 if (!volheader) {
1618 volheader = 1;
1619 printf("%-7s %-10s %14s %-8s\n",
1620 "Volume", "Status", "Size", "Device");
1621 }
1622
1623 percent[0] = '\0';
1624 seconds[0] = '\0';
1625 if (bv.bv_percent != -1)
1626 snprintf(percent, sizeof percent,
1627 " %d%% done", bv.bv_percent);
1628 if (bv.bv_seconds)
1629 snprintf(seconds, sizeof seconds,
1630 " %u seconds", bv.bv_seconds);
1631 switch (bv.bv_status) {
1632 case BIOC_SVONLINE:
1633 status = BIOC_SVONLINE_S;
1634 break;
1635 case BIOC_SVOFFLINE:
1636 status = BIOC_SVOFFLINE_S;
1637 break;
1638 case BIOC_SVDEGRADED:
1639 status = BIOC_SVDEGRADED_S;
1640 break;
1641 case BIOC_SVBUILDING:
1642 status = BIOC_SVBUILDING_S;
1643 break;
1644 case BIOC_SVREBUILD:
1645 status = BIOC_SVREBUILD_S;
1646 break;
1647 case BIOC_SVSCRUB:
1648 status = BIOC_SVSCRUB_S;
1649 break;
1650 case BIOC_SVINVALID:
1651 default:
1652 status = BIOC_SVINVALID_S;
1653 }
1654
1655 snprintf(volname, sizeof volname, "%s %u",
1656 bi.bi_dev, bv.bv_volid);
1657
1658 if (bv.bv_level == -1 && bv.bv_nodisk == 1) {
1659 hotspare = 1;
1660 unused = 0;
1661 } else if (bv.bv_level == -2 && bv.bv_nodisk == 1) {
1662 unused = 1;
1663 hotspare = 0;
1664 } else {
1665 unused = 0;
1666 hotspare = 0;
1667
1668 if (human)
1669 humanize_number(size, 5,
1670 (int64_t)bv.bv_size, "", HN_AUTOSCALE,
1671 HN_B | HN_NOSPACE | HN_DECIMAL);
1672 else
1673 snprintf(size, sizeof size, "%14llu",
1674 (long long unsigned int)bv.bv_size);
1675 printf("%7s %-10s %14s %-7s RAID%u%s%s\n",
1676 volname, status, size, bv.bv_dev,
1677 bv.bv_level, percent, seconds);
1678 }
1679
1680 for (d = 0; d < bv.bv_nodisk; d++) {
1681 memset(&bd, 0, sizeof(bd));
1682 bd.bd_cookie = bl.bl_cookie;
1683 bd.bd_diskid = d;
1684 bd.bd_volid = i;
1685
1686 rv = ioctl(devh, BIOCDISK, &bd);
1687 if (rv == -1) {
1688 warn("BIOCDISK");
1689 return;
1690 }
1691
1692 switch (bd.bd_status) {
1693 case BIOC_SDONLINE:
1694 status = BIOC_SDONLINE_S;
1695 break;
1696 case BIOC_SDOFFLINE:
1697 status = BIOC_SDOFFLINE_S;
1698 break;
1699 case BIOC_SDFAILED:
1700 status = BIOC_SDFAILED_S;
1701 break;
1702 case BIOC_SDREBUILD:
1703 status = BIOC_SDREBUILD_S;
1704 break;
1705 case BIOC_SDHOTSPARE:
1706 status = BIOC_SDHOTSPARE_S;
1707 break;
1708 case BIOC_SDUNUSED:
1709 status = BIOC_SDUNUSED_S;
1710 break;
1711 case BIOC_SDSCRUB:
1712 status = BIOC_SDSCRUB_S;
1713 break;
1714 case BIOC_SDINVALID:
1715 default:
1716 status = BIOC_SDINVALID_S;
1717 }
1718
1719 if (hotspare || unused)
1720 ; /* use volname from parent volume */
1721 else
1722 snprintf(volname, sizeof volname, " %3u",
1723 bd.bd_diskid);
1724
1725 if (human)
1726 humanize_number(size, 5,
1727 bd.bd_size, "", HN_AUTOSCALE,
1728 HN_B | HN_NOSPACE | HN_DECIMAL);
1729 else
1730 snprintf(size, sizeof size, "%14llu",
1731 (long long unsigned int)bd.bd_size);
1732 snprintf(scsiname, sizeof scsiname,
1733 "%u:%u.%u",
1734 bd.bd_channel, bd.bd_target, bd.bd_lun);
1735 if (bd.bd_procdev[0])
1736 strlcpy(encname, bd.bd_procdev, sizeof encname);
1737 else
1738 strlcpy(encname, "noencl", sizeof encname);
1739 if (bd.bd_serial[0])
1740 strlcpy(serial, bd.bd_serial, sizeof serial);
1741 else
1742 strlcpy(serial, "unknown serial", sizeof serial);
1743
1744 printf("%7s %-10s %14s %-7s %-6s <%s>\n",
1745 volname, status, size, scsiname, encname,
1746 bd.bd_vendor);
1747 if (verbose)
1748 printf("%7s %-10s %14s %-7s %-6s '%s'\n",
1749 "", "", "", "", "", serial);
1750 }
1751 }
1752 }
1753
1754 void
1755 bio_alarm(char *arg)
1756 {
1757 int rv;
1758 struct bioc_alarm ba;
1759
1760 ba.ba_cookie = bl.bl_cookie;
1761
1762 switch (arg[0]) {
1763 case 'q': /* silence alarm */
1764 /* FALLTHROUGH */
1765 case 's':
1766 ba.ba_opcode = BIOC_SASILENCE;
1767 break;
1768
1769 case 'e': /* enable alarm */
1770 ba.ba_opcode = BIOC_SAENABLE;
1771 break;
1772
1773 case 'd': /* disable alarm */
1774 ba.ba_opcode = BIOC_SADISABLE;
1775 break;
1776
1777 case 't': /* test alarm */
1778 ba.ba_opcode = BIOC_SATEST;
1779 break;
1780
1781 case 'g': /* get alarm state */
1782 ba.ba_opcode = BIOC_GASTATUS;
1783 break;
1784
1785 default:
1786 warnx("invalid alarm function: %s", arg);
1787 return;
1788 }
1789
1790 rv = ioctl(devh, BIOCALARM, &ba);
1791 if (rv == -1) {
1792 warn("BIOCALARM");
1793 return;
1794 }
1795
1796 if (arg[0] == 'g') {
1797 printf("alarm is currently %s\n",
1798 ba.ba_status ? "enabled" : "disabled");
1799
1800 }
1801 }
1802
1803 void
1804 bio_setstate(char *arg)
1805 {
1806 struct bioc_setstate bs;
1807 struct locator location;
1808 const char *errstr;
1809 int rv;
1810
1811 errstr = str2locator(arg, &location);
1812 if (errstr)
1813 errx(1, "Target %s: %s", arg, errstr);
1814
1815 bs.bs_cookie = bl.bl_cookie;
1816 bs.bs_status = BIOC_SSHOTSPARE;
1817 bs.bs_channel = location.channel;
1818 bs.bs_target = location.target;
1819 bs.bs_lun = location.lun;
1820
1821 rv = ioctl(devh, BIOCSETSTATE, &bs);
1822 if (rv == -1) {
1823 warn("BIOCSETSTATE");
1824 return;
1825 }
1826 }
1827
1828 void
1829 bio_setblink(char *name, char *arg, int blink)
1830 {
1831 struct locator location;
1832 struct bioc_inq bi;
1833 struct bioc_vol bv;
1834 struct bioc_disk bd;
1835 struct bioc_blink bb;
1836 const char *errstr;
1837 int v, d, rv;
1838
1839 errstr = str2locator(arg, &location);
1840 if (errstr)
1841 errx(1, "Target %s: %s", arg, errstr);
1842
1843 /* try setting blink on the device directly */
1844 memset(&bb, 0, sizeof(bb));
1845 bb.bb_cookie = bl.bl_cookie;
1846 bb.bb_status = blink;
1847 bb.bb_target = location.target;
1848 bb.bb_channel = location.channel;
1849 rv = ioctl(devh, BIOCBLINK, &bb);
1850 if (rv == 0)
1851 return;
1852
1853 /* if the blink didnt work, try to find something that will */
1854
1855 memset(&bi, 0, sizeof(bi));
1856 bi.bi_cookie = bl.bl_cookie;
1857 rv = ioctl(devh, BIOCINQ, &bi);
1858 if (rv == -1) {
1859 warn("BIOCINQ");
1860 return;
1861 }
1862
1863 for (v = 0; v < bi.bi_novol; v++) {
1864 memset(&bv, 0, sizeof(bv));
1865 bv.bv_cookie = bl.bl_cookie;
1866 bv.bv_volid = v;
1867 rv = ioctl(devh, BIOCVOL, &bv);
1868 if (rv == -1) {
1869 warn("BIOCVOL");
1870 return;
1871 }
1872
1873 if (name && strcmp(name, bv.bv_dev) != 0)
1874 continue;
1875
1876 for (d = 0; d < bv.bv_nodisk; d++) {
1877 memset(&bd, 0, sizeof(bd));
1878 bd.bd_cookie = bl.bl_cookie;
1879 bd.bd_volid = v;
1880 bd.bd_diskid = d;
1881
1882 rv = ioctl(devh, BIOCDISK, &bd);
1883 if (rv == -1) {
1884 warn("BIOCDISK");
1885 return;
1886 }
1887
1888 if (bd.bd_channel == location.channel &&
1889 bd.bd_target == location.target &&
1890 bd.bd_lun == location.lun) {
1891 if (bd.bd_procdev[0] != '\0') {
1892 bio_blink(bd.bd_procdev,
1893 location.target, blink);
1894 } else
1895 warnx("Disk %s is not in an enclosure", arg);
1896 return;
1897 }
1898 }
1899 }
1900
1901 warnx("Disk %s does not exist", arg);
1902 return;
1903 }
1904
1905 void
1906 bio_blink(char *enclosure, int target, int blinktype)
1907 {
1908 int bioh;
1909 struct bio_locate bio;
1910 struct bioc_blink blink;
1911 int rv;
1912
1913 bioh = open("/dev/bio", O_RDWR);
1914 if (bioh == -1)
1915 err(1, "Can't open %s", "/dev/bio");
1916
1917 bio.bl_name = enclosure;
1918 rv = ioctl(bioh, BIOCLOCATE, &bio);
1919 if (rv == -1)
1920 errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
1921
1922 memset(&blink, 0, sizeof(blink));
1923 blink.bb_cookie = bio.bl_cookie;
1924 blink.bb_status = blinktype;
1925 blink.bb_target = target;
1926
1927 rv = ioctl(bioh, BIOCBLINK, &blink);
1928 if (rv == -1)
1929 warn("BIOCBLINK");
1930
1931 close(bioh);
1932 }
1933
1934 void
1935 bio_createraid(u_int16_t level, char *dev_list)
1936 {
1937 struct bioc_createraid create;
1938 int rv;
1939 u_int16_t min_disks = 0;
1940
1941 if (debug)
1942 printf("bio_createraid\n");
1943
1944 if (!dev_list)
1945 errx(1, "no devices specified");
1946
1947 switch (level) {
1948 case 0:
1949 min_disks = 1;
1950 break;
1951 case 1:
1952 min_disks = 2;
1953 break;
1954 default:
1955 errx(1, "unsuported raid level");
1956 }
1957
1958 /* XXX validate device list for real */
1959 #if 0
1960 if (strncmp(dev_list, "sd", 2) == 0 && strlen(dev_list) > 2 &&
1961 isdigit(dev_list[2])) {
1962 if (strlen(dev_list) != 3)
1963 errx(1, "only one device supported");
1964
1965 if (debug)
1966 printf("bio_createraid: dev_list: %s\n", dev_list);
1967 }
1968 else
1969 errx(1, "no sd device specified");
1970 #endif
1971
1972 memset(&create, 0, sizeof(create));
1973 create.bc_cookie = bl.bl_cookie;
1974 create.bc_level = level;
1975 create.bc_dev_list_len = strlen(dev_list);
1976 create.bc_dev_list = dev_list;
1977
1978 rv = ioctl(devh, BIOCCREATERAID, &create);
1979 if (rv == -1) {
1980 warn("BIOCCREATERAID");
1981 return;
1982 }
1983 }
1984