10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*456Stn143363  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
300Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
330Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
340Sstevel@tonic-gate #endif
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  * RAID operations
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <meta.h>
420Sstevel@tonic-gate #include <sys/lvm/md_raid.h>
430Sstevel@tonic-gate #include <sys/lvm/mdvar.h>
440Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
450Sstevel@tonic-gate #include <stddef.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate  * FUNCTION:    meta_get_raid_names()
490Sstevel@tonic-gate  * INPUT:       sp      - the set name to get raid from
500Sstevel@tonic-gate  *              options - options from the command line
510Sstevel@tonic-gate  * OUTPUT:      nlpp    - list of all raid names
520Sstevel@tonic-gate  *              ep      - return error pointer
530Sstevel@tonic-gate  * RETURNS:     int     - -1 if error, 0 success
540Sstevel@tonic-gate  * PURPOSE:     returns a list of all raid in the metadb
550Sstevel@tonic-gate  *              for all devices in the specified set
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate int
580Sstevel@tonic-gate meta_get_raid_names(
590Sstevel@tonic-gate 	mdsetname_t	*sp,
600Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
610Sstevel@tonic-gate 	int		options,
620Sstevel@tonic-gate 	md_error_t	*ep
630Sstevel@tonic-gate )
640Sstevel@tonic-gate {
650Sstevel@tonic-gate 	return (meta_get_names(MD_RAID, sp, nlpp, options, ep));
660Sstevel@tonic-gate }
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * free raid unit
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate void
720Sstevel@tonic-gate meta_free_raid(
730Sstevel@tonic-gate 	md_raid_t	*raidp
740Sstevel@tonic-gate )
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	if (raidp->cols.cols_val != NULL) {
770Sstevel@tonic-gate 		assert(raidp->cols.cols_len > 0);
780Sstevel@tonic-gate 		Free(raidp->cols.cols_val);
790Sstevel@tonic-gate 	}
800Sstevel@tonic-gate 	Free(raidp);
810Sstevel@tonic-gate }
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate  * get raid (common)
850Sstevel@tonic-gate  */
860Sstevel@tonic-gate md_raid_t *
870Sstevel@tonic-gate meta_get_raid_common(
880Sstevel@tonic-gate 	mdsetname_t		*sp,
890Sstevel@tonic-gate 	mdname_t		*raidnp,
900Sstevel@tonic-gate 	int			fast,
910Sstevel@tonic-gate 	md_error_t		*ep
920Sstevel@tonic-gate )
930Sstevel@tonic-gate {
940Sstevel@tonic-gate 	mddrivename_t		*dnp = raidnp->drivenamep;
950Sstevel@tonic-gate 	char			*miscname;
960Sstevel@tonic-gate 	mr_unit_t		*mr;
970Sstevel@tonic-gate 	md_raid_t		*raidp;
980Sstevel@tonic-gate 	uint_t			ncol;
990Sstevel@tonic-gate 	uint_t			col;
1000Sstevel@tonic-gate 	md_resync_ioctl_t	ri;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	/* must have set */
1030Sstevel@tonic-gate 	assert(sp != NULL);
1040Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	/* short circuit */
1070Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
1080Sstevel@tonic-gate 		assert(dnp->unitp->type == MD_METARAID);
1090Sstevel@tonic-gate 		return ((md_raid_t *)dnp->unitp);
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/* get miscname and unit */
1130Sstevel@tonic-gate 	if ((miscname = metagetmiscname(raidnp, ep)) == NULL)
1140Sstevel@tonic-gate 		return (NULL);
1150Sstevel@tonic-gate 	if (strcmp(miscname, MD_RAID) != 0) {
1160Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NOT_RAID, meta_getminor(raidnp->dev),
1170Sstevel@tonic-gate 		    raidnp->cname);
1180Sstevel@tonic-gate 		return (NULL);
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 	if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
1210Sstevel@tonic-gate 		return (NULL);
1220Sstevel@tonic-gate 	assert(mr->c.un_type == MD_METARAID);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	/* allocate raid */
1250Sstevel@tonic-gate 	raidp = Zalloc(sizeof (*raidp));
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	/* allocate columns */
1280Sstevel@tonic-gate 	ncol = mr->un_totalcolumncnt;
1290Sstevel@tonic-gate 	assert(ncol >= MD_RAID_MIN);
1300Sstevel@tonic-gate 	raidp->cols.cols_len = ncol;
1310Sstevel@tonic-gate 	raidp->cols.cols_val = Zalloc(raidp->cols.cols_len *
1320Sstevel@tonic-gate 	    sizeof (*raidp->cols.cols_val));
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	/* get common info */
1350Sstevel@tonic-gate 	raidp->common.namep = raidnp;
1360Sstevel@tonic-gate 	raidp->common.type = mr->c.un_type;
1370Sstevel@tonic-gate 	raidp->common.state = mr->c.un_status;
1380Sstevel@tonic-gate 	raidp->common.capabilities = mr->c.un_capabilities;
1390Sstevel@tonic-gate 	raidp->common.parent = mr->c.un_parent;
1400Sstevel@tonic-gate 	raidp->common.size = mr->c.un_total_blocks;
1410Sstevel@tonic-gate 	raidp->common.user_flags = mr->c.un_user_flags;
1420Sstevel@tonic-gate 	raidp->common.revision = mr->c.un_revision;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	/* get options */
1450Sstevel@tonic-gate 	raidp->state = mr->un_state;
1460Sstevel@tonic-gate 	raidp->timestamp = mr->un_timestamp;
1470Sstevel@tonic-gate 	raidp->interlace = mr->un_segsize;
1480Sstevel@tonic-gate 	raidp->orig_ncol = mr->un_origcolumncnt;
1490Sstevel@tonic-gate 	raidp->column_size = mr->un_segsize * mr->un_segsincolumn;
1500Sstevel@tonic-gate 	raidp->pw_count = mr->un_pwcnt;
1510Sstevel@tonic-gate 	assert(raidp->orig_ncol <= ncol);
1520Sstevel@tonic-gate 	if ((mr->un_hsp_id != MD_HSP_NONE) &&
1530Sstevel@tonic-gate 	    ((raidp->hspnamep = metahsphspname(&sp, mr->un_hsp_id,
1540Sstevel@tonic-gate 	    ep)) == NULL)) {
1550Sstevel@tonic-gate 		goto out;
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/* get columns, update unit state */
1590Sstevel@tonic-gate 	for (col = 0; (col < ncol); ++col) {
1600Sstevel@tonic-gate 		mr_column_t	*rcp = &mr->un_column[col];
1610Sstevel@tonic-gate 		md_raidcol_t	*mdrcp = &raidp->cols.cols_val[col];
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 		/* get column name */
1640Sstevel@tonic-gate 		mdrcp->colnamep = metakeyname(&sp, rcp->un_orig_key, fast, ep);
1650Sstevel@tonic-gate 		if (mdrcp->colnamep == NULL)
1660Sstevel@tonic-gate 			goto out;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		/* override any start_blk */
1690Sstevel@tonic-gate #ifdef	DEBUG
1700Sstevel@tonic-gate 		if (metagetstart(sp, mdrcp->colnamep, ep) !=
1710Sstevel@tonic-gate 		    MD_DISKADDR_ERROR) {
1720Sstevel@tonic-gate 			assert(mdrcp->colnamep->start_blk <=
1730Sstevel@tonic-gate 			    rcp->un_orig_devstart);
1740Sstevel@tonic-gate 		} else {
1750Sstevel@tonic-gate 			mdclrerror(ep);
1760Sstevel@tonic-gate 		}
1770Sstevel@tonic-gate #endif	/* DEBUG */
1780Sstevel@tonic-gate 		mdrcp->colnamep->start_blk = rcp->un_orig_devstart;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 		/* if hotspared */
1810Sstevel@tonic-gate 		if (HOTSPARED(mr, col)) {
1820Sstevel@tonic-gate 			/* get hotspare name */
1830Sstevel@tonic-gate 			mdrcp->hsnamep = metakeyname(&sp, rcp->un_hs_key,
1840Sstevel@tonic-gate 			    fast, ep);
1850Sstevel@tonic-gate 			if (mdrcp->hsnamep == NULL)
1860Sstevel@tonic-gate 				goto out;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 			if (getenv("META_DEBUG_START_BLK") != NULL) {
1890Sstevel@tonic-gate 				if (metagetstart(sp, mdrcp->hsnamep, ep) ==
1900Sstevel@tonic-gate 				    MD_DISKADDR_ERROR)
1910Sstevel@tonic-gate 					mdclrerror(ep);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 				if ((mdrcp->hsnamep->start_blk == 0) &&
1940Sstevel@tonic-gate 				    (rcp->un_hs_pwstart != 0))
1950Sstevel@tonic-gate 					md_eprintf(dgettext(TEXT_DOMAIN,
1960Sstevel@tonic-gate 					    "%s: suspected bad start block,"
1970Sstevel@tonic-gate 					    " seems labelled [raid]\n"),
1980Sstevel@tonic-gate 					    mdrcp->hsnamep->cname);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 				if ((mdrcp->hsnamep->start_blk > 0) &&
2010Sstevel@tonic-gate 				    (rcp->un_hs_pwstart == 0))
2020Sstevel@tonic-gate 					md_eprintf(dgettext(TEXT_DOMAIN,
2030Sstevel@tonic-gate 					    "%s: suspected bad start block, "
2040Sstevel@tonic-gate 					    " seems unlabelled [raid]\n"),
2050Sstevel@tonic-gate 					    mdrcp->hsnamep->cname);
2060Sstevel@tonic-gate 			}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 			/* override any start_blk */
2090Sstevel@tonic-gate 			mdrcp->hsnamep->start_blk = rcp->un_hs_devstart;
2100Sstevel@tonic-gate 		}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 		/* get state, flags, and timestamp */
2130Sstevel@tonic-gate 		mdrcp->state = rcp->un_devstate;
2140Sstevel@tonic-gate 		mdrcp->flags = rcp->un_devflags;
2150Sstevel@tonic-gate 		mdrcp->timestamp = rcp->un_devtimestamp;
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	/* get resync info */
2190Sstevel@tonic-gate 	(void) memset(&ri, 0, sizeof (ri));
2200Sstevel@tonic-gate 	ri.ri_mnum = meta_getminor(raidnp->dev);
2210Sstevel@tonic-gate 	MD_SETDRIVERNAME(&ri, MD_RAID, sp->setno);
2220Sstevel@tonic-gate 	if (metaioctl(MD_IOCGETSYNC, &ri, &ri.mde, raidnp->cname) != 0) {
2230Sstevel@tonic-gate 		(void) mdstealerror(ep, &ri.mde);
2240Sstevel@tonic-gate 		goto out;
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 	raidp->resync_flags = ri.ri_flags;
2270Sstevel@tonic-gate 	raidp->percent_dirty = ri.ri_percent_dirty;
2280Sstevel@tonic-gate 	raidp->percent_done = ri.ri_percent_done;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	/* cleanup, return success */
2310Sstevel@tonic-gate 	Free(mr);
2320Sstevel@tonic-gate 	dnp->unitp = (md_common_t *)raidp;
2330Sstevel@tonic-gate 	return (raidp);
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/* cleanup, return error */
2360Sstevel@tonic-gate out:
2370Sstevel@tonic-gate 	Free(mr);
2380Sstevel@tonic-gate 	meta_free_raid(raidp);
2390Sstevel@tonic-gate 	return (NULL);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate /*
2430Sstevel@tonic-gate  * get raid
2440Sstevel@tonic-gate  */
2450Sstevel@tonic-gate md_raid_t *
2460Sstevel@tonic-gate meta_get_raid(
2470Sstevel@tonic-gate 	mdsetname_t		*sp,
2480Sstevel@tonic-gate 	mdname_t		*raidnp,
2490Sstevel@tonic-gate 	md_error_t		*ep
2500Sstevel@tonic-gate )
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	return (meta_get_raid_common(sp, raidnp, 0, ep));
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate  * check raid for dev
2570Sstevel@tonic-gate  */
2580Sstevel@tonic-gate static int
2590Sstevel@tonic-gate in_raid(
2600Sstevel@tonic-gate 	mdsetname_t	*sp,
2610Sstevel@tonic-gate 	mdname_t	*raidnp,
2620Sstevel@tonic-gate 	mdname_t	*np,
2630Sstevel@tonic-gate 	diskaddr_t	slblk,
2640Sstevel@tonic-gate 	diskaddr_t	nblks,
2650Sstevel@tonic-gate 	md_error_t	*ep
2660Sstevel@tonic-gate )
2670Sstevel@tonic-gate {
2680Sstevel@tonic-gate 	md_raid_t	*raidp;
2690Sstevel@tonic-gate 	uint_t		col;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/* should be in the same set */
2720Sstevel@tonic-gate 	assert(sp != NULL);
2730Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	/* get unit */
2760Sstevel@tonic-gate 	if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
2770Sstevel@tonic-gate 		return (-1);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	/* look in columns */
2800Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
2810Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
2820Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
2830Sstevel@tonic-gate 		diskaddr_t	col_sblk;
2840Sstevel@tonic-gate 		int		err;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 		/* check same drive since metagetstart() can fail */
2870Sstevel@tonic-gate 		if ((err = meta_check_samedrive(np, colnp, ep)) < 0)
2880Sstevel@tonic-gate 			return (-1);
2890Sstevel@tonic-gate 		else if (err == 0)
2900Sstevel@tonic-gate 			continue;
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 		/* check overlap */
2930Sstevel@tonic-gate 		if ((col_sblk = metagetstart(sp, colnp, ep)) ==
2940Sstevel@tonic-gate 		    MD_DISKADDR_ERROR)
2950Sstevel@tonic-gate 			return (-1);
2960Sstevel@tonic-gate 		if (meta_check_overlap(raidnp->cname, np, slblk, nblks,
2970Sstevel@tonic-gate 		    colnp, col_sblk, -1, ep) != 0) {
2980Sstevel@tonic-gate 			return (-1);
2990Sstevel@tonic-gate 		}
3000Sstevel@tonic-gate 	}
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	/* return success */
3030Sstevel@tonic-gate 	return (0);
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate /*
3070Sstevel@tonic-gate  * check to see if we're in a raid
3080Sstevel@tonic-gate  */
3090Sstevel@tonic-gate int
3100Sstevel@tonic-gate meta_check_inraid(
3110Sstevel@tonic-gate 	mdsetname_t	*sp,
3120Sstevel@tonic-gate 	mdname_t	*np,
3130Sstevel@tonic-gate 	diskaddr_t	slblk,
3140Sstevel@tonic-gate 	diskaddr_t	nblks,
3150Sstevel@tonic-gate 	md_error_t	*ep
3160Sstevel@tonic-gate )
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate 	mdnamelist_t	*raidnlp = NULL;
3190Sstevel@tonic-gate 	mdnamelist_t	*p;
3200Sstevel@tonic-gate 	int		rval = 0;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	/* should have a set */
3230Sstevel@tonic-gate 	assert(sp != NULL);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/* for each raid */
3260Sstevel@tonic-gate 	if (meta_get_raid_names(sp, &raidnlp, 0, ep) < 0)
3270Sstevel@tonic-gate 		return (-1);
3280Sstevel@tonic-gate 	for (p = raidnlp; (p != NULL); p = p->next) {
3290Sstevel@tonic-gate 		mdname_t	*raidnp = p->namep;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 		/* check raid */
3320Sstevel@tonic-gate 		if (in_raid(sp, raidnp, np, slblk, nblks, ep) != 0) {
3330Sstevel@tonic-gate 			rval = -1;
3340Sstevel@tonic-gate 			break;
3350Sstevel@tonic-gate 		}
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/* cleanup, return success */
3390Sstevel@tonic-gate 	metafreenamelist(raidnlp);
3400Sstevel@tonic-gate 	return (rval);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate /*
3440Sstevel@tonic-gate  * check column
3450Sstevel@tonic-gate  */
3460Sstevel@tonic-gate int
3470Sstevel@tonic-gate meta_check_column(
3480Sstevel@tonic-gate 	mdsetname_t	*sp,
3490Sstevel@tonic-gate 	mdname_t	*np,
3500Sstevel@tonic-gate 	md_error_t	*ep
3510Sstevel@tonic-gate )
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	mdchkopts_t	options = (MDCHK_ALLOW_MDDB);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	/* check for soft partitions */
3560Sstevel@tonic-gate 	if (meta_sp_issp(sp, np, ep) != 0) {
3570Sstevel@tonic-gate 		/* make sure we have a disk */
3580Sstevel@tonic-gate 		if (metachkcomp(np, ep) != 0)
3590Sstevel@tonic-gate 			return (-1);
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
3630Sstevel@tonic-gate 	if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
3640Sstevel@tonic-gate 		return (-1);
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	/* make sure it is in the set */
3680Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
3690Sstevel@tonic-gate 		return (-1);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	/* make sure its not in a metadevice */
3720Sstevel@tonic-gate 	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
3730Sstevel@tonic-gate 		return (-1);
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	/* return success */
3760Sstevel@tonic-gate 	return (0);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * print raid
3810Sstevel@tonic-gate  */
3820Sstevel@tonic-gate static int
3830Sstevel@tonic-gate raid_print(
3840Sstevel@tonic-gate 	md_raid_t	*raidp,
3850Sstevel@tonic-gate 	char		*fname,
3860Sstevel@tonic-gate 	FILE		*fp,
3870Sstevel@tonic-gate 	mdprtopts_t	options,
3880Sstevel@tonic-gate 	md_error_t	*ep
3890Sstevel@tonic-gate )
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	uint_t		col;
3920Sstevel@tonic-gate 	int		rval = -1;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
3960Sstevel@tonic-gate 		if (raidp->common.revision != MD_64BIT_META_DEV) {
3970Sstevel@tonic-gate 			rval = 0;
3980Sstevel@tonic-gate 			goto out;
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/* print name and -r */
4030Sstevel@tonic-gate 	if (fprintf(fp, "%s -r", raidp->common.namep->cname) == EOF)
4040Sstevel@tonic-gate 		goto out;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	/* print columns */
4070Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
4080Sstevel@tonic-gate 		md_raidcol_t	*mdrcp = &raidp->cols.cols_val[col];
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		/* print column */
4110Sstevel@tonic-gate 		/*
4120Sstevel@tonic-gate 		 * If the path is our standard /dev/rdsk or /dev/md/rdsk
4130Sstevel@tonic-gate 		 * then just print out the cxtxdxsx or the dx, metainit
4140Sstevel@tonic-gate 		 * will assume the default, otherwise we need the full
4150Sstevel@tonic-gate 		 * pathname to make sure this works as we intend.
4160Sstevel@tonic-gate 		 */
4170Sstevel@tonic-gate 		if ((strstr(mdrcp->colnamep->rname, "/dev/rdsk") == NULL) &&
4180Sstevel@tonic-gate 		    (strstr(mdrcp->colnamep->rname, "/dev/md/rdsk") == NULL) &&
4190Sstevel@tonic-gate 		    (strstr(mdrcp->colnamep->rname, "/dev/td/") == NULL)) {
4200Sstevel@tonic-gate 			/* not standard path, print full pathname */
4210Sstevel@tonic-gate 			if (fprintf(fp, " %s", mdrcp->colnamep->rname) == EOF)
4220Sstevel@tonic-gate 				goto out;
4230Sstevel@tonic-gate 		} else {
4240Sstevel@tonic-gate 			/* standard path so print ctd or d number */
4250Sstevel@tonic-gate 			if (fprintf(fp, " %s", mdrcp->colnamep->cname) == EOF)
4260Sstevel@tonic-gate 				goto out;
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	if (fprintf(fp, " -k") == EOF)
4310Sstevel@tonic-gate 		goto out;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/* print options */
4340Sstevel@tonic-gate 	if (fprintf(fp, " -i %lldb", raidp->interlace) == EOF)
4350Sstevel@tonic-gate 		goto out;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	if (raidp->pw_count != PWCNT_MIN)
4380Sstevel@tonic-gate 		if (fprintf(fp, " -w %d", raidp->pw_count) == EOF)
4390Sstevel@tonic-gate 			goto out;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if (raidp->hspnamep != NULL) {
4420Sstevel@tonic-gate 		if (fprintf(fp, " -h %s", raidp->hspnamep->hspname) == EOF)
4430Sstevel@tonic-gate 			goto out;
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 	if (raidp->orig_ncol != raidp->cols.cols_len) {
4460Sstevel@tonic-gate 		assert(raidp->orig_ncol < raidp->cols.cols_len);
4470Sstevel@tonic-gate 		if (fprintf(fp, " -o %u", raidp->orig_ncol) == EOF)
4480Sstevel@tonic-gate 			goto out;
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	/* terminate last line */
4520Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
4530Sstevel@tonic-gate 		goto out;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	/* success */
4560Sstevel@tonic-gate 	rval = 0;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/* cleanup, return error */
4590Sstevel@tonic-gate out:
4600Sstevel@tonic-gate 	if (rval != 0)
4610Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
4620Sstevel@tonic-gate 	return (rval);
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate static int
4660Sstevel@tonic-gate find_resyncing_column(
4670Sstevel@tonic-gate 	md_raid_t *raidp
4680Sstevel@tonic-gate )
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate 	int		col;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
4730Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
4740Sstevel@tonic-gate 		if (cp->state & RCS_RESYNC)
4750Sstevel@tonic-gate 			return (col);
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	/* No resyncing columns */
4790Sstevel@tonic-gate 	return (-1);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate /*
4830Sstevel@tonic-gate  * convert raid state to name
4840Sstevel@tonic-gate  */
4850Sstevel@tonic-gate char *
4860Sstevel@tonic-gate raid_state_to_name(
4870Sstevel@tonic-gate 	md_raid_t	*raidp,
4880Sstevel@tonic-gate 	md_timeval32_t	*tvp,
4890Sstevel@tonic-gate 	uint_t		tstate /* Errored tstate flags */
4900Sstevel@tonic-gate )
4910Sstevel@tonic-gate {
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	/* grab time */
4940Sstevel@tonic-gate 	if (tvp != NULL)
4950Sstevel@tonic-gate 		*tvp = raidp->timestamp;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	/*
4980Sstevel@tonic-gate 	 * If the device has a transient error state (due to it being DR'ed or
4990Sstevel@tonic-gate 	 * failed) and there has been no I/O to it (the actual device is still
5000Sstevel@tonic-gate 	 * marked as 'Okay') then we cannot know what the state is or what
5010Sstevel@tonic-gate 	 * action to take on it. Therefore report the device as 'Unavailable'.
5020Sstevel@tonic-gate 	 * A subsequent I/O to the device will cause the 'Okay' status to
5030Sstevel@tonic-gate 	 * disappear if the device is actually gone and then we will print out
5040Sstevel@tonic-gate 	 * the appropriate status.  The MD_INACCESSIBLE state is only set
5050Sstevel@tonic-gate 	 * on the raid when we open it or probe it.  One the raid is open
5060Sstevel@tonic-gate 	 * then we will just have regular error status on the device.
5070Sstevel@tonic-gate 	 */
5080Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
5090Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/* resyncing */
5130Sstevel@tonic-gate 	if (find_resyncing_column(raidp) >= 0)
5140Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Resyncing"));
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	/* everything else */
5170Sstevel@tonic-gate 	switch (raidp->state) {
5180Sstevel@tonic-gate 		case RUS_INIT :
5190Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Initializing"));
5200Sstevel@tonic-gate 		case RUS_OKAY :
5210Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Okay"));
5220Sstevel@tonic-gate 		case RUS_ERRED :
5230Sstevel@tonic-gate 		/*FALLTHROUGH*/
5240Sstevel@tonic-gate 		case RUS_LAST_ERRED :
5250Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Needs Maintenance"));
5260Sstevel@tonic-gate 		case RUS_DOI :
5270Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Initialization Failed"));
5280Sstevel@tonic-gate 		case RUS_REGEN :
5290Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Regen"));
5300Sstevel@tonic-gate 		default :
5310Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "invalid"));
5320Sstevel@tonic-gate 	} /* switch */
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate static int
5360Sstevel@tonic-gate find_erred_column(md_raid_t *raidp, rcs_state_t state)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	int		col;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
5410Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
5420Sstevel@tonic-gate 		if (cp->state & state)
5430Sstevel@tonic-gate 			return (col);
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	/* No erred columns */
5470Sstevel@tonic-gate 	return (-1);
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate /*
5510Sstevel@tonic-gate  * convert raid state to repair action
5520Sstevel@tonic-gate  */
5530Sstevel@tonic-gate char *
5540Sstevel@tonic-gate raid_state_to_action(md_raid_t *raidp)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate 	static char	emsg[1024];
5570Sstevel@tonic-gate 	mdname_t	*raidnp = raidp->common.namep;
5580Sstevel@tonic-gate 	int		err_col;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	/* first check for full init failure */
5610Sstevel@tonic-gate 	if (raidp->state & RUS_DOI) {
5620Sstevel@tonic-gate 		(void) snprintf(emsg, sizeof (emsg),
5630Sstevel@tonic-gate 		    "metaclear -f %s", raidnp->cname);
5640Sstevel@tonic-gate 		return (emsg);
5650Sstevel@tonic-gate 	}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	/* replace errored or init errored raid column */
5680Sstevel@tonic-gate 	if ((err_col = find_erred_column(raidp,
5690Sstevel@tonic-gate 	    (RCS_ERRED | RCS_INIT_ERRED))) >= 0) {
5700Sstevel@tonic-gate 		mdname_t	*colnp;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 		/* get column with error */
5730Sstevel@tonic-gate 		assert(err_col < raidp->cols.cols_len);
5740Sstevel@tonic-gate 		colnp = raidp->cols.cols_val[err_col].colnamep;
5750Sstevel@tonic-gate 		(void) snprintf(emsg, sizeof (emsg),
5760Sstevel@tonic-gate 		    "metareplace %s%s %s <%s>",
5770Sstevel@tonic-gate 		    ((raidp->state == RUS_LAST_ERRED) ? "-f " : ""),
5780Sstevel@tonic-gate 		    raidnp->cname, colnp->cname,
5790Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "new device"));
5800Sstevel@tonic-gate 		return (emsg);
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	/* replace last errored raid column */
5850Sstevel@tonic-gate 	if ((err_col = find_erred_column(raidp, RCS_LAST_ERRED)) >= 0) {
5860Sstevel@tonic-gate 		mdname_t	*colnp;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		assert(err_col < raidp->cols.cols_len);
5890Sstevel@tonic-gate 		colnp = raidp->cols.cols_val[err_col].colnamep;
5900Sstevel@tonic-gate 		(void) snprintf(emsg, sizeof (emsg),
5910Sstevel@tonic-gate 		    "metareplace %s %s %s <%s>",
5920Sstevel@tonic-gate 		    ((raidp->state == RUS_LAST_ERRED) ? "-f " : ""),
5930Sstevel@tonic-gate 		    raidnp->cname, colnp->cname,
5940Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "new device"));
5950Sstevel@tonic-gate 		return (emsg);
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	/* OK */
5990Sstevel@tonic-gate 	return (NULL);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate /*
6030Sstevel@tonic-gate  * get printable raid column state
6040Sstevel@tonic-gate  */
6050Sstevel@tonic-gate char *
6060Sstevel@tonic-gate raid_col_state_to_name(
6070Sstevel@tonic-gate 	md_raidcol_t	*colp,
6080Sstevel@tonic-gate 	md_timeval32_t	*tvp,
6090Sstevel@tonic-gate 	uint_t		tstate
6100Sstevel@tonic-gate )
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate 	/* grab time */
6130Sstevel@tonic-gate 	if (tvp != NULL)
6140Sstevel@tonic-gate 		*tvp = colp->timestamp;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	if (tstate != 0) {
6170Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	/* everything else */
6210Sstevel@tonic-gate 	switch (colp->state) {
6220Sstevel@tonic-gate 	case RCS_INIT:
6230Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Initializing"));
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	case RCS_OKAY:
6260Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Okay"));
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	case RCS_INIT_ERRED:
6290Sstevel@tonic-gate 	/*FALLTHROUGH*/
6300Sstevel@tonic-gate 	case RCS_ERRED:
6310Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Maintenance"));
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	case RCS_LAST_ERRED:
6340Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Last Erred"));
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	case RCS_RESYNC:
6370Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Resyncing"));
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	default:
6400Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unknown"));
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate /*
6450Sstevel@tonic-gate  * print raid column
6460Sstevel@tonic-gate  */
6470Sstevel@tonic-gate static int
6480Sstevel@tonic-gate display_raid_device_info(
6490Sstevel@tonic-gate 	mdsetname_t	*sp,
6500Sstevel@tonic-gate 	md_raidcol_t	*colp,
6510Sstevel@tonic-gate 	char		*fname,
6520Sstevel@tonic-gate 	FILE		*fp,
6530Sstevel@tonic-gate 	mdprtopts_t	options,
6540Sstevel@tonic-gate 	int		print_len,
6550Sstevel@tonic-gate 	uint_t		top_tstate, /* Errored tstate flags */
6560Sstevel@tonic-gate 	md_error_t	*ep
6570Sstevel@tonic-gate )
6580Sstevel@tonic-gate {
6590Sstevel@tonic-gate 	mdname_t	*namep = ((colp->hsnamep != NULL) ?
6600Sstevel@tonic-gate 				    colp->hsnamep : colp->colnamep);
6610Sstevel@tonic-gate 	char 		*devid = "";
6620Sstevel@tonic-gate 	char		*cname = colp->colnamep->cname;
6630Sstevel@tonic-gate 	diskaddr_t	start_blk;
6640Sstevel@tonic-gate 	int		has_mddb;
6650Sstevel@tonic-gate 	char		*has_mddb_str;
6660Sstevel@tonic-gate 	char		*col_state;
6670Sstevel@tonic-gate 	md_timeval32_t	tv;
6680Sstevel@tonic-gate 	char		*hsname = ((colp->hsnamep != NULL) ?
6690Sstevel@tonic-gate 			    colp->hsnamep->cname : "");
6700Sstevel@tonic-gate 	int		rval = -1;
6710Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
6720Sstevel@tonic-gate 	ddi_devid_t	dtp;
6730Sstevel@tonic-gate 	uint_t		tstate = 0;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	/* get info */
6760Sstevel@tonic-gate 	if ((start_blk = metagetstart(sp, namep, ep)) == MD_DISKADDR_ERROR)
6770Sstevel@tonic-gate 		return (-1);
6780Sstevel@tonic-gate 	if ((has_mddb = metahasmddb(sp, namep, ep)) < 0)
6790Sstevel@tonic-gate 		return (-1);
6800Sstevel@tonic-gate 	if (has_mddb)
6810Sstevel@tonic-gate 		has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
6820Sstevel@tonic-gate 	else
6830Sstevel@tonic-gate 		has_mddb_str = dgettext(TEXT_DOMAIN, "No");
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	if (metaismeta(namep)) {
6860Sstevel@tonic-gate 		if (meta_get_tstate(namep->dev, &tstate, ep) != 0)
6870Sstevel@tonic-gate 			return (-1);
6880Sstevel@tonic-gate 		col_state = raid_col_state_to_name(colp, &tv,
6890Sstevel@tonic-gate 		    tstate & MD_DEV_ERRORED);
6900Sstevel@tonic-gate 	} else {
6910Sstevel@tonic-gate 		/*
6920Sstevel@tonic-gate 		 * if top_tstate is set, that implies that you have
6930Sstevel@tonic-gate 		 * a ctd type device with an unavailable metadevice
6940Sstevel@tonic-gate 		 * on top of it. If so, print a - for it's state
6950Sstevel@tonic-gate 		 */
6960Sstevel@tonic-gate 		if (top_tstate != 0)
6970Sstevel@tonic-gate 			col_state = "-";
6980Sstevel@tonic-gate 		else
6990Sstevel@tonic-gate 			col_state = raid_col_state_to_name(colp, &tv, tstate);
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	/* populate the key in the name_p structure */
7030Sstevel@tonic-gate 	if ((didnp = metadevname(&sp, namep->dev, ep)) == NULL)
7040Sstevel@tonic-gate 		return (-1);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/* determine if devid does NOT exist */
7070Sstevel@tonic-gate 	if (options & PRINT_DEVID) {
7080Sstevel@tonic-gate 		if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
7090Sstevel@tonic-gate 			didnp->key, ep)) == NULL)
7100Sstevel@tonic-gate 			devid = dgettext(TEXT_DOMAIN, "No ");
7110Sstevel@tonic-gate 		else {
7120Sstevel@tonic-gate 			devid = dgettext(TEXT_DOMAIN, "Yes");
7130Sstevel@tonic-gate 			free(dtp);
7140Sstevel@tonic-gate 		}
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 	/* print column */
7170Sstevel@tonic-gate 	/*
7180Sstevel@tonic-gate 	 * Building a format string on the fly that will
7190Sstevel@tonic-gate 	 * be used in (f)printf. This allows the length
7200Sstevel@tonic-gate 	 * of the ctd to vary from small to large without
7210Sstevel@tonic-gate 	 * looking horrible.
7220Sstevel@tonic-gate 	 */
7230Sstevel@tonic-gate 	if (! (options & PRINT_TIMES)) {
7240Sstevel@tonic-gate 		if (fprintf(fp,
7250Sstevel@tonic-gate 		    "\t%-*.*s %8lld     %5.5s %12.12s %5.5s %s\n",
7260Sstevel@tonic-gate 		    print_len, print_len, cname, start_blk, has_mddb_str,
7270Sstevel@tonic-gate 		    col_state, devid, hsname) == EOF) {
7280Sstevel@tonic-gate 			goto out;
7290Sstevel@tonic-gate 		}
7300Sstevel@tonic-gate 	} else {
7310Sstevel@tonic-gate 		char	*timep = meta_print_time(&tv);
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 		if (fprintf(fp,
7340Sstevel@tonic-gate 		    "\t%-*s %5lld %-5s %-11s %-5s %-9s %s\n",
7350Sstevel@tonic-gate 		    print_len, cname, start_blk, has_mddb_str,
7360Sstevel@tonic-gate 		    col_state, devid, hsname, timep) == EOF) {
7370Sstevel@tonic-gate 			goto out;
7380Sstevel@tonic-gate 		}
7390Sstevel@tonic-gate 	}
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	/* success */
7420Sstevel@tonic-gate 	rval = 0;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	/* cleanup, return error */
7450Sstevel@tonic-gate out:
7460Sstevel@tonic-gate 	if (rval != 0)
7470Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	return (rval);
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate /*
7530Sstevel@tonic-gate  * print raid options
7540Sstevel@tonic-gate  */
7550Sstevel@tonic-gate int
7560Sstevel@tonic-gate meta_print_raid_options(
7570Sstevel@tonic-gate 	mdhspname_t	*hspnamep,
7580Sstevel@tonic-gate 	char		*fname,
7590Sstevel@tonic-gate 	FILE		*fp,
7600Sstevel@tonic-gate 	md_error_t	*ep
7610Sstevel@tonic-gate )
7620Sstevel@tonic-gate {
7630Sstevel@tonic-gate 	char		*hspname = ((hspnamep != NULL) ? hspnamep->hspname :
7640Sstevel@tonic-gate 					dgettext(TEXT_DOMAIN, "none"));
7650Sstevel@tonic-gate 	int		rval = -1;
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/* print options */
7680Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN,
7690Sstevel@tonic-gate 	    "    Hot spare pool: %s\n"), hspname) == EOF) {
7700Sstevel@tonic-gate 		goto out;
7710Sstevel@tonic-gate 	}
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	/* success */
7740Sstevel@tonic-gate 	rval = 0;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/* cleanup, return error */
7770Sstevel@tonic-gate out:
7780Sstevel@tonic-gate 	if (rval != 0)
7790Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
7800Sstevel@tonic-gate 	return (rval);
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate /*
7840Sstevel@tonic-gate  * report raid
7850Sstevel@tonic-gate  */
7860Sstevel@tonic-gate static int
7870Sstevel@tonic-gate raid_report(
7880Sstevel@tonic-gate 	mdsetname_t	*sp,
7890Sstevel@tonic-gate 	md_raid_t	*raidp,
7900Sstevel@tonic-gate 	char		*fname,
7910Sstevel@tonic-gate 	FILE		*fp,
7920Sstevel@tonic-gate 	mdprtopts_t	options,
7930Sstevel@tonic-gate 	md_error_t	*ep
7940Sstevel@tonic-gate )
7950Sstevel@tonic-gate {
7960Sstevel@tonic-gate 	char		*p;
7970Sstevel@tonic-gate 	uint_t		ncol = raidp->cols.cols_len;
7980Sstevel@tonic-gate 	uint_t		orig_ncol = raidp->orig_ncol;
7990Sstevel@tonic-gate 	diskaddr_t	column_size = raidp->column_size;
8000Sstevel@tonic-gate 	char		*raid_state;
8010Sstevel@tonic-gate 	md_timeval32_t	tv;
8020Sstevel@tonic-gate 	char		*timep;
8030Sstevel@tonic-gate 	uint_t		col;
8040Sstevel@tonic-gate 	int		rval = -1;
8050Sstevel@tonic-gate 	int		len = 0;
8060Sstevel@tonic-gate 	uint_t		tstate = 0;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
8090Sstevel@tonic-gate 		if (raidp->common.revision != MD_64BIT_META_DEV) {
8100Sstevel@tonic-gate 			rval = 0;
8110Sstevel@tonic-gate 			goto out;
8120Sstevel@tonic-gate 		}
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	/* print header */
8160Sstevel@tonic-gate 	if (options & PRINT_HEADER) {
8170Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: RAID\n"),
8180Sstevel@tonic-gate 		    raidp->common.namep->cname) == EOF) {
8190Sstevel@tonic-gate 			goto out;
8200Sstevel@tonic-gate 		}
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	}
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	/* print state */
8250Sstevel@tonic-gate 	if (metaismeta(raidp->common.namep)) {
8260Sstevel@tonic-gate 		if (meta_get_tstate(raidp->common.namep->dev, &tstate, ep) != 0)
8270Sstevel@tonic-gate 			return (-1);
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 	tstate &= MD_DEV_ERRORED; /* extract the errored tstate bits */
8300Sstevel@tonic-gate 	raid_state = raid_state_to_name(raidp, &tv, tstate);
8310Sstevel@tonic-gate 	if (options & PRINT_TIMES) {
8320Sstevel@tonic-gate 		timep = meta_print_time(&tv);
8330Sstevel@tonic-gate 	} else {
8340Sstevel@tonic-gate 		timep = "";
8350Sstevel@tonic-gate 	}
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    State: %-12s %s\n"),
8380Sstevel@tonic-gate 	    raid_state, timep) == EOF) {
8390Sstevel@tonic-gate 		goto out;
8400Sstevel@tonic-gate 	}
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	/*
8430Sstevel@tonic-gate 	 * Display recovery action if we're marked in the Unavailable state.
8440Sstevel@tonic-gate 	 */
8450Sstevel@tonic-gate 	if ((tstate == 0) || (tstate & MD_INACCESSIBLE)) {
8460Sstevel@tonic-gate 		/* print what to do */
8470Sstevel@tonic-gate 		if (tstate & MD_INACCESSIBLE) {
8480Sstevel@tonic-gate 			char sname[MD_MAX_SETNAME + 3]; /* 3 = sizeof("-s ") */
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 			if (metaislocalset(sp)) {
8510Sstevel@tonic-gate 				sname[0] = '\0';
8520Sstevel@tonic-gate 			} else {
8530Sstevel@tonic-gate 				(void) snprintf(sname, MD_MAX_SETNAME + 3,
8540Sstevel@tonic-gate 				    "-s %s", sp->setname);
8550Sstevel@tonic-gate 			}
8560Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
8570Sstevel@tonic-gate 			    "    Invoke: metastat -i %s\n"), sname) == EOF) {
8580Sstevel@tonic-gate 				goto out;
8590Sstevel@tonic-gate 			}
8600Sstevel@tonic-gate 		} else if ((p = raid_state_to_action(raidp)) != NULL) {
8610Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
8620Sstevel@tonic-gate 			    "    Invoke: %s\n"), p) == EOF) {
8630Sstevel@tonic-gate 				goto out;
8640Sstevel@tonic-gate 			}
8650Sstevel@tonic-gate 		}
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 		/* resync status */
8680Sstevel@tonic-gate 		if (raidp->resync_flags & MD_RI_INPROGRESS) {
8690Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
8700Sstevel@tonic-gate 			    "    Resync in progress: %2d.%1d%% done\n"),
8710Sstevel@tonic-gate 			    raidp->percent_done/10,
8720Sstevel@tonic-gate 			    raidp->percent_done % 10) == EOF) {
8730Sstevel@tonic-gate 				goto out;
8740Sstevel@tonic-gate 			}
8750Sstevel@tonic-gate 		} else if (raidp->resync_flags & MD_GROW_INPROGRESS) {
8760Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
8770Sstevel@tonic-gate 			    "    Initialization in progress: %2d.%1d%% "
8780Sstevel@tonic-gate 			    "done\n"),
8790Sstevel@tonic-gate 			    raidp->percent_done/10,
8800Sstevel@tonic-gate 			    raidp->percent_done % 10) == EOF) {
8810Sstevel@tonic-gate 				goto out;
8820Sstevel@tonic-gate 			}
8830Sstevel@tonic-gate 		} else if (raidp->state & RUS_REGEN) {
8840Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
8850Sstevel@tonic-gate 			    "    Parity regeneration in progress: %2d.%1d%% "
8860Sstevel@tonic-gate 			    "done\n"),
8870Sstevel@tonic-gate 			    raidp->percent_done/10,
8880Sstevel@tonic-gate 			    raidp->percent_done % 10) == EOF) {
8890Sstevel@tonic-gate 				goto out;
8900Sstevel@tonic-gate 			}
8910Sstevel@tonic-gate 		}
8920Sstevel@tonic-gate 	}
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	/* print hotspare pool */
8950Sstevel@tonic-gate 	if (raidp->hspnamep != NULL) {
8960Sstevel@tonic-gate 		if (meta_print_raid_options(raidp->hspnamep,
8970Sstevel@tonic-gate 		    fname, fp, ep) != 0) {
8980Sstevel@tonic-gate 			return (-1);
8990Sstevel@tonic-gate 		}
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	/* print interlace */
9030Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Interlace: %lld blocks\n"),
9040Sstevel@tonic-gate 	    raidp->interlace) == EOF) {
9050Sstevel@tonic-gate 		goto out;
9060Sstevel@tonic-gate 	}
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	/* print size */
9090Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %lld blocks (%s)\n"),
9100Sstevel@tonic-gate 	    raidp->common.size,
9110Sstevel@tonic-gate 	    meta_number_to_string(raidp->common.size, DEV_BSIZE)) == EOF) {
9120Sstevel@tonic-gate 		goto out;
9130Sstevel@tonic-gate 	}
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	/* MD_DEBUG stuff */
9160Sstevel@tonic-gate 	if (options & PRINT_DEBUG) {
9170Sstevel@tonic-gate 		mdname_t	*raidnp = raidp->common.namep;
9180Sstevel@tonic-gate 		mr_unit_t	*mr;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 		/* get additional info */
9210Sstevel@tonic-gate 		if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
9220Sstevel@tonic-gate 			return (-1);
9230Sstevel@tonic-gate 		assert(mr->c.un_type == MD_METARAID);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 		/* print prewrite count and size */
9260Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
9270Sstevel@tonic-gate 		    "    Prewrite Count: %u slots\n"),
9280Sstevel@tonic-gate 		    mr->un_pwcnt) == EOF) {
9290Sstevel@tonic-gate 			Free(mr);
9300Sstevel@tonic-gate 			goto out;
9310Sstevel@tonic-gate 		}
9320Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
9330Sstevel@tonic-gate 		    "    Prewrite Slot Size: %u blocks\n"),
9340Sstevel@tonic-gate 		    (mr->un_pwsize / mr->un_pwcnt)) == EOF) {
9350Sstevel@tonic-gate 			Free(mr);
9360Sstevel@tonic-gate 			goto out;
9370Sstevel@tonic-gate 		}
9380Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
9390Sstevel@tonic-gate 		    "    Prewrite Total Size: %u blocks\n"),
9400Sstevel@tonic-gate 		    mr->un_pwsize) == EOF) {
9410Sstevel@tonic-gate 			Free(mr);
9420Sstevel@tonic-gate 			goto out;
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 		Free(mr);
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	/* print original devices */
9480Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "Original device:\n")) == EOF)
9490Sstevel@tonic-gate 		goto out;
9500Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %lld blocks (%s)\n"),
9510Sstevel@tonic-gate 	    column_size * (orig_ncol - 1),
9520Sstevel@tonic-gate 	    meta_number_to_string(column_size * (orig_ncol - 1), DEV_BSIZE))
9530Sstevel@tonic-gate 	    == EOF) {
9540Sstevel@tonic-gate 		goto out;
9550Sstevel@tonic-gate 	}
9560Sstevel@tonic-gate 	/*
9570Sstevel@tonic-gate 	 * Building a format string on the fly that will
9580Sstevel@tonic-gate 	 * be used in (f)printf. This allows the length
9590Sstevel@tonic-gate 	 * of the ctd to vary from small to large without
9600Sstevel@tonic-gate 	 * looking horrible.
9610Sstevel@tonic-gate 	 */
9620Sstevel@tonic-gate 	for (col = 0; (col < orig_ncol); ++col) {
9630Sstevel@tonic-gate 		len = max(len,
9640Sstevel@tonic-gate 		    strlen(raidp->cols.cols_val[col].colnamep->cname));
9650Sstevel@tonic-gate 	}
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
9680Sstevel@tonic-gate 	len += 2;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	if (! (options & PRINT_TIMES)) {
9710Sstevel@tonic-gate 		if (fprintf(fp,
9720Sstevel@tonic-gate 		    "\t%-*.*s %-12.12s %-5.5s %12.12s %-5.5s  %s\n",
9730Sstevel@tonic-gate 		    len, len,
9740Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
9750Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start Block"),
9760Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
9770Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "State"),
9780Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc"),
9790Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Hot Spare")) == EOF) {
9800Sstevel@tonic-gate 			goto out;
9810Sstevel@tonic-gate 		}
9820Sstevel@tonic-gate 	} else {
9830Sstevel@tonic-gate 		if (fprintf(fp,
9840Sstevel@tonic-gate 		    "\t%-*s  %5s  %-5s  %-11s  %-5s   %-9s  %s\n",
9850Sstevel@tonic-gate 		    len,
9860Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Device"),
9870Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start"),
9880Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
9890Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "State"),
9900Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Reloc"),
9910Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Hot Spare"),
9920Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Time")) == EOF) {
9930Sstevel@tonic-gate 			goto out;
9940Sstevel@tonic-gate 		}
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate 	for (col = 0; (col < orig_ncol); ++col) {
9970Sstevel@tonic-gate 		md_raidcol_t	*mdrcp = &raidp->cols.cols_val[col];
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 		if (display_raid_device_info(sp, mdrcp, fname, fp, options,
10000Sstevel@tonic-gate 		    len, tstate, ep) != 0) {
10010Sstevel@tonic-gate 			return (-1);
10020Sstevel@tonic-gate 		}
10030Sstevel@tonic-gate 	}
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	/* print concatenated devices */
10060Sstevel@tonic-gate 	if (col < ncol) {
10070Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
10080Sstevel@tonic-gate 		    "Concatenated Devices:\n")) == EOF) {
10090Sstevel@tonic-gate 			goto out;
10100Sstevel@tonic-gate 		}
10110Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
10120Sstevel@tonic-gate 		    "    Size: %lld blocks (%s)\n"),
10130Sstevel@tonic-gate 		    column_size * (ncol - orig_ncol),
10140Sstevel@tonic-gate 		    meta_number_to_string(column_size * (ncol - orig_ncol),
10150Sstevel@tonic-gate 		    DEV_BSIZE))
10160Sstevel@tonic-gate 		    == EOF) {
10170Sstevel@tonic-gate 			goto out;
10180Sstevel@tonic-gate 		}
10190Sstevel@tonic-gate 		/*
10200Sstevel@tonic-gate 		 * This allows the length
10210Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
10220Sstevel@tonic-gate 		 * looking horrible.
10230Sstevel@tonic-gate 		 */
10240Sstevel@tonic-gate 		if (! (options & PRINT_TIMES)) {
10250Sstevel@tonic-gate 			if (fprintf(fp,
10260Sstevel@tonic-gate 			    "\t%-*.*s %-12.12s %-5.5s %-12.12s %5.5s %s\n",
10270Sstevel@tonic-gate 			    len, len,
10280Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
10290Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Start Block"),
10300Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Dbase"),
10310Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "State"),
10320Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc"),
10330Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Hot Spare")) == EOF) {
10340Sstevel@tonic-gate 				goto out;
10350Sstevel@tonic-gate 			}
10360Sstevel@tonic-gate 		} else {
10370Sstevel@tonic-gate 			if (fprintf(fp,
10380Sstevel@tonic-gate 			    "\t%-*s %5s %-5s %-11s %-9s %s\t%s\n",
10390Sstevel@tonic-gate 			    len,
10400Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
10410Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Start"),
10420Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Dbase"),
10430Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "State"),
10440Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc"),
10450Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Hot Spare"),
10460Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Time")) == EOF) {
10470Sstevel@tonic-gate 				goto out;
10480Sstevel@tonic-gate 			}
10490Sstevel@tonic-gate 		}
10500Sstevel@tonic-gate 		assert(col == orig_ncol);
10510Sstevel@tonic-gate 		for (/* void */; (col < ncol); col++) {
10520Sstevel@tonic-gate 			md_raidcol_t	*mdrcp = &raidp->cols.cols_val[col];
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 			if (display_raid_device_info(sp, mdrcp, fname, fp,
10550Sstevel@tonic-gate 			    options, len, tstate, ep) != 0) {
10560Sstevel@tonic-gate 				return (-1);
10570Sstevel@tonic-gate 			}
10580Sstevel@tonic-gate 		}
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	/* add extra line */
10620Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
10630Sstevel@tonic-gate 		goto out;
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	/* success */
10660Sstevel@tonic-gate 	rval = 0;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	/* cleanup, return error */
10690Sstevel@tonic-gate out:
10700Sstevel@tonic-gate 	if (rval != 0)
10710Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
10720Sstevel@tonic-gate 	return (rval);
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate /*
10760Sstevel@tonic-gate  * print/report raid
10770Sstevel@tonic-gate  */
10780Sstevel@tonic-gate int
10790Sstevel@tonic-gate meta_raid_print(
10800Sstevel@tonic-gate 	mdsetname_t	*sp,
10810Sstevel@tonic-gate 	mdname_t	*raidnp,
10820Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
10830Sstevel@tonic-gate 	char		*fname,
10840Sstevel@tonic-gate 	FILE		*fp,
10850Sstevel@tonic-gate 	mdprtopts_t	options,
10860Sstevel@tonic-gate 	md_error_t	*ep
10870Sstevel@tonic-gate )
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	md_raid_t	*raidp;
10900Sstevel@tonic-gate 	int		col;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	/* should have same set */
10930Sstevel@tonic-gate 	assert(sp != NULL);
10940Sstevel@tonic-gate 	assert((raidnp == NULL) ||
10950Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev))));
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	/* print all raids */
10980Sstevel@tonic-gate 	if (raidnp == NULL) {
10990Sstevel@tonic-gate 		mdnamelist_t	*nlp = NULL;
11000Sstevel@tonic-gate 		mdnamelist_t	*p;
11010Sstevel@tonic-gate 		int		cnt;
11020Sstevel@tonic-gate 		int		rval = 0;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 		/* get list */
11050Sstevel@tonic-gate 		if ((cnt = meta_get_raid_names(sp, &nlp, options, ep)) < 0)
11060Sstevel@tonic-gate 			return (-1);
11070Sstevel@tonic-gate 		else if (cnt == 0)
11080Sstevel@tonic-gate 			return (0);
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 		/* recurse */
11110Sstevel@tonic-gate 		for (p = nlp; (p != NULL); p = p->next) {
11120Sstevel@tonic-gate 			mdname_t	*np = p->namep;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 			if (meta_raid_print(sp, np, nlpp, fname, fp,
11150Sstevel@tonic-gate 			    options, ep) != 0)
11160Sstevel@tonic-gate 				rval = -1;
11170Sstevel@tonic-gate 		}
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 		/* cleanup, return success */
11200Sstevel@tonic-gate 		metafreenamelist(nlp);
11210Sstevel@tonic-gate 		return (rval);
11220Sstevel@tonic-gate 	}
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	/* get unit structure */
11250Sstevel@tonic-gate 	if ((raidp = meta_get_raid_common(sp, raidnp,
11260Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
11270Sstevel@tonic-gate 		return (-1);
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	/* check for parented */
11300Sstevel@tonic-gate 	if ((! (options & PRINT_SUBDEVS)) &&
11310Sstevel@tonic-gate 	    (MD_HAS_PARENT(raidp->common.parent))) {
11320Sstevel@tonic-gate 		return (0);
11330Sstevel@tonic-gate 	}
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	/* print appropriate detail */
11360Sstevel@tonic-gate 	if (options & PRINT_SHORT) {
11370Sstevel@tonic-gate 		if (raid_print(raidp, fname, fp, options, ep) != 0)
11380Sstevel@tonic-gate 			return (-1);
11390Sstevel@tonic-gate 	} else {
11400Sstevel@tonic-gate 		if (raid_report(sp, raidp, fname, fp, options, ep) != 0)
11410Sstevel@tonic-gate 			return (-1);
11420Sstevel@tonic-gate 	}
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	/* Recurse on components that are metadevices */
11450Sstevel@tonic-gate 	for (col = 0; col < raidp->cols.cols_len; ++col) {
11460Sstevel@tonic-gate 		md_raidcol_t	*colp = &raidp->cols.cols_val[col];
11470Sstevel@tonic-gate 		mdname_t	*namep = colp->colnamep;
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 		if ((metaismeta(namep)) &&
11500Sstevel@tonic-gate 		    (meta_print_name(sp, namep, nlpp, fname, fp,
11510Sstevel@tonic-gate 		    (options | PRINT_HEADER | PRINT_SUBDEVS),
11520Sstevel@tonic-gate 		    NULL, ep) != 0)) {
11530Sstevel@tonic-gate 			return (-1);
11540Sstevel@tonic-gate 		}
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	return (0);
11580Sstevel@tonic-gate }
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate /*
11610Sstevel@tonic-gate  * adjust raid geometry
11620Sstevel@tonic-gate  */
11630Sstevel@tonic-gate static int
11640Sstevel@tonic-gate adjust_geom(
11650Sstevel@tonic-gate 	mdname_t	*raidnp,
11660Sstevel@tonic-gate 	mdname_t	*colnp,
11670Sstevel@tonic-gate 	mr_unit_t	*mr,
11680Sstevel@tonic-gate 	md_error_t	*ep
11690Sstevel@tonic-gate )
11700Sstevel@tonic-gate {
11710Sstevel@tonic-gate 	uint_t		round_cyl = 1;
11720Sstevel@tonic-gate 	mdgeom_t	*geomp;
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	/* get reinstructs */
11750Sstevel@tonic-gate 	if ((geomp = metagetgeom(colnp, ep)) == NULL)
11760Sstevel@tonic-gate 		return (-1);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	/* adjust geometry */
11790Sstevel@tonic-gate 	if (meta_adjust_geom((md_unit_t *)mr, raidnp, geomp->write_reinstruct,
11800Sstevel@tonic-gate 	    geomp->read_reinstruct, round_cyl, ep) != 0)
11810Sstevel@tonic-gate 		return (-1);
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	/* return success */
11840Sstevel@tonic-gate 	return (0);
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate /*
11880Sstevel@tonic-gate  * add another column to the raid unit structure
11890Sstevel@tonic-gate  */
11900Sstevel@tonic-gate static int
11910Sstevel@tonic-gate attach_raid_col(
11920Sstevel@tonic-gate 	mdsetname_t	*sp,
11930Sstevel@tonic-gate 	mdname_t	*raidnp,
11940Sstevel@tonic-gate 	mr_unit_t	*mr,
11950Sstevel@tonic-gate 	mr_column_t	*mdc,
11960Sstevel@tonic-gate 	mdname_t	*colnp,
11970Sstevel@tonic-gate 	rcs_state_t	state,
11980Sstevel@tonic-gate 	mdnamelist_t	**keynlpp,
11990Sstevel@tonic-gate 	mdcmdopts_t	options,
12000Sstevel@tonic-gate 	md_error_t	*ep
12010Sstevel@tonic-gate )
12020Sstevel@tonic-gate {
12030Sstevel@tonic-gate 	diskaddr_t	column_size = mr->un_segsize * mr->un_segsincolumn;
12040Sstevel@tonic-gate 	diskaddr_t	size;
12050Sstevel@tonic-gate 	uint_t		 maxio;
12060Sstevel@tonic-gate 	mdcinfo_t	*cinfop;
12070Sstevel@tonic-gate 	md_timeval32_t	tmp_time;
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	/* setup state and timestamp */
12100Sstevel@tonic-gate 	mdc->un_devstate = state;
12110Sstevel@tonic-gate 	if (meta_gettimeofday(&tmp_time) == -1)
12120Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	mdc->un_devtimestamp = tmp_time;
12150Sstevel@tonic-gate 	/* get start, size, and maxio */
12160Sstevel@tonic-gate 	if ((mdc->un_orig_devstart = metagetstart(sp, colnp, ep)) ==
12170Sstevel@tonic-gate 	    MD_DISKADDR_ERROR)
12180Sstevel@tonic-gate 		return (-1);
12190Sstevel@tonic-gate 	if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
12200Sstevel@tonic-gate 		return (-1);
12210Sstevel@tonic-gate 	if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
12220Sstevel@tonic-gate 		return (-1);
12230Sstevel@tonic-gate 	maxio = cinfop->maxtransfer;
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	/* adjust start and size by prewrite */
12260Sstevel@tonic-gate 	mdc->un_orig_pwstart = mdc->un_orig_devstart;
12270Sstevel@tonic-gate 	mdc->un_orig_devstart += mr->un_pwsize;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	/* make sure we still have something left */
12300Sstevel@tonic-gate 	if ((mdc->un_orig_devstart >= size) ||
12310Sstevel@tonic-gate 	    ((size - mdc->un_orig_devstart) < column_size)) {
12320Sstevel@tonic-gate 		return (mdsyserror(ep, ENOSPC, colnp->cname));
12330Sstevel@tonic-gate 	}
12340Sstevel@tonic-gate 	size -= mdc->un_orig_devstart;
12350Sstevel@tonic-gate 	if (maxio < mr->un_maxio) {
12360Sstevel@tonic-gate 		return (mdcomperror(ep, MDE_MAXIO,
12370Sstevel@tonic-gate 		    meta_getminor(raidnp->dev), colnp->dev, colnp->cname));
12380Sstevel@tonic-gate 	}
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
12410Sstevel@tonic-gate 		/* store name in namespace */
12420Sstevel@tonic-gate 		if (add_key_name(sp, colnp, keynlpp, ep) != 0)
12430Sstevel@tonic-gate 			return (-1);
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	/* setup column */
12470Sstevel@tonic-gate 	mdc->un_orig_dev = colnp->dev;
12480Sstevel@tonic-gate 	mdc->un_orig_key = colnp->key;
12490Sstevel@tonic-gate 	mdc->un_dev = colnp->dev;
12500Sstevel@tonic-gate 	mdc->un_pwstart = mdc->un_orig_pwstart;
12510Sstevel@tonic-gate 	mdc->un_devstart = mdc->un_orig_devstart;
12520Sstevel@tonic-gate 	mdc->un_alt_dev = NODEV64;
12530Sstevel@tonic-gate 	mdc->un_alt_pwstart = 0;
12540Sstevel@tonic-gate 	mdc->un_alt_devstart = 0;
12550Sstevel@tonic-gate 	mdc->un_hs_id = 0;
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	/* add the size (we use) of the device to the total */
12580Sstevel@tonic-gate 	mr->c.un_actual_tb += column_size;
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 	/* adjust geometry */
12610Sstevel@tonic-gate 	if (adjust_geom(raidnp, colnp, mr, ep) != 0)
12620Sstevel@tonic-gate 		return (-1);
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	/* count column */
12650Sstevel@tonic-gate 	mr->un_totalcolumncnt++;
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	/* return success */
12680Sstevel@tonic-gate 	return (0);
12690Sstevel@tonic-gate }
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate /*
12720Sstevel@tonic-gate  * invalidate column names
12730Sstevel@tonic-gate  */
12740Sstevel@tonic-gate static int
12750Sstevel@tonic-gate invalidate_columns(
12760Sstevel@tonic-gate 	mdsetname_t	*sp,
12770Sstevel@tonic-gate 	mdname_t	*raidnp,
12780Sstevel@tonic-gate 	md_error_t	*ep
12790Sstevel@tonic-gate )
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate 	md_raid_t	*raidp;
12820Sstevel@tonic-gate 	uint_t		col;
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
12850Sstevel@tonic-gate 		return (-1);
12860Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
12870Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
12880Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 		meta_invalidate_name(colnp);
12910Sstevel@tonic-gate 	}
12920Sstevel@tonic-gate 	return (0);
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate /*
12960Sstevel@tonic-gate  * attach columns to raid
12970Sstevel@tonic-gate  */
12980Sstevel@tonic-gate int
12990Sstevel@tonic-gate meta_raid_attach(
13000Sstevel@tonic-gate 	mdsetname_t		*sp,
13010Sstevel@tonic-gate 	mdname_t		*raidnp,
13020Sstevel@tonic-gate 	mdnamelist_t		*colnlp,
13030Sstevel@tonic-gate 	mdcmdopts_t		options,
13040Sstevel@tonic-gate 	md_error_t		*ep
13050Sstevel@tonic-gate )
13060Sstevel@tonic-gate {
13070Sstevel@tonic-gate 	uint_t			concat_cnt = 0;
13080Sstevel@tonic-gate 	mdnamelist_t		*p;
13090Sstevel@tonic-gate 	mr_unit_t		*old_mr;
13100Sstevel@tonic-gate 	mr_unit_t		*new_mr;
13110Sstevel@tonic-gate 	size_t			old_rusize;
13120Sstevel@tonic-gate 	size_t			new_rusize;
13130Sstevel@tonic-gate 	mdnamelist_t		*keynlp = NULL;
13140Sstevel@tonic-gate 	md_grow_params_t	mgp;
13150Sstevel@tonic-gate 	int			rval = -1;
13160Sstevel@tonic-gate 	int			create_flag = MD_CRO_32BIT;
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	/* should have a set */
13190Sstevel@tonic-gate 	assert(sp != NULL);
13200Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 	/* check type */
13230Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
13240Sstevel@tonic-gate 		return (-1);
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	/* check and count new columns */
13270Sstevel@tonic-gate 	for (p = colnlp; (p != NULL); p = p->next) {
13280Sstevel@tonic-gate 		mdname_t	*np = p->namep;
13290Sstevel@tonic-gate 		mdnamelist_t	*p2;
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 		/* check against existing devices */
13320Sstevel@tonic-gate 		if (meta_check_column(sp, np, ep) != 0)
13330Sstevel@tonic-gate 			return (-1);
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 		/* check against ourselves */
13360Sstevel@tonic-gate 		for (p2 = p->next; (p2 != NULL); p2 = p2->next) {
13370Sstevel@tonic-gate 			if (meta_check_overlap(np->cname, np, 0, -1,
13380Sstevel@tonic-gate 			    p2->namep, 0, -1, ep) != 0) {
13390Sstevel@tonic-gate 				return (-1);
13400Sstevel@tonic-gate 			}
13410Sstevel@tonic-gate 		}
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 		/* count */
13440Sstevel@tonic-gate 		++concat_cnt;
13450Sstevel@tonic-gate 	}
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	/* get old unit */
13480Sstevel@tonic-gate 	if ((old_mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
13490Sstevel@tonic-gate 		return (-1);
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	/*
13520Sstevel@tonic-gate 	 * calculate the size needed for the new raid unit and allocate
13530Sstevel@tonic-gate 	 * the appropriate structure. allocate new unit.
13540Sstevel@tonic-gate 	 */
13550Sstevel@tonic-gate 	old_rusize = sizeof (*old_mr) - sizeof (old_mr->un_column[0]);
13560Sstevel@tonic-gate 	old_rusize += old_mr->un_totalcolumncnt * sizeof (old_mr->un_column[0]);
13570Sstevel@tonic-gate 	new_rusize = sizeof (*new_mr) - sizeof (new_mr->un_column[0]);
13580Sstevel@tonic-gate 	new_rusize += (old_mr->un_totalcolumncnt + concat_cnt)
13590Sstevel@tonic-gate 	    * sizeof (new_mr->un_column[0]);
13600Sstevel@tonic-gate 	new_mr = Zalloc(new_rusize);
13610Sstevel@tonic-gate 	(void) memcpy(new_mr, old_mr, old_rusize);
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	/* We always want a do-it, this is for attach_raid_col below */
13640Sstevel@tonic-gate 	options |= MDCMD_DOIT;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	/* build new unit structure */
13670Sstevel@tonic-gate 	for (p = colnlp; (p != NULL); p = p->next) {
13680Sstevel@tonic-gate 		mdname_t	*colnp = p->namep;
13690Sstevel@tonic-gate 		mr_column_t	*mdc;
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 		/* attach column */
13720Sstevel@tonic-gate 		mdc = &new_mr->un_column[new_mr->un_totalcolumncnt];
13730Sstevel@tonic-gate 		if (attach_raid_col(sp, raidnp, new_mr, mdc, colnp,
13740Sstevel@tonic-gate 		    RCS_INIT, &keynlp, options, ep) != 0) {
13750Sstevel@tonic-gate 			goto out;
13760Sstevel@tonic-gate 		}
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate 	assert(new_mr->un_totalcolumncnt
13790Sstevel@tonic-gate 	    == (old_mr->un_totalcolumncnt + concat_cnt));
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	create_flag = meta_check_devicesize(new_mr->c.un_total_blocks);
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	/* grow raid */
13850Sstevel@tonic-gate 	(void) memset(&mgp, 0, sizeof (mgp));
13860Sstevel@tonic-gate 	mgp.mnum = MD_SID(new_mr);
13870Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mgp, MD_RAID, sp->setno);
13880Sstevel@tonic-gate 	mgp.size = new_rusize;
13890Sstevel@tonic-gate 	mgp.mdp = (uintptr_t)new_mr;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	if (create_flag == MD_CRO_32BIT) {
13920Sstevel@tonic-gate 		mgp.options = MD_CRO_32BIT;
13930Sstevel@tonic-gate 		new_mr->c.un_revision = MD_32BIT_META_DEV;
13940Sstevel@tonic-gate 	} else {
13950Sstevel@tonic-gate 		mgp.options = MD_CRO_64BIT;
13960Sstevel@tonic-gate 		new_mr->c.un_revision = MD_64BIT_META_DEV;
13970Sstevel@tonic-gate 	}
13980Sstevel@tonic-gate 	if (metaioctl(MD_IOCGROW, &mgp, &mgp.mde, NULL) != 0) {
13990Sstevel@tonic-gate 		(void) mdstealerror(ep, &mgp.mde);
14000Sstevel@tonic-gate 		goto out;
14010Sstevel@tonic-gate 	}
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	/* clear cache */
14040Sstevel@tonic-gate 	if (invalidate_columns(sp, raidnp, ep) != 0)
14050Sstevel@tonic-gate 		goto out;
14060Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	/* let em know */
14090Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
14100Sstevel@tonic-gate 		if (concat_cnt == 1) {
14110Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
14120Sstevel@tonic-gate 			    "%s: component is attached\n"),
14130Sstevel@tonic-gate 			    raidnp->cname);
14140Sstevel@tonic-gate 		} else {
14150Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
14160Sstevel@tonic-gate 			    "%s: components are attached\n"),
14170Sstevel@tonic-gate 			    raidnp->cname);
14180Sstevel@tonic-gate 		}
14190Sstevel@tonic-gate 		(void) fflush(stdout);
14200Sstevel@tonic-gate 	}
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	/* grow any parents */
14240Sstevel@tonic-gate 	if (meta_concat_parent(sp, raidnp, ep) != 0)
14250Sstevel@tonic-gate 		goto out;
14260Sstevel@tonic-gate 	rval = 0;	/* success */
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	/* cleanup, return error */
14290Sstevel@tonic-gate out:
14300Sstevel@tonic-gate 	Free(old_mr);
14310Sstevel@tonic-gate 	Free(new_mr);
14320Sstevel@tonic-gate 	if (rval != 0)
14330Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
14340Sstevel@tonic-gate 	metafreenamelist(keynlp);
14350Sstevel@tonic-gate 	return (rval);
14360Sstevel@tonic-gate }
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate /*
14390Sstevel@tonic-gate  * get raid parameters
14400Sstevel@tonic-gate  */
14410Sstevel@tonic-gate int
14420Sstevel@tonic-gate meta_raid_get_params(
14430Sstevel@tonic-gate 	mdsetname_t	*sp,
14440Sstevel@tonic-gate 	mdname_t	*raidnp,
14450Sstevel@tonic-gate 	mr_params_t	*paramsp,
14460Sstevel@tonic-gate 	md_error_t	*ep
14470Sstevel@tonic-gate )
14480Sstevel@tonic-gate {
14490Sstevel@tonic-gate 	md_raid_t	*raidp;
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	/* should have a set */
14520Sstevel@tonic-gate 	assert(sp != NULL);
14530Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 	/* check name */
14560Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
14570Sstevel@tonic-gate 		return (-1);
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	/* get unit */
14600Sstevel@tonic-gate 	if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
14610Sstevel@tonic-gate 		return (-1);
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	/* return parameters */
14640Sstevel@tonic-gate 	(void) memset(paramsp, 0, sizeof (*paramsp));
14650Sstevel@tonic-gate 	if (raidp->hspnamep == NULL)
14660Sstevel@tonic-gate 		paramsp->hsp_id = MD_HSP_NONE;
14670Sstevel@tonic-gate 	else
14680Sstevel@tonic-gate 		paramsp->hsp_id = raidp->hspnamep->hsp;
14690Sstevel@tonic-gate 	return (0);
14700Sstevel@tonic-gate }
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate /*
14730Sstevel@tonic-gate  * set raid parameters
14740Sstevel@tonic-gate  */
14750Sstevel@tonic-gate int
14760Sstevel@tonic-gate meta_raid_set_params(
14770Sstevel@tonic-gate 	mdsetname_t		*sp,
14780Sstevel@tonic-gate 	mdname_t		*raidnp,
14790Sstevel@tonic-gate 	mr_params_t		*paramsp,
14800Sstevel@tonic-gate 	md_error_t		*ep
14810Sstevel@tonic-gate )
14820Sstevel@tonic-gate {
14830Sstevel@tonic-gate 	md_raid_params_t	msp;
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 	/* should have a set */
14860Sstevel@tonic-gate 	assert(sp != NULL);
14870Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 	/* check name */
14900Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
14910Sstevel@tonic-gate 		return (-1);
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	/* set parameters */
14940Sstevel@tonic-gate 	(void) memset(&msp, 0, sizeof (msp));
14950Sstevel@tonic-gate 	MD_SETDRIVERNAME(&msp, MD_RAID, sp->setno);
14960Sstevel@tonic-gate 	msp.mnum = meta_getminor(raidnp->dev);
14970Sstevel@tonic-gate 	msp.params = *paramsp;
14980Sstevel@tonic-gate 	if (metaioctl(MD_IOCCHANGE, &msp, &msp.mde, raidnp->cname) != 0)
14990Sstevel@tonic-gate 		return (mdstealerror(ep, &msp.mde));
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	/* clear cache */
15020Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	/* return success */
15050Sstevel@tonic-gate 	return (0);
15060Sstevel@tonic-gate }
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate /*
15090Sstevel@tonic-gate  * validate raid replace column
15100Sstevel@tonic-gate  */
15110Sstevel@tonic-gate static int
15120Sstevel@tonic-gate validate_new_raid(
15130Sstevel@tonic-gate 	mdsetname_t	*sp,
15140Sstevel@tonic-gate 	mdname_t	*raidnp,
15150Sstevel@tonic-gate 	mdname_t	*colnp,
15160Sstevel@tonic-gate 	replace_params_t *paramsp,
15170Sstevel@tonic-gate 	int		dup_ok,
15180Sstevel@tonic-gate 	md_error_t	*ep
15190Sstevel@tonic-gate )
15200Sstevel@tonic-gate {
15210Sstevel@tonic-gate 	mr_unit_t	*mr;
15220Sstevel@tonic-gate 	diskaddr_t	column_size;
15230Sstevel@tonic-gate 	diskaddr_t	label;
15240Sstevel@tonic-gate 	mdcinfo_t	*cinfop;
15250Sstevel@tonic-gate 	int		rval = -1;
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 	/* get raid unit */
15280Sstevel@tonic-gate 	if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
15290Sstevel@tonic-gate 		return (-1);
15300Sstevel@tonic-gate 	column_size = mr->un_segsize * mr->un_segsincolumn;
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	/* check it out */
15330Sstevel@tonic-gate 	if (meta_check_column(sp, colnp, ep) != 0) {
15340Sstevel@tonic-gate 		if ((! dup_ok) || (! mdisuseerror(ep, MDE_ALREADY)))
15350Sstevel@tonic-gate 			goto out;
15360Sstevel@tonic-gate 		mdclrerror(ep);
15370Sstevel@tonic-gate 	}
15380Sstevel@tonic-gate 	if ((paramsp->number_blks = metagetsize(colnp, ep)) ==
15390Sstevel@tonic-gate 	    MD_DISKADDR_ERROR)
15400Sstevel@tonic-gate 		goto out;
15410Sstevel@tonic-gate 	if ((label = metagetlabel(colnp, ep)) == MD_DISKADDR_ERROR)
15420Sstevel@tonic-gate 		goto out;
15430Sstevel@tonic-gate 	paramsp->has_label = ((label > 0) ? 1 : 0);
15440Sstevel@tonic-gate 	if ((paramsp->start_blk = metagetstart(sp, colnp, ep)) ==
15450Sstevel@tonic-gate 	    MD_DISKADDR_ERROR)
15460Sstevel@tonic-gate 		goto out;
15470Sstevel@tonic-gate 	if ((paramsp->number_blks - paramsp->start_blk) < column_size) {
15480Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, colnp->cname);
15490Sstevel@tonic-gate 		goto out;
15500Sstevel@tonic-gate 	}
15510Sstevel@tonic-gate 	if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
15520Sstevel@tonic-gate 		goto out;
15530Sstevel@tonic-gate 	if (cinfop->maxtransfer < mr->un_maxio) {
15540Sstevel@tonic-gate 		(void) mdcomperror(ep, MDE_MAXIO, meta_getminor(raidnp->dev),
15550Sstevel@tonic-gate 		    colnp->dev, colnp->cname);
15560Sstevel@tonic-gate 		goto out;
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	/* success */
15600Sstevel@tonic-gate 	rval = 0;
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	/* cleanup, return error */
15630Sstevel@tonic-gate out:
15640Sstevel@tonic-gate 	Free(mr);
15650Sstevel@tonic-gate 	return (rval);
15660Sstevel@tonic-gate }
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate /*
15690Sstevel@tonic-gate  * replace raid column
15700Sstevel@tonic-gate  */
15710Sstevel@tonic-gate int
15720Sstevel@tonic-gate meta_raid_replace(
15730Sstevel@tonic-gate 	mdsetname_t		*sp,
15740Sstevel@tonic-gate 	mdname_t		*raidnp,
15750Sstevel@tonic-gate 	mdname_t		*oldnp,
15760Sstevel@tonic-gate 	mdname_t		*newnp,
15770Sstevel@tonic-gate 	mdcmdopts_t		options,
15780Sstevel@tonic-gate 	md_error_t		*ep
15790Sstevel@tonic-gate )
15800Sstevel@tonic-gate {
15810Sstevel@tonic-gate 	int			force = ((options & MDCMD_FORCE) ? 1 : 0);
15820Sstevel@tonic-gate 	replace_params_t	params;
15830Sstevel@tonic-gate 	md_dev64_t		old_dev, new_dev;
15840Sstevel@tonic-gate 	diskaddr_t		new_start_blk, new_end_blk;
15850Sstevel@tonic-gate 	int			rebind;
15860Sstevel@tonic-gate 	mr_unit_t		*mr;
15870Sstevel@tonic-gate 	char			*new_devidp = NULL;
15880Sstevel@tonic-gate 	md_error_t		xep = mdnullerror;
15890Sstevel@tonic-gate 	int			ret;
15900Sstevel@tonic-gate 	md_set_desc		*sd;
15910Sstevel@tonic-gate 	uint_t			tstate;
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 	/* should have same set */
15940Sstevel@tonic-gate 	assert(sp != NULL);
15950Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	/* check name */
15980Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
15990Sstevel@tonic-gate 		return (-1);
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	/* save new binding incase this is a rebind where oldnp==newnp */
16020Sstevel@tonic-gate 	new_dev = newnp->dev;
16030Sstevel@tonic-gate 	new_start_blk = newnp->start_blk;
16040Sstevel@tonic-gate 	new_end_blk = newnp->end_blk;
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	/* invalidate, then get the raid (fill in oldnp from metadb) */
16070Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
16080Sstevel@tonic-gate 	if (meta_get_raid(sp, raidnp, ep) == NULL)
16090Sstevel@tonic-gate 		return (-1);
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	/* can't replace a component if the raid inaccessible */
16120Sstevel@tonic-gate 	if (meta_get_tstate(raidnp->dev, &tstate, ep) != 0) {
16130Sstevel@tonic-gate 		return (-1);
16140Sstevel@tonic-gate 	}
16150Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
16160Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_UNAVAIL_STATE,
16170Sstevel@tonic-gate 		    meta_getminor(raidnp->dev), raidnp->cname));
16180Sstevel@tonic-gate 	}
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	/* the old device binding is now established */
16210Sstevel@tonic-gate 	if ((old_dev = oldnp->dev) == NODEV64)
16220Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, oldnp->cname));
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 	/* setup raid info */
16260Sstevel@tonic-gate 	(void) memset(&params, 0, sizeof (params));
16270Sstevel@tonic-gate 	params.mnum = meta_getminor(raidnp->dev);
16280Sstevel@tonic-gate 	MD_SETDRIVERNAME(&params, MD_RAID, sp->setno);
16290Sstevel@tonic-gate 	params.old_dev = old_dev;
16300Sstevel@tonic-gate 	params.cmd = force ? FORCE_REPLACE_COMP : REPLACE_COMP;
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	if (options & MDCMD_CLUSTER_REPLACE) {
16330Sstevel@tonic-gate 		if ((mr = (mr_unit_t *)meta_get_mdunit(sp, raidnp, ep)) == NULL)
16340Sstevel@tonic-gate 			return (NULL);
16350Sstevel@tonic-gate 		Free(mr);
16360Sstevel@tonic-gate 		params.options = MDIOCTL_NO_RESYNC_RAID;
16370Sstevel@tonic-gate 		params.number_blks = metagetsize(newnp, ep);
16380Sstevel@tonic-gate 		if ((metagetlabel(newnp, ep) == MD_DISKADDR_ERROR) ||
16390Sstevel@tonic-gate 		    (metagetlabel(newnp, ep) == 0))
16400Sstevel@tonic-gate 			params.has_label = 0;
16410Sstevel@tonic-gate 		else
16420Sstevel@tonic-gate 			params.has_label = 1;
16430Sstevel@tonic-gate 		params.start_blk = metagetstart(sp, newnp, ep);
16440Sstevel@tonic-gate 	} else {
16450Sstevel@tonic-gate 		if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
16460Sstevel@tonic-gate 		    (old_dev != new_dev)) {
16470Sstevel@tonic-gate 			rebind = 1;
16480Sstevel@tonic-gate 		} else {
16490Sstevel@tonic-gate 			rebind = 0;
16500Sstevel@tonic-gate 		}
16510Sstevel@tonic-gate 		if (rebind) {
16520Sstevel@tonic-gate 			newnp->dev = new_dev;
16530Sstevel@tonic-gate 			newnp->start_blk = new_start_blk;
16540Sstevel@tonic-gate 			newnp->end_blk = new_end_blk;
16550Sstevel@tonic-gate 		}
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 		/*
16580Sstevel@tonic-gate 		 * Save a copy of the devid associated with the new disk, the
16590Sstevel@tonic-gate 		 * reason is that the checks for the column (meta_check_column)
16600Sstevel@tonic-gate 		 * via validate_new_raid(), could cause the disk's devid to be
16610Sstevel@tonic-gate 		 * changed to that of the devid that is currently stored in the
16620Sstevel@tonic-gate 		 * replica namespace for the disk in question. This devid could
16630Sstevel@tonic-gate 		 * be stale if we are replacing the disk. The actual function
16640Sstevel@tonic-gate 		 * that overwrites the devid is dr2drivedesc().
16650Sstevel@tonic-gate 		 */
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate 		/* don't setup new_devid if no devid's or MN diskset */
16680Sstevel@tonic-gate 		if (newnp->drivenamep->devid != NULL)
16690Sstevel@tonic-gate 			new_devidp = Strdup(newnp->drivenamep->devid);
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 		if (!metaislocalset(sp)) {
16720Sstevel@tonic-gate 			if ((sd = metaget_setdesc(sp, ep)) == NULL)
16730Sstevel@tonic-gate 				return (-1);
16740Sstevel@tonic-gate 			if (MD_MNSET_DESC(sd))
16750Sstevel@tonic-gate 				new_devidp = NULL;
16760Sstevel@tonic-gate 		}
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 		/* check out new (sets up start_blk, has_label, number_blks) */
16790Sstevel@tonic-gate 		if (validate_new_raid(sp, raidnp, newnp, &params, rebind,
16800Sstevel@tonic-gate 		    ep) != 0) {
16810Sstevel@tonic-gate 			Free(new_devidp);
16820Sstevel@tonic-gate 			return (-1);
16830Sstevel@tonic-gate 		}
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 		/*
16860Sstevel@tonic-gate 		 * Copy back the saved devid.
16870Sstevel@tonic-gate 		 */
16880Sstevel@tonic-gate 		Free(newnp->drivenamep->devid);
16890Sstevel@tonic-gate 		if (new_devidp) {
16900Sstevel@tonic-gate 			newnp->drivenamep->devid = Strdup(new_devidp);
16910Sstevel@tonic-gate 			Free(new_devidp);
16920Sstevel@tonic-gate 		}
16930Sstevel@tonic-gate 	}
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 	/* store name in namespace, allocate new key */
16960Sstevel@tonic-gate 	if (add_key_name(sp, newnp, NULL, ep) != 0)
16970Sstevel@tonic-gate 		return (-1);
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	if (rebind && !metaislocalset(sp)) {
17000Sstevel@tonic-gate 		/*
17010Sstevel@tonic-gate 		 * We are 'rebind'ing a disk that is in a diskset so as well
17020Sstevel@tonic-gate 		 * as updating the diskset's namespace the local set needs
17030Sstevel@tonic-gate 		 * to be updated because it also contains a reference to the
17040Sstevel@tonic-gate 		 * disk in question.
17050Sstevel@tonic-gate 		 */
17060Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
17070Sstevel@tonic-gate 		    newnp->cname, ep);
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
17100Sstevel@tonic-gate 			(void) del_key_name(sp, newnp, &xep);
17110Sstevel@tonic-gate 			return (-1);
17120Sstevel@tonic-gate 		}
17130Sstevel@tonic-gate 	}
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	/* replace column */
17160Sstevel@tonic-gate 	params.new_dev = new_dev;
17170Sstevel@tonic-gate 	params.new_key = newnp->key;
17180Sstevel@tonic-gate 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0) {
17190Sstevel@tonic-gate 		(void) del_key_name(sp, newnp, ep);
17200Sstevel@tonic-gate 		return (mdstealerror(ep, &params.mde));
17210Sstevel@tonic-gate 	}
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	/* clear cache */
17240Sstevel@tonic-gate 	meta_invalidate_name(oldnp);
17250Sstevel@tonic-gate 	meta_invalidate_name(newnp);
17260Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	/* let em know */
17290Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
17300Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
17310Sstevel@tonic-gate 		    "%s: device %s is replaced with %s\n"),
17320Sstevel@tonic-gate 		    raidnp->cname, oldnp->cname, newnp->cname);
17330Sstevel@tonic-gate 		(void) fflush(stdout);
17340Sstevel@tonic-gate 	}
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 	/* return success */
17370Sstevel@tonic-gate 	return (0);
17380Sstevel@tonic-gate }
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate /*
17410Sstevel@tonic-gate  * enable raid column
17420Sstevel@tonic-gate  */
17430Sstevel@tonic-gate int
17440Sstevel@tonic-gate meta_raid_enable(
17450Sstevel@tonic-gate 	mdsetname_t		*sp,
17460Sstevel@tonic-gate 	mdname_t		*raidnp,
17470Sstevel@tonic-gate 	mdname_t		*colnp,
17480Sstevel@tonic-gate 	mdcmdopts_t		options,
17490Sstevel@tonic-gate 	md_error_t		*ep
17500Sstevel@tonic-gate )
17510Sstevel@tonic-gate {
17520Sstevel@tonic-gate 	int			force = ((options & MDCMD_FORCE) ? 1 : 0);
17530Sstevel@tonic-gate 	replace_params_t	params;
17540Sstevel@tonic-gate 	md_dev64_t		fs_dev, del_dev;
17550Sstevel@tonic-gate 	int			err = 0;
17560Sstevel@tonic-gate 	char			*devnm;
17570Sstevel@tonic-gate 	int			ret;
17580Sstevel@tonic-gate 	uint_t			tstate;
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	/* should have same set */
17610Sstevel@tonic-gate 	assert(sp != NULL);
17620Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 	/* check name */
17650Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
17660Sstevel@tonic-gate 		return (-1);
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	/* get the file_system dev binding */
17690Sstevel@tonic-gate 	if (meta_getdev(sp, colnp, ep) != 0)
17700Sstevel@tonic-gate 		return (-1);
17710Sstevel@tonic-gate 	fs_dev = colnp->dev;
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	/* get the raid unit (fill in colnp->dev with metadb version) */
17740Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
17750Sstevel@tonic-gate 	if (meta_get_raid(sp, raidnp, ep) == NULL)
17760Sstevel@tonic-gate 		return (-1);
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	/* enabling a component can't work if the raid inaccessible */
17790Sstevel@tonic-gate 	if (meta_get_tstate(raidnp->dev, &tstate, ep) != 0) {
17800Sstevel@tonic-gate 		return (-1);
17810Sstevel@tonic-gate 	}
17820Sstevel@tonic-gate 	if (tstate & MD_INACCESSIBLE) {
17830Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_UNAVAIL_STATE,
17840Sstevel@tonic-gate 		    meta_getminor(raidnp->dev), raidnp->cname));
17850Sstevel@tonic-gate 	}
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 	/* the metadb device binding is now established */
17880Sstevel@tonic-gate 	if (colnp->dev == NODEV64)
17890Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, colnp->cname));
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	/*
17920Sstevel@tonic-gate 	 * check for the case where the dev_t has changed between the
17930Sstevel@tonic-gate 	 * filesystem and the metadb.  This is called a rebind, and
17940Sstevel@tonic-gate 	 * is handled by meta_raid_replace.
17950Sstevel@tonic-gate 	 */
17960Sstevel@tonic-gate 	if (fs_dev != colnp->dev) {
17970Sstevel@tonic-gate 		/*
17980Sstevel@tonic-gate 		 * Save the devt of mddb version
17990Sstevel@tonic-gate 		 */
18000Sstevel@tonic-gate 		del_dev = colnp->dev;
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 		/* establish file system binding with invalid start/end */
18030Sstevel@tonic-gate 		colnp->dev = fs_dev;
18040Sstevel@tonic-gate 		colnp->start_blk = -1;
18050Sstevel@tonic-gate 		colnp->end_blk = -1;
18060Sstevel@tonic-gate 		err = meta_raid_replace(sp, raidnp, colnp, colnp, options, ep);
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 		/*
18090Sstevel@tonic-gate 		 * Don't do it if meta_raid_replace returns an error
18100Sstevel@tonic-gate 		 */
18110Sstevel@tonic-gate 		if (!err && (devnm = meta_getnmentbydev(sp->setno, MD_SIDEWILD,
18120Sstevel@tonic-gate 			del_dev, NULL, NULL, &colnp->key, ep)) != NULL) {
18130Sstevel@tonic-gate 			(void) del_key_name(sp, colnp, ep);
18140Sstevel@tonic-gate 			Free(devnm);
18150Sstevel@tonic-gate 		}
18160Sstevel@tonic-gate 		return (err);
18170Sstevel@tonic-gate 	}
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 	/* setup raid info */
18200Sstevel@tonic-gate 	(void) memset(&params, 0, sizeof (params));
18210Sstevel@tonic-gate 	params.mnum = meta_getminor(raidnp->dev);
18220Sstevel@tonic-gate 	MD_SETDRIVERNAME(&params, MD_RAID, sp->setno);
18230Sstevel@tonic-gate 	params.old_dev = params.new_dev = colnp->dev;
18240Sstevel@tonic-gate 	if (force)
18250Sstevel@tonic-gate 		params.cmd = FORCE_ENABLE_COMP;
18260Sstevel@tonic-gate 	else
18270Sstevel@tonic-gate 		params.cmd = ENABLE_COMP;
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	/* check it out */
18300Sstevel@tonic-gate 	if (validate_new_raid(sp, raidnp, colnp, &params, 1, ep) != 0)
18310Sstevel@tonic-gate 		return (-1);
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 	/* enable column */
18340Sstevel@tonic-gate 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0)
18350Sstevel@tonic-gate 		return (mdstealerror(ep, &params.mde));
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	/*
18380Sstevel@tonic-gate 	 * are we dealing with a non-local set? If so need to update the
18390Sstevel@tonic-gate 	 * local namespace so that the disk record has the correct devid.
18400Sstevel@tonic-gate 	 */
18410Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
18420Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, colnp->cname,
18430Sstevel@tonic-gate 		    ep);
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
18460Sstevel@tonic-gate 			/*
18470Sstevel@tonic-gate 			 * Failed to update the local set. Nothing to do here
18480Sstevel@tonic-gate 			 * apart from report the error. The namespace is
18490Sstevel@tonic-gate 			 * most likely broken and some form of remedial
18500Sstevel@tonic-gate 			 * recovery is going to be required.
18510Sstevel@tonic-gate 			 */
18520Sstevel@tonic-gate 			mde_perror(ep, "");
18530Sstevel@tonic-gate 			mdclrerror(ep);
18540Sstevel@tonic-gate 		}
18550Sstevel@tonic-gate 	}
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	/* clear cache */
18580Sstevel@tonic-gate 	meta_invalidate_name(colnp);
18590Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	/* let em know */
18620Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
18630Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
18640Sstevel@tonic-gate 		    "%s: device %s is enabled\n"),
18650Sstevel@tonic-gate 		    raidnp->cname, colnp->cname);
18660Sstevel@tonic-gate 		(void) fflush(stdout);
18670Sstevel@tonic-gate 	}
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 	/* return success */
18700Sstevel@tonic-gate 	return (0);
18710Sstevel@tonic-gate }
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate /*
18740Sstevel@tonic-gate  * check for dups in the raid itself
18750Sstevel@tonic-gate  */
18760Sstevel@tonic-gate static int
18770Sstevel@tonic-gate check_twice(
18780Sstevel@tonic-gate 	md_raid_t	*raidp,
18790Sstevel@tonic-gate 	uint_t		col,
18800Sstevel@tonic-gate 	md_error_t	*ep
18810Sstevel@tonic-gate )
18820Sstevel@tonic-gate {
18830Sstevel@tonic-gate 	mdname_t	*raidnp = raidp->common.namep;
18840Sstevel@tonic-gate 	mdname_t	*thisnp;
18850Sstevel@tonic-gate 	uint_t		c;
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	thisnp = raidp->cols.cols_val[col].colnamep;
18880Sstevel@tonic-gate 	for (c = 0; (c < col); ++c) {
18890Sstevel@tonic-gate 		md_raidcol_t	*mdcp = &raidp->cols.cols_val[c];
18900Sstevel@tonic-gate 		mdname_t	*colnp = mdcp->colnamep;
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 		if (meta_check_overlap(raidnp->cname, thisnp, 0, -1,
18930Sstevel@tonic-gate 		    colnp, 0, -1, ep) != 0) {
18940Sstevel@tonic-gate 			return (-1);
18950Sstevel@tonic-gate 		}
18960Sstevel@tonic-gate 	}
18970Sstevel@tonic-gate 	return (0);
18980Sstevel@tonic-gate }
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate /*
19010Sstevel@tonic-gate  * default raid interlace
19020Sstevel@tonic-gate  */
19030Sstevel@tonic-gate diskaddr_t
19040Sstevel@tonic-gate meta_default_raid_interlace(void)
19050Sstevel@tonic-gate {
19060Sstevel@tonic-gate 	diskaddr_t	interlace;
19070Sstevel@tonic-gate 
1908*456Stn143363 	/* default to 512k, round up if necessary */
1909*456Stn143363 	interlace = btodb(512 * 1024);
19100Sstevel@tonic-gate 	if (interlace < lbtodb(MININTERLACE))
19110Sstevel@tonic-gate 		interlace = roundup(MININTERLACE, interlace);
19120Sstevel@tonic-gate 	return (interlace);
19130Sstevel@tonic-gate }
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate /*
19160Sstevel@tonic-gate  * convert interlaces
19170Sstevel@tonic-gate  */
19180Sstevel@tonic-gate int
19190Sstevel@tonic-gate meta_raid_check_interlace(
19200Sstevel@tonic-gate 	diskaddr_t	interlace,
19210Sstevel@tonic-gate 	char		*uname,
19220Sstevel@tonic-gate 	md_error_t	*ep
19230Sstevel@tonic-gate )
19240Sstevel@tonic-gate {
19250Sstevel@tonic-gate 	if ((interlace < btodb(RAID_MIN_INTERLACE)) ||
19260Sstevel@tonic-gate 	    (interlace > btodb(MAXINTERLACE))) {
19270Sstevel@tonic-gate 		return (mderror(ep, MDE_BAD_INTERLACE, uname));
19280Sstevel@tonic-gate 	}
19290Sstevel@tonic-gate 	return (0);
19300Sstevel@tonic-gate }
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate /*
19330Sstevel@tonic-gate  * check raid
19340Sstevel@tonic-gate  */
19350Sstevel@tonic-gate int
19360Sstevel@tonic-gate meta_check_raid(
19370Sstevel@tonic-gate 	mdsetname_t	*sp,
19380Sstevel@tonic-gate 	md_raid_t	*raidp,
19390Sstevel@tonic-gate 	mdcmdopts_t	options,
19400Sstevel@tonic-gate 	md_error_t	*ep
19410Sstevel@tonic-gate )
19420Sstevel@tonic-gate {
19430Sstevel@tonic-gate 	mdname_t	*raidnp = raidp->common.namep;
19440Sstevel@tonic-gate 	int		doit = ((options & MDCMD_DOIT) ? 1 : 0);
19450Sstevel@tonic-gate 	int		updateit = ((options & MDCMD_UPDATE) ? 1 : 0);
19460Sstevel@tonic-gate 	uint_t		ncol;
19470Sstevel@tonic-gate 	uint_t		col;
19480Sstevel@tonic-gate 	minor_t		mnum = meta_getminor(raidnp->dev);
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 	/* check number */
19510Sstevel@tonic-gate 	if (((ncol = raidp->cols.cols_len) < MD_RAID_MIN) ||
19520Sstevel@tonic-gate 	    (raidp->orig_ncol > ncol)) {
19530Sstevel@tonic-gate 		return (mdmderror(ep, MDE_BAD_RAID, mnum, raidnp->cname));
19540Sstevel@tonic-gate 	}
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	/* compute default interlace */
19570Sstevel@tonic-gate 	if (raidp->interlace == 0) {
19580Sstevel@tonic-gate 		raidp->interlace = meta_default_raid_interlace();
19590Sstevel@tonic-gate 	}
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 	/* check state */
19620Sstevel@tonic-gate 	switch (raidp->state) {
19630Sstevel@tonic-gate 	case RUS_INIT:
19640Sstevel@tonic-gate 	case RUS_OKAY:
19650Sstevel@tonic-gate 		break;
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	default:
19680Sstevel@tonic-gate 		return (mdmderror(ep, MDE_BAD_RAID, mnum, raidnp->cname));
19690Sstevel@tonic-gate 	}
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	/* check interlace */
19720Sstevel@tonic-gate 	if (meta_raid_check_interlace(raidp->interlace, raidnp->cname, ep) != 0)
19730Sstevel@tonic-gate 		return (-1);
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 	/* check hotspare pool name */
19760Sstevel@tonic-gate 	if (doit) {
19770Sstevel@tonic-gate 		if ((raidp->hspnamep != NULL) &&
19780Sstevel@tonic-gate 		    (metachkhsp(sp, raidp->hspnamep, ep) != 0)) {
19790Sstevel@tonic-gate 			return (-1);
19800Sstevel@tonic-gate 		}
19810Sstevel@tonic-gate 	}
19820Sstevel@tonic-gate 
19830Sstevel@tonic-gate 	/* check columns */
19840Sstevel@tonic-gate 	for (col = 0; (col < ncol); ++col) {
19850Sstevel@tonic-gate 		md_raidcol_t	*mdcp = &raidp->cols.cols_val[col];
19860Sstevel@tonic-gate 		mdname_t	*colnp = mdcp->colnamep;
19870Sstevel@tonic-gate 		diskaddr_t	start_blk, size;
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 		/* setup column */
19900Sstevel@tonic-gate 		if (raidp->state == RUS_INIT)
19910Sstevel@tonic-gate 			mdcp->state = RCS_INIT;
19920Sstevel@tonic-gate 		else
19930Sstevel@tonic-gate 			mdcp->state = RCS_OKAY;
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 		/* check column */
19960Sstevel@tonic-gate 		if (!updateit) {
19970Sstevel@tonic-gate 			if (meta_check_column(sp, colnp, ep) != 0)
19980Sstevel@tonic-gate 				return (-1);
19990Sstevel@tonic-gate 			if (((start_blk = metagetstart(sp, colnp, ep)) ==
20000Sstevel@tonic-gate 			    MD_DISKADDR_ERROR) || ((size = metagetsize(colnp,
20010Sstevel@tonic-gate 			    ep)) == MD_DISKADDR_ERROR)) {
20020Sstevel@tonic-gate 				return (-1);
20030Sstevel@tonic-gate 			}
20040Sstevel@tonic-gate 			if (start_blk >= size)
20050Sstevel@tonic-gate 				return (mdsyserror(ep, ENOSPC, colnp->cname));
20060Sstevel@tonic-gate 			size -= start_blk;
20070Sstevel@tonic-gate 			size = rounddown(size, raidp->interlace);
20080Sstevel@tonic-gate 			if (size == 0)
20090Sstevel@tonic-gate 				return (mdsyserror(ep, ENOSPC, colnp->cname));
20100Sstevel@tonic-gate 		}
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 		/* check this raid too */
20130Sstevel@tonic-gate 		if (check_twice(raidp, col, ep) != 0)
20140Sstevel@tonic-gate 			return (-1);
20150Sstevel@tonic-gate 	}
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	/* return success */
20180Sstevel@tonic-gate 	return (0);
20190Sstevel@tonic-gate }
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate /*
20220Sstevel@tonic-gate  * setup raid geometry
20230Sstevel@tonic-gate  */
20240Sstevel@tonic-gate static int
20250Sstevel@tonic-gate raid_geom(
20260Sstevel@tonic-gate 	md_raid_t	*raidp,
20270Sstevel@tonic-gate 	mr_unit_t	*mr,
20280Sstevel@tonic-gate 	md_error_t	*ep
20290Sstevel@tonic-gate )
20300Sstevel@tonic-gate {
20310Sstevel@tonic-gate 	uint_t		write_reinstruct = 0;
20320Sstevel@tonic-gate 	uint_t		read_reinstruct = 0;
20330Sstevel@tonic-gate 	uint_t		round_cyl = 1;
20340Sstevel@tonic-gate 	uint_t		col;
20350Sstevel@tonic-gate 	mdgeom_t	*geomp;
20360Sstevel@tonic-gate 
20370Sstevel@tonic-gate 	/* get worst reinstructs */
20380Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
20390Sstevel@tonic-gate 		md_raidcol_t	*mdcp = &raidp->cols.cols_val[col];
20400Sstevel@tonic-gate 		mdname_t	*colnp = mdcp->colnamep;
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate 		if ((geomp = metagetgeom(colnp, ep)) == NULL)
20430Sstevel@tonic-gate 			return (-1);
20440Sstevel@tonic-gate 		if (geomp->write_reinstruct > write_reinstruct)
20450Sstevel@tonic-gate 			write_reinstruct = geomp->write_reinstruct;
20460Sstevel@tonic-gate 		if (geomp->read_reinstruct > read_reinstruct)
20470Sstevel@tonic-gate 			read_reinstruct = geomp->read_reinstruct;
20480Sstevel@tonic-gate 	}
20490Sstevel@tonic-gate 
20500Sstevel@tonic-gate 	/* setup geometry from first column */
20510Sstevel@tonic-gate 	assert(raidp->cols.cols_len > 0);
20520Sstevel@tonic-gate 	if ((geomp = metagetgeom(raidp->cols.cols_val[0].colnamep,
20530Sstevel@tonic-gate 	    ep)) == NULL) {
20540Sstevel@tonic-gate 		return (-1);
20550Sstevel@tonic-gate 	}
20560Sstevel@tonic-gate 	if (meta_setup_geom((md_unit_t *)mr, raidp->common.namep, geomp,
20570Sstevel@tonic-gate 	    write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
20580Sstevel@tonic-gate 		return (-1);
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 	/* return success */
20610Sstevel@tonic-gate 	return (0);
20620Sstevel@tonic-gate }
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate int
20650Sstevel@tonic-gate meta_raid_state_cnt(mr_unit_t *mr, rcs_state_t state)
20660Sstevel@tonic-gate {
20670Sstevel@tonic-gate 	int 	statecnt = 0;
20680Sstevel@tonic-gate 	int	col;
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	for (col = 0; col < mr->un_totalcolumncnt; col++)
20710Sstevel@tonic-gate 		if (mr->un_column[col].un_devstate & state)
20720Sstevel@tonic-gate 			statecnt++;
20730Sstevel@tonic-gate 	return (statecnt);
20740Sstevel@tonic-gate }
20750Sstevel@tonic-gate /*
20760Sstevel@tonic-gate  * validate that a raid device being created with the -k flag is a real
20770Sstevel@tonic-gate  * raid device
20780Sstevel@tonic-gate  */
20790Sstevel@tonic-gate int
20800Sstevel@tonic-gate meta_raid_valid(md_raid_t *raidp, mr_unit_t *mr)
20810Sstevel@tonic-gate {
20820Sstevel@tonic-gate 	long long	buf[DEV_BSIZE / sizeof (long long)];
20830Sstevel@tonic-gate 	raid_pwhdr_t	pwhdr;
20840Sstevel@tonic-gate 	raid_pwhdr_t	*rpw = &pwhdr;
20850Sstevel@tonic-gate 	minor_t		mnum;
20860Sstevel@tonic-gate 	int		col;
20870Sstevel@tonic-gate 	int		fd;
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 	for (col = 0; col < mr->un_totalcolumncnt; col++) {
20900Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
20910Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 		if ((fd = open(colnp->rname, O_RDONLY)) < 0)
20940Sstevel@tonic-gate 			goto error_exit;
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 		if (lseek64(fd,
20970Sstevel@tonic-gate 		    (mr->un_column[col].un_pwstart * DEV_BSIZE), SEEK_SET) < 0)
20980Sstevel@tonic-gate 			goto error_exit;
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 		if (read(fd, buf, DEV_BSIZE) < 0)
21010Sstevel@tonic-gate 			goto error_exit;
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 		/*
21040Sstevel@tonic-gate 		 * If our raid device is a 64 bit device, we can accept the
21050Sstevel@tonic-gate 		 * pw header we just read in.
21060Sstevel@tonic-gate 		 * Otherwise it's of type raid_pwhdr32_od_t and has to
21070Sstevel@tonic-gate 		 * be converted.
21080Sstevel@tonic-gate 		 */
21090Sstevel@tonic-gate 		if (mr->c.un_revision == MD_64BIT_META_DEV) {
21100Sstevel@tonic-gate 			rpw = (raid_pwhdr_t *)buf;
21110Sstevel@tonic-gate 		} else {
21120Sstevel@tonic-gate 			RAID_CONVERT_RPW((raid_pwhdr32_od_t *)buf, rpw);
21130Sstevel@tonic-gate 		}
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 		if (rpw->rpw_column != col)
21160Sstevel@tonic-gate 			goto error_exit;
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate 		if (col == 0)
21190Sstevel@tonic-gate 			mnum = rpw->rpw_unit;
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 		if (rpw->rpw_unit != mnum)
21220Sstevel@tonic-gate 			goto error_exit;
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 		if (rpw->rpw_magic_ext == RAID_PWMAGIC) {
21250Sstevel@tonic-gate 			/* 4.1 prewrite header */
21260Sstevel@tonic-gate 			if ((rpw->rpw_origcolumncnt != mr->un_origcolumncnt) ||
21270Sstevel@tonic-gate 			    (rpw->rpw_totalcolumncnt
21280Sstevel@tonic-gate 				!= mr->un_totalcolumncnt) ||
21290Sstevel@tonic-gate 			    (rpw->rpw_segsize != mr->un_segsize) ||
21300Sstevel@tonic-gate 			    (rpw->rpw_segsincolumn != mr->un_segsincolumn) ||
21310Sstevel@tonic-gate 			    (rpw->rpw_pwcnt != mr->un_pwcnt) ||
21320Sstevel@tonic-gate 			    (rpw->rpw_pwstart !=
21330Sstevel@tonic-gate 				mr->un_column[col].un_pwstart) ||
21340Sstevel@tonic-gate 			    (rpw->rpw_devstart !=
21350Sstevel@tonic-gate 				mr->un_column[col].un_devstart) ||
21360Sstevel@tonic-gate 			    (rpw->rpw_pwsize != mr->un_pwsize))
21370Sstevel@tonic-gate 				goto error_exit;
21380Sstevel@tonic-gate 		}
21390Sstevel@tonic-gate 		/*
21400Sstevel@tonic-gate 		 * this is an old prewrite header (4.0) the unit structure
21410Sstevel@tonic-gate 		 * will have to be trusted.
21420Sstevel@tonic-gate 		 */
21430Sstevel@tonic-gate 		(void) close(fd);
21440Sstevel@tonic-gate 	}
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 	return (0);
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate error_exit:
21490Sstevel@tonic-gate 	(void) close(fd);
21500Sstevel@tonic-gate 	return (-1);
21510Sstevel@tonic-gate }
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate /*
21540Sstevel@tonic-gate  * create raid
21550Sstevel@tonic-gate  */
21560Sstevel@tonic-gate int
21570Sstevel@tonic-gate meta_create_raid(
21580Sstevel@tonic-gate 	mdsetname_t	*sp,
21590Sstevel@tonic-gate 	md_raid_t	*raidp,
21600Sstevel@tonic-gate 	mdcmdopts_t	options,
21610Sstevel@tonic-gate 	md_error_t	*ep
21620Sstevel@tonic-gate )
21630Sstevel@tonic-gate {
21640Sstevel@tonic-gate 	mdname_t	*raidnp = raidp->common.namep;
21650Sstevel@tonic-gate 	uint_t		ncol = raidp->cols.cols_len;
21660Sstevel@tonic-gate 	uint_t		orig_ncol = raidp->orig_ncol;
21670Sstevel@tonic-gate 	size_t		rdsize;
21680Sstevel@tonic-gate 	mr_unit_t	*mr;
21690Sstevel@tonic-gate 	uint_t		col;
21700Sstevel@tonic-gate 	diskaddr_t	disk_size = 0;
21710Sstevel@tonic-gate 	uint_t		disk_maxio = 0;
21720Sstevel@tonic-gate 	uint_t		pwes;
21730Sstevel@tonic-gate 	diskaddr_t	non_pw_blks, column_size;
21740Sstevel@tonic-gate 	mdnamelist_t	*keynlp = NULL;
21750Sstevel@tonic-gate 	md_set_params_t	set_params;
21760Sstevel@tonic-gate 	int		rval = -1;
21770Sstevel@tonic-gate 	md_timeval32_t	creation_time;
21780Sstevel@tonic-gate 	int		create_flag = MD_CRO_32BIT;
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 	/* validate raid */
21810Sstevel@tonic-gate 	if (meta_check_raid(sp, raidp, options, ep) != 0)
21820Sstevel@tonic-gate 		return (-1);
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 	/* allocate raid unit */
21850Sstevel@tonic-gate 	rdsize = sizeof (*mr) - sizeof (mr->un_column[0]);
21860Sstevel@tonic-gate 	rdsize += ncol * sizeof (mr->un_column[0]);
21870Sstevel@tonic-gate 	mr = Zalloc(rdsize);
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 	if (meta_gettimeofday(&creation_time) == -1)
21900Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
21910Sstevel@tonic-gate 	/*
21920Sstevel@tonic-gate 	 * initialize the top level mr_unit_t structure
21930Sstevel@tonic-gate 	 * setup the unit state to indicate whether to retain
21940Sstevel@tonic-gate 	 * any data currently on the metadevice or to clear it
21950Sstevel@tonic-gate 	 */
21960Sstevel@tonic-gate 	mr->c.un_type = MD_METARAID;
21970Sstevel@tonic-gate 	MD_SID(mr) = meta_getminor(raidnp->dev);
21980Sstevel@tonic-gate 	mr->c.un_size = rdsize;
21990Sstevel@tonic-gate 	mr->un_magic = RAID_UNMAGIC;
22000Sstevel@tonic-gate 	mr->un_state = raidp->state;
22010Sstevel@tonic-gate 	mr->un_timestamp = creation_time;
22020Sstevel@tonic-gate 	mr->un_origcolumncnt = orig_ncol;
22030Sstevel@tonic-gate 	mr->un_segsize = (uint_t)raidp->interlace;
22040Sstevel@tonic-gate 	if (raidp->hspnamep != NULL) {
22050Sstevel@tonic-gate 		mr->un_hsp_id = raidp->hspnamep->hsp;
22060Sstevel@tonic-gate 	} else {
22070Sstevel@tonic-gate 		mr->un_hsp_id = MD_HSP_NONE;
22080Sstevel@tonic-gate 	}
22090Sstevel@tonic-gate 	/*
22100Sstevel@tonic-gate 	 * setup original columns, saving start_block and
22110Sstevel@tonic-gate 	 * finding smallest size and maxio
22120Sstevel@tonic-gate 	 */
22130Sstevel@tonic-gate 	for (col = 0; (col < orig_ncol); ++col) {
22140Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
22150Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
22160Sstevel@tonic-gate 		mr_column_t	*mdc = &mr->un_column[col];
22170Sstevel@tonic-gate 		diskaddr_t	size;
22180Sstevel@tonic-gate 		uint_t		maxio;
22190Sstevel@tonic-gate 		mdcinfo_t	*cinfop;
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 		/* setup state */
22220Sstevel@tonic-gate 		mdc->un_devstate = cp->state;
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 		/* setup creation time */
22250Sstevel@tonic-gate 		mdc->un_devtimestamp = creation_time;
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 		/* get start, size, and maxio */
22280Sstevel@tonic-gate 		if ((mdc->un_orig_devstart = metagetstart(sp, colnp, ep)) ==
22290Sstevel@tonic-gate 		    MD_DISKADDR_ERROR)
22300Sstevel@tonic-gate 			goto out;
22310Sstevel@tonic-gate 		if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
22320Sstevel@tonic-gate 			goto out;
22330Sstevel@tonic-gate 		size -= mdc->un_orig_devstart;
22340Sstevel@tonic-gate 		if ((cinfop = metagetcinfo(colnp, ep)) == NULL)
22350Sstevel@tonic-gate 			goto out;
22360Sstevel@tonic-gate 		maxio = cinfop->maxtransfer;
22370Sstevel@tonic-gate 
22380Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
22390Sstevel@tonic-gate 			/* store name in namespace */
22400Sstevel@tonic-gate 			if (add_key_name(sp, colnp, &keynlp, ep) != 0)
22410Sstevel@tonic-gate 				goto out;
22420Sstevel@tonic-gate 		}
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 		/* setup column */
22450Sstevel@tonic-gate 		mdc->un_orig_key = colnp->key;
22460Sstevel@tonic-gate 		mdc->un_orig_dev = colnp->dev;
22470Sstevel@tonic-gate 		mdc->un_dev = mdc->un_orig_dev;
22480Sstevel@tonic-gate 		mdc->un_pwstart = mdc->un_orig_pwstart;
22490Sstevel@tonic-gate 		mdc->un_devstart = mdc->un_orig_devstart;
22500Sstevel@tonic-gate 		mdc->un_alt_dev = NODEV64;
22510Sstevel@tonic-gate 		mdc->un_alt_pwstart = 0;
22520Sstevel@tonic-gate 		mdc->un_alt_devstart = 0;
22530Sstevel@tonic-gate 		mdc->un_hs_id = 0;
22540Sstevel@tonic-gate 		if (mr->un_state == RUS_INIT)
22550Sstevel@tonic-gate 			mdc->un_devstate = RCS_INIT;
22560Sstevel@tonic-gate 		else
22570Sstevel@tonic-gate 			mdc->un_devstate = RCS_OKAY;
22580Sstevel@tonic-gate 
22590Sstevel@tonic-gate 		/* adjust for smallest disk */
22600Sstevel@tonic-gate 		if (disk_size == 0) {
22610Sstevel@tonic-gate 			disk_size = size;
22620Sstevel@tonic-gate 		} else if (size < disk_size) {
22630Sstevel@tonic-gate 			disk_size = size;
22640Sstevel@tonic-gate 		}
22650Sstevel@tonic-gate 		if (disk_maxio == 0) {
22660Sstevel@tonic-gate 			disk_maxio = maxio;
22670Sstevel@tonic-gate 		} else if (maxio < disk_maxio) {
22680Sstevel@tonic-gate 			disk_maxio = maxio;
22690Sstevel@tonic-gate 		}
22700Sstevel@tonic-gate 	}
22710Sstevel@tonic-gate 	assert(col == mr->un_origcolumncnt);
22720Sstevel@tonic-gate 
22730Sstevel@tonic-gate 	/*
22740Sstevel@tonic-gate 	 * before processing any of the attached column(s)
22750Sstevel@tonic-gate 	 * set up the composition of the metadevice for column
22760Sstevel@tonic-gate 	 * sizes and pre-write information
22770Sstevel@tonic-gate 	 */
22780Sstevel@tonic-gate 	mr->un_maxio = disk_maxio;	/* smallest maxio */
22790Sstevel@tonic-gate 	mr->un_iosize = min(mr->un_maxio, (mr->un_segsize + 1));
22800Sstevel@tonic-gate 	pwes = mr->un_iosize;
22810Sstevel@tonic-gate 	if (raidp->pw_count)
22820Sstevel@tonic-gate 		mr->un_pwcnt = raidp->pw_count;
22830Sstevel@tonic-gate 	else
22840Sstevel@tonic-gate 		mr->un_pwcnt = PWCNT_MIN;
22850Sstevel@tonic-gate 	if ((mr->un_pwcnt < PWCNT_MIN) || (mr->un_pwcnt > PWCNT_MAX)) {
22860Sstevel@tonic-gate 		(void) mderror(ep, MDE_RAID_BAD_PW_CNT, raidnp->cname);
22870Sstevel@tonic-gate 		goto out;
22880Sstevel@tonic-gate 	}
22890Sstevel@tonic-gate 	mr->un_pwsize = roundup((mr->un_pwcnt * pwes), 2);
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 	/* now calculate the number of segments per column */
22920Sstevel@tonic-gate 	non_pw_blks = disk_size - mr->un_pwsize;	/* smallest disk */
22930Sstevel@tonic-gate 	if ((mr->un_pwsize > disk_size) ||
22940Sstevel@tonic-gate 	    (non_pw_blks < (diskaddr_t)mr->un_segsize)) {
22950Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, raidnp->cname);
22960Sstevel@tonic-gate 		goto out;
22970Sstevel@tonic-gate 	}
22980Sstevel@tonic-gate 	mr->un_segsincolumn = non_pw_blks / mr->un_segsize;
22990Sstevel@tonic-gate 	column_size = mr->un_segsize * mr->un_segsincolumn;
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	/*
23020Sstevel@tonic-gate 	 * adjust the pw_cnt, pw_size, to fit into any fragmentation
23030Sstevel@tonic-gate 	 * left over after column_size has been computed
23040Sstevel@tonic-gate 	 */
23050Sstevel@tonic-gate 	mr->un_pwsize = rounddown(((uint_t)(disk_size - column_size)), 2);
23060Sstevel@tonic-gate 	mr->un_pwcnt = mr->un_pwsize / pwes;
23070Sstevel@tonic-gate 	assert(mr->un_pwcnt >= PWCNT_MIN);
23080Sstevel@tonic-gate 	mr->un_pwsize = roundup((mr->un_pwcnt * pwes), 2);
23090Sstevel@tonic-gate 	assert((mr->un_pwsize + column_size) <= disk_size);
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate 	/*
23120Sstevel@tonic-gate 	 * calculate the actual block count available based on the
23130Sstevel@tonic-gate 	 * segment size and the number of segments per column ...
23140Sstevel@tonic-gate 	 * ... and adjust for the number of parity segments
23150Sstevel@tonic-gate 	 */
23160Sstevel@tonic-gate 	mr->c.un_actual_tb = column_size * (mr->un_origcolumncnt - 1);
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 	if (raid_geom(raidp, mr, ep) != 0)
23190Sstevel@tonic-gate 		goto out;
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 	create_flag = meta_check_devicesize(mr->c.un_total_blocks);
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 	/*
23240Sstevel@tonic-gate 	 * now calculate the pre-write offset and update the column
23250Sstevel@tonic-gate 	 * structures to include the address of the individual pre-write
23260Sstevel@tonic-gate 	 * areas
23270Sstevel@tonic-gate 	 */
23280Sstevel@tonic-gate 	for (col = 0; (col < orig_ncol); ++col) {
23290Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
23300Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
23310Sstevel@tonic-gate 		mr_column_t	*mdc = &mr->un_column[col];
23320Sstevel@tonic-gate 		diskaddr_t	size;
23330Sstevel@tonic-gate 
23340Sstevel@tonic-gate 		/* get size */
23350Sstevel@tonic-gate 		if ((size = metagetsize(colnp, ep)) == MD_DISKADDR_ERROR)
23360Sstevel@tonic-gate 			goto out;
23370Sstevel@tonic-gate 
23380Sstevel@tonic-gate 		/* adjust start and size by prewrite */
23390Sstevel@tonic-gate 		mdc->un_orig_pwstart = mdc->un_orig_devstart;
23400Sstevel@tonic-gate 		mdc->un_orig_devstart += mr->un_pwsize;
23410Sstevel@tonic-gate 		mdc->un_pwstart = mdc->un_orig_pwstart;
23420Sstevel@tonic-gate 		mdc->un_devstart = mdc->un_orig_devstart;
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate 		assert(size >= mdc->un_orig_devstart);
23450Sstevel@tonic-gate 		size -= mdc->un_orig_devstart;
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate 		/* make sure we still have something left */
23480Sstevel@tonic-gate 		assert(size >= column_size);
23490Sstevel@tonic-gate 	}
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	/* do concat cols */
23520Sstevel@tonic-gate 	mr->un_totalcolumncnt = mr->un_origcolumncnt;
23530Sstevel@tonic-gate 	assert(col == mr->un_origcolumncnt);
23540Sstevel@tonic-gate 	for (col = orig_ncol; (col < ncol); ++col) {
23550Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
23560Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
23570Sstevel@tonic-gate 		mr_column_t	*mdc = &mr->un_column[col];
23580Sstevel@tonic-gate 
23590Sstevel@tonic-gate 		/* attach column */
23600Sstevel@tonic-gate 		if (attach_raid_col(sp, raidnp, mr, mdc, colnp,
23610Sstevel@tonic-gate 		    cp->state, &keynlp, options, ep) != 0) {
23620Sstevel@tonic-gate 			goto out;
23630Sstevel@tonic-gate 		}
23640Sstevel@tonic-gate 	}
23650Sstevel@tonic-gate 	assert(mr->un_totalcolumncnt == ncol);
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 	/* fill in the size of the raid */
23680Sstevel@tonic-gate 	if (options & MDCMD_UPDATE) {
23690Sstevel@tonic-gate 		raidp->common.size = mr->c.un_total_blocks;
23700Sstevel@tonic-gate 		raidp->column_size = mr->un_segsize * mr->un_segsincolumn;
23710Sstevel@tonic-gate 	}
23720Sstevel@tonic-gate 
23730Sstevel@tonic-gate 	/* if we're not doing anything, return success */
23740Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT)) {
23750Sstevel@tonic-gate 		rval = 0;	/* success */
23760Sstevel@tonic-gate 		goto out;
23770Sstevel@tonic-gate 	}
23780Sstevel@tonic-gate 
23790Sstevel@tonic-gate 	if ((mr->un_state & RUS_OKAY) &&
23800Sstevel@tonic-gate 	    (meta_raid_valid(raidp, mr) != 0)) {
23810Sstevel@tonic-gate 		(void) mderror(ep, MDE_RAID_INVALID, raidnp->cname);
23820Sstevel@tonic-gate 		goto out;
23830Sstevel@tonic-gate 	}
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 	/* create raid */
23860Sstevel@tonic-gate 	(void) memset(&set_params, 0, sizeof (set_params));
23870Sstevel@tonic-gate 	/* did the user tell us to generate a large device? */
23880Sstevel@tonic-gate 	if (create_flag == MD_CRO_64BIT) {
23890Sstevel@tonic-gate 		mr->c.un_revision = MD_64BIT_META_DEV;
23900Sstevel@tonic-gate 		set_params.options = MD_CRO_64BIT;
23910Sstevel@tonic-gate 	} else {
23920Sstevel@tonic-gate 		mr->c.un_revision = MD_32BIT_META_DEV;
23930Sstevel@tonic-gate 		set_params.options = MD_CRO_32BIT;
23940Sstevel@tonic-gate 	}
23950Sstevel@tonic-gate 	set_params.mnum = MD_SID(mr);
23960Sstevel@tonic-gate 	set_params.size = mr->c.un_size;
23970Sstevel@tonic-gate 	set_params.mdp = (uintptr_t)mr;
23980Sstevel@tonic-gate 	MD_SETDRIVERNAME(&set_params, MD_RAID, MD_MIN2SET(set_params.mnum));
23990Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
24000Sstevel@tonic-gate 	    raidnp->cname) != 0) {
24010Sstevel@tonic-gate 		(void) mdstealerror(ep, &set_params.mde);
24020Sstevel@tonic-gate 		goto out;
24030Sstevel@tonic-gate 	}
24040Sstevel@tonic-gate 	rval = 0;	/* success */
24050Sstevel@tonic-gate 
24060Sstevel@tonic-gate 	/* cleanup, return success */
24070Sstevel@tonic-gate out:
24080Sstevel@tonic-gate 	Free(mr);
24090Sstevel@tonic-gate 	if (rval != 0) {
24100Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
24110Sstevel@tonic-gate 	}
24120Sstevel@tonic-gate 	metafreenamelist(keynlp);
24130Sstevel@tonic-gate 	if ((rval == 0) && (options & MDCMD_DOIT)) {
24140Sstevel@tonic-gate 		if (invalidate_columns(sp, raidnp, ep) != 0)
24150Sstevel@tonic-gate 			rval = -1;
24160Sstevel@tonic-gate 		meta_invalidate_name(raidnp);
24170Sstevel@tonic-gate 	}
24180Sstevel@tonic-gate 	return (rval);
24190Sstevel@tonic-gate }
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate /*
24220Sstevel@tonic-gate  * initialize raid
24230Sstevel@tonic-gate  * NOTE: this functions is metainit(1m)'s command line parser!
24240Sstevel@tonic-gate  */
24250Sstevel@tonic-gate int
24260Sstevel@tonic-gate meta_init_raid(
24270Sstevel@tonic-gate 	mdsetname_t	**spp,
24280Sstevel@tonic-gate 	int		argc,
24290Sstevel@tonic-gate 	char		*argv[],
24300Sstevel@tonic-gate 	mdcmdopts_t	options,
24310Sstevel@tonic-gate 	md_error_t	*ep
24320Sstevel@tonic-gate )
24330Sstevel@tonic-gate {
24340Sstevel@tonic-gate 	char		*uname = argv[0];
24350Sstevel@tonic-gate 	mdname_t	*raidnp = NULL;
24360Sstevel@tonic-gate 	int		old_optind;
24370Sstevel@tonic-gate 	int		c;
24380Sstevel@tonic-gate 	md_raid_t	*raidp = NULL;
24390Sstevel@tonic-gate 	uint_t		ncol, col;
24400Sstevel@tonic-gate 	int		rval = -1;
24410Sstevel@tonic-gate 	md_set_desc	*sd;
24420Sstevel@tonic-gate 
24430Sstevel@tonic-gate 	/* get raid name */
24440Sstevel@tonic-gate 	assert(argc > 0);
24450Sstevel@tonic-gate 	if (argc < 1)
24460Sstevel@tonic-gate 		goto syntax;
24470Sstevel@tonic-gate 	if ((raidnp = metaname(spp, uname, ep)) == NULL)
24480Sstevel@tonic-gate 		goto out;
24490Sstevel@tonic-gate 	assert(*spp != NULL);
24500Sstevel@tonic-gate 
24510Sstevel@tonic-gate 	/*
24520Sstevel@tonic-gate 	 * Raid metadevice not allowed on multi-node diskset.
24530Sstevel@tonic-gate 	 */
24540Sstevel@tonic-gate 	if (! metaislocalset(*spp)) {
24550Sstevel@tonic-gate 		if ((sd = metaget_setdesc(*spp, ep)) == NULL)
24560Sstevel@tonic-gate 			goto out;
24570Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
24580Sstevel@tonic-gate 			rval = meta_cook_syntax(ep, MDE_MNSET_NORAID, uname,
24590Sstevel@tonic-gate 						argc, argv);
24600Sstevel@tonic-gate 			goto out;
24610Sstevel@tonic-gate 		}
24620Sstevel@tonic-gate 	}
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate 	uname = raidnp->cname;
24650Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
24660Sstevel@tonic-gate 		goto out;
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
24690Sstevel@tonic-gate 		/* grab set lock */
24700Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep) != 0)
24710Sstevel@tonic-gate 			goto out;
24720Sstevel@tonic-gate 
24730Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
24740Sstevel@tonic-gate 			goto out;
24750Sstevel@tonic-gate 	}
24760Sstevel@tonic-gate 
24770Sstevel@tonic-gate 	/* see if it exists already */
24780Sstevel@tonic-gate 	if (metagetmiscname(raidnp, ep) != NULL) {
24790Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
24800Sstevel@tonic-gate 		    meta_getminor(raidnp->dev), uname);
24810Sstevel@tonic-gate 		goto out;
24820Sstevel@tonic-gate 	} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
24830Sstevel@tonic-gate 		goto out;
24840Sstevel@tonic-gate 	} else {
24850Sstevel@tonic-gate 		mdclrerror(ep);
24860Sstevel@tonic-gate 	}
24870Sstevel@tonic-gate 	--argc, ++argv;
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate 	/* grab -r */
24900Sstevel@tonic-gate 	if ((argc < 1) || (strcmp(argv[0], "-r") != 0))
24910Sstevel@tonic-gate 		goto syntax;
24920Sstevel@tonic-gate 	--argc, ++argv;
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 	/* parse general options */
24950Sstevel@tonic-gate 	optind = 0;
24960Sstevel@tonic-gate 	opterr = 0;
24970Sstevel@tonic-gate 	if (getopt(argc, argv, "") != -1)
24980Sstevel@tonic-gate 		goto options;
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate 	/* allocate raid */
25010Sstevel@tonic-gate 	raidp = Zalloc(sizeof (*raidp));
25020Sstevel@tonic-gate 
25030Sstevel@tonic-gate 	/* setup common */
25040Sstevel@tonic-gate 	raidp->common.namep = raidnp;
25050Sstevel@tonic-gate 	raidp->common.type = MD_METARAID;
25060Sstevel@tonic-gate 	raidp->state = RUS_INIT;
25070Sstevel@tonic-gate 
25080Sstevel@tonic-gate 	/* allocate and parse cols */
25090Sstevel@tonic-gate 	for (ncol = 0; ((ncol < argc) && (argv[ncol][0] != '-')); ++ncol)
25100Sstevel@tonic-gate 		;
25110Sstevel@tonic-gate 	raidp->cols.cols_len = ncol;
25120Sstevel@tonic-gate 	if (ncol != 0) {
25130Sstevel@tonic-gate 		raidp->cols.cols_val =
25140Sstevel@tonic-gate 		    Zalloc(ncol * sizeof (*raidp->cols.cols_val));
25150Sstevel@tonic-gate 	}
25160Sstevel@tonic-gate 	for (col = 0; ((argc > 0) && (col < ncol)); ++col) {
25170Sstevel@tonic-gate 		md_raidcol_t	*mdc = &raidp->cols.cols_val[col];
25180Sstevel@tonic-gate 		mdname_t	*colnp;
25190Sstevel@tonic-gate 
25200Sstevel@tonic-gate 		/* parse column name */
25210Sstevel@tonic-gate 		if ((colnp = metaname(spp, argv[0], ep)) == NULL)
25220Sstevel@tonic-gate 			goto out;
25230Sstevel@tonic-gate 		/* check for soft partitions */
25240Sstevel@tonic-gate 		if (meta_sp_issp(*spp, colnp, ep) != 0) {
25250Sstevel@tonic-gate 			/* check disks */
25260Sstevel@tonic-gate 			if (metachkcomp(colnp, ep) != 0)
25270Sstevel@tonic-gate 				goto out;
25280Sstevel@tonic-gate 		}
25290Sstevel@tonic-gate 		mdc->colnamep = colnp;
25300Sstevel@tonic-gate 		--argc, ++argv;
25310Sstevel@tonic-gate 	}
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 	/* parse raid options */
25340Sstevel@tonic-gate 	old_optind = optind = 0;
25350Sstevel@tonic-gate 	opterr = 0;
25360Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "h:i:ko:w:")) != -1) {
25370Sstevel@tonic-gate 		switch (c) {
25380Sstevel@tonic-gate 		case 'h':
25390Sstevel@tonic-gate 			if ((raidp->hspnamep = metahspname(spp, optarg,
25400Sstevel@tonic-gate 			    ep)) == NULL) {
25410Sstevel@tonic-gate 				goto out;
25420Sstevel@tonic-gate 			}
25430Sstevel@tonic-gate 			break;
25440Sstevel@tonic-gate 
25450Sstevel@tonic-gate 		case 'i':
25460Sstevel@tonic-gate 			if (parse_interlace(uname, optarg, &raidp->interlace,
25470Sstevel@tonic-gate 			    ep) != 0) {
25480Sstevel@tonic-gate 				goto out;
25490Sstevel@tonic-gate 			}
25500Sstevel@tonic-gate 			if (meta_raid_check_interlace(raidp->interlace,
25510Sstevel@tonic-gate 			    uname, ep))
25520Sstevel@tonic-gate 				goto out;
25530Sstevel@tonic-gate 			break;
25540Sstevel@tonic-gate 
25550Sstevel@tonic-gate 		case 'k':
25560Sstevel@tonic-gate 			raidp->state = RUS_OKAY;
25570Sstevel@tonic-gate 			break;
25580Sstevel@tonic-gate 
25590Sstevel@tonic-gate 		case 'o':
25600Sstevel@tonic-gate 			if ((sscanf(optarg, "%u", &raidp->orig_ncol) != 1) ||
25610Sstevel@tonic-gate 			    ((int)raidp->orig_ncol < 0)) {
25620Sstevel@tonic-gate 				goto syntax;
25630Sstevel@tonic-gate 			}
25640Sstevel@tonic-gate 			if ((raidp->orig_ncol < MD_RAID_MIN) ||
25650Sstevel@tonic-gate 			    (raidp->orig_ncol > ncol)) {
25660Sstevel@tonic-gate 				rval = mderror(ep, MDE_BAD_ORIG_NCOL, uname);
25670Sstevel@tonic-gate 				goto out;
25680Sstevel@tonic-gate 			}
25690Sstevel@tonic-gate 			break;
25700Sstevel@tonic-gate 		case 'w':
25710Sstevel@tonic-gate 			if ((sscanf(optarg, "%d", &raidp->pw_count) != 1) ||
25720Sstevel@tonic-gate 			    ((int)raidp->pw_count < 0))
25730Sstevel@tonic-gate 				goto syntax;
25740Sstevel@tonic-gate 			if (((int)raidp->pw_count < PWCNT_MIN) ||
25750Sstevel@tonic-gate 			    ((int)raidp->pw_count > PWCNT_MAX)) {
25760Sstevel@tonic-gate 				rval = mderror(ep, MDE_RAID_BAD_PW_CNT, uname);
25770Sstevel@tonic-gate 				goto out;
25780Sstevel@tonic-gate 			}
25790Sstevel@tonic-gate 			break;
25800Sstevel@tonic-gate 		default:
25810Sstevel@tonic-gate 			argc += old_optind;
25820Sstevel@tonic-gate 			argv -= old_optind;
25830Sstevel@tonic-gate 			goto options;
25840Sstevel@tonic-gate 		}
25850Sstevel@tonic-gate 		old_optind = optind;
25860Sstevel@tonic-gate 	}
25870Sstevel@tonic-gate 	argc -= optind;
25880Sstevel@tonic-gate 	argv += optind;
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 	/* we should be at the end */
25910Sstevel@tonic-gate 	if (argc != 0)
25920Sstevel@tonic-gate 		goto syntax;
25930Sstevel@tonic-gate 
25940Sstevel@tonic-gate 	/* default to all original columns */
25950Sstevel@tonic-gate 	if (raidp->orig_ncol == 0)
25960Sstevel@tonic-gate 		raidp->orig_ncol = ncol;
25970Sstevel@tonic-gate 
25980Sstevel@tonic-gate 	/* create raid */
25990Sstevel@tonic-gate 	if (meta_create_raid(*spp, raidp, options, ep) != 0)
26000Sstevel@tonic-gate 		goto out;
26010Sstevel@tonic-gate 	rval = 0;	/* success */
26020Sstevel@tonic-gate 
26030Sstevel@tonic-gate 	/* let em know */
26040Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
26050Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "%s: RAID is setup\n"),
26060Sstevel@tonic-gate 		    uname);
26070Sstevel@tonic-gate 		(void) fflush(stdout);
26080Sstevel@tonic-gate 	}
26090Sstevel@tonic-gate 	goto out;
26100Sstevel@tonic-gate 
26110Sstevel@tonic-gate 	/* syntax error */
26120Sstevel@tonic-gate syntax:
26130Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
26140Sstevel@tonic-gate 	goto out;
26150Sstevel@tonic-gate 
26160Sstevel@tonic-gate 	/* options error */
26170Sstevel@tonic-gate options:
26180Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
26190Sstevel@tonic-gate 	goto out;
26200Sstevel@tonic-gate 
26210Sstevel@tonic-gate 	/* cleanup, return error */
26220Sstevel@tonic-gate out:
26230Sstevel@tonic-gate 	if (raidp != NULL)
26240Sstevel@tonic-gate 		meta_free_raid(raidp);
26250Sstevel@tonic-gate 	return (rval);
26260Sstevel@tonic-gate }
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate /*
26290Sstevel@tonic-gate  * reset RAIDs
26300Sstevel@tonic-gate  */
26310Sstevel@tonic-gate int
26320Sstevel@tonic-gate meta_raid_reset(
26330Sstevel@tonic-gate 	mdsetname_t	*sp,
26340Sstevel@tonic-gate 	mdname_t	*raidnp,
26350Sstevel@tonic-gate 	mdcmdopts_t	options,
26360Sstevel@tonic-gate 	md_error_t	*ep
26370Sstevel@tonic-gate )
26380Sstevel@tonic-gate {
26390Sstevel@tonic-gate 	md_raid_t	*raidp;
26400Sstevel@tonic-gate 	int		rval = -1;
26410Sstevel@tonic-gate 	int		col;
26420Sstevel@tonic-gate 
26430Sstevel@tonic-gate 	/* should have same set */
26440Sstevel@tonic-gate 	assert(sp != NULL);
26450Sstevel@tonic-gate 	assert((raidnp == NULL) ||
26460Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev))));
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate 	/* reset all raids */
26490Sstevel@tonic-gate 	if (raidnp == NULL) {
26500Sstevel@tonic-gate 		mdnamelist_t	*raidnlp = NULL;
26510Sstevel@tonic-gate 		mdnamelist_t	*p;
26520Sstevel@tonic-gate 
26530Sstevel@tonic-gate 		/* for each raid */
26540Sstevel@tonic-gate 		rval = 0;
26550Sstevel@tonic-gate 		if (meta_get_raid_names(sp, &raidnlp, 0, ep) < 0)
26560Sstevel@tonic-gate 			return (-1);
26570Sstevel@tonic-gate 		for (p = raidnlp; (p != NULL); p = p->next) {
26580Sstevel@tonic-gate 			/* reset RAID */
26590Sstevel@tonic-gate 			raidnp = p->namep;
26600Sstevel@tonic-gate 			if (meta_raid_reset(sp, raidnp, options, ep) != 0) {
26610Sstevel@tonic-gate 				rval = -1;
26620Sstevel@tonic-gate 				break;
26630Sstevel@tonic-gate 			}
26640Sstevel@tonic-gate 		}
26650Sstevel@tonic-gate 
26660Sstevel@tonic-gate 		/* cleanup, return success */
26670Sstevel@tonic-gate 		metafreenamelist(raidnlp);
26680Sstevel@tonic-gate 		return (rval);
26690Sstevel@tonic-gate 	}
26700Sstevel@tonic-gate 
26710Sstevel@tonic-gate 	/* check name */
26720Sstevel@tonic-gate 	if (metachkmeta(raidnp, ep) != 0)
26730Sstevel@tonic-gate 		return (-1);
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate 	/* get unit structure */
26760Sstevel@tonic-gate 	if ((raidp = meta_get_raid(sp, raidnp, ep)) == NULL)
26770Sstevel@tonic-gate 		return (-1);
26780Sstevel@tonic-gate 
26790Sstevel@tonic-gate 	/* make sure nobody owns us */
26800Sstevel@tonic-gate 	if (MD_HAS_PARENT(raidp->common.parent)) {
26810Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(raidnp->dev),
26820Sstevel@tonic-gate 		    raidnp->cname));
26830Sstevel@tonic-gate 	}
26840Sstevel@tonic-gate 
26850Sstevel@tonic-gate 	/* clear subdevices cache */
26860Sstevel@tonic-gate 	if (invalidate_columns(sp, raidnp, ep) != 0)
26870Sstevel@tonic-gate 		return (-1);
26880Sstevel@tonic-gate 
26890Sstevel@tonic-gate 	/* clear metadevice */
26900Sstevel@tonic-gate 	if (meta_reset(sp, raidnp, options, ep) != 0)
26910Sstevel@tonic-gate 		goto out;
26920Sstevel@tonic-gate 	rval = 0;	/* success */
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 	/* let em know */
26950Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
26960Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "%s: RAID is cleared\n"),
26970Sstevel@tonic-gate 		    raidnp->cname);
26980Sstevel@tonic-gate 		(void) fflush(stdout);
26990Sstevel@tonic-gate 	}
27000Sstevel@tonic-gate 
27010Sstevel@tonic-gate 	/* clear subdevices */
27020Sstevel@tonic-gate 	if (! (options & MDCMD_RECURSE))
27030Sstevel@tonic-gate 		goto out;
27040Sstevel@tonic-gate 
27050Sstevel@tonic-gate 	for (col = 0; (col < raidp->cols.cols_len); ++col) {
27060Sstevel@tonic-gate 		md_raidcol_t	*cp = &raidp->cols.cols_val[col];
27070Sstevel@tonic-gate 		mdname_t	*colnp = cp->colnamep;
27080Sstevel@tonic-gate 
27090Sstevel@tonic-gate 		/* only recurse on metadevices */
27100Sstevel@tonic-gate 		if (! metaismeta(colnp))
27110Sstevel@tonic-gate 			continue;
27120Sstevel@tonic-gate 
27130Sstevel@tonic-gate 		if (meta_reset_by_name(sp, colnp, options, ep) != 0)
27140Sstevel@tonic-gate 			rval = -1;
27150Sstevel@tonic-gate 	}
27160Sstevel@tonic-gate 
27170Sstevel@tonic-gate 	/* cleanup, return success */
27180Sstevel@tonic-gate out:
27190Sstevel@tonic-gate 	meta_invalidate_name(raidnp);
27200Sstevel@tonic-gate 	return (rval);
27210Sstevel@tonic-gate }
27220Sstevel@tonic-gate 
27230Sstevel@tonic-gate /*
27240Sstevel@tonic-gate  * reports TRUE if any RAID component is in error
27250Sstevel@tonic-gate  */
27260Sstevel@tonic-gate int
27270Sstevel@tonic-gate meta_raid_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *raid_names)
27280Sstevel@tonic-gate {
27290Sstevel@tonic-gate 	mdnamelist_t	*nlp;
27300Sstevel@tonic-gate 	md_error_t	  status	= mdnullerror;
27310Sstevel@tonic-gate 	md_error_t	 *ep		= &status;
27320Sstevel@tonic-gate 	int		  any_errs	= FALSE;
27330Sstevel@tonic-gate 
27340Sstevel@tonic-gate 	for (nlp = raid_names; nlp; nlp = nlp->next) {
27350Sstevel@tonic-gate 		md_raid_t	*raidp;
27360Sstevel@tonic-gate 
27370Sstevel@tonic-gate 		if ((raidp = meta_get_raid(sp, nlp->namep, ep)) == NULL) {
27380Sstevel@tonic-gate 			any_errs |= TRUE;
27390Sstevel@tonic-gate 			goto out;
27400Sstevel@tonic-gate 		}
27410Sstevel@tonic-gate 		if (raidp->state != RUS_OKAY && raidp->state != RUS_INIT) {
27420Sstevel@tonic-gate 			any_errs |= TRUE;
27430Sstevel@tonic-gate 			goto out;
27440Sstevel@tonic-gate 		}
27450Sstevel@tonic-gate 	}
27460Sstevel@tonic-gate out:
27470Sstevel@tonic-gate 	if (!mdisok(ep))
27480Sstevel@tonic-gate 		mdclrerror(ep);
27490Sstevel@tonic-gate 
27500Sstevel@tonic-gate 	return (any_errs);
27510Sstevel@tonic-gate }
27520Sstevel@tonic-gate /*
27530Sstevel@tonic-gate  * regen parity on a raid
27540Sstevel@tonic-gate  */
27550Sstevel@tonic-gate int
27560Sstevel@tonic-gate meta_raid_regen_byname(mdsetname_t *sp, mdname_t *raidnp, diskaddr_t size,
27570Sstevel@tonic-gate 	md_error_t *ep)
27580Sstevel@tonic-gate {
27590Sstevel@tonic-gate 	char			*miscname;
27600Sstevel@tonic-gate 	md_resync_ioctl_t	ri;
27610Sstevel@tonic-gate 
27620Sstevel@tonic-gate 	/* should have a set */
27630Sstevel@tonic-gate 	assert(sp != NULL);
27640Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
27650Sstevel@tonic-gate 
27660Sstevel@tonic-gate 	/* make sure we have a raid */
27670Sstevel@tonic-gate 	if ((miscname = metagetmiscname(raidnp, ep)) == NULL)
27680Sstevel@tonic-gate 		return (-1);
27690Sstevel@tonic-gate 	if (strcmp(miscname, MD_RAID) != 0) {
27700Sstevel@tonic-gate 		return (mdmderror(ep, MDE_NOT_RAID, meta_getminor(raidnp->dev),
27710Sstevel@tonic-gate 		    raidnp->cname));
27720Sstevel@tonic-gate 	}
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate 	/* start resync */
27750Sstevel@tonic-gate 	(void) memset(&ri, 0, sizeof (ri));
27760Sstevel@tonic-gate 	MD_SETDRIVERNAME(&ri, MD_RAID, sp->setno);
27770Sstevel@tonic-gate 	ri.ri_mnum = meta_getminor(raidnp->dev);
27780Sstevel@tonic-gate 	ri.ri_copysize = size;
27790Sstevel@tonic-gate 	if (metaioctl(MD_IOCSETREGEN, &ri, &ri.mde, raidnp->cname) != 0)
27800Sstevel@tonic-gate 		return (mdstealerror(ep, &ri.mde));
27810Sstevel@tonic-gate 
27820Sstevel@tonic-gate 	/* return success */
27830Sstevel@tonic-gate 	return (0);
27840Sstevel@tonic-gate }
2785