xref: /illumos-gate/usr/src/cmd/fm/schemes/cpu/cpu.c (revision 60a3f738d56f92ae8b80e4b62a2331c6e1f2311f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/processor.h>
31 #include <fm/fmd_fmri.h>
32 
33 #include <strings.h>
34 #include <errno.h>
35 #include <kstat.h>
36 
37 #ifdef	sparc
38 #include <cpu_mdesc.h>
39 #include <sys/fm/ldom.h>
40 #endif
41 
42 /*
43  * The scheme plugin for cpu FMRIs.
44  */
45 
46 #ifdef sparc
47 cpu_t cpu;
48 static ldom_hdl_t *cpu_scheme_lhp;
49 #endif /* sparc */
50 
51 ssize_t
52 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
53 {
54 	int err;
55 	uint8_t version;
56 	uint32_t cpuid;
57 	uint64_t serint;
58 	char *serstr;
59 
60 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0)
61 		return (fmd_fmri_set_errno(EINVAL));
62 
63 	if (version == CPU_SCHEME_VERSION0) {
64 		if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 ||
65 		    nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serint)
66 		    != 0)
67 			return (fmd_fmri_set_errno(EINVAL));
68 
69 		return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX",
70 		    FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID,
71 		    (u_longlong_t)serint));
72 
73 	} else if (version == CPU_SCHEME_VERSION1) {
74 		if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
75 			return (fmd_fmri_set_errno(EINVAL));
76 
77 		/*
78 		 * Serial number is an optional element
79 		 */
80 		if ((err = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
81 		    &serstr)) != 0)
82 			if (err == ENOENT)
83 				return (snprintf(buf, buflen, "cpu:///%s=%u",
84 				    FM_FMRI_CPU_ID, cpuid));
85 			else
86 				return (fmd_fmri_set_errno(EINVAL));
87 		else
88 			return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%s",
89 			    FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID,
90 			    serstr));
91 
92 	} else {
93 		return (fmd_fmri_set_errno(EINVAL));
94 	}
95 }
96 
97 static int
98 cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp)
99 {
100 	kstat_named_t *kn;
101 	kstat_ctl_t *kc;
102 	kstat_t *ksp;
103 	int i;
104 
105 	if ((kc = kstat_open()) == NULL)
106 		return (-1); /* errno is set for us */
107 
108 	if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) {
109 		(void) kstat_close(kc);
110 		return (fmd_fmri_set_errno(ENOENT));
111 	}
112 
113 	if (kstat_read(kc, ksp, NULL) == -1) {
114 		int oserr = errno;
115 		(void) kstat_close(kc);
116 		return (fmd_fmri_set_errno(oserr));
117 	}
118 
119 	for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) {
120 		if (strcmp(kn->name, "device_ID") == 0) {
121 			*serialidp = kn->value.ui64;
122 			(void) kstat_close(kc);
123 			return (0);
124 		}
125 	}
126 
127 	(void) kstat_close(kc);
128 	return (fmd_fmri_set_errno(ENOENT));
129 }
130 
131 static int
132 cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len)
133 {
134 	int err;
135 	uint64_t serial = 0;
136 
137 #ifdef	sparc
138 	if (cpu.cpu_mdesc_cpus != NULL)
139 		err = cpu_get_serialid_mdesc(cpuid, &serial);
140 	else
141 #endif	/* sparc */
142 		err = cpu_get_serialid_kstat(cpuid, &serial);
143 
144 	(void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial);
145 	return (err);
146 }
147 
148 static int
149 cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp)
150 {
151 #ifdef  sparc
152 	if (cpu.cpu_mdesc_cpus != NULL)
153 		return (cpu_get_serialid_mdesc(cpuid, serialidp));
154 	else
155 #endif  /* sparc */
156 		return (cpu_get_serialid_kstat(cpuid, serialidp));
157 }
158 
159 int
160 fmd_fmri_expand(nvlist_t *nvl)
161 {
162 	uint8_t version;
163 	uint32_t cpuid;
164 	uint64_t serialid;
165 	char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
166 	int rc;
167 
168 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
169 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
170 		return (fmd_fmri_set_errno(EINVAL));
171 
172 	if (version == CPU_SCHEME_VERSION0) {
173 		if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
174 		    &serialid)) != 0) {
175 			if (rc != ENOENT)
176 				return (fmd_fmri_set_errno(rc));
177 
178 			if (cpu_get_serialid_V0(cpuid, &serialid) != 0)
179 				return (-1); /* errno is set for us */
180 
181 			if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
182 			    serialid)) != 0)
183 				return (fmd_fmri_set_errno(rc));
184 		}
185 	} else if (version == CPU_SCHEME_VERSION1) {
186 		if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
187 		    &serstr)) != 0) {
188 			if (rc != ENOENT)
189 				return (fmd_fmri_set_errno(rc));
190 
191 			if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0)
192 				return (0); /* Serial number is optional */
193 
194 			if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID,
195 			    serbuf)) != 0)
196 				return (fmd_fmri_set_errno(rc));
197 		}
198 	} else {
199 		return (fmd_fmri_set_errno(EINVAL));
200 	}
201 
202 	return (0);
203 }
204 
205 int
206 fmd_fmri_present(nvlist_t *nvl)
207 {
208 	int rc;
209 	uint8_t version;
210 	uint32_t cpuid;
211 	uint64_t nvlserid, curserid;
212 	char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
213 
214 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
215 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
216 		return (fmd_fmri_set_errno(EINVAL));
217 
218 	if (version == CPU_SCHEME_VERSION0) {
219 		if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
220 		    &nvlserid) != 0)
221 			return (fmd_fmri_set_errno(EINVAL));
222 		if (cpu_get_serialid_V0(cpuid, &curserid) != 0)
223 			return (errno == ENOENT ? 0 : -1);
224 
225 		return (curserid == nvlserid);
226 
227 	} else if (version == CPU_SCHEME_VERSION1) {
228 		if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
229 		    &nvlserstr)) != 0)
230 			if (rc != ENOENT)
231 				return (fmd_fmri_set_errno(EINVAL));
232 
233 		/*
234 		 * Serial id may not be available, return true
235 		 */
236 		if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0)
237 			return (1);
238 
239 		return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0);
240 
241 	} else {
242 		return (fmd_fmri_set_errno(EINVAL));
243 	}
244 }
245 
246 int
247 fmd_fmri_unusable(nvlist_t *nvl)
248 {
249 	uint8_t version;
250 	uint32_t cpuid;
251 
252 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
253 	    version > FM_CPU_SCHEME_VERSION ||
254 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
255 		return (fmd_fmri_set_errno(EINVAL));
256 
257 #ifdef sparc
258 	{
259 		int cpustatus = ldom_fmri_status(cpu_scheme_lhp, nvl);
260 
261 		return (cpustatus == P_FAULTED || (cpustatus == P_OFFLINE &&
262 				ldom_major_version(cpu_scheme_lhp) == 1));
263 	}
264 #else
265 	return (p_online(cpuid, P_STATUS) == P_FAULTED);
266 #endif
267 }
268 
269 #ifdef	sparc
270 int
271 fmd_fmri_init(void)
272 {
273 	cpu_scheme_lhp = ldom_init(fmd_fmri_alloc, fmd_fmri_free);
274 	return (cpu_mdesc_init(cpu_scheme_lhp));
275 }
276 
277 void
278 fmd_fmri_fini(void)
279 {
280 	cpu_mdesc_fini();
281 	ldom_fini(cpu_scheme_lhp);
282 }
283 #endif	/* sparc */
284