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