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