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*8fea755aSjm22469 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241d4b38e0Srsmaeda * Use is subject to license terms. 251d4b38e0Srsmaeda */ 261d4b38e0Srsmaeda 271d4b38e0Srsmaeda #pragma ident "%Z%%M% %I% %E% SMI" 281d4b38e0Srsmaeda 291d4b38e0Srsmaeda /* 301d4b38e0Srsmaeda * RCM backend for the DR Daemon 311d4b38e0Srsmaeda */ 321d4b38e0Srsmaeda 331d4b38e0Srsmaeda #include <unistd.h> 341d4b38e0Srsmaeda #include <strings.h> 351d4b38e0Srsmaeda #include <errno.h> 361d4b38e0Srsmaeda #include <kstat.h> 371d4b38e0Srsmaeda #include <libnvpair.h> 381d4b38e0Srsmaeda #include <librcm.h> 39*8fea755aSjm22469 #include <locale.h> 401d4b38e0Srsmaeda 411d4b38e0Srsmaeda #include "drd.h" 421d4b38e0Srsmaeda 431d4b38e0Srsmaeda /* 441d4b38e0Srsmaeda * RCM Backend Support 451d4b38e0Srsmaeda */ 461d4b38e0Srsmaeda static int drd_rcm_init(void); 471d4b38e0Srsmaeda static int drd_rcm_fini(void); 481d4b38e0Srsmaeda static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc); 491d4b38e0Srsmaeda static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc); 501d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc); 511d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc); 52*8fea755aSjm22469 static int drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc); 53*8fea755aSjm22469 static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc); 54*8fea755aSjm22469 static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc); 55*8fea755aSjm22469 static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc); 561d4b38e0Srsmaeda 571d4b38e0Srsmaeda drd_backend_t drd_rcm_backend = { 581d4b38e0Srsmaeda drd_rcm_init, /* init */ 591d4b38e0Srsmaeda drd_rcm_fini, /* fini */ 601d4b38e0Srsmaeda drd_rcm_cpu_config_request, /* cpu_config_request */ 611d4b38e0Srsmaeda drd_rcm_cpu_config_notify, /* cpu_config_notify */ 621d4b38e0Srsmaeda drd_rcm_cpu_unconfig_request, /* cpu_unconfig_request */ 63*8fea755aSjm22469 drd_rcm_cpu_unconfig_notify, /* cpu_unconfig_notify */ 64*8fea755aSjm22469 drd_rcm_io_config_request, /* io_config_request */ 65*8fea755aSjm22469 drd_rcm_io_config_notify, /* io_config_notify */ 66*8fea755aSjm22469 drd_rcm_io_unconfig_request, /* io_unconfig_request */ 67*8fea755aSjm22469 drd_rcm_io_unconfig_notify /* io_unconfig_notify */ 681d4b38e0Srsmaeda }; 691d4b38e0Srsmaeda 701d4b38e0Srsmaeda #define RCM_CPU_ALL "SUNW_cpu" 711d4b38e0Srsmaeda #define RCM_CPU RCM_CPU_ALL"/cpu" 721d4b38e0Srsmaeda #define RCM_CPU_MAX_LEN (32) 731d4b38e0Srsmaeda 741d4b38e0Srsmaeda /* global RCM handle used in all RCM operations */ 751d4b38e0Srsmaeda static rcm_handle_t *rcm_hdl; 761d4b38e0Srsmaeda 771d4b38e0Srsmaeda /* functions that call into RCM */ 781d4b38e0Srsmaeda static int drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 791d4b38e0Srsmaeda static int drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 801d4b38e0Srsmaeda static int drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc); 811d4b38e0Srsmaeda static int drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc); 821d4b38e0Srsmaeda static int drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 831d4b38e0Srsmaeda static int drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 841d4b38e0Srsmaeda static int drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 851d4b38e0Srsmaeda 861d4b38e0Srsmaeda /* utility functions */ 871d4b38e0Srsmaeda static char **drd_rcm_cpu_rlist_init(drctl_rsrc_t *, int nrsrc, int status); 881d4b38e0Srsmaeda static void drd_rcm_cpu_rlist_fini(char **rlist); 891d4b38e0Srsmaeda static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int); 901d4b38e0Srsmaeda static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids); 911d4b38e0Srsmaeda static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len); 92*8fea755aSjm22469 static char *rcm_info_table(rcm_info_t *rinfo); 931d4b38e0Srsmaeda 941d4b38e0Srsmaeda /* debugging utility functions */ 951d4b38e0Srsmaeda static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids); 961d4b38e0Srsmaeda static void dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *, int nrsrc); 971d4b38e0Srsmaeda static void dump_cpu_rlist(char **rlist); 981d4b38e0Srsmaeda 991d4b38e0Srsmaeda static int 1001d4b38e0Srsmaeda drd_rcm_init(void) 1011d4b38e0Srsmaeda { 1021d4b38e0Srsmaeda int rv; 1031d4b38e0Srsmaeda 1041d4b38e0Srsmaeda drd_dbg("drd_rcm_init..."); 1051d4b38e0Srsmaeda 1061d4b38e0Srsmaeda rv = rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl); 1071d4b38e0Srsmaeda if (rv == RCM_FAILURE) { 1081d4b38e0Srsmaeda drd_err("unable to allocate RCM handle: %s", strerror(errno)); 1091d4b38e0Srsmaeda return (-1); 1101d4b38e0Srsmaeda } 1111d4b38e0Srsmaeda 1121d4b38e0Srsmaeda return (0); 1131d4b38e0Srsmaeda } 1141d4b38e0Srsmaeda 1151d4b38e0Srsmaeda static int 1161d4b38e0Srsmaeda drd_rcm_fini(void) 1171d4b38e0Srsmaeda { 1181d4b38e0Srsmaeda drd_dbg("drd_rcm_fini..."); 1191d4b38e0Srsmaeda 1201d4b38e0Srsmaeda if (rcm_hdl != NULL) 1211d4b38e0Srsmaeda rcm_free_handle(rcm_hdl); 1221d4b38e0Srsmaeda 1231d4b38e0Srsmaeda return (0); 1241d4b38e0Srsmaeda } 1251d4b38e0Srsmaeda 1261d4b38e0Srsmaeda static int 1271d4b38e0Srsmaeda drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc) 1281d4b38e0Srsmaeda { 1291d4b38e0Srsmaeda int idx; 1301d4b38e0Srsmaeda 1311d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_config_request..."); 1321d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 1331d4b38e0Srsmaeda 1341d4b38e0Srsmaeda /* 1351d4b38e0Srsmaeda * There is no RCM operation to request the addition 1361d4b38e0Srsmaeda * of resources. So, by definition, the operation for 1371d4b38e0Srsmaeda * all the CPUs is allowed. 1381d4b38e0Srsmaeda */ 1391d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) 1401d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_ALLOW; 1411d4b38e0Srsmaeda 1421d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 1431d4b38e0Srsmaeda 1441d4b38e0Srsmaeda return (0); 1451d4b38e0Srsmaeda } 1461d4b38e0Srsmaeda 1471d4b38e0Srsmaeda static int 1481d4b38e0Srsmaeda drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc) 1491d4b38e0Srsmaeda { 1501d4b38e0Srsmaeda int rv = 0; 1511d4b38e0Srsmaeda 1521d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_config_notify..."); 1531d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 1541d4b38e0Srsmaeda 1551d4b38e0Srsmaeda /* notify RCM about the newly added CPUs */ 1561d4b38e0Srsmaeda if (drd_rcm_online_cpu_notify(rsrcs, nrsrc) != 0) { 1571d4b38e0Srsmaeda rv = -1; 1581d4b38e0Srsmaeda goto done; 1591d4b38e0Srsmaeda } 1601d4b38e0Srsmaeda 1611d4b38e0Srsmaeda /* notify RCM about the increased CPU capacity */ 1621d4b38e0Srsmaeda if (drd_rcm_add_cpu_notify(rsrcs, nrsrc) != 0) { 1631d4b38e0Srsmaeda rv = -1; 1641d4b38e0Srsmaeda } 1651d4b38e0Srsmaeda 1661d4b38e0Srsmaeda done: 1671d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 1681d4b38e0Srsmaeda 1691d4b38e0Srsmaeda return (rv); 1701d4b38e0Srsmaeda } 1711d4b38e0Srsmaeda 1721d4b38e0Srsmaeda static int 1731d4b38e0Srsmaeda drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc) 1741d4b38e0Srsmaeda { 1751d4b38e0Srsmaeda int rv = 0; 1761d4b38e0Srsmaeda int idx; 1771d4b38e0Srsmaeda 1781d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_unconfig_request..."); 1791d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 1801d4b38e0Srsmaeda 1811d4b38e0Srsmaeda /* contact RCM to request a decrease in CPU capacity */ 1821d4b38e0Srsmaeda if (drd_rcm_del_cpu_request(rsrcs, nrsrc) != 0) { 1831d4b38e0Srsmaeda rv = -1; 1841d4b38e0Srsmaeda goto done; 1851d4b38e0Srsmaeda } 1861d4b38e0Srsmaeda 1871d4b38e0Srsmaeda /* contact RCM to request the removal of CPUs */ 1881d4b38e0Srsmaeda if (drd_rcm_offline_cpu_request(rsrcs, nrsrc) != 0) { 1891d4b38e0Srsmaeda rv = -1; 1901d4b38e0Srsmaeda goto done; 1911d4b38e0Srsmaeda } 1921d4b38e0Srsmaeda 1931d4b38e0Srsmaeda done: 1941d4b38e0Srsmaeda /* 1951d4b38e0Srsmaeda * If any errors occurred, the status field for 1961d4b38e0Srsmaeda * a CPU may still be in the INIT state. Set the 1971d4b38e0Srsmaeda * status for any such CPU to DENY to ensure it 1981d4b38e0Srsmaeda * gets processed properly. 1991d4b38e0Srsmaeda */ 2001d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 2011d4b38e0Srsmaeda if (rsrcs[idx].status == DRCTL_STATUS_INIT) 2021d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_DENY; 2031d4b38e0Srsmaeda } 2041d4b38e0Srsmaeda 2051d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 2061d4b38e0Srsmaeda 2071d4b38e0Srsmaeda return (rv); 2081d4b38e0Srsmaeda } 2091d4b38e0Srsmaeda 2101d4b38e0Srsmaeda static int 2111d4b38e0Srsmaeda drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc) 2121d4b38e0Srsmaeda { 2131d4b38e0Srsmaeda int rv = 0; 2141d4b38e0Srsmaeda 2151d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_unconfig_notify..."); 2161d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 2171d4b38e0Srsmaeda 2181d4b38e0Srsmaeda /* 2191d4b38e0Srsmaeda * Notify RCM about the CPUs that were removed. 2201d4b38e0Srsmaeda * Failures are ignored so that CPUs that could 2211d4b38e0Srsmaeda * not be unconfigured can be processed by RCM. 2221d4b38e0Srsmaeda */ 2231d4b38e0Srsmaeda (void) drd_rcm_remove_cpu_notify(rsrcs, nrsrc); 2241d4b38e0Srsmaeda 2251d4b38e0Srsmaeda /* 2261d4b38e0Srsmaeda * Notify RCM about any CPUs that did not make it 2271d4b38e0Srsmaeda * in to the unconfigured state. 2281d4b38e0Srsmaeda */ 2291d4b38e0Srsmaeda if (drd_rcm_restore_cpu_notify(rsrcs, nrsrc) != 0) { 2301d4b38e0Srsmaeda rv = -1; 2311d4b38e0Srsmaeda goto done; 2321d4b38e0Srsmaeda } 2331d4b38e0Srsmaeda 2341d4b38e0Srsmaeda /* notify RCM about the decreased CPU capacity */ 2351d4b38e0Srsmaeda if (drd_rcm_del_cpu_notify(rsrcs, nrsrc) != 0) { 2361d4b38e0Srsmaeda rv = -1; 2371d4b38e0Srsmaeda } 2381d4b38e0Srsmaeda 2391d4b38e0Srsmaeda done: 2401d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 2411d4b38e0Srsmaeda 2421d4b38e0Srsmaeda return (rv); 2431d4b38e0Srsmaeda } 2441d4b38e0Srsmaeda 2451d4b38e0Srsmaeda static int 2461d4b38e0Srsmaeda drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 2471d4b38e0Srsmaeda { 2481d4b38e0Srsmaeda char **rlist; 2491d4b38e0Srsmaeda int rv = 0; 2501d4b38e0Srsmaeda rcm_info_t *rinfo; 2511d4b38e0Srsmaeda 2521d4b38e0Srsmaeda drd_dbg("drd_rcm_online_cpu_notify..."); 2531d4b38e0Srsmaeda 2541d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 2551d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) { 2561d4b38e0Srsmaeda drd_dbg(" no CPUs were successfully added, nothing to do"); 2571d4b38e0Srsmaeda return (0); 2581d4b38e0Srsmaeda } 2591d4b38e0Srsmaeda 2601d4b38e0Srsmaeda rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo); 2611d4b38e0Srsmaeda if (rv != RCM_SUCCESS) { 2621d4b38e0Srsmaeda drd_info("rcm_notify_online_list failed: %d", rv); 2631d4b38e0Srsmaeda rcm_free_info(rinfo); 2641d4b38e0Srsmaeda rv = -1; 2651d4b38e0Srsmaeda } 2661d4b38e0Srsmaeda 2671d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist); 2681d4b38e0Srsmaeda 2691d4b38e0Srsmaeda return (rv); 2701d4b38e0Srsmaeda } 2711d4b38e0Srsmaeda 2721d4b38e0Srsmaeda static int 2731d4b38e0Srsmaeda drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 2741d4b38e0Srsmaeda { 2751d4b38e0Srsmaeda cpuid_t *cpus = NULL; 2761d4b38e0Srsmaeda int ncpus; 2771d4b38e0Srsmaeda int rv = -1; 2781d4b38e0Srsmaeda cpuid_t *oldcpus = NULL; 2791d4b38e0Srsmaeda cpuid_t *newcpus = NULL; 2801d4b38e0Srsmaeda int oldncpus = 0; 2811d4b38e0Srsmaeda int newncpus = 0; 2821d4b38e0Srsmaeda nvlist_t *nvl = NULL; 2831d4b38e0Srsmaeda int idx; 2841d4b38e0Srsmaeda rcm_info_t *rinfo; 2851d4b38e0Srsmaeda 2861d4b38e0Srsmaeda drd_dbg("drd_rcm_add_cpu_notify..."); 2871d4b38e0Srsmaeda 2881d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) { 2891d4b38e0Srsmaeda drd_err("add_cpu_notify: cpu list empty"); 2901d4b38e0Srsmaeda goto done; 2911d4b38e0Srsmaeda } 2921d4b38e0Srsmaeda 2931d4b38e0Srsmaeda ncpus = nrsrc; 2941d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 2951d4b38e0Srsmaeda 2961d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 2971d4b38e0Srsmaeda drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id); 2981d4b38e0Srsmaeda cpus[idx] = rsrcs[idx].res_cpu_id; 2991d4b38e0Srsmaeda } 3001d4b38e0Srsmaeda 3011d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */ 3021d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 3031d4b38e0Srsmaeda goto done; 3041d4b38e0Srsmaeda 3051d4b38e0Srsmaeda /* 3061d4b38e0Srsmaeda * Added CPU capacity, so newcpus is the current list 3071d4b38e0Srsmaeda * of CPUs in the system. 3081d4b38e0Srsmaeda */ 3091d4b38e0Srsmaeda if (get_sys_cpuids(&newcpus, &newncpus) == -1) 3101d4b38e0Srsmaeda goto done; 3111d4b38e0Srsmaeda 3121d4b38e0Srsmaeda /* 3131d4b38e0Srsmaeda * Since the operation added CPU capacity, the old CPU 3141d4b38e0Srsmaeda * list is the new CPU list with the CPUs involved in 3151d4b38e0Srsmaeda * the operation removed. 3161d4b38e0Srsmaeda */ 3171d4b38e0Srsmaeda oldcpus = (cpuid_t *)calloc(newncpus, sizeof (cpuid_t)); 3181d4b38e0Srsmaeda if (oldcpus == NULL) 3191d4b38e0Srsmaeda goto done; 3201d4b38e0Srsmaeda 3211d4b38e0Srsmaeda for (idx = 0; idx < newncpus; idx++) { 3221d4b38e0Srsmaeda if (!is_cpu_in_list(newcpus[idx], cpus, ncpus)) 3231d4b38e0Srsmaeda oldcpus[oldncpus++] = newcpus[idx]; 3241d4b38e0Srsmaeda } 3251d4b38e0Srsmaeda 3261d4b38e0Srsmaeda /* dump pre and post lists */ 3271d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 3281d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus); 3291d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, ncpus); 3301d4b38e0Srsmaeda 3311d4b38e0Srsmaeda /* setup the nvlist for the RCM call */ 3321d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") || 3331d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) || 3341d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) || 3351d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 3361d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 3371d4b38e0Srsmaeda goto done; 3381d4b38e0Srsmaeda } 3391d4b38e0Srsmaeda 3401d4b38e0Srsmaeda rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 3411d4b38e0Srsmaeda rv = (rv == RCM_SUCCESS) ? 0 : -1; 3421d4b38e0Srsmaeda 3431d4b38e0Srsmaeda done: 3441d4b38e0Srsmaeda s_nvfree(nvl); 3451d4b38e0Srsmaeda s_free(cpus); 3461d4b38e0Srsmaeda s_free(oldcpus); 3471d4b38e0Srsmaeda s_free(newcpus); 3481d4b38e0Srsmaeda 3491d4b38e0Srsmaeda return (rv); 3501d4b38e0Srsmaeda } 3511d4b38e0Srsmaeda 3521d4b38e0Srsmaeda static int 3531d4b38e0Srsmaeda drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc) 3541d4b38e0Srsmaeda { 3551d4b38e0Srsmaeda cpuid_t *cpus = NULL; 3561d4b38e0Srsmaeda int ncpus; 3571d4b38e0Srsmaeda int rv = -1; 3581d4b38e0Srsmaeda cpuid_t *oldcpus = NULL; 3591d4b38e0Srsmaeda cpuid_t *newcpus = NULL; 3601d4b38e0Srsmaeda int oldncpus = 0; 3611d4b38e0Srsmaeda int newncpus = 0; 3621d4b38e0Srsmaeda nvlist_t *nvl = NULL; 3631d4b38e0Srsmaeda int idx; 3641d4b38e0Srsmaeda rcm_info_t *rinfo; 3651d4b38e0Srsmaeda 3661d4b38e0Srsmaeda drd_dbg("drd_rcm_del_cpu_request..."); 3671d4b38e0Srsmaeda 3681d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) { 3691d4b38e0Srsmaeda drd_err("del_cpu_request: cpu list empty"); 3701d4b38e0Srsmaeda goto done; 3711d4b38e0Srsmaeda } 3721d4b38e0Srsmaeda 3731d4b38e0Srsmaeda ncpus = nrsrc; 3741d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 3751d4b38e0Srsmaeda 3761d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 3771d4b38e0Srsmaeda cpus[idx] = rsrcs[idx].res_cpu_id; 3781d4b38e0Srsmaeda } 3791d4b38e0Srsmaeda 3801d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */ 3811d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 3821d4b38e0Srsmaeda goto done; 3831d4b38e0Srsmaeda } 3841d4b38e0Srsmaeda 3851d4b38e0Srsmaeda /* 3861d4b38e0Srsmaeda * Removing CPU capacity, so oldcpus is the current 3871d4b38e0Srsmaeda * list of CPUs in the system. 3881d4b38e0Srsmaeda */ 3891d4b38e0Srsmaeda if (get_sys_cpuids(&oldcpus, &oldncpus) == -1) { 3901d4b38e0Srsmaeda goto done; 3911d4b38e0Srsmaeda } 3921d4b38e0Srsmaeda 3931d4b38e0Srsmaeda /* 3941d4b38e0Srsmaeda * Since this is a request to remove CPU capacity, 3951d4b38e0Srsmaeda * the new CPU list is the old CPU list with the CPUs 3961d4b38e0Srsmaeda * involved in the operation removed. 3971d4b38e0Srsmaeda */ 3981d4b38e0Srsmaeda newcpus = (cpuid_t *)calloc(oldncpus, sizeof (cpuid_t)); 3991d4b38e0Srsmaeda if (newcpus == NULL) { 4001d4b38e0Srsmaeda goto done; 4011d4b38e0Srsmaeda } 4021d4b38e0Srsmaeda 4031d4b38e0Srsmaeda for (idx = 0; idx < oldncpus; idx++) { 4041d4b38e0Srsmaeda if (!is_cpu_in_list(oldcpus[idx], cpus, ncpus)) 4051d4b38e0Srsmaeda newcpus[newncpus++] = oldcpus[idx]; 4061d4b38e0Srsmaeda } 4071d4b38e0Srsmaeda 4081d4b38e0Srsmaeda /* dump pre and post lists */ 4091d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 4101d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus); 4111d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, ncpus); 4121d4b38e0Srsmaeda 4131d4b38e0Srsmaeda /* setup the nvlist for the RCM call */ 4141d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") || 4151d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) || 4161d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) || 4171d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 4181d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 4191d4b38e0Srsmaeda goto done; 4201d4b38e0Srsmaeda } 4211d4b38e0Srsmaeda 4221d4b38e0Srsmaeda rv = rcm_request_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 4231d4b38e0Srsmaeda if (rv != RCM_SUCCESS) { 4241d4b38e0Srsmaeda drd_dbg("RCM call failed: %d", rv); 4251d4b38e0Srsmaeda /* 4261d4b38e0Srsmaeda * Since the capcity change was blocked, we 4271d4b38e0Srsmaeda * mark all CPUs as blocked. It is up to the 4281d4b38e0Srsmaeda * user to reframe the query so that it can 4291d4b38e0Srsmaeda * succeed. 4301d4b38e0Srsmaeda */ 4311d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 4321d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_DENY; 4331d4b38e0Srsmaeda } 4341d4b38e0Srsmaeda 4351d4b38e0Srsmaeda /* tack on message to first resource */ 4361d4b38e0Srsmaeda rsrcs[0].offset = (uintptr_t)strdup("unable to remove " 4371d4b38e0Srsmaeda "specified number of CPUs"); 4381d4b38e0Srsmaeda drd_dbg(" unable to remove specified number of CPUs"); 4391d4b38e0Srsmaeda goto done; 4401d4b38e0Srsmaeda } 4411d4b38e0Srsmaeda 4421d4b38e0Srsmaeda rv = 0; 4431d4b38e0Srsmaeda 4441d4b38e0Srsmaeda done: 4451d4b38e0Srsmaeda s_nvfree(nvl); 4461d4b38e0Srsmaeda s_free(cpus); 4471d4b38e0Srsmaeda s_free(oldcpus); 4481d4b38e0Srsmaeda s_free(newcpus); 4491d4b38e0Srsmaeda 4501d4b38e0Srsmaeda return (rv); 4511d4b38e0Srsmaeda } 4521d4b38e0Srsmaeda 4531d4b38e0Srsmaeda static int 4541d4b38e0Srsmaeda drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc) 4551d4b38e0Srsmaeda { 4561d4b38e0Srsmaeda char **rlist; 4571d4b38e0Srsmaeda drctl_rsrc_t *rsrc; 4581d4b38e0Srsmaeda int idx; 4591d4b38e0Srsmaeda int state; 4601d4b38e0Srsmaeda int rv = 0; 4611d4b38e0Srsmaeda rcm_info_t *rinfo = NULL; 4621d4b38e0Srsmaeda rcm_info_tuple_t *tuple = NULL; 4631d4b38e0Srsmaeda const char *rsrcstr; 4641d4b38e0Srsmaeda const char *errstr; 4651d4b38e0Srsmaeda 4661d4b38e0Srsmaeda drd_dbg("drd_rcm_offline_cpu_request..."); 4671d4b38e0Srsmaeda 4681d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 4691d4b38e0Srsmaeda DRCTL_STATUS_INIT)) == NULL) { 4701d4b38e0Srsmaeda drd_err("unable to generate resource list"); 4711d4b38e0Srsmaeda return (-1); 4721d4b38e0Srsmaeda } 4731d4b38e0Srsmaeda 4741d4b38e0Srsmaeda rv = rcm_request_offline_list(rcm_hdl, rlist, 0, &rinfo); 4751d4b38e0Srsmaeda if (rv == RCM_SUCCESS) { 4761d4b38e0Srsmaeda drd_dbg("RCM success, rinfo=%p", rinfo); 4771d4b38e0Srsmaeda goto done; 4781d4b38e0Srsmaeda } 4791d4b38e0Srsmaeda 4801d4b38e0Srsmaeda drd_dbg("RCM call failed (%d):", rv); 4811d4b38e0Srsmaeda 4821d4b38e0Srsmaeda /* 4831d4b38e0Srsmaeda * Loop through the result of the operation and add 4841d4b38e0Srsmaeda * any error messages to the resource structure. 4851d4b38e0Srsmaeda */ 4861d4b38e0Srsmaeda while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { 4871d4b38e0Srsmaeda 4881d4b38e0Srsmaeda /* find the resource of interest */ 4891d4b38e0Srsmaeda rsrcstr = rcm_info_rsrc(tuple); 4901d4b38e0Srsmaeda rsrc = cpu_rsrcstr_to_rsrc(rsrcstr, rsrcs, nrsrc); 4911d4b38e0Srsmaeda 4921d4b38e0Srsmaeda if (rsrc == NULL) { 4931d4b38e0Srsmaeda drd_dbg("unable to find resource for %s", rsrcstr); 4941d4b38e0Srsmaeda continue; 4951d4b38e0Srsmaeda } 4961d4b38e0Srsmaeda 4971d4b38e0Srsmaeda errstr = rcm_info_error(tuple); 4981d4b38e0Srsmaeda 4991d4b38e0Srsmaeda if (errstr) { 5001d4b38e0Srsmaeda drd_dbg(" %s: '%s'", rsrcstr, errstr); 5011d4b38e0Srsmaeda rsrc->offset = (uintptr_t)strdup(errstr); 5021d4b38e0Srsmaeda } 5031d4b38e0Srsmaeda } 5041d4b38e0Srsmaeda 5051d4b38e0Srsmaeda rcm_free_info(rinfo); 5061d4b38e0Srsmaeda rv = 0; 5071d4b38e0Srsmaeda 5081d4b38e0Srsmaeda done: 5091d4b38e0Srsmaeda /* 5101d4b38e0Srsmaeda * Set the state of the resource based on the RCM 5111d4b38e0Srsmaeda * state. CPUs in the offline state have the ok to 5121d4b38e0Srsmaeda * proceed. All others have been blocked. 5131d4b38e0Srsmaeda */ 5141d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) { 5151d4b38e0Srsmaeda 5161d4b38e0Srsmaeda state = 0; 5171d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state); 5181d4b38e0Srsmaeda 5191d4b38e0Srsmaeda /* find the resource of interest */ 5201d4b38e0Srsmaeda rsrc = cpu_rsrcstr_to_rsrc(rlist[idx], rsrcs, nrsrc); 5211d4b38e0Srsmaeda 5221d4b38e0Srsmaeda if (rsrc == NULL) { 5231d4b38e0Srsmaeda drd_dbg("unable to find resource for %s", rlist[idx]); 5241d4b38e0Srsmaeda continue; 5251d4b38e0Srsmaeda } 5261d4b38e0Srsmaeda 5271d4b38e0Srsmaeda rsrc->status = ((state == RCM_STATE_OFFLINE) ? 5281d4b38e0Srsmaeda DRCTL_STATUS_ALLOW : DRCTL_STATUS_DENY); 5291d4b38e0Srsmaeda } 5301d4b38e0Srsmaeda 5311d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist); 5321d4b38e0Srsmaeda 5331d4b38e0Srsmaeda return (rv); 5341d4b38e0Srsmaeda } 5351d4b38e0Srsmaeda 5361d4b38e0Srsmaeda static int 5371d4b38e0Srsmaeda drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 5381d4b38e0Srsmaeda { 5391d4b38e0Srsmaeda char **rlist; 5401d4b38e0Srsmaeda int rv = 0; 5411d4b38e0Srsmaeda rcm_info_t *rinfo; 5421d4b38e0Srsmaeda 5431d4b38e0Srsmaeda drd_dbg("drd_rcm_remove_cpu_notify..."); 5441d4b38e0Srsmaeda 5451d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 5461d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) { 5471d4b38e0Srsmaeda drd_dbg(" no CPUs in the success state, nothing to do"); 5481d4b38e0Srsmaeda return (0); 5491d4b38e0Srsmaeda } 5501d4b38e0Srsmaeda 5511d4b38e0Srsmaeda rv = rcm_notify_remove_list(rcm_hdl, rlist, 0, &rinfo); 5521d4b38e0Srsmaeda if (rv != RCM_SUCCESS) { 5531d4b38e0Srsmaeda drd_info("rcm_notify_remove_list failed: %d", rv); 5541d4b38e0Srsmaeda rcm_free_info(rinfo); 5551d4b38e0Srsmaeda rv = -1; 5561d4b38e0Srsmaeda } 5571d4b38e0Srsmaeda 5581d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist); 5591d4b38e0Srsmaeda 5601d4b38e0Srsmaeda return (rv); 5611d4b38e0Srsmaeda } 5621d4b38e0Srsmaeda 5631d4b38e0Srsmaeda static int 5641d4b38e0Srsmaeda drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 5651d4b38e0Srsmaeda { 5661d4b38e0Srsmaeda char **rlist; 5671d4b38e0Srsmaeda char **full_rlist; 5681d4b38e0Srsmaeda int idx; 5691d4b38e0Srsmaeda int ridx; 5701d4b38e0Srsmaeda int state; 5711d4b38e0Srsmaeda int rv = 0; 5721d4b38e0Srsmaeda rcm_info_t *rinfo; 5731d4b38e0Srsmaeda 5741d4b38e0Srsmaeda drd_dbg("drd_rcm_restore_cpu_notify..."); 5751d4b38e0Srsmaeda 5761d4b38e0Srsmaeda if ((full_rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 5771d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_FAILURE)) == NULL) { 5781d4b38e0Srsmaeda drd_dbg(" no CPUs in the failed state, nothing to do"); 5791d4b38e0Srsmaeda return (0); 5801d4b38e0Srsmaeda } 5811d4b38e0Srsmaeda 5821d4b38e0Srsmaeda /* 5831d4b38e0Srsmaeda * Since the desired result of this operation is to 5841d4b38e0Srsmaeda * restore resources to the online state, filter out 5851d4b38e0Srsmaeda * the resources already in the online state before 5861d4b38e0Srsmaeda * passing the list to RCM. 5871d4b38e0Srsmaeda */ 5881d4b38e0Srsmaeda 5891d4b38e0Srsmaeda /* allocate a zero filled array to ensure NULL terminated list */ 5901d4b38e0Srsmaeda rlist = (char **)calloc((nrsrc + 1), sizeof (char *)); 5911d4b38e0Srsmaeda if (rlist == NULL) { 5921d4b38e0Srsmaeda drd_err("calloc failed: %s", strerror(errno)); 5931d4b38e0Srsmaeda rv = -1; 5941d4b38e0Srsmaeda goto done; 5951d4b38e0Srsmaeda } 5961d4b38e0Srsmaeda 5971d4b38e0Srsmaeda for (idx = 0, ridx = 0; full_rlist[idx] != NULL; idx++) { 5981d4b38e0Srsmaeda state = 0; 5991d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, full_rlist[idx], &state); 6001d4b38e0Srsmaeda if (state != RCM_STATE_ONLINE) { 6011d4b38e0Srsmaeda rlist[ridx] = full_rlist[idx]; 6021d4b38e0Srsmaeda ridx++; 6031d4b38e0Srsmaeda } 6041d4b38e0Srsmaeda } 6051d4b38e0Srsmaeda 6061d4b38e0Srsmaeda /* check if everything got filtered out */ 6071d4b38e0Srsmaeda if (ridx == 0) { 6081d4b38e0Srsmaeda drd_dbg(" all CPUs already online, nothing to do"); 6091d4b38e0Srsmaeda goto done; 6101d4b38e0Srsmaeda } 6111d4b38e0Srsmaeda 6121d4b38e0Srsmaeda rv = rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo); 6131d4b38e0Srsmaeda if (rv != RCM_SUCCESS) { 6141d4b38e0Srsmaeda drd_info("rcm_notify_online_list failed: %d", rv); 6151d4b38e0Srsmaeda rcm_free_info(rinfo); 6161d4b38e0Srsmaeda rv = -1; 6171d4b38e0Srsmaeda } 6181d4b38e0Srsmaeda 6191d4b38e0Srsmaeda done: 6201d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(full_rlist); 6211d4b38e0Srsmaeda s_free(rlist); 6221d4b38e0Srsmaeda 6231d4b38e0Srsmaeda return (rv); 6241d4b38e0Srsmaeda } 6251d4b38e0Srsmaeda 6261d4b38e0Srsmaeda static int 6271d4b38e0Srsmaeda drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 6281d4b38e0Srsmaeda { 6291d4b38e0Srsmaeda cpuid_t *cpus = NULL; 6301d4b38e0Srsmaeda int rv = -1; 6311d4b38e0Srsmaeda cpuid_t *oldcpus = NULL; 6321d4b38e0Srsmaeda cpuid_t *newcpus = NULL; 6331d4b38e0Srsmaeda int oldncpus = 0; 6341d4b38e0Srsmaeda int newncpus = 0; 6351d4b38e0Srsmaeda nvlist_t *nvl = NULL; 6361d4b38e0Srsmaeda int idx; 6371d4b38e0Srsmaeda int cidx; 6381d4b38e0Srsmaeda rcm_info_t *rinfo; 6391d4b38e0Srsmaeda 6401d4b38e0Srsmaeda drd_dbg("drd_rcm_del_cpu_notify..."); 6411d4b38e0Srsmaeda 6421d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) { 6431d4b38e0Srsmaeda drd_err("del_cpu_notify: cpu list empty"); 6441d4b38e0Srsmaeda goto done; 6451d4b38e0Srsmaeda } 6461d4b38e0Srsmaeda 6471d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 6481d4b38e0Srsmaeda 6491d4b38e0Srsmaeda /* 6501d4b38e0Srsmaeda * Filter out the CPUs that could not be unconfigured. 6511d4b38e0Srsmaeda */ 6521d4b38e0Srsmaeda for (idx = 0, cidx = 0; idx < nrsrc; idx++) { 6531d4b38e0Srsmaeda if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS) 6541d4b38e0Srsmaeda continue; 6551d4b38e0Srsmaeda drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id); 6561d4b38e0Srsmaeda cpus[cidx] = rsrcs[idx].res_cpu_id; 6571d4b38e0Srsmaeda cidx++; 6581d4b38e0Srsmaeda } 6591d4b38e0Srsmaeda 6601d4b38e0Srsmaeda drd_dbg(" ncpus = %d", cidx); 6611d4b38e0Srsmaeda 6621d4b38e0Srsmaeda /* nothing to do */ 6631d4b38e0Srsmaeda if (cidx == 0) { 6641d4b38e0Srsmaeda rv = 0; 6651d4b38e0Srsmaeda goto done; 6661d4b38e0Srsmaeda } 6671d4b38e0Srsmaeda 6681d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */ 6691d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 6701d4b38e0Srsmaeda goto done; 6711d4b38e0Srsmaeda } 6721d4b38e0Srsmaeda 6731d4b38e0Srsmaeda /* 6741d4b38e0Srsmaeda * Removed CPU capacity, so newcpus is the current list 6751d4b38e0Srsmaeda * of CPUs in the system. 6761d4b38e0Srsmaeda */ 6771d4b38e0Srsmaeda if (get_sys_cpuids(&newcpus, &newncpus) == -1) { 6781d4b38e0Srsmaeda goto done; 6791d4b38e0Srsmaeda } 6801d4b38e0Srsmaeda 6811d4b38e0Srsmaeda /* 6821d4b38e0Srsmaeda * Since the operation removed CPU capacity, the old CPU 6831d4b38e0Srsmaeda * list is the new CPU list with the CPUs involved in 6841d4b38e0Srsmaeda * the operation added. 6851d4b38e0Srsmaeda */ 6861d4b38e0Srsmaeda oldcpus = (cpuid_t *)calloc(newncpus + cidx, sizeof (cpuid_t)); 6871d4b38e0Srsmaeda if (oldcpus == NULL) { 6881d4b38e0Srsmaeda goto done; 6891d4b38e0Srsmaeda } 6901d4b38e0Srsmaeda 6911d4b38e0Srsmaeda for (idx = 0; idx < newncpus; idx++) { 6921d4b38e0Srsmaeda if (!is_cpu_in_list(newcpus[idx], cpus, cidx)) 6931d4b38e0Srsmaeda oldcpus[oldncpus++] = newcpus[idx]; 6941d4b38e0Srsmaeda } 6951d4b38e0Srsmaeda 6961d4b38e0Srsmaeda for (idx = 0; idx < cidx; idx++) { 6971d4b38e0Srsmaeda oldcpus[oldncpus++] = cpus[idx]; 6981d4b38e0Srsmaeda } 6991d4b38e0Srsmaeda 7001d4b38e0Srsmaeda /* dump pre and post lists */ 7011d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 7021d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus); 7031d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, cidx); 7041d4b38e0Srsmaeda 7051d4b38e0Srsmaeda /* setup the nvlist for the RCM call */ 7061d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") || 7071d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) || 7081d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) || 7091d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 7101d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 7111d4b38e0Srsmaeda goto done; 7121d4b38e0Srsmaeda } 7131d4b38e0Srsmaeda 7141d4b38e0Srsmaeda rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 7151d4b38e0Srsmaeda rv = (rv == RCM_SUCCESS) ? 0 : -1; 7161d4b38e0Srsmaeda 7171d4b38e0Srsmaeda done: 7181d4b38e0Srsmaeda s_nvfree(nvl); 7191d4b38e0Srsmaeda s_free(cpus); 7201d4b38e0Srsmaeda s_free(oldcpus); 7211d4b38e0Srsmaeda s_free(newcpus); 7221d4b38e0Srsmaeda 7231d4b38e0Srsmaeda return (rv); 7241d4b38e0Srsmaeda } 7251d4b38e0Srsmaeda 7261d4b38e0Srsmaeda /* 7271d4b38e0Srsmaeda * Given a list of resource structures, create a list of CPU 7281d4b38e0Srsmaeda * resource strings formatted as expected by RCM. Only resources 7291d4b38e0Srsmaeda * that are in the state specified by the status argument are 7301d4b38e0Srsmaeda * included in the resulting list. 7311d4b38e0Srsmaeda */ 7321d4b38e0Srsmaeda static char ** 7331d4b38e0Srsmaeda drd_rcm_cpu_rlist_init(drctl_rsrc_t *rsrcs, int nrsrc, int status) 7341d4b38e0Srsmaeda { 7351d4b38e0Srsmaeda char rbuf[RCM_CPU_MAX_LEN]; 7361d4b38e0Srsmaeda char **rlist; 7371d4b38e0Srsmaeda int idx; 7381d4b38e0Srsmaeda int ridx; 7391d4b38e0Srsmaeda 7401d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_rlist_init..."); 7411d4b38e0Srsmaeda 7421d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) { 7431d4b38e0Srsmaeda drd_dbg("cpu list is empty"); 7441d4b38e0Srsmaeda return (NULL); 7451d4b38e0Srsmaeda } 7461d4b38e0Srsmaeda 7471d4b38e0Srsmaeda /* allocate a zero filled array to ensure NULL terminated list */ 7481d4b38e0Srsmaeda rlist = (char **)calloc((nrsrc + 1), sizeof (char *)); 7491d4b38e0Srsmaeda if (rlist == NULL) { 7501d4b38e0Srsmaeda drd_err("calloc failed: %s", strerror(errno)); 7511d4b38e0Srsmaeda return (NULL); 7521d4b38e0Srsmaeda } 7531d4b38e0Srsmaeda 7541d4b38e0Srsmaeda for (idx = 0, ridx = 0; idx < nrsrc; idx++) { 7551d4b38e0Srsmaeda 7561d4b38e0Srsmaeda drd_dbg(" checking cpu %d, status=%d, expected status=%d", 7571d4b38e0Srsmaeda rsrcs[idx].res_cpu_id, rsrcs[idx].status, status); 7581d4b38e0Srsmaeda 7591d4b38e0Srsmaeda /* 7601d4b38e0Srsmaeda * Filter out the CPUs that are not in 7611d4b38e0Srsmaeda * the requested state. 7621d4b38e0Srsmaeda */ 7631d4b38e0Srsmaeda if (rsrcs[idx].status != status) 7641d4b38e0Srsmaeda continue; 7651d4b38e0Srsmaeda 7661d4b38e0Srsmaeda /* generate the resource string */ 7671d4b38e0Srsmaeda (void) sprintf(rbuf, "%s%d", RCM_CPU, rsrcs[idx].res_cpu_id); 7681d4b38e0Srsmaeda 7691d4b38e0Srsmaeda rlist[ridx] = strdup(rbuf); 7701d4b38e0Srsmaeda if (rlist[ridx] == NULL) { 7711d4b38e0Srsmaeda drd_err("strdup failed: %s", strerror(errno)); 7721d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist); 7731d4b38e0Srsmaeda return (NULL); 7741d4b38e0Srsmaeda } 7751d4b38e0Srsmaeda 7761d4b38e0Srsmaeda ridx++; 7771d4b38e0Srsmaeda } 7781d4b38e0Srsmaeda 7791d4b38e0Srsmaeda /* cleanup if the list is empty */ 7801d4b38e0Srsmaeda if (ridx == 0) { 7811d4b38e0Srsmaeda s_free(rlist); 7821d4b38e0Srsmaeda } 7831d4b38e0Srsmaeda 7841d4b38e0Srsmaeda drd_dbg("final rlist:"); 7851d4b38e0Srsmaeda dump_cpu_rlist(rlist); 7861d4b38e0Srsmaeda 7871d4b38e0Srsmaeda return (rlist); 7881d4b38e0Srsmaeda } 7891d4b38e0Srsmaeda 7901d4b38e0Srsmaeda static void 7911d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(char **rlist) 7921d4b38e0Srsmaeda { 7931d4b38e0Srsmaeda int idx; 7941d4b38e0Srsmaeda 7951d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_rlist_fini..."); 7961d4b38e0Srsmaeda 7971d4b38e0Srsmaeda dump_cpu_rlist(rlist); 7981d4b38e0Srsmaeda 7991d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) { 8001d4b38e0Srsmaeda s_free(rlist[idx]); 8011d4b38e0Srsmaeda } 8021d4b38e0Srsmaeda 8031d4b38e0Srsmaeda s_free(rlist); 8041d4b38e0Srsmaeda } 8051d4b38e0Srsmaeda 8061d4b38e0Srsmaeda /* 8071d4b38e0Srsmaeda * Convert an RCM CPU resource string into a numerical cpuid. 8081d4b38e0Srsmaeda * Assumes the resource string has the form: "SUNW_cpu/cpu<C>" 8091d4b38e0Srsmaeda * where "<C>" is the numerical cpuid of interest. 8101d4b38e0Srsmaeda */ 8111d4b38e0Srsmaeda static cpuid_t 8121d4b38e0Srsmaeda cpu_rsrcstr_to_cpuid(const char *rsrc) 8131d4b38e0Srsmaeda { 8141d4b38e0Srsmaeda char *cpuid_off; 8151d4b38e0Srsmaeda cpuid_t cpuid; 8161d4b38e0Srsmaeda 8171d4b38e0Srsmaeda /* 8181d4b38e0Srsmaeda * Search for the last occurrance of 'u' in the 8191d4b38e0Srsmaeda * expected RCM resource string "SUNW_cpu/cpu<C>". 8201d4b38e0Srsmaeda * This will give a pointer to the cpuid portion. 8211d4b38e0Srsmaeda */ 8221d4b38e0Srsmaeda cpuid_off = strrchr(rsrc, 'u'); 8231d4b38e0Srsmaeda cpuid_off++; 8241d4b38e0Srsmaeda 8251d4b38e0Srsmaeda cpuid = atoi(cpuid_off); 8261d4b38e0Srsmaeda 8271d4b38e0Srsmaeda return (cpuid); 8281d4b38e0Srsmaeda } 8291d4b38e0Srsmaeda 8301d4b38e0Srsmaeda /* 8311d4b38e0Srsmaeda * Given an RCM CPU resource string, return a pointer to the 8321d4b38e0Srsmaeda * corresponding resource structure from the given resource list. 8331d4b38e0Srsmaeda * NULL is returned if no matching resource structure can be 8341d4b38e0Srsmaeda * found. 8351d4b38e0Srsmaeda */ 8361d4b38e0Srsmaeda static drctl_rsrc_t * 8371d4b38e0Srsmaeda cpu_rsrcstr_to_rsrc(const char *rsrcstr, drctl_rsrc_t *rsrcs, int nrsrc) 8381d4b38e0Srsmaeda { 8391d4b38e0Srsmaeda cpuid_t cpuid; 8401d4b38e0Srsmaeda int idx; 8411d4b38e0Srsmaeda 8421d4b38e0Srsmaeda cpuid = cpu_rsrcstr_to_cpuid(rsrcstr); 8431d4b38e0Srsmaeda 8441d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 8451d4b38e0Srsmaeda if (rsrcs[idx].res_cpu_id == cpuid) 8461d4b38e0Srsmaeda return (&rsrcs[idx]); 8471d4b38e0Srsmaeda } 8481d4b38e0Srsmaeda 8491d4b38e0Srsmaeda return (NULL); 8501d4b38e0Srsmaeda } 8511d4b38e0Srsmaeda 8521d4b38e0Srsmaeda static int 8531d4b38e0Srsmaeda get_sys_cpuids(cpuid_t **cpuids, int *ncpuids) 8541d4b38e0Srsmaeda { 8551d4b38e0Srsmaeda int ncpu = 0; 8561d4b38e0Srsmaeda int maxncpu; 8571d4b38e0Srsmaeda kstat_t *ksp; 8581d4b38e0Srsmaeda kstat_ctl_t *kc = NULL; 8591d4b38e0Srsmaeda cpuid_t *cp; 8601d4b38e0Srsmaeda 8611d4b38e0Srsmaeda drd_dbg("get_sys_cpuids..."); 8621d4b38e0Srsmaeda 8631d4b38e0Srsmaeda if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1) 8641d4b38e0Srsmaeda return (-1); 8651d4b38e0Srsmaeda 8661d4b38e0Srsmaeda if ((kc = kstat_open()) == NULL) 8671d4b38e0Srsmaeda return (-1); 8681d4b38e0Srsmaeda 8691d4b38e0Srsmaeda if ((cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) { 8701d4b38e0Srsmaeda (void) kstat_close(kc); 8711d4b38e0Srsmaeda return (-1); 8721d4b38e0Srsmaeda } 8731d4b38e0Srsmaeda 8741d4b38e0Srsmaeda for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 8751d4b38e0Srsmaeda if (strcmp(ksp->ks_module, "cpu_info") == 0) 8761d4b38e0Srsmaeda cp[ncpu++] = ksp->ks_instance; 8771d4b38e0Srsmaeda } 8781d4b38e0Srsmaeda 8791d4b38e0Srsmaeda dump_cpu_list("syscpus: ", cp, ncpu); 8801d4b38e0Srsmaeda 8811d4b38e0Srsmaeda (void) kstat_close(kc); 8821d4b38e0Srsmaeda 8831d4b38e0Srsmaeda *cpuids = cp; 8841d4b38e0Srsmaeda *ncpuids = ncpu; 8851d4b38e0Srsmaeda 8861d4b38e0Srsmaeda return (0); 8871d4b38e0Srsmaeda } 8881d4b38e0Srsmaeda 8891d4b38e0Srsmaeda static boolean_t 8901d4b38e0Srsmaeda is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len) 8911d4b38e0Srsmaeda { 8921d4b38e0Srsmaeda int idx; 8931d4b38e0Srsmaeda 8941d4b38e0Srsmaeda if (list == NULL) 8951d4b38e0Srsmaeda return (B_FALSE); 8961d4b38e0Srsmaeda 8971d4b38e0Srsmaeda for (idx = 0; idx < len; idx++) { 8981d4b38e0Srsmaeda if (list[idx] == cpuid) 8991d4b38e0Srsmaeda return (B_TRUE); 9001d4b38e0Srsmaeda } 9011d4b38e0Srsmaeda 9021d4b38e0Srsmaeda return (B_FALSE); 9031d4b38e0Srsmaeda } 9041d4b38e0Srsmaeda 9051d4b38e0Srsmaeda #define CPUIDS_PER_LINE 16 9061d4b38e0Srsmaeda #define LINEWIDTH (2 * (CPUIDS_PER_LINE * 4)) 9071d4b38e0Srsmaeda 9081d4b38e0Srsmaeda static void 9091d4b38e0Srsmaeda dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids) 9101d4b38e0Srsmaeda { 9111d4b38e0Srsmaeda char line[LINEWIDTH]; 9121d4b38e0Srsmaeda char *curr; 9131d4b38e0Srsmaeda int i, j; 9141d4b38e0Srsmaeda 9151d4b38e0Srsmaeda /* return if not debugging */ 9161d4b38e0Srsmaeda if (drd_debug == 0) 9171d4b38e0Srsmaeda return; 9181d4b38e0Srsmaeda 9191d4b38e0Srsmaeda /* print just the prefix if CPU list is empty */ 9201d4b38e0Srsmaeda if (ncpuids == 0) { 9211d4b38e0Srsmaeda if (prefix) 9221d4b38e0Srsmaeda drd_dbg("%s", prefix); 9231d4b38e0Srsmaeda return; 9241d4b38e0Srsmaeda } 9251d4b38e0Srsmaeda 9261d4b38e0Srsmaeda for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) { 9271d4b38e0Srsmaeda 9281d4b38e0Srsmaeda bzero(line, LINEWIDTH); 9291d4b38e0Srsmaeda curr = line; 9301d4b38e0Srsmaeda 9311d4b38e0Srsmaeda /* start with the prefix */ 9321d4b38e0Srsmaeda (void) sprintf(curr, "%s", (prefix) ? prefix : ""); 9331d4b38e0Srsmaeda curr = line + strlen(line); 9341d4b38e0Srsmaeda 9351d4b38e0Srsmaeda /* format the CPUs for this line */ 9361d4b38e0Srsmaeda for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) { 9371d4b38e0Srsmaeda (void) sprintf(curr, "%3d ", cpuids[i + j]); 9381d4b38e0Srsmaeda curr = line + strlen(line); 9391d4b38e0Srsmaeda } 9401d4b38e0Srsmaeda 9411d4b38e0Srsmaeda drd_dbg("%s", line); 9421d4b38e0Srsmaeda } 9431d4b38e0Srsmaeda } 9441d4b38e0Srsmaeda 9451d4b38e0Srsmaeda static void 9461d4b38e0Srsmaeda dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc) 9471d4b38e0Srsmaeda { 9481d4b38e0Srsmaeda int idx; 9491d4b38e0Srsmaeda char *errstr; 9501d4b38e0Srsmaeda 9511d4b38e0Srsmaeda /* just return if not debugging */ 9521d4b38e0Srsmaeda if (drd_debug == 0) 9531d4b38e0Srsmaeda return; 9541d4b38e0Srsmaeda 9551d4b38e0Srsmaeda if (prefix) 9561d4b38e0Srsmaeda drd_dbg("%s", prefix); 9571d4b38e0Srsmaeda 9581d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 9591d4b38e0Srsmaeda 9601d4b38e0Srsmaeda /* get a pointer to the error string */ 9611d4b38e0Srsmaeda errstr = (char *)(uintptr_t)rsrcs[idx].offset; 9621d4b38e0Srsmaeda 9631d4b38e0Srsmaeda drd_dbg(" cpu[%d]: cpuid=%d, status=%d, errstr='%s'", idx, 9641d4b38e0Srsmaeda rsrcs[idx].res_cpu_id, rsrcs[idx].status, 9651d4b38e0Srsmaeda (errstr != NULL) ? errstr : ""); 9661d4b38e0Srsmaeda } 9671d4b38e0Srsmaeda } 9681d4b38e0Srsmaeda 9691d4b38e0Srsmaeda static void 9701d4b38e0Srsmaeda dump_cpu_rlist(char **rlist) 9711d4b38e0Srsmaeda { 9721d4b38e0Srsmaeda int idx; 9731d4b38e0Srsmaeda int state; 9741d4b38e0Srsmaeda 9751d4b38e0Srsmaeda static char *rcm_state_str[] = { 9761d4b38e0Srsmaeda "UNKNOWN", "ONLINE", "ONLINING", 9771d4b38e0Srsmaeda "OFFLINE_FAIL", "OFFLINING", "OFFLINE", 9781d4b38e0Srsmaeda "REMOVING", "INVALID_7", "INVALID_8", 9791d4b38e0Srsmaeda "INVALID_9", "RESUMING", "SUSPEND_FAIL", 9801d4b38e0Srsmaeda "SUSPENDING", "SUSPEND", "REMOVE", 9811d4b38e0Srsmaeda "OFFLINE_QUERYING", "OFFLINE_QUERY_FAIL", "OFFLINE_QUERY", 9821d4b38e0Srsmaeda "SUSPEND_QUERYING", "SUSPEND_QUERY_FAIL", "SUSPEND_QUERY" 9831d4b38e0Srsmaeda }; 9841d4b38e0Srsmaeda 9851d4b38e0Srsmaeda /* just return if not debugging */ 9861d4b38e0Srsmaeda if (drd_debug == 0) 9871d4b38e0Srsmaeda return; 9881d4b38e0Srsmaeda 9891d4b38e0Srsmaeda if (rlist == NULL) { 9901d4b38e0Srsmaeda drd_dbg(" empty rlist"); 9911d4b38e0Srsmaeda return; 9921d4b38e0Srsmaeda } 9931d4b38e0Srsmaeda 9941d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) { 9951d4b38e0Srsmaeda state = 0; 9961d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state); 9971d4b38e0Srsmaeda drd_dbg(" rlist[%d]: rsrc=%s, state=%-2d (%s)", idx, 9981d4b38e0Srsmaeda rlist[idx], state, rcm_state_str[state]); 9991d4b38e0Srsmaeda } 10001d4b38e0Srsmaeda } 1001*8fea755aSjm22469 1002*8fea755aSjm22469 static int 1003*8fea755aSjm22469 drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc) 1004*8fea755aSjm22469 { 1005*8fea755aSjm22469 drd_dbg("drd_rcm_io_config_request..."); 1006*8fea755aSjm22469 1007*8fea755aSjm22469 if (nrsrc != 1) { 1008*8fea755aSjm22469 drd_dbg("drd_rcm_cpu_config_request: only 1 resource " 1009*8fea755aSjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc); 1010*8fea755aSjm22469 rsrc->status = DRCTL_STATUS_DENY; 1011*8fea755aSjm22469 1012*8fea755aSjm22469 return (-1); 1013*8fea755aSjm22469 } 1014*8fea755aSjm22469 1015*8fea755aSjm22469 /* 1016*8fea755aSjm22469 * There is no RCM operation to request the addition 1017*8fea755aSjm22469 * of resources. So, by definition, the operation for 1018*8fea755aSjm22469 * the current resource is allowed. 1019*8fea755aSjm22469 */ 1020*8fea755aSjm22469 rsrc->status = DRCTL_STATUS_ALLOW; 1021*8fea755aSjm22469 1022*8fea755aSjm22469 return (0); 1023*8fea755aSjm22469 } 1024*8fea755aSjm22469 1025*8fea755aSjm22469 /*ARGSUSED*/ 1026*8fea755aSjm22469 static int 1027*8fea755aSjm22469 drd_rcm_io_config_notify(drctl_rsrc_t *rsrcs, int nrsrc) 1028*8fea755aSjm22469 { 1029*8fea755aSjm22469 drd_dbg("drd_rcm_io_config_notify..."); 1030*8fea755aSjm22469 1031*8fea755aSjm22469 if (nrsrc != 1) { 1032*8fea755aSjm22469 drd_dbg("drd_rcm_cpu_config_notify: only 1 resource " 1033*8fea755aSjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc); 1034*8fea755aSjm22469 1035*8fea755aSjm22469 return (-1); 1036*8fea755aSjm22469 } 1037*8fea755aSjm22469 1038*8fea755aSjm22469 return (0); 1039*8fea755aSjm22469 } 1040*8fea755aSjm22469 1041*8fea755aSjm22469 1042*8fea755aSjm22469 static int 1043*8fea755aSjm22469 drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc) 1044*8fea755aSjm22469 { 1045*8fea755aSjm22469 int rv; 1046*8fea755aSjm22469 char *dev = rsrc->res_dev_path; 1047*8fea755aSjm22469 rcm_info_t *rinfo = NULL; 1048*8fea755aSjm22469 1049*8fea755aSjm22469 if (nrsrc != 1) { 1050*8fea755aSjm22469 drd_dbg("drd_io_unconfig_request: only 1 resource " 1051*8fea755aSjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc); 1052*8fea755aSjm22469 rsrc->status = DRCTL_STATUS_DENY; 1053*8fea755aSjm22469 1054*8fea755aSjm22469 return (-1); 1055*8fea755aSjm22469 } 1056*8fea755aSjm22469 1057*8fea755aSjm22469 if ((rv = rcm_request_offline(rcm_hdl, dev, 0, &rinfo)) == RCM_SUCCESS) 1058*8fea755aSjm22469 rsrc->status = DRCTL_STATUS_ALLOW; 1059*8fea755aSjm22469 else { 1060*8fea755aSjm22469 rcm_notify_online(rcm_hdl, dev, 0, NULL); 1061*8fea755aSjm22469 rsrc->status = DRCTL_STATUS_DENY; 1062*8fea755aSjm22469 rsrc->offset = (uintptr_t)rcm_info_table(rinfo); 1063*8fea755aSjm22469 1064*8fea755aSjm22469 } 1065*8fea755aSjm22469 1066*8fea755aSjm22469 rcm_free_info(rinfo); 1067*8fea755aSjm22469 drd_dbg("drd_rcm_io_unconfig_request(%s) = %d", dev, rv); 1068*8fea755aSjm22469 1069*8fea755aSjm22469 return (rv); 1070*8fea755aSjm22469 } 1071*8fea755aSjm22469 1072*8fea755aSjm22469 static int 1073*8fea755aSjm22469 drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc) 1074*8fea755aSjm22469 { 1075*8fea755aSjm22469 drd_dbg("drd_rcm_io_unconfig_notify..."); 1076*8fea755aSjm22469 1077*8fea755aSjm22469 if (nrsrc != 1) { 1078*8fea755aSjm22469 drd_dbg("drd_io_cpu_unconfig_notify: only 1 resource " 1079*8fea755aSjm22469 "allowed for I/O requests, passed %d resources\n", nrsrc); 1080*8fea755aSjm22469 1081*8fea755aSjm22469 return (-1); 1082*8fea755aSjm22469 } 1083*8fea755aSjm22469 1084*8fea755aSjm22469 return (rcm_notify_remove(rcm_hdl, rsrc->res_dev_path, 0, NULL)); 1085*8fea755aSjm22469 } 1086*8fea755aSjm22469 1087*8fea755aSjm22469 #define MAX_FORMAT 80 1088*8fea755aSjm22469 1089*8fea755aSjm22469 /* 1090*8fea755aSjm22469 * Convert rcm_info_t data into a printable table. 1091*8fea755aSjm22469 */ 1092*8fea755aSjm22469 static char * 1093*8fea755aSjm22469 rcm_info_table(rcm_info_t *rinfo) 1094*8fea755aSjm22469 { 1095*8fea755aSjm22469 int i; 1096*8fea755aSjm22469 size_t w; 1097*8fea755aSjm22469 size_t width = 0; 1098*8fea755aSjm22469 size_t w_rsrc = 0; 1099*8fea755aSjm22469 size_t w_info = 0; 1100*8fea755aSjm22469 size_t table_size = 0; 1101*8fea755aSjm22469 uint_t tuples = 0; 1102*8fea755aSjm22469 rcm_info_tuple_t *tuple = NULL; 1103*8fea755aSjm22469 char *rsrc; 1104*8fea755aSjm22469 char *info; 1105*8fea755aSjm22469 char *table; 1106*8fea755aSjm22469 static char format[MAX_FORMAT]; 1107*8fea755aSjm22469 const char *infostr; 1108*8fea755aSjm22469 1109*8fea755aSjm22469 /* Protect against invalid arguments */ 1110*8fea755aSjm22469 if (rinfo == NULL) 1111*8fea755aSjm22469 return (NULL); 1112*8fea755aSjm22469 1113*8fea755aSjm22469 /* Set localized table header strings */ 1114*8fea755aSjm22469 rsrc = dgettext(TEXT_DOMAIN, "Resource"); 1115*8fea755aSjm22469 info = dgettext(TEXT_DOMAIN, "Information"); 1116*8fea755aSjm22469 1117*8fea755aSjm22469 /* A first pass, to size up the RCM information */ 1118*8fea755aSjm22469 while (tuple = rcm_info_next(rinfo, tuple)) { 1119*8fea755aSjm22469 if ((infostr = rcm_info_info(tuple)) != NULL) { 1120*8fea755aSjm22469 tuples++; 1121*8fea755aSjm22469 if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc) 1122*8fea755aSjm22469 w_rsrc = w; 1123*8fea755aSjm22469 if ((w = strlen(infostr)) > w_info) 1124*8fea755aSjm22469 w_info = w; 1125*8fea755aSjm22469 } 1126*8fea755aSjm22469 } 1127*8fea755aSjm22469 1128*8fea755aSjm22469 /* If nothing was sized up above, stop early */ 1129*8fea755aSjm22469 if (tuples == 0) 1130*8fea755aSjm22469 return (NULL); 1131*8fea755aSjm22469 1132*8fea755aSjm22469 /* Adjust column widths for column headings */ 1133*8fea755aSjm22469 if ((w = strlen(rsrc)) > w_rsrc) 1134*8fea755aSjm22469 w_rsrc = w; 1135*8fea755aSjm22469 else if ((w_rsrc - w) % 2) 1136*8fea755aSjm22469 w_rsrc++; 1137*8fea755aSjm22469 if ((w = strlen(info)) > w_info) 1138*8fea755aSjm22469 w_info = w; 1139*8fea755aSjm22469 else if ((w_info - w) % 2) 1140*8fea755aSjm22469 w_info++; 1141*8fea755aSjm22469 1142*8fea755aSjm22469 /* 1143*8fea755aSjm22469 * Compute the total line width of each line, 1144*8fea755aSjm22469 * accounting for intercolumn spacing. 1145*8fea755aSjm22469 */ 1146*8fea755aSjm22469 width = w_info + w_rsrc + 4; 1147*8fea755aSjm22469 1148*8fea755aSjm22469 /* Allocate space for the table */ 1149*8fea755aSjm22469 table_size = (2 + tuples) * (width + 1) + 2; 1150*8fea755aSjm22469 1151*8fea755aSjm22469 /* zero fill for the strcat() call below */ 1152*8fea755aSjm22469 table = calloc(table_size, sizeof (char)); 1153*8fea755aSjm22469 if (table == NULL) 1154*8fea755aSjm22469 return (NULL); 1155*8fea755aSjm22469 1156*8fea755aSjm22469 /* Place a table header into the string */ 1157*8fea755aSjm22469 1158*8fea755aSjm22469 /* The resource header */ 1159*8fea755aSjm22469 (void) strcat(table, "\n"); 1160*8fea755aSjm22469 w = strlen(rsrc); 1161*8fea755aSjm22469 for (i = 0; i < ((w_rsrc - w) / 2); i++) 1162*8fea755aSjm22469 (void) strcat(table, " "); 1163*8fea755aSjm22469 (void) strcat(table, rsrc); 1164*8fea755aSjm22469 for (i = 0; i < ((w_rsrc - w) / 2); i++) 1165*8fea755aSjm22469 (void) strcat(table, " "); 1166*8fea755aSjm22469 1167*8fea755aSjm22469 /* The information header */ 1168*8fea755aSjm22469 (void) strcat(table, " "); 1169*8fea755aSjm22469 w = strlen(info); 1170*8fea755aSjm22469 for (i = 0; i < ((w_info - w) / 2); i++) 1171*8fea755aSjm22469 (void) strcat(table, " "); 1172*8fea755aSjm22469 (void) strcat(table, info); 1173*8fea755aSjm22469 for (i = 0; i < ((w_info - w) / 2); i++) 1174*8fea755aSjm22469 (void) strcat(table, " "); 1175*8fea755aSjm22469 /* Underline the headers */ 1176*8fea755aSjm22469 (void) strcat(table, "\n"); 1177*8fea755aSjm22469 for (i = 0; i < w_rsrc; i++) 1178*8fea755aSjm22469 (void) strcat(table, "-"); 1179*8fea755aSjm22469 (void) strcat(table, " "); 1180*8fea755aSjm22469 for (i = 0; i < w_info; i++) 1181*8fea755aSjm22469 (void) strcat(table, "-"); 1182*8fea755aSjm22469 1183*8fea755aSjm22469 /* Construct the format string */ 1184*8fea755aSjm22469 (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds", 1185*8fea755aSjm22469 (int)w_rsrc, (int)w_info); 1186*8fea755aSjm22469 1187*8fea755aSjm22469 /* Add the tuples to the table string */ 1188*8fea755aSjm22469 tuple = NULL; 1189*8fea755aSjm22469 while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { 1190*8fea755aSjm22469 if ((infostr = rcm_info_info(tuple)) != NULL) { 1191*8fea755aSjm22469 (void) strcat(table, "\n"); 1192*8fea755aSjm22469 (void) sprintf(&((table)[strlen(table)]), 1193*8fea755aSjm22469 format, rcm_info_rsrc(tuple), 1194*8fea755aSjm22469 infostr); 1195*8fea755aSjm22469 } 1196*8fea755aSjm22469 } 1197*8fea755aSjm22469 drd_dbg("rcm_info_table: %s\n", table); 1198*8fea755aSjm22469 1199*8fea755aSjm22469 return (table); 1200*8fea755aSjm22469 } 1201