xref: /onnv-gate/usr/src/uts/common/io/lvm/hotspares/hotspares.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/param.h>
30*0Sstevel@tonic-gate #include <sys/systm.h>
31*0Sstevel@tonic-gate #include <sys/conf.h>
32*0Sstevel@tonic-gate #include <sys/file.h>
33*0Sstevel@tonic-gate #include <sys/user.h>
34*0Sstevel@tonic-gate #include <sys/uio.h>
35*0Sstevel@tonic-gate #include <sys/t_lock.h>
36*0Sstevel@tonic-gate #include <sys/kmem.h>
37*0Sstevel@tonic-gate #include <vm/page.h>
38*0Sstevel@tonic-gate #include <sys/sysmacros.h>
39*0Sstevel@tonic-gate #include <sys/types.h>
40*0Sstevel@tonic-gate #include <sys/mkdev.h>
41*0Sstevel@tonic-gate #include <sys/stat.h>
42*0Sstevel@tonic-gate #include <sys/open.h>
43*0Sstevel@tonic-gate #include <sys/modctl.h>
44*0Sstevel@tonic-gate #include <sys/ddi.h>
45*0Sstevel@tonic-gate #include <sys/sunddi.h>
46*0Sstevel@tonic-gate #include <sys/debug.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include <sys/lvm/md_hotspares.h>
49*0Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
52*0Sstevel@tonic-gate #include <sys/sysevent/svm.h>
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate md_ops_t		hotspares_md_ops;
55*0Sstevel@tonic-gate #ifndef	lint
56*0Sstevel@tonic-gate static char		_depends_on[] = "drv/md";
57*0Sstevel@tonic-gate md_ops_t		*md_interface_ops = &hotspares_md_ops;
58*0Sstevel@tonic-gate #endif
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate extern md_ops_t		**md_ops;
61*0Sstevel@tonic-gate extern md_ops_t		*md_opslist;
62*0Sstevel@tonic-gate extern md_set_t		md_set[];
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate extern kmutex_t		md_mx;		/* used to md global stuff */
65*0Sstevel@tonic-gate extern kcondvar_t	md_cv;		/* md_status events */
66*0Sstevel@tonic-gate extern int		md_status;
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate extern void		md_clear_hot_spare_interface();
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate static void
71*0Sstevel@tonic-gate set_hot_spare_state(hot_spare_t *hs, hotspare_states_t newstate)
72*0Sstevel@tonic-gate {
73*0Sstevel@tonic-gate 	hs->hs_state = newstate;
74*0Sstevel@tonic-gate 	uniqtime32(&hs->hs_timestamp);
75*0Sstevel@tonic-gate }
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate static hot_spare_t *
78*0Sstevel@tonic-gate lookup_hot_spare(set_t setno, mddb_recid_t hs_id, int must_exist)
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	hot_spare_t *hs;
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	for (hs = (hot_spare_t *)md_set[setno].s_hs; hs; hs = hs->hs_next) {
83*0Sstevel@tonic-gate 		if (hs->hs_record_id == hs_id)
84*0Sstevel@tonic-gate 			return (hs);
85*0Sstevel@tonic-gate 	}
86*0Sstevel@tonic-gate 	if (must_exist)
87*0Sstevel@tonic-gate 		ASSERT(0);
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	return ((hot_spare_t *)NULL);
90*0Sstevel@tonic-gate }
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate static hot_spare_pool_t *
93*0Sstevel@tonic-gate find_hot_spare_pool(set_t setno, int hsp_id)
94*0Sstevel@tonic-gate {
95*0Sstevel@tonic-gate 	hot_spare_pool_t *hsp;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
98*0Sstevel@tonic-gate 	while (hsp != NULL) {
99*0Sstevel@tonic-gate 		if (hsp->hsp_self_id == hsp_id)
100*0Sstevel@tonic-gate 			return (hsp);
101*0Sstevel@tonic-gate 		hsp = hsp->hsp_next;
102*0Sstevel@tonic-gate 	}
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	return ((hot_spare_pool_t *)0);
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate static int
109*0Sstevel@tonic-gate seths_create_hsp(set_hs_params_t *shs)
110*0Sstevel@tonic-gate {
111*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
112*0Sstevel@tonic-gate 	mddb_recid_t		recid;
113*0Sstevel@tonic-gate 	set_t			setno;
114*0Sstevel@tonic-gate 	mddb_type_t		typ1;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	/* Scan the hot spare pool list */
119*0Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
120*0Sstevel@tonic-gate 	if (hsp != (hot_spare_pool_t *)0)
121*0Sstevel@tonic-gate 		return (0);
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
124*0Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	/* create a hot spare pool record */
127*0Sstevel@tonic-gate 	if (shs->shs_options & MD_CRO_64BIT) {
128*0Sstevel@tonic-gate #if defined(_ILP32)
129*0Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_HSP_UNIT_TOO_LARGE,
130*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
131*0Sstevel@tonic-gate #else
132*0Sstevel@tonic-gate 		recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1,
133*0Sstevel@tonic-gate 			HSP_REC, MD_CRO_64BIT | MD_CRO_HOTSPARE_POOL, setno);
134*0Sstevel@tonic-gate #endif
135*0Sstevel@tonic-gate 	} else {
136*0Sstevel@tonic-gate 		recid = mddb_createrec(sizeof (hot_spare_pool_ond_t), typ1,
137*0Sstevel@tonic-gate 			HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL, setno);
138*0Sstevel@tonic-gate 	}
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	if (recid < 0) {
141*0Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
142*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
143*0Sstevel@tonic-gate 	}
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	/* get the record addr */
146*0Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, sizeof (*hsp),
147*0Sstevel@tonic-gate 		HSP_ONDSK_STR_OFF);
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	hsp->hsp_self_id = shs->shs_hot_spare_pool;
150*0Sstevel@tonic-gate 	hsp->hsp_record_id = recid;
151*0Sstevel@tonic-gate 	hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
152*0Sstevel@tonic-gate 	hsp->hsp_refcount = 0;
153*0Sstevel@tonic-gate 	hsp->hsp_nhotspares = 0;
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	md_set[setno].s_hsp = (void *) hsp;
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	mddb_commitrec_wrapper(recid);
158*0Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno,
159*0Sstevel@tonic-gate 	    md_expldev(hsp->hsp_self_id));
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
162*0Sstevel@tonic-gate 	hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
163*0Sstevel@tonic-gate 	hsp->hsp_link.ln_setno = setno;
164*0Sstevel@tonic-gate 	hsp->hsp_link.ln_id = hsp->hsp_self_id;
165*0Sstevel@tonic-gate 	hotspares_md_ops.md_head = &hsp->hsp_link;
166*0Sstevel@tonic-gate 	rw_exit(&hotspares_md_ops.md_link_rw.lock);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	return (0);
169*0Sstevel@tonic-gate }
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate static int
173*0Sstevel@tonic-gate seths_add(set_hs_params_t *shs)
174*0Sstevel@tonic-gate {
175*0Sstevel@tonic-gate 	hot_spare_t		*hs;
176*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
177*0Sstevel@tonic-gate 	hot_spare_pool_t	*prev_hsp;
178*0Sstevel@tonic-gate 	hot_spare_pool_t	*new_hsp;
179*0Sstevel@tonic-gate 	hot_spare_pool_t	*old_hsp;
180*0Sstevel@tonic-gate 	mddb_recid_t		recid;
181*0Sstevel@tonic-gate 	mddb_recid_t		recids[5];
182*0Sstevel@tonic-gate 	size_t			new_size;
183*0Sstevel@tonic-gate 	int			i;
184*0Sstevel@tonic-gate 	int			delete_hsp = 0;
185*0Sstevel@tonic-gate 	int			irecid;
186*0Sstevel@tonic-gate 	set_t			setno;
187*0Sstevel@tonic-gate 	mddb_type_t		typ1;
188*0Sstevel@tonic-gate 	int			hsp_created = 0;
189*0Sstevel@tonic-gate 	mdkey_t			key_old;
190*0Sstevel@tonic-gate 	int			num_keys_old = 0;
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	/* Not much to do here in case of a dryrun */
193*0Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
194*0Sstevel@tonic-gate 		return (0);
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	/* create an empty hot spare pool */
198*0Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_POOL) {
199*0Sstevel@tonic-gate 		return (seths_create_hsp(shs));
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
203*0Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
204*0Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	/* Scan the hot spare list */
207*0Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
208*0Sstevel@tonic-gate 	while (hs) {
209*0Sstevel@tonic-gate 		if (hs->hs_devnum == shs->shs_component_old) {
210*0Sstevel@tonic-gate 			break;
211*0Sstevel@tonic-gate 		}
212*0Sstevel@tonic-gate 		hs = hs->hs_next;
213*0Sstevel@tonic-gate 	}
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	if (hs == NULL) {
216*0Sstevel@tonic-gate 		/*
217*0Sstevel@tonic-gate 		 * Did not find match for device using devnum so use
218*0Sstevel@tonic-gate 		 * key associated with shs_component_old just
219*0Sstevel@tonic-gate 		 * in case there is a match but the match's dev is NODEV.
220*0Sstevel@tonic-gate 		 * If unable to find a unique key for shs_component_old
221*0Sstevel@tonic-gate 		 * then fail since namespace has multiple entries
222*0Sstevel@tonic-gate 		 * for this old component and we shouldn't allow
223*0Sstevel@tonic-gate 		 * an addition of a hotspare in this case.
224*0Sstevel@tonic-gate 		 */
225*0Sstevel@tonic-gate 		if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
226*0Sstevel@tonic-gate 		    shs->shs_component_old, &key_old, &num_keys_old) != 0) {
227*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_NAME_SPACE,
228*0Sstevel@tonic-gate 			    shs->shs_component_old));
229*0Sstevel@tonic-gate 		}
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 		/*
232*0Sstevel@tonic-gate 		 * If more than one key matches given old_dev - fail command
233*0Sstevel@tonic-gate 		 * since shouldn't add new hotspare if namespace has
234*0Sstevel@tonic-gate 		 * multiple entries.
235*0Sstevel@tonic-gate 		 */
236*0Sstevel@tonic-gate 		if (num_keys_old > 1) {
237*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_MULTNM,
238*0Sstevel@tonic-gate 			    shs->shs_component_old));
239*0Sstevel@tonic-gate 		}
240*0Sstevel@tonic-gate 		/*
241*0Sstevel@tonic-gate 		 * If there is no key for this entry then fail since
242*0Sstevel@tonic-gate 		 * a key for this entry should exist.
243*0Sstevel@tonic-gate 		 */
244*0Sstevel@tonic-gate 		if (num_keys_old == 0) {
245*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_INVAL_HS,
246*0Sstevel@tonic-gate 			    shs->shs_component_old));
247*0Sstevel@tonic-gate 		}
248*0Sstevel@tonic-gate 		/* Scan the hot spare list again */
249*0Sstevel@tonic-gate 		hs = (hot_spare_t *)md_set[setno].s_hs;
250*0Sstevel@tonic-gate 		while (hs) {
251*0Sstevel@tonic-gate 			/*
252*0Sstevel@tonic-gate 			 * Only need to compare keys when hs_devnum is NODEV.
253*0Sstevel@tonic-gate 			 */
254*0Sstevel@tonic-gate 			if ((hs->hs_devnum == NODEV64) &&
255*0Sstevel@tonic-gate 			    (hs->hs_key == key_old)) {
256*0Sstevel@tonic-gate 				break;
257*0Sstevel@tonic-gate 			}
258*0Sstevel@tonic-gate 			hs = hs->hs_next;
259*0Sstevel@tonic-gate 		}
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	if (hs == NULL) {
263*0Sstevel@tonic-gate 		/* create a hot spare record */
264*0Sstevel@tonic-gate 		if (shs->shs_size_option & MD_CRO_64BIT) {
265*0Sstevel@tonic-gate #if defined(_ILP32)
266*0Sstevel@tonic-gate 			return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE,
267*0Sstevel@tonic-gate 			    shs->shs_hot_spare_pool, shs->shs_component_old));
268*0Sstevel@tonic-gate #else
269*0Sstevel@tonic-gate 			recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
270*0Sstevel@tonic-gate 				MD_CRO_64BIT | MD_CRO_HOTSPARE, setno);
271*0Sstevel@tonic-gate #endif
272*0Sstevel@tonic-gate 		} else {
273*0Sstevel@tonic-gate 			recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
274*0Sstevel@tonic-gate 				MD_CRO_32BIT | MD_CRO_HOTSPARE, setno);
275*0Sstevel@tonic-gate 		}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 		if (recid < 0) {
278*0Sstevel@tonic-gate 			return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE,
279*0Sstevel@tonic-gate 			    shs->shs_hot_spare_pool,
280*0Sstevel@tonic-gate 			    shs->shs_component_old));
281*0Sstevel@tonic-gate 		}
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 		/* get the addr */
284*0Sstevel@tonic-gate 		hs = (hot_spare_t *)mddb_getrecaddr_resize(recid, sizeof (*hs),
285*0Sstevel@tonic-gate 			0);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 		hs->hs_record_id = recid;
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 		hs->hs_devnum = shs->shs_component_old;
290*0Sstevel@tonic-gate 		hs->hs_key = shs->shs_key_old;
291*0Sstevel@tonic-gate 		hs->hs_start_blk = shs->shs_start_blk;
292*0Sstevel@tonic-gate 		hs->hs_has_label = shs->shs_has_label;
293*0Sstevel@tonic-gate 		hs->hs_number_blks = shs->shs_number_blks;
294*0Sstevel@tonic-gate 		set_hot_spare_state(hs, HSS_AVAILABLE);
295*0Sstevel@tonic-gate 		hs->hs_refcount = 0;
296*0Sstevel@tonic-gate 		hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
297*0Sstevel@tonic-gate 		md_set[setno].s_hs = (void *) hs;
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	/* Scan the hot spare pool list */
301*0Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
302*0Sstevel@tonic-gate 	prev_hsp = (hot_spare_pool_t *)0;
303*0Sstevel@tonic-gate 	while (hsp) {
304*0Sstevel@tonic-gate 		if (hsp->hsp_self_id == shs->shs_hot_spare_pool) {
305*0Sstevel@tonic-gate 			break;
306*0Sstevel@tonic-gate 		}
307*0Sstevel@tonic-gate 		prev_hsp = hsp;
308*0Sstevel@tonic-gate 		hsp = hsp->hsp_next;
309*0Sstevel@tonic-gate 	}
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	if (hsp == NULL) {
312*0Sstevel@tonic-gate 		/* create a hot spare pool record */
313*0Sstevel@tonic-gate 		recid = mddb_createrec(sizeof (hot_spare_pool_ond_t),
314*0Sstevel@tonic-gate 		    typ1, HSP_REC, MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL, setno);
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 		if (recid < 0) {
317*0Sstevel@tonic-gate 			return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
318*0Sstevel@tonic-gate 			    shs->shs_hot_spare_pool));
319*0Sstevel@tonic-gate 		}
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 		/* get the record addr */
322*0Sstevel@tonic-gate 		hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid,
323*0Sstevel@tonic-gate 			sizeof (*hsp), HSP_ONDSK_STR_OFF);
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 		hsp->hsp_self_id = shs->shs_hot_spare_pool;
326*0Sstevel@tonic-gate 		hsp->hsp_record_id = recid;
327*0Sstevel@tonic-gate 		hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
328*0Sstevel@tonic-gate 		hsp->hsp_refcount = 0;
329*0Sstevel@tonic-gate 		hsp->hsp_nhotspares = 0;
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 		/* force prev_hsp to NULL, this will cause hsp to be linked */
332*0Sstevel@tonic-gate 		prev_hsp = (hot_spare_pool_t *)0;
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 		rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
335*0Sstevel@tonic-gate 		hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
336*0Sstevel@tonic-gate 		hsp->hsp_link.ln_setno = setno;
337*0Sstevel@tonic-gate 		hsp->hsp_link.ln_id = hsp->hsp_self_id;
338*0Sstevel@tonic-gate 		hotspares_md_ops.md_head = &hsp->hsp_link;
339*0Sstevel@tonic-gate 		rw_exit(&hotspares_md_ops.md_link_rw.lock);
340*0Sstevel@tonic-gate 		hsp_created = 1;
341*0Sstevel@tonic-gate 	} else {
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 		/*
344*0Sstevel@tonic-gate 		 * Make sure the hot spare is not already in the pool.
345*0Sstevel@tonic-gate 		 */
346*0Sstevel@tonic-gate 		for (i = 0; i < hsp->hsp_nhotspares; i++)
347*0Sstevel@tonic-gate 			if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
348*0Sstevel@tonic-gate 				return (mdhserror(&shs->mde, MDE_HS_INUSE,
349*0Sstevel@tonic-gate 					shs->shs_hot_spare_pool,
350*0Sstevel@tonic-gate 					hs->hs_devnum));
351*0Sstevel@tonic-gate 			}
352*0Sstevel@tonic-gate 		/*
353*0Sstevel@tonic-gate 		 * Create a new hot spare pool record
354*0Sstevel@tonic-gate 		 * This gives us the one extra hs slot,
355*0Sstevel@tonic-gate 		 * because there is one slot in the
356*0Sstevel@tonic-gate 		 * hot_spare_pool struct
357*0Sstevel@tonic-gate 		 */
358*0Sstevel@tonic-gate 		new_size = sizeof (hot_spare_pool_ond_t) +
359*0Sstevel@tonic-gate 			(sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
360*0Sstevel@tonic-gate 		recid = mddb_createrec(new_size, typ1, HSP_REC,
361*0Sstevel@tonic-gate 		    MD_CRO_32BIT | MD_CRO_HOTSPARE_POOL, setno);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 		if (recid < 0) {
364*0Sstevel@tonic-gate 			return (mdhsperror(&shs->mde, MDE_HSP_CREATE_FAILURE,
365*0Sstevel@tonic-gate 			    hsp->hsp_self_id));
366*0Sstevel@tonic-gate 		}
367*0Sstevel@tonic-gate 		new_size = sizeof (hot_spare_pool_t) +
368*0Sstevel@tonic-gate 			(sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 		/* get the record addr */
371*0Sstevel@tonic-gate 		new_hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid,
372*0Sstevel@tonic-gate 			new_size, HSP_ONDSK_STR_OFF);
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 		/* copy the old record into the new one */
375*0Sstevel@tonic-gate 		bcopy((caddr_t)hsp, (caddr_t)new_hsp,
376*0Sstevel@tonic-gate 		    (size_t)((sizeof (hot_spare_pool_t) +
377*0Sstevel@tonic-gate 		    (sizeof (mddb_recid_t) * hsp->hsp_nhotspares)
378*0Sstevel@tonic-gate 		    - sizeof (mddb_recid_t))));
379*0Sstevel@tonic-gate 		new_hsp->hsp_record_id = recid;
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 		md_rem_link(setno, hsp->hsp_self_id,
382*0Sstevel@tonic-gate 		    &hotspares_md_ops.md_link_rw.lock,
383*0Sstevel@tonic-gate 		    &hotspares_md_ops.md_head);
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 		rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
386*0Sstevel@tonic-gate 		new_hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
387*0Sstevel@tonic-gate 		new_hsp->hsp_link.ln_setno = setno;
388*0Sstevel@tonic-gate 		new_hsp->hsp_link.ln_id = new_hsp->hsp_self_id;
389*0Sstevel@tonic-gate 		hotspares_md_ops.md_head = &new_hsp->hsp_link;
390*0Sstevel@tonic-gate 		rw_exit(&hotspares_md_ops.md_link_rw.lock);
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 		/* mark the old hsp to be deleted */
393*0Sstevel@tonic-gate 		delete_hsp = 1;
394*0Sstevel@tonic-gate 		old_hsp = hsp;
395*0Sstevel@tonic-gate 		hsp = new_hsp;
396*0Sstevel@tonic-gate 	}
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	if (shs->shs_size_option & MD_CRO_64BIT) {
399*0Sstevel@tonic-gate 		hs->hs_revision = MD_64BIT_META_DEV;
400*0Sstevel@tonic-gate 	} else {
401*0Sstevel@tonic-gate 		hs->hs_revision = MD_32BIT_META_DEV;
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	/* lock the db records */
405*0Sstevel@tonic-gate 	recids[0] = hs->hs_record_id;
406*0Sstevel@tonic-gate 	recids[1] = hsp->hsp_record_id;
407*0Sstevel@tonic-gate 	irecid = 2;
408*0Sstevel@tonic-gate 	if (delete_hsp)
409*0Sstevel@tonic-gate 		recids[irecid++] = old_hsp->hsp_record_id;
410*0Sstevel@tonic-gate 	recids[irecid] = 0;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	/* increment the reference count */
413*0Sstevel@tonic-gate 	hs->hs_refcount++;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	/* add the hs at the end of the hot spare pool */
416*0Sstevel@tonic-gate 	hsp->hsp_hotspares[hsp->hsp_nhotspares] = hs->hs_record_id;
417*0Sstevel@tonic-gate 	hsp->hsp_nhotspares++;
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	/*
420*0Sstevel@tonic-gate 	 * NOTE: We do not commit the previous hot spare pool record.
421*0Sstevel@tonic-gate 	 *	 There is no need, the link gets rebuilt at boot time.
422*0Sstevel@tonic-gate 	 */
423*0Sstevel@tonic-gate 	if (prev_hsp)
424*0Sstevel@tonic-gate 		prev_hsp->hsp_next = hsp;
425*0Sstevel@tonic-gate 	else
426*0Sstevel@tonic-gate 		md_set[setno].s_hsp = (void *) hsp;
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	if (delete_hsp)
429*0Sstevel@tonic-gate 		old_hsp->hsp_self_id = MD_HSP_NONE;
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	/* commit the db records */
432*0Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	if (delete_hsp) {
435*0Sstevel@tonic-gate 		/* delete the old hot spare pool record */
436*0Sstevel@tonic-gate 		mddb_deleterec_wrapper(old_hsp->hsp_record_id);
437*0Sstevel@tonic-gate 	}
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	if (hsp_created) {
440*0Sstevel@tonic-gate 		SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, SVM_TAG_HSP, setno,
441*0Sstevel@tonic-gate 		    md_expldev(hsp->hsp_self_id));
442*0Sstevel@tonic-gate 	}
443*0Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_ADD, SVM_TAG_HSP, setno,
444*0Sstevel@tonic-gate 	    md_expldev(hsp->hsp_self_id));
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	return (0);
447*0Sstevel@tonic-gate }
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate static int
451*0Sstevel@tonic-gate seths_delete_hsp(set_hs_params_t *shs)
452*0Sstevel@tonic-gate {
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	hot_spare_pool_t	*prev_hsp;
455*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
456*0Sstevel@tonic-gate 	set_t			setno;
457*0Sstevel@tonic-gate 	hsp_t			hspid;
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	/* Scan the hot spare pool list */
462*0Sstevel@tonic-gate 	prev_hsp = (hot_spare_pool_t *)0;
463*0Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
464*0Sstevel@tonic-gate 	while (hsp) {
465*0Sstevel@tonic-gate 		if (hsp->hsp_self_id == shs->shs_hot_spare_pool) {
466*0Sstevel@tonic-gate 			break;
467*0Sstevel@tonic-gate 		}
468*0Sstevel@tonic-gate 		prev_hsp = hsp;
469*0Sstevel@tonic-gate 		hsp = hsp->hsp_next;
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	if (hsp == NULL) {
473*0Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
474*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
475*0Sstevel@tonic-gate 	}
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	if (hsp->hsp_nhotspares != 0) {
478*0Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_HSP_BUSY,
479*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
480*0Sstevel@tonic-gate 	}
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	if (hsp->hsp_refcount != 0) {
483*0Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_HSP_REF,
484*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	/* In case of a dryrun, we're done here */
488*0Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
489*0Sstevel@tonic-gate 		return (0);
490*0Sstevel@tonic-gate 	}
491*0Sstevel@tonic-gate 	/*
492*0Sstevel@tonic-gate 	 * NOTE: We do not commit the previous hot spare pool record.
493*0Sstevel@tonic-gate 	 *	 There is no need, the link gets rebuilt at boot time.
494*0Sstevel@tonic-gate 	 */
495*0Sstevel@tonic-gate 	if (prev_hsp)
496*0Sstevel@tonic-gate 		prev_hsp->hsp_next = hsp->hsp_next;
497*0Sstevel@tonic-gate 	else
498*0Sstevel@tonic-gate 		md_set[setno].s_hsp = (void *) hsp->hsp_next;
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	hspid = hsp->hsp_self_id;
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	md_rem_link(setno, hsp->hsp_self_id,
503*0Sstevel@tonic-gate 	    &hotspares_md_ops.md_link_rw.lock,
504*0Sstevel@tonic-gate 	    &hotspares_md_ops.md_head);
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	mddb_deleterec_wrapper(hsp->hsp_record_id);
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_DELETE, SVM_TAG_HSP, setno,
509*0Sstevel@tonic-gate 	    md_expldev(hspid));
510*0Sstevel@tonic-gate 	return (0);
511*0Sstevel@tonic-gate }
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate static int
515*0Sstevel@tonic-gate seths_delete(set_hs_params_t *shs)
516*0Sstevel@tonic-gate {
517*0Sstevel@tonic-gate 	hot_spare_t		*hs;
518*0Sstevel@tonic-gate 	hot_spare_t		*prev_hs;
519*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
520*0Sstevel@tonic-gate 	mddb_recid_t		recids[4];
521*0Sstevel@tonic-gate 	int			i;
522*0Sstevel@tonic-gate 	set_t			setno;
523*0Sstevel@tonic-gate 	sv_dev_t		sv;
524*0Sstevel@tonic-gate 	int			delete_hs = 0;
525*0Sstevel@tonic-gate 	mdkey_t			key_old;
526*0Sstevel@tonic-gate 	int			num_keys_old = 0;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	/* delete the hot spare pool */
529*0Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_POOL) {
530*0Sstevel@tonic-gate 		return (seths_delete_hsp(shs));
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	/* Scan the hot spare list */
536*0Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
537*0Sstevel@tonic-gate 	prev_hs = (hot_spare_t *)0;
538*0Sstevel@tonic-gate 	while (hs) {
539*0Sstevel@tonic-gate 		if (hs->hs_devnum == shs->shs_component_old) {
540*0Sstevel@tonic-gate 			break;
541*0Sstevel@tonic-gate 		}
542*0Sstevel@tonic-gate 		prev_hs = hs;
543*0Sstevel@tonic-gate 		hs = hs->hs_next;
544*0Sstevel@tonic-gate 	}
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	if (hs == NULL) {
547*0Sstevel@tonic-gate 		/*
548*0Sstevel@tonic-gate 		 * Unable to find device using devnum so use
549*0Sstevel@tonic-gate 		 * key associated with shs_component_old instead.
550*0Sstevel@tonic-gate 		 * If unable to find a unique key for shs_component_old
551*0Sstevel@tonic-gate 		 * then fail since namespace has multiple entries
552*0Sstevel@tonic-gate 		 * for this old component and we're unable to determine
553*0Sstevel@tonic-gate 		 * which key is the valid match for shs_component_old.
554*0Sstevel@tonic-gate 		 *
555*0Sstevel@tonic-gate 		 * Only need to compare keys when hs_devnum is NODEV.
556*0Sstevel@tonic-gate 		 */
557*0Sstevel@tonic-gate 		if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
558*0Sstevel@tonic-gate 		    shs->shs_component_old, &key_old, &num_keys_old) != 0) {
559*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_NAME_SPACE,
560*0Sstevel@tonic-gate 			    shs->shs_component_old));
561*0Sstevel@tonic-gate 		}
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 		/*
564*0Sstevel@tonic-gate 		 * If more than one key matches given old_dev - fail command
565*0Sstevel@tonic-gate 		 * since shouldn't add new hotspare if namespace has
566*0Sstevel@tonic-gate 		 * multiple entries.
567*0Sstevel@tonic-gate 		 */
568*0Sstevel@tonic-gate 		if (num_keys_old > 1) {
569*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_MULTNM,
570*0Sstevel@tonic-gate 			    shs->shs_component_old));
571*0Sstevel@tonic-gate 		}
572*0Sstevel@tonic-gate 		/*
573*0Sstevel@tonic-gate 		 * If there is no key for this entry then fail since
574*0Sstevel@tonic-gate 		 * a key for this entry should exist.
575*0Sstevel@tonic-gate 		 */
576*0Sstevel@tonic-gate 		if (num_keys_old == 0) {
577*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_INVAL_HS,
578*0Sstevel@tonic-gate 			    shs->shs_component_old));
579*0Sstevel@tonic-gate 		}
580*0Sstevel@tonic-gate 		/* Scan the hot spare list again */
581*0Sstevel@tonic-gate 		hs = (hot_spare_t *)md_set[setno].s_hs;
582*0Sstevel@tonic-gate 		prev_hs = (hot_spare_t *)0;
583*0Sstevel@tonic-gate 		while (hs) {
584*0Sstevel@tonic-gate 			/*
585*0Sstevel@tonic-gate 			 * Only need to compare keys when hs_devnum is NODEV.
586*0Sstevel@tonic-gate 			 */
587*0Sstevel@tonic-gate 			if ((hs->hs_devnum == NODEV64) &&
588*0Sstevel@tonic-gate 			    (hs->hs_key == key_old)) {
589*0Sstevel@tonic-gate 				break;
590*0Sstevel@tonic-gate 			}
591*0Sstevel@tonic-gate 			prev_hs = hs;
592*0Sstevel@tonic-gate 			hs = hs->hs_next;
593*0Sstevel@tonic-gate 		}
594*0Sstevel@tonic-gate 	}
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	if (hs == NULL) {
597*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
598*0Sstevel@tonic-gate 		    shs->shs_component_old));
599*0Sstevel@tonic-gate 	}
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	/* Scan the hot spare pool list */
602*0Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
603*0Sstevel@tonic-gate 	if (hsp == (hot_spare_pool_t *)0) {
604*0Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
605*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
606*0Sstevel@tonic-gate 	}
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	/* check for force flag and state of hot spare */
609*0Sstevel@tonic-gate 	if (((shs->shs_options & HS_OPT_FORCE) == 0) &&
610*0Sstevel@tonic-gate 	    (hs->hs_state == HSS_RESERVED)) {
611*0Sstevel@tonic-gate 		return (mdhserror(&shs->mde, MDE_HS_RESVD,
612*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool, shs->shs_component_old));
613*0Sstevel@tonic-gate 	}
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	if (hsp->hsp_refcount && (hs->hs_state == HSS_RESERVED)) {
616*0Sstevel@tonic-gate 		return (mdhserror(&shs->mde, MDE_HS_RESVD,
617*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool, shs->shs_component_old));
618*0Sstevel@tonic-gate 	}
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	/*
621*0Sstevel@tonic-gate 	 * Make sure the device is in the pool.
622*0Sstevel@tonic-gate 	 */
623*0Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
624*0Sstevel@tonic-gate 		if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
625*0Sstevel@tonic-gate 			break;
626*0Sstevel@tonic-gate 		}
627*0Sstevel@tonic-gate 	}
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	if (i >= hsp->hsp_nhotspares) {
630*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
631*0Sstevel@tonic-gate 		    hs->hs_devnum));
632*0Sstevel@tonic-gate 	}
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	/* In case of a dryrun, we're done here */
635*0Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
636*0Sstevel@tonic-gate 		return (0);
637*0Sstevel@tonic-gate 	}
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	/* lock the db records */
640*0Sstevel@tonic-gate 	recids[0] = hs->hs_record_id;
641*0Sstevel@tonic-gate 	recids[1] = hsp->hsp_record_id;
642*0Sstevel@tonic-gate 	recids[2] = 0;
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	sv.setno = setno;
645*0Sstevel@tonic-gate 	sv.key = hs->hs_key;
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	hs->hs_refcount--;
648*0Sstevel@tonic-gate 	if (hs->hs_refcount == 0) {
649*0Sstevel@tonic-gate 		/*
650*0Sstevel@tonic-gate 		 * NOTE: We do not commit the previous hot spare record.
651*0Sstevel@tonic-gate 		 *	 There is no need, the link we get rebuilt at boot time.
652*0Sstevel@tonic-gate 		 */
653*0Sstevel@tonic-gate 		if (prev_hs) {
654*0Sstevel@tonic-gate 			prev_hs->hs_next = hs->hs_next;
655*0Sstevel@tonic-gate 		} else
656*0Sstevel@tonic-gate 			md_set[setno].s_hs = (void *) hs->hs_next;
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 		/* mark the hot spare to be deleted */
659*0Sstevel@tonic-gate 		delete_hs = 1;
660*0Sstevel@tonic-gate 		recids[0] = hsp->hsp_record_id;
661*0Sstevel@tonic-gate 		recids[1] = 0;
662*0Sstevel@tonic-gate 	}
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	/* find the location of the hs in the hsp */
665*0Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
666*0Sstevel@tonic-gate 		if (hsp->hsp_hotspares[i] == hs->hs_record_id)
667*0Sstevel@tonic-gate 			break;
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	/* remove the hs from the hsp */
671*0Sstevel@tonic-gate 	for (i++; i < hsp->hsp_nhotspares; i++)
672*0Sstevel@tonic-gate 		hsp->hsp_hotspares[i - 1] = hsp->hsp_hotspares[i];
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	hsp->hsp_nhotspares--;
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 	/* commit the db records */
677*0Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	if (delete_hs)
680*0Sstevel@tonic-gate 		mddb_deleterec_wrapper(hs->hs_record_id);
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	md_rem_names(&sv, 1);
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REMOVE, SVM_TAG_HSP, setno,
685*0Sstevel@tonic-gate 	    md_expldev(hsp->hsp_self_id));
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	return (0);
688*0Sstevel@tonic-gate }
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate static int
691*0Sstevel@tonic-gate seths_replace(set_hs_params_t *shs)
692*0Sstevel@tonic-gate {
693*0Sstevel@tonic-gate 	hot_spare_t		*hs;
694*0Sstevel@tonic-gate 	hot_spare_t		*prev_hs;
695*0Sstevel@tonic-gate 	hot_spare_t		*new_hs;
696*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
697*0Sstevel@tonic-gate 	int			new_found = 0;
698*0Sstevel@tonic-gate 	mddb_recid_t		recid;
699*0Sstevel@tonic-gate 	mddb_recid_t		recids[5];
700*0Sstevel@tonic-gate 	int			i;
701*0Sstevel@tonic-gate 	sv_dev_t		sv;
702*0Sstevel@tonic-gate 	int			delete_hs = 0;
703*0Sstevel@tonic-gate 	set_t			setno;
704*0Sstevel@tonic-gate 	mddb_type_t		typ1;
705*0Sstevel@tonic-gate 	mdkey_t			key_old;
706*0Sstevel@tonic-gate 	int			num_keys_old = 0;
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	setno = HSP_SET(shs->shs_hot_spare_pool);
709*0Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
710*0Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 	/* Scan the hot spare list */
713*0Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
714*0Sstevel@tonic-gate 	prev_hs = (hot_spare_t *)0;
715*0Sstevel@tonic-gate 	while (hs) {
716*0Sstevel@tonic-gate 		if (hs->hs_devnum == shs->shs_component_old) {
717*0Sstevel@tonic-gate 			break;
718*0Sstevel@tonic-gate 		}
719*0Sstevel@tonic-gate 		prev_hs = hs;
720*0Sstevel@tonic-gate 		hs = hs->hs_next;
721*0Sstevel@tonic-gate 	}
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 	if (hs == NULL) {
724*0Sstevel@tonic-gate 		/*
725*0Sstevel@tonic-gate 		 * Unable to find device using devnum so use
726*0Sstevel@tonic-gate 		 * key associated with shs_component_old instead.
727*0Sstevel@tonic-gate 		 * If unable to find a unique key for shs_component_old
728*0Sstevel@tonic-gate 		 * then fail since namespace has multiple entries
729*0Sstevel@tonic-gate 		 * for this old component and we're unable to determine
730*0Sstevel@tonic-gate 		 * which key is the valid match for shs_component_old.
731*0Sstevel@tonic-gate 		 *
732*0Sstevel@tonic-gate 		 * Only need to compare keys when hs_devnum is NODEV.
733*0Sstevel@tonic-gate 		 */
734*0Sstevel@tonic-gate 		if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
735*0Sstevel@tonic-gate 		    shs->shs_component_old, &key_old, &num_keys_old) != 0) {
736*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_NAME_SPACE,
737*0Sstevel@tonic-gate 			    shs->shs_component_old));
738*0Sstevel@tonic-gate 		}
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 		/*
741*0Sstevel@tonic-gate 		 * If more than one key matches given old_dev - fail command
742*0Sstevel@tonic-gate 		 * since unable to determine which key is correct.
743*0Sstevel@tonic-gate 		 */
744*0Sstevel@tonic-gate 		if (num_keys_old > 1) {
745*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_MULTNM,
746*0Sstevel@tonic-gate 			    shs->shs_component_old));
747*0Sstevel@tonic-gate 		}
748*0Sstevel@tonic-gate 		/*
749*0Sstevel@tonic-gate 		 * If there is no key for this entry then fail since
750*0Sstevel@tonic-gate 		 * a key for this entry should exist.
751*0Sstevel@tonic-gate 		 */
752*0Sstevel@tonic-gate 		if (num_keys_old == 0) {
753*0Sstevel@tonic-gate 			return (mddeverror(&shs->mde, MDE_INVAL_HS,
754*0Sstevel@tonic-gate 			    shs->shs_component_old));
755*0Sstevel@tonic-gate 		}
756*0Sstevel@tonic-gate 		/* Scan the hot spare list again */
757*0Sstevel@tonic-gate 		hs = (hot_spare_t *)md_set[setno].s_hs;
758*0Sstevel@tonic-gate 		prev_hs = (hot_spare_t *)0;
759*0Sstevel@tonic-gate 		while (hs) {
760*0Sstevel@tonic-gate 			/*
761*0Sstevel@tonic-gate 			 * Only need to compare keys when hs_devnum is NODEV.
762*0Sstevel@tonic-gate 			 */
763*0Sstevel@tonic-gate 			if ((hs->hs_devnum == NODEV64) &&
764*0Sstevel@tonic-gate 			    (hs->hs_key == key_old)) {
765*0Sstevel@tonic-gate 				break;
766*0Sstevel@tonic-gate 			}
767*0Sstevel@tonic-gate 			prev_hs = hs;
768*0Sstevel@tonic-gate 			hs = hs->hs_next;
769*0Sstevel@tonic-gate 		}
770*0Sstevel@tonic-gate 	}
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	if (hs == NULL) {
773*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
774*0Sstevel@tonic-gate 		    shs->shs_component_old));
775*0Sstevel@tonic-gate 	}
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	/* check the force flag and the state of the hot spare */
778*0Sstevel@tonic-gate 	if (((shs->shs_options & HS_OPT_FORCE) == 0) &&
779*0Sstevel@tonic-gate 	    (hs->hs_state == HSS_RESERVED)) {
780*0Sstevel@tonic-gate 		return (mdhserror(&shs->mde, MDE_HS_RESVD,
781*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool,
782*0Sstevel@tonic-gate 		    hs->hs_devnum));
783*0Sstevel@tonic-gate 	}
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 	/* Scan the hot spare pool list */
786*0Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, shs->shs_hot_spare_pool);
787*0Sstevel@tonic-gate 	if (hsp == (hot_spare_pool_t *)0) {
788*0Sstevel@tonic-gate 		return (mdhsperror(&shs->mde, MDE_INVAL_HSP,
789*0Sstevel@tonic-gate 		    shs->shs_hot_spare_pool));
790*0Sstevel@tonic-gate 	}
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	/*
793*0Sstevel@tonic-gate 	 * Make sure the old device is in the pool.
794*0Sstevel@tonic-gate 	 */
795*0Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
796*0Sstevel@tonic-gate 		if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
797*0Sstevel@tonic-gate 			break;
798*0Sstevel@tonic-gate 		}
799*0Sstevel@tonic-gate 	}
800*0Sstevel@tonic-gate 	if (i >= hsp->hsp_nhotspares) {
801*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
802*0Sstevel@tonic-gate 		    hs->hs_devnum));
803*0Sstevel@tonic-gate 	}
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate 	/* Scan the hot spare list for the new hs */
806*0Sstevel@tonic-gate 	new_hs = (hot_spare_t *)md_set[setno].s_hs;
807*0Sstevel@tonic-gate 	new_found = 0;
808*0Sstevel@tonic-gate 	while (new_hs) {
809*0Sstevel@tonic-gate 		if (new_hs->hs_devnum == shs->shs_component_new) {
810*0Sstevel@tonic-gate 			new_found = 1;
811*0Sstevel@tonic-gate 			break;
812*0Sstevel@tonic-gate 		}
813*0Sstevel@tonic-gate 		new_hs = new_hs->hs_next;
814*0Sstevel@tonic-gate 	}
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate 	/*
817*0Sstevel@tonic-gate 	 * Make sure the new device is not already in the pool.
818*0Sstevel@tonic-gate 	 * We don't have to search the hs in this hsp, if the
819*0Sstevel@tonic-gate 	 * new hs was just created. Only if the hot spare was found.
820*0Sstevel@tonic-gate 	 */
821*0Sstevel@tonic-gate 	if (new_found) {
822*0Sstevel@tonic-gate 		for (i = 0; i < hsp->hsp_nhotspares; i++)
823*0Sstevel@tonic-gate 			if (hsp->hsp_hotspares[i] == new_hs->hs_record_id) {
824*0Sstevel@tonic-gate 				return (mdhserror(&shs->mde, MDE_HS_INUSE,
825*0Sstevel@tonic-gate 				    shs->shs_hot_spare_pool,
826*0Sstevel@tonic-gate 				    new_hs->hs_devnum));
827*0Sstevel@tonic-gate 			}
828*0Sstevel@tonic-gate 	}
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 	/* In case of a dryrun, we're done here */
831*0Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
832*0Sstevel@tonic-gate 		return (0);
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	/*
836*0Sstevel@tonic-gate 	 * Create the new hotspare
837*0Sstevel@tonic-gate 	 */
838*0Sstevel@tonic-gate 	if (!new_found) {
839*0Sstevel@tonic-gate 		/* create a hot spare record */
840*0Sstevel@tonic-gate 		if (shs->shs_size_option & MD_CRO_64BIT) {
841*0Sstevel@tonic-gate #if defined(_ILP32)
842*0Sstevel@tonic-gate 			return (mdhserror(&shs->mde, MDE_HS_UNIT_TOO_LARGE,
843*0Sstevel@tonic-gate 			    shs->shs_hot_spare_pool, shs->shs_component_new));
844*0Sstevel@tonic-gate #else
845*0Sstevel@tonic-gate 			recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
846*0Sstevel@tonic-gate 				MD_CRO_64BIT | MD_CRO_HOTSPARE, setno);
847*0Sstevel@tonic-gate #endif
848*0Sstevel@tonic-gate 		} else {
849*0Sstevel@tonic-gate 			recid = mddb_createrec(HS_ONDSK_STR_SIZE, typ1, HS_REC,
850*0Sstevel@tonic-gate 				MD_CRO_32BIT | MD_CRO_HOTSPARE, setno);
851*0Sstevel@tonic-gate 		}
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate 		if (recid < 0) {
854*0Sstevel@tonic-gate 			return (mdhserror(&shs->mde, MDE_HS_CREATE_FAILURE,
855*0Sstevel@tonic-gate 			    shs->shs_hot_spare_pool,
856*0Sstevel@tonic-gate 			    shs->shs_component_new));
857*0Sstevel@tonic-gate 		}
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 		/* get the addr */
860*0Sstevel@tonic-gate 		new_hs = (hot_spare_t *)mddb_getrecaddr_resize(recid,
861*0Sstevel@tonic-gate 			sizeof (*new_hs), 0);
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 		new_hs->hs_record_id = recid;
864*0Sstevel@tonic-gate 		new_hs->hs_devnum = shs->shs_component_new;
865*0Sstevel@tonic-gate 		new_hs->hs_key = shs->shs_key_new;
866*0Sstevel@tonic-gate 		new_hs->hs_start_blk = shs->shs_start_blk;
867*0Sstevel@tonic-gate 		new_hs->hs_has_label = shs->shs_has_label;
868*0Sstevel@tonic-gate 		new_hs->hs_number_blks = shs->shs_number_blks;
869*0Sstevel@tonic-gate 		set_hot_spare_state(new_hs, HSS_AVAILABLE);
870*0Sstevel@tonic-gate 		new_hs->hs_refcount = 0;
871*0Sstevel@tonic-gate 		new_hs->hs_isopen = 1;
872*0Sstevel@tonic-gate 	}
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	/* lock the db records */
875*0Sstevel@tonic-gate 	recids[0] = hs->hs_record_id;
876*0Sstevel@tonic-gate 	recids[1] = new_hs->hs_record_id;
877*0Sstevel@tonic-gate 	recids[2] = hsp->hsp_record_id;
878*0Sstevel@tonic-gate 	recids[3] = 0;
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 	sv.setno = setno;
881*0Sstevel@tonic-gate 	sv.key = hs->hs_key;
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	hs->hs_refcount--;
884*0Sstevel@tonic-gate 	if (hs->hs_refcount == 0) {
885*0Sstevel@tonic-gate 		/*
886*0Sstevel@tonic-gate 		 * NOTE: We do not commit the previous hot spare record.
887*0Sstevel@tonic-gate 		 *	 There is no need, the link we get rebuilt at boot time.
888*0Sstevel@tonic-gate 		 */
889*0Sstevel@tonic-gate 		if (prev_hs) {
890*0Sstevel@tonic-gate 			prev_hs->hs_next = hs->hs_next;
891*0Sstevel@tonic-gate 		} else
892*0Sstevel@tonic-gate 			md_set[setno].s_hs = (void *) hs->hs_next;
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 		/* mark hs to be deleted in the correct order */
895*0Sstevel@tonic-gate 		delete_hs = 1;
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 		recids[0] = new_hs->hs_record_id;
898*0Sstevel@tonic-gate 		recids[1] = hsp->hsp_record_id;
899*0Sstevel@tonic-gate 		recids[2] = 0;
900*0Sstevel@tonic-gate 	}
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	/* link into the hs list */
903*0Sstevel@tonic-gate 	new_hs->hs_refcount++;
904*0Sstevel@tonic-gate 	if (!new_found) {
905*0Sstevel@tonic-gate 		/* do this AFTER the old dev is possibly removed */
906*0Sstevel@tonic-gate 		new_hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
907*0Sstevel@tonic-gate 		md_set[setno].s_hs = (void *) new_hs;
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	/* find the location of the old hs in the hsp */
911*0Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
912*0Sstevel@tonic-gate 		if (hsp->hsp_hotspares[i] == hs->hs_record_id) {
913*0Sstevel@tonic-gate 			hsp->hsp_hotspares[i] = new_hs->hs_record_id;
914*0Sstevel@tonic-gate 			break;
915*0Sstevel@tonic-gate 		}
916*0Sstevel@tonic-gate 	}
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 	if (shs->shs_size_option & MD_CRO_64BIT) {
919*0Sstevel@tonic-gate 		new_hs->hs_revision = MD_64BIT_META_DEV;
920*0Sstevel@tonic-gate 	} else {
921*0Sstevel@tonic-gate 		new_hs->hs_revision = MD_32BIT_META_DEV;
922*0Sstevel@tonic-gate 	}
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	/* commit the db records */
925*0Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 	if (delete_hs)
928*0Sstevel@tonic-gate 		mddb_deleterec_wrapper(hs->hs_record_id);
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 	md_rem_names(&sv, 1);
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REPLACE, SVM_TAG_HSP, setno,
933*0Sstevel@tonic-gate 	    md_expldev(hsp->hsp_self_id));
934*0Sstevel@tonic-gate 	return (0);
935*0Sstevel@tonic-gate }
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate static int
938*0Sstevel@tonic-gate seths_enable(set_hs_params_t *shs)
939*0Sstevel@tonic-gate {
940*0Sstevel@tonic-gate 	hot_spare_t	*hs;
941*0Sstevel@tonic-gate 	mddb_recid_t	recids[2];
942*0Sstevel@tonic-gate 	set_t		setno = shs->md_driver.md_setno;
943*0Sstevel@tonic-gate 	mdkey_t		key_old;
944*0Sstevel@tonic-gate 	int		num_keys_old = 0;
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 
947*0Sstevel@tonic-gate 	/*
948*0Sstevel@tonic-gate 	 * Find device by using key associated with shs_component_old.
949*0Sstevel@tonic-gate 	 * If unable to find a unique key for shs_component_old
950*0Sstevel@tonic-gate 	 * then fail since namespace has multiple entries
951*0Sstevel@tonic-gate 	 * for this old component and we're unable to determine
952*0Sstevel@tonic-gate 	 * which key is the valid match for shs_component_old.
953*0Sstevel@tonic-gate 	 * This failure keeps a hotspare from being enabled on a slice
954*0Sstevel@tonic-gate 	 * that may already be in use by another metadevice.
955*0Sstevel@tonic-gate 	 */
956*0Sstevel@tonic-gate 	if (md_getkeyfromdev(setno, mddb_getsidenum(setno),
957*0Sstevel@tonic-gate 	    shs->shs_component_old, &key_old, &num_keys_old) != 0) {
958*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_NAME_SPACE,
959*0Sstevel@tonic-gate 		    shs->shs_component_old));
960*0Sstevel@tonic-gate 	}
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate 	/*
963*0Sstevel@tonic-gate 	 * If more than one key matches given old_dev - fail command
964*0Sstevel@tonic-gate 	 * since unable to determine which key is correct.
965*0Sstevel@tonic-gate 	 */
966*0Sstevel@tonic-gate 	if (num_keys_old > 1) {
967*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_MULTNM,
968*0Sstevel@tonic-gate 		    shs->shs_component_old));
969*0Sstevel@tonic-gate 	}
970*0Sstevel@tonic-gate 	/*
971*0Sstevel@tonic-gate 	 * If there is no key for this entry then fail since
972*0Sstevel@tonic-gate 	 * a key for this entry should exist.
973*0Sstevel@tonic-gate 	 */
974*0Sstevel@tonic-gate 	if (num_keys_old == 0) {
975*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
976*0Sstevel@tonic-gate 		    shs->shs_component_old));
977*0Sstevel@tonic-gate 	}
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 	/* Scan the hot spare list for the hs */
980*0Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
981*0Sstevel@tonic-gate 	while (hs) {
982*0Sstevel@tonic-gate 		/*
983*0Sstevel@tonic-gate 		 * Since component may or may not be currently in the system,
984*0Sstevel@tonic-gate 		 * use the keys to find a match (not the devt).
985*0Sstevel@tonic-gate 		 */
986*0Sstevel@tonic-gate 		if (hs->hs_key == key_old) {
987*0Sstevel@tonic-gate 			break;
988*0Sstevel@tonic-gate 		}
989*0Sstevel@tonic-gate 		hs = hs->hs_next;
990*0Sstevel@tonic-gate 	}
991*0Sstevel@tonic-gate 
992*0Sstevel@tonic-gate 	if (hs == NULL) {
993*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_INVAL_HS,
994*0Sstevel@tonic-gate 			shs->shs_component_old));
995*0Sstevel@tonic-gate 	}
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 	/* make sure it's broken */
998*0Sstevel@tonic-gate 	if (hs->hs_state != HSS_BROKEN) {
999*0Sstevel@tonic-gate 		return (mddeverror(&shs->mde, MDE_FIX_INVAL_HS_STATE,
1000*0Sstevel@tonic-gate 		    hs->hs_devnum));
1001*0Sstevel@tonic-gate 	}
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 	/* In case of a dryrun, we're done here */
1004*0Sstevel@tonic-gate 	if (shs->shs_options & HS_OPT_DRYRUN) {
1005*0Sstevel@tonic-gate 		return (0);
1006*0Sstevel@tonic-gate 	}
1007*0Sstevel@tonic-gate 
1008*0Sstevel@tonic-gate 	/* fix it */
1009*0Sstevel@tonic-gate 	set_hot_spare_state(hs, HSS_AVAILABLE);
1010*0Sstevel@tonic-gate 	hs->hs_start_blk = shs->shs_start_blk;
1011*0Sstevel@tonic-gate 	hs->hs_has_label = shs->shs_has_label;
1012*0Sstevel@tonic-gate 	hs->hs_number_blks = shs->shs_number_blks;
1013*0Sstevel@tonic-gate 
1014*0Sstevel@tonic-gate 	/* commit the db records */
1015*0Sstevel@tonic-gate 	recids[0] = hs->hs_record_id;
1016*0Sstevel@tonic-gate 	recids[1] = 0;
1017*0Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
1018*0Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ENABLE, SVM_TAG_HS, setno,
1019*0Sstevel@tonic-gate 	    shs->shs_component_old);
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate 	return (0);
1022*0Sstevel@tonic-gate }
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate static int
1025*0Sstevel@tonic-gate get_hs(
1026*0Sstevel@tonic-gate 	get_hs_params_t	*ghs
1027*0Sstevel@tonic-gate )
1028*0Sstevel@tonic-gate {
1029*0Sstevel@tonic-gate 	hot_spare_t	*hs;
1030*0Sstevel@tonic-gate 	set_t		setno = ghs->md_driver.md_setno;
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate 	mdclrerror(&ghs->mde);
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate 	/* Scan the hot spare list for the hs */
1035*0Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
1036*0Sstevel@tonic-gate 	while (hs) {
1037*0Sstevel@tonic-gate 		if (hs->hs_key == ghs->ghs_key) {
1038*0Sstevel@tonic-gate 			break;
1039*0Sstevel@tonic-gate 		}
1040*0Sstevel@tonic-gate 		hs = hs->hs_next;
1041*0Sstevel@tonic-gate 	}
1042*0Sstevel@tonic-gate 
1043*0Sstevel@tonic-gate 	if (hs == NULL) {
1044*0Sstevel@tonic-gate 		return (mddeverror(&ghs->mde, MDE_INVAL_HS,
1045*0Sstevel@tonic-gate 		    ghs->ghs_devnum));
1046*0Sstevel@tonic-gate 	}
1047*0Sstevel@tonic-gate 
1048*0Sstevel@tonic-gate 	ghs->ghs_start_blk = hs->hs_start_blk;
1049*0Sstevel@tonic-gate 	ghs->ghs_number_blks = hs->hs_number_blks;
1050*0Sstevel@tonic-gate 	ghs->ghs_state = hs->hs_state;
1051*0Sstevel@tonic-gate 	ghs->ghs_timestamp = hs->hs_timestamp;
1052*0Sstevel@tonic-gate 	ghs->ghs_revision = hs->hs_revision;
1053*0Sstevel@tonic-gate 	return (0);
1054*0Sstevel@tonic-gate }
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate static void
1057*0Sstevel@tonic-gate build_key_list(set_t setno, hot_spare_pool_t *hsp, mdkey_t *list)
1058*0Sstevel@tonic-gate {
1059*0Sstevel@tonic-gate 	int	i;
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
1062*0Sstevel@tonic-gate 		hot_spare_t *hs;
1063*0Sstevel@tonic-gate 		hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1);
1064*0Sstevel@tonic-gate 		list[i] = hs->hs_key;
1065*0Sstevel@tonic-gate 	}
1066*0Sstevel@tonic-gate }
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate static int
1069*0Sstevel@tonic-gate get_hsp(
1070*0Sstevel@tonic-gate 	void			*d,
1071*0Sstevel@tonic-gate 	int			mode
1072*0Sstevel@tonic-gate )
1073*0Sstevel@tonic-gate {
1074*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
1075*0Sstevel@tonic-gate 	get_hsp_t		*ghsp;
1076*0Sstevel@tonic-gate 	size_t			size;
1077*0Sstevel@tonic-gate 	set_t			setno;
1078*0Sstevel@tonic-gate 	int			err = 0;
1079*0Sstevel@tonic-gate 	md_i_get_t		*migp = (md_i_get_t *)d;
1080*0Sstevel@tonic-gate 
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 	setno = migp->md_driver.md_setno;
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 	mdclrerror(&migp->mde);
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate 	/* Scan the hot spare pool list */
1087*0Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, migp->id);
1088*0Sstevel@tonic-gate 	if (hsp == NULL) {
1089*0Sstevel@tonic-gate 		return (mdhsperror(&migp->mde, MDE_INVAL_HSP,
1090*0Sstevel@tonic-gate 			migp->id));
1091*0Sstevel@tonic-gate 	}
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 	size = (sizeof (ghsp->ghsp_hs_keys[0]) * (hsp->hsp_nhotspares - 1)) +
1094*0Sstevel@tonic-gate 	    sizeof (get_hsp_t);
1095*0Sstevel@tonic-gate 
1096*0Sstevel@tonic-gate 	if (migp->size == 0) {
1097*0Sstevel@tonic-gate 		migp->size = (int)size;
1098*0Sstevel@tonic-gate 		return (0);
1099*0Sstevel@tonic-gate 	}
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate 	if (migp->size < size)
1102*0Sstevel@tonic-gate 		return (EFAULT);
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 	ghsp = kmem_alloc(size, KM_SLEEP);
1105*0Sstevel@tonic-gate 
1106*0Sstevel@tonic-gate 	ghsp->ghsp_id = hsp->hsp_self_id;
1107*0Sstevel@tonic-gate 	ghsp->ghsp_refcount = hsp->hsp_refcount;
1108*0Sstevel@tonic-gate 	ghsp->ghsp_nhotspares = hsp->hsp_nhotspares;
1109*0Sstevel@tonic-gate 	build_key_list(setno, hsp, ghsp->ghsp_hs_keys);
1110*0Sstevel@tonic-gate 	if (ddi_copyout(ghsp, (caddr_t)(uintptr_t)migp->mdp, size, mode))
1111*0Sstevel@tonic-gate 		err = EFAULT;
1112*0Sstevel@tonic-gate 	kmem_free(ghsp, size);
1113*0Sstevel@tonic-gate 	return (err);
1114*0Sstevel@tonic-gate }
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate static int
1117*0Sstevel@tonic-gate set_hs(
1118*0Sstevel@tonic-gate 	set_hs_params_t	*shs
1119*0Sstevel@tonic-gate )
1120*0Sstevel@tonic-gate {
1121*0Sstevel@tonic-gate 	mdclrerror(&shs->mde);
1122*0Sstevel@tonic-gate 
1123*0Sstevel@tonic-gate 	if (md_get_setstatus(shs->md_driver.md_setno) & MD_SET_STALE)
1124*0Sstevel@tonic-gate 		return (mdmddberror(&shs->mde, MDE_DB_STALE, NODEV32,
1125*0Sstevel@tonic-gate 		    shs->md_driver.md_setno));
1126*0Sstevel@tonic-gate 
1127*0Sstevel@tonic-gate 	switch (shs->shs_cmd) {
1128*0Sstevel@tonic-gate 	case ADD_HOT_SPARE:
1129*0Sstevel@tonic-gate 		return (seths_add(shs));
1130*0Sstevel@tonic-gate 	case DELETE_HOT_SPARE:
1131*0Sstevel@tonic-gate 		return (seths_delete(shs));
1132*0Sstevel@tonic-gate 	case REPLACE_HOT_SPARE:
1133*0Sstevel@tonic-gate 		return (seths_replace(shs));
1134*0Sstevel@tonic-gate 	case FIX_HOT_SPARE:
1135*0Sstevel@tonic-gate 		return (seths_enable(shs));
1136*0Sstevel@tonic-gate 	default:
1137*0Sstevel@tonic-gate 		return (mderror(&shs->mde, MDE_INVAL_HSOP));
1138*0Sstevel@tonic-gate 	}
1139*0Sstevel@tonic-gate }
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate static void
1142*0Sstevel@tonic-gate hotspares_poke_hotspares(void)
1143*0Sstevel@tonic-gate {
1144*0Sstevel@tonic-gate 	intptr_t	(*poke_hs)();
1145*0Sstevel@tonic-gate 	int		i;
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate 	for (i = 0; i < MD_NOPS; i++) {
1148*0Sstevel@tonic-gate 		/* handle change */
1149*0Sstevel@tonic-gate 		poke_hs = md_get_named_service(NODEV64, i, "poke hotspares", 0);
1150*0Sstevel@tonic-gate 		if (poke_hs)
1151*0Sstevel@tonic-gate 			(void) (*poke_hs)();
1152*0Sstevel@tonic-gate 	}
1153*0Sstevel@tonic-gate }
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate /*ARGSUSED4*/
1157*0Sstevel@tonic-gate static int
1158*0Sstevel@tonic-gate hotspares_ioctl(
1159*0Sstevel@tonic-gate 	dev_t	dev,
1160*0Sstevel@tonic-gate 	int	cmd,
1161*0Sstevel@tonic-gate 	void	*data,
1162*0Sstevel@tonic-gate 	int	mode,
1163*0Sstevel@tonic-gate 	IOLOCK	*lockp
1164*0Sstevel@tonic-gate )
1165*0Sstevel@tonic-gate {
1166*0Sstevel@tonic-gate 	size_t	sz = 0;
1167*0Sstevel@tonic-gate 	void	*d = NULL;
1168*0Sstevel@tonic-gate 	int	err = 0;
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate 	/* single thread */
1171*0Sstevel@tonic-gate 	if (getminor(dev) != MD_ADM_MINOR)
1172*0Sstevel@tonic-gate 		return (ENOTTY);
1173*0Sstevel@tonic-gate 
1174*0Sstevel@tonic-gate 	/* We can only handle 32-bit clients for internal commands */
1175*0Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) != DATAMODEL_ILP32) {
1176*0Sstevel@tonic-gate 		return (EINVAL);
1177*0Sstevel@tonic-gate 	}
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate 	mutex_enter(&md_mx);
1180*0Sstevel@tonic-gate 	while (md_status & MD_GBL_HS_LOCK)
1181*0Sstevel@tonic-gate 		cv_wait(&md_cv, &md_mx);
1182*0Sstevel@tonic-gate 	md_status |= MD_GBL_HS_LOCK;
1183*0Sstevel@tonic-gate 	mutex_exit(&md_mx);
1184*0Sstevel@tonic-gate 
1185*0Sstevel@tonic-gate 	/* dispatch ioctl */
1186*0Sstevel@tonic-gate 	switch (cmd) {
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	case MD_IOCSET_HS:	/* setup hot spares and pools */
1189*0Sstevel@tonic-gate 	{
1190*0Sstevel@tonic-gate 		if (! (mode & FWRITE)) {
1191*0Sstevel@tonic-gate 			err = EACCES;
1192*0Sstevel@tonic-gate 			break;
1193*0Sstevel@tonic-gate 		}
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate 		sz = sizeof (set_hs_params_t);
1196*0Sstevel@tonic-gate 		d = kmem_alloc(sz, KM_SLEEP);
1197*0Sstevel@tonic-gate 
1198*0Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
1199*0Sstevel@tonic-gate 			err = EFAULT;
1200*0Sstevel@tonic-gate 			break;
1201*0Sstevel@tonic-gate 		}
1202*0Sstevel@tonic-gate 
1203*0Sstevel@tonic-gate 		err = set_hs(d);
1204*0Sstevel@tonic-gate 		break;
1205*0Sstevel@tonic-gate 	}
1206*0Sstevel@tonic-gate 
1207*0Sstevel@tonic-gate 	case MD_IOCGET_HS:	/* get hot spare info */
1208*0Sstevel@tonic-gate 	{
1209*0Sstevel@tonic-gate 		if (! (mode & FREAD)) {
1210*0Sstevel@tonic-gate 			err = EACCES;
1211*0Sstevel@tonic-gate 			break;
1212*0Sstevel@tonic-gate 		}
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate 		sz = sizeof (get_hs_params_t);
1215*0Sstevel@tonic-gate 		d = kmem_alloc(sz, KM_SLEEP);
1216*0Sstevel@tonic-gate 
1217*0Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
1218*0Sstevel@tonic-gate 			err = EFAULT;
1219*0Sstevel@tonic-gate 			break;
1220*0Sstevel@tonic-gate 		}
1221*0Sstevel@tonic-gate 
1222*0Sstevel@tonic-gate 		err = get_hs(d);
1223*0Sstevel@tonic-gate 		break;
1224*0Sstevel@tonic-gate 	}
1225*0Sstevel@tonic-gate 
1226*0Sstevel@tonic-gate 	case MD_IOCGET:		/* get hot spare pool info */
1227*0Sstevel@tonic-gate 	{
1228*0Sstevel@tonic-gate 		if (! (mode & FREAD)) {
1229*0Sstevel@tonic-gate 			err = EACCES;
1230*0Sstevel@tonic-gate 			break;
1231*0Sstevel@tonic-gate 		}
1232*0Sstevel@tonic-gate 
1233*0Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
1234*0Sstevel@tonic-gate 		d = kmem_alloc(sz, KM_SLEEP);
1235*0Sstevel@tonic-gate 
1236*0Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
1237*0Sstevel@tonic-gate 			err = EFAULT;
1238*0Sstevel@tonic-gate 			break;
1239*0Sstevel@tonic-gate 		}
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate 		err = get_hsp(d, mode);
1242*0Sstevel@tonic-gate 		break;
1243*0Sstevel@tonic-gate 	}
1244*0Sstevel@tonic-gate 
1245*0Sstevel@tonic-gate 	default:
1246*0Sstevel@tonic-gate 		err = ENOTTY;
1247*0Sstevel@tonic-gate 	}
1248*0Sstevel@tonic-gate 
1249*0Sstevel@tonic-gate 	/*
1250*0Sstevel@tonic-gate 	 * copyout and free any args
1251*0Sstevel@tonic-gate 	 */
1252*0Sstevel@tonic-gate 	if (sz != 0) {
1253*0Sstevel@tonic-gate 		if (err == 0) {
1254*0Sstevel@tonic-gate 			if (ddi_copyout(d, data, sz, mode) != 0) {
1255*0Sstevel@tonic-gate 				err = EFAULT;
1256*0Sstevel@tonic-gate 			}
1257*0Sstevel@tonic-gate 		}
1258*0Sstevel@tonic-gate 		kmem_free(d, sz);
1259*0Sstevel@tonic-gate 	}
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate 	/* un single thread */
1262*0Sstevel@tonic-gate 	mutex_enter(&md_mx);
1263*0Sstevel@tonic-gate 	md_status &= ~MD_GBL_HS_LOCK;
1264*0Sstevel@tonic-gate 	cv_broadcast(&md_cv);
1265*0Sstevel@tonic-gate 	mutex_exit(&md_mx);
1266*0Sstevel@tonic-gate 
1267*0Sstevel@tonic-gate 	/* handle change */
1268*0Sstevel@tonic-gate 	hotspares_poke_hotspares();
1269*0Sstevel@tonic-gate 
1270*0Sstevel@tonic-gate 	/* return success */
1271*0Sstevel@tonic-gate 	return (err);
1272*0Sstevel@tonic-gate }
1273*0Sstevel@tonic-gate 
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate static void
1276*0Sstevel@tonic-gate load_hotspare(set_t setno, mddb_recid_t recid)
1277*0Sstevel@tonic-gate {
1278*0Sstevel@tonic-gate 	hot_spare_t	*hs;
1279*0Sstevel@tonic-gate 	mddb_de_ic_t	*dep;
1280*0Sstevel@tonic-gate 	mddb_rb32_t	*rbp;
1281*0Sstevel@tonic-gate 	size_t		newreqsize;
1282*0Sstevel@tonic-gate 	hot_spare_t	*b_hs;
1283*0Sstevel@tonic-gate 	hot_spare32_od_t *s_hs;
1284*0Sstevel@tonic-gate 
1285*0Sstevel@tonic-gate 	mddb_setrecprivate(recid, MD_PRV_GOTIT);
1286*0Sstevel@tonic-gate 
1287*0Sstevel@tonic-gate 	dep = mddb_getrecdep(recid);
1288*0Sstevel@tonic-gate 	dep->de_flags = MDDB_F_HOTSPARE;
1289*0Sstevel@tonic-gate 	rbp = dep->de_rb;
1290*0Sstevel@tonic-gate 	if (rbp->rb_revision == MDDB_REV_RB) {
1291*0Sstevel@tonic-gate 		/*
1292*0Sstevel@tonic-gate 		 * Needs to convert to internal 64 bit
1293*0Sstevel@tonic-gate 		 */
1294*0Sstevel@tonic-gate 		s_hs = (hot_spare32_od_t *)mddb_getrecaddr(recid);
1295*0Sstevel@tonic-gate 		newreqsize = sizeof (hot_spare_t);
1296*0Sstevel@tonic-gate 		b_hs = (hot_spare_t *)kmem_zalloc(newreqsize, KM_SLEEP);
1297*0Sstevel@tonic-gate 		hs_convert((caddr_t)s_hs, (caddr_t)b_hs, SMALL_2_BIG);
1298*0Sstevel@tonic-gate 		kmem_free(s_hs, dep->de_reqsize);
1299*0Sstevel@tonic-gate 		dep->de_rb_userdata = b_hs;
1300*0Sstevel@tonic-gate 		dep->de_reqsize = newreqsize;
1301*0Sstevel@tonic-gate 		hs = b_hs;
1302*0Sstevel@tonic-gate 	} else {
1303*0Sstevel@tonic-gate 		hs = (hot_spare_t *)mddb_getrecaddr_resize
1304*0Sstevel@tonic-gate 			(recid, sizeof (*hs), 0);
1305*0Sstevel@tonic-gate 	}
1306*0Sstevel@tonic-gate 
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate #if defined(_ILP32)
1309*0Sstevel@tonic-gate 	if (hs->hs_revision == MD_64BIT_META_DEV) {
1310*0Sstevel@tonic-gate 		char	devname[MD_MAX_CTDLEN];
1311*0Sstevel@tonic-gate 
1312*0Sstevel@tonic-gate 		set_hot_spare_state(hs, HSS_BROKEN);
1313*0Sstevel@tonic-gate 		(void) md_devname(setno, hs->hs_devnum, devname,
1314*0Sstevel@tonic-gate 		    sizeof (devname));
1315*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%s is unavailable because 64 bit hotspares "
1316*0Sstevel@tonic-gate 		    "are not accessible on a 32 bit kernel\n", devname);
1317*0Sstevel@tonic-gate 	}
1318*0Sstevel@tonic-gate #endif
1319*0Sstevel@tonic-gate 
1320*0Sstevel@tonic-gate 	ASSERT(hs != NULL);
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate 	if (hs->hs_refcount == 0) {
1323*0Sstevel@tonic-gate 		mddb_setrecprivate(recid, MD_PRV_PENDDEL);
1324*0Sstevel@tonic-gate 		return;
1325*0Sstevel@tonic-gate 	}
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 	hs->hs_next = (hot_spare_t *)md_set[setno].s_hs;
1328*0Sstevel@tonic-gate 	md_set[setno].s_hs = (void *)hs;
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate 	hs->hs_isopen = 0;
1331*0Sstevel@tonic-gate 
1332*0Sstevel@tonic-gate 	hs->hs_devnum = md_getdevnum(setno, mddb_getsidenum(setno),
1333*0Sstevel@tonic-gate 		hs->hs_key, MD_NOTRUST_DEVT);
1334*0Sstevel@tonic-gate }
1335*0Sstevel@tonic-gate 
1336*0Sstevel@tonic-gate 
1337*0Sstevel@tonic-gate static void
1338*0Sstevel@tonic-gate load_hotsparepool(set_t setno, mddb_recid_t recid)
1339*0Sstevel@tonic-gate {
1340*0Sstevel@tonic-gate 	hot_spare_pool_t *hsp;
1341*0Sstevel@tonic-gate 	hot_spare_pool_ond_t *hsp_ond;
1342*0Sstevel@tonic-gate 	size_t hsp_icsize;
1343*0Sstevel@tonic-gate 
1344*0Sstevel@tonic-gate 	mddb_setrecprivate(recid, MD_PRV_GOTIT);
1345*0Sstevel@tonic-gate 
1346*0Sstevel@tonic-gate 	hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid);
1347*0Sstevel@tonic-gate 	ASSERT(hsp_ond != NULL);
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 	if (hsp_ond->hsp_self_id == MD_HSP_NONE) {
1350*0Sstevel@tonic-gate 		mddb_setrecprivate(recid, MD_PRV_PENDDEL);
1351*0Sstevel@tonic-gate 		return;
1352*0Sstevel@tonic-gate 	}
1353*0Sstevel@tonic-gate 
1354*0Sstevel@tonic-gate 	hsp_icsize =  HSP_ONDSK_STR_OFF + mddb_getrecsize(recid);
1355*0Sstevel@tonic-gate 
1356*0Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)mddb_getrecaddr_resize(recid, hsp_icsize,
1357*0Sstevel@tonic-gate 		HSP_ONDSK_STR_OFF);
1358*0Sstevel@tonic-gate 	hsp->hsp_next = (hot_spare_pool_t *)md_set[setno].s_hsp;
1359*0Sstevel@tonic-gate 	md_set[setno].s_hsp = (void *) hsp;
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate 	rw_enter(&hotspares_md_ops.md_link_rw.lock, RW_WRITER);
1362*0Sstevel@tonic-gate 	hsp->hsp_link.ln_next = hotspares_md_ops.md_head;
1363*0Sstevel@tonic-gate 	hsp->hsp_link.ln_setno = setno;
1364*0Sstevel@tonic-gate 	hsp->hsp_link.ln_id = hsp->hsp_self_id;
1365*0Sstevel@tonic-gate 	hotspares_md_ops.md_head = &hsp->hsp_link;
1366*0Sstevel@tonic-gate 	rw_exit(&hotspares_md_ops.md_link_rw.lock);
1367*0Sstevel@tonic-gate }
1368*0Sstevel@tonic-gate 
1369*0Sstevel@tonic-gate static int
1370*0Sstevel@tonic-gate hotspares_snarf(md_snarfcmd_t cmd, set_t setno)
1371*0Sstevel@tonic-gate {
1372*0Sstevel@tonic-gate 	mddb_recid_t	recid;
1373*0Sstevel@tonic-gate 	int		gotsomething;
1374*0Sstevel@tonic-gate 	mddb_type_t	typ1;
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate 	if (cmd == MD_SNARF_CLEANUP)
1377*0Sstevel@tonic-gate 		return (0);
1378*0Sstevel@tonic-gate 
1379*0Sstevel@tonic-gate 	gotsomething = 0;
1380*0Sstevel@tonic-gate 
1381*0Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
1382*0Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
1383*0Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
1384*0Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) {
1385*0Sstevel@tonic-gate 		if (mddb_getrecprivate(recid) & MD_PRV_GOTIT)
1386*0Sstevel@tonic-gate 			continue;
1387*0Sstevel@tonic-gate 
1388*0Sstevel@tonic-gate 		switch (mddb_getrectype2(recid)) {
1389*0Sstevel@tonic-gate 		case HSP_REC:
1390*0Sstevel@tonic-gate 			load_hotsparepool(setno, recid);
1391*0Sstevel@tonic-gate 			gotsomething = 1;
1392*0Sstevel@tonic-gate 			break;
1393*0Sstevel@tonic-gate 		case HS_REC:
1394*0Sstevel@tonic-gate 			load_hotspare(setno, recid);
1395*0Sstevel@tonic-gate 			gotsomething = 1;
1396*0Sstevel@tonic-gate 			break;
1397*0Sstevel@tonic-gate 		default:
1398*0Sstevel@tonic-gate 			ASSERT(0);
1399*0Sstevel@tonic-gate 		}
1400*0Sstevel@tonic-gate 	}
1401*0Sstevel@tonic-gate 
1402*0Sstevel@tonic-gate 	if (gotsomething)
1403*0Sstevel@tonic-gate 		return (gotsomething);
1404*0Sstevel@tonic-gate 
1405*0Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
1406*0Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0)
1407*0Sstevel@tonic-gate 		if (!(mddb_getrecprivate(recid) & MD_PRV_GOTIT))
1408*0Sstevel@tonic-gate 			mddb_setrecprivate(recid, MD_PRV_PENDDEL);
1409*0Sstevel@tonic-gate 
1410*0Sstevel@tonic-gate 	return (0);
1411*0Sstevel@tonic-gate }
1412*0Sstevel@tonic-gate 
1413*0Sstevel@tonic-gate static int
1414*0Sstevel@tonic-gate hotspares_halt(md_haltcmd_t cmd, set_t setno)
1415*0Sstevel@tonic-gate {
1416*0Sstevel@tonic-gate 	hot_spare_t		*hs, **p_hs;
1417*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp, **p_hsp;
1418*0Sstevel@tonic-gate 
1419*0Sstevel@tonic-gate 	if (cmd == MD_HALT_CLOSE)
1420*0Sstevel@tonic-gate 		return (0);
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate 	if (cmd == MD_HALT_OPEN)
1423*0Sstevel@tonic-gate 		return (0);
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 	if (cmd == MD_HALT_CHECK)
1426*0Sstevel@tonic-gate 		return (0);
1427*0Sstevel@tonic-gate 
1428*0Sstevel@tonic-gate 	if (cmd == MD_HALT_UNLOAD)
1429*0Sstevel@tonic-gate 		return (0);
1430*0Sstevel@tonic-gate 
1431*0Sstevel@tonic-gate 	if (cmd != MD_HALT_DOIT)
1432*0Sstevel@tonic-gate 		return (1);
1433*0Sstevel@tonic-gate 	/*
1434*0Sstevel@tonic-gate 	 * Find all the hotspares for set "setno"
1435*0Sstevel@tonic-gate 	 *   and remove them from the hot_spare_list.
1436*0Sstevel@tonic-gate 	 */
1437*0Sstevel@tonic-gate 	p_hs = (hot_spare_t **)&md_set[setno].s_hs;
1438*0Sstevel@tonic-gate 	hs = (hot_spare_t *)md_set[setno].s_hs;
1439*0Sstevel@tonic-gate 	for (; hs != NULL; hs = *p_hs)
1440*0Sstevel@tonic-gate 		*p_hs = hs->hs_next;
1441*0Sstevel@tonic-gate 
1442*0Sstevel@tonic-gate 	/*
1443*0Sstevel@tonic-gate 	 * Find all the hotspare pools for set "setno"
1444*0Sstevel@tonic-gate 	 *   and remove them from the hot_spare_pools list.
1445*0Sstevel@tonic-gate 	 * Also remove from the get_next list.
1446*0Sstevel@tonic-gate 	 */
1447*0Sstevel@tonic-gate 	p_hsp = (hot_spare_pool_t **)&md_set[setno].s_hsp;
1448*0Sstevel@tonic-gate 	hsp = (hot_spare_pool_t *)md_set[setno].s_hsp;
1449*0Sstevel@tonic-gate 	for (; hsp != NULL; hsp = *p_hsp) {
1450*0Sstevel@tonic-gate 		md_rem_link(setno, hsp->hsp_self_id,
1451*0Sstevel@tonic-gate 		    &hotspares_md_ops.md_link_rw.lock,
1452*0Sstevel@tonic-gate 		    &hotspares_md_ops.md_head);
1453*0Sstevel@tonic-gate 		*p_hsp = hsp->hsp_next;
1454*0Sstevel@tonic-gate 	}
1455*0Sstevel@tonic-gate 
1456*0Sstevel@tonic-gate 	return (0);
1457*0Sstevel@tonic-gate }
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate static hot_spare_t *
1460*0Sstevel@tonic-gate usable_hs(
1461*0Sstevel@tonic-gate 	set_t		setno,
1462*0Sstevel@tonic-gate 	mddb_recid_t	hs_id,
1463*0Sstevel@tonic-gate 	diskaddr_t	nblks,
1464*0Sstevel@tonic-gate 	int		labeled,
1465*0Sstevel@tonic-gate 	diskaddr_t	*start)
1466*0Sstevel@tonic-gate {
1467*0Sstevel@tonic-gate 	hot_spare_t	*hs;
1468*0Sstevel@tonic-gate 
1469*0Sstevel@tonic-gate 	hs = lookup_hot_spare(setno, hs_id, 1);
1470*0Sstevel@tonic-gate 
1471*0Sstevel@tonic-gate 	if (hs->hs_state != HSS_AVAILABLE)
1472*0Sstevel@tonic-gate 		return ((hot_spare_t *)0);
1473*0Sstevel@tonic-gate 
1474*0Sstevel@tonic-gate 	if (labeled && hs->hs_has_label && (hs->hs_number_blks >= nblks)) {
1475*0Sstevel@tonic-gate 		*start = 0;
1476*0Sstevel@tonic-gate 		return (hs);
1477*0Sstevel@tonic-gate 	} else if ((hs->hs_number_blks - hs->hs_start_blk) >= nblks) {
1478*0Sstevel@tonic-gate 		*start = hs->hs_start_blk;
1479*0Sstevel@tonic-gate 		return (hs);
1480*0Sstevel@tonic-gate 	}
1481*0Sstevel@tonic-gate 	return ((hot_spare_t *)0);
1482*0Sstevel@tonic-gate }
1483*0Sstevel@tonic-gate 
1484*0Sstevel@tonic-gate static int
1485*0Sstevel@tonic-gate reserve_a_hs(
1486*0Sstevel@tonic-gate 	set_t		setno,
1487*0Sstevel@tonic-gate 	mddb_recid_t	id,
1488*0Sstevel@tonic-gate 	uint64_t	size,
1489*0Sstevel@tonic-gate 	int		labeled,
1490*0Sstevel@tonic-gate 	mddb_recid_t	*hs_id,
1491*0Sstevel@tonic-gate 	mdkey_t		*key,
1492*0Sstevel@tonic-gate 	md_dev64_t	*dev,
1493*0Sstevel@tonic-gate 	diskaddr_t	*sblock)
1494*0Sstevel@tonic-gate {
1495*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
1496*0Sstevel@tonic-gate 	hot_spare_t		*hs;
1497*0Sstevel@tonic-gate 	int			i;
1498*0Sstevel@tonic-gate 
1499*0Sstevel@tonic-gate 	*hs_id = 0;
1500*0Sstevel@tonic-gate 
1501*0Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, id);
1502*0Sstevel@tonic-gate 	if (hsp == NULL)
1503*0Sstevel@tonic-gate 		return (-1);
1504*0Sstevel@tonic-gate 
1505*0Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
1506*0Sstevel@tonic-gate 		hs = usable_hs(setno, hsp->hsp_hotspares[i],
1507*0Sstevel@tonic-gate 		    size, labeled, sblock);
1508*0Sstevel@tonic-gate 		if (hs == NULL)
1509*0Sstevel@tonic-gate 			continue;
1510*0Sstevel@tonic-gate 
1511*0Sstevel@tonic-gate 		set_hot_spare_state(hs, HSS_RESERVED);
1512*0Sstevel@tonic-gate 		*hs_id = hs->hs_record_id;
1513*0Sstevel@tonic-gate 		*key = hs->hs_key;
1514*0Sstevel@tonic-gate 		*dev = hs->hs_devnum;
1515*0Sstevel@tonic-gate 		/* NOTE: Mirror code commits the hs record */
1516*0Sstevel@tonic-gate 		return (0);
1517*0Sstevel@tonic-gate 	}
1518*0Sstevel@tonic-gate 
1519*0Sstevel@tonic-gate 	return (-1);
1520*0Sstevel@tonic-gate }
1521*0Sstevel@tonic-gate 
1522*0Sstevel@tonic-gate 
1523*0Sstevel@tonic-gate /* ARGSUSED3 */
1524*0Sstevel@tonic-gate static int
1525*0Sstevel@tonic-gate return_a_hs(
1526*0Sstevel@tonic-gate 	set_t			setno,
1527*0Sstevel@tonic-gate 	mddb_recid_t		id,
1528*0Sstevel@tonic-gate 	mddb_recid_t		*hs_id,
1529*0Sstevel@tonic-gate 	mdkey_t			key,
1530*0Sstevel@tonic-gate 	diskaddr_t		sblock,
1531*0Sstevel@tonic-gate 	uint64_t		size,
1532*0Sstevel@tonic-gate 	hotspare_states_t	new_state)
1533*0Sstevel@tonic-gate {
1534*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
1535*0Sstevel@tonic-gate 	hot_spare_t		*hs;
1536*0Sstevel@tonic-gate 	int			i;
1537*0Sstevel@tonic-gate 
1538*0Sstevel@tonic-gate 	/*
1539*0Sstevel@tonic-gate 	 * NOTE: sblock/size are not currently being used.
1540*0Sstevel@tonic-gate 	 *	 That is because we always allocate the whole hs.
1541*0Sstevel@tonic-gate 	 *	 Later if we choose to allocate only what is needed
1542*0Sstevel@tonic-gate 	 *	 then the sblock/size can be used to determine
1543*0Sstevel@tonic-gate 	 *	 which part is being unreseved.
1544*0Sstevel@tonic-gate 	 */
1545*0Sstevel@tonic-gate 	*hs_id = 0;
1546*0Sstevel@tonic-gate 
1547*0Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, id);
1548*0Sstevel@tonic-gate 	if (hsp == NULL)
1549*0Sstevel@tonic-gate 		return (-1);
1550*0Sstevel@tonic-gate 
1551*0Sstevel@tonic-gate 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
1552*0Sstevel@tonic-gate 		hs = lookup_hot_spare(setno, hsp->hsp_hotspares[i], 1);
1553*0Sstevel@tonic-gate 		if (hs->hs_key != key)
1554*0Sstevel@tonic-gate 			continue;
1555*0Sstevel@tonic-gate 
1556*0Sstevel@tonic-gate 		set_hot_spare_state(hs, new_state);
1557*0Sstevel@tonic-gate 		*hs_id = hs->hs_record_id;
1558*0Sstevel@tonic-gate 		if (new_state == HSS_BROKEN) {
1559*0Sstevel@tonic-gate 			SE_NOTIFY(EC_SVM_STATE, ESC_SVM_ERRED, SVM_TAG_HS,
1560*0Sstevel@tonic-gate 			    setno, hs->hs_devnum);
1561*0Sstevel@tonic-gate 		}
1562*0Sstevel@tonic-gate 		if (new_state == HSS_AVAILABLE) {
1563*0Sstevel@tonic-gate 			SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_HS,
1564*0Sstevel@tonic-gate 			    setno, hs->hs_devnum);
1565*0Sstevel@tonic-gate 		}
1566*0Sstevel@tonic-gate 
1567*0Sstevel@tonic-gate 		/* NOTE: Mirror/Raid code commits the hs record */
1568*0Sstevel@tonic-gate 		return (0);
1569*0Sstevel@tonic-gate 	}
1570*0Sstevel@tonic-gate 
1571*0Sstevel@tonic-gate 	return (-1);
1572*0Sstevel@tonic-gate }
1573*0Sstevel@tonic-gate 
1574*0Sstevel@tonic-gate 
1575*0Sstevel@tonic-gate static int
1576*0Sstevel@tonic-gate modify_hsp_ref(set_t setno, mddb_recid_t id, int incref,  mddb_recid_t *hsp_id)
1577*0Sstevel@tonic-gate {
1578*0Sstevel@tonic-gate 	hot_spare_pool_t	*hsp;
1579*0Sstevel@tonic-gate 
1580*0Sstevel@tonic-gate 	*hsp_id = 0;
1581*0Sstevel@tonic-gate 
1582*0Sstevel@tonic-gate 	if (id  < 0)
1583*0Sstevel@tonic-gate 		return (0);
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate 	hsp = find_hot_spare_pool(setno, id);
1586*0Sstevel@tonic-gate 	if (hsp == NULL)
1587*0Sstevel@tonic-gate 		return (-1);
1588*0Sstevel@tonic-gate 
1589*0Sstevel@tonic-gate 	if (incref)
1590*0Sstevel@tonic-gate 		hsp->hsp_refcount++;
1591*0Sstevel@tonic-gate 	else
1592*0Sstevel@tonic-gate 		hsp->hsp_refcount--;
1593*0Sstevel@tonic-gate 
1594*0Sstevel@tonic-gate 	*hsp_id = hsp->hsp_record_id;
1595*0Sstevel@tonic-gate 
1596*0Sstevel@tonic-gate 	/* NOTE: Stripe code commits the hsp record */
1597*0Sstevel@tonic-gate 	return (0);
1598*0Sstevel@tonic-gate }
1599*0Sstevel@tonic-gate 
1600*0Sstevel@tonic-gate 
1601*0Sstevel@tonic-gate static int
1602*0Sstevel@tonic-gate mkdev_for_a_hs(mddb_recid_t hs_id, md_dev64_t *dev)
1603*0Sstevel@tonic-gate {
1604*0Sstevel@tonic-gate 	hot_spare_t	*hs;
1605*0Sstevel@tonic-gate 
1606*0Sstevel@tonic-gate 	hs = lookup_hot_spare(mddb_getsetnum(hs_id), hs_id, 0);
1607*0Sstevel@tonic-gate 	if (hs == NULL)
1608*0Sstevel@tonic-gate 		return (0);
1609*0Sstevel@tonic-gate 
1610*0Sstevel@tonic-gate 	*dev = hs->hs_devnum;
1611*0Sstevel@tonic-gate 	return (0);
1612*0Sstevel@tonic-gate }
1613*0Sstevel@tonic-gate 
1614*0Sstevel@tonic-gate static intptr_t
1615*0Sstevel@tonic-gate hotspares_interface(
1616*0Sstevel@tonic-gate 	hs_cmds_t	cmd,
1617*0Sstevel@tonic-gate 	mddb_recid_t	id,
1618*0Sstevel@tonic-gate 	uint64_t	size,
1619*0Sstevel@tonic-gate 	int		bool,
1620*0Sstevel@tonic-gate 	mddb_recid_t	*hs_id,
1621*0Sstevel@tonic-gate 	mdkey_t		*key,
1622*0Sstevel@tonic-gate 	md_dev64_t	*dev,
1623*0Sstevel@tonic-gate 	diskaddr_t	*sblock)
1624*0Sstevel@tonic-gate {
1625*0Sstevel@tonic-gate 	set_t	setno;
1626*0Sstevel@tonic-gate 	int	err = -1;
1627*0Sstevel@tonic-gate 
1628*0Sstevel@tonic-gate 	mutex_enter(&md_mx);
1629*0Sstevel@tonic-gate 	while (md_status & MD_GBL_HS_LOCK)
1630*0Sstevel@tonic-gate 		cv_wait(&md_cv, &md_mx);
1631*0Sstevel@tonic-gate 
1632*0Sstevel@tonic-gate 	/* If md_halt has been run do not continue */
1633*0Sstevel@tonic-gate 	if (md_status & (MD_GBL_HALTED | MD_GBL_DAEMONS_DIE)) {
1634*0Sstevel@tonic-gate 		mutex_exit(&md_mx);
1635*0Sstevel@tonic-gate 		return (ENXIO);
1636*0Sstevel@tonic-gate 	}
1637*0Sstevel@tonic-gate 
1638*0Sstevel@tonic-gate 	md_status |= MD_GBL_HS_LOCK;
1639*0Sstevel@tonic-gate 	mutex_exit(&md_mx);
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate 	setno = mddb_getsetnum(id);
1642*0Sstevel@tonic-gate 
1643*0Sstevel@tonic-gate 	switch (cmd) {
1644*0Sstevel@tonic-gate 	case HS_GET:
1645*0Sstevel@tonic-gate 		err = reserve_a_hs(setno, id, size, bool, hs_id,
1646*0Sstevel@tonic-gate 		    key, dev, sblock);
1647*0Sstevel@tonic-gate 		break;
1648*0Sstevel@tonic-gate 	case HS_FREE:
1649*0Sstevel@tonic-gate 		err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_AVAILABLE);
1650*0Sstevel@tonic-gate 		hotspares_poke_hotspares();
1651*0Sstevel@tonic-gate 		break;
1652*0Sstevel@tonic-gate 	case HS_BAD:
1653*0Sstevel@tonic-gate 		err = return_a_hs(setno, id, hs_id, *key, 0, 0, HSS_BROKEN);
1654*0Sstevel@tonic-gate 		break;
1655*0Sstevel@tonic-gate 	case HSP_INCREF:
1656*0Sstevel@tonic-gate 		err = modify_hsp_ref(setno, id, 1, hs_id);
1657*0Sstevel@tonic-gate 		break;
1658*0Sstevel@tonic-gate 	case HSP_DECREF:
1659*0Sstevel@tonic-gate 		err = modify_hsp_ref(setno, id, 0, hs_id);
1660*0Sstevel@tonic-gate 		break;
1661*0Sstevel@tonic-gate 	case HS_MKDEV:
1662*0Sstevel@tonic-gate 		err = mkdev_for_a_hs(*hs_id, dev);
1663*0Sstevel@tonic-gate 		break;
1664*0Sstevel@tonic-gate 	}
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 	mutex_enter(&md_mx);
1667*0Sstevel@tonic-gate 	md_status &= ~MD_GBL_HS_LOCK;
1668*0Sstevel@tonic-gate 	cv_broadcast(&md_cv);
1669*0Sstevel@tonic-gate 	mutex_exit(&md_mx);
1670*0Sstevel@tonic-gate 
1671*0Sstevel@tonic-gate 	return (err);
1672*0Sstevel@tonic-gate }
1673*0Sstevel@tonic-gate 
1674*0Sstevel@tonic-gate static void
1675*0Sstevel@tonic-gate imp_hotsparepool(
1676*0Sstevel@tonic-gate 	set_t	setno,
1677*0Sstevel@tonic-gate 	mddb_recid_t	recid
1678*0Sstevel@tonic-gate )
1679*0Sstevel@tonic-gate {
1680*0Sstevel@tonic-gate 	hot_spare_pool_ond_t	*hsp_ond;
1681*0Sstevel@tonic-gate 	mddb_recid_t		*hsp_recid, *hs_recid;
1682*0Sstevel@tonic-gate 	int			i;
1683*0Sstevel@tonic-gate 	uint_t			*hsp_selfid;
1684*0Sstevel@tonic-gate 
1685*0Sstevel@tonic-gate 	mddb_setrecprivate(recid, MD_PRV_GOTIT);
1686*0Sstevel@tonic-gate 
1687*0Sstevel@tonic-gate 	hsp_ond = (hot_spare_pool_ond_t *)mddb_getrecaddr(recid);
1688*0Sstevel@tonic-gate 	hsp_recid = &(hsp_ond->hsp_record_id);
1689*0Sstevel@tonic-gate 	hsp_selfid = &(hsp_ond->hsp_self_id);
1690*0Sstevel@tonic-gate 	/*
1691*0Sstevel@tonic-gate 	 * Fixup the pool and hotspares
1692*0Sstevel@tonic-gate 	 */
1693*0Sstevel@tonic-gate 	*hsp_recid = MAKERECID(setno, DBID(*hsp_recid));
1694*0Sstevel@tonic-gate 	*hsp_selfid = MAKERECID(setno, DBID(*hsp_selfid));
1695*0Sstevel@tonic-gate 
1696*0Sstevel@tonic-gate 	for (i = 0; i < hsp_ond->hsp_nhotspares; i++) {
1697*0Sstevel@tonic-gate 		hs_recid = &(hsp_ond->hsp_hotspares[i]);
1698*0Sstevel@tonic-gate 		*hs_recid = MAKERECID(setno, DBID(*hs_recid));
1699*0Sstevel@tonic-gate 	}
1700*0Sstevel@tonic-gate }
1701*0Sstevel@tonic-gate 
1702*0Sstevel@tonic-gate static void
1703*0Sstevel@tonic-gate imp_hotspare(
1704*0Sstevel@tonic-gate 	set_t	setno,
1705*0Sstevel@tonic-gate 	mddb_recid_t	recid
1706*0Sstevel@tonic-gate )
1707*0Sstevel@tonic-gate {
1708*0Sstevel@tonic-gate 	mddb_de_ic_t	*dep;
1709*0Sstevel@tonic-gate 	mddb_rb32_t	*rbp;
1710*0Sstevel@tonic-gate 	hot_spare_t	*hs64;
1711*0Sstevel@tonic-gate 	hot_spare32_od_t	*hs32;
1712*0Sstevel@tonic-gate 	mddb_recid_t	*hs_recid;
1713*0Sstevel@tonic-gate 
1714*0Sstevel@tonic-gate 	mddb_setrecprivate(recid, MD_PRV_GOTIT);
1715*0Sstevel@tonic-gate 
1716*0Sstevel@tonic-gate 	dep = mddb_getrecdep(recid);
1717*0Sstevel@tonic-gate 	rbp = dep->de_rb;
1718*0Sstevel@tonic-gate 	if (rbp->rb_revision == MDDB_REV_RB) {
1719*0Sstevel@tonic-gate 		/*
1720*0Sstevel@tonic-gate 		 * 32 bit hotspare
1721*0Sstevel@tonic-gate 		 */
1722*0Sstevel@tonic-gate 		hs32 = (hot_spare32_od_t *)mddb_getrecaddr(recid);
1723*0Sstevel@tonic-gate 		hs_recid = &(hs32->hs_record_id);
1724*0Sstevel@tonic-gate 	} else {
1725*0Sstevel@tonic-gate 		hs64 = (hot_spare_t *)mddb_getrecaddr(recid);
1726*0Sstevel@tonic-gate 		hs_recid = &(hs64->hs_record_id);
1727*0Sstevel@tonic-gate 	}
1728*0Sstevel@tonic-gate 
1729*0Sstevel@tonic-gate 	/*
1730*0Sstevel@tonic-gate 	 * Fixup the setno
1731*0Sstevel@tonic-gate 	 */
1732*0Sstevel@tonic-gate 	*hs_recid = MAKERECID(setno, DBID(*hs_recid));
1733*0Sstevel@tonic-gate }
1734*0Sstevel@tonic-gate 
1735*0Sstevel@tonic-gate static int
1736*0Sstevel@tonic-gate hotspares_imp_set(
1737*0Sstevel@tonic-gate 	set_t	setno
1738*0Sstevel@tonic-gate )
1739*0Sstevel@tonic-gate {
1740*0Sstevel@tonic-gate 	mddb_recid_t	recid;
1741*0Sstevel@tonic-gate 	int		gotsomething;
1742*0Sstevel@tonic-gate 	mddb_type_t	typ1;
1743*0Sstevel@tonic-gate 
1744*0Sstevel@tonic-gate 
1745*0Sstevel@tonic-gate 	gotsomething = 0;
1746*0Sstevel@tonic-gate 
1747*0Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
1748*0Sstevel@tonic-gate 	    hotspares_md_ops.md_driver.md_drivername);
1749*0Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
1750*0Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) {
1751*0Sstevel@tonic-gate 		if (mddb_getrecprivate(recid) & MD_PRV_GOTIT)
1752*0Sstevel@tonic-gate 			continue;
1753*0Sstevel@tonic-gate 
1754*0Sstevel@tonic-gate 		switch (mddb_getrectype2(recid)) {
1755*0Sstevel@tonic-gate 		case HSP_REC:
1756*0Sstevel@tonic-gate 			imp_hotsparepool(setno, recid);
1757*0Sstevel@tonic-gate 			gotsomething = 1;
1758*0Sstevel@tonic-gate 			break;
1759*0Sstevel@tonic-gate 		case HS_REC:
1760*0Sstevel@tonic-gate 			imp_hotspare(setno, recid);
1761*0Sstevel@tonic-gate 			gotsomething = 1;
1762*0Sstevel@tonic-gate 			break;
1763*0Sstevel@tonic-gate 		default:
1764*0Sstevel@tonic-gate 			ASSERT(0);
1765*0Sstevel@tonic-gate 		}
1766*0Sstevel@tonic-gate 	}
1767*0Sstevel@tonic-gate 
1768*0Sstevel@tonic-gate 	return (gotsomething);
1769*0Sstevel@tonic-gate }
1770*0Sstevel@tonic-gate 
1771*0Sstevel@tonic-gate static md_named_services_t hotspares_named_services[] = {
1772*0Sstevel@tonic-gate 	{hotspares_interface,	"hot spare interface"},
1773*0Sstevel@tonic-gate 	{NULL,			0}
1774*0Sstevel@tonic-gate };
1775*0Sstevel@tonic-gate 
1776*0Sstevel@tonic-gate md_ops_t hotspares_md_ops = {
1777*0Sstevel@tonic-gate 	NULL,			/* open */
1778*0Sstevel@tonic-gate 	NULL,			/* close */
1779*0Sstevel@tonic-gate 	NULL,			/* strategy */
1780*0Sstevel@tonic-gate 	NULL,			/* print */
1781*0Sstevel@tonic-gate 	NULL,			/* dump */
1782*0Sstevel@tonic-gate 	NULL,			/* read */
1783*0Sstevel@tonic-gate 	NULL,			/* write */
1784*0Sstevel@tonic-gate 	hotspares_ioctl,	/* hotspares_ioctl, */
1785*0Sstevel@tonic-gate 	hotspares_snarf,	/* hotspares_snarf */
1786*0Sstevel@tonic-gate 	hotspares_halt,		/* halt */
1787*0Sstevel@tonic-gate 	NULL,			/* aread */
1788*0Sstevel@tonic-gate 	NULL,			/* awrite */
1789*0Sstevel@tonic-gate 	hotspares_imp_set,	/* import set */
1790*0Sstevel@tonic-gate 	hotspares_named_services /* named_services */
1791*0Sstevel@tonic-gate };
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate static void
1794*0Sstevel@tonic-gate fini_uninit()
1795*0Sstevel@tonic-gate {
1796*0Sstevel@tonic-gate 	/* prevent access to services that may have been imported */
1797*0Sstevel@tonic-gate 	md_clear_hot_spare_interface();
1798*0Sstevel@tonic-gate }
1799*0Sstevel@tonic-gate 
1800*0Sstevel@tonic-gate /* define the module linkage */
1801*0Sstevel@tonic-gate MD_PLUGIN_MISC_MODULE("hot spares module %I%", md_noop, fini_uninit())
1802