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