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/buf.h>
37*0Sstevel@tonic-gate #include <sys/dkio.h>
38*0Sstevel@tonic-gate #include <sys/vtoc.h>
39*0Sstevel@tonic-gate #include <sys/kmem.h>
40*0Sstevel@tonic-gate #include <vm/page.h>
41*0Sstevel@tonic-gate #include <sys/cmn_err.h>
42*0Sstevel@tonic-gate #include <sys/sysmacros.h>
43*0Sstevel@tonic-gate #include <sys/types.h>
44*0Sstevel@tonic-gate #include <sys/mkdev.h>
45*0Sstevel@tonic-gate #include <sys/stat.h>
46*0Sstevel@tonic-gate #include <sys/open.h>
47*0Sstevel@tonic-gate #include <sys/lvm/mdio.h>
48*0Sstevel@tonic-gate #include <sys/lvm/mdvar.h>
49*0Sstevel@tonic-gate #include <sys/lvm/md_stripe.h>
50*0Sstevel@tonic-gate #include <sys/lvm/md_convert.h>
51*0Sstevel@tonic-gate #include <sys/lvm/md_notify.h>
52*0Sstevel@tonic-gate #include <sys/modctl.h>
53*0Sstevel@tonic-gate #include <sys/ddi.h>
54*0Sstevel@tonic-gate #include <sys/sunddi.h>
55*0Sstevel@tonic-gate #include <sys/debug.h>
56*0Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
57*0Sstevel@tonic-gate #include <sys/sysevent/svm.h>
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate md_ops_t		stripe_md_ops;
60*0Sstevel@tonic-gate #ifndef	lint
61*0Sstevel@tonic-gate static char		_depends_on[] = "drv/md";
62*0Sstevel@tonic-gate static md_ops_t		*md_interface_ops = &stripe_md_ops;
63*0Sstevel@tonic-gate #endif
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate extern unit_t		md_nunits;
66*0Sstevel@tonic-gate extern set_t		md_nsets;
67*0Sstevel@tonic-gate extern md_set_t		md_set[];
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate extern kmutex_t		md_mx;
70*0Sstevel@tonic-gate extern kcondvar_t	md_cv;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate extern int		md_status;
73*0Sstevel@tonic-gate extern major_t		md_major;
74*0Sstevel@tonic-gate extern mdq_anchor_t	md_done_daemon;
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate static int		md_stripe_mcs_buf_off;
77*0Sstevel@tonic-gate static kmem_cache_t	*stripe_parent_cache = NULL;
78*0Sstevel@tonic-gate static kmem_cache_t	*stripe_child_cache = NULL;
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate /*ARGSUSED1*/
81*0Sstevel@tonic-gate static int
82*0Sstevel@tonic-gate stripe_parent_constructor(void *p, void *d1, int d2)
83*0Sstevel@tonic-gate {
84*0Sstevel@tonic-gate 	mutex_init(&((md_sps_t *)p)->ps_mx,
85*0Sstevel@tonic-gate 	    NULL, MUTEX_DEFAULT, NULL);
86*0Sstevel@tonic-gate 	return (0);
87*0Sstevel@tonic-gate }
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate static void
90*0Sstevel@tonic-gate stripe_parent_init(void *ps)
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate 	bzero(ps, offsetof(md_sps_t, ps_mx));
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*ARGSUSED1*/
96*0Sstevel@tonic-gate static void
97*0Sstevel@tonic-gate stripe_parent_destructor(void *p, void *d)
98*0Sstevel@tonic-gate {
99*0Sstevel@tonic-gate 	mutex_destroy(&((md_sps_t *)p)->ps_mx);
100*0Sstevel@tonic-gate }
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate /*ARGSUSED1*/
103*0Sstevel@tonic-gate static int
104*0Sstevel@tonic-gate stripe_child_constructor(void *p, void *d1, int d2)
105*0Sstevel@tonic-gate {
106*0Sstevel@tonic-gate 	bioinit(&((md_scs_t *)p)->cs_buf);
107*0Sstevel@tonic-gate 	return (0);
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate static void
111*0Sstevel@tonic-gate stripe_child_init(md_scs_t *cs)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	cs->cs_mdunit = 0;
114*0Sstevel@tonic-gate 	cs->cs_ps = NULL;
115*0Sstevel@tonic-gate 	cs->cs_comp = NULL;
116*0Sstevel@tonic-gate 	md_bioreset(&cs->cs_buf);
117*0Sstevel@tonic-gate }
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /*ARGSUSED1*/
120*0Sstevel@tonic-gate static void
121*0Sstevel@tonic-gate stripe_child_destructor(void *p, void *d)
122*0Sstevel@tonic-gate {
123*0Sstevel@tonic-gate 	biofini(&((md_scs_t *)p)->cs_buf);
124*0Sstevel@tonic-gate }
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate /*ARGSUSED*/
127*0Sstevel@tonic-gate static void
128*0Sstevel@tonic-gate stripe_run_queue(void *d)
129*0Sstevel@tonic-gate {
130*0Sstevel@tonic-gate 	if (!(md_status & MD_GBL_DAEMONS_LIVE))
131*0Sstevel@tonic-gate 		md_daemon(1, &md_done_daemon);
132*0Sstevel@tonic-gate }
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate static void
135*0Sstevel@tonic-gate stripe_close_all_devs(ms_unit_t *un, int md_cflags)
136*0Sstevel@tonic-gate {
137*0Sstevel@tonic-gate 	int		row;
138*0Sstevel@tonic-gate 	int		i;
139*0Sstevel@tonic-gate 	int		c;
140*0Sstevel@tonic-gate 	struct ms_comp	*mdcomp;
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 	mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
143*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
144*0Sstevel@tonic-gate 		struct ms_row *mdr = &un->un_row[row];
145*0Sstevel@tonic-gate 		for (i = 0, c = mdr->un_icomp; i < mdr->un_ncomp; i++) {
146*0Sstevel@tonic-gate 			struct ms_comp	*mdc;
147*0Sstevel@tonic-gate 			mdc = &mdcomp[c++];
148*0Sstevel@tonic-gate 			if (md_cflags & MD_OFLG_PROBEDEV) {
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 			/*
151*0Sstevel@tonic-gate 			 * It is possible that the md_layered_open
152*0Sstevel@tonic-gate 			 * failed because the stripe unit structure
153*0Sstevel@tonic-gate 			 * contained a NODEV.  In such a case since
154*0Sstevel@tonic-gate 			 * there is nothing to open, there is nothing
155*0Sstevel@tonic-gate 			 * to close.
156*0Sstevel@tonic-gate 			 */
157*0Sstevel@tonic-gate 				if (mdc->un_dev == NODEV64)
158*0Sstevel@tonic-gate 					continue;
159*0Sstevel@tonic-gate 			}
160*0Sstevel@tonic-gate 			if ((md_cflags & MD_OFLG_PROBEDEV) &&
161*0Sstevel@tonic-gate 			    (mdc->un_mirror.ms_flags & MDM_S_PROBEOPEN)) {
162*0Sstevel@tonic-gate 				md_layered_close(mdc->un_dev,
163*0Sstevel@tonic-gate 				    md_cflags);
164*0Sstevel@tonic-gate 				mdc->un_mirror.ms_flags &=
165*0Sstevel@tonic-gate 						~MDM_S_PROBEOPEN;
166*0Sstevel@tonic-gate 			} else if (mdc->un_mirror.ms_flags & MDM_S_ISOPEN) {
167*0Sstevel@tonic-gate 				md_layered_close(mdc->un_dev, md_cflags);
168*0Sstevel@tonic-gate 				mdc->un_mirror.ms_flags &= ~MDM_S_ISOPEN;
169*0Sstevel@tonic-gate 			}
170*0Sstevel@tonic-gate 		}
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate static int
175*0Sstevel@tonic-gate stripe_open_all_devs(ms_unit_t *un, int md_oflags)
176*0Sstevel@tonic-gate {
177*0Sstevel@tonic-gate 	minor_t		mnum = MD_SID(un);
178*0Sstevel@tonic-gate 	int		row;
179*0Sstevel@tonic-gate 	int		i;
180*0Sstevel@tonic-gate 	int		c;
181*0Sstevel@tonic-gate 	struct ms_comp	*mdcomp;
182*0Sstevel@tonic-gate 	int		err;
183*0Sstevel@tonic-gate 	int		cont_on_errors = (md_oflags & MD_OFLG_CONT_ERRS);
184*0Sstevel@tonic-gate 	int		probe_err_cnt = 0;
185*0Sstevel@tonic-gate 	int		total_comp_cnt = 0;
186*0Sstevel@tonic-gate 	set_t		setno = MD_MIN2SET(MD_SID(un));
187*0Sstevel@tonic-gate 	side_t		side = mddb_getsidenum(setno);
188*0Sstevel@tonic-gate 	mdkey_t		key;
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	/*
193*0Sstevel@tonic-gate 	 * For a probe call, if any component of a stripe or a concat
194*0Sstevel@tonic-gate 	 * can be opened, it is considered to be a success. The total number
195*0Sstevel@tonic-gate 	 * of components in a stripe are computed prior to starting a probe.
196*0Sstevel@tonic-gate 	 * This number is then compared against the number of components
197*0Sstevel@tonic-gate 	 * that could be be successfully opened. If none of the components
198*0Sstevel@tonic-gate 	 * in a stripe can be opened, only then an ENXIO is returned for a
199*0Sstevel@tonic-gate 	 * probe type open.
200*0Sstevel@tonic-gate 	 */
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
203*0Sstevel@tonic-gate 		struct ms_row *mdr = &un->un_row[row];
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 		if (md_oflags & MD_OFLG_PROBEDEV)
206*0Sstevel@tonic-gate 			total_comp_cnt += mdr->un_ncomp;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 		for (i = 0, c = mdr->un_icomp; i < mdr->un_ncomp; i++) {
209*0Sstevel@tonic-gate 			struct ms_comp	*mdc;
210*0Sstevel@tonic-gate 			md_dev64_t tmpdev;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 			mdc = &mdcomp[c++];
213*0Sstevel@tonic-gate 			tmpdev = mdc->un_dev;
214*0Sstevel@tonic-gate 			/*
215*0Sstevel@tonic-gate 			 * Do the open by device id
216*0Sstevel@tonic-gate 			 * Check if this comp is hotspared and
217*0Sstevel@tonic-gate 			 * if it is then use the key for hotspare.
218*0Sstevel@tonic-gate 			 * MN disksets don't use devids, so we better don't use
219*0Sstevel@tonic-gate 			 * md_devid_found/md_resolve_bydevid there. Rather do,
220*0Sstevel@tonic-gate 			 * what's done in stripe_build_incore()
221*0Sstevel@tonic-gate 			 */
222*0Sstevel@tonic-gate 			if (MD_MNSET_SETNO(setno)) {
223*0Sstevel@tonic-gate 				if (mdc->un_mirror.ms_hs_id != 0) {
224*0Sstevel@tonic-gate 					(void) md_hot_spare_ifc(HS_MKDEV, 0, 0,
225*0Sstevel@tonic-gate 					    0, &mdc->un_mirror.ms_hs_id, NULL,
226*0Sstevel@tonic-gate 					    &tmpdev, NULL);
227*0Sstevel@tonic-gate 				}
228*0Sstevel@tonic-gate 			} else {
229*0Sstevel@tonic-gate 				key = mdc->un_mirror.ms_hs_id ?
230*0Sstevel@tonic-gate 				    mdc->un_mirror.ms_hs_key : mdc->un_key;
231*0Sstevel@tonic-gate 				if ((md_getmajor(tmpdev) != md_major) &&
232*0Sstevel@tonic-gate 				    md_devid_found(setno, side, key) == 1) {
233*0Sstevel@tonic-gate 					tmpdev = md_resolve_bydevid(mnum,
234*0Sstevel@tonic-gate 					    tmpdev, key);
235*0Sstevel@tonic-gate 				}
236*0Sstevel@tonic-gate 			}
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 			/*
239*0Sstevel@tonic-gate 			 * For a submirror, we only want to open those devices
240*0Sstevel@tonic-gate 			 * that are not errored. If the device is errored then
241*0Sstevel@tonic-gate 			 * then there is no reason to open it and leaving it
242*0Sstevel@tonic-gate 			 * closed allows the RCM/DR code to work so that the
243*0Sstevel@tonic-gate 			 * errored device can be replaced.
244*0Sstevel@tonic-gate 			 */
245*0Sstevel@tonic-gate 			if ((md_oflags & MD_OFLG_PROBEDEV) ||
246*0Sstevel@tonic-gate 			    ! (mdc->un_mirror.ms_state & CS_ERRED)) {
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 				err = md_layered_open(mnum, &tmpdev, md_oflags);
249*0Sstevel@tonic-gate 			} else {
250*0Sstevel@tonic-gate 				err = ENXIO;
251*0Sstevel@tonic-gate 			}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 			/*
254*0Sstevel@tonic-gate 			 * Only set the un_dev if the tmpdev != NODEV64. If
255*0Sstevel@tonic-gate 			 * it is NODEV64 then the md_layered_open() will have
256*0Sstevel@tonic-gate 			 * failed in some manner.
257*0Sstevel@tonic-gate 			 */
258*0Sstevel@tonic-gate 			if (tmpdev != NODEV64)
259*0Sstevel@tonic-gate 				mdc->un_dev = tmpdev;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 			if (err) {
262*0Sstevel@tonic-gate 				if (!cont_on_errors) {
263*0Sstevel@tonic-gate 					stripe_close_all_devs(un, md_oflags);
264*0Sstevel@tonic-gate 					return (ENXIO);
265*0Sstevel@tonic-gate 				}
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 				if (md_oflags & MD_OFLG_PROBEDEV)
268*0Sstevel@tonic-gate 					probe_err_cnt++;
269*0Sstevel@tonic-gate 			} else {
270*0Sstevel@tonic-gate 				if (md_oflags & MD_OFLG_PROBEDEV) {
271*0Sstevel@tonic-gate 					mdc->un_mirror.ms_flags |=
272*0Sstevel@tonic-gate 						MDM_S_PROBEOPEN;
273*0Sstevel@tonic-gate 				} else
274*0Sstevel@tonic-gate 					mdc->un_mirror.ms_flags |= MDM_S_ISOPEN;
275*0Sstevel@tonic-gate 			}
276*0Sstevel@tonic-gate 		}
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	/* If every component in a stripe could not be opened fail */
280*0Sstevel@tonic-gate 	if ((md_oflags & MD_OFLG_PROBEDEV) &&
281*0Sstevel@tonic-gate 	    (probe_err_cnt == total_comp_cnt))
282*0Sstevel@tonic-gate 		return (ENXIO);
283*0Sstevel@tonic-gate 	else
284*0Sstevel@tonic-gate 		return (0);
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate int
288*0Sstevel@tonic-gate stripe_build_incore(void *p, int snarfing)
289*0Sstevel@tonic-gate {
290*0Sstevel@tonic-gate 	ms_unit_t *un = (ms_unit_t *)p;
291*0Sstevel@tonic-gate 	struct ms_comp	*mdcomp;
292*0Sstevel@tonic-gate 	minor_t		mnum;
293*0Sstevel@tonic-gate 	int		row;
294*0Sstevel@tonic-gate 	int		i;
295*0Sstevel@tonic-gate 	int		c;
296*0Sstevel@tonic-gate 	int		ncomps;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	mnum = MD_SID(un);
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	if (MD_UNIT(mnum) != NULL)
301*0Sstevel@tonic-gate 		return (0);
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	MD_STATUS(un) = 0;
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	/*
306*0Sstevel@tonic-gate 	 * Reset all the is_open flags, these are probably set
307*0Sstevel@tonic-gate 	 * cause they just came out of the database.
308*0Sstevel@tonic-gate 	 */
309*0Sstevel@tonic-gate 	mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	ncomps = 0;
312*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
313*0Sstevel@tonic-gate 		struct ms_row *mdr = &un->un_row[row];
314*0Sstevel@tonic-gate 		ncomps += mdr->un_ncomp;
315*0Sstevel@tonic-gate 	}
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
318*0Sstevel@tonic-gate 		struct ms_row *mdr = &un->un_row[row];
319*0Sstevel@tonic-gate 		for (i = 0, c = mdr->un_icomp; i < mdr->un_ncomp; i++) {
320*0Sstevel@tonic-gate 			struct ms_comp		*mdc;
321*0Sstevel@tonic-gate 			set_t			setno;
322*0Sstevel@tonic-gate 			md_dev64_t		tmpdev;
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 			mdc = &mdcomp[c++];
325*0Sstevel@tonic-gate 			mdc->un_mirror.ms_flags &=
326*0Sstevel@tonic-gate 			    ~(MDM_S_ISOPEN | MDM_S_IOERR | MDM_S_RS_TRIED);
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 			if (!snarfing)
329*0Sstevel@tonic-gate 				continue;
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 			setno = MD_MIN2SET(mnum);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 			tmpdev = md_getdevnum(setno, mddb_getsidenum(setno),
334*0Sstevel@tonic-gate 			    mdc->un_key, MD_NOTRUST_DEVT);
335*0Sstevel@tonic-gate 			mdc->un_dev = tmpdev;
336*0Sstevel@tonic-gate 			/*
337*0Sstevel@tonic-gate 			 * Check for hotspares. If the hotspares haven't been
338*0Sstevel@tonic-gate 			 * snarfed yet, stripe_open_all_devs() will do the
339*0Sstevel@tonic-gate 			 * remapping of the dev's later.
340*0Sstevel@tonic-gate 			 */
341*0Sstevel@tonic-gate 			if (mdc->un_mirror.ms_hs_id != 0) {
342*0Sstevel@tonic-gate 				mdc->un_mirror.ms_orig_dev = mdc->un_dev;
343*0Sstevel@tonic-gate 				(void) md_hot_spare_ifc(HS_MKDEV, 0, 0,
344*0Sstevel@tonic-gate 				    0, &mdc->un_mirror.ms_hs_id, NULL,
345*0Sstevel@tonic-gate 				    &tmpdev, NULL);
346*0Sstevel@tonic-gate 				mdc->un_dev = tmpdev;
347*0Sstevel@tonic-gate 			}
348*0Sstevel@tonic-gate 		}
349*0Sstevel@tonic-gate 	}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	MD_UNIT(mnum) = un;
352*0Sstevel@tonic-gate 	return (0);
353*0Sstevel@tonic-gate }
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate void
356*0Sstevel@tonic-gate reset_stripe(ms_unit_t *un, minor_t mnum, int removing)
357*0Sstevel@tonic-gate {
358*0Sstevel@tonic-gate 	ms_comp_t	*mdcomp;
359*0Sstevel@tonic-gate 	struct ms_row	*mdr;
360*0Sstevel@tonic-gate 	int		i, c;
361*0Sstevel@tonic-gate 	int		row;
362*0Sstevel@tonic-gate 	int		nsv;
363*0Sstevel@tonic-gate 	int		isv;
364*0Sstevel@tonic-gate 	sv_dev_t	*sv;
365*0Sstevel@tonic-gate 	mddb_recid_t	*recids;
366*0Sstevel@tonic-gate 	mddb_recid_t	vtoc_id;
367*0Sstevel@tonic-gate 	int		rid = 0;
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	md_destroy_unit_incore(mnum, &stripe_md_ops);
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	MD_UNIT(mnum) = NULL;
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	if (!removing)
374*0Sstevel@tonic-gate 		return;
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	nsv = 0;
377*0Sstevel@tonic-gate 	/* Count the number of devices */
378*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
379*0Sstevel@tonic-gate 		mdr = &un->un_row[row];
380*0Sstevel@tonic-gate 		nsv += mdr->un_ncomp;
381*0Sstevel@tonic-gate 	}
382*0Sstevel@tonic-gate 	sv = (sv_dev_t *)kmem_alloc(sizeof (sv_dev_t) * nsv, KM_SLEEP);
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	/*
385*0Sstevel@tonic-gate 	 * allocate recids array.  since we may have to commit
386*0Sstevel@tonic-gate 	 * underlying soft partition records, we need an array
387*0Sstevel@tonic-gate 	 * of size: total number of components in stripe + 3
388*0Sstevel@tonic-gate 	 * (one for the stripe itself, one for the hotspare, one
389*0Sstevel@tonic-gate 	 * for the end marker).
390*0Sstevel@tonic-gate 	 */
391*0Sstevel@tonic-gate 	recids = kmem_alloc(sizeof (mddb_recid_t) * (nsv + 3), KM_SLEEP);
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	/*
394*0Sstevel@tonic-gate 	 * Save the md_dev64_t's and driver nm indexes.
395*0Sstevel@tonic-gate 	 * Because after the mddb_deleterec() we will
396*0Sstevel@tonic-gate 	 * not be able to access the unit structure.
397*0Sstevel@tonic-gate 	 *
398*0Sstevel@tonic-gate 	 * NOTE: Deleting the names before deleting the
399*0Sstevel@tonic-gate 	 *	 unit structure would cause problems if
400*0Sstevel@tonic-gate 	 *	 the machine crashed in between the two.
401*0Sstevel@tonic-gate 	 */
402*0Sstevel@tonic-gate 	isv = 0;
403*0Sstevel@tonic-gate 	mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
406*0Sstevel@tonic-gate 		mdr = &un->un_row[row];
407*0Sstevel@tonic-gate 		for (i = 0, c = mdr->un_icomp; i < mdr->un_ncomp; i++) {
408*0Sstevel@tonic-gate 			struct ms_comp	*mdc;
409*0Sstevel@tonic-gate 			md_dev64_t	child_dev;
410*0Sstevel@tonic-gate 			md_unit_t	*child_un;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 			mdc = &mdcomp[c++];
413*0Sstevel@tonic-gate 			if (mdc->un_mirror.ms_hs_id != 0) {
414*0Sstevel@tonic-gate 				mdkey_t		hs_key;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 				hs_key = mdc->un_mirror.ms_hs_key;
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 				mdc->un_dev = mdc->un_mirror.ms_orig_dev;
419*0Sstevel@tonic-gate 				mdc->un_start_block =
420*0Sstevel@tonic-gate 				    mdc->un_mirror.ms_orig_blk;
421*0Sstevel@tonic-gate 				mdc->un_mirror.ms_hs_id = 0;
422*0Sstevel@tonic-gate 				mdc->un_mirror.ms_hs_key = 0;
423*0Sstevel@tonic-gate 				mdc->un_mirror.ms_orig_dev = 0;
424*0Sstevel@tonic-gate 				recids[0] = 0;
425*0Sstevel@tonic-gate 				recids[1] = 0;	/* recids[1] filled in below */
426*0Sstevel@tonic-gate 				recids[2] = 0;
427*0Sstevel@tonic-gate 				(void) md_hot_spare_ifc(HS_FREE, un->un_hsp_id,
428*0Sstevel@tonic-gate 				    0, 0, &recids[0], &hs_key, NULL, NULL);
429*0Sstevel@tonic-gate 				mddb_commitrecs_wrapper(recids);
430*0Sstevel@tonic-gate 			}
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 			/*
433*0Sstevel@tonic-gate 			 * check if we've got metadevice below us and
434*0Sstevel@tonic-gate 			 * deparent it if we do.
435*0Sstevel@tonic-gate 			 * NOTE: currently soft partitions are the
436*0Sstevel@tonic-gate 			 * the only metadevices stripes can be
437*0Sstevel@tonic-gate 			 * built on top of.
438*0Sstevel@tonic-gate 			 */
439*0Sstevel@tonic-gate 			child_dev = mdc->un_dev;
440*0Sstevel@tonic-gate 			if (md_getmajor(child_dev) == md_major) {
441*0Sstevel@tonic-gate 				child_un = MD_UNIT(md_getminor(child_dev));
442*0Sstevel@tonic-gate 				md_reset_parent(child_dev);
443*0Sstevel@tonic-gate 				recids[rid++] = MD_RECID(child_un);
444*0Sstevel@tonic-gate 			}
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 			sv[isv].setno = MD_MIN2SET(mnum);
447*0Sstevel@tonic-gate 			sv[isv++].key = mdc->un_key;
448*0Sstevel@tonic-gate 		}
449*0Sstevel@tonic-gate 	}
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	recids[rid++] = un->c.un_record_id;
452*0Sstevel@tonic-gate 	recids[rid] = 0;	/* filled in below */
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	/*
455*0Sstevel@tonic-gate 	 * Decrement the HSP reference count and
456*0Sstevel@tonic-gate 	 * remove the knowledge of the HSP from the unit struct.
457*0Sstevel@tonic-gate 	 * This is done atomically to remove a window.
458*0Sstevel@tonic-gate 	 */
459*0Sstevel@tonic-gate 	if (un->un_hsp_id != -1) {
460*0Sstevel@tonic-gate 		(void) md_hot_spare_ifc(HSP_DECREF, un->un_hsp_id, 0, 0,
461*0Sstevel@tonic-gate 		    &recids[rid++], NULL, NULL, NULL);
462*0Sstevel@tonic-gate 		un->un_hsp_id = -1;
463*0Sstevel@tonic-gate 	}
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	/* set end marker and commit records */
466*0Sstevel@tonic-gate 	recids[rid] = 0;
467*0Sstevel@tonic-gate 	mddb_commitrecs_wrapper(recids);
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	vtoc_id = un->c.un_vtoc_id;
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	/* Remove the unit structure */
472*0Sstevel@tonic-gate 	mddb_deleterec_wrapper(un->c.un_record_id);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	/* Remove the vtoc, if present */
475*0Sstevel@tonic-gate 	if (vtoc_id)
476*0Sstevel@tonic-gate 		mddb_deleterec_wrapper(vtoc_id);
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_DELETE, SVM_TAG_METADEVICE,
479*0Sstevel@tonic-gate 	    MD_MIN2SET(mnum), MD_MIN2UNIT(mnum));
480*0Sstevel@tonic-gate 	md_rem_names(sv, nsv);
481*0Sstevel@tonic-gate 	kmem_free(sv, sizeof (sv_dev_t) * nsv);
482*0Sstevel@tonic-gate 	kmem_free(recids, sizeof (mddb_recid_t) * (nsv + 3));
483*0Sstevel@tonic-gate }
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate static void
486*0Sstevel@tonic-gate stripe_error(md_sps_t *ps)
487*0Sstevel@tonic-gate {
488*0Sstevel@tonic-gate 	struct buf	*pb = ps->ps_bp;
489*0Sstevel@tonic-gate 	mdi_unit_t	*ui = ps->ps_ui;
490*0Sstevel@tonic-gate 	md_dev64_t	dev = ps->ps_errcomp->un_dev;
491*0Sstevel@tonic-gate 	md_dev64_t	md_dev = md_expldev(pb->b_edev);
492*0Sstevel@tonic-gate 	char		*str;
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	if (pb->b_flags & B_READ) {
495*0Sstevel@tonic-gate 		ps->ps_errcomp->un_mirror.ms_flags |= MDM_S_READERR;
496*0Sstevel@tonic-gate 		str = "read";
497*0Sstevel@tonic-gate 	} else {
498*0Sstevel@tonic-gate 		ps->ps_errcomp->un_mirror.ms_flags |= MDM_S_WRTERR;
499*0Sstevel@tonic-gate 		str = "write";
500*0Sstevel@tonic-gate 	}
501*0Sstevel@tonic-gate 	if (!(ps->ps_flags & MD_SPS_DONTFREE)) {
502*0Sstevel@tonic-gate 		if (MUTEX_HELD(&ps->ps_mx)) {
503*0Sstevel@tonic-gate 			mutex_exit(&ps->ps_mx);
504*0Sstevel@tonic-gate 		}
505*0Sstevel@tonic-gate 	} else {
506*0Sstevel@tonic-gate 		ASSERT(panicstr);
507*0Sstevel@tonic-gate 	}
508*0Sstevel@tonic-gate 	SPS_FREE(stripe_parent_cache, ps);
509*0Sstevel@tonic-gate 	pb->b_flags |= B_ERROR;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	md_kstat_done(ui, pb, 0);
512*0Sstevel@tonic-gate 	md_unit_readerexit(ui);
513*0Sstevel@tonic-gate 	md_biodone(pb);
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	cmn_err(CE_WARN, "md: %s: %s error on %s",
516*0Sstevel@tonic-gate 	    md_shortname(md_getminor(md_dev)), str,
517*0Sstevel@tonic-gate 	    md_devname(MD_DEV2SET(md_dev), dev, NULL, 0));
518*0Sstevel@tonic-gate }
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate static int
521*0Sstevel@tonic-gate stripe_done(struct buf *cb)
522*0Sstevel@tonic-gate {
523*0Sstevel@tonic-gate 	struct buf	*pb;
524*0Sstevel@tonic-gate 	mdi_unit_t	*ui;
525*0Sstevel@tonic-gate 	md_sps_t	*ps;
526*0Sstevel@tonic-gate 	md_scs_t	*cs;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	/*LINTED*/
529*0Sstevel@tonic-gate 	cs = (md_scs_t *)((caddr_t)cb - md_stripe_mcs_buf_off);
530*0Sstevel@tonic-gate 	ps = cs->cs_ps;
531*0Sstevel@tonic-gate 	pb = ps->ps_bp;
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	mutex_enter(&ps->ps_mx);
534*0Sstevel@tonic-gate 	if (cb->b_flags & B_ERROR) {
535*0Sstevel@tonic-gate 		ps->ps_flags |= MD_SPS_ERROR;
536*0Sstevel@tonic-gate 		pb->b_error = cb->b_error;
537*0Sstevel@tonic-gate 		ps->ps_errcomp = cs->cs_comp;
538*0Sstevel@tonic-gate 	}
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	if (cb->b_flags & B_REMAPPED)
541*0Sstevel@tonic-gate 		bp_mapout(cb);
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 	ps->ps_frags--;
544*0Sstevel@tonic-gate 	if (ps->ps_frags != 0) {
545*0Sstevel@tonic-gate 		mutex_exit(&ps->ps_mx);
546*0Sstevel@tonic-gate 		kmem_cache_free(stripe_child_cache, cs);
547*0Sstevel@tonic-gate 		return (1);
548*0Sstevel@tonic-gate 	}
549*0Sstevel@tonic-gate 	kmem_cache_free(stripe_child_cache, cs);
550*0Sstevel@tonic-gate 	if (ps->ps_flags & MD_SPS_ERROR) {
551*0Sstevel@tonic-gate 		stripe_error(ps);
552*0Sstevel@tonic-gate 		return (1);
553*0Sstevel@tonic-gate 	}
554*0Sstevel@tonic-gate 	ui = ps->ps_ui;
555*0Sstevel@tonic-gate 	if (!(ps->ps_flags & MD_SPS_DONTFREE)) {
556*0Sstevel@tonic-gate 		mutex_exit(&ps->ps_mx);
557*0Sstevel@tonic-gate 	} else {
558*0Sstevel@tonic-gate 		ASSERT(panicstr);
559*0Sstevel@tonic-gate 	}
560*0Sstevel@tonic-gate 	SPS_FREE(stripe_parent_cache, ps);
561*0Sstevel@tonic-gate 	md_kstat_done(ui, pb, 0);
562*0Sstevel@tonic-gate 	md_unit_readerexit(ui);
563*0Sstevel@tonic-gate 	md_biodone(pb);
564*0Sstevel@tonic-gate 	return (0);
565*0Sstevel@tonic-gate }
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate /*
569*0Sstevel@tonic-gate  * This routine does the mapping from virtual (dev, blkno) of a metapartition
570*0Sstevel@tonic-gate  * to the real (dev, blkno) of a real disk partition.
571*0Sstevel@tonic-gate  * It goes to the md_conf[] table to find out the correct real partition
572*0Sstevel@tonic-gate  * dev and block number for this buffer.
573*0Sstevel@tonic-gate  *
574*0Sstevel@tonic-gate  * A single buf request can not go across real disk partition boundary.
575*0Sstevel@tonic-gate  * When the virtual request specified by (dev, blkno) spans more than one
576*0Sstevel@tonic-gate  * real partition, md_mapbuf will return 1. Then the caller should prepare
577*0Sstevel@tonic-gate  * another real buf and continue calling md_mapbuf to do the mapping until
578*0Sstevel@tonic-gate  * it returns 0.
579*0Sstevel@tonic-gate  *
580*0Sstevel@tonic-gate  */
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate static int
583*0Sstevel@tonic-gate md_mapbuf(
584*0Sstevel@tonic-gate 	ms_unit_t	*un,
585*0Sstevel@tonic-gate 	diskaddr_t	blkno,
586*0Sstevel@tonic-gate 	u_longlong_t	bcount,
587*0Sstevel@tonic-gate 	buf_t		*bp,	/* if bp==NULL, skip bp updates */
588*0Sstevel@tonic-gate 	ms_comp_t	**mdc)	/* if bp==NULL, skip mdc update */
589*0Sstevel@tonic-gate {
590*0Sstevel@tonic-gate 	struct ms_row	*mdr;
591*0Sstevel@tonic-gate 	struct ms_comp	*mdcomp;
592*0Sstevel@tonic-gate 	diskaddr_t	stripe_blk;
593*0Sstevel@tonic-gate 	diskaddr_t	fragment, blk_in_row, endblk;
594*0Sstevel@tonic-gate 	offset_t	interlace;
595*0Sstevel@tonic-gate 	size_t		dev_index;
596*0Sstevel@tonic-gate 	int		row_index, more;
597*0Sstevel@tonic-gate 	extern unsigned md_maxphys;
598*0Sstevel@tonic-gate 	/* Work var's when bp==NULL */
599*0Sstevel@tonic-gate 	u_longlong_t	wb_bcount;
600*0Sstevel@tonic-gate 	diskaddr_t	wb_blkno;
601*0Sstevel@tonic-gate 	md_dev64_t	wb_edev;
602*0Sstevel@tonic-gate 	ms_comp_t	*wmdc;
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	/*
605*0Sstevel@tonic-gate 	 * Do a real calculation to derive the minor device of the
606*0Sstevel@tonic-gate 	 * Virtual Disk, which in turn will let us derive the
607*0Sstevel@tonic-gate 	 * device/minor of the underlying real device.
608*0Sstevel@tonic-gate 	 */
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	for (row_index = 0; row_index < un->un_nrows; row_index++) {
612*0Sstevel@tonic-gate 		mdr = &un->un_row[row_index];
613*0Sstevel@tonic-gate 		if (blkno < mdr->un_cum_blocks)
614*0Sstevel@tonic-gate 			break;
615*0Sstevel@tonic-gate 	}
616*0Sstevel@tonic-gate 	ASSERT(row_index != un->un_nrows);
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	mdcomp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	blk_in_row = blkno - mdr->un_cum_blocks + mdr->un_blocks;
621*0Sstevel@tonic-gate 	endblk = (diskaddr_t)(blkno + howmany(bcount, DEV_BSIZE));
622*0Sstevel@tonic-gate 	if (mdr->un_ncomp == 1) { /* No striping */
623*0Sstevel@tonic-gate 		if (endblk > mdr->un_cum_blocks) {
624*0Sstevel@tonic-gate 			wb_bcount = ldbtob(mdr->un_cum_blocks - blkno);
625*0Sstevel@tonic-gate 			if ((row_index + 1) == un->un_nrows)
626*0Sstevel@tonic-gate 				more = 0;
627*0Sstevel@tonic-gate 			else
628*0Sstevel@tonic-gate 				more = 1;
629*0Sstevel@tonic-gate 		} else {
630*0Sstevel@tonic-gate 			wb_bcount = bcount;
631*0Sstevel@tonic-gate 			more = 0;
632*0Sstevel@tonic-gate 		}
633*0Sstevel@tonic-gate 		wmdc = &mdcomp[mdr->un_icomp];
634*0Sstevel@tonic-gate 		wb_blkno = blk_in_row;
635*0Sstevel@tonic-gate 	} else { /* Have striping */
636*0Sstevel@tonic-gate 		interlace = mdr->un_interlace;
637*0Sstevel@tonic-gate 		fragment = blk_in_row % interlace;
638*0Sstevel@tonic-gate 		if (bcount > ldbtob(interlace - fragment)) {
639*0Sstevel@tonic-gate 			more = 1;
640*0Sstevel@tonic-gate 			wb_bcount = ldbtob(interlace - fragment);
641*0Sstevel@tonic-gate 		} else {
642*0Sstevel@tonic-gate 			more = 0;
643*0Sstevel@tonic-gate 			wb_bcount = bcount;
644*0Sstevel@tonic-gate 		}
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 		stripe_blk = blk_in_row / interlace;
647*0Sstevel@tonic-gate 		dev_index = (size_t)(stripe_blk % mdr->un_ncomp);
648*0Sstevel@tonic-gate 		wmdc = &mdcomp[mdr->un_icomp + dev_index];
649*0Sstevel@tonic-gate 		wb_blkno = (diskaddr_t)(((stripe_blk / mdr->un_ncomp)
650*0Sstevel@tonic-gate 			* interlace) + fragment);
651*0Sstevel@tonic-gate 	}
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	wb_blkno += wmdc->un_start_block;
654*0Sstevel@tonic-gate 	wb_edev = wmdc->un_dev;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	/* only break up the I/O if we're not built on another metadevice */
657*0Sstevel@tonic-gate 	if ((md_getmajor(wb_edev) != md_major) && (wb_bcount > md_maxphys)) {
658*0Sstevel@tonic-gate 		wb_bcount = md_maxphys;
659*0Sstevel@tonic-gate 		more = 1;
660*0Sstevel@tonic-gate 	}
661*0Sstevel@tonic-gate 	if (bp != (buf_t *)NULL) {
662*0Sstevel@tonic-gate 		/*
663*0Sstevel@tonic-gate 		 * wb_bcount is limited by md_maxphys which is 'int'
664*0Sstevel@tonic-gate 		 */
665*0Sstevel@tonic-gate 		bp->b_bcount = (size_t)wb_bcount;
666*0Sstevel@tonic-gate 		bp->b_lblkno = wb_blkno;
667*0Sstevel@tonic-gate 		bp->b_edev = md_dev64_to_dev(wb_edev);
668*0Sstevel@tonic-gate 		*mdc = wmdc;
669*0Sstevel@tonic-gate 	}
670*0Sstevel@tonic-gate 	return (more);
671*0Sstevel@tonic-gate }
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate static void
674*0Sstevel@tonic-gate md_stripe_strategy(buf_t *pb, int flag, void *private)
675*0Sstevel@tonic-gate {
676*0Sstevel@tonic-gate 	md_sps_t	*ps;
677*0Sstevel@tonic-gate 	md_scs_t	*cs;
678*0Sstevel@tonic-gate 	int		doing_writes;
679*0Sstevel@tonic-gate 	int		more;
680*0Sstevel@tonic-gate 	ms_unit_t	*un;
681*0Sstevel@tonic-gate 	mdi_unit_t	*ui;
682*0Sstevel@tonic-gate 	size_t		current_count;
683*0Sstevel@tonic-gate 	diskaddr_t	current_blkno;
684*0Sstevel@tonic-gate 	off_t		current_offset;
685*0Sstevel@tonic-gate 	buf_t		*cb;		/* child buf pointer */
686*0Sstevel@tonic-gate 	set_t		setno;
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 	setno = MD_MIN2SET(getminor(pb->b_edev));
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 	/*
691*0Sstevel@tonic-gate 	 * When doing IO to a multi owner meta device, check if set is halted.
692*0Sstevel@tonic-gate 	 * We do this check without the needed lock held, for performance
693*0Sstevel@tonic-gate 	 * reasons.
694*0Sstevel@tonic-gate 	 * If an IO just slips through while the set is locked via an
695*0Sstevel@tonic-gate 	 * MD_MN_SUSPEND_SET, we don't care about it.
696*0Sstevel@tonic-gate 	 * Only check for a suspended set if we are a top-level i/o request
697*0Sstevel@tonic-gate 	 * (MD_STR_NOTTOP is cleared in 'flag').
698*0Sstevel@tonic-gate 	 */
699*0Sstevel@tonic-gate 	if ((md_set[setno].s_status & (MD_SET_HALTED | MD_SET_MNSET)) ==
700*0Sstevel@tonic-gate 	    (MD_SET_HALTED | MD_SET_MNSET)) {
701*0Sstevel@tonic-gate 		if ((flag & MD_STR_NOTTOP) == 0) {
702*0Sstevel@tonic-gate 			mutex_enter(&md_mx);
703*0Sstevel@tonic-gate 			/* Here we loop until the set is no longer halted */
704*0Sstevel@tonic-gate 			while (md_set[setno].s_status & MD_SET_HALTED) {
705*0Sstevel@tonic-gate 				cv_wait(&md_cv, &md_mx);
706*0Sstevel@tonic-gate 			}
707*0Sstevel@tonic-gate 			mutex_exit(&md_mx);
708*0Sstevel@tonic-gate 		}
709*0Sstevel@tonic-gate 	}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	ui = MDI_UNIT(getminor(pb->b_edev));
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	md_kstat_waitq_enter(ui);
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	un = (ms_unit_t *)md_unit_readerlock(ui);
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	if ((flag & MD_NOBLOCK) == 0) {
718*0Sstevel@tonic-gate 		if (md_inc_iocount(setno) != 0) {
719*0Sstevel@tonic-gate 			pb->b_flags |= B_ERROR;
720*0Sstevel@tonic-gate 			pb->b_error = ENXIO;
721*0Sstevel@tonic-gate 			pb->b_resid = pb->b_bcount;
722*0Sstevel@tonic-gate 			md_unit_readerexit(ui);
723*0Sstevel@tonic-gate 			biodone(pb);
724*0Sstevel@tonic-gate 			return;
725*0Sstevel@tonic-gate 		}
726*0Sstevel@tonic-gate 	} else {
727*0Sstevel@tonic-gate 		md_inc_iocount_noblock(setno);
728*0Sstevel@tonic-gate 	}
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	if (!(flag & MD_STR_NOTTOP)) {
731*0Sstevel@tonic-gate 		if (md_checkbuf(ui, (md_unit_t *)un, pb) != 0) {
732*0Sstevel@tonic-gate 			md_kstat_waitq_exit(ui);
733*0Sstevel@tonic-gate 			return;
734*0Sstevel@tonic-gate 		}
735*0Sstevel@tonic-gate 	}
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	ps = kmem_cache_alloc(stripe_parent_cache, MD_ALLOCFLAGS);
738*0Sstevel@tonic-gate 	stripe_parent_init(ps);
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	/*
741*0Sstevel@tonic-gate 	 * Save essential information from the original buffhdr
742*0Sstevel@tonic-gate 	 * in the md_save structure.
743*0Sstevel@tonic-gate 	 */
744*0Sstevel@tonic-gate 	ps->ps_un = un;
745*0Sstevel@tonic-gate 	ps->ps_ui = ui;
746*0Sstevel@tonic-gate 	ps->ps_bp = pb;
747*0Sstevel@tonic-gate 	ps->ps_addr = pb->b_un.b_addr;
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	if ((pb->b_flags & B_READ) == 0)
750*0Sstevel@tonic-gate 		doing_writes = 1;
751*0Sstevel@tonic-gate 	else
752*0Sstevel@tonic-gate 		doing_writes = 0;
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	current_count = pb->b_bcount;
756*0Sstevel@tonic-gate 	current_blkno = pb->b_lblkno;
757*0Sstevel@tonic-gate 	current_offset  = 0;
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate 	if (!(flag & MD_STR_NOTTOP) && panicstr)
760*0Sstevel@tonic-gate 		ps->ps_flags |= MD_SPS_DONTFREE;
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate 	md_kstat_waitq_to_runq(ui);
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	ps->ps_frags++;
765*0Sstevel@tonic-gate 	do {
766*0Sstevel@tonic-gate 		cs = kmem_cache_alloc(stripe_child_cache, MD_ALLOCFLAGS);
767*0Sstevel@tonic-gate 		stripe_child_init(cs);
768*0Sstevel@tonic-gate 		cb = &cs->cs_buf;
769*0Sstevel@tonic-gate 		cs->cs_ps = ps;
770*0Sstevel@tonic-gate 		more = md_mapbuf(un, current_blkno, current_count, cb,
771*0Sstevel@tonic-gate 			&cs->cs_comp);
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 		cb = md_bioclone(pb, current_offset, cb->b_bcount, cb->b_edev,
774*0Sstevel@tonic-gate 				cb->b_lblkno, stripe_done, cb, KM_NOSLEEP);
775*0Sstevel@tonic-gate 		/*
776*0Sstevel@tonic-gate 		 * Do these calculations now,
777*0Sstevel@tonic-gate 		 *  so that we pickup a valid b_bcount from the chld_bp.
778*0Sstevel@tonic-gate 		 */
779*0Sstevel@tonic-gate 		current_offset += cb->b_bcount;
780*0Sstevel@tonic-gate 		current_count -=  cb->b_bcount;
781*0Sstevel@tonic-gate 		current_blkno +=  (diskaddr_t)(lbtodb(cb->b_bcount));
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 		if (more) {
784*0Sstevel@tonic-gate 			mutex_enter(&ps->ps_mx);
785*0Sstevel@tonic-gate 			ps->ps_frags++;
786*0Sstevel@tonic-gate 			mutex_exit(&ps->ps_mx);
787*0Sstevel@tonic-gate 		}
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 		if (doing_writes &&
790*0Sstevel@tonic-gate 		    cs->cs_comp->un_mirror.ms_flags & MDM_S_NOWRITE) {
791*0Sstevel@tonic-gate 			(void) stripe_done(cb);
792*0Sstevel@tonic-gate 			continue;
793*0Sstevel@tonic-gate 		}
794*0Sstevel@tonic-gate 		md_call_strategy(cb, flag, private);
795*0Sstevel@tonic-gate 	} while (more);
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	if (!(flag & MD_STR_NOTTOP) && panicstr) {
798*0Sstevel@tonic-gate 		while (!(ps->ps_flags & MD_SPS_DONE)) {
799*0Sstevel@tonic-gate 			md_daemon(1, &md_done_daemon);
800*0Sstevel@tonic-gate 			drv_usecwait(10);
801*0Sstevel@tonic-gate 		}
802*0Sstevel@tonic-gate 		kmem_cache_free(stripe_parent_cache, ps);
803*0Sstevel@tonic-gate 	}
804*0Sstevel@tonic-gate }
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate static int
807*0Sstevel@tonic-gate stripe_snarf(md_snarfcmd_t cmd, set_t setno)
808*0Sstevel@tonic-gate {
809*0Sstevel@tonic-gate 	ms_unit_t	*un;
810*0Sstevel@tonic-gate 	mddb_recid_t	recid;
811*0Sstevel@tonic-gate 	int		gotsomething;
812*0Sstevel@tonic-gate 	int		all_stripes_gotten;
813*0Sstevel@tonic-gate 	mddb_type_t	typ1;
814*0Sstevel@tonic-gate 	mddb_de_ic_t	*dep;
815*0Sstevel@tonic-gate 	mddb_rb32_t	*rbp;
816*0Sstevel@tonic-gate 	size_t		newreqsize;
817*0Sstevel@tonic-gate 	ms_unit_t	*big_un;
818*0Sstevel@tonic-gate 	ms_unit32_od_t	*small_un;
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	if (cmd == MD_SNARF_CLEANUP)
822*0Sstevel@tonic-gate 		return (0);
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	all_stripes_gotten = 1;
825*0Sstevel@tonic-gate 	gotsomething = 0;
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
828*0Sstevel@tonic-gate 	    stripe_md_ops.md_driver.md_drivername);
829*0Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) {
832*0Sstevel@tonic-gate 		if (mddb_getrecprivate(recid) & MD_PRV_GOTIT)
833*0Sstevel@tonic-gate 			continue;
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 		dep = mddb_getrecdep(recid);
836*0Sstevel@tonic-gate 		dep->de_flags = MDDB_F_STRIPE;
837*0Sstevel@tonic-gate 		rbp = dep->de_rb;
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 		if ((rbp->rb_revision == MDDB_REV_RB) &&
840*0Sstevel@tonic-gate 		    ((rbp->rb_private & MD_PRV_CONVD) == 0)) {
841*0Sstevel@tonic-gate 			/*
842*0Sstevel@tonic-gate 			 * This means, we have an old and small record
843*0Sstevel@tonic-gate 			 * and this record hasn't already been converted.
844*0Sstevel@tonic-gate 			 * Before we create an incore metadevice from this
845*0Sstevel@tonic-gate 			 * we have to convert it to a big record.
846*0Sstevel@tonic-gate 			 */
847*0Sstevel@tonic-gate 			small_un = (ms_unit32_od_t *)mddb_getrecaddr(recid);
848*0Sstevel@tonic-gate 			newreqsize = get_big_stripe_req_size(small_un,
849*0Sstevel@tonic-gate 					COMPLETE_STRUCTURE);
850*0Sstevel@tonic-gate 			big_un = (ms_unit_t *)kmem_zalloc(newreqsize, KM_SLEEP);
851*0Sstevel@tonic-gate 			stripe_convert((caddr_t)small_un, (caddr_t)big_un,
852*0Sstevel@tonic-gate 			    SMALL_2_BIG);
853*0Sstevel@tonic-gate 			kmem_free(small_un, dep->de_reqsize);
854*0Sstevel@tonic-gate 			dep->de_rb_userdata = big_un;
855*0Sstevel@tonic-gate 			dep->de_reqsize = newreqsize;
856*0Sstevel@tonic-gate 			un = big_un;
857*0Sstevel@tonic-gate 			rbp->rb_private |= MD_PRV_CONVD;
858*0Sstevel@tonic-gate 		} else {
859*0Sstevel@tonic-gate 			/* Big device */
860*0Sstevel@tonic-gate 			un = (ms_unit_t *)mddb_getrecaddr(recid);
861*0Sstevel@tonic-gate 		}
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 		/* Set revision and flag accordingly */
864*0Sstevel@tonic-gate 		if (rbp->rb_revision == MDDB_REV_RB) {
865*0Sstevel@tonic-gate 			un->c.un_revision = MD_32BIT_META_DEV;
866*0Sstevel@tonic-gate 		} else {
867*0Sstevel@tonic-gate 			un->c.un_revision = MD_64BIT_META_DEV;
868*0Sstevel@tonic-gate 			un->c.un_flag |= MD_EFILABEL;
869*0Sstevel@tonic-gate 		}
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 		/* Create minor node for snarfed unit. */
872*0Sstevel@tonic-gate 		(void) md_create_minor_node(MD_MIN2SET(MD_SID(un)), MD_SID(un));
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 		if (MD_UNIT(MD_SID(un)) != NULL) {
875*0Sstevel@tonic-gate 			mddb_setrecprivate(recid, MD_PRV_PENDDEL);
876*0Sstevel@tonic-gate 			continue;
877*0Sstevel@tonic-gate 		}
878*0Sstevel@tonic-gate 		all_stripes_gotten = 0;
879*0Sstevel@tonic-gate 		if (stripe_build_incore((void *)un, 1) == 0) {
880*0Sstevel@tonic-gate 			mddb_setrecprivate(recid, MD_PRV_GOTIT);
881*0Sstevel@tonic-gate 			md_create_unit_incore(MD_SID(un), &stripe_md_ops, 0);
882*0Sstevel@tonic-gate 			gotsomething = 1;
883*0Sstevel@tonic-gate 		}
884*0Sstevel@tonic-gate 	}
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 	if (!all_stripes_gotten)
887*0Sstevel@tonic-gate 		return (gotsomething);
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
890*0Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0)
891*0Sstevel@tonic-gate 		if (!(mddb_getrecprivate(recid) & MD_PRV_GOTIT))
892*0Sstevel@tonic-gate 			mddb_setrecprivate(recid, MD_PRV_PENDDEL);
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 	return (0);
895*0Sstevel@tonic-gate }
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate static int
898*0Sstevel@tonic-gate stripe_halt(md_haltcmd_t cmd, set_t setno)
899*0Sstevel@tonic-gate {
900*0Sstevel@tonic-gate 	int		i;
901*0Sstevel@tonic-gate 	mdi_unit_t	*ui;
902*0Sstevel@tonic-gate 	minor_t		mnum;
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate 	if (cmd == MD_HALT_CLOSE)
905*0Sstevel@tonic-gate 		return (0);
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	if (cmd == MD_HALT_OPEN)
908*0Sstevel@tonic-gate 		return (0);
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	if (cmd == MD_HALT_UNLOAD)
911*0Sstevel@tonic-gate 		return (0);
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 	if (cmd == MD_HALT_CHECK) {
914*0Sstevel@tonic-gate 		for (i = 0; i < md_nunits; i++) {
915*0Sstevel@tonic-gate 			mnum = MD_MKMIN(setno, i);
916*0Sstevel@tonic-gate 			if ((ui = MDI_UNIT(mnum)) == NULL)
917*0Sstevel@tonic-gate 				continue;
918*0Sstevel@tonic-gate 			if (ui->ui_opsindex != stripe_md_ops.md_selfindex)
919*0Sstevel@tonic-gate 				continue;
920*0Sstevel@tonic-gate 			if (md_unit_isopen(ui))
921*0Sstevel@tonic-gate 				return (1);
922*0Sstevel@tonic-gate 		}
923*0Sstevel@tonic-gate 		return (0);
924*0Sstevel@tonic-gate 	}
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	if (cmd != MD_HALT_DOIT)
927*0Sstevel@tonic-gate 		return (1);
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 	for (i = 0; i < md_nunits; i++) {
930*0Sstevel@tonic-gate 		mnum = MD_MKMIN(setno, i);
931*0Sstevel@tonic-gate 		if ((ui = MDI_UNIT(mnum)) == NULL)
932*0Sstevel@tonic-gate 			continue;
933*0Sstevel@tonic-gate 		if (ui->ui_opsindex != stripe_md_ops.md_selfindex)
934*0Sstevel@tonic-gate 			continue;
935*0Sstevel@tonic-gate 		reset_stripe((ms_unit_t *)MD_UNIT(mnum), mnum, 0);
936*0Sstevel@tonic-gate 	}
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 	return (0);
939*0Sstevel@tonic-gate }
940*0Sstevel@tonic-gate 
941*0Sstevel@tonic-gate /*ARGSUSED3*/
942*0Sstevel@tonic-gate static int
943*0Sstevel@tonic-gate stripe_open(dev_t *dev, int flag, int otyp, cred_t *cred_p, int md_oflags)
944*0Sstevel@tonic-gate {
945*0Sstevel@tonic-gate 	minor_t		mnum = getminor(*dev);
946*0Sstevel@tonic-gate 	mdi_unit_t	*ui = MDI_UNIT(mnum);
947*0Sstevel@tonic-gate 	ms_unit_t	*un;
948*0Sstevel@tonic-gate 	int		err = 0;
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	/* single thread */
951*0Sstevel@tonic-gate 	un = (ms_unit_t *)md_unit_openclose_enter(ui);
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	/* open devices, if necessary */
954*0Sstevel@tonic-gate 	if (! md_unit_isopen(ui) || (md_oflags & MD_OFLG_PROBEDEV)) {
955*0Sstevel@tonic-gate 		if ((err = stripe_open_all_devs(un, md_oflags)) != 0) {
956*0Sstevel@tonic-gate 			goto out;
957*0Sstevel@tonic-gate 		}
958*0Sstevel@tonic-gate 	}
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	/* count open */
961*0Sstevel@tonic-gate 	if ((err = md_unit_incopen(mnum, flag, otyp)) != 0)
962*0Sstevel@tonic-gate 		goto out;
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	/* unlock, return success */
965*0Sstevel@tonic-gate out:
966*0Sstevel@tonic-gate 	md_unit_openclose_exit(ui);
967*0Sstevel@tonic-gate 	return (err);
968*0Sstevel@tonic-gate }
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate /*ARGSUSED1*/
971*0Sstevel@tonic-gate static int
972*0Sstevel@tonic-gate stripe_close(
973*0Sstevel@tonic-gate 	dev_t		dev,
974*0Sstevel@tonic-gate 	int		flag,
975*0Sstevel@tonic-gate 	int		otyp,
976*0Sstevel@tonic-gate 	cred_t		*cred_p,
977*0Sstevel@tonic-gate 	int		md_cflags
978*0Sstevel@tonic-gate )
979*0Sstevel@tonic-gate {
980*0Sstevel@tonic-gate 	minor_t		mnum = getminor(dev);
981*0Sstevel@tonic-gate 	mdi_unit_t	*ui = MDI_UNIT(mnum);
982*0Sstevel@tonic-gate 	ms_unit_t	*un;
983*0Sstevel@tonic-gate 	int		err = 0;
984*0Sstevel@tonic-gate 
985*0Sstevel@tonic-gate 	/* single thread */
986*0Sstevel@tonic-gate 	un = (ms_unit_t *)md_unit_openclose_enter(ui);
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 	/* count closed */
989*0Sstevel@tonic-gate 	if ((err = md_unit_decopen(mnum, otyp)) != 0)
990*0Sstevel@tonic-gate 		goto out;
991*0Sstevel@tonic-gate 
992*0Sstevel@tonic-gate 	/* close devices, if necessary */
993*0Sstevel@tonic-gate 	if (! md_unit_isopen(ui) || (md_cflags & MD_OFLG_PROBEDEV)) {
994*0Sstevel@tonic-gate 		stripe_close_all_devs(un, md_cflags);
995*0Sstevel@tonic-gate 	}
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 	/* unlock, return success */
998*0Sstevel@tonic-gate out:
999*0Sstevel@tonic-gate 	md_unit_openclose_exit(ui);
1000*0Sstevel@tonic-gate 	return (err);
1001*0Sstevel@tonic-gate }
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 
1004*0Sstevel@tonic-gate static struct buf dumpbuf;
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate /*
1007*0Sstevel@tonic-gate  * This routine dumps memory to the disk.  It assumes that the memory has
1008*0Sstevel@tonic-gate  * already been mapped into mainbus space.  It is called at disk interrupt
1009*0Sstevel@tonic-gate  * priority when the system is in trouble.
1010*0Sstevel@tonic-gate  *
1011*0Sstevel@tonic-gate  */
1012*0Sstevel@tonic-gate static int
1013*0Sstevel@tonic-gate stripe_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
1014*0Sstevel@tonic-gate {
1015*0Sstevel@tonic-gate 	ms_unit_t	*un;
1016*0Sstevel@tonic-gate 	buf_t		*bp;
1017*0Sstevel@tonic-gate 	ms_comp_t	*mdc;
1018*0Sstevel@tonic-gate 	u_longlong_t	nb;
1019*0Sstevel@tonic-gate 	diskaddr_t	mapblk;
1020*0Sstevel@tonic-gate 	int		result;
1021*0Sstevel@tonic-gate 	int		more;
1022*0Sstevel@tonic-gate 	int		saveresult = 0;
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate 	/*
1025*0Sstevel@tonic-gate 	 * Don't need to grab the unit lock.
1026*0Sstevel@tonic-gate 	 * Cause nothing else is suppose to be happenning.
1027*0Sstevel@tonic-gate 	 * Also dump is not suppose to sleep.
1028*0Sstevel@tonic-gate 	 */
1029*0Sstevel@tonic-gate 	un = (ms_unit_t *)MD_UNIT(getminor(dev));
1030*0Sstevel@tonic-gate 
1031*0Sstevel@tonic-gate 	if ((diskaddr_t)blkno >= un->c.un_total_blocks)
1032*0Sstevel@tonic-gate 		return (EINVAL);
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate 	if ((diskaddr_t)blkno + nblk > un->c.un_total_blocks)
1035*0Sstevel@tonic-gate 		return (EINVAL);
1036*0Sstevel@tonic-gate 
1037*0Sstevel@tonic-gate 	bp = &dumpbuf;
1038*0Sstevel@tonic-gate 	nb = ldbtob(nblk);
1039*0Sstevel@tonic-gate 	do {
1040*0Sstevel@tonic-gate 		bzero((caddr_t)bp, sizeof (*bp));
1041*0Sstevel@tonic-gate 		more = md_mapbuf(un, (diskaddr_t)blkno, nb, bp, &mdc);
1042*0Sstevel@tonic-gate 		nblk = btodb(bp->b_bcount);
1043*0Sstevel@tonic-gate 		mapblk = bp->b_lblkno;
1044*0Sstevel@tonic-gate 		if (!(mdc->un_mirror.ms_flags & MDM_S_NOWRITE)) {
1045*0Sstevel@tonic-gate 			/*
1046*0Sstevel@tonic-gate 			 * bdev_dump() is currently only able to take
1047*0Sstevel@tonic-gate 			 * 32 bit wide blkno's.
1048*0Sstevel@tonic-gate 			 */
1049*0Sstevel@tonic-gate 			result = bdev_dump(bp->b_edev, addr, (daddr_t)mapblk,
1050*0Sstevel@tonic-gate 						nblk);
1051*0Sstevel@tonic-gate 			if (result)
1052*0Sstevel@tonic-gate 				saveresult = result;
1053*0Sstevel@tonic-gate 		}
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate 		nb -= bp->b_bcount;
1056*0Sstevel@tonic-gate 		addr += bp->b_bcount;
1057*0Sstevel@tonic-gate 		blkno += nblk;
1058*0Sstevel@tonic-gate 	} while (more);
1059*0Sstevel@tonic-gate 
1060*0Sstevel@tonic-gate 	return (saveresult);
1061*0Sstevel@tonic-gate }
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate /*ARGSUSED*/
1064*0Sstevel@tonic-gate static intptr_t
1065*0Sstevel@tonic-gate stripe_shared_by_blk(
1066*0Sstevel@tonic-gate 	md_dev64_t dev,
1067*0Sstevel@tonic-gate 	void *junk,
1068*0Sstevel@tonic-gate 	diskaddr_t blkno,
1069*0Sstevel@tonic-gate 	u_longlong_t *cnt)
1070*0Sstevel@tonic-gate {
1071*0Sstevel@tonic-gate 	ms_unit_t	*un;
1072*0Sstevel@tonic-gate 	buf_t		bp;
1073*0Sstevel@tonic-gate 	ms_comp_t	*comp;
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	un = MD_UNIT(md_getminor(dev));
1076*0Sstevel@tonic-gate 	(void) md_mapbuf(un, blkno, ldbtob(*cnt), &bp, &comp);
1077*0Sstevel@tonic-gate 	*cnt = (u_longlong_t)lbtodb(bp.b_bcount);
1078*0Sstevel@tonic-gate 	return ((intptr_t)&comp->un_mirror);
1079*0Sstevel@tonic-gate }
1080*0Sstevel@tonic-gate 
1081*0Sstevel@tonic-gate /*
1082*0Sstevel@tonic-gate  * stripe_block_count_skip_size() returns the following values
1083*0Sstevel@tonic-gate  *	so that the logical to physical block mappings can
1084*0Sstevel@tonic-gate  *	be calculated without intimate knowledge of the underpinnings.
1085*0Sstevel@tonic-gate  *
1086*0Sstevel@tonic-gate  *	block - first logical block number of the device.
1087*0Sstevel@tonic-gate  *		block = [ # of blocks before THE row ] +
1088*0Sstevel@tonic-gate  *			[ # of blocks in THE row before the component ]
1089*0Sstevel@tonic-gate  *	count - # of segments (interlaced size).
1090*0Sstevel@tonic-gate  *	skip  - # of logical blocks between segments, or delta to
1091*0Sstevel@tonic-gate  *		  get to next segment
1092*0Sstevel@tonic-gate  *	size  - interlace size used for the block, count, skip.
1093*0Sstevel@tonic-gate  */
1094*0Sstevel@tonic-gate /*ARGSUSED*/
1095*0Sstevel@tonic-gate static intptr_t
1096*0Sstevel@tonic-gate stripe_block_count_skip_size(
1097*0Sstevel@tonic-gate 	md_dev64_t	 dev,
1098*0Sstevel@tonic-gate 	void		*junk,
1099*0Sstevel@tonic-gate 	int		ci,
1100*0Sstevel@tonic-gate 	diskaddr_t	*block,
1101*0Sstevel@tonic-gate 	size_t		*count,
1102*0Sstevel@tonic-gate 	u_longlong_t	*skip,
1103*0Sstevel@tonic-gate 	u_longlong_t	*size)
1104*0Sstevel@tonic-gate {
1105*0Sstevel@tonic-gate 	ms_unit_t	*un;
1106*0Sstevel@tonic-gate 	int		row;
1107*0Sstevel@tonic-gate 	struct ms_row	*mdr;
1108*0Sstevel@tonic-gate 	int		cmpcount = 0;
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate 	un = MD_UNIT(md_getminor(dev));
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
1113*0Sstevel@tonic-gate 		mdr = &un->un_row[row];
1114*0Sstevel@tonic-gate 		if ((mdr->un_ncomp + cmpcount) > ci)
1115*0Sstevel@tonic-gate 			break;
1116*0Sstevel@tonic-gate 		cmpcount += mdr->un_ncomp;
1117*0Sstevel@tonic-gate 	}
1118*0Sstevel@tonic-gate 	ASSERT(row != un->un_nrows);
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate 	/*
1121*0Sstevel@tonic-gate 	 * Concatenations are always contiguous blocks,
1122*0Sstevel@tonic-gate 	 * you cannot depend on the interlace being a usable
1123*0Sstevel@tonic-gate 	 * value (except for stripes).
1124*0Sstevel@tonic-gate 	 */
1125*0Sstevel@tonic-gate 	if (mdr->un_ncomp == 1) {	/* Concats */
1126*0Sstevel@tonic-gate 		*block = mdr->un_cum_blocks - mdr->un_blocks;
1127*0Sstevel@tonic-gate 		*count = 1;
1128*0Sstevel@tonic-gate 		*skip = 0;
1129*0Sstevel@tonic-gate 		*size = mdr->un_blocks;
1130*0Sstevel@tonic-gate 	} else {			/* Stripes */
1131*0Sstevel@tonic-gate 		*block = (mdr->un_cum_blocks - mdr->un_blocks) +
1132*0Sstevel@tonic-gate 		    ((ci - cmpcount) * mdr->un_interlace);
1133*0Sstevel@tonic-gate 		*count	= (size_t)(mdr->un_blocks / (mdr->un_interlace
1134*0Sstevel@tonic-gate 			* mdr->un_ncomp));
1135*0Sstevel@tonic-gate 		*skip = (mdr->un_interlace * mdr->un_ncomp) - mdr->un_interlace;
1136*0Sstevel@tonic-gate 		*size = mdr->un_interlace;
1137*0Sstevel@tonic-gate 	}
1138*0Sstevel@tonic-gate 
1139*0Sstevel@tonic-gate 	return (0);
1140*0Sstevel@tonic-gate }
1141*0Sstevel@tonic-gate 
1142*0Sstevel@tonic-gate /*ARGSUSED*/
1143*0Sstevel@tonic-gate static intptr_t
1144*0Sstevel@tonic-gate stripe_shared_by_indx(md_dev64_t dev, void *junk, int indx)
1145*0Sstevel@tonic-gate {
1146*0Sstevel@tonic-gate 	ms_unit_t	*un;
1147*0Sstevel@tonic-gate 	ms_comp_t	*comp;
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate 	un = MD_UNIT(md_getminor(dev));
1150*0Sstevel@tonic-gate 	comp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
1151*0Sstevel@tonic-gate 	comp += indx;
1152*0Sstevel@tonic-gate 	return ((intptr_t)&comp->un_mirror);
1153*0Sstevel@tonic-gate }
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate /*ARGSUSED*/
1156*0Sstevel@tonic-gate intptr_t
1157*0Sstevel@tonic-gate stripe_component_count(md_dev64_t dev, void *junk)
1158*0Sstevel@tonic-gate {
1159*0Sstevel@tonic-gate 	/*
1160*0Sstevel@tonic-gate 	 * See comments for stripe_get_dev
1161*0Sstevel@tonic-gate 	 */
1162*0Sstevel@tonic-gate 
1163*0Sstevel@tonic-gate 	ms_unit_t	*un;
1164*0Sstevel@tonic-gate 	int		count = 0;
1165*0Sstevel@tonic-gate 	int		row;
1166*0Sstevel@tonic-gate 
1167*0Sstevel@tonic-gate 	un = MD_UNIT(md_getminor(dev));
1168*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++)
1169*0Sstevel@tonic-gate 		count += un->un_row[row].un_ncomp;
1170*0Sstevel@tonic-gate 	return (count);
1171*0Sstevel@tonic-gate }
1172*0Sstevel@tonic-gate 
1173*0Sstevel@tonic-gate /*ARGSUSED*/
1174*0Sstevel@tonic-gate intptr_t
1175*0Sstevel@tonic-gate stripe_get_dev(md_dev64_t dev, void *junk, int indx, ms_cd_info_t *cd)
1176*0Sstevel@tonic-gate {
1177*0Sstevel@tonic-gate 	/*
1178*0Sstevel@tonic-gate 	 * It should be noted that stripe_replace in stripe_ioctl.c calls this
1179*0Sstevel@tonic-gate 	 * routine using makedevice(0, minor) for the first argument.
1180*0Sstevel@tonic-gate 	 *
1181*0Sstevel@tonic-gate 	 * If this routine at some point in the future needs to use the major
1182*0Sstevel@tonic-gate 	 * number stripe_replace must be changed.
1183*0Sstevel@tonic-gate 	 */
1184*0Sstevel@tonic-gate 
1185*0Sstevel@tonic-gate 	ms_unit_t	*un;
1186*0Sstevel@tonic-gate 	ms_comp_t	*comp;
1187*0Sstevel@tonic-gate 	md_dev64_t	tmpdev;
1188*0Sstevel@tonic-gate 
1189*0Sstevel@tonic-gate 	un = MD_UNIT(md_getminor(dev));
1190*0Sstevel@tonic-gate 	comp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
1191*0Sstevel@tonic-gate 	comp += indx;
1192*0Sstevel@tonic-gate 	tmpdev = comp->un_dev;
1193*0Sstevel@tonic-gate 	/*
1194*0Sstevel@tonic-gate 	 * Try to resolve devt again if NODEV64
1195*0Sstevel@tonic-gate 	 * Check if this comp is hotspared and if it is
1196*0Sstevel@tonic-gate 	 * then use key for hotspare
1197*0Sstevel@tonic-gate 	 */
1198*0Sstevel@tonic-gate 	if (tmpdev == NODEV64) {
1199*0Sstevel@tonic-gate 		tmpdev = md_resolve_bydevid(md_getminor(dev), tmpdev,
1200*0Sstevel@tonic-gate 			comp->un_mirror.ms_hs_id ?
1201*0Sstevel@tonic-gate 			comp->un_mirror.ms_hs_key :
1202*0Sstevel@tonic-gate 			comp->un_key);
1203*0Sstevel@tonic-gate 		comp->un_dev = tmpdev;
1204*0Sstevel@tonic-gate 	}
1205*0Sstevel@tonic-gate 
1206*0Sstevel@tonic-gate 	cd->cd_dev = comp->un_dev;
1207*0Sstevel@tonic-gate 	cd->cd_orig_dev = comp->un_mirror.ms_orig_dev;
1208*0Sstevel@tonic-gate 	return (0);
1209*0Sstevel@tonic-gate }
1210*0Sstevel@tonic-gate 
1211*0Sstevel@tonic-gate /*ARGSUSED*/
1212*0Sstevel@tonic-gate void
1213*0Sstevel@tonic-gate stripe_replace_done(md_dev64_t dev, sv_dev_t *sv)
1214*0Sstevel@tonic-gate {
1215*0Sstevel@tonic-gate 	/*
1216*0Sstevel@tonic-gate 	 * See comments for stripe_get_dev
1217*0Sstevel@tonic-gate 	 */
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	minor_t		mnum = md_getminor(dev);
1220*0Sstevel@tonic-gate 
1221*0Sstevel@tonic-gate 	if (sv != NULL) {
1222*0Sstevel@tonic-gate 		md_rem_names(sv, 1);
1223*0Sstevel@tonic-gate 		kmem_free(sv, sizeof (sv_dev_t));
1224*0Sstevel@tonic-gate 	}
1225*0Sstevel@tonic-gate 
1226*0Sstevel@tonic-gate 	md_unit_writerexit(MDI_UNIT(mnum));
1227*0Sstevel@tonic-gate }
1228*0Sstevel@tonic-gate 
1229*0Sstevel@tonic-gate /*ARGSUSED*/
1230*0Sstevel@tonic-gate intptr_t
1231*0Sstevel@tonic-gate stripe_replace_dev(md_dev64_t dev, void *junk, int ci, ms_new_dev_t *nd,
1232*0Sstevel@tonic-gate     mddb_recid_t *recids, int nrecids, void (**replace_done)(),
1233*0Sstevel@tonic-gate     void **replace_data)
1234*0Sstevel@tonic-gate {
1235*0Sstevel@tonic-gate 	minor_t		mnum;
1236*0Sstevel@tonic-gate 	ms_unit_t	*un;
1237*0Sstevel@tonic-gate 	mdi_unit_t	*ui;
1238*0Sstevel@tonic-gate 	ms_comp_t	*comp;
1239*0Sstevel@tonic-gate 	diskaddr_t	dev_size;
1240*0Sstevel@tonic-gate 	int		row;
1241*0Sstevel@tonic-gate 	int		ncomps = 0;
1242*0Sstevel@tonic-gate 	int		cmpcount = 0;
1243*0Sstevel@tonic-gate 	int		rid = 0;
1244*0Sstevel@tonic-gate 	struct ms_row	*mdr;
1245*0Sstevel@tonic-gate 	sv_dev_t	*sv = NULL;
1246*0Sstevel@tonic-gate 	mddb_recid_t	hs_id = 0;
1247*0Sstevel@tonic-gate 	set_t		setno;
1248*0Sstevel@tonic-gate 	side_t		side;
1249*0Sstevel@tonic-gate 	md_dev64_t	this_dev;
1250*0Sstevel@tonic-gate 
1251*0Sstevel@tonic-gate 	mnum = md_getminor(dev);
1252*0Sstevel@tonic-gate 	ui = MDI_UNIT(mnum);
1253*0Sstevel@tonic-gate 	setno = MD_MIN2SET(mnum);
1254*0Sstevel@tonic-gate 	side = mddb_getsidenum(setno);
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate 	un = md_unit_writerlock(ui);
1257*0Sstevel@tonic-gate 
1258*0Sstevel@tonic-gate 	*replace_data = NULL;
1259*0Sstevel@tonic-gate 	comp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate 	comp += ci;
1262*0Sstevel@tonic-gate 
1263*0Sstevel@tonic-gate 	/*
1264*0Sstevel@tonic-gate 	 * Count the number of components
1265*0Sstevel@tonic-gate 	 */
1266*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
1267*0Sstevel@tonic-gate 		struct ms_row *mdr = &un->un_row[row];
1268*0Sstevel@tonic-gate 		ncomps += mdr->un_ncomp;
1269*0Sstevel@tonic-gate 	}
1270*0Sstevel@tonic-gate 
1271*0Sstevel@tonic-gate 	recids[0] = 0;
1272*0Sstevel@tonic-gate 	/*
1273*0Sstevel@tonic-gate 	 * No need of checking size of new device,
1274*0Sstevel@tonic-gate 	 * when hotsparing (it has already been done), or
1275*0Sstevel@tonic-gate 	 * when enabling the device.
1276*0Sstevel@tonic-gate 	 */
1277*0Sstevel@tonic-gate 	if ((nd != NULL) && (nd->nd_hs_id == 0)) {
1278*0Sstevel@tonic-gate 		for (row = 0; row < un->un_nrows; row++) {
1279*0Sstevel@tonic-gate 			mdr = &un->un_row[row];
1280*0Sstevel@tonic-gate 			if ((mdr->un_ncomp + cmpcount) > ci)
1281*0Sstevel@tonic-gate 				break;
1282*0Sstevel@tonic-gate 			cmpcount += mdr->un_ncomp;
1283*0Sstevel@tonic-gate 		}
1284*0Sstevel@tonic-gate 		ASSERT(row != un->un_nrows);
1285*0Sstevel@tonic-gate 
1286*0Sstevel@tonic-gate 		/* Concatenations have a ncomp = 1 */
1287*0Sstevel@tonic-gate 		dev_size = mdr->un_blocks / mdr->un_ncomp;
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate 		/*
1290*0Sstevel@tonic-gate 		 * now check to see if new comp can be used in
1291*0Sstevel@tonic-gate 		 * place of old comp
1292*0Sstevel@tonic-gate 		 */
1293*0Sstevel@tonic-gate 		if ((un->c.un_flag & MD_LABELED) && (ci == 0) &&
1294*0Sstevel@tonic-gate 		    nd->nd_labeled)
1295*0Sstevel@tonic-gate 			nd->nd_start_blk = 0;
1296*0Sstevel@tonic-gate 		else
1297*0Sstevel@tonic-gate 			nd->nd_nblks -= nd->nd_start_blk;
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate 		if (dev_size > nd->nd_nblks) {
1300*0Sstevel@tonic-gate 			md_unit_writerexit(ui);
1301*0Sstevel@tonic-gate 			return (MDE_COMP_TOO_SMALL);
1302*0Sstevel@tonic-gate 		}
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate 		sv = (sv_dev_t *)kmem_alloc(sizeof (sv_dev_t), KM_SLEEP);
1305*0Sstevel@tonic-gate 		sv->setno = MD_MIN2SET(mnum);
1306*0Sstevel@tonic-gate 		sv->key = comp->un_key;
1307*0Sstevel@tonic-gate 	}
1308*0Sstevel@tonic-gate 
1309*0Sstevel@tonic-gate 	/*
1310*0Sstevel@tonic-gate 	 * Close this component.
1311*0Sstevel@tonic-gate 	 */
1312*0Sstevel@tonic-gate 	if (comp->un_mirror.ms_flags & MDM_S_ISOPEN) {
1313*0Sstevel@tonic-gate 		md_layered_close(comp->un_dev, MD_OFLG_NULL);
1314*0Sstevel@tonic-gate 		comp->un_mirror.ms_flags &= ~MDM_S_ISOPEN;
1315*0Sstevel@tonic-gate 	}
1316*0Sstevel@tonic-gate 
1317*0Sstevel@tonic-gate 	/*
1318*0Sstevel@tonic-gate 	 * If the component is hotspared, return to the pool.
1319*0Sstevel@tonic-gate 	 */
1320*0Sstevel@tonic-gate 	if (comp->un_mirror.ms_hs_id != 0) {
1321*0Sstevel@tonic-gate 		hs_cmds_t	cmd;
1322*0Sstevel@tonic-gate 		mdkey_t		hs_key;
1323*0Sstevel@tonic-gate 
1324*0Sstevel@tonic-gate 		hs_key = comp->un_mirror.ms_hs_key;
1325*0Sstevel@tonic-gate 		comp->un_dev = comp->un_mirror.ms_orig_dev;
1326*0Sstevel@tonic-gate 		comp->un_start_block = comp->un_mirror.ms_orig_blk;
1327*0Sstevel@tonic-gate 		comp->un_mirror.ms_hs_key = 0;
1328*0Sstevel@tonic-gate 		comp->un_mirror.ms_hs_id = 0;
1329*0Sstevel@tonic-gate 		comp->un_mirror.ms_orig_dev = 0;
1330*0Sstevel@tonic-gate 
1331*0Sstevel@tonic-gate 		cmd = HS_FREE;
1332*0Sstevel@tonic-gate 		if ((comp->un_mirror.ms_state != CS_OKAY) &&
1333*0Sstevel@tonic-gate 		    (comp->un_mirror.ms_state != CS_RESYNC))
1334*0Sstevel@tonic-gate 			cmd = HS_BAD;
1335*0Sstevel@tonic-gate 		(void) md_hot_spare_ifc(cmd, un->un_hsp_id, 0, 0, &hs_id,
1336*0Sstevel@tonic-gate 		    &hs_key, NULL, NULL);
1337*0Sstevel@tonic-gate 	}
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 	/*
1340*0Sstevel@tonic-gate 	 * Open by device id; for enable (indicated by a NULL
1341*0Sstevel@tonic-gate 	 * nd pointer), use the existing component info.  For
1342*0Sstevel@tonic-gate 	 * replace, use the new device.
1343*0Sstevel@tonic-gate 	 */
1344*0Sstevel@tonic-gate 	if (nd == NULL) {
1345*0Sstevel@tonic-gate 		this_dev = md_resolve_bydevid(mnum, comp->un_dev, comp->un_key);
1346*0Sstevel@tonic-gate 		/*
1347*0Sstevel@tonic-gate 		 * If someone replaced a new disk in the same slot
1348*0Sstevel@tonic-gate 		 * we get NODEV64 since old device id cannot be
1349*0Sstevel@tonic-gate 		 * resolved. The new devt is obtained from the
1350*0Sstevel@tonic-gate 		 * mddb since devt is going to be unchanged for the
1351*0Sstevel@tonic-gate 		 * enable case. No need to check for multiple
1352*0Sstevel@tonic-gate 		 * keys here because the caller (comp_replace)
1353*0Sstevel@tonic-gate 		 * has already sanity checked it for us.
1354*0Sstevel@tonic-gate 		 */
1355*0Sstevel@tonic-gate 		if (this_dev == NODEV64) {
1356*0Sstevel@tonic-gate 			this_dev = md_getdevnum(setno, side, comp->un_key,
1357*0Sstevel@tonic-gate 			    MD_TRUST_DEVT);
1358*0Sstevel@tonic-gate 		}
1359*0Sstevel@tonic-gate 	} else {
1360*0Sstevel@tonic-gate 		/*
1361*0Sstevel@tonic-gate 		 * If this is a hotspare, save the original dev_t for later
1362*0Sstevel@tonic-gate 		 * use. If this has occured during boot then the value of
1363*0Sstevel@tonic-gate 		 * comp->un_dev will be NODEV64 because of the failure to look
1364*0Sstevel@tonic-gate 		 * up the devid of the device.
1365*0Sstevel@tonic-gate 		 */
1366*0Sstevel@tonic-gate 		if (nd->nd_hs_id != 0)
1367*0Sstevel@tonic-gate 			comp->un_mirror.ms_orig_dev = comp->un_dev;
1368*0Sstevel@tonic-gate 		this_dev = md_resolve_bydevid(mnum, nd->nd_dev, nd->nd_key);
1369*0Sstevel@tonic-gate 	}
1370*0Sstevel@tonic-gate 
1371*0Sstevel@tonic-gate 	comp->un_dev = this_dev;
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate 	/*
1374*0Sstevel@tonic-gate 	 * Now open the new device if required. Note for a single component
1375*0Sstevel@tonic-gate 	 * stripe it will not be open - leave this for the mirror driver to
1376*0Sstevel@tonic-gate 	 * deal with.
1377*0Sstevel@tonic-gate 	 */
1378*0Sstevel@tonic-gate 	if (md_unit_isopen(ui)) {
1379*0Sstevel@tonic-gate 		if (md_layered_open(mnum, &this_dev, MD_OFLG_NULL)) {
1380*0Sstevel@tonic-gate 			mddb_recid_t	ids[3];
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 			ids[0] = un->c.un_record_id;
1383*0Sstevel@tonic-gate 			ids[1] = hs_id;
1384*0Sstevel@tonic-gate 			ids[2] = 0;
1385*0Sstevel@tonic-gate 			mddb_commitrecs_wrapper(ids);
1386*0Sstevel@tonic-gate 			if ((nd != NULL) && (nd->nd_hs_id != 0)) {
1387*0Sstevel@tonic-gate 				/*
1388*0Sstevel@tonic-gate 				 * Revert back to the original device.
1389*0Sstevel@tonic-gate 				 */
1390*0Sstevel@tonic-gate 				comp->un_dev = comp->un_mirror.ms_orig_dev;
1391*0Sstevel@tonic-gate 
1392*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
1393*0Sstevel@tonic-gate 				    "md: %s: open error of hotspare %s",
1394*0Sstevel@tonic-gate 				    md_shortname(mnum),
1395*0Sstevel@tonic-gate 				    md_devname(MD_MIN2SET(mnum), nd->nd_dev,
1396*0Sstevel@tonic-gate 				    NULL, 0));
1397*0Sstevel@tonic-gate 				SE_NOTIFY(EC_SVM_STATE, ESC_SVM_OPEN_FAIL,
1398*0Sstevel@tonic-gate 				    SVM_TAG_HS, MD_MIN2SET(mnum), nd->nd_dev);
1399*0Sstevel@tonic-gate 			}
1400*0Sstevel@tonic-gate 			md_unit_writerexit(ui);
1401*0Sstevel@tonic-gate 			return (MDE_COMP_OPEN_ERR);
1402*0Sstevel@tonic-gate 		}
1403*0Sstevel@tonic-gate 		if (nd != NULL)
1404*0Sstevel@tonic-gate 			nd->nd_dev = this_dev;
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate 		comp->un_mirror.ms_flags |= MDM_S_ISOPEN;
1407*0Sstevel@tonic-gate 	}
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 	if (nd == NULL) {
1410*0Sstevel@tonic-gate 		recids[0] = un->c.un_record_id;
1411*0Sstevel@tonic-gate 		recids[1] = hs_id;
1412*0Sstevel@tonic-gate 		recids[2] = 0;
1413*0Sstevel@tonic-gate 		*replace_done = stripe_replace_done;
1414*0Sstevel@tonic-gate 		return (0);
1415*0Sstevel@tonic-gate 	}
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate 	/* if hot sparing this device */
1418*0Sstevel@tonic-gate 	if (nd->nd_hs_id != 0) {
1419*0Sstevel@tonic-gate 		char	devname[MD_MAX_CTDLEN];
1420*0Sstevel@tonic-gate 		char	hs_devname[MD_MAX_CTDLEN];
1421*0Sstevel@tonic-gate 		set_t	setno;
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 		comp->un_mirror.ms_hs_id = nd->nd_hs_id;
1424*0Sstevel@tonic-gate 		comp->un_mirror.ms_hs_key = nd->nd_key;
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate 		comp->un_mirror.ms_orig_blk = comp->un_start_block;
1427*0Sstevel@tonic-gate 
1428*0Sstevel@tonic-gate 		setno = MD_MIN2SET(mnum);
1429*0Sstevel@tonic-gate 
1430*0Sstevel@tonic-gate 		(void) md_devname(setno, comp->un_mirror.ms_orig_dev, devname,
1431*0Sstevel@tonic-gate 					sizeof (devname));
1432*0Sstevel@tonic-gate 		(void) md_devname(setno, nd->nd_dev, hs_devname,
1433*0Sstevel@tonic-gate 		    sizeof (hs_devname));
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "md: %s: hotspared device %s with %s",
1436*0Sstevel@tonic-gate 		    md_shortname(mnum), devname, hs_devname);
1437*0Sstevel@tonic-gate 
1438*0Sstevel@tonic-gate 	} else {	/* replacing the device */
1439*0Sstevel@tonic-gate 		comp->un_key = nd->nd_key;
1440*0Sstevel@tonic-gate 		*replace_data = (void *)sv;
1441*0Sstevel@tonic-gate 
1442*0Sstevel@tonic-gate 		/*
1443*0Sstevel@tonic-gate 		 * For the old device, make sure to reset the parent
1444*0Sstevel@tonic-gate 		 * if it's a  metadevice.
1445*0Sstevel@tonic-gate 		 */
1446*0Sstevel@tonic-gate 		if (md_getmajor(comp->un_dev) == md_major) {
1447*0Sstevel@tonic-gate 			minor_t	  comp_mnum = md_getminor(comp->un_dev);
1448*0Sstevel@tonic-gate 			md_unit_t *comp_un = MD_UNIT(comp_mnum);
1449*0Sstevel@tonic-gate 
1450*0Sstevel@tonic-gate 			md_reset_parent(comp->un_dev);
1451*0Sstevel@tonic-gate 			recids[rid++] = MD_RECID(comp_un);
1452*0Sstevel@tonic-gate 		}
1453*0Sstevel@tonic-gate 	}
1454*0Sstevel@tonic-gate 
1455*0Sstevel@tonic-gate 	comp->un_dev = nd->nd_dev;
1456*0Sstevel@tonic-gate 	comp->un_start_block = nd->nd_start_blk;
1457*0Sstevel@tonic-gate 
1458*0Sstevel@tonic-gate 	/*
1459*0Sstevel@tonic-gate 	 * For the new device, make sure to set the parent if it's a
1460*0Sstevel@tonic-gate 	 * metadevice.
1461*0Sstevel@tonic-gate 	 *
1462*0Sstevel@tonic-gate 	 * If we ever support using metadevices as hot spares, this
1463*0Sstevel@tonic-gate 	 * will need to be tested, and possibly moved into the
1464*0Sstevel@tonic-gate 	 * preceding "else" clause, immediately following the parent
1465*0Sstevel@tonic-gate 	 * reset block.  For now, it's convenient to leave it here and
1466*0Sstevel@tonic-gate 	 * only compress nd->nd_dev once.
1467*0Sstevel@tonic-gate 	 */
1468*0Sstevel@tonic-gate 	if (md_getmajor(comp->un_dev) == md_major) {
1469*0Sstevel@tonic-gate 		minor_t		comp_mnum = md_getminor(comp->un_dev);
1470*0Sstevel@tonic-gate 		md_unit_t	*comp_un = MD_UNIT(comp_mnum);
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate 		md_set_parent(comp->un_dev, MD_SID(un));
1473*0Sstevel@tonic-gate 		recids[rid++] = MD_RECID(comp_un);
1474*0Sstevel@tonic-gate 	}
1475*0Sstevel@tonic-gate 
1476*0Sstevel@tonic-gate 	recids[rid++] = un->c.un_record_id;
1477*0Sstevel@tonic-gate 	recids[rid++] = hs_id;
1478*0Sstevel@tonic-gate 	recids[rid] = 0;
1479*0Sstevel@tonic-gate 	*replace_done = stripe_replace_done;
1480*0Sstevel@tonic-gate 	return (0);
1481*0Sstevel@tonic-gate }
1482*0Sstevel@tonic-gate 
1483*0Sstevel@tonic-gate /*ARGSUSED*/
1484*0Sstevel@tonic-gate static intptr_t
1485*0Sstevel@tonic-gate stripe_hotspare_dev(
1486*0Sstevel@tonic-gate 	md_dev64_t	dev,
1487*0Sstevel@tonic-gate 	void		*junk,
1488*0Sstevel@tonic-gate 	int		ci,
1489*0Sstevel@tonic-gate 	mddb_recid_t	*recids,
1490*0Sstevel@tonic-gate 	int		nrecids,
1491*0Sstevel@tonic-gate 	void		(**replace_done)(),
1492*0Sstevel@tonic-gate 	void		**replace_data)
1493*0Sstevel@tonic-gate {
1494*0Sstevel@tonic-gate 	ms_unit_t	*un;
1495*0Sstevel@tonic-gate 	mdi_unit_t	*ui;
1496*0Sstevel@tonic-gate 	ms_comp_t	*comp;
1497*0Sstevel@tonic-gate 	int		row;
1498*0Sstevel@tonic-gate 	struct ms_row	*mdr;
1499*0Sstevel@tonic-gate 	ms_new_dev_t	nd;
1500*0Sstevel@tonic-gate 	int		err;
1501*0Sstevel@tonic-gate 	int		i;
1502*0Sstevel@tonic-gate 	minor_t		mnum;
1503*0Sstevel@tonic-gate 	set_t		setno;
1504*0Sstevel@tonic-gate 	int		cmpcount = 0;
1505*0Sstevel@tonic-gate 
1506*0Sstevel@tonic-gate 	mnum = md_getminor(dev);
1507*0Sstevel@tonic-gate 	ui = MDI_UNIT(mnum);
1508*0Sstevel@tonic-gate 	un = MD_UNIT(mnum);
1509*0Sstevel@tonic-gate 	setno = MD_MIN2SET(mnum);
1510*0Sstevel@tonic-gate 
1511*0Sstevel@tonic-gate 	if (md_get_setstatus(setno) & MD_SET_STALE)
1512*0Sstevel@tonic-gate 		return (1);
1513*0Sstevel@tonic-gate 
1514*0Sstevel@tonic-gate 	if (un->un_hsp_id == -1)
1515*0Sstevel@tonic-gate 		return (1);
1516*0Sstevel@tonic-gate 
1517*0Sstevel@tonic-gate 	for (row = 0; row < un->un_nrows; row++) {
1518*0Sstevel@tonic-gate 		mdr = &un->un_row[row];
1519*0Sstevel@tonic-gate 		if ((mdr->un_ncomp + cmpcount) > ci)
1520*0Sstevel@tonic-gate 			break;
1521*0Sstevel@tonic-gate 		cmpcount += mdr->un_ncomp;
1522*0Sstevel@tonic-gate 	}
1523*0Sstevel@tonic-gate 	ASSERT(row != un->un_nrows);
1524*0Sstevel@tonic-gate 
1525*0Sstevel@tonic-gate 	comp = (struct ms_comp *)((void *)&((char *)un)[un->un_ocomp]);
1526*0Sstevel@tonic-gate 	comp += ci;
1527*0Sstevel@tonic-gate 	/* Concatenations have a ncomp = 1 */
1528*0Sstevel@tonic-gate 	nd.nd_nblks = mdr->un_blocks / mdr->un_ncomp;
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate 	if ((un->c.un_flag & MD_LABELED) && (ci == 0))
1531*0Sstevel@tonic-gate 		nd.nd_labeled = 1;
1532*0Sstevel@tonic-gate 	else
1533*0Sstevel@tonic-gate 		nd.nd_labeled = 0;
1534*0Sstevel@tonic-gate 
1535*0Sstevel@tonic-gate again:
1536*0Sstevel@tonic-gate 	err = md_hot_spare_ifc(HS_GET, un->un_hsp_id, nd.nd_nblks,
1537*0Sstevel@tonic-gate 	    nd.nd_labeled, &nd.nd_hs_id, &nd.nd_key, &nd.nd_dev,
1538*0Sstevel@tonic-gate 	    &nd.nd_start_blk);
1539*0Sstevel@tonic-gate 
1540*0Sstevel@tonic-gate 	if (err) {
1541*0Sstevel@tonic-gate 		if (!stripe_replace_dev(dev, junk, ci, NULL, recids, nrecids,
1542*0Sstevel@tonic-gate 		    replace_done, replace_data)) {
1543*0Sstevel@tonic-gate 			mddb_commitrecs_wrapper(recids);
1544*0Sstevel@tonic-gate 			md_unit_writerexit(ui);
1545*0Sstevel@tonic-gate 		}
1546*0Sstevel@tonic-gate 		recids[0] = 0;
1547*0Sstevel@tonic-gate 		return (1);
1548*0Sstevel@tonic-gate 	}
1549*0Sstevel@tonic-gate 
1550*0Sstevel@tonic-gate 	if (stripe_replace_dev(dev, junk, ci, &nd, recids, nrecids,
1551*0Sstevel@tonic-gate 		replace_done, replace_data)) {
1552*0Sstevel@tonic-gate 
1553*0Sstevel@tonic-gate 		(void) md_hot_spare_ifc(HS_BAD, un->un_hsp_id, 0, 0,
1554*0Sstevel@tonic-gate 		    &nd.nd_hs_id, &nd.nd_key, NULL, NULL);
1555*0Sstevel@tonic-gate 		mddb_commitrec_wrapper(nd.nd_hs_id);
1556*0Sstevel@tonic-gate 		goto again;
1557*0Sstevel@tonic-gate 	}
1558*0Sstevel@tonic-gate 
1559*0Sstevel@tonic-gate 	/* Leave a slot for the null recid */
1560*0Sstevel@tonic-gate 	for (i = 0; i < (nrecids - 1); i++) {
1561*0Sstevel@tonic-gate 		if (recids[i] == 0) {
1562*0Sstevel@tonic-gate 			recids[i++] = nd.nd_hs_id;
1563*0Sstevel@tonic-gate 			recids[i] = 0;
1564*0Sstevel@tonic-gate 		}
1565*0Sstevel@tonic-gate 	}
1566*0Sstevel@tonic-gate 	return (0);
1567*0Sstevel@tonic-gate }
1568*0Sstevel@tonic-gate 
1569*0Sstevel@tonic-gate static int
1570*0Sstevel@tonic-gate stripe_imp_set(
1571*0Sstevel@tonic-gate 	set_t	setno
1572*0Sstevel@tonic-gate )
1573*0Sstevel@tonic-gate {
1574*0Sstevel@tonic-gate 
1575*0Sstevel@tonic-gate 	mddb_recid_t	recid;
1576*0Sstevel@tonic-gate 	int		i, row, c, gotsomething;
1577*0Sstevel@tonic-gate 	mddb_type_t	typ1;
1578*0Sstevel@tonic-gate 	mddb_de_ic_t	*dep;
1579*0Sstevel@tonic-gate 	mddb_rb32_t	*rbp;
1580*0Sstevel@tonic-gate 	ms_unit32_od_t	*un32;
1581*0Sstevel@tonic-gate 	ms_unit_t	*un64;
1582*0Sstevel@tonic-gate 	minor_t		*self_id;	/* minor needs to be updated */
1583*0Sstevel@tonic-gate 	md_parent_t	*parent_id;	/* parent needs to be updated */
1584*0Sstevel@tonic-gate 	mddb_recid_t	*record_id;	/* record id needs to be updated */
1585*0Sstevel@tonic-gate 	mddb_recid_t	*hsp_id;
1586*0Sstevel@tonic-gate 	ms_comp32_od_t	*comp32;
1587*0Sstevel@tonic-gate 	ms_comp_t	*comp64;
1588*0Sstevel@tonic-gate 
1589*0Sstevel@tonic-gate 
1590*0Sstevel@tonic-gate 	gotsomething = 0;
1591*0Sstevel@tonic-gate 
1592*0Sstevel@tonic-gate 	typ1 = (mddb_type_t)md_getshared_key(setno,
1593*0Sstevel@tonic-gate 	    stripe_md_ops.md_driver.md_drivername);
1594*0Sstevel@tonic-gate 	recid = mddb_makerecid(setno, 0);
1595*0Sstevel@tonic-gate 
1596*0Sstevel@tonic-gate 	while ((recid = mddb_getnextrec(recid, typ1, 0)) > 0) {
1597*0Sstevel@tonic-gate 		if (mddb_getrecprivate(recid) & MD_PRV_GOTIT)
1598*0Sstevel@tonic-gate 			continue;
1599*0Sstevel@tonic-gate 
1600*0Sstevel@tonic-gate 		dep = mddb_getrecdep(recid);
1601*0Sstevel@tonic-gate 		rbp = dep->de_rb;
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate 		if (rbp->rb_revision == MDDB_REV_RB) {
1604*0Sstevel@tonic-gate 			/*
1605*0Sstevel@tonic-gate 			 * Small device
1606*0Sstevel@tonic-gate 			 */
1607*0Sstevel@tonic-gate 			un32 = (ms_unit32_od_t *)mddb_getrecaddr(recid);
1608*0Sstevel@tonic-gate 			self_id = &(un32->c.un_self_id);
1609*0Sstevel@tonic-gate 			parent_id = &(un32->c.un_parent);
1610*0Sstevel@tonic-gate 			record_id = &(un32->c.un_record_id);
1611*0Sstevel@tonic-gate 			hsp_id = &(un32->un_hsp_id);
1612*0Sstevel@tonic-gate 
1613*0Sstevel@tonic-gate 			comp32 = (ms_comp32_od_t *)((void *)&((char *)un32)
1614*0Sstevel@tonic-gate 				[un32->un_ocomp]);
1615*0Sstevel@tonic-gate 			for (row = 0; row < un32->un_nrows; row++) {
1616*0Sstevel@tonic-gate 			    struct ms_row32_od *mdr = &un32->un_row[row];
1617*0Sstevel@tonic-gate 			    for (i = 0, c = mdr->un_icomp;
1618*0Sstevel@tonic-gate 				i < mdr->un_ncomp; i++) {
1619*0Sstevel@tonic-gate 				ms_comp32_od_t *mdc;
1620*0Sstevel@tonic-gate 				mdc = &comp32[c++];
1621*0Sstevel@tonic-gate 
1622*0Sstevel@tonic-gate 				if (!md_update_minor(setno, mddb_getsidenum
1623*0Sstevel@tonic-gate 				    (setno), mdc->un_key))
1624*0Sstevel@tonic-gate 					goto out;
1625*0Sstevel@tonic-gate 
1626*0Sstevel@tonic-gate 				if (mdc->un_mirror.ms_hs_id != 0)
1627*0Sstevel@tonic-gate 				    mdc->un_mirror.ms_hs_id = MAKERECID(
1628*0Sstevel@tonic-gate 				    setno, mdc->un_mirror.ms_hs_id);
1629*0Sstevel@tonic-gate 			    }
1630*0Sstevel@tonic-gate 			}
1631*0Sstevel@tonic-gate 		} else {
1632*0Sstevel@tonic-gate 			un64 = (ms_unit_t *)mddb_getrecaddr(recid);
1633*0Sstevel@tonic-gate 			self_id = &(un64->c.un_self_id);
1634*0Sstevel@tonic-gate 			parent_id = &(un64->c.un_parent);
1635*0Sstevel@tonic-gate 			record_id = &(un64->c.un_record_id);
1636*0Sstevel@tonic-gate 			hsp_id = &(un64->un_hsp_id);
1637*0Sstevel@tonic-gate 
1638*0Sstevel@tonic-gate 			comp64 = (ms_comp_t *)((void *)&((char *)un64)
1639*0Sstevel@tonic-gate 				[un64->un_ocomp]);
1640*0Sstevel@tonic-gate 			for (row = 0; row < un64->un_nrows; row++) {
1641*0Sstevel@tonic-gate 			    struct ms_row *mdr = &un64->un_row[row];
1642*0Sstevel@tonic-gate 			    for (i = 0, c = mdr->un_icomp;
1643*0Sstevel@tonic-gate 				i < mdr->un_ncomp; i++) {
1644*0Sstevel@tonic-gate 				ms_comp_t *mdc;
1645*0Sstevel@tonic-gate 				mdc = &comp64[c++];
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate 				if (!md_update_minor(setno, mddb_getsidenum
1648*0Sstevel@tonic-gate 				    (setno), mdc->un_key))
1649*0Sstevel@tonic-gate 					goto out;
1650*0Sstevel@tonic-gate 
1651*0Sstevel@tonic-gate 				if (mdc->un_mirror.ms_hs_id != 0)
1652*0Sstevel@tonic-gate 				    mdc->un_mirror.ms_hs_id = MAKERECID(
1653*0Sstevel@tonic-gate 				    setno, mdc->un_mirror.ms_hs_id);
1654*0Sstevel@tonic-gate 			    }
1655*0Sstevel@tonic-gate 			}
1656*0Sstevel@tonic-gate 		}
1657*0Sstevel@tonic-gate 
1658*0Sstevel@tonic-gate 		/*
1659*0Sstevel@tonic-gate 		 * Update unit with the imported setno
1660*0Sstevel@tonic-gate 		 *
1661*0Sstevel@tonic-gate 		 */
1662*0Sstevel@tonic-gate 		mddb_setrecprivate(recid, MD_PRV_GOTIT);
1663*0Sstevel@tonic-gate 
1664*0Sstevel@tonic-gate 		*self_id = MD_MKMIN(setno, MD_MIN2UNIT(*self_id));
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 		if (*hsp_id != -1)
1667*0Sstevel@tonic-gate 			*hsp_id = MAKERECID(setno, DBID(*hsp_id));
1668*0Sstevel@tonic-gate 
1669*0Sstevel@tonic-gate 		if (*parent_id != MD_NO_PARENT)
1670*0Sstevel@tonic-gate 			*parent_id = MD_MKMIN(setno, MD_MIN2UNIT(*parent_id));
1671*0Sstevel@tonic-gate 		*record_id = MAKERECID(setno, DBID(*record_id));
1672*0Sstevel@tonic-gate 
1673*0Sstevel@tonic-gate 		gotsomething = 1;
1674*0Sstevel@tonic-gate 	}
1675*0Sstevel@tonic-gate 
1676*0Sstevel@tonic-gate out:
1677*0Sstevel@tonic-gate 	return (gotsomething);
1678*0Sstevel@tonic-gate }
1679*0Sstevel@tonic-gate 
1680*0Sstevel@tonic-gate static md_named_services_t stripe_named_services[] = {
1681*0Sstevel@tonic-gate 	{stripe_shared_by_blk,			"shared by blk"		    },
1682*0Sstevel@tonic-gate 	{stripe_shared_by_indx,			"shared by indx"	    },
1683*0Sstevel@tonic-gate 	{stripe_component_count,		"get component count"	    },
1684*0Sstevel@tonic-gate 	{stripe_block_count_skip_size,		"get block count skip size" },
1685*0Sstevel@tonic-gate 	{stripe_get_dev,			"get device"		    },
1686*0Sstevel@tonic-gate 	{stripe_replace_dev,			"replace device"	    },
1687*0Sstevel@tonic-gate 	{stripe_hotspare_dev,			"hotspare device"	    },
1688*0Sstevel@tonic-gate 	{stripe_rename_check,			MDRNM_CHECK		    },
1689*0Sstevel@tonic-gate 	{NULL,					0}
1690*0Sstevel@tonic-gate };
1691*0Sstevel@tonic-gate 
1692*0Sstevel@tonic-gate md_ops_t stripe_md_ops = {
1693*0Sstevel@tonic-gate 	stripe_open,		/* open */
1694*0Sstevel@tonic-gate 	stripe_close,		/* close */
1695*0Sstevel@tonic-gate 	md_stripe_strategy,	/* strategy */
1696*0Sstevel@tonic-gate 	NULL,			/* print */
1697*0Sstevel@tonic-gate 	stripe_dump,		/* dump */
1698*0Sstevel@tonic-gate 	NULL,			/* read */
1699*0Sstevel@tonic-gate 	NULL,			/* write */
1700*0Sstevel@tonic-gate 	md_stripe_ioctl,	/* stripe_ioctl, */
1701*0Sstevel@tonic-gate 	stripe_snarf,		/* stripe_snarf */
1702*0Sstevel@tonic-gate 	stripe_halt,		/* stripe_halt */
1703*0Sstevel@tonic-gate 	NULL,			/* aread */
1704*0Sstevel@tonic-gate 	NULL,			/* awrite */
1705*0Sstevel@tonic-gate 	stripe_imp_set,		/* import set */
1706*0Sstevel@tonic-gate 	stripe_named_services
1707*0Sstevel@tonic-gate };
1708*0Sstevel@tonic-gate 
1709*0Sstevel@tonic-gate static void
1710*0Sstevel@tonic-gate init_init()
1711*0Sstevel@tonic-gate {
1712*0Sstevel@tonic-gate 	md_stripe_mcs_buf_off = sizeof (md_scs_t) - sizeof (buf_t);
1713*0Sstevel@tonic-gate 
1714*0Sstevel@tonic-gate 	stripe_parent_cache = kmem_cache_create("md_stripe_parent",
1715*0Sstevel@tonic-gate 	    sizeof (md_sps_t), 0, stripe_parent_constructor,
1716*0Sstevel@tonic-gate 	    stripe_parent_destructor, stripe_run_queue, NULL, NULL,
1717*0Sstevel@tonic-gate 	    0);
1718*0Sstevel@tonic-gate 	stripe_child_cache = kmem_cache_create("md_stripe_child",
1719*0Sstevel@tonic-gate 	    sizeof (md_scs_t) - sizeof (buf_t) + biosize(), 0,
1720*0Sstevel@tonic-gate 	    stripe_child_constructor, stripe_child_destructor,
1721*0Sstevel@tonic-gate 	    stripe_run_queue, NULL, NULL, 0);
1722*0Sstevel@tonic-gate }
1723*0Sstevel@tonic-gate 
1724*0Sstevel@tonic-gate static void
1725*0Sstevel@tonic-gate fini_uninit()
1726*0Sstevel@tonic-gate {
1727*0Sstevel@tonic-gate 	kmem_cache_destroy(stripe_parent_cache);
1728*0Sstevel@tonic-gate 	kmem_cache_destroy(stripe_child_cache);
1729*0Sstevel@tonic-gate 	stripe_parent_cache = stripe_child_cache = NULL;
1730*0Sstevel@tonic-gate }
1731*0Sstevel@tonic-gate 
1732*0Sstevel@tonic-gate /* define the module linkage */
1733*0Sstevel@tonic-gate MD_PLUGIN_MISC_MODULE("stripes module %I%", init_init(), fini_uninit())
1734