1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "volume_devconfig.h" 30 31 #include <string.h> 32 #include <ctype.h> 33 #include <meta.h> 34 #include "volume_nvpair.h" 35 #include "volume_error.h" 36 #include "volume_output.h" 37 #include "volume_string.h" 38 39 /* 40 * Methods which manipulate a devconfig_t struct 41 */ 42 43 /* 44 * Constructor: Create a devconfig_t struct. This devconfig_t must be 45 * freed with free_devconfig(). 46 * 47 * @param devconfig 48 * RETURN: a new devconfig_t 49 * 50 * @param type 51 * the type of devconfig_t to create 52 * 53 * @return 0 54 * if successful 55 * 56 * @return non-zero 57 * if an error occurred. Use get_error_string() to 58 * retrieve the associated error message. 59 */ 60 int 61 new_devconfig( 62 devconfig_t **devconfig, 63 component_type_t type) 64 { 65 int error; 66 67 *devconfig = (devconfig_t *)calloc(1, sizeof (devconfig_t)); 68 if (*devconfig == NULL) { 69 volume_set_error(gettext("new_devconfig() calloc() failed\n")); 70 return (-1); 71 } 72 73 /* Create attribute list */ 74 if ((error = nvlist_alloc(&((*devconfig)->attributes), 75 NV_UNIQUE_NAME_TYPE, 0)) != 0) { 76 volume_set_error(gettext("devconfig_t nvlist_alloc() failed\n")); 77 free_devconfig(*devconfig); 78 return (error); 79 } 80 81 if ((error = devconfig_set_type(*devconfig, type)) != 0) { 82 free_devconfig(*devconfig); 83 return (error); 84 } 85 86 return (0); 87 } 88 89 /* 90 * Free memory (recursively) allocated to a devconfig_t struct 91 * 92 * @param arg 93 * pointer to the devconfig_t to be freed 94 */ 95 void 96 free_devconfig( 97 void *arg) 98 { 99 devconfig_t *devconfig = (devconfig_t *)arg; 100 101 if (devconfig == NULL) { 102 return; 103 } 104 105 /* Free the attributes nvlist */ 106 if (devconfig->attributes != NULL) { 107 nvlist_free(devconfig->attributes); 108 } 109 110 /* Free available devices */ 111 if (devconfig->available != NULL) { 112 free_string_array(devconfig->available); 113 } 114 115 /* Free unavailable devices */ 116 if (devconfig->unavailable != NULL) { 117 free_string_array(devconfig->unavailable); 118 } 119 120 /* Free the components */ 121 if (devconfig->components != NULL) { 122 dlist_free_items(devconfig->components, free_devconfig); 123 } 124 125 /* Free the devconfig itself */ 126 free(devconfig); 127 } 128 129 /* 130 * Check the type of the given device. 131 * 132 * @param device 133 * the device whose type to check 134 * 135 * @param type 136 * the type of the device against which to compare 137 * 138 * @return B_TRUE if the device is of the given type, B_FALSE 139 * otherwise 140 */ 141 boolean_t 142 devconfig_isA( 143 devconfig_t *device, 144 component_type_t type) 145 { 146 component_type_t curtype; 147 148 if (device == NULL) { 149 return (B_FALSE); 150 } 151 152 if (devconfig_get_type(device, &curtype) != 0) { 153 return (B_FALSE); 154 } 155 156 if (curtype != type) { 157 return (B_FALSE); 158 } 159 160 return (B_TRUE); 161 } 162 163 /* 164 * Get the first component of the given type from the given 165 * devconfig_t. Create the component if create is B_TRUE. 166 * 167 * @return ENOENT 168 * if the requested component does not exist and its 169 * creation was not requested 170 * 171 * @return 0 172 * if the requested component exists or was created 173 * 174 * @return non-zero 175 * if the requested component did not exist and could not 176 * be created 177 */ 178 int 179 devconfig_get_component( 180 devconfig_t *device, 181 component_type_t type, 182 devconfig_t **component, 183 boolean_t create) 184 { 185 dlist_t *list; 186 int error = 0; 187 char *typestr = devconfig_type_to_str(type); 188 189 oprintf(OUTPUT_DEBUG, gettext("Searching for singleton %s\n"), typestr); 190 191 /* For each component of this device... */ 192 for (list = devconfig_get_components(device); 193 list != NULL; list = list->next) { 194 195 *component = (devconfig_t *)list->obj; 196 197 /* Is this subcomponent an instance of the given type? */ 198 if (*component != NULL && devconfig_isA(*component, type)) { 199 oprintf(OUTPUT_DEBUG, gettext("Found %s\n"), typestr); 200 return (0); 201 } 202 } 203 204 /* No component found */ 205 error = ENOENT; 206 *component = NULL; 207 208 oprintf(OUTPUT_DEBUG, gettext("%s not found\n"), typestr); 209 210 if (create == B_TRUE) { 211 oprintf(OUTPUT_DEBUG, gettext("Creating %s\n"), typestr); 212 213 /* 214 * An existing singleton component of the given type was 215 * not found under the given disk set. So, create one. 216 */ 217 if ((error = new_devconfig(component, type)) == 0) { 218 /* Attach new component to given device */ 219 devconfig_set_components( 220 device, dlist_append(dlist_new_item(*component), 221 devconfig_get_components(device), AT_TAIL)); 222 } 223 } 224 225 return (error); 226 } 227 228 /* 229 * Set the available devices for use in creating this device 230 * 231 * @param device 232 * a devconfig_t representing the device to modify 233 * 234 * @param available 235 * A NULL-terminated array of device names 236 */ 237 void 238 devconfig_set_available( 239 devconfig_t *device, 240 char **available) 241 { 242 device->available = available; 243 } 244 245 /* 246 * Get the available devices for use in creating this device 247 * 248 * @param device 249 * a devconfig_t representing the device to examine 250 * 251 * @return available 252 * A NULL-terminated array of device names 253 */ 254 char ** 255 devconfig_get_available( 256 devconfig_t *device) 257 { 258 return (device->available); 259 } 260 261 /* 262 * Set the unavailable devices which may not be used in creating this 263 * device 264 * 265 * @param device 266 * a devconfig_t representing the device to modify 267 * 268 * @param available 269 * A NULL-terminated array of device names 270 */ 271 void 272 devconfig_set_unavailable( 273 devconfig_t *device, 274 char **unavailable) 275 { 276 device->unavailable = unavailable; 277 } 278 279 /* 280 * Get the unavailable devices for use in creating this device 281 * 282 * @param device 283 * a devconfig_t representing the device to examine 284 * 285 * @return unavailable 286 * A NULL-terminated array of device names 287 */ 288 char ** 289 devconfig_get_unavailable( 290 devconfig_t *device) 291 { 292 return (device->unavailable); 293 } 294 295 /* 296 * Set the subcomponent devices of a given device 297 * 298 * @param device 299 * a devconfig_t representing the device to examine 300 * 301 * @param components 302 * A dlist_t containing devconfig_t devices 303 */ 304 void 305 devconfig_set_components( 306 devconfig_t *device, 307 dlist_t *components) 308 { 309 device->components = components; 310 } 311 312 /* 313 * Get the subcomponent devices of a given device 314 * 315 * @param device 316 * a devconfig_t representing the device to examine 317 * 318 * @return A dlist_t containing devconfig_t devices 319 */ 320 dlist_t * 321 devconfig_get_components( 322 devconfig_t *device) 323 { 324 return (device->components); 325 } 326 327 /* 328 * Set the device name 329 * 330 * @param device 331 * a devconfig_t representing the device to modify 332 * 333 * @param name 334 * the value to set as the device name 335 * 336 * @return 0 337 * if successful 338 * 339 * @return non-zero 340 * if an error occurred. Use get_error_string() to 341 * retrieve the associated error message. 342 */ 343 int 344 devconfig_set_name( 345 devconfig_t *device, 346 char *name) 347 { 348 return (set_string(device->attributes, ATTR_NAME, name)); 349 } 350 351 /* 352 * Set the disk set name 353 * 354 * @param diskset 355 * a devconfig_t representing the diskset to modify 356 * 357 * @param name 358 * the value to set as the device name 359 * 360 * @return 0 361 * if successful 362 * 363 * @return non-zero 364 * if an error occurred. Use get_error_string() to 365 * retrieve the associated error message. 366 */ 367 int 368 devconfig_set_diskset_name( 369 devconfig_t *diskset, 370 char *name) 371 { 372 md_error_t error = mdnullerror; 373 374 /* Verify syntax of disk set name */ 375 if (meta_set_checkname(name, &error)) { 376 volume_set_error(gettext("invalid disk set name: %s"), name); 377 return (-1); 378 } 379 380 return (devconfig_set_name(diskset, name)); 381 } 382 383 /* 384 * Set the device name 385 * 386 * @param hsp 387 * a devconfig_t representing the hsp to modify 388 * 389 * @param name 390 * the value to set as the device name 391 * 392 * @return 0 393 * if successful 394 * 395 * @return non-zero 396 * if an error occurred. Use get_error_string() to 397 * retrieve the associated error message. 398 */ 399 int 400 devconfig_set_hsp_name( 401 devconfig_t *hsp, 402 char *name) 403 { 404 /* Validate name */ 405 if (!is_hspname(name)) { 406 volume_set_error(gettext("invalid hot spare pool name: %s"), name); 407 return (-1); 408 } 409 410 return (devconfig_set_name(hsp, name)); 411 } 412 413 /* 414 * Set the device name 415 * 416 * @param volume 417 * a devconfig_t representing the volume to modify 418 * 419 * @param name 420 * the value to set as the device name 421 * 422 * @return 0 423 * if successful 424 * 425 * @return non-zero 426 * if an error occurred. Use get_error_string() to 427 * retrieve the associated error message. 428 */ 429 int 430 devconfig_set_volume_name( 431 devconfig_t *volume, 432 char *name) 433 { 434 /* Validate name */ 435 if (!is_metaname(name)) { 436 volume_set_error(gettext("invalid volume name: %s"), name); 437 return (-1); 438 } 439 440 return (devconfig_set_name(volume, name)); 441 } 442 443 /* 444 * Get the device name 445 * 446 * @param volume 447 * a devconfig_t representing the volume to examine 448 * 449 * @param name 450 * RETURN: the device name 451 * 452 * @return 0 453 * if successful 454 * 455 * @return non-zero 456 * if an error occurred. Use get_error_string() to 457 * retrieve the associated error message. 458 */ 459 int 460 devconfig_get_name( 461 devconfig_t *device, 462 char **name) 463 { 464 int error = get_string(device->attributes, ATTR_NAME, name); 465 466 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 467 if (error == ENOENT) { 468 volume_set_error(gettext("device name not set")); 469 error = ERR_ATTR_UNSET; 470 } 471 472 return (error); 473 } 474 475 /* 476 * Set the device type 477 * 478 * @param device 479 * a devconfig_t representing the device to modify 480 * 481 * @param type 482 * the value to set as the device type 483 * 484 * @return 0 485 * if successful 486 * 487 * @return non-zero 488 * if an error occurred. Use get_error_string() to 489 * retrieve the associated error message. 490 */ 491 int 492 devconfig_set_type( 493 devconfig_t *device, 494 component_type_t type) 495 { 496 return (set_uint16(device->attributes, ATTR_TYPE, (uint16_t)type)); 497 } 498 499 /* 500 * Get the device type 501 * 502 * @param device 503 * a devconfig_t representing the device to examine 504 * 505 * @param type 506 * RETURN: the device type 507 * 508 * @return 0 509 * if successful 510 * 511 * @return non-zero 512 * if an error occurred. Use get_error_string() to 513 * retrieve the associated error message. 514 */ 515 int 516 devconfig_get_type( 517 devconfig_t *device, 518 component_type_t *type) 519 { 520 uint16_t val; 521 int error = get_uint16(device->attributes, ATTR_TYPE, &val); 522 523 switch (error) { 524 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 525 case ENOENT: 526 volume_set_error(gettext("device type not set")); 527 error = ERR_ATTR_UNSET; 528 break; 529 530 /* Success */ 531 case 0: 532 *type = (component_type_t)val; 533 } 534 535 return (error); 536 } 537 538 /* 539 * Set the device size (for volume, mirror, stripe, concat) in bytes 540 * 541 * Note that size in bytes in a 64-bit field cannot hold the size that 542 * can be accessed in a 16 byte CDB. Since CDBs operate on blocks, 543 * the max capacity is 2^73 bytes with 512 byte blocks. 544 * 545 * @param device 546 * a devconfig_t representing the device to modify 547 * 548 * @param size_in_bytes 549 * the value to set as the device size in bytes 550 * 551 * @return 0 552 * if successful 553 * 554 * @return non-zero 555 * if an error occurred. Use get_error_string() to 556 * retrieve the associated error message. 557 */ 558 int 559 devconfig_set_size( 560 devconfig_t *device, 561 uint64_t size_in_bytes) 562 { 563 564 /* Validate against limits */ 565 /* LINTED -- MIN_SIZE may be 0 */ 566 if (size_in_bytes < MIN_SIZE) { 567 volume_set_error(gettext("size (in bytes) too small: %llu"), 568 (unsigned long long)size_in_bytes); 569 return (-1); 570 } 571 572 return (set_uint64(device->attributes, 573 ATTR_SIZEINBYTES, size_in_bytes)); 574 } 575 576 /* 577 * Get the device size (for volume, mirror, stripe, concat) in bytes 578 * 579 * Note that size in bytes in a 64-bit field cannot hold the size that 580 * can be accessed in a 16 byte CDB. Since CDBs operate on blocks, 581 * the max capacity is 2^73 bytes with 512 byte blocks. 582 * 583 * @param device 584 * a devconfig_t representing the device to examine 585 * 586 * @param size_in_bytes 587 * RETURN: the device size in bytes 588 * 589 * @return 0 590 * if successful 591 * 592 * @return non-zero 593 * if an error occurred. Use get_error_string() to 594 * retrieve the associated error message. 595 */ 596 int 597 devconfig_get_size( 598 devconfig_t *device, 599 uint64_t *size_in_bytes) 600 { 601 int error = get_uint64( 602 device->attributes, ATTR_SIZEINBYTES, size_in_bytes); 603 604 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 605 if (error == ENOENT) { 606 volume_set_error(gettext("size (in bytes) not set")); 607 error = ERR_ATTR_UNSET; 608 } 609 610 return (error); 611 } 612 613 /* 614 * Set the device size in blocks 615 * 616 * @param device 617 * a devconfig_t representing the device to modify 618 * 619 * @param type 620 * the value to set as the device size in blocks 621 * 622 * @return 0 623 * if successful 624 * 625 * @return non-zero 626 * if an error occurred. Use get_error_string() to 627 * retrieve the associated error message. 628 */ 629 int 630 devconfig_set_size_in_blocks( 631 devconfig_t *device, 632 uint64_t size_in_blocks) 633 { 634 /* Validate against limits */ 635 /* LINTED -- MIN_SIZE_IN_BLOCKS may be 0 */ 636 if (size_in_blocks < MIN_SIZE_IN_BLOCKS) { 637 volume_set_error(gettext("size (in blocks) too small: %llu"), 638 (unsigned long long)size_in_blocks); 639 return (-1); 640 } 641 642 return (set_uint64(device->attributes, 643 ATTR_SIZEINBLOCKS, size_in_blocks)); 644 } 645 646 /* 647 * Get the device size in blocks 648 * 649 * @param device 650 * a devconfig_t representing the device to examine 651 * 652 * @param size_in_blocks 653 * RETURN: the device size in blocks 654 * 655 * @return 0 656 * if successful 657 * 658 * @return non-zero 659 * if an error occurred. Use get_error_string() to 660 * retrieve the associated error message. 661 */ 662 int 663 devconfig_get_size_in_blocks( 664 devconfig_t *device, 665 uint64_t *size_in_blocks) 666 { 667 int error = get_uint64( 668 device->attributes, ATTR_SIZEINBLOCKS, size_in_blocks); 669 670 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 671 if (error == ENOENT) { 672 volume_set_error(gettext("size (in blocks) not set")); 673 error = ERR_ATTR_UNSET; 674 } 675 676 return (error); 677 } 678 679 /* 680 * Set the the slice index 681 * 682 * @param slice 683 * a devconfig_t representing the slice to modify 684 * 685 * @param index 686 * the value to set as the the slice index 687 * 688 * @return 0 689 * if successful 690 * 691 * @return non-zero 692 * if an error occurred. Use get_error_string() to 693 * retrieve the associated error message. 694 */ 695 int 696 devconfig_set_slice_index( 697 devconfig_t *slice, 698 uint16_t index) 699 { 700 return (set_uint16(slice->attributes, ATTR_SLICE_INDEX, index)); 701 } 702 703 /* 704 * Get the slice index 705 * 706 * @param device 707 * a devconfig_t representing the device to examine 708 * 709 * @param index 710 * RETURN: the slice index 711 * 712 * @return 0 713 * if successful 714 * 715 * @return non-zero 716 * if an error occurred. Use get_error_string() to 717 * retrieve the associated error message. 718 */ 719 int 720 devconfig_get_slice_index( 721 devconfig_t *slice, 722 uint16_t *index) 723 { 724 int error = get_uint16(slice->attributes, ATTR_SLICE_INDEX, index); 725 726 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 727 if (error == ENOENT) { 728 volume_set_error(gettext("slice index not set")); 729 error = ERR_ATTR_UNSET; 730 } 731 732 return (error); 733 } 734 735 /* 736 * Set the the slice start block 737 * 738 * @param slice 739 * a devconfig_t representing the slice to modify 740 * 741 * @param start_block 742 * the value to set as the the slice start block 743 * 744 * @return 0 745 * if successful 746 * 747 * @return non-zero 748 * if an error occurred. Use get_error_string() to 749 * retrieve the associated error message. 750 */ 751 int 752 devconfig_set_slice_start_block( 753 devconfig_t *slice, 754 uint64_t start_block) 755 { 756 return (set_uint64(slice->attributes, 757 ATTR_SLICE_STARTSECTOR, start_block)); 758 } 759 760 /* 761 * Get the slice start block 762 * 763 * @param device 764 * a devconfig_t representing the device to examine 765 * 766 * @param start_block 767 * RETURN: the slice start block 768 * 769 * @return 0 770 * if successful 771 * 772 * @return non-zero 773 * if an error occurred. Use get_error_string() to 774 * retrieve the associated error message. 775 */ 776 int 777 devconfig_get_slice_start_block( 778 devconfig_t *slice, 779 uint64_t *start_block) 780 { 781 int error = get_uint64( 782 slice->attributes, ATTR_SLICE_STARTSECTOR, start_block); 783 784 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 785 if (error == ENOENT) { 786 volume_set_error(gettext("slice start block not set")); 787 error = ERR_ATTR_UNSET; 788 } 789 790 return (error); 791 } 792 793 /* 794 * Set the number of subcomponents in mirror 795 * 796 * @param mirror 797 * a devconfig_t representing the mirror to modify 798 * 799 * @param nsubs 800 * the value to set as the number of subcomponents in 801 * mirror 802 * 803 * @return 0 804 * if successful 805 * 806 * @return non-zero 807 * if an error occurred. Use get_error_string() to 808 * retrieve the associated error message. 809 */ 810 int 811 devconfig_set_mirror_nsubs( 812 devconfig_t *mirror, 813 uint16_t nsubs) 814 { 815 /* Validate against limits */ 816 if (nsubs < 1 || nsubs > NMIRROR) { 817 volume_set_error( 818 gettext("number of submirrors (%d) out of valid range (%d-%d)"), 819 nsubs, 1, NMIRROR); 820 return (-1); 821 } 822 823 return (set_uint16(mirror->attributes, ATTR_MIRROR_NSUBMIRRORS, nsubs)); 824 } 825 826 /* 827 * Get number of subcomponents in mirror 828 * 829 * @param device 830 * a devconfig_t representing the device to examine 831 * 832 * @param nsubs 833 * RETURN: number of subcomponents in mirror 834 * 835 * @return 0 836 * if successful 837 * 838 * @return non-zero 839 * if an error occurred. Use get_error_string() to 840 * retrieve the associated error message. 841 */ 842 int 843 devconfig_get_mirror_nsubs( 844 devconfig_t *mirror, 845 uint16_t *nsubs) 846 { 847 int error = get_uint16( 848 mirror->attributes, ATTR_MIRROR_NSUBMIRRORS, nsubs); 849 850 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 851 if (error == ENOENT) { 852 volume_set_error(gettext("number or submirrors not set")); 853 error = ERR_ATTR_UNSET; 854 } 855 856 return (error); 857 } 858 859 /* 860 * Set the read strategy for mirror 861 * 862 * @param mirror 863 * a devconfig_t representing the mirror to modify 864 * 865 * @param read 866 * the value to set as the read strategy for mirror 867 * 868 * @return 0 869 * if successful 870 * 871 * @return non-zero 872 * if an error occurred. Use get_error_string() to 873 * retrieve the associated error message. 874 */ 875 int 876 devconfig_set_mirror_read( 877 devconfig_t *mirror, 878 mirror_read_strategy_t read) 879 { 880 return (set_uint16(mirror->attributes, 881 ATTR_MIRROR_READ, (uint16_t)read)); 882 } 883 884 /* 885 * Get read strategy for mirror 886 * 887 * @param device 888 * a devconfig_t representing the device to examine 889 * 890 * @param read 891 * RETURN: read strategy for mirror 892 * 893 * @return 0 894 * if successful 895 * 896 * @return non-zero 897 * if an error occurred. Use get_error_string() to 898 * retrieve the associated error message. 899 */ 900 int 901 devconfig_get_mirror_read( 902 devconfig_t *mirror, 903 mirror_read_strategy_t *read) 904 { 905 uint16_t val; 906 int error = get_uint16(mirror->attributes, ATTR_MIRROR_READ, &val); 907 908 switch (error) { 909 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 910 case ENOENT: 911 volume_set_error(gettext("mirror read strategy not set")); 912 error = ERR_ATTR_UNSET; 913 break; 914 915 /* Success */ 916 case 0: 917 *read = (mirror_read_strategy_t)val; 918 } 919 920 return (error); 921 } 922 923 /* 924 * Set the write strategy for mirror 925 * 926 * @param mirror 927 * a devconfig_t representing the mirror to modify 928 * 929 * @param write 930 * the value to set as the write strategy for mirror 931 * 932 * @return 0 933 * if successful 934 * 935 * @return non-zero 936 * if an error occurred. Use get_error_string() to 937 * retrieve the associated error message. 938 */ 939 int 940 devconfig_set_mirror_write( 941 devconfig_t *mirror, 942 mirror_write_strategy_t write) 943 { 944 return (set_uint16(mirror->attributes, 945 ATTR_MIRROR_WRITE, (uint16_t)write)); 946 } 947 948 /* 949 * Get write strategy for mirror 950 * 951 * @param device 952 * a devconfig_t representing the device to examine 953 * 954 * @param write 955 * RETURN: write strategy for mirror 956 * 957 * @return 0 958 * if successful 959 * 960 * @return non-zero 961 * if an error occurred. Use get_error_string() to 962 * retrieve the associated error message. 963 */ 964 int 965 devconfig_get_mirror_write( 966 devconfig_t *mirror, 967 mirror_write_strategy_t *write) 968 { 969 uint16_t val; 970 int error = get_uint16(mirror->attributes, ATTR_MIRROR_WRITE, &val); 971 972 switch (error) { 973 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 974 case ENOENT: 975 volume_set_error(gettext("mirror write strategy not set")); 976 error = ERR_ATTR_UNSET; 977 break; 978 979 /* Success */ 980 case 0: 981 *write = (mirror_write_strategy_t)val; 982 } 983 984 return (error); 985 } 986 987 /* 988 * Set the resync pass for mirror 989 * 990 * @param mirror 991 * a devconfig_t representing the mirror to modify 992 * 993 * @param pass 994 * the value to set as the resync pass for mirror 995 * 996 * @return 0 997 * if successful 998 * 999 * @return non-zero 1000 * if an error occurred. Use get_error_string() to 1001 * retrieve the associated error message. 1002 */ 1003 int 1004 devconfig_set_mirror_pass( 1005 devconfig_t *mirror, 1006 uint16_t pass) 1007 { 1008 /* Validate against max value */ 1009 if (pass > MD_PASS_MAX) { 1010 volume_set_error( 1011 gettext("mirror pass number (%d) out of valid range (0-%d)"), 1012 pass, MD_PASS_MAX); 1013 return (-1); 1014 } 1015 1016 return (set_uint16(mirror->attributes, ATTR_MIRROR_PASSNUM, pass)); 1017 } 1018 1019 /* 1020 * Get resync pass for mirror 1021 * 1022 * @param device 1023 * a devconfig_t representing the device to examine 1024 * 1025 * @param pass 1026 * RETURN: resync pass for mirror 1027 * 1028 * @return 0 1029 * if successful 1030 * 1031 * @return non-zero 1032 * if an error occurred. Use get_error_string() to 1033 * retrieve the associated error message. 1034 */ 1035 int 1036 devconfig_get_mirror_pass( 1037 devconfig_t *mirror, 1038 uint16_t *pass) 1039 { 1040 int error = get_uint16(mirror->attributes, ATTR_MIRROR_PASSNUM, pass); 1041 1042 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 1043 if (error == ENOENT) { 1044 volume_set_error(gettext("mirror pass number not set")); 1045 error = ERR_ATTR_UNSET; 1046 } 1047 1048 return (error); 1049 } 1050 1051 /* 1052 * Set the minimum number of components in stripe 1053 * 1054 * @param stripe 1055 * a devconfig_t representing the stripe to modify 1056 * 1057 * @param mincomp 1058 * the value to set as the minimum number of components 1059 * in stripe 1060 * 1061 * @return 0 1062 * if successful 1063 * 1064 * @return non-zero 1065 * if an error occurred. Use get_error_string() to 1066 * retrieve the associated error message. 1067 */ 1068 int 1069 devconfig_set_stripe_mincomp( 1070 devconfig_t *stripe, 1071 uint16_t mincomp) 1072 { 1073 /* Validate against minimum value */ 1074 if (mincomp < MIN_NSTRIPE_COMP) { 1075 volume_set_error(gettext( 1076 "minimum stripe components (%d) below minimum allowable (%d)"), 1077 mincomp, MIN_NSTRIPE_COMP); 1078 return (-1); 1079 } 1080 1081 return (set_uint16(stripe->attributes, ATTR_STRIPE_MINCOMP, mincomp)); 1082 } 1083 1084 /* 1085 * Get minimum number of components in stripe 1086 * 1087 * @param device 1088 * a devconfig_t representing the device to examine 1089 * 1090 * @param mincomp 1091 * RETURN: minimum number of components in stripe 1092 * 1093 * @return 0 1094 * if successful 1095 * 1096 * @return non-zero 1097 * if an error occurred. Use get_error_string() to 1098 * retrieve the associated error message. 1099 */ 1100 int 1101 devconfig_get_stripe_mincomp( 1102 devconfig_t *stripe, 1103 uint16_t *mincomp) 1104 { 1105 int error = get_uint16( 1106 stripe->attributes, ATTR_STRIPE_MINCOMP, mincomp); 1107 1108 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 1109 if (error == ENOENT) { 1110 volume_set_error( 1111 gettext("minimum number of stripe components not set")); 1112 error = ERR_ATTR_UNSET; 1113 } 1114 1115 return (error); 1116 } 1117 1118 /* 1119 * Set the maximum number of components in stripe 1120 * 1121 * @param stripe 1122 * a devconfig_t representing the stripe to modify 1123 * 1124 * @param maxcomp 1125 * the value to set as the maximum number of components 1126 * in stripe 1127 * 1128 * @return 0 1129 * if successful 1130 * 1131 * @return non-zero 1132 * if an error occurred. Use get_error_string() to 1133 * retrieve the associated error message. 1134 */ 1135 int 1136 devconfig_set_stripe_maxcomp( 1137 devconfig_t *stripe, 1138 uint16_t maxcomp) 1139 { 1140 /* Validate against minimum value */ 1141 if (maxcomp < MIN_NSTRIPE_COMP) { 1142 volume_set_error(gettext( 1143 "maximum stripe components (%d) below minimum allowable (%d)"), 1144 maxcomp, MIN_NSTRIPE_COMP); 1145 return (-1); 1146 } 1147 1148 return (set_uint16(stripe->attributes, ATTR_STRIPE_MAXCOMP, maxcomp)); 1149 } 1150 1151 /* 1152 * Get maximum number of components in stripe 1153 * 1154 * @param device 1155 * a devconfig_t representing the device to examine 1156 * 1157 * @param maxcomp 1158 * RETURN: maximum number of components in stripe 1159 * 1160 * @return 0 1161 * if successful 1162 * 1163 * @return non-zero 1164 * if an error occurred. Use get_error_string() to 1165 * retrieve the associated error message. 1166 */ 1167 int 1168 devconfig_get_stripe_maxcomp( 1169 devconfig_t *stripe, 1170 uint16_t *maxcomp) 1171 { 1172 int error = get_uint16( 1173 stripe->attributes, ATTR_STRIPE_MAXCOMP, maxcomp); 1174 1175 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 1176 if (error == ENOENT) { 1177 volume_set_error( 1178 gettext("maximum number of stripe components not set")); 1179 error = ERR_ATTR_UNSET; 1180 } 1181 1182 return (error); 1183 } 1184 1185 /* 1186 * Set the stripe interlace 1187 * 1188 * @param stripe 1189 * a devconfig_t representing the stripe to modify 1190 * 1191 * @param interlace 1192 * the value to set as the stripe interlace 1193 * 1194 * @return 0 1195 * if successful 1196 * 1197 * @return non-zero 1198 * if an error occurred. Use get_error_string() to 1199 * retrieve the associated error message. 1200 */ 1201 int 1202 devconfig_set_stripe_interlace( 1203 devconfig_t *stripe, 1204 uint64_t interlace) 1205 { 1206 if (interlace < MININTERLACE || interlace > MAXINTERLACE) { 1207 char *intstr = NULL; 1208 char *minstr = NULL; 1209 char *maxstr = NULL; 1210 1211 /* Get string representations of interlaces */ 1212 bytes_to_sizestr(interlace, &intstr, universal_units, B_FALSE); 1213 bytes_to_sizestr(MININTERLACE, &minstr, universal_units, B_FALSE); 1214 bytes_to_sizestr(MAXINTERLACE, &maxstr, universal_units, B_FALSE); 1215 1216 volume_set_error( 1217 gettext("interlace (%s) out of valid range (%s - %s)"), 1218 intstr, minstr, maxstr); 1219 1220 free(intstr); 1221 free(minstr); 1222 free(maxstr); 1223 1224 return (-1); 1225 } 1226 1227 return (set_uint64(stripe->attributes, 1228 ATTR_STRIPE_INTERLACE, interlace)); 1229 } 1230 1231 /* 1232 * Get stripe interlace 1233 * 1234 * @param device 1235 * a devconfig_t representing the device to examine 1236 * 1237 * @param interlace 1238 * RETURN: stripe interlace 1239 * 1240 * @return 0 1241 * if successful 1242 * 1243 * @return non-zero 1244 * if an error occurred. Use get_error_string() to 1245 * retrieve the associated error message. 1246 */ 1247 int 1248 devconfig_get_stripe_interlace( 1249 devconfig_t *stripe, 1250 uint64_t *interlace) 1251 { 1252 int error = get_uint64( 1253 stripe->attributes, ATTR_STRIPE_INTERLACE, interlace); 1254 1255 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 1256 if (error == ENOENT) { 1257 volume_set_error(gettext("stripe interlace not set")); 1258 error = ERR_ATTR_UNSET; 1259 } 1260 1261 return (error); 1262 } 1263 1264 /* 1265 * Set the redundancy level for a volume. 1266 * 1267 * @param volume 1268 * a devconfig_t representing the volume to modify 1269 * 1270 * @param rlevel 1271 * If 0, a stripe will be created. If > 0, a mirror with 1272 * this number of submirrors will be created. 1273 * 1274 * @return 0 1275 * if successful 1276 * 1277 * @return non-zero 1278 * if an error occurred. Use get_error_string() to 1279 * retrieve the associated error message. 1280 */ 1281 int 1282 devconfig_set_volume_redundancy_level( 1283 devconfig_t *volume, 1284 uint16_t rlevel) 1285 { 1286 /* Validate against limits */ 1287 if (rlevel > NMIRROR) { 1288 volume_set_error(gettext( 1289 "volume redundancy level (%d) out of valid range (%d-%d)"), 1290 rlevel, 0, NMIRROR); 1291 return (-1); 1292 } 1293 1294 return (set_uint16(volume->attributes, ATTR_VOLUME_REDUNDANCY, rlevel)); 1295 } 1296 1297 /* 1298 * Get the redundancy level for a volume. 1299 * 1300 * @param device 1301 * a devconfig_t representing the device to examine 1302 * 1303 * @param rlevel 1304 * RETURN: the redundancy level for a volume 1305 * 1306 * @return 0 1307 * if successful 1308 * 1309 * @return non-zero 1310 * if an error occurred. Use get_error_string() to 1311 * retrieve the associated error message. 1312 */ 1313 int 1314 devconfig_get_volume_redundancy_level( 1315 devconfig_t *volume, 1316 uint16_t *rlevel) 1317 { 1318 int error = get_uint16( 1319 volume->attributes, ATTR_VOLUME_REDUNDANCY, rlevel); 1320 1321 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 1322 if (error == ENOENT) { 1323 volume_set_error(gettext("volume redundancy level not set")); 1324 error = ERR_ATTR_UNSET; 1325 } 1326 1327 return (error); 1328 } 1329 1330 /* 1331 * Set the number of paths in volume 1332 * 1333 * @param volume 1334 * a devconfig_t representing the volume to modify 1335 * 1336 * @param npaths 1337 * the value to set as the number of paths in volume 1338 * 1339 * @return 0 1340 * if successful 1341 * 1342 * @return non-zero 1343 * if an error occurred. Use get_error_string() to 1344 * retrieve the associated error message. 1345 */ 1346 int 1347 devconfig_set_volume_npaths( 1348 devconfig_t *volume, 1349 uint16_t npaths) 1350 { 1351 /* Validate against limits */ 1352 if (npaths < MIN_NDATAPATHS || npaths > MAX_NDATAPATHS) { 1353 volume_set_error( 1354 gettext("number of data paths (%d) out of valid range (%d-%d)"), 1355 npaths, MIN_NDATAPATHS, MAX_NDATAPATHS); 1356 return (-1); 1357 } 1358 1359 return (set_uint16(volume->attributes, ATTR_VOLUME_DATAPATHS, npaths)); 1360 } 1361 1362 /* 1363 * Get number of paths in volume 1364 * 1365 * @param device 1366 * a devconfig_t representing the device to examine 1367 * 1368 * @param npaths 1369 * RETURN: number of paths in volume 1370 * 1371 * @return 0 1372 * if successful 1373 * 1374 * @return non-zero 1375 * if an error occurred. Use get_error_string() to 1376 * retrieve the associated error message. 1377 */ 1378 int 1379 devconfig_get_volume_npaths( 1380 devconfig_t *volume, 1381 uint16_t *npaths) 1382 { 1383 int error = get_uint16( 1384 volume->attributes, ATTR_VOLUME_DATAPATHS, npaths); 1385 1386 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 1387 if (error == ENOENT) { 1388 volume_set_error(gettext("number of data paths not set")); 1389 error = ERR_ATTR_UNSET; 1390 } 1391 1392 return (error); 1393 } 1394 1395 /* 1396 * Set the HSP creation option (for volume, stripe, concat, mirror) 1397 * 1398 * @param volume 1399 * a devconfig_t representing the volume to modify 1400 * 1401 * @param usehsp 1402 * the value to set as the HSP creation option 1403 * 1404 * @return 0 1405 * if successful 1406 * 1407 * @return non-zero 1408 * if an error occurred. Use get_error_string() to 1409 * retrieve the associated error message. 1410 */ 1411 int 1412 devconfig_set_volume_usehsp( 1413 devconfig_t *volume, 1414 boolean_t usehsp) 1415 { 1416 return (set_boolean(volume->attributes, ATTR_VOLUME_USEHSP, usehsp)); 1417 } 1418 1419 /* 1420 * Get HSP creation option (for volume, stripe, concat, mirror) 1421 * 1422 * @param device 1423 * a devconfig_t representing the device to examine 1424 * 1425 * @param usehsp 1426 * RETURN: HSP creation option (for volume, stripe, 1427 * concat, mirror) 1428 * 1429 * @return 0 1430 * if successful 1431 * 1432 * @return non-zero 1433 * if an error occurred. Use get_error_string() to 1434 * retrieve the associated error message. 1435 */ 1436 int 1437 devconfig_get_volume_usehsp( 1438 devconfig_t *volume, 1439 boolean_t *usehsp) 1440 { 1441 int error = get_boolean( 1442 volume->attributes, ATTR_VOLUME_USEHSP, usehsp); 1443 1444 /* Convert ENOENT to ERR_ATTR_UNSET for a custom error message */ 1445 if (error == ENOENT) { 1446 volume_set_error(gettext("volume usehsp not set")); 1447 error = ERR_ATTR_UNSET; 1448 } 1449 1450 return (error); 1451 } 1452 1453 /* 1454 * Get the string representation of the volume's type 1455 * 1456 * @param type 1457 * a valid component_type_t 1458 * 1459 * @return an internationalized string representing the given 1460 * type 1461 */ 1462 char * 1463 devconfig_type_to_str( 1464 component_type_t type) 1465 { 1466 char *str; 1467 1468 switch (type) { 1469 case TYPE_CONCAT: str = gettext("Concat"); break; 1470 case TYPE_CONTROLLER: str = gettext("Controller"); break; 1471 case TYPE_DISKSET: str = gettext("Diskset"); break; 1472 case TYPE_DRIVE: str = gettext("Disk"); break; 1473 case TYPE_EXTENT: str = gettext("Extent"); break; 1474 case TYPE_HOST: str = gettext("Host"); break; 1475 case TYPE_HSP: str = gettext("Hot Spare Pool"); break; 1476 case TYPE_MIRROR: str = gettext("Mirror"); break; 1477 case TYPE_RAID5: str = gettext("Raid5"); break; 1478 case TYPE_SLICE: str = gettext("Slice"); break; 1479 case TYPE_SOFTPART: str = gettext("Soft Partition"); break; 1480 case TYPE_STRIPE: str = gettext("Stripe"); break; 1481 case TYPE_TRANS: str = gettext("Trans"); break; 1482 case TYPE_VOLUME: str = gettext("Volume"); break; 1483 default: 1484 case TYPE_UNKNOWN: str = gettext("Unknown"); break; 1485 } 1486 1487 return (str); 1488 } 1489 1490 /* 1491 * Get the string representation of the mirror's read strategy 1492 * 1493 * @param read 1494 * a valid mirror_read_strategy_t 1495 * 1496 * @return an internationalized string representing the given 1497 * read strategy 1498 */ 1499 char * 1500 devconfig_read_strategy_to_str( 1501 mirror_read_strategy_t read) 1502 { 1503 char *str; 1504 1505 switch (read) { 1506 case MIRROR_READ_ROUNDROBIN: str = gettext("ROUNDROBIN"); break; 1507 case MIRROR_READ_GEOMETRIC: str = gettext("GEOMETRIC"); break; 1508 case MIRROR_READ_FIRST: str = gettext("FIRST"); break; 1509 default: str = ""; 1510 } 1511 1512 return (str); 1513 } 1514 1515 /* 1516 * Get the string representation of the mirror's write strategy 1517 * 1518 * @param write 1519 * a valid mirror_write_strategy_t 1520 * 1521 * @return an internationalized string representing the given 1522 * write strategy 1523 */ 1524 char * 1525 devconfig_write_strategy_to_str( 1526 mirror_write_strategy_t write) 1527 { 1528 char *str; 1529 1530 switch (write) { 1531 case MIRROR_WRITE_PARALLEL: str = gettext("PARALLEL"); break; 1532 case MIRROR_WRITE_SERIAL: str = gettext("SERIAL"); break; 1533 default: str = ""; 1534 } 1535 1536 return (str); 1537 } 1538 1539 #ifdef DEBUG 1540 /* 1541 * Dump the contents of a devconfig_t struct to stdout. 1542 * 1543 * @param device 1544 * the devconfig_t to examine 1545 * 1546 * @param prefix 1547 * a prefix string to print before each line 1548 */ 1549 void 1550 devconfig_dump( 1551 devconfig_t *device, 1552 char *prefix) 1553 { 1554 dlist_t *comps = NULL; 1555 char **array = NULL; 1556 char *str = NULL; 1557 int i = 0; 1558 1559 component_type_t type = TYPE_UNKNOWN; 1560 boolean_t bool = B_FALSE; 1561 uint16_t val16 = 0; 1562 uint64_t val64 = 0; 1563 mirror_read_strategy_t read; 1564 mirror_write_strategy_t write; 1565 1566 if (device == NULL) { 1567 return; 1568 } 1569 1570 /* Type */ 1571 if (devconfig_get_type(device, &type) == 0) { 1572 printf("%s%s\n", prefix, devconfig_type_to_str(type)); 1573 } 1574 1575 /* Name */ 1576 if (devconfig_get_name(device, &str) == 0) { 1577 printf("%s name: %s\n", prefix, str); 1578 } 1579 1580 /* Size in bytes */ 1581 if (devconfig_get_size(device, &val64) == 0) { 1582 printf("%s size in bytes: %llu\n", prefix, val64); 1583 } 1584 1585 /* Size in blocks */ 1586 if (devconfig_get_size_in_blocks(device, &val64) == 0) { 1587 printf("%s size in blocks: %llu\n", prefix, val64); 1588 } 1589 1590 /* Use HSP */ 1591 if (devconfig_get_volume_usehsp(device, &bool) == 0) { 1592 printf("%s usehsp: %s\n", prefix, bool? "TRUE" : "FALSE"); 1593 } 1594 1595 switch (type) { 1596 case TYPE_VOLUME: 1597 /* Volume rlevel */ 1598 if (devconfig_get_volume_redundancy_level( 1599 device, &val16) == 0) { 1600 printf("%s volume redundancy level: %d\n", prefix, val16); 1601 } 1602 1603 /* Volume npaths */ 1604 if (devconfig_get_volume_npaths(device, &val16) == 0) { 1605 printf("%s volume npaths: %d\n", prefix, val16); 1606 } 1607 break; 1608 1609 case TYPE_MIRROR: 1610 1611 /* Mirror nsubs */ 1612 if (devconfig_get_mirror_nsubs(device, &val16) == 0) { 1613 printf("%s mirror nsubs: %d\n", prefix, val16); 1614 } 1615 1616 /* Mirror read */ 1617 if (devconfig_get_mirror_read(device, &read) == 0) { 1618 printf("%s mirror read: %s\n", prefix, 1619 devconfig_read_strategy_to_str(read)); 1620 } 1621 1622 /* Mirror write */ 1623 if (devconfig_get_mirror_write(device, &write) == 0) { 1624 printf("%s mirror write: %s\n", prefix, 1625 devconfig_write_strategy_to_str(write)); 1626 } 1627 1628 /* Mirror pass */ 1629 if (devconfig_get_mirror_pass(device, &val16) == 0) { 1630 printf("%s mirror pass: %d\n", prefix, val16); 1631 } 1632 break; 1633 1634 case TYPE_STRIPE: 1635 /* Stripe mincomp */ 1636 if (devconfig_get_stripe_mincomp(device, &val16) == 0) { 1637 printf("%s stripe mincomp: %d\n", prefix, val16); 1638 } 1639 1640 /* Stripe maxcomp */ 1641 if (devconfig_get_stripe_maxcomp(device, &val16) == 0) { 1642 printf("%s stripe maxcomp: %d\n", prefix, val16); 1643 } 1644 1645 /* Stripe interlace */ 1646 if (devconfig_get_stripe_interlace(device, &val64) == 0) { 1647 printf("%s stripe interlace: %lld\n", prefix, val64); 1648 } 1649 break; 1650 1651 case TYPE_SLICE: 1652 /* Slice index */ 1653 if (devconfig_get_slice_index(device, &val16) == 0) { 1654 printf("%s slice index: %d\n", prefix, val16); 1655 } 1656 1657 /* Slice start block */ 1658 if (devconfig_get_slice_start_block(device, &val64) == 0) { 1659 printf("%s slice start block: %llu\n", prefix, val64); 1660 } 1661 break; 1662 } 1663 1664 array = devconfig_get_available(device); 1665 if (array != NULL) { 1666 printf("%s available:\n", prefix); 1667 for (i = 0; array[i] != NULL; i++) { 1668 printf("%s %s\n", prefix, array[i]); 1669 } 1670 } 1671 1672 array = devconfig_get_unavailable(device); 1673 if (array != NULL) { 1674 printf("%s unavailable:\n", prefix); 1675 for (i = 0; array[i] != NULL; i++) { 1676 printf("%s %s\n", prefix, array[i]); 1677 } 1678 } 1679 1680 printf("\n"); 1681 1682 comps = devconfig_get_components(device); 1683 if (comps != NULL) { 1684 char buf[128]; 1685 snprintf(buf, 128, "%s%s", prefix, " "); 1686 for (; comps != NULL; comps = comps->next) { 1687 devconfig_dump((devconfig_t *)comps->obj, buf); 1688 } 1689 } 1690 } 1691 #endif /* DEBUG */ 1692