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  * Just in case we're not in a build environment, make sure that
30*0Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
33*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
34*0Sstevel@tonic-gate #endif
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate /*
37*0Sstevel@tonic-gate  * RAID operations
38*0Sstevel@tonic-gate  */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include <stdlib.h>
41*0Sstevel@tonic-gate #include <meta.h>
42*0Sstevel@tonic-gate #include <sys/lvm/md_raid.h>
43*0Sstevel@tonic-gate #include <sys/lvm/mdvar.h>
44*0Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
45*0Sstevel@tonic-gate #include <stddef.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate /*
48*0Sstevel@tonic-gate  * FUNCTION:    meta_get_raid_names()
49*0Sstevel@tonic-gate  * INPUT:       sp      - the set name to get raid from
50*0Sstevel@tonic-gate  *              options - options from the command line
51*0Sstevel@tonic-gate  * OUTPUT:      nlpp    - list of all raid names
52*0Sstevel@tonic-gate  *              ep      - return error pointer
53*0Sstevel@tonic-gate  * RETURNS:     int     - -1 if error, 0 success
54*0Sstevel@tonic-gate  * PURPOSE:     returns a list of all raid in the metadb
55*0Sstevel@tonic-gate  *              for all devices in the specified set
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate int
58*0Sstevel@tonic-gate meta_get_raid_names(
59*0Sstevel@tonic-gate 	mdsetname_t	*sp,
60*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
61*0Sstevel@tonic-gate 	int		options,
62*0Sstevel@tonic-gate 	md_error_t	*ep
63*0Sstevel@tonic-gate )
64*0Sstevel@tonic-gate {
65*0Sstevel@tonic-gate 	return (meta_get_names(MD_RAID, sp, nlpp, options, ep));
66*0Sstevel@tonic-gate }
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /*
69*0Sstevel@tonic-gate  * free raid unit
70*0Sstevel@tonic-gate  */
71*0Sstevel@tonic-gate void
72*0Sstevel@tonic-gate meta_free_raid(
73*0Sstevel@tonic-gate 	md_raid_t	*raidp
74*0Sstevel@tonic-gate )
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate 	if (raidp->cols.cols_val != NULL) {
77*0Sstevel@tonic-gate 		assert(raidp->cols.cols_len > 0);
78*0Sstevel@tonic-gate 		Free(raidp->cols.cols_val);
79*0Sstevel@tonic-gate 	}
80*0Sstevel@tonic-gate 	Free(raidp);
81*0Sstevel@tonic-gate }
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate /*
84*0Sstevel@tonic-gate  * get raid (common)
85*0Sstevel@tonic-gate  */
86*0Sstevel@tonic-gate md_raid_t *
87*0Sstevel@tonic-gate meta_get_raid_common(
88*0Sstevel@tonic-gate 	mdsetname_t		*sp,
89*0Sstevel@tonic-gate 	mdname_t		*raidnp,
90*0Sstevel@tonic-gate 	int			fast,
91*0Sstevel@tonic-gate 	md_error_t		*ep
92*0Sstevel@tonic-gate )
93*0Sstevel@tonic-gate {
94*0Sstevel@tonic-gate 	mddrivename_t		*dnp = raidnp->drivenamep;
95*0Sstevel@tonic-gate 	char			*miscname;
96*0Sstevel@tonic-gate 	mr_unit_t		*mr;
97*0Sstevel@tonic-gate 	md_raid_t		*raidp;
98*0Sstevel@tonic-gate 	uint_t			ncol;
99*0Sstevel@tonic-gate 	uint_t			col;
100*0Sstevel@tonic-gate 	md_resync_ioctl_t	ri;
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	/* must have set */
103*0Sstevel@tonic-gate 	assert(sp != NULL);
104*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	/* short circuit */
107*0Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
108*0Sstevel@tonic-gate 		assert(dnp->unitp->type == MD_METARAID);
109*0Sstevel@tonic-gate 		return ((md_raid_t *)dnp->unitp);
110*0Sstevel@tonic-gate 	}
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	/* get miscname and unit */
113*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(raidnp, ep)) == NULL)
114*0Sstevel@tonic-gate 		return (NULL);
115*0Sstevel@tonic-gate 	if (strcmp(miscname, MD_RAID) != 0) {
116*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NOT_RAID, meta_getminor(raidnp->dev),
117*0Sstevel@tonic-gate 		    raidnp->cname);
118*0Sstevel@tonic-gate 		return (NULL);
119*0Sstevel@tonic-gate 	}
120*0Sstevel@tonic-gate 	if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
121*0Sstevel@tonic-gate 		return (NULL);
122*0Sstevel@tonic-gate 	assert(mr->c.un_type == MD_METARAID);
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	/* allocate raid */
125*0Sstevel@tonic-gate 	raidp = Zalloc(sizeof (*raidp));
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	/* allocate columns */
128*0Sstevel@tonic-gate 	ncol = mr->un_totalcolumncnt;
129*0Sstevel@tonic-gate 	assert(ncol >= MD_RAID_MIN);
130*0Sstevel@tonic-gate 	raidp->cols.cols_len = ncol;
131*0Sstevel@tonic-gate 	raidp->cols.cols_val = Zalloc(raidp->cols.cols_len *
132*0Sstevel@tonic-gate 	    sizeof (*raidp->cols.cols_val));
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	/* get common info */
135*0Sstevel@tonic-gate 	raidp->common.namep = raidnp;
136*0Sstevel@tonic-gate 	raidp->common.type = mr->c.un_type;
137*0Sstevel@tonic-gate 	raidp->common.state = mr->c.un_status;
138*0Sstevel@tonic-gate 	raidp->common.capabilities = mr->c.un_capabilities;
139*0Sstevel@tonic-gate 	raidp->common.parent = mr->c.un_parent;
140*0Sstevel@tonic-gate 	raidp->common.size = mr->c.un_total_blocks;
141*0Sstevel@tonic-gate 	raidp->common.user_flags = mr->c.un_user_flags;
142*0Sstevel@tonic-gate 	raidp->common.revision = mr->c.un_revision;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	/* get options */
145*0Sstevel@tonic-gate 	raidp->state = mr->un_state;
146*0Sstevel@tonic-gate 	raidp->timestamp = mr->un_timestamp;
147*0Sstevel@tonic-gate 	raidp->interlace = mr->un_segsize;
148*0Sstevel@tonic-gate 	raidp->orig_ncol = mr->un_origcolumncnt;
149*0Sstevel@tonic-gate 	raidp->column_size = mr->un_segsize * mr->un_segsincolumn;
150*0Sstevel@tonic-gate 	raidp->pw_count = mr->un_pwcnt;
151*0Sstevel@tonic-gate 	assert(raidp->orig_ncol <= ncol);
152*0Sstevel@tonic-gate 	if ((mr->un_hsp_id != MD_HSP_NONE) &&
153*0Sstevel@tonic-gate 	    ((raidp->hspnamep = metahsphspname(&sp, mr->un_hsp_id,
154*0Sstevel@tonic-gate 	    ep)) == NULL)) {
155*0Sstevel@tonic-gate 		goto out;
156*0Sstevel@tonic-gate 	}
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	/* get columns, update unit state */
159*0Sstevel@tonic-gate 	for (col = 0; (col < ncol); ++col) {
160*0Sstevel@tonic-gate 		mr_column_t	*rcp = &mr->un_column[col];
161*0Sstevel@tonic-gate 		md_raidcol_t	*mdrcp = &raidp->cols.cols_val[col];
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 		/* get column name */
164*0Sstevel@tonic-gate 		mdrcp->colnamep = metakeyname(&sp, rcp->un_orig_key, fast, ep);
165*0Sstevel@tonic-gate 		if (mdrcp->colnamep == NULL)
166*0Sstevel@tonic-gate 			goto out;
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 		/* override any start_blk */
169*0Sstevel@tonic-gate #ifdef	DEBUG
170*0Sstevel@tonic-gate 		if (metagetstart(sp, mdrcp->colnamep, ep) !=
171*0Sstevel@tonic-gate 		    MD_DISKADDR_ERROR) {
172*0Sstevel@tonic-gate 			assert(mdrcp->colnamep->start_blk <=
173*0Sstevel@tonic-gate 			    rcp->un_orig_devstart);
174*0Sstevel@tonic-gate 		} else {
175*0Sstevel@tonic-gate 			mdclrerror(ep);
176*0Sstevel@tonic-gate 		}
177*0Sstevel@tonic-gate #endif	/* DEBUG */
178*0Sstevel@tonic-gate 		mdrcp->colnamep->start_blk = rcp->un_orig_devstart;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 		/* if hotspared */
181*0Sstevel@tonic-gate 		if (HOTSPARED(mr, col)) {
182*0Sstevel@tonic-gate 			/* get hotspare name */
183*0Sstevel@tonic-gate 			mdrcp->hsnamep = metakeyname(&sp, rcp->un_hs_key,
184*0Sstevel@tonic-gate 			    fast, ep);
185*0Sstevel@tonic-gate 			if (mdrcp->hsnamep == NULL)
186*0Sstevel@tonic-gate 				goto out;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 			if (getenv("META_DEBUG_START_BLK") != NULL) {
189*0Sstevel@tonic-gate 				if (metagetstart(sp, mdrcp->hsnamep, ep) ==
190*0Sstevel@tonic-gate 				    MD_DISKADDR_ERROR)
191*0Sstevel@tonic-gate 					mdclrerror(ep);
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 				if ((mdrcp->hsnamep->start_blk == 0) &&
194*0Sstevel@tonic-gate 				    (rcp->un_hs_pwstart != 0))
195*0Sstevel@tonic-gate 					md_eprintf(dgettext(TEXT_DOMAIN,
196*0Sstevel@tonic-gate 					    "%s: suspected bad start block,"
197*0Sstevel@tonic-gate 					    " seems labelled [raid]\n"),
198*0Sstevel@tonic-gate 					    mdrcp->hsnamep->cname);
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 				if ((mdrcp->hsnamep->start_blk > 0) &&
201*0Sstevel@tonic-gate 				    (rcp->un_hs_pwstart == 0))
202*0Sstevel@tonic-gate 					md_eprintf(dgettext(TEXT_DOMAIN,
203*0Sstevel@tonic-gate 					    "%s: suspected bad start block, "
204*0Sstevel@tonic-gate 					    " seems unlabelled [raid]\n"),
205*0Sstevel@tonic-gate 					    mdrcp->hsnamep->cname);
206*0Sstevel@tonic-gate 			}
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 			/* override any start_blk */
209*0Sstevel@tonic-gate 			mdrcp->hsnamep->start_blk = rcp->un_hs_devstart;
210*0Sstevel@tonic-gate 		}
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 		/* get state, flags, and timestamp */
213*0Sstevel@tonic-gate 		mdrcp->state = rcp->un_devstate;
214*0Sstevel@tonic-gate 		mdrcp->flags = rcp->un_devflags;
215*0Sstevel@tonic-gate 		mdrcp->timestamp = rcp->un_devtimestamp;
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	/* get resync info */
219*0Sstevel@tonic-gate 	(void) memset(&ri, 0, sizeof (ri));
220*0Sstevel@tonic-gate 	ri.ri_mnum = meta_getminor(raidnp->dev);
221*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&ri, MD_RAID, sp->setno);
222*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGETSYNC, &ri, &ri.mde, raidnp->cname) != 0) {
223*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &ri.mde);
224*0Sstevel@tonic-gate 		goto out;
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 	raidp->resync_flags = ri.ri_flags;
227*0Sstevel@tonic-gate 	raidp->percent_dirty = ri.ri_percent_dirty;
228*0Sstevel@tonic-gate 	raidp->percent_done = ri.ri_percent_done;
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	/* cleanup, return success */
231*0Sstevel@tonic-gate 	Free(mr);
232*0Sstevel@tonic-gate 	dnp->unitp = (md_common_t *)raidp;
233*0Sstevel@tonic-gate 	return (raidp);
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	/* cleanup, return error */
236*0Sstevel@tonic-gate out:
237*0Sstevel@tonic-gate 	Free(mr);
238*0Sstevel@tonic-gate 	meta_free_raid(raidp);
239*0Sstevel@tonic-gate 	return (NULL);
240*0Sstevel@tonic-gate }
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate /*
243*0Sstevel@tonic-gate  * get raid
244*0Sstevel@tonic-gate  */
245*0Sstevel@tonic-gate md_raid_t *
246*0Sstevel@tonic-gate meta_get_raid(
247*0Sstevel@tonic-gate 	mdsetname_t		*sp,
248*0Sstevel@tonic-gate 	mdname_t		*raidnp,
249*0Sstevel@tonic-gate 	md_error_t		*ep
250*0Sstevel@tonic-gate )
251*0Sstevel@tonic-gate {
252*0Sstevel@tonic-gate 	return (meta_get_raid_common(sp, raidnp, 0, ep));
253*0Sstevel@tonic-gate }
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate /*
256*0Sstevel@tonic-gate  * check raid for dev
257*0Sstevel@tonic-gate  */
258*0Sstevel@tonic-gate static int
259*0Sstevel@tonic-gate in_raid(
260*0Sstevel@tonic-gate 	mdsetname_t	*sp,
261*0Sstevel@tonic-gate 	mdname_t	*raidnp,
262*0Sstevel@tonic-gate 	mdname_t	*np,
263*0Sstevel@tonic-gate 	diskaddr_t	slblk,
264*0Sstevel@tonic-gate 	diskaddr_t	nblks,
265*0Sstevel@tonic-gate 	md_error_t	*ep
266*0Sstevel@tonic-gate )
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate 	md_raid_t	*raidp;
269*0Sstevel@tonic-gate 	uint_t		col;
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	/* should be in the same set */
272*0Sstevel@tonic-gate 	assert(sp != NULL);
273*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	/* get unit */
276*0Sstevel@tonic-gate 	if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
277*0Sstevel@tonic-gate 		return (-1);
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	/* look in columns */
280*0Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
281*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
282*0Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
283*0Sstevel@tonic-gate 		diskaddr_t	col_sblk;
284*0Sstevel@tonic-gate 		int		err;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 		/* check same drive since metagetstart() can fail */
287*0Sstevel@tonic-gate 		if ((err = meta_check_samedrive(np, colnp, ep)) < 0)
288*0Sstevel@tonic-gate 			return (-1);
289*0Sstevel@tonic-gate 		else if (err == 0)
290*0Sstevel@tonic-gate 			continue;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 		/* check overlap */
293*0Sstevel@tonic-gate 		if ((col_sblk = metagetstart(sp, colnp, ep)) ==
294*0Sstevel@tonic-gate 		    MD_DISKADDR_ERROR)
295*0Sstevel@tonic-gate 			return (-1);
296*0Sstevel@tonic-gate 		if (meta_check_overlap(raidnp->cname, np, slblk, nblks,
297*0Sstevel@tonic-gate 		    colnp, col_sblk, -1, ep) != 0) {
298*0Sstevel@tonic-gate 			return (-1);
299*0Sstevel@tonic-gate 		}
300*0Sstevel@tonic-gate 	}
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	/* return success */
303*0Sstevel@tonic-gate 	return (0);
304*0Sstevel@tonic-gate }
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate /*
307*0Sstevel@tonic-gate  * check to see if we're in a raid
308*0Sstevel@tonic-gate  */
309*0Sstevel@tonic-gate int
310*0Sstevel@tonic-gate meta_check_inraid(
311*0Sstevel@tonic-gate 	mdsetname_t	*sp,
312*0Sstevel@tonic-gate 	mdname_t	*np,
313*0Sstevel@tonic-gate 	diskaddr_t	slblk,
314*0Sstevel@tonic-gate 	diskaddr_t	nblks,
315*0Sstevel@tonic-gate 	md_error_t	*ep
316*0Sstevel@tonic-gate )
317*0Sstevel@tonic-gate {
318*0Sstevel@tonic-gate 	mdnamelist_t	*raidnlp = NULL;
319*0Sstevel@tonic-gate 	mdnamelist_t	*p;
320*0Sstevel@tonic-gate 	int		rval = 0;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	/* should have a set */
323*0Sstevel@tonic-gate 	assert(sp != NULL);
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	/* for each raid */
326*0Sstevel@tonic-gate 	if (meta_get_raid_names(sp, &raidnlp, 0, ep) < 0)
327*0Sstevel@tonic-gate 		return (-1);
328*0Sstevel@tonic-gate 	for (p = raidnlp; (p != NULL); p = p->next) {
329*0Sstevel@tonic-gate 		mdname_t	*raidnp = p->namep;
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 		/* check raid */
332*0Sstevel@tonic-gate 		if (in_raid(sp, raidnp, np, slblk, nblks, ep) != 0) {
333*0Sstevel@tonic-gate 			rval = -1;
334*0Sstevel@tonic-gate 			break;
335*0Sstevel@tonic-gate 		}
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	/* cleanup, return success */
339*0Sstevel@tonic-gate 	metafreenamelist(raidnlp);
340*0Sstevel@tonic-gate 	return (rval);
341*0Sstevel@tonic-gate }
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate /*
344*0Sstevel@tonic-gate  * check column
345*0Sstevel@tonic-gate  */
346*0Sstevel@tonic-gate int
347*0Sstevel@tonic-gate meta_check_column(
348*0Sstevel@tonic-gate 	mdsetname_t	*sp,
349*0Sstevel@tonic-gate 	mdname_t	*np,
350*0Sstevel@tonic-gate 	md_error_t	*ep
351*0Sstevel@tonic-gate )
352*0Sstevel@tonic-gate {
353*0Sstevel@tonic-gate 	mdchkopts_t	options = (MDCHK_ALLOW_MDDB);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	/* check for soft partitions */
356*0Sstevel@tonic-gate 	if (meta_sp_issp(sp, np, ep) != 0) {
357*0Sstevel@tonic-gate 		/* make sure we have a disk */
358*0Sstevel@tonic-gate 		if (metachkcomp(np, ep) != 0)
359*0Sstevel@tonic-gate 			return (-1);
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
363*0Sstevel@tonic-gate 	if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
364*0Sstevel@tonic-gate 		return (-1);
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	/* make sure it is in the set */
368*0Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
369*0Sstevel@tonic-gate 		return (-1);
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	/* make sure its not in a metadevice */
372*0Sstevel@tonic-gate 	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
373*0Sstevel@tonic-gate 		return (-1);
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	/* return success */
376*0Sstevel@tonic-gate 	return (0);
377*0Sstevel@tonic-gate }
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate /*
380*0Sstevel@tonic-gate  * print raid
381*0Sstevel@tonic-gate  */
382*0Sstevel@tonic-gate static int
383*0Sstevel@tonic-gate raid_print(
384*0Sstevel@tonic-gate 	md_raid_t	*raidp,
385*0Sstevel@tonic-gate 	char		*fname,
386*0Sstevel@tonic-gate 	FILE		*fp,
387*0Sstevel@tonic-gate 	mdprtopts_t	options,
388*0Sstevel@tonic-gate 	md_error_t	*ep
389*0Sstevel@tonic-gate )
390*0Sstevel@tonic-gate {
391*0Sstevel@tonic-gate 	uint_t		col;
392*0Sstevel@tonic-gate 	int		rval = -1;
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
396*0Sstevel@tonic-gate 		if (raidp->common.revision != MD_64BIT_META_DEV) {
397*0Sstevel@tonic-gate 			rval = 0;
398*0Sstevel@tonic-gate 			goto out;
399*0Sstevel@tonic-gate 		}
400*0Sstevel@tonic-gate 	}
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	/* print name and -r */
403*0Sstevel@tonic-gate 	if (fprintf(fp, "%s -r", raidp->common.namep->cname) == EOF)
404*0Sstevel@tonic-gate 		goto out;
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	/* print columns */
407*0Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
408*0Sstevel@tonic-gate 		md_raidcol_t	*mdrcp = &raidp->cols.cols_val[col];
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 		/* print column */
411*0Sstevel@tonic-gate 		/*
412*0Sstevel@tonic-gate 		 * If the path is our standard /dev/rdsk or /dev/md/rdsk
413*0Sstevel@tonic-gate 		 * then just print out the cxtxdxsx or the dx, metainit
414*0Sstevel@tonic-gate 		 * will assume the default, otherwise we need the full
415*0Sstevel@tonic-gate 		 * pathname to make sure this works as we intend.
416*0Sstevel@tonic-gate 		 */
417*0Sstevel@tonic-gate 		if ((strstr(mdrcp->colnamep->rname, "/dev/rdsk") == NULL) &&
418*0Sstevel@tonic-gate 		    (strstr(mdrcp->colnamep->rname, "/dev/md/rdsk") == NULL) &&
419*0Sstevel@tonic-gate 		    (strstr(mdrcp->colnamep->rname, "/dev/td/") == NULL)) {
420*0Sstevel@tonic-gate 			/* not standard path, print full pathname */
421*0Sstevel@tonic-gate 			if (fprintf(fp, " %s", mdrcp->colnamep->rname) == EOF)
422*0Sstevel@tonic-gate 				goto out;
423*0Sstevel@tonic-gate 		} else {
424*0Sstevel@tonic-gate 			/* standard path so print ctd or d number */
425*0Sstevel@tonic-gate 			if (fprintf(fp, " %s", mdrcp->colnamep->cname) == EOF)
426*0Sstevel@tonic-gate 				goto out;
427*0Sstevel@tonic-gate 		}
428*0Sstevel@tonic-gate 	}
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	if (fprintf(fp, " -k") == EOF)
431*0Sstevel@tonic-gate 		goto out;
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	/* print options */
434*0Sstevel@tonic-gate 	if (fprintf(fp, " -i %lldb", raidp->interlace) == EOF)
435*0Sstevel@tonic-gate 		goto out;
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	if (raidp->pw_count != PWCNT_MIN)
438*0Sstevel@tonic-gate 		if (fprintf(fp, " -w %d", raidp->pw_count) == EOF)
439*0Sstevel@tonic-gate 			goto out;
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	if (raidp->hspnamep != NULL) {
442*0Sstevel@tonic-gate 		if (fprintf(fp, " -h %s", raidp->hspnamep->hspname) == EOF)
443*0Sstevel@tonic-gate 			goto out;
444*0Sstevel@tonic-gate 	}
445*0Sstevel@tonic-gate 	if (raidp->orig_ncol != raidp->cols.cols_len) {
446*0Sstevel@tonic-gate 		assert(raidp->orig_ncol < raidp->cols.cols_len);
447*0Sstevel@tonic-gate 		if (fprintf(fp, " -o %u", raidp->orig_ncol) == EOF)
448*0Sstevel@tonic-gate 			goto out;
449*0Sstevel@tonic-gate 	}
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	/* terminate last line */
452*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
453*0Sstevel@tonic-gate 		goto out;
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	/* success */
456*0Sstevel@tonic-gate 	rval = 0;
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	/* cleanup, return error */
459*0Sstevel@tonic-gate out:
460*0Sstevel@tonic-gate 	if (rval != 0)
461*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
462*0Sstevel@tonic-gate 	return (rval);
463*0Sstevel@tonic-gate }
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate static int
466*0Sstevel@tonic-gate find_resyncing_column(
467*0Sstevel@tonic-gate 	md_raid_t *raidp
468*0Sstevel@tonic-gate )
469*0Sstevel@tonic-gate {
470*0Sstevel@tonic-gate 	int		col;
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
473*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
474*0Sstevel@tonic-gate 		if (cp->state & RCS_RESYNC)
475*0Sstevel@tonic-gate 			return (col);
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	/* No resyncing columns */
479*0Sstevel@tonic-gate 	return (-1);
480*0Sstevel@tonic-gate }
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate /*
483*0Sstevel@tonic-gate  * convert raid state to name
484*0Sstevel@tonic-gate  */
485*0Sstevel@tonic-gate char *
486*0Sstevel@tonic-gate raid_state_to_name(
487*0Sstevel@tonic-gate 	md_raid_t	*raidp,
488*0Sstevel@tonic-gate 	md_timeval32_t	*tvp,
489*0Sstevel@tonic-gate 	uint_t		tstate /* Errored tstate flags */
490*0Sstevel@tonic-gate )
491*0Sstevel@tonic-gate {
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	/* grab time */
494*0Sstevel@tonic-gate 	if (tvp != NULL)
495*0Sstevel@tonic-gate 		*tvp = raidp->timestamp;
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	/*
498*0Sstevel@tonic-gate 	 * If the device has a transient error state (due to it being DR'ed or
499*0Sstevel@tonic-gate 	 * failed) and there has been no I/O to it (the actual device is still
500*0Sstevel@tonic-gate 	 * marked as 'Okay') then we cannot know what the state is or what
501*0Sstevel@tonic-gate 	 * action to take on it. Therefore report the device as 'Unavailable'.
502*0Sstevel@tonic-gate 	 * A subsequent I/O to the device will cause the 'Okay' status to
503*0Sstevel@tonic-gate 	 * disappear if the device is actually gone and then we will print out
504*0Sstevel@tonic-gate 	 * the appropriate status.  The MD_INACCESSIBLE state is only set
505*0Sstevel@tonic-gate 	 * on the raid when we open it or probe it.  One the raid is open
506*0Sstevel@tonic-gate 	 * then we will just have regular error status on the device.
507*0Sstevel@tonic-gate 	 */
508*0Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
509*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
510*0Sstevel@tonic-gate 	}
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 	/* resyncing */
513*0Sstevel@tonic-gate 	if (find_resyncing_column(raidp) >= 0)
514*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Resyncing"));
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	/* everything else */
517*0Sstevel@tonic-gate 	switch (raidp->state) {
518*0Sstevel@tonic-gate 		case RUS_INIT :
519*0Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Initializing"));
520*0Sstevel@tonic-gate 		case RUS_OKAY :
521*0Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Okay"));
522*0Sstevel@tonic-gate 		case RUS_ERRED :
523*0Sstevel@tonic-gate 		/*FALLTHROUGH*/
524*0Sstevel@tonic-gate 		case RUS_LAST_ERRED :
525*0Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Needs Maintenance"));
526*0Sstevel@tonic-gate 		case RUS_DOI :
527*0Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Initialization Failed"));
528*0Sstevel@tonic-gate 		case RUS_REGEN :
529*0Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Regen"));
530*0Sstevel@tonic-gate 		default :
531*0Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "invalid"));
532*0Sstevel@tonic-gate 	} /* switch */
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate static int
536*0Sstevel@tonic-gate find_erred_column(md_raid_t *raidp, rcs_state_t state)
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	int		col;
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
541*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
542*0Sstevel@tonic-gate 		if (cp->state & state)
543*0Sstevel@tonic-gate 			return (col);
544*0Sstevel@tonic-gate 	}
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	/* No erred columns */
547*0Sstevel@tonic-gate 	return (-1);
548*0Sstevel@tonic-gate }
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate /*
551*0Sstevel@tonic-gate  * convert raid state to repair action
552*0Sstevel@tonic-gate  */
553*0Sstevel@tonic-gate char *
554*0Sstevel@tonic-gate raid_state_to_action(md_raid_t *raidp)
555*0Sstevel@tonic-gate {
556*0Sstevel@tonic-gate 	static char	emsg[1024];
557*0Sstevel@tonic-gate 	mdname_t	*raidnp = raidp->common.namep;
558*0Sstevel@tonic-gate 	int		err_col;
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	/* first check for full init failure */
561*0Sstevel@tonic-gate 	if (raidp->state & RUS_DOI) {
562*0Sstevel@tonic-gate 		(void) snprintf(emsg, sizeof (emsg),
563*0Sstevel@tonic-gate 		    "metaclear -f %s", raidnp->cname);
564*0Sstevel@tonic-gate 		return (emsg);
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	/* replace errored or init errored raid column */
568*0Sstevel@tonic-gate 	if ((err_col = find_erred_column(raidp,
569*0Sstevel@tonic-gate 	    (RCS_ERRED | RCS_INIT_ERRED))) >= 0) {
570*0Sstevel@tonic-gate 		mdname_t	*colnp;
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 		/* get column with error */
573*0Sstevel@tonic-gate 		assert(err_col < raidp->cols.cols_len);
574*0Sstevel@tonic-gate 		colnp = raidp->cols.cols_val[err_col].colnamep;
575*0Sstevel@tonic-gate 		(void) snprintf(emsg, sizeof (emsg),
576*0Sstevel@tonic-gate 		    "metareplace %s%s %s <%s>",
577*0Sstevel@tonic-gate 		    ((raidp->state == RUS_LAST_ERRED) ? "-f " : ""),
578*0Sstevel@tonic-gate 		    raidnp->cname, colnp->cname,
579*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "new device"));
580*0Sstevel@tonic-gate 		return (emsg);
581*0Sstevel@tonic-gate 	}
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	/* replace last errored raid column */
585*0Sstevel@tonic-gate 	if ((err_col = find_erred_column(raidp, RCS_LAST_ERRED)) >= 0) {
586*0Sstevel@tonic-gate 		mdname_t	*colnp;
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 		assert(err_col < raidp->cols.cols_len);
589*0Sstevel@tonic-gate 		colnp = raidp->cols.cols_val[err_col].colnamep;
590*0Sstevel@tonic-gate 		(void) snprintf(emsg, sizeof (emsg),
591*0Sstevel@tonic-gate 		    "metareplace %s %s %s <%s>",
592*0Sstevel@tonic-gate 		    ((raidp->state == RUS_LAST_ERRED) ? "-f " : ""),
593*0Sstevel@tonic-gate 		    raidnp->cname, colnp->cname,
594*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "new device"));
595*0Sstevel@tonic-gate 		return (emsg);
596*0Sstevel@tonic-gate 	}
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate 	/* OK */
599*0Sstevel@tonic-gate 	return (NULL);
600*0Sstevel@tonic-gate }
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate /*
603*0Sstevel@tonic-gate  * get printable raid column state
604*0Sstevel@tonic-gate  */
605*0Sstevel@tonic-gate char *
606*0Sstevel@tonic-gate raid_col_state_to_name(
607*0Sstevel@tonic-gate 	md_raidcol_t	*colp,
608*0Sstevel@tonic-gate 	md_timeval32_t	*tvp,
609*0Sstevel@tonic-gate 	uint_t		tstate
610*0Sstevel@tonic-gate )
611*0Sstevel@tonic-gate {
612*0Sstevel@tonic-gate 	/* grab time */
613*0Sstevel@tonic-gate 	if (tvp != NULL)
614*0Sstevel@tonic-gate 		*tvp = colp->timestamp;
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	if (tstate != 0) {
617*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
618*0Sstevel@tonic-gate 	}
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	/* everything else */
621*0Sstevel@tonic-gate 	switch (colp->state) {
622*0Sstevel@tonic-gate 	case RCS_INIT:
623*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Initializing"));
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	case RCS_OKAY:
626*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Okay"));
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	case RCS_INIT_ERRED:
629*0Sstevel@tonic-gate 	/*FALLTHROUGH*/
630*0Sstevel@tonic-gate 	case RCS_ERRED:
631*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Maintenance"));
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	case RCS_LAST_ERRED:
634*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Last Erred"));
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	case RCS_RESYNC:
637*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Resyncing"));
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	default:
640*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unknown"));
641*0Sstevel@tonic-gate 	}
642*0Sstevel@tonic-gate }
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate /*
645*0Sstevel@tonic-gate  * print raid column
646*0Sstevel@tonic-gate  */
647*0Sstevel@tonic-gate static int
648*0Sstevel@tonic-gate display_raid_device_info(
649*0Sstevel@tonic-gate 	mdsetname_t	*sp,
650*0Sstevel@tonic-gate 	md_raidcol_t	*colp,
651*0Sstevel@tonic-gate 	char		*fname,
652*0Sstevel@tonic-gate 	FILE		*fp,
653*0Sstevel@tonic-gate 	mdprtopts_t	options,
654*0Sstevel@tonic-gate 	int		print_len,
655*0Sstevel@tonic-gate 	uint_t		top_tstate, /* Errored tstate flags */
656*0Sstevel@tonic-gate 	md_error_t	*ep
657*0Sstevel@tonic-gate )
658*0Sstevel@tonic-gate {
659*0Sstevel@tonic-gate 	mdname_t	*namep = ((colp->hsnamep != NULL) ?
660*0Sstevel@tonic-gate 				    colp->hsnamep : colp->colnamep);
661*0Sstevel@tonic-gate 	char 		*devid = "";
662*0Sstevel@tonic-gate 	char		*cname = colp->colnamep->cname;
663*0Sstevel@tonic-gate 	diskaddr_t	start_blk;
664*0Sstevel@tonic-gate 	int		has_mddb;
665*0Sstevel@tonic-gate 	char		*has_mddb_str;
666*0Sstevel@tonic-gate 	char		*col_state;
667*0Sstevel@tonic-gate 	md_timeval32_t	tv;
668*0Sstevel@tonic-gate 	char		*hsname = ((colp->hsnamep != NULL) ?
669*0Sstevel@tonic-gate 			    colp->hsnamep->cname : "");
670*0Sstevel@tonic-gate 	int		rval = -1;
671*0Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
672*0Sstevel@tonic-gate 	ddi_devid_t	dtp;
673*0Sstevel@tonic-gate 	uint_t		tstate = 0;
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	/* get info */
676*0Sstevel@tonic-gate 	if ((start_blk = metagetstart(sp, namep, ep)) == MD_DISKADDR_ERROR)
677*0Sstevel@tonic-gate 		return (-1);
678*0Sstevel@tonic-gate 	if ((has_mddb = metahasmddb(sp, namep, ep)) < 0)
679*0Sstevel@tonic-gate 		return (-1);
680*0Sstevel@tonic-gate 	if (has_mddb)
681*0Sstevel@tonic-gate 		has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
682*0Sstevel@tonic-gate 	else
683*0Sstevel@tonic-gate 		has_mddb_str = dgettext(TEXT_DOMAIN, "No");
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	if (metaismeta(namep)) {
686*0Sstevel@tonic-gate 		if (meta_get_tstate(namep->dev, &tstate, ep) != 0)
687*0Sstevel@tonic-gate 			return (-1);
688*0Sstevel@tonic-gate 		col_state = raid_col_state_to_name(colp, &tv,
689*0Sstevel@tonic-gate 		    tstate & MD_DEV_ERRORED);
690*0Sstevel@tonic-gate 	} else {
691*0Sstevel@tonic-gate 		/*
692*0Sstevel@tonic-gate 		 * if top_tstate is set, that implies that you have
693*0Sstevel@tonic-gate 		 * a ctd type device with an unavailable metadevice
694*0Sstevel@tonic-gate 		 * on top of it. If so, print a - for it's state
695*0Sstevel@tonic-gate 		 */
696*0Sstevel@tonic-gate 		if (top_tstate != 0)
697*0Sstevel@tonic-gate 			col_state = "-";
698*0Sstevel@tonic-gate 		else
699*0Sstevel@tonic-gate 			col_state = raid_col_state_to_name(colp, &tv, tstate);
700*0Sstevel@tonic-gate 	}
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate 	/* populate the key in the name_p structure */
703*0Sstevel@tonic-gate 	if ((didnp = metadevname(&sp, namep->dev, ep)) == NULL)
704*0Sstevel@tonic-gate 		return (-1);
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	/* determine if devid does NOT exist */
707*0Sstevel@tonic-gate 	if (options & PRINT_DEVID) {
708*0Sstevel@tonic-gate 		if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
709*0Sstevel@tonic-gate 			didnp->key, ep)) == NULL)
710*0Sstevel@tonic-gate 			devid = dgettext(TEXT_DOMAIN, "No ");
711*0Sstevel@tonic-gate 		else {
712*0Sstevel@tonic-gate 			devid = dgettext(TEXT_DOMAIN, "Yes");
713*0Sstevel@tonic-gate 			free(dtp);
714*0Sstevel@tonic-gate 		}
715*0Sstevel@tonic-gate 	}
716*0Sstevel@tonic-gate 	/* print column */
717*0Sstevel@tonic-gate 	/*
718*0Sstevel@tonic-gate 	 * Building a format string on the fly that will
719*0Sstevel@tonic-gate 	 * be used in (f)printf. This allows the length
720*0Sstevel@tonic-gate 	 * of the ctd to vary from small to large without
721*0Sstevel@tonic-gate 	 * looking horrible.
722*0Sstevel@tonic-gate 	 */
723*0Sstevel@tonic-gate 	if (! (options & PRINT_TIMES)) {
724*0Sstevel@tonic-gate 		if (fprintf(fp,
725*0Sstevel@tonic-gate 		    "\t%-*.*s %8lld     %5.5s %12.12s %5.5s %s\n",
726*0Sstevel@tonic-gate 		    print_len, print_len, cname, start_blk, has_mddb_str,
727*0Sstevel@tonic-gate 		    col_state, devid, hsname) == EOF) {
728*0Sstevel@tonic-gate 			goto out;
729*0Sstevel@tonic-gate 		}
730*0Sstevel@tonic-gate 	} else {
731*0Sstevel@tonic-gate 		char	*timep = meta_print_time(&tv);
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 		if (fprintf(fp,
734*0Sstevel@tonic-gate 		    "\t%-*s %5lld %-5s %-11s %-5s %-9s %s\n",
735*0Sstevel@tonic-gate 		    print_len, cname, start_blk, has_mddb_str,
736*0Sstevel@tonic-gate 		    col_state, devid, hsname, timep) == EOF) {
737*0Sstevel@tonic-gate 			goto out;
738*0Sstevel@tonic-gate 		}
739*0Sstevel@tonic-gate 	}
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	/* success */
742*0Sstevel@tonic-gate 	rval = 0;
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	/* cleanup, return error */
745*0Sstevel@tonic-gate out:
746*0Sstevel@tonic-gate 	if (rval != 0)
747*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	return (rval);
750*0Sstevel@tonic-gate }
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate /*
753*0Sstevel@tonic-gate  * print raid options
754*0Sstevel@tonic-gate  */
755*0Sstevel@tonic-gate int
756*0Sstevel@tonic-gate meta_print_raid_options(
757*0Sstevel@tonic-gate 	mdhspname_t	*hspnamep,
758*0Sstevel@tonic-gate 	char		*fname,
759*0Sstevel@tonic-gate 	FILE		*fp,
760*0Sstevel@tonic-gate 	md_error_t	*ep
761*0Sstevel@tonic-gate )
762*0Sstevel@tonic-gate {
763*0Sstevel@tonic-gate 	char		*hspname = ((hspnamep != NULL) ? hspnamep->hspname :
764*0Sstevel@tonic-gate 					dgettext(TEXT_DOMAIN, "none"));
765*0Sstevel@tonic-gate 	int		rval = -1;
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	/* print options */
768*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN,
769*0Sstevel@tonic-gate 	    "    Hot spare pool: %s\n"), hspname) == EOF) {
770*0Sstevel@tonic-gate 		goto out;
771*0Sstevel@tonic-gate 	}
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	/* success */
774*0Sstevel@tonic-gate 	rval = 0;
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	/* cleanup, return error */
777*0Sstevel@tonic-gate out:
778*0Sstevel@tonic-gate 	if (rval != 0)
779*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
780*0Sstevel@tonic-gate 	return (rval);
781*0Sstevel@tonic-gate }
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate /*
784*0Sstevel@tonic-gate  * report raid
785*0Sstevel@tonic-gate  */
786*0Sstevel@tonic-gate static int
787*0Sstevel@tonic-gate raid_report(
788*0Sstevel@tonic-gate 	mdsetname_t	*sp,
789*0Sstevel@tonic-gate 	md_raid_t	*raidp,
790*0Sstevel@tonic-gate 	char		*fname,
791*0Sstevel@tonic-gate 	FILE		*fp,
792*0Sstevel@tonic-gate 	mdprtopts_t	options,
793*0Sstevel@tonic-gate 	md_error_t	*ep
794*0Sstevel@tonic-gate )
795*0Sstevel@tonic-gate {
796*0Sstevel@tonic-gate 	char		*p;
797*0Sstevel@tonic-gate 	uint_t		ncol = raidp->cols.cols_len;
798*0Sstevel@tonic-gate 	uint_t		orig_ncol = raidp->orig_ncol;
799*0Sstevel@tonic-gate 	diskaddr_t	column_size = raidp->column_size;
800*0Sstevel@tonic-gate 	char		*raid_state;
801*0Sstevel@tonic-gate 	md_timeval32_t	tv;
802*0Sstevel@tonic-gate 	char		*timep;
803*0Sstevel@tonic-gate 	uint_t		col;
804*0Sstevel@tonic-gate 	int		rval = -1;
805*0Sstevel@tonic-gate 	int		len = 0;
806*0Sstevel@tonic-gate 	uint_t		tstate = 0;
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
809*0Sstevel@tonic-gate 		if (raidp->common.revision != MD_64BIT_META_DEV) {
810*0Sstevel@tonic-gate 			rval = 0;
811*0Sstevel@tonic-gate 			goto out;
812*0Sstevel@tonic-gate 		}
813*0Sstevel@tonic-gate 	}
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	/* print header */
816*0Sstevel@tonic-gate 	if (options & PRINT_HEADER) {
817*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: RAID\n"),
818*0Sstevel@tonic-gate 		    raidp->common.namep->cname) == EOF) {
819*0Sstevel@tonic-gate 			goto out;
820*0Sstevel@tonic-gate 		}
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 	}
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	/* print state */
825*0Sstevel@tonic-gate 	if (metaismeta(raidp->common.namep)) {
826*0Sstevel@tonic-gate 		if (meta_get_tstate(raidp->common.namep->dev, &tstate, ep) != 0)
827*0Sstevel@tonic-gate 			return (-1);
828*0Sstevel@tonic-gate 	}
829*0Sstevel@tonic-gate 	tstate &= MD_DEV_ERRORED; /* extract the errored tstate bits */
830*0Sstevel@tonic-gate 	raid_state = raid_state_to_name(raidp, &tv, tstate);
831*0Sstevel@tonic-gate 	if (options & PRINT_TIMES) {
832*0Sstevel@tonic-gate 		timep = meta_print_time(&tv);
833*0Sstevel@tonic-gate 	} else {
834*0Sstevel@tonic-gate 		timep = "";
835*0Sstevel@tonic-gate 	}
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    State: %-12s %s\n"),
838*0Sstevel@tonic-gate 	    raid_state, timep) == EOF) {
839*0Sstevel@tonic-gate 		goto out;
840*0Sstevel@tonic-gate 	}
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	/*
843*0Sstevel@tonic-gate 	 * Display recovery action if we're marked in the Unavailable state.
844*0Sstevel@tonic-gate 	 */
845*0Sstevel@tonic-gate 	if ((tstate == 0) || (tstate & MD_INACCESSIBLE)) {
846*0Sstevel@tonic-gate 		/* print what to do */
847*0Sstevel@tonic-gate 		if (tstate & MD_INACCESSIBLE) {
848*0Sstevel@tonic-gate 			char sname[MD_MAX_SETNAME + 3]; /* 3 = sizeof("-s ") */
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 			if (metaislocalset(sp)) {
851*0Sstevel@tonic-gate 				sname[0] = '\0';
852*0Sstevel@tonic-gate 			} else {
853*0Sstevel@tonic-gate 				(void) snprintf(sname, MD_MAX_SETNAME + 3,
854*0Sstevel@tonic-gate 				    "-s %s", sp->setname);
855*0Sstevel@tonic-gate 			}
856*0Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
857*0Sstevel@tonic-gate 			    "    Invoke: metastat -i %s\n"), sname) == EOF) {
858*0Sstevel@tonic-gate 				goto out;
859*0Sstevel@tonic-gate 			}
860*0Sstevel@tonic-gate 		} else if ((p = raid_state_to_action(raidp)) != NULL) {
861*0Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
862*0Sstevel@tonic-gate 			    "    Invoke: %s\n"), p) == EOF) {
863*0Sstevel@tonic-gate 				goto out;
864*0Sstevel@tonic-gate 			}
865*0Sstevel@tonic-gate 		}
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 		/* resync status */
868*0Sstevel@tonic-gate 		if (raidp->resync_flags & MD_RI_INPROGRESS) {
869*0Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
870*0Sstevel@tonic-gate 			    "    Resync in progress: %2d.%1d%% done\n"),
871*0Sstevel@tonic-gate 			    raidp->percent_done/10,
872*0Sstevel@tonic-gate 			    raidp->percent_done % 10) == EOF) {
873*0Sstevel@tonic-gate 				goto out;
874*0Sstevel@tonic-gate 			}
875*0Sstevel@tonic-gate 		} else if (raidp->resync_flags & MD_GROW_INPROGRESS) {
876*0Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
877*0Sstevel@tonic-gate 			    "    Initialization in progress: %2d.%1d%% "
878*0Sstevel@tonic-gate 			    "done\n"),
879*0Sstevel@tonic-gate 			    raidp->percent_done/10,
880*0Sstevel@tonic-gate 			    raidp->percent_done % 10) == EOF) {
881*0Sstevel@tonic-gate 				goto out;
882*0Sstevel@tonic-gate 			}
883*0Sstevel@tonic-gate 		} else if (raidp->state & RUS_REGEN) {
884*0Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
885*0Sstevel@tonic-gate 			    "    Parity regeneration in progress: %2d.%1d%% "
886*0Sstevel@tonic-gate 			    "done\n"),
887*0Sstevel@tonic-gate 			    raidp->percent_done/10,
888*0Sstevel@tonic-gate 			    raidp->percent_done % 10) == EOF) {
889*0Sstevel@tonic-gate 				goto out;
890*0Sstevel@tonic-gate 			}
891*0Sstevel@tonic-gate 		}
892*0Sstevel@tonic-gate 	}
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 	/* print hotspare pool */
895*0Sstevel@tonic-gate 	if (raidp->hspnamep != NULL) {
896*0Sstevel@tonic-gate 		if (meta_print_raid_options(raidp->hspnamep,
897*0Sstevel@tonic-gate 		    fname, fp, ep) != 0) {
898*0Sstevel@tonic-gate 			return (-1);
899*0Sstevel@tonic-gate 		}
900*0Sstevel@tonic-gate 	}
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	/* print interlace */
903*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Interlace: %lld blocks\n"),
904*0Sstevel@tonic-gate 	    raidp->interlace) == EOF) {
905*0Sstevel@tonic-gate 		goto out;
906*0Sstevel@tonic-gate 	}
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate 	/* print size */
909*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %lld blocks (%s)\n"),
910*0Sstevel@tonic-gate 	    raidp->common.size,
911*0Sstevel@tonic-gate 	    meta_number_to_string(raidp->common.size, DEV_BSIZE)) == EOF) {
912*0Sstevel@tonic-gate 		goto out;
913*0Sstevel@tonic-gate 	}
914*0Sstevel@tonic-gate 
915*0Sstevel@tonic-gate 	/* MD_DEBUG stuff */
916*0Sstevel@tonic-gate 	if (options & PRINT_DEBUG) {
917*0Sstevel@tonic-gate 		mdname_t	*raidnp = raidp->common.namep;
918*0Sstevel@tonic-gate 		mr_unit_t	*mr;
919*0Sstevel@tonic-gate 
920*0Sstevel@tonic-gate 		/* get additional info */
921*0Sstevel@tonic-gate 		if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
922*0Sstevel@tonic-gate 			return (-1);
923*0Sstevel@tonic-gate 		assert(mr->c.un_type == MD_METARAID);
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate 		/* print prewrite count and size */
926*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
927*0Sstevel@tonic-gate 		    "    Prewrite Count: %u slots\n"),
928*0Sstevel@tonic-gate 		    mr->un_pwcnt) == EOF) {
929*0Sstevel@tonic-gate 			Free(mr);
930*0Sstevel@tonic-gate 			goto out;
931*0Sstevel@tonic-gate 		}
932*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
933*0Sstevel@tonic-gate 		    "    Prewrite Slot Size: %u blocks\n"),
934*0Sstevel@tonic-gate 		    (mr->un_pwsize / mr->un_pwcnt)) == EOF) {
935*0Sstevel@tonic-gate 			Free(mr);
936*0Sstevel@tonic-gate 			goto out;
937*0Sstevel@tonic-gate 		}
938*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
939*0Sstevel@tonic-gate 		    "    Prewrite Total Size: %u blocks\n"),
940*0Sstevel@tonic-gate 		    mr->un_pwsize) == EOF) {
941*0Sstevel@tonic-gate 			Free(mr);
942*0Sstevel@tonic-gate 			goto out;
943*0Sstevel@tonic-gate 		}
944*0Sstevel@tonic-gate 		Free(mr);
945*0Sstevel@tonic-gate 	}
946*0Sstevel@tonic-gate 
947*0Sstevel@tonic-gate 	/* print original devices */
948*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "Original device:\n")) == EOF)
949*0Sstevel@tonic-gate 		goto out;
950*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %lld blocks (%s)\n"),
951*0Sstevel@tonic-gate 	    column_size * (orig_ncol - 1),
952*0Sstevel@tonic-gate 	    meta_number_to_string(column_size * (orig_ncol - 1), DEV_BSIZE))
953*0Sstevel@tonic-gate 	    == EOF) {
954*0Sstevel@tonic-gate 		goto out;
955*0Sstevel@tonic-gate 	}
956*0Sstevel@tonic-gate 	/*
957*0Sstevel@tonic-gate 	 * Building a format string on the fly that will
958*0Sstevel@tonic-gate 	 * be used in (f)printf. This allows the length
959*0Sstevel@tonic-gate 	 * of the ctd to vary from small to large without
960*0Sstevel@tonic-gate 	 * looking horrible.
961*0Sstevel@tonic-gate 	 */
962*0Sstevel@tonic-gate 	for (col = 0; (col < orig_ncol); ++col) {
963*0Sstevel@tonic-gate 		len = max(len,
964*0Sstevel@tonic-gate 		    strlen(raidp->cols.cols_val[col].colnamep->cname));
965*0Sstevel@tonic-gate 	}
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 	len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
968*0Sstevel@tonic-gate 	len += 2;
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 	if (! (options & PRINT_TIMES)) {
971*0Sstevel@tonic-gate 		if (fprintf(fp,
972*0Sstevel@tonic-gate 		    "\t%-*.*s %-12.12s %-5.5s %12.12s %-5.5s  %s\n",
973*0Sstevel@tonic-gate 		    len, len,
974*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
975*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start Block"),
976*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
977*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "State"),
978*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc"),
979*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Hot Spare")) == EOF) {
980*0Sstevel@tonic-gate 			goto out;
981*0Sstevel@tonic-gate 		}
982*0Sstevel@tonic-gate 	} else {
983*0Sstevel@tonic-gate 		if (fprintf(fp,
984*0Sstevel@tonic-gate 		    "\t%-*s  %5s  %-5s  %-11s  %-5s   %-9s  %s\n",
985*0Sstevel@tonic-gate 		    len,
986*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
987*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start"),
988*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
989*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "State"),
990*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc"),
991*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Hot Spare"),
992*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Time")) == EOF) {
993*0Sstevel@tonic-gate 			goto out;
994*0Sstevel@tonic-gate 		}
995*0Sstevel@tonic-gate 	}
996*0Sstevel@tonic-gate 	for (col = 0; (col < orig_ncol); ++col) {
997*0Sstevel@tonic-gate 		md_raidcol_t	*mdrcp = &raidp->cols.cols_val[col];
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 		if (display_raid_device_info(sp, mdrcp, fname, fp, options,
1000*0Sstevel@tonic-gate 		    len, tstate, ep) != 0) {
1001*0Sstevel@tonic-gate 			return (-1);
1002*0Sstevel@tonic-gate 		}
1003*0Sstevel@tonic-gate 	}
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 	/* print concatenated devices */
1006*0Sstevel@tonic-gate 	if (col < ncol) {
1007*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
1008*0Sstevel@tonic-gate 		    "Concatenated Devices:\n")) == EOF) {
1009*0Sstevel@tonic-gate 			goto out;
1010*0Sstevel@tonic-gate 		}
1011*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
1012*0Sstevel@tonic-gate 		    "    Size: %lld blocks (%s)\n"),
1013*0Sstevel@tonic-gate 		    column_size * (ncol - orig_ncol),
1014*0Sstevel@tonic-gate 		    meta_number_to_string(column_size * (ncol - orig_ncol),
1015*0Sstevel@tonic-gate 		    DEV_BSIZE))
1016*0Sstevel@tonic-gate 		    == EOF) {
1017*0Sstevel@tonic-gate 			goto out;
1018*0Sstevel@tonic-gate 		}
1019*0Sstevel@tonic-gate 		/*
1020*0Sstevel@tonic-gate 		 * This allows the length
1021*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
1022*0Sstevel@tonic-gate 		 * looking horrible.
1023*0Sstevel@tonic-gate 		 */
1024*0Sstevel@tonic-gate 		if (! (options & PRINT_TIMES)) {
1025*0Sstevel@tonic-gate 			if (fprintf(fp,
1026*0Sstevel@tonic-gate 			    "\t%-*.*s %-12.12s %-5.5s %-12.12s %5.5s %s\n",
1027*0Sstevel@tonic-gate 			    len, len,
1028*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
1029*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Start Block"),
1030*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Dbase"),
1031*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "State"),
1032*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc"),
1033*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Hot Spare")) == EOF) {
1034*0Sstevel@tonic-gate 				goto out;
1035*0Sstevel@tonic-gate 			}
1036*0Sstevel@tonic-gate 		} else {
1037*0Sstevel@tonic-gate 			if (fprintf(fp,
1038*0Sstevel@tonic-gate 			    "\t%-*s %5s %-5s %-11s %-9s %s\t%s\n",
1039*0Sstevel@tonic-gate 			    len,
1040*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
1041*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Start"),
1042*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Dbase"),
1043*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "State"),
1044*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc"),
1045*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Hot Spare"),
1046*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Time")) == EOF) {
1047*0Sstevel@tonic-gate 				goto out;
1048*0Sstevel@tonic-gate 			}
1049*0Sstevel@tonic-gate 		}
1050*0Sstevel@tonic-gate 		assert(col == orig_ncol);
1051*0Sstevel@tonic-gate 		for (/* void */; (col < ncol); col++) {
1052*0Sstevel@tonic-gate 			md_raidcol_t	*mdrcp = &raidp->cols.cols_val[col];
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate 			if (display_raid_device_info(sp, mdrcp, fname, fp,
1055*0Sstevel@tonic-gate 			    options, len, tstate, ep) != 0) {
1056*0Sstevel@tonic-gate 				return (-1);
1057*0Sstevel@tonic-gate 			}
1058*0Sstevel@tonic-gate 		}
1059*0Sstevel@tonic-gate 	}
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	/* add extra line */
1062*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
1063*0Sstevel@tonic-gate 		goto out;
1064*0Sstevel@tonic-gate 
1065*0Sstevel@tonic-gate 	/* success */
1066*0Sstevel@tonic-gate 	rval = 0;
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 	/* cleanup, return error */
1069*0Sstevel@tonic-gate out:
1070*0Sstevel@tonic-gate 	if (rval != 0)
1071*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
1072*0Sstevel@tonic-gate 	return (rval);
1073*0Sstevel@tonic-gate }
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate /*
1076*0Sstevel@tonic-gate  * print/report raid
1077*0Sstevel@tonic-gate  */
1078*0Sstevel@tonic-gate int
1079*0Sstevel@tonic-gate meta_raid_print(
1080*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1081*0Sstevel@tonic-gate 	mdname_t	*raidnp,
1082*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
1083*0Sstevel@tonic-gate 	char		*fname,
1084*0Sstevel@tonic-gate 	FILE		*fp,
1085*0Sstevel@tonic-gate 	mdprtopts_t	options,
1086*0Sstevel@tonic-gate 	md_error_t	*ep
1087*0Sstevel@tonic-gate )
1088*0Sstevel@tonic-gate {
1089*0Sstevel@tonic-gate 	md_raid_t	*raidp;
1090*0Sstevel@tonic-gate 	int		col;
1091*0Sstevel@tonic-gate 
1092*0Sstevel@tonic-gate 	/* should have same set */
1093*0Sstevel@tonic-gate 	assert(sp != NULL);
1094*0Sstevel@tonic-gate 	assert((raidnp == NULL) ||
1095*0Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev))));
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate 	/* print all raids */
1098*0Sstevel@tonic-gate 	if (raidnp == NULL) {
1099*0Sstevel@tonic-gate 		mdnamelist_t	*nlp = NULL;
1100*0Sstevel@tonic-gate 		mdnamelist_t	*p;
1101*0Sstevel@tonic-gate 		int		cnt;
1102*0Sstevel@tonic-gate 		int		rval = 0;
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 		/* get list */
1105*0Sstevel@tonic-gate 		if ((cnt = meta_get_raid_names(sp, &nlp, options, ep)) < 0)
1106*0Sstevel@tonic-gate 			return (-1);
1107*0Sstevel@tonic-gate 		else if (cnt == 0)
1108*0Sstevel@tonic-gate 			return (0);
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate 		/* recurse */
1111*0Sstevel@tonic-gate 		for (p = nlp; (p != NULL); p = p->next) {
1112*0Sstevel@tonic-gate 			mdname_t	*np = p->namep;
1113*0Sstevel@tonic-gate 
1114*0Sstevel@tonic-gate 			if (meta_raid_print(sp, np, nlpp, fname, fp,
1115*0Sstevel@tonic-gate 			    options, ep) != 0)
1116*0Sstevel@tonic-gate 				rval = -1;
1117*0Sstevel@tonic-gate 		}
1118*0Sstevel@tonic-gate 
1119*0Sstevel@tonic-gate 		/* cleanup, return success */
1120*0Sstevel@tonic-gate 		metafreenamelist(nlp);
1121*0Sstevel@tonic-gate 		return (rval);
1122*0Sstevel@tonic-gate 	}
1123*0Sstevel@tonic-gate 
1124*0Sstevel@tonic-gate 	/* get unit structure */
1125*0Sstevel@tonic-gate 	if ((raidp = meta_get_raid_common(sp, raidnp,
1126*0Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
1127*0Sstevel@tonic-gate 		return (-1);
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate 	/* check for parented */
1130*0Sstevel@tonic-gate 	if ((! (options & PRINT_SUBDEVS)) &&
1131*0Sstevel@tonic-gate 	    (MD_HAS_PARENT(raidp->common.parent))) {
1132*0Sstevel@tonic-gate 		return (0);
1133*0Sstevel@tonic-gate 	}
1134*0Sstevel@tonic-gate 
1135*0Sstevel@tonic-gate 	/* print appropriate detail */
1136*0Sstevel@tonic-gate 	if (options & PRINT_SHORT) {
1137*0Sstevel@tonic-gate 		if (raid_print(raidp, fname, fp, options, ep) != 0)
1138*0Sstevel@tonic-gate 			return (-1);
1139*0Sstevel@tonic-gate 	} else {
1140*0Sstevel@tonic-gate 		if (raid_report(sp, raidp, fname, fp, options, ep) != 0)
1141*0Sstevel@tonic-gate 			return (-1);
1142*0Sstevel@tonic-gate 	}
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	/* Recurse on components that are metadevices */
1145*0Sstevel@tonic-gate 	for (col = 0; col < raidp->cols.cols_len; ++col) {
1146*0Sstevel@tonic-gate 		md_raidcol_t	*colp = &raidp->cols.cols_val[col];
1147*0Sstevel@tonic-gate 		mdname_t	*namep = colp->colnamep;
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate 		if ((metaismeta(namep)) &&
1150*0Sstevel@tonic-gate 		    (meta_print_name(sp, namep, nlpp, fname, fp,
1151*0Sstevel@tonic-gate 		    (options | PRINT_HEADER | PRINT_SUBDEVS),
1152*0Sstevel@tonic-gate 		    NULL, ep) != 0)) {
1153*0Sstevel@tonic-gate 			return (-1);
1154*0Sstevel@tonic-gate 		}
1155*0Sstevel@tonic-gate 	}
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 	return (0);
1158*0Sstevel@tonic-gate }
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate /*
1161*0Sstevel@tonic-gate  * adjust raid geometry
1162*0Sstevel@tonic-gate  */
1163*0Sstevel@tonic-gate static int
1164*0Sstevel@tonic-gate adjust_geom(
1165*0Sstevel@tonic-gate 	mdname_t	*raidnp,
1166*0Sstevel@tonic-gate 	mdname_t	*colnp,
1167*0Sstevel@tonic-gate 	mr_unit_t	*mr,
1168*0Sstevel@tonic-gate 	md_error_t	*ep
1169*0Sstevel@tonic-gate )
1170*0Sstevel@tonic-gate {
1171*0Sstevel@tonic-gate 	uint_t		round_cyl = 1;
1172*0Sstevel@tonic-gate 	mdgeom_t	*geomp;
1173*0Sstevel@tonic-gate 
1174*0Sstevel@tonic-gate 	/* get reinstructs */
1175*0Sstevel@tonic-gate 	if ((geomp = metagetgeom(colnp, ep)) == NULL)
1176*0Sstevel@tonic-gate 		return (-1);
1177*0Sstevel@tonic-gate 
1178*0Sstevel@tonic-gate 	/* adjust geometry */
1179*0Sstevel@tonic-gate 	if (meta_adjust_geom((md_unit_t *)mr, raidnp, geomp->write_reinstruct,
1180*0Sstevel@tonic-gate 	    geomp->read_reinstruct, round_cyl, ep) != 0)
1181*0Sstevel@tonic-gate 		return (-1);
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 	/* return success */
1184*0Sstevel@tonic-gate 	return (0);
1185*0Sstevel@tonic-gate }
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate /*
1188*0Sstevel@tonic-gate  * add another column to the raid unit structure
1189*0Sstevel@tonic-gate  */
1190*0Sstevel@tonic-gate static int
1191*0Sstevel@tonic-gate attach_raid_col(
1192*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1193*0Sstevel@tonic-gate 	mdname_t	*raidnp,
1194*0Sstevel@tonic-gate 	mr_unit_t	*mr,
1195*0Sstevel@tonic-gate 	mr_column_t	*mdc,
1196*0Sstevel@tonic-gate 	mdname_t	*colnp,
1197*0Sstevel@tonic-gate 	rcs_state_t	state,
1198*0Sstevel@tonic-gate 	mdnamelist_t	**keynlpp,
1199*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1200*0Sstevel@tonic-gate 	md_error_t	*ep
1201*0Sstevel@tonic-gate )
1202*0Sstevel@tonic-gate {
1203*0Sstevel@tonic-gate 	diskaddr_t	column_size = mr->un_segsize * mr->un_segsincolumn;
1204*0Sstevel@tonic-gate 	diskaddr_t	size;
1205*0Sstevel@tonic-gate 	uint_t		 maxio;
1206*0Sstevel@tonic-gate 	mdcinfo_t	*cinfop;
1207*0Sstevel@tonic-gate 	md_timeval32_t	tmp_time;
1208*0Sstevel@tonic-gate 
1209*0Sstevel@tonic-gate 	/* setup state and timestamp */
1210*0Sstevel@tonic-gate 	mdc->un_devstate = state;
1211*0Sstevel@tonic-gate 	if (meta_gettimeofday(&tmp_time) == -1)
1212*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate 	mdc->un_devtimestamp = tmp_time;
1215*0Sstevel@tonic-gate 	/* get start, size, and maxio */
1216*0Sstevel@tonic-gate 	if ((mdc->un_orig_devstart = metagetstart(sp, colnp, ep)) ==
1217*0Sstevel@tonic-gate 	    MD_DISKADDR_ERROR)
1218*0Sstevel@tonic-gate 		return (-1);
1219*0Sstevel@tonic-gate 	if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
1220*0Sstevel@tonic-gate 		return (-1);
1221*0Sstevel@tonic-gate 	if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
1222*0Sstevel@tonic-gate 		return (-1);
1223*0Sstevel@tonic-gate 	maxio = cinfop->maxtransfer;
1224*0Sstevel@tonic-gate 
1225*0Sstevel@tonic-gate 	/* adjust start and size by prewrite */
1226*0Sstevel@tonic-gate 	mdc->un_orig_pwstart = mdc->un_orig_devstart;
1227*0Sstevel@tonic-gate 	mdc->un_orig_devstart += mr->un_pwsize;
1228*0Sstevel@tonic-gate 
1229*0Sstevel@tonic-gate 	/* make sure we still have something left */
1230*0Sstevel@tonic-gate 	if ((mdc->un_orig_devstart >= size) ||
1231*0Sstevel@tonic-gate 	    ((size - mdc->un_orig_devstart) < column_size)) {
1232*0Sstevel@tonic-gate 		return (mdsyserror(ep, ENOSPC, colnp->cname));
1233*0Sstevel@tonic-gate 	}
1234*0Sstevel@tonic-gate 	size -= mdc->un_orig_devstart;
1235*0Sstevel@tonic-gate 	if (maxio < mr->un_maxio) {
1236*0Sstevel@tonic-gate 		return (mdcomperror(ep, MDE_MAXIO,
1237*0Sstevel@tonic-gate 		    meta_getminor(raidnp->dev), colnp->dev, colnp->cname));
1238*0Sstevel@tonic-gate 	}
1239*0Sstevel@tonic-gate 
1240*0Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
1241*0Sstevel@tonic-gate 		/* store name in namespace */
1242*0Sstevel@tonic-gate 		if (add_key_name(sp, colnp, keynlpp, ep) != 0)
1243*0Sstevel@tonic-gate 			return (-1);
1244*0Sstevel@tonic-gate 	}
1245*0Sstevel@tonic-gate 
1246*0Sstevel@tonic-gate 	/* setup column */
1247*0Sstevel@tonic-gate 	mdc->un_orig_dev = colnp->dev;
1248*0Sstevel@tonic-gate 	mdc->un_orig_key = colnp->key;
1249*0Sstevel@tonic-gate 	mdc->un_dev = colnp->dev;
1250*0Sstevel@tonic-gate 	mdc->un_pwstart = mdc->un_orig_pwstart;
1251*0Sstevel@tonic-gate 	mdc->un_devstart = mdc->un_orig_devstart;
1252*0Sstevel@tonic-gate 	mdc->un_alt_dev = NODEV64;
1253*0Sstevel@tonic-gate 	mdc->un_alt_pwstart = 0;
1254*0Sstevel@tonic-gate 	mdc->un_alt_devstart = 0;
1255*0Sstevel@tonic-gate 	mdc->un_hs_id = 0;
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate 	/* add the size (we use) of the device to the total */
1258*0Sstevel@tonic-gate 	mr->c.un_actual_tb += column_size;
1259*0Sstevel@tonic-gate 
1260*0Sstevel@tonic-gate 	/* adjust geometry */
1261*0Sstevel@tonic-gate 	if (adjust_geom(raidnp, colnp, mr, ep) != 0)
1262*0Sstevel@tonic-gate 		return (-1);
1263*0Sstevel@tonic-gate 
1264*0Sstevel@tonic-gate 	/* count column */
1265*0Sstevel@tonic-gate 	mr->un_totalcolumncnt++;
1266*0Sstevel@tonic-gate 
1267*0Sstevel@tonic-gate 	/* return success */
1268*0Sstevel@tonic-gate 	return (0);
1269*0Sstevel@tonic-gate }
1270*0Sstevel@tonic-gate 
1271*0Sstevel@tonic-gate /*
1272*0Sstevel@tonic-gate  * invalidate column names
1273*0Sstevel@tonic-gate  */
1274*0Sstevel@tonic-gate static int
1275*0Sstevel@tonic-gate invalidate_columns(
1276*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1277*0Sstevel@tonic-gate 	mdname_t	*raidnp,
1278*0Sstevel@tonic-gate 	md_error_t	*ep
1279*0Sstevel@tonic-gate )
1280*0Sstevel@tonic-gate {
1281*0Sstevel@tonic-gate 	md_raid_t	*raidp;
1282*0Sstevel@tonic-gate 	uint_t		col;
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 	if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
1285*0Sstevel@tonic-gate 		return (-1);
1286*0Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
1287*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
1288*0Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
1289*0Sstevel@tonic-gate 
1290*0Sstevel@tonic-gate 		meta_invalidate_name(colnp);
1291*0Sstevel@tonic-gate 	}
1292*0Sstevel@tonic-gate 	return (0);
1293*0Sstevel@tonic-gate }
1294*0Sstevel@tonic-gate 
1295*0Sstevel@tonic-gate /*
1296*0Sstevel@tonic-gate  * attach columns to raid
1297*0Sstevel@tonic-gate  */
1298*0Sstevel@tonic-gate int
1299*0Sstevel@tonic-gate meta_raid_attach(
1300*0Sstevel@tonic-gate 	mdsetname_t		*sp,
1301*0Sstevel@tonic-gate 	mdname_t		*raidnp,
1302*0Sstevel@tonic-gate 	mdnamelist_t		*colnlp,
1303*0Sstevel@tonic-gate 	mdcmdopts_t		options,
1304*0Sstevel@tonic-gate 	md_error_t		*ep
1305*0Sstevel@tonic-gate )
1306*0Sstevel@tonic-gate {
1307*0Sstevel@tonic-gate 	uint_t			concat_cnt = 0;
1308*0Sstevel@tonic-gate 	mdnamelist_t		*p;
1309*0Sstevel@tonic-gate 	mr_unit_t		*old_mr;
1310*0Sstevel@tonic-gate 	mr_unit_t		*new_mr;
1311*0Sstevel@tonic-gate 	size_t			old_rusize;
1312*0Sstevel@tonic-gate 	size_t			new_rusize;
1313*0Sstevel@tonic-gate 	mdnamelist_t		*keynlp = NULL;
1314*0Sstevel@tonic-gate 	md_grow_params_t	mgp;
1315*0Sstevel@tonic-gate 	int			rval = -1;
1316*0Sstevel@tonic-gate 	int			create_flag = MD_CRO_32BIT;
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate 	/* should have a set */
1319*0Sstevel@tonic-gate 	assert(sp != NULL);
1320*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate 	/* check type */
1323*0Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
1324*0Sstevel@tonic-gate 		return (-1);
1325*0Sstevel@tonic-gate 
1326*0Sstevel@tonic-gate 	/* check and count new columns */
1327*0Sstevel@tonic-gate 	for (p = colnlp; (p != NULL); p = p->next) {
1328*0Sstevel@tonic-gate 		mdname_t	*np = p->namep;
1329*0Sstevel@tonic-gate 		mdnamelist_t	*p2;
1330*0Sstevel@tonic-gate 
1331*0Sstevel@tonic-gate 		/* check against existing devices */
1332*0Sstevel@tonic-gate 		if (meta_check_column(sp, np, ep) != 0)
1333*0Sstevel@tonic-gate 			return (-1);
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 		/* check against ourselves */
1336*0Sstevel@tonic-gate 		for (p2 = p->next; (p2 != NULL); p2 = p2->next) {
1337*0Sstevel@tonic-gate 			if (meta_check_overlap(np->cname, np, 0, -1,
1338*0Sstevel@tonic-gate 			    p2->namep, 0, -1, ep) != 0) {
1339*0Sstevel@tonic-gate 				return (-1);
1340*0Sstevel@tonic-gate 			}
1341*0Sstevel@tonic-gate 		}
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 		/* count */
1344*0Sstevel@tonic-gate 		++concat_cnt;
1345*0Sstevel@tonic-gate 	}
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 	/* get old unit */
1348*0Sstevel@tonic-gate 	if ((old_mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
1349*0Sstevel@tonic-gate 		return (-1);
1350*0Sstevel@tonic-gate 
1351*0Sstevel@tonic-gate 	/*
1352*0Sstevel@tonic-gate 	 * calculate the size needed for the new raid unit and allocate
1353*0Sstevel@tonic-gate 	 * the appropriate structure. allocate new unit.
1354*0Sstevel@tonic-gate 	 */
1355*0Sstevel@tonic-gate 	old_rusize = sizeof (*old_mr) - sizeof (old_mr->un_column[0]);
1356*0Sstevel@tonic-gate 	old_rusize += old_mr->un_totalcolumncnt * sizeof (old_mr->un_column[0]);
1357*0Sstevel@tonic-gate 	new_rusize = sizeof (*new_mr) - sizeof (new_mr->un_column[0]);
1358*0Sstevel@tonic-gate 	new_rusize += (old_mr->un_totalcolumncnt + concat_cnt)
1359*0Sstevel@tonic-gate 	    * sizeof (new_mr->un_column[0]);
1360*0Sstevel@tonic-gate 	new_mr = Zalloc(new_rusize);
1361*0Sstevel@tonic-gate 	(void) memcpy(new_mr, old_mr, old_rusize);
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 	/* We always want a do-it, this is for attach_raid_col below */
1364*0Sstevel@tonic-gate 	options |= MDCMD_DOIT;
1365*0Sstevel@tonic-gate 
1366*0Sstevel@tonic-gate 	/* build new unit structure */
1367*0Sstevel@tonic-gate 	for (p = colnlp; (p != NULL); p = p->next) {
1368*0Sstevel@tonic-gate 		mdname_t	*colnp = p->namep;
1369*0Sstevel@tonic-gate 		mr_column_t	*mdc;
1370*0Sstevel@tonic-gate 
1371*0Sstevel@tonic-gate 		/* attach column */
1372*0Sstevel@tonic-gate 		mdc = &new_mr->un_column[new_mr->un_totalcolumncnt];
1373*0Sstevel@tonic-gate 		if (attach_raid_col(sp, raidnp, new_mr, mdc, colnp,
1374*0Sstevel@tonic-gate 		    RCS_INIT, &keynlp, options, ep) != 0) {
1375*0Sstevel@tonic-gate 			goto out;
1376*0Sstevel@tonic-gate 		}
1377*0Sstevel@tonic-gate 	}
1378*0Sstevel@tonic-gate 	assert(new_mr->un_totalcolumncnt
1379*0Sstevel@tonic-gate 	    == (old_mr->un_totalcolumncnt + concat_cnt));
1380*0Sstevel@tonic-gate 
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 	create_flag = meta_check_devicesize(new_mr->c.un_total_blocks);
1383*0Sstevel@tonic-gate 
1384*0Sstevel@tonic-gate 	/* grow raid */
1385*0Sstevel@tonic-gate 	(void) memset(&mgp, 0, sizeof (mgp));
1386*0Sstevel@tonic-gate 	mgp.mnum = MD_SID(new_mr);
1387*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mgp, MD_RAID, sp->setno);
1388*0Sstevel@tonic-gate 	mgp.size = new_rusize;
1389*0Sstevel@tonic-gate 	mgp.mdp = (uintptr_t)new_mr;
1390*0Sstevel@tonic-gate 
1391*0Sstevel@tonic-gate 	if (create_flag == MD_CRO_32BIT) {
1392*0Sstevel@tonic-gate 		mgp.options = MD_CRO_32BIT;
1393*0Sstevel@tonic-gate 		new_mr->c.un_revision = MD_32BIT_META_DEV;
1394*0Sstevel@tonic-gate 	} else {
1395*0Sstevel@tonic-gate 		mgp.options = MD_CRO_64BIT;
1396*0Sstevel@tonic-gate 		new_mr->c.un_revision = MD_64BIT_META_DEV;
1397*0Sstevel@tonic-gate 	}
1398*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCGROW, &mgp, &mgp.mde, NULL) != 0) {
1399*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &mgp.mde);
1400*0Sstevel@tonic-gate 		goto out;
1401*0Sstevel@tonic-gate 	}
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate 	/* clear cache */
1404*0Sstevel@tonic-gate 	if (invalidate_columns(sp, raidnp, ep) != 0)
1405*0Sstevel@tonic-gate 		goto out;
1406*0Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
1407*0Sstevel@tonic-gate 
1408*0Sstevel@tonic-gate 	/* let em know */
1409*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
1410*0Sstevel@tonic-gate 		if (concat_cnt == 1) {
1411*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
1412*0Sstevel@tonic-gate 			    "%s: component is attached\n"),
1413*0Sstevel@tonic-gate 			    raidnp->cname);
1414*0Sstevel@tonic-gate 		} else {
1415*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
1416*0Sstevel@tonic-gate 			    "%s: components are attached\n"),
1417*0Sstevel@tonic-gate 			    raidnp->cname);
1418*0Sstevel@tonic-gate 		}
1419*0Sstevel@tonic-gate 		(void) fflush(stdout);
1420*0Sstevel@tonic-gate 	}
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 	/* grow any parents */
1424*0Sstevel@tonic-gate 	if (meta_concat_parent(sp, raidnp, ep) != 0)
1425*0Sstevel@tonic-gate 		goto out;
1426*0Sstevel@tonic-gate 	rval = 0;	/* success */
1427*0Sstevel@tonic-gate 
1428*0Sstevel@tonic-gate 	/* cleanup, return error */
1429*0Sstevel@tonic-gate out:
1430*0Sstevel@tonic-gate 	Free(old_mr);
1431*0Sstevel@tonic-gate 	Free(new_mr);
1432*0Sstevel@tonic-gate 	if (rval != 0)
1433*0Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
1434*0Sstevel@tonic-gate 	metafreenamelist(keynlp);
1435*0Sstevel@tonic-gate 	return (rval);
1436*0Sstevel@tonic-gate }
1437*0Sstevel@tonic-gate 
1438*0Sstevel@tonic-gate /*
1439*0Sstevel@tonic-gate  * get raid parameters
1440*0Sstevel@tonic-gate  */
1441*0Sstevel@tonic-gate int
1442*0Sstevel@tonic-gate meta_raid_get_params(
1443*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1444*0Sstevel@tonic-gate 	mdname_t	*raidnp,
1445*0Sstevel@tonic-gate 	mr_params_t	*paramsp,
1446*0Sstevel@tonic-gate 	md_error_t	*ep
1447*0Sstevel@tonic-gate )
1448*0Sstevel@tonic-gate {
1449*0Sstevel@tonic-gate 	md_raid_t	*raidp;
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 	/* should have a set */
1452*0Sstevel@tonic-gate 	assert(sp != NULL);
1453*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
1454*0Sstevel@tonic-gate 
1455*0Sstevel@tonic-gate 	/* check name */
1456*0Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
1457*0Sstevel@tonic-gate 		return (-1);
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 	/* get unit */
1460*0Sstevel@tonic-gate 	if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
1461*0Sstevel@tonic-gate 		return (-1);
1462*0Sstevel@tonic-gate 
1463*0Sstevel@tonic-gate 	/* return parameters */
1464*0Sstevel@tonic-gate 	(void) memset(paramsp, 0, sizeof (*paramsp));
1465*0Sstevel@tonic-gate 	if (raidp->hspnamep == NULL)
1466*0Sstevel@tonic-gate 		paramsp->hsp_id = MD_HSP_NONE;
1467*0Sstevel@tonic-gate 	else
1468*0Sstevel@tonic-gate 		paramsp->hsp_id = raidp->hspnamep->hsp;
1469*0Sstevel@tonic-gate 	return (0);
1470*0Sstevel@tonic-gate }
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate /*
1473*0Sstevel@tonic-gate  * set raid parameters
1474*0Sstevel@tonic-gate  */
1475*0Sstevel@tonic-gate int
1476*0Sstevel@tonic-gate meta_raid_set_params(
1477*0Sstevel@tonic-gate 	mdsetname_t		*sp,
1478*0Sstevel@tonic-gate 	mdname_t		*raidnp,
1479*0Sstevel@tonic-gate 	mr_params_t		*paramsp,
1480*0Sstevel@tonic-gate 	md_error_t		*ep
1481*0Sstevel@tonic-gate )
1482*0Sstevel@tonic-gate {
1483*0Sstevel@tonic-gate 	md_raid_params_t	msp;
1484*0Sstevel@tonic-gate 
1485*0Sstevel@tonic-gate 	/* should have a set */
1486*0Sstevel@tonic-gate 	assert(sp != NULL);
1487*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
1488*0Sstevel@tonic-gate 
1489*0Sstevel@tonic-gate 	/* check name */
1490*0Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
1491*0Sstevel@tonic-gate 		return (-1);
1492*0Sstevel@tonic-gate 
1493*0Sstevel@tonic-gate 	/* set parameters */
1494*0Sstevel@tonic-gate 	(void) memset(&msp, 0, sizeof (msp));
1495*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&msp, MD_RAID, sp->setno);
1496*0Sstevel@tonic-gate 	msp.mnum = meta_getminor(raidnp->dev);
1497*0Sstevel@tonic-gate 	msp.params = *paramsp;
1498*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCCHANGE, &msp, &msp.mde, raidnp->cname) != 0)
1499*0Sstevel@tonic-gate 		return (mdstealerror(ep, &msp.mde));
1500*0Sstevel@tonic-gate 
1501*0Sstevel@tonic-gate 	/* clear cache */
1502*0Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
1503*0Sstevel@tonic-gate 
1504*0Sstevel@tonic-gate 	/* return success */
1505*0Sstevel@tonic-gate 	return (0);
1506*0Sstevel@tonic-gate }
1507*0Sstevel@tonic-gate 
1508*0Sstevel@tonic-gate /*
1509*0Sstevel@tonic-gate  * validate raid replace column
1510*0Sstevel@tonic-gate  */
1511*0Sstevel@tonic-gate static int
1512*0Sstevel@tonic-gate validate_new_raid(
1513*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1514*0Sstevel@tonic-gate 	mdname_t	*raidnp,
1515*0Sstevel@tonic-gate 	mdname_t	*colnp,
1516*0Sstevel@tonic-gate 	replace_params_t *paramsp,
1517*0Sstevel@tonic-gate 	int		dup_ok,
1518*0Sstevel@tonic-gate 	md_error_t	*ep
1519*0Sstevel@tonic-gate )
1520*0Sstevel@tonic-gate {
1521*0Sstevel@tonic-gate 	mr_unit_t	*mr;
1522*0Sstevel@tonic-gate 	diskaddr_t	column_size;
1523*0Sstevel@tonic-gate 	diskaddr_t	label;
1524*0Sstevel@tonic-gate 	mdcinfo_t	*cinfop;
1525*0Sstevel@tonic-gate 	int		rval = -1;
1526*0Sstevel@tonic-gate 
1527*0Sstevel@tonic-gate 	/* get raid unit */
1528*0Sstevel@tonic-gate 	if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
1529*0Sstevel@tonic-gate 		return (-1);
1530*0Sstevel@tonic-gate 	column_size = mr->un_segsize * mr->un_segsincolumn;
1531*0Sstevel@tonic-gate 
1532*0Sstevel@tonic-gate 	/* check it out */
1533*0Sstevel@tonic-gate 	if (meta_check_column(sp, colnp, ep) != 0) {
1534*0Sstevel@tonic-gate 		if ((! dup_ok) || (! mdisuseerror(ep, MDE_ALREADY)))
1535*0Sstevel@tonic-gate 			goto out;
1536*0Sstevel@tonic-gate 		mdclrerror(ep);
1537*0Sstevel@tonic-gate 	}
1538*0Sstevel@tonic-gate 	if ((paramsp->number_blks = metagetsize(colnp, ep)) ==
1539*0Sstevel@tonic-gate 	    MD_DISKADDR_ERROR)
1540*0Sstevel@tonic-gate 		goto out;
1541*0Sstevel@tonic-gate 	if ((label = metagetlabel(colnp, ep)) == MD_DISKADDR_ERROR)
1542*0Sstevel@tonic-gate 		goto out;
1543*0Sstevel@tonic-gate 	paramsp->has_label = ((label > 0) ? 1 : 0);
1544*0Sstevel@tonic-gate 	if ((paramsp->start_blk = metagetstart(sp, colnp, ep)) ==
1545*0Sstevel@tonic-gate 	    MD_DISKADDR_ERROR)
1546*0Sstevel@tonic-gate 		goto out;
1547*0Sstevel@tonic-gate 	if ((paramsp->number_blks - paramsp->start_blk) < column_size) {
1548*0Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, colnp->cname);
1549*0Sstevel@tonic-gate 		goto out;
1550*0Sstevel@tonic-gate 	}
1551*0Sstevel@tonic-gate 	if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
1552*0Sstevel@tonic-gate 		goto out;
1553*0Sstevel@tonic-gate 	if (cinfop->maxtransfer < mr->un_maxio) {
1554*0Sstevel@tonic-gate 		(void) mdcomperror(ep, MDE_MAXIO, meta_getminor(raidnp->dev),
1555*0Sstevel@tonic-gate 		    colnp->dev, colnp->cname);
1556*0Sstevel@tonic-gate 		goto out;
1557*0Sstevel@tonic-gate 	}
1558*0Sstevel@tonic-gate 
1559*0Sstevel@tonic-gate 	/* success */
1560*0Sstevel@tonic-gate 	rval = 0;
1561*0Sstevel@tonic-gate 
1562*0Sstevel@tonic-gate 	/* cleanup, return error */
1563*0Sstevel@tonic-gate out:
1564*0Sstevel@tonic-gate 	Free(mr);
1565*0Sstevel@tonic-gate 	return (rval);
1566*0Sstevel@tonic-gate }
1567*0Sstevel@tonic-gate 
1568*0Sstevel@tonic-gate /*
1569*0Sstevel@tonic-gate  * replace raid column
1570*0Sstevel@tonic-gate  */
1571*0Sstevel@tonic-gate int
1572*0Sstevel@tonic-gate meta_raid_replace(
1573*0Sstevel@tonic-gate 	mdsetname_t		*sp,
1574*0Sstevel@tonic-gate 	mdname_t		*raidnp,
1575*0Sstevel@tonic-gate 	mdname_t		*oldnp,
1576*0Sstevel@tonic-gate 	mdname_t		*newnp,
1577*0Sstevel@tonic-gate 	mdcmdopts_t		options,
1578*0Sstevel@tonic-gate 	md_error_t		*ep
1579*0Sstevel@tonic-gate )
1580*0Sstevel@tonic-gate {
1581*0Sstevel@tonic-gate 	int			force = ((options & MDCMD_FORCE) ? 1 : 0);
1582*0Sstevel@tonic-gate 	replace_params_t	params;
1583*0Sstevel@tonic-gate 	md_dev64_t		old_dev, new_dev;
1584*0Sstevel@tonic-gate 	diskaddr_t		new_start_blk, new_end_blk;
1585*0Sstevel@tonic-gate 	int			rebind;
1586*0Sstevel@tonic-gate 	mr_unit_t		*mr;
1587*0Sstevel@tonic-gate 	char			*new_devidp = NULL;
1588*0Sstevel@tonic-gate 	md_error_t		xep = mdnullerror;
1589*0Sstevel@tonic-gate 	int			ret;
1590*0Sstevel@tonic-gate 	md_set_desc		*sd;
1591*0Sstevel@tonic-gate 	uint_t			tstate;
1592*0Sstevel@tonic-gate 
1593*0Sstevel@tonic-gate 	/* should have same set */
1594*0Sstevel@tonic-gate 	assert(sp != NULL);
1595*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
1596*0Sstevel@tonic-gate 
1597*0Sstevel@tonic-gate 	/* check name */
1598*0Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
1599*0Sstevel@tonic-gate 		return (-1);
1600*0Sstevel@tonic-gate 
1601*0Sstevel@tonic-gate 	/* save new binding incase this is a rebind where oldnp==newnp */
1602*0Sstevel@tonic-gate 	new_dev = newnp->dev;
1603*0Sstevel@tonic-gate 	new_start_blk = newnp->start_blk;
1604*0Sstevel@tonic-gate 	new_end_blk = newnp->end_blk;
1605*0Sstevel@tonic-gate 
1606*0Sstevel@tonic-gate 	/* invalidate, then get the raid (fill in oldnp from metadb) */
1607*0Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
1608*0Sstevel@tonic-gate 	if (meta_get_raid(sp, raidnp, ep) == NULL)
1609*0Sstevel@tonic-gate 		return (-1);
1610*0Sstevel@tonic-gate 
1611*0Sstevel@tonic-gate 	/* can't replace a component if the raid inaccessible */
1612*0Sstevel@tonic-gate 	if (meta_get_tstate(raidnp->dev, &tstate, ep) != 0) {
1613*0Sstevel@tonic-gate 		return (-1);
1614*0Sstevel@tonic-gate 	}
1615*0Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
1616*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_UNAVAIL_STATE,
1617*0Sstevel@tonic-gate 		    meta_getminor(raidnp->dev), raidnp->cname));
1618*0Sstevel@tonic-gate 	}
1619*0Sstevel@tonic-gate 
1620*0Sstevel@tonic-gate 	/* the old device binding is now established */
1621*0Sstevel@tonic-gate 	if ((old_dev = oldnp->dev) == NODEV64)
1622*0Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, oldnp->cname));
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate 
1625*0Sstevel@tonic-gate 	/* setup raid info */
1626*0Sstevel@tonic-gate 	(void) memset(&params, 0, sizeof (params));
1627*0Sstevel@tonic-gate 	params.mnum = meta_getminor(raidnp->dev);
1628*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&params, MD_RAID, sp->setno);
1629*0Sstevel@tonic-gate 	params.old_dev = old_dev;
1630*0Sstevel@tonic-gate 	params.cmd = force ? FORCE_REPLACE_COMP : REPLACE_COMP;
1631*0Sstevel@tonic-gate 
1632*0Sstevel@tonic-gate 	if (options & MDCMD_CLUSTER_REPLACE) {
1633*0Sstevel@tonic-gate 		if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
1634*0Sstevel@tonic-gate 			return (NULL);
1635*0Sstevel@tonic-gate 		Free(mr);
1636*0Sstevel@tonic-gate 		params.options = MDIOCTL_NO_RESYNC_RAID;
1637*0Sstevel@tonic-gate 		params.number_blks = metagetsize(newnp, ep);
1638*0Sstevel@tonic-gate 		if ((metagetlabel(newnp, ep) == MD_DISKADDR_ERROR) ||
1639*0Sstevel@tonic-gate 		    (metagetlabel(newnp, ep) == 0))
1640*0Sstevel@tonic-gate 			params.has_label = 0;
1641*0Sstevel@tonic-gate 		else
1642*0Sstevel@tonic-gate 			params.has_label = 1;
1643*0Sstevel@tonic-gate 		params.start_blk = metagetstart(sp, newnp, ep);
1644*0Sstevel@tonic-gate 	} else {
1645*0Sstevel@tonic-gate 		if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
1646*0Sstevel@tonic-gate 		    (old_dev != new_dev)) {
1647*0Sstevel@tonic-gate 			rebind = 1;
1648*0Sstevel@tonic-gate 		} else {
1649*0Sstevel@tonic-gate 			rebind = 0;
1650*0Sstevel@tonic-gate 		}
1651*0Sstevel@tonic-gate 		if (rebind) {
1652*0Sstevel@tonic-gate 			newnp->dev = new_dev;
1653*0Sstevel@tonic-gate 			newnp->start_blk = new_start_blk;
1654*0Sstevel@tonic-gate 			newnp->end_blk = new_end_blk;
1655*0Sstevel@tonic-gate 		}
1656*0Sstevel@tonic-gate 
1657*0Sstevel@tonic-gate 		/*
1658*0Sstevel@tonic-gate 		 * Save a copy of the devid associated with the new disk, the
1659*0Sstevel@tonic-gate 		 * reason is that the checks for the column (meta_check_column)
1660*0Sstevel@tonic-gate 		 * via validate_new_raid(), could cause the disk's devid to be
1661*0Sstevel@tonic-gate 		 * changed to that of the devid that is currently stored in the
1662*0Sstevel@tonic-gate 		 * replica namespace for the disk in question. This devid could
1663*0Sstevel@tonic-gate 		 * be stale if we are replacing the disk. The actual function
1664*0Sstevel@tonic-gate 		 * that overwrites the devid is dr2drivedesc().
1665*0Sstevel@tonic-gate 		 */
1666*0Sstevel@tonic-gate 
1667*0Sstevel@tonic-gate 		/* don't setup new_devid if no devid's or MN diskset */
1668*0Sstevel@tonic-gate 		if (newnp->drivenamep->devid != NULL)
1669*0Sstevel@tonic-gate 			new_devidp = Strdup(newnp->drivenamep->devid);
1670*0Sstevel@tonic-gate 
1671*0Sstevel@tonic-gate 		if (!metaislocalset(sp)) {
1672*0Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL)
1673*0Sstevel@tonic-gate 				return (-1);
1674*0Sstevel@tonic-gate 			if (MD_MNSET_DESC(sd))
1675*0Sstevel@tonic-gate 				new_devidp = NULL;
1676*0Sstevel@tonic-gate 		}
1677*0Sstevel@tonic-gate 
1678*0Sstevel@tonic-gate 		/* check out new (sets up start_blk, has_label, number_blks) */
1679*0Sstevel@tonic-gate 		if (validate_new_raid(sp, raidnp, newnp, &params, rebind,
1680*0Sstevel@tonic-gate 		    ep) != 0) {
1681*0Sstevel@tonic-gate 			Free(new_devidp);
1682*0Sstevel@tonic-gate 			return (-1);
1683*0Sstevel@tonic-gate 		}
1684*0Sstevel@tonic-gate 
1685*0Sstevel@tonic-gate 		/*
1686*0Sstevel@tonic-gate 		 * Copy back the saved devid.
1687*0Sstevel@tonic-gate 		 */
1688*0Sstevel@tonic-gate 		Free(newnp->drivenamep->devid);
1689*0Sstevel@tonic-gate 		if (new_devidp) {
1690*0Sstevel@tonic-gate 			newnp->drivenamep->devid = Strdup(new_devidp);
1691*0Sstevel@tonic-gate 			Free(new_devidp);
1692*0Sstevel@tonic-gate 		}
1693*0Sstevel@tonic-gate 	}
1694*0Sstevel@tonic-gate 
1695*0Sstevel@tonic-gate 	/* store name in namespace, allocate new key */
1696*0Sstevel@tonic-gate 	if (add_key_name(sp, newnp, NULL, ep) != 0)
1697*0Sstevel@tonic-gate 		return (-1);
1698*0Sstevel@tonic-gate 
1699*0Sstevel@tonic-gate 	if (rebind && !metaislocalset(sp)) {
1700*0Sstevel@tonic-gate 		/*
1701*0Sstevel@tonic-gate 		 * We are 'rebind'ing a disk that is in a diskset so as well
1702*0Sstevel@tonic-gate 		 * as updating the diskset's namespace the local set needs
1703*0Sstevel@tonic-gate 		 * to be updated because it also contains a reference to the
1704*0Sstevel@tonic-gate 		 * disk in question.
1705*0Sstevel@tonic-gate 		 */
1706*0Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
1707*0Sstevel@tonic-gate 		    newnp->cname, ep);
1708*0Sstevel@tonic-gate 
1709*0Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
1710*0Sstevel@tonic-gate 			(void) del_key_name(sp, newnp, &xep);
1711*0Sstevel@tonic-gate 			return (-1);
1712*0Sstevel@tonic-gate 		}
1713*0Sstevel@tonic-gate 	}
1714*0Sstevel@tonic-gate 
1715*0Sstevel@tonic-gate 	/* replace column */
1716*0Sstevel@tonic-gate 	params.new_dev = new_dev;
1717*0Sstevel@tonic-gate 	params.new_key = newnp->key;
1718*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0) {
1719*0Sstevel@tonic-gate 		(void) del_key_name(sp, newnp, ep);
1720*0Sstevel@tonic-gate 		return (mdstealerror(ep, &params.mde));
1721*0Sstevel@tonic-gate 	}
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 	/* clear cache */
1724*0Sstevel@tonic-gate 	meta_invalidate_name(oldnp);
1725*0Sstevel@tonic-gate 	meta_invalidate_name(newnp);
1726*0Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
1727*0Sstevel@tonic-gate 
1728*0Sstevel@tonic-gate 	/* let em know */
1729*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
1730*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
1731*0Sstevel@tonic-gate 		    "%s: device %s is replaced with %s\n"),
1732*0Sstevel@tonic-gate 		    raidnp->cname, oldnp->cname, newnp->cname);
1733*0Sstevel@tonic-gate 		(void) fflush(stdout);
1734*0Sstevel@tonic-gate 	}
1735*0Sstevel@tonic-gate 
1736*0Sstevel@tonic-gate 	/* return success */
1737*0Sstevel@tonic-gate 	return (0);
1738*0Sstevel@tonic-gate }
1739*0Sstevel@tonic-gate 
1740*0Sstevel@tonic-gate /*
1741*0Sstevel@tonic-gate  * enable raid column
1742*0Sstevel@tonic-gate  */
1743*0Sstevel@tonic-gate int
1744*0Sstevel@tonic-gate meta_raid_enable(
1745*0Sstevel@tonic-gate 	mdsetname_t		*sp,
1746*0Sstevel@tonic-gate 	mdname_t		*raidnp,
1747*0Sstevel@tonic-gate 	mdname_t		*colnp,
1748*0Sstevel@tonic-gate 	mdcmdopts_t		options,
1749*0Sstevel@tonic-gate 	md_error_t		*ep
1750*0Sstevel@tonic-gate )
1751*0Sstevel@tonic-gate {
1752*0Sstevel@tonic-gate 	int			force = ((options & MDCMD_FORCE) ? 1 : 0);
1753*0Sstevel@tonic-gate 	replace_params_t	params;
1754*0Sstevel@tonic-gate 	md_dev64_t		fs_dev, del_dev;
1755*0Sstevel@tonic-gate 	int			err = 0;
1756*0Sstevel@tonic-gate 	char			*devnm;
1757*0Sstevel@tonic-gate 	int			ret;
1758*0Sstevel@tonic-gate 	uint_t			tstate;
1759*0Sstevel@tonic-gate 
1760*0Sstevel@tonic-gate 	/* should have same set */
1761*0Sstevel@tonic-gate 	assert(sp != NULL);
1762*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
1763*0Sstevel@tonic-gate 
1764*0Sstevel@tonic-gate 	/* check name */
1765*0Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
1766*0Sstevel@tonic-gate 		return (-1);
1767*0Sstevel@tonic-gate 
1768*0Sstevel@tonic-gate 	/* get the file_system dev binding */
1769*0Sstevel@tonic-gate 	if (meta_getdev(sp, colnp, ep) != 0)
1770*0Sstevel@tonic-gate 		return (-1);
1771*0Sstevel@tonic-gate 	fs_dev = colnp->dev;
1772*0Sstevel@tonic-gate 
1773*0Sstevel@tonic-gate 	/* get the raid unit (fill in colnp->dev with metadb version) */
1774*0Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
1775*0Sstevel@tonic-gate 	if (meta_get_raid(sp, raidnp, ep) == NULL)
1776*0Sstevel@tonic-gate 		return (-1);
1777*0Sstevel@tonic-gate 
1778*0Sstevel@tonic-gate 	/* enabling a component can't work if the raid inaccessible */
1779*0Sstevel@tonic-gate 	if (meta_get_tstate(raidnp->dev, &tstate, ep) != 0) {
1780*0Sstevel@tonic-gate 		return (-1);
1781*0Sstevel@tonic-gate 	}
1782*0Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
1783*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_UNAVAIL_STATE,
1784*0Sstevel@tonic-gate 		    meta_getminor(raidnp->dev), raidnp->cname));
1785*0Sstevel@tonic-gate 	}
1786*0Sstevel@tonic-gate 
1787*0Sstevel@tonic-gate 	/* the metadb device binding is now established */
1788*0Sstevel@tonic-gate 	if (colnp->dev == NODEV64)
1789*0Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, colnp->cname));
1790*0Sstevel@tonic-gate 
1791*0Sstevel@tonic-gate 	/*
1792*0Sstevel@tonic-gate 	 * check for the case where the dev_t has changed between the
1793*0Sstevel@tonic-gate 	 * filesystem and the metadb.  This is called a rebind, and
1794*0Sstevel@tonic-gate 	 * is handled by meta_raid_replace.
1795*0Sstevel@tonic-gate 	 */
1796*0Sstevel@tonic-gate 	if (fs_dev != colnp->dev) {
1797*0Sstevel@tonic-gate 		/*
1798*0Sstevel@tonic-gate 		 * Save the devt of mddb version
1799*0Sstevel@tonic-gate 		 */
1800*0Sstevel@tonic-gate 		del_dev = colnp->dev;
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 		/* establish file system binding with invalid start/end */
1803*0Sstevel@tonic-gate 		colnp->dev = fs_dev;
1804*0Sstevel@tonic-gate 		colnp->start_blk = -1;
1805*0Sstevel@tonic-gate 		colnp->end_blk = -1;
1806*0Sstevel@tonic-gate 		err = meta_raid_replace(sp, raidnp, colnp, colnp, options, ep);
1807*0Sstevel@tonic-gate 
1808*0Sstevel@tonic-gate 		/*
1809*0Sstevel@tonic-gate 		 * Don't do it if meta_raid_replace returns an error
1810*0Sstevel@tonic-gate 		 */
1811*0Sstevel@tonic-gate 		if (!err && (devnm = meta_getnmentbydev(sp->setno, MD_SIDEWILD,
1812*0Sstevel@tonic-gate 			del_dev, NULL, NULL, &colnp->key, ep)) != NULL) {
1813*0Sstevel@tonic-gate 			(void) del_key_name(sp, colnp, ep);
1814*0Sstevel@tonic-gate 			Free(devnm);
1815*0Sstevel@tonic-gate 		}
1816*0Sstevel@tonic-gate 		return (err);
1817*0Sstevel@tonic-gate 	}
1818*0Sstevel@tonic-gate 
1819*0Sstevel@tonic-gate 	/* setup raid info */
1820*0Sstevel@tonic-gate 	(void) memset(&params, 0, sizeof (params));
1821*0Sstevel@tonic-gate 	params.mnum = meta_getminor(raidnp->dev);
1822*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&params, MD_RAID, sp->setno);
1823*0Sstevel@tonic-gate 	params.old_dev = params.new_dev = colnp->dev;
1824*0Sstevel@tonic-gate 	if (force)
1825*0Sstevel@tonic-gate 		params.cmd = FORCE_ENABLE_COMP;
1826*0Sstevel@tonic-gate 	else
1827*0Sstevel@tonic-gate 		params.cmd = ENABLE_COMP;
1828*0Sstevel@tonic-gate 
1829*0Sstevel@tonic-gate 	/* check it out */
1830*0Sstevel@tonic-gate 	if (validate_new_raid(sp, raidnp, colnp, &params, 1, ep) != 0)
1831*0Sstevel@tonic-gate 		return (-1);
1832*0Sstevel@tonic-gate 
1833*0Sstevel@tonic-gate 	/* enable column */
1834*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0)
1835*0Sstevel@tonic-gate 		return (mdstealerror(ep, &params.mde));
1836*0Sstevel@tonic-gate 
1837*0Sstevel@tonic-gate 	/*
1838*0Sstevel@tonic-gate 	 * are we dealing with a non-local set? If so need to update the
1839*0Sstevel@tonic-gate 	 * local namespace so that the disk record has the correct devid.
1840*0Sstevel@tonic-gate 	 */
1841*0Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
1842*0Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, colnp->cname,
1843*0Sstevel@tonic-gate 		    ep);
1844*0Sstevel@tonic-gate 
1845*0Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
1846*0Sstevel@tonic-gate 			/*
1847*0Sstevel@tonic-gate 			 * Failed to update the local set. Nothing to do here
1848*0Sstevel@tonic-gate 			 * apart from report the error. The namespace is
1849*0Sstevel@tonic-gate 			 * most likely broken and some form of remedial
1850*0Sstevel@tonic-gate 			 * recovery is going to be required.
1851*0Sstevel@tonic-gate 			 */
1852*0Sstevel@tonic-gate 			mde_perror(ep, "");
1853*0Sstevel@tonic-gate 			mdclrerror(ep);
1854*0Sstevel@tonic-gate 		}
1855*0Sstevel@tonic-gate 	}
1856*0Sstevel@tonic-gate 
1857*0Sstevel@tonic-gate 	/* clear cache */
1858*0Sstevel@tonic-gate 	meta_invalidate_name(colnp);
1859*0Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
1860*0Sstevel@tonic-gate 
1861*0Sstevel@tonic-gate 	/* let em know */
1862*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
1863*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
1864*0Sstevel@tonic-gate 		    "%s: device %s is enabled\n"),
1865*0Sstevel@tonic-gate 		    raidnp->cname, colnp->cname);
1866*0Sstevel@tonic-gate 		(void) fflush(stdout);
1867*0Sstevel@tonic-gate 	}
1868*0Sstevel@tonic-gate 
1869*0Sstevel@tonic-gate 	/* return success */
1870*0Sstevel@tonic-gate 	return (0);
1871*0Sstevel@tonic-gate }
1872*0Sstevel@tonic-gate 
1873*0Sstevel@tonic-gate /*
1874*0Sstevel@tonic-gate  * check for dups in the raid itself
1875*0Sstevel@tonic-gate  */
1876*0Sstevel@tonic-gate static int
1877*0Sstevel@tonic-gate check_twice(
1878*0Sstevel@tonic-gate 	md_raid_t	*raidp,
1879*0Sstevel@tonic-gate 	uint_t		col,
1880*0Sstevel@tonic-gate 	md_error_t	*ep
1881*0Sstevel@tonic-gate )
1882*0Sstevel@tonic-gate {
1883*0Sstevel@tonic-gate 	mdname_t	*raidnp = raidp->common.namep;
1884*0Sstevel@tonic-gate 	mdname_t	*thisnp;
1885*0Sstevel@tonic-gate 	uint_t		c;
1886*0Sstevel@tonic-gate 
1887*0Sstevel@tonic-gate 	thisnp = raidp->cols.cols_val[col].colnamep;
1888*0Sstevel@tonic-gate 	for (c = 0; (c < col); ++c) {
1889*0Sstevel@tonic-gate 		md_raidcol_t	*mdcp = &raidp->cols.cols_val[c];
1890*0Sstevel@tonic-gate 		mdname_t	*colnp = mdcp->colnamep;
1891*0Sstevel@tonic-gate 
1892*0Sstevel@tonic-gate 		if (meta_check_overlap(raidnp->cname, thisnp, 0, -1,
1893*0Sstevel@tonic-gate 		    colnp, 0, -1, ep) != 0) {
1894*0Sstevel@tonic-gate 			return (-1);
1895*0Sstevel@tonic-gate 		}
1896*0Sstevel@tonic-gate 	}
1897*0Sstevel@tonic-gate 	return (0);
1898*0Sstevel@tonic-gate }
1899*0Sstevel@tonic-gate 
1900*0Sstevel@tonic-gate /*
1901*0Sstevel@tonic-gate  * default raid interlace
1902*0Sstevel@tonic-gate  */
1903*0Sstevel@tonic-gate diskaddr_t
1904*0Sstevel@tonic-gate meta_default_raid_interlace(void)
1905*0Sstevel@tonic-gate {
1906*0Sstevel@tonic-gate 	diskaddr_t	interlace;
1907*0Sstevel@tonic-gate 
1908*0Sstevel@tonic-gate 	/* default to 16k, round up if necessary */
1909*0Sstevel@tonic-gate 	interlace = btodb(16 * 1024);
1910*0Sstevel@tonic-gate 	if (interlace < lbtodb(MININTERLACE))
1911*0Sstevel@tonic-gate 		interlace = roundup(MININTERLACE, interlace);
1912*0Sstevel@tonic-gate 	return (interlace);
1913*0Sstevel@tonic-gate }
1914*0Sstevel@tonic-gate 
1915*0Sstevel@tonic-gate /*
1916*0Sstevel@tonic-gate  * convert interlaces
1917*0Sstevel@tonic-gate  */
1918*0Sstevel@tonic-gate int
1919*0Sstevel@tonic-gate meta_raid_check_interlace(
1920*0Sstevel@tonic-gate 	diskaddr_t	interlace,
1921*0Sstevel@tonic-gate 	char		*uname,
1922*0Sstevel@tonic-gate 	md_error_t	*ep
1923*0Sstevel@tonic-gate )
1924*0Sstevel@tonic-gate {
1925*0Sstevel@tonic-gate 	if ((interlace < btodb(RAID_MIN_INTERLACE)) ||
1926*0Sstevel@tonic-gate 	    (interlace > btodb(MAXINTERLACE))) {
1927*0Sstevel@tonic-gate 		return (mderror(ep, MDE_BAD_INTERLACE, uname));
1928*0Sstevel@tonic-gate 	}
1929*0Sstevel@tonic-gate 	return (0);
1930*0Sstevel@tonic-gate }
1931*0Sstevel@tonic-gate 
1932*0Sstevel@tonic-gate /*
1933*0Sstevel@tonic-gate  * check raid
1934*0Sstevel@tonic-gate  */
1935*0Sstevel@tonic-gate int
1936*0Sstevel@tonic-gate meta_check_raid(
1937*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1938*0Sstevel@tonic-gate 	md_raid_t	*raidp,
1939*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1940*0Sstevel@tonic-gate 	md_error_t	*ep
1941*0Sstevel@tonic-gate )
1942*0Sstevel@tonic-gate {
1943*0Sstevel@tonic-gate 	mdname_t	*raidnp = raidp->common.namep;
1944*0Sstevel@tonic-gate 	int		doit = ((options & MDCMD_DOIT) ? 1 : 0);
1945*0Sstevel@tonic-gate 	int		updateit = ((options & MDCMD_UPDATE) ? 1 : 0);
1946*0Sstevel@tonic-gate 	uint_t		ncol;
1947*0Sstevel@tonic-gate 	uint_t		col;
1948*0Sstevel@tonic-gate 	minor_t		mnum = meta_getminor(raidnp->dev);
1949*0Sstevel@tonic-gate 
1950*0Sstevel@tonic-gate 	/* check number */
1951*0Sstevel@tonic-gate 	if (((ncol = raidp->cols.cols_len) < MD_RAID_MIN) ||
1952*0Sstevel@tonic-gate 	    (raidp->orig_ncol > ncol)) {
1953*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_BAD_RAID, mnum, raidnp->cname));
1954*0Sstevel@tonic-gate 	}
1955*0Sstevel@tonic-gate 
1956*0Sstevel@tonic-gate 	/* compute default interlace */
1957*0Sstevel@tonic-gate 	if (raidp->interlace == 0) {
1958*0Sstevel@tonic-gate 		raidp->interlace = meta_default_raid_interlace();
1959*0Sstevel@tonic-gate 	}
1960*0Sstevel@tonic-gate 
1961*0Sstevel@tonic-gate 	/* check state */
1962*0Sstevel@tonic-gate 	switch (raidp->state) {
1963*0Sstevel@tonic-gate 	case RUS_INIT:
1964*0Sstevel@tonic-gate 	case RUS_OKAY:
1965*0Sstevel@tonic-gate 		break;
1966*0Sstevel@tonic-gate 
1967*0Sstevel@tonic-gate 	default:
1968*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_BAD_RAID, mnum, raidnp->cname));
1969*0Sstevel@tonic-gate 	}
1970*0Sstevel@tonic-gate 
1971*0Sstevel@tonic-gate 	/* check interlace */
1972*0Sstevel@tonic-gate 	if (meta_raid_check_interlace(raidp->interlace, raidnp->cname, ep) != 0)
1973*0Sstevel@tonic-gate 		return (-1);
1974*0Sstevel@tonic-gate 
1975*0Sstevel@tonic-gate 	/* check hotspare pool name */
1976*0Sstevel@tonic-gate 	if (doit) {
1977*0Sstevel@tonic-gate 		if ((raidp->hspnamep != NULL) &&
1978*0Sstevel@tonic-gate 		    (metachkhsp(sp, raidp->hspnamep, ep) != 0)) {
1979*0Sstevel@tonic-gate 			return (-1);
1980*0Sstevel@tonic-gate 		}
1981*0Sstevel@tonic-gate 	}
1982*0Sstevel@tonic-gate 
1983*0Sstevel@tonic-gate 	/* check columns */
1984*0Sstevel@tonic-gate 	for (col = 0; (col < ncol); ++col) {
1985*0Sstevel@tonic-gate 		md_raidcol_t	*mdcp = &raidp->cols.cols_val[col];
1986*0Sstevel@tonic-gate 		mdname_t	*colnp = mdcp->colnamep;
1987*0Sstevel@tonic-gate 		diskaddr_t	start_blk, size;
1988*0Sstevel@tonic-gate 
1989*0Sstevel@tonic-gate 		/* setup column */
1990*0Sstevel@tonic-gate 		if (raidp->state == RUS_INIT)
1991*0Sstevel@tonic-gate 			mdcp->state = RCS_INIT;
1992*0Sstevel@tonic-gate 		else
1993*0Sstevel@tonic-gate 			mdcp->state = RCS_OKAY;
1994*0Sstevel@tonic-gate 
1995*0Sstevel@tonic-gate 		/* check column */
1996*0Sstevel@tonic-gate 		if (!updateit) {
1997*0Sstevel@tonic-gate 			if (meta_check_column(sp, colnp, ep) != 0)
1998*0Sstevel@tonic-gate 				return (-1);
1999*0Sstevel@tonic-gate 			if (((start_blk = metagetstart(sp, colnp, ep)) ==
2000*0Sstevel@tonic-gate 			    MD_DISKADDR_ERROR) || ((size = metagetsize(colnp,
2001*0Sstevel@tonic-gate 			    ep)) == MD_DISKADDR_ERROR)) {
2002*0Sstevel@tonic-gate 				return (-1);
2003*0Sstevel@tonic-gate 			}
2004*0Sstevel@tonic-gate 			if (start_blk >= size)
2005*0Sstevel@tonic-gate 				return (mdsyserror(ep, ENOSPC, colnp->cname));
2006*0Sstevel@tonic-gate 			size -= start_blk;
2007*0Sstevel@tonic-gate 			size = rounddown(size, raidp->interlace);
2008*0Sstevel@tonic-gate 			if (size == 0)
2009*0Sstevel@tonic-gate 				return (mdsyserror(ep, ENOSPC, colnp->cname));
2010*0Sstevel@tonic-gate 		}
2011*0Sstevel@tonic-gate 
2012*0Sstevel@tonic-gate 		/* check this raid too */
2013*0Sstevel@tonic-gate 		if (check_twice(raidp, col, ep) != 0)
2014*0Sstevel@tonic-gate 			return (-1);
2015*0Sstevel@tonic-gate 	}
2016*0Sstevel@tonic-gate 
2017*0Sstevel@tonic-gate 	/* return success */
2018*0Sstevel@tonic-gate 	return (0);
2019*0Sstevel@tonic-gate }
2020*0Sstevel@tonic-gate 
2021*0Sstevel@tonic-gate /*
2022*0Sstevel@tonic-gate  * setup raid geometry
2023*0Sstevel@tonic-gate  */
2024*0Sstevel@tonic-gate static int
2025*0Sstevel@tonic-gate raid_geom(
2026*0Sstevel@tonic-gate 	md_raid_t	*raidp,
2027*0Sstevel@tonic-gate 	mr_unit_t	*mr,
2028*0Sstevel@tonic-gate 	md_error_t	*ep
2029*0Sstevel@tonic-gate )
2030*0Sstevel@tonic-gate {
2031*0Sstevel@tonic-gate 	uint_t		write_reinstruct = 0;
2032*0Sstevel@tonic-gate 	uint_t		read_reinstruct = 0;
2033*0Sstevel@tonic-gate 	uint_t		round_cyl = 1;
2034*0Sstevel@tonic-gate 	uint_t		col;
2035*0Sstevel@tonic-gate 	mdgeom_t	*geomp;
2036*0Sstevel@tonic-gate 
2037*0Sstevel@tonic-gate 	/* get worst reinstructs */
2038*0Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
2039*0Sstevel@tonic-gate 		md_raidcol_t	*mdcp = &raidp->cols.cols_val[col];
2040*0Sstevel@tonic-gate 		mdname_t	*colnp = mdcp->colnamep;
2041*0Sstevel@tonic-gate 
2042*0Sstevel@tonic-gate 		if ((geomp = metagetgeom(colnp, ep)) == NULL)
2043*0Sstevel@tonic-gate 			return (-1);
2044*0Sstevel@tonic-gate 		if (geomp->write_reinstruct > write_reinstruct)
2045*0Sstevel@tonic-gate 			write_reinstruct = geomp->write_reinstruct;
2046*0Sstevel@tonic-gate 		if (geomp->read_reinstruct > read_reinstruct)
2047*0Sstevel@tonic-gate 			read_reinstruct = geomp->read_reinstruct;
2048*0Sstevel@tonic-gate 	}
2049*0Sstevel@tonic-gate 
2050*0Sstevel@tonic-gate 	/* setup geometry from first column */
2051*0Sstevel@tonic-gate 	assert(raidp->cols.cols_len > 0);
2052*0Sstevel@tonic-gate 	if ((geomp = metagetgeom(raidp->cols.cols_val[0].colnamep,
2053*0Sstevel@tonic-gate 	    ep)) == NULL) {
2054*0Sstevel@tonic-gate 		return (-1);
2055*0Sstevel@tonic-gate 	}
2056*0Sstevel@tonic-gate 	if (meta_setup_geom((md_unit_t *)mr, raidp->common.namep, geomp,
2057*0Sstevel@tonic-gate 	    write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
2058*0Sstevel@tonic-gate 		return (-1);
2059*0Sstevel@tonic-gate 
2060*0Sstevel@tonic-gate 	/* return success */
2061*0Sstevel@tonic-gate 	return (0);
2062*0Sstevel@tonic-gate }
2063*0Sstevel@tonic-gate 
2064*0Sstevel@tonic-gate int
2065*0Sstevel@tonic-gate meta_raid_state_cnt(mr_unit_t *mr, rcs_state_t state)
2066*0Sstevel@tonic-gate {
2067*0Sstevel@tonic-gate 	int 	statecnt = 0;
2068*0Sstevel@tonic-gate 	int	col;
2069*0Sstevel@tonic-gate 
2070*0Sstevel@tonic-gate 	for (col = 0; col < mr->un_totalcolumncnt; col++)
2071*0Sstevel@tonic-gate 		if (mr->un_column[col].un_devstate & state)
2072*0Sstevel@tonic-gate 			statecnt++;
2073*0Sstevel@tonic-gate 	return (statecnt);
2074*0Sstevel@tonic-gate }
2075*0Sstevel@tonic-gate /*
2076*0Sstevel@tonic-gate  * validate that a raid device being created with the -k flag is a real
2077*0Sstevel@tonic-gate  * raid device
2078*0Sstevel@tonic-gate  */
2079*0Sstevel@tonic-gate int
2080*0Sstevel@tonic-gate meta_raid_valid(md_raid_t *raidp, mr_unit_t *mr)
2081*0Sstevel@tonic-gate {
2082*0Sstevel@tonic-gate 	long long	buf[DEV_BSIZE / sizeof (long long)];
2083*0Sstevel@tonic-gate 	raid_pwhdr_t	pwhdr;
2084*0Sstevel@tonic-gate 	raid_pwhdr_t	*rpw = &pwhdr;
2085*0Sstevel@tonic-gate 	minor_t		mnum;
2086*0Sstevel@tonic-gate 	int		col;
2087*0Sstevel@tonic-gate 	int		fd;
2088*0Sstevel@tonic-gate 
2089*0Sstevel@tonic-gate 	for (col = 0; col < mr->un_totalcolumncnt; col++) {
2090*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
2091*0Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
2092*0Sstevel@tonic-gate 
2093*0Sstevel@tonic-gate 		if ((fd = open(colnp->rname, O_RDONLY)) < 0)
2094*0Sstevel@tonic-gate 			goto error_exit;
2095*0Sstevel@tonic-gate 
2096*0Sstevel@tonic-gate 		if (lseek64(fd,
2097*0Sstevel@tonic-gate 		    (mr->un_column[col].un_pwstart * DEV_BSIZE), SEEK_SET) < 0)
2098*0Sstevel@tonic-gate 			goto error_exit;
2099*0Sstevel@tonic-gate 
2100*0Sstevel@tonic-gate 		if (read(fd, buf, DEV_BSIZE) < 0)
2101*0Sstevel@tonic-gate 			goto error_exit;
2102*0Sstevel@tonic-gate 
2103*0Sstevel@tonic-gate 		/*
2104*0Sstevel@tonic-gate 		 * If our raid device is a 64 bit device, we can accept the
2105*0Sstevel@tonic-gate 		 * pw header we just read in.
2106*0Sstevel@tonic-gate 		 * Otherwise it's of type raid_pwhdr32_od_t and has to
2107*0Sstevel@tonic-gate 		 * be converted.
2108*0Sstevel@tonic-gate 		 */
2109*0Sstevel@tonic-gate 		if (mr->c.un_revision == MD_64BIT_META_DEV) {
2110*0Sstevel@tonic-gate 			rpw = (raid_pwhdr_t *)buf;
2111*0Sstevel@tonic-gate 		} else {
2112*0Sstevel@tonic-gate 			RAID_CONVERT_RPW((raid_pwhdr32_od_t *)buf, rpw);
2113*0Sstevel@tonic-gate 		}
2114*0Sstevel@tonic-gate 
2115*0Sstevel@tonic-gate 		if (rpw->rpw_column != col)
2116*0Sstevel@tonic-gate 			goto error_exit;
2117*0Sstevel@tonic-gate 
2118*0Sstevel@tonic-gate 		if (col == 0)
2119*0Sstevel@tonic-gate 			mnum = rpw->rpw_unit;
2120*0Sstevel@tonic-gate 
2121*0Sstevel@tonic-gate 		if (rpw->rpw_unit != mnum)
2122*0Sstevel@tonic-gate 			goto error_exit;
2123*0Sstevel@tonic-gate 
2124*0Sstevel@tonic-gate 		if (rpw->rpw_magic_ext == RAID_PWMAGIC) {
2125*0Sstevel@tonic-gate 			/* 4.1 prewrite header */
2126*0Sstevel@tonic-gate 			if ((rpw->rpw_origcolumncnt != mr->un_origcolumncnt) ||
2127*0Sstevel@tonic-gate 			    (rpw->rpw_totalcolumncnt
2128*0Sstevel@tonic-gate 				!= mr->un_totalcolumncnt) ||
2129*0Sstevel@tonic-gate 			    (rpw->rpw_segsize != mr->un_segsize) ||
2130*0Sstevel@tonic-gate 			    (rpw->rpw_segsincolumn != mr->un_segsincolumn) ||
2131*0Sstevel@tonic-gate 			    (rpw->rpw_pwcnt != mr->un_pwcnt) ||
2132*0Sstevel@tonic-gate 			    (rpw->rpw_pwstart !=
2133*0Sstevel@tonic-gate 				mr->un_column[col].un_pwstart) ||
2134*0Sstevel@tonic-gate 			    (rpw->rpw_devstart !=
2135*0Sstevel@tonic-gate 				mr->un_column[col].un_devstart) ||
2136*0Sstevel@tonic-gate 			    (rpw->rpw_pwsize != mr->un_pwsize))
2137*0Sstevel@tonic-gate 				goto error_exit;
2138*0Sstevel@tonic-gate 		}
2139*0Sstevel@tonic-gate 		/*
2140*0Sstevel@tonic-gate 		 * this is an old prewrite header (4.0) the unit structure
2141*0Sstevel@tonic-gate 		 * will have to be trusted.
2142*0Sstevel@tonic-gate 		 */
2143*0Sstevel@tonic-gate 		(void) close(fd);
2144*0Sstevel@tonic-gate 	}
2145*0Sstevel@tonic-gate 
2146*0Sstevel@tonic-gate 	return (0);
2147*0Sstevel@tonic-gate 
2148*0Sstevel@tonic-gate error_exit:
2149*0Sstevel@tonic-gate 	(void) close(fd);
2150*0Sstevel@tonic-gate 	return (-1);
2151*0Sstevel@tonic-gate }
2152*0Sstevel@tonic-gate 
2153*0Sstevel@tonic-gate /*
2154*0Sstevel@tonic-gate  * create raid
2155*0Sstevel@tonic-gate  */
2156*0Sstevel@tonic-gate int
2157*0Sstevel@tonic-gate meta_create_raid(
2158*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2159*0Sstevel@tonic-gate 	md_raid_t	*raidp,
2160*0Sstevel@tonic-gate 	mdcmdopts_t	options,
2161*0Sstevel@tonic-gate 	md_error_t	*ep
2162*0Sstevel@tonic-gate )
2163*0Sstevel@tonic-gate {
2164*0Sstevel@tonic-gate 	mdname_t	*raidnp = raidp->common.namep;
2165*0Sstevel@tonic-gate 	uint_t		ncol = raidp->cols.cols_len;
2166*0Sstevel@tonic-gate 	uint_t		orig_ncol = raidp->orig_ncol;
2167*0Sstevel@tonic-gate 	size_t		rdsize;
2168*0Sstevel@tonic-gate 	mr_unit_t	*mr;
2169*0Sstevel@tonic-gate 	uint_t		col;
2170*0Sstevel@tonic-gate 	diskaddr_t	disk_size = 0;
2171*0Sstevel@tonic-gate 	uint_t		disk_maxio = 0;
2172*0Sstevel@tonic-gate 	uint_t		pwes;
2173*0Sstevel@tonic-gate 	diskaddr_t	non_pw_blks, column_size;
2174*0Sstevel@tonic-gate 	mdnamelist_t	*keynlp = NULL;
2175*0Sstevel@tonic-gate 	md_set_params_t	set_params;
2176*0Sstevel@tonic-gate 	int		rval = -1;
2177*0Sstevel@tonic-gate 	md_timeval32_t	creation_time;
2178*0Sstevel@tonic-gate 	int		create_flag = MD_CRO_32BIT;
2179*0Sstevel@tonic-gate 
2180*0Sstevel@tonic-gate 	/* validate raid */
2181*0Sstevel@tonic-gate 	if (meta_check_raid(sp, raidp, options, ep) != 0)
2182*0Sstevel@tonic-gate 		return (-1);
2183*0Sstevel@tonic-gate 
2184*0Sstevel@tonic-gate 	/* allocate raid unit */
2185*0Sstevel@tonic-gate 	rdsize = sizeof (*mr) - sizeof (mr->un_column[0]);
2186*0Sstevel@tonic-gate 	rdsize += ncol * sizeof (mr->un_column[0]);
2187*0Sstevel@tonic-gate 	mr = Zalloc(rdsize);
2188*0Sstevel@tonic-gate 
2189*0Sstevel@tonic-gate 	if (meta_gettimeofday(&creation_time) == -1)
2190*0Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
2191*0Sstevel@tonic-gate 	/*
2192*0Sstevel@tonic-gate 	 * initialize the top level mr_unit_t structure
2193*0Sstevel@tonic-gate 	 * setup the unit state to indicate whether to retain
2194*0Sstevel@tonic-gate 	 * any data currently on the metadevice or to clear it
2195*0Sstevel@tonic-gate 	 */
2196*0Sstevel@tonic-gate 	mr->c.un_type = MD_METARAID;
2197*0Sstevel@tonic-gate 	MD_SID(mr) = meta_getminor(raidnp->dev);
2198*0Sstevel@tonic-gate 	mr->c.un_size = rdsize;
2199*0Sstevel@tonic-gate 	mr->un_magic = RAID_UNMAGIC;
2200*0Sstevel@tonic-gate 	mr->un_state = raidp->state;
2201*0Sstevel@tonic-gate 	mr->un_timestamp = creation_time;
2202*0Sstevel@tonic-gate 	mr->un_origcolumncnt = orig_ncol;
2203*0Sstevel@tonic-gate 	mr->un_segsize = (uint_t)raidp->interlace;
2204*0Sstevel@tonic-gate 	if (raidp->hspnamep != NULL) {
2205*0Sstevel@tonic-gate 		mr->un_hsp_id = raidp->hspnamep->hsp;
2206*0Sstevel@tonic-gate 	} else {
2207*0Sstevel@tonic-gate 		mr->un_hsp_id = MD_HSP_NONE;
2208*0Sstevel@tonic-gate 	}
2209*0Sstevel@tonic-gate 	/*
2210*0Sstevel@tonic-gate 	 * setup original columns, saving start_block and
2211*0Sstevel@tonic-gate 	 * finding smallest size and maxio
2212*0Sstevel@tonic-gate 	 */
2213*0Sstevel@tonic-gate 	for (col = 0; (col < orig_ncol); ++col) {
2214*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
2215*0Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
2216*0Sstevel@tonic-gate 		mr_column_t	*mdc = &mr->un_column[col];
2217*0Sstevel@tonic-gate 		diskaddr_t	size;
2218*0Sstevel@tonic-gate 		uint_t		maxio;
2219*0Sstevel@tonic-gate 		mdcinfo_t	*cinfop;
2220*0Sstevel@tonic-gate 
2221*0Sstevel@tonic-gate 		/* setup state */
2222*0Sstevel@tonic-gate 		mdc->un_devstate = cp->state;
2223*0Sstevel@tonic-gate 
2224*0Sstevel@tonic-gate 		/* setup creation time */
2225*0Sstevel@tonic-gate 		mdc->un_devtimestamp = creation_time;
2226*0Sstevel@tonic-gate 
2227*0Sstevel@tonic-gate 		/* get start, size, and maxio */
2228*0Sstevel@tonic-gate 		if ((mdc->un_orig_devstart = metagetstart(sp, colnp, ep)) ==
2229*0Sstevel@tonic-gate 		    MD_DISKADDR_ERROR)
2230*0Sstevel@tonic-gate 			goto out;
2231*0Sstevel@tonic-gate 		if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
2232*0Sstevel@tonic-gate 			goto out;
2233*0Sstevel@tonic-gate 		size -= mdc->un_orig_devstart;
2234*0Sstevel@tonic-gate 		if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
2235*0Sstevel@tonic-gate 			goto out;
2236*0Sstevel@tonic-gate 		maxio = cinfop->maxtransfer;
2237*0Sstevel@tonic-gate 
2238*0Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
2239*0Sstevel@tonic-gate 			/* store name in namespace */
2240*0Sstevel@tonic-gate 			if (add_key_name(sp, colnp, &keynlp, ep) != 0)
2241*0Sstevel@tonic-gate 				goto out;
2242*0Sstevel@tonic-gate 		}
2243*0Sstevel@tonic-gate 
2244*0Sstevel@tonic-gate 		/* setup column */
2245*0Sstevel@tonic-gate 		mdc->un_orig_key = colnp->key;
2246*0Sstevel@tonic-gate 		mdc->un_orig_dev = colnp->dev;
2247*0Sstevel@tonic-gate 		mdc->un_dev = mdc->un_orig_dev;
2248*0Sstevel@tonic-gate 		mdc->un_pwstart = mdc->un_orig_pwstart;
2249*0Sstevel@tonic-gate 		mdc->un_devstart = mdc->un_orig_devstart;
2250*0Sstevel@tonic-gate 		mdc->un_alt_dev = NODEV64;
2251*0Sstevel@tonic-gate 		mdc->un_alt_pwstart = 0;
2252*0Sstevel@tonic-gate 		mdc->un_alt_devstart = 0;
2253*0Sstevel@tonic-gate 		mdc->un_hs_id = 0;
2254*0Sstevel@tonic-gate 		if (mr->un_state == RUS_INIT)
2255*0Sstevel@tonic-gate 			mdc->un_devstate = RCS_INIT;
2256*0Sstevel@tonic-gate 		else
2257*0Sstevel@tonic-gate 			mdc->un_devstate = RCS_OKAY;
2258*0Sstevel@tonic-gate 
2259*0Sstevel@tonic-gate 		/* adjust for smallest disk */
2260*0Sstevel@tonic-gate 		if (disk_size == 0) {
2261*0Sstevel@tonic-gate 			disk_size = size;
2262*0Sstevel@tonic-gate 		} else if (size < disk_size) {
2263*0Sstevel@tonic-gate 			disk_size = size;
2264*0Sstevel@tonic-gate 		}
2265*0Sstevel@tonic-gate 		if (disk_maxio == 0) {
2266*0Sstevel@tonic-gate 			disk_maxio = maxio;
2267*0Sstevel@tonic-gate 		} else if (maxio < disk_maxio) {
2268*0Sstevel@tonic-gate 			disk_maxio = maxio;
2269*0Sstevel@tonic-gate 		}
2270*0Sstevel@tonic-gate 	}
2271*0Sstevel@tonic-gate 	assert(col == mr->un_origcolumncnt);
2272*0Sstevel@tonic-gate 
2273*0Sstevel@tonic-gate 	/*
2274*0Sstevel@tonic-gate 	 * before processing any of the attached column(s)
2275*0Sstevel@tonic-gate 	 * set up the composition of the metadevice for column
2276*0Sstevel@tonic-gate 	 * sizes and pre-write information
2277*0Sstevel@tonic-gate 	 */
2278*0Sstevel@tonic-gate 	mr->un_maxio = disk_maxio;	/* smallest maxio */
2279*0Sstevel@tonic-gate 	mr->un_iosize = min(mr->un_maxio, (mr->un_segsize + 1));
2280*0Sstevel@tonic-gate 	pwes = mr->un_iosize;
2281*0Sstevel@tonic-gate 	if (raidp->pw_count)
2282*0Sstevel@tonic-gate 		mr->un_pwcnt = raidp->pw_count;
2283*0Sstevel@tonic-gate 	else
2284*0Sstevel@tonic-gate 		mr->un_pwcnt = PWCNT_MIN;
2285*0Sstevel@tonic-gate 	if ((mr->un_pwcnt < PWCNT_MIN) || (mr->un_pwcnt > PWCNT_MAX)) {
2286*0Sstevel@tonic-gate 		(void) mderror(ep, MDE_RAID_BAD_PW_CNT, raidnp->cname);
2287*0Sstevel@tonic-gate 		goto out;
2288*0Sstevel@tonic-gate 	}
2289*0Sstevel@tonic-gate 	mr->un_pwsize = roundup((mr->un_pwcnt * pwes), 2);
2290*0Sstevel@tonic-gate 
2291*0Sstevel@tonic-gate 	/* now calculate the number of segments per column */
2292*0Sstevel@tonic-gate 	non_pw_blks = disk_size - mr->un_pwsize;	/* smallest disk */
2293*0Sstevel@tonic-gate 	if ((mr->un_pwsize > disk_size) ||
2294*0Sstevel@tonic-gate 	    (non_pw_blks < (diskaddr_t)mr->un_segsize)) {
2295*0Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, raidnp->cname);
2296*0Sstevel@tonic-gate 		goto out;
2297*0Sstevel@tonic-gate 	}
2298*0Sstevel@tonic-gate 	mr->un_segsincolumn = non_pw_blks / mr->un_segsize;
2299*0Sstevel@tonic-gate 	column_size = mr->un_segsize * mr->un_segsincolumn;
2300*0Sstevel@tonic-gate 
2301*0Sstevel@tonic-gate 	/*
2302*0Sstevel@tonic-gate 	 * adjust the pw_cnt, pw_size, to fit into any fragmentation
2303*0Sstevel@tonic-gate 	 * left over after column_size has been computed
2304*0Sstevel@tonic-gate 	 */
2305*0Sstevel@tonic-gate 	mr->un_pwsize = rounddown(((uint_t)(disk_size - column_size)), 2);
2306*0Sstevel@tonic-gate 	mr->un_pwcnt = mr->un_pwsize / pwes;
2307*0Sstevel@tonic-gate 	assert(mr->un_pwcnt >= PWCNT_MIN);
2308*0Sstevel@tonic-gate 	mr->un_pwsize = roundup((mr->un_pwcnt * pwes), 2);
2309*0Sstevel@tonic-gate 	assert((mr->un_pwsize + column_size) <= disk_size);
2310*0Sstevel@tonic-gate 
2311*0Sstevel@tonic-gate 	/*
2312*0Sstevel@tonic-gate 	 * calculate the actual block count available based on the
2313*0Sstevel@tonic-gate 	 * segment size and the number of segments per column ...
2314*0Sstevel@tonic-gate 	 * ... and adjust for the number of parity segments
2315*0Sstevel@tonic-gate 	 */
2316*0Sstevel@tonic-gate 	mr->c.un_actual_tb = column_size * (mr->un_origcolumncnt - 1);
2317*0Sstevel@tonic-gate 
2318*0Sstevel@tonic-gate 	if (raid_geom(raidp, mr, ep) != 0)
2319*0Sstevel@tonic-gate 		goto out;
2320*0Sstevel@tonic-gate 
2321*0Sstevel@tonic-gate 	create_flag = meta_check_devicesize(mr->c.un_total_blocks);
2322*0Sstevel@tonic-gate 
2323*0Sstevel@tonic-gate 	/*
2324*0Sstevel@tonic-gate 	 * now calculate the pre-write offset and update the column
2325*0Sstevel@tonic-gate 	 * structures to include the address of the individual pre-write
2326*0Sstevel@tonic-gate 	 * areas
2327*0Sstevel@tonic-gate 	 */
2328*0Sstevel@tonic-gate 	for (col = 0; (col < orig_ncol); ++col) {
2329*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
2330*0Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
2331*0Sstevel@tonic-gate 		mr_column_t	*mdc = &mr->un_column[col];
2332*0Sstevel@tonic-gate 		diskaddr_t	size;
2333*0Sstevel@tonic-gate 
2334*0Sstevel@tonic-gate 		/* get size */
2335*0Sstevel@tonic-gate 		if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
2336*0Sstevel@tonic-gate 			goto out;
2337*0Sstevel@tonic-gate 
2338*0Sstevel@tonic-gate 		/* adjust start and size by prewrite */
2339*0Sstevel@tonic-gate 		mdc->un_orig_pwstart = mdc->un_orig_devstart;
2340*0Sstevel@tonic-gate 		mdc->un_orig_devstart += mr->un_pwsize;
2341*0Sstevel@tonic-gate 		mdc->un_pwstart = mdc->un_orig_pwstart;
2342*0Sstevel@tonic-gate 		mdc->un_devstart = mdc->un_orig_devstart;
2343*0Sstevel@tonic-gate 
2344*0Sstevel@tonic-gate 		assert(size >= mdc->un_orig_devstart);
2345*0Sstevel@tonic-gate 		size -= mdc->un_orig_devstart;
2346*0Sstevel@tonic-gate 
2347*0Sstevel@tonic-gate 		/* make sure we still have something left */
2348*0Sstevel@tonic-gate 		assert(size >= column_size);
2349*0Sstevel@tonic-gate 	}
2350*0Sstevel@tonic-gate 
2351*0Sstevel@tonic-gate 	/* do concat cols */
2352*0Sstevel@tonic-gate 	mr->un_totalcolumncnt = mr->un_origcolumncnt;
2353*0Sstevel@tonic-gate 	assert(col == mr->un_origcolumncnt);
2354*0Sstevel@tonic-gate 	for (col = orig_ncol; (col < ncol); ++col) {
2355*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
2356*0Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
2357*0Sstevel@tonic-gate 		mr_column_t	*mdc = &mr->un_column[col];
2358*0Sstevel@tonic-gate 
2359*0Sstevel@tonic-gate 		/* attach column */
2360*0Sstevel@tonic-gate 		if (attach_raid_col(sp, raidnp, mr, mdc, colnp,
2361*0Sstevel@tonic-gate 		    cp->state, &keynlp, options, ep) != 0) {
2362*0Sstevel@tonic-gate 			goto out;
2363*0Sstevel@tonic-gate 		}
2364*0Sstevel@tonic-gate 	}
2365*0Sstevel@tonic-gate 	assert(mr->un_totalcolumncnt == ncol);
2366*0Sstevel@tonic-gate 
2367*0Sstevel@tonic-gate 	/* fill in the size of the raid */
2368*0Sstevel@tonic-gate 	if (options & MDCMD_UPDATE) {
2369*0Sstevel@tonic-gate 		raidp->common.size = mr->c.un_total_blocks;
2370*0Sstevel@tonic-gate 		raidp->column_size = mr->un_segsize * mr->un_segsincolumn;
2371*0Sstevel@tonic-gate 	}
2372*0Sstevel@tonic-gate 
2373*0Sstevel@tonic-gate 	/* if we're not doing anything, return success */
2374*0Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT)) {
2375*0Sstevel@tonic-gate 		rval = 0;	/* success */
2376*0Sstevel@tonic-gate 		goto out;
2377*0Sstevel@tonic-gate 	}
2378*0Sstevel@tonic-gate 
2379*0Sstevel@tonic-gate 	if ((mr->un_state & RUS_OKAY) &&
2380*0Sstevel@tonic-gate 	    (meta_raid_valid(raidp, mr) != 0)) {
2381*0Sstevel@tonic-gate 		(void) mderror(ep, MDE_RAID_INVALID, raidnp->cname);
2382*0Sstevel@tonic-gate 		goto out;
2383*0Sstevel@tonic-gate 	}
2384*0Sstevel@tonic-gate 
2385*0Sstevel@tonic-gate 	/* create raid */
2386*0Sstevel@tonic-gate 	(void) memset(&set_params, 0, sizeof (set_params));
2387*0Sstevel@tonic-gate 	/* did the user tell us to generate a large device? */
2388*0Sstevel@tonic-gate 	if (create_flag == MD_CRO_64BIT) {
2389*0Sstevel@tonic-gate 		mr->c.un_revision = MD_64BIT_META_DEV;
2390*0Sstevel@tonic-gate 		set_params.options = MD_CRO_64BIT;
2391*0Sstevel@tonic-gate 	} else {
2392*0Sstevel@tonic-gate 		mr->c.un_revision = MD_32BIT_META_DEV;
2393*0Sstevel@tonic-gate 		set_params.options = MD_CRO_32BIT;
2394*0Sstevel@tonic-gate 	}
2395*0Sstevel@tonic-gate 	set_params.mnum = MD_SID(mr);
2396*0Sstevel@tonic-gate 	set_params.size = mr->c.un_size;
2397*0Sstevel@tonic-gate 	set_params.mdp = (uintptr_t)mr;
2398*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&set_params, MD_RAID, MD_MIN2SET(set_params.mnum));
2399*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
2400*0Sstevel@tonic-gate 	    raidnp->cname) != 0) {
2401*0Sstevel@tonic-gate 		(void) mdstealerror(ep, &set_params.mde);
2402*0Sstevel@tonic-gate 		goto out;
2403*0Sstevel@tonic-gate 	}
2404*0Sstevel@tonic-gate 	rval = 0;	/* success */
2405*0Sstevel@tonic-gate 
2406*0Sstevel@tonic-gate 	/* cleanup, return success */
2407*0Sstevel@tonic-gate out:
2408*0Sstevel@tonic-gate 	Free(mr);
2409*0Sstevel@tonic-gate 	if (rval != 0) {
2410*0Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
2411*0Sstevel@tonic-gate 	}
2412*0Sstevel@tonic-gate 	metafreenamelist(keynlp);
2413*0Sstevel@tonic-gate 	if ((rval == 0) && (options & MDCMD_DOIT)) {
2414*0Sstevel@tonic-gate 		if (invalidate_columns(sp, raidnp, ep) != 0)
2415*0Sstevel@tonic-gate 			rval = -1;
2416*0Sstevel@tonic-gate 		meta_invalidate_name(raidnp);
2417*0Sstevel@tonic-gate 	}
2418*0Sstevel@tonic-gate 	return (rval);
2419*0Sstevel@tonic-gate }
2420*0Sstevel@tonic-gate 
2421*0Sstevel@tonic-gate /*
2422*0Sstevel@tonic-gate  * initialize raid
2423*0Sstevel@tonic-gate  * NOTE: this functions is metainit(1m)'s command line parser!
2424*0Sstevel@tonic-gate  */
2425*0Sstevel@tonic-gate int
2426*0Sstevel@tonic-gate meta_init_raid(
2427*0Sstevel@tonic-gate 	mdsetname_t	**spp,
2428*0Sstevel@tonic-gate 	int		argc,
2429*0Sstevel@tonic-gate 	char		*argv[],
2430*0Sstevel@tonic-gate 	mdcmdopts_t	options,
2431*0Sstevel@tonic-gate 	md_error_t	*ep
2432*0Sstevel@tonic-gate )
2433*0Sstevel@tonic-gate {
2434*0Sstevel@tonic-gate 	char		*uname = argv[0];
2435*0Sstevel@tonic-gate 	mdname_t	*raidnp = NULL;
2436*0Sstevel@tonic-gate 	int		old_optind;
2437*0Sstevel@tonic-gate 	int		c;
2438*0Sstevel@tonic-gate 	md_raid_t	*raidp = NULL;
2439*0Sstevel@tonic-gate 	uint_t		ncol, col;
2440*0Sstevel@tonic-gate 	int		rval = -1;
2441*0Sstevel@tonic-gate 	md_set_desc	*sd;
2442*0Sstevel@tonic-gate 
2443*0Sstevel@tonic-gate 	/* get raid name */
2444*0Sstevel@tonic-gate 	assert(argc > 0);
2445*0Sstevel@tonic-gate 	if (argc < 1)
2446*0Sstevel@tonic-gate 		goto syntax;
2447*0Sstevel@tonic-gate 	if ((raidnp = metaname(spp, uname, ep)) == NULL)
2448*0Sstevel@tonic-gate 		goto out;
2449*0Sstevel@tonic-gate 	assert(*spp != NULL);
2450*0Sstevel@tonic-gate 
2451*0Sstevel@tonic-gate 	/*
2452*0Sstevel@tonic-gate 	 * Raid metadevice not allowed on multi-node diskset.
2453*0Sstevel@tonic-gate 	 */
2454*0Sstevel@tonic-gate 	if (! metaislocalset(*spp)) {
2455*0Sstevel@tonic-gate 		if ((sd = metaget_setdesc(*spp, ep)) == NULL)
2456*0Sstevel@tonic-gate 			goto out;
2457*0Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
2458*0Sstevel@tonic-gate 			rval = meta_cook_syntax(ep, MDE_MNSET_NORAID, uname,
2459*0Sstevel@tonic-gate 						argc, argv);
2460*0Sstevel@tonic-gate 			goto out;
2461*0Sstevel@tonic-gate 		}
2462*0Sstevel@tonic-gate 	}
2463*0Sstevel@tonic-gate 
2464*0Sstevel@tonic-gate 	uname = raidnp->cname;
2465*0Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
2466*0Sstevel@tonic-gate 		goto out;
2467*0Sstevel@tonic-gate 
2468*0Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
2469*0Sstevel@tonic-gate 		/* grab set lock */
2470*0Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep) != 0)
2471*0Sstevel@tonic-gate 			goto out;
2472*0Sstevel@tonic-gate 
2473*0Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
2474*0Sstevel@tonic-gate 			goto out;
2475*0Sstevel@tonic-gate 	}
2476*0Sstevel@tonic-gate 
2477*0Sstevel@tonic-gate 	/* see if it exists already */
2478*0Sstevel@tonic-gate 	if (metagetmiscname(raidnp, ep) != NULL) {
2479*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
2480*0Sstevel@tonic-gate 		    meta_getminor(raidnp->dev), uname);
2481*0Sstevel@tonic-gate 		goto out;
2482*0Sstevel@tonic-gate 	} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
2483*0Sstevel@tonic-gate 		goto out;
2484*0Sstevel@tonic-gate 	} else {
2485*0Sstevel@tonic-gate 		mdclrerror(ep);
2486*0Sstevel@tonic-gate 	}
2487*0Sstevel@tonic-gate 	--argc, ++argv;
2488*0Sstevel@tonic-gate 
2489*0Sstevel@tonic-gate 	/* grab -r */
2490*0Sstevel@tonic-gate 	if ((argc < 1) || (strcmp(argv[0], "-r") != 0))
2491*0Sstevel@tonic-gate 		goto syntax;
2492*0Sstevel@tonic-gate 	--argc, ++argv;
2493*0Sstevel@tonic-gate 
2494*0Sstevel@tonic-gate 	/* parse general options */
2495*0Sstevel@tonic-gate 	optind = 0;
2496*0Sstevel@tonic-gate 	opterr = 0;
2497*0Sstevel@tonic-gate 	if (getopt(argc, argv, "") != -1)
2498*0Sstevel@tonic-gate 		goto options;
2499*0Sstevel@tonic-gate 
2500*0Sstevel@tonic-gate 	/* allocate raid */
2501*0Sstevel@tonic-gate 	raidp = Zalloc(sizeof (*raidp));
2502*0Sstevel@tonic-gate 
2503*0Sstevel@tonic-gate 	/* setup common */
2504*0Sstevel@tonic-gate 	raidp->common.namep = raidnp;
2505*0Sstevel@tonic-gate 	raidp->common.type = MD_METARAID;
2506*0Sstevel@tonic-gate 	raidp->state = RUS_INIT;
2507*0Sstevel@tonic-gate 
2508*0Sstevel@tonic-gate 	/* allocate and parse cols */
2509*0Sstevel@tonic-gate 	for (ncol = 0; ((ncol < argc) && (argv[ncol][0] != '-')); ++ncol)
2510*0Sstevel@tonic-gate 		;
2511*0Sstevel@tonic-gate 	raidp->cols.cols_len = ncol;
2512*0Sstevel@tonic-gate 	if (ncol != 0) {
2513*0Sstevel@tonic-gate 		raidp->cols.cols_val =
2514*0Sstevel@tonic-gate 		    Zalloc(ncol * sizeof (*raidp->cols.cols_val));
2515*0Sstevel@tonic-gate 	}
2516*0Sstevel@tonic-gate 	for (col = 0; ((argc > 0) && (col < ncol)); ++col) {
2517*0Sstevel@tonic-gate 		md_raidcol_t	*mdc = &raidp->cols.cols_val[col];
2518*0Sstevel@tonic-gate 		mdname_t	*colnp;
2519*0Sstevel@tonic-gate 
2520*0Sstevel@tonic-gate 		/* parse column name */
2521*0Sstevel@tonic-gate 		if ((colnp = metaname(spp, argv[0], ep)) == NULL)
2522*0Sstevel@tonic-gate 			goto out;
2523*0Sstevel@tonic-gate 		/* check for soft partitions */
2524*0Sstevel@tonic-gate 		if (meta_sp_issp(*spp, colnp, ep) != 0) {
2525*0Sstevel@tonic-gate 			/* check disks */
2526*0Sstevel@tonic-gate 			if (metachkcomp(colnp, ep) != 0)
2527*0Sstevel@tonic-gate 				goto out;
2528*0Sstevel@tonic-gate 		}
2529*0Sstevel@tonic-gate 		mdc->colnamep = colnp;
2530*0Sstevel@tonic-gate 		--argc, ++argv;
2531*0Sstevel@tonic-gate 	}
2532*0Sstevel@tonic-gate 
2533*0Sstevel@tonic-gate 	/* parse raid options */
2534*0Sstevel@tonic-gate 	old_optind = optind = 0;
2535*0Sstevel@tonic-gate 	opterr = 0;
2536*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "h:i:ko:w:")) != -1) {
2537*0Sstevel@tonic-gate 		switch (c) {
2538*0Sstevel@tonic-gate 		case 'h':
2539*0Sstevel@tonic-gate 			if ((raidp->hspnamep = metahspname(spp, optarg,
2540*0Sstevel@tonic-gate 			    ep)) == NULL) {
2541*0Sstevel@tonic-gate 				goto out;
2542*0Sstevel@tonic-gate 			}
2543*0Sstevel@tonic-gate 			break;
2544*0Sstevel@tonic-gate 
2545*0Sstevel@tonic-gate 		case 'i':
2546*0Sstevel@tonic-gate 			if (parse_interlace(uname, optarg, &raidp->interlace,
2547*0Sstevel@tonic-gate 			    ep) != 0) {
2548*0Sstevel@tonic-gate 				goto out;
2549*0Sstevel@tonic-gate 			}
2550*0Sstevel@tonic-gate 			if (meta_raid_check_interlace(raidp->interlace,
2551*0Sstevel@tonic-gate 			    uname, ep))
2552*0Sstevel@tonic-gate 				goto out;
2553*0Sstevel@tonic-gate 			break;
2554*0Sstevel@tonic-gate 
2555*0Sstevel@tonic-gate 		case 'k':
2556*0Sstevel@tonic-gate 			raidp->state = RUS_OKAY;
2557*0Sstevel@tonic-gate 			break;
2558*0Sstevel@tonic-gate 
2559*0Sstevel@tonic-gate 		case 'o':
2560*0Sstevel@tonic-gate 			if ((sscanf(optarg, "%u", &raidp->orig_ncol) != 1) ||
2561*0Sstevel@tonic-gate 			    ((int)raidp->orig_ncol < 0)) {
2562*0Sstevel@tonic-gate 				goto syntax;
2563*0Sstevel@tonic-gate 			}
2564*0Sstevel@tonic-gate 			if ((raidp->orig_ncol < MD_RAID_MIN) ||
2565*0Sstevel@tonic-gate 			    (raidp->orig_ncol > ncol)) {
2566*0Sstevel@tonic-gate 				rval = mderror(ep, MDE_BAD_ORIG_NCOL, uname);
2567*0Sstevel@tonic-gate 				goto out;
2568*0Sstevel@tonic-gate 			}
2569*0Sstevel@tonic-gate 			break;
2570*0Sstevel@tonic-gate 		case 'w':
2571*0Sstevel@tonic-gate 			if ((sscanf(optarg, "%d", &raidp->pw_count) != 1) ||
2572*0Sstevel@tonic-gate 			    ((int)raidp->pw_count < 0))
2573*0Sstevel@tonic-gate 				goto syntax;
2574*0Sstevel@tonic-gate 			if (((int)raidp->pw_count < PWCNT_MIN) ||
2575*0Sstevel@tonic-gate 			    ((int)raidp->pw_count > PWCNT_MAX)) {
2576*0Sstevel@tonic-gate 				rval = mderror(ep, MDE_RAID_BAD_PW_CNT, uname);
2577*0Sstevel@tonic-gate 				goto out;
2578*0Sstevel@tonic-gate 			}
2579*0Sstevel@tonic-gate 			break;
2580*0Sstevel@tonic-gate 		default:
2581*0Sstevel@tonic-gate 			argc += old_optind;
2582*0Sstevel@tonic-gate 			argv -= old_optind;
2583*0Sstevel@tonic-gate 			goto options;
2584*0Sstevel@tonic-gate 		}
2585*0Sstevel@tonic-gate 		old_optind = optind;
2586*0Sstevel@tonic-gate 	}
2587*0Sstevel@tonic-gate 	argc -= optind;
2588*0Sstevel@tonic-gate 	argv += optind;
2589*0Sstevel@tonic-gate 
2590*0Sstevel@tonic-gate 	/* we should be at the end */
2591*0Sstevel@tonic-gate 	if (argc != 0)
2592*0Sstevel@tonic-gate 		goto syntax;
2593*0Sstevel@tonic-gate 
2594*0Sstevel@tonic-gate 	/* default to all original columns */
2595*0Sstevel@tonic-gate 	if (raidp->orig_ncol == 0)
2596*0Sstevel@tonic-gate 		raidp->orig_ncol = ncol;
2597*0Sstevel@tonic-gate 
2598*0Sstevel@tonic-gate 	/* create raid */
2599*0Sstevel@tonic-gate 	if (meta_create_raid(*spp, raidp, options, ep) != 0)
2600*0Sstevel@tonic-gate 		goto out;
2601*0Sstevel@tonic-gate 	rval = 0;	/* success */
2602*0Sstevel@tonic-gate 
2603*0Sstevel@tonic-gate 	/* let em know */
2604*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
2605*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "%s: RAID is setup\n"),
2606*0Sstevel@tonic-gate 		    uname);
2607*0Sstevel@tonic-gate 		(void) fflush(stdout);
2608*0Sstevel@tonic-gate 	}
2609*0Sstevel@tonic-gate 	goto out;
2610*0Sstevel@tonic-gate 
2611*0Sstevel@tonic-gate 	/* syntax error */
2612*0Sstevel@tonic-gate syntax:
2613*0Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
2614*0Sstevel@tonic-gate 	goto out;
2615*0Sstevel@tonic-gate 
2616*0Sstevel@tonic-gate 	/* options error */
2617*0Sstevel@tonic-gate options:
2618*0Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
2619*0Sstevel@tonic-gate 	goto out;
2620*0Sstevel@tonic-gate 
2621*0Sstevel@tonic-gate 	/* cleanup, return error */
2622*0Sstevel@tonic-gate out:
2623*0Sstevel@tonic-gate 	if (raidp != NULL)
2624*0Sstevel@tonic-gate 		meta_free_raid(raidp);
2625*0Sstevel@tonic-gate 	return (rval);
2626*0Sstevel@tonic-gate }
2627*0Sstevel@tonic-gate 
2628*0Sstevel@tonic-gate /*
2629*0Sstevel@tonic-gate  * reset RAIDs
2630*0Sstevel@tonic-gate  */
2631*0Sstevel@tonic-gate int
2632*0Sstevel@tonic-gate meta_raid_reset(
2633*0Sstevel@tonic-gate 	mdsetname_t	*sp,
2634*0Sstevel@tonic-gate 	mdname_t	*raidnp,
2635*0Sstevel@tonic-gate 	mdcmdopts_t	options,
2636*0Sstevel@tonic-gate 	md_error_t	*ep
2637*0Sstevel@tonic-gate )
2638*0Sstevel@tonic-gate {
2639*0Sstevel@tonic-gate 	md_raid_t	*raidp;
2640*0Sstevel@tonic-gate 	int		rval = -1;
2641*0Sstevel@tonic-gate 	int		col;
2642*0Sstevel@tonic-gate 
2643*0Sstevel@tonic-gate 	/* should have same set */
2644*0Sstevel@tonic-gate 	assert(sp != NULL);
2645*0Sstevel@tonic-gate 	assert((raidnp == NULL) ||
2646*0Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev))));
2647*0Sstevel@tonic-gate 
2648*0Sstevel@tonic-gate 	/* reset all raids */
2649*0Sstevel@tonic-gate 	if (raidnp == NULL) {
2650*0Sstevel@tonic-gate 		mdnamelist_t	*raidnlp = NULL;
2651*0Sstevel@tonic-gate 		mdnamelist_t	*p;
2652*0Sstevel@tonic-gate 
2653*0Sstevel@tonic-gate 		/* for each raid */
2654*0Sstevel@tonic-gate 		rval = 0;
2655*0Sstevel@tonic-gate 		if (meta_get_raid_names(sp, &raidnlp, 0, ep) < 0)
2656*0Sstevel@tonic-gate 			return (-1);
2657*0Sstevel@tonic-gate 		for (p = raidnlp; (p != NULL); p = p->next) {
2658*0Sstevel@tonic-gate 			/* reset RAID */
2659*0Sstevel@tonic-gate 			raidnp = p->namep;
2660*0Sstevel@tonic-gate 			if (meta_raid_reset(sp, raidnp, options, ep) != 0) {
2661*0Sstevel@tonic-gate 				rval = -1;
2662*0Sstevel@tonic-gate 				break;
2663*0Sstevel@tonic-gate 			}
2664*0Sstevel@tonic-gate 		}
2665*0Sstevel@tonic-gate 
2666*0Sstevel@tonic-gate 		/* cleanup, return success */
2667*0Sstevel@tonic-gate 		metafreenamelist(raidnlp);
2668*0Sstevel@tonic-gate 		return (rval);
2669*0Sstevel@tonic-gate 	}
2670*0Sstevel@tonic-gate 
2671*0Sstevel@tonic-gate 	/* check name */
2672*0Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
2673*0Sstevel@tonic-gate 		return (-1);
2674*0Sstevel@tonic-gate 
2675*0Sstevel@tonic-gate 	/* get unit structure */
2676*0Sstevel@tonic-gate 	if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
2677*0Sstevel@tonic-gate 		return (-1);
2678*0Sstevel@tonic-gate 
2679*0Sstevel@tonic-gate 	/* make sure nobody owns us */
2680*0Sstevel@tonic-gate 	if (MD_HAS_PARENT(raidp->common.parent)) {
2681*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(raidnp->dev),
2682*0Sstevel@tonic-gate 		    raidnp->cname));
2683*0Sstevel@tonic-gate 	}
2684*0Sstevel@tonic-gate 
2685*0Sstevel@tonic-gate 	/* clear subdevices cache */
2686*0Sstevel@tonic-gate 	if (invalidate_columns(sp, raidnp, ep) != 0)
2687*0Sstevel@tonic-gate 		return (-1);
2688*0Sstevel@tonic-gate 
2689*0Sstevel@tonic-gate 	/* clear metadevice */
2690*0Sstevel@tonic-gate 	if (meta_reset(sp, raidnp, options, ep) != 0)
2691*0Sstevel@tonic-gate 		goto out;
2692*0Sstevel@tonic-gate 	rval = 0;	/* success */
2693*0Sstevel@tonic-gate 
2694*0Sstevel@tonic-gate 	/* let em know */
2695*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
2696*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "%s: RAID is cleared\n"),
2697*0Sstevel@tonic-gate 		    raidnp->cname);
2698*0Sstevel@tonic-gate 		(void) fflush(stdout);
2699*0Sstevel@tonic-gate 	}
2700*0Sstevel@tonic-gate 
2701*0Sstevel@tonic-gate 	/* clear subdevices */
2702*0Sstevel@tonic-gate 	if (! (options & MDCMD_RECURSE))
2703*0Sstevel@tonic-gate 		goto out;
2704*0Sstevel@tonic-gate 
2705*0Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
2706*0Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
2707*0Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
2708*0Sstevel@tonic-gate 
2709*0Sstevel@tonic-gate 		/* only recurse on metadevices */
2710*0Sstevel@tonic-gate 		if (! metaismeta(colnp))
2711*0Sstevel@tonic-gate 			continue;
2712*0Sstevel@tonic-gate 
2713*0Sstevel@tonic-gate 		if (meta_reset_by_name(sp, colnp, options, ep) != 0)
2714*0Sstevel@tonic-gate 			rval = -1;
2715*0Sstevel@tonic-gate 	}
2716*0Sstevel@tonic-gate 
2717*0Sstevel@tonic-gate 	/* cleanup, return success */
2718*0Sstevel@tonic-gate out:
2719*0Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
2720*0Sstevel@tonic-gate 	return (rval);
2721*0Sstevel@tonic-gate }
2722*0Sstevel@tonic-gate 
2723*0Sstevel@tonic-gate /*
2724*0Sstevel@tonic-gate  * reports TRUE if any RAID component is in error
2725*0Sstevel@tonic-gate  */
2726*0Sstevel@tonic-gate int
2727*0Sstevel@tonic-gate meta_raid_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *raid_names)
2728*0Sstevel@tonic-gate {
2729*0Sstevel@tonic-gate 	mdnamelist_t	*nlp;
2730*0Sstevel@tonic-gate 	md_error_t	  status	= mdnullerror;
2731*0Sstevel@tonic-gate 	md_error_t	 *ep		= &status;
2732*0Sstevel@tonic-gate 	int		  any_errs	= FALSE;
2733*0Sstevel@tonic-gate 
2734*0Sstevel@tonic-gate 	for (nlp = raid_names; nlp; nlp = nlp->next) {
2735*0Sstevel@tonic-gate 		md_raid_t	*raidp;
2736*0Sstevel@tonic-gate 
2737*0Sstevel@tonic-gate 		if ((raidp = meta_get_raid(sp, nlp->namep, ep)) == NULL) {
2738*0Sstevel@tonic-gate 			any_errs |= TRUE;
2739*0Sstevel@tonic-gate 			goto out;
2740*0Sstevel@tonic-gate 		}
2741*0Sstevel@tonic-gate 		if (raidp->state != RUS_OKAY && raidp->state != RUS_INIT) {
2742*0Sstevel@tonic-gate 			any_errs |= TRUE;
2743*0Sstevel@tonic-gate 			goto out;
2744*0Sstevel@tonic-gate 		}
2745*0Sstevel@tonic-gate 	}
2746*0Sstevel@tonic-gate out:
2747*0Sstevel@tonic-gate 	if (!mdisok(ep))
2748*0Sstevel@tonic-gate 		mdclrerror(ep);
2749*0Sstevel@tonic-gate 
2750*0Sstevel@tonic-gate 	return (any_errs);
2751*0Sstevel@tonic-gate }
2752*0Sstevel@tonic-gate /*
2753*0Sstevel@tonic-gate  * regen parity on a raid
2754*0Sstevel@tonic-gate  */
2755*0Sstevel@tonic-gate int
2756*0Sstevel@tonic-gate meta_raid_regen_byname(mdsetname_t *sp, mdname_t *raidnp, diskaddr_t size,
2757*0Sstevel@tonic-gate 	md_error_t *ep)
2758*0Sstevel@tonic-gate {
2759*0Sstevel@tonic-gate 	char			*miscname;
2760*0Sstevel@tonic-gate 	md_resync_ioctl_t	ri;
2761*0Sstevel@tonic-gate 
2762*0Sstevel@tonic-gate 	/* should have a set */
2763*0Sstevel@tonic-gate 	assert(sp != NULL);
2764*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
2765*0Sstevel@tonic-gate 
2766*0Sstevel@tonic-gate 	/* make sure we have a raid */
2767*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(raidnp, ep)) == NULL)
2768*0Sstevel@tonic-gate 		return (-1);
2769*0Sstevel@tonic-gate 	if (strcmp(miscname, MD_RAID) != 0) {
2770*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_NOT_RAID, meta_getminor(raidnp->dev),
2771*0Sstevel@tonic-gate 		    raidnp->cname));
2772*0Sstevel@tonic-gate 	}
2773*0Sstevel@tonic-gate 
2774*0Sstevel@tonic-gate 	/* start resync */
2775*0Sstevel@tonic-gate 	(void) memset(&ri, 0, sizeof (ri));
2776*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&ri, MD_RAID, sp->setno);
2777*0Sstevel@tonic-gate 	ri.ri_mnum = meta_getminor(raidnp->dev);
2778*0Sstevel@tonic-gate 	ri.ri_copysize = size;
2779*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCSETREGEN, &ri, &ri.mde, raidnp->cname) != 0)
2780*0Sstevel@tonic-gate 		return (mdstealerror(ep, &ri.mde));
2781*0Sstevel@tonic-gate 
2782*0Sstevel@tonic-gate 	/* return success */
2783*0Sstevel@tonic-gate 	return (0);
2784*0Sstevel@tonic-gate }
2785