1 1.20 rin /* $NetBSD: bioctl.c,v 1.20 2023/08/04 03:45:07 rin Exp $ */ 2 1.7 xtraeme /* $OpenBSD: bioctl.c,v 1.52 2007/03/20 15:26:06 jmc Exp $ */ 3 1.1 bouyer 4 1.1 bouyer /* 5 1.7 xtraeme * Copyright (c) 2007, 2008 Juan Romero Pardines 6 1.1 bouyer * Copyright (c) 2004, 2005 Marco Peereboom 7 1.1 bouyer * All rights reserved. 8 1.1 bouyer * 9 1.1 bouyer * Redistribution and use in source and binary forms, with or without 10 1.1 bouyer * modification, are permitted provided that the following conditions 11 1.1 bouyer * are met: 12 1.1 bouyer * 1. Redistributions of source code must retain the above copyright 13 1.1 bouyer * notice, this list of conditions and the following disclaimer. 14 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 bouyer * notice, this list of conditions and the following disclaimer in the 16 1.1 bouyer * documentation and/or other materials provided with the distribution. 17 1.1 bouyer * 18 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 1.1 bouyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 1.1 bouyer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 1.1 bouyer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 22 1.1 bouyer * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 1.1 bouyer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 1.1 bouyer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 bouyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 1.1 bouyer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 bouyer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 bouyer * SUCH DAMAGE. 29 1.1 bouyer * 30 1.1 bouyer */ 31 1.1 bouyer #include <sys/cdefs.h> 32 1.1 bouyer 33 1.1 bouyer #ifndef lint 34 1.20 rin __RCSID("$NetBSD: bioctl.c,v 1.20 2023/08/04 03:45:07 rin Exp $"); 35 1.1 bouyer #endif 36 1.1 bouyer 37 1.7 xtraeme #include <sys/types.h> 38 1.1 bouyer #include <sys/ioctl.h> 39 1.1 bouyer #include <sys/param.h> 40 1.1 bouyer #include <sys/queue.h> 41 1.1 bouyer #include <dev/biovar.h> 42 1.1 bouyer 43 1.1 bouyer #include <errno.h> 44 1.1 bouyer #include <err.h> 45 1.1 bouyer #include <fcntl.h> 46 1.1 bouyer #include <util.h> 47 1.7 xtraeme #include <stdbool.h> 48 1.1 bouyer #include <stdio.h> 49 1.1 bouyer #include <stdlib.h> 50 1.1 bouyer #include <string.h> 51 1.1 bouyer #include <unistd.h> 52 1.1 bouyer #include <ctype.h> 53 1.1 bouyer #include <util.h> 54 1.1 bouyer 55 1.7 xtraeme struct command { 56 1.7 xtraeme const char *cmd_name; 57 1.7 xtraeme const char *arg_names; 58 1.7 xtraeme void (*cmd_func)(int, int, char **); 59 1.7 xtraeme }; 60 1.7 xtraeme 61 1.7 xtraeme struct biotmp { 62 1.7 xtraeme struct bioc_inq *bi; 63 1.7 xtraeme struct bioc_vol *bv; 64 1.7 xtraeme char volname[64]; 65 1.7 xtraeme int fd; 66 1.7 xtraeme int volid; 67 1.7 xtraeme int diskid; 68 1.7 xtraeme bool format; 69 1.7 xtraeme bool show_disknovol; 70 1.7 xtraeme }; 71 1.7 xtraeme 72 1.1 bouyer struct locator { 73 1.1 bouyer int channel; 74 1.1 bouyer int target; 75 1.1 bouyer int lun; 76 1.1 bouyer }; 77 1.1 bouyer 78 1.15 joerg __dead static void usage(void); 79 1.7 xtraeme static void bio_alarm(int, int, char **); 80 1.7 xtraeme static void bio_show_common(int, int, char **); 81 1.20 rin static int bio_show_volumes(struct biotmp *, struct bioc_vol *); 82 1.7 xtraeme static void bio_show_disks(struct biotmp *); 83 1.7 xtraeme static void bio_setblink(int, int, char **); 84 1.7 xtraeme static void bio_blink(int, char *, int, int); 85 1.7 xtraeme static void bio_setstate_hotspare(int, int, char **); 86 1.7 xtraeme static void bio_setstate_passthru(int, int, char **); 87 1.7 xtraeme static void bio_setstate_common(int, char *, struct bioc_setstate *, 88 1.7 xtraeme struct locator *); 89 1.7 xtraeme static void bio_setstate_consistency(int, int, char **); 90 1.7 xtraeme static void bio_volops_create(int, int, char **); 91 1.7 xtraeme #ifdef notyet 92 1.7 xtraeme static void bio_volops_modify(int, int, char **); 93 1.7 xtraeme #endif 94 1.7 xtraeme static void bio_volops_remove(int, int, char **); 95 1.7 xtraeme 96 1.2 xtraeme static const char *str2locator(const char *, struct locator *); 97 1.1 bouyer 98 1.7 xtraeme static struct bio_locate bl; 99 1.7 xtraeme static struct command commands[] = { 100 1.7 xtraeme { 101 1.7 xtraeme "show", 102 1.7 xtraeme "[disks] | [volumes]", 103 1.7 xtraeme bio_show_common }, 104 1.7 xtraeme { 105 1.7 xtraeme "alarm", 106 1.7 xtraeme "[enable] | [disable] | [silence] | [test]", 107 1.7 xtraeme bio_alarm }, 108 1.7 xtraeme { 109 1.7 xtraeme "blink", 110 1.11 xtraeme "start [channel:target[.lun]] | stop [channel:target[.lun]]", 111 1.7 xtraeme bio_setblink }, 112 1.7 xtraeme { 113 1.7 xtraeme "hotspare", 114 1.11 xtraeme "add channel:target.lun | remove channel:target.lun", 115 1.7 xtraeme bio_setstate_hotspare }, 116 1.7 xtraeme { 117 1.7 xtraeme "passthru", 118 1.11 xtraeme "add DISKID channel:target.lun | remove channel:target.lun", 119 1.7 xtraeme bio_setstate_passthru }, 120 1.7 xtraeme { 121 1.7 xtraeme "check", 122 1.11 xtraeme "start VOLID | stop VOLID", 123 1.7 xtraeme bio_setstate_consistency }, 124 1.7 xtraeme { 125 1.7 xtraeme "create", 126 1.7 xtraeme "volume VOLID DISKIDs [SIZE] STRIPE RAID_LEVEL channel:target.lun", 127 1.7 xtraeme bio_volops_create }, 128 1.7 xtraeme #ifdef notyet 129 1.7 xtraeme { 130 1.7 xtraeme "modify", 131 1.7 xtraeme "volume VOLID STRIPE RAID_LEVEL channel:target.lun", 132 1.7 xtraeme bio_volops_modify }, 133 1.7 xtraeme #endif 134 1.7 xtraeme { 135 1.7 xtraeme "remove", 136 1.7 xtraeme "volume VOLID channel:target.lun", 137 1.7 xtraeme bio_volops_remove }, 138 1.2 xtraeme 139 1.7 xtraeme { NULL, NULL, NULL } 140 1.7 xtraeme }; 141 1.1 bouyer 142 1.1 bouyer int 143 1.7 xtraeme main(int argc, char **argv) 144 1.1 bouyer { 145 1.7 xtraeme char *dvname; 146 1.7 xtraeme const char *cmdname; 147 1.7 xtraeme int fd = 0, i; 148 1.1 bouyer 149 1.7 xtraeme /* Must have at least: device command */ 150 1.7 xtraeme if (argc < 3) 151 1.1 bouyer usage(); 152 1.1 bouyer 153 1.7 xtraeme /* Skip program name, get and skip device name and command */ 154 1.2 xtraeme setprogname(*argv); 155 1.7 xtraeme dvname = argv[1]; 156 1.7 xtraeme cmdname = argv[2]; 157 1.7 xtraeme argv += 3; 158 1.7 xtraeme argc -= 3; 159 1.7 xtraeme 160 1.7 xtraeme /* Look up and call the command */ 161 1.7 xtraeme for (i = 0; commands[i].cmd_name != NULL; i++) 162 1.7 xtraeme if (strcmp(cmdname, commands[i].cmd_name) == 0) 163 1.7 xtraeme break; 164 1.7 xtraeme if (commands[i].cmd_name == NULL) 165 1.7 xtraeme errx(EXIT_FAILURE, "unknown command: %s", cmdname); 166 1.7 xtraeme 167 1.7 xtraeme /* Locate the device by issuing the BIOCLOCATE ioctl */ 168 1.7 xtraeme fd = open("/dev/bio", O_RDWR); 169 1.7 xtraeme if (fd == -1) 170 1.7 xtraeme err(EXIT_FAILURE, "Can't open /dev/bio"); 171 1.7 xtraeme 172 1.7 xtraeme bl.bl_name = dvname; 173 1.7 xtraeme if (ioctl(fd, BIOCLOCATE, &bl) == -1) 174 1.7 xtraeme errx(EXIT_FAILURE, "Can't locate %s device via /dev/bio", 175 1.7 xtraeme bl.bl_name); 176 1.2 xtraeme 177 1.7 xtraeme /* and execute the command */ 178 1.7 xtraeme (*commands[i].cmd_func)(fd, argc, argv); 179 1.1 bouyer 180 1.7 xtraeme (void)close(fd); 181 1.2 xtraeme exit(EXIT_SUCCESS); 182 1.1 bouyer } 183 1.1 bouyer 184 1.2 xtraeme static void 185 1.1 bouyer usage(void) 186 1.1 bouyer { 187 1.7 xtraeme int i; 188 1.7 xtraeme 189 1.7 xtraeme (void)fprintf(stderr, "usage: %s device command [arg [...]]\n", 190 1.7 xtraeme getprogname()); 191 1.7 xtraeme 192 1.7 xtraeme (void)fprintf(stderr, "Available commands:\n"); 193 1.7 xtraeme for (i = 0; commands[i].cmd_name != NULL; i++) 194 1.7 xtraeme (void)fprintf(stderr, " %s %s\n", commands[i].cmd_name, 195 1.7 xtraeme commands[i].arg_names); 196 1.7 xtraeme 197 1.2 xtraeme exit(EXIT_FAILURE); 198 1.2 xtraeme /* NOTREACHED */ 199 1.1 bouyer } 200 1.1 bouyer 201 1.2 xtraeme static const char * 202 1.1 bouyer str2locator(const char *string, struct locator *location) 203 1.1 bouyer { 204 1.7 xtraeme const char *errstr; 205 1.7 xtraeme char parse[80], *targ, *lun; 206 1.1 bouyer 207 1.1 bouyer strlcpy(parse, string, sizeof parse); 208 1.1 bouyer targ = strchr(parse, ':'); 209 1.1 bouyer if (targ == NULL) 210 1.7 xtraeme return "target not specified"; 211 1.7 xtraeme 212 1.1 bouyer *targ++ = '\0'; 213 1.1 bouyer lun = strchr(targ, '.'); 214 1.1 bouyer if (lun != NULL) { 215 1.1 bouyer *lun++ = '\0'; 216 1.1 bouyer location->lun = strtonum(lun, 0, 256, &errstr); 217 1.1 bouyer if (errstr) 218 1.2 xtraeme return errstr; 219 1.1 bouyer } else 220 1.1 bouyer location->lun = 0; 221 1.1 bouyer 222 1.1 bouyer location->target = strtonum(targ, 0, 256, &errstr); 223 1.1 bouyer if (errstr) 224 1.2 xtraeme return errstr; 225 1.1 bouyer location->channel = strtonum(parse, 0, 256, &errstr); 226 1.1 bouyer if (errstr) 227 1.2 xtraeme return errstr; 228 1.2 xtraeme return NULL; 229 1.1 bouyer } 230 1.1 bouyer 231 1.7 xtraeme /* 232 1.7 xtraeme * Shows info about available RAID volumes. 233 1.7 xtraeme */ 234 1.7 xtraeme static int 235 1.20 rin bio_show_volumes(struct biotmp *bt, struct bioc_vol *bv) 236 1.7 xtraeme { 237 1.10 xtraeme const char *status, *rtypestr, *stripestr; 238 1.7 xtraeme char size[64], percent[16], seconds[20]; 239 1.18 mrg char rtype[16], stripe[16], tmp[48]; 240 1.7 xtraeme 241 1.10 xtraeme rtypestr = stripestr = NULL; 242 1.10 xtraeme 243 1.20 rin memset(bv, 0, sizeof(*bv)); 244 1.20 rin bv->bv_cookie = bl.bl_cookie; 245 1.20 rin bv->bv_volid = bt->volid; 246 1.20 rin bv->bv_percent = -1; 247 1.20 rin bv->bv_seconds = 0; 248 1.7 xtraeme 249 1.20 rin if (ioctl(bt->fd, BIOCVOL, bv) == -1) 250 1.7 xtraeme err(EXIT_FAILURE, "BIOCVOL"); 251 1.7 xtraeme 252 1.7 xtraeme percent[0] = '\0'; 253 1.7 xtraeme seconds[0] = '\0'; 254 1.20 rin if (bv->bv_percent != -1) 255 1.7 xtraeme snprintf(percent, sizeof(percent), 256 1.20 rin " %3.2f%% done", bv->bv_percent / 10.0); 257 1.20 rin if (bv->bv_seconds) 258 1.7 xtraeme snprintf(seconds, sizeof(seconds), 259 1.20 rin " %u seconds", bv->bv_seconds); 260 1.7 xtraeme 261 1.20 rin switch (bv->bv_status) { 262 1.7 xtraeme case BIOC_SVONLINE: 263 1.7 xtraeme status = BIOC_SVONLINE_S; 264 1.7 xtraeme break; 265 1.7 xtraeme case BIOC_SVOFFLINE: 266 1.7 xtraeme status = BIOC_SVOFFLINE_S; 267 1.7 xtraeme break; 268 1.7 xtraeme case BIOC_SVDEGRADED: 269 1.7 xtraeme status = BIOC_SVDEGRADED_S; 270 1.7 xtraeme break; 271 1.7 xtraeme case BIOC_SVBUILDING: 272 1.7 xtraeme status = BIOC_SVBUILDING_S; 273 1.7 xtraeme break; 274 1.7 xtraeme case BIOC_SVREBUILD: 275 1.7 xtraeme status = BIOC_SVREBUILD_S; 276 1.7 xtraeme break; 277 1.7 xtraeme case BIOC_SVMIGRATING: 278 1.7 xtraeme status = BIOC_SVMIGRATING_S; 279 1.7 xtraeme break; 280 1.7 xtraeme case BIOC_SVSCRUB: 281 1.7 xtraeme status = BIOC_SVSCRUB_S; 282 1.7 xtraeme break; 283 1.7 xtraeme case BIOC_SVCHECKING: 284 1.7 xtraeme status = BIOC_SVCHECKING_S; 285 1.7 xtraeme break; 286 1.7 xtraeme case BIOC_SVINVALID: 287 1.7 xtraeme default: 288 1.7 xtraeme status = BIOC_SVINVALID_S; 289 1.7 xtraeme break; 290 1.7 xtraeme } 291 1.7 xtraeme 292 1.20 rin snprintf(bt->volname, sizeof(bt->volname), "%u", bv->bv_volid); 293 1.20 rin if (bv->bv_vendor[0]) 294 1.20 rin snprintf(tmp, sizeof(tmp), "%s %s", bv->bv_dev, bv->bv_vendor); 295 1.7 xtraeme else 296 1.20 rin snprintf(tmp, sizeof(tmp), "%s", bv->bv_dev); 297 1.7 xtraeme 298 1.20 rin switch (bv->bv_level) { 299 1.7 xtraeme case BIOC_SVOL_HOTSPARE: 300 1.10 xtraeme rtypestr = "Hot spare"; 301 1.10 xtraeme stripestr = "N/A"; 302 1.7 xtraeme break; 303 1.7 xtraeme case BIOC_SVOL_PASSTHRU: 304 1.10 xtraeme rtypestr = "Pass through"; 305 1.10 xtraeme stripestr = "N/A"; 306 1.10 xtraeme break; 307 1.10 xtraeme case BIOC_SVOL_RAID01: 308 1.10 xtraeme rtypestr = "RAID 0+1"; 309 1.10 xtraeme break; 310 1.10 xtraeme case BIOC_SVOL_RAID10: 311 1.10 xtraeme rtypestr = "RAID 1+0"; 312 1.7 xtraeme break; 313 1.7 xtraeme default: 314 1.20 rin snprintf(rtype, sizeof(rtype), "RAID %u", bv->bv_level); 315 1.20 rin if (bv->bv_level == 1 || bv->bv_stripe_size == 0) 316 1.10 xtraeme stripestr = "N/A"; 317 1.7 xtraeme break; 318 1.7 xtraeme } 319 1.7 xtraeme 320 1.10 xtraeme if (rtypestr) 321 1.14 joerg strlcpy(rtype, rtypestr, sizeof(rtype)); 322 1.10 xtraeme if (stripestr) 323 1.14 joerg strlcpy(stripe, stripestr, sizeof(stripe)); 324 1.10 xtraeme else 325 1.20 rin snprintf(stripe, sizeof(stripe), "%uK", bv->bv_stripe_size); 326 1.10 xtraeme 327 1.20 rin humanize_number(size, 5, (int64_t)bv->bv_size, "", HN_AUTOSCALE, 328 1.7 xtraeme HN_B | HN_NOSPACE | HN_DECIMAL); 329 1.7 xtraeme 330 1.9 xtraeme printf("%6s %-12s %4s %20s %8s %6s %s%s\n", 331 1.7 xtraeme bt->volname, status, size, tmp, 332 1.7 xtraeme rtype, stripe, percent, seconds); 333 1.7 xtraeme 334 1.20 rin bt->bv = bv; 335 1.7 xtraeme 336 1.20 rin return bv->bv_nodisk; 337 1.7 xtraeme } 338 1.7 xtraeme 339 1.7 xtraeme /* 340 1.7 xtraeme * Shows info about physical disks. 341 1.7 xtraeme */ 342 1.2 xtraeme static void 343 1.7 xtraeme bio_show_disks(struct biotmp *bt) 344 1.1 bouyer { 345 1.7 xtraeme struct bioc_disk bd; 346 1.7 xtraeme const char *status; 347 1.18 mrg char size[64], serial[32], scsiname[34]; 348 1.7 xtraeme 349 1.7 xtraeme memset(&bd, 0, sizeof(bd)); 350 1.7 xtraeme bd.bd_cookie = bl.bl_cookie; 351 1.7 xtraeme bd.bd_diskid = bt->diskid; 352 1.7 xtraeme bd.bd_volid = bt->volid; 353 1.7 xtraeme 354 1.7 xtraeme if (bt->show_disknovol) { 355 1.7 xtraeme if (ioctl(bt->fd, BIOCDISK_NOVOL, &bd) == -1) 356 1.7 xtraeme err(EXIT_FAILURE, "BIOCDISK_NOVOL"); 357 1.7 xtraeme if (!bd.bd_disknovol) 358 1.7 xtraeme return; 359 1.7 xtraeme } else { 360 1.7 xtraeme if (ioctl(bt->fd, BIOCDISK, &bd) == -1) 361 1.7 xtraeme err(EXIT_FAILURE, "BIOCDISK"); 362 1.7 xtraeme } 363 1.7 xtraeme 364 1.7 xtraeme switch (bd.bd_status) { 365 1.7 xtraeme case BIOC_SDONLINE: 366 1.7 xtraeme status = BIOC_SDONLINE_S; 367 1.7 xtraeme break; 368 1.7 xtraeme case BIOC_SDOFFLINE: 369 1.7 xtraeme status = BIOC_SDOFFLINE_S; 370 1.7 xtraeme break; 371 1.7 xtraeme case BIOC_SDFAILED: 372 1.7 xtraeme status = BIOC_SDFAILED_S; 373 1.7 xtraeme break; 374 1.7 xtraeme case BIOC_SDREBUILD: 375 1.7 xtraeme status = BIOC_SDREBUILD_S; 376 1.7 xtraeme break; 377 1.7 xtraeme case BIOC_SDHOTSPARE: 378 1.7 xtraeme status = BIOC_SDHOTSPARE_S; 379 1.7 xtraeme break; 380 1.7 xtraeme case BIOC_SDUNUSED: 381 1.7 xtraeme status = BIOC_SDUNUSED_S; 382 1.7 xtraeme break; 383 1.7 xtraeme case BIOC_SDSCRUB: 384 1.7 xtraeme status = BIOC_SDSCRUB_S; 385 1.7 xtraeme break; 386 1.7 xtraeme case BIOC_SDPASSTHRU: 387 1.7 xtraeme status = BIOC_SDPASSTHRU_S; 388 1.7 xtraeme break; 389 1.7 xtraeme case BIOC_SDINVALID: 390 1.7 xtraeme default: 391 1.7 xtraeme status = BIOC_SDINVALID_S; 392 1.7 xtraeme break; 393 1.7 xtraeme } 394 1.7 xtraeme 395 1.7 xtraeme if (bt->format) 396 1.7 xtraeme snprintf(bt->volname, sizeof(bt->volname), 397 1.7 xtraeme "%u:%u", bt->bv->bv_volid, bd.bd_diskid); 398 1.7 xtraeme 399 1.7 xtraeme humanize_number(size, 5, bd.bd_size, "", HN_AUTOSCALE, 400 1.7 xtraeme HN_B | HN_NOSPACE | HN_DECIMAL); 401 1.7 xtraeme 402 1.7 xtraeme if (bd.bd_procdev[0]) 403 1.7 xtraeme snprintf(scsiname, sizeof(scsiname), "%u:%u.%u %s", 404 1.7 xtraeme bd.bd_channel, bd.bd_target, bd.bd_lun, 405 1.7 xtraeme bd.bd_procdev); 406 1.7 xtraeme else 407 1.7 xtraeme snprintf(scsiname, sizeof(scsiname), "%u:%u.%u noencl", 408 1.7 xtraeme bd.bd_channel, bd.bd_target, bd.bd_lun); 409 1.7 xtraeme 410 1.7 xtraeme if (bd.bd_serial[0]) 411 1.7 xtraeme strlcpy(serial, bd.bd_serial, sizeof(serial)); 412 1.7 xtraeme else 413 1.7 xtraeme strlcpy(serial, "unknown serial", sizeof(serial)); 414 1.7 xtraeme 415 1.7 xtraeme if (bt->format) 416 1.7 xtraeme printf("%6s %-12s %4s %20s <%s>\n", 417 1.7 xtraeme bt->volname, status, size, scsiname, 418 1.7 xtraeme bd.bd_vendor); 419 1.7 xtraeme else 420 1.7 xtraeme printf("%5d [%-28s] %-12s %-6s %12s\n", 421 1.7 xtraeme bt->diskid, bd.bd_vendor, status, size, scsiname); 422 1.1 bouyer 423 1.7 xtraeme } 424 1.7 xtraeme 425 1.7 xtraeme /* 426 1.7 xtraeme * Shows info about volumes/disks. 427 1.7 xtraeme */ 428 1.7 xtraeme static void 429 1.7 xtraeme bio_show_common(int fd, int argc, char **argv) 430 1.7 xtraeme { 431 1.7 xtraeme struct biotmp *biot; 432 1.7 xtraeme struct bioc_inq bi; 433 1.20 rin struct bioc_vol bv; 434 1.7 xtraeme int i, d, ndisks; 435 1.7 xtraeme bool show_all, show_disks; 436 1.7 xtraeme bool show_vols, show_caps; 437 1.1 bouyer 438 1.7 xtraeme show_all = show_disks = show_vols = show_caps = false; 439 1.1 bouyer 440 1.7 xtraeme if (argc > 1) 441 1.7 xtraeme usage(); 442 1.1 bouyer 443 1.7 xtraeme if (argv[0]) { 444 1.7 xtraeme if (strcmp(argv[0], "disks") == 0) 445 1.7 xtraeme show_disks = true; 446 1.7 xtraeme else if (strcmp(argv[0], "volumes") == 0) 447 1.7 xtraeme show_vols = true; 448 1.7 xtraeme else 449 1.7 xtraeme usage(); 450 1.7 xtraeme } else 451 1.7 xtraeme show_all = true; 452 1.1 bouyer 453 1.7 xtraeme memset(&bi, 0, sizeof(bi)); 454 1.7 xtraeme bi.bi_cookie = bl.bl_cookie; 455 1.1 bouyer 456 1.7 xtraeme if (ioctl(fd, BIOCINQ, &bi) == -1) 457 1.7 xtraeme err(EXIT_FAILURE, "BIOCINQ"); 458 1.1 bouyer 459 1.7 xtraeme /* 460 1.7 xtraeme * If there are volumes there's no point to continue. 461 1.7 xtraeme */ 462 1.7 xtraeme if (show_all || show_vols) { 463 1.7 xtraeme if (!bi.bi_novol) { 464 1.7 xtraeme warnx("no volumes available"); 465 1.7 xtraeme return; 466 1.1 bouyer } 467 1.7 xtraeme } 468 1.1 bouyer 469 1.7 xtraeme biot = calloc(1, sizeof(*biot)); 470 1.7 xtraeme if (!biot) 471 1.7 xtraeme err(EXIT_FAILURE, "biotemp calloc"); 472 1.7 xtraeme 473 1.7 xtraeme biot->fd = fd; 474 1.7 xtraeme biot->bi = &bi; 475 1.7 xtraeme /* 476 1.7 xtraeme * Go to the disks section if that was specified. 477 1.7 xtraeme */ 478 1.7 xtraeme if (show_disks) 479 1.7 xtraeme goto disks; 480 1.7 xtraeme 481 1.7 xtraeme /* 482 1.7 xtraeme * Common code to show only info about volumes and disks 483 1.7 xtraeme * associated to them. 484 1.7 xtraeme */ 485 1.9 xtraeme printf("%6s %-12s %4s %20s %8s %6s\n", 486 1.7 xtraeme "Volume", "Status", "Size", "Device/Label", 487 1.9 xtraeme "Level", "Stripe"); 488 1.7 xtraeme printf("==============================================" 489 1.9 xtraeme "===============\n"); 490 1.1 bouyer 491 1.7 xtraeme for (i = 0; i < bi.bi_novol; i++) { 492 1.7 xtraeme biot->format = true; 493 1.7 xtraeme biot->volid = i; 494 1.20 rin ndisks = bio_show_volumes(biot, &bv); 495 1.7 xtraeme if (show_vols) 496 1.7 xtraeme continue; 497 1.7 xtraeme 498 1.7 xtraeme for (d = 0; d < ndisks; d++) { 499 1.7 xtraeme biot->diskid = d; 500 1.7 xtraeme bio_show_disks(biot); 501 1.1 bouyer } 502 1.1 bouyer 503 1.7 xtraeme } 504 1.7 xtraeme goto out; 505 1.1 bouyer 506 1.7 xtraeme disks: 507 1.7 xtraeme /* 508 1.7 xtraeme * show info about all disks connected to the raid controller, 509 1.7 xtraeme * even if they aren't associated with a volume or raid set. 510 1.7 xtraeme */ 511 1.7 xtraeme if (show_disks) { 512 1.7 xtraeme printf("%5s %-30s %-12s %-6s %12s\n", 513 1.7 xtraeme "Disk", "Model/Serial", "Status", "Size", "Location"); 514 1.7 xtraeme printf("===============================================" 515 1.7 xtraeme "======================\n"); 516 1.7 xtraeme for (d = 0; d < bi.bi_nodisk; d++) { 517 1.7 xtraeme biot->show_disknovol = true; 518 1.7 xtraeme biot->diskid = d; 519 1.7 xtraeme bio_show_disks(biot); 520 1.1 bouyer } 521 1.1 bouyer } 522 1.7 xtraeme out: 523 1.7 xtraeme free(biot); 524 1.1 bouyer } 525 1.1 bouyer 526 1.7 xtraeme /* 527 1.7 xtraeme * To handle the alarm feature. 528 1.7 xtraeme */ 529 1.2 xtraeme static void 530 1.7 xtraeme bio_alarm(int fd, int argc, char **argv) 531 1.1 bouyer { 532 1.7 xtraeme struct bioc_alarm ba; 533 1.7 xtraeme bool show = false; 534 1.1 bouyer 535 1.7 xtraeme memset(&ba, 0, sizeof(ba)); 536 1.1 bouyer ba.ba_cookie = bl.bl_cookie; 537 1.1 bouyer 538 1.7 xtraeme if (argc > 1) 539 1.7 xtraeme usage(); 540 1.7 xtraeme 541 1.7 xtraeme if (argc == 0) { 542 1.7 xtraeme /* show alarm status */ 543 1.7 xtraeme ba.ba_opcode = BIOC_GASTATUS; 544 1.7 xtraeme show = true; 545 1.7 xtraeme } else if (strcmp(argv[0], "silence") == 0) { 546 1.7 xtraeme /* silence alarm */ 547 1.1 bouyer ba.ba_opcode = BIOC_SASILENCE; 548 1.7 xtraeme } else if (strcmp(argv[0], "enable") == 0) { 549 1.7 xtraeme /* enable alarm */ 550 1.7 xtraeme ba.ba_opcode = BIOC_SAENABLE; 551 1.7 xtraeme } else if (strcmp(argv[0], "disable") == 0) { 552 1.7 xtraeme /* disable alarm */ 553 1.7 xtraeme ba.ba_opcode = BIOC_SADISABLE; 554 1.7 xtraeme } else if (strcmp(argv[0], "test") == 0) { 555 1.7 xtraeme /* test alarm */ 556 1.7 xtraeme ba.ba_opcode = BIOC_SATEST; 557 1.7 xtraeme } else 558 1.7 xtraeme usage(); 559 1.7 xtraeme 560 1.7 xtraeme if (ioctl(fd, BIOCALARM, &ba) == -1) 561 1.7 xtraeme err(EXIT_FAILURE, "BIOCALARM"); 562 1.7 xtraeme 563 1.7 xtraeme if (show) 564 1.7 xtraeme printf("alarm is currently %s\n", 565 1.7 xtraeme ba.ba_status ? "enabled" : "disabled"); 566 1.7 xtraeme } 567 1.7 xtraeme 568 1.7 xtraeme /* 569 1.7 xtraeme * To add/remove a hotspare disk. 570 1.7 xtraeme */ 571 1.7 xtraeme static void 572 1.7 xtraeme bio_setstate_hotspare(int fd, int argc, char **argv) 573 1.7 xtraeme { 574 1.7 xtraeme struct bioc_setstate bs; 575 1.7 xtraeme struct locator location; 576 1.7 xtraeme 577 1.7 xtraeme memset(&bs, 0, sizeof(bs)); 578 1.7 xtraeme 579 1.7 xtraeme if (argc != 2) 580 1.7 xtraeme usage(); 581 1.7 xtraeme 582 1.7 xtraeme if (strcmp(argv[0], "add") == 0) 583 1.7 xtraeme bs.bs_status = BIOC_SSHOTSPARE; 584 1.7 xtraeme else if (strcmp(argv[0], "remove") == 0) 585 1.7 xtraeme bs.bs_status = BIOC_SSDELHOTSPARE; 586 1.7 xtraeme else 587 1.7 xtraeme usage(); 588 1.7 xtraeme 589 1.7 xtraeme bio_setstate_common(fd, argv[1], &bs, &location); 590 1.7 xtraeme } 591 1.7 xtraeme 592 1.7 xtraeme /* 593 1.7 xtraeme * To add/remove a pass through disk. 594 1.7 xtraeme */ 595 1.7 xtraeme static void 596 1.7 xtraeme bio_setstate_passthru(int fd, int argc, char **argv) 597 1.7 xtraeme { 598 1.7 xtraeme struct bioc_setstate bs; 599 1.7 xtraeme struct locator location; 600 1.7 xtraeme char *endptr; 601 1.7 xtraeme bool rem = false; 602 1.7 xtraeme 603 1.13 ahoka if (argc < 2 || argc > 3) 604 1.7 xtraeme usage(); 605 1.7 xtraeme 606 1.7 xtraeme memset(&bs, 0, sizeof(bs)); 607 1.7 xtraeme 608 1.7 xtraeme if (strcmp(argv[0], "add") == 0) { 609 1.7 xtraeme if (argv[1] == NULL || argv[2] == NULL) 610 1.7 xtraeme usage(); 611 1.7 xtraeme 612 1.7 xtraeme bs.bs_status = BIOC_SSPASSTHRU; 613 1.7 xtraeme } else if (strcmp(argv[0], "remove") == 0) { 614 1.7 xtraeme if (argv[1] == NULL) 615 1.7 xtraeme usage(); 616 1.7 xtraeme 617 1.7 xtraeme bs.bs_status = BIOC_SSDELPASSTHRU; 618 1.7 xtraeme rem = true; 619 1.7 xtraeme } else 620 1.7 xtraeme usage(); 621 1.7 xtraeme 622 1.7 xtraeme if (rem) 623 1.7 xtraeme bio_setstate_common(fd, argv[1], &bs, &location); 624 1.7 xtraeme else { 625 1.7 xtraeme bs.bs_other_id = (unsigned int)strtoul(argv[1], &endptr, 10); 626 1.7 xtraeme if (*endptr != '\0') 627 1.7 xtraeme errx(EXIT_FAILURE, "Invalid Volume ID value"); 628 1.7 xtraeme 629 1.7 xtraeme bio_setstate_common(fd, argv[2], &bs, &location); 630 1.7 xtraeme } 631 1.7 xtraeme } 632 1.7 xtraeme 633 1.7 xtraeme /* 634 1.7 xtraeme * To start/stop a consistency check in a RAID volume. 635 1.7 xtraeme */ 636 1.7 xtraeme static void 637 1.7 xtraeme bio_setstate_consistency(int fd, int argc, char **argv) 638 1.7 xtraeme { 639 1.7 xtraeme struct bioc_setstate bs; 640 1.7 xtraeme char *endptr; 641 1.7 xtraeme 642 1.13 ahoka if (argc != 2) 643 1.7 xtraeme usage(); 644 1.7 xtraeme 645 1.8 xtraeme memset(&bs, 0, sizeof(bs)); 646 1.8 xtraeme 647 1.7 xtraeme if (strcmp(argv[0], "start") == 0) 648 1.7 xtraeme bs.bs_status = BIOC_SSCHECKSTART_VOL; 649 1.7 xtraeme else if (strcmp(argv[0], "stop") == 0) 650 1.7 xtraeme bs.bs_status = BIOC_SSCHECKSTOP_VOL; 651 1.7 xtraeme else 652 1.7 xtraeme usage(); 653 1.7 xtraeme 654 1.8 xtraeme bs.bs_volid = (unsigned int)strtoul(argv[1], &endptr, 10); 655 1.7 xtraeme if (*endptr != '\0') 656 1.7 xtraeme errx(EXIT_FAILURE, "Invalid Volume ID value"); 657 1.7 xtraeme 658 1.7 xtraeme bio_setstate_common(fd, NULL, &bs, NULL); 659 1.7 xtraeme } 660 1.7 xtraeme 661 1.7 xtraeme static void 662 1.7 xtraeme bio_setstate_common(int fd, char *arg, struct bioc_setstate *bs, 663 1.7 xtraeme struct locator *location) 664 1.7 xtraeme { 665 1.7 xtraeme const char *errstr; 666 1.7 xtraeme 667 1.7 xtraeme if (!arg || !location) 668 1.7 xtraeme goto send; 669 1.7 xtraeme 670 1.7 xtraeme errstr = str2locator(arg, location); 671 1.7 xtraeme if (errstr) 672 1.7 xtraeme errx(EXIT_FAILURE, "Target %s: %s", arg, errstr); 673 1.7 xtraeme 674 1.7 xtraeme bs->bs_channel = location->channel; 675 1.7 xtraeme bs->bs_target = location->target; 676 1.7 xtraeme bs->bs_lun = location->lun; 677 1.7 xtraeme 678 1.7 xtraeme send: 679 1.7 xtraeme bs->bs_cookie = bl.bl_cookie; 680 1.7 xtraeme 681 1.7 xtraeme if (ioctl(fd, BIOCSETSTATE, bs) == -1) 682 1.7 xtraeme err(EXIT_FAILURE, "BIOCSETSTATE"); 683 1.7 xtraeme } 684 1.7 xtraeme 685 1.7 xtraeme /* 686 1.7 xtraeme * To create a RAID volume. 687 1.7 xtraeme */ 688 1.7 xtraeme static void 689 1.7 xtraeme bio_volops_create(int fd, int argc, char **argv) 690 1.7 xtraeme { 691 1.7 xtraeme struct bioc_volops bc; 692 1.7 xtraeme struct bioc_inq bi; 693 1.7 xtraeme struct bioc_disk bd; 694 1.7 xtraeme struct locator location; 695 1.10 xtraeme uint64_t total_size = 0, disksize = 0; 696 1.7 xtraeme int64_t volsize = 0; 697 1.7 xtraeme const char *errstr; 698 1.10 xtraeme char *endptr, *stripe, levelstr[32]; 699 1.7 xtraeme char *scsiname, *raid_level, size[64]; 700 1.7 xtraeme int disk_first = 0, disk_end = 0; 701 1.7 xtraeme int i, nfreedisks = 0; 702 1.7 xtraeme int user_disks = 0; 703 1.7 xtraeme 704 1.7 xtraeme if (argc < 6 || argc > 7) 705 1.7 xtraeme usage(); 706 1.7 xtraeme 707 1.7 xtraeme if (strcmp(argv[0], "volume") != 0) 708 1.7 xtraeme usage(); 709 1.7 xtraeme 710 1.7 xtraeme /* 711 1.7 xtraeme * No size requested, use max size depending on RAID level. 712 1.7 xtraeme */ 713 1.7 xtraeme if (argc == 6) { 714 1.7 xtraeme stripe = argv[3]; 715 1.7 xtraeme raid_level = argv[4]; 716 1.7 xtraeme scsiname = argv[5]; 717 1.7 xtraeme } else { 718 1.7 xtraeme stripe = argv[4]; 719 1.7 xtraeme raid_level = argv[5]; 720 1.7 xtraeme scsiname = argv[6]; 721 1.7 xtraeme } 722 1.7 xtraeme 723 1.7 xtraeme memset(&bd, 0, sizeof(bd)); 724 1.7 xtraeme memset(&bc, 0, sizeof(bc)); 725 1.7 xtraeme memset(&bi, 0, sizeof(bi)); 726 1.7 xtraeme 727 1.7 xtraeme bc.bc_cookie = bd.bd_cookie = bi.bi_cookie = bl.bl_cookie; 728 1.7 xtraeme bc.bc_opcode = BIOC_VCREATE_VOLUME; 729 1.7 xtraeme 730 1.7 xtraeme bc.bc_volid = (unsigned int)strtoul(argv[1], &endptr, 10); 731 1.7 xtraeme if (*endptr != '\0') 732 1.7 xtraeme errx(EXIT_FAILURE, "Invalid Volume ID value"); 733 1.7 xtraeme 734 1.7 xtraeme if (argc == 7) 735 1.12 lukem if (dehumanize_number(argv[3], &volsize) == -1 736 1.12 lukem || volsize < 0) 737 1.7 xtraeme errx(EXIT_FAILURE, "Invalid SIZE value"); 738 1.7 xtraeme 739 1.7 xtraeme bc.bc_stripe = (unsigned int)strtoul(stripe, &endptr, 10); 740 1.7 xtraeme if (*endptr != '\0') 741 1.7 xtraeme errx(EXIT_FAILURE, "Invalid STRIPE size value"); 742 1.7 xtraeme 743 1.7 xtraeme bc.bc_level = (unsigned int)strtoul(raid_level, &endptr, 10); 744 1.7 xtraeme if (*endptr != '\0') 745 1.7 xtraeme errx(EXIT_FAILURE, "Invalid RAID_LEVEL value"); 746 1.7 xtraeme 747 1.7 xtraeme errstr = str2locator(scsiname, &location); 748 1.7 xtraeme if (errstr) 749 1.7 xtraeme errx(EXIT_FAILURE, "Target %s: %s", scsiname, errstr); 750 1.7 xtraeme 751 1.7 xtraeme /* 752 1.7 xtraeme * Parse the device list that will be used for the volume, 753 1.7 xtraeme * by using a bit field for the disks. 754 1.7 xtraeme */ 755 1.7 xtraeme if ((isdigit((unsigned char)argv[2][0]) == 0) || argv[2][1] != '-' || 756 1.7 xtraeme (isdigit((unsigned char)argv[2][2]) == 0)) 757 1.7 xtraeme errx(EXIT_FAILURE, "Invalid DISKIDs value"); 758 1.7 xtraeme 759 1.7 xtraeme disk_first = atoi(&argv[2][0]); 760 1.7 xtraeme disk_end = atoi(&argv[2][2]); 761 1.7 xtraeme 762 1.7 xtraeme for (i = disk_first; i < disk_end + 1; i++) { 763 1.7 xtraeme bc.bc_devmask |= (1 << i); 764 1.7 xtraeme user_disks++; 765 1.7 xtraeme } 766 1.7 xtraeme 767 1.7 xtraeme /* 768 1.7 xtraeme * Find out how many disks are free and how much size we 769 1.7 xtraeme * have available for the new volume. 770 1.7 xtraeme */ 771 1.7 xtraeme if (ioctl(fd, BIOCINQ, &bi) == -1) 772 1.7 xtraeme err(EXIT_FAILURE, "BIOCINQ"); 773 1.7 xtraeme 774 1.7 xtraeme for (i = 0; i < bi.bi_nodisk; i++) { 775 1.7 xtraeme bd.bd_diskid = i; 776 1.7 xtraeme if (ioctl(fd, BIOCDISK_NOVOL, &bd) == -1) 777 1.7 xtraeme err(EXIT_FAILURE, "BIOCDISK_NOVOL"); 778 1.7 xtraeme 779 1.7 xtraeme if (bd.bd_status == BIOC_SDUNUSED) { 780 1.7 xtraeme if (i == 0) 781 1.10 xtraeme disksize = bd.bd_size; 782 1.7 xtraeme 783 1.10 xtraeme total_size += bd.bd_size; 784 1.7 xtraeme nfreedisks++; 785 1.7 xtraeme } 786 1.7 xtraeme } 787 1.7 xtraeme 788 1.10 xtraeme if (user_disks > nfreedisks) 789 1.10 xtraeme errx(EXIT_FAILURE, "specified disks number is higher than " 790 1.10 xtraeme "available free disks"); 791 1.10 xtraeme 792 1.7 xtraeme /* 793 1.7 xtraeme * Basic checks to be sure we don't do something stupid. 794 1.7 xtraeme */ 795 1.7 xtraeme if (nfreedisks == 0) 796 1.7 xtraeme errx(EXIT_FAILURE, "No free disks available"); 797 1.7 xtraeme 798 1.7 xtraeme switch (bc.bc_level) { 799 1.7 xtraeme case 0: /* RAID 0 requires at least one disk */ 800 1.7 xtraeme if (argc == 7) { 801 1.12 lukem if ((uint64_t)volsize > (disksize * user_disks)) 802 1.7 xtraeme errx(EXIT_FAILURE, "volume size specified " 803 1.7 xtraeme "is larger than available on free disks"); 804 1.7 xtraeme bc.bc_size = (uint64_t)volsize; 805 1.7 xtraeme } else 806 1.10 xtraeme bc.bc_size = disksize * user_disks; 807 1.1 bouyer 808 1.1 bouyer break; 809 1.10 xtraeme case 1: /* RAID 1 requires two disks and size is total / 2 */ 810 1.7 xtraeme if (nfreedisks < 2 || user_disks < 2) 811 1.7 xtraeme errx(EXIT_FAILURE, "2 disks are required at least for " 812 1.7 xtraeme "this RAID level"); 813 1.7 xtraeme 814 1.10 xtraeme /* RAID 1+0 requires three disks at least */ 815 1.10 xtraeme if (nfreedisks > 2 && user_disks > 2) 816 1.10 xtraeme bc.bc_level = BIOC_SVOL_RAID10; 817 1.10 xtraeme 818 1.7 xtraeme if (argc == 7) { 819 1.12 lukem if ((uint64_t)volsize > ((disksize * user_disks) / 2)) 820 1.7 xtraeme errx(EXIT_FAILURE, "volume size specified " 821 1.7 xtraeme "is larger than available on free disks"); 822 1.7 xtraeme bc.bc_size = (uint64_t)volsize; 823 1.7 xtraeme } else 824 1.10 xtraeme bc.bc_size = ((disksize * user_disks) / 2); 825 1.1 bouyer 826 1.1 bouyer break; 827 1.10 xtraeme case 3: /* RAID 3/5 requires three disks and size is total - 1 disk */ 828 1.7 xtraeme case 5: 829 1.7 xtraeme if (nfreedisks < 3 || user_disks < 3) 830 1.7 xtraeme errx(EXIT_FAILURE, "3 disks are required at least for " 831 1.7 xtraeme "this RAID level"); 832 1.7 xtraeme 833 1.7 xtraeme if (argc == 7) { 834 1.12 lukem if ((uint64_t)volsize > (disksize * (user_disks - 1))) 835 1.7 xtraeme errx(EXIT_FAILURE, "volume size specified " 836 1.7 xtraeme "is larger than available on free disks"); 837 1.7 xtraeme bc.bc_size = (uint64_t)volsize; 838 1.7 xtraeme } else 839 1.10 xtraeme bc.bc_size = (disksize * (user_disks - 1)); 840 1.1 bouyer 841 1.1 bouyer break; 842 1.7 xtraeme case 6: /* RAID 6 requires four disks and size is total - 2 disks */ 843 1.7 xtraeme if (nfreedisks < 4 || user_disks < 4) 844 1.7 xtraeme errx(EXIT_FAILURE, "4 disks are required at least for " 845 1.7 xtraeme "this RAID level"); 846 1.7 xtraeme 847 1.7 xtraeme if (argc == 7) { 848 1.12 lukem if ((uint64_t)volsize > 849 1.10 xtraeme ((disksize * user_disks) - (disksize * 2))) 850 1.7 xtraeme err(EXIT_FAILURE, "volume size specified " 851 1.7 xtraeme "is larger than available on free disks"); 852 1.7 xtraeme bc.bc_size = (uint64_t)volsize; 853 1.7 xtraeme } else 854 1.10 xtraeme bc.bc_size = 855 1.10 xtraeme (((disksize * user_disks) - (disksize * 2))); 856 1.1 bouyer 857 1.1 bouyer break; 858 1.1 bouyer default: 859 1.7 xtraeme errx(EXIT_FAILURE, "Unsupported RAID level"); 860 1.1 bouyer } 861 1.1 bouyer 862 1.7 xtraeme bc.bc_channel = location.channel; 863 1.7 xtraeme bc.bc_target = location.target; 864 1.7 xtraeme bc.bc_lun = location.lun; 865 1.7 xtraeme 866 1.7 xtraeme if (ioctl(fd, BIOCVOLOPS, &bc) == -1) 867 1.7 xtraeme err(EXIT_FAILURE, "BIOCVOLOPS"); 868 1.7 xtraeme 869 1.7 xtraeme humanize_number(size, 5, bc.bc_size, "", HN_AUTOSCALE, 870 1.7 xtraeme HN_B | HN_NOSPACE | HN_DECIMAL); 871 1.7 xtraeme 872 1.10 xtraeme if (bc.bc_level == BIOC_SVOL_RAID10) 873 1.10 xtraeme snprintf(levelstr, sizeof(levelstr), "1+0"); 874 1.10 xtraeme else 875 1.10 xtraeme snprintf(levelstr, sizeof(levelstr), "%u", bc.bc_level); 876 1.10 xtraeme 877 1.10 xtraeme printf("Created volume %u size: %s stripe: %uK level: %s " 878 1.7 xtraeme "SCSI location: %u:%u.%u\n", bc.bc_volid, size, bc.bc_stripe, 879 1.10 xtraeme levelstr, bc.bc_channel, bc.bc_target, bc.bc_lun); 880 1.7 xtraeme } 881 1.1 bouyer 882 1.7 xtraeme #ifdef notyet 883 1.7 xtraeme /* 884 1.7 xtraeme * To modify a RAID volume. 885 1.7 xtraeme */ 886 1.7 xtraeme static void 887 1.7 xtraeme bio_volops_modify(int fd, int argc, char **argv) 888 1.7 xtraeme { 889 1.7 xtraeme /* XTRAEME: TODO */ 890 1.1 bouyer } 891 1.7 xtraeme #endif 892 1.1 bouyer 893 1.7 xtraeme /* 894 1.7 xtraeme * To remove a RAID volume. 895 1.7 xtraeme */ 896 1.2 xtraeme static void 897 1.7 xtraeme bio_volops_remove(int fd, int argc, char **argv) 898 1.1 bouyer { 899 1.7 xtraeme struct bioc_volops bc; 900 1.1 bouyer struct locator location; 901 1.1 bouyer const char *errstr; 902 1.7 xtraeme char *endptr; 903 1.1 bouyer 904 1.7 xtraeme if (argc != 3 || strcmp(argv[0], "volume") != 0) 905 1.7 xtraeme usage(); 906 1.7 xtraeme 907 1.7 xtraeme memset(&bc, 0, sizeof(bc)); 908 1.7 xtraeme bc.bc_cookie = bl.bl_cookie; 909 1.7 xtraeme bc.bc_opcode = BIOC_VREMOVE_VOLUME; 910 1.7 xtraeme 911 1.7 xtraeme bc.bc_volid = (unsigned int)strtoul(argv[1], &endptr, 10); 912 1.7 xtraeme if (*endptr != '\0') 913 1.7 xtraeme errx(EXIT_FAILURE, "Invalid Volume ID value"); 914 1.7 xtraeme 915 1.7 xtraeme errstr = str2locator(argv[2], &location); 916 1.1 bouyer if (errstr) 917 1.7 xtraeme errx(EXIT_FAILURE, "Target %s: %s", argv[2], errstr); 918 1.7 xtraeme 919 1.7 xtraeme bc.bc_channel = location.channel; 920 1.7 xtraeme bc.bc_target = location.target; 921 1.7 xtraeme bc.bc_lun = location.lun; 922 1.1 bouyer 923 1.7 xtraeme if (ioctl(fd, BIOCVOLOPS, &bc) == -1) 924 1.7 xtraeme err(EXIT_FAILURE, "BIOCVOLOPS"); 925 1.1 bouyer 926 1.7 xtraeme printf("Removed volume %u at SCSI location %u:%u.%u\n", 927 1.7 xtraeme bc.bc_volid, bc.bc_channel, bc.bc_target, bc.bc_lun); 928 1.1 bouyer } 929 1.1 bouyer 930 1.7 xtraeme /* 931 1.7 xtraeme * To blink/unblink a disk in enclosures. 932 1.7 xtraeme */ 933 1.2 xtraeme static void 934 1.7 xtraeme bio_setblink(int fd, int argc, char **argv) 935 1.1 bouyer { 936 1.1 bouyer struct locator location; 937 1.1 bouyer struct bioc_inq bi; 938 1.1 bouyer struct bioc_vol bv; 939 1.1 bouyer struct bioc_disk bd; 940 1.1 bouyer struct bioc_blink bb; 941 1.1 bouyer const char *errstr; 942 1.7 xtraeme int v, d, rv, blink = 0; 943 1.7 xtraeme 944 1.7 xtraeme if (argc != 2) 945 1.7 xtraeme usage(); 946 1.1 bouyer 947 1.7 xtraeme if (strcmp(argv[0], "start") == 0) 948 1.7 xtraeme blink = BIOC_SBBLINK; 949 1.7 xtraeme else if (strcmp(argv[0], "stop") == 0) 950 1.7 xtraeme blink = BIOC_SBUNBLINK; 951 1.7 xtraeme else 952 1.7 xtraeme usage(); 953 1.7 xtraeme 954 1.7 xtraeme errstr = str2locator(argv[1], &location); 955 1.1 bouyer if (errstr) 956 1.7 xtraeme errx(EXIT_FAILURE, "Target %s: %s", argv[1], errstr); 957 1.1 bouyer 958 1.1 bouyer /* try setting blink on the device directly */ 959 1.1 bouyer memset(&bb, 0, sizeof(bb)); 960 1.1 bouyer bb.bb_cookie = bl.bl_cookie; 961 1.1 bouyer bb.bb_status = blink; 962 1.1 bouyer bb.bb_target = location.target; 963 1.1 bouyer bb.bb_channel = location.channel; 964 1.2 xtraeme rv = ioctl(fd, BIOCBLINK, &bb); 965 1.1 bouyer if (rv == 0) 966 1.1 bouyer return; 967 1.1 bouyer 968 1.1 bouyer /* if the blink didnt work, try to find something that will */ 969 1.1 bouyer memset(&bi, 0, sizeof(bi)); 970 1.1 bouyer bi.bi_cookie = bl.bl_cookie; 971 1.2 xtraeme rv = ioctl(fd, BIOCINQ, &bi); 972 1.7 xtraeme if (rv == -1) 973 1.7 xtraeme err(EXIT_FAILURE, "BIOCINQ"); 974 1.1 bouyer 975 1.1 bouyer for (v = 0; v < bi.bi_novol; v++) { 976 1.1 bouyer memset(&bv, 0, sizeof(bv)); 977 1.1 bouyer bv.bv_cookie = bl.bl_cookie; 978 1.1 bouyer bv.bv_volid = v; 979 1.2 xtraeme rv = ioctl(fd, BIOCVOL, &bv); 980 1.4 xtraeme if (rv == -1) 981 1.7 xtraeme err(EXIT_FAILURE, "BIOCVOL"); 982 1.1 bouyer 983 1.1 bouyer for (d = 0; d < bv.bv_nodisk; d++) { 984 1.1 bouyer memset(&bd, 0, sizeof(bd)); 985 1.1 bouyer bd.bd_cookie = bl.bl_cookie; 986 1.1 bouyer bd.bd_volid = v; 987 1.1 bouyer bd.bd_diskid = d; 988 1.1 bouyer 989 1.2 xtraeme rv = ioctl(fd, BIOCDISK, &bd); 990 1.4 xtraeme if (rv == -1) 991 1.7 xtraeme err(EXIT_FAILURE, "BIOCDISK"); 992 1.1 bouyer 993 1.1 bouyer if (bd.bd_channel == location.channel && 994 1.1 bouyer bd.bd_target == location.target && 995 1.1 bouyer bd.bd_lun == location.lun) { 996 1.1 bouyer if (bd.bd_procdev[0] != '\0') { 997 1.2 xtraeme bio_blink(fd, bd.bd_procdev, 998 1.1 bouyer location.target, blink); 999 1.1 bouyer } else 1000 1.7 xtraeme warnx("Disk %s is not in an enclosure", 1001 1.7 xtraeme argv[1]); 1002 1.1 bouyer return; 1003 1.1 bouyer } 1004 1.1 bouyer } 1005 1.1 bouyer } 1006 1.1 bouyer 1007 1.7 xtraeme warnx("Disk %s does not exist", argv[1]); 1008 1.1 bouyer } 1009 1.1 bouyer 1010 1.2 xtraeme static void 1011 1.2 xtraeme bio_blink(int fd, char *enclosure, int target, int blinktype) 1012 1.1 bouyer { 1013 1.1 bouyer struct bio_locate bio; 1014 1.1 bouyer struct bioc_blink blink; 1015 1.1 bouyer 1016 1.1 bouyer bio.bl_name = enclosure; 1017 1.7 xtraeme if (ioctl(fd, BIOCLOCATE, &bio) == -1) 1018 1.4 xtraeme errx(EXIT_FAILURE, 1019 1.7 xtraeme "Can't locate %s device via /dev/bio", enclosure); 1020 1.1 bouyer 1021 1.1 bouyer memset(&blink, 0, sizeof(blink)); 1022 1.1 bouyer blink.bb_cookie = bio.bl_cookie; 1023 1.1 bouyer blink.bb_status = blinktype; 1024 1.1 bouyer blink.bb_target = target; 1025 1.1 bouyer 1026 1.7 xtraeme if (ioctl(fd, BIOCBLINK, &blink) == -1) 1027 1.7 xtraeme err(EXIT_FAILURE, "BIOCBLINK"); 1028 1.1 bouyer } 1029