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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * Support routines for managing per-CPU state. 29 */ 30 31 #include <cmd_cpu.h> 32 #include <cmd_ecache.h> 33 #include <cmd_mem.h> 34 #include <cmd.h> 35 36 #include <stdio.h> 37 #include <string.h> 38 #include <strings.h> 39 #include <errno.h> 40 #include <kstat.h> 41 #include <fm/fmd_api.h> 42 #include <sys/async.h> 43 #include <sys/fm/protocol.h> 44 #include <sys/fm/cpu/UltraSPARC-III.h> 45 #include <sys/cheetahregs.h> 46 47 /* 48 * The unused argument 'clcode' is needed for our sun4v sibling. 49 */ 50 51 /*ARGSUSED*/ 52 int 53 cmd_xr_fill(fmd_hdl_t *hdl, nvlist_t *nvl, cmd_xr_t *xr, cmd_errcl_t clcode) 54 { 55 if (nvlist_lookup_uint16(nvl, FM_EREPORT_PAYLOAD_NAME_SYND, 56 &xr->xr_synd) != 0) 57 return (-1); 58 if (nvlist_lookup_uint8(nvl, FM_EREPORT_PAYLOAD_NAME_SYND_STATUS, 59 &xr->xr_synd_status) != 0) 60 return (-1); 61 if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_NAME_AFAR, 62 &xr->xr_afar) != 0) 63 return (-1); 64 if (nvlist_lookup_uint8(nvl, FM_EREPORT_PAYLOAD_NAME_AFAR_STATUS, 65 &xr->xr_afar_status) != 0) 66 return (-1); 67 return (0); 68 } 69 70 /* 71 * Search for the entry that matches the ena and the AFAR 72 * if we have a valid AFAR, otherwise just match the ENA 73 */ 74 cmd_xxcu_trw_t * 75 cmd_trw_lookup(uint64_t ena, uint8_t afar_status, uint64_t afar) 76 { 77 int i; 78 79 if (afar_status == AFLT_STAT_VALID) { 80 for (i = 0; i < cmd.cmd_xxcu_ntrw; i++) { 81 if (cmd.cmd_xxcu_trw[i].trw_ena == ena && 82 cmd.cmd_xxcu_trw[i].trw_afar == afar) 83 return (&cmd.cmd_xxcu_trw[i]); 84 } 85 } else { 86 for (i = 0; i < cmd.cmd_xxcu_ntrw; i++) { 87 if (cmd.cmd_xxcu_trw[i].trw_ena == ena) 88 return (&cmd.cmd_xxcu_trw[i]); 89 } 90 } 91 return (NULL); 92 } 93 94 /*ARGSUSED*/ 95 cmd_errcl_t 96 cmd_train_match(cmd_errcl_t trw_mask, cmd_errcl_t resolved_err) 97 { 98 return (cmd_xxcu_train_match(trw_mask)); 99 } 100 101 /*ARGSUSED*/ 102 int 103 cmd_afar_status_check(uint8_t afar_status, cmd_errcl_t clcode) 104 { 105 if (afar_status == AFLT_STAT_VALID) 106 return (0); 107 return (-1); 108 } 109 110 const errdata_t l3errdata = 111 { &cmd.cmd_l3data_serd, "l3cachedata", CMD_PTR_CPU_L3DATA }; 112 const errdata_t l2errdata = 113 { &cmd.cmd_l2data_serd, "l2cachedata", CMD_PTR_CPU_L2DATA }; 114 115 void 116 cmd_fill_errdata(cmd_errcl_t clcode, cmd_cpu_t *cpu, cmd_case_t **cc, 117 const errdata_t **ed) 118 { 119 if (CMD_ERRCL_ISL2XXCU(clcode)) { 120 *ed = &l2errdata; 121 *cc = &cpu->cpu_l2data; 122 } else { 123 *ed = &l3errdata; 124 *cc = &cpu->cpu_l3data; 125 } 126 } 127 128 /*ARGSUSED*/ 129 int 130 cmd_cpu_synd_check(uint16_t synd, cmd_errcl_t clcode) 131 { 132 if (synd == CH_POISON_SYND_FROM_XXU_WRITE || 133 synd == CH_POISON_SYND_FROM_XXU_WRMERGE || 134 synd == CH_POISON_SYND_FROM_DSTAT23) 135 return (-1); 136 else 137 return (0); 138 } 139 /*ARGSUSED*/ 140 int 141 cmd_afar_valid(fmd_hdl_t *hdl, nvlist_t *nvl, cmd_errcl_t clcode, 142 uint64_t *afar) 143 { 144 uint8_t afar_status; 145 146 if (nvlist_lookup_uint8(nvl, 147 FM_EREPORT_PAYLOAD_NAME_AFAR_STATUS, &afar_status) == 0) { 148 if (afar_status == AFLT_STAT_VALID) { 149 (void) nvlist_lookup_uint64(nvl, 150 FM_EREPORT_PAYLOAD_NAME_AFAR, afar); 151 return (0); 152 } else 153 return (-1); 154 } else 155 return (-1); 156 } 157 158 char * 159 cmd_cpu_getfrustr_by_id(fmd_hdl_t *hdl, uint32_t cpuid) 160 { 161 kstat_named_t *kn; 162 kstat_ctl_t *kc; 163 kstat_t *ksp; 164 int i; 165 166 if ((kc = kstat_open()) == NULL) 167 return (NULL); /* errno is set for us */ 168 169 if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL || 170 kstat_read(kc, ksp, NULL) == -1) { 171 int oserr = errno; 172 (void) kstat_close(kc); 173 (void) cmd_set_errno(oserr); 174 return (NULL); 175 } 176 177 for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { 178 if (strcmp(kn->name, "cpu_fru") == 0) { 179 char *str = fmd_hdl_strdup(hdl, 180 KSTAT_NAMED_STR_PTR(kn), FMD_SLEEP); 181 (void) kstat_close(kc); 182 return (str); 183 } 184 } 185 186 (void) kstat_close(kc); 187 (void) cmd_set_errno(ENOENT); 188 return (NULL); 189 } 190 191 char * 192 cmd_cpu_getfrustr(fmd_hdl_t *hdl, cmd_cpu_t *cp) 193 { 194 return (cmd_cpu_getfrustr_by_id(hdl, cp->cpu_cpuid)); 195 } 196 197 /*ARGSUSED*/ 198 char * 199 cmd_cpu_getpartstr(fmd_hdl_t *hdl, cmd_cpu_t *cp) { 200 return (NULL); 201 } 202 203 /*ARGSUSED*/ 204 char * 205 cmd_cpu_getserialstr(fmd_hdl_t *hdl, cmd_cpu_t *cp) { 206 return (NULL); 207 } 208 209 /*ARGSUSED*/ 210 nvlist_t * 211 cmd_cpu_mkfru(fmd_hdl_t *hdl, char *frustr, char *serialstr, char *partstr) 212 { 213 char *comp; 214 nvlist_t *fru, *hcelem; 215 216 if (strncmp(frustr, CPU_FRU_FMRI, sizeof (CPU_FRU_FMRI) - 1) != 0) 217 return (NULL); 218 219 comp = frustr + sizeof (CPU_FRU_FMRI) - 1; 220 221 if (nvlist_alloc(&hcelem, NV_UNIQUE_NAME, 0) != 0) 222 return (NULL); 223 224 if (nvlist_add_string(hcelem, FM_FMRI_HC_NAME, 225 FM_FMRI_LEGACY_HC) != 0 || 226 nvlist_add_string(hcelem, FM_FMRI_HC_ID, comp) != 0) { 227 nvlist_free(hcelem); 228 return (NULL); 229 } 230 231 if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) { 232 nvlist_free(hcelem); 233 return (NULL); 234 } 235 236 if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 || 237 nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 || 238 (partstr != NULL && 239 nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0) || 240 (serialstr != NULL && 241 nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID, 242 serialstr) != 0) || 243 nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 || 244 nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, 1) != 0 || 245 nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, &hcelem, 1) != 0) { 246 nvlist_free(hcelem); 247 nvlist_free(fru); 248 return (NULL); 249 } 250 251 nvlist_free(hcelem); 252 return (fru); 253 } 254 255 nvlist_t * 256 cmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t cert, 257 nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc) 258 { 259 (void) nvlist_add_nvlist(fru, FM_FMRI_AUTHORITY, 260 cmd.cmd_auth); 261 return (fmd_nvl_create_fault(hdl, class, cert, asru, fru, rsrc)); 262 } 263