xref: /onnv-gate/usr/src/cmd/lvm/metassist/layout/layout_discovery.c (revision 62:5e51ad5d0496)
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 <limits.h>
300Sstevel@tonic-gate #include <libdiskmgt.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <meta.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #define	_LAYOUT_DISCOVERY_C
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include "volume_dlist.h"
380Sstevel@tonic-gate #include "volume_error.h"
390Sstevel@tonic-gate #include "volume_nvpair.h"
400Sstevel@tonic-gate #include "volume_output.h"
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include "layout_device_cache.h"
430Sstevel@tonic-gate #include "layout_device_util.h"
440Sstevel@tonic-gate #include "layout_dlist_util.h"
450Sstevel@tonic-gate #include "layout_discovery.h"
460Sstevel@tonic-gate #include "layout_request.h"
470Sstevel@tonic-gate #include "layout_slice.h"
480Sstevel@tonic-gate #include "layout_svm_util.h"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * lists of device dm_descriptor_t handles discovered during
520Sstevel@tonic-gate  * the initial system probe.  Lists are populated by
530Sstevel@tonic-gate  * discover_known_devices.
540Sstevel@tonic-gate  *
550Sstevel@tonic-gate  * "bad" slices are those that are known to libdiskmgt but
560Sstevel@tonic-gate  * cannot be accessed. An example would be a slice that has
570Sstevel@tonic-gate  * disappeared due to disk re-slicing: libdiskmgt may have a
580Sstevel@tonic-gate  * cached handle for it, but the slice no longer exists.
590Sstevel@tonic-gate  *
600Sstevel@tonic-gate  * "bad" disks are thoese that are known to libdiskmgt but
610Sstevel@tonic-gate  * cannot be accessed.  An example would be a disk that has
620Sstevel@tonic-gate  * failed or has gone offline: libdiskmgt may have a cached
630Sstevel@tonic-gate  * handle for it, but the disk does not respond.
640Sstevel@tonic-gate  */
650Sstevel@tonic-gate static dlist_t	*_bad_slices = NULL;
660Sstevel@tonic-gate static dlist_t	*_bad_disks = NULL;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate static dlist_t	*_known_slices = NULL;
690Sstevel@tonic-gate static dlist_t	*_known_disks = NULL;
700Sstevel@tonic-gate static dlist_t	*_known_hbas = NULL;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * helper functions for building known device lists, used by
740Sstevel@tonic-gate  * discover_known_devices.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate static int generate_known_slices(dlist_t *disks, dlist_t **known,
770Sstevel@tonic-gate 	dlist_t **bad);
780Sstevel@tonic-gate static int generate_known_disks(dlist_t **known, dlist_t **bad);
790Sstevel@tonic-gate static int generate_known_hbas(dlist_t *disks, dlist_t **known);
800Sstevel@tonic-gate static int generate_known_hba_name(
810Sstevel@tonic-gate 	dm_descriptor_t hba,
820Sstevel@tonic-gate 	dm_descriptor_t	alias,
830Sstevel@tonic-gate 	dm_descriptor_t disk);
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static void print_known_devices();
860Sstevel@tonic-gate static void print_device_list(dlist_t *devices);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate  * lists of device dm_descriptor_t handles that are usable by layout.
900Sstevel@tonic-gate  * These devices must still pass the user specified available/unavailable
910Sstevel@tonic-gate  * filter before they're actually considered available.
920Sstevel@tonic-gate  *
930Sstevel@tonic-gate  * Lists are populated by discover_usable_devices.
940Sstevel@tonic-gate  */
950Sstevel@tonic-gate static dlist_t	*_usable_slices = NULL;
960Sstevel@tonic-gate static dlist_t	*_usable_disks = NULL;
970Sstevel@tonic-gate static dlist_t	*_usable_hbas = NULL;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * private flag that remembers if any HBA is known to support MPXIO
1010Sstevel@tonic-gate  */
1020Sstevel@tonic-gate static boolean_t _mpxio_enabled = B_FALSE;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * The slice_class struct is used to group slices by usage class.
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate typedef struct {
1080Sstevel@tonic-gate 	char	*usage;		/* usage description */
1090Sstevel@tonic-gate 	dlist_t	*sliceinfo;	/* list with info about each slice with usage */
1100Sstevel@tonic-gate } slice_class_t;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate #define	USE_DISKSET	"diskset"
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate static int check_slice_usage(
1150Sstevel@tonic-gate 	char		*dsname,
1160Sstevel@tonic-gate 	dm_descriptor_t slice,
1170Sstevel@tonic-gate 	dm_descriptor_t disk,
1180Sstevel@tonic-gate 	boolean_t	*avail,
1190Sstevel@tonic-gate 	dlist_t		**bad,
1200Sstevel@tonic-gate 	dlist_t		**classes);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static int check_svm_slice_usage(
1230Sstevel@tonic-gate 	char		*dsname,
1240Sstevel@tonic-gate 	dm_descriptor_t slice,
1250Sstevel@tonic-gate 	dm_descriptor_t disk,
1260Sstevel@tonic-gate 	boolean_t	*avail,
1270Sstevel@tonic-gate 	dlist_t		**classes);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static int save_slice_classification(
1300Sstevel@tonic-gate 	char		*dsname,
1310Sstevel@tonic-gate 	dm_descriptor_t slice,
1320Sstevel@tonic-gate 	dm_descriptor_t disk,
1330Sstevel@tonic-gate 	char		*usage,
1340Sstevel@tonic-gate 	char		*usage_detail,
1350Sstevel@tonic-gate 	dlist_t		**classes);
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate static int generate_usable_disks_and_slices_in_local_set(
1380Sstevel@tonic-gate 	dlist_t		**classes,
1390Sstevel@tonic-gate 	dlist_t		**bad_disks,
1400Sstevel@tonic-gate 	dlist_t		**usable_disks,
1410Sstevel@tonic-gate 	dlist_t		**usable_slices);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate static int generate_usable_disks_and_slices_in_named_set(
1440Sstevel@tonic-gate 	char		*dsname,
1450Sstevel@tonic-gate 	dlist_t		**classes,
1460Sstevel@tonic-gate 	dlist_t		**bad_slices,
1470Sstevel@tonic-gate 	dlist_t		**usable_disks,
1480Sstevel@tonic-gate 	dlist_t		**usable_slices);
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate static int create_usable_slices(
1510Sstevel@tonic-gate 	dm_descriptor_t disk,
1520Sstevel@tonic-gate 	dlist_t		*used,
1530Sstevel@tonic-gate 	dlist_t		*unused,
1540Sstevel@tonic-gate 	dlist_t 	**usable);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate static int add_new_usable(
1570Sstevel@tonic-gate 	dm_descriptor_t disk,
1580Sstevel@tonic-gate 	uint64_t	stblk,
1590Sstevel@tonic-gate 	uint64_t	nblks,
1600Sstevel@tonic-gate 	dlist_t		**next_unused,
1610Sstevel@tonic-gate 	dlist_t		**usable);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate static int update_slice_attributes(
1640Sstevel@tonic-gate 	dm_descriptor_t slice,
1650Sstevel@tonic-gate 	uint64_t	stblk,
1660Sstevel@tonic-gate 	uint64_t	nblks,
1670Sstevel@tonic-gate 	uint64_t	nbytes);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate static int generate_usable_hbas(
1700Sstevel@tonic-gate 	dlist_t		*disks,
1710Sstevel@tonic-gate 	dlist_t		**usable);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate static void print_usable_devices();
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate static void print_unusable_devices(
1760Sstevel@tonic-gate 	dlist_t		*badslices,
1770Sstevel@tonic-gate 	dlist_t		*baddisks,
1780Sstevel@tonic-gate 	dlist_t		*usedslices);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate static char *get_slice_usage_msg(
1810Sstevel@tonic-gate 	char		*usage);
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate  * virtual slices...
1850Sstevel@tonic-gate  */
1860Sstevel@tonic-gate static int generate_virtual_slices(
1870Sstevel@tonic-gate 	dlist_t 	*avail_disks_local_set,
1880Sstevel@tonic-gate 	dlist_t		**usable);
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate  * multipathed disks have aliases, as do slices on those disks.
1920Sstevel@tonic-gate  * these need to be tracked since the user may specify them.
1930Sstevel@tonic-gate  * A multi-pathed disk is one connected to the system thru
1940Sstevel@tonic-gate  * more than one physical HBA, each connection gets a distinct
1950Sstevel@tonic-gate  * name in the device tree and they're all more or less equivalent.
1960Sstevel@tonic-gate  * No indication as to how many possible physical connections a
1970Sstevel@tonic-gate  * disk may have, so we pick an arbitrary number of aliases to
1980Sstevel@tonic-gate  * support. There is nothing significant about this number,
1990Sstevel@tonic-gate  * it just controls the number of alias slots that get allocated.
2000Sstevel@tonic-gate  */
2010Sstevel@tonic-gate #define	MAX_ALIASES	8
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate  * attribute name for layout private information stored in
2050Sstevel@tonic-gate  * device nvpair attribute lists.
2060Sstevel@tonic-gate  */
2070Sstevel@tonic-gate static char *ATTR_DEVICE_ALIASES = "layout_device_aliases";
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate static int compare_start_blocks(
2100Sstevel@tonic-gate 	void *desc1, void *desc2);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate static int compare_desc_display_names(
2130Sstevel@tonic-gate 	void *desc1, void *desc2);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate /*
2160Sstevel@tonic-gate  * FUNCTION:	is_mpxio_enabled()
2170Sstevel@tonic-gate  *
2180Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE - if MPXIO appears enabled for the system
2190Sstevel@tonic-gate  *			    B_FALSE - otherwise
2200Sstevel@tonic-gate  *
2210Sstevel@tonic-gate  * PURPOSE:	returns the value of _mpxio_enabled which is set to B_TRUE
2220Sstevel@tonic-gate  *		during system configuration discovery if any of the knwon
2230Sstevel@tonic-gate  *		HBAs advertises itself as a "multiplex" controller.
2240Sstevel@tonic-gate  */
2250Sstevel@tonic-gate boolean_t
is_mpxio_enabled()2260Sstevel@tonic-gate is_mpxio_enabled()
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate 	return (_mpxio_enabled);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate  * FUNCTION:	discover_known_devices()
2330Sstevel@tonic-gate  *
2340Sstevel@tonic-gate  * SIDEEFFECT:	populates the module private lists of known devices
2350Sstevel@tonic-gate  *		(_known_slices, _known_disks, _known_hbas).
2360Sstevel@tonic-gate  *
2370Sstevel@tonic-gate  *		All known devices will also have had their CTD
2380Sstevel@tonic-gate  *		short names inferred and stored.
2390Sstevel@tonic-gate  *
2400Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2410Sstevel@tonic-gate  *			 !0 otherwise
2420Sstevel@tonic-gate  *
2430Sstevel@tonic-gate  * PURPOSE:	Load physical devices discovered thru libdiskmgt.
2440Sstevel@tonic-gate  */
2450Sstevel@tonic-gate int
discover_known_devices()2460Sstevel@tonic-gate discover_known_devices()
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate 	int	error = 0;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
2510Sstevel@tonic-gate 		gettext("\nScanning system physical "
2520Sstevel@tonic-gate 			"device configuration...\n"));
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	/* initialize layout_device_cache */
2550Sstevel@tonic-gate 	((error = create_device_caches()) != 0) ||
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	(error = generate_known_disks(&_known_disks, &_bad_disks)) ||
2580Sstevel@tonic-gate 	(error = generate_known_slices(_known_disks, &_known_slices,
2590Sstevel@tonic-gate 		&_bad_slices)) ||
2600Sstevel@tonic-gate 	(error = generate_known_hbas(_known_disks, &_known_hbas));
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	if (error == 0) {
2630Sstevel@tonic-gate 	    print_known_devices();
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	return (error);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate  * FUNCTION:	release_known_devices()
2710Sstevel@tonic-gate  *
2720Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2730Sstevel@tonic-gate  *			 !0 otherwise
2740Sstevel@tonic-gate  *
2750Sstevel@tonic-gate  * PURPOSE:	Unloads all state currently held for known
2760Sstevel@tonic-gate  *		physical devices.
2770Sstevel@tonic-gate  */
2780Sstevel@tonic-gate int
release_known_devices(char * diskset)2790Sstevel@tonic-gate release_known_devices(
2800Sstevel@tonic-gate 	char	*diskset)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	/* these lists are module private */
2830Sstevel@tonic-gate 	dlist_free_items(_bad_slices, NULL);
2840Sstevel@tonic-gate 	dlist_free_items(_bad_disks, NULL);
2850Sstevel@tonic-gate 	dlist_free_items(_known_slices, NULL);
2860Sstevel@tonic-gate 	dlist_free_items(_known_disks, NULL);
2870Sstevel@tonic-gate 	dlist_free_items(_known_hbas, NULL);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	_bad_slices = NULL;
2900Sstevel@tonic-gate 	_bad_disks = NULL;
2910Sstevel@tonic-gate 	_known_slices = NULL;
2920Sstevel@tonic-gate 	_known_disks = NULL;
2930Sstevel@tonic-gate 	_known_hbas = NULL;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	/* clean up state kept in layout_device_cache */
2960Sstevel@tonic-gate 	release_device_caches();
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	return (0);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate /*
3020Sstevel@tonic-gate  * FUNCTION:	discover_usable_devices(char *diskset)
3030Sstevel@tonic-gate  *
3040Sstevel@tonic-gate  * INPUT:	diskset	- a char * diskset name.
3050Sstevel@tonic-gate  *
3060Sstevel@tonic-gate  * SIDEEFFECT:	Traverses the lists of known devices and populates the
3070Sstevel@tonic-gate  *		module private lists of usable devices (_usable_slices,
3080Sstevel@tonic-gate  *		_usable_disks, _usable_hbas), as well as the module
3090Sstevel@tonic-gate  *		private list of used slices.
3100Sstevel@tonic-gate  *
3110Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
3120Sstevel@tonic-gate  *			 !0 otherwise
3130Sstevel@tonic-gate  *
3140Sstevel@tonic-gate  * PURPOSE:	Process the known devices and determine which of them are
3150Sstevel@tonic-gate  *		usable for generating volumes in the specified diskset.
3160Sstevel@tonic-gate  *
3170Sstevel@tonic-gate  *		The specified diskset's name cannot be NULL or 0 length.
3180Sstevel@tonic-gate  */
3190Sstevel@tonic-gate int
discover_usable_devices(char * diskset)3200Sstevel@tonic-gate discover_usable_devices(
3210Sstevel@tonic-gate 	char	*diskset)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 	int	error = 0;
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	dlist_t *used_classes = NULL;
3260Sstevel@tonic-gate 	dlist_t *iter = NULL;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if (diskset == NULL || diskset[0] == '\0') {
3290Sstevel@tonic-gate 	    volume_set_error(
3300Sstevel@tonic-gate 		    gettext("a diskset name must be specified in "
3310Sstevel@tonic-gate 			    "the request\n"));
3320Sstevel@tonic-gate 	    return (-1);
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
3360Sstevel@tonic-gate 		gettext("\nDetermining usable physical devices "
3370Sstevel@tonic-gate 			"for disk set \"%s\"...\n"),
3380Sstevel@tonic-gate 		diskset);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	error = generate_usable_disks_and_slices_in_local_set(
3410Sstevel@tonic-gate 	    &used_classes, &_bad_slices, &_usable_disks, &_usable_slices);
3420Sstevel@tonic-gate 	if (error == 0) {
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	    error = generate_usable_disks_and_slices_in_named_set(
3450Sstevel@tonic-gate 		diskset, &used_classes, &_bad_slices, &_usable_disks,
3460Sstevel@tonic-gate 		&_usable_slices);
3470Sstevel@tonic-gate 	    if (error == 0) {
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		error = generate_usable_hbas(_usable_disks, &_usable_hbas);
3500Sstevel@tonic-gate 		if (error == 0) {
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		    print_usable_devices();
3530Sstevel@tonic-gate 		    print_unusable_devices(
3540Sstevel@tonic-gate 			_bad_slices, _bad_disks, used_classes);
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 	    }
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/*
3600Sstevel@tonic-gate 	 * free slice classification usage and lists, items are char*
3610Sstevel@tonic-gate 	 * the used_classes structure is only filled in if verbose
3620Sstevel@tonic-gate 	 * output was requested.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	for (iter = used_classes; iter != NULL; iter = iter->next) {
3650Sstevel@tonic-gate 	    slice_class_t *class = (slice_class_t *)iter->obj;
3660Sstevel@tonic-gate 	    free(class->usage);
3670Sstevel@tonic-gate 	    dlist_free_items(class->sliceinfo, free);
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	dlist_free_items(used_classes, free);
3710Sstevel@tonic-gate 	return (error);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate  * FUNCTION:	release_usable_devices()
3760Sstevel@tonic-gate  *
3770Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
3780Sstevel@tonic-gate  *			 !0 otherwise
3790Sstevel@tonic-gate  *
3800Sstevel@tonic-gate  * PURPOSE:	Unloads all state currently held for usable
3810Sstevel@tonic-gate  *		physical devices.
3820Sstevel@tonic-gate  */
3830Sstevel@tonic-gate int
release_usable_devices()3840Sstevel@tonic-gate release_usable_devices()
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate 	/* list items are shared with _known_XXX lists */
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	dlist_free_items(_usable_slices, NULL);
3890Sstevel@tonic-gate 	dlist_free_items(_usable_disks, NULL);
3900Sstevel@tonic-gate 	dlist_free_items(_usable_hbas, NULL);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	_usable_slices = NULL;
3930Sstevel@tonic-gate 	_usable_disks = NULL;
3940Sstevel@tonic-gate 	_usable_hbas = NULL;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/* clean up state kept in layout_device_util */
3970Sstevel@tonic-gate 	release_virtual_slices();
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	return (0);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate  * FUNCTION:	get_known_slices(dlist_t **list)
4040Sstevel@tonic-gate  *		get_known_disks(dlist_t **list)
4050Sstevel@tonic-gate  *		get_known_hbas(dlist_t **list)
4060Sstevel@tonic-gate  *
4070Sstevel@tonic-gate  * OUTPUT:	list	- a dlist_t pointer to hold the returned list of
4080Sstevel@tonic-gate  *			devices.
4090Sstevel@tonic-gate  *
4100Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
4110Sstevel@tonic-gate  *			 !0 otherwise
4120Sstevel@tonic-gate  *
4130Sstevel@tonic-gate  * PURPOSE:	Public accessors for the module private lists of
4140Sstevel@tonic-gate  *		available devices.
4150Sstevel@tonic-gate  */
4160Sstevel@tonic-gate int
get_known_slices(dlist_t ** list)4170Sstevel@tonic-gate get_known_slices(
4180Sstevel@tonic-gate 	dlist_t **list)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate 	*list = _known_slices;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	return (0);
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate int
get_known_disks(dlist_t ** list)4260Sstevel@tonic-gate get_known_disks(
4270Sstevel@tonic-gate 	dlist_t **list)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	*list = _known_disks;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	return (0);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate int
get_known_hbas(dlist_t ** list)4350Sstevel@tonic-gate get_known_hbas(
4360Sstevel@tonic-gate 	dlist_t **list)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate 	*list = _known_hbas;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	return (0);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate /* make fully qualified DID device name */
4440Sstevel@tonic-gate static char *
make_fully_qualified_did_device_name(char * device)4450Sstevel@tonic-gate make_fully_qualified_did_device_name(
4460Sstevel@tonic-gate 	char	*device)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	static char	buf[MAXPATHLEN];
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	if (device != NULL && strrchr(device, '/') == NULL) {
4510Sstevel@tonic-gate 	    (void) snprintf(buf, MAXPATHLEN-1, "%s/%s",
4520Sstevel@tonic-gate 		    "/dev/did/dsk", device);
4530Sstevel@tonic-gate 	    return (buf);
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	return (device);
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate /*
4600Sstevel@tonic-gate  * FUNCTION:	generate_known_disks(dlist_t **known,
4610Sstevel@tonic-gate  *			dlist_t **bad)
4620Sstevel@tonic-gate  *
4630Sstevel@tonic-gate  * INPUT:	NONE
4640Sstevel@tonic-gate  *
4650Sstevel@tonic-gate  * OUTPUT:	known	- populated list of known disks
4660Sstevel@tonic-gate  *		bad	- populated list of known bad disks
4670Sstevel@tonic-gate  *
4680Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
4690Sstevel@tonic-gate  *			 !0 otherwise
4700Sstevel@tonic-gate  *
4710Sstevel@tonic-gate  * PURPOSE:	Does the system configuration discovery to determine
4720Sstevel@tonic-gate  *		what disks are known to be attached to the system.
4730Sstevel@tonic-gate  *
4740Sstevel@tonic-gate  *		Determines the CTD name for each disk and saves it.
4750Sstevel@tonic-gate  */
4760Sstevel@tonic-gate static int
generate_known_disks(dlist_t ** known,dlist_t ** bad)4770Sstevel@tonic-gate generate_known_disks(
4780Sstevel@tonic-gate 	dlist_t	**known,
4790Sstevel@tonic-gate 	dlist_t **bad)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	int	i;
4820Sstevel@tonic-gate 	int	error = 0;
4830Sstevel@tonic-gate 	dm_descriptor_t	*ddp;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	ddp = dm_get_descriptors(DM_DRIVE, NULL, &error);
4860Sstevel@tonic-gate 	(void) add_descriptors_to_free(ddp);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	*known = NULL;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	if (error != 0) {
4910Sstevel@tonic-gate 	    volume_set_error(
4920Sstevel@tonic-gate 		    gettext("Error discovering system hardware configuration,\n"
4930Sstevel@tonic-gate 		    "unable to communicate with libdiskmgt or diskmgtd.\n"));
4940Sstevel@tonic-gate 	    return (-1);
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	if ((ddp == NULL) || (ddp[0] == NULL)) {
4980Sstevel@tonic-gate 	    volume_set_error(gettext("there are no known disks\n"));
4990Sstevel@tonic-gate 	    return (-1);
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	/* iterate all returned disks and add them to the known list */
5030Sstevel@tonic-gate 	for (i = 0; (ddp[i] != NULL) && (error == 0); i++) {
5040Sstevel@tonic-gate 	    dm_descriptor_t disk = (dm_descriptor_t)ddp[i];
5050Sstevel@tonic-gate 	    dlist_t *aliases = NULL;
5060Sstevel@tonic-gate 	    uint32_t mtype = DM_MT_UNKNOWN;
5070Sstevel@tonic-gate 	    uint32_t dtype = DM_DT_UNKNOWN;
5080Sstevel@tonic-gate 	    boolean_t bad_disk = B_FALSE;
5090Sstevel@tonic-gate 	    boolean_t online = B_TRUE;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate #if defined(i386)
5120Sstevel@tonic-gate 	    /* on X86, disks must have a solaris FDISK partition */
5130Sstevel@tonic-gate 	    boolean_t solpart = B_FALSE;
5140Sstevel@tonic-gate #endif	/* defined(i386) */
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	    if (((error = disk_get_is_online(disk, &online)) == 0 &&
5170Sstevel@tonic-gate 		online == B_FALSE) || error == ENODEV) {
5180Sstevel@tonic-gate 		/* if the disk is offline, report it as bad */
5190Sstevel@tonic-gate 		bad_disk = B_TRUE;
5200Sstevel@tonic-gate 		error = 0;
5210Sstevel@tonic-gate 	    } else
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	    if (error == 0 &&
5240Sstevel@tonic-gate 		(((error = disk_get_media_type(disk, &mtype)) != 0) ||
5250Sstevel@tonic-gate 		((error = disk_get_drive_type(disk, &dtype)) != 0)) &&
5260Sstevel@tonic-gate 		error == ENODEV) {
5270Sstevel@tonic-gate 		/*
5280Sstevel@tonic-gate 		 * if any disk attribute access fails with ENODEV
5290Sstevel@tonic-gate 		 * report it as bad
5300Sstevel@tonic-gate 		 */
5310Sstevel@tonic-gate 		bad_disk = B_TRUE;
5320Sstevel@tonic-gate 		error = 0;
5330Sstevel@tonic-gate 	    } else {
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 		/*
5360Sstevel@tonic-gate 		 * Determine whether disk is fixed by checking its
5370Sstevel@tonic-gate 		 * drive type.  If drive type is unknown, check media
5380Sstevel@tonic-gate 		 * type.
5390Sstevel@tonic-gate 		 */
5400Sstevel@tonic-gate 		int isfixed = (dtype == DM_DT_FIXED ||
5410Sstevel@tonic-gate 		    (dtype == DM_DT_UNKNOWN && mtype == DM_MT_FIXED));
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 		if (!isfixed) {
5440Sstevel@tonic-gate 		    continue;  /* ignore non-fixed disks */
5450Sstevel@tonic-gate 		}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate #if defined(i386)
5480Sstevel@tonic-gate 		if (((error = disk_get_has_solaris_partition(disk,
5490Sstevel@tonic-gate 		    &solpart)) != 0) || (solpart != B_TRUE)) {
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 		    /* X86 drive has no solaris partition, report as bad */
5520Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
5530Sstevel@tonic-gate 			    gettext("%s has no solaris FDISK partition.\n"));
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 		    bad_disk = B_TRUE;
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate #endif	/* defined(i386) */
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	    }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	    if (bad_disk) {
5620Sstevel@tonic-gate 		/* remember bad disks and continue */
563*62Sjeanm 		if (dlist_contains(*bad, (void *)(uintptr_t)disk,
564*62Sjeanm 		    compare_descriptor_names) != B_TRUE) {
565*62Sjeanm 		    dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
5660Sstevel@tonic-gate 		    if (item == NULL) {
5670Sstevel@tonic-gate 			error = ENOMEM;
5680Sstevel@tonic-gate 		    } else {
5690Sstevel@tonic-gate 			*bad = dlist_append(item, *bad, AT_TAIL);
5700Sstevel@tonic-gate 		    }
5710Sstevel@tonic-gate 		}
5720Sstevel@tonic-gate 		continue;
5730Sstevel@tonic-gate 	    }
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	    /* get disk name and multipath aliases */
5760Sstevel@tonic-gate 	    if ((error = disk_get_aliases(disk, &aliases)) == 0) {
5770Sstevel@tonic-gate 		dlist_t *iter;
5780Sstevel@tonic-gate 		boolean_t disk_name_set = B_FALSE;
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 		for (iter = aliases;
5810Sstevel@tonic-gate 		    (iter != NULL) && (error == 0);
5820Sstevel@tonic-gate 		    iter = iter->next) {
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 		    dm_descriptor_t	ap = (uintptr_t)iter->obj;
5850Sstevel@tonic-gate 		    char		*alias;
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 		    if ((error = get_name(ap, &alias)) == 0) {
5880Sstevel@tonic-gate 			/* save first alias as display name */
5890Sstevel@tonic-gate 			if (disk_name_set != B_TRUE) {
5900Sstevel@tonic-gate 			    /* make sure DID disk alias is fully qualified */
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 			    if (is_did_disk_name(alias) == B_TRUE) {
5930Sstevel@tonic-gate 				char *qual_name =
5940Sstevel@tonic-gate 				    make_fully_qualified_did_device_name(alias);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 				set_display_name(disk, qual_name);
5970Sstevel@tonic-gate 				oprintf(OUTPUT_DEBUG,
5980Sstevel@tonic-gate 					gettext("DID disk name: %s\n"),
5990Sstevel@tonic-gate 					qual_name);
6000Sstevel@tonic-gate 			    } else {
6010Sstevel@tonic-gate 				set_display_name(disk, alias);
6020Sstevel@tonic-gate 				oprintf(OUTPUT_DEBUG,
6030Sstevel@tonic-gate 					gettext("disk name: %s\n"),
6040Sstevel@tonic-gate 					alias);
6050Sstevel@tonic-gate 			    }
6060Sstevel@tonic-gate 			    disk_name_set = B_TRUE;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 			} else {
6090Sstevel@tonic-gate 			    /* save others as aliases */
6100Sstevel@tonic-gate 			    set_alias(disk, alias);
6110Sstevel@tonic-gate 			    oprintf(OUTPUT_DEBUG,
6120Sstevel@tonic-gate 				    gettext("  alias: %s\n"),
6130Sstevel@tonic-gate 				    alias);
6140Sstevel@tonic-gate 			}
6150Sstevel@tonic-gate 		    }
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 		dlist_free_items(aliases, NULL);
6190Sstevel@tonic-gate 	    }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	    if (error == 0) {
622*62Sjeanm 		dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
6230Sstevel@tonic-gate 		if (item == NULL) {
6240Sstevel@tonic-gate 		    error = ENOMEM;
6250Sstevel@tonic-gate 		} else {
6260Sstevel@tonic-gate 		    *known =
6270Sstevel@tonic-gate 			dlist_insert_ordered(item, *known,
6280Sstevel@tonic-gate 				ASCENDING, compare_desc_display_names);
6290Sstevel@tonic-gate 		}
6300Sstevel@tonic-gate 	    }
6310Sstevel@tonic-gate 	}
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	if (ddp != NULL) {
6340Sstevel@tonic-gate 	    free(ddp);
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	return (error);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate  * FUNCTION:	generate_known_slices(dlist_t *disks,
6420Sstevel@tonic-gate  *		dlist_t **known, dlist_t **bad)
6430Sstevel@tonic-gate  *
6440Sstevel@tonic-gate  * OUTPUT:	disks	- a pointer to a list of known disks
6450Sstevel@tonic-gate  *		known	- a pointer to a dlist_t list to hold the known slices
6460Sstevel@tonic-gate  *		bad	- a pointer to a dlist_t to hold the bad slices
6470Sstevel@tonic-gate  *
6480Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
6490Sstevel@tonic-gate  *			 !0 otherwise.
6500Sstevel@tonic-gate  *
6510Sstevel@tonic-gate  * PURPOSE:	Examines input list of known disks and determines the slices
6520Sstevel@tonic-gate  *		attached to each.
6530Sstevel@tonic-gate  *
6540Sstevel@tonic-gate  *		Some slices returned from libdiskmgt may not really exist,
6550Sstevel@tonic-gate  *		this is detected when trying to get more information about
6560Sstevel@tonic-gate  *		the slice -- ENODEV is returned.  Any such slices will be
6570Sstevel@tonic-gate  *		added to the bad slice list.
6580Sstevel@tonic-gate  */
6590Sstevel@tonic-gate static int
generate_known_slices(dlist_t * disks,dlist_t ** known,dlist_t ** bad)6600Sstevel@tonic-gate generate_known_slices(
6610Sstevel@tonic-gate 	dlist_t		*disks,
6620Sstevel@tonic-gate 	dlist_t		**known,
6630Sstevel@tonic-gate 	dlist_t		**bad)
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate 	dlist_t		*iter;
6660Sstevel@tonic-gate 	int		error = 0;
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	/* iterate list of disks and add their slices to the known list */
6690Sstevel@tonic-gate 	for (iter = disks; (iter != NULL) && (error == 0); iter = iter->next) {
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	    dm_descriptor_t disk = (uintptr_t)iter->obj;
6720Sstevel@tonic-gate 	    dlist_t *slices = NULL;
6730Sstevel@tonic-gate 	    dlist_t *iter1;
6740Sstevel@tonic-gate 	    char *dname = NULL;
6750Sstevel@tonic-gate 	    boolean_t disk_ctd_alias_derived = B_FALSE;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	    if (((error = disk_get_slices(disk, &slices)) != 0) ||
6780Sstevel@tonic-gate 		((error = get_display_name(disk, &dname)) != 0)) {
6790Sstevel@tonic-gate 		continue;
6800Sstevel@tonic-gate 	    }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	    for (iter1 = slices;
6830Sstevel@tonic-gate 		(iter1 != NULL) && (error == 0);
6840Sstevel@tonic-gate 		iter1 = iter1->next) {
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 		dm_descriptor_t slice = (uintptr_t)iter1->obj;
6870Sstevel@tonic-gate 		uint32_t index = 0;
6880Sstevel@tonic-gate 		nvlist_t *attrs = NULL;
6890Sstevel@tonic-gate 		char *sname = NULL;
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 		if (((error = get_name(slice, &sname)) != 0) ||
6920Sstevel@tonic-gate 		    ((error = slice_get_index(slice, &index)) != 0) ||
6930Sstevel@tonic-gate 		    ((error = get_cached_attributes(slice, &attrs)) != 0)) {
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 		    if (error == ENODEV) {
6960Sstevel@tonic-gate 			/* bad slice, remember it and continue */
697*62Sjeanm 			dlist_t *item =
698*62Sjeanm 			    dlist_new_item((void *)(uintptr_t)slice);
6990Sstevel@tonic-gate 			if (item == NULL) {
7000Sstevel@tonic-gate 			    error = ENOMEM;
7010Sstevel@tonic-gate 			} else {
7020Sstevel@tonic-gate 			    *bad = dlist_insert_ordered(
7030Sstevel@tonic-gate 				    item, *bad,
7040Sstevel@tonic-gate 				    ASCENDING, compare_descriptor_names);
7050Sstevel@tonic-gate 			    error = 0;
7060Sstevel@tonic-gate 			}
7070Sstevel@tonic-gate 		    }
7080Sstevel@tonic-gate 		    continue;
7090Sstevel@tonic-gate 		}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 		if ((error == 0) && (is_did_slice_name(sname) == B_TRUE) &&
7120Sstevel@tonic-gate 		    (disk_ctd_alias_derived == B_FALSE)) {
7130Sstevel@tonic-gate 		    /* BEGIN CSTYLED */
7140Sstevel@tonic-gate 		    /*
7150Sstevel@tonic-gate 		     * If the slice name is a DID name, get the local CTD
7160Sstevel@tonic-gate 		     * name for slice, extract the disk name and add it as
7170Sstevel@tonic-gate 		     * an alias for the disk.
7180Sstevel@tonic-gate 		     *
7190Sstevel@tonic-gate 		     * This is the only way to derive the CTD alias for the
7200Sstevel@tonic-gate 		     * disk when DID is enabled.
7210Sstevel@tonic-gate 		     *
7220Sstevel@tonic-gate 		     * The disk_ctd_alias_derived flag ensure the disk's
7230Sstevel@tonic-gate 		     * CTD alias is only set once.
7240Sstevel@tonic-gate 		     *
7250Sstevel@tonic-gate 		     * The slice's CTD aliases are then derived from the
7260Sstevel@tonic-gate 		     * disk's CTD alias in the normal, non-DID name processing
7270Sstevel@tonic-gate 		     * which happens below.
7280Sstevel@tonic-gate 		     */
7290Sstevel@tonic-gate 		    /* END CSTYLED */
7300Sstevel@tonic-gate 		    char *local = NULL;
7310Sstevel@tonic-gate 		    if ((error = nvlist_lookup_string(attrs, DM_LOCALNAME,
7320Sstevel@tonic-gate 				&local)) != 0) {
7330Sstevel@tonic-gate 			if (error == ENOENT) {
7340Sstevel@tonic-gate 			    /* no local name -> no DID */
7350Sstevel@tonic-gate 			    error = 0;
7360Sstevel@tonic-gate 			}
7370Sstevel@tonic-gate 		    } else {
7380Sstevel@tonic-gate 			char *localdisk = NULL;
7390Sstevel@tonic-gate 			char *diskonly = NULL;
7400Sstevel@tonic-gate 			if ((error = extract_diskname(local,
7410Sstevel@tonic-gate 			    &localdisk)) == 0) {
7420Sstevel@tonic-gate 			    if ((diskonly = strrchr(localdisk, '/')) != NULL) {
7430Sstevel@tonic-gate 				++diskonly;
7440Sstevel@tonic-gate 			    } else {
7450Sstevel@tonic-gate 				diskonly = localdisk;
7460Sstevel@tonic-gate 			    }
7470Sstevel@tonic-gate 			    oprintf(OUTPUT_DEBUG,
7480Sstevel@tonic-gate 				    gettext("  set DID disk CTD alias: %s\n"),
7490Sstevel@tonic-gate 				    diskonly);
7500Sstevel@tonic-gate 			    error = set_alias(disk, diskonly);
7510Sstevel@tonic-gate 			    free(localdisk);
7520Sstevel@tonic-gate 			    disk_ctd_alias_derived = B_TRUE;
7530Sstevel@tonic-gate 			}
7540Sstevel@tonic-gate 		    }
7550Sstevel@tonic-gate 		}
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 		/* derive slice display name from disk's display name */
7580Sstevel@tonic-gate 		if (error == 0) {
7590Sstevel@tonic-gate 		    if ((error = make_slicename_for_diskname_and_index(
7600Sstevel@tonic-gate 			dname, index, &sname)) == 0) {
7610Sstevel@tonic-gate 			error = set_display_name(slice, sname);
7620Sstevel@tonic-gate 		    }
7630Sstevel@tonic-gate 		}
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 		/* set slice aliases using disk aliases */
7660Sstevel@tonic-gate 		if (error == 0) {
7670Sstevel@tonic-gate 		    dlist_t *aliases = NULL;
7680Sstevel@tonic-gate 		    if ((error = get_aliases(disk, &aliases)) == 0) {
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 			dlist_t *iter2 = aliases;
7710Sstevel@tonic-gate 			for (; (iter2 != NULL) && (error == 0);
7720Sstevel@tonic-gate 			    iter2 = iter2->next) {
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 			    char *dalias = (char *)iter2->obj;
7750Sstevel@tonic-gate 			    char *salias = NULL;
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 			    if ((error = make_slicename_for_diskname_and_index(
7780Sstevel@tonic-gate 				dalias, index, &salias)) == 0) {
7790Sstevel@tonic-gate 				error = set_alias(slice, salias);
7800Sstevel@tonic-gate 				free(salias);
7810Sstevel@tonic-gate 			    }
7820Sstevel@tonic-gate 			}
7830Sstevel@tonic-gate 			dlist_free_items(aliases, free);
7840Sstevel@tonic-gate 		    }
7850Sstevel@tonic-gate 		}
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 		if (error == 0) {
788*62Sjeanm 		    dlist_t *item = dlist_new_item((void *)(uintptr_t)slice);
7890Sstevel@tonic-gate 		    if (item == NULL) {
7900Sstevel@tonic-gate 			error = ENOMEM;
7910Sstevel@tonic-gate 		    } else {
7920Sstevel@tonic-gate 			*known =
7930Sstevel@tonic-gate 			    dlist_insert_ordered(
7940Sstevel@tonic-gate 				    item, *known,
7950Sstevel@tonic-gate 				    ASCENDING, compare_desc_display_names);
7960Sstevel@tonic-gate 		    }
7970Sstevel@tonic-gate 		}
7980Sstevel@tonic-gate 	    }
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	    dlist_free_items(slices, NULL);
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	return (error);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate /*
8070Sstevel@tonic-gate  * FUNCTION:	generate_known_hbas(dlist_t *disks, dlist_t **known)
8080Sstevel@tonic-gate  *
8090Sstevel@tonic-gate  * INPUT:	diskset	- a char * diskset name.
8100Sstevel@tonic-gate  *
8110Sstevel@tonic-gate  * OUTPUT:	populates the list of known HBAs.
8120Sstevel@tonic-gate  *
8130Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
8140Sstevel@tonic-gate  *			 !0 otherwise
8150Sstevel@tonic-gate  *
8160Sstevel@tonic-gate  * PURPOSE:	Examines known disk list and derives the list of known HBAs.
8170Sstevel@tonic-gate  *
8180Sstevel@tonic-gate  *		Determines the CTD name for an HBA and saves it.
8190Sstevel@tonic-gate  */
8200Sstevel@tonic-gate static int
generate_known_hbas(dlist_t * disks,dlist_t ** known)8210Sstevel@tonic-gate generate_known_hbas(
8220Sstevel@tonic-gate 	dlist_t	*disks,
8230Sstevel@tonic-gate 	dlist_t	**known)
8240Sstevel@tonic-gate {
8250Sstevel@tonic-gate 	dlist_t	*iter;
8260Sstevel@tonic-gate 	int	error = 0;
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	/*
8290Sstevel@tonic-gate 	 * for each known disk follow its HBA connections and
8300Sstevel@tonic-gate 	 * assemble the list of known HBAs.
8310Sstevel@tonic-gate 	 */
8320Sstevel@tonic-gate 	for (iter = disks;
8330Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
8340Sstevel@tonic-gate 	    iter = iter->next) {
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	    dm_descriptor_t	disk = (uintptr_t)iter->obj;
8370Sstevel@tonic-gate 	    dlist_t 		*hbas = NULL;
8380Sstevel@tonic-gate 	    dlist_t 		*iter2 = NULL;
8390Sstevel@tonic-gate 	    dlist_t		*iter3 = NULL;
8400Sstevel@tonic-gate 	    dlist_t		*aliases = NULL;
8410Sstevel@tonic-gate 	    char		*dname = NULL;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	    ((error = get_display_name(disk, &dname)) != 0) ||
8440Sstevel@tonic-gate 	    (error = disk_get_aliases(disk, &aliases)) ||
8450Sstevel@tonic-gate 	    (error = disk_get_hbas(disk, &hbas));
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	    if (error == 0) {
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 		if ((hbas == NULL) || (dlist_length(hbas) == 0)) {
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
8520Sstevel@tonic-gate 			    gettext("Disk %s has no HBA/Controller?!\n"),
8530Sstevel@tonic-gate 			    dname);
8540Sstevel@tonic-gate 		    error = -1;
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		    dlist_free_items(hbas, NULL);
8570Sstevel@tonic-gate 		    dlist_free_items(aliases, NULL);
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		    continue;
8600Sstevel@tonic-gate 		}
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 		for (iter2 = hbas, iter3 = aliases;
8630Sstevel@tonic-gate 		    iter2 != NULL && iter3 != NULL;
8640Sstevel@tonic-gate 		    iter2 = iter2->next, iter3 = iter3->next) {
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 		    dm_descriptor_t	hba = (uintptr_t)iter2->obj;
8670Sstevel@tonic-gate 		    dm_descriptor_t	alias = (uintptr_t)iter3->obj;
8680Sstevel@tonic-gate 		    dlist_t		*item = NULL;
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 		    /* scan list of known HBAs and see if known */
871*62Sjeanm 		    if (dlist_contains(*known, (void*)(uintptr_t)hba,
872*62Sjeanm 			compare_descriptor_names) == B_TRUE) {
8730Sstevel@tonic-gate 			/* known HBA */
8740Sstevel@tonic-gate 			continue;
8750Sstevel@tonic-gate 		    }
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 		    /* see if HBA supports MPXIO */
8780Sstevel@tonic-gate 		    if ((error == 0) && (_mpxio_enabled != B_TRUE)) {
8790Sstevel@tonic-gate 			hba_is_multiplex(hba, &_mpxio_enabled);
8800Sstevel@tonic-gate 		    }
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 		    /* generate a CTD name for HBA */
8830Sstevel@tonic-gate 		    error = generate_known_hba_name(hba, alias, disk);
8840Sstevel@tonic-gate 		    if (error == 0) {
8850Sstevel@tonic-gate 			/* add to known HBA list */
886*62Sjeanm 			if ((item = dlist_new_item((void *)(uintptr_t)hba)) ==
887*62Sjeanm 			    NULL) {
8880Sstevel@tonic-gate 			    error = ENOMEM;
8890Sstevel@tonic-gate 			} else {
8900Sstevel@tonic-gate 			    *known =
8910Sstevel@tonic-gate 				dlist_insert_ordered(item, *known,
8920Sstevel@tonic-gate 				    ASCENDING, compare_desc_display_names);
8930Sstevel@tonic-gate 			}
8940Sstevel@tonic-gate 		    }
8950Sstevel@tonic-gate 		}
8960Sstevel@tonic-gate 	    }
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	    dlist_free_items(aliases, NULL);
8990Sstevel@tonic-gate 	    dlist_free_items(hbas, NULL);
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	return (error);
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate /*
9060Sstevel@tonic-gate  * FUNCTION:	generate_known_hba_name(dm_descriptor_t hba,
9070Sstevel@tonic-gate  *		dm_descriptor_t alias, char *diskname)
9080Sstevel@tonic-gate  *
9090Sstevel@tonic-gate  * INPUT:	hba	- a dm_descriptor_t HBA handle.
9100Sstevel@tonic-gate  *		alias	- a dm_descriptor_t disk alias handle.
9110Sstevel@tonic-gate  *		diskname - a char * disk name
9120Sstevel@tonic-gate  *
9130Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
9140Sstevel@tonic-gate  *			 !0 otherwise
9150Sstevel@tonic-gate  *
9160Sstevel@tonic-gate  * PURPOSE:	Sets the CTD name for the input HBA.
9170Sstevel@tonic-gate  *
9180Sstevel@tonic-gate  *		The CTD name for the HBA is generated from the input
9190Sstevel@tonic-gate  *		disk alias (ex: cXdXtXsX) or from the disk name if
9200Sstevel@tonic-gate  *		the input alias is a DID name (ex: dX).
9210Sstevel@tonic-gate  */
9220Sstevel@tonic-gate static int
generate_known_hba_name(dm_descriptor_t hba,dm_descriptor_t alias,dm_descriptor_t disk)9230Sstevel@tonic-gate generate_known_hba_name(
9240Sstevel@tonic-gate 	dm_descriptor_t	hba,
9250Sstevel@tonic-gate 	dm_descriptor_t	alias,
9260Sstevel@tonic-gate 	dm_descriptor_t disk)
9270Sstevel@tonic-gate {
9280Sstevel@tonic-gate 	char	*hbaname = NULL;
9290Sstevel@tonic-gate 	char	*aliasname = NULL;
9300Sstevel@tonic-gate 	int	error = 0;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	((error = get_name(alias, &aliasname)) != 0) ||
9330Sstevel@tonic-gate 	(error = extract_hbaname(aliasname, &hbaname));
9340Sstevel@tonic-gate 	if (error != 0) {
9350Sstevel@tonic-gate 	    free(hbaname);
9360Sstevel@tonic-gate 	    return (error);
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	/* see if the input alias is a DID name... */
9400Sstevel@tonic-gate 	if (is_did_disk_name(aliasname) == B_TRUE) {
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	    /* look for a non-DID name in disk's aliases */
9430Sstevel@tonic-gate 	    dlist_t *aliases = NULL;
9440Sstevel@tonic-gate 	    error = get_aliases(disk, &aliases);
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	    for (; (error == 0) && (aliases != NULL);
9470Sstevel@tonic-gate 		aliases = aliases->next) {
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 		aliasname = (char *)aliases->obj;
9500Sstevel@tonic-gate 		if (is_did_disk_name(aliasname) != B_TRUE) {
9510Sstevel@tonic-gate 		    /* this is the "local" CTD name generated by */
9520Sstevel@tonic-gate 		    /* generate_known_disks() above */
9530Sstevel@tonic-gate 		    error = extract_hbaname(aliasname, &hbaname);
9540Sstevel@tonic-gate 		    if ((error == 0) && (hbaname != NULL)) {
9550Sstevel@tonic-gate 			set_display_name(hba, hbaname);
9560Sstevel@tonic-gate 			break;
9570Sstevel@tonic-gate 		    }
9580Sstevel@tonic-gate 		}
9590Sstevel@tonic-gate 	    }
9600Sstevel@tonic-gate 	    dlist_free_items(aliases, free);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	} else {
9630Sstevel@tonic-gate 	    /* use whatever was derived from the alias name */
9640Sstevel@tonic-gate 	    set_display_name(hba, hbaname);
9650Sstevel@tonic-gate 	}
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	return (error);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate /*
9710Sstevel@tonic-gate  * FUNCTION:	print_known_devices()
9720Sstevel@tonic-gate  *
9730Sstevel@tonic-gate  * PURPOSE:	Print out the known devices.
9740Sstevel@tonic-gate  *
9750Sstevel@tonic-gate  *		Iterates the lists of known slices, disks and HBAs
9760Sstevel@tonic-gate  *		and prints out their CTD and device names.
9770Sstevel@tonic-gate  */
9780Sstevel@tonic-gate static void
print_known_devices(char * diskset)9790Sstevel@tonic-gate print_known_devices(
9800Sstevel@tonic-gate 	char	*diskset)
9810Sstevel@tonic-gate {
9820Sstevel@tonic-gate 	int i = 0;
9830Sstevel@tonic-gate 	struct {
9840Sstevel@tonic-gate 		char *msg;
9850Sstevel@tonic-gate 		dlist_t *list;
9860Sstevel@tonic-gate 	}	devs[3];
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	devs[0].msg = gettext("HBA/Controllers");
9890Sstevel@tonic-gate 	devs[0].list = _known_hbas;
9900Sstevel@tonic-gate 	devs[1].msg = gettext("disks");
9910Sstevel@tonic-gate 	devs[1].list = _known_disks;
9920Sstevel@tonic-gate 	devs[2].msg = gettext("slices");
9930Sstevel@tonic-gate 	devs[2].list = _known_slices;
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	for (i = 0; i < 3; i++) {
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	    oprintf(OUTPUT_VERBOSE,
9980Sstevel@tonic-gate 		    gettext("\n  These %s are known:\n\n"),
9990Sstevel@tonic-gate 		    devs[i].msg);
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	    print_device_list(devs[i].list);
10020Sstevel@tonic-gate 	}
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate /*
10060Sstevel@tonic-gate  * FUNCTION:	get_usable_slices(dlist_t **list)
10070Sstevel@tonic-gate  *
10080Sstevel@tonic-gate  * OUTPUT:	list	- a dlist_t pointer to hold the returned list of
10090Sstevel@tonic-gate  *			devices.
10100Sstevel@tonic-gate  *
10110Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
10120Sstevel@tonic-gate  *			 !0 otherwise
10130Sstevel@tonic-gate  *
10140Sstevel@tonic-gate  * PURPOSE:	Public accessors the the modules private lists of
10150Sstevel@tonic-gate  *		available devices.
10160Sstevel@tonic-gate  *
10170Sstevel@tonic-gate  *		The functions are keyed by diskset name in the event
10180Sstevel@tonic-gate  *		objects in different disksets are loaded concurrently.
10190Sstevel@tonic-gate  */
10200Sstevel@tonic-gate int
get_usable_slices(dlist_t ** list)10210Sstevel@tonic-gate get_usable_slices(
10220Sstevel@tonic-gate 	dlist_t **list)
10230Sstevel@tonic-gate {
10240Sstevel@tonic-gate 	*list = _usable_slices;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	return (0);
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate int
get_usable_disks(dlist_t ** list)10300Sstevel@tonic-gate get_usable_disks(
10310Sstevel@tonic-gate 	dlist_t **list)
10320Sstevel@tonic-gate {
10330Sstevel@tonic-gate 	*list = _usable_disks;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	return (0);
10360Sstevel@tonic-gate }
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate int
get_usable_hbas(dlist_t ** list)10390Sstevel@tonic-gate get_usable_hbas(
10400Sstevel@tonic-gate 	dlist_t **list)
10410Sstevel@tonic-gate {
10420Sstevel@tonic-gate 	*list = _usable_hbas;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	return (0);
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate /*
10480Sstevel@tonic-gate  * FUNCTION:	generate_usable_disks_and_slices_in_local_set(dlist_t **classes,
10490Sstevel@tonic-gate  *			dlist_t **bad_disks, dlist_t **usable_disks,
10500Sstevel@tonic-gate  *			dlist_t **usable_slices)
10510Sstevel@tonic-gate  *
10520Sstevel@tonic-gate  * OUTPUT:	used_classes - a pointer to a list of slice_class_t structs
10530Sstevel@tonic-gate  *			updated with known slices that have detected uses
10540Sstevel@tonic-gate  *			added to the correct class'e list of slices.
10550Sstevel@tonic-gate  *		bad_disks - a pointer to a list of bad/unusable disks updated
10560Sstevel@tonic-gate  *			with any bad disks that were detected
10570Sstevel@tonic-gate  *		useable_disks - a pointer to a list of usable disks
10580Sstevel@tonic-gate  *		useable_slices - a pointer to a list of usable slices
10590Sstevel@tonic-gate  *
10600Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
10610Sstevel@tonic-gate  *			 !0 otherwise.
10620Sstevel@tonic-gate  *
10630Sstevel@tonic-gate  * PURPOSE:	Scans the disks in the local set to determine which are
10640Sstevel@tonic-gate  *		usable during layout processing.
10650Sstevel@tonic-gate  *
10660Sstevel@tonic-gate  *		Determines which are usable by layout using usages detected
10670Sstevel@tonic-gate  *		by libdiskmgt.
10680Sstevel@tonic-gate  */
10690Sstevel@tonic-gate static int
generate_usable_disks_and_slices_in_local_set(dlist_t ** classes,dlist_t ** bad_slices,dlist_t ** usable_disks,dlist_t ** usable_slices)10700Sstevel@tonic-gate generate_usable_disks_and_slices_in_local_set(
10710Sstevel@tonic-gate 	dlist_t **classes,
10720Sstevel@tonic-gate 	dlist_t **bad_slices,
10730Sstevel@tonic-gate 	dlist_t **usable_disks,
10740Sstevel@tonic-gate 	dlist_t **usable_slices)
10750Sstevel@tonic-gate {
10760Sstevel@tonic-gate 	char	*dsname = MD_LOCAL_NAME;
10770Sstevel@tonic-gate 	dlist_t *disks;
10780Sstevel@tonic-gate 	dlist_t *iter;
10790Sstevel@tonic-gate 	int 	error;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	/* Get disks in local set */
10820Sstevel@tonic-gate 	error = get_disks_in_diskset(dsname, &disks);
10830Sstevel@tonic-gate 	if (error != 0) {
10840Sstevel@tonic-gate 	    return (error);
10850Sstevel@tonic-gate 	}
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	/* For each disk in this set... */
10880Sstevel@tonic-gate 	for (iter = disks; iter != NULL && error == 0; iter = iter->next) {
10890Sstevel@tonic-gate 	    dm_descriptor_t disk = (uintptr_t)iter->obj;
10900Sstevel@tonic-gate 	    dlist_t *slices;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	    /* Get slices on this disk */
10930Sstevel@tonic-gate 	    error = disk_get_slices(disk, &slices);
10940Sstevel@tonic-gate 	    if (error == 0) {
10950Sstevel@tonic-gate 		dlist_t *iter2;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 		/*
10980Sstevel@tonic-gate 		 * Assume disk is available until a bad or unavailable
10990Sstevel@tonic-gate 		 * slice is found
11000Sstevel@tonic-gate 		 */
11010Sstevel@tonic-gate 		boolean_t avail = B_TRUE;
11020Sstevel@tonic-gate 		boolean_t bad_disk = B_FALSE;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 		/* For each slice on this disk... */
11050Sstevel@tonic-gate 		for (iter2 = slices;
11060Sstevel@tonic-gate 		    iter2 != NULL && error == 0 &&
11070Sstevel@tonic-gate 			avail == B_TRUE && bad_disk == B_FALSE;
11080Sstevel@tonic-gate 		    iter2 = iter2->next) {
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 		    dm_descriptor_t slice = (uintptr_t)iter2->obj;
11110Sstevel@tonic-gate 		    dlist_t *bad_slices_on_this_disk = NULL;
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 		    /* Is this slice available? */
11140Sstevel@tonic-gate 		    error = check_slice_usage(dsname, slice,
11150Sstevel@tonic-gate 			disk, &avail, &bad_slices_on_this_disk, classes);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 		    /* Is the slice bad (inaccessible)? */
11180Sstevel@tonic-gate 		    if (error != 0 && bad_slices_on_this_disk != NULL) {
11190Sstevel@tonic-gate 			bad_disk = B_TRUE;
11200Sstevel@tonic-gate 			*bad_slices = dlist_append_list(
11210Sstevel@tonic-gate 			    *bad_slices, bad_slices_on_this_disk);
11220Sstevel@tonic-gate 		    }
11230Sstevel@tonic-gate 		}
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		/* Is the disk available? */
11260Sstevel@tonic-gate 		if (error == 0 && bad_disk == B_FALSE && avail == B_TRUE) {
11270Sstevel@tonic-gate 		    error = dlist_append_object(
1128*62Sjeanm 			(void *)(uintptr_t)disk, usable_disks, AT_TAIL);
11290Sstevel@tonic-gate 		}
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 		dlist_free_items(slices, NULL);
11320Sstevel@tonic-gate 	    }
11330Sstevel@tonic-gate 	}
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	dlist_free_items(disks, NULL);
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	if (error == 0) {
11380Sstevel@tonic-gate 	    /* BEGIN CSTYLED */
11390Sstevel@tonic-gate 	    /*
11400Sstevel@tonic-gate 	     * Now reslice usable disks in the local set to
11410Sstevel@tonic-gate 	     * simulate the slices they'll have when they're added
11420Sstevel@tonic-gate 	     * to the named disk set, and add these resulting
11430Sstevel@tonic-gate 	     * virtual slices to the list of available slices.
11440Sstevel@tonic-gate 	     */
11450Sstevel@tonic-gate 	    /* END CSTYLED */
11460Sstevel@tonic-gate 	    error = generate_virtual_slices(*usable_disks, usable_slices);
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	return (error);
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate /*
11530Sstevel@tonic-gate  * FUNCTION:	generate_virtual_slices(dlist_t *unused, dlist_t **usable)
11540Sstevel@tonic-gate  *
11550Sstevel@tonic-gate  * INPUT:	slice_classes - a list of unused slice dm_descriptor_t handles.
11560Sstevel@tonic-gate  *
11570Sstevel@tonic-gate  * OUTPUT:	usable - pointer to the list of usable slices, updated
11580Sstevel@tonic-gate  *			with any created virtual slices.
11590Sstevel@tonic-gate  *
11600Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
11610Sstevel@tonic-gate  *			 !0 otherwise.
11620Sstevel@tonic-gate  *
11630Sstevel@tonic-gate  * PURPOSE:	Helper which creates virtual slices for each disk which
11640Sstevel@tonic-gate  *		could be added to a diskset if necessary...
11650Sstevel@tonic-gate  *
11660Sstevel@tonic-gate  *		Search the input list of slice classes for the entry
11670Sstevel@tonic-gate  *		containing slices known to be available for use by layout.
11680Sstevel@tonic-gate  *
11690Sstevel@tonic-gate  *		Iterate the list of unused slices and determine the set
11700Sstevel@tonic-gate  *		of unique disks.
11710Sstevel@tonic-gate  *
11720Sstevel@tonic-gate  *		For each unique disk, create virtual slice descriptors to
11730Sstevel@tonic-gate  *		represent those that will exist if/when the disk is added
11740Sstevel@tonic-gate  *		to the diskset.
11750Sstevel@tonic-gate  *
11760Sstevel@tonic-gate  *		Add theese virtual slices to the list of usable slices.
11770Sstevel@tonic-gate  */
11780Sstevel@tonic-gate static int
generate_virtual_slices(dlist_t * avail_disks_local_set,dlist_t ** usable)11790Sstevel@tonic-gate generate_virtual_slices(
11800Sstevel@tonic-gate 	dlist_t 	*avail_disks_local_set,
11810Sstevel@tonic-gate 	dlist_t		**usable)
11820Sstevel@tonic-gate {
11830Sstevel@tonic-gate 	dlist_t	*iter = NULL;
11840Sstevel@tonic-gate 	int	error = 0;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	/* generate virtual slices */
11870Sstevel@tonic-gate 	error = create_virtual_slices(avail_disks_local_set);
11880Sstevel@tonic-gate 	if (error == 0) {
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	    get_virtual_slices(&iter);
11910Sstevel@tonic-gate 	    for (; (iter != NULL) && (error == 0); iter = iter->next) {
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 		dlist_t *item = dlist_new_item((void *) iter->obj);
11940Sstevel@tonic-gate 		if (item == NULL) {
11950Sstevel@tonic-gate 		    error = ENOMEM;
11960Sstevel@tonic-gate 		} else {
11970Sstevel@tonic-gate 		    *usable =
11980Sstevel@tonic-gate 			dlist_insert_ordered(item, *usable,
11990Sstevel@tonic-gate 				ASCENDING, compare_desc_display_names);
12000Sstevel@tonic-gate 		}
12010Sstevel@tonic-gate 	    }
12020Sstevel@tonic-gate 	}
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	return (error);
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate /*
12080Sstevel@tonic-gate  * FUNCTION:	generate_usable_disks_and_slices_in_named_set(char *dsname,
12090Sstevel@tonic-gate  *			dlist_t **classes, dlist_t **bad_slices,
12100Sstevel@tonic-gate  *			dlist_t **usable_slices, dlist_t **usable_disks)
12110Sstevel@tonic-gate  *
12120Sstevel@tonic-gate  * INPUT:	dsname	- a char * diskset name.
12130Sstevel@tonic-gate  *
12140Sstevel@tonic-gate  * OUTPUT:	classes	- pointer to a list of slice_class_t structs,
12150Sstevel@tonic-gate  *			updated to include slices in the disk set with
12160Sstevel@tonic-gate  *			known uses.
12170Sstevel@tonic-gate  * 		bad_slices - pointer to a list of bad/unusable slices,
12180Sstevel@tonic-gate  *			updated to include slices in the disk set that
12190Sstevel@tonic-gate  *			are inaccessible or no longer existent.
12200Sstevel@tonic-gate  *		usable_slices - pointer to a list of usable slices in the
12210Sstevel@tonic-gate  *			disk set.
12220Sstevel@tonic-gate  *		usable_disks - pointer to a list of usable disks in the
12230Sstevel@tonic-gate  *			disk set.
12240Sstevel@tonic-gate  *
12250Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
12260Sstevel@tonic-gate  *			 !0 otherwise.
12270Sstevel@tonic-gate  *
12280Sstevel@tonic-gate  * PURPOSE:	1. determine the disks in the named disk set
12290Sstevel@tonic-gate  *		2. determine the used slices on the disks
12300Sstevel@tonic-gate  *		3. determine the unused slices on the disks
12310Sstevel@tonic-gate  *		4. look for unused space on the disks and collect it
12320Sstevel@tonic-gate  *		   into an existing unused slice, or create a new
12330Sstevel@tonic-gate  *		   virtual slice.
12340Sstevel@tonic-gate  */
12350Sstevel@tonic-gate static int
generate_usable_disks_and_slices_in_named_set(char * dsname,dlist_t ** classes,dlist_t ** bad_slices,dlist_t ** usable_disks,dlist_t ** usable_slices)12360Sstevel@tonic-gate generate_usable_disks_and_slices_in_named_set(
12370Sstevel@tonic-gate 	char		*dsname,
12380Sstevel@tonic-gate 	dlist_t		**classes,
12390Sstevel@tonic-gate 	dlist_t		**bad_slices,
12400Sstevel@tonic-gate 	dlist_t		**usable_disks,
12410Sstevel@tonic-gate 	dlist_t		**usable_slices)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate 	dlist_t		*disks = NULL;
12440Sstevel@tonic-gate 	dlist_t		*iter = NULL;
12450Sstevel@tonic-gate 	int		error = 0;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	error = get_disks_in_diskset(dsname, &disks);
12480Sstevel@tonic-gate 	if (error != 0) {
12490Sstevel@tonic-gate 	    return (error);
12500Sstevel@tonic-gate 	}
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	/* For each disk... */
12530Sstevel@tonic-gate 	for (iter = disks;
12540Sstevel@tonic-gate 	    iter != NULL && error == 0;
12550Sstevel@tonic-gate 	    iter = iter->next) {
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	    dm_descriptor_t	disk = (uintptr_t)iter->obj;
12580Sstevel@tonic-gate 	    dlist_t		*iter2;
12590Sstevel@tonic-gate 	    dlist_t		*slices = NULL;
12600Sstevel@tonic-gate 	    dlist_t		*bad_slices_on_this_disk = NULL;
12610Sstevel@tonic-gate 	    dlist_t		*used_slices_on_this_disk = NULL;
12620Sstevel@tonic-gate 	    dlist_t		*unused_slices_on_this_disk = NULL;
12630Sstevel@tonic-gate 	    boolean_t		bad_disk = B_FALSE;
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	    error = disk_get_slices(disk, &slices);
12660Sstevel@tonic-gate 	    if (error != 0) {
12670Sstevel@tonic-gate 		break;
12680Sstevel@tonic-gate 	    }
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	    /* Determine the used, unused, and bad slices on the disk */
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	    /* For each slice... */
12730Sstevel@tonic-gate 	    for (iter2 = slices;
12740Sstevel@tonic-gate 		iter2 != NULL && error == 0 && bad_disk == B_FALSE;
12750Sstevel@tonic-gate 		iter2 = iter2->next) {
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 		dm_descriptor_t slice = (uintptr_t)iter2->obj;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 		boolean_t	rsvd = B_FALSE;
12800Sstevel@tonic-gate 		boolean_t	avail = B_FALSE;
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 		/* Get slice usage */
12830Sstevel@tonic-gate 		if (((error = is_reserved_slice(slice, &rsvd)) == 0) &&
12840Sstevel@tonic-gate 		    ((error = check_slice_usage(dsname, slice, disk, &avail,
12850Sstevel@tonic-gate 			&bad_slices_on_this_disk, classes)) == 0)) {
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 		    /* Is the slice bad (inaccessible)? */
12880Sstevel@tonic-gate 		    if (bad_slices_on_this_disk != NULL) {
12890Sstevel@tonic-gate 			*bad_slices = dlist_append_list(
12900Sstevel@tonic-gate 			    *bad_slices, bad_slices_on_this_disk);
12910Sstevel@tonic-gate 			/*
12920Sstevel@tonic-gate 			 * Since one slice on this disk is bad, don't
12930Sstevel@tonic-gate 			 * use any slices on this disk
12940Sstevel@tonic-gate 			 */
12950Sstevel@tonic-gate 			bad_disk = B_TRUE;
12960Sstevel@tonic-gate 		    } else {
12970Sstevel@tonic-gate 
1298*62Sjeanm 			dlist_t *item =
1299*62Sjeanm 			    dlist_new_item((void *)(uintptr_t)slice);
13000Sstevel@tonic-gate 			if (item == NULL) {
13010Sstevel@tonic-gate 			    error = ENOMEM;
13020Sstevel@tonic-gate 			} else {
13030Sstevel@tonic-gate 			    /* Add slice to used/unused list as appropriate */
13040Sstevel@tonic-gate 			    if (avail == B_TRUE && rsvd == B_FALSE) {
13050Sstevel@tonic-gate 				unused_slices_on_this_disk = dlist_append(
13060Sstevel@tonic-gate 				    item, unused_slices_on_this_disk, AT_TAIL);
13070Sstevel@tonic-gate 			    } else {
13080Sstevel@tonic-gate 				used_slices_on_this_disk =
13090Sstevel@tonic-gate 				    dlist_insert_ordered(item,
13100Sstevel@tonic-gate 					used_slices_on_this_disk,
13110Sstevel@tonic-gate 					ASCENDING, compare_start_blocks);
13120Sstevel@tonic-gate 			    }
13130Sstevel@tonic-gate 			}
13140Sstevel@tonic-gate 		    }
13150Sstevel@tonic-gate 		}
13160Sstevel@tonic-gate 	    }
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	    /* Done iterating slices */
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	    if (error == 0 && bad_disk == B_FALSE) {
13210Sstevel@tonic-gate 		/* For each unused slice... */
13220Sstevel@tonic-gate 		for (iter2 = unused_slices_on_this_disk;
13230Sstevel@tonic-gate 		    iter2 != NULL && error == 0;
13240Sstevel@tonic-gate 		    iter2 = iter2->next) {
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 		    dm_descriptor_t slice = (uintptr_t)iter2->obj;
13270Sstevel@tonic-gate 		    error = update_slice_attributes(slice, 0, 0, 0);
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 		    /* Only do this once */
13300Sstevel@tonic-gate 		    if (error == 0 && iter2 == unused_slices_on_this_disk) {
13310Sstevel@tonic-gate 			error = add_modified_disk(NULL, disk);
13320Sstevel@tonic-gate 		    }
13330Sstevel@tonic-gate 		}
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 		if (error == 0) {
13360Sstevel@tonic-gate 		    /* Create usable slices from the used/unused slice lists */
13370Sstevel@tonic-gate 		    error = create_usable_slices(disk, used_slices_on_this_disk,
13380Sstevel@tonic-gate 			unused_slices_on_this_disk, usable_slices);
13390Sstevel@tonic-gate 		    if (error == 0) {
1340*62Sjeanm 			error = dlist_append_object((void *)(uintptr_t)disk,
1341*62Sjeanm 			    usable_disks, AT_TAIL);
13420Sstevel@tonic-gate 		    }
13430Sstevel@tonic-gate 		}
13440Sstevel@tonic-gate 	    }
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	    dlist_free_items(slices, NULL);
13470Sstevel@tonic-gate 	    dlist_free_items(used_slices_on_this_disk, NULL);
13480Sstevel@tonic-gate 	    dlist_free_items(unused_slices_on_this_disk, NULL);
13490Sstevel@tonic-gate 	}
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	return (error);
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate /*
13550Sstevel@tonic-gate  * FUNCTION:	create_usable_slices(dm_descriptor_t disk, dlist_t *used,
13560Sstevel@tonic-gate  *			dlist_t *unused, dlist_t **usable);
13570Sstevel@tonic-gate  *
13580Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t disk handle
13590Sstevel@tonic-gate  *		used	- pointer to a list of pvt_t structs
13600Sstevel@tonic-gate  *			  representing existing used slices
13610Sstevel@tonic-gate  *			  on the input disk.
13620Sstevel@tonic-gate  *		unused	- pointer to a list of pvt_t structs
13630Sstevel@tonic-gate  *			  representing existing unused slices
13640Sstevel@tonic-gate  *			  on the input disk.
13650Sstevel@tonic-gate  *
13660Sstevel@tonic-gate  * OUTPUT:	usable	- pointer to a list of pvts representing slices
13670Sstevel@tonic-gate  *			which can be used for new volume layouts.
13680Sstevel@tonic-gate  *
13690Sstevel@tonic-gate  *			Slices in this list have any available space on the
13700Sstevel@tonic-gate  *			disk collected into the fewest, lowest indexed slices
13710Sstevel@tonic-gate  *			possible.
13720Sstevel@tonic-gate  *
13730Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
13740Sstevel@tonic-gate  *			 !0 otherwise.
13750Sstevel@tonic-gate  *
13760Sstevel@tonic-gate  * PURPOSE:	helper for generate_usable_slices_and_disks_in_diskset() which
13770Sstevel@tonic-gate  *		turns any detected free space on the input disk into one or
13780Sstevel@tonic-gate  *		more slices.
13790Sstevel@tonic-gate  */
13800Sstevel@tonic-gate static int
create_usable_slices(dm_descriptor_t disk,dlist_t * used,dlist_t * unused,dlist_t ** usable)13810Sstevel@tonic-gate create_usable_slices(
13820Sstevel@tonic-gate 	dm_descriptor_t disk,
13830Sstevel@tonic-gate 	dlist_t		*used,
13840Sstevel@tonic-gate 	dlist_t		*unused,
13850Sstevel@tonic-gate 	dlist_t		**usable)
13860Sstevel@tonic-gate {
13870Sstevel@tonic-gate 	dlist_t		*iter;
13880Sstevel@tonic-gate 	int		error = 0;
13890Sstevel@tonic-gate 	boolean_t	first = B_TRUE;
13900Sstevel@tonic-gate 	dlist_t		*next_unused = unused;
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	char		*dname = NULL;
13930Sstevel@tonic-gate 	uint64_t 	disk_firstblk = 0;
13940Sstevel@tonic-gate 	uint64_t 	disk_nblks = 0;
13950Sstevel@tonic-gate 	uint64_t 	disk_endblk = 0;
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	oprintf(OUTPUT_DEBUG,
13980Sstevel@tonic-gate 		gettext("\n  create_usable_slices for disk\n"));
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 	/* get necessary info about disk: */
14010Sstevel@tonic-gate 	error = get_display_name(disk, &dname);
14020Sstevel@tonic-gate 	if (error != 0) {
14030Sstevel@tonic-gate 	    return (error);
14040Sstevel@tonic-gate 	}
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	/* disk start block is first usable block */
14070Sstevel@tonic-gate 	error = disk_get_start_block(disk, &disk_firstblk);
14080Sstevel@tonic-gate 	if (error != 0) {
14090Sstevel@tonic-gate 	    return (error);
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	/* disk size determines last usable disk block */
14130Sstevel@tonic-gate 	error = disk_get_size_in_blocks(disk, &disk_nblks);
14140Sstevel@tonic-gate 	if (error != 0) {
14150Sstevel@tonic-gate 	    return (error);
14160Sstevel@tonic-gate 	}
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	disk_endblk = disk_firstblk + disk_nblks - 1;
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	/* search for gaps before, between and after used slices */
14210Sstevel@tonic-gate 	for (iter = used; iter != NULL && error == 0; iter = iter->next) {
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	    dm_descriptor_t cur = (uintptr_t)iter->obj;
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 	    uint64_t cur_stblk = 0;
14260Sstevel@tonic-gate 	    uint64_t cur_nblks = 0;
14270Sstevel@tonic-gate 	    uint64_t cur_endblk = 0;
14280Sstevel@tonic-gate 	    uint32_t cur_index = 0;
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	    uint64_t new_stblk = 0;
14310Sstevel@tonic-gate 	    uint64_t new_endblk = 0;
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	    char *sname = NULL;
14340Sstevel@tonic-gate 	    (void) get_display_name(cur, &sname);
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	    if (((error = slice_get_index(cur, &cur_index)) != 0) ||
14370Sstevel@tonic-gate 		((error = slice_get_start_block(cur, &cur_stblk)) != 0) ||
14380Sstevel@tonic-gate 		((error = slice_get_size_in_blocks(cur, &cur_nblks)) != 0)) {
14390Sstevel@tonic-gate 		continue;
14400Sstevel@tonic-gate 	    }
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	    cur_endblk = cur_stblk + cur_nblks - 1;
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
14450Sstevel@tonic-gate 		    gettext("  used slice %d (%10llu to %10llu)\n"),
14460Sstevel@tonic-gate 		    cur_index, cur_stblk, cur_endblk);
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 	    if (first == B_TRUE) {
14490Sstevel@tonic-gate 		/* first slice: make sure it starts at disk_firstblk */
14500Sstevel@tonic-gate 		first = B_FALSE;
14510Sstevel@tonic-gate 		if (cur_stblk != disk_firstblk) {
14520Sstevel@tonic-gate 		    /* close gap at beginning of disk */
14530Sstevel@tonic-gate 		    new_stblk = disk_firstblk;
14540Sstevel@tonic-gate 		    new_endblk = cur_stblk - 1;
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
14570Sstevel@tonic-gate 			    gettext("    unused space before first "
14580Sstevel@tonic-gate 				    "used slice\n"));
14590Sstevel@tonic-gate 		}
14600Sstevel@tonic-gate 	    }
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	    if (iter->next != NULL) {
14630Sstevel@tonic-gate 		/* check for gap between slices */
14640Sstevel@tonic-gate 		dm_descriptor_t next = (uintptr_t)iter->next->obj;
14650Sstevel@tonic-gate 		uint64_t next_stblk = 0;
14660Sstevel@tonic-gate 		uint32_t next_index = 0;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 		if (((error = slice_get_start_block(next, &next_stblk)) == 0) &&
14690Sstevel@tonic-gate 		    ((error = slice_get_index(next, &next_index)) == 0)) {
14700Sstevel@tonic-gate 		    if (cur_endblk != next_stblk - 1) {
14710Sstevel@tonic-gate 			/* close gap between slices */
14720Sstevel@tonic-gate 			new_stblk = cur_endblk + 1;
14730Sstevel@tonic-gate 			new_endblk = next_stblk - 1;
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 			oprintf(OUTPUT_DEBUG,
14760Sstevel@tonic-gate 				gettext("    unused space between slices "
14770Sstevel@tonic-gate 					"%d and %d\n"), cur_index, next_index);
14780Sstevel@tonic-gate 		    }
14790Sstevel@tonic-gate 		}
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 	    } else {
14820Sstevel@tonic-gate 		/* last slice: make sure it includes last block on disk */
14830Sstevel@tonic-gate 		if (cur_endblk != disk_endblk) {
14840Sstevel@tonic-gate 		    /* close gap at end of disk */
14850Sstevel@tonic-gate 		    new_stblk = cur_endblk + 1;
14860Sstevel@tonic-gate 		    new_endblk = disk_endblk;
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
14890Sstevel@tonic-gate 			    gettext("    unused space after last slice "
14900Sstevel@tonic-gate 				    "cur_endblk: %llu disk_endblk: %llu\n"),
14910Sstevel@tonic-gate 			    cur_endblk, disk_endblk);
14920Sstevel@tonic-gate 		}
14930Sstevel@tonic-gate 	    }
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 	    if ((error == 0) && (new_endblk != 0)) {
14960Sstevel@tonic-gate 		error = add_new_usable(disk, new_stblk,
14970Sstevel@tonic-gate 			new_endblk - new_stblk + 1, &next_unused, usable);
14980Sstevel@tonic-gate 	    }
14990Sstevel@tonic-gate 	}
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	if (error != 0) {
15020Sstevel@tonic-gate 	    dlist_free_items(*usable, free);
15030Sstevel@tonic-gate 	    *usable = NULL;
15040Sstevel@tonic-gate 	}
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	return (error);
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate /*
15100Sstevel@tonic-gate  * FUNCTION:	add_new_usable(dm_descriptor_t disk, uint64_t stblk,
15110Sstevel@tonic-gate  *			uint64_t nblks, dlist_t **next_unused,
15120Sstevel@tonic-gate  *			dlist_t **usable);
15130Sstevel@tonic-gate  *
15140Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t disk handle
15150Sstevel@tonic-gate  *		stblk	- start block of the usable space
15160Sstevel@tonic-gate  *		nblks	- number of usable blocks
15170Sstevel@tonic-gate  *		next_unused	- pointer to the next unused slice
15180Sstevel@tonic-gate  *
15190Sstevel@tonic-gate  * OUTPUT:	next_unused	- updated pointer to the next unused slice
15200Sstevel@tonic-gate  *		usable	- possibly updated pointer to a list of slices on
15210Sstevel@tonic-gate  *			the disk with usable space
15220Sstevel@tonic-gate  *
15230Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
15240Sstevel@tonic-gate  *			 !0 otherwise.
15250Sstevel@tonic-gate  *
15260Sstevel@tonic-gate  * PURPOSE:	helper for create_usable_slices() which turns free space
15270Sstevel@tonic-gate  *		on the input disk into a usable slice.
15280Sstevel@tonic-gate  *
15290Sstevel@tonic-gate  *		If possible an existing unused slice will be recycled
15300Sstevel@tonic-gate  *		into a usable slice. If there are none, a new virtual
15310Sstevel@tonic-gate  *		slice will be created.
15320Sstevel@tonic-gate  */
15330Sstevel@tonic-gate static int
add_new_usable(dm_descriptor_t disk,uint64_t stblk,uint64_t nblks,dlist_t ** next_unused,dlist_t ** usable)15340Sstevel@tonic-gate add_new_usable(
15350Sstevel@tonic-gate 	dm_descriptor_t disk,
15360Sstevel@tonic-gate 	uint64_t	stblk,
15370Sstevel@tonic-gate 	uint64_t	nblks,
15380Sstevel@tonic-gate 	dlist_t		**next_unused,
15390Sstevel@tonic-gate 	dlist_t		**usable)
15400Sstevel@tonic-gate {
15410Sstevel@tonic-gate 	dm_descriptor_t new_usable = 0;
15420Sstevel@tonic-gate 	int		error = 0;
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	/* try to use an existing unused slice for the usable slice */
15450Sstevel@tonic-gate 	if (*next_unused != NULL) {
15460Sstevel@tonic-gate 	    new_usable = (uintptr_t)((*next_unused)->obj);
15470Sstevel@tonic-gate 	    *next_unused = (*next_unused)->next;
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
15500Sstevel@tonic-gate 		    gettext("\trecyling used slice into usable slice "
15510Sstevel@tonic-gate 			    "start: %llu, end: %llu\n"),
15520Sstevel@tonic-gate 		    stblk, stblk + nblks + 1);
15530Sstevel@tonic-gate 	}
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 	if (new_usable == NULL) {
15560Sstevel@tonic-gate 	    /* no unused slices, try to make a new virtual slice */
15570Sstevel@tonic-gate 	    uint32_t index = UINT32_MAX;
15580Sstevel@tonic-gate 	    error = disk_get_available_slice_index(disk, &index);
15590Sstevel@tonic-gate 	    if ((error == 0) && (index != UINT32_MAX)) {
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 		char *dname = NULL;
15620Sstevel@tonic-gate 		error = get_display_name(disk, &dname);
15630Sstevel@tonic-gate 		if (error == 0) {
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 		    char buf[MAXNAMELEN];
15660Sstevel@tonic-gate 		    (void) snprintf(buf, MAXNAMELEN-1, "%ss%d", dname, index);
15670Sstevel@tonic-gate 		    error = add_virtual_slice(buf, index, 0, 0, disk);
15680Sstevel@tonic-gate 		    if (error == 0) {
15690Sstevel@tonic-gate 			/* retrieve the virtual slice */
15700Sstevel@tonic-gate 			error = slice_get_by_name(buf, &new_usable);
15710Sstevel@tonic-gate 		    }
15720Sstevel@tonic-gate 		}
15730Sstevel@tonic-gate 	    }
15740Sstevel@tonic-gate 	}
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	if ((error == 0) && (new_usable != (dm_descriptor_t)0)) {
15770Sstevel@tonic-gate 	    /* BEGIN CSTYLED */
15780Sstevel@tonic-gate 	    /*
15790Sstevel@tonic-gate 	     * have an unused slice, update its attributes to reflect
15800Sstevel@tonic-gate 	     * the usable space it represents
15810Sstevel@tonic-gate 	     */
15820Sstevel@tonic-gate 	    /* END CSTYLED */
15830Sstevel@tonic-gate 	    uint64_t disk_blksz = 0;
15840Sstevel@tonic-gate 	    error = disk_get_blocksize(disk, &disk_blksz);
15850Sstevel@tonic-gate 	    if (error == 0) {
15860Sstevel@tonic-gate 		error = update_slice_attributes(new_usable, stblk,
15870Sstevel@tonic-gate 		    nblks, nblks * disk_blksz);
15880Sstevel@tonic-gate 		if (error == 0) {
15890Sstevel@tonic-gate 		    error = dlist_append_object(
1590*62Sjeanm 			(void *)(uintptr_t)new_usable, usable, AT_TAIL);
15910Sstevel@tonic-gate 		}
15920Sstevel@tonic-gate 	    }
15930Sstevel@tonic-gate 	}
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	return (error);
15960Sstevel@tonic-gate }
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate /*
15990Sstevel@tonic-gate  * FUNCTION:	update_slice_attributes(dm_descriptor_t slice, uint64_t stblk,
16000Sstevel@tonic-gate  *			uint64_t nblks, uint64_t nbytes)
16010Sstevel@tonic-gate  *
16020Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t slice handle
16030Sstevel@tonic-gate  *		stblk	- start block of the usable space
16040Sstevel@tonic-gate  *		nblks	- size of slice in blocks
16050Sstevel@tonic-gate  *		nbytes	- size of slice in bytes
16060Sstevel@tonic-gate  *
16070Sstevel@tonic-gate  * SIDEEFFECT:	adds a modification record for the slice.
16080Sstevel@tonic-gate  *
16090Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
16100Sstevel@tonic-gate  *			 !0 otherwise.
16110Sstevel@tonic-gate  *
16120Sstevel@tonic-gate  * PURPOSE:	utility which updates several slice attributes in one call.
16130Sstevel@tonic-gate  */
16140Sstevel@tonic-gate static int
update_slice_attributes(dm_descriptor_t slice,uint64_t stblk,uint64_t nblks,uint64_t nbytes)16150Sstevel@tonic-gate update_slice_attributes(
16160Sstevel@tonic-gate 	dm_descriptor_t slice,
16170Sstevel@tonic-gate 	uint64_t	stblk,
16180Sstevel@tonic-gate 	uint64_t	nblks,
16190Sstevel@tonic-gate 	uint64_t	nbytes)
16200Sstevel@tonic-gate {
16210Sstevel@tonic-gate 	char		*sname = NULL;
16220Sstevel@tonic-gate 	uint32_t	 index = 0;
16230Sstevel@tonic-gate 	int		error = 0;
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 	if ((error = get_display_name(slice, &sname)) == 0) {
16260Sstevel@tonic-gate 	    if ((error = slice_get_index(slice, &index)) == 0) {
16270Sstevel@tonic-gate 		if ((error = slice_set_start_block(slice, stblk)) == 0) {
16280Sstevel@tonic-gate 		    if ((error = slice_set_size_in_blocks(slice, nblks)) == 0) {
16290Sstevel@tonic-gate 			if (nblks == 0) {
16300Sstevel@tonic-gate 			    error = add_slice_to_remove(sname, index);
16310Sstevel@tonic-gate 			} else {
16320Sstevel@tonic-gate 			    error = assemble_modified_slice((dm_descriptor_t)0,
16330Sstevel@tonic-gate 				    sname, index, stblk, nblks, nbytes, NULL);
16340Sstevel@tonic-gate 			}
16350Sstevel@tonic-gate 		    }
16360Sstevel@tonic-gate 		}
16370Sstevel@tonic-gate 	    }
16380Sstevel@tonic-gate 	}
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 	return (error);
16410Sstevel@tonic-gate }
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate /*
16440Sstevel@tonic-gate  * FUNCTION:	generate_usable_hbas(dlist_t *slices,
16450Sstevel@tonic-gate  *			dlist_t **usable)
16460Sstevel@tonic-gate  *
16470Sstevel@tonic-gate  * INPUT:	disks	- a list of usable disks.
16480Sstevel@tonic-gate  *
16490Sstevel@tonic-gate  * OUTPUT:	usable	- a populated list of usable HBAs.
16500Sstevel@tonic-gate  *
16510Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
16520Sstevel@tonic-gate  *			 !0 otherwise
16530Sstevel@tonic-gate  *
16540Sstevel@tonic-gate  * PURPOSE:	Examines usable disk list and derives the list of usable HBAs.
16550Sstevel@tonic-gate  *
16560Sstevel@tonic-gate  */
16570Sstevel@tonic-gate static int
generate_usable_hbas(dlist_t * disks,dlist_t ** usable)16580Sstevel@tonic-gate generate_usable_hbas(
16590Sstevel@tonic-gate 	dlist_t *disks,
16600Sstevel@tonic-gate 	dlist_t	**usable)
16610Sstevel@tonic-gate {
16620Sstevel@tonic-gate 	dlist_t	*iter;
16630Sstevel@tonic-gate 	int	error = 0;
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 	/*
16660Sstevel@tonic-gate 	 * for each usable disk, follow its HBA connections and
16670Sstevel@tonic-gate 	 * add them to the list of usable HBAs.
16680Sstevel@tonic-gate 	 */
16690Sstevel@tonic-gate 	for (iter = disks; (iter != NULL) && (error == 0); iter = iter->next) {
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	    dm_descriptor_t	dp = NULL;
16720Sstevel@tonic-gate 	    dlist_t 		*hbas = NULL;
16730Sstevel@tonic-gate 	    dlist_t		*iter2 = NULL;
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	    dp = (uintptr_t)iter->obj;
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	    error = disk_get_hbas(dp, &hbas);
16780Sstevel@tonic-gate 	    if (error == 0) {
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 		for (iter2 = hbas;
16810Sstevel@tonic-gate 		    (iter2 != NULL) && (error == 0);
16820Sstevel@tonic-gate 		    iter2 = iter2->next) {
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 		    dm_descriptor_t	hba = (uintptr_t)iter2->obj;
16850Sstevel@tonic-gate 		    dlist_t		*item = NULL;
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 		    /* scan list of usable HBAs and see if known */
1688*62Sjeanm 		    if (dlist_contains(*usable, (void*)(uintptr_t)hba,
1689*62Sjeanm 			compare_descriptor_names) == B_TRUE) {
16900Sstevel@tonic-gate 			/* known HBA, continue to next HBA/alias */
16910Sstevel@tonic-gate 			continue;
16920Sstevel@tonic-gate 		    }
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 		    /* add this HBA to the usable list */
1695*62Sjeanm 		    if ((item = dlist_new_item((void *)(uintptr_t)hba)) ==
1696*62Sjeanm 			NULL) {
16970Sstevel@tonic-gate 			error = ENOMEM;
16980Sstevel@tonic-gate 		    } else {
16990Sstevel@tonic-gate 			*usable =
17000Sstevel@tonic-gate 			    dlist_insert_ordered(item, *usable,
17010Sstevel@tonic-gate 				    ASCENDING, compare_desc_display_names);
17020Sstevel@tonic-gate 		    }
17030Sstevel@tonic-gate 		}
17040Sstevel@tonic-gate 	    }
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 	    dlist_free_items(hbas, NULL);
17070Sstevel@tonic-gate 	}
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 	return (error);
17100Sstevel@tonic-gate }
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate /*
17130Sstevel@tonic-gate  * FUNCTION:	check_slice_usage(char *dsname, dm_descriptor_t slice,
17140Sstevel@tonic-gate  *			dm_descriptor_t disk, boolean_t *avail,
17150Sstevel@tonic-gate  *			dlist_t **bad, dlist_t **classes)
17160Sstevel@tonic-gate  *
17170Sstevel@tonic-gate  * INPUT:	dsname	- a char * diskset name.
17180Sstevel@tonic-gate  *		slice	- a dm_descriptor_t handle for a known slices.
17190Sstevel@tonic-gate  *		disk	- a dm_descriptor_t handle the slice's disk.
17200Sstevel@tonic-gate  *
17210Sstevel@tonic-gate  * OUTPUT:	avail	- a boolean_t to hold the slice's availability.
17220Sstevel@tonic-gate  *		bad	- pointer to a list of bad/unusable slices,
17230Sstevel@tonic-gate  *				possibly updated if the input slice
17240Sstevel@tonic-gate  *				was determined to be inaccessible.
17250Sstevel@tonic-gate  *		classes	- pointer to a list of slice_class_t structs,
17260Sstevel@tonic-gate  *				possibly updated to include the input slice
17270Sstevel@tonic-gate  *				if it has a known use.
17280Sstevel@tonic-gate  *
17290Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
17300Sstevel@tonic-gate  *			 !0 otherwise.
17310Sstevel@tonic-gate  *
17320Sstevel@tonic-gate  * PURPOSE:	Handles the details of
17330Sstevel@tonic-gate  *		determining usage and/or availability of a single slice.
17340Sstevel@tonic-gate  *
17350Sstevel@tonic-gate  *		Queries the device library for the input slice's detectable
17360Sstevel@tonic-gate  *		usage status.
17370Sstevel@tonic-gate  *
17380Sstevel@tonic-gate  *		If the slice has a detected usage, its name is added to
17390Sstevel@tonic-gate  *		the appropriate slice_class_t list in the input list of
17400Sstevel@tonic-gate  *		slice classes, this is only done if verbose output was
17410Sstevel@tonic-gate  * 		requested.
17420Sstevel@tonic-gate  */
17430Sstevel@tonic-gate static int
check_slice_usage(char * dsname,dm_descriptor_t slice,dm_descriptor_t disk,boolean_t * avail,dlist_t ** bad,dlist_t ** classes)17440Sstevel@tonic-gate check_slice_usage(
17450Sstevel@tonic-gate 	char		*dsname,
17460Sstevel@tonic-gate 	dm_descriptor_t slice,
17470Sstevel@tonic-gate 	dm_descriptor_t disk,
17480Sstevel@tonic-gate 	boolean_t	*avail,
17490Sstevel@tonic-gate 	dlist_t		**bad,
17500Sstevel@tonic-gate 	dlist_t		**classes)
17510Sstevel@tonic-gate {
17520Sstevel@tonic-gate 	boolean_t	online = B_FALSE;
17530Sstevel@tonic-gate 	boolean_t	used = B_FALSE;
17540Sstevel@tonic-gate 	nvlist_t	*stats = NULL;
17550Sstevel@tonic-gate 	char		*name = NULL;
17560Sstevel@tonic-gate 	char		*used_by = NULL;
17570Sstevel@tonic-gate 	char		*use_detail = NULL;
17580Sstevel@tonic-gate 	int		error = 0;
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	*avail = B_FALSE;
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 	if (((error = get_display_name(slice, &name)) != 0) ||
17630Sstevel@tonic-gate 	    (error = disk_get_is_online(disk, &online))) {
17640Sstevel@tonic-gate 	    return (error);
17650Sstevel@tonic-gate 	}
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 	/*
17680Sstevel@tonic-gate 	 * if the disk is known to be offline, skip getting status
17690Sstevel@tonic-gate 	 * for the slice since it will just fail and return ENODEV.
17700Sstevel@tonic-gate 	 */
17710Sstevel@tonic-gate 	if (online != B_TRUE) {
17720Sstevel@tonic-gate 	    error = ENODEV;
17730Sstevel@tonic-gate 	} else {
17740Sstevel@tonic-gate 	    stats = dm_get_stats(slice, DM_SLICE_STAT_USE, &error);
17750Sstevel@tonic-gate 	}
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	if (error != 0) {
17780Sstevel@tonic-gate 	    if (error == ENODEV) {
1779*62Sjeanm 		dlist_t *item = dlist_new_item((void *)(uintptr_t)slice);
17800Sstevel@tonic-gate 		oprintf(OUTPUT_TERSE,
17810Sstevel@tonic-gate 			gettext("Warning: unable to get slice information "
17820Sstevel@tonic-gate 				"for %s, it will not be used.\n"), name);
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 		if (item == NULL) {
17850Sstevel@tonic-gate 		    error = ENOMEM;
17860Sstevel@tonic-gate 		} else {
17870Sstevel@tonic-gate 		    error = 0;
17880Sstevel@tonic-gate 		    *bad = dlist_insert_ordered(item, *bad, ASCENDING,
17890Sstevel@tonic-gate 			    compare_desc_display_names);
17900Sstevel@tonic-gate 		}
17910Sstevel@tonic-gate 	    } else {
17920Sstevel@tonic-gate 		oprintf(OUTPUT_TERSE,
17930Sstevel@tonic-gate 			gettext("check_slice_usage: dm_get_stats for "
17940Sstevel@tonic-gate 				"%s failed %d\n"),
17950Sstevel@tonic-gate 			name, error);
17960Sstevel@tonic-gate 	    }
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 	    return (error);
17990Sstevel@tonic-gate 	}
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 	/*
18020Sstevel@tonic-gate 	 * check if/how the slice is currently being used,
18030Sstevel@tonic-gate 	 * device library provides this info in the nvpair_t list:
18040Sstevel@tonic-gate 	 *
18050Sstevel@tonic-gate 	 *   stat_type is DM_SLICE_STAT_USE
18060Sstevel@tonic-gate 	 *	used_by:	string (mount, svm, lu, vxvm, fs)
18070Sstevel@tonic-gate 	 *	used_name:	string
18080Sstevel@tonic-gate 	 *
18090Sstevel@tonic-gate 	 */
18100Sstevel@tonic-gate 	if (stats != NULL) {
18110Sstevel@tonic-gate 	    error = get_string(stats, DM_USED_BY, &used_by);
18120Sstevel@tonic-gate 	    if (error != 0) {
18130Sstevel@tonic-gate 		if (error == ENOENT) {
18140Sstevel@tonic-gate 		    used_by = NULL;
18150Sstevel@tonic-gate 		    error = 0;
18160Sstevel@tonic-gate 		} else {
18170Sstevel@tonic-gate 		    oprintf(OUTPUT_TERSE,
18180Sstevel@tonic-gate 			    gettext("check_slice_usage: dm_get_stats.%s for "
18190Sstevel@tonic-gate 				    "%s failed %d\n"),
18200Sstevel@tonic-gate 			    DM_USED_BY, name, error);
18210Sstevel@tonic-gate 		}
18220Sstevel@tonic-gate 	    }
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 	    if (error == 0) {
18250Sstevel@tonic-gate 		error = get_string(stats, DM_USED_NAME, &use_detail);
18260Sstevel@tonic-gate 		if (error != 0) {
18270Sstevel@tonic-gate 		    if (error == ENOENT) {
18280Sstevel@tonic-gate 			use_detail = NULL;
18290Sstevel@tonic-gate 			error = 0;
18300Sstevel@tonic-gate 		    } else {
18310Sstevel@tonic-gate 			oprintf(OUTPUT_TERSE,
18320Sstevel@tonic-gate 				gettext("check_slice_usage: "
18330Sstevel@tonic-gate 					"dm_get_stats.%s for "
18340Sstevel@tonic-gate 					"%s failed %d\n"),
18350Sstevel@tonic-gate 					DM_USED_NAME, name, error);
18360Sstevel@tonic-gate 		    }
18370Sstevel@tonic-gate 		}
18380Sstevel@tonic-gate 	    }
18390Sstevel@tonic-gate 	}
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 	if ((error == 0) && (used_by != NULL) && (used_by[0] != '\0')) {
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate 	    /* was detected usage SVM? */
18440Sstevel@tonic-gate 	    if (string_case_compare(used_by, DM_USE_SVM) == 0) {
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 		/* check use_detail, it is in the form diskset:name */
18470Sstevel@tonic-gate 		if (strncmp("diskset:", use_detail, 8) == 0) {
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 		    /* check disk set name */
18500Sstevel@tonic-gate 		    char *str = strrchr(use_detail, ':');
18510Sstevel@tonic-gate 		    if ((str != NULL) &&
18520Sstevel@tonic-gate 			    (string_case_compare(str+1, dsname) == 0)) {
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 			/* slice in the right diskset */
18550Sstevel@tonic-gate 			error = check_svm_slice_usage(
18560Sstevel@tonic-gate 				dsname, slice, disk, &used, classes);
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 		    } else {
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 			/* slice in other diskset */
18610Sstevel@tonic-gate 			save_slice_classification(
18620Sstevel@tonic-gate 				dsname, slice, disk, used_by, use_detail,
18630Sstevel@tonic-gate 				classes);
18640Sstevel@tonic-gate 			used = B_TRUE;
18650Sstevel@tonic-gate 		    }
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate 		} else {
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 		    /* slice is volume component */
18700Sstevel@tonic-gate 		    save_slice_classification(
18710Sstevel@tonic-gate 			    dsname, slice, disk, used_by, use_detail,
18720Sstevel@tonic-gate 			    classes);
18730Sstevel@tonic-gate 		    used = B_TRUE;
18740Sstevel@tonic-gate 		}
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 	    } else {
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 		/* save usage */
18790Sstevel@tonic-gate 		save_slice_classification(
18800Sstevel@tonic-gate 			dsname, slice, disk, used_by, use_detail,
18810Sstevel@tonic-gate 			classes);
18820Sstevel@tonic-gate 		used = B_TRUE;
18830Sstevel@tonic-gate 	    }
18840Sstevel@tonic-gate 	}
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	nvlist_free(stats);
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 	if (error == 0) {
18890Sstevel@tonic-gate 	    if (used == B_TRUE) {
18900Sstevel@tonic-gate 		*avail = B_FALSE;
18910Sstevel@tonic-gate 	    } else {
18920Sstevel@tonic-gate 		*avail = B_TRUE;
18930Sstevel@tonic-gate 	    }
18940Sstevel@tonic-gate 	}
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	return (error);
18970Sstevel@tonic-gate }
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate /*
19000Sstevel@tonic-gate  * FUNCTION:	check_svm_slice_usage(char *dsname, dm_descriptor_t slice,
19010Sstevel@tonic-gate  *			dm_descriptor_t disk, boolean_t *used,
19020Sstevel@tonic-gate  *			dlist_t **classes)
19030Sstevel@tonic-gate  *
19040Sstevel@tonic-gate  * INPUT:	dsname	- a char * diskset name.
19050Sstevel@tonic-gate  *		slice	- a dm_descriptor_t handle for a known slices.
19060Sstevel@tonic-gate  *		disk	- a dm_descriptor_t handle the slice's disk.
19070Sstevel@tonic-gate  *
19080Sstevel@tonic-gate  * OUTPUT:	used	- a boolean_t to hold the slice usage status.
19090Sstevel@tonic-gate  *		classes	- pointer to a list of slice_class_t possibly updated
19100Sstevel@tonic-gate  *				with the input slice's SVM specific usage
19110Sstevel@tonic-gate  *				classification.
19120Sstevel@tonic-gate  *
19130Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
19140Sstevel@tonic-gate  *			 !0 otherwise.
19150Sstevel@tonic-gate  *
19160Sstevel@tonic-gate  * PURPOSE:	Handles the finer details of
19170Sstevel@tonic-gate  *		a single slice is being used in the context of SVM.
19180Sstevel@tonic-gate  *
19190Sstevel@tonic-gate  *		Currently, one thing is checked:
19200Sstevel@tonic-gate  *
19210Sstevel@tonic-gate  *		1. determine if the slice is reserved for metadb replicas.
19220Sstevel@tonic-gate  *		   The convention for disks in disksets is that a single slice
19230Sstevel@tonic-gate  *		   (index 6 or 7) is set aside for metadb replicas.
19240Sstevel@tonic-gate  *
19250Sstevel@tonic-gate  *		If this condition does not hold, the slice is considered
19260Sstevel@tonic-gate  *		available for use by layout and 'used' is set to B_FALSE.
19270Sstevel@tonic-gate  */
19280Sstevel@tonic-gate static int
check_svm_slice_usage(char * dsname,dm_descriptor_t slice,dm_descriptor_t disk,boolean_t * used,dlist_t ** classes)19290Sstevel@tonic-gate check_svm_slice_usage(
19300Sstevel@tonic-gate 	char		*dsname,
19310Sstevel@tonic-gate 	dm_descriptor_t slice,
19320Sstevel@tonic-gate 	dm_descriptor_t disk,
19330Sstevel@tonic-gate 	boolean_t	*used,
19340Sstevel@tonic-gate 	dlist_t		**classes)
19350Sstevel@tonic-gate {
19360Sstevel@tonic-gate 	boolean_t is_replica = B_FALSE;
19370Sstevel@tonic-gate 	uint32_t index = 0;
19380Sstevel@tonic-gate 	char	*diskname = NULL;
19390Sstevel@tonic-gate 	int	error = 0;
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 	((error = slice_get_index(slice, &index)) != 0) ||
19420Sstevel@tonic-gate 	(error = get_display_name(disk, &diskname)) ||
19430Sstevel@tonic-gate 	(error = is_reserved_replica_slice_index(
19440Sstevel@tonic-gate 		dsname, diskname, index, &is_replica));
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	if (error == 0) {
19470Sstevel@tonic-gate 	    if (is_replica == B_TRUE) {
19480Sstevel@tonic-gate 		/* is replica slice -> used */
19490Sstevel@tonic-gate 		save_slice_classification(dsname, slice, disk, DM_USE_SVM,
19500Sstevel@tonic-gate 			gettext("reserved for metadb replicas"), classes);
19510Sstevel@tonic-gate 		*used = B_TRUE;
19520Sstevel@tonic-gate 	    } else {
19530Sstevel@tonic-gate 		*used = B_FALSE;
19540Sstevel@tonic-gate 	    }
19550Sstevel@tonic-gate 	}
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate 	return (error);
19580Sstevel@tonic-gate }
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate /*
19610Sstevel@tonic-gate  * FUNCTION:	save_slice_classification(char *dsname, dm_descriptor_t slice,
19620Sstevel@tonic-gate  *			dm_descriptor_t disk, char *used_by, char *usage_detail,
19630Sstevel@tonic-gate  *			dlist_t **classes)
19640Sstevel@tonic-gate  *
19650Sstevel@tonic-gate  * INPUT:	dsname	- a char * disk set name
19660Sstevel@tonic-gate  *		slice	- a dm_descriptor_t slice handle.
19670Sstevel@tonic-gate  *		disk	- a dm_descriptor_t handle for the slice's disk.
19680Sstevel@tonic-gate  *		used_by - a char * usage classification.
19690Sstevel@tonic-gate  *		usage_detail - a char * usage description for the slice.
19700Sstevel@tonic-gate  *
19710Sstevel@tonic-gate  * OUTPUT:	classes	- a list of slice_class_t updated to hold a usage
19720Sstevel@tonic-gate  *				entry for the input slicexs.
19730Sstevel@tonic-gate  *
19740Sstevel@tonic-gate  * SIDEEFFECT:	adds the input slice to the list of known, used slices.
19750Sstevel@tonic-gate  *
19760Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
19770Sstevel@tonic-gate  *			 !0 otherwise.
19780Sstevel@tonic-gate  *
19790Sstevel@tonic-gate  * PURPOSE:	Adds an entry to the
19800Sstevel@tonic-gate  *		appropriate slice_class_t list of slices.  If there is
19810Sstevel@tonic-gate  *		not an appropriate slice_class_t entry in the input list
19820Sstevel@tonic-gate  *		of classes, one is added.
19830Sstevel@tonic-gate  *
19840Sstevel@tonic-gate  *		As a performance optimization the slice usage classification
19850Sstevel@tonic-gate  *		information is only saved if verbose output was requested by
19860Sstevel@tonic-gate  *		the user.
19870Sstevel@tonic-gate  */
19880Sstevel@tonic-gate static int
save_slice_classification(char * dsname,dm_descriptor_t slice,dm_descriptor_t disk,char * usage,char * usage_detail,dlist_t ** classes)19890Sstevel@tonic-gate save_slice_classification(
19900Sstevel@tonic-gate 	char		*dsname,
19910Sstevel@tonic-gate 	dm_descriptor_t	slice,
19920Sstevel@tonic-gate 	dm_descriptor_t	disk,
19930Sstevel@tonic-gate 	char		*usage,
19940Sstevel@tonic-gate 	char		*usage_detail,
19950Sstevel@tonic-gate 	dlist_t		**classes)
19960Sstevel@tonic-gate {
19970Sstevel@tonic-gate 	int		error = 0;
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate 	error = add_used_slice(slice);
20000Sstevel@tonic-gate 
20010Sstevel@tonic-gate 	if ((error == 0) && (get_max_verbosity() >= OUTPUT_VERBOSE)) {
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	    dlist_t		*iter;
20040Sstevel@tonic-gate 	    dlist_t		*item;
20050Sstevel@tonic-gate 	    slice_class_t 	*class = NULL;
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate 	    /* locate class struct matching 'usage' */
20080Sstevel@tonic-gate 	    for (iter = *classes; iter != NULL; iter = iter->next) {
20090Sstevel@tonic-gate 		class = (slice_class_t *)iter->obj;
20100Sstevel@tonic-gate 		if (string_case_compare(usage, class->usage) == 0) {
20110Sstevel@tonic-gate 		    break;
20120Sstevel@tonic-gate 		}
20130Sstevel@tonic-gate 	    }
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	    if (iter == NULL) {
20160Sstevel@tonic-gate 		/* add a new class to the list of classes */
20170Sstevel@tonic-gate 		class = (slice_class_t *)calloc(1, sizeof (slice_class_t));
20180Sstevel@tonic-gate 		if (class == NULL) {
20190Sstevel@tonic-gate 		    error = ENOMEM;
20200Sstevel@tonic-gate 		} else {
20210Sstevel@tonic-gate 		    class->usage = strdup(usage);
20220Sstevel@tonic-gate 		    if (class->usage == NULL) {
20230Sstevel@tonic-gate 			free(class);
20240Sstevel@tonic-gate 			class = NULL;
20250Sstevel@tonic-gate 			error = ENOMEM;
20260Sstevel@tonic-gate 		    } else {
20270Sstevel@tonic-gate 			item = dlist_new_item((void *)class);
20280Sstevel@tonic-gate 			if (item == NULL) {
20290Sstevel@tonic-gate 			    free(class->usage);
20300Sstevel@tonic-gate 			    free(class);
20310Sstevel@tonic-gate 			    class = NULL;
20320Sstevel@tonic-gate 			    error = ENOMEM;
20330Sstevel@tonic-gate 			} else {
20340Sstevel@tonic-gate 			    *classes = dlist_append(item, *classes, AT_TAIL);
20350Sstevel@tonic-gate 			}
20360Sstevel@tonic-gate 		    }
20370Sstevel@tonic-gate 		}
20380Sstevel@tonic-gate 	    }
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 	    if ((error == 0) && (class != NULL)) {
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate 		char buf[BUFSIZ];
20430Sstevel@tonic-gate 		char *dup = NULL;
20440Sstevel@tonic-gate 		char *slicename = NULL;
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 		(void) get_display_name(slice, &slicename);
20470Sstevel@tonic-gate 		(void) snprintf(buf, BUFSIZ-1, "  %s: %s",
20480Sstevel@tonic-gate 			slicename, usage_detail);
20490Sstevel@tonic-gate 		if ((dup = strdup(buf)) == NULL) {
20500Sstevel@tonic-gate 		    error = ENOMEM;
20510Sstevel@tonic-gate 		} else {
20520Sstevel@tonic-gate 		    if ((item = dlist_new_item((void *)dup)) == NULL) {
20530Sstevel@tonic-gate 			free(dup);
20540Sstevel@tonic-gate 			error = ENOMEM;
20550Sstevel@tonic-gate 		    } else {
20560Sstevel@tonic-gate 			class->sliceinfo =
20570Sstevel@tonic-gate 			    dlist_insert_ordered(
20580Sstevel@tonic-gate 				    item, class->sliceinfo,
20590Sstevel@tonic-gate 				    ASCENDING, compare_strings);
20600Sstevel@tonic-gate 		    }
20610Sstevel@tonic-gate 		}
20620Sstevel@tonic-gate 	    }
20630Sstevel@tonic-gate 	}
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	return (error);
20660Sstevel@tonic-gate }
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate /*
20690Sstevel@tonic-gate  * FUNCTION:	print_usable_devices()
20700Sstevel@tonic-gate  *
20710Sstevel@tonic-gate  * PURPOSE:	Print out the devices determined to be available for
20720Sstevel@tonic-gate  *		use by layout.
20730Sstevel@tonic-gate  *
20740Sstevel@tonic-gate  *		Iterates the lists of usable slices, disks and HBAs
20750Sstevel@tonic-gate  *		and prints out their CTD and device names.
20760Sstevel@tonic-gate  */
20770Sstevel@tonic-gate static void
print_usable_devices()20780Sstevel@tonic-gate print_usable_devices()
20790Sstevel@tonic-gate {
20800Sstevel@tonic-gate 	int	i = 0;
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 	struct {
20830Sstevel@tonic-gate 		char *msg;
20840Sstevel@tonic-gate 		dlist_t *list;
20850Sstevel@tonic-gate 	}	devs[3];
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate 	devs[0].msg = gettext("HBA/Controllers");
20880Sstevel@tonic-gate 	devs[0].list = _usable_hbas;
20890Sstevel@tonic-gate 	devs[1].msg = gettext("disks");
20900Sstevel@tonic-gate 	devs[1].list = _usable_disks;
20910Sstevel@tonic-gate 	devs[2].msg = gettext("slices");
20920Sstevel@tonic-gate 	devs[2].list = _usable_slices;
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	for (i = 0; i < 3; i++) {
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 	    oprintf(OUTPUT_VERBOSE,
20970Sstevel@tonic-gate 		    gettext("\n  These %s are usable:\n\n"),
20980Sstevel@tonic-gate 		    devs[i].msg);
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 	    print_device_list(devs[i].list);
21010Sstevel@tonic-gate 	}
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate /*
21050Sstevel@tonic-gate  * FUNCTION:	print_device_list(dlist_t *devices)
21060Sstevel@tonic-gate  *
21070Sstevel@tonic-gate  * INPUT:	devices	- a list of device descriptor handles
21080Sstevel@tonic-gate  *
21090Sstevel@tonic-gate  * PURPOSE:	A helper for the print_XXX_devices() routines which iterates
21100Sstevel@tonic-gate  *		the input list and prints out each device name, CTD name and
21110Sstevel@tonic-gate  *		alias(es).
21120Sstevel@tonic-gate  */
21130Sstevel@tonic-gate static void
print_device_list(dlist_t * devices)21140Sstevel@tonic-gate print_device_list(
21150Sstevel@tonic-gate 	dlist_t *devices)
21160Sstevel@tonic-gate {
21170Sstevel@tonic-gate 	dlist_t *iter = NULL;
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 	for (iter = devices; iter != NULL; iter = iter->next) {
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 	    dm_descriptor_t device = ((uintptr_t)iter->obj);
21220Sstevel@tonic-gate 	    char	*name = NULL;
21230Sstevel@tonic-gate 	    char	*ctd = NULL;
21240Sstevel@tonic-gate 	    dlist_t	*aliases = NULL;
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 	    (void) get_display_name(device, &ctd);
21270Sstevel@tonic-gate 	    (void) get_name(device, &name);
21280Sstevel@tonic-gate 	    oprintf(OUTPUT_VERBOSE,
21290Sstevel@tonic-gate 		    "    %-25s %s\n", (ctd != NULL ? ctd : ""), name);
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 	    (void) get_aliases(device, &aliases);
21320Sstevel@tonic-gate 	    for (; aliases != NULL; aliases = aliases->next) {
21330Sstevel@tonic-gate 		oprintf(OUTPUT_VERBOSE,
21340Sstevel@tonic-gate 			gettext("      (alias: %s)\n"),
21350Sstevel@tonic-gate 			(char *)aliases->obj);
21360Sstevel@tonic-gate 	    }
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate 	    dlist_free_items(aliases, free);
21390Sstevel@tonic-gate 	}
21400Sstevel@tonic-gate }
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate /*
21430Sstevel@tonic-gate  * FUNCTION:	print_unusable_devices(
21440Sstevel@tonic-gate  *			dlist_t *bad_slices, dlist_t *bad_disks,
21450Sstevel@tonic-gate  *			dlist_t	*used_classes)
21460Sstevel@tonic-gate  *
21470Sstevel@tonic-gate  * INPUT:	used_classes - a list of slice_class_t structs
21480Sstevel@tonic-gate  *
21490Sstevel@tonic-gate  * PURPOSE:	Print out the devices determined to be unavailable for
21500Sstevel@tonic-gate  *		use by layout.
21510Sstevel@tonic-gate  *
21520Sstevel@tonic-gate  *		Iterates the input list of slice classifications and prints
21530Sstevel@tonic-gate  *		out a description of the class and the slices so classified.
21540Sstevel@tonic-gate  *
21550Sstevel@tonic-gate  *		Also iterates the lists of bad slices and disks (those that
21560Sstevel@tonic-gate  *		libdiskmgt returned descriptors for but cannot be accessed)
21570Sstevel@tonic-gate  *		and notes them as unusable.
21580Sstevel@tonic-gate  */
21590Sstevel@tonic-gate static void
print_unusable_devices(dlist_t * bad_slices,dlist_t * bad_disks,dlist_t * used_classes)21600Sstevel@tonic-gate print_unusable_devices(
21610Sstevel@tonic-gate 	dlist_t	*bad_slices,
21620Sstevel@tonic-gate 	dlist_t	*bad_disks,
21630Sstevel@tonic-gate 	dlist_t	*used_classes)
21640Sstevel@tonic-gate {
21650Sstevel@tonic-gate 	dlist_t	*iter = NULL;
21660Sstevel@tonic-gate 	dlist_t	*slices = NULL;
21670Sstevel@tonic-gate 	char	*preamble;
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 	struct {
21700Sstevel@tonic-gate 		char *msg;
21710Sstevel@tonic-gate 		dlist_t *list;
21720Sstevel@tonic-gate 	}	devs[2];
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	/* report bad disks and slices */
21750Sstevel@tonic-gate 	devs[0].msg = gettext("disks");
21760Sstevel@tonic-gate 	devs[0].list = bad_disks;
21770Sstevel@tonic-gate 	devs[1].msg = gettext("slices");
21780Sstevel@tonic-gate 	devs[1].list = bad_slices;
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 	if (bad_disks != NULL) {
21810Sstevel@tonic-gate 	    oprintf(OUTPUT_VERBOSE,
21820Sstevel@tonic-gate #if defined(sparc)
21830Sstevel@tonic-gate 		    gettext("\n  These disks are not usable, they may "
21840Sstevel@tonic-gate 			    "may be offline or cannot be accessed:\n\n"));
21850Sstevel@tonic-gate #elif defined(i386)
21860Sstevel@tonic-gate 		    gettext("\n  These disks are not usable, they may "
21870Sstevel@tonic-gate 			    "may be offline,\n  missing a Solaris FDISK "
21880Sstevel@tonic-gate 			    "partition or cannot be accessed:\n\n"));
21890Sstevel@tonic-gate #endif
21900Sstevel@tonic-gate 	    print_device_list(bad_disks);
21910Sstevel@tonic-gate 	}
21920Sstevel@tonic-gate 
21930Sstevel@tonic-gate 	if (bad_slices != NULL) {
21940Sstevel@tonic-gate 	    oprintf(OUTPUT_VERBOSE, gettext(
21950Sstevel@tonic-gate 		"\n  These slices, and subsequently the disks on which they\n"
21960Sstevel@tonic-gate 		"reside, are not usable, they cannot be accessed:\n\n"));
21970Sstevel@tonic-gate 	    print_device_list(bad_slices);
21980Sstevel@tonic-gate 	}
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 	/* report used slices and usages */
22010Sstevel@tonic-gate 	preamble = gettext("\n  These slices are not usable, %s:\n\n");
22020Sstevel@tonic-gate 	for (iter = used_classes; iter != NULL; iter = iter->next) {
22030Sstevel@tonic-gate 	    slice_class_t *class = (slice_class_t *)iter->obj;
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate 	    if (class->sliceinfo != NULL) {
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 		oprintf(OUTPUT_VERBOSE, preamble,
22080Sstevel@tonic-gate 			get_slice_usage_msg(class->usage));
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 		slices = class->sliceinfo;
22110Sstevel@tonic-gate 		for (; slices != NULL; slices = slices->next) {
22120Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, "  %s\n", (char *)slices->obj);
22130Sstevel@tonic-gate 		}
22140Sstevel@tonic-gate 	    }
22150Sstevel@tonic-gate 	}
22160Sstevel@tonic-gate 
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate /*
22200Sstevel@tonic-gate  * FUNCTION:	char * get_slice_usage_msg(char *usage)
22210Sstevel@tonic-gate  *
22220Sstevel@tonic-gate  * INPUT:	usage - char * string representing a slice usage classification
22230Sstevel@tonic-gate  *
22240Sstevel@tonic-gate  * OUTPUT:	char * "friendly" usage message
22250Sstevel@tonic-gate  *
22260Sstevel@tonic-gate  * PURPOSE:	the input usage string comes from libdiskmgt and is very terse.
22270Sstevel@tonic-gate  *
22280Sstevel@tonic-gate  *		Convert it into a friendlier usage description suitable for user
22290Sstevel@tonic-gate  *		consumption.
22300Sstevel@tonic-gate  */
22310Sstevel@tonic-gate static char *
get_slice_usage_msg(char * usage)22320Sstevel@tonic-gate get_slice_usage_msg(
22330Sstevel@tonic-gate 	char *usage)
22340Sstevel@tonic-gate {
22350Sstevel@tonic-gate 	char *str = NULL;
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 	if (string_case_compare(usage, DM_USE_MOUNT) == 0) {
22380Sstevel@tonic-gate 	    str = gettext("they have mounted filesystems");
22390Sstevel@tonic-gate 	} else if (string_case_compare(usage, DM_USE_FS) == 0) {
22400Sstevel@tonic-gate 	    str = gettext("they appear to have unmounted filesystems");
22410Sstevel@tonic-gate 	} else if (string_case_compare(usage, DM_USE_SVM) == 0) {
22420Sstevel@tonic-gate 	    str = gettext("they are utilized by SVM");
22430Sstevel@tonic-gate 	} else if (string_case_compare(usage, DM_USE_VXVM) == 0) {
22440Sstevel@tonic-gate 	    str = gettext("they are utilized by VxVm");
22450Sstevel@tonic-gate 	} else if (string_case_compare(usage, DM_USE_LU) == 0) {
22460Sstevel@tonic-gate 	    str = gettext("they are utilized by LiveUpgrade");
22470Sstevel@tonic-gate 	} else if (string_case_compare(usage, DM_USE_DUMP) == 0) {
22480Sstevel@tonic-gate 	    str = gettext("they are reserved as dump devices");
22490Sstevel@tonic-gate 	} else if (string_case_compare(usage, USE_DISKSET) == 0) {
22500Sstevel@tonic-gate 	    str = gettext("they have disk set issues");
22510Sstevel@tonic-gate 	} else {
22520Sstevel@tonic-gate 	    /* libdiskmgt has detected a usage unknown to layout */
22530Sstevel@tonic-gate 	    str = usage;
22540Sstevel@tonic-gate 	}
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	return (str);
22570Sstevel@tonic-gate }
22580Sstevel@tonic-gate 
22590Sstevel@tonic-gate /*
22600Sstevel@tonic-gate  * FUNCTION:	set_alias(dm_descriptor_t desc, char *alias)
22610Sstevel@tonic-gate  *
22620Sstevel@tonic-gate  * INPUT:	desc	- a dm_descriptor_t handle.
22630Sstevel@tonic-gate  *		alias	- a char * alias for the device represented
22640Sstevel@tonic-gate  *				by the descriptor.
22650Sstevel@tonic-gate  *
22660Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
22670Sstevel@tonic-gate  *			 !0 otherwise
22680Sstevel@tonic-gate  *
22690Sstevel@tonic-gate  * PURPOSE:	Adds the specified alias to the known aliases for the
22700Sstevel@tonic-gate  *		device associated with the input descriptor.
22710Sstevel@tonic-gate  */
22720Sstevel@tonic-gate int
set_alias(dm_descriptor_t desc,char * alias)22730Sstevel@tonic-gate set_alias(
22740Sstevel@tonic-gate 	dm_descriptor_t desc,
22750Sstevel@tonic-gate 	char	*alias)
22760Sstevel@tonic-gate {
22770Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
22780Sstevel@tonic-gate 	char		**old_aliases = NULL;
22790Sstevel@tonic-gate 	char		**new_aliases = NULL;
22800Sstevel@tonic-gate 	uint_t		nelem = 0;
22810Sstevel@tonic-gate 	int		error = 0;
22820Sstevel@tonic-gate 	int		i = 0;
22830Sstevel@tonic-gate 
22840Sstevel@tonic-gate 	if ((error = get_cached_attributes(desc, &attrs)) != 0) {
22850Sstevel@tonic-gate 	    return (error);
22860Sstevel@tonic-gate 	}
22870Sstevel@tonic-gate 
22880Sstevel@tonic-gate 	if ((error = get_string_array(
22890Sstevel@tonic-gate 	    attrs, ATTR_DEVICE_ALIASES, &old_aliases, &nelem)) != 0) {
22900Sstevel@tonic-gate 	    if (error != ENOENT) {
22910Sstevel@tonic-gate 		return (error);
22920Sstevel@tonic-gate 	    }
22930Sstevel@tonic-gate 	    /* no aliases yet */
22940Sstevel@tonic-gate 	    error = 0;
22950Sstevel@tonic-gate 	}
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 	/* add new alias */
22980Sstevel@tonic-gate 	new_aliases = (char **)calloc(MAX_ALIASES, sizeof (char *));
22990Sstevel@tonic-gate 	if (new_aliases != NULL) {
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	    for (i = 0; i < nelem && i < MAX_ALIASES; i++) {
23020Sstevel@tonic-gate 		char *dup = strdup(old_aliases[i]);
23030Sstevel@tonic-gate 		if (dup != NULL) {
23040Sstevel@tonic-gate 		    new_aliases[i] = dup;
23050Sstevel@tonic-gate 		} else {
23060Sstevel@tonic-gate 		    error = ENOMEM;
23070Sstevel@tonic-gate 		}
23080Sstevel@tonic-gate 	    }
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 	    if (error == 0) {
23110Sstevel@tonic-gate 		if (i == MAX_ALIASES) {
23120Sstevel@tonic-gate 		    volume_set_error(
23130Sstevel@tonic-gate 			    gettext("Maximum number of device aliases "
23140Sstevel@tonic-gate 				    "(8) reached\n"),
23150Sstevel@tonic-gate 			    MAX_ALIASES);
23160Sstevel@tonic-gate 		    error = -1;
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 		} else {
23190Sstevel@tonic-gate 		    new_aliases[i] = alias;
23200Sstevel@tonic-gate 		    error = set_string_array(attrs, ATTR_DEVICE_ALIASES,
23210Sstevel@tonic-gate 			    new_aliases, i + 1);
23220Sstevel@tonic-gate 		}
23230Sstevel@tonic-gate 	    }
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 	    free(new_aliases);
23260Sstevel@tonic-gate 	}
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 	if (error == 0) {
23290Sstevel@tonic-gate 	    /* cache descriptor under this alias */
23300Sstevel@tonic-gate 	    error = add_cached_descriptor(alias, desc);
23310Sstevel@tonic-gate 	}
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 	return (error);
23340Sstevel@tonic-gate }
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate /*
23370Sstevel@tonic-gate  * FUNCTION:	get_aliases(dm_descriptor_t desc, dlist_t **list)
23380Sstevel@tonic-gate  *
23390Sstevel@tonic-gate  * INPUT:	desc	- a dm_descriptor_t handle.
23400Sstevel@tonic-gate  *
23410Sstevel@tonic-gate  * OUTPUT:	list	- a dlist_t list pointing to the list of
23420Sstevel@tonic-gate  *				aliases associated with the device
23430Sstevel@tonic-gate  *				represented by the descriptor.
23440Sstevel@tonic-gate  *
23450Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
23460Sstevel@tonic-gate  *			 !0 otherwise
23470Sstevel@tonic-gate  *
23480Sstevel@tonic-gate  * PURPOSE:	Retrieves aliases for the input descriptor and
23490Sstevel@tonic-gate  *		appends them to the input list.
23500Sstevel@tonic-gate  *
23510Sstevel@tonic-gate  *		The list of returned items must be freed by calling
23520Sstevel@tonic-gate  *		dlist_free_items(list, free)
23530Sstevel@tonic-gate  */
23540Sstevel@tonic-gate int
get_aliases(dm_descriptor_t desc,dlist_t ** list)23550Sstevel@tonic-gate get_aliases(
23560Sstevel@tonic-gate 	dm_descriptor_t desc,
23570Sstevel@tonic-gate 	dlist_t		**list)
23580Sstevel@tonic-gate {
23590Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
23600Sstevel@tonic-gate 	char		**aliases = NULL;
23610Sstevel@tonic-gate 	uint_t		nelem = 0;
23620Sstevel@tonic-gate 	int		error = 0;
23630Sstevel@tonic-gate 	int		i;
23640Sstevel@tonic-gate 
23650Sstevel@tonic-gate 	if ((error = get_cached_attributes(desc, &attrs)) != 0) {
23660Sstevel@tonic-gate 	    return (error);
23670Sstevel@tonic-gate 	}
23680Sstevel@tonic-gate 
23690Sstevel@tonic-gate 	if ((error = get_string_array(
23700Sstevel@tonic-gate 	    attrs, ATTR_DEVICE_ALIASES, &aliases, &nelem)) != 0) {
23710Sstevel@tonic-gate 	    if (error == ENOENT) {
23720Sstevel@tonic-gate 		/* no aliases */
23730Sstevel@tonic-gate 		return (0);
23740Sstevel@tonic-gate 	    }
23750Sstevel@tonic-gate 	}
23760Sstevel@tonic-gate 
23770Sstevel@tonic-gate 	for (i = 0; i < nelem; i++) {
23780Sstevel@tonic-gate 	    dlist_t *item;
23790Sstevel@tonic-gate 	    char *dup;
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate 	    if ((dup = strdup(aliases[i])) == NULL) {
23820Sstevel@tonic-gate 		error = ENOMEM;
23830Sstevel@tonic-gate 		break;
23840Sstevel@tonic-gate 	    }
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 	    if ((item = dlist_new_item(dup)) == NULL) {
23870Sstevel@tonic-gate 		free(dup);
23880Sstevel@tonic-gate 		error = ENOMEM;
23890Sstevel@tonic-gate 		break;
23900Sstevel@tonic-gate 	    }
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 	    *list = dlist_append(item, *list, AT_TAIL);
23930Sstevel@tonic-gate 	}
23940Sstevel@tonic-gate 
23950Sstevel@tonic-gate 	return (error);
23960Sstevel@tonic-gate }
23970Sstevel@tonic-gate 
23980Sstevel@tonic-gate /*
23990Sstevel@tonic-gate  * FUNCTION:	compare_start_blocks(
24000Sstevel@tonic-gate  *			void *obj1, void *obj2)
24010Sstevel@tonic-gate  *
24020Sstevel@tonic-gate  * INPUT:	desc1	- opaque pointer to a dm_descriptor_t
24030Sstevel@tonic-gate  * 		desc2	- opaque pointer to a dm_descriptor_t
24040Sstevel@tonic-gate  *
24050Sstevel@tonic-gate  * RETURNS:	int	- <0 - if desc1.stblk < desc2.stblk
24060Sstevel@tonic-gate  *			   0 - if desc1.stblk == desc2.stblk
24070Sstevel@tonic-gate  *			  >0 - if desc1.stblk > desc.stblk
24080Sstevel@tonic-gate  *
24090Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the start blocks of
24100Sstevel@tonic-gate  *		the two input dm_descriptor_t slice handles.
24110Sstevel@tonic-gate  */
24120Sstevel@tonic-gate static int
compare_start_blocks(void * desc1,void * desc2)24130Sstevel@tonic-gate compare_start_blocks(
24140Sstevel@tonic-gate 	void	*desc1,
24150Sstevel@tonic-gate 	void	*desc2)
24160Sstevel@tonic-gate {
24170Sstevel@tonic-gate 	uint64_t stblk1 = 0;
24180Sstevel@tonic-gate 	uint64_t stblk2 = 0;
24190Sstevel@tonic-gate 
24200Sstevel@tonic-gate 	assert(desc1 != (dm_descriptor_t)0);
24210Sstevel@tonic-gate 	assert(desc2 != (dm_descriptor_t)0);
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate 	(void) slice_get_start_block((uintptr_t)desc1, &stblk1);
24240Sstevel@tonic-gate 	(void) slice_get_start_block((uintptr_t)desc2, &stblk2);
24250Sstevel@tonic-gate 
24260Sstevel@tonic-gate 	return (stblk1 - stblk2);
24270Sstevel@tonic-gate }
24280Sstevel@tonic-gate 
24290Sstevel@tonic-gate /*
24300Sstevel@tonic-gate  * FUNCTION:	compare_desc_display_names(
24310Sstevel@tonic-gate  *			void *desc1, void *desc2)
24320Sstevel@tonic-gate  *
24330Sstevel@tonic-gate  * INPUT:	desc1	- opaque pointer to a dm_descriptor_t
24340Sstevel@tonic-gate  * 		desc2	- opaque pointer to a dm_descriptor_t
24350Sstevel@tonic-gate  *
24360Sstevel@tonic-gate  * RETURNS:	int	- <0 - if desc1.name < desc2.name
24370Sstevel@tonic-gate  *			   0 - if desc1.name == desc2.name
24380Sstevel@tonic-gate  *			  >0 - if desc1.name > desc.name
24390Sstevel@tonic-gate  *
24400Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the CTD names of the
24410Sstevel@tonic-gate  *		two input dm_descriptor_t objects.
24420Sstevel@tonic-gate  */
24430Sstevel@tonic-gate static int
compare_desc_display_names(void * desc1,void * desc2)24440Sstevel@tonic-gate compare_desc_display_names(
24450Sstevel@tonic-gate 	void	*desc1,
24460Sstevel@tonic-gate 	void	*desc2)
24470Sstevel@tonic-gate {
24480Sstevel@tonic-gate 	char	*name1 = NULL;
24490Sstevel@tonic-gate 	char	*name2 = NULL;
24500Sstevel@tonic-gate 
24510Sstevel@tonic-gate 	assert(desc1 != (dm_descriptor_t)0);
24520Sstevel@tonic-gate 	assert(desc2 != (dm_descriptor_t)0);
24530Sstevel@tonic-gate 
24540Sstevel@tonic-gate 	(void) get_display_name((uintptr_t)desc1, &name1);
24550Sstevel@tonic-gate 	(void) get_display_name((uintptr_t)desc2, &name2);
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	return (string_case_compare(name1, name2));
24580Sstevel@tonic-gate }
2459