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