1 /* $NetBSD: raidctl.c,v 1.41 2009/10/11 12:14:05 pooka 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This program is a re-write of the original rf_ctrl program 34 * distributed by CMU with RAIDframe 1.1. 35 * 36 * This program is the user-land interface to the RAIDframe kernel 37 * driver in NetBSD. 38 */ 39 #include <sys/cdefs.h> 40 41 #ifndef lint 42 __RCSID("$NetBSD: raidctl.c,v 1.41 2009/10/11 12:14:05 pooka Exp $"); 43 #endif 44 45 46 #include <sys/param.h> 47 #include <sys/ioctl.h> 48 #include <sys/stat.h> 49 #include <sys/disklabel.h> 50 51 #include <ctype.h> 52 #include <err.h> 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 #include <util.h> 60 61 #include <rump/rump.h> 62 #include <rump/rump_syscalls.h> 63 64 #include <dev/raidframe/raidframevar.h> 65 #include <dev/raidframe/raidframeio.h> 66 #include "rf_configure.h" 67 68 void do_ioctl(int, u_long, void *, const char *); 69 static void rf_configure(int, char*, int); 70 static const char *device_status(RF_DiskStatus_t); 71 static void rf_get_device_status(int); 72 static void rf_output_configuration(int, const char *); 73 static void get_component_number(int, char *, int *, int *); 74 static void rf_fail_disk(int, char *, int); 75 static void usage(void); 76 static void get_component_label(int, char *); 77 static void set_component_label(int, char *); 78 static void init_component_labels(int, int); 79 static void set_autoconfig(int, int, char *); 80 static void add_hot_spare(int, char *); 81 static void remove_hot_spare(int, char *); 82 static void rebuild_in_place(int, char *); 83 static void check_status(int,int); 84 static void check_parity(int,int, char *); 85 static void do_meter(int, u_long); 86 static void get_bar(char *, double, int); 87 static void get_time_string(char *, int); 88 89 int verbose; 90 91 int 92 main(int argc,char *argv[]) 93 { 94 int ch; 95 int num_options; 96 unsigned long action; 97 char config_filename[PATH_MAX]; 98 char dev_name[PATH_MAX]; 99 char name[PATH_MAX]; 100 char component[PATH_MAX]; 101 char autoconf[10]; 102 int do_output; 103 int do_recon; 104 int do_rewrite; 105 int is_clean; 106 int raidID; 107 int serial_number; 108 struct stat st; 109 int fd; 110 int force; 111 int openmode; 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 serial_number = 0; 120 force = 0; 121 openmode = O_RDWR; /* default to read/write */ 122 123 #ifdef RUMP_ACTION 124 rump_init(); 125 #endif 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 #ifdef RUMP_ACTION 247 fd = opendisk1(name, openmode, dev_name, sizeof(dev_name), 0, 248 rump_sys_open); 249 #else 250 fd = opendisk(name, openmode, dev_name, sizeof(dev_name), 0); 251 #endif 252 if (fd == -1) { 253 fprintf(stderr, "%s: unable to open device file: %s\n", 254 getprogname(), name); 255 exit(1); 256 } 257 if (fstat(fd, &st) != 0) { 258 fprintf(stderr,"%s: stat failure on: %s\n", 259 getprogname(), dev_name); 260 exit(1); 261 } 262 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) { 263 fprintf(stderr,"%s: invalid device: %s\n", 264 getprogname(), dev_name); 265 exit(1); 266 } 267 268 raidID = DISKUNIT(st.st_rdev); 269 270 switch(action) { 271 case RAIDFRAME_ADD_HOT_SPARE: 272 add_hot_spare(fd, component); 273 break; 274 case RAIDFRAME_REMOVE_HOT_SPARE: 275 remove_hot_spare(fd, component); 276 break; 277 case RAIDFRAME_CONFIGURE: 278 rf_configure(fd, config_filename, force); 279 break; 280 case RAIDFRAME_SET_AUTOCONFIG: 281 set_autoconfig(fd, raidID, autoconf); 282 break; 283 case RAIDFRAME_COPYBACK: 284 printf("Copyback.\n"); 285 do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK"); 286 if (verbose) { 287 sleep(3); /* XXX give the copyback a chance to start */ 288 printf("Copyback status:\n"); 289 do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); 290 } 291 break; 292 case RAIDFRAME_FAIL_DISK: 293 rf_fail_disk(fd, component, do_recon); 294 break; 295 case RAIDFRAME_SET_COMPONENT_LABEL: 296 set_component_label(fd, component); 297 break; 298 case RAIDFRAME_GET_COMPONENT_LABEL: 299 get_component_label(fd, component); 300 break; 301 case RAIDFRAME_INIT_LABELS: 302 init_component_labels(fd, serial_number); 303 break; 304 case RAIDFRAME_REWRITEPARITY: 305 printf("Initiating re-write of parity\n"); 306 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 307 "RAIDFRAME_REWRITEPARITY"); 308 if (verbose) { 309 sleep(3); /* XXX give it time to get started */ 310 printf("Parity Re-write status:\n"); 311 do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 312 } 313 break; 314 case RAIDFRAME_CHECK_RECON_STATUS_EXT: 315 check_status(fd,1); 316 break; 317 case RAIDFRAME_GET_INFO: 318 if (do_output) 319 rf_output_configuration(fd, dev_name); 320 else 321 rf_get_device_status(fd); 322 break; 323 case RAIDFRAME_REBUILD_IN_PLACE: 324 rebuild_in_place(fd, component); 325 break; 326 case RAIDFRAME_CHECK_PARITY: 327 check_parity(fd, do_rewrite, dev_name); 328 break; 329 case RAIDFRAME_SHUTDOWN: 330 do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN"); 331 break; 332 default: 333 break; 334 } 335 336 close(fd); 337 exit(0); 338 } 339 340 void 341 do_ioctl(int fd, unsigned long command, void *arg, const char *ioctl_name) 342 { 343 if (ioctl(fd, command, arg) < 0) { 344 warn("ioctl (%s) failed", ioctl_name); 345 exit(1); 346 } 347 } 348 349 350 static void 351 rf_configure(int fd, char *config_file, int force) 352 { 353 void *generic; 354 RF_Config_t cfg; 355 356 if (rf_MakeConfig( config_file, &cfg ) != 0) { 357 fprintf(stderr,"%s: unable to create RAIDframe %s\n", 358 getprogname(), "configuration structure\n"); 359 exit(1); 360 } 361 362 cfg.force = force; 363 364 /* 365 * Note the extra level of redirection needed here, since 366 * what we really want to pass in is a pointer to the pointer to 367 * the configuration structure. 368 */ 369 370 generic = (void *) &cfg; 371 do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE"); 372 } 373 374 static const char * 375 device_status(RF_DiskStatus_t status) 376 { 377 378 switch (status) { 379 case rf_ds_optimal: 380 return ("optimal"); 381 break; 382 case rf_ds_failed: 383 return ("failed"); 384 break; 385 case rf_ds_reconstructing: 386 return ("reconstructing"); 387 break; 388 case rf_ds_dist_spared: 389 return ("dist_spared"); 390 break; 391 case rf_ds_spared: 392 return ("spared"); 393 break; 394 case rf_ds_spare: 395 return ("spare"); 396 break; 397 case rf_ds_used_spare: 398 return ("used_spare"); 399 break; 400 default: 401 return ("UNKNOWN"); 402 } 403 /* NOTREACHED */ 404 } 405 406 static void 407 rf_get_device_status(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(int fd, const char *name) 471 { 472 RF_DeviceConfig_t device_config; 473 void *cfg_ptr; 474 int i; 475 RF_ComponentLabel_t component_label; 476 void *label_ptr; 477 int component_num; 478 int num_cols; 479 480 cfg_ptr = &device_config; 481 482 printf("# raidctl config file for %s\n", name); 483 printf("\n"); 484 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); 485 486 printf("START array\n"); 487 printf("# numRow numCol numSpare\n"); 488 printf("%d %d %d\n", device_config.rows, device_config.cols, 489 device_config.nspares); 490 printf("\n"); 491 492 printf("START disks\n"); 493 for(i=0; i < device_config.ndevs; i++) 494 printf("%s\n", device_config.devs[i].devname); 495 printf("\n"); 496 497 if (device_config.nspares > 0) { 498 printf("START spare\n"); 499 for(i=0; i < device_config.nspares; i++) 500 printf("%s\n", device_config.spares[i].devname); 501 printf("\n"); 502 } 503 504 for(i=0; i < device_config.ndevs; i++) { 505 if (device_config.devs[i].status == rf_ds_optimal) 506 break; 507 } 508 if (i == device_config.ndevs) { 509 printf("# WARNING: no optimal components; using %s\n", 510 device_config.devs[0].devname); 511 i = 0; 512 } 513 get_component_number(fd, device_config.devs[i].devname, 514 &component_num, &num_cols); 515 memset(&component_label, 0, sizeof(RF_ComponentLabel_t)); 516 component_label.row = component_num / num_cols; 517 component_label.column = component_num % num_cols; 518 label_ptr = &component_label; 519 do_ioctl(fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, 520 "RAIDFRAME_GET_COMPONENT_LABEL"); 521 522 printf("START layout\n"); 523 printf( 524 "# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level_%c\n", 525 (char) component_label.parityConfig); 526 printf("%d %d %d %c\n", 527 component_label.sectPerSU, component_label.SUsPerPU, 528 component_label.SUsPerRU, (char) component_label.parityConfig); 529 printf("\n"); 530 531 printf("START queue\n"); 532 printf("fifo %d\n", device_config.maxqdepth); 533 } 534 535 static void 536 get_component_number(int fd, char *component_name, int *component_number, 537 int *num_columns) 538 { 539 RF_DeviceConfig_t device_config; 540 void *cfg_ptr; 541 int i; 542 int found; 543 544 *component_number = -1; 545 546 /* Assuming a full path spec... */ 547 cfg_ptr = &device_config; 548 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, 549 "RAIDFRAME_GET_INFO"); 550 551 *num_columns = device_config.cols; 552 553 found = 0; 554 for(i=0; i < device_config.ndevs; i++) { 555 if (strncmp(component_name, device_config.devs[i].devname, 556 PATH_MAX)==0) { 557 found = 1; 558 *component_number = i; 559 } 560 } 561 if (!found) { /* maybe it's a spare? */ 562 for(i=0; i < device_config.nspares; i++) { 563 if (strncmp(component_name, 564 device_config.spares[i].devname, 565 PATH_MAX)==0) { 566 found = 1; 567 *component_number = i + device_config.ndevs; 568 /* the way spares are done should 569 really change... */ 570 *num_columns = device_config.cols + 571 device_config.nspares; 572 } 573 } 574 } 575 576 if (!found) { 577 fprintf(stderr,"%s: %s is not a component %s", getprogname(), 578 component_name, "of this device\n"); 579 exit(1); 580 } 581 } 582 583 static void 584 rf_fail_disk(int fd, char *component_to_fail, int do_recon) 585 { 586 struct rf_recon_req recon_request; 587 int component_num; 588 int num_cols; 589 590 get_component_number(fd, component_to_fail, &component_num, &num_cols); 591 592 recon_request.row = component_num / num_cols; 593 recon_request.col = component_num % num_cols; 594 if (do_recon) { 595 recon_request.flags = RF_FDFLAGS_RECON; 596 } else { 597 recon_request.flags = RF_FDFLAGS_NONE; 598 } 599 do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request, 600 "RAIDFRAME_FAIL_DISK"); 601 if (do_recon && verbose) { 602 printf("Reconstruction status:\n"); 603 sleep(3); /* XXX give reconstruction a chance to start */ 604 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 605 } 606 } 607 608 static void 609 get_component_label(int fd, char *component) 610 { 611 RF_ComponentLabel_t component_label; 612 void *label_ptr; 613 int component_num; 614 int num_cols; 615 616 get_component_number(fd, component, &component_num, &num_cols); 617 618 memset( &component_label, 0, sizeof(RF_ComponentLabel_t)); 619 component_label.row = component_num / num_cols; 620 component_label.column = component_num % num_cols; 621 622 label_ptr = &component_label; 623 do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, 624 "RAIDFRAME_GET_COMPONENT_LABEL"); 625 626 printf("Component label for %s:\n",component); 627 628 printf(" Row: %d, Column: %d, Num Rows: %d, Num Columns: %d\n", 629 component_label.row, component_label.column, 630 component_label.num_rows, component_label.num_columns); 631 printf(" Version: %d, Serial Number: %d, Mod Counter: %d\n", 632 component_label.version, component_label.serial_number, 633 component_label.mod_counter); 634 printf(" Clean: %s, Status: %d\n", 635 component_label.clean ? "Yes" : "No", 636 component_label.status ); 637 printf(" sectPerSU: %d, SUsPerPU: %d, SUsPerRU: %d\n", 638 component_label.sectPerSU, component_label.SUsPerPU, 639 component_label.SUsPerRU); 640 printf(" Queue size: %d, blocksize: %d, numBlocks: %u\n", 641 component_label.maxOutstanding, component_label.blockSize, 642 component_label.numBlocks); 643 printf(" RAID Level: %c\n", (char) component_label.parityConfig); 644 printf(" Autoconfig: %s\n", 645 component_label.autoconfigure ? "Yes" : "No" ); 646 printf(" Root partition: %s\n", 647 component_label.root_partition ? "Yes" : "No" ); 648 printf(" Last configured as: raid%d\n", component_label.last_unit ); 649 } 650 651 static void 652 set_component_label(int fd, char *component) 653 { 654 RF_ComponentLabel_t component_label; 655 int component_num; 656 int num_cols; 657 658 get_component_number(fd, component, &component_num, &num_cols); 659 660 /* XXX This is currently here for testing, and future expandability */ 661 662 component_label.version = 1; 663 component_label.serial_number = 123456; 664 component_label.mod_counter = 0; 665 component_label.row = component_num / num_cols; 666 component_label.column = component_num % num_cols; 667 component_label.num_rows = 0; 668 component_label.num_columns = 5; 669 component_label.clean = 0; 670 component_label.status = 1; 671 672 do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label, 673 "RAIDFRAME_SET_COMPONENT_LABEL"); 674 } 675 676 677 static void 678 init_component_labels(int fd, int serial_number) 679 { 680 RF_ComponentLabel_t component_label; 681 682 component_label.version = 0; 683 component_label.serial_number = serial_number; 684 component_label.mod_counter = 0; 685 component_label.row = 0; 686 component_label.column = 0; 687 component_label.num_rows = 0; 688 component_label.num_columns = 0; 689 component_label.clean = 0; 690 component_label.status = 0; 691 692 do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label, 693 "RAIDFRAME_SET_COMPONENT_LABEL"); 694 } 695 696 static void 697 set_autoconfig(int fd, int raidID, char *autoconf) 698 { 699 int auto_config; 700 int root_config; 701 702 auto_config = 0; 703 root_config = 0; 704 705 if (strncasecmp(autoconf,"root", 4) == 0) { 706 root_config = 1; 707 } 708 709 if ((strncasecmp(autoconf,"yes", 3) == 0) || 710 root_config == 1) { 711 auto_config = 1; 712 } 713 714 do_ioctl(fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config, 715 "RAIDFRAME_SET_AUTOCONFIG"); 716 717 do_ioctl(fd, RAIDFRAME_SET_ROOT, &root_config, 718 "RAIDFRAME_SET_ROOT"); 719 720 printf("raid%d: Autoconfigure: %s\n", raidID, 721 auto_config ? "Yes" : "No"); 722 723 if (root_config == 1) { 724 printf("raid%d: Root: %s\n", raidID, 725 auto_config ? "Yes" : "No"); 726 } 727 } 728 729 static void 730 add_hot_spare(int fd, char *component) 731 { 732 RF_SingleComponent_t hot_spare; 733 734 hot_spare.row = 0; 735 hot_spare.column = 0; 736 strncpy(hot_spare.component_name, component, 737 sizeof(hot_spare.component_name)); 738 739 do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare, 740 "RAIDFRAME_ADD_HOT_SPARE"); 741 } 742 743 static void 744 remove_hot_spare(int fd, char *component) 745 { 746 RF_SingleComponent_t hot_spare; 747 int component_num; 748 int num_cols; 749 750 get_component_number(fd, component, &component_num, &num_cols); 751 752 hot_spare.row = component_num / num_cols; 753 hot_spare.column = component_num % num_cols; 754 755 strncpy(hot_spare.component_name, component, 756 sizeof(hot_spare.component_name)); 757 758 do_ioctl( fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare, 759 "RAIDFRAME_REMOVE_HOT_SPARE"); 760 } 761 762 static void 763 rebuild_in_place(int fd, char *component) 764 { 765 RF_SingleComponent_t comp; 766 int component_num; 767 int num_cols; 768 769 get_component_number(fd, component, &component_num, &num_cols); 770 771 comp.row = 0; 772 comp.column = component_num; 773 strncpy(comp.component_name, component, sizeof(comp.component_name)); 774 775 do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp, 776 "RAIDFRAME_REBUILD_IN_PLACE"); 777 778 if (verbose) { 779 printf("Reconstruction status:\n"); 780 sleep(3); /* XXX give reconstruction a chance to start */ 781 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 782 } 783 784 } 785 786 static void 787 check_parity(int fd, int do_rewrite, char *dev_name) 788 { 789 int is_clean; 790 int percent_done; 791 792 is_clean = 0; 793 percent_done = 0; 794 do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, 795 "RAIDFRAME_CHECK_PARITY"); 796 if (is_clean) { 797 printf("%s: Parity status: clean\n",dev_name); 798 } else { 799 printf("%s: Parity status: DIRTY\n",dev_name); 800 if (do_rewrite) { 801 printf("%s: Initiating re-write of parity\n", 802 dev_name); 803 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 804 "RAIDFRAME_REWRITEPARITY"); 805 sleep(3); /* XXX give it time to 806 get started. */ 807 if (verbose) { 808 printf("Parity Re-write status:\n"); 809 do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 810 } else { 811 do_ioctl(fd, 812 RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 813 &percent_done, 814 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS" 815 ); 816 while( percent_done < 100 ) { 817 sleep(3); /* wait a bit... */ 818 do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 819 &percent_done, "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); 820 } 821 822 } 823 printf("%s: Parity Re-write complete\n", 824 dev_name); 825 } else { 826 /* parity is wrong, and is not being fixed. 827 Exit w/ an error. */ 828 exit(1); 829 } 830 } 831 } 832 833 834 static void 835 check_status(int fd, int meter) 836 { 837 int recon_percent_done = 0; 838 int parity_percent_done = 0; 839 int copyback_percent_done = 0; 840 841 do_ioctl(fd, RAIDFRAME_CHECK_RECON_STATUS, &recon_percent_done, 842 "RAIDFRAME_CHECK_RECON_STATUS"); 843 printf("Reconstruction is %d%% complete.\n", recon_percent_done); 844 do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 845 &parity_percent_done, 846 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); 847 printf("Parity Re-write is %d%% complete.\n", parity_percent_done); 848 do_ioctl(fd, RAIDFRAME_CHECK_COPYBACK_STATUS, ©back_percent_done, 849 "RAIDFRAME_CHECK_COPYBACK_STATUS"); 850 printf("Copyback is %d%% complete.\n", copyback_percent_done); 851 852 if (meter) { 853 /* These 3 should be mutually exclusive at this point */ 854 if (recon_percent_done < 100) { 855 printf("Reconstruction status:\n"); 856 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 857 } else if (parity_percent_done < 100) { 858 printf("Parity Re-write status:\n"); 859 do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 860 } else if (copyback_percent_done < 100) { 861 printf("Copyback status:\n"); 862 do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); 863 } 864 } 865 } 866 867 const char *tbits = "|/-\\"; 868 869 static void 870 do_meter(int fd, u_long option) 871 { 872 int percent_done; 873 RF_uint64 start_value; 874 RF_ProgressInfo_t progressInfo; 875 void *pInfoPtr; 876 struct timeval start_time; 877 struct timeval current_time; 878 double elapsed; 879 int elapsed_sec; 880 int elapsed_usec; 881 int simple_eta,last_eta; 882 double rate; 883 RF_uint64 amount; 884 int tbit_value; 885 char buffer[1024]; 886 char bar_buffer[1024]; 887 char eta_buffer[1024]; 888 889 if (gettimeofday(&start_time,NULL)) { 890 fprintf(stderr,"%s: gettimeofday failed!?!?\n", getprogname()); 891 exit(errno); 892 } 893 memset(&progressInfo, 0, sizeof(RF_ProgressInfo_t)); 894 pInfoPtr=&progressInfo; 895 896 percent_done = 0; 897 do_ioctl(fd, option, &pInfoPtr, ""); 898 start_value = progressInfo.completed; 899 current_time = start_time; 900 simple_eta = 0; 901 last_eta = 0; 902 903 tbit_value = 0; 904 while(progressInfo.completed < progressInfo.total) { 905 906 percent_done = (progressInfo.completed * 100) / 907 progressInfo.total; 908 909 get_bar(bar_buffer, percent_done, 40); 910 911 elapsed_sec = current_time.tv_sec - start_time.tv_sec; 912 elapsed_usec = current_time.tv_usec - start_time.tv_usec; 913 if (elapsed_usec < 0) { 914 elapsed_usec-=1000000; 915 elapsed_sec++; 916 } 917 918 elapsed = (double) elapsed_sec + 919 (double) elapsed_usec / 1000000.0; 920 921 amount = progressInfo.completed - start_value; 922 923 if (amount <= 0) { /* we don't do negatives (yet?) */ 924 amount = 0; 925 } 926 927 if (elapsed == 0) 928 rate = 0.0; 929 else 930 rate = amount / elapsed; 931 932 if (rate > 0.0) { 933 simple_eta = (int) (((double)progressInfo.total - 934 (double) progressInfo.completed) 935 / rate); 936 } else { 937 simple_eta = -1; 938 } 939 940 if (simple_eta <=0) { 941 simple_eta = last_eta; 942 } else { 943 last_eta = simple_eta; 944 } 945 946 get_time_string(eta_buffer, simple_eta); 947 948 snprintf(buffer,1024,"\r%3d%% |%s| ETA: %s %c", 949 percent_done,bar_buffer,eta_buffer,tbits[tbit_value]); 950 951 write(fileno(stdout),buffer,strlen(buffer)); 952 fflush(stdout); 953 954 if (++tbit_value>3) 955 tbit_value = 0; 956 957 sleep(2); 958 959 if (gettimeofday(¤t_time,NULL)) { 960 fprintf(stderr,"%s: gettimeofday failed!?!?\n", 961 getprogname()); 962 exit(errno); 963 } 964 965 do_ioctl( fd, option, &pInfoPtr, ""); 966 967 968 } 969 printf("\n"); 970 } 971 /* 40 '*''s per line, then 40 ' ''s line. */ 972 /* If you've got a screen wider than 160 characters, "tough" */ 973 974 #define STAR_MIDPOINT 4*40 975 const char stars[] = "****************************************" 976 "****************************************" 977 "****************************************" 978 "****************************************" 979 " " 980 " " 981 " " 982 " " 983 " "; 984 985 static void 986 get_bar(char *string, double percent, int max_strlen) 987 { 988 int offset; 989 990 if (max_strlen > STAR_MIDPOINT) { 991 max_strlen = STAR_MIDPOINT; 992 } 993 offset = STAR_MIDPOINT - 994 (int)((percent * max_strlen)/ 100); 995 if (offset < 0) 996 offset = 0; 997 snprintf(string,max_strlen,"%s",&stars[offset]); 998 } 999 1000 static void 1001 get_time_string(char *string, int simple_time) 1002 { 1003 int minutes, seconds, hours; 1004 char hours_buffer[5]; 1005 char minutes_buffer[5]; 1006 char seconds_buffer[5]; 1007 1008 if (simple_time >= 0) { 1009 1010 minutes = (int) simple_time / 60; 1011 seconds = ((int)simple_time - 60*minutes); 1012 hours = minutes / 60; 1013 minutes = minutes - 60*hours; 1014 1015 if (hours > 0) { 1016 snprintf(hours_buffer,5,"%02d:",hours); 1017 } else { 1018 snprintf(hours_buffer,5," "); 1019 } 1020 1021 snprintf(minutes_buffer,5,"%02d:",minutes); 1022 snprintf(seconds_buffer,5,"%02d",seconds); 1023 snprintf(string,1024,"%s%s%s", 1024 hours_buffer, minutes_buffer, seconds_buffer); 1025 } else { 1026 snprintf(string,1024," --:--"); 1027 } 1028 1029 } 1030 1031 static void 1032 usage(void) 1033 { 1034 const char *progname = getprogname(); 1035 1036 fprintf(stderr, "usage: %s [-v] -a component dev\n", progname); 1037 fprintf(stderr, " %s [-v] -A yes | no | root dev\n", progname); 1038 fprintf(stderr, " %s [-v] -B dev\n", progname); 1039 fprintf(stderr, " %s [-v] -c config_file dev\n", progname); 1040 fprintf(stderr, " %s [-v] -C config_file dev\n", progname); 1041 fprintf(stderr, " %s [-v] -f component dev\n", progname); 1042 fprintf(stderr, " %s [-v] -F component dev\n", progname); 1043 fprintf(stderr, " %s [-v] -g component dev\n", progname); 1044 fprintf(stderr, " %s [-v] -G dev\n", progname); 1045 fprintf(stderr, " %s [-v] -i dev\n", progname); 1046 fprintf(stderr, " %s [-v] -I serial_number dev\n", progname); 1047 fprintf(stderr, " %s [-v] -p dev\n", progname); 1048 fprintf(stderr, " %s [-v] -P dev\n", progname); 1049 fprintf(stderr, " %s [-v] -r component dev\n", progname); 1050 fprintf(stderr, " %s [-v] -R component dev\n", progname); 1051 fprintf(stderr, " %s [-v] -s dev\n", progname); 1052 fprintf(stderr, " %s [-v] -S dev\n", progname); 1053 fprintf(stderr, " %s [-v] -u dev\n", progname); 1054 exit(1); 1055 /* NOTREACHED */ 1056 } 1057