xref: /titanic_52/usr/src/cmd/fm/schemes/cpu/cpu.c (revision a99982a76d4cc12b1e9021e88531cf425d1e7369)
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 2007 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 /*
98  * Determine if a cpuid is present.
99  */
100 /*ARGSUSED*/
101 static int
102 cpu_cpuid_present(uint32_t cpuid)
103 {
104 #ifdef	sparc
105 	/*
106 	 * For SPARC, use kstats to see if the cpuid is present.
107 	 * Note that this may need to change for sun4v.
108 	 */
109 	kstat_ctl_t *kc;
110 	kstat_t *ksp = NULL;
111 	if ((kc = kstat_open()) == NULL)
112 		return (-1); /* errno is set for us */
113 	ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL);
114 	(void) kstat_close(kc);
115 	return ((ksp == NULL) ? 0 : 1);
116 #else	/* sparc */
117 	/*
118 	 * For x64, just return true.
119 	 */
120 	return (1);
121 #endif	/* sparc */
122 }
123 
124 static int
125 cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp)
126 {
127 	kstat_named_t *kn;
128 	kstat_ctl_t *kc;
129 	kstat_t *ksp;
130 	int i;
131 
132 	if ((kc = kstat_open()) == NULL)
133 		return (-1); /* errno is set for us */
134 
135 	if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) {
136 		(void) kstat_close(kc);
137 		return (fmd_fmri_set_errno(ENOENT));
138 	}
139 
140 	if (kstat_read(kc, ksp, NULL) == -1) {
141 		int oserr = errno;
142 		(void) kstat_close(kc);
143 		return (fmd_fmri_set_errno(oserr));
144 	}
145 
146 	for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) {
147 		if (strcmp(kn->name, "device_ID") == 0) {
148 			*serialidp = kn->value.ui64;
149 			(void) kstat_close(kc);
150 			return (0);
151 		}
152 	}
153 
154 	(void) kstat_close(kc);
155 	return (fmd_fmri_set_errno(ENOENT));
156 }
157 
158 static int
159 cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len)
160 {
161 	int err;
162 	uint64_t serial = 0;
163 
164 #ifdef	sparc
165 	if (cpu.cpu_mdesc_cpus != NULL)
166 		err = cpu_get_serialid_mdesc(cpuid, &serial);
167 	else
168 #endif	/* sparc */
169 		err = cpu_get_serialid_kstat(cpuid, &serial);
170 
171 	(void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial);
172 	return (err);
173 }
174 
175 static int
176 cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp)
177 {
178 #ifdef  sparc
179 	if (cpu.cpu_mdesc_cpus != NULL)
180 		return (cpu_get_serialid_mdesc(cpuid, serialidp));
181 	else
182 #endif  /* sparc */
183 		return (cpu_get_serialid_kstat(cpuid, serialidp));
184 }
185 
186 int
187 fmd_fmri_expand(nvlist_t *nvl)
188 {
189 	uint8_t version;
190 	uint32_t cpuid;
191 	uint64_t serialid;
192 	char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
193 	int rc;
194 
195 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
196 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
197 		return (fmd_fmri_set_errno(EINVAL));
198 
199 	if (version == CPU_SCHEME_VERSION0) {
200 		if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
201 		    &serialid)) != 0) {
202 			if (rc != ENOENT)
203 				return (fmd_fmri_set_errno(rc));
204 
205 			if (cpu_get_serialid_V0(cpuid, &serialid) != 0)
206 				return (-1); /* errno is set for us */
207 
208 			if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
209 			    serialid)) != 0)
210 				return (fmd_fmri_set_errno(rc));
211 		}
212 #ifdef sparc
213 		if (cpu.cpu_mdesc_cpus != NULL) {
214 			md_cpumap_t *mcmp = cpu_find_cpumap(cpuid);
215 			if (mcmp != NULL) {
216 			    if (strcmp(mcmp->cpumap_cpufrudn, "") == 0) {
217 				(void) nvlist_add_string(nvl,
218 				    FM_FMRI_HC_PART, mcmp->cpumap_cpufrupn);
219 			    } else {
220 				size_t ss = strlen(mcmp->cpumap_cpufrupn) +
221 				    strlen(mcmp->cpumap_cpufrudn) + 1;
222 				char *sp = fmd_fmri_alloc(ss);
223 				sp = strcpy(sp, mcmp->cpumap_cpufrupn);
224 				sp = strncat(sp, mcmp->cpumap_cpufrudn,
225 				    strlen(mcmp->cpumap_cpufrudn) + 1);
226 				(void) nvlist_add_string(nvl,
227 				    FM_FMRI_HC_PART, sp);
228 				fmd_fmri_free(sp, ss);
229 			    }
230 			    (void) nvlist_add_string(nvl,
231 				FM_FMRI_CPU_CPUFRU, mcmp->cpumap_cpufru);
232 			    nvl->nvl_nvflag = NV_UNIQUE_NAME_TYPE;
233 			    (void) nvlist_add_string(nvl, FM_FMRI_HC_SERIAL_ID,
234 				mcmp->cpumap_cpufrusn);
235 			}
236 		}
237 #endif	/* sparc */
238 	} else if (version == CPU_SCHEME_VERSION1) {
239 		if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
240 		    &serstr)) != 0) {
241 			if (rc != ENOENT)
242 				return (fmd_fmri_set_errno(rc));
243 
244 			if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0)
245 				return (0); /* Serial number is optional */
246 
247 			if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID,
248 			    serbuf)) != 0)
249 				return (fmd_fmri_set_errno(rc));
250 		}
251 	} else {
252 		return (fmd_fmri_set_errno(EINVAL));
253 	}
254 
255 	return (0);
256 }
257 
258 int
259 fmd_fmri_present(nvlist_t *nvl)
260 {
261 	int rc;
262 	uint8_t version;
263 	uint32_t cpuid;
264 	uint64_t nvlserid, curserid;
265 	char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
266 
267 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
268 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
269 		return (fmd_fmri_set_errno(EINVAL));
270 
271 	if (version == CPU_SCHEME_VERSION0) {
272 		if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
273 		    &nvlserid) != 0)
274 			return (fmd_fmri_set_errno(EINVAL));
275 		if (cpu_get_serialid_V0(cpuid, &curserid) != 0)
276 			return (errno == ENOENT ? 0 : -1);
277 
278 		return (curserid == nvlserid);
279 
280 	} else if (version == CPU_SCHEME_VERSION1) {
281 		if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
282 		    &nvlserstr)) != 0)
283 			if (rc != ENOENT)
284 				return (fmd_fmri_set_errno(EINVAL));
285 
286 		/*
287 		 * If serial id is not available, just check if the cpuid
288 		 * is present.
289 		 */
290 		if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0)
291 			return (cpu_cpuid_present(cpuid));
292 
293 		return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0);
294 
295 	} else {
296 		return (fmd_fmri_set_errno(EINVAL));
297 	}
298 }
299 
300 int
301 fmd_fmri_unusable(nvlist_t *nvl)
302 {
303 	uint8_t version;
304 	uint32_t cpuid;
305 
306 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
307 	    version > FM_CPU_SCHEME_VERSION ||
308 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
309 		return (fmd_fmri_set_errno(EINVAL));
310 
311 #ifdef sparc
312 	{
313 		int cpustatus = ldom_fmri_status(cpu_scheme_lhp, nvl);
314 
315 		return (cpustatus == P_FAULTED || (cpustatus == P_OFFLINE &&
316 				ldom_major_version(cpu_scheme_lhp) == 1));
317 	}
318 #else
319 	return (p_online(cpuid, P_STATUS) == P_FAULTED);
320 #endif
321 }
322 
323 #ifdef	sparc
324 int
325 fmd_fmri_init(void)
326 {
327 	cpu_scheme_lhp = ldom_init(fmd_fmri_alloc, fmd_fmri_free);
328 	return (cpu_mdesc_init(cpu_scheme_lhp));
329 }
330 
331 void
332 fmd_fmri_fini(void)
333 {
334 	cpu_mdesc_fini();
335 	ldom_fini(cpu_scheme_lhp);
336 }
337 #endif	/* sparc */
338