1*b9950701Smarco /* $OpenBSD: bioctl.c,v 1.30 2005/08/17 06:31:01 marco Exp $ */ 2cf6503d7Sderaadt 33af9de98Smarco /* 42f39728eSdlg * Copyright (c) 2004, 2005 Marco Peereboom 53af9de98Smarco * All rights reserved. 63af9de98Smarco * 73af9de98Smarco * Redistribution and use in source and binary forms, with or without 83af9de98Smarco * modification, are permitted provided that the following conditions 93af9de98Smarco * are met: 103af9de98Smarco * 1. Redistributions of source code must retain the above copyright 113af9de98Smarco * notice, this list of conditions and the following disclaimer. 123af9de98Smarco * 2. Redistributions in binary form must reproduce the above copyright 133af9de98Smarco * notice, this list of conditions and the following disclaimer in the 143af9de98Smarco * documentation and/or other materials provided with the distribution. 153af9de98Smarco * 163af9de98Smarco * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 173af9de98Smarco * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 183af9de98Smarco * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 193af9de98Smarco * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 203af9de98Smarco * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 213af9de98Smarco * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 223af9de98Smarco * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 233af9de98Smarco * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 243af9de98Smarco * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 253af9de98Smarco * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 263af9de98Smarco * SUCH DAMAGE. 273af9de98Smarco * 283af9de98Smarco */ 293af9de98Smarco 30c2126c9aSmarco #include <sys/ioctl.h> 31c2126c9aSmarco #include <sys/param.h> 32c2126c9aSmarco #include <sys/queue.h> 33c2126c9aSmarco #include <scsi/scsi_disk.h> 342b69df39Smarco #include <scsi/scsi_all.h> 353af9de98Smarco #include <dev/biovar.h> 363af9de98Smarco 37db2730c1Smarco #include <errno.h> 38db2730c1Smarco #include <err.h> 39db2730c1Smarco #include <fcntl.h> 408ccdd032Sderaadt #include <util.h> 41db2730c1Smarco #include <stdio.h> 42db2730c1Smarco #include <stdlib.h> 43db2730c1Smarco #include <string.h> 44db2730c1Smarco #include <unistd.h> 45e4e14ad7Sderaadt #include <ctype.h> 46db2730c1Smarco #include <util.h> 47db2730c1Smarco 488ccdd032Sderaadt void usage(void); 498ccdd032Sderaadt void cleanup(void); 508ccdd032Sderaadt 518ccdd032Sderaadt void bio_inq(char *); 528ccdd032Sderaadt void bio_alarm(char *); 533af9de98Smarco 54c2126c9aSmarco /* globals */ 55c2126c9aSmarco const char *bio_device = "/dev/bio"; 563af9de98Smarco 573af9de98Smarco int devh = -1; 58abe9d68eSderaadt int debug; 59abe9d68eSderaadt int human; 60abe9d68eSderaadt int verbose; 613af9de98Smarco 623af9de98Smarco struct bio_locate bl; 633af9de98Smarco 643af9de98Smarco int 653af9de98Smarco main(int argc, char *argv[]) 663af9de98Smarco { 673af9de98Smarco extern char *optarg; 68db2730c1Smarco u_int64_t func = 0; 69db2730c1Smarco /* u_int64_t subfunc = 0; */ 70cf6503d7Sderaadt char *bioc_dev = NULL, *sd_dev = NULL; 71cf6503d7Sderaadt char *realname = NULL, *al_arg = NULL; 72cf6503d7Sderaadt int ch, rv; 733af9de98Smarco 743af9de98Smarco if (argc < 2) 753af9de98Smarco usage(); 763af9de98Smarco 77abe9d68eSderaadt while ((ch = getopt(argc, argv, "ha:Div")) != -1) { 783af9de98Smarco switch (ch) { 79edfd9792Smarco case 'a': /* alarm */ 80edfd9792Smarco func |= BIOC_ALARM; 81edfd9792Smarco al_arg = optarg; 82edfd9792Smarco break; 83db2730c1Smarco case 'D': /* debug */ 843af9de98Smarco debug = 1; 853af9de98Smarco break; 868ccdd032Sderaadt case 'h': 878ccdd032Sderaadt human = 1; 888ccdd032Sderaadt break; 89db2730c1Smarco case 'i': /* inquiry */ 90db2730c1Smarco func |= BIOC_INQ; 913af9de98Smarco break; 92abe9d68eSderaadt case 'v': 93abe9d68eSderaadt verbose = 1; 94abe9d68eSderaadt break; 953af9de98Smarco default: 963af9de98Smarco usage(); 973af9de98Smarco /* NOTREACHED */ 983af9de98Smarco } 993af9de98Smarco } 100cf6503d7Sderaadt argc -= optind; 101cf6503d7Sderaadt argv += optind; 1023af9de98Smarco 1038ccdd032Sderaadt if (argc != 1) 104cf6503d7Sderaadt usage(); 105cf6503d7Sderaadt 106dcbaf4c8Sderaadt if (func == 0) 107dcbaf4c8Sderaadt func |= BIOC_INQ; 108dcbaf4c8Sderaadt 109e4e14ad7Sderaadt /* if at least glob sd[0-9]*, it is a drive identifier */ 110e4e14ad7Sderaadt if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 && 111e4e14ad7Sderaadt isdigit(argv[0][2])) 112cf6503d7Sderaadt sd_dev = argv[0]; 113cf6503d7Sderaadt else 114cf6503d7Sderaadt bioc_dev = argv[0]; 11510b411a7Smarco 11610b411a7Smarco if (bioc_dev) { 1173af9de98Smarco devh = open(bio_device, O_RDWR); 1183af9de98Smarco if (devh == -1) 1193af9de98Smarco err(1, "Can't open %s", bio_device); 1203af9de98Smarco 1218ccdd032Sderaadt bl.bl_name = bioc_dev; 1223af9de98Smarco rv = ioctl(devh, BIOCLOCATE, &bl); 1233af9de98Smarco if (rv == -1) 12410b411a7Smarco errx(1, "Can't locate %s device via %s", 1258ccdd032Sderaadt bl.bl_name, bio_device); 126db2730c1Smarco } else if (sd_dev) { 12710b411a7Smarco devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname); 12810b411a7Smarco if (devh == -1) 12910b411a7Smarco err(1, "Can't open %s", sd_dev); 130db2730c1Smarco } else 13110b411a7Smarco errx(1, "need -d or -f parameter"); 1323af9de98Smarco 1333af9de98Smarco if (debug) 1348ccdd032Sderaadt warnx("cookie = %p", bl.bl_cookie); 1353af9de98Smarco 136db2730c1Smarco if (func & BIOC_INQ) { 1378ccdd032Sderaadt bio_inq(sd_dev); 138edfd9792Smarco } else if (func == BIOC_ALARM) { 139edfd9792Smarco bio_alarm(al_arg); 1403af9de98Smarco } 1413af9de98Smarco 1423af9de98Smarco return (0); 1433af9de98Smarco } 1443af9de98Smarco 1453af9de98Smarco void 1463af9de98Smarco usage(void) 1473af9de98Smarco { 1483af9de98Smarco extern char *__progname; 1493af9de98Smarco 150cf6503d7Sderaadt fprintf(stderr, 151abe9d68eSderaadt "usage: %s [-Dhiv] [-a alarm-function] device\n", __progname); 1523af9de98Smarco exit(1); 1533af9de98Smarco } 1543af9de98Smarco 1553af9de98Smarco void 1568ccdd032Sderaadt bio_inq(char *name) 157d4546a56Sdlg { 158aa65acf1Sderaadt char *status, size[64], scsiname[16], volname[32]; 159*b9950701Smarco int rv, i, d, volheader, hotspare, unused; 160aa65acf1Sderaadt char encname[16], serial[32]; 1618ccdd032Sderaadt struct bioc_disk bd; 1628ccdd032Sderaadt struct bioc_inq bi; 1638ccdd032Sderaadt struct bioc_vol bv; 164db2730c1Smarco 165db2730c1Smarco memset(&bi, 0, sizeof(bi)); 1663af9de98Smarco 1673af9de98Smarco if (debug) 168db2730c1Smarco printf("bio_inq\n"); 1693af9de98Smarco 1708ccdd032Sderaadt bi.bi_cookie = bl.bl_cookie; 1713af9de98Smarco 172db2730c1Smarco rv = ioctl(devh, BIOCINQ, &bi); 1733af9de98Smarco if (rv == -1) { 174*b9950701Smarco warnx("bioc_ioctl(BIOCINQ) call failed"); 1753af9de98Smarco return; 1763af9de98Smarco } 1773af9de98Smarco 1788ccdd032Sderaadt volheader = 0; 1798ccdd032Sderaadt for (i = 0; i < bi.bi_novol; i++) { 180db2730c1Smarco memset(&bv, 0, sizeof(bv)); 1818ccdd032Sderaadt bv.bv_cookie = bl.bl_cookie; 1828ccdd032Sderaadt bv.bv_volid = i; 18370a2ae7bSmarco 184db2730c1Smarco rv = ioctl(devh, BIOCVOL, &bv); 1853af9de98Smarco if (rv == -1) { 186*b9950701Smarco warnx("bioc_ioctl(BIOCVOL) call failed"); 1873af9de98Smarco return; 1883af9de98Smarco } 1893af9de98Smarco 1908ccdd032Sderaadt if (name && strcmp(name, bv.bv_dev) != 0) 1918ccdd032Sderaadt continue; 1928ccdd032Sderaadt 1938ccdd032Sderaadt if (!volheader) { 1948ccdd032Sderaadt volheader = 1; 1958ccdd032Sderaadt printf("%-7s %-10s %-14s %-8s\n", 1968ccdd032Sderaadt "Volume", "Status", "Size", "Device"); 1978ccdd032Sderaadt } 1988ccdd032Sderaadt 1998ccdd032Sderaadt switch (bv.bv_status) { 200db2730c1Smarco case BIOC_SVONLINE: 2018ccdd032Sderaadt status = BIOC_SVONLINE_S; 202db2730c1Smarco break; 203db2730c1Smarco case BIOC_SVOFFLINE: 2048ccdd032Sderaadt status = BIOC_SVOFFLINE_S; 205db2730c1Smarco break; 206db2730c1Smarco case BIOC_SVDEGRADED: 2078ccdd032Sderaadt status = BIOC_SVDEGRADED_S; 208db2730c1Smarco break; 209db2730c1Smarco case BIOC_SVINVALID: 210db2730c1Smarco default: 2118ccdd032Sderaadt status = BIOC_SVINVALID_S; 212d4546a56Sdlg } 2133af9de98Smarco 214aa65acf1Sderaadt snprintf(volname, sizeof volname, "%s %u", 2158ccdd032Sderaadt bi.bi_dev, bv.bv_volid); 216*b9950701Smarco 217aa65acf1Sderaadt if (bv.bv_level == -1 && bv.bv_nodisk == 1) 218aa65acf1Sderaadt hotspare = 1; 219*b9950701Smarco else if (bv.bv_level == -2 && bv.bv_nodisk == 1) 220*b9950701Smarco unused = 1; 221aa65acf1Sderaadt else { 222*b9950701Smarco unused = 0; 223aa65acf1Sderaadt hotspare = 0; 224aa65acf1Sderaadt 2258ccdd032Sderaadt if (human) 2268ccdd032Sderaadt fmt_scaled(bv.bv_size, size); 2278ccdd032Sderaadt else 2288ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 2298ccdd032Sderaadt bv.bv_size); 230813b6523Sderaadt printf("%7s %-10s %14s %-7s RAID%u\n", 231aa65acf1Sderaadt volname, status, size, bv.bv_dev, bv.bv_level); 232aa65acf1Sderaadt } 2338ccdd032Sderaadt 2348ccdd032Sderaadt for (d = 0; d < bv.bv_nodisk; d++) { 235db2730c1Smarco memset(&bd, 0, sizeof(bd)); 2368ccdd032Sderaadt bd.bd_cookie = bl.bl_cookie; 2378ccdd032Sderaadt bd.bd_diskid = d; 2388ccdd032Sderaadt bd.bd_volid = i; 2393af9de98Smarco 240db2730c1Smarco rv = ioctl(devh, BIOCDISK, &bd); 2413af9de98Smarco if (rv == -1) { 242*b9950701Smarco warnx("bioc_ioctl(BIOCDISK) call failed"); 2433af9de98Smarco return; 2443af9de98Smarco } 2453af9de98Smarco 2468ccdd032Sderaadt switch (bd.bd_status) { 247db2730c1Smarco case BIOC_SDONLINE: 2488ccdd032Sderaadt status = BIOC_SDONLINE_S; 249d4546a56Sdlg break; 250db2730c1Smarco case BIOC_SDOFFLINE: 2518ccdd032Sderaadt status = BIOC_SDOFFLINE_S; 252d4546a56Sdlg break; 253db2730c1Smarco case BIOC_SDFAILED: 2548ccdd032Sderaadt status = BIOC_SDFAILED_S; 255db2730c1Smarco break; 256db2730c1Smarco case BIOC_SDREBUILD: 2578ccdd032Sderaadt status = BIOC_SDREBUILD_S; 258db2730c1Smarco break; 259db2730c1Smarco case BIOC_SDHOTSPARE: 2608ccdd032Sderaadt status = BIOC_SDHOTSPARE_S; 261db2730c1Smarco break; 262db2730c1Smarco case BIOC_SDUNUSED: 2638ccdd032Sderaadt status = BIOC_SDUNUSED_S; 264db2730c1Smarco break; 265db2730c1Smarco case BIOC_SDINVALID: 266d4546a56Sdlg default: 2678ccdd032Sderaadt status = BIOC_SDINVALID_S; 268d4546a56Sdlg } 269aa65acf1Sderaadt 270*b9950701Smarco if (hotspare || unused) 271aa65acf1Sderaadt ; /* use volname from parent volume */ 272aa65acf1Sderaadt else 273aa65acf1Sderaadt snprintf(volname, sizeof volname, " %3u", 274aa65acf1Sderaadt bd.bd_diskid); 275aa65acf1Sderaadt 2768ccdd032Sderaadt if (human) 2778ccdd032Sderaadt fmt_scaled(bd.bd_size, size); 2788ccdd032Sderaadt else 2798ccdd032Sderaadt snprintf(size, sizeof size, "%14llu", 2808ccdd032Sderaadt bd.bd_size); 2818ccdd032Sderaadt snprintf(scsiname, sizeof scsiname, 28243d61178Sderaadt "%u:%u.%u", 28343d61178Sderaadt bd.bd_channel, bd.bd_target, bd.bd_lun); 2845978b28dSderaadt if (bd.bd_procdev[0]) 285abe9d68eSderaadt strlcpy(encname, bd.bd_procdev, sizeof encname); 2865978b28dSderaadt else 287abe9d68eSderaadt strlcpy(encname, "noencl", sizeof encname); 288abe9d68eSderaadt if (bd.bd_serial[0]) 289abe9d68eSderaadt strlcpy(serial, bd.bd_serial, sizeof serial); 290abe9d68eSderaadt else 291abe9d68eSderaadt strlcpy(serial, "unknown serial", sizeof serial); 2928ccdd032Sderaadt 293aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s <%s>\n", 294aa65acf1Sderaadt volname, status, size, scsiname, encname, 2958ccdd032Sderaadt bd.bd_vendor); 296abe9d68eSderaadt if (verbose) 297aa65acf1Sderaadt printf("%7s %-10s %14s %-7s %-6s '%s'\n", 298abe9d68eSderaadt "", "", "", "", "", serial); 299d4546a56Sdlg } 300d4546a56Sdlg } 301d4546a56Sdlg } 302edfd9792Smarco 303edfd9792Smarco void 304edfd9792Smarco bio_alarm(char *arg) 305edfd9792Smarco { 306edfd9792Smarco int rv; 3078ccdd032Sderaadt struct bioc_alarm ba; 308edfd9792Smarco 3098ccdd032Sderaadt ba.ba_cookie = bl.bl_cookie; 310edfd9792Smarco 311edfd9792Smarco switch (arg[0]) { 312edfd9792Smarco case 'q': /* silence alarm */ 313edfd9792Smarco /* FALLTHROUGH */ 314edfd9792Smarco case 's': 3158ccdd032Sderaadt ba.ba_opcode = BIOC_SASILENCE; 316edfd9792Smarco break; 317edfd9792Smarco 318edfd9792Smarco case 'e': /* enable alarm */ 3198ccdd032Sderaadt ba.ba_opcode = BIOC_SAENABLE; 320edfd9792Smarco break; 321edfd9792Smarco 322edfd9792Smarco case 'd': /* disable alarm */ 3238ccdd032Sderaadt ba.ba_opcode = BIOC_SADISABLE; 324edfd9792Smarco break; 325edfd9792Smarco 326edfd9792Smarco case 't': /* test alarm */ 3278ccdd032Sderaadt ba.ba_opcode = BIOC_SATEST; 328edfd9792Smarco break; 329edfd9792Smarco 330edfd9792Smarco case 'g': /* get alarm state */ 3318ccdd032Sderaadt ba.ba_opcode = BIOC_GASTATUS; 332edfd9792Smarco break; 333edfd9792Smarco 334edfd9792Smarco default: 335edfd9792Smarco warnx("invalid alarm function: %s", arg); 336edfd9792Smarco return; 337edfd9792Smarco } 338edfd9792Smarco 339edfd9792Smarco rv = ioctl(devh, BIOCALARM, &ba); 340edfd9792Smarco if (rv == -1) { 341edfd9792Smarco warnx("bioc_ioctl() call failed"); 342edfd9792Smarco return; 343edfd9792Smarco } 344edfd9792Smarco 345edfd9792Smarco if (arg[0] == 'g') { 346edfd9792Smarco printf("alarm is currently %s\n", 3478ccdd032Sderaadt ba.ba_status ? "enabled" : "disabled"); 3488ccdd032Sderaadt 349edfd9792Smarco } 350edfd9792Smarco } 351