xref: /onnv-gate/usr/src/cmd/lvm/metassist/layout/layout_slice.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/param.h>
30*0Sstevel@tonic-gate #include <meta.h>
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include "volume_string.h"
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include "volume_devconfig.h"
35*0Sstevel@tonic-gate #include "volume_error.h"
36*0Sstevel@tonic-gate #include "volume_dlist.h"
37*0Sstevel@tonic-gate #include "volume_output.h"
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #include "layout_device_cache.h"
40*0Sstevel@tonic-gate #include "layout_device_util.h"
41*0Sstevel@tonic-gate #include "layout_discovery.h"
42*0Sstevel@tonic-gate #include "layout_dlist_util.h"
43*0Sstevel@tonic-gate #include "layout_messages.h"
44*0Sstevel@tonic-gate #include "layout_request.h"
45*0Sstevel@tonic-gate #include "layout_slice.h"
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate #define	_LAYOUT_SLICE_C
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate static int pick_from_best_hba_and_disk(
50*0Sstevel@tonic-gate 	dlist_t   	*list,
51*0Sstevel@tonic-gate 	dlist_t   	*used,
52*0Sstevel@tonic-gate 	dm_descriptor_t *chosen);
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate static int slice_has_same_disk_geom(
55*0Sstevel@tonic-gate 	dm_descriptor_t slice,
56*0Sstevel@tonic-gate 	dlist_t		*used,
57*0Sstevel@tonic-gate 	boolean_t	*bool);
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate static int slice_on_unique_disk(
60*0Sstevel@tonic-gate 	dm_descriptor_t slice,
61*0Sstevel@tonic-gate 	dlist_t		*used,
62*0Sstevel@tonic-gate 	dlist_t		*othervols,
63*0Sstevel@tonic-gate 	boolean_t	*bool);
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate static int slice_on_unique_hba(
66*0Sstevel@tonic-gate 	dm_descriptor_t slice,
67*0Sstevel@tonic-gate 	dlist_t		*used,
68*0Sstevel@tonic-gate 	dlist_t		*othervols,
69*0Sstevel@tonic-gate 	boolean_t	*bool);
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate static int slice_on_similar_bus(
72*0Sstevel@tonic-gate 	dm_descriptor_t slice,
73*0Sstevel@tonic-gate 	dlist_t		*used,
74*0Sstevel@tonic-gate 	boolean_t	*bool);
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate static int slice_has_n_paths(
77*0Sstevel@tonic-gate 	dm_descriptor_t	slice,
78*0Sstevel@tonic-gate 	uint16_t	npaths,
79*0Sstevel@tonic-gate 	boolean_t	*bool);
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static int compare_modslice_names(
82*0Sstevel@tonic-gate 	void 		*obj1,
83*0Sstevel@tonic-gate 	void		*obj2);
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate static int compare_string_to_modslice_name(
86*0Sstevel@tonic-gate 	void		*str,
87*0Sstevel@tonic-gate 	void		*modslice);
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate static int create_new_slice(
90*0Sstevel@tonic-gate 	dm_descriptor_t oslice,
91*0Sstevel@tonic-gate 	uint64_t	nbytes,
92*0Sstevel@tonic-gate 	boolean_t	add_extra_cyl,
93*0Sstevel@tonic-gate 	devconfig_t	**nslice);
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate static int create_modified_slice(
96*0Sstevel@tonic-gate 	dm_descriptor_t	oslice,
97*0Sstevel@tonic-gate 	char		*oname,
98*0Sstevel@tonic-gate 	uint32_t	oindex,
99*0Sstevel@tonic-gate 	uint64_t	ostart,
100*0Sstevel@tonic-gate 	uint64_t	osize,
101*0Sstevel@tonic-gate 	uint64_t	bps,
102*0Sstevel@tonic-gate 	char		*nname,
103*0Sstevel@tonic-gate 	uint32_t	nindex,
104*0Sstevel@tonic-gate 	uint64_t	nsize,
105*0Sstevel@tonic-gate 	devconfig_t	**nslice);
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate  * list to track resized slices
109*0Sstevel@tonic-gate  */
110*0Sstevel@tonic-gate static  dlist_t	*_modified_slices = NULL;
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate /*
113*0Sstevel@tonic-gate  * struct to track used slices and their disks...
114*0Sstevel@tonic-gate  */
115*0Sstevel@tonic-gate typedef struct {
116*0Sstevel@tonic-gate 	char		*slicename;
117*0Sstevel@tonic-gate 	dm_descriptor_t	disk;
118*0Sstevel@tonic-gate } usedslice_t;
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate /*
121*0Sstevel@tonic-gate  * list to of usedslice_t to track slices that have been
122*0Sstevel@tonic-gate  * used for any reason.
123*0Sstevel@tonic-gate  */
124*0Sstevel@tonic-gate static dlist_t	*_used_slices = NULL;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate static int add_used_slice_list_entry(char *slicename, dm_descriptor_t disk);
127*0Sstevel@tonic-gate static int compare_usedslice_name_to_string(void *obj1, void *obj2);
128*0Sstevel@tonic-gate static void free_used_slice(void *obj);
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate /*
131*0Sstevel@tonic-gate  * list of slices reserved to be used for explicit
132*0Sstevel@tonic-gate  * volume requests
133*0Sstevel@tonic-gate  */
134*0Sstevel@tonic-gate static dlist_t *_rsvd_slices = NULL;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate /*
137*0Sstevel@tonic-gate  * list of slices needing to be removed (zeroed out) prior to
138*0Sstevel@tonic-gate  * applying any metassist modifications to the system.
139*0Sstevel@tonic-gate  */
140*0Sstevel@tonic-gate static dlist_t *_rmvd_slices = NULL;
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate /*
143*0Sstevel@tonic-gate  * FUNCTION:	choose_slice(
144*0Sstevel@tonic-gate  *		uint64_t	nbytes,
145*0Sstevel@tonic-gate  *		uint16_t	npaths,
146*0Sstevel@tonic-gate  *		dlist_t		*slices,
147*0Sstevel@tonic-gate  *		dlist_t		*used,
148*0Sstevel@tonic-gate  *		dlist_t		*used_hbas,
149*0Sstevel@tonic-gate  *		dlist_t		*used_disks,
150*0Sstevel@tonic-gate  *		boolean_t	unused_disk,
151*0Sstevel@tonic-gate  *		boolean_t	nbytes_is_min,
152*0Sstevel@tonic-gate  *		boolean_t	add_extra_cyl,
153*0Sstevel@tonic-gate  *		devconfig_t	**chosen)
154*0Sstevel@tonic-gate  *
155*0Sstevel@tonic-gate  * INPUT:	nbytes -	required size
156*0Sstevel@tonic-gate  *		npaths -	minimum required data paths
157*0Sstevel@tonic-gate  *		*slices -	slices from which to choose
158*0Sstevel@tonic-gate  *		*used -		slices used by the volume under construction
159*0Sstevel@tonic-gate  *		*used_hbas -	hbas used by other volumes relevant to
160*0Sstevel@tonic-gate  *					the volume under construction
161*0Sstevel@tonic-gate  *		*used_disks -	disks used by other volumes relevant to
162*0Sstevel@tonic-gate  *					the volume under construction
163*0Sstevel@tonic-gate  *		unused_disk -	if true, the chosen slice must be from an
164*0Sstevel@tonic-gate  *					unused disk
165*0Sstevel@tonic-gate  *		nbytes_is_min -	if true, the chosen slice may be larger than
166*0Sstevel@tonic-gate  *					nbytes.
167*0Sstevel@tonic-gate  *		add_extra_cyl -	passed to create_new_slice, see comment there.
168*0Sstevel@tonic-gate  *		**chosen -	pointer to hold the chosen slice
169*0Sstevel@tonic-gate  *
170*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
171*0Sstevel@tonic-gate  *			 !0 otherwise
172*0Sstevel@tonic-gate  *
173*0Sstevel@tonic-gate  * PURPOSE:	Choosen a slice from the list of those available.
174*0Sstevel@tonic-gate  *
175*0Sstevel@tonic-gate  *		Of those available, choose in order of preference:
176*0Sstevel@tonic-gate  *
177*0Sstevel@tonic-gate  *		- one on a unique HBA and disk that is of the exact size
178*0Sstevel@tonic-gate  *		- one on a unique HBA and disk that is of sufficient size
179*0Sstevel@tonic-gate  *		- one on unique HBA that is of the exact size
180*0Sstevel@tonic-gate  *		- one on unique HBA that is of sufficient size
181*0Sstevel@tonic-gate  *		- one on unique disk that is of the exact size
182*0Sstevel@tonic-gate  *		- one on unique disk that is of sufficient size
183*0Sstevel@tonic-gate  *		- one on any HBA that is of exact size
184*0Sstevel@tonic-gate  *		- one on any HBA that is of sufficient size
185*0Sstevel@tonic-gate  *		- one on a unique HBA that is the largest size
186*0Sstevel@tonic-gate  *		- one on a unique disk that is the largest size
187*0Sstevel@tonic-gate  *		- one on any HBA that is the largest size
188*0Sstevel@tonic-gate  *
189*0Sstevel@tonic-gate  *		The function scans the available slices and builds lists of
190*0Sstevel@tonic-gate  *		those meeting the criteria above.  After the scan is complete,
191*0Sstevel@tonic-gate  *		the lists are examined in order, the first non-empty list is
192*0Sstevel@tonic-gate  *		chosen.  If there are several possibilities in the chosen list,
193*0Sstevel@tonic-gate  *		see if it is possible select the slice from the least used HBA
194*0Sstevel@tonic-gate  *		and/or disk.
195*0Sstevel@tonic-gate  *
196*0Sstevel@tonic-gate  *		If nbytes_is_min is true, the returned slice will be
197*0Sstevel@tonic-gate  *		at least nbytes in capacity.
198*0Sstevel@tonic-gate  *
199*0Sstevel@tonic-gate  *		If unused_disk is true, the returned slice will be from
200*0Sstevel@tonic-gate  *		a disk with no other known uses.
201*0Sstevel@tonic-gate  */
202*0Sstevel@tonic-gate int
203*0Sstevel@tonic-gate choose_slice(
204*0Sstevel@tonic-gate 	uint64_t	nbytes,
205*0Sstevel@tonic-gate 	uint16_t	npaths,
206*0Sstevel@tonic-gate 	dlist_t		*slices,
207*0Sstevel@tonic-gate 	dlist_t		*used,
208*0Sstevel@tonic-gate 	dlist_t		*used_hbas,
209*0Sstevel@tonic-gate 	dlist_t		*used_disks,
210*0Sstevel@tonic-gate 	boolean_t	unused_disk,
211*0Sstevel@tonic-gate 	boolean_t	nbytes_is_min,
212*0Sstevel@tonic-gate 	boolean_t	add_extra_cyl,
213*0Sstevel@tonic-gate 	devconfig_t	**chosen)
214*0Sstevel@tonic-gate {
215*0Sstevel@tonic-gate 	dlist_t		*iter	= NULL;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	dm_descriptor_t	slice	= NULL;
218*0Sstevel@tonic-gate 	boolean_t	resize  = B_FALSE;
219*0Sstevel@tonic-gate 	boolean_t	verbose = (get_max_verbosity() == OUTPUT_VERBOSE);
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	int		error	= 0;
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	/*
224*0Sstevel@tonic-gate 	 * indexes into the list array:
225*0Sstevel@tonic-gate 	 * i -> unique controller	0 = yes, 1 = no
226*0Sstevel@tonic-gate 	 * j -> same bus type		0 = yes, 1 = no
227*0Sstevel@tonic-gate 	 * k -> unique disk		0 = yes, 1 = no
228*0Sstevel@tonic-gate 	 * l -> same disk geom		0 = yes, 1 = no
229*0Sstevel@tonic-gate 	 * m -> size			0 == exact, 1 = larger, 2 = any
230*0Sstevel@tonic-gate 	 */
231*0Sstevel@tonic-gate 	int		i, j, k, l, m;
232*0Sstevel@tonic-gate 	dlist_t		*list[2][2][2][2][3];
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	/* output string arrays for each array dimension and index */
235*0Sstevel@tonic-gate 	char	*uniqhba[2];
236*0Sstevel@tonic-gate 	char	*samebus[2];
237*0Sstevel@tonic-gate 	char	*uniqdisk[2];
238*0Sstevel@tonic-gate 	char	*samegeom[2];
239*0Sstevel@tonic-gate 	char	*sizes[3];
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	/* other output strings */
242*0Sstevel@tonic-gate 	char	*look_msg = NULL;
243*0Sstevel@tonic-gate 	char	*npaths_msg = NULL;
244*0Sstevel@tonic-gate 	char	*samegeom_msg = NULL;
245*0Sstevel@tonic-gate 	char	*samebus_msg = NULL;
246*0Sstevel@tonic-gate 	char	*uniqhba_msg = NULL;
247*0Sstevel@tonic-gate 	char	*uniqdisk_msg = NULL;
248*0Sstevel@tonic-gate 	char	*exact_msg = NULL;
249*0Sstevel@tonic-gate 	char	*larger_msg = NULL;
250*0Sstevel@tonic-gate 	char	*smaller_msg = NULL;
251*0Sstevel@tonic-gate 	char	*insuff_paths = NULL;
252*0Sstevel@tonic-gate 	char	*too_small = NULL;
253*0Sstevel@tonic-gate 	char	*useddisk_msg = NULL;
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	if (verbose == B_TRUE) {
256*0Sstevel@tonic-gate 	    /* only initialize the output strings if needed */
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	    /* BEGIN CSTYLED */
259*0Sstevel@tonic-gate 	    look_msg = gettext(
260*0Sstevel@tonic-gate 		    "\tlooking at slice: %s (%s)\n");
261*0Sstevel@tonic-gate 	    npaths_msg = gettext(
262*0Sstevel@tonic-gate 		    "\t    has the requested number of data paths (%d)\n");
263*0Sstevel@tonic-gate 	    samegeom_msg = gettext(
264*0Sstevel@tonic-gate 		    "\t    has the same disk geometry relative to used slices\n");
265*0Sstevel@tonic-gate 	    samebus_msg = gettext(
266*0Sstevel@tonic-gate 		    "\t    on a similar I/O bus/HBA relative to used slices\n");
267*0Sstevel@tonic-gate 	    uniqhba_msg = gettext(
268*0Sstevel@tonic-gate 		    "\t    on a unique HBA relative to used slices\n");
269*0Sstevel@tonic-gate 	    uniqdisk_msg = gettext(
270*0Sstevel@tonic-gate 		    "\t    on a unique disk relative to used slices\n");
271*0Sstevel@tonic-gate 	    exact_msg = gettext(
272*0Sstevel@tonic-gate 		    "\t    the exact size necessary\n");
273*0Sstevel@tonic-gate 	    larger_msg = gettext(
274*0Sstevel@tonic-gate 		    "\t    larger than necessary\n");
275*0Sstevel@tonic-gate 	    smaller_msg = gettext(
276*0Sstevel@tonic-gate 		    "\t    smaller than necessary\n");
277*0Sstevel@tonic-gate 	    insuff_paths = gettext(
278*0Sstevel@tonic-gate 		    "\t    rejected: not enough paths (%d requested)\n");
279*0Sstevel@tonic-gate 	    too_small = gettext(
280*0Sstevel@tonic-gate 		    "\t    rejected: too small\n");
281*0Sstevel@tonic-gate 	    useddisk_msg = gettext(
282*0Sstevel@tonic-gate 		    "\t    rejected: on a disk with other volume component(s)\n");
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	    uniqhba[0] = gettext("unique HBA");
285*0Sstevel@tonic-gate 	    uniqhba[1] = gettext("non unique HBA");
286*0Sstevel@tonic-gate 	    samebus[0] = gettext("same bus type");
287*0Sstevel@tonic-gate 	    samebus[1] = gettext("different bus type");
288*0Sstevel@tonic-gate 	    uniqdisk[0] = gettext("unique disk");
289*0Sstevel@tonic-gate 	    uniqdisk[1] = gettext("non unique disk");
290*0Sstevel@tonic-gate 	    samegeom[0] = gettext("same geometry");
291*0Sstevel@tonic-gate 	    samegeom[1] = gettext("different geometry");
292*0Sstevel@tonic-gate 	    sizes[0] = gettext("an exact size slice");
293*0Sstevel@tonic-gate 	    sizes[1] = gettext("a larger slice");
294*0Sstevel@tonic-gate 	    sizes[2] = gettext("a smaller slice");
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	    /* END CSTYLED */
297*0Sstevel@tonic-gate 	}
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	/* init list array pointers */
300*0Sstevel@tonic-gate 	(void) memset(list, 0,  2*2*2*2*3 * sizeof (dlist_t *));
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	for (iter = slices;
303*0Sstevel@tonic-gate 	    (iter != NULL) && (error == 0); iter = iter->next) {
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	    dm_descriptor_t	slice = (uintptr_t)iter->obj;
306*0Sstevel@tonic-gate 	    uint64_t		snbytes = 0;
307*0Sstevel@tonic-gate 	    boolean_t		uniqdisk = B_FALSE;
308*0Sstevel@tonic-gate 	    boolean_t		uniqhba = B_FALSE;
309*0Sstevel@tonic-gate 	    boolean_t		samegeom = B_FALSE;
310*0Sstevel@tonic-gate 	    boolean_t		samebus = B_FALSE;
311*0Sstevel@tonic-gate 	    boolean_t		paths = B_FALSE;
312*0Sstevel@tonic-gate 	    dlist_t		*item = NULL;
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	    ((error = slice_get_size(slice, &snbytes)) != 0) ||
315*0Sstevel@tonic-gate 	    (error = slice_has_n_paths(slice, npaths, &paths)) ||
316*0Sstevel@tonic-gate 	    (error = slice_on_unique_hba(slice, used, used_hbas, &uniqhba)) ||
317*0Sstevel@tonic-gate 	    (error = slice_on_unique_disk(slice, used, used_disks,
318*0Sstevel@tonic-gate 		    &uniqdisk)) ||
319*0Sstevel@tonic-gate 	    (error = slice_on_similar_bus(slice, used, &samebus)) ||
320*0Sstevel@tonic-gate 	    (error = slice_has_same_disk_geom(slice, used, &samegeom));
321*0Sstevel@tonic-gate 	    if (error != 0) {
322*0Sstevel@tonic-gate 		continue;
323*0Sstevel@tonic-gate 	    }
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	    if (verbose == B_TRUE) {
326*0Sstevel@tonic-gate 		char *sname = NULL;
327*0Sstevel@tonic-gate 		char *sizestr = NULL;
328*0Sstevel@tonic-gate 		(void) get_display_name(slice, &sname);
329*0Sstevel@tonic-gate 		if (bytes_to_sizestr(snbytes, &sizestr,
330*0Sstevel@tonic-gate 			    universal_units, B_FALSE) == 0) {
331*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, look_msg, sname, sizestr);
332*0Sstevel@tonic-gate 		    free(sizestr);
333*0Sstevel@tonic-gate 		}
334*0Sstevel@tonic-gate 	    }
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	    if (npaths > 1) {
337*0Sstevel@tonic-gate 		if (paths && verbose) {
338*0Sstevel@tonic-gate 		    /* specifically asked for more paths, ... */
339*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, npaths_msg);
340*0Sstevel@tonic-gate 		}
341*0Sstevel@tonic-gate 	    } else if (npaths == 1) {
342*0Sstevel@tonic-gate 		/* every disk has at least 1 path */
343*0Sstevel@tonic-gate 		paths = B_TRUE;
344*0Sstevel@tonic-gate 	    }
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	    if (verbose == B_TRUE) {
347*0Sstevel@tonic-gate 		if (uniqhba) {
348*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, uniqhba_msg);
349*0Sstevel@tonic-gate 		}
350*0Sstevel@tonic-gate 		if (uniqdisk) {
351*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, uniqdisk_msg);
352*0Sstevel@tonic-gate 		}
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 		if (used != NULL) {
355*0Sstevel@tonic-gate 		    if (samebus) {
356*0Sstevel@tonic-gate 			oprintf(OUTPUT_VERBOSE, samebus_msg);
357*0Sstevel@tonic-gate 		    }
358*0Sstevel@tonic-gate 		    if (samegeom) {
359*0Sstevel@tonic-gate 			oprintf(OUTPUT_VERBOSE, samegeom_msg);
360*0Sstevel@tonic-gate 		    }
361*0Sstevel@tonic-gate 		}
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 		if (snbytes > nbytes) {
364*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, larger_msg);
365*0Sstevel@tonic-gate 		} else if (snbytes == nbytes) {
366*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, exact_msg);
367*0Sstevel@tonic-gate 		} else {
368*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, smaller_msg);
369*0Sstevel@tonic-gate 		}
370*0Sstevel@tonic-gate 	    }
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	    /* filter slices not meeting minimum criteria */
373*0Sstevel@tonic-gate 	    if (nbytes_is_min && (snbytes < nbytes)) {
374*0Sstevel@tonic-gate 		/* not large enough */
375*0Sstevel@tonic-gate 		if (verbose == B_TRUE) {
376*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, too_small);
377*0Sstevel@tonic-gate 		}
378*0Sstevel@tonic-gate 		continue;
379*0Sstevel@tonic-gate 	    }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	    if (paths == B_FALSE) {
382*0Sstevel@tonic-gate 		/* not connected thru enough paths */
383*0Sstevel@tonic-gate 		if (verbose == B_TRUE) {
384*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, insuff_paths, npaths);
385*0Sstevel@tonic-gate 		}
386*0Sstevel@tonic-gate 		continue;
387*0Sstevel@tonic-gate 	    }
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	    if (uniqdisk != B_TRUE && unused_disk == TRUE) {
390*0Sstevel@tonic-gate 		/* not on a unique disk */
391*0Sstevel@tonic-gate 		if (verbose == B_TRUE) {
392*0Sstevel@tonic-gate 		    oprintf(OUTPUT_VERBOSE, useddisk_msg);
393*0Sstevel@tonic-gate 		}
394*0Sstevel@tonic-gate 		continue;
395*0Sstevel@tonic-gate 	    }
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	    /* map slice properties into array indices */
398*0Sstevel@tonic-gate 	    i = (uniqhba ? 0 : 1);
399*0Sstevel@tonic-gate 	    j = (samebus ? 0 : 1);
400*0Sstevel@tonic-gate 	    k = (uniqdisk ? 0 : 1);
401*0Sstevel@tonic-gate 	    l = (samegeom ? 0 : 1);
402*0Sstevel@tonic-gate 	    m = (snbytes == nbytes ? 0 : (snbytes > nbytes ? 1 : 2));
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 		/*
405*0Sstevel@tonic-gate 		 * insert slice into the list array using derived indices.
406*0Sstevel@tonic-gate 		 * NB: lists of slices larger than necessary are kept in
407*0Sstevel@tonic-gate 		 * ascending order (results in best fit, not worst fit)
408*0Sstevel@tonic-gate 		 */
409*0Sstevel@tonic-gate 	    if ((item = dlist_new_item((void*)slice)) == NULL) {
410*0Sstevel@tonic-gate 		error = ENOMEM;
411*0Sstevel@tonic-gate 	    } else {
412*0Sstevel@tonic-gate 		list[i][j][k][l][m] =
413*0Sstevel@tonic-gate 		    dlist_insert_ordered(
414*0Sstevel@tonic-gate 			    item,
415*0Sstevel@tonic-gate 			    list[i][j][k][l][m],
416*0Sstevel@tonic-gate 			    (m == 1 ? ASCENDING : DESCENDING),
417*0Sstevel@tonic-gate 			    compare_slice_sizes);
418*0Sstevel@tonic-gate 	    }
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	/*
422*0Sstevel@tonic-gate 	 * Select a slice from one of the lists.
423*0Sstevel@tonic-gate 	 *
424*0Sstevel@tonic-gate 	 * The list with the combination of lowest indices
425*0Sstevel@tonic-gate 	 * is the most preferred list... in rough order:
426*0Sstevel@tonic-gate 	 *
427*0Sstevel@tonic-gate 	 *   one on a unique HBA and disk that is of the exact size
428*0Sstevel@tonic-gate 	 *   one on a unique HBA and disk that is of sufficient size (resize)
429*0Sstevel@tonic-gate 	 *   one on unique HBA that is of the exact size
430*0Sstevel@tonic-gate 	 *   one on unique HBA that is of sufficient size (resize)
431*0Sstevel@tonic-gate 	 *   one on unique disk that is of the exact size
432*0Sstevel@tonic-gate 	 *   one on unique disk that is of sufficient size (resize)
433*0Sstevel@tonic-gate 	 *   one on any HBA that is of exact size
434*0Sstevel@tonic-gate 	 *   one on any HBA that is of sufficient size (resize)
435*0Sstevel@tonic-gate 	 *   one on a unique HBA that is the largest size
436*0Sstevel@tonic-gate 	 *   one on a unique disk that is the largest size
437*0Sstevel@tonic-gate 	 *   one on any HBA that is the largest size
438*0Sstevel@tonic-gate 	 */
439*0Sstevel@tonic-gate 	slice = NULL;
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
442*0Sstevel@tonic-gate 	    for (j = 0; j < 2; j++) {
443*0Sstevel@tonic-gate 		for (k = 0; k < 2; k++) {
444*0Sstevel@tonic-gate 		    for (l = 0; l < 2; l++) {
445*0Sstevel@tonic-gate 			for (m = 0; m < 3; m++) {
446*0Sstevel@tonic-gate 			    if (list[i][j][k][l][m] != NULL) {
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 				/* pick least used slice from this list */
449*0Sstevel@tonic-gate 				error = pick_from_best_hba_and_disk(
450*0Sstevel@tonic-gate 					list[i][j][k][l][m],
451*0Sstevel@tonic-gate 					used, &slice);
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 				resize = (m == 1);
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 				/* terminate all loops */
456*0Sstevel@tonic-gate 				goto stop;
457*0Sstevel@tonic-gate 			    }
458*0Sstevel@tonic-gate 			}
459*0Sstevel@tonic-gate 		    }
460*0Sstevel@tonic-gate 		}
461*0Sstevel@tonic-gate 	    }
462*0Sstevel@tonic-gate 	}
463*0Sstevel@tonic-gate stop:
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	/*
466*0Sstevel@tonic-gate 	 * Slice chosen, is a resize necessary?
467*0Sstevel@tonic-gate 	 */
468*0Sstevel@tonic-gate 	if ((error == 0) && (slice != NULL)) {
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	    if (error == 0) {
471*0Sstevel@tonic-gate 		if (verbose == B_TRUE) {
472*0Sstevel@tonic-gate 		    uint64_t	snbytes = 0;
473*0Sstevel@tonic-gate 		    char	*sname = NULL;
474*0Sstevel@tonic-gate 		    char	*sizestr = NULL;
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 		    (void) get_display_name(slice, &sname);
477*0Sstevel@tonic-gate 		    (void) slice_get_size(slice, &snbytes);
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 		    if (bytes_to_sizestr(snbytes, &sizestr,
480*0Sstevel@tonic-gate 				universal_units, B_FALSE) == 0) {
481*0Sstevel@tonic-gate 			oprintf(OUTPUT_VERBOSE,
482*0Sstevel@tonic-gate 				gettext("      selected %s (%s)\n"
483*0Sstevel@tonic-gate 					"        it is %s on a\n"
484*0Sstevel@tonic-gate 					"          %s (%s) and a\n"
485*0Sstevel@tonic-gate 					"          %s (%s)\n"),
486*0Sstevel@tonic-gate 				sname, sizestr,
487*0Sstevel@tonic-gate 				sizes[m],
488*0Sstevel@tonic-gate 				uniqhba[i], samebus[j],
489*0Sstevel@tonic-gate 				uniqdisk[k], samegeom[l]);
490*0Sstevel@tonic-gate 			free(sizestr);
491*0Sstevel@tonic-gate 		    }
492*0Sstevel@tonic-gate 		}
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 		if (resize) {
495*0Sstevel@tonic-gate 		    if (verbose == B_TRUE) {
496*0Sstevel@tonic-gate 			oprintf(OUTPUT_VERBOSE,
497*0Sstevel@tonic-gate 				gettext("        it has excess space, "
498*0Sstevel@tonic-gate 					"resizing...\n"));
499*0Sstevel@tonic-gate 		    }
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 		    error = create_new_slice(slice, nbytes, add_extra_cyl,
502*0Sstevel@tonic-gate 			    chosen);
503*0Sstevel@tonic-gate 		    if ((error == 0) &&	(*chosen != NULL) && verbose) {
504*0Sstevel@tonic-gate 			oprintf(OUTPUT_VERBOSE,
505*0Sstevel@tonic-gate 				gettext("        exactly resized\n"));
506*0Sstevel@tonic-gate 		    }
507*0Sstevel@tonic-gate 		}
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 		if (error == 0) {
510*0Sstevel@tonic-gate 		    /* either no resize was necessary or the resize failed */
511*0Sstevel@tonic-gate 		    if (*chosen == NULL) {
512*0Sstevel@tonic-gate 			/*
513*0Sstevel@tonic-gate 			 * use the original slice as it is.
514*0Sstevel@tonic-gate 			 * Make a devconfig_t for it.
515*0Sstevel@tonic-gate 			 */
516*0Sstevel@tonic-gate 			error = create_devconfig_for_slice(slice, chosen);
517*0Sstevel@tonic-gate 		    }
518*0Sstevel@tonic-gate 		}
519*0Sstevel@tonic-gate 	    }
520*0Sstevel@tonic-gate 	} else if (slice == NULL) {
521*0Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
522*0Sstevel@tonic-gate 		    gettext("      no possible slice\n"));
523*0Sstevel@tonic-gate 	}
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
526*0Sstevel@tonic-gate 	    for (j = 0; j < 2; j++) {
527*0Sstevel@tonic-gate 		for (k = 0; k < 2; k++) {
528*0Sstevel@tonic-gate 		    for (l = 0; l < 2; l++) {
529*0Sstevel@tonic-gate 			for (m = 0; m < 3; m++) {
530*0Sstevel@tonic-gate 			    if (list[i][j][k][l][m] != NULL) {
531*0Sstevel@tonic-gate 				dlist_free_items(list[i][j][k][l][m], NULL);
532*0Sstevel@tonic-gate 			    }
533*0Sstevel@tonic-gate 			}
534*0Sstevel@tonic-gate 		    }
535*0Sstevel@tonic-gate 		}
536*0Sstevel@tonic-gate 	    }
537*0Sstevel@tonic-gate 	}
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	return (error);
540*0Sstevel@tonic-gate }
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate /*
543*0Sstevel@tonic-gate  * FUNCTION:	create_devconfig_for_slice(dm_descriptor_t slice,
544*0Sstevel@tonic-gate  *			devconfig_t **nslice)
545*0Sstevel@tonic-gate  *
546*0Sstevel@tonic-gate  * INPUT:	slice	- dm_descriptor_t handle to an existing slice
547*0Sstevel@tonic-gate  *		nslice	- devconfig_t pointer to hold the new slice
548*0Sstevel@tonic-gate  *
549*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
550*0Sstevel@tonic-gate  *			 !0 otherwise
551*0Sstevel@tonic-gate  *
552*0Sstevel@tonic-gate  * PURPOSE:	Creates a devconfig_t struct representation of the input
553*0Sstevel@tonic-gate  *		slice dm_descriptor.
554*0Sstevel@tonic-gate  */
555*0Sstevel@tonic-gate int
556*0Sstevel@tonic-gate create_devconfig_for_slice(
557*0Sstevel@tonic-gate 	dm_descriptor_t slice,
558*0Sstevel@tonic-gate 	devconfig_t 	**nslice)
559*0Sstevel@tonic-gate {
560*0Sstevel@tonic-gate 	uint64_t 	nbytes = 0;
561*0Sstevel@tonic-gate 	uint64_t 	nblks = 0;
562*0Sstevel@tonic-gate 	uint64_t 	stblk = 0;
563*0Sstevel@tonic-gate 	uint32_t 	index = 0;
564*0Sstevel@tonic-gate 	char		*name = NULL;
565*0Sstevel@tonic-gate 	int		error = 0;
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	((error = get_display_name(slice, &name)) != 0) ||
568*0Sstevel@tonic-gate 	(error = slice_get_size(slice, &nbytes)) ||
569*0Sstevel@tonic-gate 	(error = slice_get_size_in_blocks(slice, &nblks)) ||
570*0Sstevel@tonic-gate 	(error = slice_get_start_block(slice, &stblk)) ||
571*0Sstevel@tonic-gate 	(error = slice_get_index(slice, &index));
572*0Sstevel@tonic-gate 	if (error != 0) {
573*0Sstevel@tonic-gate 	    return (error);
574*0Sstevel@tonic-gate 	}
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	((error = new_devconfig(nslice, TYPE_SLICE)) != 0) ||
577*0Sstevel@tonic-gate 	(error = devconfig_set_name(*nslice, name)) ||
578*0Sstevel@tonic-gate 	(error = devconfig_set_slice_index(*nslice, index)) ||
579*0Sstevel@tonic-gate 	(error = devconfig_set_slice_start_block(*nslice, stblk)) ||
580*0Sstevel@tonic-gate 	(error = devconfig_set_size_in_blocks(*nslice, nblks)) ||
581*0Sstevel@tonic-gate 	(error = devconfig_set_size(*nslice, nbytes));
582*0Sstevel@tonic-gate 	if (error != 0) {
583*0Sstevel@tonic-gate 	    free_devconfig(*nslice);
584*0Sstevel@tonic-gate 	}
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	return (error);
587*0Sstevel@tonic-gate }
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate /*
590*0Sstevel@tonic-gate  * FUNCTION:	make_slicename_for_disk_and_index(dm_descriptor_t disk,
591*0Sstevel@tonic-gate  *			uint32_t index, char **slicename)
592*0Sstevel@tonic-gate  *
593*0Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t disk handle
594*0Sstevel@tonic-gate  *		index	- a slice index
595*0Sstevel@tonic-gate  *
596*0Sstevel@tonic-gate  * OUTPUT	slicename - a char * pointer to hold the resulting slicename
597*0Sstevel@tonic-gate  *
598*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
599*0Sstevel@tonic-gate  *			 !0 otherwise
600*0Sstevel@tonic-gate  *
601*0Sstevel@tonic-gate  * PURPOSE:	Utility function to manufacture a new slice name given the
602*0Sstevel@tonic-gate  *		"parent" disk and an available slice index.
603*0Sstevel@tonic-gate  *
604*0Sstevel@tonic-gate  *		The caller should free the returned name when done with it.
605*0Sstevel@tonic-gate  */
606*0Sstevel@tonic-gate static int
607*0Sstevel@tonic-gate make_slicename_for_disk_and_index(
608*0Sstevel@tonic-gate 	dm_descriptor_t	disk,
609*0Sstevel@tonic-gate 	uint16_t	index,
610*0Sstevel@tonic-gate 	char		**slicename)
611*0Sstevel@tonic-gate {
612*0Sstevel@tonic-gate 	char *dname;
613*0Sstevel@tonic-gate 	int error = 0;
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	if ((error = get_display_name(disk, &dname)) == 0) {
616*0Sstevel@tonic-gate 	    error = make_slicename_for_diskname_and_index(dname,
617*0Sstevel@tonic-gate 		    index, slicename);
618*0Sstevel@tonic-gate 	}
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	return (error);
621*0Sstevel@tonic-gate }
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate /*
624*0Sstevel@tonic-gate  * FUNCTION:	make_slicename_for_diskname_and_index(char *diskname,
625*0Sstevel@tonic-gate  *			uint32_t index, char **slicename)
626*0Sstevel@tonic-gate  *
627*0Sstevel@tonic-gate  * INPUT:	diskname - a char * disk name
628*0Sstevel@tonic-gate  *		index	- a slice index
629*0Sstevel@tonic-gate  *
630*0Sstevel@tonic-gate  * OUTPUT	slicename - a char * pointer to hold the resulting slicename
631*0Sstevel@tonic-gate  *
632*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
633*0Sstevel@tonic-gate  *			 !0 otherwise
634*0Sstevel@tonic-gate  *
635*0Sstevel@tonic-gate  * PURPOSE:	Utility function to manufacture a new slice name given the
636*0Sstevel@tonic-gate  *		name of a disk and an available slice index.
637*0Sstevel@tonic-gate  *
638*0Sstevel@tonic-gate  *		The caller should free the returned name when done with it.
639*0Sstevel@tonic-gate  */
640*0Sstevel@tonic-gate int
641*0Sstevel@tonic-gate make_slicename_for_diskname_and_index(
642*0Sstevel@tonic-gate 	char	*diskname,
643*0Sstevel@tonic-gate 	uint16_t index,
644*0Sstevel@tonic-gate 	char	**slicename)
645*0Sstevel@tonic-gate {
646*0Sstevel@tonic-gate 	int error = 0;
647*0Sstevel@tonic-gate 	char buf[MAXNAMELEN+1];
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%ss%u", diskname, index);
650*0Sstevel@tonic-gate 	if ((*slicename = strdup(buf)) == NULL) {
651*0Sstevel@tonic-gate 	    *slicename = NULL;
652*0Sstevel@tonic-gate 	    error = ENOMEM;
653*0Sstevel@tonic-gate 	}
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 	return (error);
656*0Sstevel@tonic-gate }
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate /*
659*0Sstevel@tonic-gate  * FUNCTION:	create_new_slice(dm_descriptor_t oslice, uint64_t nbytes,
660*0Sstevel@tonic-gate  *			boolean_t add_extra_cyl, devconfig_t **nslice)
661*0Sstevel@tonic-gate  *
662*0Sstevel@tonic-gate  * INPUT:	oslice	- dm_descriptor_t handle to an existing slice
663*0Sstevel@tonic-gate  *		nbytes	- desired minimum size of the new slice
664*0Sstevel@tonic-gate  *		add_extra_cyl - boolean indicating whether the resized slice
665*0Sstevel@tonic-gate  *			needs to be oversized by 1 cylinder to account for
666*0Sstevel@tonic-gate  *			interlace rounding done for stripe components.
667*0Sstevel@tonic-gate  *		nslice	- devconfig_t pointer to hold the new slice
668*0Sstevel@tonic-gate  *
669*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
670*0Sstevel@tonic-gate  *			 !0 otherwise
671*0Sstevel@tonic-gate  *
672*0Sstevel@tonic-gate  * PURPOSE:	Creates a new slice object using space from the input slice.
673*0Sstevel@tonic-gate  *
674*0Sstevel@tonic-gate  *		If there is an open slice slot in the disk VTOC, it will be
675*0Sstevel@tonic-gate  *		reserved for the new slice.  Space for the new slice will be
676*0Sstevel@tonic-gate  *		taken from the original slice.
677*0Sstevel@tonic-gate  *
678*0Sstevel@tonic-gate  *		If there is no open slice slot, the original slice will be
679*0Sstevel@tonic-gate  *		returned as the usable new slice.
680*0Sstevel@tonic-gate  *
681*0Sstevel@tonic-gate  *		The new slice will be of at least 'nbytes' bytes and possibly
682*0Sstevel@tonic-gate  *		larger due to sector and cylinder boundary alignment.
683*0Sstevel@tonic-gate  *
684*0Sstevel@tonic-gate  *		For EFI labeled disks, nbytes is rounded up to the next block
685*0Sstevel@tonic-gate  *		boundary.
686*0Sstevel@tonic-gate  *
687*0Sstevel@tonic-gate  *		For VTOC labeled disks, nbytes is rounded up to the next
688*0Sstevel@tonic-gate  *		cylinder boundary.
689*0Sstevel@tonic-gate  *
690*0Sstevel@tonic-gate  *		Additionally, if add_extra_cyl is true, the new slice will be
691*0Sstevel@tonic-gate  *		made 1 cylinder larger than necessary. This accounts for the
692*0Sstevel@tonic-gate  *		interlace rounding done within libmeta when computing the
693*0Sstevel@tonic-gate  *		usable size of stripe components on disks with VTOC labels.
694*0Sstevel@tonic-gate  *		Rounding the size up to the next cylinder boundary is not
695*0Sstevel@tonic-gate  *		sufficient because libmeta will round this size down to an
696*0Sstevel@tonic-gate  *		integral multiple of the stripe	interlace and then round that
697*0Sstevel@tonic-gate  *		result down to a cylinder boundary.  This makes the usable
698*0Sstevel@tonic-gate  *		size of the slice one cylinder smaller and possibly less than
699*0Sstevel@tonic-gate  *		nbytes.  Adding an extra cylinder ensures the usable size is
700*0Sstevel@tonic-gate  *		greater than nbytes despite the rounding.
701*0Sstevel@tonic-gate  *
702*0Sstevel@tonic-gate  *		If the resize is successful a pointer to the devconfig_t
703*0Sstevel@tonic-gate  *		representing the new slice will be returned in "newslice".
704*0Sstevel@tonic-gate  *
705*0Sstevel@tonic-gate  *		If the resize cannot be done, the newslice pointer will
706*0Sstevel@tonic-gate  *		be NULL.
707*0Sstevel@tonic-gate  */
708*0Sstevel@tonic-gate static int
709*0Sstevel@tonic-gate create_new_slice(
710*0Sstevel@tonic-gate 	dm_descriptor_t	oslice,
711*0Sstevel@tonic-gate 	uint64_t	nbytes,
712*0Sstevel@tonic-gate 	boolean_t	add_extra_cyl,
713*0Sstevel@tonic-gate 	devconfig_t	**nslice)
714*0Sstevel@tonic-gate {
715*0Sstevel@tonic-gate 	dm_descriptor_t odisk = NULL;
716*0Sstevel@tonic-gate 	boolean_t	efi = B_FALSE;
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	char		*oname = NULL;
719*0Sstevel@tonic-gate 	uint64_t	osize = 0;	/* orig size (bytes) */
720*0Sstevel@tonic-gate 	uint64_t	ostart = 0;	/* orig start (byte) */
721*0Sstevel@tonic-gate 	uint64_t	ostblk = 0;	/* orig start (blk) */
722*0Sstevel@tonic-gate 	uint64_t	nsize = 0;	/* new size (bytes) */
723*0Sstevel@tonic-gate 	uint64_t	bytes_per_sect = 0;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	uint32_t 	oindex = 0;
726*0Sstevel@tonic-gate 	uint32_t	nindex = oindex;
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	int		error = 0;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	*nslice = NULL;
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	((error = slice_get_disk(oslice, &odisk)) != 0) ||
733*0Sstevel@tonic-gate 	(error = slice_get_index(oslice, &oindex));
734*0Sstevel@tonic-gate 	if (error != 0) {
735*0Sstevel@tonic-gate 	    return (error);
736*0Sstevel@tonic-gate 	}
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	/* find an unused slice number, default to oindex */
739*0Sstevel@tonic-gate 	nindex = oindex;
740*0Sstevel@tonic-gate 	if ((error = disk_get_available_slice_index(odisk, &nindex)) != 0) {
741*0Sstevel@tonic-gate 	    return (error);
742*0Sstevel@tonic-gate 	}
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	((error = get_display_name(oslice, &oname)) != 0) ||
745*0Sstevel@tonic-gate 	(error = slice_get_size(oslice, &osize)) ||
746*0Sstevel@tonic-gate 	(error = slice_get_start(oslice, &ostart)) ||
747*0Sstevel@tonic-gate 	(error = slice_get_start_block(oslice, &ostblk)) ||
748*0Sstevel@tonic-gate 	(error = disk_get_is_efi(odisk, &efi)) ||
749*0Sstevel@tonic-gate 	(error = disk_get_blocksize(odisk, &bytes_per_sect));
750*0Sstevel@tonic-gate 	if (error != 0) {
751*0Sstevel@tonic-gate 	    return (error);
752*0Sstevel@tonic-gate 	}
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	if (efi) {
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 	    /* EFI: round size to an integral number of blocks (sectors) */
757*0Sstevel@tonic-gate 	    nsize = bytes_per_sect *
758*0Sstevel@tonic-gate 		((nbytes + (bytes_per_sect - 1)) / bytes_per_sect);
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
761*0Sstevel@tonic-gate 		    gettext("          "
762*0Sstevel@tonic-gate 			    "rounded up to %10.2f blocks\n"),
763*0Sstevel@tonic-gate 		    (double)(nsize/bytes_per_sect));
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	} else {
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	    /* VTOC: round size to an integral number of cylinders */
768*0Sstevel@tonic-gate 	    uint64_t	nhead = 0;
769*0Sstevel@tonic-gate 	    uint64_t	nsect = 0;
770*0Sstevel@tonic-gate 	    uint64_t	ncyls = 0;
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	    ((error = disk_get_ncylinders(odisk, &ncyls)) != 0) ||
773*0Sstevel@tonic-gate 	    (error = disk_get_nheads(odisk, &nhead)) ||
774*0Sstevel@tonic-gate 	    (error = disk_get_nsectors(odisk, &nsect));
775*0Sstevel@tonic-gate 	    if (error == 0) {
776*0Sstevel@tonic-gate 		uint64_t bytes_per_cyl = nhead * nsect * bytes_per_sect;
777*0Sstevel@tonic-gate 		nsize = bytes_per_cyl *
778*0Sstevel@tonic-gate 		    ((nbytes + (bytes_per_cyl - 1)) / bytes_per_cyl);
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 		if (add_extra_cyl == TRUE) {
781*0Sstevel@tonic-gate 		    nsize += bytes_per_cyl;
782*0Sstevel@tonic-gate 		}
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate 		oprintf(OUTPUT_DEBUG,
785*0Sstevel@tonic-gate 			gettext("          "
786*0Sstevel@tonic-gate 				"rounded VTOC slice to %10.2f cylinders "
787*0Sstevel@tonic-gate 				"(out of %llu)\n"),
788*0Sstevel@tonic-gate 			(double)(nsize/bytes_per_cyl), ncyls);
789*0Sstevel@tonic-gate 	    }
790*0Sstevel@tonic-gate 	}
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	/* is sufficient space still available? */
793*0Sstevel@tonic-gate 	if (error == 0) {
794*0Sstevel@tonic-gate 	    if (osize == nsize) {
795*0Sstevel@tonic-gate 		/* use existing slice as is */
796*0Sstevel@tonic-gate 		((error = create_devconfig_for_slice(oslice, nslice)) != 0) ||
797*0Sstevel@tonic-gate 		(error = disk_reserve_index(odisk, (uint16_t)nindex));
798*0Sstevel@tonic-gate 	    } else if (osize > nsize) {
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 		if (nindex == oindex) {
801*0Sstevel@tonic-gate 		    /* no more slices, resize existing slice */
802*0Sstevel@tonic-gate 		    ((error = create_devconfig_for_slice(oslice,
803*0Sstevel@tonic-gate 			nslice)) != 0) ||
804*0Sstevel@tonic-gate 		    (error = devconfig_set_size(*nslice, nsize)) ||
805*0Sstevel@tonic-gate 		    (error = devconfig_set_size_in_blocks(*nslice,
806*0Sstevel@tonic-gate 			nsize/bytes_per_sect));
807*0Sstevel@tonic-gate 		    (error = disk_reserve_index(odisk, (uint16_t)nindex));
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 		} else {
810*0Sstevel@tonic-gate 		    /* make a new slice */
811*0Sstevel@tonic-gate 		    char *nname = NULL;
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 		    ((error = make_slicename_for_disk_and_index(odisk,
814*0Sstevel@tonic-gate 			nindex, &nname)) != 0) ||
815*0Sstevel@tonic-gate 		    (error = create_modified_slice(oslice, oname, oindex,
816*0Sstevel@tonic-gate 			ostart, osize, bytes_per_sect, nname, nindex, nsize,
817*0Sstevel@tonic-gate 			nslice)) ||
818*0Sstevel@tonic-gate 			/* mark the new slice's index as used */
819*0Sstevel@tonic-gate 		    (error = disk_reserve_index(odisk, (uint16_t)nindex));
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 		    if ((error != 0) && (*nslice == NULL)) {
822*0Sstevel@tonic-gate 			free(nname);
823*0Sstevel@tonic-gate 		    }
824*0Sstevel@tonic-gate 		}
825*0Sstevel@tonic-gate 	    }
826*0Sstevel@tonic-gate 	}
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 	return (error);
829*0Sstevel@tonic-gate }
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate /*
832*0Sstevel@tonic-gate  * FUNCTION:	create_modified_slice(dm_descriptor_t oslice, char *oname,
833*0Sstevel@tonic-gate  *			uint32_t oindex, uint64_t ostart, uint64_t osize,
834*0Sstevel@tonic-gate  *			uint64_t bytes_per_sect, uint64_t nsize,
835*0Sstevel@tonic-gate  *			char *nname, uint32_t nindex, devconfig_t **nslice)
836*0Sstevel@tonic-gate  *
837*0Sstevel@tonic-gate  * INPUT:	oslice	- dm_descriptor_t handle for the original slice
838*0Sstevel@tonic-gate  *		oname - existing source slice name
839*0Sstevel@tonic-gate  *		oindex - existing source slice VTOC index
840*0Sstevel@tonic-gate  *		ostart - existing source slice start byte
841*0Sstevel@tonic-gate  *		osize - existing source slice size in bytes
842*0Sstevel@tonic-gate  *		bytes_per_sect - bytes per block (sector) for the disk
843*0Sstevel@tonic-gate  *		nname - new slice name
844*0Sstevel@tonic-gate  *		nindex - new slice VTOC index
845*0Sstevel@tonic-gate  *		nsize - new slice size in bytes (cylinder and block aligned)
846*0Sstevel@tonic-gate  *
847*0Sstevel@tonic-gate  * SIDEEFFECTS: updates the module private list of modified slices
848*0Sstevel@tonic-gate  *
849*0Sstevel@tonic-gate  * OUTPUT:	nslice - pointer to a devconfig_t to hold the new slice
850*0Sstevel@tonic-gate  *
851*0Sstevel@tonic-gate  * PURPOSE:	create a new VTOC slice by taking space from an
852*0Sstevel@tonic-gate  *		existing slice.
853*0Sstevel@tonic-gate  *
854*0Sstevel@tonic-gate  *		The input size for the new slice is expected to be
855*0Sstevel@tonic-gate  *		cylinder aligned.
856*0Sstevel@tonic-gate  */
857*0Sstevel@tonic-gate static int
858*0Sstevel@tonic-gate create_modified_slice(
859*0Sstevel@tonic-gate 	dm_descriptor_t	oslice,
860*0Sstevel@tonic-gate 	char		*oname,
861*0Sstevel@tonic-gate 	uint32_t	oindex,
862*0Sstevel@tonic-gate 	uint64_t	ostart,
863*0Sstevel@tonic-gate 	uint64_t	osize,
864*0Sstevel@tonic-gate 	uint64_t	bytes_per_sect,
865*0Sstevel@tonic-gate 	char		*nname,
866*0Sstevel@tonic-gate 	uint32_t	nindex,
867*0Sstevel@tonic-gate 	uint64_t	nsize,
868*0Sstevel@tonic-gate 	devconfig_t	**nslice)
869*0Sstevel@tonic-gate {
870*0Sstevel@tonic-gate 	int		error = 0;
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	/* compute start sector and size in sectors for the new slice */
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	/* subtract nsize from original slice to get starting byte */
875*0Sstevel@tonic-gate 	uint64_t	nstart = (ostart + osize) - nsize;
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 	/* convert starting byte to a sector */
878*0Sstevel@tonic-gate 	uint64_t	nstblk = (uint64_t)(nstart / bytes_per_sect);
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 	/* convert nsize to an integral number of blocks (sectors) */
881*0Sstevel@tonic-gate 	uint64_t	nblks = (uint64_t)(nsize / bytes_per_sect);
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	/* create a modified slice record for the new slice */
884*0Sstevel@tonic-gate 	error = assemble_modified_slice(oslice, nname, nindex,
885*0Sstevel@tonic-gate 		nstblk, nblks, nsize, nslice);
886*0Sstevel@tonic-gate 	if (error != 0) {
887*0Sstevel@tonic-gate 	    free(nname);
888*0Sstevel@tonic-gate 	    return (error);
889*0Sstevel@tonic-gate 	}
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 	/* update the existing source slice's new size */
892*0Sstevel@tonic-gate 	osize = osize - nsize;
893*0Sstevel@tonic-gate 	(void) slice_set_size(oslice, osize);
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 	/* update/create the modified slice record gfor the source slice */
896*0Sstevel@tonic-gate 	error = assemble_modified_slice((dm_descriptor_t)0,
897*0Sstevel@tonic-gate 		oname, oindex, (uint64_t)(ostart / bytes_per_sect),
898*0Sstevel@tonic-gate 		(uint64_t)(osize / bytes_per_sect),
899*0Sstevel@tonic-gate 		osize, NULL);
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 	return (error);
902*0Sstevel@tonic-gate }
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate /*
905*0Sstevel@tonic-gate  * FUNCTION:	assemble_modified_slice(dm_descriptor_t src_slice,
906*0Sstevel@tonic-gate  *			char *mod_name,	uint32_t mod_index,
907*0Sstevel@tonic-gate  *			uint64_t mod_stblk, uint64_t mod_nblks,
908*0Sstevel@tonic-gate  *			uint64_t mod_size, devconfig_t **modslice)
909*0Sstevel@tonic-gate  *
910*0Sstevel@tonic-gate  * INPUT:	src_slice - dm_descriptor_t handle of the slice space
911*0Sstevel@tonic-gate  *			was taken from to create the modified slice
912*0Sstevel@tonic-gate  *		mod_name - name of the modified slice
913*0Sstevel@tonic-gate  *		mod_index - name of the modified slice
914*0Sstevel@tonic-gate  *		mod_stblk - start block of the modified slice
915*0Sstevel@tonic-gate  *		mod_nblks - size in blocks of the modified slice
916*0Sstevel@tonic-gate  *		mod_size - size in bytes of the modified slice
917*0Sstevel@tonic-gate  *
918*0Sstevel@tonic-gate  * OUTPUT:	mod_slice	- if non-NULL, will be populated with a
919*0Sstevel@tonic-gate  *			devconfig_t representing the modified slice.
920*0Sstevel@tonic-gate  *
921*0Sstevel@tonic-gate  * SIDEEFFECTS: adds or updates an entry in the modified slice list
922*0Sstevel@tonic-gate  *		tracking the slices that have been explicitly modified
923*0Sstevel@tonic-gate  *		by the layout code.
924*0Sstevel@tonic-gate  *
925*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
926*0Sstevel@tonic-gate  *			 !0 otherwise
927*0Sstevel@tonic-gate  *
928*0Sstevel@tonic-gate  * PURPOSE:	Utility function to which updates or creates a devconfig_t
929*0Sstevel@tonic-gate  *		representing a slice that needs to be modified.
930*0Sstevel@tonic-gate  *
931*0Sstevel@tonic-gate  *		If a modified slice record does not exist for the named
932*0Sstevel@tonic-gate  *		slice, a new devconfig_t struct is allocated and added
933*0Sstevel@tonic-gate  *		to the modified slice list.
934*0Sstevel@tonic-gate  *
935*0Sstevel@tonic-gate  *		The existing or created devconfig_t struct is updated with
936*0Sstevel@tonic-gate  *		the input values.
937*0Sstevel@tonic-gate  *
938*0Sstevel@tonic-gate  *		The information about the slices in the modified slice list
939*0Sstevel@tonic-gate  *		will eventually be handed to fmthard.
940*0Sstevel@tonic-gate  */
941*0Sstevel@tonic-gate int
942*0Sstevel@tonic-gate assemble_modified_slice(
943*0Sstevel@tonic-gate 	dm_descriptor_t	src_slice,
944*0Sstevel@tonic-gate 	char		*mod_name,
945*0Sstevel@tonic-gate 	uint32_t	mod_index,
946*0Sstevel@tonic-gate 	uint64_t	mod_stblk,
947*0Sstevel@tonic-gate 	uint64_t	mod_nblks,
948*0Sstevel@tonic-gate 	uint64_t	mod_size,
949*0Sstevel@tonic-gate 	devconfig_t	**mod_slice)
950*0Sstevel@tonic-gate {
951*0Sstevel@tonic-gate 	devconfig_t	*slice = NULL;
952*0Sstevel@tonic-gate 	modslice_t	*mstp = NULL;
953*0Sstevel@tonic-gate 	dlist_t		*item = NULL;
954*0Sstevel@tonic-gate 	int		error = 0;
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 	/* see if the slice has been modified before */
957*0Sstevel@tonic-gate 	if ((item = dlist_find(_modified_slices, mod_name,
958*0Sstevel@tonic-gate 	    compare_string_to_modslice_name)) != NULL) {
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	    /* yes, update the resize count and attributes */
961*0Sstevel@tonic-gate 	    mstp = (modslice_t *)item->obj;
962*0Sstevel@tonic-gate 	    slice = mstp->slice_devcfg;
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	    mstp->times_modified += 1;
965*0Sstevel@tonic-gate 	    mstp->src_slice_desc = src_slice;
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 	    ((error = devconfig_set_slice_start_block(slice,
968*0Sstevel@tonic-gate 		mod_stblk)) != 0) ||
969*0Sstevel@tonic-gate 	    (error = devconfig_set_size(slice, mod_size)) ||
970*0Sstevel@tonic-gate 	    (error = devconfig_set_size_in_blocks(slice, mod_nblks));
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 	} else {
973*0Sstevel@tonic-gate 
974*0Sstevel@tonic-gate 	    /* no, first modification... */
975*0Sstevel@tonic-gate 	    /* create a devconfig_t representing the new slice */
976*0Sstevel@tonic-gate 	    ((error = new_devconfig(&slice, TYPE_SLICE)) != 0) ||
977*0Sstevel@tonic-gate 	    (error = devconfig_set_name(slice, mod_name)) ||
978*0Sstevel@tonic-gate 	    (error = devconfig_set_slice_index(slice, mod_index)) ||
979*0Sstevel@tonic-gate 	    (error = devconfig_set_slice_start_block(slice, mod_stblk)) ||
980*0Sstevel@tonic-gate 	    (error = devconfig_set_size_in_blocks(slice, mod_nblks)) ||
981*0Sstevel@tonic-gate 	    (error = devconfig_set_size(slice, mod_size));
982*0Sstevel@tonic-gate 	    if (error == 0) {
983*0Sstevel@tonic-gate 		/* add to list of modified slices */
984*0Sstevel@tonic-gate 		if ((mstp = (modslice_t *)
985*0Sstevel@tonic-gate 		    calloc(1, sizeof (modslice_t))) != NULL) {
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 		    /* count # of times source slice has been modified */
988*0Sstevel@tonic-gate 		    if (src_slice != (dm_descriptor_t)0) {
989*0Sstevel@tonic-gate 			mstp->times_modified = 0;
990*0Sstevel@tonic-gate 		    } else {
991*0Sstevel@tonic-gate 			mstp->times_modified = 1;
992*0Sstevel@tonic-gate 		    }
993*0Sstevel@tonic-gate 		    mstp->src_slice_desc = src_slice;
994*0Sstevel@tonic-gate 		    mstp->slice_devcfg = slice;
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 		    if ((item = dlist_new_item(mstp)) != NULL) {
997*0Sstevel@tonic-gate 			_modified_slices =
998*0Sstevel@tonic-gate 			    dlist_insert_ordered(
999*0Sstevel@tonic-gate 				    item,
1000*0Sstevel@tonic-gate 				    _modified_slices,
1001*0Sstevel@tonic-gate 				    ASCENDING,
1002*0Sstevel@tonic-gate 				    compare_modslice_names);
1003*0Sstevel@tonic-gate 		    } else {
1004*0Sstevel@tonic-gate 			error = ENOMEM;
1005*0Sstevel@tonic-gate 		    }
1006*0Sstevel@tonic-gate 		} else {
1007*0Sstevel@tonic-gate 		    error = ENOMEM;
1008*0Sstevel@tonic-gate 		}
1009*0Sstevel@tonic-gate 	    }
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 	    if (error != 0) {
1012*0Sstevel@tonic-gate 		free_devconfig(mstp);
1013*0Sstevel@tonic-gate 		free_devconfig(slice);
1014*0Sstevel@tonic-gate 	    }
1015*0Sstevel@tonic-gate 	}
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 	if (error == 0) {
1018*0Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
1019*0Sstevel@tonic-gate 		    "          "
1020*0Sstevel@tonic-gate 		    "modified %s (start blk: %9llu, nblks: %9llu)\n",
1021*0Sstevel@tonic-gate 		    mod_name, mod_stblk, mod_nblks);
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	    /* return devconfig_t for modified slice */
1024*0Sstevel@tonic-gate 	    if (mod_slice != NULL) {
1025*0Sstevel@tonic-gate 		*mod_slice = slice;
1026*0Sstevel@tonic-gate 		mstp->volume_component = B_TRUE;
1027*0Sstevel@tonic-gate 	    }
1028*0Sstevel@tonic-gate 	}
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 	return (error);
1031*0Sstevel@tonic-gate }
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate /*
1034*0Sstevel@tonic-gate  * FUNCTION:	dlist_t *get_modified_slices()
1035*0Sstevel@tonic-gate  *
1036*0Sstevel@tonic-gate  * RETURNS:	pointer to the list of modslice_t structs representing
1037*0Sstevel@tonic-gate  *		modified slices
1038*0Sstevel@tonic-gate  *
1039*0Sstevel@tonic-gate  * PURPOSE:	public accessor to the list of slices modified while
1040*0Sstevel@tonic-gate  *		processing a request.
1041*0Sstevel@tonic-gate  */
1042*0Sstevel@tonic-gate dlist_t *
1043*0Sstevel@tonic-gate get_modified_slices()
1044*0Sstevel@tonic-gate {
1045*0Sstevel@tonic-gate 	return (_modified_slices);
1046*0Sstevel@tonic-gate }
1047*0Sstevel@tonic-gate 
1048*0Sstevel@tonic-gate /*
1049*0Sstevel@tonic-gate  * FUNCTION:	free_modslice_object(void *obj)
1050*0Sstevel@tonic-gate  *
1051*0Sstevel@tonic-gate  * INPUT:	obj	- opaque pointer
1052*0Sstevel@tonic-gate  *
1053*0Sstevel@tonic-gate  * PURPOSE:	Frees memory associated with a modslice_t struct.
1054*0Sstevel@tonic-gate  */
1055*0Sstevel@tonic-gate static void
1056*0Sstevel@tonic-gate free_modslice_object(
1057*0Sstevel@tonic-gate 	void	*obj)
1058*0Sstevel@tonic-gate {
1059*0Sstevel@tonic-gate 	assert(obj != (modslice_t *)NULL);
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	if (((modslice_t *)obj)->slice_devcfg != NULL) {
1062*0Sstevel@tonic-gate 	    if (((modslice_t *)obj)->volume_component != B_TRUE) {
1063*0Sstevel@tonic-gate 		free_devconfig(((modslice_t *)obj)->slice_devcfg);
1064*0Sstevel@tonic-gate 	    }
1065*0Sstevel@tonic-gate 	}
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	free(obj);
1068*0Sstevel@tonic-gate }
1069*0Sstevel@tonic-gate 
1070*0Sstevel@tonic-gate /*
1071*0Sstevel@tonic-gate  * FUNCTION:	void release_modified_slices()
1072*0Sstevel@tonic-gate  *
1073*0Sstevel@tonic-gate  * INPUT:	none   -
1074*0Sstevel@tonic-gate  * OUTPUT:	none   -
1075*0Sstevel@tonic-gate  *
1076*0Sstevel@tonic-gate  * PURPOSE:	cleanup the module global list of slices modified
1077*0Sstevel@tonic-gate  *		while processing a request.
1078*0Sstevel@tonic-gate  */
1079*0Sstevel@tonic-gate int
1080*0Sstevel@tonic-gate release_modified_slices()
1081*0Sstevel@tonic-gate {
1082*0Sstevel@tonic-gate 	dlist_free_items(_modified_slices, free_modslice_object);
1083*0Sstevel@tonic-gate 	_modified_slices = NULL;
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 	return (0);
1086*0Sstevel@tonic-gate }
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate /*
1089*0Sstevel@tonic-gate  * FUNCTION:	destroy_new_slice(devconfig_t *dev)
1090*0Sstevel@tonic-gate  *
1091*0Sstevel@tonic-gate  * INPUT:	dev	- a devconfig_t pointer to a slice object
1092*0Sstevel@tonic-gate  *
1093*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1094*0Sstevel@tonic-gate  *			 !0 otherwise
1095*0Sstevel@tonic-gate  *
1096*0Sstevel@tonic-gate  * PURPOSE:	Undoes slice creation done by create_new_slice():
1097*0Sstevel@tonic-gate  *
1098*0Sstevel@tonic-gate  *		release index
1099*0Sstevel@tonic-gate  *		remove from used_slices
1100*0Sstevel@tonic-gate  *		remove from modified_slices
1101*0Sstevel@tonic-gate  *		return space to source slice
1102*0Sstevel@tonic-gate  *		free memory
1103*0Sstevel@tonic-gate  */
1104*0Sstevel@tonic-gate int
1105*0Sstevel@tonic-gate destroy_new_slice(
1106*0Sstevel@tonic-gate 	devconfig_t	*dev)
1107*0Sstevel@tonic-gate {
1108*0Sstevel@tonic-gate 	dm_descriptor_t disk = NULL;
1109*0Sstevel@tonic-gate 	uint64_t	size = 0;
1110*0Sstevel@tonic-gate 	uint16_t	index = 0;
1111*0Sstevel@tonic-gate 	modslice_t	*modified = NULL;
1112*0Sstevel@tonic-gate 	dlist_t		*item = NULL;
1113*0Sstevel@tonic-gate 	char		*name = NULL;
1114*0Sstevel@tonic-gate 	int		error = 0;
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate 	((error = devconfig_get_name(dev, &name)) != 0) ||
1117*0Sstevel@tonic-gate 	(error = devconfig_get_slice_index(dev, &index)) ||
1118*0Sstevel@tonic-gate 	(error = devconfig_get_size(dev, &size)) ||
1119*0Sstevel@tonic-gate 	(error = get_disk_for_named_slice(name, &disk)) ||
1120*0Sstevel@tonic-gate 	(error = disk_release_index(disk, index)) ||
1121*0Sstevel@tonic-gate 	(error = remove_used_slice_by_name(name));
1122*0Sstevel@tonic-gate 	if (error != 0) {
1123*0Sstevel@tonic-gate 	    return (error);
1124*0Sstevel@tonic-gate 	}
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	/* remove from the modified_slices list */
1127*0Sstevel@tonic-gate 	_modified_slices =
1128*0Sstevel@tonic-gate 	    dlist_remove_equivalent_item(
1129*0Sstevel@tonic-gate 		    _modified_slices, name,
1130*0Sstevel@tonic-gate 		    compare_string_to_modslice_name, &item);
1131*0Sstevel@tonic-gate 
1132*0Sstevel@tonic-gate 	if (item != NULL) {
1133*0Sstevel@tonic-gate 	    modified = (modslice_t *)item->obj;
1134*0Sstevel@tonic-gate 	    free((void*) item);
1135*0Sstevel@tonic-gate 	}
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate 	/* space from an existing slice? if so reclaim it. */
1138*0Sstevel@tonic-gate 	if (modified != NULL) {
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 	    dm_descriptor_t src = modified->src_slice_desc;
1141*0Sstevel@tonic-gate 	    char	*srcname = NULL;
1142*0Sstevel@tonic-gate 	    dlist_t	*srcitem = NULL;
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	    if (src != (dm_descriptor_t)0) {
1145*0Sstevel@tonic-gate 		if ((error = get_display_name(src, &srcname)) == 0) {
1146*0Sstevel@tonic-gate 		    srcitem =
1147*0Sstevel@tonic-gate 			dlist_find(
1148*0Sstevel@tonic-gate 				_modified_slices,
1149*0Sstevel@tonic-gate 				srcname,
1150*0Sstevel@tonic-gate 				compare_string_to_modslice_name);
1151*0Sstevel@tonic-gate 		}
1152*0Sstevel@tonic-gate 	    }
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate 	    if ((error == 0) && (srcitem != NULL)) {
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate 		modslice_t	*source = (modslice_t *)srcitem->obj;
1157*0Sstevel@tonic-gate 		devconfig_t	*srcdevcfg = NULL;
1158*0Sstevel@tonic-gate 		uint64_t	srcsize = NULL;
1159*0Sstevel@tonic-gate 		uint64_t	srcsizeblks = NULL;
1160*0Sstevel@tonic-gate 		uint64_t	inblks = NULL;
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate 		srcdevcfg = source->slice_devcfg;
1163*0Sstevel@tonic-gate 		source->times_modified -= 1;
1164*0Sstevel@tonic-gate 
1165*0Sstevel@tonic-gate 		((error = devconfig_get_size(srcdevcfg, &srcsize)) != 0) ||
1166*0Sstevel@tonic-gate 		(error = devconfig_set_size(srcdevcfg, srcsize + size)) ||
1167*0Sstevel@tonic-gate 		(error = slice_set_size(src, srcsize + size)) ||
1168*0Sstevel@tonic-gate 		(error = slice_get_size_in_blocks(src, &srcsizeblks)) ||
1169*0Sstevel@tonic-gate 		(error = devconfig_get_size_in_blocks(srcdevcfg, &inblks));
1170*0Sstevel@tonic-gate 		(error = devconfig_set_size_in_blocks(srcdevcfg, srcsizeblks));
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate 		if (error == 0) {
1173*0Sstevel@tonic-gate 
1174*0Sstevel@tonic-gate 		    /* was only modification undone? */
1175*0Sstevel@tonic-gate 		    if (source->times_modified == 0) {
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 			_modified_slices =
1178*0Sstevel@tonic-gate 			    dlist_remove_equivalent_item(
1179*0Sstevel@tonic-gate 				    _modified_slices, srcname,
1180*0Sstevel@tonic-gate 				    compare_string_to_modslice_name,
1181*0Sstevel@tonic-gate 				    &srcitem);
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 			free_modslice_object((modslice_t *)srcitem->obj);
1184*0Sstevel@tonic-gate 			free((void *)srcitem);
1185*0Sstevel@tonic-gate 		    }
1186*0Sstevel@tonic-gate 		}
1187*0Sstevel@tonic-gate 	    }
1188*0Sstevel@tonic-gate 
1189*0Sstevel@tonic-gate 	    free_modslice_object(modified);
1190*0Sstevel@tonic-gate 	}
1191*0Sstevel@tonic-gate 
1192*0Sstevel@tonic-gate 	return (error);
1193*0Sstevel@tonic-gate }
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate /*
1196*0Sstevel@tonic-gate  * FUNCTION:	pick_from_best_hba_and_disk(dlist_t *slices,
1197*0Sstevel@tonic-gate  *			dlist_t *used, dm_descriptor_t *chosen)
1198*0Sstevel@tonic-gate  *
1199*0Sstevel@tonic-gate  * INPUT:	slices	- a dlist_t poitner to a list of slices
1200*0Sstevel@tonic-gate  *		used	- a dlist_t pointer to a list of used slices
1201*0Sstevel@tonic-gate  *		chosen  - a dm_descriptor_t pointer to hold the result
1202*0Sstevel@tonic-gate  *
1203*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1204*0Sstevel@tonic-gate  *			 !0 otherwise
1205*0Sstevel@tonic-gate  *
1206*0Sstevel@tonic-gate  * PURPOSE:	Examines the input list of slices and chooses the one
1207*0Sstevel@tonic-gate  *		that is on the least used HBA and disk.
1208*0Sstevel@tonic-gate  *
1209*0Sstevel@tonic-gate  *		HBA and disk usage is determined by examining the input
1210*0Sstevel@tonic-gate  *		list of used slices and counting the number of slices
1211*0Sstevel@tonic-gate  *		each HBA and disk contributes.
1212*0Sstevel@tonic-gate  *
1213*0Sstevel@tonic-gate  * 		The HBA which contributes the fewest is selected, and
1214*0Sstevel@tonic-gate  *		then the disk on that HBA which contributes the fewest
1215*0Sstevel@tonic-gate  *		is selected.
1216*0Sstevel@tonic-gate  *
1217*0Sstevel@tonic-gate  *		The largest slice from that disk is then returned.
1218*0Sstevel@tonic-gate  */
1219*0Sstevel@tonic-gate static int
1220*0Sstevel@tonic-gate pick_from_best_hba_and_disk(
1221*0Sstevel@tonic-gate 	dlist_t		*slices,
1222*0Sstevel@tonic-gate 	dlist_t		*used,
1223*0Sstevel@tonic-gate 	dm_descriptor_t *chosen)
1224*0Sstevel@tonic-gate {
1225*0Sstevel@tonic-gate 	dlist_t		*iter = NULL;
1226*0Sstevel@tonic-gate 	dlist_t		*iter1 = NULL;
1227*0Sstevel@tonic-gate 	dlist_t		*iter2 = NULL;
1228*0Sstevel@tonic-gate 	dlist_t		*item = NULL;
1229*0Sstevel@tonic-gate 
1230*0Sstevel@tonic-gate 	dlist_t		*used_slice_hbas = NULL;
1231*0Sstevel@tonic-gate 
1232*0Sstevel@tonic-gate 	int		maxuses = 128;
1233*0Sstevel@tonic-gate 	int		maxslices = VTOC_SIZE;  /* meta.h */
1234*0Sstevel@tonic-gate 
1235*0Sstevel@tonic-gate 	int		i = 0;
1236*0Sstevel@tonic-gate 	int 		error = 0;
1237*0Sstevel@tonic-gate 
1238*0Sstevel@tonic-gate 	/*
1239*0Sstevel@tonic-gate 	 * allocate an array to hold lists of slices grouped by
1240*0Sstevel@tonic-gate 	 * HBA contribution... the list indexed by N is the list
1241*0Sstevel@tonic-gate 	 * of slices that are on HBAs contributing N slices
1242*0Sstevel@tonic-gate 	 */
1243*0Sstevel@tonic-gate 	dlist_t **prefhbas = (dlist_t **)calloc(maxuses, sizeof (dlist_t *));
1244*0Sstevel@tonic-gate 
1245*0Sstevel@tonic-gate 	/*
1246*0Sstevel@tonic-gate 	 * allocate an array to hold lists of slices grouped by
1247*0Sstevel@tonic-gate 	 * disk contribution... the list indexed by N is the list
1248*0Sstevel@tonic-gate 	 * of slices that are on disks contributing N slices
1249*0Sstevel@tonic-gate 	 */
1250*0Sstevel@tonic-gate 	dlist_t **prefdisks = (dlist_t **)calloc(maxslices, sizeof (dlist_t *));
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate 	*chosen = (dm_descriptor_t)0;
1253*0Sstevel@tonic-gate 
1254*0Sstevel@tonic-gate 	if (prefhbas == NULL || prefdisks == NULL) {
1255*0Sstevel@tonic-gate 	    free(prefhbas);
1256*0Sstevel@tonic-gate 	    free(prefdisks);
1257*0Sstevel@tonic-gate 	    return (ENOMEM);
1258*0Sstevel@tonic-gate 	}
1259*0Sstevel@tonic-gate 
1260*0Sstevel@tonic-gate 	/*
1261*0Sstevel@tonic-gate 	 * precompute the used slices' lists of HBAS: iterate the list
1262*0Sstevel@tonic-gate 	 * of used slices and determine the HBA(s) each is connected thru.
1263*0Sstevel@tonic-gate 	 * construct a list of lists containing the HBAs.
1264*0Sstevel@tonic-gate 	 */
1265*0Sstevel@tonic-gate 	for (iter = used;
1266*0Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
1267*0Sstevel@tonic-gate 	    iter = iter->next) {
1268*0Sstevel@tonic-gate 
1269*0Sstevel@tonic-gate 	    devconfig_t	*uslice = (devconfig_t *)iter->obj;
1270*0Sstevel@tonic-gate 	    dm_descriptor_t udisk = NULL;
1271*0Sstevel@tonic-gate 	    char	*uname = NULL;
1272*0Sstevel@tonic-gate 	    dlist_t	*uhbas = NULL;
1273*0Sstevel@tonic-gate 
1274*0Sstevel@tonic-gate 	    /* need to use disk to get to HBAs because */
1275*0Sstevel@tonic-gate 	    /* the slice doesn't exist yet */
1276*0Sstevel@tonic-gate 	    ((error = devconfig_get_name(uslice, &uname)) != 0) ||
1277*0Sstevel@tonic-gate 	    (error = get_disk_for_named_slice(uname, &udisk)) ||
1278*0Sstevel@tonic-gate 	    (error = disk_get_hbas(udisk, &uhbas));
1279*0Sstevel@tonic-gate 	    if (error == 0) {
1280*0Sstevel@tonic-gate 		if ((item = dlist_new_item((void *)uhbas)) == NULL) {
1281*0Sstevel@tonic-gate 		    error = ENOMEM;
1282*0Sstevel@tonic-gate 		} else {
1283*0Sstevel@tonic-gate 		    used_slice_hbas = dlist_append(
1284*0Sstevel@tonic-gate 			    item, used_slice_hbas, AT_HEAD);
1285*0Sstevel@tonic-gate 		}
1286*0Sstevel@tonic-gate 	    }
1287*0Sstevel@tonic-gate 	}
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate 	/*
1290*0Sstevel@tonic-gate 	 * iterate the list of chosen slices and for each,
1291*0Sstevel@tonic-gate 	 * determine how many other slices from its HBA(s)
1292*0Sstevel@tonic-gate 	 * are already being used...
1293*0Sstevel@tonic-gate 	 *
1294*0Sstevel@tonic-gate 	 * iter steps thru the list of slices
1295*0Sstevel@tonic-gate 	 * iter1 steps thru each of the slice's HBAs
1296*0Sstevel@tonic-gate 	 * iter2 steps thru the precomputed list of used slice's HBAs
1297*0Sstevel@tonic-gate 	 * dlist_contains then searches each used slice's HBAs
1298*0Sstevel@tonic-gate 	 *   to see if it contains iter1's HBA
1299*0Sstevel@tonic-gate 	 *
1300*0Sstevel@tonic-gate 	 * If it does, increment the count for that HBA.
1301*0Sstevel@tonic-gate 	 */
1302*0Sstevel@tonic-gate 	for (iter = slices;
1303*0Sstevel@tonic-gate 	    (iter != NULL) && (error == 0);
1304*0Sstevel@tonic-gate 	    iter = iter->next) {
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate 	    dm_descriptor_t slice = (uintptr_t)iter->obj;
1307*0Sstevel@tonic-gate 	    dlist_t	*hbas = NULL;
1308*0Sstevel@tonic-gate 	    int		n = 0; /* # slices each HBA contributes */
1309*0Sstevel@tonic-gate 
1310*0Sstevel@tonic-gate 	    if ((error = slice_get_hbas(slice, &hbas)) != 0) {
1311*0Sstevel@tonic-gate 		continue;
1312*0Sstevel@tonic-gate 	    }
1313*0Sstevel@tonic-gate 
1314*0Sstevel@tonic-gate 	    for (iter1 = hbas; iter1 != NULL; iter1 = iter1->next) {
1315*0Sstevel@tonic-gate 		for (iter2 = used_slice_hbas; iter2 != NULL;
1316*0Sstevel@tonic-gate 		    iter2 = iter2->next) {
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate 		    dlist_t *uhbas = (dlist_t *)iter2->obj;
1319*0Sstevel@tonic-gate 		    if (dlist_contains(uhbas, iter1->obj,
1320*0Sstevel@tonic-gate 				compare_descriptor_names) == B_TRUE) {
1321*0Sstevel@tonic-gate 			n++;
1322*0Sstevel@tonic-gate 		    }
1323*0Sstevel@tonic-gate 		}
1324*0Sstevel@tonic-gate 	    }
1325*0Sstevel@tonic-gate 
1326*0Sstevel@tonic-gate 	    dlist_free_items(hbas, NULL);
1327*0Sstevel@tonic-gate 
1328*0Sstevel@tonic-gate 	    /* group slices from HBAs contributing more than maxuses */
1329*0Sstevel@tonic-gate 	    if (n >= maxuses) {
1330*0Sstevel@tonic-gate 		n = maxuses - 1;
1331*0Sstevel@tonic-gate 	    }
1332*0Sstevel@tonic-gate 
1333*0Sstevel@tonic-gate 	    /* add slice to list in descending size order */
1334*0Sstevel@tonic-gate 	    if ((item = dlist_new_item((void*)slice)) == NULL) {
1335*0Sstevel@tonic-gate 		error = ENOMEM;
1336*0Sstevel@tonic-gate 	    } else {
1337*0Sstevel@tonic-gate 		prefhbas[n] =
1338*0Sstevel@tonic-gate 		    dlist_insert_ordered(
1339*0Sstevel@tonic-gate 			    item,
1340*0Sstevel@tonic-gate 			    prefhbas[n],
1341*0Sstevel@tonic-gate 			    DESCENDING,
1342*0Sstevel@tonic-gate 			    compare_slice_sizes);
1343*0Sstevel@tonic-gate 	    }
1344*0Sstevel@tonic-gate 	}
1345*0Sstevel@tonic-gate 
1346*0Sstevel@tonic-gate 	/* free list of lists of used slices HBAs */
1347*0Sstevel@tonic-gate 	for (iter = used_slice_hbas; iter != NULL; iter = iter->next) {
1348*0Sstevel@tonic-gate 	    dlist_free_items((dlist_t *)iter->obj, NULL);
1349*0Sstevel@tonic-gate 	}
1350*0Sstevel@tonic-gate 	dlist_free_items(used_slice_hbas, NULL);
1351*0Sstevel@tonic-gate 
1352*0Sstevel@tonic-gate 	/*
1353*0Sstevel@tonic-gate 	 * Select the list of slices that are on the HBA(s) contributing
1354*0Sstevel@tonic-gate 	 * the fewest slices... iterate these slices and for each, detemmine
1355*0Sstevel@tonic-gate 	 * how many other slices from its disk are already being used...
1356*0Sstevel@tonic-gate 	 */
1357*0Sstevel@tonic-gate 	for (i = 0; (i < maxuses) && (error == 0); i++) {
1358*0Sstevel@tonic-gate 
1359*0Sstevel@tonic-gate 	    for (iter = (dlist_t *)prefhbas[i];
1360*0Sstevel@tonic-gate 		(iter != NULL) && (error == 0);
1361*0Sstevel@tonic-gate 		iter = iter->next) {
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 		dm_descriptor_t slice = (uintptr_t)iter->obj;
1364*0Sstevel@tonic-gate 		dm_descriptor_t disk;
1365*0Sstevel@tonic-gate 		int		n = 0;
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 		(void) slice_get_disk(slice, &disk);
1368*0Sstevel@tonic-gate 
1369*0Sstevel@tonic-gate 		/*
1370*0Sstevel@tonic-gate 		 * count how many slices this slice's disk is contributing
1371*0Sstevel@tonic-gate 		 * by comparing it to the list of used slices
1372*0Sstevel@tonic-gate 		 */
1373*0Sstevel@tonic-gate 		for (iter1 = _used_slices; iter1 != NULL; iter1 = iter1->next) {
1374*0Sstevel@tonic-gate 		    usedslice_t *used = (usedslice_t *)iter1->obj;
1375*0Sstevel@tonic-gate 		    if (compare_descriptors(
1376*0Sstevel@tonic-gate 				(void *)disk, (void *)used->disk) == 0) {
1377*0Sstevel@tonic-gate 			n++;
1378*0Sstevel@tonic-gate 		    }
1379*0Sstevel@tonic-gate 		}
1380*0Sstevel@tonic-gate 
1381*0Sstevel@tonic-gate 		/* add slice to list in descending size order */
1382*0Sstevel@tonic-gate 		if ((item = dlist_new_item((void *)slice)) == NULL) {
1383*0Sstevel@tonic-gate 		    error = ENOMEM;
1384*0Sstevel@tonic-gate 		} else {
1385*0Sstevel@tonic-gate 		    prefdisks[n] =
1386*0Sstevel@tonic-gate 			dlist_insert_ordered(
1387*0Sstevel@tonic-gate 				item,
1388*0Sstevel@tonic-gate 				prefdisks[n],
1389*0Sstevel@tonic-gate 				DESCENDING,
1390*0Sstevel@tonic-gate 				compare_slice_sizes);
1391*0Sstevel@tonic-gate 		}
1392*0Sstevel@tonic-gate 	    }
1393*0Sstevel@tonic-gate 	}
1394*0Sstevel@tonic-gate 
1395*0Sstevel@tonic-gate 	if (error == 0) {
1396*0Sstevel@tonic-gate 	    /* select largest slice from least used disk */
1397*0Sstevel@tonic-gate 	    for (i = 0; (i < maxslices) && (*chosen == NULL); i++) {
1398*0Sstevel@tonic-gate 		if (prefdisks[i] != NULL) {
1399*0Sstevel@tonic-gate 		    *chosen = (uintptr_t)prefdisks[i]->obj;
1400*0Sstevel@tonic-gate 		}
1401*0Sstevel@tonic-gate 	    }
1402*0Sstevel@tonic-gate 	}
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate 	for (i = 0; i < maxuses; i++) {
1405*0Sstevel@tonic-gate 	    dlist_free_items(prefhbas[i], NULL);
1406*0Sstevel@tonic-gate 	}
1407*0Sstevel@tonic-gate 	for (i = 0; i < maxslices; i++) {
1408*0Sstevel@tonic-gate 	    dlist_free_items(prefdisks[i], NULL);
1409*0Sstevel@tonic-gate 	}
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 	free((void*)prefhbas);
1412*0Sstevel@tonic-gate 	free((void*)prefdisks);
1413*0Sstevel@tonic-gate 
1414*0Sstevel@tonic-gate 	return (error);
1415*0Sstevel@tonic-gate }
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate /*
1418*0Sstevel@tonic-gate  * FUNCTION:	slice_on_unique_hba(dm_descriptor_t slice,
1419*0Sstevel@tonic-gate  *			dlist_t *used, dlist_t *used_hbas,
1420*0Sstevel@tonic-gate  *			boolean_t *unique)
1421*0Sstevel@tonic-gate  *
1422*0Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1423*0Sstevel@tonic-gate  *		used	- a dlist_t pointer to a list of used slices
1424*0Sstevel@tonic-gate  *		used_hbas - a dlist_t pointer to a list of used_hbas
1425*0Sstevel@tonic-gate  *		unique	- a boolean_t pointer to hold the result
1426*0Sstevel@tonic-gate  *
1427*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1428*0Sstevel@tonic-gate  *			 !0 otherwise
1429*0Sstevel@tonic-gate  *
1430*0Sstevel@tonic-gate  * PURPOSE:	Determines if the input slice is connected thru the same HBA
1431*0Sstevel@tonic-gate  *		as a slice in the used list.
1432*0Sstevel@tonic-gate  *
1433*0Sstevel@tonic-gate  *		Also checks to see if the input slice is connected thru any
1434*0Sstevel@tonic-gate  *		HBA in the used_hbas list.
1435*0Sstevel@tonic-gate  *
1436*0Sstevel@tonic-gate  *		If the slice is found to be on a unique HBA, bool is set
1437*0Sstevel@tonic-gate  *		to B_TRUE, B_FALSE otherwise.
1438*0Sstevel@tonic-gate  */
1439*0Sstevel@tonic-gate static int
1440*0Sstevel@tonic-gate slice_on_unique_hba(
1441*0Sstevel@tonic-gate 	dm_descriptor_t	slice,
1442*0Sstevel@tonic-gate 	dlist_t		*used,
1443*0Sstevel@tonic-gate 	dlist_t		*used_hbas,
1444*0Sstevel@tonic-gate 	boolean_t	*unique)
1445*0Sstevel@tonic-gate {
1446*0Sstevel@tonic-gate 	dlist_t		*iter	= NULL;
1447*0Sstevel@tonic-gate 	dlist_t		*iter1	= NULL;
1448*0Sstevel@tonic-gate 
1449*0Sstevel@tonic-gate 	dlist_t		*hbas = NULL;
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 	int		error	= 0;
1452*0Sstevel@tonic-gate 
1453*0Sstevel@tonic-gate 	*unique = B_TRUE;
1454*0Sstevel@tonic-gate 
1455*0Sstevel@tonic-gate 	if ((error = slice_get_hbas(slice, &hbas)) != 0) {
1456*0Sstevel@tonic-gate 	    return (error);
1457*0Sstevel@tonic-gate 	}
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 	/*
1460*0Sstevel@tonic-gate 	 * check to see if any of slice's HBAs is the same
1461*0Sstevel@tonic-gate 	 * as the HBA for any of the used
1462*0Sstevel@tonic-gate 	 */
1463*0Sstevel@tonic-gate 	for (iter = used;
1464*0Sstevel@tonic-gate 	    (iter != NULL) && (*unique == B_TRUE) && (error == 0);
1465*0Sstevel@tonic-gate 	    iter = iter->next) {
1466*0Sstevel@tonic-gate 
1467*0Sstevel@tonic-gate 	    devconfig_t	*dev = (devconfig_t *)iter->obj;
1468*0Sstevel@tonic-gate 	    if (devconfig_isA(dev, TYPE_SLICE)) {
1469*0Sstevel@tonic-gate 
1470*0Sstevel@tonic-gate 		dm_descriptor_t	odisk = NULL;
1471*0Sstevel@tonic-gate 		char		*oname = NULL;
1472*0Sstevel@tonic-gate 		dlist_t		*ohbas = NULL;
1473*0Sstevel@tonic-gate 
1474*0Sstevel@tonic-gate 		/* get HBAs for other slice using its disk */
1475*0Sstevel@tonic-gate 		/* because the slice doesn't exist yet. */
1476*0Sstevel@tonic-gate 		((error = devconfig_get_name(dev, &oname)) != 0) ||
1477*0Sstevel@tonic-gate 		(error = get_disk_for_named_slice(oname, &odisk)) ||
1478*0Sstevel@tonic-gate 		(error = disk_get_hbas(odisk, &ohbas));
1479*0Sstevel@tonic-gate 
1480*0Sstevel@tonic-gate 		/* any HBA overlap? */
1481*0Sstevel@tonic-gate 		for (iter1 = hbas;
1482*0Sstevel@tonic-gate 		    (iter1 != NULL) && (*unique == B_TRUE) && (error == 0);
1483*0Sstevel@tonic-gate 		    iter1 = iter1->next) {
1484*0Sstevel@tonic-gate 
1485*0Sstevel@tonic-gate 		    if (dlist_contains(ohbas, iter1->obj,
1486*0Sstevel@tonic-gate 				compare_descriptor_names) == B_TRUE) {
1487*0Sstevel@tonic-gate 			*unique = B_FALSE;
1488*0Sstevel@tonic-gate 		    }
1489*0Sstevel@tonic-gate 		}
1490*0Sstevel@tonic-gate 		dlist_free_items(ohbas, NULL);
1491*0Sstevel@tonic-gate 	    }
1492*0Sstevel@tonic-gate 	}
1493*0Sstevel@tonic-gate 
1494*0Sstevel@tonic-gate 	/*
1495*0Sstevel@tonic-gate 	 * check to see if any of slice's HBAs is the contained
1496*0Sstevel@tonic-gate 	 * in the list of used hbas
1497*0Sstevel@tonic-gate 	 */
1498*0Sstevel@tonic-gate 	for (iter = hbas;
1499*0Sstevel@tonic-gate 	    (iter != NULL) && (*unique == B_TRUE) && (error == 0);
1500*0Sstevel@tonic-gate 	    iter = iter->next) {
1501*0Sstevel@tonic-gate 	    if (dlist_contains(used_hbas,
1502*0Sstevel@tonic-gate 		iter->obj, compare_descriptor_names) == B_TRUE) {
1503*0Sstevel@tonic-gate 		*unique = B_FALSE;
1504*0Sstevel@tonic-gate 	    }
1505*0Sstevel@tonic-gate 	}
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 	dlist_free_items(hbas, NULL);
1508*0Sstevel@tonic-gate 
1509*0Sstevel@tonic-gate 	return (error);
1510*0Sstevel@tonic-gate }
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate /*
1513*0Sstevel@tonic-gate  * FUNCTION:	slice_on_unique_disk(dm_descriptor_t slice,
1514*0Sstevel@tonic-gate  *			dlist_t *used, dlist_t *used_disks,
1515*0Sstevel@tonic-gate  *			boolean_t *unique)
1516*0Sstevel@tonic-gate  *
1517*0Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1518*0Sstevel@tonic-gate  *		used	- a dlist_t pointer to a list of used slices
1519*0Sstevel@tonic-gate  *		othervols - a dlist_t pointer to a list of other volumes
1520*0Sstevel@tonic-gate  *		bool	- a boolean_t pointer to hold the result
1521*0Sstevel@tonic-gate  *
1522*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1523*0Sstevel@tonic-gate  *			 !0 otherwise
1524*0Sstevel@tonic-gate  *
1525*0Sstevel@tonic-gate  * PURPOSE:	Determines if the input slice is on a drive that is not
1526*0Sstevel@tonic-gate  *		part of any volume in the othervols list, or on the same
1527*0Sstevel@tonic-gate  *		drive as any slice in the used list.
1528*0Sstevel@tonic-gate  *
1529*0Sstevel@tonic-gate  *		If the slice is found to be on a unique disk, bool is set
1530*0Sstevel@tonic-gate  *		to B_TRUE, B_FALSE otherwise.
1531*0Sstevel@tonic-gate  */
1532*0Sstevel@tonic-gate static int
1533*0Sstevel@tonic-gate slice_on_unique_disk(
1534*0Sstevel@tonic-gate 	dm_descriptor_t	slice,
1535*0Sstevel@tonic-gate 	dlist_t		*used,
1536*0Sstevel@tonic-gate 	dlist_t		*used_disks,
1537*0Sstevel@tonic-gate 	boolean_t	*unique)
1538*0Sstevel@tonic-gate {
1539*0Sstevel@tonic-gate 	dm_descriptor_t	disk = NULL;
1540*0Sstevel@tonic-gate 	dlist_t		*iter = NULL;
1541*0Sstevel@tonic-gate 	int		error = 0;
1542*0Sstevel@tonic-gate 
1543*0Sstevel@tonic-gate 	*unique = B_TRUE;
1544*0Sstevel@tonic-gate 
1545*0Sstevel@tonic-gate 	if ((error = slice_get_disk(slice, &disk)) != 0) {
1546*0Sstevel@tonic-gate 	    return (error);
1547*0Sstevel@tonic-gate 	}
1548*0Sstevel@tonic-gate 
1549*0Sstevel@tonic-gate 	/*
1550*0Sstevel@tonic-gate 	 * check to see if this disk is the same as the
1551*0Sstevel@tonic-gate 	 * disk for any of the used
1552*0Sstevel@tonic-gate 	 */
1553*0Sstevel@tonic-gate 	for (iter = used;
1554*0Sstevel@tonic-gate 	    (iter != NULL) && (*unique == B_TRUE) && (error == 0);
1555*0Sstevel@tonic-gate 	    iter = iter->next) {
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate 	    devconfig_t	*dev = (devconfig_t *)iter->obj;
1558*0Sstevel@tonic-gate 
1559*0Sstevel@tonic-gate 	    if (devconfig_isA(dev, TYPE_SLICE)) {
1560*0Sstevel@tonic-gate 
1561*0Sstevel@tonic-gate 		/* get disk for otherslice */
1562*0Sstevel@tonic-gate 		dm_descriptor_t	odisk = NULL;
1563*0Sstevel@tonic-gate 		char		*oname = NULL;
1564*0Sstevel@tonic-gate 
1565*0Sstevel@tonic-gate 		((error = devconfig_get_name(dev, &oname)) != 0) ||
1566*0Sstevel@tonic-gate 		(error = get_disk_for_named_slice(oname, &odisk));
1567*0Sstevel@tonic-gate 
1568*0Sstevel@tonic-gate 		if ((error == 0) &&
1569*0Sstevel@tonic-gate 			(compare_descriptor_names(
1570*0Sstevel@tonic-gate 				(void*)disk, (void*)odisk) == 0)) {
1571*0Sstevel@tonic-gate 		    /* origslice is on same disk, stop */
1572*0Sstevel@tonic-gate 		    *unique = B_FALSE;
1573*0Sstevel@tonic-gate 		}
1574*0Sstevel@tonic-gate 	    }
1575*0Sstevel@tonic-gate 	}
1576*0Sstevel@tonic-gate 
1577*0Sstevel@tonic-gate 	/* check disk against the used disks */
1578*0Sstevel@tonic-gate 	if ((error == 0) && (*unique == B_TRUE) &&
1579*0Sstevel@tonic-gate 		dlist_contains(used_disks, (void *)disk,
1580*0Sstevel@tonic-gate 			compare_descriptor_names) == B_TRUE) {
1581*0Sstevel@tonic-gate 		*unique = B_FALSE;
1582*0Sstevel@tonic-gate 	}
1583*0Sstevel@tonic-gate 
1584*0Sstevel@tonic-gate 	return (error);
1585*0Sstevel@tonic-gate }
1586*0Sstevel@tonic-gate 
1587*0Sstevel@tonic-gate /*
1588*0Sstevel@tonic-gate  * FUNCTION:	slice_has_same_disk_geom(dm_descriptor_t slice,
1589*0Sstevel@tonic-gate  *			dlist_t *used, boolean_t *has_same_geom)
1590*0Sstevel@tonic-gate  *
1591*0Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1592*0Sstevel@tonic-gate  *		used	- a dlist_t pointer to a list of used slices
1593*0Sstevel@tonic-gate  *		bool	- a boolean_t pointer to hold the result
1594*0Sstevel@tonic-gate  *
1595*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1596*0Sstevel@tonic-gate  *			 !0 otherwise
1597*0Sstevel@tonic-gate  *
1598*0Sstevel@tonic-gate  * PURPOSE:	Determines if the input slice is on a drive with similar
1599*0Sstevel@tonic-gate  *		hardware geometry as the slices in the used list.
1600*0Sstevel@tonic-gate  *
1601*0Sstevel@tonic-gate  *		If the slice is found to be on a disk with similar geometry,
1602*0Sstevel@tonic-gate  *		bool is set to B_TRUE, B_FALSE otherwise.
1603*0Sstevel@tonic-gate  *
1604*0Sstevel@tonic-gate  *		The comparison is based on the available disk geometry
1605*0Sstevel@tonic-gate  *		information which may not be relevant or accurate for
1606*0Sstevel@tonic-gate  *		EFI labeled disks, so the disk drive type needs to be
1607*0Sstevel@tonic-gate  *		checked	as well.
1608*0Sstevel@tonic-gate  */
1609*0Sstevel@tonic-gate static int
1610*0Sstevel@tonic-gate slice_has_same_disk_geom(
1611*0Sstevel@tonic-gate 	dm_descriptor_t	slice,
1612*0Sstevel@tonic-gate 	dlist_t		*used,
1613*0Sstevel@tonic-gate 	boolean_t	*has_same_geom)
1614*0Sstevel@tonic-gate {
1615*0Sstevel@tonic-gate 	dm_descriptor_t	disk = NULL;
1616*0Sstevel@tonic-gate 	boolean_t	efi = B_FALSE;
1617*0Sstevel@tonic-gate 	uint64_t	bsize	= 0;
1618*0Sstevel@tonic-gate 	uint64_t	ncyls	= 0;
1619*0Sstevel@tonic-gate 	uint64_t	nsects	= 0;
1620*0Sstevel@tonic-gate 	uint64_t	nheads	= 0;
1621*0Sstevel@tonic-gate 	dlist_t		*iter	= NULL;
1622*0Sstevel@tonic-gate 	int		error	= 0;
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate 	*has_same_geom = B_TRUE;
1625*0Sstevel@tonic-gate 
1626*0Sstevel@tonic-gate 	((error = slice_get_disk(slice, &disk)) != 0) ||
1627*0Sstevel@tonic-gate 	(error = disk_get_is_efi(disk, &efi)) ||
1628*0Sstevel@tonic-gate 	(error = disk_get_blocksize(disk, &bsize));
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 	if ((error == 0) && (efi == B_FALSE)) {
1631*0Sstevel@tonic-gate 	    ((error = disk_get_ncylinders(disk, &ncyls)) != 0) ||
1632*0Sstevel@tonic-gate 	    (error = disk_get_nheads(disk, &nheads)) ||
1633*0Sstevel@tonic-gate 	    (error = disk_get_nsectors(disk, &nsects));
1634*0Sstevel@tonic-gate 	}
1635*0Sstevel@tonic-gate 
1636*0Sstevel@tonic-gate 	if (error != 0) {
1637*0Sstevel@tonic-gate 	    return (error);
1638*0Sstevel@tonic-gate 	}
1639*0Sstevel@tonic-gate 
1640*0Sstevel@tonic-gate 	/*
1641*0Sstevel@tonic-gate 	 * check to see if slice's disk has the same geometry
1642*0Sstevel@tonic-gate 	 * as the disks for the slices in the used list
1643*0Sstevel@tonic-gate 	 */
1644*0Sstevel@tonic-gate 	for (iter = used;
1645*0Sstevel@tonic-gate 	    (iter != NULL) && (*has_same_geom == B_TRUE) && (error = 0);
1646*0Sstevel@tonic-gate 	    iter = iter->next) {
1647*0Sstevel@tonic-gate 
1648*0Sstevel@tonic-gate 	    devconfig_t	*dev = (devconfig_t *)iter->obj;
1649*0Sstevel@tonic-gate 
1650*0Sstevel@tonic-gate 	    if (devconfig_isA(dev, TYPE_SLICE)) {
1651*0Sstevel@tonic-gate 
1652*0Sstevel@tonic-gate 		/* get disk info for otherslice */
1653*0Sstevel@tonic-gate 		dm_descriptor_t	odisk	= NULL;
1654*0Sstevel@tonic-gate 		char		*oname	= NULL;
1655*0Sstevel@tonic-gate 		boolean_t	oefi = B_FALSE;
1656*0Sstevel@tonic-gate 		uint64_t	obsize	= 0;
1657*0Sstevel@tonic-gate 		uint64_t	oncyls	= 0;
1658*0Sstevel@tonic-gate 		uint64_t	onsects = 0;
1659*0Sstevel@tonic-gate 		uint64_t	onheads = 0;
1660*0Sstevel@tonic-gate 
1661*0Sstevel@tonic-gate 		((error = devconfig_get_name(dev, &oname)) != 0) ||
1662*0Sstevel@tonic-gate 		(error = get_disk_for_named_slice(oname, &odisk)) ||
1663*0Sstevel@tonic-gate 		(error = disk_get_is_efi(odisk, &oefi)) ||
1664*0Sstevel@tonic-gate 		(error = disk_get_blocksize(odisk, &obsize));
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 		if ((error == 0) && (oefi == B_FALSE)) {
1667*0Sstevel@tonic-gate 		    ((error = disk_get_ncylinders(odisk, &oncyls)) != 0) ||
1668*0Sstevel@tonic-gate 		    (error = disk_get_nheads(odisk, &onheads)) ||
1669*0Sstevel@tonic-gate 		    (error = disk_get_nsectors(odisk, &onsects));
1670*0Sstevel@tonic-gate 		}
1671*0Sstevel@tonic-gate 
1672*0Sstevel@tonic-gate 		if (error == 0) {
1673*0Sstevel@tonic-gate 		    if ((bsize != obsize) || (ncyls != oncyls) ||
1674*0Sstevel@tonic-gate 			(nsects != onsects) || (nheads != onheads)) {
1675*0Sstevel@tonic-gate 			/* this disk has a different geometry */
1676*0Sstevel@tonic-gate 			*has_same_geom = B_FALSE;
1677*0Sstevel@tonic-gate 		    }
1678*0Sstevel@tonic-gate 		}
1679*0Sstevel@tonic-gate 	    }
1680*0Sstevel@tonic-gate 	}
1681*0Sstevel@tonic-gate 
1682*0Sstevel@tonic-gate 	return (error);
1683*0Sstevel@tonic-gate }
1684*0Sstevel@tonic-gate 
1685*0Sstevel@tonic-gate /*
1686*0Sstevel@tonic-gate  * FUNCTION:	slice_on_similar_bus(dm_descriptor_t slice,
1687*0Sstevel@tonic-gate  *			dlist_t *used, boolean_t *on_smlr_bus)
1688*0Sstevel@tonic-gate  *
1689*0Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1690*0Sstevel@tonic-gate  *		used	- a dlist_t pointer to a list of used slices
1691*0Sstevel@tonic-gate  *		bool	- a boolean_t pointer to hold the result
1692*0Sstevel@tonic-gate  *
1693*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1694*0Sstevel@tonic-gate  *			 !0 otherwise
1695*0Sstevel@tonic-gate  *
1696*0Sstevel@tonic-gate  * PURPOSE:	Determines if the input slice is connected thru a bus with
1697*0Sstevel@tonic-gate  *		characteristics similar to the slices in the used list.
1698*0Sstevel@tonic-gate  *
1699*0Sstevel@tonic-gate  *		If the slice is found to be on a similar bus, bool is set
1700*0Sstevel@tonic-gate  *		to B_TRUE, B_FALSE otherwise.
1701*0Sstevel@tonic-gate  *
1702*0Sstevel@tonic-gate  *		The comparison is actually between any of the HBA/controllers
1703*0Sstevel@tonic-gate  *		thru which the slices are connected to the system.
1704*0Sstevel@tonic-gate  *		If any are of similar type (e.g., fibre, SCSI) and
1705*0Sstevel@tonic-gate  *		protocol (SCSI-2, -3, fast/wide), then the slices are
1706*0Sstevel@tonic-gate  *		considered to be on similar busses.
1707*0Sstevel@tonic-gate  */
1708*0Sstevel@tonic-gate static int
1709*0Sstevel@tonic-gate slice_on_similar_bus(
1710*0Sstevel@tonic-gate 	dm_descriptor_t	slice,
1711*0Sstevel@tonic-gate 	dlist_t		*used,
1712*0Sstevel@tonic-gate 	boolean_t	*on_smlr_bus)
1713*0Sstevel@tonic-gate {
1714*0Sstevel@tonic-gate 	dlist_t		*iter	= NULL;
1715*0Sstevel@tonic-gate 	dlist_t		*iter1	= NULL;
1716*0Sstevel@tonic-gate 	dlist_t		*hbas = NULL;
1717*0Sstevel@tonic-gate 	int		error	= 0;
1718*0Sstevel@tonic-gate 
1719*0Sstevel@tonic-gate 	/* if there are no used slices, then the bus is similar */
1720*0Sstevel@tonic-gate 	*on_smlr_bus = B_TRUE;
1721*0Sstevel@tonic-gate 	if (dlist_length(used) == 0) {
1722*0Sstevel@tonic-gate 	    return (0);
1723*0Sstevel@tonic-gate 	}
1724*0Sstevel@tonic-gate 
1725*0Sstevel@tonic-gate 	(error = slice_get_hbas(slice, &hbas));
1726*0Sstevel@tonic-gate 	if (error != 0) {
1727*0Sstevel@tonic-gate 	    return (error);
1728*0Sstevel@tonic-gate 	}
1729*0Sstevel@tonic-gate 
1730*0Sstevel@tonic-gate 	/* if there are used slices, then make sure the bus is similar */
1731*0Sstevel@tonic-gate 	*on_smlr_bus = B_FALSE;
1732*0Sstevel@tonic-gate 	for (iter = hbas;
1733*0Sstevel@tonic-gate 	    (iter != NULL) && (*on_smlr_bus == B_FALSE) && (error == 0);
1734*0Sstevel@tonic-gate 	    iter = iter->next) {
1735*0Sstevel@tonic-gate 
1736*0Sstevel@tonic-gate 	    dm_descriptor_t hba = (uintptr_t)iter->obj;
1737*0Sstevel@tonic-gate 	    char	*type	= NULL;
1738*0Sstevel@tonic-gate 	    boolean_t	fast80	= B_FALSE;
1739*0Sstevel@tonic-gate 	    boolean_t	fast40	= B_FALSE;
1740*0Sstevel@tonic-gate 	    boolean_t	fast20	= B_FALSE;
1741*0Sstevel@tonic-gate 	    boolean_t	wide	= B_FALSE;
1742*0Sstevel@tonic-gate 
1743*0Sstevel@tonic-gate 	    ((error = hba_get_type(hba, &type)) != 0) ||
1744*0Sstevel@tonic-gate 	    (error = hba_is_fast_80(hba, &fast80)) ||
1745*0Sstevel@tonic-gate 	    (error = hba_is_fast_40(hba, &fast40)) ||
1746*0Sstevel@tonic-gate 	    (error = hba_is_fast_20(hba, &fast20)) ||
1747*0Sstevel@tonic-gate 	    (error = hba_supports_wide(hba, &wide));
1748*0Sstevel@tonic-gate 	    if (error != 0) {
1749*0Sstevel@tonic-gate 		continue;
1750*0Sstevel@tonic-gate 	    }
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate 	    /* check against the HBAs for the used slices */
1753*0Sstevel@tonic-gate 	    for (iter1 = used;
1754*0Sstevel@tonic-gate 		(iter1 != NULL) && (*on_smlr_bus == B_FALSE) && (error == 0);
1755*0Sstevel@tonic-gate 		iter1 = iter1->next) {
1756*0Sstevel@tonic-gate 
1757*0Sstevel@tonic-gate 		devconfig_t *used = (devconfig_t *)iter1->obj;
1758*0Sstevel@tonic-gate 
1759*0Sstevel@tonic-gate 		/* get HBAs for otherslice */
1760*0Sstevel@tonic-gate 		dm_descriptor_t	udisk = NULL;
1761*0Sstevel@tonic-gate 		char		*uname = NULL;
1762*0Sstevel@tonic-gate 		dlist_t		*uhbas = NULL;
1763*0Sstevel@tonic-gate 		dlist_t		*iter2 = NULL;
1764*0Sstevel@tonic-gate 
1765*0Sstevel@tonic-gate 		((error = devconfig_get_name(used, &uname)) != 0) ||
1766*0Sstevel@tonic-gate 		(error = get_disk_for_named_slice(uname, &udisk)) ||
1767*0Sstevel@tonic-gate 		(error = disk_get_hbas(udisk, &uhbas));
1768*0Sstevel@tonic-gate 
1769*0Sstevel@tonic-gate 		for (iter2 = uhbas;
1770*0Sstevel@tonic-gate 		    (iter2 != NULL) && (*on_smlr_bus == B_FALSE) &&
1771*0Sstevel@tonic-gate 			(error == 0);
1772*0Sstevel@tonic-gate 		    iter2 = iter2 ->next) {
1773*0Sstevel@tonic-gate 
1774*0Sstevel@tonic-gate 		    dm_descriptor_t uhba = (uintptr_t)iter2->obj;
1775*0Sstevel@tonic-gate 		    char		*utype	= NULL;
1776*0Sstevel@tonic-gate 		    boolean_t	ufast80	= B_FALSE;
1777*0Sstevel@tonic-gate 		    boolean_t	ufast40	= B_FALSE;
1778*0Sstevel@tonic-gate 		    boolean_t	ufast20	= B_FALSE;
1779*0Sstevel@tonic-gate 		    boolean_t	uwide	= B_FALSE;
1780*0Sstevel@tonic-gate 
1781*0Sstevel@tonic-gate 		    ((error = hba_get_type(uhba, &utype)) != 0) ||
1782*0Sstevel@tonic-gate 		    (error = hba_is_fast_80(uhba, &ufast80)) ||
1783*0Sstevel@tonic-gate 		    (error = hba_is_fast_40(uhba, &ufast40)) ||
1784*0Sstevel@tonic-gate 		    (error = hba_is_fast_20(uhba, &ufast20)) ||
1785*0Sstevel@tonic-gate 		    (error = hba_supports_wide(uhba, &uwide));
1786*0Sstevel@tonic-gate 
1787*0Sstevel@tonic-gate 		    if (error == 0) {
1788*0Sstevel@tonic-gate 			/* check sync speed ? */
1789*0Sstevel@tonic-gate 			if ((fast80 == ufast80) && (fast40 == ufast40) &&
1790*0Sstevel@tonic-gate 			    (fast20 == ufast20) && (wide == uwide) &&
1791*0Sstevel@tonic-gate 			    (type == utype)) {
1792*0Sstevel@tonic-gate 			    *on_smlr_bus = B_TRUE;
1793*0Sstevel@tonic-gate 			}
1794*0Sstevel@tonic-gate 		    }
1795*0Sstevel@tonic-gate 		}
1796*0Sstevel@tonic-gate 		dlist_free_items(uhbas, NULL);
1797*0Sstevel@tonic-gate 	    }
1798*0Sstevel@tonic-gate 	}
1799*0Sstevel@tonic-gate 
1800*0Sstevel@tonic-gate 	dlist_free_items(hbas, NULL);
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 	return (error);
1803*0Sstevel@tonic-gate }
1804*0Sstevel@tonic-gate 
1805*0Sstevel@tonic-gate /*
1806*0Sstevel@tonic-gate  * FUNCTION:	slice_has_n_paths(dm_descriptor_t slice,
1807*0Sstevel@tonic-gate  *			uint16_t npaths, boolean_t *has_n_paths)
1808*0Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t handle for the slice of interest
1809*0Sstevel@tonic-gate  * 		npaths	- the number of paths desired
1810*0Sstevel@tonic-gate  *		has_n_paths - a boolean_t pointer to hold the result
1811*0Sstevel@tonic-gate  *
1812*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1813*0Sstevel@tonic-gate  *			 !0 otherwise
1814*0Sstevel@tonic-gate  *
1815*0Sstevel@tonic-gate  * PURPOSE:	Determines if the input slice is connected via npaths.
1816*0Sstevel@tonic-gate  *		has_n_paths is set to B_TRUE if so, B_FALSE otherwise.
1817*0Sstevel@tonic-gate  *
1818*0Sstevel@tonic-gate  *		In order for a disk to have multiple paths, MPXIO must
1819*0Sstevel@tonic-gate  *		be enabled and these conditions should hold:
1820*0Sstevel@tonic-gate  *
1821*0Sstevel@tonic-gate  *			Slice will have one drive object.
1822*0Sstevel@tonic-gate  *			Drive will have one HBA (scsi_vhci)
1823*0Sstevel@tonic-gate  *			Drive will have one alias.
1824*0Sstevel@tonic-gate  *			Drive will have possibly > 1 paths.
1825*0Sstevel@tonic-gate  *
1826*0Sstevel@tonic-gate  *		Getting the HBAs and aliases for the disk is relatively
1827*0Sstevel@tonic-gate  *		expensive, so they aren't checked.  The actual number of
1828*0Sstevel@tonic-gate  *		paths is only checked if MPXIO is known to be enabled on
1829*0Sstevel@tonic-gate  *		the system and the input npaths is > 1.
1830*0Sstevel@tonic-gate  */
1831*0Sstevel@tonic-gate static int
1832*0Sstevel@tonic-gate slice_has_n_paths(
1833*0Sstevel@tonic-gate 	dm_descriptor_t	slice,
1834*0Sstevel@tonic-gate 	uint16_t	npaths,
1835*0Sstevel@tonic-gate 	boolean_t	*has_n_paths)
1836*0Sstevel@tonic-gate {
1837*0Sstevel@tonic-gate 	int		error	= 0;
1838*0Sstevel@tonic-gate 
1839*0Sstevel@tonic-gate 	*has_n_paths = B_FALSE;
1840*0Sstevel@tonic-gate 
1841*0Sstevel@tonic-gate 	if ((npaths > 1) && (is_mpxio_enabled() == B_TRUE)) {
1842*0Sstevel@tonic-gate 
1843*0Sstevel@tonic-gate 	    dm_descriptor_t	disk	= NULL;
1844*0Sstevel@tonic-gate 	    dlist_t		*paths	= NULL;
1845*0Sstevel@tonic-gate 
1846*0Sstevel@tonic-gate 	    ((error = slice_get_disk(slice, &disk)) != 0) ||
1847*0Sstevel@tonic-gate 	    (error = disk_get_paths(disk, &paths));
1848*0Sstevel@tonic-gate 
1849*0Sstevel@tonic-gate 	    if ((error == 0) && (dlist_length(paths) == npaths)) {
1850*0Sstevel@tonic-gate 		*has_n_paths = B_TRUE;
1851*0Sstevel@tonic-gate 	    }
1852*0Sstevel@tonic-gate 	    dlist_free_items(paths, NULL);
1853*0Sstevel@tonic-gate 	}
1854*0Sstevel@tonic-gate 
1855*0Sstevel@tonic-gate 	return (error);
1856*0Sstevel@tonic-gate }
1857*0Sstevel@tonic-gate 
1858*0Sstevel@tonic-gate /*
1859*0Sstevel@tonic-gate  * FUNCTION:	compare_string_to_modslice_name(void *str, void *modslice)
1860*0Sstevel@tonic-gate  *
1861*0Sstevel@tonic-gate  * INPUT:	str	- opaque char * pointer
1862*0Sstevel@tonic-gate  * 		modslice - opaque modslice_t pointer
1863*0Sstevel@tonic-gate  *
1864*0Sstevel@tonic-gate  * RETURNS:	int	- <0 - if str < modslice->slice_devcfg.name
1865*0Sstevel@tonic-gate  *			   0 - if str == modslice->slice_devcfg.name
1866*0Sstevel@tonic-gate  *			  >0 - if str > modslice->slice_devcfg.name
1867*0Sstevel@tonic-gate  *
1868*0Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the input string to
1869*0Sstevel@tonic-gate  *		the name of a slice represented as modslice_t struct.
1870*0Sstevel@tonic-gate  *
1871*0Sstevel@tonic-gate  *		Comparison is done via string_case_compare.
1872*0Sstevel@tonic-gate  */
1873*0Sstevel@tonic-gate static int
1874*0Sstevel@tonic-gate compare_string_to_modslice_name(
1875*0Sstevel@tonic-gate 	void		*str,
1876*0Sstevel@tonic-gate 	void		*modslice)
1877*0Sstevel@tonic-gate {
1878*0Sstevel@tonic-gate 	char		*name = NULL;
1879*0Sstevel@tonic-gate 
1880*0Sstevel@tonic-gate 	assert(str != NULL);
1881*0Sstevel@tonic-gate 	assert(modslice != NULL);
1882*0Sstevel@tonic-gate 
1883*0Sstevel@tonic-gate 	(void) devconfig_get_name(
1884*0Sstevel@tonic-gate 		((modslice_t *)modslice)->slice_devcfg, &name);
1885*0Sstevel@tonic-gate 
1886*0Sstevel@tonic-gate 	return (string_case_compare((char *)str, name));
1887*0Sstevel@tonic-gate }
1888*0Sstevel@tonic-gate 
1889*0Sstevel@tonic-gate /*
1890*0Sstevel@tonic-gate  * FUNCTION:	compare_modslice_names(void *obj1, void *obj2)
1891*0Sstevel@tonic-gate  *
1892*0Sstevel@tonic-gate  * INPUT:	obj1	- opaque pointer
1893*0Sstevel@tonic-gate  * 		obj2	- opaque pointer
1894*0Sstevel@tonic-gate  *
1895*0Sstevel@tonic-gate  * RETURNS:	int	- <0 - if obj1 name < obj2 name
1896*0Sstevel@tonic-gate  *			   0 - if obj1 name == obj2 name
1897*0Sstevel@tonic-gate  *			  >0 - if obj1 name > obj2 name
1898*0Sstevel@tonic-gate  *
1899*0Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the names of two slices
1900*0Sstevel@tonic-gate  *		represented as modslice_t structs.
1901*0Sstevel@tonic-gate  *
1902*0Sstevel@tonic-gate  *		Comparison is done by string_case_compare
1903*0Sstevel@tonic-gate  */
1904*0Sstevel@tonic-gate static int
1905*0Sstevel@tonic-gate compare_modslice_names(
1906*0Sstevel@tonic-gate 	void		*obj1,
1907*0Sstevel@tonic-gate 	void		*obj2)
1908*0Sstevel@tonic-gate {
1909*0Sstevel@tonic-gate 	char		*name1 = NULL;
1910*0Sstevel@tonic-gate 	char		*name2 = NULL;
1911*0Sstevel@tonic-gate 
1912*0Sstevel@tonic-gate 	assert(obj1 != NULL);
1913*0Sstevel@tonic-gate 	assert(obj2 != NULL);
1914*0Sstevel@tonic-gate 
1915*0Sstevel@tonic-gate 	(void) devconfig_get_name(
1916*0Sstevel@tonic-gate 		((modslice_t *)obj1)->slice_devcfg, &name1);
1917*0Sstevel@tonic-gate 	(void) devconfig_get_name(
1918*0Sstevel@tonic-gate 		((modslice_t *)obj2)->slice_devcfg, &name2);
1919*0Sstevel@tonic-gate 
1920*0Sstevel@tonic-gate 	return (string_case_compare(name1, name2));
1921*0Sstevel@tonic-gate }
1922*0Sstevel@tonic-gate 
1923*0Sstevel@tonic-gate /*
1924*0Sstevel@tonic-gate  * FUNCTION:	release_used_slices()
1925*0Sstevel@tonic-gate  *
1926*0Sstevel@tonic-gate  * PURPOSE:	Helper which cleans up the module private list of used
1927*0Sstevel@tonic-gate  *		slices.
1928*0Sstevel@tonic-gate  */
1929*0Sstevel@tonic-gate void
1930*0Sstevel@tonic-gate release_used_slices()
1931*0Sstevel@tonic-gate {
1932*0Sstevel@tonic-gate 	dlist_free_items(_used_slices, free_used_slice);
1933*0Sstevel@tonic-gate 	_used_slices = NULL;
1934*0Sstevel@tonic-gate }
1935*0Sstevel@tonic-gate 
1936*0Sstevel@tonic-gate static void
1937*0Sstevel@tonic-gate free_used_slice(
1938*0Sstevel@tonic-gate 	void *obj)
1939*0Sstevel@tonic-gate {
1940*0Sstevel@tonic-gate 	if (obj != NULL) {
1941*0Sstevel@tonic-gate 	    usedslice_t *used = (usedslice_t *)obj;
1942*0Sstevel@tonic-gate 	    free(used->slicename);
1943*0Sstevel@tonic-gate 	    free(used);
1944*0Sstevel@tonic-gate 	}
1945*0Sstevel@tonic-gate }
1946*0Sstevel@tonic-gate 
1947*0Sstevel@tonic-gate /*
1948*0Sstevel@tonic-gate  * FUNCTION:	is_used_slice(dm_descriptor_t slice, boolean_t *is_used)
1949*0Sstevel@tonic-gate  *
1950*0Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t slice handle
1951*0Sstevel@tonic-gate  *
1952*0Sstevel@tonic-gate  * OUTPUT:	is_reserved - pointer to a boolean_t to hold the
1953*0Sstevel@tonic-gate  *			return result.
1954*0Sstevel@tonic-gate  *
1955*0Sstevel@tonic-gate  * PURPOSE:	Helper which checks to see if the input slice
1956*0Sstevel@tonic-gate  *		is in the used_slice list.
1957*0Sstevel@tonic-gate  *
1958*0Sstevel@tonic-gate  *		Check the input name against any used slice name or alias.
1959*0Sstevel@tonic-gate  *		is_used is set to B_TRUE if the	input slice is already used,
1960*0Sstevel@tonic-gate  *		B_FALSE otherwise.
1961*0Sstevel@tonic-gate  */
1962*0Sstevel@tonic-gate int
1963*0Sstevel@tonic-gate is_used_slice(
1964*0Sstevel@tonic-gate 	dm_descriptor_t	slice,
1965*0Sstevel@tonic-gate 	boolean_t	*is_used)
1966*0Sstevel@tonic-gate {
1967*0Sstevel@tonic-gate 	char	*name;
1968*0Sstevel@tonic-gate 	int	error = 0;
1969*0Sstevel@tonic-gate 
1970*0Sstevel@tonic-gate 	if ((error = get_display_name(slice, &name)) == 0) {
1971*0Sstevel@tonic-gate 	    *is_used = dlist_contains(_used_slices, (void *)name,
1972*0Sstevel@tonic-gate 		    compare_usedslice_name_to_string);
1973*0Sstevel@tonic-gate 	}
1974*0Sstevel@tonic-gate 
1975*0Sstevel@tonic-gate 	return (error);
1976*0Sstevel@tonic-gate }
1977*0Sstevel@tonic-gate 
1978*0Sstevel@tonic-gate /*
1979*0Sstevel@tonic-gate  * FUNCTIONS:	add_used_slice(dm_descriptor_t slice)
1980*0Sstevel@tonic-gate  *		add_used_slice_by_name(char *slicename)
1981*0Sstevel@tonic-gate  *		add_used_slice_list_entry(char *slice)
1982*0Sstevel@tonic-gate  *		remove_used_slice_by_name(char *slicename)
1983*0Sstevel@tonic-gate  *
1984*0Sstevel@tonic-gate  * INPUT:	diskset	- a char * diskset name.
1985*0Sstevel@tonic-gate  *		slice	- a dm_descriptor_t slice handle
1986*0Sstevel@tonic-gate  *
1987*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
1988*0Sstevel@tonic-gate  *			 !0 otherwise
1989*0Sstevel@tonic-gate  *
1990*0Sstevel@tonic-gate  * PURPOSE:	Access or maintain the list of used slices.
1991*0Sstevel@tonic-gate  */
1992*0Sstevel@tonic-gate int
1993*0Sstevel@tonic-gate add_used_slice(
1994*0Sstevel@tonic-gate 	dm_descriptor_t	slice)
1995*0Sstevel@tonic-gate {
1996*0Sstevel@tonic-gate 	dm_descriptor_t disk;
1997*0Sstevel@tonic-gate 	char	*name;
1998*0Sstevel@tonic-gate 	int	error = 0;
1999*0Sstevel@tonic-gate 
2000*0Sstevel@tonic-gate 	assert(slice != (dm_descriptor_t)0);
2001*0Sstevel@tonic-gate 
2002*0Sstevel@tonic-gate 	((error = get_display_name(slice, &name)) != 0) ||
2003*0Sstevel@tonic-gate 	(error = slice_get_disk(slice, &disk)) ||
2004*0Sstevel@tonic-gate 	(error = add_used_slice_list_entry(name, disk));
2005*0Sstevel@tonic-gate 
2006*0Sstevel@tonic-gate 	return (error);
2007*0Sstevel@tonic-gate }
2008*0Sstevel@tonic-gate 
2009*0Sstevel@tonic-gate int
2010*0Sstevel@tonic-gate add_used_slice_by_name(
2011*0Sstevel@tonic-gate 	char	*slicename)
2012*0Sstevel@tonic-gate {
2013*0Sstevel@tonic-gate 	dm_descriptor_t disk = (dm_descriptor_t)0;
2014*0Sstevel@tonic-gate 	int	error = 0;
2015*0Sstevel@tonic-gate 
2016*0Sstevel@tonic-gate 	assert(slicename != NULL);
2017*0Sstevel@tonic-gate 
2018*0Sstevel@tonic-gate 	/* find disk for slice */
2019*0Sstevel@tonic-gate 	error = get_disk_for_named_slice(slicename, &disk);
2020*0Sstevel@tonic-gate 	if (error == 0) {
2021*0Sstevel@tonic-gate 	    error = add_used_slice_list_entry(slicename, disk);
2022*0Sstevel@tonic-gate 	}
2023*0Sstevel@tonic-gate 
2024*0Sstevel@tonic-gate 	return (error);
2025*0Sstevel@tonic-gate }
2026*0Sstevel@tonic-gate 
2027*0Sstevel@tonic-gate static int
2028*0Sstevel@tonic-gate add_used_slice_list_entry(
2029*0Sstevel@tonic-gate 	char	*slicename,
2030*0Sstevel@tonic-gate 	dm_descriptor_t	disk)
2031*0Sstevel@tonic-gate {
2032*0Sstevel@tonic-gate 	usedslice_t *used = NULL;
2033*0Sstevel@tonic-gate 	int	error = 0;
2034*0Sstevel@tonic-gate 
2035*0Sstevel@tonic-gate 	assert(slicename != NULL);
2036*0Sstevel@tonic-gate 	assert(disk != (dm_descriptor_t)0);
2037*0Sstevel@tonic-gate 
2038*0Sstevel@tonic-gate 	used = (usedslice_t *)calloc(1, sizeof (usedslice_t));
2039*0Sstevel@tonic-gate 	if (used == NULL) {
2040*0Sstevel@tonic-gate 	    error = ENOMEM;
2041*0Sstevel@tonic-gate 	} else {
2042*0Sstevel@tonic-gate 
2043*0Sstevel@tonic-gate 	    used->disk = disk;
2044*0Sstevel@tonic-gate 	    if ((used->slicename = strdup(slicename)) == NULL) {
2045*0Sstevel@tonic-gate 		free(used);
2046*0Sstevel@tonic-gate 		error = ENOMEM;
2047*0Sstevel@tonic-gate 	    } else {
2048*0Sstevel@tonic-gate 		dlist_t *item = dlist_new_item((void *) used);
2049*0Sstevel@tonic-gate 		if (item == NULL) {
2050*0Sstevel@tonic-gate 		    free(used->slicename);
2051*0Sstevel@tonic-gate 		    free(used);
2052*0Sstevel@tonic-gate 		    error = ENOMEM;
2053*0Sstevel@tonic-gate 		} else {
2054*0Sstevel@tonic-gate 		    _used_slices =
2055*0Sstevel@tonic-gate 			dlist_append(item, _used_slices, AT_HEAD);
2056*0Sstevel@tonic-gate 		}
2057*0Sstevel@tonic-gate 	    }
2058*0Sstevel@tonic-gate 	}
2059*0Sstevel@tonic-gate 	return (error);
2060*0Sstevel@tonic-gate }
2061*0Sstevel@tonic-gate 
2062*0Sstevel@tonic-gate int
2063*0Sstevel@tonic-gate remove_used_slice_by_name(
2064*0Sstevel@tonic-gate 	char	*slice)
2065*0Sstevel@tonic-gate {
2066*0Sstevel@tonic-gate 	dlist_t *removed = NULL;
2067*0Sstevel@tonic-gate 
2068*0Sstevel@tonic-gate 	_used_slices =
2069*0Sstevel@tonic-gate 	    dlist_remove_equivalent_item(_used_slices, (void *)slice,
2070*0Sstevel@tonic-gate 		    compare_usedslice_name_to_string, &removed);
2071*0Sstevel@tonic-gate 
2072*0Sstevel@tonic-gate 	if (removed != NULL) {
2073*0Sstevel@tonic-gate 	    free_used_slice(removed->obj);
2074*0Sstevel@tonic-gate 	    removed->obj = NULL;
2075*0Sstevel@tonic-gate 	    free(removed);
2076*0Sstevel@tonic-gate 	}
2077*0Sstevel@tonic-gate 
2078*0Sstevel@tonic-gate 	return (0);
2079*0Sstevel@tonic-gate }
2080*0Sstevel@tonic-gate 
2081*0Sstevel@tonic-gate /*
2082*0Sstevel@tonic-gate  * FUNCTION:	compare_usedslice_name_to_string(void *obj1, void *obj2)
2083*0Sstevel@tonic-gate  * INPUT:	obj1	- opaque pointer
2084*0Sstevel@tonic-gate  * 		obj2	- opaque pointer
2085*0Sstevel@tonic-gate  *
2086*0Sstevel@tonic-gate  * RETURNS:	int	- <0 - if obj1 name < obj2 name
2087*0Sstevel@tonic-gate  *			   0 - if obj1 name == obj2 name
2088*0Sstevel@tonic-gate  *			  >0 - if obj1 name > obj2 name
2089*0Sstevel@tonic-gate  *
2090*0Sstevel@tonic-gate  * PURPOSE:	dlist_t helper which compares the names of a slice
2091*0Sstevel@tonic-gate  *		represented as modslice_t struct to a string.
2092*0Sstevel@tonic-gate  *
2093*0Sstevel@tonic-gate  *		obj1 is assumed to be a char *
2094*0Sstevel@tonic-gate  *		obj2 is assumed to be a usedslice_t *
2095*0Sstevel@tonic-gate  *
2096*0Sstevel@tonic-gate  *		Comparison is done via string_case_compare.
2097*0Sstevel@tonic-gate  */
2098*0Sstevel@tonic-gate static int
2099*0Sstevel@tonic-gate compare_usedslice_name_to_string(
2100*0Sstevel@tonic-gate 	void		*obj1,
2101*0Sstevel@tonic-gate 	void		*obj2)
2102*0Sstevel@tonic-gate {
2103*0Sstevel@tonic-gate 	assert(obj1 != NULL);
2104*0Sstevel@tonic-gate 	assert(obj2 != NULL);
2105*0Sstevel@tonic-gate 
2106*0Sstevel@tonic-gate 	return (string_case_compare((char *)obj1,
2107*0Sstevel@tonic-gate 			((usedslice_t *)obj2)->slicename));
2108*0Sstevel@tonic-gate }
2109*0Sstevel@tonic-gate 
2110*0Sstevel@tonic-gate /*
2111*0Sstevel@tonic-gate  * FUNCTION:	disk_has_used_slice(dm_descriptor_t disk, boolean_t *hasused)
2112*0Sstevel@tonic-gate  *
2113*0Sstevel@tonic-gate  * INPUT:	disk	- a dm_descriptor_t disk handle.
2114*0Sstevel@tonic-gate  *		inuse	- a boolean_t pointer to hold the result
2115*0Sstevel@tonic-gate  *
2116*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2117*0Sstevel@tonic-gate  *			 !0 othersize.
2118*0Sstevel@tonic-gate  *
2119*0Sstevel@tonic-gate  * PURPOSE:	Determines if any of the known used slices is on the
2120*0Sstevel@tonic-gate  *		input disk.
2121*0Sstevel@tonic-gate  */
2122*0Sstevel@tonic-gate int
2123*0Sstevel@tonic-gate disk_has_used_slice(
2124*0Sstevel@tonic-gate 	dm_descriptor_t disk,
2125*0Sstevel@tonic-gate 	boolean_t	*hasused)
2126*0Sstevel@tonic-gate {
2127*0Sstevel@tonic-gate 	dlist_t		*iter;
2128*0Sstevel@tonic-gate 	int		error = 0;
2129*0Sstevel@tonic-gate 
2130*0Sstevel@tonic-gate 	*hasused = B_FALSE;
2131*0Sstevel@tonic-gate 	for (iter = _used_slices;
2132*0Sstevel@tonic-gate 	    (iter != NULL) && (*hasused == B_FALSE);
2133*0Sstevel@tonic-gate 	    iter = iter->next) {
2134*0Sstevel@tonic-gate 
2135*0Sstevel@tonic-gate 	    usedslice_t *used = (usedslice_t *)iter->obj;
2136*0Sstevel@tonic-gate 
2137*0Sstevel@tonic-gate 	    /* compare used slice's disk to disk */
2138*0Sstevel@tonic-gate 	    if (compare_descriptors((void *)disk, (void *)used->disk) == 0) {
2139*0Sstevel@tonic-gate 		*hasused = B_TRUE;
2140*0Sstevel@tonic-gate 	    }
2141*0Sstevel@tonic-gate 	}
2142*0Sstevel@tonic-gate 
2143*0Sstevel@tonic-gate 	return (error);
2144*0Sstevel@tonic-gate }
2145*0Sstevel@tonic-gate 
2146*0Sstevel@tonic-gate /*
2147*0Sstevel@tonic-gate  * FUNCTION:	add_reserved_slice(dm_descriptor_t slice)
2148*0Sstevel@tonic-gate  *
2149*0Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t slice handle
2150*0Sstevel@tonic-gate  *
2151*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2152*0Sstevel@tonic-gate  *			 !0 otherwise.
2153*0Sstevel@tonic-gate  *
2154*0Sstevel@tonic-gate  * PURPOSE:	Helper which remembers specfically requested slices
2155*0Sstevel@tonic-gate  *		in a private list to ensure that the same slice isn't
2156*0Sstevel@tonic-gate  *		requested more than once.
2157*0Sstevel@tonic-gate  *
2158*0Sstevel@tonic-gate  *		Does not check to see if the slice already exists
2159*0Sstevel@tonic-gate  *		in the list of reserved slices. Assumes that the
2160*0Sstevel@tonic-gate  *		caller has checked using is_reserved_slice().
2161*0Sstevel@tonic-gate  *
2162*0Sstevel@tonic-gate  *		The reserved slice list is used by several functions:
2163*0Sstevel@tonic-gate  *
2164*0Sstevel@tonic-gate  *		1. layout_validate.validate_slice_components() adds user
2165*0Sstevel@tonic-gate  *		   requested slices to the list.
2166*0Sstevel@tonic-gate  *
2167*0Sstevel@tonic-gate  *		2. After all potentially usable slices have been scanned,
2168*0Sstevel@tonic-gate  *		   layout_validate.validate_reserved_slices() checks the
2169*0Sstevel@tonic-gate  *		   slices in the reserved and ensures that each slice is
2170*0Sstevel@tonic-gate  *		   actually usable as a volume component.
2171*0Sstevel@tonic-gate  *
2172*0Sstevel@tonic-gate  *		3. layout.disk_get_avail_space(), layout.disk_get_avail_slices()
2173*0Sstevel@tonic-gate  *		   exclude slices in the reserved list from being considered
2174*0Sstevel@tonic-gate  *		   available for general layout use.
2175*0Sstevel@tonic-gate  */
2176*0Sstevel@tonic-gate int
2177*0Sstevel@tonic-gate add_reserved_slice(
2178*0Sstevel@tonic-gate 	dm_descriptor_t	slice)
2179*0Sstevel@tonic-gate {
2180*0Sstevel@tonic-gate 	dlist_t	*item = NULL;
2181*0Sstevel@tonic-gate 
2182*0Sstevel@tonic-gate 	if ((item = dlist_new_item((void *)slice)) == NULL) {
2183*0Sstevel@tonic-gate 	    return (ENOMEM);
2184*0Sstevel@tonic-gate 	}
2185*0Sstevel@tonic-gate 
2186*0Sstevel@tonic-gate 	_rsvd_slices = dlist_append(item, _rsvd_slices, AT_HEAD);
2187*0Sstevel@tonic-gate 
2188*0Sstevel@tonic-gate 	return (0);
2189*0Sstevel@tonic-gate }
2190*0Sstevel@tonic-gate 
2191*0Sstevel@tonic-gate /*
2192*0Sstevel@tonic-gate  * FUNCTION:	is_reserved_slice(dm_descriptor_t slice,
2193*0Sstevel@tonic-gate  *			boolean_t *is_reserved)
2194*0Sstevel@tonic-gate  *
2195*0Sstevel@tonic-gate  * INPUT:	slice	- a dm_descriptor_t slice handle
2196*0Sstevel@tonic-gate  *
2197*0Sstevel@tonic-gate  * OUTPUT:	is_reserved - pointer to a boolean_t to hold the
2198*0Sstevel@tonic-gate  *			return result.
2199*0Sstevel@tonic-gate  *
2200*0Sstevel@tonic-gate  * PURPOSE:	Helper which checks to see if the input slice
2201*0Sstevel@tonic-gate  *		was previously reserved.
2202*0Sstevel@tonic-gate  *
2203*0Sstevel@tonic-gate  *		Check the input name against any reserved slice
2204*0Sstevel@tonic-gate  *		name or alias. is_reserved is set to B_TRUE if the
2205*0Sstevel@tonic-gate  *		input slice is already reserved, B_FALSE otherwise.
2206*0Sstevel@tonic-gate  */
2207*0Sstevel@tonic-gate int
2208*0Sstevel@tonic-gate is_reserved_slice(
2209*0Sstevel@tonic-gate 	dm_descriptor_t	slice,
2210*0Sstevel@tonic-gate 	boolean_t	*is_reserved)
2211*0Sstevel@tonic-gate {
2212*0Sstevel@tonic-gate 	*is_reserved = dlist_contains(
2213*0Sstevel@tonic-gate 		_rsvd_slices, (void *)slice, compare_descriptor_names);
2214*0Sstevel@tonic-gate 
2215*0Sstevel@tonic-gate 	return (0);
2216*0Sstevel@tonic-gate }
2217*0Sstevel@tonic-gate 
2218*0Sstevel@tonic-gate /*
2219*0Sstevel@tonic-gate  * FUNCTION:	release_reserved_slice()
2220*0Sstevel@tonic-gate  *
2221*0Sstevel@tonic-gate  * PURPOSE:	Helper which cleans up the module private list of reserved
2222*0Sstevel@tonic-gate  *		slices.
2223*0Sstevel@tonic-gate  */
2224*0Sstevel@tonic-gate void
2225*0Sstevel@tonic-gate release_reserved_slices()
2226*0Sstevel@tonic-gate {
2227*0Sstevel@tonic-gate 	dlist_free_items(_rsvd_slices, free);
2228*0Sstevel@tonic-gate 	_rsvd_slices = NULL;
2229*0Sstevel@tonic-gate }
2230*0Sstevel@tonic-gate 
2231*0Sstevel@tonic-gate /*
2232*0Sstevel@tonic-gate  * FUNCTION:	get_reserved_slices(dlist_t **list)
2233*0Sstevel@tonic-gate  *
2234*0Sstevel@tonic-gate  * OUTPUT:	list	- a dlist_t pointer to hold the returned list of
2235*0Sstevel@tonic-gate  *			reserverd slices.
2236*0Sstevel@tonic-gate  *
2237*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2238*0Sstevel@tonic-gate  *			 !0 otherwise
2239*0Sstevel@tonic-gate  *
2240*0Sstevel@tonic-gate  * PURPOSE:	Accessor to retrieve the current list of reserved slice
2241*0Sstevel@tonic-gate  *		dm_descriptor_t handles.
2242*0Sstevel@tonic-gate  */
2243*0Sstevel@tonic-gate int
2244*0Sstevel@tonic-gate get_reserved_slices(
2245*0Sstevel@tonic-gate 	dlist_t **list)
2246*0Sstevel@tonic-gate {
2247*0Sstevel@tonic-gate 	*list = _rsvd_slices;
2248*0Sstevel@tonic-gate 
2249*0Sstevel@tonic-gate 	return (0);
2250*0Sstevel@tonic-gate }
2251*0Sstevel@tonic-gate 
2252*0Sstevel@tonic-gate /*
2253*0Sstevel@tonic-gate  * FUNCTION:	add_slice_to_remove(char *name, uint32_t index)
2254*0Sstevel@tonic-gate  *
2255*0Sstevel@tonic-gate  * INPUT:	name	-	name of a slice
2256*0Sstevel@tonic-gate  *		index	-	index for the slice
2257*0Sstevel@tonic-gate  *
2258*0Sstevel@tonic-gate  * RETURNS:	int	- 0 on success
2259*0Sstevel@tonic-gate  *			 !0 otherwise
2260*0Sstevel@tonic-gate  *
2261*0Sstevel@tonic-gate  * PURPOSE:	Utility function to add the named slice to the list of
2262*0Sstevel@tonic-gate  *		those that need to be "removed" by having their sizes
2263*0Sstevel@tonic-gate  *		set to 0.
2264*0Sstevel@tonic-gate  */
2265*0Sstevel@tonic-gate int
2266*0Sstevel@tonic-gate add_slice_to_remove(
2267*0Sstevel@tonic-gate 	char		*name,
2268*0Sstevel@tonic-gate 	uint32_t	index)
2269*0Sstevel@tonic-gate {
2270*0Sstevel@tonic-gate 	rmvdslice_t *rmvd = NULL;
2271*0Sstevel@tonic-gate 	int	error = 0;
2272*0Sstevel@tonic-gate 
2273*0Sstevel@tonic-gate 	assert(name != NULL);
2274*0Sstevel@tonic-gate 
2275*0Sstevel@tonic-gate 	rmvd = (rmvdslice_t *)calloc(1, sizeof (rmvdslice_t));
2276*0Sstevel@tonic-gate 	if (rmvd == NULL) {
2277*0Sstevel@tonic-gate 	    error = ENOMEM;
2278*0Sstevel@tonic-gate 	} else {
2279*0Sstevel@tonic-gate 	    rmvd->slice_index = index;
2280*0Sstevel@tonic-gate 	    if ((rmvd->slice_name = strdup(name)) == NULL) {
2281*0Sstevel@tonic-gate 		free(rmvd);
2282*0Sstevel@tonic-gate 		error = ENOMEM;
2283*0Sstevel@tonic-gate 	    } else {
2284*0Sstevel@tonic-gate 		dlist_t *item = dlist_new_item((void *) rmvd);
2285*0Sstevel@tonic-gate 		if (item == NULL) {
2286*0Sstevel@tonic-gate 		    free(rmvd->slice_name);
2287*0Sstevel@tonic-gate 		    free(rmvd);
2288*0Sstevel@tonic-gate 		    error = ENOMEM;
2289*0Sstevel@tonic-gate 		} else {
2290*0Sstevel@tonic-gate 		    _rmvd_slices =
2291*0Sstevel@tonic-gate 			dlist_append(item, _rmvd_slices, AT_HEAD);
2292*0Sstevel@tonic-gate 		}
2293*0Sstevel@tonic-gate 	    }
2294*0Sstevel@tonic-gate 	}
2295*0Sstevel@tonic-gate 	return (error);
2296*0Sstevel@tonic-gate }
2297*0Sstevel@tonic-gate 
2298*0Sstevel@tonic-gate /*
2299*0Sstevel@tonic-gate  * FUNCTION:	get_removed_slices()
2300*0Sstevel@tonic-gate  *
2301*0Sstevel@tonic-gate  * RETURNS:	dlist_t * - pointer to a list of rmvdslice_t structs
2302*0Sstevel@tonic-gate  *
2303*0Sstevel@tonic-gate  * PURPOSE:	Accessor to retrieve the current list of names of slices
2304*0Sstevel@tonic-gate  *		to be removed.
2305*0Sstevel@tonic-gate  */
2306*0Sstevel@tonic-gate dlist_t *
2307*0Sstevel@tonic-gate get_slices_to_remove(
2308*0Sstevel@tonic-gate 	dlist_t **list)
2309*0Sstevel@tonic-gate {
2310*0Sstevel@tonic-gate 	return (_rmvd_slices);
2311*0Sstevel@tonic-gate }
2312*0Sstevel@tonic-gate 
2313*0Sstevel@tonic-gate static void
2314*0Sstevel@tonic-gate free_rmvd_slice(
2315*0Sstevel@tonic-gate 	void *obj)
2316*0Sstevel@tonic-gate {
2317*0Sstevel@tonic-gate 	if (obj != NULL) {
2318*0Sstevel@tonic-gate 	    rmvdslice_t *rmvd = (rmvdslice_t *)obj;
2319*0Sstevel@tonic-gate 	    free(rmvd->slice_name);
2320*0Sstevel@tonic-gate 	    free(rmvd);
2321*0Sstevel@tonic-gate 	}
2322*0Sstevel@tonic-gate }
2323*0Sstevel@tonic-gate 
2324*0Sstevel@tonic-gate /*
2325*0Sstevel@tonic-gate  * FUNCTION:	release_removed_slices()
2326*0Sstevel@tonic-gate  *
2327*0Sstevel@tonic-gate  * PURPOSE:	Helper which cleans up the module private list of removed
2328*0Sstevel@tonic-gate  *		slices.
2329*0Sstevel@tonic-gate  */
2330*0Sstevel@tonic-gate void
2331*0Sstevel@tonic-gate release_slices_to_remove()
2332*0Sstevel@tonic-gate {
2333*0Sstevel@tonic-gate 	dlist_free_items(_rmvd_slices, free_rmvd_slice);
2334*0Sstevel@tonic-gate 	_rmvd_slices = NULL;
2335*0Sstevel@tonic-gate }
2336