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  * stripe operations
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include <limits.h>
42*0Sstevel@tonic-gate #include <stdlib.h>
43*0Sstevel@tonic-gate #include <meta.h>
44*0Sstevel@tonic-gate #include <sys/lvm/md_stripe.h>
45*0Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate #define	QUOTE(x)	#x
48*0Sstevel@tonic-gate #define	VAL2STR(x)	QUOTE(x)
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate /*
51*0Sstevel@tonic-gate  * replace stripe/concat
52*0Sstevel@tonic-gate  */
53*0Sstevel@tonic-gate int
54*0Sstevel@tonic-gate meta_stripe_replace(
55*0Sstevel@tonic-gate 	mdsetname_t	*sp,
56*0Sstevel@tonic-gate 	mdname_t	*stripenp,
57*0Sstevel@tonic-gate 	mdname_t	*oldnp,
58*0Sstevel@tonic-gate 	mdname_t	*newnp,
59*0Sstevel@tonic-gate 	mdcmdopts_t	options,
60*0Sstevel@tonic-gate 	md_error_t	*ep
61*0Sstevel@tonic-gate )
62*0Sstevel@tonic-gate {
63*0Sstevel@tonic-gate 	replace_params_t	params;
64*0Sstevel@tonic-gate 	md_dev64_t		old_dev,
65*0Sstevel@tonic-gate 				new_dev;
66*0Sstevel@tonic-gate 	diskaddr_t		new_start_blk,
67*0Sstevel@tonic-gate 				new_end_blk,
68*0Sstevel@tonic-gate 				label,
69*0Sstevel@tonic-gate 				size,
70*0Sstevel@tonic-gate 				start_blk;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate 	/* should have same set */
73*0Sstevel@tonic-gate 	assert(sp != NULL);
74*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	new_dev = newnp->dev;
77*0Sstevel@tonic-gate 	new_start_blk = newnp->start_blk;
78*0Sstevel@tonic-gate 	new_end_blk = newnp->end_blk;
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 	meta_invalidate_name(stripenp);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	/* the old device binding is now established */
83*0Sstevel@tonic-gate 	if ((old_dev = oldnp->dev) == NODEV64)
84*0Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, oldnp->cname));
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	if (((strcmp(oldnp->rname, newnp->rname) == 0) &&
87*0Sstevel@tonic-gate 	    (old_dev != new_dev))) {
88*0Sstevel@tonic-gate 		newnp->dev = new_dev;
89*0Sstevel@tonic-gate 		newnp->start_blk = new_start_blk;
90*0Sstevel@tonic-gate 		newnp->end_blk = new_end_blk;
91*0Sstevel@tonic-gate 	}
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR)
94*0Sstevel@tonic-gate 		return (-1);
95*0Sstevel@tonic-gate 	if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR)
96*0Sstevel@tonic-gate 		return (-1);
97*0Sstevel@tonic-gate 	if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR)
98*0Sstevel@tonic-gate 		return (-1);
99*0Sstevel@tonic-gate 	if (start_blk >= size) {
100*0Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, newnp->cname);
101*0Sstevel@tonic-gate 		return (-1);
102*0Sstevel@tonic-gate 	}
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
105*0Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
106*0Sstevel@tonic-gate 		if (add_key_name(sp, newnp, NULL, ep) != 0)
107*0Sstevel@tonic-gate 			return (-1);
108*0Sstevel@tonic-gate 	}
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	/*
111*0Sstevel@tonic-gate 	 * There is no need to call meta_fixdevid() here as this function is
112*0Sstevel@tonic-gate 	 * only called by the metareplace -c command which actually does
113*0Sstevel@tonic-gate 	 * nothing (in terms of a resync) and thus does nothing with the devid.
114*0Sstevel@tonic-gate 	 */
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	(void) memset(&params, 0, sizeof (params));
117*0Sstevel@tonic-gate 	params.mnum = meta_getminor(stripenp->dev);
118*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&params, MD_STRIPE, sp->setno);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	params.cmd = REPLACE_COMP;
121*0Sstevel@tonic-gate 	params.old_dev = old_dev;
122*0Sstevel@tonic-gate 	params.new_dev = new_dev;
123*0Sstevel@tonic-gate 	params.new_key = newnp->key;
124*0Sstevel@tonic-gate 	params.start_blk = newnp->start_blk;
125*0Sstevel@tonic-gate 	params.number_blks = size;
126*0Sstevel@tonic-gate 	/* Is this just a dryrun ? */
127*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
128*0Sstevel@tonic-gate 		params.options |= MDIOCTL_DRYRUN;
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 	if (label == 0)
131*0Sstevel@tonic-gate 		params.has_label = 0;
132*0Sstevel@tonic-gate 	else
133*0Sstevel@tonic-gate 		params.has_label = 1;
134*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0) {
135*0Sstevel@tonic-gate 		if (options & MDCMD_DOIT)
136*0Sstevel@tonic-gate 			(void) del_key_name(sp, newnp, ep);
137*0Sstevel@tonic-gate 		return (mdstealerror(ep, &params.mde));
138*0Sstevel@tonic-gate 	}
139*0Sstevel@tonic-gate 	meta_invalidate_name(oldnp);
140*0Sstevel@tonic-gate 	meta_invalidate_name(newnp);
141*0Sstevel@tonic-gate 	meta_invalidate_name(stripenp);
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
144*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
145*0Sstevel@tonic-gate 		    "%s: device %s is replaced with %s\n"),
146*0Sstevel@tonic-gate 		    stripenp->cname, oldnp->cname, newnp->cname);
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 	}
149*0Sstevel@tonic-gate 	return (0);
150*0Sstevel@tonic-gate }
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate /*
154*0Sstevel@tonic-gate  * FUNCTION:	meta_get_stripe_names()
155*0Sstevel@tonic-gate  * INPUT:	sp	- the set name to get stripes from
156*0Sstevel@tonic-gate  *		options	- options from the command line
157*0Sstevel@tonic-gate  * OUTPUT:	nlpp	- list of all stripe names
158*0Sstevel@tonic-gate  *		ep	- return error pointer
159*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
160*0Sstevel@tonic-gate  * PURPOSE:	returns a list of all stripes in the metadb
161*0Sstevel@tonic-gate  *		for all devices in the specified set
162*0Sstevel@tonic-gate  */
163*0Sstevel@tonic-gate int
164*0Sstevel@tonic-gate meta_get_stripe_names(
165*0Sstevel@tonic-gate 	mdsetname_t	*sp,
166*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
167*0Sstevel@tonic-gate 	int		options,
168*0Sstevel@tonic-gate 	md_error_t	*ep
169*0Sstevel@tonic-gate )
170*0Sstevel@tonic-gate {
171*0Sstevel@tonic-gate 	return (meta_get_names(MD_STRIPE, sp, nlpp, options, ep));
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate /*
175*0Sstevel@tonic-gate  * free stripe
176*0Sstevel@tonic-gate  */
177*0Sstevel@tonic-gate void
178*0Sstevel@tonic-gate meta_free_stripe(
179*0Sstevel@tonic-gate 	md_stripe_t	*stripep
180*0Sstevel@tonic-gate )
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate 	uint_t		row;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
185*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 		if (rp->comps.comps_val != NULL) {
188*0Sstevel@tonic-gate 			assert(rp->comps.comps_len > 0);
189*0Sstevel@tonic-gate 			Free(rp->comps.comps_val);
190*0Sstevel@tonic-gate 		}
191*0Sstevel@tonic-gate 	}
192*0Sstevel@tonic-gate 	if (stripep->rows.rows_val != NULL) {
193*0Sstevel@tonic-gate 		assert(stripep->rows.rows_len > 0);
194*0Sstevel@tonic-gate 		Free(stripep->rows.rows_val);
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate 	Free(stripep);
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate /*
201*0Sstevel@tonic-gate  * get stripe (common)
202*0Sstevel@tonic-gate  */
203*0Sstevel@tonic-gate md_stripe_t *
204*0Sstevel@tonic-gate meta_get_stripe_common(
205*0Sstevel@tonic-gate 	mdsetname_t	*sp,
206*0Sstevel@tonic-gate 	mdname_t	*stripenp,
207*0Sstevel@tonic-gate 	int		fast,
208*0Sstevel@tonic-gate 	md_error_t	*ep
209*0Sstevel@tonic-gate )
210*0Sstevel@tonic-gate {
211*0Sstevel@tonic-gate 	mddrivename_t	*dnp = stripenp->drivenamep;
212*0Sstevel@tonic-gate 	char		*miscname;
213*0Sstevel@tonic-gate 	ms_unit_t	*ms;
214*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
215*0Sstevel@tonic-gate 	uint_t		row;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	/* must have set */
218*0Sstevel@tonic-gate 	assert(sp != NULL);
219*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/* short circuit */
222*0Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
223*0Sstevel@tonic-gate 		assert(dnp->unitp->type == MD_DEVICE);
224*0Sstevel@tonic-gate 		return ((md_stripe_t *)dnp->unitp);
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	/* get miscname and unit */
228*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(stripenp, ep)) == NULL)
229*0Sstevel@tonic-gate 		return (NULL);
230*0Sstevel@tonic-gate 	if (strcmp(miscname, MD_STRIPE) != 0) {
231*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NOT_STRIPE,
232*0Sstevel@tonic-gate 			    meta_getminor(stripenp->dev), stripenp->cname);
233*0Sstevel@tonic-gate 		return (NULL);
234*0Sstevel@tonic-gate 	}
235*0Sstevel@tonic-gate 	if ((ms = (ms_unit_t *)meta_get_mdunit(sp, stripenp, ep)) == NULL)
236*0Sstevel@tonic-gate 		return (NULL);
237*0Sstevel@tonic-gate 	assert(ms->c.un_type == MD_DEVICE);
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	/* allocate stripe */
240*0Sstevel@tonic-gate 	stripep = Zalloc(sizeof (*stripep));
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	/* allocate rows */
243*0Sstevel@tonic-gate 	assert(ms->un_nrows > 0);
244*0Sstevel@tonic-gate 	stripep->rows.rows_len = ms->un_nrows;
245*0Sstevel@tonic-gate 	stripep->rows.rows_val = Zalloc(stripep->rows.rows_len *
246*0Sstevel@tonic-gate 	    sizeof (*stripep->rows.rows_val));
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	/* get common info */
249*0Sstevel@tonic-gate 	stripep->common.namep = stripenp;
250*0Sstevel@tonic-gate 	stripep->common.type = ms->c.un_type;
251*0Sstevel@tonic-gate 	stripep->common.state = ms->c.un_status;
252*0Sstevel@tonic-gate 	stripep->common.capabilities = ms->c.un_capabilities;
253*0Sstevel@tonic-gate 	stripep->common.parent = ms->c.un_parent;
254*0Sstevel@tonic-gate 	stripep->common.size = ms->c.un_total_blocks;
255*0Sstevel@tonic-gate 	stripep->common.user_flags = ms->c.un_user_flags;
256*0Sstevel@tonic-gate 	stripep->common.revision = ms->c.un_revision;
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	/* get options */
259*0Sstevel@tonic-gate 	if ((ms->un_hsp_id != MD_HSP_NONE) &&
260*0Sstevel@tonic-gate 	    ((stripep->hspnamep = metahsphspname(&sp, ms->un_hsp_id,
261*0Sstevel@tonic-gate 	    ep)) == NULL)) {
262*0Sstevel@tonic-gate 		goto out;
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	/* get rows */
266*0Sstevel@tonic-gate 	for (row = 0; (row < ms->un_nrows); ++row) {
267*0Sstevel@tonic-gate 		struct ms_row	*mdr = &ms->un_row[row];
268*0Sstevel@tonic-gate 		struct ms_comp	*mdcomp = (void *)&((char *)ms)[ms->un_ocomp];
269*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
270*0Sstevel@tonic-gate 		uint_t		comp, c;
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 		/* get interlace */
273*0Sstevel@tonic-gate 		rp->interlace = mdr->un_interlace;
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 		/* allocate comps */
276*0Sstevel@tonic-gate 		assert(mdr->un_ncomp > 0);
277*0Sstevel@tonic-gate 		rp->comps.comps_len = mdr->un_ncomp;
278*0Sstevel@tonic-gate 		rp->comps.comps_val = Zalloc(rp->comps.comps_len *
279*0Sstevel@tonic-gate 		    sizeof (*rp->comps.comps_val));
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 		/* get components */
282*0Sstevel@tonic-gate 		for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp);
283*0Sstevel@tonic-gate 		    ++comp, ++c) {
284*0Sstevel@tonic-gate 			struct ms_comp	*mdc = &mdcomp[c];
285*0Sstevel@tonic-gate 			diskaddr_t	comp_start_blk = mdc->un_start_block;
286*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 			/* get the component name */
289*0Sstevel@tonic-gate 			cp->compnamep = metakeyname(&sp, mdc->un_key, fast, ep);
290*0Sstevel@tonic-gate 			if (cp->compnamep == NULL)
291*0Sstevel@tonic-gate 				goto out;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 			/* if hotspared */
294*0Sstevel@tonic-gate 			if (mdc->un_mirror.ms_hs_id != 0) {
295*0Sstevel@tonic-gate 				diskaddr_t hs_start_blk = mdc->un_start_block;
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 				/* get the hotspare name */
298*0Sstevel@tonic-gate 				cp->hsnamep = metakeyname(&sp,
299*0Sstevel@tonic-gate 				    mdc->un_mirror.ms_hs_key, fast, ep);
300*0Sstevel@tonic-gate 				if (cp->hsnamep == NULL)
301*0Sstevel@tonic-gate 					goto out;
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 				if (getenv("META_DEBUG_START_BLK") != NULL) {
304*0Sstevel@tonic-gate 					if (metagetstart(sp, cp->hsnamep,
305*0Sstevel@tonic-gate 					    ep) == MD_DISKADDR_ERROR)
306*0Sstevel@tonic-gate 						mdclrerror(ep);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 					if ((cp->hsnamep->start_blk == 0) &&
309*0Sstevel@tonic-gate 					    (hs_start_blk != 0))
310*0Sstevel@tonic-gate 						md_eprintf(dgettext(TEXT_DOMAIN,
311*0Sstevel@tonic-gate 					    "%s: suspected bad start block,"
312*0Sstevel@tonic-gate 					    " seems labelled [stripe/hs]\n"),
313*0Sstevel@tonic-gate 					    cp->hsnamep->cname);
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 					if ((cp->hsnamep->start_blk > 0) &&
316*0Sstevel@tonic-gate 					    (hs_start_blk == 0) &&
317*0Sstevel@tonic-gate 					    ! ((row == 0) && (comp == 0)))
318*0Sstevel@tonic-gate 						md_eprintf(dgettext(TEXT_DOMAIN,
319*0Sstevel@tonic-gate 					    "%s: suspected bad start block, "
320*0Sstevel@tonic-gate 					    "seems unlabelled [stripe/hs]\n"),
321*0Sstevel@tonic-gate 					    cp->hsnamep->cname);
322*0Sstevel@tonic-gate 				}
323*0Sstevel@tonic-gate 				/* override any start_blk */
324*0Sstevel@tonic-gate 				cp->hsnamep->start_blk = hs_start_blk;
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 				/* get the right component start_blk */
327*0Sstevel@tonic-gate 				comp_start_blk = mdc->un_mirror.ms_orig_blk;
328*0Sstevel@tonic-gate 			} else {
329*0Sstevel@tonic-gate 				if (getenv("META_DEBUG_START_BLK") != NULL) {
330*0Sstevel@tonic-gate 					if (metagetstart(sp, cp->compnamep,
331*0Sstevel@tonic-gate 					    ep) == MD_DISKADDR_ERROR)
332*0Sstevel@tonic-gate 						mdclrerror(ep);
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 					if ((cp->compnamep->start_blk == 0) &&
335*0Sstevel@tonic-gate 					    (comp_start_blk != 0))
336*0Sstevel@tonic-gate 						md_eprintf(dgettext(TEXT_DOMAIN,
337*0Sstevel@tonic-gate 					    "%s: suspected bad start block,"
338*0Sstevel@tonic-gate 					    " seems labelled [stripe]"),
339*0Sstevel@tonic-gate 					    cp->compnamep->cname);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 					if ((cp->compnamep->start_blk > 0) &&
342*0Sstevel@tonic-gate 					    (comp_start_blk == 0) &&
343*0Sstevel@tonic-gate 					    ! ((row == 0) && (comp == 0)))
344*0Sstevel@tonic-gate 						md_eprintf(dgettext(TEXT_DOMAIN,
345*0Sstevel@tonic-gate 					    "%s: suspected bad start block, "
346*0Sstevel@tonic-gate 					    "seems unlabelled [stripe]"),
347*0Sstevel@tonic-gate 					    cp->compnamep->cname);
348*0Sstevel@tonic-gate 				}
349*0Sstevel@tonic-gate 			}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 			/* override any start_blk */
352*0Sstevel@tonic-gate 			cp->compnamep->start_blk = comp_start_blk;
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 			/* get state */
355*0Sstevel@tonic-gate 			cp->state = mdc->un_mirror.ms_state;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 			/* get time of last state change */
358*0Sstevel@tonic-gate 			cp->timestamp = mdc->un_mirror.ms_timestamp;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 			/* get lasterr count */
361*0Sstevel@tonic-gate 			cp->lasterrcnt = mdc->un_mirror.ms_lasterrcnt;
362*0Sstevel@tonic-gate 		}
363*0Sstevel@tonic-gate 	}
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	/* cleanup, return success */
366*0Sstevel@tonic-gate 	Free(ms);
367*0Sstevel@tonic-gate 	dnp->unitp = (md_common_t *)stripep;
368*0Sstevel@tonic-gate 	return (stripep);
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	/* cleanup, return error */
371*0Sstevel@tonic-gate out:
372*0Sstevel@tonic-gate 	Free(ms);
373*0Sstevel@tonic-gate 	meta_free_stripe(stripep);
374*0Sstevel@tonic-gate 	return (NULL);
375*0Sstevel@tonic-gate }
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate /*
378*0Sstevel@tonic-gate  * get stripe
379*0Sstevel@tonic-gate  */
380*0Sstevel@tonic-gate md_stripe_t *
381*0Sstevel@tonic-gate meta_get_stripe(
382*0Sstevel@tonic-gate 	mdsetname_t	*sp,
383*0Sstevel@tonic-gate 	mdname_t	*stripenp,
384*0Sstevel@tonic-gate 	md_error_t	*ep
385*0Sstevel@tonic-gate )
386*0Sstevel@tonic-gate {
387*0Sstevel@tonic-gate 	return (meta_get_stripe_common(sp, stripenp, 0, ep));
388*0Sstevel@tonic-gate }
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate /*
391*0Sstevel@tonic-gate  * check stripe for dev
392*0Sstevel@tonic-gate  */
393*0Sstevel@tonic-gate static int
394*0Sstevel@tonic-gate in_stripe(
395*0Sstevel@tonic-gate 	mdsetname_t	*sp,
396*0Sstevel@tonic-gate 	mdname_t	*stripenp,
397*0Sstevel@tonic-gate 	mdname_t	*np,
398*0Sstevel@tonic-gate 	diskaddr_t	slblk,
399*0Sstevel@tonic-gate 	diskaddr_t	nblks,
400*0Sstevel@tonic-gate 	md_error_t	*ep
401*0Sstevel@tonic-gate )
402*0Sstevel@tonic-gate {
403*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
404*0Sstevel@tonic-gate 	uint_t		row;
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	/* should be in the same set */
407*0Sstevel@tonic-gate 	assert(sp != NULL);
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	/* get unit */
410*0Sstevel@tonic-gate 	if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
411*0Sstevel@tonic-gate 		return (-1);
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	/* look in rows */
414*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
415*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
416*0Sstevel@tonic-gate 		uint_t		comp;
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 		/* look in columns */
419*0Sstevel@tonic-gate 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
420*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
421*0Sstevel@tonic-gate 			mdname_t	*compnp = cp->compnamep;
422*0Sstevel@tonic-gate 			diskaddr_t	comp_sblk;
423*0Sstevel@tonic-gate 			int		err;
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 			/* check same drive since metagetstart() can fail */
426*0Sstevel@tonic-gate 			if ((err = meta_check_samedrive(np, compnp, ep)) < 0)
427*0Sstevel@tonic-gate 				return (-1);
428*0Sstevel@tonic-gate 			else if (err == 0)
429*0Sstevel@tonic-gate 				continue;
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 			/* check overlap */
432*0Sstevel@tonic-gate 			if ((comp_sblk = metagetstart(sp, compnp, ep)) ==
433*0Sstevel@tonic-gate 			    MD_DISKADDR_ERROR)
434*0Sstevel@tonic-gate 				return (-1);
435*0Sstevel@tonic-gate 			if (meta_check_overlap(stripenp->cname, np,
436*0Sstevel@tonic-gate 			    slblk, nblks, compnp, comp_sblk, -1,
437*0Sstevel@tonic-gate 			    ep) != 0) {
438*0Sstevel@tonic-gate 				return (-1);
439*0Sstevel@tonic-gate 			}
440*0Sstevel@tonic-gate 		}
441*0Sstevel@tonic-gate 	}
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 	/* return success */
444*0Sstevel@tonic-gate 	return (0);
445*0Sstevel@tonic-gate }
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate /*
448*0Sstevel@tonic-gate  * check to see if we're in a stripe
449*0Sstevel@tonic-gate  */
450*0Sstevel@tonic-gate int
451*0Sstevel@tonic-gate meta_check_instripe(
452*0Sstevel@tonic-gate 	mdsetname_t	*sp,
453*0Sstevel@tonic-gate 	mdname_t	*np,
454*0Sstevel@tonic-gate 	diskaddr_t	slblk,
455*0Sstevel@tonic-gate 	diskaddr_t	nblks,
456*0Sstevel@tonic-gate 	md_error_t	*ep
457*0Sstevel@tonic-gate )
458*0Sstevel@tonic-gate {
459*0Sstevel@tonic-gate 	mdnamelist_t	*stripenlp = NULL;
460*0Sstevel@tonic-gate 	mdnamelist_t	*p;
461*0Sstevel@tonic-gate 	int		rval = 0;
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	/* should have a set */
464*0Sstevel@tonic-gate 	assert(sp != NULL);
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	/* for each stripe */
467*0Sstevel@tonic-gate 	if (meta_get_stripe_names(sp, &stripenlp, 0, ep) < 0)
468*0Sstevel@tonic-gate 		return (-1);
469*0Sstevel@tonic-gate 	for (p = stripenlp; (p != NULL); p = p->next) {
470*0Sstevel@tonic-gate 		mdname_t	*stripenp = p->namep;
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 		/* check stripe */
473*0Sstevel@tonic-gate 		if (in_stripe(sp, stripenp, np, slblk, nblks, ep) != 0) {
474*0Sstevel@tonic-gate 			rval = -1;
475*0Sstevel@tonic-gate 			break;
476*0Sstevel@tonic-gate 		}
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	/* cleanup, return success */
480*0Sstevel@tonic-gate 	metafreenamelist(stripenlp);
481*0Sstevel@tonic-gate 	return (rval);
482*0Sstevel@tonic-gate }
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate /*
485*0Sstevel@tonic-gate  * check component
486*0Sstevel@tonic-gate  */
487*0Sstevel@tonic-gate int
488*0Sstevel@tonic-gate meta_check_component(
489*0Sstevel@tonic-gate 	mdsetname_t	*sp,
490*0Sstevel@tonic-gate 	mdname_t	*np,
491*0Sstevel@tonic-gate 	int		force,
492*0Sstevel@tonic-gate 	md_error_t	*ep
493*0Sstevel@tonic-gate )
494*0Sstevel@tonic-gate {
495*0Sstevel@tonic-gate 	mdchkopts_t	options = (MDCHK_ALLOW_MDDB);
496*0Sstevel@tonic-gate 	md_common_t	*mdp;
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	/*
499*0Sstevel@tonic-gate 	 * See if we are a soft partition: meta_sp_issp() returns 0 if
500*0Sstevel@tonic-gate 	 * np points to a soft partition, so the if and else clauses
501*0Sstevel@tonic-gate 	 * here represent "not a soft partition" and "soft partition,"
502*0Sstevel@tonic-gate 	 * respectively.
503*0Sstevel@tonic-gate 	 */
504*0Sstevel@tonic-gate 	if (meta_sp_issp(sp, np, ep) != 0) {
505*0Sstevel@tonic-gate 		/* make sure we have a disk */
506*0Sstevel@tonic-gate 		if (metachkcomp(np, ep) != 0)
507*0Sstevel@tonic-gate 			return (-1);
508*0Sstevel@tonic-gate 	} else {
509*0Sstevel@tonic-gate 		/* make sure soft partition can parent & doesn't have parent */
510*0Sstevel@tonic-gate 		if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
511*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_INVAL_UNIT, NULL,
512*0Sstevel@tonic-gate 			    np->cname));
513*0Sstevel@tonic-gate 		if (mdp->capabilities == MD_CANT_PARENT)
514*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_INVAL_UNIT, NULL,
515*0Sstevel@tonic-gate 			    np->cname));
516*0Sstevel@tonic-gate 		if (MD_HAS_PARENT(mdp->parent)) {
517*0Sstevel@tonic-gate 			mdname_t *pnp;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 			pnp = metamnumname(&sp, mdp->parent, 0, ep);
520*0Sstevel@tonic-gate 			if (pnp == NULL) {
521*0Sstevel@tonic-gate 				return (-1);
522*0Sstevel@tonic-gate 			}
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 			return (mduseerror(ep, MDE_ALREADY, np->dev,
525*0Sstevel@tonic-gate 			    pnp->cname, np->cname));
526*0Sstevel@tonic-gate 		}
527*0Sstevel@tonic-gate 	}
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
530*0Sstevel@tonic-gate 	if ((! force) &&
531*0Sstevel@tonic-gate 	    (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0)) {
532*0Sstevel@tonic-gate 		return (-1);
533*0Sstevel@tonic-gate 	}
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	/* make sure it is in the set */
536*0Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
537*0Sstevel@tonic-gate 		return (-1);
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	/* make sure its not in a metadevice */
540*0Sstevel@tonic-gate 	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
541*0Sstevel@tonic-gate 		return (-1);
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 	/* return success */
544*0Sstevel@tonic-gate 	return (0);
545*0Sstevel@tonic-gate }
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate /*
548*0Sstevel@tonic-gate  * print stripe
549*0Sstevel@tonic-gate  */
550*0Sstevel@tonic-gate static int
551*0Sstevel@tonic-gate stripe_print(
552*0Sstevel@tonic-gate 	md_stripe_t	*stripep,
553*0Sstevel@tonic-gate 	char		*fname,
554*0Sstevel@tonic-gate 	FILE		*fp,
555*0Sstevel@tonic-gate 	mdprtopts_t	options,
556*0Sstevel@tonic-gate 	md_error_t	*ep
557*0Sstevel@tonic-gate )
558*0Sstevel@tonic-gate {
559*0Sstevel@tonic-gate 	uint_t		row;
560*0Sstevel@tonic-gate 	int		rval = -1;
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
563*0Sstevel@tonic-gate 		if (stripep->common.revision != MD_64BIT_META_DEV) {
564*0Sstevel@tonic-gate 			rval = 0;
565*0Sstevel@tonic-gate 			goto out;
566*0Sstevel@tonic-gate 		}
567*0Sstevel@tonic-gate 	}
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 	/* print name and num rows */
570*0Sstevel@tonic-gate 	if (fprintf(fp, "%s %u",
571*0Sstevel@tonic-gate 	    stripep->common.namep->cname, stripep->rows.rows_len) == EOF)
572*0Sstevel@tonic-gate 		goto out;
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	/* print rows */
575*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
576*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
577*0Sstevel@tonic-gate 		uint_t		comp;
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 		/* print num components */
580*0Sstevel@tonic-gate 		if (fprintf(fp, " %u", rp->comps.comps_len) == EOF)
581*0Sstevel@tonic-gate 			goto out;
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 		/* print components */
584*0Sstevel@tonic-gate 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
585*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 			/* print component */
588*0Sstevel@tonic-gate 			/*
589*0Sstevel@tonic-gate 			 * If the path is our standard /dev/rdsk or /dev/md/rdsk
590*0Sstevel@tonic-gate 			 * then just print out the cxtxdxsx or the dx, metainit
591*0Sstevel@tonic-gate 			 * will assume the default, otherwise we need the full
592*0Sstevel@tonic-gate 			 * pathname to make sure this works as we intend.
593*0Sstevel@tonic-gate 			 */
594*0Sstevel@tonic-gate 			if ((strstr(cp->compnamep->rname, "/dev/rdsk") ==
595*0Sstevel@tonic-gate 			    NULL) && (strstr(cp->compnamep->rname,
596*0Sstevel@tonic-gate 			    "/dev/md/rdsk") == NULL) &&
597*0Sstevel@tonic-gate 			    (strstr(cp->compnamep->rname, "/dev/td/") ==
598*0Sstevel@tonic-gate 			    NULL)) {
599*0Sstevel@tonic-gate 				/* not standard path, print full pathname */
600*0Sstevel@tonic-gate 				if (fprintf(fp, " %s", cp->compnamep->rname)
601*0Sstevel@tonic-gate 				    == EOF)
602*0Sstevel@tonic-gate 					goto out;
603*0Sstevel@tonic-gate 			} else {
604*0Sstevel@tonic-gate 				/* standard path */
605*0Sstevel@tonic-gate 				if (fprintf(fp, " %s", cp->compnamep->cname)
606*0Sstevel@tonic-gate 				    == EOF)
607*0Sstevel@tonic-gate 					goto out;
608*0Sstevel@tonic-gate 			}
609*0Sstevel@tonic-gate 		}
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 		/* print interlace */
612*0Sstevel@tonic-gate 		if (rp->comps.comps_len > 1)
613*0Sstevel@tonic-gate 			if (fprintf(fp, " -i %lldb", rp->interlace) == EOF)
614*0Sstevel@tonic-gate 				goto out;
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 		/* print continuation */
617*0Sstevel@tonic-gate 		if (row != (stripep->rows.rows_len - 1))
618*0Sstevel@tonic-gate 			if (fprintf(fp, " \\\n\t") == EOF)
619*0Sstevel@tonic-gate 				goto out;
620*0Sstevel@tonic-gate 	}
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	/* print hotspare name */
623*0Sstevel@tonic-gate 	if (stripep->hspnamep != NULL)
624*0Sstevel@tonic-gate 		if (fprintf(fp, " -h %s", stripep->hspnamep->hspname) == EOF)
625*0Sstevel@tonic-gate 			goto out;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	/* terminate last line */
628*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
629*0Sstevel@tonic-gate 		goto out;
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	/* success */
632*0Sstevel@tonic-gate 	rval = 0;
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	/* cleanup, return error */
635*0Sstevel@tonic-gate out:
636*0Sstevel@tonic-gate 	if (rval != 0)
637*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
638*0Sstevel@tonic-gate 	return (rval);
639*0Sstevel@tonic-gate }
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate /*
642*0Sstevel@tonic-gate  * convert component state to name
643*0Sstevel@tonic-gate  */
644*0Sstevel@tonic-gate char *
645*0Sstevel@tonic-gate comp_state_to_name(
646*0Sstevel@tonic-gate 	md_comp_t	*mdcp,
647*0Sstevel@tonic-gate 	md_timeval32_t	*tvp,
648*0Sstevel@tonic-gate 	uint_t		tstate	/* Errored tstate flags */
649*0Sstevel@tonic-gate )
650*0Sstevel@tonic-gate {
651*0Sstevel@tonic-gate 	comp_state_t	state = mdcp->state;
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	/* grab time */
654*0Sstevel@tonic-gate 	if (tvp != NULL)
655*0Sstevel@tonic-gate 		*tvp = mdcp->timestamp;
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	if (tstate != 0) {
658*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
659*0Sstevel@tonic-gate 	}
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 	/* return state */
662*0Sstevel@tonic-gate 	switch (state) {
663*0Sstevel@tonic-gate 	case CS_OKAY:
664*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Okay"));
665*0Sstevel@tonic-gate 	case CS_ERRED:
666*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Maintenance"));
667*0Sstevel@tonic-gate 	case CS_LAST_ERRED:
668*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Last Erred"));
669*0Sstevel@tonic-gate 	case CS_RESYNC:
670*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Resyncing"));
671*0Sstevel@tonic-gate 	default:
672*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "invalid"));
673*0Sstevel@tonic-gate 	}
674*0Sstevel@tonic-gate }
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate /*
677*0Sstevel@tonic-gate  * print subdevice stripe row
678*0Sstevel@tonic-gate  */
679*0Sstevel@tonic-gate static int
680*0Sstevel@tonic-gate subdev_row_report(
681*0Sstevel@tonic-gate 	mdsetname_t	*sp,
682*0Sstevel@tonic-gate 	md_row_t	*rp,
683*0Sstevel@tonic-gate 	char		*fname,
684*0Sstevel@tonic-gate 	FILE		*fp,
685*0Sstevel@tonic-gate 	mdprtopts_t	options,
686*0Sstevel@tonic-gate 	uint_t		top_tstate,	/* Errored tstate flags */
687*0Sstevel@tonic-gate 	md_error_t	*ep
688*0Sstevel@tonic-gate )
689*0Sstevel@tonic-gate {
690*0Sstevel@tonic-gate 	uint_t		comp;
691*0Sstevel@tonic-gate 	int		rval = -1;
692*0Sstevel@tonic-gate 	ddi_devid_t	dtp;
693*0Sstevel@tonic-gate 	int		len = 0;
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 	/*
697*0Sstevel@tonic-gate 	 * building a format string on the fly that will be used
698*0Sstevel@tonic-gate 	 * in fprintf. This is to allow really really long ctd names
699*0Sstevel@tonic-gate 	 */
700*0Sstevel@tonic-gate 	for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
701*0Sstevel@tonic-gate 		md_comp_t	*cp = &rp->comps.comps_val[comp];
702*0Sstevel@tonic-gate 		char		*cname = cp->compnamep->cname;
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 		len = max(len, strlen(cname));
705*0Sstevel@tonic-gate 	}
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
708*0Sstevel@tonic-gate 	len += 2;
709*0Sstevel@tonic-gate 	/* print header */
710*0Sstevel@tonic-gate 	if (! (options & PRINT_TIMES)) {
711*0Sstevel@tonic-gate 		if (fprintf(fp,
712*0Sstevel@tonic-gate 		    "\t%-*.*s %-12.12s %5.5s %12.12s %5.5s %s\n",
713*0Sstevel@tonic-gate 		    len, len,
714*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
715*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start Block"),
716*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
717*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "State"),
718*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc"),
719*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN, "Hot Spare")) == EOF) {
720*0Sstevel@tonic-gate 			goto out;
721*0Sstevel@tonic-gate 		}
722*0Sstevel@tonic-gate 	} else {
723*0Sstevel@tonic-gate 		if (fprintf(fp,
724*0Sstevel@tonic-gate 		    "\t%-*s %5s %5s %-11s %-5s %-9s %s\n",
725*0Sstevel@tonic-gate 		    len,
726*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
727*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start"),
728*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
729*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "State"),
730*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc"),
731*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Hot Spare"),
732*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN, "Time")) == EOF) {
733*0Sstevel@tonic-gate 			goto out;
734*0Sstevel@tonic-gate 		}
735*0Sstevel@tonic-gate 	}
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	/* print components */
739*0Sstevel@tonic-gate 	for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
740*0Sstevel@tonic-gate 		md_comp_t	*cp = &rp->comps.comps_val[comp];
741*0Sstevel@tonic-gate 		mdname_t	*namep = cp->compnamep;
742*0Sstevel@tonic-gate 		char		*cname = namep->cname;
743*0Sstevel@tonic-gate 		diskaddr_t	start_blk;
744*0Sstevel@tonic-gate 		int		has_mddb;
745*0Sstevel@tonic-gate 		char		*has_mddb_str;
746*0Sstevel@tonic-gate 		char		*comp_state;
747*0Sstevel@tonic-gate 		md_timeval32_t	tv;
748*0Sstevel@tonic-gate 		char		*hsname = ((cp->hsnamep != NULL) ?
749*0Sstevel@tonic-gate 					    cp->hsnamep->cname : "");
750*0Sstevel@tonic-gate 		char		*devid = " ";
751*0Sstevel@tonic-gate 		mdname_t	*didnp = NULL;
752*0Sstevel@tonic-gate 		uint_t		tstate = 0;
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 		/* get info */
755*0Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, namep, ep)) ==
756*0Sstevel@tonic-gate 		    MD_DISKADDR_ERROR) {
757*0Sstevel@tonic-gate 			return (-1);
758*0Sstevel@tonic-gate 		}
759*0Sstevel@tonic-gate 		if ((has_mddb = metahasmddb(sp, namep, ep)) < 0) {
760*0Sstevel@tonic-gate 			return (-1);
761*0Sstevel@tonic-gate 		}
762*0Sstevel@tonic-gate 		if (has_mddb)
763*0Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
764*0Sstevel@tonic-gate 		else
765*0Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "No");
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 		/*
768*0Sstevel@tonic-gate 		 * If the component is a metadevice, print out either
769*0Sstevel@tonic-gate 		 * unavailable or the state of the metadevice, if not
770*0Sstevel@tonic-gate 		 * a metadevice, print nothing if the state of the
771*0Sstevel@tonic-gate 		 * stripe is unavailable
772*0Sstevel@tonic-gate 		 */
773*0Sstevel@tonic-gate 		if (metaismeta(namep)) {
774*0Sstevel@tonic-gate 			if (meta_get_tstate(namep->dev, &tstate, ep) != 0)
775*0Sstevel@tonic-gate 				return (-1);
776*0Sstevel@tonic-gate 			comp_state = comp_state_to_name(cp, &tv, tstate &
777*0Sstevel@tonic-gate 			    MD_DEV_ERRORED);
778*0Sstevel@tonic-gate 		} else {
779*0Sstevel@tonic-gate 			/*
780*0Sstevel@tonic-gate 			 * if top_tstate is set, that implies that you have
781*0Sstevel@tonic-gate 			 * a ctd type device with an unavailable metadevice
782*0Sstevel@tonic-gate 			 * on top of it. If so, print a - for it's state
783*0Sstevel@tonic-gate 			 */
784*0Sstevel@tonic-gate 			if (top_tstate != 0)
785*0Sstevel@tonic-gate 				comp_state = "-";
786*0Sstevel@tonic-gate 			else
787*0Sstevel@tonic-gate 				comp_state = comp_state_to_name(cp, &tv,
788*0Sstevel@tonic-gate 				    tstate & MD_DEV_ERRORED);
789*0Sstevel@tonic-gate 		}
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 		/* populate the key in the name_p structure */
792*0Sstevel@tonic-gate 		if ((didnp = metadevname(&sp, namep->dev, ep))
793*0Sstevel@tonic-gate 				== NULL) {
794*0Sstevel@tonic-gate 			return (-1);
795*0Sstevel@tonic-gate 		}
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	    /* determine if devid does NOT exist */
798*0Sstevel@tonic-gate 		if (options & PRINT_DEVID) {
799*0Sstevel@tonic-gate 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
800*0Sstevel@tonic-gate 				didnp->key, ep)) == NULL)
801*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
802*0Sstevel@tonic-gate 			else {
803*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
804*0Sstevel@tonic-gate 				free(dtp);
805*0Sstevel@tonic-gate 			}
806*0Sstevel@tonic-gate 		}
807*0Sstevel@tonic-gate 		/* print info */
808*0Sstevel@tonic-gate 		/*
809*0Sstevel@tonic-gate 		 * building a format string on the fly that will be used
810*0Sstevel@tonic-gate 		 * in fprintf. This is to allow really really long ctd names
811*0Sstevel@tonic-gate 		 */
812*0Sstevel@tonic-gate 		if (! (options & PRINT_TIMES)) {
813*0Sstevel@tonic-gate 			if (fprintf(fp,
814*0Sstevel@tonic-gate 			    "\t%-*s %8lld     %-5.5s %12.12s %5.5s %s\n",
815*0Sstevel@tonic-gate 			    len, cname, start_blk,
816*0Sstevel@tonic-gate 			    has_mddb_str, comp_state, devid, hsname) == EOF) {
817*0Sstevel@tonic-gate 				goto out;
818*0Sstevel@tonic-gate 			}
819*0Sstevel@tonic-gate 		} else {
820*0Sstevel@tonic-gate 			char	*timep = meta_print_time(&tv);
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 			if (fprintf(fp,
823*0Sstevel@tonic-gate 			    "\t%-*s %5lld %-5s %-11s %-5s %-9s %s\n",
824*0Sstevel@tonic-gate 			    len, cname, start_blk,
825*0Sstevel@tonic-gate 			    has_mddb_str, comp_state, devid, hsname,
826*0Sstevel@tonic-gate 			    timep) == EOF) {
827*0Sstevel@tonic-gate 				goto out;
828*0Sstevel@tonic-gate 			}
829*0Sstevel@tonic-gate 		}
830*0Sstevel@tonic-gate 	}
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 	/* success */
833*0Sstevel@tonic-gate 	rval = 0;
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	/* cleanup, return error */
836*0Sstevel@tonic-gate out:
837*0Sstevel@tonic-gate 	if (rval != 0)
838*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
839*0Sstevel@tonic-gate 	return (rval);
840*0Sstevel@tonic-gate }
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate /*
843*0Sstevel@tonic-gate  * print toplevel stripe row
844*0Sstevel@tonic-gate  */
845*0Sstevel@tonic-gate /*ARGSUSED4*/
846*0Sstevel@tonic-gate static int
847*0Sstevel@tonic-gate toplev_row_report(
848*0Sstevel@tonic-gate 	mdsetname_t	*sp,
849*0Sstevel@tonic-gate 	md_row_t	*rp,
850*0Sstevel@tonic-gate 	char		*fname,
851*0Sstevel@tonic-gate 	FILE		*fp,
852*0Sstevel@tonic-gate 	mdprtopts_t	options,
853*0Sstevel@tonic-gate 	md_error_t	*ep
854*0Sstevel@tonic-gate )
855*0Sstevel@tonic-gate {
856*0Sstevel@tonic-gate 	uint_t		comp;
857*0Sstevel@tonic-gate 	int		rval = -1;
858*0Sstevel@tonic-gate 	char		*devid = " ";
859*0Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
860*0Sstevel@tonic-gate 	int		len = 0;
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 	/*
863*0Sstevel@tonic-gate 	 * building a format string on the fly that will be used
864*0Sstevel@tonic-gate 	 * in fprintf. This is to allow really really long ctd names
865*0Sstevel@tonic-gate 	 */
866*0Sstevel@tonic-gate 	for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
867*0Sstevel@tonic-gate 		len = max(len,
868*0Sstevel@tonic-gate 		    strlen(rp->comps.comps_val[comp].compnamep->cname));
869*0Sstevel@tonic-gate 	}
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
872*0Sstevel@tonic-gate 	len += 2;
873*0Sstevel@tonic-gate 	/* print header */
874*0Sstevel@tonic-gate 	if (fprintf(fp,
875*0Sstevel@tonic-gate 	    "\t%-*.*s %-12.12s %-5.5s\t%s\n",
876*0Sstevel@tonic-gate 	    len, len,
877*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Device"),
878*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Start Block"),
879*0Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, "Dbase"),
880*0Sstevel@tonic-gate 		dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
881*0Sstevel@tonic-gate 		goto out;
882*0Sstevel@tonic-gate 	}
883*0Sstevel@tonic-gate 
884*0Sstevel@tonic-gate 	/* print components */
885*0Sstevel@tonic-gate 	for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
886*0Sstevel@tonic-gate 		md_comp_t	*cp = &rp->comps.comps_val[comp];
887*0Sstevel@tonic-gate 		mdname_t	*namep = cp->compnamep;
888*0Sstevel@tonic-gate 		char		*cname = namep->cname;
889*0Sstevel@tonic-gate 		diskaddr_t	start_blk;
890*0Sstevel@tonic-gate 		int		has_mddb;
891*0Sstevel@tonic-gate 		char		*has_mddb_str;
892*0Sstevel@tonic-gate 		ddi_devid_t	dtp;
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 		/* get info */
895*0Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, namep, ep)) ==
896*0Sstevel@tonic-gate 		    MD_DISKADDR_ERROR) {
897*0Sstevel@tonic-gate 			return (-1);
898*0Sstevel@tonic-gate 		}
899*0Sstevel@tonic-gate 		if ((has_mddb = metahasmddb(sp, namep, ep)) < 0) {
900*0Sstevel@tonic-gate 			return (-1);
901*0Sstevel@tonic-gate 		}
902*0Sstevel@tonic-gate 		if (has_mddb)
903*0Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
904*0Sstevel@tonic-gate 		else
905*0Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "No");
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 		/* populate the key in the name_p structure */
908*0Sstevel@tonic-gate 		if ((didnp = metadevname(&sp, namep->dev, ep))
909*0Sstevel@tonic-gate 				== NULL) {
910*0Sstevel@tonic-gate 			return (-1);
911*0Sstevel@tonic-gate 		}
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 	    /* determine if devid does NOT exist */
914*0Sstevel@tonic-gate 	    if (options & PRINT_DEVID) {
915*0Sstevel@tonic-gate 		if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
916*0Sstevel@tonic-gate 				didnp->key, ep)) == NULL) {
917*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
918*0Sstevel@tonic-gate 			} else {
919*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
920*0Sstevel@tonic-gate 				free(dtp);
921*0Sstevel@tonic-gate 			}
922*0Sstevel@tonic-gate 		}
923*0Sstevel@tonic-gate 		/* print info */
924*0Sstevel@tonic-gate 		/*
925*0Sstevel@tonic-gate 		 * building a format string on the fly that will be used
926*0Sstevel@tonic-gate 		 * in fprintf. This is to allow really really long ctd names
927*0Sstevel@tonic-gate 		 */
928*0Sstevel@tonic-gate 		if (fprintf(fp,
929*0Sstevel@tonic-gate 		    "\t%-*s %8lld     %-5.5s\t%s\n", len,
930*0Sstevel@tonic-gate 		    cname, start_blk, has_mddb_str, devid) == EOF) {
931*0Sstevel@tonic-gate 			goto out;
932*0Sstevel@tonic-gate 		}
933*0Sstevel@tonic-gate 	}
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 	/* success */
936*0Sstevel@tonic-gate 	rval = 0;
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 	/* cleanup, return error */
939*0Sstevel@tonic-gate out:
940*0Sstevel@tonic-gate 	if (rval != 0)
941*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
942*0Sstevel@tonic-gate 	return (rval);
943*0Sstevel@tonic-gate }
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate /*
946*0Sstevel@tonic-gate  * print stripe options
947*0Sstevel@tonic-gate  */
948*0Sstevel@tonic-gate int
949*0Sstevel@tonic-gate meta_print_stripe_options(
950*0Sstevel@tonic-gate 	mdhspname_t	*hspnamep,
951*0Sstevel@tonic-gate 	char		*fname,
952*0Sstevel@tonic-gate 	FILE		*fp,
953*0Sstevel@tonic-gate 	md_error_t	*ep
954*0Sstevel@tonic-gate )
955*0Sstevel@tonic-gate {
956*0Sstevel@tonic-gate 	char		*hspname = ((hspnamep != NULL) ? hspnamep->hspname :
957*0Sstevel@tonic-gate 					dgettext(TEXT_DOMAIN, "none"));
958*0Sstevel@tonic-gate 	int		rval = -1;
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	/* print options */
961*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN,
962*0Sstevel@tonic-gate 	    "    Hot spare pool: %s\n"), hspname) == EOF) {
963*0Sstevel@tonic-gate 		goto out;
964*0Sstevel@tonic-gate 	}
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate 	/* success */
967*0Sstevel@tonic-gate 	rval = 0;
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	/* cleanup, return error */
970*0Sstevel@tonic-gate out:
971*0Sstevel@tonic-gate 	if (rval != 0)
972*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
973*0Sstevel@tonic-gate 	return (rval);
974*0Sstevel@tonic-gate }
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate /*
977*0Sstevel@tonic-gate  * report stripe
978*0Sstevel@tonic-gate  */
979*0Sstevel@tonic-gate static int
980*0Sstevel@tonic-gate stripe_report(
981*0Sstevel@tonic-gate 	mdsetname_t	*sp,
982*0Sstevel@tonic-gate 	md_stripe_t	*stripep,
983*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
984*0Sstevel@tonic-gate 	char		*fname,
985*0Sstevel@tonic-gate 	FILE		*fp,
986*0Sstevel@tonic-gate 	mdprtopts_t	options,
987*0Sstevel@tonic-gate 	md_error_t	*ep
988*0Sstevel@tonic-gate )
989*0Sstevel@tonic-gate {
990*0Sstevel@tonic-gate 	uint_t		row;
991*0Sstevel@tonic-gate 	int		rval = -1;
992*0Sstevel@tonic-gate 	uint_t		tstate = 0;
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 	/*
995*0Sstevel@tonic-gate 	 * if the -B option has been specified check to see if the
996*0Sstevel@tonic-gate 	 * metadevice is s "big" one and print if so, also if a
997*0Sstevel@tonic-gate 	 * big device we need to store the ctd involved for use in
998*0Sstevel@tonic-gate 	 * printing out the relocation information.
999*0Sstevel@tonic-gate 	 */
1000*0Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
1001*0Sstevel@tonic-gate 		if (stripep->common.revision != MD_64BIT_META_DEV) {
1002*0Sstevel@tonic-gate 			rval = 0;
1003*0Sstevel@tonic-gate 			goto out;
1004*0Sstevel@tonic-gate 		} else {
1005*0Sstevel@tonic-gate 			if (meta_getdevs(sp, stripep->common.namep,
1006*0Sstevel@tonic-gate 			    nlpp, ep) != 0)
1007*0Sstevel@tonic-gate 				goto out;
1008*0Sstevel@tonic-gate 		}
1009*0Sstevel@tonic-gate 	}
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 	/* print header */
1012*0Sstevel@tonic-gate 	if (options & PRINT_HEADER) {
1013*0Sstevel@tonic-gate 		if (fprintf(fp, "%s: Concat/Stripe\n",
1014*0Sstevel@tonic-gate 		    stripep->common.namep->cname) == EOF) {
1015*0Sstevel@tonic-gate 			goto out;
1016*0Sstevel@tonic-gate 		}
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	}
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate 	/* print hotspare pool */
1021*0Sstevel@tonic-gate 	if (stripep->hspnamep != NULL) {
1022*0Sstevel@tonic-gate 		if (meta_print_stripe_options(stripep->hspnamep,
1023*0Sstevel@tonic-gate 		    fname, fp, ep) != 0) {
1024*0Sstevel@tonic-gate 			return (-1);
1025*0Sstevel@tonic-gate 		}
1026*0Sstevel@tonic-gate 	}
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 	if (metaismeta(stripep->common.namep)) {
1029*0Sstevel@tonic-gate 		if (meta_get_tstate(stripep->common.namep->dev, &tstate, ep)
1030*0Sstevel@tonic-gate 		    != 0)
1031*0Sstevel@tonic-gate 			return (-1);
1032*0Sstevel@tonic-gate 	}
1033*0Sstevel@tonic-gate 	if ((tstate & MD_DEV_ERRORED) != 0) {
1034*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
1035*0Sstevel@tonic-gate 		    "    State: Unavailable\n"
1036*0Sstevel@tonic-gate 		    "    Reconnect disk and invoke: metastat -i\n")) == EOF) {
1037*0Sstevel@tonic-gate 			goto out;
1038*0Sstevel@tonic-gate 		}
1039*0Sstevel@tonic-gate 	}
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 	/* print size */
1042*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %lld blocks (%s)\n"),
1043*0Sstevel@tonic-gate 	    stripep->common.size,
1044*0Sstevel@tonic-gate 	    meta_number_to_string(stripep->common.size, DEV_BSIZE))
1045*0Sstevel@tonic-gate 	    == EOF) {
1046*0Sstevel@tonic-gate 		goto out;
1047*0Sstevel@tonic-gate 	}
1048*0Sstevel@tonic-gate 
1049*0Sstevel@tonic-gate 	/* print rows */
1050*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
1051*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1052*0Sstevel@tonic-gate 
1053*0Sstevel@tonic-gate 		/* print stripe and interlace */
1054*0Sstevel@tonic-gate 		if (rp->comps.comps_len > 1) {
1055*0Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
1056*0Sstevel@tonic-gate 			    "    Stripe %u: (interlace: %lld blocks)\n"),
1057*0Sstevel@tonic-gate 			    row, rp->interlace) == EOF) {
1058*0Sstevel@tonic-gate 				goto out;
1059*0Sstevel@tonic-gate 			}
1060*0Sstevel@tonic-gate 		} else {
1061*0Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
1062*0Sstevel@tonic-gate 			    "    Stripe %u:\n"),
1063*0Sstevel@tonic-gate 			    row) == EOF) {
1064*0Sstevel@tonic-gate 				goto out;
1065*0Sstevel@tonic-gate 			}
1066*0Sstevel@tonic-gate 		}
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 		/* print components appropriately */
1069*0Sstevel@tonic-gate 		if (MD_HAS_PARENT(stripep->common.parent)) {
1070*0Sstevel@tonic-gate 			if (subdev_row_report(sp, rp, fname, fp, options,
1071*0Sstevel@tonic-gate 			    tstate & MD_DEV_ERRORED, ep) != 0) {
1072*0Sstevel@tonic-gate 				return (-1);
1073*0Sstevel@tonic-gate 			}
1074*0Sstevel@tonic-gate 		} else {
1075*0Sstevel@tonic-gate 			if (toplev_row_report(sp, rp, fname, fp, options,
1076*0Sstevel@tonic-gate 			    ep) != 0) {
1077*0Sstevel@tonic-gate 				return (-1);
1078*0Sstevel@tonic-gate 			}
1079*0Sstevel@tonic-gate 		}
1080*0Sstevel@tonic-gate 	}
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 	/* add extra line */
1083*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
1084*0Sstevel@tonic-gate 		goto out;
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate 	/* success */
1087*0Sstevel@tonic-gate 	rval = 0;
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate 	/* cleanup, return error */
1090*0Sstevel@tonic-gate out:
1091*0Sstevel@tonic-gate 	if (rval != 0)
1092*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
1093*0Sstevel@tonic-gate 	return (rval);
1094*0Sstevel@tonic-gate }
1095*0Sstevel@tonic-gate 
1096*0Sstevel@tonic-gate /*
1097*0Sstevel@tonic-gate  * print/report stripe
1098*0Sstevel@tonic-gate  */
1099*0Sstevel@tonic-gate int
1100*0Sstevel@tonic-gate meta_stripe_print(
1101*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1102*0Sstevel@tonic-gate 	mdname_t	*stripenp,
1103*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
1104*0Sstevel@tonic-gate 	char		*fname,
1105*0Sstevel@tonic-gate 	FILE		*fp,
1106*0Sstevel@tonic-gate 	mdprtopts_t	options,
1107*0Sstevel@tonic-gate 	md_error_t	*ep
1108*0Sstevel@tonic-gate )
1109*0Sstevel@tonic-gate {
1110*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
1111*0Sstevel@tonic-gate 	int		row, comp;
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	/* should have same set */
1114*0Sstevel@tonic-gate 	assert(sp != NULL);
1115*0Sstevel@tonic-gate 	assert((stripenp == NULL) ||
1116*0Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))));
1117*0Sstevel@tonic-gate 
1118*0Sstevel@tonic-gate 	/* print all stripes */
1119*0Sstevel@tonic-gate 	if (stripenp == NULL) {
1120*0Sstevel@tonic-gate 		mdnamelist_t	*nlp = NULL;
1121*0Sstevel@tonic-gate 		mdnamelist_t	*p;
1122*0Sstevel@tonic-gate 		int		cnt;
1123*0Sstevel@tonic-gate 		int		rval = 0;
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 		/* get list */
1126*0Sstevel@tonic-gate 		if ((cnt = meta_get_stripe_names(sp, &nlp, options, ep)) < 0)
1127*0Sstevel@tonic-gate 			return (-1);
1128*0Sstevel@tonic-gate 		else if (cnt == 0)
1129*0Sstevel@tonic-gate 			return (0);
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate 		/* recurse */
1132*0Sstevel@tonic-gate 		for (p = nlp; (p != NULL); p = p->next) {
1133*0Sstevel@tonic-gate 			mdname_t	*np = p->namep;
1134*0Sstevel@tonic-gate 
1135*0Sstevel@tonic-gate 			if (meta_stripe_print(sp, np, nlpp, fname, fp,
1136*0Sstevel@tonic-gate 			    options, ep) != 0)
1137*0Sstevel@tonic-gate 				rval = -1;
1138*0Sstevel@tonic-gate 		}
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 		/* cleanup, return success */
1141*0Sstevel@tonic-gate 		metafreenamelist(nlp);
1142*0Sstevel@tonic-gate 		return (rval);
1143*0Sstevel@tonic-gate 	}
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 	/* get unit structure */
1146*0Sstevel@tonic-gate 	if ((stripep = meta_get_stripe_common(sp, stripenp,
1147*0Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
1148*0Sstevel@tonic-gate 		return (-1);
1149*0Sstevel@tonic-gate 
1150*0Sstevel@tonic-gate 	/* check for parented */
1151*0Sstevel@tonic-gate 	if ((! (options & PRINT_SUBDEVS)) &&
1152*0Sstevel@tonic-gate 	    (MD_HAS_PARENT(stripep->common.parent))) {
1153*0Sstevel@tonic-gate 		return (0);
1154*0Sstevel@tonic-gate 	}
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate 	/* print appropriate detail */
1157*0Sstevel@tonic-gate 	if (options & PRINT_SHORT) {
1158*0Sstevel@tonic-gate 		if (stripe_print(stripep, fname, fp, options, ep) != 0)
1159*0Sstevel@tonic-gate 			return (-1);
1160*0Sstevel@tonic-gate 	} else {
1161*0Sstevel@tonic-gate 		if (stripe_report(sp, stripep, nlpp, fname, fp, options,
1162*0Sstevel@tonic-gate 		    ep) != 0)
1163*0Sstevel@tonic-gate 			return (-1);
1164*0Sstevel@tonic-gate 	}
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 	/* Recurse on components that are metadevices */
1167*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
1168*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate 		/* look for components that are metadevices */
1171*0Sstevel@tonic-gate 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
1172*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
1173*0Sstevel@tonic-gate 			mdname_t	*namep = cp->compnamep;
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate 			if ((metaismeta(namep)) &&
1176*0Sstevel@tonic-gate 			    (meta_print_name(sp, namep, nlpp, fname, fp,
1177*0Sstevel@tonic-gate 			    (options | PRINT_HEADER | PRINT_SUBDEVS),
1178*0Sstevel@tonic-gate 			    NULL, ep) != 0)) {
1179*0Sstevel@tonic-gate 				return (-1);
1180*0Sstevel@tonic-gate 			}
1181*0Sstevel@tonic-gate 		}
1182*0Sstevel@tonic-gate 	}
1183*0Sstevel@tonic-gate 	return (0);
1184*0Sstevel@tonic-gate }
1185*0Sstevel@tonic-gate 
1186*0Sstevel@tonic-gate /*
1187*0Sstevel@tonic-gate  * find stripe component to replace
1188*0Sstevel@tonic-gate  */
1189*0Sstevel@tonic-gate int
1190*0Sstevel@tonic-gate meta_find_erred_comp(
1191*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1192*0Sstevel@tonic-gate 	mdname_t	*stripenp,
1193*0Sstevel@tonic-gate 	mdname_t	**compnpp,
1194*0Sstevel@tonic-gate 	comp_state_t	*compstate,
1195*0Sstevel@tonic-gate 	md_error_t	*ep
1196*0Sstevel@tonic-gate )
1197*0Sstevel@tonic-gate {
1198*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
1199*0Sstevel@tonic-gate 	md_comp_t	*compp = NULL;
1200*0Sstevel@tonic-gate 	uint_t		lasterrcnt = 0;
1201*0Sstevel@tonic-gate 	uint_t		row;
1202*0Sstevel@tonic-gate 
1203*0Sstevel@tonic-gate 	/* get stripe */
1204*0Sstevel@tonic-gate 	*compnpp = NULL;
1205*0Sstevel@tonic-gate 	if ((stripep = meta_get_stripe_common(sp, stripenp, 1, ep)) == NULL)
1206*0Sstevel@tonic-gate 		return (-1);
1207*0Sstevel@tonic-gate 
1208*0Sstevel@tonic-gate 	/*
1209*0Sstevel@tonic-gate 	 * Try to find the first erred component.
1210*0Sstevel@tonic-gate 	 * If there is not one, then look for the
1211*0Sstevel@tonic-gate 	 *	first last_erred component.
1212*0Sstevel@tonic-gate 	 */
1213*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
1214*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1215*0Sstevel@tonic-gate 		uint_t		comp;
1216*0Sstevel@tonic-gate 
1217*0Sstevel@tonic-gate 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
1218*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
1219*0Sstevel@tonic-gate 
1220*0Sstevel@tonic-gate 			if ((cp->state == CS_ERRED) && ((compp == NULL) ||
1221*0Sstevel@tonic-gate 			    (cp->lasterrcnt < lasterrcnt))) {
1222*0Sstevel@tonic-gate 				compp = cp;
1223*0Sstevel@tonic-gate 				lasterrcnt = cp->lasterrcnt;
1224*0Sstevel@tonic-gate 			}
1225*0Sstevel@tonic-gate 		}
1226*0Sstevel@tonic-gate 	}
1227*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
1228*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1229*0Sstevel@tonic-gate 		uint_t		comp;
1230*0Sstevel@tonic-gate 
1231*0Sstevel@tonic-gate 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
1232*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
1233*0Sstevel@tonic-gate 
1234*0Sstevel@tonic-gate 			if ((cp->state == CS_LAST_ERRED) && ((compp == NULL) ||
1235*0Sstevel@tonic-gate 			    (cp->lasterrcnt < lasterrcnt))) {
1236*0Sstevel@tonic-gate 				compp = cp;
1237*0Sstevel@tonic-gate 				lasterrcnt = cp->lasterrcnt;
1238*0Sstevel@tonic-gate 			}
1239*0Sstevel@tonic-gate 		}
1240*0Sstevel@tonic-gate 	}
1241*0Sstevel@tonic-gate 
1242*0Sstevel@tonic-gate 	/* return component */
1243*0Sstevel@tonic-gate 	if (compp != NULL) {
1244*0Sstevel@tonic-gate 		*compnpp = compp->compnamep;
1245*0Sstevel@tonic-gate 		*compstate = compp->state;
1246*0Sstevel@tonic-gate 	}
1247*0Sstevel@tonic-gate 
1248*0Sstevel@tonic-gate 	/* return success */
1249*0Sstevel@tonic-gate 	return (0);
1250*0Sstevel@tonic-gate }
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate /*
1253*0Sstevel@tonic-gate  * invalidate component names
1254*0Sstevel@tonic-gate  */
1255*0Sstevel@tonic-gate static int
1256*0Sstevel@tonic-gate invalidate_components(
1257*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1258*0Sstevel@tonic-gate 	mdname_t	*stripenp,
1259*0Sstevel@tonic-gate 	md_error_t	*ep
1260*0Sstevel@tonic-gate )
1261*0Sstevel@tonic-gate {
1262*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
1263*0Sstevel@tonic-gate 	uint_t		row;
1264*0Sstevel@tonic-gate 
1265*0Sstevel@tonic-gate 	if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
1266*0Sstevel@tonic-gate 		return (-1);
1267*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
1268*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1269*0Sstevel@tonic-gate 		uint_t		comp;
1270*0Sstevel@tonic-gate 
1271*0Sstevel@tonic-gate 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
1272*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
1273*0Sstevel@tonic-gate 			mdname_t	*compnp = cp->compnamep;
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate 			meta_invalidate_name(compnp);
1276*0Sstevel@tonic-gate 		}
1277*0Sstevel@tonic-gate 	}
1278*0Sstevel@tonic-gate 	return (0);
1279*0Sstevel@tonic-gate }
1280*0Sstevel@tonic-gate 
1281*0Sstevel@tonic-gate /*
1282*0Sstevel@tonic-gate  * attach components to stripe
1283*0Sstevel@tonic-gate  */
1284*0Sstevel@tonic-gate int
1285*0Sstevel@tonic-gate meta_stripe_attach(
1286*0Sstevel@tonic-gate 	mdsetname_t		*sp,
1287*0Sstevel@tonic-gate 	mdname_t		*stripenp,
1288*0Sstevel@tonic-gate 	mdnamelist_t		*nlp,
1289*0Sstevel@tonic-gate 	diskaddr_t		interlace,
1290*0Sstevel@tonic-gate 	mdcmdopts_t		options,
1291*0Sstevel@tonic-gate 	md_error_t		*ep
1292*0Sstevel@tonic-gate )
1293*0Sstevel@tonic-gate {
1294*0Sstevel@tonic-gate 	mdnamelist_t		*lp;
1295*0Sstevel@tonic-gate 	ms_unit_t		*old_un, *new_un;
1296*0Sstevel@tonic-gate 	struct ms_row		*mdr, *new_mdr;
1297*0Sstevel@tonic-gate 	uint_t			newcomps, ncomps, icomp;
1298*0Sstevel@tonic-gate 	uint_t			row;
1299*0Sstevel@tonic-gate 	size_t			mdsize, first_comp;
1300*0Sstevel@tonic-gate 	diskaddr_t		new_blks;
1301*0Sstevel@tonic-gate 	diskaddr_t		limit;
1302*0Sstevel@tonic-gate 	diskaddr_t		disk_size = 0;
1303*0Sstevel@tonic-gate 	ms_comp_t		*mdcomp, *new_comp;
1304*0Sstevel@tonic-gate 	uint_t			write_reinstruct = 0;
1305*0Sstevel@tonic-gate 	uint_t			read_reinstruct = 0;
1306*0Sstevel@tonic-gate 	mdnamelist_t		*keynlp = NULL;
1307*0Sstevel@tonic-gate 	uint_t			round_cyl = 1;
1308*0Sstevel@tonic-gate 	minor_t			parent;
1309*0Sstevel@tonic-gate 	md_grow_params_t	mgp;
1310*0Sstevel@tonic-gate 	int			rval = -1;
1311*0Sstevel@tonic-gate 	md_timeval32_t		creation_time;
1312*0Sstevel@tonic-gate 	int			create_flag = MD_CRO_32BIT;
1313*0Sstevel@tonic-gate 
1314*0Sstevel@tonic-gate 	/* should have a set */
1315*0Sstevel@tonic-gate 	assert(sp != NULL);
1316*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate 	/* check type */
1319*0Sstevel@tonic-gate 	if (metachkmeta(stripenp, ep) != 0)
1320*0Sstevel@tonic-gate 		return (-1);
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate 	/* check and count components */
1323*0Sstevel@tonic-gate 	assert(nlp != NULL);
1324*0Sstevel@tonic-gate 	newcomps = 0;
1325*0Sstevel@tonic-gate 	for (lp = nlp; (lp != NULL); lp = lp->next) {
1326*0Sstevel@tonic-gate 		mdname_t	*np = lp->namep;
1327*0Sstevel@tonic-gate 		mdnamelist_t	*p;
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 		/* check against existing devices */
1330*0Sstevel@tonic-gate 		if (meta_check_component(sp, np, 0, ep) != 0)
1331*0Sstevel@tonic-gate 			return (-1);
1332*0Sstevel@tonic-gate 
1333*0Sstevel@tonic-gate 		/* check against ourselves */
1334*0Sstevel@tonic-gate 		for (p = lp->next; (p != NULL); p = p->next) {
1335*0Sstevel@tonic-gate 			if (meta_check_overlap(np->cname, np, 0, -1,
1336*0Sstevel@tonic-gate 			    p->namep, 0, -1, ep) != 0) {
1337*0Sstevel@tonic-gate 				return (-1);
1338*0Sstevel@tonic-gate 			}
1339*0Sstevel@tonic-gate 		}
1340*0Sstevel@tonic-gate 
1341*0Sstevel@tonic-gate 		/* count */
1342*0Sstevel@tonic-gate 		++newcomps;
1343*0Sstevel@tonic-gate 	}
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 	/* get old unit */
1346*0Sstevel@tonic-gate 	if ((old_un = (ms_unit_t *)meta_get_mdunit(sp, stripenp, ep)) == NULL)
1347*0Sstevel@tonic-gate 		return (-1);
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 	/* if zero, inherit the last rows interlace value */
1350*0Sstevel@tonic-gate 	if (interlace == 0) {
1351*0Sstevel@tonic-gate 		mdr = &old_un->un_row[old_un->un_nrows - 1];
1352*0Sstevel@tonic-gate 		interlace = mdr->un_interlace;
1353*0Sstevel@tonic-gate 	}
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 	/*
1356*0Sstevel@tonic-gate 	 * calculate size of new unit structure
1357*0Sstevel@tonic-gate 	 */
1358*0Sstevel@tonic-gate 
1359*0Sstevel@tonic-gate 	/* unit + rows */
1360*0Sstevel@tonic-gate 	mdsize = sizeof (ms_unit_t) - sizeof (struct ms_row);
1361*0Sstevel@tonic-gate 	mdsize += sizeof (struct ms_row) * (old_un->un_nrows + 1);
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 	/* number of new components being added */
1364*0Sstevel@tonic-gate 	ncomps = newcomps;
1365*0Sstevel@tonic-gate 
1366*0Sstevel@tonic-gate 	/* count the # of components in the old unit */
1367*0Sstevel@tonic-gate 	mdr = &old_un->un_row[0];
1368*0Sstevel@tonic-gate 	for (row = 0; (row < old_un->un_nrows); row++)
1369*0Sstevel@tonic-gate 		ncomps += mdr[row].un_ncomp;
1370*0Sstevel@tonic-gate 	first_comp = roundup(mdsize, sizeof (long long));
1371*0Sstevel@tonic-gate 	mdsize += sizeof (ms_comp_t) * ncomps + (first_comp - mdsize);
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate 	/* allocate new unit */
1374*0Sstevel@tonic-gate 	new_un = Zalloc(mdsize);
1375*0Sstevel@tonic-gate 	new_un->un_ocomp = first_comp;
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate 	/* compute new data */
1378*0Sstevel@tonic-gate 	new_mdr = &new_un->un_row[old_un->un_nrows];
1379*0Sstevel@tonic-gate 	new_mdr->un_icomp = ncomps - newcomps;
1380*0Sstevel@tonic-gate 	new_mdr->un_ncomp = newcomps;
1381*0Sstevel@tonic-gate 	new_mdr->un_blocks = 0;
1382*0Sstevel@tonic-gate 	new_mdr->un_cum_blocks =
1383*0Sstevel@tonic-gate 	    old_un->un_row[old_un->un_nrows - 1].un_cum_blocks;
1384*0Sstevel@tonic-gate 	new_mdr->un_interlace = interlace;
1385*0Sstevel@tonic-gate 
1386*0Sstevel@tonic-gate 	/* for each new device */
1387*0Sstevel@tonic-gate 	mdcomp = (struct ms_comp *)(void *)&((char *)new_un)[new_un->un_ocomp];
1388*0Sstevel@tonic-gate 	icomp = new_mdr->un_icomp;
1389*0Sstevel@tonic-gate 	if (meta_gettimeofday(&creation_time) == -1)
1390*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
1391*0Sstevel@tonic-gate 	for (lp = nlp; (lp != NULL); lp = lp->next) {
1392*0Sstevel@tonic-gate 		mdname_t	*np = lp->namep;
1393*0Sstevel@tonic-gate 		diskaddr_t	size, start_blk;
1394*0Sstevel@tonic-gate 		mdgeom_t		*geomp;
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate 		/* figure out how big */
1397*0Sstevel@tonic-gate 		if ((size = metagetsize(np, ep)) == MD_DISKADDR_ERROR)
1398*0Sstevel@tonic-gate 			goto out;
1399*0Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, np, ep)) ==
1400*0Sstevel@tonic-gate 		    MD_DISKADDR_ERROR)
1401*0Sstevel@tonic-gate 			goto out;
1402*0Sstevel@tonic-gate 		if (start_blk >= size) {
1403*0Sstevel@tonic-gate 			(void) mdsyserror(ep, ENOSPC, np->cname);
1404*0Sstevel@tonic-gate 			goto out;
1405*0Sstevel@tonic-gate 		}
1406*0Sstevel@tonic-gate 		size -= start_blk;
1407*0Sstevel@tonic-gate 		if (newcomps > 1)
1408*0Sstevel@tonic-gate 			size = rounddown(size, interlace);
1409*0Sstevel@tonic-gate 
1410*0Sstevel@tonic-gate 		/* adjust for smallest disk */
1411*0Sstevel@tonic-gate 		if (disk_size == 0) {
1412*0Sstevel@tonic-gate 			disk_size = size;
1413*0Sstevel@tonic-gate 		} else if (size < disk_size) {
1414*0Sstevel@tonic-gate 			disk_size = size;
1415*0Sstevel@tonic-gate 		}
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate 		/* get worst reinstructs */
1418*0Sstevel@tonic-gate 		if ((geomp = metagetgeom(np, ep)) == NULL)
1419*0Sstevel@tonic-gate 			goto out;
1420*0Sstevel@tonic-gate 		if (geomp->write_reinstruct > write_reinstruct)
1421*0Sstevel@tonic-gate 			write_reinstruct = geomp->write_reinstruct;
1422*0Sstevel@tonic-gate 		if (geomp->read_reinstruct > read_reinstruct)
1423*0Sstevel@tonic-gate 			read_reinstruct = geomp->read_reinstruct;
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 		/* In dryrun mode (DOIT not set) we must not alter the mddb */
1426*0Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
1427*0Sstevel@tonic-gate 			/* store name in namespace */
1428*0Sstevel@tonic-gate 			if (add_key_name(sp, np, &keynlp, ep) != 0)
1429*0Sstevel@tonic-gate 				goto out;
1430*0Sstevel@tonic-gate 		}
1431*0Sstevel@tonic-gate 
1432*0Sstevel@tonic-gate 		/* build new component */
1433*0Sstevel@tonic-gate 		new_comp = &mdcomp[icomp++];
1434*0Sstevel@tonic-gate 		new_comp->un_key = np->key;
1435*0Sstevel@tonic-gate 		new_comp->un_dev = np->dev;
1436*0Sstevel@tonic-gate 		new_comp->un_start_block = start_blk;
1437*0Sstevel@tonic-gate 		new_comp->un_mirror.ms_state = CS_OKAY;
1438*0Sstevel@tonic-gate 		new_comp->un_mirror.ms_timestamp = creation_time;
1439*0Sstevel@tonic-gate 	}
1440*0Sstevel@tonic-gate 
1441*0Sstevel@tonic-gate 	limit = LLONG_MAX;
1442*0Sstevel@tonic-gate 
1443*0Sstevel@tonic-gate 	/* compute new size */
1444*0Sstevel@tonic-gate 	new_mdr->un_blocks = new_mdr->un_ncomp * disk_size;
1445*0Sstevel@tonic-gate 	new_blks = new_mdr->un_cum_blocks + new_mdr->un_blocks;
1446*0Sstevel@tonic-gate 	if (new_blks > limit) {
1447*0Sstevel@tonic-gate 		new_mdr->un_cum_blocks = limit;
1448*0Sstevel@tonic-gate 		new_blks = limit;
1449*0Sstevel@tonic-gate 		md_eprintf(dgettext(TEXT_DOMAIN,
1450*0Sstevel@tonic-gate 		    "unit size overflow, limit is %lld blocks\n"),
1451*0Sstevel@tonic-gate 		    limit);
1452*0Sstevel@tonic-gate 	} else {
1453*0Sstevel@tonic-gate 		new_mdr->un_cum_blocks += new_mdr->un_blocks;
1454*0Sstevel@tonic-gate 	}
1455*0Sstevel@tonic-gate 	new_un->c.un_actual_tb = new_mdr->un_cum_blocks;
1456*0Sstevel@tonic-gate 	new_un->un_nrows = old_un->un_nrows + 1;
1457*0Sstevel@tonic-gate 
1458*0Sstevel@tonic-gate 	/* adjust geometry */
1459*0Sstevel@tonic-gate 	new_un->c.un_nhead = old_un->c.un_nhead;
1460*0Sstevel@tonic-gate 	new_un->c.un_nsect = old_un->c.un_nsect;
1461*0Sstevel@tonic-gate 	new_un->c.un_rpm = old_un->c.un_rpm;
1462*0Sstevel@tonic-gate 	new_un->c.un_wr_reinstruct = old_un->c.un_wr_reinstruct;
1463*0Sstevel@tonic-gate 	new_un->c.un_rd_reinstruct = old_un->c.un_rd_reinstruct;
1464*0Sstevel@tonic-gate 	if (meta_adjust_geom((md_unit_t *)new_un, stripenp,
1465*0Sstevel@tonic-gate 	    write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
1466*0Sstevel@tonic-gate 		goto out;
1467*0Sstevel@tonic-gate 
1468*0Sstevel@tonic-gate 	/* if in dryrun mode, we are done here. */
1469*0Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0)  {
1470*0Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
1471*0Sstevel@tonic-gate 			if (newcomps == 1) {
1472*0Sstevel@tonic-gate 				(void) printf(dgettext(TEXT_DOMAIN,
1473*0Sstevel@tonic-gate 				"%s: attaching component would suceed\n"),
1474*0Sstevel@tonic-gate 				stripenp->cname);
1475*0Sstevel@tonic-gate 			} else {
1476*0Sstevel@tonic-gate 				(void) printf(dgettext(TEXT_DOMAIN,
1477*0Sstevel@tonic-gate 				"%s: attaching components would suceed\n"),
1478*0Sstevel@tonic-gate 				stripenp->cname);
1479*0Sstevel@tonic-gate 			}
1480*0Sstevel@tonic-gate 		}
1481*0Sstevel@tonic-gate 		rval = 0; /* success */
1482*0Sstevel@tonic-gate 		goto out;
1483*0Sstevel@tonic-gate 	}
1484*0Sstevel@tonic-gate 
1485*0Sstevel@tonic-gate 	create_flag = meta_check_devicesize(new_un->c.un_total_blocks);
1486*0Sstevel@tonic-gate 
1487*0Sstevel@tonic-gate 	/* grow stripe */
1488*0Sstevel@tonic-gate 	(void) memset(&mgp, 0, sizeof (mgp));
1489*0Sstevel@tonic-gate 	mgp.mnum = MD_SID(old_un);
1490*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mgp, MD_STRIPE, sp->setno);
1491*0Sstevel@tonic-gate 	mgp.size = mdsize;
1492*0Sstevel@tonic-gate 	mgp.mdp = (uintptr_t)new_un;
1493*0Sstevel@tonic-gate 	mgp.nrows = old_un->un_nrows;
1494*0Sstevel@tonic-gate 	if (create_flag == MD_CRO_32BIT) {
1495*0Sstevel@tonic-gate 		mgp.options = MD_CRO_32BIT;
1496*0Sstevel@tonic-gate 		new_un->c.un_revision = MD_32BIT_META_DEV;
1497*0Sstevel@tonic-gate 	} else {
1498*0Sstevel@tonic-gate 		mgp.options = MD_CRO_64BIT;
1499*0Sstevel@tonic-gate 		new_un->c.un_revision = MD_64BIT_META_DEV;
1500*0Sstevel@tonic-gate 	}
1501*0Sstevel@tonic-gate 
1502*0Sstevel@tonic-gate 	if ((MD_HAS_PARENT(old_un->c.un_parent)) &&
1503*0Sstevel@tonic-gate 	    (old_un->c.un_parent != MD_MULTI_PARENT)) {
1504*0Sstevel@tonic-gate 		mgp.npar = 1;
1505*0Sstevel@tonic-gate 		parent = old_un->c.un_parent;
1506*0Sstevel@tonic-gate 		mgp.par = (uintptr_t)(&parent);
1507*0Sstevel@tonic-gate 	}
1508*0Sstevel@tonic-gate 
1509*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGROW, &mgp, &mgp.mde, NULL) != 0) {
1510*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &mgp.mde);
1511*0Sstevel@tonic-gate 		goto out;
1512*0Sstevel@tonic-gate 	}
1513*0Sstevel@tonic-gate 
1514*0Sstevel@tonic-gate 	/* clear cache */
1515*0Sstevel@tonic-gate 	if (invalidate_components(sp, stripenp, ep) != 0)
1516*0Sstevel@tonic-gate 		goto out;
1517*0Sstevel@tonic-gate 	meta_invalidate_name(stripenp);
1518*0Sstevel@tonic-gate 
1519*0Sstevel@tonic-gate 	/* let em know */
1520*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
1521*0Sstevel@tonic-gate 		if (newcomps == 1) {
1522*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
1523*0Sstevel@tonic-gate 			    "%s: component is attached\n"), stripenp->cname);
1524*0Sstevel@tonic-gate 		} else {
1525*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
1526*0Sstevel@tonic-gate 			    "%s: components are attached\n"), stripenp->cname);
1527*0Sstevel@tonic-gate 		}
1528*0Sstevel@tonic-gate 		(void) fflush(stdout);
1529*0Sstevel@tonic-gate 	}
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate 	/* grow any parents */
1532*0Sstevel@tonic-gate 	if (meta_concat_parent(sp, stripenp, ep) != 0)
1533*0Sstevel@tonic-gate 		return (-1);
1534*0Sstevel@tonic-gate 
1535*0Sstevel@tonic-gate 	rval = 0;	/* success */
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate 	/* cleanup, return error */
1538*0Sstevel@tonic-gate out:
1539*0Sstevel@tonic-gate 	Free(old_un);
1540*0Sstevel@tonic-gate 	Free(new_un);
1541*0Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
1542*0Sstevel@tonic-gate 		if (rval != 0)
1543*0Sstevel@tonic-gate 			(void) del_key_names(sp, keynlp, NULL);
1544*0Sstevel@tonic-gate 		metafreenamelist(keynlp);
1545*0Sstevel@tonic-gate 	}
1546*0Sstevel@tonic-gate 	return (rval);
1547*0Sstevel@tonic-gate }
1548*0Sstevel@tonic-gate 
1549*0Sstevel@tonic-gate /*
1550*0Sstevel@tonic-gate  * get stripe parameters
1551*0Sstevel@tonic-gate  */
1552*0Sstevel@tonic-gate int
1553*0Sstevel@tonic-gate meta_stripe_get_params(
1554*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1555*0Sstevel@tonic-gate 	mdname_t	*stripenp,
1556*0Sstevel@tonic-gate 	ms_params_t	*paramsp,
1557*0Sstevel@tonic-gate 	md_error_t	*ep
1558*0Sstevel@tonic-gate )
1559*0Sstevel@tonic-gate {
1560*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
1561*0Sstevel@tonic-gate 
1562*0Sstevel@tonic-gate 	/* should have a set */
1563*0Sstevel@tonic-gate 	assert(sp != NULL);
1564*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
1565*0Sstevel@tonic-gate 
1566*0Sstevel@tonic-gate 	/* check name */
1567*0Sstevel@tonic-gate 	if (metachkmeta(stripenp, ep) != 0)
1568*0Sstevel@tonic-gate 		return (-1);
1569*0Sstevel@tonic-gate 
1570*0Sstevel@tonic-gate 	/* get unit */
1571*0Sstevel@tonic-gate 	if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
1572*0Sstevel@tonic-gate 		return (-1);
1573*0Sstevel@tonic-gate 
1574*0Sstevel@tonic-gate 	/* return parameters */
1575*0Sstevel@tonic-gate 	(void) memset(paramsp, 0, sizeof (*paramsp));
1576*0Sstevel@tonic-gate 	if (stripep->hspnamep == NULL)
1577*0Sstevel@tonic-gate 		paramsp->hsp_id = MD_HSP_NONE;
1578*0Sstevel@tonic-gate 	else
1579*0Sstevel@tonic-gate 		paramsp->hsp_id = stripep->hspnamep->hsp;
1580*0Sstevel@tonic-gate 	return (0);
1581*0Sstevel@tonic-gate }
1582*0Sstevel@tonic-gate 
1583*0Sstevel@tonic-gate /*
1584*0Sstevel@tonic-gate  * set stripe parameters
1585*0Sstevel@tonic-gate  */
1586*0Sstevel@tonic-gate int
1587*0Sstevel@tonic-gate meta_stripe_set_params(
1588*0Sstevel@tonic-gate 	mdsetname_t		*sp,
1589*0Sstevel@tonic-gate 	mdname_t		*stripenp,
1590*0Sstevel@tonic-gate 	ms_params_t		*paramsp,
1591*0Sstevel@tonic-gate 	md_error_t		*ep
1592*0Sstevel@tonic-gate )
1593*0Sstevel@tonic-gate {
1594*0Sstevel@tonic-gate 	md_stripe_params_t	msp;
1595*0Sstevel@tonic-gate 
1596*0Sstevel@tonic-gate 	/* should have a set */
1597*0Sstevel@tonic-gate 	assert(sp != NULL);
1598*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
1599*0Sstevel@tonic-gate 
1600*0Sstevel@tonic-gate 	/* check name */
1601*0Sstevel@tonic-gate 	if (metachkmeta(stripenp, ep) != 0)
1602*0Sstevel@tonic-gate 		return (-1);
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 	/* set parameters */
1605*0Sstevel@tonic-gate 	(void) memset(&msp, 0, sizeof (msp));
1606*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&msp, MD_STRIPE, sp->setno);
1607*0Sstevel@tonic-gate 	msp.mnum = meta_getminor(stripenp->dev);
1608*0Sstevel@tonic-gate 	msp.params = *paramsp;
1609*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCCHANGE, &msp, &msp.mde, stripenp->cname) != 0)
1610*0Sstevel@tonic-gate 		return (mdstealerror(ep, &msp.mde));
1611*0Sstevel@tonic-gate 
1612*0Sstevel@tonic-gate 	/* clear cache */
1613*0Sstevel@tonic-gate 	meta_invalidate_name(stripenp);
1614*0Sstevel@tonic-gate 
1615*0Sstevel@tonic-gate 	/* return success */
1616*0Sstevel@tonic-gate 	return (0);
1617*0Sstevel@tonic-gate }
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate /*
1620*0Sstevel@tonic-gate  * check for dups in the stripe itself
1621*0Sstevel@tonic-gate  */
1622*0Sstevel@tonic-gate static int
1623*0Sstevel@tonic-gate check_twice(
1624*0Sstevel@tonic-gate 	md_stripe_t	*stripep,
1625*0Sstevel@tonic-gate 	uint_t		row,
1626*0Sstevel@tonic-gate 	uint_t		comp,
1627*0Sstevel@tonic-gate 	md_error_t	*ep
1628*0Sstevel@tonic-gate )
1629*0Sstevel@tonic-gate {
1630*0Sstevel@tonic-gate 	mdname_t	*stripenp = stripep->common.namep;
1631*0Sstevel@tonic-gate 	mdname_t	*thisnp;
1632*0Sstevel@tonic-gate 	uint_t		r;
1633*0Sstevel@tonic-gate 
1634*0Sstevel@tonic-gate 	thisnp = stripep->rows.rows_val[row].comps.comps_val[comp].compnamep;
1635*0Sstevel@tonic-gate 	for (r = 0; (r <= row); ++r) {
1636*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[r];
1637*0Sstevel@tonic-gate 		uint_t		e = ((r == row) ? comp : rp->comps.comps_len);
1638*0Sstevel@tonic-gate 		uint_t		c;
1639*0Sstevel@tonic-gate 
1640*0Sstevel@tonic-gate 		for (c = 0; (c < e); ++c) {
1641*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[c];
1642*0Sstevel@tonic-gate 			mdname_t	*compnp = cp->compnamep;
1643*0Sstevel@tonic-gate 
1644*0Sstevel@tonic-gate 			if (meta_check_overlap(stripenp->cname, thisnp, 0, -1,
1645*0Sstevel@tonic-gate 			    compnp, 0, -1, ep) != 0) {
1646*0Sstevel@tonic-gate 				return (-1);
1647*0Sstevel@tonic-gate 			}
1648*0Sstevel@tonic-gate 		}
1649*0Sstevel@tonic-gate 	}
1650*0Sstevel@tonic-gate 	return (0);
1651*0Sstevel@tonic-gate }
1652*0Sstevel@tonic-gate 
1653*0Sstevel@tonic-gate /*
1654*0Sstevel@tonic-gate  * default stripe interlace
1655*0Sstevel@tonic-gate  */
1656*0Sstevel@tonic-gate diskaddr_t
1657*0Sstevel@tonic-gate meta_default_stripe_interlace(void)
1658*0Sstevel@tonic-gate {
1659*0Sstevel@tonic-gate 	diskaddr_t		interlace;
1660*0Sstevel@tonic-gate 
1661*0Sstevel@tonic-gate 	/* default to 16k, round up if necessary */
1662*0Sstevel@tonic-gate 	interlace = btodb(16 * 1024);
1663*0Sstevel@tonic-gate 	if (interlace < btodb(MININTERLACE))
1664*0Sstevel@tonic-gate 		interlace = roundup(MININTERLACE, interlace);
1665*0Sstevel@tonic-gate 	return (interlace);
1666*0Sstevel@tonic-gate }
1667*0Sstevel@tonic-gate 
1668*0Sstevel@tonic-gate /*
1669*0Sstevel@tonic-gate  * convert interlaces
1670*0Sstevel@tonic-gate  */
1671*0Sstevel@tonic-gate int
1672*0Sstevel@tonic-gate meta_stripe_check_interlace(
1673*0Sstevel@tonic-gate 	diskaddr_t	interlace,
1674*0Sstevel@tonic-gate 	char		*uname,
1675*0Sstevel@tonic-gate 	md_error_t	*ep
1676*0Sstevel@tonic-gate )
1677*0Sstevel@tonic-gate {
1678*0Sstevel@tonic-gate 	if ((interlace < btodb(MININTERLACE)) ||
1679*0Sstevel@tonic-gate 		(interlace > btodb(MAXINTERLACE))) {
1680*0Sstevel@tonic-gate 		return (mderror(ep, MDE_BAD_INTERLACE, uname));
1681*0Sstevel@tonic-gate 	}
1682*0Sstevel@tonic-gate 	return (0);
1683*0Sstevel@tonic-gate }
1684*0Sstevel@tonic-gate 
1685*0Sstevel@tonic-gate 
1686*0Sstevel@tonic-gate /*
1687*0Sstevel@tonic-gate  * check stripe
1688*0Sstevel@tonic-gate  */
1689*0Sstevel@tonic-gate int
1690*0Sstevel@tonic-gate meta_check_stripe(
1691*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1692*0Sstevel@tonic-gate 	md_stripe_t	*stripep,
1693*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1694*0Sstevel@tonic-gate 	md_error_t	*ep
1695*0Sstevel@tonic-gate )
1696*0Sstevel@tonic-gate {
1697*0Sstevel@tonic-gate 	mdname_t	*stripenp = stripep->common.namep;
1698*0Sstevel@tonic-gate 	int		force = ((options & MDCMD_FORCE) ? 1 : 0);
1699*0Sstevel@tonic-gate 	int		doit = ((options & MDCMD_DOIT) ? 1 : 0);
1700*0Sstevel@tonic-gate 	int		updateit = ((options & MDCMD_UPDATE) ? 1 : 0);
1701*0Sstevel@tonic-gate 	uint_t		row;
1702*0Sstevel@tonic-gate 
1703*0Sstevel@tonic-gate 	/* check rows */
1704*0Sstevel@tonic-gate 	if (stripep->rows.rows_len < 1) {
1705*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_BAD_STRIPE,
1706*0Sstevel@tonic-gate 		    meta_getminor(stripenp->dev), stripenp->cname));
1707*0Sstevel@tonic-gate 	}
1708*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
1709*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1710*0Sstevel@tonic-gate 		uint_t		comp;
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 		/* check number */
1713*0Sstevel@tonic-gate 		if (rp->comps.comps_len < 1) {
1714*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_BAD_STRIPE,
1715*0Sstevel@tonic-gate 			    meta_getminor(stripenp->dev), stripenp->cname));
1716*0Sstevel@tonic-gate 		}
1717*0Sstevel@tonic-gate 
1718*0Sstevel@tonic-gate 		/* compute default interlace */
1719*0Sstevel@tonic-gate 		if (rp->interlace == 0) {
1720*0Sstevel@tonic-gate 			rp->interlace = meta_default_stripe_interlace();
1721*0Sstevel@tonic-gate 		}
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 		/* check interlace */
1724*0Sstevel@tonic-gate 		if (meta_stripe_check_interlace(rp->interlace, stripenp->cname,
1725*0Sstevel@tonic-gate 		    ep) != 0) {
1726*0Sstevel@tonic-gate 			return (-1);
1727*0Sstevel@tonic-gate 		}
1728*0Sstevel@tonic-gate 
1729*0Sstevel@tonic-gate 		/* check components */
1730*0Sstevel@tonic-gate 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
1731*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
1732*0Sstevel@tonic-gate 			mdname_t	*compnp = cp->compnamep;
1733*0Sstevel@tonic-gate 			diskaddr_t	start_blk, size;
1734*0Sstevel@tonic-gate 
1735*0Sstevel@tonic-gate 			/* check component */
1736*0Sstevel@tonic-gate 			if (!updateit) {
1737*0Sstevel@tonic-gate 				if (meta_check_component(sp, compnp,
1738*0Sstevel@tonic-gate 					force, ep) != 0)
1739*0Sstevel@tonic-gate 					return (-1);
1740*0Sstevel@tonic-gate 				if (((start_blk = metagetstart(sp, compnp,
1741*0Sstevel@tonic-gate 				    ep)) == MD_DISKADDR_ERROR) ||
1742*0Sstevel@tonic-gate 				    ((size = metagetsize(compnp, ep)) ==
1743*0Sstevel@tonic-gate 				    MD_DISKADDR_ERROR)) {
1744*0Sstevel@tonic-gate 					return (-1);
1745*0Sstevel@tonic-gate 				}
1746*0Sstevel@tonic-gate 				if (start_blk >= size)
1747*0Sstevel@tonic-gate 					return (mdsyserror(ep, ENOSPC,
1748*0Sstevel@tonic-gate 						compnp->cname));
1749*0Sstevel@tonic-gate 				size -= start_blk;
1750*0Sstevel@tonic-gate 				size = rounddown(size, rp->interlace);
1751*0Sstevel@tonic-gate 				if (size == 0)
1752*0Sstevel@tonic-gate 					return (mdsyserror(ep, ENOSPC,
1753*0Sstevel@tonic-gate 						compnp->cname));
1754*0Sstevel@tonic-gate 			}
1755*0Sstevel@tonic-gate 
1756*0Sstevel@tonic-gate 			/* check this stripe too */
1757*0Sstevel@tonic-gate 			if (check_twice(stripep, row, comp, ep) != 0)
1758*0Sstevel@tonic-gate 				return (-1);
1759*0Sstevel@tonic-gate 		}
1760*0Sstevel@tonic-gate 	}
1761*0Sstevel@tonic-gate 
1762*0Sstevel@tonic-gate 	/* check hotspare pool name */
1763*0Sstevel@tonic-gate 	if (doit) {
1764*0Sstevel@tonic-gate 		if ((stripep->hspnamep != NULL) &&
1765*0Sstevel@tonic-gate 		    (metachkhsp(sp, stripep->hspnamep, ep) != 0)) {
1766*0Sstevel@tonic-gate 			return (-1);
1767*0Sstevel@tonic-gate 		}
1768*0Sstevel@tonic-gate 	}
1769*0Sstevel@tonic-gate 
1770*0Sstevel@tonic-gate 	/* return success */
1771*0Sstevel@tonic-gate 	return (0);
1772*0Sstevel@tonic-gate }
1773*0Sstevel@tonic-gate 
1774*0Sstevel@tonic-gate /*
1775*0Sstevel@tonic-gate  * setup stripe geometry
1776*0Sstevel@tonic-gate  */
1777*0Sstevel@tonic-gate static int
1778*0Sstevel@tonic-gate stripe_geom(
1779*0Sstevel@tonic-gate 	md_stripe_t	*stripep,
1780*0Sstevel@tonic-gate 	ms_unit_t	*ms,
1781*0Sstevel@tonic-gate 	md_error_t	*ep
1782*0Sstevel@tonic-gate )
1783*0Sstevel@tonic-gate {
1784*0Sstevel@tonic-gate 	uint_t		nrow = stripep->rows.rows_len;
1785*0Sstevel@tonic-gate 	uint_t		write_reinstruct = 0;
1786*0Sstevel@tonic-gate 	uint_t		read_reinstruct = 0;
1787*0Sstevel@tonic-gate 	uint_t		round_cyl = 1;
1788*0Sstevel@tonic-gate 	uint_t		row;
1789*0Sstevel@tonic-gate 	mdgeom_t	*geomp;
1790*0Sstevel@tonic-gate 	diskaddr_t	first_row_size = 0;
1791*0Sstevel@tonic-gate 	char		*miscname;
1792*0Sstevel@tonic-gate 	int		is_sp = 0;
1793*0Sstevel@tonic-gate 
1794*0Sstevel@tonic-gate 	/* get worst reinstructs */
1795*0Sstevel@tonic-gate 	for (row = 0; (row < nrow); ++row) {
1796*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1797*0Sstevel@tonic-gate 		uint_t		ncomp = rp->comps.comps_len;
1798*0Sstevel@tonic-gate 		uint_t		comp;
1799*0Sstevel@tonic-gate 
1800*0Sstevel@tonic-gate 		for (comp = 0; (comp < ncomp); ++comp) {
1801*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
1802*0Sstevel@tonic-gate 			mdname_t	*compnp = cp->compnamep;
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate 			if ((geomp = metagetgeom(compnp, ep)) == NULL)
1805*0Sstevel@tonic-gate 				return (-1);
1806*0Sstevel@tonic-gate 			if (geomp->write_reinstruct > write_reinstruct)
1807*0Sstevel@tonic-gate 				write_reinstruct = geomp->write_reinstruct;
1808*0Sstevel@tonic-gate 			if (geomp->read_reinstruct > read_reinstruct)
1809*0Sstevel@tonic-gate 				read_reinstruct = geomp->read_reinstruct;
1810*0Sstevel@tonic-gate 		}
1811*0Sstevel@tonic-gate 	}
1812*0Sstevel@tonic-gate 
1813*0Sstevel@tonic-gate 	if ((geomp = metagetgeom(
1814*0Sstevel@tonic-gate 	    stripep->rows.rows_val[0].comps.comps_val[0].compnamep,
1815*0Sstevel@tonic-gate 	    ep)) == NULL) {
1816*0Sstevel@tonic-gate 		return (-1);
1817*0Sstevel@tonic-gate 	}
1818*0Sstevel@tonic-gate 	/*
1819*0Sstevel@tonic-gate 	 * Figure out if the first component is a softpartition as the
1820*0Sstevel@tonic-gate 	 * truncation check only occurs on them.
1821*0Sstevel@tonic-gate 	 */
1822*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(
1823*0Sstevel@tonic-gate 	    stripep->rows.rows_val[0].comps.comps_val[0].compnamep,
1824*0Sstevel@tonic-gate 	    ep)) == NULL) {
1825*0Sstevel@tonic-gate 		if (!mdisdeverror(ep, MDE_NOT_META))
1826*0Sstevel@tonic-gate 			return (-1);
1827*0Sstevel@tonic-gate 	} else if (strcmp(miscname, MD_SP) == 0) {
1828*0Sstevel@tonic-gate 		is_sp = 1;
1829*0Sstevel@tonic-gate 	}
1830*0Sstevel@tonic-gate 
1831*0Sstevel@tonic-gate 
1832*0Sstevel@tonic-gate 	/* setup geometry from first device */
1833*0Sstevel@tonic-gate 	if (meta_setup_geom((md_unit_t *)ms, stripep->common.namep, geomp,
1834*0Sstevel@tonic-gate 	    write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
1835*0Sstevel@tonic-gate 		return (-1);
1836*0Sstevel@tonic-gate 
1837*0Sstevel@tonic-gate 	/*
1838*0Sstevel@tonic-gate 	 * Here we want to make sure that any truncation did not
1839*0Sstevel@tonic-gate 	 * result in lost data (or, more appropriately, inaccessible
1840*0Sstevel@tonic-gate 	 * data).
1841*0Sstevel@tonic-gate 	 *
1842*0Sstevel@tonic-gate 	 * This is mainly a danger for (1, 1) concats, but it is
1843*0Sstevel@tonic-gate 	 * mathematically possible for other somewhat contrived
1844*0Sstevel@tonic-gate 	 * arrangements where in the sum of the lengths of each row
1845*0Sstevel@tonic-gate 	 * beyond the first is smaller than the cylinder size of the
1846*0Sstevel@tonic-gate 	 * only component in the first row.
1847*0Sstevel@tonic-gate 	 *
1848*0Sstevel@tonic-gate 	 * It is tempting to simply test for truncation here, by
1849*0Sstevel@tonic-gate 	 * (md->c.un_total_blocks < md->c.un_actual_tb). That does
1850*0Sstevel@tonic-gate 	 * not tell us, however, if rounding resulted in data loss,
1851*0Sstevel@tonic-gate 	 * rather only that it occurred. The somewhat less obvious
1852*0Sstevel@tonic-gate 	 * test below covers both the obvious (1, 1) case and the
1853*0Sstevel@tonic-gate 	 * aforementioned corner case.
1854*0Sstevel@tonic-gate 	 */
1855*0Sstevel@tonic-gate 	first_row_size = ms->un_row[0].un_blocks;
1856*0Sstevel@tonic-gate 	if (is_sp == 1) {
1857*0Sstevel@tonic-gate 		md_unit_t	*md = (md_unit_t *)ms;
1858*0Sstevel@tonic-gate 
1859*0Sstevel@tonic-gate 		if (md->c.un_total_blocks < first_row_size) {
1860*0Sstevel@tonic-gate 			char buf[] = VAL2STR(ULLONG_MAX);
1861*0Sstevel@tonic-gate 
1862*0Sstevel@tonic-gate 			/*
1863*0Sstevel@tonic-gate 			 * The only difference here is the text of the error
1864*0Sstevel@tonic-gate 			 * message, since the remediation is slightly
1865*0Sstevel@tonic-gate 			 * different in the one-component versus
1866*0Sstevel@tonic-gate 			 * multiple-component cases.
1867*0Sstevel@tonic-gate 			 */
1868*0Sstevel@tonic-gate 			if (nrow == 1) {
1869*0Sstevel@tonic-gate 				(void) mderror(ep, MDE_STRIPE_TRUNC_SINGLE,
1870*0Sstevel@tonic-gate 				    stripep->common.namep->cname);
1871*0Sstevel@tonic-gate 			} else {
1872*0Sstevel@tonic-gate 				(void) mderror(ep, MDE_STRIPE_TRUNC_MULTIPLE,
1873*0Sstevel@tonic-gate 				    stripep->common.namep->cname);
1874*0Sstevel@tonic-gate 			}
1875*0Sstevel@tonic-gate 
1876*0Sstevel@tonic-gate 			/*
1877*0Sstevel@tonic-gate 			 * By the size comparison above and the initialization
1878*0Sstevel@tonic-gate 			 * of buf[] in terms of ULLONG_MAX, we guarantee that
1879*0Sstevel@tonic-gate 			 * the value arg is non-negative and that we won't
1880*0Sstevel@tonic-gate 			 * overflow the container.
1881*0Sstevel@tonic-gate 			 */
1882*0Sstevel@tonic-gate 			mderrorextra(ep, ulltostr((md->c.un_total_blocks +
1883*0Sstevel@tonic-gate 			    (geomp->nhead * geomp->nsect))
1884*0Sstevel@tonic-gate 			    - first_row_size, &buf[sizeof (buf) - 1]));
1885*0Sstevel@tonic-gate 
1886*0Sstevel@tonic-gate 			return (-1);
1887*0Sstevel@tonic-gate 		}
1888*0Sstevel@tonic-gate 	}
1889*0Sstevel@tonic-gate 
1890*0Sstevel@tonic-gate 	/* return success */
1891*0Sstevel@tonic-gate 	return (0);
1892*0Sstevel@tonic-gate }
1893*0Sstevel@tonic-gate 
1894*0Sstevel@tonic-gate /*
1895*0Sstevel@tonic-gate  * create stripe
1896*0Sstevel@tonic-gate  */
1897*0Sstevel@tonic-gate int
1898*0Sstevel@tonic-gate meta_create_stripe(
1899*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1900*0Sstevel@tonic-gate 	md_stripe_t	*stripep,
1901*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1902*0Sstevel@tonic-gate 	md_error_t	*ep
1903*0Sstevel@tonic-gate )
1904*0Sstevel@tonic-gate {
1905*0Sstevel@tonic-gate 	mdname_t	*stripenp = stripep->common.namep;
1906*0Sstevel@tonic-gate 	int		force = ((options & MDCMD_FORCE) ? 1 : 0);
1907*0Sstevel@tonic-gate 	int		doall = ((options & MDCMD_ALLOPTION) ? 1 : 0);
1908*0Sstevel@tonic-gate 	uint_t		nrow = stripep->rows.rows_len;
1909*0Sstevel@tonic-gate 	uint_t		ncomp = 0;
1910*0Sstevel@tonic-gate 	uint_t		icomp = 0;
1911*0Sstevel@tonic-gate 	diskaddr_t	cum_blocks = 0;
1912*0Sstevel@tonic-gate 	diskaddr_t	limit;
1913*0Sstevel@tonic-gate 	size_t		mdsize, first_comp;
1914*0Sstevel@tonic-gate 	uint_t		row;
1915*0Sstevel@tonic-gate 	ms_unit_t	*ms;
1916*0Sstevel@tonic-gate 	ms_comp_t	*mdcomp;
1917*0Sstevel@tonic-gate 	mdnamelist_t	*keynlp = NULL;
1918*0Sstevel@tonic-gate 	md_set_params_t	set_params;
1919*0Sstevel@tonic-gate 	int		rval = -1;
1920*0Sstevel@tonic-gate 	md_timeval32_t	creation_time;
1921*0Sstevel@tonic-gate 	int		create_flag = MD_CRO_32BIT;
1922*0Sstevel@tonic-gate 
1923*0Sstevel@tonic-gate 	/* validate stripe */
1924*0Sstevel@tonic-gate 	if (meta_check_stripe(sp, stripep, options, ep) != 0)
1925*0Sstevel@tonic-gate 		return (-1);
1926*0Sstevel@tonic-gate 
1927*0Sstevel@tonic-gate 	/* allocate stripe unit */
1928*0Sstevel@tonic-gate 	mdsize = sizeof (*ms) - sizeof (ms->un_row[0]);
1929*0Sstevel@tonic-gate 	mdsize += sizeof (ms->un_row) * nrow;
1930*0Sstevel@tonic-gate 	for (row = 0; (row < nrow); ++row) {
1931*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1932*0Sstevel@tonic-gate 
1933*0Sstevel@tonic-gate 		ncomp += rp->comps.comps_len;
1934*0Sstevel@tonic-gate 	}
1935*0Sstevel@tonic-gate 	first_comp = roundup(mdsize, sizeof (long long));
1936*0Sstevel@tonic-gate 	mdsize += (first_comp - mdsize) + (ncomp * sizeof (ms_comp_t));
1937*0Sstevel@tonic-gate 	ms = Zalloc(mdsize);
1938*0Sstevel@tonic-gate 	ms->un_ocomp = first_comp;
1939*0Sstevel@tonic-gate 	if (meta_gettimeofday(&creation_time) == -1)
1940*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
1941*0Sstevel@tonic-gate 
1942*0Sstevel@tonic-gate 	/* do rows */
1943*0Sstevel@tonic-gate 	mdcomp = (ms_comp_t *)(void *)&((char *)ms)[ms->un_ocomp];
1944*0Sstevel@tonic-gate 	for (row = 0; (row < nrow); ++row) {
1945*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
1946*0Sstevel@tonic-gate 		uint_t		ncomp = rp->comps.comps_len;
1947*0Sstevel@tonic-gate 		struct ms_row	*mdr = &ms->un_row[row];
1948*0Sstevel@tonic-gate 		diskaddr_t	disk_size = 0;
1949*0Sstevel@tonic-gate 		uint_t		comp;
1950*0Sstevel@tonic-gate 
1951*0Sstevel@tonic-gate 		/* setup component count and offfset */
1952*0Sstevel@tonic-gate 		mdr->un_icomp = icomp;
1953*0Sstevel@tonic-gate 		mdr->un_ncomp = ncomp;
1954*0Sstevel@tonic-gate 
1955*0Sstevel@tonic-gate 		/* do components */
1956*0Sstevel@tonic-gate 		for (comp = 0; (comp < ncomp); ++comp) {
1957*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
1958*0Sstevel@tonic-gate 			mdname_t	*compnp = cp->compnamep;
1959*0Sstevel@tonic-gate 			ms_comp_t	*mdc = &mdcomp[icomp++];
1960*0Sstevel@tonic-gate 			diskaddr_t	size, start_blk;
1961*0Sstevel@tonic-gate 
1962*0Sstevel@tonic-gate 			/*
1963*0Sstevel@tonic-gate 			 * get start and size
1964*0Sstevel@tonic-gate 			 * if first component is labelled, include label
1965*0Sstevel@tonic-gate 			 */
1966*0Sstevel@tonic-gate 			if ((size = metagetsize(compnp, ep)) ==
1967*0Sstevel@tonic-gate 			    MD_DISKADDR_ERROR)
1968*0Sstevel@tonic-gate 				goto out;
1969*0Sstevel@tonic-gate 			if ((start_blk = metagetstart(sp, compnp, ep)) ==
1970*0Sstevel@tonic-gate 			    MD_DISKADDR_ERROR)
1971*0Sstevel@tonic-gate 				goto out;
1972*0Sstevel@tonic-gate 			if ((row == 0) && (comp == 0)) {
1973*0Sstevel@tonic-gate 				diskaddr_t	label;
1974*0Sstevel@tonic-gate 				int		has_db;
1975*0Sstevel@tonic-gate 
1976*0Sstevel@tonic-gate 				if ((has_db = metahasmddb(sp, compnp, ep)) < 0)
1977*0Sstevel@tonic-gate 					goto out;
1978*0Sstevel@tonic-gate 				if ((label = metagetlabel(compnp, ep)) ==
1979*0Sstevel@tonic-gate 				    MD_DISKADDR_ERROR)
1980*0Sstevel@tonic-gate 					goto out;
1981*0Sstevel@tonic-gate 				if ((has_db == 0) && (label != 0)) {
1982*0Sstevel@tonic-gate 					ms->c.un_flag |= MD_LABELED;
1983*0Sstevel@tonic-gate 					start_blk = compnp->start_blk = 0;
1984*0Sstevel@tonic-gate 				}
1985*0Sstevel@tonic-gate 			}
1986*0Sstevel@tonic-gate 			/* make sure we still have something left */
1987*0Sstevel@tonic-gate 			if (start_blk >= size) {
1988*0Sstevel@tonic-gate 				(void) mdsyserror(ep, ENOSPC, compnp->cname);
1989*0Sstevel@tonic-gate 				goto out;
1990*0Sstevel@tonic-gate 			}
1991*0Sstevel@tonic-gate 			size -= start_blk;
1992*0Sstevel@tonic-gate 
1993*0Sstevel@tonic-gate 			/*
1994*0Sstevel@tonic-gate 			 * round down by interlace: this only applies
1995*0Sstevel@tonic-gate 			 * if this row is a stripe, as indicated by
1996*0Sstevel@tonic-gate 			 * (ncomp > 1)
1997*0Sstevel@tonic-gate 			 */
1998*0Sstevel@tonic-gate 			if (ncomp > 1)
1999*0Sstevel@tonic-gate 				size = rounddown(size, rp->interlace);
2000*0Sstevel@tonic-gate 
2001*0Sstevel@tonic-gate 			if (size == 0) {
2002*0Sstevel@tonic-gate 				(void) mdsyserror(ep, ENOSPC, compnp->cname);
2003*0Sstevel@tonic-gate 				goto out;
2004*0Sstevel@tonic-gate 			}
2005*0Sstevel@tonic-gate 
2006*0Sstevel@tonic-gate 			/*
2007*0Sstevel@tonic-gate 			 * adjust for smallest disk: for a concat (any
2008*0Sstevel@tonic-gate 			 * row with only one component), this will
2009*0Sstevel@tonic-gate 			 * never hit the second conditional.
2010*0Sstevel@tonic-gate 			 */
2011*0Sstevel@tonic-gate 			if (disk_size == 0) {
2012*0Sstevel@tonic-gate 				disk_size = size;
2013*0Sstevel@tonic-gate 			} else if (size < disk_size) {
2014*0Sstevel@tonic-gate 				disk_size = size;
2015*0Sstevel@tonic-gate 			}
2016*0Sstevel@tonic-gate 
2017*0Sstevel@tonic-gate 			if (options & MDCMD_DOIT) {
2018*0Sstevel@tonic-gate 				/* store name in namespace */
2019*0Sstevel@tonic-gate 				if (add_key_name(sp, compnp, &keynlp, ep) != 0)
2020*0Sstevel@tonic-gate 					goto out;
2021*0Sstevel@tonic-gate 			}
2022*0Sstevel@tonic-gate 
2023*0Sstevel@tonic-gate 			/* setup component */
2024*0Sstevel@tonic-gate 			mdc->un_key = compnp->key;
2025*0Sstevel@tonic-gate 			mdc->un_dev = compnp->dev;
2026*0Sstevel@tonic-gate 			mdc->un_start_block = start_blk;
2027*0Sstevel@tonic-gate 			mdc->un_mirror.ms_state = CS_OKAY;
2028*0Sstevel@tonic-gate 			mdc->un_mirror.ms_timestamp = creation_time;
2029*0Sstevel@tonic-gate 		}
2030*0Sstevel@tonic-gate 		limit = LLONG_MAX;
2031*0Sstevel@tonic-gate 
2032*0Sstevel@tonic-gate 		/* setup row */
2033*0Sstevel@tonic-gate 		mdr->un_blocks = mdr->un_ncomp * disk_size;
2034*0Sstevel@tonic-gate 		cum_blocks += mdr->un_blocks;
2035*0Sstevel@tonic-gate 		if (cum_blocks > limit) {
2036*0Sstevel@tonic-gate 			cum_blocks = limit;
2037*0Sstevel@tonic-gate 			md_eprintf(dgettext(TEXT_DOMAIN,
2038*0Sstevel@tonic-gate 			    "unit size overflow, limit is %lld blocks\n"),
2039*0Sstevel@tonic-gate 			    limit);
2040*0Sstevel@tonic-gate 		}
2041*0Sstevel@tonic-gate 		mdr->un_cum_blocks = cum_blocks;
2042*0Sstevel@tonic-gate 		mdr->un_interlace = rp->interlace;
2043*0Sstevel@tonic-gate 	}
2044*0Sstevel@tonic-gate 
2045*0Sstevel@tonic-gate 	/* setup unit */
2046*0Sstevel@tonic-gate 	ms->c.un_type = MD_DEVICE;
2047*0Sstevel@tonic-gate 	MD_SID(ms) = meta_getminor(stripenp->dev);
2048*0Sstevel@tonic-gate 	ms->c.un_actual_tb = cum_blocks;
2049*0Sstevel@tonic-gate 	ms->c.un_size = mdsize;
2050*0Sstevel@tonic-gate 	if (stripep->hspnamep != NULL)
2051*0Sstevel@tonic-gate 		ms->un_hsp_id = stripep->hspnamep->hsp;
2052*0Sstevel@tonic-gate 	else
2053*0Sstevel@tonic-gate 		ms->un_hsp_id = MD_HSP_NONE;
2054*0Sstevel@tonic-gate 	ms->un_nrows = nrow;
2055*0Sstevel@tonic-gate 
2056*0Sstevel@tonic-gate 	/* fill in the size of the stripe */
2057*0Sstevel@tonic-gate 	if (options & MDCMD_UPDATE) {
2058*0Sstevel@tonic-gate 		stripep->common.size = ms->c.un_total_blocks;
2059*0Sstevel@tonic-gate 		for (row = 0; (row < nrow); ++row) {
2060*0Sstevel@tonic-gate 			stripep->rows.rows_val[row].row_size =
2061*0Sstevel@tonic-gate 			    ms->un_row[row].un_blocks;
2062*0Sstevel@tonic-gate 		}
2063*0Sstevel@tonic-gate 	}
2064*0Sstevel@tonic-gate 
2065*0Sstevel@tonic-gate 	if (stripe_geom(stripep, ms, ep) != 0) {
2066*0Sstevel@tonic-gate 		/*
2067*0Sstevel@tonic-gate 		 * If the device is being truncated then only allow this
2068*0Sstevel@tonic-gate 		 * if the user is aware (using the -f option) or they
2069*0Sstevel@tonic-gate 		 * are in a recovery/complete build situation (using the -a
2070*0Sstevel@tonic-gate 		 * option).
2071*0Sstevel@tonic-gate 		 */
2072*0Sstevel@tonic-gate 		if ((mdiserror(ep, MDE_STRIPE_TRUNC_SINGLE) ||
2073*0Sstevel@tonic-gate 		    mdiserror(ep, MDE_STRIPE_TRUNC_MULTIPLE)) &&
2074*0Sstevel@tonic-gate 		    (force || doall)) {
2075*0Sstevel@tonic-gate 			md_eprintf(dgettext(TEXT_DOMAIN,
2076*0Sstevel@tonic-gate "%s: WARNING: This form of metainit is not recommended.\n"
2077*0Sstevel@tonic-gate "The stripe is truncating the size of the underlying device.\n"
2078*0Sstevel@tonic-gate "Please see ERRORS in metainit(1M) for additional information.\n"),
2079*0Sstevel@tonic-gate 			    stripenp->cname);
2080*0Sstevel@tonic-gate 			mdclrerror(ep);
2081*0Sstevel@tonic-gate 		} else {
2082*0Sstevel@tonic-gate 			goto out;
2083*0Sstevel@tonic-gate 		}
2084*0Sstevel@tonic-gate 	}
2085*0Sstevel@tonic-gate 
2086*0Sstevel@tonic-gate 	create_flag = meta_check_devicesize(ms->c.un_total_blocks);
2087*0Sstevel@tonic-gate 
2088*0Sstevel@tonic-gate 	/* if we're not doing anything, return success */
2089*0Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT)) {
2090*0Sstevel@tonic-gate 		rval = 0;	/* success */
2091*0Sstevel@tonic-gate 		goto out;
2092*0Sstevel@tonic-gate 	}
2093*0Sstevel@tonic-gate 
2094*0Sstevel@tonic-gate 	/* create stripe */
2095*0Sstevel@tonic-gate 	(void) memset(&set_params, 0, sizeof (set_params));
2096*0Sstevel@tonic-gate 
2097*0Sstevel@tonic-gate 	/* did the user tell us to generate a large device? */
2098*0Sstevel@tonic-gate 	if (create_flag == MD_CRO_64BIT) {
2099*0Sstevel@tonic-gate 		ms->c.un_revision = MD_64BIT_META_DEV;
2100*0Sstevel@tonic-gate 		set_params.options = MD_CRO_64BIT;
2101*0Sstevel@tonic-gate 	} else {
2102*0Sstevel@tonic-gate 		ms->c.un_revision = MD_32BIT_META_DEV;
2103*0Sstevel@tonic-gate 		set_params.options = MD_CRO_32BIT;
2104*0Sstevel@tonic-gate 	}
2105*0Sstevel@tonic-gate 
2106*0Sstevel@tonic-gate 	set_params.mnum = MD_SID(ms);
2107*0Sstevel@tonic-gate 	set_params.size = ms->c.un_size;
2108*0Sstevel@tonic-gate 	set_params.mdp = (uintptr_t)ms;
2109*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&set_params, MD_STRIPE, MD_MIN2SET(set_params.mnum));
2110*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
2111*0Sstevel@tonic-gate 	    stripenp->cname) != 0) {
2112*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &set_params.mde);
2113*0Sstevel@tonic-gate 		goto out;
2114*0Sstevel@tonic-gate 	}
2115*0Sstevel@tonic-gate 	rval = 0;	/* success */
2116*0Sstevel@tonic-gate 
2117*0Sstevel@tonic-gate 	/* cleanup, return success */
2118*0Sstevel@tonic-gate out:
2119*0Sstevel@tonic-gate 	Free(ms);
2120*0Sstevel@tonic-gate 	if (rval != 0) {
2121*0Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
2122*0Sstevel@tonic-gate 	}
2123*0Sstevel@tonic-gate 
2124*0Sstevel@tonic-gate 	metafreenamelist(keynlp);
2125*0Sstevel@tonic-gate 	if ((rval == 0) && (options & MDCMD_DOIT)) {
2126*0Sstevel@tonic-gate 		if (invalidate_components(sp, stripenp, ep) != 0)
2127*0Sstevel@tonic-gate 			rval = -1;
2128*0Sstevel@tonic-gate 		meta_invalidate_name(stripenp);
2129*0Sstevel@tonic-gate 	}
2130*0Sstevel@tonic-gate 	return (rval);
2131*0Sstevel@tonic-gate }
2132*0Sstevel@tonic-gate 
2133*0Sstevel@tonic-gate /*
2134*0Sstevel@tonic-gate  * initialize stripe
2135*0Sstevel@tonic-gate  * NOTE: this functions is metainit(1m)'s command line parser!
2136*0Sstevel@tonic-gate  */
2137*0Sstevel@tonic-gate int
2138*0Sstevel@tonic-gate meta_init_stripe(
2139*0Sstevel@tonic-gate 	mdsetname_t	**spp,
2140*0Sstevel@tonic-gate 	int		argc,
2141*0Sstevel@tonic-gate 	char		*argv[],
2142*0Sstevel@tonic-gate 	mdcmdopts_t	options,
2143*0Sstevel@tonic-gate 	md_error_t	*ep
2144*0Sstevel@tonic-gate )
2145*0Sstevel@tonic-gate {
2146*0Sstevel@tonic-gate 	char		*uname = argv[0];
2147*0Sstevel@tonic-gate 	mdname_t	*stripenp = NULL;
2148*0Sstevel@tonic-gate 	int		old_optind;
2149*0Sstevel@tonic-gate 	int		c;
2150*0Sstevel@tonic-gate 	md_stripe_t	*stripep = NULL;
2151*0Sstevel@tonic-gate 	uint_t		nrow, row;
2152*0Sstevel@tonic-gate 	int		rval = -1;
2153*0Sstevel@tonic-gate 
2154*0Sstevel@tonic-gate 	/* get stripe name */
2155*0Sstevel@tonic-gate 	assert(argc > 0);
2156*0Sstevel@tonic-gate 	if (argc < 1)
2157*0Sstevel@tonic-gate 		goto syntax;
2158*0Sstevel@tonic-gate 
2159*0Sstevel@tonic-gate 	if ((stripenp = metaname(spp, uname, ep)) == NULL)
2160*0Sstevel@tonic-gate 		goto out;
2161*0Sstevel@tonic-gate 	assert(*spp != NULL);
2162*0Sstevel@tonic-gate 	uname = stripenp->cname;
2163*0Sstevel@tonic-gate 	if (metachkmeta(stripenp, ep) != 0)
2164*0Sstevel@tonic-gate 		goto out;
2165*0Sstevel@tonic-gate 
2166*0Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
2167*0Sstevel@tonic-gate 		/* grab set lock */
2168*0Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep))
2169*0Sstevel@tonic-gate 			goto out;
2170*0Sstevel@tonic-gate 
2171*0Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
2172*0Sstevel@tonic-gate 			goto out;
2173*0Sstevel@tonic-gate 	}
2174*0Sstevel@tonic-gate 
2175*0Sstevel@tonic-gate 	/* see if it exists already */
2176*0Sstevel@tonic-gate 	if (metagetmiscname(stripenp, ep) != NULL) {
2177*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
2178*0Sstevel@tonic-gate 		    meta_getminor(stripenp->dev), uname);
2179*0Sstevel@tonic-gate 		goto out;
2180*0Sstevel@tonic-gate 	} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
2181*0Sstevel@tonic-gate 		goto out;
2182*0Sstevel@tonic-gate 	} else {
2183*0Sstevel@tonic-gate 		mdclrerror(ep);
2184*0Sstevel@tonic-gate 	}
2185*0Sstevel@tonic-gate 	--argc, ++argv;
2186*0Sstevel@tonic-gate 
2187*0Sstevel@tonic-gate 	/* parse general options */
2188*0Sstevel@tonic-gate 	optind = 0;
2189*0Sstevel@tonic-gate 	opterr = 0;
2190*0Sstevel@tonic-gate 	if (getopt(argc, argv, "") != -1)
2191*0Sstevel@tonic-gate 		goto options;
2192*0Sstevel@tonic-gate 
2193*0Sstevel@tonic-gate 	/* allocate stripe */
2194*0Sstevel@tonic-gate 	stripep = Zalloc(sizeof (*stripep));
2195*0Sstevel@tonic-gate 
2196*0Sstevel@tonic-gate 	/* setup common */
2197*0Sstevel@tonic-gate 	stripep->common.namep = stripenp;
2198*0Sstevel@tonic-gate 	stripep->common.type = MD_DEVICE;
2199*0Sstevel@tonic-gate 
2200*0Sstevel@tonic-gate 	/* allocate and parse rows */
2201*0Sstevel@tonic-gate 	if (argc < 1) {
2202*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NROWS, meta_getminor(stripenp->dev),
2203*0Sstevel@tonic-gate 				uname);
2204*0Sstevel@tonic-gate 		goto out;
2205*0Sstevel@tonic-gate 	} else if ((sscanf(argv[0], "%u", &nrow) != 1) || ((int)nrow < 0)) {
2206*0Sstevel@tonic-gate 		goto syntax;
2207*0Sstevel@tonic-gate 	} else if (nrow < 1) {
2208*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NROWS, meta_getminor(stripenp->dev),
2209*0Sstevel@tonic-gate 				uname);
2210*0Sstevel@tonic-gate 		goto out;
2211*0Sstevel@tonic-gate 	}
2212*0Sstevel@tonic-gate 	--argc, ++argv;
2213*0Sstevel@tonic-gate 	stripep->rows.rows_len = nrow;
2214*0Sstevel@tonic-gate 	stripep->rows.rows_val =
2215*0Sstevel@tonic-gate 	    Zalloc(nrow * sizeof (*stripep->rows.rows_val));
2216*0Sstevel@tonic-gate 	for (row = 0; (row < nrow); ++row) {
2217*0Sstevel@tonic-gate 		md_row_t	*mdr = &stripep->rows.rows_val[row];
2218*0Sstevel@tonic-gate 		uint_t		ncomp, comp;
2219*0Sstevel@tonic-gate 
2220*0Sstevel@tonic-gate 		/* allocate and parse components */
2221*0Sstevel@tonic-gate 		if (argc < 1) {
2222*0Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_NROWS,
2223*0Sstevel@tonic-gate 					meta_getminor(stripenp->dev), uname);
2224*0Sstevel@tonic-gate 			goto out;
2225*0Sstevel@tonic-gate 		} else if ((sscanf(argv[0], "%u", &ncomp) != 1) ||
2226*0Sstevel@tonic-gate 		    ((int)ncomp < 0)) {
2227*0Sstevel@tonic-gate 			goto syntax;
2228*0Sstevel@tonic-gate 		} else if (ncomp < 1) {
2229*0Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_NCOMPS,
2230*0Sstevel@tonic-gate 					meta_getminor(stripenp->dev), uname);
2231*0Sstevel@tonic-gate 			goto out;
2232*0Sstevel@tonic-gate 		}
2233*0Sstevel@tonic-gate 		--argc, ++argv;
2234*0Sstevel@tonic-gate 		mdr->comps.comps_len = ncomp;
2235*0Sstevel@tonic-gate 		mdr->comps.comps_val =
2236*0Sstevel@tonic-gate 		    Zalloc(ncomp * sizeof (*mdr->comps.comps_val));
2237*0Sstevel@tonic-gate 		for (comp = 0; (comp < ncomp); ++comp) {
2238*0Sstevel@tonic-gate 			md_comp_t	*mdc = &mdr->comps.comps_val[comp];
2239*0Sstevel@tonic-gate 			mdname_t	*compnp;
2240*0Sstevel@tonic-gate 
2241*0Sstevel@tonic-gate 			/* parse component name */
2242*0Sstevel@tonic-gate 			if (argc < 1) {
2243*0Sstevel@tonic-gate 				(void) mdmderror(ep, MDE_NCOMPS,
2244*0Sstevel@tonic-gate 				    meta_getminor(stripenp->dev), uname);
2245*0Sstevel@tonic-gate 				goto out;
2246*0Sstevel@tonic-gate 			}
2247*0Sstevel@tonic-gate 			if ((compnp = metaname(spp, argv[0], ep)) == NULL) {
2248*0Sstevel@tonic-gate 				goto out;
2249*0Sstevel@tonic-gate 			}
2250*0Sstevel@tonic-gate 			/* check for soft partition */
2251*0Sstevel@tonic-gate 			if (meta_sp_issp(*spp, compnp, ep) != 0) {
2252*0Sstevel@tonic-gate 				/* check disk */
2253*0Sstevel@tonic-gate 				if (metachkcomp(compnp, ep) != 0) {
2254*0Sstevel@tonic-gate 					goto out;
2255*0Sstevel@tonic-gate 				}
2256*0Sstevel@tonic-gate 			}
2257*0Sstevel@tonic-gate 			mdc->compnamep = compnp;
2258*0Sstevel@tonic-gate 			--argc, ++argv;
2259*0Sstevel@tonic-gate 		}
2260*0Sstevel@tonic-gate 
2261*0Sstevel@tonic-gate 		/* parse row options */
2262*0Sstevel@tonic-gate 		old_optind = optind = 0;
2263*0Sstevel@tonic-gate 		opterr = 0;
2264*0Sstevel@tonic-gate 		while ((c = getopt(argc, argv, "i:")) != -1) {
2265*0Sstevel@tonic-gate 			switch (c) {
2266*0Sstevel@tonic-gate 			case 'i':
2267*0Sstevel@tonic-gate 				if (parse_interlace(uname, optarg,
2268*0Sstevel@tonic-gate 				    &mdr->interlace, ep) != 0) {
2269*0Sstevel@tonic-gate 					goto out;
2270*0Sstevel@tonic-gate 				}
2271*0Sstevel@tonic-gate 				if (meta_stripe_check_interlace(mdr->interlace,
2272*0Sstevel@tonic-gate 					uname, ep))
2273*0Sstevel@tonic-gate 					goto out;
2274*0Sstevel@tonic-gate 				break;
2275*0Sstevel@tonic-gate 
2276*0Sstevel@tonic-gate 			default:
2277*0Sstevel@tonic-gate 				optind = old_optind;	/* bomb out later */
2278*0Sstevel@tonic-gate 				goto done_row_opts;
2279*0Sstevel@tonic-gate 			}
2280*0Sstevel@tonic-gate 			old_optind = optind;
2281*0Sstevel@tonic-gate 		}
2282*0Sstevel@tonic-gate done_row_opts:
2283*0Sstevel@tonic-gate 		argc -= optind;
2284*0Sstevel@tonic-gate 		argv += optind;
2285*0Sstevel@tonic-gate 	}
2286*0Sstevel@tonic-gate 
2287*0Sstevel@tonic-gate 	/* parse stripe options */
2288*0Sstevel@tonic-gate 	old_optind = optind = 0;
2289*0Sstevel@tonic-gate 	opterr = 0;
2290*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "h:")) != -1) {
2291*0Sstevel@tonic-gate 		switch (c) {
2292*0Sstevel@tonic-gate 		case 'h':
2293*0Sstevel@tonic-gate 			if ((stripep->hspnamep = metahspname(spp, optarg,
2294*0Sstevel@tonic-gate 			    ep)) == NULL) {
2295*0Sstevel@tonic-gate 				goto out;
2296*0Sstevel@tonic-gate 			}
2297*0Sstevel@tonic-gate 			break;
2298*0Sstevel@tonic-gate 
2299*0Sstevel@tonic-gate 		default:
2300*0Sstevel@tonic-gate 			argc += old_optind;
2301*0Sstevel@tonic-gate 			argv += old_optind;
2302*0Sstevel@tonic-gate 			goto options;
2303*0Sstevel@tonic-gate 		}
2304*0Sstevel@tonic-gate 		old_optind = optind;
2305*0Sstevel@tonic-gate 	}
2306*0Sstevel@tonic-gate 	argc -= optind;
2307*0Sstevel@tonic-gate 	argv += optind;
2308*0Sstevel@tonic-gate 
2309*0Sstevel@tonic-gate 	/* we should be at the end */
2310*0Sstevel@tonic-gate 	if (argc != 0)
2311*0Sstevel@tonic-gate 		goto syntax;
2312*0Sstevel@tonic-gate 
2313*0Sstevel@tonic-gate 	/* create stripe */
2314*0Sstevel@tonic-gate 	if (meta_create_stripe(*spp, stripep, options, ep) != 0)
2315*0Sstevel@tonic-gate 		goto out;
2316*0Sstevel@tonic-gate 	rval = 0;	/* success */
2317*0Sstevel@tonic-gate 
2318*0Sstevel@tonic-gate 	/* let em know */
2319*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
2320*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
2321*0Sstevel@tonic-gate 		    "%s: Concat/Stripe is setup\n"),
2322*0Sstevel@tonic-gate 		    uname);
2323*0Sstevel@tonic-gate 		(void) fflush(stdout);
2324*0Sstevel@tonic-gate 	}
2325*0Sstevel@tonic-gate 	goto out;
2326*0Sstevel@tonic-gate 
2327*0Sstevel@tonic-gate 	/* syntax error */
2328*0Sstevel@tonic-gate syntax:
2329*0Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
2330*0Sstevel@tonic-gate 	goto out;
2331*0Sstevel@tonic-gate 
2332*0Sstevel@tonic-gate 	/* options error */
2333*0Sstevel@tonic-gate options:
2334*0Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
2335*0Sstevel@tonic-gate 	goto out;
2336*0Sstevel@tonic-gate 
2337*0Sstevel@tonic-gate 	/* cleanup, return error */
2338*0Sstevel@tonic-gate out:
2339*0Sstevel@tonic-gate 	if (stripep != NULL)
2340*0Sstevel@tonic-gate 		meta_free_stripe(stripep);
2341*0Sstevel@tonic-gate 	return (rval);
2342*0Sstevel@tonic-gate }
2343*0Sstevel@tonic-gate 
2344*0Sstevel@tonic-gate /*
2345*0Sstevel@tonic-gate  * reset stripes
2346*0Sstevel@tonic-gate  */
2347*0Sstevel@tonic-gate int
2348*0Sstevel@tonic-gate meta_stripe_reset(
2349*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2350*0Sstevel@tonic-gate 	mdname_t	*stripenp,
2351*0Sstevel@tonic-gate 	mdcmdopts_t	options,
2352*0Sstevel@tonic-gate 	md_error_t	*ep
2353*0Sstevel@tonic-gate )
2354*0Sstevel@tonic-gate {
2355*0Sstevel@tonic-gate 	md_stripe_t	*stripep;
2356*0Sstevel@tonic-gate 	int		rval = -1;
2357*0Sstevel@tonic-gate 	int		row, comp;
2358*0Sstevel@tonic-gate 
2359*0Sstevel@tonic-gate 	/* should have same set */
2360*0Sstevel@tonic-gate 	assert(sp != NULL);
2361*0Sstevel@tonic-gate 	assert((stripenp == NULL) ||
2362*0Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev))));
2363*0Sstevel@tonic-gate 
2364*0Sstevel@tonic-gate 	/* reset all stripes */
2365*0Sstevel@tonic-gate 	if (stripenp == NULL) {
2366*0Sstevel@tonic-gate 		mdnamelist_t	*stripenlp = NULL;
2367*0Sstevel@tonic-gate 		mdnamelist_t	*p;
2368*0Sstevel@tonic-gate 
2369*0Sstevel@tonic-gate 		/* for each stripe */
2370*0Sstevel@tonic-gate 		rval = 0;
2371*0Sstevel@tonic-gate 		if (meta_get_stripe_names(sp, &stripenlp, 0, ep) < 0)
2372*0Sstevel@tonic-gate 			return (-1);
2373*0Sstevel@tonic-gate 		for (p = stripenlp; (p != NULL); p = p->next) {
2374*0Sstevel@tonic-gate 			/* reset stripe */
2375*0Sstevel@tonic-gate 			stripenp = p->namep;
2376*0Sstevel@tonic-gate 
2377*0Sstevel@tonic-gate 			/*
2378*0Sstevel@tonic-gate 			 * If this is a multi-node set, we send a series
2379*0Sstevel@tonic-gate 			 * of individual metaclear commands.
2380*0Sstevel@tonic-gate 			 */
2381*0Sstevel@tonic-gate 			if (meta_is_mn_set(sp, ep)) {
2382*0Sstevel@tonic-gate 				if (meta_mn_send_metaclear_command(sp,
2383*0Sstevel@tonic-gate 				    stripenp->cname, options, 0, ep) != 0) {
2384*0Sstevel@tonic-gate 					rval = -1;
2385*0Sstevel@tonic-gate 					break;
2386*0Sstevel@tonic-gate 				}
2387*0Sstevel@tonic-gate 			} else {
2388*0Sstevel@tonic-gate 				if (meta_stripe_reset(sp, stripenp,
2389*0Sstevel@tonic-gate 				    options, ep) != 0) {
2390*0Sstevel@tonic-gate 					rval = -1;
2391*0Sstevel@tonic-gate 					break;
2392*0Sstevel@tonic-gate 				}
2393*0Sstevel@tonic-gate 			}
2394*0Sstevel@tonic-gate 		}
2395*0Sstevel@tonic-gate 
2396*0Sstevel@tonic-gate 		/* cleanup, return success */
2397*0Sstevel@tonic-gate 		metafreenamelist(stripenlp);
2398*0Sstevel@tonic-gate 		return (rval);
2399*0Sstevel@tonic-gate 	}
2400*0Sstevel@tonic-gate 
2401*0Sstevel@tonic-gate 	/* check name */
2402*0Sstevel@tonic-gate 	if (metachkmeta(stripenp, ep) != 0)
2403*0Sstevel@tonic-gate 		return (-1);
2404*0Sstevel@tonic-gate 
2405*0Sstevel@tonic-gate 	/* get unit structure */
2406*0Sstevel@tonic-gate 	if ((stripep = meta_get_stripe(sp, stripenp, ep)) == NULL)
2407*0Sstevel@tonic-gate 		return (-1);
2408*0Sstevel@tonic-gate 
2409*0Sstevel@tonic-gate 	/* make sure nobody owns us */
2410*0Sstevel@tonic-gate 	if (MD_HAS_PARENT(stripep->common.parent)) {
2411*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(stripenp->dev),
2412*0Sstevel@tonic-gate 		    stripenp->cname));
2413*0Sstevel@tonic-gate 	}
2414*0Sstevel@tonic-gate 
2415*0Sstevel@tonic-gate 	/* clear subdevices cache */
2416*0Sstevel@tonic-gate 	if (invalidate_components(sp, stripenp, ep) != 0)
2417*0Sstevel@tonic-gate 		return (-1);
2418*0Sstevel@tonic-gate 
2419*0Sstevel@tonic-gate 	/* clear metadevice */
2420*0Sstevel@tonic-gate 	if (meta_reset(sp, stripenp, options, ep) != 0)
2421*0Sstevel@tonic-gate 		goto out;
2422*0Sstevel@tonic-gate 	rval = 0;	/* success */
2423*0Sstevel@tonic-gate 
2424*0Sstevel@tonic-gate 	/* let em know */
2425*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
2426*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
2427*0Sstevel@tonic-gate 		    "%s: Concat/Stripe is cleared\n"),
2428*0Sstevel@tonic-gate 		    stripenp->cname);
2429*0Sstevel@tonic-gate 		(void) fflush(stdout);
2430*0Sstevel@tonic-gate 	}
2431*0Sstevel@tonic-gate 
2432*0Sstevel@tonic-gate 	/* clear subdevices */
2433*0Sstevel@tonic-gate 	if (! (options & MDCMD_RECURSE))
2434*0Sstevel@tonic-gate 		goto out;
2435*0Sstevel@tonic-gate 
2436*0Sstevel@tonic-gate 	for (row = 0; (row < stripep->rows.rows_len); ++row) {
2437*0Sstevel@tonic-gate 		md_row_t	*rp = &stripep->rows.rows_val[row];
2438*0Sstevel@tonic-gate 		for (comp = 0; (comp < rp->comps.comps_len); ++comp) {
2439*0Sstevel@tonic-gate 			md_comp_t	*cp = &rp->comps.comps_val[comp];
2440*0Sstevel@tonic-gate 			mdname_t	*compnp = cp->compnamep;
2441*0Sstevel@tonic-gate 
2442*0Sstevel@tonic-gate 			/* only recurse on metadevices */
2443*0Sstevel@tonic-gate 			if (! metaismeta(compnp))
2444*0Sstevel@tonic-gate 				continue;
2445*0Sstevel@tonic-gate 
2446*0Sstevel@tonic-gate 			if (meta_reset_by_name(sp, compnp, options, ep) != 0)
2447*0Sstevel@tonic-gate 				rval = -1;
2448*0Sstevel@tonic-gate 		}
2449*0Sstevel@tonic-gate 	}
2450*0Sstevel@tonic-gate 
2451*0Sstevel@tonic-gate 	/* cleanup, return success */
2452*0Sstevel@tonic-gate out:
2453*0Sstevel@tonic-gate 	meta_invalidate_name(stripenp);
2454*0Sstevel@tonic-gate 	return (rval);
2455*0Sstevel@tonic-gate }
2456*0Sstevel@tonic-gate 
2457*0Sstevel@tonic-gate /*
2458*0Sstevel@tonic-gate  * reports TRUE if any stripe component is in error
2459*0Sstevel@tonic-gate  */
2460*0Sstevel@tonic-gate int
2461*0Sstevel@tonic-gate meta_stripe_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *stripe_names)
2462*0Sstevel@tonic-gate {
2463*0Sstevel@tonic-gate 	mdnamelist_t	*nlp;
2464*0Sstevel@tonic-gate 	md_error_t	  status	= mdnullerror;
2465*0Sstevel@tonic-gate 	md_error_t	 *ep		= &status;
2466*0Sstevel@tonic-gate 	int		  any_errs	= FALSE;
2467*0Sstevel@tonic-gate 
2468*0Sstevel@tonic-gate 	for (nlp = stripe_names; nlp; nlp = nlp->next) {
2469*0Sstevel@tonic-gate 		md_stripe_t	*stripep;
2470*0Sstevel@tonic-gate 		int		 row;
2471*0Sstevel@tonic-gate 
2472*0Sstevel@tonic-gate 		if ((stripep = meta_get_stripe(sp, nlp->namep, ep)) == NULL) {
2473*0Sstevel@tonic-gate 			any_errs |= TRUE;
2474*0Sstevel@tonic-gate 			goto out;
2475*0Sstevel@tonic-gate 		}
2476*0Sstevel@tonic-gate 
2477*0Sstevel@tonic-gate 		for (row = 0; row < stripep->rows.rows_len; ++row) {
2478*0Sstevel@tonic-gate 			md_row_t	*rp	= &stripep->rows.rows_val[row];
2479*0Sstevel@tonic-gate 			uint_t		 comp;
2480*0Sstevel@tonic-gate 
2481*0Sstevel@tonic-gate 			for (comp = 0; comp < rp->comps.comps_len; ++comp) {
2482*0Sstevel@tonic-gate 				md_comp_t *cp	= &rp->comps.comps_val[comp];
2483*0Sstevel@tonic-gate 
2484*0Sstevel@tonic-gate 				if (cp->state != CS_OKAY) {
2485*0Sstevel@tonic-gate 					any_errs |= TRUE;
2486*0Sstevel@tonic-gate 					goto out;
2487*0Sstevel@tonic-gate 				}
2488*0Sstevel@tonic-gate 			}
2489*0Sstevel@tonic-gate 		}
2490*0Sstevel@tonic-gate 	}
2491*0Sstevel@tonic-gate out:
2492*0Sstevel@tonic-gate 	if (!mdisok(ep))
2493*0Sstevel@tonic-gate 		mdclrerror(ep);
2494*0Sstevel@tonic-gate 
2495*0Sstevel@tonic-gate 	return (any_errs);
2496*0Sstevel@tonic-gate }
2497