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