1 /* $NetBSD: raidctl.c,v 1.6 1999/03/02 03:13:59 oster Exp $ */ 2 /*- 3 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Greg Oster 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 40 This program is a re-write of the original rf_ctrl program 41 distributed by CMU with RAIDframe 1.1. 42 43 This program is the user-land interface to the RAIDframe kernel 44 driver in NetBSD. 45 46 */ 47 48 #include <sys/param.h> 49 #include <sys/ioctl.h> 50 #include <sys/stat.h> 51 #include <util.h> 52 #include <stdio.h> 53 #include <fcntl.h> 54 #include <ctype.h> 55 #include <err.h> 56 #include <errno.h> 57 #include <sys/types.h> 58 #include <string.h> 59 #include <sys/disklabel.h> 60 #include <machine/disklabel.h> 61 #include <stdlib.h> 62 #include <unistd.h> 63 64 #include "rf_raidframe.h" 65 66 extern char *__progname; 67 68 int main __P((int, char *[])); 69 static void do_ioctl __P((int, unsigned long, void *, char *)); 70 static void rf_configure __P((int, char*, int)); 71 static char *device_status __P((RF_DiskStatus_t)); 72 static void rf_get_device_status __P((int)); 73 static void get_component_number __P((int, char *, int *, int *)); 74 static void rf_fail_disk __P((int, char *, int)); 75 static void usage __P((void)); 76 static void get_component_label __P((int, char *)); 77 static void set_component_label __P((int, char *)); 78 static void init_component_labels __P((int, int)); 79 static void add_hot_spare __P((int, char *)); 80 static void remove_hot_spare __P((int, char *)); 81 static void rebuild_in_place __P((int, char *)); 82 83 int 84 main(argc,argv) 85 int argc; 86 char *argv[]; 87 { 88 extern char *optarg; 89 extern int optind; 90 int ch; 91 int num_options; 92 unsigned long action; 93 char config_filename[PATH_MAX]; 94 char dev_name[PATH_MAX]; 95 char name[PATH_MAX]; 96 char component[PATH_MAX]; 97 int do_recon; 98 int raidID; 99 int rawpart; 100 int recon_percent_done; 101 int serial_number; 102 struct stat st; 103 int fd; 104 int force; 105 106 num_options = 0; 107 action = 0; 108 do_recon = 0; 109 force = 0; 110 111 while ((ch = getopt(argc, argv, "a:Bc:C:f:F:g:iI:l:r:R:sSu")) != -1) 112 switch(ch) { 113 case 'a': 114 action = RAIDFRAME_ADD_HOT_SPARE; 115 strncpy(component, optarg, PATH_MAX); 116 num_options++; 117 break; 118 case 'B': 119 action = RAIDFRAME_COPYBACK; 120 num_options++; 121 break; 122 case 'c': 123 action = RAIDFRAME_CONFIGURE; 124 strncpy(config_filename,optarg,PATH_MAX); 125 force = 0; 126 num_options++; 127 break; 128 case 'C': 129 strncpy(config_filename,optarg,PATH_MAX); 130 action = RAIDFRAME_CONFIGURE; 131 force = 1; 132 num_options++; 133 break; 134 case 'f': 135 action = RAIDFRAME_FAIL_DISK; 136 strncpy(component, optarg, PATH_MAX); 137 do_recon = 0; 138 num_options++; 139 break; 140 case 'F': 141 action = RAIDFRAME_FAIL_DISK; 142 strncpy(component, optarg, PATH_MAX); 143 do_recon = 1; 144 num_options++; 145 break; 146 case 'g': 147 action = RAIDFRAME_GET_COMPONENT_LABEL; 148 strncpy(component, optarg, PATH_MAX); 149 num_options++; 150 break; 151 case 'i': 152 action = RAIDFRAME_REWRITEPARITY; 153 num_options++; 154 break; 155 case 'I': 156 action = RAIDFRAME_INIT_LABELS; 157 serial_number = atoi(optarg); 158 num_options++; 159 break; 160 case 'l': 161 action = RAIDFRAME_SET_COMPONENT_LABEL; 162 strncpy(component, optarg, PATH_MAX); 163 num_options++; 164 break; 165 case 'r': 166 action = RAIDFRAME_REMOVE_HOT_SPARE; 167 strncpy(component, optarg, PATH_MAX); 168 num_options++; 169 break; 170 case 'R': 171 strncpy(component,optarg,PATH_MAX); 172 action = RAIDFRAME_REBUILD_IN_PLACE; 173 num_options++; 174 break; 175 case 's': 176 action = RAIDFRAME_GET_INFO; 177 num_options++; 178 break; 179 case 'S': 180 action = RAIDFRAME_CHECKRECON; 181 num_options++; 182 break; 183 case 'u': 184 action = RAIDFRAME_SHUTDOWN; 185 num_options++; 186 break; 187 default: 188 usage(); 189 } 190 argc -= optind; 191 argv += optind; 192 193 if ((num_options > 1) || (argc == NULL)) 194 usage(); 195 196 strncpy(name,argv[0],PATH_MAX); 197 198 if ((name[0] == '/') || (name[0] == '.')) { 199 /* they've (apparently) given a full path... */ 200 strncpy(dev_name, name, PATH_MAX); 201 } else { 202 if (isdigit(name[strlen(name)-1])) { 203 rawpart = getrawpartition(); 204 snprintf(dev_name,PATH_MAX,"/dev/%s%c",name, 205 'a'+rawpart); 206 } else { 207 snprintf(dev_name,PATH_MAX,"/dev/%s",name); 208 } 209 } 210 211 if (stat(dev_name, &st) != 0) { 212 fprintf(stderr,"%s: stat failure on: %s\n", 213 __progname,dev_name); 214 return (errno); 215 } 216 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) { 217 fprintf(stderr,"%s: invalid device: %s\n", 218 __progname,dev_name); 219 return (EINVAL); 220 } 221 222 raidID = RF_DEV2RAIDID(st.st_rdev); 223 224 if ((fd = open( dev_name, O_RDWR, 0640)) < 0) { 225 fprintf(stderr, "%s: unable to open device file: %s\n", 226 __progname, dev_name); 227 exit(1); 228 } 229 230 231 switch(action) { 232 case RAIDFRAME_ADD_HOT_SPARE: 233 add_hot_spare(fd,component); 234 break; 235 case RAIDFRAME_REMOVE_HOT_SPARE: 236 remove_hot_spare(fd,component); 237 break; 238 case RAIDFRAME_CONFIGURE: 239 rf_configure(fd, config_filename,force); 240 break; 241 case RAIDFRAME_COPYBACK: 242 printf("Copyback.\n"); 243 do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK"); 244 break; 245 case RAIDFRAME_FAIL_DISK: 246 rf_fail_disk(fd,component,do_recon); 247 break; 248 case RAIDFRAME_SET_COMPONENT_LABEL: 249 set_component_label(fd,component); 250 break; 251 case RAIDFRAME_GET_COMPONENT_LABEL: 252 get_component_label(fd,component); 253 break; 254 case RAIDFRAME_INIT_LABELS: 255 init_component_labels(fd,serial_number); 256 break; 257 case RAIDFRAME_REWRITEPARITY: 258 printf("Initiating re-write of parity\n"); 259 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 260 "RAIDFRAME_REWRITEPARITY"); 261 break; 262 case RAIDFRAME_CHECKRECON: 263 do_ioctl(fd, RAIDFRAME_CHECKRECON, &recon_percent_done, 264 "RAIDFRAME_CHECKRECON"); 265 printf("Reconstruction is %d%% complete.\n", 266 recon_percent_done); 267 break; 268 case RAIDFRAME_GET_INFO: 269 rf_get_device_status(fd); 270 break; 271 case RAIDFRAME_REBUILD_IN_PLACE: 272 rebuild_in_place(fd,component); 273 break; 274 case RAIDFRAME_SHUTDOWN: 275 do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN"); 276 break; 277 default: 278 break; 279 } 280 281 close(fd); 282 exit(0); 283 } 284 285 static void 286 do_ioctl(fd, command, arg, ioctl_name) 287 int fd; 288 unsigned long command; 289 void *arg; 290 char *ioctl_name; 291 { 292 if (ioctl(fd, command, arg) < 0) { 293 warn("ioctl (%s) failed", ioctl_name); 294 exit(1); 295 } 296 } 297 298 299 static void 300 rf_configure(fd,config_file,force) 301 int fd; 302 char *config_file; 303 int force; 304 { 305 void *generic; 306 RF_Config_t cfg; 307 308 if (rf_MakeConfig( config_file, &cfg ) < 0) { 309 fprintf(stderr,"%s: unable to create RAIDframe %s\n", 310 __progname, "configuration structure\n"); 311 exit(1); 312 } 313 314 cfg.force = force; 315 316 /* 317 318 Note the extra level of redirection needed here, since 319 what we really want to pass in is a pointer to the pointer to 320 the configuration structure. 321 322 */ 323 324 generic = (void *) &cfg; 325 do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE"); 326 } 327 328 static char * 329 device_status(status) 330 RF_DiskStatus_t status; 331 { 332 static char status_string[256]; 333 334 switch (status) { 335 case rf_ds_optimal: 336 strcpy(status_string,"optimal"); 337 break; 338 case rf_ds_failed: 339 strcpy(status_string,"failed"); 340 break; 341 case rf_ds_reconstructing: 342 strcpy(status_string,"reconstructing"); 343 break; 344 case rf_ds_dist_spared: 345 strcpy(status_string,"dist_spared"); 346 break; 347 case rf_ds_spared: 348 strcpy(status_string,"spared"); 349 break; 350 case rf_ds_spare: 351 strcpy(status_string,"spare"); 352 break; 353 case rf_ds_used_spare: 354 strcpy(status_string,"used_spare"); 355 break; 356 default: 357 strcpy(status_string,"UNKNOWN"); 358 break; 359 } 360 return(status_string); 361 } 362 363 static void 364 rf_get_device_status(fd) 365 int fd; 366 { 367 RF_DeviceConfig_t device_config; 368 void *cfg_ptr; 369 int i; 370 371 cfg_ptr = &device_config; 372 373 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); 374 375 printf("Components:\n"); 376 for(i=0; i < device_config.ndevs; i++) { 377 printf("%20s: %s\n", device_config.devs[i].devname, 378 device_status(device_config.devs[i].status)); 379 } 380 if (device_config.nspares > 0) { 381 printf("Spares:\n"); 382 for(i=0; i < device_config.nspares; i++) { 383 printf("%20s: %s\n", 384 device_config.spares[i].devname, 385 device_status(device_config.spares[i].status)); 386 } 387 } else { 388 printf("No spares.\n"); 389 } 390 } 391 392 static void 393 get_component_number(fd, component_name, component_number, num_columns) 394 int fd; 395 char *component_name; 396 int *component_number; 397 int *num_columns; 398 { 399 RF_DeviceConfig_t device_config; 400 void *cfg_ptr; 401 int i; 402 int found; 403 404 *component_number = -1; 405 406 /* Assuming a full path spec... */ 407 cfg_ptr = &device_config; 408 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, 409 "RAIDFRAME_GET_INFO"); 410 411 *num_columns = device_config.cols; 412 413 found = 0; 414 for(i=0; i < device_config.ndevs; i++) { 415 if (strncmp(component_name, device_config.devs[i].devname, 416 PATH_MAX)==0) { 417 found = 1; 418 *component_number = i; 419 } 420 } 421 if (!found) { 422 fprintf(stderr,"%s: %s is not a component %s", __progname, 423 component_name, "of this device\n"); 424 exit(1); 425 } 426 } 427 428 static void 429 rf_fail_disk(fd, component_to_fail, do_recon) 430 int fd; 431 char *component_to_fail; 432 int do_recon; 433 { 434 struct rf_recon_req recon_request; 435 int component_num; 436 int num_cols; 437 438 get_component_number(fd, component_to_fail, &component_num, &num_cols); 439 440 recon_request.row = component_num / num_cols; 441 recon_request.col = component_num % num_cols; 442 if (do_recon) { 443 recon_request.flags = RF_FDFLAGS_RECON; 444 } else { 445 recon_request.flags = RF_FDFLAGS_NONE; 446 } 447 do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request, 448 "RAIDFRAME_FAIL_DISK"); 449 } 450 451 static void 452 get_component_label(fd, component) 453 int fd; 454 char *component; 455 { 456 RF_ComponentLabel_t component_label; 457 void *label_ptr; 458 int component_num; 459 int num_cols; 460 461 get_component_number(fd, component, &component_num, &num_cols); 462 463 memset( &component_label, 0, sizeof(RF_ComponentLabel_t)); 464 component_label.row = component_num / num_cols; 465 component_label.column = component_num % num_cols; 466 467 label_ptr = &component_label; 468 do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, 469 "RAIDFRAME_GET_COMPONENT_LABEL"); 470 471 printf("Component label for %s:\n",component); 472 printf("Version: %d\n",component_label.version); 473 printf("Serial Number: %d\n",component_label.serial_number); 474 printf("Mod counter: %d\n",component_label.mod_counter); 475 printf("Row: %d\n", component_label.row); 476 printf("Column: %d\n", component_label.column); 477 printf("Num Rows: %d\n", component_label.num_rows); 478 printf("Num Columns: %d\n", component_label.num_columns); 479 printf("Clean: %d\n", component_label.clean); 480 printf("Status: %s\n", device_status(component_label.status)); 481 } 482 483 static void 484 set_component_label(fd, component) 485 int fd; 486 char *component; 487 { 488 RF_ComponentLabel_t component_label; 489 int component_num; 490 int num_cols; 491 492 get_component_number(fd, component, &component_num, &num_cols); 493 494 /* XXX This is currently here for testing, and future expandability */ 495 496 component_label.version = 1; 497 component_label.serial_number = 123456; 498 component_label.mod_counter = 0; 499 component_label.row = component_num / num_cols; 500 component_label.column = component_num % num_cols; 501 component_label.num_rows = 0; 502 component_label.num_columns = 5; 503 component_label.clean = 0; 504 component_label.status = 1; 505 506 do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label, 507 "RAIDFRAME_SET_COMPONENT_LABEL"); 508 } 509 510 511 static void 512 init_component_labels(fd, serial_number) 513 int fd; 514 int serial_number; 515 { 516 RF_ComponentLabel_t component_label; 517 518 component_label.version = 0; 519 component_label.serial_number = serial_number; 520 component_label.mod_counter = 0; 521 component_label.row = 0; 522 component_label.column = 0; 523 component_label.num_rows = 0; 524 component_label.num_columns = 0; 525 component_label.clean = 0; 526 component_label.status = 0; 527 528 do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label, 529 "RAIDFRAME_SET_COMPONENT_LABEL"); 530 } 531 532 static void 533 add_hot_spare(fd, component) 534 int fd; 535 char *component; 536 { 537 RF_SingleComponent_t hot_spare; 538 539 hot_spare.row = 0; 540 hot_spare.column = 0; 541 strncpy(hot_spare.component_name, component, 542 sizeof(hot_spare.component_name)); 543 544 do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare, 545 "RAIDFRAME_ADD_HOT_SPARE"); 546 } 547 548 static void 549 remove_hot_spare(fd, component) 550 int fd; 551 char *component; 552 { 553 RF_SingleComponent_t hot_spare; 554 int component_num; 555 int num_cols; 556 557 get_component_number(fd, component, &component_num, &num_cols); 558 559 hot_spare.row = component_num / num_cols; 560 hot_spare.column = component_num % num_cols; 561 562 strncpy(hot_spare.component_name, component, 563 sizeof(hot_spare.component_name)); 564 565 do_ioctl( fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare, 566 "RAIDFRAME_REMOVE_HOT_SPARE"); 567 } 568 569 static void 570 rebuild_in_place( fd, component ) 571 int fd; 572 char *component; 573 { 574 RF_SingleComponent_t comp; 575 int component_num; 576 int num_cols; 577 578 get_component_number(fd, component, &component_num, &num_cols); 579 580 comp.row = 0; 581 comp.column = component_num; 582 strncpy(comp.component_name, component, sizeof(comp.component_name)); 583 584 do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp, 585 "RAIDFRAME_REBUILD_IN_PLACE"); 586 } 587 588 589 static void 590 usage() 591 { 592 fprintf(stderr, "usage: %s -a component dev\n", __progname); 593 fprintf(stderr, " %s -B dev\n", __progname); 594 fprintf(stderr, " %s -c config_file dev\n", __progname); 595 fprintf(stderr, " %s -C config_file dev\n", __progname); 596 fprintf(stderr, " %s -f component dev\n", __progname); 597 fprintf(stderr, " %s -F component dev\n", __progname); 598 fprintf(stderr, " %s -g component dev\n", __progname); 599 fprintf(stderr, " %s -i dev\n", __progname); 600 fprintf(stderr, " %s -I serial_number dev\n", __progname); 601 fprintf(stderr, " %s -r component dev\n", __progname); 602 fprintf(stderr, " %s -R component dev\n", __progname); 603 fprintf(stderr, " %s -s dev\n", __progname); 604 fprintf(stderr, " %s -S dev\n", __progname); 605 fprintf(stderr, " %s -u dev\n", __progname); 606 #if 0 607 fprintf(stderr, "usage: %s %s\n", __progname, 608 "-a | -f | -F | -g | -r | -R component dev"); 609 fprintf(stderr, " %s -B | -i | -s | -S -u dev\n", __progname); 610 fprintf(stderr, " %s -c | -C config_file dev\n", __progname); 611 fprintf(stderr, " %s -I serial_number dev\n", __progname); 612 #endif 613 exit(1); 614 /* NOTREACHED */ 615 } 616