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