10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*62Sjeanm  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
310Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
340Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
350Sstevel@tonic-gate #endif
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * hotspares utilities
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include <meta.h>
420Sstevel@tonic-gate #include <sys/lvm/md_hotspares.h>
430Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * FUNCTION:	meta_get_hsp_names()
480Sstevel@tonic-gate  * INPUT:	sp	- the set name to get hotspares from
490Sstevel@tonic-gate  *		options	- options from the command line
500Sstevel@tonic-gate  * OUTPUT:	hspnlpp	- list of all hotspare names
510Sstevel@tonic-gate  *		ep	- return error pointer
520Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
530Sstevel@tonic-gate  * PURPOSE:	returns a list of all hotspares in the metadb
540Sstevel@tonic-gate  *		for all devices in the specified set
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate /*ARGSUSED*/
570Sstevel@tonic-gate int
580Sstevel@tonic-gate meta_get_hsp_names(
590Sstevel@tonic-gate 	mdsetname_t	*sp,
600Sstevel@tonic-gate 	mdhspnamelist_t	**hspnlpp,
610Sstevel@tonic-gate 	int		options,
620Sstevel@tonic-gate 	md_error_t	*ep
630Sstevel@tonic-gate )
640Sstevel@tonic-gate {
650Sstevel@tonic-gate 	md_i_getnum_t	gn;		/* MD_IOCGET_NUM params */
660Sstevel@tonic-gate 	minor_t		*minors = NULL;
670Sstevel@tonic-gate 	minor_t		*m_ptr;
680Sstevel@tonic-gate 	int		i;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	/* we must have a set */
710Sstevel@tonic-gate 	assert(sp != NULL);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	(void) memset(&gn, 0, sizeof (gn));
740Sstevel@tonic-gate 	MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	/* get number of devices */
770Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
780Sstevel@tonic-gate 		if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
790Sstevel@tonic-gate 			mdclrerror(&gn.mde);
800Sstevel@tonic-gate 		} else {
810Sstevel@tonic-gate 			(void) mdstealerror(ep, &gn.mde);
820Sstevel@tonic-gate 			return (-1);
830Sstevel@tonic-gate 		}
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	if (gn.size > 0) {
870Sstevel@tonic-gate 		/* malloc minor number buffer to be filled by ioctl */
880Sstevel@tonic-gate 		if ((minors = (minor_t *)malloc(
890Sstevel@tonic-gate 				gn.size * sizeof (minor_t))) == 0) {
900Sstevel@tonic-gate 			return (ENOMEM);
910Sstevel@tonic-gate 		}
920Sstevel@tonic-gate 		gn.minors = (uintptr_t)minors;
930Sstevel@tonic-gate 		if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
940Sstevel@tonic-gate 			(void) mdstealerror(ep, &gn.mde);
950Sstevel@tonic-gate 			free(minors);
960Sstevel@tonic-gate 			return (-1);
970Sstevel@tonic-gate 		}
980Sstevel@tonic-gate 		m_ptr = minors;
990Sstevel@tonic-gate 		for (i = 0; i < gn.size; i++) {
1000Sstevel@tonic-gate 			mdhspname_t	*hspnp;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 			/* get name */
1040Sstevel@tonic-gate 			if ((hspnp = metahsphspname(&sp, *m_ptr, ep))
1050Sstevel@tonic-gate 					== NULL)
1060Sstevel@tonic-gate 				goto out;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 			/* append to list */
1090Sstevel@tonic-gate 			(void) metahspnamelist_append(hspnlpp, hspnp);
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 			/* next device */
1120Sstevel@tonic-gate 			m_ptr++;
1130Sstevel@tonic-gate 		}
1140Sstevel@tonic-gate 		free(minors);
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 	return (gn.size);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate out:
1190Sstevel@tonic-gate 	if (minors != NULL)
1200Sstevel@tonic-gate 		free(minors);
1210Sstevel@tonic-gate 	metafreehspnamelist(*hspnlpp);
1220Sstevel@tonic-gate 	*hspnlpp = NULL;
1230Sstevel@tonic-gate 	return (-1);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate  * get information of a specific hotspare pool from driver
1280Sstevel@tonic-gate  */
1290Sstevel@tonic-gate static get_hsp_t *
1300Sstevel@tonic-gate get_hspinfo(
1310Sstevel@tonic-gate 	mdsetname_t	*sp,
1320Sstevel@tonic-gate 	mdhspname_t	*hspnp,
1330Sstevel@tonic-gate 	md_error_t	*ep
1340Sstevel@tonic-gate )
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	md_i_get_t	mig;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	/* should have a set */
1390Sstevel@tonic-gate 	assert(sp != NULL);
1400Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	/* get size of unit structure */
1430Sstevel@tonic-gate 	(void) memset(&mig, 0, sizeof (mig));
1440Sstevel@tonic-gate 	MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno);
1450Sstevel@tonic-gate 	mig.id = hspnp->hsp;
1460Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
1470Sstevel@tonic-gate 		(void) mdstealerror(ep, &mig.mde);
1480Sstevel@tonic-gate 		return (NULL);
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	/* get actual unit structure */
1520Sstevel@tonic-gate 	assert(mig.size > 0);
1530Sstevel@tonic-gate 	mig.mdp = (uintptr_t)Zalloc(mig.size);
1540Sstevel@tonic-gate 	if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
1550Sstevel@tonic-gate 		(void) mdstealerror(ep, &mig.mde);
156*62Sjeanm 		Free((void *)(uintptr_t)mig.mdp);
1570Sstevel@tonic-gate 		return (NULL);
1580Sstevel@tonic-gate 	}
159*62Sjeanm 	return ((get_hsp_t *)(uintptr_t)mig.mdp);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate  * free hotspare pool unit
1640Sstevel@tonic-gate  */
1650Sstevel@tonic-gate void
1660Sstevel@tonic-gate meta_free_hsp(
1670Sstevel@tonic-gate 	md_hsp_t	*hspp
1680Sstevel@tonic-gate )
1690Sstevel@tonic-gate {
1700Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_val != NULL) {
1710Sstevel@tonic-gate 		assert(hspp->hotspares.hotspares_len > 0);
1720Sstevel@tonic-gate 		Free(hspp->hotspares.hotspares_val);
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 	Free(hspp);
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate /*
1780Sstevel@tonic-gate  * get hotspare pool unit (common)
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate md_hsp_t *
1810Sstevel@tonic-gate meta_get_hsp_common(
1820Sstevel@tonic-gate 	mdsetname_t	*sp,
1830Sstevel@tonic-gate 	mdhspname_t	*hspnp,
1840Sstevel@tonic-gate 	int		fast,
1850Sstevel@tonic-gate 	md_error_t	*ep
1860Sstevel@tonic-gate )
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	get_hsp_t	*ghsp;
1890Sstevel@tonic-gate 	md_hsp_t	*hspp;
1900Sstevel@tonic-gate 	uint_t		hsi;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	/* must have set */
1930Sstevel@tonic-gate 	assert(sp != NULL);
1940Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	/* short circuit */
1970Sstevel@tonic-gate 	if (hspnp->unitp != NULL)
1980Sstevel@tonic-gate 		return (hspnp->unitp);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/* get unit */
2010Sstevel@tonic-gate 	if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL)
2020Sstevel@tonic-gate 		return (NULL);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/* allocate hsp */
2050Sstevel@tonic-gate 	hspp = Zalloc(sizeof (*hspp));
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	/* allocate hotspares */
2080Sstevel@tonic-gate 	hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/* if empty hotspare pool, we are done */
2110Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_len != 0)
2120Sstevel@tonic-gate 		hspp->hotspares.hotspares_val =
2130Sstevel@tonic-gate 		    Zalloc(hspp->hotspares.hotspares_len *
2140Sstevel@tonic-gate 		    sizeof (*hspp->hotspares.hotspares_val));
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	/* get name, refcount */
2170Sstevel@tonic-gate 	hspp->hspnamep = hspnp;
2180Sstevel@tonic-gate 	hspp->refcount = ghsp->ghsp_refcount;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	/* get hotspares */
2210Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
2220Sstevel@tonic-gate 		mdkey_t		hs_key = ghsp->ghsp_hs_keys[hsi];
2230Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
2240Sstevel@tonic-gate 		get_hs_params_t	ghs;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 		/* get hotspare name */
2270Sstevel@tonic-gate 		hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep);
2280Sstevel@tonic-gate 		if (hsp->hsnamep == NULL)
2290Sstevel@tonic-gate 			goto out;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 		/* get hotspare state */
2320Sstevel@tonic-gate 		(void) memset(&ghs, 0, sizeof (ghs));
2330Sstevel@tonic-gate 		MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno);
2340Sstevel@tonic-gate 		ghs.ghs_key = hs_key;
2350Sstevel@tonic-gate 		if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) {
2360Sstevel@tonic-gate 			(void) mdstealerror(ep, &ghs.mde);
2370Sstevel@tonic-gate 			goto out;
2380Sstevel@tonic-gate 		}
2390Sstevel@tonic-gate 		hsp->state = ghs.ghs_state;
2400Sstevel@tonic-gate 		hsp->size = ghs.ghs_number_blks;
2410Sstevel@tonic-gate 		hsp->timestamp = ghs.ghs_timestamp;
2420Sstevel@tonic-gate 		hsp->revision = ghs.ghs_revision;
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/* cleanup, return success */
2460Sstevel@tonic-gate 	Free(ghsp);
2470Sstevel@tonic-gate 	hspnp->unitp = hspp;
2480Sstevel@tonic-gate 	return (hspp);
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	/* cleanup, return error */
2510Sstevel@tonic-gate out:
2520Sstevel@tonic-gate 	Free(ghsp);
2530Sstevel@tonic-gate 	meta_free_hsp(hspp);
2540Sstevel@tonic-gate 	return (NULL);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate  * get hotspare pool unit
2590Sstevel@tonic-gate  */
2600Sstevel@tonic-gate md_hsp_t *
2610Sstevel@tonic-gate meta_get_hsp(
2620Sstevel@tonic-gate 	mdsetname_t	*sp,
2630Sstevel@tonic-gate 	mdhspname_t	*hspnp,
2640Sstevel@tonic-gate 	md_error_t	*ep
2650Sstevel@tonic-gate )
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate 	return (meta_get_hsp_common(sp, hspnp, 0, ep));
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate /*
2710Sstevel@tonic-gate  * check hotspare pool for dev
2720Sstevel@tonic-gate  */
2730Sstevel@tonic-gate static int
2740Sstevel@tonic-gate in_hsp(
2750Sstevel@tonic-gate 	mdsetname_t	*sp,
2760Sstevel@tonic-gate 	mdhspname_t	*hspnp,
2770Sstevel@tonic-gate 	mdname_t	*np,
2780Sstevel@tonic-gate 	diskaddr_t	slblk,
2790Sstevel@tonic-gate 	diskaddr_t	nblks,
2800Sstevel@tonic-gate 	md_error_t	*ep
2810Sstevel@tonic-gate )
2820Sstevel@tonic-gate {
2830Sstevel@tonic-gate 	md_hsp_t	*hspp;
2840Sstevel@tonic-gate 	uint_t		i;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	/* should be in the same set */
2870Sstevel@tonic-gate 	assert(sp != NULL);
2880Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	/* get unit */
2910Sstevel@tonic-gate 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
2920Sstevel@tonic-gate 		return (-1);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/* look in hotspares */
2950Sstevel@tonic-gate 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
2960Sstevel@tonic-gate 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
2970Sstevel@tonic-gate 		mdname_t	*hsnp = hs->hsnamep;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 		/* check overlap */
3000Sstevel@tonic-gate 		if (metaismeta(hsnp))
3010Sstevel@tonic-gate 			continue;
3020Sstevel@tonic-gate 		if (meta_check_overlap(hspnp->hspname, np, slblk, nblks,
3030Sstevel@tonic-gate 		    hsnp, 0, -1, ep) != 0)
3040Sstevel@tonic-gate 			return (-1);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	/* return success */
3080Sstevel@tonic-gate 	return (0);
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate /*
3120Sstevel@tonic-gate  * check to see if we're in a hotspare pool
3130Sstevel@tonic-gate  */
3140Sstevel@tonic-gate int
3150Sstevel@tonic-gate meta_check_inhsp(
3160Sstevel@tonic-gate 	mdsetname_t	*sp,
3170Sstevel@tonic-gate 	mdname_t	*np,
3180Sstevel@tonic-gate 	diskaddr_t	slblk,
3190Sstevel@tonic-gate 	diskaddr_t	nblks,
3200Sstevel@tonic-gate 	md_error_t	*ep
3210Sstevel@tonic-gate )
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
3240Sstevel@tonic-gate 	mdhspnamelist_t	*p;
3250Sstevel@tonic-gate 	int		rval = 0;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	/* should have a set */
3280Sstevel@tonic-gate 	assert(sp != NULL);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	/* for each hotspare pool */
3310Sstevel@tonic-gate 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
3320Sstevel@tonic-gate 		return (-1);
3330Sstevel@tonic-gate 	for (p = hspnlp; (p != NULL); p = p->next) {
3340Sstevel@tonic-gate 		mdhspname_t	*hspnp = p->hspnamep;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 		/* check hotspare pool */
3370Sstevel@tonic-gate 		if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) {
3380Sstevel@tonic-gate 			rval = -1;
3390Sstevel@tonic-gate 			break;
3400Sstevel@tonic-gate 		}
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/* cleanup, return success */
3440Sstevel@tonic-gate 	metafreehspnamelist(hspnlp);
3450Sstevel@tonic-gate 	return (rval);
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate  * check hotspare
3500Sstevel@tonic-gate  */
3510Sstevel@tonic-gate int
3520Sstevel@tonic-gate meta_check_hotspare(
3530Sstevel@tonic-gate 	mdsetname_t	*sp,
3540Sstevel@tonic-gate 	mdname_t	*np,
3550Sstevel@tonic-gate 	md_error_t	*ep
3560Sstevel@tonic-gate )
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate 	mdchkopts_t	options = (MDCHK_ALLOW_HS);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/* make sure we have a disk */
3610Sstevel@tonic-gate 	if (metachkcomp(np, ep) != 0)
3620Sstevel@tonic-gate 		return (-1);
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
3650Sstevel@tonic-gate 	if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
3660Sstevel@tonic-gate 		return (-1);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	/* make sure it is in the set */
3700Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
3710Sstevel@tonic-gate 		return (-1);
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	/* make sure its not in a metadevice */
3740Sstevel@tonic-gate 	if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
3750Sstevel@tonic-gate 		return (-1);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	/* return success */
3780Sstevel@tonic-gate 	return (0);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate  * print hsp
3830Sstevel@tonic-gate  */
3840Sstevel@tonic-gate static int
3850Sstevel@tonic-gate hsp_print(
3860Sstevel@tonic-gate 	md_hsp_t	*hspp,
3870Sstevel@tonic-gate 	char		*fname,
3880Sstevel@tonic-gate 	FILE		*fp,
3890Sstevel@tonic-gate 	md_error_t	*ep
3900Sstevel@tonic-gate )
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	uint_t		hsi;
3930Sstevel@tonic-gate 	int		rval = -1;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	/* print name */
3960Sstevel@tonic-gate 	if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF)
3970Sstevel@tonic-gate 		goto out;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/* print hotspares */
4000Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
4010Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		/* print hotspare */
4040Sstevel@tonic-gate 		/*
4050Sstevel@tonic-gate 		 * If the path is our standard /dev/rdsk or /dev/md/rdsk
4060Sstevel@tonic-gate 		 * then just print out the cxtxdxsx or the dx, metainit
4070Sstevel@tonic-gate 		 * will assume the default, otherwise we need the full
4080Sstevel@tonic-gate 		 * pathname to make sure this works as we intend.
4090Sstevel@tonic-gate 		 */
4100Sstevel@tonic-gate 		if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) &&
4110Sstevel@tonic-gate 		    (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) &&
4120Sstevel@tonic-gate 		    (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) {
4130Sstevel@tonic-gate 			/* not standard path, print full pathname */
4140Sstevel@tonic-gate 			if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF)
4150Sstevel@tonic-gate 				goto out;
4160Sstevel@tonic-gate 		} else {
4170Sstevel@tonic-gate 			/* standard path, just print ctd or d value */
4180Sstevel@tonic-gate 			if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF)
4190Sstevel@tonic-gate 				goto out;
4200Sstevel@tonic-gate 		}
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	/* terminate last line */
4240Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
4250Sstevel@tonic-gate 		goto out;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	/* success */
4280Sstevel@tonic-gate 	rval = 0;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/* cleanup, return error */
4310Sstevel@tonic-gate out:
4320Sstevel@tonic-gate 	if (rval != 0)
4330Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
4340Sstevel@tonic-gate 	return (rval);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate  * hotspare state name
4390Sstevel@tonic-gate  */
4400Sstevel@tonic-gate char *
4410Sstevel@tonic-gate hs_state_to_name(
4420Sstevel@tonic-gate 	md_hs_t			*hsp,
4430Sstevel@tonic-gate 	md_timeval32_t		*tvp
4440Sstevel@tonic-gate )
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate 	hotspare_states_t	state = hsp->state;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	/* grab time */
4490Sstevel@tonic-gate 	if (tvp != NULL)
4500Sstevel@tonic-gate 		*tvp = hsp->timestamp;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	switch (state) {
4530Sstevel@tonic-gate 	case HSS_AVAILABLE:
4540Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Available"));
4550Sstevel@tonic-gate 	case HSS_RESERVED:
4560Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "In use"));
4570Sstevel@tonic-gate 	case HSS_BROKEN:
4580Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Broken"));
4590Sstevel@tonic-gate 	case HSS_UNUSED:
4600Sstevel@tonic-gate 	default:
4610Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "invalid"));
4620Sstevel@tonic-gate 	}
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate /*
4660Sstevel@tonic-gate  * report hsp
4670Sstevel@tonic-gate  */
4680Sstevel@tonic-gate static int
4690Sstevel@tonic-gate hsp_report(
4700Sstevel@tonic-gate 	md_hsp_t	*hspp,
4710Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
4720Sstevel@tonic-gate 	char		*fname,
4730Sstevel@tonic-gate 	FILE		*fp,
4740Sstevel@tonic-gate 	mdprtopts_t	options,
4750Sstevel@tonic-gate 	md_error_t	*ep,
4760Sstevel@tonic-gate 	mdsetname_t	*sp
4770Sstevel@tonic-gate )
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate 	uint_t		hsi;
4800Sstevel@tonic-gate 	int		rval = -1;
4810Sstevel@tonic-gate 	char		*devid = "";
4820Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
4830Sstevel@tonic-gate 	uint_t		len;
4840Sstevel@tonic-gate 	int		large_hs_dev_cnt = 0;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	if (options & PRINT_LARGEDEVICES) {
4870Sstevel@tonic-gate 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
4880Sstevel@tonic-gate 			md_hs_t	*hsp = &hspp->hotspares.hotspares_val[hsi];
4890Sstevel@tonic-gate 			if (hsp->revision == MD_64BIT_META_DEV) {
4900Sstevel@tonic-gate 				large_hs_dev_cnt += 1;
4910Sstevel@tonic-gate 				if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
4920Sstevel@tonic-gate 				    != 0)
4930Sstevel@tonic-gate 					goto out;
4940Sstevel@tonic-gate 			}
4950Sstevel@tonic-gate 		}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 		if (large_hs_dev_cnt == 0) {
4980Sstevel@tonic-gate 			rval = 0;
4990Sstevel@tonic-gate 			goto out;
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 	/* print header */
5030Sstevel@tonic-gate 	if (hspp->hotspares.hotspares_len == 0) {
5040Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"),
5050Sstevel@tonic-gate 		    hspp->hspnamep->hspname) == EOF) {
5060Sstevel@tonic-gate 			goto out;
5070Sstevel@tonic-gate 		}
5080Sstevel@tonic-gate 	} else if (hspp->hotspares.hotspares_len == 1) {
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 		/*
5110Sstevel@tonic-gate 		 * This allows the length
5120Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
5130Sstevel@tonic-gate 		 * looking horrible.
5140Sstevel@tonic-gate 		 */
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname);
5170Sstevel@tonic-gate 		/*
5180Sstevel@tonic-gate 		 * if the length is to short to print out all of the header
5190Sstevel@tonic-gate 		 * force the matter
5200Sstevel@tonic-gate 		 */
5210Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
5220Sstevel@tonic-gate 		len += 2;
5230Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
5240Sstevel@tonic-gate 			if (fprintf(fp,
5250Sstevel@tonic-gate 			    "%s: 1 hot spare (1 big device)\n\t%-*.*s  "
5260Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
5270Sstevel@tonic-gate 			    hspp->hspnamep->hspname, len, len,
5280Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
5290Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
5300Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
5310Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5320Sstevel@tonic-gate 				goto out;
5330Sstevel@tonic-gate 			}
5340Sstevel@tonic-gate 		} else {
5350Sstevel@tonic-gate 			if (fprintf(fp,
5360Sstevel@tonic-gate 			    "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n",
5370Sstevel@tonic-gate 			    hspp->hspnamep->hspname, len, len,
5380Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
5390Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
5400Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
5410Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5420Sstevel@tonic-gate 				goto out;
5430Sstevel@tonic-gate 			}
5440Sstevel@tonic-gate 		}
5450Sstevel@tonic-gate 	} else {
5460Sstevel@tonic-gate 		/*
5470Sstevel@tonic-gate 		 * This allows the length
5480Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
5490Sstevel@tonic-gate 		 * looking horrible.
5500Sstevel@tonic-gate 		 */
5510Sstevel@tonic-gate 		len = 0;
5520Sstevel@tonic-gate 		for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
5530Sstevel@tonic-gate 			len = max(len, strlen(hspp->
5540Sstevel@tonic-gate 			    hotspares.hotspares_val[hsi].hsnamep->cname));
5550Sstevel@tonic-gate 		}
5560Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
5570Sstevel@tonic-gate 		len += 2;
5580Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
5590Sstevel@tonic-gate 			if (fprintf(fp,
5600Sstevel@tonic-gate 			    "%s: %u hot spares (%d big device(s))\n\t%-*.*s "
5610Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
5620Sstevel@tonic-gate 			    hspp->hspnamep->hspname,
5630Sstevel@tonic-gate 			    hspp->hotspares.hotspares_len,
5640Sstevel@tonic-gate 			    large_hs_dev_cnt, len, len,
5650Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
5660Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
5670Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
5680Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5690Sstevel@tonic-gate 				goto out;
5700Sstevel@tonic-gate 			}
5710Sstevel@tonic-gate 		} else {
5720Sstevel@tonic-gate 			if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s "
5730Sstevel@tonic-gate 			    "%-12.12s%-8.6s\t\t%s\n",
5740Sstevel@tonic-gate 			    hspp->hspnamep->hspname,
5750Sstevel@tonic-gate 			    hspp->hotspares.hotspares_len, len, len,
5760Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Device"),
5770Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Status"),
5780Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Length"),
5790Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
5800Sstevel@tonic-gate 				goto out;
5810Sstevel@tonic-gate 			}
5820Sstevel@tonic-gate 		}
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	/* print hotspares */
5860Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
5870Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
5880Sstevel@tonic-gate 		char		*cname = hsp->hsnamep->cname;
5890Sstevel@tonic-gate 		char		*hs_state;
5900Sstevel@tonic-gate 		md_timeval32_t	tv;
5910Sstevel@tonic-gate 		char		*timep;
5920Sstevel@tonic-gate 		ddi_devid_t	dtp;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 		/* populate the key in the name_p structure */
5950Sstevel@tonic-gate 		if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) {
5960Sstevel@tonic-gate 			return (-1);
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 		if (options & PRINT_LARGEDEVICES) {
6000Sstevel@tonic-gate 			if (hsp->revision != MD_64BIT_META_DEV)
6010Sstevel@tonic-gate 				continue;
6020Sstevel@tonic-gate 		}
6030Sstevel@tonic-gate 		/* determine if devid does NOT exist */
6040Sstevel@tonic-gate 		if (options & PRINT_DEVID) {
6050Sstevel@tonic-gate 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
6060Sstevel@tonic-gate 				didnp->key, ep)) == NULL)
6070Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
6080Sstevel@tonic-gate 			else {
6090Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
6100Sstevel@tonic-gate 				free(dtp);
6110Sstevel@tonic-gate 			}
6120Sstevel@tonic-gate 		}
6130Sstevel@tonic-gate 		/* print hotspare */
6140Sstevel@tonic-gate 		hs_state = hs_state_to_name(hsp, &tv);
6150Sstevel@tonic-gate 		/*
6160Sstevel@tonic-gate 		 * This allows the length
6170Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
6180Sstevel@tonic-gate 		 * looking horrible.
6190Sstevel@tonic-gate 		 */
6200Sstevel@tonic-gate 		if (! (options & PRINT_TIMES)) {
6210Sstevel@tonic-gate 			if (fprintf(fp,
6220Sstevel@tonic-gate 			    "        %-*s %-12s %lld blocks\t%s\n",
6230Sstevel@tonic-gate 			    len, cname, hs_state,
6240Sstevel@tonic-gate 			    hsp->size, devid) == EOF) {
6250Sstevel@tonic-gate 				goto out;
6260Sstevel@tonic-gate 			}
6270Sstevel@tonic-gate 		} else {
6280Sstevel@tonic-gate 			timep = meta_print_time(&tv);
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 			if (fprintf(fp,
6310Sstevel@tonic-gate 			    "        %-*s\t    %-11s %8lld blocks%s\t%s\n",
6320Sstevel@tonic-gate 			    len, cname, hs_state,
6330Sstevel@tonic-gate 			    hsp->size, devid, timep) == EOF) {
6340Sstevel@tonic-gate 				goto out;
6350Sstevel@tonic-gate 			}
6360Sstevel@tonic-gate 		}
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	/* add extra line */
6400Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
6410Sstevel@tonic-gate 		goto out;
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	/* success */
6440Sstevel@tonic-gate 	rval = 0;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	/* cleanup, return error */
6470Sstevel@tonic-gate out:
6480Sstevel@tonic-gate 	if (rval != 0)
6490Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
6500Sstevel@tonic-gate 	return (rval);
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate /*
6540Sstevel@tonic-gate  * print/report hsp
6550Sstevel@tonic-gate  */
6560Sstevel@tonic-gate int
6570Sstevel@tonic-gate meta_hsp_print(
6580Sstevel@tonic-gate 	mdsetname_t	*sp,
6590Sstevel@tonic-gate 	mdhspname_t	*hspnp,
6600Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
6610Sstevel@tonic-gate 	char		*fname,
6620Sstevel@tonic-gate 	FILE		*fp,
6630Sstevel@tonic-gate 	mdprtopts_t	options,
6640Sstevel@tonic-gate 	md_error_t	*ep
6650Sstevel@tonic-gate )
6660Sstevel@tonic-gate {
6670Sstevel@tonic-gate 	md_hsp_t	*hspp;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	/* should have same set */
6700Sstevel@tonic-gate 	assert(sp != NULL);
6710Sstevel@tonic-gate 	assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp)));
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	/* print all hsps */
6740Sstevel@tonic-gate 	if (hspnp == NULL) {
6750Sstevel@tonic-gate 		mdhspnamelist_t	*hspnlp = NULL;
6760Sstevel@tonic-gate 		mdhspnamelist_t	*p;
6770Sstevel@tonic-gate 		int		cnt;
6780Sstevel@tonic-gate 		int		rval = 0;
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 		if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0)
6810Sstevel@tonic-gate 			return (-1);
6820Sstevel@tonic-gate 		else if (cnt == 0)
6830Sstevel@tonic-gate 			return (0);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 		/* recurse */
6860Sstevel@tonic-gate 		for (p = hspnlp; (p != NULL); p = p->next) {
6870Sstevel@tonic-gate 			mdhspname_t	*hspnp = p->hspnamep;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 			if (meta_hsp_print(sp, hspnp, nlpp, fname, fp,
6900Sstevel@tonic-gate 			    options, ep) != 0)
6910Sstevel@tonic-gate 				rval = -1;
6920Sstevel@tonic-gate 		}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 		/* cleanup, return success */
6950Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
6960Sstevel@tonic-gate 		return (rval);
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	/* get unit structure */
7000Sstevel@tonic-gate 	if ((hspp = meta_get_hsp_common(sp, hspnp,
7010Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
7020Sstevel@tonic-gate 		return (-1);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	/* print appropriate detail */
7050Sstevel@tonic-gate 	if (options & PRINT_SHORT)
7060Sstevel@tonic-gate 		return (hsp_print(hspp, fname, fp, ep));
7070Sstevel@tonic-gate 	else
7080Sstevel@tonic-gate 		return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp));
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate /*
7120Sstevel@tonic-gate  * check for valid hotspare pool
7130Sstevel@tonic-gate  */
7140Sstevel@tonic-gate int
7150Sstevel@tonic-gate metachkhsp(
7160Sstevel@tonic-gate 	mdsetname_t	*sp,
7170Sstevel@tonic-gate 	mdhspname_t	*hspnp,
7180Sstevel@tonic-gate 	md_error_t	*ep
7190Sstevel@tonic-gate )
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate 	if (meta_get_hsp(sp, hspnp, ep) == NULL)
7220Sstevel@tonic-gate 		return (-1);
7230Sstevel@tonic-gate 	return (0);
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate /*
7270Sstevel@tonic-gate  * invalidate hotspare pool info
7280Sstevel@tonic-gate  */
7290Sstevel@tonic-gate void
7300Sstevel@tonic-gate meta_invalidate_hsp(
7310Sstevel@tonic-gate 	mdhspname_t	*hspnp
7320Sstevel@tonic-gate )
7330Sstevel@tonic-gate {
7340Sstevel@tonic-gate 	md_hsp_t	*hspp = hspnp->unitp;
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	/* free it up */
7370Sstevel@tonic-gate 	if (hspp == NULL)
7380Sstevel@tonic-gate 		return;
7390Sstevel@tonic-gate 	meta_free_hsp(hspp);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	/* clear cache */
7420Sstevel@tonic-gate 	hspnp->unitp = NULL;
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate /*
7460Sstevel@tonic-gate  * add hotspares and/or hotspare pool
7470Sstevel@tonic-gate  */
7480Sstevel@tonic-gate int
7490Sstevel@tonic-gate meta_hs_add(
7500Sstevel@tonic-gate 	mdsetname_t	*sp,
7510Sstevel@tonic-gate 	mdhspname_t	*hspnp,
7520Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
7530Sstevel@tonic-gate 	mdcmdopts_t	options,
7540Sstevel@tonic-gate 	md_error_t	*ep
7550Sstevel@tonic-gate )
7560Sstevel@tonic-gate {
7570Sstevel@tonic-gate 	mdnamelist_t	*p;
7580Sstevel@tonic-gate 	set_hs_params_t	shs;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	/* should have a set */
7610Sstevel@tonic-gate 	assert(sp != NULL);
7620Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	/* clear cache */
7650Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/* setup hotspare pool info */
7680Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
7690Sstevel@tonic-gate 	shs.shs_cmd = ADD_HOT_SPARE;
7700Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
7710Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	/* add empty hotspare pool */
7740Sstevel@tonic-gate 	if (hsnlp == NULL) {
7750Sstevel@tonic-gate 		shs.shs_options = HS_OPT_POOL;
7760Sstevel@tonic-gate 		/* If DOIT is not set, it's a dryrun */
7770Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) == 0) {
7780Sstevel@tonic-gate 			shs.shs_options |= HS_OPT_DRYRUN;
7790Sstevel@tonic-gate 		}
7800Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
7810Sstevel@tonic-gate 		    hspnp->hspname) != 0)
7820Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
7830Sstevel@tonic-gate 		goto success;
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	/* add hotspares */
7870Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
7880Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
7890Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
7900Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 	for (p = hsnlp; (p != NULL); p = p->next) {
7930Sstevel@tonic-gate 		mdname_t	*hsnp = p->namep;
7940Sstevel@tonic-gate 		diskaddr_t	size, label, start_blk;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		/* should be in same set */
7970Sstevel@tonic-gate 		assert(sp->setno == HSP_SET(hspnp->hsp));
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 		/* check it out */
8000Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
8010Sstevel@tonic-gate 			return (-1);
8020Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
8030Sstevel@tonic-gate 			return (-1);
8040Sstevel@tonic-gate 		else if (size == 0)
8050Sstevel@tonic-gate 			return (mdsyserror(ep, ENOSPC, hsnp->cname));
8060Sstevel@tonic-gate 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
8070Sstevel@tonic-gate 			return (-1);
8080Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, hsnp, ep))
8090Sstevel@tonic-gate 		    == MD_DISKADDR_ERROR)
8100Sstevel@tonic-gate 			return (-1);
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 		shs.shs_size_option = meta_check_devicesize(size);
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 		/* In dryrun mode (DOIT not set) we must not alter the mddb */
8150Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
8160Sstevel@tonic-gate 			/* store name in namespace */
8170Sstevel@tonic-gate 			if (add_key_name(sp, hsnp, NULL, ep) != 0)
8180Sstevel@tonic-gate 				return (-1);
8190Sstevel@tonic-gate 		}
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 		/* add hotspare and/or hotspare pool */
8220Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
8230Sstevel@tonic-gate 		shs.shs_start_blk = start_blk;
8240Sstevel@tonic-gate 		shs.shs_has_label = ((label > 0) ? 1 : 0);
8250Sstevel@tonic-gate 		shs.shs_number_blks = size;
8260Sstevel@tonic-gate 		shs.shs_key_old = hsnp->key;
8270Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
8280Sstevel@tonic-gate 			if ((options & MDCMD_DOIT) &&
8290Sstevel@tonic-gate 			    (shs.shs_options != HS_OPT_POOL)) {
8300Sstevel@tonic-gate 				(void) del_key_name(sp, hsnp, ep);
8310Sstevel@tonic-gate 			}
8320Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
8330Sstevel@tonic-gate 		}
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	/* print success message */
8370Sstevel@tonic-gate success:
8380Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
8390Sstevel@tonic-gate 		if ((options & MDCMD_INIT) || (hsnlp == NULL)) {
8400Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
8410Sstevel@tonic-gate 			    "%s: Hotspare pool is setup\n"),
8420Sstevel@tonic-gate 			    hspnp->hspname);
8430Sstevel@tonic-gate 		} else if (hsnlp->next == NULL) {
8440Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
8450Sstevel@tonic-gate 			    "%s: Hotspare is added\n"),
8460Sstevel@tonic-gate 			    hspnp->hspname);
8470Sstevel@tonic-gate 		} else {
8480Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
8490Sstevel@tonic-gate 			    "%s: Hotspares are added\n"),
8500Sstevel@tonic-gate 			    hspnp->hspname);
8510Sstevel@tonic-gate 		}
8520Sstevel@tonic-gate 		(void) fflush(stdout);
8530Sstevel@tonic-gate 	}
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	/* return success */
8560Sstevel@tonic-gate 	return (0);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate /*
8600Sstevel@tonic-gate  * delete hotspares from pool
8610Sstevel@tonic-gate  */
8620Sstevel@tonic-gate int
8630Sstevel@tonic-gate meta_hs_delete(
8640Sstevel@tonic-gate 	mdsetname_t	*sp,
8650Sstevel@tonic-gate 	mdhspname_t	*hspnp,
8660Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
8670Sstevel@tonic-gate 	mdcmdopts_t	options,
8680Sstevel@tonic-gate 	md_error_t	*ep
8690Sstevel@tonic-gate )
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 	mdnamelist_t	*p;
8720Sstevel@tonic-gate 	set_hs_params_t	shs;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	/* should have a set */
8750Sstevel@tonic-gate 	assert(sp != NULL);
8760Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/* clear cache */
8790Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	/* setup hotspare pool info */
8820Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
8830Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
8840Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
8850Sstevel@tonic-gate 	shs.shs_cmd = DELETE_HOT_SPARE;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	/* delete empty hotspare pool */
8880Sstevel@tonic-gate 	if (hsnlp == NULL) {
8890Sstevel@tonic-gate 		shs.shs_options = HS_OPT_POOL;
8900Sstevel@tonic-gate 		/* If DOIT is not set, it's a dryrun */
8910Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) == 0) {
8920Sstevel@tonic-gate 			shs.shs_options |= HS_OPT_DRYRUN;
8930Sstevel@tonic-gate 		}
8940Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
8950Sstevel@tonic-gate 		    hspnp->hspname) != 0)
8960Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
8970Sstevel@tonic-gate 		goto success;
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	/* delete hotspares */
9010Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
9020Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
9030Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
9040Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
9050Sstevel@tonic-gate 	}
9060Sstevel@tonic-gate 	for (p = hsnlp; (p != NULL); p = p->next) {
9070Sstevel@tonic-gate 		mdname_t	*hsnp = p->namep;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 		/* should be in same set */
9100Sstevel@tonic-gate 		assert(sp->setno == HSP_SET(hspnp->hsp));
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 		/* delete hotspare */
9130Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
9140Sstevel@tonic-gate 		meta_invalidate_name(hsnp);
9150Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0)
9160Sstevel@tonic-gate 			return (mdstealerror(ep, &shs.mde));
9170Sstevel@tonic-gate 	}
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	/* print success message */
9200Sstevel@tonic-gate success:
9210Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
9220Sstevel@tonic-gate 		if (hsnlp == NULL) {
9230Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
9240Sstevel@tonic-gate 			    "%s: Hotspare pool is cleared\n"),
9250Sstevel@tonic-gate 			    hspnp->hspname);
9260Sstevel@tonic-gate 		} else if (hsnlp->next == NULL) {
9270Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
9280Sstevel@tonic-gate 			    "%s: Hotspare is deleted\n"),
9290Sstevel@tonic-gate 			    hspnp->hspname);
9300Sstevel@tonic-gate 		} else {
9310Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
9320Sstevel@tonic-gate 			    "%s: Hotspares are deleted\n"),
9330Sstevel@tonic-gate 			    hspnp->hspname);
9340Sstevel@tonic-gate 		}
9350Sstevel@tonic-gate 		(void) fflush(stdout);
9360Sstevel@tonic-gate 	}
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	/* return success */
9390Sstevel@tonic-gate 	return (0);
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate /*
9430Sstevel@tonic-gate  * replace hotspare in pool
9440Sstevel@tonic-gate  */
9450Sstevel@tonic-gate int
9460Sstevel@tonic-gate meta_hs_replace(
9470Sstevel@tonic-gate 	mdsetname_t	*sp,
9480Sstevel@tonic-gate 	mdhspname_t	*hspnp,
9490Sstevel@tonic-gate 	mdname_t	*oldnp,
9500Sstevel@tonic-gate 	mdname_t	*newnp,
9510Sstevel@tonic-gate 	mdcmdopts_t	options,
9520Sstevel@tonic-gate 	md_error_t	*ep
9530Sstevel@tonic-gate )
9540Sstevel@tonic-gate {
9550Sstevel@tonic-gate 	set_hs_params_t	shs;
9560Sstevel@tonic-gate 	diskaddr_t	size, label, start_blk;
9570Sstevel@tonic-gate 	md_dev64_t	old_dev, new_dev;
9580Sstevel@tonic-gate 	diskaddr_t	new_start_blk, new_end_blk;
9590Sstevel@tonic-gate 	int		rebind;
9600Sstevel@tonic-gate 	char		*new_devidp = NULL;
9610Sstevel@tonic-gate 	int		ret;
9620Sstevel@tonic-gate 	md_set_desc	*sd;
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	/* should be in same set */
9650Sstevel@tonic-gate 	assert(sp != NULL);
9660Sstevel@tonic-gate 	assert(sp->setno == HSP_SET(hspnp->hsp));
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	/* save new binding incase this is a rebind where oldnp==newnp */
9690Sstevel@tonic-gate 	new_dev = newnp->dev;
9700Sstevel@tonic-gate 	new_start_blk = newnp->start_blk;
9710Sstevel@tonic-gate 	new_end_blk = newnp->end_blk;
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	/* invalidate, then get the hotspare (fill in oldnp from metadb) */
9740Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
9750Sstevel@tonic-gate 	if (meta_get_hsp(sp, hspnp, ep) == NULL)
9760Sstevel@tonic-gate 		return (-1);
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	/* the old device binding is now established */
9790Sstevel@tonic-gate 	if ((old_dev = oldnp->dev) == NODEV64)
9800Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, oldnp->cname));
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	/*
9830Sstevel@tonic-gate 	 * check for the case where oldnp and newnp indicate the same
9840Sstevel@tonic-gate 	 * device, but the dev_t of the device has changed between old
9850Sstevel@tonic-gate 	 * and new.  This is called a rebind.  On entry the dev_t
9860Sstevel@tonic-gate 	 * represents the new device binding determined from the
9870Sstevel@tonic-gate 	 * filesystem (meta_getdev). After calling meta_get_hsp
9880Sstevel@tonic-gate 	 * oldnp (and maybe newnp if this is a rebind) is updated based
9890Sstevel@tonic-gate 	 * to the old binding from the metadb (done by metakeyname).
9900Sstevel@tonic-gate 	 */
9910Sstevel@tonic-gate 	if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
9920Sstevel@tonic-gate 	    (old_dev != new_dev)) {
9930Sstevel@tonic-gate 		rebind = 1;
9940Sstevel@tonic-gate 	} else {
9950Sstevel@tonic-gate 		rebind = 0;
9960Sstevel@tonic-gate 	}
9970Sstevel@tonic-gate 	if (rebind) {
9980Sstevel@tonic-gate 		newnp->dev = new_dev;
9990Sstevel@tonic-gate 		newnp->start_blk = new_start_blk;
10000Sstevel@tonic-gate 		newnp->end_blk = new_end_blk;
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	/*
10040Sstevel@tonic-gate 	 * Save a copy of the devid associated with the new disk, the reason
10050Sstevel@tonic-gate 	 * is that the meta_check_hotspare() call could cause the devid to
10060Sstevel@tonic-gate 	 * be changed to that of the devid that is currently stored in the
10070Sstevel@tonic-gate 	 * replica namespace for the disk in question. This devid could be
10080Sstevel@tonic-gate 	 * stale if we are replacing the disk. The function that overwrites
10090Sstevel@tonic-gate 	 * the devid is dr2drivedesc().
10100Sstevel@tonic-gate 	 */
10110Sstevel@tonic-gate 	if (newnp->drivenamep->devid != NULL)
10120Sstevel@tonic-gate 		new_devidp = Strdup(newnp->drivenamep->devid);
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	/* if it's a multi-node diskset clear new_devidp */
10150Sstevel@tonic-gate 	if (!metaislocalset(sp)) {
10160Sstevel@tonic-gate 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
10170Sstevel@tonic-gate 			Free(new_devidp);
10180Sstevel@tonic-gate 			return (-1);
10190Sstevel@tonic-gate 		}
10200Sstevel@tonic-gate 		if (MD_MNSET_DESC(sd)) {
10210Sstevel@tonic-gate 			Free(new_devidp);
10220Sstevel@tonic-gate 			new_devidp = NULL;
10230Sstevel@tonic-gate 		}
10240Sstevel@tonic-gate 	}
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	/* check it out */
10270Sstevel@tonic-gate 	if (meta_check_hotspare(sp, newnp, ep) != 0) {
10280Sstevel@tonic-gate 		if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
10290Sstevel@tonic-gate 			Free(new_devidp);
10300Sstevel@tonic-gate 			return (-1);
10310Sstevel@tonic-gate 		}
10320Sstevel@tonic-gate 		mdclrerror(ep);
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate 	if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
10350Sstevel@tonic-gate 		Free(new_devidp);
10360Sstevel@tonic-gate 		return (-1);
10370Sstevel@tonic-gate 	}
10380Sstevel@tonic-gate 	if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
10390Sstevel@tonic-gate 		Free(new_devidp);
10400Sstevel@tonic-gate 		return (-1);
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 	if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
10430Sstevel@tonic-gate 		Free(new_devidp);
10440Sstevel@tonic-gate 		return (-1);
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 	if (start_blk >= size) {
10470Sstevel@tonic-gate 		(void) mdsyserror(ep, ENOSPC, newnp->cname);
10480Sstevel@tonic-gate 		Free(new_devidp);
10490Sstevel@tonic-gate 		return (-1);
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
10530Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
10540Sstevel@tonic-gate 		/* store name in namespace */
10550Sstevel@tonic-gate 		if (add_key_name(sp, newnp, NULL, ep) != 0)
10560Sstevel@tonic-gate 			return (-1);
10570Sstevel@tonic-gate 	}
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	/*
10600Sstevel@tonic-gate 	 * Copy back the saved devid.
10610Sstevel@tonic-gate 	 */
10620Sstevel@tonic-gate 	Free(newnp->drivenamep->devid);
10630Sstevel@tonic-gate 	if (new_devidp != NULL) {
10640Sstevel@tonic-gate 		newnp->drivenamep->devid = new_devidp;
10650Sstevel@tonic-gate 		new_devidp = NULL;
10660Sstevel@tonic-gate 	}
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	/* In dryrun mode (DOIT not set) we must not alter the mddb */
10690Sstevel@tonic-gate 	if (options & MDCMD_DOIT) {
10700Sstevel@tonic-gate 		/* store name in namespace */
10710Sstevel@tonic-gate 		if (add_key_name(sp, newnp, NULL, ep) != 0)
10720Sstevel@tonic-gate 			return (-1);
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	if (rebind && !metaislocalset(sp)) {
10760Sstevel@tonic-gate 		/*
10770Sstevel@tonic-gate 		 * We are 'rebind'ing a disk that is in a diskset so as well
10780Sstevel@tonic-gate 		 * as updating the diskset's namespace the local set needs
10790Sstevel@tonic-gate 		 * to be updated because it also contains a reference to the
10800Sstevel@tonic-gate 		 * disk in question.
10810Sstevel@tonic-gate 		 */
10820Sstevel@tonic-gate 		ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname,
10830Sstevel@tonic-gate 		    ep);
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 		if (ret != METADEVADM_SUCCESS) {
10860Sstevel@tonic-gate 			md_error_t	xep = mdnullerror;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 			/*
10890Sstevel@tonic-gate 			 * In dryrun mode (DOIT not set) we must not alter
10900Sstevel@tonic-gate 			 * the mddb
10910Sstevel@tonic-gate 			 */
10920Sstevel@tonic-gate 			if (options & MDCMD_DOIT) {
10930Sstevel@tonic-gate 				(void) del_key_name(sp, newnp, &xep);
10940Sstevel@tonic-gate 				mdclrerror(&xep);
10950Sstevel@tonic-gate 				return (-1);
10960Sstevel@tonic-gate 			}
10970Sstevel@tonic-gate 		}
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	/* replace hotspare */
11010Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	shs.shs_size_option = meta_check_devicesize(size);
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	shs.shs_cmd = REPLACE_HOT_SPARE;
11060Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
11070Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
11080Sstevel@tonic-gate 	shs.shs_component_old = old_dev;
11090Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
11100Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
11110Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
11120Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
11130Sstevel@tonic-gate 	}
11140Sstevel@tonic-gate 	shs.shs_component_new = new_dev;
11150Sstevel@tonic-gate 	shs.shs_start_blk = start_blk;
11160Sstevel@tonic-gate 	shs.shs_has_label = ((label > 0) ? 1 : 0);
11170Sstevel@tonic-gate 	shs.shs_number_blks = size;
11180Sstevel@tonic-gate 	shs.shs_key_new = newnp->key;
11190Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
11200Sstevel@tonic-gate 		if (options & MDCMD_DOIT) {
11210Sstevel@tonic-gate 			(void) del_key_name(sp, newnp, ep);
11220Sstevel@tonic-gate 		}
11230Sstevel@tonic-gate 		return (mdstealerror(ep, &shs.mde));
11240Sstevel@tonic-gate 	}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	/* clear cache */
11270Sstevel@tonic-gate 	meta_invalidate_name(oldnp);
11280Sstevel@tonic-gate 	meta_invalidate_name(newnp);
11290Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	/* let em know */
11320Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
11330Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
11340Sstevel@tonic-gate 		    "%s: Hotspare %s is replaced with %s\n"),
11350Sstevel@tonic-gate 		    hspnp->hspname, oldnp->cname, newnp->cname);
11360Sstevel@tonic-gate 		(void) fflush(stdout);
11370Sstevel@tonic-gate 	}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	/* return success */
11400Sstevel@tonic-gate 	return (0);
11410Sstevel@tonic-gate }
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate /*
11440Sstevel@tonic-gate  * enable hotspares
11450Sstevel@tonic-gate  */
11460Sstevel@tonic-gate int
11470Sstevel@tonic-gate meta_hs_enable(
11480Sstevel@tonic-gate 	mdsetname_t	*sp,
11490Sstevel@tonic-gate 	mdnamelist_t	*hsnlp,
11500Sstevel@tonic-gate 	mdcmdopts_t	options,
11510Sstevel@tonic-gate 	md_error_t	*ep
11520Sstevel@tonic-gate )
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate 	mdhspnamelist_t	*hspnlp = NULL;
11550Sstevel@tonic-gate 	mdhspnamelist_t	*hspnp;
11560Sstevel@tonic-gate 	set_hs_params_t	shs;
11570Sstevel@tonic-gate 	int		rval = -1;
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 	/* should have a set */
11600Sstevel@tonic-gate 	assert(sp != NULL);
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	/* setup device info */
11630Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
11640Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
11650Sstevel@tonic-gate 	shs.shs_cmd = FIX_HOT_SPARE;
11660Sstevel@tonic-gate 	shs.shs_options = HS_OPT_NONE;
11670Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
11680Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
11690Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
11700Sstevel@tonic-gate 	}
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	/* get the list of hotspare names */
11730Sstevel@tonic-gate 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
11740Sstevel@tonic-gate 		goto out;
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	/* enable hotspares for each components */
11770Sstevel@tonic-gate 	for (; (hsnlp != NULL); hsnlp = hsnlp->next) {
11780Sstevel@tonic-gate 		mdname_t	*hsnp = hsnlp->namep;
11790Sstevel@tonic-gate 		md_dev64_t	fs_dev;
11800Sstevel@tonic-gate 		int		rebind = 0;
11810Sstevel@tonic-gate 		diskaddr_t	size, label, start_blk;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 		/* get the file_system dev binding */
11840Sstevel@tonic-gate 		if (meta_getdev(sp, hsnp, ep) != 0)
11850Sstevel@tonic-gate 			return (-1);
11860Sstevel@tonic-gate 		fs_dev = hsnp->dev;
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 		/*
11890Sstevel@tonic-gate 		 * search for the component in each hotspare pool
11900Sstevel@tonic-gate 		 * and replace it (instead of enable) if the binding
11910Sstevel@tonic-gate 		 * has changed.
11920Sstevel@tonic-gate 		 */
11930Sstevel@tonic-gate 		for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
11940Sstevel@tonic-gate 			/*
11950Sstevel@tonic-gate 			 * in_hsp will call meta_get_hsp which will fill
11960Sstevel@tonic-gate 			 * in hspnp with metadb version of component
11970Sstevel@tonic-gate 			 */
11980Sstevel@tonic-gate 			meta_invalidate_hsp(hspnp->hspnamep);
11990Sstevel@tonic-gate 			if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) {
12000Sstevel@tonic-gate 				/*
12010Sstevel@tonic-gate 				 * check for the case where the dev_t has
12020Sstevel@tonic-gate 				 * changed between the filesystem and the
12030Sstevel@tonic-gate 				 * metadb.  This is called a rebind, and
12040Sstevel@tonic-gate 				 * is handled by meta_hs_replace.
12050Sstevel@tonic-gate 				 */
12060Sstevel@tonic-gate 				if (fs_dev != hsnp->dev) {
12070Sstevel@tonic-gate 					/*
12080Sstevel@tonic-gate 					 * establish file system binding
12090Sstevel@tonic-gate 					 * with invalid start/end
12100Sstevel@tonic-gate 					 */
12110Sstevel@tonic-gate 					rebind++;
12120Sstevel@tonic-gate 					hsnp->dev = fs_dev;
12130Sstevel@tonic-gate 					hsnp->start_blk = -1;
12140Sstevel@tonic-gate 					hsnp->end_blk = -1;
12150Sstevel@tonic-gate 					rval = meta_hs_replace(sp,
12160Sstevel@tonic-gate 					    hspnp->hspnamep,
12170Sstevel@tonic-gate 					    hsnp, hsnp, options, ep);
12180Sstevel@tonic-gate 					if (rval != 0)
12190Sstevel@tonic-gate 						goto out;
12200Sstevel@tonic-gate 				}
12210Sstevel@tonic-gate 			}
12220Sstevel@tonic-gate 		}
12230Sstevel@tonic-gate 		if (rebind)
12240Sstevel@tonic-gate 			continue;
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 		/* enable the component in all hotspares that use it */
12270Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
12280Sstevel@tonic-gate 			goto out;
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
12310Sstevel@tonic-gate 			goto out;
12320Sstevel@tonic-gate 		if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
12330Sstevel@tonic-gate 			goto out;
12340Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, hsnp, ep))
12350Sstevel@tonic-gate 		    == MD_DISKADDR_ERROR)
12360Sstevel@tonic-gate 			goto out;
12370Sstevel@tonic-gate 		if (start_blk >= size) {
12380Sstevel@tonic-gate 			(void) mdsyserror(ep, ENOSPC, hsnp->cname);
12390Sstevel@tonic-gate 			goto out;
12400Sstevel@tonic-gate 		}
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 		/* enable hotspare */
12430Sstevel@tonic-gate 		shs.shs_component_old = hsnp->dev;
12440Sstevel@tonic-gate 		shs.shs_component_new = hsnp->dev;
12450Sstevel@tonic-gate 		shs.shs_start_blk = start_blk;
12460Sstevel@tonic-gate 		shs.shs_has_label = ((label > 0) ? 1 : 0);
12470Sstevel@tonic-gate 		shs.shs_number_blks = size;
12480Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) {
12490Sstevel@tonic-gate 			rval = mdstealerror(ep, &shs.mde);
12500Sstevel@tonic-gate 			goto out;
12510Sstevel@tonic-gate 		}
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 		/*
12540Sstevel@tonic-gate 		 * Are we dealing with a non-local set? If so need to update
12550Sstevel@tonic-gate 		 * the local namespace so that the disk record has the correct
12560Sstevel@tonic-gate 		 * devid.
12570Sstevel@tonic-gate 		 */
12580Sstevel@tonic-gate 		if (!metaislocalset(sp)) {
12590Sstevel@tonic-gate 			rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
12600Sstevel@tonic-gate 			    hsnp->cname, ep);
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 			if (rval != METADEVADM_SUCCESS) {
12630Sstevel@tonic-gate 				/*
12640Sstevel@tonic-gate 				 * Failed to update the local set. Nothing to
12650Sstevel@tonic-gate 				 * do here apart from report the error. The
12660Sstevel@tonic-gate 				 * namespace is most likely broken and some
12670Sstevel@tonic-gate 				 * form of remedial recovery is going to
12680Sstevel@tonic-gate 				 * be required.
12690Sstevel@tonic-gate 				 */
12700Sstevel@tonic-gate 				mde_perror(ep, "");
12710Sstevel@tonic-gate 				mdclrerror(ep);
12720Sstevel@tonic-gate 			}
12730Sstevel@tonic-gate 		}
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 		/* clear cache */
12760Sstevel@tonic-gate 		meta_invalidate_name(hsnp);
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 		/* let em know */
12790Sstevel@tonic-gate 		if (options & MDCMD_PRINT) {
12800Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
12810Sstevel@tonic-gate 			    "hotspare %s is enabled\n"),
12820Sstevel@tonic-gate 			    hsnp->cname);
12830Sstevel@tonic-gate 			(void) fflush(stdout);
12840Sstevel@tonic-gate 		}
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	/* clear whole cache */
12880Sstevel@tonic-gate 	for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
12890Sstevel@tonic-gate 		meta_invalidate_hsp(hspnp->hspnamep);
12900Sstevel@tonic-gate 	}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	/* return success */
12940Sstevel@tonic-gate 	rval = 0;
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate out:
12970Sstevel@tonic-gate 	if (hspnlp)
12980Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
12990Sstevel@tonic-gate 	return (rval);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate /*
13030Sstevel@tonic-gate  * check for dups in the hsp itself
13040Sstevel@tonic-gate  */
13050Sstevel@tonic-gate static int
13060Sstevel@tonic-gate check_twice(
13070Sstevel@tonic-gate 	md_hsp_t	*hspp,
13080Sstevel@tonic-gate 	uint_t		hsi,
13090Sstevel@tonic-gate 	md_error_t	*ep
13100Sstevel@tonic-gate )
13110Sstevel@tonic-gate {
13120Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
13130Sstevel@tonic-gate 	mdname_t	*thisnp;
13140Sstevel@tonic-gate 	uint_t		h;
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep;
13170Sstevel@tonic-gate 	for (h = 0; (h < hsi); ++h) {
13180Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[h];
13190Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 		if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1,
13220Sstevel@tonic-gate 		    hsnp, 0, -1, ep) != 0)
13230Sstevel@tonic-gate 			return (-1);
13240Sstevel@tonic-gate 	}
13250Sstevel@tonic-gate 	return (0);
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate /*
13290Sstevel@tonic-gate  * check hsp
13300Sstevel@tonic-gate  */
13310Sstevel@tonic-gate /*ARGSUSED2*/
13320Sstevel@tonic-gate int
13330Sstevel@tonic-gate meta_check_hsp(
13340Sstevel@tonic-gate 	mdsetname_t	*sp,
13350Sstevel@tonic-gate 	md_hsp_t	*hspp,
13360Sstevel@tonic-gate 	mdcmdopts_t	options,
13370Sstevel@tonic-gate 	md_error_t	*ep
13380Sstevel@tonic-gate )
13390Sstevel@tonic-gate {
13400Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
13410Sstevel@tonic-gate 	uint_t		hsi;
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	/* check hotspares */
13440Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
13450Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
13460Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
13470Sstevel@tonic-gate 		diskaddr_t	size;
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 		/* check hotspare */
13500Sstevel@tonic-gate 		if (meta_check_hotspare(sp, hsnp, ep) != 0)
13510Sstevel@tonic-gate 			return (-1);
13520Sstevel@tonic-gate 		if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) {
13530Sstevel@tonic-gate 			return (-1);
13540Sstevel@tonic-gate 		} else if (size == 0) {
13550Sstevel@tonic-gate 			return (mdsyserror(ep, ENOSPC, hspnp->hspname));
13560Sstevel@tonic-gate 		}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 		/* check this hsp too */
13590Sstevel@tonic-gate 		if (check_twice(hspp, hsi, ep) != 0)
13600Sstevel@tonic-gate 			return (-1);
13610Sstevel@tonic-gate 	}
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	/* return success */
13640Sstevel@tonic-gate 	return (0);
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate /*
13680Sstevel@tonic-gate  * create hsp
13690Sstevel@tonic-gate  */
13700Sstevel@tonic-gate int
13710Sstevel@tonic-gate meta_create_hsp(
13720Sstevel@tonic-gate 	mdsetname_t	*sp,
13730Sstevel@tonic-gate 	md_hsp_t	*hspp,
13740Sstevel@tonic-gate 	mdcmdopts_t	options,
13750Sstevel@tonic-gate 	md_error_t	*ep
13760Sstevel@tonic-gate )
13770Sstevel@tonic-gate {
13780Sstevel@tonic-gate 	mdhspname_t	*hspnp = hspp->hspnamep;
13790Sstevel@tonic-gate 	mdnamelist_t	*hsnlp = NULL;
13800Sstevel@tonic-gate 	uint_t		hsi;
13810Sstevel@tonic-gate 	int		rval = -1;
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	/* validate hsp */
13840Sstevel@tonic-gate 	if (meta_check_hsp(sp, hspp, options, ep) != 0)
13850Sstevel@tonic-gate 		return (-1);
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	/* if we're not doing anything, return success */
13880Sstevel@tonic-gate 	if (! (options & MDCMD_DOIT))
13890Sstevel@tonic-gate 		return (0);
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	/* create hsp */
13920Sstevel@tonic-gate 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
13930Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
13940Sstevel@tonic-gate 		mdname_t	*hsnp = hsp->hsnamep;
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 		(void) metanamelist_append(&hsnlp, hsnp);
13970Sstevel@tonic-gate 	}
13980Sstevel@tonic-gate 	options |= MDCMD_INIT;
13990Sstevel@tonic-gate 	rval = meta_hs_add(sp, hspnp, hsnlp, options, ep);
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 	/* cleanup, return success */
14020Sstevel@tonic-gate 	metafreenamelist(hsnlp);
14030Sstevel@tonic-gate 	return (rval);
14040Sstevel@tonic-gate }
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate /*
14070Sstevel@tonic-gate  * initialize hsp
14080Sstevel@tonic-gate  * NOTE: this functions is metainit(1m)'s command line parser!
14090Sstevel@tonic-gate  */
14100Sstevel@tonic-gate int
14110Sstevel@tonic-gate meta_init_hsp(
14120Sstevel@tonic-gate 	mdsetname_t	**spp,
14130Sstevel@tonic-gate 	int		argc,
14140Sstevel@tonic-gate 	char		*argv[],
14150Sstevel@tonic-gate 	mdcmdopts_t	options,
14160Sstevel@tonic-gate 	md_error_t	*ep
14170Sstevel@tonic-gate )
14180Sstevel@tonic-gate {
14190Sstevel@tonic-gate 	char		*uname = argv[0];
14200Sstevel@tonic-gate 	mdhspname_t	*hspnp = NULL;
14210Sstevel@tonic-gate 	md_hsp_t	*hspp = NULL;
14220Sstevel@tonic-gate 	uint_t		hsi;
14230Sstevel@tonic-gate 	int		rval = -1;
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	/* get hsp name */
14270Sstevel@tonic-gate 	assert(argc > 0);
14280Sstevel@tonic-gate 	if (argc < 1)
14290Sstevel@tonic-gate 		goto syntax;
14300Sstevel@tonic-gate 	if ((hspnp = metahspname(spp, uname, ep)) == NULL)
14310Sstevel@tonic-gate 		goto out;
14320Sstevel@tonic-gate 	assert(*spp != NULL);
14330Sstevel@tonic-gate 	uname = hspnp->hspname;
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	if (!(options & MDCMD_NOLOCK)) {
14360Sstevel@tonic-gate 		/* grab set lock */
14370Sstevel@tonic-gate 		if (meta_lock(*spp, TRUE, ep))
14380Sstevel@tonic-gate 			goto out;
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 		if (meta_check_ownership(*spp, ep) != 0)
14410Sstevel@tonic-gate 			goto out;
14420Sstevel@tonic-gate 	}
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	/* see if it exists already */
14450Sstevel@tonic-gate 	if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
14460Sstevel@tonic-gate 		(void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP, hspnp->hsp, uname);
14470Sstevel@tonic-gate 		goto out;
14480Sstevel@tonic-gate 	} else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
14490Sstevel@tonic-gate 		goto out;
14500Sstevel@tonic-gate 	} else {
14510Sstevel@tonic-gate 		mdclrerror(ep);
14520Sstevel@tonic-gate 	}
14530Sstevel@tonic-gate 	--argc, ++argv;
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 	/* parse general options */
14560Sstevel@tonic-gate 	optind = 0;
14570Sstevel@tonic-gate 	opterr = 0;
14580Sstevel@tonic-gate 	if (getopt(argc, argv, "") != -1)
14590Sstevel@tonic-gate 		goto options;
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	/* allocate hsp */
14620Sstevel@tonic-gate 	hspp = Zalloc(sizeof (*hspp));
14630Sstevel@tonic-gate 	hspp->hotspares.hotspares_len = argc;
14640Sstevel@tonic-gate 	if (argc > 0) {
14650Sstevel@tonic-gate 		hspp->hotspares.hotspares_val =
14660Sstevel@tonic-gate 		    Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
14670Sstevel@tonic-gate 	}
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	/* setup pool */
14700Sstevel@tonic-gate 	hspp->hspnamep = hspnp;
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	/* parse hotspares */
14730Sstevel@tonic-gate 	for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
14740Sstevel@tonic-gate 	    ++hsi) {
14750Sstevel@tonic-gate 		md_hs_t		*hsp = &hspp->hotspares.hotspares_val[hsi];
14760Sstevel@tonic-gate 		mdname_t	*hsnamep;
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 		/* parse hotspare name */
14790Sstevel@tonic-gate 		if ((hsnamep = metaname(spp, argv[0], ep)) == NULL)
14800Sstevel@tonic-gate 			goto out;
14810Sstevel@tonic-gate 		hsp->hsnamep = hsnamep;
14820Sstevel@tonic-gate 		--argc, ++argv;
14830Sstevel@tonic-gate 	}
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 	/* we should be at the end */
14860Sstevel@tonic-gate 	if (argc != 0)
14870Sstevel@tonic-gate 		goto syntax;
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 	/* create hotspare pool */
14900Sstevel@tonic-gate 	if (meta_create_hsp(*spp, hspp, options, ep) != 0)
14910Sstevel@tonic-gate 		goto out;
14920Sstevel@tonic-gate 	rval = 0;	/* success */
14930Sstevel@tonic-gate 	goto out;
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 	/* syntax error */
14960Sstevel@tonic-gate syntax:
14970Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
14980Sstevel@tonic-gate 	goto out;
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 	/* options error */
15010Sstevel@tonic-gate options:
15020Sstevel@tonic-gate 	rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
15030Sstevel@tonic-gate 	goto out;
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	/* cleanup, return error */
15060Sstevel@tonic-gate out:
15070Sstevel@tonic-gate 	if (hspp != NULL)
15080Sstevel@tonic-gate 		meta_free_hsp(hspp);
15090Sstevel@tonic-gate 	return (rval);
15100Sstevel@tonic-gate }
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate /*
15130Sstevel@tonic-gate  * reset hotspare pool
15140Sstevel@tonic-gate  */
15150Sstevel@tonic-gate int
15160Sstevel@tonic-gate meta_hsp_reset(
15170Sstevel@tonic-gate 	mdsetname_t	*sp,
15180Sstevel@tonic-gate 	mdhspname_t	*hspnp,
15190Sstevel@tonic-gate 	mdcmdopts_t	options,
15200Sstevel@tonic-gate 	md_error_t	*ep
15210Sstevel@tonic-gate )
15220Sstevel@tonic-gate {
15230Sstevel@tonic-gate 	md_hsp_t	*hspp;
15240Sstevel@tonic-gate 	set_hs_params_t	shs;
15250Sstevel@tonic-gate 	uint_t		i;
15260Sstevel@tonic-gate 	int		rval = -1;
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 	/* should have the same set */
15290Sstevel@tonic-gate 	assert(sp != NULL);
15300Sstevel@tonic-gate 	assert((hspnp == NULL) || (sp->setno == HSP_SET(hspnp->hsp)));
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	/* reset all hotspares */
15330Sstevel@tonic-gate 	if (hspnp == NULL) {
15340Sstevel@tonic-gate 		mdhspnamelist_t	*hspnlp = NULL;
15350Sstevel@tonic-gate 		mdhspnamelist_t	*p;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 		/* for each hotspare pool */
15380Sstevel@tonic-gate 		rval = 0;
15390Sstevel@tonic-gate 		if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
15400Sstevel@tonic-gate 			return (-1);
15410Sstevel@tonic-gate 		for (p = hspnlp; (p != NULL); p = p->next) {
15420Sstevel@tonic-gate 			/* reset hotspare pool */
15430Sstevel@tonic-gate 			hspnp = p->hspnamep;
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 			/*
15460Sstevel@tonic-gate 			 * If this is a multi-node set, we send a series
15470Sstevel@tonic-gate 			 * of individual metaclear commands.
15480Sstevel@tonic-gate 			 */
15490Sstevel@tonic-gate 			if (meta_is_mn_set(sp, ep)) {
15500Sstevel@tonic-gate 				if (meta_mn_send_metaclear_command(sp,
15510Sstevel@tonic-gate 				    hspnp->hspname, options, 0, ep) != 0) {
15520Sstevel@tonic-gate 					rval = -1;
15530Sstevel@tonic-gate 					break;
15540Sstevel@tonic-gate 				}
15550Sstevel@tonic-gate 			} else {
15560Sstevel@tonic-gate 				if (meta_hsp_reset(sp, hspnp, options,
15570Sstevel@tonic-gate 				    ep) != 0) {
15580Sstevel@tonic-gate 					rval = -1;
15590Sstevel@tonic-gate 					break;
15600Sstevel@tonic-gate 				}
15610Sstevel@tonic-gate 			}
15620Sstevel@tonic-gate 		}
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 		/* cleanup, return success */
15650Sstevel@tonic-gate 		metafreehspnamelist(hspnlp);
15660Sstevel@tonic-gate 		return (rval);
15670Sstevel@tonic-gate 	}
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 	/* get unit structure */
15700Sstevel@tonic-gate 	if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
15710Sstevel@tonic-gate 		return (-1);
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	/* make sure nobody owns us */
15740Sstevel@tonic-gate 	if (hspp->refcount > 0) {
15750Sstevel@tonic-gate 		return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
15760Sstevel@tonic-gate 		    hspnp->hspname));
15770Sstevel@tonic-gate 	}
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	/* clear hotspare pool members */
15800Sstevel@tonic-gate 	(void) memset(&shs, 0, sizeof (shs));
15810Sstevel@tonic-gate 	MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
15820Sstevel@tonic-gate 	shs.shs_cmd = DELETE_HOT_SPARE;
15830Sstevel@tonic-gate 	shs.shs_hot_spare_pool = hspnp->hsp;
15840Sstevel@tonic-gate 	for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
15850Sstevel@tonic-gate 		md_hs_t		*hs = &hspp->hotspares.hotspares_val[i];
15860Sstevel@tonic-gate 		mdname_t	*hsnamep = hs->hsnamep;
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 		/* clear cache */
15890Sstevel@tonic-gate 		meta_invalidate_name(hsnamep);
15900Sstevel@tonic-gate 
15910Sstevel@tonic-gate 		/* clear hotspare */
15920Sstevel@tonic-gate 		shs.shs_component_old = hsnamep->dev;
15930Sstevel@tonic-gate 		shs.shs_options = HS_OPT_FORCE;
15940Sstevel@tonic-gate 		/* If DOIT is not set, it's a dryrun */
15950Sstevel@tonic-gate 		if ((options & MDCMD_DOIT) == 0) {
15960Sstevel@tonic-gate 			shs.shs_options |= HS_OPT_DRYRUN;
15970Sstevel@tonic-gate 		}
15980Sstevel@tonic-gate 		if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
15990Sstevel@tonic-gate 			(void) mdstealerror(ep, &shs.mde);
16000Sstevel@tonic-gate 			goto out;
16010Sstevel@tonic-gate 		}
16020Sstevel@tonic-gate 	}
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 	/* clear hotspare pool */
16050Sstevel@tonic-gate 	shs.shs_options = HS_OPT_POOL;
16060Sstevel@tonic-gate 	/* If DOIT is not set, it's a dryrun */
16070Sstevel@tonic-gate 	if ((options & MDCMD_DOIT) == 0) {
16080Sstevel@tonic-gate 		shs.shs_options |= HS_OPT_DRYRUN;
16090Sstevel@tonic-gate 	}
16100Sstevel@tonic-gate 	if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hspnp->hspname) != 0) {
16110Sstevel@tonic-gate 		(void) mdstealerror(ep, &shs.mde);
16120Sstevel@tonic-gate 		goto out;
16130Sstevel@tonic-gate 	}
16140Sstevel@tonic-gate 	rval = 0;	/* success */
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	/* let em know */
16170Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
16180Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
16190Sstevel@tonic-gate 		    "%s: Hotspare pool is cleared\n"),
16200Sstevel@tonic-gate 		    hspnp->hspname);
16210Sstevel@tonic-gate 		(void) fflush(stdout);
16220Sstevel@tonic-gate 	}
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	/* clear subdevices (nothing to do) */
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	/* cleanup, return success */
16270Sstevel@tonic-gate out:
16280Sstevel@tonic-gate 	meta_invalidate_hsp(hspnp);
16290Sstevel@tonic-gate 	return (rval);
16300Sstevel@tonic-gate }
1631