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
fmd_fmri_nvl2str(nvlist_t * nvl,char * buf,size_t buflen)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
cpu_cpuid_present(uint32_t cpuid)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
cpu_get_serialid_kstat(uint32_t cpuid,uint64_t * serialidp)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
cpu_get_serialid_V1(uint32_t cpuid,char * serbuf,size_t len)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
cpu_get_serialid_V0(uint32_t cpuid,uint64_t * serialidp)1387aec1d6eScindi cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp)
139822fb41dStsien {
140822fb41dStsien return (cpu_get_serialid_kstat(cpuid, serialidp));
141822fb41dStsien }
142822fb41dStsien
143822fb41dStsien int
fmd_fmri_expand(nvlist_t * nvl)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
fmd_fmri_present(nvlist_t * nvl)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
fmd_fmri_replaced(nvlist_t * nvl)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
fmd_fmri_unusable(nvlist_t * nvl)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
fmd_fmri_contains(nvlist_t * er,nvlist_t * ee)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