1*7532SSean.Ye@Sun.COM /* 2*7532SSean.Ye@Sun.COM * CDDL HEADER START 3*7532SSean.Ye@Sun.COM * 4*7532SSean.Ye@Sun.COM * The contents of this file are subject to the terms of the 5*7532SSean.Ye@Sun.COM * Common Development and Distribution License (the "License"). 6*7532SSean.Ye@Sun.COM * You may not use this file except in compliance with the License. 7*7532SSean.Ye@Sun.COM * 8*7532SSean.Ye@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7532SSean.Ye@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*7532SSean.Ye@Sun.COM * See the License for the specific language governing permissions 11*7532SSean.Ye@Sun.COM * and limitations under the License. 12*7532SSean.Ye@Sun.COM * 13*7532SSean.Ye@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*7532SSean.Ye@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7532SSean.Ye@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*7532SSean.Ye@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*7532SSean.Ye@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*7532SSean.Ye@Sun.COM * 19*7532SSean.Ye@Sun.COM * CDDL HEADER END 20*7532SSean.Ye@Sun.COM */ 21*7532SSean.Ye@Sun.COM /* 22*7532SSean.Ye@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*7532SSean.Ye@Sun.COM * Use is subject to license terms. 24*7532SSean.Ye@Sun.COM */ 25*7532SSean.Ye@Sun.COM 26*7532SSean.Ye@Sun.COM #include <sys/stat.h> 27*7532SSean.Ye@Sun.COM #include <sys/types.h> 28*7532SSean.Ye@Sun.COM #include <sys/time.h> 29*7532SSean.Ye@Sun.COM 30*7532SSean.Ye@Sun.COM #include <sys/fm/protocol.h> 31*7532SSean.Ye@Sun.COM #include <sys/devfm.h> 32*7532SSean.Ye@Sun.COM 33*7532SSean.Ye@Sun.COM #include <sys/cpu_module.h> 34*7532SSean.Ye@Sun.COM 35*7532SSean.Ye@Sun.COM #define ANY_ID (uint_t)-1 36*7532SSean.Ye@Sun.COM 37*7532SSean.Ye@Sun.COM /* 38*7532SSean.Ye@Sun.COM * INIT_HDLS is the initial size of cmi_hdl_t array. We fill the array 39*7532SSean.Ye@Sun.COM * during cmi_hdl_walk, if the array overflows, we will reallocate 40*7532SSean.Ye@Sun.COM * a new array twice the size of the old one. 41*7532SSean.Ye@Sun.COM */ 42*7532SSean.Ye@Sun.COM #define INIT_HDLS 16 43*7532SSean.Ye@Sun.COM 44*7532SSean.Ye@Sun.COM typedef struct fm_cmi_walk_t 45*7532SSean.Ye@Sun.COM { 46*7532SSean.Ye@Sun.COM uint_t chipid; /* chipid to match during walk */ 47*7532SSean.Ye@Sun.COM uint_t coreid; /* coreid to match */ 48*7532SSean.Ye@Sun.COM uint_t strandid; /* strandid to match */ 49*7532SSean.Ye@Sun.COM int (*cbfunc)(cmi_hdl_t, void *, void *); /* callback function */ 50*7532SSean.Ye@Sun.COM cmi_hdl_t *hdls; /* allocated array to save the handles */ 51*7532SSean.Ye@Sun.COM int nhdl_max; /* allocated array size */ 52*7532SSean.Ye@Sun.COM int nhdl; /* handles saved */ 53*7532SSean.Ye@Sun.COM } fm_cmi_walk_t; 54*7532SSean.Ye@Sun.COM 55*7532SSean.Ye@Sun.COM int 56*7532SSean.Ye@Sun.COM fm_get_paddr(nvlist_t *nvl, uint64_t *paddr) 57*7532SSean.Ye@Sun.COM { 58*7532SSean.Ye@Sun.COM uint8_t version; 59*7532SSean.Ye@Sun.COM uint64_t pa; 60*7532SSean.Ye@Sun.COM char *scheme; 61*7532SSean.Ye@Sun.COM int err; 62*7532SSean.Ye@Sun.COM 63*7532SSean.Ye@Sun.COM /* Verify FMRI scheme name and version number */ 64*7532SSean.Ye@Sun.COM if ((nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) || 65*7532SSean.Ye@Sun.COM (strcmp(scheme, FM_FMRI_SCHEME_HC) != 0) || 66*7532SSean.Ye@Sun.COM (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0) || 67*7532SSean.Ye@Sun.COM version > FM_HC_SCHEME_VERSION) { 68*7532SSean.Ye@Sun.COM return (EINVAL); 69*7532SSean.Ye@Sun.COM } 70*7532SSean.Ye@Sun.COM 71*7532SSean.Ye@Sun.COM if ((err = cmi_mc_unumtopa(NULL, nvl, &pa)) != CMI_SUCCESS && 72*7532SSean.Ye@Sun.COM err != CMIERR_MC_PARTIALUNUMTOPA) 73*7532SSean.Ye@Sun.COM return (EINVAL); 74*7532SSean.Ye@Sun.COM 75*7532SSean.Ye@Sun.COM *paddr = pa; 76*7532SSean.Ye@Sun.COM return (0); 77*7532SSean.Ye@Sun.COM } 78*7532SSean.Ye@Sun.COM 79*7532SSean.Ye@Sun.COM /* 80*7532SSean.Ye@Sun.COM * Routines for cmi handles walk. 81*7532SSean.Ye@Sun.COM */ 82*7532SSean.Ye@Sun.COM 83*7532SSean.Ye@Sun.COM static void 84*7532SSean.Ye@Sun.COM walk_init(fm_cmi_walk_t *wp, uint_t chipid, uint_t coreid, uint_t strandid, 85*7532SSean.Ye@Sun.COM int (*cbfunc)(cmi_hdl_t, void *, void *)) 86*7532SSean.Ye@Sun.COM { 87*7532SSean.Ye@Sun.COM wp->chipid = chipid; 88*7532SSean.Ye@Sun.COM wp->coreid = coreid; 89*7532SSean.Ye@Sun.COM wp->strandid = strandid; 90*7532SSean.Ye@Sun.COM /* 91*7532SSean.Ye@Sun.COM * If callback is not set, we allocate an array to save the 92*7532SSean.Ye@Sun.COM * cmi handles. 93*7532SSean.Ye@Sun.COM */ 94*7532SSean.Ye@Sun.COM if ((wp->cbfunc = cbfunc) == NULL) { 95*7532SSean.Ye@Sun.COM wp->hdls = kmem_alloc(sizeof (cmi_hdl_t) * INIT_HDLS, KM_SLEEP); 96*7532SSean.Ye@Sun.COM wp->nhdl_max = INIT_HDLS; 97*7532SSean.Ye@Sun.COM wp->nhdl = 0; 98*7532SSean.Ye@Sun.COM } 99*7532SSean.Ye@Sun.COM } 100*7532SSean.Ye@Sun.COM 101*7532SSean.Ye@Sun.COM static void 102*7532SSean.Ye@Sun.COM walk_fini(fm_cmi_walk_t *wp) 103*7532SSean.Ye@Sun.COM { 104*7532SSean.Ye@Sun.COM if (wp->cbfunc == NULL) 105*7532SSean.Ye@Sun.COM kmem_free(wp->hdls, sizeof (cmi_hdl_t) * wp->nhdl_max); 106*7532SSean.Ye@Sun.COM } 107*7532SSean.Ye@Sun.COM 108*7532SSean.Ye@Sun.COM static int 109*7532SSean.Ye@Sun.COM select_cmi_hdl(cmi_hdl_t hdl, void *arg1, void *arg2, void *arg3) 110*7532SSean.Ye@Sun.COM { 111*7532SSean.Ye@Sun.COM fm_cmi_walk_t *wp = (fm_cmi_walk_t *)arg1; 112*7532SSean.Ye@Sun.COM 113*7532SSean.Ye@Sun.COM if (wp->chipid != ANY_ID && wp->chipid != cmi_hdl_chipid(hdl)) 114*7532SSean.Ye@Sun.COM return (CMI_HDL_WALK_NEXT); 115*7532SSean.Ye@Sun.COM if (wp->coreid != ANY_ID && wp->coreid != cmi_hdl_coreid(hdl)) 116*7532SSean.Ye@Sun.COM return (CMI_HDL_WALK_NEXT); 117*7532SSean.Ye@Sun.COM if (wp->strandid != ANY_ID && wp->strandid != cmi_hdl_strandid(hdl)) 118*7532SSean.Ye@Sun.COM return (CMI_HDL_WALK_NEXT); 119*7532SSean.Ye@Sun.COM 120*7532SSean.Ye@Sun.COM /* 121*7532SSean.Ye@Sun.COM * Call the callback function if any exists, otherwise we hold a 122*7532SSean.Ye@Sun.COM * reference of the handle and push it to preallocated array. 123*7532SSean.Ye@Sun.COM * If the allocated array is going to overflow, reallocate a 124*7532SSean.Ye@Sun.COM * bigger one to replace it. 125*7532SSean.Ye@Sun.COM */ 126*7532SSean.Ye@Sun.COM if (wp->cbfunc != NULL) 127*7532SSean.Ye@Sun.COM return (wp->cbfunc(hdl, arg2, arg3)); 128*7532SSean.Ye@Sun.COM 129*7532SSean.Ye@Sun.COM if (wp->nhdl == wp->nhdl_max) { 130*7532SSean.Ye@Sun.COM size_t sz = sizeof (cmi_hdl_t) * wp->nhdl_max; 131*7532SSean.Ye@Sun.COM cmi_hdl_t *newarray = kmem_alloc(sz << 1, KM_SLEEP); 132*7532SSean.Ye@Sun.COM 133*7532SSean.Ye@Sun.COM bcopy(wp->hdls, newarray, sz); 134*7532SSean.Ye@Sun.COM kmem_free(wp->hdls, sz); 135*7532SSean.Ye@Sun.COM wp->hdls = newarray; 136*7532SSean.Ye@Sun.COM wp->nhdl_max <<= 1; 137*7532SSean.Ye@Sun.COM } 138*7532SSean.Ye@Sun.COM 139*7532SSean.Ye@Sun.COM cmi_hdl_hold(hdl); 140*7532SSean.Ye@Sun.COM wp->hdls[wp->nhdl++] = hdl; 141*7532SSean.Ye@Sun.COM 142*7532SSean.Ye@Sun.COM return (CMI_HDL_WALK_NEXT); 143*7532SSean.Ye@Sun.COM } 144*7532SSean.Ye@Sun.COM 145*7532SSean.Ye@Sun.COM static void 146*7532SSean.Ye@Sun.COM populate_cpu(nvlist_t **nvlp, cmi_hdl_t hdl) 147*7532SSean.Ye@Sun.COM { 148*7532SSean.Ye@Sun.COM (void) nvlist_alloc(nvlp, NV_UNIQUE_NAME, KM_SLEEP); 149*7532SSean.Ye@Sun.COM fm_payload_set(*nvlp, 150*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_VENDOR_ID, DATA_TYPE_STRING, 151*7532SSean.Ye@Sun.COM cmi_hdl_vendorstr(hdl), 152*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_FAMILY, DATA_TYPE_INT32, 153*7532SSean.Ye@Sun.COM (int32_t)cmi_hdl_family(hdl), 154*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_MODEL, DATA_TYPE_INT32, 155*7532SSean.Ye@Sun.COM (int32_t)cmi_hdl_model(hdl), 156*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_STEPPING, DATA_TYPE_INT32, 157*7532SSean.Ye@Sun.COM (int32_t)cmi_hdl_stepping(hdl), 158*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_CHIP_ID, DATA_TYPE_INT32, 159*7532SSean.Ye@Sun.COM (int32_t)cmi_hdl_chipid(hdl), 160*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_CORE_ID, DATA_TYPE_INT32, 161*7532SSean.Ye@Sun.COM (int32_t)cmi_hdl_coreid(hdl), 162*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_STRAND_ID, DATA_TYPE_INT32, 163*7532SSean.Ye@Sun.COM (int32_t)cmi_hdl_strandid(hdl), 164*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_CHIP_REV, DATA_TYPE_STRING, 165*7532SSean.Ye@Sun.COM cmi_hdl_chiprevstr(hdl), 166*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_SOCKET_TYPE, DATA_TYPE_UINT32, 167*7532SSean.Ye@Sun.COM (uint32_t)cmi_hdl_getsockettype(hdl), 168*7532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_CPU_ID, DATA_TYPE_INT32, 169*7532SSean.Ye@Sun.COM (int32_t)cmi_hdl_logical_id(hdl), 170*7532SSean.Ye@Sun.COM NULL); 171*7532SSean.Ye@Sun.COM } 172*7532SSean.Ye@Sun.COM 173*7532SSean.Ye@Sun.COM /*ARGSUSED*/ 174*7532SSean.Ye@Sun.COM int 175*7532SSean.Ye@Sun.COM fm_ioctl_physcpu_info(int cmd, nvlist_t *invl, nvlist_t **onvlp) 176*7532SSean.Ye@Sun.COM { 177*7532SSean.Ye@Sun.COM nvlist_t **cpus, *nvl; 178*7532SSean.Ye@Sun.COM int i, err; 179*7532SSean.Ye@Sun.COM fm_cmi_walk_t wk; 180*7532SSean.Ye@Sun.COM 181*7532SSean.Ye@Sun.COM /* 182*7532SSean.Ye@Sun.COM * Do a walk to save all the cmi handles in the array. 183*7532SSean.Ye@Sun.COM */ 184*7532SSean.Ye@Sun.COM walk_init(&wk, ANY_ID, ANY_ID, ANY_ID, NULL); 185*7532SSean.Ye@Sun.COM cmi_hdl_walk(select_cmi_hdl, &wk, NULL, NULL); 186*7532SSean.Ye@Sun.COM 187*7532SSean.Ye@Sun.COM if (wk.nhdl == 0) { 188*7532SSean.Ye@Sun.COM walk_fini(&wk); 189*7532SSean.Ye@Sun.COM return (ENOENT); 190*7532SSean.Ye@Sun.COM } 191*7532SSean.Ye@Sun.COM 192*7532SSean.Ye@Sun.COM cpus = kmem_alloc(sizeof (nvlist_t *) * wk.nhdl, KM_SLEEP); 193*7532SSean.Ye@Sun.COM for (i = 0; i < wk.nhdl; i++) { 194*7532SSean.Ye@Sun.COM populate_cpu(cpus + i, wk.hdls[i]); 195*7532SSean.Ye@Sun.COM cmi_hdl_rele(wk.hdls[i]); 196*7532SSean.Ye@Sun.COM } 197*7532SSean.Ye@Sun.COM 198*7532SSean.Ye@Sun.COM walk_fini(&wk); 199*7532SSean.Ye@Sun.COM 200*7532SSean.Ye@Sun.COM (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 201*7532SSean.Ye@Sun.COM err = nvlist_add_nvlist_array(nvl, FM_PHYSCPU_INFO_CPUS, 202*7532SSean.Ye@Sun.COM cpus, wk.nhdl); 203*7532SSean.Ye@Sun.COM 204*7532SSean.Ye@Sun.COM for (i = 0; i < wk.nhdl; i++) 205*7532SSean.Ye@Sun.COM nvlist_free(cpus[i]); 206*7532SSean.Ye@Sun.COM kmem_free(cpus, sizeof (nvlist_t *) * wk.nhdl); 207*7532SSean.Ye@Sun.COM 208*7532SSean.Ye@Sun.COM if (err != 0) { 209*7532SSean.Ye@Sun.COM nvlist_free(nvl); 210*7532SSean.Ye@Sun.COM return (err); 211*7532SSean.Ye@Sun.COM } 212*7532SSean.Ye@Sun.COM 213*7532SSean.Ye@Sun.COM *onvlp = nvl; 214*7532SSean.Ye@Sun.COM return (0); 215*7532SSean.Ye@Sun.COM } 216*7532SSean.Ye@Sun.COM 217*7532SSean.Ye@Sun.COM int 218*7532SSean.Ye@Sun.COM fm_ioctl_cpu_retire(int cmd, nvlist_t *invl, nvlist_t **onvlp) 219*7532SSean.Ye@Sun.COM { 220*7532SSean.Ye@Sun.COM int32_t chipid, coreid, strandid; 221*7532SSean.Ye@Sun.COM int rc, new_status, old_status; 222*7532SSean.Ye@Sun.COM cmi_hdl_t hdl; 223*7532SSean.Ye@Sun.COM nvlist_t *nvl; 224*7532SSean.Ye@Sun.COM 225*7532SSean.Ye@Sun.COM switch (cmd) { 226*7532SSean.Ye@Sun.COM case FM_IOC_CPU_RETIRE: 227*7532SSean.Ye@Sun.COM new_status = P_FAULTED; 228*7532SSean.Ye@Sun.COM break; 229*7532SSean.Ye@Sun.COM case FM_IOC_CPU_STATUS: 230*7532SSean.Ye@Sun.COM new_status = P_STATUS; 231*7532SSean.Ye@Sun.COM break; 232*7532SSean.Ye@Sun.COM case FM_IOC_CPU_UNRETIRE: 233*7532SSean.Ye@Sun.COM new_status = P_ONLINE; 234*7532SSean.Ye@Sun.COM break; 235*7532SSean.Ye@Sun.COM default: 236*7532SSean.Ye@Sun.COM return (ENOTTY); 237*7532SSean.Ye@Sun.COM } 238*7532SSean.Ye@Sun.COM 239*7532SSean.Ye@Sun.COM if (nvlist_lookup_int32(invl, FM_CPU_RETIRE_CHIP_ID, &chipid) != 0 || 240*7532SSean.Ye@Sun.COM nvlist_lookup_int32(invl, FM_CPU_RETIRE_CORE_ID, &coreid) != 0 || 241*7532SSean.Ye@Sun.COM nvlist_lookup_int32(invl, FM_CPU_RETIRE_STRAND_ID, &strandid) != 0) 242*7532SSean.Ye@Sun.COM return (EINVAL); 243*7532SSean.Ye@Sun.COM 244*7532SSean.Ye@Sun.COM hdl = cmi_hdl_lookup(CMI_HDL_NEUTRAL, chipid, coreid, strandid); 245*7532SSean.Ye@Sun.COM if (hdl == NULL) 246*7532SSean.Ye@Sun.COM return (EINVAL); 247*7532SSean.Ye@Sun.COM 248*7532SSean.Ye@Sun.COM rc = cmi_hdl_online(hdl, new_status, &old_status); 249*7532SSean.Ye@Sun.COM cmi_hdl_rele(hdl); 250*7532SSean.Ye@Sun.COM 251*7532SSean.Ye@Sun.COM if (rc == 0) { 252*7532SSean.Ye@Sun.COM (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 253*7532SSean.Ye@Sun.COM (void) nvlist_add_int32(nvl, FM_CPU_RETIRE_OLDSTATUS, 254*7532SSean.Ye@Sun.COM old_status); 255*7532SSean.Ye@Sun.COM *onvlp = nvl; 256*7532SSean.Ye@Sun.COM } 257*7532SSean.Ye@Sun.COM 258*7532SSean.Ye@Sun.COM return (rc); 259*7532SSean.Ye@Sun.COM } 260