10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*62Sjeanm  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/vtoc.h>
340Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate #include <meta.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <libdiskmgt.h>
390Sstevel@tonic-gate #include "meta_repartition.h"
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #define	_LAYOUT_DEVICE_UTIL_C
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include "volume_dlist.h"
440Sstevel@tonic-gate #include "volume_error.h"
450Sstevel@tonic-gate #include "volume_output.h"
460Sstevel@tonic-gate #include "volume_nvpair.h"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include "layout_device_cache.h"
490Sstevel@tonic-gate #include "layout_device_util.h"
500Sstevel@tonic-gate #include "layout_discovery.h"
510Sstevel@tonic-gate #include "layout_dlist_util.h"
520Sstevel@tonic-gate #include "layout_slice.h"
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  *	Macros to produce a quoted string containing the value of a
560Sstevel@tonic-gate  *	preprocessor macro. For example, if SIZE is defined to be 256,
570Sstevel@tonic-gate  *	VAL2STR(SIZE) is "256". This is used to construct format
580Sstevel@tonic-gate  *	strings for scanf-family functions below.
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate #define	QUOTE(x)	#x
610Sstevel@tonic-gate #define	VAL2STR(x)	QUOTE(x)
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /* private utilities for disks */
640Sstevel@tonic-gate static int disk_get_uint64_attribute(
650Sstevel@tonic-gate 	dm_descriptor_t disk,
660Sstevel@tonic-gate 	char		*attr,
670Sstevel@tonic-gate 	uint64_t 	*val);
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static int disk_get_boolean_attribute(
700Sstevel@tonic-gate 	dm_descriptor_t	disk,
710Sstevel@tonic-gate 	char		*attr,
720Sstevel@tonic-gate 	boolean_t	*bool);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate static int disk_get_rpm(
750Sstevel@tonic-gate 	dm_descriptor_t disk,
760Sstevel@tonic-gate 	uint32_t 	*val);
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static int disk_get_sync_speed(
790Sstevel@tonic-gate 	dm_descriptor_t disk,
800Sstevel@tonic-gate 	uint32_t 	*val);
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static int disk_has_virtual_slices(
830Sstevel@tonic-gate 	dm_descriptor_t disk,
840Sstevel@tonic-gate 	boolean_t 	*bool);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate static int disk_get_virtual_slices(
870Sstevel@tonic-gate 	dm_descriptor_t disk,
880Sstevel@tonic-gate 	dlist_t 	**list);
890Sstevel@tonic-gate 
900Sstevel@tonic-gate static int disk_get_reserved_indexes(
910Sstevel@tonic-gate 	dm_descriptor_t disk,
920Sstevel@tonic-gate 	uint16_t 	**array);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate static int disk_get_associated_desc(
950Sstevel@tonic-gate 	dm_descriptor_t	disk,
960Sstevel@tonic-gate 	dm_desc_type_t	assoc_type,
970Sstevel@tonic-gate 	char		*assoc_type_str,
980Sstevel@tonic-gate 	dlist_t		**list);
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /* utilities for slices */
1010Sstevel@tonic-gate static int slice_get_uint64_attribute(
1020Sstevel@tonic-gate 	dm_descriptor_t slice,
1030Sstevel@tonic-gate 	char		*attr,
1040Sstevel@tonic-gate 	uint64_t 	*val);
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate static int slice_set_attribute(
1070Sstevel@tonic-gate 	dm_descriptor_t slice,
1080Sstevel@tonic-gate 	char		*attr,
1090Sstevel@tonic-gate 	uint64_t 	val);
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate  * Virtual slices are created to represent slices that will be
1130Sstevel@tonic-gate  * on the system after disks have been added to the destination
1140Sstevel@tonic-gate  * diskset.  For the purposes of layout, these slices must
1150Sstevel@tonic-gate  * look & function just as real slices that are currently on
1160Sstevel@tonic-gate  * the system.
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate static dlist_t	*_virtual_slices = NULL;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /* temporary implementation */
1210Sstevel@tonic-gate static int virtual_repartition_drive(
1220Sstevel@tonic-gate 	dm_descriptor_t disk,
1230Sstevel@tonic-gate 	mdvtoc_t	*vtocp);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate static int disk_add_virtual_slice(
1260Sstevel@tonic-gate 	dm_descriptor_t disk,
1270Sstevel@tonic-gate 	dm_descriptor_t slice);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static int virtual_slice_get_disk(
1300Sstevel@tonic-gate 	dm_descriptor_t slice,
1310Sstevel@tonic-gate 	dm_descriptor_t *diskp);
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /*
1340Sstevel@tonic-gate  * attribute names for layout private information stored in
1350Sstevel@tonic-gate  * device nvpair attribute lists.
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate static char *ATTR_RESERVED_INDEX = "vdu_reserved_index";
1380Sstevel@tonic-gate static char *ATTR_VIRTUAL_SLICES = "vdu_virtual_slices";
1390Sstevel@tonic-gate static char *ATTR_DISK_FOR_SLICE = "vdu_disk_for_slice";
1400Sstevel@tonic-gate static char *ATTR_DEV_CTD_NAME = "vdu_device_ctd_name";
1410Sstevel@tonic-gate static char *ATTR_HBA_N_DISKS = "vdu_hba_n_usable_disks";
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate  * FUNCTION:	is_ctd_like_slice_name(char *name)
1450Sstevel@tonic-gate  * INPUT:	name	- a char *
1460Sstevel@tonic-gate  *
1470Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name follows an alternate slice
1480Sstevel@tonic-gate  *				naming scheme similar to CTD
1490Sstevel@tonic-gate  *			    B_FALSE - otherwise
1500Sstevel@tonic-gate  *
1510Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is of the form XXXsNNN
1520Sstevel@tonic-gate  *		(e.g., whizzy0s1)
1530Sstevel@tonic-gate  */
1540Sstevel@tonic-gate boolean_t
is_ctd_like_slice_name(char * name)1550Sstevel@tonic-gate is_ctd_like_slice_name(
1560Sstevel@tonic-gate 	char *name)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	uint_t		s = 0;
1590Sstevel@tonic-gate 	uint_t		d = 0;
1600Sstevel@tonic-gate 	int		l = 0;
1610Sstevel@tonic-gate 	boolean_t	is = B_FALSE;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	/* The format strings below match and discard the non-numeric part. */
1640Sstevel@tonic-gate 	if ((sscanf(name, "/dev/dsk/%*[^0-9/]%us%u%n", &d, &s, &l) == 2 ||
1650Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/%*[^0-9/]%us%u%n", &d, &s, &l) == 2 ||
1660Sstevel@tonic-gate 	    sscanf(name, "%*[^0-9/]%us%u%n", &d, &s, &l) == 2) &&
1670Sstevel@tonic-gate 		(l == strlen(name))) {
1680Sstevel@tonic-gate 	    is = B_TRUE;
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	return (is);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate  * FUNCTION:	is_bsd_like_slice_name(char *name)
1760Sstevel@tonic-gate  * INPUT:	name	- a char *
1770Sstevel@tonic-gate  *
1780Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name follows an alternate slice
1790Sstevel@tonic-gate  *				BSD-like naming scheme
1800Sstevel@tonic-gate  *			    B_FALSE - otherwise
1810Sstevel@tonic-gate  *
1820Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is of the form XXXNNN[a-h]
1830Sstevel@tonic-gate  *			(e.g., whizzy0a)
1840Sstevel@tonic-gate  */
1850Sstevel@tonic-gate boolean_t
is_bsd_like_slice_name(char * name)1860Sstevel@tonic-gate is_bsd_like_slice_name(
1870Sstevel@tonic-gate 	char *name)
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate 	uint_t		d = 0;
1900Sstevel@tonic-gate 	int		l = 0;
1910Sstevel@tonic-gate 	boolean_t	is = B_FALSE;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/* The format strings below match and discard the non-numeric part. */
1940Sstevel@tonic-gate 	if ((sscanf(name, "/dev/dsk/%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1 ||
1950Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1 ||
1960Sstevel@tonic-gate 	    sscanf(name, "%*[^0-9/]%u%*[a-h]%n", &d, &l) == 1) &&
1970Sstevel@tonic-gate 		(l == strlen(name))) {
1980Sstevel@tonic-gate 	    is = B_TRUE;
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	return (is);
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate /*
2050Sstevel@tonic-gate  * FUNCTION:	is_did_name(char *name)
2060Sstevel@tonic-gate  * INPUT:	name	- a char *
2070Sstevel@tonic-gate  *
2080Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name is from the DID namespace
2090Sstevel@tonic-gate  *			    B_FALSE - otherwise
2100Sstevel@tonic-gate  *
2110Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is from the DID namespace.
2120Sstevel@tonic-gate  */
2130Sstevel@tonic-gate boolean_t
is_did_name(char * name)2140Sstevel@tonic-gate is_did_name(
2150Sstevel@tonic-gate 	char *name)
2160Sstevel@tonic-gate {
2170Sstevel@tonic-gate 	return (is_did_slice_name(name) || is_did_disk_name(name));
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate /*
2210Sstevel@tonic-gate  * FUNCTION:	is_did_slice_name(char *name)
2220Sstevel@tonic-gate  * INPUT:	name	- a char *
2230Sstevel@tonic-gate  *
2240Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name represents a slice from the DID
2250Sstevel@tonic-gate  *					namespace
2260Sstevel@tonic-gate  *			    B_FALSE - otherwise
2270Sstevel@tonic-gate  *
2280Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is a slice from the DID namespace.
2290Sstevel@tonic-gate  */
2300Sstevel@tonic-gate boolean_t
is_did_slice_name(char * name)2310Sstevel@tonic-gate is_did_slice_name(
2320Sstevel@tonic-gate 	char *name)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate 	uint_t		d = 0, s = 0;
2350Sstevel@tonic-gate 	int		l = 0;
2360Sstevel@tonic-gate 	boolean_t	is = B_FALSE;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	if ((sscanf(name, "/dev/did/rdsk/d%us%u%n", &d, &s, &l) == 2 ||
2390Sstevel@tonic-gate 		sscanf(name, "/dev/did/dsk/d%us%u%n", &d, &s, &l) == 2 ||
2400Sstevel@tonic-gate 		sscanf(name, "d%us%u%n", &d, &s, &l) == 2) ||
2410Sstevel@tonic-gate 		(l == strlen(name))) {
2420Sstevel@tonic-gate 	    is = B_TRUE;
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	return (is);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * FUNCTION:	is_did_disk_name(char *name)
2500Sstevel@tonic-gate  * INPUT:	name	- a char *
2510Sstevel@tonic-gate  *
2520Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name represents a disk from the DID
2530Sstevel@tonic-gate  *					namespace
2540Sstevel@tonic-gate  *			    B_FALSE - otherwise
2550Sstevel@tonic-gate  *
2560Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is a disk from the DID namespace.
2570Sstevel@tonic-gate  */
2580Sstevel@tonic-gate boolean_t
is_did_disk_name(char * name)2590Sstevel@tonic-gate is_did_disk_name(
2600Sstevel@tonic-gate 	char *name)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	uint_t		d = 0;
2630Sstevel@tonic-gate 	int		l = 0;
2640Sstevel@tonic-gate 	boolean_t	is = B_FALSE;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	if ((sscanf(name, "/dev/did/rdsk/d%u%n", &d, &l) == 1 ||
2670Sstevel@tonic-gate 		sscanf(name, "/dev/did/dsk/d%u%n", &d, &l) == 1 ||
2680Sstevel@tonic-gate 		sscanf(name, "d%u%n", &d, &l) == 1) &&
2690Sstevel@tonic-gate 		(l == strlen(name))) {
2700Sstevel@tonic-gate 	    is = B_TRUE;
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	return (is);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate /*
2770Sstevel@tonic-gate  * FUNCTION:	is_ctd_name(char *name)
2780Sstevel@tonic-gate  * INPUT:	name	- a char *
2790Sstevel@tonic-gate  *
2800Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name is from the CTD namespace
2810Sstevel@tonic-gate  *			    B_FALSE - otherwise
2820Sstevel@tonic-gate  *
2830Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is from the CTD namespace.
2840Sstevel@tonic-gate  *
2850Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXtXdXsX
2860Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXtXdX
2870Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXdXsX
2880Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXdX
2890Sstevel@tonic-gate  */
2900Sstevel@tonic-gate boolean_t
is_ctd_name(char * name)2910Sstevel@tonic-gate is_ctd_name(
2920Sstevel@tonic-gate 	char *name)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	return (is_ctd_slice_name(name) || is_ctd_disk_name(name) ||
2950Sstevel@tonic-gate 		is_ctd_target_name(name) || is_ctd_ctrl_name(name));
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate /*
2990Sstevel@tonic-gate  * FUNCTION:	is_ctd_slice_name(char *name)
3000Sstevel@tonic-gate  * INPUT:	name	- a char *
3010Sstevel@tonic-gate  *
3020Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name represents a slice from the CTD
3030Sstevel@tonic-gate  *				namespace
3040Sstevel@tonic-gate  *			    B_FALSE - otherwise
3050Sstevel@tonic-gate  *
3060Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is a slice name from the
3070Sstevel@tonic-gate  *		CTD namespace.
3080Sstevel@tonic-gate  *
3090Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXt<WWN>dXsX
3100Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXtXdXsX
3110Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXdXsX
3120Sstevel@tonic-gate  */
3130Sstevel@tonic-gate boolean_t
is_ctd_slice_name(char * name)3140Sstevel@tonic-gate is_ctd_slice_name(
3150Sstevel@tonic-gate     char *name)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	uint_t		c = 0, t = 0, d = 0, s = 0;
3180Sstevel@tonic-gate 	char		buf[MAXNAMELEN+1];
3190Sstevel@tonic-gate 	int		l = 0;
3200Sstevel@tonic-gate 	boolean_t	is = B_FALSE;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if ((sscanf(name, "/dev/dsk/c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 ||
3230Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 ||
3240Sstevel@tonic-gate 	    sscanf(name, "c%ut%ud%us%u%n", &c, &t, &d, &s, &l) == 4 ||
3250Sstevel@tonic-gate 	    sscanf(name, "/dev/dsk/c%ud%us%u%n", &c, &d, &s, &l) == 3 ||
3260Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%ud%us%u%n", &c, &d, &s, &l) == 3 ||
3270Sstevel@tonic-gate 	    sscanf(name, "c%ud%us%u%n", &c, &d, &s, &l) == 3 ||
3280Sstevel@tonic-gate 	    sscanf(name, "c%ud%us%u%n", &c, &d, &s, &l) == 2) &&
3290Sstevel@tonic-gate 		(l == strlen(name))) {
3300Sstevel@tonic-gate 	    is = B_TRUE;
3310Sstevel@tonic-gate 	} else if (
3320Sstevel@tonic-gate 	    (sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
3330Sstevel@tonic-gate 		&c, buf, &l) == 2 ||
3340Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
3350Sstevel@tonic-gate 		&c, buf, &l) == 2 ||
3360Sstevel@tonic-gate 	    sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n",
3370Sstevel@tonic-gate 		&c, buf, &l) == 2) && (l == strlen(name))) {
3380Sstevel@tonic-gate 	    char *dev_pos;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	    /* see if buf ends with "dXsX" */
3410Sstevel@tonic-gate 	    if (((dev_pos = strrchr(buf, 'd')) != NULL) &&
3420Sstevel@tonic-gate 		(sscanf(dev_pos, "d%us%u%n", &d, &s, &l) == 2) &&
3430Sstevel@tonic-gate 		(l == strlen(dev_pos))) {
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 		char wwn[MAXNAMELEN+2];
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		/* buf ends with "dXsX", truncate at the 'd' */
3480Sstevel@tonic-gate 		*dev_pos = '\0';
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 		/* prepend "0X" to remainder and try to scan as a hex WWN */
3510Sstevel@tonic-gate 		(void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf);
3520Sstevel@tonic-gate 		if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) {
3530Sstevel@tonic-gate 		    is = B_TRUE;
3540Sstevel@tonic-gate 		}
3550Sstevel@tonic-gate 	    }
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	return (is);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate /*
3620Sstevel@tonic-gate  * FUNCTION:	is_ctd_disk_name(char *name)
3630Sstevel@tonic-gate  * INPUT:	name	- a char *
3640Sstevel@tonic-gate  *
3650Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name represents a disk from the CTD
3660Sstevel@tonic-gate  *				namespace
3670Sstevel@tonic-gate  *			    B_FALSE - otherwise
3680Sstevel@tonic-gate  *
3690Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is a disk name from the
3700Sstevel@tonic-gate  *		CTD namespace.
3710Sstevel@tonic-gate  *
3720Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXt<WWN>dX
3730Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXtXdX
3740Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXdX
3750Sstevel@tonic-gate  */
3760Sstevel@tonic-gate boolean_t
is_ctd_disk_name(char * name)3770Sstevel@tonic-gate is_ctd_disk_name(
3780Sstevel@tonic-gate     char *name)
3790Sstevel@tonic-gate {
3800Sstevel@tonic-gate 	uint_t		c = 0, t = 0, d = 0;
3810Sstevel@tonic-gate 	int		l = 0;
3820Sstevel@tonic-gate 	char		buf[MAXNAMELEN+1];
3830Sstevel@tonic-gate 	boolean_t	is = B_FALSE;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	if ((sscanf(name, "/dev/dsk/c%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
3860Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
3870Sstevel@tonic-gate 	    sscanf(name, "c%ut%ud%u%n", &c, &t, &d, &l) == 3 ||
3880Sstevel@tonic-gate 	    sscanf(name, "/dev/dsk/c%ud%u%n", &c, &d, &l) == 2 ||
3890Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%ud%n%n", &c, &d, &l) == 2 ||
3900Sstevel@tonic-gate 	    sscanf(name, "c%ud%u%n", &c, &d, &l) == 2) &&
3910Sstevel@tonic-gate 		(l == strlen(name))) {
3920Sstevel@tonic-gate 	    is = B_TRUE;
3930Sstevel@tonic-gate 	} else if ((sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
3940Sstevel@tonic-gate 	    &c, buf, &l) == 2 ||
3950Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
3960Sstevel@tonic-gate 		&c, buf, &l) == 2 ||
3970Sstevel@tonic-gate 	    sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n",
3980Sstevel@tonic-gate 		&c, buf, &l) == 2) && (l == strlen(name))) {
3990Sstevel@tonic-gate 	    char *dev_pos;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	    /* see if buf ends with "dX" */
4020Sstevel@tonic-gate 	    if (((dev_pos = strrchr(buf, 'd')) != NULL) &&
4030Sstevel@tonic-gate 		(sscanf(dev_pos, "d%u%n", &d, &l) == 1) &&
4040Sstevel@tonic-gate 		(l == strlen(dev_pos))) {
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		char wwn[MAXNAMELEN+2];
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		/* buf ends with "dX", truncate at the 'd' */
4090Sstevel@tonic-gate 		*dev_pos = '\0';
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 		/* prepend "0X" to remainder and try to scan as a hex WWN */
4120Sstevel@tonic-gate 		(void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf);
4130Sstevel@tonic-gate 		if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) {
4140Sstevel@tonic-gate 		    is = B_TRUE;
4150Sstevel@tonic-gate 		}
4160Sstevel@tonic-gate 	    }
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	return (is);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate /*
4230Sstevel@tonic-gate  * FUNCTION:	is_ctd_disk_name(char *name)
4240Sstevel@tonic-gate  * INPUT:	name	- a char *
4250Sstevel@tonic-gate  *
4260Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name represents a target from the CTD
4270Sstevel@tonic-gate  *				namespace
4280Sstevel@tonic-gate  *			    B_FALSE - otherwise
4290Sstevel@tonic-gate  *
4300Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is a target name from the
4310Sstevel@tonic-gate  *		CTD namespace.
4320Sstevel@tonic-gate  *
4330Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXt<WWN>
4340Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cXtX
4350Sstevel@tonic-gate  */
4360Sstevel@tonic-gate boolean_t
is_ctd_target_name(char * name)4370Sstevel@tonic-gate is_ctd_target_name(
4380Sstevel@tonic-gate     char *name)
4390Sstevel@tonic-gate {
4400Sstevel@tonic-gate 	uint_t		c = 0, t = 0;
4410Sstevel@tonic-gate 	int		l = 0;
4420Sstevel@tonic-gate 	char		buf[MAXNAMELEN+1];
4430Sstevel@tonic-gate 	boolean_t	is = B_FALSE;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if ((sscanf(name, "/dev/dsk/c%ut%u%n", &c, &t, &l) == 2 ||
4460Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%ut%u%n", &c, &t, &l) == 2 ||
4470Sstevel@tonic-gate 	    sscanf(name, "c%ut%u%n", &c, &t, &l) == 2) &&
4480Sstevel@tonic-gate 		(l == strlen(name))) {
4490Sstevel@tonic-gate 	    is = B_TRUE;
4500Sstevel@tonic-gate 	} else if (
4510Sstevel@tonic-gate 	    (sscanf(name, "/dev/dsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
4520Sstevel@tonic-gate 		&c, buf, &l) == 2 ||
4530Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%ut%" VAL2STR(MAXNAMELEN) "s%n",
4540Sstevel@tonic-gate 		&c, buf, &l) == 2 ||
4550Sstevel@tonic-gate 	    sscanf(name, "c%ut%" VAL2STR(MAXNAMELEN) "s%n",
4560Sstevel@tonic-gate 		&c, &buf, &l) == 2) && (l == strlen(name))) {
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	    char wwn[MAXNAMELEN+2];
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	    /* prepend "0X" to buf and try to scan as a hex WWN */
4610Sstevel@tonic-gate 	    (void) snprintf(wwn, sizeof (wwn), "%s%s", "0X", buf);
4620Sstevel@tonic-gate 	    if ((sscanf(wwn, "%x%n", &t, &l) == 1) && (l == strlen(wwn))) {
4630Sstevel@tonic-gate 		is = B_TRUE;
4640Sstevel@tonic-gate 	    }
4650Sstevel@tonic-gate 	}
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	return (is);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate /*
4710Sstevel@tonic-gate  * FUNCTION:	is_ctd_ctrl_name(char *name)
4720Sstevel@tonic-gate  * INPUT:	name	- a char *
4730Sstevel@tonic-gate  *
4740Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if name represents a controller/hba
4750Sstevel@tonic-gate  *				from the CTD namespace
4760Sstevel@tonic-gate  *			    B_FALSE - otherwise
4770Sstevel@tonic-gate  *
4780Sstevel@tonic-gate  * PURPOSE:	Determines if the input name is an HBA name from the
4790Sstevel@tonic-gate  *		CTD namespace.
4800Sstevel@tonic-gate  *
4810Sstevel@tonic-gate  *		{/dev/dsk/, /dev/rdsk/}cX
4820Sstevel@tonic-gate  */
4830Sstevel@tonic-gate boolean_t
is_ctd_ctrl_name(char * name)4840Sstevel@tonic-gate is_ctd_ctrl_name(
4850Sstevel@tonic-gate 	char	*name)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate 	uint_t		c = 0;
4880Sstevel@tonic-gate 	int		l = 0;
4890Sstevel@tonic-gate 	boolean_t	is = B_FALSE;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	if ((sscanf(name, "/dev/dsk/c%u%n", &c, &l) == 1 ||
4920Sstevel@tonic-gate 	    sscanf(name, "/dev/rdsk/c%u%n", &c, &l) == 1 ||
4930Sstevel@tonic-gate 	    sscanf(name, "c%u%n", &c, &l) == 1) &&
4940Sstevel@tonic-gate 		(l == strlen(name))) {
4950Sstevel@tonic-gate 	    is = B_TRUE;
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	return (is);
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate /*
5020Sstevel@tonic-gate  * FUNCTION:	set_display_name(dm_descriptor_t desc, char *name)
5030Sstevel@tonic-gate  *		get_display_name(dm_descriptor_t desc, char **name)
5040Sstevel@tonic-gate  *
5050Sstevel@tonic-gate  * INPUT:	desc	- a dm_descriptor_t handle for a device
5060Sstevel@tonic-gate  *		name    - a char * name
5070Sstevel@tonic-gate  *
5080Sstevel@tonic-gate  * OUTPUT:	**name	- a pointer to a char * to hold the display
5090Sstevel@tonic-gate  *			name associated with the input descriptor.
5100Sstevel@tonic-gate  *
5110Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
5120Sstevel@tonic-gate  *			 !0 otherwise.
5130Sstevel@tonic-gate  *
5140Sstevel@tonic-gate  * PURPOSE:	Helpers to set/get the input descriptor's display name.
5150Sstevel@tonic-gate  *
5160Sstevel@tonic-gate  *		Only slices, disks and HBAs should have display names.
5170Sstevel@tonic-gate  *
5180Sstevel@tonic-gate  *		The attribute is only set in the cached copy of
5190Sstevel@tonic-gate  *		the device's nvpair attribute list.  This function
5200Sstevel@tonic-gate  *		does not affect the underlying physical device.
5210Sstevel@tonic-gate  *
5220Sstevel@tonic-gate  *		An entry is added in the name->descriptor cache
5230Sstevel@tonic-gate  *		so the descriptor can be found by name quickly.
5240Sstevel@tonic-gate  */
5250Sstevel@tonic-gate int
set_display_name(dm_descriptor_t desc,char * name)5260Sstevel@tonic-gate set_display_name(
5270Sstevel@tonic-gate 	dm_descriptor_t	desc,
5280Sstevel@tonic-gate 	char		*name)
5290Sstevel@tonic-gate {
5300Sstevel@tonic-gate 	nvlist_t	*attrs	= NULL;
5310Sstevel@tonic-gate 	int		error	= 0;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	((error = add_cached_descriptor(name, desc)) != 0) ||
5340Sstevel@tonic-gate 	(error = get_cached_attributes(desc, &attrs)) ||
5350Sstevel@tonic-gate 	(error = set_string(attrs, ATTR_DEV_CTD_NAME, name));
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	return (error);
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate int
get_display_name(dm_descriptor_t desc,char ** name)5410Sstevel@tonic-gate get_display_name(
5420Sstevel@tonic-gate 	dm_descriptor_t	desc,
5430Sstevel@tonic-gate 	char		**name)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate 	nvlist_t	*attrs	= NULL;
5460Sstevel@tonic-gate 	int		error	= 0;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	((error = get_cached_attributes(desc, &attrs)) != 0) ||
5490Sstevel@tonic-gate 	(error = get_string(attrs, ATTR_DEV_CTD_NAME, name));
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	return (error);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate /*
5550Sstevel@tonic-gate  * FUNCTION:	disk_get_slices(dm_descriptor_t disk, dlist_t **list)
5560Sstevel@tonic-gate  *
5570Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
5580Sstevel@tonic-gate  *
5590Sstevel@tonic-gate  * OUTPUT:	*list	- a pointer to list to hold the results.
5600Sstevel@tonic-gate  *
5610Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
5620Sstevel@tonic-gate  *			 !0 otherwise.
5630Sstevel@tonic-gate  *
5640Sstevel@tonic-gate  * PURPOSE:	Collect all of the known slices for the input disk.
5650Sstevel@tonic-gate  *
5660Sstevel@tonic-gate  *		These slices may be actual slices which currently exist
5670Sstevel@tonic-gate  *		on the disk, or virtual slices which will exist when the
5680Sstevel@tonic-gate  *		disk is added to the destination diskset.
5690Sstevel@tonic-gate  */
5700Sstevel@tonic-gate int
disk_get_slices(dm_descriptor_t disk,dlist_t ** list)5710Sstevel@tonic-gate disk_get_slices(
5720Sstevel@tonic-gate 	dm_descriptor_t disk,
5730Sstevel@tonic-gate 	dlist_t		**list)
5740Sstevel@tonic-gate {
5750Sstevel@tonic-gate 	dm_descriptor_t	*media = NULL;
5760Sstevel@tonic-gate 	boolean_t	virtual = B_FALSE;
5770Sstevel@tonic-gate 	int		i = 0;
5780Sstevel@tonic-gate 	int		error = 0;
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	*list = 0;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	if ((error = disk_has_virtual_slices(disk, &virtual)) != 0) {
5830Sstevel@tonic-gate 	    return (error);
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	if (virtual == B_TRUE) {
5870Sstevel@tonic-gate 	    error = disk_get_virtual_slices(disk, list);
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	/* add real slices from disk's media... */
5910Sstevel@tonic-gate 	media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
5920Sstevel@tonic-gate 	(void) add_descriptors_to_free(media);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	if (error == 0) {
5950Sstevel@tonic-gate 	    /* if there's no media, this is a removeable drive */
5960Sstevel@tonic-gate 	    if (media != NULL && *media != NULL) {
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 		/* examine media's slices... */
5990Sstevel@tonic-gate 		dm_descriptor_t	*slices = NULL;
6000Sstevel@tonic-gate 		slices = dm_get_associated_descriptors(*media,
6010Sstevel@tonic-gate 			DM_SLICE, &error);
6020Sstevel@tonic-gate 		(void) add_descriptors_to_free(slices);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 		if (error != 0) {
6050Sstevel@tonic-gate 		    print_get_assoc_desc_error(disk, gettext("slice"), error);
6060Sstevel@tonic-gate 		} else {
6070Sstevel@tonic-gate 		    for (i = 0; (slices[i] != NULL) && (error == 0); i++) {
608*62Sjeanm 			dlist_t *item =
609*62Sjeanm 			    dlist_new_item((void *)(uintptr_t)slices[i]);
6100Sstevel@tonic-gate 			if (item == NULL) {
6110Sstevel@tonic-gate 			    error = ENOMEM;
6120Sstevel@tonic-gate 			} else {
6130Sstevel@tonic-gate 			    *list = dlist_append(item, *list, AT_TAIL);
6140Sstevel@tonic-gate 			}
6150Sstevel@tonic-gate 		    }
6160Sstevel@tonic-gate 		    free(slices);
6170Sstevel@tonic-gate 		}
6180Sstevel@tonic-gate 		free(media);
6190Sstevel@tonic-gate 	    }
6200Sstevel@tonic-gate 	} else {
6210Sstevel@tonic-gate 	    print_get_assoc_desc_error(disk, gettext("media"), error);
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	return (error);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate int
get_virtual_slices(dlist_t ** list)6280Sstevel@tonic-gate get_virtual_slices(
6290Sstevel@tonic-gate 	dlist_t **list)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate 	*list = _virtual_slices;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	return (0);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate /*
6370Sstevel@tonic-gate  * FUNCTION:	virtual_repartition_drive(dm_descriptor_t disk,
6380Sstevel@tonic-gate  *			mdvtoc_t *vtocp)
6390Sstevel@tonic-gate  *
6400Sstevel@tonic-gate  * INPUT:	disk	- the disk to be virtually repartitioned
6410Sstevel@tonic-gate  *
6420Sstevel@tonic-gate  * OUTPUT:	vtocp	- a poitner to a mdvtoc struct to hold the results
6430Sstevel@tonic-gate  *
6440Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
6450Sstevel@tonic-gate  *			 !0 otherwise.
6460Sstevel@tonic-gate  *
6470Sstevel@tonic-gate  * PURPOSE:	Helper which emulates the repartitioning that is done
6480Sstevel@tonic-gate  *		when a disk is added to a diskset.
6490Sstevel@tonic-gate  *
6500Sstevel@tonic-gate  *		Modified version of meta_partition_drive which uses info
6510Sstevel@tonic-gate  * 		from libdiskmgt to accomplish the repartitioning.
6520Sstevel@tonic-gate  *
6530Sstevel@tonic-gate  * 		This exists to allow the layout module to run with a
6540Sstevel@tonic-gate  *		simulated hardware environment.
6550Sstevel@tonic-gate  *
6560Sstevel@tonic-gate  *		XXX This method absolutely does not produce the exact
6570Sstevel@tonic-gate  *		same result as meta_repartition_drive: only information
6580Sstevel@tonic-gate  *		required by the layout code is returned.  Basically,
6590Sstevel@tonic-gate  *		a slice 7 (or 6 on EFI labelled disks) is created and
6600Sstevel@tonic-gate  *		sized, the remained of the available cylinders are put
6610Sstevel@tonic-gate  *		into slice 0.
6620Sstevel@tonic-gate  *
6630Sstevel@tonic-gate  *		XXX2 This method is required until there is resolution
6640Sstevel@tonic-gate  *		on whether metassist testing will be done using the
6650Sstevel@tonic-gate  *		hardware simulation mechanism libdiskmgt provides.
6660Sstevel@tonic-gate  *		Doing so will also require parts of libmeta to be
6670Sstevel@tonic-gate  *		simulated as well.  Some research has been done into
6680Sstevel@tonic-gate  *		building an alternate libmeta.so containing
6690Sstevel@tonic-gate  *		implementations of the functions used by metassist
6700Sstevel@tonic-gate  *		that are compatible with the simulated hardware.
6710Sstevel@tonic-gate  *		Actual work is currently on hold.
6720Sstevel@tonic-gate  */
6730Sstevel@tonic-gate static int
virtual_repartition_drive(dm_descriptor_t disk,mdvtoc_t * vtocp)6740Sstevel@tonic-gate virtual_repartition_drive(
6750Sstevel@tonic-gate 	dm_descriptor_t	disk,
6760Sstevel@tonic-gate 	mdvtoc_t	*vtocp)
6770Sstevel@tonic-gate {
6780Sstevel@tonic-gate 	uint_t		replicaslice = 7;
6790Sstevel@tonic-gate 	unsigned long long cylsize;
6800Sstevel@tonic-gate 	unsigned long long drvsize;
6810Sstevel@tonic-gate 	uint_t		reservedcyl;
6820Sstevel@tonic-gate 	ushort_t	resflag;
6830Sstevel@tonic-gate 	unsigned long long ressize;
6840Sstevel@tonic-gate 	diskaddr_t	replica_start;
6850Sstevel@tonic-gate 	diskaddr_t	replica_size;
6860Sstevel@tonic-gate 	diskaddr_t	data_start;
6870Sstevel@tonic-gate 	diskaddr_t	data_size;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	boolean_t	efi = B_FALSE;
6900Sstevel@tonic-gate 	uint64_t	ncyls = 0;
6910Sstevel@tonic-gate 	uint64_t	nheads = 0;
6920Sstevel@tonic-gate 	uint64_t	nsects = 0;
6930Sstevel@tonic-gate 	int		error = 0;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/*
6960Sstevel@tonic-gate 	 * At this point, ressize is used as a minimum value.  Later it
6970Sstevel@tonic-gate 	 * will be rounded up to a cylinder boundary.  ressize is in
6980Sstevel@tonic-gate 	 * units of disk sectors.
6990Sstevel@tonic-gate 	 */
7000Sstevel@tonic-gate 	ressize = MD_DBSIZE + VTOC_SIZE;
7010Sstevel@tonic-gate 	resflag = V_UNMNT;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	((error = disk_get_is_efi(disk, &efi)) != 0) ||
7040Sstevel@tonic-gate 	(error = disk_get_ncylinders(disk, &ncyls)) ||
7050Sstevel@tonic-gate 	(error = disk_get_nheads(disk, &nheads)) ||
7060Sstevel@tonic-gate 	(error = disk_get_nsectors(disk, &nsects));
7070Sstevel@tonic-gate 	if (error != 0) {
7080Sstevel@tonic-gate 	    return (error);
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	if (efi) {
7120Sstevel@tonic-gate 	    replicaslice = 6;
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	/*
7160Sstevel@tonic-gate 	 * Both cylsize and drvsize are in units of disk sectors.
7170Sstevel@tonic-gate 	 *
7180Sstevel@tonic-gate 	 * The intended results are of type unsigned long long.  Since
7190Sstevel@tonic-gate 	 * each operand of the first multiplication is of type
7200Sstevel@tonic-gate 	 * unsigned int, we risk overflow by multiplying and then
7210Sstevel@tonic-gate 	 * converting the result.  Therefore we explicitly cast (at
7220Sstevel@tonic-gate 	 * least) one of the operands, forcing conversion BEFORE
7230Sstevel@tonic-gate 	 * multiplication, and avoiding overflow.  The second
7240Sstevel@tonic-gate 	 * assignment is OK, since one of the operands is already of
7250Sstevel@tonic-gate 	 * the desired type.
7260Sstevel@tonic-gate 	 */
7270Sstevel@tonic-gate 	cylsize = ((unsigned long long)nheads) * nsects;
7280Sstevel@tonic-gate 	drvsize = cylsize * ncyls;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	/*
7310Sstevel@tonic-gate 	 * How many cylinders must we reserve for slice seven to
7320Sstevel@tonic-gate 	 * ensure that it meets the previously calculated minimum
7330Sstevel@tonic-gate 	 * size?
7340Sstevel@tonic-gate 	 */
7350Sstevel@tonic-gate 	reservedcyl = (ressize + cylsize - 1) / cylsize;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	/*
7380Sstevel@tonic-gate 	 * It seems unlikely that someone would pass us too small a
7390Sstevel@tonic-gate 	 * disk, but it's still worth checking for...
7400Sstevel@tonic-gate 	 */
7410Sstevel@tonic-gate 	if (reservedcyl >= ncyls) {
7420Sstevel@tonic-gate 	    volume_set_error(
7430Sstevel@tonic-gate 		    gettext("disk is too small to hold a metadb replica"));
7440Sstevel@tonic-gate 	    return (-1);
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	replica_start = 0;
7480Sstevel@tonic-gate 	replica_size = reservedcyl * cylsize;
7490Sstevel@tonic-gate 	data_start = reservedcyl * cylsize;
7500Sstevel@tonic-gate 	data_size = drvsize - (reservedcyl * cylsize);
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	/*
7530Sstevel@tonic-gate 	 * fill in the proposed VTOC information.
7540Sstevel@tonic-gate 	 */
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	/* We need at least replicaslice partitions in the proposed vtoc */
7570Sstevel@tonic-gate 	vtocp->nparts = replicaslice + 1;
7580Sstevel@tonic-gate 	vtocp->parts[MD_SLICE0].start = data_start;
7590Sstevel@tonic-gate 	vtocp->parts[MD_SLICE0].size = data_size;
7600Sstevel@tonic-gate 	vtocp->parts[MD_SLICE0].tag = V_USR;
7610Sstevel@tonic-gate 	vtocp->parts[replicaslice].start = replica_start;
7620Sstevel@tonic-gate 	vtocp->parts[replicaslice].size = replica_size;
7630Sstevel@tonic-gate 	vtocp->parts[replicaslice].flag = resflag;
7640Sstevel@tonic-gate 	vtocp->parts[replicaslice].tag = V_USR;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	return (0);
7670Sstevel@tonic-gate }
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate /*
7700Sstevel@tonic-gate  * FUNCTION:	create_virtual_slices(dlist_t *disks)
7710Sstevel@tonic-gate  *
7720Sstevel@tonic-gate  * INPUT:	possibles - a list of dm_descriptor_t disk handles for
7730Sstevel@tonic-gate  *			disks known to be available for use by layout.
7740Sstevel@tonic-gate  *
7750Sstevel@tonic-gate  * SIDEEFFECT:	populates the private of virtual slices.
7760Sstevel@tonic-gate  *
7770Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
7780Sstevel@tonic-gate  *			 !0 otherwise.
7790Sstevel@tonic-gate  *
7800Sstevel@tonic-gate  * PURPOSE:	Helper which creates virtual slices for each disk which
7810Sstevel@tonic-gate  *		could be added to a diskset if necessary...
7820Sstevel@tonic-gate  *
7830Sstevel@tonic-gate  *		Iterate the input list of available disks and see what the
7840Sstevel@tonic-gate  *		slicing would be if the disk were added to a diskset.
7850Sstevel@tonic-gate  *
7860Sstevel@tonic-gate  *		For the resulting slices, create virtual slice descriptors
7870Sstevel@tonic-gate  *		and attributes for these slices and add them to the list of
7880Sstevel@tonic-gate  *		available slices.
7890Sstevel@tonic-gate  */
7900Sstevel@tonic-gate int
create_virtual_slices(dlist_t * disks)7910Sstevel@tonic-gate create_virtual_slices(
7920Sstevel@tonic-gate 	dlist_t 	*disks)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate 	int		error = 0;
7950Sstevel@tonic-gate 	dlist_t		*iter;
7960Sstevel@tonic-gate 	boolean_t	sim = B_FALSE;
7970Sstevel@tonic-gate 	static char	*simfile = "METASSISTSIMFILE";
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	sim = ((getenv(simfile) != NULL) && (strlen(getenv(simfile)) > 0));
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	/* see what slices each of the disks will have when added to a set */
8020Sstevel@tonic-gate 	for (iter = disks; error == 0 && iter != NULL; iter = iter->next) {
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	    dm_descriptor_t 	disk = (uintptr_t)iter->obj;
8050Sstevel@tonic-gate 	    dlist_t		*slices = NULL;
8060Sstevel@tonic-gate 	    mdvtoc_t		vtoc;
8070Sstevel@tonic-gate 	    char		*dname;
8080Sstevel@tonic-gate 	    int			i = 0;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	    if ((error = get_display_name(disk, &dname)) != 0) {
8110Sstevel@tonic-gate 		break;
8120Sstevel@tonic-gate 	    }
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	    if (sim != B_TRUE) {
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 		/* sim disabled: use meta_repartition_drive() */
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		md_error_t	mderror = mdnullerror;
8190Sstevel@tonic-gate 		int		opts = (MD_REPART_FORCE | MD_REPART_DONT_LABEL);
8200Sstevel@tonic-gate 		mdsetname_t	*sp;
8210Sstevel@tonic-gate 		mddrivename_t	*dnp;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 		/* disk is in the local set */
8240Sstevel@tonic-gate 		sp = metasetname(MD_LOCAL_NAME, &mderror);
8250Sstevel@tonic-gate 		if (!mdisok(&mderror)) {
8260Sstevel@tonic-gate 		    volume_set_error(mde_sperror(&mderror, NULL));
8270Sstevel@tonic-gate 		    mdclrerror(&mderror);
8280Sstevel@tonic-gate 		    error = -1;
8290Sstevel@tonic-gate 		    break;
8300Sstevel@tonic-gate 		}
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 		dnp = metadrivename(&sp, dname, &mderror);
8330Sstevel@tonic-gate 		if (!mdisok(&mderror)) {
8340Sstevel@tonic-gate 		    volume_set_error(mde_sperror(&mderror, NULL));
8350Sstevel@tonic-gate 		    mdclrerror(&mderror);
8360Sstevel@tonic-gate 		    error = -1;
8370Sstevel@tonic-gate 		    break;
8380Sstevel@tonic-gate 		}
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 		if (meta_repartition_drive(
8410Sstevel@tonic-gate 		    sp, dnp, opts, &vtoc, &mderror) != 0) {
8420Sstevel@tonic-gate 		    volume_set_error(
8430Sstevel@tonic-gate 			    gettext("failed to repartition disk %s\n"),
8440Sstevel@tonic-gate 			    dname);
8450Sstevel@tonic-gate 		    error = -1;
8460Sstevel@tonic-gate 		    break;
8470Sstevel@tonic-gate 		}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	    } else {
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 		/* sim enabled: use faked repartition code */
8520Sstevel@tonic-gate 		if (virtual_repartition_drive(disk, &vtoc) != 0) {
8530Sstevel@tonic-gate 		    volume_set_error(
8540Sstevel@tonic-gate 			    gettext("failed simulated repartition of %s\n"),
8550Sstevel@tonic-gate 			    dname);
8560Sstevel@tonic-gate 		    error = -1;
8570Sstevel@tonic-gate 		    break;
8580Sstevel@tonic-gate 		}
8590Sstevel@tonic-gate 	    }
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	    /* BEGIN CSTYLED */
8620Sstevel@tonic-gate 	    /*
8630Sstevel@tonic-gate 	     * get the existing slices on the disk, if the repartition
8640Sstevel@tonic-gate 	     * was successful, these slices need to have their size, start
8650Sstevel@tonic-gate 	     * blk and size in blks set to 0
8660Sstevel@tonic-gate 	     */
8670Sstevel@tonic-gate 	    /* END CSTYLED */
8680Sstevel@tonic-gate 	    if ((error = disk_get_slices(disk, &slices)) == 0) {
8690Sstevel@tonic-gate 		dlist_t *iter2 = slices;
8700Sstevel@tonic-gate 		for (; iter2 != NULL; iter2 = iter2->next) {
8710Sstevel@tonic-gate 		    dm_descriptor_t sp = (uintptr_t)iter2->obj;
8720Sstevel@tonic-gate 		    ((error = slice_set_start_block(sp, 0)) != 0) ||
8730Sstevel@tonic-gate 		    (error = slice_set_size_in_blocks(sp, 0)) ||
8740Sstevel@tonic-gate 		    (error = slice_set_size(sp, 0));
8750Sstevel@tonic-gate 		}
8760Sstevel@tonic-gate 		dlist_free_items(slices, NULL);
8770Sstevel@tonic-gate 	    }
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	    /* scan VTOC, find slice with the free space */
8800Sstevel@tonic-gate 	    for (i = 0; i < vtoc.nparts; i++) {
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 		if (vtoc.parts[i].tag == V_USR &&
8830Sstevel@tonic-gate 			vtoc.parts[i].flag != V_UNMNT) {
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 		    /* non-replica slice with free space */
8860Sstevel@tonic-gate 		    char buf[MAXPATHLEN];
8870Sstevel@tonic-gate 		    (void) snprintf(buf, MAXPATHLEN-1, "%ss%d", dname, i);
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 		    if ((error = add_virtual_slice(buf,
8900Sstevel@tonic-gate 			(uint32_t)i,
8910Sstevel@tonic-gate 			(uint64_t)vtoc.parts[i].start,
8920Sstevel@tonic-gate 			(uint64_t)vtoc.parts[i].size,
8930Sstevel@tonic-gate 			disk)) != 0) {
8940Sstevel@tonic-gate 			break;
8950Sstevel@tonic-gate 		    }
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 		} else if (vtoc.parts[i].tag == V_RESERVED) {
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 		    /* skip EFI reserved slice */
9000Sstevel@tonic-gate 		    continue;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		} else if (vtoc.parts[i].tag == V_USR &&
9030Sstevel@tonic-gate 			vtoc.parts[i].flag == V_UNMNT) {
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 		    /* BEGIN CSTYLED */
9060Sstevel@tonic-gate 		    /*
9070Sstevel@tonic-gate 		     * Make the replica slice 0 sized -- this will
9080Sstevel@tonic-gate 		     * force the disk to be repartitioned by
9090Sstevel@tonic-gate 		     * metaset when it is added to the disk set.
9100Sstevel@tonic-gate 		     *
9110Sstevel@tonic-gate 		     * XXX this is a temporary workaround until
9120Sstevel@tonic-gate 		     * 4712873 is integrated...
9130Sstevel@tonic-gate 		     */
9140Sstevel@tonic-gate 		    /* BEGIN CSTYLED */
9150Sstevel@tonic-gate 		    char buf[MAXPATHLEN];
9160Sstevel@tonic-gate 		    (void) snprintf(buf, MAXPATHLEN-1, "%ss%d", dname, i);
9170Sstevel@tonic-gate 		    add_slice_to_remove(buf, i);
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 		    /* replica slice, stop here */
9200Sstevel@tonic-gate 		    break;
9210Sstevel@tonic-gate 		}
9220Sstevel@tonic-gate 	    }
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	return (error);
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate /*
9290Sstevel@tonic-gate  * FUNCTION:	add_virtual_slice(char *name, uint32_t index,
9300Sstevel@tonic-gate  *			uint64_t startblk, uint64_t sizeblks,
9310Sstevel@tonic-gate  *			dm_descriptor_t disk)
9320Sstevel@tonic-gate  *
9330Sstevel@tonic-gate  * INPUT:	name	- the name of the new virtual slice
9340Sstevel@tonic-gate  *		index	- the VTOC index ...
9350Sstevel@tonic-gate  *		startblk - the start block ...
9360Sstevel@tonic-gate  *		sizeblks - the size in blocks ...
9370Sstevel@tonic-gate  *		disk	- the parent disk ...
9380Sstevel@tonic-gate  *
9390Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
9400Sstevel@tonic-gate  *			 !0 otherwise.
9410Sstevel@tonic-gate  *
9420Sstevel@tonic-gate  * PURPOSE:	Helper which adds the appropriate data structures to
9430Sstevel@tonic-gate  *		represent a new virtual slice.
9440Sstevel@tonic-gate  *
9450Sstevel@tonic-gate  *		allocates a new descriptor
9460Sstevel@tonic-gate  *		adds entries to name->desc and desc->name caches
9470Sstevel@tonic-gate  *		allocates an attribute nvpair list
9480Sstevel@tonic-gate  *		fills in the relevant attributes for the slice
9490Sstevel@tonic-gate  *		associates the slice with its parent disk
9500Sstevel@tonic-gate  *		adds an entry to the list of all virtual slices
9510Sstevel@tonic-gate  *		generates aliases if the associated disk has aliases.
9520Sstevel@tonic-gate  */
9530Sstevel@tonic-gate int
add_virtual_slice(char * name,uint32_t index,uint64_t startblk,uint64_t sizeblks,dm_descriptor_t disk)9540Sstevel@tonic-gate add_virtual_slice(
9550Sstevel@tonic-gate 	char		*name,
9560Sstevel@tonic-gate 	uint32_t	index,
9570Sstevel@tonic-gate 	uint64_t	startblk,
9580Sstevel@tonic-gate 	uint64_t	sizeblks,
9590Sstevel@tonic-gate 	dm_descriptor_t	disk)
9600Sstevel@tonic-gate {
9610Sstevel@tonic-gate 	dm_descriptor_t sp;
9620Sstevel@tonic-gate 	nvlist_t	*attrs;
9630Sstevel@tonic-gate 	char		*sname;
9640Sstevel@tonic-gate 	dlist_t		*aliases = NULL;
9650Sstevel@tonic-gate 	dlist_t		*item = NULL;
9660Sstevel@tonic-gate 	int 		error = 0;
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	if ((error = nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0)) != 0) {
9690Sstevel@tonic-gate 	    return (error);
9700Sstevel@tonic-gate 	}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	/* create descriptor */
9730Sstevel@tonic-gate 	((error = new_descriptor(&sp)) != 0) ||
9740Sstevel@tonic-gate 	/* cache name for the descriptor */
9750Sstevel@tonic-gate 	(error = add_cached_name(sp, name)) ||
9760Sstevel@tonic-gate 	/* cache descriptor for the name */
9770Sstevel@tonic-gate 	(error = add_cached_descriptor(name, sp)) ||
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	/* fill in attributes */
9800Sstevel@tonic-gate 	(error = set_string(attrs, ATTR_DEV_CTD_NAME, name)) ||
9810Sstevel@tonic-gate 	(error = set_uint32(attrs, DM_INDEX, index)) ||
9820Sstevel@tonic-gate 	(error = set_uint64(attrs, DM_START, startblk)) ||
9830Sstevel@tonic-gate 	(error = set_uint64(attrs, DM_SIZE, sizeblks)) ||
9840Sstevel@tonic-gate 	(error = set_uint64(attrs, ATTR_DISK_FOR_SLICE, (uint64_t)disk)) ||
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	/* add attributes to the cache */
9870Sstevel@tonic-gate 	(error = get_name(sp, &sname)) ||
9880Sstevel@tonic-gate 	(error = add_cached_attributes(sname, attrs)) ||
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	/* connect slice to disk */
9910Sstevel@tonic-gate 	(error = disk_add_virtual_slice(disk, sp)) ||
9920Sstevel@tonic-gate 	(error = get_display_name(disk, &name)) ||
9930Sstevel@tonic-gate 	(error = get_aliases(disk, &aliases));
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	if (error != 0) {
9960Sstevel@tonic-gate 	    return (error);
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	/* generate slice's aliases if the disk has aliases */
10000Sstevel@tonic-gate 	if (aliases != NULL) {
10010Sstevel@tonic-gate 	    char buf[MAXNAMELEN];
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	    for (; aliases != NULL; aliases = aliases->next) {
10040Sstevel@tonic-gate 		(void) snprintf(buf, MAXNAMELEN-1, "%ss%d",
10050Sstevel@tonic-gate 			(char *)aliases->obj, index);
10060Sstevel@tonic-gate 		error = set_alias(sp, buf);
10070Sstevel@tonic-gate 	    }
10080Sstevel@tonic-gate 	    dlist_free_items(aliases, free);
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate 
1011*62Sjeanm 	if ((item = dlist_new_item((void *)(uintptr_t)sp)) == NULL) {
10120Sstevel@tonic-gate 	    return (ENOMEM);
10130Sstevel@tonic-gate 	}
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	_virtual_slices = dlist_append(item, _virtual_slices, AT_HEAD);
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	oprintf(OUTPUT_DEBUG,
10180Sstevel@tonic-gate 		gettext("  created virtual slice %s start: %llu, size: %llu\n"),
10190Sstevel@tonic-gate 		sname, startblk, sizeblks);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	return (error);
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate /*
10250Sstevel@tonic-gate  * FUNCTION:	release_virtual_slices()
10260Sstevel@tonic-gate  *
10270Sstevel@tonic-gate  * PURPOSE:	Helper which cleans up the module private list of virtual
10280Sstevel@tonic-gate  *		slices.
10290Sstevel@tonic-gate  *
10300Sstevel@tonic-gate  *		The descriptors for the virtual slices are cleaned up
10310Sstevel@tonic-gate  *		in device_cache_util.free_cached_descriptors
10320Sstevel@tonic-gate  */
10330Sstevel@tonic-gate void
release_virtual_slices()10340Sstevel@tonic-gate release_virtual_slices()
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate 	dlist_free_items(_virtual_slices, NULL);
10370Sstevel@tonic-gate 	_virtual_slices = NULL;
10380Sstevel@tonic-gate }
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate /*
10410Sstevel@tonic-gate  * FUNCTION:	disk_add_virtual_slice(dm_descriptor_t disk,
10420Sstevel@tonic-gate  *			dm_descriptor_t slice)
10430Sstevel@tonic-gate  *
10440Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t disk handle
10450Sstevel@tonic-gate  *		slice	- a dm_descriptor_t virtual slice handle
10460Sstevel@tonic-gate  *
10470Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
10480Sstevel@tonic-gate  *			 !0 otherwise
10490Sstevel@tonic-gate  *
10500Sstevel@tonic-gate  * PURPOSE:	Helper which adds a virtual slice to the input disk's
10510Sstevel@tonic-gate  *		list of virtual slices.
10520Sstevel@tonic-gate  *
10530Sstevel@tonic-gate  *		The disk's virtual slice dm_descriptor_t handles are
10540Sstevel@tonic-gate  *		stored in the disk's nvpair attribute list.
10550Sstevel@tonic-gate  */
10560Sstevel@tonic-gate static int
disk_add_virtual_slice(dm_descriptor_t disk,dm_descriptor_t slice)10570Sstevel@tonic-gate disk_add_virtual_slice(
10580Sstevel@tonic-gate 	dm_descriptor_t	disk,
10590Sstevel@tonic-gate 	dm_descriptor_t slice)
10600Sstevel@tonic-gate {
10610Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
10620Sstevel@tonic-gate 	uint64_t	*old_slices = NULL;
10630Sstevel@tonic-gate 	uint64_t	*new_slices = NULL;
10640Sstevel@tonic-gate 	uint_t		nelem = 0;
10650Sstevel@tonic-gate 	int		i = 0;
10660Sstevel@tonic-gate 	int		error = 0;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
10690Sstevel@tonic-gate 	    return (error);
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	if ((error = get_uint64_array(
10730Sstevel@tonic-gate 	    attrs, ATTR_VIRTUAL_SLICES, &old_slices, &nelem)) != 0) {
10740Sstevel@tonic-gate 	    if (error != ENOENT) {
10750Sstevel@tonic-gate 		return (error);
10760Sstevel@tonic-gate 	    }
10770Sstevel@tonic-gate 	    error = 0;
10780Sstevel@tonic-gate 	}
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	/* make a new array */
10810Sstevel@tonic-gate 	new_slices = (uint64_t *)calloc(nelem + 1, sizeof (uint64_t));
10820Sstevel@tonic-gate 	if (new_slices != NULL) {
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	    for (i = 0; i < nelem; i++) {
10850Sstevel@tonic-gate 		new_slices[i] = old_slices[i];
10860Sstevel@tonic-gate 	    }
10870Sstevel@tonic-gate 	    new_slices[i] = slice;
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	    error = set_uint64_array(
10900Sstevel@tonic-gate 		    attrs, ATTR_VIRTUAL_SLICES, new_slices, nelem);
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	    free(new_slices);
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	} else {
10950Sstevel@tonic-gate 	    error = ENOMEM;
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	return (error);
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate /*
11020Sstevel@tonic-gate  * FUNCTION:	disk_has_virtual_slices(dm_descriptor_t disk, boolean_t *bool)
11030Sstevel@tonic-gate  *
11040Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t disk handle
11050Sstevel@tonic-gate  *
11060Sstevel@tonic-gate  * OUTPUT:	bool	- B_TRUE - if the disk has virtual slices
11070Sstevel@tonic-gate  *			  B_FALSE - otherwise
11080Sstevel@tonic-gate  *
11090Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
11100Sstevel@tonic-gate  *			 !0 otherwise
11110Sstevel@tonic-gate  *
11120Sstevel@tonic-gate  * PURPOSE:	Helper which determines if the input disk has virtual slices.
11130Sstevel@tonic-gate  *
11140Sstevel@tonic-gate  *		If a disk has virtual slices, their dm_descriptor_t handles
11150Sstevel@tonic-gate  *		will be stored in the disk's nvpair attribute list.
11160Sstevel@tonic-gate  */
11170Sstevel@tonic-gate static int
disk_has_virtual_slices(dm_descriptor_t disk,boolean_t * bool)11180Sstevel@tonic-gate disk_has_virtual_slices(
11190Sstevel@tonic-gate 	dm_descriptor_t	disk,
11200Sstevel@tonic-gate 	boolean_t	*bool)
11210Sstevel@tonic-gate {
11220Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
11230Sstevel@tonic-gate 	uint64_t	*slices = NULL;
11240Sstevel@tonic-gate 	uint_t		nelem = 0;
11250Sstevel@tonic-gate 	int		error = 0;
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	*bool = B_FALSE;
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
11300Sstevel@tonic-gate 	    return (error);
11310Sstevel@tonic-gate 	}
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	if ((error = get_uint64_array(
11340Sstevel@tonic-gate 	    attrs, ATTR_VIRTUAL_SLICES, &slices, &nelem)) != 0) {
11350Sstevel@tonic-gate 	    if (error == ENOENT) {
11360Sstevel@tonic-gate 		error = 0;
11370Sstevel@tonic-gate 		nelem = 0;
11380Sstevel@tonic-gate 	    } else {
11390Sstevel@tonic-gate 		/* count actual number of elements */
11400Sstevel@tonic-gate 		int i = 0;
11410Sstevel@tonic-gate 		while (i < nelem) {
11420Sstevel@tonic-gate 		    if (slices[i] != -1) {
11430Sstevel@tonic-gate 			++i;
11440Sstevel@tonic-gate 		    }
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 		nelem = i;
11470Sstevel@tonic-gate 	    }
11480Sstevel@tonic-gate 	}
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	*bool = (nelem != 0);
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	return (error);
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate /*
11560Sstevel@tonic-gate  * FUNCTION:	disk_get_virtual_slices(dm_descriptor_t disk, boolean_t *bool)
11570Sstevel@tonic-gate  *
11580Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t disk handle
11590Sstevel@tonic-gate  *
11600Sstevel@tonic-gate  * OUTPUT:	list	- a dlist_t list of dm_descriptor_t handles for the
11610Sstevel@tonic-gate  *				disk's virtual slices.
11620Sstevel@tonic-gate  *
11630Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
11640Sstevel@tonic-gate  *			 !0 otherwise
11650Sstevel@tonic-gate  *
11660Sstevel@tonic-gate  * PURPOSE:	Helper which retrieves a list of the input disk's virtual
11670Sstevel@tonic-gate  *		slices.
11680Sstevel@tonic-gate  *
11690Sstevel@tonic-gate  *		If a disk has virtual slices, their dm_descriptor_t handles
11700Sstevel@tonic-gate  *		will be stored in the disk's nvpair attribute list.
11710Sstevel@tonic-gate  */
11720Sstevel@tonic-gate static int
disk_get_virtual_slices(dm_descriptor_t disk,dlist_t ** list)11730Sstevel@tonic-gate disk_get_virtual_slices(
11740Sstevel@tonic-gate 	dm_descriptor_t	disk,
11750Sstevel@tonic-gate 	dlist_t		**list)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
11780Sstevel@tonic-gate 	uint64_t	*slices = NULL;
11790Sstevel@tonic-gate 	uint_t		nelem = 0;
11800Sstevel@tonic-gate 	int		error = 0;
11810Sstevel@tonic-gate 	int		i = 0;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
11840Sstevel@tonic-gate 	    return (error);
11850Sstevel@tonic-gate 	}
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	if ((error = get_uint64_array(
11880Sstevel@tonic-gate 	    attrs, ATTR_VIRTUAL_SLICES, &slices, &nelem)) != 0) {
11890Sstevel@tonic-gate 	    if (error != ENOENT) {
11900Sstevel@tonic-gate 		return (error);
11910Sstevel@tonic-gate 	    }
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	    return (0);
11940Sstevel@tonic-gate 	}
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	for (i = 0; i < nelem && slices[i] != -1; i++) {
11970Sstevel@tonic-gate 	    dlist_t *item = NULL;
11980Sstevel@tonic-gate 
1199*62Sjeanm 	    if ((item = dlist_new_item((void*)(uintptr_t)slices[i])) == NULL) {
12000Sstevel@tonic-gate 		error = ENOMEM;
12010Sstevel@tonic-gate 		break;
12020Sstevel@tonic-gate 	    }
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	    *list = dlist_append(item, *list, AT_TAIL);
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	return (error);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate /*
12110Sstevel@tonic-gate  * FUNCTION:	is_virtual_slice(dm_descriptor_t desc)
12120Sstevel@tonic-gate  *
12130Sstevel@tonic-gate  * INPUT:	desc	- a dm_descriptor_t handle
12140Sstevel@tonic-gate  *
12150Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the input descriptor is for
12160Sstevel@tonic-gate  *				a virtual slice.
12170Sstevel@tonic-gate  * 			B_FALSE otherwise
12180Sstevel@tonic-gate  *
12190Sstevel@tonic-gate  * PURPOSE:	Helper which determines whether the input descriptor
12200Sstevel@tonic-gate  *		corresponds to a virtual slice.
12210Sstevel@tonic-gate  *
12220Sstevel@tonic-gate  *		All virtual slices are stored in a module private list.
12230Sstevel@tonic-gate  *		This list is iterated to see if it contains the input
12240Sstevel@tonic-gate  *		descriptor.
12250Sstevel@tonic-gate  */
12260Sstevel@tonic-gate boolean_t
is_virtual_slice(dm_descriptor_t desc)12270Sstevel@tonic-gate is_virtual_slice(
12280Sstevel@tonic-gate 	dm_descriptor_t desc)
12290Sstevel@tonic-gate {
12300Sstevel@tonic-gate         return (dlist_contains(_virtual_slices,
1231*62Sjeanm 			(void*)(uintptr_t)desc, compare_descriptors));
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate /*
12350Sstevel@tonic-gate  * FUNCTION:	disk_get_available_slice_index(dm_descriptor_t disk,
12360Sstevel@tonic-gate  *			uint32_t *newindex)
12370Sstevel@tonic-gate  *
12380Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
12390Sstevel@tonic-gate  *
12400Sstevel@tonic-gate  * OUTPUT:	*newindex - a pointer to a uint32_t to hold the available
12410Sstevel@tonic-gate  *			index.  If no index is available, the value pointed
12420Sstevel@tonic-gate  *			to is not modified.
12430Sstevel@tonic-gate  *
12440Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
12450Sstevel@tonic-gate  *			 !0 otherwise.
12460Sstevel@tonic-gate  *
12470Sstevel@tonic-gate  * PURPOSE:	examine the input disk's list of slices and find an unused
12480Sstevel@tonic-gate  *		slice index.  The replica slice (index 7 or 6) is always
12490Sstevel@tonic-gate  *		off-limits -- it shows up as in use.  Slice 0 should only
12500Sstevel@tonic-gate  *		be used as a last resort.
12510Sstevel@tonic-gate  *
12520Sstevel@tonic-gate  *		If an available index is found, it is stored into newindex.
12530Sstevel@tonic-gate  *		Otherwise, newindex is unchanged.  This allows the caller to
12540Sstevel@tonic-gate  *		pass in an index and check if it has been modified on return.
12550Sstevel@tonic-gate  *
12560Sstevel@tonic-gate  *		V_NUMPAR is used as the number of available slices,
12570Sstevel@tonic-gate  *		SPARC systems have V_NUMPAR == 8, X86 have V_NUMPAR == 16.
12580Sstevel@tonic-gate  *
12590Sstevel@tonic-gate  *		EFI disks have only 7.
12600Sstevel@tonic-gate  */
12610Sstevel@tonic-gate int
disk_get_available_slice_index(dm_descriptor_t disk,uint32_t * newindex)12620Sstevel@tonic-gate disk_get_available_slice_index(
12630Sstevel@tonic-gate 	dm_descriptor_t	disk,
12640Sstevel@tonic-gate 	uint32_t	*newindex)
12650Sstevel@tonic-gate {
12660Sstevel@tonic-gate 	dlist_t		*iter	= NULL;
12670Sstevel@tonic-gate 	dlist_t		*slices = NULL;
12680Sstevel@tonic-gate 	uint32_t	index	= 0;
12690Sstevel@tonic-gate 	uint16_t	*reserved = NULL;
12700Sstevel@tonic-gate 	boolean_t 	*used 	= NULL;
12710Sstevel@tonic-gate 	boolean_t 	is_efi	= B_FALSE;
12720Sstevel@tonic-gate 	int		error	= 0;
12730Sstevel@tonic-gate 	int		i	= 0;
12740Sstevel@tonic-gate 	int		nslices = V_NUMPAR;
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	if (((error = disk_get_slices(disk, &slices)) != 0) ||
12770Sstevel@tonic-gate 	    (error = disk_get_is_efi(disk, &is_efi)) != 0) {
12780Sstevel@tonic-gate 	    return (error);
12790Sstevel@tonic-gate 	}
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	if (is_efi == B_TRUE) {
12820Sstevel@tonic-gate 	    /* limit possible indexes to 7 for EFI */
12830Sstevel@tonic-gate 	    nslices = 7;
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	used = (boolean_t *)calloc(nslices, sizeof (boolean_t));
12870Sstevel@tonic-gate 	if (used == NULL) {
12880Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
12890Sstevel@tonic-gate 		    gettext("failed allocating slice index array\n"),
12900Sstevel@tonic-gate 		    NULL);
12910Sstevel@tonic-gate 	    return (ENOMEM);
12920Sstevel@tonic-gate 	}
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	/* eliminate indexes that are reserved */
12950Sstevel@tonic-gate 	if ((error = disk_get_reserved_indexes(disk, &reserved)) != 0) {
12960Sstevel@tonic-gate 	    return (error);
12970Sstevel@tonic-gate 	}
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	if (reserved != NULL) {
13000Sstevel@tonic-gate 	    for (i = 0; i < nslices; i++) {
13010Sstevel@tonic-gate 		if (reserved[i] == 1) {
13020Sstevel@tonic-gate 		    used[i] = B_TRUE;
13030Sstevel@tonic-gate 		}
13040Sstevel@tonic-gate 	    }
13050Sstevel@tonic-gate 	}
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	/* eliminate slices that are in use (have a size > 0) */
13080Sstevel@tonic-gate 	/* 0 sized slices unused slices */
13090Sstevel@tonic-gate 	for (iter = slices; iter != NULL; iter = iter->next) {
13100Sstevel@tonic-gate 	    dm_descriptor_t sp = (uintptr_t)iter->obj;
13110Sstevel@tonic-gate 	    uint64_t	size = 0;
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	    ((error = slice_get_index(sp, &index)) != 0) ||
13140Sstevel@tonic-gate 	    (error = slice_get_size_in_blocks(sp, &size));
13150Sstevel@tonic-gate 	    if (error != 0) {
13160Sstevel@tonic-gate 		return (error);
13170Sstevel@tonic-gate 	    }
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	    if (size > 0) {
13200Sstevel@tonic-gate 		used[(int)index] = B_TRUE;
13210Sstevel@tonic-gate 	    }
13220Sstevel@tonic-gate 	}
13230Sstevel@tonic-gate 	dlist_free_items(slices, NULL);
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 	for (i = 0; i < nslices; i++) {
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	    /* skip the index passed in */
13280Sstevel@tonic-gate 	    if (i == *newindex) {
13290Sstevel@tonic-gate 		continue;
13300Sstevel@tonic-gate 	    }
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	    if (used[i] != B_TRUE) {
13330Sstevel@tonic-gate 		index = i;
13340Sstevel@tonic-gate 		break;
13350Sstevel@tonic-gate 	    }
13360Sstevel@tonic-gate 	}
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 	if (i != nslices) {
13390Sstevel@tonic-gate 	    /* return unused slice index */
13400Sstevel@tonic-gate 	    *newindex = index;
13410Sstevel@tonic-gate 	}
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	free((void *)used);
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	return (0);
13460Sstevel@tonic-gate }
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate /*
13490Sstevel@tonic-gate  * FUNCTION:	disk_get_media_type(dm_descriptor_t slice, uint32_t *type)
13500Sstevel@tonic-gate  *
13510Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for a disk
13520Sstevel@tonic-gate  *
13530Sstevel@tonic-gate  * OUTPUT:	*type	- a pointer to a uint32_t to hold the
13540Sstevel@tonic-gate  *			current type value for the media on which
13550Sstevel@tonic-gate  *			the input slice resides.
13560Sstevel@tonic-gate  *
13570Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
13580Sstevel@tonic-gate  *			 !0 otherwise.
13590Sstevel@tonic-gate  *
13600Sstevel@tonic-gate  * PURPOSE:	Retrieves the media type for the disk.
13610Sstevel@tonic-gate  *
13620Sstevel@tonic-gate  *		Get the media associate with the input disk descriptor
13630Sstevel@tonic-gate  *		and determine its type.
13640Sstevel@tonic-gate  */
13650Sstevel@tonic-gate int
disk_get_media_type(dm_descriptor_t disk,uint32_t * type)13660Sstevel@tonic-gate disk_get_media_type(
13670Sstevel@tonic-gate 	dm_descriptor_t	disk,
13680Sstevel@tonic-gate 	uint32_t	*type)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate 	int		error = 0;
13710Sstevel@tonic-gate 	dm_descriptor_t	*mdp = NULL;
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	mdp = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
13740Sstevel@tonic-gate 	(void) add_descriptors_to_free(mdp);
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	if (error != 0) {
13770Sstevel@tonic-gate 	    print_get_assoc_desc_error(disk, gettext("media"), error);
13780Sstevel@tonic-gate 	} else {
13790Sstevel@tonic-gate 	    /* disk should have exactly 1 media */
13800Sstevel@tonic-gate 	    if ((mdp != NULL) && (*mdp != NULL)) {
13810Sstevel@tonic-gate 		nvlist_t *attrs = dm_get_attributes(*mdp, &error);
13820Sstevel@tonic-gate 		if ((error == 0) && (attrs != NULL)) {
13830Sstevel@tonic-gate 		    error = get_uint32(attrs, DM_MTYPE, type);
13840Sstevel@tonic-gate 		}
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 		nvlist_free(attrs);
13870Sstevel@tonic-gate 	    }
13880Sstevel@tonic-gate 	    /* no media: removeable drive */
13890Sstevel@tonic-gate 	}
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	if (mdp != NULL) {
13920Sstevel@tonic-gate 	    free(mdp);
13930Sstevel@tonic-gate 	}
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	return (error);
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate /*
13990Sstevel@tonic-gate  * FUNCTION:	disk_get_rpm(dm_descriptor_t disk, uint32_t *val)
14000Sstevel@tonic-gate  *		disk_get_sync_speed(dm_descriptor_t disk, uint32_t *val)
14010Sstevel@tonic-gate  *		disk_get_size_in_blocks(dm_descriptor_t disk, uint64_t *val)
14020Sstevel@tonic-gate  *		disk_get_blocksize(dm_descriptor_t disk, uint64_t *val)
14030Sstevel@tonic-gate  *		disk_get_ncylinders(dm_descriptor_t disk, uint64_t *val)
14040Sstevel@tonic-gate  *		disk_get_nheads(dm_descriptor_t disk, uint64_t *val)
14050Sstevel@tonic-gate  *		disk_get_nsectors(dm_descriptor_t disk, uint64_t *val)
14060Sstevel@tonic-gate  *		disk_get_is_efi(dm_descriptor_t disk, boolean_t *val)
14070Sstevel@tonic-gate  *		disk_get_is_online(dm_descriptor_t disk, boolean_t *val)
14080Sstevel@tonic-gate  *		disk_get_media_type(dm_descriptor_t disk, uint32_t *type)
14090Sstevel@tonic-gate  *		disk_get_has_fdisk(dm_descriptor_t disk, boolean_t *val)
14100Sstevel@tonic-gate  *		disk_get_start_block(dm_descriptor_t disk, uint64_t *val)
14110Sstevel@tonic-gate  *
14120Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
14130Sstevel@tonic-gate  *
14140Sstevel@tonic-gate  * OUTPUT:	*bool	- a pointer to a variable of the appropriate
14150Sstevel@tonic-gate  *			type to hold the current value for the attribute
14160Sstevel@tonic-gate  *			of interest.
14170Sstevel@tonic-gate  *
14180Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
14190Sstevel@tonic-gate  *			 !0 otherwise.
14200Sstevel@tonic-gate  *
14210Sstevel@tonic-gate  * PURPOSE:	Wrappers around disk_get_XXX_attribute that know
14220Sstevel@tonic-gate  *	        which attribute needs to be retrieved and also handle
14230Sstevel@tonic-gate  *		any necesasry type or units conversions.
14240Sstevel@tonic-gate  */
14250Sstevel@tonic-gate static int
disk_get_rpm(dm_descriptor_t disk,uint32_t * val)14260Sstevel@tonic-gate disk_get_rpm(
14270Sstevel@tonic-gate 	dm_descriptor_t	disk,
14280Sstevel@tonic-gate 	uint32_t	*val)
14290Sstevel@tonic-gate {
14300Sstevel@tonic-gate 	uint64_t	val64 = 0;
14310Sstevel@tonic-gate 	int		error = 0;
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	if ((error = disk_get_uint64_attribute(
14340Sstevel@tonic-gate 	    disk, DM_RPM, &val64)) != 0) {
14350Sstevel@tonic-gate 	    return (error);
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	*val = (uint32_t)val64;
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 	return (error);
14410Sstevel@tonic-gate }
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate int
disk_get_drive_type(dm_descriptor_t disk,uint32_t * val)14440Sstevel@tonic-gate disk_get_drive_type(
14450Sstevel@tonic-gate 	dm_descriptor_t	disk,
14460Sstevel@tonic-gate 	uint32_t	*val)
14470Sstevel@tonic-gate {
14480Sstevel@tonic-gate 	uint64_t	val64 = 0;
14490Sstevel@tonic-gate 	int		error = 0;
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	if ((error = disk_get_uint64_attribute(
14520Sstevel@tonic-gate 	    disk, DM_DRVTYPE, &val64)) != 0) {
14530Sstevel@tonic-gate 	    return (error);
14540Sstevel@tonic-gate 	}
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	*val = (uint32_t)val64;
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	return (error);
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate static int
disk_get_sync_speed(dm_descriptor_t disk,uint32_t * val)14620Sstevel@tonic-gate disk_get_sync_speed(
14630Sstevel@tonic-gate 	dm_descriptor_t	disk,
14640Sstevel@tonic-gate 	uint32_t	*val)
14650Sstevel@tonic-gate {
14660Sstevel@tonic-gate 	uint64_t	val64 = 0;
14670Sstevel@tonic-gate 	int		error = 0;
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	if ((error = disk_get_uint64_attribute(
14700Sstevel@tonic-gate 	    disk, DM_SYNC_SPEED, &val64)) != 0) {
14710Sstevel@tonic-gate 	    return (error);
14720Sstevel@tonic-gate 	}
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	*val = (uint32_t)val64;
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	return (error);
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate /* returns number of usable blocks */
14800Sstevel@tonic-gate int
disk_get_size_in_blocks(dm_descriptor_t disk,uint64_t * val)14810Sstevel@tonic-gate disk_get_size_in_blocks(
14820Sstevel@tonic-gate 	dm_descriptor_t	disk,
14830Sstevel@tonic-gate 	uint64_t	*val)
14840Sstevel@tonic-gate {
14850Sstevel@tonic-gate 	return (disk_get_uint64_attribute(disk, DM_NACCESSIBLE, val));
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate /* returns first usable block on disk */
14890Sstevel@tonic-gate int
disk_get_start_block(dm_descriptor_t disk,uint64_t * val)14900Sstevel@tonic-gate disk_get_start_block(
14910Sstevel@tonic-gate 	dm_descriptor_t	disk,
14920Sstevel@tonic-gate 	uint64_t	*val)
14930Sstevel@tonic-gate {
14940Sstevel@tonic-gate 	return (disk_get_uint64_attribute(disk, DM_START, val));
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate int
disk_get_blocksize(dm_descriptor_t disk,uint64_t * val)14980Sstevel@tonic-gate disk_get_blocksize(
14990Sstevel@tonic-gate 	dm_descriptor_t	disk,
15000Sstevel@tonic-gate 	uint64_t	*val)
15010Sstevel@tonic-gate {
15020Sstevel@tonic-gate 	return (disk_get_uint64_attribute(disk, DM_BLOCKSIZE, val));
15030Sstevel@tonic-gate }
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate int
disk_get_ncylinders(dm_descriptor_t disk,uint64_t * val)15060Sstevel@tonic-gate disk_get_ncylinders(
15070Sstevel@tonic-gate 	dm_descriptor_t	disk,
15080Sstevel@tonic-gate 	uint64_t	*val)
15090Sstevel@tonic-gate {
15100Sstevel@tonic-gate 	return (disk_get_uint64_attribute(disk, DM_NCYLINDERS, val));
15110Sstevel@tonic-gate }
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate int
disk_get_nheads(dm_descriptor_t disk,uint64_t * val)15140Sstevel@tonic-gate disk_get_nheads(
15150Sstevel@tonic-gate 	dm_descriptor_t	disk,
15160Sstevel@tonic-gate 	uint64_t	*val)
15170Sstevel@tonic-gate {
15180Sstevel@tonic-gate 	return (disk_get_uint64_attribute(disk, DM_NHEADS, val));
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate int
disk_get_nsectors(dm_descriptor_t disk,uint64_t * val)15220Sstevel@tonic-gate disk_get_nsectors(
15230Sstevel@tonic-gate 	dm_descriptor_t	disk,
15240Sstevel@tonic-gate 	uint64_t	*val)
15250Sstevel@tonic-gate {
15260Sstevel@tonic-gate 	return (disk_get_uint64_attribute(disk, DM_NSECTORS, val));
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate /*
15300Sstevel@tonic-gate  * FUNCTION:	disk_get_is_online(dm_descriptor_t disk, boolean_t *val)
15310Sstevel@tonic-gate  *
15320Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
15330Sstevel@tonic-gate  *
15340Sstevel@tonic-gate  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the result.
15350Sstevel@tonic-gate  *
15360Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
15370Sstevel@tonic-gate  *			 !0 otherwise.
15380Sstevel@tonic-gate  *
15390Sstevel@tonic-gate  * PURPOSE:	Determine if the input disk is "online".
15400Sstevel@tonic-gate  *
15410Sstevel@tonic-gate  *		Check the status bit of the drive, if it is 1 the drive
15420Sstevel@tonic-gate  *		is online, if it is 0 the drive is offline.
15430Sstevel@tonic-gate  */
15440Sstevel@tonic-gate int
disk_get_is_online(dm_descriptor_t disk,boolean_t * val)15450Sstevel@tonic-gate disk_get_is_online(
15460Sstevel@tonic-gate 	dm_descriptor_t	disk,
15470Sstevel@tonic-gate 	boolean_t	*val)
15480Sstevel@tonic-gate {
15490Sstevel@tonic-gate 	uint64_t	status = 0;
15500Sstevel@tonic-gate 	int		error = 0;
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	*val = B_FALSE;
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 	error = disk_get_uint64_attribute(disk, DM_STATUS, &status);
15550Sstevel@tonic-gate 	if (error == 0) {
15560Sstevel@tonic-gate 	    *val = (status == 1) ? B_TRUE : B_FALSE;
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	return (error);
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate /*
15630Sstevel@tonic-gate  * FUNCTION:	disk_get_is_efi(dm_descriptor_t disk, boolean_t *bool)
15640Sstevel@tonic-gate  *
15650Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
15660Sstevel@tonic-gate  *
15670Sstevel@tonic-gate  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the result.
15680Sstevel@tonic-gate  *
15690Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
15700Sstevel@tonic-gate  *			 !0 otherwise.
15710Sstevel@tonic-gate  *
15720Sstevel@tonic-gate  * PURPOSE:	Determine if the input disk is labeled with an EFI label.
15730Sstevel@tonic-gate  *
15740Sstevel@tonic-gate  *		The label type is actually a property of the media
15750Sstevel@tonic-gate  *		associated with the disk, so retrieve the media and
15760Sstevel@tonic-gate  *		check if it is EFI labeled.
15770Sstevel@tonic-gate  */
15780Sstevel@tonic-gate int
disk_get_is_efi(dm_descriptor_t disk,boolean_t * bool)15790Sstevel@tonic-gate disk_get_is_efi(
15800Sstevel@tonic-gate 	dm_descriptor_t	disk,
15810Sstevel@tonic-gate 	boolean_t	*bool)
15820Sstevel@tonic-gate {
15830Sstevel@tonic-gate 	return (disk_get_boolean_attribute(disk, DM_EFI, bool));
15840Sstevel@tonic-gate }
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate /*
15870Sstevel@tonic-gate  * FUNCTION:	disk_get_has_fdisk(dm_descriptor_t disk, boolean_t *bool)
15880Sstevel@tonic-gate  *
15890Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
15900Sstevel@tonic-gate  *
15910Sstevel@tonic-gate  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the result.
15920Sstevel@tonic-gate  *
15930Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
15940Sstevel@tonic-gate  *			 !0 otherwise.
15950Sstevel@tonic-gate  *
15960Sstevel@tonic-gate  * PURPOSE:	Determine if the input disk has an FDISK partition.
15970Sstevel@tonic-gate  */
15980Sstevel@tonic-gate int
disk_get_has_fdisk(dm_descriptor_t disk,boolean_t * bool)15990Sstevel@tonic-gate disk_get_has_fdisk(
16000Sstevel@tonic-gate 	dm_descriptor_t	disk,
16010Sstevel@tonic-gate 	boolean_t	*bool)
16020Sstevel@tonic-gate {
16030Sstevel@tonic-gate 	return (disk_get_boolean_attribute(disk, DM_FDISK, bool));
16040Sstevel@tonic-gate }
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate /*
16070Sstevel@tonic-gate  * FUNCTION:	disk_get_has_solaris_partition(dm_descriptor_t disk, boolean_t *bool)
16080Sstevel@tonic-gate  *
16090Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
16100Sstevel@tonic-gate  *
16110Sstevel@tonic-gate  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the result.
16120Sstevel@tonic-gate  *
16130Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
16140Sstevel@tonic-gate  *			 !0 otherwise.
16150Sstevel@tonic-gate  *
16160Sstevel@tonic-gate  * PURPOSE:	Determine if the input disk has a Solaris FDISK partition.
16170Sstevel@tonic-gate  */
16180Sstevel@tonic-gate int
disk_get_has_solaris_partition(dm_descriptor_t disk,boolean_t * bool)16190Sstevel@tonic-gate disk_get_has_solaris_partition(
16200Sstevel@tonic-gate 	dm_descriptor_t	disk,
16210Sstevel@tonic-gate 	boolean_t	*bool)
16220Sstevel@tonic-gate {
16230Sstevel@tonic-gate 	boolean_t	has_fdisk = B_FALSE;
16240Sstevel@tonic-gate 	int		error = 0;
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	if ((error = disk_get_has_fdisk(disk, &has_fdisk)) != 0) {
16270Sstevel@tonic-gate 	    return (error);
16280Sstevel@tonic-gate 	}
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 	*bool = B_FALSE;
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	if (has_fdisk == B_TRUE) {
16330Sstevel@tonic-gate 	    /* get disk's media */
16340Sstevel@tonic-gate 	    dm_descriptor_t *media;
16350Sstevel@tonic-gate 	    media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
16360Sstevel@tonic-gate 	    (void) add_descriptors_to_free(media);
16370Sstevel@tonic-gate 	    if (error != 0) {
16380Sstevel@tonic-gate 		print_get_assoc_desc_error(disk, gettext("media"), error);
16390Sstevel@tonic-gate 	    } else if ((media != NULL) && (*media != NULL)) {
16400Sstevel@tonic-gate 		/* get media's partitions */
16410Sstevel@tonic-gate 		dm_descriptor_t *parts;
16420Sstevel@tonic-gate 		parts = dm_get_associated_descriptors(
16430Sstevel@tonic-gate 			media[0], DM_PARTITION, &error);
16440Sstevel@tonic-gate 		(void) add_descriptors_to_free(parts);
16450Sstevel@tonic-gate 		if (error != 0) {
16460Sstevel@tonic-gate 		    print_get_assoc_desc_error(media[0],
16470Sstevel@tonic-gate 			    gettext("partitions"), error);
16480Sstevel@tonic-gate 		} else {
16490Sstevel@tonic-gate 		    /* search partitions for one with type Solaris */
16500Sstevel@tonic-gate 		    int i = 0;
16510Sstevel@tonic-gate 		    for (; (parts != NULL) && (parts[i] != NULL) &&
16520Sstevel@tonic-gate 			(error == 0) && (*bool == B_FALSE); i++) {
16530Sstevel@tonic-gate 			nvlist_t *attrs = dm_get_attributes(parts[i], &error);
16540Sstevel@tonic-gate 			uint32_t ptype = 0;
16550Sstevel@tonic-gate 			if ((error == 0) && (attrs != NULL)) {
16560Sstevel@tonic-gate 			    error = get_uint32(attrs, DM_PTYPE, &ptype);
16570Sstevel@tonic-gate 			    if ((error == 0) &&
16580Sstevel@tonic-gate 			        (ptype == SUNIXOS || ptype == SUNIXOS2)) {
16590Sstevel@tonic-gate 				    *bool = B_TRUE;
16600Sstevel@tonic-gate 			    }
16610Sstevel@tonic-gate 			}
16620Sstevel@tonic-gate 			nvlist_free(attrs);
16630Sstevel@tonic-gate 		    }
16640Sstevel@tonic-gate 		}
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 		free(parts);
16670Sstevel@tonic-gate 		free(media);
16680Sstevel@tonic-gate 	    }
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 	    /* if there was no media, it was a removeable drive */
16710Sstevel@tonic-gate 	}
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	return (error);
16740Sstevel@tonic-gate }
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate static int
disk_get_boolean_attribute(dm_descriptor_t disk,char * attr,boolean_t * bool)16770Sstevel@tonic-gate disk_get_boolean_attribute(
16780Sstevel@tonic-gate 	dm_descriptor_t	disk,
16790Sstevel@tonic-gate 	char		*attr,
16800Sstevel@tonic-gate 	boolean_t	*bool)
16810Sstevel@tonic-gate {
16820Sstevel@tonic-gate 	nvlist_t	*attrs	= NULL;
16830Sstevel@tonic-gate 	int		error	= 0;
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 	*bool = B_FALSE;
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 	if ((strcmp(attr, DM_EFI) == 0) ||
16880Sstevel@tonic-gate 	    (strcmp(attr, DM_FDISK) == 0)) {
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	    /*
16910Sstevel@tonic-gate 	     * these attributes are actually on the media,
16920Sstevel@tonic-gate 	     * not the disk... so get the media descriptor
16930Sstevel@tonic-gate 	     * for this disk
16940Sstevel@tonic-gate 	     */
16950Sstevel@tonic-gate 	    dm_descriptor_t *media;
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	    media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
16980Sstevel@tonic-gate 	    (void) add_descriptors_to_free(media);
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	    if (error != 0) {
17010Sstevel@tonic-gate 		print_get_assoc_desc_error(disk, gettext("media"), error);
17020Sstevel@tonic-gate 	    } else if ((media != NULL) && (*media != NULL)) {
17030Sstevel@tonic-gate 		/* if there's no media, it is a removeable drive */
17040Sstevel@tonic-gate 		error = get_cached_attributes(media[0], &attrs);
17050Sstevel@tonic-gate 	    }
17060Sstevel@tonic-gate 	    free(media);
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	} else {
17090Sstevel@tonic-gate 	    error = get_cached_attributes(disk, &attrs);
17100Sstevel@tonic-gate 	    if (error != 0) {
17110Sstevel@tonic-gate 		print_get_desc_attr_error(disk, gettext("drive"), attr, error);
17120Sstevel@tonic-gate 	    }
17130Sstevel@tonic-gate 	}
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	if (error != 0) {
17160Sstevel@tonic-gate 	    return (error);
17170Sstevel@tonic-gate 	}
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	if (nvlist_lookup_boolean(attrs, attr) == 0) {
17200Sstevel@tonic-gate 	    *bool = B_TRUE;
17210Sstevel@tonic-gate 	}
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	return (error);
17240Sstevel@tonic-gate }
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate static int
disk_get_uint64_attribute(dm_descriptor_t disk,char * attr,uint64_t * val)17270Sstevel@tonic-gate disk_get_uint64_attribute(
17280Sstevel@tonic-gate 	dm_descriptor_t	disk,
17290Sstevel@tonic-gate 	char		*attr,
17300Sstevel@tonic-gate 	uint64_t	*val)
17310Sstevel@tonic-gate {
17320Sstevel@tonic-gate 	nvlist_t	*attrs	= NULL;
17330Sstevel@tonic-gate 	uint32_t	ui32	= 0;
17340Sstevel@tonic-gate 	int		error	= 0;
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 	/*
17370Sstevel@tonic-gate 	 * these attributes are actually on the media,
17380Sstevel@tonic-gate 	 * not the disk... so get the media descriptor
17390Sstevel@tonic-gate 	 * for this disk
17400Sstevel@tonic-gate 	 */
17410Sstevel@tonic-gate 	if ((strcmp(attr, DM_SIZE) == 0) ||
17420Sstevel@tonic-gate 	    (strcmp(attr, DM_START) == 0) ||
17430Sstevel@tonic-gate 	    (strcmp(attr, DM_NACCESSIBLE) == 0) ||
17440Sstevel@tonic-gate 	    (strcmp(attr, DM_BLOCKSIZE) == 0) ||
17450Sstevel@tonic-gate 	    (strcmp(attr, DM_NCYLINDERS) == 0) ||
17460Sstevel@tonic-gate 	    (strcmp(attr, DM_NHEADS) == 0) ||
17470Sstevel@tonic-gate 	    (strcmp(attr, DM_NSECTORS) == 0)) {
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	    dm_descriptor_t *media;
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 	    media = dm_get_associated_descriptors(disk, DM_MEDIA, &error);
17520Sstevel@tonic-gate 	    (void) add_descriptors_to_free(media);
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 	    if (error != 0) {
17550Sstevel@tonic-gate 		print_get_assoc_desc_error(disk, gettext("media"), error);
17560Sstevel@tonic-gate 	    } else if ((media == NULL) || (*media == NULL)) {
17570Sstevel@tonic-gate 		print_get_assoc_desc_error(disk, gettext("media"), error);
17580Sstevel@tonic-gate 		error = -1;
17590Sstevel@tonic-gate 	    } else {
17600Sstevel@tonic-gate 		error = get_cached_attributes(media[0], &attrs);
17610Sstevel@tonic-gate 		free(media);
17620Sstevel@tonic-gate 	    }
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 	} else {
17650Sstevel@tonic-gate 	    error = get_cached_attributes(disk, &attrs);
17660Sstevel@tonic-gate 	    if (error != 0) {
17670Sstevel@tonic-gate 		print_get_desc_attr_error(disk, gettext("drive"), attr, error);
17680Sstevel@tonic-gate 	    }
17690Sstevel@tonic-gate 	}
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	if (error != 0) {
17720Sstevel@tonic-gate 	    return (error);
17730Sstevel@tonic-gate 	}
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	if (strcmp(attr, DM_SIZE) == 0 ||
17760Sstevel@tonic-gate 	    strcmp(attr, DM_NACCESSIBLE) == 0 ||
17770Sstevel@tonic-gate 	    strcmp(attr, DM_START) == 0) {
17780Sstevel@tonic-gate 	    error = get_uint64(attrs, attr, val);
17790Sstevel@tonic-gate 	} else if (strcmp(attr, DM_BLOCKSIZE) == 0 ||
17800Sstevel@tonic-gate 	    strcmp(attr, DM_NCYLINDERS) == 0 ||
17810Sstevel@tonic-gate 	    strcmp(attr, DM_NHEADS) == 0 ||
17820Sstevel@tonic-gate 	    strcmp(attr, DM_NSECTORS) == 0 ||
17830Sstevel@tonic-gate 	    strcmp(attr, DM_RPM) == 0 ||
17840Sstevel@tonic-gate 	    strcmp(attr, DM_DRVTYPE) == 0 ||
17850Sstevel@tonic-gate 	    strcmp(attr, DM_SYNC_SPEED) == 0 ||
17860Sstevel@tonic-gate 	    strcmp(attr, DM_STATUS) == 0) {
17870Sstevel@tonic-gate 	    error = get_uint32(attrs, attr, &ui32);
17880Sstevel@tonic-gate 	    *val = (uint64_t)ui32;
17890Sstevel@tonic-gate 	}
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	return (error);
17920Sstevel@tonic-gate }
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate /*
17950Sstevel@tonic-gate  * FUNCTION:	group_similar_hbas(dlist_t *hbas, dlist_t **list)
17960Sstevel@tonic-gate  *
17970Sstevel@tonic-gate  * INPUT:	hbas	- a list of HBA dm_descriptor_t handles.
17980Sstevel@tonic-gate  *
17990Sstevel@tonic-gate  * OUTPUT:	**list	- a pointer to a list to hold the lists of HBAs
18000Sstevel@tonic-gate  *			grouped by characteristics.
18010Sstevel@tonic-gate  *
18020Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
18030Sstevel@tonic-gate  *			 !0 otherwise.
18040Sstevel@tonic-gate  *
18050Sstevel@tonic-gate  * PURPOSE:	Examine the input HBAs and collate them into separate
18060Sstevel@tonic-gate  *		lists, grouped by their type and the protocols they
18070Sstevel@tonic-gate  *		support.
18080Sstevel@tonic-gate  *
18090Sstevel@tonic-gate  *		The returned list of list is arranged in decreasing order
18100Sstevel@tonic-gate  *		of preference, "better" HBAs come first.
18110Sstevel@tonic-gate  *
18120Sstevel@tonic-gate  *		find all MPXIO controllers
18130Sstevel@tonic-gate  *		find all similar FC HBAs
18140Sstevel@tonic-gate  *		find all similar SCSI HBAs
18150Sstevel@tonic-gate  *		    fast{wide}80
18160Sstevel@tonic-gate  *		    fast{wide}40
18170Sstevel@tonic-gate  *		    fast{wide}20
18180Sstevel@tonic-gate  *		    clock         uint32  ??
18190Sstevel@tonic-gate  *		find all similar ATA/IDE HBAs
18200Sstevel@tonic-gate  *		find all similar USB HBAs
18210Sstevel@tonic-gate  */
18220Sstevel@tonic-gate int
group_similar_hbas(dlist_t * hbas,dlist_t ** list)18230Sstevel@tonic-gate group_similar_hbas(
18240Sstevel@tonic-gate 	dlist_t	*hbas,
18250Sstevel@tonic-gate 	dlist_t **list)
18260Sstevel@tonic-gate {
18270Sstevel@tonic-gate 	/* preference order of HBAs */
18280Sstevel@tonic-gate 	enum {
18290Sstevel@tonic-gate 		HBA_FIBRE_MPXIO = 0,
18300Sstevel@tonic-gate 		HBA_SCSI_MPXIO,
18310Sstevel@tonic-gate 		HBA_FIBRE,
18320Sstevel@tonic-gate 		HBA_SCSI_FW80,
18330Sstevel@tonic-gate 		HBA_SCSI_FW40,
18340Sstevel@tonic-gate 		HBA_SCSI_FW20,
18350Sstevel@tonic-gate 		HBA_SCSI_F80,
18360Sstevel@tonic-gate 		HBA_SCSI_F40,
18370Sstevel@tonic-gate 		HBA_SCSI_F20,
18380Sstevel@tonic-gate 		HBA_SCSI,
18390Sstevel@tonic-gate 		HBA_ATA,
18400Sstevel@tonic-gate 		HBA_USB,
18410Sstevel@tonic-gate 		HBA_LAST
18420Sstevel@tonic-gate 	};
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 	dlist_t		*groups	= NULL;
18450Sstevel@tonic-gate 	dlist_t		*iter = NULL;
18460Sstevel@tonic-gate 	dlist_t		*item = NULL;
18470Sstevel@tonic-gate 	dlist_t		*lists[HBA_LAST];
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	int		error = 0;
18500Sstevel@tonic-gate 	int		i = 0;
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	(void) memset(lists, '\0', HBA_LAST * sizeof (dlist_t *));
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 	for (iter = hbas;
18550Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
18560Sstevel@tonic-gate 	    iter = iter->next) {
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
18590Sstevel@tonic-gate 	    char	*type = NULL;
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	    /* if item doesn't go into a list it must be freed */
1862*62Sjeanm 	    if ((item = dlist_new_item((void *)(uintptr_t)hba)) == NULL) {
18630Sstevel@tonic-gate 		error = ENOMEM;
18640Sstevel@tonic-gate 		continue;
18650Sstevel@tonic-gate 	    }
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate 	    if ((error = hba_get_type(hba, &type)) != 0) {
18680Sstevel@tonic-gate 		free(item);
18690Sstevel@tonic-gate 		continue;
18700Sstevel@tonic-gate 	    }
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	    if (strcmp(type, DM_CTYPE_FIBRE) == 0) {
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 		boolean_t	ismpxio = B_FALSE;
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 		if ((error = hba_is_multiplex(hba, &ismpxio)) == 0) {
18770Sstevel@tonic-gate 		    if (ismpxio) {
18780Sstevel@tonic-gate 			lists[HBA_FIBRE_MPXIO] =
18790Sstevel@tonic-gate 			    dlist_append(item,
18800Sstevel@tonic-gate 				    lists[HBA_FIBRE_MPXIO], AT_TAIL);
18810Sstevel@tonic-gate 		    } else {
18820Sstevel@tonic-gate 			lists[HBA_FIBRE] =
18830Sstevel@tonic-gate 			    dlist_append(item,
18840Sstevel@tonic-gate 				    lists[HBA_FIBRE], AT_TAIL);
18850Sstevel@tonic-gate 		    }
18860Sstevel@tonic-gate 		} else {
18870Sstevel@tonic-gate 		    free(item);
18880Sstevel@tonic-gate 		}
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 	    } else if (strcmp(type, DM_CTYPE_SCSI) == 0) {
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 		/* determine subtype */
18930Sstevel@tonic-gate 		boolean_t	iswide = B_FALSE;
18940Sstevel@tonic-gate 		boolean_t	ismpxio = B_FALSE;
18950Sstevel@tonic-gate 		boolean_t	is80 = B_FALSE;
18960Sstevel@tonic-gate 		boolean_t	is40 = B_FALSE;
18970Sstevel@tonic-gate 		boolean_t	is20 = B_FALSE;
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 		((error = hba_supports_wide(hba, &iswide)) != 0) ||
19000Sstevel@tonic-gate 		(error = hba_is_multiplex(hba, &ismpxio)) ||
19010Sstevel@tonic-gate 		(error = hba_is_fast_80(hba, &is80)) ||
19020Sstevel@tonic-gate 		(error = hba_is_fast_40(hba, &is40)) ||
19030Sstevel@tonic-gate 		(error = hba_is_fast_20(hba, &is20));
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 		if (error == 0) {
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 		    if (ismpxio) {
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 			lists[HBA_SCSI_MPXIO] =
19100Sstevel@tonic-gate 			    dlist_append(item,
19110Sstevel@tonic-gate 				    lists[HBA_SCSI_MPXIO], AT_TAIL);
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 		    } else if (is80) {
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 			if (iswide) {
19160Sstevel@tonic-gate 			    lists[HBA_SCSI_FW80] =
19170Sstevel@tonic-gate 				dlist_append(item,
19180Sstevel@tonic-gate 					lists[HBA_SCSI_FW80], AT_TAIL);
19190Sstevel@tonic-gate 			} else {
19200Sstevel@tonic-gate 			    lists[HBA_SCSI_F80] =
19210Sstevel@tonic-gate 				dlist_append(item,
19220Sstevel@tonic-gate 					lists[HBA_SCSI_F80], AT_TAIL);
19230Sstevel@tonic-gate 			}
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 		    } else if (is40) {
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 			if (iswide) {
19280Sstevel@tonic-gate 			    lists[HBA_SCSI_FW40] =
19290Sstevel@tonic-gate 				dlist_append(item,
19300Sstevel@tonic-gate 					lists[HBA_SCSI_FW40], AT_TAIL);
19310Sstevel@tonic-gate 			} else {
19320Sstevel@tonic-gate 			    lists[HBA_SCSI_F40] =
19330Sstevel@tonic-gate 				dlist_append(item,
19340Sstevel@tonic-gate 					lists[HBA_SCSI_F40], AT_TAIL);
19350Sstevel@tonic-gate 			}
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 		    } else if (is20) {
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 			if (iswide) {
19400Sstevel@tonic-gate 			    lists[HBA_SCSI_FW20] =
19410Sstevel@tonic-gate 				dlist_append(item,
19420Sstevel@tonic-gate 					lists[HBA_SCSI_FW20], AT_TAIL);
19430Sstevel@tonic-gate 			} else {
19440Sstevel@tonic-gate 			    lists[HBA_SCSI_F20] =
19450Sstevel@tonic-gate 				dlist_append(item,
19460Sstevel@tonic-gate 					lists[HBA_SCSI_F20], AT_TAIL);
19470Sstevel@tonic-gate 			}
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 		    } else {
19500Sstevel@tonic-gate 			lists[HBA_SCSI] =
19510Sstevel@tonic-gate 			    dlist_append(item, lists[HBA_SCSI], AT_TAIL);
19520Sstevel@tonic-gate 		    }
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 		} else {
19550Sstevel@tonic-gate 		    free(item);
19560Sstevel@tonic-gate 		}
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 	    } else if (strcmp(type, DM_CTYPE_ATA) == 0) {
19590Sstevel@tonic-gate 		lists[HBA_ATA] =
19600Sstevel@tonic-gate 		    dlist_append(item, lists[HBA_ATA], AT_TAIL);
19610Sstevel@tonic-gate 	    } else if (strcmp(type, DM_CTYPE_USB) == 0) {
19620Sstevel@tonic-gate 		lists[HBA_USB] =
19630Sstevel@tonic-gate 		    dlist_append(item, lists[HBA_USB], AT_TAIL);
19640Sstevel@tonic-gate 	    } else if (strcmp(type, DM_CTYPE_UNKNOWN) == 0) {
19650Sstevel@tonic-gate 		oprintf(OUTPUT_DEBUG,
19660Sstevel@tonic-gate 			gettext("found an HBA with unknown type\n"));
19670Sstevel@tonic-gate 		free(item);
19680Sstevel@tonic-gate 	    }
19690Sstevel@tonic-gate 	}
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	if (error == 0) {
19720Sstevel@tonic-gate 	    /* collect individual lists into a list of lists */
19730Sstevel@tonic-gate 	    for (i = 0; (i < HBA_LAST) && (error == 0); i++) {
19740Sstevel@tonic-gate 		if (lists[i] != NULL) {
19750Sstevel@tonic-gate 		    if ((item = dlist_new_item(lists[i])) == NULL) {
19760Sstevel@tonic-gate 			error = ENOMEM;
19770Sstevel@tonic-gate 		    } else {
19780Sstevel@tonic-gate 			groups = dlist_append(item, groups, AT_TAIL);
19790Sstevel@tonic-gate 		    }
19800Sstevel@tonic-gate 		}
19810Sstevel@tonic-gate 	    }
19820Sstevel@tonic-gate 	}
19830Sstevel@tonic-gate 
19840Sstevel@tonic-gate 	if (error != 0) {
19850Sstevel@tonic-gate 	    for (i = 0; i < HBA_LAST; i++) {
19860Sstevel@tonic-gate 		dlist_free_items(lists[i], NULL);
19870Sstevel@tonic-gate 		lists[i] = NULL;
19880Sstevel@tonic-gate 	    }
19890Sstevel@tonic-gate 
19900Sstevel@tonic-gate 	    if (groups != NULL) {
19910Sstevel@tonic-gate 		dlist_free_items(groups, NULL);
19920Sstevel@tonic-gate 	    }
19930Sstevel@tonic-gate 	}
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 	*list = groups;
19960Sstevel@tonic-gate 
19970Sstevel@tonic-gate 	return (error);
19980Sstevel@tonic-gate }
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate /*
20010Sstevel@tonic-gate  * FUNCTION:	hba_group_usable_disks(dm_descriptor_t hba, dlist_t **list)
20020Sstevel@tonic-gate  *
20030Sstevel@tonic-gate  * INPUT:	hba	- a dm_descriptor_t handle for a slice
20040Sstevel@tonic-gate  *
20050Sstevel@tonic-gate  * OUTPUT:	**list	- a pointer to a list to hold the lists of disks
20060Sstevel@tonic-gate  *			grouped by characteristics.
20070Sstevel@tonic-gate  *
20080Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
20090Sstevel@tonic-gate  *			 !0 otherwise.
20100Sstevel@tonic-gate  *
20110Sstevel@tonic-gate  * PURPOSE:	Examine the disks assocated with the HBA and collates them
20120Sstevel@tonic-gate  *		into separate lists, grouped by similar characteristics.
20130Sstevel@tonic-gate  *
20140Sstevel@tonic-gate  *		get disks on HBA
20150Sstevel@tonic-gate  *		check disks against _usable_disks list
20160Sstevel@tonic-gate  *		group disks by similarities:
20170Sstevel@tonic-gate  *			sync-speed    uint32
20180Sstevel@tonic-gate  *			wide          boolean
20190Sstevel@tonic-gate  *			rpm           uint32
20200Sstevel@tonic-gate  *
20210Sstevel@tonic-gate  *		XXX this function is currently unused.  At some point,
20220Sstevel@tonic-gate  *		it may be useful to group disks by performance
20230Sstevel@tonic-gate  *		characteristics and use "better" disks before others.
20240Sstevel@tonic-gate  */
20250Sstevel@tonic-gate int
hba_group_usable_disks(dm_descriptor_t hba,dlist_t ** list)20260Sstevel@tonic-gate hba_group_usable_disks(
20270Sstevel@tonic-gate 	dm_descriptor_t	hba,
20280Sstevel@tonic-gate 	dlist_t		**list)
20290Sstevel@tonic-gate {
20300Sstevel@tonic-gate 	dm_descriptor_t *disk = NULL;
20310Sstevel@tonic-gate 	char 		*name = NULL;
20320Sstevel@tonic-gate 	int		i = 0;
20330Sstevel@tonic-gate 	int		error = 0;
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	disk = dm_get_associated_descriptors(hba, DM_DRIVE, &error);
20360Sstevel@tonic-gate 	(void) add_descriptors_to_free(disk);
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 	if (error != 0) {
20390Sstevel@tonic-gate 	    print_get_assoc_desc_error(hba, gettext("drive"), error);
20400Sstevel@tonic-gate 	    return (error);
20410Sstevel@tonic-gate 	} else if ((disk == NULL) || (*disk == NULL)) {
20420Sstevel@tonic-gate 	    print_get_assoc_desc_error(hba, gettext("drive"), error);
20430Sstevel@tonic-gate 	    error = -1;
20440Sstevel@tonic-gate 	}
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	for (i = 0; (disk[i] != NULL) && (error == 0); i++) {
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 	    uint32_t dtype = DM_DT_UNKNOWN;
20490Sstevel@tonic-gate 	    dlist_t *usable = NULL;
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 	    /* ignore non fixed media drives */
20520Sstevel@tonic-gate 	    if (((error = disk_get_drive_type(disk[i], &dtype)) != 0) ||
20530Sstevel@tonic-gate 		(dtype != DM_DT_FIXED)) {
20540Sstevel@tonic-gate 		continue;
20550Sstevel@tonic-gate 	    }
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	    if (dlist_contains(usable, &disk[i],
20580Sstevel@tonic-gate 		compare_descriptor_names) == B_TRUE) {
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 		uint64_t bsize	= 0;
20610Sstevel@tonic-gate 		uint64_t ncyls	= 0;
20620Sstevel@tonic-gate 		uint64_t nsects	= 0;
20630Sstevel@tonic-gate 		uint64_t nheads	= 0;
20640Sstevel@tonic-gate 		uint32_t rpm	= 0;
20650Sstevel@tonic-gate 		uint32_t sync	= 0;
20660Sstevel@tonic-gate 
20670Sstevel@tonic-gate 		name = NULL;
20680Sstevel@tonic-gate 		((error = get_display_name(disk[i], &name)) != 0) ||
20690Sstevel@tonic-gate 		(error = disk_get_blocksize(disk[i], &bsize)) ||
20700Sstevel@tonic-gate 		(error = disk_get_nheads(disk[i], &nheads)) ||
20710Sstevel@tonic-gate 		(error = disk_get_nsectors(disk[i], &nsects)) ||
20720Sstevel@tonic-gate 		(error = disk_get_ncylinders(disk[i], &ncyls)) ||
20730Sstevel@tonic-gate 		(error = disk_get_rpm(disk[i], &rpm)) ||
20740Sstevel@tonic-gate 		(error = disk_get_sync_speed(disk[i], &sync));
20750Sstevel@tonic-gate 		if (error != 0) {
20760Sstevel@tonic-gate 		    continue;
20770Sstevel@tonic-gate 		}
20780Sstevel@tonic-gate 
20790Sstevel@tonic-gate 		oprintf(OUTPUT_VERBOSE,
20800Sstevel@tonic-gate 			gettext("found an available disk: %s\n\t"
20810Sstevel@tonic-gate 			"sync_speed = %u, rpm = %u, "
20820Sstevel@tonic-gate 			"nsect = %llu, blksiz = %llu\n"),
20830Sstevel@tonic-gate 			name, sync, rpm, nsects, bsize);
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 		/* add to the appropriate list */
20860Sstevel@tonic-gate 	    }
20870Sstevel@tonic-gate 	}
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 	if (disk != NULL) {
20900Sstevel@tonic-gate 	    free(disk);
20910Sstevel@tonic-gate 	}
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 	return (error);
20940Sstevel@tonic-gate }
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate /*
20970Sstevel@tonic-gate  * FUNCTION:	hba_get_n_avail_disks(dm_descriptor_t hba, uint16_t *val)
20980Sstevel@tonic-gate  *		hba_set_n_avail_disks(dm_descriptor_t hba, uint16_t val)
20990Sstevel@tonic-gate  *
21000Sstevel@tonic-gate  * INPUT:	hba	- a dm_descriptor_t handle for a slice
21010Sstevel@tonic-gate  *
21020Sstevel@tonic-gate  * OUTPUT:	*val	- a pointer to a uint16_t to hold the current number
21030Sstevel@tonic-gate  *				of available disks for the input HBA.
21040Sstevel@tonic-gate  *
21050Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
21060Sstevel@tonic-gate  *			 !0 otherwise.
21070Sstevel@tonic-gate  */
21080Sstevel@tonic-gate int
hba_set_n_avail_disks(dm_descriptor_t hba,uint16_t val)21090Sstevel@tonic-gate hba_set_n_avail_disks(
21100Sstevel@tonic-gate 	dm_descriptor_t	hba,
21110Sstevel@tonic-gate 	uint16_t	val)
21120Sstevel@tonic-gate {
21130Sstevel@tonic-gate 	nvlist_t	*attrs;
21140Sstevel@tonic-gate 	int		error = 0;
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate 	((error = get_cached_attributes(hba, &attrs)) != 0) ||
21170Sstevel@tonic-gate 	(error = set_uint16(attrs, ATTR_HBA_N_DISKS, val));
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 	return (error);
21200Sstevel@tonic-gate }
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate int
hba_get_n_avail_disks(dm_descriptor_t hba,uint16_t * val)21230Sstevel@tonic-gate hba_get_n_avail_disks(
21240Sstevel@tonic-gate 	dm_descriptor_t	hba,
21250Sstevel@tonic-gate 	uint16_t	*val)
21260Sstevel@tonic-gate {
21270Sstevel@tonic-gate 	nvlist_t	*attrs;
21280Sstevel@tonic-gate 	int		error = 0;
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	*val = 0;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 	((error = get_cached_attributes(hba, &attrs)) != 0) ||
21330Sstevel@tonic-gate 	(error = get_uint16(attrs, ATTR_HBA_N_DISKS, val));
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 	return (error);
21360Sstevel@tonic-gate }
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate /*
21390Sstevel@tonic-gate  * FUNCTION:	hba_get_type(dm_descriptor_t hba, char **type)
21400Sstevel@tonic-gate  *
21410Sstevel@tonic-gate  * INPUT:	hba	- a dm_descriptor_t handle for a HBA
21420Sstevel@tonic-gate  *
21430Sstevel@tonic-gate  * OUTPUT:	**type	- a char * to hold the current type value for
21440Sstevel@tonic-gate  *			the HBA.
21450Sstevel@tonic-gate  *
21460Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
21470Sstevel@tonic-gate  *			 !0 otherwise.
21480Sstevel@tonic-gate  *
21490Sstevel@tonic-gate  * PURPOSE:	Retrieves the type attribute for the HBA.
21500Sstevel@tonic-gate  */
21510Sstevel@tonic-gate int
hba_get_type(dm_descriptor_t hba,char ** type)21520Sstevel@tonic-gate hba_get_type(
21530Sstevel@tonic-gate 	dm_descriptor_t	hba,
21540Sstevel@tonic-gate 	char		**type)
21550Sstevel@tonic-gate {
21560Sstevel@tonic-gate 	nvlist_t	*attrs;
21570Sstevel@tonic-gate 	int		error = 0;
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 	*type = NULL;
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	((error = get_cached_attributes(hba, &attrs)) != 0) ||
21620Sstevel@tonic-gate 	(error = get_string(attrs, DM_CTYPE, type));
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate 	return (error);
21650Sstevel@tonic-gate }
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate /*
21680Sstevel@tonic-gate  * FUNCTION:	hba_is_fast(dm_descriptor_t hba, boolean_t *bool)
21690Sstevel@tonic-gate  *		hba_is_fast20(dm_descriptor_t hba, boolean_t *bool)
21700Sstevel@tonic-gate  *		hba_is_fast40(dm_descriptor_t hba, boolean_t *bool)
21710Sstevel@tonic-gate  *		hba_is_fast80(dm_descriptor_t hba, boolean_t *bool)
21720Sstevel@tonic-gate  *		hba_is_multiplex(dm_descriptor_t hba, boolean_t *bool)
21730Sstevel@tonic-gate  *		hba_is_wide(dm_descriptor_t hba, boolean_t *bool)
21740Sstevel@tonic-gate  *
21750Sstevel@tonic-gate  * INPUT:	hba	- a dm_descriptor_t handle for a HBA
21760Sstevel@tonic-gate  *
21770Sstevel@tonic-gate  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the
21780Sstevel@tonic-gate  *			boolean value of the predicate.
21790Sstevel@tonic-gate  *
21800Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
21810Sstevel@tonic-gate  *			 !0 otherwise.
21820Sstevel@tonic-gate  *
21830Sstevel@tonic-gate  * PURPOSE:	Wrappers around hba_supports_protocol which determines
21840Sstevel@tonic-gate  *		if the input HBA supports the protocol of interest.
21850Sstevel@tonic-gate  */
21860Sstevel@tonic-gate int
hba_is_fast(dm_descriptor_t hba,boolean_t * bool)21870Sstevel@tonic-gate hba_is_fast(
21880Sstevel@tonic-gate 	dm_descriptor_t	hba,
21890Sstevel@tonic-gate 	boolean_t	*bool)
21900Sstevel@tonic-gate {
21910Sstevel@tonic-gate 	return (hba_supports_protocol(hba, DM_FAST, bool));
21920Sstevel@tonic-gate }
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate int
hba_is_fast_20(dm_descriptor_t hba,boolean_t * bool)21950Sstevel@tonic-gate hba_is_fast_20(
21960Sstevel@tonic-gate 	dm_descriptor_t	hba,
21970Sstevel@tonic-gate 	boolean_t	*bool)
21980Sstevel@tonic-gate {
21990Sstevel@tonic-gate 	return (hba_supports_protocol(hba, DM_FAST20, bool));
22000Sstevel@tonic-gate }
22010Sstevel@tonic-gate 
22020Sstevel@tonic-gate int
hba_is_fast_40(dm_descriptor_t hba,boolean_t * bool)22030Sstevel@tonic-gate hba_is_fast_40(
22040Sstevel@tonic-gate 	dm_descriptor_t	hba,
22050Sstevel@tonic-gate 	boolean_t	*bool)
22060Sstevel@tonic-gate {
22070Sstevel@tonic-gate 	return (hba_supports_protocol(hba, DM_FAST40, bool));
22080Sstevel@tonic-gate }
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate int
hba_is_fast_80(dm_descriptor_t hba,boolean_t * bool)22110Sstevel@tonic-gate hba_is_fast_80(
22120Sstevel@tonic-gate 	dm_descriptor_t	hba,
22130Sstevel@tonic-gate 	boolean_t	*bool)
22140Sstevel@tonic-gate {
22150Sstevel@tonic-gate 	return (hba_supports_protocol(hba, DM_FAST80, bool));
22160Sstevel@tonic-gate }
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate int
hba_is_multiplex(dm_descriptor_t hba,boolean_t * bool)22190Sstevel@tonic-gate hba_is_multiplex(
22200Sstevel@tonic-gate 	dm_descriptor_t	hba,
22210Sstevel@tonic-gate 	boolean_t	*bool)
22220Sstevel@tonic-gate {
22230Sstevel@tonic-gate 	return (hba_supports_protocol(hba, DM_MULTIPLEX, bool));
22240Sstevel@tonic-gate }
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate int
hba_supports_wide(dm_descriptor_t hba,boolean_t * bool)22270Sstevel@tonic-gate hba_supports_wide(
22280Sstevel@tonic-gate 	dm_descriptor_t	hba,
22290Sstevel@tonic-gate 	boolean_t	*bool)
22300Sstevel@tonic-gate {
22310Sstevel@tonic-gate 	nvlist_t	*attrs	= NULL;
22320Sstevel@tonic-gate 	int		error	= 0;
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 	*bool = B_FALSE;
22350Sstevel@tonic-gate 
22360Sstevel@tonic-gate 	if ((error = get_cached_attributes(hba, &attrs)) != 0) {
22370Sstevel@tonic-gate 	    return (error);
22380Sstevel@tonic-gate 	}
22390Sstevel@tonic-gate 
22400Sstevel@tonic-gate 	*bool = (0 == nvlist_lookup_boolean(attrs, DM_WIDE));
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 	return (error);
22430Sstevel@tonic-gate }
22440Sstevel@tonic-gate 
22450Sstevel@tonic-gate /*
22460Sstevel@tonic-gate  * FUNCTION:	hba_supports_protocol(dm_descriptor_t hba, char *attr,
22470Sstevel@tonic-gate  *			boolean_t *bool)
22480Sstevel@tonic-gate  *
22490Sstevel@tonic-gate  * INPUT:	hba	- a dm_descriptor_t handle for a HBA
22500Sstevel@tonic-gate  *		attr	- a protocol "name"
22510Sstevel@tonic-gate  *
22520Sstevel@tonic-gate  * OUTPUT:	*bool	- a pointer to a boolean_t to hold the
22530Sstevel@tonic-gate  *			boolean value of the predicate.
22540Sstevel@tonic-gate  *
22550Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
22560Sstevel@tonic-gate  *			 !0 otherwise.
22570Sstevel@tonic-gate  *
22580Sstevel@tonic-gate  * PURPOSE:	Checks the HBAs attributes to see if it is known to
22590Sstevel@tonic-gate  *		support the protocol of interest.
22600Sstevel@tonic-gate  *
22610Sstevel@tonic-gate  *		If the protocol is supported, it will have an entry
22620Sstevel@tonic-gate  *		in the nvpair attribute list that can be retrieved.
22630Sstevel@tonic-gate  *
22640Sstevel@tonic-gate  *		If the entry cannot be retrieved, the protocol is not
22650Sstevel@tonic-gate  *		supported.
22660Sstevel@tonic-gate  */
22670Sstevel@tonic-gate int
hba_supports_protocol(dm_descriptor_t hba,char * attr,boolean_t * bool)22680Sstevel@tonic-gate hba_supports_protocol(
22690Sstevel@tonic-gate 	dm_descriptor_t	hba,
22700Sstevel@tonic-gate 	char		*attr,
22710Sstevel@tonic-gate 	boolean_t	*bool)
22720Sstevel@tonic-gate {
22730Sstevel@tonic-gate 	nvlist_t	*attrs	= NULL;
22740Sstevel@tonic-gate 	int		error	= 0;
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 	*bool = B_FALSE;
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 	if ((error = get_cached_attributes(hba, &attrs)) != 0) {
22790Sstevel@tonic-gate 	    return (error);
22800Sstevel@tonic-gate 	}
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 	*bool = (0 == nvlist_lookup_boolean(attrs, attr));
22830Sstevel@tonic-gate 
22840Sstevel@tonic-gate 	return (error);
22850Sstevel@tonic-gate }
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate /*
22880Sstevel@tonic-gate  * FUNCTION:	slice_set_size(dm_descriptor_t slice, uint64_t size)
22890Sstevel@tonic-gate  *
22900Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for a slice
22910Sstevel@tonic-gate  *
22920Sstevel@tonic-gate  * OUTPUT:	size	- a uint64_t value representing the size of the
22930Sstevel@tonic-gate  *			slice.
22940Sstevel@tonic-gate  *
22950Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
22960Sstevel@tonic-gate  *			 !0 otherwise.
22970Sstevel@tonic-gate  *
22980Sstevel@tonic-gate  * PURPOSE:	Wrapper around slice_set_uint64_attribute which converts
22990Sstevel@tonic-gate  *		the input size in bytes to blocks prior to storing it.
23000Sstevel@tonic-gate  *
23010Sstevel@tonic-gate  *		This function is used when an existing slice gets resized
23020Sstevel@tonic-gate  *		to provide space for a new slice. It is necessary to update
23030Sstevel@tonic-gate  *		the slice's size so that it is accurate.
23040Sstevel@tonic-gate  */
23050Sstevel@tonic-gate int
slice_set_size(dm_descriptor_t slice,uint64_t size)23060Sstevel@tonic-gate slice_set_size(
23070Sstevel@tonic-gate 	dm_descriptor_t	slice,
23080Sstevel@tonic-gate 	uint64_t	size)
23090Sstevel@tonic-gate {
23100Sstevel@tonic-gate 	dm_descriptor_t	disk	= NULL;
23110Sstevel@tonic-gate 	uint64_t	blksize	= 0;
23120Sstevel@tonic-gate 	int		error	= 0;
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate 	((error = slice_get_disk(slice, &disk)) != 0) ||
23150Sstevel@tonic-gate 	(error = disk_get_blocksize(disk, &blksize)) ||
23160Sstevel@tonic-gate 	(error = slice_set_size_in_blocks(slice, (uint64_t)(size / blksize)));
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 	return (error);
23190Sstevel@tonic-gate }
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate /*
23220Sstevel@tonic-gate  * FUNCTION:	slice_set_size_in_blocks(dm_descriptor_t slice, uint64_t size)
23230Sstevel@tonic-gate  *
23240Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for a slice
23250Sstevel@tonic-gate  *
23260Sstevel@tonic-gate  * OUTPUT:	size	- a uint64_t value representing the size of the
23270Sstevel@tonic-gate  *			slice.
23280Sstevel@tonic-gate  *
23290Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
23300Sstevel@tonic-gate  *			 !0 otherwise.
23310Sstevel@tonic-gate  *
23320Sstevel@tonic-gate  * PURPOSE:	Wrapper around slice_set_uint64_attribute to set the slice
23330Sstevel@tonic-gate  *		size.
23340Sstevel@tonic-gate  *
23350Sstevel@tonic-gate  *		This function is used when an existing slice gets resized
23360Sstevel@tonic-gate  *		to provide space for a new slice. It is necessary to update
23370Sstevel@tonic-gate  *		the slice's size so that it is accurate.
23380Sstevel@tonic-gate  */
23390Sstevel@tonic-gate int
slice_set_size_in_blocks(dm_descriptor_t slice,uint64_t size)23400Sstevel@tonic-gate slice_set_size_in_blocks(
23410Sstevel@tonic-gate 	dm_descriptor_t	slice,
23420Sstevel@tonic-gate 	uint64_t	size)
23430Sstevel@tonic-gate {
23440Sstevel@tonic-gate 	return (slice_set_attribute(slice, DM_SIZE, size));
23450Sstevel@tonic-gate }
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate /*
23480Sstevel@tonic-gate  * FUNCTION:	slice_set_start_block(dm_descriptor_t slice, uint64_t start)
23490Sstevel@tonic-gate  *
23500Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for a slice
23510Sstevel@tonic-gate  *
23520Sstevel@tonic-gate  * OUTPUT:	size	- a uint64_t value representing the start block of the
23530Sstevel@tonic-gate  *			slice.
23540Sstevel@tonic-gate  *
23550Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
23560Sstevel@tonic-gate  *			 !0 otherwise.
23570Sstevel@tonic-gate  *
23580Sstevel@tonic-gate  * PURPOSE:	Wrapper around slice_set_attribute.
23590Sstevel@tonic-gate  *
23600Sstevel@tonic-gate  *		This function is used when an existing slice gets adjusted
23610Sstevel@tonic-gate  *		due to being resized or combined with another slice.
23620Sstevel@tonic-gate  */
23630Sstevel@tonic-gate int
slice_set_start_block(dm_descriptor_t slice,uint64_t start)23640Sstevel@tonic-gate slice_set_start_block(
23650Sstevel@tonic-gate 	dm_descriptor_t	slice,
23660Sstevel@tonic-gate 	uint64_t	start)
23670Sstevel@tonic-gate {
23680Sstevel@tonic-gate 	return (slice_set_attribute(slice, DM_START, start));
23690Sstevel@tonic-gate }
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate /*
23720Sstevel@tonic-gate  * FUNCTION:	slice_get_start_block(dm_descriptor_t slice, uint64_t *val)
23730Sstevel@tonic-gate  *		slice_get_size_in_blocks(dm_descriptor_t slice, uint64_t *val)
23740Sstevel@tonic-gate  *		slice_get_start(dm_descriptor_t slice, uint64_t *val)
23750Sstevel@tonic-gate  *		slice_get_size(dm_descriptor_t slice, uint64_t *val)
23760Sstevel@tonic-gate  *		slice_get_index(dm_descriptor_t slice, uint64_t *val)
23770Sstevel@tonic-gate  *
23780Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for a slice
23790Sstevel@tonic-gate  *
23800Sstevel@tonic-gate  * OUTPUT:	*val	- a pointer to a uint64_t to hold the
23810Sstevel@tonic-gate  *			current value of the desired attribute.
23820Sstevel@tonic-gate  *
23830Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
23840Sstevel@tonic-gate  *			 !0 otherwise.
23850Sstevel@tonic-gate  *
23860Sstevel@tonic-gate  * PURPOSE:	Wrappers around slice_get_uint64_attribute which retrieve
23870Sstevel@tonic-gate  *		specific attribute values.
23880Sstevel@tonic-gate  */
23890Sstevel@tonic-gate int
slice_get_start_block(dm_descriptor_t slice,uint64_t * val)23900Sstevel@tonic-gate slice_get_start_block(
23910Sstevel@tonic-gate 	dm_descriptor_t	slice,
23920Sstevel@tonic-gate 	uint64_t	*val)
23930Sstevel@tonic-gate {
23940Sstevel@tonic-gate 	return (slice_get_uint64_attribute(slice, DM_START, val));
23950Sstevel@tonic-gate }
23960Sstevel@tonic-gate 
23970Sstevel@tonic-gate int
slice_get_size_in_blocks(dm_descriptor_t slice,uint64_t * val)23980Sstevel@tonic-gate slice_get_size_in_blocks(
23990Sstevel@tonic-gate 	dm_descriptor_t	slice,
24000Sstevel@tonic-gate 	uint64_t	*val)
24010Sstevel@tonic-gate {
24020Sstevel@tonic-gate 	return (slice_get_uint64_attribute(slice, DM_SIZE, val));
24030Sstevel@tonic-gate }
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate int
slice_get_start(dm_descriptor_t slice,uint64_t * val)24060Sstevel@tonic-gate slice_get_start(
24070Sstevel@tonic-gate 	dm_descriptor_t	slice,
24080Sstevel@tonic-gate 	uint64_t	*val)
24090Sstevel@tonic-gate {
24100Sstevel@tonic-gate 	dm_descriptor_t	disk	= NULL;
24110Sstevel@tonic-gate 	uint64_t	blksize	= 0;
24120Sstevel@tonic-gate 	uint64_t	nblks	= 0;
24130Sstevel@tonic-gate 	int		error	= 0;
24140Sstevel@tonic-gate 
24150Sstevel@tonic-gate 	((error = slice_get_disk(slice, &disk)) != 0) ||
24160Sstevel@tonic-gate 	(error = disk_get_blocksize(disk, &blksize)) ||
24170Sstevel@tonic-gate 	(error = slice_get_start_block(slice, &nblks));
24180Sstevel@tonic-gate 
24190Sstevel@tonic-gate 	if (error == 0) {
24200Sstevel@tonic-gate 	    *val = (blksize * nblks);
24210Sstevel@tonic-gate 	}
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate 	return (error);
24240Sstevel@tonic-gate }
24250Sstevel@tonic-gate 
24260Sstevel@tonic-gate int
slice_get_size(dm_descriptor_t slice,uint64_t * val)24270Sstevel@tonic-gate slice_get_size(
24280Sstevel@tonic-gate 	dm_descriptor_t	slice,
24290Sstevel@tonic-gate 	uint64_t	*val)
24300Sstevel@tonic-gate {
24310Sstevel@tonic-gate 	dm_descriptor_t	disk	= NULL;
24320Sstevel@tonic-gate 	uint64_t	blksize	= 0;
24330Sstevel@tonic-gate 	uint64_t	nblks	= 0;
24340Sstevel@tonic-gate 	int		error	= 0;
24350Sstevel@tonic-gate 
24360Sstevel@tonic-gate 	*val = 0;
24370Sstevel@tonic-gate 
24380Sstevel@tonic-gate 	((error = slice_get_disk(slice, &disk)) != 0) ||
24390Sstevel@tonic-gate 	(error = slice_get_size_in_blocks(slice, &nblks)) ||
24400Sstevel@tonic-gate 	(error = disk_get_blocksize(disk, &blksize));
24410Sstevel@tonic-gate 
24420Sstevel@tonic-gate 	if (error == 0) {
24430Sstevel@tonic-gate 	    *val = (blksize * nblks);
24440Sstevel@tonic-gate 	}
24450Sstevel@tonic-gate 
24460Sstevel@tonic-gate 	return (error);
24470Sstevel@tonic-gate }
24480Sstevel@tonic-gate 
24490Sstevel@tonic-gate int
slice_get_index(dm_descriptor_t slice,uint32_t * val)24500Sstevel@tonic-gate slice_get_index(
24510Sstevel@tonic-gate 	dm_descriptor_t	slice,
24520Sstevel@tonic-gate 	uint32_t	*val)
24530Sstevel@tonic-gate {
24540Sstevel@tonic-gate 	uint64_t	index = 0;
24550Sstevel@tonic-gate 	int		error = 0;
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	if ((error = slice_get_uint64_attribute(
24580Sstevel@tonic-gate 	    slice, DM_INDEX, &index)) != 0) {
24590Sstevel@tonic-gate 	    return (error);
24600Sstevel@tonic-gate 	}
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 	*val = (uint32_t)index;
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate 	return (0);
24650Sstevel@tonic-gate }
24660Sstevel@tonic-gate 
24670Sstevel@tonic-gate /*
24680Sstevel@tonic-gate  * FUNCTION:	slice_set_uint64_attribute(dm_descriptor_t slice,
24690Sstevel@tonic-gate  *			char *attr, uint64_t val)
24700Sstevel@tonic-gate  * 		slice_get_uint64_attribute(dm_descriptor_t slice,
24710Sstevel@tonic-gate  *			char *attr, uint64_t *val)
24720Sstevel@tonic-gate  *
24730Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for a slice
24740Sstevel@tonic-gate  *		attr    - a char * attribute name
24750Sstevel@tonic-gate  *		val	- auint64_t value
24760Sstevel@tonic-gate  *
24770Sstevel@tonic-gate  * OUTPUT:	*val	- a pointer to a uint64_t to hold the
24780Sstevel@tonic-gate  *			current value of the named attribute.
24790Sstevel@tonic-gate  *
24800Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
24810Sstevel@tonic-gate  *			 !0 otherwise.
24820Sstevel@tonic-gate  *
24830Sstevel@tonic-gate  * PURPOSE:	Helpers to set/get the value for a slice's attribute.
24840Sstevel@tonic-gate  *
24850Sstevel@tonic-gate  *		Consolidate the details of getting/setting slice
24860Sstevel@tonic-gate  *		attributes.  Some attributes are actually stored as
24870Sstevel@tonic-gate  *		uint32_t or uint16_t values, these functions mask
24880Sstevel@tonic-gate  *		the type conversions.
24890Sstevel@tonic-gate  */
24900Sstevel@tonic-gate static int
slice_get_uint64_attribute(dm_descriptor_t slice,char * attr,uint64_t * val)24910Sstevel@tonic-gate slice_get_uint64_attribute(
24920Sstevel@tonic-gate 	dm_descriptor_t	slice,
24930Sstevel@tonic-gate 	char		*attr,
24940Sstevel@tonic-gate 	uint64_t	*val)
24950Sstevel@tonic-gate {
24960Sstevel@tonic-gate 	nvlist_t	*attrs	= NULL;
24970Sstevel@tonic-gate 	uint32_t	ui32	= 0;
24980Sstevel@tonic-gate 	int		error	= 0;
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate 	if ((error = get_cached_attributes(slice, &attrs)) != 0) {
25010Sstevel@tonic-gate 	    return (error);
25020Sstevel@tonic-gate 	}
25030Sstevel@tonic-gate 
25040Sstevel@tonic-gate 	if (strcmp(attr, DM_INDEX) == 0) {
25050Sstevel@tonic-gate 	    error = get_uint32(attrs, attr, &ui32);
25060Sstevel@tonic-gate 	    *val = (uint64_t)ui32;
25070Sstevel@tonic-gate 	} else if (strcmp(attr, DM_START) == 0) {
25080Sstevel@tonic-gate 	    error = get_uint64(attrs, attr, val);
25090Sstevel@tonic-gate 	} else if (strcmp(attr, DM_SIZE) == 0) {
25100Sstevel@tonic-gate 	    error = get_uint64(attrs, attr, val);
25110Sstevel@tonic-gate 	} else if (strcmp(attr, ATTR_DISK_FOR_SLICE) == 0) {
25120Sstevel@tonic-gate 	    error = get_uint64(attrs, attr, val);
25130Sstevel@tonic-gate 	}
25140Sstevel@tonic-gate 
25150Sstevel@tonic-gate 	if (error != 0) {
25160Sstevel@tonic-gate 	    print_get_desc_attr_error(slice, "slice", attr, error);
25170Sstevel@tonic-gate 	}
25180Sstevel@tonic-gate 
25190Sstevel@tonic-gate 	return (error);
25200Sstevel@tonic-gate }
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate /*
25230Sstevel@tonic-gate  * Set a slice attribute.  The attribute is only set in the cached
25240Sstevel@tonic-gate  * copy of the slice's nvpair attribute list.  This function does
25250Sstevel@tonic-gate  * NOT affect the underlying physical device.
25260Sstevel@tonic-gate  */
25270Sstevel@tonic-gate static int
slice_set_attribute(dm_descriptor_t slice,char * attr,uint64_t val)25280Sstevel@tonic-gate slice_set_attribute(
25290Sstevel@tonic-gate 	dm_descriptor_t	slice,
25300Sstevel@tonic-gate 	char		*attr,
25310Sstevel@tonic-gate 	uint64_t	val)
25320Sstevel@tonic-gate {
25330Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
25340Sstevel@tonic-gate 	int		error = 0;
25350Sstevel@tonic-gate 
25360Sstevel@tonic-gate 	if ((error = get_cached_attributes(slice, &attrs)) != 0) {
25370Sstevel@tonic-gate 	    return (error);
25380Sstevel@tonic-gate 	}
25390Sstevel@tonic-gate 
25400Sstevel@tonic-gate 	if (strcmp(attr, DM_INDEX) == 0) {
25410Sstevel@tonic-gate 	    error = set_uint32(attrs, attr, (uint32_t)val);
25420Sstevel@tonic-gate 	} else if (strcmp(attr, DM_START) == 0) {
25430Sstevel@tonic-gate 	    error = set_uint64(attrs, attr, val);
25440Sstevel@tonic-gate 	} else if (strcmp(attr, DM_SIZE) == 0) {
25450Sstevel@tonic-gate 	    error = set_uint64(attrs, attr, val);
25460Sstevel@tonic-gate 	} else if (strcmp(attr, ATTR_DISK_FOR_SLICE) == 0) {
25470Sstevel@tonic-gate 	    error = set_uint64(attrs, attr, val);
25480Sstevel@tonic-gate 	}
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate 	if (error != 0) {
25510Sstevel@tonic-gate 	    print_set_desc_attr_error(slice, "slice", attr, error);
25520Sstevel@tonic-gate 	}
25530Sstevel@tonic-gate 
25540Sstevel@tonic-gate 	return (error);
25550Sstevel@tonic-gate }
25560Sstevel@tonic-gate 
25570Sstevel@tonic-gate /*
25580Sstevel@tonic-gate  * FUNCTION:	virtual_slice_get_disk(dm_descriptor_t slice,
25590Sstevel@tonic-gate  *			dm_descriptor_t *diskp)
25600Sstevel@tonic-gate  *
25610Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t virtual slice handle
25620Sstevel@tonic-gate  *		diskp	- pointer to a dm_descriptor_t disk handle
25630Sstevel@tonic-gate  *				to return the slice's disk
25640Sstevel@tonic-gate  *
25650Sstevel@tonic-gate  * OUTPUT:	the disk associated with the virtual slice.
25660Sstevel@tonic-gate  *
25670Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
25680Sstevel@tonic-gate  *			 !0 otherwise
25690Sstevel@tonic-gate  *
25700Sstevel@tonic-gate  * PURPOSE:	Helper which determines the disk that the input virtual
25710Sstevel@tonic-gate  *		slice "belongs" to.
25720Sstevel@tonic-gate  *
25730Sstevel@tonic-gate  *		The virtual slice's disk is stored in the slice's nvpair
25740Sstevel@tonic-gate  *		attribute list when the slice gets created.
25750Sstevel@tonic-gate  */
25760Sstevel@tonic-gate static int
virtual_slice_get_disk(dm_descriptor_t slice,dm_descriptor_t * diskp)25770Sstevel@tonic-gate virtual_slice_get_disk(
25780Sstevel@tonic-gate 	dm_descriptor_t	slice,
25790Sstevel@tonic-gate 	dm_descriptor_t	*diskp)
25800Sstevel@tonic-gate {
25810Sstevel@tonic-gate 	uint64_t disk = 0;
25820Sstevel@tonic-gate 	int	error = 0;
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate 	if ((error = slice_get_uint64_attribute(
25850Sstevel@tonic-gate 	    slice, ATTR_DISK_FOR_SLICE, &disk)) != 0) {
25860Sstevel@tonic-gate 	    return (error);
25870Sstevel@tonic-gate 	}
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 	*diskp = (dm_descriptor_t)disk;
25900Sstevel@tonic-gate 
25910Sstevel@tonic-gate 	if (disk == 0) {
25920Sstevel@tonic-gate 	    print_get_desc_attr_error(slice, "virtual slice", "disk", error);
25930Sstevel@tonic-gate 	    return (-1);
25940Sstevel@tonic-gate 	}
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate 	return (0);
25970Sstevel@tonic-gate }
25980Sstevel@tonic-gate 
25990Sstevel@tonic-gate /*
26000Sstevel@tonic-gate  * FUNCTION:	slice_get_disk(dm_descriptor_t disk, dm_descriptor_t *diskp)
26010Sstevel@tonic-gate  *
26020Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for a slice
26030Sstevel@tonic-gate  *
26040Sstevel@tonic-gate  * OUTPUT:	diskp	- a pointer to a dm_descriptor_t to hold the
26050Sstevel@tonic-gate  *			disk associated with the input slice
26060Sstevel@tonic-gate  *
26070Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
26080Sstevel@tonic-gate  *			 !0 otherwise.
26090Sstevel@tonic-gate  *
26100Sstevel@tonic-gate  * PURPOSE:	Helper which retrieves the disk for a slice device.
26110Sstevel@tonic-gate  *
26120Sstevel@tonic-gate  *		A slice is actually connected to its disk thru an intermediate
26130Sstevel@tonic-gate  *		device known as the "media". The media concept exists to
26140Sstevel@tonic-gate  *		model drives with removeable disk media. For the purposes
26150Sstevel@tonic-gate  *		of layout, such devices aren't relevant and the intermediate
26160Sstevel@tonic-gate  *		media can mostly be ignored.
26170Sstevel@tonic-gate  */
26180Sstevel@tonic-gate int
slice_get_disk(dm_descriptor_t slice,dm_descriptor_t * diskp)26190Sstevel@tonic-gate slice_get_disk(
26200Sstevel@tonic-gate 	dm_descriptor_t	slice,
26210Sstevel@tonic-gate 	dm_descriptor_t *diskp)
26220Sstevel@tonic-gate {
26230Sstevel@tonic-gate 	dm_descriptor_t	*media = NULL;
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate 	int	i = 0;
26260Sstevel@tonic-gate 	int	error = 0;
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 	*diskp = 0;
26290Sstevel@tonic-gate 
26300Sstevel@tonic-gate 	if (is_virtual_slice(slice)) {
26310Sstevel@tonic-gate 	    return (virtual_slice_get_disk(slice, diskp));
26320Sstevel@tonic-gate 	}
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate 	media = dm_get_associated_descriptors(slice, DM_MEDIA, &error);
26350Sstevel@tonic-gate 	(void) add_descriptors_to_free(media);
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	if (error != 0) {
26380Sstevel@tonic-gate 	    print_get_assoc_desc_error(slice, gettext("media"), error);
26390Sstevel@tonic-gate 	} else if ((media == NULL) || (*media == NULL)) {
26400Sstevel@tonic-gate 	    print_get_assoc_desc_error(slice, gettext("media"), error);
26410Sstevel@tonic-gate 	    error = -1;
26420Sstevel@tonic-gate 	}
26430Sstevel@tonic-gate 
26440Sstevel@tonic-gate 	if (error != 0) {
26450Sstevel@tonic-gate 	    return (error);
26460Sstevel@tonic-gate 	}
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate 	/* slice should have exactly 1 media */
26490Sstevel@tonic-gate 	for (i = 0; (media[i] != NULL) && (*diskp == NULL); i++) {
26500Sstevel@tonic-gate 	    /* get disk from media */
26510Sstevel@tonic-gate 	    dm_descriptor_t *disks = NULL;
26520Sstevel@tonic-gate 	    disks = dm_get_associated_descriptors(media[i], DM_DRIVE, &error);
26530Sstevel@tonic-gate 	    (void) add_descriptors_to_free(disks);
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate 	    if ((error == 0) && (disks != NULL) && (disks[0] != NULL)) {
26560Sstevel@tonic-gate 		*diskp = disks[0];
26570Sstevel@tonic-gate 	    }
26580Sstevel@tonic-gate 	    free(disks);
26590Sstevel@tonic-gate 	}
26600Sstevel@tonic-gate 
26610Sstevel@tonic-gate 	if (media != NULL) {
26620Sstevel@tonic-gate 	    free(media);
26630Sstevel@tonic-gate 	}
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 	if (*diskp == 0) {
26660Sstevel@tonic-gate 	    print_get_desc_attr_error(slice,
26670Sstevel@tonic-gate 		    gettext("slice"), gettext("disk"), ENODEV);
26680Sstevel@tonic-gate 	    error = -1;
26690Sstevel@tonic-gate 	}
26700Sstevel@tonic-gate 
26710Sstevel@tonic-gate 	return (error);
26720Sstevel@tonic-gate }
26730Sstevel@tonic-gate 
26740Sstevel@tonic-gate /*
26750Sstevel@tonic-gate  * FUNCTION:	slice_get_hbas(dm_descriptor_t slice, dlist_t **list)
26760Sstevel@tonic-gate  *
26770Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for a slice
26780Sstevel@tonic-gate  *
26790Sstevel@tonic-gate  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
26800Sstevel@tonic-gate  *			HBAs associated with the input slice
26810Sstevel@tonic-gate  *
26820Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
26830Sstevel@tonic-gate  *			 !0 otherwise.
26840Sstevel@tonic-gate  *
26850Sstevel@tonic-gate  * PURPOSE:	Helper which retrieves the known HBAs for a slice device.
26860Sstevel@tonic-gate  *
26870Sstevel@tonic-gate  */
26880Sstevel@tonic-gate int
slice_get_hbas(dm_descriptor_t slice,dlist_t ** list)26890Sstevel@tonic-gate slice_get_hbas(
26900Sstevel@tonic-gate 	dm_descriptor_t	slice,
26910Sstevel@tonic-gate 	dlist_t		**list)
26920Sstevel@tonic-gate {
26930Sstevel@tonic-gate 	dm_descriptor_t	disk	= NULL;
26940Sstevel@tonic-gate 	int		error	= 0;
26950Sstevel@tonic-gate 
26960Sstevel@tonic-gate 	*list = NULL;
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate 	((error = slice_get_disk(slice, &disk)) != 0) ||
26990Sstevel@tonic-gate 	(error = disk_get_hbas(disk, list));
27000Sstevel@tonic-gate 
27010Sstevel@tonic-gate 	if (*list == NULL) {
27020Sstevel@tonic-gate 	    print_get_desc_attr_error(slice, "slice", "HBA", ENODEV);
27030Sstevel@tonic-gate 	    error = -1;
27040Sstevel@tonic-gate 	}
27050Sstevel@tonic-gate 
27060Sstevel@tonic-gate 	return (error);
27070Sstevel@tonic-gate }
27080Sstevel@tonic-gate 
27090Sstevel@tonic-gate /*
27100Sstevel@tonic-gate  * FUNCTION:	disk_get_associated_desc(dm_descriptor_t disk,
27110Sstevel@tonic-gate  *			dm_desc_type_t assoc_type, char *assoc_type_str,
27120Sstevel@tonic-gate  *			dlist_t **list)
27130Sstevel@tonic-gate  *
27140Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
27150Sstevel@tonic-gate  *		assoc_type - the type of associated object to get
27160Sstevel@tonic-gate  *		assoc_type_str - a char * string for the associated type
27170Sstevel@tonic-gate  *
27180Sstevel@tonic-gate  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
27190Sstevel@tonic-gate  *			objects associated with the input disk
27200Sstevel@tonic-gate  *
27210Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
27220Sstevel@tonic-gate  *			 !0 otherwise.
27230Sstevel@tonic-gate  *
27240Sstevel@tonic-gate  * PURPOSE:	Helper which retrieves the associated objects of the
27250Sstevel@tonic-gate  *		requested type for a disk device.
27260Sstevel@tonic-gate  */
27270Sstevel@tonic-gate static int
disk_get_associated_desc(dm_descriptor_t disk,dm_desc_type_t assoc_type,char * assoc_type_str,dlist_t ** list)27280Sstevel@tonic-gate disk_get_associated_desc(
27290Sstevel@tonic-gate 	dm_descriptor_t	disk,
27300Sstevel@tonic-gate 	dm_desc_type_t 	assoc_type,
27310Sstevel@tonic-gate 	char		*assoc_type_str,
27320Sstevel@tonic-gate 	dlist_t		**list)
27330Sstevel@tonic-gate {
27340Sstevel@tonic-gate 	int	i = 0;
27350Sstevel@tonic-gate 	int	error = 0;
27360Sstevel@tonic-gate 
27370Sstevel@tonic-gate 	dm_descriptor_t	*assoc =
27380Sstevel@tonic-gate 	    dm_get_associated_descriptors(disk, assoc_type, &error);
27390Sstevel@tonic-gate 
27400Sstevel@tonic-gate 	(void) add_descriptors_to_free(assoc);
27410Sstevel@tonic-gate 
27420Sstevel@tonic-gate 	if (error == 0) {
27430Sstevel@tonic-gate 	    for (i = 0;
27440Sstevel@tonic-gate 		(assoc != NULL) && (assoc[i] != NULL) && (error == 0);
27450Sstevel@tonic-gate 		i++) {
2746*62Sjeanm 		dlist_t *item = dlist_new_item((void *)(uintptr_t)assoc[i]);
27470Sstevel@tonic-gate 		if (item == NULL) {
27480Sstevel@tonic-gate 		    error = ENOMEM;
27490Sstevel@tonic-gate 		} else {
27500Sstevel@tonic-gate 		    *list = dlist_append(item, *list, AT_TAIL);
27510Sstevel@tonic-gate 		}
27520Sstevel@tonic-gate 	    }
27530Sstevel@tonic-gate 	} else {
27540Sstevel@tonic-gate 	    print_get_assoc_desc_error(disk, assoc_type_str, error);
27550Sstevel@tonic-gate 	}
27560Sstevel@tonic-gate 
27570Sstevel@tonic-gate 	if (assoc != NULL) {
27580Sstevel@tonic-gate 	    free(assoc);
27590Sstevel@tonic-gate 	}
27600Sstevel@tonic-gate 
27610Sstevel@tonic-gate 	if (error != 0) {
27620Sstevel@tonic-gate 	    dlist_free_items(*list, NULL);
27630Sstevel@tonic-gate 	    *list = NULL;
27640Sstevel@tonic-gate 	}
27650Sstevel@tonic-gate 
27660Sstevel@tonic-gate 	return (error);
27670Sstevel@tonic-gate }
27680Sstevel@tonic-gate 
27690Sstevel@tonic-gate /*
27700Sstevel@tonic-gate  * FUNCTION:	disk_get_hbas(dm_descriptor_t disk, dlist_t **list)
27710Sstevel@tonic-gate  *
27720Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
27730Sstevel@tonic-gate  *
27740Sstevel@tonic-gate  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
27750Sstevel@tonic-gate  *			HBAs associated with the input disk
27760Sstevel@tonic-gate  *
27770Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
27780Sstevel@tonic-gate  *			 !0 otherwise.
27790Sstevel@tonic-gate  *
27800Sstevel@tonic-gate  * PURPOSE:	Helper which retrieves the known HBAs for a disk device.
27810Sstevel@tonic-gate  *
27820Sstevel@tonic-gate  */
27830Sstevel@tonic-gate int
disk_get_hbas(dm_descriptor_t disk,dlist_t ** list)27840Sstevel@tonic-gate disk_get_hbas(
27850Sstevel@tonic-gate 	dm_descriptor_t	disk,
27860Sstevel@tonic-gate 	dlist_t		**list)
27870Sstevel@tonic-gate {
27880Sstevel@tonic-gate 	return (disk_get_associated_desc(disk, DM_CONTROLLER,
27890Sstevel@tonic-gate 			gettext("controller"), list));
27900Sstevel@tonic-gate }
27910Sstevel@tonic-gate 
27920Sstevel@tonic-gate /*
27930Sstevel@tonic-gate  * FUNCTION:	disk_get_paths(dm_descriptor_t disk, dlist_t **list)
27940Sstevel@tonic-gate  *
27950Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
27960Sstevel@tonic-gate  *
27970Sstevel@tonic-gate  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
27980Sstevel@tonic-gate  *			paths associated with the input disk
27990Sstevel@tonic-gate  *
28000Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
28010Sstevel@tonic-gate  *			 !0 otherwise.
28020Sstevel@tonic-gate  *
28030Sstevel@tonic-gate  * PURPOSE:	Helper which retrieves the known paths for a disk device.
28040Sstevel@tonic-gate  *
28050Sstevel@tonic-gate  *		Paths are managed by the MPXIO driver, they represent hardware
28060Sstevel@tonic-gate  *		paths to the disk drive managed by the MPXIO and not visible
28070Sstevel@tonic-gate  *		externally, unlike aliases which are.
28080Sstevel@tonic-gate  */
28090Sstevel@tonic-gate int
disk_get_paths(dm_descriptor_t disk,dlist_t ** list)28100Sstevel@tonic-gate disk_get_paths(
28110Sstevel@tonic-gate 	dm_descriptor_t	disk,
28120Sstevel@tonic-gate 	dlist_t		**list)
28130Sstevel@tonic-gate {
28140Sstevel@tonic-gate 	return (disk_get_associated_desc(disk, DM_PATH,
28150Sstevel@tonic-gate 			gettext("path"), list));
28160Sstevel@tonic-gate }
28170Sstevel@tonic-gate 
28180Sstevel@tonic-gate /*
28190Sstevel@tonic-gate  * FUNCTION:	disk_get_aliases(dm_descriptor_t disk, dlist_t **list)
28200Sstevel@tonic-gate  *
28210Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for a disk
28220Sstevel@tonic-gate  *
28230Sstevel@tonic-gate  * OUTPUT:	list	- a pointer to a dlist_t list to hold the
28240Sstevel@tonic-gate  *			alias descriptors associated with the input disk
28250Sstevel@tonic-gate  *
28260Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
28270Sstevel@tonic-gate  *			 !0 otherwise.
28280Sstevel@tonic-gate  *
28290Sstevel@tonic-gate  * PURPOSE:	Helper which retrieves the known aliases for a disk device.
28300Sstevel@tonic-gate  *
28310Sstevel@tonic-gate  *		Aliases are the different CTD names for the disk drive when
28320Sstevel@tonic-gate  *		MPXIO is not enabled for multipathed drives.
28330Sstevel@tonic-gate  */
28340Sstevel@tonic-gate int
disk_get_aliases(dm_descriptor_t disk,dlist_t ** list)28350Sstevel@tonic-gate disk_get_aliases(
28360Sstevel@tonic-gate 	dm_descriptor_t	disk,
28370Sstevel@tonic-gate 	dlist_t		**list)
28380Sstevel@tonic-gate {
28390Sstevel@tonic-gate 	return (disk_get_associated_desc(disk, DM_ALIAS,
28400Sstevel@tonic-gate 			gettext("alias"), list));
28410Sstevel@tonic-gate }
28420Sstevel@tonic-gate 
28430Sstevel@tonic-gate /*
28440Sstevel@tonic-gate  * FUNCTION:	compare_string_to_desc_name_or_alias(
28450Sstevel@tonic-gate  *			void *str, void *desc)
28460Sstevel@tonic-gate  *
28470Sstevel@tonic-gate  * INPUT:	str	- opaque pointer
28480Sstevel@tonic-gate  * 		descr	- opaque pointer
28490Sstevel@tonic-gate  *
28500Sstevel@tonic-gate  * RETURNS:	int	- <0 - if str < desc.name
28510Sstevel@tonic-gate  *			   0 - if str == desc.name
28520Sstevel@tonic-gate  *			  >0 - if str > desc.name
28530Sstevel@tonic-gate  *
28540Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares a string to the name
28550Sstevel@tonic-gate  *		and aliases associated with the input dm_descriptor_t
28560Sstevel@tonic-gate  *		handle.
28570Sstevel@tonic-gate  *
28580Sstevel@tonic-gate  *		Comparison is done via compare_device_names.
28590Sstevel@tonic-gate  */
28600Sstevel@tonic-gate static int
compare_string_to_desc_name_or_alias(void * str,void * desc)28610Sstevel@tonic-gate compare_string_to_desc_name_or_alias(
28620Sstevel@tonic-gate 	void	*str,
28630Sstevel@tonic-gate 	void	*desc)
28640Sstevel@tonic-gate {
28650Sstevel@tonic-gate 	char	*dname = NULL;
28660Sstevel@tonic-gate 	int	result = -1;
28670Sstevel@tonic-gate 
28680Sstevel@tonic-gate 	assert(str != (char *)NULL);
28690Sstevel@tonic-gate 	assert(desc != (dm_descriptor_t)0);
28700Sstevel@tonic-gate 
28710Sstevel@tonic-gate 	(void) get_display_name((uintptr_t)desc, &dname);
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate 	/* try name first, then aliases */
28740Sstevel@tonic-gate 	if ((result = compare_device_names(str, dname)) != 0) {
28750Sstevel@tonic-gate 	    dlist_t *aliases = NULL;
28760Sstevel@tonic-gate 
28770Sstevel@tonic-gate 	    (void) get_aliases((uintptr_t)desc, &aliases);
28780Sstevel@tonic-gate 	    if ((aliases != NULL) && (dlist_contains(aliases,
28790Sstevel@tonic-gate 			str, compare_device_names) == B_TRUE)) {
28800Sstevel@tonic-gate 		result = 0;
28810Sstevel@tonic-gate 	    }
28820Sstevel@tonic-gate 	    dlist_free_items(aliases, free);
28830Sstevel@tonic-gate 	}
28840Sstevel@tonic-gate 
28850Sstevel@tonic-gate 	return (result);
28860Sstevel@tonic-gate }
28870Sstevel@tonic-gate 
28880Sstevel@tonic-gate /*
28890Sstevel@tonic-gate  * FUNCTION:	hba_get_by_name(char *name, dm_descriptor_t *hba)
28900Sstevel@tonic-gate  *
28910Sstevel@tonic-gate  * INPUT:	name	- a char * disk name
28920Sstevel@tonic-gate  *
28930Sstevel@tonic-gate  * OUTPUT:	hba	- a pointer to a dm_descriptor_t to hold the
28940Sstevel@tonic-gate  *			HBA corresponding to the input name, if found
28950Sstevel@tonic-gate  *
28960Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
28970Sstevel@tonic-gate  *			 !0 otherwise
28980Sstevel@tonic-gate  *
28990Sstevel@tonic-gate  * PURPOSE:	Helper which iterates the known HBAs, searching for
29000Sstevel@tonic-gate  *		the one matching name.
29010Sstevel@tonic-gate  *
29020Sstevel@tonic-gate  *		If no HBA matches the name, 0 is returned and the
29030Sstevel@tonic-gate  *		value of 'hba' will be (dm_descriptor_t)0;
29040Sstevel@tonic-gate  */
29050Sstevel@tonic-gate int
hba_get_by_name(char * name,dm_descriptor_t * hba)29060Sstevel@tonic-gate hba_get_by_name(
29070Sstevel@tonic-gate 	char		*name,
29080Sstevel@tonic-gate 	dm_descriptor_t *hba)
29090Sstevel@tonic-gate {
29100Sstevel@tonic-gate 	int		error = 0;
29110Sstevel@tonic-gate 	dlist_t		*list = NULL;
29120Sstevel@tonic-gate 	dlist_t		*item = NULL;
29130Sstevel@tonic-gate 
29140Sstevel@tonic-gate 	*hba = (dm_descriptor_t)0;
29150Sstevel@tonic-gate 
29160Sstevel@tonic-gate 	if (name == NULL) {
29170Sstevel@tonic-gate 	    return (0);
29180Sstevel@tonic-gate 	}
29190Sstevel@tonic-gate 
29200Sstevel@tonic-gate 	if ((error = get_known_hbas(&list)) != 0) {
29210Sstevel@tonic-gate 	    return (error);
29220Sstevel@tonic-gate 	}
29230Sstevel@tonic-gate 
29240Sstevel@tonic-gate 	if ((item = dlist_find(list, name,
29250Sstevel@tonic-gate 	    compare_string_to_desc_name_or_alias)) != NULL) {
29260Sstevel@tonic-gate 	    *hba = (uintptr_t)item->obj;
29270Sstevel@tonic-gate 	}
29280Sstevel@tonic-gate 
29290Sstevel@tonic-gate 	return (error);
29300Sstevel@tonic-gate }
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate /*
29330Sstevel@tonic-gate  * FUNCTION:	disk_get_by_name(char *name, dm_descriptor_t *disk)
29340Sstevel@tonic-gate  *
29350Sstevel@tonic-gate  * INPUT:	name	- a char * disk name
29360Sstevel@tonic-gate  *
29370Sstevel@tonic-gate  * OUTPUT:	disk	- a pointer to a dm_descriptor_t to hold the
29380Sstevel@tonic-gate  *			disk corresponding to the input name, if found
29390Sstevel@tonic-gate  *
29400Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
29410Sstevel@tonic-gate  *			 !0 otherwise.
29420Sstevel@tonic-gate  *
29430Sstevel@tonic-gate  * PURPOSE:	Helper which retrieves a dm_descriptor_t disk handle
29440Sstevel@tonic-gate  *		by name.
29450Sstevel@tonic-gate  *
29460Sstevel@tonic-gate  *		If no disk is found for the input name, variations of
29470Sstevel@tonic-gate  *		the name are tried.
29480Sstevel@tonic-gate  *
29490Sstevel@tonic-gate  *		If the input name is unqualified, an appropriate leading
29500Sstevel@tonic-gate  *		path is prepended.
29510Sstevel@tonic-gate  *
29520Sstevel@tonic-gate  *		If the input name is qualified, the leading path is
29530Sstevel@tonic-gate  *		removed.
29540Sstevel@tonic-gate  *
29550Sstevel@tonic-gate  *		If no disk is found for the variations, 0 is returned
29560Sstevel@tonic-gate  *		and the	value of 'disk' will be (dm_descriptor_t)0;
29570Sstevel@tonic-gate  */
29580Sstevel@tonic-gate int
disk_get_by_name(char * name,dm_descriptor_t * disk)29590Sstevel@tonic-gate disk_get_by_name(
29600Sstevel@tonic-gate 	char		*name,
29610Sstevel@tonic-gate 	dm_descriptor_t *disk)
29620Sstevel@tonic-gate {
29630Sstevel@tonic-gate 	assert(name != (char *)NULL);
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	*disk = find_cached_descriptor(name);
29660Sstevel@tonic-gate 	if (*disk == (dm_descriptor_t)0) {
29670Sstevel@tonic-gate 	    if (name[0] == '/') {
29680Sstevel@tonic-gate 		/* fully qualified, try unqualified */
29690Sstevel@tonic-gate 		char *cp = strrchr(name, '/');
29700Sstevel@tonic-gate 		if (cp != NULL) {
29710Sstevel@tonic-gate 		    *disk = find_cached_descriptor(cp + 1);
29720Sstevel@tonic-gate 		}
29730Sstevel@tonic-gate 	    } else {
29740Sstevel@tonic-gate 		/* unqualified, try fully qualified */
29750Sstevel@tonic-gate 		char buf[MAXNAMELEN+1];
29760Sstevel@tonic-gate 		if (is_ctd_disk_name(name)) {
29770Sstevel@tonic-gate 		    (void) snprintf(buf, MAXNAMELEN, "/dev/dsk/%s", name);
29780Sstevel@tonic-gate 		} else if (is_did_disk_name(name)) {
29790Sstevel@tonic-gate 		    (void) snprintf(buf, MAXNAMELEN, "/dev/did/dsk/%s", name);
29800Sstevel@tonic-gate 		}
29810Sstevel@tonic-gate 		*disk = find_cached_descriptor(buf);
29820Sstevel@tonic-gate 	    }
29830Sstevel@tonic-gate 	}
29840Sstevel@tonic-gate 
29850Sstevel@tonic-gate 	/*
29860Sstevel@tonic-gate 	 * since the descriptor cache includes HBAs, disks and slices,
29870Sstevel@tonic-gate 	 * what gets returned may not be a disk... make sure it is
29880Sstevel@tonic-gate 	 */
29890Sstevel@tonic-gate 	if (*disk != (dm_descriptor_t)0) {
29900Sstevel@tonic-gate 	    if (dm_get_type(*disk) != DM_DRIVE) {
29910Sstevel@tonic-gate 		*disk = (dm_descriptor_t)0;
29920Sstevel@tonic-gate 	    }
29930Sstevel@tonic-gate 	}
29940Sstevel@tonic-gate 
29950Sstevel@tonic-gate 	return (0);
29960Sstevel@tonic-gate }
29970Sstevel@tonic-gate 
29980Sstevel@tonic-gate /*
29990Sstevel@tonic-gate  * FUNCTION:	slice_get_by_name(char *name, dm_descriptor_t *slice)
30000Sstevel@tonic-gate  *
30010Sstevel@tonic-gate  * INPUT:	name	- a char * slice name
30020Sstevel@tonic-gate  *
30030Sstevel@tonic-gate  * OUTPUT:	slice	- a pointer to a dm_descriptor_t to hold the
30040Sstevel@tonic-gate  *			slice corresponding to the input name, if found.
30050Sstevel@tonic-gate  *
30060Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
30070Sstevel@tonic-gate  *			 !0 otherwise.
30080Sstevel@tonic-gate  *
30090Sstevel@tonic-gate  * PURPOSE:	Helper which iterates the known slices, searching for
30100Sstevel@tonic-gate  *		the one matching name.
30110Sstevel@tonic-gate  *
30120Sstevel@tonic-gate  *		If no slice is found for the input name, variations of
30130Sstevel@tonic-gate  *		the name are tried.
30140Sstevel@tonic-gate  *
30150Sstevel@tonic-gate  *		If the input name is unqualified, an appropriate leading
30160Sstevel@tonic-gate  *		path is prepended.
30170Sstevel@tonic-gate  *
30180Sstevel@tonic-gate  *		If the input name is qualified, the leading path is
30190Sstevel@tonic-gate  *		removed.
30200Sstevel@tonic-gate  *
30210Sstevel@tonic-gate  *		If no slice matches the variations, 0 is returned and the
30220Sstevel@tonic-gate  *		value of 'slice' will be (dm_descriptor_t)0;
30230Sstevel@tonic-gate  */
30240Sstevel@tonic-gate int
slice_get_by_name(char * name,dm_descriptor_t * slice)30250Sstevel@tonic-gate slice_get_by_name(
30260Sstevel@tonic-gate 	char		*name,
30270Sstevel@tonic-gate 	dm_descriptor_t *slice)
30280Sstevel@tonic-gate {
30290Sstevel@tonic-gate 	assert(name != (char *)NULL);
30300Sstevel@tonic-gate 
30310Sstevel@tonic-gate 	*slice = find_cached_descriptor(name);
30320Sstevel@tonic-gate 	if (*slice == (dm_descriptor_t)0) {
30330Sstevel@tonic-gate 	    if (name[0] == '/') {
30340Sstevel@tonic-gate 		/* fully qualified, try unqualified */
30350Sstevel@tonic-gate 		char *cp = strrchr(name, '/');
30360Sstevel@tonic-gate 		if (cp != NULL) {
30370Sstevel@tonic-gate 		    *slice = find_cached_descriptor(cp + 1);
30380Sstevel@tonic-gate 		}
30390Sstevel@tonic-gate 	    } else {
30400Sstevel@tonic-gate 		/* unqualified, try fully qualified */
30410Sstevel@tonic-gate 		char buf[MAXNAMELEN+1];
30420Sstevel@tonic-gate 		if (is_ctd_slice_name(name) || is_ctd_like_slice_name(name) ||
30430Sstevel@tonic-gate 			is_bsd_like_slice_name(name)) {
30440Sstevel@tonic-gate 		    (void) snprintf(buf, MAXNAMELEN, "/dev/dsk/%s", name);
30450Sstevel@tonic-gate 		} else if (is_did_slice_name(name)) {
30460Sstevel@tonic-gate 		    (void) snprintf(buf, MAXNAMELEN, "/dev/did/dsk/%s", name);
30470Sstevel@tonic-gate 		}
30480Sstevel@tonic-gate 		*slice = find_cached_descriptor(buf);
30490Sstevel@tonic-gate 	    }
30500Sstevel@tonic-gate 	}
30510Sstevel@tonic-gate 
30520Sstevel@tonic-gate 	/*
30530Sstevel@tonic-gate 	 * since the descriptor cache includes HBAs, disks and slices,
30540Sstevel@tonic-gate 	 * what gets returned may not be a slice... make sure it is
30550Sstevel@tonic-gate 	 */
30560Sstevel@tonic-gate 	if (*slice != (dm_descriptor_t)0) {
30570Sstevel@tonic-gate 	    if (dm_get_type(*slice) != DM_SLICE &&
30580Sstevel@tonic-gate 		is_virtual_slice(*slice) != B_TRUE) {
30590Sstevel@tonic-gate 		*slice = (dm_descriptor_t)0;
30600Sstevel@tonic-gate 	    }
30610Sstevel@tonic-gate 	}
30620Sstevel@tonic-gate 
30630Sstevel@tonic-gate 	return (0);
30640Sstevel@tonic-gate }
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate /*
30670Sstevel@tonic-gate  * FUNCTION:	extract_hbaname(char *name, char **hbaname)
30680Sstevel@tonic-gate  *
30690Sstevel@tonic-gate  * INPUT:	slicename - a char * device name
30700Sstevel@tonic-gate  *
30710Sstevel@tonic-gate  * OUTPUT:	hbaname - a pointer to a char * to hold the hbaname derived
30720Sstevel@tonic-gate  *			from the input name.
30730Sstevel@tonic-gate  *
30740Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
30750Sstevel@tonic-gate  *			 !0 otherwise.
30760Sstevel@tonic-gate  *
30770Sstevel@tonic-gate  * PURPOSE:	Helper which extracts the HBA name from the input name.
30780Sstevel@tonic-gate  *
30790Sstevel@tonic-gate  *		If the input name is in ctd form, extracts just the cX part,
30800Sstevel@tonic-gate  *		by truncating everything following the last 't'.
30810Sstevel@tonic-gate  *
30820Sstevel@tonic-gate  *		Of course on X86, with IDE drives, there is no 't' in the
30830Sstevel@tonic-gate  *		ctd name, so start by truncating everything following 'd'
30840Sstevel@tonic-gate  *		and then look for 't'.
30850Sstevel@tonic-gate  *
30860Sstevel@tonic-gate  * 		The returned string must be passed to free().
30870Sstevel@tonic-gate  */
30880Sstevel@tonic-gate int
extract_hbaname(char * name,char ** hbaname)30890Sstevel@tonic-gate extract_hbaname(
30900Sstevel@tonic-gate 	char	*name,
30910Sstevel@tonic-gate 	char	**hbaname)
30920Sstevel@tonic-gate {
30930Sstevel@tonic-gate 	char	*cp;
30940Sstevel@tonic-gate 
30950Sstevel@tonic-gate 	if (is_ctd_name(name)) {
30960Sstevel@tonic-gate 	    if ((*hbaname = strdup(name)) == NULL) {
30970Sstevel@tonic-gate 		return (ENOMEM);
30980Sstevel@tonic-gate 	    }
30990Sstevel@tonic-gate 	    if ((cp = strrchr(*hbaname, 'd')) != NULL) {
31000Sstevel@tonic-gate 		*cp = '\0';
31010Sstevel@tonic-gate 	    }
31020Sstevel@tonic-gate 	    if ((cp = strrchr(*hbaname, 't')) != NULL) {
31030Sstevel@tonic-gate 		*cp = '\0';
31040Sstevel@tonic-gate 	    }
31050Sstevel@tonic-gate 	}
31060Sstevel@tonic-gate 
31070Sstevel@tonic-gate 	return (0);
31080Sstevel@tonic-gate }
31090Sstevel@tonic-gate 
31100Sstevel@tonic-gate /*
31110Sstevel@tonic-gate  * FUNCTION:	extract_diskname(char *slicename, char **diskname)
31120Sstevel@tonic-gate  *
31130Sstevel@tonic-gate  * INPUT:	slicename - a char * slice name
31140Sstevel@tonic-gate  *
31150Sstevel@tonic-gate  * OUTPUT:	diskname - a pointer to a char * to hold the diskname derived
31160Sstevel@tonic-gate  *			from the input slicename.
31170Sstevel@tonic-gate  *
31180Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
31190Sstevel@tonic-gate  *			 !0 otherwise.
31200Sstevel@tonic-gate  *
31210Sstevel@tonic-gate  * PURPOSE:	Helper which extracts the disk's name from a slice name.
31220Sstevel@tonic-gate  *
31230Sstevel@tonic-gate  *		Checks to see if the input slicename is in ctd or did form,
31240Sstevel@tonic-gate  *		and if so, truncates everything following the last 's'.
31250Sstevel@tonic-gate  *
31260Sstevel@tonic-gate  *		If the input slicename is BSD-like, truncate the last
31270Sstevel@tonic-gate  *		character (a-h).
31280Sstevel@tonic-gate  *
31290Sstevel@tonic-gate  * 		The returned string must be passed to free().
31300Sstevel@tonic-gate  */
31310Sstevel@tonic-gate int
extract_diskname(char * slicename,char ** diskname)31320Sstevel@tonic-gate extract_diskname(
31330Sstevel@tonic-gate 	char	*slicename,
31340Sstevel@tonic-gate 	char	**diskname)
31350Sstevel@tonic-gate {
31360Sstevel@tonic-gate 	char	*cp;
31370Sstevel@tonic-gate 
31380Sstevel@tonic-gate 	if (is_ctd_slice_name(slicename) || is_did_slice_name(slicename) ||
31390Sstevel@tonic-gate 	    is_ctd_like_slice_name(slicename)) {
31400Sstevel@tonic-gate 
31410Sstevel@tonic-gate 	    if ((*diskname = strdup(slicename)) == NULL) {
31420Sstevel@tonic-gate 		return (ENOMEM);
31430Sstevel@tonic-gate 	    }
31440Sstevel@tonic-gate 	    if ((cp = strrchr(*diskname, 's')) != NULL) {
31450Sstevel@tonic-gate 		*cp = '\0';
31460Sstevel@tonic-gate 	    }
31470Sstevel@tonic-gate 
31480Sstevel@tonic-gate 	} else if (is_bsd_like_slice_name(slicename)) {
31490Sstevel@tonic-gate 
31500Sstevel@tonic-gate 	    if ((*diskname = strdup(slicename)) == NULL) {
31510Sstevel@tonic-gate 		return (ENOMEM);
31520Sstevel@tonic-gate 	    }
31530Sstevel@tonic-gate 	    (*diskname)[strlen((*diskname)-1)] = '\0';
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 	}
31560Sstevel@tonic-gate 
31570Sstevel@tonic-gate 	return (0);
31580Sstevel@tonic-gate }
31590Sstevel@tonic-gate 
31600Sstevel@tonic-gate /*
31610Sstevel@tonic-gate  * FUNCTION:	get_disk_for_named_slice(char *slicename,
31620Sstevel@tonic-gate  *			dm_descriptor_t disk)
31630Sstevel@tonic-gate  *
31640Sstevel@tonic-gate  * INPUT:	slicename - a char * slice name
31650Sstevel@tonic-gate  *
31660Sstevel@tonic-gate  * OUTPUT:	disk	- a pointer to a dm_descriptor_t to hold the
31670Sstevel@tonic-gate  *			disk corresponding to the input name, if found
31680Sstevel@tonic-gate  *
31690Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
31700Sstevel@tonic-gate  *			 !0 otherwise.
31710Sstevel@tonic-gate  *
31720Sstevel@tonic-gate  * PURPOSE:	Helper which locates the disk dm_descriptor_t handle for
31730Sstevel@tonic-gate  *		the input slice name.
31740Sstevel@tonic-gate  *
31750Sstevel@tonic-gate  *		If no disk matches the name, 0 is returned and the
31760Sstevel@tonic-gate  *		value of 'disk' will be (dm_descriptor_t)0;
31770Sstevel@tonic-gate  */
31780Sstevel@tonic-gate int
get_disk_for_named_slice(char * slicename,dm_descriptor_t * disk)31790Sstevel@tonic-gate get_disk_for_named_slice(
31800Sstevel@tonic-gate 	char		*slicename,
31810Sstevel@tonic-gate 	dm_descriptor_t *disk)
31820Sstevel@tonic-gate {
31830Sstevel@tonic-gate 	dm_descriptor_t slice = (dm_descriptor_t)0;
31840Sstevel@tonic-gate 	int		error = 0;
31850Sstevel@tonic-gate 
31860Sstevel@tonic-gate 	assert(slicename != NULL);
31870Sstevel@tonic-gate 
31880Sstevel@tonic-gate 	/* find disk for slice */
31890Sstevel@tonic-gate 	if ((error = slice_get_by_name(slicename, &slice)) == 0) {
31900Sstevel@tonic-gate 
31910Sstevel@tonic-gate 	    if (slice != (dm_descriptor_t)0) {
31920Sstevel@tonic-gate 		error = slice_get_disk(slice, disk);
31930Sstevel@tonic-gate 	    } else {
31940Sstevel@tonic-gate 		/* named slice was created by layout: */
31950Sstevel@tonic-gate 		/* need to find disk by name */
31960Sstevel@tonic-gate 		char *dname;
31970Sstevel@tonic-gate 
31980Sstevel@tonic-gate 		error = extract_diskname(slicename, &dname);
31990Sstevel@tonic-gate 		if (error == 0) {
32000Sstevel@tonic-gate 		    error = disk_get_by_name(dname, disk);
32010Sstevel@tonic-gate 		}
32020Sstevel@tonic-gate 		free(dname);
32030Sstevel@tonic-gate 	    }
32040Sstevel@tonic-gate 	}
32050Sstevel@tonic-gate 
32060Sstevel@tonic-gate 	assert(*disk != (dm_descriptor_t)0);
32070Sstevel@tonic-gate 
32080Sstevel@tonic-gate 	return (error);
32090Sstevel@tonic-gate }
32100Sstevel@tonic-gate 
32110Sstevel@tonic-gate /*
32120Sstevel@tonic-gate  * FUNCTION:	disk_get_reserved_indexes(dm_descriptor_t disk,
32130Sstevel@tonic-gate  *			uint16_t **array)
32140Sstevel@tonic-gate  *
32150Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t disk handle
32160Sstevel@tonic-gate  *
32170Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
32180Sstevel@tonic-gate  *			 !0 otherwise
32190Sstevel@tonic-gate  *
32200Sstevel@tonic-gate  * PURPOSE:	Retrieves the input disk's list of reserved slice indices.
32210Sstevel@tonic-gate  *
32220Sstevel@tonic-gate  *		The list of reserved indices is stored as an array in
32230Sstevel@tonic-gate  *		the disk's nvpair attribute list.
32240Sstevel@tonic-gate  */
32250Sstevel@tonic-gate static int
disk_get_reserved_indexes(dm_descriptor_t disk,uint16_t ** array)32260Sstevel@tonic-gate disk_get_reserved_indexes(
32270Sstevel@tonic-gate 	dm_descriptor_t	disk,
32280Sstevel@tonic-gate 	uint16_t	**array)
32290Sstevel@tonic-gate {
32300Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
32310Sstevel@tonic-gate 	uint_t		nelem = 0;
32320Sstevel@tonic-gate 	int		error = 0;
32330Sstevel@tonic-gate 
32340Sstevel@tonic-gate 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
32350Sstevel@tonic-gate 	    return (error);
32360Sstevel@tonic-gate 	}
32370Sstevel@tonic-gate 
32380Sstevel@tonic-gate 	if ((error = get_uint16_array(
32390Sstevel@tonic-gate 	    attrs, ATTR_RESERVED_INDEX, array, &nelem)) != 0) {
32400Sstevel@tonic-gate 	    if (error == ENOENT) {
32410Sstevel@tonic-gate 		/* no reserved indices yet */
32420Sstevel@tonic-gate 		error = 0;
32430Sstevel@tonic-gate 	    }
32440Sstevel@tonic-gate 	}
32450Sstevel@tonic-gate 
32460Sstevel@tonic-gate 	return (error);
32470Sstevel@tonic-gate }
32480Sstevel@tonic-gate 
32490Sstevel@tonic-gate /*
32500Sstevel@tonic-gate  * FUNCTION:	disk_reserve_index(dm_descriptor_t disk, uint16_t index)
32510Sstevel@tonic-gate  *
32520Sstevel@tonic-gate  * INPUT:	disk	- a disk dm_descirptor_t handle
32530Sstevel@tonic-gate  *		undex	- a VTOC slice index
32540Sstevel@tonic-gate  *
32550Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
32560Sstevel@tonic-gate  *			 !0 otherwise
32570Sstevel@tonic-gate  *
32580Sstevel@tonic-gate  * PURPOSE:	Reserves the input VTOC slice index for the input disk.
32590Sstevel@tonic-gate  *
32600Sstevel@tonic-gate  *		The list of reserved indices is stored as an array in
32610Sstevel@tonic-gate  *		the disk's nvpair attribute list.
32620Sstevel@tonic-gate  */
32630Sstevel@tonic-gate int
disk_reserve_index(dm_descriptor_t disk,uint16_t index)32640Sstevel@tonic-gate disk_reserve_index(
32650Sstevel@tonic-gate 	dm_descriptor_t	disk,
32660Sstevel@tonic-gate 	uint16_t	index)
32670Sstevel@tonic-gate {
32680Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
32690Sstevel@tonic-gate 	uint16_t	*oldindexes = NULL;
32700Sstevel@tonic-gate 	uint16_t	*newindexes = NULL;
32710Sstevel@tonic-gate 	uint_t		nelem = 0;
32720Sstevel@tonic-gate 	int		error = 0;
32730Sstevel@tonic-gate 	int		i = 0;
32740Sstevel@tonic-gate 
32750Sstevel@tonic-gate 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
32760Sstevel@tonic-gate 	    return (error);
32770Sstevel@tonic-gate 	}
32780Sstevel@tonic-gate 
32790Sstevel@tonic-gate 	if ((error = get_uint16_array(
32800Sstevel@tonic-gate 	    attrs, ATTR_RESERVED_INDEX, &oldindexes, &nelem)) != 0) {
32810Sstevel@tonic-gate 	    if (error != ENOENT) {
32820Sstevel@tonic-gate 		return (error);
32830Sstevel@tonic-gate 	    }
32840Sstevel@tonic-gate 	    /* no reserved indices yet */
32850Sstevel@tonic-gate 	    error = 0;
32860Sstevel@tonic-gate 	}
32870Sstevel@tonic-gate 
32880Sstevel@tonic-gate 	/* add new index */
32890Sstevel@tonic-gate 	newindexes = (uint16_t *)calloc(VTOC_SIZE, sizeof (uint16_t));
32900Sstevel@tonic-gate 	if (newindexes != NULL) {
32910Sstevel@tonic-gate 	    for (i = 0; i < nelem; i++) {
32920Sstevel@tonic-gate 		newindexes[i] = oldindexes[i];
32930Sstevel@tonic-gate 	    }
32940Sstevel@tonic-gate 	    newindexes[(int)index] = 1;
32950Sstevel@tonic-gate 
32960Sstevel@tonic-gate 	    error = set_uint16_array(attrs, ATTR_RESERVED_INDEX,
32970Sstevel@tonic-gate 		    newindexes, VTOC_SIZE);
32980Sstevel@tonic-gate 
32990Sstevel@tonic-gate 	    free(newindexes);
33000Sstevel@tonic-gate 	} else {
33010Sstevel@tonic-gate 	    error = ENOMEM;
33020Sstevel@tonic-gate 	}
33030Sstevel@tonic-gate 	return (error);
33040Sstevel@tonic-gate }
33050Sstevel@tonic-gate 
33060Sstevel@tonic-gate /*
33070Sstevel@tonic-gate  * FUNCTION:	disk_release_index(dm_descriptor_t disk, uint16_t index)
33080Sstevel@tonic-gate  *
33090Sstevel@tonic-gate  * INPUT:	disk	- a disk dm_descirptor_t handle
33100Sstevel@tonic-gate  *		undex	- a VTOC slice index
33110Sstevel@tonic-gate  *
33120Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
33130Sstevel@tonic-gate  *			 !0 otherwise
33140Sstevel@tonic-gate  *
33150Sstevel@tonic-gate  * PURPOSE:	Releases the input VTOC slice index for the input disk.
33160Sstevel@tonic-gate  *		The index was previously reserved by disk_reserve_index()
33170Sstevel@tonic-gate  */
33180Sstevel@tonic-gate int
disk_release_index(dm_descriptor_t disk,uint16_t index)33190Sstevel@tonic-gate disk_release_index(
33200Sstevel@tonic-gate 	dm_descriptor_t	disk,
33210Sstevel@tonic-gate 	uint16_t	index)
33220Sstevel@tonic-gate {
33230Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
33240Sstevel@tonic-gate 	uint16_t	*oldindexes = NULL;
33250Sstevel@tonic-gate 	uint16_t	*newindexes = NULL;
33260Sstevel@tonic-gate 	uint_t		nelem = 0;
33270Sstevel@tonic-gate 	int		error = 0;
33280Sstevel@tonic-gate 	int		i = 0;
33290Sstevel@tonic-gate 
33300Sstevel@tonic-gate 	if ((error = get_cached_attributes(disk, &attrs)) != 0) {
33310Sstevel@tonic-gate 	    return (error);
33320Sstevel@tonic-gate 	}
33330Sstevel@tonic-gate 
33340Sstevel@tonic-gate 	if ((error = get_uint16_array(
33350Sstevel@tonic-gate 	    attrs, ATTR_RESERVED_INDEX, &oldindexes, &nelem)) != 0) {
33360Sstevel@tonic-gate 	    if (error != ENOENT) {
33370Sstevel@tonic-gate 		return (error);
33380Sstevel@tonic-gate 	    }
33390Sstevel@tonic-gate 	    error = 0;
33400Sstevel@tonic-gate 	}
33410Sstevel@tonic-gate 
33420Sstevel@tonic-gate 	newindexes = (uint16_t *)calloc(VTOC_SIZE, sizeof (uint16_t));
33430Sstevel@tonic-gate 	if (newindexes != NULL) {
33440Sstevel@tonic-gate 	    for (i = 0; i < nelem; i++) {
33450Sstevel@tonic-gate 		newindexes[i] = oldindexes[i];
33460Sstevel@tonic-gate 	    }
33470Sstevel@tonic-gate 
33480Sstevel@tonic-gate 	    /* release index */
33490Sstevel@tonic-gate 	    newindexes[(int)index] = 0;
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate 	    error = set_uint16_array(attrs, ATTR_RESERVED_INDEX,
33520Sstevel@tonic-gate 		    newindexes, VTOC_SIZE);
33530Sstevel@tonic-gate 
33540Sstevel@tonic-gate 	    free(newindexes);
33550Sstevel@tonic-gate 	} else {
33560Sstevel@tonic-gate 	    error = ENOMEM;
33570Sstevel@tonic-gate 	}
33580Sstevel@tonic-gate 
33590Sstevel@tonic-gate 	return (error);
33600Sstevel@tonic-gate }
33610Sstevel@tonic-gate 
33620Sstevel@tonic-gate /*
33630Sstevel@tonic-gate  * FUNCTION:	print_get_assoc_desc_error(dm_descriptor_t desc, char *which,
33640Sstevel@tonic-gate  *			int error)
33650Sstevel@tonic-gate  *
33660Sstevel@tonic-gate  * INPUT:	desc	- a dm_descriptor_t handle
33670Sstevel@tonic-gate  *		which	- a char * indicating which association
33680Sstevel@tonic-gate  *		error	- an integer error value
33690Sstevel@tonic-gate  *
33700Sstevel@tonic-gate  * PURPOSE:	Utility function to print an error message for a failed
33710Sstevel@tonic-gate  *		call to dm_get_associated_descriptors().
33720Sstevel@tonic-gate  *
33730Sstevel@tonic-gate  *		Extracts the device's CTD name and formats an error message.
33740Sstevel@tonic-gate  */
33750Sstevel@tonic-gate void
print_get_assoc_desc_error(dm_descriptor_t desc,char * which,int error)33760Sstevel@tonic-gate print_get_assoc_desc_error(
33770Sstevel@tonic-gate 	dm_descriptor_t desc,
33780Sstevel@tonic-gate 	char		*which,
33790Sstevel@tonic-gate 	int		error)
33800Sstevel@tonic-gate {
33810Sstevel@tonic-gate 	char *name = "";
33820Sstevel@tonic-gate 
33830Sstevel@tonic-gate 	(void) get_display_name(desc, &name);
33840Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
33850Sstevel@tonic-gate 		gettext("dm_get_associated_descriptors(%s) for "
33860Sstevel@tonic-gate 			"'%s' failed: %d\n"),
33870Sstevel@tonic-gate 		which, name, error);
33880Sstevel@tonic-gate 
33890Sstevel@tonic-gate 	volume_set_error(
33900Sstevel@tonic-gate 		gettext("Unexpected error getting associated "
33910Sstevel@tonic-gate 			"descriptors for '%s'"),
33920Sstevel@tonic-gate 			name);
33930Sstevel@tonic-gate }
33940Sstevel@tonic-gate 
33950Sstevel@tonic-gate /*
33960Sstevel@tonic-gate  * FUNCTION:	print_get_desc_attr_error(dm_descriptor_t desc,
33970Sstevel@tonic-gate  *			char *devtype, char *attr, int error)
33980Sstevel@tonic-gate  *
33990Sstevel@tonic-gate  * INPUT:	desc	- a dm_descriptor_t handle
34000Sstevel@tonic-gate  *		devtype	- a char * device type that's being accessed
34010Sstevel@tonic-gate  *		attr	- a char * attribute name
34020Sstevel@tonic-gate  *		error	- an integer error value
34030Sstevel@tonic-gate  *
34040Sstevel@tonic-gate  * PURPOSE:	Shared utility function to print an error message for a failed
34050Sstevel@tonic-gate  *		call to retrieve an attribute for a descriptor.
34060Sstevel@tonic-gate  *
34070Sstevel@tonic-gate  *		Extracts the device's CTD name and formats an error message.
34080Sstevel@tonic-gate  */
34090Sstevel@tonic-gate void
print_get_desc_attr_error(dm_descriptor_t desc,char * devtype,char * attr,int error)34100Sstevel@tonic-gate print_get_desc_attr_error(
34110Sstevel@tonic-gate 	dm_descriptor_t desc,
34120Sstevel@tonic-gate 	char		*devtype,
34130Sstevel@tonic-gate 	char		*attr,
34140Sstevel@tonic-gate 	int		error)
34150Sstevel@tonic-gate {
34160Sstevel@tonic-gate 	char *name = "";
34170Sstevel@tonic-gate 
34180Sstevel@tonic-gate 	(void) get_display_name(desc, &name);
34190Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
34200Sstevel@tonic-gate 		gettext("'%s' get attribute (%s.%s) error: %d\n"),
34210Sstevel@tonic-gate 		name, devtype, attr, error);
34220Sstevel@tonic-gate 
34230Sstevel@tonic-gate 	volume_set_error(
34240Sstevel@tonic-gate 		gettext("Unexpected error getting attribute '%s.%s' for '%s'"),
34250Sstevel@tonic-gate 			devtype, attr, name);
34260Sstevel@tonic-gate }
34270Sstevel@tonic-gate 
34280Sstevel@tonic-gate /*
34290Sstevel@tonic-gate  * FUNCTION:	print_set_desc_attr_error(dm_descriptor_t desc,
34300Sstevel@tonic-gate  *			char *devtype, char *attr, int error)
34310Sstevel@tonic-gate  *
34320Sstevel@tonic-gate  * INPUT:	desc	- a dm_descriptor_t handle
34330Sstevel@tonic-gate  *		devtype	- a char * device type that's being accessed
34340Sstevel@tonic-gate  *		attr	- a char * attribute name
34350Sstevel@tonic-gate  *		error	- an integer error value
34360Sstevel@tonic-gate  *
34370Sstevel@tonic-gate  * PURPOSE:	Shared utility function to print an error message for a failed
34380Sstevel@tonic-gate  *		call to set an attribute for a descriptor.
34390Sstevel@tonic-gate  *
34400Sstevel@tonic-gate  *		Extracts the device's CTD name and formats an error message.
34410Sstevel@tonic-gate  */
34420Sstevel@tonic-gate void
print_set_desc_attr_error(dm_descriptor_t desc,char * devtype,char * attr,int error)34430Sstevel@tonic-gate print_set_desc_attr_error(
34440Sstevel@tonic-gate 	dm_descriptor_t desc,
34450Sstevel@tonic-gate 	char		*devtype,
34460Sstevel@tonic-gate 	char		*attr,
34470Sstevel@tonic-gate 	int		error)
34480Sstevel@tonic-gate {
34490Sstevel@tonic-gate 	char *name = "";
34500Sstevel@tonic-gate 
34510Sstevel@tonic-gate 	(void) get_display_name(desc, &name);
34520Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
34530Sstevel@tonic-gate 		gettext("'%s' set attribute (%s.%s) error: %d\n"),
34540Sstevel@tonic-gate 		name, devtype, attr, error);
34550Sstevel@tonic-gate 
34560Sstevel@tonic-gate 	volume_set_error(
34570Sstevel@tonic-gate 		gettext("Unexpected error setting attribute '%s.%s' for '%s'"),
34580Sstevel@tonic-gate 			devtype, attr, name);
34590Sstevel@tonic-gate }
3460