xref: /onnv-gate/usr/src/uts/sun4v/io/dr_mem.c (revision 10106:b235491976d3)
1*10106SJason.Beloro@Sun.COM /*
2*10106SJason.Beloro@Sun.COM  * CDDL HEADER START
3*10106SJason.Beloro@Sun.COM  *
4*10106SJason.Beloro@Sun.COM  * The contents of this file are subject to the terms of the
5*10106SJason.Beloro@Sun.COM  * Common Development and Distribution License (the "License").
6*10106SJason.Beloro@Sun.COM  * You may not use this file except in compliance with the License.
7*10106SJason.Beloro@Sun.COM  *
8*10106SJason.Beloro@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10106SJason.Beloro@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10106SJason.Beloro@Sun.COM  * See the License for the specific language governing permissions
11*10106SJason.Beloro@Sun.COM  * and limitations under the License.
12*10106SJason.Beloro@Sun.COM  *
13*10106SJason.Beloro@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10106SJason.Beloro@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10106SJason.Beloro@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10106SJason.Beloro@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10106SJason.Beloro@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10106SJason.Beloro@Sun.COM  *
19*10106SJason.Beloro@Sun.COM  * CDDL HEADER END
20*10106SJason.Beloro@Sun.COM  */
21*10106SJason.Beloro@Sun.COM 
22*10106SJason.Beloro@Sun.COM /*
23*10106SJason.Beloro@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*10106SJason.Beloro@Sun.COM  * Use is subject to license terms.
25*10106SJason.Beloro@Sun.COM  */
26*10106SJason.Beloro@Sun.COM 
27*10106SJason.Beloro@Sun.COM /*
28*10106SJason.Beloro@Sun.COM  * sun4v Memory DR Module
29*10106SJason.Beloro@Sun.COM  */
30*10106SJason.Beloro@Sun.COM 
31*10106SJason.Beloro@Sun.COM 
32*10106SJason.Beloro@Sun.COM #include <sys/types.h>
33*10106SJason.Beloro@Sun.COM #include <sys/cmn_err.h>
34*10106SJason.Beloro@Sun.COM #include <sys/vmem.h>
35*10106SJason.Beloro@Sun.COM #include <sys/kmem.h>
36*10106SJason.Beloro@Sun.COM #include <sys/systm.h>
37*10106SJason.Beloro@Sun.COM #include <sys/machsystm.h>	/* for page_freelist_coalesce() */
38*10106SJason.Beloro@Sun.COM #include <sys/errno.h>
39*10106SJason.Beloro@Sun.COM #include <sys/memnode.h>
40*10106SJason.Beloro@Sun.COM #include <sys/memlist.h>
41*10106SJason.Beloro@Sun.COM #include <sys/memlist_impl.h>
42*10106SJason.Beloro@Sun.COM #include <sys/tuneable.h>
43*10106SJason.Beloro@Sun.COM #include <sys/proc.h>
44*10106SJason.Beloro@Sun.COM #include <sys/disp.h>
45*10106SJason.Beloro@Sun.COM #include <sys/debug.h>
46*10106SJason.Beloro@Sun.COM #include <sys/vm.h>
47*10106SJason.Beloro@Sun.COM #include <sys/callb.h>
48*10106SJason.Beloro@Sun.COM #include <sys/memlist_plat.h>	/* for installed_top_size() */
49*10106SJason.Beloro@Sun.COM #include <sys/condvar_impl.h>	/* for CV_HAS_WAITERS() */
50*10106SJason.Beloro@Sun.COM #include <sys/dumphdr.h>	/* for dump_resize() */
51*10106SJason.Beloro@Sun.COM #include <sys/atomic.h>		/* for use in stats collection */
52*10106SJason.Beloro@Sun.COM #include <sys/rwlock.h>
53*10106SJason.Beloro@Sun.COM #include <vm/seg_kmem.h>
54*10106SJason.Beloro@Sun.COM #include <vm/seg_kpm.h>
55*10106SJason.Beloro@Sun.COM #include <vm/page.h>
56*10106SJason.Beloro@Sun.COM #include <vm/vm_dep.h>
57*10106SJason.Beloro@Sun.COM #define	SUNDDI_IMPL		/* so sunddi.h will not redefine splx() et al */
58*10106SJason.Beloro@Sun.COM #include <sys/sunddi.h>
59*10106SJason.Beloro@Sun.COM #include <sys/mem_config.h>
60*10106SJason.Beloro@Sun.COM #include <sys/mem_cage.h>
61*10106SJason.Beloro@Sun.COM #include <sys/lgrp.h>
62*10106SJason.Beloro@Sun.COM #include <sys/ddi.h>
63*10106SJason.Beloro@Sun.COM 
64*10106SJason.Beloro@Sun.COM #include <sys/modctl.h>
65*10106SJason.Beloro@Sun.COM #include <sys/sysevent/dr.h>
66*10106SJason.Beloro@Sun.COM #include <sys/mach_descrip.h>
67*10106SJason.Beloro@Sun.COM #include <sys/mdesc.h>
68*10106SJason.Beloro@Sun.COM #include <sys/ds.h>
69*10106SJason.Beloro@Sun.COM #include <sys/drctl.h>
70*10106SJason.Beloro@Sun.COM #include <sys/dr_util.h>
71*10106SJason.Beloro@Sun.COM #include <sys/dr_mem.h>
72*10106SJason.Beloro@Sun.COM 
73*10106SJason.Beloro@Sun.COM 
74*10106SJason.Beloro@Sun.COM /*
75*10106SJason.Beloro@Sun.COM  * DR operations are subject to Memory Alignment restrictions
76*10106SJason.Beloro@Sun.COM  * for both address and the size of the request.
77*10106SJason.Beloro@Sun.COM  */
78*10106SJason.Beloro@Sun.COM #define	MA_ADDR	0x10000000	/* addr alignment 256M */
79*10106SJason.Beloro@Sun.COM #define	MA_SIZE	0x10000000	/* size alignment 256M */
80*10106SJason.Beloro@Sun.COM 
81*10106SJason.Beloro@Sun.COM #define	MBLK_IS_VALID(m) \
82*10106SJason.Beloro@Sun.COM 	(IS_P2ALIGNED((m)->addr, MA_ADDR) && IS_P2ALIGNED((m)->size, MA_SIZE))
83*10106SJason.Beloro@Sun.COM 
84*10106SJason.Beloro@Sun.COM static memhandle_t dr_mh;	/* memory handle for delete */
85*10106SJason.Beloro@Sun.COM 
86*10106SJason.Beloro@Sun.COM static struct modlmisc modlmisc = {
87*10106SJason.Beloro@Sun.COM 	&mod_miscops,
88*10106SJason.Beloro@Sun.COM 	"sun4v memory DR"
89*10106SJason.Beloro@Sun.COM };
90*10106SJason.Beloro@Sun.COM 
91*10106SJason.Beloro@Sun.COM static struct modlinkage modlinkage = {
92*10106SJason.Beloro@Sun.COM 	MODREV_1,
93*10106SJason.Beloro@Sun.COM 	(void *)&modlmisc,
94*10106SJason.Beloro@Sun.COM 	NULL
95*10106SJason.Beloro@Sun.COM };
96*10106SJason.Beloro@Sun.COM 
97*10106SJason.Beloro@Sun.COM static int dr_mem_allow_unload = 0;
98*10106SJason.Beloro@Sun.COM 
99*10106SJason.Beloro@Sun.COM typedef int (*fn_t)(dr_mem_blk_t *, int *);
100*10106SJason.Beloro@Sun.COM 
101*10106SJason.Beloro@Sun.COM /*
102*10106SJason.Beloro@Sun.COM  * Global Domain Services (DS) Handle
103*10106SJason.Beloro@Sun.COM  */
104*10106SJason.Beloro@Sun.COM static ds_svc_hdl_t ds_handle;
105*10106SJason.Beloro@Sun.COM 
106*10106SJason.Beloro@Sun.COM /*
107*10106SJason.Beloro@Sun.COM  * Supported DS Capability Versions
108*10106SJason.Beloro@Sun.COM  */
109*10106SJason.Beloro@Sun.COM static ds_ver_t		dr_mem_vers[] = { { 1, 0 } };
110*10106SJason.Beloro@Sun.COM #define	DR_MEM_NVERS	(sizeof (dr_mem_vers) / sizeof (dr_mem_vers[0]))
111*10106SJason.Beloro@Sun.COM 
112*10106SJason.Beloro@Sun.COM /*
113*10106SJason.Beloro@Sun.COM  * DS Capability Description
114*10106SJason.Beloro@Sun.COM  */
115*10106SJason.Beloro@Sun.COM static ds_capability_t dr_mem_cap = {
116*10106SJason.Beloro@Sun.COM 	DR_MEM_DS_ID,		/* svc_id */
117*10106SJason.Beloro@Sun.COM 	dr_mem_vers,		/* vers */
118*10106SJason.Beloro@Sun.COM 	DR_MEM_NVERS		/* nvers */
119*10106SJason.Beloro@Sun.COM };
120*10106SJason.Beloro@Sun.COM 
121*10106SJason.Beloro@Sun.COM /*
122*10106SJason.Beloro@Sun.COM  * DS Callbacks
123*10106SJason.Beloro@Sun.COM  */
124*10106SJason.Beloro@Sun.COM static void dr_mem_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
125*10106SJason.Beloro@Sun.COM static void dr_mem_unreg_handler(ds_cb_arg_t arg);
126*10106SJason.Beloro@Sun.COM static void dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
127*10106SJason.Beloro@Sun.COM 
128*10106SJason.Beloro@Sun.COM /*
129*10106SJason.Beloro@Sun.COM  * DS Client Ops Vector
130*10106SJason.Beloro@Sun.COM  */
131*10106SJason.Beloro@Sun.COM static ds_clnt_ops_t dr_mem_ops = {
132*10106SJason.Beloro@Sun.COM 	dr_mem_reg_handler,	/* ds_reg_cb */
133*10106SJason.Beloro@Sun.COM 	dr_mem_unreg_handler,	/* ds_unreg_cb */
134*10106SJason.Beloro@Sun.COM 	dr_mem_data_handler,	/* ds_data_cb */
135*10106SJason.Beloro@Sun.COM 	NULL			/* cb_arg */
136*10106SJason.Beloro@Sun.COM };
137*10106SJason.Beloro@Sun.COM 
138*10106SJason.Beloro@Sun.COM /*
139*10106SJason.Beloro@Sun.COM  * Operation Results
140*10106SJason.Beloro@Sun.COM  *
141*10106SJason.Beloro@Sun.COM  * Used internally to gather results while an operation on a
142*10106SJason.Beloro@Sun.COM  * list of mblks is in progress. In particular, it is used to
143*10106SJason.Beloro@Sun.COM  * keep track of which mblks have already failed so that they are
144*10106SJason.Beloro@Sun.COM  * not processed further, and the manner in which they failed.
145*10106SJason.Beloro@Sun.COM  */
146*10106SJason.Beloro@Sun.COM typedef struct {
147*10106SJason.Beloro@Sun.COM 	uint64_t	addr;
148*10106SJason.Beloro@Sun.COM 	uint64_t	size;
149*10106SJason.Beloro@Sun.COM 	uint32_t	result;
150*10106SJason.Beloro@Sun.COM 	uint32_t	status;
151*10106SJason.Beloro@Sun.COM 	char		*string;
152*10106SJason.Beloro@Sun.COM } dr_mem_res_t;
153*10106SJason.Beloro@Sun.COM 
154*10106SJason.Beloro@Sun.COM static char *
155*10106SJason.Beloro@Sun.COM dr_mem_estr[] = {
156*10106SJason.Beloro@Sun.COM 	"operation succeeded",		/* DR_MEM_RES_OK */
157*10106SJason.Beloro@Sun.COM 	"operation failed",		/* DR_MEM_RES_FAILURE */
158*10106SJason.Beloro@Sun.COM 	"operation was blocked",	/* DR_MEM_RES_BLOCKED */
159*10106SJason.Beloro@Sun.COM 	"memory not defined in MD",	/* DR_MEM_RES_NOT_IN_MD */
160*10106SJason.Beloro@Sun.COM 	"memory already in use",	/* DR_MEM_RES_ESPAN */
161*10106SJason.Beloro@Sun.COM 	"memory access test failed",	/* DR_MEM_RES_EFAULT */
162*10106SJason.Beloro@Sun.COM 	"resource not available",	/* DR_MEM_RES_ERESOURCE */
163*10106SJason.Beloro@Sun.COM 	"permanent pages in span",	/* DR_MEM_RES_PERM */
164*10106SJason.Beloro@Sun.COM 	"memory span busy",		/* DR_MEM_RES_EBUSY */
165*10106SJason.Beloro@Sun.COM 	"VM viability test failed",	/* DR_MEM_RES_ENOTVIABLE */
166*10106SJason.Beloro@Sun.COM 	"no pages to unconfigure",	/* DR_MEM_RES_ENOWORK */
167*10106SJason.Beloro@Sun.COM 	"operation cancelled",		/* DR_MEM_RES_ECANCELLED */
168*10106SJason.Beloro@Sun.COM 	"operation refused",		/* DR_MEM_RES_EREFUSED */
169*10106SJason.Beloro@Sun.COM 	"memory span duplicate",	/* DR_MEM_RES_EDUP */
170*10106SJason.Beloro@Sun.COM 	"invalid argument"		/* DR_MEM_RES_EINVAL */
171*10106SJason.Beloro@Sun.COM };
172*10106SJason.Beloro@Sun.COM 
173*10106SJason.Beloro@Sun.COM typedef struct {
174*10106SJason.Beloro@Sun.COM 	kcondvar_t cond;
175*10106SJason.Beloro@Sun.COM 	kmutex_t lock;
176*10106SJason.Beloro@Sun.COM 	int error;
177*10106SJason.Beloro@Sun.COM 	int done;
178*10106SJason.Beloro@Sun.COM } mem_sync_t;
179*10106SJason.Beloro@Sun.COM 
180*10106SJason.Beloro@Sun.COM /*
181*10106SJason.Beloro@Sun.COM  * Internal Functions
182*10106SJason.Beloro@Sun.COM  */
183*10106SJason.Beloro@Sun.COM static int dr_mem_init(void);
184*10106SJason.Beloro@Sun.COM static int dr_mem_fini(void);
185*10106SJason.Beloro@Sun.COM 
186*10106SJason.Beloro@Sun.COM static int dr_mem_list_wrk(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
187*10106SJason.Beloro@Sun.COM static int dr_mem_list_query(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
188*10106SJason.Beloro@Sun.COM static int dr_mem_del_stat(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
189*10106SJason.Beloro@Sun.COM static int dr_mem_del_cancel(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
190*10106SJason.Beloro@Sun.COM 
191*10106SJason.Beloro@Sun.COM static int dr_mem_unconfigure(dr_mem_blk_t *, int *);
192*10106SJason.Beloro@Sun.COM static int dr_mem_configure(dr_mem_blk_t *, int *);
193*10106SJason.Beloro@Sun.COM static void dr_mem_query(dr_mem_blk_t *, dr_mem_query_t *);
194*10106SJason.Beloro@Sun.COM 
195*10106SJason.Beloro@Sun.COM static dr_mem_res_t *dr_mem_res_array_init(dr_mem_hdr_t *, drctl_rsrc_t *, int);
196*10106SJason.Beloro@Sun.COM static void dr_mem_res_array_fini(dr_mem_res_t *res, int nres);
197*10106SJason.Beloro@Sun.COM static size_t dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res,
198*10106SJason.Beloro@Sun.COM     dr_mem_hdr_t **respp);
199*10106SJason.Beloro@Sun.COM 
200*10106SJason.Beloro@Sun.COM static int dr_mem_find(dr_mem_blk_t *mbp);
201*10106SJason.Beloro@Sun.COM static mde_cookie_t dr_mem_find_node_md(dr_mem_blk_t *, md_t *, mde_cookie_t *);
202*10106SJason.Beloro@Sun.COM 
203*10106SJason.Beloro@Sun.COM static int mem_add(pfn_t, pgcnt_t);
204*10106SJason.Beloro@Sun.COM static int mem_del(pfn_t, pgcnt_t);
205*10106SJason.Beloro@Sun.COM 
206*10106SJason.Beloro@Sun.COM static size_t rsvaddsz;
207*10106SJason.Beloro@Sun.COM extern void i_dr_mem_init(uint64_t *);
208*10106SJason.Beloro@Sun.COM extern void i_dr_mem_fini();
209*10106SJason.Beloro@Sun.COM extern void i_dr_mem_update();
210*10106SJason.Beloro@Sun.COM extern int kphysm_add_memory_dynamic(pfn_t, pgcnt_t);
211*10106SJason.Beloro@Sun.COM 
212*10106SJason.Beloro@Sun.COM int
213*10106SJason.Beloro@Sun.COM _init(void)
214*10106SJason.Beloro@Sun.COM {
215*10106SJason.Beloro@Sun.COM 	int	status;
216*10106SJason.Beloro@Sun.COM 
217*10106SJason.Beloro@Sun.COM 	/* check that Memory DR is enabled */
218*10106SJason.Beloro@Sun.COM 	if (dr_is_disabled(DR_TYPE_MEM))
219*10106SJason.Beloro@Sun.COM 		return (ENOTSUP);
220*10106SJason.Beloro@Sun.COM 
221*10106SJason.Beloro@Sun.COM 	if ((status = dr_mem_init()) != 0) {
222*10106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "Memory DR initialization failed");
223*10106SJason.Beloro@Sun.COM 		return (status);
224*10106SJason.Beloro@Sun.COM 	}
225*10106SJason.Beloro@Sun.COM 
226*10106SJason.Beloro@Sun.COM 	if ((status = mod_install(&modlinkage)) != 0) {
227*10106SJason.Beloro@Sun.COM 		(void) dr_mem_fini();
228*10106SJason.Beloro@Sun.COM 	}
229*10106SJason.Beloro@Sun.COM 
230*10106SJason.Beloro@Sun.COM 	return (status);
231*10106SJason.Beloro@Sun.COM }
232*10106SJason.Beloro@Sun.COM 
233*10106SJason.Beloro@Sun.COM int
234*10106SJason.Beloro@Sun.COM _info(struct modinfo *modinfop)
235*10106SJason.Beloro@Sun.COM {
236*10106SJason.Beloro@Sun.COM 	return (mod_info(&modlinkage, modinfop));
237*10106SJason.Beloro@Sun.COM }
238*10106SJason.Beloro@Sun.COM 
239*10106SJason.Beloro@Sun.COM int
240*10106SJason.Beloro@Sun.COM _fini(void)
241*10106SJason.Beloro@Sun.COM {
242*10106SJason.Beloro@Sun.COM 	int	status;
243*10106SJason.Beloro@Sun.COM 
244*10106SJason.Beloro@Sun.COM 	if (dr_mem_allow_unload == 0)
245*10106SJason.Beloro@Sun.COM 		return (EBUSY);
246*10106SJason.Beloro@Sun.COM 
247*10106SJason.Beloro@Sun.COM 	if ((status = mod_remove(&modlinkage)) == 0) {
248*10106SJason.Beloro@Sun.COM 		(void) dr_mem_fini();
249*10106SJason.Beloro@Sun.COM 	}
250*10106SJason.Beloro@Sun.COM 
251*10106SJason.Beloro@Sun.COM 	return (status);
252*10106SJason.Beloro@Sun.COM }
253*10106SJason.Beloro@Sun.COM 
254*10106SJason.Beloro@Sun.COM static int
255*10106SJason.Beloro@Sun.COM dr_mem_init(void)
256*10106SJason.Beloro@Sun.COM {
257*10106SJason.Beloro@Sun.COM 	int rv;
258*10106SJason.Beloro@Sun.COM 
259*10106SJason.Beloro@Sun.COM 	if ((rv = ds_cap_init(&dr_mem_cap, &dr_mem_ops)) != 0) {
260*10106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "dr_mem: ds_cap_init failed: %d", rv);
261*10106SJason.Beloro@Sun.COM 		return (rv);
262*10106SJason.Beloro@Sun.COM 	}
263*10106SJason.Beloro@Sun.COM 
264*10106SJason.Beloro@Sun.COM 	i_dr_mem_init(&rsvaddsz);
265*10106SJason.Beloro@Sun.COM 
266*10106SJason.Beloro@Sun.COM 	return (0);
267*10106SJason.Beloro@Sun.COM }
268*10106SJason.Beloro@Sun.COM 
269*10106SJason.Beloro@Sun.COM static int
270*10106SJason.Beloro@Sun.COM dr_mem_fini(void)
271*10106SJason.Beloro@Sun.COM {
272*10106SJason.Beloro@Sun.COM 	int rv;
273*10106SJason.Beloro@Sun.COM 
274*10106SJason.Beloro@Sun.COM 	i_dr_mem_fini();
275*10106SJason.Beloro@Sun.COM 
276*10106SJason.Beloro@Sun.COM 	if ((rv = ds_cap_fini(&dr_mem_cap)) != 0) {
277*10106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "dr_mem: ds_cap_fini failed: %d", rv);
278*10106SJason.Beloro@Sun.COM 	}
279*10106SJason.Beloro@Sun.COM 
280*10106SJason.Beloro@Sun.COM 	return (rv);
281*10106SJason.Beloro@Sun.COM }
282*10106SJason.Beloro@Sun.COM 
283*10106SJason.Beloro@Sun.COM static void
284*10106SJason.Beloro@Sun.COM dr_mem_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
285*10106SJason.Beloro@Sun.COM {
286*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
287*10106SJason.Beloro@Sun.COM 	    ver->major, ver->minor, hdl);
288*10106SJason.Beloro@Sun.COM 
289*10106SJason.Beloro@Sun.COM 	ds_handle = hdl;
290*10106SJason.Beloro@Sun.COM }
291*10106SJason.Beloro@Sun.COM 
292*10106SJason.Beloro@Sun.COM static void
293*10106SJason.Beloro@Sun.COM dr_mem_unreg_handler(ds_cb_arg_t arg)
294*10106SJason.Beloro@Sun.COM {
295*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("unreg_handler: arg=0x%p\n", arg);
296*10106SJason.Beloro@Sun.COM 
297*10106SJason.Beloro@Sun.COM 	ds_handle = DS_INVALID_HDL;
298*10106SJason.Beloro@Sun.COM }
299*10106SJason.Beloro@Sun.COM 
300*10106SJason.Beloro@Sun.COM /*ARGSUSED*/
301*10106SJason.Beloro@Sun.COM static void
302*10106SJason.Beloro@Sun.COM dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
303*10106SJason.Beloro@Sun.COM {
304*10106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*req = buf;
305*10106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	err_resp;
306*10106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*resp = &err_resp;
307*10106SJason.Beloro@Sun.COM 	int		resp_len = 0;
308*10106SJason.Beloro@Sun.COM 	int		rv = EINVAL;
309*10106SJason.Beloro@Sun.COM 
310*10106SJason.Beloro@Sun.COM 	/*
311*10106SJason.Beloro@Sun.COM 	 * Sanity check the message
312*10106SJason.Beloro@Sun.COM 	 */
313*10106SJason.Beloro@Sun.COM 	if (buflen < sizeof (dr_mem_hdr_t)) {
314*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("incoming message short: expected at least %ld "
315*10106SJason.Beloro@Sun.COM 		    "bytes, received %ld\n", sizeof (dr_mem_hdr_t), buflen);
316*10106SJason.Beloro@Sun.COM 		goto done;
317*10106SJason.Beloro@Sun.COM 	}
318*10106SJason.Beloro@Sun.COM 
319*10106SJason.Beloro@Sun.COM 	if (req == NULL) {
320*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("empty message: expected at least %ld bytes\n",
321*10106SJason.Beloro@Sun.COM 		    sizeof (dr_mem_hdr_t));
322*10106SJason.Beloro@Sun.COM 		goto done;
323*10106SJason.Beloro@Sun.COM 	}
324*10106SJason.Beloro@Sun.COM 
325*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("incoming request:\n");
326*10106SJason.Beloro@Sun.COM 	DR_DBG_DUMP_MSG(buf, buflen);
327*10106SJason.Beloro@Sun.COM 
328*10106SJason.Beloro@Sun.COM 	/*
329*10106SJason.Beloro@Sun.COM 	 * Process the command
330*10106SJason.Beloro@Sun.COM 	 */
331*10106SJason.Beloro@Sun.COM 	switch (req->msg_type) {
332*10106SJason.Beloro@Sun.COM 	case DR_MEM_CONFIGURE:
333*10106SJason.Beloro@Sun.COM 	case DR_MEM_UNCONFIGURE:
334*10106SJason.Beloro@Sun.COM 		if (req->msg_arg == 0) {
335*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("No mblks specified for operation\n");
336*10106SJason.Beloro@Sun.COM 			goto done;
337*10106SJason.Beloro@Sun.COM 		}
338*10106SJason.Beloro@Sun.COM 		if ((rv = dr_mem_list_wrk(req, &resp, &resp_len)) != 0) {
339*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("%s failed (%d)\n",
340*10106SJason.Beloro@Sun.COM 			    (req->msg_type == DR_MEM_CONFIGURE) ?
341*10106SJason.Beloro@Sun.COM 			    "Memory configure" : "Memory unconfigure", rv);
342*10106SJason.Beloro@Sun.COM 		}
343*10106SJason.Beloro@Sun.COM 		break;
344*10106SJason.Beloro@Sun.COM 
345*10106SJason.Beloro@Sun.COM 	case DR_MEM_UNCONF_STATUS:
346*10106SJason.Beloro@Sun.COM 		if ((rv = dr_mem_del_stat(req, &resp, &resp_len)) != 0)
347*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Memory delete status failed (%d)\n", rv);
348*10106SJason.Beloro@Sun.COM 		break;
349*10106SJason.Beloro@Sun.COM 
350*10106SJason.Beloro@Sun.COM 	case DR_MEM_UNCONF_CANCEL:
351*10106SJason.Beloro@Sun.COM 		if ((rv = dr_mem_del_cancel(req, &resp, &resp_len)) != 0)
352*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Memory delete cancel failed (%d)\n", rv);
353*10106SJason.Beloro@Sun.COM 		break;
354*10106SJason.Beloro@Sun.COM 
355*10106SJason.Beloro@Sun.COM 	case DR_MEM_QUERY:
356*10106SJason.Beloro@Sun.COM 		if (req->msg_arg == 0) {
357*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("No mblks specified for operation\n");
358*10106SJason.Beloro@Sun.COM 			goto done;
359*10106SJason.Beloro@Sun.COM 		}
360*10106SJason.Beloro@Sun.COM 		if ((rv = dr_mem_list_query(req, &resp, &resp_len)) != 0)
361*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Memory query failed (%d)\n", rv);
362*10106SJason.Beloro@Sun.COM 		break;
363*10106SJason.Beloro@Sun.COM 
364*10106SJason.Beloro@Sun.COM 	default:
365*10106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "unsupported memory DR operation (%d)",
366*10106SJason.Beloro@Sun.COM 		    req->msg_type);
367*10106SJason.Beloro@Sun.COM 		break;
368*10106SJason.Beloro@Sun.COM 	}
369*10106SJason.Beloro@Sun.COM 
370*10106SJason.Beloro@Sun.COM done:
371*10106SJason.Beloro@Sun.COM 	/* check if an error occurred */
372*10106SJason.Beloro@Sun.COM 	if (resp == &err_resp) {
373*10106SJason.Beloro@Sun.COM 		resp->req_num = (req) ? req->req_num : 0;
374*10106SJason.Beloro@Sun.COM 		resp->msg_type = DR_MEM_ERROR;
375*10106SJason.Beloro@Sun.COM 		resp->msg_arg = rv;
376*10106SJason.Beloro@Sun.COM 		resp_len = sizeof (dr_mem_hdr_t);
377*10106SJason.Beloro@Sun.COM 	}
378*10106SJason.Beloro@Sun.COM 
379*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("outgoing response:\n");
380*10106SJason.Beloro@Sun.COM 	DR_DBG_DUMP_MSG(resp, resp_len);
381*10106SJason.Beloro@Sun.COM 
382*10106SJason.Beloro@Sun.COM 	/* send back the response */
383*10106SJason.Beloro@Sun.COM 	if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
384*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("ds_send failed\n");
385*10106SJason.Beloro@Sun.COM 	}
386*10106SJason.Beloro@Sun.COM 
387*10106SJason.Beloro@Sun.COM 	/* free any allocated memory */
388*10106SJason.Beloro@Sun.COM 	if (resp != &err_resp) {
389*10106SJason.Beloro@Sun.COM 		kmem_free(resp, resp_len);
390*10106SJason.Beloro@Sun.COM 	}
391*10106SJason.Beloro@Sun.COM }
392*10106SJason.Beloro@Sun.COM 
393*10106SJason.Beloro@Sun.COM /*
394*10106SJason.Beloro@Sun.COM  * Common routine to config or unconfig multiple mblks.
395*10106SJason.Beloro@Sun.COM  *
396*10106SJason.Beloro@Sun.COM  * Note: Do not modify result buffer or length on error.
397*10106SJason.Beloro@Sun.COM  */
398*10106SJason.Beloro@Sun.COM static int
399*10106SJason.Beloro@Sun.COM dr_mem_list_wrk(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
400*10106SJason.Beloro@Sun.COM {
401*10106SJason.Beloro@Sun.COM 	int		rv;
402*10106SJason.Beloro@Sun.COM 	int		idx;
403*10106SJason.Beloro@Sun.COM 	int		count;
404*10106SJason.Beloro@Sun.COM 	int		result;
405*10106SJason.Beloro@Sun.COM 	int		status;
406*10106SJason.Beloro@Sun.COM 	fn_t		dr_fn;
407*10106SJason.Beloro@Sun.COM 	int		se_hint;
408*10106SJason.Beloro@Sun.COM 	dr_mem_blk_t	*req_mblks;
409*10106SJason.Beloro@Sun.COM 	dr_mem_res_t	*res;
410*10106SJason.Beloro@Sun.COM 	int		drctl_cmd;
411*10106SJason.Beloro@Sun.COM 	int		drctl_flags = 0;
412*10106SJason.Beloro@Sun.COM 	drctl_rsrc_t	*drctl_req;
413*10106SJason.Beloro@Sun.COM 	size_t		drctl_req_len;
414*10106SJason.Beloro@Sun.COM 	drctl_resp_t	*drctl_resp;
415*10106SJason.Beloro@Sun.COM 	drctl_rsrc_t	*drctl_rsrc;
416*10106SJason.Beloro@Sun.COM 	size_t		drctl_resp_len = 0;
417*10106SJason.Beloro@Sun.COM 	drctl_cookie_t	drctl_res_ck;
418*10106SJason.Beloro@Sun.COM 
419*10106SJason.Beloro@Sun.COM 	ASSERT((req != NULL) && (req->msg_arg != 0));
420*10106SJason.Beloro@Sun.COM 
421*10106SJason.Beloro@Sun.COM 	count = req->msg_arg;
422*10106SJason.Beloro@Sun.COM 
423*10106SJason.Beloro@Sun.COM 	/*
424*10106SJason.Beloro@Sun.COM 	 * Extract all information that is specific
425*10106SJason.Beloro@Sun.COM 	 * to the various types of operations.
426*10106SJason.Beloro@Sun.COM 	 */
427*10106SJason.Beloro@Sun.COM 	switch (req->msg_type) {
428*10106SJason.Beloro@Sun.COM 	case DR_MEM_CONFIGURE:
429*10106SJason.Beloro@Sun.COM 		dr_fn = dr_mem_configure;
430*10106SJason.Beloro@Sun.COM 		drctl_cmd = DRCTL_MEM_CONFIG_REQUEST;
431*10106SJason.Beloro@Sun.COM 		se_hint = SE_HINT_INSERT;
432*10106SJason.Beloro@Sun.COM 		break;
433*10106SJason.Beloro@Sun.COM 	case DR_MEM_UNCONFIGURE:
434*10106SJason.Beloro@Sun.COM 		dr_fn = dr_mem_unconfigure;
435*10106SJason.Beloro@Sun.COM 		drctl_cmd = DRCTL_MEM_UNCONFIG_REQUEST;
436*10106SJason.Beloro@Sun.COM 		se_hint = SE_HINT_REMOVE;
437*10106SJason.Beloro@Sun.COM 		break;
438*10106SJason.Beloro@Sun.COM 	default:
439*10106SJason.Beloro@Sun.COM 		/* Programming error if we reach this. */
440*10106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "%s: bad msg_type %d\n",
441*10106SJason.Beloro@Sun.COM 		    __func__, req->msg_type);
442*10106SJason.Beloro@Sun.COM 		ASSERT(0);
443*10106SJason.Beloro@Sun.COM 		return (-1);
444*10106SJason.Beloro@Sun.COM 	}
445*10106SJason.Beloro@Sun.COM 
446*10106SJason.Beloro@Sun.COM 	/* the incoming array of mblks to operate on */
447*10106SJason.Beloro@Sun.COM 	req_mblks = DR_MEM_CMD_MBLKS(req);
448*10106SJason.Beloro@Sun.COM 
449*10106SJason.Beloro@Sun.COM 	/* allocate drctl request msg based on incoming resource count */
450*10106SJason.Beloro@Sun.COM 	drctl_req_len = sizeof (drctl_rsrc_t) * count;
451*10106SJason.Beloro@Sun.COM 	drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
452*10106SJason.Beloro@Sun.COM 
453*10106SJason.Beloro@Sun.COM 	/* copy the size for the drctl call from the incoming request msg */
454*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < count; idx++) {
455*10106SJason.Beloro@Sun.COM 		drctl_req[idx].res_mem_addr = req_mblks[idx].addr;
456*10106SJason.Beloro@Sun.COM 		drctl_req[idx].res_mem_size = req_mblks[idx].size;
457*10106SJason.Beloro@Sun.COM 	}
458*10106SJason.Beloro@Sun.COM 
459*10106SJason.Beloro@Sun.COM 	rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
460*10106SJason.Beloro@Sun.COM 	    count, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
461*10106SJason.Beloro@Sun.COM 
462*10106SJason.Beloro@Sun.COM 	ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
463*10106SJason.Beloro@Sun.COM 
464*10106SJason.Beloro@Sun.COM 	if (rv != 0) {
465*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: drctl_config_init returned: %d\n",
466*10106SJason.Beloro@Sun.COM 		    __func__, rv);
467*10106SJason.Beloro@Sun.COM 		kmem_free(drctl_resp, drctl_resp_len);
468*10106SJason.Beloro@Sun.COM 		kmem_free(drctl_req, drctl_req_len);
469*10106SJason.Beloro@Sun.COM 		return (rv);
470*10106SJason.Beloro@Sun.COM 	}
471*10106SJason.Beloro@Sun.COM 
472*10106SJason.Beloro@Sun.COM 	ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
473*10106SJason.Beloro@Sun.COM 
474*10106SJason.Beloro@Sun.COM 	drctl_rsrc = drctl_resp->resp_resources;
475*10106SJason.Beloro@Sun.COM 
476*10106SJason.Beloro@Sun.COM 	/* create the result scratch array */
477*10106SJason.Beloro@Sun.COM 	res = dr_mem_res_array_init(req, drctl_rsrc, count);
478*10106SJason.Beloro@Sun.COM 
479*10106SJason.Beloro@Sun.COM 	/* perform the specified operation on each of the mblks */
480*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < count; idx++) {
481*10106SJason.Beloro@Sun.COM 		/*
482*10106SJason.Beloro@Sun.COM 		 * If no action will be taken against the current
483*10106SJason.Beloro@Sun.COM 		 * mblk, update the drctl resource information to
484*10106SJason.Beloro@Sun.COM 		 * ensure that it gets recovered properly during
485*10106SJason.Beloro@Sun.COM 		 * the drctl fini() call.
486*10106SJason.Beloro@Sun.COM 		 */
487*10106SJason.Beloro@Sun.COM 		if (res[idx].result != DR_MEM_RES_OK) {
488*10106SJason.Beloro@Sun.COM 			drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
489*10106SJason.Beloro@Sun.COM 			continue;
490*10106SJason.Beloro@Sun.COM 		}
491*10106SJason.Beloro@Sun.COM 
492*10106SJason.Beloro@Sun.COM 		/* call the function to perform the actual operation */
493*10106SJason.Beloro@Sun.COM 		result = (*dr_fn)(&req_mblks[idx], &status);
494*10106SJason.Beloro@Sun.COM 
495*10106SJason.Beloro@Sun.COM 		/* save off results of the operation */
496*10106SJason.Beloro@Sun.COM 		res[idx].result = result;
497*10106SJason.Beloro@Sun.COM 		res[idx].status = status;
498*10106SJason.Beloro@Sun.COM 		res[idx].addr = req_mblks[idx].addr;	/* for partial case */
499*10106SJason.Beloro@Sun.COM 		res[idx].size = req_mblks[idx].size;	/* for partial case */
500*10106SJason.Beloro@Sun.COM 		res[idx].string = i_ddi_strdup(dr_mem_estr[result], KM_SLEEP);
501*10106SJason.Beloro@Sun.COM 
502*10106SJason.Beloro@Sun.COM 		/* save result for drctl fini() reusing init() msg memory */
503*10106SJason.Beloro@Sun.COM 		drctl_req[idx].status = (result != DR_MEM_RES_OK) ?
504*10106SJason.Beloro@Sun.COM 		    DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
505*10106SJason.Beloro@Sun.COM 
506*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: mblk 0x%lx.0x%lx stat %d result %d off '%s'\n",
507*10106SJason.Beloro@Sun.COM 		    __func__, req_mblks[idx].addr, req_mblks[idx].size,
508*10106SJason.Beloro@Sun.COM 		    drctl_req[idx].status, result,
509*10106SJason.Beloro@Sun.COM 		    (res[idx].string) ? res[idx].string : "");
510*10106SJason.Beloro@Sun.COM 	}
511*10106SJason.Beloro@Sun.COM 
512*10106SJason.Beloro@Sun.COM 	if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
513*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: drctl_config_fini returned: %d\n",
514*10106SJason.Beloro@Sun.COM 		    __func__, rv);
515*10106SJason.Beloro@Sun.COM 
516*10106SJason.Beloro@Sun.COM 	/*
517*10106SJason.Beloro@Sun.COM 	 * Operation completed without any fatal errors.
518*10106SJason.Beloro@Sun.COM 	 * Pack the response for transmission.
519*10106SJason.Beloro@Sun.COM 	 */
520*10106SJason.Beloro@Sun.COM 	*resp_len = dr_mem_pack_response(req, res, resp);
521*10106SJason.Beloro@Sun.COM 
522*10106SJason.Beloro@Sun.COM 	/* notify interested parties about the operation */
523*10106SJason.Beloro@Sun.COM 	dr_generate_event(DR_TYPE_MEM, se_hint);
524*10106SJason.Beloro@Sun.COM 
525*10106SJason.Beloro@Sun.COM 	/*
526*10106SJason.Beloro@Sun.COM 	 * Deallocate any scratch memory.
527*10106SJason.Beloro@Sun.COM 	 */
528*10106SJason.Beloro@Sun.COM 	kmem_free(drctl_resp, drctl_resp_len);
529*10106SJason.Beloro@Sun.COM 	kmem_free(drctl_req, drctl_req_len);
530*10106SJason.Beloro@Sun.COM 
531*10106SJason.Beloro@Sun.COM 	dr_mem_res_array_fini(res, count);
532*10106SJason.Beloro@Sun.COM 
533*10106SJason.Beloro@Sun.COM 	return (0);
534*10106SJason.Beloro@Sun.COM }
535*10106SJason.Beloro@Sun.COM 
536*10106SJason.Beloro@Sun.COM /*
537*10106SJason.Beloro@Sun.COM  * Allocate and initialize a result array based on the initial
538*10106SJason.Beloro@Sun.COM  * drctl operation. A valid result array is always returned.
539*10106SJason.Beloro@Sun.COM  */
540*10106SJason.Beloro@Sun.COM static dr_mem_res_t *
541*10106SJason.Beloro@Sun.COM dr_mem_res_array_init(dr_mem_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
542*10106SJason.Beloro@Sun.COM {
543*10106SJason.Beloro@Sun.COM 	int		idx;
544*10106SJason.Beloro@Sun.COM 	dr_mem_res_t	*res;
545*10106SJason.Beloro@Sun.COM 	char		*err_str;
546*10106SJason.Beloro@Sun.COM 	size_t		err_len;
547*10106SJason.Beloro@Sun.COM 
548*10106SJason.Beloro@Sun.COM 	/* allocate zero filled buffer to initialize fields */
549*10106SJason.Beloro@Sun.COM 	res = kmem_zalloc(nrsrc * sizeof (dr_mem_res_t), KM_SLEEP);
550*10106SJason.Beloro@Sun.COM 
551*10106SJason.Beloro@Sun.COM 	/*
552*10106SJason.Beloro@Sun.COM 	 * Fill in the result information for each resource.
553*10106SJason.Beloro@Sun.COM 	 */
554*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nrsrc; idx++) {
555*10106SJason.Beloro@Sun.COM 		res[idx].addr = rsrc[idx].res_mem_addr;
556*10106SJason.Beloro@Sun.COM 		res[idx].size = rsrc[idx].res_mem_size;
557*10106SJason.Beloro@Sun.COM 		res[idx].result = DR_MEM_RES_OK;
558*10106SJason.Beloro@Sun.COM 
559*10106SJason.Beloro@Sun.COM 		if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
560*10106SJason.Beloro@Sun.COM 			continue;
561*10106SJason.Beloro@Sun.COM 
562*10106SJason.Beloro@Sun.COM 		/*
563*10106SJason.Beloro@Sun.COM 		 * Update the state information for this mblk.
564*10106SJason.Beloro@Sun.COM 		 */
565*10106SJason.Beloro@Sun.COM 		res[idx].result = DR_MEM_RES_BLOCKED;
566*10106SJason.Beloro@Sun.COM 		res[idx].status = (req->msg_type == DR_MEM_CONFIGURE) ?
567*10106SJason.Beloro@Sun.COM 		    DR_MEM_STAT_UNCONFIGURED : DR_MEM_STAT_CONFIGURED;
568*10106SJason.Beloro@Sun.COM 
569*10106SJason.Beloro@Sun.COM 		/*
570*10106SJason.Beloro@Sun.COM 		 * If an error string exists, copy it out of the
571*10106SJason.Beloro@Sun.COM 		 * message buffer. This eliminates any dependency
572*10106SJason.Beloro@Sun.COM 		 * on the memory allocated for the message buffer
573*10106SJason.Beloro@Sun.COM 		 * itself.
574*10106SJason.Beloro@Sun.COM 		 */
575*10106SJason.Beloro@Sun.COM 		if (rsrc[idx].offset != NULL) {
576*10106SJason.Beloro@Sun.COM 			err_str = (char *)rsrc + rsrc[idx].offset;
577*10106SJason.Beloro@Sun.COM 			err_len = strlen(err_str) + 1;
578*10106SJason.Beloro@Sun.COM 
579*10106SJason.Beloro@Sun.COM 			res[idx].string = kmem_alloc(err_len, KM_SLEEP);
580*10106SJason.Beloro@Sun.COM 			bcopy(err_str, res[idx].string, err_len);
581*10106SJason.Beloro@Sun.COM 		}
582*10106SJason.Beloro@Sun.COM 	}
583*10106SJason.Beloro@Sun.COM 
584*10106SJason.Beloro@Sun.COM 	return (res);
585*10106SJason.Beloro@Sun.COM }
586*10106SJason.Beloro@Sun.COM 
587*10106SJason.Beloro@Sun.COM static void
588*10106SJason.Beloro@Sun.COM dr_mem_res_array_fini(dr_mem_res_t *res, int nres)
589*10106SJason.Beloro@Sun.COM {
590*10106SJason.Beloro@Sun.COM 	int	idx;
591*10106SJason.Beloro@Sun.COM 	size_t	str_len;
592*10106SJason.Beloro@Sun.COM 
593*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nres; idx++) {
594*10106SJason.Beloro@Sun.COM 		/* deallocate the error string if present */
595*10106SJason.Beloro@Sun.COM 		if (res[idx].string) {
596*10106SJason.Beloro@Sun.COM 			str_len = strlen(res[idx].string) + 1;
597*10106SJason.Beloro@Sun.COM 			kmem_free(res[idx].string, str_len);
598*10106SJason.Beloro@Sun.COM 		}
599*10106SJason.Beloro@Sun.COM 	}
600*10106SJason.Beloro@Sun.COM 
601*10106SJason.Beloro@Sun.COM 	/* deallocate the result array itself */
602*10106SJason.Beloro@Sun.COM 	kmem_free(res, sizeof (dr_mem_res_t) * nres);
603*10106SJason.Beloro@Sun.COM }
604*10106SJason.Beloro@Sun.COM 
605*10106SJason.Beloro@Sun.COM /*
606*10106SJason.Beloro@Sun.COM  * Allocate and pack a response message for transmission based
607*10106SJason.Beloro@Sun.COM  * on the specified result array. A valid response message and
608*10106SJason.Beloro@Sun.COM  * valid size information is always returned.
609*10106SJason.Beloro@Sun.COM  */
610*10106SJason.Beloro@Sun.COM static size_t
611*10106SJason.Beloro@Sun.COM dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res, dr_mem_hdr_t **respp)
612*10106SJason.Beloro@Sun.COM {
613*10106SJason.Beloro@Sun.COM 	int		idx;
614*10106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*resp;
615*10106SJason.Beloro@Sun.COM 	dr_mem_stat_t	*resp_stat;
616*10106SJason.Beloro@Sun.COM 	size_t		resp_len;
617*10106SJason.Beloro@Sun.COM 	uint32_t	curr_off;
618*10106SJason.Beloro@Sun.COM 	caddr_t		curr_str;
619*10106SJason.Beloro@Sun.COM 	size_t		str_len;
620*10106SJason.Beloro@Sun.COM 	size_t		stat_len;
621*10106SJason.Beloro@Sun.COM 	int		nstat = req->msg_arg;
622*10106SJason.Beloro@Sun.COM 
623*10106SJason.Beloro@Sun.COM 	/*
624*10106SJason.Beloro@Sun.COM 	 * Calculate the size of the response message
625*10106SJason.Beloro@Sun.COM 	 * and allocate an appropriately sized buffer.
626*10106SJason.Beloro@Sun.COM 	 */
627*10106SJason.Beloro@Sun.COM 	resp_len = sizeof (dr_mem_hdr_t);
628*10106SJason.Beloro@Sun.COM 
629*10106SJason.Beloro@Sun.COM 	/* add the stat array size */
630*10106SJason.Beloro@Sun.COM 	stat_len = sizeof (dr_mem_stat_t) * nstat;
631*10106SJason.Beloro@Sun.COM 	resp_len += stat_len;
632*10106SJason.Beloro@Sun.COM 
633*10106SJason.Beloro@Sun.COM 	/* add the size of any error strings */
634*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nstat; idx++) {
635*10106SJason.Beloro@Sun.COM 		if (res[idx].string != NULL) {
636*10106SJason.Beloro@Sun.COM 			resp_len += strlen(res[idx].string) + 1;
637*10106SJason.Beloro@Sun.COM 		}
638*10106SJason.Beloro@Sun.COM 	}
639*10106SJason.Beloro@Sun.COM 
640*10106SJason.Beloro@Sun.COM 	/* allocate the message buffer */
641*10106SJason.Beloro@Sun.COM 	resp = kmem_zalloc(resp_len, KM_SLEEP);
642*10106SJason.Beloro@Sun.COM 
643*10106SJason.Beloro@Sun.COM 	/*
644*10106SJason.Beloro@Sun.COM 	 * Fill in the header information.
645*10106SJason.Beloro@Sun.COM 	 */
646*10106SJason.Beloro@Sun.COM 	resp->req_num = req->req_num;
647*10106SJason.Beloro@Sun.COM 	resp->msg_type = DR_MEM_OK;
648*10106SJason.Beloro@Sun.COM 	resp->msg_arg = nstat;
649*10106SJason.Beloro@Sun.COM 
650*10106SJason.Beloro@Sun.COM 	/*
651*10106SJason.Beloro@Sun.COM 	 * Fill in the stat information.
652*10106SJason.Beloro@Sun.COM 	 */
653*10106SJason.Beloro@Sun.COM 	resp_stat = DR_MEM_RESP_STATS(resp);
654*10106SJason.Beloro@Sun.COM 
655*10106SJason.Beloro@Sun.COM 	/* string offsets start immediately after stat array */
656*10106SJason.Beloro@Sun.COM 	curr_off = sizeof (dr_mem_hdr_t) + stat_len;
657*10106SJason.Beloro@Sun.COM 	curr_str = (char *)resp_stat + stat_len;
658*10106SJason.Beloro@Sun.COM 
659*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nstat; idx++) {
660*10106SJason.Beloro@Sun.COM 		resp_stat[idx].addr = res[idx].addr;
661*10106SJason.Beloro@Sun.COM 		resp_stat[idx].size = res[idx].size;
662*10106SJason.Beloro@Sun.COM 		resp_stat[idx].result = res[idx].result;
663*10106SJason.Beloro@Sun.COM 		resp_stat[idx].status = res[idx].status;
664*10106SJason.Beloro@Sun.COM 
665*10106SJason.Beloro@Sun.COM 		if (res[idx].string != NULL) {
666*10106SJason.Beloro@Sun.COM 			/* copy over the error string */
667*10106SJason.Beloro@Sun.COM 			str_len = strlen(res[idx].string) + 1;
668*10106SJason.Beloro@Sun.COM 			bcopy(res[idx].string, curr_str, str_len);
669*10106SJason.Beloro@Sun.COM 			resp_stat[idx].string_off = curr_off;
670*10106SJason.Beloro@Sun.COM 
671*10106SJason.Beloro@Sun.COM 			curr_off += str_len;
672*10106SJason.Beloro@Sun.COM 			curr_str += str_len;
673*10106SJason.Beloro@Sun.COM 		}
674*10106SJason.Beloro@Sun.COM 	}
675*10106SJason.Beloro@Sun.COM 
676*10106SJason.Beloro@Sun.COM 	/* buffer should be exactly filled */
677*10106SJason.Beloro@Sun.COM 	ASSERT(curr_off == resp_len);
678*10106SJason.Beloro@Sun.COM 
679*10106SJason.Beloro@Sun.COM 	*respp = resp;
680*10106SJason.Beloro@Sun.COM 	return (resp_len);
681*10106SJason.Beloro@Sun.COM }
682*10106SJason.Beloro@Sun.COM 
683*10106SJason.Beloro@Sun.COM static void
684*10106SJason.Beloro@Sun.COM dr_mem_query(dr_mem_blk_t *mbp, dr_mem_query_t *mqp)
685*10106SJason.Beloro@Sun.COM {
686*10106SJason.Beloro@Sun.COM 	memquery_t mq;
687*10106SJason.Beloro@Sun.COM 
688*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("dr_mem_query...\n");
689*10106SJason.Beloro@Sun.COM 
690*10106SJason.Beloro@Sun.COM 
691*10106SJason.Beloro@Sun.COM 	(void) kphysm_del_span_query(btop(mbp->addr), btop(mbp->size), &mq);
692*10106SJason.Beloro@Sun.COM 
693*10106SJason.Beloro@Sun.COM 	if (!mq.phys_pages)
694*10106SJason.Beloro@Sun.COM 		return;
695*10106SJason.Beloro@Sun.COM 
696*10106SJason.Beloro@Sun.COM 	mqp->addr = mbp->addr;
697*10106SJason.Beloro@Sun.COM 	mqp->mq.phys_pages = ptob(mq.phys_pages);
698*10106SJason.Beloro@Sun.COM 	mqp->mq.managed = ptob(mq.managed);
699*10106SJason.Beloro@Sun.COM 	mqp->mq.nonrelocatable = ptob(mq.nonrelocatable);
700*10106SJason.Beloro@Sun.COM 	mqp->mq.first_nonrelocatable = ptob(mq.first_nonrelocatable);
701*10106SJason.Beloro@Sun.COM 	mqp->mq.last_nonrelocatable = ptob(mq.last_nonrelocatable);
702*10106SJason.Beloro@Sun.COM 	/*
703*10106SJason.Beloro@Sun.COM 	 * Set to the max byte offset within the page.
704*10106SJason.Beloro@Sun.COM 	 */
705*10106SJason.Beloro@Sun.COM 	if (mqp->mq.nonrelocatable)
706*10106SJason.Beloro@Sun.COM 		mqp->mq.last_nonrelocatable += PAGESIZE - 1;
707*10106SJason.Beloro@Sun.COM }
708*10106SJason.Beloro@Sun.COM 
709*10106SJason.Beloro@Sun.COM /*
710*10106SJason.Beloro@Sun.COM  * Do not modify result buffer or length on error.
711*10106SJason.Beloro@Sun.COM  */
712*10106SJason.Beloro@Sun.COM static int
713*10106SJason.Beloro@Sun.COM dr_mem_list_query(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
714*10106SJason.Beloro@Sun.COM {
715*10106SJason.Beloro@Sun.COM 	int		idx;
716*10106SJason.Beloro@Sun.COM 	int		rlen;
717*10106SJason.Beloro@Sun.COM 	int		nml;
718*10106SJason.Beloro@Sun.COM 	struct memlist	*ml;
719*10106SJason.Beloro@Sun.COM 	dr_mem_blk_t	*req_mblks, mb;
720*10106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*rp;
721*10106SJason.Beloro@Sun.COM 	dr_mem_query_t	*stat;
722*10106SJason.Beloro@Sun.COM 
723*10106SJason.Beloro@Sun.COM 	/* the incoming array of req_mblks to configure */
724*10106SJason.Beloro@Sun.COM 	req_mblks = DR_MEM_CMD_MBLKS(req);
725*10106SJason.Beloro@Sun.COM 
726*10106SJason.Beloro@Sun.COM 	/* allocate a response message, should be freed by caller */
727*10106SJason.Beloro@Sun.COM 	nml = 0;
728*10106SJason.Beloro@Sun.COM 	rlen = sizeof (dr_mem_hdr_t);
729*10106SJason.Beloro@Sun.COM 	if (req_mblks->addr == NULL && req_mblks->size == 0) {
730*10106SJason.Beloro@Sun.COM 		/*
731*10106SJason.Beloro@Sun.COM 		 * Request is for domain's full view of it's memory.
732*10106SJason.Beloro@Sun.COM 		 */
733*10106SJason.Beloro@Sun.COM 		memlist_read_lock();
734*10106SJason.Beloro@Sun.COM 		for (ml = phys_install; ml; ml = ml->next)
735*10106SJason.Beloro@Sun.COM 			nml++;
736*10106SJason.Beloro@Sun.COM 
737*10106SJason.Beloro@Sun.COM 		rlen += nml * sizeof (dr_mem_query_t);
738*10106SJason.Beloro@Sun.COM 	} else {
739*10106SJason.Beloro@Sun.COM 		rlen += req->msg_arg * sizeof (dr_mem_query_t);
740*10106SJason.Beloro@Sun.COM 	}
741*10106SJason.Beloro@Sun.COM 	rp = kmem_zalloc(rlen, KM_SLEEP);
742*10106SJason.Beloro@Sun.COM 
743*10106SJason.Beloro@Sun.COM 	/* fill in the known data */
744*10106SJason.Beloro@Sun.COM 	rp->req_num = req->req_num;
745*10106SJason.Beloro@Sun.COM 	rp->msg_type = DR_MEM_OK;
746*10106SJason.Beloro@Sun.COM 	rp->msg_arg = nml ? nml : req->msg_arg;
747*10106SJason.Beloro@Sun.COM 
748*10106SJason.Beloro@Sun.COM 	/* stat array for the response */
749*10106SJason.Beloro@Sun.COM 	stat = DR_MEM_RESP_QUERY(rp);
750*10106SJason.Beloro@Sun.COM 
751*10106SJason.Beloro@Sun.COM 	/* get the status for each of the mblocks */
752*10106SJason.Beloro@Sun.COM 	if (nml) {
753*10106SJason.Beloro@Sun.COM 		for (idx = 0, ml = phys_install; ml; ml = ml->next, idx++) {
754*10106SJason.Beloro@Sun.COM 			mb.addr = ml->address;
755*10106SJason.Beloro@Sun.COM 			mb.size = ml->size;
756*10106SJason.Beloro@Sun.COM 			dr_mem_query(&mb, &stat[idx]);
757*10106SJason.Beloro@Sun.COM 		}
758*10106SJason.Beloro@Sun.COM 		memlist_read_unlock();
759*10106SJason.Beloro@Sun.COM 	} else {
760*10106SJason.Beloro@Sun.COM 		for (idx = 0; idx < req->msg_arg; idx++)
761*10106SJason.Beloro@Sun.COM 			dr_mem_query(&req_mblks[idx], &stat[idx]);
762*10106SJason.Beloro@Sun.COM 	}
763*10106SJason.Beloro@Sun.COM 
764*10106SJason.Beloro@Sun.COM 	*resp = rp;
765*10106SJason.Beloro@Sun.COM 	*resp_len = rlen;
766*10106SJason.Beloro@Sun.COM 
767*10106SJason.Beloro@Sun.COM 	return (0);
768*10106SJason.Beloro@Sun.COM }
769*10106SJason.Beloro@Sun.COM 
770*10106SJason.Beloro@Sun.COM static int
771*10106SJason.Beloro@Sun.COM cvt_err(int err)
772*10106SJason.Beloro@Sun.COM {
773*10106SJason.Beloro@Sun.COM 	int rv;
774*10106SJason.Beloro@Sun.COM 
775*10106SJason.Beloro@Sun.COM 	switch (err) {
776*10106SJason.Beloro@Sun.COM 	case KPHYSM_OK:
777*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_OK;
778*10106SJason.Beloro@Sun.COM 		break;
779*10106SJason.Beloro@Sun.COM 	case KPHYSM_ESPAN:
780*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ESPAN;
781*10106SJason.Beloro@Sun.COM 		break;
782*10106SJason.Beloro@Sun.COM 	case KPHYSM_EFAULT:
783*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EFAULT;
784*10106SJason.Beloro@Sun.COM 		break;
785*10106SJason.Beloro@Sun.COM 	case KPHYSM_ERESOURCE:
786*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ERESOURCE;
787*10106SJason.Beloro@Sun.COM 		break;
788*10106SJason.Beloro@Sun.COM 	case KPHYSM_ENOTSUP:
789*10106SJason.Beloro@Sun.COM 	case KPHYSM_ENOHANDLES:
790*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
791*10106SJason.Beloro@Sun.COM 		break;
792*10106SJason.Beloro@Sun.COM 	case KPHYSM_ENONRELOC:
793*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_PERM;
794*10106SJason.Beloro@Sun.COM 		break;
795*10106SJason.Beloro@Sun.COM 	case KPHYSM_EHANDLE:
796*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
797*10106SJason.Beloro@Sun.COM 		break;
798*10106SJason.Beloro@Sun.COM 	case KPHYSM_EBUSY:
799*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EBUSY;
800*10106SJason.Beloro@Sun.COM 		break;
801*10106SJason.Beloro@Sun.COM 	case KPHYSM_ENOTVIABLE:
802*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ENOTVIABLE;
803*10106SJason.Beloro@Sun.COM 		break;
804*10106SJason.Beloro@Sun.COM 	case KPHYSM_ESEQUENCE:
805*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
806*10106SJason.Beloro@Sun.COM 		break;
807*10106SJason.Beloro@Sun.COM 	case KPHYSM_ENOWORK:
808*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ENOWORK;
809*10106SJason.Beloro@Sun.COM 		break;
810*10106SJason.Beloro@Sun.COM 	case KPHYSM_ECANCELLED:
811*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ECANCELLED;
812*10106SJason.Beloro@Sun.COM 		break;
813*10106SJason.Beloro@Sun.COM 	case KPHYSM_EREFUSED:
814*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EREFUSED;
815*10106SJason.Beloro@Sun.COM 		break;
816*10106SJason.Beloro@Sun.COM 	case KPHYSM_ENOTFINISHED:
817*10106SJason.Beloro@Sun.COM 	case KPHYSM_ENOTRUNNING:
818*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
819*10106SJason.Beloro@Sun.COM 		break;
820*10106SJason.Beloro@Sun.COM 	case KPHYSM_EDUP:
821*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EDUP;
822*10106SJason.Beloro@Sun.COM 		break;
823*10106SJason.Beloro@Sun.COM 	default:
824*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
825*10106SJason.Beloro@Sun.COM 		break;
826*10106SJason.Beloro@Sun.COM 	}
827*10106SJason.Beloro@Sun.COM 
828*10106SJason.Beloro@Sun.COM 	return (rv);
829*10106SJason.Beloro@Sun.COM }
830*10106SJason.Beloro@Sun.COM 
831*10106SJason.Beloro@Sun.COM static int
832*10106SJason.Beloro@Sun.COM dr_mem_configure(dr_mem_blk_t *mbp, int *status)
833*10106SJason.Beloro@Sun.COM {
834*10106SJason.Beloro@Sun.COM 	int rv;
835*10106SJason.Beloro@Sun.COM 	uint64_t addr, size, addsz;
836*10106SJason.Beloro@Sun.COM 
837*10106SJason.Beloro@Sun.COM 	rv = 0;
838*10106SJason.Beloro@Sun.COM 	addr = mbp->addr;
839*10106SJason.Beloro@Sun.COM 	size = mbp->size;
840*10106SJason.Beloro@Sun.COM 
841*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("dr_mem_configure...\n");
842*10106SJason.Beloro@Sun.COM 
843*10106SJason.Beloro@Sun.COM 	if (!MBLK_IS_VALID(mbp)) {
844*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n", addr, size);
845*10106SJason.Beloro@Sun.COM 		*status = DR_MEM_STAT_UNCONFIGURED;
846*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EINVAL;
847*10106SJason.Beloro@Sun.COM 	} else if (rv = dr_mem_find(mbp)) {
848*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("failed to find mblk 0x%lx.0x%lx (%d)\n",
849*10106SJason.Beloro@Sun.COM 		    addr, size, rv);
850*10106SJason.Beloro@Sun.COM 		if (rv == EINVAL) {
851*10106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_NOT_PRESENT;
852*10106SJason.Beloro@Sun.COM 			rv = DR_MEM_RES_NOT_IN_MD;
853*10106SJason.Beloro@Sun.COM 		} else {
854*10106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_UNCONFIGURED;
855*10106SJason.Beloro@Sun.COM 			rv = DR_MEM_RES_FAILURE;
856*10106SJason.Beloro@Sun.COM 		}
857*10106SJason.Beloro@Sun.COM 	} else if (rsvaddsz) {
858*10106SJason.Beloro@Sun.COM 		addr += size;
859*10106SJason.Beloro@Sun.COM 
860*10106SJason.Beloro@Sun.COM 		/*
861*10106SJason.Beloro@Sun.COM 		 * Add up to the first <rsvaddsz> portion of mblock
862*10106SJason.Beloro@Sun.COM 		 * first since that portion has reserved meta pages.
863*10106SJason.Beloro@Sun.COM 		 * This will likely guarantee an additional amount of
864*10106SJason.Beloro@Sun.COM 		 * free pages from which we may have to allocate the
865*10106SJason.Beloro@Sun.COM 		 * rest of the meta pages.
866*10106SJason.Beloro@Sun.COM 		 *
867*10106SJason.Beloro@Sun.COM 		 * Break up the request in descending order (if needed)
868*10106SJason.Beloro@Sun.COM 		 * in order to ensure that cage grows from the high end
869*10106SJason.Beloro@Sun.COM 		 * of the original request.
870*10106SJason.Beloro@Sun.COM 		 */
871*10106SJason.Beloro@Sun.COM 		for (addsz = MIN(size, rsvaddsz); addsz > 0; addsz = size) {
872*10106SJason.Beloro@Sun.COM 			ASSERT(addr >= mbp->addr);
873*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("addsz=0x%lx  size=0x%lx\n", addsz, size);
874*10106SJason.Beloro@Sun.COM 			if (rv = mem_add(btop(addr - addsz), btop(addsz))) {
875*10106SJason.Beloro@Sun.COM 				DR_DBG_MEM("failed to configure span"
876*10106SJason.Beloro@Sun.COM 				    " 0x%lx.0x%lx (%d)\n", addr, addsz, rv);
877*10106SJason.Beloro@Sun.COM 				break;
878*10106SJason.Beloro@Sun.COM 			} else {
879*10106SJason.Beloro@Sun.COM 				size -= addsz;
880*10106SJason.Beloro@Sun.COM 				addr -= addsz;
881*10106SJason.Beloro@Sun.COM 			}
882*10106SJason.Beloro@Sun.COM 		}
883*10106SJason.Beloro@Sun.COM 
884*10106SJason.Beloro@Sun.COM 		/*
885*10106SJason.Beloro@Sun.COM 		 * Mark the mblock configured if any span
886*10106SJason.Beloro@Sun.COM 		 * in that mblock was successfully added.
887*10106SJason.Beloro@Sun.COM 		 *
888*10106SJason.Beloro@Sun.COM 		 * In case of partial success:
889*10106SJason.Beloro@Sun.COM 		 *
890*10106SJason.Beloro@Sun.COM 		 *	rv != DR_MEM_RES_OK
891*10106SJason.Beloro@Sun.COM 		 *	status == DR_MEM_STAT_CONFIGURED
892*10106SJason.Beloro@Sun.COM 		 *
893*10106SJason.Beloro@Sun.COM 		 * mark span actually configured.
894*10106SJason.Beloro@Sun.COM 		 */
895*10106SJason.Beloro@Sun.COM 		if (size == mbp->size && rv != KPHYSM_ESPAN) {
896*10106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_UNCONFIGURED;
897*10106SJason.Beloro@Sun.COM 		} else {
898*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("failed (partial) to configure span"
899*10106SJason.Beloro@Sun.COM 			    " 0x%lx.0x%lx (%d)\n", addr, addsz, rv);
900*10106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_CONFIGURED;
901*10106SJason.Beloro@Sun.COM 			mbp->addr = addr;
902*10106SJason.Beloro@Sun.COM 			mbp->size -= size;
903*10106SJason.Beloro@Sun.COM 		}
904*10106SJason.Beloro@Sun.COM 
905*10106SJason.Beloro@Sun.COM 		rv = cvt_err(rv);
906*10106SJason.Beloro@Sun.COM 		i_dr_mem_update();
907*10106SJason.Beloro@Sun.COM 	} else {
908*10106SJason.Beloro@Sun.COM 		/*
909*10106SJason.Beloro@Sun.COM 		 * The reserved feature is disabled, add whole mblock.
910*10106SJason.Beloro@Sun.COM 		 */
911*10106SJason.Beloro@Sun.COM 		rv = mem_add(btop(addr), btop(size));
912*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("addr=0x%lx size=0x%lx rv=%d\n", addr, size, rv);
913*10106SJason.Beloro@Sun.COM 		if (rv) {
914*10106SJason.Beloro@Sun.COM 			rv = cvt_err(rv);
915*10106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_UNCONFIGURED;
916*10106SJason.Beloro@Sun.COM 		} else {
917*10106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_CONFIGURED;
918*10106SJason.Beloro@Sun.COM 		}
919*10106SJason.Beloro@Sun.COM 	}
920*10106SJason.Beloro@Sun.COM 
921*10106SJason.Beloro@Sun.COM 	return (rv);
922*10106SJason.Beloro@Sun.COM }
923*10106SJason.Beloro@Sun.COM 
924*10106SJason.Beloro@Sun.COM static int
925*10106SJason.Beloro@Sun.COM dr_mem_unconfigure(dr_mem_blk_t *mbp, int *status)
926*10106SJason.Beloro@Sun.COM {
927*10106SJason.Beloro@Sun.COM 	int rv;
928*10106SJason.Beloro@Sun.COM 
929*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("dr_mem_unconfigure...\n");
930*10106SJason.Beloro@Sun.COM 
931*10106SJason.Beloro@Sun.COM 	if (!MBLK_IS_VALID(mbp)) {
932*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n",
933*10106SJason.Beloro@Sun.COM 		    mbp->addr, mbp->size);
934*10106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_CONFIGURED;
935*10106SJason.Beloro@Sun.COM 			rv = DR_MEM_RES_EINVAL;
936*10106SJason.Beloro@Sun.COM 	} else if (rv = mem_del(btop(mbp->addr), btop(mbp->size))) {
937*10106SJason.Beloro@Sun.COM 		rv = cvt_err(rv);
938*10106SJason.Beloro@Sun.COM 		*status = DR_MEM_STAT_CONFIGURED;
939*10106SJason.Beloro@Sun.COM 	} else {
940*10106SJason.Beloro@Sun.COM 		*status = DR_MEM_STAT_UNCONFIGURED;
941*10106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_OK;
942*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("mblk 0x%lx.0x%lx unconfigured\n",
943*10106SJason.Beloro@Sun.COM 		    mbp->addr, mbp->size);
944*10106SJason.Beloro@Sun.COM 	}
945*10106SJason.Beloro@Sun.COM 	return (rv);
946*10106SJason.Beloro@Sun.COM }
947*10106SJason.Beloro@Sun.COM 
948*10106SJason.Beloro@Sun.COM static int
949*10106SJason.Beloro@Sun.COM dr_mem_del_stat(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
950*10106SJason.Beloro@Sun.COM {
951*10106SJason.Beloro@Sun.COM 	int			status;
952*10106SJason.Beloro@Sun.COM 	int			rlen;
953*10106SJason.Beloro@Sun.COM 	memdelstat_t		del_stat, *stat;
954*10106SJason.Beloro@Sun.COM 	dr_mem_hdr_t		*rp;
955*10106SJason.Beloro@Sun.COM 
956*10106SJason.Beloro@Sun.COM 	/*
957*10106SJason.Beloro@Sun.COM 	 * If a mem delete is in progress, get its status.
958*10106SJason.Beloro@Sun.COM 	 */
959*10106SJason.Beloro@Sun.COM 	status = (dr_mh && (kphysm_del_status(dr_mh, &del_stat) == KPHYSM_OK));
960*10106SJason.Beloro@Sun.COM 
961*10106SJason.Beloro@Sun.COM 	/* allocate a response message, should be freed by caller */
962*10106SJason.Beloro@Sun.COM 	rlen = sizeof (dr_mem_hdr_t);
963*10106SJason.Beloro@Sun.COM 	rlen += status * sizeof (memdelstat_t);
964*10106SJason.Beloro@Sun.COM 	rp = kmem_zalloc(rlen, KM_SLEEP);
965*10106SJason.Beloro@Sun.COM 
966*10106SJason.Beloro@Sun.COM 	/* fill in the known data */
967*10106SJason.Beloro@Sun.COM 	rp->req_num = req->req_num;
968*10106SJason.Beloro@Sun.COM 	rp->msg_type = DR_MEM_OK;
969*10106SJason.Beloro@Sun.COM 	rp->msg_arg = status;
970*10106SJason.Beloro@Sun.COM 
971*10106SJason.Beloro@Sun.COM 	if (status) {
972*10106SJason.Beloro@Sun.COM 		/* stat struct for the response */
973*10106SJason.Beloro@Sun.COM 		stat = DR_MEM_RESP_DEL_STAT(rp);
974*10106SJason.Beloro@Sun.COM 		stat->phys_pages = ptob(del_stat.phys_pages);
975*10106SJason.Beloro@Sun.COM 		stat->managed = ptob(del_stat.managed);
976*10106SJason.Beloro@Sun.COM 		stat->collected = ptob(del_stat.collected);
977*10106SJason.Beloro@Sun.COM 	}
978*10106SJason.Beloro@Sun.COM 
979*10106SJason.Beloro@Sun.COM 	*resp = rp;
980*10106SJason.Beloro@Sun.COM 	*resp_len = rlen;
981*10106SJason.Beloro@Sun.COM 
982*10106SJason.Beloro@Sun.COM 	return (0);
983*10106SJason.Beloro@Sun.COM }
984*10106SJason.Beloro@Sun.COM 
985*10106SJason.Beloro@Sun.COM static int
986*10106SJason.Beloro@Sun.COM dr_mem_del_cancel(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
987*10106SJason.Beloro@Sun.COM {
988*10106SJason.Beloro@Sun.COM 	int		rlen;
989*10106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*rp;
990*10106SJason.Beloro@Sun.COM 
991*10106SJason.Beloro@Sun.COM 	/* allocate a response message, should be freed by caller */
992*10106SJason.Beloro@Sun.COM 	rlen = sizeof (dr_mem_hdr_t);
993*10106SJason.Beloro@Sun.COM 	rp = kmem_zalloc(rlen, KM_SLEEP);
994*10106SJason.Beloro@Sun.COM 
995*10106SJason.Beloro@Sun.COM 	/* fill in the known data */
996*10106SJason.Beloro@Sun.COM 	rp->req_num = req->req_num;
997*10106SJason.Beloro@Sun.COM 	rp->msg_type = DR_MEM_OK;
998*10106SJason.Beloro@Sun.COM 	rp->msg_arg = (dr_mh && kphysm_del_cancel(dr_mh) != KPHYSM_OK) ?
999*10106SJason.Beloro@Sun.COM 	    DR_MEM_RES_EINVAL : DR_MEM_RES_OK;
1000*10106SJason.Beloro@Sun.COM 
1001*10106SJason.Beloro@Sun.COM 	*resp = rp;
1002*10106SJason.Beloro@Sun.COM 	*resp_len = rlen;
1003*10106SJason.Beloro@Sun.COM 
1004*10106SJason.Beloro@Sun.COM 	return (0);
1005*10106SJason.Beloro@Sun.COM }
1006*10106SJason.Beloro@Sun.COM 
1007*10106SJason.Beloro@Sun.COM static int
1008*10106SJason.Beloro@Sun.COM dr_mem_find(dr_mem_blk_t *mbp)
1009*10106SJason.Beloro@Sun.COM {
1010*10106SJason.Beloro@Sun.COM 	md_t		*mdp = NULL;
1011*10106SJason.Beloro@Sun.COM 	int		num_nodes;
1012*10106SJason.Beloro@Sun.COM 	int		rv = 0;
1013*10106SJason.Beloro@Sun.COM 	int		listsz;
1014*10106SJason.Beloro@Sun.COM 	mde_cookie_t	*listp = NULL;
1015*10106SJason.Beloro@Sun.COM 	mde_cookie_t	memnode;
1016*10106SJason.Beloro@Sun.COM 	char		*found = "found";
1017*10106SJason.Beloro@Sun.COM 
1018*10106SJason.Beloro@Sun.COM 	if ((mdp = md_get_handle()) == NULL) {
1019*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("unable to initialize machine description\n");
1020*10106SJason.Beloro@Sun.COM 		return (-1);
1021*10106SJason.Beloro@Sun.COM 	}
1022*10106SJason.Beloro@Sun.COM 
1023*10106SJason.Beloro@Sun.COM 	num_nodes = md_node_count(mdp);
1024*10106SJason.Beloro@Sun.COM 	ASSERT(num_nodes > 0);
1025*10106SJason.Beloro@Sun.COM 
1026*10106SJason.Beloro@Sun.COM 	listsz = num_nodes * sizeof (mde_cookie_t);
1027*10106SJason.Beloro@Sun.COM 	listp = kmem_zalloc(listsz, KM_SLEEP);
1028*10106SJason.Beloro@Sun.COM 
1029*10106SJason.Beloro@Sun.COM 	memnode = dr_mem_find_node_md(mbp, mdp, listp);
1030*10106SJason.Beloro@Sun.COM 
1031*10106SJason.Beloro@Sun.COM 	if (memnode == MDE_INVAL_ELEM_COOKIE) {
1032*10106SJason.Beloro@Sun.COM 		rv = EINVAL;
1033*10106SJason.Beloro@Sun.COM 		found = "not found";
1034*10106SJason.Beloro@Sun.COM 	}
1035*10106SJason.Beloro@Sun.COM 
1036*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("mblk 0x%lx.0x%lx %s\n", mbp->addr, mbp->size, found);
1037*10106SJason.Beloro@Sun.COM 
1038*10106SJason.Beloro@Sun.COM 	kmem_free(listp, listsz);
1039*10106SJason.Beloro@Sun.COM 	(void) md_fini_handle(mdp);
1040*10106SJason.Beloro@Sun.COM 
1041*10106SJason.Beloro@Sun.COM 	return (rv);
1042*10106SJason.Beloro@Sun.COM }
1043*10106SJason.Beloro@Sun.COM 
1044*10106SJason.Beloro@Sun.COM /*
1045*10106SJason.Beloro@Sun.COM  * Look up a particular mblk in the MD. Returns the mde_cookie_t
1046*10106SJason.Beloro@Sun.COM  * representing that mblk if present, and MDE_INVAL_ELEM_COOKIE
1047*10106SJason.Beloro@Sun.COM  * otherwise. It is assumed the scratch array has already been
1048*10106SJason.Beloro@Sun.COM  * allocated so that it can accommodate the worst case scenario,
1049*10106SJason.Beloro@Sun.COM  * every node in the MD.
1050*10106SJason.Beloro@Sun.COM  */
1051*10106SJason.Beloro@Sun.COM static mde_cookie_t
1052*10106SJason.Beloro@Sun.COM dr_mem_find_node_md(dr_mem_blk_t *mbp, md_t *mdp, mde_cookie_t *listp)
1053*10106SJason.Beloro@Sun.COM {
1054*10106SJason.Beloro@Sun.COM 	int		idx;
1055*10106SJason.Beloro@Sun.COM 	int		nnodes;
1056*10106SJason.Beloro@Sun.COM 	mde_cookie_t	rootnode;
1057*10106SJason.Beloro@Sun.COM 	uint64_t	base_prop;
1058*10106SJason.Beloro@Sun.COM 	uint64_t	size_prop;
1059*10106SJason.Beloro@Sun.COM 	mde_cookie_t	result = MDE_INVAL_ELEM_COOKIE;
1060*10106SJason.Beloro@Sun.COM 
1061*10106SJason.Beloro@Sun.COM 	rootnode = md_root_node(mdp);
1062*10106SJason.Beloro@Sun.COM 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
1063*10106SJason.Beloro@Sun.COM 
1064*10106SJason.Beloro@Sun.COM 	/*
1065*10106SJason.Beloro@Sun.COM 	 * Scan the DAG for all the mem nodes
1066*10106SJason.Beloro@Sun.COM 	 */
1067*10106SJason.Beloro@Sun.COM 	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "mblock"),
1068*10106SJason.Beloro@Sun.COM 	    md_find_name(mdp, "fwd"), listp);
1069*10106SJason.Beloro@Sun.COM 
1070*10106SJason.Beloro@Sun.COM 	if (nnodes < 0) {
1071*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("Scan for mblks failed\n");
1072*10106SJason.Beloro@Sun.COM 		return (result);
1073*10106SJason.Beloro@Sun.COM 	}
1074*10106SJason.Beloro@Sun.COM 
1075*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("dr_mem_find_node_md: found %d mblks in the MD\n", nnodes);
1076*10106SJason.Beloro@Sun.COM 
1077*10106SJason.Beloro@Sun.COM 	/*
1078*10106SJason.Beloro@Sun.COM 	 * Find the mblk of interest
1079*10106SJason.Beloro@Sun.COM 	 */
1080*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nnodes; idx++) {
1081*10106SJason.Beloro@Sun.COM 
1082*10106SJason.Beloro@Sun.COM 		if (md_get_prop_val(mdp, listp[idx], "base", &base_prop)) {
1083*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Missing 'base' property for mblk node %d\n",
1084*10106SJason.Beloro@Sun.COM 			    idx);
1085*10106SJason.Beloro@Sun.COM 			break;
1086*10106SJason.Beloro@Sun.COM 		}
1087*10106SJason.Beloro@Sun.COM 
1088*10106SJason.Beloro@Sun.COM 		if (md_get_prop_val(mdp, listp[idx], "size", &size_prop)) {
1089*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Missing 'size' property for mblk node %d\n",
1090*10106SJason.Beloro@Sun.COM 			    idx);
1091*10106SJason.Beloro@Sun.COM 			break;
1092*10106SJason.Beloro@Sun.COM 		}
1093*10106SJason.Beloro@Sun.COM 
1094*10106SJason.Beloro@Sun.COM 		if (base_prop <= mbp->addr &&
1095*10106SJason.Beloro@Sun.COM 		    (base_prop + size_prop) >= (mbp->addr + mbp->size)) {
1096*10106SJason.Beloro@Sun.COM 			/* found a match */
1097*10106SJason.Beloro@Sun.COM 			DR_DBG_MEM("dr_mem_find_node_md: found mblk "
1098*10106SJason.Beloro@Sun.COM 			    "0x%lx.0x%lx in MD\n", mbp->addr, mbp->size);
1099*10106SJason.Beloro@Sun.COM 			result = listp[idx];
1100*10106SJason.Beloro@Sun.COM 			break;
1101*10106SJason.Beloro@Sun.COM 		}
1102*10106SJason.Beloro@Sun.COM 	}
1103*10106SJason.Beloro@Sun.COM 
1104*10106SJason.Beloro@Sun.COM 	if (result == MDE_INVAL_ELEM_COOKIE) {
1105*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("mblk 0x%lx.0x%lx not in MD\n",
1106*10106SJason.Beloro@Sun.COM 		    mbp->addr, mbp->size);
1107*10106SJason.Beloro@Sun.COM 	}
1108*10106SJason.Beloro@Sun.COM 
1109*10106SJason.Beloro@Sun.COM 	return (result);
1110*10106SJason.Beloro@Sun.COM }
1111*10106SJason.Beloro@Sun.COM 
1112*10106SJason.Beloro@Sun.COM static int
1113*10106SJason.Beloro@Sun.COM mem_add(pfn_t base, pgcnt_t npgs)
1114*10106SJason.Beloro@Sun.COM {
1115*10106SJason.Beloro@Sun.COM 	int rv, rc;
1116*10106SJason.Beloro@Sun.COM 
1117*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
1118*10106SJason.Beloro@Sun.COM 
1119*10106SJason.Beloro@Sun.COM 	if (npgs == 0)
1120*10106SJason.Beloro@Sun.COM 		return (0);
1121*10106SJason.Beloro@Sun.COM 
1122*10106SJason.Beloro@Sun.COM 	rv = kphysm_add_memory_dynamic(base, npgs);
1123*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: kphysm_add(0x%lx, 0x%lx) = %d", __func__, base, npgs,
1124*10106SJason.Beloro@Sun.COM 	    rv);
1125*10106SJason.Beloro@Sun.COM 	if (!rv) {
1126*10106SJason.Beloro@Sun.COM 		if (rc = kcage_range_add(base, npgs, KCAGE_DOWN))
1127*10106SJason.Beloro@Sun.COM 			cmn_err(CE_WARN, "kcage_range_add() = %d", rc);
1128*10106SJason.Beloro@Sun.COM 	}
1129*10106SJason.Beloro@Sun.COM 	return (rv);
1130*10106SJason.Beloro@Sun.COM }
1131*10106SJason.Beloro@Sun.COM 
1132*10106SJason.Beloro@Sun.COM static void
1133*10106SJason.Beloro@Sun.COM del_done(void *arg, int error)
1134*10106SJason.Beloro@Sun.COM {
1135*10106SJason.Beloro@Sun.COM 	mem_sync_t *ms = arg;
1136*10106SJason.Beloro@Sun.COM 
1137*10106SJason.Beloro@Sun.COM 	mutex_enter(&ms->lock);
1138*10106SJason.Beloro@Sun.COM 	ms->error = error;
1139*10106SJason.Beloro@Sun.COM 	ms->done = 1;
1140*10106SJason.Beloro@Sun.COM 	cv_signal(&ms->cond);
1141*10106SJason.Beloro@Sun.COM 	mutex_exit(&ms->lock);
1142*10106SJason.Beloro@Sun.COM }
1143*10106SJason.Beloro@Sun.COM 
1144*10106SJason.Beloro@Sun.COM static int
1145*10106SJason.Beloro@Sun.COM mem_del(pfn_t base, pgcnt_t npgs)
1146*10106SJason.Beloro@Sun.COM {
1147*10106SJason.Beloro@Sun.COM 	int rv, err, del_range = 0;
1148*10106SJason.Beloro@Sun.COM 	mem_sync_t ms;
1149*10106SJason.Beloro@Sun.COM 	memquery_t mq;
1150*10106SJason.Beloro@Sun.COM 	memhandle_t mh;
1151*10106SJason.Beloro@Sun.COM 	struct memlist *ml;
1152*10106SJason.Beloro@Sun.COM 	struct memlist *d_ml = NULL;
1153*10106SJason.Beloro@Sun.COM 
1154*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
1155*10106SJason.Beloro@Sun.COM 
1156*10106SJason.Beloro@Sun.COM 	if (npgs == 0)
1157*10106SJason.Beloro@Sun.COM 		return (0);
1158*10106SJason.Beloro@Sun.COM 
1159*10106SJason.Beloro@Sun.COM 	if ((rv = kphysm_del_gethandle(&mh)) != KPHYSM_OK) {
1160*10106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_gethandle() = %d", __func__, rv);
1161*10106SJason.Beloro@Sun.COM 		return (rv);
1162*10106SJason.Beloro@Sun.COM 	}
1163*10106SJason.Beloro@Sun.COM 	if ((rv = kphysm_del_span_query(base, npgs, &mq))
1164*10106SJason.Beloro@Sun.COM 	    != KPHYSM_OK) {
1165*10106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_span_query() = %d", __func__, rv);
1166*10106SJason.Beloro@Sun.COM 		goto done;
1167*10106SJason.Beloro@Sun.COM 	}
1168*10106SJason.Beloro@Sun.COM 	if (mq.nonrelocatable) {
1169*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: non-reloc pages = %ld",
1170*10106SJason.Beloro@Sun.COM 		    __func__, mq.nonrelocatable);
1171*10106SJason.Beloro@Sun.COM 		rv = KPHYSM_ENONRELOC;
1172*10106SJason.Beloro@Sun.COM 		goto done;
1173*10106SJason.Beloro@Sun.COM 	}
1174*10106SJason.Beloro@Sun.COM 	if (rv = kcage_range_delete(base, npgs)) {
1175*10106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_range() = %d", __func__, rv);
1176*10106SJason.Beloro@Sun.COM 		goto done;
1177*10106SJason.Beloro@Sun.COM 	} else {
1178*10106SJason.Beloro@Sun.COM 		del_range++;
1179*10106SJason.Beloro@Sun.COM 	}
1180*10106SJason.Beloro@Sun.COM 	if ((rv = kphysm_del_span(mh, base, npgs)) != KPHYSM_OK) {
1181*10106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_span() = %d", __func__, rv);
1182*10106SJason.Beloro@Sun.COM 		goto done;
1183*10106SJason.Beloro@Sun.COM 	}
1184*10106SJason.Beloro@Sun.COM 	if ((rv = memlist_add_span(ptob(base), ptob(npgs), &d_ml))
1185*10106SJason.Beloro@Sun.COM 	    != MEML_SPANOP_OK) {
1186*10106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: add_span() = %d", __func__, rv);
1187*10106SJason.Beloro@Sun.COM 		goto done;
1188*10106SJason.Beloro@Sun.COM 	}
1189*10106SJason.Beloro@Sun.COM 
1190*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: reserved=0x%lx", __func__, npgs);
1191*10106SJason.Beloro@Sun.COM 
1192*10106SJason.Beloro@Sun.COM 	bzero((void *) &ms, sizeof (ms));
1193*10106SJason.Beloro@Sun.COM 
1194*10106SJason.Beloro@Sun.COM 	mutex_init(&ms.lock, NULL, MUTEX_DRIVER, NULL);
1195*10106SJason.Beloro@Sun.COM 	cv_init(&ms.cond, NULL, CV_DRIVER, NULL);
1196*10106SJason.Beloro@Sun.COM 	mutex_enter(&ms.lock);
1197*10106SJason.Beloro@Sun.COM 
1198*10106SJason.Beloro@Sun.COM 	if ((rv = kphysm_del_start(mh, del_done, (void *) &ms)) == KPHYSM_OK) {
1199*10106SJason.Beloro@Sun.COM 		/*
1200*10106SJason.Beloro@Sun.COM 		 * Since we've called drctl_config_init, we are the only
1201*10106SJason.Beloro@Sun.COM 		 * DR ctl operation in progress.  Set dr_mh to the
1202*10106SJason.Beloro@Sun.COM 		 * delete memhandle for use by stat and cancel.
1203*10106SJason.Beloro@Sun.COM 		 */
1204*10106SJason.Beloro@Sun.COM 		ASSERT(dr_mh == NULL);
1205*10106SJason.Beloro@Sun.COM 		dr_mh = mh;
1206*10106SJason.Beloro@Sun.COM 
1207*10106SJason.Beloro@Sun.COM 		/*
1208*10106SJason.Beloro@Sun.COM 		 * Wait for completion or interrupt.
1209*10106SJason.Beloro@Sun.COM 		 */
1210*10106SJason.Beloro@Sun.COM 		while (!ms.done) {
1211*10106SJason.Beloro@Sun.COM 			if (cv_wait_sig(&ms.cond, &ms.lock) == 0) {
1212*10106SJason.Beloro@Sun.COM 				/*
1213*10106SJason.Beloro@Sun.COM 				 * There is a pending signal.
1214*10106SJason.Beloro@Sun.COM 				 */
1215*10106SJason.Beloro@Sun.COM 				(void) kphysm_del_cancel(mh);
1216*10106SJason.Beloro@Sun.COM 				DR_DBG_MEM("%s: cancel", __func__);
1217*10106SJason.Beloro@Sun.COM 				/*
1218*10106SJason.Beloro@Sun.COM 				 * Wait for completion.
1219*10106SJason.Beloro@Sun.COM 				 */
1220*10106SJason.Beloro@Sun.COM 				while (!ms.done)
1221*10106SJason.Beloro@Sun.COM 					cv_wait(&ms.cond, &ms.lock);
1222*10106SJason.Beloro@Sun.COM 			}
1223*10106SJason.Beloro@Sun.COM 		}
1224*10106SJason.Beloro@Sun.COM 		dr_mh = NULL;
1225*10106SJason.Beloro@Sun.COM 		rv = ms.error;
1226*10106SJason.Beloro@Sun.COM 	} else {
1227*10106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: del_start() = %d", __func__, rv);
1228*10106SJason.Beloro@Sun.COM 	}
1229*10106SJason.Beloro@Sun.COM 
1230*10106SJason.Beloro@Sun.COM 	mutex_exit(&ms.lock);
1231*10106SJason.Beloro@Sun.COM 	cv_destroy(&ms.cond);
1232*10106SJason.Beloro@Sun.COM 	mutex_destroy(&ms.lock);
1233*10106SJason.Beloro@Sun.COM 
1234*10106SJason.Beloro@Sun.COM done:
1235*10106SJason.Beloro@Sun.COM 	if (rv && del_range) {
1236*10106SJason.Beloro@Sun.COM 		/*
1237*10106SJason.Beloro@Sun.COM 		 * Add back the spans to the kcage growth list.
1238*10106SJason.Beloro@Sun.COM 		 */
1239*10106SJason.Beloro@Sun.COM 		for (ml = d_ml; ml; ml = ml->next)
1240*10106SJason.Beloro@Sun.COM 			if (err = kcage_range_add(btop(ml->address),
1241*10106SJason.Beloro@Sun.COM 			    btop(ml->size), KCAGE_DOWN))
1242*10106SJason.Beloro@Sun.COM 				cmn_err(CE_WARN, "kcage_range_add() = %d", err);
1243*10106SJason.Beloro@Sun.COM 	}
1244*10106SJason.Beloro@Sun.COM 	memlist_free_list(d_ml);
1245*10106SJason.Beloro@Sun.COM 
1246*10106SJason.Beloro@Sun.COM 	if ((err = kphysm_del_release(mh)) != KPHYSM_OK)
1247*10106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_release() = %d", __func__, err);
1248*10106SJason.Beloro@Sun.COM 
1249*10106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: rv=%d", __func__, rv);
1250*10106SJason.Beloro@Sun.COM 
1251*10106SJason.Beloro@Sun.COM 	return (rv);
1252*10106SJason.Beloro@Sun.COM }
1253