xref: /onnv-gate/usr/src/cmd/lvm/metassist/layout/layout_hsp.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 <string.h>
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include "volume_error.h"
340Sstevel@tonic-gate #include "volume_dlist.h"
350Sstevel@tonic-gate #include "volume_output.h"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include "layout_device_cache.h"
380Sstevel@tonic-gate #include "layout_device_util.h"
390Sstevel@tonic-gate #include "layout_discovery.h"
400Sstevel@tonic-gate #include "layout_dlist_util.h"
410Sstevel@tonic-gate #include "layout_messages.h"
420Sstevel@tonic-gate #include "layout_request.h"
430Sstevel@tonic-gate #include "layout_slice.h"
440Sstevel@tonic-gate #include "layout_svm_util.h"
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #define	_LAYOUT_HSP_C
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static int layout_explicit_hsp(
490Sstevel@tonic-gate 	devconfig_t 	*hsprequest,
500Sstevel@tonic-gate 	dlist_t		*devices,
510Sstevel@tonic-gate 	devconfig_t 	**hsp);
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int layout_default_hsp(
540Sstevel@tonic-gate 	devconfig_t 	*request,
550Sstevel@tonic-gate 	dlist_t		*devices,
560Sstevel@tonic-gate 	devconfig_t 	**hsp);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate static int populate_hsp(
590Sstevel@tonic-gate 	devconfig_t	*request,
600Sstevel@tonic-gate 	devconfig_t	*hsp,
610Sstevel@tonic-gate 	dlist_t		*devices);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static int assemble_hsp(
640Sstevel@tonic-gate 	devconfig_t 	*hsp,
650Sstevel@tonic-gate 	dlist_t		*newspares,
660Sstevel@tonic-gate 	dlist_t		*devices);
670Sstevel@tonic-gate 
680Sstevel@tonic-gate static int get_uniquely_sized_slices(
690Sstevel@tonic-gate 	dlist_t 	*devices,
700Sstevel@tonic-gate 	dlist_t 	**unique);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static int remove_undersized_slices(
730Sstevel@tonic-gate 	dlist_t 	*unique,
740Sstevel@tonic-gate 	dlist_t 	**avail);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static int find_spare_for_component(
770Sstevel@tonic-gate 	devconfig_t 	*component,
780Sstevel@tonic-gate 	dlist_t		*all_spares,
790Sstevel@tonic-gate 	dlist_t		*hbas,
800Sstevel@tonic-gate 	dlist_t		*disks,
810Sstevel@tonic-gate 	boolean_t 	*found);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate static int choose_spare_for_component(
840Sstevel@tonic-gate 	devconfig_t 	*comp,
850Sstevel@tonic-gate 	dlist_t 	**all_spares,
860Sstevel@tonic-gate 	dlist_t 	**new_spares,
870Sstevel@tonic-gate 	dlist_t 	**avail,
880Sstevel@tonic-gate 	dlist_t 	*used_hbas,
890Sstevel@tonic-gate 	dlist_t 	*used_disks,
900Sstevel@tonic-gate 	uint16_t	npaths);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * FUNCTION:	layout_hsp(devconfig_t *request, devconfig_t hsprequest,
940Sstevel@tonic-gate  *			dlist_t *devices, dlist_t **results)
950Sstevel@tonic-gate  *
960Sstevel@tonic-gate  * INPUT:	request	- pointer to the toplevel request devconfig_t
970Sstevel@tonic-gate  *		hsp	- pointer to the optional HSP request devconfig_t
980Sstevel@tonic-gate  *		devices - pointer to a list of devices to be served by the HSP
990Sstevel@tonic-gate  *
1000Sstevel@tonic-gate  * OUTPUT:	results - pointer to a list result devconfig_t, if the HSP
1010Sstevel@tonic-gate  *			to service the input list of devices needs to be
1020Sstevel@tonic-gate  *			created or modified, it will be appended to the list.
1030Sstevel@tonic-gate  *
1040Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1050Sstevel@tonic-gate  *			 !0 otherwise.
1060Sstevel@tonic-gate  *
1070Sstevel@tonic-gate  * PURPOSE:	Main layout driver for HSP, attempts to build/populate a
1080Sstevel@tonic-gate  *		single HSP to service the list of devices.
1090Sstevel@tonic-gate  *
1100Sstevel@tonic-gate  *		If the input hsprequest is NULL, use the default HSP scheme:
1110Sstevel@tonic-gate  *		a. use the first HSP in the diskset
1120Sstevel@tonic-gate  *		b. create an HSP if the diskset has none
1130Sstevel@tonic-gate  *
1140Sstevel@tonic-gate  *		If the hsprequest is not NULL:
1150Sstevel@tonic-gate  *		a. if the request names an HSP and it already exists, use it
1160Sstevel@tonic-gate  *		b. if the request names an HSP and it does not exist, create it
1170Sstevel@tonic-gate  *		c. if the request specifies components, use them
1180Sstevel@tonic-gate  */
1190Sstevel@tonic-gate int
layout_hsp(devconfig_t * request,devconfig_t * hsprequest,dlist_t * devices,dlist_t ** results)1200Sstevel@tonic-gate layout_hsp(
1210Sstevel@tonic-gate 	devconfig_t	*request,
1220Sstevel@tonic-gate 	devconfig_t	*hsprequest,
1230Sstevel@tonic-gate 	dlist_t		*devices,
1240Sstevel@tonic-gate 	dlist_t		**results)
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate 	int		error = 0;
1270Sstevel@tonic-gate 	devconfig_t  	*hsp = NULL;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
1300Sstevel@tonic-gate 		gettext("  ->Layout a %s\n"),
1310Sstevel@tonic-gate 		devconfig_type_to_str(TYPE_HSP));
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	if (hsprequest == NULL) {
1340Sstevel@tonic-gate 	    error = layout_default_hsp(request, devices, &hsp);
1350Sstevel@tonic-gate 	} else {
1360Sstevel@tonic-gate 	    error = layout_explicit_hsp(hsprequest, devices, &hsp);
1370Sstevel@tonic-gate 	}
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	if (error != 0) {
1400Sstevel@tonic-gate 	    print_debug_failure_msg(devconfig_type_to_str(TYPE_HSP),
1410Sstevel@tonic-gate 		    get_error_string(error));
1420Sstevel@tonic-gate 	} else if (hsp != NULL) {
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	    if (devconfig_get_components(hsp) == NULL) {
1450Sstevel@tonic-gate 		/* HSP is usable as it is */
1460Sstevel@tonic-gate 		free_devconfig(hsp);
1470Sstevel@tonic-gate 		hsp = NULL;
1480Sstevel@tonic-gate 	    } else {
1490Sstevel@tonic-gate 		dlist_t *item = NULL;
1500Sstevel@tonic-gate 		if ((item = dlist_new_item(hsp)) == NULL) {
1510Sstevel@tonic-gate 		    error = ENOMEM;
1520Sstevel@tonic-gate 		} else {
1530Sstevel@tonic-gate 		    *results = dlist_append(item, *results, AT_TAIL);
1540Sstevel@tonic-gate 		    print_layout_success_msg();
1550Sstevel@tonic-gate 		}
1560Sstevel@tonic-gate 	    }
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	return (error);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate  * FUNCTION:	layout_default_hsp(devconfig_t *request,
1640Sstevel@tonic-gate  *			dlist_t *devices, devconfig_t **hsp)
1650Sstevel@tonic-gate  *
1660Sstevel@tonic-gate  * INPUT:	request	- pointer to the toplevel request devconfig_t
1670Sstevel@tonic-gate  *		devices - pointer to a list of devices to be served by the HSP
1680Sstevel@tonic-gate  *
1690Sstevel@tonic-gate  * OUTPUT:	hsp	- pointer to a devconfig_t to hold the resulting HSP
1700Sstevel@tonic-gate  *
1710Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1720Sstevel@tonic-gate  *			 !0 otherwise.
1730Sstevel@tonic-gate  *
1740Sstevel@tonic-gate  * PURPOSE:	Layout driver for default HSP construction.
1750Sstevel@tonic-gate  *
1760Sstevel@tonic-gate  *		a. use the first HSP in the diskset
1770Sstevel@tonic-gate  *		b. create an HSP if the diskset has none
1780Sstevel@tonic-gate  *		c. add spares to the HSP to service the list of input devices.
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate static int
layout_default_hsp(devconfig_t * request,dlist_t * devices,devconfig_t ** hsp)1810Sstevel@tonic-gate layout_default_hsp(
1820Sstevel@tonic-gate 	devconfig_t 	*request,
1830Sstevel@tonic-gate 	dlist_t		*devices,
1840Sstevel@tonic-gate 	devconfig_t 	**hsp)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	char		*dsname = get_request_diskset();
1870Sstevel@tonic-gate 	char		*hspname = NULL;
1880Sstevel@tonic-gate 	boolean_t	free_hspname = B_FALSE;
1890Sstevel@tonic-gate 	devconfig_t	*default_hsp = NULL;
1900Sstevel@tonic-gate 	int		error = 0;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	oprintf(OUTPUT_TERSE,
1930Sstevel@tonic-gate 		gettext("  -->Using default HSP scheme...\n"));
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if ((error = get_default_hsp_name(request, &hspname)) != 0) {
1960Sstevel@tonic-gate 	    volume_set_error(
1970Sstevel@tonic-gate 		    gettext("error getting HSP name from defaults\n"));
1980Sstevel@tonic-gate 	    return (error);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if (hspname != NULL) {
2020Sstevel@tonic-gate 	    if ((error = hsp_get_by_name(dsname, hspname, &default_hsp)) != 0) {
2030Sstevel@tonic-gate 		volume_set_error(
2040Sstevel@tonic-gate 			gettext("error getting default HSP by name\n"));
2050Sstevel@tonic-gate 		return (error);
2060Sstevel@tonic-gate 	    }
2070Sstevel@tonic-gate 	} else {
2080Sstevel@tonic-gate 	    /* no default HSP name, get diskset's default HSP */
2090Sstevel@tonic-gate 	    if ((error = hsp_get_default_for_diskset(dsname,
2100Sstevel@tonic-gate 		&default_hsp)) != 0) {
2110Sstevel@tonic-gate 		volume_set_error(
2120Sstevel@tonic-gate 			gettext("error getting default HSP\n"));
2130Sstevel@tonic-gate 		return (error);
2140Sstevel@tonic-gate 	    }
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	    if (default_hsp == NULL) {
2170Sstevel@tonic-gate 		/* no default HSP name, no default HSP, make one */
2180Sstevel@tonic-gate 		if ((error = get_next_hsp_name(&hspname)) != 0) {
2190Sstevel@tonic-gate 		    volume_set_error(
2200Sstevel@tonic-gate 			    gettext("error making default HSP name\n"));
2210Sstevel@tonic-gate 		    return (error);
2220Sstevel@tonic-gate 		}
2230Sstevel@tonic-gate 		free_hspname = B_TRUE;
2240Sstevel@tonic-gate 	    }
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	if (default_hsp != NULL) {
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	    /* Found existing default HSP, copy it */
2300Sstevel@tonic-gate 	    dlist_t *spares = devconfig_get_components(default_hsp);
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	    ((error = devconfig_get_name(default_hsp, &hspname)) != 0) ||
2330Sstevel@tonic-gate 	    (error = new_devconfig(hsp, TYPE_HSP)) ||
2340Sstevel@tonic-gate 	    (error = devconfig_set_name(*hsp, hspname));
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	    if (error == 0) {
2370Sstevel@tonic-gate 		devconfig_set_components(*hsp, spares);
2380Sstevel@tonic-gate 		devconfig_set_components(default_hsp, NULL);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 		oprintf(OUTPUT_TERSE,
2410Sstevel@tonic-gate 			gettext("  --->Using %s from disk set %s...\n"),
2420Sstevel@tonic-gate 			hspname, dsname);
2430Sstevel@tonic-gate 	    } else {
2440Sstevel@tonic-gate 		free_devconfig(*hsp);
2450Sstevel@tonic-gate 		*hsp = NULL;
2460Sstevel@tonic-gate 	    }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	} else {
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	    /* no existing default HSP, make it */
2510Sstevel@tonic-gate 	    ((error = new_devconfig(hsp, TYPE_HSP)) != 0) ||
2520Sstevel@tonic-gate 	    (error = devconfig_set_name(*hsp, hspname));
2530Sstevel@tonic-gate 	    if (error == 0) {
2540Sstevel@tonic-gate 		oprintf(OUTPUT_VERBOSE,
2550Sstevel@tonic-gate 			gettext("  --->Created %s for disk set %s...\n "),
2560Sstevel@tonic-gate 			hspname, dsname);
2570Sstevel@tonic-gate 	    } else {
2580Sstevel@tonic-gate 		free_devconfig(*hsp);
2590Sstevel@tonic-gate 		*hsp = NULL;
2600Sstevel@tonic-gate 	    }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	    if (free_hspname == B_TRUE) {
2630Sstevel@tonic-gate 		free(hspname);
2640Sstevel@tonic-gate 	    }
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	if (error == 0) {
2680Sstevel@tonic-gate 	    error = populate_hsp(request, *hsp, devices);
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	return (error);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate  * FUNCTION:	layout_explicit_hsp(devconfig_t *hsprequest,
2760Sstevel@tonic-gate  *			dlist_t *devices, devconfig_t **hsp)
2770Sstevel@tonic-gate  *
2780Sstevel@tonic-gate  * INPUT:	hsprequest - pointer to the explicit HSP request devconfig_t
2790Sstevel@tonic-gate  *		devices - pointer to a list of devices to be served by the HSP
2800Sstevel@tonic-gate  *
2810Sstevel@tonic-gate  * OUTPUT:	hsp	- pointer to a HSP devconfig_t to hold resulting HSP
2820Sstevel@tonic-gate  *
2830Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2840Sstevel@tonic-gate  *			 !0 otherwise.
2850Sstevel@tonic-gate  *
2860Sstevel@tonic-gate  * PURPOSE:	Layout driver for an explicit HSP request.
2870Sstevel@tonic-gate  *
2880Sstevel@tonic-gate  *		a. if the request names an HSP and it already exists, use it
2890Sstevel@tonic-gate  *		b. if the request names an HSP and it does not exist, create it
2900Sstevel@tonic-gate  *		c. if the request specifies components, use them
2910Sstevel@tonic-gate  *		   otherwise, add new spares to handle the input list
2920Sstevel@tonic-gate  *		   of devices.
2930Sstevel@tonic-gate  */
2940Sstevel@tonic-gate static int
layout_explicit_hsp(devconfig_t * hsprequest,dlist_t * devices,devconfig_t ** hsp)2950Sstevel@tonic-gate layout_explicit_hsp(
2960Sstevel@tonic-gate 	devconfig_t	*hsprequest,
2970Sstevel@tonic-gate 	dlist_t		*devices,
2980Sstevel@tonic-gate 	devconfig_t 	**hsp)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	char		*dsname = get_request_diskset();
3010Sstevel@tonic-gate 	char		*hspname = NULL;
3020Sstevel@tonic-gate 	dlist_t		*rspares = NULL;
3030Sstevel@tonic-gate 	int		error = 0;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	oprintf(OUTPUT_VERBOSE,
3060Sstevel@tonic-gate 		gettext("  --->Explicit HSP request...\n"));
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	(void) devconfig_get_name(hsprequest, &hspname);
3090Sstevel@tonic-gate 	if (hspname != NULL) {
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	    (void) hsp_get_by_name(dsname, hspname, hsp);
3120Sstevel@tonic-gate 	    if (*hsp != NULL) {
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 		oprintf(OUTPUT_VERBOSE,
3150Sstevel@tonic-gate 			gettext("  --->Using %s...\n"),
3160Sstevel@tonic-gate 			hspname);
3170Sstevel@tonic-gate 	    } else {
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		/* named HSP doesn't exist, create it */
3200Sstevel@tonic-gate 		((error = new_devconfig(hsp, TYPE_HSP)) != 0) ||
3210Sstevel@tonic-gate 		(error = devconfig_set_name(*hsp, hspname));
3220Sstevel@tonic-gate 		if (error == 0) {
3230Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE,
3240Sstevel@tonic-gate 			    gettext("  --->%s does not exist, "
3250Sstevel@tonic-gate 				    "created...\n"), hspname);
3260Sstevel@tonic-gate 		} else {
3270Sstevel@tonic-gate 		    free_devconfig(*hsp);
3280Sstevel@tonic-gate 		    *hsp = NULL;
3290Sstevel@tonic-gate 		}
3300Sstevel@tonic-gate 		free(hspname);
3310Sstevel@tonic-gate 	    }
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	if (error == 0) {
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	    /* does the hsprequest specify spares? */
3370Sstevel@tonic-gate 	    rspares = devconfig_get_components(hsprequest);
3380Sstevel@tonic-gate 	    if (rspares != NULL) {
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 		/* put requested spares into HSP */
3410Sstevel@tonic-gate 		dlist_t	*list = NULL;
3420Sstevel@tonic-gate 		dlist_t *iter = NULL;
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 		for (iter = rspares;
3450Sstevel@tonic-gate 		    (iter != NULL) && (error == 0);
3460Sstevel@tonic-gate 		    iter = iter->next) {
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 		    dlist_t *item = NULL;
3490Sstevel@tonic-gate 		    if ((dlist_new_item(iter->obj)) == NULL) {
3500Sstevel@tonic-gate 			error = ENOMEM;
3510Sstevel@tonic-gate 		    } else {
3520Sstevel@tonic-gate 			list = dlist_append(item, list, AT_TAIL);
3530Sstevel@tonic-gate 		    }
3540Sstevel@tonic-gate 		}
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 		if (error == 0) {
3570Sstevel@tonic-gate 		    error = assemble_hsp(*hsp, rspares, devices);
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	    } else {
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		/* select new spares */
3630Sstevel@tonic-gate 		error = populate_hsp(hsprequest, *hsp, devices);
3640Sstevel@tonic-gate 	    }
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	return (error);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate /*
3710Sstevel@tonic-gate  * FUNCTION:	populate_hsp(devconfig_t *request, devconfig_t *hsp,
3720Sstevel@tonic-gate  *			dlist_t *devices)
3730Sstevel@tonic-gate  *
3740Sstevel@tonic-gate  * INPUT:	request	- pointer to a request devconfig_t
3750Sstevel@tonic-gate  *		hsp	- pointer to a HSP devconfig_t
3760Sstevel@tonic-gate  *		devices - pointer to a list of devices to be served by the HSP
3770Sstevel@tonic-gate  *
3780Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
3790Sstevel@tonic-gate  *			 !0 otherwise.
3800Sstevel@tonic-gate  *
3810Sstevel@tonic-gate  * PURPOSE:	Processes the input HSP request and add spares sufficient
3820Sstevel@tonic-gate  *		to service the input list of devices.
3830Sstevel@tonic-gate  *
3840Sstevel@tonic-gate  *		Determine the available HBAs, disks, and slices.
3850Sstevel@tonic-gate  *		Sort thru the input list of devices and determine
3860Sstevel@tonic-gate  *		    the unique component sizes which need to be spared.
3870Sstevel@tonic-gate  *		Filter the available slices and remove those that are
3880Sstevel@tonic-gate  *		    too small to serve as spares.
3890Sstevel@tonic-gate  *
3900Sstevel@tonic-gate  *		Iterate each device and its components and see if the
3910Sstevel@tonic-gate  *		    HSP currently has a sufficient spare, if not, try
3920Sstevel@tonic-gate  *		    to select one from the available slices.
3930Sstevel@tonic-gate  *
3940Sstevel@tonic-gate  *		If a spare cannot be found for any device component,
3950Sstevel@tonic-gate  *		    the HSP layout process stops.
3960Sstevel@tonic-gate  *
3970Sstevel@tonic-gate  *              If spares are found for all device components, add
3980Sstevel@tonic-gate  *		    any required new ones to the HSP.
3990Sstevel@tonic-gate  */
4000Sstevel@tonic-gate static int
populate_hsp(devconfig_t * request,devconfig_t * hsp,dlist_t * devices)4010Sstevel@tonic-gate populate_hsp(
4020Sstevel@tonic-gate 	devconfig_t	*request,
4030Sstevel@tonic-gate 	devconfig_t	*hsp,
4040Sstevel@tonic-gate 	dlist_t		*devices)
4050Sstevel@tonic-gate {
4060Sstevel@tonic-gate 	int		error = 0;
4070Sstevel@tonic-gate 	uint16_t	npaths	= 0;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	dlist_t		*usable_hbas = NULL;
4100Sstevel@tonic-gate 	dlist_t		*sel_hbas = NULL;
4110Sstevel@tonic-gate 	dlist_t		*disks = NULL;
4120Sstevel@tonic-gate 	dlist_t		*iter = NULL;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	dlist_t		*avail = NULL;	/* available slices */
4150Sstevel@tonic-gate 	dlist_t		*slices = NULL;	/* avail slices of sufficient size */
4160Sstevel@tonic-gate 	dlist_t		*unique = NULL;	/* volume slices that need spares */
4170Sstevel@tonic-gate 	dlist_t		*curspares = NULL; /* current spares in the HSP */
4180Sstevel@tonic-gate 	dlist_t		*newspares = NULL; /* slices to add to HSP */
4190Sstevel@tonic-gate 	dlist_t		*allspares = NULL; /* current and new spares */
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	((error = get_usable_hbas(&usable_hbas)) != 0) ||
4220Sstevel@tonic-gate 	(error = select_hbas_with_n_disks(request, usable_hbas, 1, &sel_hbas,
4230Sstevel@tonic-gate 		&disks)) ||
4240Sstevel@tonic-gate 	(error = disks_get_avail_slices(request, disks, &avail)) ||
4250Sstevel@tonic-gate 	(error = get_volume_npaths(request, &npaths));
4260Sstevel@tonic-gate 	if (error != 0) {
4270Sstevel@tonic-gate 	    dlist_free_items(sel_hbas, NULL);
4280Sstevel@tonic-gate 	    dlist_free_items(disks, NULL);
4290Sstevel@tonic-gate 	    dlist_free_items(avail, NULL);
4300Sstevel@tonic-gate 	    return (error);
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (disks == NULL || dlist_length(disks) == 0) {
4340Sstevel@tonic-gate 	    /* all disks have been consumed by the devices */
4350Sstevel@tonic-gate 	    volume_set_error(
4360Sstevel@tonic-gate 		    gettext("  no available disks to populate HSP\n"));
4370Sstevel@tonic-gate 	    dlist_free_items(sel_hbas, NULL);
4380Sstevel@tonic-gate 	    dlist_free_items(avail, NULL);
4390Sstevel@tonic-gate 	    return (-1);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	if (avail == NULL || dlist_length(avail) == 0) {
4430Sstevel@tonic-gate 	    /* all slices have been consumed by the devices */
4440Sstevel@tonic-gate 	    volume_set_error(
4450Sstevel@tonic-gate 		    gettext("  no available slices to populate HSP\n"));
4460Sstevel@tonic-gate 	    dlist_free_items(sel_hbas, NULL);
4470Sstevel@tonic-gate 	    dlist_free_items(disks, NULL);
4480Sstevel@tonic-gate 	    return (-1);
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	dlist_free_items(sel_hbas, NULL);
4520Sstevel@tonic-gate 	dlist_free_items(disks, NULL);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/* build list of slices needing to be spared */
4550Sstevel@tonic-gate 	((error = get_uniquely_sized_slices(devices, &unique)) != 0) ||
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	/* and list of slices of sufficient size to spare for them */
4580Sstevel@tonic-gate 	(error = remove_undersized_slices(unique, &avail));
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (error != 0) {
4610Sstevel@tonic-gate 	    dlist_free_items(avail, NULL);
4620Sstevel@tonic-gate 	    dlist_free_items(unique, NULL);
4630Sstevel@tonic-gate 	    dlist_free_items(slices, NULL);
4640Sstevel@tonic-gate 	    return (error);
4650Sstevel@tonic-gate 	}
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	/* get spares currently in the HSP */
4680Sstevel@tonic-gate 	curspares = devconfig_get_components(hsp);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/* clone current spares list */
4710Sstevel@tonic-gate 	for (iter = curspares;
4720Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
4730Sstevel@tonic-gate 	    iter = iter->next) {
4740Sstevel@tonic-gate 	    dlist_t *item = dlist_new_item(iter->obj);
4750Sstevel@tonic-gate 	    if (item == NULL) {
4760Sstevel@tonic-gate 		error = ENOMEM;
4770Sstevel@tonic-gate 	    } else {
4780Sstevel@tonic-gate 		allspares = dlist_append(item, allspares, AT_TAIL);
4790Sstevel@tonic-gate 	    }
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	if (error != 0) {
4830Sstevel@tonic-gate 	    dlist_free_items(avail, NULL);
4840Sstevel@tonic-gate 	    dlist_free_items(unique, NULL);
4850Sstevel@tonic-gate 	    dlist_free_items(slices, NULL);
4860Sstevel@tonic-gate 	    dlist_free_items(allspares, NULL);
4870Sstevel@tonic-gate 	    return (error);
4880Sstevel@tonic-gate 	}
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	/*
4910Sstevel@tonic-gate 	 * examine device component slices and see if the HSP already
4920Sstevel@tonic-gate 	 * has a suitable spare. If not, select the best available
4930Sstevel@tonic-gate 	 * of the same (or larger) size
4940Sstevel@tonic-gate 	 */
4950Sstevel@tonic-gate 	for (iter = devices;
4960Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
4970Sstevel@tonic-gate 	    iter = iter->next) {
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	    devconfig_t *device = (devconfig_t *)iter->obj;
5000Sstevel@tonic-gate 	    dlist_t *components = devconfig_get_components(device);
5010Sstevel@tonic-gate 	    dlist_t *hbas = NULL;
5020Sstevel@tonic-gate 	    dlist_t *disks = NULL;
5030Sstevel@tonic-gate 	    dlist_t *iter1;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	    error = get_hbas_and_disks_used_by_volume(device, &hbas, &disks);
5060Sstevel@tonic-gate 	    for (iter1 = components; (iter1 != NULL) && (error == 0);
5070Sstevel@tonic-gate 		iter1 = iter1->next) {
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 		devconfig_t	*comp = (devconfig_t *)iter1->obj;
5100Sstevel@tonic-gate 		boolean_t	found = B_FALSE;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 		if ((error = find_spare_for_component(
5130Sstevel@tonic-gate 		    comp, allspares, hbas, disks, &found)) == 0) {
5140Sstevel@tonic-gate 		    if (found != B_TRUE) {
5150Sstevel@tonic-gate 			error = choose_spare_for_component(
5160Sstevel@tonic-gate 				comp, &allspares, &newspares,
5170Sstevel@tonic-gate 				&avail, hbas, disks, npaths);
5180Sstevel@tonic-gate 		    }
5190Sstevel@tonic-gate 		}
5200Sstevel@tonic-gate 	    }
5210Sstevel@tonic-gate 	    dlist_free_items(disks, NULL);
5220Sstevel@tonic-gate 	    dlist_free_items(hbas, NULL);
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	if (error == 0) {
5260Sstevel@tonic-gate 	    /* existing spares are no longer needed */
5270Sstevel@tonic-gate 	    dlist_free_items(curspares, free_devconfig_object);
5280Sstevel@tonic-gate 	    curspares = NULL;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	    error = assemble_hsp(hsp, newspares, devices);
5310Sstevel@tonic-gate 	} else {
5320Sstevel@tonic-gate 	    dlist_free_items(newspares, free_devconfig_object);
5330Sstevel@tonic-gate 	    newspares = NULL;
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	dlist_free_items(avail, NULL);
5370Sstevel@tonic-gate 	dlist_free_items(slices, NULL);
5380Sstevel@tonic-gate 	dlist_free_items(unique, NULL);
5390Sstevel@tonic-gate 	dlist_free_items(allspares, NULL);
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	return (error);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate /*
5450Sstevel@tonic-gate  * FUNCTION:	assemble_hsp(devconfig_t *hsp, dlist_t *newspares,
5460Sstevel@tonic-gate  *			dlist_t *devices)
5470Sstevel@tonic-gate  *
5480Sstevel@tonic-gate  * INPUT:	request	- pointer to a HSP devconfig_t
5490Sstevel@tonic-gate  *		newspare - pointer to a list of new spares for the HSP
5500Sstevel@tonic-gate  *		devices - pointer to a list of devices to be served by the HSP
5510Sstevel@tonic-gate  *
5520Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
5530Sstevel@tonic-gate  *			 !0 otherwise.
5540Sstevel@tonic-gate  *
5550Sstevel@tonic-gate  * PURPOSE:	Final assembly of an HSP. Attach new spare components
5560Sstevel@tonic-gate  *		and associate the HSP with each device in the input list.
5570Sstevel@tonic-gate  */
5580Sstevel@tonic-gate static int
assemble_hsp(devconfig_t * hsp,dlist_t * newspares,dlist_t * devices)5590Sstevel@tonic-gate assemble_hsp(
5600Sstevel@tonic-gate 	devconfig_t 	*hsp,
5610Sstevel@tonic-gate 	dlist_t		*newspares,
5620Sstevel@tonic-gate 	dlist_t		*devices)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate 	dlist_t		*iter;
5650Sstevel@tonic-gate 	char		*hspname = NULL;
5660Sstevel@tonic-gate 	int		error = 0;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	/* add new spares to HSP */
5690Sstevel@tonic-gate 	(void) devconfig_set_components(hsp, newspares);
5700Sstevel@tonic-gate 	(void) devconfig_get_name(hsp, &hspname);
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	/* associate HSP with each of the devices */
5730Sstevel@tonic-gate 	for (iter = devices;
5740Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
5750Sstevel@tonic-gate 	    iter = iter->next) {
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	    devconfig_t *dev = iter->obj;
5780Sstevel@tonic-gate 	    devconfig_t *hspcomp = NULL;
5790Sstevel@tonic-gate 	    dlist_t	*item = NULL;
5800Sstevel@tonic-gate 	    char	*devname = NULL;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	    ((error = devconfig_get_name(dev, &devname)) != 0) ||
5830Sstevel@tonic-gate 	    (error = new_devconfig(&hspcomp, TYPE_HSP)) ||
5840Sstevel@tonic-gate 	    (error = devconfig_set_name(hspcomp, hspname));
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	    if (error != 0) {
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		free_devconfig(hspcomp);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	    } else if ((item = dlist_new_item(hspcomp)) == NULL) {
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 		free_devconfig(hspcomp);
5930Sstevel@tonic-gate 		error = ENOMEM;
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	    } else {
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 		dlist_t	*comps = devconfig_get_components(dev);
5980Sstevel@tonic-gate 		comps = dlist_append(comps, item, AT_TAIL);
5990Sstevel@tonic-gate 		(void) devconfig_set_components(dev, comps);
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		oprintf(OUTPUT_VERBOSE,
6020Sstevel@tonic-gate 			gettext("  --->volume %s will use HSP %s\n"),
6030Sstevel@tonic-gate 			devname, hspname);
6040Sstevel@tonic-gate 	    }
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	return (error);
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate /*
6110Sstevel@tonic-gate  * FUNCTION:	get_uniquely_sized_slices(dlist_t *devices,
6120Sstevel@tonic-gate  *			dlist_t **unique)
6130Sstevel@tonic-gate  *
6140Sstevel@tonic-gate  * INPUT:	devices	- pointer to a list of devconfig_t devices
6150Sstevel@tonic-gate  *
6160Sstevel@tonic-gate  * OUTPUT:	unique	- pointer to a list of uniquely size slices
6170Sstevel@tonic-gate  *			from the input list of devices.
6180Sstevel@tonic-gate  *
6190Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
6200Sstevel@tonic-gate  *			 !0 otherwise.
6210Sstevel@tonic-gate  *
6220Sstevel@tonic-gate  * PURPOSE:	Examine each device's slice components and build a list
6230Sstevel@tonic-gate  *		of uniquely sized slices.
6240Sstevel@tonic-gate  */
6250Sstevel@tonic-gate static int
get_uniquely_sized_slices(dlist_t * devices,dlist_t ** unique)6260Sstevel@tonic-gate get_uniquely_sized_slices(
6270Sstevel@tonic-gate 	dlist_t 	*devices,
6280Sstevel@tonic-gate 	dlist_t 	**unique)
6290Sstevel@tonic-gate {
6300Sstevel@tonic-gate 	int		error = 0;
6310Sstevel@tonic-gate 	dlist_t		*iter = NULL;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	for (iter = devices;
6340Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
6350Sstevel@tonic-gate 	    iter = iter->next) {
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	    dlist_t *iter1;
6380Sstevel@tonic-gate 	    for (iter1 = devconfig_get_components((devconfig_t *)iter->obj);
6390Sstevel@tonic-gate 		(iter1 != NULL) && (error == 0);
6400Sstevel@tonic-gate 		iter1 = iter1->next) {
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		devconfig_t *comp = (devconfig_t *)iter1->obj;
6430Sstevel@tonic-gate 		if (dlist_contains(*unique, comp,
6440Sstevel@tonic-gate 		    compare_devconfig_sizes) != B_TRUE) {
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 		    dlist_t *item = NULL;
6470Sstevel@tonic-gate 		    if ((item = dlist_new_item(comp)) == NULL) {
6480Sstevel@tonic-gate 			error = ENOMEM;
6490Sstevel@tonic-gate 		    } else {
6500Sstevel@tonic-gate 			*unique = dlist_insert_ordered(item, *unique,
6510Sstevel@tonic-gate 				ASCENDING, compare_devconfig_sizes);
6520Sstevel@tonic-gate 		    }
6530Sstevel@tonic-gate 		}
6540Sstevel@tonic-gate 	    }
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	return (error);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate /*
6610Sstevel@tonic-gate  * FUNCTION:	remove_undersized_slices(dlist_t *unique,
6620Sstevel@tonic-gate  *			dlist_t **avail)
6630Sstevel@tonic-gate  *
6640Sstevel@tonic-gate  * INPUT:	avail	- pointer to a list of available slices
6650Sstevel@tonic-gate  * 		unique	- pointer to a list of uniquely size slices
6660Sstevel@tonic-gate  *
6670Sstevel@tonic-gate  * OUTPUT:	avail - pointer to an updated list of available slices
6680Sstevel@tonic-gate  *			that are at least as large as slices in the
6690Sstevel@tonic-gate  *			unique list.
6700Sstevel@tonic-gate  *
6710Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
6720Sstevel@tonic-gate  *			 !0 otherwise.
6730Sstevel@tonic-gate  *
6740Sstevel@tonic-gate  * PURPOSE:	filter available slices and remove those that aren't
6750Sstevel@tonic-gate  *		large enough for the device components which need spares.
6760Sstevel@tonic-gate  *
6770Sstevel@tonic-gate  *		For each uniquely sized slice, find all available slices
6780Sstevel@tonic-gate  *		that are larger and add them to the filtered list.
6790Sstevel@tonic-gate  */
6800Sstevel@tonic-gate static int
remove_undersized_slices(dlist_t * unique,dlist_t ** avail)6810Sstevel@tonic-gate remove_undersized_slices(
6820Sstevel@tonic-gate 	dlist_t		*unique,
6830Sstevel@tonic-gate 	dlist_t		**avail)
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate 	dlist_t		*filtered = NULL;
6860Sstevel@tonic-gate 	dlist_t		*iter = NULL;
6870Sstevel@tonic-gate 	int		error = 0;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	for (iter = unique;
6900Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
6910Sstevel@tonic-gate 	    iter = iter->next) {
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	    devconfig_t	*uslice = (devconfig_t *)iter->obj;
6940Sstevel@tonic-gate 	    uint64_t	usize = 0;
6950Sstevel@tonic-gate 	    dlist_t	*iter2 = NULL;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	    error = devconfig_get_size(uslice, &usize);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	    for (iter2 = *avail;
7000Sstevel@tonic-gate 		(iter2 != NULL) && (error == 0);
7010Sstevel@tonic-gate 		iter2 = iter2->next) {
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		dm_descriptor_t	aslice = (uintptr_t)iter2->obj;
7040Sstevel@tonic-gate 		uint64_t	asize = 0;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		error = slice_get_size(aslice, &asize);
7070Sstevel@tonic-gate 		if (asize >= usize) {
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 		    /* this slice is large enough */
7100Sstevel@tonic-gate 		    dlist_t *item = NULL;
711*62Sjeanm 		    if ((item = dlist_new_item((void *)(uintptr_t)aslice)) ==
712*62Sjeanm 			NULL) {
7130Sstevel@tonic-gate 			error = ENOMEM;
7140Sstevel@tonic-gate 		    } else {
7150Sstevel@tonic-gate 			filtered = dlist_insert_ordered(item, filtered,
7160Sstevel@tonic-gate 				ASCENDING, compare_slice_sizes);
7170Sstevel@tonic-gate 		    }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 		}
7200Sstevel@tonic-gate 	    }
7210Sstevel@tonic-gate 	}
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (error == 0) {
7240Sstevel@tonic-gate 	    dlist_free_items(*avail, NULL);
7250Sstevel@tonic-gate 	    *avail = filtered;
7260Sstevel@tonic-gate 	} else {
7270Sstevel@tonic-gate 	    dlist_free_items(filtered, NULL);
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	return (error);
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate /*
7340Sstevel@tonic-gate  * FUNCTION:	find_spare_for_component(devconfig_t *component,
7350Sstevel@tonic-gate  *			dlist_t *all_spares, dlist_t *hbas, dlist_t *disks,
7360Sstevel@tonic-gate  *			boolean_t *found)
7370Sstevel@tonic-gate  *
7380Sstevel@tonic-gate  * INPUT:	comp	- pointer to a devconfig_t slice compenent that
7390Sstevel@tonic-gate  *				needs to be spared
7400Sstevel@tonic-gate  * 		all_spares - pointer to a list of spares currently
7410Sstevel@tonic-gate  *				in the pool or that will be added
7420Sstevel@tonic-gate  * 		hbas	- pointer to a list of HBAs the component's
7430Sstevel@tonic-gate  *				parent device utilizes
7440Sstevel@tonic-gate  * 		disks	- pointer to a list of disks the component's
7450Sstevel@tonic-gate  *				parent device utilizes
7460Sstevel@tonic-gate  *
7470Sstevel@tonic-gate  * OUTPUT:	found - pointer to a boolean_t to hold the result.
7480Sstevel@tonic-gate  *
7490Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
7500Sstevel@tonic-gate  *			 !0 otherwise.
7510Sstevel@tonic-gate  *
7520Sstevel@tonic-gate  * PURPOSE:	Find a spare for the input component.
7530Sstevel@tonic-gate  *
7540Sstevel@tonic-gate  *		Searches the input list of spares to see if one is
7550Sstevel@tonic-gate  *		sufficient.
7560Sstevel@tonic-gate  *
7570Sstevel@tonic-gate  *		A suffcient spare is one that is large enough to spare
7580Sstevel@tonic-gate  *		for the input component and not on the same disk as any
7590Sstevel@tonic-gate  *		of the components in the parent device.
7600Sstevel@tonic-gate  *
7610Sstevel@tonic-gate  *		The optimal spare would be on a different controller/HBA
7620Sstevel@tonic-gate  *		as the component and any of the components in the parent
7630Sstevel@tonic-gate  *		device.  We settle for sufficient.
7640Sstevel@tonic-gate  */
7650Sstevel@tonic-gate static int
find_spare_for_component(devconfig_t * component,dlist_t * all_spares,dlist_t * hbas,dlist_t * disks,boolean_t * found)7660Sstevel@tonic-gate find_spare_for_component(
7670Sstevel@tonic-gate 	devconfig_t	*component,
7680Sstevel@tonic-gate 	dlist_t		*all_spares,
7690Sstevel@tonic-gate 	dlist_t		*hbas,
7700Sstevel@tonic-gate 	dlist_t		*disks,
7710Sstevel@tonic-gate 	boolean_t	*found)
7720Sstevel@tonic-gate {
7730Sstevel@tonic-gate 	dlist_t		*iter = NULL;
7740Sstevel@tonic-gate 	uint64_t	csize = 0;
7750Sstevel@tonic-gate 	int		error = 0;
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	*found = B_FALSE;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	(void) devconfig_get_size(component, &csize);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	for (iter = all_spares;
7820Sstevel@tonic-gate 	    (iter != NULL) && (*found == B_FALSE) && (error == 0);
7830Sstevel@tonic-gate 	    iter = iter->next) {
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	    devconfig_t		*spare = (devconfig_t *)iter->obj;
7860Sstevel@tonic-gate 	    char 		*spname = NULL;
7870Sstevel@tonic-gate 	    uint64_t 		spsize = 0;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	    if (((error = devconfig_get_name(spare, &spname)) != 0) ||
7900Sstevel@tonic-gate 		((error = devconfig_get_size(spare, &spsize)) != 0)) {
7910Sstevel@tonic-gate 		continue;
7920Sstevel@tonic-gate 	    }
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	    if (spsize >= csize) {
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		dm_descriptor_t	disk = NULL;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 		/* see if spare's disk is independent of the volume */
7990Sstevel@tonic-gate 		error = get_disk_for_named_slice(spname, &disk);
800*62Sjeanm 		if ((error == 0) && (dlist_contains(disks,
801*62Sjeanm 		    (void *)(uintptr_t)disk, compare_descriptor_names) ==
802*62Sjeanm 		    B_FALSE)) {
8030Sstevel@tonic-gate 		    *found = B_TRUE;
8040Sstevel@tonic-gate 		}
8050Sstevel@tonic-gate 	    }
8060Sstevel@tonic-gate 	}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	if ((*found == B_TRUE) && (get_max_verbosity() >= OUTPUT_DEBUG)) {
8090Sstevel@tonic-gate 	    char *cname = NULL;
8100Sstevel@tonic-gate 	    (void) devconfig_get_name(component, &cname);
8110Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
8120Sstevel@tonic-gate 		    gettext("    found existing spare for: %s (%llu)\n"),
8130Sstevel@tonic-gate 		    cname, csize);
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	return (error);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate /*
8200Sstevel@tonic-gate  * FUNCTION:	choose_spare_for_component(devconfig_t *component,
8210Sstevel@tonic-gate  *			dlist_t *all_spares, dlist_t **new_spares,
8220Sstevel@tonic-gate  *			dlist_t avail, uint16_t npaths, dlist_t *used_hbas,
8230Sstevel@tonic-gate  *			dlist_t *used_disks)
8240Sstevel@tonic-gate  *
8250Sstevel@tonic-gate  * INPUT:	comp	- pointer to a devconfig_t slice compenent that
8260Sstevel@tonic-gate  *				needs to be spared
8270Sstevel@tonic-gate  * 		all_spares - pointer to a list of spares currently
8280Sstevel@tonic-gate  *				in the pool and those to be added
8290Sstevel@tonic-gate  * 		new_spares - pointer to a list of spares that need to
8300Sstevel@tonic-gate  *				be added to the pool
8310Sstevel@tonic-gate  *		avail	- list of available slices
8320Sstevel@tonic-gate  *		npaths	- required number of paths for the spare
8330Sstevel@tonic-gate  *		used_hbas - list of HBAs used by the component's parent
8340Sstevel@tonic-gate  *		used_disks - list of disks used by the component's parent
8350Sstevel@tonic-gate  *
8360Sstevel@tonic-gate  * OUTPUT:	all_spares - the possibly updated list of all spares
8370Sstevel@tonic-gate  *		new_spares - the possibly updated list of spares which
8380Sstevel@tonic-gate  *			need to be added to the pool.
8390Sstevel@tonic-gate  *
8400Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
8410Sstevel@tonic-gate  *			 !0 otherwise.
8420Sstevel@tonic-gate  *
8430Sstevel@tonic-gate  * PURPOSE:	Find a new spare for the input component.
8440Sstevel@tonic-gate  *
8450Sstevel@tonic-gate  *		Select a spare from the available slice list and add
8460Sstevel@tonic-gate  *		it to the new_spares list.
8470Sstevel@tonic-gate  *
8480Sstevel@tonic-gate  *		The spare slice chosen should be on a unique HBA and
8490Sstevel@tonic-gate  *		disk relative to the input lists of used HBAs and disks
8500Sstevel@tonic-gate  *		and any spares in the pool.
8510Sstevel@tonic-gate  */
8520Sstevel@tonic-gate static int
choose_spare_for_component(devconfig_t * component,dlist_t ** all_spares,dlist_t ** new_spares,dlist_t ** avail,dlist_t * used_hbas,dlist_t * used_disks,uint16_t npaths)8530Sstevel@tonic-gate choose_spare_for_component(
8540Sstevel@tonic-gate 	devconfig_t	*component,
8550Sstevel@tonic-gate 	dlist_t		**all_spares,
8560Sstevel@tonic-gate 	dlist_t		**new_spares,
8570Sstevel@tonic-gate 	dlist_t		**avail,
8580Sstevel@tonic-gate 	dlist_t		*used_hbas,
8590Sstevel@tonic-gate 	dlist_t		*used_disks,
8600Sstevel@tonic-gate 	uint16_t	npaths)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	devconfig_t	*spare = NULL;
8630Sstevel@tonic-gate 	uint64_t	csize = 0;
8640Sstevel@tonic-gate 	int		error = 0;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	(void) devconfig_get_size(component, &csize);
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	if (get_max_verbosity() >= OUTPUT_DEBUG) {
8690Sstevel@tonic-gate 	    char *cname = NULL;
8700Sstevel@tonic-gate 	    (void) devconfig_get_name(component, &cname);
8710Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
8720Sstevel@tonic-gate 		    gettext("    select new spare for: %s (%llu)\n"),
8730Sstevel@tonic-gate 		    cname, csize);
8740Sstevel@tonic-gate 	}
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	/*
8770Sstevel@tonic-gate 	 * find a spare for the input component.
8780Sstevel@tonic-gate 	 * select the best one from the available list that
8790Sstevel@tonic-gate 	 * is on a unique disk.
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	/*
8830Sstevel@tonic-gate 	 * 1st B_TRUE: require a different disk than those used by
8840Sstevel@tonic-gate 	 *		all spares and devices
8850Sstevel@tonic-gate 	 * 2nd B_TRUE: requested size is the minimum acceptable
8860Sstevel@tonic-gate 	 * 1st B_FALSE: do not add an extra cylinder when resizing slice,
8870Sstevel@tonic-gate 	 *		this is only necessary for Stripe components whose
8880Sstevel@tonic-gate 	 *		sizes get rounded down to an interlace multiple and
8890Sstevel@tonic-gate 	 *		then down to a cylinder boundary.
8900Sstevel@tonic-gate 	 */
8910Sstevel@tonic-gate 	error = choose_slice(csize, npaths, *avail, *all_spares,
8920Sstevel@tonic-gate 		used_hbas, used_disks, B_TRUE, B_TRUE, B_FALSE, &spare);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	if ((error == 0) && (spare == NULL)) {
8950Sstevel@tonic-gate 	    /* can't find one on a unique disk, try again on any disk */
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	    /* BEGIN CSTYLED */
8980Sstevel@tonic-gate 	    /*
8990Sstevel@tonic-gate 	     * 1st B_FALSE: don't require a different disk than those used
9000Sstevel@tonic-gate 	     *		by all spares and devices
9010Sstevel@tonic-gate 	     * 2nd B_TRUE: requested size is still the minimum acceptable
9020Sstevel@tonic-gate 	     * 2nd B_FALSE: do not add an extra cylinder when resizing slice
9030Sstevel@tonic-gate 	     *		this is only necessary for Stripe components whose
9040Sstevel@tonic-gate 	     *		sizes get rounded down to an interlace multiple and
9050Sstevel@tonic-gate 	     *		then down to a cylinder boundary.
9060Sstevel@tonic-gate 	     */
9070Sstevel@tonic-gate 	    /* END CSTYLED */
9080Sstevel@tonic-gate 	    error = choose_slice(
9090Sstevel@tonic-gate 		    csize, npaths, *avail, *all_spares, used_hbas,
9100Sstevel@tonic-gate 		    used_disks, B_FALSE, B_TRUE, B_FALSE, &spare);
9110Sstevel@tonic-gate 	}
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	if ((error == 0) && (spare != NULL)) {
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	    dlist_t	*rmvd = NULL;
9160Sstevel@tonic-gate 	    dlist_t	*item = NULL;
9170Sstevel@tonic-gate 	    char	*spname = NULL;
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	    if ((item = dlist_new_item(spare)) == NULL) {
9200Sstevel@tonic-gate 		error = ENOMEM;
9210Sstevel@tonic-gate 	    } else {
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 		/* add spare to the all spares list */
9240Sstevel@tonic-gate 		*all_spares = dlist_append(item, *all_spares, AT_HEAD);
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 		if ((item = dlist_new_item(spare)) == NULL) {
9270Sstevel@tonic-gate 		    error = ENOMEM;
9280Sstevel@tonic-gate 		} else {
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 		    /* add spare to the new spares list */
9310Sstevel@tonic-gate 		    *new_spares = dlist_insert_ordered(
9320Sstevel@tonic-gate 			    item, *new_spares, ASCENDING,
9330Sstevel@tonic-gate 			    compare_devconfig_sizes);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 		    /* remove it from the available list */
9360Sstevel@tonic-gate 		    *avail = dlist_remove_equivalent_item(*avail, spare,
9370Sstevel@tonic-gate 			    compare_devconfig_and_descriptor_names,
9380Sstevel@tonic-gate 			    &rmvd);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		    if (rmvd != NULL) {
9410Sstevel@tonic-gate 			free(rmvd);
9420Sstevel@tonic-gate 		    }
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 		    /* add the spare to the used slice list */
9450Sstevel@tonic-gate 		    error = devconfig_get_name(spare, &spname);
9460Sstevel@tonic-gate 		    if (error == 0) {
9470Sstevel@tonic-gate 			error = add_used_slice_by_name(spname);
9480Sstevel@tonic-gate 		    }
9490Sstevel@tonic-gate 		}
9500Sstevel@tonic-gate 	    }
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	} else {
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	    /* no spare, give up on layout */
9550Sstevel@tonic-gate 	    oprintf(OUTPUT_TERSE,
9560Sstevel@tonic-gate 		    gettext("  <---Failed: insufficient suitable spares\n"));
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	    volume_set_error(
9590Sstevel@tonic-gate 		    gettext("failed to find sufficient spares for HSP\n"));
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	    error = -1;
9620Sstevel@tonic-gate 	}
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	return (error);
9650Sstevel@tonic-gate }
966