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 /* 23*02b4e56cSHaik 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> 71*02b4e56cSHaik 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 173*02b4e56cSHaik Aftandilian static char * 174*02b4e56cSHaik Aftandilian dr_mem_estr_detail[] = { 175*02b4e56cSHaik Aftandilian "", /* DR_MEM_SRES_NONE */ 176*02b4e56cSHaik Aftandilian "memory DR disabled after migration" /* DR_MEM_SRES_OS_SUSPENDED */ 177*02b4e56cSHaik Aftandilian }; 178*02b4e56cSHaik 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 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 2369853d9e8SJason Beloro _info(struct modinfo *modinfop) 2379853d9e8SJason Beloro { 2389853d9e8SJason Beloro return (mod_info(&modlinkage, modinfop)); 2399853d9e8SJason Beloro } 2409853d9e8SJason Beloro 2419853d9e8SJason Beloro int 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 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 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 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 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 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 391*02b4e56cSHaik Aftandilian static char * 392*02b4e56cSHaik Aftandilian dr_mem_get_errstr(int result, int subresult) 393*02b4e56cSHaik Aftandilian { 394*02b4e56cSHaik Aftandilian size_t len; 395*02b4e56cSHaik Aftandilian char *errstr; 396*02b4e56cSHaik Aftandilian const char *separator = ": "; 397*02b4e56cSHaik Aftandilian 398*02b4e56cSHaik Aftandilian if (subresult == DR_MEM_SRES_NONE) 399*02b4e56cSHaik Aftandilian return (i_ddi_strdup(dr_mem_estr[result], KM_SLEEP)); 400*02b4e56cSHaik Aftandilian 401*02b4e56cSHaik Aftandilian len = snprintf(NULL, 0, "%s%s%s", dr_mem_estr[result], 402*02b4e56cSHaik Aftandilian separator, dr_mem_estr_detail[subresult]) + 1; 403*02b4e56cSHaik Aftandilian 404*02b4e56cSHaik Aftandilian errstr = kmem_alloc(len, KM_SLEEP); 405*02b4e56cSHaik Aftandilian 406*02b4e56cSHaik Aftandilian (void) snprintf(errstr, len, "%s%s%s", dr_mem_estr[result], 407*02b4e56cSHaik Aftandilian separator, dr_mem_estr_detail[subresult]); 408*02b4e56cSHaik Aftandilian 409*02b4e56cSHaik Aftandilian return (errstr); 410*02b4e56cSHaik Aftandilian } 411*02b4e56cSHaik 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 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; 424*02b4e56cSHaik Aftandilian int subresult; 4259853d9e8SJason Beloro int status; 426*02b4e56cSHaik 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 500*02b4e56cSHaik Aftandilian /* 501*02b4e56cSHaik Aftandilian * Memory DR operations are not safe if we have been suspended and 502*02b4e56cSHaik Aftandilian * resumed. Until this limitation is lifted, check to see if memory 503*02b4e56cSHaik Aftandilian * DR operations are permitted at this time by the suspend subsystem. 504*02b4e56cSHaik Aftandilian */ 505*02b4e56cSHaik Aftandilian if ((suspend_allows_dr = suspend_memdr_allowed()) == B_FALSE) { 506*02b4e56cSHaik Aftandilian result = DR_MEM_RES_BLOCKED; 507*02b4e56cSHaik Aftandilian subresult = DR_MEM_SRES_OS_SUSPENDED; 508*02b4e56cSHaik Aftandilian } else { 509*02b4e56cSHaik Aftandilian subresult = DR_MEM_SRES_NONE; 510*02b4e56cSHaik Aftandilian } 511*02b4e56cSHaik 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 525*02b4e56cSHaik Aftandilian /* 526*02b4e56cSHaik Aftandilian * If memory DR operations are permitted at this time by 527*02b4e56cSHaik Aftandilian * the suspend subsystem, call the function to perform the 528*02b4e56cSHaik Aftandilian * operation, otherwise return a result indicating that the 529*02b4e56cSHaik Aftandilian * operation was blocked. 530*02b4e56cSHaik Aftandilian */ 531*02b4e56cSHaik 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 */ 539*02b4e56cSHaik 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 * 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 */ 6149853d9e8SJason Beloro if (rsrc[idx].offset != NULL) { 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 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 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 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 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); 7719853d9e8SJason Beloro if (req_mblks->addr == NULL && 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 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 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 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 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 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 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 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 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 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 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