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