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