xref: /onnv-gate/usr/src/cmd/fm/schemes/cpu/cpu.c (revision 7197:6062b005c7ea)
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