1600Stsien /* 2600Stsien * CDDL HEADER START 3600Stsien * 4600Stsien * The contents of this file are subject to the terms of the 51606Ssaisai * Common Development and Distribution License (the "License"). 61606Ssaisai * You may not use this file except in compliance with the License. 7600Stsien * 8600Stsien * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9600Stsien * or http://www.opensolaris.org/os/licensing. 10600Stsien * See the License for the specific language governing permissions 11600Stsien * and limitations under the License. 12600Stsien * 13600Stsien * When distributing Covered Code, include this CDDL HEADER in each 14600Stsien * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15600Stsien * If applicable, add the following below this CDDL HEADER, with the 16600Stsien * fields enclosed by brackets "[]" replaced with your own identifying 17600Stsien * information: Portions Copyright [yyyy] [name of copyright owner] 18600Stsien * 19600Stsien * CDDL HEADER END 20600Stsien */ 211414Scindi 22600Stsien /* 236330Sjc25722 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24600Stsien * Use is subject to license terms. 25600Stsien */ 26600Stsien 27600Stsien #pragma ident "%Z%%M% %I% %E% SMI" 28600Stsien 29600Stsien #include <sys/types.h> 30600Stsien #include <sys/processor.h> 31600Stsien #include <fm/fmd_fmri.h> 323681Svn83148 #include <fm/libtopo.h> 33600Stsien 34600Stsien #include <strings.h> 35600Stsien #include <errno.h> 36600Stsien #include <kstat.h> 371414Scindi 386330Sjc25722 39600Stsien /* 40600Stsien * The scheme plugin for cpu FMRIs. 41600Stsien */ 42600Stsien 43600Stsien ssize_t 44600Stsien fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 45600Stsien { 461414Scindi int err; 47*7197Sstephh ssize_t len; 48*7197Sstephh topo_hdl_t *thp; 49*7197Sstephh char *str; 506330Sjc25722 51*7197Sstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 52*7197Sstephh return (fmd_fmri_set_errno(EINVAL)); 53*7197Sstephh if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) { 54*7197Sstephh fmd_fmri_topo_rele(thp); 551414Scindi return (fmd_fmri_set_errno(EINVAL)); 56*7197Sstephh } 57*7197Sstephh if (buf != NULL) 58*7197Sstephh len = snprintf(buf, buflen, "%s", str); 59*7197Sstephh else 60*7197Sstephh len = strlen(str); 61*7197Sstephh topo_hdl_strfree(thp, str); 62*7197Sstephh fmd_fmri_topo_rele(thp); 63*7197Sstephh return (len); 64600Stsien } 65600Stsien 663548Shueston /* 673548Shueston * Determine if a cpuid is present. 683548Shueston */ 693548Shueston /*ARGSUSED*/ 703548Shueston static int 713548Shueston cpu_cpuid_present(uint32_t cpuid) 723548Shueston { 733548Shueston #ifdef sparc 743548Shueston /* 753548Shueston * For SPARC, use kstats to see if the cpuid is present. 763548Shueston * Note that this may need to change for sun4v. 773548Shueston */ 783548Shueston kstat_ctl_t *kc; 793548Shueston kstat_t *ksp = NULL; 803548Shueston if ((kc = kstat_open()) == NULL) 813548Shueston return (-1); /* errno is set for us */ 823548Shueston ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL); 833548Shueston (void) kstat_close(kc); 843548Shueston return ((ksp == NULL) ? 0 : 1); 853548Shueston #else /* sparc */ 863548Shueston /* 873548Shueston * For x64, just return true. 883548Shueston */ 893548Shueston return (1); 903548Shueston #endif /* sparc */ 913548Shueston } 923548Shueston 93600Stsien static int 94600Stsien cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp) 95600Stsien { 96600Stsien kstat_named_t *kn; 97600Stsien kstat_ctl_t *kc; 98600Stsien kstat_t *ksp; 99600Stsien int i; 100600Stsien 1011414Scindi if ((kc = kstat_open()) == NULL) 102600Stsien return (-1); /* errno is set for us */ 103600Stsien 104600Stsien if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) { 105600Stsien (void) kstat_close(kc); 106600Stsien return (fmd_fmri_set_errno(ENOENT)); 107600Stsien } 108600Stsien 109600Stsien if (kstat_read(kc, ksp, NULL) == -1) { 110600Stsien int oserr = errno; 111600Stsien (void) kstat_close(kc); 112600Stsien return (fmd_fmri_set_errno(oserr)); 113600Stsien } 114600Stsien 115600Stsien for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { 116600Stsien if (strcmp(kn->name, "device_ID") == 0) { 117600Stsien *serialidp = kn->value.ui64; 118600Stsien (void) kstat_close(kc); 119600Stsien return (0); 120600Stsien } 121600Stsien } 122600Stsien 123600Stsien (void) kstat_close(kc); 124600Stsien return (fmd_fmri_set_errno(ENOENT)); 125600Stsien } 126600Stsien 127600Stsien static int 1281414Scindi cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len) 129600Stsien { 1301414Scindi int err; 1311414Scindi uint64_t serial = 0; 1321414Scindi 1333681Svn83148 err = cpu_get_serialid_kstat(cpuid, &serial); 1341414Scindi 1351414Scindi (void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial); 1361414Scindi return (err); 1371414Scindi } 1381414Scindi 1391414Scindi static int 1401414Scindi cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp) 1411414Scindi { 1423681Svn83148 return (cpu_get_serialid_kstat(cpuid, serialidp)); 143600Stsien } 144600Stsien 145600Stsien int 146600Stsien fmd_fmri_expand(nvlist_t *nvl) 147600Stsien { 148600Stsien uint8_t version; 149600Stsien uint32_t cpuid; 150600Stsien uint64_t serialid; 1511414Scindi char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 1523681Svn83148 int rc, err; 1534198Seschrock topo_hdl_t *thp; 154600Stsien 155600Stsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 156600Stsien nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 157600Stsien return (fmd_fmri_set_errno(EINVAL)); 158600Stsien 1593681Svn83148 /* 1603681Svn83148 * If the cpu-scheme topology exports this method expand(), invoke it. 1613681Svn83148 */ 1624198Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 1634198Seschrock return (fmd_fmri_set_errno(EINVAL)); 1644198Seschrock 1654198Seschrock rc = topo_fmri_expand(thp, nvl, &err); 1664198Seschrock fmd_fmri_topo_rele(thp); 1673681Svn83148 if (err != ETOPO_METHOD_NOTSUP) 1683681Svn83148 return (rc); 1693681Svn83148 1701414Scindi if (version == CPU_SCHEME_VERSION0) { 1711414Scindi if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 1721414Scindi &serialid)) != 0) { 1731414Scindi if (rc != ENOENT) 1741414Scindi return (fmd_fmri_set_errno(rc)); 1751414Scindi 1761414Scindi if (cpu_get_serialid_V0(cpuid, &serialid) != 0) 1771414Scindi return (-1); /* errno is set for us */ 178962Stsien 1791414Scindi if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 1801414Scindi serialid)) != 0) 1811414Scindi return (fmd_fmri_set_errno(rc)); 1823530Srb144127 } 1831414Scindi } else if (version == CPU_SCHEME_VERSION1) { 1841414Scindi if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 1851414Scindi &serstr)) != 0) { 1861414Scindi if (rc != ENOENT) 1871414Scindi return (fmd_fmri_set_errno(rc)); 188962Stsien 1891414Scindi if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0) 1901414Scindi return (0); /* Serial number is optional */ 1911414Scindi 1921414Scindi if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID, 1931414Scindi serbuf)) != 0) 1941414Scindi return (fmd_fmri_set_errno(rc)); 1951414Scindi } 1961414Scindi } else { 1971414Scindi return (fmd_fmri_set_errno(EINVAL)); 198962Stsien } 199600Stsien 200600Stsien return (0); 201600Stsien } 202600Stsien 203600Stsien int 204600Stsien fmd_fmri_present(nvlist_t *nvl) 205600Stsien { 2063681Svn83148 int rc, err; 207600Stsien uint8_t version; 208600Stsien uint32_t cpuid; 209600Stsien uint64_t nvlserid, curserid; 2101414Scindi char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 2114198Seschrock topo_hdl_t *thp; 212600Stsien 213600Stsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 2141414Scindi nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 215600Stsien return (fmd_fmri_set_errno(EINVAL)); 216600Stsien 2173681Svn83148 /* 2183681Svn83148 * If the cpu-scheme topology exports this method present(), invoke it. 2193681Svn83148 */ 2204198Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 2214198Seschrock return (fmd_fmri_set_errno(EINVAL)); 2224198Seschrock rc = topo_fmri_present(thp, nvl, &err); 2234198Seschrock fmd_fmri_topo_rele(thp); 2243681Svn83148 if (err != ETOPO_METHOD_NOTSUP) 2253681Svn83148 return (rc); 2263681Svn83148 2271414Scindi if (version == CPU_SCHEME_VERSION0) { 2281414Scindi if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 2291414Scindi &nvlserid) != 0) 2301414Scindi return (fmd_fmri_set_errno(EINVAL)); 2311414Scindi if (cpu_get_serialid_V0(cpuid, &curserid) != 0) 2321414Scindi return (errno == ENOENT ? 0 : -1); 2331414Scindi 2341414Scindi return (curserid == nvlserid); 235600Stsien 2361414Scindi } else if (version == CPU_SCHEME_VERSION1) { 2371414Scindi if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 2381414Scindi &nvlserstr)) != 0) 2391414Scindi if (rc != ENOENT) 2401414Scindi return (fmd_fmri_set_errno(EINVAL)); 2411414Scindi 2421414Scindi /* 2433548Shueston * If serial id is not available, just check if the cpuid 2443548Shueston * is present. 2451414Scindi */ 2461414Scindi if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0) 2473548Shueston return (cpu_cpuid_present(cpuid)); 2481414Scindi 2491414Scindi return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0); 2501414Scindi 2511414Scindi } else { 2521414Scindi return (fmd_fmri_set_errno(EINVAL)); 2531414Scindi } 254600Stsien } 255600Stsien 256600Stsien int 257600Stsien fmd_fmri_unusable(nvlist_t *nvl) 258600Stsien { 2596330Sjc25722 int rc, err = 0; 260600Stsien uint8_t version; 261600Stsien uint32_t cpuid; 2624198Seschrock topo_hdl_t *thp; 263600Stsien 264600Stsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 265600Stsien version > FM_CPU_SCHEME_VERSION || 266600Stsien nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 267600Stsien return (fmd_fmri_set_errno(EINVAL)); 2682072Svn83148 2693681Svn83148 /* 2703681Svn83148 * If the cpu-scheme topology exports this method unusable(), invoke it. 2713681Svn83148 */ 2724198Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 2734198Seschrock return (fmd_fmri_set_errno(EINVAL)); 2744198Seschrock rc = topo_fmri_unusable(thp, nvl, &err); 2754198Seschrock fmd_fmri_topo_rele(thp); 2763681Svn83148 if (err != ETOPO_METHOD_NOTSUP) 2773681Svn83148 return (rc); 278600Stsien 2793681Svn83148 return (p_online(cpuid, P_STATUS) == P_FAULTED); 280600Stsien } 2816330Sjc25722 int 2826330Sjc25722 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) 2836330Sjc25722 { 2846360Srobj int ret1, ret2; 2856330Sjc25722 char *erserstr, *eeserstr; 2866330Sjc25722 uint8_t ertype, eetype, erversion, eeversion; 2876330Sjc25722 uint64_t erserint, eeserint; 2886330Sjc25722 uint32_t erval, eeval; 2896330Sjc25722 size_t count; 2906330Sjc25722 2916330Sjc25722 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_ID, &erval) != 0) 2926330Sjc25722 return (0); 2936330Sjc25722 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_ID, &eeval) != 0) 2946330Sjc25722 return (0); 2956330Sjc25722 if (erval != eeval) 2966330Sjc25722 return (0); 2976330Sjc25722 2986330Sjc25722 if (nvlist_lookup_uint8(er, FM_VERSION, &erversion) != 0) 2996330Sjc25722 return (0); 3006330Sjc25722 3016330Sjc25722 if (nvlist_lookup_uint8(ee, FM_VERSION, &eeversion) != 0) 3026330Sjc25722 return (0); 3036330Sjc25722 3046330Sjc25722 if (erversion != eeversion) 3056330Sjc25722 return (0); 3066330Sjc25722 3076330Sjc25722 if (erversion == CPU_SCHEME_VERSION0) { 3086330Sjc25722 if (nvlist_lookup_uint64(er, FM_FMRI_CPU_SERIAL_ID, 3096330Sjc25722 &erserint) != 0) 3106330Sjc25722 return (0); 3116330Sjc25722 if (nvlist_lookup_uint64(ee, FM_FMRI_CPU_SERIAL_ID, 3126330Sjc25722 &eeserint) != 0) 3136330Sjc25722 return (0); 3146330Sjc25722 if (erserint != eeserint) 3156330Sjc25722 return (0); 3166330Sjc25722 } else if (erversion == CPU_SCHEME_VERSION1) { 3176330Sjc25722 /* Serial ID is an optional element */ 3186360Srobj if ((ret1 = nvlist_lookup_string(er, FM_FMRI_CPU_SERIAL_ID, 3196330Sjc25722 &erserstr)) != 0) 3206360Srobj if (ret1 != ENOENT) 3216330Sjc25722 return (0); 3226360Srobj if ((ret2 = nvlist_lookup_string(ee, FM_FMRI_CPU_SERIAL_ID, 3236330Sjc25722 &eeserstr)) != 0) 3246360Srobj if (ret2 != ENOENT) 3256330Sjc25722 return (0); 3266360Srobj if (ret1 == 0 && ret2 == 0) { 3276360Srobj count = strlen(erserstr); 3286360Srobj if (strncmp(erserstr, eeserstr, count) != 0) 3296360Srobj return (0); 3306360Srobj } 3316330Sjc25722 } 3326330Sjc25722 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_CACHE_INDEX, &erval) != 0) 3336330Sjc25722 return (0); 3346330Sjc25722 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_CACHE_INDEX, &eeval) != 0) 3356330Sjc25722 return (0); 3366330Sjc25722 3376330Sjc25722 if (erval != eeval) 3386330Sjc25722 return (0); 3396330Sjc25722 3406330Sjc25722 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_CACHE_WAY, &erval) != 0) 3416330Sjc25722 return (0); 3426330Sjc25722 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_CACHE_WAY, &eeval) != 0) 3436330Sjc25722 return (0); 3446330Sjc25722 3456330Sjc25722 if (erval != eeval) 3466330Sjc25722 return (0); 3476330Sjc25722 3486330Sjc25722 if (nvlist_lookup_uint8(er, FM_FMRI_CPU_CACHE_TYPE, &ertype) != 0) 3496330Sjc25722 return (0); 3506330Sjc25722 if (nvlist_lookup_uint8(ee, FM_FMRI_CPU_CACHE_TYPE, &eetype) != 0) 3516330Sjc25722 return (0); 3526330Sjc25722 3536330Sjc25722 if (eetype != ertype) 3546330Sjc25722 return (0); 3556330Sjc25722 3566330Sjc25722 return (1); 3576330Sjc25722 } 358