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*/ 52int 53cmd_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 */ 74cmd_xxcu_trw_t * 75cmd_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*/ 95cmd_errcl_t 96cmd_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*/ 102int 103cmd_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 110const errdata_t l3errdata = 111 { &cmd.cmd_l3data_serd, "l3cachedata", CMD_PTR_CPU_L3DATA }; 112const errdata_t l2errdata = 113 { &cmd.cmd_l2data_serd, "l2cachedata", CMD_PTR_CPU_L2DATA }; 114 115void 116cmd_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*/ 129int 130cmd_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*/ 140int 141cmd_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 158char * 159cmd_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 191char * 192cmd_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*/ 198char * 199cmd_cpu_getpartstr(fmd_hdl_t *hdl, cmd_cpu_t *cp) { 200 return (NULL); 201} 202 203/*ARGSUSED*/ 204char * 205cmd_cpu_getserialstr(fmd_hdl_t *hdl, cmd_cpu_t *cp) { 206 return (NULL); 207} 208 209/*ARGSUSED*/ 210nvlist_t * 211cmd_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 255nvlist_t * 256cmd_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