xref: /onnv-gate/usr/src/lib/lvm/libmeta/common/meta_mirror.c (revision 4150:b39c1d0a6cde)
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
51623Stw21770  * Common Development and Distribution License (the "License").
61623Stw21770  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*4150Sjmf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
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  * mirror operations
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include <meta.h>
410Sstevel@tonic-gate #include <sys/lvm/md_mirror.h>
420Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include <ctype.h>
450Sstevel@tonic-gate #include <stddef.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate  * FUNCTION:    meta_get_mirror_names()
490Sstevel@tonic-gate  * INPUT:       sp      - the set name to get mirrors from
500Sstevel@tonic-gate  *              options - options from the command line
510Sstevel@tonic-gate  * OUTPUT:      nlpp    - list of all mirror 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 mirrors in the metadb
550Sstevel@tonic-gate  *              for all devices in the specified set
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate int
meta_get_mirror_names(mdsetname_t * sp,mdnamelist_t ** nlpp,int options,md_error_t * ep)580Sstevel@tonic-gate meta_get_mirror_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_MIRROR, sp, nlpp, options, ep));
660Sstevel@tonic-gate }
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * free mirror unit
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate void
meta_free_mirror(md_mirror_t * mirrorp)720Sstevel@tonic-gate meta_free_mirror(
730Sstevel@tonic-gate 	md_mirror_t	*mirrorp
740Sstevel@tonic-gate )
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	Free(mirrorp);
770Sstevel@tonic-gate }
780Sstevel@tonic-gate 
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate  * get mirror unit
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate static md_mirror_t *
meta_get_mirror_common(mdsetname_t * sp,mdname_t * mirnp,int fast,md_error_t * ep)830Sstevel@tonic-gate meta_get_mirror_common(
840Sstevel@tonic-gate 	mdsetname_t	*sp,
850Sstevel@tonic-gate 	mdname_t	*mirnp,
860Sstevel@tonic-gate 	int		fast,
870Sstevel@tonic-gate 	md_error_t	*ep
880Sstevel@tonic-gate )
890Sstevel@tonic-gate {
900Sstevel@tonic-gate 	mddrivename_t	*dnp = mirnp->drivenamep;
910Sstevel@tonic-gate 	char		*miscname;
920Sstevel@tonic-gate 	mm_unit_t	*mm;
930Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
940Sstevel@tonic-gate 	uint_t		smi, nsm;
950Sstevel@tonic-gate 	md_resync_ioctl_t ri;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	/* must have set */
980Sstevel@tonic-gate 	assert(sp != NULL);
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	/* short circuit */
1010Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
1020Sstevel@tonic-gate 		assert(dnp->unitp->type == MD_METAMIRROR);
1030Sstevel@tonic-gate 		return ((md_mirror_t *)dnp->unitp);
1040Sstevel@tonic-gate 	}
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	/* get miscname and unit */
1070Sstevel@tonic-gate 	if ((miscname = metagetmiscname(mirnp, ep)) == NULL)
1080Sstevel@tonic-gate 		return (NULL);
1090Sstevel@tonic-gate 	if (strcmp(miscname, MD_MIRROR) != 0) {
1100Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NOT_MM, meta_getminor(mirnp->dev),
1110Sstevel@tonic-gate 		    mirnp->cname);
1120Sstevel@tonic-gate 		return (NULL);
1130Sstevel@tonic-gate 	}
1140Sstevel@tonic-gate 	if ((mm = (mm_unit_t *)meta_get_mdunit(sp, mirnp, ep)) == NULL)
1150Sstevel@tonic-gate 		return (NULL);
1160Sstevel@tonic-gate 	assert(mm->c.un_type == MD_METAMIRROR);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	/* allocate mirror */
1190Sstevel@tonic-gate 	mirrorp = Zalloc(sizeof (*mirrorp));
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	/* get common info */
1220Sstevel@tonic-gate 	mirrorp->common.namep = mirnp;
1230Sstevel@tonic-gate 	mirrorp->common.type = mm->c.un_type;
1240Sstevel@tonic-gate 	mirrorp->common.state = mm->c.un_status;
1250Sstevel@tonic-gate 	mirrorp->common.capabilities = mm->c.un_capabilities;
1260Sstevel@tonic-gate 	mirrorp->common.parent = mm->c.un_parent;
1270Sstevel@tonic-gate 	mirrorp->common.size = mm->c.un_total_blocks;
1280Sstevel@tonic-gate 	mirrorp->common.user_flags = mm->c.un_user_flags;
1290Sstevel@tonic-gate 	mirrorp->common.revision = mm->c.un_revision;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	/* get options */
1320Sstevel@tonic-gate 	mirrorp->read_option = mm->un_read_option;
1330Sstevel@tonic-gate 	mirrorp->write_option = mm->un_write_option;
1340Sstevel@tonic-gate 	mirrorp->pass_num = mm->un_pass_num;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	/* get submirrors */
1370Sstevel@tonic-gate 	for (smi = 0, nsm = 0; (smi < NMIRROR); ++smi) {
1380Sstevel@tonic-gate 		mm_submirror_t	*mmsp = &mm->un_sm[smi];
1390Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 		/* get submirror state */
1420Sstevel@tonic-gate 		mdsp->state = mmsp->sm_state;
1430Sstevel@tonic-gate 		if (mdsp->state == SMS_UNUSED)
1440Sstevel@tonic-gate 			continue;
1450Sstevel@tonic-gate 		++nsm;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 		/* get submirror time of last state change */
1480Sstevel@tonic-gate 		mdsp->timestamp = mmsp->sm_timestamp;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 		/* get submirror flags */
1510Sstevel@tonic-gate 		mdsp->flags = mmsp->sm_flags;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 		/* get submirror name */
1540Sstevel@tonic-gate 		mdsp->submirnamep = metakeyname(&sp, mmsp->sm_key, fast, ep);
1550Sstevel@tonic-gate 		if (mdsp->submirnamep == NULL)
1560Sstevel@tonic-gate 			goto out;
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 	assert(nsm == mm->un_nsm);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	/* get resync info */
1610Sstevel@tonic-gate 	(void) memset(&ri, 0, sizeof (ri));
1620Sstevel@tonic-gate 	ri.ri_mnum = meta_getminor(mirnp->dev);
1630Sstevel@tonic-gate 	MD_SETDRIVERNAME(&ri, MD_MIRROR, sp->setno);
1640Sstevel@tonic-gate 	if (metaioctl(MD_IOCGETSYNC, &ri, &ri.mde, mirnp->cname) != 0) {
1650Sstevel@tonic-gate 		(void) mdstealerror(ep, &ri.mde);
1660Sstevel@tonic-gate 		goto out;
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 	mirrorp->percent_done = ri.ri_percent_done;
1690Sstevel@tonic-gate 	mirrorp->percent_dirty = ri.ri_percent_dirty;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	/* cleanup, return success */
1720Sstevel@tonic-gate 	Free(mm);
1730Sstevel@tonic-gate 	dnp->unitp = (md_common_t *)mirrorp;
1740Sstevel@tonic-gate 	return (mirrorp);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	/* cleanup, return error */
1770Sstevel@tonic-gate out:
1780Sstevel@tonic-gate 	Free(mm);
1790Sstevel@tonic-gate 	meta_free_mirror(mirrorp);
1800Sstevel@tonic-gate 	return (NULL);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate  * get mirror unit
1850Sstevel@tonic-gate  */
1860Sstevel@tonic-gate md_mirror_t *
meta_get_mirror(mdsetname_t * sp,mdname_t * mirnp,md_error_t * ep)1870Sstevel@tonic-gate meta_get_mirror(
1880Sstevel@tonic-gate 	mdsetname_t	*sp,
1890Sstevel@tonic-gate 	mdname_t	*mirnp,
1900Sstevel@tonic-gate 	md_error_t	*ep
1910Sstevel@tonic-gate )
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	return (meta_get_mirror_common(sp, mirnp, 0, ep));
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate  * check mirror for dev
1980Sstevel@tonic-gate  */
1990Sstevel@tonic-gate static int
in_mirror(mdsetname_t * sp,mdname_t * mirnp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)2000Sstevel@tonic-gate in_mirror(
2010Sstevel@tonic-gate 	mdsetname_t	*sp,
2020Sstevel@tonic-gate 	mdname_t	*mirnp,
2030Sstevel@tonic-gate 	mdname_t	*np,
2040Sstevel@tonic-gate 	diskaddr_t	slblk,
2050Sstevel@tonic-gate 	diskaddr_t	nblks,
2060Sstevel@tonic-gate 	md_error_t	*ep
2070Sstevel@tonic-gate )
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
2100Sstevel@tonic-gate 	uint_t		smi;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	/* should be in the same set */
2130Sstevel@tonic-gate 	assert(sp != NULL);
2140Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	/* get unit */
2170Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
2180Sstevel@tonic-gate 		return (-1);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	/* look in submirrors */
2210Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
2220Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
2230Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 		/* skip unused submirrors */
2260Sstevel@tonic-gate 		if (submirnp == NULL) {
2270Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
2280Sstevel@tonic-gate 			continue;
2290Sstevel@tonic-gate 		}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 		/* check overlap */
2320Sstevel@tonic-gate 		if (metaismeta(submirnp))
2330Sstevel@tonic-gate 			continue;
2340Sstevel@tonic-gate 		if (meta_check_overlap(mirnp->cname, np, slblk, nblks,
2350Sstevel@tonic-gate 		    submirnp, 0, -1, ep) != 0)
2360Sstevel@tonic-gate 			return (-1);
2370Sstevel@tonic-gate 	}
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/* return success */
2400Sstevel@tonic-gate 	return (0);
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate  * check to see if we're in a mirror
2450Sstevel@tonic-gate  */
2460Sstevel@tonic-gate int
meta_check_inmirror(mdsetname_t * sp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)2470Sstevel@tonic-gate meta_check_inmirror(
2480Sstevel@tonic-gate 	mdsetname_t	*sp,
2490Sstevel@tonic-gate 	mdname_t	*np,
2500Sstevel@tonic-gate 	diskaddr_t	slblk,
2510Sstevel@tonic-gate 	diskaddr_t	nblks,
2520Sstevel@tonic-gate 	md_error_t	*ep
2530Sstevel@tonic-gate )
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	mdnamelist_t	*mirrornlp = NULL;
2560Sstevel@tonic-gate 	mdnamelist_t	*p;
2570Sstevel@tonic-gate 	int		rval = 0;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	/* should have a set */
2600Sstevel@tonic-gate 	assert(sp != NULL);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/* for each mirror */
2630Sstevel@tonic-gate 	if (meta_get_mirror_names(sp, &mirrornlp, 0, ep) < 0)
2640Sstevel@tonic-gate 		return (-1);
2650Sstevel@tonic-gate 	for (p = mirrornlp; (p != NULL); p = p->next) {
2660Sstevel@tonic-gate 		mdname_t	*mirnp = p->namep;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 		/* check mirror */
2690Sstevel@tonic-gate 		if (in_mirror(sp, mirnp, np, slblk, nblks, ep) != 0) {
2700Sstevel@tonic-gate 			rval = -1;
2710Sstevel@tonic-gate 			break;
2720Sstevel@tonic-gate 		}
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	/* cleanup, return success */
2760Sstevel@tonic-gate 	metafreenamelist(mirrornlp);
2770Sstevel@tonic-gate 	return (rval);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate /*
2810Sstevel@tonic-gate  * Check to see if the primary mirror is built on top of a
2820Sstevel@tonic-gate  * root slice which is mounted. This check is primarily to
2830Sstevel@tonic-gate  * account for this case -
2840Sstevel@tonic-gate  *
2850Sstevel@tonic-gate  * # metainit -f d1 1 1 <root slice>
2860Sstevel@tonic-gate  * # metainit d0 -m d1
2870Sstevel@tonic-gate  * # metainit d2 1 1 ctds
2880Sstevel@tonic-gate  * # metattach d0 d2
2890Sstevel@tonic-gate  *
2900Sstevel@tonic-gate  * The metattach here needs to fail if the root slice is
2910Sstevel@tonic-gate  * being mirrored; otherwise there is a potential for
2920Sstevel@tonic-gate  * data corruption.
2930Sstevel@tonic-gate  */
2940Sstevel@tonic-gate static int
meta_check_primary_mirror(mdsetname_t * sp,mdname_t * mirnp,md_error_t * ep)2950Sstevel@tonic-gate meta_check_primary_mirror(
2960Sstevel@tonic-gate 	mdsetname_t	*sp,
2970Sstevel@tonic-gate 	mdname_t	*mirnp,
2980Sstevel@tonic-gate 	md_error_t	*ep
2990Sstevel@tonic-gate )
3000Sstevel@tonic-gate {
3010Sstevel@tonic-gate 	int		smi;
3020Sstevel@tonic-gate 	char		*curroot;
303*4150Sjmf 	char		*temproot;
3040Sstevel@tonic-gate 	mdname_t	*rootnp;
3050Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
3060Sstevel@tonic-gate 	md_stripe_t	*stripep;
3070Sstevel@tonic-gate 	md_row_t	*rp;
3080Sstevel@tonic-gate 	md_comp_t	*cp;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	if ((curroot = meta_get_current_root(ep)) == NULL)
3110Sstevel@tonic-gate 		return (-1);
312*4150Sjmf 
313*4150Sjmf 	/*
314*4150Sjmf 	 * We need to take the canonical name here otherwise the call to
315*4150Sjmf 	 * metaname will add a bad entry to the drivelistp cache and
316*4150Sjmf 	 * things will get nasty later on.
317*4150Sjmf 	 * However we also need to trap the case where we have a logical
318*4150Sjmf 	 * device name and meta_canonicalize returns NULL.
319*4150Sjmf 	 */
320*4150Sjmf 	temproot = meta_canonicalize(sp, curroot);
321*4150Sjmf 	if (temproot != NULL) {
322*4150Sjmf 		curroot = Strdup(temproot);
323*4150Sjmf 		Free(temproot);
324*4150Sjmf 	}
325*4150Sjmf 
3260Sstevel@tonic-gate 	/*
3270Sstevel@tonic-gate 	 * Get device name of current root metadevice. If root
3280Sstevel@tonic-gate 	 * is net mounted as happens if we're part of the
3290Sstevel@tonic-gate 	 * install process, rootnp will be set to NULL and we
3300Sstevel@tonic-gate 	 * return success.
3311623Stw21770 	 *
3321623Stw21770 	 * Since curroot should be a complete path, we only
3331623Stw21770 	 * need to check whether the device is a logical device.
3341623Stw21770 	 * The metaname below returns NULL if curroot is not a logical
3351623Stw21770 	 * device.
3360Sstevel@tonic-gate 	 */
3371623Stw21770 	if ((rootnp = metaname(&sp, curroot, LOGICAL_DEVICE, ep)) == NULL)
3380Sstevel@tonic-gate 		return (0);
3390Sstevel@tonic-gate 	/*
3401623Stw21770 	 * If we're here, the curroot is a mounted on a logical device.
3411623Stw21770 	 * Make sure this mirror is not on the root logical device.
3420Sstevel@tonic-gate 	 */
3431623Stw21770 	if (metaismeta(mirnp)) {
3440Sstevel@tonic-gate 		if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
3450Sstevel@tonic-gate 			return (-1);
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		for (smi = 0; (smi < NMIRROR); ++smi) {
3480Sstevel@tonic-gate 			/* Check all submirrors */
3490Sstevel@tonic-gate 			md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
3500Sstevel@tonic-gate 			mdname_t	*submirnamep = mdsp->submirnamep;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 			/* skip unused submirrors */
3530Sstevel@tonic-gate 			if (submirnamep == NULL) {
3540Sstevel@tonic-gate 				assert(mdsp->state == SMS_UNUSED);
3550Sstevel@tonic-gate 				continue;
3560Sstevel@tonic-gate 			}
3570Sstevel@tonic-gate 			/* check if submirror is a stripe or not */
3580Sstevel@tonic-gate 			if (strcmp(metagetmiscname(submirnamep, ep), MD_STRIPE)
3590Sstevel@tonic-gate 			    != 0)
3600Sstevel@tonic-gate 				return (-1);
3610Sstevel@tonic-gate 			if ((stripep = meta_get_stripe(sp, submirnamep, ep))
3620Sstevel@tonic-gate 			    == NULL)
3630Sstevel@tonic-gate 				return (-1);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 			/*
3660Sstevel@tonic-gate 			 * Examine the first component of the first row and
3670Sstevel@tonic-gate 			 * check to see if it has a mounted root slice
3680Sstevel@tonic-gate 			 */
3690Sstevel@tonic-gate 			rp = &stripep->rows.rows_val[0];
3700Sstevel@tonic-gate 			cp = &rp->comps.comps_val[0];
3710Sstevel@tonic-gate 			/*
3720Sstevel@tonic-gate 			 * we just care about the component built on
3730Sstevel@tonic-gate 			 * top of a raw device
3740Sstevel@tonic-gate 			 */
3750Sstevel@tonic-gate 			if (!metaismeta(cp->compnamep)) {
3760Sstevel@tonic-gate 				/*
3770Sstevel@tonic-gate 				 * If root device is the 1st component of
3780Sstevel@tonic-gate 				 * the stripe, then fail.
3790Sstevel@tonic-gate 				 */
3800Sstevel@tonic-gate 				if (strcmp(rootnp->cname, cp->compnamep->cname)
3810Sstevel@tonic-gate 				    == 0) {
3820Sstevel@tonic-gate 					(void) mduseerror(ep, MDE_IS_MOUNTED,
3830Sstevel@tonic-gate 					rootnp->dev, "/", rootnp->cname);
3840Sstevel@tonic-gate 					return (-1);
3850Sstevel@tonic-gate 				}
3860Sstevel@tonic-gate 			}
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 	/* return success */
3900Sstevel@tonic-gate 	return (0);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate /*
3940Sstevel@tonic-gate  * check submirror
3950Sstevel@tonic-gate  */
3960Sstevel@tonic-gate int
meta_check_submirror(mdsetname_t * sp,mdname_t * np,mdname_t * mirnp,int force,md_error_t * ep)3970Sstevel@tonic-gate meta_check_submirror(
3980Sstevel@tonic-gate 	mdsetname_t	*sp,
3990Sstevel@tonic-gate 	mdname_t	*np,
4000Sstevel@tonic-gate 	mdname_t	*mirnp,
4010Sstevel@tonic-gate 	int		force,
4020Sstevel@tonic-gate 	md_error_t	*ep
4030Sstevel@tonic-gate )
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	mdchkopts_t	options = 0;
4060Sstevel@tonic-gate 	md_common_t	*mdp;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/* make sure we have a metadevice disk */
4090Sstevel@tonic-gate 	if (metachkmeta(np, ep) != 0)
4100Sstevel@tonic-gate 		return (-1);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/*
4130Sstevel@tonic-gate 	 * Check to see if the primary mirror consists of a root
4140Sstevel@tonic-gate 	 * mounted device
4150Sstevel@tonic-gate 	 */
4160Sstevel@tonic-gate 	if (mirnp && (!force) && ((meta_check_primary_mirror(sp, mirnp, ep)
4170Sstevel@tonic-gate 	    != 0)))
4180Sstevel@tonic-gate 		return (-1);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
4210Sstevel@tonic-gate 	if ((! force) &&
4220Sstevel@tonic-gate 	    (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0)) {
4230Sstevel@tonic-gate 		return (-1);
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	/* make sure it is in the set */
4270Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
4280Sstevel@tonic-gate 		return (-1);
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/* make sure its not in a metadevice */
4310Sstevel@tonic-gate 	if (! metaismeta(np)) {		/* Non-metadevices */
4320Sstevel@tonic-gate 		if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
4330Sstevel@tonic-gate 			return (-1);
4340Sstevel@tonic-gate 	} else {			/* Metadevices only! */
4350Sstevel@tonic-gate 		/* make sure it can be parented */
4360Sstevel@tonic-gate 		if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
4370Sstevel@tonic-gate 			return (-1);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 		if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
4400Sstevel@tonic-gate 		    (! (mdp->capabilities & MD_CAN_SUB_MIRROR)) ||
4410Sstevel@tonic-gate 		    (mdp->parent != MD_NO_PARENT)) {
4420Sstevel@tonic-gate 			return (mdmderror(ep, MDE_INVAL_UNIT,
4430Sstevel@tonic-gate 					meta_getminor(np->dev), np->cname));
4440Sstevel@tonic-gate 		}
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/* return success */
4480Sstevel@tonic-gate 	return (0);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate /*
4520Sstevel@tonic-gate  * convert read options
4530Sstevel@tonic-gate  */
4540Sstevel@tonic-gate char *
rd_opt_to_name(mm_rd_opt_t opt)4550Sstevel@tonic-gate rd_opt_to_name(
4560Sstevel@tonic-gate 	mm_rd_opt_t	opt
4570Sstevel@tonic-gate )
4580Sstevel@tonic-gate {
4590Sstevel@tonic-gate 	switch (opt) {
4600Sstevel@tonic-gate 	case RD_LOAD_BAL:
4610Sstevel@tonic-gate 		return ("roundrobin");
4620Sstevel@tonic-gate 	case RD_GEOMETRY:
4630Sstevel@tonic-gate 		return ("geometric");
4640Sstevel@tonic-gate 	case RD_FIRST:
4650Sstevel@tonic-gate 		return ("first");
4660Sstevel@tonic-gate 	default:
4670Sstevel@tonic-gate 		assert(0);
4680Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "invalid"));
4690Sstevel@tonic-gate 	}
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate static char *
rd_opt_to_opt(mm_rd_opt_t opt)4730Sstevel@tonic-gate rd_opt_to_opt(
4740Sstevel@tonic-gate 	mm_rd_opt_t	opt
4750Sstevel@tonic-gate )
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 	switch (opt) {
4780Sstevel@tonic-gate 	case RD_LOAD_BAL:
4790Sstevel@tonic-gate 		return (NULL);	/* default */
4800Sstevel@tonic-gate 	case RD_GEOMETRY:
4810Sstevel@tonic-gate 		return ("-g");
4820Sstevel@tonic-gate 	case RD_FIRST:
4830Sstevel@tonic-gate 		return ("-r");
4840Sstevel@tonic-gate 	default:
4850Sstevel@tonic-gate 		assert(0);
4860Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "invalid"));
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate int
name_to_rd_opt(char * uname,char * name,mm_rd_opt_t * optp,md_error_t * ep)4910Sstevel@tonic-gate name_to_rd_opt(
4920Sstevel@tonic-gate 	char		*uname,
4930Sstevel@tonic-gate 	char		*name,
4940Sstevel@tonic-gate 	mm_rd_opt_t	*optp,
4950Sstevel@tonic-gate 	md_error_t	*ep
4960Sstevel@tonic-gate )
4970Sstevel@tonic-gate {
4980Sstevel@tonic-gate 	if (strcasecmp(name, "roundrobin") == 0) {
4990Sstevel@tonic-gate 		*optp = RD_LOAD_BAL;
5000Sstevel@tonic-gate 		return (0);
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 	if (strcasecmp(name, "geometric") == 0) {
5030Sstevel@tonic-gate 		*optp = RD_GEOMETRY;
5040Sstevel@tonic-gate 		return (0);
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 	if (strcasecmp(name, "first") == 0) {
5070Sstevel@tonic-gate 		*optp = RD_FIRST;
5080Sstevel@tonic-gate 		return (0);
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 	return (meta_cook_syntax(ep, MDE_BAD_RD_OPT, uname, 1, &name));
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate /*
5140Sstevel@tonic-gate  * convert write options
5150Sstevel@tonic-gate  */
5160Sstevel@tonic-gate char *
wr_opt_to_name(mm_wr_opt_t opt)5170Sstevel@tonic-gate wr_opt_to_name(
5180Sstevel@tonic-gate 	mm_wr_opt_t	opt
5190Sstevel@tonic-gate )
5200Sstevel@tonic-gate {
5210Sstevel@tonic-gate 	switch (opt) {
5220Sstevel@tonic-gate 	case WR_PARALLEL:
5230Sstevel@tonic-gate 		return ("parallel");
5240Sstevel@tonic-gate 	case WR_SERIAL:
5250Sstevel@tonic-gate 		return ("serial");
5260Sstevel@tonic-gate 	default:
5270Sstevel@tonic-gate 		assert(0);
5280Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "invalid"));
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate static char *
wr_opt_to_opt(mm_wr_opt_t opt)5330Sstevel@tonic-gate wr_opt_to_opt(
5340Sstevel@tonic-gate 	mm_wr_opt_t	opt
5350Sstevel@tonic-gate )
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate 	switch (opt) {
5380Sstevel@tonic-gate 	case WR_PARALLEL:
5390Sstevel@tonic-gate 		return (NULL);	/* default */
5400Sstevel@tonic-gate 	case WR_SERIAL:
5410Sstevel@tonic-gate 		return ("-S");
5420Sstevel@tonic-gate 	default:
5430Sstevel@tonic-gate 		assert(0);
5440Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "invalid"));
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate int
name_to_wr_opt(char * uname,char * name,mm_wr_opt_t * optp,md_error_t * ep)5490Sstevel@tonic-gate name_to_wr_opt(
5500Sstevel@tonic-gate 	char		*uname,
5510Sstevel@tonic-gate 	char		*name,
5520Sstevel@tonic-gate 	mm_wr_opt_t	*optp,
5530Sstevel@tonic-gate 	md_error_t	*ep
5540Sstevel@tonic-gate )
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate 	if (strcasecmp(name, "parallel") == 0) {
5570Sstevel@tonic-gate 		*optp = WR_PARALLEL;
5580Sstevel@tonic-gate 		return (0);
5590Sstevel@tonic-gate 	}
5600Sstevel@tonic-gate 	if (strcasecmp(name, "serial") == 0) {
5610Sstevel@tonic-gate 		*optp = WR_SERIAL;
5620Sstevel@tonic-gate 		return (0);
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 	return (meta_cook_syntax(ep, MDE_BAD_WR_OPT, uname, 1, &name));
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate /*
5680Sstevel@tonic-gate  * convert pass numbers
5690Sstevel@tonic-gate  */
5700Sstevel@tonic-gate int
name_to_pass_num(char * uname,char * name,mm_pass_num_t * passp,md_error_t * ep)5710Sstevel@tonic-gate name_to_pass_num(
5720Sstevel@tonic-gate 	char		*uname,
5730Sstevel@tonic-gate 	char		*name,
5740Sstevel@tonic-gate 	mm_pass_num_t	*passp,
5750Sstevel@tonic-gate 	md_error_t	*ep
5760Sstevel@tonic-gate )
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	if ((sscanf(name, "%hd", passp) != 1) ||
5790Sstevel@tonic-gate 	    (*passp < 0) || (*passp > MD_PASS_MAX)) {
5800Sstevel@tonic-gate 		return (meta_cook_syntax(ep, MDE_BAD_PASS_NUM,
5810Sstevel@tonic-gate 		    uname, 1, &name));
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 	return (0);
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate /*
5870Sstevel@tonic-gate  * convert resync option
5880Sstevel@tonic-gate  */
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate static char *
resync_opt_to_name(uint_t tstate)5910Sstevel@tonic-gate resync_opt_to_name(
5920Sstevel@tonic-gate 	uint_t	tstate
5930Sstevel@tonic-gate )
5940Sstevel@tonic-gate {
5950Sstevel@tonic-gate 	if (tstate & MD_ABR_CAP)
5960Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "application based"));
5970Sstevel@tonic-gate 	else
5980Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "optimized resync"));
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate /*
6020Sstevel@tonic-gate  * print mirror
6030Sstevel@tonic-gate  */
6040Sstevel@tonic-gate static int
mirror_print(md_mirror_t * mirrorp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)6050Sstevel@tonic-gate mirror_print(
6060Sstevel@tonic-gate 	md_mirror_t	*mirrorp,
6070Sstevel@tonic-gate 	char		*fname,
6080Sstevel@tonic-gate 	FILE		*fp,
6090Sstevel@tonic-gate 	mdprtopts_t	options,
6100Sstevel@tonic-gate 	md_error_t	*ep
6110Sstevel@tonic-gate )
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate 	uint_t		smi;
6140Sstevel@tonic-gate 	char		*p;
6150Sstevel@tonic-gate 	int		rval = -1;
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
6191623Stw21770 		if ((mirrorp->common.revision & MD_64BIT_META_DEV) == 0) {
6201623Stw21770 			rval = 0;
6211623Stw21770 			goto out;
6221623Stw21770 		}
6231623Stw21770 	}
6241623Stw21770 
6251623Stw21770 	if (options & PRINT_FN) {
6261623Stw21770 		if ((mirrorp->common.revision & MD_FN_META_DEV) == 0) {
6270Sstevel@tonic-gate 			rval = 0;
6280Sstevel@tonic-gate 			goto out;
6290Sstevel@tonic-gate 		}
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	/* print name and -m */
6330Sstevel@tonic-gate 	if (fprintf(fp, "%s -m", mirrorp->common.namep->cname) == EOF)
6340Sstevel@tonic-gate 		goto out;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	/* print submirrors */
6370Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
6380Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
6390Sstevel@tonic-gate 		mdname_t	*submirnamep = mdsp->submirnamep;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 		/* skip unused submirrors */
6420Sstevel@tonic-gate 		if (submirnamep == NULL) {
6430Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
6440Sstevel@tonic-gate 			continue;
6450Sstevel@tonic-gate 		}
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 		/* print submirror */
6481623Stw21770 		if (fprintf(fp, " %s", submirnamep->rname) == EOF)
6490Sstevel@tonic-gate 			goto out;
6500Sstevel@tonic-gate 	}
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	/* print options */
6530Sstevel@tonic-gate 	if ((p = rd_opt_to_opt(mirrorp->read_option)) != NULL) {
6540Sstevel@tonic-gate 		if (fprintf(fp, " %s", p) == EOF)
6550Sstevel@tonic-gate 			goto out;
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 	if ((p = wr_opt_to_opt(mirrorp->write_option)) != NULL) {
6580Sstevel@tonic-gate 		if (fprintf(fp, " %s", p) == EOF)
6590Sstevel@tonic-gate 			goto out;
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 	if (fprintf(fp, " %u\n", mirrorp->pass_num) == EOF)
6620Sstevel@tonic-gate 		goto out;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	/* success */
6650Sstevel@tonic-gate 	rval = 0;
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	/* cleanup, return error */
6680Sstevel@tonic-gate out:
6690Sstevel@tonic-gate 	if (rval != 0)
6700Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
6710Sstevel@tonic-gate 	return (rval);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate  * convert submirror state to name
6760Sstevel@tonic-gate  */
6770Sstevel@tonic-gate char *
sm_state_to_name(md_submirror_t * mdsp,md_status_t mirror_status,md_timeval32_t * tvp,uint_t tstate)6780Sstevel@tonic-gate sm_state_to_name(
6790Sstevel@tonic-gate 	md_submirror_t	*mdsp,
6800Sstevel@tonic-gate 	md_status_t	mirror_status,
6810Sstevel@tonic-gate 	md_timeval32_t	*tvp,
6820Sstevel@tonic-gate 	uint_t		tstate
6830Sstevel@tonic-gate )
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate 	static char	state_to_str[100];
6860Sstevel@tonic-gate 	sm_state_t	state = mdsp->state;
6870Sstevel@tonic-gate 	uint_t		is_target = mdsp->flags & MD_SM_RESYNC_TARGET;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	/* grab time */
6900Sstevel@tonic-gate 	if (tvp != NULL)
6910Sstevel@tonic-gate 		*tvp = mdsp->timestamp;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/*
6940Sstevel@tonic-gate 	 * Only return Unavailable if there is no flagged error on the
6950Sstevel@tonic-gate 	 * submirror. If the mirror has received any writes since the submirror
6960Sstevel@tonic-gate 	 * went into Unavailable state a resync is required. To alert the
6970Sstevel@tonic-gate 	 * administrator to this we return a 'Needs maintenance' message.
6980Sstevel@tonic-gate 	 */
6990Sstevel@tonic-gate 	if ((tstate != 0) && (state & SMS_RUNNING)) {
7000Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	/* all is well */
7040Sstevel@tonic-gate 	if (state & SMS_RUNNING) {
7050Sstevel@tonic-gate 		if (!(mirror_status & MD_UN_OPT_NOT_DONE) ||
7060Sstevel@tonic-gate 		    ((mirror_status & MD_UN_OPT_NOT_DONE) && !is_target)) {
7070Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Okay"));
7080Sstevel@tonic-gate 		}
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/* resyncing, needs repair */
7120Sstevel@tonic-gate 	if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
7130Sstevel@tonic-gate 	    SMS_OFFLINE_RESYNC)) ||
7140Sstevel@tonic-gate 	    (mirror_status & MD_UN_OPT_NOT_DONE)) {
7150Sstevel@tonic-gate 		if (mirror_status & MD_UN_RESYNC_ACTIVE) {
7160Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Resyncing"));
7170Sstevel@tonic-gate 		}
7180Sstevel@tonic-gate 		if (mirror_status & MD_UN_RESYNC_CANCEL) {
7190Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Resync cancelled"));
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Needs maintenance"));
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	/* needs repair */
7250Sstevel@tonic-gate 	if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE)) {
7260Sstevel@tonic-gate 		if (mirror_status & MD_UN_RESYNC_CANCEL) {
7270Sstevel@tonic-gate 			return (dgettext(TEXT_DOMAIN, "Resync cancelled"));
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Needs maintenance"));
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	/* unknown */
7330Sstevel@tonic-gate 	assert(0);
7340Sstevel@tonic-gate 	(void) sprintf(state_to_str, "0x%x", state);
7350Sstevel@tonic-gate 	return (state_to_str);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate /*
7390Sstevel@tonic-gate  * convert submirror state to repair action
7400Sstevel@tonic-gate  */
7410Sstevel@tonic-gate int
sm_state_to_action(mdsetname_t * sp,md_submirror_t * mdsp,md_status_t mirror_status,md_mirror_t * mirrorp,char ** actionp,md_error_t * ep)7420Sstevel@tonic-gate sm_state_to_action(
7430Sstevel@tonic-gate 	mdsetname_t	*sp,
7440Sstevel@tonic-gate 	md_submirror_t	*mdsp,
7450Sstevel@tonic-gate 	md_status_t	mirror_status,
7460Sstevel@tonic-gate 	md_mirror_t	*mirrorp,
7470Sstevel@tonic-gate 	char		**actionp,
7480Sstevel@tonic-gate 	md_error_t	*ep
7490Sstevel@tonic-gate )
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate 	static char	buf[1024];
7520Sstevel@tonic-gate 	mdname_t	*submirnamep = mdsp->submirnamep;
7530Sstevel@tonic-gate 	sm_state_t	state = mdsp->state;
7540Sstevel@tonic-gate 	char		*miscname;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	/* all is well */
7570Sstevel@tonic-gate 	*actionp = NULL;
7580Sstevel@tonic-gate 	if (mirror_status & MD_UN_RESYNC_ACTIVE)
7590Sstevel@tonic-gate 		return (0);
7600Sstevel@tonic-gate 	if ((state == SMS_RUNNING) && !(mirror_status & MD_UN_OPT_NOT_DONE))
7610Sstevel@tonic-gate 		return (0);
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	/* complete cancelled resync */
7640Sstevel@tonic-gate 	if (mirror_status & MD_UN_RESYNC_CANCEL) {
7650Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf),
7660Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "metasync %s"),
7670Sstevel@tonic-gate 		    mirrorp->common.namep->cname);
7680Sstevel@tonic-gate 		*actionp = buf;
7690Sstevel@tonic-gate 		return (0);
7700Sstevel@tonic-gate 	}
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	/* replace stripe component */
7730Sstevel@tonic-gate 	if ((metaismeta(submirnamep)) && (state & SMS_COMP_ERRED)) {
7740Sstevel@tonic-gate 		if ((miscname = metagetmiscname(submirnamep, ep)) == NULL)
7750Sstevel@tonic-gate 			return (-1);
7760Sstevel@tonic-gate 		if (strcmp(miscname, MD_STRIPE) == 0) {
7770Sstevel@tonic-gate 			mdname_t	*compnamep;
7780Sstevel@tonic-gate 			comp_state_t	compstate;
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 			if (meta_find_erred_comp(sp, submirnamep,
7810Sstevel@tonic-gate 			    &compnamep, &compstate, ep) != 0) {
7820Sstevel@tonic-gate 				return (-1);
7830Sstevel@tonic-gate 			}
7840Sstevel@tonic-gate 			if (compstate != CS_LAST_ERRED)
7850Sstevel@tonic-gate 				(void) snprintf(buf, sizeof (buf),
7860Sstevel@tonic-gate 				    "metareplace %s %s <%s>",
7870Sstevel@tonic-gate 				    mirrorp->common.namep->cname,
7880Sstevel@tonic-gate 				    compnamep->cname,
7890Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN, "new device"));
7900Sstevel@tonic-gate 			else
7910Sstevel@tonic-gate 				(void) snprintf(buf, sizeof (buf),
7920Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
7930Sstevel@tonic-gate 				    "after replacing \"Maintenance\" "
7940Sstevel@tonic-gate 				    "components:\n"
7950Sstevel@tonic-gate 				    "\t\tmetareplace %s %s <new device>"),
7960Sstevel@tonic-gate 				    mirrorp->common.namep->cname,
7970Sstevel@tonic-gate 				    compnamep->cname);
7980Sstevel@tonic-gate 			*actionp = buf;
7990Sstevel@tonic-gate 			return (0);
8000Sstevel@tonic-gate 		}
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	/* resync mirror */
8040Sstevel@tonic-gate 	if ((state & (SMS_ATTACHED_RESYNC | SMS_OFFLINE_RESYNC |
8050Sstevel@tonic-gate 	    SMS_COMP_RESYNC | SMS_ATTACHED)) ||
8060Sstevel@tonic-gate 	    (mirror_status & MD_UN_OPT_NOT_DONE)) {
8070Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "metasync %s",
8080Sstevel@tonic-gate 		    mirrorp->common.namep->cname);
8090Sstevel@tonic-gate 		*actionp = buf;
8100Sstevel@tonic-gate 		return (0);
8110Sstevel@tonic-gate 	}
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	/* online submirror */
8140Sstevel@tonic-gate 	if (state & SMS_OFFLINE) {
8150Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "metaonline %s %s",
8160Sstevel@tonic-gate 		    mirrorp->common.namep->cname, submirnamep->cname);
8170Sstevel@tonic-gate 		*actionp = buf;
8180Sstevel@tonic-gate 		return (0);
8190Sstevel@tonic-gate 	}
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	/* unknown action */
8220Sstevel@tonic-gate 	*actionp = dgettext(TEXT_DOMAIN, "???");
8230Sstevel@tonic-gate 	return (0);
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate  * print mirror options
8280Sstevel@tonic-gate  */
8290Sstevel@tonic-gate int
meta_print_mirror_options(mm_rd_opt_t read_option,mm_wr_opt_t write_option,mm_pass_num_t pass_num,uint_t tstate,char * fname,mdsetname_t * sp,FILE * fp,md_error_t * ep)8300Sstevel@tonic-gate meta_print_mirror_options(
8310Sstevel@tonic-gate 	mm_rd_opt_t	read_option,
8320Sstevel@tonic-gate 	mm_wr_opt_t	write_option,
8330Sstevel@tonic-gate 	mm_pass_num_t	pass_num,
8340Sstevel@tonic-gate 	uint_t		tstate,
8350Sstevel@tonic-gate 	char		*fname,
8360Sstevel@tonic-gate 	mdsetname_t	*sp,
8370Sstevel@tonic-gate 	FILE		*fp,
8380Sstevel@tonic-gate 	md_error_t	*ep
8390Sstevel@tonic-gate )
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	char		*p;
8420Sstevel@tonic-gate 	int		rval = -1;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	/* print options */
8450Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Pass: %u\n"),
8460Sstevel@tonic-gate 	    pass_num) == EOF) {
8470Sstevel@tonic-gate 		goto out;
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 	if ((p = rd_opt_to_opt(read_option)) == NULL)
8500Sstevel@tonic-gate 		p = dgettext(TEXT_DOMAIN, "default");
8510Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Read option: %s (%s)\n"),
8520Sstevel@tonic-gate 	    rd_opt_to_name(read_option), p) == EOF) {
8530Sstevel@tonic-gate 		goto out;
8540Sstevel@tonic-gate 	}
8550Sstevel@tonic-gate 	if ((p = wr_opt_to_opt(write_option)) == NULL)
8560Sstevel@tonic-gate 		p = dgettext(TEXT_DOMAIN, "default");
8570Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Write option: %s (%s)\n"),
8580Sstevel@tonic-gate 	    wr_opt_to_name(write_option), p) == EOF) {
8590Sstevel@tonic-gate 		goto out;
8600Sstevel@tonic-gate 	}
8610Sstevel@tonic-gate 	/* Display resync option for mirror, if MultiNode set */
8620Sstevel@tonic-gate 	if (meta_is_mn_set(sp, ep)) {
8630Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
8640Sstevel@tonic-gate 		    "    Resync option: %s\n"),
8650Sstevel@tonic-gate 		    resync_opt_to_name(tstate)) == EOF) {
8660Sstevel@tonic-gate 			goto out;
8670Sstevel@tonic-gate 		}
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	/* success */
8710Sstevel@tonic-gate 	rval = 0;
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	/* cleanup, return error */
8740Sstevel@tonic-gate out:
8750Sstevel@tonic-gate 	if (rval != 0)
8760Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
8770Sstevel@tonic-gate 	return (rval);
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate static char *
get_node_name(uint_t nid,md_error_t * ep)8810Sstevel@tonic-gate get_node_name(uint_t nid, md_error_t *ep)
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate 	mndiskset_membershiplist_t	*nl, *p;
8840Sstevel@tonic-gate 	int				n;
8850Sstevel@tonic-gate 	char				*node_nm;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	/* get the known membership list */
8880Sstevel@tonic-gate 	if (meta_read_nodelist(&n, &nl, ep)) {
8890Sstevel@tonic-gate 		return (NULL);
8900Sstevel@tonic-gate 	}
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	/* find the matching node and return the name */
8930Sstevel@tonic-gate 	for (p = nl; (p != NULL); p = p->next) {
8940Sstevel@tonic-gate 		if (nid == p->msl_node_id) {
8950Sstevel@tonic-gate 			/* match found */
8960Sstevel@tonic-gate 			node_nm = Strdup(p->msl_node_name);
8970Sstevel@tonic-gate 			goto out;
8980Sstevel@tonic-gate 		}
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/* match not found */
9020Sstevel@tonic-gate 	node_nm = Strdup(dgettext(TEXT_DOMAIN, "None"));
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate out:
9050Sstevel@tonic-gate 	meta_free_nodelist(nl);
9060Sstevel@tonic-gate 	return (node_nm);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate  * report mirror
9110Sstevel@tonic-gate  */
9120Sstevel@tonic-gate static int
mirror_report(mdsetname_t * sp,md_mirror_t * mirrorp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)9130Sstevel@tonic-gate mirror_report(
9140Sstevel@tonic-gate 	mdsetname_t	*sp,
9150Sstevel@tonic-gate 	md_mirror_t	*mirrorp,
9160Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
9170Sstevel@tonic-gate 	char		*fname,
9180Sstevel@tonic-gate 	FILE		*fp,
9190Sstevel@tonic-gate 	mdprtopts_t	options,
9200Sstevel@tonic-gate 	md_error_t	*ep
9210Sstevel@tonic-gate )
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate 	md_status_t	status = mirrorp->common.state;
9240Sstevel@tonic-gate 	uint_t		smi;
9250Sstevel@tonic-gate 	char		*p;
9260Sstevel@tonic-gate 	int		rval = -1;
9270Sstevel@tonic-gate 	uint_t		tstate = 0;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	/*
9300Sstevel@tonic-gate 	 * check for the -B option. If -B and the metadevice is
9310Sstevel@tonic-gate 	 * a 64 bit device, get the dev for relocation information
9320Sstevel@tonic-gate 	 * printout. If not a 64 bit device, just don't print this
9330Sstevel@tonic-gate 	 * information out but you need to go down to the subdevice
9340Sstevel@tonic-gate 	 * level and print there if appropriate.
9350Sstevel@tonic-gate 	 */
9360Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
9371623Stw21770 		if ((mirrorp->common.revision & MD_64BIT_META_DEV) == 0) {
9381623Stw21770 			for (smi = 0; (smi < NMIRROR); ++smi) {
9391623Stw21770 				md_submirror_t	*mdsp =
9401623Stw21770 				    &mirrorp->submirrors[smi];
9411623Stw21770 				mdname_t	*submirnamep =
9421623Stw21770 				    mdsp->submirnamep;
9431623Stw21770 				if (submirnamep == NULL) {
9441623Stw21770 					continue;
9451623Stw21770 				}
9461623Stw21770 				if ((metaismeta(submirnamep)) &&
9471623Stw21770 				    (meta_print_name(sp, submirnamep, nlpp,
9481623Stw21770 				    fname, fp, options | PRINT_SUBDEVS, NULL,
9491623Stw21770 				    ep) != 0)) {
9501623Stw21770 					return (-1);
9511623Stw21770 				}
9521623Stw21770 			}
9531623Stw21770 			rval = 0;
9541623Stw21770 			goto out;
9551623Stw21770 		} else {
9561623Stw21770 			if (meta_getdevs(sp, mirrorp->common.namep,
9571623Stw21770 			    nlpp, ep) != 0)
9581623Stw21770 				goto out;
9591623Stw21770 		}
9601623Stw21770 	}
9611623Stw21770 
9621623Stw21770 	/*
9631623Stw21770 	 * check for the -D option. If -D and the name is
9641623Stw21770 	 * a descriptive name, get the dev for relocation information
9651623Stw21770 	 * printout. If not a descriptive name, don't print this
9661623Stw21770 	 * information out but you need to go down to the subdevice
9671623Stw21770 	 * level and print there if appropriate.
9681623Stw21770 	 */
9691623Stw21770 	if (options & PRINT_FN) {
9701623Stw21770 		if ((mirrorp->common.revision & MD_FN_META_DEV) == 0) {
9710Sstevel@tonic-gate 			for (smi = 0; (smi < NMIRROR); ++smi) {
9720Sstevel@tonic-gate 				md_submirror_t	*mdsp =
9730Sstevel@tonic-gate 				    &mirrorp->submirrors[smi];
9740Sstevel@tonic-gate 				mdname_t	*submirnamep =
9750Sstevel@tonic-gate 				    mdsp->submirnamep;
9760Sstevel@tonic-gate 				if (submirnamep == NULL) {
9770Sstevel@tonic-gate 					continue;
9780Sstevel@tonic-gate 				}
9790Sstevel@tonic-gate 				if ((metaismeta(submirnamep)) &&
9800Sstevel@tonic-gate 				    (meta_print_name(sp, submirnamep, nlpp,
9810Sstevel@tonic-gate 				    fname, fp, options | PRINT_SUBDEVS, NULL,
9820Sstevel@tonic-gate 				    ep) != 0)) {
9830Sstevel@tonic-gate 					return (-1);
9840Sstevel@tonic-gate 				}
9850Sstevel@tonic-gate 			}
9860Sstevel@tonic-gate 			rval = 0;
9870Sstevel@tonic-gate 			goto out;
9880Sstevel@tonic-gate 		} else {
9890Sstevel@tonic-gate 			if (meta_getdevs(sp, mirrorp->common.namep,
9900Sstevel@tonic-gate 			    nlpp, ep) != 0)
9910Sstevel@tonic-gate 				goto out;
9920Sstevel@tonic-gate 		}
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	/* print header */
9960Sstevel@tonic-gate 	if (options & PRINT_HEADER) {
9970Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Mirror\n"),
9980Sstevel@tonic-gate 		    mirrorp->common.namep->cname) == EOF) {
9990Sstevel@tonic-gate 			goto out;
10000Sstevel@tonic-gate 		}
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	/* print submirrors, adjust status */
10040Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
10050Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
10060Sstevel@tonic-gate 		mdname_t	*submirnamep = mdsp->submirnamep;
10070Sstevel@tonic-gate 		char		*sm_state;
10080Sstevel@tonic-gate 		md_timeval32_t	tv;
10090Sstevel@tonic-gate 		char		*timep;
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 		/* skip unused submirrors */
10120Sstevel@tonic-gate 		if (submirnamep == NULL) {
10130Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
10140Sstevel@tonic-gate 			continue;
10150Sstevel@tonic-gate 		}
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 		if (mdsp->state & SMS_OFFLINE)
10180Sstevel@tonic-gate 			status &= ~MD_UN_OPT_NOT_DONE;
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 		/* print submirror */
10210Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Submirror %u: %s\n"),
10220Sstevel@tonic-gate 		    smi, submirnamep->cname) == EOF) {
10230Sstevel@tonic-gate 			goto out;
10240Sstevel@tonic-gate 		}
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 		/* print state */
10270Sstevel@tonic-gate 		if (metaismeta(mdsp->submirnamep)) {
10280Sstevel@tonic-gate 			if (meta_get_tstate(mdsp->submirnamep->dev, &tstate,
10290Sstevel@tonic-gate 			    ep) != 0)
10300Sstevel@tonic-gate 				return (-1);
10310Sstevel@tonic-gate 		}
10320Sstevel@tonic-gate 		sm_state = sm_state_to_name(mdsp, status, &tv,
10330Sstevel@tonic-gate 		    tstate & MD_DEV_ERRORED);
10340Sstevel@tonic-gate 		if (options & PRINT_TIMES) {
10350Sstevel@tonic-gate 			timep = meta_print_time(&tv);
10360Sstevel@tonic-gate 		} else {
10370Sstevel@tonic-gate 			timep = "";
10380Sstevel@tonic-gate 		}
10390Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
10400Sstevel@tonic-gate 		    "      State: %-12s %s\n"),
10410Sstevel@tonic-gate 		    sm_state, timep) == EOF) {
10420Sstevel@tonic-gate 			goto out;
10430Sstevel@tonic-gate 		}
10440Sstevel@tonic-gate 	}
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	/* print resync status */
10470Sstevel@tonic-gate 	if (status & MD_UN_RESYNC_CANCEL) {
10480Sstevel@tonic-gate 		/* Resync was cancelled but is restartable */
10491623Stw21770 		if (mirrorp->common.revision & MD_64BIT_META_DEV) {
10500Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
10510Sstevel@tonic-gate 			    "    Resync cancelled: %2d.%1d %% done\n"),
10520Sstevel@tonic-gate 			    mirrorp->percent_done/10,
10530Sstevel@tonic-gate 			    mirrorp->percent_done%10) == EOF) {
10540Sstevel@tonic-gate 				goto out;
10550Sstevel@tonic-gate 			}
10560Sstevel@tonic-gate 		} else {
10570Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
10580Sstevel@tonic-gate 			    "    Resync cancelled: %d %% done\n"),
10590Sstevel@tonic-gate 			    mirrorp->percent_done) == EOF) {
10600Sstevel@tonic-gate 				goto out;
10610Sstevel@tonic-gate 			}
10620Sstevel@tonic-gate 		}
10630Sstevel@tonic-gate 	} else if (status & MD_UN_RESYNC_ACTIVE) {
10641623Stw21770 		if (mirrorp->common.revision & MD_64BIT_META_DEV) {
10650Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
10660Sstevel@tonic-gate 			    "    Resync in progress: %2d.%1d %% done\n"),
10670Sstevel@tonic-gate 			    mirrorp->percent_done/10,
10680Sstevel@tonic-gate 			    mirrorp->percent_done%10) == EOF) {
10690Sstevel@tonic-gate 				goto out;
10700Sstevel@tonic-gate 			}
10710Sstevel@tonic-gate 		} else {
10720Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
10730Sstevel@tonic-gate 			    "    Resync in progress: %d %% done\n"),
10740Sstevel@tonic-gate 			    mirrorp->percent_done) == EOF) {
10750Sstevel@tonic-gate 				goto out;
10760Sstevel@tonic-gate 			}
10770Sstevel@tonic-gate 		}
10780Sstevel@tonic-gate 	}
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	/* print options */
10810Sstevel@tonic-gate 	if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
10820Sstevel@tonic-gate 		return (-1);
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	if (meta_print_mirror_options(mirrorp->read_option,
10850Sstevel@tonic-gate 	    mirrorp->write_option, mirrorp->pass_num,
10860Sstevel@tonic-gate 	    tstate, fname, sp, fp, ep) != 0)
10870Sstevel@tonic-gate 		return (-1);
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	/* print mirror owner for multi-node metadevice */
10900Sstevel@tonic-gate 	if (meta_is_mn_set(sp, ep)) {
10910Sstevel@tonic-gate 		md_set_mmown_params_t	ownpar;
10920Sstevel@tonic-gate 		mdname_t		*mirnp = mirrorp->common.namep;
10930Sstevel@tonic-gate 		char			*node_name;
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 		(void) memset(&ownpar, 0, sizeof (ownpar));
10960Sstevel@tonic-gate 		ownpar.d.mnum = meta_getminor(mirnp->dev);
10970Sstevel@tonic-gate 		MD_SETDRIVERNAME(&ownpar, MD_MIRROR, sp->setno);
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 		if (metaioctl(MD_MN_GET_MM_OWNER, &ownpar, ep,
11000Sstevel@tonic-gate 		    "MD_MN_GET_MM_OWNER") != 0) {
11010Sstevel@tonic-gate 			return (-1);
11020Sstevel@tonic-gate 		}
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 		node_name = get_node_name(ownpar.d.owner, ep);
11050Sstevel@tonic-gate 		if (node_name == NULL)
11060Sstevel@tonic-gate 			return (-1);
11070Sstevel@tonic-gate 		else if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Owner: %s\n"),
11080Sstevel@tonic-gate 		    node_name) == EOF) {
11090Sstevel@tonic-gate 			Free(node_name);
11100Sstevel@tonic-gate 			goto out;
11110Sstevel@tonic-gate 		}
11120Sstevel@tonic-gate 		Free(node_name);
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	}
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	/* print size */
11170Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %lld blocks (%s)\n"),
11180Sstevel@tonic-gate 	    mirrorp->common.size,
11190Sstevel@tonic-gate 	    meta_number_to_string(mirrorp->common.size, DEV_BSIZE))
11200Sstevel@tonic-gate 	    == EOF) {
11210Sstevel@tonic-gate 		goto out;
11220Sstevel@tonic-gate 	}
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	/* MD_DEBUG stuff */
11250Sstevel@tonic-gate 	if (options & PRINT_DEBUG) {
11260Sstevel@tonic-gate 		mdname_t	*mirnp = mirrorp->common.namep;
11270Sstevel@tonic-gate 		mm_unit_t	*mm;
11280Sstevel@tonic-gate 		mddb_optloc_t	optloc;
11290Sstevel@tonic-gate 		uint_t		i;
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 		/* get real mirror unit */
11320Sstevel@tonic-gate 		if ((mm = (mm_unit_t *)meta_get_mdunit(sp, mirnp, ep))
11330Sstevel@tonic-gate 		    == NULL) {
11340Sstevel@tonic-gate 			return (-1);
11350Sstevel@tonic-gate 		}
11360Sstevel@tonic-gate 		assert(mm->c.un_type == MD_METAMIRROR);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 		/* print dirty regions */
11390Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
11400Sstevel@tonic-gate "    Regions which are dirty: %d%% (blksize %d num %d)\n"),
11410Sstevel@tonic-gate 		    mirrorp->percent_dirty, mm->un_rrd_blksize,
11420Sstevel@tonic-gate 		    mm->un_rrd_num) == EOF) {
11430Sstevel@tonic-gate 			Free(mm);
11440Sstevel@tonic-gate 			goto out;
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 		/* print optimized resync record locations */
11480Sstevel@tonic-gate 		(void) memset(&optloc, 0, sizeof (optloc));
11490Sstevel@tonic-gate 		optloc.recid = mm->un_rr_dirty_recid;
11500Sstevel@tonic-gate 		if (metaioctl(MD_DB_GETOPTLOC, &optloc, ep,
11510Sstevel@tonic-gate 		    "MD_DB_GETOPTLOC") != 0) {
11520Sstevel@tonic-gate 			Free(mm);
11530Sstevel@tonic-gate 			return (-1);
11540Sstevel@tonic-gate 		}
11550Sstevel@tonic-gate 		for (i = 0; (i < ((sizeof optloc.li) / sizeof (optloc.li[0])));
11560Sstevel@tonic-gate 		    ++i) {
11570Sstevel@tonic-gate 			mddb_config_t	dbconf;
11580Sstevel@tonic-gate 			char		*devname;
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 			(void) memset(&dbconf, 0, sizeof (dbconf));
11610Sstevel@tonic-gate 			dbconf.c_id = optloc.li[i];
11620Sstevel@tonic-gate 			dbconf.c_setno = sp->setno;
11630Sstevel@tonic-gate 			dbconf.c_subcmd = MDDB_CONFIG_ABS;
11640Sstevel@tonic-gate 			/* Don't need device id information from this ioctl */
11650Sstevel@tonic-gate 			dbconf.c_locator.l_devid = (uint64_t)0;
11660Sstevel@tonic-gate 			dbconf.c_locator.l_devid_flags = 0;
11670Sstevel@tonic-gate 			if (metaioctl(MD_DB_ENDDEV, &dbconf, &dbconf.c_mde,
11680Sstevel@tonic-gate 			    "MD_DB_ENDDEV") != 0) {
11690Sstevel@tonic-gate 				Free(mm);
11700Sstevel@tonic-gate 				return (mdstealerror(ep, &dbconf.c_mde));
11710Sstevel@tonic-gate 			}
11720Sstevel@tonic-gate 			if ((devname = splicename(&dbconf.c_devname))
11730Sstevel@tonic-gate 			    == NULL) {
11740Sstevel@tonic-gate 				devname = Strdup(dgettext(TEXT_DOMAIN,
11750Sstevel@tonic-gate 				    "unknown"));
11760Sstevel@tonic-gate 			}
11770Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
11780Sstevel@tonic-gate 			    "    Resync record[%u]: %d (%s %d %d)\n"), i,
11790Sstevel@tonic-gate 			    optloc.li[i], devname, dbconf.c_locator.l_blkno,
11800Sstevel@tonic-gate 			    (dbconf.c_dbend - dbconf.c_locator.l_blkno + 1))
11810Sstevel@tonic-gate 			    == EOF) {
11820Sstevel@tonic-gate 				Free(mm);
11830Sstevel@tonic-gate 				Free(devname);
11840Sstevel@tonic-gate 				goto out;
11850Sstevel@tonic-gate 			}
11860Sstevel@tonic-gate 			Free(devname);
11870Sstevel@tonic-gate 		}
11880Sstevel@tonic-gate 		Free(mm);
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	/* print submirror details */
11920Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
11930Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
11940Sstevel@tonic-gate 		mdname_t	*submirnamep = mdsp->submirnamep;
11950Sstevel@tonic-gate 		char		*sm_state;
11960Sstevel@tonic-gate 		md_timeval32_t	tv;
11970Sstevel@tonic-gate 		char		*timep;
11981623Stw21770 		md_stripe_t	*stripep;
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 		/* skip unused submirrors */
12010Sstevel@tonic-gate 		if (submirnamep == NULL) {
12020Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
12030Sstevel@tonic-gate 			continue;
12040Sstevel@tonic-gate 		}
12050Sstevel@tonic-gate 
12061623Stw21770 		if (options & PRINT_FN) {
12071623Stw21770 			/* get unit structure */
12081623Stw21770 			if ((stripep = meta_get_stripe_common(sp, submirnamep,
12091623Stw21770 			    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
12101623Stw21770 				goto out;
12111623Stw21770 
12121623Stw21770 			if ((stripep->common.revision & MD_FN_META_DEV)
12131623Stw21770 			    == 0)
12141623Stw21770 				continue;
12151623Stw21770 		}
12161623Stw21770 
12170Sstevel@tonic-gate 		/* add extra line */
12180Sstevel@tonic-gate 		if (fprintf(fp, "\n") == EOF)
12190Sstevel@tonic-gate 			goto out;
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 		/* print submirror */
12220Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
12230Sstevel@tonic-gate 		    "%s: Submirror of %s\n"),
12240Sstevel@tonic-gate 		    submirnamep->cname,
12250Sstevel@tonic-gate 		    mirrorp->common.namep->cname) == EOF) {
12260Sstevel@tonic-gate 			goto out;
12270Sstevel@tonic-gate 		}
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 		/* print state */
12300Sstevel@tonic-gate 		if (metaismeta(mdsp->submirnamep)) {
12310Sstevel@tonic-gate 			if (meta_get_tstate(mdsp->submirnamep->dev, &tstate, ep)
12320Sstevel@tonic-gate 			    != 0)
12330Sstevel@tonic-gate 				return (-1);
12340Sstevel@tonic-gate 		}
12350Sstevel@tonic-gate 		sm_state = sm_state_to_name(mdsp, status, &tv, NULL);
12360Sstevel@tonic-gate 		if (options & PRINT_TIMES) {
12370Sstevel@tonic-gate 			timep = meta_print_time(&tv);
12380Sstevel@tonic-gate 		} else {
12390Sstevel@tonic-gate 			timep = "";
12400Sstevel@tonic-gate 		}
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 		if ((tstate & MD_DEV_ERRORED) == 0) {
12430Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
12440Sstevel@tonic-gate 			    "    State: %-12s %s\n"),
12450Sstevel@tonic-gate 			    sm_state, timep) == EOF) {
12460Sstevel@tonic-gate 				goto out;
12470Sstevel@tonic-gate 			}
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 			/* print what to do */
12500Sstevel@tonic-gate 			if (sm_state_to_action(sp, mdsp, status,
12510Sstevel@tonic-gate 			    mirrorp, &p, ep) != 0)
12520Sstevel@tonic-gate 				return (-1);
12530Sstevel@tonic-gate 			if ((p != NULL) &&
12540Sstevel@tonic-gate 			    (fprintf(fp, dgettext(TEXT_DOMAIN,
12550Sstevel@tonic-gate 			    "    Invoke: %s\n"), p) == EOF)) {
12560Sstevel@tonic-gate 				goto out;
12570Sstevel@tonic-gate 			}
12580Sstevel@tonic-gate 		}
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 		/* print underlying metadevice */
12610Sstevel@tonic-gate 		if ((metaismeta(submirnamep)) &&
12620Sstevel@tonic-gate 		    (meta_print_name(sp, submirnamep, nlpp, fname, fp,
12630Sstevel@tonic-gate 		    ((options & ~PRINT_HEADER) | PRINT_SUBDEVS),
12640Sstevel@tonic-gate 		    NULL, ep) != 0)) {
12650Sstevel@tonic-gate 			return (-1);
12660Sstevel@tonic-gate 		}
12670Sstevel@tonic-gate 	}
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	/* add extra line */
12700Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
12710Sstevel@tonic-gate 		goto out;
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	/* success */
12740Sstevel@tonic-gate 	rval = 0;
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	/* cleanup, return error */
12770Sstevel@tonic-gate out:
12780Sstevel@tonic-gate 	if (rval != 0)
12790Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
12800Sstevel@tonic-gate 	return (rval);
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate /*
12840Sstevel@tonic-gate  * print/report mirror
12850Sstevel@tonic-gate  */
12860Sstevel@tonic-gate int
meta_mirror_print(mdsetname_t * sp,mdname_t * mirnp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)12870Sstevel@tonic-gate meta_mirror_print(
12880Sstevel@tonic-gate 	mdsetname_t	*sp,
12890Sstevel@tonic-gate 	mdname_t	*mirnp,
12900Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
12910Sstevel@tonic-gate 	char		*fname,
12920Sstevel@tonic-gate 	FILE		*fp,
12930Sstevel@tonic-gate 	mdprtopts_t	options,
12940Sstevel@tonic-gate 	md_error_t	*ep
12950Sstevel@tonic-gate )
12960Sstevel@tonic-gate {
12970Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
12980Sstevel@tonic-gate 	uint_t		smi;
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	/* should have same set */
13010Sstevel@tonic-gate 	assert(sp != NULL);
13020Sstevel@tonic-gate 	assert((mirnp == NULL) ||
13030Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev))));
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	/* print all mirrors */
13060Sstevel@tonic-gate 	if (mirnp == NULL) {
13070Sstevel@tonic-gate 		mdnamelist_t	*nlp = NULL;
13080Sstevel@tonic-gate 		mdnamelist_t	*p;
13090Sstevel@tonic-gate 		int		cnt;
13100Sstevel@tonic-gate 		int		rval = 0;
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 		/* get list */
13130Sstevel@tonic-gate 		if ((cnt = meta_get_mirror_names(sp, &nlp, options, ep)) < 0)
13140Sstevel@tonic-gate 			return (-1);
13150Sstevel@tonic-gate 		else if (cnt == 0)
13160Sstevel@tonic-gate 			return (0);
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 		/* recurse */
13190Sstevel@tonic-gate 		for (p = nlp; (p != NULL); p = p->next) {
13200Sstevel@tonic-gate 			mdname_t	*np = p->namep;
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 			if (meta_mirror_print(sp, np, nlpp, fname, fp,
13230Sstevel@tonic-gate 			    options, ep) != 0)
13240Sstevel@tonic-gate 				rval = -1;
13250Sstevel@tonic-gate 		}
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 		/* cleanup, return success */
13280Sstevel@tonic-gate 		metafreenamelist(nlp);
13290Sstevel@tonic-gate 		return (rval);
13300Sstevel@tonic-gate 	}
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	/* get unit structure */
13330Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror_common(sp, mirnp,
13340Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
13350Sstevel@tonic-gate 		return (-1);
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	/* check for parented */
13380Sstevel@tonic-gate 	if ((! (options & PRINT_SUBDEVS)) &&
13390Sstevel@tonic-gate 	    (MD_HAS_PARENT(mirrorp->common.parent))) {
13400Sstevel@tonic-gate 		return (0);
13410Sstevel@tonic-gate 	}
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	/* print appropriate detail */
13440Sstevel@tonic-gate 	if (options & PRINT_SHORT) {
13450Sstevel@tonic-gate 		/* print mirror */
13460Sstevel@tonic-gate 		if (mirror_print(mirrorp, fname, fp, options, ep) != 0)
13470Sstevel@tonic-gate 			return (-1);
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 		/* print underlying metadevices */
13500Sstevel@tonic-gate 		for (smi = 0; (smi < NMIRROR); ++smi) {
13510Sstevel@tonic-gate 			md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
13520Sstevel@tonic-gate 			mdname_t	*submirnamep = mdsp->submirnamep;
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 			/* skip unused submirrors */
13550Sstevel@tonic-gate 			if (submirnamep == NULL) {
13560Sstevel@tonic-gate 				assert(mdsp->state == SMS_UNUSED);
13570Sstevel@tonic-gate 				continue;
13580Sstevel@tonic-gate 			}
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 			/* print submirror */
13610Sstevel@tonic-gate 			if (metaismeta(submirnamep)) {
13620Sstevel@tonic-gate 				if (meta_print_name(sp, submirnamep, nlpp,
13630Sstevel@tonic-gate 				    fname, fp, (options | PRINT_SUBDEVS), NULL,
13640Sstevel@tonic-gate 				    ep) != 0) {
13650Sstevel@tonic-gate 					return (-1);
13660Sstevel@tonic-gate 				}
13670Sstevel@tonic-gate 			}
13680Sstevel@tonic-gate 		}
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 		/* return success */
13710Sstevel@tonic-gate 		return (0);
13720Sstevel@tonic-gate 	} else {
13730Sstevel@tonic-gate 		return (mirror_report(sp, mirrorp, nlpp, fname, fp,
13740Sstevel@tonic-gate 		    options, ep));
13750Sstevel@tonic-gate 	}
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate /*
13790Sstevel@tonic-gate  * online submirror
13800Sstevel@tonic-gate  */
13810Sstevel@tonic-gate int
meta_mirror_online(mdsetname_t * sp,mdname_t * mirnp,mdname_t * submirnp,mdcmdopts_t options,md_error_t * ep)13820Sstevel@tonic-gate meta_mirror_online(
13830Sstevel@tonic-gate 	mdsetname_t	*sp,
13840Sstevel@tonic-gate 	mdname_t	*mirnp,
13850Sstevel@tonic-gate 	mdname_t	*submirnp,
13860Sstevel@tonic-gate 	mdcmdopts_t	options,
13870Sstevel@tonic-gate 	md_error_t	*ep
13880Sstevel@tonic-gate )
13890Sstevel@tonic-gate {
13900Sstevel@tonic-gate 	md_i_off_on_t	mio;
13910Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
13920Sstevel@tonic-gate 	md_set_desc	*sd;
13930Sstevel@tonic-gate 	uint_t		tstate;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	/* should have same set */
13960Sstevel@tonic-gate 	assert(sp != NULL);
13970Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	/* check name */
14000Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
14010Sstevel@tonic-gate 		return (-1);
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
14040Sstevel@tonic-gate 		return (-1);
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	/* Only valid for mirror without ABR set */
14070Sstevel@tonic-gate 	if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
14080Sstevel@tonic-gate 		return (-1);
14090Sstevel@tonic-gate 	if (tstate & MD_ABR_CAP) {
14100Sstevel@tonic-gate 		(void) mderror(ep, MDE_ABR_SET, NULL);
14110Sstevel@tonic-gate 		return (-1);
14120Sstevel@tonic-gate 	}
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	/*
14150Sstevel@tonic-gate 	 * In a MN set, the master always executes the online command first.
14160Sstevel@tonic-gate 	 * Before the master executes the IOC_ONLINE ioctl,
14170Sstevel@tonic-gate 	 * the master sends a message to all nodes to suspend writes to
14180Sstevel@tonic-gate 	 * this mirror.  Then the master executes the IOC_ONLINE ioctl
14190Sstevel@tonic-gate 	 * which resumes writes to this mirror from the master node.
14200Sstevel@tonic-gate 	 * As each slave executes the online command, each slave will
14210Sstevel@tonic-gate 	 * call the IOC_ONLINE ioctl which will resume writes to this mirror
14220Sstevel@tonic-gate 	 * from that slave node.
14230Sstevel@tonic-gate 	 */
14240Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
14250Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
14260Sstevel@tonic-gate 			return (-1);
14270Sstevel@tonic-gate 		if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
14280Sstevel@tonic-gate 			if (meta_mn_send_suspend_writes(
14290Sstevel@tonic-gate 			    meta_getminor(mirnp->dev), ep) != 0)
14300Sstevel@tonic-gate 				return (-1);
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	/* online submirror */
14340Sstevel@tonic-gate 	(void) memset(&mio, 0, sizeof (mio));
14350Sstevel@tonic-gate 	mio.mnum = meta_getminor(mirnp->dev);
14360Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mio, MD_MIRROR, sp->setno);
14370Sstevel@tonic-gate 	mio.submirror = submirnp->dev;
14380Sstevel@tonic-gate 	if (metaioctl(MD_IOCONLINE, &mio, &mio.mde, NULL) != 0)
14390Sstevel@tonic-gate 		return (mdstealerror(ep, &mio.mde));
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	/* clear cache */
14420Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
14430Sstevel@tonic-gate 	meta_invalidate_name(submirnp);
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	/* let em know */
14460Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
14470Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
14480Sstevel@tonic-gate 		    "%s: submirror %s is onlined\n"),
14490Sstevel@tonic-gate 		    mirnp->cname, submirnp->cname);
14500Sstevel@tonic-gate 		(void) fflush(stdout);
14510Sstevel@tonic-gate 	}
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	/* return success */
14540Sstevel@tonic-gate 	return (0);
14550Sstevel@tonic-gate }
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate /*
14580Sstevel@tonic-gate  * offline submirror
14590Sstevel@tonic-gate  */
14600Sstevel@tonic-gate int
meta_mirror_offline(mdsetname_t * sp,mdname_t * mirnp,mdname_t * submirnp,mdcmdopts_t options,md_error_t * ep)14610Sstevel@tonic-gate meta_mirror_offline(
14620Sstevel@tonic-gate 	mdsetname_t	*sp,
14630Sstevel@tonic-gate 	mdname_t	*mirnp,
14640Sstevel@tonic-gate 	mdname_t	*submirnp,
14650Sstevel@tonic-gate 	mdcmdopts_t	options,
14660Sstevel@tonic-gate 	md_error_t	*ep
14670Sstevel@tonic-gate )
14680Sstevel@tonic-gate {
14690Sstevel@tonic-gate 	int		force = ((options & MDCMD_FORCE) ? 1 : 0);
14700Sstevel@tonic-gate 	md_i_off_on_t	mio;
14710Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
14720Sstevel@tonic-gate 	md_set_desc	*sd;
14730Sstevel@tonic-gate 	uint_t		tstate;
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 	/* should have same set */
14760Sstevel@tonic-gate 	assert(sp != NULL);
14770Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	/* check name */
14800Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
14810Sstevel@tonic-gate 		return (-1);
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
14840Sstevel@tonic-gate 		return (-1);
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	/* Only valid for mirror without ABR set */
14870Sstevel@tonic-gate 	if (meta_get_tstate(mirrorp->common.namep->dev, &tstate, ep) != 0)
14880Sstevel@tonic-gate 		return (-1);
14890Sstevel@tonic-gate 	if (tstate & MD_ABR_CAP) {
14900Sstevel@tonic-gate 		(void) mderror(ep, MDE_ABR_SET, NULL);
14910Sstevel@tonic-gate 		return (-1);
14920Sstevel@tonic-gate 	}
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	/*
14950Sstevel@tonic-gate 	 * In a MN set, the master always executes the offline command first.
14960Sstevel@tonic-gate 	 * Before the master executes the IOC_OFFLINE ioctl,
14970Sstevel@tonic-gate 	 * the master sends a message to all nodes to suspend writes to
14980Sstevel@tonic-gate 	 * this mirror.  Then the master executes the IOC_OFFLINE ioctl
14990Sstevel@tonic-gate 	 * which resumes writes to this mirror from the master node.
15000Sstevel@tonic-gate 	 * As each slave executes the offline command, each slave will
15010Sstevel@tonic-gate 	 * call the IOC_OFFLINE ioctl which will resume writes to this mirror
15020Sstevel@tonic-gate 	 * from that slave node.
15030Sstevel@tonic-gate 	 */
15040Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
15050Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
15060Sstevel@tonic-gate 			return (-1);
15070Sstevel@tonic-gate 		if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
15080Sstevel@tonic-gate 			if (meta_mn_send_suspend_writes(
15090Sstevel@tonic-gate 			    meta_getminor(mirnp->dev), ep) != 0)
15100Sstevel@tonic-gate 				return (-1);
15110Sstevel@tonic-gate 	}
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	/* offline submirror */
15140Sstevel@tonic-gate 	(void) memset(&mio, 0, sizeof (mio));
15150Sstevel@tonic-gate 	mio.mnum = meta_getminor(mirnp->dev);
15160Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mio, MD_MIRROR, sp->setno);
15170Sstevel@tonic-gate 	mio.submirror = submirnp->dev;
15180Sstevel@tonic-gate 	mio.force_offline = force;
15190Sstevel@tonic-gate 	if (metaioctl(MD_IOCOFFLINE, &mio, &mio.mde, NULL) != 0)
15200Sstevel@tonic-gate 		return (mdstealerror(ep, &mio.mde));
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	/* clear cache */
15230Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
15240Sstevel@tonic-gate 	meta_invalidate_name(submirnp);
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	/* let em know */
15270Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
15280Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
15290Sstevel@tonic-gate 		    "%s: submirror %s is offlined\n"),
15300Sstevel@tonic-gate 		    mirnp->cname, submirnp->cname);
15310Sstevel@tonic-gate 		(void) fflush(stdout);
15320Sstevel@tonic-gate 	}
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	/* return success */
15350Sstevel@tonic-gate 	return (0);
15360Sstevel@tonic-gate }
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate /*
15390Sstevel@tonic-gate  * attach submirror to mirror
15400Sstevel@tonic-gate  * we actually never have to worry about crossing a thresh hold here.
15410Sstevel@tonic-gate  * 2 cases 1) attach and the only way the mirror can be 64 bit is if
15420Sstevel@tonic-gate  * one of the submirrors already is. 2) grow and the only way the mirror
15430Sstevel@tonic-gate  * is 64 bit is if one of the submirror's already is.
15440Sstevel@tonic-gate  */
15450Sstevel@tonic-gate int
meta_mirror_attach(mdsetname_t * sp,mdname_t * mirnp,mdname_t * submirnp,mdcmdopts_t options,md_error_t * ep)15460Sstevel@tonic-gate meta_mirror_attach(
15470Sstevel@tonic-gate 	mdsetname_t	*sp,
15480Sstevel@tonic-gate 	mdname_t	*mirnp,
15490Sstevel@tonic-gate 	mdname_t	*submirnp,
15500Sstevel@tonic-gate 	mdcmdopts_t	options,
15510Sstevel@tonic-gate 	md_error_t	*ep
15520Sstevel@tonic-gate )
15530Sstevel@tonic-gate {
15540Sstevel@tonic-gate 	md_att_struct_t	att;
15550Sstevel@tonic-gate 	md_set_desc		*sd;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	/* should have same set */
15580Sstevel@tonic-gate 	assert(sp != NULL);
15590Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	/* check name */
15620Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
15630Sstevel@tonic-gate 		return (-1);
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	/* just grow */
15660Sstevel@tonic-gate 	if (submirnp == NULL) {
15670Sstevel@tonic-gate 		return (meta_concat_generic(sp, mirnp, NULL, ep));
15680Sstevel@tonic-gate 	}
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	/* check submirror */
15710Sstevel@tonic-gate 	if (meta_check_submirror(sp, submirnp, mirnp, 0, ep) != 0)
15720Sstevel@tonic-gate 		return (-1);
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
15750Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
15760Sstevel@tonic-gate 		/* store name in namespace */
15770Sstevel@tonic-gate 		if (add_key_name(sp, submirnp, NULL, ep) != 0)
15780Sstevel@tonic-gate 			return (-1);
15790Sstevel@tonic-gate 	}
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 	/*
15820Sstevel@tonic-gate 	 * In a MN set, the master always executes the attach command first.
15830Sstevel@tonic-gate 	 * Before the master executes the IOC_ATTACH ioctl, in non-DRYRUN mode
15840Sstevel@tonic-gate 	 * the master sends a message to all nodes to suspend writes to
15850Sstevel@tonic-gate 	 * this mirror.  Then the master executes the IOC_ATTACH ioctl
15860Sstevel@tonic-gate 	 * which resumes writes to this mirror from the master node.
15870Sstevel@tonic-gate 	 * As each slave executes the attach command, each slave will
15880Sstevel@tonic-gate 	 * call the IOC_ATTACH ioctl which will resume writes to this mirror
15890Sstevel@tonic-gate 	 * from that slave node.
15900Sstevel@tonic-gate 	 */
15910Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
15920Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
15930Sstevel@tonic-gate 			return (-1);
15940Sstevel@tonic-gate 		if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
15950Sstevel@tonic-gate 		    sd->sd_mn_am_i_master)
15960Sstevel@tonic-gate 			if (meta_mn_send_suspend_writes(
15970Sstevel@tonic-gate 			    meta_getminor(mirnp->dev), ep) != 0)
15980Sstevel@tonic-gate 				return (-1);
15990Sstevel@tonic-gate 	}
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	/* attach submirror */
16020Sstevel@tonic-gate 	(void) memset(&att, 0, sizeof (att));
16030Sstevel@tonic-gate 	att.mnum = meta_getminor(mirnp->dev);
16040Sstevel@tonic-gate 	MD_SETDRIVERNAME(&att, MD_MIRROR, sp->setno);
16050Sstevel@tonic-gate 	att.submirror = submirnp->dev;
16060Sstevel@tonic-gate 	att.key = submirnp->key;
16070Sstevel@tonic-gate 	/* if the comamnd was issued with -n option, use dryrun mode */
16080Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
16090Sstevel@tonic-gate 		att.options = MDIOCTL_DRYRUN;
16100Sstevel@tonic-gate 	}
16110Sstevel@tonic-gate 	if (metaioctl(MD_IOCATTACH, &att, &att.mde, NULL) != 0) {
16120Sstevel@tonic-gate 		/* In dryrun mode (DOIT not set) we must not alter the mddb */
16130Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
16140Sstevel@tonic-gate 			(void) del_key_name(sp, submirnp, ep);
16150Sstevel@tonic-gate 		}
16160Sstevel@tonic-gate 		return (mdstealerror(ep, &att.mde));
16170Sstevel@tonic-gate 	}
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
16200Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
16210Sstevel@tonic-gate 		/* clear cache */
16220Sstevel@tonic-gate 		meta_invalidate_name(mirnp);
16230Sstevel@tonic-gate 		meta_invalidate_name(submirnp);
16240Sstevel@tonic-gate 	}
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	/* let em know */
16270Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
16280Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
16290Sstevel@tonic-gate 		    "%s: submirror %s %s\n"), mirnp->cname, submirnp->cname,
16300Sstevel@tonic-gate 		    (options & MDCMD_DOIT) ? "is attached" : "would attach");
16310Sstevel@tonic-gate 		(void) fflush(stdout);
16320Sstevel@tonic-gate 	}
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate 	/* return success */
16350Sstevel@tonic-gate 	return (0);
16360Sstevel@tonic-gate }
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate /*
16390Sstevel@tonic-gate  * detach submirror
16400Sstevel@tonic-gate  */
16410Sstevel@tonic-gate int
meta_mirror_detach(mdsetname_t * sp,mdname_t * mirnp,mdname_t * submirnp,mdcmdopts_t options,md_error_t * ep)16420Sstevel@tonic-gate meta_mirror_detach(
16430Sstevel@tonic-gate 	mdsetname_t		*sp,
16440Sstevel@tonic-gate 	mdname_t		*mirnp,
16450Sstevel@tonic-gate 	mdname_t		*submirnp,
16460Sstevel@tonic-gate 	mdcmdopts_t		options,
16470Sstevel@tonic-gate 	md_error_t		*ep
16480Sstevel@tonic-gate )
16490Sstevel@tonic-gate {
16500Sstevel@tonic-gate 	int			force = ((options & MDCMD_FORCE) ? 1 : 0);
16510Sstevel@tonic-gate 	md_detach_params_t	detach;
16520Sstevel@tonic-gate 	md_set_desc		*sd;
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	/* should have same set */
16550Sstevel@tonic-gate 	assert(sp != NULL);
16560Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 	/* check name */
16590Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
16600Sstevel@tonic-gate 		return (-1);
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	/*
16630Sstevel@tonic-gate 	 * In a MN set, the master always executes the detach command first.
16640Sstevel@tonic-gate 	 * Before the master executes the IOC_DETACH ioctl,
16650Sstevel@tonic-gate 	 * the master sends a message to all nodes to suspend writes to
16660Sstevel@tonic-gate 	 * this mirror.  Then the master executes the IOC_DETACH ioctl
16670Sstevel@tonic-gate 	 * which resumes writes to this mirror from the master node.
16680Sstevel@tonic-gate 	 * As each slave executes the detach command, each slave will
16690Sstevel@tonic-gate 	 * call the IOC_DETACH ioctl which will resume writes to this mirror
16700Sstevel@tonic-gate 	 * from that slave node.
16710Sstevel@tonic-gate 	 */
16720Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
16730Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
16740Sstevel@tonic-gate 			return (-1);
16750Sstevel@tonic-gate 		if ((MD_MNSET_DESC(sd)) && sd->sd_mn_am_i_master)
16760Sstevel@tonic-gate 			if (meta_mn_send_suspend_writes(
16770Sstevel@tonic-gate 			    meta_getminor(mirnp->dev), ep) != 0)
16780Sstevel@tonic-gate 				return (-1);
16790Sstevel@tonic-gate 	}
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 	/* detach submirror */
16820Sstevel@tonic-gate 	(void) memset(&detach, 0, sizeof (detach));
16830Sstevel@tonic-gate 	detach.mnum = meta_getminor(mirnp->dev);
16840Sstevel@tonic-gate 	MD_SETDRIVERNAME(&detach, MD_MIRROR, sp->setno);
16850Sstevel@tonic-gate 	detach.submirror = submirnp->dev;
16860Sstevel@tonic-gate 	detach.force_detach = force;
16870Sstevel@tonic-gate 	if (metaioctl(MD_IOCDETACH, &detach, &detach.mde, NULL) != 0)
16880Sstevel@tonic-gate 		return (mdstealerror(ep, &detach.mde));
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	/* clear cache */
16910Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
16920Sstevel@tonic-gate 	meta_invalidate_name(submirnp);
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 	/* let em know */
16950Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
16960Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
16970Sstevel@tonic-gate 		    "%s: submirror %s is detached\n"),
16980Sstevel@tonic-gate 		    mirnp->cname, submirnp->cname);
16990Sstevel@tonic-gate 		(void) fflush(stdout);
17000Sstevel@tonic-gate 	}
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 	/* return success */
17030Sstevel@tonic-gate 	return (0);
17040Sstevel@tonic-gate }
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate /*
17070Sstevel@tonic-gate  * get mirror parameters
17080Sstevel@tonic-gate  */
17090Sstevel@tonic-gate int
meta_mirror_get_params(mdsetname_t * sp,mdname_t * mirnp,mm_params_t * paramsp,md_error_t * ep)17100Sstevel@tonic-gate meta_mirror_get_params(
17110Sstevel@tonic-gate 	mdsetname_t	*sp,
17120Sstevel@tonic-gate 	mdname_t	*mirnp,
17130Sstevel@tonic-gate 	mm_params_t	*paramsp,
17140Sstevel@tonic-gate 	md_error_t	*ep
17150Sstevel@tonic-gate )
17160Sstevel@tonic-gate {
17170Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	/* should have a set */
17200Sstevel@tonic-gate 	assert(sp != NULL);
17210Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	/* check name */
17240Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
17250Sstevel@tonic-gate 		return (-1);
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	/* get unit */
17280Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
17290Sstevel@tonic-gate 		return (-1);
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	/* return parameters */
17320Sstevel@tonic-gate 	(void) memset(paramsp, 0, sizeof (*paramsp));
17330Sstevel@tonic-gate 	paramsp->read_option = mirrorp->read_option;
17340Sstevel@tonic-gate 	paramsp->write_option = mirrorp->write_option;
17350Sstevel@tonic-gate 	paramsp->pass_num = mirrorp->pass_num;
17360Sstevel@tonic-gate 	return (0);
17370Sstevel@tonic-gate }
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate /*
17400Sstevel@tonic-gate  * set mirror parameters
17410Sstevel@tonic-gate  */
17420Sstevel@tonic-gate int
meta_mirror_set_params(mdsetname_t * sp,mdname_t * mirnp,mm_params_t * paramsp,md_error_t * ep)17430Sstevel@tonic-gate meta_mirror_set_params(
17440Sstevel@tonic-gate 	mdsetname_t		*sp,
17450Sstevel@tonic-gate 	mdname_t		*mirnp,
17460Sstevel@tonic-gate 	mm_params_t		*paramsp,
17470Sstevel@tonic-gate 	md_error_t		*ep
17480Sstevel@tonic-gate )
17490Sstevel@tonic-gate {
17500Sstevel@tonic-gate 	md_mirror_params_t	mmp;
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 	/* should have a set */
17530Sstevel@tonic-gate 	assert(sp != NULL);
17540Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 	/* check name */
17570Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
17580Sstevel@tonic-gate 		return (-1);
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	/* set parameters */
17610Sstevel@tonic-gate 	(void) memset(&mmp, 0, sizeof (mmp));
17620Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mmp, MD_MIRROR, sp->setno);
17630Sstevel@tonic-gate 	mmp.mnum = meta_getminor(mirnp->dev);
17640Sstevel@tonic-gate 	mmp.params = *paramsp;
17650Sstevel@tonic-gate 	if (metaioctl(MD_IOCCHANGE, &mmp, &mmp.mde, mirnp->cname) != 0)
17660Sstevel@tonic-gate 		return (mdstealerror(ep, &mmp.mde));
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	/* clear cache */
17690Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	/* return success */
17720Sstevel@tonic-gate 	return (0);
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate /*
17760Sstevel@tonic-gate  * invalidate submirror names
17770Sstevel@tonic-gate  */
17780Sstevel@tonic-gate static int
invalidate_submirrors(mdsetname_t * sp,mdname_t * mirnp,md_error_t * ep)17790Sstevel@tonic-gate invalidate_submirrors(
17800Sstevel@tonic-gate 	mdsetname_t	*sp,
17810Sstevel@tonic-gate 	mdname_t	*mirnp,
17820Sstevel@tonic-gate 	md_error_t	*ep
17830Sstevel@tonic-gate )
17840Sstevel@tonic-gate {
17850Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
17860Sstevel@tonic-gate 	uint_t		smi;
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
17890Sstevel@tonic-gate 		return (-1);
17900Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
17910Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
17920Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 		if (submirnp == NULL) {
17950Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
17960Sstevel@tonic-gate 			continue;
17970Sstevel@tonic-gate 		}
17980Sstevel@tonic-gate 		meta_invalidate_name(submirnp);
17990Sstevel@tonic-gate 	}
18000Sstevel@tonic-gate 	return (0);
18010Sstevel@tonic-gate }
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate /*
18040Sstevel@tonic-gate  * replace mirror component
18050Sstevel@tonic-gate  */
18060Sstevel@tonic-gate int
meta_mirror_replace(mdsetname_t * sp,mdname_t * mirnp,mdname_t * oldnp,mdname_t * newnp,mdcmdopts_t options,md_error_t * ep)18070Sstevel@tonic-gate meta_mirror_replace(
18080Sstevel@tonic-gate 	mdsetname_t		*sp,
18090Sstevel@tonic-gate 	mdname_t		*mirnp,
18100Sstevel@tonic-gate 	mdname_t		*oldnp,
18110Sstevel@tonic-gate 	mdname_t		*newnp,
18120Sstevel@tonic-gate 	mdcmdopts_t		options,
18130Sstevel@tonic-gate 	md_error_t		*ep
18140Sstevel@tonic-gate )
18150Sstevel@tonic-gate {
18160Sstevel@tonic-gate 	md_mirror_t		*mirrorp;
18170Sstevel@tonic-gate 	uint_t			smi;
18180Sstevel@tonic-gate 	replace_params_t	params;
18190Sstevel@tonic-gate 	diskaddr_t		size, label, start_blk;
18200Sstevel@tonic-gate 	md_dev64_t		old_dev, new_dev;
18210Sstevel@tonic-gate 	diskaddr_t		new_start_blk, new_end_blk;
18220Sstevel@tonic-gate 	int			rebind;
18230Sstevel@tonic-gate 	md_set_desc		*sd;
18240Sstevel@tonic-gate 	char			*new_devidp = NULL;
18250Sstevel@tonic-gate 	int			ret;
18260Sstevel@tonic-gate 	md_error_t		xep = mdnullerror;
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 	/* should have same set */
18290Sstevel@tonic-gate 	assert(sp != NULL);
18300Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 	/* check name */
18330Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
18340Sstevel@tonic-gate 		return (-1);
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 	/* save new binding incase this is a rebind where oldnp==newnp */
18370Sstevel@tonic-gate 	new_dev = newnp->dev;
18380Sstevel@tonic-gate 	new_start_blk = newnp->start_blk;
18390Sstevel@tonic-gate 	new_end_blk = newnp->end_blk;
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 	/* invalidate, then get the mirror (fill in oldnp from metadb) */
18420Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
18430Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
18440Sstevel@tonic-gate 		return (-1);
18450Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
18460Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
18470Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 		if (submirnp == NULL) {
18500Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
18510Sstevel@tonic-gate 			continue;
18520Sstevel@tonic-gate 		}
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 		if (! metaismeta(submirnp))
18550Sstevel@tonic-gate 			continue;
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 		meta_invalidate_name(submirnp);
18580Sstevel@tonic-gate 		if (meta_get_unit(sp, submirnp, ep) == NULL)
18590Sstevel@tonic-gate 			return (-1);
18600Sstevel@tonic-gate 	}
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	/* the old device binding is now established */
18630Sstevel@tonic-gate 	if ((old_dev = oldnp->dev) == NODEV64)
18640Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, oldnp->cname));
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	/*
18670Sstevel@tonic-gate 	 * check for the case where oldnp and newnp indicate the same
18680Sstevel@tonic-gate 	 * device, but the dev_t of the device has changed between old
18690Sstevel@tonic-gate 	 * and new.  This is called a rebind.  On entry the dev_t
18700Sstevel@tonic-gate 	 * represents the new device binding determined from the
18710Sstevel@tonic-gate 	 * filesystem (meta_getdev). After calling meta_get_unit
18720Sstevel@tonic-gate 	 * oldnp (and maybe newnp if this is a rebind) is updated based
18730Sstevel@tonic-gate 	 * to the old binding from the metadb (done by metakeyname).
18740Sstevel@tonic-gate 	 */
18750Sstevel@tonic-gate 	if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
18760Sstevel@tonic-gate 	    (old_dev != new_dev)) {
18770Sstevel@tonic-gate 		rebind = 1;
18780Sstevel@tonic-gate 	} else {
18790Sstevel@tonic-gate 		rebind = 0;
18800Sstevel@tonic-gate 	}
18810Sstevel@tonic-gate 	if (rebind) {
18820Sstevel@tonic-gate 		newnp->dev = new_dev;
18830Sstevel@tonic-gate 		newnp->start_blk = new_start_blk;
18840Sstevel@tonic-gate 		newnp->end_blk = new_end_blk;
18850Sstevel@tonic-gate 	}
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	/*
18880Sstevel@tonic-gate 	 * Save a copy of the devid associated with the new disk, the reason
18890Sstevel@tonic-gate 	 * is that if we are rebinding then the call to meta_check_component()
18900Sstevel@tonic-gate 	 * will cause the devid of the disk to be overwritten with what is in
18910Sstevel@tonic-gate 	 * the replica namespace. The function that actually overwrites the
18920Sstevel@tonic-gate 	 * devid is dr2drivedesc().
18930Sstevel@tonic-gate 	 */
18940Sstevel@tonic-gate 	if (newnp->drivenamep->devid != NULL)
18950Sstevel@tonic-gate 		new_devidp = Strdup(newnp->drivenamep->devid);
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 	/* if it's a multi-node diskset clear new_devidp */
18980Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
18990Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
19000Sstevel@tonic-gate 			return (-1);
19010Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd))
19020Sstevel@tonic-gate 			new_devidp = NULL;
19030Sstevel@tonic-gate 	}
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 	/* check it out (dup on rebind is ok) */
19060Sstevel@tonic-gate 	if (meta_check_component(sp, newnp, 0, ep) != 0) {
19070Sstevel@tonic-gate 		if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
19080Sstevel@tonic-gate 			Free(new_devidp);
19090Sstevel@tonic-gate 			return (-1);
19100Sstevel@tonic-gate 		}
19110Sstevel@tonic-gate 		mdclrerror(ep);
19120Sstevel@tonic-gate 	}
19130Sstevel@tonic-gate 	if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
19140Sstevel@tonic-gate 		Free(new_devidp);
19150Sstevel@tonic-gate 		return (-1);
19160Sstevel@tonic-gate 	}
19170Sstevel@tonic-gate 	if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
19180Sstevel@tonic-gate 		Free(new_devidp);
19190Sstevel@tonic-gate 		return (-1);
19200Sstevel@tonic-gate 	}
19210Sstevel@tonic-gate 	if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
19220Sstevel@tonic-gate 		Free(new_devidp);
19230Sstevel@tonic-gate 		return (-1);
19240Sstevel@tonic-gate 	}
19250Sstevel@tonic-gate 	if (start_blk >= size) {
19260Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, newnp->cname);
19270Sstevel@tonic-gate 		Free(new_devidp);
19280Sstevel@tonic-gate 		return (-1);
19290Sstevel@tonic-gate 	}
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	/*
19320Sstevel@tonic-gate 	 * Copy back the saved devid.
19330Sstevel@tonic-gate 	 */
19340Sstevel@tonic-gate 	Free(newnp->drivenamep->devid);
19350Sstevel@tonic-gate 	if (new_devidp != NULL) {
19360Sstevel@tonic-gate 		newnp->drivenamep->devid = Strdup(new_devidp);
19370Sstevel@tonic-gate 		Free(new_devidp);
19380Sstevel@tonic-gate 	}
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate 	/* store name in namespace, allocate new key */
19410Sstevel@tonic-gate 	if (add_key_name(sp, newnp, NULL, ep) != 0)
19420Sstevel@tonic-gate 		return (-1);
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	/*
19450Sstevel@tonic-gate 	 * In a MN set, the master always executes the replace command first.
19460Sstevel@tonic-gate 	 * Before the master executes the IOC_REPLACE ioctl, in non-DRYRUN mode
19470Sstevel@tonic-gate 	 * the master sends a message to all nodes to suspend writes to
19480Sstevel@tonic-gate 	 * this mirror.  Then the master executes the IOC_REPLACE ioctl
19490Sstevel@tonic-gate 	 * which resumes writes to this mirror from the master node.
19500Sstevel@tonic-gate 	 * As each slave executes the replace command, each slave will
19510Sstevel@tonic-gate 	 * call the IOC_REPLACE ioctl which will resume writes to this mirror
19520Sstevel@tonic-gate 	 * from that slave node.
19530Sstevel@tonic-gate 	 */
19540Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
19550Sstevel@tonic-gate 		if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
19560Sstevel@tonic-gate 		    sd->sd_mn_am_i_master)
19570Sstevel@tonic-gate 			if (meta_mn_send_suspend_writes(
19580Sstevel@tonic-gate 			    meta_getminor(mirnp->dev), ep) != 0)
19590Sstevel@tonic-gate 				return (-1);
19600Sstevel@tonic-gate 	}
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 	if (rebind && !metaislocalset(sp)) {
19630Sstevel@tonic-gate 		/*
19640Sstevel@tonic-gate 		 * We are 'rebind'ing a disk that is in a diskset so as well
19650Sstevel@tonic-gate 		 * as updating the diskset's namespace the local set needs
19660Sstevel@tonic-gate 		 * to be updated because it also contains a reference to
19670Sstevel@tonic-gate 		 * the disk in question.
19680Sstevel@tonic-gate 		 */
19690Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
19700Sstevel@tonic-gate 		    newnp->cname, ep);
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
19730Sstevel@tonic-gate 			(void) del_key_name(sp, newnp, &xep);
19740Sstevel@tonic-gate 			return (-1);
19750Sstevel@tonic-gate 		}
19760Sstevel@tonic-gate 	}
19770Sstevel@tonic-gate 
19780Sstevel@tonic-gate 	/* replace component */
19790Sstevel@tonic-gate 	(void) memset(&params, 0, sizeof (params));
19800Sstevel@tonic-gate 	params.mnum = meta_getminor(mirnp->dev);
19810Sstevel@tonic-gate 	MD_SETDRIVERNAME(&params, MD_MIRROR, sp->setno);
19820Sstevel@tonic-gate 	params.cmd = REPLACE_COMP;
19830Sstevel@tonic-gate 	params.old_dev = old_dev;
19840Sstevel@tonic-gate 	params.new_dev = new_dev;
19850Sstevel@tonic-gate 	params.start_blk = start_blk;
19860Sstevel@tonic-gate 	params.has_label = ((label > 0) ? 1 : 0);
19870Sstevel@tonic-gate 	params.number_blks = size;
19880Sstevel@tonic-gate 	params.new_key = newnp->key;
19890Sstevel@tonic-gate 	/* Is this just a dryrun ? */
19900Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
19910Sstevel@tonic-gate 		params.options |= MDIOCTL_DRYRUN;
19920Sstevel@tonic-gate 	}
19930Sstevel@tonic-gate 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0) {
19940Sstevel@tonic-gate 		(void) del_key_name(sp, newnp, ep);
19950Sstevel@tonic-gate 		return (mdstealerror(ep, &params.mde));
19960Sstevel@tonic-gate 	}
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate 	/* clear cache */
19990Sstevel@tonic-gate 	meta_invalidate_name(oldnp);
20000Sstevel@tonic-gate 	meta_invalidate_name(newnp);
20010Sstevel@tonic-gate 	if (invalidate_submirrors(sp, mirnp, ep) != 0) {
20020Sstevel@tonic-gate 		meta_invalidate_name(mirnp);
20030Sstevel@tonic-gate 		return (-1);
20040Sstevel@tonic-gate 	}
20050Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate 	/* let em know */
20080Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
20090Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
20100Sstevel@tonic-gate 		    "%s: device %s is replaced with %s\n"),
20110Sstevel@tonic-gate 		    mirnp->cname, oldnp->cname, newnp->cname);
20120Sstevel@tonic-gate 		(void) fflush(stdout);
20130Sstevel@tonic-gate 	}
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	/* return success */
20160Sstevel@tonic-gate 	return (0);
20170Sstevel@tonic-gate }
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate /*
20200Sstevel@tonic-gate  * enable mirror component
20210Sstevel@tonic-gate  */
20220Sstevel@tonic-gate int
meta_mirror_enable(mdsetname_t * sp,mdname_t * mirnp,mdname_t * compnp,mdcmdopts_t options,md_error_t * ep)20230Sstevel@tonic-gate meta_mirror_enable(
20240Sstevel@tonic-gate 	mdsetname_t		*sp,
20250Sstevel@tonic-gate 	mdname_t		*mirnp,
20260Sstevel@tonic-gate 	mdname_t		*compnp,
20270Sstevel@tonic-gate 	mdcmdopts_t		options,
20280Sstevel@tonic-gate 	md_error_t		*ep
20290Sstevel@tonic-gate )
20300Sstevel@tonic-gate {
20310Sstevel@tonic-gate 	md_mirror_t		*mirrorp;
20320Sstevel@tonic-gate 	uint_t			smi;
20330Sstevel@tonic-gate 	replace_params_t	params;
20340Sstevel@tonic-gate 	diskaddr_t		size, label, start_blk;
20350Sstevel@tonic-gate 	md_dev64_t		fs_dev;
20360Sstevel@tonic-gate 	md_set_desc		*sd;
20370Sstevel@tonic-gate 	int			ret;
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 	/* should have same set */
20400Sstevel@tonic-gate 	assert(sp != NULL);
20410Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate 	/* check name */
20440Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
20450Sstevel@tonic-gate 		return (-1);
20460Sstevel@tonic-gate 
20470Sstevel@tonic-gate 	/* get the file_system dev binding */
20480Sstevel@tonic-gate 	if (meta_getdev(sp, compnp, ep) != 0)
20490Sstevel@tonic-gate 		return (-1);
20500Sstevel@tonic-gate 	fs_dev = compnp->dev;
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	/* get the mirror unit (fill in compnp->dev with metadb version) */
20530Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
20540Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
20550Sstevel@tonic-gate 		return (-1);
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
20580Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
20590Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 		if (submirnp == NULL) {
20620Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
20630Sstevel@tonic-gate 			continue;
20640Sstevel@tonic-gate 		}
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate 		if (! metaismeta(submirnp))
20670Sstevel@tonic-gate 			continue;
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 		meta_invalidate_name(submirnp);
20700Sstevel@tonic-gate 		if (meta_get_unit(sp, submirnp, ep) == NULL)
20710Sstevel@tonic-gate 			return (-1);
20720Sstevel@tonic-gate 	}
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate 	/* the metadb device binding is now established */
20750Sstevel@tonic-gate 	if (compnp->dev == NODEV64)
20760Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, compnp->cname));
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	/*
20790Sstevel@tonic-gate 	 * check for the case where the dev_t has changed between the
20800Sstevel@tonic-gate 	 * filesystem and the metadb.  This is called a rebind, and
20810Sstevel@tonic-gate 	 * is handled by meta_mirror_replace.
20820Sstevel@tonic-gate 	 */
20830Sstevel@tonic-gate 	if (fs_dev != compnp->dev) {
20840Sstevel@tonic-gate 		/* establish file system binding with invalid start/end */
20850Sstevel@tonic-gate 		compnp->dev = fs_dev;
20860Sstevel@tonic-gate 		compnp->start_blk = -1;
20870Sstevel@tonic-gate 		compnp->end_blk = -1;
20880Sstevel@tonic-gate 		return (meta_mirror_replace(sp, mirnp,
20890Sstevel@tonic-gate 		    compnp, compnp, options, ep));
20900Sstevel@tonic-gate 	}
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate 	/* setup mirror info */
20930Sstevel@tonic-gate 	(void) memset(&params, 0, sizeof (params));
20940Sstevel@tonic-gate 	params.mnum = meta_getminor(mirnp->dev);
20950Sstevel@tonic-gate 	MD_SETDRIVERNAME(&params, MD_MIRROR, sp->setno);
20960Sstevel@tonic-gate 	params.cmd = ENABLE_COMP;
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate 	/* check it out */
20990Sstevel@tonic-gate 	if (meta_check_component(sp, compnp, 0, ep) != 0) {
21000Sstevel@tonic-gate 		if (! mdisuseerror(ep, MDE_ALREADY))
21010Sstevel@tonic-gate 			return (-1);
21020Sstevel@tonic-gate 		mdclrerror(ep);
21030Sstevel@tonic-gate 	}
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 	if ((size = metagetsize(compnp, ep)) == MD_DISKADDR_ERROR)
21060Sstevel@tonic-gate 		return (-1);
21070Sstevel@tonic-gate 	if ((label = metagetlabel(compnp, ep)) == MD_DISKADDR_ERROR)
21080Sstevel@tonic-gate 		return (-1);
21090Sstevel@tonic-gate 	if ((start_blk = metagetstart(sp, compnp, ep)) == MD_DISKADDR_ERROR)
21100Sstevel@tonic-gate 		return (-1);
21110Sstevel@tonic-gate 	if (start_blk >= size) {
21120Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, compnp->cname);
21130Sstevel@tonic-gate 		return (-1);
21140Sstevel@tonic-gate 	}
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate 	/*
21170Sstevel@tonic-gate 	 * In a MN set, the master always executes the replace command first.
21180Sstevel@tonic-gate 	 * Before the master executes the IOC_REPLACE ioctl, in non-DRYRUN mode
21190Sstevel@tonic-gate 	 * the master sends a message to all nodes to suspend writes to
21200Sstevel@tonic-gate 	 * this mirror.  Then the master executes the IOC_REPLACE ioctl
21210Sstevel@tonic-gate 	 * which resumes writes to this mirror from the master node.
21220Sstevel@tonic-gate 	 * As each slave executes the replace command, each slave will
21230Sstevel@tonic-gate 	 * call the IOC_REPLACE ioctl which will resume writes to this mirror
21240Sstevel@tonic-gate 	 * from that slave node.
21250Sstevel@tonic-gate 	 */
21260Sstevel@tonic-gate 	if (! metaislocalset(sp)) {
21270Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
21280Sstevel@tonic-gate 			return (-1);
21290Sstevel@tonic-gate 		if ((MD_MNSET_DESC(sd)) && (options & MDCMD_DOIT) &&
21300Sstevel@tonic-gate 		    sd->sd_mn_am_i_master)
21310Sstevel@tonic-gate 			if (meta_mn_send_suspend_writes(
21320Sstevel@tonic-gate 			    meta_getminor(mirnp->dev), ep) != 0)
21330Sstevel@tonic-gate 				return (-1);
21340Sstevel@tonic-gate 	}
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate 	/* enable component */
21370Sstevel@tonic-gate 	params.old_dev = compnp->dev;
21380Sstevel@tonic-gate 	params.new_dev = compnp->dev;
21390Sstevel@tonic-gate 	params.start_blk = start_blk;
21400Sstevel@tonic-gate 	params.has_label = ((label > 0) ? 1 : 0);
21410Sstevel@tonic-gate 	params.number_blks = size;
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 	/* Is this just a dryrun ? */
21440Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
21450Sstevel@tonic-gate 		params.options |= MDIOCTL_DRYRUN;
21460Sstevel@tonic-gate 	}
21470Sstevel@tonic-gate 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0)
21480Sstevel@tonic-gate 		return (mdstealerror(ep, &params.mde));
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 	/*
21510Sstevel@tonic-gate 	 * Are we dealing with a non-local set? If so need to update the
21520Sstevel@tonic-gate 	 * local namespace so that the disk record has the correct devid.
21530Sstevel@tonic-gate 	 */
21540Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
21550Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, compnp->cname,
21560Sstevel@tonic-gate 		    ep);
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
21590Sstevel@tonic-gate 			/*
21600Sstevel@tonic-gate 			 * Failed to update the local set. Nothing to do here
21610Sstevel@tonic-gate 			 * apart from report the error. The namespace is
21620Sstevel@tonic-gate 			 * most likely broken and some form of remedial
21630Sstevel@tonic-gate 			 * recovery is going to be required.
21640Sstevel@tonic-gate 			 */
21650Sstevel@tonic-gate 			mde_perror(ep, "");
21660Sstevel@tonic-gate 			mdclrerror(ep);
21670Sstevel@tonic-gate 		}
21680Sstevel@tonic-gate 	}
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 	/* clear cache */
21710Sstevel@tonic-gate 	meta_invalidate_name(compnp);
21720Sstevel@tonic-gate 	if (invalidate_submirrors(sp, mirnp, ep) != 0) {
21730Sstevel@tonic-gate 		meta_invalidate_name(mirnp);
21740Sstevel@tonic-gate 		return (-1);
21750Sstevel@tonic-gate 	}
21760Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 	/* let em know */
21790Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
21800Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
21810Sstevel@tonic-gate 		    "%s: device %s is enabled\n"),
21820Sstevel@tonic-gate 		    mirnp->cname, compnp->cname);
21830Sstevel@tonic-gate 		(void) fflush(stdout);
21840Sstevel@tonic-gate 	}
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 	/* return success */
21870Sstevel@tonic-gate 	return (0);
21880Sstevel@tonic-gate }
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate /*
21910Sstevel@tonic-gate  * check for dups in the mirror itself
21920Sstevel@tonic-gate  */
21930Sstevel@tonic-gate static int
check_twice(md_mirror_t * mirrorp,uint_t smi,md_error_t * ep)21940Sstevel@tonic-gate check_twice(
21950Sstevel@tonic-gate 	md_mirror_t	*mirrorp,
21960Sstevel@tonic-gate 	uint_t		smi,
21970Sstevel@tonic-gate 	md_error_t	*ep
21980Sstevel@tonic-gate )
21990Sstevel@tonic-gate {
22000Sstevel@tonic-gate 	mdname_t	*mirnp = mirrorp->common.namep;
22010Sstevel@tonic-gate 	mdname_t	*thisnp;
22020Sstevel@tonic-gate 	uint_t		s;
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 	thisnp = mirrorp->submirrors[smi].submirnamep;
22050Sstevel@tonic-gate 	for (s = 0; (s < smi); ++s) {
22060Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[s];
22070Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 		if (submirnp == NULL)
22100Sstevel@tonic-gate 			continue;
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 		if (meta_check_overlap(mirnp->cname, thisnp, 0, -1,
22130Sstevel@tonic-gate 		    submirnp, 0, -1, ep) != 0) {
22140Sstevel@tonic-gate 			return (-1);
22150Sstevel@tonic-gate 		}
22160Sstevel@tonic-gate 	}
22170Sstevel@tonic-gate 	return (0);
22180Sstevel@tonic-gate }
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate /*
22210Sstevel@tonic-gate  * check mirror
22220Sstevel@tonic-gate  */
22230Sstevel@tonic-gate int
meta_check_mirror(mdsetname_t * sp,md_mirror_t * mirrorp,mdcmdopts_t options,md_error_t * ep)22240Sstevel@tonic-gate meta_check_mirror(
22250Sstevel@tonic-gate 	mdsetname_t	*sp,
22260Sstevel@tonic-gate 	md_mirror_t	*mirrorp,
22270Sstevel@tonic-gate 	mdcmdopts_t	options,
22280Sstevel@tonic-gate 	md_error_t	*ep
22290Sstevel@tonic-gate )
22300Sstevel@tonic-gate {
22310Sstevel@tonic-gate 	mdname_t	*mirnp = mirrorp->common.namep;
22320Sstevel@tonic-gate 	int		force = ((options & MDCMD_FORCE) ? 1 : 0);
22330Sstevel@tonic-gate 	int		doit = ((options & MDCMD_DOIT) ? 1 : 0);
22340Sstevel@tonic-gate 	uint_t		nsm = 0;
22350Sstevel@tonic-gate 	uint_t		smi;
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 	/* check submirrors */
22380Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
22390Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
22400Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 		if (submirnp == NULL)
22430Sstevel@tonic-gate 			continue;
22440Sstevel@tonic-gate 		++nsm;
22450Sstevel@tonic-gate 	}
22460Sstevel@tonic-gate 	if (nsm < 1) {
22470Sstevel@tonic-gate 		return (mdmderror(ep, MDE_BAD_MIRROR,
22480Sstevel@tonic-gate 		    meta_getminor(mirnp->dev), mirnp->cname));
22490Sstevel@tonic-gate 	}
22500Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
22510Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
22520Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
22530Sstevel@tonic-gate 		diskaddr_t	size;
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 		/* skip unused submirrors */
22560Sstevel@tonic-gate 		if (submirnp == NULL) {
22570Sstevel@tonic-gate 			if (mdsp->state != SMS_UNUSED) {
22580Sstevel@tonic-gate 				return (mdmderror(ep, MDE_BAD_MIRROR,
22590Sstevel@tonic-gate 				    meta_getminor(mirnp->dev), mirnp->cname));
22600Sstevel@tonic-gate 			}
22610Sstevel@tonic-gate 			continue;
22620Sstevel@tonic-gate 		}
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 		/* check submirror */
22650Sstevel@tonic-gate 		if (doit) {
22660Sstevel@tonic-gate 			if (meta_check_submirror(sp, submirnp, NULL, force,
22670Sstevel@tonic-gate 			    ep) != 0)
22680Sstevel@tonic-gate 				return (-1);
22690Sstevel@tonic-gate 			if ((size = metagetsize(submirnp, ep)) ==
22700Sstevel@tonic-gate 			    MD_DISKADDR_ERROR) {
22710Sstevel@tonic-gate 				return (-1);
22720Sstevel@tonic-gate 			} else if (size == 0) {
22730Sstevel@tonic-gate 				return (mdsyserror(ep, ENOSPC,
22740Sstevel@tonic-gate 					submirnp->cname));
22750Sstevel@tonic-gate 			}
22760Sstevel@tonic-gate 		}
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 		/* check this mirror too */
22790Sstevel@tonic-gate 		if (check_twice(mirrorp, smi, ep) != 0)
22800Sstevel@tonic-gate 			return (-1);
22810Sstevel@tonic-gate 	}
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 	/* check read option */
22840Sstevel@tonic-gate 	switch (mirrorp->read_option) {
22850Sstevel@tonic-gate 	case RD_LOAD_BAL:
22860Sstevel@tonic-gate 	case RD_GEOMETRY:
22870Sstevel@tonic-gate 	case RD_FIRST:
22880Sstevel@tonic-gate 		break;
22890Sstevel@tonic-gate 	default:
22900Sstevel@tonic-gate 		return (mderror(ep, MDE_BAD_RD_OPT, mirnp->cname));
22910Sstevel@tonic-gate 	}
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 	/* check write option */
22940Sstevel@tonic-gate 	switch (mirrorp->write_option) {
22950Sstevel@tonic-gate 	case WR_PARALLEL:
22960Sstevel@tonic-gate 	case WR_SERIAL:
22970Sstevel@tonic-gate 		break;
22980Sstevel@tonic-gate 	default:
22990Sstevel@tonic-gate 		return (mderror(ep, MDE_BAD_WR_OPT, mirnp->cname));
23000Sstevel@tonic-gate 	}
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 	/* check pass number */
23030Sstevel@tonic-gate 	if ((mirrorp->pass_num < 0) || (mirrorp->pass_num > MD_PASS_MAX))
23040Sstevel@tonic-gate 		return (mderror(ep, MDE_BAD_PASS_NUM, mirnp->cname));
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate 	/* return success */
23070Sstevel@tonic-gate 	return (0);
23080Sstevel@tonic-gate }
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate /*
23110Sstevel@tonic-gate  * setup mirror geometry
23120Sstevel@tonic-gate  */
23130Sstevel@tonic-gate static int
mirror_geom(md_mirror_t * mirrorp,mm_unit_t * mm,md_error_t * ep)23140Sstevel@tonic-gate mirror_geom(
23150Sstevel@tonic-gate 	md_mirror_t	*mirrorp,
23160Sstevel@tonic-gate 	mm_unit_t	*mm,
23170Sstevel@tonic-gate 	md_error_t	*ep
23180Sstevel@tonic-gate )
23190Sstevel@tonic-gate {
23200Sstevel@tonic-gate 	uint_t		write_reinstruct = 0;
23210Sstevel@tonic-gate 	uint_t		read_reinstruct = 0;
23220Sstevel@tonic-gate 	uint_t		round_cyl = 1;
23230Sstevel@tonic-gate 	mdname_t	*smnp = NULL;
23240Sstevel@tonic-gate 	uint_t		smi;
23250Sstevel@tonic-gate 	mdgeom_t	*geomp;
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 	/* get worst reinstructs */
23280Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
23290Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
23300Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 		if (submirnp == NULL)
23330Sstevel@tonic-gate 			continue;
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate 		if ((geomp = metagetgeom(submirnp, ep)) == NULL)
23360Sstevel@tonic-gate 			return (-1);
23370Sstevel@tonic-gate 		if (geomp->write_reinstruct > write_reinstruct)
23380Sstevel@tonic-gate 			write_reinstruct = geomp->write_reinstruct;
23390Sstevel@tonic-gate 		if (geomp->read_reinstruct > read_reinstruct)
23400Sstevel@tonic-gate 			read_reinstruct = geomp->read_reinstruct;
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 		if (smnp == NULL)
23430Sstevel@tonic-gate 			smnp = submirnp;
23440Sstevel@tonic-gate 	}
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate 	/* setup geometry from first submirror */
23470Sstevel@tonic-gate 	assert(smnp != NULL);
23480Sstevel@tonic-gate 	if ((geomp = metagetgeom(smnp, ep)) == NULL)
23490Sstevel@tonic-gate 		return (-1);
23500Sstevel@tonic-gate 	if (meta_setup_geom((md_unit_t *)mm, mirrorp->common.namep, geomp,
23510Sstevel@tonic-gate 	    write_reinstruct, read_reinstruct, round_cyl, ep) != 0)
23520Sstevel@tonic-gate 		return (-1);
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 	/* return success */
23550Sstevel@tonic-gate 	return (0);
23560Sstevel@tonic-gate }
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate /*
23590Sstevel@tonic-gate  * create mirror
23600Sstevel@tonic-gate  */
23610Sstevel@tonic-gate int
meta_create_mirror(mdsetname_t * sp,md_mirror_t * mirrorp,mdcmdopts_t options,md_error_t * ep)23620Sstevel@tonic-gate meta_create_mirror(
23630Sstevel@tonic-gate 	mdsetname_t	*sp,
23640Sstevel@tonic-gate 	md_mirror_t	*mirrorp,
23650Sstevel@tonic-gate 	mdcmdopts_t	options,
23660Sstevel@tonic-gate 	md_error_t	*ep
23670Sstevel@tonic-gate )
23680Sstevel@tonic-gate {
23690Sstevel@tonic-gate 	mdname_t	*mirnp = mirrorp->common.namep;
23700Sstevel@tonic-gate 	mm_unit_t	*mm;
23710Sstevel@tonic-gate 	diskaddr_t	submir_size = MD_DISKADDR_ERROR;
23720Sstevel@tonic-gate 	ushort_t	nsm = 0;
23730Sstevel@tonic-gate 	uint_t		smi;
23740Sstevel@tonic-gate 	mdnamelist_t	*keynlp = NULL;
23750Sstevel@tonic-gate 	md_set_params_t	set_params;
23760Sstevel@tonic-gate 	int		rval = -1;
23770Sstevel@tonic-gate 	md_timeval32_t	creation_time;
23780Sstevel@tonic-gate 	int		create_flag = MD_CRO_32BIT;
23790Sstevel@tonic-gate 
23800Sstevel@tonic-gate 	/* validate mirror */
23810Sstevel@tonic-gate 	if (meta_check_mirror(sp, mirrorp, options, ep) != 0)
23820Sstevel@tonic-gate 		return (-1);
23830Sstevel@tonic-gate 
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 	/* allocate mirror unit */
23860Sstevel@tonic-gate 	mm = Zalloc(sizeof (*mm));
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 	if (meta_gettimeofday(&creation_time) == -1)
23890Sstevel@tonic-gate 		return (mdsyserror(ep, errno, NULL));
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate 	/* do submirrors */
23920Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
23930Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
23940Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
23950Sstevel@tonic-gate 		mm_submirror_t	*mmsp = &mm->un_sm[smi];
23960Sstevel@tonic-gate 		diskaddr_t	size;
23970Sstevel@tonic-gate 
23980Sstevel@tonic-gate 		/* skip unused submirrors */
23990Sstevel@tonic-gate 		if (submirnp == NULL) {
24000Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
24010Sstevel@tonic-gate 			continue;
24020Sstevel@tonic-gate 		}
24030Sstevel@tonic-gate 		++nsm;
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate 		/* get size */
24060Sstevel@tonic-gate 		if ((size = metagetsize(submirnp, ep)) == MD_DISKADDR_ERROR)
24070Sstevel@tonic-gate 			goto out;
24080Sstevel@tonic-gate 		assert(size > 0);
24090Sstevel@tonic-gate 
24100Sstevel@tonic-gate 		/* adjust for smallest submirror */
24110Sstevel@tonic-gate 		if (submir_size == MD_DISKADDR_ERROR) {
24120Sstevel@tonic-gate 			submir_size = size;
24130Sstevel@tonic-gate 		} else if (size < submir_size) {
24140Sstevel@tonic-gate 			submir_size = size;
24150Sstevel@tonic-gate 		}
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
24180Sstevel@tonic-gate 			/* store name in namespace */
24190Sstevel@tonic-gate 			if (add_key_name(sp, submirnp, &keynlp, ep) != 0)
24200Sstevel@tonic-gate 				goto out;
24210Sstevel@tonic-gate 		}
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate 		/* setup submirror */
24240Sstevel@tonic-gate 		mmsp->sm_key = submirnp->key;
24250Sstevel@tonic-gate 		mmsp->sm_dev = submirnp->dev;
24260Sstevel@tonic-gate 		mmsp->sm_state = SMS_RUNNING;
24270Sstevel@tonic-gate 		mmsp->sm_timestamp = creation_time;
24280Sstevel@tonic-gate 	}
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate 	/* setup unit */
24310Sstevel@tonic-gate 	mm->c.un_type = MD_METAMIRROR;
24320Sstevel@tonic-gate 	MD_SID(mm) = meta_getminor(mirnp->dev);
24330Sstevel@tonic-gate 	mm->c.un_actual_tb = submir_size;
24340Sstevel@tonic-gate 	mm->c.un_size = offsetof(mm_unit_t, un_smic);
24350Sstevel@tonic-gate 	mm->un_nsm = nsm;
24360Sstevel@tonic-gate 	mm->un_read_option = mirrorp->read_option;
24370Sstevel@tonic-gate 	mm->un_write_option = mirrorp->write_option;
24380Sstevel@tonic-gate 	mm->un_pass_num = mirrorp->pass_num;
24390Sstevel@tonic-gate 	if (mirror_geom(mirrorp, mm, ep) != 0)
24400Sstevel@tonic-gate 		goto out;
24410Sstevel@tonic-gate 
24420Sstevel@tonic-gate 	/* fill in the size of the mirror */
24430Sstevel@tonic-gate 	if (options & MDCMD_UPDATE) {
24440Sstevel@tonic-gate 		mirrorp->common.size = mm->c.un_total_blocks;
24450Sstevel@tonic-gate 	}
24460Sstevel@tonic-gate 
24470Sstevel@tonic-gate 	/* if we're not doing anything, return success */
24480Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT)) {
24490Sstevel@tonic-gate 		rval = 0;	/* success */
24500Sstevel@tonic-gate 		goto out;
24510Sstevel@tonic-gate 	}
24520Sstevel@tonic-gate 
24530Sstevel@tonic-gate 	/* create mirror */
24540Sstevel@tonic-gate 	(void) memset(&set_params, 0, sizeof (set_params));
24550Sstevel@tonic-gate 	/* did the user tell us to generate a large device? */
24560Sstevel@tonic-gate 	create_flag = meta_check_devicesize(mm->c.un_total_blocks);
24570Sstevel@tonic-gate 	if (create_flag == MD_CRO_64BIT) {
24581623Stw21770 		mm->c.un_revision |= MD_64BIT_META_DEV;
24590Sstevel@tonic-gate 		set_params.options = MD_CRO_64BIT;
24600Sstevel@tonic-gate 	} else {
24611623Stw21770 		mm->c.un_revision &= ~MD_64BIT_META_DEV;
24620Sstevel@tonic-gate 		set_params.options = MD_CRO_32BIT;
24630Sstevel@tonic-gate 	}
24640Sstevel@tonic-gate 	set_params.mnum = MD_SID(mm);
24650Sstevel@tonic-gate 	set_params.size = mm->c.un_size;
24660Sstevel@tonic-gate 	set_params.mdp = (uintptr_t)mm;
24670Sstevel@tonic-gate 	MD_SETDRIVERNAME(&set_params, MD_MIRROR, MD_MIN2SET(set_params.mnum));
24680Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET, &set_params, &set_params.mde,
24690Sstevel@tonic-gate 	    mirnp->cname) != 0) {
24700Sstevel@tonic-gate 		(void) mdstealerror(ep, &set_params.mde);
24710Sstevel@tonic-gate 		goto out;
24720Sstevel@tonic-gate 	}
24730Sstevel@tonic-gate 	rval = 0;	/* success */
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	/* cleanup, return success */
24760Sstevel@tonic-gate out:
24770Sstevel@tonic-gate 	Free(mm);
24780Sstevel@tonic-gate 	if (rval != 0) {
24790Sstevel@tonic-gate 		(void) del_key_names(sp, keynlp, NULL);
24800Sstevel@tonic-gate 	}
24810Sstevel@tonic-gate 	metafreenamelist(keynlp);
24820Sstevel@tonic-gate 	if ((rval == 0) && (options & MDCMD_DOIT)) {
24830Sstevel@tonic-gate 		if (invalidate_submirrors(sp, mirnp, ep) != 0)
24840Sstevel@tonic-gate 			rval = -1;
24850Sstevel@tonic-gate 		meta_invalidate_name(mirnp);
24860Sstevel@tonic-gate 	}
24870Sstevel@tonic-gate 	return (rval);
24880Sstevel@tonic-gate }
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate /*
24910Sstevel@tonic-gate  * initialize mirror
24920Sstevel@tonic-gate  * NOTE: this functions is metainit(1m)'s command line parser!
24930Sstevel@tonic-gate  */
24940Sstevel@tonic-gate int
meta_init_mirror(mdsetname_t ** spp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)24950Sstevel@tonic-gate meta_init_mirror(
24960Sstevel@tonic-gate 	mdsetname_t	**spp,
24970Sstevel@tonic-gate 	int		argc,
24980Sstevel@tonic-gate 	char		*argv[],
24990Sstevel@tonic-gate 	mdcmdopts_t	options,
25000Sstevel@tonic-gate 	md_error_t	*ep
25010Sstevel@tonic-gate )
25020Sstevel@tonic-gate {
25030Sstevel@tonic-gate 	char		*uname = argv[0];
25040Sstevel@tonic-gate 	mdname_t	*mirnp = NULL;
25050Sstevel@tonic-gate 	int		old_optind;
25060Sstevel@tonic-gate 	int		c;
25070Sstevel@tonic-gate 	md_mirror_t	*mirrorp = NULL;
25080Sstevel@tonic-gate 	uint_t		smi;
25090Sstevel@tonic-gate 	int		rval = -1;
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	/* get mirror name */
25120Sstevel@tonic-gate 	assert(argc > 0);
25130Sstevel@tonic-gate 	if (argc < 1)
25140Sstevel@tonic-gate 		goto syntax;
25151623Stw21770 	if ((mirnp = metaname(spp, uname, META_DEVICE, ep)) == NULL)
25160Sstevel@tonic-gate 		goto out;
25170Sstevel@tonic-gate 	assert(*spp != NULL);
25180Sstevel@tonic-gate 	uname = mirnp->cname;
25190Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
25200Sstevel@tonic-gate 		goto out;
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
25230Sstevel@tonic-gate 		/* grab set lock */
25240Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep) != 0)
25250Sstevel@tonic-gate 			goto out;
25260Sstevel@tonic-gate 
25270Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
25280Sstevel@tonic-gate 			goto out;
25290Sstevel@tonic-gate 	}
25300Sstevel@tonic-gate 
25310Sstevel@tonic-gate 	/* see if it exists already */
25320Sstevel@tonic-gate 	if (metagetmiscname(mirnp, ep) != NULL) {
25330Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
25340Sstevel@tonic-gate 		    meta_getminor(mirnp->dev), uname);
25350Sstevel@tonic-gate 		goto out;
25360Sstevel@tonic-gate 	} else if (! mdismderror(ep, MDE_UNIT_NOT_SETUP)) {
25370Sstevel@tonic-gate 		goto out;
25380Sstevel@tonic-gate 	} else {
25390Sstevel@tonic-gate 		mdclrerror(ep);
25400Sstevel@tonic-gate 	}
25410Sstevel@tonic-gate 	--argc, ++argv;
25420Sstevel@tonic-gate 
25430Sstevel@tonic-gate 	/* grab -m */
25440Sstevel@tonic-gate 	if ((argc < 1) || (strcmp(argv[0], "-m") != 0))
25450Sstevel@tonic-gate 		goto syntax;
25460Sstevel@tonic-gate 	--argc, ++argv;
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 	if (argc == 0)
25490Sstevel@tonic-gate 		goto syntax;
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate 	/* parse general options */
25520Sstevel@tonic-gate 	optind = 0;
25530Sstevel@tonic-gate 	opterr = 0;
25540Sstevel@tonic-gate 	if (getopt(argc, argv, "") != -1)
25550Sstevel@tonic-gate 		goto options;
25560Sstevel@tonic-gate 
25570Sstevel@tonic-gate 	/* allocate mirror */
25580Sstevel@tonic-gate 	mirrorp = Zalloc(sizeof (*mirrorp));
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 	/* setup common */
25610Sstevel@tonic-gate 	mirrorp->common.namep = mirnp;
25620Sstevel@tonic-gate 	mirrorp->common.type = MD_METAMIRROR;
25630Sstevel@tonic-gate 
25640Sstevel@tonic-gate 	/* parse submirrors */
25650Sstevel@tonic-gate 	for (smi = 0; ((argc > 0) && (argv[0][0] != '-') &&
25660Sstevel@tonic-gate 	    (! isdigit(argv[0][0]))); ++smi) {
25670Sstevel@tonic-gate 		md_submirror_t	*mdsm = &mirrorp->submirrors[smi];
25680Sstevel@tonic-gate 		mdname_t	*submirnamep;
25690Sstevel@tonic-gate 
25700Sstevel@tonic-gate 		/* check for room */
25710Sstevel@tonic-gate 		if (smi >= NMIRROR) {
25720Sstevel@tonic-gate 			(void) mdmderror(ep, MDE_MIRROR_FULL,
25730Sstevel@tonic-gate 			    meta_getminor(mirnp->dev), uname);
25740Sstevel@tonic-gate 			goto out;
25750Sstevel@tonic-gate 		}
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate 		/* parse submirror name */
25781623Stw21770 		if ((submirnamep = metaname(spp, argv[0],
25791623Stw21770 		    META_DEVICE, ep)) == NULL)
25800Sstevel@tonic-gate 			goto out;
25810Sstevel@tonic-gate 		mdsm->submirnamep = submirnamep;
25820Sstevel@tonic-gate 		--argc, ++argv;
25830Sstevel@tonic-gate 	}
25840Sstevel@tonic-gate 	if (smi == 0) {
25850Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NSUBMIRS, meta_getminor(mirnp->dev),
25860Sstevel@tonic-gate 					uname);
25870Sstevel@tonic-gate 		goto out;
25880Sstevel@tonic-gate 	}
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 	/* dangerous n-way mirror creation */
25910Sstevel@tonic-gate 	if ((smi > 1) && (options & MDCMD_PRINT)) {
25920Sstevel@tonic-gate 		md_eprintf(dgettext(TEXT_DOMAIN,
25930Sstevel@tonic-gate "%s: WARNING: This form of metainit is not recommended.\n"
25940Sstevel@tonic-gate "The submirrors may not have the same data.\n"
25950Sstevel@tonic-gate "Please see ERRORS in metainit(1M) for additional information.\n"),
25960Sstevel@tonic-gate 		    uname);
25970Sstevel@tonic-gate 	}
25980Sstevel@tonic-gate 
25990Sstevel@tonic-gate 	/* parse mirror options */
26000Sstevel@tonic-gate 	mirrorp->read_option = RD_LOAD_BAL;
26010Sstevel@tonic-gate 	mirrorp->write_option = WR_PARALLEL;
26020Sstevel@tonic-gate 	mirrorp->pass_num = MD_PASS_DEFAULT;
26030Sstevel@tonic-gate 	old_optind = optind = 0;
26040Sstevel@tonic-gate 	opterr = 0;
26050Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "grS")) != -1) {
26060Sstevel@tonic-gate 		switch (c) {
26070Sstevel@tonic-gate 		case 'g':
26080Sstevel@tonic-gate 			if (mirrorp->read_option != RD_LOAD_BAL) {
26090Sstevel@tonic-gate 				(void) mderror(ep, MDE_BAD_RD_OPT, uname);
26100Sstevel@tonic-gate 				goto out;
26110Sstevel@tonic-gate 			}
26120Sstevel@tonic-gate 			mirrorp->read_option = RD_GEOMETRY;
26130Sstevel@tonic-gate 			break;
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate 		case 'r':
26160Sstevel@tonic-gate 			if (mirrorp->read_option != RD_LOAD_BAL) {
26170Sstevel@tonic-gate 				(void) mderror(ep, MDE_BAD_RD_OPT, uname);
26180Sstevel@tonic-gate 				goto out;
26190Sstevel@tonic-gate 			}
26200Sstevel@tonic-gate 			mirrorp->read_option = RD_FIRST;
26210Sstevel@tonic-gate 			break;
26220Sstevel@tonic-gate 
26230Sstevel@tonic-gate 		case 'S':
26240Sstevel@tonic-gate 			if (mirrorp->write_option != WR_PARALLEL) {
26250Sstevel@tonic-gate 				(void) mderror(ep, MDE_BAD_WR_OPT, uname);
26260Sstevel@tonic-gate 				goto out;
26270Sstevel@tonic-gate 			}
26280Sstevel@tonic-gate 			mirrorp->write_option = WR_SERIAL;
26290Sstevel@tonic-gate 			break;
26300Sstevel@tonic-gate 
26310Sstevel@tonic-gate 		default:
26320Sstevel@tonic-gate 			argc -= old_optind;
26330Sstevel@tonic-gate 			argv += old_optind;
26340Sstevel@tonic-gate 			goto options;
26350Sstevel@tonic-gate 		}
26360Sstevel@tonic-gate 		old_optind = optind;
26370Sstevel@tonic-gate 	}
26380Sstevel@tonic-gate 	argc -= optind;
26390Sstevel@tonic-gate 	argv += optind;
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	/* parse pass number */
26420Sstevel@tonic-gate 	if ((argc > 0) && (isdigit(argv[0][0]))) {
26430Sstevel@tonic-gate 		if (name_to_pass_num(uname, argv[0],
26440Sstevel@tonic-gate 		    &mirrorp->pass_num, ep) != 0) {
26450Sstevel@tonic-gate 			goto out;
26460Sstevel@tonic-gate 		}
26470Sstevel@tonic-gate 		--argc, ++argv;
26480Sstevel@tonic-gate 	}
26490Sstevel@tonic-gate 
26500Sstevel@tonic-gate 	/* we should be at the end */
26510Sstevel@tonic-gate 	if (argc != 0)
26520Sstevel@tonic-gate 		goto syntax;
26530Sstevel@tonic-gate 
26540Sstevel@tonic-gate 	/* create mirror */
26550Sstevel@tonic-gate 	if (meta_create_mirror(*spp, mirrorp, options, ep) != 0)
26560Sstevel@tonic-gate 		goto out;
26570Sstevel@tonic-gate 	rval = 0;	/* success */
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate 	/* let em know */
26600Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
26610Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
26620Sstevel@tonic-gate 		    "%s: Mirror is setup\n"),
26630Sstevel@tonic-gate 		    uname);
26640Sstevel@tonic-gate 		(void) fflush(stdout);
26650Sstevel@tonic-gate 	}
26660Sstevel@tonic-gate 	goto out;
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	/* syntax error */
26690Sstevel@tonic-gate syntax:
26700Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
26710Sstevel@tonic-gate 	goto out;
26720Sstevel@tonic-gate 
26730Sstevel@tonic-gate 	/* options error */
26740Sstevel@tonic-gate options:
26750Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
26760Sstevel@tonic-gate 	goto out;
26770Sstevel@tonic-gate 
26780Sstevel@tonic-gate 	/* cleanup, return error */
26790Sstevel@tonic-gate out:
26800Sstevel@tonic-gate 	if (mirrorp != NULL)
26810Sstevel@tonic-gate 		meta_free_mirror(mirrorp);
26820Sstevel@tonic-gate 	return (rval);
26830Sstevel@tonic-gate }
26840Sstevel@tonic-gate 
26850Sstevel@tonic-gate /*
26860Sstevel@tonic-gate  * reset mirrors
26870Sstevel@tonic-gate  */
26880Sstevel@tonic-gate int
meta_mirror_reset(mdsetname_t * sp,mdname_t * mirnp,mdcmdopts_t options,md_error_t * ep)26890Sstevel@tonic-gate meta_mirror_reset(
26900Sstevel@tonic-gate 	mdsetname_t	*sp,
26910Sstevel@tonic-gate 	mdname_t	*mirnp,
26920Sstevel@tonic-gate 	mdcmdopts_t	options,
26930Sstevel@tonic-gate 	md_error_t	*ep
26940Sstevel@tonic-gate )
26950Sstevel@tonic-gate {
26960Sstevel@tonic-gate 	md_mirror_t	*mirrorp;
26970Sstevel@tonic-gate 	uint_t		smi;
26980Sstevel@tonic-gate 	int		rval = -1;
26990Sstevel@tonic-gate 
27000Sstevel@tonic-gate 	/* should have same set */
27010Sstevel@tonic-gate 	assert(sp != NULL);
27020Sstevel@tonic-gate 	assert((mirnp == NULL) ||
27030Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev))));
27040Sstevel@tonic-gate 
27050Sstevel@tonic-gate 	/* reset all mirrors */
27060Sstevel@tonic-gate 	if (mirnp == NULL) {
27070Sstevel@tonic-gate 		mdnamelist_t	*mirrornlp = NULL;
27080Sstevel@tonic-gate 		mdnamelist_t	*p;
27090Sstevel@tonic-gate 
27100Sstevel@tonic-gate 		/* for each mirror */
27110Sstevel@tonic-gate 		rval = 0;
27120Sstevel@tonic-gate 		if (meta_get_mirror_names(sp, &mirrornlp, 0, ep) < 0)
27130Sstevel@tonic-gate 			return (-1);
27140Sstevel@tonic-gate 		for (p = mirrornlp; (p != NULL); p = p->next) {
27150Sstevel@tonic-gate 			/* reset mirror */
27160Sstevel@tonic-gate 			mirnp = p->namep;
27170Sstevel@tonic-gate 			/*
27180Sstevel@tonic-gate 			 * If this is a multi-node set, we send a series
27190Sstevel@tonic-gate 			 * of individual metaclear commands.
27200Sstevel@tonic-gate 			 */
27210Sstevel@tonic-gate 			if (meta_is_mn_set(sp, ep)) {
27220Sstevel@tonic-gate 				if (meta_mn_send_metaclear_command(sp,
27230Sstevel@tonic-gate 				    mirnp->cname, options, 0, ep) != 0) {
27240Sstevel@tonic-gate 					rval = -1;
27250Sstevel@tonic-gate 					break;
27260Sstevel@tonic-gate 				}
27270Sstevel@tonic-gate 			} else {
27280Sstevel@tonic-gate 				if (meta_mirror_reset(sp, mirnp, options,
27290Sstevel@tonic-gate 				    ep) != 0) {
27300Sstevel@tonic-gate 					rval = -1;
27310Sstevel@tonic-gate 					break;
27320Sstevel@tonic-gate 				}
27330Sstevel@tonic-gate 			}
27340Sstevel@tonic-gate 		}
27350Sstevel@tonic-gate 
27360Sstevel@tonic-gate 		/* cleanup return success */
27370Sstevel@tonic-gate 		metafreenamelist(mirrornlp);
27380Sstevel@tonic-gate 		return (rval);
27390Sstevel@tonic-gate 	}
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 	/* check name */
27420Sstevel@tonic-gate 	if (metachkmeta(mirnp, ep) != 0)
27430Sstevel@tonic-gate 		return (-1);
27440Sstevel@tonic-gate 
27450Sstevel@tonic-gate 	/* get unit structure */
27460Sstevel@tonic-gate 	if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL)
27470Sstevel@tonic-gate 		return (-1);
27480Sstevel@tonic-gate 
27490Sstevel@tonic-gate 	/* make sure nobody owns us */
27500Sstevel@tonic-gate 	if (MD_HAS_PARENT(mirrorp->common.parent)) {
27510Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(mirnp->dev),
27520Sstevel@tonic-gate 		    mirnp->cname));
27530Sstevel@tonic-gate 	}
27540Sstevel@tonic-gate 
27550Sstevel@tonic-gate 	/* clear subdevices cache */
27560Sstevel@tonic-gate 	if (invalidate_submirrors(sp, mirnp, ep) != 0)
27570Sstevel@tonic-gate 		return (-1);
27580Sstevel@tonic-gate 
27590Sstevel@tonic-gate 	/* clear metadevice */
27600Sstevel@tonic-gate 	if (meta_reset(sp, mirnp, options, ep) != 0)
27610Sstevel@tonic-gate 		goto out;
27620Sstevel@tonic-gate 	rval = 0;	/* success */
27630Sstevel@tonic-gate 
27640Sstevel@tonic-gate 	/* let em know */
27650Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
27660Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
27670Sstevel@tonic-gate 		    "%s: Mirror is cleared\n"), mirnp->cname);
27680Sstevel@tonic-gate 		(void) fflush(stdout);
27690Sstevel@tonic-gate 	}
27700Sstevel@tonic-gate 
27710Sstevel@tonic-gate 	/* clear subdevices */
27720Sstevel@tonic-gate 	if (! (options & MDCMD_RECURSE))
27730Sstevel@tonic-gate 		goto out;
27740Sstevel@tonic-gate 	for (smi = 0; (smi < NMIRROR); ++smi) {
27750Sstevel@tonic-gate 		md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
27760Sstevel@tonic-gate 		mdname_t	*submirnp = mdsp->submirnamep;
27770Sstevel@tonic-gate 
27780Sstevel@tonic-gate 		/* skip unused submirrors */
27790Sstevel@tonic-gate 		if (submirnp == NULL) {
27800Sstevel@tonic-gate 			assert(mdsp->state == SMS_UNUSED);
27810Sstevel@tonic-gate 			continue;
27820Sstevel@tonic-gate 		}
27830Sstevel@tonic-gate 
27840Sstevel@tonic-gate 		/* make sure we have a metadevice */
27850Sstevel@tonic-gate 		if (! metaismeta(submirnp))
27860Sstevel@tonic-gate 			continue;
27870Sstevel@tonic-gate 
27880Sstevel@tonic-gate 		/* clear submirror */
27890Sstevel@tonic-gate 		if (meta_reset_by_name(sp, submirnp, options, ep) != 0)
27900Sstevel@tonic-gate 			rval = -1;
27910Sstevel@tonic-gate 	}
27920Sstevel@tonic-gate 
27930Sstevel@tonic-gate 	/* cleanup, return success */
27940Sstevel@tonic-gate out:
27950Sstevel@tonic-gate 	meta_invalidate_name(mirnp);
27960Sstevel@tonic-gate 	return (rval);
27970Sstevel@tonic-gate }
27980Sstevel@tonic-gate 
27990Sstevel@tonic-gate /*
28000Sstevel@tonic-gate  * reports TRUE if any mirror component is in error
28010Sstevel@tonic-gate  */
28020Sstevel@tonic-gate int
meta_mirror_anycomp_is_err(mdsetname_t * sp,mdnamelist_t * mirror_names)28030Sstevel@tonic-gate meta_mirror_anycomp_is_err(mdsetname_t *sp, mdnamelist_t *mirror_names)
28040Sstevel@tonic-gate {
28050Sstevel@tonic-gate 	mdnamelist_t	*nlp;
28060Sstevel@tonic-gate 	md_error_t	  status	= mdnullerror;
28070Sstevel@tonic-gate 	md_error_t	 *ep		= &status;
28080Sstevel@tonic-gate 	int		  any_errs	= FALSE;
28090Sstevel@tonic-gate 
28100Sstevel@tonic-gate 	for (nlp = mirror_names; nlp; nlp = nlp->next) {
28110Sstevel@tonic-gate 		md_mirror_t	*mirrorp;
28120Sstevel@tonic-gate 		int		 smi;
28130Sstevel@tonic-gate 
28140Sstevel@tonic-gate 		if ((mirrorp = meta_get_mirror(sp, nlp->namep, ep)) == NULL) {
28150Sstevel@tonic-gate 			any_errs |= TRUE;
28160Sstevel@tonic-gate 			goto out;
28170Sstevel@tonic-gate 		}
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate 		for (smi = 0; smi < NMIRROR; ++smi) {
28200Sstevel@tonic-gate 			md_submirror_t	*mdsp = &mirrorp->submirrors[smi];
28210Sstevel@tonic-gate 
28220Sstevel@tonic-gate 			if (mdsp->state &
28230Sstevel@tonic-gate 			    (SMS_COMP_ERRED|SMS_ATTACHED|SMS_OFFLINE)) {
28240Sstevel@tonic-gate 				any_errs |= TRUE;
28250Sstevel@tonic-gate 				goto out;
28260Sstevel@tonic-gate 			}
28270Sstevel@tonic-gate 		}
28280Sstevel@tonic-gate 	}
28290Sstevel@tonic-gate out:
28300Sstevel@tonic-gate 	if (!mdisok(ep))
28310Sstevel@tonic-gate 		mdclrerror(ep);
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate 	return (any_errs);
28340Sstevel@tonic-gate }
2835