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 #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 static int 98 cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp) 99 { 100 kstat_named_t *kn; 101 kstat_ctl_t *kc; 102 kstat_t *ksp; 103 int i; 104 105 if ((kc = kstat_open()) == NULL) 106 return (-1); /* errno is set for us */ 107 108 if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) { 109 (void) kstat_close(kc); 110 return (fmd_fmri_set_errno(ENOENT)); 111 } 112 113 if (kstat_read(kc, ksp, NULL) == -1) { 114 int oserr = errno; 115 (void) kstat_close(kc); 116 return (fmd_fmri_set_errno(oserr)); 117 } 118 119 for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { 120 if (strcmp(kn->name, "device_ID") == 0) { 121 *serialidp = kn->value.ui64; 122 (void) kstat_close(kc); 123 return (0); 124 } 125 } 126 127 (void) kstat_close(kc); 128 return (fmd_fmri_set_errno(ENOENT)); 129 } 130 131 static int 132 cpu_get_serialid_V1(uint32_t cpuid, char *serbuf, size_t len) 133 { 134 int err; 135 uint64_t serial = 0; 136 137 #ifdef sparc 138 if (cpu.cpu_mdesc_cpus != NULL) 139 err = cpu_get_serialid_mdesc(cpuid, &serial); 140 else 141 #endif /* sparc */ 142 err = cpu_get_serialid_kstat(cpuid, &serial); 143 144 (void) snprintf(serbuf, len, "%llX", (u_longlong_t)serial); 145 return (err); 146 } 147 148 static int 149 cpu_get_serialid_V0(uint32_t cpuid, uint64_t *serialidp) 150 { 151 #ifdef sparc 152 if (cpu.cpu_mdesc_cpus != NULL) 153 return (cpu_get_serialid_mdesc(cpuid, serialidp)); 154 else 155 #endif /* sparc */ 156 return (cpu_get_serialid_kstat(cpuid, serialidp)); 157 } 158 159 int 160 fmd_fmri_expand(nvlist_t *nvl) 161 { 162 uint8_t version; 163 uint32_t cpuid; 164 uint64_t serialid; 165 char *serstr, serbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 166 int rc; 167 168 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 169 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 170 return (fmd_fmri_set_errno(EINVAL)); 171 172 if (version == CPU_SCHEME_VERSION0) { 173 if ((rc = nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 174 &serialid)) != 0) { 175 if (rc != ENOENT) 176 return (fmd_fmri_set_errno(rc)); 177 178 if (cpu_get_serialid_V0(cpuid, &serialid) != 0) 179 return (-1); /* errno is set for us */ 180 181 if ((rc = nvlist_add_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 182 serialid)) != 0) 183 return (fmd_fmri_set_errno(rc)); 184 } 185 } else if (version == CPU_SCHEME_VERSION1) { 186 if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 187 &serstr)) != 0) { 188 if (rc != ENOENT) 189 return (fmd_fmri_set_errno(rc)); 190 191 if (cpu_get_serialid_V1(cpuid, serbuf, 21) != 0) 192 return (0); /* Serial number is optional */ 193 194 if ((rc = nvlist_add_string(nvl, FM_FMRI_CPU_SERIAL_ID, 195 serbuf)) != 0) 196 return (fmd_fmri_set_errno(rc)); 197 } 198 } else { 199 return (fmd_fmri_set_errno(EINVAL)); 200 } 201 202 return (0); 203 } 204 205 int 206 fmd_fmri_present(nvlist_t *nvl) 207 { 208 int rc; 209 uint8_t version; 210 uint32_t cpuid; 211 uint64_t nvlserid, curserid; 212 char *nvlserstr, curserbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ 213 214 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 215 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 216 return (fmd_fmri_set_errno(EINVAL)); 217 218 if (version == CPU_SCHEME_VERSION0) { 219 if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 220 &nvlserid) != 0) 221 return (fmd_fmri_set_errno(EINVAL)); 222 if (cpu_get_serialid_V0(cpuid, &curserid) != 0) 223 return (errno == ENOENT ? 0 : -1); 224 225 return (curserid == nvlserid); 226 227 } else if (version == CPU_SCHEME_VERSION1) { 228 if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 229 &nvlserstr)) != 0) 230 if (rc != ENOENT) 231 return (fmd_fmri_set_errno(EINVAL)); 232 233 /* 234 * Serial id may not be available, return true 235 */ 236 if (cpu_get_serialid_V1(cpuid, curserbuf, 21) != 0) 237 return (1); 238 239 return (strcmp(curserbuf, nvlserstr) == 0 ? 1 : 0); 240 241 } else { 242 return (fmd_fmri_set_errno(EINVAL)); 243 } 244 } 245 246 int 247 fmd_fmri_unusable(nvlist_t *nvl) 248 { 249 uint8_t version; 250 uint32_t cpuid; 251 252 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 253 version > FM_CPU_SCHEME_VERSION || 254 nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 255 return (fmd_fmri_set_errno(EINVAL)); 256 257 #ifdef sparc 258 { 259 int cpustatus = ldom_fmri_status(cpu_scheme_lhp, nvl); 260 261 return (cpustatus == P_FAULTED || (cpustatus == P_OFFLINE && 262 ldom_major_version(cpu_scheme_lhp) == 1)); 263 } 264 #else 265 return (p_online(cpuid, P_STATUS) == P_FAULTED); 266 #endif 267 } 268 269 #ifdef sparc 270 int 271 fmd_fmri_init(void) 272 { 273 cpu_scheme_lhp = ldom_init(fmd_fmri_alloc, fmd_fmri_free); 274 return (cpu_mdesc_init(cpu_scheme_lhp)); 275 } 276 277 void 278 fmd_fmri_fini(void) 279 { 280 cpu_mdesc_fini(); 281 ldom_fini(cpu_scheme_lhp); 282 } 283 #endif /* sparc */ 284