11d4b38e0Srsmaeda /*
21d4b38e0Srsmaeda * CDDL HEADER START
31d4b38e0Srsmaeda *
41d4b38e0Srsmaeda * The contents of this file are subject to the terms of the
51d4b38e0Srsmaeda * Common Development and Distribution License (the "License").
61d4b38e0Srsmaeda * You may not use this file except in compliance with the License.
71d4b38e0Srsmaeda *
81d4b38e0Srsmaeda * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91d4b38e0Srsmaeda * or http://www.opensolaris.org/os/licensing.
101d4b38e0Srsmaeda * See the License for the specific language governing permissions
111d4b38e0Srsmaeda * and limitations under the License.
121d4b38e0Srsmaeda *
131d4b38e0Srsmaeda * When distributing Covered Code, include this CDDL HEADER in each
141d4b38e0Srsmaeda * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151d4b38e0Srsmaeda * If applicable, add the following below this CDDL HEADER, with the
161d4b38e0Srsmaeda * fields enclosed by brackets "[]" replaced with your own identifying
171d4b38e0Srsmaeda * information: Portions Copyright [yyyy] [name of copyright owner]
181d4b38e0Srsmaeda *
191d4b38e0Srsmaeda * CDDL HEADER END
201d4b38e0Srsmaeda */
211d4b38e0Srsmaeda
221d4b38e0Srsmaeda /*
23*9853d9e8SJason Beloro * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241d4b38e0Srsmaeda * Use is subject to license terms.
251d4b38e0Srsmaeda */
261d4b38e0Srsmaeda
271d4b38e0Srsmaeda /*
281d4b38e0Srsmaeda * RCM backend for the DR Daemon
291d4b38e0Srsmaeda */
301d4b38e0Srsmaeda
311d4b38e0Srsmaeda #include <unistd.h>
321d4b38e0Srsmaeda #include <strings.h>
331d4b38e0Srsmaeda #include <errno.h>
341d4b38e0Srsmaeda #include <kstat.h>
351d4b38e0Srsmaeda #include <libnvpair.h>
361d4b38e0Srsmaeda #include <librcm.h>
378fea755aSjm22469 #include <locale.h>
38*9853d9e8SJason Beloro #include <assert.h>
391d4b38e0Srsmaeda
401d4b38e0Srsmaeda #include "drd.h"
411d4b38e0Srsmaeda
421d4b38e0Srsmaeda /*
431d4b38e0Srsmaeda * RCM Backend Support
441d4b38e0Srsmaeda */
451d4b38e0Srsmaeda static int drd_rcm_init(void);
461d4b38e0Srsmaeda static int drd_rcm_fini(void);
471d4b38e0Srsmaeda static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
481d4b38e0Srsmaeda static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
491d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
501d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
518fea755aSjm22469 static int drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc);
528fea755aSjm22469 static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc);
538fea755aSjm22469 static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc);
548fea755aSjm22469 static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc);
55*9853d9e8SJason Beloro static int drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
56*9853d9e8SJason Beloro static int drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
57*9853d9e8SJason Beloro static int drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
58*9853d9e8SJason Beloro static int drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
591d4b38e0Srsmaeda
601d4b38e0Srsmaeda drd_backend_t drd_rcm_backend = {
611d4b38e0Srsmaeda drd_rcm_init, /* init */
621d4b38e0Srsmaeda drd_rcm_fini, /* fini */
631d4b38e0Srsmaeda drd_rcm_cpu_config_request, /* cpu_config_request */
641d4b38e0Srsmaeda drd_rcm_cpu_config_notify, /* cpu_config_notify */
651d4b38e0Srsmaeda drd_rcm_cpu_unconfig_request, /* cpu_unconfig_request */
668fea755aSjm22469 drd_rcm_cpu_unconfig_notify, /* cpu_unconfig_notify */
678fea755aSjm22469 drd_rcm_io_config_request, /* io_config_request */
688fea755aSjm22469 drd_rcm_io_config_notify, /* io_config_notify */
698fea755aSjm22469 drd_rcm_io_unconfig_request, /* io_unconfig_request */
70*9853d9e8SJason Beloro drd_rcm_io_unconfig_notify, /* io_unconfig_notify */
71*9853d9e8SJason Beloro drd_rcm_mem_config_request, /* mem_config_request */
72*9853d9e8SJason Beloro drd_rcm_mem_config_notify, /* mem_config_notify */
73*9853d9e8SJason Beloro drd_rcm_mem_unconfig_request, /* mem_unconfig_request */
74*9853d9e8SJason Beloro drd_rcm_mem_unconfig_notify /* mem_unconfig_notify */
751d4b38e0Srsmaeda };
761d4b38e0Srsmaeda
77*9853d9e8SJason Beloro typedef int (*rcm_op_t)(rcm_handle_t *, char *, uint_t, nvlist_t *,
78*9853d9e8SJason Beloro rcm_info_t **);
79*9853d9e8SJason Beloro
80*9853d9e8SJason Beloro #define RCM_MEM_ALL "SUNW_memory"
811d4b38e0Srsmaeda #define RCM_CPU_ALL "SUNW_cpu"
821d4b38e0Srsmaeda #define RCM_CPU RCM_CPU_ALL"/cpu"
831d4b38e0Srsmaeda #define RCM_CPU_MAX_LEN (32)
841d4b38e0Srsmaeda
851d4b38e0Srsmaeda /* global RCM handle used in all RCM operations */
861d4b38e0Srsmaeda static rcm_handle_t *rcm_hdl;
871d4b38e0Srsmaeda
881d4b38e0Srsmaeda /* functions that call into RCM */
891d4b38e0Srsmaeda static int drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
901d4b38e0Srsmaeda static int drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
911d4b38e0Srsmaeda static int drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
921d4b38e0Srsmaeda static int drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
931d4b38e0Srsmaeda static int drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
941d4b38e0Srsmaeda static int drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
951d4b38e0Srsmaeda static int drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
961d4b38e0Srsmaeda
971d4b38e0Srsmaeda /* utility functions */
981d4b38e0Srsmaeda static char **drd_rcm_cpu_rlist_init(drctl_rsrc_t *, int nrsrc, int status);
991d4b38e0Srsmaeda static void drd_rcm_cpu_rlist_fini(char **rlist);
1001d4b38e0Srsmaeda static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int);
1011d4b38e0Srsmaeda static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids);
1021d4b38e0Srsmaeda static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len);
1038fea755aSjm22469 static char *rcm_info_table(rcm_info_t *rinfo);
1041d4b38e0Srsmaeda
1051d4b38e0Srsmaeda /* debugging utility functions */
1061d4b38e0Srsmaeda static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids);
1071d4b38e0Srsmaeda static void dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *, int nrsrc);
1081d4b38e0Srsmaeda static void dump_cpu_rlist(char **rlist);
1091d4b38e0Srsmaeda
1101d4b38e0Srsmaeda static int
drd_rcm_init(void)1111d4b38e0Srsmaeda drd_rcm_init(void)
1121d4b38e0Srsmaeda {
1131d4b38e0Srsmaeda int rv;
1141d4b38e0Srsmaeda
1151d4b38e0Srsmaeda drd_dbg("drd_rcm_init...");
1161d4b38e0Srsmaeda
1171d4b38e0Srsmaeda rv = rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl);
1181d4b38e0Srsmaeda if (rv == RCM_FAILURE) {
1191d4b38e0Srsmaeda drd_err("unable to allocate RCM handle: %s", strerror(errno));
1201d4b38e0Srsmaeda return (-1);
1211d4b38e0Srsmaeda }
1221d4b38e0Srsmaeda
1231d4b38e0Srsmaeda return (0);
1241d4b38e0Srsmaeda }
1251d4b38e0Srsmaeda
1261d4b38e0Srsmaeda static int
drd_rcm_fini(void)1271d4b38e0Srsmaeda drd_rcm_fini(void)
1281d4b38e0Srsmaeda {
1291d4b38e0Srsmaeda drd_dbg("drd_rcm_fini...");
1301d4b38e0Srsmaeda
1311d4b38e0Srsmaeda if (rcm_hdl != NULL)
1321d4b38e0Srsmaeda rcm_free_handle(rcm_hdl);
1331d4b38e0Srsmaeda
1341d4b38e0Srsmaeda return (0);
1351d4b38e0Srsmaeda }
1361d4b38e0Srsmaeda
1371d4b38e0Srsmaeda static int
drd_rcm_cpu_config_request(drctl_rsrc_t * rsrcs,int nrsrc)1381d4b38e0Srsmaeda drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
1391d4b38e0Srsmaeda {
1401d4b38e0Srsmaeda int idx;
1411d4b38e0Srsmaeda
1421d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_config_request...");
1431d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1441d4b38e0Srsmaeda
1451d4b38e0Srsmaeda /*
1461d4b38e0Srsmaeda * There is no RCM operation to request the addition
1471d4b38e0Srsmaeda * of resources. So, by definition, the operation for
1481d4b38e0Srsmaeda * all the CPUs is allowed.
1491d4b38e0Srsmaeda */
1501d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++)
1511d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1521d4b38e0Srsmaeda
1531d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
1541d4b38e0Srsmaeda
1551d4b38e0Srsmaeda return (0);
1561d4b38e0Srsmaeda }
1571d4b38e0Srsmaeda
1581d4b38e0Srsmaeda static int
drd_rcm_cpu_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)1591d4b38e0Srsmaeda drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1601d4b38e0Srsmaeda {
1611d4b38e0Srsmaeda int rv = 0;
1621d4b38e0Srsmaeda
1631d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_config_notify...");
1641d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1651d4b38e0Srsmaeda
1661d4b38e0Srsmaeda /* notify RCM about the newly added CPUs */
1671d4b38e0Srsmaeda if (drd_rcm_online_cpu_notify(rsrcs, nrsrc) != 0) {
1681d4b38e0Srsmaeda rv = -1;
1691d4b38e0Srsmaeda goto done;
1701d4b38e0Srsmaeda }
1711d4b38e0Srsmaeda
1721d4b38e0Srsmaeda /* notify RCM about the increased CPU capacity */
1731d4b38e0Srsmaeda if (drd_rcm_add_cpu_notify(rsrcs, nrsrc) != 0) {
1741d4b38e0Srsmaeda rv = -1;
1751d4b38e0Srsmaeda }
1761d4b38e0Srsmaeda
1771d4b38e0Srsmaeda done:
1781d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
1791d4b38e0Srsmaeda
1801d4b38e0Srsmaeda return (rv);
1811d4b38e0Srsmaeda }
1821d4b38e0Srsmaeda
1831d4b38e0Srsmaeda static int
drd_rcm_cpu_unconfig_request(drctl_rsrc_t * rsrcs,int nrsrc)1841d4b38e0Srsmaeda drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
1851d4b38e0Srsmaeda {
1861d4b38e0Srsmaeda int rv = 0;
1871d4b38e0Srsmaeda int idx;
1881d4b38e0Srsmaeda
1891d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_unconfig_request...");
1901d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1911d4b38e0Srsmaeda
1921d4b38e0Srsmaeda /* contact RCM to request a decrease in CPU capacity */
1931d4b38e0Srsmaeda if (drd_rcm_del_cpu_request(rsrcs, nrsrc) != 0) {
1941d4b38e0Srsmaeda rv = -1;
1951d4b38e0Srsmaeda goto done;
1961d4b38e0Srsmaeda }
1971d4b38e0Srsmaeda
1981d4b38e0Srsmaeda /* contact RCM to request the removal of CPUs */
1991d4b38e0Srsmaeda if (drd_rcm_offline_cpu_request(rsrcs, nrsrc) != 0) {
2001d4b38e0Srsmaeda rv = -1;
2011d4b38e0Srsmaeda goto done;
2021d4b38e0Srsmaeda }
2031d4b38e0Srsmaeda
2041d4b38e0Srsmaeda done:
2051d4b38e0Srsmaeda /*
2061d4b38e0Srsmaeda * If any errors occurred, the status field for
2071d4b38e0Srsmaeda * a CPU may still be in the INIT state. Set the
2081d4b38e0Srsmaeda * status for any such CPU to DENY to ensure it
2091d4b38e0Srsmaeda * gets processed properly.
2101d4b38e0Srsmaeda */
2111d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
2121d4b38e0Srsmaeda if (rsrcs[idx].status == DRCTL_STATUS_INIT)
2131d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_DENY;
2141d4b38e0Srsmaeda }
2151d4b38e0Srsmaeda
2161d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
2171d4b38e0Srsmaeda
2181d4b38e0Srsmaeda return (rv);
2191d4b38e0Srsmaeda }
2201d4b38e0Srsmaeda
2211d4b38e0Srsmaeda static int
drd_rcm_cpu_unconfig_notify(drctl_rsrc_t * rsrcs,int nrsrc)2221d4b38e0Srsmaeda drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2231d4b38e0Srsmaeda {
2241d4b38e0Srsmaeda int rv = 0;
2251d4b38e0Srsmaeda
2261d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_unconfig_notify...");
2271d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
2281d4b38e0Srsmaeda
2291d4b38e0Srsmaeda /*
2301d4b38e0Srsmaeda * Notify RCM about the CPUs that were removed.
2311d4b38e0Srsmaeda * Failures are ignored so that CPUs that could
2321d4b38e0Srsmaeda * not be unconfigured can be processed by RCM.
2331d4b38e0Srsmaeda */
2341d4b38e0Srsmaeda (void) drd_rcm_remove_cpu_notify(rsrcs, nrsrc);
2351d4b38e0Srsmaeda
2361d4b38e0Srsmaeda /*
2371d4b38e0Srsmaeda * Notify RCM about any CPUs that did not make it
2381d4b38e0Srsmaeda * in to the unconfigured state.
2391d4b38e0Srsmaeda */
2401d4b38e0Srsmaeda if (drd_rcm_restore_cpu_notify(rsrcs, nrsrc) != 0) {
2411d4b38e0Srsmaeda rv = -1;
2421d4b38e0Srsmaeda goto done;
2431d4b38e0Srsmaeda }
2441d4b38e0Srsmaeda
2451d4b38e0Srsmaeda /* notify RCM about the decreased CPU capacity */
2461d4b38e0Srsmaeda if (drd_rcm_del_cpu_notify(rsrcs, nrsrc) != 0) {
2471d4b38e0Srsmaeda rv = -1;
2481d4b38e0Srsmaeda }
2491d4b38e0Srsmaeda
2501d4b38e0Srsmaeda done:
2511d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
2521d4b38e0Srsmaeda
2531d4b38e0Srsmaeda return (rv);
2541d4b38e0Srsmaeda }
2551d4b38e0Srsmaeda
2561d4b38e0Srsmaeda static int
drd_rcm_online_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)2571d4b38e0Srsmaeda drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2581d4b38e0Srsmaeda {
2591d4b38e0Srsmaeda char **rlist;
2601d4b38e0Srsmaeda int rv = 0;
2611d4b38e0Srsmaeda rcm_info_t *rinfo;
2621d4b38e0Srsmaeda
2631d4b38e0Srsmaeda drd_dbg("drd_rcm_online_cpu_notify...");
2641d4b38e0Srsmaeda
2651d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
2661d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
2671d4b38e0Srsmaeda drd_dbg(" no CPUs were successfully added, nothing to do");
2681d4b38e0Srsmaeda return (0);
2691d4b38e0Srsmaeda }
2701d4b38e0Srsmaeda
2711d4b38e0Srsmaeda rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
2721d4b38e0Srsmaeda if (rv != RCM_SUCCESS) {
2731d4b38e0Srsmaeda drd_info("rcm_notify_online_list failed: %d", rv);
2741d4b38e0Srsmaeda rcm_free_info(rinfo);
2751d4b38e0Srsmaeda rv = -1;
2761d4b38e0Srsmaeda }
2771d4b38e0Srsmaeda
2781d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist);
2791d4b38e0Srsmaeda
2801d4b38e0Srsmaeda return (rv);
2811d4b38e0Srsmaeda }
2821d4b38e0Srsmaeda
2831d4b38e0Srsmaeda static int
drd_rcm_add_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)2841d4b38e0Srsmaeda drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2851d4b38e0Srsmaeda {
2861d4b38e0Srsmaeda cpuid_t *cpus = NULL;
2871d4b38e0Srsmaeda int ncpus;
2881d4b38e0Srsmaeda int rv = -1;
2891d4b38e0Srsmaeda cpuid_t *oldcpus = NULL;
2901d4b38e0Srsmaeda cpuid_t *newcpus = NULL;
2911d4b38e0Srsmaeda int oldncpus = 0;
2921d4b38e0Srsmaeda int newncpus = 0;
2931d4b38e0Srsmaeda nvlist_t *nvl = NULL;
2941d4b38e0Srsmaeda int idx;
2951d4b38e0Srsmaeda rcm_info_t *rinfo;
2961d4b38e0Srsmaeda
2971d4b38e0Srsmaeda drd_dbg("drd_rcm_add_cpu_notify...");
2981d4b38e0Srsmaeda
2991d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) {
3001d4b38e0Srsmaeda drd_err("add_cpu_notify: cpu list empty");
3011d4b38e0Srsmaeda goto done;
3021d4b38e0Srsmaeda }
3031d4b38e0Srsmaeda
3041d4b38e0Srsmaeda ncpus = nrsrc;
3051d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
3061d4b38e0Srsmaeda
3071d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
3081d4b38e0Srsmaeda drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
3091d4b38e0Srsmaeda cpus[idx] = rsrcs[idx].res_cpu_id;
3101d4b38e0Srsmaeda }
3111d4b38e0Srsmaeda
3121d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */
3131d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3141d4b38e0Srsmaeda goto done;
3151d4b38e0Srsmaeda
3161d4b38e0Srsmaeda /*
3171d4b38e0Srsmaeda * Added CPU capacity, so newcpus is the current list
3181d4b38e0Srsmaeda * of CPUs in the system.
3191d4b38e0Srsmaeda */
3201d4b38e0Srsmaeda if (get_sys_cpuids(&newcpus, &newncpus) == -1)
3211d4b38e0Srsmaeda goto done;
3221d4b38e0Srsmaeda
3231d4b38e0Srsmaeda /*
3241d4b38e0Srsmaeda * Since the operation added CPU capacity, the old CPU
3251d4b38e0Srsmaeda * list is the new CPU list with the CPUs involved in
3261d4b38e0Srsmaeda * the operation removed.
3271d4b38e0Srsmaeda */
3281d4b38e0Srsmaeda oldcpus = (cpuid_t *)calloc(newncpus, sizeof (cpuid_t));
3291d4b38e0Srsmaeda if (oldcpus == NULL)
3301d4b38e0Srsmaeda goto done;
3311d4b38e0Srsmaeda
3321d4b38e0Srsmaeda for (idx = 0; idx < newncpus; idx++) {
3331d4b38e0Srsmaeda if (!is_cpu_in_list(newcpus[idx], cpus, ncpus))
3341d4b38e0Srsmaeda oldcpus[oldncpus++] = newcpus[idx];
3351d4b38e0Srsmaeda }
3361d4b38e0Srsmaeda
3371d4b38e0Srsmaeda /* dump pre and post lists */
3381d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
3391d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus);
3401d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, ncpus);
3411d4b38e0Srsmaeda
3421d4b38e0Srsmaeda /* setup the nvlist for the RCM call */
3431d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") ||
3441d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) ||
3451d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) ||
3461d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
3471d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
3481d4b38e0Srsmaeda goto done;
3491d4b38e0Srsmaeda }
3501d4b38e0Srsmaeda
3511d4b38e0Srsmaeda rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
3521d4b38e0Srsmaeda rv = (rv == RCM_SUCCESS) ? 0 : -1;
3531d4b38e0Srsmaeda
3541d4b38e0Srsmaeda done:
3551d4b38e0Srsmaeda s_nvfree(nvl);
3561d4b38e0Srsmaeda s_free(cpus);
3571d4b38e0Srsmaeda s_free(oldcpus);
3581d4b38e0Srsmaeda s_free(newcpus);
3591d4b38e0Srsmaeda
3601d4b38e0Srsmaeda return (rv);
3611d4b38e0Srsmaeda }
3621d4b38e0Srsmaeda
3631d4b38e0Srsmaeda static int
drd_rcm_del_cpu_request(drctl_rsrc_t * rsrcs,int nrsrc)3641d4b38e0Srsmaeda drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
3651d4b38e0Srsmaeda {
3661d4b38e0Srsmaeda cpuid_t *cpus = NULL;
3671d4b38e0Srsmaeda int ncpus;
3681d4b38e0Srsmaeda int rv = -1;
3691d4b38e0Srsmaeda cpuid_t *oldcpus = NULL;
3701d4b38e0Srsmaeda cpuid_t *newcpus = NULL;
3711d4b38e0Srsmaeda int oldncpus = 0;
3721d4b38e0Srsmaeda int newncpus = 0;
3731d4b38e0Srsmaeda nvlist_t *nvl = NULL;
3741d4b38e0Srsmaeda int idx;
3751d4b38e0Srsmaeda rcm_info_t *rinfo;
3761d4b38e0Srsmaeda
3771d4b38e0Srsmaeda drd_dbg("drd_rcm_del_cpu_request...");
3781d4b38e0Srsmaeda
3791d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) {
3801d4b38e0Srsmaeda drd_err("del_cpu_request: cpu list empty");
3811d4b38e0Srsmaeda goto done;
3821d4b38e0Srsmaeda }
3831d4b38e0Srsmaeda
3841d4b38e0Srsmaeda ncpus = nrsrc;
3851d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
3861d4b38e0Srsmaeda
3871d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
3881d4b38e0Srsmaeda cpus[idx] = rsrcs[idx].res_cpu_id;
3891d4b38e0Srsmaeda }
3901d4b38e0Srsmaeda
3911d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */
3921d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
3931d4b38e0Srsmaeda goto done;
3941d4b38e0Srsmaeda }
3951d4b38e0Srsmaeda
3961d4b38e0Srsmaeda /*
3971d4b38e0Srsmaeda * Removing CPU capacity, so oldcpus is the current
3981d4b38e0Srsmaeda * list of CPUs in the system.
3991d4b38e0Srsmaeda */
4001d4b38e0Srsmaeda if (get_sys_cpuids(&oldcpus, &oldncpus) == -1) {
4011d4b38e0Srsmaeda goto done;
4021d4b38e0Srsmaeda }
4031d4b38e0Srsmaeda
4041d4b38e0Srsmaeda /*
4051d4b38e0Srsmaeda * Since this is a request to remove CPU capacity,
4061d4b38e0Srsmaeda * the new CPU list is the old CPU list with the CPUs
4071d4b38e0Srsmaeda * involved in the operation removed.
4081d4b38e0Srsmaeda */
4091d4b38e0Srsmaeda newcpus = (cpuid_t *)calloc(oldncpus, sizeof (cpuid_t));
4101d4b38e0Srsmaeda if (newcpus == NULL) {
4111d4b38e0Srsmaeda goto done;
4121d4b38e0Srsmaeda }
4131d4b38e0Srsmaeda
4141d4b38e0Srsmaeda for (idx = 0; idx < oldncpus; idx++) {
4151d4b38e0Srsmaeda if (!is_cpu_in_list(oldcpus[idx], cpus, ncpus))
4161d4b38e0Srsmaeda newcpus[newncpus++] = oldcpus[idx];
4171d4b38e0Srsmaeda }
4181d4b38e0Srsmaeda
4191d4b38e0Srsmaeda /* dump pre and post lists */
4201d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
4211d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus);
4221d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, ncpus);
4231d4b38e0Srsmaeda
4241d4b38e0Srsmaeda /* setup the nvlist for the RCM call */
4251d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") ||
4261d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) ||
4271d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) ||
4281d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
4291d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
4301d4b38e0Srsmaeda goto done;
4311d4b38e0Srsmaeda }
4321d4b38e0Srsmaeda
4331d4b38e0Srsmaeda rv = rcm_request_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
4341d4b38e0Srsmaeda if (rv != RCM_SUCCESS) {
4351d4b38e0Srsmaeda drd_dbg("RCM call failed: %d", rv);
4361d4b38e0Srsmaeda /*
437*9853d9e8SJason Beloro * Since the capacity change was blocked, we
4381d4b38e0Srsmaeda * mark all CPUs as blocked. It is up to the
4391d4b38e0Srsmaeda * user to reframe the query so that it can
4401d4b38e0Srsmaeda * succeed.
4411d4b38e0Srsmaeda */
4421d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
4431d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_DENY;
4441d4b38e0Srsmaeda }
4451d4b38e0Srsmaeda
4461d4b38e0Srsmaeda /* tack on message to first resource */
4471d4b38e0Srsmaeda rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
4481d4b38e0Srsmaeda "specified number of CPUs");
4491d4b38e0Srsmaeda drd_dbg(" unable to remove specified number of CPUs");
4501d4b38e0Srsmaeda goto done;
4511d4b38e0Srsmaeda }
4521d4b38e0Srsmaeda
4531d4b38e0Srsmaeda rv = 0;
4541d4b38e0Srsmaeda
4551d4b38e0Srsmaeda done:
4561d4b38e0Srsmaeda s_nvfree(nvl);
4571d4b38e0Srsmaeda s_free(cpus);
4581d4b38e0Srsmaeda s_free(oldcpus);
4591d4b38e0Srsmaeda s_free(newcpus);
4601d4b38e0Srsmaeda
4611d4b38e0Srsmaeda return (rv);
4621d4b38e0Srsmaeda }
4631d4b38e0Srsmaeda
4641d4b38e0Srsmaeda static int
drd_rcm_offline_cpu_request(drctl_rsrc_t * rsrcs,int nrsrc)4651d4b38e0Srsmaeda drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
4661d4b38e0Srsmaeda {
4671d4b38e0Srsmaeda char **rlist;
4681d4b38e0Srsmaeda drctl_rsrc_t *rsrc;
4691d4b38e0Srsmaeda int idx;
4701d4b38e0Srsmaeda int state;
4711d4b38e0Srsmaeda int rv = 0;
4721d4b38e0Srsmaeda rcm_info_t *rinfo = NULL;
4731d4b38e0Srsmaeda rcm_info_tuple_t *tuple = NULL;
4741d4b38e0Srsmaeda const char *rsrcstr;
4751d4b38e0Srsmaeda const char *errstr;
4761d4b38e0Srsmaeda
4771d4b38e0Srsmaeda drd_dbg("drd_rcm_offline_cpu_request...");
4781d4b38e0Srsmaeda
4791d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
4801d4b38e0Srsmaeda DRCTL_STATUS_INIT)) == NULL) {
4811d4b38e0Srsmaeda drd_err("unable to generate resource list");
4821d4b38e0Srsmaeda return (-1);
4831d4b38e0Srsmaeda }
4841d4b38e0Srsmaeda
4851d4b38e0Srsmaeda rv = rcm_request_offline_list(rcm_hdl, rlist, 0, &rinfo);
4861d4b38e0Srsmaeda if (rv == RCM_SUCCESS) {
4871d4b38e0Srsmaeda drd_dbg("RCM success, rinfo=%p", rinfo);
4881d4b38e0Srsmaeda goto done;
4891d4b38e0Srsmaeda }
4901d4b38e0Srsmaeda
4911d4b38e0Srsmaeda drd_dbg("RCM call failed (%d):", rv);
4921d4b38e0Srsmaeda
4931d4b38e0Srsmaeda /*
4941d4b38e0Srsmaeda * Loop through the result of the operation and add
4951d4b38e0Srsmaeda * any error messages to the resource structure.
4961d4b38e0Srsmaeda */
4971d4b38e0Srsmaeda while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
4981d4b38e0Srsmaeda
4991d4b38e0Srsmaeda /* find the resource of interest */
5001d4b38e0Srsmaeda rsrcstr = rcm_info_rsrc(tuple);
5011d4b38e0Srsmaeda rsrc = cpu_rsrcstr_to_rsrc(rsrcstr, rsrcs, nrsrc);
5021d4b38e0Srsmaeda
5031d4b38e0Srsmaeda if (rsrc == NULL) {
5041d4b38e0Srsmaeda drd_dbg("unable to find resource for %s", rsrcstr);
5051d4b38e0Srsmaeda continue;
5061d4b38e0Srsmaeda }
5071d4b38e0Srsmaeda
5081d4b38e0Srsmaeda errstr = rcm_info_error(tuple);
5091d4b38e0Srsmaeda
5101d4b38e0Srsmaeda if (errstr) {
5111d4b38e0Srsmaeda drd_dbg(" %s: '%s'", rsrcstr, errstr);
5121d4b38e0Srsmaeda rsrc->offset = (uintptr_t)strdup(errstr);
5131d4b38e0Srsmaeda }
5141d4b38e0Srsmaeda }
5151d4b38e0Srsmaeda
5161d4b38e0Srsmaeda rcm_free_info(rinfo);
5171d4b38e0Srsmaeda rv = 0;
5181d4b38e0Srsmaeda
5191d4b38e0Srsmaeda done:
5201d4b38e0Srsmaeda /*
5211d4b38e0Srsmaeda * Set the state of the resource based on the RCM
5221d4b38e0Srsmaeda * state. CPUs in the offline state have the ok to
5231d4b38e0Srsmaeda * proceed. All others have been blocked.
5241d4b38e0Srsmaeda */
5251d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) {
5261d4b38e0Srsmaeda
5271d4b38e0Srsmaeda state = 0;
5281d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
5291d4b38e0Srsmaeda
5301d4b38e0Srsmaeda /* find the resource of interest */
5311d4b38e0Srsmaeda rsrc = cpu_rsrcstr_to_rsrc(rlist[idx], rsrcs, nrsrc);
5321d4b38e0Srsmaeda
5331d4b38e0Srsmaeda if (rsrc == NULL) {
5341d4b38e0Srsmaeda drd_dbg("unable to find resource for %s", rlist[idx]);
5351d4b38e0Srsmaeda continue;
5361d4b38e0Srsmaeda }
5371d4b38e0Srsmaeda
5381d4b38e0Srsmaeda rsrc->status = ((state == RCM_STATE_OFFLINE) ?
5391d4b38e0Srsmaeda DRCTL_STATUS_ALLOW : DRCTL_STATUS_DENY);
5401d4b38e0Srsmaeda }
5411d4b38e0Srsmaeda
5421d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist);
5431d4b38e0Srsmaeda
5441d4b38e0Srsmaeda return (rv);
5451d4b38e0Srsmaeda }
5461d4b38e0Srsmaeda
5471d4b38e0Srsmaeda static int
drd_rcm_remove_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)5481d4b38e0Srsmaeda drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
5491d4b38e0Srsmaeda {
5501d4b38e0Srsmaeda char **rlist;
5511d4b38e0Srsmaeda int rv = 0;
5521d4b38e0Srsmaeda rcm_info_t *rinfo;
5531d4b38e0Srsmaeda
5541d4b38e0Srsmaeda drd_dbg("drd_rcm_remove_cpu_notify...");
5551d4b38e0Srsmaeda
5561d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
5571d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
5581d4b38e0Srsmaeda drd_dbg(" no CPUs in the success state, nothing to do");
5591d4b38e0Srsmaeda return (0);
5601d4b38e0Srsmaeda }
5611d4b38e0Srsmaeda
5621d4b38e0Srsmaeda rv = rcm_notify_remove_list(rcm_hdl, rlist, 0, &rinfo);
5631d4b38e0Srsmaeda if (rv != RCM_SUCCESS) {
5641d4b38e0Srsmaeda drd_info("rcm_notify_remove_list failed: %d", rv);
5651d4b38e0Srsmaeda rcm_free_info(rinfo);
5661d4b38e0Srsmaeda rv = -1;
5671d4b38e0Srsmaeda }
5681d4b38e0Srsmaeda
5691d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist);
5701d4b38e0Srsmaeda
5711d4b38e0Srsmaeda return (rv);
5721d4b38e0Srsmaeda }
5731d4b38e0Srsmaeda
5741d4b38e0Srsmaeda static int
drd_rcm_restore_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)5751d4b38e0Srsmaeda drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
5761d4b38e0Srsmaeda {
5771d4b38e0Srsmaeda char **rlist;
5781d4b38e0Srsmaeda char **full_rlist;
5791d4b38e0Srsmaeda int idx;
5801d4b38e0Srsmaeda int ridx;
5811d4b38e0Srsmaeda int state;
5821d4b38e0Srsmaeda int rv = 0;
5831d4b38e0Srsmaeda rcm_info_t *rinfo;
5841d4b38e0Srsmaeda
5851d4b38e0Srsmaeda drd_dbg("drd_rcm_restore_cpu_notify...");
5861d4b38e0Srsmaeda
5871d4b38e0Srsmaeda if ((full_rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
5881d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_FAILURE)) == NULL) {
5891d4b38e0Srsmaeda drd_dbg(" no CPUs in the failed state, nothing to do");
5901d4b38e0Srsmaeda return (0);
5911d4b38e0Srsmaeda }
5921d4b38e0Srsmaeda
5931d4b38e0Srsmaeda /*
5941d4b38e0Srsmaeda * Since the desired result of this operation is to
5951d4b38e0Srsmaeda * restore resources to the online state, filter out
5961d4b38e0Srsmaeda * the resources already in the online state before
5971d4b38e0Srsmaeda * passing the list to RCM.
5981d4b38e0Srsmaeda */
5991d4b38e0Srsmaeda
6001d4b38e0Srsmaeda /* allocate a zero filled array to ensure NULL terminated list */
6011d4b38e0Srsmaeda rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
6021d4b38e0Srsmaeda if (rlist == NULL) {
6031d4b38e0Srsmaeda drd_err("calloc failed: %s", strerror(errno));
6041d4b38e0Srsmaeda rv = -1;
6051d4b38e0Srsmaeda goto done;
6061d4b38e0Srsmaeda }
6071d4b38e0Srsmaeda
6081d4b38e0Srsmaeda for (idx = 0, ridx = 0; full_rlist[idx] != NULL; idx++) {
6091d4b38e0Srsmaeda state = 0;
6101d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, full_rlist[idx], &state);
6111d4b38e0Srsmaeda if (state != RCM_STATE_ONLINE) {
6121d4b38e0Srsmaeda rlist[ridx] = full_rlist[idx];
6131d4b38e0Srsmaeda ridx++;
6141d4b38e0Srsmaeda }
6151d4b38e0Srsmaeda }
6161d4b38e0Srsmaeda
6171d4b38e0Srsmaeda /* check if everything got filtered out */
6181d4b38e0Srsmaeda if (ridx == 0) {
6191d4b38e0Srsmaeda drd_dbg(" all CPUs already online, nothing to do");
6201d4b38e0Srsmaeda goto done;
6211d4b38e0Srsmaeda }
6221d4b38e0Srsmaeda
6231d4b38e0Srsmaeda rv = rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
6241d4b38e0Srsmaeda if (rv != RCM_SUCCESS) {
6251d4b38e0Srsmaeda drd_info("rcm_notify_online_list failed: %d", rv);
6261d4b38e0Srsmaeda rcm_free_info(rinfo);
6271d4b38e0Srsmaeda rv = -1;
6281d4b38e0Srsmaeda }
6291d4b38e0Srsmaeda
6301d4b38e0Srsmaeda done:
6311d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(full_rlist);
6321d4b38e0Srsmaeda s_free(rlist);
6331d4b38e0Srsmaeda
6341d4b38e0Srsmaeda return (rv);
6351d4b38e0Srsmaeda }
6361d4b38e0Srsmaeda
6371d4b38e0Srsmaeda static int
drd_rcm_del_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)6381d4b38e0Srsmaeda drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
6391d4b38e0Srsmaeda {
6401d4b38e0Srsmaeda cpuid_t *cpus = NULL;
6411d4b38e0Srsmaeda int rv = -1;
6421d4b38e0Srsmaeda cpuid_t *oldcpus = NULL;
6431d4b38e0Srsmaeda cpuid_t *newcpus = NULL;
6441d4b38e0Srsmaeda int oldncpus = 0;
6451d4b38e0Srsmaeda int newncpus = 0;
6461d4b38e0Srsmaeda nvlist_t *nvl = NULL;
6471d4b38e0Srsmaeda int idx;
6481d4b38e0Srsmaeda int cidx;
6491d4b38e0Srsmaeda rcm_info_t *rinfo;
6501d4b38e0Srsmaeda
6511d4b38e0Srsmaeda drd_dbg("drd_rcm_del_cpu_notify...");
6521d4b38e0Srsmaeda
6531d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) {
6541d4b38e0Srsmaeda drd_err("del_cpu_notify: cpu list empty");
6551d4b38e0Srsmaeda goto done;
6561d4b38e0Srsmaeda }
6571d4b38e0Srsmaeda
6581d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
6591d4b38e0Srsmaeda
6601d4b38e0Srsmaeda /*
6611d4b38e0Srsmaeda * Filter out the CPUs that could not be unconfigured.
6621d4b38e0Srsmaeda */
6631d4b38e0Srsmaeda for (idx = 0, cidx = 0; idx < nrsrc; idx++) {
6641d4b38e0Srsmaeda if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
6651d4b38e0Srsmaeda continue;
6661d4b38e0Srsmaeda drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
6671d4b38e0Srsmaeda cpus[cidx] = rsrcs[idx].res_cpu_id;
6681d4b38e0Srsmaeda cidx++;
6691d4b38e0Srsmaeda }
6701d4b38e0Srsmaeda
6711d4b38e0Srsmaeda drd_dbg(" ncpus = %d", cidx);
6721d4b38e0Srsmaeda
6731d4b38e0Srsmaeda /* nothing to do */
6741d4b38e0Srsmaeda if (cidx == 0) {
6751d4b38e0Srsmaeda rv = 0;
6761d4b38e0Srsmaeda goto done;
6771d4b38e0Srsmaeda }
6781d4b38e0Srsmaeda
6791d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */
6801d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
6811d4b38e0Srsmaeda goto done;
6821d4b38e0Srsmaeda }
6831d4b38e0Srsmaeda
6841d4b38e0Srsmaeda /*
6851d4b38e0Srsmaeda * Removed CPU capacity, so newcpus is the current list
6861d4b38e0Srsmaeda * of CPUs in the system.
6871d4b38e0Srsmaeda */
6881d4b38e0Srsmaeda if (get_sys_cpuids(&newcpus, &newncpus) == -1) {
6891d4b38e0Srsmaeda goto done;
6901d4b38e0Srsmaeda }
6911d4b38e0Srsmaeda
6921d4b38e0Srsmaeda /*
6931d4b38e0Srsmaeda * Since the operation removed CPU capacity, the old CPU
6941d4b38e0Srsmaeda * list is the new CPU list with the CPUs involved in
6951d4b38e0Srsmaeda * the operation added.
6961d4b38e0Srsmaeda */
6971d4b38e0Srsmaeda oldcpus = (cpuid_t *)calloc(newncpus + cidx, sizeof (cpuid_t));
6981d4b38e0Srsmaeda if (oldcpus == NULL) {
6991d4b38e0Srsmaeda goto done;
7001d4b38e0Srsmaeda }
7011d4b38e0Srsmaeda
7021d4b38e0Srsmaeda for (idx = 0; idx < newncpus; idx++) {
7031d4b38e0Srsmaeda if (!is_cpu_in_list(newcpus[idx], cpus, cidx))
7041d4b38e0Srsmaeda oldcpus[oldncpus++] = newcpus[idx];
7051d4b38e0Srsmaeda }
7061d4b38e0Srsmaeda
7071d4b38e0Srsmaeda for (idx = 0; idx < cidx; idx++) {
7081d4b38e0Srsmaeda oldcpus[oldncpus++] = cpus[idx];
7091d4b38e0Srsmaeda }
7101d4b38e0Srsmaeda
7111d4b38e0Srsmaeda /* dump pre and post lists */
7121d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
7131d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus);
7141d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, cidx);
7151d4b38e0Srsmaeda
7161d4b38e0Srsmaeda /* setup the nvlist for the RCM call */
7171d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") ||
7181d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) ||
7191d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) ||
7201d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
7211d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
7221d4b38e0Srsmaeda goto done;
7231d4b38e0Srsmaeda }
7241d4b38e0Srsmaeda
7251d4b38e0Srsmaeda rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
7261d4b38e0Srsmaeda rv = (rv == RCM_SUCCESS) ? 0 : -1;
7271d4b38e0Srsmaeda
7281d4b38e0Srsmaeda done:
7291d4b38e0Srsmaeda s_nvfree(nvl);
7301d4b38e0Srsmaeda s_free(cpus);
7311d4b38e0Srsmaeda s_free(oldcpus);
7321d4b38e0Srsmaeda s_free(newcpus);
7331d4b38e0Srsmaeda
7341d4b38e0Srsmaeda return (rv);
7351d4b38e0Srsmaeda }
7361d4b38e0Srsmaeda
7371d4b38e0Srsmaeda /*
7381d4b38e0Srsmaeda * Given a list of resource structures, create a list of CPU
7391d4b38e0Srsmaeda * resource strings formatted as expected by RCM. Only resources
7401d4b38e0Srsmaeda * that are in the state specified by the status argument are
7411d4b38e0Srsmaeda * included in the resulting list.
7421d4b38e0Srsmaeda */
7431d4b38e0Srsmaeda static char **
drd_rcm_cpu_rlist_init(drctl_rsrc_t * rsrcs,int nrsrc,int status)7441d4b38e0Srsmaeda drd_rcm_cpu_rlist_init(drctl_rsrc_t *rsrcs, int nrsrc, int status)
7451d4b38e0Srsmaeda {
7461d4b38e0Srsmaeda char rbuf[RCM_CPU_MAX_LEN];
7471d4b38e0Srsmaeda char **rlist;
7481d4b38e0Srsmaeda int idx;
7491d4b38e0Srsmaeda int ridx;
7501d4b38e0Srsmaeda
7511d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_rlist_init...");
7521d4b38e0Srsmaeda
7531d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) {
7541d4b38e0Srsmaeda drd_dbg("cpu list is empty");
7551d4b38e0Srsmaeda return (NULL);
7561d4b38e0Srsmaeda }
7571d4b38e0Srsmaeda
7581d4b38e0Srsmaeda /* allocate a zero filled array to ensure NULL terminated list */
7591d4b38e0Srsmaeda rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
7601d4b38e0Srsmaeda if (rlist == NULL) {
7611d4b38e0Srsmaeda drd_err("calloc failed: %s", strerror(errno));
7621d4b38e0Srsmaeda return (NULL);
7631d4b38e0Srsmaeda }
7641d4b38e0Srsmaeda
7651d4b38e0Srsmaeda for (idx = 0, ridx = 0; idx < nrsrc; idx++) {
7661d4b38e0Srsmaeda
7671d4b38e0Srsmaeda drd_dbg(" checking cpu %d, status=%d, expected status=%d",
7681d4b38e0Srsmaeda rsrcs[idx].res_cpu_id, rsrcs[idx].status, status);
7691d4b38e0Srsmaeda
7701d4b38e0Srsmaeda /*
7711d4b38e0Srsmaeda * Filter out the CPUs that are not in
7721d4b38e0Srsmaeda * the requested state.
7731d4b38e0Srsmaeda */
7741d4b38e0Srsmaeda if (rsrcs[idx].status != status)
7751d4b38e0Srsmaeda continue;
7761d4b38e0Srsmaeda
7771d4b38e0Srsmaeda /* generate the resource string */
7781d4b38e0Srsmaeda (void) sprintf(rbuf, "%s%d", RCM_CPU, rsrcs[idx].res_cpu_id);
7791d4b38e0Srsmaeda
7801d4b38e0Srsmaeda rlist[ridx] = strdup(rbuf);
7811d4b38e0Srsmaeda if (rlist[ridx] == NULL) {
7821d4b38e0Srsmaeda drd_err("strdup failed: %s", strerror(errno));
7831d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist);
7841d4b38e0Srsmaeda return (NULL);
7851d4b38e0Srsmaeda }
7861d4b38e0Srsmaeda
7871d4b38e0Srsmaeda ridx++;
7881d4b38e0Srsmaeda }
7891d4b38e0Srsmaeda
7901d4b38e0Srsmaeda /* cleanup if the list is empty */
7911d4b38e0Srsmaeda if (ridx == 0) {
7921d4b38e0Srsmaeda s_free(rlist);
7931d4b38e0Srsmaeda }
7941d4b38e0Srsmaeda
7951d4b38e0Srsmaeda drd_dbg("final rlist:");
7961d4b38e0Srsmaeda dump_cpu_rlist(rlist);
7971d4b38e0Srsmaeda
7981d4b38e0Srsmaeda return (rlist);
7991d4b38e0Srsmaeda }
8001d4b38e0Srsmaeda
8011d4b38e0Srsmaeda static void
drd_rcm_cpu_rlist_fini(char ** rlist)8021d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(char **rlist)
8031d4b38e0Srsmaeda {
8041d4b38e0Srsmaeda int idx;
8051d4b38e0Srsmaeda
8061d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_rlist_fini...");
8071d4b38e0Srsmaeda
8081d4b38e0Srsmaeda dump_cpu_rlist(rlist);
8091d4b38e0Srsmaeda
8101d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) {
8111d4b38e0Srsmaeda s_free(rlist[idx]);
8121d4b38e0Srsmaeda }
8131d4b38e0Srsmaeda
8141d4b38e0Srsmaeda s_free(rlist);
8151d4b38e0Srsmaeda }
8161d4b38e0Srsmaeda
8171d4b38e0Srsmaeda /*
8181d4b38e0Srsmaeda * Convert an RCM CPU resource string into a numerical cpuid.
8191d4b38e0Srsmaeda * Assumes the resource string has the form: "SUNW_cpu/cpu<C>"
8201d4b38e0Srsmaeda * where "<C>" is the numerical cpuid of interest.
8211d4b38e0Srsmaeda */
8221d4b38e0Srsmaeda static cpuid_t
cpu_rsrcstr_to_cpuid(const char * rsrc)8231d4b38e0Srsmaeda cpu_rsrcstr_to_cpuid(const char *rsrc)
8241d4b38e0Srsmaeda {
8251d4b38e0Srsmaeda char *cpuid_off;
8261d4b38e0Srsmaeda cpuid_t cpuid;
8271d4b38e0Srsmaeda
8281d4b38e0Srsmaeda /*
8291d4b38e0Srsmaeda * Search for the last occurrance of 'u' in the
8301d4b38e0Srsmaeda * expected RCM resource string "SUNW_cpu/cpu<C>".
8311d4b38e0Srsmaeda * This will give a pointer to the cpuid portion.
8321d4b38e0Srsmaeda */
8331d4b38e0Srsmaeda cpuid_off = strrchr(rsrc, 'u');
8341d4b38e0Srsmaeda cpuid_off++;
8351d4b38e0Srsmaeda
8361d4b38e0Srsmaeda cpuid = atoi(cpuid_off);
8371d4b38e0Srsmaeda
8381d4b38e0Srsmaeda return (cpuid);
8391d4b38e0Srsmaeda }
8401d4b38e0Srsmaeda
8411d4b38e0Srsmaeda /*
8421d4b38e0Srsmaeda * Given an RCM CPU resource string, return a pointer to the
8431d4b38e0Srsmaeda * corresponding resource structure from the given resource list.
8441d4b38e0Srsmaeda * NULL is returned if no matching resource structure can be
8451d4b38e0Srsmaeda * found.
8461d4b38e0Srsmaeda */
8471d4b38e0Srsmaeda static drctl_rsrc_t *
cpu_rsrcstr_to_rsrc(const char * rsrcstr,drctl_rsrc_t * rsrcs,int nrsrc)8481d4b38e0Srsmaeda cpu_rsrcstr_to_rsrc(const char *rsrcstr, drctl_rsrc_t *rsrcs, int nrsrc)
8491d4b38e0Srsmaeda {
8501d4b38e0Srsmaeda cpuid_t cpuid;
8511d4b38e0Srsmaeda int idx;
8521d4b38e0Srsmaeda
8531d4b38e0Srsmaeda cpuid = cpu_rsrcstr_to_cpuid(rsrcstr);
8541d4b38e0Srsmaeda
8551d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
8561d4b38e0Srsmaeda if (rsrcs[idx].res_cpu_id == cpuid)
8571d4b38e0Srsmaeda return (&rsrcs[idx]);
8581d4b38e0Srsmaeda }
8591d4b38e0Srsmaeda
8601d4b38e0Srsmaeda return (NULL);
8611d4b38e0Srsmaeda }
8621d4b38e0Srsmaeda
8631d4b38e0Srsmaeda static int
get_sys_cpuids(cpuid_t ** cpuids,int * ncpuids)8641d4b38e0Srsmaeda get_sys_cpuids(cpuid_t **cpuids, int *ncpuids)
8651d4b38e0Srsmaeda {
8661d4b38e0Srsmaeda int ncpu = 0;
8671d4b38e0Srsmaeda int maxncpu;
8681d4b38e0Srsmaeda kstat_t *ksp;
8691d4b38e0Srsmaeda kstat_ctl_t *kc = NULL;
8701d4b38e0Srsmaeda cpuid_t *cp;
8711d4b38e0Srsmaeda
8721d4b38e0Srsmaeda drd_dbg("get_sys_cpuids...");
8731d4b38e0Srsmaeda
8741d4b38e0Srsmaeda if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1)
8751d4b38e0Srsmaeda return (-1);
8761d4b38e0Srsmaeda
8771d4b38e0Srsmaeda if ((kc = kstat_open()) == NULL)
8781d4b38e0Srsmaeda return (-1);
8791d4b38e0Srsmaeda
8801d4b38e0Srsmaeda if ((cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) {
8811d4b38e0Srsmaeda (void) kstat_close(kc);
8821d4b38e0Srsmaeda return (-1);
8831d4b38e0Srsmaeda }
8841d4b38e0Srsmaeda
8851d4b38e0Srsmaeda for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
8861d4b38e0Srsmaeda if (strcmp(ksp->ks_module, "cpu_info") == 0)
8871d4b38e0Srsmaeda cp[ncpu++] = ksp->ks_instance;
8881d4b38e0Srsmaeda }
8891d4b38e0Srsmaeda
8901d4b38e0Srsmaeda dump_cpu_list("syscpus: ", cp, ncpu);
8911d4b38e0Srsmaeda
8921d4b38e0Srsmaeda (void) kstat_close(kc);
8931d4b38e0Srsmaeda
8941d4b38e0Srsmaeda *cpuids = cp;
8951d4b38e0Srsmaeda *ncpuids = ncpu;
8961d4b38e0Srsmaeda
8971d4b38e0Srsmaeda return (0);
8981d4b38e0Srsmaeda }
8991d4b38e0Srsmaeda
9001d4b38e0Srsmaeda static boolean_t
is_cpu_in_list(cpuid_t cpuid,cpuid_t * list,int len)9011d4b38e0Srsmaeda is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len)
9021d4b38e0Srsmaeda {
9031d4b38e0Srsmaeda int idx;
9041d4b38e0Srsmaeda
9051d4b38e0Srsmaeda if (list == NULL)
9061d4b38e0Srsmaeda return (B_FALSE);
9071d4b38e0Srsmaeda
9081d4b38e0Srsmaeda for (idx = 0; idx < len; idx++) {
9091d4b38e0Srsmaeda if (list[idx] == cpuid)
9101d4b38e0Srsmaeda return (B_TRUE);
9111d4b38e0Srsmaeda }
9121d4b38e0Srsmaeda
9131d4b38e0Srsmaeda return (B_FALSE);
9141d4b38e0Srsmaeda }
9151d4b38e0Srsmaeda
9161d4b38e0Srsmaeda #define CPUIDS_PER_LINE 16
9171d4b38e0Srsmaeda #define LINEWIDTH (2 * (CPUIDS_PER_LINE * 4))
9181d4b38e0Srsmaeda
9191d4b38e0Srsmaeda static void
dump_cpu_list(char * prefix,cpuid_t * cpuids,int ncpuids)9201d4b38e0Srsmaeda dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids)
9211d4b38e0Srsmaeda {
9221d4b38e0Srsmaeda char line[LINEWIDTH];
9231d4b38e0Srsmaeda char *curr;
9241d4b38e0Srsmaeda int i, j;
9251d4b38e0Srsmaeda
9261d4b38e0Srsmaeda /* return if not debugging */
9271d4b38e0Srsmaeda if (drd_debug == 0)
9281d4b38e0Srsmaeda return;
9291d4b38e0Srsmaeda
9301d4b38e0Srsmaeda /* print just the prefix if CPU list is empty */
9311d4b38e0Srsmaeda if (ncpuids == 0) {
9321d4b38e0Srsmaeda if (prefix)
9331d4b38e0Srsmaeda drd_dbg("%s", prefix);
9341d4b38e0Srsmaeda return;
9351d4b38e0Srsmaeda }
9361d4b38e0Srsmaeda
9371d4b38e0Srsmaeda for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) {
9381d4b38e0Srsmaeda
9391d4b38e0Srsmaeda bzero(line, LINEWIDTH);
9401d4b38e0Srsmaeda curr = line;
9411d4b38e0Srsmaeda
9421d4b38e0Srsmaeda /* start with the prefix */
9431d4b38e0Srsmaeda (void) sprintf(curr, "%s", (prefix) ? prefix : "");
9441d4b38e0Srsmaeda curr = line + strlen(line);
9451d4b38e0Srsmaeda
9461d4b38e0Srsmaeda /* format the CPUs for this line */
9471d4b38e0Srsmaeda for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) {
9481d4b38e0Srsmaeda (void) sprintf(curr, "%3d ", cpuids[i + j]);
9491d4b38e0Srsmaeda curr = line + strlen(line);
9501d4b38e0Srsmaeda }
9511d4b38e0Srsmaeda
9521d4b38e0Srsmaeda drd_dbg("%s", line);
9531d4b38e0Srsmaeda }
9541d4b38e0Srsmaeda }
9551d4b38e0Srsmaeda
9561d4b38e0Srsmaeda static void
dump_cpu_rsrc_list(char * prefix,drctl_rsrc_t * rsrcs,int nrsrc)9571d4b38e0Srsmaeda dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
9581d4b38e0Srsmaeda {
9591d4b38e0Srsmaeda int idx;
9601d4b38e0Srsmaeda char *errstr;
9611d4b38e0Srsmaeda
9621d4b38e0Srsmaeda /* just return if not debugging */
9631d4b38e0Srsmaeda if (drd_debug == 0)
9641d4b38e0Srsmaeda return;
9651d4b38e0Srsmaeda
9661d4b38e0Srsmaeda if (prefix)
9671d4b38e0Srsmaeda drd_dbg("%s", prefix);
9681d4b38e0Srsmaeda
9691d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) {
9701d4b38e0Srsmaeda
9711d4b38e0Srsmaeda /* get a pointer to the error string */
9721d4b38e0Srsmaeda errstr = (char *)(uintptr_t)rsrcs[idx].offset;
9731d4b38e0Srsmaeda
9741d4b38e0Srsmaeda drd_dbg(" cpu[%d]: cpuid=%d, status=%d, errstr='%s'", idx,
9751d4b38e0Srsmaeda rsrcs[idx].res_cpu_id, rsrcs[idx].status,
9761d4b38e0Srsmaeda (errstr != NULL) ? errstr : "");
9771d4b38e0Srsmaeda }
9781d4b38e0Srsmaeda }
9791d4b38e0Srsmaeda
9801d4b38e0Srsmaeda static void
dump_cpu_rlist(char ** rlist)9811d4b38e0Srsmaeda dump_cpu_rlist(char **rlist)
9821d4b38e0Srsmaeda {
9831d4b38e0Srsmaeda int idx;
9841d4b38e0Srsmaeda int state;
9851d4b38e0Srsmaeda
9861d4b38e0Srsmaeda static char *rcm_state_str[] = {
9871d4b38e0Srsmaeda "UNKNOWN", "ONLINE", "ONLINING",
9881d4b38e0Srsmaeda "OFFLINE_FAIL", "OFFLINING", "OFFLINE",
9891d4b38e0Srsmaeda "REMOVING", "INVALID_7", "INVALID_8",
9901d4b38e0Srsmaeda "INVALID_9", "RESUMING", "SUSPEND_FAIL",
9911d4b38e0Srsmaeda "SUSPENDING", "SUSPEND", "REMOVE",
9921d4b38e0Srsmaeda "OFFLINE_QUERYING", "OFFLINE_QUERY_FAIL", "OFFLINE_QUERY",
9931d4b38e0Srsmaeda "SUSPEND_QUERYING", "SUSPEND_QUERY_FAIL", "SUSPEND_QUERY"
9941d4b38e0Srsmaeda };
9951d4b38e0Srsmaeda
9961d4b38e0Srsmaeda /* just return if not debugging */
9971d4b38e0Srsmaeda if (drd_debug == 0)
9981d4b38e0Srsmaeda return;
9991d4b38e0Srsmaeda
10001d4b38e0Srsmaeda if (rlist == NULL) {
10011d4b38e0Srsmaeda drd_dbg(" empty rlist");
10021d4b38e0Srsmaeda return;
10031d4b38e0Srsmaeda }
10041d4b38e0Srsmaeda
10051d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) {
10061d4b38e0Srsmaeda state = 0;
10071d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
10081d4b38e0Srsmaeda drd_dbg(" rlist[%d]: rsrc=%s, state=%-2d (%s)", idx,
10091d4b38e0Srsmaeda rlist[idx], state, rcm_state_str[state]);
10101d4b38e0Srsmaeda }
10111d4b38e0Srsmaeda }
10128fea755aSjm22469
10138fea755aSjm22469 static int
drd_rcm_io_config_request(drctl_rsrc_t * rsrc,int nrsrc)10148fea755aSjm22469 drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc)
10158fea755aSjm22469 {
10168fea755aSjm22469 drd_dbg("drd_rcm_io_config_request...");
10178fea755aSjm22469
10188fea755aSjm22469 if (nrsrc != 1) {
10198fea755aSjm22469 drd_dbg("drd_rcm_cpu_config_request: only 1 resource "
10208fea755aSjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc);
10218fea755aSjm22469 rsrc->status = DRCTL_STATUS_DENY;
10228fea755aSjm22469
10238fea755aSjm22469 return (-1);
10248fea755aSjm22469 }
10258fea755aSjm22469
10268fea755aSjm22469 /*
10278fea755aSjm22469 * There is no RCM operation to request the addition
10288fea755aSjm22469 * of resources. So, by definition, the operation for
10298fea755aSjm22469 * the current resource is allowed.
10308fea755aSjm22469 */
10318fea755aSjm22469 rsrc->status = DRCTL_STATUS_ALLOW;
10328fea755aSjm22469
10338fea755aSjm22469 return (0);
10348fea755aSjm22469 }
10358fea755aSjm22469
10368fea755aSjm22469 /*ARGSUSED*/
10378fea755aSjm22469 static int
drd_rcm_io_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)10388fea755aSjm22469 drd_rcm_io_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
10398fea755aSjm22469 {
10408fea755aSjm22469 drd_dbg("drd_rcm_io_config_notify...");
10418fea755aSjm22469
10428fea755aSjm22469 if (nrsrc != 1) {
10438fea755aSjm22469 drd_dbg("drd_rcm_cpu_config_notify: only 1 resource "
10448fea755aSjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc);
10458fea755aSjm22469
10468fea755aSjm22469 return (-1);
10478fea755aSjm22469 }
10488fea755aSjm22469
10498fea755aSjm22469 return (0);
10508fea755aSjm22469 }
10518fea755aSjm22469
10528fea755aSjm22469
10538fea755aSjm22469 static int
drd_rcm_io_unconfig_request(drctl_rsrc_t * rsrc,int nrsrc)10548fea755aSjm22469 drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc)
10558fea755aSjm22469 {
10568fea755aSjm22469 int rv;
10578fea755aSjm22469 char *dev = rsrc->res_dev_path;
10588fea755aSjm22469 rcm_info_t *rinfo = NULL;
10598fea755aSjm22469
10608fea755aSjm22469 if (nrsrc != 1) {
10618fea755aSjm22469 drd_dbg("drd_io_unconfig_request: only 1 resource "
10628fea755aSjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc);
10638fea755aSjm22469 rsrc->status = DRCTL_STATUS_DENY;
10648fea755aSjm22469
10658fea755aSjm22469 return (-1);
10668fea755aSjm22469 }
10678fea755aSjm22469
10688fea755aSjm22469 if ((rv = rcm_request_offline(rcm_hdl, dev, 0, &rinfo)) == RCM_SUCCESS)
10698fea755aSjm22469 rsrc->status = DRCTL_STATUS_ALLOW;
10708fea755aSjm22469 else {
10718fea755aSjm22469 rcm_notify_online(rcm_hdl, dev, 0, NULL);
10728fea755aSjm22469 rsrc->status = DRCTL_STATUS_DENY;
10738fea755aSjm22469 rsrc->offset = (uintptr_t)rcm_info_table(rinfo);
10748fea755aSjm22469
10758fea755aSjm22469 }
10768fea755aSjm22469
10778fea755aSjm22469 rcm_free_info(rinfo);
10788fea755aSjm22469 drd_dbg("drd_rcm_io_unconfig_request(%s) = %d", dev, rv);
10798fea755aSjm22469
10808fea755aSjm22469 return (rv);
10818fea755aSjm22469 }
10828fea755aSjm22469
10838fea755aSjm22469 static int
drd_rcm_io_unconfig_notify(drctl_rsrc_t * rsrc,int nrsrc)10848fea755aSjm22469 drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc)
10858fea755aSjm22469 {
10868fea755aSjm22469 drd_dbg("drd_rcm_io_unconfig_notify...");
10878fea755aSjm22469
10888fea755aSjm22469 if (nrsrc != 1) {
10898fea755aSjm22469 drd_dbg("drd_io_cpu_unconfig_notify: only 1 resource "
10908fea755aSjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc);
10918fea755aSjm22469
10928fea755aSjm22469 return (-1);
10938fea755aSjm22469 }
10948fea755aSjm22469
10958fea755aSjm22469 return (rcm_notify_remove(rcm_hdl, rsrc->res_dev_path, 0, NULL));
10968fea755aSjm22469 }
10978fea755aSjm22469
10988fea755aSjm22469 #define MAX_FORMAT 80
10998fea755aSjm22469
11008fea755aSjm22469 /*
11018fea755aSjm22469 * Convert rcm_info_t data into a printable table.
11028fea755aSjm22469 */
11038fea755aSjm22469 static char *
rcm_info_table(rcm_info_t * rinfo)11048fea755aSjm22469 rcm_info_table(rcm_info_t *rinfo)
11058fea755aSjm22469 {
11068fea755aSjm22469 int i;
11078fea755aSjm22469 size_t w;
11088fea755aSjm22469 size_t width = 0;
11098fea755aSjm22469 size_t w_rsrc = 0;
11108fea755aSjm22469 size_t w_info = 0;
11118fea755aSjm22469 size_t table_size = 0;
11128fea755aSjm22469 uint_t tuples = 0;
11138fea755aSjm22469 rcm_info_tuple_t *tuple = NULL;
11148fea755aSjm22469 char *rsrc;
11158fea755aSjm22469 char *info;
11168fea755aSjm22469 char *table;
11178fea755aSjm22469 static char format[MAX_FORMAT];
11188fea755aSjm22469 const char *infostr;
11198fea755aSjm22469
11208fea755aSjm22469 /* Protect against invalid arguments */
11218fea755aSjm22469 if (rinfo == NULL)
11228fea755aSjm22469 return (NULL);
11238fea755aSjm22469
11248fea755aSjm22469 /* Set localized table header strings */
11258fea755aSjm22469 rsrc = dgettext(TEXT_DOMAIN, "Resource");
11268fea755aSjm22469 info = dgettext(TEXT_DOMAIN, "Information");
11278fea755aSjm22469
11288fea755aSjm22469 /* A first pass, to size up the RCM information */
11298fea755aSjm22469 while (tuple = rcm_info_next(rinfo, tuple)) {
11308fea755aSjm22469 if ((infostr = rcm_info_info(tuple)) != NULL) {
11318fea755aSjm22469 tuples++;
11328fea755aSjm22469 if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
11338fea755aSjm22469 w_rsrc = w;
11348fea755aSjm22469 if ((w = strlen(infostr)) > w_info)
11358fea755aSjm22469 w_info = w;
11368fea755aSjm22469 }
11378fea755aSjm22469 }
11388fea755aSjm22469
11398fea755aSjm22469 /* If nothing was sized up above, stop early */
11408fea755aSjm22469 if (tuples == 0)
11418fea755aSjm22469 return (NULL);
11428fea755aSjm22469
11438fea755aSjm22469 /* Adjust column widths for column headings */
11448fea755aSjm22469 if ((w = strlen(rsrc)) > w_rsrc)
11458fea755aSjm22469 w_rsrc = w;
11468fea755aSjm22469 else if ((w_rsrc - w) % 2)
11478fea755aSjm22469 w_rsrc++;
11488fea755aSjm22469 if ((w = strlen(info)) > w_info)
11498fea755aSjm22469 w_info = w;
11508fea755aSjm22469 else if ((w_info - w) % 2)
11518fea755aSjm22469 w_info++;
11528fea755aSjm22469
11538fea755aSjm22469 /*
11548fea755aSjm22469 * Compute the total line width of each line,
11558fea755aSjm22469 * accounting for intercolumn spacing.
11568fea755aSjm22469 */
11578fea755aSjm22469 width = w_info + w_rsrc + 4;
11588fea755aSjm22469
11598fea755aSjm22469 /* Allocate space for the table */
11608fea755aSjm22469 table_size = (2 + tuples) * (width + 1) + 2;
11618fea755aSjm22469
11628fea755aSjm22469 /* zero fill for the strcat() call below */
11638fea755aSjm22469 table = calloc(table_size, sizeof (char));
11648fea755aSjm22469 if (table == NULL)
11658fea755aSjm22469 return (NULL);
11668fea755aSjm22469
11678fea755aSjm22469 /* Place a table header into the string */
11688fea755aSjm22469
11698fea755aSjm22469 /* The resource header */
11708fea755aSjm22469 (void) strcat(table, "\n");
11718fea755aSjm22469 w = strlen(rsrc);
11728fea755aSjm22469 for (i = 0; i < ((w_rsrc - w) / 2); i++)
11738fea755aSjm22469 (void) strcat(table, " ");
11748fea755aSjm22469 (void) strcat(table, rsrc);
11758fea755aSjm22469 for (i = 0; i < ((w_rsrc - w) / 2); i++)
11768fea755aSjm22469 (void) strcat(table, " ");
11778fea755aSjm22469
11788fea755aSjm22469 /* The information header */
11798fea755aSjm22469 (void) strcat(table, " ");
11808fea755aSjm22469 w = strlen(info);
11818fea755aSjm22469 for (i = 0; i < ((w_info - w) / 2); i++)
11828fea755aSjm22469 (void) strcat(table, " ");
11838fea755aSjm22469 (void) strcat(table, info);
11848fea755aSjm22469 for (i = 0; i < ((w_info - w) / 2); i++)
11858fea755aSjm22469 (void) strcat(table, " ");
11868fea755aSjm22469 /* Underline the headers */
11878fea755aSjm22469 (void) strcat(table, "\n");
11888fea755aSjm22469 for (i = 0; i < w_rsrc; i++)
11898fea755aSjm22469 (void) strcat(table, "-");
11908fea755aSjm22469 (void) strcat(table, " ");
11918fea755aSjm22469 for (i = 0; i < w_info; i++)
11928fea755aSjm22469 (void) strcat(table, "-");
11938fea755aSjm22469
11948fea755aSjm22469 /* Construct the format string */
11958fea755aSjm22469 (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds",
11968fea755aSjm22469 (int)w_rsrc, (int)w_info);
11978fea755aSjm22469
11988fea755aSjm22469 /* Add the tuples to the table string */
11998fea755aSjm22469 tuple = NULL;
12008fea755aSjm22469 while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
12018fea755aSjm22469 if ((infostr = rcm_info_info(tuple)) != NULL) {
12028fea755aSjm22469 (void) strcat(table, "\n");
12038fea755aSjm22469 (void) sprintf(&((table)[strlen(table)]),
12048fea755aSjm22469 format, rcm_info_rsrc(tuple),
12058fea755aSjm22469 infostr);
12068fea755aSjm22469 }
12078fea755aSjm22469 }
12088fea755aSjm22469 drd_dbg("rcm_info_table: %s\n", table);
12098fea755aSjm22469
12108fea755aSjm22469 return (table);
12118fea755aSjm22469 }
1212*9853d9e8SJason Beloro
1213*9853d9e8SJason Beloro static void
dump_mem_rsrc_list(char * prefix,drctl_rsrc_t * rsrcs,int nrsrc)1214*9853d9e8SJason Beloro dump_mem_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
1215*9853d9e8SJason Beloro {
1216*9853d9e8SJason Beloro int idx;
1217*9853d9e8SJason Beloro char *errstr;
1218*9853d9e8SJason Beloro
1219*9853d9e8SJason Beloro /* just return if not debugging */
1220*9853d9e8SJason Beloro if (drd_debug == 0)
1221*9853d9e8SJason Beloro return;
1222*9853d9e8SJason Beloro
1223*9853d9e8SJason Beloro if (prefix)
1224*9853d9e8SJason Beloro drd_dbg("%s", prefix);
1225*9853d9e8SJason Beloro
1226*9853d9e8SJason Beloro for (idx = 0; idx < nrsrc; idx++) {
1227*9853d9e8SJason Beloro
1228*9853d9e8SJason Beloro /* get a pointer to the error string */
1229*9853d9e8SJason Beloro errstr = (char *)(uintptr_t)rsrcs[idx].offset;
1230*9853d9e8SJason Beloro
1231*9853d9e8SJason Beloro drd_dbg(" mem[%d]: addr=0x%llx, size=0x%llx"
1232*9853d9e8SJason Beloro " status=%d, errstr='%s'", idx,
1233*9853d9e8SJason Beloro rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size,
1234*9853d9e8SJason Beloro rsrcs[idx].status, (errstr != NULL) ? errstr : "");
1235*9853d9e8SJason Beloro }
1236*9853d9e8SJason Beloro }
1237*9853d9e8SJason Beloro
1238*9853d9e8SJason Beloro static int
drd_rcm_mem_op(rcm_op_t op,uint64_t change)1239*9853d9e8SJason Beloro drd_rcm_mem_op(rcm_op_t op, uint64_t change)
1240*9853d9e8SJason Beloro {
1241*9853d9e8SJason Beloro int rv = -1;
1242*9853d9e8SJason Beloro int pgsize;
1243*9853d9e8SJason Beloro long oldpages;
1244*9853d9e8SJason Beloro long newpages;
1245*9853d9e8SJason Beloro nvlist_t *nvl = NULL;
1246*9853d9e8SJason Beloro rcm_info_t *rinfo;
1247*9853d9e8SJason Beloro
1248*9853d9e8SJason Beloro /* allocate an nvlist for the RCM call */
1249*9853d9e8SJason Beloro if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1250*9853d9e8SJason Beloro goto done;
1251*9853d9e8SJason Beloro
1252*9853d9e8SJason Beloro if ((pgsize = sysconf(_SC_PAGE_SIZE)) == -1 ||
1253*9853d9e8SJason Beloro (newpages = sysconf(_SC_PHYS_PAGES)) == -1)
1254*9853d9e8SJason Beloro goto done;
1255*9853d9e8SJason Beloro
1256*9853d9e8SJason Beloro /*
1257*9853d9e8SJason Beloro * If this is a notify add, the capacity change
1258*9853d9e8SJason Beloro * was positive and the current page count reflects
1259*9853d9e8SJason Beloro * the new capacity level.
1260*9853d9e8SJason Beloro *
1261*9853d9e8SJason Beloro * If this is a request del, the capacity change
1262*9853d9e8SJason Beloro * is negative and the current page count will
1263*9853d9e8SJason Beloro * reflect the old capacity level.
1264*9853d9e8SJason Beloro */
1265*9853d9e8SJason Beloro assert(change % pgsize == 0);
1266*9853d9e8SJason Beloro if (change > 0) {
1267*9853d9e8SJason Beloro oldpages = newpages - (long)(change / pgsize);
1268*9853d9e8SJason Beloro } else {
1269*9853d9e8SJason Beloro assert(newpages >= change / pgsize);
1270*9853d9e8SJason Beloro oldpages = newpages;
1271*9853d9e8SJason Beloro newpages = oldpages + (long)(change / pgsize);
1272*9853d9e8SJason Beloro }
1273*9853d9e8SJason Beloro
1274*9853d9e8SJason Beloro drd_dbg("oldpages=%lld newpages=%lld delta=%lld",
1275*9853d9e8SJason Beloro oldpages, newpages, newpages - oldpages);
1276*9853d9e8SJason Beloro
1277*9853d9e8SJason Beloro /* setup the nvlist for the RCM call */
1278*9853d9e8SJason Beloro if (nvlist_add_string(nvl, "state", "capacity") != 0 ||
1279*9853d9e8SJason Beloro nvlist_add_int32(nvl, "page_size", pgsize) != 0 ||
1280*9853d9e8SJason Beloro nvlist_add_int32(nvl, "old_pages", oldpages) != 0 ||
1281*9853d9e8SJason Beloro nvlist_add_int32(nvl, "new_pages", newpages) != 0) {
1282*9853d9e8SJason Beloro goto done;
1283*9853d9e8SJason Beloro }
1284*9853d9e8SJason Beloro
1285*9853d9e8SJason Beloro rv = (*op)(rcm_hdl, RCM_MEM_ALL, 0, nvl, &rinfo);
1286*9853d9e8SJason Beloro rv = (rv == RCM_SUCCESS) ? 0 : -1;
1287*9853d9e8SJason Beloro
1288*9853d9e8SJason Beloro done:
1289*9853d9e8SJason Beloro s_nvfree(nvl);
1290*9853d9e8SJason Beloro
1291*9853d9e8SJason Beloro return (rv);
1292*9853d9e8SJason Beloro }
1293*9853d9e8SJason Beloro
1294*9853d9e8SJason Beloro /*
1295*9853d9e8SJason Beloro * RCM clients can interpose only on removal of resources.
1296*9853d9e8SJason Beloro */
1297*9853d9e8SJason Beloro static int
drd_rcm_mem_config_request(drctl_rsrc_t * rsrcs,int nrsrc)1298*9853d9e8SJason Beloro drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
1299*9853d9e8SJason Beloro {
1300*9853d9e8SJason Beloro int idx;
1301*9853d9e8SJason Beloro
1302*9853d9e8SJason Beloro drd_dbg("drd_rcm_mem_config_request...");
1303*9853d9e8SJason Beloro
1304*9853d9e8SJason Beloro if ((rsrcs == NULL) || (nrsrc == 0))
1305*9853d9e8SJason Beloro return (0);
1306*9853d9e8SJason Beloro dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1307*9853d9e8SJason Beloro
1308*9853d9e8SJason Beloro /*
1309*9853d9e8SJason Beloro * There is no RCM operation to request the addition
1310*9853d9e8SJason Beloro * of resources. So, by definition, the operation for
1311*9853d9e8SJason Beloro * all the memory is allowed.
1312*9853d9e8SJason Beloro */
1313*9853d9e8SJason Beloro for (idx = 0; idx < nrsrc; idx++)
1314*9853d9e8SJason Beloro rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1315*9853d9e8SJason Beloro
1316*9853d9e8SJason Beloro dump_mem_rsrc_list("returning:", rsrcs, nrsrc);
1317*9853d9e8SJason Beloro
1318*9853d9e8SJason Beloro return (0);
1319*9853d9e8SJason Beloro }
1320*9853d9e8SJason Beloro
1321*9853d9e8SJason Beloro static int
drd_rcm_mem_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)1322*9853d9e8SJason Beloro drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1323*9853d9e8SJason Beloro {
1324*9853d9e8SJason Beloro int idx;
1325*9853d9e8SJason Beloro int rv = -1;
1326*9853d9e8SJason Beloro uint64_t change = 0;
1327*9853d9e8SJason Beloro
1328*9853d9e8SJason Beloro drd_dbg("drd_rcm_mem_config_notify...");
1329*9853d9e8SJason Beloro
1330*9853d9e8SJason Beloro if ((rsrcs == NULL) || (nrsrc == 0)) {
1331*9853d9e8SJason Beloro drd_err("mem_config_notify: mem list empty");
1332*9853d9e8SJason Beloro goto done;
1333*9853d9e8SJason Beloro }
1334*9853d9e8SJason Beloro dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1335*9853d9e8SJason Beloro
1336*9853d9e8SJason Beloro for (idx = 0; idx < nrsrc; idx++) {
1337*9853d9e8SJason Beloro if (rsrcs[idx].status == DRCTL_STATUS_CONFIG_SUCCESS)
1338*9853d9e8SJason Beloro change += rsrcs[idx].res_mem_size;
1339*9853d9e8SJason Beloro drd_dbg(" idx=%d addr=0x%llx size=0x%llx",
1340*9853d9e8SJason Beloro idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1341*9853d9e8SJason Beloro }
1342*9853d9e8SJason Beloro
1343*9853d9e8SJason Beloro rv = drd_rcm_mem_op(rcm_notify_capacity_change, change);
1344*9853d9e8SJason Beloro done:
1345*9853d9e8SJason Beloro return (rv);
1346*9853d9e8SJason Beloro }
1347*9853d9e8SJason Beloro
1348*9853d9e8SJason Beloro static int
drd_rcm_mem_unconfig_request(drctl_rsrc_t * rsrcs,int nrsrc)1349*9853d9e8SJason Beloro drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
1350*9853d9e8SJason Beloro {
1351*9853d9e8SJason Beloro int rv = -1;
1352*9853d9e8SJason Beloro int idx;
1353*9853d9e8SJason Beloro uint64_t change = 0;
1354*9853d9e8SJason Beloro
1355*9853d9e8SJason Beloro drd_dbg("drd_rcm_del_mem_request...");
1356*9853d9e8SJason Beloro
1357*9853d9e8SJason Beloro if ((rsrcs == NULL) || (nrsrc == 0)) {
1358*9853d9e8SJason Beloro drd_err("mem_unconfig_request: mem list empty");
1359*9853d9e8SJason Beloro goto done;
1360*9853d9e8SJason Beloro }
1361*9853d9e8SJason Beloro dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1362*9853d9e8SJason Beloro
1363*9853d9e8SJason Beloro for (idx = 0; idx < nrsrc; idx++) {
1364*9853d9e8SJason Beloro drd_dbg(" idx=%d addr=0x%llx size=0x%llx",
1365*9853d9e8SJason Beloro idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1366*9853d9e8SJason Beloro change += rsrcs[idx].res_mem_size;
1367*9853d9e8SJason Beloro }
1368*9853d9e8SJason Beloro
1369*9853d9e8SJason Beloro rv = drd_rcm_mem_op(rcm_request_capacity_change, -change);
1370*9853d9e8SJason Beloro
1371*9853d9e8SJason Beloro if (rv != RCM_SUCCESS) {
1372*9853d9e8SJason Beloro drd_dbg("RCM call failed: %d", rv);
1373*9853d9e8SJason Beloro /*
1374*9853d9e8SJason Beloro * Since the capacity change was blocked, we
1375*9853d9e8SJason Beloro * mark all mblocks as blocked. It is up to the
1376*9853d9e8SJason Beloro * user to reframe the query so that it can
1377*9853d9e8SJason Beloro * succeed.
1378*9853d9e8SJason Beloro */
1379*9853d9e8SJason Beloro for (idx = 0; idx < nrsrc; idx++) {
1380*9853d9e8SJason Beloro rsrcs[idx].status = DRCTL_STATUS_DENY;
1381*9853d9e8SJason Beloro }
1382*9853d9e8SJason Beloro
1383*9853d9e8SJason Beloro /* tack on message to first resource */
1384*9853d9e8SJason Beloro rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
1385*9853d9e8SJason Beloro "specified amount of memory");
1386*9853d9e8SJason Beloro drd_dbg(" unable to remove specified amount of memory");
1387*9853d9e8SJason Beloro } else {
1388*9853d9e8SJason Beloro for (idx = 0; idx < nrsrc; idx++)
1389*9853d9e8SJason Beloro rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1390*9853d9e8SJason Beloro rv = 0;
1391*9853d9e8SJason Beloro }
1392*9853d9e8SJason Beloro
1393*9853d9e8SJason Beloro done:
1394*9853d9e8SJason Beloro
1395*9853d9e8SJason Beloro dump_mem_rsrc_list("returning:", rsrcs, nrsrc);
1396*9853d9e8SJason Beloro return (rv);
1397*9853d9e8SJason Beloro }
1398*9853d9e8SJason Beloro
1399*9853d9e8SJason Beloro static int
drd_rcm_mem_unconfig_notify(drctl_rsrc_t * rsrcs,int nrsrc)1400*9853d9e8SJason Beloro drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1401*9853d9e8SJason Beloro {
1402*9853d9e8SJason Beloro int idx;
1403*9853d9e8SJason Beloro int rv = -1;
1404*9853d9e8SJason Beloro uint64_t change = 0;
1405*9853d9e8SJason Beloro
1406*9853d9e8SJason Beloro drd_dbg("drd_rcm_mem_unconfig_notify...");
1407*9853d9e8SJason Beloro
1408*9853d9e8SJason Beloro if ((rsrcs == NULL) || (nrsrc == 0)) {
1409*9853d9e8SJason Beloro drd_err("unconfig_mem_notify: mem list empty");
1410*9853d9e8SJason Beloro goto done;
1411*9853d9e8SJason Beloro }
1412*9853d9e8SJason Beloro dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1413*9853d9e8SJason Beloro
1414*9853d9e8SJason Beloro /*
1415*9853d9e8SJason Beloro * Filter out the memory that was configured.
1416*9853d9e8SJason Beloro *
1417*9853d9e8SJason Beloro * We need to notify RCM about a memory capacity change
1418*9853d9e8SJason Beloro * only if the memory unconfigure request wasn't successful
1419*9853d9e8SJason Beloro * because if both the RCM capacity delete request and the
1420*9853d9e8SJason Beloro * memory unconfigure succeed, this notify would give a
1421*9853d9e8SJason Beloro * memory capacity identical to the delete request.
1422*9853d9e8SJason Beloro */
1423*9853d9e8SJason Beloro for (idx = 0; idx < nrsrc; idx++) {
1424*9853d9e8SJason Beloro if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
1425*9853d9e8SJason Beloro change += rsrcs[idx].res_mem_size;
1426*9853d9e8SJason Beloro drd_dbg(" idx=%d addr=0x%llx size=0x%llx",
1427*9853d9e8SJason Beloro idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1428*9853d9e8SJason Beloro }
1429*9853d9e8SJason Beloro
1430*9853d9e8SJason Beloro rv = drd_rcm_mem_op(rcm_notify_capacity_change, change);
1431*9853d9e8SJason Beloro done:
1432*9853d9e8SJason Beloro return (rv);
1433*9853d9e8SJason Beloro }
1434