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