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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #include <strings.h> 27 #include <sys/fm/io/sun4_fire.h> 28 29 #include "fabric-xlate.h" 30 31 typedef struct fab_fire_tbl { 32 const char *err_class; 33 uint32_t fire_bit; /* Fire error bit */ 34 uint16_t pci_err_sts; /* Equivalent PCI Error Status */ 35 uint16_t pci_bdg_sts; /* Equivalent PCI Bridge Status */ 36 } fab_fire_tbl_t; 37 38 /* 39 * Translation tables for converting fire error bits into "pci" ereports. 40 * <Fire Bit> 41 * <pci ereport Class> 42 * <pci error status reg> 43 * <pci bridge status reg> 44 * <pci target class> 45 */ 46 #define FAB_FIRE_PEC_BIT(fb) "ereport.io." PCIEX_FIRE "." FIRE_PEC_ ## fb 47 #define FAB_FIRE_DMC_BIT(fb) "ereport.io." PCIEX_FIRE "." FIRE_DMC_ ## fb 48 #define FAB_N2_DMU_BIT(fb) "ereport.io.n2.dmu." fb 49 #define FAB_OB_PEC_BIT(fb) "ereport.io." PCIEX_OBERON "." FIRE_PEC_ ## fb 50 51 #define FAB_FIRE_UE(fb, bit, sts, bdg) \ 52 FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, sts, bdg 53 #define FAB_OB_UE(fb, bit, sts, bdg) \ 54 FAB_OB_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, sts, bdg 55 static fab_fire_tbl_t fab_fire_pec_ue_tbl[] = { 56 FAB_FIRE_UE(UR, UR, PCI_STAT_S_SYSERR, 0), 57 FAB_FIRE_UE(UC, UC, PCI_STAT_S_SYSERR, 0), 58 FAB_OB_UE(ECRC, ECRC, PCI_STAT_S_SYSERR, 0), 59 FAB_FIRE_UE(CTO, TO, PCI_STAT_S_SYSERR, 0), 60 FAB_FIRE_UE(ROF, RO, PCI_STAT_S_SYSERR, 0), 61 FAB_FIRE_UE(MFP, MTLP, PCI_STAT_S_SYSERR, 0), 62 FAB_FIRE_UE(PP, PTLP, PCI_STAT_S_PERROR, 63 (PCI_STAT_S_SYSERR | PCI_STAT_PERROR)), 64 FAB_FIRE_UE(FCP, FCP, PCI_STAT_S_SYSERR, 0), 65 FAB_FIRE_UE(DLP, DLP, PCI_STAT_S_SYSERR, 0), 66 FAB_FIRE_UE(TE, TRAINING, PCI_STAT_S_SYSERR, 0), 67 FAB_FIRE_UE(CA, CA, PCI_STAT_S_TARG_AB, 68 PCI_STAT_S_TARG_AB), 69 NULL, 0, 0, 70 }; 71 72 #define FAB_FIRE_CE(fb, bit) \ 73 FAB_FIRE_PEC_BIT(fb), PCIE_AER_CE_ ## bit, 0, 0 74 static fab_fire_tbl_t fab_fire_pec_ce_tbl[] = { 75 FAB_FIRE_CE(RTO, REPLAY_TO), 76 FAB_FIRE_CE(RNR, REPLAY_ROLLOVER), 77 FAB_FIRE_CE(BDP, BAD_DLLP), 78 FAB_FIRE_CE(BTP, BAD_TLP), 79 FAB_FIRE_CE(RE, RECEIVER_ERR), 80 NULL, 0, 0, 81 }; 82 83 /* 84 * WUC/RUC will need to be special cased for the target ereports, because you 85 * need to decode the tlp log. 86 */ 87 #define FAB_FIRE_WUCRUC(fb) \ 88 FAB_FIRE_PEC_BIT(fb), 0, 0, (PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR) 89 #define FAB_FIRE_OE(fb, bit) \ 90 FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, PCI_STAT_S_SYSERR, 0 91 #define FAB_OB_OE(fb, bit) \ 92 FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, PCI_STAT_S_SYSERR, 0 93 static fab_fire_tbl_t fab_fire_pec_oe_tbl[] = { 94 FAB_FIRE_WUCRUC(WUC), 95 FAB_FIRE_WUCRUC(RUC), 96 FAB_FIRE_OE(ERU, DLP), 97 FAB_FIRE_OE(ERO, DLP), 98 FAB_FIRE_OE(EMP, DLP), 99 FAB_FIRE_OE(EPE, DLP), 100 NULL, 0, 0, 101 }; 102 103 #define FAB_FIRE_DMC(fb) \ 104 FAB_FIRE_DMC_BIT(fb), PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB 105 #define FAB_N2_DMU(fb) \ 106 FAB_N2_DMU_BIT(fb), PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB 107 static fab_fire_tbl_t fab_fire_dmc_tbl[] = { 108 FAB_FIRE_DMC(BYP_ERR), 109 FAB_FIRE_DMC(BYP_OOR), 110 FAB_FIRE_DMC(TRN_OOR), 111 FAB_FIRE_DMC(TTE_INV), 112 FAB_FIRE_DMC(TTE_PRT), 113 FAB_N2_DMU("iotsbdesc_inv"), 114 FAB_N2_DMU("sun4v_adj_va_uf"), 115 FAB_N2_DMU("sun4v_inv_pg_sz"), 116 FAB_N2_DMU("sun4v_key_err"), 117 FAB_N2_DMU("sun4v_va_oor"), 118 NULL, 0, 0 119 }; 120 121 /* ARGSUSED */ 122 static void 123 fab_fire_to_data(fmd_hdl_t *hdl, nvlist_t *nvl, fab_data_t *data) 124 { 125 data->nvl = nvl; 126 127 /* Always Root Complex */ 128 data->dev_type = PCIE_PCIECAP_DEV_TYPE_ROOT; 129 130 data->pcie_ue_sev = (PCIE_AER_UCE_DLP | PCIE_AER_UCE_SD | 131 PCIE_AER_UCE_FCP | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP); 132 } 133 134 static int 135 fab_xlate_fire_ce(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt, 136 const char *class) 137 { 138 fab_fire_tbl_t *entry; 139 uint64_t reg; 140 141 for (entry = fab_fire_pec_ce_tbl; entry->err_class; entry++) { 142 if (STRCMP(class, entry->err_class)) 143 goto send; 144 } 145 146 return (0); 147 148 send: 149 fmd_hdl_debug(hdl, "Translate Fire CE %s\n", class); 150 151 /* Fill in the device status register */ 152 data->pcie_err_status = PCIE_DEVSTS_CE_DETECTED; 153 154 /* Fill in the AER CE register */ 155 if (nvlist_lookup_uint64(erpt, "tlu-cess", ®) == 0) { 156 data->pcie_ce_status = (uint32_t)reg | (uint32_t)(reg >> 32); 157 } 158 159 return (1); 160 } 161 162 static int 163 fab_xlate_fire_ue(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt, 164 const char *class) 165 { 166 fab_fire_tbl_t *entry; 167 uint64_t reg; 168 uint32_t temp; 169 pcie_tlp_hdr_t *hdr; 170 171 for (entry = fab_fire_pec_ue_tbl; entry->err_class; entry++) { 172 if (STRCMP(class, entry->err_class)) 173 goto send; 174 } 175 176 return (0); 177 178 send: 179 fmd_hdl_debug(hdl, "Translate Fire UE %s\n", class); 180 181 /* Fill in PCI Status Register */ 182 data->pci_err_status = entry->pci_err_sts; 183 data->pci_bdg_sec_stat = entry->pci_bdg_sts; 184 185 /* Fill in the device status register */ 186 if (entry->fire_bit & data->pcie_ue_sev) 187 data->pcie_err_status = PCIE_DEVSTS_FE_DETECTED; 188 else 189 data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED; 190 191 if (entry->fire_bit == PCIE_AER_UCE_UR) 192 data->pcie_err_status |= PCIE_DEVSTS_UR_DETECTED; 193 194 /* Fill in the AER UE register */ 195 if (nvlist_lookup_uint64(erpt, "tlu-uess", ®) == 0) { 196 data->pcie_ue_status = (uint32_t)reg | (uint32_t)(reg >> 32); 197 } 198 199 /* Fill in the AER Control register */ 200 if ((reg & (uint64_t)entry->fire_bit) && 201 nvlist_lookup_boolean(erpt, "primary")) { 202 temp = entry->fire_bit; 203 for (data->pcie_adv_ctl = (uint32_t)-1; temp; 204 data->pcie_adv_ctl++) 205 temp = temp >> 1; 206 } 207 208 /* If CTO create target information */ 209 if (entry->fire_bit == PCIE_AER_UCE_TO && 210 nvlist_lookup_boolean(erpt, "primary")) { 211 if (nvlist_lookup_uint64(erpt, "tlu-tueh1l", ®) == 0) { 212 data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32); 213 data->pcie_ue_hdr[1] = (uint32_t)(reg); 214 } 215 if (nvlist_lookup_uint64(erpt, "tlu-tueh2l", ®) == 0) { 216 data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32); 217 data->pcie_ue_hdr[3] = (uint32_t)(reg); 218 } 219 220 hdr = (pcie_tlp_hdr_t *)(&data->pcie_ue_hdr[0]); 221 switch (hdr->type) { 222 case PCIE_TLP_TYPE_IO: 223 case PCIE_TLP_TYPE_MEM: 224 case PCIE_TLP_TYPE_MEMLK: 225 data->pcie_ue_tgt_trans = PF_ADDR_PIO; 226 if (hdr->fmt & 0x1) { 227 data->pcie_ue_tgt_addr = reg; 228 } else { 229 data->pcie_ue_tgt_addr = data->pcie_ue_hdr[2]; 230 } 231 break; 232 case PCIE_TLP_TYPE_CFG0: 233 case PCIE_TLP_TYPE_CFG1: 234 data->pcie_ue_tgt_trans = PF_ADDR_CFG; 235 data->pcie_ue_tgt_bdf = data->pcie_ue_hdr[2] >> 16; 236 break; 237 } 238 } 239 240 /* Fill in the AER Header registers */ 241 if (nvlist_lookup_uint64(erpt, "tlu-rueh1l", ®) == 0) { 242 data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32); 243 data->pcie_ue_hdr[1] = (uint32_t)(reg); 244 } 245 if (nvlist_lookup_uint64(erpt, "tlu-rueh2l", ®) == 0) { 246 data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32); 247 data->pcie_ue_hdr[3] = (uint32_t)(reg); 248 } 249 250 return (1); 251 } 252 253 static int 254 fab_xlate_fire_oe(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt, 255 const char *class) 256 { 257 fab_fire_tbl_t *entry; 258 uint64_t reg; 259 260 for (entry = fab_fire_pec_oe_tbl; entry->err_class; entry++) { 261 if (STRCMP(class, entry->err_class)) 262 goto send; 263 } 264 265 return (0); 266 267 send: 268 fmd_hdl_debug(hdl, "Translate Fire OE %s\n", class); 269 270 /* Fill in PCI Status Register */ 271 if (entry->fire_bit) { 272 data->pci_err_status = entry->pci_err_sts; 273 data->pci_bdg_sec_stat = entry->pci_bdg_sts; 274 } else { 275 if (nvlist_lookup_uint64(erpt, "tlu-roeeh1l", ®) == 0) { 276 data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32); 277 data->pcie_ue_hdr[1] = (uint32_t)(reg); 278 } 279 if (nvlist_lookup_uint64(erpt, "tlu-roeeh2l", ®) == 0) { 280 data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32); 281 data->pcie_ue_hdr[3] = (uint32_t)(reg); 282 } 283 284 if (((pcie_tlp_hdr_t *)(&data->pcie_ue_hdr[0]))->type == 285 PCIE_TLP_TYPE_CPL) { 286 pcie_cpl_t *cpl = (pcie_cpl_t *)&data->pcie_ue_hdr[1]; 287 switch (cpl->status) { 288 case PCIE_CPL_STS_UR: 289 data->pci_err_status = 0; 290 data->pci_bdg_sec_stat = PCI_STAT_R_MAST_AB | 291 PCI_STAT_S_SYSERR; 292 break; 293 case PCIE_CPL_STS_CA: 294 data->pci_err_status = 0; 295 data->pci_bdg_sec_stat = PCI_STAT_R_TARG_AB | 296 PCI_STAT_S_SYSERR; 297 break; 298 } 299 } 300 } 301 302 /* Fill in the device status register */ 303 if (entry->fire_bit & data->pcie_ue_sev) 304 data->pcie_err_status = PCIE_DEVSTS_FE_DETECTED; 305 else 306 data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED; 307 308 /* Fill in the AER UE register */ 309 data->pcie_ue_status = entry->fire_bit; 310 311 return (1); 312 } 313 314 static int 315 fab_xlate_fire_dmc(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt, 316 const char *class) 317 { 318 fab_fire_tbl_t *entry; 319 uint64_t reg; 320 uint32_t temp; 321 322 for (entry = fab_fire_dmc_tbl; entry->err_class; entry++) { 323 fmd_hdl_debug(hdl, "Matching %s\n", entry->err_class); 324 if (STRCMP(class, entry->err_class) && 325 nvlist_lookup_boolean(erpt, "primary")) 326 goto send; 327 } 328 329 return (0); 330 331 send: 332 fmd_hdl_debug(hdl, "Translate Fire DMC %s\n", class); 333 334 /* Fill in PCI Status Register */ 335 data->pci_err_status = entry->pci_err_sts; 336 data->pci_bdg_sec_stat = entry->pci_bdg_sts; 337 338 /* Fill in the device status register */ 339 data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED; 340 341 /* Fill in the AER UE register */ 342 data->pcie_ue_status = entry->fire_bit; 343 344 /* Fill in the AER Control register */ 345 temp = entry->fire_bit; 346 for (data->pcie_adv_ctl = (uint32_t)-1; temp; data->pcie_adv_ctl++) 347 temp = temp >> 1; 348 349 /* Fill in the AER Header registers */ 350 if (nvlist_lookup_uint64(erpt, "mmu-tfsr", ®) == 0) { 351 fmd_hdl_debug(hdl, "tfsr 0x%llx\n", reg); 352 /* Get the trans type */ 353 temp = (reg & 0x3F0000) >> 16; 354 data->pcie_ue_hdr[0] = (uint32_t)(temp << 24); 355 data->pcie_ue_tgt_trans = PF_ADDR_DMA; 356 /* Get the req id */ 357 temp = (reg & 0xFFFF); 358 data->pcie_ue_hdr[1] = (uint32_t)(temp << 16); 359 data->pcie_ue_tgt_bdf = temp; 360 } 361 362 if (nvlist_lookup_uint64(erpt, "mmu-tfar", ®) == 0) { 363 fmd_hdl_debug(hdl, "tfar 0x%llx\n", reg); 364 /* Get the address */ 365 data->pcie_ue_hdr[2] = reg; 366 data->pcie_ue_hdr[3] = 0; 367 data->pcie_ue_tgt_addr = reg; 368 } 369 370 fmd_hdl_debug(hdl, "HEADER 0 0x%x\n", data->pcie_ue_hdr[0]); 371 fmd_hdl_debug(hdl, "HEADER 1 0x%x\n", data->pcie_ue_hdr[1]); 372 fmd_hdl_debug(hdl, "HEADER 2 0x%x\n", data->pcie_ue_hdr[2]); 373 fmd_hdl_debug(hdl, "HEADER 3 0x%x\n", data->pcie_ue_hdr[3]); 374 375 return (1); 376 } 377 378 void 379 fab_xlate_fire_erpts(fmd_hdl_t *hdl, nvlist_t *nvl, const char *class) 380 { 381 fab_data_t data = {0}; 382 383 fmd_hdl_debug(hdl, "Fire RC ereport received: %s\n", class); 384 385 fab_fire_to_data(hdl, nvl, &data); 386 387 if (fmd_nvl_class_match(hdl, nvl, "ereport.io.fire.pec.*")) { 388 if (! fab_xlate_fire_ce(hdl, &data, nvl, class) && 389 ! fab_xlate_fire_ue(hdl, &data, nvl, class)) 390 (void) fab_xlate_fire_oe(hdl, &data, nvl, class); 391 } else if (fmd_nvl_class_match(hdl, nvl, "ereport.io.fire.dmc.*") || 392 fmd_nvl_class_match(hdl, nvl, "ereport.io.n2.dmu.*")) 393 (void) fab_xlate_fire_dmc(hdl, &data, nvl, class); 394 395 fab_xlate_pcie_erpts(hdl, &data); 396 } 397