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