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 2006 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 #endif 40 41 /* 42 * The scheme plugin for cpu FMRIs. 43 */ 44 45 #ifdef sparc 46 #define ONTARIO_PLAT_NAME "SUNW,Sun-Fire-T200" 47 #define ERIE_PLAT_NAME "SUNW,Sun-Fire-T1000" 48 #define PELTON_PLAT_NAME "SUNW,Netra-T2000" 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 int err; 56 uint8_t version; 57 uint32_t cpuid; 58 uint64_t serint; 59 char *serstr; 60 61 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0) 62 return (fmd_fmri_set_errno(EINVAL)); 63 64 if (version == CPU_SCHEME_VERSION0) { 65 if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 || 66 nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serint) 67 != 0) 68 return (fmd_fmri_set_errno(EINVAL)); 69 70 return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX", 71 FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID, 72 (u_longlong_t)serint)); 73 74 } else if (version == CPU_SCHEME_VERSION1) { 75 if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 76 return (fmd_fmri_set_errno(EINVAL)); 77 78 /* 79 * Serial number is an optional element 80 */ 81 if ((err = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 82 &serstr)) != 0) 83 if (err == ENOENT) 84 return (snprintf(buf, buflen, "cpu:///%s=%u", 85 FM_FMRI_CPU_ID, cpuid)); 86 else 87 return (fmd_fmri_set_errno(EINVAL)); 88 else 89 return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%s", 90 FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID, 91 serstr)); 92 93 } else { 94 return (fmd_fmri_set_errno(EINVAL)); 95 } 96 } 97 98 static int 99 cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp) 100 { 101 kstat_named_t *kn; 102 kstat_ctl_t *kc; 103 kstat_t *ksp; 104 int i; 105 106 if ((kc = kstat_open()) == NULL) 107 return (-1); /* errno is set for us */ 108 109 if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) { 110 (void) kstat_close(kc); 111 return (fmd_fmri_set_errno(ENOENT)); 112 } 113 114 if (kstat_read(kc, ksp, NULL) == -1) { 115 int oserr = errno; 116 (void) kstat_close(kc); 117 return (fmd_fmri_set_errno(oserr)); 118 } 119 120 for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { 121 if (strcmp(kn->name, "device_ID") == 0) { 122 *serialidp = kn->value.ui64; 123 (void) kstat_close(kc); 124 return (0); 125 } 126 } 127 128 (void) kstat_close(kc); 129 return (fmd_fmri_set_errno(ENOENT)); 130 } 131 132 static int 133 cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len) 134 { 135 int err; 136 uint64_t serial = 0; 137 138 #ifdef sparc 139 if (cpu.cpu_mdesc_cpus != NULL) 140 err = cpu_get_serialid_mdesc(cpuid, &serial); 141 else 142 #endif /* sparc */ 143 err = cpu_get_serialid_kstat(cpuid, &serial); 144 145 (void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial); 146 return (err); 147 } 148 149 static int 150 cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp) 151 { 152 #ifdef sparc 153 if (cpu.cpu_mdesc_cpus != NULL) 154 return (cpu_get_serialid_mdesc(cpuid, serialidp)); 155 else 156 #endif /* sparc */ 157 return (cpu_get_serialid_kstat(cpuid, serialidp)); 158 } 159 160 #ifdef sparc 161 static int 162 cpu_phys2virt(uint32_t cpuid, uint32_t *cpuvidp) 163 { 164 md_cpumap_t *mcmp; 165 int idx; 166 167 if (cpu.cpu_mdesc_cpus == NULL) 168 return (ENOENT); 169 170 for (idx = 0, mcmp = cpu.cpu_mdesc_cpus; 171 idx < cpu.cpu_mdesc_ncpus; idx++, mcmp++) { 172 if (mcmp->cpumap_pid == (uint32_t)-1) 173 continue; /* ignore invalid value */ 174 if (mcmp->cpumap_pid == cpuid) { 175 *cpuvidp = mcmp->cpumap_id; 176 return (0); 177 } 178 } 179 180 return (ENOENT); 181 } 182 #endif /* sparc */ 183 184 int 185 fmd_fmri_expand(nvlist_t *nvl) 186 { 187 uint8_t version; 188 uint32_t cpuid; 189 uint64_t serialid; 190 char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 191 int rc; 192 193 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 194 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 195 return (fmd_fmri_set_errno(EINVAL)); 196 197 if (version == CPU_SCHEME_VERSION0) { 198 if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 199 &serialid)) != 0) { 200 if (rc != ENOENT) 201 return (fmd_fmri_set_errno(rc)); 202 203 if (cpu_get_serialid_V0(cpuid, &serialid) != 0) 204 return (-1); /* errno is set for us */ 205 206 if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 207 serialid)) != 0) 208 return (fmd_fmri_set_errno(rc)); 209 } 210 } else if (version == CPU_SCHEME_VERSION1) { 211 if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 212 &serstr)) != 0) { 213 if (rc != ENOENT) 214 return (fmd_fmri_set_errno(rc)); 215 216 if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0) 217 return (0); /* Serial number is optional */ 218 219 if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID, 220 serbuf)) != 0) 221 return (fmd_fmri_set_errno(rc)); 222 } 223 } else { 224 return (fmd_fmri_set_errno(EINVAL)); 225 } 226 227 #ifdef sparc 228 { 229 uint32_t cpuvid; 230 const char *platform = fmd_fmri_get_platform(); 231 232 if (strcmp(platform, ONTARIO_PLAT_NAME) == 0 || 233 strcmp(platform, PELTON_PLAT_NAME) == 0 || 234 strcmp(platform, ERIE_PLAT_NAME) == 0) { 235 if (cpu_phys2virt(cpuid, &cpuvid) != 0) 236 return (fmd_fmri_set_errno(ENOENT)); 237 238 (void) nvlist_remove_all(nvl, FM_FMRI_CPU_VID); 239 if ((rc = nvlist_add_uint32(nvl, FM_FMRI_CPU_VID, 240 cpuvid)) != 0) 241 return (fmd_fmri_set_errno(rc)); 242 } 243 } 244 #endif /* sparc */ 245 246 return (0); 247 } 248 249 int 250 fmd_fmri_present(nvlist_t *nvl) 251 { 252 int rc; 253 uint8_t version; 254 uint32_t cpuid; 255 uint64_t nvlserid, curserid; 256 char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 257 258 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 259 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 260 return (fmd_fmri_set_errno(EINVAL)); 261 262 if (version == CPU_SCHEME_VERSION0) { 263 if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 264 &nvlserid) != 0) 265 return (fmd_fmri_set_errno(EINVAL)); 266 if (cpu_get_serialid_V0(cpuid, &curserid) != 0) 267 return (errno == ENOENT ? 0 : -1); 268 269 return (curserid == nvlserid); 270 271 } else if (version == CPU_SCHEME_VERSION1) { 272 if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 273 &nvlserstr)) != 0) 274 if (rc != ENOENT) 275 return (fmd_fmri_set_errno(EINVAL)); 276 277 /* 278 * Serial id may not be available, return true 279 */ 280 if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0) 281 return (1); 282 283 return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0); 284 285 } else { 286 return (fmd_fmri_set_errno(EINVAL)); 287 } 288 } 289 290 int 291 fmd_fmri_unusable(nvlist_t *nvl) 292 { 293 uint8_t version; 294 uint32_t cpuid; 295 296 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 297 version > FM_CPU_SCHEME_VERSION || 298 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 299 return (fmd_fmri_set_errno(EINVAL)); 300 #ifdef sparc 301 { 302 uint32_t cpuvid; 303 if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_VID, &cpuvid) == 0) { 304 /* 305 * This FMRI has a 'cpuvid' member, but its value could 306 * be stale -- especially when restoring saved state. 307 * Do a fresh lookup and use the result for p_online(). 308 */ 309 if (cpu_phys2virt(cpuid, &cpuvid) != 0) 310 return (fmd_fmri_set_errno(ENOENT)); 311 return (p_online(cpuvid, P_STATUS) == P_FAULTED); 312 } 313 } 314 #endif /* sparc */ 315 316 return (p_online(cpuid, P_STATUS) == P_FAULTED); 317 } 318 319 #ifdef sparc 320 int 321 fmd_fmri_init(void) 322 { 323 return (cpu_mdesc_init()); 324 } 325 326 void 327 fmd_fmri_fini(void) 328 { 329 cpu_mdesc_fini(); 330 } 331 #endif /* sparc */ 332