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; 477197Sstephh ssize_t len; 487197Sstephh topo_hdl_t *thp; 497197Sstephh char *str; 506330Sjc25722 517197Sstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 527197Sstephh return (fmd_fmri_set_errno(EINVAL)); 537197Sstephh if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) { 547197Sstephh fmd_fmri_topo_rele(thp); 551414Scindi return (fmd_fmri_set_errno(EINVAL)); 567197Sstephh } 577197Sstephh if (buf != NULL) 587197Sstephh len = snprintf(buf, buflen, "%s", str); 597197Sstephh else 607197Sstephh len = strlen(str); 617197Sstephh topo_hdl_strfree(thp, str); 627197Sstephh fmd_fmri_topo_rele(thp); 637197Sstephh 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 257*7275Sstephh fmd_fmri_replaced(nvlist_t *nvl) 258*7275Sstephh { 259*7275Sstephh int rc, err = 0; 260*7275Sstephh uint8_t version; 261*7275Sstephh uint32_t cpuid; 262*7275Sstephh uint64_t nvlserid, curserid; 263*7275Sstephh char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 264*7275Sstephh topo_hdl_t *thp; 265*7275Sstephh 266*7275Sstephh if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 267*7275Sstephh nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 268*7275Sstephh return (fmd_fmri_set_errno(EINVAL)); 269*7275Sstephh 270*7275Sstephh /* 271*7275Sstephh * If the cpu-scheme topology exports this method replaced(), invoke it. 272*7275Sstephh */ 273*7275Sstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 274*7275Sstephh return (fmd_fmri_set_errno(EINVAL)); 275*7275Sstephh rc = topo_fmri_replaced(thp, nvl, &err); 276*7275Sstephh fmd_fmri_topo_rele(thp); 277*7275Sstephh if (err != ETOPO_METHOD_NOTSUP) 278*7275Sstephh return (rc); 279*7275Sstephh 280*7275Sstephh if (version == CPU_SCHEME_VERSION0) { 281*7275Sstephh if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 282*7275Sstephh &nvlserid) != 0) 283*7275Sstephh return (fmd_fmri_set_errno(EINVAL)); 284*7275Sstephh if (cpu_get_serialid_V0(cpuid, &curserid) != 0) 285*7275Sstephh return (errno == ENOENT ? 286*7275Sstephh FMD_OBJ_STATE_NOT_PRESENT : -1); 287*7275Sstephh 288*7275Sstephh return (curserid == nvlserid ? FMD_OBJ_STATE_STILL_PRESENT : 289*7275Sstephh FMD_OBJ_STATE_REPLACED); 290*7275Sstephh 291*7275Sstephh } else if (version == CPU_SCHEME_VERSION1) { 292*7275Sstephh if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 293*7275Sstephh &nvlserstr)) != 0) 294*7275Sstephh if (rc != ENOENT) 295*7275Sstephh return (fmd_fmri_set_errno(EINVAL)); 296*7275Sstephh 297*7275Sstephh /* 298*7275Sstephh * If serial id is not available, just check if the cpuid 299*7275Sstephh * is present. 300*7275Sstephh */ 301*7275Sstephh if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0) 302*7275Sstephh if (cpu_cpuid_present(cpuid)) 303*7275Sstephh return (FMD_OBJ_STATE_UNKNOWN); 304*7275Sstephh else 305*7275Sstephh return (FMD_OBJ_STATE_NOT_PRESENT); 306*7275Sstephh 307*7275Sstephh return (strcmp(curserbuf, nvlserstr) == 0 ? 308*7275Sstephh FMD_OBJ_STATE_STILL_PRESENT : FMD_OBJ_STATE_REPLACED); 309*7275Sstephh 310*7275Sstephh } else { 311*7275Sstephh return (fmd_fmri_set_errno(EINVAL)); 312*7275Sstephh } 313*7275Sstephh } 314*7275Sstephh 315*7275Sstephh int 316600Stsien fmd_fmri_unusable(nvlist_t *nvl) 317600Stsien { 3186330Sjc25722 int rc, err = 0; 319600Stsien uint8_t version; 320600Stsien uint32_t cpuid; 3214198Seschrock topo_hdl_t *thp; 322600Stsien 323600Stsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 324600Stsien version > FM_CPU_SCHEME_VERSION || 325600Stsien nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 326600Stsien return (fmd_fmri_set_errno(EINVAL)); 3272072Svn83148 3283681Svn83148 /* 3293681Svn83148 * If the cpu-scheme topology exports this method unusable(), invoke it. 3303681Svn83148 */ 3314198Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 3324198Seschrock return (fmd_fmri_set_errno(EINVAL)); 3334198Seschrock rc = topo_fmri_unusable(thp, nvl, &err); 3344198Seschrock fmd_fmri_topo_rele(thp); 3353681Svn83148 if (err != ETOPO_METHOD_NOTSUP) 3363681Svn83148 return (rc); 337600Stsien 3383681Svn83148 return (p_online(cpuid, P_STATUS) == P_FAULTED); 339600Stsien } 3406330Sjc25722 int 3416330Sjc25722 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) 3426330Sjc25722 { 3436360Srobj int ret1, ret2; 3446330Sjc25722 char *erserstr, *eeserstr; 3456330Sjc25722 uint8_t ertype, eetype, erversion, eeversion; 3466330Sjc25722 uint64_t erserint, eeserint; 3476330Sjc25722 uint32_t erval, eeval; 3486330Sjc25722 size_t count; 3496330Sjc25722 3506330Sjc25722 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_ID, &erval) != 0) 3516330Sjc25722 return (0); 3526330Sjc25722 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_ID, &eeval) != 0) 3536330Sjc25722 return (0); 3546330Sjc25722 if (erval != eeval) 3556330Sjc25722 return (0); 3566330Sjc25722 3576330Sjc25722 if (nvlist_lookup_uint8(er, FM_VERSION, &erversion) != 0) 3586330Sjc25722 return (0); 3596330Sjc25722 3606330Sjc25722 if (nvlist_lookup_uint8(ee, FM_VERSION, &eeversion) != 0) 3616330Sjc25722 return (0); 3626330Sjc25722 3636330Sjc25722 if (erversion != eeversion) 3646330Sjc25722 return (0); 3656330Sjc25722 3666330Sjc25722 if (erversion == CPU_SCHEME_VERSION0) { 3676330Sjc25722 if (nvlist_lookup_uint64(er, FM_FMRI_CPU_SERIAL_ID, 3686330Sjc25722 &erserint) != 0) 3696330Sjc25722 return (0); 3706330Sjc25722 if (nvlist_lookup_uint64(ee, FM_FMRI_CPU_SERIAL_ID, 3716330Sjc25722 &eeserint) != 0) 3726330Sjc25722 return (0); 3736330Sjc25722 if (erserint != eeserint) 3746330Sjc25722 return (0); 3756330Sjc25722 } else if (erversion == CPU_SCHEME_VERSION1) { 3766330Sjc25722 /* Serial ID is an optional element */ 3776360Srobj if ((ret1 = nvlist_lookup_string(er, FM_FMRI_CPU_SERIAL_ID, 3786330Sjc25722 &erserstr)) != 0) 3796360Srobj if (ret1 != ENOENT) 3806330Sjc25722 return (0); 3816360Srobj if ((ret2 = nvlist_lookup_string(ee, FM_FMRI_CPU_SERIAL_ID, 3826330Sjc25722 &eeserstr)) != 0) 3836360Srobj if (ret2 != ENOENT) 3846330Sjc25722 return (0); 3856360Srobj if (ret1 == 0 && ret2 == 0) { 3866360Srobj count = strlen(erserstr); 3876360Srobj if (strncmp(erserstr, eeserstr, count) != 0) 3886360Srobj return (0); 3896360Srobj } 3906330Sjc25722 } 3916330Sjc25722 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_CACHE_INDEX, &erval) != 0) 3926330Sjc25722 return (0); 3936330Sjc25722 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_CACHE_INDEX, &eeval) != 0) 3946330Sjc25722 return (0); 3956330Sjc25722 3966330Sjc25722 if (erval != eeval) 3976330Sjc25722 return (0); 3986330Sjc25722 3996330Sjc25722 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_CACHE_WAY, &erval) != 0) 4006330Sjc25722 return (0); 4016330Sjc25722 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_CACHE_WAY, &eeval) != 0) 4026330Sjc25722 return (0); 4036330Sjc25722 4046330Sjc25722 if (erval != eeval) 4056330Sjc25722 return (0); 4066330Sjc25722 4076330Sjc25722 if (nvlist_lookup_uint8(er, FM_FMRI_CPU_CACHE_TYPE, &ertype) != 0) 4086330Sjc25722 return (0); 4096330Sjc25722 if (nvlist_lookup_uint8(ee, FM_FMRI_CPU_CACHE_TYPE, &eetype) != 0) 4106330Sjc25722 return (0); 4116330Sjc25722 4126330Sjc25722 if (eetype != ertype) 4136330Sjc25722 return (0); 4146330Sjc25722 4156330Sjc25722 return (1); 4166330Sjc25722 } 417