1 /*- 2 * Copyright (c) 2008, 2009 Yahoo!, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The names of the authors may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: src/usr.sbin/mfiutil/mfi_config.c,v 1.8 2011/11/29 08:16:14 delphij Exp $ 30 */ 31 32 #include <sys/param.h> 33 #ifdef DEBUG 34 #include <sys/sysctl.h> 35 #endif 36 #include <err.h> 37 #include <errno.h> 38 #include <libutil.h> 39 #ifdef DEBUG 40 #include <stdint.h> 41 #endif 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include "mfiutil.h" 47 48 #ifdef DEBUG 49 static void dump_config(int fd, struct mfi_config_data *config); 50 #endif 51 52 static int add_spare(int ac, char **av); 53 static int remove_spare(int ac, char **av); 54 55 int 56 mfi_config_read(int fd, struct mfi_config_data **configp) 57 { 58 struct mfi_config_data *config; 59 uint32_t config_size; 60 int error; 61 62 /* 63 * Keep fetching the config in a loop until we have a large enough 64 * buffer to hold the entire configuration. 65 */ 66 config = NULL; 67 config_size = 1024; 68 fetch: 69 config = reallocf(config, config_size); 70 if (config == NULL) 71 return (-1); 72 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_READ, config, 73 config_size, NULL, 0, NULL) < 0) { 74 error = errno; 75 free(config); 76 errno = error; 77 return (-1); 78 } 79 80 if (config->size > config_size) { 81 config_size = config->size; 82 goto fetch; 83 } 84 85 *configp = config; 86 return (0); 87 } 88 89 static struct mfi_array * 90 mfi_config_lookup_array(struct mfi_config_data *config, uint16_t array_ref) 91 { 92 struct mfi_array *ar; 93 char *p; 94 int i; 95 96 p = (char *)config->array; 97 for (i = 0; i < config->array_count; i++) { 98 ar = (struct mfi_array *)p; 99 if (ar->array_ref == array_ref) 100 return (ar); 101 p += config->array_size; 102 } 103 104 return (NULL); 105 } 106 107 static struct mfi_ld_config * 108 mfi_config_lookup_volume(struct mfi_config_data *config, uint8_t target_id) 109 { 110 struct mfi_ld_config *ld; 111 char *p; 112 int i; 113 114 p = (char *)config->array + config->array_count * config->array_size; 115 for (i = 0; i < config->log_drv_count; i++) { 116 ld = (struct mfi_ld_config *)p; 117 if (ld->properties.ld.v.target_id == target_id) 118 return (ld); 119 p += config->log_drv_size; 120 } 121 122 return (NULL); 123 } 124 125 static int 126 clear_config(int ac, char **av) 127 { 128 struct mfi_ld_list list; 129 int ch, error, fd; 130 u_int i; 131 132 fd = mfi_open(mfi_unit); 133 if (fd < 0) { 134 error = errno; 135 warn("mfi_open"); 136 return (error); 137 } 138 139 if (!mfi_reconfig_supported()) { 140 warnx("The current mfi(4) driver does not support " 141 "configuration changes."); 142 close(fd); 143 return (EOPNOTSUPP); 144 } 145 146 if (mfi_ld_get_list(fd, &list, NULL) < 0) { 147 error = errno; 148 warn("Failed to get volume list"); 149 close(fd); 150 return (error); 151 } 152 153 for (i = 0; i < list.ld_count; i++) { 154 if (mfi_volume_busy(fd, list.ld_list[i].ld.v.target_id)) { 155 warnx("Volume %s is busy and cannot be deleted", 156 mfi_volume_name(fd, list.ld_list[i].ld.v.target_id)); 157 close(fd); 158 return (EBUSY); 159 } 160 } 161 162 printf( 163 "Are you sure you wish to clear the configuration on mfi%u? [y/N] ", 164 mfi_unit); 165 ch = getchar(); 166 if (ch != 'y' && ch != 'Y') { 167 printf("\nAborting\n"); 168 close(fd); 169 return (0); 170 } 171 172 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_CLEAR, NULL, 0, NULL, 0, NULL) < 0) { 173 error = errno; 174 warn("Failed to clear configuration"); 175 close(fd); 176 return (error); 177 } 178 179 printf("mfi%d: Configuration cleared\n", mfi_unit); 180 close(fd); 181 182 return (0); 183 } 184 MFI_COMMAND(top, clear, clear_config); 185 186 #define MFI_ARRAY_SIZE 288 187 #define MAX_DRIVES_PER_ARRAY \ 188 ((MFI_ARRAY_SIZE - sizeof(struct mfi_array)) / 8) 189 190 #define RT_RAID0 0 191 #define RT_RAID1 1 192 #define RT_RAID5 2 193 #define RT_RAID6 3 194 #define RT_JBOD 4 195 #define RT_CONCAT 5 196 #define RT_RAID10 6 197 #define RT_RAID50 7 198 #define RT_RAID60 8 199 200 static int 201 compare_int(const void *one, const void *two) 202 { 203 int first, second; 204 205 first = *(const int *)one; 206 second = *(const int *)two; 207 208 return (first - second); 209 } 210 211 static struct raid_type_entry { 212 const char *name; 213 int raid_type; 214 } raid_type_table[] = { 215 { "raid0", RT_RAID0 }, 216 { "raid-0", RT_RAID0 }, 217 { "raid1", RT_RAID1 }, 218 { "raid-1", RT_RAID1 }, 219 { "mirror", RT_RAID1 }, 220 { "raid5", RT_RAID5 }, 221 { "raid-5", RT_RAID5 }, 222 { "raid6", RT_RAID6 }, 223 { "raid-6", RT_RAID6 }, 224 { "jbod", RT_JBOD }, 225 { "concat", RT_CONCAT }, 226 { "raid10", RT_RAID10 }, 227 { "raid1+0", RT_RAID10 }, 228 { "raid-10", RT_RAID10 }, 229 { "raid-1+0", RT_RAID10 }, 230 { "raid50", RT_RAID50 }, 231 { "raid5+0", RT_RAID50 }, 232 { "raid-50", RT_RAID50 }, 233 { "raid-5+0", RT_RAID50 }, 234 { "raid60", RT_RAID60 }, 235 { "raid6+0", RT_RAID60 }, 236 { "raid-60", RT_RAID60 }, 237 { "raid-6+0", RT_RAID60 }, 238 { NULL, 0 }, 239 }; 240 241 struct config_id_state { 242 int array_count; 243 int log_drv_count; 244 int *arrays; 245 int *volumes; 246 uint16_t array_ref; 247 uint8_t target_id; 248 }; 249 250 struct array_info { 251 int drive_count; 252 struct mfi_pd_info *drives; 253 struct mfi_array *array; 254 }; 255 256 /* Parse a comma-separated list of drives for an array. */ 257 static int 258 parse_array(int fd, int raid_type, char *array_str, struct array_info *info) 259 { 260 struct mfi_pd_info *pinfo; 261 uint16_t device_id; 262 char *cp; 263 u_int count; 264 int error; 265 266 cp = array_str; 267 for (count = 0; cp != NULL; count++) { 268 cp = strchr(cp, ','); 269 if (cp != NULL) { 270 cp++; 271 if (*cp == ',') { 272 warnx("Invalid drive list '%s'", array_str); 273 return (EINVAL); 274 } 275 } 276 } 277 278 /* Validate the number of drives for this array. */ 279 if (count >= MAX_DRIVES_PER_ARRAY) { 280 warnx("Too many drives for a single array: max is %zu", 281 MAX_DRIVES_PER_ARRAY); 282 return (EINVAL); 283 } 284 switch (raid_type) { 285 case RT_RAID1: 286 case RT_RAID10: 287 if (count % 2 != 0) { 288 warnx("RAID1 and RAID10 require an even number of " 289 "drives in each array"); 290 return (EINVAL); 291 } 292 break; 293 case RT_RAID5: 294 case RT_RAID50: 295 if (count < 3) { 296 warnx("RAID5 and RAID50 require at least 3 drives in " 297 "each array"); 298 return (EINVAL); 299 } 300 break; 301 case RT_RAID6: 302 case RT_RAID60: 303 if (count < 4) { 304 warnx("RAID6 and RAID60 require at least 4 drives in " 305 "each array"); 306 return (EINVAL); 307 } 308 break; 309 } 310 311 /* Validate each drive. */ 312 info->drives = calloc(count, sizeof(struct mfi_pd_info)); 313 if (info->drives == NULL) { 314 warnx("malloc failed"); 315 return (ENOMEM); 316 } 317 info->drive_count = count; 318 for (pinfo = info->drives; (cp = strsep(&array_str, ",")) != NULL; 319 pinfo++) { 320 error = mfi_lookup_drive(fd, cp, &device_id); 321 if (error) { 322 free(info->drives); 323 info->drives = NULL; 324 return (error); 325 } 326 327 if (mfi_pd_get_info(fd, device_id, pinfo, NULL) < 0) { 328 error = errno; 329 warn("Failed to fetch drive info for drive %s", cp); 330 free(info->drives); 331 info->drives = NULL; 332 return (error); 333 } 334 335 if (pinfo->fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) { 336 warnx("Drive %u is not available", device_id); 337 free(info->drives); 338 info->drives = NULL; 339 return (EINVAL); 340 } 341 } 342 343 return (0); 344 } 345 346 /* 347 * Find the next free array ref assuming that 'array_ref' is the last 348 * one used. 'array_ref' should be 0xffff for the initial test. 349 */ 350 static uint16_t 351 find_next_array(struct config_id_state *state) 352 { 353 int i; 354 355 /* Assume the current one is used. */ 356 state->array_ref++; 357 358 /* Find the next free one. */ 359 for (i = 0; i < state->array_count; i++) 360 if (state->arrays[i] == state->array_ref) 361 state->array_ref++; 362 return (state->array_ref); 363 } 364 365 /* 366 * Find the next free volume ID assuming that 'target_id' is the last 367 * one used. 'target_id' should be 0xff for the initial test. 368 */ 369 static uint8_t 370 find_next_volume(struct config_id_state *state) 371 { 372 int i; 373 374 /* Assume the current one is used. */ 375 state->target_id++; 376 377 /* Find the next free one. */ 378 for (i = 0; i < state->log_drv_count; i++) 379 if (state->volumes[i] == state->target_id) 380 state->target_id++; 381 return (state->target_id); 382 } 383 384 /* Populate an array with drives. */ 385 static void 386 build_array(int fd, char *arrayp, struct array_info *array_info, 387 struct config_id_state *state, int verbose) 388 { 389 struct mfi_array *ar = (struct mfi_array *)arrayp; 390 int i; 391 392 ar->size = array_info->drives[0].coerced_size; 393 ar->num_drives = array_info->drive_count; 394 ar->array_ref = find_next_array(state); 395 for (i = 0; i < array_info->drive_count; i++) { 396 if (verbose) 397 printf("Adding drive %s to array %u\n", 398 mfi_drive_name(NULL, 399 array_info->drives[i].ref.v.device_id, 400 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS), 401 ar->array_ref); 402 if (ar->size > array_info->drives[i].coerced_size) 403 ar->size = array_info->drives[i].coerced_size; 404 ar->pd[i].ref = array_info->drives[i].ref; 405 ar->pd[i].fw_state = MFI_PD_STATE_ONLINE; 406 } 407 array_info->array = ar; 408 } 409 410 /* 411 * Create a volume that spans one or more arrays. 412 */ 413 static void 414 build_volume(char *volumep, int narrays, struct array_info *arrays, 415 int raid_type, long stripe_size, struct config_id_state *state, int verbose) 416 { 417 struct mfi_ld_config *ld = (struct mfi_ld_config *)volumep; 418 struct mfi_array *ar; 419 int i; 420 421 /* properties */ 422 ld->properties.ld.v.target_id = find_next_volume(state); 423 ld->properties.ld.v.seq = 0; 424 ld->properties.default_cache_policy = MR_LD_CACHE_ALLOW_WRITE_CACHE | 425 MR_LD_CACHE_WRITE_BACK; 426 ld->properties.access_policy = MFI_LD_ACCESS_RW; 427 ld->properties.disk_cache_policy = MR_PD_CACHE_UNCHANGED; 428 ld->properties.current_cache_policy = MR_LD_CACHE_ALLOW_WRITE_CACHE | 429 MR_LD_CACHE_WRITE_BACK; 430 ld->properties.no_bgi = 0; 431 432 /* params */ 433 switch (raid_type) { 434 case RT_RAID0: 435 case RT_JBOD: 436 ld->params.primary_raid_level = DDF_RAID0; 437 ld->params.raid_level_qualifier = 0; 438 ld->params.secondary_raid_level = 0; 439 break; 440 case RT_RAID1: 441 ld->params.primary_raid_level = DDF_RAID1; 442 ld->params.raid_level_qualifier = 0; 443 ld->params.secondary_raid_level = 0; 444 break; 445 case RT_RAID5: 446 ld->params.primary_raid_level = DDF_RAID5; 447 ld->params.raid_level_qualifier = 3; 448 ld->params.secondary_raid_level = 0; 449 break; 450 case RT_RAID6: 451 ld->params.primary_raid_level = DDF_RAID6; 452 ld->params.raid_level_qualifier = 3; 453 ld->params.secondary_raid_level = 0; 454 break; 455 case RT_CONCAT: 456 ld->params.primary_raid_level = DDF_CONCAT; 457 ld->params.raid_level_qualifier = 0; 458 ld->params.secondary_raid_level = 0; 459 break; 460 case RT_RAID10: 461 ld->params.primary_raid_level = DDF_RAID1; 462 ld->params.raid_level_qualifier = 0; 463 ld->params.secondary_raid_level = 3; /* XXX? */ 464 break; 465 case RT_RAID50: 466 /* 467 * XXX: This appears to work though the card's BIOS 468 * complains that the configuration is foreign. The 469 * BIOS setup does not allow for creation of RAID-50 470 * or RAID-60 arrays. The only nested array 471 * configuration it allows for is RAID-10. 472 */ 473 ld->params.primary_raid_level = DDF_RAID5; 474 ld->params.raid_level_qualifier = 3; 475 ld->params.secondary_raid_level = 3; /* XXX? */ 476 break; 477 case RT_RAID60: 478 ld->params.primary_raid_level = DDF_RAID6; 479 ld->params.raid_level_qualifier = 3; 480 ld->params.secondary_raid_level = 3; /* XXX? */ 481 break; 482 } 483 484 /* 485 * Stripe size is encoded as (2 ^ N) * 512 = stripe_size. Use 486 * ffs() to simulate log2(stripe_size). 487 */ 488 ld->params.stripe_size = ffs(stripe_size) - 1 - 9; 489 ld->params.num_drives = arrays[0].array->num_drives; 490 ld->params.span_depth = narrays; 491 ld->params.state = MFI_LD_STATE_OPTIMAL; 492 ld->params.init_state = MFI_LD_PARAMS_INIT_NO; 493 ld->params.is_consistent = 0; 494 495 /* spans */ 496 for (i = 0; i < narrays; i++) { 497 ar = arrays[i].array; 498 if (verbose) 499 printf("Adding array %u to volume %u\n", ar->array_ref, 500 ld->properties.ld.v.target_id); 501 ld->span[i].start_block = 0; 502 ld->span[i].num_blocks = ar->size; 503 ld->span[i].array_ref = ar->array_ref; 504 } 505 } 506 507 static int 508 create_volume(int ac, char **av) 509 { 510 struct mfi_config_data *config; 511 struct mfi_array *ar; 512 struct mfi_ld_config *ld; 513 struct config_id_state state; 514 size_t config_size; 515 char *p, *cfg_arrays, *cfg_volumes; 516 int error, fd, i, raid_type; 517 int narrays, nvolumes, arrays_per_volume; 518 struct array_info *arrays; 519 int64_t stripe_size; 520 #ifdef DEBUG 521 int dump; 522 #endif 523 int ch, verbose; 524 525 /* 526 * Backwards compat. Map 'create volume' to 'create' and 527 * 'create spare' to 'add'. 528 */ 529 if (ac > 1) { 530 if (strcmp(av[1], "volume") == 0) { 531 av++; 532 ac--; 533 } else if (strcmp(av[1], "spare") == 0) { 534 av++; 535 ac--; 536 return (add_spare(ac, av)); 537 } 538 } 539 540 if (ac < 2) { 541 warnx("create volume: volume type required"); 542 return (EINVAL); 543 } 544 545 bzero(&state, sizeof(state)); 546 config = NULL; 547 arrays = NULL; 548 narrays = 0; 549 error = 0; 550 551 fd = mfi_open(mfi_unit); 552 if (fd < 0) { 553 error = errno; 554 warn("mfi_open"); 555 return (error); 556 } 557 558 if (!mfi_reconfig_supported()) { 559 warnx("The current mfi(4) driver does not support " 560 "configuration changes."); 561 error = EOPNOTSUPP; 562 goto error; 563 } 564 565 /* Lookup the RAID type first. */ 566 raid_type = -1; 567 for (i = 0; raid_type_table[i].name != NULL; i++) 568 if (strcasecmp(raid_type_table[i].name, av[1]) == 0) { 569 raid_type = raid_type_table[i].raid_type; 570 break; 571 } 572 573 if (raid_type == -1) { 574 warnx("Unknown or unsupported volume type %s", av[1]); 575 error = EINVAL; 576 goto error; 577 } 578 579 /* Parse any options. */ 580 optind = 2; 581 #ifdef DEBUG 582 dump = 0; 583 #endif 584 verbose = 0; 585 stripe_size = 64 * 1024; 586 587 while ((ch = getopt(ac, av, "ds:v")) != -1) { 588 switch (ch) { 589 #ifdef DEBUG 590 case 'd': 591 dump = 1; 592 break; 593 #endif 594 case 's': 595 error = dehumanize_number(optarg, &stripe_size); 596 if (error != 0) { 597 warnx("Illegal stripe size"); 598 goto error; 599 } 600 if ((stripe_size < 512) || (!powerof2(stripe_size))) { 601 warnx("Illegal stripe size, using 64K"); 602 stripe_size = 64 * 1024; 603 } 604 break; 605 case 'v': 606 verbose = 1; 607 break; 608 case '?': 609 default: 610 error = EINVAL; 611 goto error; 612 } 613 } 614 ac -= optind; 615 av += optind; 616 617 /* Parse all the arrays. */ 618 narrays = ac; 619 if (narrays == 0) { 620 warnx("At least one drive list is required"); 621 error = EINVAL; 622 goto error; 623 } 624 switch (raid_type) { 625 case RT_RAID0: 626 case RT_RAID1: 627 case RT_RAID5: 628 case RT_RAID6: 629 case RT_CONCAT: 630 if (narrays != 1) { 631 warnx("Only one drive list can be specified"); 632 error = EINVAL; 633 goto error; 634 } 635 break; 636 case RT_RAID10: 637 case RT_RAID50: 638 case RT_RAID60: 639 if (narrays < 1) { 640 warnx("RAID10, RAID50, and RAID60 require at least " 641 "two drive lists"); 642 error = EINVAL; 643 goto error; 644 } 645 if (narrays > MFI_MAX_SPAN_DEPTH) { 646 warnx("Volume spans more than %d arrays", 647 MFI_MAX_SPAN_DEPTH); 648 error = EINVAL; 649 goto error; 650 } 651 break; 652 } 653 arrays = calloc(narrays, sizeof(*arrays)); 654 if (arrays == NULL) { 655 warnx("malloc failed"); 656 error = ENOMEM; 657 goto error; 658 } 659 for (i = 0; i < narrays; i++) { 660 error = parse_array(fd, raid_type, av[i], &arrays[i]); 661 if (error) 662 goto error; 663 } 664 665 switch (raid_type) { 666 case RT_RAID10: 667 case RT_RAID50: 668 case RT_RAID60: 669 for (i = 1; i < narrays; i++) { 670 if (arrays[i].drive_count != arrays[0].drive_count) { 671 warnx("All arrays must contain the same " 672 "number of drives"); 673 error = EINVAL; 674 goto error; 675 } 676 } 677 break; 678 } 679 680 /* 681 * Fetch the current config and build sorted lists of existing 682 * array and volume identifiers. 683 */ 684 if (mfi_config_read(fd, &config) < 0) { 685 error = errno; 686 warn("Failed to read configuration"); 687 goto error; 688 } 689 p = (char *)config->array; 690 state.array_ref = 0xffff; 691 state.target_id = 0xff; 692 state.array_count = config->array_count; 693 if (config->array_count > 0) { 694 state.arrays = calloc(config->array_count, sizeof(int)); 695 if (state.arrays == NULL) { 696 warnx("malloc failed"); 697 error = ENOMEM; 698 goto error; 699 } 700 for (i = 0; i < config->array_count; i++) { 701 ar = (struct mfi_array *)p; 702 state.arrays[i] = ar->array_ref; 703 p += config->array_size; 704 } 705 qsort(state.arrays, config->array_count, sizeof(int), 706 compare_int); 707 } else 708 state.arrays = NULL; 709 state.log_drv_count = config->log_drv_count; 710 if (config->log_drv_count) { 711 state.volumes = calloc(config->log_drv_count, sizeof(int)); 712 if (state.volumes == NULL) { 713 warnx("malloc failed"); 714 error = ENOMEM; 715 goto error; 716 } 717 for (i = 0; i < config->log_drv_count; i++) { 718 ld = (struct mfi_ld_config *)p; 719 state.volumes[i] = ld->properties.ld.v.target_id; 720 p += config->log_drv_size; 721 } 722 qsort(state.volumes, config->log_drv_count, sizeof(int), 723 compare_int); 724 } else 725 state.volumes = NULL; 726 free(config); 727 728 /* Determine the size of the configuration we will build. */ 729 switch (raid_type) { 730 case RT_RAID0: 731 case RT_RAID1: 732 case RT_RAID5: 733 case RT_RAID6: 734 case RT_CONCAT: 735 case RT_JBOD: 736 /* Each volume spans a single array. */ 737 nvolumes = narrays; 738 break; 739 case RT_RAID10: 740 case RT_RAID50: 741 case RT_RAID60: 742 /* A single volume spans multiple arrays. */ 743 nvolumes = 1; 744 break; 745 default: 746 /* Pacify gcc. */ 747 abort(); 748 } 749 750 config_size = sizeof(struct mfi_config_data) + 751 sizeof(struct mfi_ld_config) * nvolumes + MFI_ARRAY_SIZE * narrays; 752 config = calloc(1, config_size); 753 if (config == NULL) { 754 warnx("malloc failed"); 755 error = ENOMEM; 756 goto error; 757 } 758 config->size = config_size; 759 config->array_count = narrays; 760 config->array_size = MFI_ARRAY_SIZE; /* XXX: Firmware hardcode */ 761 config->log_drv_count = nvolumes; 762 config->log_drv_size = sizeof(struct mfi_ld_config); 763 config->spares_count = 0; 764 config->spares_size = 40; /* XXX: Firmware hardcode */ 765 cfg_arrays = (char *)config->array; 766 cfg_volumes = cfg_arrays + config->array_size * narrays; 767 768 /* Build the arrays. */ 769 for (i = 0; i < narrays; i++) { 770 build_array(fd, cfg_arrays, &arrays[i], &state, verbose); 771 cfg_arrays += config->array_size; 772 } 773 774 /* Now build the volume(s). */ 775 arrays_per_volume = narrays / nvolumes; 776 for (i = 0; i < nvolumes; i++) { 777 build_volume(cfg_volumes, arrays_per_volume, 778 &arrays[i * arrays_per_volume], raid_type, stripe_size, 779 &state, verbose); 780 cfg_volumes += config->log_drv_size; 781 } 782 783 #ifdef DEBUG 784 if (dump) 785 dump_config(fd, config); 786 #endif 787 788 /* Send the new config to the controller. */ 789 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_ADD, config, config_size, 790 NULL, 0, NULL) < 0) { 791 error = errno; 792 warn("Failed to add volume"); 793 /* FALLTHROUGH */ 794 } 795 796 error: 797 /* Clean up. */ 798 free(config); 799 free(state.volumes); 800 free(state.arrays); 801 if (arrays != NULL) { 802 for (i = 0; i < narrays; i++) 803 free(arrays[i].drives); 804 free(arrays); 805 } 806 close(fd); 807 808 return (error); 809 } 810 MFI_COMMAND(top, create, create_volume); 811 812 static int 813 delete_volume(int ac, char **av) 814 { 815 struct mfi_ld_info info; 816 int error, fd; 817 uint8_t target_id, mbox[4]; 818 819 /* 820 * Backwards compat. Map 'delete volume' to 'delete' and 821 * 'delete spare' to 'remove'. 822 */ 823 if (ac > 1) { 824 if (strcmp(av[1], "volume") == 0) { 825 av++; 826 ac--; 827 } else if (strcmp(av[1], "spare") == 0) { 828 av++; 829 ac--; 830 return (remove_spare(ac, av)); 831 } 832 } 833 834 if (ac != 2) { 835 warnx("delete volume: volume required"); 836 return (EINVAL); 837 } 838 839 fd = mfi_open(mfi_unit); 840 if (fd < 0) { 841 error = errno; 842 warn("mfi_open"); 843 return (error); 844 } 845 846 if (!mfi_reconfig_supported()) { 847 warnx("The current mfi(4) driver does not support " 848 "configuration changes."); 849 close(fd); 850 return (EOPNOTSUPP); 851 } 852 853 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) { 854 error = errno; 855 warn("Invalid volume %s", av[1]); 856 close(fd); 857 return (error); 858 } 859 860 if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) { 861 error = errno; 862 warn("Failed to get info for volume %d", target_id); 863 close(fd); 864 return (error); 865 } 866 867 if (mfi_volume_busy(fd, target_id)) { 868 warnx("Volume %s is busy and cannot be deleted", 869 mfi_volume_name(fd, target_id)); 870 close(fd); 871 return (EBUSY); 872 } 873 874 mbox_store_ldref(mbox, &info.ld_config.properties.ld); 875 if (mfi_dcmd_command(fd, MFI_DCMD_LD_DELETE, NULL, 0, mbox, 876 sizeof(mbox), NULL) < 0) { 877 error = errno; 878 warn("Failed to delete volume"); 879 close(fd); 880 return (error); 881 } 882 883 close(fd); 884 885 return (0); 886 } 887 MFI_COMMAND(top, delete, delete_volume); 888 889 static int 890 add_spare(int ac, char **av) 891 { 892 struct mfi_pd_info info; 893 struct mfi_config_data *config; 894 struct mfi_array *ar; 895 struct mfi_ld_config *ld; 896 struct mfi_spare *spare; 897 uint16_t device_id; 898 uint8_t target_id; 899 char *p; 900 int error, fd, i; 901 902 if (ac < 2) { 903 warnx("add spare: drive required"); 904 return (EINVAL); 905 } 906 907 fd = mfi_open(mfi_unit); 908 if (fd < 0) { 909 error = errno; 910 warn("mfi_open"); 911 return (error); 912 } 913 914 config = NULL; 915 spare = NULL; 916 error = mfi_lookup_drive(fd, av[1], &device_id); 917 if (error) 918 goto error; 919 920 if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) { 921 error = errno; 922 warn("Failed to fetch drive info"); 923 goto error; 924 } 925 926 if (info.fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) { 927 warnx("Drive %u is not available", device_id); 928 error = EINVAL; 929 goto error; 930 } 931 932 if (ac > 2) { 933 if (mfi_lookup_volume(fd, av[2], &target_id) < 0) { 934 error = errno; 935 warn("Invalid volume %s", av[2]); 936 goto error; 937 } 938 } 939 940 if (mfi_config_read(fd, &config) < 0) { 941 error = errno; 942 warn("Failed to read configuration"); 943 goto error; 944 } 945 946 spare = malloc(sizeof(struct mfi_spare) + sizeof(uint16_t) * 947 config->array_count); 948 if (spare == NULL) { 949 warnx("malloc failed"); 950 error = ENOMEM; 951 goto error; 952 } 953 bzero(spare, sizeof(struct mfi_spare)); 954 spare->ref = info.ref; 955 956 if (ac == 2) { 957 /* Global spare backs all arrays. */ 958 p = (char *)config->array; 959 for (i = 0; i < config->array_count; i++) { 960 ar = (struct mfi_array *)p; 961 if (ar->size > info.coerced_size) { 962 warnx("Spare isn't large enough for array %u", 963 ar->array_ref); 964 error = EINVAL; 965 goto error; 966 } 967 p += config->array_size; 968 } 969 spare->array_count = 0; 970 } else { 971 /* 972 * Dedicated spares only back the arrays for a 973 * specific volume. 974 */ 975 ld = mfi_config_lookup_volume(config, target_id); 976 if (ld == NULL) { 977 warnx("Did not find volume %d", target_id); 978 error = EINVAL; 979 goto error; 980 } 981 982 spare->spare_type |= MFI_SPARE_DEDICATED; 983 spare->array_count = ld->params.span_depth; 984 for (i = 0; i < ld->params.span_depth; i++) { 985 ar = mfi_config_lookup_array(config, 986 ld->span[i].array_ref); 987 if (ar == NULL) { 988 warnx("Missing array; inconsistent config?"); 989 error = ENXIO; 990 goto error; 991 } 992 if (ar->size > info.coerced_size) { 993 warnx("Spare isn't large enough for array %u", 994 ar->array_ref); 995 error = EINVAL; 996 goto error; 997 } 998 spare->array_ref[i] = ar->array_ref; 999 } 1000 } 1001 1002 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_MAKE_SPARE, spare, 1003 sizeof(struct mfi_spare) + sizeof(uint16_t) * spare->array_count, 1004 NULL, 0, NULL) < 0) { 1005 error = errno; 1006 warn("Failed to assign spare"); 1007 /* FALLTHROUGH. */ 1008 } 1009 1010 error: 1011 free(spare); 1012 free(config); 1013 close(fd); 1014 1015 return (error); 1016 } 1017 MFI_COMMAND(top, add, add_spare); 1018 1019 static int 1020 remove_spare(int ac, char **av) 1021 { 1022 struct mfi_pd_info info; 1023 int error, fd; 1024 uint16_t device_id; 1025 uint8_t mbox[4]; 1026 1027 if (ac != 2) { 1028 warnx("remove spare: drive required"); 1029 return (EINVAL); 1030 } 1031 1032 fd = mfi_open(mfi_unit); 1033 if (fd < 0) { 1034 error = errno; 1035 warn("mfi_open"); 1036 return (error); 1037 } 1038 1039 error = mfi_lookup_drive(fd, av[1], &device_id); 1040 if (error) { 1041 close(fd); 1042 return (error); 1043 } 1044 1045 /* Get the info for this drive. */ 1046 if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) { 1047 error = errno; 1048 warn("Failed to fetch info for drive %u", device_id); 1049 close(fd); 1050 return (error); 1051 } 1052 1053 if (info.fw_state != MFI_PD_STATE_HOT_SPARE) { 1054 warnx("Drive %u is not a hot spare", device_id); 1055 close(fd); 1056 return (EINVAL); 1057 } 1058 1059 mbox_store_pdref(mbox, &info.ref); 1060 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_REMOVE_SPARE, NULL, 0, mbox, 1061 sizeof(mbox), NULL) < 0) { 1062 error = errno; 1063 warn("Failed to delete spare"); 1064 close(fd); 1065 return (error); 1066 } 1067 1068 close(fd); 1069 1070 return (0); 1071 } 1072 MFI_COMMAND(top, remove, remove_spare); 1073 1074 #ifdef DEBUG 1075 /* Display raw data about a config. */ 1076 static void 1077 dump_config(int fd, struct mfi_config_data *config) 1078 { 1079 struct mfi_array *ar; 1080 struct mfi_ld_config *ld; 1081 struct mfi_spare *sp; 1082 struct mfi_pd_info pinfo; 1083 uint16_t device_id; 1084 char *p; 1085 int i, j; 1086 1087 printf( 1088 "mfi%d Configuration (Debug): %d arrays, %d volumes, %d spares\n", 1089 mfi_unit, config->array_count, config->log_drv_count, 1090 config->spares_count); 1091 printf(" array size: %u\n", config->array_size); 1092 printf(" volume size: %u\n", config->log_drv_size); 1093 printf(" spare size: %u\n", config->spares_size); 1094 p = (char *)config->array; 1095 1096 for (i = 0; i < config->array_count; i++) { 1097 ar = (struct mfi_array *)p; 1098 printf(" array %u of %u drives:\n", ar->array_ref, 1099 ar->num_drives); 1100 printf(" size = %ju\n", (uintmax_t)ar->size); 1101 for (j = 0; j < ar->num_drives; j++) { 1102 device_id = ar->pd[j].ref.v.device_id; 1103 if (device_id == 0xffff) 1104 printf(" drive MISSING\n"); 1105 else { 1106 printf(" drive %u %s\n", device_id, 1107 mfi_pdstate(ar->pd[j].fw_state)); 1108 if (mfi_pd_get_info(fd, device_id, &pinfo, 1109 NULL) >= 0) { 1110 printf(" raw size: %ju\n", 1111 (uintmax_t)pinfo.raw_size); 1112 printf(" non-coerced size: %ju\n", 1113 (uintmax_t)pinfo.non_coerced_size); 1114 printf(" coerced size: %ju\n", 1115 (uintmax_t)pinfo.coerced_size); 1116 } 1117 } 1118 } 1119 p += config->array_size; 1120 } 1121 1122 for (i = 0; i < config->log_drv_count; i++) { 1123 ld = (struct mfi_ld_config *)p; 1124 printf(" volume %s ", 1125 mfi_volume_name(fd, ld->properties.ld.v.target_id)); 1126 printf("%s %s", 1127 mfi_raid_level(ld->params.primary_raid_level, 1128 ld->params.secondary_raid_level), 1129 mfi_ldstate(ld->params.state)); 1130 if (ld->properties.name[0] != '\0') 1131 printf(" <%s>", ld->properties.name); 1132 printf("\n"); 1133 printf(" primary raid level: %u\n", 1134 ld->params.primary_raid_level); 1135 printf(" raid level qualifier: %u\n", 1136 ld->params.raid_level_qualifier); 1137 printf(" secondary raid level: %u\n", 1138 ld->params.secondary_raid_level); 1139 printf(" stripe size: %u\n", ld->params.stripe_size); 1140 printf(" num drives: %u\n", ld->params.num_drives); 1141 printf(" init state: %u\n", ld->params.init_state); 1142 printf(" consistent: %u\n", ld->params.is_consistent); 1143 printf(" no bgi: %u\n", ld->properties.no_bgi); 1144 printf(" spans:\n"); 1145 for (j = 0; j < ld->params.span_depth; j++) { 1146 printf(" array %u @ ", ld->span[j].array_ref); 1147 printf("%ju : %ju\n", 1148 (uintmax_t)ld->span[j].start_block, 1149 (uintmax_t)ld->span[j].num_blocks); 1150 } 1151 p += config->log_drv_size; 1152 } 1153 1154 for (i = 0; i < config->spares_count; i++) { 1155 sp = (struct mfi_spare *)p; 1156 printf(" %s spare %u ", 1157 sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" : 1158 "global", sp->ref.v.device_id); 1159 printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE)); 1160 printf(" backs:\n"); 1161 for (j = 0; j < sp->array_count; j++) 1162 printf(" array %u\n", sp->array_ref[j]); 1163 p += config->spares_size; 1164 } 1165 } 1166 1167 static int 1168 debug_config(int ac, char **av) 1169 { 1170 struct mfi_config_data *config; 1171 int error, fd; 1172 1173 if (ac != 1) { 1174 warnx("debug: extra arguments"); 1175 return (EINVAL); 1176 } 1177 1178 fd = mfi_open(mfi_unit); 1179 if (fd < 0) { 1180 error = errno; 1181 warn("mfi_open"); 1182 return (error); 1183 } 1184 1185 /* Get the config from the controller. */ 1186 if (mfi_config_read(fd, &config) < 0) { 1187 error = errno; 1188 warn("Failed to get config"); 1189 close(fd); 1190 return (error); 1191 } 1192 1193 /* Dump out the configuration. */ 1194 dump_config(fd, config); 1195 free(config); 1196 close(fd); 1197 1198 return (0); 1199 } 1200 MFI_COMMAND(top, debug, debug_config); 1201 1202 static int 1203 dump(int ac, char **av) 1204 { 1205 struct mfi_config_data *config; 1206 char buf[64]; 1207 size_t len; 1208 int error, fd; 1209 1210 if (ac != 1) { 1211 warnx("dump: extra arguments"); 1212 return (EINVAL); 1213 } 1214 1215 fd = mfi_open(mfi_unit); 1216 if (fd < 0) { 1217 error = errno; 1218 warn("mfi_open"); 1219 return (error); 1220 } 1221 1222 /* Get the stashed copy of the last dcmd from the driver. */ 1223 snprintf(buf, sizeof(buf), "hw.mfi%d.debug_command", mfi_unit); 1224 if (sysctlbyname(buf, NULL, &len, NULL, 0) < 0) { 1225 error = errno; 1226 warn("Failed to read debug command"); 1227 if (error == ENOENT) 1228 error = EOPNOTSUPP; 1229 close(fd); 1230 return (error); 1231 } 1232 1233 config = malloc(len); 1234 if (config == NULL) { 1235 warnx("malloc failed"); 1236 close(fd); 1237 return (ENOMEM); 1238 } 1239 if (sysctlbyname(buf, config, &len, NULL, 0) < 0) { 1240 error = errno; 1241 warn("Failed to read debug command"); 1242 free(config); 1243 close(fd); 1244 return (error); 1245 } 1246 dump_config(fd, config); 1247 free(config); 1248 close(fd); 1249 1250 return (0); 1251 } 1252 MFI_COMMAND(top, dump, dump); 1253 #endif 1254