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