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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 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 <string.h> 34 #include <strings.h> 35 #include <errno.h> 36 #include <kstat.h> 37 #ifdef sparc 38 #include <sys/mdesc.h> 39 #include <cpu.h> 40 #endif /* sparc */ 41 42 /* 43 * The scheme plugin for cpu FMRIs. 44 */ 45 46 #ifdef sparc 47 #define ONTARIO_PLAT_NAME "SUNW,Sun-Fire-T200" 48 #define ERIE_PLAT_NAME "SUNW,Sun-Fire-T1000" 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 uint8_t version; 56 uint32_t cpuid; 57 uint64_t serialid; 58 59 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 60 version > FM_CPU_SCHEME_VERSION || 61 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 || 62 nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serialid) != 0) 63 return (fmd_fmri_set_errno(EINVAL)); 64 65 return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX", FM_FMRI_CPU_ID, 66 cpuid, FM_FMRI_CPU_SERIAL_ID, (u_longlong_t)serialid)); 67 } 68 69 static int 70 cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp) 71 { 72 kstat_named_t *kn; 73 kstat_ctl_t *kc; 74 kstat_t *ksp; 75 int i; 76 77 if ((kc = kstat_open()) == NULL) /* XXX commonify */ 78 return (-1); /* errno is set for us */ 79 80 if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) { 81 (void) kstat_close(kc); 82 return (fmd_fmri_set_errno(ENOENT)); 83 } 84 85 if (kstat_read(kc, ksp, NULL) == -1) { 86 int oserr = errno; 87 (void) kstat_close(kc); 88 return (fmd_fmri_set_errno(oserr)); 89 } 90 91 for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { 92 if (strcmp(kn->name, "device_ID") == 0) { 93 *serialidp = kn->value.ui64; 94 (void) kstat_close(kc); 95 return (0); 96 } 97 } 98 99 (void) kstat_close(kc); 100 101 return (fmd_fmri_set_errno(ENOENT)); 102 } 103 104 static int 105 cpu_get_serialid(uint32_t cpuid, uint64_t *serialidp) 106 { 107 #ifdef sparc 108 if (cpu.cpu_mdesc_cpus != NULL) 109 return (cpu_get_serialid_mdesc(cpuid, serialidp)); 110 else 111 #endif /* sparc */ 112 return (cpu_get_serialid_kstat(cpuid, serialidp)); 113 } 114 115 #ifdef sparc 116 static int 117 cpu_phys2virt(uint32_t cpuid, uint32_t *cpuvidp) 118 { 119 md_cpumap_t *mcmp; 120 int idx; 121 122 if (cpu.cpu_mdesc_cpus == NULL) 123 return (ENOENT); 124 125 for (idx = 0, mcmp = cpu.cpu_mdesc_cpus; 126 idx < cpu.cpu_mdesc_ncpus; idx++, mcmp++) { 127 if (mcmp->cpumap_pid == (uint64_t)-1) 128 continue; /* ignore invalid value */ 129 if (mcmp->cpumap_pid == cpuid) { 130 *cpuvidp = mcmp->cpumap_id; 131 return (0); 132 } 133 } 134 135 return (ENOENT); 136 } 137 #endif /* sparc */ 138 139 int 140 fmd_fmri_expand(nvlist_t *nvl) 141 { 142 uint8_t version; 143 uint32_t cpuid; 144 uint64_t serialid; 145 int rc; 146 147 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 148 version > FM_CPU_SCHEME_VERSION || 149 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 150 return (fmd_fmri_set_errno(EINVAL)); 151 152 if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 153 &serialid)) != 0) { 154 if (rc != ENOENT) 155 return (fmd_fmri_set_errno(rc)); 156 157 if (cpu_get_serialid(cpuid, &serialid) != 0) 158 return (-1); /* errno is set for us */ 159 160 if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 161 serialid)) != 0) 162 return (fmd_fmri_set_errno(rc)); 163 } 164 165 #ifdef sparc 166 { 167 uint32_t cpuvid; 168 const char *platform = fmd_fmri_get_platform(); 169 170 if (strcmp(platform, ONTARIO_PLAT_NAME) == 0 || 171 strcmp(platform, ERIE_PLAT_NAME) == 0) { 172 if (cpu_phys2virt(cpuid, &cpuvid) != 0) 173 return (fmd_fmri_set_errno(ENOENT)); 174 175 (void) nvlist_remove_all(nvl, FM_FMRI_CPU_VID); 176 if ((rc = nvlist_add_uint32(nvl, FM_FMRI_CPU_VID, 177 cpuvid)) != 0) 178 return (fmd_fmri_set_errno(rc)); 179 } 180 } 181 #endif /* sparc */ 182 183 return (0); 184 } 185 186 int 187 fmd_fmri_present(nvlist_t *nvl) 188 { 189 uint8_t version; 190 uint32_t cpuid; 191 uint64_t nvlserid, curserid; 192 193 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 194 version > FM_CPU_SCHEME_VERSION || 195 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 || 196 nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &nvlserid) != 0) 197 return (fmd_fmri_set_errno(EINVAL)); 198 199 if (cpu_get_serialid(cpuid, &curserid) != 0) 200 return (errno == ENOENT ? 0 : -1); 201 202 return (curserid == nvlserid); 203 } 204 205 int 206 fmd_fmri_unusable(nvlist_t *nvl) 207 { 208 uint8_t version; 209 uint32_t cpuid; 210 211 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 212 version > FM_CPU_SCHEME_VERSION || 213 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 214 return (fmd_fmri_set_errno(EINVAL)); 215 #ifdef sparc 216 { 217 uint32_t cpuvid; 218 if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_VID, &cpuvid) == 0) { 219 /* 220 * This FMRI has a 'cpuvid' member, but its value could 221 * be stale -- especially when restoring saved state. 222 * Do a fresh lookup and use the result for p_online(). 223 */ 224 if (cpu_phys2virt(cpuid, &cpuvid) != 0) 225 return (fmd_fmri_set_errno(ENOENT)); 226 return (p_online(cpuvid, P_STATUS) == P_FAULTED); 227 } 228 } 229 #endif /* sparc */ 230 231 return (p_online(cpuid, P_STATUS) == P_FAULTED); 232 } 233 234 #ifdef sparc 235 int 236 fmd_fmri_init(void) 237 { 238 bzero(&cpu, sizeof (cpu_t)); 239 return (cpu_mdesc_init()); 240 } 241 242 void 243 fmd_fmri_fini(void) 244 { 245 cpu_mdesc_fini(); 246 } 247 #endif /* sparc */ 248