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