xref: /onnv-gate/usr/src/uts/sun4v/io/dr_mem.c (revision 11474:857f9db4ef05)
110106SJason.Beloro@Sun.COM /*
210106SJason.Beloro@Sun.COM  * CDDL HEADER START
310106SJason.Beloro@Sun.COM  *
410106SJason.Beloro@Sun.COM  * The contents of this file are subject to the terms of the
510106SJason.Beloro@Sun.COM  * Common Development and Distribution License (the "License").
610106SJason.Beloro@Sun.COM  * You may not use this file except in compliance with the License.
710106SJason.Beloro@Sun.COM  *
810106SJason.Beloro@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910106SJason.Beloro@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010106SJason.Beloro@Sun.COM  * See the License for the specific language governing permissions
1110106SJason.Beloro@Sun.COM  * and limitations under the License.
1210106SJason.Beloro@Sun.COM  *
1310106SJason.Beloro@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410106SJason.Beloro@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510106SJason.Beloro@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610106SJason.Beloro@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710106SJason.Beloro@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810106SJason.Beloro@Sun.COM  *
1910106SJason.Beloro@Sun.COM  * CDDL HEADER END
2010106SJason.Beloro@Sun.COM  */
2110106SJason.Beloro@Sun.COM 
2210106SJason.Beloro@Sun.COM /*
23*11474SJonathan.Adams@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2410106SJason.Beloro@Sun.COM  * Use is subject to license terms.
2510106SJason.Beloro@Sun.COM  */
2610106SJason.Beloro@Sun.COM 
2710106SJason.Beloro@Sun.COM /*
2810106SJason.Beloro@Sun.COM  * sun4v Memory DR Module
2910106SJason.Beloro@Sun.COM  */
3010106SJason.Beloro@Sun.COM 
3110106SJason.Beloro@Sun.COM 
3210106SJason.Beloro@Sun.COM #include <sys/types.h>
3310106SJason.Beloro@Sun.COM #include <sys/cmn_err.h>
3410106SJason.Beloro@Sun.COM #include <sys/vmem.h>
3510106SJason.Beloro@Sun.COM #include <sys/kmem.h>
3610106SJason.Beloro@Sun.COM #include <sys/systm.h>
3710106SJason.Beloro@Sun.COM #include <sys/machsystm.h>	/* for page_freelist_coalesce() */
3810106SJason.Beloro@Sun.COM #include <sys/errno.h>
3910106SJason.Beloro@Sun.COM #include <sys/memnode.h>
4010106SJason.Beloro@Sun.COM #include <sys/memlist.h>
4110106SJason.Beloro@Sun.COM #include <sys/memlist_impl.h>
4210106SJason.Beloro@Sun.COM #include <sys/tuneable.h>
4310106SJason.Beloro@Sun.COM #include <sys/proc.h>
4410106SJason.Beloro@Sun.COM #include <sys/disp.h>
4510106SJason.Beloro@Sun.COM #include <sys/debug.h>
4610106SJason.Beloro@Sun.COM #include <sys/vm.h>
4710106SJason.Beloro@Sun.COM #include <sys/callb.h>
4810106SJason.Beloro@Sun.COM #include <sys/memlist_plat.h>	/* for installed_top_size() */
4910106SJason.Beloro@Sun.COM #include <sys/condvar_impl.h>	/* for CV_HAS_WAITERS() */
5010106SJason.Beloro@Sun.COM #include <sys/dumphdr.h>	/* for dump_resize() */
5110106SJason.Beloro@Sun.COM #include <sys/atomic.h>		/* for use in stats collection */
5210106SJason.Beloro@Sun.COM #include <sys/rwlock.h>
5310106SJason.Beloro@Sun.COM #include <vm/seg_kmem.h>
5410106SJason.Beloro@Sun.COM #include <vm/seg_kpm.h>
5510106SJason.Beloro@Sun.COM #include <vm/page.h>
5610106SJason.Beloro@Sun.COM #include <vm/vm_dep.h>
5710106SJason.Beloro@Sun.COM #define	SUNDDI_IMPL		/* so sunddi.h will not redefine splx() et al */
5810106SJason.Beloro@Sun.COM #include <sys/sunddi.h>
5910106SJason.Beloro@Sun.COM #include <sys/mem_config.h>
6010106SJason.Beloro@Sun.COM #include <sys/mem_cage.h>
6110106SJason.Beloro@Sun.COM #include <sys/lgrp.h>
6210106SJason.Beloro@Sun.COM #include <sys/ddi.h>
6310106SJason.Beloro@Sun.COM 
6410106SJason.Beloro@Sun.COM #include <sys/modctl.h>
6510106SJason.Beloro@Sun.COM #include <sys/sysevent/dr.h>
6610106SJason.Beloro@Sun.COM #include <sys/mach_descrip.h>
6710106SJason.Beloro@Sun.COM #include <sys/mdesc.h>
6810106SJason.Beloro@Sun.COM #include <sys/ds.h>
6910106SJason.Beloro@Sun.COM #include <sys/drctl.h>
7010106SJason.Beloro@Sun.COM #include <sys/dr_util.h>
7110106SJason.Beloro@Sun.COM #include <sys/dr_mem.h>
7210106SJason.Beloro@Sun.COM 
7310106SJason.Beloro@Sun.COM 
7410106SJason.Beloro@Sun.COM /*
7510106SJason.Beloro@Sun.COM  * DR operations are subject to Memory Alignment restrictions
7610106SJason.Beloro@Sun.COM  * for both address and the size of the request.
7710106SJason.Beloro@Sun.COM  */
7810106SJason.Beloro@Sun.COM #define	MA_ADDR	0x10000000	/* addr alignment 256M */
7910106SJason.Beloro@Sun.COM #define	MA_SIZE	0x10000000	/* size alignment 256M */
8010106SJason.Beloro@Sun.COM 
8110106SJason.Beloro@Sun.COM #define	MBLK_IS_VALID(m) \
8210106SJason.Beloro@Sun.COM 	(IS_P2ALIGNED((m)->addr, MA_ADDR) && IS_P2ALIGNED((m)->size, MA_SIZE))
8310106SJason.Beloro@Sun.COM 
8410106SJason.Beloro@Sun.COM static memhandle_t dr_mh;	/* memory handle for delete */
8510106SJason.Beloro@Sun.COM 
8610106SJason.Beloro@Sun.COM static struct modlmisc modlmisc = {
8710106SJason.Beloro@Sun.COM 	&mod_miscops,
8810106SJason.Beloro@Sun.COM 	"sun4v memory DR"
8910106SJason.Beloro@Sun.COM };
9010106SJason.Beloro@Sun.COM 
9110106SJason.Beloro@Sun.COM static struct modlinkage modlinkage = {
9210106SJason.Beloro@Sun.COM 	MODREV_1,
9310106SJason.Beloro@Sun.COM 	(void *)&modlmisc,
9410106SJason.Beloro@Sun.COM 	NULL
9510106SJason.Beloro@Sun.COM };
9610106SJason.Beloro@Sun.COM 
9710106SJason.Beloro@Sun.COM static int dr_mem_allow_unload = 0;
9810106SJason.Beloro@Sun.COM 
9910106SJason.Beloro@Sun.COM typedef int (*fn_t)(dr_mem_blk_t *, int *);
10010106SJason.Beloro@Sun.COM 
10110106SJason.Beloro@Sun.COM /*
10210106SJason.Beloro@Sun.COM  * Global Domain Services (DS) Handle
10310106SJason.Beloro@Sun.COM  */
10410106SJason.Beloro@Sun.COM static ds_svc_hdl_t ds_handle;
10510106SJason.Beloro@Sun.COM 
10610106SJason.Beloro@Sun.COM /*
10710106SJason.Beloro@Sun.COM  * Supported DS Capability Versions
10810106SJason.Beloro@Sun.COM  */
10910106SJason.Beloro@Sun.COM static ds_ver_t		dr_mem_vers[] = { { 1, 0 } };
11010106SJason.Beloro@Sun.COM #define	DR_MEM_NVERS	(sizeof (dr_mem_vers) / sizeof (dr_mem_vers[0]))
11110106SJason.Beloro@Sun.COM 
11210106SJason.Beloro@Sun.COM /*
11310106SJason.Beloro@Sun.COM  * DS Capability Description
11410106SJason.Beloro@Sun.COM  */
11510106SJason.Beloro@Sun.COM static ds_capability_t dr_mem_cap = {
11610106SJason.Beloro@Sun.COM 	DR_MEM_DS_ID,		/* svc_id */
11710106SJason.Beloro@Sun.COM 	dr_mem_vers,		/* vers */
11810106SJason.Beloro@Sun.COM 	DR_MEM_NVERS		/* nvers */
11910106SJason.Beloro@Sun.COM };
12010106SJason.Beloro@Sun.COM 
12110106SJason.Beloro@Sun.COM /*
12210106SJason.Beloro@Sun.COM  * DS Callbacks
12310106SJason.Beloro@Sun.COM  */
12410106SJason.Beloro@Sun.COM static void dr_mem_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
12510106SJason.Beloro@Sun.COM static void dr_mem_unreg_handler(ds_cb_arg_t arg);
12610106SJason.Beloro@Sun.COM static void dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
12710106SJason.Beloro@Sun.COM 
12810106SJason.Beloro@Sun.COM /*
12910106SJason.Beloro@Sun.COM  * DS Client Ops Vector
13010106SJason.Beloro@Sun.COM  */
13110106SJason.Beloro@Sun.COM static ds_clnt_ops_t dr_mem_ops = {
13210106SJason.Beloro@Sun.COM 	dr_mem_reg_handler,	/* ds_reg_cb */
13310106SJason.Beloro@Sun.COM 	dr_mem_unreg_handler,	/* ds_unreg_cb */
13410106SJason.Beloro@Sun.COM 	dr_mem_data_handler,	/* ds_data_cb */
13510106SJason.Beloro@Sun.COM 	NULL			/* cb_arg */
13610106SJason.Beloro@Sun.COM };
13710106SJason.Beloro@Sun.COM 
13810106SJason.Beloro@Sun.COM /*
13910106SJason.Beloro@Sun.COM  * Operation Results
14010106SJason.Beloro@Sun.COM  *
14110106SJason.Beloro@Sun.COM  * Used internally to gather results while an operation on a
14210106SJason.Beloro@Sun.COM  * list of mblks is in progress. In particular, it is used to
14310106SJason.Beloro@Sun.COM  * keep track of which mblks have already failed so that they are
14410106SJason.Beloro@Sun.COM  * not processed further, and the manner in which they failed.
14510106SJason.Beloro@Sun.COM  */
14610106SJason.Beloro@Sun.COM typedef struct {
14710106SJason.Beloro@Sun.COM 	uint64_t	addr;
14810106SJason.Beloro@Sun.COM 	uint64_t	size;
14910106SJason.Beloro@Sun.COM 	uint32_t	result;
15010106SJason.Beloro@Sun.COM 	uint32_t	status;
15110106SJason.Beloro@Sun.COM 	char		*string;
15210106SJason.Beloro@Sun.COM } dr_mem_res_t;
15310106SJason.Beloro@Sun.COM 
15410106SJason.Beloro@Sun.COM static char *
15510106SJason.Beloro@Sun.COM dr_mem_estr[] = {
15610106SJason.Beloro@Sun.COM 	"operation succeeded",		/* DR_MEM_RES_OK */
15710106SJason.Beloro@Sun.COM 	"operation failed",		/* DR_MEM_RES_FAILURE */
15810106SJason.Beloro@Sun.COM 	"operation was blocked",	/* DR_MEM_RES_BLOCKED */
15910106SJason.Beloro@Sun.COM 	"memory not defined in MD",	/* DR_MEM_RES_NOT_IN_MD */
16010106SJason.Beloro@Sun.COM 	"memory already in use",	/* DR_MEM_RES_ESPAN */
16110106SJason.Beloro@Sun.COM 	"memory access test failed",	/* DR_MEM_RES_EFAULT */
16210106SJason.Beloro@Sun.COM 	"resource not available",	/* DR_MEM_RES_ERESOURCE */
16310106SJason.Beloro@Sun.COM 	"permanent pages in span",	/* DR_MEM_RES_PERM */
16410106SJason.Beloro@Sun.COM 	"memory span busy",		/* DR_MEM_RES_EBUSY */
16510106SJason.Beloro@Sun.COM 	"VM viability test failed",	/* DR_MEM_RES_ENOTVIABLE */
16610106SJason.Beloro@Sun.COM 	"no pages to unconfigure",	/* DR_MEM_RES_ENOWORK */
16710106SJason.Beloro@Sun.COM 	"operation cancelled",		/* DR_MEM_RES_ECANCELLED */
16810106SJason.Beloro@Sun.COM 	"operation refused",		/* DR_MEM_RES_EREFUSED */
16910106SJason.Beloro@Sun.COM 	"memory span duplicate",	/* DR_MEM_RES_EDUP */
17010106SJason.Beloro@Sun.COM 	"invalid argument"		/* DR_MEM_RES_EINVAL */
17110106SJason.Beloro@Sun.COM };
17210106SJason.Beloro@Sun.COM 
17310106SJason.Beloro@Sun.COM typedef struct {
17410106SJason.Beloro@Sun.COM 	kcondvar_t cond;
17510106SJason.Beloro@Sun.COM 	kmutex_t lock;
17610106SJason.Beloro@Sun.COM 	int error;
17710106SJason.Beloro@Sun.COM 	int done;
17810106SJason.Beloro@Sun.COM } mem_sync_t;
17910106SJason.Beloro@Sun.COM 
18010106SJason.Beloro@Sun.COM /*
18110106SJason.Beloro@Sun.COM  * Internal Functions
18210106SJason.Beloro@Sun.COM  */
18310106SJason.Beloro@Sun.COM static int dr_mem_init(void);
18410106SJason.Beloro@Sun.COM static int dr_mem_fini(void);
18510106SJason.Beloro@Sun.COM 
18610106SJason.Beloro@Sun.COM static int dr_mem_list_wrk(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
18710106SJason.Beloro@Sun.COM static int dr_mem_list_query(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
18810106SJason.Beloro@Sun.COM static int dr_mem_del_stat(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
18910106SJason.Beloro@Sun.COM static int dr_mem_del_cancel(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
19010106SJason.Beloro@Sun.COM 
19110106SJason.Beloro@Sun.COM static int dr_mem_unconfigure(dr_mem_blk_t *, int *);
19210106SJason.Beloro@Sun.COM static int dr_mem_configure(dr_mem_blk_t *, int *);
19310106SJason.Beloro@Sun.COM static void dr_mem_query(dr_mem_blk_t *, dr_mem_query_t *);
19410106SJason.Beloro@Sun.COM 
19510106SJason.Beloro@Sun.COM static dr_mem_res_t *dr_mem_res_array_init(dr_mem_hdr_t *, drctl_rsrc_t *, int);
19610106SJason.Beloro@Sun.COM static void dr_mem_res_array_fini(dr_mem_res_t *res, int nres);
19710106SJason.Beloro@Sun.COM static size_t dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res,
19810106SJason.Beloro@Sun.COM     dr_mem_hdr_t **respp);
19910106SJason.Beloro@Sun.COM 
20010106SJason.Beloro@Sun.COM static int dr_mem_find(dr_mem_blk_t *mbp);
20110106SJason.Beloro@Sun.COM static mde_cookie_t dr_mem_find_node_md(dr_mem_blk_t *, md_t *, mde_cookie_t *);
20210106SJason.Beloro@Sun.COM 
20310106SJason.Beloro@Sun.COM static int mem_add(pfn_t, pgcnt_t);
20410106SJason.Beloro@Sun.COM static int mem_del(pfn_t, pgcnt_t);
20510106SJason.Beloro@Sun.COM 
20610106SJason.Beloro@Sun.COM extern int kphysm_add_memory_dynamic(pfn_t, pgcnt_t);
20710106SJason.Beloro@Sun.COM 
20810106SJason.Beloro@Sun.COM int
20910106SJason.Beloro@Sun.COM _init(void)
21010106SJason.Beloro@Sun.COM {
21110106SJason.Beloro@Sun.COM 	int	status;
21210106SJason.Beloro@Sun.COM 
21310106SJason.Beloro@Sun.COM 	/* check that Memory DR is enabled */
21410106SJason.Beloro@Sun.COM 	if (dr_is_disabled(DR_TYPE_MEM))
21510106SJason.Beloro@Sun.COM 		return (ENOTSUP);
21610106SJason.Beloro@Sun.COM 
21710106SJason.Beloro@Sun.COM 	if ((status = dr_mem_init()) != 0) {
21810106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "Memory DR initialization failed");
21910106SJason.Beloro@Sun.COM 		return (status);
22010106SJason.Beloro@Sun.COM 	}
22110106SJason.Beloro@Sun.COM 
22210106SJason.Beloro@Sun.COM 	if ((status = mod_install(&modlinkage)) != 0) {
22310106SJason.Beloro@Sun.COM 		(void) dr_mem_fini();
22410106SJason.Beloro@Sun.COM 	}
22510106SJason.Beloro@Sun.COM 
22610106SJason.Beloro@Sun.COM 	return (status);
22710106SJason.Beloro@Sun.COM }
22810106SJason.Beloro@Sun.COM 
22910106SJason.Beloro@Sun.COM int
23010106SJason.Beloro@Sun.COM _info(struct modinfo *modinfop)
23110106SJason.Beloro@Sun.COM {
23210106SJason.Beloro@Sun.COM 	return (mod_info(&modlinkage, modinfop));
23310106SJason.Beloro@Sun.COM }
23410106SJason.Beloro@Sun.COM 
23510106SJason.Beloro@Sun.COM int
23610106SJason.Beloro@Sun.COM _fini(void)
23710106SJason.Beloro@Sun.COM {
23810106SJason.Beloro@Sun.COM 	int	status;
23910106SJason.Beloro@Sun.COM 
24010106SJason.Beloro@Sun.COM 	if (dr_mem_allow_unload == 0)
24110106SJason.Beloro@Sun.COM 		return (EBUSY);
24210106SJason.Beloro@Sun.COM 
24310106SJason.Beloro@Sun.COM 	if ((status = mod_remove(&modlinkage)) == 0) {
24410106SJason.Beloro@Sun.COM 		(void) dr_mem_fini();
24510106SJason.Beloro@Sun.COM 	}
24610106SJason.Beloro@Sun.COM 
24710106SJason.Beloro@Sun.COM 	return (status);
24810106SJason.Beloro@Sun.COM }
24910106SJason.Beloro@Sun.COM 
25010106SJason.Beloro@Sun.COM static int
25110106SJason.Beloro@Sun.COM dr_mem_init(void)
25210106SJason.Beloro@Sun.COM {
25310106SJason.Beloro@Sun.COM 	int rv;
25410106SJason.Beloro@Sun.COM 
25510106SJason.Beloro@Sun.COM 	if ((rv = ds_cap_init(&dr_mem_cap, &dr_mem_ops)) != 0) {
25610106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "dr_mem: ds_cap_init failed: %d", rv);
25710106SJason.Beloro@Sun.COM 		return (rv);
25810106SJason.Beloro@Sun.COM 	}
25910106SJason.Beloro@Sun.COM 
26010106SJason.Beloro@Sun.COM 	return (0);
26110106SJason.Beloro@Sun.COM }
26210106SJason.Beloro@Sun.COM 
26310106SJason.Beloro@Sun.COM static int
26410106SJason.Beloro@Sun.COM dr_mem_fini(void)
26510106SJason.Beloro@Sun.COM {
26610106SJason.Beloro@Sun.COM 	int rv;
26710106SJason.Beloro@Sun.COM 
26810106SJason.Beloro@Sun.COM 	if ((rv = ds_cap_fini(&dr_mem_cap)) != 0) {
26910106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "dr_mem: ds_cap_fini failed: %d", rv);
27010106SJason.Beloro@Sun.COM 	}
27110106SJason.Beloro@Sun.COM 
27210106SJason.Beloro@Sun.COM 	return (rv);
27310106SJason.Beloro@Sun.COM }
27410106SJason.Beloro@Sun.COM 
27510106SJason.Beloro@Sun.COM static void
27610106SJason.Beloro@Sun.COM dr_mem_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
27710106SJason.Beloro@Sun.COM {
27810106SJason.Beloro@Sun.COM 	DR_DBG_MEM("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
27910106SJason.Beloro@Sun.COM 	    ver->major, ver->minor, hdl);
28010106SJason.Beloro@Sun.COM 
28110106SJason.Beloro@Sun.COM 	ds_handle = hdl;
28210106SJason.Beloro@Sun.COM }
28310106SJason.Beloro@Sun.COM 
28410106SJason.Beloro@Sun.COM static void
28510106SJason.Beloro@Sun.COM dr_mem_unreg_handler(ds_cb_arg_t arg)
28610106SJason.Beloro@Sun.COM {
28710106SJason.Beloro@Sun.COM 	DR_DBG_MEM("unreg_handler: arg=0x%p\n", arg);
28810106SJason.Beloro@Sun.COM 
28910106SJason.Beloro@Sun.COM 	ds_handle = DS_INVALID_HDL;
29010106SJason.Beloro@Sun.COM }
29110106SJason.Beloro@Sun.COM 
29210106SJason.Beloro@Sun.COM /*ARGSUSED*/
29310106SJason.Beloro@Sun.COM static void
29410106SJason.Beloro@Sun.COM dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
29510106SJason.Beloro@Sun.COM {
29610106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*req = buf;
29710106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	err_resp;
29810106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*resp = &err_resp;
29910106SJason.Beloro@Sun.COM 	int		resp_len = 0;
30010106SJason.Beloro@Sun.COM 	int		rv = EINVAL;
30110106SJason.Beloro@Sun.COM 
30210106SJason.Beloro@Sun.COM 	/*
30310106SJason.Beloro@Sun.COM 	 * Sanity check the message
30410106SJason.Beloro@Sun.COM 	 */
30510106SJason.Beloro@Sun.COM 	if (buflen < sizeof (dr_mem_hdr_t)) {
30610106SJason.Beloro@Sun.COM 		DR_DBG_MEM("incoming message short: expected at least %ld "
30710106SJason.Beloro@Sun.COM 		    "bytes, received %ld\n", sizeof (dr_mem_hdr_t), buflen);
30810106SJason.Beloro@Sun.COM 		goto done;
30910106SJason.Beloro@Sun.COM 	}
31010106SJason.Beloro@Sun.COM 
31110106SJason.Beloro@Sun.COM 	if (req == NULL) {
31210106SJason.Beloro@Sun.COM 		DR_DBG_MEM("empty message: expected at least %ld bytes\n",
31310106SJason.Beloro@Sun.COM 		    sizeof (dr_mem_hdr_t));
31410106SJason.Beloro@Sun.COM 		goto done;
31510106SJason.Beloro@Sun.COM 	}
31610106SJason.Beloro@Sun.COM 
31710106SJason.Beloro@Sun.COM 	DR_DBG_MEM("incoming request:\n");
31810106SJason.Beloro@Sun.COM 	DR_DBG_DUMP_MSG(buf, buflen);
31910106SJason.Beloro@Sun.COM 
32010106SJason.Beloro@Sun.COM 	/*
32110106SJason.Beloro@Sun.COM 	 * Process the command
32210106SJason.Beloro@Sun.COM 	 */
32310106SJason.Beloro@Sun.COM 	switch (req->msg_type) {
32410106SJason.Beloro@Sun.COM 	case DR_MEM_CONFIGURE:
32510106SJason.Beloro@Sun.COM 	case DR_MEM_UNCONFIGURE:
32610106SJason.Beloro@Sun.COM 		if (req->msg_arg == 0) {
32710106SJason.Beloro@Sun.COM 			DR_DBG_MEM("No mblks specified for operation\n");
32810106SJason.Beloro@Sun.COM 			goto done;
32910106SJason.Beloro@Sun.COM 		}
33010106SJason.Beloro@Sun.COM 		if ((rv = dr_mem_list_wrk(req, &resp, &resp_len)) != 0) {
33110106SJason.Beloro@Sun.COM 			DR_DBG_MEM("%s failed (%d)\n",
33210106SJason.Beloro@Sun.COM 			    (req->msg_type == DR_MEM_CONFIGURE) ?
33310106SJason.Beloro@Sun.COM 			    "Memory configure" : "Memory unconfigure", rv);
33410106SJason.Beloro@Sun.COM 		}
33510106SJason.Beloro@Sun.COM 		break;
33610106SJason.Beloro@Sun.COM 
33710106SJason.Beloro@Sun.COM 	case DR_MEM_UNCONF_STATUS:
33810106SJason.Beloro@Sun.COM 		if ((rv = dr_mem_del_stat(req, &resp, &resp_len)) != 0)
33910106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Memory delete status failed (%d)\n", rv);
34010106SJason.Beloro@Sun.COM 		break;
34110106SJason.Beloro@Sun.COM 
34210106SJason.Beloro@Sun.COM 	case DR_MEM_UNCONF_CANCEL:
34310106SJason.Beloro@Sun.COM 		if ((rv = dr_mem_del_cancel(req, &resp, &resp_len)) != 0)
34410106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Memory delete cancel failed (%d)\n", rv);
34510106SJason.Beloro@Sun.COM 		break;
34610106SJason.Beloro@Sun.COM 
34710106SJason.Beloro@Sun.COM 	case DR_MEM_QUERY:
34810106SJason.Beloro@Sun.COM 		if (req->msg_arg == 0) {
34910106SJason.Beloro@Sun.COM 			DR_DBG_MEM("No mblks specified for operation\n");
35010106SJason.Beloro@Sun.COM 			goto done;
35110106SJason.Beloro@Sun.COM 		}
35210106SJason.Beloro@Sun.COM 		if ((rv = dr_mem_list_query(req, &resp, &resp_len)) != 0)
35310106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Memory query failed (%d)\n", rv);
35410106SJason.Beloro@Sun.COM 		break;
35510106SJason.Beloro@Sun.COM 
35610106SJason.Beloro@Sun.COM 	default:
35710106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "unsupported memory DR operation (%d)",
35810106SJason.Beloro@Sun.COM 		    req->msg_type);
35910106SJason.Beloro@Sun.COM 		break;
36010106SJason.Beloro@Sun.COM 	}
36110106SJason.Beloro@Sun.COM 
36210106SJason.Beloro@Sun.COM done:
36310106SJason.Beloro@Sun.COM 	/* check if an error occurred */
36410106SJason.Beloro@Sun.COM 	if (resp == &err_resp) {
36510106SJason.Beloro@Sun.COM 		resp->req_num = (req) ? req->req_num : 0;
36610106SJason.Beloro@Sun.COM 		resp->msg_type = DR_MEM_ERROR;
36710106SJason.Beloro@Sun.COM 		resp->msg_arg = rv;
36810106SJason.Beloro@Sun.COM 		resp_len = sizeof (dr_mem_hdr_t);
36910106SJason.Beloro@Sun.COM 	}
37010106SJason.Beloro@Sun.COM 
37110106SJason.Beloro@Sun.COM 	DR_DBG_MEM("outgoing response:\n");
37210106SJason.Beloro@Sun.COM 	DR_DBG_DUMP_MSG(resp, resp_len);
37310106SJason.Beloro@Sun.COM 
37410106SJason.Beloro@Sun.COM 	/* send back the response */
37510106SJason.Beloro@Sun.COM 	if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
37610106SJason.Beloro@Sun.COM 		DR_DBG_MEM("ds_send failed\n");
37710106SJason.Beloro@Sun.COM 	}
37810106SJason.Beloro@Sun.COM 
37910106SJason.Beloro@Sun.COM 	/* free any allocated memory */
38010106SJason.Beloro@Sun.COM 	if (resp != &err_resp) {
38110106SJason.Beloro@Sun.COM 		kmem_free(resp, resp_len);
38210106SJason.Beloro@Sun.COM 	}
38310106SJason.Beloro@Sun.COM }
38410106SJason.Beloro@Sun.COM 
38510106SJason.Beloro@Sun.COM /*
38610106SJason.Beloro@Sun.COM  * Common routine to config or unconfig multiple mblks.
38710106SJason.Beloro@Sun.COM  *
38810106SJason.Beloro@Sun.COM  * Note: Do not modify result buffer or length on error.
38910106SJason.Beloro@Sun.COM  */
39010106SJason.Beloro@Sun.COM static int
39110106SJason.Beloro@Sun.COM dr_mem_list_wrk(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
39210106SJason.Beloro@Sun.COM {
39310106SJason.Beloro@Sun.COM 	int		rv;
39410106SJason.Beloro@Sun.COM 	int		idx;
39510106SJason.Beloro@Sun.COM 	int		count;
39610106SJason.Beloro@Sun.COM 	int		result;
39710106SJason.Beloro@Sun.COM 	int		status;
39810106SJason.Beloro@Sun.COM 	fn_t		dr_fn;
39910106SJason.Beloro@Sun.COM 	int		se_hint;
40010106SJason.Beloro@Sun.COM 	dr_mem_blk_t	*req_mblks;
40110106SJason.Beloro@Sun.COM 	dr_mem_res_t	*res;
40210106SJason.Beloro@Sun.COM 	int		drctl_cmd;
40310106SJason.Beloro@Sun.COM 	int		drctl_flags = 0;
40410106SJason.Beloro@Sun.COM 	drctl_rsrc_t	*drctl_req;
40510106SJason.Beloro@Sun.COM 	size_t		drctl_req_len;
40610106SJason.Beloro@Sun.COM 	drctl_resp_t	*drctl_resp;
40710106SJason.Beloro@Sun.COM 	drctl_rsrc_t	*drctl_rsrc;
40810106SJason.Beloro@Sun.COM 	size_t		drctl_resp_len = 0;
40910106SJason.Beloro@Sun.COM 	drctl_cookie_t	drctl_res_ck;
41010106SJason.Beloro@Sun.COM 
41110106SJason.Beloro@Sun.COM 	ASSERT((req != NULL) && (req->msg_arg != 0));
41210106SJason.Beloro@Sun.COM 
41310106SJason.Beloro@Sun.COM 	count = req->msg_arg;
41410106SJason.Beloro@Sun.COM 
41510106SJason.Beloro@Sun.COM 	/*
41610106SJason.Beloro@Sun.COM 	 * Extract all information that is specific
41710106SJason.Beloro@Sun.COM 	 * to the various types of operations.
41810106SJason.Beloro@Sun.COM 	 */
41910106SJason.Beloro@Sun.COM 	switch (req->msg_type) {
42010106SJason.Beloro@Sun.COM 	case DR_MEM_CONFIGURE:
42110106SJason.Beloro@Sun.COM 		dr_fn = dr_mem_configure;
42210106SJason.Beloro@Sun.COM 		drctl_cmd = DRCTL_MEM_CONFIG_REQUEST;
42310106SJason.Beloro@Sun.COM 		se_hint = SE_HINT_INSERT;
42410106SJason.Beloro@Sun.COM 		break;
42510106SJason.Beloro@Sun.COM 	case DR_MEM_UNCONFIGURE:
42610106SJason.Beloro@Sun.COM 		dr_fn = dr_mem_unconfigure;
42710106SJason.Beloro@Sun.COM 		drctl_cmd = DRCTL_MEM_UNCONFIG_REQUEST;
42810106SJason.Beloro@Sun.COM 		se_hint = SE_HINT_REMOVE;
42910106SJason.Beloro@Sun.COM 		break;
43010106SJason.Beloro@Sun.COM 	default:
43110106SJason.Beloro@Sun.COM 		/* Programming error if we reach this. */
43210106SJason.Beloro@Sun.COM 		cmn_err(CE_NOTE, "%s: bad msg_type %d\n",
43310106SJason.Beloro@Sun.COM 		    __func__, req->msg_type);
43410106SJason.Beloro@Sun.COM 		ASSERT(0);
43510106SJason.Beloro@Sun.COM 		return (-1);
43610106SJason.Beloro@Sun.COM 	}
43710106SJason.Beloro@Sun.COM 
43810106SJason.Beloro@Sun.COM 	/* the incoming array of mblks to operate on */
43910106SJason.Beloro@Sun.COM 	req_mblks = DR_MEM_CMD_MBLKS(req);
44010106SJason.Beloro@Sun.COM 
44110106SJason.Beloro@Sun.COM 	/* allocate drctl request msg based on incoming resource count */
44210106SJason.Beloro@Sun.COM 	drctl_req_len = sizeof (drctl_rsrc_t) * count;
44310106SJason.Beloro@Sun.COM 	drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
44410106SJason.Beloro@Sun.COM 
44510106SJason.Beloro@Sun.COM 	/* copy the size for the drctl call from the incoming request msg */
44610106SJason.Beloro@Sun.COM 	for (idx = 0; idx < count; idx++) {
44710106SJason.Beloro@Sun.COM 		drctl_req[idx].res_mem_addr = req_mblks[idx].addr;
44810106SJason.Beloro@Sun.COM 		drctl_req[idx].res_mem_size = req_mblks[idx].size;
44910106SJason.Beloro@Sun.COM 	}
45010106SJason.Beloro@Sun.COM 
45110106SJason.Beloro@Sun.COM 	rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
45210106SJason.Beloro@Sun.COM 	    count, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
45310106SJason.Beloro@Sun.COM 
45410106SJason.Beloro@Sun.COM 	ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
45510106SJason.Beloro@Sun.COM 
45610106SJason.Beloro@Sun.COM 	if (rv != 0) {
45710106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: drctl_config_init returned: %d\n",
45810106SJason.Beloro@Sun.COM 		    __func__, rv);
45910106SJason.Beloro@Sun.COM 		kmem_free(drctl_resp, drctl_resp_len);
46010106SJason.Beloro@Sun.COM 		kmem_free(drctl_req, drctl_req_len);
46110106SJason.Beloro@Sun.COM 		return (rv);
46210106SJason.Beloro@Sun.COM 	}
46310106SJason.Beloro@Sun.COM 
46410106SJason.Beloro@Sun.COM 	ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
46510106SJason.Beloro@Sun.COM 
46610106SJason.Beloro@Sun.COM 	drctl_rsrc = drctl_resp->resp_resources;
46710106SJason.Beloro@Sun.COM 
46810106SJason.Beloro@Sun.COM 	/* create the result scratch array */
46910106SJason.Beloro@Sun.COM 	res = dr_mem_res_array_init(req, drctl_rsrc, count);
47010106SJason.Beloro@Sun.COM 
47110106SJason.Beloro@Sun.COM 	/* perform the specified operation on each of the mblks */
47210106SJason.Beloro@Sun.COM 	for (idx = 0; idx < count; idx++) {
47310106SJason.Beloro@Sun.COM 		/*
47410106SJason.Beloro@Sun.COM 		 * If no action will be taken against the current
47510106SJason.Beloro@Sun.COM 		 * mblk, update the drctl resource information to
47610106SJason.Beloro@Sun.COM 		 * ensure that it gets recovered properly during
47710106SJason.Beloro@Sun.COM 		 * the drctl fini() call.
47810106SJason.Beloro@Sun.COM 		 */
47910106SJason.Beloro@Sun.COM 		if (res[idx].result != DR_MEM_RES_OK) {
48010106SJason.Beloro@Sun.COM 			drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
48110106SJason.Beloro@Sun.COM 			continue;
48210106SJason.Beloro@Sun.COM 		}
48310106SJason.Beloro@Sun.COM 
48410106SJason.Beloro@Sun.COM 		/* call the function to perform the actual operation */
48510106SJason.Beloro@Sun.COM 		result = (*dr_fn)(&req_mblks[idx], &status);
48610106SJason.Beloro@Sun.COM 
48710106SJason.Beloro@Sun.COM 		/* save off results of the operation */
48810106SJason.Beloro@Sun.COM 		res[idx].result = result;
48910106SJason.Beloro@Sun.COM 		res[idx].status = status;
49010106SJason.Beloro@Sun.COM 		res[idx].addr = req_mblks[idx].addr;	/* for partial case */
49110106SJason.Beloro@Sun.COM 		res[idx].size = req_mblks[idx].size;	/* for partial case */
49210106SJason.Beloro@Sun.COM 		res[idx].string = i_ddi_strdup(dr_mem_estr[result], KM_SLEEP);
49310106SJason.Beloro@Sun.COM 
49410106SJason.Beloro@Sun.COM 		/* save result for drctl fini() reusing init() msg memory */
49510106SJason.Beloro@Sun.COM 		drctl_req[idx].status = (result != DR_MEM_RES_OK) ?
49610106SJason.Beloro@Sun.COM 		    DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
49710106SJason.Beloro@Sun.COM 
49810106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: mblk 0x%lx.0x%lx stat %d result %d off '%s'\n",
49910106SJason.Beloro@Sun.COM 		    __func__, req_mblks[idx].addr, req_mblks[idx].size,
50010106SJason.Beloro@Sun.COM 		    drctl_req[idx].status, result,
50110106SJason.Beloro@Sun.COM 		    (res[idx].string) ? res[idx].string : "");
50210106SJason.Beloro@Sun.COM 	}
50310106SJason.Beloro@Sun.COM 
50410106SJason.Beloro@Sun.COM 	if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
50510106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: drctl_config_fini returned: %d\n",
50610106SJason.Beloro@Sun.COM 		    __func__, rv);
50710106SJason.Beloro@Sun.COM 
50810106SJason.Beloro@Sun.COM 	/*
50910106SJason.Beloro@Sun.COM 	 * Operation completed without any fatal errors.
51010106SJason.Beloro@Sun.COM 	 * Pack the response for transmission.
51110106SJason.Beloro@Sun.COM 	 */
51210106SJason.Beloro@Sun.COM 	*resp_len = dr_mem_pack_response(req, res, resp);
51310106SJason.Beloro@Sun.COM 
51410106SJason.Beloro@Sun.COM 	/* notify interested parties about the operation */
51510106SJason.Beloro@Sun.COM 	dr_generate_event(DR_TYPE_MEM, se_hint);
51610106SJason.Beloro@Sun.COM 
51710106SJason.Beloro@Sun.COM 	/*
51810106SJason.Beloro@Sun.COM 	 * Deallocate any scratch memory.
51910106SJason.Beloro@Sun.COM 	 */
52010106SJason.Beloro@Sun.COM 	kmem_free(drctl_resp, drctl_resp_len);
52110106SJason.Beloro@Sun.COM 	kmem_free(drctl_req, drctl_req_len);
52210106SJason.Beloro@Sun.COM 
52310106SJason.Beloro@Sun.COM 	dr_mem_res_array_fini(res, count);
52410106SJason.Beloro@Sun.COM 
52510106SJason.Beloro@Sun.COM 	return (0);
52610106SJason.Beloro@Sun.COM }
52710106SJason.Beloro@Sun.COM 
52810106SJason.Beloro@Sun.COM /*
52910106SJason.Beloro@Sun.COM  * Allocate and initialize a result array based on the initial
53010106SJason.Beloro@Sun.COM  * drctl operation. A valid result array is always returned.
53110106SJason.Beloro@Sun.COM  */
53210106SJason.Beloro@Sun.COM static dr_mem_res_t *
53310106SJason.Beloro@Sun.COM dr_mem_res_array_init(dr_mem_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
53410106SJason.Beloro@Sun.COM {
53510106SJason.Beloro@Sun.COM 	int		idx;
53610106SJason.Beloro@Sun.COM 	dr_mem_res_t	*res;
53710106SJason.Beloro@Sun.COM 	char		*err_str;
53810106SJason.Beloro@Sun.COM 	size_t		err_len;
53910106SJason.Beloro@Sun.COM 
54010106SJason.Beloro@Sun.COM 	/* allocate zero filled buffer to initialize fields */
54110106SJason.Beloro@Sun.COM 	res = kmem_zalloc(nrsrc * sizeof (dr_mem_res_t), KM_SLEEP);
54210106SJason.Beloro@Sun.COM 
54310106SJason.Beloro@Sun.COM 	/*
54410106SJason.Beloro@Sun.COM 	 * Fill in the result information for each resource.
54510106SJason.Beloro@Sun.COM 	 */
54610106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nrsrc; idx++) {
54710106SJason.Beloro@Sun.COM 		res[idx].addr = rsrc[idx].res_mem_addr;
54810106SJason.Beloro@Sun.COM 		res[idx].size = rsrc[idx].res_mem_size;
54910106SJason.Beloro@Sun.COM 		res[idx].result = DR_MEM_RES_OK;
55010106SJason.Beloro@Sun.COM 
55110106SJason.Beloro@Sun.COM 		if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
55210106SJason.Beloro@Sun.COM 			continue;
55310106SJason.Beloro@Sun.COM 
55410106SJason.Beloro@Sun.COM 		/*
55510106SJason.Beloro@Sun.COM 		 * Update the state information for this mblk.
55610106SJason.Beloro@Sun.COM 		 */
55710106SJason.Beloro@Sun.COM 		res[idx].result = DR_MEM_RES_BLOCKED;
55810106SJason.Beloro@Sun.COM 		res[idx].status = (req->msg_type == DR_MEM_CONFIGURE) ?
55910106SJason.Beloro@Sun.COM 		    DR_MEM_STAT_UNCONFIGURED : DR_MEM_STAT_CONFIGURED;
56010106SJason.Beloro@Sun.COM 
56110106SJason.Beloro@Sun.COM 		/*
56210106SJason.Beloro@Sun.COM 		 * If an error string exists, copy it out of the
56310106SJason.Beloro@Sun.COM 		 * message buffer. This eliminates any dependency
56410106SJason.Beloro@Sun.COM 		 * on the memory allocated for the message buffer
56510106SJason.Beloro@Sun.COM 		 * itself.
56610106SJason.Beloro@Sun.COM 		 */
56710106SJason.Beloro@Sun.COM 		if (rsrc[idx].offset != NULL) {
56810106SJason.Beloro@Sun.COM 			err_str = (char *)rsrc + rsrc[idx].offset;
56910106SJason.Beloro@Sun.COM 			err_len = strlen(err_str) + 1;
57010106SJason.Beloro@Sun.COM 
57110106SJason.Beloro@Sun.COM 			res[idx].string = kmem_alloc(err_len, KM_SLEEP);
57210106SJason.Beloro@Sun.COM 			bcopy(err_str, res[idx].string, err_len);
57310106SJason.Beloro@Sun.COM 		}
57410106SJason.Beloro@Sun.COM 	}
57510106SJason.Beloro@Sun.COM 
57610106SJason.Beloro@Sun.COM 	return (res);
57710106SJason.Beloro@Sun.COM }
57810106SJason.Beloro@Sun.COM 
57910106SJason.Beloro@Sun.COM static void
58010106SJason.Beloro@Sun.COM dr_mem_res_array_fini(dr_mem_res_t *res, int nres)
58110106SJason.Beloro@Sun.COM {
58210106SJason.Beloro@Sun.COM 	int	idx;
58310106SJason.Beloro@Sun.COM 	size_t	str_len;
58410106SJason.Beloro@Sun.COM 
58510106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nres; idx++) {
58610106SJason.Beloro@Sun.COM 		/* deallocate the error string if present */
58710106SJason.Beloro@Sun.COM 		if (res[idx].string) {
58810106SJason.Beloro@Sun.COM 			str_len = strlen(res[idx].string) + 1;
58910106SJason.Beloro@Sun.COM 			kmem_free(res[idx].string, str_len);
59010106SJason.Beloro@Sun.COM 		}
59110106SJason.Beloro@Sun.COM 	}
59210106SJason.Beloro@Sun.COM 
59310106SJason.Beloro@Sun.COM 	/* deallocate the result array itself */
59410106SJason.Beloro@Sun.COM 	kmem_free(res, sizeof (dr_mem_res_t) * nres);
59510106SJason.Beloro@Sun.COM }
59610106SJason.Beloro@Sun.COM 
59710106SJason.Beloro@Sun.COM /*
59810106SJason.Beloro@Sun.COM  * Allocate and pack a response message for transmission based
59910106SJason.Beloro@Sun.COM  * on the specified result array. A valid response message and
60010106SJason.Beloro@Sun.COM  * valid size information is always returned.
60110106SJason.Beloro@Sun.COM  */
60210106SJason.Beloro@Sun.COM static size_t
60310106SJason.Beloro@Sun.COM dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res, dr_mem_hdr_t **respp)
60410106SJason.Beloro@Sun.COM {
60510106SJason.Beloro@Sun.COM 	int		idx;
60610106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*resp;
60710106SJason.Beloro@Sun.COM 	dr_mem_stat_t	*resp_stat;
60810106SJason.Beloro@Sun.COM 	size_t		resp_len;
60910106SJason.Beloro@Sun.COM 	uint32_t	curr_off;
61010106SJason.Beloro@Sun.COM 	caddr_t		curr_str;
61110106SJason.Beloro@Sun.COM 	size_t		str_len;
61210106SJason.Beloro@Sun.COM 	size_t		stat_len;
61310106SJason.Beloro@Sun.COM 	int		nstat = req->msg_arg;
61410106SJason.Beloro@Sun.COM 
61510106SJason.Beloro@Sun.COM 	/*
61610106SJason.Beloro@Sun.COM 	 * Calculate the size of the response message
61710106SJason.Beloro@Sun.COM 	 * and allocate an appropriately sized buffer.
61810106SJason.Beloro@Sun.COM 	 */
61910106SJason.Beloro@Sun.COM 	resp_len = sizeof (dr_mem_hdr_t);
62010106SJason.Beloro@Sun.COM 
62110106SJason.Beloro@Sun.COM 	/* add the stat array size */
62210106SJason.Beloro@Sun.COM 	stat_len = sizeof (dr_mem_stat_t) * nstat;
62310106SJason.Beloro@Sun.COM 	resp_len += stat_len;
62410106SJason.Beloro@Sun.COM 
62510106SJason.Beloro@Sun.COM 	/* add the size of any error strings */
62610106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nstat; idx++) {
62710106SJason.Beloro@Sun.COM 		if (res[idx].string != NULL) {
62810106SJason.Beloro@Sun.COM 			resp_len += strlen(res[idx].string) + 1;
62910106SJason.Beloro@Sun.COM 		}
63010106SJason.Beloro@Sun.COM 	}
63110106SJason.Beloro@Sun.COM 
63210106SJason.Beloro@Sun.COM 	/* allocate the message buffer */
63310106SJason.Beloro@Sun.COM 	resp = kmem_zalloc(resp_len, KM_SLEEP);
63410106SJason.Beloro@Sun.COM 
63510106SJason.Beloro@Sun.COM 	/*
63610106SJason.Beloro@Sun.COM 	 * Fill in the header information.
63710106SJason.Beloro@Sun.COM 	 */
63810106SJason.Beloro@Sun.COM 	resp->req_num = req->req_num;
63910106SJason.Beloro@Sun.COM 	resp->msg_type = DR_MEM_OK;
64010106SJason.Beloro@Sun.COM 	resp->msg_arg = nstat;
64110106SJason.Beloro@Sun.COM 
64210106SJason.Beloro@Sun.COM 	/*
64310106SJason.Beloro@Sun.COM 	 * Fill in the stat information.
64410106SJason.Beloro@Sun.COM 	 */
64510106SJason.Beloro@Sun.COM 	resp_stat = DR_MEM_RESP_STATS(resp);
64610106SJason.Beloro@Sun.COM 
64710106SJason.Beloro@Sun.COM 	/* string offsets start immediately after stat array */
64810106SJason.Beloro@Sun.COM 	curr_off = sizeof (dr_mem_hdr_t) + stat_len;
64910106SJason.Beloro@Sun.COM 	curr_str = (char *)resp_stat + stat_len;
65010106SJason.Beloro@Sun.COM 
65110106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nstat; idx++) {
65210106SJason.Beloro@Sun.COM 		resp_stat[idx].addr = res[idx].addr;
65310106SJason.Beloro@Sun.COM 		resp_stat[idx].size = res[idx].size;
65410106SJason.Beloro@Sun.COM 		resp_stat[idx].result = res[idx].result;
65510106SJason.Beloro@Sun.COM 		resp_stat[idx].status = res[idx].status;
65610106SJason.Beloro@Sun.COM 
65710106SJason.Beloro@Sun.COM 		if (res[idx].string != NULL) {
65810106SJason.Beloro@Sun.COM 			/* copy over the error string */
65910106SJason.Beloro@Sun.COM 			str_len = strlen(res[idx].string) + 1;
66010106SJason.Beloro@Sun.COM 			bcopy(res[idx].string, curr_str, str_len);
66110106SJason.Beloro@Sun.COM 			resp_stat[idx].string_off = curr_off;
66210106SJason.Beloro@Sun.COM 
66310106SJason.Beloro@Sun.COM 			curr_off += str_len;
66410106SJason.Beloro@Sun.COM 			curr_str += str_len;
66510106SJason.Beloro@Sun.COM 		}
66610106SJason.Beloro@Sun.COM 	}
66710106SJason.Beloro@Sun.COM 
66810106SJason.Beloro@Sun.COM 	/* buffer should be exactly filled */
66910106SJason.Beloro@Sun.COM 	ASSERT(curr_off == resp_len);
67010106SJason.Beloro@Sun.COM 
67110106SJason.Beloro@Sun.COM 	*respp = resp;
67210106SJason.Beloro@Sun.COM 	return (resp_len);
67310106SJason.Beloro@Sun.COM }
67410106SJason.Beloro@Sun.COM 
67510106SJason.Beloro@Sun.COM static void
67610106SJason.Beloro@Sun.COM dr_mem_query(dr_mem_blk_t *mbp, dr_mem_query_t *mqp)
67710106SJason.Beloro@Sun.COM {
67810106SJason.Beloro@Sun.COM 	memquery_t mq;
67910106SJason.Beloro@Sun.COM 
68010106SJason.Beloro@Sun.COM 	DR_DBG_MEM("dr_mem_query...\n");
68110106SJason.Beloro@Sun.COM 
68210106SJason.Beloro@Sun.COM 
68310106SJason.Beloro@Sun.COM 	(void) kphysm_del_span_query(btop(mbp->addr), btop(mbp->size), &mq);
68410106SJason.Beloro@Sun.COM 
68510106SJason.Beloro@Sun.COM 	if (!mq.phys_pages)
68610106SJason.Beloro@Sun.COM 		return;
68710106SJason.Beloro@Sun.COM 
68810106SJason.Beloro@Sun.COM 	mqp->addr = mbp->addr;
68910106SJason.Beloro@Sun.COM 	mqp->mq.phys_pages = ptob(mq.phys_pages);
69010106SJason.Beloro@Sun.COM 	mqp->mq.managed = ptob(mq.managed);
69110106SJason.Beloro@Sun.COM 	mqp->mq.nonrelocatable = ptob(mq.nonrelocatable);
69210106SJason.Beloro@Sun.COM 	mqp->mq.first_nonrelocatable = ptob(mq.first_nonrelocatable);
69310106SJason.Beloro@Sun.COM 	mqp->mq.last_nonrelocatable = ptob(mq.last_nonrelocatable);
69410106SJason.Beloro@Sun.COM 	/*
69510106SJason.Beloro@Sun.COM 	 * Set to the max byte offset within the page.
69610106SJason.Beloro@Sun.COM 	 */
69710106SJason.Beloro@Sun.COM 	if (mqp->mq.nonrelocatable)
69810106SJason.Beloro@Sun.COM 		mqp->mq.last_nonrelocatable += PAGESIZE - 1;
69910106SJason.Beloro@Sun.COM }
70010106SJason.Beloro@Sun.COM 
70110106SJason.Beloro@Sun.COM /*
70210106SJason.Beloro@Sun.COM  * Do not modify result buffer or length on error.
70310106SJason.Beloro@Sun.COM  */
70410106SJason.Beloro@Sun.COM static int
70510106SJason.Beloro@Sun.COM dr_mem_list_query(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
70610106SJason.Beloro@Sun.COM {
70710106SJason.Beloro@Sun.COM 	int		idx;
70810106SJason.Beloro@Sun.COM 	int		rlen;
70910106SJason.Beloro@Sun.COM 	int		nml;
71010106SJason.Beloro@Sun.COM 	struct memlist	*ml;
71110106SJason.Beloro@Sun.COM 	dr_mem_blk_t	*req_mblks, mb;
71210106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*rp;
71310106SJason.Beloro@Sun.COM 	dr_mem_query_t	*stat;
71410106SJason.Beloro@Sun.COM 
71511185SSean.McEnroe@Sun.COM 	drctl_block();
71611185SSean.McEnroe@Sun.COM 
71710106SJason.Beloro@Sun.COM 	/* the incoming array of req_mblks to configure */
71810106SJason.Beloro@Sun.COM 	req_mblks = DR_MEM_CMD_MBLKS(req);
71910106SJason.Beloro@Sun.COM 
72010106SJason.Beloro@Sun.COM 	/* allocate a response message, should be freed by caller */
72110106SJason.Beloro@Sun.COM 	nml = 0;
72210106SJason.Beloro@Sun.COM 	rlen = sizeof (dr_mem_hdr_t);
72310106SJason.Beloro@Sun.COM 	if (req_mblks->addr == NULL && req_mblks->size == 0) {
72410106SJason.Beloro@Sun.COM 		/*
72510106SJason.Beloro@Sun.COM 		 * Request is for domain's full view of it's memory.
72610106SJason.Beloro@Sun.COM 		 */
72710106SJason.Beloro@Sun.COM 		memlist_read_lock();
728*11474SJonathan.Adams@Sun.COM 		for (ml = phys_install; ml; ml = ml->ml_next)
72910106SJason.Beloro@Sun.COM 			nml++;
73010106SJason.Beloro@Sun.COM 
73110106SJason.Beloro@Sun.COM 		rlen += nml * sizeof (dr_mem_query_t);
73210106SJason.Beloro@Sun.COM 	} else {
73310106SJason.Beloro@Sun.COM 		rlen += req->msg_arg * sizeof (dr_mem_query_t);
73410106SJason.Beloro@Sun.COM 	}
73510106SJason.Beloro@Sun.COM 	rp = kmem_zalloc(rlen, KM_SLEEP);
73610106SJason.Beloro@Sun.COM 
73710106SJason.Beloro@Sun.COM 	/* fill in the known data */
73810106SJason.Beloro@Sun.COM 	rp->req_num = req->req_num;
73910106SJason.Beloro@Sun.COM 	rp->msg_type = DR_MEM_OK;
74010106SJason.Beloro@Sun.COM 	rp->msg_arg = nml ? nml : req->msg_arg;
74110106SJason.Beloro@Sun.COM 
74210106SJason.Beloro@Sun.COM 	/* stat array for the response */
74310106SJason.Beloro@Sun.COM 	stat = DR_MEM_RESP_QUERY(rp);
74410106SJason.Beloro@Sun.COM 
74510106SJason.Beloro@Sun.COM 	/* get the status for each of the mblocks */
74610106SJason.Beloro@Sun.COM 	if (nml) {
747*11474SJonathan.Adams@Sun.COM 		for (idx = 0, ml = phys_install; ml; ml = ml->ml_next, idx++) {
748*11474SJonathan.Adams@Sun.COM 			mb.addr = ml->ml_address;
749*11474SJonathan.Adams@Sun.COM 			mb.size = ml->ml_size;
75010106SJason.Beloro@Sun.COM 			dr_mem_query(&mb, &stat[idx]);
75110106SJason.Beloro@Sun.COM 		}
75210106SJason.Beloro@Sun.COM 		memlist_read_unlock();
75310106SJason.Beloro@Sun.COM 	} else {
75410106SJason.Beloro@Sun.COM 		for (idx = 0; idx < req->msg_arg; idx++)
75510106SJason.Beloro@Sun.COM 			dr_mem_query(&req_mblks[idx], &stat[idx]);
75610106SJason.Beloro@Sun.COM 	}
75710106SJason.Beloro@Sun.COM 
75810106SJason.Beloro@Sun.COM 	*resp = rp;
75910106SJason.Beloro@Sun.COM 	*resp_len = rlen;
76010106SJason.Beloro@Sun.COM 
76111185SSean.McEnroe@Sun.COM 	drctl_unblock();
76211185SSean.McEnroe@Sun.COM 
76310106SJason.Beloro@Sun.COM 	return (0);
76410106SJason.Beloro@Sun.COM }
76510106SJason.Beloro@Sun.COM 
76610106SJason.Beloro@Sun.COM static int
76710106SJason.Beloro@Sun.COM cvt_err(int err)
76810106SJason.Beloro@Sun.COM {
76910106SJason.Beloro@Sun.COM 	int rv;
77010106SJason.Beloro@Sun.COM 
77110106SJason.Beloro@Sun.COM 	switch (err) {
77210106SJason.Beloro@Sun.COM 	case KPHYSM_OK:
77310106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_OK;
77410106SJason.Beloro@Sun.COM 		break;
77510106SJason.Beloro@Sun.COM 	case KPHYSM_ESPAN:
77610106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ESPAN;
77710106SJason.Beloro@Sun.COM 		break;
77810106SJason.Beloro@Sun.COM 	case KPHYSM_EFAULT:
77910106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EFAULT;
78010106SJason.Beloro@Sun.COM 		break;
78110106SJason.Beloro@Sun.COM 	case KPHYSM_ERESOURCE:
78210106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ERESOURCE;
78310106SJason.Beloro@Sun.COM 		break;
78410106SJason.Beloro@Sun.COM 	case KPHYSM_ENOTSUP:
78510106SJason.Beloro@Sun.COM 	case KPHYSM_ENOHANDLES:
78610106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
78710106SJason.Beloro@Sun.COM 		break;
78810106SJason.Beloro@Sun.COM 	case KPHYSM_ENONRELOC:
78910106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_PERM;
79010106SJason.Beloro@Sun.COM 		break;
79110106SJason.Beloro@Sun.COM 	case KPHYSM_EHANDLE:
79210106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
79310106SJason.Beloro@Sun.COM 		break;
79410106SJason.Beloro@Sun.COM 	case KPHYSM_EBUSY:
79510106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EBUSY;
79610106SJason.Beloro@Sun.COM 		break;
79710106SJason.Beloro@Sun.COM 	case KPHYSM_ENOTVIABLE:
79810106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ENOTVIABLE;
79910106SJason.Beloro@Sun.COM 		break;
80010106SJason.Beloro@Sun.COM 	case KPHYSM_ESEQUENCE:
80110106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
80210106SJason.Beloro@Sun.COM 		break;
80310106SJason.Beloro@Sun.COM 	case KPHYSM_ENOWORK:
80410106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ENOWORK;
80510106SJason.Beloro@Sun.COM 		break;
80610106SJason.Beloro@Sun.COM 	case KPHYSM_ECANCELLED:
80710106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_ECANCELLED;
80810106SJason.Beloro@Sun.COM 		break;
80910106SJason.Beloro@Sun.COM 	case KPHYSM_EREFUSED:
81010106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EREFUSED;
81110106SJason.Beloro@Sun.COM 		break;
81210106SJason.Beloro@Sun.COM 	case KPHYSM_ENOTFINISHED:
81310106SJason.Beloro@Sun.COM 	case KPHYSM_ENOTRUNNING:
81410106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
81510106SJason.Beloro@Sun.COM 		break;
81610106SJason.Beloro@Sun.COM 	case KPHYSM_EDUP:
81710106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EDUP;
81810106SJason.Beloro@Sun.COM 		break;
81910106SJason.Beloro@Sun.COM 	default:
82010106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_FAILURE;
82110106SJason.Beloro@Sun.COM 		break;
82210106SJason.Beloro@Sun.COM 	}
82310106SJason.Beloro@Sun.COM 
82410106SJason.Beloro@Sun.COM 	return (rv);
82510106SJason.Beloro@Sun.COM }
82610106SJason.Beloro@Sun.COM 
82710106SJason.Beloro@Sun.COM static int
82810106SJason.Beloro@Sun.COM dr_mem_configure(dr_mem_blk_t *mbp, int *status)
82910106SJason.Beloro@Sun.COM {
83010106SJason.Beloro@Sun.COM 	int rv;
83111185SSean.McEnroe@Sun.COM 	uint64_t addr, size;
83210106SJason.Beloro@Sun.COM 
83310106SJason.Beloro@Sun.COM 	rv = 0;
83410106SJason.Beloro@Sun.COM 	addr = mbp->addr;
83510106SJason.Beloro@Sun.COM 	size = mbp->size;
83610106SJason.Beloro@Sun.COM 
83710106SJason.Beloro@Sun.COM 	DR_DBG_MEM("dr_mem_configure...\n");
83810106SJason.Beloro@Sun.COM 
83910106SJason.Beloro@Sun.COM 	if (!MBLK_IS_VALID(mbp)) {
84010106SJason.Beloro@Sun.COM 		DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n", addr, size);
84110106SJason.Beloro@Sun.COM 		*status = DR_MEM_STAT_UNCONFIGURED;
84210106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_EINVAL;
84310106SJason.Beloro@Sun.COM 	} else if (rv = dr_mem_find(mbp)) {
84410106SJason.Beloro@Sun.COM 		DR_DBG_MEM("failed to find mblk 0x%lx.0x%lx (%d)\n",
84510106SJason.Beloro@Sun.COM 		    addr, size, rv);
84610106SJason.Beloro@Sun.COM 		if (rv == EINVAL) {
84710106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_NOT_PRESENT;
84810106SJason.Beloro@Sun.COM 			rv = DR_MEM_RES_NOT_IN_MD;
84910106SJason.Beloro@Sun.COM 		} else {
85010106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_UNCONFIGURED;
85110106SJason.Beloro@Sun.COM 			rv = DR_MEM_RES_FAILURE;
85210106SJason.Beloro@Sun.COM 		}
85310106SJason.Beloro@Sun.COM 	} else {
85410106SJason.Beloro@Sun.COM 		rv = mem_add(btop(addr), btop(size));
85510106SJason.Beloro@Sun.COM 		DR_DBG_MEM("addr=0x%lx size=0x%lx rv=%d\n", addr, size, rv);
85610106SJason.Beloro@Sun.COM 		if (rv) {
85710106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_UNCONFIGURED;
85810106SJason.Beloro@Sun.COM 		} else {
85910106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_CONFIGURED;
86010106SJason.Beloro@Sun.COM 		}
86110106SJason.Beloro@Sun.COM 	}
86210106SJason.Beloro@Sun.COM 
86310106SJason.Beloro@Sun.COM 	return (rv);
86410106SJason.Beloro@Sun.COM }
86510106SJason.Beloro@Sun.COM 
86610106SJason.Beloro@Sun.COM static int
86710106SJason.Beloro@Sun.COM dr_mem_unconfigure(dr_mem_blk_t *mbp, int *status)
86810106SJason.Beloro@Sun.COM {
86910106SJason.Beloro@Sun.COM 	int rv;
87010106SJason.Beloro@Sun.COM 
87110106SJason.Beloro@Sun.COM 	DR_DBG_MEM("dr_mem_unconfigure...\n");
87210106SJason.Beloro@Sun.COM 
87310106SJason.Beloro@Sun.COM 	if (!MBLK_IS_VALID(mbp)) {
87410106SJason.Beloro@Sun.COM 		DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n",
87510106SJason.Beloro@Sun.COM 		    mbp->addr, mbp->size);
87610106SJason.Beloro@Sun.COM 			*status = DR_MEM_STAT_CONFIGURED;
87710106SJason.Beloro@Sun.COM 			rv = DR_MEM_RES_EINVAL;
87810106SJason.Beloro@Sun.COM 	} else if (rv = mem_del(btop(mbp->addr), btop(mbp->size))) {
87910106SJason.Beloro@Sun.COM 		*status = DR_MEM_STAT_CONFIGURED;
88010106SJason.Beloro@Sun.COM 	} else {
88110106SJason.Beloro@Sun.COM 		*status = DR_MEM_STAT_UNCONFIGURED;
88210106SJason.Beloro@Sun.COM 		rv = DR_MEM_RES_OK;
88310106SJason.Beloro@Sun.COM 		DR_DBG_MEM("mblk 0x%lx.0x%lx unconfigured\n",
88410106SJason.Beloro@Sun.COM 		    mbp->addr, mbp->size);
88510106SJason.Beloro@Sun.COM 	}
88610106SJason.Beloro@Sun.COM 	return (rv);
88710106SJason.Beloro@Sun.COM }
88810106SJason.Beloro@Sun.COM 
88910106SJason.Beloro@Sun.COM static int
89010106SJason.Beloro@Sun.COM dr_mem_del_stat(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
89110106SJason.Beloro@Sun.COM {
89210106SJason.Beloro@Sun.COM 	int			status;
89310106SJason.Beloro@Sun.COM 	int			rlen;
89410106SJason.Beloro@Sun.COM 	memdelstat_t		del_stat, *stat;
89510106SJason.Beloro@Sun.COM 	dr_mem_hdr_t		*rp;
89610106SJason.Beloro@Sun.COM 
89710106SJason.Beloro@Sun.COM 	/*
89810106SJason.Beloro@Sun.COM 	 * If a mem delete is in progress, get its status.
89910106SJason.Beloro@Sun.COM 	 */
90010106SJason.Beloro@Sun.COM 	status = (dr_mh && (kphysm_del_status(dr_mh, &del_stat) == KPHYSM_OK));
90110106SJason.Beloro@Sun.COM 
90210106SJason.Beloro@Sun.COM 	/* allocate a response message, should be freed by caller */
90310106SJason.Beloro@Sun.COM 	rlen = sizeof (dr_mem_hdr_t);
90410106SJason.Beloro@Sun.COM 	rlen += status * sizeof (memdelstat_t);
90510106SJason.Beloro@Sun.COM 	rp = kmem_zalloc(rlen, KM_SLEEP);
90610106SJason.Beloro@Sun.COM 
90710106SJason.Beloro@Sun.COM 	/* fill in the known data */
90810106SJason.Beloro@Sun.COM 	rp->req_num = req->req_num;
90910106SJason.Beloro@Sun.COM 	rp->msg_type = DR_MEM_OK;
91010106SJason.Beloro@Sun.COM 	rp->msg_arg = status;
91110106SJason.Beloro@Sun.COM 
91210106SJason.Beloro@Sun.COM 	if (status) {
91310106SJason.Beloro@Sun.COM 		/* stat struct for the response */
91410106SJason.Beloro@Sun.COM 		stat = DR_MEM_RESP_DEL_STAT(rp);
91510106SJason.Beloro@Sun.COM 		stat->phys_pages = ptob(del_stat.phys_pages);
91610106SJason.Beloro@Sun.COM 		stat->managed = ptob(del_stat.managed);
91710106SJason.Beloro@Sun.COM 		stat->collected = ptob(del_stat.collected);
91810106SJason.Beloro@Sun.COM 	}
91910106SJason.Beloro@Sun.COM 
92010106SJason.Beloro@Sun.COM 	*resp = rp;
92110106SJason.Beloro@Sun.COM 	*resp_len = rlen;
92210106SJason.Beloro@Sun.COM 
92310106SJason.Beloro@Sun.COM 	return (0);
92410106SJason.Beloro@Sun.COM }
92510106SJason.Beloro@Sun.COM 
92610106SJason.Beloro@Sun.COM static int
92710106SJason.Beloro@Sun.COM dr_mem_del_cancel(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
92810106SJason.Beloro@Sun.COM {
92910106SJason.Beloro@Sun.COM 	int		rlen;
93010106SJason.Beloro@Sun.COM 	dr_mem_hdr_t	*rp;
93110106SJason.Beloro@Sun.COM 
93210106SJason.Beloro@Sun.COM 	/* allocate a response message, should be freed by caller */
93310106SJason.Beloro@Sun.COM 	rlen = sizeof (dr_mem_hdr_t);
93410106SJason.Beloro@Sun.COM 	rp = kmem_zalloc(rlen, KM_SLEEP);
93510106SJason.Beloro@Sun.COM 
93610106SJason.Beloro@Sun.COM 	/* fill in the known data */
93710106SJason.Beloro@Sun.COM 	rp->req_num = req->req_num;
93810106SJason.Beloro@Sun.COM 	rp->msg_type = DR_MEM_OK;
93910106SJason.Beloro@Sun.COM 	rp->msg_arg = (dr_mh && kphysm_del_cancel(dr_mh) != KPHYSM_OK) ?
94010106SJason.Beloro@Sun.COM 	    DR_MEM_RES_EINVAL : DR_MEM_RES_OK;
94110106SJason.Beloro@Sun.COM 
94210106SJason.Beloro@Sun.COM 	*resp = rp;
94310106SJason.Beloro@Sun.COM 	*resp_len = rlen;
94410106SJason.Beloro@Sun.COM 
94510106SJason.Beloro@Sun.COM 	return (0);
94610106SJason.Beloro@Sun.COM }
94710106SJason.Beloro@Sun.COM 
94810106SJason.Beloro@Sun.COM static int
94910106SJason.Beloro@Sun.COM dr_mem_find(dr_mem_blk_t *mbp)
95010106SJason.Beloro@Sun.COM {
95110106SJason.Beloro@Sun.COM 	md_t		*mdp = NULL;
95210106SJason.Beloro@Sun.COM 	int		num_nodes;
95310106SJason.Beloro@Sun.COM 	int		rv = 0;
95410106SJason.Beloro@Sun.COM 	int		listsz;
95510106SJason.Beloro@Sun.COM 	mde_cookie_t	*listp = NULL;
95610106SJason.Beloro@Sun.COM 	mde_cookie_t	memnode;
95710106SJason.Beloro@Sun.COM 	char		*found = "found";
95810106SJason.Beloro@Sun.COM 
95910106SJason.Beloro@Sun.COM 	if ((mdp = md_get_handle()) == NULL) {
96010106SJason.Beloro@Sun.COM 		DR_DBG_MEM("unable to initialize machine description\n");
96110106SJason.Beloro@Sun.COM 		return (-1);
96210106SJason.Beloro@Sun.COM 	}
96310106SJason.Beloro@Sun.COM 
96410106SJason.Beloro@Sun.COM 	num_nodes = md_node_count(mdp);
96510106SJason.Beloro@Sun.COM 	ASSERT(num_nodes > 0);
96610106SJason.Beloro@Sun.COM 
96710106SJason.Beloro@Sun.COM 	listsz = num_nodes * sizeof (mde_cookie_t);
96810106SJason.Beloro@Sun.COM 	listp = kmem_zalloc(listsz, KM_SLEEP);
96910106SJason.Beloro@Sun.COM 
97010106SJason.Beloro@Sun.COM 	memnode = dr_mem_find_node_md(mbp, mdp, listp);
97110106SJason.Beloro@Sun.COM 
97210106SJason.Beloro@Sun.COM 	if (memnode == MDE_INVAL_ELEM_COOKIE) {
97310106SJason.Beloro@Sun.COM 		rv = EINVAL;
97410106SJason.Beloro@Sun.COM 		found = "not found";
97510106SJason.Beloro@Sun.COM 	}
97610106SJason.Beloro@Sun.COM 
97710106SJason.Beloro@Sun.COM 	DR_DBG_MEM("mblk 0x%lx.0x%lx %s\n", mbp->addr, mbp->size, found);
97810106SJason.Beloro@Sun.COM 
97910106SJason.Beloro@Sun.COM 	kmem_free(listp, listsz);
98010106SJason.Beloro@Sun.COM 	(void) md_fini_handle(mdp);
98110106SJason.Beloro@Sun.COM 
98210106SJason.Beloro@Sun.COM 	return (rv);
98310106SJason.Beloro@Sun.COM }
98410106SJason.Beloro@Sun.COM 
98510106SJason.Beloro@Sun.COM /*
98610106SJason.Beloro@Sun.COM  * Look up a particular mblk in the MD. Returns the mde_cookie_t
98710106SJason.Beloro@Sun.COM  * representing that mblk if present, and MDE_INVAL_ELEM_COOKIE
98810106SJason.Beloro@Sun.COM  * otherwise. It is assumed the scratch array has already been
98910106SJason.Beloro@Sun.COM  * allocated so that it can accommodate the worst case scenario,
99010106SJason.Beloro@Sun.COM  * every node in the MD.
99110106SJason.Beloro@Sun.COM  */
99210106SJason.Beloro@Sun.COM static mde_cookie_t
99310106SJason.Beloro@Sun.COM dr_mem_find_node_md(dr_mem_blk_t *mbp, md_t *mdp, mde_cookie_t *listp)
99410106SJason.Beloro@Sun.COM {
99510106SJason.Beloro@Sun.COM 	int		idx;
99610106SJason.Beloro@Sun.COM 	int		nnodes;
99710106SJason.Beloro@Sun.COM 	mde_cookie_t	rootnode;
99810106SJason.Beloro@Sun.COM 	uint64_t	base_prop;
99910106SJason.Beloro@Sun.COM 	uint64_t	size_prop;
100010106SJason.Beloro@Sun.COM 	mde_cookie_t	result = MDE_INVAL_ELEM_COOKIE;
100110106SJason.Beloro@Sun.COM 
100210106SJason.Beloro@Sun.COM 	rootnode = md_root_node(mdp);
100310106SJason.Beloro@Sun.COM 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
100410106SJason.Beloro@Sun.COM 
100510106SJason.Beloro@Sun.COM 	/*
100610106SJason.Beloro@Sun.COM 	 * Scan the DAG for all the mem nodes
100710106SJason.Beloro@Sun.COM 	 */
100810106SJason.Beloro@Sun.COM 	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "mblock"),
100910106SJason.Beloro@Sun.COM 	    md_find_name(mdp, "fwd"), listp);
101010106SJason.Beloro@Sun.COM 
101110106SJason.Beloro@Sun.COM 	if (nnodes < 0) {
101210106SJason.Beloro@Sun.COM 		DR_DBG_MEM("Scan for mblks failed\n");
101310106SJason.Beloro@Sun.COM 		return (result);
101410106SJason.Beloro@Sun.COM 	}
101510106SJason.Beloro@Sun.COM 
101610106SJason.Beloro@Sun.COM 	DR_DBG_MEM("dr_mem_find_node_md: found %d mblks in the MD\n", nnodes);
101710106SJason.Beloro@Sun.COM 
101810106SJason.Beloro@Sun.COM 	/*
101910106SJason.Beloro@Sun.COM 	 * Find the mblk of interest
102010106SJason.Beloro@Sun.COM 	 */
102110106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nnodes; idx++) {
102210106SJason.Beloro@Sun.COM 
102310106SJason.Beloro@Sun.COM 		if (md_get_prop_val(mdp, listp[idx], "base", &base_prop)) {
102410106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Missing 'base' property for mblk node %d\n",
102510106SJason.Beloro@Sun.COM 			    idx);
102610106SJason.Beloro@Sun.COM 			break;
102710106SJason.Beloro@Sun.COM 		}
102810106SJason.Beloro@Sun.COM 
102910106SJason.Beloro@Sun.COM 		if (md_get_prop_val(mdp, listp[idx], "size", &size_prop)) {
103010106SJason.Beloro@Sun.COM 			DR_DBG_MEM("Missing 'size' property for mblk node %d\n",
103110106SJason.Beloro@Sun.COM 			    idx);
103210106SJason.Beloro@Sun.COM 			break;
103310106SJason.Beloro@Sun.COM 		}
103410106SJason.Beloro@Sun.COM 
103510106SJason.Beloro@Sun.COM 		if (base_prop <= mbp->addr &&
103610106SJason.Beloro@Sun.COM 		    (base_prop + size_prop) >= (mbp->addr + mbp->size)) {
103710106SJason.Beloro@Sun.COM 			/* found a match */
103810106SJason.Beloro@Sun.COM 			DR_DBG_MEM("dr_mem_find_node_md: found mblk "
103910106SJason.Beloro@Sun.COM 			    "0x%lx.0x%lx in MD\n", mbp->addr, mbp->size);
104010106SJason.Beloro@Sun.COM 			result = listp[idx];
104110106SJason.Beloro@Sun.COM 			break;
104210106SJason.Beloro@Sun.COM 		}
104310106SJason.Beloro@Sun.COM 	}
104410106SJason.Beloro@Sun.COM 
104510106SJason.Beloro@Sun.COM 	if (result == MDE_INVAL_ELEM_COOKIE) {
104610106SJason.Beloro@Sun.COM 		DR_DBG_MEM("mblk 0x%lx.0x%lx not in MD\n",
104710106SJason.Beloro@Sun.COM 		    mbp->addr, mbp->size);
104810106SJason.Beloro@Sun.COM 	}
104910106SJason.Beloro@Sun.COM 
105010106SJason.Beloro@Sun.COM 	return (result);
105110106SJason.Beloro@Sun.COM }
105210106SJason.Beloro@Sun.COM 
105310106SJason.Beloro@Sun.COM static int
105410106SJason.Beloro@Sun.COM mem_add(pfn_t base, pgcnt_t npgs)
105510106SJason.Beloro@Sun.COM {
105610106SJason.Beloro@Sun.COM 	int rv, rc;
105710106SJason.Beloro@Sun.COM 
105810106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
105910106SJason.Beloro@Sun.COM 
106010106SJason.Beloro@Sun.COM 	if (npgs == 0)
106111185SSean.McEnroe@Sun.COM 		return (DR_MEM_RES_OK);
106210106SJason.Beloro@Sun.COM 
106310106SJason.Beloro@Sun.COM 	rv = kphysm_add_memory_dynamic(base, npgs);
106410106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: kphysm_add(0x%lx, 0x%lx) = %d", __func__, base, npgs,
106510106SJason.Beloro@Sun.COM 	    rv);
106611185SSean.McEnroe@Sun.COM 	if (rv == KPHYSM_OK) {
106710106SJason.Beloro@Sun.COM 		if (rc = kcage_range_add(base, npgs, KCAGE_DOWN))
106810106SJason.Beloro@Sun.COM 			cmn_err(CE_WARN, "kcage_range_add() = %d", rc);
106910106SJason.Beloro@Sun.COM 	}
107011185SSean.McEnroe@Sun.COM 	rv = cvt_err(rv);
107110106SJason.Beloro@Sun.COM 	return (rv);
107210106SJason.Beloro@Sun.COM }
107310106SJason.Beloro@Sun.COM 
107410106SJason.Beloro@Sun.COM static void
107510106SJason.Beloro@Sun.COM del_done(void *arg, int error)
107610106SJason.Beloro@Sun.COM {
107710106SJason.Beloro@Sun.COM 	mem_sync_t *ms = arg;
107810106SJason.Beloro@Sun.COM 
107910106SJason.Beloro@Sun.COM 	mutex_enter(&ms->lock);
108010106SJason.Beloro@Sun.COM 	ms->error = error;
108110106SJason.Beloro@Sun.COM 	ms->done = 1;
108210106SJason.Beloro@Sun.COM 	cv_signal(&ms->cond);
108310106SJason.Beloro@Sun.COM 	mutex_exit(&ms->lock);
108410106SJason.Beloro@Sun.COM }
108510106SJason.Beloro@Sun.COM 
108610106SJason.Beloro@Sun.COM static int
108710106SJason.Beloro@Sun.COM mem_del(pfn_t base, pgcnt_t npgs)
108810106SJason.Beloro@Sun.COM {
108910106SJason.Beloro@Sun.COM 	int rv, err, del_range = 0;
109011185SSean.McEnroe@Sun.COM 	int convert = 1;
109110106SJason.Beloro@Sun.COM 	mem_sync_t ms;
109210106SJason.Beloro@Sun.COM 	memquery_t mq;
109310106SJason.Beloro@Sun.COM 	memhandle_t mh;
109410106SJason.Beloro@Sun.COM 	struct memlist *ml;
109510106SJason.Beloro@Sun.COM 	struct memlist *d_ml = NULL;
109610106SJason.Beloro@Sun.COM 
109710106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
109810106SJason.Beloro@Sun.COM 
109910106SJason.Beloro@Sun.COM 	if (npgs == 0)
110011185SSean.McEnroe@Sun.COM 		return (DR_MEM_RES_OK);
110110106SJason.Beloro@Sun.COM 
110210106SJason.Beloro@Sun.COM 	if ((rv = kphysm_del_gethandle(&mh)) != KPHYSM_OK) {
110310106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_gethandle() = %d", __func__, rv);
110411185SSean.McEnroe@Sun.COM 		rv = cvt_err(rv);
110510106SJason.Beloro@Sun.COM 		return (rv);
110610106SJason.Beloro@Sun.COM 	}
110710106SJason.Beloro@Sun.COM 	if ((rv = kphysm_del_span_query(base, npgs, &mq))
110810106SJason.Beloro@Sun.COM 	    != KPHYSM_OK) {
110910106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_span_query() = %d", __func__, rv);
111010106SJason.Beloro@Sun.COM 		goto done;
111110106SJason.Beloro@Sun.COM 	}
111210106SJason.Beloro@Sun.COM 	if (mq.nonrelocatable) {
111310106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: non-reloc pages = %ld",
111410106SJason.Beloro@Sun.COM 		    __func__, mq.nonrelocatable);
111511185SSean.McEnroe@Sun.COM 		rv  = KPHYSM_ENONRELOC;
111610106SJason.Beloro@Sun.COM 		goto done;
111710106SJason.Beloro@Sun.COM 	}
111810106SJason.Beloro@Sun.COM 	if (rv = kcage_range_delete(base, npgs)) {
111911185SSean.McEnroe@Sun.COM 		switch (rv) {
112011185SSean.McEnroe@Sun.COM 		case EBUSY:
112111185SSean.McEnroe@Sun.COM 			rv = DR_MEM_RES_ENOTVIABLE;
112211185SSean.McEnroe@Sun.COM 			break;
112311185SSean.McEnroe@Sun.COM 		default:
112411185SSean.McEnroe@Sun.COM 			rv = DR_MEM_RES_FAILURE;
112511185SSean.McEnroe@Sun.COM 			break;
112611185SSean.McEnroe@Sun.COM 		}
112711185SSean.McEnroe@Sun.COM 		convert = 0; /* conversion done */
112810106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_range() = %d", __func__, rv);
112910106SJason.Beloro@Sun.COM 		goto done;
113010106SJason.Beloro@Sun.COM 	} else {
113110106SJason.Beloro@Sun.COM 		del_range++;
113210106SJason.Beloro@Sun.COM 	}
113310106SJason.Beloro@Sun.COM 	if ((rv = kphysm_del_span(mh, base, npgs)) != KPHYSM_OK) {
113410106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_span() = %d", __func__, rv);
113510106SJason.Beloro@Sun.COM 		goto done;
113610106SJason.Beloro@Sun.COM 	}
113710106SJason.Beloro@Sun.COM 	if ((rv = memlist_add_span(ptob(base), ptob(npgs), &d_ml))
113810106SJason.Beloro@Sun.COM 	    != MEML_SPANOP_OK) {
113911185SSean.McEnroe@Sun.COM 		switch (rv) {
114011185SSean.McEnroe@Sun.COM 		case MEML_SPANOP_ESPAN:
114111185SSean.McEnroe@Sun.COM 			rv = DR_MEM_RES_ESPAN;
114211185SSean.McEnroe@Sun.COM 			break;
114311185SSean.McEnroe@Sun.COM 		case MEML_SPANOP_EALLOC:
114411185SSean.McEnroe@Sun.COM 			rv = DR_MEM_RES_ERESOURCE;
114511185SSean.McEnroe@Sun.COM 			break;
114611185SSean.McEnroe@Sun.COM 		default:
114711185SSean.McEnroe@Sun.COM 			rv = DR_MEM_RES_FAILURE;
114811185SSean.McEnroe@Sun.COM 			break;
114911185SSean.McEnroe@Sun.COM 		}
115011185SSean.McEnroe@Sun.COM 		convert = 0; /* conversion done */
115110106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: add_span() = %d", __func__, rv);
115210106SJason.Beloro@Sun.COM 		goto done;
115310106SJason.Beloro@Sun.COM 	}
115410106SJason.Beloro@Sun.COM 
115510106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: reserved=0x%lx", __func__, npgs);
115610106SJason.Beloro@Sun.COM 
115710106SJason.Beloro@Sun.COM 	bzero((void *) &ms, sizeof (ms));
115810106SJason.Beloro@Sun.COM 
115910106SJason.Beloro@Sun.COM 	mutex_init(&ms.lock, NULL, MUTEX_DRIVER, NULL);
116010106SJason.Beloro@Sun.COM 	cv_init(&ms.cond, NULL, CV_DRIVER, NULL);
116110106SJason.Beloro@Sun.COM 	mutex_enter(&ms.lock);
116210106SJason.Beloro@Sun.COM 
116310106SJason.Beloro@Sun.COM 	if ((rv = kphysm_del_start(mh, del_done, (void *) &ms)) == KPHYSM_OK) {
116410106SJason.Beloro@Sun.COM 		/*
116510106SJason.Beloro@Sun.COM 		 * Since we've called drctl_config_init, we are the only
116610106SJason.Beloro@Sun.COM 		 * DR ctl operation in progress.  Set dr_mh to the
116710106SJason.Beloro@Sun.COM 		 * delete memhandle for use by stat and cancel.
116810106SJason.Beloro@Sun.COM 		 */
116910106SJason.Beloro@Sun.COM 		ASSERT(dr_mh == NULL);
117010106SJason.Beloro@Sun.COM 		dr_mh = mh;
117110106SJason.Beloro@Sun.COM 
117210106SJason.Beloro@Sun.COM 		/*
117310106SJason.Beloro@Sun.COM 		 * Wait for completion or interrupt.
117410106SJason.Beloro@Sun.COM 		 */
117510106SJason.Beloro@Sun.COM 		while (!ms.done) {
117610106SJason.Beloro@Sun.COM 			if (cv_wait_sig(&ms.cond, &ms.lock) == 0) {
117710106SJason.Beloro@Sun.COM 				/*
117810106SJason.Beloro@Sun.COM 				 * There is a pending signal.
117910106SJason.Beloro@Sun.COM 				 */
118010106SJason.Beloro@Sun.COM 				(void) kphysm_del_cancel(mh);
118110106SJason.Beloro@Sun.COM 				DR_DBG_MEM("%s: cancel", __func__);
118210106SJason.Beloro@Sun.COM 				/*
118310106SJason.Beloro@Sun.COM 				 * Wait for completion.
118410106SJason.Beloro@Sun.COM 				 */
118510106SJason.Beloro@Sun.COM 				while (!ms.done)
118610106SJason.Beloro@Sun.COM 					cv_wait(&ms.cond, &ms.lock);
118710106SJason.Beloro@Sun.COM 			}
118810106SJason.Beloro@Sun.COM 		}
118910106SJason.Beloro@Sun.COM 		dr_mh = NULL;
119010106SJason.Beloro@Sun.COM 		rv = ms.error;
119110106SJason.Beloro@Sun.COM 	} else {
119210106SJason.Beloro@Sun.COM 		DR_DBG_MEM("%s: del_start() = %d", __func__, rv);
119310106SJason.Beloro@Sun.COM 	}
119410106SJason.Beloro@Sun.COM 
119510106SJason.Beloro@Sun.COM 	mutex_exit(&ms.lock);
119610106SJason.Beloro@Sun.COM 	cv_destroy(&ms.cond);
119710106SJason.Beloro@Sun.COM 	mutex_destroy(&ms.lock);
119810106SJason.Beloro@Sun.COM 
119910106SJason.Beloro@Sun.COM done:
120010106SJason.Beloro@Sun.COM 	if (rv && del_range) {
120110106SJason.Beloro@Sun.COM 		/*
120210106SJason.Beloro@Sun.COM 		 * Add back the spans to the kcage growth list.
120310106SJason.Beloro@Sun.COM 		 */
1204*11474SJonathan.Adams@Sun.COM 		for (ml = d_ml; ml; ml = ml->ml_next)
1205*11474SJonathan.Adams@Sun.COM 			if (err = kcage_range_add(btop(ml->ml_address),
1206*11474SJonathan.Adams@Sun.COM 			    btop(ml->ml_size), KCAGE_DOWN))
120710106SJason.Beloro@Sun.COM 				cmn_err(CE_WARN, "kcage_range_add() = %d", err);
120810106SJason.Beloro@Sun.COM 	}
120910106SJason.Beloro@Sun.COM 	memlist_free_list(d_ml);
121010106SJason.Beloro@Sun.COM 
121110106SJason.Beloro@Sun.COM 	if ((err = kphysm_del_release(mh)) != KPHYSM_OK)
121210106SJason.Beloro@Sun.COM 		cmn_err(CE_WARN, "%s: del_release() = %d", __func__, err);
121311185SSean.McEnroe@Sun.COM 	if (convert)
121411185SSean.McEnroe@Sun.COM 		rv = cvt_err(rv);
121510106SJason.Beloro@Sun.COM 
121610106SJason.Beloro@Sun.COM 	DR_DBG_MEM("%s: rv=%d", __func__, rv);
121710106SJason.Beloro@Sun.COM 
121810106SJason.Beloro@Sun.COM 	return (rv);
121910106SJason.Beloro@Sun.COM }
1220