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