1 /* $NetBSD: bioctl.c,v 1.11 2008/03/03 16:10:48 xtraeme Exp $ */
2 /* $OpenBSD: bioctl.c,v 1.52 2007/03/20 15:26:06 jmc Exp $ */
5 * Copyright (c) 2007, 2008 Juan Romero Pardines
6 * Copyright (c) 2004, 2005 Marco Peereboom
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: bioctl.c,v 1.11 2008/03/03 16:10:48 xtraeme Exp $");
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <sys/param.h>
40 #include <sys/queue.h>
41 #include <dev/biovar.h>
58 const char *arg_names
;
59 void (*cmd_func
)(int, int, char **);
79 static void usage(void);
80 static void bio_alarm(int, int, char **);
81 static void bio_show_common(int, int, char **);
82 static int bio_show_volumes(struct biotmp
*);
83 static void bio_show_disks(struct biotmp
*);
84 static void bio_setblink(int, int, char **);
85 static void bio_blink(int, char *, int, int);
86 static void bio_setstate_hotspare(int, int, char **);
87 static void bio_setstate_passthru(int, int, char **);
88 static void bio_setstate_common(int, char *, struct bioc_setstate
*,
90 static void bio_setstate_consistency(int, int, char **);
91 static void bio_volops_create(int, int, char **);
93 static void bio_volops_modify(int, int, char **);
95 static void bio_volops_remove(int, int, char **);
97 static const char *str2locator(const char *, struct locator
*);
99 static struct bio_locate bl
;
100 static struct command commands
[] = {
103 "[disks] | [volumes]",
107 "[enable] | [disable] | [silence] | [test]",
111 "start [channel:target[.lun]] | stop [channel:target[.lun]]",
115 "add channel:target.lun | remove channel:target.lun",
116 bio_setstate_hotspare
},
119 "add DISKID channel:target.lun | remove channel:target.lun",
120 bio_setstate_passthru
},
123 "start VOLID | stop VOLID",
124 bio_setstate_consistency
},
127 "volume VOLID DISKIDs [SIZE] STRIPE RAID_LEVEL channel:target.lun",
132 "volume VOLID STRIPE RAID_LEVEL channel:target.lun",
137 "volume VOLID channel:target.lun",
144 main(int argc
, char **argv
)
150 /* Must have at least: device command */
154 /* Skip program name, get and skip device name and command */
161 /* Look up and call the command */
162 for (i
= 0; commands
[i
].cmd_name
!= NULL
; i
++)
163 if (strcmp(cmdname
, commands
[i
].cmd_name
) == 0)
165 if (commands
[i
].cmd_name
== NULL
)
166 errx(EXIT_FAILURE
, "unknown command: %s", cmdname
);
168 /* Locate the device by issuing the BIOCLOCATE ioctl */
169 fd
= open("/dev/bio", O_RDWR
);
171 err(EXIT_FAILURE
, "Can't open /dev/bio");
174 if (ioctl(fd
, BIOCLOCATE
, &bl
) == -1)
175 errx(EXIT_FAILURE
, "Can't locate %s device via /dev/bio",
178 /* and execute the command */
179 (*commands
[i
].cmd_func
)(fd
, argc
, argv
);
190 (void)fprintf(stderr
, "usage: %s device command [arg [...]]\n",
193 (void)fprintf(stderr
, "Available commands:\n");
194 for (i
= 0; commands
[i
].cmd_name
!= NULL
; i
++)
195 (void)fprintf(stderr
, " %s %s\n", commands
[i
].cmd_name
,
196 commands
[i
].arg_names
);
203 str2locator(const char *string
, struct locator
*location
)
206 char parse
[80], *targ
, *lun
;
208 strlcpy(parse
, string
, sizeof parse
);
209 targ
= strchr(parse
, ':');
211 return "target not specified";
214 lun
= strchr(targ
, '.');
217 location
->lun
= strtonum(lun
, 0, 256, &errstr
);
223 location
->target
= strtonum(targ
, 0, 256, &errstr
);
226 location
->channel
= strtonum(parse
, 0, 256, &errstr
);
233 * Shows info about available RAID volumes.
236 bio_show_volumes(struct biotmp
*bt
)
239 const char *status
, *rtypestr
, *stripestr
;
240 char size
[64], percent
[16], seconds
[20];
241 char rtype
[16], stripe
[16], tmp
[32];
243 rtypestr
= stripestr
= NULL
;
245 memset(&bv
, 0, sizeof(bv
));
246 bv
.bv_cookie
= bl
.bl_cookie
;
247 bv
.bv_volid
= bt
->volid
;
251 if (ioctl(bt
->fd
, BIOCVOL
, &bv
) == -1)
252 err(EXIT_FAILURE
, "BIOCVOL");
256 if (bv
.bv_percent
!= -1)
257 snprintf(percent
, sizeof(percent
),
258 " %3.2f%% done", bv
.bv_percent
/ 10.0);
260 snprintf(seconds
, sizeof(seconds
),
261 " %u seconds", bv
.bv_seconds
);
263 switch (bv
.bv_status
) {
265 status
= BIOC_SVONLINE_S
;
268 status
= BIOC_SVOFFLINE_S
;
270 case BIOC_SVDEGRADED
:
271 status
= BIOC_SVDEGRADED_S
;
273 case BIOC_SVBUILDING
:
274 status
= BIOC_SVBUILDING_S
;
277 status
= BIOC_SVREBUILD_S
;
279 case BIOC_SVMIGRATING
:
280 status
= BIOC_SVMIGRATING_S
;
283 status
= BIOC_SVSCRUB_S
;
285 case BIOC_SVCHECKING
:
286 status
= BIOC_SVCHECKING_S
;
290 status
= BIOC_SVINVALID_S
;
294 snprintf(bt
->volname
, sizeof(bt
->volname
), "%u", bv
.bv_volid
);
296 snprintf(tmp
, sizeof(tmp
), "%s %s", bv
.bv_dev
, bv
.bv_vendor
);
298 snprintf(tmp
, sizeof(tmp
), "%s", bv
.bv_dev
);
300 switch (bv
.bv_level
) {
301 case BIOC_SVOL_HOTSPARE
:
302 rtypestr
= "Hot spare";
305 case BIOC_SVOL_PASSTHRU
:
306 rtypestr
= "Pass through";
309 case BIOC_SVOL_RAID01
:
310 rtypestr
= "RAID 0+1";
312 case BIOC_SVOL_RAID10
:
313 rtypestr
= "RAID 1+0";
316 snprintf(rtype
, sizeof(rtype
), "RAID %u", bv
.bv_level
);
317 if (bv
.bv_level
== 1 || bv
.bv_stripe_size
== 0)
323 snprintf(rtype
, sizeof(rtype
), rtypestr
);
325 snprintf(stripe
, sizeof(stripe
), stripestr
);
327 snprintf(stripe
, sizeof(stripe
), "%uK", bv
.bv_stripe_size
);
329 humanize_number(size
, 5, (int64_t)bv
.bv_size
, "", HN_AUTOSCALE
,
330 HN_B
| HN_NOSPACE
| HN_DECIMAL
);
332 printf("%6s %-12s %4s %20s %8s %6s %s%s\n",
333 bt
->volname
, status
, size
, tmp
,
334 rtype
, stripe
, percent
, seconds
);
342 * Shows info about physical disks.
345 bio_show_disks(struct biotmp
*bt
)
349 char size
[64], serial
[32], scsiname
[16];
351 memset(&bd
, 0, sizeof(bd
));
352 bd
.bd_cookie
= bl
.bl_cookie
;
353 bd
.bd_diskid
= bt
->diskid
;
354 bd
.bd_volid
= bt
->volid
;
356 if (bt
->show_disknovol
) {
357 if (ioctl(bt
->fd
, BIOCDISK_NOVOL
, &bd
) == -1)
358 err(EXIT_FAILURE
, "BIOCDISK_NOVOL");
359 if (!bd
.bd_disknovol
)
362 if (ioctl(bt
->fd
, BIOCDISK
, &bd
) == -1)
363 err(EXIT_FAILURE
, "BIOCDISK");
366 switch (bd
.bd_status
) {
368 status
= BIOC_SDONLINE_S
;
371 status
= BIOC_SDOFFLINE_S
;
374 status
= BIOC_SDFAILED_S
;
377 status
= BIOC_SDREBUILD_S
;
379 case BIOC_SDHOTSPARE
:
380 status
= BIOC_SDHOTSPARE_S
;
383 status
= BIOC_SDUNUSED_S
;
386 status
= BIOC_SDSCRUB_S
;
388 case BIOC_SDPASSTHRU
:
389 status
= BIOC_SDPASSTHRU_S
;
393 status
= BIOC_SDINVALID_S
;
398 snprintf(bt
->volname
, sizeof(bt
->volname
),
399 "%u:%u", bt
->bv
->bv_volid
, bd
.bd_diskid
);
401 humanize_number(size
, 5, bd
.bd_size
, "", HN_AUTOSCALE
,
402 HN_B
| HN_NOSPACE
| HN_DECIMAL
);
404 if (bd
.bd_procdev
[0])
405 snprintf(scsiname
, sizeof(scsiname
), "%u:%u.%u %s",
406 bd
.bd_channel
, bd
.bd_target
, bd
.bd_lun
,
409 snprintf(scsiname
, sizeof(scsiname
), "%u:%u.%u noencl",
410 bd
.bd_channel
, bd
.bd_target
, bd
.bd_lun
);
413 strlcpy(serial
, bd
.bd_serial
, sizeof(serial
));
415 strlcpy(serial
, "unknown serial", sizeof(serial
));
418 printf("%6s %-12s %4s %20s <%s>\n",
419 bt
->volname
, status
, size
, scsiname
,
422 printf("%5d [%-28s] %-12s %-6s %12s\n",
423 bt
->diskid
, bd
.bd_vendor
, status
, size
, scsiname
);
428 * Shows info about volumes/disks.
431 bio_show_common(int fd
, int argc
, char **argv
)
436 bool show_all
, show_disks
;
437 bool show_vols
, show_caps
;
439 show_all
= show_disks
= show_vols
= show_caps
= false;
445 if (strcmp(argv
[0], "disks") == 0)
447 else if (strcmp(argv
[0], "volumes") == 0)
454 memset(&bi
, 0, sizeof(bi
));
455 bi
.bi_cookie
= bl
.bl_cookie
;
457 if (ioctl(fd
, BIOCINQ
, &bi
) == -1)
458 err(EXIT_FAILURE
, "BIOCINQ");
461 * If there are volumes there's no point to continue.
463 if (show_all
|| show_vols
) {
465 warnx("no volumes available");
470 biot
= calloc(1, sizeof(*biot
));
472 err(EXIT_FAILURE
, "biotemp calloc");
477 * Go to the disks section if that was specified.
483 * Common code to show only info about volumes and disks
484 * associated to them.
486 printf("%6s %-12s %4s %20s %8s %6s\n",
487 "Volume", "Status", "Size", "Device/Label",
489 printf("=============================================="
490 "===============\n");
492 for (i
= 0; i
< bi
.bi_novol
; i
++) {
495 ndisks
= bio_show_volumes(biot
);
499 for (d
= 0; d
< ndisks
; d
++) {
501 bio_show_disks(biot
);
509 * show info about all disks connected to the raid controller,
510 * even if they aren't associated with a volume or raid set.
513 printf("%5s %-30s %-12s %-6s %12s\n",
514 "Disk", "Model/Serial", "Status", "Size", "Location");
515 printf("==============================================="
516 "======================\n");
517 for (d
= 0; d
< bi
.bi_nodisk
; d
++) {
518 biot
->show_disknovol
= true;
520 bio_show_disks(biot
);
528 * To handle the alarm feature.
531 bio_alarm(int fd
, int argc
, char **argv
)
533 struct bioc_alarm ba
;
536 memset(&ba
, 0, sizeof(ba
));
537 ba
.ba_cookie
= bl
.bl_cookie
;
543 /* show alarm status */
544 ba
.ba_opcode
= BIOC_GASTATUS
;
546 } else if (strcmp(argv
[0], "silence") == 0) {
548 ba
.ba_opcode
= BIOC_SASILENCE
;
549 } else if (strcmp(argv
[0], "enable") == 0) {
551 ba
.ba_opcode
= BIOC_SAENABLE
;
552 } else if (strcmp(argv
[0], "disable") == 0) {
554 ba
.ba_opcode
= BIOC_SADISABLE
;
555 } else if (strcmp(argv
[0], "test") == 0) {
557 ba
.ba_opcode
= BIOC_SATEST
;
561 if (ioctl(fd
, BIOCALARM
, &ba
) == -1)
562 err(EXIT_FAILURE
, "BIOCALARM");
565 printf("alarm is currently %s\n",
566 ba
.ba_status
? "enabled" : "disabled");
570 * To add/remove a hotspare disk.
573 bio_setstate_hotspare(int fd
, int argc
, char **argv
)
575 struct bioc_setstate bs
;
576 struct locator location
;
578 memset(&bs
, 0, sizeof(bs
));
583 if (strcmp(argv
[0], "add") == 0)
584 bs
.bs_status
= BIOC_SSHOTSPARE
;
585 else if (strcmp(argv
[0], "remove") == 0)
586 bs
.bs_status
= BIOC_SSDELHOTSPARE
;
590 bio_setstate_common(fd
, argv
[1], &bs
, &location
);
594 * To add/remove a pass through disk.
597 bio_setstate_passthru(int fd
, int argc
, char **argv
)
599 struct bioc_setstate bs
;
600 struct locator location
;
607 memset(&bs
, 0, sizeof(bs
));
609 if (strcmp(argv
[0], "add") == 0) {
610 if (argv
[1] == NULL
|| argv
[2] == NULL
)
613 bs
.bs_status
= BIOC_SSPASSTHRU
;
614 } else if (strcmp(argv
[0], "remove") == 0) {
618 bs
.bs_status
= BIOC_SSDELPASSTHRU
;
624 bio_setstate_common(fd
, argv
[1], &bs
, &location
);
626 bs
.bs_other_id
= (unsigned int)strtoul(argv
[1], &endptr
, 10);
628 errx(EXIT_FAILURE
, "Invalid Volume ID value");
630 bio_setstate_common(fd
, argv
[2], &bs
, &location
);
635 * To start/stop a consistency check in a RAID volume.
638 bio_setstate_consistency(int fd
, int argc
, char **argv
)
640 struct bioc_setstate bs
;
646 memset(&bs
, 0, sizeof(bs
));
648 if (strcmp(argv
[0], "start") == 0)
649 bs
.bs_status
= BIOC_SSCHECKSTART_VOL
;
650 else if (strcmp(argv
[0], "stop") == 0)
651 bs
.bs_status
= BIOC_SSCHECKSTOP_VOL
;
655 bs
.bs_volid
= (unsigned int)strtoul(argv
[1], &endptr
, 10);
657 errx(EXIT_FAILURE
, "Invalid Volume ID value");
659 bio_setstate_common(fd
, NULL
, &bs
, NULL
);
663 bio_setstate_common(int fd
, char *arg
, struct bioc_setstate
*bs
,
664 struct locator
*location
)
668 if (!arg
|| !location
)
671 errstr
= str2locator(arg
, location
);
673 errx(EXIT_FAILURE
, "Target %s: %s", arg
, errstr
);
675 bs
->bs_channel
= location
->channel
;
676 bs
->bs_target
= location
->target
;
677 bs
->bs_lun
= location
->lun
;
680 bs
->bs_cookie
= bl
.bl_cookie
;
682 if (ioctl(fd
, BIOCSETSTATE
, bs
) == -1)
683 err(EXIT_FAILURE
, "BIOCSETSTATE");
687 * To create a RAID volume.
690 bio_volops_create(int fd
, int argc
, char **argv
)
692 struct bioc_volops bc
;
695 struct locator location
;
696 uint64_t total_size
= 0, disksize
= 0;
699 char *endptr
, *stripe
, levelstr
[32];
700 char *scsiname
, *raid_level
, size
[64];
701 int disk_first
= 0, disk_end
= 0;
702 int i
, nfreedisks
= 0;
705 if (argc
< 6 || argc
> 7)
708 if (strcmp(argv
[0], "volume") != 0)
712 * No size requested, use max size depending on RAID level.
716 raid_level
= argv
[4];
720 raid_level
= argv
[5];
724 memset(&bd
, 0, sizeof(bd
));
725 memset(&bc
, 0, sizeof(bc
));
726 memset(&bi
, 0, sizeof(bi
));
728 bc
.bc_cookie
= bd
.bd_cookie
= bi
.bi_cookie
= bl
.bl_cookie
;
729 bc
.bc_opcode
= BIOC_VCREATE_VOLUME
;
731 bc
.bc_volid
= (unsigned int)strtoul(argv
[1], &endptr
, 10);
733 errx(EXIT_FAILURE
, "Invalid Volume ID value");
736 if (dehumanize_number(argv
[3], &volsize
) == -1
738 errx(EXIT_FAILURE
, "Invalid SIZE value");
740 bc
.bc_stripe
= (unsigned int)strtoul(stripe
, &endptr
, 10);
742 errx(EXIT_FAILURE
, "Invalid STRIPE size value");
744 bc
.bc_level
= (unsigned int)strtoul(raid_level
, &endptr
, 10);
746 errx(EXIT_FAILURE
, "Invalid RAID_LEVEL value");
748 errstr
= str2locator(scsiname
, &location
);
750 errx(EXIT_FAILURE
, "Target %s: %s", scsiname
, errstr
);
753 * Parse the device list that will be used for the volume,
754 * by using a bit field for the disks.
756 if ((isdigit((unsigned char)argv
[2][0]) == 0) || argv
[2][1] != '-' ||
757 (isdigit((unsigned char)argv
[2][2]) == 0))
758 errx(EXIT_FAILURE
, "Invalid DISKIDs value");
760 disk_first
= atoi(&argv
[2][0]);
761 disk_end
= atoi(&argv
[2][2]);
763 for (i
= disk_first
; i
< disk_end
+ 1; i
++) {
764 bc
.bc_devmask
|= (1 << i
);
769 * Find out how many disks are free and how much size we
770 * have available for the new volume.
772 if (ioctl(fd
, BIOCINQ
, &bi
) == -1)
773 err(EXIT_FAILURE
, "BIOCINQ");
775 for (i
= 0; i
< bi
.bi_nodisk
; i
++) {
777 if (ioctl(fd
, BIOCDISK_NOVOL
, &bd
) == -1)
778 err(EXIT_FAILURE
, "BIOCDISK_NOVOL");
780 if (bd
.bd_status
== BIOC_SDUNUSED
) {
782 disksize
= bd
.bd_size
;
784 total_size
+= bd
.bd_size
;
789 if (user_disks
> nfreedisks
)
790 errx(EXIT_FAILURE
, "specified disks number is higher than "
791 "available free disks");
794 * Basic checks to be sure we don't do something stupid.
797 errx(EXIT_FAILURE
, "No free disks available");
799 switch (bc
.bc_level
) {
800 case 0: /* RAID 0 requires at least one disk */
802 if ((uint64_t)volsize
> (disksize
* user_disks
))
803 errx(EXIT_FAILURE
, "volume size specified "
804 "is larger than available on free disks");
805 bc
.bc_size
= (uint64_t)volsize
;
807 bc
.bc_size
= disksize
* user_disks
;
810 case 1: /* RAID 1 requires two disks and size is total / 2 */
811 if (nfreedisks
< 2 || user_disks
< 2)
812 errx(EXIT_FAILURE
, "2 disks are required at least for "
815 /* RAID 1+0 requires three disks at least */
816 if (nfreedisks
> 2 && user_disks
> 2)
817 bc
.bc_level
= BIOC_SVOL_RAID10
;
820 if ((uint64_t)volsize
> ((disksize
* user_disks
) / 2))
821 errx(EXIT_FAILURE
, "volume size specified "
822 "is larger than available on free disks");
823 bc
.bc_size
= (uint64_t)volsize
;
825 bc
.bc_size
= ((disksize
* user_disks
) / 2);
828 case 3: /* RAID 3/5 requires three disks and size is total - 1 disk */
830 if (nfreedisks
< 3 || user_disks
< 3)
831 errx(EXIT_FAILURE
, "3 disks are required at least for "
835 if ((uint64_t)volsize
> (disksize
* (user_disks
- 1)))
836 errx(EXIT_FAILURE
, "volume size specified "
837 "is larger than available on free disks");
838 bc
.bc_size
= (uint64_t)volsize
;
840 bc
.bc_size
= (disksize
* (user_disks
- 1));
843 case 6: /* RAID 6 requires four disks and size is total - 2 disks */
844 if (nfreedisks
< 4 || user_disks
< 4)
845 errx(EXIT_FAILURE
, "4 disks are required at least for "
849 if ((uint64_t)volsize
>
850 ((disksize
* user_disks
) - (disksize
* 2)))
851 err(EXIT_FAILURE
, "volume size specified "
852 "is larger than available on free disks");
853 bc
.bc_size
= (uint64_t)volsize
;
856 (((disksize
* user_disks
) - (disksize
* 2)));
860 errx(EXIT_FAILURE
, "Unsupported RAID level");
863 bc
.bc_channel
= location
.channel
;
864 bc
.bc_target
= location
.target
;
865 bc
.bc_lun
= location
.lun
;
867 if (ioctl(fd
, BIOCVOLOPS
, &bc
) == -1)
868 err(EXIT_FAILURE
, "BIOCVOLOPS");
870 humanize_number(size
, 5, bc
.bc_size
, "", HN_AUTOSCALE
,
871 HN_B
| HN_NOSPACE
| HN_DECIMAL
);
873 if (bc
.bc_level
== BIOC_SVOL_RAID10
)
874 snprintf(levelstr
, sizeof(levelstr
), "1+0");
876 snprintf(levelstr
, sizeof(levelstr
), "%u", bc
.bc_level
);
878 printf("Created volume %u size: %s stripe: %uK level: %s "
879 "SCSI location: %u:%u.%u\n", bc
.bc_volid
, size
, bc
.bc_stripe
,
880 levelstr
, bc
.bc_channel
, bc
.bc_target
, bc
.bc_lun
);
885 * To modify a RAID volume.
888 bio_volops_modify(int fd
, int argc
, char **argv
)
895 * To remove a RAID volume.
898 bio_volops_remove(int fd
, int argc
, char **argv
)
900 struct bioc_volops bc
;
901 struct locator location
;
905 if (argc
!= 3 || strcmp(argv
[0], "volume") != 0)
908 memset(&bc
, 0, sizeof(bc
));
909 bc
.bc_cookie
= bl
.bl_cookie
;
910 bc
.bc_opcode
= BIOC_VREMOVE_VOLUME
;
912 bc
.bc_volid
= (unsigned int)strtoul(argv
[1], &endptr
, 10);
914 errx(EXIT_FAILURE
, "Invalid Volume ID value");
916 errstr
= str2locator(argv
[2], &location
);
918 errx(EXIT_FAILURE
, "Target %s: %s", argv
[2], errstr
);
920 bc
.bc_channel
= location
.channel
;
921 bc
.bc_target
= location
.target
;
922 bc
.bc_lun
= location
.lun
;
924 if (ioctl(fd
, BIOCVOLOPS
, &bc
) == -1)
925 err(EXIT_FAILURE
, "BIOCVOLOPS");
927 printf("Removed volume %u at SCSI location %u:%u.%u\n",
928 bc
.bc_volid
, bc
.bc_channel
, bc
.bc_target
, bc
.bc_lun
);
932 * To blink/unblink a disk in enclosures.
935 bio_setblink(int fd
, int argc
, char **argv
)
937 struct locator location
;
941 struct bioc_blink bb
;
943 int v
, d
, rv
, blink
= 0;
948 if (strcmp(argv
[0], "start") == 0)
949 blink
= BIOC_SBBLINK
;
950 else if (strcmp(argv
[0], "stop") == 0)
951 blink
= BIOC_SBUNBLINK
;
955 errstr
= str2locator(argv
[1], &location
);
957 errx(EXIT_FAILURE
, "Target %s: %s", argv
[1], errstr
);
959 /* try setting blink on the device directly */
960 memset(&bb
, 0, sizeof(bb
));
961 bb
.bb_cookie
= bl
.bl_cookie
;
962 bb
.bb_status
= blink
;
963 bb
.bb_target
= location
.target
;
964 bb
.bb_channel
= location
.channel
;
965 rv
= ioctl(fd
, BIOCBLINK
, &bb
);
969 /* if the blink didnt work, try to find something that will */
970 memset(&bi
, 0, sizeof(bi
));
971 bi
.bi_cookie
= bl
.bl_cookie
;
972 rv
= ioctl(fd
, BIOCINQ
, &bi
);
974 err(EXIT_FAILURE
, "BIOCINQ");
976 for (v
= 0; v
< bi
.bi_novol
; v
++) {
977 memset(&bv
, 0, sizeof(bv
));
978 bv
.bv_cookie
= bl
.bl_cookie
;
980 rv
= ioctl(fd
, BIOCVOL
, &bv
);
982 err(EXIT_FAILURE
, "BIOCVOL");
984 for (d
= 0; d
< bv
.bv_nodisk
; d
++) {
985 memset(&bd
, 0, sizeof(bd
));
986 bd
.bd_cookie
= bl
.bl_cookie
;
990 rv
= ioctl(fd
, BIOCDISK
, &bd
);
992 err(EXIT_FAILURE
, "BIOCDISK");
994 if (bd
.bd_channel
== location
.channel
&&
995 bd
.bd_target
== location
.target
&&
996 bd
.bd_lun
== location
.lun
) {
997 if (bd
.bd_procdev
[0] != '\0') {
998 bio_blink(fd
, bd
.bd_procdev
,
999 location
.target
, blink
);
1001 warnx("Disk %s is not in an enclosure",
1008 warnx("Disk %s does not exist", argv
[1]);
1012 bio_blink(int fd
, char *enclosure
, int target
, int blinktype
)
1014 struct bio_locate bio
;
1015 struct bioc_blink blink
;
1017 bio
.bl_name
= enclosure
;
1018 if (ioctl(fd
, BIOCLOCATE
, &bio
) == -1)
1020 "Can't locate %s device via /dev/bio", enclosure
);
1022 memset(&blink
, 0, sizeof(blink
));
1023 blink
.bb_cookie
= bio
.bl_cookie
;
1024 blink
.bb_status
= blinktype
;
1025 blink
.bb_target
= target
;
1027 if (ioctl(fd
, BIOCBLINK
, &blink
) == -1)
1028 err(EXIT_FAILURE
, "BIOCBLINK");