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