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