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