xref: /illumos-gate/usr/src/cmd/fm/schemes/cpu/cpu.c (revision 141040e8a310da49386b596573e5dde5580572ec)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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 <string.h>
34 #include <strings.h>
35 #include <errno.h>
36 #include <kstat.h>
37 #ifdef	sparc
38 #include <sys/mdesc.h>
39 #include <cpu.h>
40 #endif	/* sparc */
41 
42 /*
43  * The scheme plugin for cpu FMRIs.
44  */
45 
46 #ifdef sparc
47 #define	ONTARIO_PLAT_NAME	"SUNW,Sun-Fire-T200"
48 #define	ERIE_PLAT_NAME		"SUNW,Sun-Fire-T1000"
49 cpu_t cpu;
50 #endif /* sparc */
51 
52 ssize_t
53 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
54 {
55 	uint8_t version;
56 	uint32_t cpuid;
57 	uint64_t serialid;
58 
59 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
60 	    version > FM_CPU_SCHEME_VERSION ||
61 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 ||
62 	    nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serialid) != 0)
63 		return (fmd_fmri_set_errno(EINVAL));
64 
65 	return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX", FM_FMRI_CPU_ID,
66 	    cpuid, FM_FMRI_CPU_SERIAL_ID, (u_longlong_t)serialid));
67 }
68 
69 static int
70 cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp)
71 {
72 	kstat_named_t *kn;
73 	kstat_ctl_t *kc;
74 	kstat_t *ksp;
75 	int i;
76 
77 	if ((kc = kstat_open()) == NULL) /* XXX commonify */
78 		return (-1); /* errno is set for us */
79 
80 	if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) {
81 		(void) kstat_close(kc);
82 		return (fmd_fmri_set_errno(ENOENT));
83 	}
84 
85 	if (kstat_read(kc, ksp, NULL) == -1) {
86 		int oserr = errno;
87 		(void) kstat_close(kc);
88 		return (fmd_fmri_set_errno(oserr));
89 	}
90 
91 	for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) {
92 		if (strcmp(kn->name, "device_ID") == 0) {
93 			*serialidp = kn->value.ui64;
94 			(void) kstat_close(kc);
95 			return (0);
96 		}
97 	}
98 
99 	(void) kstat_close(kc);
100 
101 	return (fmd_fmri_set_errno(ENOENT));
102 }
103 
104 static int
105 cpu_get_serialid(uint32_t cpuid, uint64_t *serialidp)
106 {
107 #ifdef	sparc
108 	if (cpu.cpu_mdesc_cpus != NULL)
109 		return (cpu_get_serialid_mdesc(cpuid, serialidp));
110 	else
111 #endif	/* sparc */
112 		return (cpu_get_serialid_kstat(cpuid, serialidp));
113 }
114 
115 #ifdef sparc
116 static int
117 cpu_phys2virt(uint32_t cpuid, uint32_t *cpuvidp)
118 {
119 	md_cpumap_t *mcmp;
120 	int idx;
121 
122 	if (cpu.cpu_mdesc_cpus == NULL)
123 		return (ENOENT);
124 
125 	for (idx = 0, mcmp = cpu.cpu_mdesc_cpus;
126 	    idx < cpu.cpu_mdesc_ncpus; idx++, mcmp++) {
127 		if (mcmp->cpumap_pid == (uint64_t)-1)
128 			continue; /* ignore invalid value */
129 		if (mcmp->cpumap_pid == cpuid) {
130 			*cpuvidp = mcmp->cpumap_id;
131 			return (0);
132 		}
133 	}
134 
135 	return (ENOENT);
136 }
137 #endif /* sparc */
138 
139 int
140 fmd_fmri_expand(nvlist_t *nvl)
141 {
142 	uint8_t version;
143 	uint32_t cpuid;
144 	uint64_t serialid;
145 	int rc;
146 
147 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
148 	    version > FM_CPU_SCHEME_VERSION ||
149 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
150 		return (fmd_fmri_set_errno(EINVAL));
151 
152 	if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
153 	    &serialid)) != 0) {
154 		if (rc != ENOENT)
155 			return (fmd_fmri_set_errno(rc));
156 
157 		if (cpu_get_serialid(cpuid, &serialid) != 0)
158 			return (-1); /* errno is set for us */
159 
160 		if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
161 		    serialid)) != 0)
162 			return (fmd_fmri_set_errno(rc));
163 	}
164 
165 #ifdef sparc
166 	{
167 		uint32_t cpuvid;
168 		const char *platform = fmd_fmri_get_platform();
169 
170 		if (strcmp(platform, ONTARIO_PLAT_NAME) == 0 ||
171 		    strcmp(platform, ERIE_PLAT_NAME) == 0) {
172 			if (cpu_phys2virt(cpuid, &cpuvid) != 0)
173 				return (fmd_fmri_set_errno(ENOENT));
174 
175 			(void) nvlist_remove_all(nvl, FM_FMRI_CPU_VID);
176 			if ((rc = nvlist_add_uint32(nvl, FM_FMRI_CPU_VID,
177 			    cpuvid)) != 0)
178 				return (fmd_fmri_set_errno(rc));
179 		}
180 	}
181 #endif /* sparc */
182 
183 	return (0);
184 }
185 
186 int
187 fmd_fmri_present(nvlist_t *nvl)
188 {
189 	uint8_t version;
190 	uint32_t cpuid;
191 	uint64_t nvlserid, curserid;
192 
193 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
194 	    version > FM_CPU_SCHEME_VERSION ||
195 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 ||
196 	    nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &nvlserid) != 0)
197 		return (fmd_fmri_set_errno(EINVAL));
198 
199 	if (cpu_get_serialid(cpuid, &curserid) != 0)
200 		return (errno == ENOENT ? 0 : -1);
201 
202 	return (curserid == nvlserid);
203 }
204 
205 int
206 fmd_fmri_unusable(nvlist_t *nvl)
207 {
208 	uint8_t version;
209 	uint32_t cpuid;
210 
211 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
212 	    version > FM_CPU_SCHEME_VERSION ||
213 	    nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
214 		return (fmd_fmri_set_errno(EINVAL));
215 #ifdef sparc
216 	{
217 		uint32_t cpuvid;
218 		if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_VID, &cpuvid) == 0) {
219 			/*
220 			 * This FMRI has a 'cpuvid' member, but its value could
221 			 * be stale -- especially when restoring saved state.
222 			 * Do a fresh lookup and use the result for p_online().
223 			 */
224 			if (cpu_phys2virt(cpuid, &cpuvid) != 0)
225 				return (fmd_fmri_set_errno(ENOENT));
226 			return (p_online(cpuvid, P_STATUS) == P_FAULTED);
227 		}
228 	}
229 #endif /* sparc */
230 
231 	return (p_online(cpuid, P_STATUS) == P_FAULTED);
232 }
233 
234 #ifdef	sparc
235 int
236 fmd_fmri_init(void)
237 {
238 	bzero(&cpu, sizeof (cpu_t));
239 	return (cpu_mdesc_init());
240 }
241 
242 void
243 fmd_fmri_fini(void)
244 {
245 	cpu_mdesc_fini();
246 }
247 #endif	/* sparc */
248