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