12309Srsmaeda /*
22309Srsmaeda * CDDL HEADER START
32309Srsmaeda *
42309Srsmaeda * The contents of this file are subject to the terms of the
52309Srsmaeda * Common Development and Distribution License (the "License").
62309Srsmaeda * You may not use this file except in compliance with the License.
72309Srsmaeda *
82309Srsmaeda * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92309Srsmaeda * or http://www.opensolaris.org/os/licensing.
102309Srsmaeda * See the License for the specific language governing permissions
112309Srsmaeda * and limitations under the License.
122309Srsmaeda *
132309Srsmaeda * When distributing Covered Code, include this CDDL HEADER in each
142309Srsmaeda * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152309Srsmaeda * If applicable, add the following below this CDDL HEADER, with the
162309Srsmaeda * fields enclosed by brackets "[]" replaced with your own identifying
172309Srsmaeda * information: Portions Copyright [yyyy] [name of copyright owner]
182309Srsmaeda *
192309Srsmaeda * CDDL HEADER END
202309Srsmaeda */
212309Srsmaeda
222309Srsmaeda /*
23*10106SJason.Beloro@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
242309Srsmaeda * Use is subject to license terms.
252309Srsmaeda */
262309Srsmaeda
272309Srsmaeda /*
282309Srsmaeda * RCM backend for the DR Daemon
292309Srsmaeda */
302309Srsmaeda
312309Srsmaeda #include <unistd.h>
322309Srsmaeda #include <strings.h>
332309Srsmaeda #include <errno.h>
342309Srsmaeda #include <kstat.h>
352309Srsmaeda #include <libnvpair.h>
362309Srsmaeda #include <librcm.h>
376441Sjm22469 #include <locale.h>
38*10106SJason.Beloro@Sun.COM #include <assert.h>
392309Srsmaeda
402309Srsmaeda #include "drd.h"
412309Srsmaeda
422309Srsmaeda /*
432309Srsmaeda * RCM Backend Support
442309Srsmaeda */
452309Srsmaeda static int drd_rcm_init(void);
462309Srsmaeda static int drd_rcm_fini(void);
472309Srsmaeda static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
482309Srsmaeda static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
492309Srsmaeda static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
502309Srsmaeda static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
516441Sjm22469 static int drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc);
526441Sjm22469 static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc);
536441Sjm22469 static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc);
546441Sjm22469 static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc);
55*10106SJason.Beloro@Sun.COM static int drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
56*10106SJason.Beloro@Sun.COM static int drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
57*10106SJason.Beloro@Sun.COM static int drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
58*10106SJason.Beloro@Sun.COM static int drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
592309Srsmaeda
602309Srsmaeda drd_backend_t drd_rcm_backend = {
612309Srsmaeda drd_rcm_init, /* init */
622309Srsmaeda drd_rcm_fini, /* fini */
632309Srsmaeda drd_rcm_cpu_config_request, /* cpu_config_request */
642309Srsmaeda drd_rcm_cpu_config_notify, /* cpu_config_notify */
652309Srsmaeda drd_rcm_cpu_unconfig_request, /* cpu_unconfig_request */
666441Sjm22469 drd_rcm_cpu_unconfig_notify, /* cpu_unconfig_notify */
676441Sjm22469 drd_rcm_io_config_request, /* io_config_request */
686441Sjm22469 drd_rcm_io_config_notify, /* io_config_notify */
696441Sjm22469 drd_rcm_io_unconfig_request, /* io_unconfig_request */
70*10106SJason.Beloro@Sun.COM drd_rcm_io_unconfig_notify, /* io_unconfig_notify */
71*10106SJason.Beloro@Sun.COM drd_rcm_mem_config_request, /* mem_config_request */
72*10106SJason.Beloro@Sun.COM drd_rcm_mem_config_notify, /* mem_config_notify */
73*10106SJason.Beloro@Sun.COM drd_rcm_mem_unconfig_request, /* mem_unconfig_request */
74*10106SJason.Beloro@Sun.COM drd_rcm_mem_unconfig_notify /* mem_unconfig_notify */
752309Srsmaeda };
762309Srsmaeda
77*10106SJason.Beloro@Sun.COM typedef int (*rcm_op_t)(rcm_handle_t *, char *, uint_t, nvlist_t *,
78*10106SJason.Beloro@Sun.COM rcm_info_t **);
79*10106SJason.Beloro@Sun.COM
80*10106SJason.Beloro@Sun.COM #define RCM_MEM_ALL "SUNW_memory"
812309Srsmaeda #define RCM_CPU_ALL "SUNW_cpu"
822309Srsmaeda #define RCM_CPU RCM_CPU_ALL"/cpu"
832309Srsmaeda #define RCM_CPU_MAX_LEN (32)
842309Srsmaeda
852309Srsmaeda /* global RCM handle used in all RCM operations */
862309Srsmaeda static rcm_handle_t *rcm_hdl;
872309Srsmaeda
882309Srsmaeda /* functions that call into RCM */
892309Srsmaeda static int drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
902309Srsmaeda static int drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
912309Srsmaeda static int drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
922309Srsmaeda static int drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
932309Srsmaeda static int drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
942309Srsmaeda static int drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
952309Srsmaeda static int drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
962309Srsmaeda
972309Srsmaeda /* utility functions */
982309Srsmaeda static char **drd_rcm_cpu_rlist_init(drctl_rsrc_t *, int nrsrc, int status);
992309Srsmaeda static void drd_rcm_cpu_rlist_fini(char **rlist);
1002309Srsmaeda static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int);
1012309Srsmaeda static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids);
1022309Srsmaeda static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len);
1036441Sjm22469 static char *rcm_info_table(rcm_info_t *rinfo);
1042309Srsmaeda
1052309Srsmaeda /* debugging utility functions */
1062309Srsmaeda static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids);
1072309Srsmaeda static void dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *, int nrsrc);
1082309Srsmaeda static void dump_cpu_rlist(char **rlist);
1092309Srsmaeda
1102309Srsmaeda static int
drd_rcm_init(void)1112309Srsmaeda drd_rcm_init(void)
1122309Srsmaeda {
1132309Srsmaeda int rv;
1142309Srsmaeda
1152309Srsmaeda drd_dbg("drd_rcm_init...");
1162309Srsmaeda
1172309Srsmaeda rv = rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl);
1182309Srsmaeda if (rv == RCM_FAILURE) {
1192309Srsmaeda drd_err("unable to allocate RCM handle: %s", strerror(errno));
1202309Srsmaeda return (-1);
1212309Srsmaeda }
1222309Srsmaeda
1232309Srsmaeda return (0);
1242309Srsmaeda }
1252309Srsmaeda
1262309Srsmaeda static int
drd_rcm_fini(void)1272309Srsmaeda drd_rcm_fini(void)
1282309Srsmaeda {
1292309Srsmaeda drd_dbg("drd_rcm_fini...");
1302309Srsmaeda
1312309Srsmaeda if (rcm_hdl != NULL)
1322309Srsmaeda rcm_free_handle(rcm_hdl);
1332309Srsmaeda
1342309Srsmaeda return (0);
1352309Srsmaeda }
1362309Srsmaeda
1372309Srsmaeda static int
drd_rcm_cpu_config_request(drctl_rsrc_t * rsrcs,int nrsrc)1382309Srsmaeda drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
1392309Srsmaeda {
1402309Srsmaeda int idx;
1412309Srsmaeda
1422309Srsmaeda drd_dbg("drd_rcm_cpu_config_request...");
1432309Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1442309Srsmaeda
1452309Srsmaeda /*
1462309Srsmaeda * There is no RCM operation to request the addition
1476441Sjm22469 * of resources. So, by definition, the operation for
1482309Srsmaeda * all the CPUs is allowed.
1492309Srsmaeda */
1502309Srsmaeda for (idx = 0; idx < nrsrc; idx++)
1512309Srsmaeda rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1522309Srsmaeda
1532309Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
1542309Srsmaeda
1552309Srsmaeda return (0);
1562309Srsmaeda }
1572309Srsmaeda
1582309Srsmaeda static int
drd_rcm_cpu_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)1592309Srsmaeda drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1602309Srsmaeda {
1612309Srsmaeda int rv = 0;
1622309Srsmaeda
1632309Srsmaeda drd_dbg("drd_rcm_cpu_config_notify...");
1642309Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1652309Srsmaeda
1662309Srsmaeda /* notify RCM about the newly added CPUs */
1672309Srsmaeda if (drd_rcm_online_cpu_notify(rsrcs, nrsrc) != 0) {
1682309Srsmaeda rv = -1;
1692309Srsmaeda goto done;
1702309Srsmaeda }
1712309Srsmaeda
1722309Srsmaeda /* notify RCM about the increased CPU capacity */
1732309Srsmaeda if (drd_rcm_add_cpu_notify(rsrcs, nrsrc) != 0) {
1742309Srsmaeda rv = -1;
1752309Srsmaeda }
1762309Srsmaeda
1772309Srsmaeda done:
1782309Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
1792309Srsmaeda
1802309Srsmaeda return (rv);
1812309Srsmaeda }
1822309Srsmaeda
1832309Srsmaeda static int
drd_rcm_cpu_unconfig_request(drctl_rsrc_t * rsrcs,int nrsrc)1842309Srsmaeda drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
1852309Srsmaeda {
1862309Srsmaeda int rv = 0;
1872309Srsmaeda int idx;
1882309Srsmaeda
1892309Srsmaeda drd_dbg("drd_rcm_cpu_unconfig_request...");
1902309Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1912309Srsmaeda
1922309Srsmaeda /* contact RCM to request a decrease in CPU capacity */
1932309Srsmaeda if (drd_rcm_del_cpu_request(rsrcs, nrsrc) != 0) {
1942309Srsmaeda rv = -1;
1952309Srsmaeda goto done;
1962309Srsmaeda }
1972309Srsmaeda
1982309Srsmaeda /* contact RCM to request the removal of CPUs */
1992309Srsmaeda if (drd_rcm_offline_cpu_request(rsrcs, nrsrc) != 0) {
2002309Srsmaeda rv = -1;
2012309Srsmaeda goto done;
2022309Srsmaeda }
2032309Srsmaeda
2042309Srsmaeda done:
2052309Srsmaeda /*
2062309Srsmaeda * If any errors occurred, the status field for
2072309Srsmaeda * a CPU may still be in the INIT state. Set the
2082309Srsmaeda * status for any such CPU to DENY to ensure it
2092309Srsmaeda * gets processed properly.
2102309Srsmaeda */
2112309Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
2122309Srsmaeda if (rsrcs[idx].status == DRCTL_STATUS_INIT)
2132309Srsmaeda rsrcs[idx].status = DRCTL_STATUS_DENY;
2142309Srsmaeda }
2152309Srsmaeda
2162309Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
2172309Srsmaeda
2182309Srsmaeda return (rv);
2192309Srsmaeda }
2202309Srsmaeda
2212309Srsmaeda static int
drd_rcm_cpu_unconfig_notify(drctl_rsrc_t * rsrcs,int nrsrc)2222309Srsmaeda drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2232309Srsmaeda {
2242309Srsmaeda int rv = 0;
2252309Srsmaeda
2262309Srsmaeda drd_dbg("drd_rcm_cpu_unconfig_notify...");
2272309Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
2282309Srsmaeda
2292309Srsmaeda /*
2302309Srsmaeda * Notify RCM about the CPUs that were removed.
2312309Srsmaeda * Failures are ignored so that CPUs that could
2322309Srsmaeda * not be unconfigured can be processed by RCM.
2332309Srsmaeda */
2342309Srsmaeda (void) drd_rcm_remove_cpu_notify(rsrcs, nrsrc);
2352309Srsmaeda
2362309Srsmaeda /*
2372309Srsmaeda * Notify RCM about any CPUs that did not make it
2382309Srsmaeda * in to the unconfigured state.
2392309Srsmaeda */
2402309Srsmaeda if (drd_rcm_restore_cpu_notify(rsrcs, nrsrc) != 0) {
2412309Srsmaeda rv = -1;
2422309Srsmaeda goto done;
2432309Srsmaeda }
2442309Srsmaeda
2452309Srsmaeda /* notify RCM about the decreased CPU capacity */
2462309Srsmaeda if (drd_rcm_del_cpu_notify(rsrcs, nrsrc) != 0) {
2472309Srsmaeda rv = -1;
2482309Srsmaeda }
2492309Srsmaeda
2502309Srsmaeda done:
2512309Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
2522309Srsmaeda
2532309Srsmaeda return (rv);
2542309Srsmaeda }
2552309Srsmaeda
2562309Srsmaeda static int
drd_rcm_online_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)2572309Srsmaeda drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2582309Srsmaeda {
2592309Srsmaeda char **rlist;
2602309Srsmaeda int rv = 0;
2612309Srsmaeda rcm_info_t *rinfo;
2622309Srsmaeda
2632309Srsmaeda drd_dbg("drd_rcm_online_cpu_notify...");
2642309Srsmaeda
2652309Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
2662309Srsmaeda DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
2672309Srsmaeda drd_dbg(" no CPUs were successfully added, nothing to do");
2682309Srsmaeda return (0);
2692309Srsmaeda }
2702309Srsmaeda
2712309Srsmaeda rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
2722309Srsmaeda if (rv != RCM_SUCCESS) {
2732309Srsmaeda drd_info("rcm_notify_online_list failed: %d", rv);
2742309Srsmaeda rcm_free_info(rinfo);
2752309Srsmaeda rv = -1;
2762309Srsmaeda }
2772309Srsmaeda
2782309Srsmaeda drd_rcm_cpu_rlist_fini(rlist);
2792309Srsmaeda
2802309Srsmaeda return (rv);
2812309Srsmaeda }
2822309Srsmaeda
2832309Srsmaeda static int
drd_rcm_add_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)2842309Srsmaeda drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2852309Srsmaeda {
2862309Srsmaeda cpuid_t *cpus = NULL;
2872309Srsmaeda int ncpus;
2882309Srsmaeda int rv = -1;
2892309Srsmaeda cpuid_t *oldcpus = NULL;
2902309Srsmaeda cpuid_t *newcpus = NULL;
2912309Srsmaeda int oldncpus = 0;
2922309Srsmaeda int newncpus = 0;
2932309Srsmaeda nvlist_t *nvl = NULL;
2942309Srsmaeda int idx;
2952309Srsmaeda rcm_info_t *rinfo;
2962309Srsmaeda
2972309Srsmaeda drd_dbg("drd_rcm_add_cpu_notify...");
2982309Srsmaeda
2992309Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) {
3002309Srsmaeda drd_err("add_cpu_notify: cpu list empty");
3012309Srsmaeda goto done;
3022309Srsmaeda }
3032309Srsmaeda
3042309Srsmaeda ncpus = nrsrc;
3052309Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
3062309Srsmaeda
3072309Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
3082309Srsmaeda drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
3092309Srsmaeda cpus[idx] = rsrcs[idx].res_cpu_id;
3102309Srsmaeda }
3112309Srsmaeda
3122309Srsmaeda /* allocate an nvlist for the RCM call */
3132309Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3142309Srsmaeda goto done;
3152309Srsmaeda
3162309Srsmaeda /*
3172309Srsmaeda * Added CPU capacity, so newcpus is the current list
3182309Srsmaeda * of CPUs in the system.
3192309Srsmaeda */
3202309Srsmaeda if (get_sys_cpuids(&newcpus, &newncpus) == -1)
3212309Srsmaeda goto done;
3222309Srsmaeda
3232309Srsmaeda /*
3242309Srsmaeda * Since the operation added CPU capacity, the old CPU
3252309Srsmaeda * list is the new CPU list with the CPUs involved in
3262309Srsmaeda * the operation removed.
3272309Srsmaeda */
3282309Srsmaeda oldcpus = (cpuid_t *)calloc(newncpus, sizeof (cpuid_t));
3292309Srsmaeda if (oldcpus == NULL)
3302309Srsmaeda goto done;
3312309Srsmaeda
3322309Srsmaeda for (idx = 0; idx < newncpus; idx++) {
3332309Srsmaeda if (!is_cpu_in_list(newcpus[idx], cpus, ncpus))
3342309Srsmaeda oldcpus[oldncpus++] = newcpus[idx];
3352309Srsmaeda }
3362309Srsmaeda
3372309Srsmaeda /* dump pre and post lists */
3382309Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
3392309Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus);
3402309Srsmaeda dump_cpu_list("delta: ", cpus, ncpus);
3412309Srsmaeda
3422309Srsmaeda /* setup the nvlist for the RCM call */
3432309Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") ||
3442309Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) ||
3452309Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) ||
3462309Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
3472309Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
3482309Srsmaeda goto done;
3492309Srsmaeda }
3502309Srsmaeda
3512309Srsmaeda rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
3522309Srsmaeda rv = (rv == RCM_SUCCESS) ? 0 : -1;
3532309Srsmaeda
3542309Srsmaeda done:
3552309Srsmaeda s_nvfree(nvl);
3562309Srsmaeda s_free(cpus);
3572309Srsmaeda s_free(oldcpus);
3582309Srsmaeda s_free(newcpus);
3592309Srsmaeda
3602309Srsmaeda return (rv);
3612309Srsmaeda }
3622309Srsmaeda
3632309Srsmaeda static int
drd_rcm_del_cpu_request(drctl_rsrc_t * rsrcs,int nrsrc)3642309Srsmaeda drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
3652309Srsmaeda {
3662309Srsmaeda cpuid_t *cpus = NULL;
3672309Srsmaeda int ncpus;
3682309Srsmaeda int rv = -1;
3692309Srsmaeda cpuid_t *oldcpus = NULL;
3702309Srsmaeda cpuid_t *newcpus = NULL;
3712309Srsmaeda int oldncpus = 0;
3722309Srsmaeda int newncpus = 0;
3732309Srsmaeda nvlist_t *nvl = NULL;
3742309Srsmaeda int idx;
3752309Srsmaeda rcm_info_t *rinfo;
3762309Srsmaeda
3772309Srsmaeda drd_dbg("drd_rcm_del_cpu_request...");
3782309Srsmaeda
3792309Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) {
3802309Srsmaeda drd_err("del_cpu_request: cpu list empty");
3812309Srsmaeda goto done;
3822309Srsmaeda }
3832309Srsmaeda
3842309Srsmaeda ncpus = nrsrc;
3852309Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
3862309Srsmaeda
3872309Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
3882309Srsmaeda cpus[idx] = rsrcs[idx].res_cpu_id;
3892309Srsmaeda }
3902309Srsmaeda
3912309Srsmaeda /* allocate an nvlist for the RCM call */
3922309Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
3932309Srsmaeda goto done;
3942309Srsmaeda }
3952309Srsmaeda
3962309Srsmaeda /*
3972309Srsmaeda * Removing CPU capacity, so oldcpus is the current
3982309Srsmaeda * list of CPUs in the system.
3992309Srsmaeda */
4002309Srsmaeda if (get_sys_cpuids(&oldcpus, &oldncpus) == -1) {
4012309Srsmaeda goto done;
4022309Srsmaeda }
4032309Srsmaeda
4042309Srsmaeda /*
4052309Srsmaeda * Since this is a request to remove CPU capacity,
4062309Srsmaeda * the new CPU list is the old CPU list with the CPUs
4072309Srsmaeda * involved in the operation removed.
4082309Srsmaeda */
4092309Srsmaeda newcpus = (cpuid_t *)calloc(oldncpus, sizeof (cpuid_t));
4102309Srsmaeda if (newcpus == NULL) {
4112309Srsmaeda goto done;
4122309Srsmaeda }
4132309Srsmaeda
4142309Srsmaeda for (idx = 0; idx < oldncpus; idx++) {
4152309Srsmaeda if (!is_cpu_in_list(oldcpus[idx], cpus, ncpus))
4162309Srsmaeda newcpus[newncpus++] = oldcpus[idx];
4172309Srsmaeda }
4182309Srsmaeda
4192309Srsmaeda /* dump pre and post lists */
4202309Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
4212309Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus);
4222309Srsmaeda dump_cpu_list("delta: ", cpus, ncpus);
4232309Srsmaeda
4242309Srsmaeda /* setup the nvlist for the RCM call */
4252309Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") ||
4262309Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) ||
4272309Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) ||
4282309Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
4292309Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
4302309Srsmaeda goto done;
4312309Srsmaeda }
4322309Srsmaeda
4332309Srsmaeda rv = rcm_request_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
4342309Srsmaeda if (rv != RCM_SUCCESS) {
4352309Srsmaeda drd_dbg("RCM call failed: %d", rv);
4362309Srsmaeda /*
437*10106SJason.Beloro@Sun.COM * Since the capacity change was blocked, we
4382309Srsmaeda * mark all CPUs as blocked. It is up to the
4392309Srsmaeda * user to reframe the query so that it can
4402309Srsmaeda * succeed.
4412309Srsmaeda */
4422309Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
4432309Srsmaeda rsrcs[idx].status = DRCTL_STATUS_DENY;
4442309Srsmaeda }
4452309Srsmaeda
4462309Srsmaeda /* tack on message to first resource */
4472309Srsmaeda rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
4482309Srsmaeda "specified number of CPUs");
4492309Srsmaeda drd_dbg(" unable to remove specified number of CPUs");
4502309Srsmaeda goto done;
4512309Srsmaeda }
4522309Srsmaeda
4532309Srsmaeda rv = 0;
4542309Srsmaeda
4552309Srsmaeda done:
4562309Srsmaeda s_nvfree(nvl);
4572309Srsmaeda s_free(cpus);
4582309Srsmaeda s_free(oldcpus);
4592309Srsmaeda s_free(newcpus);
4602309Srsmaeda
4612309Srsmaeda return (rv);
4622309Srsmaeda }
4632309Srsmaeda
4642309Srsmaeda static int
drd_rcm_offline_cpu_request(drctl_rsrc_t * rsrcs,int nrsrc)4652309Srsmaeda drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
4662309Srsmaeda {
4672309Srsmaeda char **rlist;
4682309Srsmaeda drctl_rsrc_t *rsrc;
4692309Srsmaeda int idx;
4702309Srsmaeda int state;
4712309Srsmaeda int rv = 0;
4722309Srsmaeda rcm_info_t *rinfo = NULL;
4732309Srsmaeda rcm_info_tuple_t *tuple = NULL;
4742309Srsmaeda const char *rsrcstr;
4752309Srsmaeda const char *errstr;
4762309Srsmaeda
4772309Srsmaeda drd_dbg("drd_rcm_offline_cpu_request...");
4782309Srsmaeda
4792309Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
4802309Srsmaeda DRCTL_STATUS_INIT)) == NULL) {
4812309Srsmaeda drd_err("unable to generate resource list");
4822309Srsmaeda return (-1);
4832309Srsmaeda }
4842309Srsmaeda
4852309Srsmaeda rv = rcm_request_offline_list(rcm_hdl, rlist, 0, &rinfo);
4862309Srsmaeda if (rv == RCM_SUCCESS) {
4872309Srsmaeda drd_dbg("RCM success, rinfo=%p", rinfo);
4882309Srsmaeda goto done;
4892309Srsmaeda }
4902309Srsmaeda
4912309Srsmaeda drd_dbg("RCM call failed (%d):", rv);
4922309Srsmaeda
4932309Srsmaeda /*
4942309Srsmaeda * Loop through the result of the operation and add
4952309Srsmaeda * any error messages to the resource structure.
4962309Srsmaeda */
4972309Srsmaeda while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
4982309Srsmaeda
4992309Srsmaeda /* find the resource of interest */
5002309Srsmaeda rsrcstr = rcm_info_rsrc(tuple);
5012309Srsmaeda rsrc = cpu_rsrcstr_to_rsrc(rsrcstr, rsrcs, nrsrc);
5022309Srsmaeda
5032309Srsmaeda if (rsrc == NULL) {
5042309Srsmaeda drd_dbg("unable to find resource for %s", rsrcstr);
5052309Srsmaeda continue;
5062309Srsmaeda }
5072309Srsmaeda
5082309Srsmaeda errstr = rcm_info_error(tuple);
5092309Srsmaeda
5102309Srsmaeda if (errstr) {
5112309Srsmaeda drd_dbg(" %s: '%s'", rsrcstr, errstr);
5122309Srsmaeda rsrc->offset = (uintptr_t)strdup(errstr);
5132309Srsmaeda }
5142309Srsmaeda }
5152309Srsmaeda
5162309Srsmaeda rcm_free_info(rinfo);
5172309Srsmaeda rv = 0;
5182309Srsmaeda
5192309Srsmaeda done:
5202309Srsmaeda /*
5212309Srsmaeda * Set the state of the resource based on the RCM
5222309Srsmaeda * state. CPUs in the offline state have the ok to
5232309Srsmaeda * proceed. All others have been blocked.
5242309Srsmaeda */
5252309Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) {
5262309Srsmaeda
5272309Srsmaeda state = 0;
5282309Srsmaeda rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
5292309Srsmaeda
5302309Srsmaeda /* find the resource of interest */
5312309Srsmaeda rsrc = cpu_rsrcstr_to_rsrc(rlist[idx], rsrcs, nrsrc);
5322309Srsmaeda
5332309Srsmaeda if (rsrc == NULL) {
5342309Srsmaeda drd_dbg("unable to find resource for %s", rlist[idx]);
5352309Srsmaeda continue;
5362309Srsmaeda }
5372309Srsmaeda
5382309Srsmaeda rsrc->status = ((state == RCM_STATE_OFFLINE) ?
5392309Srsmaeda DRCTL_STATUS_ALLOW : DRCTL_STATUS_DENY);
5402309Srsmaeda }
5412309Srsmaeda
5422309Srsmaeda drd_rcm_cpu_rlist_fini(rlist);
5432309Srsmaeda
5442309Srsmaeda return (rv);
5452309Srsmaeda }
5462309Srsmaeda
5472309Srsmaeda static int
drd_rcm_remove_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)5482309Srsmaeda drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
5492309Srsmaeda {
5502309Srsmaeda char **rlist;
5512309Srsmaeda int rv = 0;
5522309Srsmaeda rcm_info_t *rinfo;
5532309Srsmaeda
5542309Srsmaeda drd_dbg("drd_rcm_remove_cpu_notify...");
5552309Srsmaeda
5562309Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
5572309Srsmaeda DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
5582309Srsmaeda drd_dbg(" no CPUs in the success state, nothing to do");
5592309Srsmaeda return (0);
5602309Srsmaeda }
5612309Srsmaeda
5622309Srsmaeda rv = rcm_notify_remove_list(rcm_hdl, rlist, 0, &rinfo);
5632309Srsmaeda if (rv != RCM_SUCCESS) {
5642309Srsmaeda drd_info("rcm_notify_remove_list failed: %d", rv);
5652309Srsmaeda rcm_free_info(rinfo);
5662309Srsmaeda rv = -1;
5672309Srsmaeda }
5682309Srsmaeda
5692309Srsmaeda drd_rcm_cpu_rlist_fini(rlist);
5702309Srsmaeda
5712309Srsmaeda return (rv);
5722309Srsmaeda }
5732309Srsmaeda
5742309Srsmaeda static int
drd_rcm_restore_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)5752309Srsmaeda drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
5762309Srsmaeda {
5772309Srsmaeda char **rlist;
5782309Srsmaeda char **full_rlist;
5792309Srsmaeda int idx;
5802309Srsmaeda int ridx;
5812309Srsmaeda int state;
5822309Srsmaeda int rv = 0;
5832309Srsmaeda rcm_info_t *rinfo;
5842309Srsmaeda
5852309Srsmaeda drd_dbg("drd_rcm_restore_cpu_notify...");
5862309Srsmaeda
5872309Srsmaeda if ((full_rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
5882309Srsmaeda DRCTL_STATUS_CONFIG_FAILURE)) == NULL) {
5892309Srsmaeda drd_dbg(" no CPUs in the failed state, nothing to do");
5902309Srsmaeda return (0);
5912309Srsmaeda }
5922309Srsmaeda
5932309Srsmaeda /*
5942309Srsmaeda * Since the desired result of this operation is to
5952309Srsmaeda * restore resources to the online state, filter out
5962309Srsmaeda * the resources already in the online state before
5972309Srsmaeda * passing the list to RCM.
5982309Srsmaeda */
5992309Srsmaeda
6002309Srsmaeda /* allocate a zero filled array to ensure NULL terminated list */
6012309Srsmaeda rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
6022309Srsmaeda if (rlist == NULL) {
6032309Srsmaeda drd_err("calloc failed: %s", strerror(errno));
6042309Srsmaeda rv = -1;
6052309Srsmaeda goto done;
6062309Srsmaeda }
6072309Srsmaeda
6082309Srsmaeda for (idx = 0, ridx = 0; full_rlist[idx] != NULL; idx++) {
6092309Srsmaeda state = 0;
6102309Srsmaeda rcm_get_rsrcstate(rcm_hdl, full_rlist[idx], &state);
6112309Srsmaeda if (state != RCM_STATE_ONLINE) {
6122309Srsmaeda rlist[ridx] = full_rlist[idx];
6132309Srsmaeda ridx++;
6142309Srsmaeda }
6152309Srsmaeda }
6162309Srsmaeda
6172309Srsmaeda /* check if everything got filtered out */
6182309Srsmaeda if (ridx == 0) {
6192309Srsmaeda drd_dbg(" all CPUs already online, nothing to do");
6202309Srsmaeda goto done;
6212309Srsmaeda }
6222309Srsmaeda
6232309Srsmaeda rv = rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
6242309Srsmaeda if (rv != RCM_SUCCESS) {
6252309Srsmaeda drd_info("rcm_notify_online_list failed: %d", rv);
6262309Srsmaeda rcm_free_info(rinfo);
6272309Srsmaeda rv = -1;
6282309Srsmaeda }
6292309Srsmaeda
6302309Srsmaeda done:
6312309Srsmaeda drd_rcm_cpu_rlist_fini(full_rlist);
6322309Srsmaeda s_free(rlist);
6332309Srsmaeda
6342309Srsmaeda return (rv);
6352309Srsmaeda }
6362309Srsmaeda
6372309Srsmaeda static int
drd_rcm_del_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)6382309Srsmaeda drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
6392309Srsmaeda {
6402309Srsmaeda cpuid_t *cpus = NULL;
6412309Srsmaeda int rv = -1;
6422309Srsmaeda cpuid_t *oldcpus = NULL;
6432309Srsmaeda cpuid_t *newcpus = NULL;
6442309Srsmaeda int oldncpus = 0;
6452309Srsmaeda int newncpus = 0;
6462309Srsmaeda nvlist_t *nvl = NULL;
6472309Srsmaeda int idx;
6482309Srsmaeda int cidx;
6492309Srsmaeda rcm_info_t *rinfo;
6502309Srsmaeda
6512309Srsmaeda drd_dbg("drd_rcm_del_cpu_notify...");
6522309Srsmaeda
6532309Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) {
6542309Srsmaeda drd_err("del_cpu_notify: cpu list empty");
6552309Srsmaeda goto done;
6562309Srsmaeda }
6572309Srsmaeda
6582309Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
6592309Srsmaeda
6602309Srsmaeda /*
6612309Srsmaeda * Filter out the CPUs that could not be unconfigured.
6622309Srsmaeda */
6632309Srsmaeda for (idx = 0, cidx = 0; idx < nrsrc; idx++) {
6642309Srsmaeda if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
6652309Srsmaeda continue;
6662309Srsmaeda drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
6672309Srsmaeda cpus[cidx] = rsrcs[idx].res_cpu_id;
6682309Srsmaeda cidx++;
6692309Srsmaeda }
6702309Srsmaeda
6712309Srsmaeda drd_dbg(" ncpus = %d", cidx);
6722309Srsmaeda
6732309Srsmaeda /* nothing to do */
6742309Srsmaeda if (cidx == 0) {
6752309Srsmaeda rv = 0;
6762309Srsmaeda goto done;
6772309Srsmaeda }
6782309Srsmaeda
6792309Srsmaeda /* allocate an nvlist for the RCM call */
6802309Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
6812309Srsmaeda goto done;
6822309Srsmaeda }
6832309Srsmaeda
6842309Srsmaeda /*
6852309Srsmaeda * Removed CPU capacity, so newcpus is the current list
6862309Srsmaeda * of CPUs in the system.
6872309Srsmaeda */
6882309Srsmaeda if (get_sys_cpuids(&newcpus, &newncpus) == -1) {
6892309Srsmaeda goto done;
6902309Srsmaeda }
6912309Srsmaeda
6922309Srsmaeda /*
6932309Srsmaeda * Since the operation removed CPU capacity, the old CPU
6942309Srsmaeda * list is the new CPU list with the CPUs involved in
6952309Srsmaeda * the operation added.
6962309Srsmaeda */
6972309Srsmaeda oldcpus = (cpuid_t *)calloc(newncpus + cidx, sizeof (cpuid_t));
6982309Srsmaeda if (oldcpus == NULL) {
6992309Srsmaeda goto done;
7002309Srsmaeda }
7012309Srsmaeda
7022309Srsmaeda for (idx = 0; idx < newncpus; idx++) {
7032309Srsmaeda if (!is_cpu_in_list(newcpus[idx], cpus, cidx))
7042309Srsmaeda oldcpus[oldncpus++] = newcpus[idx];
7052309Srsmaeda }
7062309Srsmaeda
7072309Srsmaeda for (idx = 0; idx < cidx; idx++) {
7082309Srsmaeda oldcpus[oldncpus++] = cpus[idx];
7092309Srsmaeda }
7102309Srsmaeda
7112309Srsmaeda /* dump pre and post lists */
7122309Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
7132309Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus);
7142309Srsmaeda dump_cpu_list("delta: ", cpus, cidx);
7152309Srsmaeda
7162309Srsmaeda /* setup the nvlist for the RCM call */
7172309Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") ||
7182309Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) ||
7192309Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) ||
7202309Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
7212309Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
7222309Srsmaeda goto done;
7232309Srsmaeda }
7242309Srsmaeda
7252309Srsmaeda rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
7262309Srsmaeda rv = (rv == RCM_SUCCESS) ? 0 : -1;
7272309Srsmaeda
7282309Srsmaeda done:
7292309Srsmaeda s_nvfree(nvl);
7302309Srsmaeda s_free(cpus);
7312309Srsmaeda s_free(oldcpus);
7322309Srsmaeda s_free(newcpus);
7332309Srsmaeda
7342309Srsmaeda return (rv);
7352309Srsmaeda }
7362309Srsmaeda
7372309Srsmaeda /*
7382309Srsmaeda * Given a list of resource structures, create a list of CPU
7392309Srsmaeda * resource strings formatted as expected by RCM. Only resources
7402309Srsmaeda * that are in the state specified by the status argument are
7412309Srsmaeda * included in the resulting list.
7422309Srsmaeda */
7432309Srsmaeda static char **
drd_rcm_cpu_rlist_init(drctl_rsrc_t * rsrcs,int nrsrc,int status)7442309Srsmaeda drd_rcm_cpu_rlist_init(drctl_rsrc_t *rsrcs, int nrsrc, int status)
7452309Srsmaeda {
7462309Srsmaeda char rbuf[RCM_CPU_MAX_LEN];
7472309Srsmaeda char **rlist;
7482309Srsmaeda int idx;
7492309Srsmaeda int ridx;
7502309Srsmaeda
7512309Srsmaeda drd_dbg("drd_rcm_cpu_rlist_init...");
7522309Srsmaeda
7532309Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) {
7542309Srsmaeda drd_dbg("cpu list is empty");
7552309Srsmaeda return (NULL);
7562309Srsmaeda }
7572309Srsmaeda
7582309Srsmaeda /* allocate a zero filled array to ensure NULL terminated list */
7592309Srsmaeda rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
7602309Srsmaeda if (rlist == NULL) {
7612309Srsmaeda drd_err("calloc failed: %s", strerror(errno));
7622309Srsmaeda return (NULL);
7632309Srsmaeda }
7642309Srsmaeda
7652309Srsmaeda for (idx = 0, ridx = 0; idx < nrsrc; idx++) {
7662309Srsmaeda
7672309Srsmaeda drd_dbg(" checking cpu %d, status=%d, expected status=%d",
7682309Srsmaeda rsrcs[idx].res_cpu_id, rsrcs[idx].status, status);
7692309Srsmaeda
7702309Srsmaeda /*
7712309Srsmaeda * Filter out the CPUs that are not in
7722309Srsmaeda * the requested state.
7732309Srsmaeda */
7742309Srsmaeda if (rsrcs[idx].status != status)
7752309Srsmaeda continue;
7762309Srsmaeda
7772309Srsmaeda /* generate the resource string */
7782309Srsmaeda (void) sprintf(rbuf, "%s%d", RCM_CPU, rsrcs[idx].res_cpu_id);
7792309Srsmaeda
7802309Srsmaeda rlist[ridx] = strdup(rbuf);
7812309Srsmaeda if (rlist[ridx] == NULL) {
7822309Srsmaeda drd_err("strdup failed: %s", strerror(errno));
7832309Srsmaeda drd_rcm_cpu_rlist_fini(rlist);
7842309Srsmaeda return (NULL);
7852309Srsmaeda }
7862309Srsmaeda
7872309Srsmaeda ridx++;
7882309Srsmaeda }
7892309Srsmaeda
7902309Srsmaeda /* cleanup if the list is empty */
7912309Srsmaeda if (ridx == 0) {
7922309Srsmaeda s_free(rlist);
7932309Srsmaeda }
7942309Srsmaeda
7952309Srsmaeda drd_dbg("final rlist:");
7962309Srsmaeda dump_cpu_rlist(rlist);
7972309Srsmaeda
7982309Srsmaeda return (rlist);
7992309Srsmaeda }
8002309Srsmaeda
8012309Srsmaeda static void
drd_rcm_cpu_rlist_fini(char ** rlist)8022309Srsmaeda drd_rcm_cpu_rlist_fini(char **rlist)
8032309Srsmaeda {
8042309Srsmaeda int idx;
8052309Srsmaeda
8062309Srsmaeda drd_dbg("drd_rcm_cpu_rlist_fini...");
8072309Srsmaeda
8082309Srsmaeda dump_cpu_rlist(rlist);
8092309Srsmaeda
8102309Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) {
8112309Srsmaeda s_free(rlist[idx]);
8122309Srsmaeda }
8132309Srsmaeda
8142309Srsmaeda s_free(rlist);
8152309Srsmaeda }
8162309Srsmaeda
8172309Srsmaeda /*
8182309Srsmaeda * Convert an RCM CPU resource string into a numerical cpuid.
8192309Srsmaeda * Assumes the resource string has the form: "SUNW_cpu/cpu<C>"
8202309Srsmaeda * where "<C>" is the numerical cpuid of interest.
8212309Srsmaeda */
8222309Srsmaeda static cpuid_t
cpu_rsrcstr_to_cpuid(const char * rsrc)8232309Srsmaeda cpu_rsrcstr_to_cpuid(const char *rsrc)
8242309Srsmaeda {
8252309Srsmaeda char *cpuid_off;
8262309Srsmaeda cpuid_t cpuid;
8272309Srsmaeda
8282309Srsmaeda /*
8292309Srsmaeda * Search for the last occurrance of 'u' in the
8302309Srsmaeda * expected RCM resource string "SUNW_cpu/cpu<C>".
8312309Srsmaeda * This will give a pointer to the cpuid portion.
8322309Srsmaeda */
8332309Srsmaeda cpuid_off = strrchr(rsrc, 'u');
8342309Srsmaeda cpuid_off++;
8352309Srsmaeda
8362309Srsmaeda cpuid = atoi(cpuid_off);
8372309Srsmaeda
8382309Srsmaeda return (cpuid);
8392309Srsmaeda }
8402309Srsmaeda
8412309Srsmaeda /*
8422309Srsmaeda * Given an RCM CPU resource string, return a pointer to the
8432309Srsmaeda * corresponding resource structure from the given resource list.
8442309Srsmaeda * NULL is returned if no matching resource structure can be
8452309Srsmaeda * found.
8462309Srsmaeda */
8472309Srsmaeda static drctl_rsrc_t *
cpu_rsrcstr_to_rsrc(const char * rsrcstr,drctl_rsrc_t * rsrcs,int nrsrc)8482309Srsmaeda cpu_rsrcstr_to_rsrc(const char *rsrcstr, drctl_rsrc_t *rsrcs, int nrsrc)
8492309Srsmaeda {
8502309Srsmaeda cpuid_t cpuid;
8512309Srsmaeda int idx;
8522309Srsmaeda
8532309Srsmaeda cpuid = cpu_rsrcstr_to_cpuid(rsrcstr);
8542309Srsmaeda
8552309Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
8562309Srsmaeda if (rsrcs[idx].res_cpu_id == cpuid)
8572309Srsmaeda return (&rsrcs[idx]);
8582309Srsmaeda }
8592309Srsmaeda
8602309Srsmaeda return (NULL);
8612309Srsmaeda }
8622309Srsmaeda
8632309Srsmaeda static int
get_sys_cpuids(cpuid_t ** cpuids,int * ncpuids)8642309Srsmaeda get_sys_cpuids(cpuid_t **cpuids, int *ncpuids)
8652309Srsmaeda {
8662309Srsmaeda int ncpu = 0;
8672309Srsmaeda int maxncpu;
8682309Srsmaeda kstat_t *ksp;
8692309Srsmaeda kstat_ctl_t *kc = NULL;
8702309Srsmaeda cpuid_t *cp;
8712309Srsmaeda
8722309Srsmaeda drd_dbg("get_sys_cpuids...");
8732309Srsmaeda
8742309Srsmaeda if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1)
8752309Srsmaeda return (-1);
8762309Srsmaeda
8772309Srsmaeda if ((kc = kstat_open()) == NULL)
8782309Srsmaeda return (-1);
8792309Srsmaeda
8802309Srsmaeda if ((cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) {
8812309Srsmaeda (void) kstat_close(kc);
8822309Srsmaeda return (-1);
8832309Srsmaeda }
8842309Srsmaeda
8852309Srsmaeda for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
8862309Srsmaeda if (strcmp(ksp->ks_module, "cpu_info") == 0)
8872309Srsmaeda cp[ncpu++] = ksp->ks_instance;
8882309Srsmaeda }
8892309Srsmaeda
8902309Srsmaeda dump_cpu_list("syscpus: ", cp, ncpu);
8912309Srsmaeda
8922309Srsmaeda (void) kstat_close(kc);
8932309Srsmaeda
8942309Srsmaeda *cpuids = cp;
8952309Srsmaeda *ncpuids = ncpu;
8962309Srsmaeda
8972309Srsmaeda return (0);
8982309Srsmaeda }
8992309Srsmaeda
9002309Srsmaeda static boolean_t
is_cpu_in_list(cpuid_t cpuid,cpuid_t * list,int len)9012309Srsmaeda is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len)
9022309Srsmaeda {
9032309Srsmaeda int idx;
9042309Srsmaeda
9052309Srsmaeda if (list == NULL)
9062309Srsmaeda return (B_FALSE);
9072309Srsmaeda
9082309Srsmaeda for (idx = 0; idx < len; idx++) {
9092309Srsmaeda if (list[idx] == cpuid)
9102309Srsmaeda return (B_TRUE);
9112309Srsmaeda }
9122309Srsmaeda
9132309Srsmaeda return (B_FALSE);
9142309Srsmaeda }
9152309Srsmaeda
9162309Srsmaeda #define CPUIDS_PER_LINE 16
9172309Srsmaeda #define LINEWIDTH (2 * (CPUIDS_PER_LINE * 4))
9182309Srsmaeda
9192309Srsmaeda static void
dump_cpu_list(char * prefix,cpuid_t * cpuids,int ncpuids)9202309Srsmaeda dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids)
9212309Srsmaeda {
9222309Srsmaeda char line[LINEWIDTH];
9232309Srsmaeda char *curr;
9242309Srsmaeda int i, j;
9252309Srsmaeda
9262309Srsmaeda /* return if not debugging */
9272309Srsmaeda if (drd_debug == 0)
9282309Srsmaeda return;
9292309Srsmaeda
9302309Srsmaeda /* print just the prefix if CPU list is empty */
9312309Srsmaeda if (ncpuids == 0) {
9322309Srsmaeda if (prefix)
9332309Srsmaeda drd_dbg("%s", prefix);
9342309Srsmaeda return;
9352309Srsmaeda }
9362309Srsmaeda
9372309Srsmaeda for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) {
9382309Srsmaeda
9392309Srsmaeda bzero(line, LINEWIDTH);
9402309Srsmaeda curr = line;
9412309Srsmaeda
9422309Srsmaeda /* start with the prefix */
9432309Srsmaeda (void) sprintf(curr, "%s", (prefix) ? prefix : "");
9442309Srsmaeda curr = line + strlen(line);
9452309Srsmaeda
9462309Srsmaeda /* format the CPUs for this line */
9472309Srsmaeda for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) {
9482309Srsmaeda (void) sprintf(curr, "%3d ", cpuids[i + j]);
9492309Srsmaeda curr = line + strlen(line);
9502309Srsmaeda }
9512309Srsmaeda
9522309Srsmaeda drd_dbg("%s", line);
9532309Srsmaeda }
9542309Srsmaeda }
9552309Srsmaeda
9562309Srsmaeda static void
dump_cpu_rsrc_list(char * prefix,drctl_rsrc_t * rsrcs,int nrsrc)9572309Srsmaeda dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
9582309Srsmaeda {
9592309Srsmaeda int idx;
9602309Srsmaeda char *errstr;
9612309Srsmaeda
9622309Srsmaeda /* just return if not debugging */
9632309Srsmaeda if (drd_debug == 0)
9642309Srsmaeda return;
9652309Srsmaeda
9662309Srsmaeda if (prefix)
9672309Srsmaeda drd_dbg("%s", prefix);
9682309Srsmaeda
9692309Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
9702309Srsmaeda
9712309Srsmaeda /* get a pointer to the error string */
9722309Srsmaeda errstr = (char *)(uintptr_t)rsrcs[idx].offset;
9732309Srsmaeda
9742309Srsmaeda drd_dbg(" cpu[%d]: cpuid=%d, status=%d, errstr='%s'", idx,
9752309Srsmaeda rsrcs[idx].res_cpu_id, rsrcs[idx].status,
9762309Srsmaeda (errstr != NULL) ? errstr : "");
9772309Srsmaeda }
9782309Srsmaeda }
9792309Srsmaeda
9802309Srsmaeda static void
dump_cpu_rlist(char ** rlist)9812309Srsmaeda dump_cpu_rlist(char **rlist)
9822309Srsmaeda {
9832309Srsmaeda int idx;
9842309Srsmaeda int state;
9852309Srsmaeda
9862309Srsmaeda static char *rcm_state_str[] = {
9872309Srsmaeda "UNKNOWN", "ONLINE", "ONLINING",
9882309Srsmaeda "OFFLINE_FAIL", "OFFLINING", "OFFLINE",
9892309Srsmaeda "REMOVING", "INVALID_7", "INVALID_8",
9902309Srsmaeda "INVALID_9", "RESUMING", "SUSPEND_FAIL",
9912309Srsmaeda "SUSPENDING", "SUSPEND", "REMOVE",
9922309Srsmaeda "OFFLINE_QUERYING", "OFFLINE_QUERY_FAIL", "OFFLINE_QUERY",
9932309Srsmaeda "SUSPEND_QUERYING", "SUSPEND_QUERY_FAIL", "SUSPEND_QUERY"
9942309Srsmaeda };
9952309Srsmaeda
9962309Srsmaeda /* just return if not debugging */
9972309Srsmaeda if (drd_debug == 0)
9982309Srsmaeda return;
9992309Srsmaeda
10002309Srsmaeda if (rlist == NULL) {
10012309Srsmaeda drd_dbg(" empty rlist");
10022309Srsmaeda return;
10032309Srsmaeda }
10042309Srsmaeda
10052309Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) {
10062309Srsmaeda state = 0;
10072309Srsmaeda rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
10082309Srsmaeda drd_dbg(" rlist[%d]: rsrc=%s, state=%-2d (%s)", idx,
10092309Srsmaeda rlist[idx], state, rcm_state_str[state]);
10102309Srsmaeda }
10112309Srsmaeda }
10126441Sjm22469
10136441Sjm22469 static int
drd_rcm_io_config_request(drctl_rsrc_t * rsrc,int nrsrc)10146441Sjm22469 drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc)
10156441Sjm22469 {
10166441Sjm22469 drd_dbg("drd_rcm_io_config_request...");
10176441Sjm22469
10186441Sjm22469 if (nrsrc != 1) {
10196441Sjm22469 drd_dbg("drd_rcm_cpu_config_request: only 1 resource "
10206441Sjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc);
10216441Sjm22469 rsrc->status = DRCTL_STATUS_DENY;
10226441Sjm22469
10236441Sjm22469 return (-1);
10246441Sjm22469 }
10256441Sjm22469
10266441Sjm22469 /*
10276441Sjm22469 * There is no RCM operation to request the addition
10286441Sjm22469 * of resources. So, by definition, the operation for
10296441Sjm22469 * the current resource is allowed.
10306441Sjm22469 */
10316441Sjm22469 rsrc->status = DRCTL_STATUS_ALLOW;
10326441Sjm22469
10336441Sjm22469 return (0);
10346441Sjm22469 }
10356441Sjm22469
10366441Sjm22469 /*ARGSUSED*/
10376441Sjm22469 static int
drd_rcm_io_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)10386441Sjm22469 drd_rcm_io_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
10396441Sjm22469 {
10406441Sjm22469 drd_dbg("drd_rcm_io_config_notify...");
10416441Sjm22469
10426441Sjm22469 if (nrsrc != 1) {
10436441Sjm22469 drd_dbg("drd_rcm_cpu_config_notify: only 1 resource "
10446441Sjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc);
10456441Sjm22469
10466441Sjm22469 return (-1);
10476441Sjm22469 }
10486441Sjm22469
10496441Sjm22469 return (0);
10506441Sjm22469 }
10516441Sjm22469
10526441Sjm22469
10536441Sjm22469 static int
drd_rcm_io_unconfig_request(drctl_rsrc_t * rsrc,int nrsrc)10546441Sjm22469 drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc)
10556441Sjm22469 {
10566441Sjm22469 int rv;
10576441Sjm22469 char *dev = rsrc->res_dev_path;
10586441Sjm22469 rcm_info_t *rinfo = NULL;
10596441Sjm22469
10606441Sjm22469 if (nrsrc != 1) {
10616441Sjm22469 drd_dbg("drd_io_unconfig_request: only 1 resource "
10626441Sjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc);
10636441Sjm22469 rsrc->status = DRCTL_STATUS_DENY;
10646441Sjm22469
10656441Sjm22469 return (-1);
10666441Sjm22469 }
10676441Sjm22469
10686441Sjm22469 if ((rv = rcm_request_offline(rcm_hdl, dev, 0, &rinfo)) == RCM_SUCCESS)
10696441Sjm22469 rsrc->status = DRCTL_STATUS_ALLOW;
10706441Sjm22469 else {
10716441Sjm22469 rcm_notify_online(rcm_hdl, dev, 0, NULL);
10726441Sjm22469 rsrc->status = DRCTL_STATUS_DENY;
10736441Sjm22469 rsrc->offset = (uintptr_t)rcm_info_table(rinfo);
10746441Sjm22469
10756441Sjm22469 }
10766441Sjm22469
10776441Sjm22469 rcm_free_info(rinfo);
10786441Sjm22469 drd_dbg("drd_rcm_io_unconfig_request(%s) = %d", dev, rv);
10796441Sjm22469
10806441Sjm22469 return (rv);
10816441Sjm22469 }
10826441Sjm22469
10836441Sjm22469 static int
drd_rcm_io_unconfig_notify(drctl_rsrc_t * rsrc,int nrsrc)10846441Sjm22469 drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc)
10856441Sjm22469 {
10866441Sjm22469 drd_dbg("drd_rcm_io_unconfig_notify...");
10876441Sjm22469
10886441Sjm22469 if (nrsrc != 1) {
10896441Sjm22469 drd_dbg("drd_io_cpu_unconfig_notify: only 1 resource "
10906441Sjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc);
10916441Sjm22469
10926441Sjm22469 return (-1);
10936441Sjm22469 }
10946441Sjm22469
10956441Sjm22469 return (rcm_notify_remove(rcm_hdl, rsrc->res_dev_path, 0, NULL));
10966441Sjm22469 }
10976441Sjm22469
10986441Sjm22469 #define MAX_FORMAT 80
10996441Sjm22469
11006441Sjm22469 /*
11016441Sjm22469 * Convert rcm_info_t data into a printable table.
11026441Sjm22469 */
11036441Sjm22469 static char *
rcm_info_table(rcm_info_t * rinfo)11046441Sjm22469 rcm_info_table(rcm_info_t *rinfo)
11056441Sjm22469 {
11066441Sjm22469 int i;
11076441Sjm22469 size_t w;
11086441Sjm22469 size_t width = 0;
11096441Sjm22469 size_t w_rsrc = 0;
11106441Sjm22469 size_t w_info = 0;
11116441Sjm22469 size_t table_size = 0;
11126441Sjm22469 uint_t tuples = 0;
11136441Sjm22469 rcm_info_tuple_t *tuple = NULL;
11146441Sjm22469 char *rsrc;
11156441Sjm22469 char *info;
11166441Sjm22469 char *table;
11176441Sjm22469 static char format[MAX_FORMAT];
11186441Sjm22469 const char *infostr;
11196441Sjm22469
11206441Sjm22469 /* Protect against invalid arguments */
11216441Sjm22469 if (rinfo == NULL)
11226441Sjm22469 return (NULL);
11236441Sjm22469
11246441Sjm22469 /* Set localized table header strings */
11256441Sjm22469 rsrc = dgettext(TEXT_DOMAIN, "Resource");
11266441Sjm22469 info = dgettext(TEXT_DOMAIN, "Information");
11276441Sjm22469
11286441Sjm22469 /* A first pass, to size up the RCM information */
11296441Sjm22469 while (tuple = rcm_info_next(rinfo, tuple)) {
11306441Sjm22469 if ((infostr = rcm_info_info(tuple)) != NULL) {
11316441Sjm22469 tuples++;
11326441Sjm22469 if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
11336441Sjm22469 w_rsrc = w;
11346441Sjm22469 if ((w = strlen(infostr)) > w_info)
11356441Sjm22469 w_info = w;
11366441Sjm22469 }
11376441Sjm22469 }
11386441Sjm22469
11396441Sjm22469 /* If nothing was sized up above, stop early */
11406441Sjm22469 if (tuples == 0)
11416441Sjm22469 return (NULL);
11426441Sjm22469
11436441Sjm22469 /* Adjust column widths for column headings */
11446441Sjm22469 if ((w = strlen(rsrc)) > w_rsrc)
11456441Sjm22469 w_rsrc = w;
11466441Sjm22469 else if ((w_rsrc - w) % 2)
11476441Sjm22469 w_rsrc++;
11486441Sjm22469 if ((w = strlen(info)) > w_info)
11496441Sjm22469 w_info = w;
11506441Sjm22469 else if ((w_info - w) % 2)
11516441Sjm22469 w_info++;
11526441Sjm22469
11536441Sjm22469 /*
11546441Sjm22469 * Compute the total line width of each line,
11556441Sjm22469 * accounting for intercolumn spacing.
11566441Sjm22469 */
11576441Sjm22469 width = w_info + w_rsrc + 4;
11586441Sjm22469
11596441Sjm22469 /* Allocate space for the table */
11606441Sjm22469 table_size = (2 + tuples) * (width + 1) + 2;
11616441Sjm22469
11626441Sjm22469 /* zero fill for the strcat() call below */
11636441Sjm22469 table = calloc(table_size, sizeof (char));
11646441Sjm22469 if (table == NULL)
11656441Sjm22469 return (NULL);
11666441Sjm22469
11676441Sjm22469 /* Place a table header into the string */
11686441Sjm22469
11696441Sjm22469 /* The resource header */
11706441Sjm22469 (void) strcat(table, "\n");
11716441Sjm22469 w = strlen(rsrc);
11726441Sjm22469 for (i = 0; i < ((w_rsrc - w) / 2); i++)
11736441Sjm22469 (void) strcat(table, " ");
11746441Sjm22469 (void) strcat(table, rsrc);
11756441Sjm22469 for (i = 0; i < ((w_rsrc - w) / 2); i++)
11766441Sjm22469 (void) strcat(table, " ");
11776441Sjm22469
11786441Sjm22469 /* The information header */
11796441Sjm22469 (void) strcat(table, " ");
11806441Sjm22469 w = strlen(info);
11816441Sjm22469 for (i = 0; i < ((w_info - w) / 2); i++)
11826441Sjm22469 (void) strcat(table, " ");
11836441Sjm22469 (void) strcat(table, info);
11846441Sjm22469 for (i = 0; i < ((w_info - w) / 2); i++)
11856441Sjm22469 (void) strcat(table, " ");
11866441Sjm22469 /* Underline the headers */
11876441Sjm22469 (void) strcat(table, "\n");
11886441Sjm22469 for (i = 0; i < w_rsrc; i++)
11896441Sjm22469 (void) strcat(table, "-");
11906441Sjm22469 (void) strcat(table, " ");
11916441Sjm22469 for (i = 0; i < w_info; i++)
11926441Sjm22469 (void) strcat(table, "-");
11936441Sjm22469
11946441Sjm22469 /* Construct the format string */
11956441Sjm22469 (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds",
11966441Sjm22469 (int)w_rsrc, (int)w_info);
11976441Sjm22469
11986441Sjm22469 /* Add the tuples to the table string */
11996441Sjm22469 tuple = NULL;
12006441Sjm22469 while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
12016441Sjm22469 if ((infostr = rcm_info_info(tuple)) != NULL) {
12026441Sjm22469 (void) strcat(table, "\n");
12036441Sjm22469 (void) sprintf(&((table)[strlen(table)]),
12046441Sjm22469 format, rcm_info_rsrc(tuple),
12056441Sjm22469 infostr);
12066441Sjm22469 }
12076441Sjm22469 }
12086441Sjm22469 drd_dbg("rcm_info_table: %s\n", table);
12096441Sjm22469
12106441Sjm22469 return (table);
12116441Sjm22469 }
1212*10106SJason.Beloro@Sun.COM
1213*10106SJason.Beloro@Sun.COM static void
dump_mem_rsrc_list(char * prefix,drctl_rsrc_t * rsrcs,int nrsrc)1214*10106SJason.Beloro@Sun.COM dump_mem_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
1215*10106SJason.Beloro@Sun.COM {
1216*10106SJason.Beloro@Sun.COM int idx;
1217*10106SJason.Beloro@Sun.COM char *errstr;
1218*10106SJason.Beloro@Sun.COM
1219*10106SJason.Beloro@Sun.COM /* just return if not debugging */
1220*10106SJason.Beloro@Sun.COM if (drd_debug == 0)
1221*10106SJason.Beloro@Sun.COM return;
1222*10106SJason.Beloro@Sun.COM
1223*10106SJason.Beloro@Sun.COM if (prefix)
1224*10106SJason.Beloro@Sun.COM drd_dbg("%s", prefix);
1225*10106SJason.Beloro@Sun.COM
1226*10106SJason.Beloro@Sun.COM for (idx = 0; idx < nrsrc; idx++) {
1227*10106SJason.Beloro@Sun.COM
1228*10106SJason.Beloro@Sun.COM /* get a pointer to the error string */
1229*10106SJason.Beloro@Sun.COM errstr = (char *)(uintptr_t)rsrcs[idx].offset;
1230*10106SJason.Beloro@Sun.COM
1231*10106SJason.Beloro@Sun.COM drd_dbg(" mem[%d]: addr=0x%llx, size=0x%llx"
1232*10106SJason.Beloro@Sun.COM " status=%d, errstr='%s'", idx,
1233*10106SJason.Beloro@Sun.COM rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size,
1234*10106SJason.Beloro@Sun.COM rsrcs[idx].status, (errstr != NULL) ? errstr : "");
1235*10106SJason.Beloro@Sun.COM }
1236*10106SJason.Beloro@Sun.COM }
1237*10106SJason.Beloro@Sun.COM
1238*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_op(rcm_op_t op,uint64_t change)1239*10106SJason.Beloro@Sun.COM drd_rcm_mem_op(rcm_op_t op, uint64_t change)
1240*10106SJason.Beloro@Sun.COM {
1241*10106SJason.Beloro@Sun.COM int rv = -1;
1242*10106SJason.Beloro@Sun.COM int pgsize;
1243*10106SJason.Beloro@Sun.COM long oldpages;
1244*10106SJason.Beloro@Sun.COM long newpages;
1245*10106SJason.Beloro@Sun.COM nvlist_t *nvl = NULL;
1246*10106SJason.Beloro@Sun.COM rcm_info_t *rinfo;
1247*10106SJason.Beloro@Sun.COM
1248*10106SJason.Beloro@Sun.COM /* allocate an nvlist for the RCM call */
1249*10106SJason.Beloro@Sun.COM if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1250*10106SJason.Beloro@Sun.COM goto done;
1251*10106SJason.Beloro@Sun.COM
1252*10106SJason.Beloro@Sun.COM if ((pgsize = sysconf(_SC_PAGE_SIZE)) == -1 ||
1253*10106SJason.Beloro@Sun.COM (newpages = sysconf(_SC_PHYS_PAGES)) == -1)
1254*10106SJason.Beloro@Sun.COM goto done;
1255*10106SJason.Beloro@Sun.COM
1256*10106SJason.Beloro@Sun.COM /*
1257*10106SJason.Beloro@Sun.COM * If this is a notify add, the capacity change
1258*10106SJason.Beloro@Sun.COM * was positive and the current page count reflects
1259*10106SJason.Beloro@Sun.COM * the new capacity level.
1260*10106SJason.Beloro@Sun.COM *
1261*10106SJason.Beloro@Sun.COM * If this is a request del, the capacity change
1262*10106SJason.Beloro@Sun.COM * is negative and the current page count will
1263*10106SJason.Beloro@Sun.COM * reflect the old capacity level.
1264*10106SJason.Beloro@Sun.COM */
1265*10106SJason.Beloro@Sun.COM assert(change % pgsize == 0);
1266*10106SJason.Beloro@Sun.COM if (change > 0) {
1267*10106SJason.Beloro@Sun.COM oldpages = newpages - (long)(change / pgsize);
1268*10106SJason.Beloro@Sun.COM } else {
1269*10106SJason.Beloro@Sun.COM assert(newpages >= change / pgsize);
1270*10106SJason.Beloro@Sun.COM oldpages = newpages;
1271*10106SJason.Beloro@Sun.COM newpages = oldpages + (long)(change / pgsize);
1272*10106SJason.Beloro@Sun.COM }
1273*10106SJason.Beloro@Sun.COM
1274*10106SJason.Beloro@Sun.COM drd_dbg("oldpages=%lld newpages=%lld delta=%lld",
1275*10106SJason.Beloro@Sun.COM oldpages, newpages, newpages - oldpages);
1276*10106SJason.Beloro@Sun.COM
1277*10106SJason.Beloro@Sun.COM /* setup the nvlist for the RCM call */
1278*10106SJason.Beloro@Sun.COM if (nvlist_add_string(nvl, "state", "capacity") != 0 ||
1279*10106SJason.Beloro@Sun.COM nvlist_add_int32(nvl, "page_size", pgsize) != 0 ||
1280*10106SJason.Beloro@Sun.COM nvlist_add_int32(nvl, "old_pages", oldpages) != 0 ||
1281*10106SJason.Beloro@Sun.COM nvlist_add_int32(nvl, "new_pages", newpages) != 0) {
1282*10106SJason.Beloro@Sun.COM goto done;
1283*10106SJason.Beloro@Sun.COM }
1284*10106SJason.Beloro@Sun.COM
1285*10106SJason.Beloro@Sun.COM rv = (*op)(rcm_hdl, RCM_MEM_ALL, 0, nvl, &rinfo);
1286*10106SJason.Beloro@Sun.COM rv = (rv == RCM_SUCCESS) ? 0 : -1;
1287*10106SJason.Beloro@Sun.COM
1288*10106SJason.Beloro@Sun.COM done:
1289*10106SJason.Beloro@Sun.COM s_nvfree(nvl);
1290*10106SJason.Beloro@Sun.COM
1291*10106SJason.Beloro@Sun.COM return (rv);
1292*10106SJason.Beloro@Sun.COM }
1293*10106SJason.Beloro@Sun.COM
1294*10106SJason.Beloro@Sun.COM /*
1295*10106SJason.Beloro@Sun.COM * RCM clients can interpose only on removal of resources.
1296*10106SJason.Beloro@Sun.COM */
1297*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_config_request(drctl_rsrc_t * rsrcs,int nrsrc)1298*10106SJason.Beloro@Sun.COM drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
1299*10106SJason.Beloro@Sun.COM {
1300*10106SJason.Beloro@Sun.COM int idx;
1301*10106SJason.Beloro@Sun.COM
1302*10106SJason.Beloro@Sun.COM drd_dbg("drd_rcm_mem_config_request...");
1303*10106SJason.Beloro@Sun.COM
1304*10106SJason.Beloro@Sun.COM if ((rsrcs == NULL) || (nrsrc == 0))
1305*10106SJason.Beloro@Sun.COM return (0);
1306*10106SJason.Beloro@Sun.COM dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1307*10106SJason.Beloro@Sun.COM
1308*10106SJason.Beloro@Sun.COM /*
1309*10106SJason.Beloro@Sun.COM * There is no RCM operation to request the addition
1310*10106SJason.Beloro@Sun.COM * of resources. So, by definition, the operation for
1311*10106SJason.Beloro@Sun.COM * all the memory is allowed.
1312*10106SJason.Beloro@Sun.COM */
1313*10106SJason.Beloro@Sun.COM for (idx = 0; idx < nrsrc; idx++)
1314*10106SJason.Beloro@Sun.COM rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1315*10106SJason.Beloro@Sun.COM
1316*10106SJason.Beloro@Sun.COM dump_mem_rsrc_list("returning:", rsrcs, nrsrc);
1317*10106SJason.Beloro@Sun.COM
1318*10106SJason.Beloro@Sun.COM return (0);
1319*10106SJason.Beloro@Sun.COM }
1320*10106SJason.Beloro@Sun.COM
1321*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)1322*10106SJason.Beloro@Sun.COM drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1323*10106SJason.Beloro@Sun.COM {
1324*10106SJason.Beloro@Sun.COM int idx;
1325*10106SJason.Beloro@Sun.COM int rv = -1;
1326*10106SJason.Beloro@Sun.COM uint64_t change = 0;
1327*10106SJason.Beloro@Sun.COM
1328*10106SJason.Beloro@Sun.COM drd_dbg("drd_rcm_mem_config_notify...");
1329*10106SJason.Beloro@Sun.COM
1330*10106SJason.Beloro@Sun.COM if ((rsrcs == NULL) || (nrsrc == 0)) {
1331*10106SJason.Beloro@Sun.COM drd_err("mem_config_notify: mem list empty");
1332*10106SJason.Beloro@Sun.COM goto done;
1333*10106SJason.Beloro@Sun.COM }
1334*10106SJason.Beloro@Sun.COM dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1335*10106SJason.Beloro@Sun.COM
1336*10106SJason.Beloro@Sun.COM for (idx = 0; idx < nrsrc; idx++) {
1337*10106SJason.Beloro@Sun.COM if (rsrcs[idx].status == DRCTL_STATUS_CONFIG_SUCCESS)
1338*10106SJason.Beloro@Sun.COM change += rsrcs[idx].res_mem_size;
1339*10106SJason.Beloro@Sun.COM drd_dbg(" idx=%d addr=0x%llx size=0x%llx",
1340*10106SJason.Beloro@Sun.COM idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1341*10106SJason.Beloro@Sun.COM }
1342*10106SJason.Beloro@Sun.COM
1343*10106SJason.Beloro@Sun.COM rv = drd_rcm_mem_op(rcm_notify_capacity_change, change);
1344*10106SJason.Beloro@Sun.COM done:
1345*10106SJason.Beloro@Sun.COM return (rv);
1346*10106SJason.Beloro@Sun.COM }
1347*10106SJason.Beloro@Sun.COM
1348*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_unconfig_request(drctl_rsrc_t * rsrcs,int nrsrc)1349*10106SJason.Beloro@Sun.COM drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
1350*10106SJason.Beloro@Sun.COM {
1351*10106SJason.Beloro@Sun.COM int rv = -1;
1352*10106SJason.Beloro@Sun.COM int idx;
1353*10106SJason.Beloro@Sun.COM uint64_t change = 0;
1354*10106SJason.Beloro@Sun.COM
1355*10106SJason.Beloro@Sun.COM drd_dbg("drd_rcm_del_mem_request...");
1356*10106SJason.Beloro@Sun.COM
1357*10106SJason.Beloro@Sun.COM if ((rsrcs == NULL) || (nrsrc == 0)) {
1358*10106SJason.Beloro@Sun.COM drd_err("mem_unconfig_request: mem list empty");
1359*10106SJason.Beloro@Sun.COM goto done;
1360*10106SJason.Beloro@Sun.COM }
1361*10106SJason.Beloro@Sun.COM dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1362*10106SJason.Beloro@Sun.COM
1363*10106SJason.Beloro@Sun.COM for (idx = 0; idx < nrsrc; idx++) {
1364*10106SJason.Beloro@Sun.COM drd_dbg(" idx=%d addr=0x%llx size=0x%llx",
1365*10106SJason.Beloro@Sun.COM idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1366*10106SJason.Beloro@Sun.COM change += rsrcs[idx].res_mem_size;
1367*10106SJason.Beloro@Sun.COM }
1368*10106SJason.Beloro@Sun.COM
1369*10106SJason.Beloro@Sun.COM rv = drd_rcm_mem_op(rcm_request_capacity_change, -change);
1370*10106SJason.Beloro@Sun.COM
1371*10106SJason.Beloro@Sun.COM if (rv != RCM_SUCCESS) {
1372*10106SJason.Beloro@Sun.COM drd_dbg("RCM call failed: %d", rv);
1373*10106SJason.Beloro@Sun.COM /*
1374*10106SJason.Beloro@Sun.COM * Since the capacity change was blocked, we
1375*10106SJason.Beloro@Sun.COM * mark all mblocks as blocked. It is up to the
1376*10106SJason.Beloro@Sun.COM * user to reframe the query so that it can
1377*10106SJason.Beloro@Sun.COM * succeed.
1378*10106SJason.Beloro@Sun.COM */
1379*10106SJason.Beloro@Sun.COM for (idx = 0; idx < nrsrc; idx++) {
1380*10106SJason.Beloro@Sun.COM rsrcs[idx].status = DRCTL_STATUS_DENY;
1381*10106SJason.Beloro@Sun.COM }
1382*10106SJason.Beloro@Sun.COM
1383*10106SJason.Beloro@Sun.COM /* tack on message to first resource */
1384*10106SJason.Beloro@Sun.COM rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
1385*10106SJason.Beloro@Sun.COM "specified amount of memory");
1386*10106SJason.Beloro@Sun.COM drd_dbg(" unable to remove specified amount of memory");
1387*10106SJason.Beloro@Sun.COM } else {
1388*10106SJason.Beloro@Sun.COM for (idx = 0; idx < nrsrc; idx++)
1389*10106SJason.Beloro@Sun.COM rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1390*10106SJason.Beloro@Sun.COM rv = 0;
1391*10106SJason.Beloro@Sun.COM }
1392*10106SJason.Beloro@Sun.COM
1393*10106SJason.Beloro@Sun.COM done:
1394*10106SJason.Beloro@Sun.COM
1395*10106SJason.Beloro@Sun.COM dump_mem_rsrc_list("returning:", rsrcs, nrsrc);
1396*10106SJason.Beloro@Sun.COM return (rv);
1397*10106SJason.Beloro@Sun.COM }
1398*10106SJason.Beloro@Sun.COM
1399*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_unconfig_notify(drctl_rsrc_t * rsrcs,int nrsrc)1400*10106SJason.Beloro@Sun.COM drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1401*10106SJason.Beloro@Sun.COM {
1402*10106SJason.Beloro@Sun.COM int idx;
1403*10106SJason.Beloro@Sun.COM int rv = -1;
1404*10106SJason.Beloro@Sun.COM uint64_t change = 0;
1405*10106SJason.Beloro@Sun.COM
1406*10106SJason.Beloro@Sun.COM drd_dbg("drd_rcm_mem_unconfig_notify...");
1407*10106SJason.Beloro@Sun.COM
1408*10106SJason.Beloro@Sun.COM if ((rsrcs == NULL) || (nrsrc == 0)) {
1409*10106SJason.Beloro@Sun.COM drd_err("unconfig_mem_notify: mem list empty");
1410*10106SJason.Beloro@Sun.COM goto done;
1411*10106SJason.Beloro@Sun.COM }
1412*10106SJason.Beloro@Sun.COM dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1413*10106SJason.Beloro@Sun.COM
1414*10106SJason.Beloro@Sun.COM /*
1415*10106SJason.Beloro@Sun.COM * Filter out the memory that was configured.
1416*10106SJason.Beloro@Sun.COM *
1417*10106SJason.Beloro@Sun.COM * We need to notify RCM about a memory capacity change
1418*10106SJason.Beloro@Sun.COM * only if the memory unconfigure request wasn't successful
1419*10106SJason.Beloro@Sun.COM * because if both the RCM capacity delete request and the
1420*10106SJason.Beloro@Sun.COM * memory unconfigure succeed, this notify would give a
1421*10106SJason.Beloro@Sun.COM * memory capacity identical to the delete request.
1422*10106SJason.Beloro@Sun.COM */
1423*10106SJason.Beloro@Sun.COM for (idx = 0; idx < nrsrc; idx++) {
1424*10106SJason.Beloro@Sun.COM if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
1425*10106SJason.Beloro@Sun.COM change += rsrcs[idx].res_mem_size;
1426*10106SJason.Beloro@Sun.COM drd_dbg(" idx=%d addr=0x%llx size=0x%llx",
1427*10106SJason.Beloro@Sun.COM idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1428*10106SJason.Beloro@Sun.COM }
1429*10106SJason.Beloro@Sun.COM
1430*10106SJason.Beloro@Sun.COM rv = drd_rcm_mem_op(rcm_notify_capacity_change, change);
1431*10106SJason.Beloro@Sun.COM done:
1432*10106SJason.Beloro@Sun.COM return (rv);
1433*10106SJason.Beloro@Sun.COM }
1434