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