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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <sys/types.h>
34 #include <sys/dktp/fdisk.h>
38 #include <libdiskmgt.h>
39 #include "meta_repartition.h"
41 #define _LAYOUT_DEVICE_UTIL_C
43 #include "volume_dlist.h"
44 #include "volume_error.h"
45 #include "volume_output.h"
46 #include "volume_nvpair.h"
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"
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.
61 #define VAL2STR(x) QUOTE(x)
63 /* private utilities for disks */
64 static int disk_get_uint64_attribute(
69 static int disk_get_boolean_attribute(
74 static int disk_get_rpm(
78 static int disk_get_sync_speed(
82 static int disk_has_virtual_slices(
86 static int disk_get_virtual_slices(
90 static int disk_get_reserved_indexes(
94 static int disk_get_associated_desc(
96 dm_desc_type_t assoc_type
,
100 /* utilities for slices */
101 static int slice_get_uint64_attribute(
102 dm_descriptor_t slice
,
106 static int slice_set_attribute(
107 dm_descriptor_t slice
,
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
118 static dlist_t
*_virtual_slices
= NULL
;
120 /* temporary implementation */
121 static int virtual_repartition_drive(
122 dm_descriptor_t disk
,
125 static int disk_add_virtual_slice(
126 dm_descriptor_t disk
,
127 dm_descriptor_t slice
);
129 static int virtual_slice_get_disk(
130 dm_descriptor_t slice
,
131 dm_descriptor_t
*diskp
);
134 * attribute names for layout private information stored in
135 * device nvpair attribute lists.
137 static char *ATTR_RESERVED_INDEX
= "vdu_reserved_index";
138 static char *ATTR_VIRTUAL_SLICES
= "vdu_virtual_slices";
139 static char *ATTR_DISK_FOR_SLICE
= "vdu_disk_for_slice";
140 static char *ATTR_DEV_CTD_NAME
= "vdu_device_ctd_name";
141 static char *ATTR_HBA_N_DISKS
= "vdu_hba_n_usable_disks";
144 * FUNCTION: is_ctd_like_slice_name(char *name)
145 * INPUT: name - a char *
147 * RETURNS: boolean_t - B_TRUE - if name follows an alternate slice
148 * naming scheme similar to CTD
149 * B_FALSE - otherwise
151 * PURPOSE: Determines if the input name is of the form XXXsNNN
155 is_ctd_like_slice_name(
161 boolean_t is
= B_FALSE
;
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
))) {
175 * FUNCTION: is_bsd_like_slice_name(char *name)
176 * INPUT: name - a char *
178 * RETURNS: boolean_t - B_TRUE - if name follows an alternate slice
179 * BSD-like naming scheme
180 * B_FALSE - otherwise
182 * PURPOSE: Determines if the input name is of the form XXXNNN[a-h]
186 is_bsd_like_slice_name(
191 boolean_t is
= B_FALSE
;
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
))) {
205 * FUNCTION: is_did_name(char *name)
206 * INPUT: name - a char *
208 * RETURNS: boolean_t - B_TRUE - if name is from the DID namespace
209 * B_FALSE - otherwise
211 * PURPOSE: Determines if the input name is from the DID namespace.
217 return (is_did_slice_name(name
) || is_did_disk_name(name
));
221 * FUNCTION: is_did_slice_name(char *name)
222 * INPUT: name - a char *
224 * RETURNS: boolean_t - B_TRUE - if name represents a slice from the DID
226 * B_FALSE - otherwise
228 * PURPOSE: Determines if the input name is a slice from the DID namespace.
236 boolean_t is
= B_FALSE
;
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
))) {
249 * FUNCTION: is_did_disk_name(char *name)
250 * INPUT: name - a char *
252 * RETURNS: boolean_t - B_TRUE - if name represents a disk from the DID
254 * B_FALSE - otherwise
256 * PURPOSE: Determines if the input name is a disk from the DID namespace.
264 boolean_t is
= B_FALSE
;
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
))) {
277 * FUNCTION: is_ctd_name(char *name)
278 * INPUT: name - a char *
280 * RETURNS: boolean_t - B_TRUE - if name is from the CTD namespace
281 * B_FALSE - otherwise
283 * PURPOSE: Determines if the input name is from the CTD namespace.
285 * {/dev/dsk/, /dev/rdsk/}cXtXdXsX
286 * {/dev/dsk/, /dev/rdsk/}cXtXdX
287 * {/dev/dsk/, /dev/rdsk/}cXdXsX
288 * {/dev/dsk/, /dev/rdsk/}cXdX
294 return (is_ctd_slice_name(name
) || is_ctd_disk_name(name
) ||
295 is_ctd_target_name(name
) || is_ctd_ctrl_name(name
));
299 * FUNCTION: is_ctd_slice_name(char *name)
300 * INPUT: name - a char *
302 * RETURNS: boolean_t - B_TRUE - if name represents a slice from the CTD
304 * B_FALSE - otherwise
306 * PURPOSE: Determines if the input name is a slice name from the
309 * {/dev/dsk/, /dev/rdsk/}cXt<WWN>dXsX
310 * {/dev/dsk/, /dev/rdsk/}cXtXdXsX
311 * {/dev/dsk/, /dev/rdsk/}cXdXsX
317 uint_t c
= 0, t
= 0, d
= 0, s
= 0;
318 char buf
[MAXNAMELEN
+1];
320 boolean_t is
= B_FALSE
;
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
))) {
332 (sscanf(name
, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
334 sscanf(name
, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
336 sscanf(name
, "c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
337 &c
, buf
, &l
) == 2) && (l
== strlen(name
))) {
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
))) {
345 char wwn
[MAXNAMELEN
+2];
347 /* buf ends with "dXsX", truncate at the 'd' */
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
))) {
362 * FUNCTION: is_ctd_disk_name(char *name)
363 * INPUT: name - a char *
365 * RETURNS: boolean_t - B_TRUE - if name represents a disk from the CTD
367 * B_FALSE - otherwise
369 * PURPOSE: Determines if the input name is a disk name from the
372 * {/dev/dsk/, /dev/rdsk/}cXt<WWN>dX
373 * {/dev/dsk/, /dev/rdsk/}cXtXdX
374 * {/dev/dsk/, /dev/rdsk/}cXdX
380 uint_t c
= 0, t
= 0, d
= 0;
382 char buf
[MAXNAMELEN
+1];
383 boolean_t is
= B_FALSE
;
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
))) {
393 } else if ((sscanf(name
, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
395 sscanf(name
, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
397 sscanf(name
, "c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
398 &c
, buf
, &l
) == 2) && (l
== strlen(name
))) {
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
))) {
406 char wwn
[MAXNAMELEN
+2];
408 /* buf ends with "dX", truncate at the 'd' */
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
))) {
423 * FUNCTION: is_ctd_disk_name(char *name)
424 * INPUT: name - a char *
426 * RETURNS: boolean_t - B_TRUE - if name represents a target from the CTD
428 * B_FALSE - otherwise
430 * PURPOSE: Determines if the input name is a target name from the
433 * {/dev/dsk/, /dev/rdsk/}cXt<WWN>
434 * {/dev/dsk/, /dev/rdsk/}cXtX
442 char buf
[MAXNAMELEN
+1];
443 boolean_t is
= B_FALSE
;
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
))) {
451 (sscanf(name
, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
453 sscanf(name
, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
455 sscanf(name
, "c%ut%" VAL2STR(MAXNAMELEN
) "s%n",
456 &c
, &buf
, &l
) == 2) && (l
== strlen(name
))) {
458 char wwn
[MAXNAMELEN
+2];
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
))) {
471 * FUNCTION: is_ctd_ctrl_name(char *name)
472 * INPUT: name - a char *
474 * RETURNS: boolean_t - B_TRUE - if name represents a controller/hba
475 * from the CTD namespace
476 * B_FALSE - otherwise
478 * PURPOSE: Determines if the input name is an HBA name from the
481 * {/dev/dsk/, /dev/rdsk/}cX
489 boolean_t is
= B_FALSE
;
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
))) {
502 * FUNCTION: set_display_name(dm_descriptor_t desc, char *name)
503 * get_display_name(dm_descriptor_t desc, char **name)
505 * INPUT: desc - a dm_descriptor_t handle for a device
506 * name - a char * name
508 * OUTPUT: **name - a pointer to a char * to hold the display
509 * name associated with the input descriptor.
511 * RETURNS: int - 0 on success
514 * PURPOSE: Helpers to set/get the input descriptor's display name.
516 * Only slices, disks and HBAs should have display names.
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.
522 * An entry is added in the name->descriptor cache
523 * so the descriptor can be found by name quickly.
527 dm_descriptor_t desc
,
530 nvlist_t
*attrs
= NULL
;
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
));
542 dm_descriptor_t desc
,
545 nvlist_t
*attrs
= NULL
;
548 ((error
= get_cached_attributes(desc
, &attrs
)) != 0) ||
549 (error
= get_string(attrs
, ATTR_DEV_CTD_NAME
, name
));
555 * FUNCTION: disk_get_slices(dm_descriptor_t disk, dlist_t **list)
557 * INPUT: disk - a dm_descriptor_t handle for a disk
559 * OUTPUT: *list - a pointer to list to hold the results.
561 * RETURNS: int - 0 on success
564 * PURPOSE: Collect all of the known slices for the input disk.
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.
572 dm_descriptor_t disk
,
575 dm_descriptor_t
*media
= NULL
;
576 boolean_t
virtual = B_FALSE
;
582 if ((error
= disk_has_virtual_slices(disk
, &virtual)) != 0) {
586 if (virtual == B_TRUE
) {
587 error
= disk_get_virtual_slices(disk
, list
);
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
);
595 /* if there's no media, this is a removeable drive */
596 if (media
!= NULL
&& *media
!= NULL
) {
598 /* examine media's slices... */
599 dm_descriptor_t
*slices
= NULL
;
600 slices
= dm_get_associated_descriptors(*media
,
602 (void) add_descriptors_to_free(slices
);
605 print_get_assoc_desc_error(disk
, gettext("slice"), error
);
607 for (i
= 0; (slices
[i
] != NULL
) && (error
== 0); i
++) {
609 dlist_new_item((void *)(uintptr_t)slices
[i
]);
613 *list
= dlist_append(item
, *list
, AT_TAIL
);
621 print_get_assoc_desc_error(disk
, gettext("media"), error
);
631 *list
= _virtual_slices
;
637 * FUNCTION: virtual_repartition_drive(dm_descriptor_t disk,
640 * INPUT: disk - the disk to be virtually repartitioned
642 * OUTPUT: vtocp - a poitner to a mdvtoc struct to hold the results
644 * RETURNS: int - 0 on success
647 * PURPOSE: Helper which emulates the repartitioning that is done
648 * when a disk is added to a diskset.
650 * Modified version of meta_partition_drive which uses info
651 * from libdiskmgt to accomplish the repartitioning.
653 * This exists to allow the layout module to run with a
654 * simulated hardware environment.
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
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.
674 virtual_repartition_drive(
675 dm_descriptor_t disk
,
678 uint_t replicaslice
= 7;
679 unsigned long long cylsize
;
680 unsigned long long drvsize
;
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
;
689 boolean_t efi
= B_FALSE
;
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.
700 ressize
= MD_DBSIZE
+ VTOC_SIZE
;
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
));
716 * Both cylsize and drvsize are in units of disk sectors.
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
727 cylsize
= ((unsigned long long)nheads
) * nsects
;
728 drvsize
= cylsize
* ncyls
;
731 * How many cylinders must we reserve for slice seven to
732 * ensure that it meets the previously calculated minimum
735 reservedcyl
= (ressize
+ cylsize
- 1) / cylsize
;
738 * It seems unlikely that someone would pass us too small a
739 * disk, but it's still worth checking for...
741 if (reservedcyl
>= ncyls
) {
743 gettext("disk is too small to hold a metadb replica"));
748 replica_size
= reservedcyl
* cylsize
;
749 data_start
= reservedcyl
* cylsize
;
750 data_size
= drvsize
- (reservedcyl
* cylsize
);
753 * fill in the proposed VTOC information.
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
;
770 * FUNCTION: create_virtual_slices(dlist_t *disks)
772 * INPUT: possibles - a list of dm_descriptor_t disk handles for
773 * disks known to be available for use by layout.
775 * SIDEEFFECT: populates the private of virtual slices.
777 * RETURNS: int - 0 on success
780 * PURPOSE: Helper which creates virtual slices for each disk which
781 * could be added to a diskset if necessary...
783 * Iterate the input list of available disks and see what the
784 * slicing would be if the disk were added to a diskset.
786 * For the resulting slices, create virtual slice descriptors
787 * and attributes for these slices and add them to the list of
791 create_virtual_slices(
796 boolean_t sim
= B_FALSE
;
797 static char *simfile
= "METASSISTSIMFILE";
799 sim
= ((getenv(simfile
) != NULL
) && (strlen(getenv(simfile
)) > 0));
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
) {
804 dm_descriptor_t disk
= (uintptr_t)iter
->obj
;
805 dlist_t
*slices
= NULL
;
810 if ((error
= get_display_name(disk
, &dname
)) != 0) {
816 /* sim disabled: use meta_repartition_drive() */
818 md_error_t mderror
= mdnullerror
;
819 int opts
= (MD_REPART_FORCE
| MD_REPART_DONT_LABEL
);
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
);
832 dnp
= metadrivename(&sp
, dname
, &mderror
);
833 if (!mdisok(&mderror
)) {
834 volume_set_error(mde_sperror(&mderror
, NULL
));
835 mdclrerror(&mderror
);
840 if (meta_repartition_drive(
841 sp
, dnp
, opts
, &vtoc
, &mderror
) != 0) {
843 gettext("failed to repartition disk %s\n"),
851 /* sim enabled: use faked repartition code */
852 if (virtual_repartition_drive(disk
, &vtoc
) != 0) {
854 gettext("failed simulated repartition of %s\n"),
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
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));
876 dlist_free_items(slices
, NULL
);
879 /* scan VTOC, find slice with the free space */
880 for (i
= 0; i
< vtoc
.nparts
; i
++) {
882 if (vtoc
.parts
[i
].tag
== V_USR
&&
883 vtoc
.parts
[i
].flag
!= V_UNMNT
) {
885 /* non-replica slice with free space */
886 char buf
[MAXPATHLEN
];
887 (void) snprintf(buf
, MAXPATHLEN
-1, "%ss%d", dname
, i
);
889 if ((error
= add_virtual_slice(buf
,
891 (uint64_t)vtoc
.parts
[i
].start
,
892 (uint64_t)vtoc
.parts
[i
].size
,
897 } else if (vtoc
.parts
[i
].tag
== V_RESERVED
) {
899 /* skip EFI reserved slice */
902 } else if (vtoc
.parts
[i
].tag
== V_USR
&&
903 vtoc
.parts
[i
].flag
== V_UNMNT
) {
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.
911 * XXX this is a temporary workaround until
912 * 4712873 is integrated...
915 char buf
[MAXPATHLEN
];
916 (void) snprintf(buf
, MAXPATHLEN
-1, "%ss%d", dname
, i
);
917 add_slice_to_remove(buf
, i
);
919 /* replica slice, stop here */
929 * FUNCTION: add_virtual_slice(char *name, uint32_t index,
930 * uint64_t startblk, uint64_t sizeblks,
931 * dm_descriptor_t disk)
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 ...
939 * RETURNS: int - 0 on success
942 * PURPOSE: Helper which adds the appropriate data structures to
943 * represent a new virtual slice.
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.
959 dm_descriptor_t disk
)
964 dlist_t
*aliases
= NULL
;
965 dlist_t
*item
= NULL
;
968 if ((error
= nvlist_alloc(&attrs
, NV_UNIQUE_NAME
, 0)) != 0) {
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
)) ||
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
)) ||
986 /* add attributes to the cache */
987 (error
= get_name(sp
, &sname
)) ||
988 (error
= add_cached_attributes(sname
, attrs
)) ||
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
));
999 /* generate slice's aliases if the disk has aliases */
1000 if (aliases
!= NULL
) {
1001 char buf
[MAXNAMELEN
];
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
);
1008 dlist_free_items(aliases
, free
);
1011 if ((item
= dlist_new_item((void *)(uintptr_t)sp
)) == NULL
) {
1015 _virtual_slices
= dlist_append(item
, _virtual_slices
, AT_HEAD
);
1017 oprintf(OUTPUT_DEBUG
,
1018 gettext(" created virtual slice %s start: %llu, size: %llu\n"),
1019 sname
, startblk
, sizeblks
);
1025 * FUNCTION: release_virtual_slices()
1027 * PURPOSE: Helper which cleans up the module private list of virtual
1030 * The descriptors for the virtual slices are cleaned up
1031 * in device_cache_util.free_cached_descriptors
1034 release_virtual_slices()
1036 dlist_free_items(_virtual_slices
, NULL
);
1037 _virtual_slices
= NULL
;
1041 * FUNCTION: disk_add_virtual_slice(dm_descriptor_t disk,
1042 * dm_descriptor_t slice)
1044 * INPUT: disk - a dm_descriptor_t disk handle
1045 * slice - a dm_descriptor_t virtual slice handle
1047 * RETURNS: int - 0 on success
1050 * PURPOSE: Helper which adds a virtual slice to the input disk's
1051 * list of virtual slices.
1053 * The disk's virtual slice dm_descriptor_t handles are
1054 * stored in the disk's nvpair attribute list.
1057 disk_add_virtual_slice(
1058 dm_descriptor_t disk
,
1059 dm_descriptor_t slice
)
1061 nvlist_t
*attrs
= NULL
;
1062 uint64_t *old_slices
= NULL
;
1063 uint64_t *new_slices
= NULL
;
1068 if ((error
= get_cached_attributes(disk
, &attrs
)) != 0) {
1072 if ((error
= get_uint64_array(
1073 attrs
, ATTR_VIRTUAL_SLICES
, &old_slices
, &nelem
)) != 0) {
1074 if (error
!= ENOENT
) {
1080 /* make a new array */
1081 new_slices
= (uint64_t *)calloc(nelem
+ 1, sizeof (uint64_t));
1082 if (new_slices
!= NULL
) {
1084 for (i
= 0; i
< nelem
; i
++) {
1085 new_slices
[i
] = old_slices
[i
];
1087 new_slices
[i
] = slice
;
1089 error
= set_uint64_array(
1090 attrs
, ATTR_VIRTUAL_SLICES
, new_slices
, nelem
);
1102 * FUNCTION: disk_has_virtual_slices(dm_descriptor_t disk, boolean_t *bool)
1104 * INPUT: disk - a dm_descriptor_t disk handle
1106 * OUTPUT: bool - B_TRUE - if the disk has virtual slices
1107 * B_FALSE - otherwise
1109 * RETURNS: int - 0 on success
1112 * PURPOSE: Helper which determines if the input disk has virtual slices.
1114 * If a disk has virtual slices, their dm_descriptor_t handles
1115 * will be stored in the disk's nvpair attribute list.
1118 disk_has_virtual_slices(
1119 dm_descriptor_t disk
,
1122 nvlist_t
*attrs
= NULL
;
1123 uint64_t *slices
= NULL
;
1129 if ((error
= get_cached_attributes(disk
, &attrs
)) != 0) {
1133 if ((error
= get_uint64_array(
1134 attrs
, ATTR_VIRTUAL_SLICES
, &slices
, &nelem
)) != 0) {
1135 if (error
== ENOENT
) {
1139 /* count actual number of elements */
1142 if (slices
[i
] != -1) {
1150 *bool = (nelem
!= 0);
1156 * FUNCTION: disk_get_virtual_slices(dm_descriptor_t disk, boolean_t *bool)
1158 * INPUT: disk - a dm_descriptor_t disk handle
1160 * OUTPUT: list - a dlist_t list of dm_descriptor_t handles for the
1161 * disk's virtual slices.
1163 * RETURNS: int - 0 on success
1166 * PURPOSE: Helper which retrieves a list of the input disk's virtual
1169 * If a disk has virtual slices, their dm_descriptor_t handles
1170 * will be stored in the disk's nvpair attribute list.
1173 disk_get_virtual_slices(
1174 dm_descriptor_t disk
,
1177 nvlist_t
*attrs
= NULL
;
1178 uint64_t *slices
= NULL
;
1183 if ((error
= get_cached_attributes(disk
, &attrs
)) != 0) {
1187 if ((error
= get_uint64_array(
1188 attrs
, ATTR_VIRTUAL_SLICES
, &slices
, &nelem
)) != 0) {
1189 if (error
!= ENOENT
) {
1196 for (i
= 0; i
< nelem
&& slices
[i
] != -1; i
++) {
1197 dlist_t
*item
= NULL
;
1199 if ((item
= dlist_new_item((void*)(uintptr_t)slices
[i
])) == NULL
) {
1204 *list
= dlist_append(item
, *list
, AT_TAIL
);
1211 * FUNCTION: is_virtual_slice(dm_descriptor_t desc)
1213 * INPUT: desc - a dm_descriptor_t handle
1215 * RETURNS: boolean_t - B_TRUE if the input descriptor is for
1219 * PURPOSE: Helper which determines whether the input descriptor
1220 * corresponds to a virtual slice.
1222 * All virtual slices are stored in a module private list.
1223 * This list is iterated to see if it contains the input
1228 dm_descriptor_t desc
)
1230 return (dlist_contains(_virtual_slices
,
1231 (void*)(uintptr_t)desc
, compare_descriptors
));
1235 * FUNCTION: disk_get_available_slice_index(dm_descriptor_t disk,
1236 * uint32_t *newindex)
1238 * INPUT: disk - a dm_descriptor_t handle for a disk
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.
1244 * RETURNS: int - 0 on success
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.
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.
1256 * V_NUMPAR is used as the number of available slices,
1257 * SPARC systems have V_NUMPAR == 8, X86 have V_NUMPAR == 16.
1259 * EFI disks have only 7.
1262 disk_get_available_slice_index(
1263 dm_descriptor_t disk
,
1266 dlist_t
*iter
= NULL
;
1267 dlist_t
*slices
= NULL
;
1269 uint16_t *reserved
= NULL
;
1270 boolean_t
*used
= NULL
;
1271 boolean_t is_efi
= B_FALSE
;
1274 int nslices
= V_NUMPAR
;
1276 if (((error
= disk_get_slices(disk
, &slices
)) != 0) ||
1277 (error
= disk_get_is_efi(disk
, &is_efi
)) != 0) {
1281 if (is_efi
== B_TRUE
) {
1282 /* limit possible indexes to 7 for EFI */
1286 used
= (boolean_t
*)calloc(nslices
, sizeof (boolean_t
));
1288 oprintf(OUTPUT_DEBUG
,
1289 gettext("failed allocating slice index array\n"),
1294 /* eliminate indexes that are reserved */
1295 if ((error
= disk_get_reserved_indexes(disk
, &reserved
)) != 0) {
1299 if (reserved
!= NULL
) {
1300 for (i
= 0; i
< nslices
; i
++) {
1301 if (reserved
[i
] == 1) {
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
;
1313 ((error
= slice_get_index(sp
, &index
)) != 0) ||
1314 (error
= slice_get_size_in_blocks(sp
, &size
));
1320 used
[(int)index
] = B_TRUE
;
1323 dlist_free_items(slices
, NULL
);
1325 for (i
= 0; i
< nslices
; i
++) {
1327 /* skip the index passed in */
1328 if (i
== *newindex
) {
1332 if (used
[i
] != B_TRUE
) {
1339 /* return unused slice index */
1349 * FUNCTION: disk_get_media_type(dm_descriptor_t slice, uint32_t *type)
1351 * INPUT: slice - a dm_descriptor_t handle for a disk
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.
1357 * RETURNS: int - 0 on success
1360 * PURPOSE: Retrieves the media type for the disk.
1362 * Get the media associate with the input disk descriptor
1363 * and determine its type.
1366 disk_get_media_type(
1367 dm_descriptor_t disk
,
1371 dm_descriptor_t
*mdp
= NULL
;
1373 mdp
= dm_get_associated_descriptors(disk
, DM_MEDIA
, &error
);
1374 (void) add_descriptors_to_free(mdp
);
1377 print_get_assoc_desc_error(disk
, gettext("media"), error
);
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
);
1388 /* no media: removeable drive */
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)
1412 * INPUT: disk - a dm_descriptor_t handle for a disk
1414 * OUTPUT: *bool - a pointer to a variable of the appropriate
1415 * type to hold the current value for the attribute
1418 * RETURNS: int - 0 on success
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.
1427 dm_descriptor_t disk
,
1433 if ((error
= disk_get_uint64_attribute(
1434 disk
, DM_RPM
, &val64
)) != 0) {
1438 *val
= (uint32_t)val64
;
1444 disk_get_drive_type(
1445 dm_descriptor_t disk
,
1451 if ((error
= disk_get_uint64_attribute(
1452 disk
, DM_DRVTYPE
, &val64
)) != 0) {
1456 *val
= (uint32_t)val64
;
1462 disk_get_sync_speed(
1463 dm_descriptor_t disk
,
1469 if ((error
= disk_get_uint64_attribute(
1470 disk
, DM_SYNC_SPEED
, &val64
)) != 0) {
1474 *val
= (uint32_t)val64
;
1479 /* returns number of usable blocks */
1481 disk_get_size_in_blocks(
1482 dm_descriptor_t disk
,
1485 return (disk_get_uint64_attribute(disk
, DM_NACCESSIBLE
, val
));
1488 /* returns first usable block on disk */
1490 disk_get_start_block(
1491 dm_descriptor_t disk
,
1494 return (disk_get_uint64_attribute(disk
, DM_START
, val
));
1499 dm_descriptor_t disk
,
1502 return (disk_get_uint64_attribute(disk
, DM_BLOCKSIZE
, val
));
1506 disk_get_ncylinders(
1507 dm_descriptor_t disk
,
1510 return (disk_get_uint64_attribute(disk
, DM_NCYLINDERS
, val
));
1515 dm_descriptor_t disk
,
1518 return (disk_get_uint64_attribute(disk
, DM_NHEADS
, val
));
1523 dm_descriptor_t disk
,
1526 return (disk_get_uint64_attribute(disk
, DM_NSECTORS
, val
));
1530 * FUNCTION: disk_get_is_online(dm_descriptor_t disk, boolean_t *val)
1532 * INPUT: disk - a dm_descriptor_t handle for a disk
1534 * OUTPUT: *bool - a pointer to a boolean_t to hold the result.
1536 * RETURNS: int - 0 on success
1539 * PURPOSE: Determine if the input disk is "online".
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.
1546 dm_descriptor_t disk
,
1549 uint64_t status
= 0;
1554 error
= disk_get_uint64_attribute(disk
, DM_STATUS
, &status
);
1556 *val
= (status
== 1) ? B_TRUE
: B_FALSE
;
1563 * FUNCTION: disk_get_is_efi(dm_descriptor_t disk, boolean_t *bool)
1565 * INPUT: disk - a dm_descriptor_t handle for a disk
1567 * OUTPUT: *bool - a pointer to a boolean_t to hold the result.
1569 * RETURNS: int - 0 on success
1572 * PURPOSE: Determine if the input disk is labeled with an EFI label.
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.
1580 dm_descriptor_t disk
,
1583 return (disk_get_boolean_attribute(disk
, DM_EFI
, bool));
1587 * FUNCTION: disk_get_has_fdisk(dm_descriptor_t disk, boolean_t *bool)
1589 * INPUT: disk - a dm_descriptor_t handle for a disk
1591 * OUTPUT: *bool - a pointer to a boolean_t to hold the result.
1593 * RETURNS: int - 0 on success
1596 * PURPOSE: Determine if the input disk has an FDISK partition.
1600 dm_descriptor_t disk
,
1603 return (disk_get_boolean_attribute(disk
, DM_FDISK
, bool));
1607 * FUNCTION: disk_get_has_solaris_partition(dm_descriptor_t disk, boolean_t *bool)
1609 * INPUT: disk - a dm_descriptor_t handle for a disk
1611 * OUTPUT: *bool - a pointer to a boolean_t to hold the result.
1613 * RETURNS: int - 0 on success
1616 * PURPOSE: Determine if the input disk has a Solaris FDISK partition.
1619 disk_get_has_solaris_partition(
1620 dm_descriptor_t disk
,
1623 boolean_t has_fdisk
= B_FALSE
;
1626 if ((error
= disk_get_has_fdisk(disk
, &has_fdisk
)) != 0) {
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
);
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
);
1646 print_get_assoc_desc_error(media
[0],
1647 gettext("partitions"), error
);
1649 /* search partitions for one with type Solaris */
1651 for (; (parts
!= NULL
) && (parts
[i
] != NULL
) &&
1652 (error
== 0) && (*bool == B_FALSE
); i
++) {
1653 nvlist_t
*attrs
= dm_get_attributes(parts
[i
], &error
);
1655 if ((error
== 0) && (attrs
!= NULL
)) {
1656 error
= get_uint32(attrs
, DM_PTYPE
, &ptype
);
1658 (ptype
== SUNIXOS
|| ptype
== SUNIXOS2
)) {
1670 /* if there was no media, it was a removeable drive */
1677 disk_get_boolean_attribute(
1678 dm_descriptor_t disk
,
1682 nvlist_t
*attrs
= NULL
;
1687 if ((strcmp(attr
, DM_EFI
) == 0) ||
1688 (strcmp(attr
, DM_FDISK
) == 0)) {
1691 * these attributes are actually on the media,
1692 * not the disk... so get the media descriptor
1695 dm_descriptor_t
*media
;
1697 media
= dm_get_associated_descriptors(disk
, DM_MEDIA
, &error
);
1698 (void) add_descriptors_to_free(media
);
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
);
1709 error
= get_cached_attributes(disk
, &attrs
);
1711 print_get_desc_attr_error(disk
, gettext("drive"), attr
, error
);
1719 if (nvlist_lookup_boolean(attrs
, attr
) == 0) {
1727 disk_get_uint64_attribute(
1728 dm_descriptor_t disk
,
1732 nvlist_t
*attrs
= NULL
;
1737 * these attributes are actually on the media,
1738 * not the disk... so get the media descriptor
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)) {
1749 dm_descriptor_t
*media
;
1751 media
= dm_get_associated_descriptors(disk
, DM_MEDIA
, &error
);
1752 (void) add_descriptors_to_free(media
);
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
);
1760 error
= get_cached_attributes(media
[0], &attrs
);
1765 error
= get_cached_attributes(disk
, &attrs
);
1767 print_get_desc_attr_error(disk
, gettext("drive"), attr
, error
);
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
;
1795 * FUNCTION: group_similar_hbas(dlist_t *hbas, dlist_t **list)
1797 * INPUT: hbas - a list of HBA dm_descriptor_t handles.
1799 * OUTPUT: **list - a pointer to a list to hold the lists of HBAs
1800 * grouped by characteristics.
1802 * RETURNS: int - 0 on success
1805 * PURPOSE: Examine the input HBAs and collate them into separate
1806 * lists, grouped by their type and the protocols they
1809 * The returned list of list is arranged in decreasing order
1810 * of preference, "better" HBAs come first.
1812 * find all MPXIO controllers
1813 * find all similar FC HBAs
1814 * find all similar SCSI HBAs
1819 * find all similar ATA/IDE HBAs
1820 * find all similar USB HBAs
1827 /* preference order of HBAs */
1829 HBA_FIBRE_MPXIO
= 0,
1844 dlist_t
*groups
= NULL
;
1845 dlist_t
*iter
= NULL
;
1846 dlist_t
*item
= NULL
;
1847 dlist_t
*lists
[HBA_LAST
];
1852 (void) memset(lists
, '\0', HBA_LAST
* sizeof (dlist_t
*));
1855 (iter
!= NULL
) && (error
== 0);
1856 iter
= iter
->next
) {
1858 dm_descriptor_t hba
= (uintptr_t)iter
->obj
;
1861 /* if item doesn't go into a list it must be freed */
1862 if ((item
= dlist_new_item((void *)(uintptr_t)hba
)) == NULL
) {
1867 if ((error
= hba_get_type(hba
, &type
)) != 0) {
1872 if (strcmp(type
, DM_CTYPE_FIBRE
) == 0) {
1874 boolean_t ismpxio
= B_FALSE
;
1876 if ((error
= hba_is_multiplex(hba
, &ismpxio
)) == 0) {
1878 lists
[HBA_FIBRE_MPXIO
] =
1880 lists
[HBA_FIBRE_MPXIO
], AT_TAIL
);
1884 lists
[HBA_FIBRE
], AT_TAIL
);
1890 } else if (strcmp(type
, DM_CTYPE_SCSI
) == 0) {
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
;
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
));
1909 lists
[HBA_SCSI_MPXIO
] =
1911 lists
[HBA_SCSI_MPXIO
], AT_TAIL
);
1916 lists
[HBA_SCSI_FW80
] =
1918 lists
[HBA_SCSI_FW80
], AT_TAIL
);
1920 lists
[HBA_SCSI_F80
] =
1922 lists
[HBA_SCSI_F80
], AT_TAIL
);
1928 lists
[HBA_SCSI_FW40
] =
1930 lists
[HBA_SCSI_FW40
], AT_TAIL
);
1932 lists
[HBA_SCSI_F40
] =
1934 lists
[HBA_SCSI_F40
], AT_TAIL
);
1940 lists
[HBA_SCSI_FW20
] =
1942 lists
[HBA_SCSI_FW20
], AT_TAIL
);
1944 lists
[HBA_SCSI_F20
] =
1946 lists
[HBA_SCSI_F20
], AT_TAIL
);
1951 dlist_append(item
, lists
[HBA_SCSI
], AT_TAIL
);
1958 } else if (strcmp(type
, DM_CTYPE_ATA
) == 0) {
1960 dlist_append(item
, lists
[HBA_ATA
], AT_TAIL
);
1961 } else if (strcmp(type
, DM_CTYPE_USB
) == 0) {
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"));
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
) {
1978 groups
= dlist_append(item
, groups
, AT_TAIL
);
1985 for (i
= 0; i
< HBA_LAST
; i
++) {
1986 dlist_free_items(lists
[i
], NULL
);
1990 if (groups
!= NULL
) {
1991 dlist_free_items(groups
, NULL
);
2001 * FUNCTION: hba_group_usable_disks(dm_descriptor_t hba, dlist_t **list)
2003 * INPUT: hba - a dm_descriptor_t handle for a slice
2005 * OUTPUT: **list - a pointer to a list to hold the lists of disks
2006 * grouped by characteristics.
2008 * RETURNS: int - 0 on success
2011 * PURPOSE: Examine the disks assocated with the HBA and collates them
2012 * into separate lists, grouped by similar characteristics.
2015 * check disks against _usable_disks list
2016 * group disks by similarities:
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.
2026 hba_group_usable_disks(
2027 dm_descriptor_t hba
,
2030 dm_descriptor_t
*disk
= NULL
;
2035 disk
= dm_get_associated_descriptors(hba
, DM_DRIVE
, &error
);
2036 (void) add_descriptors_to_free(disk
);
2039 print_get_assoc_desc_error(hba
, gettext("drive"), error
);
2041 } else if ((disk
== NULL
) || (*disk
== NULL
)) {
2042 print_get_assoc_desc_error(hba
, gettext("drive"), error
);
2046 for (i
= 0; (disk
[i
] != NULL
) && (error
== 0); i
++) {
2048 uint32_t dtype
= DM_DT_UNKNOWN
;
2049 dlist_t
*usable
= NULL
;
2051 /* ignore non fixed media drives */
2052 if (((error
= disk_get_drive_type(disk
[i
], &dtype
)) != 0) ||
2053 (dtype
!= DM_DT_FIXED
)) {
2057 if (dlist_contains(usable
, &disk
[i
],
2058 compare_descriptor_names
) == B_TRUE
) {
2062 uint64_t nsects
= 0;
2063 uint64_t nheads
= 0;
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
));
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
);
2085 /* add to the appropriate list */
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)
2100 * INPUT: hba - a dm_descriptor_t handle for a slice
2102 * OUTPUT: *val - a pointer to a uint16_t to hold the current number
2103 * of available disks for the input HBA.
2105 * RETURNS: int - 0 on success
2109 hba_set_n_avail_disks(
2110 dm_descriptor_t hba
,
2116 ((error
= get_cached_attributes(hba
, &attrs
)) != 0) ||
2117 (error
= set_uint16(attrs
, ATTR_HBA_N_DISKS
, val
));
2123 hba_get_n_avail_disks(
2124 dm_descriptor_t hba
,
2132 ((error
= get_cached_attributes(hba
, &attrs
)) != 0) ||
2133 (error
= get_uint16(attrs
, ATTR_HBA_N_DISKS
, val
));
2139 * FUNCTION: hba_get_type(dm_descriptor_t hba, char **type)
2141 * INPUT: hba - a dm_descriptor_t handle for a HBA
2143 * OUTPUT: **type - a char * to hold the current type value for
2146 * RETURNS: int - 0 on success
2149 * PURPOSE: Retrieves the type attribute for the HBA.
2153 dm_descriptor_t hba
,
2161 ((error
= get_cached_attributes(hba
, &attrs
)) != 0) ||
2162 (error
= get_string(attrs
, DM_CTYPE
, type
));
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)
2175 * INPUT: hba - a dm_descriptor_t handle for a HBA
2177 * OUTPUT: *bool - a pointer to a boolean_t to hold the
2178 * boolean value of the predicate.
2180 * RETURNS: int - 0 on success
2183 * PURPOSE: Wrappers around hba_supports_protocol which determines
2184 * if the input HBA supports the protocol of interest.
2188 dm_descriptor_t hba
,
2191 return (hba_supports_protocol(hba
, DM_FAST
, bool));
2196 dm_descriptor_t hba
,
2199 return (hba_supports_protocol(hba
, DM_FAST20
, bool));
2204 dm_descriptor_t hba
,
2207 return (hba_supports_protocol(hba
, DM_FAST40
, bool));
2212 dm_descriptor_t hba
,
2215 return (hba_supports_protocol(hba
, DM_FAST80
, bool));
2220 dm_descriptor_t hba
,
2223 return (hba_supports_protocol(hba
, DM_MULTIPLEX
, bool));
2228 dm_descriptor_t hba
,
2231 nvlist_t
*attrs
= NULL
;
2236 if ((error
= get_cached_attributes(hba
, &attrs
)) != 0) {
2240 *bool = (0 == nvlist_lookup_boolean(attrs
, DM_WIDE
));
2246 * FUNCTION: hba_supports_protocol(dm_descriptor_t hba, char *attr,
2249 * INPUT: hba - a dm_descriptor_t handle for a HBA
2250 * attr - a protocol "name"
2252 * OUTPUT: *bool - a pointer to a boolean_t to hold the
2253 * boolean value of the predicate.
2255 * RETURNS: int - 0 on success
2258 * PURPOSE: Checks the HBAs attributes to see if it is known to
2259 * support the protocol of interest.
2261 * If the protocol is supported, it will have an entry
2262 * in the nvpair attribute list that can be retrieved.
2264 * If the entry cannot be retrieved, the protocol is not
2268 hba_supports_protocol(
2269 dm_descriptor_t hba
,
2273 nvlist_t
*attrs
= NULL
;
2278 if ((error
= get_cached_attributes(hba
, &attrs
)) != 0) {
2282 *bool = (0 == nvlist_lookup_boolean(attrs
, attr
));
2288 * FUNCTION: slice_set_size(dm_descriptor_t slice, uint64_t size)
2290 * INPUT: slice - a dm_descriptor_t handle for a slice
2292 * OUTPUT: size - a uint64_t value representing the size of the
2295 * RETURNS: int - 0 on success
2298 * PURPOSE: Wrapper around slice_set_uint64_attribute which converts
2299 * the input size in bytes to blocks prior to storing it.
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.
2307 dm_descriptor_t slice
,
2310 dm_descriptor_t disk
= NULL
;
2311 uint64_t blksize
= 0;
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
)));
2322 * FUNCTION: slice_set_size_in_blocks(dm_descriptor_t slice, uint64_t size)
2324 * INPUT: slice - a dm_descriptor_t handle for a slice
2326 * OUTPUT: size - a uint64_t value representing the size of the
2329 * RETURNS: int - 0 on success
2332 * PURPOSE: Wrapper around slice_set_uint64_attribute to set the slice
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.
2340 slice_set_size_in_blocks(
2341 dm_descriptor_t slice
,
2344 return (slice_set_attribute(slice
, DM_SIZE
, size
));
2348 * FUNCTION: slice_set_start_block(dm_descriptor_t slice, uint64_t start)
2350 * INPUT: slice - a dm_descriptor_t handle for a slice
2352 * OUTPUT: size - a uint64_t value representing the start block of the
2355 * RETURNS: int - 0 on success
2358 * PURPOSE: Wrapper around slice_set_attribute.
2360 * This function is used when an existing slice gets adjusted
2361 * due to being resized or combined with another slice.
2364 slice_set_start_block(
2365 dm_descriptor_t slice
,
2368 return (slice_set_attribute(slice
, DM_START
, start
));
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)
2378 * INPUT: slice - a dm_descriptor_t handle for a slice
2380 * OUTPUT: *val - a pointer to a uint64_t to hold the
2381 * current value of the desired attribute.
2383 * RETURNS: int - 0 on success
2386 * PURPOSE: Wrappers around slice_get_uint64_attribute which retrieve
2387 * specific attribute values.
2390 slice_get_start_block(
2391 dm_descriptor_t slice
,
2394 return (slice_get_uint64_attribute(slice
, DM_START
, val
));
2398 slice_get_size_in_blocks(
2399 dm_descriptor_t slice
,
2402 return (slice_get_uint64_attribute(slice
, DM_SIZE
, val
));
2407 dm_descriptor_t slice
,
2410 dm_descriptor_t disk
= NULL
;
2411 uint64_t blksize
= 0;
2415 ((error
= slice_get_disk(slice
, &disk
)) != 0) ||
2416 (error
= disk_get_blocksize(disk
, &blksize
)) ||
2417 (error
= slice_get_start_block(slice
, &nblks
));
2420 *val
= (blksize
* nblks
);
2428 dm_descriptor_t slice
,
2431 dm_descriptor_t disk
= NULL
;
2432 uint64_t blksize
= 0;
2438 ((error
= slice_get_disk(slice
, &disk
)) != 0) ||
2439 (error
= slice_get_size_in_blocks(slice
, &nblks
)) ||
2440 (error
= disk_get_blocksize(disk
, &blksize
));
2443 *val
= (blksize
* nblks
);
2451 dm_descriptor_t slice
,
2457 if ((error
= slice_get_uint64_attribute(
2458 slice
, DM_INDEX
, &index
)) != 0) {
2462 *val
= (uint32_t)index
;
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)
2473 * INPUT: slice - a dm_descriptor_t handle for a slice
2474 * attr - a char * attribute name
2475 * val - auint64_t value
2477 * OUTPUT: *val - a pointer to a uint64_t to hold the
2478 * current value of the named attribute.
2480 * RETURNS: int - 0 on success
2483 * PURPOSE: Helpers to set/get the value for a slice's attribute.
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.
2491 slice_get_uint64_attribute(
2492 dm_descriptor_t slice
,
2496 nvlist_t
*attrs
= NULL
;
2500 if ((error
= get_cached_attributes(slice
, &attrs
)) != 0) {
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
);
2516 print_get_desc_attr_error(slice
, "slice", attr
, error
);
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.
2528 slice_set_attribute(
2529 dm_descriptor_t slice
,
2533 nvlist_t
*attrs
= NULL
;
2536 if ((error
= get_cached_attributes(slice
, &attrs
)) != 0) {
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
);
2551 print_set_desc_attr_error(slice
, "slice", attr
, error
);
2558 * FUNCTION: virtual_slice_get_disk(dm_descriptor_t slice,
2559 * dm_descriptor_t *diskp)
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
2565 * OUTPUT: the disk associated with the virtual slice.
2567 * RETURNS: int - 0 on success
2570 * PURPOSE: Helper which determines the disk that the input virtual
2571 * slice "belongs" to.
2573 * The virtual slice's disk is stored in the slice's nvpair
2574 * attribute list when the slice gets created.
2577 virtual_slice_get_disk(
2578 dm_descriptor_t slice
,
2579 dm_descriptor_t
*diskp
)
2584 if ((error
= slice_get_uint64_attribute(
2585 slice
, ATTR_DISK_FOR_SLICE
, &disk
)) != 0) {
2589 *diskp
= (dm_descriptor_t
)disk
;
2592 print_get_desc_attr_error(slice
, "virtual slice", "disk", error
);
2600 * FUNCTION: slice_get_disk(dm_descriptor_t disk, dm_descriptor_t *diskp)
2602 * INPUT: slice - a dm_descriptor_t handle for a slice
2604 * OUTPUT: diskp - a pointer to a dm_descriptor_t to hold the
2605 * disk associated with the input slice
2607 * RETURNS: int - 0 on success
2610 * PURPOSE: Helper which retrieves the disk for a slice device.
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.
2620 dm_descriptor_t slice
,
2621 dm_descriptor_t
*diskp
)
2623 dm_descriptor_t
*media
= NULL
;
2630 if (is_virtual_slice(slice
)) {
2631 return (virtual_slice_get_disk(slice
, diskp
));
2634 media
= dm_get_associated_descriptors(slice
, DM_MEDIA
, &error
);
2635 (void) add_descriptors_to_free(media
);
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
);
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
);
2655 if ((error
== 0) && (disks
!= NULL
) && (disks
[0] != NULL
)) {
2661 if (media
!= NULL
) {
2666 print_get_desc_attr_error(slice
,
2667 gettext("slice"), gettext("disk"), ENODEV
);
2675 * FUNCTION: slice_get_hbas(dm_descriptor_t slice, dlist_t **list)
2677 * INPUT: slice - a dm_descriptor_t handle for a slice
2679 * OUTPUT: list - a pointer to a dlist_t list to hold the
2680 * HBAs associated with the input slice
2682 * RETURNS: int - 0 on success
2685 * PURPOSE: Helper which retrieves the known HBAs for a slice device.
2690 dm_descriptor_t slice
,
2693 dm_descriptor_t disk
= NULL
;
2698 ((error
= slice_get_disk(slice
, &disk
)) != 0) ||
2699 (error
= disk_get_hbas(disk
, list
));
2701 if (*list
== NULL
) {
2702 print_get_desc_attr_error(slice
, "slice", "HBA", ENODEV
);
2710 * FUNCTION: disk_get_associated_desc(dm_descriptor_t disk,
2711 * dm_desc_type_t assoc_type, char *assoc_type_str,
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
2718 * OUTPUT: list - a pointer to a dlist_t list to hold the
2719 * objects associated with the input disk
2721 * RETURNS: int - 0 on success
2724 * PURPOSE: Helper which retrieves the associated objects of the
2725 * requested type for a disk device.
2728 disk_get_associated_desc(
2729 dm_descriptor_t disk
,
2730 dm_desc_type_t assoc_type
,
2731 char *assoc_type_str
,
2737 dm_descriptor_t
*assoc
=
2738 dm_get_associated_descriptors(disk
, assoc_type
, &error
);
2740 (void) add_descriptors_to_free(assoc
);
2744 (assoc
!= NULL
) && (assoc
[i
] != NULL
) && (error
== 0);
2746 dlist_t
*item
= dlist_new_item((void *)(uintptr_t)assoc
[i
]);
2750 *list
= dlist_append(item
, *list
, AT_TAIL
);
2754 print_get_assoc_desc_error(disk
, assoc_type_str
, error
);
2757 if (assoc
!= NULL
) {
2762 dlist_free_items(*list
, NULL
);
2770 * FUNCTION: disk_get_hbas(dm_descriptor_t disk, dlist_t **list)
2772 * INPUT: disk - a dm_descriptor_t handle for a disk
2774 * OUTPUT: list - a pointer to a dlist_t list to hold the
2775 * HBAs associated with the input disk
2777 * RETURNS: int - 0 on success
2780 * PURPOSE: Helper which retrieves the known HBAs for a disk device.
2785 dm_descriptor_t disk
,
2788 return (disk_get_associated_desc(disk
, DM_CONTROLLER
,
2789 gettext("controller"), list
));
2793 * FUNCTION: disk_get_paths(dm_descriptor_t disk, dlist_t **list)
2795 * INPUT: disk - a dm_descriptor_t handle for a disk
2797 * OUTPUT: list - a pointer to a dlist_t list to hold the
2798 * paths associated with the input disk
2800 * RETURNS: int - 0 on success
2803 * PURPOSE: Helper which retrieves the known paths for a disk device.
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.
2811 dm_descriptor_t disk
,
2814 return (disk_get_associated_desc(disk
, DM_PATH
,
2815 gettext("path"), list
));
2819 * FUNCTION: disk_get_aliases(dm_descriptor_t disk, dlist_t **list)
2821 * INPUT: disk - a dm_descriptor_t handle for a disk
2823 * OUTPUT: list - a pointer to a dlist_t list to hold the
2824 * alias descriptors associated with the input disk
2826 * RETURNS: int - 0 on success
2829 * PURPOSE: Helper which retrieves the known aliases for a disk device.
2831 * Aliases are the different CTD names for the disk drive when
2832 * MPXIO is not enabled for multipathed drives.
2836 dm_descriptor_t disk
,
2839 return (disk_get_associated_desc(disk
, DM_ALIAS
,
2840 gettext("alias"), list
));
2844 * FUNCTION: compare_string_to_desc_name_or_alias(
2845 * void *str, void *desc)
2847 * INPUT: str - opaque pointer
2848 * descr - opaque pointer
2850 * RETURNS: int - <0 - if str < desc.name
2851 * 0 - if str == desc.name
2852 * >0 - if str > desc.name
2854 * PURPOSE: dlist_t helper which compares a string to the name
2855 * and aliases associated with the input dm_descriptor_t
2858 * Comparison is done via compare_device_names.
2861 compare_string_to_desc_name_or_alias(
2868 assert(str
!= (char *)NULL
);
2869 assert(desc
!= (dm_descriptor_t
)0);
2871 (void) get_display_name((uintptr_t)desc
, &dname
);
2873 /* try name first, then aliases */
2874 if ((result
= compare_device_names(str
, dname
)) != 0) {
2875 dlist_t
*aliases
= NULL
;
2877 (void) get_aliases((uintptr_t)desc
, &aliases
);
2878 if ((aliases
!= NULL
) && (dlist_contains(aliases
,
2879 str
, compare_device_names
) == B_TRUE
)) {
2882 dlist_free_items(aliases
, free
);
2889 * FUNCTION: hba_get_by_name(char *name, dm_descriptor_t *hba)
2891 * INPUT: name - a char * disk name
2893 * OUTPUT: hba - a pointer to a dm_descriptor_t to hold the
2894 * HBA corresponding to the input name, if found
2896 * RETURNS: int - 0 on success
2899 * PURPOSE: Helper which iterates the known HBAs, searching for
2900 * the one matching name.
2902 * If no HBA matches the name, 0 is returned and the
2903 * value of 'hba' will be (dm_descriptor_t)0;
2908 dm_descriptor_t
*hba
)
2911 dlist_t
*list
= NULL
;
2912 dlist_t
*item
= NULL
;
2914 *hba
= (dm_descriptor_t
)0;
2920 if ((error
= get_known_hbas(&list
)) != 0) {
2924 if ((item
= dlist_find(list
, name
,
2925 compare_string_to_desc_name_or_alias
)) != NULL
) {
2926 *hba
= (uintptr_t)item
->obj
;
2933 * FUNCTION: disk_get_by_name(char *name, dm_descriptor_t *disk)
2935 * INPUT: name - a char * disk name
2937 * OUTPUT: disk - a pointer to a dm_descriptor_t to hold the
2938 * disk corresponding to the input name, if found
2940 * RETURNS: int - 0 on success
2943 * PURPOSE: Helper which retrieves a dm_descriptor_t disk handle
2946 * If no disk is found for the input name, variations of
2947 * the name are tried.
2949 * If the input name is unqualified, an appropriate leading
2950 * path is prepended.
2952 * If the input name is qualified, the leading path is
2955 * If no disk is found for the variations, 0 is returned
2956 * and the value of 'disk' will be (dm_descriptor_t)0;
2961 dm_descriptor_t
*disk
)
2963 assert(name
!= (char *)NULL
);
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
, '/');
2971 *disk
= find_cached_descriptor(cp
+ 1);
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
);
2981 *disk
= find_cached_descriptor(buf
);
2986 * since the descriptor cache includes HBAs, disks and slices,
2987 * what gets returned may not be a disk... make sure it is
2989 if (*disk
!= (dm_descriptor_t
)0) {
2990 if (dm_get_type(*disk
) != DM_DRIVE
) {
2991 *disk
= (dm_descriptor_t
)0;
2999 * FUNCTION: slice_get_by_name(char *name, dm_descriptor_t *slice)
3001 * INPUT: name - a char * slice name
3003 * OUTPUT: slice - a pointer to a dm_descriptor_t to hold the
3004 * slice corresponding to the input name, if found.
3006 * RETURNS: int - 0 on success
3009 * PURPOSE: Helper which iterates the known slices, searching for
3010 * the one matching name.
3012 * If no slice is found for the input name, variations of
3013 * the name are tried.
3015 * If the input name is unqualified, an appropriate leading
3016 * path is prepended.
3018 * If the input name is qualified, the leading path is
3021 * If no slice matches the variations, 0 is returned and the
3022 * value of 'slice' will be (dm_descriptor_t)0;
3027 dm_descriptor_t
*slice
)
3029 assert(name
!= (char *)NULL
);
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
, '/');
3037 *slice
= find_cached_descriptor(cp
+ 1);
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
);
3048 *slice
= find_cached_descriptor(buf
);
3053 * since the descriptor cache includes HBAs, disks and slices,
3054 * what gets returned may not be a slice... make sure it is
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;
3067 * FUNCTION: extract_hbaname(char *name, char **hbaname)
3069 * INPUT: slicename - a char * device name
3071 * OUTPUT: hbaname - a pointer to a char * to hold the hbaname derived
3072 * from the input name.
3074 * RETURNS: int - 0 on success
3077 * PURPOSE: Helper which extracts the HBA name from the input name.
3079 * If the input name is in ctd form, extracts just the cX part,
3080 * by truncating everything following the last 't'.
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'.
3086 * The returned string must be passed to free().
3095 if (is_ctd_name(name
)) {
3096 if ((*hbaname
= strdup(name
)) == NULL
) {
3099 if ((cp
= strrchr(*hbaname
, 'd')) != NULL
) {
3102 if ((cp
= strrchr(*hbaname
, 't')) != NULL
) {
3111 * FUNCTION: extract_diskname(char *slicename, char **diskname)
3113 * INPUT: slicename - a char * slice name
3115 * OUTPUT: diskname - a pointer to a char * to hold the diskname derived
3116 * from the input slicename.
3118 * RETURNS: int - 0 on success
3121 * PURPOSE: Helper which extracts the disk's name from a slice name.
3123 * Checks to see if the input slicename is in ctd or did form,
3124 * and if so, truncates everything following the last 's'.
3126 * If the input slicename is BSD-like, truncate the last
3129 * The returned string must be passed to free().
3138 if (is_ctd_slice_name(slicename
) || is_did_slice_name(slicename
) ||
3139 is_ctd_like_slice_name(slicename
)) {
3141 if ((*diskname
= strdup(slicename
)) == NULL
) {
3144 if ((cp
= strrchr(*diskname
, 's')) != NULL
) {
3148 } else if (is_bsd_like_slice_name(slicename
)) {
3150 if ((*diskname
= strdup(slicename
)) == NULL
) {
3153 (*diskname
)[strlen((*diskname
)-1)] = '\0';
3161 * FUNCTION: get_disk_for_named_slice(char *slicename,
3162 * dm_descriptor_t disk)
3164 * INPUT: slicename - a char * slice name
3166 * OUTPUT: disk - a pointer to a dm_descriptor_t to hold the
3167 * disk corresponding to the input name, if found
3169 * RETURNS: int - 0 on success
3172 * PURPOSE: Helper which locates the disk dm_descriptor_t handle for
3173 * the input slice name.
3175 * If no disk matches the name, 0 is returned and the
3176 * value of 'disk' will be (dm_descriptor_t)0;
3179 get_disk_for_named_slice(
3181 dm_descriptor_t
*disk
)
3183 dm_descriptor_t slice
= (dm_descriptor_t
)0;
3186 assert(slicename
!= NULL
);
3188 /* find disk for slice */
3189 if ((error
= slice_get_by_name(slicename
, &slice
)) == 0) {
3191 if (slice
!= (dm_descriptor_t
)0) {
3192 error
= slice_get_disk(slice
, disk
);
3194 /* named slice was created by layout: */
3195 /* need to find disk by name */
3198 error
= extract_diskname(slicename
, &dname
);
3200 error
= disk_get_by_name(dname
, disk
);
3206 assert(*disk
!= (dm_descriptor_t
)0);
3212 * FUNCTION: disk_get_reserved_indexes(dm_descriptor_t disk,
3215 * INPUT: disk - a dm_descriptor_t disk handle
3217 * RETURNS: int - 0 on success
3220 * PURPOSE: Retrieves the input disk's list of reserved slice indices.
3222 * The list of reserved indices is stored as an array in
3223 * the disk's nvpair attribute list.
3226 disk_get_reserved_indexes(
3227 dm_descriptor_t disk
,
3230 nvlist_t
*attrs
= NULL
;
3234 if ((error
= get_cached_attributes(disk
, &attrs
)) != 0) {
3238 if ((error
= get_uint16_array(
3239 attrs
, ATTR_RESERVED_INDEX
, array
, &nelem
)) != 0) {
3240 if (error
== ENOENT
) {
3241 /* no reserved indices yet */
3250 * FUNCTION: disk_reserve_index(dm_descriptor_t disk, uint16_t index)
3252 * INPUT: disk - a disk dm_descirptor_t handle
3253 * undex - a VTOC slice index
3255 * RETURNS: int - 0 on success
3258 * PURPOSE: Reserves the input VTOC slice index for the input disk.
3260 * The list of reserved indices is stored as an array in
3261 * the disk's nvpair attribute list.
3265 dm_descriptor_t disk
,
3268 nvlist_t
*attrs
= NULL
;
3269 uint16_t *oldindexes
= NULL
;
3270 uint16_t *newindexes
= NULL
;
3275 if ((error
= get_cached_attributes(disk
, &attrs
)) != 0) {
3279 if ((error
= get_uint16_array(
3280 attrs
, ATTR_RESERVED_INDEX
, &oldindexes
, &nelem
)) != 0) {
3281 if (error
!= ENOENT
) {
3284 /* no reserved indices yet */
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
];
3294 newindexes
[(int)index
] = 1;
3296 error
= set_uint16_array(attrs
, ATTR_RESERVED_INDEX
,
3297 newindexes
, VTOC_SIZE
);
3307 * FUNCTION: disk_release_index(dm_descriptor_t disk, uint16_t index)
3309 * INPUT: disk - a disk dm_descirptor_t handle
3310 * undex - a VTOC slice index
3312 * RETURNS: int - 0 on success
3315 * PURPOSE: Releases the input VTOC slice index for the input disk.
3316 * The index was previously reserved by disk_reserve_index()
3320 dm_descriptor_t disk
,
3323 nvlist_t
*attrs
= NULL
;
3324 uint16_t *oldindexes
= NULL
;
3325 uint16_t *newindexes
= NULL
;
3330 if ((error
= get_cached_attributes(disk
, &attrs
)) != 0) {
3334 if ((error
= get_uint16_array(
3335 attrs
, ATTR_RESERVED_INDEX
, &oldindexes
, &nelem
)) != 0) {
3336 if (error
!= ENOENT
) {
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
];
3349 newindexes
[(int)index
] = 0;
3351 error
= set_uint16_array(attrs
, ATTR_RESERVED_INDEX
,
3352 newindexes
, VTOC_SIZE
);
3363 * FUNCTION: print_get_assoc_desc_error(dm_descriptor_t desc, char *which,
3366 * INPUT: desc - a dm_descriptor_t handle
3367 * which - a char * indicating which association
3368 * error - an integer error value
3370 * PURPOSE: Utility function to print an error message for a failed
3371 * call to dm_get_associated_descriptors().
3373 * Extracts the device's CTD name and formats an error message.
3376 print_get_assoc_desc_error(
3377 dm_descriptor_t desc
,
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
);
3390 gettext("Unexpected error getting associated "
3391 "descriptors for '%s'"),
3396 * FUNCTION: print_get_desc_attr_error(dm_descriptor_t desc,
3397 * char *devtype, char *attr, int error)
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
3404 * PURPOSE: Shared utility function to print an error message for a failed
3405 * call to retrieve an attribute for a descriptor.
3407 * Extracts the device's CTD name and formats an error message.
3410 print_get_desc_attr_error(
3411 dm_descriptor_t desc
,
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
);
3424 gettext("Unexpected error getting attribute '%s.%s' for '%s'"),
3425 devtype
, attr
, name
);
3429 * FUNCTION: print_set_desc_attr_error(dm_descriptor_t desc,
3430 * char *devtype, char *attr, int error)
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
3437 * PURPOSE: Shared utility function to print an error message for a failed
3438 * call to set an attribute for a descriptor.
3440 * Extracts the device's CTD name and formats an error message.
3443 print_set_desc_attr_error(
3444 dm_descriptor_t desc
,
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
);
3457 gettext("Unexpected error setting attribute '%s.%s' for '%s'"),
3458 devtype
, attr
, name
);