1f8d2de6bSjchu /* 2f8d2de6bSjchu * CDDL HEADER START 3f8d2de6bSjchu * 4f8d2de6bSjchu * The contents of this file are subject to the terms of the 501689544Sjchu * Common Development and Distribution License (the "License"). 601689544Sjchu * You may not use this file except in compliance with the License. 7f8d2de6bSjchu * 8f8d2de6bSjchu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9f8d2de6bSjchu * or http://www.opensolaris.org/os/licensing. 10f8d2de6bSjchu * See the License for the specific language governing permissions 11f8d2de6bSjchu * and limitations under the License. 12f8d2de6bSjchu * 13f8d2de6bSjchu * When distributing Covered Code, include this CDDL HEADER in each 14f8d2de6bSjchu * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15f8d2de6bSjchu * If applicable, add the following below this CDDL HEADER, with the 16f8d2de6bSjchu * fields enclosed by brackets "[]" replaced with your own identifying 17f8d2de6bSjchu * information: Portions Copyright [yyyy] [name of copyright owner] 18f8d2de6bSjchu * 19f8d2de6bSjchu * CDDL HEADER END 20f8d2de6bSjchu */ 21f8d2de6bSjchu /* 2201689544Sjchu * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23f8d2de6bSjchu * Use is subject to license terms. 24f8d2de6bSjchu */ 25f8d2de6bSjchu 26f8d2de6bSjchu #pragma ident "%Z%%M% %I% %E% SMI" 27f8d2de6bSjchu 28f8d2de6bSjchu /* 29f8d2de6bSjchu * sun4v Fire Error Handling 30f8d2de6bSjchu */ 31f8d2de6bSjchu 32f8d2de6bSjchu #include <sys/types.h> 33f8d2de6bSjchu #include <sys/ddi.h> 34f8d2de6bSjchu #include <sys/sunddi.h> 35f8d2de6bSjchu #include <sys/fm/protocol.h> 36f8d2de6bSjchu #include <sys/fm/util.h> 37f8d2de6bSjchu #include <sys/membar.h> 38f8d2de6bSjchu #include "px_obj.h" 39f8d2de6bSjchu #include "px_err.h" 40f8d2de6bSjchu 41*bf8fc234Set static void px_err_fill_pf_data(dev_info_t *dip, px_t *px_p, px_rc_err_t *epkt); 42*bf8fc234Set static uint_t px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt); 43*bf8fc234Set static int px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, 44f8d2de6bSjchu px_rc_err_t *epkt, int caller); 45f8d2de6bSjchu 46*bf8fc234Set static void px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt, 47*bf8fc234Set boolean_t is_block_pci, char *msg); 48*bf8fc234Set static int px_cb_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, 49*bf8fc234Set px_rc_err_t *epkt); 50*bf8fc234Set static int px_mmu_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, 51*bf8fc234Set px_rc_err_t *epkt); 52*bf8fc234Set static int px_intr_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, 53*bf8fc234Set px_rc_err_t *epkt); 54*bf8fc234Set static int px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, 55*bf8fc234Set px_rc_err_t *epkt); 56*bf8fc234Set static int px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, 57*bf8fc234Set px_rc_err_t *epkt); 58*bf8fc234Set static void px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr, 59*bf8fc234Set px_rc_err_t *epkt); 60*bf8fc234Set static int px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr, 61*bf8fc234Set px_rc_err_t *epkt); 62*bf8fc234Set 63*bf8fc234Set /* Include the code generated sun4v epkt checking code */ 64*bf8fc234Set #include "px_err_gen.c" 65*bf8fc234Set 66*bf8fc234Set /* 67*bf8fc234Set * This variable indicates if we have a hypervisor that could potentially send 68*bf8fc234Set * incorrect epkts. We always set this to TRUE for now until we find a way to 69*bf8fc234Set * tell if this HV bug has been fixed. 70*bf8fc234Set */ 71*bf8fc234Set boolean_t px_legacy_epkt = B_TRUE; 72f8d2de6bSjchu 73f8d2de6bSjchu /* 74f8d2de6bSjchu * px_err_cb_intr: 75f8d2de6bSjchu * Interrupt handler for the Host Bus Block. 76f8d2de6bSjchu */ 77f8d2de6bSjchu uint_t 78f8d2de6bSjchu px_err_cb_intr(caddr_t arg) 79f8d2de6bSjchu { 80f8d2de6bSjchu px_fault_t *fault_p = (px_fault_t *)arg; 81f8d2de6bSjchu px_rc_err_t *epkt = (px_rc_err_t *)fault_p->px_intr_payload; 82f8d2de6bSjchu 83f8d2de6bSjchu if (epkt != NULL) { 84*bf8fc234Set return (px_err_intr(fault_p, epkt)); 85f8d2de6bSjchu } 86f8d2de6bSjchu 87f8d2de6bSjchu return (DDI_INTR_UNCLAIMED); 88f8d2de6bSjchu } 89f8d2de6bSjchu 90f8d2de6bSjchu /* 91f8d2de6bSjchu * px_err_dmc_pec_intr: 92f8d2de6bSjchu * Interrupt handler for the DMC/PEC block. 93f8d2de6bSjchu */ 94f8d2de6bSjchu uint_t 95f8d2de6bSjchu px_err_dmc_pec_intr(caddr_t arg) 96f8d2de6bSjchu { 97f8d2de6bSjchu px_fault_t *fault_p = (px_fault_t *)arg; 98f8d2de6bSjchu px_rc_err_t *epkt = (px_rc_err_t *)fault_p->px_intr_payload; 99f8d2de6bSjchu 100f8d2de6bSjchu if (epkt != NULL) { 101*bf8fc234Set return (px_err_intr(fault_p, epkt)); 102f8d2de6bSjchu } 103f8d2de6bSjchu 104f8d2de6bSjchu return (DDI_INTR_UNCLAIMED); 105f8d2de6bSjchu } 106f8d2de6bSjchu 107f8d2de6bSjchu /* 108*bf8fc234Set * px_err_cmn_intr: 109f8d2de6bSjchu * Common function called by trap, mondo and fabric intr. 110f8d2de6bSjchu * This function is more meaningful in sun4u implementation. Kept 111f8d2de6bSjchu * to mirror sun4u call stack. 112f8d2de6bSjchu * o check for safe access 113*bf8fc234Set * o create and queue RC info for later use in fabric scan. 114*bf8fc234Set * o RUC/WUC, PTLP, MMU Errors(CA), UR 115f8d2de6bSjchu * 116f8d2de6bSjchu * @param px_p leaf in which to check access 117f8d2de6bSjchu * @param derr fm err data structure to be updated 118f8d2de6bSjchu * @param caller PX_TRAP_CALL | PX_INTR_CALL 119f8d2de6bSjchu * @param chkjbc whether to handle hostbus registers (ignored) 120*bf8fc234Set * @return err PX_NO_PANIC | PX_PROTECTED | 121*bf8fc234Set * PX_PANIC | PX_HW_RESET | PX_EXPECTED 122f8d2de6bSjchu */ 123f8d2de6bSjchu /* ARGSUSED */ 124f8d2de6bSjchu int 125*bf8fc234Set px_err_cmn_intr(px_t *px_p, ddi_fm_error_t *derr, int caller, int block) 126f8d2de6bSjchu { 127f8d2de6bSjchu px_err_safeacc_check(px_p, derr); 128e51949e6Sdduvall return (DDI_FM_OK); 1293d9c56a1Set } 1303d9c56a1Set 1313d9c56a1Set /* 132*bf8fc234Set * fills RC specific fault data 133*bf8fc234Set */ 134*bf8fc234Set static void 135*bf8fc234Set px_err_fill_pfd(dev_info_t *dip, px_t *px_p, px_rc_err_t *epkt) { 136*bf8fc234Set pf_data_t pf_data = {0}; 137*bf8fc234Set int sts = DDI_SUCCESS; 138*bf8fc234Set pcie_req_id_t fault_bdf = 0; 139*bf8fc234Set uint32_t fault_addr = 0; 140*bf8fc234Set uint16_t s_status = 0; 141*bf8fc234Set 142*bf8fc234Set /* Add an PCIE PF_DATA Entry */ 143*bf8fc234Set if (epkt->rc_descr.block == BLOCK_MMU) { 144*bf8fc234Set /* Only PIO Fault Addresses are valid, this is DMA */ 145*bf8fc234Set s_status = PCI_STAT_S_TARG_AB; 146*bf8fc234Set fault_addr = NULL; 147*bf8fc234Set 148*bf8fc234Set if (epkt->rc_descr.H) 149*bf8fc234Set fault_bdf = (pcie_req_id_t)(epkt->hdr[0] >> 16); 150*bf8fc234Set else 151*bf8fc234Set sts = DDI_FAILURE; 152*bf8fc234Set } else { 153*bf8fc234Set px_pec_err_t *pec_p = (px_pec_err_t *)epkt; 154*bf8fc234Set uint32_t trans_type; 155*bf8fc234Set uint32_t dir = pec_p->pec_descr.dir; 156*bf8fc234Set 157*bf8fc234Set pf_data.aer_h0 = (uint32_t)(pec_p->hdr[0]); 158*bf8fc234Set pf_data.aer_h1 = (uint32_t)(pec_p->hdr[0] >> 32); 159*bf8fc234Set pf_data.aer_h2 = (uint32_t)(pec_p->hdr[1]); 160*bf8fc234Set pf_data.aer_h3 = (uint32_t)(pec_p->hdr[1] >> 32); 161*bf8fc234Set 162*bf8fc234Set /* translate RC UR/CA to legacy secondary errors */ 163*bf8fc234Set if ((dir == DIR_READ || dir == DIR_WRITE) && 164*bf8fc234Set pec_p->pec_descr.U) { 165*bf8fc234Set if (pec_p->ue_reg_status & PCIE_AER_UCE_UR) 166*bf8fc234Set s_status |= PCI_STAT_R_MAST_AB; 167*bf8fc234Set if (pec_p->ue_reg_status | PCIE_AER_UCE_CA) 168*bf8fc234Set s_status |= PCI_STAT_R_TARG_AB; 169*bf8fc234Set } 170*bf8fc234Set 171*bf8fc234Set if (pec_p->ue_reg_status & PCIE_AER_UCE_PTLP) 172*bf8fc234Set s_status |= PCI_STAT_PERROR; 173*bf8fc234Set 174*bf8fc234Set if (pec_p->ue_reg_status & PCIE_AER_UCE_CA) 175*bf8fc234Set s_status |= PCI_STAT_S_TARG_AB; 176*bf8fc234Set 177*bf8fc234Set sts = pf_tlp_decode(dip, &pf_data, &fault_bdf, &fault_addr, 178*bf8fc234Set &trans_type); 179*bf8fc234Set } 180*bf8fc234Set 181*bf8fc234Set if (sts == DDI_SUCCESS) 182*bf8fc234Set px_rp_en_q(px_p, fault_bdf, fault_addr, s_status); 183*bf8fc234Set } 184*bf8fc234Set 185*bf8fc234Set /* 186*bf8fc234Set * px_err_intr: 187f8d2de6bSjchu * Interrupt handler for the JBC/DMC/PEC block. 188f8d2de6bSjchu * o lock 189f8d2de6bSjchu * o create derr 190f8d2de6bSjchu * o check safe access 191*bf8fc234Set * o px_err_check_severity(epkt) 192*bf8fc234Set * o pcie_scan_fabric 193f8d2de6bSjchu * o Idle intr state 194f8d2de6bSjchu * o unlock 195f8d2de6bSjchu * o handle error: fatal? fm_panic() : return INTR_CLAIMED) 196f8d2de6bSjchu */ 197f8d2de6bSjchu static uint_t 198*bf8fc234Set px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt) 199f8d2de6bSjchu { 200f8d2de6bSjchu px_t *px_p = DIP_TO_STATE(fault_p->px_fh_dip); 201f8d2de6bSjchu dev_info_t *rpdip = px_p->px_dip; 202*bf8fc234Set int rc_err, fab_err = PF_NO_PANIC, msg; 203f8d2de6bSjchu ddi_fm_error_t derr; 204f8d2de6bSjchu 20501689544Sjchu mutex_enter(&px_p->px_fm_mutex); 206f8d2de6bSjchu 207f8d2de6bSjchu /* Create the derr */ 208f8d2de6bSjchu bzero(&derr, sizeof (ddi_fm_error_t)); 209f8d2de6bSjchu derr.fme_version = DDI_FME_VERSION; 210f8d2de6bSjchu derr.fme_ena = fm_ena_generate(epkt->stick, FM_ENA_FMT1); 211f8d2de6bSjchu derr.fme_flag = DDI_FM_ERR_UNEXPECTED; 212f8d2de6bSjchu 213f8d2de6bSjchu /* Basically check for safe access */ 214*bf8fc234Set (void) px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_ALL); 215f8d2de6bSjchu 216f8d2de6bSjchu /* Check the severity of this error */ 217*bf8fc234Set rc_err = px_err_epkt_severity(px_p, &derr, epkt, PX_INTR_CALL); 218f8d2de6bSjchu 219*bf8fc234Set /* Scan the fabric if the root port is not in drain state. */ 220*bf8fc234Set if (!px_lib_is_in_drain_state(px_p)) 221*bf8fc234Set fab_err = pf_scan_fabric(rpdip, &derr, px_p->px_dq_p, 222*bf8fc234Set &px_p->px_dq_tail); 223f8d2de6bSjchu 224f8d2de6bSjchu /* Set the intr state to idle for the leaf that received the mondo */ 225f8d2de6bSjchu if (px_lib_intr_setstate(rpdip, fault_p->px_fh_sysino, 226f8d2de6bSjchu INTR_IDLE_STATE) != DDI_SUCCESS) { 22701689544Sjchu mutex_exit(&px_p->px_fm_mutex); 228f8d2de6bSjchu return (DDI_INTR_UNCLAIMED); 229f8d2de6bSjchu } 230f8d2de6bSjchu 23101689544Sjchu mutex_exit(&px_p->px_fm_mutex); 232f8d2de6bSjchu 233*bf8fc234Set switch (epkt->rc_descr.block) { 234*bf8fc234Set case BLOCK_MMU: /* FALLTHROUGH */ 235*bf8fc234Set case BLOCK_INTR: 236*bf8fc234Set msg = PX_RC; 237*bf8fc234Set break; 238*bf8fc234Set case BLOCK_PCIE: 239*bf8fc234Set msg = PX_RP; 240*bf8fc234Set break; 241*bf8fc234Set case BLOCK_HOSTBUS: /* FALLTHROUGH */ 242*bf8fc234Set default: 243*bf8fc234Set msg = PX_HB; 244*bf8fc234Set break; 245*bf8fc234Set } 246*bf8fc234Set 247*bf8fc234Set px_err_panic(rc_err, msg, fab_err); 248f8d2de6bSjchu 249f8d2de6bSjchu return (DDI_INTR_CLAIMED); 250f8d2de6bSjchu } 251f8d2de6bSjchu 252f8d2de6bSjchu /* 253*bf8fc234Set * px_err_epkt_severity: 254f8d2de6bSjchu * Check the severity of the fire error based the epkt received 255f8d2de6bSjchu * 256f8d2de6bSjchu * @param px_p leaf in which to take the snap shot. 257f8d2de6bSjchu * @param derr fm err in which the ereport is to be based on 258f8d2de6bSjchu * @param epkt epkt recevied from HV 259f8d2de6bSjchu */ 260f8d2de6bSjchu static int 261*bf8fc234Set px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt, 262f8d2de6bSjchu int caller) 263f8d2de6bSjchu { 264f8d2de6bSjchu px_pec_t *pec_p = px_p->px_pec_p; 265f8d2de6bSjchu dev_info_t *dip = px_p->px_dip; 266*bf8fc234Set boolean_t is_safeacc = B_FALSE; 267*bf8fc234Set boolean_t is_block_pci = B_FALSE; 268*bf8fc234Set char buf[FM_MAX_CLASS], descr_buf[1024]; 269f8d2de6bSjchu int err = 0; 270f8d2de6bSjchu 271f8d2de6bSjchu /* Cautious access error handling */ 272*bf8fc234Set switch (derr->fme_flag) { 273*bf8fc234Set case DDI_FM_ERR_EXPECTED: 274f8d2de6bSjchu if (caller == PX_TRAP_CALL) { 275f8d2de6bSjchu /* 276f8d2de6bSjchu * for ddi_caut_get treat all events as nonfatal 277f8d2de6bSjchu * The trampoline will set err_ena = 0, 278f8d2de6bSjchu * err_status = NONFATAL. 279f8d2de6bSjchu */ 280f8d2de6bSjchu derr->fme_status = DDI_FM_NONFATAL; 281*bf8fc234Set is_safeacc = B_TRUE; 282f8d2de6bSjchu } else { 283f8d2de6bSjchu /* 284f8d2de6bSjchu * For ddi_caut_put treat all events as nonfatal. Here 285f8d2de6bSjchu * we have the handle and can call ndi_fm_acc_err_set(). 286f8d2de6bSjchu */ 287f8d2de6bSjchu derr->fme_status = DDI_FM_NONFATAL; 288f8d2de6bSjchu ndi_fm_acc_err_set(pec_p->pec_acc_hdl, derr); 289*bf8fc234Set is_safeacc = B_TRUE; 290f8d2de6bSjchu } 291*bf8fc234Set break; 292*bf8fc234Set case DDI_FM_ERR_PEEK: 293*bf8fc234Set case DDI_FM_ERR_POKE: 294*bf8fc234Set /* 295*bf8fc234Set * For ddi_peek/poke treat all events as nonfatal. 296*bf8fc234Set */ 297*bf8fc234Set is_safeacc = B_TRUE; 298*bf8fc234Set break; 299*bf8fc234Set default: 300*bf8fc234Set is_safeacc = B_FALSE; 301f8d2de6bSjchu } 302f8d2de6bSjchu 303*bf8fc234Set /* 304*bf8fc234Set * Older hypervisors in some cases send epkts with incorrect fields. 305*bf8fc234Set * We have to handle these "special" epkts correctly. 306*bf8fc234Set */ 307*bf8fc234Set if (px_legacy_epkt) 308*bf8fc234Set px_fix_legacy_epkt(dip, derr, epkt); 309*bf8fc234Set 310f8d2de6bSjchu switch (epkt->rc_descr.block) { 311f8d2de6bSjchu case BLOCK_HOSTBUS: 312*bf8fc234Set err = px_cb_epkt_severity(dip, derr, epkt); 313f8d2de6bSjchu break; 314f8d2de6bSjchu case BLOCK_MMU: 315*bf8fc234Set err = px_mmu_epkt_severity(dip, derr, epkt); 316*bf8fc234Set px_err_fill_pfd(dip, px_p, epkt); 317f8d2de6bSjchu break; 318f8d2de6bSjchu case BLOCK_INTR: 319*bf8fc234Set err = px_intr_epkt_severity(dip, derr, epkt); 320f8d2de6bSjchu break; 321f8d2de6bSjchu case BLOCK_PCIE: 322*bf8fc234Set is_block_pci = B_TRUE; 323*bf8fc234Set err = px_pcie_epkt_severity(dip, derr, epkt); 324*bf8fc234Set px_err_fill_pfd(dip, px_p, epkt); 325f8d2de6bSjchu break; 326f8d2de6bSjchu default: 327*bf8fc234Set err = 0; 328f8d2de6bSjchu } 329f8d2de6bSjchu 330*bf8fc234Set if ((err & PX_HW_RESET) || (err & PX_PANIC)) { 331*bf8fc234Set if (px_log & PX_PANIC) 332*bf8fc234Set px_err_log_handle(dip, epkt, is_block_pci, "PANIC"); 333*bf8fc234Set } else if (err & PX_PROTECTED) { 334*bf8fc234Set if (px_log & PX_PROTECTED) 335*bf8fc234Set px_err_log_handle(dip, epkt, is_block_pci, "PROTECTED"); 336*bf8fc234Set } else if (err & PX_NO_PANIC) { 337*bf8fc234Set if (px_log & PX_NO_PANIC) 338*bf8fc234Set px_err_log_handle(dip, epkt, is_block_pci, "NO PANIC"); 339*bf8fc234Set } else if (err & PX_NO_ERROR) { 340*bf8fc234Set if (px_log & PX_NO_ERROR) 341*bf8fc234Set px_err_log_handle(dip, epkt, is_block_pci, "NO ERROR"); 342*bf8fc234Set } else if (err == 0) { 343*bf8fc234Set px_err_log_handle(dip, epkt, is_block_pci, "UNRECOGNIZED"); 344*bf8fc234Set 345*bf8fc234Set /* Unrecognized epkt. send ereport */ 346*bf8fc234Set (void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_RC_UNRECOG); 347*bf8fc234Set 348*bf8fc234Set if (is_block_pci) { 349*bf8fc234Set px_pec_err_t *pec = (px_pec_err_t *)epkt; 350*bf8fc234Set 351*bf8fc234Set (void) snprintf(descr_buf, sizeof (descr_buf), 352*bf8fc234Set "Epkt contents:\n" 353*bf8fc234Set "Block: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d\n" 354*bf8fc234Set "I=%d, H=%d, C=%d, U=%d, E=%d, P=%d\n" 355*bf8fc234Set "PCI Err Status: 0x%x, PCIe Err Status: 0x%x\n" 356*bf8fc234Set "CE Status Reg: 0x%x, UE Status Reg: 0x%x\n" 357*bf8fc234Set "HDR1: 0x%lx, HDR2: 0x%lx\n" 358*bf8fc234Set "Err Src Reg: 0x%x, Root Err Status: 0x%x\n", 359*bf8fc234Set pec->pec_descr.block, pec->pec_descr.dir, 360*bf8fc234Set pec->pec_descr.Z, pec->pec_descr.S, 361*bf8fc234Set pec->pec_descr.R, pec->pec_descr.I, 362*bf8fc234Set pec->pec_descr.H, pec->pec_descr.C, 363*bf8fc234Set pec->pec_descr.U, pec->pec_descr.E, 364*bf8fc234Set pec->pec_descr.P, pec->pci_err_status, 365*bf8fc234Set pec->pcie_err_status, pec->ce_reg_status, 366*bf8fc234Set pec->ue_reg_status, pec->hdr[0], 367*bf8fc234Set pec->hdr[1], pec->err_src_reg, 368*bf8fc234Set pec->root_err_status); 369*bf8fc234Set 370*bf8fc234Set ddi_fm_ereport_post(dip, buf, derr->fme_ena, 371*bf8fc234Set DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 372*bf8fc234Set EPKT_SYSINO, DATA_TYPE_UINT64, pec->sysino, 373*bf8fc234Set EPKT_EHDL, DATA_TYPE_UINT64, pec->ehdl, 374*bf8fc234Set EPKT_STICK, DATA_TYPE_UINT64, pec->stick, 375*bf8fc234Set EPKT_PEC_DESCR, DATA_TYPE_STRING, descr_buf); 376*bf8fc234Set } else { 377*bf8fc234Set (void) snprintf(descr_buf, sizeof (descr_buf), 378*bf8fc234Set "Epkt contents:\n" 379*bf8fc234Set "Block: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n" 380*bf8fc234Set "Dir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d\n" 381*bf8fc234Set "M=%d, S=%d, Size: 0x%x, Addr: 0x%lx\n" 382*bf8fc234Set "Hdr1: 0x%lx, Hdr2: 0x%lx, Res: 0x%lx\n", 383*bf8fc234Set epkt->rc_descr.block, epkt->rc_descr.op, 384*bf8fc234Set epkt->rc_descr.phase, epkt->rc_descr.cond, 385*bf8fc234Set epkt->rc_descr.dir, epkt->rc_descr.STOP, 386*bf8fc234Set epkt->rc_descr.H, epkt->rc_descr.R, 387*bf8fc234Set epkt->rc_descr.D, epkt->rc_descr.M, 388*bf8fc234Set epkt->rc_descr.S, epkt->size, epkt->addr, 389*bf8fc234Set epkt->hdr[0], epkt->hdr[1], epkt->reserved); 390*bf8fc234Set 391*bf8fc234Set ddi_fm_ereport_post(dip, buf, derr->fme_ena, 392*bf8fc234Set DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 393*bf8fc234Set EPKT_SYSINO, DATA_TYPE_UINT64, epkt->sysino, 394*bf8fc234Set EPKT_EHDL, DATA_TYPE_UINT64, epkt->ehdl, 395*bf8fc234Set EPKT_STICK, DATA_TYPE_UINT64, epkt->stick, 396*bf8fc234Set EPKT_RC_DESCR, DATA_TYPE_STRING, descr_buf); 397*bf8fc234Set } 398*bf8fc234Set 399*bf8fc234Set err = PX_PANIC; 400*bf8fc234Set } 401*bf8fc234Set 402*bf8fc234Set /* Readjust the severity as a result of safe access */ 403*bf8fc234Set if (is_safeacc && !(err & PX_PANIC) && !(px_die & PX_PROTECTED)) 404*bf8fc234Set err = PX_NO_PANIC; 405*bf8fc234Set 406f8d2de6bSjchu return (err); 407f8d2de6bSjchu } 408f8d2de6bSjchu 409*bf8fc234Set static void 410*bf8fc234Set px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt, boolean_t is_block_pci, 411*bf8fc234Set char *msg) 412*bf8fc234Set { 413*bf8fc234Set if (is_block_pci) { 414*bf8fc234Set px_pec_err_t *pec = (px_pec_err_t *)epkt; 415*bf8fc234Set DBG(DBG_ERR_INTR, dip, 416*bf8fc234Set "A PCIe root port error has occured with a severity" 417*bf8fc234Set " \"%s\"\n" 418*bf8fc234Set "\tBlock: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d, I=%d\n" 419*bf8fc234Set "\tH=%d, C=%d, U=%d, E=%d, P=%d\n" 420*bf8fc234Set "\tpci_err: 0x%x, pcie_err=0x%x, ce_reg: 0x%x\n" 421*bf8fc234Set "\tue_reg: 0x%x, Hdr1: 0x%p, Hdr2: 0x%p\n" 422*bf8fc234Set "\terr_src: 0x%x, root_err: 0x%x\n", 423*bf8fc234Set msg, pec->pec_descr.block, pec->pec_descr.dir, 424*bf8fc234Set pec->pec_descr.Z, pec->pec_descr.S, pec->pec_descr.R, 425*bf8fc234Set pec->pec_descr.I, pec->pec_descr.H, pec->pec_descr.C, 426*bf8fc234Set pec->pec_descr.U, pec->pec_descr.E, pec->pec_descr.P, 427*bf8fc234Set pec->pci_err_status, pec->pcie_err_status, 428*bf8fc234Set pec->ce_reg_status, pec->ue_reg_status, pec->hdr[0], 429*bf8fc234Set pec->hdr[1], pec->err_src_reg, pec->root_err_status); 430*bf8fc234Set } else { 431*bf8fc234Set DBG(DBG_ERR_INTR, dip, 432*bf8fc234Set "A PCIe root complex error has occured with a severity" 433*bf8fc234Set " \"%s\"\n" 434*bf8fc234Set "\tBlock: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n" 435*bf8fc234Set "\tDir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d, M=%d\n" 436*bf8fc234Set "\tS=%d, Size: 0x%x, Addr: 0x%p\n" 437*bf8fc234Set "\tHdr1: 0x%p, Hdr2: 0x%p, Res: 0x%p\n", 438*bf8fc234Set msg, epkt->rc_descr.block, epkt->rc_descr.op, 439*bf8fc234Set epkt->rc_descr.phase, epkt->rc_descr.cond, 440*bf8fc234Set epkt->rc_descr.dir, epkt->rc_descr.STOP, epkt->rc_descr.H, 441*bf8fc234Set epkt->rc_descr.R, epkt->rc_descr.D, epkt->rc_descr.M, 442*bf8fc234Set epkt->rc_descr.S, epkt->size, epkt->addr, epkt->hdr[0], 443*bf8fc234Set epkt->hdr[1], epkt->reserved); 444*bf8fc234Set } 445*bf8fc234Set } 446*bf8fc234Set 447f8d2de6bSjchu /* ARGSUSED */ 448*bf8fc234Set static void 449*bf8fc234Set px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt) 450f8d2de6bSjchu { 451*bf8fc234Set /* 452*bf8fc234Set * We don't have a default case for any of the below switch statements 453*bf8fc234Set * since we are ok with the code falling through. 454*bf8fc234Set */ 455*bf8fc234Set switch (epkt->rc_descr.block) { 456*bf8fc234Set case BLOCK_HOSTBUS: 457*bf8fc234Set switch (epkt->rc_descr.op) { 458*bf8fc234Set case OP_DMA: 459*bf8fc234Set switch (epkt->rc_descr.phase) { 460*bf8fc234Set case PH_UNKNOWN: 461*bf8fc234Set switch (epkt->rc_descr.cond) { 462*bf8fc234Set case CND_UNKNOWN: 463*bf8fc234Set switch (epkt->rc_descr.dir) { 464*bf8fc234Set case DIR_RESERVED: 465*bf8fc234Set epkt->rc_descr.dir = DIR_READ; 466*bf8fc234Set break; 467*bf8fc234Set } /* DIR */ 468*bf8fc234Set } /* CND */ 469*bf8fc234Set } /* PH */ 470*bf8fc234Set } /* OP */ 471f8d2de6bSjchu break; 472*bf8fc234Set case BLOCK_MMU: 473*bf8fc234Set switch (epkt->rc_descr.op) { 474*bf8fc234Set case OP_XLAT: 475*bf8fc234Set switch (epkt->rc_descr.phase) { 476*bf8fc234Set case PH_DATA: 477*bf8fc234Set switch (epkt->rc_descr.cond) { 478*bf8fc234Set case CND_PROT: 479*bf8fc234Set switch (epkt->rc_descr.dir) { 480*bf8fc234Set case DIR_UNKNOWN: 481*bf8fc234Set epkt->rc_descr.dir = DIR_WRITE; 482*bf8fc234Set break; 483*bf8fc234Set } /* DIR */ 484*bf8fc234Set } /* CND */ 4853d9c56a1Set break; 486*bf8fc234Set case PH_IRR: 487*bf8fc234Set switch (epkt->rc_descr.cond) { 488*bf8fc234Set case CND_RESERVED: 489*bf8fc234Set switch (epkt->rc_descr.dir) { 490*bf8fc234Set case DIR_IRR: 491*bf8fc234Set epkt->rc_descr.phase = PH_ADDR; 492*bf8fc234Set epkt->rc_descr.cond = CND_IRR; 493*bf8fc234Set } /* DIR */ 494*bf8fc234Set } /* CND */ 495*bf8fc234Set } /* PH */ 496*bf8fc234Set } /* OP */ 497e51949e6Sdduvall break; 498*bf8fc234Set case BLOCK_INTR: 499*bf8fc234Set switch (epkt->rc_descr.op) { 500*bf8fc234Set case OP_MSIQ: 501*bf8fc234Set switch (epkt->rc_descr.phase) { 502*bf8fc234Set case PH_UNKNOWN: 503*bf8fc234Set switch (epkt->rc_descr.cond) { 504*bf8fc234Set case CND_ILL: 505*bf8fc234Set switch (epkt->rc_descr.dir) { 506*bf8fc234Set case DIR_RESERVED: 507*bf8fc234Set epkt->rc_descr.dir = DIR_IRR; 508*bf8fc234Set break; 509*bf8fc234Set } /* DIR */ 510*bf8fc234Set break; 511*bf8fc234Set case CND_IRR: 512*bf8fc234Set switch (epkt->rc_descr.dir) { 513*bf8fc234Set case DIR_IRR: 514*bf8fc234Set epkt->rc_descr.cond = CND_OV; 515*bf8fc234Set break; 516*bf8fc234Set } /* DIR */ 517*bf8fc234Set } /* CND */ 518*bf8fc234Set } /* PH */ 519*bf8fc234Set break; 520*bf8fc234Set case OP_RESERVED: 521*bf8fc234Set switch (epkt->rc_descr.phase) { 522*bf8fc234Set case PH_UNKNOWN: 523*bf8fc234Set switch (epkt->rc_descr.cond) { 524*bf8fc234Set case CND_ILL: 525*bf8fc234Set switch (epkt->rc_descr.dir) { 526*bf8fc234Set case DIR_IRR: 527*bf8fc234Set epkt->rc_descr.op = OP_MSI32; 528*bf8fc234Set epkt->rc_descr.phase = PH_DATA; 529*bf8fc234Set break; 530*bf8fc234Set } /* DIR */ 531*bf8fc234Set } /* CND */ 532*bf8fc234Set break; 533*bf8fc234Set case PH_DATA: 534*bf8fc234Set switch (epkt->rc_descr.cond) { 535*bf8fc234Set case CND_INT: 536*bf8fc234Set switch (epkt->rc_descr.dir) { 537*bf8fc234Set case DIR_UNKNOWN: 538*bf8fc234Set epkt->rc_descr.op = OP_MSI32; 539*bf8fc234Set break; 540*bf8fc234Set } /* DIR */ 541*bf8fc234Set } /* CND */ 542*bf8fc234Set } /* PH */ 543*bf8fc234Set } /* OP */ 544*bf8fc234Set } /* BLOCK */ 545*bf8fc234Set } 5463d9c56a1Set 547*bf8fc234Set /* ARGSUSED */ 548*bf8fc234Set static int 549*bf8fc234Set px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt) 550*bf8fc234Set { 551*bf8fc234Set return (px_err_check_eq(dip)); 552*bf8fc234Set } 553*bf8fc234Set 554*bf8fc234Set /* ARGSUSED */ 555*bf8fc234Set static int 556*bf8fc234Set px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt) 557*bf8fc234Set { 558*bf8fc234Set px_pec_err_t *pec = (px_pec_err_t *)epkt; 559*bf8fc234Set px_err_pcie_t *pcie = (px_err_pcie_t *)epkt; 560*bf8fc234Set pf_data_t pf_data; 561*bf8fc234Set int x; 562*bf8fc234Set uint32_t temp; 563f8d2de6bSjchu 564f8d2de6bSjchu /* 565*bf8fc234Set * Check for failed PIO Read/Writes, which are errors that are not 566*bf8fc234Set * defined in the PCIe spec. 567f8d2de6bSjchu */ 568*bf8fc234Set temp = PCIE_AER_UCE_UR | PCIE_AER_UCE_CA; 569*bf8fc234Set if (((pec->pec_descr.dir == DIR_READ) || (pec->pec_descr.dir == 570*bf8fc234Set DIR_WRITE)) && pec->pec_descr.U && (pec->ue_reg_status == temp)) { 571*bf8fc234Set pf_data.aer_h0 = (uint32_t)(pec->hdr[0]); 572*bf8fc234Set pf_data.aer_h1 = (uint32_t)(pec->hdr[0] >> 32); 573*bf8fc234Set pf_data.aer_h2 = (uint32_t)(pec->hdr[1]); 574*bf8fc234Set pf_data.aer_h3 = (uint32_t)(pec->hdr[1] >> 32); 575*bf8fc234Set 576*bf8fc234Set if (pf_tlp_hdl_lookup(dip, derr, &pf_data) != DDI_FM_UNKNOWN) 577*bf8fc234Set return (PX_NO_PANIC); 578f8d2de6bSjchu else 579*bf8fc234Set return (PX_PANIC); 580f8d2de6bSjchu } 581f8d2de6bSjchu 582*bf8fc234Set if (!pec->pec_descr.C) 583*bf8fc234Set pec->ce_reg_status = 0; 584*bf8fc234Set if (!pec->pec_descr.U) 585*bf8fc234Set pec->ue_reg_status = 0; 586*bf8fc234Set if (!pec->pec_descr.H) 587*bf8fc234Set pec->hdr[0] = 0; 588*bf8fc234Set if (!pec->pec_descr.I) 589*bf8fc234Set pec->hdr[1] = 0; 590f8d2de6bSjchu 591*bf8fc234Set /* 592*bf8fc234Set * According to the PCIe spec, there is a first error pointer. If there 593*bf8fc234Set * are header logs recorded and there are more than one error, the log 594*bf8fc234Set * will belong to the error that the first error pointer points to. 595*bf8fc234Set * 596*bf8fc234Set * The regs.primary_ue expects a bit number, go through the ue register 597*bf8fc234Set * and find the first error that occured. Because the sun4v epkt spec 598*bf8fc234Set * does not define this value, the algorithm below gives the lower bit 599*bf8fc234Set * priority. 600*bf8fc234Set */ 601*bf8fc234Set temp = pcie->ue_reg; 602*bf8fc234Set if (temp) { 603*bf8fc234Set for (x = 0; !(temp & 0x1); x++) { 604*bf8fc234Set temp = temp >> 1; 605*bf8fc234Set } 606*bf8fc234Set pcie->primary_ue = 1 << x; 607*bf8fc234Set } else { 608*bf8fc234Set pcie->primary_ue = 0; 6093d9c56a1Set } 610f8d2de6bSjchu 611*bf8fc234Set /* Sun4v doesn't log the TX hdr except for CTOs */ 612*bf8fc234Set if (pcie->primary_ue == PCIE_AER_UCE_TO) { 613*bf8fc234Set pcie->tx_hdr1 = pcie->rx_hdr1; 614*bf8fc234Set pcie->tx_hdr2 = pcie->rx_hdr2; 615*bf8fc234Set pcie->tx_hdr3 = pcie->rx_hdr3; 616*bf8fc234Set pcie->tx_hdr4 = pcie->rx_hdr4; 617*bf8fc234Set pcie->rx_hdr1 = 0; 618*bf8fc234Set pcie->rx_hdr2 = 0; 619*bf8fc234Set pcie->rx_hdr3 = 0; 620*bf8fc234Set pcie->rx_hdr4 = 0; 621*bf8fc234Set } else { 622*bf8fc234Set pcie->tx_hdr1 = 0; 623*bf8fc234Set pcie->tx_hdr2 = 0; 624*bf8fc234Set pcie->tx_hdr3 = 0; 625*bf8fc234Set pcie->tx_hdr4 = 0; 626*bf8fc234Set } 627e51949e6Sdduvall 628*bf8fc234Set return (px_err_check_pcie(dip, derr, pcie)); 629f8d2de6bSjchu } 630f8d2de6bSjchu 631f8d2de6bSjchu static int 632*bf8fc234Set px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt) 633f8d2de6bSjchu { 634*bf8fc234Set uint32_t addr = (uint32_t)epkt->addr; 635*bf8fc234Set pcie_req_id_t bdf = NULL; 636f8d2de6bSjchu 637*bf8fc234Set if (epkt->rc_descr.H) { 638*bf8fc234Set bdf = (uint32_t)((epkt->hdr[0] >> 16) && 0xFFFF); 639f8d2de6bSjchu } 640f8d2de6bSjchu 641*bf8fc234Set return (pf_hdl_lookup(dip, derr->fme_ena, PF_DMA_ADDR, addr, 642*bf8fc234Set bdf)); 643f8d2de6bSjchu } 644