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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <sys/processor.h>
29 #include <fm/fmd_fmri.h>
30 #include <fm/libtopo.h>
31
32 #include <strings.h>
33 #include <errno.h>
34 #include <kstat.h>
35
36
37 /*
38 * The scheme plugin for cpu FMRIs.
39 */
40
41 ssize_t
fmd_fmri_nvl2str(nvlist_t * nvl,char * buf,size_t buflen)42 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
43 {
44 int err;
45 ssize_t len;
46 topo_hdl_t *thp;
47 char *str;
48
49 if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
50 return (fmd_fmri_set_errno(EINVAL));
51 if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) {
52 fmd_fmri_topo_rele(thp);
53 return (fmd_fmri_set_errno(EINVAL));
54 }
55 if (buf != NULL)
56 len = snprintf(buf, buflen, "%s", str);
57 else
58 len = strlen(str);
59 topo_hdl_strfree(thp, str);
60 fmd_fmri_topo_rele(thp);
61 return (len);
62 }
63
64 /*
65 * Determine if a cpuid is present.
66 */
67 /*ARGSUSED*/
68 static int
cpu_cpuid_present(uint32_t cpuid)69 cpu_cpuid_present(uint32_t cpuid)
70 {
71 #ifdef sparc
72 /*
73 * For SPARC, use kstats to see if the cpuid is present.
74 * Note that this may need to change for sun4v.
75 */
76 kstat_ctl_t *kc;
77 kstat_t *ksp = NULL;
78 if ((kc = kstat_open()) == NULL)
79 return (-1); /* errno is set for us */
80 ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL);
81 (void) kstat_close(kc);
82 return ((ksp == NULL) ? 0 : 1);
83 #else /* sparc */
84 /*
85 * For x64, just return true.
86 */
87 return (1);
88 #endif /* sparc */
89 }
90
91 static int
cpu_get_serialid_kstat(uint32_t cpuid,uint64_t * serialidp)92 cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp)
93 {
94 kstat_named_t *kn;
95 kstat_ctl_t *kc;
96 kstat_t *ksp;
97 int i;
98
99 if ((kc = kstat_open()) == NULL)
100 return (-1); /* errno is set for us */
101
102 if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) {
103 (void) kstat_close(kc);
104 return (fmd_fmri_set_errno(ENOENT));
105 }
106
107 if (kstat_read(kc, ksp, NULL) == -1) {
108 int oserr = errno;
109 (void) kstat_close(kc);
110 return (fmd_fmri_set_errno(oserr));
111 }
112
113 for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) {
114 if (strcmp(kn->name, "device_ID") == 0) {
115 *serialidp = kn->value.ui64;
116 (void) kstat_close(kc);
117 return (0);
118 }
119 }
120
121 (void) kstat_close(kc);
122 return (fmd_fmri_set_errno(ENOENT));
123 }
124
125 static int
cpu_get_serialid_V1(uint32_t cpuid,char * serbuf,size_t len)126 cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len)
127 {
128 int err;
129 uint64_t serial = 0;
130
131 err = cpu_get_serialid_kstat(cpuid, &serial);
132
133 (void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial);
134 return (err);
135 }
136
137 static int
cpu_get_serialid_V0(uint32_t cpuid,uint64_t * serialidp)138 cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp)
139 {
140 return (cpu_get_serialid_kstat(cpuid, serialidp));
141 }
142
143 int
fmd_fmri_expand(nvlist_t * nvl)144 fmd_fmri_expand(nvlist_t *nvl)
145 {
146 uint8_t version;
147 uint32_t cpuid;
148 uint64_t serialid;
149 char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
150 int rc, err;
151 topo_hdl_t *thp;
152
153 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
154 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
155 return (fmd_fmri_set_errno(EINVAL));
156
157 /*
158 * If the cpu-scheme topology exports this method expand(), invoke it.
159 */
160 if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
161 return (fmd_fmri_set_errno(EINVAL));
162
163 rc = topo_fmri_expand(thp, nvl, &err);
164 fmd_fmri_topo_rele(thp);
165 if (err != ETOPO_METHOD_NOTSUP)
166 return (rc);
167
168 if (version == CPU_SCHEME_VERSION0) {
169 if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
170 &serialid)) != 0) {
171 if (rc != ENOENT)
172 return (fmd_fmri_set_errno(rc));
173
174 if (cpu_get_serialid_V0(cpuid, &serialid) != 0)
175 return (-1); /* errno is set for us */
176
177 if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
178 serialid)) != 0)
179 return (fmd_fmri_set_errno(rc));
180 }
181 } else if (version == CPU_SCHEME_VERSION1) {
182 if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
183 &serstr)) != 0) {
184 if (rc != ENOENT)
185 return (fmd_fmri_set_errno(rc));
186
187 if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0)
188 return (0); /* Serial number is optional */
189
190 if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID,
191 serbuf)) != 0)
192 return (fmd_fmri_set_errno(rc));
193 }
194 } else {
195 return (fmd_fmri_set_errno(EINVAL));
196 }
197
198 return (0);
199 }
200
201 int
fmd_fmri_present(nvlist_t * nvl)202 fmd_fmri_present(nvlist_t *nvl)
203 {
204 int rc, err;
205 uint8_t version;
206 uint32_t cpuid;
207 uint64_t nvlserid, curserid;
208 char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
209 topo_hdl_t *thp;
210
211 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
212 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
213 return (fmd_fmri_set_errno(EINVAL));
214
215 /*
216 * If the cpu-scheme topology exports this method present(), invoke it.
217 */
218 if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
219 return (fmd_fmri_set_errno(EINVAL));
220 rc = topo_fmri_present(thp, nvl, &err);
221 fmd_fmri_topo_rele(thp);
222 if (err != ETOPO_METHOD_NOTSUP)
223 return (rc);
224
225 if (version == CPU_SCHEME_VERSION0) {
226 if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
227 &nvlserid) != 0)
228 return (fmd_fmri_set_errno(EINVAL));
229 if (cpu_get_serialid_V0(cpuid, &curserid) != 0)
230 return (errno == ENOENT ? 0 : -1);
231
232 return (curserid == nvlserid);
233
234 } else if (version == CPU_SCHEME_VERSION1) {
235 if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
236 &nvlserstr)) != 0)
237 if (rc != ENOENT)
238 return (fmd_fmri_set_errno(EINVAL));
239
240 /*
241 * If serial id is not available, just check if the cpuid
242 * is present.
243 */
244 if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0)
245 return (cpu_cpuid_present(cpuid));
246
247 return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0);
248
249 } else {
250 return (fmd_fmri_set_errno(EINVAL));
251 }
252 }
253
254 int
fmd_fmri_replaced(nvlist_t * nvl)255 fmd_fmri_replaced(nvlist_t *nvl)
256 {
257 int rc, err = 0;
258 uint8_t version;
259 uint32_t cpuid;
260 uint64_t nvlserid, curserid;
261 char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */
262 topo_hdl_t *thp;
263
264 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
265 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
266 return (fmd_fmri_set_errno(EINVAL));
267
268 /*
269 * If the cpu-scheme topology exports this method replaced(), invoke it.
270 */
271 if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
272 return (fmd_fmri_set_errno(EINVAL));
273 rc = topo_fmri_replaced(thp, nvl, &err);
274 fmd_fmri_topo_rele(thp);
275 if (err != ETOPO_METHOD_NOTSUP)
276 return (rc);
277
278 if (version == CPU_SCHEME_VERSION0) {
279 if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
280 &nvlserid) != 0)
281 return (fmd_fmri_set_errno(EINVAL));
282 if (cpu_get_serialid_V0(cpuid, &curserid) != 0)
283 return (errno == ENOENT ?
284 FMD_OBJ_STATE_NOT_PRESENT : -1);
285
286 return (curserid == nvlserid ? FMD_OBJ_STATE_STILL_PRESENT :
287 FMD_OBJ_STATE_REPLACED);
288
289 } else if (version == CPU_SCHEME_VERSION1) {
290 if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
291 &nvlserstr)) != 0)
292 if (rc != ENOENT)
293 return (fmd_fmri_set_errno(EINVAL));
294
295 /*
296 * If serial id is not available, just check if the cpuid
297 * is present.
298 */
299 if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0)
300 if (cpu_cpuid_present(cpuid))
301 return (FMD_OBJ_STATE_UNKNOWN);
302 else
303 return (FMD_OBJ_STATE_NOT_PRESENT);
304
305 return (strcmp(curserbuf, nvlserstr) == 0 ?
306 FMD_OBJ_STATE_STILL_PRESENT : FMD_OBJ_STATE_REPLACED);
307
308 } else {
309 return (fmd_fmri_set_errno(EINVAL));
310 }
311 }
312
313 int
fmd_fmri_unusable(nvlist_t * nvl)314 fmd_fmri_unusable(nvlist_t *nvl)
315 {
316 int rc, err = 0;
317 uint8_t version;
318 uint32_t cpuid;
319 topo_hdl_t *thp;
320
321 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
322 version > FM_CPU_SCHEME_VERSION ||
323 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
324 return (fmd_fmri_set_errno(EINVAL));
325
326 /*
327 * If the cpu-scheme topology exports this method unusable(), invoke it.
328 */
329 if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL)
330 return (fmd_fmri_set_errno(EINVAL));
331 rc = topo_fmri_unusable(thp, nvl, &err);
332 fmd_fmri_topo_rele(thp);
333 if (err != ETOPO_METHOD_NOTSUP)
334 return (rc);
335
336 return (p_online(cpuid, P_STATUS) == P_FAULTED);
337 }
338 int
fmd_fmri_contains(nvlist_t * er,nvlist_t * ee)339 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee)
340 {
341 int ret1, ret2;
342 char *erserstr, *eeserstr;
343 uint8_t erversion, eeversion;
344 uint64_t erserint, eeserint;
345 uint32_t erval, eeval;
346
347 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_ID, &erval) != 0)
348 return (0);
349 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_ID, &eeval) != 0)
350 return (0);
351 if (erval != eeval)
352 return (0);
353
354 if (nvlist_lookup_uint8(er, FM_VERSION, &erversion) != 0)
355 return (0);
356
357 if (nvlist_lookup_uint8(ee, FM_VERSION, &eeversion) != 0)
358 return (0);
359
360 if (erversion != eeversion)
361 return (0);
362
363 if (erversion == CPU_SCHEME_VERSION0) {
364 if (nvlist_lookup_uint64(er, FM_FMRI_CPU_SERIAL_ID,
365 &erserint) != 0)
366 return (0);
367 if (nvlist_lookup_uint64(ee, FM_FMRI_CPU_SERIAL_ID,
368 &eeserint) != 0)
369 return (0);
370 if (erserint != eeserint)
371 return (0);
372 } else if (erversion == CPU_SCHEME_VERSION1) {
373 /* Serial ID is an optional element */
374 ret1 = nvlist_lookup_string(er, FM_FMRI_CPU_SERIAL_ID,
375 &erserstr);
376 ret2 = nvlist_lookup_string(ee, FM_FMRI_CPU_SERIAL_ID,
377 &eeserstr);
378 if (ret1 != ret2)
379 return (0);
380 if (ret1 == ENOENT)
381 /*
382 * Serial IDs not found in both container, containee
383 */
384 return (1);
385 if (ret1 != 0)
386 return (0);
387 /*
388 * Found Serial Ids in both container and containee.
389 * Check if they are same.
390 */
391 if (strlen(erserstr) != strlen(eeserstr))
392 return (0);
393 if (strcmp(erserstr, eeserstr) != 0)
394 return (0);
395 }
396 return (1);
397 }
398