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