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_unusable(nvlist_t *nvl) 258 { 259 int rc, err = 0; 260 uint8_t version; 261 uint32_t cpuid; 262 topo_hdl_t *thp; 263 264 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 265 version > FM_CPU_SCHEME_VERSION || 266 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 267 return (fmd_fmri_set_errno(EINVAL)); 268 269 /* 270 * If the cpu-scheme topology exports this method unusable(), invoke it. 271 */ 272 if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 273 return (fmd_fmri_set_errno(EINVAL)); 274 rc = topo_fmri_unusable(thp, nvl, &err); 275 fmd_fmri_topo_rele(thp); 276 if (err != ETOPO_METHOD_NOTSUP) 277 return (rc); 278 279 return (p_online(cpuid, P_STATUS) == P_FAULTED); 280 } 281 int 282 fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) 283 { 284 int ret1, ret2; 285 char *erserstr, *eeserstr; 286 uint8_t ertype, eetype, erversion, eeversion; 287 uint64_t erserint, eeserint; 288 uint32_t erval, eeval; 289 size_t count; 290 291 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_ID, &erval) != 0) 292 return (0); 293 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_ID, &eeval) != 0) 294 return (0); 295 if (erval != eeval) 296 return (0); 297 298 if (nvlist_lookup_uint8(er, FM_VERSION, &erversion) != 0) 299 return (0); 300 301 if (nvlist_lookup_uint8(ee, FM_VERSION, &eeversion) != 0) 302 return (0); 303 304 if (erversion != eeversion) 305 return (0); 306 307 if (erversion == CPU_SCHEME_VERSION0) { 308 if (nvlist_lookup_uint64(er, FM_FMRI_CPU_SERIAL_ID, 309 &erserint) != 0) 310 return (0); 311 if (nvlist_lookup_uint64(ee, FM_FMRI_CPU_SERIAL_ID, 312 &eeserint) != 0) 313 return (0); 314 if (erserint != eeserint) 315 return (0); 316 } else if (erversion == CPU_SCHEME_VERSION1) { 317 /* Serial ID is an optional element */ 318 if ((ret1 = nvlist_lookup_string(er, FM_FMRI_CPU_SERIAL_ID, 319 &erserstr)) != 0) 320 if (ret1 != ENOENT) 321 return (0); 322 if ((ret2 = nvlist_lookup_string(ee, FM_FMRI_CPU_SERIAL_ID, 323 &eeserstr)) != 0) 324 if (ret2 != ENOENT) 325 return (0); 326 if (ret1 == 0 && ret2 == 0) { 327 count = strlen(erserstr); 328 if (strncmp(erserstr, eeserstr, count) != 0) 329 return (0); 330 } 331 } 332 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_CACHE_INDEX, &erval) != 0) 333 return (0); 334 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_CACHE_INDEX, &eeval) != 0) 335 return (0); 336 337 if (erval != eeval) 338 return (0); 339 340 if (nvlist_lookup_uint32(er, FM_FMRI_CPU_CACHE_WAY, &erval) != 0) 341 return (0); 342 if (nvlist_lookup_uint32(ee, FM_FMRI_CPU_CACHE_WAY, &eeval) != 0) 343 return (0); 344 345 if (erval != eeval) 346 return (0); 347 348 if (nvlist_lookup_uint8(er, FM_FMRI_CPU_CACHE_TYPE, &ertype) != 0) 349 return (0); 350 if (nvlist_lookup_uint8(ee, FM_FMRI_CPU_CACHE_TYPE, &eetype) != 0) 351 return (0); 352 353 if (eetype != ertype) 354 return (0); 355 356 return (1); 357 } 358