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