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