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