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 /*
23*10784Ssinanallur.balasubramanian@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24600Stsien * Use is subject to license terms.
25600Stsien */
26600Stsien
27600Stsien #include <sys/types.h>
28600Stsien #include <sys/processor.h>
29600Stsien #include <fm/fmd_fmri.h>
303681Svn83148 #include <fm/libtopo.h>
31600Stsien
32600Stsien #include <strings.h>
33600Stsien #include <errno.h>
34600Stsien #include <kstat.h>
351414Scindi
366330Sjc25722
37600Stsien /*
38600Stsien * The scheme plugin for cpu FMRIs.
39600Stsien */
40600Stsien
41600Stsien ssize_t
fmd_fmri_nvl2str(nvlist_t * nvl,char * buf,size_t buflen)42600Stsien fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
43600Stsien {
441414Scindi int err;
457197Sstephh ssize_t len;
467197Sstephh topo_hdl_t *thp;
477197Sstephh char *str;
486330Sjc25722
497197Sstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
507197Sstephh return (fmd_fmri_set_errno(EINVAL));
517197Sstephh if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) {
527197Sstephh fmd_fmri_topo_rele(thp);
531414Scindi return (fmd_fmri_set_errno(EINVAL));
547197Sstephh }
557197Sstephh if (buf != NULL)
567197Sstephh len = snprintf(buf, buflen, "%s", str);
577197Sstephh else
587197Sstephh len = strlen(str);
597197Sstephh topo_hdl_strfree(thp, str);
607197Sstephh fmd_fmri_topo_rele(thp);
617197Sstephh return (len);
62600Stsien }
63600Stsien
643548Shueston /*
653548Shueston * Determine if a cpuid is present.
663548Shueston */
673548Shueston /*ARGSUSED*/
683548Shueston static int
cpu_cpuid_present(uint32_t cpuid)693548Shueston cpu_cpuid_present(uint32_t cpuid)
703548Shueston {
713548Shueston #ifdef sparc
723548Shueston /*
733548Shueston * For SPARC, use kstats to see if the cpuid is present.
743548Shueston * Note that this may need to change for sun4v.
753548Shueston */
763548Shueston kstat_ctl_t *kc;
773548Shueston kstat_t *ksp = NULL;
783548Shueston if ((kc = kstat_open()) == NULL)
793548Shueston return (-1); /* errno is set for us */
803548Shueston ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL);
813548Shueston (void) kstat_close(kc);
823548Shueston return ((ksp == NULL) ? 0 : 1);
833548Shueston #else /* sparc */
843548Shueston /*
853548Shueston * For x64, just return true.
863548Shueston */
873548Shueston return (1);
883548Shueston #endif /* sparc */
893548Shueston }
903548Shueston
91600Stsien static int
cpu_get_serialid_kstat(uint32_t cpuid,uint64_t * serialidp)92600Stsien cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp)
93600Stsien {
94600Stsien kstat_named_t *kn;
95600Stsien kstat_ctl_t *kc;
96600Stsien kstat_t *ksp;
97600Stsien int i;
98600Stsien
991414Scindi if ((kc = kstat_open()) == NULL)
100600Stsien return (-1); /* errno is set for us */
101600Stsien
102600Stsien if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) {
103600Stsien (void) kstat_close(kc);
104600Stsien return (fmd_fmri_set_errno(ENOENT));
105600Stsien }
106600Stsien
107600Stsien if (kstat_read(kc, ksp, NULL) == -1) {
108600Stsien int oserr = errno;
109600Stsien (void) kstat_close(kc);
110600Stsien return (fmd_fmri_set_errno(oserr));
111600Stsien }
112600Stsien
113600Stsien for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) {
114600Stsien if (strcmp(kn->name, "device_ID") == 0) {
115600Stsien *serialidp = kn->value.ui64;
116600Stsien (void) kstat_close(kc);
117600Stsien return (0);
118600Stsien }
119600Stsien }
120600Stsien
121600Stsien (void) kstat_close(kc);
122600Stsien return (fmd_fmri_set_errno(ENOENT));
123600Stsien }
124600Stsien
125600Stsien static int
cpu_get_serialid_V1(uint32_t cpuid,char * serbuf,size_t len)1261414Scindi cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len)
127600Stsien {
1281414Scindi int err;
1291414Scindi uint64_t serial = 0;
1301414Scindi
1313681Svn83148 err = cpu_get_serialid_kstat(cpuid, &serial);
1321414Scindi
1331414Scindi (void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial);
1341414Scindi return (err);
1351414Scindi }
1361414Scindi
1371414Scindi static int
cpu_get_serialid_V0(uint32_t cpuid,uint64_t * serialidp)1381414Scindi cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp)
1391414Scindi {
1403681Svn83148 return (cpu_get_serialid_kstat(cpuid, serialidp));
141600Stsien }
142600Stsien
143600Stsien int
fmd_fmri_expand(nvlist_t * nvl)144600Stsien fmd_fmri_expand(nvlist_t *nvl)
145600Stsien {
146600Stsien uint8_t version;
147600Stsien uint32_t cpuid;
148600Stsien uint64_t serialid;
1491414Scindi char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
1503681Svn83148 int rc, err;
1514198Seschrock topo_hdl_t *thp;
152600Stsien
153600Stsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
154600Stsien nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
155600Stsien return (fmd_fmri_set_errno(EINVAL));
156600Stsien
1573681Svn83148 /*
1583681Svn83148 * If the cpu-scheme topology exports this method expand(), invoke it.
1593681Svn83148 */
1604198Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
1614198Seschrock return (fmd_fmri_set_errno(EINVAL));
1624198Seschrock
1634198Seschrock rc = topo_fmri_expand(thp, nvl, &err);
1644198Seschrock fmd_fmri_topo_rele(thp);
1653681Svn83148 if (err != ETOPO_METHOD_NOTSUP)
1663681Svn83148 return (rc);
1673681Svn83148
1681414Scindi if (version == CPU_SCHEME_VERSION0) {
1691414Scindi if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
1701414Scindi &serialid)) != 0) {
1711414Scindi if (rc != ENOENT)
1721414Scindi return (fmd_fmri_set_errno(rc));
1731414Scindi
1741414Scindi if (cpu_get_serialid_V0(cpuid, &serialid) != 0)
1751414Scindi return (-1); /* errno is set for us */
176962Stsien
1771414Scindi if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
1781414Scindi serialid)) != 0)
1791414Scindi return (fmd_fmri_set_errno(rc));
1803530Srb144127 }
1811414Scindi } else if (version == CPU_SCHEME_VERSION1) {
1821414Scindi if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
1831414Scindi &serstr)) != 0) {
1841414Scindi if (rc != ENOENT)
1851414Scindi return (fmd_fmri_set_errno(rc));
186962Stsien
1871414Scindi if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0)
1881414Scindi return (0); /* Serial number is optional */
1891414Scindi
1901414Scindi if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID,
1911414Scindi serbuf)) != 0)
1921414Scindi return (fmd_fmri_set_errno(rc));
1931414Scindi }
1941414Scindi } else {
1951414Scindi return (fmd_fmri_set_errno(EINVAL));
196962Stsien }
197600Stsien
198600Stsien return (0);
199600Stsien }
200600Stsien
201600Stsien int
fmd_fmri_present(nvlist_t * nvl)202600Stsien fmd_fmri_present(nvlist_t *nvl)
203600Stsien {
2043681Svn83148 int rc, err;
205600Stsien uint8_t version;
206600Stsien uint32_t cpuid;
207600Stsien uint64_t nvlserid, curserid;
2081414Scindi char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
2094198Seschrock topo_hdl_t *thp;
210600Stsien
211600Stsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
2121414Scindi nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
213600Stsien return (fmd_fmri_set_errno(EINVAL));
214600Stsien
2153681Svn83148 /*
2163681Svn83148 * If the cpu-scheme topology exports this method present(), invoke it.
2173681Svn83148 */
2184198Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
2194198Seschrock return (fmd_fmri_set_errno(EINVAL));
2204198Seschrock rc = topo_fmri_present(thp, nvl, &err);
2214198Seschrock fmd_fmri_topo_rele(thp);
2223681Svn83148 if (err != ETOPO_METHOD_NOTSUP)
2233681Svn83148 return (rc);
2243681Svn83148
2251414Scindi if (version == CPU_SCHEME_VERSION0) {
2261414Scindi if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
2271414Scindi &nvlserid) != 0)
2281414Scindi return (fmd_fmri_set_errno(EINVAL));
2291414Scindi if (cpu_get_serialid_V0(cpuid, &curserid) != 0)
2301414Scindi return (errno == ENOENT ? 0 : -1);
2311414Scindi
2321414Scindi return (curserid == nvlserid);
233600Stsien
2341414Scindi } else if (version == CPU_SCHEME_VERSION1) {
2351414Scindi if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
2361414Scindi &nvlserstr)) != 0)
2371414Scindi if (rc != ENOENT)
2381414Scindi return (fmd_fmri_set_errno(EINVAL));
2391414Scindi
2401414Scindi /*
2413548Shueston * If serial id is not available, just check if the cpuid
2423548Shueston * is present.
2431414Scindi */
2441414Scindi if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0)
2453548Shueston return (cpu_cpuid_present(cpuid));
2461414Scindi
2471414Scindi return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0);
2481414Scindi
2491414Scindi } else {
2501414Scindi return (fmd_fmri_set_errno(EINVAL));
2511414Scindi }
252600Stsien }
253600Stsien
254600Stsien int
fmd_fmri_replaced(nvlist_t * nvl)2557275Sstephh fmd_fmri_replaced(nvlist_t *nvl)
2567275Sstephh {
2577275Sstephh int rc, err = 0;
2587275Sstephh uint8_t version;
2597275Sstephh uint32_t cpuid;
2607275Sstephh uint64_t nvlserid, curserid;
2617275Sstephh char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
2627275Sstephh topo_hdl_t *thp;
2637275Sstephh
2647275Sstephh if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
2657275Sstephh nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
2667275Sstephh return (fmd_fmri_set_errno(EINVAL));
2677275Sstephh
2687275Sstephh /*
2697275Sstephh * If the cpu-scheme topology exports this method replaced(), invoke it.
2707275Sstephh */
2717275Sstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
2727275Sstephh return (fmd_fmri_set_errno(EINVAL));
2737275Sstephh rc = topo_fmri_replaced(thp, nvl, &err);
2747275Sstephh fmd_fmri_topo_rele(thp);
2757275Sstephh if (err != ETOPO_METHOD_NOTSUP)
2767275Sstephh return (rc);
2777275Sstephh
2787275Sstephh if (version == CPU_SCHEME_VERSION0) {
2797275Sstephh if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
2807275Sstephh &nvlserid) != 0)
2817275Sstephh return (fmd_fmri_set_errno(EINVAL));
2827275Sstephh if (cpu_get_serialid_V0(cpuid, &curserid) != 0)
2837275Sstephh return (errno == ENOENT ?
2847275Sstephh FMD_OBJ_STATE_NOT_PRESENT : -1);
2857275Sstephh
2867275Sstephh return (curserid == nvlserid ? FMD_OBJ_STATE_STILL_PRESENT :
2877275Sstephh FMD_OBJ_STATE_REPLACED);
2887275Sstephh
2897275Sstephh } else if (version == CPU_SCHEME_VERSION1) {
2907275Sstephh if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
2917275Sstephh &nvlserstr)) != 0)
2927275Sstephh if (rc != ENOENT)
2937275Sstephh return (fmd_fmri_set_errno(EINVAL));
2947275Sstephh
2957275Sstephh /*
2967275Sstephh * If serial id is not available, just check if the cpuid
2977275Sstephh * is present.
2987275Sstephh */
2997275Sstephh if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0)
3007275Sstephh if (cpu_cpuid_present(cpuid))
3017275Sstephh return (FMD_OBJ_STATE_UNKNOWN);
3027275Sstephh else
3037275Sstephh return (FMD_OBJ_STATE_NOT_PRESENT);
3047275Sstephh
3057275Sstephh return (strcmp(curserbuf, nvlserstr) == 0 ?
3067275Sstephh FMD_OBJ_STATE_STILL_PRESENT : FMD_OBJ_STATE_REPLACED);
3077275Sstephh
3087275Sstephh } else {
3097275Sstephh return (fmd_fmri_set_errno(EINVAL));
3107275Sstephh }
3117275Sstephh }
3127275Sstephh
3137275Sstephh int
fmd_fmri_unusable(nvlist_t * nvl)314600Stsien fmd_fmri_unusable(nvlist_t *nvl)
315600Stsien {
3166330Sjc25722 int rc, err = 0;
317600Stsien uint8_t version;
318600Stsien uint32_t cpuid;
3194198Seschrock topo_hdl_t *thp;
320600Stsien
321600Stsien if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
322600Stsien version > FM_CPU_SCHEME_VERSION ||
323600Stsien nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
324600Stsien return (fmd_fmri_set_errno(EINVAL));
3252072Svn83148
3263681Svn83148 /*
3273681Svn83148 * If the cpu-scheme topology exports this method unusable(), invoke it.
3283681Svn83148 */
3294198Seschrock if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
3304198Seschrock return (fmd_fmri_set_errno(EINVAL));
3314198Seschrock rc = topo_fmri_unusable(thp, nvl, &err);
3324198Seschrock fmd_fmri_topo_rele(thp);
3333681Svn83148 if (err != ETOPO_METHOD_NOTSUP)
3343681Svn83148 return (rc);
335600Stsien
3363681Svn83148 return (p_online(cpuid, P_STATUS) == P_FAULTED);
337600Stsien }
3386330Sjc25722 int
fmd_fmri_contains(nvlist_t * er,nvlist_t * ee)3396330Sjc25722 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee)
3406330Sjc25722 {
3416360Srobj int ret1, ret2;
3426330Sjc25722 char *erserstr, *eeserstr;
343*10784Ssinanallur.balasubramanian@sun.com uint8_t erversion, eeversion;
3446330Sjc25722 uint64_t erserint, eeserint;
3456330Sjc25722 uint32_t erval, eeval;
3466330Sjc25722
3476330Sjc25722 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_ID, &erval) != 0)
3486330Sjc25722 return (0);
3496330Sjc25722 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_ID, &eeval) != 0)
3506330Sjc25722 return (0);
3516330Sjc25722 if (erval != eeval)
3526330Sjc25722 return (0);
3536330Sjc25722
3546330Sjc25722 if (nvlist_lookup_uint8(er, FM_VERSION, &erversion) != 0)
3556330Sjc25722 return (0);
3566330Sjc25722
3576330Sjc25722 if (nvlist_lookup_uint8(ee, FM_VERSION, &eeversion) != 0)
3586330Sjc25722 return (0);
3596330Sjc25722
3606330Sjc25722 if (erversion != eeversion)
3616330Sjc25722 return (0);
3626330Sjc25722
3636330Sjc25722 if (erversion == CPU_SCHEME_VERSION0) {
3646330Sjc25722 if (nvlist_lookup_uint64(er, FM_FMRI_CPU_SERIAL_ID,
3656330Sjc25722 &erserint) != 0)
3666330Sjc25722 return (0);
3676330Sjc25722 if (nvlist_lookup_uint64(ee, FM_FMRI_CPU_SERIAL_ID,
3686330Sjc25722 &eeserint) != 0)
3696330Sjc25722 return (0);
3706330Sjc25722 if (erserint != eeserint)
3716330Sjc25722 return (0);
3726330Sjc25722 } else if (erversion == CPU_SCHEME_VERSION1) {
3736330Sjc25722 /* Serial ID is an optional element */
374*10784Ssinanallur.balasubramanian@sun.com ret1 = nvlist_lookup_string(er, FM_FMRI_CPU_SERIAL_ID,
375*10784Ssinanallur.balasubramanian@sun.com &erserstr);
376*10784Ssinanallur.balasubramanian@sun.com ret2 = nvlist_lookup_string(ee, FM_FMRI_CPU_SERIAL_ID,
377*10784Ssinanallur.balasubramanian@sun.com &eeserstr);
378*10784Ssinanallur.balasubramanian@sun.com if (ret1 != ret2)
379*10784Ssinanallur.balasubramanian@sun.com return (0);
380*10784Ssinanallur.balasubramanian@sun.com if (ret1 == ENOENT)
381*10784Ssinanallur.balasubramanian@sun.com /*
382*10784Ssinanallur.balasubramanian@sun.com * Serial IDs not found in both container, containee
383*10784Ssinanallur.balasubramanian@sun.com */
384*10784Ssinanallur.balasubramanian@sun.com return (1);
385*10784Ssinanallur.balasubramanian@sun.com if (ret1 != 0)
386*10784Ssinanallur.balasubramanian@sun.com return (0);
387*10784Ssinanallur.balasubramanian@sun.com /*
388*10784Ssinanallur.balasubramanian@sun.com * Found Serial Ids in both container and containee.
389*10784Ssinanallur.balasubramanian@sun.com * Check if they are same.
390*10784Ssinanallur.balasubramanian@sun.com */
391*10784Ssinanallur.balasubramanian@sun.com if (strlen(erserstr) != strlen(eeserstr))
392*10784Ssinanallur.balasubramanian@sun.com return (0);
393*10784Ssinanallur.balasubramanian@sun.com if (strcmp(erserstr, eeserstr) != 0)
394*10784Ssinanallur.balasubramanian@sun.com return (0);
3956330Sjc25722 }
3966330Sjc25722 return (1);
3976330Sjc25722 }
398