1e4b86885SCheng Sean Ye /* 2e4b86885SCheng Sean Ye * CDDL HEADER START 3e4b86885SCheng Sean Ye * 4e4b86885SCheng Sean Ye * The contents of this file are subject to the terms of the 5e4b86885SCheng Sean Ye * Common Development and Distribution License (the "License"). 6e4b86885SCheng Sean Ye * You may not use this file except in compliance with the License. 7e4b86885SCheng Sean Ye * 8e4b86885SCheng Sean Ye * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9e4b86885SCheng Sean Ye * or http://www.opensolaris.org/os/licensing. 10e4b86885SCheng Sean Ye * See the License for the specific language governing permissions 11e4b86885SCheng Sean Ye * and limitations under the License. 12e4b86885SCheng Sean Ye * 13e4b86885SCheng Sean Ye * When distributing Covered Code, include this CDDL HEADER in each 14e4b86885SCheng Sean Ye * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15e4b86885SCheng Sean Ye * If applicable, add the following below this CDDL HEADER, with the 16e4b86885SCheng Sean Ye * fields enclosed by brackets "[]" replaced with your own identifying 17e4b86885SCheng Sean Ye * information: Portions Copyright [yyyy] [name of copyright owner] 18e4b86885SCheng Sean Ye * 19e4b86885SCheng Sean Ye * CDDL HEADER END 20e4b86885SCheng Sean Ye */ 21e4b86885SCheng Sean Ye /* 22074bb90dSTom Pothier * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23e4b86885SCheng Sean Ye * Use is subject to license terms. 24e4b86885SCheng Sean Ye */ 25e4b86885SCheng Sean Ye 26e4b86885SCheng Sean Ye #include <sys/stat.h> 27e4b86885SCheng Sean Ye #include <sys/types.h> 28e4b86885SCheng Sean Ye #include <sys/time.h> 29e4b86885SCheng Sean Ye 30e4b86885SCheng Sean Ye #include <sys/fm/protocol.h> 31074bb90dSTom Pothier #include <sys/fm/smb/fmsmb.h> 32e4b86885SCheng Sean Ye #include <sys/devfm.h> 33e4b86885SCheng Sean Ye 34e4b86885SCheng Sean Ye #include <sys/cpu_module.h> 35e4b86885SCheng Sean Ye 36e4b86885SCheng Sean Ye #define ANY_ID (uint_t)-1 37e4b86885SCheng Sean Ye 38e4b86885SCheng Sean Ye /* 39e4b86885SCheng Sean Ye * INIT_HDLS is the initial size of cmi_hdl_t array. We fill the array 40e4b86885SCheng Sean Ye * during cmi_hdl_walk, if the array overflows, we will reallocate 41e4b86885SCheng Sean Ye * a new array twice the size of the old one. 42e4b86885SCheng Sean Ye */ 43e4b86885SCheng Sean Ye #define INIT_HDLS 16 44e4b86885SCheng Sean Ye 45e4b86885SCheng Sean Ye typedef struct fm_cmi_walk_t 46e4b86885SCheng Sean Ye { 47e4b86885SCheng Sean Ye uint_t chipid; /* chipid to match during walk */ 48e4b86885SCheng Sean Ye uint_t coreid; /* coreid to match */ 49e4b86885SCheng Sean Ye uint_t strandid; /* strandid to match */ 50e4b86885SCheng Sean Ye int (*cbfunc)(cmi_hdl_t, void *, void *); /* callback function */ 51e4b86885SCheng Sean Ye cmi_hdl_t *hdls; /* allocated array to save the handles */ 52e4b86885SCheng Sean Ye int nhdl_max; /* allocated array size */ 53e4b86885SCheng Sean Ye int nhdl; /* handles saved */ 54e4b86885SCheng Sean Ye } fm_cmi_walk_t; 55e4b86885SCheng Sean Ye 56074bb90dSTom Pothier extern int x86gentopo_legacy; 57074bb90dSTom Pothier 58e4b86885SCheng Sean Ye int 59e4b86885SCheng Sean Ye fm_get_paddr(nvlist_t *nvl, uint64_t *paddr) 60e4b86885SCheng Sean Ye { 61e4b86885SCheng Sean Ye uint8_t version; 62e4b86885SCheng Sean Ye uint64_t pa; 63e4b86885SCheng Sean Ye char *scheme; 64e4b86885SCheng Sean Ye int err; 65e4b86885SCheng Sean Ye 66e4b86885SCheng Sean Ye /* Verify FMRI scheme name and version number */ 67e4b86885SCheng Sean Ye if ((nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) || 68e4b86885SCheng Sean Ye (strcmp(scheme, FM_FMRI_SCHEME_HC) != 0) || 69e4b86885SCheng Sean Ye (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0) || 70e4b86885SCheng Sean Ye version > FM_HC_SCHEME_VERSION) { 71e4b86885SCheng Sean Ye return (EINVAL); 72e4b86885SCheng Sean Ye } 73e4b86885SCheng Sean Ye 74e4b86885SCheng Sean Ye if ((err = cmi_mc_unumtopa(NULL, nvl, &pa)) != CMI_SUCCESS && 75e4b86885SCheng Sean Ye err != CMIERR_MC_PARTIALUNUMTOPA) 76e4b86885SCheng Sean Ye return (EINVAL); 77e4b86885SCheng Sean Ye 78e4b86885SCheng Sean Ye *paddr = pa; 79e4b86885SCheng Sean Ye return (0); 80e4b86885SCheng Sean Ye } 81e4b86885SCheng Sean Ye 82e4b86885SCheng Sean Ye /* 83e4b86885SCheng Sean Ye * Routines for cmi handles walk. 84e4b86885SCheng Sean Ye */ 85e4b86885SCheng Sean Ye 86e4b86885SCheng Sean Ye static void 87e4b86885SCheng Sean Ye walk_init(fm_cmi_walk_t *wp, uint_t chipid, uint_t coreid, uint_t strandid, 88e4b86885SCheng Sean Ye int (*cbfunc)(cmi_hdl_t, void *, void *)) 89e4b86885SCheng Sean Ye { 90e4b86885SCheng Sean Ye wp->chipid = chipid; 91e4b86885SCheng Sean Ye wp->coreid = coreid; 92e4b86885SCheng Sean Ye wp->strandid = strandid; 93e4b86885SCheng Sean Ye /* 94e4b86885SCheng Sean Ye * If callback is not set, we allocate an array to save the 95e4b86885SCheng Sean Ye * cmi handles. 96e4b86885SCheng Sean Ye */ 97e4b86885SCheng Sean Ye if ((wp->cbfunc = cbfunc) == NULL) { 98e4b86885SCheng Sean Ye wp->hdls = kmem_alloc(sizeof (cmi_hdl_t) * INIT_HDLS, KM_SLEEP); 99e4b86885SCheng Sean Ye wp->nhdl_max = INIT_HDLS; 100e4b86885SCheng Sean Ye wp->nhdl = 0; 101e4b86885SCheng Sean Ye } 102e4b86885SCheng Sean Ye } 103e4b86885SCheng Sean Ye 104e4b86885SCheng Sean Ye static void 105e4b86885SCheng Sean Ye walk_fini(fm_cmi_walk_t *wp) 106e4b86885SCheng Sean Ye { 107e4b86885SCheng Sean Ye if (wp->cbfunc == NULL) 108e4b86885SCheng Sean Ye kmem_free(wp->hdls, sizeof (cmi_hdl_t) * wp->nhdl_max); 109e4b86885SCheng Sean Ye } 110e4b86885SCheng Sean Ye 111e4b86885SCheng Sean Ye static int 112e4b86885SCheng Sean Ye select_cmi_hdl(cmi_hdl_t hdl, void *arg1, void *arg2, void *arg3) 113e4b86885SCheng Sean Ye { 114e4b86885SCheng Sean Ye fm_cmi_walk_t *wp = (fm_cmi_walk_t *)arg1; 115e4b86885SCheng Sean Ye 116e4b86885SCheng Sean Ye if (wp->chipid != ANY_ID && wp->chipid != cmi_hdl_chipid(hdl)) 117e4b86885SCheng Sean Ye return (CMI_HDL_WALK_NEXT); 118e4b86885SCheng Sean Ye if (wp->coreid != ANY_ID && wp->coreid != cmi_hdl_coreid(hdl)) 119e4b86885SCheng Sean Ye return (CMI_HDL_WALK_NEXT); 120e4b86885SCheng Sean Ye if (wp->strandid != ANY_ID && wp->strandid != cmi_hdl_strandid(hdl)) 121e4b86885SCheng Sean Ye return (CMI_HDL_WALK_NEXT); 122e4b86885SCheng Sean Ye 123e4b86885SCheng Sean Ye /* 124e4b86885SCheng Sean Ye * Call the callback function if any exists, otherwise we hold a 125e4b86885SCheng Sean Ye * reference of the handle and push it to preallocated array. 126e4b86885SCheng Sean Ye * If the allocated array is going to overflow, reallocate a 127e4b86885SCheng Sean Ye * bigger one to replace it. 128e4b86885SCheng Sean Ye */ 129e4b86885SCheng Sean Ye if (wp->cbfunc != NULL) 130e4b86885SCheng Sean Ye return (wp->cbfunc(hdl, arg2, arg3)); 131e4b86885SCheng Sean Ye 132e4b86885SCheng Sean Ye if (wp->nhdl == wp->nhdl_max) { 133e4b86885SCheng Sean Ye size_t sz = sizeof (cmi_hdl_t) * wp->nhdl_max; 134e4b86885SCheng Sean Ye cmi_hdl_t *newarray = kmem_alloc(sz << 1, KM_SLEEP); 135e4b86885SCheng Sean Ye 136e4b86885SCheng Sean Ye bcopy(wp->hdls, newarray, sz); 137e4b86885SCheng Sean Ye kmem_free(wp->hdls, sz); 138e4b86885SCheng Sean Ye wp->hdls = newarray; 139e4b86885SCheng Sean Ye wp->nhdl_max <<= 1; 140e4b86885SCheng Sean Ye } 141e4b86885SCheng Sean Ye 142e4b86885SCheng Sean Ye cmi_hdl_hold(hdl); 143e4b86885SCheng Sean Ye wp->hdls[wp->nhdl++] = hdl; 144e4b86885SCheng Sean Ye 145e4b86885SCheng Sean Ye return (CMI_HDL_WALK_NEXT); 146e4b86885SCheng Sean Ye } 147e4b86885SCheng Sean Ye 148e4b86885SCheng Sean Ye static void 149e4b86885SCheng Sean Ye populate_cpu(nvlist_t **nvlp, cmi_hdl_t hdl) 150e4b86885SCheng Sean Ye { 151074bb90dSTom Pothier uint_t fm_chipid; 152074bb90dSTom Pothier uint16_t smbios_id; 153074bb90dSTom Pothier 154e4b86885SCheng Sean Ye (void) nvlist_alloc(nvlp, NV_UNIQUE_NAME, KM_SLEEP); 155074bb90dSTom Pothier 156074bb90dSTom Pothier /* 157074bb90dSTom Pothier * If SMBIOS satisfies FMA Topology needs, gather 158074bb90dSTom Pothier * more information on the chip's physical roots 159074bb90dSTom Pothier * like /chassis=x/motherboard=y/cpuboard=z and 160074bb90dSTom Pothier * set the chip_id to match the SMBIOS' Type 4 161074bb90dSTom Pothier * ordering & this has to match the ereport's chip 162074bb90dSTom Pothier * resource instance derived off of SMBIOS. 163074bb90dSTom Pothier * Multi-Chip-Module support should set the chipid 164074bb90dSTom Pothier * in terms of the processor package rather than 165074bb90dSTom Pothier * the die/node in the processor package, for FM. 166074bb90dSTom Pothier */ 167074bb90dSTom Pothier 168074bb90dSTom Pothier if (!x86gentopo_legacy) { 169074bb90dSTom Pothier smbios_id = cmi_hdl_smbiosid(hdl); 170074bb90dSTom Pothier fm_chipid = cmi_hdl_smb_chipid(hdl); 171074bb90dSTom Pothier (void) nvlist_add_nvlist(*nvlp, FM_PHYSCPU_INFO_CHIP_ROOTS, 172074bb90dSTom Pothier cmi_hdl_smb_bboard(hdl)); 173074bb90dSTom Pothier (void) nvlist_add_uint16(*nvlp, FM_PHYSCPU_INFO_SMBIOS_ID, 174074bb90dSTom Pothier (uint16_t)smbios_id); 175074bb90dSTom Pothier } else 176074bb90dSTom Pothier fm_chipid = cmi_hdl_chipid(hdl); 177074bb90dSTom Pothier 178e4b86885SCheng Sean Ye fm_payload_set(*nvlp, 179e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_VENDOR_ID, DATA_TYPE_STRING, 180e4b86885SCheng Sean Ye cmi_hdl_vendorstr(hdl), 181e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_FAMILY, DATA_TYPE_INT32, 182e4b86885SCheng Sean Ye (int32_t)cmi_hdl_family(hdl), 183e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_MODEL, DATA_TYPE_INT32, 184e4b86885SCheng Sean Ye (int32_t)cmi_hdl_model(hdl), 185e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_STEPPING, DATA_TYPE_INT32, 186e4b86885SCheng Sean Ye (int32_t)cmi_hdl_stepping(hdl), 187e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_CHIP_ID, DATA_TYPE_INT32, 188074bb90dSTom Pothier (int32_t)fm_chipid, 189*8031591dSSrihari Venkatesan FM_PHYSCPU_INFO_NPROCNODES, DATA_TYPE_INT32, 190*8031591dSSrihari Venkatesan (int32_t)cmi_hdl_procnodes_per_pkg(hdl), 191*8031591dSSrihari Venkatesan FM_PHYSCPU_INFO_PROCNODE_ID, DATA_TYPE_INT32, 192*8031591dSSrihari Venkatesan (int32_t)cmi_hdl_procnodeid(hdl), 193e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_CORE_ID, DATA_TYPE_INT32, 194e4b86885SCheng Sean Ye (int32_t)cmi_hdl_coreid(hdl), 195e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_STRAND_ID, DATA_TYPE_INT32, 196e4b86885SCheng Sean Ye (int32_t)cmi_hdl_strandid(hdl), 197074bb90dSTom Pothier FM_PHYSCPU_INFO_STRAND_APICID, DATA_TYPE_INT32, 198074bb90dSTom Pothier (int32_t)cmi_hdl_strand_apicid(hdl), 199e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_CHIP_REV, DATA_TYPE_STRING, 200e4b86885SCheng Sean Ye cmi_hdl_chiprevstr(hdl), 201e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_SOCKET_TYPE, DATA_TYPE_UINT32, 202e4b86885SCheng Sean Ye (uint32_t)cmi_hdl_getsockettype(hdl), 203e4b86885SCheng Sean Ye FM_PHYSCPU_INFO_CPU_ID, DATA_TYPE_INT32, 204e4b86885SCheng Sean Ye (int32_t)cmi_hdl_logical_id(hdl), 205e4b86885SCheng Sean Ye NULL); 206e4b86885SCheng Sean Ye } 207e4b86885SCheng Sean Ye 208e4b86885SCheng Sean Ye /*ARGSUSED*/ 209e4b86885SCheng Sean Ye int 210e4b86885SCheng Sean Ye fm_ioctl_physcpu_info(int cmd, nvlist_t *invl, nvlist_t **onvlp) 211e4b86885SCheng Sean Ye { 212e4b86885SCheng Sean Ye nvlist_t **cpus, *nvl; 213e4b86885SCheng Sean Ye int i, err; 214e4b86885SCheng Sean Ye fm_cmi_walk_t wk; 215e4b86885SCheng Sean Ye 216e4b86885SCheng Sean Ye /* 217e4b86885SCheng Sean Ye * Do a walk to save all the cmi handles in the array. 218e4b86885SCheng Sean Ye */ 219e4b86885SCheng Sean Ye walk_init(&wk, ANY_ID, ANY_ID, ANY_ID, NULL); 220e4b86885SCheng Sean Ye cmi_hdl_walk(select_cmi_hdl, &wk, NULL, NULL); 221e4b86885SCheng Sean Ye 222e4b86885SCheng Sean Ye if (wk.nhdl == 0) { 223e4b86885SCheng Sean Ye walk_fini(&wk); 224e4b86885SCheng Sean Ye return (ENOENT); 225e4b86885SCheng Sean Ye } 226e4b86885SCheng Sean Ye 227e4b86885SCheng Sean Ye cpus = kmem_alloc(sizeof (nvlist_t *) * wk.nhdl, KM_SLEEP); 228e4b86885SCheng Sean Ye for (i = 0; i < wk.nhdl; i++) { 229e4b86885SCheng Sean Ye populate_cpu(cpus + i, wk.hdls[i]); 230e4b86885SCheng Sean Ye cmi_hdl_rele(wk.hdls[i]); 231e4b86885SCheng Sean Ye } 232e4b86885SCheng Sean Ye 233e4b86885SCheng Sean Ye walk_fini(&wk); 234e4b86885SCheng Sean Ye 235e4b86885SCheng Sean Ye (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 236e4b86885SCheng Sean Ye err = nvlist_add_nvlist_array(nvl, FM_PHYSCPU_INFO_CPUS, 237e4b86885SCheng Sean Ye cpus, wk.nhdl); 238e4b86885SCheng Sean Ye 239e4b86885SCheng Sean Ye for (i = 0; i < wk.nhdl; i++) 240e4b86885SCheng Sean Ye nvlist_free(cpus[i]); 241e4b86885SCheng Sean Ye kmem_free(cpus, sizeof (nvlist_t *) * wk.nhdl); 242e4b86885SCheng Sean Ye 243e4b86885SCheng Sean Ye if (err != 0) { 244e4b86885SCheng Sean Ye nvlist_free(nvl); 245e4b86885SCheng Sean Ye return (err); 246e4b86885SCheng Sean Ye } 247e4b86885SCheng Sean Ye 248e4b86885SCheng Sean Ye *onvlp = nvl; 249e4b86885SCheng Sean Ye return (0); 250e4b86885SCheng Sean Ye } 251e4b86885SCheng Sean Ye 252e4b86885SCheng Sean Ye int 253e4b86885SCheng Sean Ye fm_ioctl_cpu_retire(int cmd, nvlist_t *invl, nvlist_t **onvlp) 254e4b86885SCheng Sean Ye { 255e4b86885SCheng Sean Ye int32_t chipid, coreid, strandid; 256e4b86885SCheng Sean Ye int rc, new_status, old_status; 257e4b86885SCheng Sean Ye cmi_hdl_t hdl; 258e4b86885SCheng Sean Ye nvlist_t *nvl; 259e4b86885SCheng Sean Ye 260e4b86885SCheng Sean Ye switch (cmd) { 261e4b86885SCheng Sean Ye case FM_IOC_CPU_RETIRE: 262e4b86885SCheng Sean Ye new_status = P_FAULTED; 263e4b86885SCheng Sean Ye break; 264e4b86885SCheng Sean Ye case FM_IOC_CPU_STATUS: 265e4b86885SCheng Sean Ye new_status = P_STATUS; 266e4b86885SCheng Sean Ye break; 267e4b86885SCheng Sean Ye case FM_IOC_CPU_UNRETIRE: 268e4b86885SCheng Sean Ye new_status = P_ONLINE; 269e4b86885SCheng Sean Ye break; 270e4b86885SCheng Sean Ye default: 271e4b86885SCheng Sean Ye return (ENOTTY); 272e4b86885SCheng Sean Ye } 273e4b86885SCheng Sean Ye 274e4b86885SCheng Sean Ye if (nvlist_lookup_int32(invl, FM_CPU_RETIRE_CHIP_ID, &chipid) != 0 || 275e4b86885SCheng Sean Ye nvlist_lookup_int32(invl, FM_CPU_RETIRE_CORE_ID, &coreid) != 0 || 276e4b86885SCheng Sean Ye nvlist_lookup_int32(invl, FM_CPU_RETIRE_STRAND_ID, &strandid) != 0) 277e4b86885SCheng Sean Ye return (EINVAL); 278e4b86885SCheng Sean Ye 279e4b86885SCheng Sean Ye hdl = cmi_hdl_lookup(CMI_HDL_NEUTRAL, chipid, coreid, strandid); 280e4b86885SCheng Sean Ye if (hdl == NULL) 281e4b86885SCheng Sean Ye return (EINVAL); 282e4b86885SCheng Sean Ye 283e4b86885SCheng Sean Ye rc = cmi_hdl_online(hdl, new_status, &old_status); 284e4b86885SCheng Sean Ye cmi_hdl_rele(hdl); 285e4b86885SCheng Sean Ye 286e4b86885SCheng Sean Ye if (rc == 0) { 287e4b86885SCheng Sean Ye (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 288e4b86885SCheng Sean Ye (void) nvlist_add_int32(nvl, FM_CPU_RETIRE_OLDSTATUS, 289e4b86885SCheng Sean Ye old_status); 290e4b86885SCheng Sean Ye *onvlp = nvl; 291e4b86885SCheng Sean Ye } 292e4b86885SCheng Sean Ye 293e4b86885SCheng Sean Ye return (rc); 294e4b86885SCheng Sean Ye } 295074bb90dSTom Pothier 296074bb90dSTom Pothier /* 297074bb90dSTom Pothier * Retrun the value of x86gentopo_legacy variable as an nvpair. 298074bb90dSTom Pothier * 299074bb90dSTom Pothier * The caller is responsible for freeing the nvlist. 300074bb90dSTom Pothier */ 301074bb90dSTom Pothier /* ARGSUSED */ 302074bb90dSTom Pothier int 303074bb90dSTom Pothier fm_ioctl_gentopo_legacy(int cmd, nvlist_t *invl, nvlist_t **onvlp) 304074bb90dSTom Pothier { 305074bb90dSTom Pothier nvlist_t *nvl; 306074bb90dSTom Pothier 307074bb90dSTom Pothier if (cmd != FM_IOC_GENTOPO_LEGACY) { 308074bb90dSTom Pothier return (ENOTTY); 309074bb90dSTom Pothier } 310074bb90dSTom Pothier 311074bb90dSTom Pothier /* 312074bb90dSTom Pothier * Inform the caller of the intentions of the ereport generators to 313074bb90dSTom Pothier * generate either a "generic" or "legacy" x86 topology. 314074bb90dSTom Pothier */ 315074bb90dSTom Pothier 316074bb90dSTom Pothier (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 317074bb90dSTom Pothier (void) nvlist_add_int32(nvl, FM_GENTOPO_LEGACY, x86gentopo_legacy); 318074bb90dSTom Pothier *onvlp = nvl; 319074bb90dSTom Pothier 320074bb90dSTom Pothier return (0); 321074bb90dSTom Pothier } 322