1822fb41dStsien /* 2822fb41dStsien * CDDL HEADER START 3822fb41dStsien * 4822fb41dStsien * The contents of this file are subject to the terms of the 57a53f9f8Ssaisai * Common Development and Distribution License (the "License"). 67a53f9f8Ssaisai * You may not use this file except in compliance with the License. 7822fb41dStsien * 8822fb41dStsien * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9822fb41dStsien * or http://www.opensolaris.org/os/licensing. 10822fb41dStsien * See the License for the specific language governing permissions 11822fb41dStsien * and limitations under the License. 12822fb41dStsien * 13822fb41dStsien * When distributing Covered Code, include this CDDL HEADER in each 14822fb41dStsien * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15822fb41dStsien * If applicable, add the following below this CDDL HEADER, with the 16822fb41dStsien * fields enclosed by brackets "[]" replaced with your own identifying 17822fb41dStsien * information: Portions Copyright [yyyy] [name of copyright owner] 18822fb41dStsien * 19822fb41dStsien * CDDL HEADER END 20822fb41dStsien */ 217aec1d6eScindi 22822fb41dStsien /* 23*a62774dfSSinanallur Balasubramanian * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24822fb41dStsien * Use is subject to license terms. 25822fb41dStsien */ 26822fb41dStsien 27822fb41dStsien #include <sys/types.h> 28822fb41dStsien #include <sys/processor.h> 29822fb41dStsien #include <fm/fmd_fmri.h> 30dd566498Svn83148 #include <fm/libtopo.h> 31822fb41dStsien 32822fb41dStsien #include <strings.h> 33822fb41dStsien #include <errno.h> 34822fb41dStsien #include <kstat.h> 357aec1d6eScindi 367bebe46cSjc25722 37822fb41dStsien /* 38822fb41dStsien * The scheme plugin for cpu FMRIs. 39822fb41dStsien */ 40822fb41dStsien 41822fb41dStsien ssize_t 42822fb41dStsien fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 43822fb41dStsien { 447aec1d6eScindi int err; 45b7d3956bSstephh ssize_t len; 46b7d3956bSstephh topo_hdl_t *thp; 47b7d3956bSstephh char *str; 48822fb41dStsien 49b7d3956bSstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 50822fb41dStsien return (fmd_fmri_set_errno(EINVAL)); 51b7d3956bSstephh if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) { 52b7d3956bSstephh fmd_fmri_topo_rele(thp); 537aec1d6eScindi return (fmd_fmri_set_errno(EINVAL)); 547aec1d6eScindi } 55b7d3956bSstephh if (buf != NULL) 56b7d3956bSstephh len = snprintf(buf, buflen, "%s", str); 57b7d3956bSstephh else 58b7d3956bSstephh len = strlen(str); 59b7d3956bSstephh topo_hdl_strfree(thp, str); 60b7d3956bSstephh fmd_fmri_topo_rele(thp); 61b7d3956bSstephh return (len); 62822fb41dStsien } 63822fb41dStsien 649ef59e77Shueston /* 659ef59e77Shueston * Determine if a cpuid is present. 669ef59e77Shueston */ 679ef59e77Shueston /*ARGSUSED*/ 689ef59e77Shueston static int 699ef59e77Shueston cpu_cpuid_present(uint32_t cpuid) 709ef59e77Shueston { 719ef59e77Shueston #ifdef sparc 729ef59e77Shueston /* 739ef59e77Shueston * For SPARC, use kstats to see if the cpuid is present. 749ef59e77Shueston * Note that this may need to change for sun4v. 759ef59e77Shueston */ 769ef59e77Shueston kstat_ctl_t *kc; 779ef59e77Shueston kstat_t *ksp = NULL; 789ef59e77Shueston if ((kc = kstat_open()) == NULL) 799ef59e77Shueston return (-1); /* errno is set for us */ 809ef59e77Shueston ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL); 819ef59e77Shueston (void) kstat_close(kc); 829ef59e77Shueston return ((ksp == NULL) ? 0 : 1); 839ef59e77Shueston #else /* sparc */ 849ef59e77Shueston /* 859ef59e77Shueston * For x64, just return true. 869ef59e77Shueston */ 879ef59e77Shueston return (1); 889ef59e77Shueston #endif /* sparc */ 899ef59e77Shueston } 909ef59e77Shueston 91822fb41dStsien static int 92822fb41dStsien cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp) 93822fb41dStsien { 94822fb41dStsien kstat_named_t *kn; 95822fb41dStsien kstat_ctl_t *kc; 96822fb41dStsien kstat_t *ksp; 97822fb41dStsien int i; 98822fb41dStsien 997aec1d6eScindi if ((kc = kstat_open()) == NULL) 100822fb41dStsien return (-1); /* errno is set for us */ 101822fb41dStsien 102822fb41dStsien if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) { 103822fb41dStsien (void) kstat_close(kc); 104822fb41dStsien return (fmd_fmri_set_errno(ENOENT)); 105822fb41dStsien } 106822fb41dStsien 107822fb41dStsien if (kstat_read(kc, ksp, NULL) == -1) { 108822fb41dStsien int oserr = errno; 109822fb41dStsien (void) kstat_close(kc); 110822fb41dStsien return (fmd_fmri_set_errno(oserr)); 111822fb41dStsien } 112822fb41dStsien 113822fb41dStsien for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { 114822fb41dStsien if (strcmp(kn->name, "device_ID") == 0) { 115822fb41dStsien *serialidp = kn->value.ui64; 116822fb41dStsien (void) kstat_close(kc); 117822fb41dStsien return (0); 118822fb41dStsien } 119822fb41dStsien } 120822fb41dStsien 121822fb41dStsien (void) kstat_close(kc); 122822fb41dStsien return (fmd_fmri_set_errno(ENOENT)); 123822fb41dStsien } 124822fb41dStsien 125822fb41dStsien static int 1267aec1d6eScindi cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len) 1277aec1d6eScindi { 1287aec1d6eScindi int err; 1297aec1d6eScindi uint64_t serial = 0; 1307aec1d6eScindi 1317aec1d6eScindi err = cpu_get_serialid_kstat(cpuid, &serial); 1327aec1d6eScindi 1337aec1d6eScindi (void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial); 1347aec1d6eScindi return (err); 1357aec1d6eScindi } 1367aec1d6eScindi 1377aec1d6eScindi static int 1387aec1d6eScindi cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp) 139822fb41dStsien { 140822fb41dStsien return (cpu_get_serialid_kstat(cpuid, serialidp)); 141822fb41dStsien } 142822fb41dStsien 143822fb41dStsien int 144822fb41dStsien fmd_fmri_expand(nvlist_t *nvl) 145822fb41dStsien { 146822fb41dStsien uint8_t version; 147822fb41dStsien uint32_t cpuid; 148822fb41dStsien uint64_t serialid; 1497aec1d6eScindi char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 150dd566498Svn83148 int rc, err; 15124db4641Seschrock topo_hdl_t *thp; 152822fb41dStsien 153822fb41dStsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 154822fb41dStsien nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 155822fb41dStsien return (fmd_fmri_set_errno(EINVAL)); 156822fb41dStsien 157dd566498Svn83148 /* 158dd566498Svn83148 * If the cpu-scheme topology exports this method expand(), invoke it. 159dd566498Svn83148 */ 16024db4641Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 16124db4641Seschrock return (fmd_fmri_set_errno(EINVAL)); 16224db4641Seschrock 16324db4641Seschrock rc = topo_fmri_expand(thp, nvl, &err); 16424db4641Seschrock fmd_fmri_topo_rele(thp); 165dd566498Svn83148 if (err != ETOPO_METHOD_NOTSUP) 166dd566498Svn83148 return (rc); 167dd566498Svn83148 1687aec1d6eScindi if (version == CPU_SCHEME_VERSION0) { 169822fb41dStsien if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 1706dfee483Stsien &serialid)) != 0) { 1716dfee483Stsien if (rc != ENOENT) 172822fb41dStsien return (fmd_fmri_set_errno(rc)); 173822fb41dStsien 1747aec1d6eScindi if (cpu_get_serialid_V0(cpuid, &serialid) != 0) 175822fb41dStsien return (-1); /* errno is set for us */ 176822fb41dStsien 1776dfee483Stsien if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 1786dfee483Stsien serialid)) != 0) 179822fb41dStsien return (fmd_fmri_set_errno(rc)); 180ef884685Srb144127 } 1817aec1d6eScindi } else if (version == CPU_SCHEME_VERSION1) { 1827aec1d6eScindi if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 1837aec1d6eScindi &serstr)) != 0) { 1847aec1d6eScindi if (rc != ENOENT) 1857aec1d6eScindi return (fmd_fmri_set_errno(rc)); 1867aec1d6eScindi 1877aec1d6eScindi if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0) 1887aec1d6eScindi return (0); /* Serial number is optional */ 1897aec1d6eScindi 1907aec1d6eScindi if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID, 1917aec1d6eScindi serbuf)) != 0) 1927aec1d6eScindi return (fmd_fmri_set_errno(rc)); 1937aec1d6eScindi } 1947aec1d6eScindi } else { 1957aec1d6eScindi return (fmd_fmri_set_errno(EINVAL)); 1967aec1d6eScindi } 1976dfee483Stsien 198822fb41dStsien return (0); 199822fb41dStsien } 200822fb41dStsien 201822fb41dStsien int 202822fb41dStsien fmd_fmri_present(nvlist_t *nvl) 203822fb41dStsien { 204dd566498Svn83148 int rc, err; 205822fb41dStsien uint8_t version; 206822fb41dStsien uint32_t cpuid; 207822fb41dStsien uint64_t nvlserid, curserid; 2087aec1d6eScindi char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 20924db4641Seschrock topo_hdl_t *thp; 210822fb41dStsien 211822fb41dStsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 2127aec1d6eScindi nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 213822fb41dStsien return (fmd_fmri_set_errno(EINVAL)); 214822fb41dStsien 215dd566498Svn83148 /* 216dd566498Svn83148 * If the cpu-scheme topology exports this method present(), invoke it. 217dd566498Svn83148 */ 21824db4641Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 21924db4641Seschrock return (fmd_fmri_set_errno(EINVAL)); 22024db4641Seschrock rc = topo_fmri_present(thp, nvl, &err); 22124db4641Seschrock fmd_fmri_topo_rele(thp); 222dd566498Svn83148 if (err != ETOPO_METHOD_NOTSUP) 223dd566498Svn83148 return (rc); 224dd566498Svn83148 2257aec1d6eScindi if (version == CPU_SCHEME_VERSION0) { 2267aec1d6eScindi if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 2277aec1d6eScindi &nvlserid) != 0) 2287aec1d6eScindi return (fmd_fmri_set_errno(EINVAL)); 2297aec1d6eScindi if (cpu_get_serialid_V0(cpuid, &curserid) != 0) 230822fb41dStsien return (errno == ENOENT ? 0 : -1); 231822fb41dStsien 232822fb41dStsien return (curserid == nvlserid); 2337aec1d6eScindi 2347aec1d6eScindi } else if (version == CPU_SCHEME_VERSION1) { 2357aec1d6eScindi if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 2367aec1d6eScindi &nvlserstr)) != 0) 2377aec1d6eScindi if (rc != ENOENT) 2387aec1d6eScindi return (fmd_fmri_set_errno(EINVAL)); 2397aec1d6eScindi 2407aec1d6eScindi /* 2419ef59e77Shueston * If serial id is not available, just check if the cpuid 2429ef59e77Shueston * is present. 2437aec1d6eScindi */ 2447aec1d6eScindi if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0) 2459ef59e77Shueston return (cpu_cpuid_present(cpuid)); 2467aec1d6eScindi 2477aec1d6eScindi return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0); 2487aec1d6eScindi 2497aec1d6eScindi } else { 2507aec1d6eScindi return (fmd_fmri_set_errno(EINVAL)); 2517aec1d6eScindi } 252822fb41dStsien } 253822fb41dStsien 254822fb41dStsien int 25525c6ff4bSstephh fmd_fmri_replaced(nvlist_t *nvl) 25625c6ff4bSstephh { 25725c6ff4bSstephh int rc, err = 0; 25825c6ff4bSstephh uint8_t version; 25925c6ff4bSstephh uint32_t cpuid; 26025c6ff4bSstephh uint64_t nvlserid, curserid; 26125c6ff4bSstephh char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 26225c6ff4bSstephh topo_hdl_t *thp; 26325c6ff4bSstephh 26425c6ff4bSstephh if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 26525c6ff4bSstephh nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 26625c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL)); 26725c6ff4bSstephh 26825c6ff4bSstephh /* 26925c6ff4bSstephh * If the cpu-scheme topology exports this method replaced(), invoke it. 27025c6ff4bSstephh */ 27125c6ff4bSstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 27225c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL)); 27325c6ff4bSstephh rc = topo_fmri_replaced(thp, nvl, &err); 27425c6ff4bSstephh fmd_fmri_topo_rele(thp); 27525c6ff4bSstephh if (err != ETOPO_METHOD_NOTSUP) 27625c6ff4bSstephh return (rc); 27725c6ff4bSstephh 27825c6ff4bSstephh if (version == CPU_SCHEME_VERSION0) { 27925c6ff4bSstephh if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 28025c6ff4bSstephh &nvlserid) != 0) 28125c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL)); 28225c6ff4bSstephh if (cpu_get_serialid_V0(cpuid, &curserid) != 0) 28325c6ff4bSstephh return (errno == ENOENT ? 28425c6ff4bSstephh FMD_OBJ_STATE_NOT_PRESENT : -1); 28525c6ff4bSstephh 28625c6ff4bSstephh return (curserid == nvlserid ? FMD_OBJ_STATE_STILL_PRESENT : 28725c6ff4bSstephh FMD_OBJ_STATE_REPLACED); 28825c6ff4bSstephh 28925c6ff4bSstephh } else if (version == CPU_SCHEME_VERSION1) { 29025c6ff4bSstephh if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 29125c6ff4bSstephh &nvlserstr)) != 0) 29225c6ff4bSstephh if (rc != ENOENT) 29325c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL)); 29425c6ff4bSstephh 29525c6ff4bSstephh /* 29625c6ff4bSstephh * If serial id is not available, just check if the cpuid 29725c6ff4bSstephh * is present. 29825c6ff4bSstephh */ 29925c6ff4bSstephh if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0) 30025c6ff4bSstephh if (cpu_cpuid_present(cpuid)) 30125c6ff4bSstephh return (FMD_OBJ_STATE_UNKNOWN); 30225c6ff4bSstephh else 30325c6ff4bSstephh return (FMD_OBJ_STATE_NOT_PRESENT); 30425c6ff4bSstephh 30525c6ff4bSstephh return (strcmp(curserbuf, nvlserstr) == 0 ? 30625c6ff4bSstephh FMD_OBJ_STATE_STILL_PRESENT : FMD_OBJ_STATE_REPLACED); 30725c6ff4bSstephh 30825c6ff4bSstephh } else { 30925c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL)); 31025c6ff4bSstephh } 31125c6ff4bSstephh } 31225c6ff4bSstephh 31325c6ff4bSstephh int 314822fb41dStsien fmd_fmri_unusable(nvlist_t *nvl) 315822fb41dStsien { 3167bebe46cSjc25722 int rc, err = 0; 317822fb41dStsien uint8_t version; 318822fb41dStsien uint32_t cpuid; 31924db4641Seschrock topo_hdl_t *thp; 320822fb41dStsien 321822fb41dStsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 322822fb41dStsien version > FM_CPU_SCHEME_VERSION || 323822fb41dStsien nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 324822fb41dStsien return (fmd_fmri_set_errno(EINVAL)); 32531e37bb4Svn83148 326dd566498Svn83148 /* 327dd566498Svn83148 * If the cpu-scheme topology exports this method unusable(), invoke it. 328dd566498Svn83148 */ 32924db4641Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 33024db4641Seschrock return (fmd_fmri_set_errno(EINVAL)); 33124db4641Seschrock rc = topo_fmri_unusable(thp, nvl, &err); 33224db4641Seschrock fmd_fmri_topo_rele(thp); 333dd566498Svn83148 if (err != ETOPO_METHOD_NOTSUP) 334dd566498Svn83148 return (rc); 3356dfee483Stsien 336535ec645Sdduvall return (p_online(cpuid, P_STATUS) == P_FAULTED); 337535ec645Sdduvall } 3387bebe46cSjc25722 int 3397bebe46cSjc25722 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) 3407bebe46cSjc25722 { 341918a0d8aSrobj int ret1, ret2; 3427bebe46cSjc25722 char *erserstr, *eeserstr; 343*a62774dfSSinanallur Balasubramanian uint8_t erversion, eeversion; 3447bebe46cSjc25722 uint64_t erserint, eeserint; 3457bebe46cSjc25722 uint32_t erval, eeval; 3467bebe46cSjc25722 3477bebe46cSjc25722 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_ID, &erval) != 0) 3487bebe46cSjc25722 return (0); 3497bebe46cSjc25722 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_ID, &eeval) != 0) 3507bebe46cSjc25722 return (0); 3517bebe46cSjc25722 if (erval != eeval) 3527bebe46cSjc25722 return (0); 3537bebe46cSjc25722 3547bebe46cSjc25722 if (nvlist_lookup_uint8(er, FM_VERSION, &erversion) != 0) 3557bebe46cSjc25722 return (0); 3567bebe46cSjc25722 3577bebe46cSjc25722 if (nvlist_lookup_uint8(ee, FM_VERSION, &eeversion) != 0) 3587bebe46cSjc25722 return (0); 3597bebe46cSjc25722 3607bebe46cSjc25722 if (erversion != eeversion) 3617bebe46cSjc25722 return (0); 3627bebe46cSjc25722 3637bebe46cSjc25722 if (erversion == CPU_SCHEME_VERSION0) { 3647bebe46cSjc25722 if (nvlist_lookup_uint64(er, FM_FMRI_CPU_SERIAL_ID, 3657bebe46cSjc25722 &erserint) != 0) 3667bebe46cSjc25722 return (0); 3677bebe46cSjc25722 if (nvlist_lookup_uint64(ee, FM_FMRI_CPU_SERIAL_ID, 3687bebe46cSjc25722 &eeserint) != 0) 3697bebe46cSjc25722 return (0); 3707bebe46cSjc25722 if (erserint != eeserint) 3717bebe46cSjc25722 return (0); 3727bebe46cSjc25722 } else if (erversion == CPU_SCHEME_VERSION1) { 3737bebe46cSjc25722 /* Serial ID is an optional element */ 374*a62774dfSSinanallur Balasubramanian ret1 = nvlist_lookup_string(er, FM_FMRI_CPU_SERIAL_ID, 375*a62774dfSSinanallur Balasubramanian &erserstr); 376*a62774dfSSinanallur Balasubramanian ret2 = nvlist_lookup_string(ee, FM_FMRI_CPU_SERIAL_ID, 377*a62774dfSSinanallur Balasubramanian &eeserstr); 378*a62774dfSSinanallur Balasubramanian if (ret1 != ret2) 3797bebe46cSjc25722 return (0); 380*a62774dfSSinanallur Balasubramanian if (ret1 == ENOENT) 381*a62774dfSSinanallur Balasubramanian /* 382*a62774dfSSinanallur Balasubramanian * Serial IDs not found in both container, containee 383*a62774dfSSinanallur Balasubramanian */ 384*a62774dfSSinanallur Balasubramanian return (1); 385*a62774dfSSinanallur Balasubramanian if (ret1 != 0) 3867bebe46cSjc25722 return (0); 387*a62774dfSSinanallur Balasubramanian /* 388*a62774dfSSinanallur Balasubramanian * Found Serial Ids in both container and containee. 389*a62774dfSSinanallur Balasubramanian * Check if they are same. 390*a62774dfSSinanallur Balasubramanian */ 391*a62774dfSSinanallur Balasubramanian if (strlen(erserstr) != strlen(eeserstr)) 392*a62774dfSSinanallur Balasubramanian return (0); 393*a62774dfSSinanallur Balasubramanian if (strcmp(erserstr, eeserstr) != 0) 3947bebe46cSjc25722 return (0); 3957bebe46cSjc25722 } 3967bebe46cSjc25722 return (1); 3977bebe46cSjc25722 } 398