xref: /onnv-gate/usr/src/cmd/lvm/metassist/layout/layout_mirror.c (revision 62:5e51ad5d0496)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*62Sjeanm  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <libintl.h>
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include "volume_error.h"
320Sstevel@tonic-gate #include "volume_dlist.h"
330Sstevel@tonic-gate #include "volume_output.h"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "layout_concat.h"
360Sstevel@tonic-gate #include "layout_device_cache.h"
370Sstevel@tonic-gate #include "layout_device_util.h"
380Sstevel@tonic-gate #include "layout_discovery.h"
390Sstevel@tonic-gate #include "layout_dlist_util.h"
400Sstevel@tonic-gate #include "layout_messages.h"
410Sstevel@tonic-gate #include "layout_request.h"
420Sstevel@tonic-gate #include "layout_slice.h"
430Sstevel@tonic-gate #include "layout_stripe.h"
440Sstevel@tonic-gate #include "layout_svm_util.h"
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #define	_LAYOUT_MIRROR_C
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static int layout_stripe_submirrors(
490Sstevel@tonic-gate 	devconfig_t	*request,
500Sstevel@tonic-gate 	dlist_t		*cursubs,
510Sstevel@tonic-gate 	uint64_t 	nbytes,
520Sstevel@tonic-gate 	uint16_t	nsubs,
530Sstevel@tonic-gate 	dlist_t		**results);
540Sstevel@tonic-gate 
550Sstevel@tonic-gate static int layout_concat_submirrors(
560Sstevel@tonic-gate 	devconfig_t	*request,
570Sstevel@tonic-gate 	dlist_t		*cursubs,
580Sstevel@tonic-gate 	uint64_t 	nbytes,
590Sstevel@tonic-gate 	uint16_t	nsubs,
600Sstevel@tonic-gate 	dlist_t		**results);
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static int compose_stripe_per_hba(
630Sstevel@tonic-gate 	devconfig_t	*request,
640Sstevel@tonic-gate 	dlist_t		*cursubs,
650Sstevel@tonic-gate 	dlist_t		*hbas,
660Sstevel@tonic-gate 	uint64_t	nbytes,
670Sstevel@tonic-gate 	uint16_t	nsubs,
680Sstevel@tonic-gate 	uint16_t	ncomp,
690Sstevel@tonic-gate 	uint16_t	mincomp,
700Sstevel@tonic-gate 	dlist_t		**results);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static int compose_stripes_across_hbas(
730Sstevel@tonic-gate 	devconfig_t	*request,
740Sstevel@tonic-gate 	dlist_t		*cursubs,
750Sstevel@tonic-gate 	dlist_t		*hbas,
760Sstevel@tonic-gate 	dlist_t		*disks,
770Sstevel@tonic-gate 	uint64_t	nbytes,
780Sstevel@tonic-gate 	uint16_t	nsubs,
790Sstevel@tonic-gate 	uint16_t	ncomp,
800Sstevel@tonic-gate 	uint16_t	mincomp,
810Sstevel@tonic-gate 	dlist_t		**results);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate static int compose_stripes_within_hba(
840Sstevel@tonic-gate 	devconfig_t	*request,
850Sstevel@tonic-gate 	dlist_t		*cursubs,
860Sstevel@tonic-gate 	dlist_t		*hbas,
870Sstevel@tonic-gate 	uint64_t	nbytes,
880Sstevel@tonic-gate 	uint16_t	nsubs,
890Sstevel@tonic-gate 	uint16_t	ncomp,
900Sstevel@tonic-gate 	uint16_t	mincomp,
910Sstevel@tonic-gate 	dlist_t		**results);
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static int compose_concat_per_hba(
940Sstevel@tonic-gate 	devconfig_t	*request,
950Sstevel@tonic-gate 	dlist_t		*cursubs,
960Sstevel@tonic-gate 	dlist_t		*hbas,
970Sstevel@tonic-gate 	uint64_t	nbytes,
980Sstevel@tonic-gate 	uint16_t	nsubs,
990Sstevel@tonic-gate 	dlist_t		**results);
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate static int compose_concats_across_hbas(
1020Sstevel@tonic-gate 	devconfig_t	*request,
1030Sstevel@tonic-gate 	dlist_t		*cursubs,
1040Sstevel@tonic-gate 	dlist_t		*hbas,
1050Sstevel@tonic-gate 	dlist_t		*disks,
1060Sstevel@tonic-gate 	uint64_t	nbytes,
1070Sstevel@tonic-gate 	uint16_t	nsubs,
1080Sstevel@tonic-gate 	dlist_t		**results);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static int compose_concats_within_hba(
1110Sstevel@tonic-gate 	devconfig_t	*request,
1120Sstevel@tonic-gate 	dlist_t		*cursubs,
1130Sstevel@tonic-gate 	dlist_t		*hba,
1140Sstevel@tonic-gate 	uint64_t	nbytes,
1150Sstevel@tonic-gate 	uint16_t	nsubs,
1160Sstevel@tonic-gate 	dlist_t		**results);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate static int assemble_mirror(
1190Sstevel@tonic-gate 	devconfig_t	*request,
1200Sstevel@tonic-gate 	dlist_t		*subs,
1210Sstevel@tonic-gate 	devconfig_t	**mirror);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate static int remove_used_disks(
1240Sstevel@tonic-gate 	dlist_t		**disks,
1250Sstevel@tonic-gate 	devconfig_t	*volume);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static int volume_shares_disk(
1280Sstevel@tonic-gate 	dm_descriptor_t disk,
1290Sstevel@tonic-gate 	devconfig_t	*volume,
1300Sstevel@tonic-gate 	boolean_t	*bool);
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate static int select_mpxio_hbas(
1330Sstevel@tonic-gate 	dlist_t		*hbas,
1340Sstevel@tonic-gate 	dlist_t		**mpxio_hbas);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate static int set_explicit_submirror_names(
1370Sstevel@tonic-gate 	dlist_t		*reqs,
1380Sstevel@tonic-gate 	dlist_t		*subs);
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate static int set_explicit_submirror_name(
1410Sstevel@tonic-gate 	devconfig_t 	*req,
1420Sstevel@tonic-gate 	devconfig_t 	*sub);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate  * FUNCTION:	layout_mirror(devconfig_t *request, nbytes, dlist_t **results)
1460Sstevel@tonic-gate  *
1470Sstevel@tonic-gate  * INPUT:	request	- pointer to a request devconfig_t
1480Sstevel@tonic-gate  *		nsubs	- number of submirrors
1490Sstevel@tonic-gate  *		nbytes	- desired mirror size
1500Sstevel@tonic-gate  *
1510Sstevel@tonic-gate  * OUTPUT:	results	- pointer to a list of volume devconfig_t results
1520Sstevel@tonic-gate  *
1530Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1540Sstevel@tonic-gate  *			 !0 otherwise.
1550Sstevel@tonic-gate  *
1560Sstevel@tonic-gate  * PURPOSE:	Main driver to handle a mirror request that does not specify
1570Sstevel@tonic-gate  *		subcomponents.
1580Sstevel@tonic-gate  *
1590Sstevel@tonic-gate  *		Striped submirrors are tried first, then concats.
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate int
layout_mirror(devconfig_t * request,uint16_t nsubs,uint64_t nbytes,dlist_t ** results)1620Sstevel@tonic-gate layout_mirror(
1630Sstevel@tonic-gate 	devconfig_t	*request,
1640Sstevel@tonic-gate 	uint16_t	nsubs,
1650Sstevel@tonic-gate 	uint64_t 	nbytes,
1660Sstevel@tonic-gate 	dlist_t		**results)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	dlist_t		*subs = NULL;
1690Sstevel@tonic-gate 	dlist_t		*item = NULL;
1700Sstevel@tonic-gate 	boolean_t	usehsp = B_FALSE;
1710Sstevel@tonic-gate 	int		error = 0;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	if ((error = get_volume_faultrecov(request, &usehsp)) != 0) {
1740Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
1750Sstevel@tonic-gate 		return (error);
1760Sstevel@tonic-gate 	    }
1770Sstevel@tonic-gate 	    error = 0;
1780Sstevel@tonic-gate 	}
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	print_layout_volume_msg(devconfig_type_to_str(TYPE_MIRROR), nbytes);
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* prefer stripe submirrors */
1830Sstevel@tonic-gate 	if ((error = layout_stripe_submirrors(
1840Sstevel@tonic-gate 	    request, NULL, nbytes, nsubs, &subs)) != 0) {
1850Sstevel@tonic-gate 	    return (error);
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	if (subs == NULL) {
1890Sstevel@tonic-gate 	    /* second chance: mirrored concats */
1900Sstevel@tonic-gate 	    if ((error = layout_concat_submirrors(
1910Sstevel@tonic-gate 		request, NULL, nbytes, nsubs, &subs)) != 0) {
1920Sstevel@tonic-gate 		return (error);
1930Sstevel@tonic-gate 	    }
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	if (subs != NULL) {
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	    devconfig_t	*mirror = NULL;
1990Sstevel@tonic-gate 	    dlist_t	*iter = NULL;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	    /* unset submirror names prior to final assembly */
2020Sstevel@tonic-gate 	    for (iter = subs; iter != NULL; iter = iter->next) {
2030Sstevel@tonic-gate 		devconfig_t *sub = (devconfig_t *)iter->obj;
2040Sstevel@tonic-gate 		char *name = NULL;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 		(void) devconfig_get_name(sub, &name);
2070Sstevel@tonic-gate 		release_volume_name(name);
2080Sstevel@tonic-gate 		(void) devconfig_set_name(sub, "");
2090Sstevel@tonic-gate 	    }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	    error = assemble_mirror(request, subs, &mirror);
2120Sstevel@tonic-gate 	    if (error == 0) {
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 		if ((item = dlist_new_item(mirror)) == NULL) {
2150Sstevel@tonic-gate 		    error = ENOMEM;
2160Sstevel@tonic-gate 		} else {
2170Sstevel@tonic-gate 		    *results = dlist_append(item, *results, AT_TAIL);
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 		    /* remember submirrors that need HSPs */
2200Sstevel@tonic-gate 		    if (usehsp == B_TRUE) {
2210Sstevel@tonic-gate 			error = add_to_hsp_list(
2220Sstevel@tonic-gate 				devconfig_get_components(mirror));
2230Sstevel@tonic-gate 		    }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 		    print_layout_success_msg();
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 	    } else {
2280Sstevel@tonic-gate 		/* cleanup submirrors */
2290Sstevel@tonic-gate 		dlist_free_items(subs, free_devconfig_object);
2300Sstevel@tonic-gate 		subs = NULL;
2310Sstevel@tonic-gate 	    }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	} else if (error != 0) {
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	    print_debug_failure_msg(devconfig_type_to_str(TYPE_MIRROR),
2360Sstevel@tonic-gate 		    get_error_string(error));
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	} else {
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	    print_insufficient_resources_msg(
2410Sstevel@tonic-gate 		    devconfig_type_to_str(TYPE_MIRROR));
2420Sstevel@tonic-gate 	    error = -1;
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	return (error);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * FUNCTION:	populate_explicit_mirror(devconfig_t *request,
2500Sstevel@tonic-gate  *			dlist_t **results)
2510Sstevel@tonic-gate  *
2520Sstevel@tonic-gate  * INPUT:	request	- pointer to a request devconfig_t
2530Sstevel@tonic-gate  *
2540Sstevel@tonic-gate  * OUTPUT:	results	- pointer to a list of volume devconfig_t results
2550Sstevel@tonic-gate  *
2560Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2570Sstevel@tonic-gate  *			 !0 otherwise.
2580Sstevel@tonic-gate  *
2590Sstevel@tonic-gate  * PURPOSE:	Processes the input mirror request specifying explicit layout
2600Sstevel@tonic-gate  *		constraints on the submirrors.
2610Sstevel@tonic-gate  *
2620Sstevel@tonic-gate  *		Primary submirror constraint is explicit type, either
2630Sstevel@tonic-gate  *		stripe or concat.  Submirror types may be mixed.
2640Sstevel@tonic-gate  *
2650Sstevel@tonic-gate  *		Submirror sizes or components may be specified explicitly.
2660Sstevel@tonic-gate  *
2670Sstevel@tonic-gate  *		If the mirror does not specify a size, assume the first explicit
2680Sstevel@tonic-gate  *		submirror size is the desired size.  If a submirror does not
2690Sstevel@tonic-gate  *		specify a size or components, use the mirror size.
2700Sstevel@tonic-gate  *
2710Sstevel@tonic-gate  *		Scan the submirror requests: those with specific components
2720Sstevel@tonic-gate  *		get assembled as encountered.  The remainder are grouped by
2730Sstevel@tonic-gate  *		type and handled by layout_stripe_submirrors() or
2740Sstevel@tonic-gate  *		layout_concat_submirrors().
2750Sstevel@tonic-gate  *
2760Sstevel@tonic-gate  *		If all specified submirrors can be assembled, the final mirror
2770Sstevel@tonic-gate  *		is assembled and appended to the results list.
2780Sstevel@tonic-gate  */
2790Sstevel@tonic-gate int
populate_explicit_mirror(devconfig_t * request,dlist_t ** results)2800Sstevel@tonic-gate populate_explicit_mirror(
2810Sstevel@tonic-gate 	devconfig_t	*request,
2820Sstevel@tonic-gate 	dlist_t		**results)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	dlist_t		*composed = NULL;
2850Sstevel@tonic-gate 	dlist_t		*list = NULL;
2860Sstevel@tonic-gate 	dlist_t		*iter = NULL;
2870Sstevel@tonic-gate 	dlist_t		*concats_by_size = NULL;
2880Sstevel@tonic-gate 	dlist_t		*stripes_by_size = NULL;
2890Sstevel@tonic-gate 	int		nsubs = 0;
2900Sstevel@tonic-gate 	int		error = 0;
2910Sstevel@tonic-gate 	uint64_t 	msize = 0;
2920Sstevel@tonic-gate 	boolean_t	usehsp = B_FALSE;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	list = devconfig_get_components(request);
2950Sstevel@tonic-gate 	nsubs = dlist_length(list);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if ((error = get_volume_faultrecov(request, &usehsp)) != 0) {
2980Sstevel@tonic-gate 	    if (error != ERR_ATTR_UNSET) {
2990Sstevel@tonic-gate 		return (error);
3000Sstevel@tonic-gate 	    }
3010Sstevel@tonic-gate 	    error = 0;
3020Sstevel@tonic-gate 	}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if ((error = devconfig_get_size(request, &msize)) != 0) {
3050Sstevel@tonic-gate 	    if (error == ERR_ATTR_UNSET) {
3060Sstevel@tonic-gate 		error = 0;
3070Sstevel@tonic-gate 		msize = 0;
3080Sstevel@tonic-gate 	    } else {
3090Sstevel@tonic-gate 		return (error);
3100Sstevel@tonic-gate 	    }
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	print_layout_explicit_msg(devconfig_type_to_str(TYPE_MIRROR));
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	/*
3160Sstevel@tonic-gate 	 * Scan the list of specified submirrors, collect those that only
3170Sstevel@tonic-gate 	 * specify size (or no size).  Process those with explicit components
3180Sstevel@tonic-gate 	 * immediately.
3190Sstevel@tonic-gate 	 */
3200Sstevel@tonic-gate 	composed = NULL;
3210Sstevel@tonic-gate 	for (iter = list; (iter != NULL) && (error == 0); iter = iter->next) {
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	    devconfig_t		*comp = (devconfig_t *)iter->obj;
3240Sstevel@tonic-gate 	    component_type_t	ctype = TYPE_UNKNOWN;
3250Sstevel@tonic-gate 	    dlist_t		*clist = NULL;
3260Sstevel@tonic-gate 	    uint64_t 		csize = 0;
3270Sstevel@tonic-gate 	    dlist_t		*item = NULL;
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	    (void) devconfig_get_type(comp, &ctype);
3300Sstevel@tonic-gate 	    (void) devconfig_get_size(comp, &csize);
3310Sstevel@tonic-gate 	    clist = devconfig_get_components(comp);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	    if (clist != NULL) {
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 		/* components specified */
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		if (ctype == TYPE_STRIPE) {
3380Sstevel@tonic-gate 		    error = populate_explicit_stripe(comp, &item);
3390Sstevel@tonic-gate 		} else {
3400Sstevel@tonic-gate 		    error = populate_explicit_concat(comp, &item);
3410Sstevel@tonic-gate 		}
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 		if (error == 0) {
3440Sstevel@tonic-gate 		    set_explicit_submirror_name(
3450Sstevel@tonic-gate 			    comp, (devconfig_t *)item->obj);
3460Sstevel@tonic-gate 		    composed = dlist_append(item, composed, AT_TAIL);
3470Sstevel@tonic-gate 		}
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	    } else {
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 		/* no components specified */
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 		/* if no size is specified, it needs to be inferred */
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 		if (msize == 0) {
3560Sstevel@tonic-gate 		    /* mirror specified no size, first explicit submirror */
3570Sstevel@tonic-gate 		    /*  size is assumed to be the desired mirror size */
3580Sstevel@tonic-gate 		    msize = csize;
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 		if (csize == 0) {
3610Sstevel@tonic-gate 		    /* this submirror specified no size, use mirror size */
3620Sstevel@tonic-gate 		    devconfig_set_size(comp, msize);
3630Sstevel@tonic-gate 		}
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 		if ((item = dlist_new_item(comp)) == NULL) {
3660Sstevel@tonic-gate 		    error = ENOMEM;
3670Sstevel@tonic-gate 		    break;
3680Sstevel@tonic-gate 		}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 		if (ctype == TYPE_STRIPE) {
3710Sstevel@tonic-gate 		    stripes_by_size = dlist_append(
3720Sstevel@tonic-gate 			    item, stripes_by_size, AT_TAIL);
3730Sstevel@tonic-gate 		} else {
3740Sstevel@tonic-gate 		    concats_by_size = dlist_append(
3750Sstevel@tonic-gate 			    item, concats_by_size, AT_TAIL);
3760Sstevel@tonic-gate 		}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	    }
3790Sstevel@tonic-gate 	}
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	/* compose stripes specified by size */
3820Sstevel@tonic-gate 	if ((error == 0) && (stripes_by_size != NULL)) {
3830Sstevel@tonic-gate 	    uint16_t n = dlist_length(stripes_by_size);
3840Sstevel@tonic-gate 	    dlist_t *stripes = NULL;
3850Sstevel@tonic-gate 	    if ((error = layout_stripe_submirrors(
3860Sstevel@tonic-gate 		request, composed, msize, n, &stripes)) == 0) {
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		/* adjust stripe names */
3890Sstevel@tonic-gate 		set_explicit_submirror_names(stripes_by_size, stripes);
3900Sstevel@tonic-gate 		composed = dlist_append(stripes, composed, AT_TAIL);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	    } else {
3930Sstevel@tonic-gate 		/* these stripes failed, skip concats_by_size */
3940Sstevel@tonic-gate 		dlist_free_items(stripes, free_devconfig_object);
3950Sstevel@tonic-gate 		dlist_free_items(concats_by_size, NULL);
3960Sstevel@tonic-gate 		concats_by_size = NULL;
3970Sstevel@tonic-gate 	    }
3980Sstevel@tonic-gate 	    dlist_free_items(stripes_by_size, NULL);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	/* compose concats specified by size */
4020Sstevel@tonic-gate 	if ((error == 0) && (concats_by_size != NULL)) {
4030Sstevel@tonic-gate 	    uint16_t n = dlist_length(concats_by_size);
4040Sstevel@tonic-gate 	    dlist_t *concats = NULL;
4050Sstevel@tonic-gate 	    if ((error = layout_concat_submirrors(
4060Sstevel@tonic-gate 		request, composed, msize, n, &concats)) == 0) {
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		/* adjust concat names */
4090Sstevel@tonic-gate 		set_explicit_submirror_names(concats_by_size, concats);
4100Sstevel@tonic-gate 		composed = dlist_append(concats, composed, AT_TAIL);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	    } else {
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 		/* these concats failed */
4150Sstevel@tonic-gate 		dlist_free_items(concats, free_devconfig_object);
4160Sstevel@tonic-gate 	    }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	    dlist_free_items(concats_by_size, NULL);
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	if ((composed != NULL) && ((dlist_length(composed) == nsubs))) {
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	    /* assemble final mirror */
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	    devconfig_t	*mirror = NULL;
4260Sstevel@tonic-gate 	    dlist_t	*item = NULL;
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	    if ((error = assemble_mirror(request, composed, &mirror)) == 0) {
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		if ((item = dlist_new_item(mirror)) == NULL) {
4310Sstevel@tonic-gate 		    error = ENOMEM;
4320Sstevel@tonic-gate 		} else {
4330Sstevel@tonic-gate 		    *results = dlist_append(item, *results, AT_TAIL);
4340Sstevel@tonic-gate 		    if (usehsp == B_TRUE) {
4350Sstevel@tonic-gate 			error = add_to_hsp_list(
4360Sstevel@tonic-gate 				devconfig_get_components(mirror));
4370Sstevel@tonic-gate 		    }
4380Sstevel@tonic-gate 		    print_layout_success_msg();
4390Sstevel@tonic-gate 		}
4400Sstevel@tonic-gate 	    }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	} else if (error != 0) {
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	    print_debug_failure_msg(
4450Sstevel@tonic-gate 		    devconfig_type_to_str(TYPE_MIRROR),
4460Sstevel@tonic-gate 		    get_error_string(error));
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	} else {
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	    dlist_free_items(composed, free_devconfig_object);
4510Sstevel@tonic-gate 	    print_insufficient_resources_msg(
4520Sstevel@tonic-gate 		    devconfig_type_to_str(TYPE_MIRROR));
4530Sstevel@tonic-gate 	    error = -1;
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	return (error);
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate /*
4600Sstevel@tonic-gate  * FUNCTION:	assemble_mirror(devconfig_t *request, dlist_t *subs,
4610Sstevel@tonic-gate  *			devconfig_t **mirror)
4620Sstevel@tonic-gate  *
4630Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
4640Sstevel@tonic-gate  *		subs	- pointer to a list of composed submirrors
4650Sstevel@tonic-gate  *
4660Sstevel@tonic-gate  * OUPUT:	mirror	- pointer to a devconfig_t to hold final mirror
4670Sstevel@tonic-gate  *
4680Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
4690Sstevel@tonic-gate  *			 !0 otherwise.
4700Sstevel@tonic-gate  *
4710Sstevel@tonic-gate  * PURPOSE:	Helper which creates and populates a mirror devconfig_t
4720Sstevel@tonic-gate  *		struct using information from the input request and the
4730Sstevel@tonic-gate  *		list of submirror components.
4740Sstevel@tonic-gate  *
4750Sstevel@tonic-gate  *		Determines the name of the mirror either from the request
4760Sstevel@tonic-gate  *		or from the default naming scheme and assigns names to
4770Sstevel@tonic-gate  *		unnamed submirrors according to the default naming scheme.
4780Sstevel@tonic-gate  *
4790Sstevel@tonic-gate  *		Sets the read and write strategies, and the resync pass
4800Sstevel@tonic-gate  *		number for the mirror if values are specified in the request.
4810Sstevel@tonic-gate  *
4820Sstevel@tonic-gate  *		Attaches the input list of submirrors to the devconfig.
4830Sstevel@tonic-gate  */
4840Sstevel@tonic-gate static int
assemble_mirror(devconfig_t * request,dlist_t * subs,devconfig_t ** mirror)4850Sstevel@tonic-gate assemble_mirror(
4860Sstevel@tonic-gate 	devconfig_t	*request,
4870Sstevel@tonic-gate 	dlist_t		*subs,
4880Sstevel@tonic-gate 	devconfig_t	**mirror)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	dlist_t		*iter = NULL;
4910Sstevel@tonic-gate 	char		*name = NULL;
4920Sstevel@tonic-gate 	int		error = 0;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if ((error = new_devconfig(mirror, TYPE_MIRROR)) == 0) {
4950Sstevel@tonic-gate 	    /* set stripe name, use requested name if specified */
4960Sstevel@tonic-gate 	    if ((error = devconfig_get_name(request, &name)) != 0) {
4970Sstevel@tonic-gate 		if (error != ERR_ATTR_UNSET) {
4980Sstevel@tonic-gate 		    volume_set_error(gettext("error getting requested name\n"));
4990Sstevel@tonic-gate 		} else {
5000Sstevel@tonic-gate 		    error = 0;
5010Sstevel@tonic-gate 		}
5020Sstevel@tonic-gate 	    }
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	    if (error == 0) {
5050Sstevel@tonic-gate 		if (name == NULL) {
5060Sstevel@tonic-gate 		    if ((error = get_next_volume_name(&name,
5070Sstevel@tonic-gate 			TYPE_MIRROR)) == 0) {
5080Sstevel@tonic-gate 			error = devconfig_set_name(*mirror, name);
5090Sstevel@tonic-gate 			free(name);
5100Sstevel@tonic-gate 			/* get name for generating submirror names below */
5110Sstevel@tonic-gate 			error = devconfig_get_name(*mirror, &name);
5120Sstevel@tonic-gate 		    }
5130Sstevel@tonic-gate 		} else {
5140Sstevel@tonic-gate 		    error = devconfig_set_name(*mirror, name);
5150Sstevel@tonic-gate 		}
5160Sstevel@tonic-gate 	    }
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	/* assign name to any unnamed submirror */
5200Sstevel@tonic-gate 	for (iter = subs;
5210Sstevel@tonic-gate 	    (error == 0) && (iter != NULL);
5220Sstevel@tonic-gate 	    iter = iter->next) {
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	    devconfig_t *sub = (devconfig_t *)iter->obj;
5250Sstevel@tonic-gate 	    char	*subname = NULL;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	    error = devconfig_get_name(sub, &subname);
5280Sstevel@tonic-gate 	    if ((error == ERR_ATTR_UNSET) || (subname == NULL) ||
5290Sstevel@tonic-gate 		    (*subname == '\0')) {
5300Sstevel@tonic-gate 		((error = get_next_submirror_name(name, &subname)) != 0) ||
5310Sstevel@tonic-gate 		(error = devconfig_set_name(sub, subname));
5320Sstevel@tonic-gate 		free(subname);
5330Sstevel@tonic-gate 	    }
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	if (error == 0) {
5370Sstevel@tonic-gate 	    mirror_read_strategy_t read = 0;
5380Sstevel@tonic-gate 	    if ((error = get_mirror_read_strategy(request, &read)) == 0) {
5390Sstevel@tonic-gate 		error = devconfig_set_mirror_read(*mirror, read);
5400Sstevel@tonic-gate 	    } else if (error == ERR_ATTR_UNSET) {
5410Sstevel@tonic-gate 		error = 0;
5420Sstevel@tonic-gate 	    }
5430Sstevel@tonic-gate 	}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	if (error == 0) {
5460Sstevel@tonic-gate 	    mirror_write_strategy_t write = 0;
5470Sstevel@tonic-gate 	    if ((error = get_mirror_write_strategy(request, &write)) == 0) {
5480Sstevel@tonic-gate 		error = devconfig_set_mirror_write(*mirror, write);
5490Sstevel@tonic-gate 	    } else if (error == ERR_ATTR_UNSET) {
5500Sstevel@tonic-gate 		error = 0;
5510Sstevel@tonic-gate 	    }
5520Sstevel@tonic-gate 	}
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	if (error == 0) {
5550Sstevel@tonic-gate 	    uint16_t pass = 0;
5560Sstevel@tonic-gate 	    if ((error = get_mirror_pass(request, &pass)) == 0) {
5570Sstevel@tonic-gate 		error = devconfig_set_mirror_pass(*mirror, pass);
5580Sstevel@tonic-gate 	    } else if (error == ERR_ATTR_UNSET) {
5590Sstevel@tonic-gate 		error = 0;
5600Sstevel@tonic-gate 	    }
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	/* arrange submirrors in ascending size order */
5640Sstevel@tonic-gate 	if (error == 0) {
5650Sstevel@tonic-gate 	    dlist_t *sorted = NULL;
5660Sstevel@tonic-gate 	    dlist_t *next = NULL;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	    iter = subs;
5690Sstevel@tonic-gate 	    while (iter != NULL) {
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 		next = iter->next;
5720Sstevel@tonic-gate 		iter->next = NULL;
5730Sstevel@tonic-gate 		iter->prev = NULL;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 		sorted = dlist_insert_ordered(iter,
5760Sstevel@tonic-gate 			sorted, ASCENDING, compare_devconfig_sizes);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		iter = next;
5790Sstevel@tonic-gate 	    }
5800Sstevel@tonic-gate 	    subs = sorted;
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	if (error == 0) {
5840Sstevel@tonic-gate 	    devconfig_set_components(*mirror, subs);
5850Sstevel@tonic-gate 	} else {
5860Sstevel@tonic-gate 	    free_devconfig(*mirror);
5870Sstevel@tonic-gate 	    *mirror = NULL;
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	return (error);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate /*
5940Sstevel@tonic-gate  * FUNCTION:	layout_stripe_submirrors(devconfig_t *request, dlist_t *cursubs,
5950Sstevel@tonic-gate  *			uint64_t nbytes, uint16_t nsubs, dlist_t **results)
5960Sstevel@tonic-gate  *
5970Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
5980Sstevel@tonic-gate  *		cursubs - pointer to a list of already composed submirrors
5990Sstevel@tonic-gate  *			these may affect disk and HBA choices for new
6000Sstevel@tonic-gate  *			submirrors being composed and are passed along
6010Sstevel@tonic-gate  *			into the component selection functions.
6020Sstevel@tonic-gate  *		nbytes	- the desired capacity for the stripes
6030Sstevel@tonic-gate  *
6040Sstevel@tonic-gate  * OUPUT:	results	- pointer to a list of composed volumes
6050Sstevel@tonic-gate  *
6060Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
6070Sstevel@tonic-gate  *			 !0 otherwise.
6080Sstevel@tonic-gate  *
6090Sstevel@tonic-gate  * PURPOSE:	Main layout driver for composing stripe submirrors.
6100Sstevel@tonic-gate  *
6110Sstevel@tonic-gate  *		Attempts to construct nsub submirrors of size nbytes.
6120Sstevel@tonic-gate  *
6130Sstevel@tonic-gate  *		Several different layout strategies are tried in order
6140Sstevel@tonic-gate  *		of preference until one succeeds or there are none left.
6150Sstevel@tonic-gate  *
6160Sstevel@tonic-gate  *		1 - mirror with all stripes on the MPXIO "controller"
6170Sstevel@tonic-gate  *		    . requires MPXIO to be enabled
6180Sstevel@tonic-gate  *		    . requires nsubs * mincomp available disks on the
6190Sstevel@tonic-gate  *			MPXIO HBA
6200Sstevel@tonic-gate  *
6210Sstevel@tonic-gate  *		2 - mirror with stripes within separate HBAs of same type
6220Sstevel@tonic-gate  *		    . requires nsubs HBAs with mincomp disks
6230Sstevel@tonic-gate  *		    . stripe width is driven by number of disks on HBA
6240Sstevel@tonic-gate  *
6250Sstevel@tonic-gate  *		3 - mirror with stripes across HBAs of same type
6260Sstevel@tonic-gate  *		    . requires mincomp HBAs with nsubs disks
6270Sstevel@tonic-gate  *			(each stripe has a disk per HBA)
6280Sstevel@tonic-gate  *		    . stripe width is driven by number of HBAs
6290Sstevel@tonic-gate  *
6300Sstevel@tonic-gate  *		4 - mirror with stripes within separate HBAs of mixed type
6310Sstevel@tonic-gate  *		    . requires nsubs HBAs with mincomp disks
6320Sstevel@tonic-gate  *		    . stripe width is driven by number of disks on HBA
6330Sstevel@tonic-gate  *
6340Sstevel@tonic-gate  *		5 - mirror with stripes across HBAs of mixed type
6350Sstevel@tonic-gate  *		    . requires mincomp HBAs with nsubs disks
6360Sstevel@tonic-gate  *			(each stripe has a disk per HBA)
6370Sstevel@tonic-gate  *		    . stripe width is driven by number of HBAs
6380Sstevel@tonic-gate  *
6390Sstevel@tonic-gate  *		6 - mirror with all stripes within the same HBA
6400Sstevel@tonic-gate  *		    . requires an HBA with mincomp * nsubs disks
6410Sstevel@tonic-gate  *
6420Sstevel@tonic-gate  *		get available HBAs
6430Sstevel@tonic-gate  *
6440Sstevel@tonic-gate  *		group HBAs by characteristics
6450Sstevel@tonic-gate  *		for (each HBA grouping) and (nsub stripes not composed) {
6460Sstevel@tonic-gate  *		    select next HBA group
6470Sstevel@tonic-gate  *		    for (strategy[1,2,3]) and (nsub stripes not composed) {
6480Sstevel@tonic-gate  *			compose nsub stripes using HBAs in group
6490Sstevel@tonic-gate  *		    }
6500Sstevel@tonic-gate  *		}
6510Sstevel@tonic-gate  *
6520Sstevel@tonic-gate  *		if (nsub stripes not composed) {
6530Sstevel@tonic-gate  *		    for (strategy[4,5,6]) and (nsub stripes not composed) {
6540Sstevel@tonic-gate  *			compose nsub stripes using all HBAs
6550Sstevel@tonic-gate  *		    }
6560Sstevel@tonic-gate  *		}
6570Sstevel@tonic-gate  *
6580Sstevel@tonic-gate  *		if (all stripes composed) {
6590Sstevel@tonic-gate  *		    append composed stripes to results
6600Sstevel@tonic-gate  *		}
6610Sstevel@tonic-gate  *
6620Sstevel@tonic-gate  */
6630Sstevel@tonic-gate static int
layout_stripe_submirrors(devconfig_t * request,dlist_t * cursubs,uint64_t nbytes,uint16_t nsubs,dlist_t ** results)6640Sstevel@tonic-gate layout_stripe_submirrors(
6650Sstevel@tonic-gate 	devconfig_t	*request,
6660Sstevel@tonic-gate 	dlist_t		*cursubs,
6670Sstevel@tonic-gate 	uint64_t 	nbytes,
6680Sstevel@tonic-gate 	uint16_t	nsubs,
6690Sstevel@tonic-gate 	dlist_t		**results)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	/*
6720Sstevel@tonic-gate 	 * these enums define the # of strategies and the preference order
6730Sstevel@tonic-gate 	 * in which they are tried
6740Sstevel@tonic-gate 	 */
6750Sstevel@tonic-gate 	typedef enum {
6760Sstevel@tonic-gate 		ALL_STRIPES_ON_MPXIO = 0,
6770Sstevel@tonic-gate 		STRIPE_PER_SIMILAR_HBA,
6780Sstevel@tonic-gate 		STRIPE_ACROSS_SIMILAR_HBAS,
6790Sstevel@tonic-gate 		N_SIMILAR_HBA_STRATEGIES
6800Sstevel@tonic-gate 	} similar_hba_strategy_order_t;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	typedef enum {
6830Sstevel@tonic-gate 		STRIPE_PER_ANY_HBA = 0,
6840Sstevel@tonic-gate 		STRIPE_ACROSS_ANY_HBAS,
6850Sstevel@tonic-gate 		STRIPE_WITHIN_ANY_HBA,
6860Sstevel@tonic-gate 		N_ANY_HBA_STRATEGIES
6870Sstevel@tonic-gate 	} any_hba_strategy_order_t;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	dlist_t		*usable_hbas = NULL;
6900Sstevel@tonic-gate 	dlist_t		*similar_hba_groups = NULL;
6910Sstevel@tonic-gate 	dlist_t		*iter = NULL;
6920Sstevel@tonic-gate 	dlist_t		*subs = NULL;
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	boolean_t	usehsp = B_FALSE;
6950Sstevel@tonic-gate 	uint16_t	mincomp	= 0;
6960Sstevel@tonic-gate 	uint16_t	maxcomp	= 0;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	int		error = 0;
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	(error = get_usable_hbas(&usable_hbas));
7010Sstevel@tonic-gate 	if (error != 0) {
7020Sstevel@tonic-gate 	    return (error);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	print_layout_submirrors_msg(devconfig_type_to_str(TYPE_STRIPE),
7060Sstevel@tonic-gate 		nbytes, nsubs);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	if (dlist_length(usable_hbas) == 0) {
7090Sstevel@tonic-gate 	    print_no_hbas_msg();
7100Sstevel@tonic-gate 	    volume_set_error(gettext("There are no usable HBAs."));
7110Sstevel@tonic-gate 	    return (-1);
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	similar_hba_groups = NULL;
7150Sstevel@tonic-gate 	((error = group_similar_hbas(usable_hbas, &similar_hba_groups)) != 0) ||
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	/*
7180Sstevel@tonic-gate 	 * determine the min/max number of stripe components
7190Sstevel@tonic-gate 	 * based on the request, the diskset defaults or the
7200Sstevel@tonic-gate 	 * global defaults.  These are absolute limits, the
7210Sstevel@tonic-gate 	 * actual values are determined by the number of HBAs
7220Sstevel@tonic-gate 	 * and/or disks available.
7230Sstevel@tonic-gate 	 */
7240Sstevel@tonic-gate 	(error = get_stripe_min_comp(request, &mincomp)) ||
7250Sstevel@tonic-gate 	(error = get_stripe_max_comp(request, &maxcomp)) ||
7260Sstevel@tonic-gate 	(error = get_volume_faultrecov(request, &usehsp));
7270Sstevel@tonic-gate 	if (error != 0) {
7280Sstevel@tonic-gate 	    return (error);
7290Sstevel@tonic-gate 	}
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	for (iter = similar_hba_groups;
7320Sstevel@tonic-gate 	    (error == 0) && (subs == NULL) && (iter != NULL);
7330Sstevel@tonic-gate 	    iter = iter->next) {
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	    dlist_t *hbas = (dlist_t *)iter->obj;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	    similar_hba_strategy_order_t order;
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	    for (order = ALL_STRIPES_ON_MPXIO;
7400Sstevel@tonic-gate 		(order < N_SIMILAR_HBA_STRATEGIES) &&
7410Sstevel@tonic-gate 			(subs == NULL) && (error == 0);
7420Sstevel@tonic-gate 		order++) {
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 		dlist_t *selhbas = NULL;
7450Sstevel@tonic-gate 		dlist_t *disks = NULL;
7460Sstevel@tonic-gate 		int	n = 0;
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 		switch (order) {
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 		case ALL_STRIPES_ON_MPXIO:
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		    if (is_mpxio_enabled() == B_TRUE) {
7530Sstevel@tonic-gate 			dlist_t *mpxio_hbas = NULL;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 			/* see if any HBA supports MPXIO */
7560Sstevel@tonic-gate 			error = select_mpxio_hbas(hbas, &mpxio_hbas);
7570Sstevel@tonic-gate 			if ((error == 0) && (mpxio_hbas != NULL)) {
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate /* BEGIN CSTYLED */
7600Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
7610Sstevel@tonic-gate gettext("  -->Strategy 1: use %d-%d MPXIO disks\n"),
7620Sstevel@tonic-gate 	mincomp * nsubs, maxcomp * nsubs);
7630Sstevel@tonic-gate /* END CSTYLED */
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 			    /* see if MPXIO HBA has enough disks */
7660Sstevel@tonic-gate 			    error = select_hbas_with_n_disks(
7670Sstevel@tonic-gate 				    request, mpxio_hbas, (mincomp * nsubs),
7680Sstevel@tonic-gate 				    &selhbas, &disks);
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 			    if ((error == 0) && (dlist_length(selhbas) > 0)) {
7710Sstevel@tonic-gate 				error = compose_stripes_within_hba(
7720Sstevel@tonic-gate 					request, cursubs, mpxio_hbas, nbytes,
7730Sstevel@tonic-gate 					nsubs, maxcomp, mincomp, &subs);
7740Sstevel@tonic-gate 			    } else {
7750Sstevel@tonic-gate 				print_insufficient_hbas_msg(n);
7760Sstevel@tonic-gate 			    }
7770Sstevel@tonic-gate 			}
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 			dlist_free_items(mpxio_hbas, NULL);
7800Sstevel@tonic-gate 		    }
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 		    break;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 		case STRIPE_PER_SIMILAR_HBA:
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
7870Sstevel@tonic-gate 			    request, hbas, mincomp, &selhbas, &disks);
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 		    if (error == 0) {
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate /* BEGIN CSTYLED */
7920Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
7930Sstevel@tonic-gate 	gettext("  -->Strategy 2: use %d-%d disks from %d similar HBAs - stripe per HBA\n"),
7940Sstevel@tonic-gate 	mincomp, maxcomp, nsubs);
7950Sstevel@tonic-gate /* END CSTYLED */
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 			if ((n = dlist_length(selhbas)) >= nsubs) {
7980Sstevel@tonic-gate 			    error = compose_stripe_per_hba(
7990Sstevel@tonic-gate 				    request, cursubs, selhbas, nbytes,
8000Sstevel@tonic-gate 				    nsubs, maxcomp, mincomp, &subs);
8010Sstevel@tonic-gate 			} else {
8020Sstevel@tonic-gate 			    print_insufficient_hbas_msg(n);
8030Sstevel@tonic-gate 			}
8040Sstevel@tonic-gate 		    }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 		    break;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		case STRIPE_ACROSS_SIMILAR_HBAS:
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
8110Sstevel@tonic-gate 			    request, hbas, nsubs, &selhbas, &disks);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 		    if (error == 0) {
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate /* BEGIN CSTYLED */
8160Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
8170Sstevel@tonic-gate gettext("  -->Strategy 3: use %d disks from %d-%d similar HBAs - stripe across HBAs \n"),
8180Sstevel@tonic-gate 	nsubs, mincomp, maxcomp);
8190Sstevel@tonic-gate /* END CSTYLED */
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 			if ((n = dlist_length(selhbas)) >= mincomp) {
8220Sstevel@tonic-gate 			    error = compose_stripes_across_hbas(
8230Sstevel@tonic-gate 				    request, cursubs, selhbas, disks,
8240Sstevel@tonic-gate 				    nbytes, nsubs, maxcomp, mincomp, &subs);
8250Sstevel@tonic-gate 			} else {
8260Sstevel@tonic-gate 			    print_insufficient_hbas_msg(n);
8270Sstevel@tonic-gate 			}
8280Sstevel@tonic-gate 		    }
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 		    break;
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 		default:
8330Sstevel@tonic-gate 		    break;
8340Sstevel@tonic-gate 		}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 		dlist_free_items(selhbas, NULL);
8370Sstevel@tonic-gate 		dlist_free_items(disks, NULL);
8380Sstevel@tonic-gate 	    }
8390Sstevel@tonic-gate 	}
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	for (iter = similar_hba_groups; iter != NULL; iter = iter->next) {
8420Sstevel@tonic-gate 	    dlist_free_items((dlist_t *)iter->obj, NULL);
8430Sstevel@tonic-gate 	}
8440Sstevel@tonic-gate 	dlist_free_items(similar_hba_groups, NULL);
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	/* retry using all available HBAs */
8470Sstevel@tonic-gate 	if (subs == NULL) {
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	    any_hba_strategy_order_t order;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	    for (order = STRIPE_PER_ANY_HBA;
8520Sstevel@tonic-gate 		(order < N_ANY_HBA_STRATEGIES) &&
8530Sstevel@tonic-gate 			(subs == NULL) && (error == 0);
8540Sstevel@tonic-gate 		order++) {
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		dlist_t *selhbas = NULL;
8570Sstevel@tonic-gate 		dlist_t *disks = NULL;
8580Sstevel@tonic-gate 		int	n = 0;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		switch (order) {
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 		case STRIPE_PER_ANY_HBA:
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
8650Sstevel@tonic-gate 			    request, usable_hbas, nsubs, &selhbas, &disks);
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 		    if (error == 0) {
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate /* BEGIN CSTYLED */
8700Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
8710Sstevel@tonic-gate gettext("  -->Strategy 4: use %d-%d disks from any %d HBAs - stripe per HBA\n"),
8720Sstevel@tonic-gate 	mincomp, maxcomp, nsubs);
8730Sstevel@tonic-gate /* END CSTYLED */
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 			if ((n = dlist_length(selhbas)) >= nsubs) {
8760Sstevel@tonic-gate 			    error = compose_stripe_per_hba(
8770Sstevel@tonic-gate 				    request, cursubs, selhbas, nbytes,
8780Sstevel@tonic-gate 				    nsubs, maxcomp, mincomp, &subs);
8790Sstevel@tonic-gate 			} else {
8800Sstevel@tonic-gate 			    print_insufficient_hbas_msg(n);
8810Sstevel@tonic-gate 			}
8820Sstevel@tonic-gate 		    }
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 		    break;
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 		case STRIPE_ACROSS_ANY_HBAS:
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
8890Sstevel@tonic-gate 			    request, usable_hbas, nsubs, &selhbas, &disks);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		    if (error == 0) {
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate /* BEGIN CSTYLED */
8940Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
8950Sstevel@tonic-gate gettext("  -->Strategy 5: use %d disks from %d-%d HBAs - stripe across HBAs \n"),
8960Sstevel@tonic-gate 	nsubs, mincomp, maxcomp);
8970Sstevel@tonic-gate /* END CSTYLED */
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 			if ((n = dlist_length(selhbas)) >= mincomp) {
9000Sstevel@tonic-gate 			    error = compose_stripes_across_hbas(
9010Sstevel@tonic-gate 				    request, cursubs, selhbas, disks,
9020Sstevel@tonic-gate 				    nbytes, nsubs, maxcomp, mincomp, &subs);
9030Sstevel@tonic-gate 			} else {
9040Sstevel@tonic-gate 			    print_insufficient_hbas_msg(n);
9050Sstevel@tonic-gate 			}
9060Sstevel@tonic-gate 		    }
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 		    break;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 		case STRIPE_WITHIN_ANY_HBA:
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
9130Sstevel@tonic-gate 			    request, usable_hbas, (mincomp * nsubs),
9140Sstevel@tonic-gate 			    &selhbas, &disks);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 		    if (error == 0) {
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate /* BEGIN CSTYLED */
9190Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
9200Sstevel@tonic-gate gettext("  -->Strategy 6: use %d-%d disks from any single HBA - %d stripes within HBA\n"),
9210Sstevel@tonic-gate 	mincomp * nsubs, maxcomp * nsubs, nsubs);
9220Sstevel@tonic-gate /* END CSTYLED */
9230Sstevel@tonic-gate 			if ((n = dlist_length(selhbas)) > 0) {
9240Sstevel@tonic-gate 			    error = compose_stripes_within_hba(
9250Sstevel@tonic-gate 				    request, cursubs, selhbas, nbytes,
9260Sstevel@tonic-gate 				    nsubs, maxcomp, mincomp, &subs);
9270Sstevel@tonic-gate 			} else {
9280Sstevel@tonic-gate 			    print_insufficient_hbas_msg(n);
9290Sstevel@tonic-gate 			}
9300Sstevel@tonic-gate 		    }
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 		    break;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 		default:
9350Sstevel@tonic-gate 		    break;
9360Sstevel@tonic-gate 		}
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 		dlist_free_items(selhbas, NULL);
9390Sstevel@tonic-gate 		dlist_free_items(disks, NULL);
9400Sstevel@tonic-gate 	    }
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	if (error == 0) {
9440Sstevel@tonic-gate 	    *results = dlist_append(subs, *results, AT_TAIL);
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 	return (error);
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate /*
9500Sstevel@tonic-gate  * FUNCTION:	layout_concat_submirrors(devconfig_t *request, dlist_t *cursubs,
9510Sstevel@tonic-gate  *			uint64_t nbytes, uint16_t nsubs, dlist_t **results)
9520Sstevel@tonic-gate  *
9530Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
9540Sstevel@tonic-gate  *		cursubs - pointer to a list of already composed submirrors
9550Sstevel@tonic-gate  *		nbytes	- the desired capacity for the concats
9560Sstevel@tonic-gate  *
9570Sstevel@tonic-gate  * OUPUT:	results	- pointer to a list of composed volumes
9580Sstevel@tonic-gate  *
9590Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
9600Sstevel@tonic-gate  *			 !0 otherwise.
9610Sstevel@tonic-gate  *
9620Sstevel@tonic-gate  * PURPOSE:	Main layout driver for composing concat submirrors.
9630Sstevel@tonic-gate  *
9640Sstevel@tonic-gate  *		Attempts to construct nsub submirrors of size nbytes.
9650Sstevel@tonic-gate  *
9660Sstevel@tonic-gate  *		Several different layout strategies are tried in order
9670Sstevel@tonic-gate  *		of preference until one succeeds or there are none left.
9680Sstevel@tonic-gate  *
9690Sstevel@tonic-gate  *		1 - mirror with all concats on the MPXIO "controller"
9700Sstevel@tonic-gate  *		    . requires MPXIO to be enabled
9710Sstevel@tonic-gate  *		    . requires nsubs available disks on the MPXIO HBA
9720Sstevel@tonic-gate  *
9730Sstevel@tonic-gate  *		2 - mirror with concats on separate HBAs of same type
9740Sstevel@tonic-gate  *		    . requires nsubs HBAs with available disks
9750Sstevel@tonic-gate  *
9760Sstevel@tonic-gate  *		3 - mirror with concats across HBAs of same type
9770Sstevel@tonic-gate  *		    . requires an HBA with at least 1 available disk
9780Sstevel@tonic-gate  *
9790Sstevel@tonic-gate  *		4 - mirror with concats on separate HBAs of mixed type
9800Sstevel@tonic-gate  *		    . requires nsubs HBAs with available disks
9810Sstevel@tonic-gate  *
9820Sstevel@tonic-gate  *		5 - mirror with concats across HBAs of mixed type
9830Sstevel@tonic-gate  *		    . requires an HBA with at least 1 available disk
9840Sstevel@tonic-gate  *
9850Sstevel@tonic-gate  *		6 - mirror with all concats on the same HBA
9860Sstevel@tonic-gate  *		    . requires an HBA with at least nsubs available disks
9870Sstevel@tonic-gate  *
9880Sstevel@tonic-gate  *		get available HBAs
9890Sstevel@tonic-gate  *
9900Sstevel@tonic-gate  *		group HBAs by characteristics
9910Sstevel@tonic-gate  *		for (each HBA grouping) and (nsub concats not composed) {
9920Sstevel@tonic-gate  *		    select next HBA group
9930Sstevel@tonic-gate  *		    for (strategy[1,2,3]) and (nsub concats not composed) {
9940Sstevel@tonic-gate  *			compose nsub concats, nbytes in size
9950Sstevel@tonic-gate  *		    }
9960Sstevel@tonic-gate  *		}
9970Sstevel@tonic-gate  *
9980Sstevel@tonic-gate  *		if (nsub concats not composed) {
9990Sstevel@tonic-gate  *		    for (strategy[4,5,6]) and (nsub concats not composed) {
10000Sstevel@tonic-gate  *			compose nsub concats, nbytes in size
10010Sstevel@tonic-gate  *		    }
10020Sstevel@tonic-gate  *		}
10030Sstevel@tonic-gate  *
10040Sstevel@tonic-gate  *		if (all concats composed) {
10050Sstevel@tonic-gate  *		    append composed concats to results
10060Sstevel@tonic-gate  *		}
10070Sstevel@tonic-gate  *
10080Sstevel@tonic-gate  */
10090Sstevel@tonic-gate static int
layout_concat_submirrors(devconfig_t * request,dlist_t * cursubs,uint64_t nbytes,uint16_t nsubs,dlist_t ** results)10100Sstevel@tonic-gate layout_concat_submirrors(
10110Sstevel@tonic-gate 	devconfig_t	*request,
10120Sstevel@tonic-gate 	dlist_t		*cursubs,
10130Sstevel@tonic-gate 	uint64_t 	nbytes,
10140Sstevel@tonic-gate 	uint16_t	nsubs,
10150Sstevel@tonic-gate 	dlist_t		**results)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate 	/*
10180Sstevel@tonic-gate 	 * these enums define the # of strategies and the preference order
10190Sstevel@tonic-gate 	 * in which they are tried
10200Sstevel@tonic-gate 	 */
10210Sstevel@tonic-gate 	typedef enum {
10220Sstevel@tonic-gate 		ALL_CONCATS_ON_MPXIO = 0,
10230Sstevel@tonic-gate 		CONCAT_PER_SIMILAR_HBA,
10240Sstevel@tonic-gate 		CONCAT_ACROSS_SIMILAR_HBAS,
10250Sstevel@tonic-gate 		N_SIMILAR_HBA_STRATEGIES
10260Sstevel@tonic-gate 	} similar_hba_strategy_order_t;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	typedef enum {
10290Sstevel@tonic-gate 		CONCAT_PER_ANY_HBA = 0,
10300Sstevel@tonic-gate 		CONCAT_ACROSS_ANY_HBAS,
10310Sstevel@tonic-gate 		CONCAT_WITHIN_ANY_HBA,
10320Sstevel@tonic-gate 		N_ANY_HBA_STRATEGIES
10330Sstevel@tonic-gate 	} any_hba_strategy_order_t;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	dlist_t		*usable_hbas = NULL;
10360Sstevel@tonic-gate 	dlist_t		*similar_hba_groups = NULL;
10370Sstevel@tonic-gate 	dlist_t		*iter = NULL;
10380Sstevel@tonic-gate 	dlist_t		*subs = NULL;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	boolean_t	usehsp = B_FALSE;
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	int		error = 0;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	(error = get_usable_hbas(&usable_hbas));
10450Sstevel@tonic-gate 	if (error != 0) {
10460Sstevel@tonic-gate 	    return (error);
10470Sstevel@tonic-gate 	}
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	print_layout_submirrors_msg(devconfig_type_to_str(TYPE_CONCAT),
10500Sstevel@tonic-gate 		nbytes, nsubs);
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	if (dlist_length(usable_hbas) == 0) {
10530Sstevel@tonic-gate 	    print_no_hbas_msg();
10540Sstevel@tonic-gate 	    volume_set_error(gettext("There are no usable HBAs."));
10550Sstevel@tonic-gate 	    return (-1);
10560Sstevel@tonic-gate 	}
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	similar_hba_groups = NULL;
10590Sstevel@tonic-gate 	((error = group_similar_hbas(usable_hbas, &similar_hba_groups)) != 0) ||
10600Sstevel@tonic-gate 	(error = get_volume_faultrecov(request, &usehsp));
10610Sstevel@tonic-gate 	if (error != 0) {
10620Sstevel@tonic-gate 	    return (error);
10630Sstevel@tonic-gate 	}
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	for (iter = similar_hba_groups;
10660Sstevel@tonic-gate 	    (error == 0) && (subs == NULL) && (iter != NULL);
10670Sstevel@tonic-gate 	    iter = iter->next) {
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	    dlist_t *hbas = (dlist_t *)iter->obj;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	    similar_hba_strategy_order_t order;
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	    for (order = ALL_CONCATS_ON_MPXIO;
10740Sstevel@tonic-gate 		(order < N_SIMILAR_HBA_STRATEGIES) &&
10750Sstevel@tonic-gate 			(subs == NULL) && (error == 0);
10760Sstevel@tonic-gate 		order++) {
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 		dlist_t *selhbas = NULL;
10790Sstevel@tonic-gate 		dlist_t *disks = NULL;
10800Sstevel@tonic-gate 		int	n = 0;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 		switch (order) {
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 		case ALL_CONCATS_ON_MPXIO:
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 		    if (is_mpxio_enabled() == B_TRUE) {
10870Sstevel@tonic-gate 			dlist_t *mpxio_hbas = NULL;
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 			/* see if any HBA supports MPXIO */
10900Sstevel@tonic-gate 			error = select_mpxio_hbas(hbas, &mpxio_hbas);
10910Sstevel@tonic-gate 			if ((error == 0) && (mpxio_hbas != NULL)) {
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate /* BEGIN CSTYLED */
10940Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
10950Sstevel@tonic-gate 	gettext("  -->Strategy 1: use at least %d MPXIO disks\n"),
10960Sstevel@tonic-gate 	nsubs);
10970Sstevel@tonic-gate /* END CSTYLED */
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 			    /* see if MPXIO HBA has enough disks */
11000Sstevel@tonic-gate 			    error = select_hbas_with_n_disks(
11010Sstevel@tonic-gate 				    request, hbas, nsubs, &selhbas, &disks);
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 			    if ((error == 0) &&
11040Sstevel@tonic-gate 				    ((n = dlist_length(selhbas)) > 0)) {
11050Sstevel@tonic-gate 				error = compose_concats_within_hba(
11060Sstevel@tonic-gate 					request, cursubs, mpxio_hbas, nbytes,
11070Sstevel@tonic-gate 					nsubs, &subs);
11080Sstevel@tonic-gate 			    } else {
11090Sstevel@tonic-gate 				print_insufficient_hbas_msg(n);
11100Sstevel@tonic-gate 			    }
11110Sstevel@tonic-gate 			}
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 			dlist_free_items(mpxio_hbas, NULL);
11140Sstevel@tonic-gate 		    }
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 		    break;
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 		case CONCAT_PER_SIMILAR_HBA:
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
11210Sstevel@tonic-gate 			    request, hbas, 1, &selhbas, &disks);
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 		    if (error == 0) {
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate /* BEGIN CSTYLED */
11260Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
11270Sstevel@tonic-gate 	gettext("  -->Strategy 2: use any disks from %d similar HBAs - concat per HBA\n"),
11280Sstevel@tonic-gate 	nsubs);
11290Sstevel@tonic-gate /* END CSTYLED */
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 			if ((n = dlist_length(selhbas)) >= nsubs) {
11320Sstevel@tonic-gate 			    error = compose_concat_per_hba(
11330Sstevel@tonic-gate 				    request, cursubs, selhbas,
11340Sstevel@tonic-gate 				    nbytes, nsubs, &subs);
11350Sstevel@tonic-gate 			} else {
11360Sstevel@tonic-gate 			    print_insufficient_hbas_msg(n);
11370Sstevel@tonic-gate 			}
11380Sstevel@tonic-gate 		    }
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 		    break;
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 		case CONCAT_ACROSS_SIMILAR_HBAS:
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
11450Sstevel@tonic-gate 			    request, hbas, 1, &selhbas, &disks);
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 		    if (error == 0) {
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate /* BEGIN CSTYLED */
11500Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
11510Sstevel@tonic-gate 	gettext("  -->Strategy 3: use any disks from any similar HBAs - "
11520Sstevel@tonic-gate 		"%d concats across HBAs\n"),
11530Sstevel@tonic-gate 	nsubs);
11540Sstevel@tonic-gate /* END CSTYLED */
11550Sstevel@tonic-gate 			error = compose_concats_across_hbas(
11560Sstevel@tonic-gate 				request, cursubs, selhbas, disks,
11570Sstevel@tonic-gate 				nbytes, nsubs, &subs);
11580Sstevel@tonic-gate 		    }
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 		    break;
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 		default:
11630Sstevel@tonic-gate 		    break;
11640Sstevel@tonic-gate 		}
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 		dlist_free_items(selhbas, NULL);
11670Sstevel@tonic-gate 		dlist_free_items(disks, NULL);
11680Sstevel@tonic-gate 	    }
11690Sstevel@tonic-gate 	}
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	for (iter = similar_hba_groups; iter != NULL; iter = iter->next) {
11720Sstevel@tonic-gate 	    dlist_free_items((dlist_t *)iter->obj, NULL);
11730Sstevel@tonic-gate 	}
11740Sstevel@tonic-gate 	dlist_free_items(similar_hba_groups, NULL);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	/* retry using all available HBAs */
11770Sstevel@tonic-gate 	if (subs == NULL) {
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	    any_hba_strategy_order_t order;
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	    for (order = CONCAT_PER_ANY_HBA;
11820Sstevel@tonic-gate 		(order < N_ANY_HBA_STRATEGIES) &&
11830Sstevel@tonic-gate 			(subs == NULL) && (error == 0);
11840Sstevel@tonic-gate 		order++) {
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 		dlist_t *selhbas = NULL;
11870Sstevel@tonic-gate 		dlist_t *disks = NULL;
11880Sstevel@tonic-gate 		int	n = 0;
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 		switch (order) {
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 		case CONCAT_PER_ANY_HBA:
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
11950Sstevel@tonic-gate 			    request, usable_hbas, 1, &selhbas, &disks);
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 		    if (error == 0) {
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate /* BEGIN CSTYLED */
12000Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
12010Sstevel@tonic-gate 	gettext("  -->Strategy 4: use any disks from %d HBAs - concat per HBA\n"),
12020Sstevel@tonic-gate 	nsubs);
12030Sstevel@tonic-gate /* END CSTYLED */
12040Sstevel@tonic-gate 			if ((n = dlist_length(selhbas)) >= nsubs) {
12050Sstevel@tonic-gate 			    error = compose_concat_per_hba(
12060Sstevel@tonic-gate 				    request, cursubs, selhbas,
12070Sstevel@tonic-gate 				    nbytes, nsubs, &subs);
12080Sstevel@tonic-gate 			} else {
12090Sstevel@tonic-gate 			    print_insufficient_hbas_msg(n);
12100Sstevel@tonic-gate 			}
12110Sstevel@tonic-gate 		    }
12120Sstevel@tonic-gate 		    break;
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 		case CONCAT_ACROSS_ANY_HBAS:
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
12170Sstevel@tonic-gate 			    request, usable_hbas, 1, &selhbas, &disks);
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 		    if (error == 0) {
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate /* BEGIN CSTYLED */
12220Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
12230Sstevel@tonic-gate 	gettext("  -->Strategy 5: use any disks from any HBA - %d concats across HBAs\n"),
12240Sstevel@tonic-gate 	nsubs);
12250Sstevel@tonic-gate /* END CSTYLED */
12260Sstevel@tonic-gate 			error = compose_concats_across_hbas(
12270Sstevel@tonic-gate 				request, cursubs, selhbas, disks,
12280Sstevel@tonic-gate 				nbytes, nsubs, &subs);
12290Sstevel@tonic-gate 		    }
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 		    break;
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 		case CONCAT_WITHIN_ANY_HBA:
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 		    error = select_hbas_with_n_disks(
12360Sstevel@tonic-gate 			    request, usable_hbas, 1, &selhbas, &disks);
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 		    if (error == 0) {
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate /* BEGIN CSTYLED */
12410Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
12420Sstevel@tonic-gate gettext("  -->Strategy 6: use any disks from any single HBA - %d concats within an HBA\n"),
12430Sstevel@tonic-gate 	nsubs);
12440Sstevel@tonic-gate /* END CSTYLED */
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 			if ((n = dlist_length(selhbas)) > 0) {
12470Sstevel@tonic-gate 			    error = compose_concats_within_hba(
12480Sstevel@tonic-gate 				    request, cursubs, selhbas,
12490Sstevel@tonic-gate 				    nbytes, nsubs, &subs);
12500Sstevel@tonic-gate 			} else {
12510Sstevel@tonic-gate 			    print_insufficient_hbas_msg(n);
12520Sstevel@tonic-gate 			}
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 		    }
12550Sstevel@tonic-gate 		    break;
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 		default:
12580Sstevel@tonic-gate 		    break;
12590Sstevel@tonic-gate 		}
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 		dlist_free_items(selhbas, NULL);
12620Sstevel@tonic-gate 		dlist_free_items(disks, NULL);
12630Sstevel@tonic-gate 	    }
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	if (error == 0) {
12670Sstevel@tonic-gate 	    *results = dlist_append(subs, *results, AT_TAIL);
12680Sstevel@tonic-gate 	}
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	return (error);
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate /*
12740Sstevel@tonic-gate  * FUNCTION:	compose_stripe_per_hba(devconfig_t *request,
12750Sstevel@tonic-gate  *		    dlist_t *cursubs, dlist_t *hbas, uint64_t nbytes,
12760Sstevel@tonic-gate  *		    uint16_t nsubs, int maxcomp, int mincomp,
12770Sstevel@tonic-gate  *		    dlist_t **results)
12780Sstevel@tonic-gate  *
12790Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
12800Sstevel@tonic-gate  *		cursubs - pointer to a list of already composed submirrors
12810Sstevel@tonic-gate  *		hbas	- pointer to a list of available HBAs
12820Sstevel@tonic-gate  *		nbytes	- the desired capacity for the stripes
12830Sstevel@tonic-gate  *		nsubs	- the desired number of stripes
12840Sstevel@tonic-gate  *		maxcomp	- the maximum number of stripe components
12850Sstevel@tonic-gate  *		mincomp - the minimum number of stripe components
12860Sstevel@tonic-gate  *
12870Sstevel@tonic-gate  * OUPUT:	results	- pointer to a list of composed volumes
12880Sstevel@tonic-gate  *
12890Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
12900Sstevel@tonic-gate  *			 !0 otherwise.
12910Sstevel@tonic-gate  *
12920Sstevel@tonic-gate  * PURPOSE:	Layout function which composes the requested number of stripes
12930Sstevel@tonic-gate  *		of the desired size using available disks on any of the HBAs
12940Sstevel@tonic-gate  *		from the input list.
12950Sstevel@tonic-gate  *
12960Sstevel@tonic-gate  *		The number of components within the composed stripes will be
12970Sstevel@tonic-gate  *		in the range of mincomp to ncomp, preferring more components
12980Sstevel@tonic-gate  *		over fewer.  All stripes composed by a single call to this
12990Sstevel@tonic-gate  *		function will have the same number of components.
13000Sstevel@tonic-gate  *
13010Sstevel@tonic-gate  *		Each stripe will use disks from a single HBA.
13020Sstevel@tonic-gate  *
13030Sstevel@tonic-gate  * 		All input HBAs are expected to have at least mincomp available
13040Sstevel@tonic-gate  *		disks.
13050Sstevel@tonic-gate  *
13060Sstevel@tonic-gate  *		If the stripes can be composed, they are appended to the list
13070Sstevel@tonic-gate  *		of result volumes.
13080Sstevel@tonic-gate  *
13090Sstevel@tonic-gate  *		while (more HBAs and more stripes to compose) {
13100Sstevel@tonic-gate  *		    select next HBA
13110Sstevel@tonic-gate  *		    get available space for this HBA
13120Sstevel@tonic-gate  *		    get available disks for this HBA
13130Sstevel@tonic-gate  *		    if (not enough space or disks) {
13140Sstevel@tonic-gate  *			continue
13150Sstevel@tonic-gate  *		    }
13160Sstevel@tonic-gate  *
13170Sstevel@tonic-gate  *		    use # disks as # of stripe components - limit to maxcomp
13180Sstevel@tonic-gate  *		    for ((ncomps downto mincomp) && (more stripes to compose)) {
13190Sstevel@tonic-gate  *			while (more stripes to compose) {
13200Sstevel@tonic-gate  *			    if a stripe can be composed using disks {
13210Sstevel@tonic-gate  *			        save stripe
13220Sstevel@tonic-gate  *			        increment stripe count
13230Sstevel@tonic-gate  *			    }
13240Sstevel@tonic-gate  *			    while (more HBAs and more stripes to compose) {
13250Sstevel@tonic-gate  *				select next HBA
13260Sstevel@tonic-gate  *				get available space for this HBA
13270Sstevel@tonic-gate  *				get available disks for this HBA
13280Sstevel@tonic-gate  *				if (not enough space or disks) {
13290Sstevel@tonic-gate  *				    continue
13300Sstevel@tonic-gate  *				}
13310Sstevel@tonic-gate  *			        if a stripe can be composed using disks {
13320Sstevel@tonic-gate  *				    save stripe
13330Sstevel@tonic-gate  *				    increment stripe count
13340Sstevel@tonic-gate  *				}
13350Sstevel@tonic-gate  *			    }
13360Sstevel@tonic-gate  *
13370Sstevel@tonic-gate  *			    if (not all stripes composed) {
13380Sstevel@tonic-gate  *				delete any compose stripes
13390Sstevel@tonic-gate  *			    }
13400Sstevel@tonic-gate  *			}
13410Sstevel@tonic-gate  *		    }
13420Sstevel@tonic-gate  *
13430Sstevel@tonic-gate  *		    if (not all stripes composed) {
13440Sstevel@tonic-gate  *		        delete any stripes composed
13450Sstevel@tonic-gate  *		    }
13460Sstevel@tonic-gate  *		}
13470Sstevel@tonic-gate  *
13480Sstevel@tonic-gate  *		if (not all stripes composed) {
13490Sstevel@tonic-gate  *		    delete any stripes composed
13500Sstevel@tonic-gate  *		}
13510Sstevel@tonic-gate  *
13520Sstevel@tonic-gate  *		append composed stripes to results
13530Sstevel@tonic-gate  */
13540Sstevel@tonic-gate static int
compose_stripe_per_hba(devconfig_t * request,dlist_t * cursubs,dlist_t * hbas,uint64_t nbytes,uint16_t nsubs,uint16_t maxcomp,uint16_t mincomp,dlist_t ** results)13550Sstevel@tonic-gate compose_stripe_per_hba(
13560Sstevel@tonic-gate 	devconfig_t	*request,
13570Sstevel@tonic-gate 	dlist_t		*cursubs,
13580Sstevel@tonic-gate 	dlist_t		*hbas,
13590Sstevel@tonic-gate 	uint64_t	nbytes,
13600Sstevel@tonic-gate 	uint16_t	nsubs,
13610Sstevel@tonic-gate 	uint16_t	maxcomp,
13620Sstevel@tonic-gate 	uint16_t	mincomp,
13630Sstevel@tonic-gate 	dlist_t		**results)
13640Sstevel@tonic-gate {
13650Sstevel@tonic-gate 	int		error = 0;
13660Sstevel@tonic-gate 	dlist_t		*list = NULL;
13670Sstevel@tonic-gate 	dlist_t		*iter = NULL;
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	oprintf(OUTPUT_VERBOSE,
13700Sstevel@tonic-gate 		gettext("  --->Trying to compose %d Stripes with "
13710Sstevel@tonic-gate 			"%d-%d components on separate HBAs.\n"),
13720Sstevel@tonic-gate 		nsubs, mincomp, maxcomp);
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 	for (iter = hbas;
13750Sstevel@tonic-gate 	    (list == NULL) && (iter != NULL) && (error == 0);
13760Sstevel@tonic-gate 	    iter = iter->next) {
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
13790Sstevel@tonic-gate 	    dlist_t	*disks = NULL;
13800Sstevel@tonic-gate 	    uint64_t	space = 0;
13810Sstevel@tonic-gate 	    int		ncomp = 0;
13820Sstevel@tonic-gate 	    char	*name;
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	    ((error = get_display_name(hba, &name)) != 0) ||
13850Sstevel@tonic-gate 	    (error = hba_get_avail_disks_and_space(request,
13860Sstevel@tonic-gate 		    hba, &disks, &space));
13870Sstevel@tonic-gate 	    if (error != 0) {
13880Sstevel@tonic-gate 		continue;
13890Sstevel@tonic-gate 	    }
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	    /* check for sufficient space and minimum # of disks */
13920Sstevel@tonic-gate 	    if (space < nbytes) {
13930Sstevel@tonic-gate 		(void) print_hba_insufficient_space_msg(name, space);
13940Sstevel@tonic-gate 		dlist_free_items(disks, NULL);
13950Sstevel@tonic-gate 		continue;
13960Sstevel@tonic-gate 	    }
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	    if ((ncomp = dlist_length(disks)) < mincomp) {
13990Sstevel@tonic-gate 		print_insufficient_disks_msg(ncomp);
14000Sstevel@tonic-gate 		dlist_free_items(disks, NULL);
14010Sstevel@tonic-gate 		continue;
14020Sstevel@tonic-gate 	    }
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	    /* make the stripe as wide as possible, up to maxcomp */
14050Sstevel@tonic-gate 	    for (ncomp = ((ncomp > maxcomp) ? maxcomp : ncomp);
14060Sstevel@tonic-gate 		(list == NULL) && (ncomp >= mincomp) && (error == 0);
14070Sstevel@tonic-gate 		ncomp--) {
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 		int count = 0;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 		/* try composing nsubs stripes with ncomp components */
14120Sstevel@tonic-gate 		while (count < nsubs) {
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 		    devconfig_t *stripe = NULL;
14150Sstevel@tonic-gate 		    dlist_t *item = NULL;
14160Sstevel@tonic-gate 		    dlist_t *iter1 = NULL;
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 		    /* build first stripe using disks on this HBA */
14190Sstevel@tonic-gate 		    if (((error = populate_stripe(request, nbytes,
14200Sstevel@tonic-gate 			disks, ncomp, cursubs, &stripe)) != 0) ||
14210Sstevel@tonic-gate 			    (stripe == NULL)) {
14220Sstevel@tonic-gate 			/* first stripe failed at the current width */
14230Sstevel@tonic-gate 			/* break while loop and try a different width */
14240Sstevel@tonic-gate 			break;
14250Sstevel@tonic-gate 		    }
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 		    /* composed a stripe */
14280Sstevel@tonic-gate 		    if ((item = dlist_new_item((void*)stripe)) == NULL) {
14290Sstevel@tonic-gate 			error = ENOMEM;
14300Sstevel@tonic-gate 			break;
14310Sstevel@tonic-gate 		    }
14320Sstevel@tonic-gate 		    ++count;
14330Sstevel@tonic-gate 		    list = dlist_append(item, list, AT_TAIL);
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 		    /* compose stripes on remaining HBAs */
14360Sstevel@tonic-gate 		    for (iter1 = iter->next;
14370Sstevel@tonic-gate 			(count < nsubs) && (iter1 != NULL) && (error == 0);
14380Sstevel@tonic-gate 			iter1 = iter1->next) {
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 			dm_descriptor_t hba1 = (uintptr_t)iter1->obj;
14410Sstevel@tonic-gate 			uint64_t space1 = 0;
14420Sstevel@tonic-gate 			dlist_t	*disks1 = NULL;
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 			error = hba_get_avail_disks_and_space(request,
14450Sstevel@tonic-gate 				hba1, &disks1, &space1);
14460Sstevel@tonic-gate 			if (error != 0) {
14470Sstevel@tonic-gate 			    continue;
14480Sstevel@tonic-gate 			}
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 			/* enough space/disks on this HBA? */
14510Sstevel@tonic-gate 			if ((dlist_length(disks1) < ncomp) ||
14520Sstevel@tonic-gate 			    (space1 < nbytes)) {
14530Sstevel@tonic-gate 			    dlist_free_items(disks1, NULL);
14540Sstevel@tonic-gate 			    continue;
14550Sstevel@tonic-gate 			}
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 			stripe = NULL;
14580Sstevel@tonic-gate 			error = populate_stripe(
14590Sstevel@tonic-gate 				request, nbytes, disks1,
14600Sstevel@tonic-gate 				ncomp, cursubs, &stripe);
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 			if (stripe != NULL) {
14630Sstevel@tonic-gate 			    /* prepare to compose another */
14640Sstevel@tonic-gate 			    if ((item = dlist_new_item(
14650Sstevel@tonic-gate 				(void *)stripe)) == NULL) {
14660Sstevel@tonic-gate 				error = ENOMEM;
14670Sstevel@tonic-gate 				break;
14680Sstevel@tonic-gate 			    }
14690Sstevel@tonic-gate 			    list = dlist_append(item, list, AT_TAIL);
14700Sstevel@tonic-gate 			    ++count;
14710Sstevel@tonic-gate 			}
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 			dlist_free_items(disks1, NULL);
14740Sstevel@tonic-gate 			disks1 = NULL;
14750Sstevel@tonic-gate 		    }
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 		    if ((iter1 == NULL) && (count < nsubs)) {
14780Sstevel@tonic-gate 			/*
14790Sstevel@tonic-gate 			 * no HBAs remain and haven't composed
14800Sstevel@tonic-gate 			 * enough stripes at the current width.
14810Sstevel@tonic-gate 			 * break while loop and try another width.
14820Sstevel@tonic-gate 			 */
14830Sstevel@tonic-gate 			break;
14840Sstevel@tonic-gate 		    }
14850Sstevel@tonic-gate 		}
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 		if (count < nsubs) {
14880Sstevel@tonic-gate 		/*
14890Sstevel@tonic-gate 		 * stripe composition at current width failed...
14900Sstevel@tonic-gate 		 * prepare to try a narrower width.
14910Sstevel@tonic-gate 		 * NB: narrower widths may work since some HBA(s)
14920Sstevel@tonic-gate 		 * may have fewer available disks
14930Sstevel@tonic-gate 		 */
14940Sstevel@tonic-gate 		    print_layout_submirrors_failed_msg(
14950Sstevel@tonic-gate 			    devconfig_type_to_str(TYPE_STRIPE),
14960Sstevel@tonic-gate 			    count, nsubs);
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 		    dlist_free_items(list, free_devconfig_object);
14990Sstevel@tonic-gate 		    list = NULL;
15000Sstevel@tonic-gate 		}
15010Sstevel@tonic-gate 	    }
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	    dlist_free_items(disks, NULL);
15040Sstevel@tonic-gate 	    disks = NULL;
15050Sstevel@tonic-gate 	}
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 	if (error == 0) {
15080Sstevel@tonic-gate 	    *results = dlist_append(list, *results, AT_TAIL);
15090Sstevel@tonic-gate 	} else {
15100Sstevel@tonic-gate 	    dlist_free_items(list, free_devconfig_object);
15110Sstevel@tonic-gate 	}
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	return (error);
15140Sstevel@tonic-gate }
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate /*
15170Sstevel@tonic-gate  * FUNCTION:	compose_stripes_across_hbas(devconfig_t *request,
15180Sstevel@tonic-gate  *			dlist_t *cursubs, dlist_t *hbas, dlist_t *disks,
15190Sstevel@tonic-gate  *			uint64_t nbytes, uint16_t nsubs, int maxcomp,
15200Sstevel@tonic-gate  *			int mincomp, dlist_t **results)
15210Sstevel@tonic-gate  *
15220Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
15230Sstevel@tonic-gate  *		cursubs - pointer to a list of already composed submirrors
15240Sstevel@tonic-gate  *		hbas	- pointer to a list of available HBAs
15250Sstevel@tonic-gate  *		disks	- pointer to a list of available disks on the HBAs
15260Sstevel@tonic-gate  *		nbytes	- the desired capacity for the stripes
15270Sstevel@tonic-gate  *		nsubs	- the desired number of stripes
15280Sstevel@tonic-gate  *		ncomp	- the maximum number of stripe components
15290Sstevel@tonic-gate  *		mincomp - the minimum number of stripe components
15300Sstevel@tonic-gate  *
15310Sstevel@tonic-gate  * OUPUT:	results	- pointer to a list of composed volumes
15320Sstevel@tonic-gate  *
15330Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
15340Sstevel@tonic-gate  *			 !0 otherwise.
15350Sstevel@tonic-gate  *
15360Sstevel@tonic-gate  * PURPOSE:	Layout function which composes the requested number of stripes
15370Sstevel@tonic-gate  *		of the desired size using available disks on any of the HBAs
15380Sstevel@tonic-gate  *		from the input list.
15390Sstevel@tonic-gate  *
15400Sstevel@tonic-gate  *		The number of components within the composed stripes will be
15410Sstevel@tonic-gate  *		in the range of mincomp to ncomp, preferring more components
15420Sstevel@tonic-gate  *		over fewer.  All stripes composed by a single call to this
15430Sstevel@tonic-gate  *		function will have the same number of components.
15440Sstevel@tonic-gate  *
15450Sstevel@tonic-gate  *		Each stripe will use a disk from several different HBAs.
15460Sstevel@tonic-gate  *
15470Sstevel@tonic-gate  * 		All input HBAs are expected to have at least nsubs available
15480Sstevel@tonic-gate  *		disks.
15490Sstevel@tonic-gate  *
15500Sstevel@tonic-gate  *		If the stripes can be composed, they are appended to the list
15510Sstevel@tonic-gate  *		of result volumes.
15520Sstevel@tonic-gate  *
15530Sstevel@tonic-gate  *		for (ncomps downto mincomp) {
15540Sstevel@tonic-gate  *
15550Sstevel@tonic-gate  *		    copy the input disk list
15560Sstevel@tonic-gate  *		    while (more stripes to compose) {
15570Sstevel@tonic-gate  *			if a stripe can be composed using disks {
15580Sstevel@tonic-gate  *			    save stripe
15590Sstevel@tonic-gate  *			    remove used disks from disk list
15600Sstevel@tonic-gate  *			    increment stripe count
15610Sstevel@tonic-gate  *			} else
15620Sstevel@tonic-gate  *			    end while loop
15630Sstevel@tonic-gate  *		    }
15640Sstevel@tonic-gate  *
15650Sstevel@tonic-gate  *		    free copied disk list
15660Sstevel@tonic-gate  *		    if (not all stripes composed) {
15670Sstevel@tonic-gate  *		        delete any stripes composed
15680Sstevel@tonic-gate  *			decrement ncomps
15690Sstevel@tonic-gate  *		    }
15700Sstevel@tonic-gate  *		}
15710Sstevel@tonic-gate  *
15720Sstevel@tonic-gate  *		if (not all stripes composed) {
15730Sstevel@tonic-gate  *		    delete any stripes composed
15740Sstevel@tonic-gate  *		}
15750Sstevel@tonic-gate  *
15760Sstevel@tonic-gate  *		append composed stripes to results
15770Sstevel@tonic-gate  */
15780Sstevel@tonic-gate static int
compose_stripes_across_hbas(devconfig_t * request,dlist_t * cursubs,dlist_t * hbas,dlist_t * disks,uint64_t nbytes,uint16_t nsubs,uint16_t ncomp,uint16_t mincomp,dlist_t ** results)15790Sstevel@tonic-gate compose_stripes_across_hbas(
15800Sstevel@tonic-gate 	devconfig_t	*request,
15810Sstevel@tonic-gate 	dlist_t		*cursubs,
15820Sstevel@tonic-gate 	dlist_t		*hbas,
15830Sstevel@tonic-gate 	dlist_t		*disks,
15840Sstevel@tonic-gate 	uint64_t	nbytes,
15850Sstevel@tonic-gate 	uint16_t	nsubs,
15860Sstevel@tonic-gate 	uint16_t	ncomp,
15870Sstevel@tonic-gate 	uint16_t	mincomp,
15880Sstevel@tonic-gate 	dlist_t		**results)
15890Sstevel@tonic-gate {
15900Sstevel@tonic-gate 	int		error = 0;
15910Sstevel@tonic-gate 	int		count = 0;
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 	dlist_t		*list	= NULL;
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	while ((ncomp >= mincomp) && (count < nsubs) && (error == 0)) {
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	    dlist_t	*iter;
15980Sstevel@tonic-gate 	    dlist_t	*item;
15990Sstevel@tonic-gate 	    dlist_t	*disks_copy = NULL;
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	    oprintf(OUTPUT_VERBOSE,
16020Sstevel@tonic-gate 		gettext("  --->Trying to compose %d Stripes with "
16030Sstevel@tonic-gate 			"%d components across %d HBAs.\n"),
16040Sstevel@tonic-gate 		    nsubs, ncomp, dlist_length(hbas));
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	    /* copy disk list, it is modified by the while loop */
16070Sstevel@tonic-gate 	    for (iter = disks; iter != NULL; iter = iter->next) {
16080Sstevel@tonic-gate 		if ((item = dlist_new_item(iter->obj)) == NULL) {
16090Sstevel@tonic-gate 		    error = ENOMEM;
16100Sstevel@tonic-gate 		} else {
16110Sstevel@tonic-gate 		    disks_copy = dlist_append(item, disks_copy, AT_HEAD);
16120Sstevel@tonic-gate 		}
16130Sstevel@tonic-gate 	    }
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	    /* compose nsubs stripe submirrors of ncomp components */
16160Sstevel@tonic-gate 	    while ((count < nsubs) && (error == 0)) {
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 		devconfig_t *stripe = NULL;
16190Sstevel@tonic-gate 		dlist_t	*item = NULL;
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 		error = populate_stripe(
16220Sstevel@tonic-gate 			request, nbytes, disks_copy, ncomp, cursubs, &stripe);
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 		if ((error == 0) && (stripe != NULL)) {
16250Sstevel@tonic-gate 		    if ((item = dlist_new_item((void *)stripe)) == NULL) {
16260Sstevel@tonic-gate 			error = ENOMEM;
16270Sstevel@tonic-gate 		    } else {
16280Sstevel@tonic-gate 			++count;
16290Sstevel@tonic-gate 			list = dlist_append(item, list, AT_TAIL);
16300Sstevel@tonic-gate 			error = remove_used_disks(&disks_copy, stripe);
16310Sstevel@tonic-gate 		    }
16320Sstevel@tonic-gate 		} else if (stripe == NULL) {
16330Sstevel@tonic-gate 		    break;
16340Sstevel@tonic-gate 		}
16350Sstevel@tonic-gate 	    }
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	    /* free copy of disk list */
16380Sstevel@tonic-gate 	    dlist_free_items(disks_copy, NULL);
16390Sstevel@tonic-gate 	    disks_copy = NULL;
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	    if ((error == 0) && (count < nsubs)) {
16420Sstevel@tonic-gate 		/* failed to compose enough stripes at this width, */
16430Sstevel@tonic-gate 		/* prepare to try again with the next narrower width. */
16440Sstevel@tonic-gate 		print_layout_submirrors_failed_msg(
16450Sstevel@tonic-gate 			devconfig_type_to_str(TYPE_STRIPE),
16460Sstevel@tonic-gate 			count, nsubs);
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 		dlist_free_items(list, free_devconfig_object);
16490Sstevel@tonic-gate 		list = NULL;
16500Sstevel@tonic-gate 		count = 0;
16510Sstevel@tonic-gate 		--ncomp;
16520Sstevel@tonic-gate 	    }
16530Sstevel@tonic-gate 	}
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 	if (count < nsubs) {
16560Sstevel@tonic-gate 	    dlist_free_items(list, free_devconfig_object);
16570Sstevel@tonic-gate 	    list = NULL;
16580Sstevel@tonic-gate 	} else {
16590Sstevel@tonic-gate 	    *results = dlist_append(list, *results, AT_TAIL);
16600Sstevel@tonic-gate 	}
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	return (error);
16630Sstevel@tonic-gate }
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate /*
16660Sstevel@tonic-gate  * FUNCTION:	compose_stripes_within_hba(devconfig_t *request,
16670Sstevel@tonic-gate  *			dlist_t *cursubs, dlist_t *hbas, uint64_t nbytes,
16680Sstevel@tonic-gate  *			uint16_t nsubs, int maxcomp, int mincomp,
16690Sstevel@tonic-gate  *			dlist_t **results)
16700Sstevel@tonic-gate  *
16710Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
16720Sstevel@tonic-gate  *		cursubs - pointer to a list of already composed submirrors
16730Sstevel@tonic-gate  *		hbas	- pointer to a list of available HBAs
16740Sstevel@tonic-gate  *		nbytes	- the desired capacity for the stripes
16750Sstevel@tonic-gate  *		nsubs	- the desired number of stripes
16760Sstevel@tonic-gate  *		maxcomp - the maximum number of stripe components
16770Sstevel@tonic-gate  *		mincomp - the minimum number of stripe components
16780Sstevel@tonic-gate  *		nsubs	- the number of stripes to be composed
16790Sstevel@tonic-gate  *
16800Sstevel@tonic-gate  * OUPUT:	results	- pointer to a list of composed volumes
16810Sstevel@tonic-gate  *
16820Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
16830Sstevel@tonic-gate  *			 !0 otherwise.
16840Sstevel@tonic-gate  *
16850Sstevel@tonic-gate  * PURPOSE:	Layout function which composes the requested number of stripes
16860Sstevel@tonic-gate  *		of the desired size using available disks within any single
16870Sstevel@tonic-gate  *		HBA from the input list.
16880Sstevel@tonic-gate  *
16890Sstevel@tonic-gate  *		The number of components within the composed stripes will be
16900Sstevel@tonic-gate  *		in the range of mincomp to maxcomp, preferring more components
16910Sstevel@tonic-gate  *		over fewer.  All stripes composed by a single call to this
16920Sstevel@tonic-gate  *		function will have the same number of components.
16930Sstevel@tonic-gate  *
16940Sstevel@tonic-gate  *		All stripes will use disks from a single HBA.
16950Sstevel@tonic-gate  *
16960Sstevel@tonic-gate  * 		All input HBAs are expected to have at least nsubs * mincomp
16970Sstevel@tonic-gate  *		available disks and total space sufficient for subs stripes.
16980Sstevel@tonic-gate  *
16990Sstevel@tonic-gate  *		If the stripes can be composed, they are appended to the list
17000Sstevel@tonic-gate  *		of result volumes.
17010Sstevel@tonic-gate  *
17020Sstevel@tonic-gate  *		while (more HBAs and more stripes need to be composed) {
17030Sstevel@tonic-gate  *		    select next HBA
17040Sstevel@tonic-gate  *		    if (not enough available space on this HBA) {
17050Sstevel@tonic-gate  *			continue;
17060Sstevel@tonic-gate  *		    }
17070Sstevel@tonic-gate  *		    get available disks for HBA
17080Sstevel@tonic-gate  *		    use # disks as # of stripe components - limit to maxcomp
17090Sstevel@tonic-gate  *		    for (ncomps downto mincomp) {
17100Sstevel@tonic-gate  *			if ((ncomps * nsubs) > ndisks) {
17110Sstevel@tonic-gate  *			    continue;
17120Sstevel@tonic-gate  *			}
17130Sstevel@tonic-gate  *			while (more stripes need to be composed) {
17140Sstevel@tonic-gate  *			    if a stripe can be composed using disks {
17150Sstevel@tonic-gate  *				save stripe
17160Sstevel@tonic-gate  *				remove used disks from disk list
17170Sstevel@tonic-gate  *			    } else
17180Sstevel@tonic-gate  *				end while loop
17190Sstevel@tonic-gate  *			}
17200Sstevel@tonic-gate  *			if (not all stripes composed) {
17210Sstevel@tonic-gate  *			    delete any stripes composed
17220Sstevel@tonic-gate  *			}
17230Sstevel@tonic-gate  *		    }
17240Sstevel@tonic-gate  *		}
17250Sstevel@tonic-gate  *
17260Sstevel@tonic-gate  *		if (not all stripes composed) {
17270Sstevel@tonic-gate  *		    delete any stripes composed
17280Sstevel@tonic-gate  *		}
17290Sstevel@tonic-gate  *
17300Sstevel@tonic-gate  *		append composed stripes to results
17310Sstevel@tonic-gate  */
17320Sstevel@tonic-gate static int
compose_stripes_within_hba(devconfig_t * request,dlist_t * cursubs,dlist_t * hbas,uint64_t nbytes,uint16_t nsubs,uint16_t maxcomp,uint16_t mincomp,dlist_t ** results)17330Sstevel@tonic-gate compose_stripes_within_hba(
17340Sstevel@tonic-gate 	devconfig_t	*request,
17350Sstevel@tonic-gate 	dlist_t		*cursubs,
17360Sstevel@tonic-gate 	dlist_t		*hbas,
17370Sstevel@tonic-gate 	uint64_t	nbytes,
17380Sstevel@tonic-gate 	uint16_t	nsubs,
17390Sstevel@tonic-gate 	uint16_t	maxcomp,
17400Sstevel@tonic-gate 	uint16_t	mincomp,
17410Sstevel@tonic-gate 	dlist_t		**results)
17420Sstevel@tonic-gate {
17430Sstevel@tonic-gate 	int		error = 0;
17440Sstevel@tonic-gate 	int		count = 0;
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	dlist_t		*list	= NULL;
17470Sstevel@tonic-gate 	dlist_t		*iter	= NULL;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	for (iter = hbas;
17500Sstevel@tonic-gate 	    (count < nsubs) && (iter != NULL) && (error == 0);
17510Sstevel@tonic-gate 	    iter = iter->next) {
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
17540Sstevel@tonic-gate 	    uint64_t	space = 0;
17550Sstevel@tonic-gate 	    dlist_t	*disks = NULL;
17560Sstevel@tonic-gate 	    int		ndisks = 0;
17570Sstevel@tonic-gate 	    int		ncomp = 0;
17580Sstevel@tonic-gate 	    char	*name = NULL;
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	    ((error = get_display_name(hba, &name)) != 0) ||
17610Sstevel@tonic-gate 	    (error = hba_get_avail_disks_and_space(request,
17620Sstevel@tonic-gate 		    hba, &disks, &space));
17630Sstevel@tonic-gate 	    if (error != 0) {
17640Sstevel@tonic-gate 		dlist_free_items(disks, NULL);
17650Sstevel@tonic-gate 		continue;
17660Sstevel@tonic-gate 	    }
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	    if (space < (nsubs * nbytes)) {
17690Sstevel@tonic-gate 		(void) print_hba_insufficient_space_msg(name, space);
17700Sstevel@tonic-gate 		dlist_free_items(disks, NULL);
17710Sstevel@tonic-gate 		continue;
17720Sstevel@tonic-gate 	    }
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	    ndisks = dlist_length(disks);
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate 		/*
17770Sstevel@tonic-gate 		 * try composing stripes from ncomp down to mincomp.
17780Sstevel@tonic-gate 		 * stop when nsubs stripes have been composed, or when the
17790Sstevel@tonic-gate 		 * minimum stripe width has been tried
17800Sstevel@tonic-gate 		 */
17810Sstevel@tonic-gate 	    for (ncomp = maxcomp;
17820Sstevel@tonic-gate 		(ncomp >= mincomp) && (count != nsubs) && (error == 0);
17830Sstevel@tonic-gate 		ncomp--) {
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 		oprintf(OUTPUT_VERBOSE,
17860Sstevel@tonic-gate 			gettext("  --->Trying to compose %d Stripes with "
17870Sstevel@tonic-gate 				"%d components on a single HBA.\n"),
17880Sstevel@tonic-gate 			nsubs, ncomp);
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 		if (ndisks < (ncomp * nsubs)) {
17910Sstevel@tonic-gate 		    print_insufficient_disks_msg(ndisks);
17920Sstevel@tonic-gate 		    continue;
17930Sstevel@tonic-gate 		}
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 		/* try composing nsubs stripes, each ncomp wide */
17960Sstevel@tonic-gate 		for (count = 0; (count < nsubs) && (error == 0); count++) {
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 		    devconfig_t *stripe = NULL;
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 		    error = populate_stripe(
18010Sstevel@tonic-gate 			    request, nbytes, disks, ncomp, cursubs, &stripe);
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate 		    if ((error == 0) && (stripe != NULL)) {
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 			dlist_t *item = dlist_new_item((void *)stripe);
18060Sstevel@tonic-gate 			if (item == NULL) {
18070Sstevel@tonic-gate 			    error = ENOMEM;
18080Sstevel@tonic-gate 			} else {
18090Sstevel@tonic-gate 			    list = dlist_append(item, list, AT_TAIL);
18100Sstevel@tonic-gate 			    error = remove_used_disks(&disks, stripe);
18110Sstevel@tonic-gate 			}
18120Sstevel@tonic-gate 		    } else if (stripe == NULL) {
18130Sstevel@tonic-gate 			break;
18140Sstevel@tonic-gate 		    }
18150Sstevel@tonic-gate 		}
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 		if (count < nsubs) {
18180Sstevel@tonic-gate 		    /* failed to compose enough stripes at this width, */
18190Sstevel@tonic-gate 		    /* prepare to try again with fewer components */
18200Sstevel@tonic-gate 		    print_layout_submirrors_failed_msg(
18210Sstevel@tonic-gate 			    devconfig_type_to_str(TYPE_STRIPE),
18220Sstevel@tonic-gate 			    count, nsubs);
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 		    dlist_free_items(list, free_devconfig_object);
18250Sstevel@tonic-gate 		    list = NULL;
18260Sstevel@tonic-gate 		}
18270Sstevel@tonic-gate 	    }
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	    dlist_free_items(disks, NULL);
18300Sstevel@tonic-gate 	}
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 	if (count < nsubs) {
18330Sstevel@tonic-gate 	    dlist_free_items(list, free_devconfig_object);
18340Sstevel@tonic-gate 	    list = NULL;
18350Sstevel@tonic-gate 	}
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	*results = list;
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	return (error);
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate /*
18430Sstevel@tonic-gate  * FUNCTION:	compose_concats_per_hba(devconfig_t *request,
18440Sstevel@tonic-gate  *			dlist_t *cursubs, dlist_t *hbas, uint64_t nbytes,
18450Sstevel@tonic-gate  *			uint16_t nsubs, dlist_t	**results)
18460Sstevel@tonic-gate  *
18470Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
18480Sstevel@tonic-gate  *		cursubs - pointer to a list of already composed submirrors
18490Sstevel@tonic-gate  *		hbas	- pointer to a list of available HBAs
18500Sstevel@tonic-gate  *		nbytes	- the desired capacity for the concats
18510Sstevel@tonic-gate  *		nsubs	- the number of concats to be composed
18520Sstevel@tonic-gate  *
18530Sstevel@tonic-gate  * OUPUT:	results	- pointer to a list of composed volumes
18540Sstevel@tonic-gate  *
18550Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
18560Sstevel@tonic-gate  *			 !0 otherwise.
18570Sstevel@tonic-gate  *
18580Sstevel@tonic-gate  * PURPOSE:	Layout function which composes the requested number of concats
18590Sstevel@tonic-gate  *		of the desired size using available disks within HBAs from the
18600Sstevel@tonic-gate  *		input list.  Each concat will be composed using disks from a
18610Sstevel@tonic-gate  *		single HBA.
18620Sstevel@tonic-gate  *
18630Sstevel@tonic-gate  *		If the concats can be composed, they are appended to the list
18640Sstevel@tonic-gate  *		of result volumes.
18650Sstevel@tonic-gate  *
18660Sstevel@tonic-gate  *		while (more HBAs AND more concats need to be composed) {
18670Sstevel@tonic-gate  *		    if (not enough available space on this HBA) {
18680Sstevel@tonic-gate  *			continue;
18690Sstevel@tonic-gate  *		    }
18700Sstevel@tonic-gate  *
18710Sstevel@tonic-gate  *		    get available disks for HBA
18720Sstevel@tonic-gate  *		    if (concat can be composed) {
18730Sstevel@tonic-gate  *			save concat
18740Sstevel@tonic-gate  *			increment count
18750Sstevel@tonic-gate  *		    }
18760Sstevel@tonic-gate  *		}
18770Sstevel@tonic-gate  *
18780Sstevel@tonic-gate  *		if (not all stripes composed) {
18790Sstevel@tonic-gate  *		    delete any concats composed
18800Sstevel@tonic-gate  *		}
18810Sstevel@tonic-gate  *
18820Sstevel@tonic-gate  *		append composed concats to results
18830Sstevel@tonic-gate  */
18840Sstevel@tonic-gate static int
compose_concat_per_hba(devconfig_t * request,dlist_t * cursubs,dlist_t * hbas,uint64_t nbytes,uint16_t nsubs,dlist_t ** results)18850Sstevel@tonic-gate compose_concat_per_hba(
18860Sstevel@tonic-gate 	devconfig_t	*request,
18870Sstevel@tonic-gate 	dlist_t		*cursubs,
18880Sstevel@tonic-gate 	dlist_t		*hbas,
18890Sstevel@tonic-gate 	uint64_t	nbytes,
18900Sstevel@tonic-gate 	uint16_t	nsubs,
18910Sstevel@tonic-gate 	dlist_t		**results)
18920Sstevel@tonic-gate {
18930Sstevel@tonic-gate 	int		error = 0;
18940Sstevel@tonic-gate 	int		count = 0;
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	dlist_t		*list = NULL;
18970Sstevel@tonic-gate 	dlist_t		*iter = NULL;
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	oprintf(OUTPUT_VERBOSE,
19000Sstevel@tonic-gate 		gettext("  --->Trying to compose %d Concats on "
19010Sstevel@tonic-gate 			"separate HBAs.\n"), nsubs);
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 	for (iter = hbas;
19040Sstevel@tonic-gate 	    (iter != NULL) && (error == 0) && (count < nsubs);
19050Sstevel@tonic-gate 	    iter = iter->next) {
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
19080Sstevel@tonic-gate 	    uint64_t	space = 0;
19090Sstevel@tonic-gate 	    devconfig_t *concat = NULL;
19100Sstevel@tonic-gate 	    dlist_t	*disks = NULL;
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate 	    error = hba_get_avail_disks_and_space(request, hba, &disks, &space);
19130Sstevel@tonic-gate 	    if ((error == 0) && (space >= nbytes)) {
19140Sstevel@tonic-gate 		error = populate_concat(
19150Sstevel@tonic-gate 			request, nbytes, disks, cursubs, &concat);
19160Sstevel@tonic-gate 	    }
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	    if ((error == 0) && (concat != NULL)) {
19190Sstevel@tonic-gate 		dlist_t	*item = dlist_new_item((void *)concat);
19200Sstevel@tonic-gate 		if (item == NULL) {
19210Sstevel@tonic-gate 		    error = ENOMEM;
19220Sstevel@tonic-gate 		} else {
19230Sstevel@tonic-gate 		    ++count;
19240Sstevel@tonic-gate 		    list = dlist_append(item, list, AT_TAIL);
19250Sstevel@tonic-gate 		}
19260Sstevel@tonic-gate 	    }
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	    dlist_free_items(disks, NULL);
19290Sstevel@tonic-gate 	}
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	if (count != nsubs) {
19320Sstevel@tonic-gate 	    print_layout_submirrors_failed_msg(
19330Sstevel@tonic-gate 		    devconfig_type_to_str(TYPE_CONCAT),
19340Sstevel@tonic-gate 		    count, nsubs);
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	    dlist_free_items(list, free_devconfig_object);
19370Sstevel@tonic-gate 	    list = NULL;
19380Sstevel@tonic-gate 	} else {
19390Sstevel@tonic-gate 	    *results = dlist_append(list, *results, AT_TAIL);
19400Sstevel@tonic-gate 	}
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	return (error);
19430Sstevel@tonic-gate }
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate /*
19460Sstevel@tonic-gate  * FUNCTION:	compose_concats_across_hbas(devconfig_t *request,
19470Sstevel@tonic-gate  *			dlist_t *cursubs, dlist_t *hbas, dlist_t *disks,
19480Sstevel@tonic-gate  *			uint64_t nbytes, uint16_t nsubs, dlist_t **results)
19490Sstevel@tonic-gate  *
19500Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
19510Sstevel@tonic-gate  *		cursubs - pointer to a list of already composed submirrors
19520Sstevel@tonic-gate  *		hbas	- pointer to a list of available HBAs
19530Sstevel@tonic-gate  *		disks	- pointer to a list of available disks on the HBAs
19540Sstevel@tonic-gate  *		nbytes	- the desired capacity for the concats
19550Sstevel@tonic-gate  *		nsubs	- the number of concats to be composed
19560Sstevel@tonic-gate  *
19570Sstevel@tonic-gate  * OUPUT:	results	- pointer to a list of composed volumes
19580Sstevel@tonic-gate  *
19590Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
19600Sstevel@tonic-gate  *			 !0 otherwise.
19610Sstevel@tonic-gate  *
19620Sstevel@tonic-gate  * PURPOSE:	Layout function which composes the requested number of concats
19630Sstevel@tonic-gate  *		of the desired size using any available disks from the input
19640Sstevel@tonic-gate  *		list of available HBAs.
19650Sstevel@tonic-gate  *
19660Sstevel@tonic-gate  *		If the concats can be composed, they are appended to the list
19670Sstevel@tonic-gate  *		of result volumes.
19680Sstevel@tonic-gate  *
19690Sstevel@tonic-gate  *		copy the input disk list
19700Sstevel@tonic-gate  *		while (more concats need to be composed) {
19710Sstevel@tonic-gate  *		    if (a concat can be composed using remaining disks) {
19720Sstevel@tonic-gate  *			save concat
19730Sstevel@tonic-gate  *			remove used disks from disk list
19740Sstevel@tonic-gate  *			increment count
19750Sstevel@tonic-gate  *		    } else {
19760Sstevel@tonic-gate  *			end while loop
19770Sstevel@tonic-gate  *		    }
19780Sstevel@tonic-gate  *		}
19790Sstevel@tonic-gate  *
19800Sstevel@tonic-gate  *		if (not all concats composed) {
19810Sstevel@tonic-gate  *		    delete any concats composed
19820Sstevel@tonic-gate  *		}
19830Sstevel@tonic-gate  *
19840Sstevel@tonic-gate  *		append composed concats to results
19850Sstevel@tonic-gate  */
19860Sstevel@tonic-gate static int
compose_concats_across_hbas(devconfig_t * request,dlist_t * cursubs,dlist_t * hbas,dlist_t * disks,uint64_t nbytes,uint16_t nsubs,dlist_t ** results)19870Sstevel@tonic-gate compose_concats_across_hbas(
19880Sstevel@tonic-gate 	devconfig_t	*request,
19890Sstevel@tonic-gate 	dlist_t		*cursubs,
19900Sstevel@tonic-gate 	dlist_t		*hbas,
19910Sstevel@tonic-gate 	dlist_t		*disks,
19920Sstevel@tonic-gate 	uint64_t	nbytes,
19930Sstevel@tonic-gate 	uint16_t	nsubs,
19940Sstevel@tonic-gate 	dlist_t		**results)
19950Sstevel@tonic-gate {
19960Sstevel@tonic-gate 	int		error = 0;
19970Sstevel@tonic-gate 	int		count = 0;
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate 	dlist_t		*list	= NULL;
20000Sstevel@tonic-gate 	dlist_t		*item = NULL;
20010Sstevel@tonic-gate 	dlist_t		*iter	= NULL;
20020Sstevel@tonic-gate 	dlist_t		*disks_copy = NULL;
20030Sstevel@tonic-gate 
20040Sstevel@tonic-gate 	/* copy disk list, it is modified by the while loop */
20050Sstevel@tonic-gate 	for (iter = disks; iter != NULL; iter = iter->next) {
20060Sstevel@tonic-gate 	    if ((item = dlist_new_item(iter->obj)) == NULL) {
20070Sstevel@tonic-gate 		error = ENOMEM;
20080Sstevel@tonic-gate 	    } else {
20090Sstevel@tonic-gate 		disks_copy = dlist_append(item, disks_copy, AT_HEAD);
20100Sstevel@tonic-gate 	    }
20110Sstevel@tonic-gate 	}
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate 	while ((count < nsubs) && (error == 0)) {
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	    devconfig_t *concat = NULL;
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	    error = populate_concat(
20180Sstevel@tonic-gate 		    request, nbytes, disks_copy, cursubs, &concat);
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 	    if ((error == 0) && (concat != NULL)) {
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate 		item = dlist_new_item((void *)concat);
20230Sstevel@tonic-gate 		if (item == NULL) {
20240Sstevel@tonic-gate 		    error = ENOMEM;
20250Sstevel@tonic-gate 		} else {
20260Sstevel@tonic-gate 		    count++;
20270Sstevel@tonic-gate 		    list = dlist_append(item, list, AT_TAIL);
20280Sstevel@tonic-gate 		    error = remove_used_disks(&disks_copy, concat);
20290Sstevel@tonic-gate 		}
20300Sstevel@tonic-gate 	    } else if (concat == NULL) {
20310Sstevel@tonic-gate 		break;
20320Sstevel@tonic-gate 	    }
20330Sstevel@tonic-gate 	}
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	/* free copy of disk list */
20360Sstevel@tonic-gate 	dlist_free_items(disks_copy, NULL);
20370Sstevel@tonic-gate 	disks_copy = NULL;
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 	if (count != nsubs) {
20400Sstevel@tonic-gate 	    print_layout_submirrors_failed_msg(
20410Sstevel@tonic-gate 		    devconfig_type_to_str(TYPE_CONCAT),
20420Sstevel@tonic-gate 		    count, nsubs);
20430Sstevel@tonic-gate 
20440Sstevel@tonic-gate 	    dlist_free_items(list, free_devconfig_object);
20450Sstevel@tonic-gate 	    list = NULL;
20460Sstevel@tonic-gate 	} else {
20470Sstevel@tonic-gate 	    *results = dlist_append(list, *results, AT_TAIL);
20480Sstevel@tonic-gate 	}
20490Sstevel@tonic-gate 
20500Sstevel@tonic-gate 	return (error);
20510Sstevel@tonic-gate }
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate /*
20540Sstevel@tonic-gate  * FUNCTION:	compose_concats_within_hba(devconfig_t *request,
20550Sstevel@tonic-gate  *			dlist_t *cursubs, dlist_t *hbas, uint64_t nbytes,
20560Sstevel@tonic-gate  *			uint16_t nsubs, dlist_t	**results)
20570Sstevel@tonic-gate  *
20580Sstevel@tonic-gate  * INPUT:	request	- pointer to a devconfig_t of the current request
20590Sstevel@tonic-gate  *		cursubs - pointer to a list of already composed submirrors
20600Sstevel@tonic-gate  *		hbas	- pointer to a list of available HBAs
20610Sstevel@tonic-gate  *		nbytes	- the desired capacity for the concats
20620Sstevel@tonic-gate  *		nsubs	- the number of concats to be composed
20630Sstevel@tonic-gate  *
20640Sstevel@tonic-gate  * OUPUT:	results	- pointer to a list of composed volumes
20650Sstevel@tonic-gate  *
20660Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
20670Sstevel@tonic-gate  *			 !0 otherwise.
20680Sstevel@tonic-gate  *
20690Sstevel@tonic-gate  * PURPOSE:	Layout function which composes the requested number of concats
20700Sstevel@tonic-gate  *		of the desired size using available disks within any single
20710Sstevel@tonic-gate  *		HBA from the input list.
20720Sstevel@tonic-gate  *
20730Sstevel@tonic-gate  *
20740Sstevel@tonic-gate  *		HBAs in the list are expected to have at least 2 available
20750Sstevel@tonic-gate  *		disks and total space sufficient for the submirrors.
20760Sstevel@tonic-gate  *
20770Sstevel@tonic-gate  *		If the concats can be composed, they are appended to the list
20780Sstevel@tonic-gate  *		of result volumes.
20790Sstevel@tonic-gate  *
20800Sstevel@tonic-gate  *		while (more HBAs) {
20810Sstevel@tonic-gate  *		    if (not enough available space on this HBA) {
20820Sstevel@tonic-gate  *			continue;
20830Sstevel@tonic-gate  *		    }
20840Sstevel@tonic-gate  *
20850Sstevel@tonic-gate  *		    get available disks for HBA
20860Sstevel@tonic-gate  *		    while (more concats need to be composed) {
20870Sstevel@tonic-gate  *			if a concat can be composed using disks {
20880Sstevel@tonic-gate  *			    save concat
20890Sstevel@tonic-gate  *			    remove used disks from disk list
20900Sstevel@tonic-gate  *			    increment count
20910Sstevel@tonic-gate  *			} else {
20920Sstevel@tonic-gate  *			    delete any concats composed
20930Sstevel@tonic-gate  *			    end while loop
20940Sstevel@tonic-gate  *			}
20950Sstevel@tonic-gate  *		    }
20960Sstevel@tonic-gate  *		}
20970Sstevel@tonic-gate  *
20980Sstevel@tonic-gate  *		if (not all concats composed) {
20990Sstevel@tonic-gate  *		    delete any concats composed
21000Sstevel@tonic-gate  *		}
21010Sstevel@tonic-gate  *
21020Sstevel@tonic-gate  *		append composed concats to results
21030Sstevel@tonic-gate  */
21040Sstevel@tonic-gate static int
compose_concats_within_hba(devconfig_t * request,dlist_t * cursubs,dlist_t * hbas,uint64_t nbytes,uint16_t nsubs,dlist_t ** results)21050Sstevel@tonic-gate compose_concats_within_hba(
21060Sstevel@tonic-gate 	devconfig_t	*request,
21070Sstevel@tonic-gate 	dlist_t		*cursubs,
21080Sstevel@tonic-gate 	dlist_t		*hbas,
21090Sstevel@tonic-gate 	uint64_t	nbytes,
21100Sstevel@tonic-gate 	uint16_t	nsubs,
21110Sstevel@tonic-gate 	dlist_t		**results)
21120Sstevel@tonic-gate {
21130Sstevel@tonic-gate 	int		error = 0;
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	dlist_t		*iter	= NULL;
21160Sstevel@tonic-gate 	dlist_t		*list	= NULL;
21170Sstevel@tonic-gate 	int		count = 0;
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 	oprintf(OUTPUT_VERBOSE,
21200Sstevel@tonic-gate 		gettext("  --->Trying to compose %d Concats within "
21210Sstevel@tonic-gate 			"a single HBA.\n"), nsubs);
21220Sstevel@tonic-gate 
21230Sstevel@tonic-gate 	for (iter = hbas;
21240Sstevel@tonic-gate 	    (count < nsubs) && (error == 0) && (iter != NULL);
21250Sstevel@tonic-gate 	    iter = iter->next) {
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
21280Sstevel@tonic-gate 	    dlist_t	*disks	= NULL;
21290Sstevel@tonic-gate 	    uint64_t	space = 0;
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 	    error = hba_get_avail_disks_and_space(request, hba, &disks, &space);
21320Sstevel@tonic-gate 	    if ((error == 0) && (space >= (nsubs * nbytes))) {
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 		/* try composing nsubs concats all on this HBA */
21350Sstevel@tonic-gate 		count = 0;
21360Sstevel@tonic-gate 		while ((count < nsubs) && (error == 0)) {
21370Sstevel@tonic-gate 		    devconfig_t *concat = NULL;
21380Sstevel@tonic-gate 		    dlist_t	*item = NULL;
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate 		    error = populate_concat(
21410Sstevel@tonic-gate 			    request, nbytes, disks, cursubs, &concat);
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 		    if ((error == 0) && (concat != NULL)) {
21440Sstevel@tonic-gate 			item = dlist_new_item((void*)concat);
21450Sstevel@tonic-gate 			if (item == NULL) {
21460Sstevel@tonic-gate 			    error = ENOMEM;
21470Sstevel@tonic-gate 			} else {
21480Sstevel@tonic-gate 			    count++;
21490Sstevel@tonic-gate 			    list = dlist_append(item, list, AT_TAIL);
21500Sstevel@tonic-gate 			    error = remove_used_disks(&disks, concat);
21510Sstevel@tonic-gate 			}
21520Sstevel@tonic-gate 		    } else if (concat == NULL) {
21530Sstevel@tonic-gate 			dlist_free_items(list, free_devconfig_object);
21540Sstevel@tonic-gate 			list = NULL;
21550Sstevel@tonic-gate 			break;
21560Sstevel@tonic-gate 		    }
21570Sstevel@tonic-gate 		}
21580Sstevel@tonic-gate 	    }
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 	    dlist_free_items(disks, NULL);
21610Sstevel@tonic-gate 	}
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	if (count < nsubs) {
21640Sstevel@tonic-gate 	    print_layout_submirrors_failed_msg(
21650Sstevel@tonic-gate 		    devconfig_type_to_str(TYPE_CONCAT),
21660Sstevel@tonic-gate 		    count, nsubs);
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 	    dlist_free_items(list, free_devconfig_object);
21690Sstevel@tonic-gate 	    list = NULL;
21700Sstevel@tonic-gate 	} else {
21710Sstevel@tonic-gate 	    *results = dlist_append(list, *results, AT_TAIL);
21720Sstevel@tonic-gate 	}
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	return (error);
21750Sstevel@tonic-gate }
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate /*
21780Sstevel@tonic-gate  * FUNCTION:	remove_used_disks(dlist_t **disks, devconfig_t *volume)
21790Sstevel@tonic-gate  *
21800Sstevel@tonic-gate  * INPUT:	disks	- pointer to a list of disks
21810Sstevel@tonic-gate  *		volume  - pointer to a devconfig_t volume
21820Sstevel@tonic-gate  *
21830Sstevel@tonic-gate  * OUPUT:	disks	- pointer to new list of disks
21840Sstevel@tonic-gate  *
21850Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
21860Sstevel@tonic-gate  *			 !0 otherwise.
21870Sstevel@tonic-gate  *
21880Sstevel@tonic-gate  * PURPOSE:	Helper which updates the input list of disks by removing
21890Sstevel@tonic-gate  *		those which have slices	used by the input volume.
21900Sstevel@tonic-gate  *
21910Sstevel@tonic-gate  *		Constructs a new list containing only disks not used by
21920Sstevel@tonic-gate  *		the volume.
21930Sstevel@tonic-gate  *
21940Sstevel@tonic-gate  *		The original list is freed.
21950Sstevel@tonic-gate  */
21960Sstevel@tonic-gate static int
remove_used_disks(dlist_t ** disks,devconfig_t * volume)21970Sstevel@tonic-gate remove_used_disks(
21980Sstevel@tonic-gate 	dlist_t	**disks,
21990Sstevel@tonic-gate 	devconfig_t *volume)
22000Sstevel@tonic-gate {
22010Sstevel@tonic-gate 	dlist_t  *list = NULL;
22020Sstevel@tonic-gate 	dlist_t  *iter = NULL;
22030Sstevel@tonic-gate 	dlist_t  *item = NULL;
22040Sstevel@tonic-gate 	int	error = 0;
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 	for (iter = *disks; (iter != NULL) && (error == 0); iter = iter->next) {
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate 	    dm_descriptor_t diskp = (uintptr_t)iter->obj;
22090Sstevel@tonic-gate 	    boolean_t	shares = B_FALSE;
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 	    error = volume_shares_disk(diskp, volume, &shares);
22120Sstevel@tonic-gate 	    if ((error == 0) && (shares != B_TRUE)) {
22130Sstevel@tonic-gate 		/* disk is unused */
2214*62Sjeanm 		if ((item = dlist_new_item((void*)(uintptr_t)diskp)) == NULL) {
22150Sstevel@tonic-gate 		    error = ENOMEM;
22160Sstevel@tonic-gate 		} else {
22170Sstevel@tonic-gate 		    list = dlist_append(item, list, AT_TAIL);
22180Sstevel@tonic-gate 		}
22190Sstevel@tonic-gate 	    }
22200Sstevel@tonic-gate 	}
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	if (error != 0) {
22230Sstevel@tonic-gate 	    dlist_free_items(list, NULL);
22240Sstevel@tonic-gate 	} else {
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 	    /* free original disk list, return new list */
22270Sstevel@tonic-gate 	    dlist_free_items(*disks, NULL);
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 	    *disks = list;
22300Sstevel@tonic-gate 	}
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 	return (error);
22330Sstevel@tonic-gate }
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate /*
22360Sstevel@tonic-gate  * FUNCTION:	volume_shares_disk(dm_descriptor_t disk,
22370Sstevel@tonic-gate  *			devconfig_t *volume, boolean_t *shares)
22380Sstevel@tonic-gate  *
22390Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t handle for the disk of interest
22400Sstevel@tonic-gate  *		volume	- a devconfig_t pointer to a volume
22410Sstevel@tonic-gate  *		bool	- a boolean_t pointer to hold the result
22420Sstevel@tonic-gate  *
22430Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
22440Sstevel@tonic-gate  *			 !0 otherwise
22450Sstevel@tonic-gate  *
22460Sstevel@tonic-gate  * PURPOSE:	Determines if the input disk has a slice that is used
22470Sstevel@tonic-gate  *		as a component by the input volume.
22480Sstevel@tonic-gate  *
22490Sstevel@tonic-gate  *		If the disk contributes a slice component, bool is set
22500Sstevel@tonic-gate  *		to B_TRUE, B_FALSE otherwise.
22510Sstevel@tonic-gate  */
22520Sstevel@tonic-gate static int
volume_shares_disk(dm_descriptor_t disk,devconfig_t * volume,boolean_t * shares)22530Sstevel@tonic-gate volume_shares_disk(
22540Sstevel@tonic-gate 	dm_descriptor_t disk,
22550Sstevel@tonic-gate 	devconfig_t	*volume,
22560Sstevel@tonic-gate 	boolean_t	*shares)
22570Sstevel@tonic-gate {
22580Sstevel@tonic-gate 	dlist_t		*iter = NULL;
22590Sstevel@tonic-gate 	int		error = 0;
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 	*shares = B_FALSE;
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 	/* look at all slices in the volume */
22640Sstevel@tonic-gate 	for (iter = devconfig_get_components(volume);
22650Sstevel@tonic-gate 	    (iter != NULL) && (*shares == B_FALSE) && (error == 0);
22660Sstevel@tonic-gate 	    iter = iter->next) {
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate 	    devconfig_t	*dev = (devconfig_t *)iter->obj;
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	    if (devconfig_isA(dev, TYPE_SLICE)) {
22710Sstevel@tonic-gate 
22720Sstevel@tonic-gate 		/* get disk for volume's slice */
22730Sstevel@tonic-gate 		dm_descriptor_t	odisk = NULL;
22740Sstevel@tonic-gate 		char		*oname = NULL;
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 		((error = devconfig_get_name(dev, &oname)) != 0) ||
22770Sstevel@tonic-gate 		(error = get_disk_for_named_slice(oname, &odisk));
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 		if (error == 0) {
22800Sstevel@tonic-gate 		    if (compare_descriptor_names(
2281*62Sjeanm 			(void*)(uintptr_t)disk, (void*)(uintptr_t)odisk) == 0) {
22820Sstevel@tonic-gate 			/* otherslice is on same disk, stop */
22830Sstevel@tonic-gate 			*shares = B_TRUE;
22840Sstevel@tonic-gate 		    }
22850Sstevel@tonic-gate 		}
22860Sstevel@tonic-gate 	    }
22870Sstevel@tonic-gate 	}
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	return (error);
22900Sstevel@tonic-gate }
22910Sstevel@tonic-gate 
22920Sstevel@tonic-gate /*
22930Sstevel@tonic-gate  * FUNCTION:	select_mpxio_hbas(dlist_t *hbas, dlist_t **mpxio_hbas)
22940Sstevel@tonic-gate  *
22950Sstevel@tonic-gate  * INPUT:	hbas	- pointer to a list of dm_descriptor_t HBA handles
22960Sstevel@tonic-gate  *
22970Sstevel@tonic-gate  * OUTPUT:	mpxio_hbas - pointer to a new list of containing HBAs that
22980Sstevel@tonic-gate  *			are multiplex enabled.
22990Sstevel@tonic-gate  *
23000Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
23010Sstevel@tonic-gate  *			 !0 otherwise.
23020Sstevel@tonic-gate  *
23030Sstevel@tonic-gate  * PURPOSE:	Iterates the input list of HBAs and builds a new list
23040Sstevel@tonic-gate  *		containing those that are multiplex enabled.
23050Sstevel@tonic-gate  *
23060Sstevel@tonic-gate  *		The output list should be passed to dlist_free_items()
23070Sstevel@tonic-gate  *		when no longer needed.
23080Sstevel@tonic-gate  */
23090Sstevel@tonic-gate static int
select_mpxio_hbas(dlist_t * hbas,dlist_t ** mpxio_hbas)23100Sstevel@tonic-gate select_mpxio_hbas(
23110Sstevel@tonic-gate 	dlist_t	*hbas,
23120Sstevel@tonic-gate 	dlist_t **mpxio_hbas)
23130Sstevel@tonic-gate {
23140Sstevel@tonic-gate 	dlist_t *iter;
23150Sstevel@tonic-gate 	int	error = 0;
23160Sstevel@tonic-gate 
23170Sstevel@tonic-gate 	for (iter = hbas; (iter != NULL) && (error == 0); iter = iter->next) {
23180Sstevel@tonic-gate 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
23190Sstevel@tonic-gate 	    boolean_t ismpxio = B_FALSE;
23200Sstevel@tonic-gate 	    if ((error = hba_is_multiplex(hba, &ismpxio)) == 0) {
23210Sstevel@tonic-gate 		if (ismpxio == B_TRUE) {
2322*62Sjeanm 		    dlist_t *item = dlist_new_item((void *)(uintptr_t)hba);
23230Sstevel@tonic-gate 		    if (item != NULL) {
23240Sstevel@tonic-gate 			*mpxio_hbas =
23250Sstevel@tonic-gate 			    dlist_append(item, *mpxio_hbas, AT_TAIL);
23260Sstevel@tonic-gate 		    } else {
23270Sstevel@tonic-gate 			error = ENOMEM;
23280Sstevel@tonic-gate 		    }
23290Sstevel@tonic-gate 		}
23300Sstevel@tonic-gate 	    }
23310Sstevel@tonic-gate 	}
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 	if (error != 0) {
23340Sstevel@tonic-gate 	    dlist_free_items(*mpxio_hbas, NULL);
23350Sstevel@tonic-gate 	    *mpxio_hbas = NULL;
23360Sstevel@tonic-gate 	}
23370Sstevel@tonic-gate 
23380Sstevel@tonic-gate 	return (error);
23390Sstevel@tonic-gate }
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate /*
23420Sstevel@tonic-gate  * FUNCTION:	set_explicit_submirror_names(dlist_t *reqs, dlist_t *subs)
23430Sstevel@tonic-gate  *
23440Sstevel@tonic-gate  * INPUT:	reqs	- pointer to a list of request devconfig_ts
23450Sstevel@tonic-gate  *		subs	- pointer to a list of volume devconfig_ts
23460Sstevel@tonic-gate  *
23470Sstevel@tonic-gate  * SIDEEFFECT:	Modifies the volume names.
23480Sstevel@tonic-gate  *
23490Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
23500Sstevel@tonic-gate  *			 !0 otherwise.
23510Sstevel@tonic-gate  *
23520Sstevel@tonic-gate  * PURPOSE:	Iterates the lists of volumes and requests and calls
23530Sstevel@tonic-gate  *		set_explicit_mirror_name for each pair.
23540Sstevel@tonic-gate  */
23550Sstevel@tonic-gate static int
set_explicit_submirror_names(dlist_t * reqs,dlist_t * subs)23560Sstevel@tonic-gate set_explicit_submirror_names(
23570Sstevel@tonic-gate 	dlist_t	*reqs,
23580Sstevel@tonic-gate 	dlist_t	*subs)
23590Sstevel@tonic-gate {
23600Sstevel@tonic-gate 	int	error = 0;
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 	while ((reqs != NULL) && (subs != NULL) && (error == 0)) {
23630Sstevel@tonic-gate 
23640Sstevel@tonic-gate 	    error = set_explicit_submirror_name(
23650Sstevel@tonic-gate 		(devconfig_t *)reqs->obj,
23660Sstevel@tonic-gate 		(devconfig_t *)subs->obj);
23670Sstevel@tonic-gate 
23680Sstevel@tonic-gate 	    reqs = reqs->next;
23690Sstevel@tonic-gate 	    subs = subs->next;
23700Sstevel@tonic-gate 	}
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 	return (error);
23730Sstevel@tonic-gate }
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate /*
23760Sstevel@tonic-gate  * FUNCTION:	set_explicit_submirror_name(dlist_t *req, dlist_t *sub)
23770Sstevel@tonic-gate  *
23780Sstevel@tonic-gate  * INPUT:	req	- pointer to a request devconfig_t
23790Sstevel@tonic-gate  *		sub	- pointer to a volume devconfig_t
23800Sstevel@tonic-gate  *
23810Sstevel@tonic-gate  * SIDEEFFECT:	Modifies the volume name.
23820Sstevel@tonic-gate  *
23830Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
23840Sstevel@tonic-gate  *			 !0 otherwise.
23850Sstevel@tonic-gate  *
23860Sstevel@tonic-gate  * PURPOSE:	Clears the volume's current name and returns the name
23870Sstevel@tonic-gate  *		to the available pool.
23880Sstevel@tonic-gate  *
23890Sstevel@tonic-gate  *		If a name is specified in the request, the name is used
23900Sstevel@tonic-gate  *		as the volume's name.
23910Sstevel@tonic-gate  *
23920Sstevel@tonic-gate  *		(Unnamed submirrors will have default names assigned
23930Sstevel@tonic-gate  *		during final mirror assembly.)
23940Sstevel@tonic-gate  */
23950Sstevel@tonic-gate static int
set_explicit_submirror_name(devconfig_t * req,devconfig_t * sub)23960Sstevel@tonic-gate set_explicit_submirror_name(
23970Sstevel@tonic-gate 	devconfig_t *req,
23980Sstevel@tonic-gate 	devconfig_t *sub)
23990Sstevel@tonic-gate {
24000Sstevel@tonic-gate 	char *name = NULL;
24010Sstevel@tonic-gate 	int	error = 0;
24020Sstevel@tonic-gate 
24030Sstevel@tonic-gate 	/* unset current submirror name */
24040Sstevel@tonic-gate 	(void) devconfig_get_name(sub, &name);
24050Sstevel@tonic-gate 	release_volume_name(name);
24060Sstevel@tonic-gate 	(void) devconfig_set_name(sub, "");
24070Sstevel@tonic-gate 
24080Sstevel@tonic-gate 	if (devconfig_get_name(req, &name) != ERR_ATTR_UNSET) {
24090Sstevel@tonic-gate 	    (void) devconfig_set_name(sub, name);
24100Sstevel@tonic-gate 	}
24110Sstevel@tonic-gate 
24120Sstevel@tonic-gate 	return (error);
24130Sstevel@tonic-gate }
2414