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