1 /* $NetBSD: raidctl.c,v 1.74 2021/08/02 20:31:15 oster Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Greg Oster 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This program is a re-write of the original rf_ctrl program 34 * distributed by CMU with RAIDframe 1.1. 35 * 36 * This program is the user-land interface to the RAIDframe kernel 37 * driver in NetBSD. 38 */ 39 #include <sys/cdefs.h> 40 41 #ifndef lint 42 __RCSID("$NetBSD: raidctl.c,v 1.74 2021/08/02 20:31:15 oster Exp $"); 43 #endif 44 45 46 #include <sys/param.h> 47 #include <sys/ioctl.h> 48 #include <sys/stat.h> 49 #include <sys/disklabel.h> 50 51 #include <ctype.h> 52 #include <err.h> 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <inttypes.h> 59 #include <unistd.h> 60 #include <util.h> 61 62 #include <dev/raidframe/raidframevar.h> 63 #include <dev/raidframe/raidframeio.h> 64 #include "rf_configure.h" 65 #include "prog_ops.h" 66 67 void do_ioctl(int, u_long, void *, const char *); 68 static void rf_configure(int, char*, int); 69 static const char *device_status(RF_DiskStatus_t); 70 static void rf_get_device_status(int); 71 static void rf_output_configuration(int, const char *); 72 static void get_component_number(int, char *, int *, int *); 73 static void rf_fail_disk(int, char *, int); 74 __dead static void usage(void); 75 static void get_component_label(int, char *); 76 static void set_component_label(int, char *); 77 static void init_component_labels(int, int); 78 static void set_autoconfig(int, int, char *); 79 static void add_hot_spare(int, char *); 80 static void remove_hot_spare(int, char *); 81 static void rebuild_in_place(int, char *); 82 static void check_status(int,int); 83 static void check_parity(int,int, char *); 84 static void do_meter(int, u_long); 85 static void get_bar(char *, double, int); 86 static void get_time_string(char *, size_t, int); 87 static void rf_output_pmstat(int, int); 88 static void rf_pm_configure(int, int, char *, int[]); 89 static unsigned int xstrtouint(const char *); 90 91 int verbose; 92 93 static const char *rootpart[] = { "No", "Force", "Soft", "*invalid*" }; 94 95 static void 96 get_comp(char *buf, char *arg, size_t bufsz) 97 { 98 if (getfsspecname(buf, bufsz, arg) == NULL) 99 errx(1,"%s",buf); 100 } 101 102 int 103 main(int argc,char *argv[]) 104 { 105 int ch, i; 106 int num_options; 107 unsigned long action; 108 char config_filename[PATH_MAX]; 109 char dev_name[PATH_MAX]; 110 char name[PATH_MAX]; 111 char component[PATH_MAX]; 112 char autoconf[10]; 113 char *parityconf = NULL; 114 int parityparams[3]; 115 int do_output; 116 int do_recon; 117 int do_rewrite; 118 int raidID; 119 int serial_number; 120 struct stat st; 121 int fd; 122 int force; 123 int openmode; 124 int last_unit; 125 126 num_options = 0; 127 action = 0; 128 do_output = 0; 129 do_recon = 0; 130 do_rewrite = 0; 131 serial_number = 0; 132 force = 0; 133 last_unit = 0; 134 openmode = O_RDWR; /* default to read/write */ 135 136 while ((ch = getopt(argc, argv, "a:A:Bc:C:f:F:g:GiI:l:LmM:r:R:sSpPuU:v")) 137 != -1) 138 switch(ch) { 139 case 'a': 140 action = RAIDFRAME_ADD_HOT_SPARE; 141 get_comp(component, optarg, sizeof(component)); 142 num_options++; 143 break; 144 case 'A': 145 action = RAIDFRAME_SET_AUTOCONFIG; 146 strlcpy(autoconf, optarg, sizeof(autoconf)); 147 num_options++; 148 break; 149 case 'B': 150 action = RAIDFRAME_COPYBACK; 151 num_options++; 152 break; 153 case 'c': 154 action = RAIDFRAME_CONFIGURE; 155 strlcpy(config_filename, optarg, 156 sizeof(config_filename)); 157 force = 0; 158 num_options++; 159 break; 160 case 'C': 161 strlcpy(config_filename, optarg, 162 sizeof(config_filename)); 163 action = RAIDFRAME_CONFIGURE; 164 force = 1; 165 num_options++; 166 break; 167 case 'f': 168 action = RAIDFRAME_FAIL_DISK; 169 get_comp(component, optarg, sizeof(component)); 170 do_recon = 0; 171 num_options++; 172 break; 173 case 'F': 174 action = RAIDFRAME_FAIL_DISK; 175 get_comp(component, optarg, sizeof(component)); 176 do_recon = 1; 177 num_options++; 178 break; 179 case 'g': 180 action = RAIDFRAME_GET_COMPONENT_LABEL; 181 get_comp(component, optarg, sizeof(component)); 182 openmode = O_RDONLY; 183 num_options++; 184 break; 185 case 'G': 186 action = RAIDFRAME_GET_INFO; 187 openmode = O_RDONLY; 188 do_output = 1; 189 num_options++; 190 break; 191 case 'i': 192 action = RAIDFRAME_REWRITEPARITY; 193 num_options++; 194 break; 195 case 'I': 196 action = RAIDFRAME_INIT_LABELS; 197 serial_number = xstrtouint(optarg); 198 num_options++; 199 break; 200 case 'l': 201 action = RAIDFRAME_SET_COMPONENT_LABEL; 202 get_comp(component, optarg, sizeof(component)); 203 num_options++; 204 break; 205 case 'L': 206 action = RAIDFRAME_RESCAN; 207 num_options++; 208 break; 209 case 'm': 210 action = RAIDFRAME_PARITYMAP_STATUS; 211 openmode = O_RDONLY; 212 num_options++; 213 break; 214 case 'M': 215 action = RAIDFRAME_PARITYMAP_SET_DISABLE; 216 parityconf = strdup(optarg); 217 num_options++; 218 /* XXXjld: should rf_pm_configure do the strtol()s? */ 219 i = 0; 220 while (i < 3 && optind < argc && 221 isdigit((int)argv[optind][0])) 222 parityparams[i++] = xstrtouint(argv[optind++]); 223 while (i < 3) 224 parityparams[i++] = 0; 225 break; 226 case 'r': 227 action = RAIDFRAME_REMOVE_HOT_SPARE; 228 get_comp(component, optarg, sizeof(component)); 229 num_options++; 230 break; 231 case 'R': 232 get_comp(component, optarg, sizeof(component)); 233 action = RAIDFRAME_REBUILD_IN_PLACE; 234 num_options++; 235 break; 236 case 's': 237 action = RAIDFRAME_GET_INFO; 238 openmode = O_RDONLY; 239 num_options++; 240 break; 241 case 'S': 242 action = RAIDFRAME_CHECK_RECON_STATUS_EXT; 243 openmode = O_RDONLY; 244 num_options++; 245 break; 246 case 'p': 247 action = RAIDFRAME_CHECK_PARITY; 248 openmode = O_RDONLY; 249 num_options++; 250 break; 251 case 'P': 252 action = RAIDFRAME_CHECK_PARITY; 253 do_rewrite = 1; 254 num_options++; 255 break; 256 case 'u': 257 action = RAIDFRAME_SHUTDOWN; 258 num_options++; 259 break; 260 case 'U': 261 action = RAIDFRAME_SET_LAST_UNIT; 262 num_options++; 263 last_unit = atoi(optarg); 264 if (last_unit < 0) 265 errx(1, "Bad last unit %s", optarg); 266 break; 267 case 'v': 268 verbose = 1; 269 /* Don't bump num_options, as '-v' is not 270 an option like the others */ 271 /* num_options++; */ 272 break; 273 default: 274 usage(); 275 } 276 argc -= optind; 277 argv += optind; 278 279 if ((num_options > 1) || (argc == 0)) 280 usage(); 281 282 if (prog_init && prog_init() == -1) 283 err(1, "init failed"); 284 285 strlcpy(name, argv[0], sizeof(name)); 286 fd = opendisk1(name, openmode, dev_name, sizeof(dev_name), 0, 287 prog_open); 288 if (fd == -1) 289 err(1, "Unable to open device file: %s", name); 290 if (prog_fstat(fd, &st) == -1) 291 err(1, "stat failure on: %s", dev_name); 292 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) 293 err(1, "invalid device: %s", dev_name); 294 295 raidID = DISKUNIT(st.st_rdev); 296 297 switch(action) { 298 case RAIDFRAME_ADD_HOT_SPARE: 299 add_hot_spare(fd, component); 300 break; 301 case RAIDFRAME_REMOVE_HOT_SPARE: 302 remove_hot_spare(fd, component); 303 break; 304 case RAIDFRAME_CONFIGURE: 305 rf_configure(fd, config_filename, force); 306 break; 307 case RAIDFRAME_SET_AUTOCONFIG: 308 set_autoconfig(fd, raidID, autoconf); 309 break; 310 case RAIDFRAME_COPYBACK: 311 printf("Copyback.\n"); 312 do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK"); 313 if (verbose) { 314 sleep(3); /* XXX give the copyback a chance to start */ 315 printf("Copyback status:\n"); 316 do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); 317 } 318 break; 319 case RAIDFRAME_FAIL_DISK: 320 rf_fail_disk(fd, component, do_recon); 321 break; 322 case RAIDFRAME_SET_COMPONENT_LABEL: 323 set_component_label(fd, component); 324 break; 325 case RAIDFRAME_GET_COMPONENT_LABEL: 326 get_component_label(fd, component); 327 break; 328 case RAIDFRAME_INIT_LABELS: 329 init_component_labels(fd, serial_number); 330 break; 331 case RAIDFRAME_REWRITEPARITY: 332 printf("Initiating re-write of parity\n"); 333 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 334 "RAIDFRAME_REWRITEPARITY"); 335 if (verbose) { 336 sleep(3); /* XXX give it time to get started */ 337 printf("Parity Re-write status:\n"); 338 do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 339 } 340 break; 341 case RAIDFRAME_CHECK_RECON_STATUS_EXT: 342 check_status(fd,1); 343 break; 344 case RAIDFRAME_GET_INFO: 345 if (do_output) 346 rf_output_configuration(fd, dev_name); 347 else 348 rf_get_device_status(fd); 349 break; 350 case RAIDFRAME_PARITYMAP_STATUS: 351 rf_output_pmstat(fd, raidID); 352 break; 353 case RAIDFRAME_PARITYMAP_SET_DISABLE: 354 rf_pm_configure(fd, raidID, parityconf, parityparams); 355 break; 356 case RAIDFRAME_REBUILD_IN_PLACE: 357 rebuild_in_place(fd, component); 358 break; 359 case RAIDFRAME_CHECK_PARITY: 360 check_parity(fd, do_rewrite, dev_name); 361 break; 362 case RAIDFRAME_SHUTDOWN: 363 do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN"); 364 break; 365 case RAIDFRAME_SET_LAST_UNIT: 366 do_ioctl(fd, RAIDFRAME_SET_LAST_UNIT, &last_unit, 367 "RAIDFRAME_SET_LAST_UNIT"); 368 break; 369 case RAIDFRAME_RESCAN: 370 do_ioctl(fd, RAIDFRAME_RESCAN, NULL, "RAIDFRAME_RESCAN"); 371 break; 372 default: 373 break; 374 } 375 376 prog_close(fd); 377 exit(0); 378 } 379 380 void 381 do_ioctl(int fd, unsigned long command, void *arg, const char *ioctl_name) 382 { 383 if (prog_ioctl(fd, command, arg) == -1) 384 err(1, "ioctl (%s) failed", ioctl_name); 385 } 386 387 388 static void 389 rf_configure(int fd, char *config_file, int force) 390 { 391 void *generic; 392 RF_Config_t cfg; 393 394 if (rf_MakeConfig( config_file, &cfg ) != 0) 395 err(1, "Unable to create RAIDframe configuration structure"); 396 397 cfg.force = force; 398 399 /* 400 * Note the extra level of redirection needed here, since 401 * what we really want to pass in is a pointer to the pointer to 402 * the configuration structure. 403 */ 404 405 generic = &cfg; 406 do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE"); 407 } 408 409 static const char * 410 device_status(RF_DiskStatus_t status) 411 { 412 413 switch (status) { 414 case rf_ds_optimal: 415 return ("optimal"); 416 break; 417 case rf_ds_failed: 418 return ("failed"); 419 break; 420 case rf_ds_reconstructing: 421 return ("reconstructing"); 422 break; 423 case rf_ds_dist_spared: 424 return ("dist_spared"); 425 break; 426 case rf_ds_spared: 427 return ("spared"); 428 break; 429 case rf_ds_spare: 430 return ("spare"); 431 break; 432 case rf_ds_used_spare: 433 return ("used_spare"); 434 break; 435 default: 436 return ("UNKNOWN"); 437 } 438 /* NOTREACHED */ 439 } 440 441 static void 442 rf_get_device_status(int fd) 443 { 444 RF_DeviceConfig_t device_config; 445 void *cfg_ptr; 446 int is_clean; 447 int i, nspares; 448 449 cfg_ptr = &device_config; 450 451 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); 452 453 printf("Components:\n"); 454 for(i=0; i < device_config.ndevs; i++) { 455 printf("%20s: %s\n", device_config.devs[i].devname, 456 device_status(device_config.devs[i].status)); 457 } 458 459 nspares = MIN(device_config.nspares, 460 __arraycount(device_config.spares)); 461 462 if (nspares > 0) { 463 printf("Spares:\n"); 464 for(i=0; i < nspares; i++) { 465 printf("%20s: %s\n", 466 device_config.spares[i].devname, 467 device_status(device_config.spares[i].status)); 468 } 469 } else { 470 printf("No spares.\n"); 471 } 472 for(i=0; i < device_config.ndevs; i++) { 473 if (device_config.devs[i].status == rf_ds_optimal) { 474 get_component_label(fd, device_config.devs[i].devname); 475 } else { 476 printf("%s status is: %s. Skipping label.\n", 477 device_config.devs[i].devname, 478 device_status(device_config.devs[i].status)); 479 } 480 } 481 482 if (nspares > 0) { 483 for(i=0; i < nspares; i++) { 484 if ((device_config.spares[i].status == 485 rf_ds_optimal) || 486 (device_config.spares[i].status == 487 rf_ds_used_spare)) { 488 get_component_label(fd, 489 device_config.spares[i].devname); 490 } else { 491 printf("%s status is: %s. Skipping label.\n", 492 device_config.spares[i].devname, 493 device_status(device_config.spares[i].status)); 494 } 495 } 496 } 497 498 do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, 499 "RAIDFRAME_CHECK_PARITY"); 500 if (is_clean) { 501 printf("Parity status: clean\n"); 502 } else { 503 printf("Parity status: DIRTY\n"); 504 } 505 check_status(fd,0); 506 } 507 508 static void 509 rf_output_pmstat(int fd, int raidID) 510 { 511 char srs[7]; 512 unsigned int i, j; 513 int dis, dr; 514 struct rf_pmstat st; 515 516 if (prog_ioctl(fd, RAIDFRAME_PARITYMAP_STATUS, &st) == -1) { 517 if (errno == EINVAL) { 518 printf("raid%d: has no parity; parity map disabled\n", 519 raidID); 520 return; 521 } 522 err(1, "ioctl (%s) failed", "RAIDFRAME_PARITYMAP_STATUS"); 523 } 524 525 if (st.enabled) { 526 if (0 > humanize_number(srs, 7, st.region_size * DEV_BSIZE, 527 "B", HN_AUTOSCALE, HN_NOSPACE)) 528 strlcpy(srs, "???", 7); 529 530 printf("raid%d: parity map enabled with %u regions of %s\n", 531 raidID, st.params.regions, srs); 532 printf("raid%d: regions marked clean after %d intervals of" 533 " %d.%03ds\n", raidID, st.params.cooldown, 534 st.params.tickms / 1000, st.params.tickms % 1000); 535 printf("raid%d: write/sync/clean counters " 536 "%"PRIu64"/%"PRIu64"/%"PRIu64"\n", raidID, 537 st.ctrs.nwrite, st.ctrs.ncachesync, st.ctrs.nclearing); 538 539 dr = 0; 540 for (i = 0; i < st.params.regions; i++) 541 if (isset(st.dirty, i)) 542 dr++; 543 printf("raid%d: %d dirty region%s\n", raidID, dr, 544 dr == 1 ? "" : "s"); 545 546 if (verbose > 0) { 547 for (i = 0; i < RF_PARITYMAP_NBYTE; i += 32) { 548 printf(" "); 549 for (j = i; j < RF_PARITYMAP_NBYTE 550 && j < i + 32; j++) 551 printf("%x%x", st.dirty[j] & 15, 552 (st.dirty[j] >> 4) & 15); 553 printf("\n"); 554 } 555 } 556 } else { 557 printf("raid%d: parity map disabled\n", raidID); 558 } 559 560 do_ioctl(fd, RAIDFRAME_PARITYMAP_GET_DISABLE, &dis, 561 "RAIDFRAME_PARITYMAP_GET_DISABLE"); 562 printf("raid%d: parity map will %s %sabled on next configure\n", 563 raidID, dis == st.enabled ? "be" : "remain", dis ? "dis" : "en"); 564 } 565 566 static void 567 rf_pm_configure(int fd, int raidID, char *parityconf, int parityparams[]) 568 { 569 int dis; 570 struct rf_pmparams params; 571 572 if (strcasecmp(parityconf, "yes") == 0) 573 dis = 0; 574 else if (strcasecmp(parityconf, "no") == 0) 575 dis = 1; 576 else if (strcasecmp(parityconf, "set") == 0) { 577 params.cooldown = parityparams[0]; 578 params.tickms = parityparams[1]; 579 params.regions = parityparams[2]; 580 581 do_ioctl(fd, RAIDFRAME_PARITYMAP_SET_PARAMS, ¶ms, 582 "RAIDFRAME_PARITYMAP_SET_PARAMS"); 583 584 if (params.cooldown != 0 || params.tickms != 0) { 585 printf("raid%d: parity cleaned after", raidID); 586 if (params.cooldown != 0) 587 printf(" %d", params.cooldown); 588 printf(" intervals"); 589 if (params.tickms != 0) { 590 printf(" of %d.%03ds", params.tickms / 1000, 591 params.tickms % 1000); 592 } 593 printf("\n"); 594 } 595 if (params.regions != 0) 596 printf("raid%d: will use %d regions on next" 597 " configuration\n", raidID, params.regions); 598 599 return; 600 /* XXX the control flow here could be prettier. */ 601 } else 602 err(1, "`%s' is not a valid parity map command", parityconf); 603 604 do_ioctl(fd, RAIDFRAME_PARITYMAP_SET_DISABLE, &dis, 605 "RAIDFRAME_PARITYMAP_SET_DISABLE"); 606 printf("raid%d: parity map will be %sabled on next configure\n", 607 raidID, dis ? "dis" : "en"); 608 } 609 610 /* convert "component0" into "absent" */ 611 static const char *rf_output_devname(const char *name) 612 { 613 614 if (strncmp(name, "component", 9) == 0) 615 return "absent"; 616 return name; 617 } 618 619 static void 620 rf_output_configuration(int fd, const char *name) 621 { 622 RF_DeviceConfig_t device_config; 623 void *cfg_ptr; 624 int i, nspares; 625 RF_ComponentLabel_t component_label; 626 void *label_ptr; 627 int component_num; 628 int num_cols; 629 630 cfg_ptr = &device_config; 631 632 printf("# raidctl config file for %s\n", name); 633 printf("\n"); 634 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); 635 636 nspares = MIN(device_config.nspares, 637 __arraycount(device_config.spares)); 638 639 /* 640 * After NetBSD 9, convert this to not output the numRow's value, 641 * which is no longer required or ever used. 642 */ 643 printf("START array\n"); 644 printf("# numRow numCol numSpare\n"); 645 printf("%d %d %d\n", 1, device_config.cols, 646 device_config.nspares); 647 printf("\n"); 648 649 printf("START disks\n"); 650 for(i=0; i < device_config.ndevs; i++) 651 printf("%s\n", 652 rf_output_devname(device_config.devs[i].devname)); 653 printf("\n"); 654 655 if (nspares > 0) { 656 printf("START spare\n"); 657 for(i=0; i < nspares; i++) 658 printf("%s\n", device_config.spares[i].devname); 659 printf("\n"); 660 } 661 662 for(i=0; i < device_config.ndevs; i++) { 663 if (device_config.devs[i].status == rf_ds_optimal) 664 break; 665 } 666 if (i == device_config.ndevs) { 667 printf("# WARNING: no optimal components; using %s\n", 668 device_config.devs[0].devname); 669 i = 0; 670 } 671 get_component_number(fd, device_config.devs[i].devname, 672 &component_num, &num_cols); 673 memset(&component_label, 0, sizeof(RF_ComponentLabel_t)); 674 component_label.row = component_num / num_cols; 675 component_label.column = component_num % num_cols; 676 label_ptr = &component_label; 677 do_ioctl(fd, RAIDFRAME_GET_COMPONENT_LABEL, label_ptr, 678 "RAIDFRAME_GET_COMPONENT_LABEL"); 679 680 printf("START layout\n"); 681 printf( 682 "# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level_%c\n", 683 (char) component_label.parityConfig); 684 printf("%d %d %d %c\n", 685 component_label.sectPerSU, component_label.SUsPerPU, 686 component_label.SUsPerRU, (char) component_label.parityConfig); 687 printf("\n"); 688 689 printf("START queue\n"); 690 printf("fifo %d\n", device_config.maxqdepth); 691 } 692 693 static void 694 get_component_number(int fd, char *component_name, int *component_number, 695 int *num_columns) 696 { 697 RF_DeviceConfig_t device_config; 698 void *cfg_ptr; 699 int i, nspares; 700 int found; 701 702 *component_number = -1; 703 704 /* Assuming a full path spec... */ 705 cfg_ptr = &device_config; 706 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, 707 "RAIDFRAME_GET_INFO"); 708 709 *num_columns = device_config.cols; 710 711 nspares = MIN(device_config.nspares, 712 __arraycount(device_config.spares)); 713 714 found = 0; 715 for(i=0; i < device_config.ndevs; i++) { 716 if (strncmp(component_name, device_config.devs[i].devname, 717 PATH_MAX)==0) { 718 found = 1; 719 *component_number = i; 720 } 721 } 722 if (!found) { /* maybe it's a spare? */ 723 for(i=0; i < nspares; i++) { 724 if (strncmp(component_name, 725 device_config.spares[i].devname, 726 PATH_MAX)==0) { 727 found = 1; 728 *component_number = i + device_config.ndevs; 729 /* the way spares are done should 730 really change... */ 731 *num_columns = device_config.cols + 732 device_config.nspares; 733 } 734 } 735 } 736 737 if (!found) 738 err(1,"%s is not a component of this device", component_name); 739 } 740 741 static void 742 rf_fail_disk(int fd, char *component_to_fail, int do_recon) 743 { 744 struct rf_recon_req recon_request; 745 int component_num; 746 int num_cols; 747 748 get_component_number(fd, component_to_fail, &component_num, &num_cols); 749 750 recon_request.col = component_num % num_cols; 751 if (do_recon) { 752 recon_request.flags = RF_FDFLAGS_RECON; 753 } else { 754 recon_request.flags = RF_FDFLAGS_NONE; 755 } 756 do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request, 757 "RAIDFRAME_FAIL_DISK"); 758 if (do_recon && verbose) { 759 printf("Reconstruction status:\n"); 760 sleep(3); /* XXX give reconstruction a chance to start */ 761 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 762 } 763 } 764 765 static void 766 get_component_label(int fd, char *component) 767 { 768 RF_ComponentLabel_t component_label; 769 void *label_ptr; 770 int component_num; 771 int num_cols; 772 773 get_component_number(fd, component, &component_num, &num_cols); 774 775 memset( &component_label, 0, sizeof(RF_ComponentLabel_t)); 776 component_label.row = component_num / num_cols; 777 component_label.column = component_num % num_cols; 778 779 label_ptr = &component_label; 780 do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, label_ptr, 781 "RAIDFRAME_GET_COMPONENT_LABEL"); 782 783 printf("Component label for %s:\n",component); 784 785 printf(" Row: %d, Column: %d, Num Rows: %d, Num Columns: %d\n", 786 component_label.row, component_label.column, 787 component_label.num_rows, component_label.num_columns); 788 printf(" Version: %d, Serial Number: %u, Mod Counter: %d\n", 789 component_label.version, component_label.serial_number, 790 component_label.mod_counter); 791 printf(" Clean: %s, Status: %d\n", 792 component_label.clean ? "Yes" : "No", 793 component_label.status ); 794 printf(" sectPerSU: %d, SUsPerPU: %d, SUsPerRU: %d\n", 795 component_label.sectPerSU, component_label.SUsPerPU, 796 component_label.SUsPerRU); 797 printf(" Queue size: %d, blocksize: %d, numBlocks: %"PRIu64"\n", 798 component_label.maxOutstanding, component_label.blockSize, 799 rf_component_label_numblocks(&component_label)); 800 printf(" RAID Level: %c\n", (char) component_label.parityConfig); 801 printf(" Autoconfig: %s\n", 802 component_label.autoconfigure ? "Yes" : "No" ); 803 printf(" Root partition: %s\n", 804 rootpart[component_label.root_partition & 3]); 805 printf(" Last configured as: raid%d\n", component_label.last_unit ); 806 } 807 808 static void 809 set_component_label(int fd, char *component) 810 { 811 RF_ComponentLabel_t component_label; 812 int component_num; 813 int num_cols; 814 815 get_component_number(fd, component, &component_num, &num_cols); 816 817 /* XXX This is currently here for testing, and future expandability */ 818 819 component_label.version = 1; 820 component_label.serial_number = 123456; 821 component_label.mod_counter = 0; 822 component_label.row = component_num / num_cols; 823 component_label.column = component_num % num_cols; 824 component_label.num_rows = 0; 825 component_label.num_columns = 5; 826 component_label.clean = 0; 827 component_label.status = 1; 828 829 do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label, 830 "RAIDFRAME_SET_COMPONENT_LABEL"); 831 } 832 833 834 static void 835 init_component_labels(int fd, int serial_number) 836 { 837 RF_ComponentLabel_t component_label; 838 839 component_label.version = 0; 840 component_label.serial_number = serial_number; 841 component_label.mod_counter = 0; 842 component_label.row = 0; 843 component_label.column = 0; 844 component_label.num_rows = 0; 845 component_label.num_columns = 0; 846 component_label.clean = 0; 847 component_label.status = 0; 848 849 do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label, 850 "RAIDFRAME_INIT_LABELS"); 851 } 852 853 static void 854 set_autoconfig(int fd, int raidID, char *autoconf) 855 { 856 int auto_config; 857 int root_config; 858 859 auto_config = 0; 860 root_config = 0; 861 862 if (strncasecmp(autoconf, "root", 4) == 0 || 863 strncasecmp(autoconf, "hard", 4) == 0 || 864 strncasecmp(autoconf, "force", 5) == 0) { 865 root_config = 1; 866 } else if (strncasecmp(autoconf, "soft", 4) == 0) { 867 root_config = 2; 868 } 869 870 if ((strncasecmp(autoconf,"yes", 3) == 0) || 871 root_config > 0) { 872 auto_config = 1; 873 } 874 875 do_ioctl(fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config, 876 "RAIDFRAME_SET_AUTOCONFIG"); 877 878 do_ioctl(fd, RAIDFRAME_SET_ROOT, &root_config, 879 "RAIDFRAME_SET_ROOT"); 880 881 printf("raid%d: Autoconfigure: %s\n", raidID, 882 auto_config ? "Yes" : "No"); 883 884 if (auto_config == 1) { 885 printf("raid%d: Root: %s\n", raidID, rootpart[root_config]); 886 } 887 } 888 889 static void 890 add_hot_spare(int fd, char *component) 891 { 892 RF_SingleComponent_t hot_spare; 893 894 hot_spare.row = 0; 895 hot_spare.column = 0; 896 strncpy(hot_spare.component_name, component, 897 sizeof(hot_spare.component_name)); 898 899 do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare, 900 "RAIDFRAME_ADD_HOT_SPARE"); 901 } 902 903 static void 904 remove_hot_spare(int fd, char *component) 905 { 906 RF_SingleComponent_t hot_spare; 907 int component_num; 908 int num_cols; 909 910 get_component_number(fd, component, &component_num, &num_cols); 911 912 hot_spare.row = component_num / num_cols; 913 hot_spare.column = component_num % num_cols; 914 915 strncpy(hot_spare.component_name, component, 916 sizeof(hot_spare.component_name)); 917 918 do_ioctl( fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare, 919 "RAIDFRAME_REMOVE_HOT_SPARE"); 920 } 921 922 static void 923 rebuild_in_place(int fd, char *component) 924 { 925 RF_SingleComponent_t comp; 926 int component_num; 927 int num_cols; 928 929 get_component_number(fd, component, &component_num, &num_cols); 930 931 comp.row = 0; 932 comp.column = component_num; 933 strncpy(comp.component_name, component, sizeof(comp.component_name)); 934 935 do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp, 936 "RAIDFRAME_REBUILD_IN_PLACE"); 937 938 if (verbose) { 939 printf("Reconstruction status:\n"); 940 sleep(3); /* XXX give reconstruction a chance to start */ 941 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 942 } 943 944 } 945 946 static void 947 check_parity(int fd, int do_rewrite, char *dev_name) 948 { 949 int is_clean; 950 int percent_done; 951 952 is_clean = 0; 953 percent_done = 0; 954 do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, 955 "RAIDFRAME_CHECK_PARITY"); 956 if (is_clean) { 957 printf("%s: Parity status: clean\n",dev_name); 958 } else { 959 printf("%s: Parity status: DIRTY\n",dev_name); 960 if (do_rewrite) { 961 printf("%s: Initiating re-write of parity\n", 962 dev_name); 963 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 964 "RAIDFRAME_REWRITEPARITY"); 965 sleep(3); /* XXX give it time to 966 get started. */ 967 if (verbose) { 968 printf("Parity Re-write status:\n"); 969 do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 970 } else { 971 do_ioctl(fd, 972 RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 973 &percent_done, 974 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS" 975 ); 976 while( percent_done < 100 ) { 977 sleep(3); /* wait a bit... */ 978 do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 979 &percent_done, "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); 980 } 981 982 } 983 printf("%s: Parity Re-write complete\n", 984 dev_name); 985 } else { 986 /* parity is wrong, and is not being fixed. 987 Exit w/ an error. */ 988 exit(1); 989 } 990 } 991 } 992 993 994 static void 995 check_status(int fd, int meter) 996 { 997 int recon_percent_done = 0; 998 int parity_percent_done = 0; 999 int copyback_percent_done = 0; 1000 1001 do_ioctl(fd, RAIDFRAME_CHECK_RECON_STATUS, &recon_percent_done, 1002 "RAIDFRAME_CHECK_RECON_STATUS"); 1003 printf("Reconstruction is %d%% complete.\n", recon_percent_done); 1004 do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 1005 &parity_percent_done, 1006 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); 1007 printf("Parity Re-write is %d%% complete.\n", parity_percent_done); 1008 do_ioctl(fd, RAIDFRAME_CHECK_COPYBACK_STATUS, ©back_percent_done, 1009 "RAIDFRAME_CHECK_COPYBACK_STATUS"); 1010 printf("Copyback is %d%% complete.\n", copyback_percent_done); 1011 1012 if (meter) { 1013 /* These 3 should be mutually exclusive at this point */ 1014 if (recon_percent_done < 100) { 1015 printf("Reconstruction status:\n"); 1016 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 1017 } else if (parity_percent_done < 100) { 1018 printf("Parity Re-write status:\n"); 1019 do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 1020 } else if (copyback_percent_done < 100) { 1021 printf("Copyback status:\n"); 1022 do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); 1023 } 1024 } 1025 } 1026 1027 const char *tbits = "|/-\\"; 1028 1029 static void 1030 do_meter(int fd, u_long option) 1031 { 1032 int percent_done; 1033 RF_uint64 start_value; 1034 RF_ProgressInfo_t progressInfo; 1035 void *pInfoPtr; 1036 struct timeval start_time; 1037 struct timeval current_time; 1038 double elapsed; 1039 int elapsed_sec; 1040 int elapsed_usec; 1041 int simple_eta,last_eta; 1042 double rate; 1043 RF_uint64 amount; 1044 int tbit_value; 1045 char bar_buffer[1024]; 1046 char eta_buffer[1024]; 1047 1048 if (gettimeofday(&start_time,NULL) == -1) 1049 err(1, "gettimeofday failed!?!?"); 1050 memset(&progressInfo, 0, sizeof(RF_ProgressInfo_t)); 1051 pInfoPtr=&progressInfo; 1052 1053 percent_done = 0; 1054 do_ioctl(fd, option, pInfoPtr, ""); 1055 start_value = progressInfo.completed; 1056 current_time = start_time; 1057 simple_eta = 0; 1058 last_eta = 0; 1059 1060 tbit_value = 0; 1061 while(progressInfo.completed < progressInfo.total) { 1062 1063 percent_done = (progressInfo.completed * 100) / 1064 progressInfo.total; 1065 1066 get_bar(bar_buffer, percent_done, 40); 1067 1068 elapsed_sec = current_time.tv_sec - start_time.tv_sec; 1069 elapsed_usec = current_time.tv_usec - start_time.tv_usec; 1070 if (elapsed_usec < 0) { 1071 elapsed_usec-=1000000; 1072 elapsed_sec++; 1073 } 1074 1075 elapsed = (double) elapsed_sec + 1076 (double) elapsed_usec / 1000000.0; 1077 1078 amount = progressInfo.completed - start_value; 1079 1080 if (amount <= 0) { /* we don't do negatives (yet?) */ 1081 amount = 0; 1082 } 1083 1084 if (elapsed == 0) 1085 rate = 0.0; 1086 else 1087 rate = amount / elapsed; 1088 1089 if (rate > 0.0) { 1090 simple_eta = (int) (((double)progressInfo.total - 1091 (double) progressInfo.completed) 1092 / rate); 1093 } else { 1094 simple_eta = -1; 1095 } 1096 1097 if (simple_eta <=0) { 1098 simple_eta = last_eta; 1099 } else { 1100 last_eta = simple_eta; 1101 } 1102 1103 get_time_string(eta_buffer, sizeof eta_buffer, simple_eta); 1104 1105 fprintf(stdout,"\r%3d%% |%s| ETA: %s %c", 1106 percent_done,bar_buffer,eta_buffer,tbits[tbit_value]); 1107 fflush(stdout); 1108 1109 if (++tbit_value>3) 1110 tbit_value = 0; 1111 1112 sleep(2); 1113 1114 if (gettimeofday(¤t_time,NULL) == -1) 1115 err(1, "gettimeofday failed!?!?"); 1116 1117 do_ioctl( fd, option, pInfoPtr, ""); 1118 1119 1120 } 1121 printf("\n"); 1122 } 1123 /* 40 '*''s per line, then 40 ' ''s line. */ 1124 /* If you've got a screen wider than 160 characters, "tough" */ 1125 1126 #define STAR_MIDPOINT 4*40 1127 const char stars[] = "****************************************" 1128 "****************************************" 1129 "****************************************" 1130 "****************************************" 1131 " " 1132 " " 1133 " " 1134 " " 1135 " "; 1136 1137 static void 1138 get_bar(char *string, double percent, int max_strlen) 1139 { 1140 int offset; 1141 1142 if (max_strlen > STAR_MIDPOINT) { 1143 max_strlen = STAR_MIDPOINT; 1144 } 1145 offset = STAR_MIDPOINT - 1146 (int)((percent * max_strlen)/ 100); 1147 if (offset < 0) 1148 offset = 0; 1149 snprintf(string,max_strlen,"%s",stars+offset); 1150 } 1151 1152 static void 1153 get_time_string(char *string, size_t len, int simple_time) 1154 { 1155 int minutes, seconds, hours; 1156 char hours_buffer[8]; 1157 char minutes_buffer[5]; 1158 char seconds_buffer[5]; 1159 1160 if (simple_time >= 0) { 1161 1162 minutes = simple_time / 60; 1163 seconds = simple_time - 60*minutes; 1164 hours = minutes / 60; 1165 minutes = minutes - 60*hours; 1166 #if defined(__GNUC__) 1167 /* 1168 * snprintf() truncation checker fails to detect that seconds 1169 * and minutes will be 0-59 range. 1170 */ 1171 if (minutes < 0 || minutes > 60) 1172 minutes = 60; 1173 if (seconds < 0 || seconds > 60) 1174 seconds = 60; 1175 #endif 1176 1177 if (hours > 0) { 1178 snprintf(hours_buffer,sizeof hours_buffer,"%02d:",hours); 1179 } else { 1180 snprintf(hours_buffer,sizeof hours_buffer," "); 1181 } 1182 1183 snprintf(minutes_buffer,sizeof minutes_buffer,"%02d:",minutes); 1184 snprintf(seconds_buffer,sizeof seconds_buffer,"%02d",seconds); 1185 snprintf(string,len,"%s%s%s", 1186 hours_buffer, minutes_buffer, seconds_buffer); 1187 } else { 1188 snprintf(string,len," --:--"); 1189 } 1190 1191 } 1192 1193 static void 1194 usage(void) 1195 { 1196 const char *progname = getprogname(); 1197 1198 fprintf(stderr, "usage: %s [-v] -A [yes | no | softroot | hardroot] dev\n", progname); 1199 fprintf(stderr, " %s [-v] -a component dev\n", progname); 1200 fprintf(stderr, " %s [-v] -B dev\n", progname); 1201 fprintf(stderr, " %s [-v] -C config_file dev\n", progname); 1202 fprintf(stderr, " %s [-v] -c config_file dev\n", progname); 1203 fprintf(stderr, " %s [-v] -F component dev\n", progname); 1204 fprintf(stderr, " %s [-v] -f component dev\n", progname); 1205 fprintf(stderr, " %s [-v] -G dev\n", progname); 1206 fprintf(stderr, " %s [-v] -g component dev\n", progname); 1207 fprintf(stderr, " %s [-v] -I serial_number dev\n", progname); 1208 fprintf(stderr, " %s [-v] -i dev\n", progname); 1209 fprintf(stderr, " %s [-v] -M [yes | no | set params] dev\n", 1210 progname); 1211 fprintf(stderr, " %s [-v] -m dev\n", progname); 1212 fprintf(stderr, " %s [-v] -P dev\n", progname); 1213 fprintf(stderr, " %s [-v] -p dev\n", progname); 1214 fprintf(stderr, " %s [-v] -R component dev\n", progname); 1215 fprintf(stderr, " %s [-v] -r component dev\n", progname); 1216 fprintf(stderr, " %s [-v] -S dev\n", progname); 1217 fprintf(stderr, " %s [-v] -s dev\n", progname); 1218 fprintf(stderr, " %s [-v] -U unit dev\n", progname); 1219 fprintf(stderr, " %s [-v] -u dev\n", progname); 1220 exit(1); 1221 /* NOTREACHED */ 1222 } 1223 1224 static unsigned int 1225 xstrtouint(const char *str) 1226 { 1227 int e; 1228 unsigned int num = (unsigned int)strtou(str, NULL, 10, 0, INT_MAX, &e); 1229 if (e) 1230 errc(EXIT_FAILURE, e, "Bad number `%s'", str); 1231 return num; 1232 } 1233