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