1*1d4b38e0Srsmaeda /* 2*1d4b38e0Srsmaeda * CDDL HEADER START 3*1d4b38e0Srsmaeda * 4*1d4b38e0Srsmaeda * The contents of this file are subject to the terms of the 5*1d4b38e0Srsmaeda * Common Development and Distribution License (the "License"). 6*1d4b38e0Srsmaeda * You may not use this file except in compliance with the License. 7*1d4b38e0Srsmaeda * 8*1d4b38e0Srsmaeda * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1d4b38e0Srsmaeda * or http://www.opensolaris.org/os/licensing. 10*1d4b38e0Srsmaeda * See the License for the specific language governing permissions 11*1d4b38e0Srsmaeda * and limitations under the License. 12*1d4b38e0Srsmaeda * 13*1d4b38e0Srsmaeda * When distributing Covered Code, include this CDDL HEADER in each 14*1d4b38e0Srsmaeda * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1d4b38e0Srsmaeda * If applicable, add the following below this CDDL HEADER, with the 16*1d4b38e0Srsmaeda * fields enclosed by brackets "[]" replaced with your own identifying 17*1d4b38e0Srsmaeda * information: Portions Copyright [yyyy] [name of copyright owner] 18*1d4b38e0Srsmaeda * 19*1d4b38e0Srsmaeda * CDDL HEADER END 20*1d4b38e0Srsmaeda */ 21*1d4b38e0Srsmaeda 22*1d4b38e0Srsmaeda /* 23*1d4b38e0Srsmaeda * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1d4b38e0Srsmaeda * Use is subject to license terms. 25*1d4b38e0Srsmaeda */ 26*1d4b38e0Srsmaeda 27*1d4b38e0Srsmaeda #pragma ident "%Z%%M% %I% %E% SMI" 28*1d4b38e0Srsmaeda 29*1d4b38e0Srsmaeda /* 30*1d4b38e0Srsmaeda * RCM backend for the DR Daemon 31*1d4b38e0Srsmaeda */ 32*1d4b38e0Srsmaeda 33*1d4b38e0Srsmaeda #include <unistd.h> 34*1d4b38e0Srsmaeda #include <strings.h> 35*1d4b38e0Srsmaeda #include <errno.h> 36*1d4b38e0Srsmaeda #include <kstat.h> 37*1d4b38e0Srsmaeda #include <libnvpair.h> 38*1d4b38e0Srsmaeda #include <librcm.h> 39*1d4b38e0Srsmaeda 40*1d4b38e0Srsmaeda #include "drd.h" 41*1d4b38e0Srsmaeda 42*1d4b38e0Srsmaeda /* 43*1d4b38e0Srsmaeda * RCM Backend Support 44*1d4b38e0Srsmaeda */ 45*1d4b38e0Srsmaeda static int drd_rcm_init(void); 46*1d4b38e0Srsmaeda static int drd_rcm_fini(void); 47*1d4b38e0Srsmaeda static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc); 48*1d4b38e0Srsmaeda static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc); 49*1d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc); 50*1d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc); 51*1d4b38e0Srsmaeda 52*1d4b38e0Srsmaeda drd_backend_t drd_rcm_backend = { 53*1d4b38e0Srsmaeda drd_rcm_init, /* init */ 54*1d4b38e0Srsmaeda drd_rcm_fini, /* fini */ 55*1d4b38e0Srsmaeda drd_rcm_cpu_config_request, /* cpu_config_request */ 56*1d4b38e0Srsmaeda drd_rcm_cpu_config_notify, /* cpu_config_notify */ 57*1d4b38e0Srsmaeda drd_rcm_cpu_unconfig_request, /* cpu_unconfig_request */ 58*1d4b38e0Srsmaeda drd_rcm_cpu_unconfig_notify /* cpu_unconfig_notify */ 59*1d4b38e0Srsmaeda }; 60*1d4b38e0Srsmaeda 61*1d4b38e0Srsmaeda #define RCM_CPU_ALL "SUNW_cpu" 62*1d4b38e0Srsmaeda #define RCM_CPU RCM_CPU_ALL"/cpu" 63*1d4b38e0Srsmaeda #define RCM_CPU_MAX_LEN (32) 64*1d4b38e0Srsmaeda 65*1d4b38e0Srsmaeda /* global RCM handle used in all RCM operations */ 66*1d4b38e0Srsmaeda static rcm_handle_t *rcm_hdl; 67*1d4b38e0Srsmaeda 68*1d4b38e0Srsmaeda /* functions that call into RCM */ 69*1d4b38e0Srsmaeda static int drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 70*1d4b38e0Srsmaeda static int drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 71*1d4b38e0Srsmaeda static int drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc); 72*1d4b38e0Srsmaeda static int drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc); 73*1d4b38e0Srsmaeda static int drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 74*1d4b38e0Srsmaeda static int drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 75*1d4b38e0Srsmaeda static int drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 76*1d4b38e0Srsmaeda 77*1d4b38e0Srsmaeda /* utility functions */ 78*1d4b38e0Srsmaeda static char **drd_rcm_cpu_rlist_init(drctl_rsrc_t *, int nrsrc, int status); 79*1d4b38e0Srsmaeda static void drd_rcm_cpu_rlist_fini(char **rlist); 80*1d4b38e0Srsmaeda static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int); 81*1d4b38e0Srsmaeda static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids); 82*1d4b38e0Srsmaeda static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len); 83*1d4b38e0Srsmaeda 84*1d4b38e0Srsmaeda /* debugging utility functions */ 85*1d4b38e0Srsmaeda static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids); 86*1d4b38e0Srsmaeda static void dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *, int nrsrc); 87*1d4b38e0Srsmaeda static void dump_cpu_rlist(char **rlist); 88*1d4b38e0Srsmaeda 89*1d4b38e0Srsmaeda static int 90*1d4b38e0Srsmaeda drd_rcm_init(void) 91*1d4b38e0Srsmaeda { 92*1d4b38e0Srsmaeda int rv; 93*1d4b38e0Srsmaeda 94*1d4b38e0Srsmaeda drd_dbg("drd_rcm_init..."); 95*1d4b38e0Srsmaeda 96*1d4b38e0Srsmaeda rv = rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl); 97*1d4b38e0Srsmaeda if (rv == RCM_FAILURE) { 98*1d4b38e0Srsmaeda drd_err("unable to allocate RCM handle: %s", strerror(errno)); 99*1d4b38e0Srsmaeda return (-1); 100*1d4b38e0Srsmaeda } 101*1d4b38e0Srsmaeda 102*1d4b38e0Srsmaeda return (0); 103*1d4b38e0Srsmaeda } 104*1d4b38e0Srsmaeda 105*1d4b38e0Srsmaeda static int 106*1d4b38e0Srsmaeda drd_rcm_fini(void) 107*1d4b38e0Srsmaeda { 108*1d4b38e0Srsmaeda drd_dbg("drd_rcm_fini..."); 109*1d4b38e0Srsmaeda 110*1d4b38e0Srsmaeda if (rcm_hdl != NULL) 111*1d4b38e0Srsmaeda rcm_free_handle(rcm_hdl); 112*1d4b38e0Srsmaeda 113*1d4b38e0Srsmaeda return (0); 114*1d4b38e0Srsmaeda } 115*1d4b38e0Srsmaeda 116*1d4b38e0Srsmaeda static int 117*1d4b38e0Srsmaeda drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc) 118*1d4b38e0Srsmaeda { 119*1d4b38e0Srsmaeda int idx; 120*1d4b38e0Srsmaeda 121*1d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_config_request..."); 122*1d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 123*1d4b38e0Srsmaeda 124*1d4b38e0Srsmaeda /* 125*1d4b38e0Srsmaeda * There is no RCM operation to request the addition 126*1d4b38e0Srsmaeda * of resources. So, by definition, the operation for 127*1d4b38e0Srsmaeda * all the CPUs is allowed. 128*1d4b38e0Srsmaeda */ 129*1d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) 130*1d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_ALLOW; 131*1d4b38e0Srsmaeda 132*1d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 133*1d4b38e0Srsmaeda 134*1d4b38e0Srsmaeda return (0); 135*1d4b38e0Srsmaeda } 136*1d4b38e0Srsmaeda 137*1d4b38e0Srsmaeda static int 138*1d4b38e0Srsmaeda drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc) 139*1d4b38e0Srsmaeda { 140*1d4b38e0Srsmaeda int rv = 0; 141*1d4b38e0Srsmaeda 142*1d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_config_notify..."); 143*1d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 144*1d4b38e0Srsmaeda 145*1d4b38e0Srsmaeda /* notify RCM about the newly added CPUs */ 146*1d4b38e0Srsmaeda if (drd_rcm_online_cpu_notify(rsrcs, nrsrc) != 0) { 147*1d4b38e0Srsmaeda rv = -1; 148*1d4b38e0Srsmaeda goto done; 149*1d4b38e0Srsmaeda } 150*1d4b38e0Srsmaeda 151*1d4b38e0Srsmaeda /* notify RCM about the increased CPU capacity */ 152*1d4b38e0Srsmaeda if (drd_rcm_add_cpu_notify(rsrcs, nrsrc) != 0) { 153*1d4b38e0Srsmaeda rv = -1; 154*1d4b38e0Srsmaeda } 155*1d4b38e0Srsmaeda 156*1d4b38e0Srsmaeda done: 157*1d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 158*1d4b38e0Srsmaeda 159*1d4b38e0Srsmaeda return (rv); 160*1d4b38e0Srsmaeda } 161*1d4b38e0Srsmaeda 162*1d4b38e0Srsmaeda static int 163*1d4b38e0Srsmaeda drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc) 164*1d4b38e0Srsmaeda { 165*1d4b38e0Srsmaeda int rv = 0; 166*1d4b38e0Srsmaeda int idx; 167*1d4b38e0Srsmaeda 168*1d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_unconfig_request..."); 169*1d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 170*1d4b38e0Srsmaeda 171*1d4b38e0Srsmaeda /* contact RCM to request a decrease in CPU capacity */ 172*1d4b38e0Srsmaeda if (drd_rcm_del_cpu_request(rsrcs, nrsrc) != 0) { 173*1d4b38e0Srsmaeda rv = -1; 174*1d4b38e0Srsmaeda goto done; 175*1d4b38e0Srsmaeda } 176*1d4b38e0Srsmaeda 177*1d4b38e0Srsmaeda /* contact RCM to request the removal of CPUs */ 178*1d4b38e0Srsmaeda if (drd_rcm_offline_cpu_request(rsrcs, nrsrc) != 0) { 179*1d4b38e0Srsmaeda rv = -1; 180*1d4b38e0Srsmaeda goto done; 181*1d4b38e0Srsmaeda } 182*1d4b38e0Srsmaeda 183*1d4b38e0Srsmaeda done: 184*1d4b38e0Srsmaeda /* 185*1d4b38e0Srsmaeda * If any errors occurred, the status field for 186*1d4b38e0Srsmaeda * a CPU may still be in the INIT state. Set the 187*1d4b38e0Srsmaeda * status for any such CPU to DENY to ensure it 188*1d4b38e0Srsmaeda * gets processed properly. 189*1d4b38e0Srsmaeda */ 190*1d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 191*1d4b38e0Srsmaeda if (rsrcs[idx].status == DRCTL_STATUS_INIT) 192*1d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_DENY; 193*1d4b38e0Srsmaeda } 194*1d4b38e0Srsmaeda 195*1d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 196*1d4b38e0Srsmaeda 197*1d4b38e0Srsmaeda return (rv); 198*1d4b38e0Srsmaeda } 199*1d4b38e0Srsmaeda 200*1d4b38e0Srsmaeda static int 201*1d4b38e0Srsmaeda drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc) 202*1d4b38e0Srsmaeda { 203*1d4b38e0Srsmaeda int rv = 0; 204*1d4b38e0Srsmaeda 205*1d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_unconfig_notify..."); 206*1d4b38e0Srsmaeda dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 207*1d4b38e0Srsmaeda 208*1d4b38e0Srsmaeda /* 209*1d4b38e0Srsmaeda * Notify RCM about the CPUs that were removed. 210*1d4b38e0Srsmaeda * Failures are ignored so that CPUs that could 211*1d4b38e0Srsmaeda * not be unconfigured can be processed by RCM. 212*1d4b38e0Srsmaeda */ 213*1d4b38e0Srsmaeda (void) drd_rcm_remove_cpu_notify(rsrcs, nrsrc); 214*1d4b38e0Srsmaeda 215*1d4b38e0Srsmaeda /* 216*1d4b38e0Srsmaeda * Notify RCM about any CPUs that did not make it 217*1d4b38e0Srsmaeda * in to the unconfigured state. 218*1d4b38e0Srsmaeda */ 219*1d4b38e0Srsmaeda if (drd_rcm_restore_cpu_notify(rsrcs, nrsrc) != 0) { 220*1d4b38e0Srsmaeda rv = -1; 221*1d4b38e0Srsmaeda goto done; 222*1d4b38e0Srsmaeda } 223*1d4b38e0Srsmaeda 224*1d4b38e0Srsmaeda /* notify RCM about the decreased CPU capacity */ 225*1d4b38e0Srsmaeda if (drd_rcm_del_cpu_notify(rsrcs, nrsrc) != 0) { 226*1d4b38e0Srsmaeda rv = -1; 227*1d4b38e0Srsmaeda } 228*1d4b38e0Srsmaeda 229*1d4b38e0Srsmaeda done: 230*1d4b38e0Srsmaeda dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 231*1d4b38e0Srsmaeda 232*1d4b38e0Srsmaeda return (rv); 233*1d4b38e0Srsmaeda } 234*1d4b38e0Srsmaeda 235*1d4b38e0Srsmaeda static int 236*1d4b38e0Srsmaeda drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 237*1d4b38e0Srsmaeda { 238*1d4b38e0Srsmaeda char **rlist; 239*1d4b38e0Srsmaeda int rv = 0; 240*1d4b38e0Srsmaeda rcm_info_t *rinfo; 241*1d4b38e0Srsmaeda 242*1d4b38e0Srsmaeda drd_dbg("drd_rcm_online_cpu_notify..."); 243*1d4b38e0Srsmaeda 244*1d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 245*1d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) { 246*1d4b38e0Srsmaeda drd_dbg(" no CPUs were successfully added, nothing to do"); 247*1d4b38e0Srsmaeda return (0); 248*1d4b38e0Srsmaeda } 249*1d4b38e0Srsmaeda 250*1d4b38e0Srsmaeda rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo); 251*1d4b38e0Srsmaeda if (rv != RCM_SUCCESS) { 252*1d4b38e0Srsmaeda drd_info("rcm_notify_online_list failed: %d", rv); 253*1d4b38e0Srsmaeda rcm_free_info(rinfo); 254*1d4b38e0Srsmaeda rv = -1; 255*1d4b38e0Srsmaeda } 256*1d4b38e0Srsmaeda 257*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist); 258*1d4b38e0Srsmaeda 259*1d4b38e0Srsmaeda return (rv); 260*1d4b38e0Srsmaeda } 261*1d4b38e0Srsmaeda 262*1d4b38e0Srsmaeda static int 263*1d4b38e0Srsmaeda drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 264*1d4b38e0Srsmaeda { 265*1d4b38e0Srsmaeda cpuid_t *cpus = NULL; 266*1d4b38e0Srsmaeda int ncpus; 267*1d4b38e0Srsmaeda int rv = -1; 268*1d4b38e0Srsmaeda cpuid_t *oldcpus = NULL; 269*1d4b38e0Srsmaeda cpuid_t *newcpus = NULL; 270*1d4b38e0Srsmaeda int oldncpus = 0; 271*1d4b38e0Srsmaeda int newncpus = 0; 272*1d4b38e0Srsmaeda nvlist_t *nvl = NULL; 273*1d4b38e0Srsmaeda int idx; 274*1d4b38e0Srsmaeda rcm_info_t *rinfo; 275*1d4b38e0Srsmaeda 276*1d4b38e0Srsmaeda drd_dbg("drd_rcm_add_cpu_notify..."); 277*1d4b38e0Srsmaeda 278*1d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) { 279*1d4b38e0Srsmaeda drd_err("add_cpu_notify: cpu list empty"); 280*1d4b38e0Srsmaeda goto done; 281*1d4b38e0Srsmaeda } 282*1d4b38e0Srsmaeda 283*1d4b38e0Srsmaeda ncpus = nrsrc; 284*1d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 285*1d4b38e0Srsmaeda 286*1d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 287*1d4b38e0Srsmaeda drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id); 288*1d4b38e0Srsmaeda cpus[idx] = rsrcs[idx].res_cpu_id; 289*1d4b38e0Srsmaeda } 290*1d4b38e0Srsmaeda 291*1d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */ 292*1d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 293*1d4b38e0Srsmaeda goto done; 294*1d4b38e0Srsmaeda 295*1d4b38e0Srsmaeda /* 296*1d4b38e0Srsmaeda * Added CPU capacity, so newcpus is the current list 297*1d4b38e0Srsmaeda * of CPUs in the system. 298*1d4b38e0Srsmaeda */ 299*1d4b38e0Srsmaeda if (get_sys_cpuids(&newcpus, &newncpus) == -1) 300*1d4b38e0Srsmaeda goto done; 301*1d4b38e0Srsmaeda 302*1d4b38e0Srsmaeda /* 303*1d4b38e0Srsmaeda * Since the operation added CPU capacity, the old CPU 304*1d4b38e0Srsmaeda * list is the new CPU list with the CPUs involved in 305*1d4b38e0Srsmaeda * the operation removed. 306*1d4b38e0Srsmaeda */ 307*1d4b38e0Srsmaeda oldcpus = (cpuid_t *)calloc(newncpus, sizeof (cpuid_t)); 308*1d4b38e0Srsmaeda if (oldcpus == NULL) 309*1d4b38e0Srsmaeda goto done; 310*1d4b38e0Srsmaeda 311*1d4b38e0Srsmaeda for (idx = 0; idx < newncpus; idx++) { 312*1d4b38e0Srsmaeda if (!is_cpu_in_list(newcpus[idx], cpus, ncpus)) 313*1d4b38e0Srsmaeda oldcpus[oldncpus++] = newcpus[idx]; 314*1d4b38e0Srsmaeda } 315*1d4b38e0Srsmaeda 316*1d4b38e0Srsmaeda /* dump pre and post lists */ 317*1d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 318*1d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus); 319*1d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, ncpus); 320*1d4b38e0Srsmaeda 321*1d4b38e0Srsmaeda /* setup the nvlist for the RCM call */ 322*1d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") || 323*1d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) || 324*1d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) || 325*1d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 326*1d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 327*1d4b38e0Srsmaeda goto done; 328*1d4b38e0Srsmaeda } 329*1d4b38e0Srsmaeda 330*1d4b38e0Srsmaeda rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 331*1d4b38e0Srsmaeda rv = (rv == RCM_SUCCESS) ? 0 : -1; 332*1d4b38e0Srsmaeda 333*1d4b38e0Srsmaeda done: 334*1d4b38e0Srsmaeda s_nvfree(nvl); 335*1d4b38e0Srsmaeda s_free(cpus); 336*1d4b38e0Srsmaeda s_free(oldcpus); 337*1d4b38e0Srsmaeda s_free(newcpus); 338*1d4b38e0Srsmaeda 339*1d4b38e0Srsmaeda return (rv); 340*1d4b38e0Srsmaeda } 341*1d4b38e0Srsmaeda 342*1d4b38e0Srsmaeda static int 343*1d4b38e0Srsmaeda drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc) 344*1d4b38e0Srsmaeda { 345*1d4b38e0Srsmaeda cpuid_t *cpus = NULL; 346*1d4b38e0Srsmaeda int ncpus; 347*1d4b38e0Srsmaeda int rv = -1; 348*1d4b38e0Srsmaeda cpuid_t *oldcpus = NULL; 349*1d4b38e0Srsmaeda cpuid_t *newcpus = NULL; 350*1d4b38e0Srsmaeda int oldncpus = 0; 351*1d4b38e0Srsmaeda int newncpus = 0; 352*1d4b38e0Srsmaeda nvlist_t *nvl = NULL; 353*1d4b38e0Srsmaeda int idx; 354*1d4b38e0Srsmaeda rcm_info_t *rinfo; 355*1d4b38e0Srsmaeda 356*1d4b38e0Srsmaeda drd_dbg("drd_rcm_del_cpu_request..."); 357*1d4b38e0Srsmaeda 358*1d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) { 359*1d4b38e0Srsmaeda drd_err("del_cpu_request: cpu list empty"); 360*1d4b38e0Srsmaeda goto done; 361*1d4b38e0Srsmaeda } 362*1d4b38e0Srsmaeda 363*1d4b38e0Srsmaeda ncpus = nrsrc; 364*1d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 365*1d4b38e0Srsmaeda 366*1d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 367*1d4b38e0Srsmaeda cpus[idx] = rsrcs[idx].res_cpu_id; 368*1d4b38e0Srsmaeda } 369*1d4b38e0Srsmaeda 370*1d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */ 371*1d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 372*1d4b38e0Srsmaeda goto done; 373*1d4b38e0Srsmaeda } 374*1d4b38e0Srsmaeda 375*1d4b38e0Srsmaeda /* 376*1d4b38e0Srsmaeda * Removing CPU capacity, so oldcpus is the current 377*1d4b38e0Srsmaeda * list of CPUs in the system. 378*1d4b38e0Srsmaeda */ 379*1d4b38e0Srsmaeda if (get_sys_cpuids(&oldcpus, &oldncpus) == -1) { 380*1d4b38e0Srsmaeda goto done; 381*1d4b38e0Srsmaeda } 382*1d4b38e0Srsmaeda 383*1d4b38e0Srsmaeda /* 384*1d4b38e0Srsmaeda * Since this is a request to remove CPU capacity, 385*1d4b38e0Srsmaeda * the new CPU list is the old CPU list with the CPUs 386*1d4b38e0Srsmaeda * involved in the operation removed. 387*1d4b38e0Srsmaeda */ 388*1d4b38e0Srsmaeda newcpus = (cpuid_t *)calloc(oldncpus, sizeof (cpuid_t)); 389*1d4b38e0Srsmaeda if (newcpus == NULL) { 390*1d4b38e0Srsmaeda goto done; 391*1d4b38e0Srsmaeda } 392*1d4b38e0Srsmaeda 393*1d4b38e0Srsmaeda for (idx = 0; idx < oldncpus; idx++) { 394*1d4b38e0Srsmaeda if (!is_cpu_in_list(oldcpus[idx], cpus, ncpus)) 395*1d4b38e0Srsmaeda newcpus[newncpus++] = oldcpus[idx]; 396*1d4b38e0Srsmaeda } 397*1d4b38e0Srsmaeda 398*1d4b38e0Srsmaeda /* dump pre and post lists */ 399*1d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 400*1d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus); 401*1d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, ncpus); 402*1d4b38e0Srsmaeda 403*1d4b38e0Srsmaeda /* setup the nvlist for the RCM call */ 404*1d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") || 405*1d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) || 406*1d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) || 407*1d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 408*1d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 409*1d4b38e0Srsmaeda goto done; 410*1d4b38e0Srsmaeda } 411*1d4b38e0Srsmaeda 412*1d4b38e0Srsmaeda rv = rcm_request_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 413*1d4b38e0Srsmaeda if (rv != RCM_SUCCESS) { 414*1d4b38e0Srsmaeda drd_dbg("RCM call failed: %d", rv); 415*1d4b38e0Srsmaeda /* 416*1d4b38e0Srsmaeda * Since the capcity change was blocked, we 417*1d4b38e0Srsmaeda * mark all CPUs as blocked. It is up to the 418*1d4b38e0Srsmaeda * user to reframe the query so that it can 419*1d4b38e0Srsmaeda * succeed. 420*1d4b38e0Srsmaeda */ 421*1d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 422*1d4b38e0Srsmaeda rsrcs[idx].status = DRCTL_STATUS_DENY; 423*1d4b38e0Srsmaeda } 424*1d4b38e0Srsmaeda 425*1d4b38e0Srsmaeda /* tack on message to first resource */ 426*1d4b38e0Srsmaeda rsrcs[0].offset = (uintptr_t)strdup("unable to remove " 427*1d4b38e0Srsmaeda "specified number of CPUs"); 428*1d4b38e0Srsmaeda drd_dbg(" unable to remove specified number of CPUs"); 429*1d4b38e0Srsmaeda goto done; 430*1d4b38e0Srsmaeda } 431*1d4b38e0Srsmaeda 432*1d4b38e0Srsmaeda rv = 0; 433*1d4b38e0Srsmaeda 434*1d4b38e0Srsmaeda done: 435*1d4b38e0Srsmaeda s_nvfree(nvl); 436*1d4b38e0Srsmaeda s_free(cpus); 437*1d4b38e0Srsmaeda s_free(oldcpus); 438*1d4b38e0Srsmaeda s_free(newcpus); 439*1d4b38e0Srsmaeda 440*1d4b38e0Srsmaeda return (rv); 441*1d4b38e0Srsmaeda } 442*1d4b38e0Srsmaeda 443*1d4b38e0Srsmaeda static int 444*1d4b38e0Srsmaeda drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc) 445*1d4b38e0Srsmaeda { 446*1d4b38e0Srsmaeda char **rlist; 447*1d4b38e0Srsmaeda drctl_rsrc_t *rsrc; 448*1d4b38e0Srsmaeda int idx; 449*1d4b38e0Srsmaeda int state; 450*1d4b38e0Srsmaeda int rv = 0; 451*1d4b38e0Srsmaeda rcm_info_t *rinfo = NULL; 452*1d4b38e0Srsmaeda rcm_info_tuple_t *tuple = NULL; 453*1d4b38e0Srsmaeda const char *rsrcstr; 454*1d4b38e0Srsmaeda const char *errstr; 455*1d4b38e0Srsmaeda 456*1d4b38e0Srsmaeda drd_dbg("drd_rcm_offline_cpu_request..."); 457*1d4b38e0Srsmaeda 458*1d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 459*1d4b38e0Srsmaeda DRCTL_STATUS_INIT)) == NULL) { 460*1d4b38e0Srsmaeda drd_err("unable to generate resource list"); 461*1d4b38e0Srsmaeda return (-1); 462*1d4b38e0Srsmaeda } 463*1d4b38e0Srsmaeda 464*1d4b38e0Srsmaeda rv = rcm_request_offline_list(rcm_hdl, rlist, 0, &rinfo); 465*1d4b38e0Srsmaeda if (rv == RCM_SUCCESS) { 466*1d4b38e0Srsmaeda drd_dbg("RCM success, rinfo=%p", rinfo); 467*1d4b38e0Srsmaeda goto done; 468*1d4b38e0Srsmaeda } 469*1d4b38e0Srsmaeda 470*1d4b38e0Srsmaeda drd_dbg("RCM call failed (%d):", rv); 471*1d4b38e0Srsmaeda 472*1d4b38e0Srsmaeda /* 473*1d4b38e0Srsmaeda * Loop through the result of the operation and add 474*1d4b38e0Srsmaeda * any error messages to the resource structure. 475*1d4b38e0Srsmaeda */ 476*1d4b38e0Srsmaeda while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { 477*1d4b38e0Srsmaeda 478*1d4b38e0Srsmaeda /* find the resource of interest */ 479*1d4b38e0Srsmaeda rsrcstr = rcm_info_rsrc(tuple); 480*1d4b38e0Srsmaeda rsrc = cpu_rsrcstr_to_rsrc(rsrcstr, rsrcs, nrsrc); 481*1d4b38e0Srsmaeda 482*1d4b38e0Srsmaeda if (rsrc == NULL) { 483*1d4b38e0Srsmaeda drd_dbg("unable to find resource for %s", rsrcstr); 484*1d4b38e0Srsmaeda continue; 485*1d4b38e0Srsmaeda } 486*1d4b38e0Srsmaeda 487*1d4b38e0Srsmaeda errstr = rcm_info_error(tuple); 488*1d4b38e0Srsmaeda 489*1d4b38e0Srsmaeda if (errstr) { 490*1d4b38e0Srsmaeda drd_dbg(" %s: '%s'", rsrcstr, errstr); 491*1d4b38e0Srsmaeda rsrc->offset = (uintptr_t)strdup(errstr); 492*1d4b38e0Srsmaeda } 493*1d4b38e0Srsmaeda } 494*1d4b38e0Srsmaeda 495*1d4b38e0Srsmaeda rcm_free_info(rinfo); 496*1d4b38e0Srsmaeda rv = 0; 497*1d4b38e0Srsmaeda 498*1d4b38e0Srsmaeda done: 499*1d4b38e0Srsmaeda /* 500*1d4b38e0Srsmaeda * Set the state of the resource based on the RCM 501*1d4b38e0Srsmaeda * state. CPUs in the offline state have the ok to 502*1d4b38e0Srsmaeda * proceed. All others have been blocked. 503*1d4b38e0Srsmaeda */ 504*1d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) { 505*1d4b38e0Srsmaeda 506*1d4b38e0Srsmaeda state = 0; 507*1d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state); 508*1d4b38e0Srsmaeda 509*1d4b38e0Srsmaeda /* find the resource of interest */ 510*1d4b38e0Srsmaeda rsrc = cpu_rsrcstr_to_rsrc(rlist[idx], rsrcs, nrsrc); 511*1d4b38e0Srsmaeda 512*1d4b38e0Srsmaeda if (rsrc == NULL) { 513*1d4b38e0Srsmaeda drd_dbg("unable to find resource for %s", rlist[idx]); 514*1d4b38e0Srsmaeda continue; 515*1d4b38e0Srsmaeda } 516*1d4b38e0Srsmaeda 517*1d4b38e0Srsmaeda rsrc->status = ((state == RCM_STATE_OFFLINE) ? 518*1d4b38e0Srsmaeda DRCTL_STATUS_ALLOW : DRCTL_STATUS_DENY); 519*1d4b38e0Srsmaeda } 520*1d4b38e0Srsmaeda 521*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist); 522*1d4b38e0Srsmaeda 523*1d4b38e0Srsmaeda return (rv); 524*1d4b38e0Srsmaeda } 525*1d4b38e0Srsmaeda 526*1d4b38e0Srsmaeda static int 527*1d4b38e0Srsmaeda drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 528*1d4b38e0Srsmaeda { 529*1d4b38e0Srsmaeda char **rlist; 530*1d4b38e0Srsmaeda int rv = 0; 531*1d4b38e0Srsmaeda rcm_info_t *rinfo; 532*1d4b38e0Srsmaeda 533*1d4b38e0Srsmaeda drd_dbg("drd_rcm_remove_cpu_notify..."); 534*1d4b38e0Srsmaeda 535*1d4b38e0Srsmaeda if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 536*1d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) { 537*1d4b38e0Srsmaeda drd_dbg(" no CPUs in the success state, nothing to do"); 538*1d4b38e0Srsmaeda return (0); 539*1d4b38e0Srsmaeda } 540*1d4b38e0Srsmaeda 541*1d4b38e0Srsmaeda rv = rcm_notify_remove_list(rcm_hdl, rlist, 0, &rinfo); 542*1d4b38e0Srsmaeda if (rv != RCM_SUCCESS) { 543*1d4b38e0Srsmaeda drd_info("rcm_notify_remove_list failed: %d", rv); 544*1d4b38e0Srsmaeda rcm_free_info(rinfo); 545*1d4b38e0Srsmaeda rv = -1; 546*1d4b38e0Srsmaeda } 547*1d4b38e0Srsmaeda 548*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist); 549*1d4b38e0Srsmaeda 550*1d4b38e0Srsmaeda return (rv); 551*1d4b38e0Srsmaeda } 552*1d4b38e0Srsmaeda 553*1d4b38e0Srsmaeda static int 554*1d4b38e0Srsmaeda drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 555*1d4b38e0Srsmaeda { 556*1d4b38e0Srsmaeda char **rlist; 557*1d4b38e0Srsmaeda char **full_rlist; 558*1d4b38e0Srsmaeda int idx; 559*1d4b38e0Srsmaeda int ridx; 560*1d4b38e0Srsmaeda int state; 561*1d4b38e0Srsmaeda int rv = 0; 562*1d4b38e0Srsmaeda rcm_info_t *rinfo; 563*1d4b38e0Srsmaeda 564*1d4b38e0Srsmaeda drd_dbg("drd_rcm_restore_cpu_notify..."); 565*1d4b38e0Srsmaeda 566*1d4b38e0Srsmaeda if ((full_rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 567*1d4b38e0Srsmaeda DRCTL_STATUS_CONFIG_FAILURE)) == NULL) { 568*1d4b38e0Srsmaeda drd_dbg(" no CPUs in the failed state, nothing to do"); 569*1d4b38e0Srsmaeda return (0); 570*1d4b38e0Srsmaeda } 571*1d4b38e0Srsmaeda 572*1d4b38e0Srsmaeda /* 573*1d4b38e0Srsmaeda * Since the desired result of this operation is to 574*1d4b38e0Srsmaeda * restore resources to the online state, filter out 575*1d4b38e0Srsmaeda * the resources already in the online state before 576*1d4b38e0Srsmaeda * passing the list to RCM. 577*1d4b38e0Srsmaeda */ 578*1d4b38e0Srsmaeda 579*1d4b38e0Srsmaeda /* allocate a zero filled array to ensure NULL terminated list */ 580*1d4b38e0Srsmaeda rlist = (char **)calloc((nrsrc + 1), sizeof (char *)); 581*1d4b38e0Srsmaeda if (rlist == NULL) { 582*1d4b38e0Srsmaeda drd_err("calloc failed: %s", strerror(errno)); 583*1d4b38e0Srsmaeda rv = -1; 584*1d4b38e0Srsmaeda goto done; 585*1d4b38e0Srsmaeda } 586*1d4b38e0Srsmaeda 587*1d4b38e0Srsmaeda for (idx = 0, ridx = 0; full_rlist[idx] != NULL; idx++) { 588*1d4b38e0Srsmaeda state = 0; 589*1d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, full_rlist[idx], &state); 590*1d4b38e0Srsmaeda if (state != RCM_STATE_ONLINE) { 591*1d4b38e0Srsmaeda rlist[ridx] = full_rlist[idx]; 592*1d4b38e0Srsmaeda ridx++; 593*1d4b38e0Srsmaeda } 594*1d4b38e0Srsmaeda } 595*1d4b38e0Srsmaeda 596*1d4b38e0Srsmaeda /* check if everything got filtered out */ 597*1d4b38e0Srsmaeda if (ridx == 0) { 598*1d4b38e0Srsmaeda drd_dbg(" all CPUs already online, nothing to do"); 599*1d4b38e0Srsmaeda goto done; 600*1d4b38e0Srsmaeda } 601*1d4b38e0Srsmaeda 602*1d4b38e0Srsmaeda rv = rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo); 603*1d4b38e0Srsmaeda if (rv != RCM_SUCCESS) { 604*1d4b38e0Srsmaeda drd_info("rcm_notify_online_list failed: %d", rv); 605*1d4b38e0Srsmaeda rcm_free_info(rinfo); 606*1d4b38e0Srsmaeda rv = -1; 607*1d4b38e0Srsmaeda } 608*1d4b38e0Srsmaeda 609*1d4b38e0Srsmaeda done: 610*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(full_rlist); 611*1d4b38e0Srsmaeda s_free(rlist); 612*1d4b38e0Srsmaeda 613*1d4b38e0Srsmaeda return (rv); 614*1d4b38e0Srsmaeda } 615*1d4b38e0Srsmaeda 616*1d4b38e0Srsmaeda static int 617*1d4b38e0Srsmaeda drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 618*1d4b38e0Srsmaeda { 619*1d4b38e0Srsmaeda cpuid_t *cpus = NULL; 620*1d4b38e0Srsmaeda int rv = -1; 621*1d4b38e0Srsmaeda cpuid_t *oldcpus = NULL; 622*1d4b38e0Srsmaeda cpuid_t *newcpus = NULL; 623*1d4b38e0Srsmaeda int oldncpus = 0; 624*1d4b38e0Srsmaeda int newncpus = 0; 625*1d4b38e0Srsmaeda nvlist_t *nvl = NULL; 626*1d4b38e0Srsmaeda int idx; 627*1d4b38e0Srsmaeda int cidx; 628*1d4b38e0Srsmaeda rcm_info_t *rinfo; 629*1d4b38e0Srsmaeda 630*1d4b38e0Srsmaeda drd_dbg("drd_rcm_del_cpu_notify..."); 631*1d4b38e0Srsmaeda 632*1d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) { 633*1d4b38e0Srsmaeda drd_err("del_cpu_notify: cpu list empty"); 634*1d4b38e0Srsmaeda goto done; 635*1d4b38e0Srsmaeda } 636*1d4b38e0Srsmaeda 637*1d4b38e0Srsmaeda cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 638*1d4b38e0Srsmaeda 639*1d4b38e0Srsmaeda /* 640*1d4b38e0Srsmaeda * Filter out the CPUs that could not be unconfigured. 641*1d4b38e0Srsmaeda */ 642*1d4b38e0Srsmaeda for (idx = 0, cidx = 0; idx < nrsrc; idx++) { 643*1d4b38e0Srsmaeda if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS) 644*1d4b38e0Srsmaeda continue; 645*1d4b38e0Srsmaeda drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id); 646*1d4b38e0Srsmaeda cpus[cidx] = rsrcs[idx].res_cpu_id; 647*1d4b38e0Srsmaeda cidx++; 648*1d4b38e0Srsmaeda } 649*1d4b38e0Srsmaeda 650*1d4b38e0Srsmaeda drd_dbg(" ncpus = %d", cidx); 651*1d4b38e0Srsmaeda 652*1d4b38e0Srsmaeda /* nothing to do */ 653*1d4b38e0Srsmaeda if (cidx == 0) { 654*1d4b38e0Srsmaeda rv = 0; 655*1d4b38e0Srsmaeda goto done; 656*1d4b38e0Srsmaeda } 657*1d4b38e0Srsmaeda 658*1d4b38e0Srsmaeda /* allocate an nvlist for the RCM call */ 659*1d4b38e0Srsmaeda if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 660*1d4b38e0Srsmaeda goto done; 661*1d4b38e0Srsmaeda } 662*1d4b38e0Srsmaeda 663*1d4b38e0Srsmaeda /* 664*1d4b38e0Srsmaeda * Removed CPU capacity, so newcpus is the current list 665*1d4b38e0Srsmaeda * of CPUs in the system. 666*1d4b38e0Srsmaeda */ 667*1d4b38e0Srsmaeda if (get_sys_cpuids(&newcpus, &newncpus) == -1) { 668*1d4b38e0Srsmaeda goto done; 669*1d4b38e0Srsmaeda } 670*1d4b38e0Srsmaeda 671*1d4b38e0Srsmaeda /* 672*1d4b38e0Srsmaeda * Since the operation removed CPU capacity, the old CPU 673*1d4b38e0Srsmaeda * list is the new CPU list with the CPUs involved in 674*1d4b38e0Srsmaeda * the operation added. 675*1d4b38e0Srsmaeda */ 676*1d4b38e0Srsmaeda oldcpus = (cpuid_t *)calloc(newncpus + cidx, sizeof (cpuid_t)); 677*1d4b38e0Srsmaeda if (oldcpus == NULL) { 678*1d4b38e0Srsmaeda goto done; 679*1d4b38e0Srsmaeda } 680*1d4b38e0Srsmaeda 681*1d4b38e0Srsmaeda for (idx = 0; idx < newncpus; idx++) { 682*1d4b38e0Srsmaeda if (!is_cpu_in_list(newcpus[idx], cpus, cidx)) 683*1d4b38e0Srsmaeda oldcpus[oldncpus++] = newcpus[idx]; 684*1d4b38e0Srsmaeda } 685*1d4b38e0Srsmaeda 686*1d4b38e0Srsmaeda for (idx = 0; idx < cidx; idx++) { 687*1d4b38e0Srsmaeda oldcpus[oldncpus++] = cpus[idx]; 688*1d4b38e0Srsmaeda } 689*1d4b38e0Srsmaeda 690*1d4b38e0Srsmaeda /* dump pre and post lists */ 691*1d4b38e0Srsmaeda dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 692*1d4b38e0Srsmaeda dump_cpu_list("newcpus: ", newcpus, newncpus); 693*1d4b38e0Srsmaeda dump_cpu_list("delta: ", cpus, cidx); 694*1d4b38e0Srsmaeda 695*1d4b38e0Srsmaeda /* setup the nvlist for the RCM call */ 696*1d4b38e0Srsmaeda if (nvlist_add_string(nvl, "state", "capacity") || 697*1d4b38e0Srsmaeda nvlist_add_int32(nvl, "old_total", oldncpus) || 698*1d4b38e0Srsmaeda nvlist_add_int32(nvl, "new_total", newncpus) || 699*1d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 700*1d4b38e0Srsmaeda nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 701*1d4b38e0Srsmaeda goto done; 702*1d4b38e0Srsmaeda } 703*1d4b38e0Srsmaeda 704*1d4b38e0Srsmaeda rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 705*1d4b38e0Srsmaeda rv = (rv == RCM_SUCCESS) ? 0 : -1; 706*1d4b38e0Srsmaeda 707*1d4b38e0Srsmaeda done: 708*1d4b38e0Srsmaeda s_nvfree(nvl); 709*1d4b38e0Srsmaeda s_free(cpus); 710*1d4b38e0Srsmaeda s_free(oldcpus); 711*1d4b38e0Srsmaeda s_free(newcpus); 712*1d4b38e0Srsmaeda 713*1d4b38e0Srsmaeda return (rv); 714*1d4b38e0Srsmaeda } 715*1d4b38e0Srsmaeda 716*1d4b38e0Srsmaeda /* 717*1d4b38e0Srsmaeda * Given a list of resource structures, create a list of CPU 718*1d4b38e0Srsmaeda * resource strings formatted as expected by RCM. Only resources 719*1d4b38e0Srsmaeda * that are in the state specified by the status argument are 720*1d4b38e0Srsmaeda * included in the resulting list. 721*1d4b38e0Srsmaeda */ 722*1d4b38e0Srsmaeda static char ** 723*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_init(drctl_rsrc_t *rsrcs, int nrsrc, int status) 724*1d4b38e0Srsmaeda { 725*1d4b38e0Srsmaeda char rbuf[RCM_CPU_MAX_LEN]; 726*1d4b38e0Srsmaeda char **rlist; 727*1d4b38e0Srsmaeda int idx; 728*1d4b38e0Srsmaeda int ridx; 729*1d4b38e0Srsmaeda 730*1d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_rlist_init..."); 731*1d4b38e0Srsmaeda 732*1d4b38e0Srsmaeda if ((rsrcs == NULL) || (nrsrc == 0)) { 733*1d4b38e0Srsmaeda drd_dbg("cpu list is empty"); 734*1d4b38e0Srsmaeda return (NULL); 735*1d4b38e0Srsmaeda } 736*1d4b38e0Srsmaeda 737*1d4b38e0Srsmaeda /* allocate a zero filled array to ensure NULL terminated list */ 738*1d4b38e0Srsmaeda rlist = (char **)calloc((nrsrc + 1), sizeof (char *)); 739*1d4b38e0Srsmaeda if (rlist == NULL) { 740*1d4b38e0Srsmaeda drd_err("calloc failed: %s", strerror(errno)); 741*1d4b38e0Srsmaeda return (NULL); 742*1d4b38e0Srsmaeda } 743*1d4b38e0Srsmaeda 744*1d4b38e0Srsmaeda for (idx = 0, ridx = 0; idx < nrsrc; idx++) { 745*1d4b38e0Srsmaeda 746*1d4b38e0Srsmaeda drd_dbg(" checking cpu %d, status=%d, expected status=%d", 747*1d4b38e0Srsmaeda rsrcs[idx].res_cpu_id, rsrcs[idx].status, status); 748*1d4b38e0Srsmaeda 749*1d4b38e0Srsmaeda /* 750*1d4b38e0Srsmaeda * Filter out the CPUs that are not in 751*1d4b38e0Srsmaeda * the requested state. 752*1d4b38e0Srsmaeda */ 753*1d4b38e0Srsmaeda if (rsrcs[idx].status != status) 754*1d4b38e0Srsmaeda continue; 755*1d4b38e0Srsmaeda 756*1d4b38e0Srsmaeda /* generate the resource string */ 757*1d4b38e0Srsmaeda (void) sprintf(rbuf, "%s%d", RCM_CPU, rsrcs[idx].res_cpu_id); 758*1d4b38e0Srsmaeda 759*1d4b38e0Srsmaeda rlist[ridx] = strdup(rbuf); 760*1d4b38e0Srsmaeda if (rlist[ridx] == NULL) { 761*1d4b38e0Srsmaeda drd_err("strdup failed: %s", strerror(errno)); 762*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(rlist); 763*1d4b38e0Srsmaeda return (NULL); 764*1d4b38e0Srsmaeda } 765*1d4b38e0Srsmaeda 766*1d4b38e0Srsmaeda ridx++; 767*1d4b38e0Srsmaeda } 768*1d4b38e0Srsmaeda 769*1d4b38e0Srsmaeda /* cleanup if the list is empty */ 770*1d4b38e0Srsmaeda if (ridx == 0) { 771*1d4b38e0Srsmaeda s_free(rlist); 772*1d4b38e0Srsmaeda } 773*1d4b38e0Srsmaeda 774*1d4b38e0Srsmaeda drd_dbg("final rlist:"); 775*1d4b38e0Srsmaeda dump_cpu_rlist(rlist); 776*1d4b38e0Srsmaeda 777*1d4b38e0Srsmaeda return (rlist); 778*1d4b38e0Srsmaeda } 779*1d4b38e0Srsmaeda 780*1d4b38e0Srsmaeda static void 781*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(char **rlist) 782*1d4b38e0Srsmaeda { 783*1d4b38e0Srsmaeda int idx; 784*1d4b38e0Srsmaeda 785*1d4b38e0Srsmaeda drd_dbg("drd_rcm_cpu_rlist_fini..."); 786*1d4b38e0Srsmaeda 787*1d4b38e0Srsmaeda dump_cpu_rlist(rlist); 788*1d4b38e0Srsmaeda 789*1d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) { 790*1d4b38e0Srsmaeda s_free(rlist[idx]); 791*1d4b38e0Srsmaeda } 792*1d4b38e0Srsmaeda 793*1d4b38e0Srsmaeda s_free(rlist); 794*1d4b38e0Srsmaeda } 795*1d4b38e0Srsmaeda 796*1d4b38e0Srsmaeda /* 797*1d4b38e0Srsmaeda * Convert an RCM CPU resource string into a numerical cpuid. 798*1d4b38e0Srsmaeda * Assumes the resource string has the form: "SUNW_cpu/cpu<C>" 799*1d4b38e0Srsmaeda * where "<C>" is the numerical cpuid of interest. 800*1d4b38e0Srsmaeda */ 801*1d4b38e0Srsmaeda static cpuid_t 802*1d4b38e0Srsmaeda cpu_rsrcstr_to_cpuid(const char *rsrc) 803*1d4b38e0Srsmaeda { 804*1d4b38e0Srsmaeda char *cpuid_off; 805*1d4b38e0Srsmaeda cpuid_t cpuid; 806*1d4b38e0Srsmaeda 807*1d4b38e0Srsmaeda /* 808*1d4b38e0Srsmaeda * Search for the last occurrance of 'u' in the 809*1d4b38e0Srsmaeda * expected RCM resource string "SUNW_cpu/cpu<C>". 810*1d4b38e0Srsmaeda * This will give a pointer to the cpuid portion. 811*1d4b38e0Srsmaeda */ 812*1d4b38e0Srsmaeda cpuid_off = strrchr(rsrc, 'u'); 813*1d4b38e0Srsmaeda cpuid_off++; 814*1d4b38e0Srsmaeda 815*1d4b38e0Srsmaeda cpuid = atoi(cpuid_off); 816*1d4b38e0Srsmaeda 817*1d4b38e0Srsmaeda return (cpuid); 818*1d4b38e0Srsmaeda } 819*1d4b38e0Srsmaeda 820*1d4b38e0Srsmaeda /* 821*1d4b38e0Srsmaeda * Given an RCM CPU resource string, return a pointer to the 822*1d4b38e0Srsmaeda * corresponding resource structure from the given resource list. 823*1d4b38e0Srsmaeda * NULL is returned if no matching resource structure can be 824*1d4b38e0Srsmaeda * found. 825*1d4b38e0Srsmaeda */ 826*1d4b38e0Srsmaeda static drctl_rsrc_t * 827*1d4b38e0Srsmaeda cpu_rsrcstr_to_rsrc(const char *rsrcstr, drctl_rsrc_t *rsrcs, int nrsrc) 828*1d4b38e0Srsmaeda { 829*1d4b38e0Srsmaeda cpuid_t cpuid; 830*1d4b38e0Srsmaeda int idx; 831*1d4b38e0Srsmaeda 832*1d4b38e0Srsmaeda cpuid = cpu_rsrcstr_to_cpuid(rsrcstr); 833*1d4b38e0Srsmaeda 834*1d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 835*1d4b38e0Srsmaeda if (rsrcs[idx].res_cpu_id == cpuid) 836*1d4b38e0Srsmaeda return (&rsrcs[idx]); 837*1d4b38e0Srsmaeda } 838*1d4b38e0Srsmaeda 839*1d4b38e0Srsmaeda return (NULL); 840*1d4b38e0Srsmaeda } 841*1d4b38e0Srsmaeda 842*1d4b38e0Srsmaeda static int 843*1d4b38e0Srsmaeda get_sys_cpuids(cpuid_t **cpuids, int *ncpuids) 844*1d4b38e0Srsmaeda { 845*1d4b38e0Srsmaeda int ncpu = 0; 846*1d4b38e0Srsmaeda int maxncpu; 847*1d4b38e0Srsmaeda kstat_t *ksp; 848*1d4b38e0Srsmaeda kstat_ctl_t *kc = NULL; 849*1d4b38e0Srsmaeda cpuid_t *cp; 850*1d4b38e0Srsmaeda 851*1d4b38e0Srsmaeda drd_dbg("get_sys_cpuids..."); 852*1d4b38e0Srsmaeda 853*1d4b38e0Srsmaeda if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1) 854*1d4b38e0Srsmaeda return (-1); 855*1d4b38e0Srsmaeda 856*1d4b38e0Srsmaeda if ((kc = kstat_open()) == NULL) 857*1d4b38e0Srsmaeda return (-1); 858*1d4b38e0Srsmaeda 859*1d4b38e0Srsmaeda if ((cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) { 860*1d4b38e0Srsmaeda (void) kstat_close(kc); 861*1d4b38e0Srsmaeda return (-1); 862*1d4b38e0Srsmaeda } 863*1d4b38e0Srsmaeda 864*1d4b38e0Srsmaeda for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 865*1d4b38e0Srsmaeda if (strcmp(ksp->ks_module, "cpu_info") == 0) 866*1d4b38e0Srsmaeda cp[ncpu++] = ksp->ks_instance; 867*1d4b38e0Srsmaeda } 868*1d4b38e0Srsmaeda 869*1d4b38e0Srsmaeda dump_cpu_list("syscpus: ", cp, ncpu); 870*1d4b38e0Srsmaeda 871*1d4b38e0Srsmaeda (void) kstat_close(kc); 872*1d4b38e0Srsmaeda 873*1d4b38e0Srsmaeda *cpuids = cp; 874*1d4b38e0Srsmaeda *ncpuids = ncpu; 875*1d4b38e0Srsmaeda 876*1d4b38e0Srsmaeda return (0); 877*1d4b38e0Srsmaeda } 878*1d4b38e0Srsmaeda 879*1d4b38e0Srsmaeda static boolean_t 880*1d4b38e0Srsmaeda is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len) 881*1d4b38e0Srsmaeda { 882*1d4b38e0Srsmaeda int idx; 883*1d4b38e0Srsmaeda 884*1d4b38e0Srsmaeda if (list == NULL) 885*1d4b38e0Srsmaeda return (B_FALSE); 886*1d4b38e0Srsmaeda 887*1d4b38e0Srsmaeda for (idx = 0; idx < len; idx++) { 888*1d4b38e0Srsmaeda if (list[idx] == cpuid) 889*1d4b38e0Srsmaeda return (B_TRUE); 890*1d4b38e0Srsmaeda } 891*1d4b38e0Srsmaeda 892*1d4b38e0Srsmaeda return (B_FALSE); 893*1d4b38e0Srsmaeda } 894*1d4b38e0Srsmaeda 895*1d4b38e0Srsmaeda #define CPUIDS_PER_LINE 16 896*1d4b38e0Srsmaeda #define LINEWIDTH (2 * (CPUIDS_PER_LINE * 4)) 897*1d4b38e0Srsmaeda 898*1d4b38e0Srsmaeda static void 899*1d4b38e0Srsmaeda dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids) 900*1d4b38e0Srsmaeda { 901*1d4b38e0Srsmaeda char line[LINEWIDTH]; 902*1d4b38e0Srsmaeda char *curr; 903*1d4b38e0Srsmaeda int i, j; 904*1d4b38e0Srsmaeda 905*1d4b38e0Srsmaeda /* return if not debugging */ 906*1d4b38e0Srsmaeda if (drd_debug == 0) 907*1d4b38e0Srsmaeda return; 908*1d4b38e0Srsmaeda 909*1d4b38e0Srsmaeda /* print just the prefix if CPU list is empty */ 910*1d4b38e0Srsmaeda if (ncpuids == 0) { 911*1d4b38e0Srsmaeda if (prefix) 912*1d4b38e0Srsmaeda drd_dbg("%s", prefix); 913*1d4b38e0Srsmaeda return; 914*1d4b38e0Srsmaeda } 915*1d4b38e0Srsmaeda 916*1d4b38e0Srsmaeda for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) { 917*1d4b38e0Srsmaeda 918*1d4b38e0Srsmaeda bzero(line, LINEWIDTH); 919*1d4b38e0Srsmaeda curr = line; 920*1d4b38e0Srsmaeda 921*1d4b38e0Srsmaeda /* start with the prefix */ 922*1d4b38e0Srsmaeda (void) sprintf(curr, "%s", (prefix) ? prefix : ""); 923*1d4b38e0Srsmaeda curr = line + strlen(line); 924*1d4b38e0Srsmaeda 925*1d4b38e0Srsmaeda /* format the CPUs for this line */ 926*1d4b38e0Srsmaeda for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) { 927*1d4b38e0Srsmaeda (void) sprintf(curr, "%3d ", cpuids[i + j]); 928*1d4b38e0Srsmaeda curr = line + strlen(line); 929*1d4b38e0Srsmaeda } 930*1d4b38e0Srsmaeda 931*1d4b38e0Srsmaeda drd_dbg("%s", line); 932*1d4b38e0Srsmaeda } 933*1d4b38e0Srsmaeda } 934*1d4b38e0Srsmaeda 935*1d4b38e0Srsmaeda static void 936*1d4b38e0Srsmaeda dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc) 937*1d4b38e0Srsmaeda { 938*1d4b38e0Srsmaeda int idx; 939*1d4b38e0Srsmaeda char *errstr; 940*1d4b38e0Srsmaeda 941*1d4b38e0Srsmaeda /* just return if not debugging */ 942*1d4b38e0Srsmaeda if (drd_debug == 0) 943*1d4b38e0Srsmaeda return; 944*1d4b38e0Srsmaeda 945*1d4b38e0Srsmaeda if (prefix) 946*1d4b38e0Srsmaeda drd_dbg("%s", prefix); 947*1d4b38e0Srsmaeda 948*1d4b38e0Srsmaeda for (idx = 0; idx < nrsrc; idx++) { 949*1d4b38e0Srsmaeda 950*1d4b38e0Srsmaeda /* get a pointer to the error string */ 951*1d4b38e0Srsmaeda errstr = (char *)(uintptr_t)rsrcs[idx].offset; 952*1d4b38e0Srsmaeda 953*1d4b38e0Srsmaeda drd_dbg(" cpu[%d]: cpuid=%d, status=%d, errstr='%s'", idx, 954*1d4b38e0Srsmaeda rsrcs[idx].res_cpu_id, rsrcs[idx].status, 955*1d4b38e0Srsmaeda (errstr != NULL) ? errstr : ""); 956*1d4b38e0Srsmaeda } 957*1d4b38e0Srsmaeda } 958*1d4b38e0Srsmaeda 959*1d4b38e0Srsmaeda static void 960*1d4b38e0Srsmaeda dump_cpu_rlist(char **rlist) 961*1d4b38e0Srsmaeda { 962*1d4b38e0Srsmaeda int idx; 963*1d4b38e0Srsmaeda int state; 964*1d4b38e0Srsmaeda 965*1d4b38e0Srsmaeda static char *rcm_state_str[] = { 966*1d4b38e0Srsmaeda "UNKNOWN", "ONLINE", "ONLINING", 967*1d4b38e0Srsmaeda "OFFLINE_FAIL", "OFFLINING", "OFFLINE", 968*1d4b38e0Srsmaeda "REMOVING", "INVALID_7", "INVALID_8", 969*1d4b38e0Srsmaeda "INVALID_9", "RESUMING", "SUSPEND_FAIL", 970*1d4b38e0Srsmaeda "SUSPENDING", "SUSPEND", "REMOVE", 971*1d4b38e0Srsmaeda "OFFLINE_QUERYING", "OFFLINE_QUERY_FAIL", "OFFLINE_QUERY", 972*1d4b38e0Srsmaeda "SUSPEND_QUERYING", "SUSPEND_QUERY_FAIL", "SUSPEND_QUERY" 973*1d4b38e0Srsmaeda }; 974*1d4b38e0Srsmaeda 975*1d4b38e0Srsmaeda /* just return if not debugging */ 976*1d4b38e0Srsmaeda if (drd_debug == 0) 977*1d4b38e0Srsmaeda return; 978*1d4b38e0Srsmaeda 979*1d4b38e0Srsmaeda if (rlist == NULL) { 980*1d4b38e0Srsmaeda drd_dbg(" empty rlist"); 981*1d4b38e0Srsmaeda return; 982*1d4b38e0Srsmaeda } 983*1d4b38e0Srsmaeda 984*1d4b38e0Srsmaeda for (idx = 0; rlist[idx] != NULL; idx++) { 985*1d4b38e0Srsmaeda state = 0; 986*1d4b38e0Srsmaeda rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state); 987*1d4b38e0Srsmaeda drd_dbg(" rlist[%d]: rsrc=%s, state=%-2d (%s)", idx, 988*1d4b38e0Srsmaeda rlist[idx], state, rcm_state_str[state]); 989*1d4b38e0Srsmaeda } 990*1d4b38e0Srsmaeda } 991