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