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 info->drive_count = count; 332 for (pinfo = info->drives; (cp = strsep(&array_str, ",")) != NULL; 333 pinfo++) { 334 error = mfi_lookup_drive(fd, cp, &device_id); 335 if (error) 336 return (error); 337 338 if (mfi_pd_get_info(fd, device_id, pinfo, NULL) < 0) { 339 error = errno; 340 warn("Failed to fetch drive info for drive %s", cp); 341 return (error); 342 } 343 344 if (pinfo->fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) { 345 warnx("Drive %u is not available", device_id); 346 return (EINVAL); 347 } 348 } 349 350 return (0); 351 } 352 353 /* 354 * Find the next free array ref assuming that 'array_ref' is the last 355 * one used. 'array_ref' should be 0xffff for the initial test. 356 */ 357 static uint16_t 358 find_next_array(struct config_id_state *state) 359 { 360 int i; 361 362 /* Assume the current one is used. */ 363 state->array_ref++; 364 365 /* Find the next free one. */ 366 for (i = 0; i < state->array_count; i++) 367 if (state->arrays[i] == state->array_ref) 368 state->array_ref++; 369 return (state->array_ref); 370 } 371 372 /* 373 * Find the next free volume ID assuming that 'target_id' is the last 374 * one used. 'target_id' should be 0xff for the initial test. 375 */ 376 static uint8_t 377 find_next_volume(struct config_id_state *state) 378 { 379 int i; 380 381 /* Assume the current one is used. */ 382 state->target_id++; 383 384 /* Find the next free one. */ 385 for (i = 0; i < state->log_drv_count; i++) 386 if (state->volumes[i] == state->target_id) 387 state->target_id++; 388 return (state->target_id); 389 } 390 391 /* Populate an array with drives. */ 392 static void 393 build_array(int fd, char *arrayp, struct array_info *array_info, 394 struct config_id_state *state, int verbose) 395 { 396 struct mfi_array *ar = (struct mfi_array *)arrayp; 397 int i; 398 399 ar->size = array_info->drives[0].coerced_size; 400 ar->num_drives = array_info->drive_count; 401 ar->array_ref = find_next_array(state); 402 for (i = 0; i < array_info->drive_count; i++) { 403 if (verbose) 404 printf("Adding drive %u to array %u\n", 405 array_info->drives[i].ref.v.device_id, 406 ar->array_ref); 407 if (ar->size > array_info->drives[i].coerced_size) 408 ar->size = array_info->drives[i].coerced_size; 409 ar->pd[i].ref = array_info->drives[i].ref; 410 ar->pd[i].fw_state = MFI_PD_STATE_ONLINE; 411 } 412 array_info->array = ar; 413 } 414 415 /* 416 * Create a volume that spans one or more arrays. 417 */ 418 static void 419 build_volume(char *volumep, int narrays, struct array_info *arrays, 420 int raid_type, long stripe_size, struct config_id_state *state, int verbose) 421 { 422 struct mfi_ld_config *ld = (struct mfi_ld_config *)volumep; 423 struct mfi_array *ar; 424 int i; 425 426 /* properties */ 427 ld->properties.ld.v.target_id = find_next_volume(state); 428 ld->properties.ld.v.seq = 0; 429 ld->properties.default_cache_policy = MR_LD_CACHE_ALLOW_WRITE_CACHE | 430 MR_LD_CACHE_WRITE_BACK; 431 ld->properties.access_policy = MFI_LD_ACCESS_RW; 432 ld->properties.disk_cache_policy = MR_PD_CACHE_UNCHANGED; 433 ld->properties.current_cache_policy = MR_LD_CACHE_ALLOW_WRITE_CACHE | 434 MR_LD_CACHE_WRITE_BACK; 435 ld->properties.no_bgi = 0; 436 437 /* params */ 438 switch (raid_type) { 439 case RT_RAID0: 440 case RT_JBOD: 441 ld->params.primary_raid_level = DDF_RAID0; 442 ld->params.raid_level_qualifier = 0; 443 ld->params.secondary_raid_level = 0; 444 break; 445 case RT_RAID1: 446 ld->params.primary_raid_level = DDF_RAID1; 447 ld->params.raid_level_qualifier = 0; 448 ld->params.secondary_raid_level = 0; 449 break; 450 case RT_RAID5: 451 ld->params.primary_raid_level = DDF_RAID5; 452 ld->params.raid_level_qualifier = 3; 453 ld->params.secondary_raid_level = 0; 454 break; 455 case RT_RAID6: 456 ld->params.primary_raid_level = DDF_RAID6; 457 ld->params.raid_level_qualifier = 3; 458 ld->params.secondary_raid_level = 0; 459 break; 460 case RT_CONCAT: 461 ld->params.primary_raid_level = DDF_CONCAT; 462 ld->params.raid_level_qualifier = 0; 463 ld->params.secondary_raid_level = 0; 464 break; 465 case RT_RAID10: 466 ld->params.primary_raid_level = DDF_RAID1; 467 ld->params.raid_level_qualifier = 0; 468 ld->params.secondary_raid_level = 3; /* XXX? */ 469 break; 470 case RT_RAID50: 471 /* 472 * XXX: This appears to work though the card's BIOS 473 * complains that the configuration is foreign. The 474 * BIOS setup does not allow for creation of RAID-50 475 * or RAID-60 arrays. The only nested array 476 * configuration it allows for is RAID-10. 477 */ 478 ld->params.primary_raid_level = DDF_RAID5; 479 ld->params.raid_level_qualifier = 3; 480 ld->params.secondary_raid_level = 3; /* XXX? */ 481 break; 482 case RT_RAID60: 483 ld->params.primary_raid_level = DDF_RAID6; 484 ld->params.raid_level_qualifier = 3; 485 ld->params.secondary_raid_level = 3; /* XXX? */ 486 break; 487 } 488 489 /* 490 * Stripe size is encoded as (2 ^ N) * 512 = stripe_size. Use 491 * ffs() to simulate log2(stripe_size). 492 */ 493 ld->params.stripe_size = ffs(stripe_size) - 1 - 9; 494 ld->params.num_drives = arrays[0].array->num_drives; 495 ld->params.span_depth = narrays; 496 ld->params.state = MFI_LD_STATE_OPTIMAL; 497 ld->params.init_state = MFI_LD_PARAMS_INIT_NO; 498 ld->params.is_consistent = 0; 499 500 /* spans */ 501 for (i = 0; i < narrays; i++) { 502 ar = arrays[i].array; 503 if (verbose) 504 printf("Adding array %u to volume %u\n", ar->array_ref, 505 ld->properties.ld.v.target_id); 506 ld->span[i].start_block = 0; 507 ld->span[i].num_blocks = ar->size; 508 ld->span[i].array_ref = ar->array_ref; 509 } 510 } 511 512 static int 513 create_volume(int ac, char **av) 514 { 515 struct mfi_config_data *config; 516 struct mfi_array *ar; 517 struct mfi_ld_config *ld; 518 struct config_id_state state; 519 size_t config_size; 520 char *p, *cfg_arrays, *cfg_volumes; 521 int error, fd, i, raid_type; 522 int narrays, nvolumes, arrays_per_volume; 523 struct array_info *arrays; 524 long stripe_size; 525 #ifdef DEBUG 526 int dump; 527 #endif 528 int ch, verbose; 529 530 /* 531 * Backwards compat. Map 'create volume' to 'create' and 532 * 'create spare' to 'add'. 533 */ 534 if (ac > 1) { 535 if (strcmp(av[1], "volume") == 0) { 536 av++; 537 ac--; 538 } else if (strcmp(av[1], "spare") == 0) { 539 av++; 540 ac--; 541 return (add_spare(ac, av)); 542 } 543 } 544 545 if (ac < 2) { 546 warnx("create volume: volume type required"); 547 return (EINVAL); 548 } 549 550 551 fd = mfi_open(mfi_unit); 552 if (fd < 0) { 553 error = errno; 554 warn("mfi_open"); 555 return (error); 556 } 557 558 if (!mfi_reconfig_supported()) { 559 warnx("The current mfi(4) driver does not support " 560 "configuration changes."); 561 return (EOPNOTSUPP); 562 } 563 564 /* Lookup the RAID type first. */ 565 raid_type = -1; 566 for (i = 0; raid_type_table[i].name != NULL; i++) 567 if (strcasecmp(raid_type_table[i].name, av[1]) == 0) { 568 raid_type = raid_type_table[i].raid_type; 569 break; 570 } 571 572 if (raid_type == -1) { 573 warnx("Unknown or unsupported volume type %s", av[1]); 574 return (EINVAL); 575 } 576 577 /* Parse any options. */ 578 optind = 2; 579 #ifdef DEBUG 580 dump = 0; 581 #endif 582 verbose = 0; 583 stripe_size = 64 * 1024; 584 585 while ((ch = getopt(ac, av, "ds:v")) != -1) { 586 switch (ch) { 587 #ifdef DEBUG 588 case 'd': 589 dump = 1; 590 break; 591 #endif 592 case 's': 593 stripe_size = dehumanize(optarg); 594 if ((stripe_size < 512) || (!powerof2(stripe_size))) 595 stripe_size = 64 * 1024; 596 break; 597 case 'v': 598 verbose = 1; 599 break; 600 case '?': 601 default: 602 return (EINVAL); 603 } 604 } 605 ac -= optind; 606 av += optind; 607 608 /* Parse all the arrays. */ 609 narrays = ac; 610 if (narrays == 0) { 611 warnx("At least one drive list is required"); 612 return (EINVAL); 613 } 614 switch (raid_type) { 615 case RT_RAID0: 616 case RT_RAID1: 617 case RT_RAID5: 618 case RT_RAID6: 619 case RT_CONCAT: 620 if (narrays != 1) { 621 warnx("Only one drive list can be specified"); 622 return (EINVAL); 623 } 624 break; 625 case RT_RAID10: 626 case RT_RAID50: 627 case RT_RAID60: 628 if (narrays < 1) { 629 warnx("RAID10, RAID50, and RAID60 require at least " 630 "two drive lists"); 631 return (EINVAL); 632 } 633 if (narrays > MFI_MAX_SPAN_DEPTH) { 634 warnx("Volume spans more than %d arrays", 635 MFI_MAX_SPAN_DEPTH); 636 return (EINVAL); 637 } 638 break; 639 } 640 arrays = calloc(narrays, sizeof(*arrays)); 641 for (i = 0; i < narrays; i++) { 642 error = parse_array(fd, raid_type, av[i], &arrays[i]); 643 if (error) 644 return (error); 645 } 646 647 switch (raid_type) { 648 case RT_RAID10: 649 case RT_RAID50: 650 case RT_RAID60: 651 for (i = 1; i < narrays; i++) { 652 if (arrays[i].drive_count != arrays[0].drive_count) { 653 warnx("All arrays must contain the same " 654 "number of drives"); 655 return (EINVAL); 656 } 657 } 658 break; 659 } 660 661 /* 662 * Fetch the current config and build sorted lists of existing 663 * array and volume identifiers. 664 */ 665 if (mfi_config_read(fd, &config) < 0) { 666 error = errno; 667 warn("Failed to read configuration"); 668 return (error); 669 } 670 p = (char *)config->array; 671 state.array_ref = 0xffff; 672 state.target_id = 0xff; 673 state.array_count = config->array_count; 674 if (config->array_count > 0) { 675 state.arrays = calloc(config->array_count, sizeof(int)); 676 for (i = 0; i < config->array_count; i++) { 677 ar = (struct mfi_array *)p; 678 state.arrays[i] = ar->array_ref; 679 p += config->array_size; 680 } 681 qsort(state.arrays, config->array_count, sizeof(int), 682 compare_int); 683 } else 684 state.arrays = NULL; 685 state.log_drv_count = config->log_drv_count; 686 if (config->log_drv_count) { 687 state.volumes = calloc(config->log_drv_count, sizeof(int)); 688 for (i = 0; i < config->log_drv_count; i++) { 689 ld = (struct mfi_ld_config *)p; 690 state.volumes[i] = ld->properties.ld.v.target_id; 691 p += config->log_drv_size; 692 } 693 qsort(state.volumes, config->log_drv_count, sizeof(int), 694 compare_int); 695 } else 696 state.volumes = NULL; 697 free(config); 698 699 /* Determine the size of the configuration we will build. */ 700 switch (raid_type) { 701 case RT_RAID0: 702 case RT_RAID1: 703 case RT_RAID5: 704 case RT_RAID6: 705 case RT_CONCAT: 706 case RT_JBOD: 707 /* Each volume spans a single array. */ 708 nvolumes = narrays; 709 break; 710 case RT_RAID10: 711 case RT_RAID50: 712 case RT_RAID60: 713 /* A single volume spans multiple arrays. */ 714 nvolumes = 1; 715 break; 716 default: 717 /* Pacify gcc. */ 718 abort(); 719 } 720 721 config_size = sizeof(struct mfi_config_data) + 722 sizeof(struct mfi_ld_config) * nvolumes + MFI_ARRAY_SIZE * narrays; 723 config = calloc(1, config_size); 724 config->size = config_size; 725 config->array_count = narrays; 726 config->array_size = MFI_ARRAY_SIZE; /* XXX: Firmware hardcode */ 727 config->log_drv_count = nvolumes; 728 config->log_drv_size = sizeof(struct mfi_ld_config); 729 config->spares_count = 0; 730 config->spares_size = 40; /* XXX: Firmware hardcode */ 731 cfg_arrays = (char *)config->array; 732 cfg_volumes = cfg_arrays + config->array_size * narrays; 733 734 /* Build the arrays. */ 735 for (i = 0; i < narrays; i++) { 736 build_array(fd, cfg_arrays, &arrays[i], &state, verbose); 737 cfg_arrays += config->array_size; 738 } 739 740 /* Now build the volume(s). */ 741 arrays_per_volume = narrays / nvolumes; 742 for (i = 0; i < nvolumes; i++) { 743 build_volume(cfg_volumes, arrays_per_volume, 744 &arrays[i * arrays_per_volume], raid_type, stripe_size, 745 &state, verbose); 746 cfg_volumes += config->log_drv_size; 747 } 748 749 #ifdef DEBUG 750 if (dump) 751 dump_config(fd, config); 752 #endif 753 754 /* Send the new config to the controller. */ 755 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_ADD, config, config_size, 756 NULL, 0, NULL) < 0) { 757 error = errno; 758 warn("Failed to add volume"); 759 return (error); 760 } 761 762 /* Clean up. */ 763 free(config); 764 if (state.log_drv_count > 0) 765 free(state.volumes); 766 if (state.array_count > 0) 767 free(state.arrays); 768 for (i = 0; i < narrays; i++) 769 free(arrays[i].drives); 770 free(arrays); 771 close(fd); 772 773 return (0); 774 } 775 MFI_COMMAND(top, create, create_volume); 776 777 static int 778 delete_volume(int ac, char **av) 779 { 780 struct mfi_ld_info info; 781 int error, fd; 782 uint8_t target_id, mbox[4]; 783 784 /* 785 * Backwards compat. Map 'delete volume' to 'delete' and 786 * 'delete spare' to 'remove'. 787 */ 788 if (ac > 1) { 789 if (strcmp(av[1], "volume") == 0) { 790 av++; 791 ac--; 792 } else if (strcmp(av[1], "spare") == 0) { 793 av++; 794 ac--; 795 return (remove_spare(ac, av)); 796 } 797 } 798 799 if (ac != 2) { 800 warnx("delete volume: volume required"); 801 return (EINVAL); 802 } 803 804 fd = mfi_open(mfi_unit); 805 if (fd < 0) { 806 error = errno; 807 warn("mfi_open"); 808 return (error); 809 } 810 811 if (!mfi_reconfig_supported()) { 812 warnx("The current mfi(4) driver does not support " 813 "configuration changes."); 814 return (EOPNOTSUPP); 815 } 816 817 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) { 818 error = errno; 819 warn("Invalid volume %s", av[1]); 820 return (error); 821 } 822 823 if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) { 824 error = errno; 825 warn("Failed to get info for volume %d", target_id); 826 return (error); 827 } 828 829 if (mfi_volume_busy(fd, target_id)) { 830 warnx("Volume %s is busy and cannot be deleted", 831 mfi_volume_name(fd, target_id)); 832 return (EBUSY); 833 } 834 835 mbox_store_ldref(mbox, &info.ld_config.properties.ld); 836 if (mfi_dcmd_command(fd, MFI_DCMD_LD_DELETE, NULL, 0, mbox, 837 sizeof(mbox), NULL) < 0) { 838 error = errno; 839 warn("Failed to delete volume"); 840 return (error); 841 } 842 843 close(fd); 844 845 return (0); 846 } 847 MFI_COMMAND(top, delete, delete_volume); 848 849 static int 850 add_spare(int ac, char **av) 851 { 852 struct mfi_pd_info info; 853 struct mfi_config_data *config; 854 struct mfi_array *ar; 855 struct mfi_ld_config *ld; 856 struct mfi_spare *spare; 857 uint16_t device_id; 858 uint8_t target_id; 859 char *p; 860 int error, fd, i; 861 862 if (ac < 2) { 863 warnx("add spare: drive required"); 864 return (EINVAL); 865 } 866 867 fd = mfi_open(mfi_unit); 868 if (fd < 0) { 869 error = errno; 870 warn("mfi_open"); 871 return (error); 872 } 873 874 error = mfi_lookup_drive(fd, av[1], &device_id); 875 if (error) 876 return (error); 877 878 if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) { 879 error = errno; 880 warn("Failed to fetch drive info"); 881 return (error); 882 } 883 884 if (info.fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) { 885 warnx("Drive %u is not available", device_id); 886 return (EINVAL); 887 } 888 889 if (ac > 2) { 890 if (mfi_lookup_volume(fd, av[2], &target_id) < 0) { 891 error = errno; 892 warn("Invalid volume %s", av[2]); 893 return (error); 894 } 895 } 896 897 if (mfi_config_read(fd, &config) < 0) { 898 error = errno; 899 warn("Failed to read configuration"); 900 return (error); 901 } 902 903 spare = malloc(sizeof(struct mfi_spare) + sizeof(uint16_t) * 904 config->array_count); 905 bzero(spare, sizeof(struct mfi_spare)); 906 spare->ref = info.ref; 907 908 if (ac == 2) { 909 /* Global spare backs all arrays. */ 910 p = (char *)config->array; 911 for (i = 0; i < config->array_count; i++) { 912 ar = (struct mfi_array *)p; 913 if (ar->size > info.coerced_size) { 914 warnx("Spare isn't large enough for array %u", 915 ar->array_ref); 916 return (EINVAL); 917 } 918 p += config->array_size; 919 } 920 spare->array_count = 0; 921 } else { 922 /* 923 * Dedicated spares only back the arrays for a 924 * specific volume. 925 */ 926 ld = mfi_config_lookup_volume(config, target_id); 927 if (ld == NULL) { 928 warnx("Did not find volume %d", target_id); 929 return (EINVAL); 930 } 931 932 spare->spare_type |= MFI_SPARE_DEDICATED; 933 spare->array_count = ld->params.span_depth; 934 for (i = 0; i < ld->params.span_depth; i++) { 935 ar = mfi_config_lookup_array(config, 936 ld->span[i].array_ref); 937 if (ar == NULL) { 938 warnx("Missing array; inconsistent config?"); 939 return (ENXIO); 940 } 941 if (ar->size > info.coerced_size) { 942 warnx("Spare isn't large enough for array %u", 943 ar->array_ref); 944 return (EINVAL); 945 } 946 spare->array_ref[i] = ar->array_ref; 947 } 948 } 949 free(config); 950 951 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_MAKE_SPARE, spare, 952 sizeof(struct mfi_spare) + sizeof(uint16_t) * spare->array_count, 953 NULL, 0, NULL) < 0) { 954 error = errno; 955 warn("Failed to assign spare"); 956 return (error); 957 } 958 959 close(fd); 960 961 return (0); 962 } 963 MFI_COMMAND(top, add, add_spare); 964 965 static int 966 remove_spare(int ac, char **av) 967 { 968 struct mfi_pd_info info; 969 int error, fd; 970 uint16_t device_id; 971 uint8_t mbox[4]; 972 973 if (ac != 2) { 974 warnx("remove spare: drive required"); 975 return (EINVAL); 976 } 977 978 fd = mfi_open(mfi_unit); 979 if (fd < 0) { 980 error = errno; 981 warn("mfi_open"); 982 return (error); 983 } 984 985 error = mfi_lookup_drive(fd, av[1], &device_id); 986 if (error) 987 return (error); 988 989 /* Get the info for this drive. */ 990 if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) { 991 error = errno; 992 warn("Failed to fetch info for drive %u", device_id); 993 return (error); 994 } 995 996 if (info.fw_state != MFI_PD_STATE_HOT_SPARE) { 997 warnx("Drive %u is not a hot spare", device_id); 998 return (EINVAL); 999 } 1000 1001 mbox_store_pdref(mbox, &info.ref); 1002 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_REMOVE_SPARE, NULL, 0, mbox, 1003 sizeof(mbox), NULL) < 0) { 1004 error = errno; 1005 warn("Failed to delete spare"); 1006 return (error); 1007 } 1008 1009 close(fd); 1010 1011 return (0); 1012 } 1013 MFI_COMMAND(top, remove, remove_spare); 1014 1015 #ifdef DEBUG 1016 /* Display raw data about a config. */ 1017 static void 1018 dump_config(int fd, struct mfi_config_data *config) 1019 { 1020 struct mfi_array *ar; 1021 struct mfi_ld_config *ld; 1022 struct mfi_spare *sp; 1023 struct mfi_pd_info pinfo; 1024 uint16_t device_id; 1025 char *p; 1026 int i, j; 1027 1028 printf( 1029 "mfi%d Configuration (Debug): %d arrays, %d volumes, %d spares\n", 1030 mfi_unit, config->array_count, config->log_drv_count, 1031 config->spares_count); 1032 printf(" array size: %u\n", config->array_size); 1033 printf(" volume size: %u\n", config->log_drv_size); 1034 printf(" spare size: %u\n", config->spares_size); 1035 p = (char *)config->array; 1036 1037 for (i = 0; i < config->array_count; i++) { 1038 ar = (struct mfi_array *)p; 1039 printf(" array %u of %u drives:\n", ar->array_ref, 1040 ar->num_drives); 1041 printf(" size = %ju\n", (uintmax_t)ar->size); 1042 for (j = 0; j < ar->num_drives; j++) { 1043 device_id = ar->pd[j].ref.v.device_id; 1044 if (device_id == 0xffff) 1045 printf(" drive MISSING\n"); 1046 else { 1047 printf(" drive %u %s\n", device_id, 1048 mfi_pdstate(ar->pd[j].fw_state)); 1049 if (mfi_pd_get_info(fd, device_id, &pinfo, 1050 NULL) >= 0) { 1051 printf(" raw size: %ju\n", 1052 (uintmax_t)pinfo.raw_size); 1053 printf(" non-coerced size: %ju\n", 1054 (uintmax_t)pinfo.non_coerced_size); 1055 printf(" coerced size: %ju\n", 1056 (uintmax_t)pinfo.coerced_size); 1057 } 1058 } 1059 } 1060 p += config->array_size; 1061 } 1062 1063 for (i = 0; i < config->log_drv_count; i++) { 1064 ld = (struct mfi_ld_config *)p; 1065 printf(" volume %s ", 1066 mfi_volume_name(fd, ld->properties.ld.v.target_id)); 1067 printf("%s %s", 1068 mfi_raid_level(ld->params.primary_raid_level, 1069 ld->params.secondary_raid_level), 1070 mfi_ldstate(ld->params.state)); 1071 if (ld->properties.name[0] != '\0') 1072 printf(" <%s>", ld->properties.name); 1073 printf("\n"); 1074 printf(" primary raid level: %u\n", 1075 ld->params.primary_raid_level); 1076 printf(" raid level qualifier: %u\n", 1077 ld->params.raid_level_qualifier); 1078 printf(" secondary raid level: %u\n", 1079 ld->params.secondary_raid_level); 1080 printf(" stripe size: %u\n", ld->params.stripe_size); 1081 printf(" num drives: %u\n", ld->params.num_drives); 1082 printf(" init state: %u\n", ld->params.init_state); 1083 printf(" consistent: %u\n", ld->params.is_consistent); 1084 printf(" no bgi: %u\n", ld->properties.no_bgi); 1085 printf(" spans:\n"); 1086 for (j = 0; j < ld->params.span_depth; j++) { 1087 printf(" array %u @ ", ld->span[j].array_ref); 1088 printf("%ju : %ju\n", 1089 (uintmax_t)ld->span[j].start_block, 1090 (uintmax_t)ld->span[j].num_blocks); 1091 } 1092 p += config->log_drv_size; 1093 } 1094 1095 for (i = 0; i < config->spares_count; i++) { 1096 sp = (struct mfi_spare *)p; 1097 printf(" %s spare %u ", 1098 sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" : 1099 "global", sp->ref.v.device_id); 1100 printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE)); 1101 printf(" backs:\n"); 1102 for (j = 0; j < sp->array_count; j++) 1103 printf(" array %u\n", sp->array_ref[j]); 1104 p += config->spares_size; 1105 } 1106 } 1107 1108 static int 1109 debug_config(int ac, char **av) 1110 { 1111 struct mfi_config_data *config; 1112 int error, fd; 1113 1114 if (ac != 1) { 1115 warnx("debug: extra arguments"); 1116 return (EINVAL); 1117 } 1118 1119 fd = mfi_open(mfi_unit); 1120 if (fd < 0) { 1121 error = errno; 1122 warn("mfi_open"); 1123 return (error); 1124 } 1125 1126 /* Get the config from the controller. */ 1127 if (mfi_config_read(fd, &config) < 0) { 1128 error = errno; 1129 warn("Failed to get config"); 1130 return (error); 1131 } 1132 1133 /* Dump out the configuration. */ 1134 dump_config(fd, config); 1135 free(config); 1136 close(fd); 1137 1138 return (0); 1139 } 1140 MFI_COMMAND(top, debug, debug_config); 1141 1142 static int 1143 dump(int ac, char **av) 1144 { 1145 struct mfi_config_data *config; 1146 char buf[64]; 1147 size_t len; 1148 int error, fd; 1149 1150 if (ac != 1) { 1151 warnx("dump: extra arguments"); 1152 return (EINVAL); 1153 } 1154 1155 fd = mfi_open(mfi_unit); 1156 if (fd < 0) { 1157 error = errno; 1158 warn("mfi_open"); 1159 return (error); 1160 } 1161 1162 /* Get the stashed copy of the last dcmd from the driver. */ 1163 snprintf(buf, sizeof(buf), "dev.mfi.%d.debug_command", mfi_unit); 1164 if (sysctlbyname(buf, NULL, &len, NULL, 0) < 0) { 1165 error = errno; 1166 warn("Failed to read debug command"); 1167 if (error == ENOENT) 1168 error = EOPNOTSUPP; 1169 return (error); 1170 } 1171 1172 config = malloc(len); 1173 if (sysctlbyname(buf, config, &len, NULL, 0) < 0) { 1174 error = errno; 1175 warn("Failed to read debug command"); 1176 return (error); 1177 } 1178 dump_config(fd, config); 1179 free(config); 1180 close(fd); 1181 1182 return (0); 1183 } 1184 MFI_COMMAND(top, dump, dump); 1185 #endif 1186