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