xref: /titanic_41/usr/src/cmd/lvm/metassist/layout/layout_request.c (revision b6c8bd52ccb0f3491c2bd1f5867985cef630564a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*b6c8bd52Sjeanm  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <assert.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <libintl.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include "volume_error.h"
347c478bd9Sstevel@tonic-gate #include "volume_defaults.h"
357c478bd9Sstevel@tonic-gate #include "volume_dlist.h"
367c478bd9Sstevel@tonic-gate #include "volume_output.h"
377c478bd9Sstevel@tonic-gate #include "volume_request.h"
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include "layout_device_cache.h"
407c478bd9Sstevel@tonic-gate #include "layout_discovery.h"
417c478bd9Sstevel@tonic-gate #include "layout_dlist_util.h"
427c478bd9Sstevel@tonic-gate #include "layout_request.h"
437c478bd9Sstevel@tonic-gate #include "layout_slice.h"
447c478bd9Sstevel@tonic-gate #include "layout_validate.h"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	_LAYOUT_REQUEST_C
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static char *_request_diskset = NULL;
497c478bd9Sstevel@tonic-gate static devconfig_t *_toplevel_request = NULL;
507c478bd9Sstevel@tonic-gate static defaults_t *_defaults = NULL;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * This file contains code which handles various aspects of the
547c478bd9Sstevel@tonic-gate  * request and defaults devconfig_t structs passed to the layout
557c478bd9Sstevel@tonic-gate  * module.
567c478bd9Sstevel@tonic-gate  *
577c478bd9Sstevel@tonic-gate  * Functions are provided which determine what devices are available
587c478bd9Sstevel@tonic-gate  * for use by the various volume layout mechanisms. These are based
597c478bd9Sstevel@tonic-gate  * on the user specified available/unavailable devices included in
607c478bd9Sstevel@tonic-gate  * a request or in the defaults associated with the destination diskset.
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * A struct to hold device "specifications" extracted from a user
657c478bd9Sstevel@tonic-gate  * specified device name.  This struct is used to compare the user's
667c478bd9Sstevel@tonic-gate  * available and unavailable device specifications against physical
677c478bd9Sstevel@tonic-gate  * devices attached to the system.
687c478bd9Sstevel@tonic-gate  *
697c478bd9Sstevel@tonic-gate  * The spec struct holds one of two different specifications: if the
707c478bd9Sstevel@tonic-gate  * user supplied device name is parsable as a CTD name, it is parsed
717c478bd9Sstevel@tonic-gate  * into the component ids.  Otherwise, it is stored as is.
727c478bd9Sstevel@tonic-gate  *
737c478bd9Sstevel@tonic-gate  * The CTD name space implies a device hierarchy and metassist
747c478bd9Sstevel@tonic-gate  * supports an implied wildcarding scheme for the CTD name space.
757c478bd9Sstevel@tonic-gate  * A CTD specification from the user is of the form cX, cXdX,
767c478bd9Sstevel@tonic-gate  * cXdXsX, cXtX, cXtXdX, or cXtXdXsX, so it may or may nor
777c478bd9Sstevel@tonic-gate  * correspond to an individual physical device depending on
787c478bd9Sstevel@tonic-gate  * the context.
797c478bd9Sstevel@tonic-gate  *
807c478bd9Sstevel@tonic-gate  * For example, "c1" can mean the controller/HBA with the
817c478bd9Sstevel@tonic-gate  * name "c1" or it can mean all devices attached to the
827c478bd9Sstevel@tonic-gate  * controller named "c1".
837c478bd9Sstevel@tonic-gate  *
847c478bd9Sstevel@tonic-gate  * The ctd specs make matching physical devices against a
857c478bd9Sstevel@tonic-gate  * user specification easier since the matching is based on
867c478bd9Sstevel@tonic-gate  * the numeric values extracted from the cXtXdXsX string
877c478bd9Sstevel@tonic-gate  * and not on the strings themselves.  The strings are
887c478bd9Sstevel@tonic-gate  * troublesome because of situations like "c1" being
897c478bd9Sstevel@tonic-gate  * compared to "c11t1d0s0" and getting false matches.
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * The ID_UNSPECIFIED value is used to flag components
927c478bd9Sstevel@tonic-gate  * that were not in the CTD name:
937c478bd9Sstevel@tonic-gate  *
947c478bd9Sstevel@tonic-gate  * "c3" -> { ctrl=3, target=ID_UNSPECIFIED,
957c478bd9Sstevel@tonic-gate  *		lun=ID_UNSPECIFIED, slice=ID_UNSPECIFIED }
967c478bd9Sstevel@tonic-gate  *
977c478bd9Sstevel@tonic-gate  * "c3t2" -> { ctrl=3, target=2,
987c478bd9Sstevel@tonic-gate  *		lun=ID_UNSPECIFIED, slice=ID_UNSPECIFIED }
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	ID_UNSPECIFIED	-1
1027c478bd9Sstevel@tonic-gate typedef struct {
1037c478bd9Sstevel@tonic-gate 	int	ctrl;
1047c478bd9Sstevel@tonic-gate 	int	target;
1057c478bd9Sstevel@tonic-gate 	int	lun;
1067c478bd9Sstevel@tonic-gate 	int	slice;
1077c478bd9Sstevel@tonic-gate 	boolean_t is_ide;
1087c478bd9Sstevel@tonic-gate } ctd_spec_t;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate typedef enum {
1117c478bd9Sstevel@tonic-gate 	SPEC_TYPE_CTD = 0,
1127c478bd9Sstevel@tonic-gate 	SPEC_TYPE_RAW,
1137c478bd9Sstevel@tonic-gate 	SPEC_TYPE_OTHER
1147c478bd9Sstevel@tonic-gate } spec_type_t;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate typedef struct {
1177c478bd9Sstevel@tonic-gate 	spec_type_t type;
1187c478bd9Sstevel@tonic-gate 	union {
1197c478bd9Sstevel@tonic-gate 		ctd_spec_t *ctd;
1207c478bd9Sstevel@tonic-gate 		char	*raw;
1217c478bd9Sstevel@tonic-gate 	} data;
1227c478bd9Sstevel@tonic-gate } device_spec_t;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static int get_spec_for_name(
1257c478bd9Sstevel@tonic-gate 	char	*name,
1267c478bd9Sstevel@tonic-gate 	device_spec_t **id);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static int create_device_spec(
1297c478bd9Sstevel@tonic-gate 	char	*name,
1307c478bd9Sstevel@tonic-gate 	device_spec_t **spec);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static int create_device_ctd_spec(
1337c478bd9Sstevel@tonic-gate 	char	*name,
1347c478bd9Sstevel@tonic-gate 	device_spec_t **spec);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate static int create_device_raw_spec(
1377c478bd9Sstevel@tonic-gate 	char	*name,
1387c478bd9Sstevel@tonic-gate 	device_spec_t **spec);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate static void destroy_device_spec(
1417c478bd9Sstevel@tonic-gate 	device_spec_t *spec);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate static boolean_t ctd_spec_includes_device(
1447c478bd9Sstevel@tonic-gate 	device_spec_t *spec,
1457c478bd9Sstevel@tonic-gate 	device_spec_t *device);
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static boolean_t raw_spec_includes_device(
1487c478bd9Sstevel@tonic-gate 	device_spec_t *spec,
1497c478bd9Sstevel@tonic-gate 	device_spec_t *device);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * get_spec_for_name builds up a cached mapping of device
1537c478bd9Sstevel@tonic-gate  * names to the corresponding device_spec_t structs.
1547c478bd9Sstevel@tonic-gate  *
1557c478bd9Sstevel@tonic-gate  * This saves repeatedly converting the device names, which
1567c478bd9Sstevel@tonic-gate  * could get expensive since devices are checked against the
1577c478bd9Sstevel@tonic-gate  * user specified available/unavailable devices a lot.
1587c478bd9Sstevel@tonic-gate  *
1597c478bd9Sstevel@tonic-gate  * The cache is implemented as a list of these structs:
1607c478bd9Sstevel@tonic-gate  */
1617c478bd9Sstevel@tonic-gate typedef struct {
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	char		*name;
1647c478bd9Sstevel@tonic-gate 	device_spec_t	*device_spec;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate } spec_cache_t;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate static dlist_t	*_spec_cache = NULL;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate static int destroy_spec_cache();
1717c478bd9Sstevel@tonic-gate static int compare_name_to_spec_cache_name(
1727c478bd9Sstevel@tonic-gate 	void *name, void *list_item);
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * The user specified available/unavailable devices are
1767c478bd9Sstevel@tonic-gate  * accessed frequently during layout. To make this more
1777c478bd9Sstevel@tonic-gate  * efficient, the char *arrays of available/unavailable
1787c478bd9Sstevel@tonic-gate  * specifications for a request or defaults devconfig_t
1797c478bd9Sstevel@tonic-gate  * object are converted to device_spec_ts the first time
1807c478bd9Sstevel@tonic-gate  * they're accessed and then cached using this struct:
1817c478bd9Sstevel@tonic-gate  */
1827c478bd9Sstevel@tonic-gate typedef struct {
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	devconfig_t	*request;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	/*
1877c478bd9Sstevel@tonic-gate 	 * avail_specs_list is a list of device spec_t
1887c478bd9Sstevel@tonic-gate 	 * corresponding to available devices specified
1897c478bd9Sstevel@tonic-gate 	 * in the request object
1907c478bd9Sstevel@tonic-gate 	 */
1917c478bd9Sstevel@tonic-gate 	dlist_t *avail_specs_list;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/*
1947c478bd9Sstevel@tonic-gate 	 * unavail_specs_list is a list of device spec_t
1957c478bd9Sstevel@tonic-gate 	 * corresponding to unavailable devices specified
1967c478bd9Sstevel@tonic-gate 	 * in the request object
1977c478bd9Sstevel@tonic-gate 	 */
1987c478bd9Sstevel@tonic-gate 	dlist_t *unavail_specs_list;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate } request_spec_list_t;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate dlist_t *_request_spec_list_cache = NULL;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate static int destroy_request_spec_list_cache();
2057c478bd9Sstevel@tonic-gate static void destroy_request_spec_list_entry(void *obj);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static int compare_request_to_request_spec_list_request(
2087c478bd9Sstevel@tonic-gate 	void *object,
2097c478bd9Sstevel@tonic-gate 	void *list_item);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate static int convert_usernames_to_specs(
2127c478bd9Sstevel@tonic-gate 	char **specs,
2137c478bd9Sstevel@tonic-gate 	dlist_t **list);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /* other private functions */
2167c478bd9Sstevel@tonic-gate static int is_device_avail(
2177c478bd9Sstevel@tonic-gate 	dm_descriptor_t	desc,
2187c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
2197c478bd9Sstevel@tonic-gate 	boolean_t	*avail);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate static int is_named_device_avail(
2227c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
2237c478bd9Sstevel@tonic-gate 	char		*device_name,
2247c478bd9Sstevel@tonic-gate 	boolean_t	check_aliases,
2257c478bd9Sstevel@tonic-gate 	boolean_t	*avail);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate static int avail_list_includes_device_name(
2287c478bd9Sstevel@tonic-gate 	dlist_t		*list,
2297c478bd9Sstevel@tonic-gate 	char		*device_name,
2307c478bd9Sstevel@tonic-gate 	boolean_t	check_aliases,
2317c478bd9Sstevel@tonic-gate 	boolean_t	*includes);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static int unavail_list_includes_device_name(
2347c478bd9Sstevel@tonic-gate 	dlist_t		*list,
2357c478bd9Sstevel@tonic-gate 	char		*device_name,
2367c478bd9Sstevel@tonic-gate 	boolean_t	check_aliases,
2377c478bd9Sstevel@tonic-gate 	boolean_t	*includes);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate static int spec_includes_device_name(
2407c478bd9Sstevel@tonic-gate 	device_spec_t *spec,
2417c478bd9Sstevel@tonic-gate 	char		 *device_name,
2427c478bd9Sstevel@tonic-gate 	boolean_t	check_aliases,
2437c478bd9Sstevel@tonic-gate 	boolean_t	*includes);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate static boolean_t spec_includes_device(
2467c478bd9Sstevel@tonic-gate 	device_spec_t *spec,
2477c478bd9Sstevel@tonic-gate 	device_spec_t *device);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate static int disk_get_avail_space(
2507c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
2517c478bd9Sstevel@tonic-gate 	dm_descriptor_t disk,
2527c478bd9Sstevel@tonic-gate 	uint64_t	*avail);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate static int compare_hba_n_avail_disks(
2557c478bd9Sstevel@tonic-gate 	void		*obj1,
2567c478bd9Sstevel@tonic-gate 	void		*obj2);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * FUNCTION:	release_request_caches()
2607c478bd9Sstevel@tonic-gate  *
2617c478bd9Sstevel@tonic-gate  * RETURNS:	0
2627c478bd9Sstevel@tonic-gate  *
2637c478bd9Sstevel@tonic-gate  * PURPOSE:	cleanup the module private caches.
2647c478bd9Sstevel@tonic-gate  */
2657c478bd9Sstevel@tonic-gate int
release_request_caches()2667c478bd9Sstevel@tonic-gate release_request_caches()
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	(void) destroy_request_spec_list_cache();
2697c478bd9Sstevel@tonic-gate 	(void) destroy_spec_cache();
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	return (0);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate  * FUNCTION:	int set_request_diskset(char *)
2757c478bd9Sstevel@tonic-gate  *
2767c478bd9Sstevel@tonic-gate  * INPUT:	char * - pointer to the diskset name
2777c478bd9Sstevel@tonic-gate  * OUTPUT:	0 - success
2787c478bd9Sstevel@tonic-gate  *		!0 - validation failure
2797c478bd9Sstevel@tonic-gate  * RETURNS:
2807c478bd9Sstevel@tonic-gate  *
2817c478bd9Sstevel@tonic-gate  * PURPOSE:	set the module global diskset name.
2827c478bd9Sstevel@tonic-gate  */
2837c478bd9Sstevel@tonic-gate int
set_request_diskset(char * dsname)2847c478bd9Sstevel@tonic-gate set_request_diskset(
2857c478bd9Sstevel@tonic-gate 	char	*dsname)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	_request_diskset = dsname;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	if (dsname == NULL || dsname[0] == '\0') {
2907c478bd9Sstevel@tonic-gate 	    volume_set_error(
2917c478bd9Sstevel@tonic-gate 		    gettext("No disk set specified in request\n"));
2927c478bd9Sstevel@tonic-gate 	    return (-1);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	return (0);
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate /*
2997c478bd9Sstevel@tonic-gate  * FUNCTION:	char *get_request_diskset()
3007c478bd9Sstevel@tonic-gate  *
3017c478bd9Sstevel@tonic-gate  * INPUT:	none   -
3027c478bd9Sstevel@tonic-gate  * OUTPUT:	none   -
3037c478bd9Sstevel@tonic-gate  * RETURNS:	char * - pointer to the currently set diskset name
3047c478bd9Sstevel@tonic-gate  *
3057c478bd9Sstevel@tonic-gate  * PURPOSE:	get the global name of the current diskset.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate char *
get_request_diskset()3087c478bd9Sstevel@tonic-gate get_request_diskset()
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	return (_request_diskset);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate  * FUNCTION:	void unset_request_diskset()
3157c478bd9Sstevel@tonic-gate  *
3167c478bd9Sstevel@tonic-gate  * PURPOSE:	unset the module global diskset name.
3177c478bd9Sstevel@tonic-gate  */
3187c478bd9Sstevel@tonic-gate void
unset_request_diskset(char * dsname)3197c478bd9Sstevel@tonic-gate unset_request_diskset(
3207c478bd9Sstevel@tonic-gate 	char	*dsname)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	_request_diskset = NULL;
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate  * FUNCTION:	int set_toplevel_request(devconfig_t *)
3277c478bd9Sstevel@tonic-gate  *
3287c478bd9Sstevel@tonic-gate  * INPUT:	devconfig_t * - pointer to the diskset request
3297c478bd9Sstevel@tonic-gate  * OUTPUT:	0 - success
3307c478bd9Sstevel@tonic-gate  *		!0 - validation failure
3317c478bd9Sstevel@tonic-gate  * RETURNS:
3327c478bd9Sstevel@tonic-gate  *
3337c478bd9Sstevel@tonic-gate  * PURPOSE:	set the module global toplevel request struct.
3347c478bd9Sstevel@tonic-gate  *		this will be set within the only public entry
3357c478bd9Sstevel@tonic-gate  *		point to the module -- get_layout()
3367c478bd9Sstevel@tonic-gate  *
3377c478bd9Sstevel@tonic-gate  * SIDEEFFECT:	The devconfig_t's list of available and unavailable
3387c478bd9Sstevel@tonic-gate  * 		devices will be validated.
3397c478bd9Sstevel@tonic-gate  */
3407c478bd9Sstevel@tonic-gate int
set_toplevel_request(devconfig_t * req)3417c478bd9Sstevel@tonic-gate set_toplevel_request(
3427c478bd9Sstevel@tonic-gate 	devconfig_t	*req)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	_toplevel_request = req;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	return (validate_request_avail_unavail(req));
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate  * FUNCTION:	void unset_toplevel_request()
3517c478bd9Sstevel@tonic-gate  *
3527c478bd9Sstevel@tonic-gate  * PURPOSE:	unset the layout module global toplevel request struct.
3537c478bd9Sstevel@tonic-gate  *
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate void
unset_toplevel_request()3567c478bd9Sstevel@tonic-gate unset_toplevel_request()
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate 	_toplevel_request = NULL;
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate  * FUNCTION:	int set_defaults(devconfig_t *)
3637c478bd9Sstevel@tonic-gate  *
3647c478bd9Sstevel@tonic-gate  * INPUT:	devconfig_t * - pointer to the global defaults devconfig_t
3657c478bd9Sstevel@tonic-gate  * OUTPUT:	0 - success
3667c478bd9Sstevel@tonic-gate  *		!0 - validation failure
3677c478bd9Sstevel@tonic-gate  * RETURNS:
3687c478bd9Sstevel@tonic-gate  *
3697c478bd9Sstevel@tonic-gate  * PURPOSE:	set the module global defaults struct.
3707c478bd9Sstevel@tonic-gate  *		this will be set within the only public entry
3717c478bd9Sstevel@tonic-gate  *		point to the module -- get_layout()
3727c478bd9Sstevel@tonic-gate  *
3737c478bd9Sstevel@tonic-gate  * SIDEEFFECT:	The devconfig_t's list of available and unavailable
3747c478bd9Sstevel@tonic-gate  * 		devices will be validated.
3757c478bd9Sstevel@tonic-gate  */
3767c478bd9Sstevel@tonic-gate int
set_request_defaults(defaults_t * defaults)3777c478bd9Sstevel@tonic-gate set_request_defaults(
3787c478bd9Sstevel@tonic-gate 	defaults_t *defaults)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	int	error = 0;
3817c478bd9Sstevel@tonic-gate 	devconfig_t *diskset = NULL;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	_defaults = defaults;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	if ((error = defaults_get_diskset_by_name(
3867c478bd9Sstevel@tonic-gate 	    _defaults, get_request_diskset(), &diskset)) == 0) {
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	    error = validate_request_avail_unavail(diskset);
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	} else if (error == ENOENT) {
3917c478bd9Sstevel@tonic-gate 	    /* no defaults to verify */
3927c478bd9Sstevel@tonic-gate 	    error = 0;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	return (error);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate  * FUNCTION:	void unset_request_defaults()
4007c478bd9Sstevel@tonic-gate  *
4017c478bd9Sstevel@tonic-gate  * PURPOSE:	unset the layout module global defaults struct.
4027c478bd9Sstevel@tonic-gate  *
4037c478bd9Sstevel@tonic-gate  */
4047c478bd9Sstevel@tonic-gate void
unset_request_defaults()4057c478bd9Sstevel@tonic-gate unset_request_defaults()
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	_defaults = NULL;
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate  * FUNCTION:	get_stripe_min_comp(devconfig_t *req, uint16_t *val)
4127c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
4137c478bd9Sstevel@tonic-gate  *		val	- pointer to a uint64_t to hold the result
4147c478bd9Sstevel@tonic-gate  *
4157c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
4167c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
4177c478bd9Sstevel@tonic-gate  *
4187c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the minimum of components
4197c478bd9Sstevel@tonic-gate  *		for striped volumes satisfying the input request.
4207c478bd9Sstevel@tonic-gate  *
4217c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
4227c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
4237c478bd9Sstevel@tonic-gate  *		global defaults.
4247c478bd9Sstevel@tonic-gate  */
4257c478bd9Sstevel@tonic-gate int
get_stripe_min_comp(devconfig_t * req,uint16_t * val)4267c478bd9Sstevel@tonic-gate get_stripe_min_comp(
4277c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
4287c478bd9Sstevel@tonic-gate 	uint16_t	*val)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	int		error = 0;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	*val = 0;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_stripe_mincomp(req, val)) != 0) {
4357c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
4367c478bd9Sstevel@tonic-gate 		return (error);
4377c478bd9Sstevel@tonic-gate 	    }
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	if (*val == 0) {
4417c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_stripe_mincomp(
4427c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
4437c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
4447c478bd9Sstevel@tonic-gate 		    return (error);
4457c478bd9Sstevel@tonic-gate 		}
4467c478bd9Sstevel@tonic-gate 	    }
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	return (error);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate  * FUNCTION:	get_stripe_max_comp(devconfig_t *req, uint16_t *val)
4547c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
4557c478bd9Sstevel@tonic-gate  *		val	- pointer to a uint64_t to hold the result
4567c478bd9Sstevel@tonic-gate  *
4577c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
4587c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
4597c478bd9Sstevel@tonic-gate  *
4607c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the maximum number of components
4617c478bd9Sstevel@tonic-gate  *		for striped volumes satisfying the input request.
4627c478bd9Sstevel@tonic-gate  *
4637c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
4647c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
4657c478bd9Sstevel@tonic-gate  *		global defaults.
4667c478bd9Sstevel@tonic-gate  */
4677c478bd9Sstevel@tonic-gate int
get_stripe_max_comp(devconfig_t * req,uint16_t * val)4687c478bd9Sstevel@tonic-gate get_stripe_max_comp(
4697c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
4707c478bd9Sstevel@tonic-gate 	uint16_t	*val)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	int		error = 0;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	*val = 0;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_stripe_maxcomp(req, val)) != 0) {
4777c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
4787c478bd9Sstevel@tonic-gate 		return (error);
4797c478bd9Sstevel@tonic-gate 	    }
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	if (*val == 0) {
4837c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_stripe_maxcomp(
4847c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
4857c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
4867c478bd9Sstevel@tonic-gate 		    return (error);
4877c478bd9Sstevel@tonic-gate 		}
4887c478bd9Sstevel@tonic-gate 	    }
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	return (error);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate  * FUNCTION:	get_stripe_interlace(devconfig_t *req, uint64_t *val)
4967c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
4977c478bd9Sstevel@tonic-gate  *		val	- pointer to a uint64_t to hold the result
4987c478bd9Sstevel@tonic-gate  *
4997c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
5007c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
5017c478bd9Sstevel@tonic-gate  *
5027c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the interlace value for striped
5037c478bd9Sstevel@tonic-gate  *		volumes satisfying the input request.
5047c478bd9Sstevel@tonic-gate  *
5057c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
5067c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
5077c478bd9Sstevel@tonic-gate  *		global defaults.
5087c478bd9Sstevel@tonic-gate  *
5097c478bd9Sstevel@tonic-gate  *		If no value is explictly specified, ERR_ATTR_UNSET is
5107c478bd9Sstevel@tonic-gate  *		returned.
5117c478bd9Sstevel@tonic-gate  */
5127c478bd9Sstevel@tonic-gate int
get_stripe_interlace(devconfig_t * req,uint64_t * val)5137c478bd9Sstevel@tonic-gate get_stripe_interlace(
5147c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
5157c478bd9Sstevel@tonic-gate 	uint64_t	*val)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	int		error = 0;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	*val = 0;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_stripe_interlace(req, val)) != 0) {
5227c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
5237c478bd9Sstevel@tonic-gate 		return (error);
5247c478bd9Sstevel@tonic-gate 	    }
5257c478bd9Sstevel@tonic-gate 	    error = 0;
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	if (*val == 0) {
5297c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_stripe_interlace(
5307c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
5317c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
5327c478bd9Sstevel@tonic-gate 		    return (error);
5337c478bd9Sstevel@tonic-gate 		}
5347c478bd9Sstevel@tonic-gate 	    }
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	return (error);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * FUNCTION:	get_mirror_read_strategy(devconfig_t *req,
5427c478bd9Sstevel@tonic-gate  *			mirror_read_strategy_t *val)
5437c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
5447c478bd9Sstevel@tonic-gate  *		val	- pointer to a mirror_read_strategy_t to hold the result
5457c478bd9Sstevel@tonic-gate  *
5467c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
5477c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
5487c478bd9Sstevel@tonic-gate  *
5497c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the write strategy mirrored volumes
5507c478bd9Sstevel@tonic-gate  *		should have for volumes satisfying the input request.
5517c478bd9Sstevel@tonic-gate  *
5527c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
5537c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
5547c478bd9Sstevel@tonic-gate  *		global defaults.
5557c478bd9Sstevel@tonic-gate  *
5567c478bd9Sstevel@tonic-gate  *		If no value is explictly specified, ERR_ATTR_UNSET is
5577c478bd9Sstevel@tonic-gate  *		returned.
5587c478bd9Sstevel@tonic-gate  */
5597c478bd9Sstevel@tonic-gate int
get_mirror_read_strategy(devconfig_t * req,mirror_read_strategy_t * val)5607c478bd9Sstevel@tonic-gate get_mirror_read_strategy(
5617c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
5627c478bd9Sstevel@tonic-gate 	mirror_read_strategy_t	*val)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	int		error = 0;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	*val = 0;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_mirror_read(req, val)) != 0) {
5697c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
5707c478bd9Sstevel@tonic-gate 		return (error);
5717c478bd9Sstevel@tonic-gate 	    }
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	if (*val == 0) {
5757c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_mirror_read(
5767c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
5777c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
5787c478bd9Sstevel@tonic-gate 		    return (error);
5797c478bd9Sstevel@tonic-gate 		}
5807c478bd9Sstevel@tonic-gate 	    }
5817c478bd9Sstevel@tonic-gate 	}
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	return (error);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate  * FUNCTION:	get_mirror_write_strategy(devconfig_t *req,
5887c478bd9Sstevel@tonic-gate  *			mirror_write_strategy_t *val)
5897c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
5907c478bd9Sstevel@tonic-gate  *		val	- pointer to a mirror_write_strategy_t to hold result
5917c478bd9Sstevel@tonic-gate  *
5927c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
5937c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
5947c478bd9Sstevel@tonic-gate  *
5957c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the write strategy mirrored volumes
5967c478bd9Sstevel@tonic-gate  *		should have for volumes satisfying the input request.
5977c478bd9Sstevel@tonic-gate  *
5987c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
5997c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
6007c478bd9Sstevel@tonic-gate  *		global defaults.
6017c478bd9Sstevel@tonic-gate  *
6027c478bd9Sstevel@tonic-gate  *		If no value is explictly specified, ERR_ATTR_UNSET is
6037c478bd9Sstevel@tonic-gate  *		returned.
6047c478bd9Sstevel@tonic-gate  */
6057c478bd9Sstevel@tonic-gate int
get_mirror_write_strategy(devconfig_t * req,mirror_write_strategy_t * val)6067c478bd9Sstevel@tonic-gate get_mirror_write_strategy(
6077c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
6087c478bd9Sstevel@tonic-gate 	mirror_write_strategy_t	*val)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	int		error = 0;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	*val = 0;
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_mirror_write(req, val)) != 0) {
6157c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
6167c478bd9Sstevel@tonic-gate 		return (error);
6177c478bd9Sstevel@tonic-gate 	    }
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (*val == 0) {
6217c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_mirror_write(
6227c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
6237c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
6247c478bd9Sstevel@tonic-gate 		    return (error);
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate 	    }
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	return (error);
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate /*
6337c478bd9Sstevel@tonic-gate  * FUNCTION:	get_mirror_pass(devconfig_t *req, uint16_t *val)
6347c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
6357c478bd9Sstevel@tonic-gate  *		val	- pointer to a uint16_t to hold the result
6367c478bd9Sstevel@tonic-gate  *
6377c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
6387c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
6397c478bd9Sstevel@tonic-gate  *
6407c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the resync pass mirrored volumes
6417c478bd9Sstevel@tonic-gate  *		should have for volumes satisfying the input request.
6427c478bd9Sstevel@tonic-gate  *
6437c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
6447c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
6457c478bd9Sstevel@tonic-gate  *		global defaults.
6467c478bd9Sstevel@tonic-gate  *
6477c478bd9Sstevel@tonic-gate  *		If no value is explictly specified, ERR_ATTR_UNSET is
6487c478bd9Sstevel@tonic-gate  *		returned.
6497c478bd9Sstevel@tonic-gate  */
6507c478bd9Sstevel@tonic-gate int
get_mirror_pass(devconfig_t * req,uint16_t * val)6517c478bd9Sstevel@tonic-gate get_mirror_pass(
6527c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
6537c478bd9Sstevel@tonic-gate 	uint16_t	*val)
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate 	int		error = 0;
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	*val = 0;
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_mirror_pass(req, val)) != 0) {
6607c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
6617c478bd9Sstevel@tonic-gate 		return (error);
6627c478bd9Sstevel@tonic-gate 	    }
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	if (*val == 0) {
6667c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_mirror_pass(
6677c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
6687c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
6697c478bd9Sstevel@tonic-gate 		    return (error);
6707c478bd9Sstevel@tonic-gate 		}
6717c478bd9Sstevel@tonic-gate 	    }
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	return (error);
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate /*
6787c478bd9Sstevel@tonic-gate  * FUNCTION:	get_mirror_nsubs(devconfig_t *req, uint16_t *val)
6797c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
6807c478bd9Sstevel@tonic-gate  *		val	- pointer to a uint16_t to hold the result
6817c478bd9Sstevel@tonic-gate  *
6827c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
6837c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
6847c478bd9Sstevel@tonic-gate  *
6857c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines how many submirrors mirrored
6867c478bd9Sstevel@tonic-gate  *		volumes should have for volumes satisfying the input
6877c478bd9Sstevel@tonic-gate  *		request.
6887c478bd9Sstevel@tonic-gate  *
6897c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
6907c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
6917c478bd9Sstevel@tonic-gate  *		global defaults.
6927c478bd9Sstevel@tonic-gate  */
6937c478bd9Sstevel@tonic-gate int
get_mirror_nsubs(devconfig_t * req,uint16_t * val)6947c478bd9Sstevel@tonic-gate get_mirror_nsubs(
6957c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
6967c478bd9Sstevel@tonic-gate 	uint16_t	*val)
6977c478bd9Sstevel@tonic-gate {
6987c478bd9Sstevel@tonic-gate 	int		error = 0;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	*val = 0;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_mirror_nsubs(req, val)) != 0) {
7037c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
7047c478bd9Sstevel@tonic-gate 		return (error);
7057c478bd9Sstevel@tonic-gate 	    }
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	if (*val == 0) {
7097c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_mirror_nsubs(
7107c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
7117c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
7127c478bd9Sstevel@tonic-gate 		    return (error);
7137c478bd9Sstevel@tonic-gate 		}
7147c478bd9Sstevel@tonic-gate 	    }
7157c478bd9Sstevel@tonic-gate 	}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	return (error);
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate /*
7217c478bd9Sstevel@tonic-gate  * FUNCTION:	get_volume_faultrecov(devconfig_t *req, boolean_t *val)
7227c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
7237c478bd9Sstevel@tonic-gate  *		val	- pointer to a boolean_t to hold the result
7247c478bd9Sstevel@tonic-gate  *
7257c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
7267c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
7277c478bd9Sstevel@tonic-gate  *
7287c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines whether data redundant volumes
7297c478bd9Sstevel@tonic-gate  *		should also have fault recovery (e.g., HSPs) for volumes
7307c478bd9Sstevel@tonic-gate  *		satisfying the input request.
7317c478bd9Sstevel@tonic-gate  *
7327c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
7337c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
7347c478bd9Sstevel@tonic-gate  *		global defaults.
7357c478bd9Sstevel@tonic-gate  */
7367c478bd9Sstevel@tonic-gate int
get_volume_faultrecov(devconfig_t * req,boolean_t * val)7377c478bd9Sstevel@tonic-gate get_volume_faultrecov(
7387c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
7397c478bd9Sstevel@tonic-gate 	boolean_t	*val)
7407c478bd9Sstevel@tonic-gate {
7417c478bd9Sstevel@tonic-gate 	int		error = 0;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	*val = B_FALSE;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_volume_usehsp(req, val)) != 0) {
7467c478bd9Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
7477c478bd9Sstevel@tonic-gate 		component_type_t	type = TYPE_UNKNOWN;
7487c478bd9Sstevel@tonic-gate 		(void) devconfig_get_type(req, &type);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 		switch (type) {
7517c478bd9Sstevel@tonic-gate 		case TYPE_MIRROR:
7527c478bd9Sstevel@tonic-gate 		    error = defaults_get_mirror_usehsp(
7537c478bd9Sstevel@tonic-gate 			    _defaults, get_request_diskset(), val);
7547c478bd9Sstevel@tonic-gate 		    break;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		case TYPE_STRIPE:
7577c478bd9Sstevel@tonic-gate 		    error = defaults_get_stripe_usehsp(
7587c478bd9Sstevel@tonic-gate 			    _defaults, get_request_diskset(), val);
7597c478bd9Sstevel@tonic-gate 		    break;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 		case TYPE_CONCAT:
7627c478bd9Sstevel@tonic-gate 		    error = defaults_get_concat_usehsp(
7637c478bd9Sstevel@tonic-gate 			    _defaults, get_request_diskset(), val);
7647c478bd9Sstevel@tonic-gate 		    break;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 		case TYPE_VOLUME:
7677c478bd9Sstevel@tonic-gate 		    error = defaults_get_volume_usehsp(
7687c478bd9Sstevel@tonic-gate 			    _defaults, get_request_diskset(), val);
7697c478bd9Sstevel@tonic-gate 		    break;
7707c478bd9Sstevel@tonic-gate 		}
7717c478bd9Sstevel@tonic-gate 	    }
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	return (error);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /*
7787c478bd9Sstevel@tonic-gate  * FUNCTION:	get_volume_redundancy_level(devconfig_t *req, uint16_t val)
7797c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
7807c478bd9Sstevel@tonic-gate  *		val	- pointer to a uint16-t to hold the result
7817c478bd9Sstevel@tonic-gate  *
7827c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
7837c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
7847c478bd9Sstevel@tonic-gate  *
7857c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the appropriate level of data
7867c478bd9Sstevel@tonic-gate  *		redundancy a volume should have for volumes satisfying
7877c478bd9Sstevel@tonic-gate  *		the input request.
7887c478bd9Sstevel@tonic-gate  *
7897c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
7907c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
7917c478bd9Sstevel@tonic-gate  *		global defaults.
7927c478bd9Sstevel@tonic-gate  */
7937c478bd9Sstevel@tonic-gate int
get_volume_redundancy_level(devconfig_t * req,uint16_t * val)7947c478bd9Sstevel@tonic-gate get_volume_redundancy_level(
7957c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
7967c478bd9Sstevel@tonic-gate 	uint16_t	*val)
7977c478bd9Sstevel@tonic-gate {
7987c478bd9Sstevel@tonic-gate 	int		error = 0;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	*val = 0;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_volume_redundancy_level(req, val)) != 0) {
8037c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
8047c478bd9Sstevel@tonic-gate 		return (error);
8057c478bd9Sstevel@tonic-gate 	    }
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	if (*val == 0) {
8097c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_volume_redundancy_level(
8107c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
8117c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
8127c478bd9Sstevel@tonic-gate 		    return (error);
8137c478bd9Sstevel@tonic-gate 		}
8147c478bd9Sstevel@tonic-gate 	    }
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	return (error);
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate /*
8217c478bd9Sstevel@tonic-gate  * FUNCTION:	get_volume_npaths(devconfig_t *req, uint16_t val)
8227c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
8237c478bd9Sstevel@tonic-gate  *		val	- pointer to a uint16-t to hold the result
8247c478bd9Sstevel@tonic-gate  *
8257c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
8267c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
8277c478bd9Sstevel@tonic-gate  *
8287c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the appropriate level of datapath
8297c478bd9Sstevel@tonic-gate  *		redundancy a slice component should have for volumes
8307c478bd9Sstevel@tonic-gate  *		satisfying the input request.
8317c478bd9Sstevel@tonic-gate  *
8327c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
8337c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
8347c478bd9Sstevel@tonic-gate  *		global defaults.
8357c478bd9Sstevel@tonic-gate  */
8367c478bd9Sstevel@tonic-gate int
get_volume_npaths(devconfig_t * req,uint16_t * val)8377c478bd9Sstevel@tonic-gate get_volume_npaths(
8387c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
8397c478bd9Sstevel@tonic-gate 	uint16_t	*val)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate 	int		error = 0;
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	*val = 0;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if ((error = devconfig_get_volume_npaths(req, val)) != 0) {
8467c478bd9Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
8477c478bd9Sstevel@tonic-gate 		return (error);
8487c478bd9Sstevel@tonic-gate 	    }
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	if (*val == 0) {
8527c478bd9Sstevel@tonic-gate 	    if ((error = defaults_get_volume_npaths(
8537c478bd9Sstevel@tonic-gate 		_defaults, get_request_diskset(), val)) != 0) {
8547c478bd9Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
8557c478bd9Sstevel@tonic-gate 		    return (error);
8567c478bd9Sstevel@tonic-gate 		}
8577c478bd9Sstevel@tonic-gate 	    }
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	return (error);
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate /*
8647c478bd9Sstevel@tonic-gate  * FUNCTION:	get_default_hsp_name(devconfig_t *req, char **hspname)
8657c478bd9Sstevel@tonic-gate  * INPUT:	req	- a devconfig_t pointer to the current request
8667c478bd9Sstevel@tonic-gate  *		hspname	- pointer to a char * to hold the result, if any
8677c478bd9Sstevel@tonic-gate  *
8687c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
8697c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
8707c478bd9Sstevel@tonic-gate  *
8717c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which determines the default HSP name for the
8727c478bd9Sstevel@tonic-gate  *		input request.
8737c478bd9Sstevel@tonic-gate  *
8747c478bd9Sstevel@tonic-gate  *		The value to use is taken from the input request, the
8757c478bd9Sstevel@tonic-gate  *		toplevel diskset request, the diskset defaults or the
8767c478bd9Sstevel@tonic-gate  *		global defaults.
8777c478bd9Sstevel@tonic-gate  */
8787c478bd9Sstevel@tonic-gate int
get_default_hsp_name(devconfig_t * req,char ** name)8797c478bd9Sstevel@tonic-gate get_default_hsp_name(
8807c478bd9Sstevel@tonic-gate 	devconfig_t	*req,
8817c478bd9Sstevel@tonic-gate 	char		**name)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate 	int		error = 0;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	*name = NULL;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	if ((error = defaults_get_hsp_name(_defaults,
8887c478bd9Sstevel@tonic-gate 	    get_request_diskset(), name)) != 0) {
8897c478bd9Sstevel@tonic-gate 	    if (error != ENOENT) {
8907c478bd9Sstevel@tonic-gate 		return (error);
8917c478bd9Sstevel@tonic-gate 	    }
8927c478bd9Sstevel@tonic-gate 	    error = 0;
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	return (error);
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate  * FUNCTION:	slice_is_available(char *sname, devconfig_t *request,
9007c478bd9Sstevel@tonic-gate  *			boolean_t bool)
9017c478bd9Sstevel@tonic-gate  * INPUT:	sname	- a slice name
9027c478bd9Sstevel@tonic-gate  *		request	- pointer to a devconfig_t struct representing
9037c478bd9Sstevel@tonic-gate  *				the current layout request being processed
9047c478bd9Sstevel@tonic-gate  * 		bool	- pointer to a boolean to hold the result
9057c478bd9Sstevel@tonic-gate  *
9067c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
9077c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
9087c478bd9Sstevel@tonic-gate  *
9097c478bd9Sstevel@tonic-gate  * PURPOSE:	Validation helper which determines if the named slice can
9107c478bd9Sstevel@tonic-gate  *		be used as a volume component when satisfying the input
9117c478bd9Sstevel@tonic-gate  *		request.
9127c478bd9Sstevel@tonic-gate  *
9137c478bd9Sstevel@tonic-gate  *		Check if the slice appears in the known slice list,
9147c478bd9Sstevel@tonic-gate  *		then check the request's available and unavailable
9157c478bd9Sstevel@tonic-gate  *		device specifications.
9167c478bd9Sstevel@tonic-gate  */
9177c478bd9Sstevel@tonic-gate int
slice_is_available(char * sname,devconfig_t * request,boolean_t * bool)9187c478bd9Sstevel@tonic-gate slice_is_available(
9197c478bd9Sstevel@tonic-gate 	char		*sname,
9207c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
9217c478bd9Sstevel@tonic-gate 	boolean_t	*bool)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	dm_descriptor_t	slice = (dm_descriptor_t)0;
9247c478bd9Sstevel@tonic-gate 	int		error = 0;
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	*bool = B_FALSE;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	if ((error = slice_get_by_name(sname, &slice)) != 0) {
9297c478bd9Sstevel@tonic-gate 	    return (error);
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	if (slice == (dm_descriptor_t)0) {
9337c478bd9Sstevel@tonic-gate 	    /* no slice found */
9347c478bd9Sstevel@tonic-gate 	    return (ENODEV);
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	if (error == 0) {
9387c478bd9Sstevel@tonic-gate 	    error = is_named_device_avail(request, sname, B_TRUE, bool);
9397c478bd9Sstevel@tonic-gate 	}
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	return (error);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate /*
9457c478bd9Sstevel@tonic-gate  * FUNCTION:	get_disks_for_target(char *name, dlist_t **disks)
9467c478bd9Sstevel@tonic-gate  *
9477c478bd9Sstevel@tonic-gate  * INPUT:	name	- a char* device CTD name
9487c478bd9Sstevel@tonic-gate  *
9497c478bd9Sstevel@tonic-gate  * OUTPUT:	disks	- disks matching the input target name
9507c478bd9Sstevel@tonic-gate  *
9517c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
9527c478bd9Sstevel@tonic-gate  *			 !0 otherwise
9537c478bd9Sstevel@tonic-gate  *
9547c478bd9Sstevel@tonic-gate  * PURPOSE:	Validation helper function which finds all disks "on" the
9557c478bd9Sstevel@tonic-gate  *		input target.
9567c478bd9Sstevel@tonic-gate  *
9577c478bd9Sstevel@tonic-gate  *		The input name is assumed to be a target name, cXtX, and
9587c478bd9Sstevel@tonic-gate  *		the list of known disks is searched to find any disk that
9597c478bd9Sstevel@tonic-gate  *		looks to be "on" that target.
9607c478bd9Sstevel@tonic-gate  *
9617c478bd9Sstevel@tonic-gate  *		"On" is determined by comparing a disk's name and
9627c478bd9Sstevel@tonic-gate  *		aliases to the target to see if they match.
9637c478bd9Sstevel@tonic-gate  */
9647c478bd9Sstevel@tonic-gate int
get_disks_for_target(char * name,dlist_t ** disks)9657c478bd9Sstevel@tonic-gate get_disks_for_target(
9667c478bd9Sstevel@tonic-gate 	char *name,
9677c478bd9Sstevel@tonic-gate 	dlist_t **disks)
9687c478bd9Sstevel@tonic-gate {
9697c478bd9Sstevel@tonic-gate 	int error = 0;
9707c478bd9Sstevel@tonic-gate 	device_spec_t *targetid = NULL;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	error = get_spec_for_name(name, &targetid);
9737c478bd9Sstevel@tonic-gate 	if (error == 0) {
9747c478bd9Sstevel@tonic-gate 	    dlist_t *known_disks = NULL;
9757c478bd9Sstevel@tonic-gate 	    dlist_t *iter = NULL;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	    get_known_disks(&known_disks);
9787c478bd9Sstevel@tonic-gate 	    for (iter = known_disks;
9797c478bd9Sstevel@tonic-gate 		(iter != NULL) && (error == 0);
9807c478bd9Sstevel@tonic-gate 		iter = iter->next) {
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		dm_descriptor_t disk = (uintptr_t)iter->obj;
9837c478bd9Sstevel@tonic-gate 		device_spec_t *diskid = NULL;
9847c478bd9Sstevel@tonic-gate 		char	*diskname = NULL;
9857c478bd9Sstevel@tonic-gate 		dlist_t *diskaliases = NULL;
9867c478bd9Sstevel@tonic-gate 		dlist_t *item;
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		((error = get_display_name(disk, &diskname)) != 0) ||
9897c478bd9Sstevel@tonic-gate 		(error = get_aliases(disk, &diskaliases)) ||
9907c478bd9Sstevel@tonic-gate 		(error = get_spec_for_name(diskname, &diskid));
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 		if (error == 0) {
9937c478bd9Sstevel@tonic-gate 		    if (spec_includes_device(targetid, diskid) == B_TRUE) {
9947c478bd9Sstevel@tonic-gate 			/* add disk */
995*b6c8bd52Sjeanm 			if ((item = dlist_new_item((void *)(uintptr_t)disk)) ==
996*b6c8bd52Sjeanm 			    NULL) {
9977c478bd9Sstevel@tonic-gate 			    error = ENOMEM;
9987c478bd9Sstevel@tonic-gate 			} else {
9997c478bd9Sstevel@tonic-gate 			    *disks = dlist_append(item, *disks, AT_HEAD);
10007c478bd9Sstevel@tonic-gate 			}
10017c478bd9Sstevel@tonic-gate 		    } else {
10027c478bd9Sstevel@tonic-gate 			/* check disk's aliases */
10037c478bd9Sstevel@tonic-gate 			dlist_t *iter2;
10047c478bd9Sstevel@tonic-gate 			for (iter2 = diskaliases;
10057c478bd9Sstevel@tonic-gate 			    (iter2 != NULL) && (error == 0);
10067c478bd9Sstevel@tonic-gate 			    iter2 = iter2->next) {
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 			    char *aliasname = NULL;
10097c478bd9Sstevel@tonic-gate 			    device_spec_t *aliasid = NULL;
10107c478bd9Sstevel@tonic-gate 			    error = get_display_name(disk, &aliasname);
10117c478bd9Sstevel@tonic-gate 			    error = get_spec_for_name(aliasname, &aliasid);
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 			    if (spec_includes_device(
10147c478bd9Sstevel@tonic-gate 					targetid, aliasid) == B_TRUE) {
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 				/* alias matched, add disk */
1017*b6c8bd52Sjeanm 				item = dlist_new_item((void *)(uintptr_t)disk);
10187c478bd9Sstevel@tonic-gate 				if (item == NULL) {
10197c478bd9Sstevel@tonic-gate 				    error = ENOMEM;
10207c478bd9Sstevel@tonic-gate 				} else {
10217c478bd9Sstevel@tonic-gate 				    *disks =
10227c478bd9Sstevel@tonic-gate 					dlist_append(item, *disks, AT_HEAD);
10237c478bd9Sstevel@tonic-gate 				}
10247c478bd9Sstevel@tonic-gate 			    }
10257c478bd9Sstevel@tonic-gate 			}
10267c478bd9Sstevel@tonic-gate 		    }
10277c478bd9Sstevel@tonic-gate 		}
10287c478bd9Sstevel@tonic-gate 	    }
10297c478bd9Sstevel@tonic-gate 	}
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	return (error);
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate  * FUNCTION:	select_hbas_with_n_disks(devconfig_t *request,
10367c478bd9Sstevel@tonic-gate  *			dlist_t	*hbas, int mindisks, dlist_t **selhbas,
10377c478bd9Sstevel@tonic-gate  *			dlist_t **seldisks)
10387c478bd9Sstevel@tonic-gate  *
10397c478bd9Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t struct representing
10407c478bd9Sstevel@tonic-gate  *				the current layout request being processed
10417c478bd9Sstevel@tonic-gate  * 		hbas	- pointer to a list of HBAs
10427c478bd9Sstevel@tonic-gate  *		mindisks - minimum number of disks required on the HBAs
10437c478bd9Sstevel@tonic-gate  *
10447c478bd9Sstevel@tonic-gate  * OUTPUT:	selhbas	- pointer to a list containing the HBAs with at
10457c478bd9Sstevel@tonic-gate  *				least mindisks available disks.
10467c478bd9Sstevel@tonic-gate  *		seldisks - pointer to a list containing the available disks
10477c478bd9Sstevel@tonic-gate  *				for the HBAs in selhbas
10487c478bd9Sstevel@tonic-gate  *
10497c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
10507c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
10517c478bd9Sstevel@tonic-gate  *
10527c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which counts the number of available disks associated
10537c478bd9Sstevel@tonic-gate  *		with each of the input HBAs and adds those that have at
10547c478bd9Sstevel@tonic-gate  *		least mindisks to the output list.
10557c478bd9Sstevel@tonic-gate  *
10567c478bd9Sstevel@tonic-gate  *		Only available disks that have available space are counted.
10577c478bd9Sstevel@tonic-gate  *
10587c478bd9Sstevel@tonic-gate  *		Disks connected thru multiple HBAs are only counted for
10597c478bd9Sstevel@tonic-gate  *		the first HBA they're accessed through.
10607c478bd9Sstevel@tonic-gate  *
10617c478bd9Sstevel@tonic-gate  *		The list of HBAs returned will be in descending order,
10627c478bd9Sstevel@tonic-gate  *		i.e., HBAs with more disks come before those with fewer.
10637c478bd9Sstevel@tonic-gate  *
10647c478bd9Sstevel@tonic-gate  *		The returned lists of HBAs and disks must be passed to
10657c478bd9Sstevel@tonic-gate  *		dlist_free_items() to recover the space allocated to hold
10667c478bd9Sstevel@tonic-gate  *		each list item.
10677c478bd9Sstevel@tonic-gate  *
10687c478bd9Sstevel@tonic-gate  *		for (each HBA) {
10697c478bd9Sstevel@tonic-gate  *
10707c478bd9Sstevel@tonic-gate  *		    select HBA
10717c478bd9Sstevel@tonic-gate  *		    get available disks on HBA
10727c478bd9Sstevel@tonic-gate  *
10737c478bd9Sstevel@tonic-gate  *		    for (each disk) {
10747c478bd9Sstevel@tonic-gate  *			if (disk is not in selected disk list)
10757c478bd9Sstevel@tonic-gate  *			    add it to the list
10767c478bd9Sstevel@tonic-gate  *			else
10777c478bd9Sstevel@tonic-gate  *			    count it as a distinct disk on this HBA
10787c478bd9Sstevel@tonic-gate  *		    }
10797c478bd9Sstevel@tonic-gate  *
10807c478bd9Sstevel@tonic-gate  *		    if (this HBA has >= mindisks distinct disks)
10817c478bd9Sstevel@tonic-gate  *			add this HBA to the list of returned HBAs
10827c478bd9Sstevel@tonic-gate  *
10837c478bd9Sstevel@tonic-gate  *		}
10847c478bd9Sstevel@tonic-gate  */
10857c478bd9Sstevel@tonic-gate int
select_hbas_with_n_disks(devconfig_t * request,dlist_t * hbas,int mindisks,dlist_t ** selhbas,dlist_t ** seldisks)10867c478bd9Sstevel@tonic-gate select_hbas_with_n_disks(
10877c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
10887c478bd9Sstevel@tonic-gate 	dlist_t		*hbas,
10897c478bd9Sstevel@tonic-gate 	int		mindisks,
10907c478bd9Sstevel@tonic-gate 	dlist_t		**selhbas,
10917c478bd9Sstevel@tonic-gate 	dlist_t		**seldisks)
10927c478bd9Sstevel@tonic-gate {
10937c478bd9Sstevel@tonic-gate 	dlist_t		*iter = NULL;
10947c478bd9Sstevel@tonic-gate 	int		error = 0;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	*selhbas = NULL;
10977c478bd9Sstevel@tonic-gate 	*seldisks = NULL;
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	/* for each input HBA */
11007c478bd9Sstevel@tonic-gate 	for (iter = hbas; (error == 0) && (iter != NULL); iter = iter->next) {
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
11037c478bd9Sstevel@tonic-gate 	    dlist_t *iter2 = NULL;
11047c478bd9Sstevel@tonic-gate 	    dlist_t *disks = NULL;
11057c478bd9Sstevel@tonic-gate 	    uint64_t space = 0;
11067c478bd9Sstevel@tonic-gate 	    uint16_t ndistinct = 0;
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	    error = hba_get_avail_disks_and_space(request, hba, &disks, &space);
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	    /* for each of this HBA's disks */
11117c478bd9Sstevel@tonic-gate 	    for (iter2 = disks;
11127c478bd9Sstevel@tonic-gate 		(iter2 != NULL) && (error == 0);
11137c478bd9Sstevel@tonic-gate 		iter2 = iter2->next) {
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 		dm_descriptor_t disk = (uintptr_t)iter2->obj;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 		/* unique disk? has it been seen thru some other HBA? */
1118*b6c8bd52Sjeanm 		if (dlist_contains(*seldisks, (void *)(uintptr_t)disk,
11197c478bd9Sstevel@tonic-gate 		    compare_descriptor_names) != B_TRUE) {
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 		    /* distinct, add to list of all_distinct */
1122*b6c8bd52Sjeanm 		    dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
11237c478bd9Sstevel@tonic-gate 		    if (item == NULL) {
11247c478bd9Sstevel@tonic-gate 			error = ENOMEM;
11257c478bd9Sstevel@tonic-gate 		    } else {
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 			*seldisks =
11287c478bd9Sstevel@tonic-gate 			    dlist_append(item, *seldisks, AT_HEAD);
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 			/* increment this HBA's distinct disk count */
11317c478bd9Sstevel@tonic-gate 			++ndistinct;
11327c478bd9Sstevel@tonic-gate 		    }
11337c478bd9Sstevel@tonic-gate 		}
11347c478bd9Sstevel@tonic-gate 	    }
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	    if (ndistinct >= mindisks) {
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 		/* this HBA has minimum # of disks, add to output list */
1139*b6c8bd52Sjeanm 		dlist_t	*item = dlist_new_item((void *)(uintptr_t)hba);
11407c478bd9Sstevel@tonic-gate 		if (item == NULL) {
11417c478bd9Sstevel@tonic-gate 		    error = ENOMEM;
11427c478bd9Sstevel@tonic-gate 		} else {
11437c478bd9Sstevel@tonic-gate 		    *selhbas =
11447c478bd9Sstevel@tonic-gate 			dlist_insert_ordered(
11457c478bd9Sstevel@tonic-gate 				item, *selhbas, DESCENDING,
11467c478bd9Sstevel@tonic-gate 				compare_hba_n_avail_disks);
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 		    /* save # of disks for ordering the list */
11497c478bd9Sstevel@tonic-gate 		    hba_set_n_avail_disks(hba, ndistinct);
11507c478bd9Sstevel@tonic-gate 		}
11517c478bd9Sstevel@tonic-gate 	    }
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	    dlist_free_items(disks, NULL);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	if (error != 0) {
11577c478bd9Sstevel@tonic-gate 	    oprintf(OUTPUT_TERSE,
11587c478bd9Sstevel@tonic-gate 		    gettext("failed selecting HBAs with n disks: %d\n"),
11597c478bd9Sstevel@tonic-gate 		    error);
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	    dlist_free_items(*selhbas, NULL);
11627c478bd9Sstevel@tonic-gate 	    *selhbas = NULL;
11637c478bd9Sstevel@tonic-gate 	    dlist_free_items(*seldisks, NULL);
11647c478bd9Sstevel@tonic-gate 	    *seldisks = NULL;
11657c478bd9Sstevel@tonic-gate 	}
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	return (error);
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate /*
11717c478bd9Sstevel@tonic-gate  * FUNCTION:	hba_get_avail_disks_and_space(devconfig_t *request,
11727c478bd9Sstevel@tonic-gate  *			dm_descriptor_t hba, dlist_t **disks, uint64_t *space)
11737c478bd9Sstevel@tonic-gate  *
11747c478bd9Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t struct representing
11757c478bd9Sstevel@tonic-gate  *				the current layout request being processed
11767c478bd9Sstevel@tonic-gate  * 		hba	- dm_descriptor_t handle for an HBA
11777c478bd9Sstevel@tonic-gate  *
11787c478bd9Sstevel@tonic-gate  * OUTPUT:	disks	- pointer to a list to hold the computed available
11797c478bd9Sstevel@tonic-gate  *				disks
11807c478bd9Sstevel@tonic-gate  * 		avail	- pointer to a uint64_t to hold the aggregate
11817c478bd9Sstevel@tonic-gate  *				available space on the available disks
11827c478bd9Sstevel@tonic-gate  *
11837c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
11847c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
11857c478bd9Sstevel@tonic-gate  *
11867c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which examines the disks associated with the
11877c478bd9Sstevel@tonic-gate  *		input HBA and assembles a list of those that are available.
11887c478bd9Sstevel@tonic-gate  *
11897c478bd9Sstevel@tonic-gate  *		Available is defined as being in the usable list, having
11907c478bd9Sstevel@tonic-gate  *		unused space and not specifically excluded by the request's
11917c478bd9Sstevel@tonic-gate  *		list of unavailable devices.
11927c478bd9Sstevel@tonic-gate  *
11937c478bd9Sstevel@tonic-gate  *		The returned list must be passed to dlist_free_items()
11947c478bd9Sstevel@tonic-gate  *		to recover the memory allocated to hold each list item.
11957c478bd9Sstevel@tonic-gate  */
11967c478bd9Sstevel@tonic-gate int
hba_get_avail_disks_and_space(devconfig_t * request,dm_descriptor_t hba,dlist_t ** disks,uint64_t * space)11977c478bd9Sstevel@tonic-gate hba_get_avail_disks_and_space(
11987c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
11997c478bd9Sstevel@tonic-gate 	dm_descriptor_t	hba,
12007c478bd9Sstevel@tonic-gate 	dlist_t		**disks,
12017c478bd9Sstevel@tonic-gate 	uint64_t	*space)
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate 	dlist_t		*usable_disks = NULL;
12047c478bd9Sstevel@tonic-gate 	dlist_t		*iter = NULL;
12057c478bd9Sstevel@tonic-gate 	int		error = 0;
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	*disks = NULL;
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	/* for each usable disk */
12107c478bd9Sstevel@tonic-gate 	error = get_usable_disks(&usable_disks);
12117c478bd9Sstevel@tonic-gate 	for (iter = usable_disks;
12127c478bd9Sstevel@tonic-gate 	    (error == 0) && (iter != NULL);
12137c478bd9Sstevel@tonic-gate 	    iter = iter->next) {
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	    dm_descriptor_t disk = (uintptr_t)iter->obj;
12167c478bd9Sstevel@tonic-gate 	    boolean_t	avail = B_FALSE;
12177c478bd9Sstevel@tonic-gate 	    dlist_t	*hbas = NULL;
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	    /* is disk attached to HBA in question? */
12207c478bd9Sstevel@tonic-gate 	    error = disk_get_hbas(disk, &hbas);
12217c478bd9Sstevel@tonic-gate 	    if (error != 0) {
12227c478bd9Sstevel@tonic-gate 		continue;
12237c478bd9Sstevel@tonic-gate 	    }
12247c478bd9Sstevel@tonic-gate 
1225*b6c8bd52Sjeanm 	    if (dlist_contains(hbas, (void *)(uintptr_t)hba,
12267c478bd9Sstevel@tonic-gate 			compare_descriptor_names) == B_TRUE) {
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 		/* is disk available? */
12297c478bd9Sstevel@tonic-gate 		error = is_device_avail(disk, request, &avail);
12307c478bd9Sstevel@tonic-gate 		if ((error == 0) && (avail == B_TRUE)) {
12317c478bd9Sstevel@tonic-gate 		    uint64_t disk_space = 0;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 		    /* does disk have available space? */
12347c478bd9Sstevel@tonic-gate 		    error = disk_get_avail_space(request, disk, &disk_space);
12357c478bd9Sstevel@tonic-gate 		    if ((error == 0) && (disk_space > 0)) {
12367c478bd9Sstevel@tonic-gate 
1237*b6c8bd52Sjeanm 			dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
12387c478bd9Sstevel@tonic-gate 			if (item == NULL) {
12397c478bd9Sstevel@tonic-gate 			    error = ENOMEM;
12407c478bd9Sstevel@tonic-gate 			} else {
12417c478bd9Sstevel@tonic-gate 			    *disks = dlist_append(item, *disks, AT_HEAD);
12427c478bd9Sstevel@tonic-gate 			}
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 			*space += disk_space;
12457c478bd9Sstevel@tonic-gate 		    }
12467c478bd9Sstevel@tonic-gate 		}
12477c478bd9Sstevel@tonic-gate 	    }
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	    dlist_free_items(hbas, NULL);
12507c478bd9Sstevel@tonic-gate 	}
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	if (error != 0) {
12537c478bd9Sstevel@tonic-gate 	    dlist_free_items(*disks, NULL);
12547c478bd9Sstevel@tonic-gate 	    *disks = NULL;
12557c478bd9Sstevel@tonic-gate 	}
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	return (error);
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate /*
12617c478bd9Sstevel@tonic-gate  * FUNCTION:	disk_get_avail_space(devconfig_t *request,
12627c478bd9Sstevel@tonic-gate  *			dlist_t *disks, uint64_t space)
12637c478bd9Sstevel@tonic-gate  *
12647c478bd9Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t struct representing
12657c478bd9Sstevel@tonic-gate  *				the current layout request being processed
12667c478bd9Sstevel@tonic-gate  * 		disks	- pointer to a list of disks
12677c478bd9Sstevel@tonic-gate  * 		space	- pointer to a uint64_t to hold the computed available
12687c478bd9Sstevel@tonic-gate  *				space
12697c478bd9Sstevel@tonic-gate  *
12707c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
12717c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
12727c478bd9Sstevel@tonic-gate  *
12737c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which iterates the input list of disks and determines
12747c478bd9Sstevel@tonic-gate  *		the aggregate amount of available space they represent.
12757c478bd9Sstevel@tonic-gate  *
12767c478bd9Sstevel@tonic-gate  *		Only disk slices that are in the usable slice list and not
12777c478bd9Sstevel@tonic-gate  *		specifically excluded by the request's list of unavailable
12787c478bd9Sstevel@tonic-gate  *		devices	will contribute to the aggregate space computation.
12797c478bd9Sstevel@tonic-gate  */
12807c478bd9Sstevel@tonic-gate static int
disk_get_avail_space(devconfig_t * request,dm_descriptor_t disk,uint64_t * space)12817c478bd9Sstevel@tonic-gate disk_get_avail_space(
12827c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
12837c478bd9Sstevel@tonic-gate 	dm_descriptor_t	disk,
12847c478bd9Sstevel@tonic-gate 	uint64_t	*space)
12857c478bd9Sstevel@tonic-gate {
12867c478bd9Sstevel@tonic-gate 	dlist_t		*usable_slices = NULL;
12877c478bd9Sstevel@tonic-gate 	dlist_t		*iter = NULL;
12887c478bd9Sstevel@tonic-gate 	int		error = 0;
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	*space = 0;
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	/* for each usable slice */
12937c478bd9Sstevel@tonic-gate 	error = get_usable_slices(&usable_slices);
12947c478bd9Sstevel@tonic-gate 	for (iter = usable_slices;
12957c478bd9Sstevel@tonic-gate 	    (error == 0) && (iter != NULL);
12967c478bd9Sstevel@tonic-gate 	    iter = iter->next) {
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	    dm_descriptor_t slice = (uintptr_t)iter->obj;
12997c478bd9Sstevel@tonic-gate 	    dm_descriptor_t slice_disk;
13007c478bd9Sstevel@tonic-gate 	    boolean_t	avail = B_FALSE;
13017c478bd9Sstevel@tonic-gate 	    boolean_t	reserved = B_FALSE;
13027c478bd9Sstevel@tonic-gate 	    boolean_t	used = B_FALSE;
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	    /* is slice on disk in question? */
13057c478bd9Sstevel@tonic-gate 	    if (((error = slice_get_disk(slice, &slice_disk)) != 0) ||
1306*b6c8bd52Sjeanm 		(compare_descriptor_names((void *)(uintptr_t)slice_disk,
1307*b6c8bd52Sjeanm 			(void *)(uintptr_t)disk) != 0)) {
13087c478bd9Sstevel@tonic-gate 		continue;
13097c478bd9Sstevel@tonic-gate 	    }
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	    /* is slice reserved by an explicit layout request? */
13127c478bd9Sstevel@tonic-gate 	    if (((error = is_reserved_slice(slice, &reserved)) != 0) ||
13137c478bd9Sstevel@tonic-gate 		(reserved == B_TRUE)) {
13147c478bd9Sstevel@tonic-gate 		continue;
13157c478bd9Sstevel@tonic-gate 	    }
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	    /* is slice used by a pending layout request? */
13187c478bd9Sstevel@tonic-gate 	    if (((error = is_used_slice(slice, &used)) != 0) ||
13197c478bd9Sstevel@tonic-gate 		(used == B_TRUE)) {
13207c478bd9Sstevel@tonic-gate 		continue;
13217c478bd9Sstevel@tonic-gate 	    }
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	    /* is slice available? */
13247c478bd9Sstevel@tonic-gate 	    if (((error = is_device_avail(slice, request, &avail)) == 0) &&
13257c478bd9Sstevel@tonic-gate 		(avail == B_TRUE)) {
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 		/* does slice have usable space? */
13287c478bd9Sstevel@tonic-gate 		uint64_t size = 0;
13297c478bd9Sstevel@tonic-gate 		if ((error = slice_get_size(slice, &size)) == 0) {
13307c478bd9Sstevel@tonic-gate 		    *space += size;
13317c478bd9Sstevel@tonic-gate 		}
13327c478bd9Sstevel@tonic-gate 	    }
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	return (error);
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate /*
13397c478bd9Sstevel@tonic-gate  * FUNCTION:	disks_get_avail_slices(devconfig_t *request,
13407c478bd9Sstevel@tonic-gate  *			dlist_t *disks, dlist_t **slices)
13417c478bd9Sstevel@tonic-gate  *
13427c478bd9Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t struct representing
13437c478bd9Sstevel@tonic-gate  *				the current layout request being processed
13447c478bd9Sstevel@tonic-gate  * 		disks	- pointer to a list of disks
13457c478bd9Sstevel@tonic-gate  * 		slices	- pointer to an output list of disks
13467c478bd9Sstevel@tonic-gate  *
13477c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
13487c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
13497c478bd9Sstevel@tonic-gate  *
13507c478bd9Sstevel@tonic-gate  * PURPOSE:	helper which iterates the input list of disks and builds a
13517c478bd9Sstevel@tonic-gate  *		new list which contains disks that are determined to be
13527c478bd9Sstevel@tonic-gate  * 		available for satisfying the input request.
13537c478bd9Sstevel@tonic-gate  *
13547c478bd9Sstevel@tonic-gate  *		A disk must contain at least one slice in the available
13557c478bd9Sstevel@tonic-gate  * 		slice list as well as have available space in order
13567c478bd9Sstevel@tonic-gate  *		to be available.
13577c478bd9Sstevel@tonic-gate  */
13587c478bd9Sstevel@tonic-gate int
disks_get_avail_slices(devconfig_t * request,dlist_t * disks,dlist_t ** slices)13597c478bd9Sstevel@tonic-gate disks_get_avail_slices(
13607c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
13617c478bd9Sstevel@tonic-gate 	dlist_t		*disks,
13627c478bd9Sstevel@tonic-gate 	dlist_t		**slices)
13637c478bd9Sstevel@tonic-gate {
13647c478bd9Sstevel@tonic-gate 	dlist_t		*usable_slices = NULL;
13657c478bd9Sstevel@tonic-gate 	dlist_t		*iter = NULL;
13667c478bd9Sstevel@tonic-gate 	int		error = 0;
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	*slices = NULL;
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 	/* for each usable slice */
13717c478bd9Sstevel@tonic-gate 	error = get_usable_slices(&usable_slices);
13727c478bd9Sstevel@tonic-gate 	for (iter = usable_slices;
13737c478bd9Sstevel@tonic-gate 	    (error == 0) && (iter != NULL);
13747c478bd9Sstevel@tonic-gate 	    iter = iter->next) {
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	    dm_descriptor_t slice = (uintptr_t)iter->obj;
13777c478bd9Sstevel@tonic-gate 	    dm_descriptor_t disk = (dm_descriptor_t)0;
13787c478bd9Sstevel@tonic-gate 	    boolean_t	avail = B_FALSE;
13797c478bd9Sstevel@tonic-gate 	    boolean_t	reserved = B_FALSE;
13807c478bd9Sstevel@tonic-gate 	    boolean_t	used = B_FALSE;
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	    /* is slice on a disk in the input list? */
13837c478bd9Sstevel@tonic-gate 	    if (((error = slice_get_disk(slice, &disk)) != 0) ||
1384*b6c8bd52Sjeanm 		(dlist_contains(disks, (void *)(uintptr_t)disk,
13857c478bd9Sstevel@tonic-gate 			compare_descriptor_names) != B_TRUE)) {
13867c478bd9Sstevel@tonic-gate 		continue;
13877c478bd9Sstevel@tonic-gate 	    }
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 	    /* is slice reserved by an explicit layout request? */
13907c478bd9Sstevel@tonic-gate 	    if (((error = is_reserved_slice(slice, &reserved)) != 0) ||
13917c478bd9Sstevel@tonic-gate 		(reserved == B_TRUE)) {
13927c478bd9Sstevel@tonic-gate 		continue;
13937c478bd9Sstevel@tonic-gate 	    }
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 	    /* is slice used by a pending layout request? */
13967c478bd9Sstevel@tonic-gate 	    if (((error = is_used_slice(slice, &used)) != 0) ||
13977c478bd9Sstevel@tonic-gate 		(used == B_TRUE)) {
13987c478bd9Sstevel@tonic-gate 		continue;
13997c478bd9Sstevel@tonic-gate 	    }
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	    /* is slice available? */
14027c478bd9Sstevel@tonic-gate 	    if (((error = is_device_avail(slice, request, &avail)) == 0) &&
14037c478bd9Sstevel@tonic-gate 		(avail == B_TRUE)) {
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		/* does slice have available space? */
14067c478bd9Sstevel@tonic-gate 		uint64_t size = 0;
14077c478bd9Sstevel@tonic-gate 		error = slice_get_size(slice, &size);
14087c478bd9Sstevel@tonic-gate 		if ((error == 0) && (size > 0)) {
1409*b6c8bd52Sjeanm 		    dlist_t *item = dlist_new_item((void *)(uintptr_t)slice);
14107c478bd9Sstevel@tonic-gate 		    if (item == NULL) {
14117c478bd9Sstevel@tonic-gate 			error = ENOMEM;
14127c478bd9Sstevel@tonic-gate 		    } else {
14137c478bd9Sstevel@tonic-gate 			*slices = dlist_append(item, *slices, AT_TAIL);
14147c478bd9Sstevel@tonic-gate 		    }
14157c478bd9Sstevel@tonic-gate 		}
14167c478bd9Sstevel@tonic-gate 	    }
14177c478bd9Sstevel@tonic-gate 	}
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	if (error != 0) {
14207c478bd9Sstevel@tonic-gate 	    dlist_free_items(*slices, NULL);
14217c478bd9Sstevel@tonic-gate 	    *slices = NULL;
14227c478bd9Sstevel@tonic-gate 	}
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	return (error);
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate /*
14297c478bd9Sstevel@tonic-gate  * FUNCTION:	get_hbas_and_disks_used_by_volumes(dlist_t *volumes,
14307c478bd9Sstevel@tonic-gate  *			dlist_t **hbas,	dlist_t **disks)
14317c478bd9Sstevel@tonic-gate  *
14327c478bd9Sstevel@tonic-gate  * INPUT:	volumes	- pointer to a list of devconfig_t volumes
14337c478bd9Sstevel@tonic-gate  *
14347c478bd9Sstevel@tonic-gate  * OUTPUT:	hbas - a list of HBAs utilized by the input volumes
14357c478bd9Sstevel@tonic-gate  *		disks - a list of disks utilized by the input volumes
14367c478bd9Sstevel@tonic-gate  *
14377c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
14387c478bd9Sstevel@tonic-gate  *			 !0 otherwise
14397c478bd9Sstevel@tonic-gate  *
14407c478bd9Sstevel@tonic-gate  * PURPOSE:	An aggregate list of HBAs and disks used by the input volumes
14417c478bd9Sstevel@tonic-gate  *		is built up by iterating the list of volumes and calling
14427c478bd9Sstevel@tonic-gate  *		get_hbas_disks_used_by_volume() to determine the HBAs and disk
14437c478bd9Sstevel@tonic-gate  *		used by each volume.
14447c478bd9Sstevel@tonic-gate  *
14457c478bd9Sstevel@tonic-gate  *		The returned lists of HBAs and disks may contain duplicates.
14467c478bd9Sstevel@tonic-gate  */
14477c478bd9Sstevel@tonic-gate int
get_hbas_and_disks_used_by_volumes(dlist_t * volumes,dlist_t ** hbas,dlist_t ** disks)14487c478bd9Sstevel@tonic-gate get_hbas_and_disks_used_by_volumes(
14497c478bd9Sstevel@tonic-gate 	dlist_t		*volumes,
14507c478bd9Sstevel@tonic-gate 	dlist_t		**hbas,
14517c478bd9Sstevel@tonic-gate 	dlist_t		**disks)
14527c478bd9Sstevel@tonic-gate {
14537c478bd9Sstevel@tonic-gate 	dlist_t		*iter = NULL;
14547c478bd9Sstevel@tonic-gate 	int		error = 0;
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	for (iter = volumes;
14577c478bd9Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
14587c478bd9Sstevel@tonic-gate 	    iter = iter->next) {
14597c478bd9Sstevel@tonic-gate 	    error = get_hbas_and_disks_used_by_volume(
14607c478bd9Sstevel@tonic-gate 		    (devconfig_t *)iter->obj, hbas, disks);
14617c478bd9Sstevel@tonic-gate 	}
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	return (error);
14647c478bd9Sstevel@tonic-gate }
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate /*
14677c478bd9Sstevel@tonic-gate  * FUNCTION:	get_hbas_and_disks_used_by_volume(devconfig_t *volume,
14687c478bd9Sstevel@tonic-gate  *			dlist_t **hbas, dlist_t **disks)
14697c478bd9Sstevel@tonic-gate  *
14707c478bd9Sstevel@tonic-gate  * INPUT:	volume	- pointer to a devconfig_t volume
14717c478bd9Sstevel@tonic-gate  *
14727c478bd9Sstevel@tonic-gate  * OUTPUT:	hbas - a list of HBAs updated to include those utilized
14737c478bd9Sstevel@tonic-gate  *			by the input volume
14747c478bd9Sstevel@tonic-gate  *		disks - a list of disks updated to inlclude those utilized
14757c478bd9Sstevel@tonic-gate  *			by the input volume
14767c478bd9Sstevel@tonic-gate  *
14777c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
14787c478bd9Sstevel@tonic-gate  *			 !0 otherwise
14797c478bd9Sstevel@tonic-gate  *
14807c478bd9Sstevel@tonic-gate  * PURPOSE:	The volume's components are iterated and the disks and HBAs
14817c478bd9Sstevel@tonic-gate  *		for each component are determined and appended to the input
14827c478bd9Sstevel@tonic-gate  *		lists of HBAs and disks.
14837c478bd9Sstevel@tonic-gate  *
14847c478bd9Sstevel@tonic-gate  *		The returned lists of HBAs and disks may contain duplicates.
14857c478bd9Sstevel@tonic-gate  */
14867c478bd9Sstevel@tonic-gate int
get_hbas_and_disks_used_by_volume(devconfig_t * volume,dlist_t ** hbas,dlist_t ** disks)14877c478bd9Sstevel@tonic-gate get_hbas_and_disks_used_by_volume(
14887c478bd9Sstevel@tonic-gate 	devconfig_t	*volume,
14897c478bd9Sstevel@tonic-gate 	dlist_t		**hbas,
14907c478bd9Sstevel@tonic-gate 	dlist_t		**disks)
14917c478bd9Sstevel@tonic-gate {
14927c478bd9Sstevel@tonic-gate 	dlist_t		*iter = NULL;
14937c478bd9Sstevel@tonic-gate 	int		error = 0;
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	for (iter = devconfig_get_components(volume);
14967c478bd9Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
14977c478bd9Sstevel@tonic-gate 	    iter = iter->next) {
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	    devconfig_t	*dev = (devconfig_t *)iter->obj;
15007c478bd9Sstevel@tonic-gate 	    if (devconfig_isA(dev, TYPE_SLICE)) {
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 		dm_descriptor_t	disk = NULL;
15037c478bd9Sstevel@tonic-gate 		char		*name = NULL;
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 		/* get disk for component slice */
15067c478bd9Sstevel@tonic-gate 		((error = devconfig_get_name(dev, &name)) != 0) ||
15077c478bd9Sstevel@tonic-gate 		(error = get_disk_for_named_slice(name, &disk));
15087c478bd9Sstevel@tonic-gate 		if (error == 0) {
1509*b6c8bd52Sjeanm 		    dlist_t *item = dlist_new_item((void *)(uintptr_t)disk);
15107c478bd9Sstevel@tonic-gate 		    if (item == NULL) {
15117c478bd9Sstevel@tonic-gate 			error = ENOMEM;
15127c478bd9Sstevel@tonic-gate 		    } else {
15137c478bd9Sstevel@tonic-gate 			*disks = dlist_append(item, *disks, AT_HEAD);
15147c478bd9Sstevel@tonic-gate 		    }
15157c478bd9Sstevel@tonic-gate 		}
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		/* get HBAs for disk */
15187c478bd9Sstevel@tonic-gate 		if (error == 0) {
15197c478bd9Sstevel@tonic-gate 		    dlist_t *disk_hbas = NULL;
15207c478bd9Sstevel@tonic-gate 		    if ((error = disk_get_hbas(disk, &disk_hbas)) == 0) {
15217c478bd9Sstevel@tonic-gate 			/* the hba list may contain dups, but that's ok */
15227c478bd9Sstevel@tonic-gate 			*hbas = dlist_append(disk_hbas, *hbas, AT_HEAD);
15237c478bd9Sstevel@tonic-gate 		    }
15247c478bd9Sstevel@tonic-gate 		}
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	    } else if (devconfig_isA(dev, TYPE_MIRROR)) {
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 		/* collect info for submirrors */
15297c478bd9Sstevel@tonic-gate 		dlist_t *iter1;
15307c478bd9Sstevel@tonic-gate 		for (iter1 = devconfig_get_components(dev);
15317c478bd9Sstevel@tonic-gate 		    (iter1 != NULL) && (error == 0);
15327c478bd9Sstevel@tonic-gate 		    iter1 = iter1->next) {
15337c478bd9Sstevel@tonic-gate 		    error = get_hbas_and_disks_used_by_volume(
15347c478bd9Sstevel@tonic-gate 			    (devconfig_t *)iter1->obj, hbas, disks);
15357c478bd9Sstevel@tonic-gate 		}
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	    }
15387c478bd9Sstevel@tonic-gate 	}
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 	return (error);
15417c478bd9Sstevel@tonic-gate }
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate /*
15447c478bd9Sstevel@tonic-gate  * FUNCTION:	compare_hba_n_avail_disks(void *obj1, void *obj2)
15457c478bd9Sstevel@tonic-gate  *
15467c478bd9Sstevel@tonic-gate  * INPUT:	obj1	- opaque pointer
15477c478bd9Sstevel@tonic-gate  * 		obj2	- opaque pointer
15487c478bd9Sstevel@tonic-gate  *
15497c478bd9Sstevel@tonic-gate  * RETURNS:	int	- <0 - if obj1 has fewer available disks than obj2
15507c478bd9Sstevel@tonic-gate  *			   0 - if obj1 has the same # of available disks as obj2
15517c478bd9Sstevel@tonic-gate  *			  >0 - if obj1 has more available disks than obj2
15527c478bd9Sstevel@tonic-gate  *
15537c478bd9Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the number of available disks
15547c478bd9Sstevel@tonic-gate  *		for two HBAs represented as dm_descriptor_t handles.
15557c478bd9Sstevel@tonic-gate  *
15567c478bd9Sstevel@tonic-gate  *		Both input objects are assumed to be dm_descriptor_t handles.
15577c478bd9Sstevel@tonic-gate  *
15587c478bd9Sstevel@tonic-gate  *		The number of available disks associated with the HBAs was
15597c478bd9Sstevel@tonic-gate  *		computed and saved in select_hbas_with_n_disks(), this
15607c478bd9Sstevel@tonic-gate  *		function just checks the saved values.
15617c478bd9Sstevel@tonic-gate  */
15627c478bd9Sstevel@tonic-gate static int
compare_hba_n_avail_disks(void * obj1,void * obj2)15637c478bd9Sstevel@tonic-gate compare_hba_n_avail_disks(
15647c478bd9Sstevel@tonic-gate 	void		*obj1,
15657c478bd9Sstevel@tonic-gate 	void		*obj2)
15667c478bd9Sstevel@tonic-gate {
15677c478bd9Sstevel@tonic-gate 	uint16_t	n1 = 0;
15687c478bd9Sstevel@tonic-gate 	uint16_t	n2 = 0;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	assert(obj1 != NULL);
15717c478bd9Sstevel@tonic-gate 	assert(obj2 != NULL);
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	(void) hba_get_n_avail_disks((uintptr_t)obj1, &n1);
15747c478bd9Sstevel@tonic-gate 	(void) hba_get_n_avail_disks((uintptr_t)obj2, &n2);
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	return ((int)n1 - n2);
15777c478bd9Sstevel@tonic-gate }
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate /*
15807c478bd9Sstevel@tonic-gate  * FUNCTION:	is_device_avail(dm_descriptor_t desc,
15817c478bd9Sstevel@tonic-gate  *			devconfig_t *request, boolean_t *avail)
15827c478bd9Sstevel@tonic-gate  *
15837c478bd9Sstevel@tonic-gate  * INPUT:	desc	- a dm_descriptor_t device handle
15847c478bd9Sstevel@tonic-gate  *		request	- pointer to a devconfig_t struct representing
15857c478bd9Sstevel@tonic-gate  *				the current layout request being processed
15867c478bd9Sstevel@tonic-gate  * 		avail	- pointer to a boolean to hold the result
15877c478bd9Sstevel@tonic-gate  *
15887c478bd9Sstevel@tonic-gate  * RETURNS:	int	-  0 - on success
15897c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
15907c478bd9Sstevel@tonic-gate  *
15917c478bd9Sstevel@tonic-gate  * PURPOSE:	Internal helper which determines if the input device can
15927c478bd9Sstevel@tonic-gate  *		be used as a volume component when satisfying the input
15937c478bd9Sstevel@tonic-gate  *		request.
15947c478bd9Sstevel@tonic-gate  *
15957c478bd9Sstevel@tonic-gate  *		The device is assumed to be a known valid device.
15967c478bd9Sstevel@tonic-gate  *
15977c478bd9Sstevel@tonic-gate  *		The function checks if the device passes the request's
15987c478bd9Sstevel@tonic-gate  *		available and unavailable device specifications.
15997c478bd9Sstevel@tonic-gate  *
16007c478bd9Sstevel@tonic-gate  *		The input device name may be either a DID name or a CTD
16017c478bd9Sstevel@tonic-gate  *		name.  All name comparisons are done using the CTD name.
16027c478bd9Sstevel@tonic-gate  */
16037c478bd9Sstevel@tonic-gate static int
is_device_avail(dm_descriptor_t desc,devconfig_t * request,boolean_t * avail)16047c478bd9Sstevel@tonic-gate is_device_avail(
16057c478bd9Sstevel@tonic-gate 	dm_descriptor_t	desc,
16067c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
16077c478bd9Sstevel@tonic-gate 	boolean_t	*avail)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate 	char		*name = NULL;
16107c478bd9Sstevel@tonic-gate 	int		error = 0;
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	*avail = B_FALSE;
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	if ((error = get_display_name(desc, &name)) == 0) {
16157c478bd9Sstevel@tonic-gate 	    error = is_named_device_avail(request, name, B_TRUE, avail);
16167c478bd9Sstevel@tonic-gate 	}
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	return (error);
16197c478bd9Sstevel@tonic-gate }
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate /*
16227c478bd9Sstevel@tonic-gate  * FUNCTION:	compare_request_to_request_spec_list_request(
16237c478bd9Sstevel@tonic-gate  *			void *request, void *list_item)
16247c478bd9Sstevel@tonic-gate  *
16257c478bd9Sstevel@tonic-gate  * INPUT:	request	- opaque pointer to a devconfig_t
16267c478bd9Sstevel@tonic-gate  * 		list_item - opaque pointer to a request_spec_list_t
16277c478bd9Sstevel@tonic-gate  *
16287c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - if request is the same as list_item->request
16297c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
16307c478bd9Sstevel@tonic-gate  *
16317c478bd9Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the input request pointer
16327c478bd9Sstevel@tonic-gate  *		to the list_item's request pointer for equality.
16337c478bd9Sstevel@tonic-gate  *
16347c478bd9Sstevel@tonic-gate  *		This function is the lookup mechanism for the lists of
16357c478bd9Sstevel@tonic-gate  *		cached device_spec_ts representing available/unavailable
16367c478bd9Sstevel@tonic-gate  *		devices for a given defaults_t request/defaults struct.
16377c478bd9Sstevel@tonic-gate  *
16387c478bd9Sstevel@tonic-gate  *		The defaults_t struct pointer is the lookup key.
16397c478bd9Sstevel@tonic-gate  */
16407c478bd9Sstevel@tonic-gate static int
compare_request_to_request_spec_list_request(void * request,void * list_item)16417c478bd9Sstevel@tonic-gate compare_request_to_request_spec_list_request(
16427c478bd9Sstevel@tonic-gate 	void *request,
16437c478bd9Sstevel@tonic-gate 	void *list_item)
16447c478bd9Sstevel@tonic-gate {
16457c478bd9Sstevel@tonic-gate 	request_spec_list_t *entry =
16467c478bd9Sstevel@tonic-gate 	    (request_spec_list_t *)list_item;
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	assert(request != NULL);
16497c478bd9Sstevel@tonic-gate 	assert(entry != NULL);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	/* compare two devconfig_t pointers, if identical, return 0 */
16527c478bd9Sstevel@tonic-gate 	return ((devconfig_t *)request != entry->request);
16537c478bd9Sstevel@tonic-gate }
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate /*
16567c478bd9Sstevel@tonic-gate  * FUNCTION:	compare_device_spec_specificity(void *spec1, void *spec2)
16577c478bd9Sstevel@tonic-gate  *
16587c478bd9Sstevel@tonic-gate  * INPUT:	spec1	- opaque pointer to a device_spec_t
16597c478bd9Sstevel@tonic-gate  * 		spec2	- opaque pointer to a device_spec_t
16607c478bd9Sstevel@tonic-gate  *
16617c478bd9Sstevel@tonic-gate  * RETURNS:	int	- <0 - if spec1 is less specific than spec2
16627c478bd9Sstevel@tonic-gate  *			   0 - if spec1 is as specific than spec2
16637c478bd9Sstevel@tonic-gate  *			  >0 - if spec1 is more specific than spec2
16647c478bd9Sstevel@tonic-gate  *
16657c478bd9Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the level of specificity
16667c478bd9Sstevel@tonic-gate  *		in the two input device_spec_t structs.  The one
16677c478bd9Sstevel@tonic-gate  *		which specifies more "components" of a cXtXdXsX device
16687c478bd9Sstevel@tonic-gate  *		name is considered more specific.
16697c478bd9Sstevel@tonic-gate  */
16707c478bd9Sstevel@tonic-gate static int
compare_device_spec_specificity(void * spec1,void * spec2)16717c478bd9Sstevel@tonic-gate compare_device_spec_specificity(
16727c478bd9Sstevel@tonic-gate 	void	*spec1,
16737c478bd9Sstevel@tonic-gate 	void	*spec2)
16747c478bd9Sstevel@tonic-gate {
16757c478bd9Sstevel@tonic-gate 	if (spec1 == NULL || spec2 == NULL) {
16767c478bd9Sstevel@tonic-gate 	    return (-1);
16777c478bd9Sstevel@tonic-gate 	}
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec1)->data.ctd->slice != ID_UNSPECIFIED) &&
16807c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec2)->data.ctd->slice == ID_UNSPECIFIED)) {
16817c478bd9Sstevel@tonic-gate 	    /* spec1 has slice, spec2 does not, spec1 more specific */
16827c478bd9Sstevel@tonic-gate 	    return (1);
16837c478bd9Sstevel@tonic-gate 	}
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec2)->data.ctd->slice != ID_UNSPECIFIED) &&
16867c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec1)->data.ctd->slice == ID_UNSPECIFIED)) {
16877c478bd9Sstevel@tonic-gate 	    /* spec2 has slice, spec1 does not, spec2 more specific */
16887c478bd9Sstevel@tonic-gate 	    return (-1);
16897c478bd9Sstevel@tonic-gate 	}
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec2)->data.ctd->slice != ID_UNSPECIFIED) &&
16927c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec1)->data.ctd->slice != ID_UNSPECIFIED)) {
16937c478bd9Sstevel@tonic-gate 	    /* both spec1 and spec2 have slice */
16947c478bd9Sstevel@tonic-gate 	    return (0);
16957c478bd9Sstevel@tonic-gate 	}
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec1)->data.ctd->lun != ID_UNSPECIFIED) &&
16987c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec2)->data.ctd->lun == ID_UNSPECIFIED)) {
16997c478bd9Sstevel@tonic-gate 	    /* spec1 has lun, spec2 does not, spec1 more specific */
17007c478bd9Sstevel@tonic-gate 	    return (1);
17017c478bd9Sstevel@tonic-gate 	}
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec2)->data.ctd->lun != ID_UNSPECIFIED) &&
17047c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec1)->data.ctd->lun == ID_UNSPECIFIED)) {
17057c478bd9Sstevel@tonic-gate 	    /* spec2 has lun, spec1 does not, spec2 more specific */
17067c478bd9Sstevel@tonic-gate 	    return (-1);
17077c478bd9Sstevel@tonic-gate 	}
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec2)->data.ctd->lun != ID_UNSPECIFIED) &&
17107c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec1)->data.ctd->lun != ID_UNSPECIFIED)) {
17117c478bd9Sstevel@tonic-gate 	    /* both spec1 and spec2 have lun */
17127c478bd9Sstevel@tonic-gate 	    return (0);
17137c478bd9Sstevel@tonic-gate 	}
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec1)->data.ctd->target != ID_UNSPECIFIED) &&
17167c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec2)->data.ctd->target == ID_UNSPECIFIED)) {
17177c478bd9Sstevel@tonic-gate 	    /* spec1 has target, spec2 does not, spec1 more specific */
17187c478bd9Sstevel@tonic-gate 	    return (1);
17197c478bd9Sstevel@tonic-gate 	}
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec2)->data.ctd->target != ID_UNSPECIFIED) &&
17227c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec1)->data.ctd->target == ID_UNSPECIFIED)) {
17237c478bd9Sstevel@tonic-gate 	    /* spec2 has target, spec1 does not, spec2 more specific */
17247c478bd9Sstevel@tonic-gate 	    return (-1);
17257c478bd9Sstevel@tonic-gate 	}
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 	if ((((device_spec_t *)spec2)->data.ctd->target != ID_UNSPECIFIED) &&
17287c478bd9Sstevel@tonic-gate 	    (((device_spec_t *)spec1)->data.ctd->target != ID_UNSPECIFIED)) {
17297c478bd9Sstevel@tonic-gate 	    /* both spec1 and spec2 have target */
17307c478bd9Sstevel@tonic-gate 	    return (0);
17317c478bd9Sstevel@tonic-gate 	}
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 	/* both specify just ctrl */
17347c478bd9Sstevel@tonic-gate 	return (0);
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate /*
17387c478bd9Sstevel@tonic-gate  * FUNCTION:	find_request_spec_list_entry(devconfig_t *request)
17397c478bd9Sstevel@tonic-gate  *
17407c478bd9Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t struct
17417c478bd9Sstevel@tonic-gate  *
17427c478bd9Sstevel@tonic-gate  * RETURNS:	request_spec_list_entry - pointer to a
17437c478bd9Sstevel@tonic-gate  *			request_spec_list_entry struct
17447c478bd9Sstevel@tonic-gate  *
17457c478bd9Sstevel@tonic-gate  * PURPOSE:	Lookup function which encapsulates the details of locating
17467c478bd9Sstevel@tonic-gate  *		the device_spec_list_t cache entry for the input request.
17477c478bd9Sstevel@tonic-gate  */
17487c478bd9Sstevel@tonic-gate static request_spec_list_t *
find_request_spec_list_entry(devconfig_t * request)17497c478bd9Sstevel@tonic-gate find_request_spec_list_entry(
17507c478bd9Sstevel@tonic-gate 	devconfig_t *request)
17517c478bd9Sstevel@tonic-gate {
17527c478bd9Sstevel@tonic-gate 	dlist_t *list_item = NULL;
17537c478bd9Sstevel@tonic-gate 	request_spec_list_t *entry = NULL;
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	list_item = dlist_find(
17567c478bd9Sstevel@tonic-gate 		_request_spec_list_cache,
17577c478bd9Sstevel@tonic-gate 		(void *)request,
17587c478bd9Sstevel@tonic-gate 		compare_request_to_request_spec_list_request);
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	if (list_item != NULL) {
17617c478bd9Sstevel@tonic-gate 	    entry = (request_spec_list_t *)list_item->obj;
17627c478bd9Sstevel@tonic-gate 	}
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	return (entry);
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate /*
17687c478bd9Sstevel@tonic-gate  * FUNCTION:	add_request_spec_list_entry(devconfig_t *request,
17697c478bd9Sstevel@tonic-gate  *			char **avail_device_specs, char **unavail_device_specs,
17707c478bd9Sstevel@tonic-gate  *			request_spec_list_entry_t **entry)
17717c478bd9Sstevel@tonic-gate  *
17727c478bd9Sstevel@tonic-gate  * INPUT:	entry - pointer to the request_spec_list_entry struct to be
17737c478bd9Sstevel@tonic-gate  *			added to the cache.
17747c478bd9Sstevel@tonic-gate  *
17757c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
17767c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
17777c478bd9Sstevel@tonic-gate  *
17787c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which encapsulates the details of adding a
17797c478bd9Sstevel@tonic-gate  *		device_spec_list_t cache entry.
17807c478bd9Sstevel@tonic-gate  */
17817c478bd9Sstevel@tonic-gate static int
add_request_spec_list_entry(request_spec_list_t * entry)17827c478bd9Sstevel@tonic-gate add_request_spec_list_entry(
17837c478bd9Sstevel@tonic-gate 	request_spec_list_t *entry)
17847c478bd9Sstevel@tonic-gate {
17857c478bd9Sstevel@tonic-gate 	dlist_t *list_item = dlist_new_item((void *)entry);
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 	if (list_item == NULL) {
17887c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
17897c478bd9Sstevel@tonic-gate 	}
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	_request_spec_list_cache = dlist_append(list_item,
17927c478bd9Sstevel@tonic-gate 		_request_spec_list_cache, AT_HEAD);
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	return (0);
17957c478bd9Sstevel@tonic-gate }
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate /*
17987c478bd9Sstevel@tonic-gate  * FUNCTION:	make_request_spec_list_entry(devconfig_t *request,
17997c478bd9Sstevel@tonic-gate  *			char **avail_device_specs, char **unavail_device_specs,
18007c478bd9Sstevel@tonic-gate  *			request_spec_list_entry_t **entry)
18017c478bd9Sstevel@tonic-gate  *
18027c478bd9Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t struct
18037c478bd9Sstevel@tonic-gate  *		avail_device_specs - char * array of user specified available
18047c478bd9Sstevel@tonic-gate  *			devices associated with the input request
18057c478bd9Sstevel@tonic-gate  *		unavail_device_specs - char * array of user specified
18067c478bd9Sstevel@tonic-gate  *			unavailable devices associated with the input
18077c478bd9Sstevel@tonic-gate  *			request
18087c478bd9Sstevel@tonic-gate  *
18097c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
18107c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
18117c478bd9Sstevel@tonic-gate  *
18127c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which encapsulates the details of generating a new
18137c478bd9Sstevel@tonic-gate  *		the device_spec_list_t cache entry for the input request
18147c478bd9Sstevel@tonic-gate  *		and its lists of avail/unavail devices.
18157c478bd9Sstevel@tonic-gate  *
18167c478bd9Sstevel@tonic-gate  *		Converts the input arrays of (un)available device names into
18177c478bd9Sstevel@tonic-gate  *		equivalent lists of device_spec_t structs.
18187c478bd9Sstevel@tonic-gate  *
18197c478bd9Sstevel@tonic-gate  *		Creates a new cache entry, populates it and adds it to the
18207c478bd9Sstevel@tonic-gate  *		cache.
18217c478bd9Sstevel@tonic-gate  */
18227c478bd9Sstevel@tonic-gate static int
make_request_spec_list_entry(devconfig_t * request,char ** avail_device_specs,char ** unavail_device_specs,request_spec_list_t ** entry)18237c478bd9Sstevel@tonic-gate make_request_spec_list_entry(
18247c478bd9Sstevel@tonic-gate 	devconfig_t *request,
18257c478bd9Sstevel@tonic-gate 	char	**avail_device_specs,
18267c478bd9Sstevel@tonic-gate 	char	**unavail_device_specs,
18277c478bd9Sstevel@tonic-gate 	request_spec_list_t **entry)
18287c478bd9Sstevel@tonic-gate {
18297c478bd9Sstevel@tonic-gate 	int error = 0;
18307c478bd9Sstevel@tonic-gate 	dlist_t *list = NULL;
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 	*entry = calloc(1, sizeof (request_spec_list_t));
18337c478bd9Sstevel@tonic-gate 	if (*entry == NULL) {
18347c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
18357c478bd9Sstevel@tonic-gate 	}
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	(*entry)->request = request;
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 	/*
18407c478bd9Sstevel@tonic-gate 	 * map the avail_device_name array into a list of device_spec_t
18417c478bd9Sstevel@tonic-gate 	 * and save the list as the entry's available list
18427c478bd9Sstevel@tonic-gate 	 */
18437c478bd9Sstevel@tonic-gate 	error = convert_usernames_to_specs(
18447c478bd9Sstevel@tonic-gate 		avail_device_specs, &list);
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate 	if (error == 0) {
18477c478bd9Sstevel@tonic-gate 	    (*entry)->avail_specs_list = list;
18487c478bd9Sstevel@tonic-gate 	}
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	/*
18517c478bd9Sstevel@tonic-gate 	 * map the unavail_device_name array into a list of device_spec_t
18527c478bd9Sstevel@tonic-gate 	 * and save the list as the entry's unavailable list
18537c478bd9Sstevel@tonic-gate 	 */
18547c478bd9Sstevel@tonic-gate 	list = NULL;
18557c478bd9Sstevel@tonic-gate 	error = convert_usernames_to_specs(
18567c478bd9Sstevel@tonic-gate 		unavail_device_specs, &list);
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	if (error == 0) {
18597c478bd9Sstevel@tonic-gate 	    (*entry)->unavail_specs_list = list;
18607c478bd9Sstevel@tonic-gate 	}
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 	if (error != 0) {
18637c478bd9Sstevel@tonic-gate 	    /* delete the partial entry */
18647c478bd9Sstevel@tonic-gate 	    destroy_request_spec_list_entry((void *)*entry);
18657c478bd9Sstevel@tonic-gate 	    *entry = NULL;
18667c478bd9Sstevel@tonic-gate 	}
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	return (error);
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate /*
18727c478bd9Sstevel@tonic-gate  * FUNCTION:	convert_usernames_to_specs(char **specs, dlist_t **list)
18737c478bd9Sstevel@tonic-gate  *
18747c478bd9Sstevel@tonic-gate  * INPUT:	specs	- char * array of device CTD names
18757c478bd9Sstevel@tonic-gate  *
18767c478bd9Sstevel@tonic-gate  * OUTPUT:	list	- pointer to a list of device_spec_t corresponding
18777c478bd9Sstevel@tonic-gate  *				to each name in the input array
18787c478bd9Sstevel@tonic-gate  *
18797c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
18807c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
18817c478bd9Sstevel@tonic-gate  *
18827c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which converts the input CTD device names to the
18837c478bd9Sstevel@tonic-gate  *		equivalent device_spec_t structs.
18847c478bd9Sstevel@tonic-gate  *
18857c478bd9Sstevel@tonic-gate  *		Iterates the input array and converts each CTD name to a
18867c478bd9Sstevel@tonic-gate  *		device_spec_t using get_spec_for_name().
18877c478bd9Sstevel@tonic-gate  */
18887c478bd9Sstevel@tonic-gate static int
convert_usernames_to_specs(char ** specs,dlist_t ** list)18897c478bd9Sstevel@tonic-gate convert_usernames_to_specs(
18907c478bd9Sstevel@tonic-gate 	char	**specs,
18917c478bd9Sstevel@tonic-gate 	dlist_t **list)
18927c478bd9Sstevel@tonic-gate {
18937c478bd9Sstevel@tonic-gate 	int i = 0;
18947c478bd9Sstevel@tonic-gate 	int error = 0;
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate 	/*
18977c478bd9Sstevel@tonic-gate 	 * For each spec in the array, get the corresponding
18987c478bd9Sstevel@tonic-gate 	 * device_spec_t and add it to the list.
18997c478bd9Sstevel@tonic-gate 	 *
19007c478bd9Sstevel@tonic-gate 	 * Any spec in the array that looks to be a DID name
19017c478bd9Sstevel@tonic-gate 	 * is first converted to its equivalent CTD name.
19027c478bd9Sstevel@tonic-gate 	 */
19037c478bd9Sstevel@tonic-gate 	for (i = 0;
19047c478bd9Sstevel@tonic-gate 	    (specs != NULL) && (specs[i] != NULL) && (error == 0);
19057c478bd9Sstevel@tonic-gate 	    i++) {
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 	    device_spec_t *spec = NULL;
19087c478bd9Sstevel@tonic-gate 	    char *userspec = specs[i];
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 	    error = get_spec_for_name(userspec, &spec);
19117c478bd9Sstevel@tonic-gate 	    if ((error == 0) && (spec != NULL)) {
19127c478bd9Sstevel@tonic-gate 		dlist_t *list_item = dlist_new_item((void *)spec);
19137c478bd9Sstevel@tonic-gate 		if (spec == NULL) {
19147c478bd9Sstevel@tonic-gate 		    error = ENOMEM;
19157c478bd9Sstevel@tonic-gate 		} else {
19167c478bd9Sstevel@tonic-gate 		    *list = dlist_insert_ordered
19177c478bd9Sstevel@tonic-gate 			(list_item, *list, DESCENDING,
19187c478bd9Sstevel@tonic-gate 				compare_device_spec_specificity);
19197c478bd9Sstevel@tonic-gate 		}
19207c478bd9Sstevel@tonic-gate 	    }
19217c478bd9Sstevel@tonic-gate 	}
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	if (error != 0) {
19247c478bd9Sstevel@tonic-gate 	    /* the device_spec_t in the list items are maintained */
19257c478bd9Sstevel@tonic-gate 	    /* in a cache elsewhere, so don't free them here. */
19267c478bd9Sstevel@tonic-gate 	    dlist_free_items(*list, NULL);
19277c478bd9Sstevel@tonic-gate 	    *list = NULL;
19287c478bd9Sstevel@tonic-gate 	}
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	return (error);
19317c478bd9Sstevel@tonic-gate }
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate /*
19347c478bd9Sstevel@tonic-gate  * FUNCTION:	destroy_request_spec_list_entry(void *entry)
19357c478bd9Sstevel@tonic-gate  *
19367c478bd9Sstevel@tonic-gate  * INPUT:	entry	- opaque pointer to a request_spec_list_t
19377c478bd9Sstevel@tonic-gate  *
19387c478bd9Sstevel@tonic-gate  * RETURNS:	nothing
19397c478bd9Sstevel@tonic-gate  *
19407c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which reclaims memory allocated to a
19417c478bd9Sstevel@tonic-gate  *		request_spec_list_t.
19427c478bd9Sstevel@tonic-gate  *
19437c478bd9Sstevel@tonic-gate  *		Frees memory allocated to the avail_spec_list and
19447c478bd9Sstevel@tonic-gate  *		unavail_spec_list.  Entries in the list are not freed,
19457c478bd9Sstevel@tonic-gate  *		since they are owned by the device_spec cache.
19467c478bd9Sstevel@tonic-gate  */
19477c478bd9Sstevel@tonic-gate static void
destroy_request_spec_list_entry(void * obj)19487c478bd9Sstevel@tonic-gate destroy_request_spec_list_entry(
19497c478bd9Sstevel@tonic-gate 	void *obj)
19507c478bd9Sstevel@tonic-gate {
19517c478bd9Sstevel@tonic-gate 	request_spec_list_t *entry = (request_spec_list_t *)obj;
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	if (entry != NULL) {
19547c478bd9Sstevel@tonic-gate 	    /* items in the list are in the spec_cache and will */
19557c478bd9Sstevel@tonic-gate 	    /* be cleaned up when it is destroyed. */
19567c478bd9Sstevel@tonic-gate 	    dlist_free_items(entry->avail_specs_list, NULL);
19577c478bd9Sstevel@tonic-gate 	    dlist_free_items(entry->unavail_specs_list, NULL);
19587c478bd9Sstevel@tonic-gate 	    free(entry);
19597c478bd9Sstevel@tonic-gate 	}
19607c478bd9Sstevel@tonic-gate }
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate /*
19637c478bd9Sstevel@tonic-gate  * FUNCTION:	destroy_request_spec_list_cache()
19647c478bd9Sstevel@tonic-gate  *
19657c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
19667c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
19677c478bd9Sstevel@tonic-gate  *
19687c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which destroys all entries in the request_spec_list
19697c478bd9Sstevel@tonic-gate  *		cache.
19707c478bd9Sstevel@tonic-gate  */
19717c478bd9Sstevel@tonic-gate static int
destroy_request_spec_list_cache()19727c478bd9Sstevel@tonic-gate destroy_request_spec_list_cache()
19737c478bd9Sstevel@tonic-gate {
19747c478bd9Sstevel@tonic-gate 	dlist_free_items(_request_spec_list_cache,
19757c478bd9Sstevel@tonic-gate 		destroy_request_spec_list_entry);
19767c478bd9Sstevel@tonic-gate 	_request_spec_list_cache = NULL;
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	return (0);
19797c478bd9Sstevel@tonic-gate }
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate /*
19827c478bd9Sstevel@tonic-gate  * FUNCTION:	get_request_avail_spec_list(devconfig_t *request,
19837c478bd9Sstevel@tonic-gate  *			dlist_t **list)
19847c478bd9Sstevel@tonic-gate  *
19857c478bd9Sstevel@tonic-gate  * INPUT:	request	- a pointer to a devconfig_t
19867c478bd9Sstevel@tonic-gate  *
19877c478bd9Sstevel@tonic-gate  * OUTPUT:	list	- pointer to a list of device_spec_t corresponding
19887c478bd9Sstevel@tonic-gate  *				to the devices specified as available by the
19897c478bd9Sstevel@tonic-gate  *				input request.
19907c478bd9Sstevel@tonic-gate  *
19917c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
19927c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
19937c478bd9Sstevel@tonic-gate  *
19947c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which locates or builds the list of device_spec_t
19957c478bd9Sstevel@tonic-gate  *		for the available devices specified in the input request.
19967c478bd9Sstevel@tonic-gate  *
19977c478bd9Sstevel@tonic-gate  *		Looks up the input request in the request_spec_list cache.
19987c478bd9Sstevel@tonic-gate  *		If there is currently no entry in the cache for the request,
19997c478bd9Sstevel@tonic-gate  *		an entry is built and added.
20007c478bd9Sstevel@tonic-gate  *
20017c478bd9Sstevel@tonic-gate  *		The entry's list of available device_spec_t is returned.
20027c478bd9Sstevel@tonic-gate  */
20037c478bd9Sstevel@tonic-gate static int
get_request_avail_spec_list(devconfig_t * request,dlist_t ** list)20047c478bd9Sstevel@tonic-gate get_request_avail_spec_list(
20057c478bd9Sstevel@tonic-gate 	devconfig_t *request,
20067c478bd9Sstevel@tonic-gate 	dlist_t	    **list)
20077c478bd9Sstevel@tonic-gate {
20087c478bd9Sstevel@tonic-gate 	request_spec_list_t *entry = NULL;
20097c478bd9Sstevel@tonic-gate 	int error = 0;
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 	if ((entry = find_request_spec_list_entry(request)) == NULL) {
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 	    /* create cache entry for this request */
20147c478bd9Sstevel@tonic-gate 	    error = make_request_spec_list_entry(
20157c478bd9Sstevel@tonic-gate 		    request,
20167c478bd9Sstevel@tonic-gate 		    devconfig_get_available(request),
20177c478bd9Sstevel@tonic-gate 		    devconfig_get_unavailable(request),
20187c478bd9Sstevel@tonic-gate 		    &entry);
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	    if ((error == 0) && (entry != NULL)) {
20217c478bd9Sstevel@tonic-gate 		if ((error = add_request_spec_list_entry(entry)) != 0) {
20227c478bd9Sstevel@tonic-gate 		    destroy_request_spec_list_entry(entry);
20237c478bd9Sstevel@tonic-gate 		    entry = NULL;
20247c478bd9Sstevel@tonic-gate 		}
20257c478bd9Sstevel@tonic-gate 	    }
20267c478bd9Sstevel@tonic-gate 	}
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 	if ((error == 0) && (entry != NULL)) {
20297c478bd9Sstevel@tonic-gate 	    *list = entry->avail_specs_list;
20307c478bd9Sstevel@tonic-gate 	}
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	return (error);
20337c478bd9Sstevel@tonic-gate }
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate /*
20367c478bd9Sstevel@tonic-gate  * FUNCTION:	get_request_unavail_spec_list(devconfig_t *request,
20377c478bd9Sstevel@tonic-gate  *			dlist_t **list)
20387c478bd9Sstevel@tonic-gate  *
20397c478bd9Sstevel@tonic-gate  * INPUT:	request	- a pointer to a devconfig_t
20407c478bd9Sstevel@tonic-gate  *
20417c478bd9Sstevel@tonic-gate  * OUTPUT:	list	- pointer to a list of device_spec_t corresponding
20427c478bd9Sstevel@tonic-gate  *				to the devices specified as unavailable by the
20437c478bd9Sstevel@tonic-gate  *				input request.
20447c478bd9Sstevel@tonic-gate  *
20457c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
20467c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
20477c478bd9Sstevel@tonic-gate  *
20487c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which locates or builds the list of device_spec_t
20497c478bd9Sstevel@tonic-gate  *		for the unavailable devices specified in the input request.
20507c478bd9Sstevel@tonic-gate  *
20517c478bd9Sstevel@tonic-gate  *		Looks up the input request in the request_spec_list cache.
20527c478bd9Sstevel@tonic-gate  *		If there is currently no entry in the cache for the request,
20537c478bd9Sstevel@tonic-gate  *		an entry is built and added.
20547c478bd9Sstevel@tonic-gate  *
20557c478bd9Sstevel@tonic-gate  *		The entry's list of unavailable device_spec_t is returned.
20567c478bd9Sstevel@tonic-gate  */
20577c478bd9Sstevel@tonic-gate static int
get_request_unavail_spec_list(devconfig_t * request,dlist_t ** list)20587c478bd9Sstevel@tonic-gate get_request_unavail_spec_list(
20597c478bd9Sstevel@tonic-gate 	devconfig_t *request,
20607c478bd9Sstevel@tonic-gate 	dlist_t	    **list)
20617c478bd9Sstevel@tonic-gate {
20627c478bd9Sstevel@tonic-gate 	request_spec_list_t *entry = NULL;
20637c478bd9Sstevel@tonic-gate 	int error = 0;
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 	if ((entry = find_request_spec_list_entry(request)) == NULL) {
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	    /* create new entry for this request */
20687c478bd9Sstevel@tonic-gate 	    error = make_request_spec_list_entry(
20697c478bd9Sstevel@tonic-gate 		    request,
20707c478bd9Sstevel@tonic-gate 		    devconfig_get_available(request),
20717c478bd9Sstevel@tonic-gate 		    devconfig_get_unavailable(request),
20727c478bd9Sstevel@tonic-gate 		    &entry);
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	    if ((error == 0) && (entry != NULL)) {
20757c478bd9Sstevel@tonic-gate 		if ((error = add_request_spec_list_entry(entry)) != 0) {
20767c478bd9Sstevel@tonic-gate 		    destroy_request_spec_list_entry(entry);
20777c478bd9Sstevel@tonic-gate 		    entry = NULL;
20787c478bd9Sstevel@tonic-gate 		}
20797c478bd9Sstevel@tonic-gate 	    }
20807c478bd9Sstevel@tonic-gate 	}
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 	if ((error == 0) && (entry != NULL)) {
20837c478bd9Sstevel@tonic-gate 	    *list = entry->unavail_specs_list;
20847c478bd9Sstevel@tonic-gate 	}
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	return (error);
20877c478bd9Sstevel@tonic-gate }
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate /*
20907c478bd9Sstevel@tonic-gate  * FUNCTION:	get_default_avail_spec_list(defaults_t *defaults,
20917c478bd9Sstevel@tonic-gate  *			char *dsname, dlist_t **list)
20927c478bd9Sstevel@tonic-gate  *
20937c478bd9Sstevel@tonic-gate  * INPUT:	defaults - a pointer to a defaults_t struct
20947c478bd9Sstevel@tonic-gate  *		dsname	- the name of the diskset whose defaults should be used
20957c478bd9Sstevel@tonic-gate  *
20967c478bd9Sstevel@tonic-gate  * OUTPUT:	list	- pointer to a list of device_spec_t corresponding
20977c478bd9Sstevel@tonic-gate  *				to the devices specified as available by the
20987c478bd9Sstevel@tonic-gate  *				defaults for the named diskset, or the global
20997c478bd9Sstevel@tonic-gate  *				defaults for all disksets.
21007c478bd9Sstevel@tonic-gate  *
21017c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
21027c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
21037c478bd9Sstevel@tonic-gate  *
21047c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which locates or builds the list of device_spec_t
21057c478bd9Sstevel@tonic-gate  *		for the available devices for the named diskset.
21067c478bd9Sstevel@tonic-gate  *
21077c478bd9Sstevel@tonic-gate  *		Locates the defaults for the named diskset, if there are none,
21087c478bd9Sstevel@tonic-gate  *		locates the global defaults for all disksets.
21097c478bd9Sstevel@tonic-gate  *
21107c478bd9Sstevel@tonic-gate  *		The defaults devconfig_t struct is then used to look up the
21117c478bd9Sstevel@tonic-gate  *		the corresponding entry in the request_spec_list cache.
21127c478bd9Sstevel@tonic-gate  *
21137c478bd9Sstevel@tonic-gate  *		If there is currently no entry in the cache for the defaults,
21147c478bd9Sstevel@tonic-gate  *		an entry is built and added.
21157c478bd9Sstevel@tonic-gate  *
21167c478bd9Sstevel@tonic-gate  *		The entry's list of available device_spec_t is returned.
21177c478bd9Sstevel@tonic-gate  */
21187c478bd9Sstevel@tonic-gate static int
get_default_avail_spec_list(defaults_t * alldefaults,char * dsname,dlist_t ** list)21197c478bd9Sstevel@tonic-gate get_default_avail_spec_list(
21207c478bd9Sstevel@tonic-gate 	defaults_t *alldefaults,
21217c478bd9Sstevel@tonic-gate 	char	*dsname,
21227c478bd9Sstevel@tonic-gate 	dlist_t	    **list)
21237c478bd9Sstevel@tonic-gate {
21247c478bd9Sstevel@tonic-gate 	request_spec_list_t *entry = NULL;
21257c478bd9Sstevel@tonic-gate 	devconfig_t *defaults = NULL;
21267c478bd9Sstevel@tonic-gate 	int error = 0;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	/* Get diskset defaults, or global if none for diskset */
21297c478bd9Sstevel@tonic-gate 	error = defaults_get_diskset_by_name(
21307c478bd9Sstevel@tonic-gate 		alldefaults, dsname, &defaults);
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	if (error != 0) {
21337c478bd9Sstevel@tonic-gate 	    if (error == ENOENT) {
21347c478bd9Sstevel@tonic-gate 		/* to get global defaults, pass a NULL diskset name */
21357c478bd9Sstevel@tonic-gate 		error = defaults_get_diskset_by_name(
21367c478bd9Sstevel@tonic-gate 			alldefaults, NULL, &defaults);
21377c478bd9Sstevel@tonic-gate 	    }
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate 	    if (error != 0) {
21407c478bd9Sstevel@tonic-gate 		if (error != ENOENT) {
21417c478bd9Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
21427c478bd9Sstevel@tonic-gate 			    gettext("get defaults for %s returned %d\n"),
21437c478bd9Sstevel@tonic-gate 			    dsname, error);
21447c478bd9Sstevel@tonic-gate 		} else {
21457c478bd9Sstevel@tonic-gate 		    error = 0;
21467c478bd9Sstevel@tonic-gate 		}
21477c478bd9Sstevel@tonic-gate 	    }
21487c478bd9Sstevel@tonic-gate 	}
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 	if ((entry = find_request_spec_list_entry(defaults)) == NULL) {
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 	    /* create new entry for these defaults */
21537c478bd9Sstevel@tonic-gate 	    error = make_request_spec_list_entry(
21547c478bd9Sstevel@tonic-gate 		    defaults,
21557c478bd9Sstevel@tonic-gate 		    devconfig_get_available(defaults),
21567c478bd9Sstevel@tonic-gate 		    devconfig_get_unavailable(defaults),
21577c478bd9Sstevel@tonic-gate 		    &entry);
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	    if ((error == 0) && (entry != NULL)) {
21607c478bd9Sstevel@tonic-gate 		if ((error = add_request_spec_list_entry(entry)) != 0) {
21617c478bd9Sstevel@tonic-gate 		    destroy_request_spec_list_entry(entry);
21627c478bd9Sstevel@tonic-gate 		    entry = NULL;
21637c478bd9Sstevel@tonic-gate 		}
21647c478bd9Sstevel@tonic-gate 	    }
21657c478bd9Sstevel@tonic-gate 	}
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 	if ((error == 0) && (entry != NULL)) {
21687c478bd9Sstevel@tonic-gate 	    *list = entry->avail_specs_list;
21697c478bd9Sstevel@tonic-gate 	}
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 	return (error);
21727c478bd9Sstevel@tonic-gate }
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate /*
21757c478bd9Sstevel@tonic-gate  * FUNCTION:	get_default_unavail_spec_list(defaults_t *defaults,
21767c478bd9Sstevel@tonic-gate  *			char *dsname, dlist_t **list)
21777c478bd9Sstevel@tonic-gate  *
21787c478bd9Sstevel@tonic-gate  * INPUT:	defaults - a pointer to a defaults_t struct
21797c478bd9Sstevel@tonic-gate  *		dsname	- the name of the diskset whose defaults should be used
21807c478bd9Sstevel@tonic-gate  *
21817c478bd9Sstevel@tonic-gate  * OUTPUT:	list	- pointer to a list of device_spec_t corresponding
21827c478bd9Sstevel@tonic-gate  *				to the devices specified as unavailable by the
21837c478bd9Sstevel@tonic-gate  *				defaults for the named diskset, or the global
21847c478bd9Sstevel@tonic-gate  *				defaults for all disksets.
21857c478bd9Sstevel@tonic-gate  *
21867c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
21877c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
21887c478bd9Sstevel@tonic-gate  *
21897c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which locates or builds the list of device_spec_t
21907c478bd9Sstevel@tonic-gate  *		for the unavailable devices for the named diskset.
21917c478bd9Sstevel@tonic-gate  *
21927c478bd9Sstevel@tonic-gate  *		Locates the defaults for the named diskset, if there are none,
21937c478bd9Sstevel@tonic-gate  *		locates the global defaults for all disksets.
21947c478bd9Sstevel@tonic-gate  *
21957c478bd9Sstevel@tonic-gate  *		The defaults devconfig_t struct is then used to look up the
21967c478bd9Sstevel@tonic-gate  *		the corresponding entry in the request_spec_list cache.
21977c478bd9Sstevel@tonic-gate  *
21987c478bd9Sstevel@tonic-gate  *		If there is currently no entry in the cache for the defaults,
21997c478bd9Sstevel@tonic-gate  *		an entry is built and added.
22007c478bd9Sstevel@tonic-gate  *
22017c478bd9Sstevel@tonic-gate  *		The entry's list of unavailable device_spec_t is returned.
22027c478bd9Sstevel@tonic-gate  */
22037c478bd9Sstevel@tonic-gate static int
get_default_unavail_spec_list(defaults_t * alldefaults,char * dsname,dlist_t ** list)22047c478bd9Sstevel@tonic-gate get_default_unavail_spec_list(
22057c478bd9Sstevel@tonic-gate 	defaults_t *alldefaults,
22067c478bd9Sstevel@tonic-gate 	char	*dsname,
22077c478bd9Sstevel@tonic-gate 	dlist_t	    **list)
22087c478bd9Sstevel@tonic-gate {
22097c478bd9Sstevel@tonic-gate 	request_spec_list_t *entry = NULL;
22107c478bd9Sstevel@tonic-gate 	devconfig_t *defaults = NULL;
22117c478bd9Sstevel@tonic-gate 	int error = 0;
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	/* Get diskset defaults, or global if none for diskset */
22147c478bd9Sstevel@tonic-gate 	error = defaults_get_diskset_by_name(
22157c478bd9Sstevel@tonic-gate 		alldefaults, dsname, &defaults);
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	if (error != 0) {
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate 	    if (error == ENOENT) {
22207c478bd9Sstevel@tonic-gate 		/* to get global defaults, pass a NULL diskset name */
22217c478bd9Sstevel@tonic-gate 		error = defaults_get_diskset_by_name(
22227c478bd9Sstevel@tonic-gate 			alldefaults, NULL, &defaults);
22237c478bd9Sstevel@tonic-gate 	    }
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 	    if (error != 0) {
22267c478bd9Sstevel@tonic-gate 		if (error != ENOENT) {
22277c478bd9Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
22287c478bd9Sstevel@tonic-gate 			    gettext("get defaults for %s returned %d\n"),
22297c478bd9Sstevel@tonic-gate 			    dsname, error);
22307c478bd9Sstevel@tonic-gate 		} else {
22317c478bd9Sstevel@tonic-gate 		    error = 0;
22327c478bd9Sstevel@tonic-gate 		}
22337c478bd9Sstevel@tonic-gate 	    }
22347c478bd9Sstevel@tonic-gate 	}
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate 	if ((entry = find_request_spec_list_entry(defaults)) == NULL) {
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	    /* create new entry for these defaults */
22397c478bd9Sstevel@tonic-gate 	    error = make_request_spec_list_entry(
22407c478bd9Sstevel@tonic-gate 		    defaults,
22417c478bd9Sstevel@tonic-gate 		    devconfig_get_available(defaults),
22427c478bd9Sstevel@tonic-gate 		    devconfig_get_unavailable(defaults),
22437c478bd9Sstevel@tonic-gate 		    &entry);
22447c478bd9Sstevel@tonic-gate 
22457c478bd9Sstevel@tonic-gate 	    if ((error == 0) && (entry != NULL)) {
22467c478bd9Sstevel@tonic-gate 		if ((error = add_request_spec_list_entry(entry)) != 0) {
22477c478bd9Sstevel@tonic-gate 		    destroy_request_spec_list_entry(entry);
22487c478bd9Sstevel@tonic-gate 		    entry = NULL;
22497c478bd9Sstevel@tonic-gate 		}
22507c478bd9Sstevel@tonic-gate 	    }
22517c478bd9Sstevel@tonic-gate 	}
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate 	if ((error == 0) && (entry != NULL)) {
22547c478bd9Sstevel@tonic-gate 	    *list = entry->unavail_specs_list;
22557c478bd9Sstevel@tonic-gate 	}
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 	return (error);
22587c478bd9Sstevel@tonic-gate }
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate /*
22617c478bd9Sstevel@tonic-gate  * FUNCTION:	is_named_device_avail(devconfig_t *request, char *device_name,
22627c478bd9Sstevel@tonic-gate  *			boolean_t check_aliases, boolean_t *avail)
22637c478bd9Sstevel@tonic-gate  *
22647c478bd9Sstevel@tonic-gate  * INPUT:	request - the current request devconfig_t
22657c478bd9Sstevel@tonic-gate  *		device_name - char * device name
22667c478bd9Sstevel@tonic-gate  *		check_aliases - boolean_t which indicates whether the device's
22677c478bd9Sstevel@tonic-gate  *			aliases should be considered by the availability checks.
22687c478bd9Sstevel@tonic-gate  *
22697c478bd9Sstevel@tonic-gate  * OUTPUT:	avail	- a boolean_t * to hold the result
22707c478bd9Sstevel@tonic-gate  *
22717c478bd9Sstevel@tonic-gate  * RETURNS:	int	- !0 on error
22727c478bd9Sstevel@tonic-gate  *
22737c478bd9Sstevel@tonic-gate  *		avail is set to B_TRUE if the named device is available for
22747c478bd9Sstevel@tonic-gate  * 		the input request, B_FALSE otherwise.
22757c478bd9Sstevel@tonic-gate  *
22767c478bd9Sstevel@tonic-gate  * PURPOSE:	Determine if the named device can be used to satisfy the
22777c478bd9Sstevel@tonic-gate  *		input request.
22787c478bd9Sstevel@tonic-gate  *
22797c478bd9Sstevel@tonic-gate  *		There are several levels at which device availabiity or
22807c478bd9Sstevel@tonic-gate  *		unavailability may be specifed:
22817c478bd9Sstevel@tonic-gate  *
22827c478bd9Sstevel@tonic-gate  *		1. the volume subrequest,
22837c478bd9Sstevel@tonic-gate  *		2. the toplevel (diskset) request,
22847c478bd9Sstevel@tonic-gate  *		3. the diskset-specific defaults
22857c478bd9Sstevel@tonic-gate  *		4. the global defaults
22867c478bd9Sstevel@tonic-gate  *
22877c478bd9Sstevel@tonic-gate  *		If the diskset-specific defaults exist, only they are checked.
22887c478bd9Sstevel@tonic-gate  *
22897c478bd9Sstevel@tonic-gate  *		The precedence ordering that is enforced:
22907c478bd9Sstevel@tonic-gate  *
22917c478bd9Sstevel@tonic-gate  *		1. if request has an avail list, the name must be in it
22927c478bd9Sstevel@tonic-gate  * 			and not in the request's unavail list.
22937c478bd9Sstevel@tonic-gate  *		2. if request has an unavail list, the name must not be in it.
22947c478bd9Sstevel@tonic-gate  *		3. if toplevel request has an avail list, the name must be
22957c478bd9Sstevel@tonic-gate  *			in it and not in the toplevel request's unavailable
22967c478bd9Sstevel@tonic-gate  *			list.
22977c478bd9Sstevel@tonic-gate  *		4. if toplevel request has an unavail list, the name must
22987c478bd9Sstevel@tonic-gate  *			not be in it.
22997c478bd9Sstevel@tonic-gate  *		5. if defaults have an avail list, the name must be in it
23007c478bd9Sstevel@tonic-gate  *			and not in the defaults unavailable list.
23017c478bd9Sstevel@tonic-gate  *		6. if defaults have an unavail list, the name must not be
23027c478bd9Sstevel@tonic-gate  *			in it.
23037c478bd9Sstevel@tonic-gate  */
23047c478bd9Sstevel@tonic-gate static int
is_named_device_avail(devconfig_t * request,char * device_name,boolean_t check_aliases,boolean_t * avail)23057c478bd9Sstevel@tonic-gate is_named_device_avail(
23067c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
23077c478bd9Sstevel@tonic-gate 	char		*device_name,
23087c478bd9Sstevel@tonic-gate 	boolean_t	check_aliases,
23097c478bd9Sstevel@tonic-gate 	boolean_t	*avail)
23107c478bd9Sstevel@tonic-gate {
23117c478bd9Sstevel@tonic-gate 	typedef enum check_types {
23127c478bd9Sstevel@tonic-gate 		DEVICE_REQUEST = 0,
23137c478bd9Sstevel@tonic-gate 		DISKSET_REQUEST,
23147c478bd9Sstevel@tonic-gate 		DEFAULTS,
23157c478bd9Sstevel@tonic-gate 		N_CHECKS
23167c478bd9Sstevel@tonic-gate 	} check_type_t;
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	check_type_t	check_type;
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 	typedef enum list_types {
23217c478bd9Sstevel@tonic-gate 		AVAIL = 0,
23227c478bd9Sstevel@tonic-gate 		UNAVAIL,
23237c478bd9Sstevel@tonic-gate 		N_LISTS
23247c478bd9Sstevel@tonic-gate 	} list_type_t;
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	dlist_t		*lists[N_CHECKS][N_LISTS];
23277c478bd9Sstevel@tonic-gate 	boolean_t	includes;
23287c478bd9Sstevel@tonic-gate 	int		error = 0;
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 	memset(lists, 0, (N_CHECKS * N_LISTS) * sizeof (dlist_t *));
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 	if (request != NULL) {
23337c478bd9Sstevel@tonic-gate 	    /* get avail/unavail specs for request */
23347c478bd9Sstevel@tonic-gate 	    ((error = get_request_avail_spec_list(
23357c478bd9Sstevel@tonic-gate 		    request, &lists[DEVICE_REQUEST][AVAIL])) != 0) ||
23367c478bd9Sstevel@tonic-gate 	    (error = get_request_unavail_spec_list(
23377c478bd9Sstevel@tonic-gate 		    request, &lists[DEVICE_REQUEST][UNAVAIL]));
23387c478bd9Sstevel@tonic-gate 	}
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	if ((error == 0) && (_toplevel_request != NULL)) {
23417c478bd9Sstevel@tonic-gate 	    /* diskset request */
23427c478bd9Sstevel@tonic-gate 	    ((error = get_request_avail_spec_list(
23437c478bd9Sstevel@tonic-gate 		    _toplevel_request, &lists[DISKSET_REQUEST][AVAIL])) != 0) ||
23447c478bd9Sstevel@tonic-gate 	    (error = get_request_unavail_spec_list(
23457c478bd9Sstevel@tonic-gate 		    _toplevel_request, &lists[DISKSET_REQUEST][UNAVAIL]));
23467c478bd9Sstevel@tonic-gate 	}
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	if ((error == 0) && (_defaults != NULL)) {
23497c478bd9Sstevel@tonic-gate 	    /* and diskset/global defaults */
23507c478bd9Sstevel@tonic-gate 	    ((error = get_default_avail_spec_list(_defaults,
23517c478bd9Sstevel@tonic-gate 		    get_request_diskset(), &lists[DEFAULTS][AVAIL])) != 0) ||
23527c478bd9Sstevel@tonic-gate 	    (error = get_default_unavail_spec_list(_defaults,
23537c478bd9Sstevel@tonic-gate 		    get_request_diskset(), &lists[DEFAULTS][UNAVAIL]));
23547c478bd9Sstevel@tonic-gate 	}
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 	if (error != 0) {
23577c478bd9Sstevel@tonic-gate 	    return (error);
23587c478bd9Sstevel@tonic-gate 	}
23597c478bd9Sstevel@tonic-gate 
23607c478bd9Sstevel@tonic-gate 	*avail = B_TRUE;
23617c478bd9Sstevel@tonic-gate 
23627c478bd9Sstevel@tonic-gate 	for (check_type = DEVICE_REQUEST;
23637c478bd9Sstevel@tonic-gate 	    (check_type < N_CHECKS) && (error == 0);
23647c478bd9Sstevel@tonic-gate 	    check_type++) {
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate 	    if (lists[check_type][AVAIL] != NULL) {
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 		/* does avail spec list include named device? */
23697c478bd9Sstevel@tonic-gate 		if ((error = avail_list_includes_device_name(
23707c478bd9Sstevel@tonic-gate 		    lists[check_type][AVAIL], device_name, check_aliases,
23717c478bd9Sstevel@tonic-gate 		    &includes)) == 0) {
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 		    if (includes != B_TRUE) {
23747c478bd9Sstevel@tonic-gate 			*avail = B_FALSE;
23757c478bd9Sstevel@tonic-gate 		    }
23767c478bd9Sstevel@tonic-gate 
23777c478bd9Sstevel@tonic-gate 		    if ((includes == B_TRUE) &&
23787c478bd9Sstevel@tonic-gate 			(lists[check_type][UNAVAIL] != NULL)) {
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 			/* device is available, is it in the unavail list? */
23817c478bd9Sstevel@tonic-gate 			if ((error = unavail_list_includes_device_name(
23827c478bd9Sstevel@tonic-gate 			    lists[check_type][UNAVAIL], device_name,
23837c478bd9Sstevel@tonic-gate 			    check_aliases, &includes)) == 0) {
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 			    if (includes == B_TRUE) {
23867c478bd9Sstevel@tonic-gate 				*avail = B_FALSE;
23877c478bd9Sstevel@tonic-gate 			    }
23887c478bd9Sstevel@tonic-gate 			}
23897c478bd9Sstevel@tonic-gate 		    }
23907c478bd9Sstevel@tonic-gate 		}
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate 		/* lists at this level checked, skip remainder */
23937c478bd9Sstevel@tonic-gate 		break;
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 	    } else if (lists[check_type][UNAVAIL] != NULL) {
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 		/* does unavail spec list include named device? */
23987c478bd9Sstevel@tonic-gate 		if ((error = unavail_list_includes_device_name(
23997c478bd9Sstevel@tonic-gate 		    lists[check_type][UNAVAIL], device_name,
24007c478bd9Sstevel@tonic-gate 		    check_aliases, &includes)) == 0) {
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 		    if (includes == B_TRUE) {
24037c478bd9Sstevel@tonic-gate 			*avail = B_FALSE;
24047c478bd9Sstevel@tonic-gate 		    }
24057c478bd9Sstevel@tonic-gate 		}
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate 		/* list at this level checked, skip remainder */
24087c478bd9Sstevel@tonic-gate 		break;
24097c478bd9Sstevel@tonic-gate 	    }
24107c478bd9Sstevel@tonic-gate 	}
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	return (error);
24137c478bd9Sstevel@tonic-gate }
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate /*
24167c478bd9Sstevel@tonic-gate  * FUNCTION:	avail_list_includes_device_name(dlist_t *list,
24177c478bd9Sstevel@tonic-gate  *			char *device_name, boolean_t check_aliases,
24187c478bd9Sstevel@tonic-gate  *			boolean_t *includes)
24197c478bd9Sstevel@tonic-gate  *
24207c478bd9Sstevel@tonic-gate  * INPUT:	list	- a dlist_t list of available device_spec_t
24217c478bd9Sstevel@tonic-gate  *		device_name  - a char * device CTD name
24227c478bd9Sstevel@tonic-gate  *		check_aliases - boolean_t which indicates if the device's
24237c478bd9Sstevel@tonic-gate  *			aliases	should be considered in the availability
24247c478bd9Sstevel@tonic-gate  *			checking.
24257c478bd9Sstevel@tonic-gate  *
24267c478bd9Sstevel@tonic-gate  * OUTPUT:	includes - B_TRUE - if named device is "included" by any
24277c478bd9Sstevel@tonic-gate  *				specification in the input list
24287c478bd9Sstevel@tonic-gate  *			   B_FALSE - otherwise
24297c478bd9Sstevel@tonic-gate  *
24307c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
24317c478bd9Sstevel@tonic-gate  *			- !0 otherwise
24327c478bd9Sstevel@tonic-gate  *
24337c478bd9Sstevel@tonic-gate  * PURPOSE:	Helper used by is_named_device_avail that determines
24347c478bd9Sstevel@tonic-gate  *		if the input list of device specifications "includes"
24357c478bd9Sstevel@tonic-gate  *		a specific device.
24367c478bd9Sstevel@tonic-gate  *
24377c478bd9Sstevel@tonic-gate  *		Iterates the elements of the input array and searches
24387c478bd9Sstevel@tonic-gate  *		for a match using spec_includes_device_name().
24397c478bd9Sstevel@tonic-gate  */
24407c478bd9Sstevel@tonic-gate static int
avail_list_includes_device_name(dlist_t * list,char * device_name,boolean_t check_aliases,boolean_t * includes)24417c478bd9Sstevel@tonic-gate avail_list_includes_device_name(
24427c478bd9Sstevel@tonic-gate 	dlist_t	*list,
24437c478bd9Sstevel@tonic-gate 	char	*device_name,
24447c478bd9Sstevel@tonic-gate 	boolean_t check_aliases,
24457c478bd9Sstevel@tonic-gate 	boolean_t *includes)
24467c478bd9Sstevel@tonic-gate {
24477c478bd9Sstevel@tonic-gate 	dlist_t *iter = NULL;
24487c478bd9Sstevel@tonic-gate 	int	error = 0;
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	*includes = B_FALSE;
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	for (iter = list;
24537c478bd9Sstevel@tonic-gate 	    (*includes == B_FALSE) && (iter != NULL) && (error == 0);
24547c478bd9Sstevel@tonic-gate 	    iter = iter->next) {
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	    device_spec_t *spec = (device_spec_t *)iter->obj;
24577c478bd9Sstevel@tonic-gate 	    error = spec_includes_device_name(spec, device_name,
24587c478bd9Sstevel@tonic-gate 		    check_aliases, includes);
24597c478bd9Sstevel@tonic-gate 	}
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 	return (0);
24627c478bd9Sstevel@tonic-gate }
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate /*
24657c478bd9Sstevel@tonic-gate  * FUNCTION:	unavail_list_includes_device_name(dlist_t *list,
24667c478bd9Sstevel@tonic-gate  *			char *device_name, boolean_t check_aliases,
24677c478bd9Sstevel@tonic-gate  *			boolean_t *includes)
24687c478bd9Sstevel@tonic-gate  *
24697c478bd9Sstevel@tonic-gate  * INPUT:	list	- a dlist_t list of unavailable device_spec_t
24707c478bd9Sstevel@tonic-gate  *		device_name  - a char * device CTD name
24717c478bd9Sstevel@tonic-gate  *		check_aliases - boolean_t which indicates if the device's
24727c478bd9Sstevel@tonic-gate  *			aliases	should be considered in the availability
24737c478bd9Sstevel@tonic-gate  *			checking.
24747c478bd9Sstevel@tonic-gate  *
24757c478bd9Sstevel@tonic-gate  * OUTPUT:	includes - B_TRUE - if named device is "included" by any
24767c478bd9Sstevel@tonic-gate  *				specification in the input list
24777c478bd9Sstevel@tonic-gate  *			   B_FALSE - otherwise
24787c478bd9Sstevel@tonic-gate  *
24797c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
24807c478bd9Sstevel@tonic-gate  *			- !0 otherwise
24817c478bd9Sstevel@tonic-gate  *
24827c478bd9Sstevel@tonic-gate  * PURPOSE:	Helper used by is_named_device_avail that determines
24837c478bd9Sstevel@tonic-gate  *		if the input list of device specifications "includes"
24847c478bd9Sstevel@tonic-gate  *		a specific device.
24857c478bd9Sstevel@tonic-gate  *
24867c478bd9Sstevel@tonic-gate  *		Iterates the elements of the input array and searches
24877c478bd9Sstevel@tonic-gate  *		for a match using spec_includes_device_name_or_alias().
24887c478bd9Sstevel@tonic-gate  */
24897c478bd9Sstevel@tonic-gate static int
unavail_list_includes_device_name(dlist_t * list,char * device_name,boolean_t check_aliases,boolean_t * includes)24907c478bd9Sstevel@tonic-gate unavail_list_includes_device_name(
24917c478bd9Sstevel@tonic-gate 	dlist_t	*list,
24927c478bd9Sstevel@tonic-gate 	char	*device_name,
24937c478bd9Sstevel@tonic-gate 	boolean_t check_aliases,
24947c478bd9Sstevel@tonic-gate 	boolean_t *includes)
24957c478bd9Sstevel@tonic-gate {
24967c478bd9Sstevel@tonic-gate 	dlist_t *iter = NULL;
24977c478bd9Sstevel@tonic-gate 	int	error = 0;
24987c478bd9Sstevel@tonic-gate 	device_spec_t *unavail_spec;
24997c478bd9Sstevel@tonic-gate 	boolean_t	check_for_alternate_hba = B_FALSE;
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 	*includes = B_FALSE;
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate 	/*
25047c478bd9Sstevel@tonic-gate 	 * the specs in the list are in descending order of specificity.
25057c478bd9Sstevel@tonic-gate 	 * so a more exact spec will rule the device out before a less
25067c478bd9Sstevel@tonic-gate 	 * exact spec.
25077c478bd9Sstevel@tonic-gate 	 *
25087c478bd9Sstevel@tonic-gate 	 * Meaning: if the list has { "c3t0d0", ..., "c3", ... } and the
25097c478bd9Sstevel@tonic-gate 	 * input device name is "c3t0d0s0", it will match "c3t0d0"
25107c478bd9Sstevel@tonic-gate 	 * before "c3".
25117c478bd9Sstevel@tonic-gate 	 *
25127c478bd9Sstevel@tonic-gate 	 * This is important for the multi-path alias checking below.
25137c478bd9Sstevel@tonic-gate 	 * If the input device name is ruled out by a non-controller
25147c478bd9Sstevel@tonic-gate 	 * specification, it is really unavailable.
25157c478bd9Sstevel@tonic-gate 	 */
25167c478bd9Sstevel@tonic-gate 	for (iter = list;
25177c478bd9Sstevel@tonic-gate 	    (*includes == B_FALSE) && (iter != NULL);
25187c478bd9Sstevel@tonic-gate 	    iter = iter->next) {
25197c478bd9Sstevel@tonic-gate 
25207c478bd9Sstevel@tonic-gate 	    unavail_spec = (device_spec_t *)iter->obj;
25217c478bd9Sstevel@tonic-gate 	    error = spec_includes_device_name(
25227c478bd9Sstevel@tonic-gate 		    unavail_spec, device_name, check_aliases, includes);
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	}
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate 	if ((error == 0) && (*includes == B_TRUE)) {
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate 	    /* matched an unavailable spec, was it a controller/HBA? */
25297c478bd9Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
25307c478bd9Sstevel@tonic-gate 		    "device \"%s\" is unavailable, "
25317c478bd9Sstevel@tonic-gate 		    "it matched \"c(%d)t(%d)d(%d)s(%d)\"\n",
25327c478bd9Sstevel@tonic-gate 		    device_name,
25337c478bd9Sstevel@tonic-gate 		    unavail_spec->data.ctd->ctrl,
25347c478bd9Sstevel@tonic-gate 		    unavail_spec->data.ctd->target,
25357c478bd9Sstevel@tonic-gate 		    unavail_spec->data.ctd->lun,
25367c478bd9Sstevel@tonic-gate 		    unavail_spec->data.ctd->slice);
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 	    if ((unavail_spec->data.ctd->ctrl != ID_UNSPECIFIED) &&
25397c478bd9Sstevel@tonic-gate 		(unavail_spec->data.ctd->target == ID_UNSPECIFIED) &&
25407c478bd9Sstevel@tonic-gate 		(unavail_spec->data.ctd->lun == ID_UNSPECIFIED) &&
25417c478bd9Sstevel@tonic-gate 		(unavail_spec->data.ctd->slice == ID_UNSPECIFIED)) {
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 		/*
25447c478bd9Sstevel@tonic-gate 		 * Need to see if the named device is a disk or slice,
25457c478bd9Sstevel@tonic-gate 		 * and if so check to see if the it is multipathed
25467c478bd9Sstevel@tonic-gate 		 * and possibly accessible thru another controller/HBA.
25477c478bd9Sstevel@tonic-gate 		 */
25487c478bd9Sstevel@tonic-gate 		check_for_alternate_hba = B_TRUE;
25497c478bd9Sstevel@tonic-gate 	    }
25507c478bd9Sstevel@tonic-gate 	}
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate 	if ((error == 0) && (check_for_alternate_hba == B_TRUE)) {
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	    dm_descriptor_t slice = (dm_descriptor_t)0;
25557c478bd9Sstevel@tonic-gate 	    dm_descriptor_t disk = (dm_descriptor_t)0;
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate 	    ((error = slice_get_by_name(device_name, &slice)) != 0) ||
25587c478bd9Sstevel@tonic-gate 	    (error = disk_get_by_name(device_name, &disk));
25597c478bd9Sstevel@tonic-gate 	    if (error != 0) {
25607c478bd9Sstevel@tonic-gate 		return (error);
25617c478bd9Sstevel@tonic-gate 	    }
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 	    /* if it is a slice, get its disk */
25647c478bd9Sstevel@tonic-gate 	    if ((error == 0) && (slice != (dm_descriptor_t)0)) {
25657c478bd9Sstevel@tonic-gate 		error = slice_get_disk(slice, &disk);
25667c478bd9Sstevel@tonic-gate 	    }
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 	    if ((error == 0) && (disk != (dm_descriptor_t)0)) {
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 		/* see if all the disk's HBAs are unavailable */
25717c478bd9Sstevel@tonic-gate 		dlist_t *hbas = NULL;
25727c478bd9Sstevel@tonic-gate 		dlist_t *iter = NULL;
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 		error = disk_get_hbas(disk, &hbas);
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 		if (hbas != NULL) {
25777c478bd9Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
25787c478bd9Sstevel@tonic-gate 			    gettext("    checking alternate paths for %s\n"),
25797c478bd9Sstevel@tonic-gate 			    device_name);
25807c478bd9Sstevel@tonic-gate 		} else {
25817c478bd9Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
25827c478bd9Sstevel@tonic-gate 			    gettext("    no alternate paths for %s\n"),
25837c478bd9Sstevel@tonic-gate 			    device_name);
25847c478bd9Sstevel@tonic-gate 		}
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 		/* for each of the disk's HBAs */
25877c478bd9Sstevel@tonic-gate 		for (iter = hbas;
25887c478bd9Sstevel@tonic-gate 		    (iter != NULL) && (*includes == B_TRUE) && (error == 0);
25897c478bd9Sstevel@tonic-gate 		    iter = iter->next) {
25907c478bd9Sstevel@tonic-gate 
25917c478bd9Sstevel@tonic-gate 		    dm_descriptor_t hba = (uintptr_t)iter->obj;
25927c478bd9Sstevel@tonic-gate 		    device_spec_t *hbaspec;
25937c478bd9Sstevel@tonic-gate 		    char *hbaname = NULL;
25947c478bd9Sstevel@tonic-gate 		    dlist_t *iter2 = NULL;
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 		    *includes = B_FALSE;
25977c478bd9Sstevel@tonic-gate 
25987c478bd9Sstevel@tonic-gate 		    ((error = get_display_name(hba, &hbaname)) != 0) ||
25997c478bd9Sstevel@tonic-gate 		    (error = get_spec_for_name(hbaname, &hbaspec));
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 		    /* is HBA unavailable? */
26027c478bd9Sstevel@tonic-gate 		    for (iter2 = list;
26037c478bd9Sstevel@tonic-gate 			(iter2 != NULL) && (error == 0) &&
26047c478bd9Sstevel@tonic-gate 				(*includes == B_FALSE);
26057c478bd9Sstevel@tonic-gate 			iter2 = iter2->next) {
26067c478bd9Sstevel@tonic-gate 
26077c478bd9Sstevel@tonic-gate 			device_spec_t *spec =
26087c478bd9Sstevel@tonic-gate 			    (device_spec_t *)iter2->obj;
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 			*includes = spec_includes_device(spec, hbaspec);
26117c478bd9Sstevel@tonic-gate 		    }
26127c478bd9Sstevel@tonic-gate 		}
26137c478bd9Sstevel@tonic-gate 		dlist_free_items(hbas, NULL);
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 		/* if *includes==B_TRUE here, all HBAs are unavailable */
26167c478bd9Sstevel@tonic-gate 	    }
26177c478bd9Sstevel@tonic-gate 	}
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 	return (error);
26207c478bd9Sstevel@tonic-gate }
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate /*
26237c478bd9Sstevel@tonic-gate  * FUNCTION:	spec_includes_device_name(device_spec_t *spec,
26247c478bd9Sstevel@tonic-gate  *			char *device_name, boolean_t check_aliases,
26257c478bd9Sstevel@tonic-gate  *			boolean_t *includes)
26267c478bd9Sstevel@tonic-gate  *
26277c478bd9Sstevel@tonic-gate  * INPUT:	spec	- a device_spec_t CTD specification.
26287c478bd9Sstevel@tonic-gate  *		device_name  - a char * device CTD name
26297c478bd9Sstevel@tonic-gate  *		check_aliases - boolean_t which indicates if the device's
26307c478bd9Sstevel@tonic-gate  *			aliases	should be considered in the checking.
26317c478bd9Sstevel@tonic-gate  *
26327c478bd9Sstevel@tonic-gate  * OUTPUT:	includes - B_TRUE - if device is "included" by the input
26337c478bd9Sstevel@tonic-gate  *				specification
26347c478bd9Sstevel@tonic-gate  *			    B_FALSE - otherwise
26357c478bd9Sstevel@tonic-gate  *
26367c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
26377c478bd9Sstevel@tonic-gate  *			- !0 otherwise
26387c478bd9Sstevel@tonic-gate  *
26397c478bd9Sstevel@tonic-gate  * PURPOSE:	Helper used by (un)avail_specs_includes_device_name() that
26407c478bd9Sstevel@tonic-gate  *		determines if the input device specification "includes"
26417c478bd9Sstevel@tonic-gate  *		the named device.
26427c478bd9Sstevel@tonic-gate  *
26437c478bd9Sstevel@tonic-gate  *		If check_aliases is true and the named device is a slice or
26447c478bd9Sstevel@tonic-gate  *		a disk drive, its multi-pathed aliases are also checked
26457c478bd9Sstevel@tonic-gate  *		against the spec.
26467c478bd9Sstevel@tonic-gate  */
26477c478bd9Sstevel@tonic-gate static int
spec_includes_device_name(device_spec_t * spec,char * device_name,boolean_t check_aliases,boolean_t * includes)26487c478bd9Sstevel@tonic-gate spec_includes_device_name(
26497c478bd9Sstevel@tonic-gate 	device_spec_t *spec,
26507c478bd9Sstevel@tonic-gate 	char		 *device_name,
26517c478bd9Sstevel@tonic-gate 	boolean_t	check_aliases,
26527c478bd9Sstevel@tonic-gate 	boolean_t	*includes)
26537c478bd9Sstevel@tonic-gate {
26547c478bd9Sstevel@tonic-gate 	device_spec_t *device_spec;
26557c478bd9Sstevel@tonic-gate 	int error = 0;
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate 	error = get_spec_for_name(device_name, &device_spec);
26587c478bd9Sstevel@tonic-gate 	if (error == 0) {
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	    *includes = spec_includes_device(spec, device_spec);
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate 	    if ((*includes == B_FALSE) && (check_aliases == B_TRUE)) {
26637c478bd9Sstevel@tonic-gate 
26647c478bd9Sstevel@tonic-gate 		/* spec doesn't include name, check aliases */
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate 		dm_descriptor_t device = (dm_descriptor_t)0;
26677c478bd9Sstevel@tonic-gate 		dlist_t *aliases = NULL;
26687c478bd9Sstevel@tonic-gate 
26697c478bd9Sstevel@tonic-gate 		/* only slices and disks have aliases */
26707c478bd9Sstevel@tonic-gate 		error = slice_get_by_name(device_name, &device);
26717c478bd9Sstevel@tonic-gate 		if (device != (dm_descriptor_t)0) {
26727c478bd9Sstevel@tonic-gate 		    error = get_aliases(device, &aliases);
26737c478bd9Sstevel@tonic-gate 		} else if (error == 0) {
26747c478bd9Sstevel@tonic-gate 		    error = disk_get_by_name(device_name, &device);
26757c478bd9Sstevel@tonic-gate 		    if (device != (dm_descriptor_t)0) {
26767c478bd9Sstevel@tonic-gate 			error = get_aliases(device, &aliases);
26777c478bd9Sstevel@tonic-gate 		    }
26787c478bd9Sstevel@tonic-gate 		}
26797c478bd9Sstevel@tonic-gate 
26807c478bd9Sstevel@tonic-gate 		if ((error == 0) && (aliases != NULL)) {
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 		    dlist_t *iter;
26837c478bd9Sstevel@tonic-gate 		    for (iter = aliases;
26847c478bd9Sstevel@tonic-gate 			(iter != NULL) && (*includes == B_FALSE) &&
26857c478bd9Sstevel@tonic-gate 				(error == 0);
26867c478bd9Sstevel@tonic-gate 			iter = iter->next) {
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate 			char *alias = (char *)iter->obj;
26897c478bd9Sstevel@tonic-gate 			device_spec_t *alias_spec;
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate 			error = get_spec_for_name(alias, &alias_spec);
26927c478bd9Sstevel@tonic-gate 			if (error == 0) {
26937c478bd9Sstevel@tonic-gate 			    /* does spec include alias? */
26947c478bd9Sstevel@tonic-gate 			    *includes =	spec_includes_device(spec, alias_spec);
26957c478bd9Sstevel@tonic-gate 			}
26967c478bd9Sstevel@tonic-gate 		    }
26977c478bd9Sstevel@tonic-gate 		}
26987c478bd9Sstevel@tonic-gate 		dlist_free_items(aliases, free);
26997c478bd9Sstevel@tonic-gate 	    }
27007c478bd9Sstevel@tonic-gate 	}
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 	return (error);
27037c478bd9Sstevel@tonic-gate }
27047c478bd9Sstevel@tonic-gate 
27057c478bd9Sstevel@tonic-gate /*
27067c478bd9Sstevel@tonic-gate  * FUNCTION:	destroy_device_spec(device_spec_t *spec)
27077c478bd9Sstevel@tonic-gate  *
27087c478bd9Sstevel@tonic-gate  * INPUT:	spec	- pointer to a device_spec_t
27097c478bd9Sstevel@tonic-gate  *
27107c478bd9Sstevel@tonic-gate  * RETURNS:	nothing
27117c478bd9Sstevel@tonic-gate  *
27127c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which reclaims memory allocated to a device_spec_t.
27137c478bd9Sstevel@tonic-gate  *
27147c478bd9Sstevel@tonic-gate  *		Frees memory allocated to hold the specific data in the spec.
27157c478bd9Sstevel@tonic-gate  */
27167c478bd9Sstevel@tonic-gate static void
destroy_device_spec(device_spec_t * spec)27177c478bd9Sstevel@tonic-gate destroy_device_spec(
27187c478bd9Sstevel@tonic-gate 	device_spec_t *spec)
27197c478bd9Sstevel@tonic-gate {
27207c478bd9Sstevel@tonic-gate 	if (spec != NULL) {
27217c478bd9Sstevel@tonic-gate 	    if (spec->type == SPEC_TYPE_CTD) {
27227c478bd9Sstevel@tonic-gate 		free(spec->data.ctd);
27237c478bd9Sstevel@tonic-gate 	    } else if (spec->type == SPEC_TYPE_RAW) {
27247c478bd9Sstevel@tonic-gate 		free(spec->data.raw);
27257c478bd9Sstevel@tonic-gate 	    }
27267c478bd9Sstevel@tonic-gate 	    free(spec);
27277c478bd9Sstevel@tonic-gate 	}
27287c478bd9Sstevel@tonic-gate }
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate /*
27317c478bd9Sstevel@tonic-gate  * FUNCTION:	create_device_spec(char *name, device_spec_t **spec);
27327c478bd9Sstevel@tonic-gate  *
27337c478bd9Sstevel@tonic-gate  * INPUT:	name	- pointer to a char* device name
27347c478bd9Sstevel@tonic-gate  *
27357c478bd9Sstevel@tonic-gate  * OUTPUT:	spec	- pointer to a device_spec_t to hold the result
27367c478bd9Sstevel@tonic-gate  *
27377c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
27387c478bd9Sstevel@tonic-gate  *			 !0 otherwise
27397c478bd9Sstevel@tonic-gate  *
27407c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which creates a device_spec_t for the input
27417c478bd9Sstevel@tonic-gate  *		device name.
27427c478bd9Sstevel@tonic-gate  *
27437c478bd9Sstevel@tonic-gate  */
27447c478bd9Sstevel@tonic-gate static int
create_device_spec(char * name,device_spec_t ** spec)27457c478bd9Sstevel@tonic-gate create_device_spec(
27467c478bd9Sstevel@tonic-gate 	char	*name,
27477c478bd9Sstevel@tonic-gate 	device_spec_t **spec)
27487c478bd9Sstevel@tonic-gate {
27497c478bd9Sstevel@tonic-gate 	int error = 0;
27507c478bd9Sstevel@tonic-gate 
27517c478bd9Sstevel@tonic-gate 	/* allocate the device spec and try various parsing schemes */
27527c478bd9Sstevel@tonic-gate 	*spec = (device_spec_t *)calloc(1, sizeof (device_spec_t));
27537c478bd9Sstevel@tonic-gate 	if (*spec == NULL) {
27547c478bd9Sstevel@tonic-gate 	    error = ENOMEM;
27557c478bd9Sstevel@tonic-gate 	} else {
27567c478bd9Sstevel@tonic-gate 	    if (((error = create_device_ctd_spec(name, spec)) != 0) &&
27577c478bd9Sstevel@tonic-gate 		    (error != ENOMEM)) {
27587c478bd9Sstevel@tonic-gate 		/* CTD failed, try other parsing schemes */
27597c478bd9Sstevel@tonic-gate 		error = create_device_raw_spec(name, spec);
27607c478bd9Sstevel@tonic-gate 	    }
27617c478bd9Sstevel@tonic-gate 	}
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate 	return (error);
27647c478bd9Sstevel@tonic-gate }
27657c478bd9Sstevel@tonic-gate 
27667c478bd9Sstevel@tonic-gate /*
27677c478bd9Sstevel@tonic-gate  * FUNCTION:	create_device_ctd_spec(char *name, device_spec_t **spec);
27687c478bd9Sstevel@tonic-gate  *
27697c478bd9Sstevel@tonic-gate  * INPUT:	name	- pointer to a char* device name
27707c478bd9Sstevel@tonic-gate  *
27717c478bd9Sstevel@tonic-gate  * OUTPUT:	spec	- pointer to a device_spec_t updated with the parsed
27727c478bd9Sstevel@tonic-gate  *				CTD spec, if successful
27737c478bd9Sstevel@tonic-gate  *
27747c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
27757c478bd9Sstevel@tonic-gate  *			 !0 otherwise
27767c478bd9Sstevel@tonic-gate  *
27777c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which atttempts to parse the input device name into
27787c478bd9Sstevel@tonic-gate  *		cXtXdXsX component ids. The ids are the integer values of each
27797c478bd9Sstevel@tonic-gate  *		specified segment of the input name.
27807c478bd9Sstevel@tonic-gate  *
27817c478bd9Sstevel@tonic-gate  *		If the name doesn't contain a segment, the id is set to
27827c478bd9Sstevel@tonic-gate  *		ID_UNSPECIFIED.
27837c478bd9Sstevel@tonic-gate  *
27847c478bd9Sstevel@tonic-gate  *		The input name must be well-formed.
27857c478bd9Sstevel@tonic-gate  *
27867c478bd9Sstevel@tonic-gate  *		These are the acceptable forms:
27877c478bd9Sstevel@tonic-gate  *
27887c478bd9Sstevel@tonic-gate  *		cXtXdXsX
27897c478bd9Sstevel@tonic-gate  *		cXtXdX
27907c478bd9Sstevel@tonic-gate  *		cXtX
27917c478bd9Sstevel@tonic-gate  *		cXdXsX
27927c478bd9Sstevel@tonic-gate  *		cXdX
27937c478bd9Sstevel@tonic-gate  *		cX
27947c478bd9Sstevel@tonic-gate  */
27957c478bd9Sstevel@tonic-gate static int
create_device_ctd_spec(char * name,device_spec_t ** spec)27967c478bd9Sstevel@tonic-gate create_device_ctd_spec(
27977c478bd9Sstevel@tonic-gate 	char	*name,
27987c478bd9Sstevel@tonic-gate 	device_spec_t **spec)
27997c478bd9Sstevel@tonic-gate {
28007c478bd9Sstevel@tonic-gate 	uint_t	ctrl;
28017c478bd9Sstevel@tonic-gate 	uint_t	target;
28027c478bd9Sstevel@tonic-gate 	uint_t	lun;
28037c478bd9Sstevel@tonic-gate 	uint_t	slice;
28047c478bd9Sstevel@tonic-gate 
28057c478bd9Sstevel@tonic-gate 	uint_t	nscan;
28067c478bd9Sstevel@tonic-gate 	uint_t	nchars;
28077c478bd9Sstevel@tonic-gate 
28087c478bd9Sstevel@tonic-gate 	char	*device_str;
28097c478bd9Sstevel@tonic-gate 	char	*target_str;
28107c478bd9Sstevel@tonic-gate 	char	*ctd_str;
28117c478bd9Sstevel@tonic-gate 	char	*t_ptr;
28127c478bd9Sstevel@tonic-gate 	char	*d_ptr;
28137c478bd9Sstevel@tonic-gate 	char	*s_ptr;
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate 	boolean_t is_ide = B_FALSE;
28167c478bd9Sstevel@tonic-gate 	boolean_t got_slice = B_FALSE;
28177c478bd9Sstevel@tonic-gate 	boolean_t got_lun = B_FALSE;
28187c478bd9Sstevel@tonic-gate 	boolean_t got_target = B_FALSE;
28197c478bd9Sstevel@tonic-gate 	boolean_t got_ctrl = B_FALSE;
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 	int 	error = 0;
28227c478bd9Sstevel@tonic-gate 
28237c478bd9Sstevel@tonic-gate 	ctd_str = strdup(name);
28247c478bd9Sstevel@tonic-gate 	if (ctd_str == NULL) {
28257c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
28267c478bd9Sstevel@tonic-gate 	}
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate 	/* trim any leading path (/dev/dsk/cXtXdXsX) */
28297c478bd9Sstevel@tonic-gate 	if ((device_str = strrchr(ctd_str, '/')) != NULL) {
28307c478bd9Sstevel@tonic-gate 	    ++device_str;
28317c478bd9Sstevel@tonic-gate 	} else {
28327c478bd9Sstevel@tonic-gate 	    device_str = ctd_str;
28337c478bd9Sstevel@tonic-gate 	}
28347c478bd9Sstevel@tonic-gate 
28357c478bd9Sstevel@tonic-gate 	/* find each segment start position */
28367c478bd9Sstevel@tonic-gate 	t_ptr = strrchr(device_str, 't');
28377c478bd9Sstevel@tonic-gate 	d_ptr = strrchr(device_str, 'd');
28387c478bd9Sstevel@tonic-gate 	s_ptr = strrchr(device_str, 's');
28397c478bd9Sstevel@tonic-gate 
28407c478bd9Sstevel@tonic-gate 	/*
28417c478bd9Sstevel@tonic-gate 	 * scan ids from each existing segment working backwards
28427c478bd9Sstevel@tonic-gate 	 * so as to leave the device_str in the correct state
28437c478bd9Sstevel@tonic-gate 	 * for the next expected segment
28447c478bd9Sstevel@tonic-gate 	 */
28457c478bd9Sstevel@tonic-gate 	if (s_ptr != NULL) {
28467c478bd9Sstevel@tonic-gate 
28477c478bd9Sstevel@tonic-gate 	    /* found 's', try to get slice */
28487c478bd9Sstevel@tonic-gate 	    nchars = strlen(s_ptr);
28497c478bd9Sstevel@tonic-gate 	    if ((sscanf(s_ptr, "s%u%n", &slice, &nscan) != 1) ||
28507c478bd9Sstevel@tonic-gate 		(nscan != nchars)) {
28517c478bd9Sstevel@tonic-gate 
28527c478bd9Sstevel@tonic-gate 		error = -1;
28537c478bd9Sstevel@tonic-gate 		oprintf(OUTPUT_DEBUG,
28547c478bd9Sstevel@tonic-gate 			gettext("no slice component in device "
28557c478bd9Sstevel@tonic-gate 				"name \"%s\".\n"),
28567c478bd9Sstevel@tonic-gate 			name);
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 	    } else {
28597c478bd9Sstevel@tonic-gate 		got_slice = B_TRUE;
28607c478bd9Sstevel@tonic-gate 		*s_ptr = '\0';
28617c478bd9Sstevel@tonic-gate 	    }
28627c478bd9Sstevel@tonic-gate 	}
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 	if ((error == 0) && (d_ptr != NULL)) {
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate 	    /* found 'd', try to get disk/lun */
28677c478bd9Sstevel@tonic-gate 	    nchars = strlen(d_ptr);
28687c478bd9Sstevel@tonic-gate 	    if ((sscanf(d_ptr, "d%u%n", &lun, &nscan) != 1) ||
28697c478bd9Sstevel@tonic-gate 		(nscan != nchars)) {
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate 		error = -1;
28727c478bd9Sstevel@tonic-gate 		oprintf(OUTPUT_DEBUG,
28737c478bd9Sstevel@tonic-gate 			gettext("no disk/lun component "
28747c478bd9Sstevel@tonic-gate 				"in device name \"%s\".\n"),
28757c478bd9Sstevel@tonic-gate 			name);
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate 	    } else {
28787c478bd9Sstevel@tonic-gate 		got_lun = B_TRUE;
28797c478bd9Sstevel@tonic-gate 		*d_ptr = '\0';
28807c478bd9Sstevel@tonic-gate 	    }
28817c478bd9Sstevel@tonic-gate 	}
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate 	if ((error == 0) && (t_ptr != NULL)) {
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate 	    /* found 't', try to get target, it may be a hex WWN id */
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate 	    /* skip leading 't' and add two for the 'OX' */
28887c478bd9Sstevel@tonic-gate 	    nchars = strlen(t_ptr + 1) + 2;
28897c478bd9Sstevel@tonic-gate 	    if ((target_str = (char *)malloc(nchars+1)) == NULL) {
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate 		error = ENOMEM;
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate 	    } else {
28947c478bd9Sstevel@tonic-gate 
28957c478bd9Sstevel@tonic-gate 		strcpy(target_str, "0X");
28967c478bd9Sstevel@tonic-gate 		strcpy(target_str+2, t_ptr + 1);
28977c478bd9Sstevel@tonic-gate 		target_str[nchars] = '\0';
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 		if ((sscanf(target_str, "%x%n", &target, &nscan) != 1) ||
29007c478bd9Sstevel@tonic-gate 		    (nscan != nchars)) {
29017c478bd9Sstevel@tonic-gate 
29027c478bd9Sstevel@tonic-gate 		    error = -1;
29037c478bd9Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
29047c478bd9Sstevel@tonic-gate 			    gettext("no target/WWN component "
29057c478bd9Sstevel@tonic-gate 				    "in device name \"%s\".\n"),
29067c478bd9Sstevel@tonic-gate 			    name);
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate 		} else {
29097c478bd9Sstevel@tonic-gate 		    got_target = B_TRUE;
29107c478bd9Sstevel@tonic-gate 		    *t_ptr = '\0';
29117c478bd9Sstevel@tonic-gate 		}
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate 		free(target_str);
29147c478bd9Sstevel@tonic-gate 	    }
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 	} else {
29177c478bd9Sstevel@tonic-gate 	    is_ide = B_TRUE;
29187c478bd9Sstevel@tonic-gate 	}
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate 	if ((error == 0) && (device_str != NULL)) {
29217c478bd9Sstevel@tonic-gate 
29227c478bd9Sstevel@tonic-gate 	    /* get controller/hba/channel */
29237c478bd9Sstevel@tonic-gate 	    nchars = strlen(device_str);
29247c478bd9Sstevel@tonic-gate 	    if ((sscanf(device_str, "c%u%n", &ctrl, &nscan) != 1) ||
29257c478bd9Sstevel@tonic-gate 		    (nscan != nchars)) {
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate 		error = -1;
29287c478bd9Sstevel@tonic-gate 		oprintf(OUTPUT_DEBUG,
29297c478bd9Sstevel@tonic-gate 			gettext("no channel/HBA component "
29307c478bd9Sstevel@tonic-gate 				"in device name \"%s\".\n"),
29317c478bd9Sstevel@tonic-gate 			name);
29327c478bd9Sstevel@tonic-gate 
29337c478bd9Sstevel@tonic-gate 	    } else {
29347c478bd9Sstevel@tonic-gate 		got_ctrl = B_TRUE;
29357c478bd9Sstevel@tonic-gate 	    }
29367c478bd9Sstevel@tonic-gate 	}
29377c478bd9Sstevel@tonic-gate 
29387c478bd9Sstevel@tonic-gate 	free(ctd_str);
29397c478bd9Sstevel@tonic-gate 
29407c478bd9Sstevel@tonic-gate 	if (error == 0) {
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate 	    /* allocate the ctd_spec_t struct and store the ids */
29437c478bd9Sstevel@tonic-gate 	    (*spec)->type = SPEC_TYPE_CTD;
29447c478bd9Sstevel@tonic-gate 	    (*spec)->data.ctd = (ctd_spec_t *)calloc(1, sizeof (ctd_spec_t));
29457c478bd9Sstevel@tonic-gate 
29467c478bd9Sstevel@tonic-gate 	    if ((*spec)->data.ctd == NULL) {
29477c478bd9Sstevel@tonic-gate 		error = ENOMEM;
29487c478bd9Sstevel@tonic-gate 	    }
29497c478bd9Sstevel@tonic-gate 
29507c478bd9Sstevel@tonic-gate 	    (*spec)->data.ctd->slice = ID_UNSPECIFIED;
29517c478bd9Sstevel@tonic-gate 	    (*spec)->data.ctd->lun = ID_UNSPECIFIED;
29527c478bd9Sstevel@tonic-gate 	    (*spec)->data.ctd->target = ID_UNSPECIFIED;
29537c478bd9Sstevel@tonic-gate 	    (*spec)->data.ctd->ctrl = ID_UNSPECIFIED;
29547c478bd9Sstevel@tonic-gate 
29557c478bd9Sstevel@tonic-gate 	    if (got_slice == B_TRUE) {
29567c478bd9Sstevel@tonic-gate 		(*spec)->data.ctd->slice = slice;
29577c478bd9Sstevel@tonic-gate 	    }
29587c478bd9Sstevel@tonic-gate 
29597c478bd9Sstevel@tonic-gate 	    if (got_lun == B_TRUE) {
29607c478bd9Sstevel@tonic-gate 		(*spec)->data.ctd->lun = lun;
29617c478bd9Sstevel@tonic-gate 	    }
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate 	    if (got_target == B_TRUE) {
29647c478bd9Sstevel@tonic-gate 		(*spec)->data.ctd->target = target;
29657c478bd9Sstevel@tonic-gate 	    }
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate 	    if (got_ctrl == B_TRUE) {
29687c478bd9Sstevel@tonic-gate 		(*spec)->data.ctd->ctrl = ctrl;
29697c478bd9Sstevel@tonic-gate 	    }
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 	    (*spec)->data.ctd->is_ide = is_ide;
29727c478bd9Sstevel@tonic-gate 	}
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate 	return (error);
29757c478bd9Sstevel@tonic-gate }
29767c478bd9Sstevel@tonic-gate 
29777c478bd9Sstevel@tonic-gate /*
29787c478bd9Sstevel@tonic-gate  * FUNCTION:	create_device_raw_spec(char *name, device_spec_t **spec);
29797c478bd9Sstevel@tonic-gate  *
29807c478bd9Sstevel@tonic-gate  * INPUT:	name	- pointer to a char* device name
29817c478bd9Sstevel@tonic-gate  *
29827c478bd9Sstevel@tonic-gate  * OUTPUT:	spec	- pointer to a device_spec_t updated with the raw spec
29837c478bd9Sstevel@tonic-gate  *
29847c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
29857c478bd9Sstevel@tonic-gate  *			 !0 otherwise
29867c478bd9Sstevel@tonic-gate  *
29877c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which creates a "raw" spec for the input name.
29887c478bd9Sstevel@tonic-gate  *
29897c478bd9Sstevel@tonic-gate  *		This is a last resort if all other spec parsing schemes failed,
29907c478bd9Sstevel@tonic-gate  *		the "raw" spec is just the input device name.
29917c478bd9Sstevel@tonic-gate  */
29927c478bd9Sstevel@tonic-gate static int
create_device_raw_spec(char * name,device_spec_t ** spec)29937c478bd9Sstevel@tonic-gate create_device_raw_spec(
29947c478bd9Sstevel@tonic-gate 	char	*name,
29957c478bd9Sstevel@tonic-gate 	device_spec_t **spec)
29967c478bd9Sstevel@tonic-gate {
29977c478bd9Sstevel@tonic-gate 	int 	error = 0;
29987c478bd9Sstevel@tonic-gate 	char	*ctd_str = strdup(name);
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 	if (ctd_str == NULL) {
30017c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
30027c478bd9Sstevel@tonic-gate 	}
30037c478bd9Sstevel@tonic-gate 
30047c478bd9Sstevel@tonic-gate 	(*spec)->type = SPEC_TYPE_RAW;
30057c478bd9Sstevel@tonic-gate 	(*spec)->data.raw = ctd_str;
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 	oprintf(OUTPUT_DEBUG,
30087c478bd9Sstevel@tonic-gate 		gettext("made raw device spec for \"%s\"\n"), ctd_str);
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 	return (error);
30117c478bd9Sstevel@tonic-gate }
30127c478bd9Sstevel@tonic-gate 
30137c478bd9Sstevel@tonic-gate /*
30147c478bd9Sstevel@tonic-gate  * FUNCTION:	get_spec_for_name(char *name, device_spec_t **id);
30157c478bd9Sstevel@tonic-gate  *
30167c478bd9Sstevel@tonic-gate  * INPUT:	name	- pointer to a char* device name
30177c478bd9Sstevel@tonic-gate  *
30187c478bd9Sstevel@tonic-gate  * OUTPUT:	id	- pointer to a device_spec_t to hold the result
30197c478bd9Sstevel@tonic-gate  *
30207c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
30217c478bd9Sstevel@tonic-gate  *			 !0 otherwise
30227c478bd9Sstevel@tonic-gate  *
30237c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which finds the device_spec_t that already
30247c478bd9Sstevel@tonic-gate  *		exists for the input name or creates it.
30257c478bd9Sstevel@tonic-gate  *
30267c478bd9Sstevel@tonic-gate  *		The returned struct should not be freed, it is maintained
30277c478bd9Sstevel@tonic-gate  *		in a cache that will be purged when the layout process
30287c478bd9Sstevel@tonic-gate  *		is complete.
30297c478bd9Sstevel@tonic-gate  */
30307c478bd9Sstevel@tonic-gate int
get_spec_for_name(char * name,device_spec_t ** id)30317c478bd9Sstevel@tonic-gate get_spec_for_name(
30327c478bd9Sstevel@tonic-gate 	char	*name,
30337c478bd9Sstevel@tonic-gate 	device_spec_t **id)
30347c478bd9Sstevel@tonic-gate {
30357c478bd9Sstevel@tonic-gate 	dlist_t *item;
30367c478bd9Sstevel@tonic-gate 	int	error = 0;
30377c478bd9Sstevel@tonic-gate 
30387c478bd9Sstevel@tonic-gate 	item = dlist_find(_spec_cache, (void *)name,
30397c478bd9Sstevel@tonic-gate 		compare_name_to_spec_cache_name);
30407c478bd9Sstevel@tonic-gate 
30417c478bd9Sstevel@tonic-gate 	if (item == NULL) {
30427c478bd9Sstevel@tonic-gate 	    if ((error = create_device_spec(name, id)) == 0) {
30437c478bd9Sstevel@tonic-gate 
30447c478bd9Sstevel@tonic-gate 		spec_cache_t *entry = (spec_cache_t *)
30457c478bd9Sstevel@tonic-gate 		    calloc(1, sizeof (spec_cache_t));
30467c478bd9Sstevel@tonic-gate 
30477c478bd9Sstevel@tonic-gate 		if (entry == NULL) {
30487c478bd9Sstevel@tonic-gate 		    destroy_device_spec(*id);
30497c478bd9Sstevel@tonic-gate 		    error = ENOMEM;
30507c478bd9Sstevel@tonic-gate 		} else {
30517c478bd9Sstevel@tonic-gate 		    char *dup = strdup(name);
30527c478bd9Sstevel@tonic-gate 		    if (dup == NULL) {
30537c478bd9Sstevel@tonic-gate 			free(entry);
30547c478bd9Sstevel@tonic-gate 			destroy_device_spec(*id);
30557c478bd9Sstevel@tonic-gate 			*id = NULL;
30567c478bd9Sstevel@tonic-gate 			error = ENOMEM;
30577c478bd9Sstevel@tonic-gate 		    } else {
30587c478bd9Sstevel@tonic-gate 			entry->name = dup;
30597c478bd9Sstevel@tonic-gate 			entry->device_spec = *id;
30607c478bd9Sstevel@tonic-gate 		    }
30617c478bd9Sstevel@tonic-gate 
30627c478bd9Sstevel@tonic-gate 		    if (error == 0) {
30637c478bd9Sstevel@tonic-gate 			dlist_t *item = dlist_new_item((void *)entry);
30647c478bd9Sstevel@tonic-gate 			if (item == NULL) {
30657c478bd9Sstevel@tonic-gate 			    free(entry);
30667c478bd9Sstevel@tonic-gate 			    destroy_device_spec(*id);
30677c478bd9Sstevel@tonic-gate 			    *id = NULL;
30687c478bd9Sstevel@tonic-gate 			    error = ENOMEM;
30697c478bd9Sstevel@tonic-gate 			} else {
30707c478bd9Sstevel@tonic-gate 			    _spec_cache =
30717c478bd9Sstevel@tonic-gate 				dlist_append(item, _spec_cache, AT_HEAD);
30727c478bd9Sstevel@tonic-gate 			}
30737c478bd9Sstevel@tonic-gate 		    }
30747c478bd9Sstevel@tonic-gate 		}
30757c478bd9Sstevel@tonic-gate 	    }
30767c478bd9Sstevel@tonic-gate 	} else {
30777c478bd9Sstevel@tonic-gate 	    *id = ((spec_cache_t *)item->obj)->device_spec;
30787c478bd9Sstevel@tonic-gate 	}
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 	return (error);
30817c478bd9Sstevel@tonic-gate }
30827c478bd9Sstevel@tonic-gate 
30837c478bd9Sstevel@tonic-gate /*
30847c478bd9Sstevel@tonic-gate  * FUNCTION:	spec_includes_device(device_spec_t *spec,
30857c478bd9Sstevel@tonic-gate  *			device_spec_t *device)
30867c478bd9Sstevel@tonic-gate  *
30877c478bd9Sstevel@tonic-gate  * INPUT:	spec	- pointer to a device_spec struct
30887c478bd9Sstevel@tonic-gate  *		device	- pointer to a device_spec struct
30897c478bd9Sstevel@tonic-gate  *
30907c478bd9Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the device is included in the spec
30917c478bd9Sstevel@tonic-gate  *			 B_FALSE otherwise
30927c478bd9Sstevel@tonic-gate  *
30937c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which determines if the input device matches the
30947c478bd9Sstevel@tonic-gate  *		input spec.
30957c478bd9Sstevel@tonic-gate  *
30967c478bd9Sstevel@tonic-gate  *		If both specs are of the same type, the appropriate
30977c478bd9Sstevel@tonic-gate  *		comparison function is called.
30987c478bd9Sstevel@tonic-gate  *
30997c478bd9Sstevel@tonic-gate  *		If the two specs are of different types, no comparison
31007c478bd9Sstevel@tonic-gate  *		is done and B_FALSE is returned.
31017c478bd9Sstevel@tonic-gate  */
31027c478bd9Sstevel@tonic-gate boolean_t
spec_includes_device(device_spec_t * spec,device_spec_t * device)31037c478bd9Sstevel@tonic-gate spec_includes_device(
31047c478bd9Sstevel@tonic-gate 	device_spec_t *spec,
31057c478bd9Sstevel@tonic-gate 	device_spec_t *device)
31067c478bd9Sstevel@tonic-gate {
31077c478bd9Sstevel@tonic-gate 	if ((spec->type == SPEC_TYPE_CTD) && (device->type == SPEC_TYPE_CTD)) {
31087c478bd9Sstevel@tonic-gate 	    return (ctd_spec_includes_device(spec, device));
31097c478bd9Sstevel@tonic-gate 	} else if ((spec->type == SPEC_TYPE_RAW) &&
31107c478bd9Sstevel@tonic-gate 	    (device->type == SPEC_TYPE_RAW)) {
31117c478bd9Sstevel@tonic-gate 	    return (raw_spec_includes_device(spec, device));
31127c478bd9Sstevel@tonic-gate 	}
31137c478bd9Sstevel@tonic-gate 
31147c478bd9Sstevel@tonic-gate 	return (B_FALSE);
31157c478bd9Sstevel@tonic-gate }
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate /*
31187c478bd9Sstevel@tonic-gate  * FUNCTION:	ctd_spec_includes_device(device_spec_t *spec,
31197c478bd9Sstevel@tonic-gate  *			device_spec_t *device)
31207c478bd9Sstevel@tonic-gate  *
31217c478bd9Sstevel@tonic-gate  * INPUT:	spec	- pointer to a device_spec struct
31227c478bd9Sstevel@tonic-gate  *		device	- pointer to a device_spec struct
31237c478bd9Sstevel@tonic-gate  *
31247c478bd9Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the device is included in the spec
31257c478bd9Sstevel@tonic-gate  *			 B_FALSE otherwise
31267c478bd9Sstevel@tonic-gate  *
31277c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which determines if the input CTD device spec
31287c478bd9Sstevel@tonic-gate  *		matches the input CTD spec.
31297c478bd9Sstevel@tonic-gate  *
31307c478bd9Sstevel@tonic-gate  *		The device_spec_t structs contain component "ids" for
31317c478bd9Sstevel@tonic-gate  *		both the specification and the device.
31327c478bd9Sstevel@tonic-gate  *
31337c478bd9Sstevel@tonic-gate  *		The device must match each of the ids in the spec that
31347c478bd9Sstevel@tonic-gate  *		are specified.
31357c478bd9Sstevel@tonic-gate  *
31367c478bd9Sstevel@tonic-gate  *		spec		devices matched
31377c478bd9Sstevel@tonic-gate  *		--------------------------------------------------------
31387c478bd9Sstevel@tonic-gate  *		cX		cX, cXtX, cXtXdX, cXtXdXsX, cXdX, cXdXsX
31397c478bd9Sstevel@tonic-gate  *		cXtX		cXtX, cXtXdX, cXtXdXsX
31407c478bd9Sstevel@tonic-gate  *		cXtXdX		cXtXdX, cXtXdXsX
31417c478bd9Sstevel@tonic-gate  *		cXtXdXsX	cXtXdXsX
31427c478bd9Sstevel@tonic-gate  *		cXdX		cXdX, cXdXsX
31437c478bd9Sstevel@tonic-gate  *		cXdXsX		cXdXsX
31447c478bd9Sstevel@tonic-gate  */
31457c478bd9Sstevel@tonic-gate static boolean_t
ctd_spec_includes_device(device_spec_t * spec,device_spec_t * device)31467c478bd9Sstevel@tonic-gate ctd_spec_includes_device(
31477c478bd9Sstevel@tonic-gate 	device_spec_t *spec,
31487c478bd9Sstevel@tonic-gate 	device_spec_t *device)
31497c478bd9Sstevel@tonic-gate {
31507c478bd9Sstevel@tonic-gate 	boolean_t match = B_FALSE;
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 	if (spec->data.ctd->is_ide) {
31537c478bd9Sstevel@tonic-gate 
31547c478bd9Sstevel@tonic-gate 	    /* valid IDE names are cX, cXdX, cXdXsX, no target */
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 	    if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) &&
31577c478bd9Sstevel@tonic-gate 		(spec->data.ctd->lun != ID_UNSPECIFIED) &&
31587c478bd9Sstevel@tonic-gate 		(spec->data.ctd->slice != ID_UNSPECIFIED)) {
31597c478bd9Sstevel@tonic-gate 
31607c478bd9Sstevel@tonic-gate 		match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) &&
31617c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->lun == device->data.ctd->lun) &&
31627c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->slice == device->data.ctd->slice);
31637c478bd9Sstevel@tonic-gate 
31647c478bd9Sstevel@tonic-gate 	    } else if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) &&
31657c478bd9Sstevel@tonic-gate 		(spec->data.ctd->lun != ID_UNSPECIFIED)) {
31667c478bd9Sstevel@tonic-gate 
31677c478bd9Sstevel@tonic-gate 		match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) &&
31687c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->lun == device->data.ctd->lun);
31697c478bd9Sstevel@tonic-gate 
31707c478bd9Sstevel@tonic-gate 	    } else if (spec->data.ctd->ctrl != ID_UNSPECIFIED) {
31717c478bd9Sstevel@tonic-gate 
31727c478bd9Sstevel@tonic-gate 		match = (spec->data.ctd->ctrl == device->data.ctd->ctrl);
31737c478bd9Sstevel@tonic-gate 
31747c478bd9Sstevel@tonic-gate 	    }
31757c478bd9Sstevel@tonic-gate 
31767c478bd9Sstevel@tonic-gate 	} else {
31777c478bd9Sstevel@tonic-gate 
31787c478bd9Sstevel@tonic-gate 	    /* valid names are cX, cXtX, cXtXdX, cXtXdXsX */
31797c478bd9Sstevel@tonic-gate 
31807c478bd9Sstevel@tonic-gate 	    if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) &&
31817c478bd9Sstevel@tonic-gate 		(spec->data.ctd->target != ID_UNSPECIFIED) &&
31827c478bd9Sstevel@tonic-gate 		(spec->data.ctd->lun != ID_UNSPECIFIED) &&
31837c478bd9Sstevel@tonic-gate 		(spec->data.ctd->slice != ID_UNSPECIFIED)) {
31847c478bd9Sstevel@tonic-gate 
31857c478bd9Sstevel@tonic-gate 		match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) &&
31867c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->target == device->data.ctd->target) &&
31877c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->lun == device->data.ctd->lun) &&
31887c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->slice == device->data.ctd->slice);
31897c478bd9Sstevel@tonic-gate 
31907c478bd9Sstevel@tonic-gate 	    } else if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) &&
31917c478bd9Sstevel@tonic-gate 		(spec->data.ctd->target != ID_UNSPECIFIED) &&
31927c478bd9Sstevel@tonic-gate 		(spec->data.ctd->lun != ID_UNSPECIFIED)) {
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 		match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) &&
31957c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->target == device->data.ctd->target) &&
31967c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->lun == device->data.ctd->lun);
31977c478bd9Sstevel@tonic-gate 
31987c478bd9Sstevel@tonic-gate 	    } else if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) &&
31997c478bd9Sstevel@tonic-gate 		(spec->data.ctd->target != ID_UNSPECIFIED)) {
32007c478bd9Sstevel@tonic-gate 
32017c478bd9Sstevel@tonic-gate 		match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) &&
32027c478bd9Sstevel@tonic-gate 		    (spec->data.ctd->target == device->data.ctd->target);
32037c478bd9Sstevel@tonic-gate 
32047c478bd9Sstevel@tonic-gate 	    } else if (spec->data.ctd->ctrl != ID_UNSPECIFIED) {
32057c478bd9Sstevel@tonic-gate 
32067c478bd9Sstevel@tonic-gate 		match = (spec->data.ctd->ctrl == device->data.ctd->ctrl);
32077c478bd9Sstevel@tonic-gate 
32087c478bd9Sstevel@tonic-gate 	    }
32097c478bd9Sstevel@tonic-gate 	}
32107c478bd9Sstevel@tonic-gate 
32117c478bd9Sstevel@tonic-gate 	oprintf(OUTPUT_DEBUG,
32127c478bd9Sstevel@tonic-gate 		gettext("spec: c(%d) t(%d) d(%d) s(%d) "
32137c478bd9Sstevel@tonic-gate 			"%s: c(%d) t(%d) d(%d) s(%d)\n"),
32147c478bd9Sstevel@tonic-gate 		spec->data.ctd->ctrl, spec->data.ctd->target,
32157c478bd9Sstevel@tonic-gate 		spec->data.ctd->lun, spec->data.ctd->slice,
32167c478bd9Sstevel@tonic-gate 		(match ? gettext("includes") : gettext("does not include")),
32177c478bd9Sstevel@tonic-gate 		device->data.ctd->ctrl, device->data.ctd->target,
32187c478bd9Sstevel@tonic-gate 		device->data.ctd->lun, device->data.ctd->slice);
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 	return (match);
32217c478bd9Sstevel@tonic-gate }
32227c478bd9Sstevel@tonic-gate 
32237c478bd9Sstevel@tonic-gate /*
32247c478bd9Sstevel@tonic-gate  * FUNCTION:	raw_spec_includes_device(device_spec_t *spec,
32257c478bd9Sstevel@tonic-gate  *			device_spec_t *device)
32267c478bd9Sstevel@tonic-gate  *
32277c478bd9Sstevel@tonic-gate  * INPUT:	spec	- pointer to a device_spec struct
32287c478bd9Sstevel@tonic-gate  *		device	- pointer to a device_spec struct
32297c478bd9Sstevel@tonic-gate  *
32307c478bd9Sstevel@tonic-gate  * RETURNS:	boolean_t - B_TRUE if the device is included in the spec
32317c478bd9Sstevel@tonic-gate  *			 B_FALSE otherwise
32327c478bd9Sstevel@tonic-gate  *
32337c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which determines if the input raw device spec
32347c478bd9Sstevel@tonic-gate  *		matches the input spec.
32357c478bd9Sstevel@tonic-gate  *
32367c478bd9Sstevel@tonic-gate  *		The device_spec_t raw elements are checked.
32377c478bd9Sstevel@tonic-gate  *
32387c478bd9Sstevel@tonic-gate  *		If the spec's raw device name is exactly contained at the
32397c478bd9Sstevel@tonic-gate  *		beginning of the device spec's raw name, then the function
32407c478bd9Sstevel@tonic-gate  *		evaluates to true.
32417c478bd9Sstevel@tonic-gate  */
32427c478bd9Sstevel@tonic-gate static boolean_t
raw_spec_includes_device(device_spec_t * spec,device_spec_t * device)32437c478bd9Sstevel@tonic-gate raw_spec_includes_device(
32447c478bd9Sstevel@tonic-gate 	device_spec_t *spec,
32457c478bd9Sstevel@tonic-gate 	device_spec_t *device)
32467c478bd9Sstevel@tonic-gate {
32477c478bd9Sstevel@tonic-gate 	return (strncasecmp(spec->data.raw,
32487c478bd9Sstevel@tonic-gate 			device->data.raw, strlen(spec->data.raw)) == 0);
32497c478bd9Sstevel@tonic-gate }
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate /*
32527c478bd9Sstevel@tonic-gate  * FUNCTION:	compare_name_to_spec_cache_name(void *name, void *list_item)
32537c478bd9Sstevel@tonic-gate  *
32547c478bd9Sstevel@tonic-gate  * INPUT:	name	- opaque pointer to a char * device name
32557c478bd9Sstevel@tonic-gate  * 		list_item - opaque pointer to a spec_cache_t entry
32567c478bd9Sstevel@tonic-gate  *
32577c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - if request is the same as list_item->request
32587c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
32597c478bd9Sstevel@tonic-gate  *
32607c478bd9Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the input device name
32617c478bd9Sstevel@tonic-gate  *		to the list_item's device name for equality.
32627c478bd9Sstevel@tonic-gate  *
32637c478bd9Sstevel@tonic-gate  *		This function is the lookup mechanism for the device_spec
32647c478bd9Sstevel@tonic-gate  *		associated with the name.
32657c478bd9Sstevel@tonic-gate  */
32667c478bd9Sstevel@tonic-gate static int
compare_name_to_spec_cache_name(void * name,void * list_item)32677c478bd9Sstevel@tonic-gate compare_name_to_spec_cache_name(
32687c478bd9Sstevel@tonic-gate 	void *name,
32697c478bd9Sstevel@tonic-gate 	void *list_item)
32707c478bd9Sstevel@tonic-gate {
32717c478bd9Sstevel@tonic-gate 	spec_cache_t *entry = (spec_cache_t *)list_item;
32727c478bd9Sstevel@tonic-gate 
32737c478bd9Sstevel@tonic-gate 	assert(name != NULL);
32747c478bd9Sstevel@tonic-gate 	assert(entry != NULL);
32757c478bd9Sstevel@tonic-gate 
32767c478bd9Sstevel@tonic-gate 	return (string_case_compare((char *)name, entry->name));
32777c478bd9Sstevel@tonic-gate }
32787c478bd9Sstevel@tonic-gate 
32797c478bd9Sstevel@tonic-gate /*
32807c478bd9Sstevel@tonic-gate  * FUNCTION:	destroy_spec_cache_entry(void *entry)
32817c478bd9Sstevel@tonic-gate  *
32827c478bd9Sstevel@tonic-gate  * INPUT:	entry	- opaque pointer to a spec_cache_t
32837c478bd9Sstevel@tonic-gate  *
32847c478bd9Sstevel@tonic-gate  * RETURNS:	nothing
32857c478bd9Sstevel@tonic-gate  *
32867c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which reclaims memory allocated to a
32877c478bd9Sstevel@tonic-gate  *		spec_cache_t entry.
32887c478bd9Sstevel@tonic-gate  *
32897c478bd9Sstevel@tonic-gate  *		Frees memory allocated to hold the CTD name and the
32907c478bd9Sstevel@tonic-gate  *		corresponding device_spec_t.
32917c478bd9Sstevel@tonic-gate  */
32927c478bd9Sstevel@tonic-gate static void
destroy_spec_cache_entry(void * obj)32937c478bd9Sstevel@tonic-gate destroy_spec_cache_entry(
32947c478bd9Sstevel@tonic-gate 	void *obj)
32957c478bd9Sstevel@tonic-gate {
32967c478bd9Sstevel@tonic-gate 	spec_cache_t *entry = (spec_cache_t *)obj;
32977c478bd9Sstevel@tonic-gate 
32987c478bd9Sstevel@tonic-gate 	if (entry != NULL) {
32997c478bd9Sstevel@tonic-gate 	    free(entry->name);
33007c478bd9Sstevel@tonic-gate 	    destroy_device_spec(entry->device_spec);
33017c478bd9Sstevel@tonic-gate 	    free(entry);
33027c478bd9Sstevel@tonic-gate 	}
33037c478bd9Sstevel@tonic-gate }
33047c478bd9Sstevel@tonic-gate 
33057c478bd9Sstevel@tonic-gate /*
33067c478bd9Sstevel@tonic-gate  * FUNCTION:	destroy_spec_cache()
33077c478bd9Sstevel@tonic-gate  *
33087c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
33097c478bd9Sstevel@tonic-gate  *			 !0 otherwise.
33107c478bd9Sstevel@tonic-gate  *
33117c478bd9Sstevel@tonic-gate  * PURPOSE:	Function which destroys all entries in the device_spec
33127c478bd9Sstevel@tonic-gate  *		cache.
33137c478bd9Sstevel@tonic-gate  */
33147c478bd9Sstevel@tonic-gate static int
destroy_spec_cache()33157c478bd9Sstevel@tonic-gate destroy_spec_cache()
33167c478bd9Sstevel@tonic-gate {
33177c478bd9Sstevel@tonic-gate 	dlist_free_items(_spec_cache, destroy_spec_cache_entry);
33187c478bd9Sstevel@tonic-gate 	_spec_cache = NULL;
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate 	return (0);
33217c478bd9Sstevel@tonic-gate }
33227c478bd9Sstevel@tonic-gate 
33237c478bd9Sstevel@tonic-gate /*
33247c478bd9Sstevel@tonic-gate  * FUNCTION:	get_device_access_name(devconfig_t *request,
33257c478bd9Sstevel@tonic-gate  *			dm_descriptor_t desc, char **name)
33267c478bd9Sstevel@tonic-gate  *
33277c478bd9Sstevel@tonic-gate  * INPUT:	request	- a devconfig_t request
33287c478bd9Sstevel@tonic-gate  *		desc	- a dm_descriptor_t device handle
33297c478bd9Sstevel@tonic-gate  *
33307c478bd9Sstevel@tonic-gate  * OUTPUT:	name	- a char * pointer to hold the preferred name
33317c478bd9Sstevel@tonic-gate  *
33327c478bd9Sstevel@tonic-gate  * RETURNS:	int	- 0 - if request is the same as list_item->request
33337c478bd9Sstevel@tonic-gate  *			  !0 - otherwise
33347c478bd9Sstevel@tonic-gate  *
33357c478bd9Sstevel@tonic-gate  * PURPOSE:	Utility function to determine which of the possible device
33367c478bd9Sstevel@tonic-gate  *		names should be used to access a known available device.
33377c478bd9Sstevel@tonic-gate  *
33387c478bd9Sstevel@tonic-gate  *		Devices handled are slices and disks.
33397c478bd9Sstevel@tonic-gate  *
33407c478bd9Sstevel@tonic-gate  *		If the input device is a multipathed disk or slice, it
33417c478bd9Sstevel@tonic-gate  *		can have several possible names.  Determine which of the
33427c478bd9Sstevel@tonic-gate  *		names should be used based on the input request's available
33437c478bd9Sstevel@tonic-gate  *		or unavailable device specifications.
33447c478bd9Sstevel@tonic-gate  *
33457c478bd9Sstevel@tonic-gate  */
33467c478bd9Sstevel@tonic-gate int
get_device_access_name(devconfig_t * request,dm_descriptor_t desc,char ** name)33477c478bd9Sstevel@tonic-gate get_device_access_name(
33487c478bd9Sstevel@tonic-gate 	devconfig_t	*request,
33497c478bd9Sstevel@tonic-gate 	dm_descriptor_t desc,
33507c478bd9Sstevel@tonic-gate 	char		**name)
33517c478bd9Sstevel@tonic-gate {
33527c478bd9Sstevel@tonic-gate 	int		error = 0;
33537c478bd9Sstevel@tonic-gate 	boolean_t	avail = B_FALSE;
33547c478bd9Sstevel@tonic-gate 	dlist_t		*aliases = NULL;
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate 	assert(desc != (dm_descriptor_t)0);
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 	*name = NULL;
33597c478bd9Sstevel@tonic-gate 
33607c478bd9Sstevel@tonic-gate 	if ((error = get_display_name(desc, name)) != 0) {
33617c478bd9Sstevel@tonic-gate 	    return (error);
33627c478bd9Sstevel@tonic-gate 	}
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate 	if (is_did_name(*name) == B_TRUE) {
33657c478bd9Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
33667c478bd9Sstevel@tonic-gate 		    gettext("device DID name %s is preferred\n"),
33677c478bd9Sstevel@tonic-gate 		    *name);
33687c478bd9Sstevel@tonic-gate 	    return (0);
33697c478bd9Sstevel@tonic-gate 	}
33707c478bd9Sstevel@tonic-gate 
33717c478bd9Sstevel@tonic-gate 	error = is_named_device_avail(request, *name, B_FALSE, &avail);
33727c478bd9Sstevel@tonic-gate 	if (error != 0) {
33737c478bd9Sstevel@tonic-gate 	    return (error);
33747c478bd9Sstevel@tonic-gate 	}
33757c478bd9Sstevel@tonic-gate 
33767c478bd9Sstevel@tonic-gate 	if (avail == B_TRUE) {
33777c478bd9Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
33787c478bd9Sstevel@tonic-gate 		    gettext("device name %s is accessible\n"),
33797c478bd9Sstevel@tonic-gate 		    *name);
33807c478bd9Sstevel@tonic-gate 	    return (0);
33817c478bd9Sstevel@tonic-gate 	}
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate 	/* search aliases for an 'available' name, prefer DID names */
33847c478bd9Sstevel@tonic-gate 	if ((error = get_aliases(desc, &aliases)) == 0) {
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate 	    dlist_t *iter = aliases;
33877c478bd9Sstevel@tonic-gate 	    char *availname = NULL;
33887c478bd9Sstevel@tonic-gate 	    char *didname = NULL;
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate 	    for (; (iter != NULL) && (error == 0); iter = iter->next) {
33917c478bd9Sstevel@tonic-gate 
33927c478bd9Sstevel@tonic-gate 		char *alias = (char *)iter->obj;
33937c478bd9Sstevel@tonic-gate 		error = is_named_device_avail(request, alias, B_FALSE, &avail);
33947c478bd9Sstevel@tonic-gate 
33957c478bd9Sstevel@tonic-gate 		if ((error == 0) && (avail == B_TRUE)) {
33967c478bd9Sstevel@tonic-gate 		    oprintf(OUTPUT_DEBUG,
33977c478bd9Sstevel@tonic-gate 			    gettext("device alias %s is accessible for %s\n"),
33987c478bd9Sstevel@tonic-gate 			    alias, *name);
33997c478bd9Sstevel@tonic-gate 
34007c478bd9Sstevel@tonic-gate 		    availname = alias;
34017c478bd9Sstevel@tonic-gate 
34027c478bd9Sstevel@tonic-gate 		    if (is_did_name(availname) == B_TRUE) {
34037c478bd9Sstevel@tonic-gate 			didname = alias;
34047c478bd9Sstevel@tonic-gate 			break;
34057c478bd9Sstevel@tonic-gate 		    }
34067c478bd9Sstevel@tonic-gate 		}
34077c478bd9Sstevel@tonic-gate 	    }
34087c478bd9Sstevel@tonic-gate 
34097c478bd9Sstevel@tonic-gate 	    if (error == 0) {
34107c478bd9Sstevel@tonic-gate 		if (didname != NULL) {
34117c478bd9Sstevel@tonic-gate 		    *name = didname;
34127c478bd9Sstevel@tonic-gate 		} else if (availname != NULL) {
34137c478bd9Sstevel@tonic-gate 		    *name = availname;
34147c478bd9Sstevel@tonic-gate 		}
34157c478bd9Sstevel@tonic-gate 	    }
34167c478bd9Sstevel@tonic-gate 	}
34177c478bd9Sstevel@tonic-gate 
34187c478bd9Sstevel@tonic-gate 	return (error);
34197c478bd9Sstevel@tonic-gate }
3420