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