xref: /illumos-gate/usr/src/uts/sun4v/io/dr_mem.c (revision 7331beb48fd554088b3de38ef30491d59e0d61f7)
19853d9e8SJason Beloro /*
29853d9e8SJason Beloro  * CDDL HEADER START
39853d9e8SJason Beloro  *
49853d9e8SJason Beloro  * The contents of this file are subject to the terms of the
59853d9e8SJason Beloro  * Common Development and Distribution License (the "License").
69853d9e8SJason Beloro  * You may not use this file except in compliance with the License.
79853d9e8SJason Beloro  *
89853d9e8SJason Beloro  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99853d9e8SJason Beloro  * or http://www.opensolaris.org/os/licensing.
109853d9e8SJason Beloro  * See the License for the specific language governing permissions
119853d9e8SJason Beloro  * and limitations under the License.
129853d9e8SJason Beloro  *
139853d9e8SJason Beloro  * When distributing Covered Code, include this CDDL HEADER in each
149853d9e8SJason Beloro  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159853d9e8SJason Beloro  * If applicable, add the following below this CDDL HEADER, with the
169853d9e8SJason Beloro  * fields enclosed by brackets "[]" replaced with your own identifying
179853d9e8SJason Beloro  * information: Portions Copyright [yyyy] [name of copyright owner]
189853d9e8SJason Beloro  *
199853d9e8SJason Beloro  * CDDL HEADER END
209853d9e8SJason Beloro  */
219853d9e8SJason Beloro 
229853d9e8SJason Beloro /*
2302b4e56cSHaik Aftandilian  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
249853d9e8SJason Beloro  */
259853d9e8SJason Beloro 
269853d9e8SJason Beloro /*
279853d9e8SJason Beloro  * sun4v Memory DR Module
289853d9e8SJason Beloro  */
299853d9e8SJason Beloro 
309853d9e8SJason Beloro 
319853d9e8SJason Beloro #include <sys/types.h>
329853d9e8SJason Beloro #include <sys/cmn_err.h>
339853d9e8SJason Beloro #include <sys/vmem.h>
349853d9e8SJason Beloro #include <sys/kmem.h>
359853d9e8SJason Beloro #include <sys/systm.h>
369853d9e8SJason Beloro #include <sys/machsystm.h>	/* for page_freelist_coalesce() */
379853d9e8SJason Beloro #include <sys/errno.h>
389853d9e8SJason Beloro #include <sys/memnode.h>
399853d9e8SJason Beloro #include <sys/memlist.h>
409853d9e8SJason Beloro #include <sys/memlist_impl.h>
419853d9e8SJason Beloro #include <sys/tuneable.h>
429853d9e8SJason Beloro #include <sys/proc.h>
439853d9e8SJason Beloro #include <sys/disp.h>
449853d9e8SJason Beloro #include <sys/debug.h>
459853d9e8SJason Beloro #include <sys/vm.h>
469853d9e8SJason Beloro #include <sys/callb.h>
479853d9e8SJason Beloro #include <sys/memlist_plat.h>	/* for installed_top_size() */
489853d9e8SJason Beloro #include <sys/condvar_impl.h>	/* for CV_HAS_WAITERS() */
499853d9e8SJason Beloro #include <sys/dumphdr.h>	/* for dump_resize() */
509853d9e8SJason Beloro #include <sys/atomic.h>		/* for use in stats collection */
519853d9e8SJason Beloro #include <sys/rwlock.h>
529853d9e8SJason Beloro #include <vm/seg_kmem.h>
539853d9e8SJason Beloro #include <vm/seg_kpm.h>
549853d9e8SJason Beloro #include <vm/page.h>
559853d9e8SJason Beloro #include <vm/vm_dep.h>
569853d9e8SJason Beloro #define	SUNDDI_IMPL		/* so sunddi.h will not redefine splx() et al */
579853d9e8SJason Beloro #include <sys/sunddi.h>
589853d9e8SJason Beloro #include <sys/mem_config.h>
599853d9e8SJason Beloro #include <sys/mem_cage.h>
609853d9e8SJason Beloro #include <sys/lgrp.h>
619853d9e8SJason Beloro #include <sys/ddi.h>
629853d9e8SJason Beloro 
639853d9e8SJason Beloro #include <sys/modctl.h>
649853d9e8SJason Beloro #include <sys/sysevent/dr.h>
659853d9e8SJason Beloro #include <sys/mach_descrip.h>
669853d9e8SJason Beloro #include <sys/mdesc.h>
679853d9e8SJason Beloro #include <sys/ds.h>
689853d9e8SJason Beloro #include <sys/drctl.h>
699853d9e8SJason Beloro #include <sys/dr_util.h>
709853d9e8SJason Beloro #include <sys/dr_mem.h>
7102b4e56cSHaik Aftandilian #include <sys/suspend.h>
729853d9e8SJason Beloro 
739853d9e8SJason Beloro 
749853d9e8SJason Beloro /*
759853d9e8SJason Beloro  * DR operations are subject to Memory Alignment restrictions
769853d9e8SJason Beloro  * for both address and the size of the request.
779853d9e8SJason Beloro  */
789853d9e8SJason Beloro #define	MA_ADDR	0x10000000	/* addr alignment 256M */
799853d9e8SJason Beloro #define	MA_SIZE	0x10000000	/* size alignment 256M */
809853d9e8SJason Beloro 
819853d9e8SJason Beloro #define	MBLK_IS_VALID(m) \
829853d9e8SJason Beloro 	(IS_P2ALIGNED((m)->addr, MA_ADDR) && IS_P2ALIGNED((m)->size, MA_SIZE))
839853d9e8SJason Beloro 
849853d9e8SJason Beloro static memhandle_t dr_mh;	/* memory handle for delete */
859853d9e8SJason Beloro 
869853d9e8SJason Beloro static struct modlmisc modlmisc = {
879853d9e8SJason Beloro 	&mod_miscops,
889853d9e8SJason Beloro 	"sun4v memory DR"
899853d9e8SJason Beloro };
909853d9e8SJason Beloro 
919853d9e8SJason Beloro static struct modlinkage modlinkage = {
929853d9e8SJason Beloro 	MODREV_1,
939853d9e8SJason Beloro 	(void *)&modlmisc,
949853d9e8SJason Beloro 	NULL
959853d9e8SJason Beloro };
969853d9e8SJason Beloro 
979853d9e8SJason Beloro static int dr_mem_allow_unload = 0;
989853d9e8SJason Beloro 
999853d9e8SJason Beloro typedef int (*fn_t)(dr_mem_blk_t *, int *);
1009853d9e8SJason Beloro 
1019853d9e8SJason Beloro /*
1029853d9e8SJason Beloro  * Global Domain Services (DS) Handle
1039853d9e8SJason Beloro  */
1049853d9e8SJason Beloro static ds_svc_hdl_t ds_handle;
1059853d9e8SJason Beloro 
1069853d9e8SJason Beloro /*
1079853d9e8SJason Beloro  * Supported DS Capability Versions
1089853d9e8SJason Beloro  */
1099853d9e8SJason Beloro static ds_ver_t		dr_mem_vers[] = { { 1, 0 } };
1109853d9e8SJason Beloro #define	DR_MEM_NVERS	(sizeof (dr_mem_vers) / sizeof (dr_mem_vers[0]))
1119853d9e8SJason Beloro 
1129853d9e8SJason Beloro /*
1139853d9e8SJason Beloro  * DS Capability Description
1149853d9e8SJason Beloro  */
1159853d9e8SJason Beloro static ds_capability_t dr_mem_cap = {
1169853d9e8SJason Beloro 	DR_MEM_DS_ID,		/* svc_id */
1179853d9e8SJason Beloro 	dr_mem_vers,		/* vers */
1189853d9e8SJason Beloro 	DR_MEM_NVERS		/* nvers */
1199853d9e8SJason Beloro };
1209853d9e8SJason Beloro 
1219853d9e8SJason Beloro /*
1229853d9e8SJason Beloro  * DS Callbacks
1239853d9e8SJason Beloro  */
1249853d9e8SJason Beloro static void dr_mem_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
1259853d9e8SJason Beloro static void dr_mem_unreg_handler(ds_cb_arg_t arg);
1269853d9e8SJason Beloro static void dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
1279853d9e8SJason Beloro 
1289853d9e8SJason Beloro /*
1299853d9e8SJason Beloro  * DS Client Ops Vector
1309853d9e8SJason Beloro  */
1319853d9e8SJason Beloro static ds_clnt_ops_t dr_mem_ops = {
1329853d9e8SJason Beloro 	dr_mem_reg_handler,	/* ds_reg_cb */
1339853d9e8SJason Beloro 	dr_mem_unreg_handler,	/* ds_unreg_cb */
1349853d9e8SJason Beloro 	dr_mem_data_handler,	/* ds_data_cb */
1359853d9e8SJason Beloro 	NULL			/* cb_arg */
1369853d9e8SJason Beloro };
1379853d9e8SJason Beloro 
1389853d9e8SJason Beloro /*
1399853d9e8SJason Beloro  * Operation Results
1409853d9e8SJason Beloro  *
1419853d9e8SJason Beloro  * Used internally to gather results while an operation on a
1429853d9e8SJason Beloro  * list of mblks is in progress. In particular, it is used to
1439853d9e8SJason Beloro  * keep track of which mblks have already failed so that they are
1449853d9e8SJason Beloro  * not processed further, and the manner in which they failed.
1459853d9e8SJason Beloro  */
1469853d9e8SJason Beloro typedef struct {
1479853d9e8SJason Beloro 	uint64_t	addr;
1489853d9e8SJason Beloro 	uint64_t	size;
1499853d9e8SJason Beloro 	uint32_t	result;
1509853d9e8SJason Beloro 	uint32_t	status;
1519853d9e8SJason Beloro 	char		*string;
1529853d9e8SJason Beloro } dr_mem_res_t;
1539853d9e8SJason Beloro 
1549853d9e8SJason Beloro static char *
1559853d9e8SJason Beloro dr_mem_estr[] = {
1569853d9e8SJason Beloro 	"operation succeeded",		/* DR_MEM_RES_OK */
1579853d9e8SJason Beloro 	"operation failed",		/* DR_MEM_RES_FAILURE */
1589853d9e8SJason Beloro 	"operation was blocked",	/* DR_MEM_RES_BLOCKED */
1599853d9e8SJason Beloro 	"memory not defined in MD",	/* DR_MEM_RES_NOT_IN_MD */
1609853d9e8SJason Beloro 	"memory already in use",	/* DR_MEM_RES_ESPAN */
1619853d9e8SJason Beloro 	"memory access test failed",	/* DR_MEM_RES_EFAULT */
1629853d9e8SJason Beloro 	"resource not available",	/* DR_MEM_RES_ERESOURCE */
1639853d9e8SJason Beloro 	"permanent pages in span",	/* DR_MEM_RES_PERM */
1649853d9e8SJason Beloro 	"memory span busy",		/* DR_MEM_RES_EBUSY */
1659853d9e8SJason Beloro 	"VM viability test failed",	/* DR_MEM_RES_ENOTVIABLE */
1669853d9e8SJason Beloro 	"no pages to unconfigure",	/* DR_MEM_RES_ENOWORK */
1679853d9e8SJason Beloro 	"operation cancelled",		/* DR_MEM_RES_ECANCELLED */
1689853d9e8SJason Beloro 	"operation refused",		/* DR_MEM_RES_EREFUSED */
1699853d9e8SJason Beloro 	"memory span duplicate",	/* DR_MEM_RES_EDUP */
1709853d9e8SJason Beloro 	"invalid argument"		/* DR_MEM_RES_EINVAL */
1719853d9e8SJason Beloro };
1729853d9e8SJason Beloro 
17302b4e56cSHaik Aftandilian static char *
17402b4e56cSHaik Aftandilian dr_mem_estr_detail[] = {
17502b4e56cSHaik Aftandilian 	"",					/* DR_MEM_SRES_NONE */
17602b4e56cSHaik Aftandilian 	"memory DR disabled after migration"	/* DR_MEM_SRES_OS_SUSPENDED */
17702b4e56cSHaik Aftandilian };
17802b4e56cSHaik Aftandilian 
1799853d9e8SJason Beloro typedef struct {
1809853d9e8SJason Beloro 	kcondvar_t cond;
1819853d9e8SJason Beloro 	kmutex_t lock;
1829853d9e8SJason Beloro 	int error;
1839853d9e8SJason Beloro 	int done;
1849853d9e8SJason Beloro } mem_sync_t;
1859853d9e8SJason Beloro 
1869853d9e8SJason Beloro /*
1879853d9e8SJason Beloro  * Internal Functions
1889853d9e8SJason Beloro  */
1899853d9e8SJason Beloro static int dr_mem_init(void);
1909853d9e8SJason Beloro static int dr_mem_fini(void);
1919853d9e8SJason Beloro 
1929853d9e8SJason Beloro static int dr_mem_list_wrk(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
1939853d9e8SJason Beloro static int dr_mem_list_query(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
1949853d9e8SJason Beloro static int dr_mem_del_stat(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
1959853d9e8SJason Beloro static int dr_mem_del_cancel(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
1969853d9e8SJason Beloro 
1979853d9e8SJason Beloro static int dr_mem_unconfigure(dr_mem_blk_t *, int *);
1989853d9e8SJason Beloro static int dr_mem_configure(dr_mem_blk_t *, int *);
1999853d9e8SJason Beloro static void dr_mem_query(dr_mem_blk_t *, dr_mem_query_t *);
2009853d9e8SJason Beloro 
2019853d9e8SJason Beloro static dr_mem_res_t *dr_mem_res_array_init(dr_mem_hdr_t *, drctl_rsrc_t *, int);
2029853d9e8SJason Beloro static void dr_mem_res_array_fini(dr_mem_res_t *res, int nres);
2039853d9e8SJason Beloro static size_t dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res,
2049853d9e8SJason Beloro     dr_mem_hdr_t **respp);
2059853d9e8SJason Beloro 
2069853d9e8SJason Beloro static int dr_mem_find(dr_mem_blk_t *mbp);
2079853d9e8SJason Beloro static mde_cookie_t dr_mem_find_node_md(dr_mem_blk_t *, md_t *, mde_cookie_t *);
2089853d9e8SJason Beloro 
2099853d9e8SJason Beloro static int mem_add(pfn_t, pgcnt_t);
2109853d9e8SJason Beloro static int mem_del(pfn_t, pgcnt_t);
2119853d9e8SJason Beloro 
2129853d9e8SJason Beloro extern int kphysm_add_memory_dynamic(pfn_t, pgcnt_t);
2139853d9e8SJason Beloro 
2149853d9e8SJason Beloro int
_init(void)2159853d9e8SJason Beloro _init(void)
2169853d9e8SJason Beloro {
2179853d9e8SJason Beloro 	int	status;
2189853d9e8SJason Beloro 
2199853d9e8SJason Beloro 	/* check that Memory DR is enabled */
2209853d9e8SJason Beloro 	if (dr_is_disabled(DR_TYPE_MEM))
2219853d9e8SJason Beloro 		return (ENOTSUP);
2229853d9e8SJason Beloro 
2239853d9e8SJason Beloro 	if ((status = dr_mem_init()) != 0) {
2249853d9e8SJason Beloro 		cmn_err(CE_NOTE, "Memory DR initialization failed");
2259853d9e8SJason Beloro 		return (status);
2269853d9e8SJason Beloro 	}
2279853d9e8SJason Beloro 
2289853d9e8SJason Beloro 	if ((status = mod_install(&modlinkage)) != 0) {
2299853d9e8SJason Beloro 		(void) dr_mem_fini();
2309853d9e8SJason Beloro 	}
2319853d9e8SJason Beloro 
2329853d9e8SJason Beloro 	return (status);
2339853d9e8SJason Beloro }
2349853d9e8SJason Beloro 
2359853d9e8SJason Beloro int
_info(struct modinfo * modinfop)2369853d9e8SJason Beloro _info(struct modinfo *modinfop)
2379853d9e8SJason Beloro {
2389853d9e8SJason Beloro 	return (mod_info(&modlinkage, modinfop));
2399853d9e8SJason Beloro }
2409853d9e8SJason Beloro 
2419853d9e8SJason Beloro int
_fini(void)2429853d9e8SJason Beloro _fini(void)
2439853d9e8SJason Beloro {
2449853d9e8SJason Beloro 	int	status;
2459853d9e8SJason Beloro 
2469853d9e8SJason Beloro 	if (dr_mem_allow_unload == 0)
2479853d9e8SJason Beloro 		return (EBUSY);
2489853d9e8SJason Beloro 
2499853d9e8SJason Beloro 	if ((status = mod_remove(&modlinkage)) == 0) {
2509853d9e8SJason Beloro 		(void) dr_mem_fini();
2519853d9e8SJason Beloro 	}
2529853d9e8SJason Beloro 
2539853d9e8SJason Beloro 	return (status);
2549853d9e8SJason Beloro }
2559853d9e8SJason Beloro 
2569853d9e8SJason Beloro static int
dr_mem_init(void)2579853d9e8SJason Beloro dr_mem_init(void)
2589853d9e8SJason Beloro {
2599853d9e8SJason Beloro 	int rv;
2609853d9e8SJason Beloro 
2619853d9e8SJason Beloro 	if ((rv = ds_cap_init(&dr_mem_cap, &dr_mem_ops)) != 0) {
2629853d9e8SJason Beloro 		cmn_err(CE_NOTE, "dr_mem: ds_cap_init failed: %d", rv);
2639853d9e8SJason Beloro 		return (rv);
2649853d9e8SJason Beloro 	}
2659853d9e8SJason Beloro 
2669853d9e8SJason Beloro 	return (0);
2679853d9e8SJason Beloro }
2689853d9e8SJason Beloro 
2699853d9e8SJason Beloro static int
dr_mem_fini(void)2709853d9e8SJason Beloro dr_mem_fini(void)
2719853d9e8SJason Beloro {
2729853d9e8SJason Beloro 	int rv;
2739853d9e8SJason Beloro 
2749853d9e8SJason Beloro 	if ((rv = ds_cap_fini(&dr_mem_cap)) != 0) {
2759853d9e8SJason Beloro 		cmn_err(CE_NOTE, "dr_mem: ds_cap_fini failed: %d", rv);
2769853d9e8SJason Beloro 	}
2779853d9e8SJason Beloro 
2789853d9e8SJason Beloro 	return (rv);
2799853d9e8SJason Beloro }
2809853d9e8SJason Beloro 
2819853d9e8SJason Beloro static void
dr_mem_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)2829853d9e8SJason Beloro dr_mem_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
2839853d9e8SJason Beloro {
2849853d9e8SJason Beloro 	DR_DBG_MEM("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
2859853d9e8SJason Beloro 	    ver->major, ver->minor, hdl);
2869853d9e8SJason Beloro 
2879853d9e8SJason Beloro 	ds_handle = hdl;
2889853d9e8SJason Beloro }
2899853d9e8SJason Beloro 
2909853d9e8SJason Beloro static void
dr_mem_unreg_handler(ds_cb_arg_t arg)2919853d9e8SJason Beloro dr_mem_unreg_handler(ds_cb_arg_t arg)
2929853d9e8SJason Beloro {
2939853d9e8SJason Beloro 	DR_DBG_MEM("unreg_handler: arg=0x%p\n", arg);
2949853d9e8SJason Beloro 
2959853d9e8SJason Beloro 	ds_handle = DS_INVALID_HDL;
2969853d9e8SJason Beloro }
2979853d9e8SJason Beloro 
2989853d9e8SJason Beloro /*ARGSUSED*/
2999853d9e8SJason Beloro static void
dr_mem_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)3009853d9e8SJason Beloro dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
3019853d9e8SJason Beloro {
3029853d9e8SJason Beloro 	dr_mem_hdr_t	*req = buf;
3039853d9e8SJason Beloro 	dr_mem_hdr_t	err_resp;
3049853d9e8SJason Beloro 	dr_mem_hdr_t	*resp = &err_resp;
3059853d9e8SJason Beloro 	int		resp_len = 0;
3069853d9e8SJason Beloro 	int		rv = EINVAL;
3079853d9e8SJason Beloro 
3089853d9e8SJason Beloro 	/*
3099853d9e8SJason Beloro 	 * Sanity check the message
3109853d9e8SJason Beloro 	 */
3119853d9e8SJason Beloro 	if (buflen < sizeof (dr_mem_hdr_t)) {
3129853d9e8SJason Beloro 		DR_DBG_MEM("incoming message short: expected at least %ld "
3139853d9e8SJason Beloro 		    "bytes, received %ld\n", sizeof (dr_mem_hdr_t), buflen);
3149853d9e8SJason Beloro 		goto done;
3159853d9e8SJason Beloro 	}
3169853d9e8SJason Beloro 
3179853d9e8SJason Beloro 	if (req == NULL) {
3189853d9e8SJason Beloro 		DR_DBG_MEM("empty message: expected at least %ld bytes\n",
3199853d9e8SJason Beloro 		    sizeof (dr_mem_hdr_t));
3209853d9e8SJason Beloro 		goto done;
3219853d9e8SJason Beloro 	}
3229853d9e8SJason Beloro 
3239853d9e8SJason Beloro 	DR_DBG_MEM("incoming request:\n");
3249853d9e8SJason Beloro 	DR_DBG_DUMP_MSG(buf, buflen);
3259853d9e8SJason Beloro 
3269853d9e8SJason Beloro 	/*
3279853d9e8SJason Beloro 	 * Process the command
3289853d9e8SJason Beloro 	 */
3299853d9e8SJason Beloro 	switch (req->msg_type) {
3309853d9e8SJason Beloro 	case DR_MEM_CONFIGURE:
3319853d9e8SJason Beloro 	case DR_MEM_UNCONFIGURE:
3329853d9e8SJason Beloro 		if (req->msg_arg == 0) {
3339853d9e8SJason Beloro 			DR_DBG_MEM("No mblks specified for operation\n");
3349853d9e8SJason Beloro 			goto done;
3359853d9e8SJason Beloro 		}
3369853d9e8SJason Beloro 		if ((rv = dr_mem_list_wrk(req, &resp, &resp_len)) != 0) {
3379853d9e8SJason Beloro 			DR_DBG_MEM("%s failed (%d)\n",
3389853d9e8SJason Beloro 			    (req->msg_type == DR_MEM_CONFIGURE) ?
3399853d9e8SJason Beloro 			    "Memory configure" : "Memory unconfigure", rv);
3409853d9e8SJason Beloro 		}
3419853d9e8SJason Beloro 		break;
3429853d9e8SJason Beloro 
3439853d9e8SJason Beloro 	case DR_MEM_UNCONF_STATUS:
3449853d9e8SJason Beloro 		if ((rv = dr_mem_del_stat(req, &resp, &resp_len)) != 0)
3459853d9e8SJason Beloro 			DR_DBG_MEM("Memory delete status failed (%d)\n", rv);
3469853d9e8SJason Beloro 		break;
3479853d9e8SJason Beloro 
3489853d9e8SJason Beloro 	case DR_MEM_UNCONF_CANCEL:
3499853d9e8SJason Beloro 		if ((rv = dr_mem_del_cancel(req, &resp, &resp_len)) != 0)
3509853d9e8SJason Beloro 			DR_DBG_MEM("Memory delete cancel failed (%d)\n", rv);
3519853d9e8SJason Beloro 		break;
3529853d9e8SJason Beloro 
3539853d9e8SJason Beloro 	case DR_MEM_QUERY:
3549853d9e8SJason Beloro 		if (req->msg_arg == 0) {
3559853d9e8SJason Beloro 			DR_DBG_MEM("No mblks specified for operation\n");
3569853d9e8SJason Beloro 			goto done;
3579853d9e8SJason Beloro 		}
3589853d9e8SJason Beloro 		if ((rv = dr_mem_list_query(req, &resp, &resp_len)) != 0)
3599853d9e8SJason Beloro 			DR_DBG_MEM("Memory query failed (%d)\n", rv);
3609853d9e8SJason Beloro 		break;
3619853d9e8SJason Beloro 
3629853d9e8SJason Beloro 	default:
3639853d9e8SJason Beloro 		cmn_err(CE_NOTE, "unsupported memory DR operation (%d)",
3649853d9e8SJason Beloro 		    req->msg_type);
3659853d9e8SJason Beloro 		break;
3669853d9e8SJason Beloro 	}
3679853d9e8SJason Beloro 
3689853d9e8SJason Beloro done:
3699853d9e8SJason Beloro 	/* check if an error occurred */
3709853d9e8SJason Beloro 	if (resp == &err_resp) {
3719853d9e8SJason Beloro 		resp->req_num = (req) ? req->req_num : 0;
3729853d9e8SJason Beloro 		resp->msg_type = DR_MEM_ERROR;
3739853d9e8SJason Beloro 		resp->msg_arg = rv;
3749853d9e8SJason Beloro 		resp_len = sizeof (dr_mem_hdr_t);
3759853d9e8SJason Beloro 	}
3769853d9e8SJason Beloro 
3779853d9e8SJason Beloro 	DR_DBG_MEM("outgoing response:\n");
3789853d9e8SJason Beloro 	DR_DBG_DUMP_MSG(resp, resp_len);
3799853d9e8SJason Beloro 
3809853d9e8SJason Beloro 	/* send back the response */
3819853d9e8SJason Beloro 	if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
3829853d9e8SJason Beloro 		DR_DBG_MEM("ds_send failed\n");
3839853d9e8SJason Beloro 	}
3849853d9e8SJason Beloro 
3859853d9e8SJason Beloro 	/* free any allocated memory */
3869853d9e8SJason Beloro 	if (resp != &err_resp) {
3879853d9e8SJason Beloro 		kmem_free(resp, resp_len);
3889853d9e8SJason Beloro 	}
3899853d9e8SJason Beloro }
3909853d9e8SJason Beloro 
39102b4e56cSHaik Aftandilian static char *
dr_mem_get_errstr(int result,int subresult)39202b4e56cSHaik Aftandilian dr_mem_get_errstr(int result, int subresult)
39302b4e56cSHaik Aftandilian {
39402b4e56cSHaik Aftandilian 	size_t len;
39502b4e56cSHaik Aftandilian 	char *errstr;
39602b4e56cSHaik Aftandilian 	const char *separator = ": ";
39702b4e56cSHaik Aftandilian 
39802b4e56cSHaik Aftandilian 	if (subresult == DR_MEM_SRES_NONE)
39902b4e56cSHaik Aftandilian 		return (i_ddi_strdup(dr_mem_estr[result], KM_SLEEP));
40002b4e56cSHaik Aftandilian 
40102b4e56cSHaik Aftandilian 	len = snprintf(NULL, 0, "%s%s%s", dr_mem_estr[result],
40202b4e56cSHaik Aftandilian 	    separator, dr_mem_estr_detail[subresult]) + 1;
40302b4e56cSHaik Aftandilian 
40402b4e56cSHaik Aftandilian 	errstr = kmem_alloc(len, KM_SLEEP);
40502b4e56cSHaik Aftandilian 
40602b4e56cSHaik Aftandilian 	(void) snprintf(errstr, len, "%s%s%s", dr_mem_estr[result],
40702b4e56cSHaik Aftandilian 	    separator, dr_mem_estr_detail[subresult]);
40802b4e56cSHaik Aftandilian 
40902b4e56cSHaik Aftandilian 	return (errstr);
41002b4e56cSHaik Aftandilian }
41102b4e56cSHaik Aftandilian 
4129853d9e8SJason Beloro /*
4139853d9e8SJason Beloro  * Common routine to config or unconfig multiple mblks.
4149853d9e8SJason Beloro  *
4159853d9e8SJason Beloro  * Note: Do not modify result buffer or length on error.
4169853d9e8SJason Beloro  */
4179853d9e8SJason Beloro static int
dr_mem_list_wrk(dr_mem_hdr_t * req,dr_mem_hdr_t ** resp,int * resp_len)4189853d9e8SJason Beloro dr_mem_list_wrk(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
4199853d9e8SJason Beloro {
4209853d9e8SJason Beloro 	int		rv;
4219853d9e8SJason Beloro 	int		idx;
4229853d9e8SJason Beloro 	int		count;
4239853d9e8SJason Beloro 	int		result;
42402b4e56cSHaik Aftandilian 	int		subresult;
4259853d9e8SJason Beloro 	int		status;
42602b4e56cSHaik Aftandilian 	boolean_t	suspend_allows_dr;
4279853d9e8SJason Beloro 	fn_t		dr_fn;
4289853d9e8SJason Beloro 	int		se_hint;
4299853d9e8SJason Beloro 	dr_mem_blk_t	*req_mblks;
4309853d9e8SJason Beloro 	dr_mem_res_t	*res;
4319853d9e8SJason Beloro 	int		drctl_cmd;
4329853d9e8SJason Beloro 	int		drctl_flags = 0;
4339853d9e8SJason Beloro 	drctl_rsrc_t	*drctl_req;
4349853d9e8SJason Beloro 	size_t		drctl_req_len;
4359853d9e8SJason Beloro 	drctl_resp_t	*drctl_resp;
4369853d9e8SJason Beloro 	drctl_rsrc_t	*drctl_rsrc;
4379853d9e8SJason Beloro 	size_t		drctl_resp_len = 0;
4389853d9e8SJason Beloro 	drctl_cookie_t	drctl_res_ck;
4399853d9e8SJason Beloro 
4409853d9e8SJason Beloro 	ASSERT((req != NULL) && (req->msg_arg != 0));
4419853d9e8SJason Beloro 
4429853d9e8SJason Beloro 	count = req->msg_arg;
4439853d9e8SJason Beloro 
4449853d9e8SJason Beloro 	/*
4459853d9e8SJason Beloro 	 * Extract all information that is specific
4469853d9e8SJason Beloro 	 * to the various types of operations.
4479853d9e8SJason Beloro 	 */
4489853d9e8SJason Beloro 	switch (req->msg_type) {
4499853d9e8SJason Beloro 	case DR_MEM_CONFIGURE:
4509853d9e8SJason Beloro 		dr_fn = dr_mem_configure;
4519853d9e8SJason Beloro 		drctl_cmd = DRCTL_MEM_CONFIG_REQUEST;
4529853d9e8SJason Beloro 		se_hint = SE_HINT_INSERT;
4539853d9e8SJason Beloro 		break;
4549853d9e8SJason Beloro 	case DR_MEM_UNCONFIGURE:
4559853d9e8SJason Beloro 		dr_fn = dr_mem_unconfigure;
4569853d9e8SJason Beloro 		drctl_cmd = DRCTL_MEM_UNCONFIG_REQUEST;
4579853d9e8SJason Beloro 		se_hint = SE_HINT_REMOVE;
4589853d9e8SJason Beloro 		break;
4599853d9e8SJason Beloro 	default:
4609853d9e8SJason Beloro 		/* Programming error if we reach this. */
4619853d9e8SJason Beloro 		cmn_err(CE_NOTE, "%s: bad msg_type %d\n",
4629853d9e8SJason Beloro 		    __func__, req->msg_type);
4639853d9e8SJason Beloro 		ASSERT(0);
4649853d9e8SJason Beloro 		return (-1);
4659853d9e8SJason Beloro 	}
4669853d9e8SJason Beloro 
4679853d9e8SJason Beloro 	/* the incoming array of mblks to operate on */
4689853d9e8SJason Beloro 	req_mblks = DR_MEM_CMD_MBLKS(req);
4699853d9e8SJason Beloro 
4709853d9e8SJason Beloro 	/* allocate drctl request msg based on incoming resource count */
4719853d9e8SJason Beloro 	drctl_req_len = sizeof (drctl_rsrc_t) * count;
4729853d9e8SJason Beloro 	drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
4739853d9e8SJason Beloro 
4749853d9e8SJason Beloro 	/* copy the size for the drctl call from the incoming request msg */
4759853d9e8SJason Beloro 	for (idx = 0; idx < count; idx++) {
4769853d9e8SJason Beloro 		drctl_req[idx].res_mem_addr = req_mblks[idx].addr;
4779853d9e8SJason Beloro 		drctl_req[idx].res_mem_size = req_mblks[idx].size;
4789853d9e8SJason Beloro 	}
4799853d9e8SJason Beloro 
4809853d9e8SJason Beloro 	rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
4819853d9e8SJason Beloro 	    count, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
4829853d9e8SJason Beloro 
4839853d9e8SJason Beloro 	ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
4849853d9e8SJason Beloro 
4859853d9e8SJason Beloro 	if (rv != 0) {
4869853d9e8SJason Beloro 		DR_DBG_MEM("%s: drctl_config_init returned: %d\n",
4879853d9e8SJason Beloro 		    __func__, rv);
4889853d9e8SJason Beloro 		kmem_free(drctl_resp, drctl_resp_len);
4899853d9e8SJason Beloro 		kmem_free(drctl_req, drctl_req_len);
4909853d9e8SJason Beloro 		return (rv);
4919853d9e8SJason Beloro 	}
4929853d9e8SJason Beloro 
4939853d9e8SJason Beloro 	ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
4949853d9e8SJason Beloro 
4959853d9e8SJason Beloro 	drctl_rsrc = drctl_resp->resp_resources;
4969853d9e8SJason Beloro 
4979853d9e8SJason Beloro 	/* create the result scratch array */
4989853d9e8SJason Beloro 	res = dr_mem_res_array_init(req, drctl_rsrc, count);
4999853d9e8SJason Beloro 
50002b4e56cSHaik Aftandilian 	/*
50102b4e56cSHaik Aftandilian 	 * Memory DR operations are not safe if we have been suspended and
50202b4e56cSHaik Aftandilian 	 * resumed. Until this limitation is lifted, check to see if memory
50302b4e56cSHaik Aftandilian 	 * DR operations are permitted at this time by the suspend subsystem.
50402b4e56cSHaik Aftandilian 	 */
50502b4e56cSHaik Aftandilian 	if ((suspend_allows_dr = suspend_memdr_allowed()) == B_FALSE) {
50602b4e56cSHaik Aftandilian 		result = DR_MEM_RES_BLOCKED;
50702b4e56cSHaik Aftandilian 		subresult = DR_MEM_SRES_OS_SUSPENDED;
50802b4e56cSHaik Aftandilian 	} else {
50902b4e56cSHaik Aftandilian 		subresult = DR_MEM_SRES_NONE;
51002b4e56cSHaik Aftandilian 	}
51102b4e56cSHaik Aftandilian 
5129853d9e8SJason Beloro 	/* perform the specified operation on each of the mblks */
5139853d9e8SJason Beloro 	for (idx = 0; idx < count; idx++) {
5149853d9e8SJason Beloro 		/*
5159853d9e8SJason Beloro 		 * If no action will be taken against the current
5169853d9e8SJason Beloro 		 * mblk, update the drctl resource information to
5179853d9e8SJason Beloro 		 * ensure that it gets recovered properly during
5189853d9e8SJason Beloro 		 * the drctl fini() call.
5199853d9e8SJason Beloro 		 */
5209853d9e8SJason Beloro 		if (res[idx].result != DR_MEM_RES_OK) {
5219853d9e8SJason Beloro 			drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
5229853d9e8SJason Beloro 			continue;
5239853d9e8SJason Beloro 		}
5249853d9e8SJason Beloro 
52502b4e56cSHaik Aftandilian 		/*
52602b4e56cSHaik Aftandilian 		 * If memory DR operations are permitted at this time by
52702b4e56cSHaik Aftandilian 		 * the suspend subsystem, call the function to perform the
52802b4e56cSHaik Aftandilian 		 * operation, otherwise return a result indicating that the
52902b4e56cSHaik Aftandilian 		 * operation was blocked.
53002b4e56cSHaik Aftandilian 		 */
53102b4e56cSHaik Aftandilian 		if (suspend_allows_dr)
5329853d9e8SJason Beloro 			result = (*dr_fn)(&req_mblks[idx], &status);
5339853d9e8SJason Beloro 
5349853d9e8SJason Beloro 		/* save off results of the operation */
5359853d9e8SJason Beloro 		res[idx].result = result;
5369853d9e8SJason Beloro 		res[idx].status = status;
5379853d9e8SJason Beloro 		res[idx].addr = req_mblks[idx].addr;	/* for partial case */
5389853d9e8SJason Beloro 		res[idx].size = req_mblks[idx].size;	/* for partial case */
53902b4e56cSHaik Aftandilian 		res[idx].string = dr_mem_get_errstr(result, subresult);
5409853d9e8SJason Beloro 
5419853d9e8SJason Beloro 		/* save result for drctl fini() reusing init() msg memory */
5429853d9e8SJason Beloro 		drctl_req[idx].status = (result != DR_MEM_RES_OK) ?
5439853d9e8SJason Beloro 		    DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
5449853d9e8SJason Beloro 
5459853d9e8SJason Beloro 		DR_DBG_MEM("%s: mblk 0x%lx.0x%lx stat %d result %d off '%s'\n",
5469853d9e8SJason Beloro 		    __func__, req_mblks[idx].addr, req_mblks[idx].size,
5479853d9e8SJason Beloro 		    drctl_req[idx].status, result,
5489853d9e8SJason Beloro 		    (res[idx].string) ? res[idx].string : "");
5499853d9e8SJason Beloro 	}
5509853d9e8SJason Beloro 
5519853d9e8SJason Beloro 	if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
5529853d9e8SJason Beloro 		DR_DBG_MEM("%s: drctl_config_fini returned: %d\n",
5539853d9e8SJason Beloro 		    __func__, rv);
5549853d9e8SJason Beloro 
5559853d9e8SJason Beloro 	/*
5569853d9e8SJason Beloro 	 * Operation completed without any fatal errors.
5579853d9e8SJason Beloro 	 * Pack the response for transmission.
5589853d9e8SJason Beloro 	 */
5599853d9e8SJason Beloro 	*resp_len = dr_mem_pack_response(req, res, resp);
5609853d9e8SJason Beloro 
5619853d9e8SJason Beloro 	/* notify interested parties about the operation */
5629853d9e8SJason Beloro 	dr_generate_event(DR_TYPE_MEM, se_hint);
5639853d9e8SJason Beloro 
5649853d9e8SJason Beloro 	/*
5659853d9e8SJason Beloro 	 * Deallocate any scratch memory.
5669853d9e8SJason Beloro 	 */
5679853d9e8SJason Beloro 	kmem_free(drctl_resp, drctl_resp_len);
5689853d9e8SJason Beloro 	kmem_free(drctl_req, drctl_req_len);
5699853d9e8SJason Beloro 
5709853d9e8SJason Beloro 	dr_mem_res_array_fini(res, count);
5719853d9e8SJason Beloro 
5729853d9e8SJason Beloro 	return (0);
5739853d9e8SJason Beloro }
5749853d9e8SJason Beloro 
5759853d9e8SJason Beloro /*
5769853d9e8SJason Beloro  * Allocate and initialize a result array based on the initial
5779853d9e8SJason Beloro  * drctl operation. A valid result array is always returned.
5789853d9e8SJason Beloro  */
5799853d9e8SJason Beloro static dr_mem_res_t *
dr_mem_res_array_init(dr_mem_hdr_t * req,drctl_rsrc_t * rsrc,int nrsrc)5809853d9e8SJason Beloro dr_mem_res_array_init(dr_mem_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
5819853d9e8SJason Beloro {
5829853d9e8SJason Beloro 	int		idx;
5839853d9e8SJason Beloro 	dr_mem_res_t	*res;
5849853d9e8SJason Beloro 	char		*err_str;
5859853d9e8SJason Beloro 	size_t		err_len;
5869853d9e8SJason Beloro 
5879853d9e8SJason Beloro 	/* allocate zero filled buffer to initialize fields */
5889853d9e8SJason Beloro 	res = kmem_zalloc(nrsrc * sizeof (dr_mem_res_t), KM_SLEEP);
5899853d9e8SJason Beloro 
5909853d9e8SJason Beloro 	/*
5919853d9e8SJason Beloro 	 * Fill in the result information for each resource.
5929853d9e8SJason Beloro 	 */
5939853d9e8SJason Beloro 	for (idx = 0; idx < nrsrc; idx++) {
5949853d9e8SJason Beloro 		res[idx].addr = rsrc[idx].res_mem_addr;
5959853d9e8SJason Beloro 		res[idx].size = rsrc[idx].res_mem_size;
5969853d9e8SJason Beloro 		res[idx].result = DR_MEM_RES_OK;
5979853d9e8SJason Beloro 
5989853d9e8SJason Beloro 		if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
5999853d9e8SJason Beloro 			continue;
6009853d9e8SJason Beloro 
6019853d9e8SJason Beloro 		/*
6029853d9e8SJason Beloro 		 * Update the state information for this mblk.
6039853d9e8SJason Beloro 		 */
6049853d9e8SJason Beloro 		res[idx].result = DR_MEM_RES_BLOCKED;
6059853d9e8SJason Beloro 		res[idx].status = (req->msg_type == DR_MEM_CONFIGURE) ?
6069853d9e8SJason Beloro 		    DR_MEM_STAT_UNCONFIGURED : DR_MEM_STAT_CONFIGURED;
6079853d9e8SJason Beloro 
6089853d9e8SJason Beloro 		/*
6099853d9e8SJason Beloro 		 * If an error string exists, copy it out of the
6109853d9e8SJason Beloro 		 * message buffer. This eliminates any dependency
6119853d9e8SJason Beloro 		 * on the memory allocated for the message buffer
6129853d9e8SJason Beloro 		 * itself.
6139853d9e8SJason Beloro 		 */
614*7331beb4SToomas Soome 		if (rsrc[idx].offset != 0) {
6159853d9e8SJason Beloro 			err_str = (char *)rsrc + rsrc[idx].offset;
6169853d9e8SJason Beloro 			err_len = strlen(err_str) + 1;
6179853d9e8SJason Beloro 
6189853d9e8SJason Beloro 			res[idx].string = kmem_alloc(err_len, KM_SLEEP);
6199853d9e8SJason Beloro 			bcopy(err_str, res[idx].string, err_len);
6209853d9e8SJason Beloro 		}
6219853d9e8SJason Beloro 	}
6229853d9e8SJason Beloro 
6239853d9e8SJason Beloro 	return (res);
6249853d9e8SJason Beloro }
6259853d9e8SJason Beloro 
6269853d9e8SJason Beloro static void
dr_mem_res_array_fini(dr_mem_res_t * res,int nres)6279853d9e8SJason Beloro dr_mem_res_array_fini(dr_mem_res_t *res, int nres)
6289853d9e8SJason Beloro {
6299853d9e8SJason Beloro 	int	idx;
6309853d9e8SJason Beloro 	size_t	str_len;
6319853d9e8SJason Beloro 
6329853d9e8SJason Beloro 	for (idx = 0; idx < nres; idx++) {
6339853d9e8SJason Beloro 		/* deallocate the error string if present */
6349853d9e8SJason Beloro 		if (res[idx].string) {
6359853d9e8SJason Beloro 			str_len = strlen(res[idx].string) + 1;
6369853d9e8SJason Beloro 			kmem_free(res[idx].string, str_len);
6379853d9e8SJason Beloro 		}
6389853d9e8SJason Beloro 	}
6399853d9e8SJason Beloro 
6409853d9e8SJason Beloro 	/* deallocate the result array itself */
6419853d9e8SJason Beloro 	kmem_free(res, sizeof (dr_mem_res_t) * nres);
6429853d9e8SJason Beloro }
6439853d9e8SJason Beloro 
6449853d9e8SJason Beloro /*
6459853d9e8SJason Beloro  * Allocate and pack a response message for transmission based
6469853d9e8SJason Beloro  * on the specified result array. A valid response message and
6479853d9e8SJason Beloro  * valid size information is always returned.
6489853d9e8SJason Beloro  */
6499853d9e8SJason Beloro static size_t
dr_mem_pack_response(dr_mem_hdr_t * req,dr_mem_res_t * res,dr_mem_hdr_t ** respp)6509853d9e8SJason Beloro dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res, dr_mem_hdr_t **respp)
6519853d9e8SJason Beloro {
6529853d9e8SJason Beloro 	int		idx;
6539853d9e8SJason Beloro 	dr_mem_hdr_t	*resp;
6549853d9e8SJason Beloro 	dr_mem_stat_t	*resp_stat;
6559853d9e8SJason Beloro 	size_t		resp_len;
6569853d9e8SJason Beloro 	uint32_t	curr_off;
6579853d9e8SJason Beloro 	caddr_t		curr_str;
6589853d9e8SJason Beloro 	size_t		str_len;
6599853d9e8SJason Beloro 	size_t		stat_len;
6609853d9e8SJason Beloro 	int		nstat = req->msg_arg;
6619853d9e8SJason Beloro 
6629853d9e8SJason Beloro 	/*
6639853d9e8SJason Beloro 	 * Calculate the size of the response message
6649853d9e8SJason Beloro 	 * and allocate an appropriately sized buffer.
6659853d9e8SJason Beloro 	 */
6669853d9e8SJason Beloro 	resp_len = sizeof (dr_mem_hdr_t);
6679853d9e8SJason Beloro 
6689853d9e8SJason Beloro 	/* add the stat array size */
6699853d9e8SJason Beloro 	stat_len = sizeof (dr_mem_stat_t) * nstat;
6709853d9e8SJason Beloro 	resp_len += stat_len;
6719853d9e8SJason Beloro 
6729853d9e8SJason Beloro 	/* add the size of any error strings */
6739853d9e8SJason Beloro 	for (idx = 0; idx < nstat; idx++) {
6749853d9e8SJason Beloro 		if (res[idx].string != NULL) {
6759853d9e8SJason Beloro 			resp_len += strlen(res[idx].string) + 1;
6769853d9e8SJason Beloro 		}
6779853d9e8SJason Beloro 	}
6789853d9e8SJason Beloro 
6799853d9e8SJason Beloro 	/* allocate the message buffer */
6809853d9e8SJason Beloro 	resp = kmem_zalloc(resp_len, KM_SLEEP);
6819853d9e8SJason Beloro 
6829853d9e8SJason Beloro 	/*
6839853d9e8SJason Beloro 	 * Fill in the header information.
6849853d9e8SJason Beloro 	 */
6859853d9e8SJason Beloro 	resp->req_num = req->req_num;
6869853d9e8SJason Beloro 	resp->msg_type = DR_MEM_OK;
6879853d9e8SJason Beloro 	resp->msg_arg = nstat;
6889853d9e8SJason Beloro 
6899853d9e8SJason Beloro 	/*
6909853d9e8SJason Beloro 	 * Fill in the stat information.
6919853d9e8SJason Beloro 	 */
6929853d9e8SJason Beloro 	resp_stat = DR_MEM_RESP_STATS(resp);
6939853d9e8SJason Beloro 
6949853d9e8SJason Beloro 	/* string offsets start immediately after stat array */
6959853d9e8SJason Beloro 	curr_off = sizeof (dr_mem_hdr_t) + stat_len;
6969853d9e8SJason Beloro 	curr_str = (char *)resp_stat + stat_len;
6979853d9e8SJason Beloro 
6989853d9e8SJason Beloro 	for (idx = 0; idx < nstat; idx++) {
6999853d9e8SJason Beloro 		resp_stat[idx].addr = res[idx].addr;
7009853d9e8SJason Beloro 		resp_stat[idx].size = res[idx].size;
7019853d9e8SJason Beloro 		resp_stat[idx].result = res[idx].result;
7029853d9e8SJason Beloro 		resp_stat[idx].status = res[idx].status;
7039853d9e8SJason Beloro 
7049853d9e8SJason Beloro 		if (res[idx].string != NULL) {
7059853d9e8SJason Beloro 			/* copy over the error string */
7069853d9e8SJason Beloro 			str_len = strlen(res[idx].string) + 1;
7079853d9e8SJason Beloro 			bcopy(res[idx].string, curr_str, str_len);
7089853d9e8SJason Beloro 			resp_stat[idx].string_off = curr_off;
7099853d9e8SJason Beloro 
7109853d9e8SJason Beloro 			curr_off += str_len;
7119853d9e8SJason Beloro 			curr_str += str_len;
7129853d9e8SJason Beloro 		}
7139853d9e8SJason Beloro 	}
7149853d9e8SJason Beloro 
7159853d9e8SJason Beloro 	/* buffer should be exactly filled */
7169853d9e8SJason Beloro 	ASSERT(curr_off == resp_len);
7179853d9e8SJason Beloro 
7189853d9e8SJason Beloro 	*respp = resp;
7199853d9e8SJason Beloro 	return (resp_len);
7209853d9e8SJason Beloro }
7219853d9e8SJason Beloro 
7229853d9e8SJason Beloro static void
dr_mem_query(dr_mem_blk_t * mbp,dr_mem_query_t * mqp)7239853d9e8SJason Beloro dr_mem_query(dr_mem_blk_t *mbp, dr_mem_query_t *mqp)
7249853d9e8SJason Beloro {
7259853d9e8SJason Beloro 	memquery_t mq;
7269853d9e8SJason Beloro 
7279853d9e8SJason Beloro 	DR_DBG_MEM("dr_mem_query...\n");
7289853d9e8SJason Beloro 
7299853d9e8SJason Beloro 
7309853d9e8SJason Beloro 	(void) kphysm_del_span_query(btop(mbp->addr), btop(mbp->size), &mq);
7319853d9e8SJason Beloro 
7329853d9e8SJason Beloro 	if (!mq.phys_pages)
7339853d9e8SJason Beloro 		return;
7349853d9e8SJason Beloro 
7359853d9e8SJason Beloro 	mqp->addr = mbp->addr;
7369853d9e8SJason Beloro 	mqp->mq.phys_pages = ptob(mq.phys_pages);
7379853d9e8SJason Beloro 	mqp->mq.managed = ptob(mq.managed);
7389853d9e8SJason Beloro 	mqp->mq.nonrelocatable = ptob(mq.nonrelocatable);
7399853d9e8SJason Beloro 	mqp->mq.first_nonrelocatable = ptob(mq.first_nonrelocatable);
7409853d9e8SJason Beloro 	mqp->mq.last_nonrelocatable = ptob(mq.last_nonrelocatable);
7419853d9e8SJason Beloro 	/*
7429853d9e8SJason Beloro 	 * Set to the max byte offset within the page.
7439853d9e8SJason Beloro 	 */
7449853d9e8SJason Beloro 	if (mqp->mq.nonrelocatable)
7459853d9e8SJason Beloro 		mqp->mq.last_nonrelocatable += PAGESIZE - 1;
7469853d9e8SJason Beloro }
7479853d9e8SJason Beloro 
7489853d9e8SJason Beloro /*
7499853d9e8SJason Beloro  * Do not modify result buffer or length on error.
7509853d9e8SJason Beloro  */
7519853d9e8SJason Beloro static int
dr_mem_list_query(dr_mem_hdr_t * req,dr_mem_hdr_t ** resp,int * resp_len)7529853d9e8SJason Beloro dr_mem_list_query(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
7539853d9e8SJason Beloro {
7549853d9e8SJason Beloro 	int		idx;
7559853d9e8SJason Beloro 	int		rlen;
7569853d9e8SJason Beloro 	int		nml;
7579853d9e8SJason Beloro 	struct memlist	*ml;
75879afa7fbSSean McEnroe 	struct memlist	*phys_copy = NULL;
7599853d9e8SJason Beloro 	dr_mem_blk_t	*req_mblks, mb;
7609853d9e8SJason Beloro 	dr_mem_hdr_t	*rp;
7619853d9e8SJason Beloro 	dr_mem_query_t	*stat;
7629853d9e8SJason Beloro 
763af4c679fSSean McEnroe 	drctl_block();
764af4c679fSSean McEnroe 
7659853d9e8SJason Beloro 	/* the incoming array of req_mblks to configure */
7669853d9e8SJason Beloro 	req_mblks = DR_MEM_CMD_MBLKS(req);
7679853d9e8SJason Beloro 
7689853d9e8SJason Beloro 	/* allocate a response message, should be freed by caller */
7699853d9e8SJason Beloro 	nml = 0;
7709853d9e8SJason Beloro 	rlen = sizeof (dr_mem_hdr_t);
771*7331beb4SToomas Soome 	if (req_mblks->addr == 0 && req_mblks->size == 0) {
7729853d9e8SJason Beloro 		/*
7739853d9e8SJason Beloro 		 * Request is for domain's full view of it's memory.
77479afa7fbSSean McEnroe 		 * place a copy in phys_copy then release the memlist lock.
7759853d9e8SJason Beloro 		 */
7769853d9e8SJason Beloro 		memlist_read_lock();
77779afa7fbSSean McEnroe 		phys_copy = dr_memlist_dup(phys_install);
77879afa7fbSSean McEnroe 		memlist_read_unlock();
77979afa7fbSSean McEnroe 
78079afa7fbSSean McEnroe 		for (ml = phys_copy; ml; ml = ml->ml_next)
7819853d9e8SJason Beloro 			nml++;
7829853d9e8SJason Beloro 
7839853d9e8SJason Beloro 		rlen += nml * sizeof (dr_mem_query_t);
7849853d9e8SJason Beloro 	} else {
7859853d9e8SJason Beloro 		rlen += req->msg_arg * sizeof (dr_mem_query_t);
7869853d9e8SJason Beloro 	}
7879853d9e8SJason Beloro 	rp = kmem_zalloc(rlen, KM_SLEEP);
7889853d9e8SJason Beloro 
7899853d9e8SJason Beloro 	/* fill in the known data */
7909853d9e8SJason Beloro 	rp->req_num = req->req_num;
7919853d9e8SJason Beloro 	rp->msg_type = DR_MEM_OK;
7929853d9e8SJason Beloro 	rp->msg_arg = nml ? nml : req->msg_arg;
7939853d9e8SJason Beloro 
7949853d9e8SJason Beloro 	/* stat array for the response */
7959853d9e8SJason Beloro 	stat = DR_MEM_RESP_QUERY(rp);
7969853d9e8SJason Beloro 
7979853d9e8SJason Beloro 	/* get the status for each of the mblocks */
7989853d9e8SJason Beloro 	if (nml) {
79979afa7fbSSean McEnroe 		for (idx = 0, ml = phys_copy; ml; ml = ml->ml_next, idx++) {
80056f33205SJonathan Adams 			mb.addr = ml->ml_address;
80156f33205SJonathan Adams 			mb.size = ml->ml_size;
8029853d9e8SJason Beloro 			dr_mem_query(&mb, &stat[idx]);
8039853d9e8SJason Beloro 		}
8049853d9e8SJason Beloro 	} else {
8059853d9e8SJason Beloro 		for (idx = 0; idx < req->msg_arg; idx++)
8069853d9e8SJason Beloro 			dr_mem_query(&req_mblks[idx], &stat[idx]);
8079853d9e8SJason Beloro 	}
8089853d9e8SJason Beloro 
8099853d9e8SJason Beloro 	*resp = rp;
8109853d9e8SJason Beloro 	*resp_len = rlen;
81179afa7fbSSean McEnroe 	if (phys_copy != NULL) {
81279afa7fbSSean McEnroe 		dr_memlist_delete(phys_copy);
81379afa7fbSSean McEnroe 	}
814af4c679fSSean McEnroe 	drctl_unblock();
815af4c679fSSean McEnroe 
8169853d9e8SJason Beloro 	return (0);
8179853d9e8SJason Beloro }
8189853d9e8SJason Beloro 
8199853d9e8SJason Beloro static int
cvt_err(int err)8209853d9e8SJason Beloro cvt_err(int err)
8219853d9e8SJason Beloro {
8229853d9e8SJason Beloro 	int rv;
8239853d9e8SJason Beloro 
8249853d9e8SJason Beloro 	switch (err) {
8259853d9e8SJason Beloro 	case KPHYSM_OK:
8269853d9e8SJason Beloro 		rv = DR_MEM_RES_OK;
8279853d9e8SJason Beloro 		break;
8289853d9e8SJason Beloro 	case KPHYSM_ESPAN:
8299853d9e8SJason Beloro 		rv = DR_MEM_RES_ESPAN;
8309853d9e8SJason Beloro 		break;
8319853d9e8SJason Beloro 	case KPHYSM_EFAULT:
8329853d9e8SJason Beloro 		rv = DR_MEM_RES_EFAULT;
8339853d9e8SJason Beloro 		break;
8349853d9e8SJason Beloro 	case KPHYSM_ERESOURCE:
8359853d9e8SJason Beloro 		rv = DR_MEM_RES_ERESOURCE;
8369853d9e8SJason Beloro 		break;
8379853d9e8SJason Beloro 	case KPHYSM_ENOTSUP:
8389853d9e8SJason Beloro 	case KPHYSM_ENOHANDLES:
8399853d9e8SJason Beloro 		rv = DR_MEM_RES_FAILURE;
8409853d9e8SJason Beloro 		break;
8419853d9e8SJason Beloro 	case KPHYSM_ENONRELOC:
8429853d9e8SJason Beloro 		rv = DR_MEM_RES_PERM;
8439853d9e8SJason Beloro 		break;
8449853d9e8SJason Beloro 	case KPHYSM_EHANDLE:
8459853d9e8SJason Beloro 		rv = DR_MEM_RES_FAILURE;
8469853d9e8SJason Beloro 		break;
8479853d9e8SJason Beloro 	case KPHYSM_EBUSY:
8489853d9e8SJason Beloro 		rv = DR_MEM_RES_EBUSY;
8499853d9e8SJason Beloro 		break;
8509853d9e8SJason Beloro 	case KPHYSM_ENOTVIABLE:
8519853d9e8SJason Beloro 		rv = DR_MEM_RES_ENOTVIABLE;
8529853d9e8SJason Beloro 		break;
8539853d9e8SJason Beloro 	case KPHYSM_ESEQUENCE:
8549853d9e8SJason Beloro 		rv = DR_MEM_RES_FAILURE;
8559853d9e8SJason Beloro 		break;
8569853d9e8SJason Beloro 	case KPHYSM_ENOWORK:
8579853d9e8SJason Beloro 		rv = DR_MEM_RES_ENOWORK;
8589853d9e8SJason Beloro 		break;
8599853d9e8SJason Beloro 	case KPHYSM_ECANCELLED:
8609853d9e8SJason Beloro 		rv = DR_MEM_RES_ECANCELLED;
8619853d9e8SJason Beloro 		break;
8629853d9e8SJason Beloro 	case KPHYSM_EREFUSED:
8639853d9e8SJason Beloro 		rv = DR_MEM_RES_EREFUSED;
8649853d9e8SJason Beloro 		break;
8659853d9e8SJason Beloro 	case KPHYSM_ENOTFINISHED:
8669853d9e8SJason Beloro 	case KPHYSM_ENOTRUNNING:
8679853d9e8SJason Beloro 		rv = DR_MEM_RES_FAILURE;
8689853d9e8SJason Beloro 		break;
8699853d9e8SJason Beloro 	case KPHYSM_EDUP:
8709853d9e8SJason Beloro 		rv = DR_MEM_RES_EDUP;
8719853d9e8SJason Beloro 		break;
8729853d9e8SJason Beloro 	default:
8739853d9e8SJason Beloro 		rv = DR_MEM_RES_FAILURE;
8749853d9e8SJason Beloro 		break;
8759853d9e8SJason Beloro 	}
8769853d9e8SJason Beloro 
8779853d9e8SJason Beloro 	return (rv);
8789853d9e8SJason Beloro }
8799853d9e8SJason Beloro 
8809853d9e8SJason Beloro static int
dr_mem_configure(dr_mem_blk_t * mbp,int * status)8819853d9e8SJason Beloro dr_mem_configure(dr_mem_blk_t *mbp, int *status)
8829853d9e8SJason Beloro {
8839853d9e8SJason Beloro 	int rv;
884af4c679fSSean McEnroe 	uint64_t addr, size;
8859853d9e8SJason Beloro 
8869853d9e8SJason Beloro 	rv = 0;
8879853d9e8SJason Beloro 	addr = mbp->addr;
8889853d9e8SJason Beloro 	size = mbp->size;
8899853d9e8SJason Beloro 
8909853d9e8SJason Beloro 	DR_DBG_MEM("dr_mem_configure...\n");
8919853d9e8SJason Beloro 
8929853d9e8SJason Beloro 	if (!MBLK_IS_VALID(mbp)) {
8939853d9e8SJason Beloro 		DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n", addr, size);
8949853d9e8SJason Beloro 		*status = DR_MEM_STAT_UNCONFIGURED;
8959853d9e8SJason Beloro 		rv = DR_MEM_RES_EINVAL;
8969853d9e8SJason Beloro 	} else if (rv = dr_mem_find(mbp)) {
8979853d9e8SJason Beloro 		DR_DBG_MEM("failed to find mblk 0x%lx.0x%lx (%d)\n",
8989853d9e8SJason Beloro 		    addr, size, rv);
8999853d9e8SJason Beloro 		if (rv == EINVAL) {
9009853d9e8SJason Beloro 			*status = DR_MEM_STAT_NOT_PRESENT;
9019853d9e8SJason Beloro 			rv = DR_MEM_RES_NOT_IN_MD;
9029853d9e8SJason Beloro 		} else {
9039853d9e8SJason Beloro 			*status = DR_MEM_STAT_UNCONFIGURED;
9049853d9e8SJason Beloro 			rv = DR_MEM_RES_FAILURE;
9059853d9e8SJason Beloro 		}
9069853d9e8SJason Beloro 	} else {
9079853d9e8SJason Beloro 		rv = mem_add(btop(addr), btop(size));
9089853d9e8SJason Beloro 		DR_DBG_MEM("addr=0x%lx size=0x%lx rv=%d\n", addr, size, rv);
9099853d9e8SJason Beloro 		if (rv) {
9109853d9e8SJason Beloro 			*status = DR_MEM_STAT_UNCONFIGURED;
9119853d9e8SJason Beloro 		} else {
9129853d9e8SJason Beloro 			*status = DR_MEM_STAT_CONFIGURED;
9139853d9e8SJason Beloro 		}
9149853d9e8SJason Beloro 	}
9159853d9e8SJason Beloro 
9169853d9e8SJason Beloro 	return (rv);
9179853d9e8SJason Beloro }
9189853d9e8SJason Beloro 
9199853d9e8SJason Beloro static int
dr_mem_unconfigure(dr_mem_blk_t * mbp,int * status)9209853d9e8SJason Beloro dr_mem_unconfigure(dr_mem_blk_t *mbp, int *status)
9219853d9e8SJason Beloro {
9229853d9e8SJason Beloro 	int rv;
9239853d9e8SJason Beloro 
9249853d9e8SJason Beloro 	DR_DBG_MEM("dr_mem_unconfigure...\n");
9259853d9e8SJason Beloro 
9269853d9e8SJason Beloro 	if (!MBLK_IS_VALID(mbp)) {
9279853d9e8SJason Beloro 		DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n",
9289853d9e8SJason Beloro 		    mbp->addr, mbp->size);
9299853d9e8SJason Beloro 		*status = DR_MEM_STAT_CONFIGURED;
9309853d9e8SJason Beloro 		rv = DR_MEM_RES_EINVAL;
9319853d9e8SJason Beloro 	} else if (rv = mem_del(btop(mbp->addr), btop(mbp->size))) {
9329853d9e8SJason Beloro 		*status = DR_MEM_STAT_CONFIGURED;
9339853d9e8SJason Beloro 	} else {
9349853d9e8SJason Beloro 		*status = DR_MEM_STAT_UNCONFIGURED;
9359853d9e8SJason Beloro 		rv = DR_MEM_RES_OK;
9369853d9e8SJason Beloro 		DR_DBG_MEM("mblk 0x%lx.0x%lx unconfigured\n",
9379853d9e8SJason Beloro 		    mbp->addr, mbp->size);
9389853d9e8SJason Beloro 	}
9399853d9e8SJason Beloro 	return (rv);
9409853d9e8SJason Beloro }
9419853d9e8SJason Beloro 
9429853d9e8SJason Beloro static int
dr_mem_del_stat(dr_mem_hdr_t * req,dr_mem_hdr_t ** resp,int * resp_len)9439853d9e8SJason Beloro dr_mem_del_stat(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
9449853d9e8SJason Beloro {
9459853d9e8SJason Beloro 	int			status;
9469853d9e8SJason Beloro 	int			rlen;
9479853d9e8SJason Beloro 	memdelstat_t		del_stat, *stat;
9489853d9e8SJason Beloro 	dr_mem_hdr_t		*rp;
9499853d9e8SJason Beloro 
9509853d9e8SJason Beloro 	/*
9519853d9e8SJason Beloro 	 * If a mem delete is in progress, get its status.
9529853d9e8SJason Beloro 	 */
9539853d9e8SJason Beloro 	status = (dr_mh && (kphysm_del_status(dr_mh, &del_stat) == KPHYSM_OK));
9549853d9e8SJason Beloro 
9559853d9e8SJason Beloro 	/* allocate a response message, should be freed by caller */
9569853d9e8SJason Beloro 	rlen = sizeof (dr_mem_hdr_t);
9579853d9e8SJason Beloro 	rlen += status * sizeof (memdelstat_t);
9589853d9e8SJason Beloro 	rp = kmem_zalloc(rlen, KM_SLEEP);
9599853d9e8SJason Beloro 
9609853d9e8SJason Beloro 	/* fill in the known data */
9619853d9e8SJason Beloro 	rp->req_num = req->req_num;
9629853d9e8SJason Beloro 	rp->msg_type = DR_MEM_OK;
9639853d9e8SJason Beloro 	rp->msg_arg = status;
9649853d9e8SJason Beloro 
9659853d9e8SJason Beloro 	if (status) {
9669853d9e8SJason Beloro 		/* stat struct for the response */
9679853d9e8SJason Beloro 		stat = DR_MEM_RESP_DEL_STAT(rp);
9689853d9e8SJason Beloro 		stat->phys_pages = ptob(del_stat.phys_pages);
9699853d9e8SJason Beloro 		stat->managed = ptob(del_stat.managed);
9709853d9e8SJason Beloro 		stat->collected = ptob(del_stat.collected);
9719853d9e8SJason Beloro 	}
9729853d9e8SJason Beloro 
9739853d9e8SJason Beloro 	*resp = rp;
9749853d9e8SJason Beloro 	*resp_len = rlen;
9759853d9e8SJason Beloro 
9769853d9e8SJason Beloro 	return (0);
9779853d9e8SJason Beloro }
9789853d9e8SJason Beloro 
9799853d9e8SJason Beloro static int
dr_mem_del_cancel(dr_mem_hdr_t * req,dr_mem_hdr_t ** resp,int * resp_len)9809853d9e8SJason Beloro dr_mem_del_cancel(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
9819853d9e8SJason Beloro {
9829853d9e8SJason Beloro 	int		rlen;
9839853d9e8SJason Beloro 	dr_mem_hdr_t	*rp;
9849853d9e8SJason Beloro 
9859853d9e8SJason Beloro 	/* allocate a response message, should be freed by caller */
9869853d9e8SJason Beloro 	rlen = sizeof (dr_mem_hdr_t);
9879853d9e8SJason Beloro 	rp = kmem_zalloc(rlen, KM_SLEEP);
9889853d9e8SJason Beloro 
9899853d9e8SJason Beloro 	/* fill in the known data */
9909853d9e8SJason Beloro 	rp->req_num = req->req_num;
9919853d9e8SJason Beloro 	rp->msg_type = DR_MEM_OK;
9929853d9e8SJason Beloro 	rp->msg_arg = (dr_mh && kphysm_del_cancel(dr_mh) != KPHYSM_OK) ?
9939853d9e8SJason Beloro 	    DR_MEM_RES_EINVAL : DR_MEM_RES_OK;
9949853d9e8SJason Beloro 
9959853d9e8SJason Beloro 	*resp = rp;
9969853d9e8SJason Beloro 	*resp_len = rlen;
9979853d9e8SJason Beloro 
9989853d9e8SJason Beloro 	return (0);
9999853d9e8SJason Beloro }
10009853d9e8SJason Beloro 
10019853d9e8SJason Beloro static int
dr_mem_find(dr_mem_blk_t * mbp)10029853d9e8SJason Beloro dr_mem_find(dr_mem_blk_t *mbp)
10039853d9e8SJason Beloro {
10049853d9e8SJason Beloro 	md_t		*mdp = NULL;
10059853d9e8SJason Beloro 	int		num_nodes;
10069853d9e8SJason Beloro 	int		rv = 0;
10079853d9e8SJason Beloro 	int		listsz;
10089853d9e8SJason Beloro 	mde_cookie_t	*listp = NULL;
10099853d9e8SJason Beloro 	mde_cookie_t	memnode;
10109853d9e8SJason Beloro 	char		*found = "found";
10119853d9e8SJason Beloro 
10129853d9e8SJason Beloro 	if ((mdp = md_get_handle()) == NULL) {
10139853d9e8SJason Beloro 		DR_DBG_MEM("unable to initialize machine description\n");
10149853d9e8SJason Beloro 		return (-1);
10159853d9e8SJason Beloro 	}
10169853d9e8SJason Beloro 
10179853d9e8SJason Beloro 	num_nodes = md_node_count(mdp);
10189853d9e8SJason Beloro 	ASSERT(num_nodes > 0);
10199853d9e8SJason Beloro 
10209853d9e8SJason Beloro 	listsz = num_nodes * sizeof (mde_cookie_t);
10219853d9e8SJason Beloro 	listp = kmem_zalloc(listsz, KM_SLEEP);
10229853d9e8SJason Beloro 
10239853d9e8SJason Beloro 	memnode = dr_mem_find_node_md(mbp, mdp, listp);
10249853d9e8SJason Beloro 
10259853d9e8SJason Beloro 	if (memnode == MDE_INVAL_ELEM_COOKIE) {
10269853d9e8SJason Beloro 		rv = EINVAL;
10279853d9e8SJason Beloro 		found = "not found";
10289853d9e8SJason Beloro 	}
10299853d9e8SJason Beloro 
10309853d9e8SJason Beloro 	DR_DBG_MEM("mblk 0x%lx.0x%lx %s\n", mbp->addr, mbp->size, found);
10319853d9e8SJason Beloro 
10329853d9e8SJason Beloro 	kmem_free(listp, listsz);
10339853d9e8SJason Beloro 	(void) md_fini_handle(mdp);
10349853d9e8SJason Beloro 
10359853d9e8SJason Beloro 	return (rv);
10369853d9e8SJason Beloro }
10379853d9e8SJason Beloro 
10389853d9e8SJason Beloro /*
10399853d9e8SJason Beloro  * Look up a particular mblk in the MD. Returns the mde_cookie_t
10409853d9e8SJason Beloro  * representing that mblk if present, and MDE_INVAL_ELEM_COOKIE
10419853d9e8SJason Beloro  * otherwise. It is assumed the scratch array has already been
10429853d9e8SJason Beloro  * allocated so that it can accommodate the worst case scenario,
10439853d9e8SJason Beloro  * every node in the MD.
10449853d9e8SJason Beloro  */
10459853d9e8SJason Beloro static mde_cookie_t
dr_mem_find_node_md(dr_mem_blk_t * mbp,md_t * mdp,mde_cookie_t * listp)10469853d9e8SJason Beloro dr_mem_find_node_md(dr_mem_blk_t *mbp, md_t *mdp, mde_cookie_t *listp)
10479853d9e8SJason Beloro {
10489853d9e8SJason Beloro 	int		idx;
10499853d9e8SJason Beloro 	int		nnodes;
10509853d9e8SJason Beloro 	mde_cookie_t	rootnode;
10519853d9e8SJason Beloro 	uint64_t	base_prop;
10529853d9e8SJason Beloro 	uint64_t	size_prop;
10539853d9e8SJason Beloro 	mde_cookie_t	result = MDE_INVAL_ELEM_COOKIE;
10549853d9e8SJason Beloro 
10559853d9e8SJason Beloro 	rootnode = md_root_node(mdp);
10569853d9e8SJason Beloro 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
10579853d9e8SJason Beloro 
10589853d9e8SJason Beloro 	/*
10599853d9e8SJason Beloro 	 * Scan the DAG for all the mem nodes
10609853d9e8SJason Beloro 	 */
10619853d9e8SJason Beloro 	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "mblock"),
10629853d9e8SJason Beloro 	    md_find_name(mdp, "fwd"), listp);
10639853d9e8SJason Beloro 
10649853d9e8SJason Beloro 	if (nnodes < 0) {
10659853d9e8SJason Beloro 		DR_DBG_MEM("Scan for mblks failed\n");
10669853d9e8SJason Beloro 		return (result);
10679853d9e8SJason Beloro 	}
10689853d9e8SJason Beloro 
10699853d9e8SJason Beloro 	DR_DBG_MEM("dr_mem_find_node_md: found %d mblks in the MD\n", nnodes);
10709853d9e8SJason Beloro 
10719853d9e8SJason Beloro 	/*
10729853d9e8SJason Beloro 	 * Find the mblk of interest
10739853d9e8SJason Beloro 	 */
10749853d9e8SJason Beloro 	for (idx = 0; idx < nnodes; idx++) {
10759853d9e8SJason Beloro 
10769853d9e8SJason Beloro 		if (md_get_prop_val(mdp, listp[idx], "base", &base_prop)) {
10779853d9e8SJason Beloro 			DR_DBG_MEM("Missing 'base' property for mblk node %d\n",
10789853d9e8SJason Beloro 			    idx);
10799853d9e8SJason Beloro 			break;
10809853d9e8SJason Beloro 		}
10819853d9e8SJason Beloro 
10829853d9e8SJason Beloro 		if (md_get_prop_val(mdp, listp[idx], "size", &size_prop)) {
10839853d9e8SJason Beloro 			DR_DBG_MEM("Missing 'size' property for mblk node %d\n",
10849853d9e8SJason Beloro 			    idx);
10859853d9e8SJason Beloro 			break;
10869853d9e8SJason Beloro 		}
10879853d9e8SJason Beloro 
10889853d9e8SJason Beloro 		if (base_prop <= mbp->addr &&
10899853d9e8SJason Beloro 		    (base_prop + size_prop) >= (mbp->addr + mbp->size)) {
10909853d9e8SJason Beloro 			/* found a match */
10919853d9e8SJason Beloro 			DR_DBG_MEM("dr_mem_find_node_md: found mblk "
10929853d9e8SJason Beloro 			    "0x%lx.0x%lx in MD\n", mbp->addr, mbp->size);
10939853d9e8SJason Beloro 			result = listp[idx];
10949853d9e8SJason Beloro 			break;
10959853d9e8SJason Beloro 		}
10969853d9e8SJason Beloro 	}
10979853d9e8SJason Beloro 
10989853d9e8SJason Beloro 	if (result == MDE_INVAL_ELEM_COOKIE) {
10999853d9e8SJason Beloro 		DR_DBG_MEM("mblk 0x%lx.0x%lx not in MD\n",
11009853d9e8SJason Beloro 		    mbp->addr, mbp->size);
11019853d9e8SJason Beloro 	}
11029853d9e8SJason Beloro 
11039853d9e8SJason Beloro 	return (result);
11049853d9e8SJason Beloro }
11059853d9e8SJason Beloro 
11069853d9e8SJason Beloro static int
mem_add(pfn_t base,pgcnt_t npgs)11079853d9e8SJason Beloro mem_add(pfn_t base, pgcnt_t npgs)
11089853d9e8SJason Beloro {
11099853d9e8SJason Beloro 	int rv, rc;
11109853d9e8SJason Beloro 
11119853d9e8SJason Beloro 	DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
11129853d9e8SJason Beloro 
11139853d9e8SJason Beloro 	if (npgs == 0)
1114af4c679fSSean McEnroe 		return (DR_MEM_RES_OK);
11159853d9e8SJason Beloro 
11169853d9e8SJason Beloro 	rv = kphysm_add_memory_dynamic(base, npgs);
11179853d9e8SJason Beloro 	DR_DBG_MEM("%s: kphysm_add(0x%lx, 0x%lx) = %d", __func__, base, npgs,
11189853d9e8SJason Beloro 	    rv);
1119af4c679fSSean McEnroe 	if (rv == KPHYSM_OK) {
11209853d9e8SJason Beloro 		if (rc = kcage_range_add(base, npgs, KCAGE_DOWN))
11219853d9e8SJason Beloro 			cmn_err(CE_WARN, "kcage_range_add() = %d", rc);
11229853d9e8SJason Beloro 	}
1123af4c679fSSean McEnroe 	rv = cvt_err(rv);
11249853d9e8SJason Beloro 	return (rv);
11259853d9e8SJason Beloro }
11269853d9e8SJason Beloro 
11279853d9e8SJason Beloro static void
del_done(void * arg,int error)11289853d9e8SJason Beloro del_done(void *arg, int error)
11299853d9e8SJason Beloro {
11309853d9e8SJason Beloro 	mem_sync_t *ms = arg;
11319853d9e8SJason Beloro 
11329853d9e8SJason Beloro 	mutex_enter(&ms->lock);
11339853d9e8SJason Beloro 	ms->error = error;
11349853d9e8SJason Beloro 	ms->done = 1;
11359853d9e8SJason Beloro 	cv_signal(&ms->cond);
11369853d9e8SJason Beloro 	mutex_exit(&ms->lock);
11379853d9e8SJason Beloro }
11389853d9e8SJason Beloro 
11399853d9e8SJason Beloro static int
mem_del(pfn_t base,pgcnt_t npgs)11409853d9e8SJason Beloro mem_del(pfn_t base, pgcnt_t npgs)
11419853d9e8SJason Beloro {
11429853d9e8SJason Beloro 	int rv, err, del_range = 0;
1143af4c679fSSean McEnroe 	int convert = 1;
11449853d9e8SJason Beloro 	mem_sync_t ms;
11459853d9e8SJason Beloro 	memquery_t mq;
11469853d9e8SJason Beloro 	memhandle_t mh;
11479853d9e8SJason Beloro 	struct memlist *ml;
11489853d9e8SJason Beloro 	struct memlist *d_ml = NULL;
11499853d9e8SJason Beloro 
11509853d9e8SJason Beloro 	DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
11519853d9e8SJason Beloro 
11529853d9e8SJason Beloro 	if (npgs == 0)
1153af4c679fSSean McEnroe 		return (DR_MEM_RES_OK);
11549853d9e8SJason Beloro 
11559853d9e8SJason Beloro 	if ((rv = kphysm_del_gethandle(&mh)) != KPHYSM_OK) {
11569853d9e8SJason Beloro 		cmn_err(CE_WARN, "%s: del_gethandle() = %d", __func__, rv);
1157af4c679fSSean McEnroe 		rv = cvt_err(rv);
11589853d9e8SJason Beloro 		return (rv);
11599853d9e8SJason Beloro 	}
11609853d9e8SJason Beloro 	if ((rv = kphysm_del_span_query(base, npgs, &mq))
11619853d9e8SJason Beloro 	    != KPHYSM_OK) {
11629853d9e8SJason Beloro 		cmn_err(CE_WARN, "%s: del_span_query() = %d", __func__, rv);
11639853d9e8SJason Beloro 		goto done;
11649853d9e8SJason Beloro 	}
11659853d9e8SJason Beloro 	if (mq.nonrelocatable) {
11669853d9e8SJason Beloro 		DR_DBG_MEM("%s: non-reloc pages = %ld",
11679853d9e8SJason Beloro 		    __func__, mq.nonrelocatable);
11689853d9e8SJason Beloro 		rv  = KPHYSM_ENONRELOC;
11699853d9e8SJason Beloro 		goto done;
11709853d9e8SJason Beloro 	}
11719853d9e8SJason Beloro 	if (rv = kcage_range_delete(base, npgs)) {
1172af4c679fSSean McEnroe 		switch (rv) {
1173af4c679fSSean McEnroe 		case EBUSY:
1174af4c679fSSean McEnroe 			rv = DR_MEM_RES_ENOTVIABLE;
1175af4c679fSSean McEnroe 			break;
1176af4c679fSSean McEnroe 		default:
1177af4c679fSSean McEnroe 			rv = DR_MEM_RES_FAILURE;
1178af4c679fSSean McEnroe 			break;
1179af4c679fSSean McEnroe 		}
1180af4c679fSSean McEnroe 		convert = 0; /* conversion done */
11819853d9e8SJason Beloro 		cmn_err(CE_WARN, "%s: del_range() = %d", __func__, rv);
11829853d9e8SJason Beloro 		goto done;
11839853d9e8SJason Beloro 	} else {
11849853d9e8SJason Beloro 		del_range++;
11859853d9e8SJason Beloro 	}
11869853d9e8SJason Beloro 	if ((rv = kphysm_del_span(mh, base, npgs)) != KPHYSM_OK) {
11879853d9e8SJason Beloro 		cmn_err(CE_WARN, "%s: del_span() = %d", __func__, rv);
11889853d9e8SJason Beloro 		goto done;
11899853d9e8SJason Beloro 	}
11909853d9e8SJason Beloro 	if ((rv = memlist_add_span(ptob(base), ptob(npgs), &d_ml))
11919853d9e8SJason Beloro 	    != MEML_SPANOP_OK) {
1192af4c679fSSean McEnroe 		switch (rv) {
1193af4c679fSSean McEnroe 		case MEML_SPANOP_ESPAN:
1194af4c679fSSean McEnroe 			rv = DR_MEM_RES_ESPAN;
1195af4c679fSSean McEnroe 			break;
1196af4c679fSSean McEnroe 		case MEML_SPANOP_EALLOC:
1197af4c679fSSean McEnroe 			rv = DR_MEM_RES_ERESOURCE;
1198af4c679fSSean McEnroe 			break;
1199af4c679fSSean McEnroe 		default:
1200af4c679fSSean McEnroe 			rv = DR_MEM_RES_FAILURE;
1201af4c679fSSean McEnroe 			break;
1202af4c679fSSean McEnroe 		}
1203af4c679fSSean McEnroe 		convert = 0; /* conversion done */
12049853d9e8SJason Beloro 		cmn_err(CE_WARN, "%s: add_span() = %d", __func__, rv);
12059853d9e8SJason Beloro 		goto done;
12069853d9e8SJason Beloro 	}
12079853d9e8SJason Beloro 
12089853d9e8SJason Beloro 	DR_DBG_MEM("%s: reserved=0x%lx", __func__, npgs);
12099853d9e8SJason Beloro 
12109853d9e8SJason Beloro 	bzero((void *) &ms, sizeof (ms));
12119853d9e8SJason Beloro 
12129853d9e8SJason Beloro 	mutex_init(&ms.lock, NULL, MUTEX_DRIVER, NULL);
12139853d9e8SJason Beloro 	cv_init(&ms.cond, NULL, CV_DRIVER, NULL);
12149853d9e8SJason Beloro 	mutex_enter(&ms.lock);
12159853d9e8SJason Beloro 
12169853d9e8SJason Beloro 	if ((rv = kphysm_del_start(mh, del_done, (void *) &ms)) == KPHYSM_OK) {
12179853d9e8SJason Beloro 		/*
12189853d9e8SJason Beloro 		 * Since we've called drctl_config_init, we are the only
12199853d9e8SJason Beloro 		 * DR ctl operation in progress.  Set dr_mh to the
12209853d9e8SJason Beloro 		 * delete memhandle for use by stat and cancel.
12219853d9e8SJason Beloro 		 */
12229853d9e8SJason Beloro 		ASSERT(dr_mh == NULL);
12239853d9e8SJason Beloro 		dr_mh = mh;
12249853d9e8SJason Beloro 
12259853d9e8SJason Beloro 		/*
12269853d9e8SJason Beloro 		 * Wait for completion or interrupt.
12279853d9e8SJason Beloro 		 */
12289853d9e8SJason Beloro 		while (!ms.done) {
12299853d9e8SJason Beloro 			if (cv_wait_sig(&ms.cond, &ms.lock) == 0) {
12309853d9e8SJason Beloro 				/*
12319853d9e8SJason Beloro 				 * There is a pending signal.
12329853d9e8SJason Beloro 				 */
12339853d9e8SJason Beloro 				(void) kphysm_del_cancel(mh);
12349853d9e8SJason Beloro 				DR_DBG_MEM("%s: cancel", __func__);
12359853d9e8SJason Beloro 				/*
12369853d9e8SJason Beloro 				 * Wait for completion.
12379853d9e8SJason Beloro 				 */
12389853d9e8SJason Beloro 				while (!ms.done)
12399853d9e8SJason Beloro 					cv_wait(&ms.cond, &ms.lock);
12409853d9e8SJason Beloro 			}
12419853d9e8SJason Beloro 		}
12429853d9e8SJason Beloro 		dr_mh = NULL;
12439853d9e8SJason Beloro 		rv = ms.error;
12449853d9e8SJason Beloro 	} else {
12459853d9e8SJason Beloro 		DR_DBG_MEM("%s: del_start() = %d", __func__, rv);
12469853d9e8SJason Beloro 	}
12479853d9e8SJason Beloro 
12489853d9e8SJason Beloro 	mutex_exit(&ms.lock);
12499853d9e8SJason Beloro 	cv_destroy(&ms.cond);
12509853d9e8SJason Beloro 	mutex_destroy(&ms.lock);
12519853d9e8SJason Beloro 
12529853d9e8SJason Beloro done:
12539853d9e8SJason Beloro 	if (rv && del_range) {
12549853d9e8SJason Beloro 		/*
12559853d9e8SJason Beloro 		 * Add back the spans to the kcage growth list.
12569853d9e8SJason Beloro 		 */
125756f33205SJonathan Adams 		for (ml = d_ml; ml; ml = ml->ml_next)
125856f33205SJonathan Adams 			if (err = kcage_range_add(btop(ml->ml_address),
125956f33205SJonathan Adams 			    btop(ml->ml_size), KCAGE_DOWN))
12609853d9e8SJason Beloro 				cmn_err(CE_WARN, "kcage_range_add() = %d", err);
12619853d9e8SJason Beloro 	}
12629853d9e8SJason Beloro 	memlist_free_list(d_ml);
12639853d9e8SJason Beloro 
12649853d9e8SJason Beloro 	if ((err = kphysm_del_release(mh)) != KPHYSM_OK)
12659853d9e8SJason Beloro 		cmn_err(CE_WARN, "%s: del_release() = %d", __func__, err);
1266af4c679fSSean McEnroe 	if (convert)
1267af4c679fSSean McEnroe 		rv = cvt_err(rv);
12689853d9e8SJason Beloro 
12699853d9e8SJason Beloro 	DR_DBG_MEM("%s: rv=%d", __func__, rv);
12709853d9e8SJason Beloro 
12719853d9e8SJason Beloro 	return (rv);
12729853d9e8SJason Beloro }
1273