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 /*
30*0Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
31*0Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
34*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
35*0Sstevel@tonic-gate #endif
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate  * hotspares utilities
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include <meta.h>
42*0Sstevel@tonic-gate #include <sys/lvm/md_hotspares.h>
43*0Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /*
47*0Sstevel@tonic-gate  * FUNCTION:	meta_get_hsp_names()
48*0Sstevel@tonic-gate  * INPUT:	sp	- the set name to get hotspares from
49*0Sstevel@tonic-gate  *		options	- options from the command line
50*0Sstevel@tonic-gate  * OUTPUT:	hspnlpp	- list of all hotspare names
51*0Sstevel@tonic-gate  *		ep	- return error pointer
52*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
53*0Sstevel@tonic-gate  * PURPOSE:	returns a list of all hotspares in the metadb
54*0Sstevel@tonic-gate  *		for all devices in the specified set
55*0Sstevel@tonic-gate  */
56*0Sstevel@tonic-gate /*ARGSUSED*/
57*0Sstevel@tonic-gate int
58*0Sstevel@tonic-gate meta_get_hsp_names(
59*0Sstevel@tonic-gate 	mdsetname_t	*sp,
60*0Sstevel@tonic-gate 	mdhspnamelist_t	**hspnlpp,
61*0Sstevel@tonic-gate 	int		options,
62*0Sstevel@tonic-gate 	md_error_t	*ep
63*0Sstevel@tonic-gate )
64*0Sstevel@tonic-gate {
65*0Sstevel@tonic-gate 	md_i_getnum_t	gn;		/* MD_IOCGET_NUM params */
66*0Sstevel@tonic-gate 	minor_t		*minors = NULL;
67*0Sstevel@tonic-gate 	minor_t		*m_ptr;
68*0Sstevel@tonic-gate 	int		i;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	/* we must have a set */
71*0Sstevel@tonic-gate 	assert(sp != NULL);
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	(void) memset(&gn, 0, sizeof (gn));
74*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno);
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	/* get number of devices */
77*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
78*0Sstevel@tonic-gate 		if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
79*0Sstevel@tonic-gate 			mdclrerror(&gn.mde);
80*0Sstevel@tonic-gate 		} else {
81*0Sstevel@tonic-gate 			(void) mdstealerror(ep, &gn.mde);
82*0Sstevel@tonic-gate 			return (-1);
83*0Sstevel@tonic-gate 		}
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	if (gn.size > 0) {
87*0Sstevel@tonic-gate 		/* malloc minor number buffer to be filled by ioctl */
88*0Sstevel@tonic-gate 		if ((minors = (minor_t *)malloc(
89*0Sstevel@tonic-gate 				gn.size * sizeof (minor_t))) == 0) {
90*0Sstevel@tonic-gate 			return (ENOMEM);
91*0Sstevel@tonic-gate 		}
92*0Sstevel@tonic-gate 		gn.minors = (uintptr_t)minors;
93*0Sstevel@tonic-gate 		if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
94*0Sstevel@tonic-gate 			(void) mdstealerror(ep, &gn.mde);
95*0Sstevel@tonic-gate 			free(minors);
96*0Sstevel@tonic-gate 			return (-1);
97*0Sstevel@tonic-gate 		}
98*0Sstevel@tonic-gate 		m_ptr = minors;
99*0Sstevel@tonic-gate 		for (i = 0; i < gn.size; i++) {
100*0Sstevel@tonic-gate 			mdhspname_t	*hspnp;
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 			/* get name */
104*0Sstevel@tonic-gate 			if ((hspnp = metahsphspname(&sp, *m_ptr, ep))
105*0Sstevel@tonic-gate 					== NULL)
106*0Sstevel@tonic-gate 				goto out;
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 			/* append to list */
109*0Sstevel@tonic-gate 			(void) metahspnamelist_append(hspnlpp, hspnp);
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 			/* next device */
112*0Sstevel@tonic-gate 			m_ptr++;
113*0Sstevel@tonic-gate 		}
114*0Sstevel@tonic-gate 		free(minors);
115*0Sstevel@tonic-gate 	}
116*0Sstevel@tonic-gate 	return (gn.size);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate out:
119*0Sstevel@tonic-gate 	if (minors != NULL)
120*0Sstevel@tonic-gate 		free(minors);
121*0Sstevel@tonic-gate 	metafreehspnamelist(*hspnlpp);
122*0Sstevel@tonic-gate 	*hspnlpp = NULL;
123*0Sstevel@tonic-gate 	return (-1);
124*0Sstevel@tonic-gate }
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate /*
127*0Sstevel@tonic-gate  * get information of a specific hotspare pool from driver
128*0Sstevel@tonic-gate  */
129*0Sstevel@tonic-gate static get_hsp_t *
130*0Sstevel@tonic-gate get_hspinfo(
131*0Sstevel@tonic-gate 	mdsetname_t	*sp,
132*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
133*0Sstevel@tonic-gate 	md_error_t	*ep
134*0Sstevel@tonic-gate )
135*0Sstevel@tonic-gate {
136*0Sstevel@tonic-gate 	md_i_get_t	mig;
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	/* should have a set */
139*0Sstevel@tonic-gate 	assert(sp != NULL);
140*0Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 	/* get size of unit structure */
143*0Sstevel@tonic-gate 	(void) memset(&mig, 0, sizeof (mig));
144*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno);
145*0Sstevel@tonic-gate 	mig.id = hspnp->hsp;
146*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
147*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &mig.mde);
148*0Sstevel@tonic-gate 		return (NULL);
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	/* get actual unit structure */
152*0Sstevel@tonic-gate 	assert(mig.size > 0);
153*0Sstevel@tonic-gate 	mig.mdp = (uintptr_t)Zalloc(mig.size);
154*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
155*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &mig.mde);
156*0Sstevel@tonic-gate 		Free((void *)mig.mdp);
157*0Sstevel@tonic-gate 		return (NULL);
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 	return ((get_hsp_t *)mig.mdp);
160*0Sstevel@tonic-gate }
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate /*
163*0Sstevel@tonic-gate  * free hotspare pool unit
164*0Sstevel@tonic-gate  */
165*0Sstevel@tonic-gate void
166*0Sstevel@tonic-gate meta_free_hsp(
167*0Sstevel@tonic-gate 	md_hsp_t	*hspp
168*0Sstevel@tonic-gate )
169*0Sstevel@tonic-gate {
170*0Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_val != NULL) {
171*0Sstevel@tonic-gate 		assert(hspp->hotspares.hotspares_len > 0);
172*0Sstevel@tonic-gate 		Free(hspp->hotspares.hotspares_val);
173*0Sstevel@tonic-gate 	}
174*0Sstevel@tonic-gate 	Free(hspp);
175*0Sstevel@tonic-gate }
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate /*
178*0Sstevel@tonic-gate  * get hotspare pool unit (common)
179*0Sstevel@tonic-gate  */
180*0Sstevel@tonic-gate md_hsp_t *
181*0Sstevel@tonic-gate meta_get_hsp_common(
182*0Sstevel@tonic-gate 	mdsetname_t	*sp,
183*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
184*0Sstevel@tonic-gate 	int		fast,
185*0Sstevel@tonic-gate 	md_error_t	*ep
186*0Sstevel@tonic-gate )
187*0Sstevel@tonic-gate {
188*0Sstevel@tonic-gate 	get_hsp_t	*ghsp;
189*0Sstevel@tonic-gate 	md_hsp_t	*hspp;
190*0Sstevel@tonic-gate 	uint_t		hsi;
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	/* must have set */
193*0Sstevel@tonic-gate 	assert(sp != NULL);
194*0Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	/* short circuit */
197*0Sstevel@tonic-gate 	if (hspnp->unitp != NULL)
198*0Sstevel@tonic-gate 		return (hspnp->unitp);
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	/* get unit */
201*0Sstevel@tonic-gate 	if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL)
202*0Sstevel@tonic-gate 		return (NULL);
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	/* allocate hsp */
205*0Sstevel@tonic-gate 	hspp = Zalloc(sizeof (*hspp));
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	/* allocate hotspares */
208*0Sstevel@tonic-gate 	hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares;
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	/* if empty hotspare pool, we are done */
211*0Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_len != 0)
212*0Sstevel@tonic-gate 		hspp->hotspares.hotspares_val =
213*0Sstevel@tonic-gate 		    Zalloc(hspp->hotspares.hotspares_len *
214*0Sstevel@tonic-gate 		    sizeof (*hspp->hotspares.hotspares_val));
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	/* get name, refcount */
217*0Sstevel@tonic-gate 	hspp->hspnamep = hspnp;
218*0Sstevel@tonic-gate 	hspp->refcount = ghsp->ghsp_refcount;
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	/* get hotspares */
221*0Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
222*0Sstevel@tonic-gate 		mdkey_t		hs_key = ghsp->ghsp_hs_keys[hsi];
223*0Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
224*0Sstevel@tonic-gate 		get_hs_params_t	ghs;
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 		/* get hotspare name */
227*0Sstevel@tonic-gate 		hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep);
228*0Sstevel@tonic-gate 		if (hsp->hsnamep == NULL)
229*0Sstevel@tonic-gate 			goto out;
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 		/* get hotspare state */
232*0Sstevel@tonic-gate 		(void) memset(&ghs, 0, sizeof (ghs));
233*0Sstevel@tonic-gate 		MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno);
234*0Sstevel@tonic-gate 		ghs.ghs_key = hs_key;
235*0Sstevel@tonic-gate 		if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) {
236*0Sstevel@tonic-gate 			(void) mdstealerror(ep, &ghs.mde);
237*0Sstevel@tonic-gate 			goto out;
238*0Sstevel@tonic-gate 		}
239*0Sstevel@tonic-gate 		hsp->state = ghs.ghs_state;
240*0Sstevel@tonic-gate 		hsp->size = ghs.ghs_number_blks;
241*0Sstevel@tonic-gate 		hsp->timestamp = ghs.ghs_timestamp;
242*0Sstevel@tonic-gate 		hsp->revision = ghs.ghs_revision;
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	/* cleanup, return success */
246*0Sstevel@tonic-gate 	Free(ghsp);
247*0Sstevel@tonic-gate 	hspnp->unitp = hspp;
248*0Sstevel@tonic-gate 	return (hspp);
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	/* cleanup, return error */
251*0Sstevel@tonic-gate out:
252*0Sstevel@tonic-gate 	Free(ghsp);
253*0Sstevel@tonic-gate 	meta_free_hsp(hspp);
254*0Sstevel@tonic-gate 	return (NULL);
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate /*
258*0Sstevel@tonic-gate  * get hotspare pool unit
259*0Sstevel@tonic-gate  */
260*0Sstevel@tonic-gate md_hsp_t *
261*0Sstevel@tonic-gate meta_get_hsp(
262*0Sstevel@tonic-gate 	mdsetname_t	*sp,
263*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
264*0Sstevel@tonic-gate 	md_error_t	*ep
265*0Sstevel@tonic-gate )
266*0Sstevel@tonic-gate {
267*0Sstevel@tonic-gate 	return (meta_get_hsp_common(sp, hspnp, 0, ep));
268*0Sstevel@tonic-gate }
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate /*
271*0Sstevel@tonic-gate  * check hotspare pool for dev
272*0Sstevel@tonic-gate  */
273*0Sstevel@tonic-gate static int
274*0Sstevel@tonic-gate in_hsp(
275*0Sstevel@tonic-gate 	mdsetname_t	*sp,
276*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
277*0Sstevel@tonic-gate 	mdname_t	*np,
278*0Sstevel@tonic-gate 	diskaddr_t	slblk,
279*0Sstevel@tonic-gate 	diskaddr_t	nblks,
280*0Sstevel@tonic-gate 	md_error_t	*ep
281*0Sstevel@tonic-gate )
282*0Sstevel@tonic-gate {
283*0Sstevel@tonic-gate 	md_hsp_t	*hspp;
284*0Sstevel@tonic-gate 	uint_t		i;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	/* should be in the same set */
287*0Sstevel@tonic-gate 	assert(sp != NULL);
288*0Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	/* get unit */
291*0Sstevel@tonic-gate 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
292*0Sstevel@tonic-gate 		return (-1);
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	/* look in hotspares */
295*0Sstevel@tonic-gate 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
296*0Sstevel@tonic-gate 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
297*0Sstevel@tonic-gate 		mdname_t	*hsnp = hs->hsnamep;
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 		/* check overlap */
300*0Sstevel@tonic-gate 		if (metaismeta(hsnp))
301*0Sstevel@tonic-gate 			continue;
302*0Sstevel@tonic-gate 		if (meta_check_overlap(hspnp->hspname, np, slblk, nblks,
303*0Sstevel@tonic-gate 		    hsnp, 0, -1, ep) != 0)
304*0Sstevel@tonic-gate 			return (-1);
305*0Sstevel@tonic-gate 	}
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	/* return success */
308*0Sstevel@tonic-gate 	return (0);
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate /*
312*0Sstevel@tonic-gate  * check to see if we're in a hotspare pool
313*0Sstevel@tonic-gate  */
314*0Sstevel@tonic-gate int
315*0Sstevel@tonic-gate meta_check_inhsp(
316*0Sstevel@tonic-gate 	mdsetname_t	*sp,
317*0Sstevel@tonic-gate 	mdname_t	*np,
318*0Sstevel@tonic-gate 	diskaddr_t	slblk,
319*0Sstevel@tonic-gate 	diskaddr_t	nblks,
320*0Sstevel@tonic-gate 	md_error_t	*ep
321*0Sstevel@tonic-gate )
322*0Sstevel@tonic-gate {
323*0Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
324*0Sstevel@tonic-gate 	mdhspnamelist_t	*p;
325*0Sstevel@tonic-gate 	int		rval = 0;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	/* should have a set */
328*0Sstevel@tonic-gate 	assert(sp != NULL);
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	/* for each hotspare pool */
331*0Sstevel@tonic-gate 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
332*0Sstevel@tonic-gate 		return (-1);
333*0Sstevel@tonic-gate 	for (p = hspnlp; (p != NULL); p = p->next) {
334*0Sstevel@tonic-gate 		mdhspname_t	*hspnp = p->hspnamep;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 		/* check hotspare pool */
337*0Sstevel@tonic-gate 		if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) {
338*0Sstevel@tonic-gate 			rval = -1;
339*0Sstevel@tonic-gate 			break;
340*0Sstevel@tonic-gate 		}
341*0Sstevel@tonic-gate 	}
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	/* cleanup, return success */
344*0Sstevel@tonic-gate 	metafreehspnamelist(hspnlp);
345*0Sstevel@tonic-gate 	return (rval);
346*0Sstevel@tonic-gate }
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate /*
349*0Sstevel@tonic-gate  * check hotspare
350*0Sstevel@tonic-gate  */
351*0Sstevel@tonic-gate int
352*0Sstevel@tonic-gate meta_check_hotspare(
353*0Sstevel@tonic-gate 	mdsetname_t	*sp,
354*0Sstevel@tonic-gate 	mdname_t	*np,
355*0Sstevel@tonic-gate 	md_error_t	*ep
356*0Sstevel@tonic-gate )
357*0Sstevel@tonic-gate {
358*0Sstevel@tonic-gate 	mdchkopts_t	options = (MDCHK_ALLOW_HS);
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	/* make sure we have a disk */
361*0Sstevel@tonic-gate 	if (metachkcomp(np, ep) != 0)
362*0Sstevel@tonic-gate 		return (-1);
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
365*0Sstevel@tonic-gate 	if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
366*0Sstevel@tonic-gate 		return (-1);
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	/* make sure it is in the set */
370*0Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
371*0Sstevel@tonic-gate 		return (-1);
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	/* make sure its not in a metadevice */
374*0Sstevel@tonic-gate 	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
375*0Sstevel@tonic-gate 		return (-1);
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	/* return success */
378*0Sstevel@tonic-gate 	return (0);
379*0Sstevel@tonic-gate }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate /*
382*0Sstevel@tonic-gate  * print hsp
383*0Sstevel@tonic-gate  */
384*0Sstevel@tonic-gate static int
385*0Sstevel@tonic-gate hsp_print(
386*0Sstevel@tonic-gate 	md_hsp_t	*hspp,
387*0Sstevel@tonic-gate 	char		*fname,
388*0Sstevel@tonic-gate 	FILE		*fp,
389*0Sstevel@tonic-gate 	md_error_t	*ep
390*0Sstevel@tonic-gate )
391*0Sstevel@tonic-gate {
392*0Sstevel@tonic-gate 	uint_t		hsi;
393*0Sstevel@tonic-gate 	int		rval = -1;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	/* print name */
396*0Sstevel@tonic-gate 	if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF)
397*0Sstevel@tonic-gate 		goto out;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	/* print hotspares */
400*0Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
401*0Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 		/* print hotspare */
404*0Sstevel@tonic-gate 		/*
405*0Sstevel@tonic-gate 		 * If the path is our standard /dev/rdsk or /dev/md/rdsk
406*0Sstevel@tonic-gate 		 * then just print out the cxtxdxsx or the dx, metainit
407*0Sstevel@tonic-gate 		 * will assume the default, otherwise we need the full
408*0Sstevel@tonic-gate 		 * pathname to make sure this works as we intend.
409*0Sstevel@tonic-gate 		 */
410*0Sstevel@tonic-gate 		if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) &&
411*0Sstevel@tonic-gate 		    (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) &&
412*0Sstevel@tonic-gate 		    (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) {
413*0Sstevel@tonic-gate 			/* not standard path, print full pathname */
414*0Sstevel@tonic-gate 			if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF)
415*0Sstevel@tonic-gate 				goto out;
416*0Sstevel@tonic-gate 		} else {
417*0Sstevel@tonic-gate 			/* standard path, just print ctd or d value */
418*0Sstevel@tonic-gate 			if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF)
419*0Sstevel@tonic-gate 				goto out;
420*0Sstevel@tonic-gate 		}
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	/* terminate last line */
424*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
425*0Sstevel@tonic-gate 		goto out;
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 	/* success */
428*0Sstevel@tonic-gate 	rval = 0;
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	/* cleanup, return error */
431*0Sstevel@tonic-gate out:
432*0Sstevel@tonic-gate 	if (rval != 0)
433*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
434*0Sstevel@tonic-gate 	return (rval);
435*0Sstevel@tonic-gate }
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate /*
438*0Sstevel@tonic-gate  * hotspare state name
439*0Sstevel@tonic-gate  */
440*0Sstevel@tonic-gate char *
441*0Sstevel@tonic-gate hs_state_to_name(
442*0Sstevel@tonic-gate 	md_hs_t			*hsp,
443*0Sstevel@tonic-gate 	md_timeval32_t		*tvp
444*0Sstevel@tonic-gate )
445*0Sstevel@tonic-gate {
446*0Sstevel@tonic-gate 	hotspare_states_t	state = hsp->state;
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	/* grab time */
449*0Sstevel@tonic-gate 	if (tvp != NULL)
450*0Sstevel@tonic-gate 		*tvp = hsp->timestamp;
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	switch (state) {
453*0Sstevel@tonic-gate 	case HSS_AVAILABLE:
454*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Available"));
455*0Sstevel@tonic-gate 	case HSS_RESERVED:
456*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "In use"));
457*0Sstevel@tonic-gate 	case HSS_BROKEN:
458*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Broken"));
459*0Sstevel@tonic-gate 	case HSS_UNUSED:
460*0Sstevel@tonic-gate 	default:
461*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "invalid"));
462*0Sstevel@tonic-gate 	}
463*0Sstevel@tonic-gate }
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate /*
466*0Sstevel@tonic-gate  * report hsp
467*0Sstevel@tonic-gate  */
468*0Sstevel@tonic-gate static int
469*0Sstevel@tonic-gate hsp_report(
470*0Sstevel@tonic-gate 	md_hsp_t	*hspp,
471*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
472*0Sstevel@tonic-gate 	char		*fname,
473*0Sstevel@tonic-gate 	FILE		*fp,
474*0Sstevel@tonic-gate 	mdprtopts_t	options,
475*0Sstevel@tonic-gate 	md_error_t	*ep,
476*0Sstevel@tonic-gate 	mdsetname_t	*sp
477*0Sstevel@tonic-gate )
478*0Sstevel@tonic-gate {
479*0Sstevel@tonic-gate 	uint_t		hsi;
480*0Sstevel@tonic-gate 	int		rval = -1;
481*0Sstevel@tonic-gate 	char		*devid = "";
482*0Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
483*0Sstevel@tonic-gate 	uint_t		len;
484*0Sstevel@tonic-gate 	int		large_hs_dev_cnt = 0;
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
487*0Sstevel@tonic-gate 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
488*0Sstevel@tonic-gate 			md_hs_t	*hsp = &hspp->hotspares.hotspares_val[hsi];
489*0Sstevel@tonic-gate 			if (hsp->revision == MD_64BIT_META_DEV) {
490*0Sstevel@tonic-gate 				large_hs_dev_cnt += 1;
491*0Sstevel@tonic-gate 				if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
492*0Sstevel@tonic-gate 				    != 0)
493*0Sstevel@tonic-gate 					goto out;
494*0Sstevel@tonic-gate 			}
495*0Sstevel@tonic-gate 		}
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 		if (large_hs_dev_cnt == 0) {
498*0Sstevel@tonic-gate 			rval = 0;
499*0Sstevel@tonic-gate 			goto out;
500*0Sstevel@tonic-gate 		}
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 	/* print header */
503*0Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_len == 0) {
504*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"),
505*0Sstevel@tonic-gate 		    hspp->hspnamep->hspname) == EOF) {
506*0Sstevel@tonic-gate 			goto out;
507*0Sstevel@tonic-gate 		}
508*0Sstevel@tonic-gate 	} else if (hspp->hotspares.hotspares_len == 1) {
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 		/*
511*0Sstevel@tonic-gate 		 * This allows the length
512*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
513*0Sstevel@tonic-gate 		 * looking horrible.
514*0Sstevel@tonic-gate 		 */
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 		len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname);
517*0Sstevel@tonic-gate 		/*
518*0Sstevel@tonic-gate 		 * if the length is to short to print out all of the header
519*0Sstevel@tonic-gate 		 * force the matter
520*0Sstevel@tonic-gate 		 */
521*0Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
522*0Sstevel@tonic-gate 		len += 2;
523*0Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
524*0Sstevel@tonic-gate 			if (fprintf(fp,
525*0Sstevel@tonic-gate 			    "%s: 1 hot spare (1 big device)\n\t%-*.*s  "
526*0Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
527*0Sstevel@tonic-gate 			    hspp->hspnamep->hspname, len, len,
528*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
529*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
530*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
531*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
532*0Sstevel@tonic-gate 				goto out;
533*0Sstevel@tonic-gate 			}
534*0Sstevel@tonic-gate 		} else {
535*0Sstevel@tonic-gate 			if (fprintf(fp,
536*0Sstevel@tonic-gate 			    "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n",
537*0Sstevel@tonic-gate 			    hspp->hspnamep->hspname, len, len,
538*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
539*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
540*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
541*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
542*0Sstevel@tonic-gate 				goto out;
543*0Sstevel@tonic-gate 			}
544*0Sstevel@tonic-gate 		}
545*0Sstevel@tonic-gate 	} else {
546*0Sstevel@tonic-gate 		/*
547*0Sstevel@tonic-gate 		 * This allows the length
548*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
549*0Sstevel@tonic-gate 		 * looking horrible.
550*0Sstevel@tonic-gate 		 */
551*0Sstevel@tonic-gate 		len = 0;
552*0Sstevel@tonic-gate 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
553*0Sstevel@tonic-gate 			len = max(len, strlen(hspp->
554*0Sstevel@tonic-gate 			    hotspares.hotspares_val[hsi].hsnamep->cname));
555*0Sstevel@tonic-gate 		}
556*0Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
557*0Sstevel@tonic-gate 		len += 2;
558*0Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
559*0Sstevel@tonic-gate 			if (fprintf(fp,
560*0Sstevel@tonic-gate 			    "%s: %u hot spares (%d big device(s))\n\t%-*.*s "
561*0Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
562*0Sstevel@tonic-gate 			    hspp->hspnamep->hspname,
563*0Sstevel@tonic-gate 			    hspp->hotspares.hotspares_len,
564*0Sstevel@tonic-gate 			    large_hs_dev_cnt, len, len,
565*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
566*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
567*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
568*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
569*0Sstevel@tonic-gate 				goto out;
570*0Sstevel@tonic-gate 			}
571*0Sstevel@tonic-gate 		} else {
572*0Sstevel@tonic-gate 			if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s "
573*0Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
574*0Sstevel@tonic-gate 			    hspp->hspnamep->hspname,
575*0Sstevel@tonic-gate 			    hspp->hotspares.hotspares_len, len, len,
576*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
577*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
578*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
579*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
580*0Sstevel@tonic-gate 				goto out;
581*0Sstevel@tonic-gate 			}
582*0Sstevel@tonic-gate 		}
583*0Sstevel@tonic-gate 	}
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	/* print hotspares */
586*0Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
587*0Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
588*0Sstevel@tonic-gate 		char		*cname = hsp->hsnamep->cname;
589*0Sstevel@tonic-gate 		char		*hs_state;
590*0Sstevel@tonic-gate 		md_timeval32_t	tv;
591*0Sstevel@tonic-gate 		char		*timep;
592*0Sstevel@tonic-gate 		ddi_devid_t	dtp;
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 		/* populate the key in the name_p structure */
595*0Sstevel@tonic-gate 		if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) {
596*0Sstevel@tonic-gate 			return (-1);
597*0Sstevel@tonic-gate 		}
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
600*0Sstevel@tonic-gate 			if (hsp->revision != MD_64BIT_META_DEV)
601*0Sstevel@tonic-gate 				continue;
602*0Sstevel@tonic-gate 		}
603*0Sstevel@tonic-gate 		/* determine if devid does NOT exist */
604*0Sstevel@tonic-gate 		if (options & PRINT_DEVID) {
605*0Sstevel@tonic-gate 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
606*0Sstevel@tonic-gate 				didnp->key, ep)) == NULL)
607*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
608*0Sstevel@tonic-gate 			else {
609*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
610*0Sstevel@tonic-gate 				free(dtp);
611*0Sstevel@tonic-gate 			}
612*0Sstevel@tonic-gate 		}
613*0Sstevel@tonic-gate 		/* print hotspare */
614*0Sstevel@tonic-gate 		hs_state = hs_state_to_name(hsp, &tv);
615*0Sstevel@tonic-gate 		/*
616*0Sstevel@tonic-gate 		 * This allows the length
617*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
618*0Sstevel@tonic-gate 		 * looking horrible.
619*0Sstevel@tonic-gate 		 */
620*0Sstevel@tonic-gate 		if (! (options & PRINT_TIMES)) {
621*0Sstevel@tonic-gate 			if (fprintf(fp,
622*0Sstevel@tonic-gate 			    "        %-*s %-12s %lld blocks\t%s\n",
623*0Sstevel@tonic-gate 			    len, cname, hs_state,
624*0Sstevel@tonic-gate 			    hsp->size, devid) == EOF) {
625*0Sstevel@tonic-gate 				goto out;
626*0Sstevel@tonic-gate 			}
627*0Sstevel@tonic-gate 		} else {
628*0Sstevel@tonic-gate 			timep = meta_print_time(&tv);
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 			if (fprintf(fp,
631*0Sstevel@tonic-gate 			    "        %-*s\t    %-11s %8lld blocks%s\t%s\n",
632*0Sstevel@tonic-gate 			    len, cname, hs_state,
633*0Sstevel@tonic-gate 			    hsp->size, devid, timep) == EOF) {
634*0Sstevel@tonic-gate 				goto out;
635*0Sstevel@tonic-gate 			}
636*0Sstevel@tonic-gate 		}
637*0Sstevel@tonic-gate 	}
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	/* add extra line */
640*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
641*0Sstevel@tonic-gate 		goto out;
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	/* success */
644*0Sstevel@tonic-gate 	rval = 0;
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	/* cleanup, return error */
647*0Sstevel@tonic-gate out:
648*0Sstevel@tonic-gate 	if (rval != 0)
649*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
650*0Sstevel@tonic-gate 	return (rval);
651*0Sstevel@tonic-gate }
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate /*
654*0Sstevel@tonic-gate  * print/report hsp
655*0Sstevel@tonic-gate  */
656*0Sstevel@tonic-gate int
657*0Sstevel@tonic-gate meta_hsp_print(
658*0Sstevel@tonic-gate 	mdsetname_t	*sp,
659*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
660*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
661*0Sstevel@tonic-gate 	char		*fname,
662*0Sstevel@tonic-gate 	FILE		*fp,
663*0Sstevel@tonic-gate 	mdprtopts_t	options,
664*0Sstevel@tonic-gate 	md_error_t	*ep
665*0Sstevel@tonic-gate )
666*0Sstevel@tonic-gate {
667*0Sstevel@tonic-gate 	md_hsp_t	*hspp;
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	/* should have same set */
670*0Sstevel@tonic-gate 	assert(sp != NULL);
671*0Sstevel@tonic-gate 	assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp)));
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 	/* print all hsps */
674*0Sstevel@tonic-gate 	if (hspnp == NULL) {
675*0Sstevel@tonic-gate 		mdhspnamelist_t	*hspnlp = NULL;
676*0Sstevel@tonic-gate 		mdhspnamelist_t	*p;
677*0Sstevel@tonic-gate 		int		cnt;
678*0Sstevel@tonic-gate 		int		rval = 0;
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 		if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0)
681*0Sstevel@tonic-gate 			return (-1);
682*0Sstevel@tonic-gate 		else if (cnt == 0)
683*0Sstevel@tonic-gate 			return (0);
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 		/* recurse */
686*0Sstevel@tonic-gate 		for (p = hspnlp; (p != NULL); p = p->next) {
687*0Sstevel@tonic-gate 			mdhspname_t	*hspnp = p->hspnamep;
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 			if (meta_hsp_print(sp, hspnp, nlpp, fname, fp,
690*0Sstevel@tonic-gate 			    options, ep) != 0)
691*0Sstevel@tonic-gate 				rval = -1;
692*0Sstevel@tonic-gate 		}
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 		/* cleanup, return success */
695*0Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
696*0Sstevel@tonic-gate 		return (rval);
697*0Sstevel@tonic-gate 	}
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	/* get unit structure */
700*0Sstevel@tonic-gate 	if ((hspp = meta_get_hsp_common(sp, hspnp,
701*0Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
702*0Sstevel@tonic-gate 		return (-1);
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	/* print appropriate detail */
705*0Sstevel@tonic-gate 	if (options & PRINT_SHORT)
706*0Sstevel@tonic-gate 		return (hsp_print(hspp, fname, fp, ep));
707*0Sstevel@tonic-gate 	else
708*0Sstevel@tonic-gate 		return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp));
709*0Sstevel@tonic-gate }
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate /*
712*0Sstevel@tonic-gate  * check for valid hotspare pool
713*0Sstevel@tonic-gate  */
714*0Sstevel@tonic-gate int
715*0Sstevel@tonic-gate metachkhsp(
716*0Sstevel@tonic-gate 	mdsetname_t	*sp,
717*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
718*0Sstevel@tonic-gate 	md_error_t	*ep
719*0Sstevel@tonic-gate )
720*0Sstevel@tonic-gate {
721*0Sstevel@tonic-gate 	if (meta_get_hsp(sp, hspnp, ep) == NULL)
722*0Sstevel@tonic-gate 		return (-1);
723*0Sstevel@tonic-gate 	return (0);
724*0Sstevel@tonic-gate }
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate /*
727*0Sstevel@tonic-gate  * invalidate hotspare pool info
728*0Sstevel@tonic-gate  */
729*0Sstevel@tonic-gate void
730*0Sstevel@tonic-gate meta_invalidate_hsp(
731*0Sstevel@tonic-gate 	mdhspname_t	*hspnp
732*0Sstevel@tonic-gate )
733*0Sstevel@tonic-gate {
734*0Sstevel@tonic-gate 	md_hsp_t	*hspp = hspnp->unitp;
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	/* free it up */
737*0Sstevel@tonic-gate 	if (hspp == NULL)
738*0Sstevel@tonic-gate 		return;
739*0Sstevel@tonic-gate 	meta_free_hsp(hspp);
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	/* clear cache */
742*0Sstevel@tonic-gate 	hspnp->unitp = NULL;
743*0Sstevel@tonic-gate }
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate /*
746*0Sstevel@tonic-gate  * add hotspares and/or hotspare pool
747*0Sstevel@tonic-gate  */
748*0Sstevel@tonic-gate int
749*0Sstevel@tonic-gate meta_hs_add(
750*0Sstevel@tonic-gate 	mdsetname_t	*sp,
751*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
752*0Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
753*0Sstevel@tonic-gate 	mdcmdopts_t	options,
754*0Sstevel@tonic-gate 	md_error_t	*ep
755*0Sstevel@tonic-gate )
756*0Sstevel@tonic-gate {
757*0Sstevel@tonic-gate 	mdnamelist_t	*p;
758*0Sstevel@tonic-gate 	set_hs_params_t	shs;
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	/* should have a set */
761*0Sstevel@tonic-gate 	assert(sp != NULL);
762*0Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	/* clear cache */
765*0Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	/* setup hotspare pool info */
768*0Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
769*0Sstevel@tonic-gate 	shs.shs_cmd = ADD_HOT_SPARE;
770*0Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
771*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	/* add empty hotspare pool */
774*0Sstevel@tonic-gate 	if (hsnlp == NULL) {
775*0Sstevel@tonic-gate 		shs.shs_options = HS_OPT_POOL;
776*0Sstevel@tonic-gate 		/* If DOIT is not set, it's a dryrun */
777*0Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) == 0) {
778*0Sstevel@tonic-gate 			shs.shs_options |= HS_OPT_DRYRUN;
779*0Sstevel@tonic-gate 		}
780*0Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
781*0Sstevel@tonic-gate 		    hspnp->hspname) != 0)
782*0Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
783*0Sstevel@tonic-gate 		goto success;
784*0Sstevel@tonic-gate 	}
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	/* add hotspares */
787*0Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
788*0Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
789*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
790*0Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
791*0Sstevel@tonic-gate 	}
792*0Sstevel@tonic-gate 	for (p = hsnlp; (p != NULL); p = p->next) {
793*0Sstevel@tonic-gate 		mdname_t	*hsnp = p->namep;
794*0Sstevel@tonic-gate 		diskaddr_t	size, label, start_blk;
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 		/* should be in same set */
797*0Sstevel@tonic-gate 		assert(sp->setno == HSP_SET(hspnp->hsp));
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 		/* check it out */
800*0Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
801*0Sstevel@tonic-gate 			return (-1);
802*0Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
803*0Sstevel@tonic-gate 			return (-1);
804*0Sstevel@tonic-gate 		else if (size == 0)
805*0Sstevel@tonic-gate 			return (mdsyserror(ep, ENOSPC, hsnp->cname));
806*0Sstevel@tonic-gate 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
807*0Sstevel@tonic-gate 			return (-1);
808*0Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, hsnp, ep))
809*0Sstevel@tonic-gate 		    == MD_DISKADDR_ERROR)
810*0Sstevel@tonic-gate 			return (-1);
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 		shs.shs_size_option = meta_check_devicesize(size);
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 		/* In dryrun mode (DOIT not set) we must not alter the mddb */
815*0Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
816*0Sstevel@tonic-gate 			/* store name in namespace */
817*0Sstevel@tonic-gate 			if (add_key_name(sp, hsnp, NULL, ep) != 0)
818*0Sstevel@tonic-gate 				return (-1);
819*0Sstevel@tonic-gate 		}
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 		/* add hotspare and/or hotspare pool */
822*0Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
823*0Sstevel@tonic-gate 		shs.shs_start_blk = start_blk;
824*0Sstevel@tonic-gate 		shs.shs_has_label = ((label > 0) ? 1 : 0);
825*0Sstevel@tonic-gate 		shs.shs_number_blks = size;
826*0Sstevel@tonic-gate 		shs.shs_key_old = hsnp->key;
827*0Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
828*0Sstevel@tonic-gate 			if ((options & MDCMD_DOIT) &&
829*0Sstevel@tonic-gate 			    (shs.shs_options != HS_OPT_POOL)) {
830*0Sstevel@tonic-gate 				(void) del_key_name(sp, hsnp, ep);
831*0Sstevel@tonic-gate 			}
832*0Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
833*0Sstevel@tonic-gate 		}
834*0Sstevel@tonic-gate 	}
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	/* print success message */
837*0Sstevel@tonic-gate success:
838*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
839*0Sstevel@tonic-gate 		if ((options & MDCMD_INIT) || (hsnlp == NULL)) {
840*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
841*0Sstevel@tonic-gate 			    "%s: Hotspare pool is setup\n"),
842*0Sstevel@tonic-gate 			    hspnp->hspname);
843*0Sstevel@tonic-gate 		} else if (hsnlp->next == NULL) {
844*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
845*0Sstevel@tonic-gate 			    "%s: Hotspare is added\n"),
846*0Sstevel@tonic-gate 			    hspnp->hspname);
847*0Sstevel@tonic-gate 		} else {
848*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
849*0Sstevel@tonic-gate 			    "%s: Hotspares are added\n"),
850*0Sstevel@tonic-gate 			    hspnp->hspname);
851*0Sstevel@tonic-gate 		}
852*0Sstevel@tonic-gate 		(void) fflush(stdout);
853*0Sstevel@tonic-gate 	}
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 	/* return success */
856*0Sstevel@tonic-gate 	return (0);
857*0Sstevel@tonic-gate }
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate /*
860*0Sstevel@tonic-gate  * delete hotspares from pool
861*0Sstevel@tonic-gate  */
862*0Sstevel@tonic-gate int
863*0Sstevel@tonic-gate meta_hs_delete(
864*0Sstevel@tonic-gate 	mdsetname_t	*sp,
865*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
866*0Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
867*0Sstevel@tonic-gate 	mdcmdopts_t	options,
868*0Sstevel@tonic-gate 	md_error_t	*ep
869*0Sstevel@tonic-gate )
870*0Sstevel@tonic-gate {
871*0Sstevel@tonic-gate 	mdnamelist_t	*p;
872*0Sstevel@tonic-gate 	set_hs_params_t	shs;
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	/* should have a set */
875*0Sstevel@tonic-gate 	assert(sp != NULL);
876*0Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	/* clear cache */
879*0Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	/* setup hotspare pool info */
882*0Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
883*0Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
884*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
885*0Sstevel@tonic-gate 	shs.shs_cmd = DELETE_HOT_SPARE;
886*0Sstevel@tonic-gate 
887*0Sstevel@tonic-gate 	/* delete empty hotspare pool */
888*0Sstevel@tonic-gate 	if (hsnlp == NULL) {
889*0Sstevel@tonic-gate 		shs.shs_options = HS_OPT_POOL;
890*0Sstevel@tonic-gate 		/* If DOIT is not set, it's a dryrun */
891*0Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) == 0) {
892*0Sstevel@tonic-gate 			shs.shs_options |= HS_OPT_DRYRUN;
893*0Sstevel@tonic-gate 		}
894*0Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
895*0Sstevel@tonic-gate 		    hspnp->hspname) != 0)
896*0Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
897*0Sstevel@tonic-gate 		goto success;
898*0Sstevel@tonic-gate 	}
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate 	/* delete hotspares */
901*0Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
902*0Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
903*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
904*0Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
905*0Sstevel@tonic-gate 	}
906*0Sstevel@tonic-gate 	for (p = hsnlp; (p != NULL); p = p->next) {
907*0Sstevel@tonic-gate 		mdname_t	*hsnp = p->namep;
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate 		/* should be in same set */
910*0Sstevel@tonic-gate 		assert(sp->setno == HSP_SET(hspnp->hsp));
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 		/* delete hotspare */
913*0Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
914*0Sstevel@tonic-gate 		meta_invalidate_name(hsnp);
915*0Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0)
916*0Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
917*0Sstevel@tonic-gate 	}
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 	/* print success message */
920*0Sstevel@tonic-gate success:
921*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
922*0Sstevel@tonic-gate 		if (hsnlp == NULL) {
923*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
924*0Sstevel@tonic-gate 			    "%s: Hotspare pool is cleared\n"),
925*0Sstevel@tonic-gate 			    hspnp->hspname);
926*0Sstevel@tonic-gate 		} else if (hsnlp->next == NULL) {
927*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
928*0Sstevel@tonic-gate 			    "%s: Hotspare is deleted\n"),
929*0Sstevel@tonic-gate 			    hspnp->hspname);
930*0Sstevel@tonic-gate 		} else {
931*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
932*0Sstevel@tonic-gate 			    "%s: Hotspares are deleted\n"),
933*0Sstevel@tonic-gate 			    hspnp->hspname);
934*0Sstevel@tonic-gate 		}
935*0Sstevel@tonic-gate 		(void) fflush(stdout);
936*0Sstevel@tonic-gate 	}
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 	/* return success */
939*0Sstevel@tonic-gate 	return (0);
940*0Sstevel@tonic-gate }
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate /*
943*0Sstevel@tonic-gate  * replace hotspare in pool
944*0Sstevel@tonic-gate  */
945*0Sstevel@tonic-gate int
946*0Sstevel@tonic-gate meta_hs_replace(
947*0Sstevel@tonic-gate 	mdsetname_t	*sp,
948*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
949*0Sstevel@tonic-gate 	mdname_t	*oldnp,
950*0Sstevel@tonic-gate 	mdname_t	*newnp,
951*0Sstevel@tonic-gate 	mdcmdopts_t	options,
952*0Sstevel@tonic-gate 	md_error_t	*ep
953*0Sstevel@tonic-gate )
954*0Sstevel@tonic-gate {
955*0Sstevel@tonic-gate 	set_hs_params_t	shs;
956*0Sstevel@tonic-gate 	diskaddr_t	size, label, start_blk;
957*0Sstevel@tonic-gate 	md_dev64_t	old_dev, new_dev;
958*0Sstevel@tonic-gate 	diskaddr_t	new_start_blk, new_end_blk;
959*0Sstevel@tonic-gate 	int		rebind;
960*0Sstevel@tonic-gate 	char		*new_devidp = NULL;
961*0Sstevel@tonic-gate 	int		ret;
962*0Sstevel@tonic-gate 	md_set_desc	*sd;
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	/* should be in same set */
965*0Sstevel@tonic-gate 	assert(sp != NULL);
966*0Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate 	/* save new binding incase this is a rebind where oldnp==newnp */
969*0Sstevel@tonic-gate 	new_dev = newnp->dev;
970*0Sstevel@tonic-gate 	new_start_blk = newnp->start_blk;
971*0Sstevel@tonic-gate 	new_end_blk = newnp->end_blk;
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	/* invalidate, then get the hotspare (fill in oldnp from metadb) */
974*0Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
975*0Sstevel@tonic-gate 	if (meta_get_hsp(sp, hspnp, ep) == NULL)
976*0Sstevel@tonic-gate 		return (-1);
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	/* the old device binding is now established */
979*0Sstevel@tonic-gate 	if ((old_dev = oldnp->dev) == NODEV64)
980*0Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, oldnp->cname));
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 	/*
983*0Sstevel@tonic-gate 	 * check for the case where oldnp and newnp indicate the same
984*0Sstevel@tonic-gate 	 * device, but the dev_t of the device has changed between old
985*0Sstevel@tonic-gate 	 * and new.  This is called a rebind.  On entry the dev_t
986*0Sstevel@tonic-gate 	 * represents the new device binding determined from the
987*0Sstevel@tonic-gate 	 * filesystem (meta_getdev). After calling meta_get_hsp
988*0Sstevel@tonic-gate 	 * oldnp (and maybe newnp if this is a rebind) is updated based
989*0Sstevel@tonic-gate 	 * to the old binding from the metadb (done by metakeyname).
990*0Sstevel@tonic-gate 	 */
991*0Sstevel@tonic-gate 	if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
992*0Sstevel@tonic-gate 	    (old_dev != new_dev)) {
993*0Sstevel@tonic-gate 		rebind = 1;
994*0Sstevel@tonic-gate 	} else {
995*0Sstevel@tonic-gate 		rebind = 0;
996*0Sstevel@tonic-gate 	}
997*0Sstevel@tonic-gate 	if (rebind) {
998*0Sstevel@tonic-gate 		newnp->dev = new_dev;
999*0Sstevel@tonic-gate 		newnp->start_blk = new_start_blk;
1000*0Sstevel@tonic-gate 		newnp->end_blk = new_end_blk;
1001*0Sstevel@tonic-gate 	}
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 	/*
1004*0Sstevel@tonic-gate 	 * Save a copy of the devid associated with the new disk, the reason
1005*0Sstevel@tonic-gate 	 * is that the meta_check_hotspare() call could cause the devid to
1006*0Sstevel@tonic-gate 	 * be changed to that of the devid that is currently stored in the
1007*0Sstevel@tonic-gate 	 * replica namespace for the disk in question. This devid could be
1008*0Sstevel@tonic-gate 	 * stale if we are replacing the disk. The function that overwrites
1009*0Sstevel@tonic-gate 	 * the devid is dr2drivedesc().
1010*0Sstevel@tonic-gate 	 */
1011*0Sstevel@tonic-gate 	if (newnp->drivenamep->devid != NULL)
1012*0Sstevel@tonic-gate 		new_devidp = Strdup(newnp->drivenamep->devid);
1013*0Sstevel@tonic-gate 
1014*0Sstevel@tonic-gate 	/* if it's a multi-node diskset clear new_devidp */
1015*0Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
1016*0Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1017*0Sstevel@tonic-gate 			Free(new_devidp);
1018*0Sstevel@tonic-gate 			return (-1);
1019*0Sstevel@tonic-gate 		}
1020*0Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
1021*0Sstevel@tonic-gate 			Free(new_devidp);
1022*0Sstevel@tonic-gate 			new_devidp = NULL;
1023*0Sstevel@tonic-gate 		}
1024*0Sstevel@tonic-gate 	}
1025*0Sstevel@tonic-gate 
1026*0Sstevel@tonic-gate 	/* check it out */
1027*0Sstevel@tonic-gate 	if (meta_check_hotspare(sp, newnp, ep) != 0) {
1028*0Sstevel@tonic-gate 		if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
1029*0Sstevel@tonic-gate 			Free(new_devidp);
1030*0Sstevel@tonic-gate 			return (-1);
1031*0Sstevel@tonic-gate 		}
1032*0Sstevel@tonic-gate 		mdclrerror(ep);
1033*0Sstevel@tonic-gate 	}
1034*0Sstevel@tonic-gate 	if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
1035*0Sstevel@tonic-gate 		Free(new_devidp);
1036*0Sstevel@tonic-gate 		return (-1);
1037*0Sstevel@tonic-gate 	}
1038*0Sstevel@tonic-gate 	if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
1039*0Sstevel@tonic-gate 		Free(new_devidp);
1040*0Sstevel@tonic-gate 		return (-1);
1041*0Sstevel@tonic-gate 	}
1042*0Sstevel@tonic-gate 	if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
1043*0Sstevel@tonic-gate 		Free(new_devidp);
1044*0Sstevel@tonic-gate 		return (-1);
1045*0Sstevel@tonic-gate 	}
1046*0Sstevel@tonic-gate 	if (start_blk >= size) {
1047*0Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, newnp->cname);
1048*0Sstevel@tonic-gate 		Free(new_devidp);
1049*0Sstevel@tonic-gate 		return (-1);
1050*0Sstevel@tonic-gate 	}
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
1053*0Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
1054*0Sstevel@tonic-gate 		/* store name in namespace */
1055*0Sstevel@tonic-gate 		if (add_key_name(sp, newnp, NULL, ep) != 0)
1056*0Sstevel@tonic-gate 			return (-1);
1057*0Sstevel@tonic-gate 	}
1058*0Sstevel@tonic-gate 
1059*0Sstevel@tonic-gate 	/*
1060*0Sstevel@tonic-gate 	 * Copy back the saved devid.
1061*0Sstevel@tonic-gate 	 */
1062*0Sstevel@tonic-gate 	Free(newnp->drivenamep->devid);
1063*0Sstevel@tonic-gate 	if (new_devidp != NULL) {
1064*0Sstevel@tonic-gate 		newnp->drivenamep->devid = new_devidp;
1065*0Sstevel@tonic-gate 		new_devidp = NULL;
1066*0Sstevel@tonic-gate 	}
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
1069*0Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
1070*0Sstevel@tonic-gate 		/* store name in namespace */
1071*0Sstevel@tonic-gate 		if (add_key_name(sp, newnp, NULL, ep) != 0)
1072*0Sstevel@tonic-gate 			return (-1);
1073*0Sstevel@tonic-gate 	}
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	if (rebind && !metaislocalset(sp)) {
1076*0Sstevel@tonic-gate 		/*
1077*0Sstevel@tonic-gate 		 * We are 'rebind'ing a disk that is in a diskset so as well
1078*0Sstevel@tonic-gate 		 * as updating the diskset's namespace the local set needs
1079*0Sstevel@tonic-gate 		 * to be updated because it also contains a reference to the
1080*0Sstevel@tonic-gate 		 * disk in question.
1081*0Sstevel@tonic-gate 		 */
1082*0Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname,
1083*0Sstevel@tonic-gate 		    ep);
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
1086*0Sstevel@tonic-gate 			md_error_t	xep = mdnullerror;
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate 			/*
1089*0Sstevel@tonic-gate 			 * In dryrun mode (DOIT not set) we must not alter
1090*0Sstevel@tonic-gate 			 * the mddb
1091*0Sstevel@tonic-gate 			 */
1092*0Sstevel@tonic-gate 			if (options & MDCMD_DOIT) {
1093*0Sstevel@tonic-gate 				(void) del_key_name(sp, newnp, &xep);
1094*0Sstevel@tonic-gate 				mdclrerror(&xep);
1095*0Sstevel@tonic-gate 				return (-1);
1096*0Sstevel@tonic-gate 			}
1097*0Sstevel@tonic-gate 		}
1098*0Sstevel@tonic-gate 	}
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate 	/* replace hotspare */
1101*0Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate 	shs.shs_size_option = meta_check_devicesize(size);
1104*0Sstevel@tonic-gate 
1105*0Sstevel@tonic-gate 	shs.shs_cmd = REPLACE_HOT_SPARE;
1106*0Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
1107*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1108*0Sstevel@tonic-gate 	shs.shs_component_old = old_dev;
1109*0Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
1110*0Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
1111*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
1112*0Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
1113*0Sstevel@tonic-gate 	}
1114*0Sstevel@tonic-gate 	shs.shs_component_new = new_dev;
1115*0Sstevel@tonic-gate 	shs.shs_start_blk = start_blk;
1116*0Sstevel@tonic-gate 	shs.shs_has_label = ((label > 0) ? 1 : 0);
1117*0Sstevel@tonic-gate 	shs.shs_number_blks = size;
1118*0Sstevel@tonic-gate 	shs.shs_key_new = newnp->key;
1119*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1120*0Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
1121*0Sstevel@tonic-gate 			(void) del_key_name(sp, newnp, ep);
1122*0Sstevel@tonic-gate 		}
1123*0Sstevel@tonic-gate 		return (mdstealerror(ep, &shs.mde));
1124*0Sstevel@tonic-gate 	}
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	/* clear cache */
1127*0Sstevel@tonic-gate 	meta_invalidate_name(oldnp);
1128*0Sstevel@tonic-gate 	meta_invalidate_name(newnp);
1129*0Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate 	/* let em know */
1132*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
1133*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
1134*0Sstevel@tonic-gate 		    "%s: Hotspare %s is replaced with %s\n"),
1135*0Sstevel@tonic-gate 		    hspnp->hspname, oldnp->cname, newnp->cname);
1136*0Sstevel@tonic-gate 		(void) fflush(stdout);
1137*0Sstevel@tonic-gate 	}
1138*0Sstevel@tonic-gate 
1139*0Sstevel@tonic-gate 	/* return success */
1140*0Sstevel@tonic-gate 	return (0);
1141*0Sstevel@tonic-gate }
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate /*
1144*0Sstevel@tonic-gate  * enable hotspares
1145*0Sstevel@tonic-gate  */
1146*0Sstevel@tonic-gate int
1147*0Sstevel@tonic-gate meta_hs_enable(
1148*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1149*0Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
1150*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1151*0Sstevel@tonic-gate 	md_error_t	*ep
1152*0Sstevel@tonic-gate )
1153*0Sstevel@tonic-gate {
1154*0Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
1155*0Sstevel@tonic-gate 	mdhspnamelist_t	*hspnp;
1156*0Sstevel@tonic-gate 	set_hs_params_t	shs;
1157*0Sstevel@tonic-gate 	int		rval = -1;
1158*0Sstevel@tonic-gate 
1159*0Sstevel@tonic-gate 	/* should have a set */
1160*0Sstevel@tonic-gate 	assert(sp != NULL);
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate 	/* setup device info */
1163*0Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
1164*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1165*0Sstevel@tonic-gate 	shs.shs_cmd = FIX_HOT_SPARE;
1166*0Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
1167*0Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
1168*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
1169*0Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
1170*0Sstevel@tonic-gate 	}
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate 	/* get the list of hotspare names */
1173*0Sstevel@tonic-gate 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1174*0Sstevel@tonic-gate 		goto out;
1175*0Sstevel@tonic-gate 
1176*0Sstevel@tonic-gate 	/* enable hotspares for each components */
1177*0Sstevel@tonic-gate 	for (; (hsnlp != NULL); hsnlp = hsnlp->next) {
1178*0Sstevel@tonic-gate 		mdname_t	*hsnp = hsnlp->namep;
1179*0Sstevel@tonic-gate 		md_dev64_t	fs_dev;
1180*0Sstevel@tonic-gate 		int		rebind = 0;
1181*0Sstevel@tonic-gate 		diskaddr_t	size, label, start_blk;
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 		/* get the file_system dev binding */
1184*0Sstevel@tonic-gate 		if (meta_getdev(sp, hsnp, ep) != 0)
1185*0Sstevel@tonic-gate 			return (-1);
1186*0Sstevel@tonic-gate 		fs_dev = hsnp->dev;
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 		/*
1189*0Sstevel@tonic-gate 		 * search for the component in each hotspare pool
1190*0Sstevel@tonic-gate 		 * and replace it (instead of enable) if the binding
1191*0Sstevel@tonic-gate 		 * has changed.
1192*0Sstevel@tonic-gate 		 */
1193*0Sstevel@tonic-gate 		for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1194*0Sstevel@tonic-gate 			/*
1195*0Sstevel@tonic-gate 			 * in_hsp will call meta_get_hsp which will fill
1196*0Sstevel@tonic-gate 			 * in hspnp with metadb version of component
1197*0Sstevel@tonic-gate 			 */
1198*0Sstevel@tonic-gate 			meta_invalidate_hsp(hspnp->hspnamep);
1199*0Sstevel@tonic-gate 			if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) {
1200*0Sstevel@tonic-gate 				/*
1201*0Sstevel@tonic-gate 				 * check for the case where the dev_t has
1202*0Sstevel@tonic-gate 				 * changed between the filesystem and the
1203*0Sstevel@tonic-gate 				 * metadb.  This is called a rebind, and
1204*0Sstevel@tonic-gate 				 * is handled by meta_hs_replace.
1205*0Sstevel@tonic-gate 				 */
1206*0Sstevel@tonic-gate 				if (fs_dev != hsnp->dev) {
1207*0Sstevel@tonic-gate 					/*
1208*0Sstevel@tonic-gate 					 * establish file system binding
1209*0Sstevel@tonic-gate 					 * with invalid start/end
1210*0Sstevel@tonic-gate 					 */
1211*0Sstevel@tonic-gate 					rebind++;
1212*0Sstevel@tonic-gate 					hsnp->dev = fs_dev;
1213*0Sstevel@tonic-gate 					hsnp->start_blk = -1;
1214*0Sstevel@tonic-gate 					hsnp->end_blk = -1;
1215*0Sstevel@tonic-gate 					rval = meta_hs_replace(sp,
1216*0Sstevel@tonic-gate 					    hspnp->hspnamep,
1217*0Sstevel@tonic-gate 					    hsnp, hsnp, options, ep);
1218*0Sstevel@tonic-gate 					if (rval != 0)
1219*0Sstevel@tonic-gate 						goto out;
1220*0Sstevel@tonic-gate 				}
1221*0Sstevel@tonic-gate 			}
1222*0Sstevel@tonic-gate 		}
1223*0Sstevel@tonic-gate 		if (rebind)
1224*0Sstevel@tonic-gate 			continue;
1225*0Sstevel@tonic-gate 
1226*0Sstevel@tonic-gate 		/* enable the component in all hotspares that use it */
1227*0Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1228*0Sstevel@tonic-gate 			goto out;
1229*0Sstevel@tonic-gate 
1230*0Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
1231*0Sstevel@tonic-gate 			goto out;
1232*0Sstevel@tonic-gate 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
1233*0Sstevel@tonic-gate 			goto out;
1234*0Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, hsnp, ep))
1235*0Sstevel@tonic-gate 		    == MD_DISKADDR_ERROR)
1236*0Sstevel@tonic-gate 			goto out;
1237*0Sstevel@tonic-gate 		if (start_blk >= size) {
1238*0Sstevel@tonic-gate 			(void) mdsyserror(ep, ENOSPC, hsnp->cname);
1239*0Sstevel@tonic-gate 			goto out;
1240*0Sstevel@tonic-gate 		}
1241*0Sstevel@tonic-gate 
1242*0Sstevel@tonic-gate 		/* enable hotspare */
1243*0Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
1244*0Sstevel@tonic-gate 		shs.shs_component_new = hsnp->dev;
1245*0Sstevel@tonic-gate 		shs.shs_start_blk = start_blk;
1246*0Sstevel@tonic-gate 		shs.shs_has_label = ((label > 0) ? 1 : 0);
1247*0Sstevel@tonic-gate 		shs.shs_number_blks = size;
1248*0Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) {
1249*0Sstevel@tonic-gate 			rval = mdstealerror(ep, &shs.mde);
1250*0Sstevel@tonic-gate 			goto out;
1251*0Sstevel@tonic-gate 		}
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 		/*
1254*0Sstevel@tonic-gate 		 * Are we dealing with a non-local set? If so need to update
1255*0Sstevel@tonic-gate 		 * the local namespace so that the disk record has the correct
1256*0Sstevel@tonic-gate 		 * devid.
1257*0Sstevel@tonic-gate 		 */
1258*0Sstevel@tonic-gate 		if (!metaislocalset(sp)) {
1259*0Sstevel@tonic-gate 			rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
1260*0Sstevel@tonic-gate 			    hsnp->cname, ep);
1261*0Sstevel@tonic-gate 
1262*0Sstevel@tonic-gate 			if (rval != METADEVADM_SUCCESS) {
1263*0Sstevel@tonic-gate 				/*
1264*0Sstevel@tonic-gate 				 * Failed to update the local set. Nothing to
1265*0Sstevel@tonic-gate 				 * do here apart from report the error. The
1266*0Sstevel@tonic-gate 				 * namespace is most likely broken and some
1267*0Sstevel@tonic-gate 				 * form of remedial recovery is going to
1268*0Sstevel@tonic-gate 				 * be required.
1269*0Sstevel@tonic-gate 				 */
1270*0Sstevel@tonic-gate 				mde_perror(ep, "");
1271*0Sstevel@tonic-gate 				mdclrerror(ep);
1272*0Sstevel@tonic-gate 			}
1273*0Sstevel@tonic-gate 		}
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate 		/* clear cache */
1276*0Sstevel@tonic-gate 		meta_invalidate_name(hsnp);
1277*0Sstevel@tonic-gate 
1278*0Sstevel@tonic-gate 		/* let em know */
1279*0Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
1280*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
1281*0Sstevel@tonic-gate 			    "hotspare %s is enabled\n"),
1282*0Sstevel@tonic-gate 			    hsnp->cname);
1283*0Sstevel@tonic-gate 			(void) fflush(stdout);
1284*0Sstevel@tonic-gate 		}
1285*0Sstevel@tonic-gate 	}
1286*0Sstevel@tonic-gate 
1287*0Sstevel@tonic-gate 	/* clear whole cache */
1288*0Sstevel@tonic-gate 	for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1289*0Sstevel@tonic-gate 		meta_invalidate_hsp(hspnp->hspnamep);
1290*0Sstevel@tonic-gate 	}
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate 
1293*0Sstevel@tonic-gate 	/* return success */
1294*0Sstevel@tonic-gate 	rval = 0;
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate out:
1297*0Sstevel@tonic-gate 	if (hspnlp)
1298*0Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
1299*0Sstevel@tonic-gate 	return (rval);
1300*0Sstevel@tonic-gate }
1301*0Sstevel@tonic-gate 
1302*0Sstevel@tonic-gate /*
1303*0Sstevel@tonic-gate  * check for dups in the hsp itself
1304*0Sstevel@tonic-gate  */
1305*0Sstevel@tonic-gate static int
1306*0Sstevel@tonic-gate check_twice(
1307*0Sstevel@tonic-gate 	md_hsp_t	*hspp,
1308*0Sstevel@tonic-gate 	uint_t		hsi,
1309*0Sstevel@tonic-gate 	md_error_t	*ep
1310*0Sstevel@tonic-gate )
1311*0Sstevel@tonic-gate {
1312*0Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
1313*0Sstevel@tonic-gate 	mdname_t	*thisnp;
1314*0Sstevel@tonic-gate 	uint_t		h;
1315*0Sstevel@tonic-gate 
1316*0Sstevel@tonic-gate 	thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep;
1317*0Sstevel@tonic-gate 	for (h = 0; (h < hsi); ++h) {
1318*0Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[h];
1319*0Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
1320*0Sstevel@tonic-gate 
1321*0Sstevel@tonic-gate 		if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1,
1322*0Sstevel@tonic-gate 		    hsnp, 0, -1, ep) != 0)
1323*0Sstevel@tonic-gate 			return (-1);
1324*0Sstevel@tonic-gate 	}
1325*0Sstevel@tonic-gate 	return (0);
1326*0Sstevel@tonic-gate }
1327*0Sstevel@tonic-gate 
1328*0Sstevel@tonic-gate /*
1329*0Sstevel@tonic-gate  * check hsp
1330*0Sstevel@tonic-gate  */
1331*0Sstevel@tonic-gate /*ARGSUSED2*/
1332*0Sstevel@tonic-gate int
1333*0Sstevel@tonic-gate meta_check_hsp(
1334*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1335*0Sstevel@tonic-gate 	md_hsp_t	*hspp,
1336*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1337*0Sstevel@tonic-gate 	md_error_t	*ep
1338*0Sstevel@tonic-gate )
1339*0Sstevel@tonic-gate {
1340*0Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
1341*0Sstevel@tonic-gate 	uint_t		hsi;
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 	/* check hotspares */
1344*0Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1345*0Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1346*0Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
1347*0Sstevel@tonic-gate 		diskaddr_t	size;
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 		/* check hotspare */
1350*0Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
1351*0Sstevel@tonic-gate 			return (-1);
1352*0Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) {
1353*0Sstevel@tonic-gate 			return (-1);
1354*0Sstevel@tonic-gate 		} else if (size == 0) {
1355*0Sstevel@tonic-gate 			return (mdsyserror(ep, ENOSPC, hspnp->hspname));
1356*0Sstevel@tonic-gate 		}
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate 		/* check this hsp too */
1359*0Sstevel@tonic-gate 		if (check_twice(hspp, hsi, ep) != 0)
1360*0Sstevel@tonic-gate 			return (-1);
1361*0Sstevel@tonic-gate 	}
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 	/* return success */
1364*0Sstevel@tonic-gate 	return (0);
1365*0Sstevel@tonic-gate }
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate /*
1368*0Sstevel@tonic-gate  * create hsp
1369*0Sstevel@tonic-gate  */
1370*0Sstevel@tonic-gate int
1371*0Sstevel@tonic-gate meta_create_hsp(
1372*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1373*0Sstevel@tonic-gate 	md_hsp_t	*hspp,
1374*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1375*0Sstevel@tonic-gate 	md_error_t	*ep
1376*0Sstevel@tonic-gate )
1377*0Sstevel@tonic-gate {
1378*0Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
1379*0Sstevel@tonic-gate 	mdnamelist_t	*hsnlp = NULL;
1380*0Sstevel@tonic-gate 	uint_t		hsi;
1381*0Sstevel@tonic-gate 	int		rval = -1;
1382*0Sstevel@tonic-gate 
1383*0Sstevel@tonic-gate 	/* validate hsp */
1384*0Sstevel@tonic-gate 	if (meta_check_hsp(sp, hspp, options, ep) != 0)
1385*0Sstevel@tonic-gate 		return (-1);
1386*0Sstevel@tonic-gate 
1387*0Sstevel@tonic-gate 	/* if we're not doing anything, return success */
1388*0Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT))
1389*0Sstevel@tonic-gate 		return (0);
1390*0Sstevel@tonic-gate 
1391*0Sstevel@tonic-gate 	/* create hsp */
1392*0Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1393*0Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1394*0Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate 		(void) metanamelist_append(&hsnlp, hsnp);
1397*0Sstevel@tonic-gate 	}
1398*0Sstevel@tonic-gate 	options |= MDCMD_INIT;
1399*0Sstevel@tonic-gate 	rval = meta_hs_add(sp, hspnp, hsnlp, options, ep);
1400*0Sstevel@tonic-gate 
1401*0Sstevel@tonic-gate 	/* cleanup, return success */
1402*0Sstevel@tonic-gate 	metafreenamelist(hsnlp);
1403*0Sstevel@tonic-gate 	return (rval);
1404*0Sstevel@tonic-gate }
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate /*
1407*0Sstevel@tonic-gate  * initialize hsp
1408*0Sstevel@tonic-gate  * NOTE: this functions is metainit(1m)'s command line parser!
1409*0Sstevel@tonic-gate  */
1410*0Sstevel@tonic-gate int
1411*0Sstevel@tonic-gate meta_init_hsp(
1412*0Sstevel@tonic-gate 	mdsetname_t	**spp,
1413*0Sstevel@tonic-gate 	int		argc,
1414*0Sstevel@tonic-gate 	char		*argv[],
1415*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1416*0Sstevel@tonic-gate 	md_error_t	*ep
1417*0Sstevel@tonic-gate )
1418*0Sstevel@tonic-gate {
1419*0Sstevel@tonic-gate 	char		*uname = argv[0];
1420*0Sstevel@tonic-gate 	mdhspname_t	*hspnp = NULL;
1421*0Sstevel@tonic-gate 	md_hsp_t	*hspp = NULL;
1422*0Sstevel@tonic-gate 	uint_t		hsi;
1423*0Sstevel@tonic-gate 	int		rval = -1;
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate 	/* get hsp name */
1427*0Sstevel@tonic-gate 	assert(argc > 0);
1428*0Sstevel@tonic-gate 	if (argc < 1)
1429*0Sstevel@tonic-gate 		goto syntax;
1430*0Sstevel@tonic-gate 	if ((hspnp = metahspname(spp, uname, ep)) == NULL)
1431*0Sstevel@tonic-gate 		goto out;
1432*0Sstevel@tonic-gate 	assert(*spp != NULL);
1433*0Sstevel@tonic-gate 	uname = hspnp->hspname;
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
1436*0Sstevel@tonic-gate 		/* grab set lock */
1437*0Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep))
1438*0Sstevel@tonic-gate 			goto out;
1439*0Sstevel@tonic-gate 
1440*0Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
1441*0Sstevel@tonic-gate 			goto out;
1442*0Sstevel@tonic-gate 	}
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 	/* see if it exists already */
1445*0Sstevel@tonic-gate 	if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
1446*0Sstevel@tonic-gate 		(void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP, hspnp->hsp, uname);
1447*0Sstevel@tonic-gate 		goto out;
1448*0Sstevel@tonic-gate 	} else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
1449*0Sstevel@tonic-gate 		goto out;
1450*0Sstevel@tonic-gate 	} else {
1451*0Sstevel@tonic-gate 		mdclrerror(ep);
1452*0Sstevel@tonic-gate 	}
1453*0Sstevel@tonic-gate 	--argc, ++argv;
1454*0Sstevel@tonic-gate 
1455*0Sstevel@tonic-gate 	/* parse general options */
1456*0Sstevel@tonic-gate 	optind = 0;
1457*0Sstevel@tonic-gate 	opterr = 0;
1458*0Sstevel@tonic-gate 	if (getopt(argc, argv, "") != -1)
1459*0Sstevel@tonic-gate 		goto options;
1460*0Sstevel@tonic-gate 
1461*0Sstevel@tonic-gate 	/* allocate hsp */
1462*0Sstevel@tonic-gate 	hspp = Zalloc(sizeof (*hspp));
1463*0Sstevel@tonic-gate 	hspp->hotspares.hotspares_len = argc;
1464*0Sstevel@tonic-gate 	if (argc > 0) {
1465*0Sstevel@tonic-gate 		hspp->hotspares.hotspares_val =
1466*0Sstevel@tonic-gate 		    Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
1467*0Sstevel@tonic-gate 	}
1468*0Sstevel@tonic-gate 
1469*0Sstevel@tonic-gate 	/* setup pool */
1470*0Sstevel@tonic-gate 	hspp->hspnamep = hspnp;
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate 	/* parse hotspares */
1473*0Sstevel@tonic-gate 	for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
1474*0Sstevel@tonic-gate 	    ++hsi) {
1475*0Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
1476*0Sstevel@tonic-gate 		mdname_t	*hsnamep;
1477*0Sstevel@tonic-gate 
1478*0Sstevel@tonic-gate 		/* parse hotspare name */
1479*0Sstevel@tonic-gate 		if ((hsnamep = metaname(spp, argv[0], ep)) == NULL)
1480*0Sstevel@tonic-gate 			goto out;
1481*0Sstevel@tonic-gate 		hsp->hsnamep = hsnamep;
1482*0Sstevel@tonic-gate 		--argc, ++argv;
1483*0Sstevel@tonic-gate 	}
1484*0Sstevel@tonic-gate 
1485*0Sstevel@tonic-gate 	/* we should be at the end */
1486*0Sstevel@tonic-gate 	if (argc != 0)
1487*0Sstevel@tonic-gate 		goto syntax;
1488*0Sstevel@tonic-gate 
1489*0Sstevel@tonic-gate 	/* create hotspare pool */
1490*0Sstevel@tonic-gate 	if (meta_create_hsp(*spp, hspp, options, ep) != 0)
1491*0Sstevel@tonic-gate 		goto out;
1492*0Sstevel@tonic-gate 	rval = 0;	/* success */
1493*0Sstevel@tonic-gate 	goto out;
1494*0Sstevel@tonic-gate 
1495*0Sstevel@tonic-gate 	/* syntax error */
1496*0Sstevel@tonic-gate syntax:
1497*0Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
1498*0Sstevel@tonic-gate 	goto out;
1499*0Sstevel@tonic-gate 
1500*0Sstevel@tonic-gate 	/* options error */
1501*0Sstevel@tonic-gate options:
1502*0Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
1503*0Sstevel@tonic-gate 	goto out;
1504*0Sstevel@tonic-gate 
1505*0Sstevel@tonic-gate 	/* cleanup, return error */
1506*0Sstevel@tonic-gate out:
1507*0Sstevel@tonic-gate 	if (hspp != NULL)
1508*0Sstevel@tonic-gate 		meta_free_hsp(hspp);
1509*0Sstevel@tonic-gate 	return (rval);
1510*0Sstevel@tonic-gate }
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate /*
1513*0Sstevel@tonic-gate  * reset hotspare pool
1514*0Sstevel@tonic-gate  */
1515*0Sstevel@tonic-gate int
1516*0Sstevel@tonic-gate meta_hsp_reset(
1517*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1518*0Sstevel@tonic-gate 	mdhspname_t	*hspnp,
1519*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1520*0Sstevel@tonic-gate 	md_error_t	*ep
1521*0Sstevel@tonic-gate )
1522*0Sstevel@tonic-gate {
1523*0Sstevel@tonic-gate 	md_hsp_t	*hspp;
1524*0Sstevel@tonic-gate 	set_hs_params_t	shs;
1525*0Sstevel@tonic-gate 	uint_t		i;
1526*0Sstevel@tonic-gate 	int		rval = -1;
1527*0Sstevel@tonic-gate 
1528*0Sstevel@tonic-gate 	/* should have the same set */
1529*0Sstevel@tonic-gate 	assert(sp != NULL);
1530*0Sstevel@tonic-gate 	assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp)));
1531*0Sstevel@tonic-gate 
1532*0Sstevel@tonic-gate 	/* reset all hotspares */
1533*0Sstevel@tonic-gate 	if (hspnp == NULL) {
1534*0Sstevel@tonic-gate 		mdhspnamelist_t	*hspnlp = NULL;
1535*0Sstevel@tonic-gate 		mdhspnamelist_t	*p;
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate 		/* for each hotspare pool */
1538*0Sstevel@tonic-gate 		rval = 0;
1539*0Sstevel@tonic-gate 		if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1540*0Sstevel@tonic-gate 			return (-1);
1541*0Sstevel@tonic-gate 		for (p = hspnlp; (p != NULL); p = p->next) {
1542*0Sstevel@tonic-gate 			/* reset hotspare pool */
1543*0Sstevel@tonic-gate 			hspnp = p->hspnamep;
1544*0Sstevel@tonic-gate 
1545*0Sstevel@tonic-gate 			/*
1546*0Sstevel@tonic-gate 			 * If this is a multi-node set, we send a series
1547*0Sstevel@tonic-gate 			 * of individual metaclear commands.
1548*0Sstevel@tonic-gate 			 */
1549*0Sstevel@tonic-gate 			if (meta_is_mn_set(sp, ep)) {
1550*0Sstevel@tonic-gate 				if (meta_mn_send_metaclear_command(sp,
1551*0Sstevel@tonic-gate 				    hspnp->hspname, options, 0, ep) != 0) {
1552*0Sstevel@tonic-gate 					rval = -1;
1553*0Sstevel@tonic-gate 					break;
1554*0Sstevel@tonic-gate 				}
1555*0Sstevel@tonic-gate 			} else {
1556*0Sstevel@tonic-gate 				if (meta_hsp_reset(sp, hspnp, options,
1557*0Sstevel@tonic-gate 				    ep) != 0) {
1558*0Sstevel@tonic-gate 					rval = -1;
1559*0Sstevel@tonic-gate 					break;
1560*0Sstevel@tonic-gate 				}
1561*0Sstevel@tonic-gate 			}
1562*0Sstevel@tonic-gate 		}
1563*0Sstevel@tonic-gate 
1564*0Sstevel@tonic-gate 		/* cleanup, return success */
1565*0Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
1566*0Sstevel@tonic-gate 		return (rval);
1567*0Sstevel@tonic-gate 	}
1568*0Sstevel@tonic-gate 
1569*0Sstevel@tonic-gate 	/* get unit structure */
1570*0Sstevel@tonic-gate 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
1571*0Sstevel@tonic-gate 		return (-1);
1572*0Sstevel@tonic-gate 
1573*0Sstevel@tonic-gate 	/* make sure nobody owns us */
1574*0Sstevel@tonic-gate 	if (hspp->refcount > 0) {
1575*0Sstevel@tonic-gate 		return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
1576*0Sstevel@tonic-gate 		    hspnp->hspname));
1577*0Sstevel@tonic-gate 	}
1578*0Sstevel@tonic-gate 
1579*0Sstevel@tonic-gate 	/* clear hotspare pool members */
1580*0Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
1581*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1582*0Sstevel@tonic-gate 	shs.shs_cmd = DELETE_HOT_SPARE;
1583*0Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
1584*0Sstevel@tonic-gate 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
1585*0Sstevel@tonic-gate 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
1586*0Sstevel@tonic-gate 		mdname_t	*hsnamep = hs->hsnamep;
1587*0Sstevel@tonic-gate 
1588*0Sstevel@tonic-gate 		/* clear cache */
1589*0Sstevel@tonic-gate 		meta_invalidate_name(hsnamep);
1590*0Sstevel@tonic-gate 
1591*0Sstevel@tonic-gate 		/* clear hotspare */
1592*0Sstevel@tonic-gate 		shs.shs_component_old = hsnamep->dev;
1593*0Sstevel@tonic-gate 		shs.shs_options = HS_OPT_FORCE;
1594*0Sstevel@tonic-gate 		/* If DOIT is not set, it's a dryrun */
1595*0Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) == 0) {
1596*0Sstevel@tonic-gate 			shs.shs_options |= HS_OPT_DRYRUN;
1597*0Sstevel@tonic-gate 		}
1598*0Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1599*0Sstevel@tonic-gate 			(void) mdstealerror(ep, &shs.mde);
1600*0Sstevel@tonic-gate 			goto out;
1601*0Sstevel@tonic-gate 		}
1602*0Sstevel@tonic-gate 	}
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 	/* clear hotspare pool */
1605*0Sstevel@tonic-gate 	shs.shs_options = HS_OPT_POOL;
1606*0Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
1607*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
1608*0Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
1609*0Sstevel@tonic-gate 	}
1610*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hspnp->hspname) != 0) {
1611*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &shs.mde);
1612*0Sstevel@tonic-gate 		goto out;
1613*0Sstevel@tonic-gate 	}
1614*0Sstevel@tonic-gate 	rval = 0;	/* success */
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate 	/* let em know */
1617*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
1618*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
1619*0Sstevel@tonic-gate 		    "%s: Hotspare pool is cleared\n"),
1620*0Sstevel@tonic-gate 		    hspnp->hspname);
1621*0Sstevel@tonic-gate 		(void) fflush(stdout);
1622*0Sstevel@tonic-gate 	}
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate 	/* clear subdevices (nothing to do) */
1625*0Sstevel@tonic-gate 
1626*0Sstevel@tonic-gate 	/* cleanup, return success */
1627*0Sstevel@tonic-gate out:
1628*0Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
1629*0Sstevel@tonic-gate 	return (rval);
1630*0Sstevel@tonic-gate }
1631