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