xref: /onnv-gate/usr/src/uts/common/io/lvm/hotspares/hotspares.c (revision 4932:cac85bf517af)
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
51366Spetede  * Common Development and Distribution License (the "License").
61366Spetede  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*4932Spetede  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/conf.h>
310Sstevel@tonic-gate #include <sys/file.h>
320Sstevel@tonic-gate #include <sys/user.h>
330Sstevel@tonic-gate #include <sys/uio.h>
340Sstevel@tonic-gate #include <sys/t_lock.h>
350Sstevel@tonic-gate #include <sys/kmem.h>
360Sstevel@tonic-gate #include <vm/page.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <sys/mkdev.h>
400Sstevel@tonic-gate #include <sys/stat.h>
410Sstevel@tonic-gate #include <sys/open.h>
420Sstevel@tonic-gate #include <sys/modctl.h>
430Sstevel@tonic-gate #include <sys/ddi.h>
440Sstevel@tonic-gate #include <sys/sunddi.h>
450Sstevel@tonic-gate #include <sys/debug.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #include <sys/lvm/md_hotspares.h>
480Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
510Sstevel@tonic-gate #include <sys/sysevent/svm.h>
520Sstevel@tonic-gate 
530Sstevel@tonic-gate md_ops_t		hotspares_md_ops;
540Sstevel@tonic-gate #ifndef	lint
551366Spetede char			_depends_on[] = "drv/md";
560Sstevel@tonic-gate md_ops_t		*md_interface_ops = &hotspares_md_ops;
570Sstevel@tonic-gate #endif
580Sstevel@tonic-gate 
590Sstevel@tonic-gate extern md_ops_t		**md_ops;
600Sstevel@tonic-gate extern md_ops_t		*md_opslist;
610Sstevel@tonic-gate extern md_set_t		md_set[];
620Sstevel@tonic-gate 
630Sstevel@tonic-gate extern kmutex_t		md_mx;		/* used to md global stuff */
640Sstevel@tonic-gate extern kcondvar_t	md_cv;		/* md_status events */
650Sstevel@tonic-gate extern int		md_status;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate extern void		md_clear_hot_spare_interface();
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static void
set_hot_spare_state(hot_spare_t * hs,hotspare_states_t newstate)700Sstevel@tonic-gate set_hot_spare_state(hot_spare_t *hs, hotspare_states_t newstate)
710Sstevel@tonic-gate {
720Sstevel@tonic-gate 	hs->hs_state = newstate;
730Sstevel@tonic-gate 	uniqtime32(&hs->hs_timestamp);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static hot_spare_t *
lookup_hot_spare(set_t setno,mddb_recid_t hs_id,int must_exist)770Sstevel@tonic-gate lookup_hot_spare(set_t setno, mddb_recid_t hs_id, int must_exist)
780Sstevel@tonic-gate {
790Sstevel@tonic-gate 	hot_spare_t *hs;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	for (hs = (hot_spare_t *)md_set[setno].s_hs; hs; hs = hs->hs_next) {
820Sstevel@tonic-gate 		if (hs->hs_record_id == hs_id)
830Sstevel@tonic-gate 			return (hs);
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 	if (must_exist)
860Sstevel@tonic-gate 		ASSERT(0);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	return ((hot_spare_t *)NULL);
890Sstevel@tonic-gate }
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static int
seths_create_hsp(set_hs_params_t * shs)930Sstevel@tonic-gate seths_create_hsp(set_hs_params_t *shs)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
960Sstevel@tonic-gate 	mddb_recid_t		recid;
970Sstevel@tonic-gate 	set_t			setno;
980Sstevel@tonic-gate 	mddb_type_t		typ1;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	/* Scan the hot spare pool list */
1030Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
1040Sstevel@tonic-gate 	if (hsp != (hot_spare_pool_t *)0)
1050Sstevel@tonic-gate 		return (0);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
1080Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	/* create a hot spare pool record */
1110Sstevel@tonic-gate 	if (shs->shs_options & MD_CRO_64BIT) {
1120Sstevel@tonic-gate #if defined(_ILP32)
1130Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_HSP_UNIT_TOO_LARGE,
1140Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
1150Sstevel@tonic-gate #else
1160Sstevel@tonic-gate 		recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1,
1171623Stw21770 		    HSP_REC, MD_CRO_64BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN,
1181623Stw21770 		    setno);
1190Sstevel@tonic-gate #endif
1200Sstevel@tonic-gate 	} else {
1210Sstevel@tonic-gate 		recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1,
1221623Stw21770 		    HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN,
1231623Stw21770 		    setno);
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	if (recid < 0) {
1270Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
1280Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
1290Sstevel@tonic-gate 	}
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	/* get the record addr */
1320Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, sizeof (*hsp),
1330Sstevel@tonic-gate 		HSP_ONDSK_STR_OFF);
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	hsp->hsp_self_id = shs->shs_hot_spare_pool;
1360Sstevel@tonic-gate 	hsp->hsp_record_id = recid;
1370Sstevel@tonic-gate 	hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
1380Sstevel@tonic-gate 	hsp->hsp_refcount = 0;
1390Sstevel@tonic-gate 	hsp->hsp_nhotspares = 0;
1401623Stw21770 	hsp->hsp_revision |= MD_FN_META_DEV;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	md_set[setno].s_hsp = (void *) hsp;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	mddb_commitrec_wrapper(recid);
1450Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno,
1460Sstevel@tonic-gate 	    md_expldev(hsp->hsp_self_id));
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
1490Sstevel@tonic-gate 	hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
1500Sstevel@tonic-gate 	hsp->hsp_link.ln_setno = setno;
1510Sstevel@tonic-gate 	hsp->hsp_link.ln_id = hsp->hsp_self_id;
1520Sstevel@tonic-gate 	hotspares_md_ops.md_head = &hsp->hsp_link;
1530Sstevel@tonic-gate 	rw_exit(&hotspares_md_ops.md_link_rw.lock);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	return (0);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate static int
seths_add(set_hs_params_t * shs)1600Sstevel@tonic-gate seths_add(set_hs_params_t *shs)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate 	hot_spare_t		*hs;
1630Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
1640Sstevel@tonic-gate 	hot_spare_pool_t	*prev_hsp;
1650Sstevel@tonic-gate 	hot_spare_pool_t	*new_hsp;
1660Sstevel@tonic-gate 	hot_spare_pool_t	*old_hsp;
1671623Stw21770 	md_create_rec_option_t	options;
1680Sstevel@tonic-gate 	mddb_recid_t		recid;
1690Sstevel@tonic-gate 	mddb_recid_t		recids[5];
1700Sstevel@tonic-gate 	size_t			new_size;
1710Sstevel@tonic-gate 	int			i;
1720Sstevel@tonic-gate 	int			delete_hsp = 0;
1730Sstevel@tonic-gate 	int			irecid;
1740Sstevel@tonic-gate 	set_t			setno;
1750Sstevel@tonic-gate 	mddb_type_t		typ1;
1760Sstevel@tonic-gate 	int			hsp_created = 0;
1770Sstevel@tonic-gate 	mdkey_t			key_old;
1780Sstevel@tonic-gate 	int			num_keys_old = 0;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	/* Not much to do here in case of a dryrun */
1810Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
1820Sstevel@tonic-gate 		return (0);
1830Sstevel@tonic-gate 	}
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	/* create an empty hot spare pool */
1860Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_POOL) {
1870Sstevel@tonic-gate 		return (seths_create_hsp(shs));
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
1910Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
1920Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/* Scan the hot spare list */
1950Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
1960Sstevel@tonic-gate 	while (hs) {
1970Sstevel@tonic-gate 		if (hs->hs_devnum == shs->shs_component_old) {
1980Sstevel@tonic-gate 			break;
1990Sstevel@tonic-gate 		}
2000Sstevel@tonic-gate 		hs = hs->hs_next;
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if (hs == NULL) {
2040Sstevel@tonic-gate 		/*
2050Sstevel@tonic-gate 		 * Did not find match for device using devnum so use
2060Sstevel@tonic-gate 		 * key associated with shs_component_old just
2070Sstevel@tonic-gate 		 * in case there is a match but the match's dev is NODEV.
2080Sstevel@tonic-gate 		 * If unable to find a unique key for shs_component_old
2090Sstevel@tonic-gate 		 * then fail since namespace has multiple entries
2100Sstevel@tonic-gate 		 * for this old component and we shouldn't allow
2110Sstevel@tonic-gate 		 * an addition of a hotspare in this case.
2120Sstevel@tonic-gate 		 */
2130Sstevel@tonic-gate 		if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
2140Sstevel@tonic-gate 		    shs->shs_component_old, &key_old, &num_keys_old) != 0) {
2150Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_NAME_SPACE,
2160Sstevel@tonic-gate 			    shs->shs_component_old));
2170Sstevel@tonic-gate 		}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 		/*
2200Sstevel@tonic-gate 		 * If more than one key matches given old_dev - fail command
2210Sstevel@tonic-gate 		 * since shouldn't add new hotspare if namespace has
2220Sstevel@tonic-gate 		 * multiple entries.
2230Sstevel@tonic-gate 		 */
2240Sstevel@tonic-gate 		if (num_keys_old > 1) {
2250Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_MULTNM,
2260Sstevel@tonic-gate 			    shs->shs_component_old));
2270Sstevel@tonic-gate 		}
2280Sstevel@tonic-gate 		/*
2290Sstevel@tonic-gate 		 * If there is no key for this entry then fail since
2300Sstevel@tonic-gate 		 * a key for this entry should exist.
2310Sstevel@tonic-gate 		 */
2320Sstevel@tonic-gate 		if (num_keys_old == 0) {
2330Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_INVAL_HS,
2340Sstevel@tonic-gate 			    shs->shs_component_old));
2350Sstevel@tonic-gate 		}
2360Sstevel@tonic-gate 		/* Scan the hot spare list again */
2370Sstevel@tonic-gate 		hs = (hot_spare_t *)md_set[setno].s_hs;
2380Sstevel@tonic-gate 		while (hs) {
2390Sstevel@tonic-gate 			/*
2400Sstevel@tonic-gate 			 * Only need to compare keys when hs_devnum is NODEV.
2410Sstevel@tonic-gate 			 */
2420Sstevel@tonic-gate 			if ((hs->hs_devnum == NODEV64) &&
2430Sstevel@tonic-gate 			    (hs->hs_key == key_old)) {
2440Sstevel@tonic-gate 				break;
2450Sstevel@tonic-gate 			}
2460Sstevel@tonic-gate 			hs = hs->hs_next;
2470Sstevel@tonic-gate 		}
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	if (hs == NULL) {
2510Sstevel@tonic-gate 		/* create a hot spare record */
2520Sstevel@tonic-gate 		if (shs->shs_size_option & MD_CRO_64BIT) {
2530Sstevel@tonic-gate #if defined(_ILP32)
2540Sstevel@tonic-gate 			return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE,
2550Sstevel@tonic-gate 			    shs->shs_hot_spare_pool, shs->shs_component_old));
2560Sstevel@tonic-gate #else
2570Sstevel@tonic-gate 			recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
2580Sstevel@tonic-gate 				MD_CRO_64BIT | MD_CRO_HOTSPARE, setno);
2590Sstevel@tonic-gate #endif
2600Sstevel@tonic-gate 		} else {
2610Sstevel@tonic-gate 			recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
2620Sstevel@tonic-gate 				MD_CRO_32BIT | MD_CRO_HOTSPARE, setno);
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		if (recid < 0) {
2660Sstevel@tonic-gate 			return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE,
2670Sstevel@tonic-gate 			    shs->shs_hot_spare_pool,
2680Sstevel@tonic-gate 			    shs->shs_component_old));
2690Sstevel@tonic-gate 		}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 		/* get the addr */
2720Sstevel@tonic-gate 		hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, sizeof (*hs),
2730Sstevel@tonic-gate 			0);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 		hs->hs_record_id = recid;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 		hs->hs_devnum = shs->shs_component_old;
2780Sstevel@tonic-gate 		hs->hs_key = shs->shs_key_old;
2790Sstevel@tonic-gate 		hs->hs_start_blk = shs->shs_start_blk;
2800Sstevel@tonic-gate 		hs->hs_has_label = shs->shs_has_label;
2810Sstevel@tonic-gate 		hs->hs_number_blks = shs->shs_number_blks;
2820Sstevel@tonic-gate 		set_hot_spare_state(hs, HSS_AVAILABLE);
2830Sstevel@tonic-gate 		hs->hs_refcount = 0;
2840Sstevel@tonic-gate 		hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
2850Sstevel@tonic-gate 		md_set[setno].s_hs = (void *) hs;
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	/* Scan the hot spare pool list */
2890Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
2900Sstevel@tonic-gate 	prev_hsp = (hot_spare_pool_t *)0;
2910Sstevel@tonic-gate 	while (hsp) {
2920Sstevel@tonic-gate 		if (hsp->hsp_self_id == shs->shs_hot_spare_pool) {
2930Sstevel@tonic-gate 			break;
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 		prev_hsp = hsp;
2960Sstevel@tonic-gate 		hsp = hsp->hsp_next;
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	if (hsp == NULL) {
3000Sstevel@tonic-gate 		/* create a hot spare pool record */
3010Sstevel@tonic-gate 		recid = mddb_createrec(sizeof (hot_spare_pool_ond_t),
3021623Stw21770 		    typ1, HSP_REC,
3031623Stw21770 		    MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN, setno);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 		if (recid < 0) {
3060Sstevel@tonic-gate 			return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
3070Sstevel@tonic-gate 			    shs->shs_hot_spare_pool));
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		/* get the record addr */
3110Sstevel@tonic-gate 		hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid,
3120Sstevel@tonic-gate 			sizeof (*hsp), HSP_ONDSK_STR_OFF);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 		hsp->hsp_self_id = shs->shs_hot_spare_pool;
3150Sstevel@tonic-gate 		hsp->hsp_record_id = recid;
3160Sstevel@tonic-gate 		hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
3170Sstevel@tonic-gate 		hsp->hsp_refcount = 0;
3180Sstevel@tonic-gate 		hsp->hsp_nhotspares = 0;
3191623Stw21770 		hsp->hsp_revision |= MD_FN_META_DEV;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 		/* force prev_hsp to NULL, this will cause hsp to be linked */
3220Sstevel@tonic-gate 		prev_hsp = (hot_spare_pool_t *)0;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 		rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
3250Sstevel@tonic-gate 		hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
3260Sstevel@tonic-gate 		hsp->hsp_link.ln_setno = setno;
3270Sstevel@tonic-gate 		hsp->hsp_link.ln_id = hsp->hsp_self_id;
3280Sstevel@tonic-gate 		hotspares_md_ops.md_head = &hsp->hsp_link;
3290Sstevel@tonic-gate 		rw_exit(&hotspares_md_ops.md_link_rw.lock);
3300Sstevel@tonic-gate 		hsp_created = 1;
3310Sstevel@tonic-gate 	} else {
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 		/*
3340Sstevel@tonic-gate 		 * Make sure the hot spare is not already in the pool.
3350Sstevel@tonic-gate 		 */
3360Sstevel@tonic-gate 		for (i = 0; i < hsp->hsp_nhotspares; i++)
3370Sstevel@tonic-gate 			if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
3380Sstevel@tonic-gate 				return (mdhserror(&shs->mde, MDE_HS_INUSE,
3390Sstevel@tonic-gate 					shs->shs_hot_spare_pool,
3400Sstevel@tonic-gate 					hs->hs_devnum));
3410Sstevel@tonic-gate 			}
3420Sstevel@tonic-gate 		/*
3430Sstevel@tonic-gate 		 * Create a new hot spare pool record
3440Sstevel@tonic-gate 		 * This gives us the one extra hs slot,
3450Sstevel@tonic-gate 		 * because there is one slot in the
3460Sstevel@tonic-gate 		 * hot_spare_pool struct
3470Sstevel@tonic-gate 		 */
3480Sstevel@tonic-gate 		new_size = sizeof (hot_spare_pool_ond_t) +
3490Sstevel@tonic-gate 			(sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
3501623Stw21770 
3511623Stw21770 		/*
3521623Stw21770 		 * The Friendly Name status of the new HSP should duplicate
3531623Stw21770 		 * the status of the existing one.
3541623Stw21770 		 */
3551623Stw21770 		if (hsp->hsp_revision & MD_FN_META_DEV) {
3561623Stw21770 			options =
3571623Stw21770 				MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL | MD_CRO_FN;
3581623Stw21770 		} else {
3591623Stw21770 			options = MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL;
3601623Stw21770 		}
3611623Stw21770 		recid = mddb_createrec(new_size, typ1, HSP_REC, options, setno);
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 		if (recid < 0) {
3640Sstevel@tonic-gate 			return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
3650Sstevel@tonic-gate 			    hsp->hsp_self_id));
3660Sstevel@tonic-gate 		}
3670Sstevel@tonic-gate 		new_size = sizeof (hot_spare_pool_t) +
3680Sstevel@tonic-gate 			(sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 		/* get the record addr */
3710Sstevel@tonic-gate 		new_hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid,
3720Sstevel@tonic-gate 			new_size, HSP_ONDSK_STR_OFF);
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		/* copy the old record into the new one */
3750Sstevel@tonic-gate 		bcopy((caddr_t)hsp, (caddr_t)new_hsp,
3760Sstevel@tonic-gate 		    (size_t)((sizeof (hot_spare_pool_t) +
3770Sstevel@tonic-gate 		    (sizeof (mddb_recid_t) * hsp->hsp_nhotspares)
3780Sstevel@tonic-gate 		    - sizeof (mddb_recid_t))));
3790Sstevel@tonic-gate 		new_hsp->hsp_record_id = recid;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 		md_rem_link(setno, hsp->hsp_self_id,
3820Sstevel@tonic-gate 		    &hotspares_md_ops.md_link_rw.lock,
3830Sstevel@tonic-gate 		    &hotspares_md_ops.md_head);
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 		rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
3860Sstevel@tonic-gate 		new_hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
3870Sstevel@tonic-gate 		new_hsp->hsp_link.ln_setno = setno;
3880Sstevel@tonic-gate 		new_hsp->hsp_link.ln_id = new_hsp->hsp_self_id;
3890Sstevel@tonic-gate 		hotspares_md_ops.md_head = &new_hsp->hsp_link;
3900Sstevel@tonic-gate 		rw_exit(&hotspares_md_ops.md_link_rw.lock);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 		/* mark the old hsp to be deleted */
3930Sstevel@tonic-gate 		delete_hsp = 1;
3940Sstevel@tonic-gate 		old_hsp = hsp;
3950Sstevel@tonic-gate 		hsp = new_hsp;
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	if (shs->shs_size_option & MD_CRO_64BIT) {
3991623Stw21770 		hs->hs_revision |= MD_64BIT_META_DEV;
4000Sstevel@tonic-gate 	} else {
4011623Stw21770 		hs->hs_revision &= ~MD_64BIT_META_DEV;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	/* lock the db records */
4050Sstevel@tonic-gate 	recids[0] = hs->hs_record_id;
4060Sstevel@tonic-gate 	recids[1] = hsp->hsp_record_id;
4070Sstevel@tonic-gate 	irecid = 2;
4080Sstevel@tonic-gate 	if (delete_hsp)
4090Sstevel@tonic-gate 		recids[irecid++] = old_hsp->hsp_record_id;
4100Sstevel@tonic-gate 	recids[irecid] = 0;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/* increment the reference count */
4130Sstevel@tonic-gate 	hs->hs_refcount++;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	/* add the hs at the end of the hot spare pool */
4160Sstevel@tonic-gate 	hsp->hsp_hotspares[hsp->hsp_nhotspares] = hs->hs_record_id;
4170Sstevel@tonic-gate 	hsp->hsp_nhotspares++;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	/*
4200Sstevel@tonic-gate 	 * NOTE: We do not commit the previous hot spare pool record.
4210Sstevel@tonic-gate 	 *	 There is no need, the link gets rebuilt at boot time.
4220Sstevel@tonic-gate 	 */
4230Sstevel@tonic-gate 	if (prev_hsp)
4240Sstevel@tonic-gate 		prev_hsp->hsp_next = hsp;
4250Sstevel@tonic-gate 	else
4260Sstevel@tonic-gate 		md_set[setno].s_hsp = (void *) hsp;
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	if (delete_hsp)
4290Sstevel@tonic-gate 		old_hsp->hsp_self_id = MD_HSP_NONE;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	/* commit the db records */
4320Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	if (delete_hsp) {
4350Sstevel@tonic-gate 		/* delete the old hot spare pool record */
4360Sstevel@tonic-gate 		mddb_deleterec_wrapper(old_hsp->hsp_record_id);
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if (hsp_created) {
4400Sstevel@tonic-gate 		SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno,
4410Sstevel@tonic-gate 		    md_expldev(hsp->hsp_self_id));
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_ADD, SVM_TAG_HSP, setno,
4440Sstevel@tonic-gate 	    md_expldev(hsp->hsp_self_id));
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	return (0);
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate static int
seths_delete_hsp(set_hs_params_t * shs)4510Sstevel@tonic-gate seths_delete_hsp(set_hs_params_t *shs)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	hot_spare_pool_t	*prev_hsp;
4550Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
4560Sstevel@tonic-gate 	set_t			setno;
4570Sstevel@tonic-gate 	hsp_t			hspid;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	/* Scan the hot spare pool list */
4620Sstevel@tonic-gate 	prev_hsp = (hot_spare_pool_t *)0;
4630Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
4640Sstevel@tonic-gate 	while (hsp) {
4650Sstevel@tonic-gate 		if (hsp->hsp_self_id == shs->shs_hot_spare_pool) {
4660Sstevel@tonic-gate 			break;
4670Sstevel@tonic-gate 		}
4680Sstevel@tonic-gate 		prev_hsp = hsp;
4690Sstevel@tonic-gate 		hsp = hsp->hsp_next;
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	if (hsp == NULL) {
4730Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
4740Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	if (hsp->hsp_nhotspares != 0) {
4780Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_HSP_BUSY,
4790Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	if (hsp->hsp_refcount != 0) {
4830Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_HSP_REF,
4840Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	/* In case of a dryrun, we're done here */
4880Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
4890Sstevel@tonic-gate 		return (0);
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 	/*
4920Sstevel@tonic-gate 	 * NOTE: We do not commit the previous hot spare pool record.
4930Sstevel@tonic-gate 	 *	 There is no need, the link gets rebuilt at boot time.
4940Sstevel@tonic-gate 	 */
4950Sstevel@tonic-gate 	if (prev_hsp)
4960Sstevel@tonic-gate 		prev_hsp->hsp_next = hsp->hsp_next;
4970Sstevel@tonic-gate 	else
4980Sstevel@tonic-gate 		md_set[setno].s_hsp = (void *) hsp->hsp_next;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	hspid = hsp->hsp_self_id;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	md_rem_link(setno, hsp->hsp_self_id,
5030Sstevel@tonic-gate 	    &hotspares_md_ops.md_link_rw.lock,
5040Sstevel@tonic-gate 	    &hotspares_md_ops.md_head);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	mddb_deleterec_wrapper(hsp->hsp_record_id);
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_DELETE, SVM_TAG_HSP, setno,
5090Sstevel@tonic-gate 	    md_expldev(hspid));
5100Sstevel@tonic-gate 	return (0);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate static int
seths_delete(set_hs_params_t * shs)5150Sstevel@tonic-gate seths_delete(set_hs_params_t *shs)
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate 	hot_spare_t		*hs;
5180Sstevel@tonic-gate 	hot_spare_t		*prev_hs;
5190Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
5200Sstevel@tonic-gate 	mddb_recid_t		recids[4];
5210Sstevel@tonic-gate 	int			i;
5220Sstevel@tonic-gate 	set_t			setno;
5230Sstevel@tonic-gate 	sv_dev_t		sv;
5240Sstevel@tonic-gate 	int			delete_hs = 0;
5250Sstevel@tonic-gate 	mdkey_t			key_old;
5260Sstevel@tonic-gate 	int			num_keys_old = 0;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	/* delete the hot spare pool */
5290Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_POOL) {
5300Sstevel@tonic-gate 		return (seths_delete_hsp(shs));
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	/* Scan the hot spare list */
5360Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
5370Sstevel@tonic-gate 	prev_hs = (hot_spare_t *)0;
5380Sstevel@tonic-gate 	while (hs) {
5390Sstevel@tonic-gate 		if (hs->hs_devnum == shs->shs_component_old) {
5400Sstevel@tonic-gate 			break;
5410Sstevel@tonic-gate 		}
5420Sstevel@tonic-gate 		prev_hs = hs;
5430Sstevel@tonic-gate 		hs = hs->hs_next;
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	if (hs == NULL) {
5470Sstevel@tonic-gate 		/*
5480Sstevel@tonic-gate 		 * Unable to find device using devnum so use
5490Sstevel@tonic-gate 		 * key associated with shs_component_old instead.
5500Sstevel@tonic-gate 		 * If unable to find a unique key for shs_component_old
5510Sstevel@tonic-gate 		 * then fail since namespace has multiple entries
5520Sstevel@tonic-gate 		 * for this old component and we're unable to determine
5530Sstevel@tonic-gate 		 * which key is the valid match for shs_component_old.
5540Sstevel@tonic-gate 		 *
5550Sstevel@tonic-gate 		 * Only need to compare keys when hs_devnum is NODEV.
5560Sstevel@tonic-gate 		 */
5570Sstevel@tonic-gate 		if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
5580Sstevel@tonic-gate 		    shs->shs_component_old, &key_old, &num_keys_old) != 0) {
5590Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_NAME_SPACE,
5600Sstevel@tonic-gate 			    shs->shs_component_old));
5610Sstevel@tonic-gate 		}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 		/*
5640Sstevel@tonic-gate 		 * If more than one key matches given old_dev - fail command
5650Sstevel@tonic-gate 		 * since shouldn't add new hotspare if namespace has
5660Sstevel@tonic-gate 		 * multiple entries.
5670Sstevel@tonic-gate 		 */
5680Sstevel@tonic-gate 		if (num_keys_old > 1) {
5690Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_MULTNM,
5700Sstevel@tonic-gate 			    shs->shs_component_old));
5710Sstevel@tonic-gate 		}
5720Sstevel@tonic-gate 		/*
5730Sstevel@tonic-gate 		 * If there is no key for this entry then fail since
5740Sstevel@tonic-gate 		 * a key for this entry should exist.
5750Sstevel@tonic-gate 		 */
5760Sstevel@tonic-gate 		if (num_keys_old == 0) {
5770Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_INVAL_HS,
5780Sstevel@tonic-gate 			    shs->shs_component_old));
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 		/* Scan the hot spare list again */
5810Sstevel@tonic-gate 		hs = (hot_spare_t *)md_set[setno].s_hs;
5820Sstevel@tonic-gate 		prev_hs = (hot_spare_t *)0;
5830Sstevel@tonic-gate 		while (hs) {
5840Sstevel@tonic-gate 			/*
5850Sstevel@tonic-gate 			 * Only need to compare keys when hs_devnum is NODEV.
5860Sstevel@tonic-gate 			 */
5870Sstevel@tonic-gate 			if ((hs->hs_devnum == NODEV64) &&
5880Sstevel@tonic-gate 			    (hs->hs_key == key_old)) {
5890Sstevel@tonic-gate 				break;
5900Sstevel@tonic-gate 			}
5910Sstevel@tonic-gate 			prev_hs = hs;
5920Sstevel@tonic-gate 			hs = hs->hs_next;
5930Sstevel@tonic-gate 		}
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	if (hs == NULL) {
5970Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
5980Sstevel@tonic-gate 		    shs->shs_component_old));
5990Sstevel@tonic-gate 	}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	/* Scan the hot spare pool list */
6020Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
6030Sstevel@tonic-gate 	if (hsp == (hot_spare_pool_t *)0) {
6040Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
6050Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	/* check for force flag and state of hot spare */
6090Sstevel@tonic-gate 	if (((shs->shs_options & HS_OPT_FORCE) == 0) &&
6100Sstevel@tonic-gate 	    (hs->hs_state == HSS_RESERVED)) {
6110Sstevel@tonic-gate 		return (mdhserror(&shs->mde, MDE_HS_RESVD,
6120Sstevel@tonic-gate 		    shs->shs_hot_spare_pool, shs->shs_component_old));
6130Sstevel@tonic-gate 	}
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	if (hsp->hsp_refcount && (hs->hs_state == HSS_RESERVED)) {
6160Sstevel@tonic-gate 		return (mdhserror(&shs->mde, MDE_HS_RESVD,
6170Sstevel@tonic-gate 		    shs->shs_hot_spare_pool, shs->shs_component_old));
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	/*
6210Sstevel@tonic-gate 	 * Make sure the device is in the pool.
6220Sstevel@tonic-gate 	 */
6230Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
6240Sstevel@tonic-gate 		if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
6250Sstevel@tonic-gate 			break;
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	if (i >= hsp->hsp_nhotspares) {
6300Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
6310Sstevel@tonic-gate 		    hs->hs_devnum));
6320Sstevel@tonic-gate 	}
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	/* In case of a dryrun, we're done here */
6350Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
6360Sstevel@tonic-gate 		return (0);
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	/* lock the db records */
6400Sstevel@tonic-gate 	recids[0] = hs->hs_record_id;
6410Sstevel@tonic-gate 	recids[1] = hsp->hsp_record_id;
6420Sstevel@tonic-gate 	recids[2] = 0;
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	sv.setno = setno;
6450Sstevel@tonic-gate 	sv.key = hs->hs_key;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	hs->hs_refcount--;
6480Sstevel@tonic-gate 	if (hs->hs_refcount == 0) {
6490Sstevel@tonic-gate 		/*
6500Sstevel@tonic-gate 		 * NOTE: We do not commit the previous hot spare record.
6510Sstevel@tonic-gate 		 *	 There is no need, the link we get rebuilt at boot time.
6520Sstevel@tonic-gate 		 */
6530Sstevel@tonic-gate 		if (prev_hs) {
6540Sstevel@tonic-gate 			prev_hs->hs_next = hs->hs_next;
6550Sstevel@tonic-gate 		} else
6560Sstevel@tonic-gate 			md_set[setno].s_hs = (void *) hs->hs_next;
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 		/* mark the hot spare to be deleted */
6590Sstevel@tonic-gate 		delete_hs = 1;
6600Sstevel@tonic-gate 		recids[0] = hsp->hsp_record_id;
6610Sstevel@tonic-gate 		recids[1] = 0;
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	/* find the location of the hs in the hsp */
6650Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
6660Sstevel@tonic-gate 		if (hsp->hsp_hotspares[i] == hs->hs_record_id)
6670Sstevel@tonic-gate 			break;
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	/* remove the hs from the hsp */
6710Sstevel@tonic-gate 	for (i++; i < hsp->hsp_nhotspares; i++)
6720Sstevel@tonic-gate 		hsp->hsp_hotspares[i - 1] = hsp->hsp_hotspares[i];
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	hsp->hsp_nhotspares--;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/* commit the db records */
6770Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	if (delete_hs)
6800Sstevel@tonic-gate 		mddb_deleterec_wrapper(hs->hs_record_id);
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	md_rem_names(&sv, 1);
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REMOVE, SVM_TAG_HSP, setno,
6850Sstevel@tonic-gate 	    md_expldev(hsp->hsp_self_id));
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	return (0);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate static int
seths_replace(set_hs_params_t * shs)6910Sstevel@tonic-gate seths_replace(set_hs_params_t *shs)
6920Sstevel@tonic-gate {
6930Sstevel@tonic-gate 	hot_spare_t		*hs;
6940Sstevel@tonic-gate 	hot_spare_t		*prev_hs;
6950Sstevel@tonic-gate 	hot_spare_t		*new_hs;
6960Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
6970Sstevel@tonic-gate 	int			new_found = 0;
6980Sstevel@tonic-gate 	mddb_recid_t		recid;
6990Sstevel@tonic-gate 	mddb_recid_t		recids[5];
7000Sstevel@tonic-gate 	int			i;
7010Sstevel@tonic-gate 	sv_dev_t		sv;
7020Sstevel@tonic-gate 	int			delete_hs = 0;
7030Sstevel@tonic-gate 	set_t			setno;
7040Sstevel@tonic-gate 	mddb_type_t		typ1;
7050Sstevel@tonic-gate 	mdkey_t			key_old;
7060Sstevel@tonic-gate 	int			num_keys_old = 0;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
7090Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
7100Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	/* Scan the hot spare list */
7130Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
7140Sstevel@tonic-gate 	prev_hs = (hot_spare_t *)0;
7150Sstevel@tonic-gate 	while (hs) {
7160Sstevel@tonic-gate 		if (hs->hs_devnum == shs->shs_component_old) {
7170Sstevel@tonic-gate 			break;
7180Sstevel@tonic-gate 		}
7190Sstevel@tonic-gate 		prev_hs = hs;
7200Sstevel@tonic-gate 		hs = hs->hs_next;
7210Sstevel@tonic-gate 	}
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (hs == NULL) {
7240Sstevel@tonic-gate 		/*
7250Sstevel@tonic-gate 		 * Unable to find device using devnum so use
7260Sstevel@tonic-gate 		 * key associated with shs_component_old instead.
7270Sstevel@tonic-gate 		 * If unable to find a unique key for shs_component_old
7280Sstevel@tonic-gate 		 * then fail since namespace has multiple entries
7290Sstevel@tonic-gate 		 * for this old component and we're unable to determine
7300Sstevel@tonic-gate 		 * which key is the valid match for shs_component_old.
7310Sstevel@tonic-gate 		 *
7320Sstevel@tonic-gate 		 * Only need to compare keys when hs_devnum is NODEV.
7330Sstevel@tonic-gate 		 */
7340Sstevel@tonic-gate 		if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
7350Sstevel@tonic-gate 		    shs->shs_component_old, &key_old, &num_keys_old) != 0) {
7360Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_NAME_SPACE,
7370Sstevel@tonic-gate 			    shs->shs_component_old));
7380Sstevel@tonic-gate 		}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 		/*
7410Sstevel@tonic-gate 		 * If more than one key matches given old_dev - fail command
7420Sstevel@tonic-gate 		 * since unable to determine which key is correct.
7430Sstevel@tonic-gate 		 */
7440Sstevel@tonic-gate 		if (num_keys_old > 1) {
7450Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_MULTNM,
7460Sstevel@tonic-gate 			    shs->shs_component_old));
7470Sstevel@tonic-gate 		}
7480Sstevel@tonic-gate 		/*
7490Sstevel@tonic-gate 		 * If there is no key for this entry then fail since
7500Sstevel@tonic-gate 		 * a key for this entry should exist.
7510Sstevel@tonic-gate 		 */
7520Sstevel@tonic-gate 		if (num_keys_old == 0) {
7530Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_INVAL_HS,
7540Sstevel@tonic-gate 			    shs->shs_component_old));
7550Sstevel@tonic-gate 		}
7560Sstevel@tonic-gate 		/* Scan the hot spare list again */
7570Sstevel@tonic-gate 		hs = (hot_spare_t *)md_set[setno].s_hs;
7580Sstevel@tonic-gate 		prev_hs = (hot_spare_t *)0;
7590Sstevel@tonic-gate 		while (hs) {
7600Sstevel@tonic-gate 			/*
7610Sstevel@tonic-gate 			 * Only need to compare keys when hs_devnum is NODEV.
7620Sstevel@tonic-gate 			 */
7630Sstevel@tonic-gate 			if ((hs->hs_devnum == NODEV64) &&
7640Sstevel@tonic-gate 			    (hs->hs_key == key_old)) {
7650Sstevel@tonic-gate 				break;
7660Sstevel@tonic-gate 			}
7670Sstevel@tonic-gate 			prev_hs = hs;
7680Sstevel@tonic-gate 			hs = hs->hs_next;
7690Sstevel@tonic-gate 		}
7700Sstevel@tonic-gate 	}
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	if (hs == NULL) {
7730Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
7740Sstevel@tonic-gate 		    shs->shs_component_old));
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	/* check the force flag and the state of the hot spare */
7780Sstevel@tonic-gate 	if (((shs->shs_options & HS_OPT_FORCE) == 0) &&
7790Sstevel@tonic-gate 	    (hs->hs_state == HSS_RESERVED)) {
7800Sstevel@tonic-gate 		return (mdhserror(&shs->mde, MDE_HS_RESVD,
7810Sstevel@tonic-gate 		    shs->shs_hot_spare_pool,
7820Sstevel@tonic-gate 		    hs->hs_devnum));
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	/* Scan the hot spare pool list */
7860Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
7870Sstevel@tonic-gate 	if (hsp == (hot_spare_pool_t *)0) {
7880Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
7890Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	/*
7930Sstevel@tonic-gate 	 * Make sure the old device is in the pool.
7940Sstevel@tonic-gate 	 */
7950Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
7960Sstevel@tonic-gate 		if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
7970Sstevel@tonic-gate 			break;
7980Sstevel@tonic-gate 		}
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 	if (i >= hsp->hsp_nhotspares) {
8010Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
8020Sstevel@tonic-gate 		    hs->hs_devnum));
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	/* Scan the hot spare list for the new hs */
8060Sstevel@tonic-gate 	new_hs = (hot_spare_t *)md_set[setno].s_hs;
8070Sstevel@tonic-gate 	new_found = 0;
8080Sstevel@tonic-gate 	while (new_hs) {
8090Sstevel@tonic-gate 		if (new_hs->hs_devnum == shs->shs_component_new) {
8100Sstevel@tonic-gate 			new_found = 1;
8110Sstevel@tonic-gate 			break;
8120Sstevel@tonic-gate 		}
8130Sstevel@tonic-gate 		new_hs = new_hs->hs_next;
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	/*
8170Sstevel@tonic-gate 	 * Make sure the new device is not already in the pool.
8180Sstevel@tonic-gate 	 * We don't have to search the hs in this hsp, if the
8190Sstevel@tonic-gate 	 * new hs was just created. Only if the hot spare was found.
8200Sstevel@tonic-gate 	 */
8210Sstevel@tonic-gate 	if (new_found) {
8220Sstevel@tonic-gate 		for (i = 0; i < hsp->hsp_nhotspares; i++)
8230Sstevel@tonic-gate 			if (hsp->hsp_hotspares[i] == new_hs->hs_record_id) {
8240Sstevel@tonic-gate 				return (mdhserror(&shs->mde, MDE_HS_INUSE,
8250Sstevel@tonic-gate 				    shs->shs_hot_spare_pool,
8260Sstevel@tonic-gate 				    new_hs->hs_devnum));
8270Sstevel@tonic-gate 			}
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	/* In case of a dryrun, we're done here */
8310Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
8320Sstevel@tonic-gate 		return (0);
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	/*
8360Sstevel@tonic-gate 	 * Create the new hotspare
8370Sstevel@tonic-gate 	 */
8380Sstevel@tonic-gate 	if (!new_found) {
8390Sstevel@tonic-gate 		/* create a hot spare record */
8400Sstevel@tonic-gate 		if (shs->shs_size_option & MD_CRO_64BIT) {
8410Sstevel@tonic-gate #if defined(_ILP32)
8420Sstevel@tonic-gate 			return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE,
8430Sstevel@tonic-gate 			    shs->shs_hot_spare_pool, shs->shs_component_new));
8440Sstevel@tonic-gate #else
8450Sstevel@tonic-gate 			recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
8460Sstevel@tonic-gate 				MD_CRO_64BIT | MD_CRO_HOTSPARE, setno);
8470Sstevel@tonic-gate #endif
8480Sstevel@tonic-gate 		} else {
8490Sstevel@tonic-gate 			recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
8500Sstevel@tonic-gate 				MD_CRO_32BIT | MD_CRO_HOTSPARE, setno);
8510Sstevel@tonic-gate 		}
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		if (recid < 0) {
8540Sstevel@tonic-gate 			return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE,
8550Sstevel@tonic-gate 			    shs->shs_hot_spare_pool,
8560Sstevel@tonic-gate 			    shs->shs_component_new));
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		/* get the addr */
8600Sstevel@tonic-gate 		new_hs = (hot_spare_t *)mddb_getrecaddr_resize(recid,
8610Sstevel@tonic-gate 			sizeof (*new_hs), 0);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 		new_hs->hs_record_id = recid;
8640Sstevel@tonic-gate 		new_hs->hs_devnum = shs->shs_component_new;
8650Sstevel@tonic-gate 		new_hs->hs_key = shs->shs_key_new;
8660Sstevel@tonic-gate 		new_hs->hs_start_blk = shs->shs_start_blk;
8670Sstevel@tonic-gate 		new_hs->hs_has_label = shs->shs_has_label;
8680Sstevel@tonic-gate 		new_hs->hs_number_blks = shs->shs_number_blks;
8690Sstevel@tonic-gate 		set_hot_spare_state(new_hs, HSS_AVAILABLE);
8700Sstevel@tonic-gate 		new_hs->hs_refcount = 0;
8710Sstevel@tonic-gate 		new_hs->hs_isopen = 1;
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	/* lock the db records */
8750Sstevel@tonic-gate 	recids[0] = hs->hs_record_id;
8760Sstevel@tonic-gate 	recids[1] = new_hs->hs_record_id;
8770Sstevel@tonic-gate 	recids[2] = hsp->hsp_record_id;
8780Sstevel@tonic-gate 	recids[3] = 0;
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	sv.setno = setno;
8810Sstevel@tonic-gate 	sv.key = hs->hs_key;
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	hs->hs_refcount--;
8840Sstevel@tonic-gate 	if (hs->hs_refcount == 0) {
8850Sstevel@tonic-gate 		/*
8860Sstevel@tonic-gate 		 * NOTE: We do not commit the previous hot spare record.
8870Sstevel@tonic-gate 		 *	 There is no need, the link we get rebuilt at boot time.
8880Sstevel@tonic-gate 		 */
8890Sstevel@tonic-gate 		if (prev_hs) {
8900Sstevel@tonic-gate 			prev_hs->hs_next = hs->hs_next;
8910Sstevel@tonic-gate 		} else
8920Sstevel@tonic-gate 			md_set[setno].s_hs = (void *) hs->hs_next;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 		/* mark hs to be deleted in the correct order */
8950Sstevel@tonic-gate 		delete_hs = 1;
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 		recids[0] = new_hs->hs_record_id;
8980Sstevel@tonic-gate 		recids[1] = hsp->hsp_record_id;
8990Sstevel@tonic-gate 		recids[2] = 0;
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	/* link into the hs list */
9030Sstevel@tonic-gate 	new_hs->hs_refcount++;
9040Sstevel@tonic-gate 	if (!new_found) {
9050Sstevel@tonic-gate 		/* do this AFTER the old dev is possibly removed */
9060Sstevel@tonic-gate 		new_hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
9070Sstevel@tonic-gate 		md_set[setno].s_hs = (void *) new_hs;
9080Sstevel@tonic-gate 	}
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	/* find the location of the old hs in the hsp */
9110Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
9120Sstevel@tonic-gate 		if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
9130Sstevel@tonic-gate 			hsp->hsp_hotspares[i] = new_hs->hs_record_id;
9140Sstevel@tonic-gate 			break;
9150Sstevel@tonic-gate 		}
9160Sstevel@tonic-gate 	}
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	if (shs->shs_size_option & MD_CRO_64BIT) {
9191623Stw21770 		new_hs->hs_revision |= MD_64BIT_META_DEV;
9200Sstevel@tonic-gate 	} else {
9211623Stw21770 		new_hs->hs_revision &= ~MD_64BIT_META_DEV;
9220Sstevel@tonic-gate 	}
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	/* commit the db records */
9250Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	if (delete_hs)
9280Sstevel@tonic-gate 		mddb_deleterec_wrapper(hs->hs_record_id);
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	md_rem_names(&sv, 1);
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REPLACE, SVM_TAG_HSP, setno,
9330Sstevel@tonic-gate 	    md_expldev(hsp->hsp_self_id));
9340Sstevel@tonic-gate 	return (0);
9350Sstevel@tonic-gate }
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate static int
seths_enable(set_hs_params_t * shs)9380Sstevel@tonic-gate seths_enable(set_hs_params_t *shs)
9390Sstevel@tonic-gate {
9400Sstevel@tonic-gate 	hot_spare_t	*hs;
9410Sstevel@tonic-gate 	mddb_recid_t	recids[2];
9420Sstevel@tonic-gate 	set_t		setno = shs->md_driver.md_setno;
9430Sstevel@tonic-gate 	mdkey_t		key_old;
9440Sstevel@tonic-gate 	int		num_keys_old = 0;
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	/*
9480Sstevel@tonic-gate 	 * Find device by using key associated with shs_component_old.
9490Sstevel@tonic-gate 	 * If unable to find a unique key for shs_component_old
9500Sstevel@tonic-gate 	 * then fail since namespace has multiple entries
9510Sstevel@tonic-gate 	 * for this old component and we're unable to determine
9520Sstevel@tonic-gate 	 * which key is the valid match for shs_component_old.
9530Sstevel@tonic-gate 	 * This failure keeps a hotspare from being enabled on a slice
9540Sstevel@tonic-gate 	 * that may already be in use by another metadevice.
9550Sstevel@tonic-gate 	 */
9560Sstevel@tonic-gate 	if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
9570Sstevel@tonic-gate 	    shs->shs_component_old, &key_old, &num_keys_old) != 0) {
9580Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_NAME_SPACE,
9590Sstevel@tonic-gate 		    shs->shs_component_old));
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	/*
9630Sstevel@tonic-gate 	 * If more than one key matches given old_dev - fail command
9640Sstevel@tonic-gate 	 * since unable to determine which key is correct.
9650Sstevel@tonic-gate 	 */
9660Sstevel@tonic-gate 	if (num_keys_old > 1) {
9670Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_MULTNM,
9680Sstevel@tonic-gate 		    shs->shs_component_old));
9690Sstevel@tonic-gate 	}
9700Sstevel@tonic-gate 	/*
9710Sstevel@tonic-gate 	 * If there is no key for this entry then fail since
9720Sstevel@tonic-gate 	 * a key for this entry should exist.
9730Sstevel@tonic-gate 	 */
9740Sstevel@tonic-gate 	if (num_keys_old == 0) {
9750Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
9760Sstevel@tonic-gate 		    shs->shs_component_old));
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	/* Scan the hot spare list for the hs */
9800Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
9810Sstevel@tonic-gate 	while (hs) {
9820Sstevel@tonic-gate 		/*
9830Sstevel@tonic-gate 		 * Since component may or may not be currently in the system,
9840Sstevel@tonic-gate 		 * use the keys to find a match (not the devt).
9850Sstevel@tonic-gate 		 */
9860Sstevel@tonic-gate 		if (hs->hs_key == key_old) {
9870Sstevel@tonic-gate 			break;
9880Sstevel@tonic-gate 		}
9890Sstevel@tonic-gate 		hs = hs->hs_next;
9900Sstevel@tonic-gate 	}
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	if (hs == NULL) {
9930Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
9940Sstevel@tonic-gate 			shs->shs_component_old));
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	/* make sure it's broken */
9980Sstevel@tonic-gate 	if (hs->hs_state != HSS_BROKEN) {
9990Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_FIX_INVAL_HS_STATE,
10000Sstevel@tonic-gate 		    hs->hs_devnum));
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	/* In case of a dryrun, we're done here */
10040Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
10050Sstevel@tonic-gate 		return (0);
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	/* fix it */
10090Sstevel@tonic-gate 	set_hot_spare_state(hs, HSS_AVAILABLE);
10100Sstevel@tonic-gate 	hs->hs_start_blk = shs->shs_start_blk;
10110Sstevel@tonic-gate 	hs->hs_has_label = shs->shs_has_label;
10120Sstevel@tonic-gate 	hs->hs_number_blks = shs->shs_number_blks;
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	/* commit the db records */
10150Sstevel@tonic-gate 	recids[0] = hs->hs_record_id;
10160Sstevel@tonic-gate 	recids[1] = 0;
10170Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
10180Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ENABLE, SVM_TAG_HS, setno,
10190Sstevel@tonic-gate 	    shs->shs_component_old);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	return (0);
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate static int
get_hs(get_hs_params_t * ghs)10250Sstevel@tonic-gate get_hs(
10260Sstevel@tonic-gate 	get_hs_params_t	*ghs
10270Sstevel@tonic-gate )
10280Sstevel@tonic-gate {
10290Sstevel@tonic-gate 	hot_spare_t	*hs;
10300Sstevel@tonic-gate 	set_t		setno = ghs->md_driver.md_setno;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	mdclrerror(&ghs->mde);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	/* Scan the hot spare list for the hs */
10350Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
10360Sstevel@tonic-gate 	while (hs) {
10370Sstevel@tonic-gate 		if (hs->hs_key == ghs->ghs_key) {
10380Sstevel@tonic-gate 			break;
10390Sstevel@tonic-gate 		}
10400Sstevel@tonic-gate 		hs = hs->hs_next;
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	if (hs == NULL) {
10440Sstevel@tonic-gate 		return (mddeverror(&ghs->mde, MDE_INVAL_HS,
10450Sstevel@tonic-gate 		    ghs->ghs_devnum));
10460Sstevel@tonic-gate 	}
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	ghs->ghs_start_blk = hs->hs_start_blk;
10490Sstevel@tonic-gate 	ghs->ghs_number_blks = hs->hs_number_blks;
10500Sstevel@tonic-gate 	ghs->ghs_state = hs->hs_state;
10510Sstevel@tonic-gate 	ghs->ghs_timestamp = hs->hs_timestamp;
10520Sstevel@tonic-gate 	ghs->ghs_revision = hs->hs_revision;
10530Sstevel@tonic-gate 	return (0);
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate static void
build_key_list(set_t setno,hot_spare_pool_t * hsp,mdkey_t * list)10570Sstevel@tonic-gate build_key_list(set_t setno, hot_spare_pool_t *hsp, mdkey_t *list)
10580Sstevel@tonic-gate {
10590Sstevel@tonic-gate 	int	i;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
10620Sstevel@tonic-gate 		hot_spare_t *hs;
10630Sstevel@tonic-gate 		hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1);
10640Sstevel@tonic-gate 		list[i] = hs->hs_key;
10650Sstevel@tonic-gate 	}
10660Sstevel@tonic-gate }
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate static int
get_hsp(void * d,int mode)10690Sstevel@tonic-gate get_hsp(
10700Sstevel@tonic-gate 	void			*d,
10710Sstevel@tonic-gate 	int			mode
10720Sstevel@tonic-gate )
10730Sstevel@tonic-gate {
10740Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
10750Sstevel@tonic-gate 	get_hsp_t		*ghsp;
10760Sstevel@tonic-gate 	size_t			size;
10770Sstevel@tonic-gate 	set_t			setno;
10780Sstevel@tonic-gate 	int			err = 0;
10790Sstevel@tonic-gate 	md_i_get_t		*migp = (md_i_get_t *)d;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	setno = migp->md_driver.md_setno;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	mdclrerror(&migp->mde);
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	/* Scan the hot spare pool list */
10870Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, migp->id);
10880Sstevel@tonic-gate 	if (hsp == NULL) {
10890Sstevel@tonic-gate 		return (mdhsperror(&migp->mde, MDE_INVAL_HSP,
10900Sstevel@tonic-gate 			migp->id));
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	size = (sizeof (ghsp->ghsp_hs_keys[0]) * (hsp->hsp_nhotspares - 1)) +
10940Sstevel@tonic-gate 	    sizeof (get_hsp_t);
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	if (migp->size == 0) {
10970Sstevel@tonic-gate 		migp->size = (int)size;
10980Sstevel@tonic-gate 		return (0);
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	if (migp->size < size)
11020Sstevel@tonic-gate 		return (EFAULT);
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	ghsp = kmem_alloc(size, KM_SLEEP);
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	ghsp->ghsp_id = hsp->hsp_self_id;
11070Sstevel@tonic-gate 	ghsp->ghsp_refcount = hsp->hsp_refcount;
11080Sstevel@tonic-gate 	ghsp->ghsp_nhotspares = hsp->hsp_nhotspares;
11090Sstevel@tonic-gate 	build_key_list(setno, hsp, ghsp->ghsp_hs_keys);
11100Sstevel@tonic-gate 	if (ddi_copyout(ghsp, (caddr_t)(uintptr_t)migp->mdp, size, mode))
11110Sstevel@tonic-gate 		err = EFAULT;
11120Sstevel@tonic-gate 	kmem_free(ghsp, size);
11130Sstevel@tonic-gate 	return (err);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate static int
set_hs(set_hs_params_t * shs)11170Sstevel@tonic-gate set_hs(
11180Sstevel@tonic-gate 	set_hs_params_t	*shs
11190Sstevel@tonic-gate )
11200Sstevel@tonic-gate {
11210Sstevel@tonic-gate 	mdclrerror(&shs->mde);
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	if (md_get_setstatus(shs->md_driver.md_setno) & MD_SET_STALE)
11240Sstevel@tonic-gate 		return (mdmddberror(&shs->mde, MDE_DB_STALE, NODEV32,
11250Sstevel@tonic-gate 		    shs->md_driver.md_setno));
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	switch (shs->shs_cmd) {
11280Sstevel@tonic-gate 	case ADD_HOT_SPARE:
11290Sstevel@tonic-gate 		return (seths_add(shs));
11300Sstevel@tonic-gate 	case DELETE_HOT_SPARE:
11310Sstevel@tonic-gate 		return (seths_delete(shs));
11320Sstevel@tonic-gate 	case REPLACE_HOT_SPARE:
11330Sstevel@tonic-gate 		return (seths_replace(shs));
11340Sstevel@tonic-gate 	case FIX_HOT_SPARE:
11350Sstevel@tonic-gate 		return (seths_enable(shs));
11360Sstevel@tonic-gate 	default:
11370Sstevel@tonic-gate 		return (mderror(&shs->mde, MDE_INVAL_HSOP));
11380Sstevel@tonic-gate 	}
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate static void
hotspares_poke_hotspares(void)11420Sstevel@tonic-gate hotspares_poke_hotspares(void)
11430Sstevel@tonic-gate {
11440Sstevel@tonic-gate 	intptr_t	(*poke_hs)();
11450Sstevel@tonic-gate 	int		i;
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 	for (i = 0; i < MD_NOPS; i++) {
11480Sstevel@tonic-gate 		/* handle change */
11490Sstevel@tonic-gate 		poke_hs = md_get_named_service(NODEV64, i, "poke hotspares", 0);
11500Sstevel@tonic-gate 		if (poke_hs)
11510Sstevel@tonic-gate 			(void) (*poke_hs)();
11520Sstevel@tonic-gate 	}
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate /*ARGSUSED4*/
11570Sstevel@tonic-gate static int
hotspares_ioctl(dev_t dev,int cmd,void * data,int mode,IOLOCK * lockp)11580Sstevel@tonic-gate hotspares_ioctl(
11590Sstevel@tonic-gate 	dev_t	dev,
11600Sstevel@tonic-gate 	int	cmd,
11610Sstevel@tonic-gate 	void	*data,
11620Sstevel@tonic-gate 	int	mode,
11630Sstevel@tonic-gate 	IOLOCK	*lockp
11640Sstevel@tonic-gate )
11650Sstevel@tonic-gate {
11660Sstevel@tonic-gate 	size_t	sz = 0;
11670Sstevel@tonic-gate 	void	*d = NULL;
11680Sstevel@tonic-gate 	int	err = 0;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	/* single thread */
11710Sstevel@tonic-gate 	if (getminor(dev) != MD_ADM_MINOR)
11720Sstevel@tonic-gate 		return (ENOTTY);
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	/* We can only handle 32-bit clients for internal commands */
11750Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) != DATAMODEL_ILP32) {
11760Sstevel@tonic-gate 		return (EINVAL);
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	mutex_enter(&md_mx);
11800Sstevel@tonic-gate 	while (md_status & MD_GBL_HS_LOCK)
11810Sstevel@tonic-gate 		cv_wait(&md_cv, &md_mx);
11820Sstevel@tonic-gate 	md_status |= MD_GBL_HS_LOCK;
11830Sstevel@tonic-gate 	mutex_exit(&md_mx);
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	/* dispatch ioctl */
11860Sstevel@tonic-gate 	switch (cmd) {
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	case MD_IOCSET_HS:	/* setup hot spares and pools */
11890Sstevel@tonic-gate 	{
11900Sstevel@tonic-gate 		if (! (mode & FWRITE)) {
11910Sstevel@tonic-gate 			err = EACCES;
11920Sstevel@tonic-gate 			break;
11930Sstevel@tonic-gate 		}
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 		sz = sizeof (set_hs_params_t);
11960Sstevel@tonic-gate 		d = kmem_alloc(sz, KM_SLEEP);
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
11990Sstevel@tonic-gate 			err = EFAULT;
12000Sstevel@tonic-gate 			break;
12010Sstevel@tonic-gate 		}
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 		err = set_hs(d);
12040Sstevel@tonic-gate 		break;
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	case MD_IOCGET_HS:	/* get hot spare info */
12080Sstevel@tonic-gate 	{
12090Sstevel@tonic-gate 		if (! (mode & FREAD)) {
12100Sstevel@tonic-gate 			err = EACCES;
12110Sstevel@tonic-gate 			break;
12120Sstevel@tonic-gate 		}
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 		sz = sizeof (get_hs_params_t);
12150Sstevel@tonic-gate 		d = kmem_alloc(sz, KM_SLEEP);
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
12180Sstevel@tonic-gate 			err = EFAULT;
12190Sstevel@tonic-gate 			break;
12200Sstevel@tonic-gate 		}
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 		err = get_hs(d);
12230Sstevel@tonic-gate 		break;
12240Sstevel@tonic-gate 	}
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	case MD_IOCGET:		/* get hot spare pool info */
12270Sstevel@tonic-gate 	{
12280Sstevel@tonic-gate 		if (! (mode & FREAD)) {
12290Sstevel@tonic-gate 			err = EACCES;
12300Sstevel@tonic-gate 			break;
12310Sstevel@tonic-gate 		}
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
12340Sstevel@tonic-gate 		d = kmem_alloc(sz, KM_SLEEP);
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
12370Sstevel@tonic-gate 			err = EFAULT;
12380Sstevel@tonic-gate 			break;
12390Sstevel@tonic-gate 		}
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 		err = get_hsp(d, mode);
12420Sstevel@tonic-gate 		break;
12430Sstevel@tonic-gate 	}
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	default:
12460Sstevel@tonic-gate 		err = ENOTTY;
12470Sstevel@tonic-gate 	}
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	/*
12500Sstevel@tonic-gate 	 * copyout and free any args
12510Sstevel@tonic-gate 	 */
12520Sstevel@tonic-gate 	if (sz != 0) {
12530Sstevel@tonic-gate 		if (err == 0) {
12540Sstevel@tonic-gate 			if (ddi_copyout(d, data, sz, mode) != 0) {
12550Sstevel@tonic-gate 				err = EFAULT;
12560Sstevel@tonic-gate 			}
12570Sstevel@tonic-gate 		}
12580Sstevel@tonic-gate 		kmem_free(d, sz);
12590Sstevel@tonic-gate 	}
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	/* un single thread */
12620Sstevel@tonic-gate 	mutex_enter(&md_mx);
12630Sstevel@tonic-gate 	md_status &= ~MD_GBL_HS_LOCK;
12640Sstevel@tonic-gate 	cv_broadcast(&md_cv);
12650Sstevel@tonic-gate 	mutex_exit(&md_mx);
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	/* handle change */
12680Sstevel@tonic-gate 	hotspares_poke_hotspares();
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	/* return success */
12710Sstevel@tonic-gate 	return (err);
12720Sstevel@tonic-gate }
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate static void
load_hotspare(set_t setno,mddb_recid_t recid)12760Sstevel@tonic-gate load_hotspare(set_t setno, mddb_recid_t recid)
12770Sstevel@tonic-gate {
12780Sstevel@tonic-gate 	hot_spare_t	*hs;
12790Sstevel@tonic-gate 	mddb_de_ic_t	*dep;
12800Sstevel@tonic-gate 	mddb_rb32_t	*rbp;
12810Sstevel@tonic-gate 	size_t		newreqsize;
12820Sstevel@tonic-gate 	hot_spare_t	*b_hs;
12830Sstevel@tonic-gate 	hot_spare32_od_t *s_hs;
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	mddb_setrecprivate(recid, MD_PRV_GOTIT);
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	dep = mddb_getrecdep(recid);
12880Sstevel@tonic-gate 	dep->de_flags = MDDB_F_HOTSPARE;
12890Sstevel@tonic-gate 	rbp = dep->de_rb;
12901623Stw21770 	switch (rbp->rb_revision) {
12911623Stw21770 	case MDDB_REV_RB:
12921623Stw21770 	case MDDB_REV_RBFN:
12930Sstevel@tonic-gate 		/*
12940Sstevel@tonic-gate 		 * Needs to convert to internal 64 bit
12950Sstevel@tonic-gate 		 */
12960Sstevel@tonic-gate 		s_hs = (hot_spare32_od_t *)mddb_getrecaddr(recid);
12970Sstevel@tonic-gate 		newreqsize = sizeof (hot_spare_t);
12980Sstevel@tonic-gate 		b_hs = (hot_spare_t *)kmem_zalloc(newreqsize, KM_SLEEP);
12990Sstevel@tonic-gate 		hs_convert((caddr_t)s_hs, (caddr_t)b_hs, SMALL_2_BIG);
13000Sstevel@tonic-gate 		kmem_free(s_hs, dep->de_reqsize);
13010Sstevel@tonic-gate 		dep->de_rb_userdata = b_hs;
13020Sstevel@tonic-gate 		dep->de_reqsize = newreqsize;
13030Sstevel@tonic-gate 		hs = b_hs;
13041623Stw21770 		break;
13051623Stw21770 	case MDDB_REV_RB64:
13061623Stw21770 	case MDDB_REV_RB64FN:
13070Sstevel@tonic-gate 		hs = (hot_spare_t *)mddb_getrecaddr_resize
13080Sstevel@tonic-gate 			(recid, sizeof (*hs), 0);
13091623Stw21770 		break;
13100Sstevel@tonic-gate 	}
13112077Stw21770 	MDDB_NOTE_FN(rbp->rb_revision, hs->hs_revision);
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate #if defined(_ILP32)
13141623Stw21770 	if (hs->hs_revision & MD_64BIT_META_DEV) {
13150Sstevel@tonic-gate 		char	devname[MD_MAX_CTDLEN];
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 		set_hot_spare_state(hs, HSS_BROKEN);
13180Sstevel@tonic-gate 		(void) md_devname(setno, hs->hs_devnum, devname,
13190Sstevel@tonic-gate 		    sizeof (devname));
13200Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%s is unavailable because 64 bit hotspares "
13210Sstevel@tonic-gate 		    "are not accessible on a 32 bit kernel\n", devname);
13220Sstevel@tonic-gate 	}
13230Sstevel@tonic-gate #endif
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 	ASSERT(hs != NULL);
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	if (hs->hs_refcount == 0) {
13280Sstevel@tonic-gate 		mddb_setrecprivate(recid, MD_PRV_PENDDEL);
13290Sstevel@tonic-gate 		return;
13300Sstevel@tonic-gate 	}
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
13330Sstevel@tonic-gate 	md_set[setno].s_hs = (void *)hs;
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	hs->hs_isopen = 0;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	hs->hs_devnum = md_getdevnum(setno, mddb_getsidenum(setno),
13380Sstevel@tonic-gate 		hs->hs_key, MD_NOTRUST_DEVT);
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate static void
load_hotsparepool(set_t setno,mddb_recid_t recid)13430Sstevel@tonic-gate load_hotsparepool(set_t setno, mddb_recid_t recid)
13440Sstevel@tonic-gate {
13450Sstevel@tonic-gate 	hot_spare_pool_t *hsp;
13460Sstevel@tonic-gate 	hot_spare_pool_ond_t *hsp_ond;
13470Sstevel@tonic-gate 	size_t hsp_icsize;
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	mddb_setrecprivate(recid, MD_PRV_GOTIT);
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid);
13520Sstevel@tonic-gate 	ASSERT(hsp_ond != NULL);
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	if (hsp_ond->hsp_self_id == MD_HSP_NONE) {
13550Sstevel@tonic-gate 		mddb_setrecprivate(recid, MD_PRV_PENDDEL);
13560Sstevel@tonic-gate 		return;
13570Sstevel@tonic-gate 	}
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	hsp_icsize =  HSP_ONDSK_STR_OFF + mddb_getrecsize(recid);
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, hsp_icsize,
13620Sstevel@tonic-gate 		HSP_ONDSK_STR_OFF);
13630Sstevel@tonic-gate 	hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
13640Sstevel@tonic-gate 	md_set[setno].s_hsp = (void *) hsp;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
13670Sstevel@tonic-gate 	hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
13680Sstevel@tonic-gate 	hsp->hsp_link.ln_setno = setno;
13690Sstevel@tonic-gate 	hsp->hsp_link.ln_id = hsp->hsp_self_id;
13700Sstevel@tonic-gate 	hotspares_md_ops.md_head = &hsp->hsp_link;
13710Sstevel@tonic-gate 	rw_exit(&hotspares_md_ops.md_link_rw.lock);
13720Sstevel@tonic-gate }
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate static int
hotspares_snarf(md_snarfcmd_t cmd,set_t setno)13750Sstevel@tonic-gate hotspares_snarf(md_snarfcmd_t cmd, set_t setno)
13760Sstevel@tonic-gate {
13770Sstevel@tonic-gate 	mddb_recid_t	recid;
13780Sstevel@tonic-gate 	int		gotsomething;
13790Sstevel@tonic-gate 	mddb_type_t	typ1;
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	if (cmd == MD_SNARF_CLEANUP)
13820Sstevel@tonic-gate 		return (0);
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	gotsomething = 0;
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
13870Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
13880Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
13890Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) {
13900Sstevel@tonic-gate 		if (mddb_getrecprivate(recid) & MD_PRV_GOTIT)
13910Sstevel@tonic-gate 			continue;
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 		switch (mddb_getrectype2(recid)) {
13940Sstevel@tonic-gate 		case HSP_REC:
13950Sstevel@tonic-gate 			load_hotsparepool(setno, recid);
13960Sstevel@tonic-gate 			gotsomething = 1;
13970Sstevel@tonic-gate 			break;
13980Sstevel@tonic-gate 		case HS_REC:
13990Sstevel@tonic-gate 			load_hotspare(setno, recid);
14000Sstevel@tonic-gate 			gotsomething = 1;
14010Sstevel@tonic-gate 			break;
14020Sstevel@tonic-gate 		default:
14030Sstevel@tonic-gate 			ASSERT(0);
14040Sstevel@tonic-gate 		}
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 	if (gotsomething)
14080Sstevel@tonic-gate 		return (gotsomething);
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
14110Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0)
14120Sstevel@tonic-gate 		if (!(mddb_getrecprivate(recid) & MD_PRV_GOTIT))
14130Sstevel@tonic-gate 			mddb_setrecprivate(recid, MD_PRV_PENDDEL);
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	return (0);
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate static int
hotspares_halt(md_haltcmd_t cmd,set_t setno)14190Sstevel@tonic-gate hotspares_halt(md_haltcmd_t cmd, set_t setno)
14200Sstevel@tonic-gate {
14210Sstevel@tonic-gate 	hot_spare_t		*hs, **p_hs;
14220Sstevel@tonic-gate 	hot_spare_pool_t	*hsp, **p_hsp;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	if (cmd == MD_HALT_CLOSE)
14250Sstevel@tonic-gate 		return (0);
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 	if (cmd == MD_HALT_OPEN)
14280Sstevel@tonic-gate 		return (0);
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	if (cmd == MD_HALT_CHECK)
14310Sstevel@tonic-gate 		return (0);
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	if (cmd == MD_HALT_UNLOAD)
14340Sstevel@tonic-gate 		return (0);
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	if (cmd != MD_HALT_DOIT)
14370Sstevel@tonic-gate 		return (1);
14380Sstevel@tonic-gate 	/*
14390Sstevel@tonic-gate 	 * Find all the hotspares for set "setno"
14400Sstevel@tonic-gate 	 *   and remove them from the hot_spare_list.
14410Sstevel@tonic-gate 	 */
14420Sstevel@tonic-gate 	p_hs = (hot_spare_t **)&md_set[setno].s_hs;
14430Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
14440Sstevel@tonic-gate 	for (; hs != NULL; hs = *p_hs)
14450Sstevel@tonic-gate 		*p_hs = hs->hs_next;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	/*
14480Sstevel@tonic-gate 	 * Find all the hotspare pools for set "setno"
14490Sstevel@tonic-gate 	 *   and remove them from the hot_spare_pools list.
14500Sstevel@tonic-gate 	 * Also remove from the get_next list.
14510Sstevel@tonic-gate 	 */
14520Sstevel@tonic-gate 	p_hsp = (hot_spare_pool_t **)&md_set[setno].s_hsp;
14530Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
14540Sstevel@tonic-gate 	for (; hsp != NULL; hsp = *p_hsp) {
14550Sstevel@tonic-gate 		md_rem_link(setno, hsp->hsp_self_id,
14560Sstevel@tonic-gate 		    &hotspares_md_ops.md_link_rw.lock,
14570Sstevel@tonic-gate 		    &hotspares_md_ops.md_head);
14580Sstevel@tonic-gate 		*p_hsp = hsp->hsp_next;
14590Sstevel@tonic-gate 	}
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	return (0);
14620Sstevel@tonic-gate }
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate static hot_spare_t *
usable_hs(set_t setno,mddb_recid_t hs_id,diskaddr_t nblks,int labeled,diskaddr_t * start)14650Sstevel@tonic-gate usable_hs(
14660Sstevel@tonic-gate 	set_t		setno,
14670Sstevel@tonic-gate 	mddb_recid_t	hs_id,
14680Sstevel@tonic-gate 	diskaddr_t	nblks,
14690Sstevel@tonic-gate 	int		labeled,
14700Sstevel@tonic-gate 	diskaddr_t	*start)
14710Sstevel@tonic-gate {
14720Sstevel@tonic-gate 	hot_spare_t	*hs;
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	hs = lookup_hot_spare(setno, hs_id, 1);
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	if (hs->hs_state != HSS_AVAILABLE)
14770Sstevel@tonic-gate 		return ((hot_spare_t *)0);
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	if (labeled && hs->hs_has_label && (hs->hs_number_blks >= nblks)) {
14800Sstevel@tonic-gate 		*start = 0;
14810Sstevel@tonic-gate 		return (hs);
14820Sstevel@tonic-gate 	} else if ((hs->hs_number_blks - hs->hs_start_blk) >= nblks) {
14830Sstevel@tonic-gate 		*start = hs->hs_start_blk;
14840Sstevel@tonic-gate 		return (hs);
14850Sstevel@tonic-gate 	}
14860Sstevel@tonic-gate 	return ((hot_spare_t *)0);
14870Sstevel@tonic-gate }
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate static int
reserve_a_hs(set_t setno,mddb_recid_t id,uint64_t size,int labeled,mddb_recid_t * hs_id,mdkey_t * key,md_dev64_t * dev,diskaddr_t * sblock)14900Sstevel@tonic-gate reserve_a_hs(
14910Sstevel@tonic-gate 	set_t		setno,
14920Sstevel@tonic-gate 	mddb_recid_t	id,
14930Sstevel@tonic-gate 	uint64_t	size,
14940Sstevel@tonic-gate 	int		labeled,
14950Sstevel@tonic-gate 	mddb_recid_t	*hs_id,
14960Sstevel@tonic-gate 	mdkey_t		*key,
14970Sstevel@tonic-gate 	md_dev64_t	*dev,
14980Sstevel@tonic-gate 	diskaddr_t	*sblock)
14990Sstevel@tonic-gate {
15000Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
15010Sstevel@tonic-gate 	hot_spare_t		*hs;
15020Sstevel@tonic-gate 	int			i;
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	*hs_id = 0;
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, id);
15070Sstevel@tonic-gate 	if (hsp == NULL)
15080Sstevel@tonic-gate 		return (-1);
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
15110Sstevel@tonic-gate 		hs = usable_hs(setno, hsp->hsp_hotspares[i],
15120Sstevel@tonic-gate 		    size, labeled, sblock);
15130Sstevel@tonic-gate 		if (hs == NULL)
15140Sstevel@tonic-gate 			continue;
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 		set_hot_spare_state(hs, HSS_RESERVED);
15170Sstevel@tonic-gate 		*hs_id = hs->hs_record_id;
15180Sstevel@tonic-gate 		*key = hs->hs_key;
15190Sstevel@tonic-gate 		*dev = hs->hs_devnum;
15200Sstevel@tonic-gate 		/* NOTE: Mirror code commits the hs record */
15210Sstevel@tonic-gate 		return (0);
15220Sstevel@tonic-gate 	}
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	return (-1);
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate /* ARGSUSED3 */
15290Sstevel@tonic-gate static int
return_a_hs(set_t setno,mddb_recid_t id,mddb_recid_t * hs_id,mdkey_t key,diskaddr_t sblock,uint64_t size,hotspare_states_t new_state)15300Sstevel@tonic-gate return_a_hs(
15310Sstevel@tonic-gate 	set_t			setno,
15320Sstevel@tonic-gate 	mddb_recid_t		id,
15330Sstevel@tonic-gate 	mddb_recid_t		*hs_id,
15340Sstevel@tonic-gate 	mdkey_t			key,
15350Sstevel@tonic-gate 	diskaddr_t		sblock,
15360Sstevel@tonic-gate 	uint64_t		size,
15370Sstevel@tonic-gate 	hotspare_states_t	new_state)
15380Sstevel@tonic-gate {
15390Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
15400Sstevel@tonic-gate 	hot_spare_t		*hs;
15410Sstevel@tonic-gate 	int			i;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 	/*
15440Sstevel@tonic-gate 	 * NOTE: sblock/size are not currently being used.
15450Sstevel@tonic-gate 	 *	 That is because we always allocate the whole hs.
15460Sstevel@tonic-gate 	 *	 Later if we choose to allocate only what is needed
15470Sstevel@tonic-gate 	 *	 then the sblock/size can be used to determine
15480Sstevel@tonic-gate 	 *	 which part is being unreseved.
15490Sstevel@tonic-gate 	 */
15500Sstevel@tonic-gate 	*hs_id = 0;
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, id);
15530Sstevel@tonic-gate 	if (hsp == NULL)
15540Sstevel@tonic-gate 		return (-1);
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
15570Sstevel@tonic-gate 		hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1);
15580Sstevel@tonic-gate 		if (hs->hs_key != key)
15590Sstevel@tonic-gate 			continue;
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 		set_hot_spare_state(hs, new_state);
15620Sstevel@tonic-gate 		*hs_id = hs->hs_record_id;
15630Sstevel@tonic-gate 		if (new_state == HSS_BROKEN) {
15640Sstevel@tonic-gate 			SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ERRED, SVM_TAG_HS,
15650Sstevel@tonic-gate 			    setno, hs->hs_devnum);
15660Sstevel@tonic-gate 		}
15670Sstevel@tonic-gate 		if (new_state == HSS_AVAILABLE) {
15680Sstevel@tonic-gate 			SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_HS,
15690Sstevel@tonic-gate 			    setno, hs->hs_devnum);
15700Sstevel@tonic-gate 		}
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 		/* NOTE: Mirror/Raid code commits the hs record */
15730Sstevel@tonic-gate 		return (0);
15740Sstevel@tonic-gate 	}
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	return (-1);
15770Sstevel@tonic-gate }
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate static int
modify_hsp_ref(set_t setno,mddb_recid_t id,int incref,mddb_recid_t * hsp_id)15810Sstevel@tonic-gate modify_hsp_ref(set_t setno, mddb_recid_t id, int incref,  mddb_recid_t *hsp_id)
15820Sstevel@tonic-gate {
15830Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate 	*hsp_id = 0;
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 	if (id  < 0)
15880Sstevel@tonic-gate 		return (0);
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, id);
15910Sstevel@tonic-gate 	if (hsp == NULL)
15920Sstevel@tonic-gate 		return (-1);
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 	if (incref)
15950Sstevel@tonic-gate 		hsp->hsp_refcount++;
15960Sstevel@tonic-gate 	else
15970Sstevel@tonic-gate 		hsp->hsp_refcount--;
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 	*hsp_id = hsp->hsp_record_id;
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	/* NOTE: Stripe code commits the hsp record */
16020Sstevel@tonic-gate 	return (0);
16030Sstevel@tonic-gate }
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate static int
mkdev_for_a_hs(mddb_recid_t hs_id,md_dev64_t * dev)16070Sstevel@tonic-gate mkdev_for_a_hs(mddb_recid_t hs_id, md_dev64_t *dev)
16080Sstevel@tonic-gate {
16090Sstevel@tonic-gate 	hot_spare_t	*hs;
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	hs = lookup_hot_spare(mddb_getsetnum(hs_id), hs_id, 0);
16120Sstevel@tonic-gate 	if (hs == NULL)
16130Sstevel@tonic-gate 		return (0);
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	*dev = hs->hs_devnum;
16160Sstevel@tonic-gate 	return (0);
16170Sstevel@tonic-gate }
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate static intptr_t
hotspares_interface(hs_cmds_t cmd,mddb_recid_t id,uint64_t size,int bool,mddb_recid_t * hs_id,mdkey_t * key,md_dev64_t * dev,diskaddr_t * sblock)16200Sstevel@tonic-gate hotspares_interface(
16210Sstevel@tonic-gate 	hs_cmds_t	cmd,
16220Sstevel@tonic-gate 	mddb_recid_t	id,
16230Sstevel@tonic-gate 	uint64_t	size,
16240Sstevel@tonic-gate 	int		bool,
16250Sstevel@tonic-gate 	mddb_recid_t	*hs_id,
16260Sstevel@tonic-gate 	mdkey_t		*key,
16270Sstevel@tonic-gate 	md_dev64_t	*dev,
16280Sstevel@tonic-gate 	diskaddr_t	*sblock)
16290Sstevel@tonic-gate {
16300Sstevel@tonic-gate 	set_t	setno;
16310Sstevel@tonic-gate 	int	err = -1;
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	mutex_enter(&md_mx);
16340Sstevel@tonic-gate 	while (md_status & MD_GBL_HS_LOCK)
16350Sstevel@tonic-gate 		cv_wait(&md_cv, &md_mx);
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	/* If md_halt has been run do not continue */
16380Sstevel@tonic-gate 	if (md_status & (MD_GBL_HALTED | MD_GBL_DAEMONS_DIE)) {
16390Sstevel@tonic-gate 		mutex_exit(&md_mx);
16400Sstevel@tonic-gate 		return (ENXIO);
16410Sstevel@tonic-gate 	}
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 	md_status |= MD_GBL_HS_LOCK;
16440Sstevel@tonic-gate 	mutex_exit(&md_mx);
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 	setno = mddb_getsetnum(id);
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	switch (cmd) {
16490Sstevel@tonic-gate 	case HS_GET:
16500Sstevel@tonic-gate 		err = reserve_a_hs(setno, id, size, bool, hs_id,
16510Sstevel@tonic-gate 		    key, dev, sblock);
16520Sstevel@tonic-gate 		break;
16530Sstevel@tonic-gate 	case HS_FREE:
16540Sstevel@tonic-gate 		err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_AVAILABLE);
16550Sstevel@tonic-gate 		hotspares_poke_hotspares();
16560Sstevel@tonic-gate 		break;
16570Sstevel@tonic-gate 	case HS_BAD:
16580Sstevel@tonic-gate 		err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_BROKEN);
16590Sstevel@tonic-gate 		break;
16600Sstevel@tonic-gate 	case HSP_INCREF:
16610Sstevel@tonic-gate 		err = modify_hsp_ref(setno, id, 1, hs_id);
16620Sstevel@tonic-gate 		break;
16630Sstevel@tonic-gate 	case HSP_DECREF:
16640Sstevel@tonic-gate 		err = modify_hsp_ref(setno, id, 0, hs_id);
16650Sstevel@tonic-gate 		break;
16660Sstevel@tonic-gate 	case HS_MKDEV:
16670Sstevel@tonic-gate 		err = mkdev_for_a_hs(*hs_id, dev);
16680Sstevel@tonic-gate 		break;
16690Sstevel@tonic-gate 	}
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	mutex_enter(&md_mx);
16720Sstevel@tonic-gate 	md_status &= ~MD_GBL_HS_LOCK;
16730Sstevel@tonic-gate 	cv_broadcast(&md_cv);
16740Sstevel@tonic-gate 	mutex_exit(&md_mx);
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate 	return (err);
16770Sstevel@tonic-gate }
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate static void
imp_hotsparepool(set_t setno,mddb_recid_t recid)16800Sstevel@tonic-gate imp_hotsparepool(
16810Sstevel@tonic-gate 	set_t	setno,
16820Sstevel@tonic-gate 	mddb_recid_t	recid
16830Sstevel@tonic-gate )
16840Sstevel@tonic-gate {
16850Sstevel@tonic-gate 	hot_spare_pool_ond_t	*hsp_ond;
16860Sstevel@tonic-gate 	mddb_recid_t		*hsp_recid, *hs_recid;
16870Sstevel@tonic-gate 	int			i;
16880Sstevel@tonic-gate 	uint_t			*hsp_selfid;
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	mddb_setrecprivate(recid, MD_PRV_GOTIT);
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid);
16930Sstevel@tonic-gate 	hsp_recid = &(hsp_ond->hsp_record_id);
16940Sstevel@tonic-gate 	hsp_selfid = &(hsp_ond->hsp_self_id);
16950Sstevel@tonic-gate 	/*
16960Sstevel@tonic-gate 	 * Fixup the pool and hotspares
16970Sstevel@tonic-gate 	 */
16980Sstevel@tonic-gate 	*hsp_recid = MAKERECID(setno, DBID(*hsp_recid));
16990Sstevel@tonic-gate 	*hsp_selfid = MAKERECID(setno, DBID(*hsp_selfid));
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 	for (i = 0; i < hsp_ond->hsp_nhotspares; i++) {
17020Sstevel@tonic-gate 		hs_recid = &(hsp_ond->hsp_hotspares[i]);
17030Sstevel@tonic-gate 		*hs_recid = MAKERECID(setno, DBID(*hs_recid));
17040Sstevel@tonic-gate 	}
17050Sstevel@tonic-gate }
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate static void
imp_hotspare(set_t setno,mddb_recid_t recid)17080Sstevel@tonic-gate imp_hotspare(
17090Sstevel@tonic-gate 	set_t	setno,
17100Sstevel@tonic-gate 	mddb_recid_t	recid
17110Sstevel@tonic-gate )
17120Sstevel@tonic-gate {
17130Sstevel@tonic-gate 	mddb_de_ic_t	*dep;
17140Sstevel@tonic-gate 	mddb_rb32_t	*rbp;
17150Sstevel@tonic-gate 	hot_spare_t	*hs64;
17160Sstevel@tonic-gate 	hot_spare32_od_t	*hs32;
17170Sstevel@tonic-gate 	mddb_recid_t	*hs_recid;
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	mddb_setrecprivate(recid, MD_PRV_GOTIT);
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	dep = mddb_getrecdep(recid);
17220Sstevel@tonic-gate 	rbp = dep->de_rb;
17231623Stw21770 	switch (rbp->rb_revision) {
17241623Stw21770 	case MDDB_REV_RB:
17251623Stw21770 	case MDDB_REV_RBFN:
17260Sstevel@tonic-gate 		/*
17270Sstevel@tonic-gate 		 * 32 bit hotspare
17280Sstevel@tonic-gate 		 */
17290Sstevel@tonic-gate 		hs32 = (hot_spare32_od_t *)mddb_getrecaddr(recid);
17300Sstevel@tonic-gate 		hs_recid = &(hs32->hs_record_id);
17311623Stw21770 		break;
17321623Stw21770 	case MDDB_REV_RB64:
17331623Stw21770 	case MDDB_REV_RB64FN:
17340Sstevel@tonic-gate 		hs64 = (hot_spare_t *)mddb_getrecaddr(recid);
17350Sstevel@tonic-gate 		hs_recid = &(hs64->hs_record_id);
17361623Stw21770 		break;
17370Sstevel@tonic-gate 	}
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate 	/*
17400Sstevel@tonic-gate 	 * Fixup the setno
17410Sstevel@tonic-gate 	 */
17420Sstevel@tonic-gate 	*hs_recid = MAKERECID(setno, DBID(*hs_recid));
17430Sstevel@tonic-gate }
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate static int
hotspares_imp_set(set_t setno)17460Sstevel@tonic-gate hotspares_imp_set(
17470Sstevel@tonic-gate 	set_t	setno
17480Sstevel@tonic-gate )
17490Sstevel@tonic-gate {
17500Sstevel@tonic-gate 	mddb_recid_t	recid;
17510Sstevel@tonic-gate 	int		gotsomething;
17520Sstevel@tonic-gate 	mddb_type_t	typ1;
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	gotsomething = 0;
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
17580Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
17590Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
17600Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) {
17610Sstevel@tonic-gate 		if (mddb_getrecprivate(recid) & MD_PRV_GOTIT)
17620Sstevel@tonic-gate 			continue;
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 		switch (mddb_getrectype2(recid)) {
17650Sstevel@tonic-gate 		case HSP_REC:
17660Sstevel@tonic-gate 			imp_hotsparepool(setno, recid);
17670Sstevel@tonic-gate 			gotsomething = 1;
17680Sstevel@tonic-gate 			break;
17690Sstevel@tonic-gate 		case HS_REC:
17700Sstevel@tonic-gate 			imp_hotspare(setno, recid);
17710Sstevel@tonic-gate 			gotsomething = 1;
17720Sstevel@tonic-gate 			break;
17730Sstevel@tonic-gate 		default:
17740Sstevel@tonic-gate 			ASSERT(0);
17750Sstevel@tonic-gate 		}
17760Sstevel@tonic-gate 	}
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	return (gotsomething);
17790Sstevel@tonic-gate }
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate static md_named_services_t hotspares_named_services[] = {
17820Sstevel@tonic-gate 	{hotspares_interface,	"hot spare interface"},
17830Sstevel@tonic-gate 	{NULL,			0}
17840Sstevel@tonic-gate };
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate md_ops_t hotspares_md_ops = {
17870Sstevel@tonic-gate 	NULL,			/* open */
17880Sstevel@tonic-gate 	NULL,			/* close */
17890Sstevel@tonic-gate 	NULL,			/* strategy */
17900Sstevel@tonic-gate 	NULL,			/* print */
17910Sstevel@tonic-gate 	NULL,			/* dump */
17920Sstevel@tonic-gate 	NULL,			/* read */
17930Sstevel@tonic-gate 	NULL,			/* write */
17940Sstevel@tonic-gate 	hotspares_ioctl,	/* hotspares_ioctl, */
17950Sstevel@tonic-gate 	hotspares_snarf,	/* hotspares_snarf */
17960Sstevel@tonic-gate 	hotspares_halt,		/* halt */
17970Sstevel@tonic-gate 	NULL,			/* aread */
17980Sstevel@tonic-gate 	NULL,			/* awrite */
17990Sstevel@tonic-gate 	hotspares_imp_set,	/* import set */
18000Sstevel@tonic-gate 	hotspares_named_services /* named_services */
18010Sstevel@tonic-gate };
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate static void
fini_uninit()18040Sstevel@tonic-gate fini_uninit()
18050Sstevel@tonic-gate {
18060Sstevel@tonic-gate 	/* prevent access to services that may have been imported */
18070Sstevel@tonic-gate 	md_clear_hot_spare_interface();
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate /* define the module linkage */
1811*4932Spetede MD_PLUGIN_MISC_MODULE("hot spares module", md_noop, fini_uninit())
1812