xref: /onnv-gate/usr/src/lib/lvm/libmeta/common/meta_hotspares.c (revision 2099:1a2e0356f4c9)
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 /*
221623Stw21770  * Copyright 2006 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  * hotspares utilities
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include <meta.h>
410Sstevel@tonic-gate #include <sys/lvm/md_hotspares.h>
420Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * FUNCTION:	meta_get_hsp_names()
460Sstevel@tonic-gate  * INPUT:	sp	- the set name to get hotspares from
470Sstevel@tonic-gate  *		options	- options from the command line
480Sstevel@tonic-gate  * OUTPUT:	hspnlpp	- list of all hotspare names
490Sstevel@tonic-gate  *		ep	- return error pointer
500Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
510Sstevel@tonic-gate  * PURPOSE:	returns a list of all hotspares in the metadb
520Sstevel@tonic-gate  *		for all devices in the specified set
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate /*ARGSUSED*/
550Sstevel@tonic-gate int
meta_get_hsp_names(mdsetname_t * sp,mdhspnamelist_t ** hspnlpp,int options,md_error_t * ep)560Sstevel@tonic-gate meta_get_hsp_names(
570Sstevel@tonic-gate 	mdsetname_t	*sp,
580Sstevel@tonic-gate 	mdhspnamelist_t	**hspnlpp,
590Sstevel@tonic-gate 	int		options,
600Sstevel@tonic-gate 	md_error_t	*ep
610Sstevel@tonic-gate )
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	md_i_getnum_t	gn;		/* MD_IOCGET_NUM params */
640Sstevel@tonic-gate 	minor_t		*minors = NULL;
650Sstevel@tonic-gate 	minor_t		*m_ptr;
660Sstevel@tonic-gate 	int		i;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	/* we must have a set */
690Sstevel@tonic-gate 	assert(sp != NULL);
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	(void) memset(&gn, 0, sizeof (gn));
720Sstevel@tonic-gate 	MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	/* get number of devices */
750Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
760Sstevel@tonic-gate 		if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
770Sstevel@tonic-gate 			mdclrerror(&gn.mde);
780Sstevel@tonic-gate 		} else {
790Sstevel@tonic-gate 			(void) mdstealerror(ep, &gn.mde);
800Sstevel@tonic-gate 			return (-1);
810Sstevel@tonic-gate 		}
820Sstevel@tonic-gate 	}
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	if (gn.size > 0) {
850Sstevel@tonic-gate 		/* malloc minor number buffer to be filled by ioctl */
860Sstevel@tonic-gate 		if ((minors = (minor_t *)malloc(
870Sstevel@tonic-gate 				gn.size * sizeof (minor_t))) == 0) {
880Sstevel@tonic-gate 			return (ENOMEM);
890Sstevel@tonic-gate 		}
900Sstevel@tonic-gate 		gn.minors = (uintptr_t)minors;
910Sstevel@tonic-gate 		if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
920Sstevel@tonic-gate 			(void) mdstealerror(ep, &gn.mde);
930Sstevel@tonic-gate 			free(minors);
940Sstevel@tonic-gate 			return (-1);
950Sstevel@tonic-gate 		}
960Sstevel@tonic-gate 		m_ptr = minors;
970Sstevel@tonic-gate 		for (i = 0; i < gn.size; i++) {
980Sstevel@tonic-gate 			mdhspname_t	*hspnp;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 			/* get name */
1020Sstevel@tonic-gate 			if ((hspnp = metahsphspname(&sp, *m_ptr, ep))
1030Sstevel@tonic-gate 					== NULL)
1040Sstevel@tonic-gate 				goto out;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 			/* append to list */
1070Sstevel@tonic-gate 			(void) metahspnamelist_append(hspnlpp, hspnp);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 			/* next device */
1100Sstevel@tonic-gate 			m_ptr++;
1110Sstevel@tonic-gate 		}
1120Sstevel@tonic-gate 		free(minors);
1130Sstevel@tonic-gate 	}
1140Sstevel@tonic-gate 	return (gn.size);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate out:
1170Sstevel@tonic-gate 	if (minors != NULL)
1180Sstevel@tonic-gate 		free(minors);
1190Sstevel@tonic-gate 	metafreehspnamelist(*hspnlpp);
1200Sstevel@tonic-gate 	*hspnlpp = NULL;
1210Sstevel@tonic-gate 	return (-1);
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  * get information of a specific hotspare pool from driver
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate static get_hsp_t *
get_hspinfo(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)1280Sstevel@tonic-gate get_hspinfo(
1290Sstevel@tonic-gate 	mdsetname_t	*sp,
1300Sstevel@tonic-gate 	mdhspname_t	*hspnp,
1310Sstevel@tonic-gate 	md_error_t	*ep
1320Sstevel@tonic-gate )
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate 	md_i_get_t	mig;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	/* should have a set */
1370Sstevel@tonic-gate 	assert(sp != NULL);
1381623Stw21770 	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	/* get size of unit structure */
1410Sstevel@tonic-gate 	(void) memset(&mig, 0, sizeof (mig));
1420Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno);
1430Sstevel@tonic-gate 	mig.id = hspnp->hsp;
1440Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
1450Sstevel@tonic-gate 		(void) mdstealerror(ep, &mig.mde);
1460Sstevel@tonic-gate 		return (NULL);
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	/* get actual unit structure */
1500Sstevel@tonic-gate 	assert(mig.size > 0);
1510Sstevel@tonic-gate 	mig.mdp = (uintptr_t)Zalloc(mig.size);
1520Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
1530Sstevel@tonic-gate 		(void) mdstealerror(ep, &mig.mde);
15462Sjeanm 		Free((void *)(uintptr_t)mig.mdp);
1550Sstevel@tonic-gate 		return (NULL);
1560Sstevel@tonic-gate 	}
15762Sjeanm 	return ((get_hsp_t *)(uintptr_t)mig.mdp);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate  * free hotspare pool unit
1620Sstevel@tonic-gate  */
1630Sstevel@tonic-gate void
meta_free_hsp(md_hsp_t * hspp)1640Sstevel@tonic-gate meta_free_hsp(
1650Sstevel@tonic-gate 	md_hsp_t	*hspp
1660Sstevel@tonic-gate )
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_val != NULL) {
1690Sstevel@tonic-gate 		assert(hspp->hotspares.hotspares_len > 0);
1700Sstevel@tonic-gate 		Free(hspp->hotspares.hotspares_val);
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 	Free(hspp);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate  * get hotspare pool unit (common)
1770Sstevel@tonic-gate  */
1780Sstevel@tonic-gate md_hsp_t *
meta_get_hsp_common(mdsetname_t * sp,mdhspname_t * hspnp,int fast,md_error_t * ep)1790Sstevel@tonic-gate meta_get_hsp_common(
1800Sstevel@tonic-gate 	mdsetname_t	*sp,
1810Sstevel@tonic-gate 	mdhspname_t	*hspnp,
1820Sstevel@tonic-gate 	int		fast,
1830Sstevel@tonic-gate 	md_error_t	*ep
1840Sstevel@tonic-gate )
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	get_hsp_t	*ghsp;
1870Sstevel@tonic-gate 	md_hsp_t	*hspp;
1880Sstevel@tonic-gate 	uint_t		hsi;
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	/* must have set */
1910Sstevel@tonic-gate 	assert(sp != NULL);
1921623Stw21770 	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/* short circuit */
1950Sstevel@tonic-gate 	if (hspnp->unitp != NULL)
1960Sstevel@tonic-gate 		return (hspnp->unitp);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	/* get unit */
1990Sstevel@tonic-gate 	if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL)
2000Sstevel@tonic-gate 		return (NULL);
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	/* allocate hsp */
2030Sstevel@tonic-gate 	hspp = Zalloc(sizeof (*hspp));
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	/* allocate hotspares */
2060Sstevel@tonic-gate 	hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	/* if empty hotspare pool, we are done */
2090Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_len != 0)
2100Sstevel@tonic-gate 		hspp->hotspares.hotspares_val =
2110Sstevel@tonic-gate 		    Zalloc(hspp->hotspares.hotspares_len *
2120Sstevel@tonic-gate 		    sizeof (*hspp->hotspares.hotspares_val));
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	/* get name, refcount */
2150Sstevel@tonic-gate 	hspp->hspnamep = hspnp;
2160Sstevel@tonic-gate 	hspp->refcount = ghsp->ghsp_refcount;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	/* get hotspares */
2190Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
2200Sstevel@tonic-gate 		mdkey_t		hs_key = ghsp->ghsp_hs_keys[hsi];
2210Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
2220Sstevel@tonic-gate 		get_hs_params_t	ghs;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 		/* get hotspare name */
2250Sstevel@tonic-gate 		hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep);
2260Sstevel@tonic-gate 		if (hsp->hsnamep == NULL)
2270Sstevel@tonic-gate 			goto out;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 		/* get hotspare state */
2300Sstevel@tonic-gate 		(void) memset(&ghs, 0, sizeof (ghs));
2310Sstevel@tonic-gate 		MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno);
2320Sstevel@tonic-gate 		ghs.ghs_key = hs_key;
2330Sstevel@tonic-gate 		if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) {
2340Sstevel@tonic-gate 			(void) mdstealerror(ep, &ghs.mde);
2350Sstevel@tonic-gate 			goto out;
2360Sstevel@tonic-gate 		}
2370Sstevel@tonic-gate 		hsp->state = ghs.ghs_state;
2380Sstevel@tonic-gate 		hsp->size = ghs.ghs_number_blks;
2390Sstevel@tonic-gate 		hsp->timestamp = ghs.ghs_timestamp;
2400Sstevel@tonic-gate 		hsp->revision = ghs.ghs_revision;
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/* cleanup, return success */
2440Sstevel@tonic-gate 	Free(ghsp);
2450Sstevel@tonic-gate 	hspnp->unitp = hspp;
2460Sstevel@tonic-gate 	return (hspp);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/* cleanup, return error */
2490Sstevel@tonic-gate out:
2500Sstevel@tonic-gate 	Free(ghsp);
2510Sstevel@tonic-gate 	meta_free_hsp(hspp);
2520Sstevel@tonic-gate 	return (NULL);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate  * get hotspare pool unit
2570Sstevel@tonic-gate  */
2580Sstevel@tonic-gate md_hsp_t *
meta_get_hsp(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)2590Sstevel@tonic-gate meta_get_hsp(
2600Sstevel@tonic-gate 	mdsetname_t	*sp,
2610Sstevel@tonic-gate 	mdhspname_t	*hspnp,
2620Sstevel@tonic-gate 	md_error_t	*ep
2630Sstevel@tonic-gate )
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 	return (meta_get_hsp_common(sp, hspnp, 0, ep));
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate  * check hotspare pool for dev
2700Sstevel@tonic-gate  */
2710Sstevel@tonic-gate static int
in_hsp(mdsetname_t * sp,mdhspname_t * hspnp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)2720Sstevel@tonic-gate in_hsp(
2730Sstevel@tonic-gate 	mdsetname_t	*sp,
2740Sstevel@tonic-gate 	mdhspname_t	*hspnp,
2750Sstevel@tonic-gate 	mdname_t	*np,
2760Sstevel@tonic-gate 	diskaddr_t	slblk,
2770Sstevel@tonic-gate 	diskaddr_t	nblks,
2780Sstevel@tonic-gate 	md_error_t	*ep
2790Sstevel@tonic-gate )
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate 	md_hsp_t	*hspp;
2820Sstevel@tonic-gate 	uint_t		i;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	/* should be in the same set */
2850Sstevel@tonic-gate 	assert(sp != NULL);
2861623Stw21770 	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	/* get unit */
2890Sstevel@tonic-gate 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
2900Sstevel@tonic-gate 		return (-1);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	/* look in hotspares */
2930Sstevel@tonic-gate 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
2940Sstevel@tonic-gate 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
2950Sstevel@tonic-gate 		mdname_t	*hsnp = hs->hsnamep;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 		/* check overlap */
2980Sstevel@tonic-gate 		if (metaismeta(hsnp))
2990Sstevel@tonic-gate 			continue;
3000Sstevel@tonic-gate 		if (meta_check_overlap(hspnp->hspname, np, slblk, nblks,
3010Sstevel@tonic-gate 		    hsnp, 0, -1, ep) != 0)
3020Sstevel@tonic-gate 			return (-1);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	/* return success */
3060Sstevel@tonic-gate 	return (0);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate /*
3100Sstevel@tonic-gate  * check to see if we're in a hotspare pool
3110Sstevel@tonic-gate  */
3120Sstevel@tonic-gate int
meta_check_inhsp(mdsetname_t * sp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)3130Sstevel@tonic-gate meta_check_inhsp(
3140Sstevel@tonic-gate 	mdsetname_t	*sp,
3150Sstevel@tonic-gate 	mdname_t	*np,
3160Sstevel@tonic-gate 	diskaddr_t	slblk,
3170Sstevel@tonic-gate 	diskaddr_t	nblks,
3180Sstevel@tonic-gate 	md_error_t	*ep
3190Sstevel@tonic-gate )
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
3220Sstevel@tonic-gate 	mdhspnamelist_t	*p;
3230Sstevel@tonic-gate 	int		rval = 0;
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/* should have a set */
3260Sstevel@tonic-gate 	assert(sp != NULL);
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	/* for each hotspare pool */
3290Sstevel@tonic-gate 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
3300Sstevel@tonic-gate 		return (-1);
3310Sstevel@tonic-gate 	for (p = hspnlp; (p != NULL); p = p->next) {
3320Sstevel@tonic-gate 		mdhspname_t	*hspnp = p->hspnamep;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 		/* check hotspare pool */
3350Sstevel@tonic-gate 		if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) {
3360Sstevel@tonic-gate 			rval = -1;
3370Sstevel@tonic-gate 			break;
3380Sstevel@tonic-gate 		}
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	/* cleanup, return success */
3420Sstevel@tonic-gate 	metafreehspnamelist(hspnlp);
3430Sstevel@tonic-gate 	return (rval);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate /*
3470Sstevel@tonic-gate  * check hotspare
3480Sstevel@tonic-gate  */
3490Sstevel@tonic-gate int
meta_check_hotspare(mdsetname_t * sp,mdname_t * np,md_error_t * ep)3500Sstevel@tonic-gate meta_check_hotspare(
3510Sstevel@tonic-gate 	mdsetname_t	*sp,
3520Sstevel@tonic-gate 	mdname_t	*np,
3530Sstevel@tonic-gate 	md_error_t	*ep
3540Sstevel@tonic-gate )
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate 	mdchkopts_t	options = (MDCHK_ALLOW_HS);
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	/* make sure we have a disk */
3590Sstevel@tonic-gate 	if (metachkcomp(np, ep) != 0)
3600Sstevel@tonic-gate 		return (-1);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
3630Sstevel@tonic-gate 	if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
3640Sstevel@tonic-gate 		return (-1);
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	/* make sure it is in the set */
3680Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
3690Sstevel@tonic-gate 		return (-1);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	/* make sure its not in a metadevice */
3720Sstevel@tonic-gate 	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
3730Sstevel@tonic-gate 		return (-1);
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	/* return success */
3760Sstevel@tonic-gate 	return (0);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * print hsp
3810Sstevel@tonic-gate  */
3820Sstevel@tonic-gate static int
hsp_print(md_hsp_t * hspp,char * fname,FILE * fp,md_error_t * ep)3830Sstevel@tonic-gate hsp_print(
3840Sstevel@tonic-gate 	md_hsp_t	*hspp,
3850Sstevel@tonic-gate 	char		*fname,
3860Sstevel@tonic-gate 	FILE		*fp,
3870Sstevel@tonic-gate 	md_error_t	*ep
3880Sstevel@tonic-gate )
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	uint_t		hsi;
3910Sstevel@tonic-gate 	int		rval = -1;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	/* print name */
3940Sstevel@tonic-gate 	if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF)
3950Sstevel@tonic-gate 		goto out;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	/* print hotspares */
3980Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
3990Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 		/* print hotspare */
4020Sstevel@tonic-gate 		/*
4030Sstevel@tonic-gate 		 * If the path is our standard /dev/rdsk or /dev/md/rdsk
4040Sstevel@tonic-gate 		 * then just print out the cxtxdxsx or the dx, metainit
4050Sstevel@tonic-gate 		 * will assume the default, otherwise we need the full
4060Sstevel@tonic-gate 		 * pathname to make sure this works as we intend.
4070Sstevel@tonic-gate 		 */
4080Sstevel@tonic-gate 		if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) &&
4090Sstevel@tonic-gate 		    (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) &&
4100Sstevel@tonic-gate 		    (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) {
4110Sstevel@tonic-gate 			/* not standard path, print full pathname */
4120Sstevel@tonic-gate 			if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF)
4130Sstevel@tonic-gate 				goto out;
4140Sstevel@tonic-gate 		} else {
4150Sstevel@tonic-gate 			/* standard path, just print ctd or d value */
4160Sstevel@tonic-gate 			if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF)
4170Sstevel@tonic-gate 				goto out;
4180Sstevel@tonic-gate 		}
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	/* terminate last line */
4220Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
4230Sstevel@tonic-gate 		goto out;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	/* success */
4260Sstevel@tonic-gate 	rval = 0;
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/* cleanup, return error */
4290Sstevel@tonic-gate out:
4300Sstevel@tonic-gate 	if (rval != 0)
4310Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
4320Sstevel@tonic-gate 	return (rval);
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate  * hotspare state name
4370Sstevel@tonic-gate  */
4380Sstevel@tonic-gate char *
hs_state_to_name(md_hs_t * hsp,md_timeval32_t * tvp)4390Sstevel@tonic-gate hs_state_to_name(
4400Sstevel@tonic-gate 	md_hs_t			*hsp,
4410Sstevel@tonic-gate 	md_timeval32_t		*tvp
4420Sstevel@tonic-gate )
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	hotspare_states_t	state = hsp->state;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	/* grab time */
4470Sstevel@tonic-gate 	if (tvp != NULL)
4480Sstevel@tonic-gate 		*tvp = hsp->timestamp;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	switch (state) {
4510Sstevel@tonic-gate 	case HSS_AVAILABLE:
4520Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Available"));
4530Sstevel@tonic-gate 	case HSS_RESERVED:
4540Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "In use"));
4550Sstevel@tonic-gate 	case HSS_BROKEN:
4560Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Broken"));
4570Sstevel@tonic-gate 	case HSS_UNUSED:
4580Sstevel@tonic-gate 	default:
4590Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "invalid"));
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate /*
4640Sstevel@tonic-gate  * report hsp
4650Sstevel@tonic-gate  */
4660Sstevel@tonic-gate static int
hsp_report(md_hsp_t * hspp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep,mdsetname_t * sp)4670Sstevel@tonic-gate hsp_report(
4680Sstevel@tonic-gate 	md_hsp_t	*hspp,
4690Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
4700Sstevel@tonic-gate 	char		*fname,
4710Sstevel@tonic-gate 	FILE		*fp,
4720Sstevel@tonic-gate 	mdprtopts_t	options,
4730Sstevel@tonic-gate 	md_error_t	*ep,
4740Sstevel@tonic-gate 	mdsetname_t	*sp
4750Sstevel@tonic-gate )
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 	uint_t		hsi;
4780Sstevel@tonic-gate 	int		rval = -1;
4790Sstevel@tonic-gate 	char		*devid = "";
4800Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
4810Sstevel@tonic-gate 	uint_t		len;
4820Sstevel@tonic-gate 	int		large_hs_dev_cnt = 0;
4831623Stw21770 	int		fn_hs_dev_cnt = 0;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
4860Sstevel@tonic-gate 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
4870Sstevel@tonic-gate 			md_hs_t	*hsp = &hspp->hotspares.hotspares_val[hsi];
4881623Stw21770 			if (hsp->revision & MD_64BIT_META_DEV) {
4890Sstevel@tonic-gate 				large_hs_dev_cnt += 1;
4900Sstevel@tonic-gate 				if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
4910Sstevel@tonic-gate 				    != 0)
4920Sstevel@tonic-gate 					goto out;
4930Sstevel@tonic-gate 			}
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		if (large_hs_dev_cnt == 0) {
4970Sstevel@tonic-gate 			rval = 0;
4980Sstevel@tonic-gate 			goto out;
4990Sstevel@tonic-gate 		}
5000Sstevel@tonic-gate 	}
5011623Stw21770 
5021623Stw21770 	if (options & PRINT_FN) {
5031623Stw21770 		if (!HSP_ID_IS_FN(hspp->hspnamep->hsp)) {
5041623Stw21770 			rval = 0;
5051623Stw21770 			goto out;
5061623Stw21770 		}
5071623Stw21770 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
5081623Stw21770 			md_hs_t	*hsp = &hspp->hotspares.hotspares_val[hsi];
5091623Stw21770 			fn_hs_dev_cnt += 1;
5101623Stw21770 			if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
5111623Stw21770 			    != 0)
5121623Stw21770 				goto out;
5131623Stw21770 		}
5141623Stw21770 	}
5151623Stw21770 
5160Sstevel@tonic-gate 	/* print header */
5170Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_len == 0) {
5180Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"),
5190Sstevel@tonic-gate 		    hspp->hspnamep->hspname) == EOF) {
5200Sstevel@tonic-gate 			goto out;
5210Sstevel@tonic-gate 		}
5220Sstevel@tonic-gate 	} else if (hspp->hotspares.hotspares_len == 1) {
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 		/*
5250Sstevel@tonic-gate 		 * This allows the length
5260Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
5270Sstevel@tonic-gate 		 * looking horrible.
5280Sstevel@tonic-gate 		 */
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 		len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname);
5310Sstevel@tonic-gate 		/*
5320Sstevel@tonic-gate 		 * if the length is to short to print out all of the header
5330Sstevel@tonic-gate 		 * force the matter
5340Sstevel@tonic-gate 		 */
5350Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
5360Sstevel@tonic-gate 		len += 2;
5370Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
5380Sstevel@tonic-gate 			if (fprintf(fp,
5390Sstevel@tonic-gate 			    "%s: 1 hot spare (1 big device)\n\t%-*.*s  "
5400Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
5410Sstevel@tonic-gate 			    hspp->hspnamep->hspname, len, len,
5420Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
5430Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
5440Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
5450Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5460Sstevel@tonic-gate 				goto out;
5470Sstevel@tonic-gate 			}
5480Sstevel@tonic-gate 		} else {
5490Sstevel@tonic-gate 			if (fprintf(fp,
5500Sstevel@tonic-gate 			    "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n",
5510Sstevel@tonic-gate 			    hspp->hspnamep->hspname, len, len,
5520Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
5530Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
5540Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
5550Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5560Sstevel@tonic-gate 				goto out;
5570Sstevel@tonic-gate 			}
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 	} else {
5600Sstevel@tonic-gate 		/*
5610Sstevel@tonic-gate 		 * This allows the length
5620Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
5630Sstevel@tonic-gate 		 * looking horrible.
5640Sstevel@tonic-gate 		 */
5650Sstevel@tonic-gate 		len = 0;
5660Sstevel@tonic-gate 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
5670Sstevel@tonic-gate 			len = max(len, strlen(hspp->
5680Sstevel@tonic-gate 			    hotspares.hotspares_val[hsi].hsnamep->cname));
5690Sstevel@tonic-gate 		}
5700Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
5710Sstevel@tonic-gate 		len += 2;
5720Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
5730Sstevel@tonic-gate 			if (fprintf(fp,
5740Sstevel@tonic-gate 			    "%s: %u hot spares (%d big device(s))\n\t%-*.*s "
5750Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
5760Sstevel@tonic-gate 			    hspp->hspnamep->hspname,
5770Sstevel@tonic-gate 			    hspp->hotspares.hotspares_len,
5780Sstevel@tonic-gate 			    large_hs_dev_cnt, len, len,
5790Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
5800Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
5810Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
5820Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5830Sstevel@tonic-gate 				goto out;
5840Sstevel@tonic-gate 			}
5850Sstevel@tonic-gate 		} else {
5860Sstevel@tonic-gate 			if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s "
5870Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
5880Sstevel@tonic-gate 			    hspp->hspnamep->hspname,
5890Sstevel@tonic-gate 			    hspp->hotspares.hotspares_len, len, len,
5900Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
5910Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
5920Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
5930Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5940Sstevel@tonic-gate 				goto out;
5950Sstevel@tonic-gate 			}
5960Sstevel@tonic-gate 		}
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	/* print hotspares */
6000Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
6010Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
6020Sstevel@tonic-gate 		char		*cname = hsp->hsnamep->cname;
6030Sstevel@tonic-gate 		char		*hs_state;
6040Sstevel@tonic-gate 		md_timeval32_t	tv;
6050Sstevel@tonic-gate 		char		*timep;
6060Sstevel@tonic-gate 		ddi_devid_t	dtp;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 		/* populate the key in the name_p structure */
6090Sstevel@tonic-gate 		if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) {
6100Sstevel@tonic-gate 			return (-1);
6110Sstevel@tonic-gate 		}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
6141623Stw21770 			if ((hsp->revision & MD_64BIT_META_DEV) == 0)
6150Sstevel@tonic-gate 				continue;
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 		/* determine if devid does NOT exist */
6180Sstevel@tonic-gate 		if (options & PRINT_DEVID) {
6190Sstevel@tonic-gate 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
6200Sstevel@tonic-gate 				didnp->key, ep)) == NULL)
6210Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
6220Sstevel@tonic-gate 			else {
6230Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
6240Sstevel@tonic-gate 				free(dtp);
6250Sstevel@tonic-gate 			}
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 		/* print hotspare */
6280Sstevel@tonic-gate 		hs_state = hs_state_to_name(hsp, &tv);
6290Sstevel@tonic-gate 		/*
6300Sstevel@tonic-gate 		 * This allows the length
6310Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
6320Sstevel@tonic-gate 		 * looking horrible.
6330Sstevel@tonic-gate 		 */
6340Sstevel@tonic-gate 		if (! (options & PRINT_TIMES)) {
6350Sstevel@tonic-gate 			if (fprintf(fp,
6360Sstevel@tonic-gate 			    "        %-*s %-12s %lld blocks\t%s\n",
6370Sstevel@tonic-gate 			    len, cname, hs_state,
6380Sstevel@tonic-gate 			    hsp->size, devid) == EOF) {
6390Sstevel@tonic-gate 				goto out;
6400Sstevel@tonic-gate 			}
6410Sstevel@tonic-gate 		} else {
6420Sstevel@tonic-gate 			timep = meta_print_time(&tv);
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 			if (fprintf(fp,
6450Sstevel@tonic-gate 			    "        %-*s\t    %-11s %8lld blocks%s\t%s\n",
6460Sstevel@tonic-gate 			    len, cname, hs_state,
6470Sstevel@tonic-gate 			    hsp->size, devid, timep) == EOF) {
6480Sstevel@tonic-gate 				goto out;
6490Sstevel@tonic-gate 			}
6500Sstevel@tonic-gate 		}
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	/* add extra line */
6540Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
6550Sstevel@tonic-gate 		goto out;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	/* success */
6580Sstevel@tonic-gate 	rval = 0;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	/* cleanup, return error */
6610Sstevel@tonic-gate out:
6620Sstevel@tonic-gate 	if (rval != 0)
6630Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
6640Sstevel@tonic-gate 	return (rval);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate  * print/report hsp
6690Sstevel@tonic-gate  */
6700Sstevel@tonic-gate int
meta_hsp_print(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)6710Sstevel@tonic-gate meta_hsp_print(
6720Sstevel@tonic-gate 	mdsetname_t	*sp,
6730Sstevel@tonic-gate 	mdhspname_t	*hspnp,
6740Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
6750Sstevel@tonic-gate 	char		*fname,
6760Sstevel@tonic-gate 	FILE		*fp,
6770Sstevel@tonic-gate 	mdprtopts_t	options,
6780Sstevel@tonic-gate 	md_error_t	*ep
6790Sstevel@tonic-gate )
6800Sstevel@tonic-gate {
6810Sstevel@tonic-gate 	md_hsp_t	*hspp;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	/* should have same set */
6840Sstevel@tonic-gate 	assert(sp != NULL);
6851623Stw21770 	assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
6861623Stw21770 	    sp->setno == HSP_SET(hspnp->hsp));
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/* print all hsps */
6890Sstevel@tonic-gate 	if (hspnp == NULL) {
6900Sstevel@tonic-gate 		mdhspnamelist_t	*hspnlp = NULL;
6910Sstevel@tonic-gate 		mdhspnamelist_t	*p;
6920Sstevel@tonic-gate 		int		cnt;
6930Sstevel@tonic-gate 		int		rval = 0;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 		if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0)
6960Sstevel@tonic-gate 			return (-1);
6970Sstevel@tonic-gate 		else if (cnt == 0)
6980Sstevel@tonic-gate 			return (0);
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 		/* recurse */
7010Sstevel@tonic-gate 		for (p = hspnlp; (p != NULL); p = p->next) {
7020Sstevel@tonic-gate 			mdhspname_t	*hspnp = p->hspnamep;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 			if (meta_hsp_print(sp, hspnp, nlpp, fname, fp,
7050Sstevel@tonic-gate 			    options, ep) != 0)
7060Sstevel@tonic-gate 				rval = -1;
7070Sstevel@tonic-gate 		}
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 		/* cleanup, return success */
7100Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
7110Sstevel@tonic-gate 		return (rval);
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	/* get unit structure */
7150Sstevel@tonic-gate 	if ((hspp = meta_get_hsp_common(sp, hspnp,
7160Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
7170Sstevel@tonic-gate 		return (-1);
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	/* print appropriate detail */
7200Sstevel@tonic-gate 	if (options & PRINT_SHORT)
7210Sstevel@tonic-gate 		return (hsp_print(hspp, fname, fp, ep));
7220Sstevel@tonic-gate 	else
7230Sstevel@tonic-gate 		return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp));
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate /*
7270Sstevel@tonic-gate  * check for valid hotspare pool
7280Sstevel@tonic-gate  */
7290Sstevel@tonic-gate int
metachkhsp(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)7300Sstevel@tonic-gate metachkhsp(
7310Sstevel@tonic-gate 	mdsetname_t	*sp,
7320Sstevel@tonic-gate 	mdhspname_t	*hspnp,
7330Sstevel@tonic-gate 	md_error_t	*ep
7340Sstevel@tonic-gate )
7350Sstevel@tonic-gate {
7360Sstevel@tonic-gate 	if (meta_get_hsp(sp, hspnp, ep) == NULL)
7370Sstevel@tonic-gate 		return (-1);
7380Sstevel@tonic-gate 	return (0);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate /*
7420Sstevel@tonic-gate  * invalidate hotspare pool info
7430Sstevel@tonic-gate  */
7440Sstevel@tonic-gate void
meta_invalidate_hsp(mdhspname_t * hspnp)7450Sstevel@tonic-gate meta_invalidate_hsp(
7460Sstevel@tonic-gate 	mdhspname_t	*hspnp
7470Sstevel@tonic-gate )
7480Sstevel@tonic-gate {
7490Sstevel@tonic-gate 	md_hsp_t	*hspp = hspnp->unitp;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	/* free it up */
7520Sstevel@tonic-gate 	if (hspp == NULL)
7530Sstevel@tonic-gate 		return;
7540Sstevel@tonic-gate 	meta_free_hsp(hspp);
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	/* clear cache */
7570Sstevel@tonic-gate 	hspnp->unitp = NULL;
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate /*
7611623Stw21770  * FUNCTION:	del_hsp_name_mn_sides()
7621623Stw21770  * INPUT:	sp	- set name
7631623Stw21770  *		curside	- side of this node
7641623Stw21770  *		key	- key of records to delete
7651623Stw21770  * OUTPUT:	ep	- error information
7661623Stw21770  * RETURNS:	none.
7671623Stw21770  * PURPOSE:	There are name records for each side in a set.  This
7681623Stw21770  *		function deletes the records associated with the specified
7691623Stw21770  *		key for all sides except curside.  This function is used
7701623Stw21770  *		when the set is a multinode set.
7711623Stw21770  */
7721623Stw21770 static void
del_hsp_name_mn_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,md_error_t * ep)7731623Stw21770 del_hsp_name_mn_sides(
7741623Stw21770 	mdsetname_t	*sp,
7751623Stw21770 	md_set_desc	*sd,
7761623Stw21770 	side_t		curside,
7771623Stw21770 	mdkey_t		key,
7781623Stw21770 	md_error_t	*ep
7791623Stw21770 )
7801623Stw21770 {
7811623Stw21770 	md_error_t	first_error = MDNULLERROR;
7821623Stw21770 	int		error_seen = FALSE;
7831623Stw21770 	md_mnnode_desc	*nd;
7841623Stw21770 
7851623Stw21770 	for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) {
7861623Stw21770 		if (nd->nd_nodeid == curside)
7871623Stw21770 			continue;
7881623Stw21770 		if (del_name(sp, nd->nd_nodeid, key, &first_error) == -1) {
7891623Stw21770 			if (error_seen == FALSE) {
7901623Stw21770 				error_seen = TRUE;
7911623Stw21770 				(void) mdstealerror(ep, &first_error);
7921623Stw21770 			}
7931623Stw21770 		}
7941623Stw21770 	}
7951623Stw21770 }
7961623Stw21770 
7971623Stw21770 /*
7981623Stw21770  * FUNCTION:	del_hsp_name_trad_sides()
7991623Stw21770  * INPUT:	sp	- set name
8001623Stw21770  *		curside	- side of this node
8011623Stw21770  *		key	- key of records to delete
8021623Stw21770  * OUTPUT:	ep	- error information
8031623Stw21770  * RETURNS:	none.
8041623Stw21770  * PURPOSE:	There are name records for each side in a set.  This
8051623Stw21770  *		function deletes the records associated with the specified
8061623Stw21770  *		key for all sides except curside.  This function is used
8071623Stw21770  *		when the set is a traditional set.
8081623Stw21770  */
8091623Stw21770 static void
del_hsp_name_trad_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,md_error_t * ep)8101623Stw21770 del_hsp_name_trad_sides(
8111623Stw21770 	mdsetname_t	*sp,
8121623Stw21770 	md_set_desc	*sd,
8131623Stw21770 	side_t		curside,
8141623Stw21770 	mdkey_t		key,
8151623Stw21770 	md_error_t	*ep
8161623Stw21770 )
8171623Stw21770 {
8181623Stw21770 	int		error_seen = FALSE;
8191623Stw21770 	md_error_t	first_error = MDNULLERROR;
8201623Stw21770 	int		i;
8211623Stw21770 
8221623Stw21770 	for (i = 0; i < MD_MAXSIDES; i++) {
8231623Stw21770 		if (i == curside)
8241623Stw21770 			continue;
8251623Stw21770 		if (sd->sd_nodes[i][0] != '\0') {
8261623Stw21770 			if (del_name(sp, i, key, &first_error) == -1) {
8271623Stw21770 				if (error_seen == FALSE) {
8281623Stw21770 					error_seen = TRUE;
8291623Stw21770 					(void) mdstealerror(ep, &first_error);
8301623Stw21770 				}
8311623Stw21770 			}
8321623Stw21770 		}
8331623Stw21770 	}
8341623Stw21770 }
8351623Stw21770 
8361623Stw21770 /*
8371623Stw21770  * FUNCTION:	del_hsp_keys()
8381623Stw21770  * INPUT:	sp	- set name
8391623Stw21770  *		hspid	- ID of records to delete
8401623Stw21770  * OUTPUT:	ep	- error information
8411623Stw21770  * RETURNS:	0	- success
8421623Stw21770  *		-1	- error
8431623Stw21770  * PURPOSE:	Remove the NM records associated with hspid from all sides
8441623Stw21770  *		of the set.  Missing records are not considered to be an
8451623Stw21770  *		error.  The key associated with the current side is removed
8461623Stw21770  *		last.
8471623Stw21770  *
8481623Stw21770  *		This function is very similar to del_key_name(), except it
8491623Stw21770  *		does not require any device look up.  This is because the
8501623Stw21770  *		hot spare pool is not a device.
8511623Stw21770  */
8521623Stw21770 static int
del_hsp_keys(mdsetname_t * sp,hsp_t hspid,md_error_t * ep)8531623Stw21770 del_hsp_keys(mdsetname_t *sp, hsp_t hspid, md_error_t *ep)
8541623Stw21770 {
8551623Stw21770 	md_error_t	first_error = MDNULLERROR;
8561623Stw21770 	mdkey_t		key = HSP_ID_TO_KEY(hspid);
8571623Stw21770 	md_set_desc	*sd;
8581623Stw21770 	side_t		thisside;	/* Side # of this node. */
8591623Stw21770 
8601623Stw21770 	/*
8611623Stw21770 	 * If there is no key, this means that the hot spare was created
8621623Stw21770 	 * before the introduction of friendly names.  Thus, the is no NM
8631623Stw21770 	 * record and nothing for us to do in this function.
8641623Stw21770 	 */
8651623Stw21770 	if (key == MD_KEYBAD)
8661623Stw21770 		return (0);
8671623Stw21770 
8681623Stw21770 	/* Find our current side */
8691623Stw21770 	mdclrerror(ep);
8701623Stw21770 	thisside = getmyside(sp, ep);
8711623Stw21770 	if (! mdisok(ep))
8721623Stw21770 		return (-1);
8731623Stw21770 
8741623Stw21770 	/*
8751623Stw21770 	 * If not the local set, we need to process the non-local sides
8761623Stw21770 	 * first.
8771623Stw21770 	 */
8781623Stw21770 	if (!metaislocalset(sp)) {
8791623Stw21770 		if ((sd = metaget_setdesc(sp, ep)) == NULL)
8801623Stw21770 			return (-1);
8811623Stw21770 		if (MD_MNSET_DESC(sd)) {
8821623Stw21770 			/* Multinode set.  Sides are in a linked list. */
8831623Stw21770 			del_hsp_name_mn_sides(sp, sd, thisside, key,
8841623Stw21770 				&first_error);
8851623Stw21770 		} else {
8861623Stw21770 			/* Sides are in an array. */
8871623Stw21770 			del_hsp_name_trad_sides(sp, sd, thisside, key,
8881623Stw21770 				&first_error);
8891623Stw21770 		}
8901623Stw21770 	}
8911623Stw21770 
8921623Stw21770 	/* Now delete the name for the current side. */
8931623Stw21770 	(void) del_name(sp, thisside, key, ep);
8941623Stw21770 	if (! mdisok(&first_error))
8951623Stw21770 		(void) mdstealerror(ep, &first_error);
8961623Stw21770 	return (mdisok(ep) ? 0 : -1);
8971623Stw21770 }
8981623Stw21770 
8991623Stw21770 /*
9001623Stw21770  * FUNCTION:	add_hsp_name_mn_sides()
9011623Stw21770  * INPUT:	sp	- set name
9021623Stw21770  *		curside	- side number for this node
9031623Stw21770  *		key	- key to use for the name record
9041623Stw21770  *		hsp_name - name of the hot spare
9051623Stw21770  * OUTPUT:	ep	- error information
9061623Stw21770  * RETURNS:	0 indicates success, and -1 indicates failure.
9071623Stw21770  * PURPOSE:	Once the name record has been added for the current side,
9081623Stw21770  *		this function adds the record to the remaining sides.  This
9091623Stw21770  *		function is to be used when the set is a multinode set.
9101623Stw21770  *		The side designated by curside will be ignored when adding
9111623Stw21770  *		records.
9121623Stw21770  */
9131623Stw21770 static int
add_hsp_name_mn_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,char * hsp_name,md_error_t * ep)9141623Stw21770 add_hsp_name_mn_sides(
9151623Stw21770 	mdsetname_t	*sp,
9161623Stw21770 	md_set_desc	*sd,
9171623Stw21770 	side_t		curside,
9181623Stw21770 	mdkey_t		key,
9191623Stw21770 	char		*hsp_name,
9201623Stw21770 	md_error_t	*ep
9211623Stw21770 )
9221623Stw21770 {
9231623Stw21770 	md_mnnode_desc	*nd;
9241623Stw21770 
9251623Stw21770 	for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) {
9261623Stw21770 		if (nd->nd_nodeid == curside)
9271623Stw21770 			continue;
9281623Stw21770 		if (add_name(sp, nd->nd_nodeid, key, MD_HOTSPARES,
9291945Sjeanm 			minor(NODEV), hsp_name, NULL, NULL, ep) == -1) {
9301623Stw21770 			return (-1);
9311623Stw21770 		}
9321623Stw21770 	}
9331623Stw21770 	return (0);
9341623Stw21770 }
9351623Stw21770 
9361623Stw21770 /*
9371623Stw21770  * FUNCTION:	add_hsp_name_trad_sides()
9381623Stw21770  * INPUT:	sp	- set name
9391623Stw21770  *		curside	- side number for this node
9401623Stw21770  *		key	- key to use for the name record
9411623Stw21770  *		hsp_name - name of the hot spare
9421623Stw21770  * OUTPUT:	ep	- error information
9431623Stw21770  * RETURNS:	0 indicates success, and -1 indicates failure.
9441623Stw21770  * PURPOSE:	Once the name record has been added for the current side,
9451623Stw21770  *		this function adds the record to the remaining sides.  This
9461623Stw21770  *		function is to be used when the set is a traditional set.
9471623Stw21770  *		The side designated by curside will be ignored when adding
9481623Stw21770  *		records.
9491623Stw21770  */
9501623Stw21770 static int
add_hsp_name_trad_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,char * hsp_name,md_error_t * ep)9511623Stw21770 add_hsp_name_trad_sides(
9521623Stw21770 	mdsetname_t	*sp,
9531623Stw21770 	md_set_desc	*sd,
9541623Stw21770 	side_t		curside,
9551623Stw21770 	mdkey_t		key,
9561623Stw21770 	char		*hsp_name,
9571623Stw21770 	md_error_t	*ep
9581623Stw21770 )
9591623Stw21770 {
9601623Stw21770 	int		i;
9611623Stw21770 
9621623Stw21770 	for (i = 0; i < MD_MAXSIDES; i++) {
9631623Stw21770 		if (i == curside)
9641623Stw21770 			continue;
9651623Stw21770 		if (sd->sd_nodes[i][0] != '\0') {
9661623Stw21770 			if (add_name(sp, i, key, MD_HOTSPARES, minor(NODEV),
9671945Sjeanm 				hsp_name, NULL, NULL, ep) == -1) {
9681623Stw21770 				return (-1);
9691623Stw21770 			}
9701623Stw21770 		}
9711623Stw21770 	}
9721623Stw21770 	return (0);
9731623Stw21770 }
9741623Stw21770 
9751623Stw21770 /*
9761623Stw21770  * FUNCTION:	add_hsp_name()
9771623Stw21770  * INPUT:	sp	- Name of the set containing the hsp
9781623Stw21770  *		hsp_name - Hot spare pool name to be added
9791623Stw21770  * OUTPUT:	ep	- Error information
9801623Stw21770  * RETURNS:	If successful the key of the newly added record is
9811623Stw21770  *		returned.  MD_KEYBAD is returned to indicate a failure.
9821623Stw21770  * PURPOSE:	This function creates a new NM record containing the name
9831623Stw21770  *		of the hotspare pool.  A record containing the name is
9841623Stw21770  *		added to each active side, but the record is added first to
9851623Stw21770  *		the current side.  This function is modeled on
9861623Stw21770  *		add_key_name() in meta_namespace.  The difference is that
9871623Stw21770  *		there is no device associated with a hot spare pool
9881623Stw21770  */
9891623Stw21770 static hsp_t
add_hsp_name(mdsetname_t * sp,char * hsp_name,md_error_t * ep)9901623Stw21770 add_hsp_name(
9911623Stw21770 	mdsetname_t	*sp,
9921623Stw21770 	char		*hsp_name,
9931623Stw21770 	md_error_t	*ep
9941623Stw21770 )
9951623Stw21770 {
9961623Stw21770 	md_error_t	ignore_error = MDNULLERROR;
9971623Stw21770 	mdkey_t		key;
9981623Stw21770 	md_set_desc	*sd;
9991623Stw21770 	side_t		thisside;	/* Side # of this node. */
10001623Stw21770 
10011623Stw21770 	if (sp == NULL) {
10021623Stw21770 		(void) mderror(ep, MDE_NO_SET, NULL);
10031623Stw21770 		return (MD_KEYBAD);
10041623Stw21770 	}
10051623Stw21770 	if (hsp_name == NULL) {
10061623Stw21770 		(void) mderror(ep, MDE_INVAL_HSOP, NULL);
10071623Stw21770 		return (MD_KEYBAD);
10081623Stw21770 	}
10091623Stw21770 
10101623Stw21770 	mdclrerror(ep);
10111623Stw21770 	thisside = getmyside(sp, ep);
10121623Stw21770 	if (! mdisok(ep))
10131623Stw21770 		return (MD_HSPID_WILD);
10141623Stw21770 
10151623Stw21770 	/* First add the record for the side of the current node. */
10161623Stw21770 	key = add_name(sp, thisside, MD_KEYWILD, MD_HOTSPARES, minor(NODEV),
10171945Sjeanm 		hsp_name, NULL, NULL, ep);
10181623Stw21770 	if (key == -1) {
10191623Stw21770 		goto cleanup;
10201623Stw21770 	}
10211623Stw21770 
10221623Stw21770 	/* Make sure that we can use the key */
10231623Stw21770 	if (!HSP_KEY_OK(key)) {
10241623Stw21770 		(void) mdhsperror(ep, MDE_HSP_CREATE_FAILURE, MD_HSPID_WILD,
10251623Stw21770 			hsp_name);
10261623Stw21770 		goto cleanup;
10271623Stw21770 	}
10281623Stw21770 
10291623Stw21770 	/*
10301623Stw21770 	 * Now that we have a key, we will use it to add a record to the
10311623Stw21770 	 * rest of the sides in the set.  For multinode sets, the sides are
10321623Stw21770 	 * in a linked list that is anchored on the set descriptor.  For
10331623Stw21770 	 * traditional sets the side information is in an array in the set
10341623Stw21770 	 * descriptor.
10351623Stw21770 	 */
10361623Stw21770 	if (!metaislocalset(sp)) {
10371623Stw21770 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
10381623Stw21770 			goto cleanup;
10391623Stw21770 		}
10401623Stw21770 		if (MD_MNSET_DESC(sd)) {
10411623Stw21770 			/* Multinode set.  Sides are in linked list. */
10421623Stw21770 			if (add_hsp_name_mn_sides(sp, sd, thisside, key,
10431623Stw21770 				hsp_name, ep) == -1) {
10441623Stw21770 				goto cleanup;
10451623Stw21770 			}
10461623Stw21770 		} else {
10471623Stw21770 			/* Traditional set.  Sides are in an array. */
10481623Stw21770 			if (add_hsp_name_trad_sides(sp, sd, thisside, key,
10491623Stw21770 				hsp_name, ep) == -1) {
10501623Stw21770 				goto cleanup;
10511623Stw21770 			}
10521623Stw21770 		}
10531623Stw21770 	}
10541623Stw21770 
10551623Stw21770 	return (KEY_TO_HSP_ID(sp->setno, key));
10561623Stw21770 
10571623Stw21770 cleanup:
10581623Stw21770 	/* Get rid records that we added. */
10591623Stw21770 	(void) del_hsp_keys(sp, KEY_TO_HSP_ID(sp->setno, key), &ignore_error);
10601623Stw21770 	return (MD_HSPID_WILD);
10611623Stw21770 }
10621623Stw21770 
10631623Stw21770 /*
10640Sstevel@tonic-gate  * add hotspares and/or hotspare pool
10650Sstevel@tonic-gate  */
10660Sstevel@tonic-gate int
meta_hs_add(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)10670Sstevel@tonic-gate meta_hs_add(
10680Sstevel@tonic-gate 	mdsetname_t	*sp,
10690Sstevel@tonic-gate 	mdhspname_t	*hspnp,
10700Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
10710Sstevel@tonic-gate 	mdcmdopts_t	options,
10720Sstevel@tonic-gate 	md_error_t	*ep
10730Sstevel@tonic-gate )
10740Sstevel@tonic-gate {
10751623Stw21770 	md_error_t	ignore_error = MDNULLERROR;
10760Sstevel@tonic-gate 	mdnamelist_t	*p;
10770Sstevel@tonic-gate 	set_hs_params_t	shs;
10781623Stw21770 	side_t		thisside;
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	/* should have a set */
10810Sstevel@tonic-gate 	assert(sp != NULL);
10821623Stw21770 	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	/* clear cache */
10850Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	/* setup hotspare pool info */
10880Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
10890Sstevel@tonic-gate 	shs.shs_cmd = ADD_HOT_SPARE;
10900Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
10910Sstevel@tonic-gate 
10921623Stw21770 	/* Get key for hot spare pool name record. */
10931623Stw21770 	if (options & MDCMD_DOIT) {
10941623Stw21770 		/* First see if the name record already exists. */
10951623Stw21770 		mdclrerror(ep);
10961623Stw21770 		thisside = getmyside(sp, ep);
10971623Stw21770 		if (! mdisok(ep))
10981623Stw21770 			return (-1);
10991623Stw21770 		shs.shs_hot_spare_pool =
11001623Stw21770 			meta_gethspnmentbyname(sp->setno, thisside,
11011623Stw21770 				hspnp->hspname, ep);
11021623Stw21770 		if (! mdisok(ep)) {
11031623Stw21770 			/*
11041623Stw21770 			 * If the error is ENOENT, then we will create a
11051623Stw21770 			 * hot spare pool name records.  For other types of
11061623Stw21770 			 * errors, however, we'll bail out.
11071623Stw21770 			 */
11081623Stw21770 			if (! mdissyserror(ep, ENOENT))
11091623Stw21770 				return (-1);
11101623Stw21770 			mdclrerror(ep);
11111623Stw21770 			/* make sure that the name isn't already in use */
11121623Stw21770 			if (is_existing_metadevice(sp, hspnp->hspname))
11131623Stw21770 				return (mderror(ep, MDE_NAME_IN_USE,
11141623Stw21770 					hspnp->hspname));
11151623Stw21770 			if ((shs.shs_hot_spare_pool =
11161623Stw21770 				add_hsp_name(sp, hspnp->hspname, ep)) ==
11171623Stw21770 				MD_HSPID_WILD) {
11181623Stw21770 				return (-1);
11191623Stw21770 			}
11201623Stw21770 		}
11211623Stw21770 	}
11221623Stw21770 
11230Sstevel@tonic-gate 	/* add empty hotspare pool */
11240Sstevel@tonic-gate 	if (hsnlp == NULL) {
11250Sstevel@tonic-gate 		shs.shs_options = HS_OPT_POOL;
11260Sstevel@tonic-gate 		/* If DOIT is not set, it's a dryrun */
11270Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) == 0) {
11280Sstevel@tonic-gate 			shs.shs_options |= HS_OPT_DRYRUN;
11290Sstevel@tonic-gate 		}
11300Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
11311623Stw21770 			hspnp->hspname) != 0) {
11321623Stw21770 			if (options & MDCMD_DOIT) {
11331623Stw21770 				(void) del_hsp_keys(sp,
11341623Stw21770 					shs.shs_hot_spare_pool,
11351623Stw21770 					&ignore_error);
11361623Stw21770 			}
11370Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
11381623Stw21770 		}
11390Sstevel@tonic-gate 		goto success;
11400Sstevel@tonic-gate 	}
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	/* add hotspares */
11430Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
11440Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
11450Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
11460Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 	for (p = hsnlp; (p != NULL); p = p->next) {
11490Sstevel@tonic-gate 		mdname_t	*hsnp = p->namep;
11500Sstevel@tonic-gate 		diskaddr_t	size, label, start_blk;
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 		/* should be in same set */
11531623Stw21770 		assert(hspnp->hsp == MD_HSP_NONE ||
11541623Stw21770 		    sp->setno == HSP_SET(hspnp->hsp));
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 		/* check it out */
11570Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
11580Sstevel@tonic-gate 			return (-1);
11590Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
11600Sstevel@tonic-gate 			return (-1);
11610Sstevel@tonic-gate 		else if (size == 0)
11620Sstevel@tonic-gate 			return (mdsyserror(ep, ENOSPC, hsnp->cname));
11630Sstevel@tonic-gate 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
11640Sstevel@tonic-gate 			return (-1);
11650Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, hsnp, ep))
11660Sstevel@tonic-gate 		    == MD_DISKADDR_ERROR)
11670Sstevel@tonic-gate 			return (-1);
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 		shs.shs_size_option = meta_check_devicesize(size);
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 		/* In dryrun mode (DOIT not set) we must not alter the mddb */
11720Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
11730Sstevel@tonic-gate 			/* store name in namespace */
11740Sstevel@tonic-gate 			if (add_key_name(sp, hsnp, NULL, ep) != 0)
11750Sstevel@tonic-gate 				return (-1);
11760Sstevel@tonic-gate 		}
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 		/* add hotspare and/or hotspare pool */
11790Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
11800Sstevel@tonic-gate 		shs.shs_start_blk = start_blk;
11810Sstevel@tonic-gate 		shs.shs_has_label = ((label > 0) ? 1 : 0);
11820Sstevel@tonic-gate 		shs.shs_number_blks = size;
11830Sstevel@tonic-gate 		shs.shs_key_old = hsnp->key;
11840Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
11850Sstevel@tonic-gate 			if ((options & MDCMD_DOIT) &&
11860Sstevel@tonic-gate 			    (shs.shs_options != HS_OPT_POOL)) {
11870Sstevel@tonic-gate 				(void) del_key_name(sp, hsnp, ep);
11880Sstevel@tonic-gate 			}
11890Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
11900Sstevel@tonic-gate 		}
11910Sstevel@tonic-gate 	}
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/* print success message */
11940Sstevel@tonic-gate success:
11950Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
11960Sstevel@tonic-gate 		if ((options & MDCMD_INIT) || (hsnlp == NULL)) {
11970Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
11980Sstevel@tonic-gate 			    "%s: Hotspare pool is setup\n"),
11990Sstevel@tonic-gate 			    hspnp->hspname);
12000Sstevel@tonic-gate 		} else if (hsnlp->next == NULL) {
12010Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
12020Sstevel@tonic-gate 			    "%s: Hotspare is added\n"),
12030Sstevel@tonic-gate 			    hspnp->hspname);
12040Sstevel@tonic-gate 		} else {
12050Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
12060Sstevel@tonic-gate 			    "%s: Hotspares are added\n"),
12070Sstevel@tonic-gate 			    hspnp->hspname);
12080Sstevel@tonic-gate 		}
12090Sstevel@tonic-gate 		(void) fflush(stdout);
12100Sstevel@tonic-gate 	}
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	/* return success */
12130Sstevel@tonic-gate 	return (0);
12140Sstevel@tonic-gate }
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate /*
12171623Stw21770  * FUNCTION:	meta_hsp_delete()
12181623Stw21770  * INPUT:	sp	- Name of the set containing the hsp
12191623Stw21770  *		hspnp	- Hot spare pool name information
12201623Stw21770  *		options	- Options from command line
12211623Stw21770  * OUTPUT:	ep	- Error information
12221623Stw21770  * RETURNS:	0 on success and -1 on failure.
12231623Stw21770  * PURPOSE:	Common code to delete an empty hot spare pool.
12241623Stw21770  */
12251623Stw21770 static int
meta_hsp_delete(mdsetname_t * sp,mdhspname_t * hspnp,mdcmdopts_t options,md_error_t * ep)12261623Stw21770 meta_hsp_delete(
12271623Stw21770 	mdsetname_t	*sp,
12281623Stw21770 	mdhspname_t	*hspnp,
12291623Stw21770 	mdcmdopts_t	options,
12301623Stw21770 	md_error_t	*ep
12311623Stw21770 )
12321623Stw21770 {
12331623Stw21770 	set_hs_params_t	shs;
12341623Stw21770 
12351623Stw21770 	/* setup hotspare pool info */
12361623Stw21770 	(void) memset(&shs, 0, sizeof (shs));
12371623Stw21770 	shs.shs_hot_spare_pool = hspnp->hsp;
12381623Stw21770 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
12391623Stw21770 	shs.shs_cmd = DELETE_HOT_SPARE;
12401623Stw21770 	shs.shs_options = HS_OPT_POOL;
12411623Stw21770 	/* If DOIT is not set, it's a dryrun */
12421623Stw21770 	if ((options & MDCMD_DOIT) == 0) {
12431623Stw21770 		shs.shs_options |= HS_OPT_DRYRUN;
12441623Stw21770 	}
12451623Stw21770 
12461623Stw21770 	/* Remove hsp record. */
12471623Stw21770 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
12481623Stw21770 	    hspnp->hspname) != 0)
12491623Stw21770 		return (mdstealerror(ep, &shs.mde));
12501623Stw21770 
12511623Stw21770 	/* Get rid of hsp NM records */
12521623Stw21770 	if ((options & MDCMD_DOIT) &&
12531623Stw21770 		(del_hsp_keys(sp, hspnp->hsp, ep) == -1)) {
12541623Stw21770 		return (-1);
12551623Stw21770 	}
12561623Stw21770 	return (0);
12571623Stw21770 }
12581623Stw21770 
12591623Stw21770 /*
12600Sstevel@tonic-gate  * delete hotspares from pool
12610Sstevel@tonic-gate  */
12620Sstevel@tonic-gate int
meta_hs_delete(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)12630Sstevel@tonic-gate meta_hs_delete(
12640Sstevel@tonic-gate 	mdsetname_t	*sp,
12650Sstevel@tonic-gate 	mdhspname_t	*hspnp,
12660Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
12670Sstevel@tonic-gate 	mdcmdopts_t	options,
12680Sstevel@tonic-gate 	md_error_t	*ep
12690Sstevel@tonic-gate )
12700Sstevel@tonic-gate {
12710Sstevel@tonic-gate 	mdnamelist_t	*p;
12720Sstevel@tonic-gate 	set_hs_params_t	shs;
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	/* should have a set */
12750Sstevel@tonic-gate 	assert(sp != NULL);
12761623Stw21770 	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	/* clear cache */
12790Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	/* setup hotspare pool info */
12820Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
12830Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
12840Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
12850Sstevel@tonic-gate 	shs.shs_cmd = DELETE_HOT_SPARE;
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	/* delete empty hotspare pool */
12880Sstevel@tonic-gate 	if (hsnlp == NULL) {
12891623Stw21770 		if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
12901623Stw21770 			return (-1);
12910Sstevel@tonic-gate 		goto success;
12920Sstevel@tonic-gate 	}
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	/* delete hotspares */
12950Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
12960Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
12970Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
12980Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
12990Sstevel@tonic-gate 	}
13000Sstevel@tonic-gate 	for (p = hsnlp; (p != NULL); p = p->next) {
13010Sstevel@tonic-gate 		mdname_t	*hsnp = p->namep;
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 		/* should be in same set */
13041623Stw21770 		assert(hspnp->hsp == MD_HSP_NONE ||
13051623Stw21770 		    sp->setno == HSP_SET(hspnp->hsp));
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 		/* delete hotspare */
13080Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
13090Sstevel@tonic-gate 		meta_invalidate_name(hsnp);
13100Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0)
13110Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	/* print success message */
13150Sstevel@tonic-gate success:
13160Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
13170Sstevel@tonic-gate 		if (hsnlp == NULL) {
13180Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
13190Sstevel@tonic-gate 			    "%s: Hotspare pool is cleared\n"),
13200Sstevel@tonic-gate 			    hspnp->hspname);
13210Sstevel@tonic-gate 		} else if (hsnlp->next == NULL) {
13220Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
13230Sstevel@tonic-gate 			    "%s: Hotspare is deleted\n"),
13240Sstevel@tonic-gate 			    hspnp->hspname);
13250Sstevel@tonic-gate 		} else {
13260Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
13270Sstevel@tonic-gate 			    "%s: Hotspares are deleted\n"),
13280Sstevel@tonic-gate 			    hspnp->hspname);
13290Sstevel@tonic-gate 		}
13300Sstevel@tonic-gate 		(void) fflush(stdout);
13310Sstevel@tonic-gate 	}
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	/* return success */
13340Sstevel@tonic-gate 	return (0);
13350Sstevel@tonic-gate }
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate /*
13380Sstevel@tonic-gate  * replace hotspare in pool
13390Sstevel@tonic-gate  */
13400Sstevel@tonic-gate int
meta_hs_replace(mdsetname_t * sp,mdhspname_t * hspnp,mdname_t * oldnp,mdname_t * newnp,mdcmdopts_t options,md_error_t * ep)13410Sstevel@tonic-gate meta_hs_replace(
13420Sstevel@tonic-gate 	mdsetname_t	*sp,
13430Sstevel@tonic-gate 	mdhspname_t	*hspnp,
13440Sstevel@tonic-gate 	mdname_t	*oldnp,
13450Sstevel@tonic-gate 	mdname_t	*newnp,
13460Sstevel@tonic-gate 	mdcmdopts_t	options,
13470Sstevel@tonic-gate 	md_error_t	*ep
13480Sstevel@tonic-gate )
13490Sstevel@tonic-gate {
13500Sstevel@tonic-gate 	set_hs_params_t	shs;
13510Sstevel@tonic-gate 	diskaddr_t	size, label, start_blk;
13520Sstevel@tonic-gate 	md_dev64_t	old_dev, new_dev;
13530Sstevel@tonic-gate 	diskaddr_t	new_start_blk, new_end_blk;
13540Sstevel@tonic-gate 	int		rebind;
13550Sstevel@tonic-gate 	char		*new_devidp = NULL;
13560Sstevel@tonic-gate 	int		ret;
13570Sstevel@tonic-gate 	md_set_desc	*sd;
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	/* should be in same set */
13600Sstevel@tonic-gate 	assert(sp != NULL);
13611623Stw21770 	assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	/* save new binding incase this is a rebind where oldnp==newnp */
13640Sstevel@tonic-gate 	new_dev = newnp->dev;
13650Sstevel@tonic-gate 	new_start_blk = newnp->start_blk;
13660Sstevel@tonic-gate 	new_end_blk = newnp->end_blk;
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	/* invalidate, then get the hotspare (fill in oldnp from metadb) */
13690Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
13700Sstevel@tonic-gate 	if (meta_get_hsp(sp, hspnp, ep) == NULL)
13710Sstevel@tonic-gate 		return (-1);
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	/* the old device binding is now established */
13740Sstevel@tonic-gate 	if ((old_dev = oldnp->dev) == NODEV64)
13750Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, oldnp->cname));
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	/*
13780Sstevel@tonic-gate 	 * check for the case where oldnp and newnp indicate the same
13790Sstevel@tonic-gate 	 * device, but the dev_t of the device has changed between old
13800Sstevel@tonic-gate 	 * and new.  This is called a rebind.  On entry the dev_t
13810Sstevel@tonic-gate 	 * represents the new device binding determined from the
13820Sstevel@tonic-gate 	 * filesystem (meta_getdev). After calling meta_get_hsp
13830Sstevel@tonic-gate 	 * oldnp (and maybe newnp if this is a rebind) is updated based
13840Sstevel@tonic-gate 	 * to the old binding from the metadb (done by metakeyname).
13850Sstevel@tonic-gate 	 */
13860Sstevel@tonic-gate 	if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
13870Sstevel@tonic-gate 	    (old_dev != new_dev)) {
13880Sstevel@tonic-gate 		rebind = 1;
13890Sstevel@tonic-gate 	} else {
13900Sstevel@tonic-gate 		rebind = 0;
13910Sstevel@tonic-gate 	}
13920Sstevel@tonic-gate 	if (rebind) {
13930Sstevel@tonic-gate 		newnp->dev = new_dev;
13940Sstevel@tonic-gate 		newnp->start_blk = new_start_blk;
13950Sstevel@tonic-gate 		newnp->end_blk = new_end_blk;
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	/*
13990Sstevel@tonic-gate 	 * Save a copy of the devid associated with the new disk, the reason
14000Sstevel@tonic-gate 	 * is that the meta_check_hotspare() call could cause the devid to
14010Sstevel@tonic-gate 	 * be changed to that of the devid that is currently stored in the
14020Sstevel@tonic-gate 	 * replica namespace for the disk in question. This devid could be
14030Sstevel@tonic-gate 	 * stale if we are replacing the disk. The function that overwrites
14040Sstevel@tonic-gate 	 * the devid is dr2drivedesc().
14050Sstevel@tonic-gate 	 */
14060Sstevel@tonic-gate 	if (newnp->drivenamep->devid != NULL)
14070Sstevel@tonic-gate 		new_devidp = Strdup(newnp->drivenamep->devid);
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	/* if it's a multi-node diskset clear new_devidp */
14100Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
14110Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
14120Sstevel@tonic-gate 			Free(new_devidp);
14130Sstevel@tonic-gate 			return (-1);
14140Sstevel@tonic-gate 		}
14150Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
14160Sstevel@tonic-gate 			Free(new_devidp);
14170Sstevel@tonic-gate 			new_devidp = NULL;
14180Sstevel@tonic-gate 		}
14190Sstevel@tonic-gate 	}
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 	/* check it out */
14220Sstevel@tonic-gate 	if (meta_check_hotspare(sp, newnp, ep) != 0) {
14230Sstevel@tonic-gate 		if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
14240Sstevel@tonic-gate 			Free(new_devidp);
14250Sstevel@tonic-gate 			return (-1);
14260Sstevel@tonic-gate 		}
14270Sstevel@tonic-gate 		mdclrerror(ep);
14280Sstevel@tonic-gate 	}
14290Sstevel@tonic-gate 	if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
14300Sstevel@tonic-gate 		Free(new_devidp);
14310Sstevel@tonic-gate 		return (-1);
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 	if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
14340Sstevel@tonic-gate 		Free(new_devidp);
14350Sstevel@tonic-gate 		return (-1);
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 	if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
14380Sstevel@tonic-gate 		Free(new_devidp);
14390Sstevel@tonic-gate 		return (-1);
14400Sstevel@tonic-gate 	}
14410Sstevel@tonic-gate 	if (start_blk >= size) {
14420Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, newnp->cname);
14430Sstevel@tonic-gate 		Free(new_devidp);
14440Sstevel@tonic-gate 		return (-1);
14450Sstevel@tonic-gate 	}
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	/*
14480Sstevel@tonic-gate 	 * Copy back the saved devid.
14490Sstevel@tonic-gate 	 */
14500Sstevel@tonic-gate 	Free(newnp->drivenamep->devid);
14510Sstevel@tonic-gate 	if (new_devidp != NULL) {
14520Sstevel@tonic-gate 		newnp->drivenamep->devid = new_devidp;
14530Sstevel@tonic-gate 		new_devidp = NULL;
14540Sstevel@tonic-gate 	}
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
14570Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
14580Sstevel@tonic-gate 		/* store name in namespace */
14590Sstevel@tonic-gate 		if (add_key_name(sp, newnp, NULL, ep) != 0)
14600Sstevel@tonic-gate 			return (-1);
14610Sstevel@tonic-gate 	}
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	if (rebind && !metaislocalset(sp)) {
14640Sstevel@tonic-gate 		/*
14650Sstevel@tonic-gate 		 * We are 'rebind'ing a disk that is in a diskset so as well
14660Sstevel@tonic-gate 		 * as updating the diskset's namespace the local set needs
14670Sstevel@tonic-gate 		 * to be updated because it also contains a reference to the
14680Sstevel@tonic-gate 		 * disk in question.
14690Sstevel@tonic-gate 		 */
14700Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname,
14710Sstevel@tonic-gate 		    ep);
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
14740Sstevel@tonic-gate 			md_error_t	xep = mdnullerror;
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 			/*
14770Sstevel@tonic-gate 			 * In dryrun mode (DOIT not set) we must not alter
14780Sstevel@tonic-gate 			 * the mddb
14790Sstevel@tonic-gate 			 */
14800Sstevel@tonic-gate 			if (options & MDCMD_DOIT) {
14810Sstevel@tonic-gate 				(void) del_key_name(sp, newnp, &xep);
14820Sstevel@tonic-gate 				mdclrerror(&xep);
14830Sstevel@tonic-gate 				return (-1);
14840Sstevel@tonic-gate 			}
14850Sstevel@tonic-gate 		}
14860Sstevel@tonic-gate 	}
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	/* replace hotspare */
14890Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	shs.shs_size_option = meta_check_devicesize(size);
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	shs.shs_cmd = REPLACE_HOT_SPARE;
14940Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
14950Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
14960Sstevel@tonic-gate 	shs.shs_component_old = old_dev;
14970Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
14980Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
14990Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
15000Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
15010Sstevel@tonic-gate 	}
15020Sstevel@tonic-gate 	shs.shs_component_new = new_dev;
15030Sstevel@tonic-gate 	shs.shs_start_blk = start_blk;
15040Sstevel@tonic-gate 	shs.shs_has_label = ((label > 0) ? 1 : 0);
15050Sstevel@tonic-gate 	shs.shs_number_blks = size;
15060Sstevel@tonic-gate 	shs.shs_key_new = newnp->key;
15070Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
15080Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
15090Sstevel@tonic-gate 			(void) del_key_name(sp, newnp, ep);
15100Sstevel@tonic-gate 		}
15110Sstevel@tonic-gate 		return (mdstealerror(ep, &shs.mde));
15120Sstevel@tonic-gate 	}
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 	/* clear cache */
15150Sstevel@tonic-gate 	meta_invalidate_name(oldnp);
15160Sstevel@tonic-gate 	meta_invalidate_name(newnp);
15170Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	/* let em know */
15200Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
15210Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
15220Sstevel@tonic-gate 		    "%s: Hotspare %s is replaced with %s\n"),
15230Sstevel@tonic-gate 		    hspnp->hspname, oldnp->cname, newnp->cname);
15240Sstevel@tonic-gate 		(void) fflush(stdout);
15250Sstevel@tonic-gate 	}
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 	/* return success */
15280Sstevel@tonic-gate 	return (0);
15290Sstevel@tonic-gate }
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate /*
15320Sstevel@tonic-gate  * enable hotspares
15330Sstevel@tonic-gate  */
15340Sstevel@tonic-gate int
meta_hs_enable(mdsetname_t * sp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)15350Sstevel@tonic-gate meta_hs_enable(
15360Sstevel@tonic-gate 	mdsetname_t	*sp,
15370Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
15380Sstevel@tonic-gate 	mdcmdopts_t	options,
15390Sstevel@tonic-gate 	md_error_t	*ep
15400Sstevel@tonic-gate )
15410Sstevel@tonic-gate {
15420Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
15430Sstevel@tonic-gate 	mdhspnamelist_t	*hspnp;
15440Sstevel@tonic-gate 	set_hs_params_t	shs;
15450Sstevel@tonic-gate 	int		rval = -1;
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 	/* should have a set */
15480Sstevel@tonic-gate 	assert(sp != NULL);
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	/* setup device info */
15510Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
15520Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
15530Sstevel@tonic-gate 	shs.shs_cmd = FIX_HOT_SPARE;
15540Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
15550Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
15560Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
15570Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
15580Sstevel@tonic-gate 	}
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	/* get the list of hotspare names */
15610Sstevel@tonic-gate 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
15620Sstevel@tonic-gate 		goto out;
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	/* enable hotspares for each components */
15650Sstevel@tonic-gate 	for (; (hsnlp != NULL); hsnlp = hsnlp->next) {
15660Sstevel@tonic-gate 		mdname_t	*hsnp = hsnlp->namep;
15670Sstevel@tonic-gate 		md_dev64_t	fs_dev;
15680Sstevel@tonic-gate 		int		rebind = 0;
15690Sstevel@tonic-gate 		diskaddr_t	size, label, start_blk;
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 		/* get the file_system dev binding */
15720Sstevel@tonic-gate 		if (meta_getdev(sp, hsnp, ep) != 0)
15730Sstevel@tonic-gate 			return (-1);
15740Sstevel@tonic-gate 		fs_dev = hsnp->dev;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 		/*
15770Sstevel@tonic-gate 		 * search for the component in each hotspare pool
15780Sstevel@tonic-gate 		 * and replace it (instead of enable) if the binding
15790Sstevel@tonic-gate 		 * has changed.
15800Sstevel@tonic-gate 		 */
15810Sstevel@tonic-gate 		for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
15820Sstevel@tonic-gate 			/*
15830Sstevel@tonic-gate 			 * in_hsp will call meta_get_hsp which will fill
15840Sstevel@tonic-gate 			 * in hspnp with metadb version of component
15850Sstevel@tonic-gate 			 */
15860Sstevel@tonic-gate 			meta_invalidate_hsp(hspnp->hspnamep);
15870Sstevel@tonic-gate 			if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) {
15880Sstevel@tonic-gate 				/*
15890Sstevel@tonic-gate 				 * check for the case where the dev_t has
15900Sstevel@tonic-gate 				 * changed between the filesystem and the
15910Sstevel@tonic-gate 				 * metadb.  This is called a rebind, and
15920Sstevel@tonic-gate 				 * is handled by meta_hs_replace.
15930Sstevel@tonic-gate 				 */
15940Sstevel@tonic-gate 				if (fs_dev != hsnp->dev) {
15950Sstevel@tonic-gate 					/*
15960Sstevel@tonic-gate 					 * establish file system binding
15970Sstevel@tonic-gate 					 * with invalid start/end
15980Sstevel@tonic-gate 					 */
15990Sstevel@tonic-gate 					rebind++;
16000Sstevel@tonic-gate 					hsnp->dev = fs_dev;
16010Sstevel@tonic-gate 					hsnp->start_blk = -1;
16020Sstevel@tonic-gate 					hsnp->end_blk = -1;
16030Sstevel@tonic-gate 					rval = meta_hs_replace(sp,
16040Sstevel@tonic-gate 					    hspnp->hspnamep,
16050Sstevel@tonic-gate 					    hsnp, hsnp, options, ep);
16060Sstevel@tonic-gate 					if (rval != 0)
16070Sstevel@tonic-gate 						goto out;
16080Sstevel@tonic-gate 				}
16090Sstevel@tonic-gate 			}
16100Sstevel@tonic-gate 		}
16110Sstevel@tonic-gate 		if (rebind)
16120Sstevel@tonic-gate 			continue;
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 		/* enable the component in all hotspares that use it */
16150Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
16160Sstevel@tonic-gate 			goto out;
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
16190Sstevel@tonic-gate 			goto out;
16200Sstevel@tonic-gate 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
16210Sstevel@tonic-gate 			goto out;
16220Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, hsnp, ep))
16230Sstevel@tonic-gate 		    == MD_DISKADDR_ERROR)
16240Sstevel@tonic-gate 			goto out;
16250Sstevel@tonic-gate 		if (start_blk >= size) {
16260Sstevel@tonic-gate 			(void) mdsyserror(ep, ENOSPC, hsnp->cname);
16270Sstevel@tonic-gate 			goto out;
16280Sstevel@tonic-gate 		}
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 		/* enable hotspare */
16310Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
16320Sstevel@tonic-gate 		shs.shs_component_new = hsnp->dev;
16330Sstevel@tonic-gate 		shs.shs_start_blk = start_blk;
16340Sstevel@tonic-gate 		shs.shs_has_label = ((label > 0) ? 1 : 0);
16350Sstevel@tonic-gate 		shs.shs_number_blks = size;
16360Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) {
16370Sstevel@tonic-gate 			rval = mdstealerror(ep, &shs.mde);
16380Sstevel@tonic-gate 			goto out;
16390Sstevel@tonic-gate 		}
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 		/*
16420Sstevel@tonic-gate 		 * Are we dealing with a non-local set? If so need to update
16430Sstevel@tonic-gate 		 * the local namespace so that the disk record has the correct
16440Sstevel@tonic-gate 		 * devid.
16450Sstevel@tonic-gate 		 */
16460Sstevel@tonic-gate 		if (!metaislocalset(sp)) {
16470Sstevel@tonic-gate 			rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
16480Sstevel@tonic-gate 			    hsnp->cname, ep);
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 			if (rval != METADEVADM_SUCCESS) {
16510Sstevel@tonic-gate 				/*
16520Sstevel@tonic-gate 				 * Failed to update the local set. Nothing to
16530Sstevel@tonic-gate 				 * do here apart from report the error. The
16540Sstevel@tonic-gate 				 * namespace is most likely broken and some
16550Sstevel@tonic-gate 				 * form of remedial recovery is going to
16560Sstevel@tonic-gate 				 * be required.
16570Sstevel@tonic-gate 				 */
16580Sstevel@tonic-gate 				mde_perror(ep, "");
16590Sstevel@tonic-gate 				mdclrerror(ep);
16600Sstevel@tonic-gate 			}
16610Sstevel@tonic-gate 		}
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 		/* clear cache */
16640Sstevel@tonic-gate 		meta_invalidate_name(hsnp);
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 		/* let em know */
16670Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
16680Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
16690Sstevel@tonic-gate 			    "hotspare %s is enabled\n"),
16700Sstevel@tonic-gate 			    hsnp->cname);
16710Sstevel@tonic-gate 			(void) fflush(stdout);
16720Sstevel@tonic-gate 		}
16730Sstevel@tonic-gate 	}
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	/* clear whole cache */
16760Sstevel@tonic-gate 	for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
16770Sstevel@tonic-gate 		meta_invalidate_hsp(hspnp->hspnamep);
16780Sstevel@tonic-gate 	}
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 	/* return success */
16820Sstevel@tonic-gate 	rval = 0;
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate out:
16850Sstevel@tonic-gate 	if (hspnlp)
16860Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
16870Sstevel@tonic-gate 	return (rval);
16880Sstevel@tonic-gate }
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate /*
16910Sstevel@tonic-gate  * check for dups in the hsp itself
16920Sstevel@tonic-gate  */
16930Sstevel@tonic-gate static int
check_twice(md_hsp_t * hspp,uint_t hsi,md_error_t * ep)16940Sstevel@tonic-gate check_twice(
16950Sstevel@tonic-gate 	md_hsp_t	*hspp,
16960Sstevel@tonic-gate 	uint_t		hsi,
16970Sstevel@tonic-gate 	md_error_t	*ep
16980Sstevel@tonic-gate )
16990Sstevel@tonic-gate {
17000Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
17010Sstevel@tonic-gate 	mdname_t	*thisnp;
17020Sstevel@tonic-gate 	uint_t		h;
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep;
17050Sstevel@tonic-gate 	for (h = 0; (h < hsi); ++h) {
17060Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[h];
17070Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 		if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1,
17100Sstevel@tonic-gate 		    hsnp, 0, -1, ep) != 0)
17110Sstevel@tonic-gate 			return (-1);
17120Sstevel@tonic-gate 	}
17130Sstevel@tonic-gate 	return (0);
17140Sstevel@tonic-gate }
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate /*
17170Sstevel@tonic-gate  * check hsp
17180Sstevel@tonic-gate  */
17190Sstevel@tonic-gate /*ARGSUSED2*/
17200Sstevel@tonic-gate int
meta_check_hsp(mdsetname_t * sp,md_hsp_t * hspp,mdcmdopts_t options,md_error_t * ep)17210Sstevel@tonic-gate meta_check_hsp(
17220Sstevel@tonic-gate 	mdsetname_t	*sp,
17230Sstevel@tonic-gate 	md_hsp_t	*hspp,
17240Sstevel@tonic-gate 	mdcmdopts_t	options,
17250Sstevel@tonic-gate 	md_error_t	*ep
17260Sstevel@tonic-gate )
17270Sstevel@tonic-gate {
17280Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
17290Sstevel@tonic-gate 	uint_t		hsi;
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	/* check hotspares */
17320Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
17330Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
17340Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
17350Sstevel@tonic-gate 		diskaddr_t	size;
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 		/* check hotspare */
17380Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
17390Sstevel@tonic-gate 			return (-1);
17400Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) {
17410Sstevel@tonic-gate 			return (-1);
17420Sstevel@tonic-gate 		} else if (size == 0) {
17430Sstevel@tonic-gate 			return (mdsyserror(ep, ENOSPC, hspnp->hspname));
17440Sstevel@tonic-gate 		}
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 		/* check this hsp too */
17470Sstevel@tonic-gate 		if (check_twice(hspp, hsi, ep) != 0)
17480Sstevel@tonic-gate 			return (-1);
17490Sstevel@tonic-gate 	}
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 	/* return success */
17520Sstevel@tonic-gate 	return (0);
17530Sstevel@tonic-gate }
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate /*
17560Sstevel@tonic-gate  * create hsp
17570Sstevel@tonic-gate  */
17580Sstevel@tonic-gate int
meta_create_hsp(mdsetname_t * sp,md_hsp_t * hspp,mdcmdopts_t options,md_error_t * ep)17590Sstevel@tonic-gate meta_create_hsp(
17600Sstevel@tonic-gate 	mdsetname_t	*sp,
17610Sstevel@tonic-gate 	md_hsp_t	*hspp,
17620Sstevel@tonic-gate 	mdcmdopts_t	options,
17630Sstevel@tonic-gate 	md_error_t	*ep
17640Sstevel@tonic-gate )
17650Sstevel@tonic-gate {
17660Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
17670Sstevel@tonic-gate 	mdnamelist_t	*hsnlp = NULL;
17680Sstevel@tonic-gate 	uint_t		hsi;
17690Sstevel@tonic-gate 	int		rval = -1;
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	/* validate hsp */
17720Sstevel@tonic-gate 	if (meta_check_hsp(sp, hspp, options, ep) != 0)
17730Sstevel@tonic-gate 		return (-1);
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	/* if we're not doing anything, return success */
17760Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT))
17770Sstevel@tonic-gate 		return (0);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	/* create hsp */
17800Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
17810Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
17820Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 		(void) metanamelist_append(&hsnlp, hsnp);
17850Sstevel@tonic-gate 	}
17860Sstevel@tonic-gate 	options |= MDCMD_INIT;
17870Sstevel@tonic-gate 	rval = meta_hs_add(sp, hspnp, hsnlp, options, ep);
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 	/* cleanup, return success */
17900Sstevel@tonic-gate 	metafreenamelist(hsnlp);
17910Sstevel@tonic-gate 	return (rval);
17920Sstevel@tonic-gate }
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate /*
17950Sstevel@tonic-gate  * initialize hsp
17960Sstevel@tonic-gate  * NOTE: this functions is metainit(1m)'s command line parser!
17970Sstevel@tonic-gate  */
17980Sstevel@tonic-gate int
meta_init_hsp(mdsetname_t ** spp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)17990Sstevel@tonic-gate meta_init_hsp(
18000Sstevel@tonic-gate 	mdsetname_t	**spp,
18010Sstevel@tonic-gate 	int		argc,
18020Sstevel@tonic-gate 	char		*argv[],
18030Sstevel@tonic-gate 	mdcmdopts_t	options,
18040Sstevel@tonic-gate 	md_error_t	*ep
18050Sstevel@tonic-gate )
18060Sstevel@tonic-gate {
18070Sstevel@tonic-gate 	char		*uname = argv[0];
18080Sstevel@tonic-gate 	mdhspname_t	*hspnp = NULL;
18090Sstevel@tonic-gate 	md_hsp_t	*hspp = NULL;
18100Sstevel@tonic-gate 	uint_t		hsi;
18110Sstevel@tonic-gate 	int		rval = -1;
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 	/* get hsp name */
18150Sstevel@tonic-gate 	assert(argc > 0);
18160Sstevel@tonic-gate 	if (argc < 1)
18170Sstevel@tonic-gate 		goto syntax;
18180Sstevel@tonic-gate 	if ((hspnp = metahspname(spp, uname, ep)) == NULL)
18190Sstevel@tonic-gate 		goto out;
18200Sstevel@tonic-gate 	assert(*spp != NULL);
18210Sstevel@tonic-gate 	uname = hspnp->hspname;
18220Sstevel@tonic-gate 
18230Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
18240Sstevel@tonic-gate 		/* grab set lock */
18250Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep))
18260Sstevel@tonic-gate 			goto out;
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
18290Sstevel@tonic-gate 			goto out;
18300Sstevel@tonic-gate 	}
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 	/* see if it exists already */
1833*2099Stn143363 	if (is_existing_metadevice(*spp, uname)) {
1834*2099Stn143363 		mdname_t	*np;
1835*2099Stn143363 		if ((np = metaname(spp, uname, META_DEVICE, ep)) != NULL)
1836*2099Stn143363 			if ((meta_get_unit(*spp, np, ep)) != NULL)
1837*2099Stn143363 				return (mderror(ep, MDE_NAME_IN_USE, uname));
1838*2099Stn143363 	}
1839*2099Stn143363 
18400Sstevel@tonic-gate 	if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
18411623Stw21770 		(void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP,
18421623Stw21770 		    hspnp->hsp, uname);
18430Sstevel@tonic-gate 		goto out;
18440Sstevel@tonic-gate 	} else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
18450Sstevel@tonic-gate 		goto out;
18460Sstevel@tonic-gate 	} else {
18470Sstevel@tonic-gate 		mdclrerror(ep);
18480Sstevel@tonic-gate 	}
18490Sstevel@tonic-gate 	--argc, ++argv;
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	/* parse general options */
18520Sstevel@tonic-gate 	optind = 0;
18530Sstevel@tonic-gate 	opterr = 0;
18540Sstevel@tonic-gate 	if (getopt(argc, argv, "") != -1)
18550Sstevel@tonic-gate 		goto options;
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	/* allocate hsp */
18580Sstevel@tonic-gate 	hspp = Zalloc(sizeof (*hspp));
18590Sstevel@tonic-gate 	hspp->hotspares.hotspares_len = argc;
18600Sstevel@tonic-gate 	if (argc > 0) {
18610Sstevel@tonic-gate 		hspp->hotspares.hotspares_val =
18620Sstevel@tonic-gate 		    Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
18630Sstevel@tonic-gate 	}
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 	/* setup pool */
18660Sstevel@tonic-gate 	hspp->hspnamep = hspnp;
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	/* parse hotspares */
18690Sstevel@tonic-gate 	for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
18700Sstevel@tonic-gate 	    ++hsi) {
18710Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
18720Sstevel@tonic-gate 		mdname_t	*hsnamep;
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 		/* parse hotspare name */
18751623Stw21770 		if ((hsnamep = metaname(spp, argv[0],
18761623Stw21770 		    LOGICAL_DEVICE, ep)) == NULL)
18770Sstevel@tonic-gate 			goto out;
18780Sstevel@tonic-gate 		hsp->hsnamep = hsnamep;
18790Sstevel@tonic-gate 		--argc, ++argv;
18800Sstevel@tonic-gate 	}
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 	/* we should be at the end */
18830Sstevel@tonic-gate 	if (argc != 0)
18840Sstevel@tonic-gate 		goto syntax;
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	/* create hotspare pool */
18870Sstevel@tonic-gate 	if (meta_create_hsp(*spp, hspp, options, ep) != 0)
18880Sstevel@tonic-gate 		goto out;
18890Sstevel@tonic-gate 	rval = 0;	/* success */
18900Sstevel@tonic-gate 	goto out;
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	/* syntax error */
18930Sstevel@tonic-gate syntax:
18940Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
18950Sstevel@tonic-gate 	goto out;
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 	/* options error */
18980Sstevel@tonic-gate options:
18990Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
19000Sstevel@tonic-gate 	goto out;
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	/* cleanup, return error */
19030Sstevel@tonic-gate out:
19040Sstevel@tonic-gate 	if (hspp != NULL)
19050Sstevel@tonic-gate 		meta_free_hsp(hspp);
19060Sstevel@tonic-gate 	return (rval);
19070Sstevel@tonic-gate }
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate /*
19100Sstevel@tonic-gate  * reset hotspare pool
19110Sstevel@tonic-gate  */
19120Sstevel@tonic-gate int
meta_hsp_reset(mdsetname_t * sp,mdhspname_t * hspnp,mdcmdopts_t options,md_error_t * ep)19130Sstevel@tonic-gate meta_hsp_reset(
19140Sstevel@tonic-gate 	mdsetname_t	*sp,
19150Sstevel@tonic-gate 	mdhspname_t	*hspnp,
19160Sstevel@tonic-gate 	mdcmdopts_t	options,
19170Sstevel@tonic-gate 	md_error_t	*ep
19180Sstevel@tonic-gate )
19190Sstevel@tonic-gate {
19200Sstevel@tonic-gate 	md_hsp_t	*hspp;
19210Sstevel@tonic-gate 	set_hs_params_t	shs;
19220Sstevel@tonic-gate 	uint_t		i;
19230Sstevel@tonic-gate 	int		rval = -1;
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 	/* should have the same set */
19260Sstevel@tonic-gate 	assert(sp != NULL);
19271623Stw21770 	assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
19281623Stw21770 	    sp->setno == HSP_SET(hspnp->hsp));
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 	/* reset all hotspares */
19310Sstevel@tonic-gate 	if (hspnp == NULL) {
19320Sstevel@tonic-gate 		mdhspnamelist_t	*hspnlp = NULL;
19330Sstevel@tonic-gate 		mdhspnamelist_t	*p;
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 		/* for each hotspare pool */
19360Sstevel@tonic-gate 		rval = 0;
19370Sstevel@tonic-gate 		if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
19380Sstevel@tonic-gate 			return (-1);
19390Sstevel@tonic-gate 		for (p = hspnlp; (p != NULL); p = p->next) {
19400Sstevel@tonic-gate 			/* reset hotspare pool */
19410Sstevel@tonic-gate 			hspnp = p->hspnamep;
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 			/*
19440Sstevel@tonic-gate 			 * If this is a multi-node set, we send a series
19450Sstevel@tonic-gate 			 * of individual metaclear commands.
19460Sstevel@tonic-gate 			 */
19470Sstevel@tonic-gate 			if (meta_is_mn_set(sp, ep)) {
19480Sstevel@tonic-gate 				if (meta_mn_send_metaclear_command(sp,
19490Sstevel@tonic-gate 				    hspnp->hspname, options, 0, ep) != 0) {
19500Sstevel@tonic-gate 					rval = -1;
19510Sstevel@tonic-gate 					break;
19520Sstevel@tonic-gate 				}
19530Sstevel@tonic-gate 			} else {
19540Sstevel@tonic-gate 				if (meta_hsp_reset(sp, hspnp, options,
19550Sstevel@tonic-gate 				    ep) != 0) {
19560Sstevel@tonic-gate 					rval = -1;
19570Sstevel@tonic-gate 					break;
19580Sstevel@tonic-gate 				}
19590Sstevel@tonic-gate 			}
19600Sstevel@tonic-gate 		}
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 		/* cleanup, return success */
19630Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
19640Sstevel@tonic-gate 		return (rval);
19650Sstevel@tonic-gate 	}
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	/* get unit structure */
19680Sstevel@tonic-gate 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
19690Sstevel@tonic-gate 		return (-1);
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	/* make sure nobody owns us */
19720Sstevel@tonic-gate 	if (hspp->refcount > 0) {
19730Sstevel@tonic-gate 		return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
19740Sstevel@tonic-gate 		    hspnp->hspname));
19750Sstevel@tonic-gate 	}
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	/* clear hotspare pool members */
19780Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
19790Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
19800Sstevel@tonic-gate 	shs.shs_cmd = DELETE_HOT_SPARE;
19810Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
19820Sstevel@tonic-gate 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
19830Sstevel@tonic-gate 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
19840Sstevel@tonic-gate 		mdname_t	*hsnamep = hs->hsnamep;
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 		/* clear cache */
19870Sstevel@tonic-gate 		meta_invalidate_name(hsnamep);
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 		/* clear hotspare */
19900Sstevel@tonic-gate 		shs.shs_component_old = hsnamep->dev;
19910Sstevel@tonic-gate 		shs.shs_options = HS_OPT_FORCE;
19920Sstevel@tonic-gate 		/* If DOIT is not set, it's a dryrun */
19930Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) == 0) {
19940Sstevel@tonic-gate 			shs.shs_options |= HS_OPT_DRYRUN;
19950Sstevel@tonic-gate 		}
19960Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
19970Sstevel@tonic-gate 			(void) mdstealerror(ep, &shs.mde);
19980Sstevel@tonic-gate 			goto out;
19990Sstevel@tonic-gate 		}
20000Sstevel@tonic-gate 	}
20010Sstevel@tonic-gate 
20020Sstevel@tonic-gate 	/* clear hotspare pool */
20031623Stw21770 	if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
20040Sstevel@tonic-gate 		goto out;
20050Sstevel@tonic-gate 	rval = 0;	/* success */
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: Hotspare pool is cleared\n"),
20110Sstevel@tonic-gate 		    hspnp->hspname);
20120Sstevel@tonic-gate 		(void) fflush(stdout);
20130Sstevel@tonic-gate 	}
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	/* clear subdevices (nothing to do) */
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	/* cleanup, return success */
20180Sstevel@tonic-gate out:
20190Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
20200Sstevel@tonic-gate 	return (rval);
20210Sstevel@tonic-gate }
2022