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