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