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