xref: /onnv-gate/usr/src/uts/common/io/lvm/raid/raid_hotspare.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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
23*0Sstevel@tonic-gate 
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * NAME:	raid_hotspare.c
31*0Sstevel@tonic-gate  * DESCRIPTION: RAID driver source file containing routines related to
32*0Sstevel@tonic-gate  *		hospare operation.
33*0Sstevel@tonic-gate  * ROUTINES PROVIDED FOR EXTERNAL USE:
34*0Sstevel@tonic-gate  * raid_hs_release() - release a hotspare device
35*0Sstevel@tonic-gate  *  raid_hotspares() - prompt the hospare daemon to attempt needed hotspare work
36*0Sstevel@tonic-gate  */
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include <sys/param.h>
39*0Sstevel@tonic-gate #include <sys/systm.h>
40*0Sstevel@tonic-gate #include <sys/conf.h>
41*0Sstevel@tonic-gate #include <sys/file.h>
42*0Sstevel@tonic-gate #include <sys/user.h>
43*0Sstevel@tonic-gate #include <sys/uio.h>
44*0Sstevel@tonic-gate #include <sys/t_lock.h>
45*0Sstevel@tonic-gate #include <sys/buf.h>
46*0Sstevel@tonic-gate #include <sys/dkio.h>
47*0Sstevel@tonic-gate #include <sys/vtoc.h>
48*0Sstevel@tonic-gate #include <sys/kmem.h>
49*0Sstevel@tonic-gate #include <vm/page.h>
50*0Sstevel@tonic-gate #include <sys/sysmacros.h>
51*0Sstevel@tonic-gate #include <sys/types.h>
52*0Sstevel@tonic-gate #include <sys/mkdev.h>
53*0Sstevel@tonic-gate #include <sys/stat.h>
54*0Sstevel@tonic-gate #include <sys/open.h>
55*0Sstevel@tonic-gate #include <sys/lvm/md_raid.h>
56*0Sstevel@tonic-gate #include <sys/modctl.h>
57*0Sstevel@tonic-gate #include <sys/ddi.h>
58*0Sstevel@tonic-gate #include <sys/sunddi.h>
59*0Sstevel@tonic-gate #include <sys/debug.h>
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
62*0Sstevel@tonic-gate #include <sys/sysevent/svm.h>
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate extern mdq_anchor_t	md_hs_daemon;
65*0Sstevel@tonic-gate static daemon_request_t hotspare_request;
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate extern md_set_t		md_set[];
68*0Sstevel@tonic-gate extern md_ops_t 	raid_md_ops;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate /*
71*0Sstevel@tonic-gate  * NAME:	raid_hs_release
72*0Sstevel@tonic-gate  *
73*0Sstevel@tonic-gate  * DESCRIPTION: Release the hotspare.
74*0Sstevel@tonic-gate  *
75*0Sstevel@tonic-gate  * PARAMETERS:	int error - indication of error on hotspare
76*0Sstevel@tonic-gate  *		mr_unit_t  *un - raid unit
77*0Sstevel@tonic-gate  *		mddb_recid_t  *recids - output records to commit revised hs info
78*0Sstevel@tonic-gate  *		int hs_index - component to release
79*0Sstevel@tonic-gate  *
80*0Sstevel@tonic-gate  * LOCKS:	Expects Unit Writer Lock to be held across call.
81*0Sstevel@tonic-gate  */
82*0Sstevel@tonic-gate void
raid_hs_release(hs_cmds_t cmd,mr_unit_t * un,mddb_recid_t * recids,int hs_index)83*0Sstevel@tonic-gate raid_hs_release(
84*0Sstevel@tonic-gate 	hs_cmds_t	cmd,
85*0Sstevel@tonic-gate 	mr_unit_t	*un,
86*0Sstevel@tonic-gate 	mddb_recid_t	*recids,
87*0Sstevel@tonic-gate 	int		hs_index
88*0Sstevel@tonic-gate )
89*0Sstevel@tonic-gate {
90*0Sstevel@tonic-gate 	mr_column_t	*col;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	col = &un->un_column[hs_index];
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	/* close the hotspare device */
95*0Sstevel@tonic-gate 	if (col->un_devflags & MD_RAID_DEV_ISOPEN) {
96*0Sstevel@tonic-gate 		md_layered_close(col->un_dev, MD_OFLG_NULL);
97*0Sstevel@tonic-gate 		col->un_devflags &= ~MD_RAID_DEV_ISOPEN;
98*0Sstevel@tonic-gate 	}
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	/* return the hotspare to the pool */
101*0Sstevel@tonic-gate 	(void) md_hot_spare_ifc(cmd, un->un_hsp_id, 0, 0, recids,
102*0Sstevel@tonic-gate 	    &col->un_hs_key, NULL, NULL);
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	col->un_hs_pwstart = 0;
105*0Sstevel@tonic-gate 	col->un_hs_devstart = 0;
106*0Sstevel@tonic-gate 	col->un_hs_id = (mddb_recid_t)0;
107*0Sstevel@tonic-gate 	col->un_hs_key = 0;
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate /*
112*0Sstevel@tonic-gate  * NAME:	check_comp_4_hs
113*0Sstevel@tonic-gate  *
114*0Sstevel@tonic-gate  * DESCRIPTION: Check whether the input component has an error and can be
115*0Sstevel@tonic-gate  *		backed with a hot spare (RCS_ERRED state), and initiate
116*0Sstevel@tonic-gate  *		a resync if so.
117*0Sstevel@tonic-gate  *
118*0Sstevel@tonic-gate  * PARAMETERS:	mr_unit_t *un - raid unit
119*0Sstevel@tonic-gate  *		int hs_index	- component to check
120*0Sstevel@tonic-gate  *
121*0Sstevel@tonic-gate  * LOCKS:	Expects Unit Writer Lock to be held upon entrance.  Releases
122*0Sstevel@tonic-gate  *		the lock prior to calling raid_resync_unit, then reacquires
123*0Sstevel@tonic-gate  *		it before returning.
124*0Sstevel@tonic-gate  */
125*0Sstevel@tonic-gate static void
check_comp_4_hs(mr_unit_t * un,int hs_index)126*0Sstevel@tonic-gate check_comp_4_hs(
127*0Sstevel@tonic-gate 	mr_unit_t *un,
128*0Sstevel@tonic-gate 	int hs_index
129*0Sstevel@tonic-gate )
130*0Sstevel@tonic-gate {
131*0Sstevel@tonic-gate 	mddb_recid_t	recids[3];
132*0Sstevel@tonic-gate 	minor_t		mnum = MD_SID(un);
133*0Sstevel@tonic-gate 	mdi_unit_t	*ui;
134*0Sstevel@tonic-gate 	rcs_state_t	state;
135*0Sstevel@tonic-gate 	diskaddr_t	size;
136*0Sstevel@tonic-gate 	int		err;
137*0Sstevel@tonic-gate 	mr_column_t	*col;
138*0Sstevel@tonic-gate 	md_error_t	mde = mdnullerror;
139*0Sstevel@tonic-gate 	char		devname[MD_MAX_CTDLEN];
140*0Sstevel@tonic-gate 	char		hs_devname[MD_MAX_CTDLEN];
141*0Sstevel@tonic-gate 	set_t		setno;
142*0Sstevel@tonic-gate 	md_dev64_t	tmpdev;
143*0Sstevel@tonic-gate 	diskaddr_t	tmpdaddr;
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 	/* initialize */
147*0Sstevel@tonic-gate 	setno = MD_UN2SET(un);
148*0Sstevel@tonic-gate 	ui = MDI_UNIT(mnum);
149*0Sstevel@tonic-gate 	md_unit_readerexit(ui);
150*0Sstevel@tonic-gate 	(void) md_io_writerlock(ui);
151*0Sstevel@tonic-gate 	un = (mr_unit_t *)md_unit_writerlock(ui);
152*0Sstevel@tonic-gate 	col = &un->un_column[hs_index];
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	/*
155*0Sstevel@tonic-gate 	 * add a hotspare for erred column only if not resyncing
156*0Sstevel@tonic-gate 	 */
157*0Sstevel@tonic-gate 	if ((!(COLUMN_STATE(un, hs_index) & RCS_ERRED)) ||
158*0Sstevel@tonic-gate 	    (raid_state_cnt(un, (RCS_ERRED | RCS_LAST_ERRED)) != 1) ||
159*0Sstevel@tonic-gate 	    (raid_state_cnt(un, RCS_RESYNC) > 0)) {
160*0Sstevel@tonic-gate 		goto errout;
161*0Sstevel@tonic-gate 	}
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	recids[0] = 0;
164*0Sstevel@tonic-gate 	recids[1] = 0;
165*0Sstevel@tonic-gate 	/* if there is already a hotspare then just return */
166*0Sstevel@tonic-gate 	if (HOTSPARED(un, hs_index) && (col->un_devstate & RCS_ERRED)) {
167*0Sstevel@tonic-gate 		raid_hs_release(HS_BAD, un, &recids[0], hs_index);
168*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "md: %s: %s hotspare errored and released",
169*0Sstevel@tonic-gate 		    md_shortname(mnum),
170*0Sstevel@tonic-gate 		    md_devname(MD_MIN2SET(mnum), col->un_dev, NULL, 0));
171*0Sstevel@tonic-gate 		col->un_dev = col->un_orig_dev;
172*0Sstevel@tonic-gate 		col->un_pwstart = col->un_orig_pwstart;
173*0Sstevel@tonic-gate 		col->un_devstart = col->un_orig_devstart;
174*0Sstevel@tonic-gate 		raid_commit(un, recids);
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 		SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_METADEVICE,
177*0Sstevel@tonic-gate 		    setno, MD_SID(un));
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate 	ASSERT(!HOTSPARED(un, hs_index));
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	state = col->un_devstate;
182*0Sstevel@tonic-gate 	size = col->un_pwstart + un->un_pwsize +
183*0Sstevel@tonic-gate 	    (un->un_segsize * un->un_segsincolumn);
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate again:
186*0Sstevel@tonic-gate 	/* quit if resync is already active */
187*0Sstevel@tonic-gate 	col->un_devflags |= MD_RAID_REGEN_RESYNC;
188*0Sstevel@tonic-gate 	if (resync_request(mnum, hs_index, 0, NULL))
189*0Sstevel@tonic-gate 		goto errout;
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	recids[0] = 0;
192*0Sstevel@tonic-gate 	recids[1] = 0;
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	tmpdev = col->un_dev;
195*0Sstevel@tonic-gate 	tmpdaddr = col->un_hs_pwstart;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	/* get a hotspare */
198*0Sstevel@tonic-gate 	if (md_hot_spare_ifc(HS_GET, un->un_hsp_id, size,
199*0Sstevel@tonic-gate 	    ((col->un_orig_pwstart >= 1) &&
200*0Sstevel@tonic-gate 	    (col->un_orig_pwstart != MD_DISKADDR_ERROR)),
201*0Sstevel@tonic-gate 	    &col->un_hs_id, &col->un_hs_key, &tmpdev, &tmpdaddr) != 0) {
202*0Sstevel@tonic-gate 		col->un_dev = tmpdev;
203*0Sstevel@tonic-gate 		col->un_hs_pwstart = tmpdaddr;
204*0Sstevel@tonic-gate 		release_resync_request(mnum);
205*0Sstevel@tonic-gate 		raid_set_state(un, hs_index, state, 1);
206*0Sstevel@tonic-gate 		goto errout;
207*0Sstevel@tonic-gate 	}
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	col->un_hs_pwstart = tmpdaddr;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	/*
212*0Sstevel@tonic-gate 	 * record id is filled in by raid_commit, recids[0] filled in by
213*0Sstevel@tonic-gate 	 * md_hot_spare_ifc if needed
214*0Sstevel@tonic-gate 	 */
215*0Sstevel@tonic-gate 	recids[0] = col->un_hs_id;
216*0Sstevel@tonic-gate 	recids[1] = 0;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	/*
219*0Sstevel@tonic-gate 	 * close the device and open the hot spare.  The device should
220*0Sstevel@tonic-gate 	 * never be a hotspare here.
221*0Sstevel@tonic-gate 	 */
222*0Sstevel@tonic-gate 	if (col->un_devflags & MD_RAID_DEV_ISOPEN) {
223*0Sstevel@tonic-gate 		md_layered_close(col->un_orig_dev, MD_OFLG_NULL);
224*0Sstevel@tonic-gate 		col->un_devflags &= ~MD_RAID_DEV_ISOPEN;
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 	/*
227*0Sstevel@tonic-gate 	 * Try open by device id
228*0Sstevel@tonic-gate 	 */
229*0Sstevel@tonic-gate 	tmpdev = md_resolve_bydevid(mnum, tmpdev, col->un_hs_key);
230*0Sstevel@tonic-gate 	if (md_layered_open(mnum, &tmpdev, MD_OFLG_NULL)) {
231*0Sstevel@tonic-gate 		md_dev64_t hs_dev = tmpdev;
232*0Sstevel@tonic-gate 		/* cannot open return to orig */
233*0Sstevel@tonic-gate 		raid_hs_release(HS_BAD, un, &recids[0], hs_index);
234*0Sstevel@tonic-gate 		release_resync_request(mnum);
235*0Sstevel@tonic-gate 		raid_set_state(un, hs_index, state, 1);
236*0Sstevel@tonic-gate 		col->un_dev = col->un_orig_dev;
237*0Sstevel@tonic-gate 		col->un_devstart = col->un_orig_devstart;
238*0Sstevel@tonic-gate 		col->un_pwstart = col->un_orig_pwstart;
239*0Sstevel@tonic-gate 		col->un_devflags &= ~MD_RAID_DEV_ISOPEN;
240*0Sstevel@tonic-gate 		raid_commit(un, recids);
241*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "md: %s: open error of hotspare %s",
242*0Sstevel@tonic-gate 		    md_shortname(mnum),
243*0Sstevel@tonic-gate 		    md_devname(MD_MIN2SET(mnum), hs_dev, NULL, 0));
244*0Sstevel@tonic-gate 		SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HS_FREED, SVM_TAG_HS, setno,
245*0Sstevel@tonic-gate 		    MD_SID(un));
246*0Sstevel@tonic-gate 		goto again;
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	col->un_dev = tmpdev;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	col->un_devflags |= MD_RAID_DEV_ISOPEN;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/*
254*0Sstevel@tonic-gate 	 * move the values into the device fields.  Since in some cases
255*0Sstevel@tonic-gate 	 * the pwstart is not zero this must be added into the start of
256*0Sstevel@tonic-gate 	 * the hotspare to avoid over writting the label
257*0Sstevel@tonic-gate 	 */
258*0Sstevel@tonic-gate 	col->un_hs_pwstart += col->un_orig_pwstart;
259*0Sstevel@tonic-gate 	col->un_pwstart = col->un_hs_pwstart;
260*0Sstevel@tonic-gate 	col->un_hs_devstart = col->un_hs_pwstart + un->un_pwsize;
261*0Sstevel@tonic-gate 	col->un_devstart = col->un_hs_devstart;
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	/* commit unit and hotspare records and release lock */
264*0Sstevel@tonic-gate 	raid_commit(un, recids);
265*0Sstevel@tonic-gate 	md_unit_writerexit(ui);
266*0Sstevel@tonic-gate 	md_io_writerexit(ui);
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	err = raid_resync_unit(mnum, &mde);
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	/* if resync fails, transition back to erred state and reset */
271*0Sstevel@tonic-gate 	if (err) {
272*0Sstevel@tonic-gate 		/* reaquire unit writerr lock */
273*0Sstevel@tonic-gate 		un = (mr_unit_t *)md_unit_writerlock(ui);
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 		raid_set_state(un, hs_index, RCS_ERRED, 0);
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 		/*
278*0Sstevel@tonic-gate 		 * close the hotspare and return it.  Then restore the
279*0Sstevel@tonic-gate 		 * original device back to the original state
280*0Sstevel@tonic-gate 		 */
281*0Sstevel@tonic-gate 		raid_hs_release(HS_FREE, un, &recids[0], hs_index);
282*0Sstevel@tonic-gate 		col->un_dev = col->un_orig_dev;
283*0Sstevel@tonic-gate 		col->un_devstart = col->un_orig_devstart;
284*0Sstevel@tonic-gate 		col->un_pwstart = col->un_orig_pwstart;
285*0Sstevel@tonic-gate 		raid_commit(un, recids);
286*0Sstevel@tonic-gate 		md_unit_writerexit(ui);
287*0Sstevel@tonic-gate 		un = (mr_unit_t *)md_unit_readerlock(ui);
288*0Sstevel@tonic-gate 		return;
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	setno = MD_MIN2SET(mnum);
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	(void) md_devname(setno, col->un_orig_dev, devname,
294*0Sstevel@tonic-gate 		sizeof (devname));
295*0Sstevel@tonic-gate 	(void) md_devname(setno, col->un_dev, hs_devname,
296*0Sstevel@tonic-gate 		sizeof (hs_devname));
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	cmn_err(CE_NOTE, "md: %s: hotspared device %s with %s",
299*0Sstevel@tonic-gate 	    md_shortname(mnum), devname, hs_devname);
300*0Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_STATE, ESC_SVM_HOTSPARED, SVM_TAG_HS, setno,
301*0Sstevel@tonic-gate 	    MD_SID(un));
302*0Sstevel@tonic-gate 	(void) md_unit_readerlock(ui);
303*0Sstevel@tonic-gate 	return;
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate errout:
306*0Sstevel@tonic-gate 	md_unit_writerexit(ui);
307*0Sstevel@tonic-gate 	md_io_writerexit(ui);
308*0Sstevel@tonic-gate 	un = (mr_unit_t *)md_unit_readerlock(ui);
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate /*
312*0Sstevel@tonic-gate  * NAME:	check_4_hs
313*0Sstevel@tonic-gate  *
314*0Sstevel@tonic-gate  * DESCRIPTION: Check every component of every raid unit for any device which
315*0Sstevel@tonic-gate  *		needs to be backed with a hot spare.
316*0Sstevel@tonic-gate  *
317*0Sstevel@tonic-gate  * PARAMETERS:	daemon_request_t *dr - hotspare request daemon
318*0Sstevel@tonic-gate  *
319*0Sstevel@tonic-gate  * LOCKS:	Acquires and releases the Hotspare Request Lock and the RAID
320*0Sstevel@tonic-gate  *		Driver Lock. Acquires the Unit Writer Lock which is released
321*0Sstevel@tonic-gate  *		in check_comp_4_hs.
322*0Sstevel@tonic-gate  */
323*0Sstevel@tonic-gate static void
check_4_hs(daemon_request_t * dr)324*0Sstevel@tonic-gate check_4_hs(daemon_request_t *dr)
325*0Sstevel@tonic-gate {
326*0Sstevel@tonic-gate 	mdi_unit_t	*ui;
327*0Sstevel@tonic-gate 	mr_unit_t	*un;
328*0Sstevel@tonic-gate 	md_link_t	*next;
329*0Sstevel@tonic-gate 	int		i;
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	mutex_enter(&dr->dr_mx);	/* clear up front so can poke */
332*0Sstevel@tonic-gate 	dr->dr_pending = 0;		/* again in low level routine if */
333*0Sstevel@tonic-gate 	mutex_exit(&dr->dr_mx);		/* something found to do	*/
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	/*
336*0Sstevel@tonic-gate 	 * Scan raid unit list and call component hotspare check routine for
337*0Sstevel@tonic-gate 	 * each component of each unit where resync is inactive.
338*0Sstevel@tonic-gate 	 */
339*0Sstevel@tonic-gate 	rw_enter(&raid_md_ops.md_link_rw.lock, RW_READER);
340*0Sstevel@tonic-gate 	for (next = raid_md_ops.md_head; next != NULL; next = next->ln_next) {
341*0Sstevel@tonic-gate 		ui = MDI_UNIT(next->ln_id);
342*0Sstevel@tonic-gate 		un = (mr_unit_t *)md_unit_readerlock(ui);
343*0Sstevel@tonic-gate 		if (!(un->c.un_status & MD_UN_RESYNC_ACTIVE) &&
344*0Sstevel@tonic-gate 		    (raid_state_cnt(un, RCS_RESYNC) == 0) &&
345*0Sstevel@tonic-gate 		    (UNIT_STATE(un) & RUS_ERRED) &&
346*0Sstevel@tonic-gate 		    (un->un_hsp_id != -1) &&
347*0Sstevel@tonic-gate 		    (raid_state_cnt(un, RCS_ERRED) == 1)) {
348*0Sstevel@tonic-gate 			for (i = 0; i < un->un_totalcolumncnt; i++)
349*0Sstevel@tonic-gate 				if (un->un_column[i].un_devstate == RCS_ERRED)
350*0Sstevel@tonic-gate 					check_comp_4_hs(un, i);
351*0Sstevel@tonic-gate 		}
352*0Sstevel@tonic-gate 		md_unit_readerexit(ui);
353*0Sstevel@tonic-gate 	}
354*0Sstevel@tonic-gate 	rw_exit(&raid_md_ops.md_link_rw.lock);
355*0Sstevel@tonic-gate }
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate /*
358*0Sstevel@tonic-gate  * NAME:	raid_hotspares
359*0Sstevel@tonic-gate  *
360*0Sstevel@tonic-gate  * DESCRIPTION: Initiate a check of all RAID devices for components which
361*0Sstevel@tonic-gate  *		may require a hot spare, if it is not already running.
362*0Sstevel@tonic-gate  *
363*0Sstevel@tonic-gate  * PARAMETERS:	NONE
364*0Sstevel@tonic-gate  *
365*0Sstevel@tonic-gate  * LOCKS:	Acquires and releases the Hotspare Request Lock.
366*0Sstevel@tonic-gate  */
367*0Sstevel@tonic-gate intptr_t
raid_hotspares()368*0Sstevel@tonic-gate raid_hotspares()
369*0Sstevel@tonic-gate {
370*0Sstevel@tonic-gate 	/* if available, make request for hotspare to master daemon */
371*0Sstevel@tonic-gate 	mutex_enter(&hotspare_request.dr_mx);
372*0Sstevel@tonic-gate 	if (hotspare_request.dr_pending == 0) {
373*0Sstevel@tonic-gate 		hotspare_request.dr_pending = 1;
374*0Sstevel@tonic-gate 		daemon_request(&md_hs_daemon,
375*0Sstevel@tonic-gate 		    check_4_hs, (daemon_queue_t *)&hotspare_request, REQ_OLD);
376*0Sstevel@tonic-gate 	}
377*0Sstevel@tonic-gate 	mutex_exit(&hotspare_request.dr_mx);
378*0Sstevel@tonic-gate 	return (0);
379*0Sstevel@tonic-gate }
380