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