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*12260SHaik.Aftandilian@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410106SJason.Beloro@Sun.COM */
2510106SJason.Beloro@Sun.COM
2610106SJason.Beloro@Sun.COM /*
2710106SJason.Beloro@Sun.COM * sun4v Memory DR Module
2810106SJason.Beloro@Sun.COM */
2910106SJason.Beloro@Sun.COM
3010106SJason.Beloro@Sun.COM
3110106SJason.Beloro@Sun.COM #include <sys/types.h>
3210106SJason.Beloro@Sun.COM #include <sys/cmn_err.h>
3310106SJason.Beloro@Sun.COM #include <sys/vmem.h>
3410106SJason.Beloro@Sun.COM #include <sys/kmem.h>
3510106SJason.Beloro@Sun.COM #include <sys/systm.h>
3610106SJason.Beloro@Sun.COM #include <sys/machsystm.h> /* for page_freelist_coalesce() */
3710106SJason.Beloro@Sun.COM #include <sys/errno.h>
3810106SJason.Beloro@Sun.COM #include <sys/memnode.h>
3910106SJason.Beloro@Sun.COM #include <sys/memlist.h>
4010106SJason.Beloro@Sun.COM #include <sys/memlist_impl.h>
4110106SJason.Beloro@Sun.COM #include <sys/tuneable.h>
4210106SJason.Beloro@Sun.COM #include <sys/proc.h>
4310106SJason.Beloro@Sun.COM #include <sys/disp.h>
4410106SJason.Beloro@Sun.COM #include <sys/debug.h>
4510106SJason.Beloro@Sun.COM #include <sys/vm.h>
4610106SJason.Beloro@Sun.COM #include <sys/callb.h>
4710106SJason.Beloro@Sun.COM #include <sys/memlist_plat.h> /* for installed_top_size() */
4810106SJason.Beloro@Sun.COM #include <sys/condvar_impl.h> /* for CV_HAS_WAITERS() */
4910106SJason.Beloro@Sun.COM #include <sys/dumphdr.h> /* for dump_resize() */
5010106SJason.Beloro@Sun.COM #include <sys/atomic.h> /* for use in stats collection */
5110106SJason.Beloro@Sun.COM #include <sys/rwlock.h>
5210106SJason.Beloro@Sun.COM #include <vm/seg_kmem.h>
5310106SJason.Beloro@Sun.COM #include <vm/seg_kpm.h>
5410106SJason.Beloro@Sun.COM #include <vm/page.h>
5510106SJason.Beloro@Sun.COM #include <vm/vm_dep.h>
5610106SJason.Beloro@Sun.COM #define SUNDDI_IMPL /* so sunddi.h will not redefine splx() et al */
5710106SJason.Beloro@Sun.COM #include <sys/sunddi.h>
5810106SJason.Beloro@Sun.COM #include <sys/mem_config.h>
5910106SJason.Beloro@Sun.COM #include <sys/mem_cage.h>
6010106SJason.Beloro@Sun.COM #include <sys/lgrp.h>
6110106SJason.Beloro@Sun.COM #include <sys/ddi.h>
6210106SJason.Beloro@Sun.COM
6310106SJason.Beloro@Sun.COM #include <sys/modctl.h>
6410106SJason.Beloro@Sun.COM #include <sys/sysevent/dr.h>
6510106SJason.Beloro@Sun.COM #include <sys/mach_descrip.h>
6610106SJason.Beloro@Sun.COM #include <sys/mdesc.h>
6710106SJason.Beloro@Sun.COM #include <sys/ds.h>
6810106SJason.Beloro@Sun.COM #include <sys/drctl.h>
6910106SJason.Beloro@Sun.COM #include <sys/dr_util.h>
7010106SJason.Beloro@Sun.COM #include <sys/dr_mem.h>
71*12260SHaik.Aftandilian@Sun.COM #include <sys/suspend.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
173*12260SHaik.Aftandilian@Sun.COM static char *
174*12260SHaik.Aftandilian@Sun.COM dr_mem_estr_detail[] = {
175*12260SHaik.Aftandilian@Sun.COM "", /* DR_MEM_SRES_NONE */
176*12260SHaik.Aftandilian@Sun.COM "memory DR disabled after migration" /* DR_MEM_SRES_OS_SUSPENDED */
177*12260SHaik.Aftandilian@Sun.COM };
178*12260SHaik.Aftandilian@Sun.COM
17910106SJason.Beloro@Sun.COM typedef struct {
18010106SJason.Beloro@Sun.COM kcondvar_t cond;
18110106SJason.Beloro@Sun.COM kmutex_t lock;
18210106SJason.Beloro@Sun.COM int error;
18310106SJason.Beloro@Sun.COM int done;
18410106SJason.Beloro@Sun.COM } mem_sync_t;
18510106SJason.Beloro@Sun.COM
18610106SJason.Beloro@Sun.COM /*
18710106SJason.Beloro@Sun.COM * Internal Functions
18810106SJason.Beloro@Sun.COM */
18910106SJason.Beloro@Sun.COM static int dr_mem_init(void);
19010106SJason.Beloro@Sun.COM static int dr_mem_fini(void);
19110106SJason.Beloro@Sun.COM
19210106SJason.Beloro@Sun.COM static int dr_mem_list_wrk(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
19310106SJason.Beloro@Sun.COM static int dr_mem_list_query(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
19410106SJason.Beloro@Sun.COM static int dr_mem_del_stat(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
19510106SJason.Beloro@Sun.COM static int dr_mem_del_cancel(dr_mem_hdr_t *, dr_mem_hdr_t **, int *);
19610106SJason.Beloro@Sun.COM
19710106SJason.Beloro@Sun.COM static int dr_mem_unconfigure(dr_mem_blk_t *, int *);
19810106SJason.Beloro@Sun.COM static int dr_mem_configure(dr_mem_blk_t *, int *);
19910106SJason.Beloro@Sun.COM static void dr_mem_query(dr_mem_blk_t *, dr_mem_query_t *);
20010106SJason.Beloro@Sun.COM
20110106SJason.Beloro@Sun.COM static dr_mem_res_t *dr_mem_res_array_init(dr_mem_hdr_t *, drctl_rsrc_t *, int);
20210106SJason.Beloro@Sun.COM static void dr_mem_res_array_fini(dr_mem_res_t *res, int nres);
20310106SJason.Beloro@Sun.COM static size_t dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res,
20410106SJason.Beloro@Sun.COM dr_mem_hdr_t **respp);
20510106SJason.Beloro@Sun.COM
20610106SJason.Beloro@Sun.COM static int dr_mem_find(dr_mem_blk_t *mbp);
20710106SJason.Beloro@Sun.COM static mde_cookie_t dr_mem_find_node_md(dr_mem_blk_t *, md_t *, mde_cookie_t *);
20810106SJason.Beloro@Sun.COM
20910106SJason.Beloro@Sun.COM static int mem_add(pfn_t, pgcnt_t);
21010106SJason.Beloro@Sun.COM static int mem_del(pfn_t, pgcnt_t);
21110106SJason.Beloro@Sun.COM
21210106SJason.Beloro@Sun.COM extern int kphysm_add_memory_dynamic(pfn_t, pgcnt_t);
21310106SJason.Beloro@Sun.COM
21410106SJason.Beloro@Sun.COM int
_init(void)21510106SJason.Beloro@Sun.COM _init(void)
21610106SJason.Beloro@Sun.COM {
21710106SJason.Beloro@Sun.COM int status;
21810106SJason.Beloro@Sun.COM
21910106SJason.Beloro@Sun.COM /* check that Memory DR is enabled */
22010106SJason.Beloro@Sun.COM if (dr_is_disabled(DR_TYPE_MEM))
22110106SJason.Beloro@Sun.COM return (ENOTSUP);
22210106SJason.Beloro@Sun.COM
22310106SJason.Beloro@Sun.COM if ((status = dr_mem_init()) != 0) {
22410106SJason.Beloro@Sun.COM cmn_err(CE_NOTE, "Memory DR initialization failed");
22510106SJason.Beloro@Sun.COM return (status);
22610106SJason.Beloro@Sun.COM }
22710106SJason.Beloro@Sun.COM
22810106SJason.Beloro@Sun.COM if ((status = mod_install(&modlinkage)) != 0) {
22910106SJason.Beloro@Sun.COM (void) dr_mem_fini();
23010106SJason.Beloro@Sun.COM }
23110106SJason.Beloro@Sun.COM
23210106SJason.Beloro@Sun.COM return (status);
23310106SJason.Beloro@Sun.COM }
23410106SJason.Beloro@Sun.COM
23510106SJason.Beloro@Sun.COM int
_info(struct modinfo * modinfop)23610106SJason.Beloro@Sun.COM _info(struct modinfo *modinfop)
23710106SJason.Beloro@Sun.COM {
23810106SJason.Beloro@Sun.COM return (mod_info(&modlinkage, modinfop));
23910106SJason.Beloro@Sun.COM }
24010106SJason.Beloro@Sun.COM
24110106SJason.Beloro@Sun.COM int
_fini(void)24210106SJason.Beloro@Sun.COM _fini(void)
24310106SJason.Beloro@Sun.COM {
24410106SJason.Beloro@Sun.COM int status;
24510106SJason.Beloro@Sun.COM
24610106SJason.Beloro@Sun.COM if (dr_mem_allow_unload == 0)
24710106SJason.Beloro@Sun.COM return (EBUSY);
24810106SJason.Beloro@Sun.COM
24910106SJason.Beloro@Sun.COM if ((status = mod_remove(&modlinkage)) == 0) {
25010106SJason.Beloro@Sun.COM (void) dr_mem_fini();
25110106SJason.Beloro@Sun.COM }
25210106SJason.Beloro@Sun.COM
25310106SJason.Beloro@Sun.COM return (status);
25410106SJason.Beloro@Sun.COM }
25510106SJason.Beloro@Sun.COM
25610106SJason.Beloro@Sun.COM static int
dr_mem_init(void)25710106SJason.Beloro@Sun.COM dr_mem_init(void)
25810106SJason.Beloro@Sun.COM {
25910106SJason.Beloro@Sun.COM int rv;
26010106SJason.Beloro@Sun.COM
26110106SJason.Beloro@Sun.COM if ((rv = ds_cap_init(&dr_mem_cap, &dr_mem_ops)) != 0) {
26210106SJason.Beloro@Sun.COM cmn_err(CE_NOTE, "dr_mem: ds_cap_init failed: %d", rv);
26310106SJason.Beloro@Sun.COM return (rv);
26410106SJason.Beloro@Sun.COM }
26510106SJason.Beloro@Sun.COM
26610106SJason.Beloro@Sun.COM return (0);
26710106SJason.Beloro@Sun.COM }
26810106SJason.Beloro@Sun.COM
26910106SJason.Beloro@Sun.COM static int
dr_mem_fini(void)27010106SJason.Beloro@Sun.COM dr_mem_fini(void)
27110106SJason.Beloro@Sun.COM {
27210106SJason.Beloro@Sun.COM int rv;
27310106SJason.Beloro@Sun.COM
27410106SJason.Beloro@Sun.COM if ((rv = ds_cap_fini(&dr_mem_cap)) != 0) {
27510106SJason.Beloro@Sun.COM cmn_err(CE_NOTE, "dr_mem: ds_cap_fini failed: %d", rv);
27610106SJason.Beloro@Sun.COM }
27710106SJason.Beloro@Sun.COM
27810106SJason.Beloro@Sun.COM return (rv);
27910106SJason.Beloro@Sun.COM }
28010106SJason.Beloro@Sun.COM
28110106SJason.Beloro@Sun.COM static void
dr_mem_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)28210106SJason.Beloro@Sun.COM dr_mem_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
28310106SJason.Beloro@Sun.COM {
28410106SJason.Beloro@Sun.COM DR_DBG_MEM("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
28510106SJason.Beloro@Sun.COM ver->major, ver->minor, hdl);
28610106SJason.Beloro@Sun.COM
28710106SJason.Beloro@Sun.COM ds_handle = hdl;
28810106SJason.Beloro@Sun.COM }
28910106SJason.Beloro@Sun.COM
29010106SJason.Beloro@Sun.COM static void
dr_mem_unreg_handler(ds_cb_arg_t arg)29110106SJason.Beloro@Sun.COM dr_mem_unreg_handler(ds_cb_arg_t arg)
29210106SJason.Beloro@Sun.COM {
29310106SJason.Beloro@Sun.COM DR_DBG_MEM("unreg_handler: arg=0x%p\n", arg);
29410106SJason.Beloro@Sun.COM
29510106SJason.Beloro@Sun.COM ds_handle = DS_INVALID_HDL;
29610106SJason.Beloro@Sun.COM }
29710106SJason.Beloro@Sun.COM
29810106SJason.Beloro@Sun.COM /*ARGSUSED*/
29910106SJason.Beloro@Sun.COM static void
dr_mem_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)30010106SJason.Beloro@Sun.COM dr_mem_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
30110106SJason.Beloro@Sun.COM {
30210106SJason.Beloro@Sun.COM dr_mem_hdr_t *req = buf;
30310106SJason.Beloro@Sun.COM dr_mem_hdr_t err_resp;
30410106SJason.Beloro@Sun.COM dr_mem_hdr_t *resp = &err_resp;
30510106SJason.Beloro@Sun.COM int resp_len = 0;
30610106SJason.Beloro@Sun.COM int rv = EINVAL;
30710106SJason.Beloro@Sun.COM
30810106SJason.Beloro@Sun.COM /*
30910106SJason.Beloro@Sun.COM * Sanity check the message
31010106SJason.Beloro@Sun.COM */
31110106SJason.Beloro@Sun.COM if (buflen < sizeof (dr_mem_hdr_t)) {
31210106SJason.Beloro@Sun.COM DR_DBG_MEM("incoming message short: expected at least %ld "
31310106SJason.Beloro@Sun.COM "bytes, received %ld\n", sizeof (dr_mem_hdr_t), buflen);
31410106SJason.Beloro@Sun.COM goto done;
31510106SJason.Beloro@Sun.COM }
31610106SJason.Beloro@Sun.COM
31710106SJason.Beloro@Sun.COM if (req == NULL) {
31810106SJason.Beloro@Sun.COM DR_DBG_MEM("empty message: expected at least %ld bytes\n",
31910106SJason.Beloro@Sun.COM sizeof (dr_mem_hdr_t));
32010106SJason.Beloro@Sun.COM goto done;
32110106SJason.Beloro@Sun.COM }
32210106SJason.Beloro@Sun.COM
32310106SJason.Beloro@Sun.COM DR_DBG_MEM("incoming request:\n");
32410106SJason.Beloro@Sun.COM DR_DBG_DUMP_MSG(buf, buflen);
32510106SJason.Beloro@Sun.COM
32610106SJason.Beloro@Sun.COM /*
32710106SJason.Beloro@Sun.COM * Process the command
32810106SJason.Beloro@Sun.COM */
32910106SJason.Beloro@Sun.COM switch (req->msg_type) {
33010106SJason.Beloro@Sun.COM case DR_MEM_CONFIGURE:
33110106SJason.Beloro@Sun.COM case DR_MEM_UNCONFIGURE:
33210106SJason.Beloro@Sun.COM if (req->msg_arg == 0) {
33310106SJason.Beloro@Sun.COM DR_DBG_MEM("No mblks specified for operation\n");
33410106SJason.Beloro@Sun.COM goto done;
33510106SJason.Beloro@Sun.COM }
33610106SJason.Beloro@Sun.COM if ((rv = dr_mem_list_wrk(req, &resp, &resp_len)) != 0) {
33710106SJason.Beloro@Sun.COM DR_DBG_MEM("%s failed (%d)\n",
33810106SJason.Beloro@Sun.COM (req->msg_type == DR_MEM_CONFIGURE) ?
33910106SJason.Beloro@Sun.COM "Memory configure" : "Memory unconfigure", rv);
34010106SJason.Beloro@Sun.COM }
34110106SJason.Beloro@Sun.COM break;
34210106SJason.Beloro@Sun.COM
34310106SJason.Beloro@Sun.COM case DR_MEM_UNCONF_STATUS:
34410106SJason.Beloro@Sun.COM if ((rv = dr_mem_del_stat(req, &resp, &resp_len)) != 0)
34510106SJason.Beloro@Sun.COM DR_DBG_MEM("Memory delete status failed (%d)\n", rv);
34610106SJason.Beloro@Sun.COM break;
34710106SJason.Beloro@Sun.COM
34810106SJason.Beloro@Sun.COM case DR_MEM_UNCONF_CANCEL:
34910106SJason.Beloro@Sun.COM if ((rv = dr_mem_del_cancel(req, &resp, &resp_len)) != 0)
35010106SJason.Beloro@Sun.COM DR_DBG_MEM("Memory delete cancel failed (%d)\n", rv);
35110106SJason.Beloro@Sun.COM break;
35210106SJason.Beloro@Sun.COM
35310106SJason.Beloro@Sun.COM case DR_MEM_QUERY:
35410106SJason.Beloro@Sun.COM if (req->msg_arg == 0) {
35510106SJason.Beloro@Sun.COM DR_DBG_MEM("No mblks specified for operation\n");
35610106SJason.Beloro@Sun.COM goto done;
35710106SJason.Beloro@Sun.COM }
35810106SJason.Beloro@Sun.COM if ((rv = dr_mem_list_query(req, &resp, &resp_len)) != 0)
35910106SJason.Beloro@Sun.COM DR_DBG_MEM("Memory query failed (%d)\n", rv);
36010106SJason.Beloro@Sun.COM break;
36110106SJason.Beloro@Sun.COM
36210106SJason.Beloro@Sun.COM default:
36310106SJason.Beloro@Sun.COM cmn_err(CE_NOTE, "unsupported memory DR operation (%d)",
36410106SJason.Beloro@Sun.COM req->msg_type);
36510106SJason.Beloro@Sun.COM break;
36610106SJason.Beloro@Sun.COM }
36710106SJason.Beloro@Sun.COM
36810106SJason.Beloro@Sun.COM done:
36910106SJason.Beloro@Sun.COM /* check if an error occurred */
37010106SJason.Beloro@Sun.COM if (resp == &err_resp) {
37110106SJason.Beloro@Sun.COM resp->req_num = (req) ? req->req_num : 0;
37210106SJason.Beloro@Sun.COM resp->msg_type = DR_MEM_ERROR;
37310106SJason.Beloro@Sun.COM resp->msg_arg = rv;
37410106SJason.Beloro@Sun.COM resp_len = sizeof (dr_mem_hdr_t);
37510106SJason.Beloro@Sun.COM }
37610106SJason.Beloro@Sun.COM
37710106SJason.Beloro@Sun.COM DR_DBG_MEM("outgoing response:\n");
37810106SJason.Beloro@Sun.COM DR_DBG_DUMP_MSG(resp, resp_len);
37910106SJason.Beloro@Sun.COM
38010106SJason.Beloro@Sun.COM /* send back the response */
38110106SJason.Beloro@Sun.COM if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
38210106SJason.Beloro@Sun.COM DR_DBG_MEM("ds_send failed\n");
38310106SJason.Beloro@Sun.COM }
38410106SJason.Beloro@Sun.COM
38510106SJason.Beloro@Sun.COM /* free any allocated memory */
38610106SJason.Beloro@Sun.COM if (resp != &err_resp) {
38710106SJason.Beloro@Sun.COM kmem_free(resp, resp_len);
38810106SJason.Beloro@Sun.COM }
38910106SJason.Beloro@Sun.COM }
39010106SJason.Beloro@Sun.COM
391*12260SHaik.Aftandilian@Sun.COM static char *
dr_mem_get_errstr(int result,int subresult)392*12260SHaik.Aftandilian@Sun.COM dr_mem_get_errstr(int result, int subresult)
393*12260SHaik.Aftandilian@Sun.COM {
394*12260SHaik.Aftandilian@Sun.COM size_t len;
395*12260SHaik.Aftandilian@Sun.COM char *errstr;
396*12260SHaik.Aftandilian@Sun.COM const char *separator = ": ";
397*12260SHaik.Aftandilian@Sun.COM
398*12260SHaik.Aftandilian@Sun.COM if (subresult == DR_MEM_SRES_NONE)
399*12260SHaik.Aftandilian@Sun.COM return (i_ddi_strdup(dr_mem_estr[result], KM_SLEEP));
400*12260SHaik.Aftandilian@Sun.COM
401*12260SHaik.Aftandilian@Sun.COM len = snprintf(NULL, 0, "%s%s%s", dr_mem_estr[result],
402*12260SHaik.Aftandilian@Sun.COM separator, dr_mem_estr_detail[subresult]) + 1;
403*12260SHaik.Aftandilian@Sun.COM
404*12260SHaik.Aftandilian@Sun.COM errstr = kmem_alloc(len, KM_SLEEP);
405*12260SHaik.Aftandilian@Sun.COM
406*12260SHaik.Aftandilian@Sun.COM (void) snprintf(errstr, len, "%s%s%s", dr_mem_estr[result],
407*12260SHaik.Aftandilian@Sun.COM separator, dr_mem_estr_detail[subresult]);
408*12260SHaik.Aftandilian@Sun.COM
409*12260SHaik.Aftandilian@Sun.COM return (errstr);
410*12260SHaik.Aftandilian@Sun.COM }
411*12260SHaik.Aftandilian@Sun.COM
41210106SJason.Beloro@Sun.COM /*
41310106SJason.Beloro@Sun.COM * Common routine to config or unconfig multiple mblks.
41410106SJason.Beloro@Sun.COM *
41510106SJason.Beloro@Sun.COM * Note: Do not modify result buffer or length on error.
41610106SJason.Beloro@Sun.COM */
41710106SJason.Beloro@Sun.COM static int
dr_mem_list_wrk(dr_mem_hdr_t * req,dr_mem_hdr_t ** resp,int * resp_len)41810106SJason.Beloro@Sun.COM dr_mem_list_wrk(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
41910106SJason.Beloro@Sun.COM {
42010106SJason.Beloro@Sun.COM int rv;
42110106SJason.Beloro@Sun.COM int idx;
42210106SJason.Beloro@Sun.COM int count;
42310106SJason.Beloro@Sun.COM int result;
424*12260SHaik.Aftandilian@Sun.COM int subresult;
42510106SJason.Beloro@Sun.COM int status;
426*12260SHaik.Aftandilian@Sun.COM boolean_t suspend_allows_dr;
42710106SJason.Beloro@Sun.COM fn_t dr_fn;
42810106SJason.Beloro@Sun.COM int se_hint;
42910106SJason.Beloro@Sun.COM dr_mem_blk_t *req_mblks;
43010106SJason.Beloro@Sun.COM dr_mem_res_t *res;
43110106SJason.Beloro@Sun.COM int drctl_cmd;
43210106SJason.Beloro@Sun.COM int drctl_flags = 0;
43310106SJason.Beloro@Sun.COM drctl_rsrc_t *drctl_req;
43410106SJason.Beloro@Sun.COM size_t drctl_req_len;
43510106SJason.Beloro@Sun.COM drctl_resp_t *drctl_resp;
43610106SJason.Beloro@Sun.COM drctl_rsrc_t *drctl_rsrc;
43710106SJason.Beloro@Sun.COM size_t drctl_resp_len = 0;
43810106SJason.Beloro@Sun.COM drctl_cookie_t drctl_res_ck;
43910106SJason.Beloro@Sun.COM
44010106SJason.Beloro@Sun.COM ASSERT((req != NULL) && (req->msg_arg != 0));
44110106SJason.Beloro@Sun.COM
44210106SJason.Beloro@Sun.COM count = req->msg_arg;
44310106SJason.Beloro@Sun.COM
44410106SJason.Beloro@Sun.COM /*
44510106SJason.Beloro@Sun.COM * Extract all information that is specific
44610106SJason.Beloro@Sun.COM * to the various types of operations.
44710106SJason.Beloro@Sun.COM */
44810106SJason.Beloro@Sun.COM switch (req->msg_type) {
44910106SJason.Beloro@Sun.COM case DR_MEM_CONFIGURE:
45010106SJason.Beloro@Sun.COM dr_fn = dr_mem_configure;
45110106SJason.Beloro@Sun.COM drctl_cmd = DRCTL_MEM_CONFIG_REQUEST;
45210106SJason.Beloro@Sun.COM se_hint = SE_HINT_INSERT;
45310106SJason.Beloro@Sun.COM break;
45410106SJason.Beloro@Sun.COM case DR_MEM_UNCONFIGURE:
45510106SJason.Beloro@Sun.COM dr_fn = dr_mem_unconfigure;
45610106SJason.Beloro@Sun.COM drctl_cmd = DRCTL_MEM_UNCONFIG_REQUEST;
45710106SJason.Beloro@Sun.COM se_hint = SE_HINT_REMOVE;
45810106SJason.Beloro@Sun.COM break;
45910106SJason.Beloro@Sun.COM default:
46010106SJason.Beloro@Sun.COM /* Programming error if we reach this. */
46110106SJason.Beloro@Sun.COM cmn_err(CE_NOTE, "%s: bad msg_type %d\n",
46210106SJason.Beloro@Sun.COM __func__, req->msg_type);
46310106SJason.Beloro@Sun.COM ASSERT(0);
46410106SJason.Beloro@Sun.COM return (-1);
46510106SJason.Beloro@Sun.COM }
46610106SJason.Beloro@Sun.COM
46710106SJason.Beloro@Sun.COM /* the incoming array of mblks to operate on */
46810106SJason.Beloro@Sun.COM req_mblks = DR_MEM_CMD_MBLKS(req);
46910106SJason.Beloro@Sun.COM
47010106SJason.Beloro@Sun.COM /* allocate drctl request msg based on incoming resource count */
47110106SJason.Beloro@Sun.COM drctl_req_len = sizeof (drctl_rsrc_t) * count;
47210106SJason.Beloro@Sun.COM drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
47310106SJason.Beloro@Sun.COM
47410106SJason.Beloro@Sun.COM /* copy the size for the drctl call from the incoming request msg */
47510106SJason.Beloro@Sun.COM for (idx = 0; idx < count; idx++) {
47610106SJason.Beloro@Sun.COM drctl_req[idx].res_mem_addr = req_mblks[idx].addr;
47710106SJason.Beloro@Sun.COM drctl_req[idx].res_mem_size = req_mblks[idx].size;
47810106SJason.Beloro@Sun.COM }
47910106SJason.Beloro@Sun.COM
48010106SJason.Beloro@Sun.COM rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
48110106SJason.Beloro@Sun.COM count, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
48210106SJason.Beloro@Sun.COM
48310106SJason.Beloro@Sun.COM ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
48410106SJason.Beloro@Sun.COM
48510106SJason.Beloro@Sun.COM if (rv != 0) {
48610106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: drctl_config_init returned: %d\n",
48710106SJason.Beloro@Sun.COM __func__, rv);
48810106SJason.Beloro@Sun.COM kmem_free(drctl_resp, drctl_resp_len);
48910106SJason.Beloro@Sun.COM kmem_free(drctl_req, drctl_req_len);
49010106SJason.Beloro@Sun.COM return (rv);
49110106SJason.Beloro@Sun.COM }
49210106SJason.Beloro@Sun.COM
49310106SJason.Beloro@Sun.COM ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
49410106SJason.Beloro@Sun.COM
49510106SJason.Beloro@Sun.COM drctl_rsrc = drctl_resp->resp_resources;
49610106SJason.Beloro@Sun.COM
49710106SJason.Beloro@Sun.COM /* create the result scratch array */
49810106SJason.Beloro@Sun.COM res = dr_mem_res_array_init(req, drctl_rsrc, count);
49910106SJason.Beloro@Sun.COM
500*12260SHaik.Aftandilian@Sun.COM /*
501*12260SHaik.Aftandilian@Sun.COM * Memory DR operations are not safe if we have been suspended and
502*12260SHaik.Aftandilian@Sun.COM * resumed. Until this limitation is lifted, check to see if memory
503*12260SHaik.Aftandilian@Sun.COM * DR operations are permitted at this time by the suspend subsystem.
504*12260SHaik.Aftandilian@Sun.COM */
505*12260SHaik.Aftandilian@Sun.COM if ((suspend_allows_dr = suspend_memdr_allowed()) == B_FALSE) {
506*12260SHaik.Aftandilian@Sun.COM result = DR_MEM_RES_BLOCKED;
507*12260SHaik.Aftandilian@Sun.COM subresult = DR_MEM_SRES_OS_SUSPENDED;
508*12260SHaik.Aftandilian@Sun.COM } else {
509*12260SHaik.Aftandilian@Sun.COM subresult = DR_MEM_SRES_NONE;
510*12260SHaik.Aftandilian@Sun.COM }
511*12260SHaik.Aftandilian@Sun.COM
51210106SJason.Beloro@Sun.COM /* perform the specified operation on each of the mblks */
51310106SJason.Beloro@Sun.COM for (idx = 0; idx < count; idx++) {
51410106SJason.Beloro@Sun.COM /*
51510106SJason.Beloro@Sun.COM * If no action will be taken against the current
51610106SJason.Beloro@Sun.COM * mblk, update the drctl resource information to
51710106SJason.Beloro@Sun.COM * ensure that it gets recovered properly during
51810106SJason.Beloro@Sun.COM * the drctl fini() call.
51910106SJason.Beloro@Sun.COM */
52010106SJason.Beloro@Sun.COM if (res[idx].result != DR_MEM_RES_OK) {
52110106SJason.Beloro@Sun.COM drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
52210106SJason.Beloro@Sun.COM continue;
52310106SJason.Beloro@Sun.COM }
52410106SJason.Beloro@Sun.COM
525*12260SHaik.Aftandilian@Sun.COM /*
526*12260SHaik.Aftandilian@Sun.COM * If memory DR operations are permitted at this time by
527*12260SHaik.Aftandilian@Sun.COM * the suspend subsystem, call the function to perform the
528*12260SHaik.Aftandilian@Sun.COM * operation, otherwise return a result indicating that the
529*12260SHaik.Aftandilian@Sun.COM * operation was blocked.
530*12260SHaik.Aftandilian@Sun.COM */
531*12260SHaik.Aftandilian@Sun.COM if (suspend_allows_dr)
532*12260SHaik.Aftandilian@Sun.COM result = (*dr_fn)(&req_mblks[idx], &status);
53310106SJason.Beloro@Sun.COM
53410106SJason.Beloro@Sun.COM /* save off results of the operation */
53510106SJason.Beloro@Sun.COM res[idx].result = result;
53610106SJason.Beloro@Sun.COM res[idx].status = status;
53710106SJason.Beloro@Sun.COM res[idx].addr = req_mblks[idx].addr; /* for partial case */
53810106SJason.Beloro@Sun.COM res[idx].size = req_mblks[idx].size; /* for partial case */
539*12260SHaik.Aftandilian@Sun.COM res[idx].string = dr_mem_get_errstr(result, subresult);
54010106SJason.Beloro@Sun.COM
54110106SJason.Beloro@Sun.COM /* save result for drctl fini() reusing init() msg memory */
54210106SJason.Beloro@Sun.COM drctl_req[idx].status = (result != DR_MEM_RES_OK) ?
54310106SJason.Beloro@Sun.COM DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
54410106SJason.Beloro@Sun.COM
54510106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: mblk 0x%lx.0x%lx stat %d result %d off '%s'\n",
54610106SJason.Beloro@Sun.COM __func__, req_mblks[idx].addr, req_mblks[idx].size,
54710106SJason.Beloro@Sun.COM drctl_req[idx].status, result,
54810106SJason.Beloro@Sun.COM (res[idx].string) ? res[idx].string : "");
54910106SJason.Beloro@Sun.COM }
55010106SJason.Beloro@Sun.COM
55110106SJason.Beloro@Sun.COM if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
55210106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: drctl_config_fini returned: %d\n",
55310106SJason.Beloro@Sun.COM __func__, rv);
55410106SJason.Beloro@Sun.COM
55510106SJason.Beloro@Sun.COM /*
55610106SJason.Beloro@Sun.COM * Operation completed without any fatal errors.
55710106SJason.Beloro@Sun.COM * Pack the response for transmission.
55810106SJason.Beloro@Sun.COM */
55910106SJason.Beloro@Sun.COM *resp_len = dr_mem_pack_response(req, res, resp);
56010106SJason.Beloro@Sun.COM
56110106SJason.Beloro@Sun.COM /* notify interested parties about the operation */
56210106SJason.Beloro@Sun.COM dr_generate_event(DR_TYPE_MEM, se_hint);
56310106SJason.Beloro@Sun.COM
56410106SJason.Beloro@Sun.COM /*
56510106SJason.Beloro@Sun.COM * Deallocate any scratch memory.
56610106SJason.Beloro@Sun.COM */
56710106SJason.Beloro@Sun.COM kmem_free(drctl_resp, drctl_resp_len);
56810106SJason.Beloro@Sun.COM kmem_free(drctl_req, drctl_req_len);
56910106SJason.Beloro@Sun.COM
57010106SJason.Beloro@Sun.COM dr_mem_res_array_fini(res, count);
57110106SJason.Beloro@Sun.COM
57210106SJason.Beloro@Sun.COM return (0);
57310106SJason.Beloro@Sun.COM }
57410106SJason.Beloro@Sun.COM
57510106SJason.Beloro@Sun.COM /*
57610106SJason.Beloro@Sun.COM * Allocate and initialize a result array based on the initial
57710106SJason.Beloro@Sun.COM * drctl operation. A valid result array is always returned.
57810106SJason.Beloro@Sun.COM */
57910106SJason.Beloro@Sun.COM static dr_mem_res_t *
dr_mem_res_array_init(dr_mem_hdr_t * req,drctl_rsrc_t * rsrc,int nrsrc)58010106SJason.Beloro@Sun.COM dr_mem_res_array_init(dr_mem_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
58110106SJason.Beloro@Sun.COM {
58210106SJason.Beloro@Sun.COM int idx;
58310106SJason.Beloro@Sun.COM dr_mem_res_t *res;
58410106SJason.Beloro@Sun.COM char *err_str;
58510106SJason.Beloro@Sun.COM size_t err_len;
58610106SJason.Beloro@Sun.COM
58710106SJason.Beloro@Sun.COM /* allocate zero filled buffer to initialize fields */
58810106SJason.Beloro@Sun.COM res = kmem_zalloc(nrsrc * sizeof (dr_mem_res_t), KM_SLEEP);
58910106SJason.Beloro@Sun.COM
59010106SJason.Beloro@Sun.COM /*
59110106SJason.Beloro@Sun.COM * Fill in the result information for each resource.
59210106SJason.Beloro@Sun.COM */
59310106SJason.Beloro@Sun.COM for (idx = 0; idx < nrsrc; idx++) {
59410106SJason.Beloro@Sun.COM res[idx].addr = rsrc[idx].res_mem_addr;
59510106SJason.Beloro@Sun.COM res[idx].size = rsrc[idx].res_mem_size;
59610106SJason.Beloro@Sun.COM res[idx].result = DR_MEM_RES_OK;
59710106SJason.Beloro@Sun.COM
59810106SJason.Beloro@Sun.COM if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
59910106SJason.Beloro@Sun.COM continue;
60010106SJason.Beloro@Sun.COM
60110106SJason.Beloro@Sun.COM /*
60210106SJason.Beloro@Sun.COM * Update the state information for this mblk.
60310106SJason.Beloro@Sun.COM */
60410106SJason.Beloro@Sun.COM res[idx].result = DR_MEM_RES_BLOCKED;
60510106SJason.Beloro@Sun.COM res[idx].status = (req->msg_type == DR_MEM_CONFIGURE) ?
60610106SJason.Beloro@Sun.COM DR_MEM_STAT_UNCONFIGURED : DR_MEM_STAT_CONFIGURED;
60710106SJason.Beloro@Sun.COM
60810106SJason.Beloro@Sun.COM /*
60910106SJason.Beloro@Sun.COM * If an error string exists, copy it out of the
61010106SJason.Beloro@Sun.COM * message buffer. This eliminates any dependency
61110106SJason.Beloro@Sun.COM * on the memory allocated for the message buffer
61210106SJason.Beloro@Sun.COM * itself.
61310106SJason.Beloro@Sun.COM */
61410106SJason.Beloro@Sun.COM if (rsrc[idx].offset != NULL) {
61510106SJason.Beloro@Sun.COM err_str = (char *)rsrc + rsrc[idx].offset;
61610106SJason.Beloro@Sun.COM err_len = strlen(err_str) + 1;
61710106SJason.Beloro@Sun.COM
61810106SJason.Beloro@Sun.COM res[idx].string = kmem_alloc(err_len, KM_SLEEP);
61910106SJason.Beloro@Sun.COM bcopy(err_str, res[idx].string, err_len);
62010106SJason.Beloro@Sun.COM }
62110106SJason.Beloro@Sun.COM }
62210106SJason.Beloro@Sun.COM
62310106SJason.Beloro@Sun.COM return (res);
62410106SJason.Beloro@Sun.COM }
62510106SJason.Beloro@Sun.COM
62610106SJason.Beloro@Sun.COM static void
dr_mem_res_array_fini(dr_mem_res_t * res,int nres)62710106SJason.Beloro@Sun.COM dr_mem_res_array_fini(dr_mem_res_t *res, int nres)
62810106SJason.Beloro@Sun.COM {
62910106SJason.Beloro@Sun.COM int idx;
63010106SJason.Beloro@Sun.COM size_t str_len;
63110106SJason.Beloro@Sun.COM
63210106SJason.Beloro@Sun.COM for (idx = 0; idx < nres; idx++) {
63310106SJason.Beloro@Sun.COM /* deallocate the error string if present */
63410106SJason.Beloro@Sun.COM if (res[idx].string) {
63510106SJason.Beloro@Sun.COM str_len = strlen(res[idx].string) + 1;
63610106SJason.Beloro@Sun.COM kmem_free(res[idx].string, str_len);
63710106SJason.Beloro@Sun.COM }
63810106SJason.Beloro@Sun.COM }
63910106SJason.Beloro@Sun.COM
64010106SJason.Beloro@Sun.COM /* deallocate the result array itself */
64110106SJason.Beloro@Sun.COM kmem_free(res, sizeof (dr_mem_res_t) * nres);
64210106SJason.Beloro@Sun.COM }
64310106SJason.Beloro@Sun.COM
64410106SJason.Beloro@Sun.COM /*
64510106SJason.Beloro@Sun.COM * Allocate and pack a response message for transmission based
64610106SJason.Beloro@Sun.COM * on the specified result array. A valid response message and
64710106SJason.Beloro@Sun.COM * valid size information is always returned.
64810106SJason.Beloro@Sun.COM */
64910106SJason.Beloro@Sun.COM static size_t
dr_mem_pack_response(dr_mem_hdr_t * req,dr_mem_res_t * res,dr_mem_hdr_t ** respp)65010106SJason.Beloro@Sun.COM dr_mem_pack_response(dr_mem_hdr_t *req, dr_mem_res_t *res, dr_mem_hdr_t **respp)
65110106SJason.Beloro@Sun.COM {
65210106SJason.Beloro@Sun.COM int idx;
65310106SJason.Beloro@Sun.COM dr_mem_hdr_t *resp;
65410106SJason.Beloro@Sun.COM dr_mem_stat_t *resp_stat;
65510106SJason.Beloro@Sun.COM size_t resp_len;
65610106SJason.Beloro@Sun.COM uint32_t curr_off;
65710106SJason.Beloro@Sun.COM caddr_t curr_str;
65810106SJason.Beloro@Sun.COM size_t str_len;
65910106SJason.Beloro@Sun.COM size_t stat_len;
66010106SJason.Beloro@Sun.COM int nstat = req->msg_arg;
66110106SJason.Beloro@Sun.COM
66210106SJason.Beloro@Sun.COM /*
66310106SJason.Beloro@Sun.COM * Calculate the size of the response message
66410106SJason.Beloro@Sun.COM * and allocate an appropriately sized buffer.
66510106SJason.Beloro@Sun.COM */
66610106SJason.Beloro@Sun.COM resp_len = sizeof (dr_mem_hdr_t);
66710106SJason.Beloro@Sun.COM
66810106SJason.Beloro@Sun.COM /* add the stat array size */
66910106SJason.Beloro@Sun.COM stat_len = sizeof (dr_mem_stat_t) * nstat;
67010106SJason.Beloro@Sun.COM resp_len += stat_len;
67110106SJason.Beloro@Sun.COM
67210106SJason.Beloro@Sun.COM /* add the size of any error strings */
67310106SJason.Beloro@Sun.COM for (idx = 0; idx < nstat; idx++) {
67410106SJason.Beloro@Sun.COM if (res[idx].string != NULL) {
67510106SJason.Beloro@Sun.COM resp_len += strlen(res[idx].string) + 1;
67610106SJason.Beloro@Sun.COM }
67710106SJason.Beloro@Sun.COM }
67810106SJason.Beloro@Sun.COM
67910106SJason.Beloro@Sun.COM /* allocate the message buffer */
68010106SJason.Beloro@Sun.COM resp = kmem_zalloc(resp_len, KM_SLEEP);
68110106SJason.Beloro@Sun.COM
68210106SJason.Beloro@Sun.COM /*
68310106SJason.Beloro@Sun.COM * Fill in the header information.
68410106SJason.Beloro@Sun.COM */
68510106SJason.Beloro@Sun.COM resp->req_num = req->req_num;
68610106SJason.Beloro@Sun.COM resp->msg_type = DR_MEM_OK;
68710106SJason.Beloro@Sun.COM resp->msg_arg = nstat;
68810106SJason.Beloro@Sun.COM
68910106SJason.Beloro@Sun.COM /*
69010106SJason.Beloro@Sun.COM * Fill in the stat information.
69110106SJason.Beloro@Sun.COM */
69210106SJason.Beloro@Sun.COM resp_stat = DR_MEM_RESP_STATS(resp);
69310106SJason.Beloro@Sun.COM
69410106SJason.Beloro@Sun.COM /* string offsets start immediately after stat array */
69510106SJason.Beloro@Sun.COM curr_off = sizeof (dr_mem_hdr_t) + stat_len;
69610106SJason.Beloro@Sun.COM curr_str = (char *)resp_stat + stat_len;
69710106SJason.Beloro@Sun.COM
69810106SJason.Beloro@Sun.COM for (idx = 0; idx < nstat; idx++) {
69910106SJason.Beloro@Sun.COM resp_stat[idx].addr = res[idx].addr;
70010106SJason.Beloro@Sun.COM resp_stat[idx].size = res[idx].size;
70110106SJason.Beloro@Sun.COM resp_stat[idx].result = res[idx].result;
70210106SJason.Beloro@Sun.COM resp_stat[idx].status = res[idx].status;
70310106SJason.Beloro@Sun.COM
70410106SJason.Beloro@Sun.COM if (res[idx].string != NULL) {
70510106SJason.Beloro@Sun.COM /* copy over the error string */
70610106SJason.Beloro@Sun.COM str_len = strlen(res[idx].string) + 1;
70710106SJason.Beloro@Sun.COM bcopy(res[idx].string, curr_str, str_len);
70810106SJason.Beloro@Sun.COM resp_stat[idx].string_off = curr_off;
70910106SJason.Beloro@Sun.COM
71010106SJason.Beloro@Sun.COM curr_off += str_len;
71110106SJason.Beloro@Sun.COM curr_str += str_len;
71210106SJason.Beloro@Sun.COM }
71310106SJason.Beloro@Sun.COM }
71410106SJason.Beloro@Sun.COM
71510106SJason.Beloro@Sun.COM /* buffer should be exactly filled */
71610106SJason.Beloro@Sun.COM ASSERT(curr_off == resp_len);
71710106SJason.Beloro@Sun.COM
71810106SJason.Beloro@Sun.COM *respp = resp;
71910106SJason.Beloro@Sun.COM return (resp_len);
72010106SJason.Beloro@Sun.COM }
72110106SJason.Beloro@Sun.COM
72210106SJason.Beloro@Sun.COM static void
dr_mem_query(dr_mem_blk_t * mbp,dr_mem_query_t * mqp)72310106SJason.Beloro@Sun.COM dr_mem_query(dr_mem_blk_t *mbp, dr_mem_query_t *mqp)
72410106SJason.Beloro@Sun.COM {
72510106SJason.Beloro@Sun.COM memquery_t mq;
72610106SJason.Beloro@Sun.COM
72710106SJason.Beloro@Sun.COM DR_DBG_MEM("dr_mem_query...\n");
72810106SJason.Beloro@Sun.COM
72910106SJason.Beloro@Sun.COM
73010106SJason.Beloro@Sun.COM (void) kphysm_del_span_query(btop(mbp->addr), btop(mbp->size), &mq);
73110106SJason.Beloro@Sun.COM
73210106SJason.Beloro@Sun.COM if (!mq.phys_pages)
73310106SJason.Beloro@Sun.COM return;
73410106SJason.Beloro@Sun.COM
73510106SJason.Beloro@Sun.COM mqp->addr = mbp->addr;
73610106SJason.Beloro@Sun.COM mqp->mq.phys_pages = ptob(mq.phys_pages);
73710106SJason.Beloro@Sun.COM mqp->mq.managed = ptob(mq.managed);
73810106SJason.Beloro@Sun.COM mqp->mq.nonrelocatable = ptob(mq.nonrelocatable);
73910106SJason.Beloro@Sun.COM mqp->mq.first_nonrelocatable = ptob(mq.first_nonrelocatable);
74010106SJason.Beloro@Sun.COM mqp->mq.last_nonrelocatable = ptob(mq.last_nonrelocatable);
74110106SJason.Beloro@Sun.COM /*
74210106SJason.Beloro@Sun.COM * Set to the max byte offset within the page.
74310106SJason.Beloro@Sun.COM */
74410106SJason.Beloro@Sun.COM if (mqp->mq.nonrelocatable)
74510106SJason.Beloro@Sun.COM mqp->mq.last_nonrelocatable += PAGESIZE - 1;
74610106SJason.Beloro@Sun.COM }
74710106SJason.Beloro@Sun.COM
74810106SJason.Beloro@Sun.COM /*
74910106SJason.Beloro@Sun.COM * Do not modify result buffer or length on error.
75010106SJason.Beloro@Sun.COM */
75110106SJason.Beloro@Sun.COM static int
dr_mem_list_query(dr_mem_hdr_t * req,dr_mem_hdr_t ** resp,int * resp_len)75210106SJason.Beloro@Sun.COM dr_mem_list_query(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
75310106SJason.Beloro@Sun.COM {
75410106SJason.Beloro@Sun.COM int idx;
75510106SJason.Beloro@Sun.COM int rlen;
75610106SJason.Beloro@Sun.COM int nml;
75710106SJason.Beloro@Sun.COM struct memlist *ml;
75812037SSean.McEnroe@Sun.COM struct memlist *phys_copy = NULL;
75910106SJason.Beloro@Sun.COM dr_mem_blk_t *req_mblks, mb;
76010106SJason.Beloro@Sun.COM dr_mem_hdr_t *rp;
76110106SJason.Beloro@Sun.COM dr_mem_query_t *stat;
76210106SJason.Beloro@Sun.COM
76311185SSean.McEnroe@Sun.COM drctl_block();
76411185SSean.McEnroe@Sun.COM
76510106SJason.Beloro@Sun.COM /* the incoming array of req_mblks to configure */
76610106SJason.Beloro@Sun.COM req_mblks = DR_MEM_CMD_MBLKS(req);
76710106SJason.Beloro@Sun.COM
76810106SJason.Beloro@Sun.COM /* allocate a response message, should be freed by caller */
76910106SJason.Beloro@Sun.COM nml = 0;
77010106SJason.Beloro@Sun.COM rlen = sizeof (dr_mem_hdr_t);
77110106SJason.Beloro@Sun.COM if (req_mblks->addr == NULL && req_mblks->size == 0) {
77210106SJason.Beloro@Sun.COM /*
77310106SJason.Beloro@Sun.COM * Request is for domain's full view of it's memory.
77412037SSean.McEnroe@Sun.COM * place a copy in phys_copy then release the memlist lock.
77510106SJason.Beloro@Sun.COM */
77610106SJason.Beloro@Sun.COM memlist_read_lock();
77712037SSean.McEnroe@Sun.COM phys_copy = dr_memlist_dup(phys_install);
77812037SSean.McEnroe@Sun.COM memlist_read_unlock();
77912037SSean.McEnroe@Sun.COM
78012037SSean.McEnroe@Sun.COM for (ml = phys_copy; ml; ml = ml->ml_next)
78110106SJason.Beloro@Sun.COM nml++;
78210106SJason.Beloro@Sun.COM
78310106SJason.Beloro@Sun.COM rlen += nml * sizeof (dr_mem_query_t);
78410106SJason.Beloro@Sun.COM } else {
78510106SJason.Beloro@Sun.COM rlen += req->msg_arg * sizeof (dr_mem_query_t);
78610106SJason.Beloro@Sun.COM }
78710106SJason.Beloro@Sun.COM rp = kmem_zalloc(rlen, KM_SLEEP);
78810106SJason.Beloro@Sun.COM
78910106SJason.Beloro@Sun.COM /* fill in the known data */
79010106SJason.Beloro@Sun.COM rp->req_num = req->req_num;
79110106SJason.Beloro@Sun.COM rp->msg_type = DR_MEM_OK;
79210106SJason.Beloro@Sun.COM rp->msg_arg = nml ? nml : req->msg_arg;
79310106SJason.Beloro@Sun.COM
79410106SJason.Beloro@Sun.COM /* stat array for the response */
79510106SJason.Beloro@Sun.COM stat = DR_MEM_RESP_QUERY(rp);
79610106SJason.Beloro@Sun.COM
79710106SJason.Beloro@Sun.COM /* get the status for each of the mblocks */
79810106SJason.Beloro@Sun.COM if (nml) {
79912037SSean.McEnroe@Sun.COM for (idx = 0, ml = phys_copy; ml; ml = ml->ml_next, idx++) {
80011474SJonathan.Adams@Sun.COM mb.addr = ml->ml_address;
80111474SJonathan.Adams@Sun.COM mb.size = ml->ml_size;
80210106SJason.Beloro@Sun.COM dr_mem_query(&mb, &stat[idx]);
80310106SJason.Beloro@Sun.COM }
80410106SJason.Beloro@Sun.COM } else {
80510106SJason.Beloro@Sun.COM for (idx = 0; idx < req->msg_arg; idx++)
80610106SJason.Beloro@Sun.COM dr_mem_query(&req_mblks[idx], &stat[idx]);
80710106SJason.Beloro@Sun.COM }
80810106SJason.Beloro@Sun.COM
80910106SJason.Beloro@Sun.COM *resp = rp;
81010106SJason.Beloro@Sun.COM *resp_len = rlen;
81112037SSean.McEnroe@Sun.COM if (phys_copy != NULL) {
81212037SSean.McEnroe@Sun.COM dr_memlist_delete(phys_copy);
81312037SSean.McEnroe@Sun.COM }
81411185SSean.McEnroe@Sun.COM drctl_unblock();
81511185SSean.McEnroe@Sun.COM
81610106SJason.Beloro@Sun.COM return (0);
81710106SJason.Beloro@Sun.COM }
81810106SJason.Beloro@Sun.COM
81910106SJason.Beloro@Sun.COM static int
cvt_err(int err)82010106SJason.Beloro@Sun.COM cvt_err(int err)
82110106SJason.Beloro@Sun.COM {
82210106SJason.Beloro@Sun.COM int rv;
82310106SJason.Beloro@Sun.COM
82410106SJason.Beloro@Sun.COM switch (err) {
82510106SJason.Beloro@Sun.COM case KPHYSM_OK:
82610106SJason.Beloro@Sun.COM rv = DR_MEM_RES_OK;
82710106SJason.Beloro@Sun.COM break;
82810106SJason.Beloro@Sun.COM case KPHYSM_ESPAN:
82910106SJason.Beloro@Sun.COM rv = DR_MEM_RES_ESPAN;
83010106SJason.Beloro@Sun.COM break;
83110106SJason.Beloro@Sun.COM case KPHYSM_EFAULT:
83210106SJason.Beloro@Sun.COM rv = DR_MEM_RES_EFAULT;
83310106SJason.Beloro@Sun.COM break;
83410106SJason.Beloro@Sun.COM case KPHYSM_ERESOURCE:
83510106SJason.Beloro@Sun.COM rv = DR_MEM_RES_ERESOURCE;
83610106SJason.Beloro@Sun.COM break;
83710106SJason.Beloro@Sun.COM case KPHYSM_ENOTSUP:
83810106SJason.Beloro@Sun.COM case KPHYSM_ENOHANDLES:
83910106SJason.Beloro@Sun.COM rv = DR_MEM_RES_FAILURE;
84010106SJason.Beloro@Sun.COM break;
84110106SJason.Beloro@Sun.COM case KPHYSM_ENONRELOC:
84210106SJason.Beloro@Sun.COM rv = DR_MEM_RES_PERM;
84310106SJason.Beloro@Sun.COM break;
84410106SJason.Beloro@Sun.COM case KPHYSM_EHANDLE:
84510106SJason.Beloro@Sun.COM rv = DR_MEM_RES_FAILURE;
84610106SJason.Beloro@Sun.COM break;
84710106SJason.Beloro@Sun.COM case KPHYSM_EBUSY:
84810106SJason.Beloro@Sun.COM rv = DR_MEM_RES_EBUSY;
84910106SJason.Beloro@Sun.COM break;
85010106SJason.Beloro@Sun.COM case KPHYSM_ENOTVIABLE:
85110106SJason.Beloro@Sun.COM rv = DR_MEM_RES_ENOTVIABLE;
85210106SJason.Beloro@Sun.COM break;
85310106SJason.Beloro@Sun.COM case KPHYSM_ESEQUENCE:
85410106SJason.Beloro@Sun.COM rv = DR_MEM_RES_FAILURE;
85510106SJason.Beloro@Sun.COM break;
85610106SJason.Beloro@Sun.COM case KPHYSM_ENOWORK:
85710106SJason.Beloro@Sun.COM rv = DR_MEM_RES_ENOWORK;
85810106SJason.Beloro@Sun.COM break;
85910106SJason.Beloro@Sun.COM case KPHYSM_ECANCELLED:
86010106SJason.Beloro@Sun.COM rv = DR_MEM_RES_ECANCELLED;
86110106SJason.Beloro@Sun.COM break;
86210106SJason.Beloro@Sun.COM case KPHYSM_EREFUSED:
86310106SJason.Beloro@Sun.COM rv = DR_MEM_RES_EREFUSED;
86410106SJason.Beloro@Sun.COM break;
86510106SJason.Beloro@Sun.COM case KPHYSM_ENOTFINISHED:
86610106SJason.Beloro@Sun.COM case KPHYSM_ENOTRUNNING:
86710106SJason.Beloro@Sun.COM rv = DR_MEM_RES_FAILURE;
86810106SJason.Beloro@Sun.COM break;
86910106SJason.Beloro@Sun.COM case KPHYSM_EDUP:
87010106SJason.Beloro@Sun.COM rv = DR_MEM_RES_EDUP;
87110106SJason.Beloro@Sun.COM break;
87210106SJason.Beloro@Sun.COM default:
87310106SJason.Beloro@Sun.COM rv = DR_MEM_RES_FAILURE;
87410106SJason.Beloro@Sun.COM break;
87510106SJason.Beloro@Sun.COM }
87610106SJason.Beloro@Sun.COM
87710106SJason.Beloro@Sun.COM return (rv);
87810106SJason.Beloro@Sun.COM }
87910106SJason.Beloro@Sun.COM
88010106SJason.Beloro@Sun.COM static int
dr_mem_configure(dr_mem_blk_t * mbp,int * status)88110106SJason.Beloro@Sun.COM dr_mem_configure(dr_mem_blk_t *mbp, int *status)
88210106SJason.Beloro@Sun.COM {
88310106SJason.Beloro@Sun.COM int rv;
88411185SSean.McEnroe@Sun.COM uint64_t addr, size;
88510106SJason.Beloro@Sun.COM
88610106SJason.Beloro@Sun.COM rv = 0;
88710106SJason.Beloro@Sun.COM addr = mbp->addr;
88810106SJason.Beloro@Sun.COM size = mbp->size;
88910106SJason.Beloro@Sun.COM
89010106SJason.Beloro@Sun.COM DR_DBG_MEM("dr_mem_configure...\n");
89110106SJason.Beloro@Sun.COM
89210106SJason.Beloro@Sun.COM if (!MBLK_IS_VALID(mbp)) {
89310106SJason.Beloro@Sun.COM DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n", addr, size);
89410106SJason.Beloro@Sun.COM *status = DR_MEM_STAT_UNCONFIGURED;
89510106SJason.Beloro@Sun.COM rv = DR_MEM_RES_EINVAL;
89610106SJason.Beloro@Sun.COM } else if (rv = dr_mem_find(mbp)) {
89710106SJason.Beloro@Sun.COM DR_DBG_MEM("failed to find mblk 0x%lx.0x%lx (%d)\n",
89810106SJason.Beloro@Sun.COM addr, size, rv);
89910106SJason.Beloro@Sun.COM if (rv == EINVAL) {
90010106SJason.Beloro@Sun.COM *status = DR_MEM_STAT_NOT_PRESENT;
90110106SJason.Beloro@Sun.COM rv = DR_MEM_RES_NOT_IN_MD;
90210106SJason.Beloro@Sun.COM } else {
90310106SJason.Beloro@Sun.COM *status = DR_MEM_STAT_UNCONFIGURED;
90410106SJason.Beloro@Sun.COM rv = DR_MEM_RES_FAILURE;
90510106SJason.Beloro@Sun.COM }
90610106SJason.Beloro@Sun.COM } else {
90710106SJason.Beloro@Sun.COM rv = mem_add(btop(addr), btop(size));
90810106SJason.Beloro@Sun.COM DR_DBG_MEM("addr=0x%lx size=0x%lx rv=%d\n", addr, size, rv);
90910106SJason.Beloro@Sun.COM if (rv) {
91010106SJason.Beloro@Sun.COM *status = DR_MEM_STAT_UNCONFIGURED;
91110106SJason.Beloro@Sun.COM } else {
91210106SJason.Beloro@Sun.COM *status = DR_MEM_STAT_CONFIGURED;
91310106SJason.Beloro@Sun.COM }
91410106SJason.Beloro@Sun.COM }
91510106SJason.Beloro@Sun.COM
91610106SJason.Beloro@Sun.COM return (rv);
91710106SJason.Beloro@Sun.COM }
91810106SJason.Beloro@Sun.COM
91910106SJason.Beloro@Sun.COM static int
dr_mem_unconfigure(dr_mem_blk_t * mbp,int * status)92010106SJason.Beloro@Sun.COM dr_mem_unconfigure(dr_mem_blk_t *mbp, int *status)
92110106SJason.Beloro@Sun.COM {
92210106SJason.Beloro@Sun.COM int rv;
92310106SJason.Beloro@Sun.COM
92410106SJason.Beloro@Sun.COM DR_DBG_MEM("dr_mem_unconfigure...\n");
92510106SJason.Beloro@Sun.COM
92610106SJason.Beloro@Sun.COM if (!MBLK_IS_VALID(mbp)) {
92710106SJason.Beloro@Sun.COM DR_DBG_MEM("invalid mblk 0x%lx.0x%lx\n",
92810106SJason.Beloro@Sun.COM mbp->addr, mbp->size);
92910106SJason.Beloro@Sun.COM *status = DR_MEM_STAT_CONFIGURED;
93010106SJason.Beloro@Sun.COM rv = DR_MEM_RES_EINVAL;
93110106SJason.Beloro@Sun.COM } else if (rv = mem_del(btop(mbp->addr), btop(mbp->size))) {
93210106SJason.Beloro@Sun.COM *status = DR_MEM_STAT_CONFIGURED;
93310106SJason.Beloro@Sun.COM } else {
93410106SJason.Beloro@Sun.COM *status = DR_MEM_STAT_UNCONFIGURED;
93510106SJason.Beloro@Sun.COM rv = DR_MEM_RES_OK;
93610106SJason.Beloro@Sun.COM DR_DBG_MEM("mblk 0x%lx.0x%lx unconfigured\n",
93710106SJason.Beloro@Sun.COM mbp->addr, mbp->size);
93810106SJason.Beloro@Sun.COM }
93910106SJason.Beloro@Sun.COM return (rv);
94010106SJason.Beloro@Sun.COM }
94110106SJason.Beloro@Sun.COM
94210106SJason.Beloro@Sun.COM static int
dr_mem_del_stat(dr_mem_hdr_t * req,dr_mem_hdr_t ** resp,int * resp_len)94310106SJason.Beloro@Sun.COM dr_mem_del_stat(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
94410106SJason.Beloro@Sun.COM {
94510106SJason.Beloro@Sun.COM int status;
94610106SJason.Beloro@Sun.COM int rlen;
94710106SJason.Beloro@Sun.COM memdelstat_t del_stat, *stat;
94810106SJason.Beloro@Sun.COM dr_mem_hdr_t *rp;
94910106SJason.Beloro@Sun.COM
95010106SJason.Beloro@Sun.COM /*
95110106SJason.Beloro@Sun.COM * If a mem delete is in progress, get its status.
95210106SJason.Beloro@Sun.COM */
95310106SJason.Beloro@Sun.COM status = (dr_mh && (kphysm_del_status(dr_mh, &del_stat) == KPHYSM_OK));
95410106SJason.Beloro@Sun.COM
95510106SJason.Beloro@Sun.COM /* allocate a response message, should be freed by caller */
95610106SJason.Beloro@Sun.COM rlen = sizeof (dr_mem_hdr_t);
95710106SJason.Beloro@Sun.COM rlen += status * sizeof (memdelstat_t);
95810106SJason.Beloro@Sun.COM rp = kmem_zalloc(rlen, KM_SLEEP);
95910106SJason.Beloro@Sun.COM
96010106SJason.Beloro@Sun.COM /* fill in the known data */
96110106SJason.Beloro@Sun.COM rp->req_num = req->req_num;
96210106SJason.Beloro@Sun.COM rp->msg_type = DR_MEM_OK;
96310106SJason.Beloro@Sun.COM rp->msg_arg = status;
96410106SJason.Beloro@Sun.COM
96510106SJason.Beloro@Sun.COM if (status) {
96610106SJason.Beloro@Sun.COM /* stat struct for the response */
96710106SJason.Beloro@Sun.COM stat = DR_MEM_RESP_DEL_STAT(rp);
96810106SJason.Beloro@Sun.COM stat->phys_pages = ptob(del_stat.phys_pages);
96910106SJason.Beloro@Sun.COM stat->managed = ptob(del_stat.managed);
97010106SJason.Beloro@Sun.COM stat->collected = ptob(del_stat.collected);
97110106SJason.Beloro@Sun.COM }
97210106SJason.Beloro@Sun.COM
97310106SJason.Beloro@Sun.COM *resp = rp;
97410106SJason.Beloro@Sun.COM *resp_len = rlen;
97510106SJason.Beloro@Sun.COM
97610106SJason.Beloro@Sun.COM return (0);
97710106SJason.Beloro@Sun.COM }
97810106SJason.Beloro@Sun.COM
97910106SJason.Beloro@Sun.COM static int
dr_mem_del_cancel(dr_mem_hdr_t * req,dr_mem_hdr_t ** resp,int * resp_len)98010106SJason.Beloro@Sun.COM dr_mem_del_cancel(dr_mem_hdr_t *req, dr_mem_hdr_t **resp, int *resp_len)
98110106SJason.Beloro@Sun.COM {
98210106SJason.Beloro@Sun.COM int rlen;
98310106SJason.Beloro@Sun.COM dr_mem_hdr_t *rp;
98410106SJason.Beloro@Sun.COM
98510106SJason.Beloro@Sun.COM /* allocate a response message, should be freed by caller */
98610106SJason.Beloro@Sun.COM rlen = sizeof (dr_mem_hdr_t);
98710106SJason.Beloro@Sun.COM rp = kmem_zalloc(rlen, KM_SLEEP);
98810106SJason.Beloro@Sun.COM
98910106SJason.Beloro@Sun.COM /* fill in the known data */
99010106SJason.Beloro@Sun.COM rp->req_num = req->req_num;
99110106SJason.Beloro@Sun.COM rp->msg_type = DR_MEM_OK;
99210106SJason.Beloro@Sun.COM rp->msg_arg = (dr_mh && kphysm_del_cancel(dr_mh) != KPHYSM_OK) ?
99310106SJason.Beloro@Sun.COM DR_MEM_RES_EINVAL : DR_MEM_RES_OK;
99410106SJason.Beloro@Sun.COM
99510106SJason.Beloro@Sun.COM *resp = rp;
99610106SJason.Beloro@Sun.COM *resp_len = rlen;
99710106SJason.Beloro@Sun.COM
99810106SJason.Beloro@Sun.COM return (0);
99910106SJason.Beloro@Sun.COM }
100010106SJason.Beloro@Sun.COM
100110106SJason.Beloro@Sun.COM static int
dr_mem_find(dr_mem_blk_t * mbp)100210106SJason.Beloro@Sun.COM dr_mem_find(dr_mem_blk_t *mbp)
100310106SJason.Beloro@Sun.COM {
100410106SJason.Beloro@Sun.COM md_t *mdp = NULL;
100510106SJason.Beloro@Sun.COM int num_nodes;
100610106SJason.Beloro@Sun.COM int rv = 0;
100710106SJason.Beloro@Sun.COM int listsz;
100810106SJason.Beloro@Sun.COM mde_cookie_t *listp = NULL;
100910106SJason.Beloro@Sun.COM mde_cookie_t memnode;
101010106SJason.Beloro@Sun.COM char *found = "found";
101110106SJason.Beloro@Sun.COM
101210106SJason.Beloro@Sun.COM if ((mdp = md_get_handle()) == NULL) {
101310106SJason.Beloro@Sun.COM DR_DBG_MEM("unable to initialize machine description\n");
101410106SJason.Beloro@Sun.COM return (-1);
101510106SJason.Beloro@Sun.COM }
101610106SJason.Beloro@Sun.COM
101710106SJason.Beloro@Sun.COM num_nodes = md_node_count(mdp);
101810106SJason.Beloro@Sun.COM ASSERT(num_nodes > 0);
101910106SJason.Beloro@Sun.COM
102010106SJason.Beloro@Sun.COM listsz = num_nodes * sizeof (mde_cookie_t);
102110106SJason.Beloro@Sun.COM listp = kmem_zalloc(listsz, KM_SLEEP);
102210106SJason.Beloro@Sun.COM
102310106SJason.Beloro@Sun.COM memnode = dr_mem_find_node_md(mbp, mdp, listp);
102410106SJason.Beloro@Sun.COM
102510106SJason.Beloro@Sun.COM if (memnode == MDE_INVAL_ELEM_COOKIE) {
102610106SJason.Beloro@Sun.COM rv = EINVAL;
102710106SJason.Beloro@Sun.COM found = "not found";
102810106SJason.Beloro@Sun.COM }
102910106SJason.Beloro@Sun.COM
103010106SJason.Beloro@Sun.COM DR_DBG_MEM("mblk 0x%lx.0x%lx %s\n", mbp->addr, mbp->size, found);
103110106SJason.Beloro@Sun.COM
103210106SJason.Beloro@Sun.COM kmem_free(listp, listsz);
103310106SJason.Beloro@Sun.COM (void) md_fini_handle(mdp);
103410106SJason.Beloro@Sun.COM
103510106SJason.Beloro@Sun.COM return (rv);
103610106SJason.Beloro@Sun.COM }
103710106SJason.Beloro@Sun.COM
103810106SJason.Beloro@Sun.COM /*
103910106SJason.Beloro@Sun.COM * Look up a particular mblk in the MD. Returns the mde_cookie_t
104010106SJason.Beloro@Sun.COM * representing that mblk if present, and MDE_INVAL_ELEM_COOKIE
104110106SJason.Beloro@Sun.COM * otherwise. It is assumed the scratch array has already been
104210106SJason.Beloro@Sun.COM * allocated so that it can accommodate the worst case scenario,
104310106SJason.Beloro@Sun.COM * every node in the MD.
104410106SJason.Beloro@Sun.COM */
104510106SJason.Beloro@Sun.COM static mde_cookie_t
dr_mem_find_node_md(dr_mem_blk_t * mbp,md_t * mdp,mde_cookie_t * listp)104610106SJason.Beloro@Sun.COM dr_mem_find_node_md(dr_mem_blk_t *mbp, md_t *mdp, mde_cookie_t *listp)
104710106SJason.Beloro@Sun.COM {
104810106SJason.Beloro@Sun.COM int idx;
104910106SJason.Beloro@Sun.COM int nnodes;
105010106SJason.Beloro@Sun.COM mde_cookie_t rootnode;
105110106SJason.Beloro@Sun.COM uint64_t base_prop;
105210106SJason.Beloro@Sun.COM uint64_t size_prop;
105310106SJason.Beloro@Sun.COM mde_cookie_t result = MDE_INVAL_ELEM_COOKIE;
105410106SJason.Beloro@Sun.COM
105510106SJason.Beloro@Sun.COM rootnode = md_root_node(mdp);
105610106SJason.Beloro@Sun.COM ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
105710106SJason.Beloro@Sun.COM
105810106SJason.Beloro@Sun.COM /*
105910106SJason.Beloro@Sun.COM * Scan the DAG for all the mem nodes
106010106SJason.Beloro@Sun.COM */
106110106SJason.Beloro@Sun.COM nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "mblock"),
106210106SJason.Beloro@Sun.COM md_find_name(mdp, "fwd"), listp);
106310106SJason.Beloro@Sun.COM
106410106SJason.Beloro@Sun.COM if (nnodes < 0) {
106510106SJason.Beloro@Sun.COM DR_DBG_MEM("Scan for mblks failed\n");
106610106SJason.Beloro@Sun.COM return (result);
106710106SJason.Beloro@Sun.COM }
106810106SJason.Beloro@Sun.COM
106910106SJason.Beloro@Sun.COM DR_DBG_MEM("dr_mem_find_node_md: found %d mblks in the MD\n", nnodes);
107010106SJason.Beloro@Sun.COM
107110106SJason.Beloro@Sun.COM /*
107210106SJason.Beloro@Sun.COM * Find the mblk of interest
107310106SJason.Beloro@Sun.COM */
107410106SJason.Beloro@Sun.COM for (idx = 0; idx < nnodes; idx++) {
107510106SJason.Beloro@Sun.COM
107610106SJason.Beloro@Sun.COM if (md_get_prop_val(mdp, listp[idx], "base", &base_prop)) {
107710106SJason.Beloro@Sun.COM DR_DBG_MEM("Missing 'base' property for mblk node %d\n",
107810106SJason.Beloro@Sun.COM idx);
107910106SJason.Beloro@Sun.COM break;
108010106SJason.Beloro@Sun.COM }
108110106SJason.Beloro@Sun.COM
108210106SJason.Beloro@Sun.COM if (md_get_prop_val(mdp, listp[idx], "size", &size_prop)) {
108310106SJason.Beloro@Sun.COM DR_DBG_MEM("Missing 'size' property for mblk node %d\n",
108410106SJason.Beloro@Sun.COM idx);
108510106SJason.Beloro@Sun.COM break;
108610106SJason.Beloro@Sun.COM }
108710106SJason.Beloro@Sun.COM
108810106SJason.Beloro@Sun.COM if (base_prop <= mbp->addr &&
108910106SJason.Beloro@Sun.COM (base_prop + size_prop) >= (mbp->addr + mbp->size)) {
109010106SJason.Beloro@Sun.COM /* found a match */
109110106SJason.Beloro@Sun.COM DR_DBG_MEM("dr_mem_find_node_md: found mblk "
109210106SJason.Beloro@Sun.COM "0x%lx.0x%lx in MD\n", mbp->addr, mbp->size);
109310106SJason.Beloro@Sun.COM result = listp[idx];
109410106SJason.Beloro@Sun.COM break;
109510106SJason.Beloro@Sun.COM }
109610106SJason.Beloro@Sun.COM }
109710106SJason.Beloro@Sun.COM
109810106SJason.Beloro@Sun.COM if (result == MDE_INVAL_ELEM_COOKIE) {
109910106SJason.Beloro@Sun.COM DR_DBG_MEM("mblk 0x%lx.0x%lx not in MD\n",
110010106SJason.Beloro@Sun.COM mbp->addr, mbp->size);
110110106SJason.Beloro@Sun.COM }
110210106SJason.Beloro@Sun.COM
110310106SJason.Beloro@Sun.COM return (result);
110410106SJason.Beloro@Sun.COM }
110510106SJason.Beloro@Sun.COM
110610106SJason.Beloro@Sun.COM static int
mem_add(pfn_t base,pgcnt_t npgs)110710106SJason.Beloro@Sun.COM mem_add(pfn_t base, pgcnt_t npgs)
110810106SJason.Beloro@Sun.COM {
110910106SJason.Beloro@Sun.COM int rv, rc;
111010106SJason.Beloro@Sun.COM
111110106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
111210106SJason.Beloro@Sun.COM
111310106SJason.Beloro@Sun.COM if (npgs == 0)
111411185SSean.McEnroe@Sun.COM return (DR_MEM_RES_OK);
111510106SJason.Beloro@Sun.COM
111610106SJason.Beloro@Sun.COM rv = kphysm_add_memory_dynamic(base, npgs);
111710106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: kphysm_add(0x%lx, 0x%lx) = %d", __func__, base, npgs,
111810106SJason.Beloro@Sun.COM rv);
111911185SSean.McEnroe@Sun.COM if (rv == KPHYSM_OK) {
112010106SJason.Beloro@Sun.COM if (rc = kcage_range_add(base, npgs, KCAGE_DOWN))
112110106SJason.Beloro@Sun.COM cmn_err(CE_WARN, "kcage_range_add() = %d", rc);
112210106SJason.Beloro@Sun.COM }
112311185SSean.McEnroe@Sun.COM rv = cvt_err(rv);
112410106SJason.Beloro@Sun.COM return (rv);
112510106SJason.Beloro@Sun.COM }
112610106SJason.Beloro@Sun.COM
112710106SJason.Beloro@Sun.COM static void
del_done(void * arg,int error)112810106SJason.Beloro@Sun.COM del_done(void *arg, int error)
112910106SJason.Beloro@Sun.COM {
113010106SJason.Beloro@Sun.COM mem_sync_t *ms = arg;
113110106SJason.Beloro@Sun.COM
113210106SJason.Beloro@Sun.COM mutex_enter(&ms->lock);
113310106SJason.Beloro@Sun.COM ms->error = error;
113410106SJason.Beloro@Sun.COM ms->done = 1;
113510106SJason.Beloro@Sun.COM cv_signal(&ms->cond);
113610106SJason.Beloro@Sun.COM mutex_exit(&ms->lock);
113710106SJason.Beloro@Sun.COM }
113810106SJason.Beloro@Sun.COM
113910106SJason.Beloro@Sun.COM static int
mem_del(pfn_t base,pgcnt_t npgs)114010106SJason.Beloro@Sun.COM mem_del(pfn_t base, pgcnt_t npgs)
114110106SJason.Beloro@Sun.COM {
114210106SJason.Beloro@Sun.COM int rv, err, del_range = 0;
114311185SSean.McEnroe@Sun.COM int convert = 1;
114410106SJason.Beloro@Sun.COM mem_sync_t ms;
114510106SJason.Beloro@Sun.COM memquery_t mq;
114610106SJason.Beloro@Sun.COM memhandle_t mh;
114710106SJason.Beloro@Sun.COM struct memlist *ml;
114810106SJason.Beloro@Sun.COM struct memlist *d_ml = NULL;
114910106SJason.Beloro@Sun.COM
115010106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: begin base=0x%lx npgs=0x%lx\n", __func__, base, npgs);
115110106SJason.Beloro@Sun.COM
115210106SJason.Beloro@Sun.COM if (npgs == 0)
115311185SSean.McEnroe@Sun.COM return (DR_MEM_RES_OK);
115410106SJason.Beloro@Sun.COM
115510106SJason.Beloro@Sun.COM if ((rv = kphysm_del_gethandle(&mh)) != KPHYSM_OK) {
115610106SJason.Beloro@Sun.COM cmn_err(CE_WARN, "%s: del_gethandle() = %d", __func__, rv);
115711185SSean.McEnroe@Sun.COM rv = cvt_err(rv);
115810106SJason.Beloro@Sun.COM return (rv);
115910106SJason.Beloro@Sun.COM }
116010106SJason.Beloro@Sun.COM if ((rv = kphysm_del_span_query(base, npgs, &mq))
116110106SJason.Beloro@Sun.COM != KPHYSM_OK) {
116210106SJason.Beloro@Sun.COM cmn_err(CE_WARN, "%s: del_span_query() = %d", __func__, rv);
116310106SJason.Beloro@Sun.COM goto done;
116410106SJason.Beloro@Sun.COM }
116510106SJason.Beloro@Sun.COM if (mq.nonrelocatable) {
116610106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: non-reloc pages = %ld",
116710106SJason.Beloro@Sun.COM __func__, mq.nonrelocatable);
116811185SSean.McEnroe@Sun.COM rv = KPHYSM_ENONRELOC;
116910106SJason.Beloro@Sun.COM goto done;
117010106SJason.Beloro@Sun.COM }
117110106SJason.Beloro@Sun.COM if (rv = kcage_range_delete(base, npgs)) {
117211185SSean.McEnroe@Sun.COM switch (rv) {
117311185SSean.McEnroe@Sun.COM case EBUSY:
117411185SSean.McEnroe@Sun.COM rv = DR_MEM_RES_ENOTVIABLE;
117511185SSean.McEnroe@Sun.COM break;
117611185SSean.McEnroe@Sun.COM default:
117711185SSean.McEnroe@Sun.COM rv = DR_MEM_RES_FAILURE;
117811185SSean.McEnroe@Sun.COM break;
117911185SSean.McEnroe@Sun.COM }
118011185SSean.McEnroe@Sun.COM convert = 0; /* conversion done */
118110106SJason.Beloro@Sun.COM cmn_err(CE_WARN, "%s: del_range() = %d", __func__, rv);
118210106SJason.Beloro@Sun.COM goto done;
118310106SJason.Beloro@Sun.COM } else {
118410106SJason.Beloro@Sun.COM del_range++;
118510106SJason.Beloro@Sun.COM }
118610106SJason.Beloro@Sun.COM if ((rv = kphysm_del_span(mh, base, npgs)) != KPHYSM_OK) {
118710106SJason.Beloro@Sun.COM cmn_err(CE_WARN, "%s: del_span() = %d", __func__, rv);
118810106SJason.Beloro@Sun.COM goto done;
118910106SJason.Beloro@Sun.COM }
119010106SJason.Beloro@Sun.COM if ((rv = memlist_add_span(ptob(base), ptob(npgs), &d_ml))
119110106SJason.Beloro@Sun.COM != MEML_SPANOP_OK) {
119211185SSean.McEnroe@Sun.COM switch (rv) {
119311185SSean.McEnroe@Sun.COM case MEML_SPANOP_ESPAN:
119411185SSean.McEnroe@Sun.COM rv = DR_MEM_RES_ESPAN;
119511185SSean.McEnroe@Sun.COM break;
119611185SSean.McEnroe@Sun.COM case MEML_SPANOP_EALLOC:
119711185SSean.McEnroe@Sun.COM rv = DR_MEM_RES_ERESOURCE;
119811185SSean.McEnroe@Sun.COM break;
119911185SSean.McEnroe@Sun.COM default:
120011185SSean.McEnroe@Sun.COM rv = DR_MEM_RES_FAILURE;
120111185SSean.McEnroe@Sun.COM break;
120211185SSean.McEnroe@Sun.COM }
120311185SSean.McEnroe@Sun.COM convert = 0; /* conversion done */
120410106SJason.Beloro@Sun.COM cmn_err(CE_WARN, "%s: add_span() = %d", __func__, rv);
120510106SJason.Beloro@Sun.COM goto done;
120610106SJason.Beloro@Sun.COM }
120710106SJason.Beloro@Sun.COM
120810106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: reserved=0x%lx", __func__, npgs);
120910106SJason.Beloro@Sun.COM
121010106SJason.Beloro@Sun.COM bzero((void *) &ms, sizeof (ms));
121110106SJason.Beloro@Sun.COM
121210106SJason.Beloro@Sun.COM mutex_init(&ms.lock, NULL, MUTEX_DRIVER, NULL);
121310106SJason.Beloro@Sun.COM cv_init(&ms.cond, NULL, CV_DRIVER, NULL);
121410106SJason.Beloro@Sun.COM mutex_enter(&ms.lock);
121510106SJason.Beloro@Sun.COM
121610106SJason.Beloro@Sun.COM if ((rv = kphysm_del_start(mh, del_done, (void *) &ms)) == KPHYSM_OK) {
121710106SJason.Beloro@Sun.COM /*
121810106SJason.Beloro@Sun.COM * Since we've called drctl_config_init, we are the only
121910106SJason.Beloro@Sun.COM * DR ctl operation in progress. Set dr_mh to the
122010106SJason.Beloro@Sun.COM * delete memhandle for use by stat and cancel.
122110106SJason.Beloro@Sun.COM */
122210106SJason.Beloro@Sun.COM ASSERT(dr_mh == NULL);
122310106SJason.Beloro@Sun.COM dr_mh = mh;
122410106SJason.Beloro@Sun.COM
122510106SJason.Beloro@Sun.COM /*
122610106SJason.Beloro@Sun.COM * Wait for completion or interrupt.
122710106SJason.Beloro@Sun.COM */
122810106SJason.Beloro@Sun.COM while (!ms.done) {
122910106SJason.Beloro@Sun.COM if (cv_wait_sig(&ms.cond, &ms.lock) == 0) {
123010106SJason.Beloro@Sun.COM /*
123110106SJason.Beloro@Sun.COM * There is a pending signal.
123210106SJason.Beloro@Sun.COM */
123310106SJason.Beloro@Sun.COM (void) kphysm_del_cancel(mh);
123410106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: cancel", __func__);
123510106SJason.Beloro@Sun.COM /*
123610106SJason.Beloro@Sun.COM * Wait for completion.
123710106SJason.Beloro@Sun.COM */
123810106SJason.Beloro@Sun.COM while (!ms.done)
123910106SJason.Beloro@Sun.COM cv_wait(&ms.cond, &ms.lock);
124010106SJason.Beloro@Sun.COM }
124110106SJason.Beloro@Sun.COM }
124210106SJason.Beloro@Sun.COM dr_mh = NULL;
124310106SJason.Beloro@Sun.COM rv = ms.error;
124410106SJason.Beloro@Sun.COM } else {
124510106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: del_start() = %d", __func__, rv);
124610106SJason.Beloro@Sun.COM }
124710106SJason.Beloro@Sun.COM
124810106SJason.Beloro@Sun.COM mutex_exit(&ms.lock);
124910106SJason.Beloro@Sun.COM cv_destroy(&ms.cond);
125010106SJason.Beloro@Sun.COM mutex_destroy(&ms.lock);
125110106SJason.Beloro@Sun.COM
125210106SJason.Beloro@Sun.COM done:
125310106SJason.Beloro@Sun.COM if (rv && del_range) {
125410106SJason.Beloro@Sun.COM /*
125510106SJason.Beloro@Sun.COM * Add back the spans to the kcage growth list.
125610106SJason.Beloro@Sun.COM */
125711474SJonathan.Adams@Sun.COM for (ml = d_ml; ml; ml = ml->ml_next)
125811474SJonathan.Adams@Sun.COM if (err = kcage_range_add(btop(ml->ml_address),
125911474SJonathan.Adams@Sun.COM btop(ml->ml_size), KCAGE_DOWN))
126010106SJason.Beloro@Sun.COM cmn_err(CE_WARN, "kcage_range_add() = %d", err);
126110106SJason.Beloro@Sun.COM }
126210106SJason.Beloro@Sun.COM memlist_free_list(d_ml);
126310106SJason.Beloro@Sun.COM
126410106SJason.Beloro@Sun.COM if ((err = kphysm_del_release(mh)) != KPHYSM_OK)
126510106SJason.Beloro@Sun.COM cmn_err(CE_WARN, "%s: del_release() = %d", __func__, err);
126611185SSean.McEnroe@Sun.COM if (convert)
126711185SSean.McEnroe@Sun.COM rv = cvt_err(rv);
126810106SJason.Beloro@Sun.COM
126910106SJason.Beloro@Sun.COM DR_DBG_MEM("%s: rv=%d", __func__, rv);
127010106SJason.Beloro@Sun.COM
127110106SJason.Beloro@Sun.COM return (rv);
127210106SJason.Beloro@Sun.COM }
1273