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