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