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 2005 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 <string.h> 30#include <stdlib.h> 31#include <stdio.h> 32#include <sys/types.h> 33#include <sys/vtoc.h> 34#include <sys/dktp/fdisk.h> 35#include <errno.h> 36#include <meta.h> 37 38#include <libdiskmgt.h> 39#include "meta_repartition.h" 40 41#define _LAYOUT_DEVICE_UTIL_C 42 43#include "volume_dlist.h" 44#include "volume_error.h" 45#include "volume_output.h" 46#include "volume_nvpair.h" 47 48#include "layout_device_cache.h" 49#include "layout_device_util.h" 50#include "layout_discovery.h" 51#include "layout_dlist_util.h" 52#include "layout_slice.h" 53 54/* 55 * Macros to produce a quoted string containing the value of a 56 * preprocessor macro. For example, if SIZE is defined to be 256, 57 * VAL2STR(SIZE) is "256". This is used to construct format 58 * strings for scanf-family functions below. 59 */ 60#define QUOTE(x) #x 61#define VAL2STR(x) QUOTE(x) 62 63/* private utilities for disks */ 64static int disk_get_uint64_attribute( 65 dm_descriptor_t disk, 66 char *attr, 67 uint64_t *val); 68 69static int disk_get_boolean_attribute( 70 dm_descriptor_t disk, 71 char *attr, 72 boolean_t *bool); 73 74static int disk_get_rpm( 75 dm_descriptor_t disk, 76 uint32_t *val); 77 78static int disk_get_sync_speed( 79 dm_descriptor_t disk, 80 uint32_t *val); 81 82static int disk_has_virtual_slices( 83 dm_descriptor_t disk, 84 boolean_t *bool); 85 86static int disk_get_virtual_slices( 87 dm_descriptor_t disk, 88 dlist_t **list); 89 90static int disk_get_reserved_indexes( 91 dm_descriptor_t disk, 92 uint16_t **array); 93 94static int disk_get_associated_desc( 95 dm_descriptor_t disk, 96 dm_desc_type_t assoc_type, 97 char *assoc_type_str, 98 dlist_t **list); 99 100/* utilities for slices */ 101static int slice_get_uint64_attribute( 102 dm_descriptor_t slice, 103 char *attr, 104 uint64_t *val); 105 106static int slice_set_attribute( 107 dm_descriptor_t slice, 108 char *attr, 109 uint64_t val); 110 111/* 112 * Virtual slices are created to represent slices that will be 113 * on the system after disks have been added to the destination 114 * diskset. For the purposes of layout, these slices must 115 * look & function just as real slices that are currently on 116 * the system. 117 */ 118static dlist_t *_virtual_slices = NULL; 119 120/* temporary implementation */ 121static int virtual_repartition_drive( 122 dm_descriptor_t disk, 123 mdvtoc_t *vtocp); 124 125static int disk_add_virtual_slice( 126 dm_descriptor_t disk, 127 dm_descriptor_t slice); 128 129static int virtual_slice_get_disk( 130 dm_descriptor_t slice, 131 dm_descriptor_t *diskp); 132 133/* 134 * attribute names for layout private information stored in 135 * device nvpair attribute lists. 136 */ 137static char *ATTR_RESERVED_INDEX = "vdu_reserved_index"; 138static char *ATTR_VIRTUAL_SLICES = "vdu_virtual_slices"; 139static char *ATTR_DISK_FOR_SLICE = "vdu_disk_for_slice"; 140static char *ATTR_DEV_CTD_NAME = "vdu_device_ctd_name"; 141static char *ATTR_HBA_N_DISKS = "vdu_hba_n_usable_disks"; 142 143/* 144 * FUNCTION: is_ctd_like_slice_name(char *name) 145 * INPUT: name - a char * 146 * 147 * RETURNS: boolean_t - B_TRUE - if name follows an alternate slice 148 * naming scheme similar to CTD 149 * B_FALSE - otherwise 150 * 151 * PURPOSE: Determines if the input name is of the form XXXsNNN 152 * (e.g., whizzy0s1) 153 */ 154boolean_t 155is_ctd_like_slice_name( 156 char *name) 157{ 158 uint_t s = 0; 159 uint_t d = 0; 160 int l = 0; 161 boolean_t is = B_FALSE; 162 163 /* The format strings below match and discard the non-numeric part. */ 164 if ((sscanf(name, "/dev/dsk/%*[^0-9/]%us%u%n", &d, &s, &l) == 2 || 165 sscanf(name, "/dev/rdsk/%*[^0-9/]%us%u%n", &d, &s, &l) == 2 || 166 sscanf(name, "%*[^0-9/]%us%u%n", &d, &s, &l) == 2) && 167 (l == strlen(name))) { 168 is = B_TRUE; 169 } 170 171 return (is); 172} 173 174/* 175 * FUNCTION: is_bsd_like_slice_name(char *name) 176 * INPUT: name - a char * 177 * 178 * RETURNS: boolean_t - B_TRUE - if name follows an alternate slice 179 * BSD-like naming scheme 180 * B_FALSE - otherwise 181 * 182 * PURPOSE: Determines if the input name is of the form XXXNNN[a-h] 183 * (e.g., whizzy0a) 184 */ 185boolean_t 186is_bsd_like_slice_name( 187 char *name) 188{ 189 uint_t d = 0; 190 int l = 0; 191 boolean_t is = B_FALSE; 192 193 /* The format strings below match and discard the non-numeric part. */ 194 if ((sscanf(name, "/dev/dsk/%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1 || 195 sscanf(name, "/dev/rdsk/%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1 || 196 sscanf(name, "%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1) && 197 (l == strlen(name))) { 198 is = B_TRUE; 199 } 200 201 return (is); 202} 203 204/* 205 * FUNCTION: is_did_name(char *name) 206 * INPUT: name - a char * 207 * 208 * RETURNS: boolean_t - B_TRUE - if name is from the DID namespace 209 * B_FALSE - otherwise 210 * 211 * PURPOSE: Determines if the input name is from the DID namespace. 212 */ 213boolean_t 214is_did_name( 215 char *name) 216{ 217 return (is_did_slice_name(name) || is_did_disk_name(name)); 218} 219 220/* 221 * FUNCTION: is_did_slice_name(char *name) 222 * INPUT: name - a char * 223 * 224 * RETURNS: boolean_t - B_TRUE - if name represents a slice from the DID 225 * namespace 226 * B_FALSE - otherwise 227 * 228 * PURPOSE: Determines if the input name is a slice from the DID namespace. 229 */ 230boolean_t 231is_did_slice_name( 232 char *name) 233{ 234 uint_t d = 0, s = 0; 235 int l = 0; 236 boolean_t is = B_FALSE; 237 238 if ((sscanf(name, "/dev/did/rdsk/d%us%u%n", &d, &s, &l) == 2 || 239 sscanf(name, "/dev/did/dsk/d%us%u%n", &d, &s, &l) == 2 || 240 sscanf(name, "d%us%u%n", &d, &s, &l) == 2) || 241 (l == strlen(name))) { 242 is = B_TRUE; 243 } 244 245 return (is); 246} 247 248/* 249 * FUNCTION: is_did_disk_name(char *name) 250 * INPUT: name - a char * 251 * 252 * RETURNS: boolean_t - B_TRUE - if name represents a disk from the DID 253 * namespace 254 * B_FALSE - otherwise 255 * 256 * PURPOSE: Determines if the input name is a disk from the DID namespace. 257 */ 258boolean_t 259is_did_disk_name( 260 char *name) 261{ 262 uint_t d = 0; 263 int l = 0; 264 boolean_t is = B_FALSE; 265 266 if ((sscanf(name, "/dev/did/rdsk/d%u%n", &d, &l) == 1 || 267 sscanf(name, "/dev/did/dsk/d%u%n", &d, &l) == 1 || 268 sscanf(name, "d%u%n", &d, &l) == 1) && 269 (l == strlen(name))) { 270 is = B_TRUE; 271 } 272 273 return (is); 274} 275 276/* 277 * FUNCTION: is_ctd_name(char *name) 278 * INPUT: name - a char * 279 * 280 * RETURNS: boolean_t - B_TRUE - if name is from the CTD namespace 281 * B_FALSE - otherwise 282 * 283 * PURPOSE: Determines if the input name is from the CTD namespace. 284 * 285 * {/dev/dsk/, /dev/rdsk/}cXtXdXsX 286 * {/dev/dsk/, /dev/rdsk/}cXtXdX 287 * {/dev/dsk/, /dev/rdsk/}cXdXsX 288 * {/dev/dsk/, /dev/rdsk/}cXdX 289 */ 290boolean_t 291is_ctd_name( 292 char *name) 293{ 294 return (is_ctd_slice_name(name) || is_ctd_disk_name(name) || 295 is_ctd_target_name(name) || is_ctd_ctrl_name(name)); 296} 297 298/* 299 * FUNCTION: is_ctd_slice_name(char *name) 300 * INPUT: name - a char * 301 * 302 * RETURNS: boolean_t - B_TRUE - if name represents a slice from the CTD 303 * namespace 304 * B_FALSE - otherwise 305 * 306 * PURPOSE: Determines if the input name is a slice name from the 307 * CTD namespace. 308 * 309 * {/dev/dsk/, /dev/rdsk/}cXt<WWN>dXsX 310 * {/dev/dsk/, /dev/rdsk/}cXtXdXsX 311 * {/dev/dsk/, /dev/rdsk/}cXdXsX 312 */ 313boolean_t 314is_ctd_slice_name( 315 char *name) 316{ 317 uint_t c = 0, t = 0, d = 0, s = 0; 318 char buf[MAXNAMELEN+1]; 319 int l = 0; 320 boolean_t is = B_FALSE; 321 322 if ((sscanf(name, "/dev/dsk/c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 || 323 sscanf(name, "/dev/rdsk/c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 || 324 sscanf(name, "c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 || 325 sscanf(name, "/dev/dsk/c%ud%us%u%n", &c, &d, &s, &l) == 3 || 326 sscanf(name, "/dev/rdsk/c%ud%us%u%n", &c, &d, &s, &l) == 3 || 327 sscanf(name, "c%ud%us%u%n", &c, &d, &s, &l) == 3 || 328 sscanf(name, "c%ud%us%u%n", &c, &d, &s, &l) == 2) && 329 (l == strlen(name))) { 330 is = B_TRUE; 331 } else if ( 332 (sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n", 333 &c, buf, &l) == 2 || 334 sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n", 335 &c, buf, &l) == 2 || 336 sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n", 337 &c, buf, &l) == 2) && (l == strlen(name))) { 338 char *dev_pos; 339 340 /* see if buf ends with "dXsX" */ 341 if (((dev_pos = strrchr(buf, 'd')) != NULL) && 342 (sscanf(dev_pos, "d%us%u%n", &d, &s, &l) == 2) && 343 (l == strlen(dev_pos))) { 344 345 char wwn[MAXNAMELEN+2]; 346 347 /* buf ends with "dXsX", truncate at the 'd' */ 348 *dev_pos = '\0'; 349 350 /* prepend "0X" to remainder and try to scan as a hex WWN */ 351 (void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf); 352 if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) { 353 is = B_TRUE; 354 } 355 } 356 } 357 358 return (is); 359} 360 361/* 362 * FUNCTION: is_ctd_disk_name(char *name) 363 * INPUT: name - a char * 364 * 365 * RETURNS: boolean_t - B_TRUE - if name represents a disk from the CTD 366 * namespace 367 * B_FALSE - otherwise 368 * 369 * PURPOSE: Determines if the input name is a disk name from the 370 * CTD namespace. 371 * 372 * {/dev/dsk/, /dev/rdsk/}cXt<WWN>dX 373 * {/dev/dsk/, /dev/rdsk/}cXtXdX 374 * {/dev/dsk/, /dev/rdsk/}cXdX 375 */ 376boolean_t 377is_ctd_disk_name( 378 char *name) 379{ 380 uint_t c = 0, t = 0, d = 0; 381 int l = 0; 382 char buf[MAXNAMELEN+1]; 383 boolean_t is = B_FALSE; 384 385 if ((sscanf(name, "/dev/dsk/c%ut%ud%u%n", &c, &t, &d, &l) == 3 || 386 sscanf(name, "/dev/rdsk/c%ut%ud%u%n", &c, &t, &d, &l) == 3 || 387 sscanf(name, "c%ut%ud%u%n", &c, &t, &d, &l) == 3 || 388 sscanf(name, "/dev/dsk/c%ud%u%n", &c, &d, &l) == 2 || 389 sscanf(name, "/dev/rdsk/c%ud%n%n", &c, &d, &l) == 2 || 390 sscanf(name, "c%ud%u%n", &c, &d, &l) == 2) && 391 (l == strlen(name))) { 392 is = B_TRUE; 393 } else if ((sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n", 394 &c, buf, &l) == 2 || 395 sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n", 396 &c, buf, &l) == 2 || 397 sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n", 398 &c, buf, &l) == 2) && (l == strlen(name))) { 399 char *dev_pos; 400 401 /* see if buf ends with "dX" */ 402 if (((dev_pos = strrchr(buf, 'd')) != NULL) && 403 (sscanf(dev_pos, "d%u%n", &d, &l) == 1) && 404 (l == strlen(dev_pos))) { 405 406 char wwn[MAXNAMELEN+2]; 407 408 /* buf ends with "dX", truncate at the 'd' */ 409 *dev_pos = '\0'; 410 411 /* prepend "0X" to remainder and try to scan as a hex WWN */ 412 (void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf); 413 if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) { 414 is = B_TRUE; 415 } 416 } 417 } 418 419 return (is); 420} 421 422/* 423 * FUNCTION: is_ctd_disk_name(char *name) 424 * INPUT: name - a char * 425 * 426 * RETURNS: boolean_t - B_TRUE - if name represents a target from the CTD 427 * namespace 428 * B_FALSE - otherwise 429 * 430 * PURPOSE: Determines if the input name is a target name from the 431 * CTD namespace. 432 * 433 * {/dev/dsk/, /dev/rdsk/}cXt<WWN> 434 * {/dev/dsk/, /dev/rdsk/}cXtX 435 */ 436boolean_t 437is_ctd_target_name( 438 char *name) 439{ 440 uint_t c = 0, t = 0; 441 int l = 0; 442 char buf[MAXNAMELEN+1]; 443 boolean_t is = B_FALSE; 444 445 if ((sscanf(name, "/dev/dsk/c%ut%u%n", &c, &t, &l) == 2 || 446 sscanf(name, "/dev/rdsk/c%ut%u%n", &c, &t, &l) == 2 || 447 sscanf(name, "c%ut%u%n", &c, &t, &l) == 2) && 448 (l == strlen(name))) { 449 is = B_TRUE; 450 } else if ( 451 (sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n", 452 &c, buf, &l) == 2 || 453 sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n", 454 &c, buf, &l) == 2 || 455 sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n", 456 &c, &buf, &l) == 2) && (l == strlen(name))) { 457 458 char wwn[MAXNAMELEN+2]; 459 460 /* prepend "0X" to buf and try to scan as a hex WWN */ 461 (void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf); 462 if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) { 463 is = B_TRUE; 464 } 465 } 466 467 return (is); 468} 469 470/* 471 * FUNCTION: is_ctd_ctrl_name(char *name) 472 * INPUT: name - a char * 473 * 474 * RETURNS: boolean_t - B_TRUE - if name represents a controller/hba 475 * from the CTD namespace 476 * B_FALSE - otherwise 477 * 478 * PURPOSE: Determines if the input name is an HBA name from the 479 * CTD namespace. 480 * 481 * {/dev/dsk/, /dev/rdsk/}cX 482 */ 483boolean_t 484is_ctd_ctrl_name( 485 char *name) 486{ 487 uint_t c = 0; 488 int l = 0; 489 boolean_t is = B_FALSE; 490 491 if ((sscanf(name, "/dev/dsk/c%u%n", &c, &l) == 1 || 492 sscanf(name, "/dev/rdsk/c%u%n", &c, &l) == 1 || 493 sscanf(name, "c%u%n", &c, &l) == 1) && 494 (l == strlen(name))) { 495 is = B_TRUE; 496 } 497 498 return (is); 499} 500 501/* 502 * FUNCTION: set_display_name(dm_descriptor_t desc, char *name) 503 * get_display_name(dm_descriptor_t desc, char **name) 504 * 505 * INPUT: desc - a dm_descriptor_t handle for a device 506 * name - a char * name 507 * 508 * OUTPUT: **name - a pointer to a char * to hold the display 509 * name associated with the input descriptor. 510 * 511 * RETURNS: int - 0 on success 512 * !0 otherwise. 513 * 514 * PURPOSE: Helpers to set/get the input descriptor's display name. 515 * 516 * Only slices, disks and HBAs should have display names. 517 * 518 * The attribute is only set in the cached copy of 519 * the device's nvpair attribute list. This function 520 * does not affect the underlying physical device. 521 * 522 * An entry is added in the name->descriptor cache 523 * so the descriptor can be found by name quickly. 524 */ 525int 526set_display_name( 527 dm_descriptor_t desc, 528 char *name) 529{ 530 nvlist_t *attrs = NULL; 531 int error = 0; 532 533 ((error = add_cached_descriptor(name, desc)) != 0) || 534 (error = get_cached_attributes(desc, &attrs)) || 535 (error = set_string(attrs, ATTR_DEV_CTD_NAME, name)); 536 537 return (error); 538} 539 540int 541get_display_name( 542 dm_descriptor_t desc, 543 char **name) 544{ 545 nvlist_t *attrs = NULL; 546 int error = 0; 547 548 ((error = get_cached_attributes(desc, &attrs)) != 0) || 549 (error = get_string(attrs, ATTR_DEV_CTD_NAME, name)); 550 551 return (error); 552} 553 554/* 555 * FUNCTION: disk_get_slices(dm_descriptor_t disk, dlist_t **list) 556 * 557 * INPUT: disk - a dm_descriptor_t handle for a disk 558 * 559 * OUTPUT: *list - a pointer to list to hold the results. 560 * 561 * RETURNS: int - 0 on success 562 * !0 otherwise. 563 * 564 * PURPOSE: Collect all of the known slices for the input disk. 565 * 566 * These slices may be actual slices which currently exist 567 * on the disk, or virtual slices which will exist when the 568 * disk is added to the destination diskset. 569 */ 570int 571disk_get_slices( 572 dm_descriptor_t disk, 573 dlist_t **list) 574{ 575 dm_descriptor_t *media = NULL; 576 boolean_t virtual = B_FALSE; 577 int i = 0; 578 int error = 0; 579 580 *list = 0; 581 582 if ((error = disk_has_virtual_slices(disk, &virtual)) != 0) { 583 return (error); 584 } 585 586 if (virtual == B_TRUE) { 587 error = disk_get_virtual_slices(disk, list); 588 } 589 590 /* add real slices from disk's media... */ 591 media = dm_get_associated_descriptors(disk, DM_MEDIA, &error); 592 (void) add_descriptors_to_free(media); 593 594 if (error == 0) { 595 /* if there's no media, this is a removeable drive */ 596 if (media != NULL && *media != NULL) { 597 598 /* examine media's slices... */ 599 dm_descriptor_t *slices = NULL; 600 slices = dm_get_associated_descriptors(*media, 601 DM_SLICE, &error); 602 (void) add_descriptors_to_free(slices); 603 604 if (error != 0) { 605 print_get_assoc_desc_error(disk, gettext("slice"), error); 606 } else { 607 for (i = 0; (slices[i] != NULL) && (error == 0); i++) { 608 dlist_t *item = 609 dlist_new_item((void *)(uintptr_t)slices[i]); 610 if (item == NULL) { 611 error = ENOMEM; 612 } else { 613 *list = dlist_append(item, *list, AT_TAIL); 614 } 615 } 616 free(slices); 617 } 618 free(media); 619 } 620 } else { 621 print_get_assoc_desc_error(disk, gettext("media"), error); 622 } 623 624 return (error); 625} 626 627int 628get_virtual_slices( 629 dlist_t **list) 630{ 631 *list = _virtual_slices; 632 633 return (0); 634} 635 636/* 637 * FUNCTION: virtual_repartition_drive(dm_descriptor_t disk, 638 * mdvtoc_t *vtocp) 639 * 640 * INPUT: disk - the disk to be virtually repartitioned 641 * 642 * OUTPUT: vtocp - a poitner to a mdvtoc struct to hold the results 643 * 644 * RETURNS: int - 0 on success 645 * !0 otherwise. 646 * 647 * PURPOSE: Helper which emulates the repartitioning that is done 648 * when a disk is added to a diskset. 649 * 650 * Modified version of meta_partition_drive which uses info 651 * from libdiskmgt to accomplish the repartitioning. 652 * 653 * This exists to allow the layout module to run with a 654 * simulated hardware environment. 655 * 656 * XXX This method absolutely does not produce the exact 657 * same result as meta_repartition_drive: only information 658 * required by the layout code is returned. Basically, 659 * a slice 7 (or 6 on EFI labelled disks) is created and 660 * sized, the remained of the available cylinders are put 661 * into slice 0. 662 * 663 * XXX2 This method is required until there is resolution 664 * on whether metassist testing will be done using the 665 * hardware simulation mechanism libdiskmgt provides. 666 * Doing so will also require parts of libmeta to be 667 * simulated as well. Some research has been done into 668 * building an alternate libmeta.so containing 669 * implementations of the functions used by metassist 670 * that are compatible with the simulated hardware. 671 * Actual work is currently on hold. 672 */ 673static int 674virtual_repartition_drive( 675 dm_descriptor_t disk, 676 mdvtoc_t *vtocp) 677{ 678 uint_t replicaslice = 7; 679 unsigned long long cylsize; 680 unsigned long long drvsize; 681 uint_t reservedcyl; 682 ushort_t resflag; 683 unsigned long long ressize; 684 diskaddr_t replica_start; 685 diskaddr_t replica_size; 686 diskaddr_t data_start; 687 diskaddr_t data_size; 688 689 boolean_t efi = B_FALSE; 690 uint64_t ncyls = 0; 691 uint64_t nheads = 0; 692 uint64_t nsects = 0; 693 int error = 0; 694 695 /* 696 * At this point, ressize is used as a minimum value. Later it 697 * will be rounded up to a cylinder boundary. ressize is in 698 * units of disk sectors. 699 */ 700 ressize = MD_DBSIZE + VTOC_SIZE; 701 resflag = V_UNMNT; 702 703 ((error = disk_get_is_efi(disk, &efi)) != 0) || 704 (error = disk_get_ncylinders(disk, &ncyls)) || 705 (error = disk_get_nheads(disk, &nheads)) || 706 (error = disk_get_nsectors(disk, &nsects)); 707 if (error != 0) { 708 return (error); 709 } 710 711 if (efi) { 712 replicaslice = 6; 713 } 714 715 /* 716 * Both cylsize and drvsize are in units of disk sectors. 717 * 718 * The intended results are of type unsigned long long. Since 719 * each operand of the first multiplication is of type 720 * unsigned int, we risk overflow by multiplying and then 721 * converting the result. Therefore we explicitly cast (at 722 * least) one of the operands, forcing conversion BEFORE 723 * multiplication, and avoiding overflow. The second 724 * assignment is OK, since one of the operands is already of 725 * the desired type. 726 */ 727 cylsize = ((unsigned long long)nheads) * nsects; 728 drvsize = cylsize * ncyls; 729 730 /* 731 * How many cylinders must we reserve for slice seven to 732 * ensure that it meets the previously calculated minimum 733 * size? 734 */ 735 reservedcyl = (ressize + cylsize - 1) / cylsize; 736 737 /* 738 * It seems unlikely that someone would pass us too small a 739 * disk, but it's still worth checking for... 740 */ 741 if (reservedcyl >= ncyls) { 742 volume_set_error( 743 gettext("disk is too small to hold a metadb replica")); 744 return (-1); 745 } 746 747 replica_start = 0; 748 replica_size = reservedcyl * cylsize; 749 data_start = reservedcyl * cylsize; 750 data_size = drvsize - (reservedcyl * cylsize); 751 752 /* 753 * fill in the proposed VTOC information. 754 */ 755 756 /* We need at least replicaslice partitions in the proposed vtoc */ 757 vtocp->nparts = replicaslice + 1; 758 vtocp->parts[MD_SLICE0].start = data_start; 759 vtocp->parts[MD_SLICE0].size = data_size; 760 vtocp->parts[MD_SLICE0].tag = V_USR; 761 vtocp->parts[replicaslice].start = replica_start; 762 vtocp->parts[replicaslice].size = replica_size; 763 vtocp->parts[replicaslice].flag = resflag; 764 vtocp->parts[replicaslice].tag = V_USR; 765 766 return (0); 767} 768 769/* 770 * FUNCTION: create_virtual_slices(dlist_t *disks) 771 * 772 * INPUT: possibles - a list of dm_descriptor_t disk handles for 773 * disks known to be available for use by layout. 774 * 775 * SIDEEFFECT: populates the private of virtual slices. 776 * 777 * RETURNS: int - 0 on success 778 * !0 otherwise. 779 * 780 * PURPOSE: Helper which creates virtual slices for each disk which 781 * could be added to a diskset if necessary... 782 * 783 * Iterate the input list of available disks and see what the 784 * slicing would be if the disk were added to a diskset. 785 * 786 * For the resulting slices, create virtual slice descriptors 787 * and attributes for these slices and add them to the list of 788 * available slices. 789 */ 790int 791create_virtual_slices( 792 dlist_t *disks) 793{ 794 int error = 0; 795 dlist_t *iter; 796 boolean_t sim = B_FALSE; 797 static char *simfile = "METASSISTSIMFILE"; 798 799 sim = ((getenv(simfile) != NULL) && (strlen(getenv(simfile)) > 0)); 800 801 /* see what slices each of the disks will have when added to a set */ 802 for (iter = disks; error == 0 && iter != NULL; iter = iter->next) { 803 804 dm_descriptor_t disk = (uintptr_t)iter->obj; 805 dlist_t *slices = NULL; 806 mdvtoc_t vtoc; 807 char *dname; 808 int i = 0; 809 810 if ((error = get_display_name(disk, &dname)) != 0) { 811 break; 812 } 813 814 if (sim != B_TRUE) { 815 816 /* sim disabled: use meta_repartition_drive() */ 817 818 md_error_t mderror = mdnullerror; 819 int opts = (MD_REPART_FORCE | MD_REPART_DONT_LABEL); 820 mdsetname_t *sp; 821 mddrivename_t *dnp; 822 823 /* disk is in the local set */ 824 sp = metasetname(MD_LOCAL_NAME, &mderror); 825 if (!mdisok(&mderror)) { 826 volume_set_error(mde_sperror(&mderror, NULL)); 827 mdclrerror(&mderror); 828 error = -1; 829 break; 830 } 831 832 dnp = metadrivename(&sp, dname, &mderror); 833 if (!mdisok(&mderror)) { 834 volume_set_error(mde_sperror(&mderror, NULL)); 835 mdclrerror(&mderror); 836 error = -1; 837 break; 838 } 839 840 if (meta_repartition_drive( 841 sp, dnp, opts, &vtoc, &mderror) != 0) { 842 volume_set_error( 843 gettext("failed to repartition disk %s\n"), 844 dname); 845 error = -1; 846 break; 847 } 848 849 } else { 850 851 /* sim enabled: use faked repartition code */ 852 if (virtual_repartition_drive(disk, &vtoc) != 0) { 853 volume_set_error( 854 gettext("failed simulated repartition of %s\n"), 855 dname); 856 error = -1; 857 break; 858 } 859 } 860 861 /* BEGIN CSTYLED */ 862 /* 863 * get the existing slices on the disk, if the repartition 864 * was successful, these slices need to have their size, start 865 * blk and size in blks set to 0 866 */ 867 /* END CSTYLED */ 868 if ((error = disk_get_slices(disk, &slices)) == 0) { 869 dlist_t *iter2 = slices; 870 for (; iter2 != NULL; iter2 = iter2->next) { 871 dm_descriptor_t sp = (uintptr_t)iter2->obj; 872 ((error = slice_set_start_block(sp, 0)) != 0) || 873 (error = slice_set_size_in_blocks(sp, 0)) || 874 (error = slice_set_size(sp, 0)); 875 } 876 dlist_free_items(slices, NULL); 877 } 878 879 /* scan VTOC, find slice with the free space */ 880 for (i = 0; i < vtoc.nparts; i++) { 881 882 if (vtoc.parts[i].tag == V_USR && 883 vtoc.parts[i].flag != V_UNMNT) { 884 885 /* non-replica slice with free space */ 886 char buf[MAXPATHLEN]; 887 (void) snprintf(buf, MAXPATHLEN-1, "%ss%d", dname, i); 888 889 if ((error = add_virtual_slice(buf, 890 (uint32_t)i, 891 (uint64_t)vtoc.parts[i].start, 892 (uint64_t)vtoc.parts[i].size, 893 disk)) != 0) { 894 break; 895 } 896 897 } else if (vtoc.parts[i].tag == V_RESERVED) { 898 899 /* skip EFI reserved slice */ 900 continue; 901 902 } else if (vtoc.parts[i].tag == V_USR && 903 vtoc.parts[i].flag == V_UNMNT) { 904 905 /* BEGIN CSTYLED */ 906 /* 907 * Make the replica slice 0 sized -- this will 908 * force the disk to be repartitioned by 909 * metaset when it is added to the disk set. 910 * 911 * XXX this is a temporary workaround until 912 * 4712873 is integrated... 913 */ 914 /* BEGIN CSTYLED */ 915 char buf[MAXPATHLEN]; 916 (void) snprintf(buf, MAXPATHLEN-1, "%ss%d", dname, i); 917 add_slice_to_remove(buf, i); 918 919 /* replica slice, stop here */ 920 break; 921 } 922 } 923 } 924 925 return (error); 926} 927 928/* 929 * FUNCTION: add_virtual_slice(char *name, uint32_t index, 930 * uint64_t startblk, uint64_t sizeblks, 931 * dm_descriptor_t disk) 932 * 933 * INPUT: name - the name of the new virtual slice 934 * index - the VTOC index ... 935 * startblk - the start block ... 936 * sizeblks - the size in blocks ... 937 * disk - the parent disk ... 938 * 939 * RETURNS: int - 0 on success 940 * !0 otherwise. 941 * 942 * PURPOSE: Helper which adds the appropriate data structures to 943 * represent a new virtual slice. 944 * 945 * allocates a new descriptor 946 * adds entries to name->desc and desc->name caches 947 * allocates an attribute nvpair list 948 * fills in the relevant attributes for the slice 949 * associates the slice with its parent disk 950 * adds an entry to the list of all virtual slices 951 * generates aliases if the associated disk has aliases. 952 */ 953int 954add_virtual_slice( 955 char *name, 956 uint32_t index, 957 uint64_t startblk, 958 uint64_t sizeblks, 959 dm_descriptor_t disk) 960{ 961 dm_descriptor_t sp; 962 nvlist_t *attrs; 963 char *sname; 964 dlist_t *aliases = NULL; 965 dlist_t *item = NULL; 966 int error = 0; 967 968 if ((error = nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0)) != 0) { 969 return (error); 970 } 971 972 /* create descriptor */ 973 ((error = new_descriptor(&sp)) != 0) || 974 /* cache name for the descriptor */ 975 (error = add_cached_name(sp, name)) || 976 /* cache descriptor for the name */ 977 (error = add_cached_descriptor(name, sp)) || 978 979 /* fill in attributes */ 980 (error = set_string(attrs, ATTR_DEV_CTD_NAME, name)) || 981 (error = set_uint32(attrs, DM_INDEX, index)) || 982 (error = set_uint64(attrs, DM_START, startblk)) || 983 (error = set_uint64(attrs, DM_SIZE, sizeblks)) || 984 (error = set_uint64(attrs, ATTR_DISK_FOR_SLICE, (uint64_t)disk)) || 985 986 /* add attributes to the cache */ 987 (error = get_name(sp, &sname)) || 988 (error = add_cached_attributes(sname, attrs)) || 989 990 /* connect slice to disk */ 991 (error = disk_add_virtual_slice(disk, sp)) || 992 (error = get_display_name(disk, &name)) || 993 (error = get_aliases(disk, &aliases)); 994 995 if (error != 0) { 996 return (error); 997 } 998 999 /* generate slice's aliases if the disk has aliases */ 1000 if (aliases != NULL) { 1001 char buf[MAXNAMELEN]; 1002 1003 for (; aliases != NULL; aliases = aliases->next) { 1004 (void) snprintf(buf, MAXNAMELEN-1, "%ss%d", 1005 (char *)aliases->obj, index); 1006 error = set_alias(sp, buf); 1007 } 1008 dlist_free_items(aliases, free); 1009 } 1010 1011 if ((item = dlist_new_item((void *)(uintptr_t)sp)) == NULL) { 1012 return (ENOMEM); 1013 } 1014 1015 _virtual_slices = dlist_append(item, _virtual_slices, AT_HEAD); 1016 1017 oprintf(OUTPUT_DEBUG, 1018 gettext(" created virtual slice %s start: %llu, size: %llu\n"), 1019 sname, startblk, sizeblks); 1020 1021 return (error); 1022} 1023 1024/* 1025 * FUNCTION: release_virtual_slices() 1026 * 1027 * PURPOSE: Helper which cleans up the module private list of virtual 1028 * slices. 1029 * 1030 * The descriptors for the virtual slices are cleaned up 1031 * in device_cache_util.free_cached_descriptors 1032 */ 1033void 1034release_virtual_slices() 1035{ 1036 dlist_free_items(_virtual_slices, NULL); 1037 _virtual_slices = NULL; 1038} 1039 1040/* 1041 * FUNCTION: disk_add_virtual_slice(dm_descriptor_t disk, 1042 * dm_descriptor_t slice) 1043 * 1044 * INPUT: disk - a dm_descriptor_t disk handle 1045 * slice - a dm_descriptor_t virtual slice handle 1046 * 1047 * RETURNS: int - 0 on success 1048 * !0 otherwise 1049 * 1050 * PURPOSE: Helper which adds a virtual slice to the input disk's 1051 * list of virtual slices. 1052 * 1053 * The disk's virtual slice dm_descriptor_t handles are 1054 * stored in the disk's nvpair attribute list. 1055 */ 1056static int 1057disk_add_virtual_slice( 1058 dm_descriptor_t disk, 1059 dm_descriptor_t slice) 1060{ 1061 nvlist_t *attrs = NULL; 1062 uint64_t *old_slices = NULL; 1063 uint64_t *new_slices = NULL; 1064 uint_t nelem = 0; 1065 int i = 0; 1066 int error = 0; 1067 1068 if ((error = get_cached_attributes(disk, &attrs)) != 0) { 1069 return (error); 1070 } 1071 1072 if ((error = get_uint64_array( 1073 attrs, ATTR_VIRTUAL_SLICES, &old_slices, &nelem)) != 0) { 1074 if (error != ENOENT) { 1075 return (error); 1076 } 1077 error = 0; 1078 } 1079 1080 /* make a new array */ 1081 new_slices = (uint64_t *)calloc(nelem + 1, sizeof (uint64_t)); 1082 if (new_slices != NULL) { 1083 1084 for (i = 0; i < nelem; i++) { 1085 new_slices[i] = old_slices[i]; 1086 } 1087 new_slices[i] = slice; 1088 1089 error = set_uint64_array( 1090 attrs, ATTR_VIRTUAL_SLICES, new_slices, nelem); 1091 1092 free(new_slices); 1093 1094 } else { 1095 error = ENOMEM; 1096 } 1097 1098 return (error); 1099} 1100 1101/* 1102 * FUNCTION: disk_has_virtual_slices(dm_descriptor_t disk, boolean_t *bool) 1103 * 1104 * INPUT: disk - a dm_descriptor_t disk handle 1105 * 1106 * OUTPUT: bool - B_TRUE - if the disk has virtual slices 1107 * B_FALSE - otherwise 1108 * 1109 * RETURNS: int - 0 on success 1110 * !0 otherwise 1111 * 1112 * PURPOSE: Helper which determines if the input disk has virtual slices. 1113 * 1114 * If a disk has virtual slices, their dm_descriptor_t handles 1115 * will be stored in the disk's nvpair attribute list. 1116 */ 1117static int 1118disk_has_virtual_slices( 1119 dm_descriptor_t disk, 1120 boolean_t *bool) 1121{ 1122 nvlist_t *attrs = NULL; 1123 uint64_t *slices = NULL; 1124 uint_t nelem = 0; 1125 int error = 0; 1126 1127 *bool = B_FALSE; 1128 1129 if ((error = get_cached_attributes(disk, &attrs)) != 0) { 1130 return (error); 1131 } 1132 1133 if ((error = get_uint64_array( 1134 attrs, ATTR_VIRTUAL_SLICES, &slices, &nelem)) != 0) { 1135 if (error == ENOENT) { 1136 error = 0; 1137 nelem = 0; 1138 } else { 1139 /* count actual number of elements */ 1140 int i = 0; 1141 while (i < nelem) { 1142 if (slices[i] != -1) { 1143 ++i; 1144 } 1145 } 1146 nelem = i; 1147 } 1148 } 1149 1150 *bool = (nelem != 0); 1151 1152 return (error); 1153} 1154 1155/* 1156 * FUNCTION: disk_get_virtual_slices(dm_descriptor_t disk, boolean_t *bool) 1157 * 1158 * INPUT: disk - a dm_descriptor_t disk handle 1159 * 1160 * OUTPUT: list - a dlist_t list of dm_descriptor_t handles for the 1161 * disk's virtual slices. 1162 * 1163 * RETURNS: int - 0 on success 1164 * !0 otherwise 1165 * 1166 * PURPOSE: Helper which retrieves a list of the input disk's virtual 1167 * slices. 1168 * 1169 * If a disk has virtual slices, their dm_descriptor_t handles 1170 * will be stored in the disk's nvpair attribute list. 1171 */ 1172static int 1173disk_get_virtual_slices( 1174 dm_descriptor_t disk, 1175 dlist_t **list) 1176{ 1177 nvlist_t *attrs = NULL; 1178 uint64_t *slices = NULL; 1179 uint_t nelem = 0; 1180 int error = 0; 1181 int i = 0; 1182 1183 if ((error = get_cached_attributes(disk, &attrs)) != 0) { 1184 return (error); 1185 } 1186 1187 if ((error = get_uint64_array( 1188 attrs, ATTR_VIRTUAL_SLICES, &slices, &nelem)) != 0) { 1189 if (error != ENOENT) { 1190 return (error); 1191 } 1192 1193 return (0); 1194 } 1195 1196 for (i = 0; i < nelem && slices[i] != -1; i++) { 1197 dlist_t *item = NULL; 1198 1199 if ((item = dlist_new_item((void*)(uintptr_t)slices[i])) == NULL) { 1200 error = ENOMEM; 1201 break; 1202 } 1203 1204 *list = dlist_append(item, *list, AT_TAIL); 1205 } 1206 1207 return (error); 1208} 1209 1210/* 1211 * FUNCTION: is_virtual_slice(dm_descriptor_t desc) 1212 * 1213 * INPUT: desc - a dm_descriptor_t handle 1214 * 1215 * RETURNS: boolean_t - B_TRUE if the input descriptor is for 1216 * a virtual slice. 1217 * B_FALSE otherwise 1218 * 1219 * PURPOSE: Helper which determines whether the input descriptor 1220 * corresponds to a virtual slice. 1221 * 1222 * All virtual slices are stored in a module private list. 1223 * This list is iterated to see if it contains the input 1224 * descriptor. 1225 */ 1226boolean_t 1227is_virtual_slice( 1228 dm_descriptor_t desc) 1229{ 1230 return (dlist_contains(_virtual_slices, 1231 (void*)(uintptr_t)desc, compare_descriptors)); 1232} 1233 1234/* 1235 * FUNCTION: disk_get_available_slice_index(dm_descriptor_t disk, 1236 * uint32_t *newindex) 1237 * 1238 * INPUT: disk - a dm_descriptor_t handle for a disk 1239 * 1240 * OUTPUT: *newindex - a pointer to a uint32_t to hold the available 1241 * index. If no index is available, the value pointed 1242 * to is not modified. 1243 * 1244 * RETURNS: int - 0 on success 1245 * !0 otherwise. 1246 * 1247 * PURPOSE: examine the input disk's list of slices and find an unused 1248 * slice index. The replica slice (index 7 or 6) is always 1249 * off-limits -- it shows up as in use. Slice 0 should only 1250 * be used as a last resort. 1251 * 1252 * If an available index is found, it is stored into newindex. 1253 * Otherwise, newindex is unchanged. This allows the caller to 1254 * pass in an index and check if it has been modified on return. 1255 * 1256 * V_NUMPAR is used as the number of available slices, 1257 * SPARC systems have V_NUMPAR == 8, X86 have V_NUMPAR == 16. 1258 * 1259 * EFI disks have only 7. 1260 */ 1261int 1262disk_get_available_slice_index( 1263 dm_descriptor_t disk, 1264 uint32_t *newindex) 1265{ 1266 dlist_t *iter = NULL; 1267 dlist_t *slices = NULL; 1268 uint32_t index = 0; 1269 uint16_t *reserved = NULL; 1270 boolean_t *used = NULL; 1271 boolean_t is_efi = B_FALSE; 1272 int error = 0; 1273 int i = 0; 1274 int nslices = V_NUMPAR; 1275 1276 if (((error = disk_get_slices(disk, &slices)) != 0) || 1277 (error = disk_get_is_efi(disk, &is_efi)) != 0) { 1278 return (error); 1279 } 1280 1281 if (is_efi == B_TRUE) { 1282 /* limit possible indexes to 7 for EFI */ 1283 nslices = 7; 1284 } 1285 1286 used = (boolean_t *)calloc(nslices, sizeof (boolean_t)); 1287 if (used == NULL) { 1288 oprintf(OUTPUT_DEBUG, 1289 gettext("failed allocating slice index array\n"), 1290 NULL); 1291 return (ENOMEM); 1292 } 1293 1294 /* eliminate indexes that are reserved */ 1295 if ((error = disk_get_reserved_indexes(disk, &reserved)) != 0) { 1296 return (error); 1297 } 1298 1299 if (reserved != NULL) { 1300 for (i = 0; i < nslices; i++) { 1301 if (reserved[i] == 1) { 1302 used[i] = B_TRUE; 1303 } 1304 } 1305 } 1306 1307 /* eliminate slices that are in use (have a size > 0) */ 1308 /* 0 sized slices unused slices */ 1309 for (iter = slices; iter != NULL; iter = iter->next) { 1310 dm_descriptor_t sp = (uintptr_t)iter->obj; 1311 uint64_t size = 0; 1312 1313 ((error = slice_get_index(sp, &index)) != 0) || 1314 (error = slice_get_size_in_blocks(sp, &size)); 1315 if (error != 0) { 1316 return (error); 1317 } 1318 1319 if (size > 0) { 1320 used[(int)index] = B_TRUE; 1321 } 1322 } 1323 dlist_free_items(slices, NULL); 1324 1325 for (i = 0; i < nslices; i++) { 1326 1327 /* skip the index passed in */ 1328 if (i == *newindex) { 1329 continue; 1330 } 1331 1332 if (used[i] != B_TRUE) { 1333 index = i; 1334 break; 1335 } 1336 } 1337 1338 if (i != nslices) { 1339 /* return unused slice index */ 1340 *newindex = index; 1341 } 1342 1343 free((void *)used); 1344 1345 return (0); 1346} 1347 1348/* 1349 * FUNCTION: disk_get_media_type(dm_descriptor_t slice, uint32_t *type) 1350 * 1351 * INPUT: slice - a dm_descriptor_t handle for a disk 1352 * 1353 * OUTPUT: *type - a pointer to a uint32_t to hold the 1354 * current type value for the media on which 1355 * the input slice resides. 1356 * 1357 * RETURNS: int - 0 on success 1358 * !0 otherwise. 1359 * 1360 * PURPOSE: Retrieves the media type for the disk. 1361 * 1362 * Get the media associate with the input disk descriptor 1363 * and determine its type. 1364 */ 1365int 1366disk_get_media_type( 1367 dm_descriptor_t disk, 1368 uint32_t *type) 1369{ 1370 int error = 0; 1371 dm_descriptor_t *mdp = NULL; 1372 1373 mdp = dm_get_associated_descriptors(disk, DM_MEDIA, &error); 1374 (void) add_descriptors_to_free(mdp); 1375 1376 if (error != 0) { 1377 print_get_assoc_desc_error(disk, gettext("media"), error); 1378 } else { 1379 /* disk should have exactly 1 media */ 1380 if ((mdp != NULL) && (*mdp != NULL)) { 1381 nvlist_t *attrs = dm_get_attributes(*mdp, &error); 1382 if ((error == 0) && (attrs != NULL)) { 1383 error = get_uint32(attrs, DM_MTYPE, type); 1384 } 1385 1386 nvlist_free(attrs); 1387 } 1388 /* no media: removeable drive */ 1389 } 1390 1391 if (mdp != NULL) { 1392 free(mdp); 1393 } 1394 1395 return (error); 1396} 1397 1398/* 1399 * FUNCTION: disk_get_rpm(dm_descriptor_t disk, uint32_t *val) 1400 * disk_get_sync_speed(dm_descriptor_t disk, uint32_t *val) 1401 * disk_get_size_in_blocks(dm_descriptor_t disk, uint64_t *val) 1402 * disk_get_blocksize(dm_descriptor_t disk, uint64_t *val) 1403 * disk_get_ncylinders(dm_descriptor_t disk, uint64_t *val) 1404 * disk_get_nheads(dm_descriptor_t disk, uint64_t *val) 1405 * disk_get_nsectors(dm_descriptor_t disk, uint64_t *val) 1406 * disk_get_is_efi(dm_descriptor_t disk, boolean_t *val) 1407 * disk_get_is_online(dm_descriptor_t disk, boolean_t *val) 1408 * disk_get_media_type(dm_descriptor_t disk, uint32_t *type) 1409 * disk_get_has_fdisk(dm_descriptor_t disk, boolean_t *val) 1410 * disk_get_start_block(dm_descriptor_t disk, uint64_t *val) 1411 * 1412 * INPUT: disk - a dm_descriptor_t handle for a disk 1413 * 1414 * OUTPUT: *bool - a pointer to a variable of the appropriate 1415 * type to hold the current value for the attribute 1416 * of interest. 1417 * 1418 * RETURNS: int - 0 on success 1419 * !0 otherwise. 1420 * 1421 * PURPOSE: Wrappers around disk_get_XXX_attribute that know 1422 * which attribute needs to be retrieved and also handle 1423 * any necesasry type or units conversions. 1424 */ 1425static int 1426disk_get_rpm( 1427 dm_descriptor_t disk, 1428 uint32_t *val) 1429{ 1430 uint64_t val64 = 0; 1431 int error = 0; 1432 1433 if ((error = disk_get_uint64_attribute( 1434 disk, DM_RPM, &val64)) != 0) { 1435 return (error); 1436 } 1437 1438 *val = (uint32_t)val64; 1439 1440 return (error); 1441} 1442 1443int 1444disk_get_drive_type( 1445 dm_descriptor_t disk, 1446 uint32_t *val) 1447{ 1448 uint64_t val64 = 0; 1449 int error = 0; 1450 1451 if ((error = disk_get_uint64_attribute( 1452 disk, DM_DRVTYPE, &val64)) != 0) { 1453 return (error); 1454 } 1455 1456 *val = (uint32_t)val64; 1457 1458 return (error); 1459} 1460 1461static int 1462disk_get_sync_speed( 1463 dm_descriptor_t disk, 1464 uint32_t *val) 1465{ 1466 uint64_t val64 = 0; 1467 int error = 0; 1468 1469 if ((error = disk_get_uint64_attribute( 1470 disk, DM_SYNC_SPEED, &val64)) != 0) { 1471 return (error); 1472 } 1473 1474 *val = (uint32_t)val64; 1475 1476 return (error); 1477} 1478 1479/* returns number of usable blocks */ 1480int 1481disk_get_size_in_blocks( 1482 dm_descriptor_t disk, 1483 uint64_t *val) 1484{ 1485 return (disk_get_uint64_attribute(disk, DM_NACCESSIBLE, val)); 1486} 1487 1488/* returns first usable block on disk */ 1489int 1490disk_get_start_block( 1491 dm_descriptor_t disk, 1492 uint64_t *val) 1493{ 1494 return (disk_get_uint64_attribute(disk, DM_START, val)); 1495} 1496 1497int 1498disk_get_blocksize( 1499 dm_descriptor_t disk, 1500 uint64_t *val) 1501{ 1502 return (disk_get_uint64_attribute(disk, DM_BLOCKSIZE, val)); 1503} 1504 1505int 1506disk_get_ncylinders( 1507 dm_descriptor_t disk, 1508 uint64_t *val) 1509{ 1510 return (disk_get_uint64_attribute(disk, DM_NCYLINDERS, val)); 1511} 1512 1513int 1514disk_get_nheads( 1515 dm_descriptor_t disk, 1516 uint64_t *val) 1517{ 1518 return (disk_get_uint64_attribute(disk, DM_NHEADS, val)); 1519} 1520 1521int 1522disk_get_nsectors( 1523 dm_descriptor_t disk, 1524 uint64_t *val) 1525{ 1526 return (disk_get_uint64_attribute(disk, DM_NSECTORS, val)); 1527} 1528 1529/* 1530 * FUNCTION: disk_get_is_online(dm_descriptor_t disk, boolean_t *val) 1531 * 1532 * INPUT: disk - a dm_descriptor_t handle for a disk 1533 * 1534 * OUTPUT: *bool - a pointer to a boolean_t to hold the result. 1535 * 1536 * RETURNS: int - 0 on success 1537 * !0 otherwise. 1538 * 1539 * PURPOSE: Determine if the input disk is "online". 1540 * 1541 * Check the status bit of the drive, if it is 1 the drive 1542 * is online, if it is 0 the drive is offline. 1543 */ 1544int 1545disk_get_is_online( 1546 dm_descriptor_t disk, 1547 boolean_t *val) 1548{ 1549 uint64_t status = 0; 1550 int error = 0; 1551 1552 *val = B_FALSE; 1553 1554 error = disk_get_uint64_attribute(disk, DM_STATUS, &status); 1555 if (error == 0) { 1556 *val = (status == 1) ? B_TRUE : B_FALSE; 1557 } 1558 1559 return (error); 1560} 1561 1562/* 1563 * FUNCTION: disk_get_is_efi(dm_descriptor_t disk, boolean_t *bool) 1564 * 1565 * INPUT: disk - a dm_descriptor_t handle for a disk 1566 * 1567 * OUTPUT: *bool - a pointer to a boolean_t to hold the result. 1568 * 1569 * RETURNS: int - 0 on success 1570 * !0 otherwise. 1571 * 1572 * PURPOSE: Determine if the input disk is labeled with an EFI label. 1573 * 1574 * The label type is actually a property of the media 1575 * associated with the disk, so retrieve the media and 1576 * check if it is EFI labeled. 1577 */ 1578int 1579disk_get_is_efi( 1580 dm_descriptor_t disk, 1581 boolean_t *bool) 1582{ 1583 return (disk_get_boolean_attribute(disk, DM_EFI, bool)); 1584} 1585 1586/* 1587 * FUNCTION: disk_get_has_fdisk(dm_descriptor_t disk, boolean_t *bool) 1588 * 1589 * INPUT: disk - a dm_descriptor_t handle for a disk 1590 * 1591 * OUTPUT: *bool - a pointer to a boolean_t to hold the result. 1592 * 1593 * RETURNS: int - 0 on success 1594 * !0 otherwise. 1595 * 1596 * PURPOSE: Determine if the input disk has an FDISK partition. 1597 */ 1598int 1599disk_get_has_fdisk( 1600 dm_descriptor_t disk, 1601 boolean_t *bool) 1602{ 1603 return (disk_get_boolean_attribute(disk, DM_FDISK, bool)); 1604} 1605 1606/* 1607 * FUNCTION: disk_get_has_solaris_partition(dm_descriptor_t disk, boolean_t *bool) 1608 * 1609 * INPUT: disk - a dm_descriptor_t handle for a disk 1610 * 1611 * OUTPUT: *bool - a pointer to a boolean_t to hold the result. 1612 * 1613 * RETURNS: int - 0 on success 1614 * !0 otherwise. 1615 * 1616 * PURPOSE: Determine if the input disk has a Solaris FDISK partition. 1617 */ 1618int 1619disk_get_has_solaris_partition( 1620 dm_descriptor_t disk, 1621 boolean_t *bool) 1622{ 1623 boolean_t has_fdisk = B_FALSE; 1624 int error = 0; 1625 1626 if ((error = disk_get_has_fdisk(disk, &has_fdisk)) != 0) { 1627 return (error); 1628 } 1629 1630 *bool = B_FALSE; 1631 1632 if (has_fdisk == B_TRUE) { 1633 /* get disk's media */ 1634 dm_descriptor_t *media; 1635 media = dm_get_associated_descriptors(disk, DM_MEDIA, &error); 1636 (void) add_descriptors_to_free(media); 1637 if (error != 0) { 1638 print_get_assoc_desc_error(disk, gettext("media"), error); 1639 } else if ((media != NULL) && (*media != NULL)) { 1640 /* get media's partitions */ 1641 dm_descriptor_t *parts; 1642 parts = dm_get_associated_descriptors( 1643 media[0], DM_PARTITION, &error); 1644 (void) add_descriptors_to_free(parts); 1645 if (error != 0) { 1646 print_get_assoc_desc_error(media[0], 1647 gettext("partitions"), error); 1648 } else { 1649 /* search partitions for one with type Solaris */ 1650 int i = 0; 1651 for (; (parts != NULL) && (parts[i] != NULL) && 1652 (error == 0) && (*bool == B_FALSE); i++) { 1653 nvlist_t *attrs = dm_get_attributes(parts[i], &error); 1654 uint32_t ptype = 0; 1655 if ((error == 0) && (attrs != NULL)) { 1656 error = get_uint32(attrs, DM_PTYPE, &ptype); 1657 if ((error == 0) && 1658 (ptype == SUNIXOS || ptype == SUNIXOS2)) { 1659 *bool = B_TRUE; 1660 } 1661 } 1662 nvlist_free(attrs); 1663 } 1664 } 1665 1666 free(parts); 1667 free(media); 1668 } 1669 1670 /* if there was no media, it was a removeable drive */ 1671 } 1672 1673 return (error); 1674} 1675 1676static int 1677disk_get_boolean_attribute( 1678 dm_descriptor_t disk, 1679 char *attr, 1680 boolean_t *bool) 1681{ 1682 nvlist_t *attrs = NULL; 1683 int error = 0; 1684 1685 *bool = B_FALSE; 1686 1687 if ((strcmp(attr, DM_EFI) == 0) || 1688 (strcmp(attr, DM_FDISK) == 0)) { 1689 1690 /* 1691 * these attributes are actually on the media, 1692 * not the disk... so get the media descriptor 1693 * for this disk 1694 */ 1695 dm_descriptor_t *media; 1696 1697 media = dm_get_associated_descriptors(disk, DM_MEDIA, &error); 1698 (void) add_descriptors_to_free(media); 1699 1700 if (error != 0) { 1701 print_get_assoc_desc_error(disk, gettext("media"), error); 1702 } else if ((media != NULL) && (*media != NULL)) { 1703 /* if there's no media, it is a removeable drive */ 1704 error = get_cached_attributes(media[0], &attrs); 1705 } 1706 free(media); 1707 1708 } else { 1709 error = get_cached_attributes(disk, &attrs); 1710 if (error != 0) { 1711 print_get_desc_attr_error(disk, gettext("drive"), attr, error); 1712 } 1713 } 1714 1715 if (error != 0) { 1716 return (error); 1717 } 1718 1719 if (nvlist_lookup_boolean(attrs, attr) == 0) { 1720 *bool = B_TRUE; 1721 } 1722 1723 return (error); 1724} 1725 1726static int 1727disk_get_uint64_attribute( 1728 dm_descriptor_t disk, 1729 char *attr, 1730 uint64_t *val) 1731{ 1732 nvlist_t *attrs = NULL; 1733 uint32_t ui32 = 0; 1734 int error = 0; 1735 1736 /* 1737 * these attributes are actually on the media, 1738 * not the disk... so get the media descriptor 1739 * for this disk 1740 */ 1741 if ((strcmp(attr, DM_SIZE) == 0) || 1742 (strcmp(attr, DM_START) == 0) || 1743 (strcmp(attr, DM_NACCESSIBLE) == 0) || 1744 (strcmp(attr, DM_BLOCKSIZE) == 0) || 1745 (strcmp(attr, DM_NCYLINDERS) == 0) || 1746 (strcmp(attr, DM_NHEADS) == 0) || 1747 (strcmp(attr, DM_NSECTORS) == 0)) { 1748 1749 dm_descriptor_t *media; 1750 1751 media = dm_get_associated_descriptors(disk, DM_MEDIA, &error); 1752 (void) add_descriptors_to_free(media); 1753 1754 if (error != 0) { 1755 print_get_assoc_desc_error(disk, gettext("media"), error); 1756 } else if ((media == NULL) || (*media == NULL)) { 1757 print_get_assoc_desc_error(disk, gettext("media"), error); 1758 error = -1; 1759 } else { 1760 error = get_cached_attributes(media[0], &attrs); 1761 free(media); 1762 } 1763 1764 } else { 1765 error = get_cached_attributes(disk, &attrs); 1766 if (error != 0) { 1767 print_get_desc_attr_error(disk, gettext("drive"), attr, error); 1768 } 1769 } 1770 1771 if (error != 0) { 1772 return (error); 1773 } 1774 1775 if (strcmp(attr, DM_SIZE) == 0 || 1776 strcmp(attr, DM_NACCESSIBLE) == 0 || 1777 strcmp(attr, DM_START) == 0) { 1778 error = get_uint64(attrs, attr, val); 1779 } else if (strcmp(attr, DM_BLOCKSIZE) == 0 || 1780 strcmp(attr, DM_NCYLINDERS) == 0 || 1781 strcmp(attr, DM_NHEADS) == 0 || 1782 strcmp(attr, DM_NSECTORS) == 0 || 1783 strcmp(attr, DM_RPM) == 0 || 1784 strcmp(attr, DM_DRVTYPE) == 0 || 1785 strcmp(attr, DM_SYNC_SPEED) == 0 || 1786 strcmp(attr, DM_STATUS) == 0) { 1787 error = get_uint32(attrs, attr, &ui32); 1788 *val = (uint64_t)ui32; 1789 } 1790 1791 return (error); 1792} 1793 1794/* 1795 * FUNCTION: group_similar_hbas(dlist_t *hbas, dlist_t **list) 1796 * 1797 * INPUT: hbas - a list of HBA dm_descriptor_t handles. 1798 * 1799 * OUTPUT: **list - a pointer to a list to hold the lists of HBAs 1800 * grouped by characteristics. 1801 * 1802 * RETURNS: int - 0 on success 1803 * !0 otherwise. 1804 * 1805 * PURPOSE: Examine the input HBAs and collate them into separate 1806 * lists, grouped by their type and the protocols they 1807 * support. 1808 * 1809 * The returned list of list is arranged in decreasing order 1810 * of preference, "better" HBAs come first. 1811 * 1812 * find all MPXIO controllers 1813 * find all similar FC HBAs 1814 * find all similar SCSI HBAs 1815 * fast{wide}80 1816 * fast{wide}40 1817 * fast{wide}20 1818 * clock uint32 ?? 1819 * find all similar ATA/IDE HBAs 1820 * find all similar USB HBAs 1821 */ 1822int 1823group_similar_hbas( 1824 dlist_t *hbas, 1825 dlist_t **list) 1826{ 1827 /* preference order of HBAs */ 1828 enum { 1829 HBA_FIBRE_MPXIO = 0, 1830 HBA_SCSI_MPXIO, 1831 HBA_FIBRE, 1832 HBA_SCSI_FW80, 1833 HBA_SCSI_FW40, 1834 HBA_SCSI_FW20, 1835 HBA_SCSI_F80, 1836 HBA_SCSI_F40, 1837 HBA_SCSI_F20, 1838 HBA_SCSI, 1839 HBA_ATA, 1840 HBA_USB, 1841 HBA_LAST 1842 }; 1843 1844 dlist_t *groups = NULL; 1845 dlist_t *iter = NULL; 1846 dlist_t *item = NULL; 1847 dlist_t *lists[HBA_LAST]; 1848 1849 int error = 0; 1850 int i = 0; 1851 1852 (void) memset(lists, '\0', HBA_LAST * sizeof (dlist_t *)); 1853 1854 for (iter = hbas; 1855 (iter != NULL) && (error == 0); 1856 iter = iter->next) { 1857 1858 dm_descriptor_t hba = (uintptr_t)iter->obj; 1859 char *type = NULL; 1860 1861 /* if item doesn't go into a list it must be freed */ 1862 if ((item = dlist_new_item((void *)(uintptr_t)hba)) == NULL) { 1863 error = ENOMEM; 1864 continue; 1865 } 1866 1867 if ((error = hba_get_type(hba, &type)) != 0) { 1868 free(item); 1869 continue; 1870 } 1871 1872 if (strcmp(type, DM_CTYPE_FIBRE) == 0) { 1873 1874 boolean_t ismpxio = B_FALSE; 1875 1876 if ((error = hba_is_multiplex(hba, &ismpxio)) == 0) { 1877 if (ismpxio) { 1878 lists[HBA_FIBRE_MPXIO] = 1879 dlist_append(item, 1880 lists[HBA_FIBRE_MPXIO], AT_TAIL); 1881 } else { 1882 lists[HBA_FIBRE] = 1883 dlist_append(item, 1884 lists[HBA_FIBRE], AT_TAIL); 1885 } 1886 } else { 1887 free(item); 1888 } 1889 1890 } else if (strcmp(type, DM_CTYPE_SCSI) == 0) { 1891 1892 /* determine subtype */ 1893 boolean_t iswide = B_FALSE; 1894 boolean_t ismpxio = B_FALSE; 1895 boolean_t is80 = B_FALSE; 1896 boolean_t is40 = B_FALSE; 1897 boolean_t is20 = B_FALSE; 1898 1899 ((error = hba_supports_wide(hba, &iswide)) != 0) || 1900 (error = hba_is_multiplex(hba, &ismpxio)) || 1901 (error = hba_is_fast_80(hba, &is80)) || 1902 (error = hba_is_fast_40(hba, &is40)) || 1903 (error = hba_is_fast_20(hba, &is20)); 1904 1905 if (error == 0) { 1906 1907 if (ismpxio) { 1908 1909 lists[HBA_SCSI_MPXIO] = 1910 dlist_append(item, 1911 lists[HBA_SCSI_MPXIO], AT_TAIL); 1912 1913 } else if (is80) { 1914 1915 if (iswide) { 1916 lists[HBA_SCSI_FW80] = 1917 dlist_append(item, 1918 lists[HBA_SCSI_FW80], AT_TAIL); 1919 } else { 1920 lists[HBA_SCSI_F80] = 1921 dlist_append(item, 1922 lists[HBA_SCSI_F80], AT_TAIL); 1923 } 1924 1925 } else if (is40) { 1926 1927 if (iswide) { 1928 lists[HBA_SCSI_FW40] = 1929 dlist_append(item, 1930 lists[HBA_SCSI_FW40], AT_TAIL); 1931 } else { 1932 lists[HBA_SCSI_F40] = 1933 dlist_append(item, 1934 lists[HBA_SCSI_F40], AT_TAIL); 1935 } 1936 1937 } else if (is20) { 1938 1939 if (iswide) { 1940 lists[HBA_SCSI_FW20] = 1941 dlist_append(item, 1942 lists[HBA_SCSI_FW20], AT_TAIL); 1943 } else { 1944 lists[HBA_SCSI_F20] = 1945 dlist_append(item, 1946 lists[HBA_SCSI_F20], AT_TAIL); 1947 } 1948 1949 } else { 1950 lists[HBA_SCSI] = 1951 dlist_append(item, lists[HBA_SCSI], AT_TAIL); 1952 } 1953 1954 } else { 1955 free(item); 1956 } 1957 1958 } else if (strcmp(type, DM_CTYPE_ATA) == 0) { 1959 lists[HBA_ATA] = 1960 dlist_append(item, lists[HBA_ATA], AT_TAIL); 1961 } else if (strcmp(type, DM_CTYPE_USB) == 0) { 1962 lists[HBA_USB] = 1963 dlist_append(item, lists[HBA_USB], AT_TAIL); 1964 } else if (strcmp(type, DM_CTYPE_UNKNOWN) == 0) { 1965 oprintf(OUTPUT_DEBUG, 1966 gettext("found an HBA with unknown type\n")); 1967 free(item); 1968 } 1969 } 1970 1971 if (error == 0) { 1972 /* collect individual lists into a list of lists */ 1973 for (i = 0; (i < HBA_LAST) && (error == 0); i++) { 1974 if (lists[i] != NULL) { 1975 if ((item = dlist_new_item(lists[i])) == NULL) { 1976 error = ENOMEM; 1977 } else { 1978 groups = dlist_append(item, groups, AT_TAIL); 1979 } 1980 } 1981 } 1982 } 1983 1984 if (error != 0) { 1985 for (i = 0; i < HBA_LAST; i++) { 1986 dlist_free_items(lists[i], NULL); 1987 lists[i] = NULL; 1988 } 1989 1990 if (groups != NULL) { 1991 dlist_free_items(groups, NULL); 1992 } 1993 } 1994 1995 *list = groups; 1996 1997 return (error); 1998} 1999 2000/* 2001 * FUNCTION: hba_group_usable_disks(dm_descriptor_t hba, dlist_t **list) 2002 * 2003 * INPUT: hba - a dm_descriptor_t handle for a slice 2004 * 2005 * OUTPUT: **list - a pointer to a list to hold the lists of disks 2006 * grouped by characteristics. 2007 * 2008 * RETURNS: int - 0 on success 2009 * !0 otherwise. 2010 * 2011 * PURPOSE: Examine the disks assocated with the HBA and collates them 2012 * into separate lists, grouped by similar characteristics. 2013 * 2014 * get disks on HBA 2015 * check disks against _usable_disks list 2016 * group disks by similarities: 2017 * sync-speed uint32 2018 * wide boolean 2019 * rpm uint32 2020 * 2021 * XXX this function is currently unused. At some point, 2022 * it may be useful to group disks by performance 2023 * characteristics and use "better" disks before others. 2024 */ 2025int 2026hba_group_usable_disks( 2027 dm_descriptor_t hba, 2028 dlist_t **list) 2029{ 2030 dm_descriptor_t *disk = NULL; 2031 char *name = NULL; 2032 int i = 0; 2033 int error = 0; 2034 2035 disk = dm_get_associated_descriptors(hba, DM_DRIVE, &error); 2036 (void) add_descriptors_to_free(disk); 2037 2038 if (error != 0) { 2039 print_get_assoc_desc_error(hba, gettext("drive"), error); 2040 return (error); 2041 } else if ((disk == NULL) || (*disk == NULL)) { 2042 print_get_assoc_desc_error(hba, gettext("drive"), error); 2043 error = -1; 2044 } 2045 2046 for (i = 0; (disk[i] != NULL) && (error == 0); i++) { 2047 2048 uint32_t dtype = DM_DT_UNKNOWN; 2049 dlist_t *usable = NULL; 2050 2051 /* ignore non fixed media drives */ 2052 if (((error = disk_get_drive_type(disk[i], &dtype)) != 0) || 2053 (dtype != DM_DT_FIXED)) { 2054 continue; 2055 } 2056 2057 if (dlist_contains(usable, &disk[i], 2058 compare_descriptor_names) == B_TRUE) { 2059 2060 uint64_t bsize = 0; 2061 uint64_t ncyls = 0; 2062 uint64_t nsects = 0; 2063 uint64_t nheads = 0; 2064 uint32_t rpm = 0; 2065 uint32_t sync = 0; 2066 2067 name = NULL; 2068 ((error = get_display_name(disk[i], &name)) != 0) || 2069 (error = disk_get_blocksize(disk[i], &bsize)) || 2070 (error = disk_get_nheads(disk[i], &nheads)) || 2071 (error = disk_get_nsectors(disk[i], &nsects)) || 2072 (error = disk_get_ncylinders(disk[i], &ncyls)) || 2073 (error = disk_get_rpm(disk[i], &rpm)) || 2074 (error = disk_get_sync_speed(disk[i], &sync)); 2075 if (error != 0) { 2076 continue; 2077 } 2078 2079 oprintf(OUTPUT_VERBOSE, 2080 gettext("found an available disk: %s\n\t" 2081 "sync_speed = %u, rpm = %u, " 2082 "nsect = %llu, blksiz = %llu\n"), 2083 name, sync, rpm, nsects, bsize); 2084 2085 /* add to the appropriate list */ 2086 } 2087 } 2088 2089 if (disk != NULL) { 2090 free(disk); 2091 } 2092 2093 return (error); 2094} 2095 2096/* 2097 * FUNCTION: hba_get_n_avail_disks(dm_descriptor_t hba, uint16_t *val) 2098 * hba_set_n_avail_disks(dm_descriptor_t hba, uint16_t val) 2099 * 2100 * INPUT: hba - a dm_descriptor_t handle for a slice 2101 * 2102 * OUTPUT: *val - a pointer to a uint16_t to hold the current number 2103 * of available disks for the input HBA. 2104 * 2105 * RETURNS: int - 0 on success 2106 * !0 otherwise. 2107 */ 2108int 2109hba_set_n_avail_disks( 2110 dm_descriptor_t hba, 2111 uint16_t val) 2112{ 2113 nvlist_t *attrs; 2114 int error = 0; 2115 2116 ((error = get_cached_attributes(hba, &attrs)) != 0) || 2117 (error = set_uint16(attrs, ATTR_HBA_N_DISKS, val)); 2118 2119 return (error); 2120} 2121 2122int 2123hba_get_n_avail_disks( 2124 dm_descriptor_t hba, 2125 uint16_t *val) 2126{ 2127 nvlist_t *attrs; 2128 int error = 0; 2129 2130 *val = 0; 2131 2132 ((error = get_cached_attributes(hba, &attrs)) != 0) || 2133 (error = get_uint16(attrs, ATTR_HBA_N_DISKS, val)); 2134 2135 return (error); 2136} 2137 2138/* 2139 * FUNCTION: hba_get_type(dm_descriptor_t hba, char **type) 2140 * 2141 * INPUT: hba - a dm_descriptor_t handle for a HBA 2142 * 2143 * OUTPUT: **type - a char * to hold the current type value for 2144 * the HBA. 2145 * 2146 * RETURNS: int - 0 on success 2147 * !0 otherwise. 2148 * 2149 * PURPOSE: Retrieves the type attribute for the HBA. 2150 */ 2151int 2152hba_get_type( 2153 dm_descriptor_t hba, 2154 char **type) 2155{ 2156 nvlist_t *attrs; 2157 int error = 0; 2158 2159 *type = NULL; 2160 2161 ((error = get_cached_attributes(hba, &attrs)) != 0) || 2162 (error = get_string(attrs, DM_CTYPE, type)); 2163 2164 return (error); 2165} 2166 2167/* 2168 * FUNCTION: hba_is_fast(dm_descriptor_t hba, boolean_t *bool) 2169 * hba_is_fast20(dm_descriptor_t hba, boolean_t *bool) 2170 * hba_is_fast40(dm_descriptor_t hba, boolean_t *bool) 2171 * hba_is_fast80(dm_descriptor_t hba, boolean_t *bool) 2172 * hba_is_multiplex(dm_descriptor_t hba, boolean_t *bool) 2173 * hba_is_wide(dm_descriptor_t hba, boolean_t *bool) 2174 * 2175 * INPUT: hba - a dm_descriptor_t handle for a HBA 2176 * 2177 * OUTPUT: *bool - a pointer to a boolean_t to hold the 2178 * boolean value of the predicate. 2179 * 2180 * RETURNS: int - 0 on success 2181 * !0 otherwise. 2182 * 2183 * PURPOSE: Wrappers around hba_supports_protocol which determines 2184 * if the input HBA supports the protocol of interest. 2185 */ 2186int 2187hba_is_fast( 2188 dm_descriptor_t hba, 2189 boolean_t *bool) 2190{ 2191 return (hba_supports_protocol(hba, DM_FAST, bool)); 2192} 2193 2194int 2195hba_is_fast_20( 2196 dm_descriptor_t hba, 2197 boolean_t *bool) 2198{ 2199 return (hba_supports_protocol(hba, DM_FAST20, bool)); 2200} 2201 2202int 2203hba_is_fast_40( 2204 dm_descriptor_t hba, 2205 boolean_t *bool) 2206{ 2207 return (hba_supports_protocol(hba, DM_FAST40, bool)); 2208} 2209 2210int 2211hba_is_fast_80( 2212 dm_descriptor_t hba, 2213 boolean_t *bool) 2214{ 2215 return (hba_supports_protocol(hba, DM_FAST80, bool)); 2216} 2217 2218int 2219hba_is_multiplex( 2220 dm_descriptor_t hba, 2221 boolean_t *bool) 2222{ 2223 return (hba_supports_protocol(hba, DM_MULTIPLEX, bool)); 2224} 2225 2226int 2227hba_supports_wide( 2228 dm_descriptor_t hba, 2229 boolean_t *bool) 2230{ 2231 nvlist_t *attrs = NULL; 2232 int error = 0; 2233 2234 *bool = B_FALSE; 2235 2236 if ((error = get_cached_attributes(hba, &attrs)) != 0) { 2237 return (error); 2238 } 2239 2240 *bool = (0 == nvlist_lookup_boolean(attrs, DM_WIDE)); 2241 2242 return (error); 2243} 2244 2245/* 2246 * FUNCTION: hba_supports_protocol(dm_descriptor_t hba, char *attr, 2247 * boolean_t *bool) 2248 * 2249 * INPUT: hba - a dm_descriptor_t handle for a HBA 2250 * attr - a protocol "name" 2251 * 2252 * OUTPUT: *bool - a pointer to a boolean_t to hold the 2253 * boolean value of the predicate. 2254 * 2255 * RETURNS: int - 0 on success 2256 * !0 otherwise. 2257 * 2258 * PURPOSE: Checks the HBAs attributes to see if it is known to 2259 * support the protocol of interest. 2260 * 2261 * If the protocol is supported, it will have an entry 2262 * in the nvpair attribute list that can be retrieved. 2263 * 2264 * If the entry cannot be retrieved, the protocol is not 2265 * supported. 2266 */ 2267int 2268hba_supports_protocol( 2269 dm_descriptor_t hba, 2270 char *attr, 2271 boolean_t *bool) 2272{ 2273 nvlist_t *attrs = NULL; 2274 int error = 0; 2275 2276 *bool = B_FALSE; 2277 2278 if ((error = get_cached_attributes(hba, &attrs)) != 0) { 2279 return (error); 2280 } 2281 2282 *bool = (0 == nvlist_lookup_boolean(attrs, attr)); 2283 2284 return (error); 2285} 2286 2287/* 2288 * FUNCTION: slice_set_size(dm_descriptor_t slice, uint64_t size) 2289 * 2290 * INPUT: slice - a dm_descriptor_t handle for a slice 2291 * 2292 * OUTPUT: size - a uint64_t value representing the size of the 2293 * slice. 2294 * 2295 * RETURNS: int - 0 on success 2296 * !0 otherwise. 2297 * 2298 * PURPOSE: Wrapper around slice_set_uint64_attribute which converts 2299 * the input size in bytes to blocks prior to storing it. 2300 * 2301 * This function is used when an existing slice gets resized 2302 * to provide space for a new slice. It is necessary to update 2303 * the slice's size so that it is accurate. 2304 */ 2305int 2306slice_set_size( 2307 dm_descriptor_t slice, 2308 uint64_t size) 2309{ 2310 dm_descriptor_t disk = NULL; 2311 uint64_t blksize = 0; 2312 int error = 0; 2313 2314 ((error = slice_get_disk(slice, &disk)) != 0) || 2315 (error = disk_get_blocksize(disk, &blksize)) || 2316 (error = slice_set_size_in_blocks(slice, (uint64_t)(size / blksize))); 2317 2318 return (error); 2319} 2320 2321/* 2322 * FUNCTION: slice_set_size_in_blocks(dm_descriptor_t slice, uint64_t size) 2323 * 2324 * INPUT: slice - a dm_descriptor_t handle for a slice 2325 * 2326 * OUTPUT: size - a uint64_t value representing the size of the 2327 * slice. 2328 * 2329 * RETURNS: int - 0 on success 2330 * !0 otherwise. 2331 * 2332 * PURPOSE: Wrapper around slice_set_uint64_attribute to set the slice 2333 * size. 2334 * 2335 * This function is used when an existing slice gets resized 2336 * to provide space for a new slice. It is necessary to update 2337 * the slice's size so that it is accurate. 2338 */ 2339int 2340slice_set_size_in_blocks( 2341 dm_descriptor_t slice, 2342 uint64_t size) 2343{ 2344 return (slice_set_attribute(slice, DM_SIZE, size)); 2345} 2346 2347/* 2348 * FUNCTION: slice_set_start_block(dm_descriptor_t slice, uint64_t start) 2349 * 2350 * INPUT: slice - a dm_descriptor_t handle for a slice 2351 * 2352 * OUTPUT: size - a uint64_t value representing the start block of the 2353 * slice. 2354 * 2355 * RETURNS: int - 0 on success 2356 * !0 otherwise. 2357 * 2358 * PURPOSE: Wrapper around slice_set_attribute. 2359 * 2360 * This function is used when an existing slice gets adjusted 2361 * due to being resized or combined with another slice. 2362 */ 2363int 2364slice_set_start_block( 2365 dm_descriptor_t slice, 2366 uint64_t start) 2367{ 2368 return (slice_set_attribute(slice, DM_START, start)); 2369} 2370 2371/* 2372 * FUNCTION: slice_get_start_block(dm_descriptor_t slice, uint64_t *val) 2373 * slice_get_size_in_blocks(dm_descriptor_t slice, uint64_t *val) 2374 * slice_get_start(dm_descriptor_t slice, uint64_t *val) 2375 * slice_get_size(dm_descriptor_t slice, uint64_t *val) 2376 * slice_get_index(dm_descriptor_t slice, uint64_t *val) 2377 * 2378 * INPUT: slice - a dm_descriptor_t handle for a slice 2379 * 2380 * OUTPUT: *val - a pointer to a uint64_t to hold the 2381 * current value of the desired attribute. 2382 * 2383 * RETURNS: int - 0 on success 2384 * !0 otherwise. 2385 * 2386 * PURPOSE: Wrappers around slice_get_uint64_attribute which retrieve 2387 * specific attribute values. 2388 */ 2389int 2390slice_get_start_block( 2391 dm_descriptor_t slice, 2392 uint64_t *val) 2393{ 2394 return (slice_get_uint64_attribute(slice, DM_START, val)); 2395} 2396 2397int 2398slice_get_size_in_blocks( 2399 dm_descriptor_t slice, 2400 uint64_t *val) 2401{ 2402 return (slice_get_uint64_attribute(slice, DM_SIZE, val)); 2403} 2404 2405int 2406slice_get_start( 2407 dm_descriptor_t slice, 2408 uint64_t *val) 2409{ 2410 dm_descriptor_t disk = NULL; 2411 uint64_t blksize = 0; 2412 uint64_t nblks = 0; 2413 int error = 0; 2414 2415 ((error = slice_get_disk(slice, &disk)) != 0) || 2416 (error = disk_get_blocksize(disk, &blksize)) || 2417 (error = slice_get_start_block(slice, &nblks)); 2418 2419 if (error == 0) { 2420 *val = (blksize * nblks); 2421 } 2422 2423 return (error); 2424} 2425 2426int 2427slice_get_size( 2428 dm_descriptor_t slice, 2429 uint64_t *val) 2430{ 2431 dm_descriptor_t disk = NULL; 2432 uint64_t blksize = 0; 2433 uint64_t nblks = 0; 2434 int error = 0; 2435 2436 *val = 0; 2437 2438 ((error = slice_get_disk(slice, &disk)) != 0) || 2439 (error = slice_get_size_in_blocks(slice, &nblks)) || 2440 (error = disk_get_blocksize(disk, &blksize)); 2441 2442 if (error == 0) { 2443 *val = (blksize * nblks); 2444 } 2445 2446 return (error); 2447} 2448 2449int 2450slice_get_index( 2451 dm_descriptor_t slice, 2452 uint32_t *val) 2453{ 2454 uint64_t index = 0; 2455 int error = 0; 2456 2457 if ((error = slice_get_uint64_attribute( 2458 slice, DM_INDEX, &index)) != 0) { 2459 return (error); 2460 } 2461 2462 *val = (uint32_t)index; 2463 2464 return (0); 2465} 2466 2467/* 2468 * FUNCTION: slice_set_uint64_attribute(dm_descriptor_t slice, 2469 * char *attr, uint64_t val) 2470 * slice_get_uint64_attribute(dm_descriptor_t slice, 2471 * char *attr, uint64_t *val) 2472 * 2473 * INPUT: slice - a dm_descriptor_t handle for a slice 2474 * attr - a char * attribute name 2475 * val - auint64_t value 2476 * 2477 * OUTPUT: *val - a pointer to a uint64_t to hold the 2478 * current value of the named attribute. 2479 * 2480 * RETURNS: int - 0 on success 2481 * !0 otherwise. 2482 * 2483 * PURPOSE: Helpers to set/get the value for a slice's attribute. 2484 * 2485 * Consolidate the details of getting/setting slice 2486 * attributes. Some attributes are actually stored as 2487 * uint32_t or uint16_t values, these functions mask 2488 * the type conversions. 2489 */ 2490static int 2491slice_get_uint64_attribute( 2492 dm_descriptor_t slice, 2493 char *attr, 2494 uint64_t *val) 2495{ 2496 nvlist_t *attrs = NULL; 2497 uint32_t ui32 = 0; 2498 int error = 0; 2499 2500 if ((error = get_cached_attributes(slice, &attrs)) != 0) { 2501 return (error); 2502 } 2503 2504 if (strcmp(attr, DM_INDEX) == 0) { 2505 error = get_uint32(attrs, attr, &ui32); 2506 *val = (uint64_t)ui32; 2507 } else if (strcmp(attr, DM_START) == 0) { 2508 error = get_uint64(attrs, attr, val); 2509 } else if (strcmp(attr, DM_SIZE) == 0) { 2510 error = get_uint64(attrs, attr, val); 2511 } else if (strcmp(attr, ATTR_DISK_FOR_SLICE) == 0) { 2512 error = get_uint64(attrs, attr, val); 2513 } 2514 2515 if (error != 0) { 2516 print_get_desc_attr_error(slice, "slice", attr, error); 2517 } 2518 2519 return (error); 2520} 2521 2522/* 2523 * Set a slice attribute. The attribute is only set in the cached 2524 * copy of the slice's nvpair attribute list. This function does 2525 * NOT affect the underlying physical device. 2526 */ 2527static int 2528slice_set_attribute( 2529 dm_descriptor_t slice, 2530 char *attr, 2531 uint64_t val) 2532{ 2533 nvlist_t *attrs = NULL; 2534 int error = 0; 2535 2536 if ((error = get_cached_attributes(slice, &attrs)) != 0) { 2537 return (error); 2538 } 2539 2540 if (strcmp(attr, DM_INDEX) == 0) { 2541 error = set_uint32(attrs, attr, (uint32_t)val); 2542 } else if (strcmp(attr, DM_START) == 0) { 2543 error = set_uint64(attrs, attr, val); 2544 } else if (strcmp(attr, DM_SIZE) == 0) { 2545 error = set_uint64(attrs, attr, val); 2546 } else if (strcmp(attr, ATTR_DISK_FOR_SLICE) == 0) { 2547 error = set_uint64(attrs, attr, val); 2548 } 2549 2550 if (error != 0) { 2551 print_set_desc_attr_error(slice, "slice", attr, error); 2552 } 2553 2554 return (error); 2555} 2556 2557/* 2558 * FUNCTION: virtual_slice_get_disk(dm_descriptor_t slice, 2559 * dm_descriptor_t *diskp) 2560 * 2561 * INPUT: slice - a dm_descriptor_t virtual slice handle 2562 * diskp - pointer to a dm_descriptor_t disk handle 2563 * to return the slice's disk 2564 * 2565 * OUTPUT: the disk associated with the virtual slice. 2566 * 2567 * RETURNS: int - 0 on success 2568 * !0 otherwise 2569 * 2570 * PURPOSE: Helper which determines the disk that the input virtual 2571 * slice "belongs" to. 2572 * 2573 * The virtual slice's disk is stored in the slice's nvpair 2574 * attribute list when the slice gets created. 2575 */ 2576static int 2577virtual_slice_get_disk( 2578 dm_descriptor_t slice, 2579 dm_descriptor_t *diskp) 2580{ 2581 uint64_t disk = 0; 2582 int error = 0; 2583 2584 if ((error = slice_get_uint64_attribute( 2585 slice, ATTR_DISK_FOR_SLICE, &disk)) != 0) { 2586 return (error); 2587 } 2588 2589 *diskp = (dm_descriptor_t)disk; 2590 2591 if (disk == 0) { 2592 print_get_desc_attr_error(slice, "virtual slice", "disk", error); 2593 return (-1); 2594 } 2595 2596 return (0); 2597} 2598 2599/* 2600 * FUNCTION: slice_get_disk(dm_descriptor_t disk, dm_descriptor_t *diskp) 2601 * 2602 * INPUT: slice - a dm_descriptor_t handle for a slice 2603 * 2604 * OUTPUT: diskp - a pointer to a dm_descriptor_t to hold the 2605 * disk associated with the input slice 2606 * 2607 * RETURNS: int - 0 on success 2608 * !0 otherwise. 2609 * 2610 * PURPOSE: Helper which retrieves the disk for a slice device. 2611 * 2612 * A slice is actually connected to its disk thru an intermediate 2613 * device known as the "media". The media concept exists to 2614 * model drives with removeable disk media. For the purposes 2615 * of layout, such devices aren't relevant and the intermediate 2616 * media can mostly be ignored. 2617 */ 2618int 2619slice_get_disk( 2620 dm_descriptor_t slice, 2621 dm_descriptor_t *diskp) 2622{ 2623 dm_descriptor_t *media = NULL; 2624 2625 int i = 0; 2626 int error = 0; 2627 2628 *diskp = 0; 2629 2630 if (is_virtual_slice(slice)) { 2631 return (virtual_slice_get_disk(slice, diskp)); 2632 } 2633 2634 media = dm_get_associated_descriptors(slice, DM_MEDIA, &error); 2635 (void) add_descriptors_to_free(media); 2636 2637 if (error != 0) { 2638 print_get_assoc_desc_error(slice, gettext("media"), error); 2639 } else if ((media == NULL) || (*media == NULL)) { 2640 print_get_assoc_desc_error(slice, gettext("media"), error); 2641 error = -1; 2642 } 2643 2644 if (error != 0) { 2645 return (error); 2646 } 2647 2648 /* slice should have exactly 1 media */ 2649 for (i = 0; (media[i] != NULL) && (*diskp == NULL); i++) { 2650 /* get disk from media */ 2651 dm_descriptor_t *disks = NULL; 2652 disks = dm_get_associated_descriptors(media[i], DM_DRIVE, &error); 2653 (void) add_descriptors_to_free(disks); 2654 2655 if ((error == 0) && (disks != NULL) && (disks[0] != NULL)) { 2656 *diskp = disks[0]; 2657 } 2658 free(disks); 2659 } 2660 2661 if (media != NULL) { 2662 free(media); 2663 } 2664 2665 if (*diskp == 0) { 2666 print_get_desc_attr_error(slice, 2667 gettext("slice"), gettext("disk"), ENODEV); 2668 error = -1; 2669 } 2670 2671 return (error); 2672} 2673 2674/* 2675 * FUNCTION: slice_get_hbas(dm_descriptor_t slice, dlist_t **list) 2676 * 2677 * INPUT: slice - a dm_descriptor_t handle for a slice 2678 * 2679 * OUTPUT: list - a pointer to a dlist_t list to hold the 2680 * HBAs associated with the input slice 2681 * 2682 * RETURNS: int - 0 on success 2683 * !0 otherwise. 2684 * 2685 * PURPOSE: Helper which retrieves the known HBAs for a slice device. 2686 * 2687 */ 2688int 2689slice_get_hbas( 2690 dm_descriptor_t slice, 2691 dlist_t **list) 2692{ 2693 dm_descriptor_t disk = NULL; 2694 int error = 0; 2695 2696 *list = NULL; 2697 2698 ((error = slice_get_disk(slice, &disk)) != 0) || 2699 (error = disk_get_hbas(disk, list)); 2700 2701 if (*list == NULL) { 2702 print_get_desc_attr_error(slice, "slice", "HBA", ENODEV); 2703 error = -1; 2704 } 2705 2706 return (error); 2707} 2708 2709/* 2710 * FUNCTION: disk_get_associated_desc(dm_descriptor_t disk, 2711 * dm_desc_type_t assoc_type, char *assoc_type_str, 2712 * dlist_t **list) 2713 * 2714 * INPUT: disk - a dm_descriptor_t handle for a disk 2715 * assoc_type - the type of associated object to get 2716 * assoc_type_str - a char * string for the associated type 2717 * 2718 * OUTPUT: list - a pointer to a dlist_t list to hold the 2719 * objects associated with the input disk 2720 * 2721 * RETURNS: int - 0 on success 2722 * !0 otherwise. 2723 * 2724 * PURPOSE: Helper which retrieves the associated objects of the 2725 * requested type for a disk device. 2726 */ 2727static int 2728disk_get_associated_desc( 2729 dm_descriptor_t disk, 2730 dm_desc_type_t assoc_type, 2731 char *assoc_type_str, 2732 dlist_t **list) 2733{ 2734 int i = 0; 2735 int error = 0; 2736 2737 dm_descriptor_t *assoc = 2738 dm_get_associated_descriptors(disk, assoc_type, &error); 2739 2740 (void) add_descriptors_to_free(assoc); 2741 2742 if (error == 0) { 2743 for (i = 0; 2744 (assoc != NULL) && (assoc[i] != NULL) && (error == 0); 2745 i++) { 2746 dlist_t *item = dlist_new_item((void *)(uintptr_t)assoc[i]); 2747 if (item == NULL) { 2748 error = ENOMEM; 2749 } else { 2750 *list = dlist_append(item, *list, AT_TAIL); 2751 } 2752 } 2753 } else { 2754 print_get_assoc_desc_error(disk, assoc_type_str, error); 2755 } 2756 2757 if (assoc != NULL) { 2758 free(assoc); 2759 } 2760 2761 if (error != 0) { 2762 dlist_free_items(*list, NULL); 2763 *list = NULL; 2764 } 2765 2766 return (error); 2767} 2768 2769/* 2770 * FUNCTION: disk_get_hbas(dm_descriptor_t disk, dlist_t **list) 2771 * 2772 * INPUT: disk - a dm_descriptor_t handle for a disk 2773 * 2774 * OUTPUT: list - a pointer to a dlist_t list to hold the 2775 * HBAs associated with the input disk 2776 * 2777 * RETURNS: int - 0 on success 2778 * !0 otherwise. 2779 * 2780 * PURPOSE: Helper which retrieves the known HBAs for a disk device. 2781 * 2782 */ 2783int 2784disk_get_hbas( 2785 dm_descriptor_t disk, 2786 dlist_t **list) 2787{ 2788 return (disk_get_associated_desc(disk, DM_CONTROLLER, 2789 gettext("controller"), list)); 2790} 2791 2792/* 2793 * FUNCTION: disk_get_paths(dm_descriptor_t disk, dlist_t **list) 2794 * 2795 * INPUT: disk - a dm_descriptor_t handle for a disk 2796 * 2797 * OUTPUT: list - a pointer to a dlist_t list to hold the 2798 * paths associated with the input disk 2799 * 2800 * RETURNS: int - 0 on success 2801 * !0 otherwise. 2802 * 2803 * PURPOSE: Helper which retrieves the known paths for a disk device. 2804 * 2805 * Paths are managed by the MPXIO driver, they represent hardware 2806 * paths to the disk drive managed by the MPXIO and not visible 2807 * externally, unlike aliases which are. 2808 */ 2809int 2810disk_get_paths( 2811 dm_descriptor_t disk, 2812 dlist_t **list) 2813{ 2814 return (disk_get_associated_desc(disk, DM_PATH, 2815 gettext("path"), list)); 2816} 2817 2818/* 2819 * FUNCTION: disk_get_aliases(dm_descriptor_t disk, dlist_t **list) 2820 * 2821 * INPUT: disk - a dm_descriptor_t handle for a disk 2822 * 2823 * OUTPUT: list - a pointer to a dlist_t list to hold the 2824 * alias descriptors associated with the input disk 2825 * 2826 * RETURNS: int - 0 on success 2827 * !0 otherwise. 2828 * 2829 * PURPOSE: Helper which retrieves the known aliases for a disk device. 2830 * 2831 * Aliases are the different CTD names for the disk drive when 2832 * MPXIO is not enabled for multipathed drives. 2833 */ 2834int 2835disk_get_aliases( 2836 dm_descriptor_t disk, 2837 dlist_t **list) 2838{ 2839 return (disk_get_associated_desc(disk, DM_ALIAS, 2840 gettext("alias"), list)); 2841} 2842 2843/* 2844 * FUNCTION: compare_string_to_desc_name_or_alias( 2845 * void *str, void *desc) 2846 * 2847 * INPUT: str - opaque pointer 2848 * descr - opaque pointer 2849 * 2850 * RETURNS: int - <0 - if str < desc.name 2851 * 0 - if str == desc.name 2852 * >0 - if str > desc.name 2853 * 2854 * PURPOSE: dlist_t helper which compares a string to the name 2855 * and aliases associated with the input dm_descriptor_t 2856 * handle. 2857 * 2858 * Comparison is done via compare_device_names. 2859 */ 2860static int 2861compare_string_to_desc_name_or_alias( 2862 void *str, 2863 void *desc) 2864{ 2865 char *dname = NULL; 2866 int result = -1; 2867 2868 assert(str != (char *)NULL); 2869 assert(desc != (dm_descriptor_t)0); 2870 2871 (void) get_display_name((uintptr_t)desc, &dname); 2872 2873 /* try name first, then aliases */ 2874 if ((result = compare_device_names(str, dname)) != 0) { 2875 dlist_t *aliases = NULL; 2876 2877 (void) get_aliases((uintptr_t)desc, &aliases); 2878 if ((aliases != NULL) && (dlist_contains(aliases, 2879 str, compare_device_names) == B_TRUE)) { 2880 result = 0; 2881 } 2882 dlist_free_items(aliases, free); 2883 } 2884 2885 return (result); 2886} 2887 2888/* 2889 * FUNCTION: hba_get_by_name(char *name, dm_descriptor_t *hba) 2890 * 2891 * INPUT: name - a char * disk name 2892 * 2893 * OUTPUT: hba - a pointer to a dm_descriptor_t to hold the 2894 * HBA corresponding to the input name, if found 2895 * 2896 * RETURNS: int - 0 on success 2897 * !0 otherwise 2898 * 2899 * PURPOSE: Helper which iterates the known HBAs, searching for 2900 * the one matching name. 2901 * 2902 * If no HBA matches the name, 0 is returned and the 2903 * value of 'hba' will be (dm_descriptor_t)0; 2904 */ 2905int 2906hba_get_by_name( 2907 char *name, 2908 dm_descriptor_t *hba) 2909{ 2910 int error = 0; 2911 dlist_t *list = NULL; 2912 dlist_t *item = NULL; 2913 2914 *hba = (dm_descriptor_t)0; 2915 2916 if (name == NULL) { 2917 return (0); 2918 } 2919 2920 if ((error = get_known_hbas(&list)) != 0) { 2921 return (error); 2922 } 2923 2924 if ((item = dlist_find(list, name, 2925 compare_string_to_desc_name_or_alias)) != NULL) { 2926 *hba = (uintptr_t)item->obj; 2927 } 2928 2929 return (error); 2930} 2931 2932/* 2933 * FUNCTION: disk_get_by_name(char *name, dm_descriptor_t *disk) 2934 * 2935 * INPUT: name - a char * disk name 2936 * 2937 * OUTPUT: disk - a pointer to a dm_descriptor_t to hold the 2938 * disk corresponding to the input name, if found 2939 * 2940 * RETURNS: int - 0 on success 2941 * !0 otherwise. 2942 * 2943 * PURPOSE: Helper which retrieves a dm_descriptor_t disk handle 2944 * by name. 2945 * 2946 * If no disk is found for the input name, variations of 2947 * the name are tried. 2948 * 2949 * If the input name is unqualified, an appropriate leading 2950 * path is prepended. 2951 * 2952 * If the input name is qualified, the leading path is 2953 * removed. 2954 * 2955 * If no disk is found for the variations, 0 is returned 2956 * and the value of 'disk' will be (dm_descriptor_t)0; 2957 */ 2958int 2959disk_get_by_name( 2960 char *name, 2961 dm_descriptor_t *disk) 2962{ 2963 assert(name != (char *)NULL); 2964 2965 *disk = find_cached_descriptor(name); 2966 if (*disk == (dm_descriptor_t)0) { 2967 if (name[0] == '/') { 2968 /* fully qualified, try unqualified */ 2969 char *cp = strrchr(name, '/'); 2970 if (cp != NULL) { 2971 *disk = find_cached_descriptor(cp + 1); 2972 } 2973 } else { 2974 /* unqualified, try fully qualified */ 2975 char buf[MAXNAMELEN+1]; 2976 if (is_ctd_disk_name(name)) { 2977 (void) snprintf(buf, MAXNAMELEN, "/dev/dsk/%s", name); 2978 } else if (is_did_disk_name(name)) { 2979 (void) snprintf(buf, MAXNAMELEN, "/dev/did/dsk/%s", name); 2980 } 2981 *disk = find_cached_descriptor(buf); 2982 } 2983 } 2984 2985 /* 2986 * since the descriptor cache includes HBAs, disks and slices, 2987 * what gets returned may not be a disk... make sure it is 2988 */ 2989 if (*disk != (dm_descriptor_t)0) { 2990 if (dm_get_type(*disk) != DM_DRIVE) { 2991 *disk = (dm_descriptor_t)0; 2992 } 2993 } 2994 2995 return (0); 2996} 2997 2998/* 2999 * FUNCTION: slice_get_by_name(char *name, dm_descriptor_t *slice) 3000 * 3001 * INPUT: name - a char * slice name 3002 * 3003 * OUTPUT: slice - a pointer to a dm_descriptor_t to hold the 3004 * slice corresponding to the input name, if found. 3005 * 3006 * RETURNS: int - 0 on success 3007 * !0 otherwise. 3008 * 3009 * PURPOSE: Helper which iterates the known slices, searching for 3010 * the one matching name. 3011 * 3012 * If no slice is found for the input name, variations of 3013 * the name are tried. 3014 * 3015 * If the input name is unqualified, an appropriate leading 3016 * path is prepended. 3017 * 3018 * If the input name is qualified, the leading path is 3019 * removed. 3020 * 3021 * If no slice matches the variations, 0 is returned and the 3022 * value of 'slice' will be (dm_descriptor_t)0; 3023 */ 3024int 3025slice_get_by_name( 3026 char *name, 3027 dm_descriptor_t *slice) 3028{ 3029 assert(name != (char *)NULL); 3030 3031 *slice = find_cached_descriptor(name); 3032 if (*slice == (dm_descriptor_t)0) { 3033 if (name[0] == '/') { 3034 /* fully qualified, try unqualified */ 3035 char *cp = strrchr(name, '/'); 3036 if (cp != NULL) { 3037 *slice = find_cached_descriptor(cp + 1); 3038 } 3039 } else { 3040 /* unqualified, try fully qualified */ 3041 char buf[MAXNAMELEN+1]; 3042 if (is_ctd_slice_name(name) || is_ctd_like_slice_name(name) || 3043 is_bsd_like_slice_name(name)) { 3044 (void) snprintf(buf, MAXNAMELEN, "/dev/dsk/%s", name); 3045 } else if (is_did_slice_name(name)) { 3046 (void) snprintf(buf, MAXNAMELEN, "/dev/did/dsk/%s", name); 3047 } 3048 *slice = find_cached_descriptor(buf); 3049 } 3050 } 3051 3052 /* 3053 * since the descriptor cache includes HBAs, disks and slices, 3054 * what gets returned may not be a slice... make sure it is 3055 */ 3056 if (*slice != (dm_descriptor_t)0) { 3057 if (dm_get_type(*slice) != DM_SLICE && 3058 is_virtual_slice(*slice) != B_TRUE) { 3059 *slice = (dm_descriptor_t)0; 3060 } 3061 } 3062 3063 return (0); 3064} 3065 3066/* 3067 * FUNCTION: extract_hbaname(char *name, char **hbaname) 3068 * 3069 * INPUT: slicename - a char * device name 3070 * 3071 * OUTPUT: hbaname - a pointer to a char * to hold the hbaname derived 3072 * from the input name. 3073 * 3074 * RETURNS: int - 0 on success 3075 * !0 otherwise. 3076 * 3077 * PURPOSE: Helper which extracts the HBA name from the input name. 3078 * 3079 * If the input name is in ctd form, extracts just the cX part, 3080 * by truncating everything following the last 't'. 3081 * 3082 * Of course on X86, with IDE drives, there is no 't' in the 3083 * ctd name, so start by truncating everything following 'd' 3084 * and then look for 't'. 3085 * 3086 * The returned string must be passed to free(). 3087 */ 3088int 3089extract_hbaname( 3090 char *name, 3091 char **hbaname) 3092{ 3093 char *cp; 3094 3095 if (is_ctd_name(name)) { 3096 if ((*hbaname = strdup(name)) == NULL) { 3097 return (ENOMEM); 3098 } 3099 if ((cp = strrchr(*hbaname, 'd')) != NULL) { 3100 *cp = '\0'; 3101 } 3102 if ((cp = strrchr(*hbaname, 't')) != NULL) { 3103 *cp = '\0'; 3104 } 3105 } 3106 3107 return (0); 3108} 3109 3110/* 3111 * FUNCTION: extract_diskname(char *slicename, char **diskname) 3112 * 3113 * INPUT: slicename - a char * slice name 3114 * 3115 * OUTPUT: diskname - a pointer to a char * to hold the diskname derived 3116 * from the input slicename. 3117 * 3118 * RETURNS: int - 0 on success 3119 * !0 otherwise. 3120 * 3121 * PURPOSE: Helper which extracts the disk's name from a slice name. 3122 * 3123 * Checks to see if the input slicename is in ctd or did form, 3124 * and if so, truncates everything following the last 's'. 3125 * 3126 * If the input slicename is BSD-like, truncate the last 3127 * character (a-h). 3128 * 3129 * The returned string must be passed to free(). 3130 */ 3131int 3132extract_diskname( 3133 char *slicename, 3134 char **diskname) 3135{ 3136 char *cp; 3137 3138 if (is_ctd_slice_name(slicename) || is_did_slice_name(slicename) || 3139 is_ctd_like_slice_name(slicename)) { 3140 3141 if ((*diskname = strdup(slicename)) == NULL) { 3142 return (ENOMEM); 3143 } 3144 if ((cp = strrchr(*diskname, 's')) != NULL) { 3145 *cp = '\0'; 3146 } 3147 3148 } else if (is_bsd_like_slice_name(slicename)) { 3149 3150 if ((*diskname = strdup(slicename)) == NULL) { 3151 return (ENOMEM); 3152 } 3153 (*diskname)[strlen((*diskname)-1)] = '\0'; 3154 3155 } 3156 3157 return (0); 3158} 3159 3160/* 3161 * FUNCTION: get_disk_for_named_slice(char *slicename, 3162 * dm_descriptor_t disk) 3163 * 3164 * INPUT: slicename - a char * slice name 3165 * 3166 * OUTPUT: disk - a pointer to a dm_descriptor_t to hold the 3167 * disk corresponding to the input name, if found 3168 * 3169 * RETURNS: int - 0 on success 3170 * !0 otherwise. 3171 * 3172 * PURPOSE: Helper which locates the disk dm_descriptor_t handle for 3173 * the input slice name. 3174 * 3175 * If no disk matches the name, 0 is returned and the 3176 * value of 'disk' will be (dm_descriptor_t)0; 3177 */ 3178int 3179get_disk_for_named_slice( 3180 char *slicename, 3181 dm_descriptor_t *disk) 3182{ 3183 dm_descriptor_t slice = (dm_descriptor_t)0; 3184 int error = 0; 3185 3186 assert(slicename != NULL); 3187 3188 /* find disk for slice */ 3189 if ((error = slice_get_by_name(slicename, &slice)) == 0) { 3190 3191 if (slice != (dm_descriptor_t)0) { 3192 error = slice_get_disk(slice, disk); 3193 } else { 3194 /* named slice was created by layout: */ 3195 /* need to find disk by name */ 3196 char *dname; 3197 3198 error = extract_diskname(slicename, &dname); 3199 if (error == 0) { 3200 error = disk_get_by_name(dname, disk); 3201 } 3202 free(dname); 3203 } 3204 } 3205 3206 assert(*disk != (dm_descriptor_t)0); 3207 3208 return (error); 3209} 3210 3211/* 3212 * FUNCTION: disk_get_reserved_indexes(dm_descriptor_t disk, 3213 * uint16_t **array) 3214 * 3215 * INPUT: disk - a dm_descriptor_t disk handle 3216 * 3217 * RETURNS: int - 0 on success 3218 * !0 otherwise 3219 * 3220 * PURPOSE: Retrieves the input disk's list of reserved slice indices. 3221 * 3222 * The list of reserved indices is stored as an array in 3223 * the disk's nvpair attribute list. 3224 */ 3225static int 3226disk_get_reserved_indexes( 3227 dm_descriptor_t disk, 3228 uint16_t **array) 3229{ 3230 nvlist_t *attrs = NULL; 3231 uint_t nelem = 0; 3232 int error = 0; 3233 3234 if ((error = get_cached_attributes(disk, &attrs)) != 0) { 3235 return (error); 3236 } 3237 3238 if ((error = get_uint16_array( 3239 attrs, ATTR_RESERVED_INDEX, array, &nelem)) != 0) { 3240 if (error == ENOENT) { 3241 /* no reserved indices yet */ 3242 error = 0; 3243 } 3244 } 3245 3246 return (error); 3247} 3248 3249/* 3250 * FUNCTION: disk_reserve_index(dm_descriptor_t disk, uint16_t index) 3251 * 3252 * INPUT: disk - a disk dm_descirptor_t handle 3253 * undex - a VTOC slice index 3254 * 3255 * RETURNS: int - 0 on success 3256 * !0 otherwise 3257 * 3258 * PURPOSE: Reserves the input VTOC slice index for the input disk. 3259 * 3260 * The list of reserved indices is stored as an array in 3261 * the disk's nvpair attribute list. 3262 */ 3263int 3264disk_reserve_index( 3265 dm_descriptor_t disk, 3266 uint16_t index) 3267{ 3268 nvlist_t *attrs = NULL; 3269 uint16_t *oldindexes = NULL; 3270 uint16_t *newindexes = NULL; 3271 uint_t nelem = 0; 3272 int error = 0; 3273 int i = 0; 3274 3275 if ((error = get_cached_attributes(disk, &attrs)) != 0) { 3276 return (error); 3277 } 3278 3279 if ((error = get_uint16_array( 3280 attrs, ATTR_RESERVED_INDEX, &oldindexes, &nelem)) != 0) { 3281 if (error != ENOENT) { 3282 return (error); 3283 } 3284 /* no reserved indices yet */ 3285 error = 0; 3286 } 3287 3288 /* add new index */ 3289 newindexes = (uint16_t *)calloc(VTOC_SIZE, sizeof (uint16_t)); 3290 if (newindexes != NULL) { 3291 for (i = 0; i < nelem; i++) { 3292 newindexes[i] = oldindexes[i]; 3293 } 3294 newindexes[(int)index] = 1; 3295 3296 error = set_uint16_array(attrs, ATTR_RESERVED_INDEX, 3297 newindexes, VTOC_SIZE); 3298 3299 free(newindexes); 3300 } else { 3301 error = ENOMEM; 3302 } 3303 return (error); 3304} 3305 3306/* 3307 * FUNCTION: disk_release_index(dm_descriptor_t disk, uint16_t index) 3308 * 3309 * INPUT: disk - a disk dm_descirptor_t handle 3310 * undex - a VTOC slice index 3311 * 3312 * RETURNS: int - 0 on success 3313 * !0 otherwise 3314 * 3315 * PURPOSE: Releases the input VTOC slice index for the input disk. 3316 * The index was previously reserved by disk_reserve_index() 3317 */ 3318int 3319disk_release_index( 3320 dm_descriptor_t disk, 3321 uint16_t index) 3322{ 3323 nvlist_t *attrs = NULL; 3324 uint16_t *oldindexes = NULL; 3325 uint16_t *newindexes = NULL; 3326 uint_t nelem = 0; 3327 int error = 0; 3328 int i = 0; 3329 3330 if ((error = get_cached_attributes(disk, &attrs)) != 0) { 3331 return (error); 3332 } 3333 3334 if ((error = get_uint16_array( 3335 attrs, ATTR_RESERVED_INDEX, &oldindexes, &nelem)) != 0) { 3336 if (error != ENOENT) { 3337 return (error); 3338 } 3339 error = 0; 3340 } 3341 3342 newindexes = (uint16_t *)calloc(VTOC_SIZE, sizeof (uint16_t)); 3343 if (newindexes != NULL) { 3344 for (i = 0; i < nelem; i++) { 3345 newindexes[i] = oldindexes[i]; 3346 } 3347 3348 /* release index */ 3349 newindexes[(int)index] = 0; 3350 3351 error = set_uint16_array(attrs, ATTR_RESERVED_INDEX, 3352 newindexes, VTOC_SIZE); 3353 3354 free(newindexes); 3355 } else { 3356 error = ENOMEM; 3357 } 3358 3359 return (error); 3360} 3361 3362/* 3363 * FUNCTION: print_get_assoc_desc_error(dm_descriptor_t desc, char *which, 3364 * int error) 3365 * 3366 * INPUT: desc - a dm_descriptor_t handle 3367 * which - a char * indicating which association 3368 * error - an integer error value 3369 * 3370 * PURPOSE: Utility function to print an error message for a failed 3371 * call to dm_get_associated_descriptors(). 3372 * 3373 * Extracts the device's CTD name and formats an error message. 3374 */ 3375void 3376print_get_assoc_desc_error( 3377 dm_descriptor_t desc, 3378 char *which, 3379 int error) 3380{ 3381 char *name = ""; 3382 3383 (void) get_display_name(desc, &name); 3384 oprintf(OUTPUT_TERSE, 3385 gettext("dm_get_associated_descriptors(%s) for " 3386 "'%s' failed: %d\n"), 3387 which, name, error); 3388 3389 volume_set_error( 3390 gettext("Unexpected error getting associated " 3391 "descriptors for '%s'"), 3392 name); 3393} 3394 3395/* 3396 * FUNCTION: print_get_desc_attr_error(dm_descriptor_t desc, 3397 * char *devtype, char *attr, int error) 3398 * 3399 * INPUT: desc - a dm_descriptor_t handle 3400 * devtype - a char * device type that's being accessed 3401 * attr - a char * attribute name 3402 * error - an integer error value 3403 * 3404 * PURPOSE: Shared utility function to print an error message for a failed 3405 * call to retrieve an attribute for a descriptor. 3406 * 3407 * Extracts the device's CTD name and formats an error message. 3408 */ 3409void 3410print_get_desc_attr_error( 3411 dm_descriptor_t desc, 3412 char *devtype, 3413 char *attr, 3414 int error) 3415{ 3416 char *name = ""; 3417 3418 (void) get_display_name(desc, &name); 3419 oprintf(OUTPUT_TERSE, 3420 gettext("'%s' get attribute (%s.%s) error: %d\n"), 3421 name, devtype, attr, error); 3422 3423 volume_set_error( 3424 gettext("Unexpected error getting attribute '%s.%s' for '%s'"), 3425 devtype, attr, name); 3426} 3427 3428/* 3429 * FUNCTION: print_set_desc_attr_error(dm_descriptor_t desc, 3430 * char *devtype, char *attr, int error) 3431 * 3432 * INPUT: desc - a dm_descriptor_t handle 3433 * devtype - a char * device type that's being accessed 3434 * attr - a char * attribute name 3435 * error - an integer error value 3436 * 3437 * PURPOSE: Shared utility function to print an error message for a failed 3438 * call to set an attribute for a descriptor. 3439 * 3440 * Extracts the device's CTD name and formats an error message. 3441 */ 3442void 3443print_set_desc_attr_error( 3444 dm_descriptor_t desc, 3445 char *devtype, 3446 char *attr, 3447 int error) 3448{ 3449 char *name = ""; 3450 3451 (void) get_display_name(desc, &name); 3452 oprintf(OUTPUT_TERSE, 3453 gettext("'%s' set attribute (%s.%s) error: %d\n"), 3454 name, devtype, attr, error); 3455 3456 volume_set_error( 3457 gettext("Unexpected error setting attribute '%s.%s' for '%s'"), 3458 devtype, attr, name); 3459} 3460