1 /* $NetBSD: raidctl.c,v 1.14 2000/02/25 22:24:11 oster Exp $ */ 2 /*- 3 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Greg Oster 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 40 This program is a re-write of the original rf_ctrl program 41 distributed by CMU with RAIDframe 1.1. 42 43 This program is the user-land interface to the RAIDframe kernel 44 driver in NetBSD. 45 46 */ 47 48 #include <sys/param.h> 49 #include <sys/ioctl.h> 50 #include <sys/stat.h> 51 #include <util.h> 52 #include <stdio.h> 53 #include <fcntl.h> 54 #include <ctype.h> 55 #include <err.h> 56 #include <errno.h> 57 #include <sys/types.h> 58 #include <string.h> 59 #include <sys/disklabel.h> 60 #include <machine/disklabel.h> 61 #include <stdlib.h> 62 #include <unistd.h> 63 64 #include "rf_raidframe.h" 65 66 extern char *__progname; 67 68 int main __P((int, char *[])); 69 void do_ioctl __P((int, unsigned long, void *, char *)); 70 static void rf_configure __P((int, char*, int)); 71 static char *device_status __P((RF_DiskStatus_t)); 72 static void rf_get_device_status __P((int)); 73 static void get_component_number __P((int, char *, int *, int *)); 74 static void rf_fail_disk __P((int, char *, int)); 75 static void usage __P((void)); 76 static void get_component_label __P((int, char *)); 77 static void set_component_label __P((int, char *)); 78 static void init_component_labels __P((int, int)); 79 static void set_autoconfig __P((int, int, char *)); 80 static void add_hot_spare __P((int, char *)); 81 static void remove_hot_spare __P((int, char *)); 82 static void rebuild_in_place __P((int, char *)); 83 static void check_status __P((int,int)); 84 static void check_parity __P((int,int,char *)); 85 static void do_meter __P((int, int)); 86 static void get_bar __P((char *, double, int)); 87 static void get_time_string __P((char *, int)); 88 89 int verbose = 0; 90 91 int 92 main(argc,argv) 93 int argc; 94 char *argv[]; 95 { 96 extern char *optarg; 97 extern int optind; 98 int ch; 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 int do_recon; 107 int do_rewrite; 108 int is_clean; 109 int raidID; 110 int rawpart; 111 int serial_number; 112 struct stat st; 113 int fd; 114 int force; 115 116 num_options = 0; 117 action = 0; 118 do_recon = 0; 119 do_rewrite = 0; 120 is_clean = 0; 121 force = 0; 122 123 while ((ch = getopt(argc, argv, "a:A:Bc:C:f:F:g:iI:l:r:R:sSpPuv")) 124 != -1) 125 switch(ch) { 126 case 'a': 127 action = RAIDFRAME_ADD_HOT_SPARE; 128 strncpy(component, optarg, PATH_MAX); 129 num_options++; 130 break; 131 case 'A': 132 action = RAIDFRAME_SET_AUTOCONFIG; 133 strncpy(autoconf, optarg, 10); 134 num_options++; 135 break; 136 case 'B': 137 action = RAIDFRAME_COPYBACK; 138 num_options++; 139 break; 140 case 'c': 141 action = RAIDFRAME_CONFIGURE; 142 strncpy(config_filename,optarg,PATH_MAX); 143 force = 0; 144 num_options++; 145 break; 146 case 'C': 147 strncpy(config_filename,optarg,PATH_MAX); 148 action = RAIDFRAME_CONFIGURE; 149 force = 1; 150 num_options++; 151 break; 152 case 'f': 153 action = RAIDFRAME_FAIL_DISK; 154 strncpy(component, optarg, PATH_MAX); 155 do_recon = 0; 156 num_options++; 157 break; 158 case 'F': 159 action = RAIDFRAME_FAIL_DISK; 160 strncpy(component, optarg, PATH_MAX); 161 do_recon = 1; 162 num_options++; 163 break; 164 case 'g': 165 action = RAIDFRAME_GET_COMPONENT_LABEL; 166 strncpy(component, optarg, PATH_MAX); 167 num_options++; 168 break; 169 case 'i': 170 action = RAIDFRAME_REWRITEPARITY; 171 num_options++; 172 break; 173 case 'I': 174 action = RAIDFRAME_INIT_LABELS; 175 serial_number = atoi(optarg); 176 num_options++; 177 break; 178 case 'l': 179 action = RAIDFRAME_SET_COMPONENT_LABEL; 180 strncpy(component, optarg, PATH_MAX); 181 num_options++; 182 break; 183 case 'r': 184 action = RAIDFRAME_REMOVE_HOT_SPARE; 185 strncpy(component, optarg, PATH_MAX); 186 num_options++; 187 break; 188 case 'R': 189 strncpy(component,optarg,PATH_MAX); 190 action = RAIDFRAME_REBUILD_IN_PLACE; 191 num_options++; 192 break; 193 case 's': 194 action = RAIDFRAME_GET_INFO; 195 num_options++; 196 break; 197 case 'S': 198 action = RAIDFRAME_CHECK_RECON_STATUS; 199 num_options++; 200 break; 201 case 'p': 202 action = RAIDFRAME_CHECK_PARITY; 203 num_options++; 204 break; 205 case 'P': 206 action = RAIDFRAME_CHECK_PARITY; 207 do_rewrite = 1; 208 num_options++; 209 break; 210 case 'u': 211 action = RAIDFRAME_SHUTDOWN; 212 num_options++; 213 break; 214 case 'v': 215 verbose = 1; 216 /* Don't bump num_options, as '-v' is not 217 an option like the others */ 218 /* num_options++; */ 219 break; 220 default: 221 usage(); 222 } 223 argc -= optind; 224 argv += optind; 225 226 if ((num_options > 1) || (argc == NULL)) 227 usage(); 228 229 strncpy(name,argv[0],PATH_MAX); 230 231 if ((name[0] == '/') || (name[0] == '.')) { 232 /* they've (apparently) given a full path... */ 233 strncpy(dev_name, name, PATH_MAX); 234 } else { 235 if (isdigit(name[strlen(name)-1])) { 236 rawpart = getrawpartition(); 237 snprintf(dev_name,PATH_MAX,"/dev/%s%c",name, 238 'a'+rawpart); 239 } else { 240 snprintf(dev_name,PATH_MAX,"/dev/%s",name); 241 } 242 } 243 244 if (stat(dev_name, &st) != 0) { 245 fprintf(stderr,"%s: stat failure on: %s\n", 246 __progname,dev_name); 247 return (errno); 248 } 249 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) { 250 fprintf(stderr,"%s: invalid device: %s\n", 251 __progname,dev_name); 252 return (EINVAL); 253 } 254 255 raidID = RF_DEV2RAIDID(st.st_rdev); 256 257 if ((fd = open( dev_name, O_RDWR, 0640)) < 0) { 258 fprintf(stderr, "%s: unable to open device file: %s\n", 259 __progname, dev_name); 260 exit(1); 261 } 262 263 264 switch(action) { 265 case RAIDFRAME_ADD_HOT_SPARE: 266 add_hot_spare(fd, component); 267 break; 268 case RAIDFRAME_REMOVE_HOT_SPARE: 269 remove_hot_spare(fd, component); 270 break; 271 case RAIDFRAME_CONFIGURE: 272 rf_configure(fd, config_filename, force); 273 break; 274 case RAIDFRAME_SET_AUTOCONFIG: 275 set_autoconfig(fd, raidID, autoconf); 276 break; 277 case RAIDFRAME_COPYBACK: 278 printf("Copyback.\n"); 279 do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK"); 280 if (verbose) { 281 sleep(3); /* XXX give the copyback a chance to start */ 282 printf("Copyback status:\n"); 283 do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS); 284 } 285 break; 286 case RAIDFRAME_FAIL_DISK: 287 rf_fail_disk(fd, component, do_recon); 288 break; 289 case RAIDFRAME_SET_COMPONENT_LABEL: 290 set_component_label(fd, component); 291 break; 292 case RAIDFRAME_GET_COMPONENT_LABEL: 293 get_component_label(fd, component); 294 break; 295 case RAIDFRAME_INIT_LABELS: 296 init_component_labels(fd, serial_number); 297 break; 298 case RAIDFRAME_REWRITEPARITY: 299 printf("Initiating re-write of parity\n"); 300 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 301 "RAIDFRAME_REWRITEPARITY"); 302 if (verbose) { 303 sleep(3); /* XXX give it time to get started */ 304 printf("Parity Re-write status:\n"); 305 do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS); 306 } 307 break; 308 case RAIDFRAME_CHECK_RECON_STATUS: 309 check_status(fd,1); 310 break; 311 case RAIDFRAME_GET_INFO: 312 rf_get_device_status(fd); 313 break; 314 case RAIDFRAME_REBUILD_IN_PLACE: 315 rebuild_in_place(fd, component); 316 break; 317 case RAIDFRAME_CHECK_PARITY: 318 check_parity(fd, do_rewrite, dev_name); 319 break; 320 case RAIDFRAME_SHUTDOWN: 321 do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN"); 322 break; 323 default: 324 break; 325 } 326 327 close(fd); 328 exit(0); 329 } 330 331 void 332 do_ioctl(fd, command, arg, ioctl_name) 333 int fd; 334 unsigned long command; 335 void *arg; 336 char *ioctl_name; 337 { 338 if (ioctl(fd, command, arg) < 0) { 339 warn("ioctl (%s) failed", ioctl_name); 340 exit(1); 341 } 342 } 343 344 345 static void 346 rf_configure(fd,config_file,force) 347 int fd; 348 char *config_file; 349 int force; 350 { 351 void *generic; 352 RF_Config_t cfg; 353 354 if (rf_MakeConfig( config_file, &cfg ) != 0) { 355 fprintf(stderr,"%s: unable to create RAIDframe %s\n", 356 __progname, "configuration structure\n"); 357 exit(1); 358 } 359 360 cfg.force = force; 361 362 /* 363 364 Note the extra level of redirection needed here, since 365 what we really want to pass in is a pointer to the pointer to 366 the configuration structure. 367 368 */ 369 370 generic = (void *) &cfg; 371 do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE"); 372 } 373 374 static char * 375 device_status(status) 376 RF_DiskStatus_t status; 377 { 378 static char status_string[256]; 379 380 switch (status) { 381 case rf_ds_optimal: 382 strcpy(status_string,"optimal"); 383 break; 384 case rf_ds_failed: 385 strcpy(status_string,"failed"); 386 break; 387 case rf_ds_reconstructing: 388 strcpy(status_string,"reconstructing"); 389 break; 390 case rf_ds_dist_spared: 391 strcpy(status_string,"dist_spared"); 392 break; 393 case rf_ds_spared: 394 strcpy(status_string,"spared"); 395 break; 396 case rf_ds_spare: 397 strcpy(status_string,"spare"); 398 break; 399 case rf_ds_used_spare: 400 strcpy(status_string,"used_spare"); 401 break; 402 default: 403 strcpy(status_string,"UNKNOWN"); 404 break; 405 } 406 return(status_string); 407 } 408 409 static void 410 rf_get_device_status(fd) 411 int fd; 412 { 413 RF_DeviceConfig_t device_config; 414 void *cfg_ptr; 415 int is_clean; 416 int i; 417 418 cfg_ptr = &device_config; 419 420 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); 421 422 printf("Components:\n"); 423 for(i=0; i < device_config.ndevs; i++) { 424 printf("%20s: %s\n", device_config.devs[i].devname, 425 device_status(device_config.devs[i].status)); 426 } 427 if (device_config.nspares > 0) { 428 printf("Spares:\n"); 429 for(i=0; i < device_config.nspares; i++) { 430 printf("%20s: %s\n", 431 device_config.spares[i].devname, 432 device_status(device_config.spares[i].status)); 433 } 434 } else { 435 printf("No spares.\n"); 436 } 437 for(i=0; i < device_config.ndevs; i++) { 438 if (device_config.devs[i].status == rf_ds_optimal) { 439 get_component_label(fd, device_config.devs[i].devname); 440 } else { 441 printf("%s status is: %s. Skipping label.\n", 442 device_config.devs[i].devname, 443 device_status(device_config.devs[i].status)); 444 } 445 } 446 do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, 447 "RAIDFRAME_CHECK_PARITY"); 448 if (is_clean) { 449 printf("Parity status: clean\n"); 450 } else { 451 printf("Parity status: DIRTY\n"); 452 } 453 check_status(fd,0); 454 } 455 456 static void 457 get_component_number(fd, component_name, component_number, num_columns) 458 int fd; 459 char *component_name; 460 int *component_number; 461 int *num_columns; 462 { 463 RF_DeviceConfig_t device_config; 464 void *cfg_ptr; 465 int i; 466 int found; 467 468 *component_number = -1; 469 470 /* Assuming a full path spec... */ 471 cfg_ptr = &device_config; 472 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, 473 "RAIDFRAME_GET_INFO"); 474 475 *num_columns = device_config.cols; 476 477 found = 0; 478 for(i=0; i < device_config.ndevs; i++) { 479 if (strncmp(component_name, device_config.devs[i].devname, 480 PATH_MAX)==0) { 481 found = 1; 482 *component_number = i; 483 } 484 } 485 if (!found) { 486 fprintf(stderr,"%s: %s is not a component %s", __progname, 487 component_name, "of this device\n"); 488 exit(1); 489 } 490 } 491 492 static void 493 rf_fail_disk(fd, component_to_fail, do_recon) 494 int fd; 495 char *component_to_fail; 496 int do_recon; 497 { 498 struct rf_recon_req recon_request; 499 int component_num; 500 int num_cols; 501 502 get_component_number(fd, component_to_fail, &component_num, &num_cols); 503 504 recon_request.row = component_num / num_cols; 505 recon_request.col = component_num % num_cols; 506 if (do_recon) { 507 recon_request.flags = RF_FDFLAGS_RECON; 508 } else { 509 recon_request.flags = RF_FDFLAGS_NONE; 510 } 511 do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request, 512 "RAIDFRAME_FAIL_DISK"); 513 if (do_recon && verbose) { 514 printf("Reconstruction status:\n"); 515 sleep(3); /* XXX give reconstruction a chance to start */ 516 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS); 517 } 518 } 519 520 static void 521 get_component_label(fd, component) 522 int fd; 523 char *component; 524 { 525 RF_ComponentLabel_t component_label; 526 void *label_ptr; 527 int component_num; 528 int num_cols; 529 530 get_component_number(fd, component, &component_num, &num_cols); 531 532 memset( &component_label, 0, sizeof(RF_ComponentLabel_t)); 533 component_label.row = component_num / num_cols; 534 component_label.column = component_num % num_cols; 535 536 label_ptr = &component_label; 537 do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, 538 "RAIDFRAME_GET_COMPONENT_LABEL"); 539 540 printf("Component label for %s:\n",component); 541 542 printf(" Row: %d Column: %d Num Rows: %d Num Columns: %d\n", 543 component_label.row, component_label.column, 544 component_label.num_rows, component_label.num_columns); 545 printf(" Version: %d Serial Number: %d Mod Counter: %d\n", 546 component_label.version, component_label.serial_number, 547 component_label.mod_counter); 548 printf(" Clean: %s Status: %d\n", 549 component_label.clean ? "Yes" : "No", 550 component_label.status ); 551 printf(" sectPerSU: %d SUsPerPU: %d SUsPerRU: %d\n", 552 component_label.sectPerSU, component_label.SUsPerPU, 553 component_label.SUsPerRU); 554 printf(" RAID Level: %c blocksize: %d numBlocks: %d\n", 555 (char) component_label.parityConfig, 556 component_label.blockSize, component_label.numBlocks); 557 printf(" Autoconfig: %s\n", 558 component_label.autoconfigure ? "Yes" : "No" ); 559 printf(" Last configured as: raid%d\n", component_label.last_unit ); 560 } 561 562 static void 563 set_component_label(fd, component) 564 int fd; 565 char *component; 566 { 567 RF_ComponentLabel_t component_label; 568 int component_num; 569 int num_cols; 570 571 get_component_number(fd, component, &component_num, &num_cols); 572 573 /* XXX This is currently here for testing, and future expandability */ 574 575 component_label.version = 1; 576 component_label.serial_number = 123456; 577 component_label.mod_counter = 0; 578 component_label.row = component_num / num_cols; 579 component_label.column = component_num % num_cols; 580 component_label.num_rows = 0; 581 component_label.num_columns = 5; 582 component_label.clean = 0; 583 component_label.status = 1; 584 585 do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label, 586 "RAIDFRAME_SET_COMPONENT_LABEL"); 587 } 588 589 590 static void 591 init_component_labels(fd, serial_number) 592 int fd; 593 int serial_number; 594 { 595 RF_ComponentLabel_t component_label; 596 597 component_label.version = 0; 598 component_label.serial_number = serial_number; 599 component_label.mod_counter = 0; 600 component_label.row = 0; 601 component_label.column = 0; 602 component_label.num_rows = 0; 603 component_label.num_columns = 0; 604 component_label.clean = 0; 605 component_label.status = 0; 606 607 do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label, 608 "RAIDFRAME_SET_COMPONENT_LABEL"); 609 } 610 611 static void 612 set_autoconfig(fd, raidID, autoconf) 613 int fd; 614 int raidID; 615 char *autoconf; 616 { 617 int auto_config; 618 int root_config; 619 620 auto_config = 0; 621 root_config = 0; 622 623 if (strncasecmp(autoconf,"root", 4) == 0) { 624 root_config = 1; 625 } 626 627 if ((strncasecmp(autoconf,"yes", 3) == 0) || 628 root_config == 1) { 629 auto_config = 1; 630 } 631 632 do_ioctl(fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config, 633 "RAIDFRAME_SET_AUTOCONFIG"); 634 635 do_ioctl(fd, RAIDFRAME_SET_ROOT, &root_config, 636 "RAIDFRAME_SET_ROOT"); 637 638 printf("raid%d: Autoconfigure: %s\n", raidID, 639 auto_config ? "Yes" : "No"); 640 641 if (root_config == 1) { 642 printf("raid%d: Root: %s\n", raidID, 643 auto_config ? "Yes" : "No"); 644 } 645 } 646 647 static void 648 add_hot_spare(fd, component) 649 int fd; 650 char *component; 651 { 652 RF_SingleComponent_t hot_spare; 653 654 hot_spare.row = 0; 655 hot_spare.column = 0; 656 strncpy(hot_spare.component_name, component, 657 sizeof(hot_spare.component_name)); 658 659 do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare, 660 "RAIDFRAME_ADD_HOT_SPARE"); 661 } 662 663 static void 664 remove_hot_spare(fd, component) 665 int fd; 666 char *component; 667 { 668 RF_SingleComponent_t hot_spare; 669 int component_num; 670 int num_cols; 671 672 get_component_number(fd, component, &component_num, &num_cols); 673 674 hot_spare.row = component_num / num_cols; 675 hot_spare.column = component_num % num_cols; 676 677 strncpy(hot_spare.component_name, component, 678 sizeof(hot_spare.component_name)); 679 680 do_ioctl( fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare, 681 "RAIDFRAME_REMOVE_HOT_SPARE"); 682 } 683 684 static void 685 rebuild_in_place( fd, component ) 686 int fd; 687 char *component; 688 { 689 RF_SingleComponent_t comp; 690 int component_num; 691 int num_cols; 692 693 get_component_number(fd, component, &component_num, &num_cols); 694 695 comp.row = 0; 696 comp.column = component_num; 697 strncpy(comp.component_name, component, sizeof(comp.component_name)); 698 699 do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp, 700 "RAIDFRAME_REBUILD_IN_PLACE"); 701 702 if (verbose) { 703 printf("Reconstruction status:\n"); 704 sleep(3); /* XXX give reconstruction a chance to start */ 705 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS); 706 } 707 708 } 709 710 static void 711 check_parity( fd, do_rewrite, dev_name ) 712 int fd; 713 int do_rewrite; 714 char *dev_name; 715 { 716 int is_clean; 717 int percent_done; 718 719 is_clean = 0; 720 percent_done = 0; 721 do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, 722 "RAIDFRAME_CHECK_PARITY"); 723 if (is_clean) { 724 printf("%s: Parity status: clean\n",dev_name); 725 } else { 726 printf("%s: Parity status: DIRTY\n",dev_name); 727 if (do_rewrite) { 728 printf("%s: Initiating re-write of parity\n", 729 dev_name); 730 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 731 "RAIDFRAME_REWRITEPARITY"); 732 sleep(3); /* XXX give it time to 733 get started. */ 734 if (verbose) { 735 printf("Parity Re-write status:\n"); 736 do_meter(fd, 737 RAIDFRAME_CHECK_PARITYREWRITE_STATUS); 738 } else { 739 do_ioctl(fd, 740 RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 741 &percent_done, 742 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS" 743 ); 744 while( percent_done < 100 ) { 745 do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 746 &percent_done, "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); 747 } 748 749 } 750 printf("%s: Parity Re-write complete\n", 751 dev_name); 752 } else { 753 /* parity is wrong, and is not being fixed. 754 Exit w/ an error. */ 755 exit(1); 756 } 757 } 758 } 759 760 761 static void 762 check_status( fd, meter ) 763 int fd; 764 int meter; 765 { 766 int recon_percent_done = 0; 767 int parity_percent_done = 0; 768 int copyback_percent_done = 0; 769 770 do_ioctl(fd, RAIDFRAME_CHECK_RECON_STATUS, &recon_percent_done, 771 "RAIDFRAME_CHECK_RECON_STATUS"); 772 printf("Reconstruction is %d%% complete.\n", recon_percent_done); 773 do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 774 &parity_percent_done, 775 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); 776 printf("Parity Re-write is %d%% complete.\n", parity_percent_done); 777 do_ioctl(fd, RAIDFRAME_CHECK_COPYBACK_STATUS, ©back_percent_done, 778 "RAIDFRAME_CHECK_COPYBACK_STATUS"); 779 printf("Copyback is %d%% complete.\n", copyback_percent_done); 780 781 if (meter) { 782 /* These 3 should be mutually exclusive at this point */ 783 if (recon_percent_done < 100) { 784 printf("Reconstruction status:\n"); 785 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS); 786 } else if (parity_percent_done < 100) { 787 printf("Parity Re-write status:\n"); 788 do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS); 789 } else if (copyback_percent_done < 100) { 790 printf("Copyback status:\n"); 791 do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS); 792 } 793 } 794 } 795 796 char *tbits = "|/-\\"; 797 798 static void 799 do_meter( fd, option ) 800 int fd; 801 int option; 802 { 803 int percent_done; 804 int last_percent; 805 int start_percent; 806 struct timeval start_time; 807 struct timeval last_time; 808 struct timeval current_time; 809 double elapsed; 810 int elapsed_sec; 811 int elapsed_usec; 812 int simple_eta,last_eta; 813 double rate; 814 int amount; 815 int tbit_value; 816 int wait_for_more_data; 817 char buffer[1024]; 818 char bar_buffer[1024]; 819 char eta_buffer[1024]; 820 821 if (gettimeofday(&start_time,NULL)) { 822 fprintf(stderr,"%s: gettimeofday failed!?!?\n",__progname); 823 exit(errno); 824 } 825 percent_done = 0; 826 do_ioctl( fd, option, &percent_done, ""); 827 last_percent = percent_done; 828 start_percent = percent_done; 829 last_time = start_time; 830 current_time = start_time; 831 832 wait_for_more_data = 0; 833 tbit_value = 0; 834 835 while(percent_done < 100) { 836 837 get_bar(bar_buffer, percent_done, 40); 838 839 elapsed_sec = current_time.tv_sec - last_time.tv_sec; 840 841 elapsed_usec = current_time.tv_usec - last_time.tv_usec; 842 843 if (elapsed_usec < 0) { 844 elapsed_usec-=1000000; 845 elapsed_sec++; 846 } 847 848 elapsed = (double) elapsed_sec + 849 (double) elapsed_usec / 1000000.0; 850 if (elapsed <= 0.0) { 851 elapsed = 0.0001; /* XXX */ 852 } 853 854 amount = percent_done - last_percent; 855 if (amount <= 0) { /* we don't do negatives (yet?) */ 856 amount = 0; 857 wait_for_more_data = 1; 858 } else { 859 wait_for_more_data = 0; 860 } 861 rate = amount / elapsed; 862 863 864 if (rate > 0.0) { 865 simple_eta = (int) ((100.0 - (double) last_percent ) / rate); 866 } else { 867 simple_eta = -1; 868 } 869 if (simple_eta <=0) { 870 simple_eta = last_eta; 871 } else { 872 last_eta = simple_eta; 873 } 874 875 get_time_string(eta_buffer, simple_eta); 876 877 snprintf(buffer,1024,"\r%3d%% |%s| ETA: %s %c", 878 percent_done,bar_buffer,eta_buffer,tbits[tbit_value]); 879 880 write(fileno(stdout),buffer,strlen(buffer)); 881 fflush(stdout); 882 883 /* resolution wasn't high enough... wait until we get another 884 timestamp and perhaps more "work" done. */ 885 886 if (!wait_for_more_data) { 887 last_time = current_time; 888 last_percent = percent_done; 889 } 890 891 if (++tbit_value>3) 892 tbit_value = 0; 893 894 sleep(2); 895 896 if (gettimeofday(¤t_time,NULL)) { 897 fprintf(stderr,"%s: gettimeofday failed!?!?\n", 898 __progname); 899 exit(errno); 900 } 901 902 do_ioctl( fd, option, &percent_done, ""); 903 904 905 } 906 printf("\n"); 907 } 908 /* 40 '*''s per line, then 40 ' ''s line. */ 909 /* If you've got a screen wider than 160 characters, "tough" */ 910 911 #define STAR_MIDPOINT 4*40 912 const char stars[] = "****************************************" 913 "****************************************" 914 "****************************************" 915 "****************************************" 916 " " 917 " " 918 " " 919 " " 920 " "; 921 922 static void 923 get_bar(string,percent,max_strlen) 924 char *string; 925 double percent; 926 int max_strlen; 927 { 928 int offset; 929 930 if (max_strlen > STAR_MIDPOINT) { 931 max_strlen = STAR_MIDPOINT; 932 } 933 offset = STAR_MIDPOINT - 934 (int)((percent * max_strlen)/ 100); 935 if (offset < 0) 936 offset = 0; 937 snprintf(string,max_strlen,"%s",&stars[offset]); 938 } 939 940 static void 941 get_time_string(string,simple_time) 942 char *string; 943 int simple_time; 944 { 945 int minutes, seconds, hours; 946 char hours_buffer[5]; 947 char minutes_buffer[5]; 948 char seconds_buffer[5]; 949 950 if (simple_time >= 0) { 951 952 minutes = (int) simple_time / 60; 953 seconds = ((int)simple_time - 60*minutes); 954 hours = minutes / 60; 955 minutes = minutes - 60*hours; 956 957 if (hours > 0) { 958 snprintf(hours_buffer,5,"%02d:",hours); 959 } else { 960 snprintf(hours_buffer,5," "); 961 } 962 963 snprintf(minutes_buffer,5,"%02d:",minutes); 964 snprintf(seconds_buffer,5,"%02d",seconds); 965 snprintf(string,1024,"%s%s%s", 966 hours_buffer, minutes_buffer, seconds_buffer); 967 } else { 968 snprintf(string,1024," --:--"); 969 } 970 971 } 972 973 static void 974 usage() 975 { 976 fprintf(stderr, "usage: %s [-v] -a component dev\n", __progname); 977 fprintf(stderr, " %s [-v] -A yes | no | root dev\n", __progname); 978 fprintf(stderr, " %s [-v] -B dev\n", __progname); 979 fprintf(stderr, " %s [-v] -c config_file dev\n", __progname); 980 fprintf(stderr, " %s [-v] -C config_file dev\n", __progname); 981 fprintf(stderr, " %s [-v] -f component dev\n", __progname); 982 fprintf(stderr, " %s [-v] -F component dev\n", __progname); 983 fprintf(stderr, " %s [-v] -g component dev\n", __progname); 984 fprintf(stderr, " %s [-v] -i dev\n", __progname); 985 fprintf(stderr, " %s [-v] -I serial_number dev\n", __progname); 986 fprintf(stderr, " %s [-v] -r component dev\n", __progname); 987 fprintf(stderr, " %s [-v] -R component dev\n", __progname); 988 fprintf(stderr, " %s [-v] -s dev\n", __progname); 989 fprintf(stderr, " %s [-v] -S dev\n", __progname); 990 fprintf(stderr, " %s [-v] -u dev\n", __progname); 991 #if 0 992 fprintf(stderr, "usage: %s %s\n", __progname, 993 "-a | -f | -F | -g | -r | -R component dev"); 994 fprintf(stderr, " %s -B | -i | -s | -S -u dev\n", __progname); 995 fprintf(stderr, " %s -c | -C config_file dev\n", __progname); 996 fprintf(stderr, " %s -I serial_number dev\n", __progname); 997 #endif 998 exit(1); 999 /* NOTREACHED */ 1000 } 1001