1*10187SKrishna.Elango@Sun.COM /* 2*10187SKrishna.Elango@Sun.COM * CDDL HEADER START 3*10187SKrishna.Elango@Sun.COM * 4*10187SKrishna.Elango@Sun.COM * The contents of this file are subject to the terms of the 5*10187SKrishna.Elango@Sun.COM * Common Development and Distribution License (the "License"). 6*10187SKrishna.Elango@Sun.COM * You may not use this file except in compliance with the License. 7*10187SKrishna.Elango@Sun.COM * 8*10187SKrishna.Elango@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10187SKrishna.Elango@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10187SKrishna.Elango@Sun.COM * See the License for the specific language governing permissions 11*10187SKrishna.Elango@Sun.COM * and limitations under the License. 12*10187SKrishna.Elango@Sun.COM * 13*10187SKrishna.Elango@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10187SKrishna.Elango@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10187SKrishna.Elango@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10187SKrishna.Elango@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10187SKrishna.Elango@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10187SKrishna.Elango@Sun.COM * 19*10187SKrishna.Elango@Sun.COM * CDDL HEADER END 20*10187SKrishna.Elango@Sun.COM */ 21*10187SKrishna.Elango@Sun.COM /* 22*10187SKrishna.Elango@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*10187SKrishna.Elango@Sun.COM * Use is subject to license terms. 24*10187SKrishna.Elango@Sun.COM */ 25*10187SKrishna.Elango@Sun.COM 26*10187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h> 27*10187SKrishna.Elango@Sun.COM #include <sys/types.h> 28*10187SKrishna.Elango@Sun.COM #include <sys/kmem.h> 29*10187SKrishna.Elango@Sun.COM #include <sys/modctl.h> 30*10187SKrishna.Elango@Sun.COM #include <sys/ddi.h> 31*10187SKrishna.Elango@Sun.COM #include <sys/sunddi.h> 32*10187SKrishna.Elango@Sun.COM #include <sys/sunndi.h> 33*10187SKrishna.Elango@Sun.COM #include <sys/fm/protocol.h> 34*10187SKrishna.Elango@Sun.COM #include <sys/fm/util.h> 35*10187SKrishna.Elango@Sun.COM #include <sys/fm/io/ddi.h> 36*10187SKrishna.Elango@Sun.COM #include <sys/fm/io/pci.h> 37*10187SKrishna.Elango@Sun.COM #include <sys/promif.h> 38*10187SKrishna.Elango@Sun.COM #include <sys/disp.h> 39*10187SKrishna.Elango@Sun.COM #include <sys/atomic.h> 40*10187SKrishna.Elango@Sun.COM #include <sys/pcie.h> 41*10187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h> 42*10187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h> 43*10187SKrishna.Elango@Sun.COM 44*10187SKrishna.Elango@Sun.COM #define PF_PCIE_BDG_ERR (PCIE_DEVSTS_FE_DETECTED | PCIE_DEVSTS_NFE_DETECTED | \ 45*10187SKrishna.Elango@Sun.COM PCIE_DEVSTS_CE_DETECTED) 46*10187SKrishna.Elango@Sun.COM 47*10187SKrishna.Elango@Sun.COM #define PF_PCI_BDG_ERR (PCI_STAT_S_SYSERR | PCI_STAT_S_TARG_AB | \ 48*10187SKrishna.Elango@Sun.COM PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB | PCI_STAT_S_PERROR) 49*10187SKrishna.Elango@Sun.COM 50*10187SKrishna.Elango@Sun.COM #define PF_AER_FATAL_ERR (PCIE_AER_UCE_DLP | PCIE_AER_UCE_SD |\ 51*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP) 52*10187SKrishna.Elango@Sun.COM #define PF_AER_NON_FATAL_ERR (PCIE_AER_UCE_PTLP | PCIE_AER_UCE_TO | \ 53*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_CA | PCIE_AER_UCE_ECRC | PCIE_AER_UCE_UR) 54*10187SKrishna.Elango@Sun.COM 55*10187SKrishna.Elango@Sun.COM #define PF_SAER_FATAL_ERR (PCIE_AER_SUCE_USC_MSG_DATA_ERR | \ 56*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_ATTR_ERR | PCIE_AER_SUCE_UC_ADDR_ERR | \ 57*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_SERR_ASSERT) 58*10187SKrishna.Elango@Sun.COM #define PF_SAER_NON_FATAL_ERR (PCIE_AER_SUCE_TA_ON_SC | \ 59*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MA_ON_SC | PCIE_AER_SUCE_RCVD_TA | \ 60*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_RCVD_MA | PCIE_AER_SUCE_USC_ERR | \ 61*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_DATA_ERR | PCIE_AER_SUCE_TIMER_EXPIRED | \ 62*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_PERR_ASSERT | PCIE_AER_SUCE_INTERNAL_ERR) 63*10187SKrishna.Elango@Sun.COM 64*10187SKrishna.Elango@Sun.COM #define PF_PCI_PARITY_ERR (PCI_STAT_S_PERROR | PCI_STAT_PERROR) 65*10187SKrishna.Elango@Sun.COM 66*10187SKrishna.Elango@Sun.COM #define PF_FIRST_AER_ERR(bit, adv) \ 67*10187SKrishna.Elango@Sun.COM (bit & (1 << (adv->pcie_adv_ctl & PCIE_AER_CTL_FST_ERR_PTR_MASK))) 68*10187SKrishna.Elango@Sun.COM 69*10187SKrishna.Elango@Sun.COM #define HAS_AER_LOGS(pfd_p, bit) \ 70*10187SKrishna.Elango@Sun.COM (PCIE_HAS_AER(pfd_p->pe_bus_p) && \ 71*10187SKrishna.Elango@Sun.COM PF_FIRST_AER_ERR(bit, PCIE_ADV_REG(pfd_p))) 72*10187SKrishna.Elango@Sun.COM 73*10187SKrishna.Elango@Sun.COM #define PF_FIRST_SAER_ERR(bit, adv) \ 74*10187SKrishna.Elango@Sun.COM (bit & (1 << (adv->pcie_sue_ctl & PCIE_AER_SCTL_FST_ERR_PTR_MASK))) 75*10187SKrishna.Elango@Sun.COM 76*10187SKrishna.Elango@Sun.COM #define HAS_SAER_LOGS(pfd_p, bit) \ 77*10187SKrishna.Elango@Sun.COM (PCIE_HAS_AER(pfd_p->pe_bus_p) && \ 78*10187SKrishna.Elango@Sun.COM PF_FIRST_SAER_ERR(bit, PCIE_ADV_BDG_REG(pfd_p))) 79*10187SKrishna.Elango@Sun.COM 80*10187SKrishna.Elango@Sun.COM #define GET_SAER_CMD(pfd_p) \ 81*10187SKrishna.Elango@Sun.COM ((PCIE_ADV_BDG_HDR(pfd_p, 1) >> \ 82*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK) 83*10187SKrishna.Elango@Sun.COM 84*10187SKrishna.Elango@Sun.COM #define CE_ADVISORY(pfd_p) \ 85*10187SKrishna.Elango@Sun.COM (PCIE_ADV_REG(pfd_p)->pcie_ce_status & PCIE_AER_CE_AD_NFE) 86*10187SKrishna.Elango@Sun.COM 87*10187SKrishna.Elango@Sun.COM /* PCIe Fault Fabric Error analysis table */ 88*10187SKrishna.Elango@Sun.COM typedef struct pf_fab_err_tbl { 89*10187SKrishna.Elango@Sun.COM uint32_t bit; /* Error bit */ 90*10187SKrishna.Elango@Sun.COM int (*handler)(); /* Error handling fuction */ 91*10187SKrishna.Elango@Sun.COM } pf_fab_err_tbl_t; 92*10187SKrishna.Elango@Sun.COM 93*10187SKrishna.Elango@Sun.COM static pcie_bus_t *pf_is_ready(dev_info_t *); 94*10187SKrishna.Elango@Sun.COM /* Functions for scanning errors */ 95*10187SKrishna.Elango@Sun.COM static int pf_default_hdl(dev_info_t *, pf_impl_t *); 96*10187SKrishna.Elango@Sun.COM static int pf_dispatch(dev_info_t *, pf_impl_t *, boolean_t); 97*10187SKrishna.Elango@Sun.COM static boolean_t pf_in_bus_range(pcie_bus_t *, pcie_req_id_t); 98*10187SKrishna.Elango@Sun.COM static boolean_t pf_in_addr_range(pcie_bus_t *, uint64_t); 99*10187SKrishna.Elango@Sun.COM 100*10187SKrishna.Elango@Sun.COM static int pf_pci_decode(pf_data_t *, uint16_t *); 101*10187SKrishna.Elango@Sun.COM 102*10187SKrishna.Elango@Sun.COM /* Functions for gathering errors */ 103*10187SKrishna.Elango@Sun.COM static void pf_pcix_ecc_regs_gather(pf_pcix_ecc_regs_t *pcix_ecc_regs, 104*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p, boolean_t bdg); 105*10187SKrishna.Elango@Sun.COM static void pf_pcix_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p); 106*10187SKrishna.Elango@Sun.COM static void pf_pcie_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p); 107*10187SKrishna.Elango@Sun.COM static void pf_pci_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p); 108*10187SKrishna.Elango@Sun.COM static int pf_dummy_cb(dev_info_t *, ddi_fm_error_t *, const void *); 109*10187SKrishna.Elango@Sun.COM static void pf_en_dq(pf_data_t *pfd_p, pf_impl_t *impl_p); 110*10187SKrishna.Elango@Sun.COM 111*10187SKrishna.Elango@Sun.COM /* Functions for analysing errors */ 112*10187SKrishna.Elango@Sun.COM static int pf_analyse_error(ddi_fm_error_t *, pf_impl_t *); 113*10187SKrishna.Elango@Sun.COM static void pf_adjust_for_no_aer(pf_data_t *); 114*10187SKrishna.Elango@Sun.COM static void pf_adjust_for_no_saer(pf_data_t *); 115*10187SKrishna.Elango@Sun.COM static pf_data_t *pf_get_pcie_bridge(pf_data_t *, pcie_req_id_t); 116*10187SKrishna.Elango@Sun.COM static pf_data_t *pf_get_parent_pcie_bridge(pf_data_t *); 117*10187SKrishna.Elango@Sun.COM static boolean_t pf_matched_in_rc(pf_data_t *, pf_data_t *, 118*10187SKrishna.Elango@Sun.COM uint32_t); 119*10187SKrishna.Elango@Sun.COM static int pf_analyse_error_tbl(ddi_fm_error_t *, pf_impl_t *, 120*10187SKrishna.Elango@Sun.COM pf_data_t *, const pf_fab_err_tbl_t *, uint32_t); 121*10187SKrishna.Elango@Sun.COM static int pf_analyse_ca_ur(ddi_fm_error_t *, uint32_t, 122*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 123*10187SKrishna.Elango@Sun.COM static int pf_analyse_ma_ta(ddi_fm_error_t *, uint32_t, 124*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 125*10187SKrishna.Elango@Sun.COM static int pf_analyse_pci(ddi_fm_error_t *, uint32_t, 126*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 127*10187SKrishna.Elango@Sun.COM static int pf_analyse_perr_assert(ddi_fm_error_t *, uint32_t, 128*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 129*10187SKrishna.Elango@Sun.COM static int pf_analyse_ptlp(ddi_fm_error_t *, uint32_t, 130*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 131*10187SKrishna.Elango@Sun.COM static int pf_analyse_sc(ddi_fm_error_t *, uint32_t, 132*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 133*10187SKrishna.Elango@Sun.COM static int pf_analyse_to(ddi_fm_error_t *, uint32_t, 134*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 135*10187SKrishna.Elango@Sun.COM static int pf_analyse_uc(ddi_fm_error_t *, uint32_t, 136*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 137*10187SKrishna.Elango@Sun.COM static int pf_analyse_uc_data(ddi_fm_error_t *, uint32_t, 138*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 139*10187SKrishna.Elango@Sun.COM static int pf_no_panic(ddi_fm_error_t *, uint32_t, 140*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 141*10187SKrishna.Elango@Sun.COM static int pf_panic(ddi_fm_error_t *, uint32_t, 142*10187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *); 143*10187SKrishna.Elango@Sun.COM static void pf_send_ereport(ddi_fm_error_t *, pf_impl_t *); 144*10187SKrishna.Elango@Sun.COM static int pf_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr); 145*10187SKrishna.Elango@Sun.COM 146*10187SKrishna.Elango@Sun.COM /* PCIe Fabric Handle Lookup Support Functions. */ 147*10187SKrishna.Elango@Sun.COM static int pf_hdl_child_lookup(dev_info_t *, ddi_fm_error_t *, uint32_t, 148*10187SKrishna.Elango@Sun.COM uint64_t, pcie_req_id_t); 149*10187SKrishna.Elango@Sun.COM static int pf_hdl_compare(dev_info_t *, ddi_fm_error_t *, uint32_t, uint64_t, 150*10187SKrishna.Elango@Sun.COM pcie_req_id_t, ndi_fmc_t *); 151*10187SKrishna.Elango@Sun.COM static int pf_log_hdl_lookup(dev_info_t *, ddi_fm_error_t *, pf_data_t *, 152*10187SKrishna.Elango@Sun.COM boolean_t); 153*10187SKrishna.Elango@Sun.COM 154*10187SKrishna.Elango@Sun.COM static int pf_handler_enter(dev_info_t *, pf_impl_t *); 155*10187SKrishna.Elango@Sun.COM static void pf_handler_exit(dev_info_t *); 156*10187SKrishna.Elango@Sun.COM 157*10187SKrishna.Elango@Sun.COM boolean_t pcie_full_scan = B_FALSE; /* Force to always do a full scan */ 158*10187SKrishna.Elango@Sun.COM int pcie_disable_scan = 0; /* Disable fabric scan */ 159*10187SKrishna.Elango@Sun.COM 160*10187SKrishna.Elango@Sun.COM /* 161*10187SKrishna.Elango@Sun.COM * Scan Fabric is the entry point for PCI/PCIe IO fabric errors. The 162*10187SKrishna.Elango@Sun.COM * caller may create a local pf_data_t with the "root fault" 163*10187SKrishna.Elango@Sun.COM * information populated to either do a precise or full scan. More 164*10187SKrishna.Elango@Sun.COM * than one pf_data_t maybe linked together if there are multiple 165*10187SKrishna.Elango@Sun.COM * errors. Only a PCIe compliant Root Port device may pass in NULL 166*10187SKrishna.Elango@Sun.COM * for the root_pfd_p. 167*10187SKrishna.Elango@Sun.COM * 168*10187SKrishna.Elango@Sun.COM * "Root Complexes" such as NPE and PX should call scan_fabric using itself as 169*10187SKrishna.Elango@Sun.COM * the rdip. PCIe Root ports should call pf_scan_fabric using it's parent as 170*10187SKrishna.Elango@Sun.COM * the rdip. 171*10187SKrishna.Elango@Sun.COM * 172*10187SKrishna.Elango@Sun.COM * Scan fabric initiated from RCs are likely due to a fabric message, traps or 173*10187SKrishna.Elango@Sun.COM * any RC detected errors that propagated to/from the fabric. 174*10187SKrishna.Elango@Sun.COM * 175*10187SKrishna.Elango@Sun.COM * This code assumes that by the time pf_scan_fabric is 176*10187SKrishna.Elango@Sun.COM * called, pf_handler_enter has NOT been called on the rdip. 177*10187SKrishna.Elango@Sun.COM */ 178*10187SKrishna.Elango@Sun.COM int 179*10187SKrishna.Elango@Sun.COM pf_scan_fabric(dev_info_t *rdip, ddi_fm_error_t *derr, pf_data_t *root_pfd_p) 180*10187SKrishna.Elango@Sun.COM { 181*10187SKrishna.Elango@Sun.COM pf_impl_t impl; 182*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p, *pfd_head_p, *pfd_tail_p; 183*10187SKrishna.Elango@Sun.COM int scan_flag = PF_SCAN_SUCCESS; 184*10187SKrishna.Elango@Sun.COM int analyse_flag = PF_ERR_NO_ERROR; 185*10187SKrishna.Elango@Sun.COM boolean_t full_scan = pcie_full_scan; 186*10187SKrishna.Elango@Sun.COM 187*10187SKrishna.Elango@Sun.COM if (pcie_disable_scan) 188*10187SKrishna.Elango@Sun.COM return (analyse_flag); 189*10187SKrishna.Elango@Sun.COM 190*10187SKrishna.Elango@Sun.COM /* Find the head and tail of this link list */ 191*10187SKrishna.Elango@Sun.COM pfd_head_p = root_pfd_p; 192*10187SKrishna.Elango@Sun.COM for (pfd_tail_p = root_pfd_p; pfd_tail_p && pfd_tail_p->pe_next; 193*10187SKrishna.Elango@Sun.COM pfd_tail_p = pfd_tail_p->pe_next) 194*10187SKrishna.Elango@Sun.COM ; 195*10187SKrishna.Elango@Sun.COM 196*10187SKrishna.Elango@Sun.COM /* Save head/tail */ 197*10187SKrishna.Elango@Sun.COM impl.pf_total = 0; 198*10187SKrishna.Elango@Sun.COM impl.pf_derr = derr; 199*10187SKrishna.Elango@Sun.COM impl.pf_dq_head_p = pfd_head_p; 200*10187SKrishna.Elango@Sun.COM impl.pf_dq_tail_p = pfd_tail_p; 201*10187SKrishna.Elango@Sun.COM 202*10187SKrishna.Elango@Sun.COM /* If scan is initiated from RP then RP itself must be scanned. */ 203*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(PCIE_DIP2BUS(rdip)) && pf_is_ready(rdip) && 204*10187SKrishna.Elango@Sun.COM !root_pfd_p) { 205*10187SKrishna.Elango@Sun.COM scan_flag = pf_handler_enter(rdip, &impl); 206*10187SKrishna.Elango@Sun.COM if (scan_flag & PF_SCAN_DEADLOCK) 207*10187SKrishna.Elango@Sun.COM goto done; 208*10187SKrishna.Elango@Sun.COM 209*10187SKrishna.Elango@Sun.COM scan_flag = pf_default_hdl(rdip, &impl); 210*10187SKrishna.Elango@Sun.COM if (scan_flag & PF_SCAN_NO_ERR_IN_CHILD) 211*10187SKrishna.Elango@Sun.COM goto done; 212*10187SKrishna.Elango@Sun.COM } 213*10187SKrishna.Elango@Sun.COM 214*10187SKrishna.Elango@Sun.COM /* 215*10187SKrishna.Elango@Sun.COM * Scan the fabric using the scan_bdf and scan_addr in error q. 216*10187SKrishna.Elango@Sun.COM * scan_bdf will be valid in the following cases: 217*10187SKrishna.Elango@Sun.COM * - Fabric message 218*10187SKrishna.Elango@Sun.COM * - Poisoned TLP 219*10187SKrishna.Elango@Sun.COM * - Signaled UR/CA 220*10187SKrishna.Elango@Sun.COM * - Received UR/CA 221*10187SKrishna.Elango@Sun.COM * - PIO load failures 222*10187SKrishna.Elango@Sun.COM */ 223*10187SKrishna.Elango@Sun.COM for (pfd_p = impl.pf_dq_head_p; pfd_p && PFD_IS_ROOT(pfd_p); 224*10187SKrishna.Elango@Sun.COM pfd_p = pfd_p->pe_next) { 225*10187SKrishna.Elango@Sun.COM impl.pf_fault = PCIE_ROOT_FAULT(pfd_p); 226*10187SKrishna.Elango@Sun.COM 227*10187SKrishna.Elango@Sun.COM if (impl.pf_fault->full_scan) 228*10187SKrishna.Elango@Sun.COM full_scan = B_TRUE; 229*10187SKrishna.Elango@Sun.COM 230*10187SKrishna.Elango@Sun.COM if (full_scan || 231*10187SKrishna.Elango@Sun.COM PCIE_CHECK_VALID_BDF(impl.pf_fault->scan_bdf) || 232*10187SKrishna.Elango@Sun.COM impl.pf_fault->scan_addr) 233*10187SKrishna.Elango@Sun.COM scan_flag |= pf_dispatch(rdip, &impl, full_scan); 234*10187SKrishna.Elango@Sun.COM 235*10187SKrishna.Elango@Sun.COM if (full_scan) 236*10187SKrishna.Elango@Sun.COM break; 237*10187SKrishna.Elango@Sun.COM } 238*10187SKrishna.Elango@Sun.COM 239*10187SKrishna.Elango@Sun.COM done: 240*10187SKrishna.Elango@Sun.COM /* 241*10187SKrishna.Elango@Sun.COM * If this is due to safe access, don't analyze the errors and return 242*10187SKrishna.Elango@Sun.COM * success regardless of how scan fabric went. 243*10187SKrishna.Elango@Sun.COM */ 244*10187SKrishna.Elango@Sun.COM if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) { 245*10187SKrishna.Elango@Sun.COM analyse_flag = PF_ERR_NO_PANIC; 246*10187SKrishna.Elango@Sun.COM } else { 247*10187SKrishna.Elango@Sun.COM analyse_flag = pf_analyse_error(derr, &impl); 248*10187SKrishna.Elango@Sun.COM } 249*10187SKrishna.Elango@Sun.COM 250*10187SKrishna.Elango@Sun.COM pf_send_ereport(derr, &impl); 251*10187SKrishna.Elango@Sun.COM 252*10187SKrishna.Elango@Sun.COM /* 253*10187SKrishna.Elango@Sun.COM * Check if any hardened driver's callback reported a panic or scan 254*10187SKrishna.Elango@Sun.COM * fabric was unable to gather all the information needed. If so panic. 255*10187SKrishna.Elango@Sun.COM */ 256*10187SKrishna.Elango@Sun.COM if (scan_flag & (PF_SCAN_CB_FAILURE | PF_SCAN_BAD_RESPONSE)) 257*10187SKrishna.Elango@Sun.COM analyse_flag |= PF_ERR_PANIC; 258*10187SKrishna.Elango@Sun.COM 259*10187SKrishna.Elango@Sun.COM /* 260*10187SKrishna.Elango@Sun.COM * If a deadlock was detected, panic the system as error analysis has 261*10187SKrishna.Elango@Sun.COM * been compromised. 262*10187SKrishna.Elango@Sun.COM */ 263*10187SKrishna.Elango@Sun.COM if (scan_flag & PF_SCAN_DEADLOCK) 264*10187SKrishna.Elango@Sun.COM analyse_flag |= PF_ERR_PANIC_DEADLOCK; 265*10187SKrishna.Elango@Sun.COM 266*10187SKrishna.Elango@Sun.COM derr->fme_status = PF_ERR2DDIFM_ERR(scan_flag); 267*10187SKrishna.Elango@Sun.COM 268*10187SKrishna.Elango@Sun.COM return (analyse_flag); 269*10187SKrishna.Elango@Sun.COM } 270*10187SKrishna.Elango@Sun.COM 271*10187SKrishna.Elango@Sun.COM /* 272*10187SKrishna.Elango@Sun.COM * pf_dispatch walks the device tree and calls the pf_default_hdl if the device 273*10187SKrishna.Elango@Sun.COM * falls in the error path. 274*10187SKrishna.Elango@Sun.COM * 275*10187SKrishna.Elango@Sun.COM * Returns PF_SCAN_* flags 276*10187SKrishna.Elango@Sun.COM */ 277*10187SKrishna.Elango@Sun.COM static int 278*10187SKrishna.Elango@Sun.COM pf_dispatch(dev_info_t *pdip, pf_impl_t *impl, boolean_t full_scan) 279*10187SKrishna.Elango@Sun.COM { 280*10187SKrishna.Elango@Sun.COM dev_info_t *dip; 281*10187SKrishna.Elango@Sun.COM pcie_req_id_t rid = impl->pf_fault->scan_bdf; 282*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 283*10187SKrishna.Elango@Sun.COM int scan_flag = PF_SCAN_SUCCESS; 284*10187SKrishna.Elango@Sun.COM 285*10187SKrishna.Elango@Sun.COM for (dip = ddi_get_child(pdip); dip; dip = ddi_get_next_sibling(dip)) { 286*10187SKrishna.Elango@Sun.COM /* Make sure dip is attached and ready */ 287*10187SKrishna.Elango@Sun.COM if (!(bus_p = pf_is_ready(dip))) 288*10187SKrishna.Elango@Sun.COM continue; 289*10187SKrishna.Elango@Sun.COM 290*10187SKrishna.Elango@Sun.COM scan_flag |= pf_handler_enter(dip, impl); 291*10187SKrishna.Elango@Sun.COM if (scan_flag & PF_SCAN_DEADLOCK) 292*10187SKrishna.Elango@Sun.COM break; 293*10187SKrishna.Elango@Sun.COM 294*10187SKrishna.Elango@Sun.COM /* 295*10187SKrishna.Elango@Sun.COM * Handle this device if it is a: 296*10187SKrishna.Elango@Sun.COM * o Full Scan 297*10187SKrishna.Elango@Sun.COM * o PCI/PCI-X Device 298*10187SKrishna.Elango@Sun.COM * o Fault BDF = Device BDF 299*10187SKrishna.Elango@Sun.COM * o BDF/ADDR is in range of the Bridge/Switch 300*10187SKrishna.Elango@Sun.COM */ 301*10187SKrishna.Elango@Sun.COM if (full_scan || 302*10187SKrishna.Elango@Sun.COM (bus_p->bus_bdf == rid) || 303*10187SKrishna.Elango@Sun.COM pf_in_bus_range(bus_p, rid) || 304*10187SKrishna.Elango@Sun.COM pf_in_addr_range(bus_p, impl->pf_fault->scan_addr)) { 305*10187SKrishna.Elango@Sun.COM int hdl_flag = pf_default_hdl(dip, impl); 306*10187SKrishna.Elango@Sun.COM scan_flag |= hdl_flag; 307*10187SKrishna.Elango@Sun.COM 308*10187SKrishna.Elango@Sun.COM /* 309*10187SKrishna.Elango@Sun.COM * If pf_default_hdl was not able gather error 310*10187SKrishna.Elango@Sun.COM * information, it means this device wasn't added to the 311*10187SKrishna.Elango@Sun.COM * error q list. In that case exit the lock now, 312*10187SKrishna.Elango@Sun.COM * otherwise it'll be locked forever. 313*10187SKrishna.Elango@Sun.COM */ 314*10187SKrishna.Elango@Sun.COM if (hdl_flag & PF_SCAN_BAD_RESPONSE) 315*10187SKrishna.Elango@Sun.COM pf_handler_exit(dip); 316*10187SKrishna.Elango@Sun.COM 317*10187SKrishna.Elango@Sun.COM /* 318*10187SKrishna.Elango@Sun.COM * A bridge may have detected no errors in which case 319*10187SKrishna.Elango@Sun.COM * there is no need to scan further down. 320*10187SKrishna.Elango@Sun.COM */ 321*10187SKrishna.Elango@Sun.COM if (hdl_flag & PF_SCAN_NO_ERR_IN_CHILD) 322*10187SKrishna.Elango@Sun.COM continue; 323*10187SKrishna.Elango@Sun.COM } else { 324*10187SKrishna.Elango@Sun.COM pf_handler_exit(dip); 325*10187SKrishna.Elango@Sun.COM continue; 326*10187SKrishna.Elango@Sun.COM } 327*10187SKrishna.Elango@Sun.COM 328*10187SKrishna.Elango@Sun.COM /* match or in bridge bus-range */ 329*10187SKrishna.Elango@Sun.COM switch (bus_p->bus_dev_type) { 330*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: 331*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE: 332*10187SKrishna.Elango@Sun.COM scan_flag |= pf_dispatch(dip, impl, B_TRUE); 333*10187SKrishna.Elango@Sun.COM break; 334*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_UP: 335*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_DOWN: 336*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_ROOT: 337*10187SKrishna.Elango@Sun.COM { 338*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_BUS2PFD(bus_p); 339*10187SKrishna.Elango@Sun.COM pf_pci_err_regs_t *err_p = PCI_ERR_REG(pfd_p); 340*10187SKrishna.Elango@Sun.COM pf_pci_bdg_err_regs_t *serr_p = PCI_BDG_ERR_REG(pfd_p); 341*10187SKrishna.Elango@Sun.COM /* 342*10187SKrishna.Elango@Sun.COM * Continue if the fault BDF != the switch or there is a 343*10187SKrishna.Elango@Sun.COM * parity error 344*10187SKrishna.Elango@Sun.COM */ 345*10187SKrishna.Elango@Sun.COM if ((bus_p->bus_bdf != rid) || 346*10187SKrishna.Elango@Sun.COM (err_p->pci_err_status & PF_PCI_PARITY_ERR) || 347*10187SKrishna.Elango@Sun.COM (serr_p->pci_bdg_sec_stat & PF_PCI_PARITY_ERR)) 348*10187SKrishna.Elango@Sun.COM scan_flag |= pf_dispatch(dip, impl, full_scan); 349*10187SKrishna.Elango@Sun.COM break; 350*10187SKrishna.Elango@Sun.COM } 351*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: 352*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI_DEV: 353*10187SKrishna.Elango@Sun.COM /* 354*10187SKrishna.Elango@Sun.COM * Reached a PCIe end point so stop. Note dev_type 355*10187SKrishna.Elango@Sun.COM * PCI_DEV is just a PCIe device that requires IO Space 356*10187SKrishna.Elango@Sun.COM */ 357*10187SKrishna.Elango@Sun.COM break; 358*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO: 359*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 360*10187SKrishna.Elango@Sun.COM scan_flag |= pf_dispatch(dip, impl, B_TRUE); 361*10187SKrishna.Elango@Sun.COM break; 362*10187SKrishna.Elango@Sun.COM default: 363*10187SKrishna.Elango@Sun.COM ASSERT(B_FALSE); 364*10187SKrishna.Elango@Sun.COM } 365*10187SKrishna.Elango@Sun.COM } 366*10187SKrishna.Elango@Sun.COM return (scan_flag); 367*10187SKrishna.Elango@Sun.COM } 368*10187SKrishna.Elango@Sun.COM 369*10187SKrishna.Elango@Sun.COM /* Returns whether the "bdf" is in the bus range of a switch/bridge */ 370*10187SKrishna.Elango@Sun.COM static boolean_t 371*10187SKrishna.Elango@Sun.COM pf_in_bus_range(pcie_bus_t *bus_p, pcie_req_id_t bdf) 372*10187SKrishna.Elango@Sun.COM { 373*10187SKrishna.Elango@Sun.COM pci_bus_range_t *br_p = &bus_p->bus_bus_range; 374*10187SKrishna.Elango@Sun.COM uint8_t bus_no = (bdf & PCIE_REQ_ID_BUS_MASK) >> 375*10187SKrishna.Elango@Sun.COM PCIE_REQ_ID_BUS_SHIFT; 376*10187SKrishna.Elango@Sun.COM 377*10187SKrishna.Elango@Sun.COM /* check if given bdf falls within bridge's bus range */ 378*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p) && 379*10187SKrishna.Elango@Sun.COM ((bus_no >= br_p->lo) && (bus_no <= br_p->hi))) 380*10187SKrishna.Elango@Sun.COM return (B_TRUE); 381*10187SKrishna.Elango@Sun.COM else 382*10187SKrishna.Elango@Sun.COM return (B_FALSE); 383*10187SKrishna.Elango@Sun.COM } 384*10187SKrishna.Elango@Sun.COM 385*10187SKrishna.Elango@Sun.COM /* 386*10187SKrishna.Elango@Sun.COM * Returns whether the "addr" is in the addr range of a switch/bridge, or if the 387*10187SKrishna.Elango@Sun.COM * "addr" is in the assigned addr of a device. 388*10187SKrishna.Elango@Sun.COM */ 389*10187SKrishna.Elango@Sun.COM static boolean_t 390*10187SKrishna.Elango@Sun.COM pf_in_addr_range(pcie_bus_t *bus_p, uint64_t addr) 391*10187SKrishna.Elango@Sun.COM { 392*10187SKrishna.Elango@Sun.COM uint_t i; 393*10187SKrishna.Elango@Sun.COM uint64_t low, hi; 394*10187SKrishna.Elango@Sun.COM ppb_ranges_t *ranges_p = bus_p->bus_addr_ranges; 395*10187SKrishna.Elango@Sun.COM pci_regspec_t *assign_p = bus_p->bus_assigned_addr; 396*10187SKrishna.Elango@Sun.COM 397*10187SKrishna.Elango@Sun.COM /* check if given address belongs to this device */ 398*10187SKrishna.Elango@Sun.COM for (i = 0; i < bus_p->bus_assigned_entries; i++, assign_p++) { 399*10187SKrishna.Elango@Sun.COM low = assign_p->pci_phys_low; 400*10187SKrishna.Elango@Sun.COM hi = low + assign_p->pci_size_low; 401*10187SKrishna.Elango@Sun.COM if ((addr < hi) && (addr >= low)) 402*10187SKrishna.Elango@Sun.COM return (B_TRUE); 403*10187SKrishna.Elango@Sun.COM } 404*10187SKrishna.Elango@Sun.COM 405*10187SKrishna.Elango@Sun.COM /* check if given address belongs to a child below this device */ 406*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_BDG(bus_p)) 407*10187SKrishna.Elango@Sun.COM return (B_FALSE); 408*10187SKrishna.Elango@Sun.COM 409*10187SKrishna.Elango@Sun.COM for (i = 0; i < bus_p->bus_addr_entries; i++, ranges_p++) { 410*10187SKrishna.Elango@Sun.COM switch (ranges_p->child_high & PCI_ADDR_MASK) { 411*10187SKrishna.Elango@Sun.COM case PCI_ADDR_IO: 412*10187SKrishna.Elango@Sun.COM case PCI_ADDR_MEM32: 413*10187SKrishna.Elango@Sun.COM low = ranges_p->child_low; 414*10187SKrishna.Elango@Sun.COM hi = ranges_p->size_low + low; 415*10187SKrishna.Elango@Sun.COM if ((addr < hi) && (addr >= low)) 416*10187SKrishna.Elango@Sun.COM return (B_TRUE); 417*10187SKrishna.Elango@Sun.COM break; 418*10187SKrishna.Elango@Sun.COM case PCI_ADDR_MEM64: 419*10187SKrishna.Elango@Sun.COM low = ((uint64_t)ranges_p->child_mid << 32) | 420*10187SKrishna.Elango@Sun.COM (uint64_t)ranges_p->child_low; 421*10187SKrishna.Elango@Sun.COM hi = (((uint64_t)ranges_p->size_high << 32) | 422*10187SKrishna.Elango@Sun.COM (uint64_t)ranges_p->size_low) + low; 423*10187SKrishna.Elango@Sun.COM if ((addr < hi) && (addr >= low)) 424*10187SKrishna.Elango@Sun.COM return (B_TRUE); 425*10187SKrishna.Elango@Sun.COM break; 426*10187SKrishna.Elango@Sun.COM } 427*10187SKrishna.Elango@Sun.COM } 428*10187SKrishna.Elango@Sun.COM return (B_FALSE); 429*10187SKrishna.Elango@Sun.COM } 430*10187SKrishna.Elango@Sun.COM 431*10187SKrishna.Elango@Sun.COM static pcie_bus_t * 432*10187SKrishna.Elango@Sun.COM pf_is_ready(dev_info_t *dip) 433*10187SKrishna.Elango@Sun.COM { 434*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 435*10187SKrishna.Elango@Sun.COM if (!bus_p) 436*10187SKrishna.Elango@Sun.COM return (NULL); 437*10187SKrishna.Elango@Sun.COM 438*10187SKrishna.Elango@Sun.COM if (!(bus_p->bus_fm_flags & PF_FM_READY)) 439*10187SKrishna.Elango@Sun.COM return (NULL); 440*10187SKrishna.Elango@Sun.COM return (bus_p); 441*10187SKrishna.Elango@Sun.COM } 442*10187SKrishna.Elango@Sun.COM 443*10187SKrishna.Elango@Sun.COM static void 444*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_gather(pf_pcix_ecc_regs_t *pcix_ecc_regs, 445*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p, boolean_t bdg) 446*10187SKrishna.Elango@Sun.COM { 447*10187SKrishna.Elango@Sun.COM if (bdg) { 448*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_ctlstat = PCIX_CAP_GET(32, bus_p, 449*10187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_ECC_STATUS); 450*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_fstaddr = PCIX_CAP_GET(32, bus_p, 451*10187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_ECC_FST_AD); 452*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_secaddr = PCIX_CAP_GET(32, bus_p, 453*10187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_ECC_SEC_AD); 454*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_attr = PCIX_CAP_GET(32, bus_p, 455*10187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_ECC_ATTR); 456*10187SKrishna.Elango@Sun.COM } else { 457*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_ctlstat = PCIX_CAP_GET(32, bus_p, 458*10187SKrishna.Elango@Sun.COM PCI_PCIX_ECC_STATUS); 459*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_fstaddr = PCIX_CAP_GET(32, bus_p, 460*10187SKrishna.Elango@Sun.COM PCI_PCIX_ECC_FST_AD); 461*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_secaddr = PCIX_CAP_GET(32, bus_p, 462*10187SKrishna.Elango@Sun.COM PCI_PCIX_ECC_SEC_AD); 463*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_attr = PCIX_CAP_GET(32, bus_p, 464*10187SKrishna.Elango@Sun.COM PCI_PCIX_ECC_ATTR); 465*10187SKrishna.Elango@Sun.COM } 466*10187SKrishna.Elango@Sun.COM } 467*10187SKrishna.Elango@Sun.COM 468*10187SKrishna.Elango@Sun.COM 469*10187SKrishna.Elango@Sun.COM static void 470*10187SKrishna.Elango@Sun.COM pf_pcix_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p) 471*10187SKrishna.Elango@Sun.COM { 472*10187SKrishna.Elango@Sun.COM /* 473*10187SKrishna.Elango@Sun.COM * For PCI-X device PCI-X Capability only exists for Type 0 Headers. 474*10187SKrishna.Elango@Sun.COM * PCI-X Bridge Capability only exists for Type 1 Headers. 475*10187SKrishna.Elango@Sun.COM * Both capabilities do not exist at the same time. 476*10187SKrishna.Elango@Sun.COM */ 477*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 478*10187SKrishna.Elango@Sun.COM pf_pcix_bdg_err_regs_t *pcix_bdg_regs; 479*10187SKrishna.Elango@Sun.COM 480*10187SKrishna.Elango@Sun.COM pcix_bdg_regs = PCIX_BDG_ERR_REG(pfd_p); 481*10187SKrishna.Elango@Sun.COM 482*10187SKrishna.Elango@Sun.COM pcix_bdg_regs->pcix_bdg_sec_stat = PCIX_CAP_GET(16, bus_p, 483*10187SKrishna.Elango@Sun.COM PCI_PCIX_SEC_STATUS); 484*10187SKrishna.Elango@Sun.COM pcix_bdg_regs->pcix_bdg_stat = PCIX_CAP_GET(32, bus_p, 485*10187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_STATUS); 486*10187SKrishna.Elango@Sun.COM 487*10187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 488*10187SKrishna.Elango@Sun.COM /* 489*10187SKrishna.Elango@Sun.COM * PCI Express to PCI-X bridges only implement the 490*10187SKrishna.Elango@Sun.COM * secondary side of the PCI-X ECC registers, bit one is 491*10187SKrishna.Elango@Sun.COM * read-only so we make sure we do not write to it. 492*10187SKrishna.Elango@Sun.COM */ 493*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) { 494*10187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS, 495*10187SKrishna.Elango@Sun.COM 0); 496*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_gather( 497*10187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0), bus_p, B_TRUE); 498*10187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS, 499*10187SKrishna.Elango@Sun.COM 1); 500*10187SKrishna.Elango@Sun.COM } 501*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_gather(PCIX_BDG_ECC_REG(pfd_p, 0), 502*10187SKrishna.Elango@Sun.COM bus_p, B_TRUE); 503*10187SKrishna.Elango@Sun.COM } 504*10187SKrishna.Elango@Sun.COM } else { 505*10187SKrishna.Elango@Sun.COM pf_pcix_err_regs_t *pcix_regs = PCIX_ERR_REG(pfd_p); 506*10187SKrishna.Elango@Sun.COM 507*10187SKrishna.Elango@Sun.COM pcix_regs->pcix_command = PCIX_CAP_GET(16, bus_p, 508*10187SKrishna.Elango@Sun.COM PCI_PCIX_COMMAND); 509*10187SKrishna.Elango@Sun.COM pcix_regs->pcix_status = PCIX_CAP_GET(32, bus_p, 510*10187SKrishna.Elango@Sun.COM PCI_PCIX_STATUS); 511*10187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) 512*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_gather(PCIX_ECC_REG(pfd_p), bus_p, 513*10187SKrishna.Elango@Sun.COM B_TRUE); 514*10187SKrishna.Elango@Sun.COM } 515*10187SKrishna.Elango@Sun.COM } 516*10187SKrishna.Elango@Sun.COM 517*10187SKrishna.Elango@Sun.COM static void 518*10187SKrishna.Elango@Sun.COM pf_pcie_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p) 519*10187SKrishna.Elango@Sun.COM { 520*10187SKrishna.Elango@Sun.COM pf_pcie_err_regs_t *pcie_regs = PCIE_ERR_REG(pfd_p); 521*10187SKrishna.Elango@Sun.COM pf_pcie_adv_err_regs_t *pcie_adv_regs = PCIE_ADV_REG(pfd_p); 522*10187SKrishna.Elango@Sun.COM 523*10187SKrishna.Elango@Sun.COM pcie_regs->pcie_err_status = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS); 524*10187SKrishna.Elango@Sun.COM pcie_regs->pcie_err_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 525*10187SKrishna.Elango@Sun.COM pcie_regs->pcie_dev_cap = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP); 526*10187SKrishna.Elango@Sun.COM 527*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) 528*10187SKrishna.Elango@Sun.COM pf_pcix_regs_gather(pfd_p, bus_p); 529*10187SKrishna.Elango@Sun.COM 530*10187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) { 531*10187SKrishna.Elango@Sun.COM pf_pcie_rp_err_regs_t *pcie_rp_regs = PCIE_RP_REG(pfd_p); 532*10187SKrishna.Elango@Sun.COM 533*10187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_status = PCIE_CAP_GET(32, bus_p, 534*10187SKrishna.Elango@Sun.COM PCIE_ROOTSTS); 535*10187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_ctl = PCIE_CAP_GET(16, bus_p, 536*10187SKrishna.Elango@Sun.COM PCIE_ROOTCTL); 537*10187SKrishna.Elango@Sun.COM } 538*10187SKrishna.Elango@Sun.COM 539*10187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 540*10187SKrishna.Elango@Sun.COM return; 541*10187SKrishna.Elango@Sun.COM 542*10187SKrishna.Elango@Sun.COM /* Gather UE AERs */ 543*10187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_adv_ctl = PCIE_AER_GET(32, bus_p, 544*10187SKrishna.Elango@Sun.COM PCIE_AER_CTL); 545*10187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ue_status = PCIE_AER_GET(32, bus_p, 546*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_STS); 547*10187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ue_mask = PCIE_AER_GET(32, bus_p, 548*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_MASK); 549*10187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ue_sev = PCIE_AER_GET(32, bus_p, 550*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_SERV); 551*10187SKrishna.Elango@Sun.COM PCIE_ADV_HDR(pfd_p, 0) = PCIE_AER_GET(32, bus_p, 552*10187SKrishna.Elango@Sun.COM PCIE_AER_HDR_LOG); 553*10187SKrishna.Elango@Sun.COM PCIE_ADV_HDR(pfd_p, 1) = PCIE_AER_GET(32, bus_p, 554*10187SKrishna.Elango@Sun.COM PCIE_AER_HDR_LOG + 0x4); 555*10187SKrishna.Elango@Sun.COM PCIE_ADV_HDR(pfd_p, 2) = PCIE_AER_GET(32, bus_p, 556*10187SKrishna.Elango@Sun.COM PCIE_AER_HDR_LOG + 0x8); 557*10187SKrishna.Elango@Sun.COM PCIE_ADV_HDR(pfd_p, 3) = PCIE_AER_GET(32, bus_p, 558*10187SKrishna.Elango@Sun.COM PCIE_AER_HDR_LOG + 0xc); 559*10187SKrishna.Elango@Sun.COM 560*10187SKrishna.Elango@Sun.COM /* Gather CE AERs */ 561*10187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ce_status = PCIE_AER_GET(32, bus_p, 562*10187SKrishna.Elango@Sun.COM PCIE_AER_CE_STS); 563*10187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ce_mask = PCIE_AER_GET(32, bus_p, 564*10187SKrishna.Elango@Sun.COM PCIE_AER_CE_MASK); 565*10187SKrishna.Elango@Sun.COM 566*10187SKrishna.Elango@Sun.COM /* 567*10187SKrishna.Elango@Sun.COM * If pci express to pci bridge then grab the bridge 568*10187SKrishna.Elango@Sun.COM * error registers. 569*10187SKrishna.Elango@Sun.COM */ 570*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p)) { 571*10187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *pcie_bdg_regs = 572*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p); 573*10187SKrishna.Elango@Sun.COM 574*10187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_ctl = PCIE_AER_GET(32, bus_p, 575*10187SKrishna.Elango@Sun.COM PCIE_AER_SCTL); 576*10187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_status = PCIE_AER_GET(32, bus_p, 577*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_STS); 578*10187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_mask = PCIE_AER_GET(32, bus_p, 579*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MASK); 580*10187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_sev = PCIE_AER_GET(32, bus_p, 581*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_SERV); 582*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_HDR(pfd_p, 0) = PCIE_AER_GET(32, bus_p, 583*10187SKrishna.Elango@Sun.COM PCIE_AER_SHDR_LOG); 584*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_HDR(pfd_p, 1) = PCIE_AER_GET(32, bus_p, 585*10187SKrishna.Elango@Sun.COM PCIE_AER_SHDR_LOG + 0x4); 586*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_HDR(pfd_p, 2) = PCIE_AER_GET(32, bus_p, 587*10187SKrishna.Elango@Sun.COM PCIE_AER_SHDR_LOG + 0x8); 588*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_HDR(pfd_p, 3) = PCIE_AER_GET(32, bus_p, 589*10187SKrishna.Elango@Sun.COM PCIE_AER_SHDR_LOG + 0xc); 590*10187SKrishna.Elango@Sun.COM } 591*10187SKrishna.Elango@Sun.COM 592*10187SKrishna.Elango@Sun.COM /* 593*10187SKrishna.Elango@Sun.COM * If PCI Express root port then grab the root port 594*10187SKrishna.Elango@Sun.COM * error registers. 595*10187SKrishna.Elango@Sun.COM */ 596*10187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) { 597*10187SKrishna.Elango@Sun.COM pf_pcie_adv_rp_err_regs_t *pcie_rp_regs = 598*10187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p); 599*10187SKrishna.Elango@Sun.COM 600*10187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_err_cmd = PCIE_AER_GET(32, bus_p, 601*10187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD); 602*10187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_err_status = PCIE_AER_GET(32, bus_p, 603*10187SKrishna.Elango@Sun.COM PCIE_AER_RE_STS); 604*10187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_ce_src_id = PCIE_AER_GET(16, bus_p, 605*10187SKrishna.Elango@Sun.COM PCIE_AER_CE_SRC_ID); 606*10187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_ue_src_id = PCIE_AER_GET(16, bus_p, 607*10187SKrishna.Elango@Sun.COM PCIE_AER_ERR_SRC_ID); 608*10187SKrishna.Elango@Sun.COM } 609*10187SKrishna.Elango@Sun.COM } 610*10187SKrishna.Elango@Sun.COM 611*10187SKrishna.Elango@Sun.COM static void 612*10187SKrishna.Elango@Sun.COM pf_pci_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p) 613*10187SKrishna.Elango@Sun.COM { 614*10187SKrishna.Elango@Sun.COM pf_pci_err_regs_t *pci_regs = PCI_ERR_REG(pfd_p); 615*10187SKrishna.Elango@Sun.COM 616*10187SKrishna.Elango@Sun.COM /* 617*10187SKrishna.Elango@Sun.COM * Start by reading all the error registers that are available for 618*10187SKrishna.Elango@Sun.COM * pci and pci express and for leaf devices and bridges/switches 619*10187SKrishna.Elango@Sun.COM */ 620*10187SKrishna.Elango@Sun.COM pci_regs->pci_err_status = PCIE_GET(16, bus_p, PCI_CONF_STAT); 621*10187SKrishna.Elango@Sun.COM pci_regs->pci_cfg_comm = PCIE_GET(16, bus_p, PCI_CONF_COMM); 622*10187SKrishna.Elango@Sun.COM 623*10187SKrishna.Elango@Sun.COM /* 624*10187SKrishna.Elango@Sun.COM * If pci-pci bridge grab PCI bridge specific error registers. 625*10187SKrishna.Elango@Sun.COM */ 626*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 627*10187SKrishna.Elango@Sun.COM pf_pci_bdg_err_regs_t *pci_bdg_regs = PCI_BDG_ERR_REG(pfd_p); 628*10187SKrishna.Elango@Sun.COM pci_bdg_regs->pci_bdg_sec_stat = 629*10187SKrishna.Elango@Sun.COM PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS); 630*10187SKrishna.Elango@Sun.COM pci_bdg_regs->pci_bdg_ctrl = 631*10187SKrishna.Elango@Sun.COM PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL); 632*10187SKrishna.Elango@Sun.COM } 633*10187SKrishna.Elango@Sun.COM 634*10187SKrishna.Elango@Sun.COM /* 635*10187SKrishna.Elango@Sun.COM * If pci express device grab pci express error registers and 636*10187SKrishna.Elango@Sun.COM * check for advanced error reporting features and grab them if 637*10187SKrishna.Elango@Sun.COM * available. 638*10187SKrishna.Elango@Sun.COM */ 639*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) 640*10187SKrishna.Elango@Sun.COM pf_pcie_regs_gather(pfd_p, bus_p); 641*10187SKrishna.Elango@Sun.COM else if (PCIE_IS_PCIX(bus_p)) 642*10187SKrishna.Elango@Sun.COM pf_pcix_regs_gather(pfd_p, bus_p); 643*10187SKrishna.Elango@Sun.COM 644*10187SKrishna.Elango@Sun.COM } 645*10187SKrishna.Elango@Sun.COM 646*10187SKrishna.Elango@Sun.COM static void 647*10187SKrishna.Elango@Sun.COM pf_pcix_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p) 648*10187SKrishna.Elango@Sun.COM { 649*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 650*10187SKrishna.Elango@Sun.COM pf_pcix_bdg_err_regs_t *pcix_bdg_regs; 651*10187SKrishna.Elango@Sun.COM 652*10187SKrishna.Elango@Sun.COM pcix_bdg_regs = PCIX_BDG_ERR_REG(pfd_p); 653*10187SKrishna.Elango@Sun.COM 654*10187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(16, bus_p, PCI_PCIX_SEC_STATUS, 655*10187SKrishna.Elango@Sun.COM pcix_bdg_regs->pcix_bdg_sec_stat); 656*10187SKrishna.Elango@Sun.COM 657*10187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_STATUS, 658*10187SKrishna.Elango@Sun.COM pcix_bdg_regs->pcix_bdg_stat); 659*10187SKrishna.Elango@Sun.COM 660*10187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 661*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *pcix_bdg_ecc_regs; 662*10187SKrishna.Elango@Sun.COM /* 663*10187SKrishna.Elango@Sun.COM * PCI Express to PCI-X bridges only implement the 664*10187SKrishna.Elango@Sun.COM * secondary side of the PCI-X ECC registers. For 665*10187SKrishna.Elango@Sun.COM * clearing, there is no need to "select" the ECC 666*10187SKrishna.Elango@Sun.COM * register, just write what was originally read. 667*10187SKrishna.Elango@Sun.COM */ 668*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) { 669*10187SKrishna.Elango@Sun.COM pcix_bdg_ecc_regs = PCIX_BDG_ECC_REG(pfd_p, 0); 670*10187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS, 671*10187SKrishna.Elango@Sun.COM pcix_bdg_ecc_regs->pcix_ecc_ctlstat); 672*10187SKrishna.Elango@Sun.COM 673*10187SKrishna.Elango@Sun.COM } 674*10187SKrishna.Elango@Sun.COM pcix_bdg_ecc_regs = PCIX_BDG_ECC_REG(pfd_p, 1); 675*10187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS, 676*10187SKrishna.Elango@Sun.COM pcix_bdg_ecc_regs->pcix_ecc_ctlstat); 677*10187SKrishna.Elango@Sun.COM } 678*10187SKrishna.Elango@Sun.COM } else { 679*10187SKrishna.Elango@Sun.COM pf_pcix_err_regs_t *pcix_regs = PCIX_ERR_REG(pfd_p); 680*10187SKrishna.Elango@Sun.COM 681*10187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_STATUS, 682*10187SKrishna.Elango@Sun.COM pcix_regs->pcix_status); 683*10187SKrishna.Elango@Sun.COM 684*10187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 685*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *pcix_ecc_regs = PCIX_ECC_REG(pfd_p); 686*10187SKrishna.Elango@Sun.COM 687*10187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_ECC_STATUS, 688*10187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_ctlstat); 689*10187SKrishna.Elango@Sun.COM } 690*10187SKrishna.Elango@Sun.COM } 691*10187SKrishna.Elango@Sun.COM } 692*10187SKrishna.Elango@Sun.COM 693*10187SKrishna.Elango@Sun.COM static void 694*10187SKrishna.Elango@Sun.COM pf_pcie_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p) 695*10187SKrishna.Elango@Sun.COM { 696*10187SKrishna.Elango@Sun.COM pf_pcie_err_regs_t *pcie_regs = PCIE_ERR_REG(pfd_p); 697*10187SKrishna.Elango@Sun.COM pf_pcie_adv_err_regs_t *pcie_adv_regs = PCIE_ADV_REG(pfd_p); 698*10187SKrishna.Elango@Sun.COM 699*10187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS, pcie_regs->pcie_err_status); 700*10187SKrishna.Elango@Sun.COM 701*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) 702*10187SKrishna.Elango@Sun.COM pf_pcix_regs_clear(pfd_p, bus_p); 703*10187SKrishna.Elango@Sun.COM 704*10187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 705*10187SKrishna.Elango@Sun.COM return; 706*10187SKrishna.Elango@Sun.COM 707*10187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_STS, 708*10187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ue_status); 709*10187SKrishna.Elango@Sun.COM 710*10187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, 711*10187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ce_status); 712*10187SKrishna.Elango@Sun.COM 713*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p)) { 714*10187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *pcie_bdg_regs = 715*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p); 716*10187SKrishna.Elango@Sun.COM 717*10187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_STS, 718*10187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_status); 719*10187SKrishna.Elango@Sun.COM } 720*10187SKrishna.Elango@Sun.COM 721*10187SKrishna.Elango@Sun.COM /* 722*10187SKrishna.Elango@Sun.COM * If PCI Express root complex then clear the root complex 723*10187SKrishna.Elango@Sun.COM * error registers. 724*10187SKrishna.Elango@Sun.COM */ 725*10187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) { 726*10187SKrishna.Elango@Sun.COM pf_pcie_adv_rp_err_regs_t *pcie_rp_regs; 727*10187SKrishna.Elango@Sun.COM 728*10187SKrishna.Elango@Sun.COM pcie_rp_regs = PCIE_ADV_RP_REG(pfd_p); 729*10187SKrishna.Elango@Sun.COM 730*10187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_RE_STS, 731*10187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_err_status); 732*10187SKrishna.Elango@Sun.COM } 733*10187SKrishna.Elango@Sun.COM } 734*10187SKrishna.Elango@Sun.COM 735*10187SKrishna.Elango@Sun.COM static void 736*10187SKrishna.Elango@Sun.COM pf_pci_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p) 737*10187SKrishna.Elango@Sun.COM { 738*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) 739*10187SKrishna.Elango@Sun.COM pf_pcie_regs_clear(pfd_p, bus_p); 740*10187SKrishna.Elango@Sun.COM else if (PCIE_IS_PCIX(bus_p)) 741*10187SKrishna.Elango@Sun.COM pf_pcix_regs_clear(pfd_p, bus_p); 742*10187SKrishna.Elango@Sun.COM 743*10187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_STAT, pfd_p->pe_pci_regs->pci_err_status); 744*10187SKrishna.Elango@Sun.COM 745*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 746*10187SKrishna.Elango@Sun.COM pf_pci_bdg_err_regs_t *pci_bdg_regs = PCI_BDG_ERR_REG(pfd_p); 747*10187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, 748*10187SKrishna.Elango@Sun.COM pci_bdg_regs->pci_bdg_sec_stat); 749*10187SKrishna.Elango@Sun.COM } 750*10187SKrishna.Elango@Sun.COM } 751*10187SKrishna.Elango@Sun.COM 752*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 753*10187SKrishna.Elango@Sun.COM void 754*10187SKrishna.Elango@Sun.COM pcie_clear_errors(dev_info_t *dip) 755*10187SKrishna.Elango@Sun.COM { 756*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 757*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip); 758*10187SKrishna.Elango@Sun.COM 759*10187SKrishna.Elango@Sun.COM ASSERT(bus_p); 760*10187SKrishna.Elango@Sun.COM 761*10187SKrishna.Elango@Sun.COM pf_pci_regs_gather(pfd_p, bus_p); 762*10187SKrishna.Elango@Sun.COM pf_pci_regs_clear(pfd_p, bus_p); 763*10187SKrishna.Elango@Sun.COM } 764*10187SKrishna.Elango@Sun.COM 765*10187SKrishna.Elango@Sun.COM /* Find the fault BDF, fault Addr or full scan on a PCIe Root Port. */ 766*10187SKrishna.Elango@Sun.COM static void 767*10187SKrishna.Elango@Sun.COM pf_pci_find_rp_fault(pf_data_t *pfd_p, pcie_bus_t *bus_p) 768*10187SKrishna.Elango@Sun.COM { 769*10187SKrishna.Elango@Sun.COM pf_root_fault_t *root_fault = PCIE_ROOT_FAULT(pfd_p); 770*10187SKrishna.Elango@Sun.COM pf_pcie_adv_rp_err_regs_t *rp_regs = PCIE_ADV_RP_REG(pfd_p); 771*10187SKrishna.Elango@Sun.COM uint32_t root_err = rp_regs->pcie_rp_err_status; 772*10187SKrishna.Elango@Sun.COM uint32_t ue_err = PCIE_ADV_REG(pfd_p)->pcie_ue_status; 773*10187SKrishna.Elango@Sun.COM int num_faults = 0; 774*10187SKrishna.Elango@Sun.COM 775*10187SKrishna.Elango@Sun.COM /* Since this data structure is reused, make sure to reset it */ 776*10187SKrishna.Elango@Sun.COM root_fault->full_scan = B_FALSE; 777*10187SKrishna.Elango@Sun.COM root_fault->scan_bdf = PCIE_INVALID_BDF; 778*10187SKrishna.Elango@Sun.COM root_fault->scan_addr = 0; 779*10187SKrishna.Elango@Sun.COM 780*10187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p) && 781*10187SKrishna.Elango@Sun.COM (PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR)) { 782*10187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE; 783*10187SKrishna.Elango@Sun.COM return; 784*10187SKrishna.Elango@Sun.COM } 785*10187SKrishna.Elango@Sun.COM 786*10187SKrishna.Elango@Sun.COM /* 787*10187SKrishna.Elango@Sun.COM * Check to see if an error has been received that 788*10187SKrishna.Elango@Sun.COM * requires a scan of the fabric. Count the number of 789*10187SKrishna.Elango@Sun.COM * faults seen. If MUL CE/FE_NFE that counts for 790*10187SKrishna.Elango@Sun.COM * atleast 2 faults, so just return with full_scan. 791*10187SKrishna.Elango@Sun.COM */ 792*10187SKrishna.Elango@Sun.COM if ((root_err & PCIE_AER_RE_STS_MUL_CE_RCVD) || 793*10187SKrishna.Elango@Sun.COM (root_err & PCIE_AER_RE_STS_MUL_FE_NFE_RCVD)) { 794*10187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE; 795*10187SKrishna.Elango@Sun.COM return; 796*10187SKrishna.Elango@Sun.COM } 797*10187SKrishna.Elango@Sun.COM 798*10187SKrishna.Elango@Sun.COM if (root_err & PCIE_AER_RE_STS_CE_RCVD) 799*10187SKrishna.Elango@Sun.COM num_faults++; 800*10187SKrishna.Elango@Sun.COM 801*10187SKrishna.Elango@Sun.COM if (root_err & PCIE_AER_RE_STS_FE_NFE_RCVD) 802*10187SKrishna.Elango@Sun.COM num_faults++; 803*10187SKrishna.Elango@Sun.COM 804*10187SKrishna.Elango@Sun.COM if (ue_err & PCIE_AER_UCE_CA) 805*10187SKrishna.Elango@Sun.COM num_faults++; 806*10187SKrishna.Elango@Sun.COM 807*10187SKrishna.Elango@Sun.COM if (ue_err & PCIE_AER_UCE_UR) 808*10187SKrishna.Elango@Sun.COM num_faults++; 809*10187SKrishna.Elango@Sun.COM 810*10187SKrishna.Elango@Sun.COM /* If no faults just return */ 811*10187SKrishna.Elango@Sun.COM if (num_faults == 0) 812*10187SKrishna.Elango@Sun.COM return; 813*10187SKrishna.Elango@Sun.COM 814*10187SKrishna.Elango@Sun.COM /* If faults > 1 do full scan */ 815*10187SKrishna.Elango@Sun.COM if (num_faults > 1) { 816*10187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE; 817*10187SKrishna.Elango@Sun.COM return; 818*10187SKrishna.Elango@Sun.COM } 819*10187SKrishna.Elango@Sun.COM 820*10187SKrishna.Elango@Sun.COM /* By this point, there is only 1 fault detected */ 821*10187SKrishna.Elango@Sun.COM if (root_err & PCIE_AER_RE_STS_CE_RCVD) { 822*10187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = rp_regs->pcie_rp_ce_src_id; 823*10187SKrishna.Elango@Sun.COM num_faults--; 824*10187SKrishna.Elango@Sun.COM } else if (root_err & PCIE_AER_RE_STS_FE_NFE_RCVD) { 825*10187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = rp_regs->pcie_rp_ue_src_id; 826*10187SKrishna.Elango@Sun.COM num_faults--; 827*10187SKrishna.Elango@Sun.COM } else if ((HAS_AER_LOGS(pfd_p, PCIE_AER_UCE_CA) || 828*10187SKrishna.Elango@Sun.COM HAS_AER_LOGS(pfd_p, PCIE_AER_UCE_UR)) && 829*10187SKrishna.Elango@Sun.COM (pf_tlp_decode(PCIE_PFD2BUS(pfd_p), PCIE_ADV_REG(pfd_p)) == 830*10187SKrishna.Elango@Sun.COM DDI_SUCCESS)) { 831*10187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_addr = 832*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr; 833*10187SKrishna.Elango@Sun.COM num_faults--; 834*10187SKrishna.Elango@Sun.COM } 835*10187SKrishna.Elango@Sun.COM 836*10187SKrishna.Elango@Sun.COM /* 837*10187SKrishna.Elango@Sun.COM * This means an error did occur, but we couldn't extract the fault BDF 838*10187SKrishna.Elango@Sun.COM */ 839*10187SKrishna.Elango@Sun.COM if (num_faults > 0) 840*10187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE; 841*10187SKrishna.Elango@Sun.COM 842*10187SKrishna.Elango@Sun.COM } 843*10187SKrishna.Elango@Sun.COM 844*10187SKrishna.Elango@Sun.COM 845*10187SKrishna.Elango@Sun.COM /* 846*10187SKrishna.Elango@Sun.COM * Load PCIe Fault Data for PCI/PCIe devices into PCIe Fault Data Queue 847*10187SKrishna.Elango@Sun.COM * 848*10187SKrishna.Elango@Sun.COM * Returns a scan flag. 849*10187SKrishna.Elango@Sun.COM * o PF_SCAN_SUCCESS - Error gathered and cleared sucessfuly, data added to 850*10187SKrishna.Elango@Sun.COM * Fault Q 851*10187SKrishna.Elango@Sun.COM * o PF_SCAN_BAD_RESPONSE - Unable to talk to device, item not added to fault Q 852*10187SKrishna.Elango@Sun.COM * o PF_SCAN_CB_FAILURE - A hardened device deemed that the error was fatal. 853*10187SKrishna.Elango@Sun.COM * o PF_SCAN_NO_ERR_IN_CHILD - Only applies to bridge to prevent further 854*10187SKrishna.Elango@Sun.COM * unnecessary scanning 855*10187SKrishna.Elango@Sun.COM * o PF_SCAN_IN_DQ - This device has already been scanned; it was skipped this 856*10187SKrishna.Elango@Sun.COM * time. 857*10187SKrishna.Elango@Sun.COM */ 858*10187SKrishna.Elango@Sun.COM static int 859*10187SKrishna.Elango@Sun.COM pf_default_hdl(dev_info_t *dip, pf_impl_t *impl) 860*10187SKrishna.Elango@Sun.COM { 861*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 862*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip); 863*10187SKrishna.Elango@Sun.COM int cb_sts, scan_flag = PF_SCAN_SUCCESS; 864*10187SKrishna.Elango@Sun.COM 865*10187SKrishna.Elango@Sun.COM /* Make sure this device hasn't already been snapshotted and cleared */ 866*10187SKrishna.Elango@Sun.COM if (pfd_p->pe_valid == B_TRUE) { 867*10187SKrishna.Elango@Sun.COM scan_flag |= PF_SCAN_IN_DQ; 868*10187SKrishna.Elango@Sun.COM goto done; 869*10187SKrishna.Elango@Sun.COM } 870*10187SKrishna.Elango@Sun.COM 871*10187SKrishna.Elango@Sun.COM /* 872*10187SKrishna.Elango@Sun.COM * Read vendor/device ID and check with cached data, if it doesn't match 873*10187SKrishna.Elango@Sun.COM * could very well be a device that isn't responding anymore. Just 874*10187SKrishna.Elango@Sun.COM * stop. Save the basic info in the error q for post mortem debugging 875*10187SKrishna.Elango@Sun.COM * purposes. 876*10187SKrishna.Elango@Sun.COM */ 877*10187SKrishna.Elango@Sun.COM if (PCIE_GET(32, bus_p, PCI_CONF_VENID) != bus_p->bus_dev_ven_id) { 878*10187SKrishna.Elango@Sun.COM char buf[FM_MAX_CLASS]; 879*10187SKrishna.Elango@Sun.COM 880*10187SKrishna.Elango@Sun.COM (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 881*10187SKrishna.Elango@Sun.COM PCI_ERROR_SUBCLASS, PCI_NR); 882*10187SKrishna.Elango@Sun.COM ddi_fm_ereport_post(dip, buf, fm_ena_generate(0, FM_ENA_FMT1), 883*10187SKrishna.Elango@Sun.COM DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 884*10187SKrishna.Elango@Sun.COM 885*10187SKrishna.Elango@Sun.COM return (PF_SCAN_BAD_RESPONSE); 886*10187SKrishna.Elango@Sun.COM } 887*10187SKrishna.Elango@Sun.COM 888*10187SKrishna.Elango@Sun.COM pf_pci_regs_gather(pfd_p, bus_p); 889*10187SKrishna.Elango@Sun.COM pf_pci_regs_clear(pfd_p, bus_p); 890*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 891*10187SKrishna.Elango@Sun.COM pf_pci_find_rp_fault(pfd_p, bus_p); 892*10187SKrishna.Elango@Sun.COM 893*10187SKrishna.Elango@Sun.COM cb_sts = pf_fm_callback(dip, impl->pf_derr); 894*10187SKrishna.Elango@Sun.COM 895*10187SKrishna.Elango@Sun.COM if (cb_sts == DDI_FM_FATAL || cb_sts == DDI_FM_UNKNOWN) 896*10187SKrishna.Elango@Sun.COM scan_flag |= PF_SCAN_CB_FAILURE; 897*10187SKrishna.Elango@Sun.COM 898*10187SKrishna.Elango@Sun.COM /* Add the snapshot to the error q */ 899*10187SKrishna.Elango@Sun.COM pf_en_dq(pfd_p, impl); 900*10187SKrishna.Elango@Sun.COM 901*10187SKrishna.Elango@Sun.COM done: 902*10187SKrishna.Elango@Sun.COM /* 903*10187SKrishna.Elango@Sun.COM * If a bridge does not have any error no need to scan any further down. 904*10187SKrishna.Elango@Sun.COM * For PCIe devices, check the PCIe device status and PCI secondary 905*10187SKrishna.Elango@Sun.COM * status. 906*10187SKrishna.Elango@Sun.COM * - Some non-compliant PCIe devices do not utilize PCIe 907*10187SKrishna.Elango@Sun.COM * error registers. If so rely on legacy PCI error registers. 908*10187SKrishna.Elango@Sun.COM * For PCI devices, check the PCI secondary status. 909*10187SKrishna.Elango@Sun.COM */ 910*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && 911*10187SKrishna.Elango@Sun.COM !(PCIE_ERR_REG(pfd_p)->pcie_err_status & PF_PCIE_BDG_ERR) && 912*10187SKrishna.Elango@Sun.COM !(PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR)) 913*10187SKrishna.Elango@Sun.COM scan_flag |= PF_SCAN_NO_ERR_IN_CHILD; 914*10187SKrishna.Elango@Sun.COM 915*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCI_BDG(bus_p) && 916*10187SKrishna.Elango@Sun.COM !(PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR)) 917*10187SKrishna.Elango@Sun.COM scan_flag |= PF_SCAN_NO_ERR_IN_CHILD; 918*10187SKrishna.Elango@Sun.COM 919*10187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_TRUE; 920*10187SKrishna.Elango@Sun.COM return (scan_flag); 921*10187SKrishna.Elango@Sun.COM } 922*10187SKrishna.Elango@Sun.COM 923*10187SKrishna.Elango@Sun.COM /* 924*10187SKrishna.Elango@Sun.COM * Called during postattach to initialize a device's error handling 925*10187SKrishna.Elango@Sun.COM * capabilities. If the devices has already been hardened, then there isn't 926*10187SKrishna.Elango@Sun.COM * much needed. Otherwise initialize the device's default FMA capabilities. 927*10187SKrishna.Elango@Sun.COM * 928*10187SKrishna.Elango@Sun.COM * In a future project where PCIe support is removed from pcifm, several 929*10187SKrishna.Elango@Sun.COM * "properties" that are setup in ddi_fm_init and pci_ereport_setup need to be 930*10187SKrishna.Elango@Sun.COM * created here so that the PCI/PCIe eversholt rules will work properly. 931*10187SKrishna.Elango@Sun.COM */ 932*10187SKrishna.Elango@Sun.COM void 933*10187SKrishna.Elango@Sun.COM pf_init(dev_info_t *dip, ddi_iblock_cookie_t ibc, ddi_attach_cmd_t cmd) 934*10187SKrishna.Elango@Sun.COM { 935*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 936*10187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 937*10187SKrishna.Elango@Sun.COM boolean_t need_cb_register = B_FALSE; 938*10187SKrishna.Elango@Sun.COM 939*10187SKrishna.Elango@Sun.COM if (!bus_p) { 940*10187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, "devi_bus information is not set for %s%d.\n", 941*10187SKrishna.Elango@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 942*10187SKrishna.Elango@Sun.COM return; 943*10187SKrishna.Elango@Sun.COM } 944*10187SKrishna.Elango@Sun.COM 945*10187SKrishna.Elango@Sun.COM if (fmhdl) { 946*10187SKrishna.Elango@Sun.COM /* 947*10187SKrishna.Elango@Sun.COM * If device is only ereport capable and not callback capable 948*10187SKrishna.Elango@Sun.COM * make it callback capable. The only downside is that the 949*10187SKrishna.Elango@Sun.COM * "fm-errcb-capable" property is not created for this device 950*10187SKrishna.Elango@Sun.COM * which should be ok since it's not used anywhere. 951*10187SKrishna.Elango@Sun.COM */ 952*10187SKrishna.Elango@Sun.COM if (!(fmhdl->fh_cap & DDI_FM_ERRCB_CAPABLE)) 953*10187SKrishna.Elango@Sun.COM need_cb_register = B_TRUE; 954*10187SKrishna.Elango@Sun.COM } else { 955*10187SKrishna.Elango@Sun.COM int cap; 956*10187SKrishna.Elango@Sun.COM /* 957*10187SKrishna.Elango@Sun.COM * fm-capable in driver.conf can be used to set fm_capabilities. 958*10187SKrishna.Elango@Sun.COM * If fm-capable is not defined, set the default 959*10187SKrishna.Elango@Sun.COM * DDI_FM_EREPORT_CAPABLE and DDI_FM_ERRCB_CAPABLE. 960*10187SKrishna.Elango@Sun.COM */ 961*10187SKrishna.Elango@Sun.COM cap = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 962*10187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "fm-capable", 963*10187SKrishna.Elango@Sun.COM DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE); 964*10187SKrishna.Elango@Sun.COM cap &= (DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE); 965*10187SKrishna.Elango@Sun.COM 966*10187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags |= PF_FM_IS_NH; 967*10187SKrishna.Elango@Sun.COM 968*10187SKrishna.Elango@Sun.COM if (cmd == DDI_ATTACH) { 969*10187SKrishna.Elango@Sun.COM ddi_fm_init(dip, &cap, &ibc); 970*10187SKrishna.Elango@Sun.COM pci_ereport_setup(dip); 971*10187SKrishna.Elango@Sun.COM } 972*10187SKrishna.Elango@Sun.COM 973*10187SKrishna.Elango@Sun.COM if (cap & DDI_FM_ERRCB_CAPABLE) 974*10187SKrishna.Elango@Sun.COM need_cb_register = B_TRUE; 975*10187SKrishna.Elango@Sun.COM 976*10187SKrishna.Elango@Sun.COM fmhdl = DEVI(dip)->devi_fmhdl; 977*10187SKrishna.Elango@Sun.COM } 978*10187SKrishna.Elango@Sun.COM 979*10187SKrishna.Elango@Sun.COM /* If ddi_fm_init fails for any reason RETURN */ 980*10187SKrishna.Elango@Sun.COM if (!fmhdl) { 981*10187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags = 0; 982*10187SKrishna.Elango@Sun.COM return; 983*10187SKrishna.Elango@Sun.COM } 984*10187SKrishna.Elango@Sun.COM 985*10187SKrishna.Elango@Sun.COM fmhdl->fh_cap |= DDI_FM_ERRCB_CAPABLE; 986*10187SKrishna.Elango@Sun.COM if (cmd == DDI_ATTACH) { 987*10187SKrishna.Elango@Sun.COM if (need_cb_register) 988*10187SKrishna.Elango@Sun.COM ddi_fm_handler_register(dip, pf_dummy_cb, NULL); 989*10187SKrishna.Elango@Sun.COM } 990*10187SKrishna.Elango@Sun.COM 991*10187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags |= PF_FM_READY; 992*10187SKrishna.Elango@Sun.COM } 993*10187SKrishna.Elango@Sun.COM 994*10187SKrishna.Elango@Sun.COM /* undo FMA lock, called at predetach */ 995*10187SKrishna.Elango@Sun.COM void 996*10187SKrishna.Elango@Sun.COM pf_fini(dev_info_t *dip, ddi_detach_cmd_t cmd) 997*10187SKrishna.Elango@Sun.COM { 998*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 999*10187SKrishna.Elango@Sun.COM 1000*10187SKrishna.Elango@Sun.COM if (!bus_p) 1001*10187SKrishna.Elango@Sun.COM return; 1002*10187SKrishna.Elango@Sun.COM 1003*10187SKrishna.Elango@Sun.COM /* Don't fini anything if device isn't FM Ready */ 1004*10187SKrishna.Elango@Sun.COM if (!(bus_p->bus_fm_flags & PF_FM_READY)) 1005*10187SKrishna.Elango@Sun.COM return; 1006*10187SKrishna.Elango@Sun.COM 1007*10187SKrishna.Elango@Sun.COM /* no other code should set the flag to false */ 1008*10187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags &= ~PF_FM_READY; 1009*10187SKrishna.Elango@Sun.COM 1010*10187SKrishna.Elango@Sun.COM /* 1011*10187SKrishna.Elango@Sun.COM * Grab the mutex to make sure device isn't in the middle of 1012*10187SKrishna.Elango@Sun.COM * error handling. Setting the bus_fm_flag to ~PF_FM_READY 1013*10187SKrishna.Elango@Sun.COM * should prevent this device from being error handled after 1014*10187SKrishna.Elango@Sun.COM * the mutex has been released. 1015*10187SKrishna.Elango@Sun.COM */ 1016*10187SKrishna.Elango@Sun.COM (void) pf_handler_enter(dip, NULL); 1017*10187SKrishna.Elango@Sun.COM pf_handler_exit(dip); 1018*10187SKrishna.Elango@Sun.COM 1019*10187SKrishna.Elango@Sun.COM /* undo non-hardened drivers */ 1020*10187SKrishna.Elango@Sun.COM if (bus_p->bus_fm_flags & PF_FM_IS_NH) { 1021*10187SKrishna.Elango@Sun.COM if (cmd == DDI_DETACH) { 1022*10187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags &= ~PF_FM_IS_NH; 1023*10187SKrishna.Elango@Sun.COM pci_ereport_teardown(dip); 1024*10187SKrishna.Elango@Sun.COM /* 1025*10187SKrishna.Elango@Sun.COM * ddi_fini itself calls ddi_handler_unregister, 1026*10187SKrishna.Elango@Sun.COM * so no need to explicitly call unregister. 1027*10187SKrishna.Elango@Sun.COM */ 1028*10187SKrishna.Elango@Sun.COM ddi_fm_fini(dip); 1029*10187SKrishna.Elango@Sun.COM } 1030*10187SKrishna.Elango@Sun.COM } 1031*10187SKrishna.Elango@Sun.COM } 1032*10187SKrishna.Elango@Sun.COM 1033*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/ 1034*10187SKrishna.Elango@Sun.COM static int 1035*10187SKrishna.Elango@Sun.COM pf_dummy_cb(dev_info_t *dip, ddi_fm_error_t *derr, const void *not_used) 1036*10187SKrishna.Elango@Sun.COM { 1037*10187SKrishna.Elango@Sun.COM return (DDI_FM_OK); 1038*10187SKrishna.Elango@Sun.COM } 1039*10187SKrishna.Elango@Sun.COM 1040*10187SKrishna.Elango@Sun.COM /* 1041*10187SKrishna.Elango@Sun.COM * Add PFD to queue. If it is an RC add it to the beginning, 1042*10187SKrishna.Elango@Sun.COM * otherwise add it to the end. 1043*10187SKrishna.Elango@Sun.COM */ 1044*10187SKrishna.Elango@Sun.COM static void 1045*10187SKrishna.Elango@Sun.COM pf_en_dq(pf_data_t *pfd_p, pf_impl_t *impl) 1046*10187SKrishna.Elango@Sun.COM { 1047*10187SKrishna.Elango@Sun.COM pf_data_t *head_p = impl->pf_dq_head_p; 1048*10187SKrishna.Elango@Sun.COM pf_data_t *tail_p = impl->pf_dq_tail_p; 1049*10187SKrishna.Elango@Sun.COM 1050*10187SKrishna.Elango@Sun.COM impl->pf_total++; 1051*10187SKrishna.Elango@Sun.COM 1052*10187SKrishna.Elango@Sun.COM if (!head_p) { 1053*10187SKrishna.Elango@Sun.COM ASSERT(PFD_IS_ROOT(pfd_p)); 1054*10187SKrishna.Elango@Sun.COM impl->pf_dq_head_p = pfd_p; 1055*10187SKrishna.Elango@Sun.COM impl->pf_dq_tail_p = pfd_p; 1056*10187SKrishna.Elango@Sun.COM pfd_p->pe_prev = NULL; 1057*10187SKrishna.Elango@Sun.COM pfd_p->pe_next = NULL; 1058*10187SKrishna.Elango@Sun.COM return; 1059*10187SKrishna.Elango@Sun.COM } 1060*10187SKrishna.Elango@Sun.COM 1061*10187SKrishna.Elango@Sun.COM /* Check if this is a Root Port eprt */ 1062*10187SKrishna.Elango@Sun.COM if (PFD_IS_ROOT(pfd_p)) { 1063*10187SKrishna.Elango@Sun.COM pf_data_t *root_p, *last_p = NULL; 1064*10187SKrishna.Elango@Sun.COM 1065*10187SKrishna.Elango@Sun.COM /* The first item must be a RP */ 1066*10187SKrishna.Elango@Sun.COM root_p = head_p; 1067*10187SKrishna.Elango@Sun.COM for (last_p = head_p; last_p && PFD_IS_ROOT(last_p); 1068*10187SKrishna.Elango@Sun.COM last_p = last_p->pe_next) 1069*10187SKrishna.Elango@Sun.COM root_p = last_p; 1070*10187SKrishna.Elango@Sun.COM 1071*10187SKrishna.Elango@Sun.COM /* root_p is the last RP pfd. last_p is the first non-RP pfd. */ 1072*10187SKrishna.Elango@Sun.COM root_p->pe_next = pfd_p; 1073*10187SKrishna.Elango@Sun.COM pfd_p->pe_prev = root_p; 1074*10187SKrishna.Elango@Sun.COM pfd_p->pe_next = last_p; 1075*10187SKrishna.Elango@Sun.COM 1076*10187SKrishna.Elango@Sun.COM if (last_p) 1077*10187SKrishna.Elango@Sun.COM last_p->pe_prev = pfd_p; 1078*10187SKrishna.Elango@Sun.COM else 1079*10187SKrishna.Elango@Sun.COM tail_p = pfd_p; 1080*10187SKrishna.Elango@Sun.COM } else { 1081*10187SKrishna.Elango@Sun.COM tail_p->pe_next = pfd_p; 1082*10187SKrishna.Elango@Sun.COM pfd_p->pe_prev = tail_p; 1083*10187SKrishna.Elango@Sun.COM pfd_p->pe_next = NULL; 1084*10187SKrishna.Elango@Sun.COM tail_p = pfd_p; 1085*10187SKrishna.Elango@Sun.COM } 1086*10187SKrishna.Elango@Sun.COM 1087*10187SKrishna.Elango@Sun.COM impl->pf_dq_head_p = head_p; 1088*10187SKrishna.Elango@Sun.COM impl->pf_dq_tail_p = tail_p; 1089*10187SKrishna.Elango@Sun.COM } 1090*10187SKrishna.Elango@Sun.COM 1091*10187SKrishna.Elango@Sun.COM /* 1092*10187SKrishna.Elango@Sun.COM * Ignore: 1093*10187SKrishna.Elango@Sun.COM * - TRAINING: as leaves do not have children 1094*10187SKrishna.Elango@Sun.COM * - SD: as leaves do not have children 1095*10187SKrishna.Elango@Sun.COM */ 1096*10187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_pcie_tbl[] = { 1097*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_DLP, pf_panic, 1098*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_PTLP, pf_analyse_ptlp, 1099*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP, pf_panic, 1100*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TO, pf_analyse_to, 1101*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_CA, pf_analyse_ca_ur, 1102*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_UC, pf_analyse_uc, 1103*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_RO, pf_panic, 1104*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_MTLP, pf_panic, 1105*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_ECRC, pf_panic, 1106*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_UR, pf_analyse_ca_ur, 1107*10187SKrishna.Elango@Sun.COM NULL, NULL 1108*10187SKrishna.Elango@Sun.COM }; 1109*10187SKrishna.Elango@Sun.COM 1110*10187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_rp_tbl[] = { 1111*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TRAINING, pf_no_panic, 1112*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_DLP, pf_panic, 1113*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_SD, pf_no_panic, 1114*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_PTLP, pf_analyse_ptlp, 1115*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP, pf_panic, 1116*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TO, pf_panic, 1117*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_CA, pf_no_panic, 1118*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_UC, pf_analyse_uc, 1119*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_RO, pf_panic, 1120*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_MTLP, pf_panic, 1121*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_ECRC, pf_panic, 1122*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_UR, pf_no_panic, 1123*10187SKrishna.Elango@Sun.COM NULL, NULL 1124*10187SKrishna.Elango@Sun.COM }; 1125*10187SKrishna.Elango@Sun.COM 1126*10187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_sw_tbl[] = { 1127*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TRAINING, pf_no_panic, 1128*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_DLP, pf_panic, 1129*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_SD, pf_no_panic, 1130*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_PTLP, pf_analyse_ptlp, 1131*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP, pf_panic, 1132*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TO, pf_analyse_to, 1133*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_CA, pf_analyse_ca_ur, 1134*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_UC, pf_analyse_uc, 1135*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_RO, pf_panic, 1136*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_MTLP, pf_panic, 1137*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_ECRC, pf_panic, 1138*10187SKrishna.Elango@Sun.COM PCIE_AER_UCE_UR, pf_analyse_ca_ur, 1139*10187SKrishna.Elango@Sun.COM NULL, NULL 1140*10187SKrishna.Elango@Sun.COM }; 1141*10187SKrishna.Elango@Sun.COM 1142*10187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_pcie_bdg_tbl[] = { 1143*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_TA_ON_SC, pf_analyse_sc, 1144*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MA_ON_SC, pf_analyse_sc, 1145*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_RCVD_TA, pf_analyse_ma_ta, 1146*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_RCVD_MA, pf_analyse_ma_ta, 1147*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_USC_ERR, pf_panic, 1148*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_USC_MSG_DATA_ERR, pf_analyse_ma_ta, 1149*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_DATA_ERR, pf_analyse_uc_data, 1150*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_ATTR_ERR, pf_panic, 1151*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_ADDR_ERR, pf_panic, 1152*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_TIMER_EXPIRED, pf_panic, 1153*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_PERR_ASSERT, pf_analyse_perr_assert, 1154*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_SERR_ASSERT, pf_no_panic, 1155*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_INTERNAL_ERR, pf_panic, 1156*10187SKrishna.Elango@Sun.COM NULL, NULL 1157*10187SKrishna.Elango@Sun.COM }; 1158*10187SKrishna.Elango@Sun.COM 1159*10187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_pci_bdg_tbl[] = { 1160*10187SKrishna.Elango@Sun.COM PCI_STAT_PERROR, pf_analyse_pci, 1161*10187SKrishna.Elango@Sun.COM PCI_STAT_S_PERROR, pf_analyse_pci, 1162*10187SKrishna.Elango@Sun.COM PCI_STAT_S_SYSERR, pf_panic, 1163*10187SKrishna.Elango@Sun.COM PCI_STAT_R_MAST_AB, pf_analyse_pci, 1164*10187SKrishna.Elango@Sun.COM PCI_STAT_R_TARG_AB, pf_analyse_pci, 1165*10187SKrishna.Elango@Sun.COM PCI_STAT_S_TARG_AB, pf_analyse_pci, 1166*10187SKrishna.Elango@Sun.COM NULL, NULL 1167*10187SKrishna.Elango@Sun.COM }; 1168*10187SKrishna.Elango@Sun.COM 1169*10187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_pci_tbl[] = { 1170*10187SKrishna.Elango@Sun.COM PCI_STAT_PERROR, pf_analyse_pci, 1171*10187SKrishna.Elango@Sun.COM PCI_STAT_S_PERROR, pf_analyse_pci, 1172*10187SKrishna.Elango@Sun.COM PCI_STAT_S_SYSERR, pf_panic, 1173*10187SKrishna.Elango@Sun.COM PCI_STAT_R_MAST_AB, pf_analyse_pci, 1174*10187SKrishna.Elango@Sun.COM PCI_STAT_R_TARG_AB, pf_analyse_pci, 1175*10187SKrishna.Elango@Sun.COM PCI_STAT_S_TARG_AB, pf_analyse_pci, 1176*10187SKrishna.Elango@Sun.COM NULL, NULL 1177*10187SKrishna.Elango@Sun.COM }; 1178*10187SKrishna.Elango@Sun.COM 1179*10187SKrishna.Elango@Sun.COM #define PF_MASKED_AER_ERR(pfd_p) \ 1180*10187SKrishna.Elango@Sun.COM (PCIE_ADV_REG(pfd_p)->pcie_ue_status & \ 1181*10187SKrishna.Elango@Sun.COM ((PCIE_ADV_REG(pfd_p)->pcie_ue_mask) ^ 0xFFFFFFFF)) 1182*10187SKrishna.Elango@Sun.COM #define PF_MASKED_SAER_ERR(pfd_p) \ 1183*10187SKrishna.Elango@Sun.COM (PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status & \ 1184*10187SKrishna.Elango@Sun.COM ((PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_mask) ^ 0xFFFFFFFF)) 1185*10187SKrishna.Elango@Sun.COM /* 1186*10187SKrishna.Elango@Sun.COM * Analyse all the PCIe Fault Data (erpt) gathered during dispatch in the erpt 1187*10187SKrishna.Elango@Sun.COM * Queue. 1188*10187SKrishna.Elango@Sun.COM */ 1189*10187SKrishna.Elango@Sun.COM static int 1190*10187SKrishna.Elango@Sun.COM pf_analyse_error(ddi_fm_error_t *derr, pf_impl_t *impl) 1191*10187SKrishna.Elango@Sun.COM { 1192*10187SKrishna.Elango@Sun.COM int sts_flags, error_flags = 0; 1193*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p; 1194*10187SKrishna.Elango@Sun.COM 1195*10187SKrishna.Elango@Sun.COM for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) { 1196*10187SKrishna.Elango@Sun.COM sts_flags = 0; 1197*10187SKrishna.Elango@Sun.COM 1198*10187SKrishna.Elango@Sun.COM switch (PCIE_PFD2BUS(pfd_p)->bus_dev_type) { 1199*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: 1200*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI_DEV: 1201*10187SKrishna.Elango@Sun.COM if (PCIE_DEVSTS_CE_DETECTED & 1202*10187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status) 1203*10187SKrishna.Elango@Sun.COM sts_flags |= PF_ERR_CE; 1204*10187SKrishna.Elango@Sun.COM 1205*10187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pfd_p); 1206*10187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl, 1207*10187SKrishna.Elango@Sun.COM pfd_p, pcie_pcie_tbl, PF_MASKED_AER_ERR(pfd_p)); 1208*10187SKrishna.Elango@Sun.COM break; 1209*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_ROOT: 1210*10187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pfd_p); 1211*10187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl, 1212*10187SKrishna.Elango@Sun.COM pfd_p, pcie_rp_tbl, PF_MASKED_AER_ERR(pfd_p)); 1213*10187SKrishna.Elango@Sun.COM break; 1214*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO: 1215*10187SKrishna.Elango@Sun.COM /* no adjust_for_aer for pseudo RC */ 1216*10187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl, pfd_p, 1217*10187SKrishna.Elango@Sun.COM pcie_rp_tbl, PF_MASKED_AER_ERR(pfd_p)); 1218*10187SKrishna.Elango@Sun.COM break; 1219*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_UP: 1220*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_DOWN: 1221*10187SKrishna.Elango@Sun.COM if (PCIE_DEVSTS_CE_DETECTED & 1222*10187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status) 1223*10187SKrishna.Elango@Sun.COM sts_flags |= PF_ERR_CE; 1224*10187SKrishna.Elango@Sun.COM 1225*10187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pfd_p); 1226*10187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl, 1227*10187SKrishna.Elango@Sun.COM pfd_p, pcie_sw_tbl, PF_MASKED_AER_ERR(pfd_p)); 1228*10187SKrishna.Elango@Sun.COM break; 1229*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: 1230*10187SKrishna.Elango@Sun.COM if (PCIE_DEVSTS_CE_DETECTED & 1231*10187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status) 1232*10187SKrishna.Elango@Sun.COM sts_flags |= PF_ERR_CE; 1233*10187SKrishna.Elango@Sun.COM 1234*10187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pfd_p); 1235*10187SKrishna.Elango@Sun.COM pf_adjust_for_no_saer(pfd_p); 1236*10187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, 1237*10187SKrishna.Elango@Sun.COM impl, pfd_p, pcie_pcie_tbl, 1238*10187SKrishna.Elango@Sun.COM PF_MASKED_AER_ERR(pfd_p)); 1239*10187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, 1240*10187SKrishna.Elango@Sun.COM impl, pfd_p, pcie_pcie_bdg_tbl, 1241*10187SKrishna.Elango@Sun.COM PF_MASKED_SAER_ERR(pfd_p)); 1242*10187SKrishna.Elango@Sun.COM /* 1243*10187SKrishna.Elango@Sun.COM * Some non-compliant PCIe devices do not utilize PCIe 1244*10187SKrishna.Elango@Sun.COM * error registers. So fallthrough and rely on legacy 1245*10187SKrishna.Elango@Sun.COM * PCI error registers. 1246*10187SKrishna.Elango@Sun.COM */ 1247*10187SKrishna.Elango@Sun.COM if ((PCIE_DEVSTS_NFE_DETECTED | PCIE_DEVSTS_FE_DETECTED) 1248*10187SKrishna.Elango@Sun.COM & PCIE_ERR_REG(pfd_p)->pcie_err_status) 1249*10187SKrishna.Elango@Sun.COM break; 1250*10187SKrishna.Elango@Sun.COM /* FALLTHROUGH */ 1251*10187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO: 1252*10187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl, 1253*10187SKrishna.Elango@Sun.COM pfd_p, pcie_pci_tbl, 1254*10187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p)->pci_err_status); 1255*10187SKrishna.Elango@Sun.COM 1256*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_BDG(PCIE_PFD2BUS(pfd_p))) 1257*10187SKrishna.Elango@Sun.COM break; 1258*10187SKrishna.Elango@Sun.COM 1259*10187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, 1260*10187SKrishna.Elango@Sun.COM impl, pfd_p, pcie_pci_bdg_tbl, 1261*10187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat); 1262*10187SKrishna.Elango@Sun.COM } 1263*10187SKrishna.Elango@Sun.COM 1264*10187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = sts_flags; 1265*10187SKrishna.Elango@Sun.COM error_flags |= pfd_p->pe_severity_flags; 1266*10187SKrishna.Elango@Sun.COM } 1267*10187SKrishna.Elango@Sun.COM 1268*10187SKrishna.Elango@Sun.COM return (error_flags); 1269*10187SKrishna.Elango@Sun.COM } 1270*10187SKrishna.Elango@Sun.COM 1271*10187SKrishna.Elango@Sun.COM static int 1272*10187SKrishna.Elango@Sun.COM pf_analyse_error_tbl(ddi_fm_error_t *derr, pf_impl_t *impl, 1273*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p, const pf_fab_err_tbl_t *tbl, uint32_t err_reg) { 1274*10187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t *row; 1275*10187SKrishna.Elango@Sun.COM int err = 0; 1276*10187SKrishna.Elango@Sun.COM 1277*10187SKrishna.Elango@Sun.COM for (row = tbl; err_reg && (row->bit != NULL) && !(err & PF_ERR_PANIC); 1278*10187SKrishna.Elango@Sun.COM row++) { 1279*10187SKrishna.Elango@Sun.COM if (err_reg & row->bit) 1280*10187SKrishna.Elango@Sun.COM err |= row->handler(derr, row->bit, impl->pf_dq_head_p, 1281*10187SKrishna.Elango@Sun.COM pfd_p); 1282*10187SKrishna.Elango@Sun.COM } 1283*10187SKrishna.Elango@Sun.COM 1284*10187SKrishna.Elango@Sun.COM if (!err) 1285*10187SKrishna.Elango@Sun.COM err = PF_ERR_NO_ERROR; 1286*10187SKrishna.Elango@Sun.COM 1287*10187SKrishna.Elango@Sun.COM return (err); 1288*10187SKrishna.Elango@Sun.COM } 1289*10187SKrishna.Elango@Sun.COM 1290*10187SKrishna.Elango@Sun.COM /* 1291*10187SKrishna.Elango@Sun.COM * PCIe Completer Abort and Unsupport Request error analyser. If a PCIe device 1292*10187SKrishna.Elango@Sun.COM * issues a CA/UR a corresponding Received CA/UR should have been seen in the 1293*10187SKrishna.Elango@Sun.COM * PCIe root complex. Check to see if RC did indeed receive a CA/UR, if so then 1294*10187SKrishna.Elango@Sun.COM * this error may be safely ignored. If not check the logs and see if an 1295*10187SKrishna.Elango@Sun.COM * associated handler for this transaction can be found. 1296*10187SKrishna.Elango@Sun.COM */ 1297*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1298*10187SKrishna.Elango@Sun.COM static int 1299*10187SKrishna.Elango@Sun.COM pf_analyse_ca_ur(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1300*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1301*10187SKrishna.Elango@Sun.COM { 1302*10187SKrishna.Elango@Sun.COM uint32_t abort_type; 1303*10187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip; 1304*10187SKrishna.Elango@Sun.COM 1305*10187SKrishna.Elango@Sun.COM /* If UR's are masked forgive this error */ 1306*10187SKrishna.Elango@Sun.COM if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) && 1307*10187SKrishna.Elango@Sun.COM (bit == PCIE_AER_UCE_UR)) 1308*10187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC); 1309*10187SKrishna.Elango@Sun.COM 1310*10187SKrishna.Elango@Sun.COM /* 1311*10187SKrishna.Elango@Sun.COM * If a RP has an CA/UR it means a leaf sent a bad request to the RP 1312*10187SKrishna.Elango@Sun.COM * such as a config read or a bad DMA address. 1313*10187SKrishna.Elango@Sun.COM */ 1314*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(PCIE_PFD2BUS(pfd_p))) 1315*10187SKrishna.Elango@Sun.COM goto handle_lookup; 1316*10187SKrishna.Elango@Sun.COM 1317*10187SKrishna.Elango@Sun.COM if (bit == PCIE_AER_UCE_UR) 1318*10187SKrishna.Elango@Sun.COM abort_type = PCI_STAT_R_MAST_AB; 1319*10187SKrishna.Elango@Sun.COM else 1320*10187SKrishna.Elango@Sun.COM abort_type = PCI_STAT_R_TARG_AB; 1321*10187SKrishna.Elango@Sun.COM 1322*10187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, abort_type)) 1323*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_RC); 1324*10187SKrishna.Elango@Sun.COM 1325*10187SKrishna.Elango@Sun.COM handle_lookup: 1326*10187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, bit) && 1327*10187SKrishna.Elango@Sun.COM pf_log_hdl_lookup(rpdip, derr, pfd_p, B_TRUE) == PF_HDL_FOUND) 1328*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE); 1329*10187SKrishna.Elango@Sun.COM 1330*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1331*10187SKrishna.Elango@Sun.COM } 1332*10187SKrishna.Elango@Sun.COM 1333*10187SKrishna.Elango@Sun.COM /* 1334*10187SKrishna.Elango@Sun.COM * PCIe-PCI Bridge Received Master Abort and Target error analyser. If a PCIe 1335*10187SKrishna.Elango@Sun.COM * Bridge receives a MA/TA a corresponding sent CA/UR should have been seen in 1336*10187SKrishna.Elango@Sun.COM * the PCIe root complex. Check to see if RC did indeed receive a CA/UR, if so 1337*10187SKrishna.Elango@Sun.COM * then this error may be safely ignored. If not check the logs and see if an 1338*10187SKrishna.Elango@Sun.COM * associated handler for this transaction can be found. 1339*10187SKrishna.Elango@Sun.COM */ 1340*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1341*10187SKrishna.Elango@Sun.COM static int 1342*10187SKrishna.Elango@Sun.COM pf_analyse_ma_ta(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1343*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1344*10187SKrishna.Elango@Sun.COM { 1345*10187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip; 1346*10187SKrishna.Elango@Sun.COM uint32_t abort_type; 1347*10187SKrishna.Elango@Sun.COM 1348*10187SKrishna.Elango@Sun.COM /* If UR's are masked forgive this error */ 1349*10187SKrishna.Elango@Sun.COM if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) && 1350*10187SKrishna.Elango@Sun.COM (bit == PCIE_AER_SUCE_RCVD_MA)) 1351*10187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC); 1352*10187SKrishna.Elango@Sun.COM 1353*10187SKrishna.Elango@Sun.COM if (bit == PCIE_AER_SUCE_RCVD_MA) 1354*10187SKrishna.Elango@Sun.COM abort_type = PCI_STAT_R_MAST_AB; 1355*10187SKrishna.Elango@Sun.COM else 1356*10187SKrishna.Elango@Sun.COM abort_type = PCI_STAT_R_TARG_AB; 1357*10187SKrishna.Elango@Sun.COM 1358*10187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, abort_type)) 1359*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_RC); 1360*10187SKrishna.Elango@Sun.COM 1361*10187SKrishna.Elango@Sun.COM if (!HAS_SAER_LOGS(pfd_p, bit)) 1362*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1363*10187SKrishna.Elango@Sun.COM 1364*10187SKrishna.Elango@Sun.COM if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE) == PF_HDL_FOUND) 1365*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE); 1366*10187SKrishna.Elango@Sun.COM 1367*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1368*10187SKrishna.Elango@Sun.COM } 1369*10187SKrishna.Elango@Sun.COM 1370*10187SKrishna.Elango@Sun.COM /* 1371*10187SKrishna.Elango@Sun.COM * Generic PCI error analyser. This function is used for Parity Errors, 1372*10187SKrishna.Elango@Sun.COM * Received Master Aborts, Received Target Aborts, and Signaled Target Aborts. 1373*10187SKrishna.Elango@Sun.COM * In general PCI devices do not have error logs, it is very difficult to figure 1374*10187SKrishna.Elango@Sun.COM * out what transaction caused the error. Instead find the nearest PCIe-PCI 1375*10187SKrishna.Elango@Sun.COM * Bridge and check to see if it has logs and if it has an error associated with 1376*10187SKrishna.Elango@Sun.COM * this PCI Device. 1377*10187SKrishna.Elango@Sun.COM */ 1378*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1379*10187SKrishna.Elango@Sun.COM static int 1380*10187SKrishna.Elango@Sun.COM pf_analyse_pci(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1381*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1382*10187SKrishna.Elango@Sun.COM { 1383*10187SKrishna.Elango@Sun.COM pf_data_t *parent_pfd_p; 1384*10187SKrishna.Elango@Sun.COM uint16_t cmd; 1385*10187SKrishna.Elango@Sun.COM uint32_t aer_ue_status; 1386*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_PFD2BUS(pfd_p); 1387*10187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *parent_saer_p; 1388*10187SKrishna.Elango@Sun.COM 1389*10187SKrishna.Elango@Sun.COM if (PCI_ERR_REG(pfd_p)->pci_err_status & PCI_STAT_S_SYSERR) 1390*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1391*10187SKrishna.Elango@Sun.COM 1392*10187SKrishna.Elango@Sun.COM /* If UR's are masked forgive this error */ 1393*10187SKrishna.Elango@Sun.COM if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) && 1394*10187SKrishna.Elango@Sun.COM (bit == PCI_STAT_R_MAST_AB)) 1395*10187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC); 1396*10187SKrishna.Elango@Sun.COM 1397*10187SKrishna.Elango@Sun.COM 1398*10187SKrishna.Elango@Sun.COM if (bit & (PCI_STAT_PERROR | PCI_STAT_S_PERROR)) { 1399*10187SKrishna.Elango@Sun.COM aer_ue_status = PCIE_AER_SUCE_PERR_ASSERT; 1400*10187SKrishna.Elango@Sun.COM } else { 1401*10187SKrishna.Elango@Sun.COM aer_ue_status = (PCIE_AER_SUCE_TA_ON_SC | 1402*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MA_ON_SC | PCIE_AER_SUCE_RCVD_TA | 1403*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_RCVD_MA); 1404*10187SKrishna.Elango@Sun.COM } 1405*10187SKrishna.Elango@Sun.COM 1406*10187SKrishna.Elango@Sun.COM parent_pfd_p = pf_get_parent_pcie_bridge(pfd_p); 1407*10187SKrishna.Elango@Sun.COM if (parent_pfd_p == NULL) 1408*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1409*10187SKrishna.Elango@Sun.COM 1410*10187SKrishna.Elango@Sun.COM /* Check if parent bridge has seen this error */ 1411*10187SKrishna.Elango@Sun.COM parent_saer_p = PCIE_ADV_BDG_REG(parent_pfd_p); 1412*10187SKrishna.Elango@Sun.COM if (!(parent_saer_p->pcie_sue_status & aer_ue_status) || 1413*10187SKrishna.Elango@Sun.COM !HAS_SAER_LOGS(parent_pfd_p, aer_ue_status)) 1414*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1415*10187SKrishna.Elango@Sun.COM 1416*10187SKrishna.Elango@Sun.COM /* 1417*10187SKrishna.Elango@Sun.COM * If the addr or bdf from the parent PCIe bridge logs belong to this 1418*10187SKrishna.Elango@Sun.COM * PCI device, assume the PCIe bridge's error handling has already taken 1419*10187SKrishna.Elango@Sun.COM * care of this PCI device's error. 1420*10187SKrishna.Elango@Sun.COM */ 1421*10187SKrishna.Elango@Sun.COM if (pf_pci_decode(parent_pfd_p, &cmd) != DDI_SUCCESS) 1422*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1423*10187SKrishna.Elango@Sun.COM 1424*10187SKrishna.Elango@Sun.COM if ((parent_saer_p->pcie_sue_tgt_bdf == bus_p->bus_bdf) || 1425*10187SKrishna.Elango@Sun.COM pf_in_addr_range(bus_p, parent_saer_p->pcie_sue_tgt_addr)) 1426*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_PARENT); 1427*10187SKrishna.Elango@Sun.COM 1428*10187SKrishna.Elango@Sun.COM /* 1429*10187SKrishna.Elango@Sun.COM * If this device is a PCI-PCI bridge, check if the bdf in the parent 1430*10187SKrishna.Elango@Sun.COM * PCIe bridge logs is in the range of this PCI-PCI Bridge's bus ranges. 1431*10187SKrishna.Elango@Sun.COM * If they are, then assume the PCIe bridge's error handling has already 1432*10187SKrishna.Elango@Sun.COM * taken care of this PCI-PCI bridge device's error. 1433*10187SKrishna.Elango@Sun.COM */ 1434*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p) && 1435*10187SKrishna.Elango@Sun.COM pf_in_bus_range(bus_p, parent_saer_p->pcie_sue_tgt_bdf)) 1436*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_PARENT); 1437*10187SKrishna.Elango@Sun.COM 1438*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1439*10187SKrishna.Elango@Sun.COM } 1440*10187SKrishna.Elango@Sun.COM 1441*10187SKrishna.Elango@Sun.COM /* 1442*10187SKrishna.Elango@Sun.COM * PCIe Bridge transactions associated with PERR. 1443*10187SKrishna.Elango@Sun.COM * o Bridge received a poisoned Non-Posted Write (CFG Writes) from PCIe 1444*10187SKrishna.Elango@Sun.COM * o Bridge received a poisoned Posted Write from (MEM Writes) from PCIe 1445*10187SKrishna.Elango@Sun.COM * o Bridge received a poisoned Completion on a Split Transction from PCIe 1446*10187SKrishna.Elango@Sun.COM * o Bridge received a poisoned Completion on a Delayed Transction from PCIe 1447*10187SKrishna.Elango@Sun.COM * 1448*10187SKrishna.Elango@Sun.COM * Check for non-poisoned PCIe transactions that got forwarded to the secondary 1449*10187SKrishna.Elango@Sun.COM * side and detects a PERR#. Except for delayed read completions, a poisoned 1450*10187SKrishna.Elango@Sun.COM * TLP will be forwarded to the secondary bus and PERR# will be asserted. 1451*10187SKrishna.Elango@Sun.COM */ 1452*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1453*10187SKrishna.Elango@Sun.COM static int 1454*10187SKrishna.Elango@Sun.COM pf_analyse_perr_assert(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1455*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1456*10187SKrishna.Elango@Sun.COM { 1457*10187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip; 1458*10187SKrishna.Elango@Sun.COM uint16_t cmd; 1459*10187SKrishna.Elango@Sun.COM int hdl_sts = PF_HDL_NOTFOUND; 1460*10187SKrishna.Elango@Sun.COM int err = PF_ERR_NO_ERROR; 1461*10187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *saer_p; 1462*10187SKrishna.Elango@Sun.COM 1463*10187SKrishna.Elango@Sun.COM 1464*10187SKrishna.Elango@Sun.COM if (HAS_SAER_LOGS(pfd_p, bit)) { 1465*10187SKrishna.Elango@Sun.COM saer_p = PCIE_ADV_BDG_REG(pfd_p); 1466*10187SKrishna.Elango@Sun.COM if (pf_pci_decode(pfd_p, &cmd) != DDI_SUCCESS) 1467*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1468*10187SKrishna.Elango@Sun.COM 1469*10187SKrishna.Elango@Sun.COM cmd_switch: 1470*10187SKrishna.Elango@Sun.COM switch (cmd) { 1471*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_IOWR: 1472*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWR: 1473*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWR_BL: 1474*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWRBL: 1475*10187SKrishna.Elango@Sun.COM /* Posted Writes Transactions */ 1476*10187SKrishna.Elango@Sun.COM if (saer_p->pcie_sue_tgt_trans == PF_ADDR_PIO) 1477*10187SKrishna.Elango@Sun.COM hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p, 1478*10187SKrishna.Elango@Sun.COM B_FALSE); 1479*10187SKrishna.Elango@Sun.COM break; 1480*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_CFWR: 1481*10187SKrishna.Elango@Sun.COM /* 1482*10187SKrishna.Elango@Sun.COM * Check to see if it is a non-posted write. If so, a 1483*10187SKrishna.Elango@Sun.COM * UR Completion would have been sent. 1484*10187SKrishna.Elango@Sun.COM */ 1485*10187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, 1486*10187SKrishna.Elango@Sun.COM PCI_STAT_R_MAST_AB)) { 1487*10187SKrishna.Elango@Sun.COM hdl_sts = PF_HDL_FOUND; 1488*10187SKrishna.Elango@Sun.COM err = PF_ERR_MATCHED_RC; 1489*10187SKrishna.Elango@Sun.COM goto done; 1490*10187SKrishna.Elango@Sun.COM } 1491*10187SKrishna.Elango@Sun.COM hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p, 1492*10187SKrishna.Elango@Sun.COM B_FALSE); 1493*10187SKrishna.Elango@Sun.COM break; 1494*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_SPL: 1495*10187SKrishna.Elango@Sun.COM hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p, 1496*10187SKrishna.Elango@Sun.COM B_FALSE); 1497*10187SKrishna.Elango@Sun.COM break; 1498*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_DADR: 1499*10187SKrishna.Elango@Sun.COM cmd = (PCIE_ADV_BDG_HDR(pfd_p, 1) >> 1500*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) & 1501*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_UP_MASK; 1502*10187SKrishna.Elango@Sun.COM if (cmd != PCI_PCIX_CMD_DADR) 1503*10187SKrishna.Elango@Sun.COM goto cmd_switch; 1504*10187SKrishna.Elango@Sun.COM /* FALLTHROUGH */ 1505*10187SKrishna.Elango@Sun.COM default: 1506*10187SKrishna.Elango@Sun.COM /* Unexpected situation, panic */ 1507*10187SKrishna.Elango@Sun.COM hdl_sts = PF_HDL_NOTFOUND; 1508*10187SKrishna.Elango@Sun.COM } 1509*10187SKrishna.Elango@Sun.COM 1510*10187SKrishna.Elango@Sun.COM if (hdl_sts == PF_HDL_FOUND) 1511*10187SKrishna.Elango@Sun.COM err = PF_ERR_MATCHED_DEVICE; 1512*10187SKrishna.Elango@Sun.COM else 1513*10187SKrishna.Elango@Sun.COM err = PF_ERR_PANIC; 1514*10187SKrishna.Elango@Sun.COM } else { 1515*10187SKrishna.Elango@Sun.COM /* 1516*10187SKrishna.Elango@Sun.COM * Check to see if it is a non-posted write. If so, a UR 1517*10187SKrishna.Elango@Sun.COM * Completion would have been sent. 1518*10187SKrishna.Elango@Sun.COM */ 1519*10187SKrishna.Elango@Sun.COM if ((PCIE_ERR_REG(pfd_p)->pcie_err_status & 1520*10187SKrishna.Elango@Sun.COM PCIE_DEVSTS_UR_DETECTED) && 1521*10187SKrishna.Elango@Sun.COM pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_R_MAST_AB)) 1522*10187SKrishna.Elango@Sun.COM err = PF_ERR_MATCHED_RC; 1523*10187SKrishna.Elango@Sun.COM 1524*10187SKrishna.Elango@Sun.COM /* Check for posted writes. Transaction is lost. */ 1525*10187SKrishna.Elango@Sun.COM if (PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & 1526*10187SKrishna.Elango@Sun.COM PCI_STAT_S_PERROR) 1527*10187SKrishna.Elango@Sun.COM err = PF_ERR_PANIC; 1528*10187SKrishna.Elango@Sun.COM 1529*10187SKrishna.Elango@Sun.COM /* 1530*10187SKrishna.Elango@Sun.COM * All other scenarios are due to read completions. Check for 1531*10187SKrishna.Elango@Sun.COM * PERR on the primary side. If found the primary side error 1532*10187SKrishna.Elango@Sun.COM * handling will take care of this error. 1533*10187SKrishna.Elango@Sun.COM */ 1534*10187SKrishna.Elango@Sun.COM if (err == PF_ERR_NO_ERROR) { 1535*10187SKrishna.Elango@Sun.COM if (PCI_ERR_REG(pfd_p)->pci_err_status & 1536*10187SKrishna.Elango@Sun.COM PCI_STAT_PERROR) 1537*10187SKrishna.Elango@Sun.COM err = PF_ERR_MATCHED_PARENT; 1538*10187SKrishna.Elango@Sun.COM else 1539*10187SKrishna.Elango@Sun.COM err = PF_ERR_PANIC; 1540*10187SKrishna.Elango@Sun.COM } 1541*10187SKrishna.Elango@Sun.COM } 1542*10187SKrishna.Elango@Sun.COM 1543*10187SKrishna.Elango@Sun.COM done: 1544*10187SKrishna.Elango@Sun.COM return (err); 1545*10187SKrishna.Elango@Sun.COM } 1546*10187SKrishna.Elango@Sun.COM 1547*10187SKrishna.Elango@Sun.COM /* 1548*10187SKrishna.Elango@Sun.COM * PCIe Poisoned TLP error analyser. If a PCIe device receives a Poisoned TLP, 1549*10187SKrishna.Elango@Sun.COM * check the logs and see if an associated handler for this transaction can be 1550*10187SKrishna.Elango@Sun.COM * found. 1551*10187SKrishna.Elango@Sun.COM */ 1552*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1553*10187SKrishna.Elango@Sun.COM static int 1554*10187SKrishna.Elango@Sun.COM pf_analyse_ptlp(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1555*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1556*10187SKrishna.Elango@Sun.COM { 1557*10187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip; 1558*10187SKrishna.Elango@Sun.COM 1559*10187SKrishna.Elango@Sun.COM /* 1560*10187SKrishna.Elango@Sun.COM * If AERs are supported find the logs in this device, otherwise look in 1561*10187SKrishna.Elango@Sun.COM * it's parent's logs. 1562*10187SKrishna.Elango@Sun.COM */ 1563*10187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, bit)) { 1564*10187SKrishna.Elango@Sun.COM pcie_tlp_hdr_t *hdr = (pcie_tlp_hdr_t *)&PCIE_ADV_HDR(pfd_p, 0); 1565*10187SKrishna.Elango@Sun.COM 1566*10187SKrishna.Elango@Sun.COM /* 1567*10187SKrishna.Elango@Sun.COM * Double check that the log contains a poisoned TLP. 1568*10187SKrishna.Elango@Sun.COM * Some devices like PLX switch do not log poison TLP headers. 1569*10187SKrishna.Elango@Sun.COM */ 1570*10187SKrishna.Elango@Sun.COM if (hdr->ep) { 1571*10187SKrishna.Elango@Sun.COM if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_TRUE) == 1572*10187SKrishna.Elango@Sun.COM PF_HDL_FOUND) 1573*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE); 1574*10187SKrishna.Elango@Sun.COM } 1575*10187SKrishna.Elango@Sun.COM 1576*10187SKrishna.Elango@Sun.COM /* 1577*10187SKrishna.Elango@Sun.COM * If an address is found and hdl lookup failed panic. 1578*10187SKrishna.Elango@Sun.COM * Otherwise check parents to see if there was enough 1579*10187SKrishna.Elango@Sun.COM * information recover. 1580*10187SKrishna.Elango@Sun.COM */ 1581*10187SKrishna.Elango@Sun.COM if (PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr) 1582*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1583*10187SKrishna.Elango@Sun.COM } 1584*10187SKrishna.Elango@Sun.COM 1585*10187SKrishna.Elango@Sun.COM /* 1586*10187SKrishna.Elango@Sun.COM * Check to see if the rc has already handled this error or a parent has 1587*10187SKrishna.Elango@Sun.COM * already handled this error. 1588*10187SKrishna.Elango@Sun.COM * 1589*10187SKrishna.Elango@Sun.COM * If the error info in the RC wasn't enough to find the fault device, 1590*10187SKrishna.Elango@Sun.COM * such as if the faulting device lies behind a PCIe-PCI bridge from a 1591*10187SKrishna.Elango@Sun.COM * poisoned completion, check to see if the PCIe-PCI bridge has enough 1592*10187SKrishna.Elango@Sun.COM * info to recover. For completion TLP's, the AER header logs only 1593*10187SKrishna.Elango@Sun.COM * contain the faulting BDF in the Root Port. For PCIe device the fault 1594*10187SKrishna.Elango@Sun.COM * BDF is the fault device. But if the fault device is behind a 1595*10187SKrishna.Elango@Sun.COM * PCIe-PCI bridge the fault BDF could turn out just to be a PCIe-PCI 1596*10187SKrishna.Elango@Sun.COM * bridge's secondary bus number. 1597*10187SKrishna.Elango@Sun.COM */ 1598*10187SKrishna.Elango@Sun.COM if (!PFD_IS_ROOT(pfd_p)) { 1599*10187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(PCIE_PFD2DIP(pfd_p)); 1600*10187SKrishna.Elango@Sun.COM pf_data_t *parent_pfd_p; 1601*10187SKrishna.Elango@Sun.COM 1602*10187SKrishna.Elango@Sun.COM if (PCIE_PFD2BUS(pfd_p)->bus_rp_dip == pdip) { 1603*10187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_PERROR)) 1604*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_RC); 1605*10187SKrishna.Elango@Sun.COM } 1606*10187SKrishna.Elango@Sun.COM 1607*10187SKrishna.Elango@Sun.COM parent_pfd_p = PCIE_DIP2PFD(pdip); 1608*10187SKrishna.Elango@Sun.COM 1609*10187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(parent_pfd_p, bit)) 1610*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_PARENT); 1611*10187SKrishna.Elango@Sun.COM } else { 1612*10187SKrishna.Elango@Sun.COM pf_data_t *bdg_pfd_p; 1613*10187SKrishna.Elango@Sun.COM pcie_req_id_t secbus; 1614*10187SKrishna.Elango@Sun.COM 1615*10187SKrishna.Elango@Sun.COM /* 1616*10187SKrishna.Elango@Sun.COM * Looking for a pcie bridge only makes sense if the BDF 1617*10187SKrishna.Elango@Sun.COM * Dev/Func = 0/0 1618*10187SKrishna.Elango@Sun.COM */ 1619*10187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p))) 1620*10187SKrishna.Elango@Sun.COM goto done; 1621*10187SKrishna.Elango@Sun.COM 1622*10187SKrishna.Elango@Sun.COM secbus = PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf; 1623*10187SKrishna.Elango@Sun.COM 1624*10187SKrishna.Elango@Sun.COM if (!PCIE_CHECK_VALID_BDF(secbus) || (secbus & 0xFF)) 1625*10187SKrishna.Elango@Sun.COM goto done; 1626*10187SKrishna.Elango@Sun.COM 1627*10187SKrishna.Elango@Sun.COM bdg_pfd_p = pf_get_pcie_bridge(pfd_p, secbus); 1628*10187SKrishna.Elango@Sun.COM 1629*10187SKrishna.Elango@Sun.COM if (bdg_pfd_p && HAS_SAER_LOGS(bdg_pfd_p, 1630*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_PERR_ASSERT)) { 1631*10187SKrishna.Elango@Sun.COM return pf_analyse_perr_assert(derr, 1632*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_PERR_ASSERT, dq_head_p, pfd_p); 1633*10187SKrishna.Elango@Sun.COM } 1634*10187SKrishna.Elango@Sun.COM } 1635*10187SKrishna.Elango@Sun.COM done: 1636*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1637*10187SKrishna.Elango@Sun.COM } 1638*10187SKrishna.Elango@Sun.COM 1639*10187SKrishna.Elango@Sun.COM /* 1640*10187SKrishna.Elango@Sun.COM * PCIe-PCI Bridge Received Master and Target abort error analyser on Split 1641*10187SKrishna.Elango@Sun.COM * Completions. If a PCIe Bridge receives a MA/TA check logs and see if an 1642*10187SKrishna.Elango@Sun.COM * associated handler for this transaction can be found. 1643*10187SKrishna.Elango@Sun.COM */ 1644*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1645*10187SKrishna.Elango@Sun.COM static int 1646*10187SKrishna.Elango@Sun.COM pf_analyse_sc(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1647*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1648*10187SKrishna.Elango@Sun.COM { 1649*10187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip; 1650*10187SKrishna.Elango@Sun.COM uint16_t cmd; 1651*10187SKrishna.Elango@Sun.COM int sts = PF_HDL_NOTFOUND; 1652*10187SKrishna.Elango@Sun.COM 1653*10187SKrishna.Elango@Sun.COM if (!HAS_SAER_LOGS(pfd_p, bit)) 1654*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1655*10187SKrishna.Elango@Sun.COM 1656*10187SKrishna.Elango@Sun.COM if (pf_pci_decode(pfd_p, &cmd) != DDI_SUCCESS) 1657*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1658*10187SKrishna.Elango@Sun.COM 1659*10187SKrishna.Elango@Sun.COM if (cmd == PCI_PCIX_CMD_SPL) 1660*10187SKrishna.Elango@Sun.COM sts = pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE); 1661*10187SKrishna.Elango@Sun.COM 1662*10187SKrishna.Elango@Sun.COM if (sts == PF_HDL_FOUND) 1663*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE); 1664*10187SKrishna.Elango@Sun.COM 1665*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1666*10187SKrishna.Elango@Sun.COM } 1667*10187SKrishna.Elango@Sun.COM 1668*10187SKrishna.Elango@Sun.COM /* 1669*10187SKrishna.Elango@Sun.COM * PCIe Timeout error analyser. This error can be forgiven if it is marked as 1670*10187SKrishna.Elango@Sun.COM * CE Advisory. If it is marked as advisory, this means the HW can recover 1671*10187SKrishna.Elango@Sun.COM * and/or retry the transaction automatically. 1672*10187SKrishna.Elango@Sun.COM */ 1673*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1674*10187SKrishna.Elango@Sun.COM static int 1675*10187SKrishna.Elango@Sun.COM pf_analyse_to(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1676*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1677*10187SKrishna.Elango@Sun.COM { 1678*10187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, bit) && CE_ADVISORY(pfd_p)) 1679*10187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC); 1680*10187SKrishna.Elango@Sun.COM 1681*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1682*10187SKrishna.Elango@Sun.COM } 1683*10187SKrishna.Elango@Sun.COM 1684*10187SKrishna.Elango@Sun.COM /* 1685*10187SKrishna.Elango@Sun.COM * PCIe Unexpected Completion. Check to see if this TLP was misrouted by 1686*10187SKrishna.Elango@Sun.COM * matching the device BDF with the TLP Log. If misrouting panic, otherwise 1687*10187SKrishna.Elango@Sun.COM * don't panic. 1688*10187SKrishna.Elango@Sun.COM */ 1689*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1690*10187SKrishna.Elango@Sun.COM static int 1691*10187SKrishna.Elango@Sun.COM pf_analyse_uc(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1692*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1693*10187SKrishna.Elango@Sun.COM { 1694*10187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, bit) && 1695*10187SKrishna.Elango@Sun.COM (PCIE_PFD2BUS(pfd_p)->bus_bdf == (PCIE_ADV_HDR(pfd_p, 2) >> 16))) 1696*10187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC); 1697*10187SKrishna.Elango@Sun.COM 1698*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1699*10187SKrishna.Elango@Sun.COM } 1700*10187SKrishna.Elango@Sun.COM 1701*10187SKrishna.Elango@Sun.COM /* 1702*10187SKrishna.Elango@Sun.COM * PCIe-PCI Bridge Uncorrectable Data error analyser. All Uncorrectable Data 1703*10187SKrishna.Elango@Sun.COM * errors should have resulted in a PCIe Poisoned TLP to the RC, except for 1704*10187SKrishna.Elango@Sun.COM * Posted Writes. Check the logs for Posted Writes and if the RC did not see a 1705*10187SKrishna.Elango@Sun.COM * Poisoned TLP. 1706*10187SKrishna.Elango@Sun.COM * 1707*10187SKrishna.Elango@Sun.COM * Non-Posted Writes will also generate a UR in the completion status, which the 1708*10187SKrishna.Elango@Sun.COM * RC should also see. 1709*10187SKrishna.Elango@Sun.COM */ 1710*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1711*10187SKrishna.Elango@Sun.COM static int 1712*10187SKrishna.Elango@Sun.COM pf_analyse_uc_data(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1713*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1714*10187SKrishna.Elango@Sun.COM { 1715*10187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip; 1716*10187SKrishna.Elango@Sun.COM 1717*10187SKrishna.Elango@Sun.COM if (!HAS_SAER_LOGS(pfd_p, bit)) 1718*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1719*10187SKrishna.Elango@Sun.COM 1720*10187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_PERROR)) 1721*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_RC); 1722*10187SKrishna.Elango@Sun.COM 1723*10187SKrishna.Elango@Sun.COM if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE) == PF_HDL_FOUND) 1724*10187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE); 1725*10187SKrishna.Elango@Sun.COM 1726*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1727*10187SKrishna.Elango@Sun.COM } 1728*10187SKrishna.Elango@Sun.COM 1729*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1730*10187SKrishna.Elango@Sun.COM static int 1731*10187SKrishna.Elango@Sun.COM pf_no_panic(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1732*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1733*10187SKrishna.Elango@Sun.COM { 1734*10187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC); 1735*10187SKrishna.Elango@Sun.COM } 1736*10187SKrishna.Elango@Sun.COM 1737*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1738*10187SKrishna.Elango@Sun.COM static int 1739*10187SKrishna.Elango@Sun.COM pf_panic(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p, 1740*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p) 1741*10187SKrishna.Elango@Sun.COM { 1742*10187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC); 1743*10187SKrishna.Elango@Sun.COM } 1744*10187SKrishna.Elango@Sun.COM 1745*10187SKrishna.Elango@Sun.COM /* 1746*10187SKrishna.Elango@Sun.COM * If a PCIe device does not support AER, assume all AER statuses have been set, 1747*10187SKrishna.Elango@Sun.COM * unless other registers do not indicate a certain error occuring. 1748*10187SKrishna.Elango@Sun.COM */ 1749*10187SKrishna.Elango@Sun.COM static void 1750*10187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pf_data_t *pfd_p) 1751*10187SKrishna.Elango@Sun.COM { 1752*10187SKrishna.Elango@Sun.COM uint32_t aer_ue = 0; 1753*10187SKrishna.Elango@Sun.COM uint16_t status; 1754*10187SKrishna.Elango@Sun.COM 1755*10187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p))) 1756*10187SKrishna.Elango@Sun.COM return; 1757*10187SKrishna.Elango@Sun.COM 1758*10187SKrishna.Elango@Sun.COM if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_FE_DETECTED) 1759*10187SKrishna.Elango@Sun.COM aer_ue = PF_AER_FATAL_ERR; 1760*10187SKrishna.Elango@Sun.COM 1761*10187SKrishna.Elango@Sun.COM if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_NFE_DETECTED) { 1762*10187SKrishna.Elango@Sun.COM aer_ue = PF_AER_NON_FATAL_ERR; 1763*10187SKrishna.Elango@Sun.COM status = PCI_ERR_REG(pfd_p)->pci_err_status; 1764*10187SKrishna.Elango@Sun.COM 1765*10187SKrishna.Elango@Sun.COM /* Check if the device received a PTLP */ 1766*10187SKrishna.Elango@Sun.COM if (!(status & PCI_STAT_PERROR)) 1767*10187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_PTLP; 1768*10187SKrishna.Elango@Sun.COM 1769*10187SKrishna.Elango@Sun.COM /* Check if the device signaled a CA */ 1770*10187SKrishna.Elango@Sun.COM if (!(status & PCI_STAT_S_TARG_AB)) 1771*10187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_CA; 1772*10187SKrishna.Elango@Sun.COM 1773*10187SKrishna.Elango@Sun.COM /* Check if the device sent a UR */ 1774*10187SKrishna.Elango@Sun.COM if (!(PCIE_ERR_REG(pfd_p)->pcie_err_status & 1775*10187SKrishna.Elango@Sun.COM PCIE_DEVSTS_UR_DETECTED)) 1776*10187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_UR; 1777*10187SKrishna.Elango@Sun.COM 1778*10187SKrishna.Elango@Sun.COM /* 1779*10187SKrishna.Elango@Sun.COM * Ignore ECRCs as it is optional and will manefest itself as 1780*10187SKrishna.Elango@Sun.COM * another error like PTLP and MFP 1781*10187SKrishna.Elango@Sun.COM */ 1782*10187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_ECRC; 1783*10187SKrishna.Elango@Sun.COM 1784*10187SKrishna.Elango@Sun.COM /* 1785*10187SKrishna.Elango@Sun.COM * Generally if NFE is set, SERR should also be set. Exception: 1786*10187SKrishna.Elango@Sun.COM * When certain non-fatal errors are masked, and some of them 1787*10187SKrishna.Elango@Sun.COM * happened to be the cause of the NFE, SERR will not be set and 1788*10187SKrishna.Elango@Sun.COM * they can not be the source of this interrupt. 1789*10187SKrishna.Elango@Sun.COM * 1790*10187SKrishna.Elango@Sun.COM * On x86, URs are masked (NFE + UR can be set), if any other 1791*10187SKrishna.Elango@Sun.COM * non-fatal errors (i.e, PTLP, CTO, CA, UC, ECRC, ACS) did 1792*10187SKrishna.Elango@Sun.COM * occur, SERR should be set since they are not masked. So if 1793*10187SKrishna.Elango@Sun.COM * SERR is not set, none of them occurred. 1794*10187SKrishna.Elango@Sun.COM */ 1795*10187SKrishna.Elango@Sun.COM if (!(status & PCI_STAT_S_SYSERR)) 1796*10187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_TO; 1797*10187SKrishna.Elango@Sun.COM } 1798*10187SKrishna.Elango@Sun.COM 1799*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_BDG(PCIE_PFD2BUS(pfd_p))) { 1800*10187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_TRAINING; 1801*10187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_SD; 1802*10187SKrishna.Elango@Sun.COM } 1803*10187SKrishna.Elango@Sun.COM 1804*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_status = aer_ue; 1805*10187SKrishna.Elango@Sun.COM } 1806*10187SKrishna.Elango@Sun.COM 1807*10187SKrishna.Elango@Sun.COM static void 1808*10187SKrishna.Elango@Sun.COM pf_adjust_for_no_saer(pf_data_t *pfd_p) 1809*10187SKrishna.Elango@Sun.COM { 1810*10187SKrishna.Elango@Sun.COM uint32_t s_aer_ue = 0; 1811*10187SKrishna.Elango@Sun.COM uint16_t status; 1812*10187SKrishna.Elango@Sun.COM 1813*10187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p))) 1814*10187SKrishna.Elango@Sun.COM return; 1815*10187SKrishna.Elango@Sun.COM 1816*10187SKrishna.Elango@Sun.COM if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_FE_DETECTED) 1817*10187SKrishna.Elango@Sun.COM s_aer_ue = PF_SAER_FATAL_ERR; 1818*10187SKrishna.Elango@Sun.COM 1819*10187SKrishna.Elango@Sun.COM if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_NFE_DETECTED) { 1820*10187SKrishna.Elango@Sun.COM s_aer_ue = PF_SAER_NON_FATAL_ERR; 1821*10187SKrishna.Elango@Sun.COM status = PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat; 1822*10187SKrishna.Elango@Sun.COM 1823*10187SKrishna.Elango@Sun.COM /* Check if the device received a UC_DATA */ 1824*10187SKrishna.Elango@Sun.COM if (!(status & PCI_STAT_PERROR)) 1825*10187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_UC_DATA_ERR; 1826*10187SKrishna.Elango@Sun.COM 1827*10187SKrishna.Elango@Sun.COM /* Check if the device received a RCVD_MA/MA_ON_SC */ 1828*10187SKrishna.Elango@Sun.COM if (!(status & (PCI_STAT_R_MAST_AB))) { 1829*10187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_RCVD_MA; 1830*10187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_MA_ON_SC; 1831*10187SKrishna.Elango@Sun.COM } 1832*10187SKrishna.Elango@Sun.COM 1833*10187SKrishna.Elango@Sun.COM /* Check if the device received a RCVD_TA/TA_ON_SC */ 1834*10187SKrishna.Elango@Sun.COM if (!(status & (PCI_STAT_R_TARG_AB))) { 1835*10187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_RCVD_TA; 1836*10187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_TA_ON_SC; 1837*10187SKrishna.Elango@Sun.COM } 1838*10187SKrishna.Elango@Sun.COM } 1839*10187SKrishna.Elango@Sun.COM 1840*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status = s_aer_ue; 1841*10187SKrishna.Elango@Sun.COM } 1842*10187SKrishna.Elango@Sun.COM 1843*10187SKrishna.Elango@Sun.COM /* Find the PCIe-PCI bridge based on secondary bus number */ 1844*10187SKrishna.Elango@Sun.COM static pf_data_t * 1845*10187SKrishna.Elango@Sun.COM pf_get_pcie_bridge(pf_data_t *pfd_p, pcie_req_id_t secbus) 1846*10187SKrishna.Elango@Sun.COM { 1847*10187SKrishna.Elango@Sun.COM pf_data_t *bdg_pfd_p; 1848*10187SKrishna.Elango@Sun.COM 1849*10187SKrishna.Elango@Sun.COM /* Search down for the PCIe-PCI device. */ 1850*10187SKrishna.Elango@Sun.COM for (bdg_pfd_p = pfd_p->pe_next; bdg_pfd_p; 1851*10187SKrishna.Elango@Sun.COM bdg_pfd_p = bdg_pfd_p->pe_next) { 1852*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(PCIE_PFD2BUS(bdg_pfd_p)) && 1853*10187SKrishna.Elango@Sun.COM PCIE_PFD2BUS(bdg_pfd_p)->bus_bdg_secbus == secbus) 1854*10187SKrishna.Elango@Sun.COM return (bdg_pfd_p); 1855*10187SKrishna.Elango@Sun.COM } 1856*10187SKrishna.Elango@Sun.COM 1857*10187SKrishna.Elango@Sun.COM return (NULL); 1858*10187SKrishna.Elango@Sun.COM } 1859*10187SKrishna.Elango@Sun.COM 1860*10187SKrishna.Elango@Sun.COM /* Find the PCIe-PCI bridge of a PCI device */ 1861*10187SKrishna.Elango@Sun.COM static pf_data_t * 1862*10187SKrishna.Elango@Sun.COM pf_get_parent_pcie_bridge(pf_data_t *pfd_p) 1863*10187SKrishna.Elango@Sun.COM { 1864*10187SKrishna.Elango@Sun.COM dev_info_t *dip, *rp_dip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip; 1865*10187SKrishna.Elango@Sun.COM 1866*10187SKrishna.Elango@Sun.COM /* This only makes sense if the device is a PCI device */ 1867*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCI(PCIE_PFD2BUS(pfd_p))) 1868*10187SKrishna.Elango@Sun.COM return (NULL); 1869*10187SKrishna.Elango@Sun.COM 1870*10187SKrishna.Elango@Sun.COM /* 1871*10187SKrishna.Elango@Sun.COM * Search up for the PCIe-PCI device. Watchout for x86 where pci 1872*10187SKrishna.Elango@Sun.COM * devices hang directly off of NPE. 1873*10187SKrishna.Elango@Sun.COM */ 1874*10187SKrishna.Elango@Sun.COM for (dip = PCIE_PFD2DIP(pfd_p); dip; dip = ddi_get_parent(dip)) { 1875*10187SKrishna.Elango@Sun.COM if (dip == rp_dip) 1876*10187SKrishna.Elango@Sun.COM dip = NULL; 1877*10187SKrishna.Elango@Sun.COM 1878*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(dip))) 1879*10187SKrishna.Elango@Sun.COM return (PCIE_DIP2PFD(dip)); 1880*10187SKrishna.Elango@Sun.COM } 1881*10187SKrishna.Elango@Sun.COM 1882*10187SKrishna.Elango@Sun.COM return (NULL); 1883*10187SKrishna.Elango@Sun.COM } 1884*10187SKrishna.Elango@Sun.COM 1885*10187SKrishna.Elango@Sun.COM /* 1886*10187SKrishna.Elango@Sun.COM * See if a leaf error was bubbled up to the Root Complex (RC) and handled. 1887*10187SKrishna.Elango@Sun.COM * As of right now only RC's have enough information to have errors found in the 1888*10187SKrishna.Elango@Sun.COM * fabric to be matched to the RC. Note that Root Port's (RP) do not carry 1889*10187SKrishna.Elango@Sun.COM * enough information. Currently known RC's are SPARC Fire architecture and 1890*10187SKrishna.Elango@Sun.COM * it's equivalents, and x86's NPE. 1891*10187SKrishna.Elango@Sun.COM * SPARC Fire architectures have a plethora of error registers, while currently 1892*10187SKrishna.Elango@Sun.COM * NPE only have the address of a failed load. 1893*10187SKrishna.Elango@Sun.COM * 1894*10187SKrishna.Elango@Sun.COM * Check if the RC logged an error with the appropriate status type/abort type. 1895*10187SKrishna.Elango@Sun.COM * Ex: Parity Error, Received Master/Target Abort 1896*10187SKrishna.Elango@Sun.COM * Check if either the fault address found in the rc matches the device's 1897*10187SKrishna.Elango@Sun.COM * assigned address range (PIO's only) or the fault BDF in the rc matches the 1898*10187SKrishna.Elango@Sun.COM * device's BDF or Secondary Bus/Bus Range. 1899*10187SKrishna.Elango@Sun.COM */ 1900*10187SKrishna.Elango@Sun.COM static boolean_t 1901*10187SKrishna.Elango@Sun.COM pf_matched_in_rc(pf_data_t *dq_head_p, pf_data_t *pfd_p, 1902*10187SKrishna.Elango@Sun.COM uint32_t abort_type) 1903*10187SKrishna.Elango@Sun.COM { 1904*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_PFD2BUS(pfd_p); 1905*10187SKrishna.Elango@Sun.COM pf_data_t *rc_pfd_p; 1906*10187SKrishna.Elango@Sun.COM pcie_req_id_t fault_bdf; 1907*10187SKrishna.Elango@Sun.COM 1908*10187SKrishna.Elango@Sun.COM for (rc_pfd_p = dq_head_p; PFD_IS_ROOT(rc_pfd_p); 1909*10187SKrishna.Elango@Sun.COM rc_pfd_p = rc_pfd_p->pe_next) { 1910*10187SKrishna.Elango@Sun.COM /* Only root complex's have enough information to match */ 1911*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_RC(PCIE_PFD2BUS(rc_pfd_p))) 1912*10187SKrishna.Elango@Sun.COM continue; 1913*10187SKrishna.Elango@Sun.COM 1914*10187SKrishna.Elango@Sun.COM /* If device and rc abort type does not match continue */ 1915*10187SKrishna.Elango@Sun.COM if (!(PCI_BDG_ERR_REG(rc_pfd_p)->pci_bdg_sec_stat & abort_type)) 1916*10187SKrishna.Elango@Sun.COM continue; 1917*10187SKrishna.Elango@Sun.COM 1918*10187SKrishna.Elango@Sun.COM fault_bdf = PCIE_ROOT_FAULT(rc_pfd_p)->scan_bdf; 1919*10187SKrishna.Elango@Sun.COM 1920*10187SKrishna.Elango@Sun.COM /* The Fault BDF = Device's BDF */ 1921*10187SKrishna.Elango@Sun.COM if (fault_bdf == bus_p->bus_bdf) 1922*10187SKrishna.Elango@Sun.COM return (B_TRUE); 1923*10187SKrishna.Elango@Sun.COM 1924*10187SKrishna.Elango@Sun.COM /* The Fault Addr is in device's address range */ 1925*10187SKrishna.Elango@Sun.COM if (pf_in_addr_range(bus_p, 1926*10187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(rc_pfd_p)->scan_addr)) 1927*10187SKrishna.Elango@Sun.COM return (B_TRUE); 1928*10187SKrishna.Elango@Sun.COM 1929*10187SKrishna.Elango@Sun.COM /* The Fault BDF is from PCIe-PCI Bridge's secondary bus */ 1930*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && 1931*10187SKrishna.Elango@Sun.COM pf_in_bus_range(bus_p, fault_bdf)) 1932*10187SKrishna.Elango@Sun.COM return (B_TRUE); 1933*10187SKrishna.Elango@Sun.COM } 1934*10187SKrishna.Elango@Sun.COM 1935*10187SKrishna.Elango@Sun.COM return (B_FALSE); 1936*10187SKrishna.Elango@Sun.COM } 1937*10187SKrishna.Elango@Sun.COM 1938*10187SKrishna.Elango@Sun.COM /* 1939*10187SKrishna.Elango@Sun.COM * Check the RP and see if the error is PIO/DMA. If the RP also has a PERR then 1940*10187SKrishna.Elango@Sun.COM * it is a DMA, otherwise it's a PIO 1941*10187SKrishna.Elango@Sun.COM */ 1942*10187SKrishna.Elango@Sun.COM static void 1943*10187SKrishna.Elango@Sun.COM pf_pci_find_trans_type(pf_data_t *pfd_p, uint64_t *addr, uint32_t *trans_type, 1944*10187SKrishna.Elango@Sun.COM pcie_req_id_t *bdf) { 1945*10187SKrishna.Elango@Sun.COM pf_data_t *rc_pfd_p; 1946*10187SKrishna.Elango@Sun.COM 1947*10187SKrishna.Elango@Sun.COM /* Could be DMA or PIO. Find out by look at error type. */ 1948*10187SKrishna.Elango@Sun.COM switch (PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status) { 1949*10187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_TA_ON_SC: 1950*10187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_MA_ON_SC: 1951*10187SKrishna.Elango@Sun.COM *trans_type = PF_ADDR_DMA; 1952*10187SKrishna.Elango@Sun.COM return; 1953*10187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_RCVD_TA: 1954*10187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_RCVD_MA: 1955*10187SKrishna.Elango@Sun.COM *bdf = PCIE_INVALID_BDF; 1956*10187SKrishna.Elango@Sun.COM *trans_type = PF_ADDR_PIO; 1957*10187SKrishna.Elango@Sun.COM return; 1958*10187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_USC_ERR: 1959*10187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_UC_DATA_ERR: 1960*10187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_PERR_ASSERT: 1961*10187SKrishna.Elango@Sun.COM break; 1962*10187SKrishna.Elango@Sun.COM default: 1963*10187SKrishna.Elango@Sun.COM *addr = 0; 1964*10187SKrishna.Elango@Sun.COM *bdf = PCIE_INVALID_BDF; 1965*10187SKrishna.Elango@Sun.COM *trans_type = 0; 1966*10187SKrishna.Elango@Sun.COM return; 1967*10187SKrishna.Elango@Sun.COM } 1968*10187SKrishna.Elango@Sun.COM 1969*10187SKrishna.Elango@Sun.COM *bdf = PCIE_INVALID_BDF; 1970*10187SKrishna.Elango@Sun.COM *trans_type = PF_ADDR_PIO; 1971*10187SKrishna.Elango@Sun.COM for (rc_pfd_p = pfd_p->pe_prev; rc_pfd_p; 1972*10187SKrishna.Elango@Sun.COM rc_pfd_p = rc_pfd_p->pe_prev) { 1973*10187SKrishna.Elango@Sun.COM if (PFD_IS_ROOT(rc_pfd_p) && 1974*10187SKrishna.Elango@Sun.COM (PCI_BDG_ERR_REG(rc_pfd_p)->pci_bdg_sec_stat & 1975*10187SKrishna.Elango@Sun.COM PCI_STAT_PERROR)) { 1976*10187SKrishna.Elango@Sun.COM *trans_type = PF_ADDR_DMA; 1977*10187SKrishna.Elango@Sun.COM return; 1978*10187SKrishna.Elango@Sun.COM } 1979*10187SKrishna.Elango@Sun.COM } 1980*10187SKrishna.Elango@Sun.COM } 1981*10187SKrishna.Elango@Sun.COM 1982*10187SKrishna.Elango@Sun.COM /* 1983*10187SKrishna.Elango@Sun.COM * pf_pci_decode function decodes the secondary aer transaction logs in 1984*10187SKrishna.Elango@Sun.COM * PCIe-PCI bridges. 1985*10187SKrishna.Elango@Sun.COM * 1986*10187SKrishna.Elango@Sun.COM * The log is 128 bits long and arranged in this manner. 1987*10187SKrishna.Elango@Sun.COM * [0:35] Transaction Attribute (s_aer_h0-saer_h1) 1988*10187SKrishna.Elango@Sun.COM * [36:39] Transaction lower command (saer_h1) 1989*10187SKrishna.Elango@Sun.COM * [40:43] Transaction upper command (saer_h1) 1990*10187SKrishna.Elango@Sun.COM * [44:63] Reserved 1991*10187SKrishna.Elango@Sun.COM * [64:127] Address (saer_h2-saer_h3) 1992*10187SKrishna.Elango@Sun.COM */ 1993*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 1994*10187SKrishna.Elango@Sun.COM static int 1995*10187SKrishna.Elango@Sun.COM pf_pci_decode(pf_data_t *pfd_p, uint16_t *cmd) { 1996*10187SKrishna.Elango@Sun.COM pcix_attr_t *attr; 1997*10187SKrishna.Elango@Sun.COM uint64_t addr; 1998*10187SKrishna.Elango@Sun.COM uint32_t trans_type; 1999*10187SKrishna.Elango@Sun.COM pcie_req_id_t bdf = PCIE_INVALID_BDF; 2000*10187SKrishna.Elango@Sun.COM 2001*10187SKrishna.Elango@Sun.COM attr = (pcix_attr_t *)&PCIE_ADV_BDG_HDR(pfd_p, 0); 2002*10187SKrishna.Elango@Sun.COM *cmd = GET_SAER_CMD(pfd_p); 2003*10187SKrishna.Elango@Sun.COM 2004*10187SKrishna.Elango@Sun.COM cmd_switch: 2005*10187SKrishna.Elango@Sun.COM switch (*cmd) { 2006*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_IORD: 2007*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_IOWR: 2008*10187SKrishna.Elango@Sun.COM /* IO Access should always be down stream */ 2009*10187SKrishna.Elango@Sun.COM addr = PCIE_ADV_BDG_HDR(pfd_p, 2); 2010*10187SKrishna.Elango@Sun.COM bdf = attr->rid; 2011*10187SKrishna.Elango@Sun.COM trans_type = PF_ADDR_PIO; 2012*10187SKrishna.Elango@Sun.COM break; 2013*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMRD_DW: 2014*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMRD_BL: 2015*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMRDBL: 2016*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWR: 2017*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWR_BL: 2018*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWRBL: 2019*10187SKrishna.Elango@Sun.COM addr = ((uint64_t)PCIE_ADV_BDG_HDR(pfd_p, 3) << 2020*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_ADDR_SHIFT) | PCIE_ADV_BDG_HDR(pfd_p, 2); 2021*10187SKrishna.Elango@Sun.COM bdf = attr->rid; 2022*10187SKrishna.Elango@Sun.COM 2023*10187SKrishna.Elango@Sun.COM pf_pci_find_trans_type(pfd_p, &addr, &trans_type, &bdf); 2024*10187SKrishna.Elango@Sun.COM break; 2025*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_CFRD: 2026*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_CFWR: 2027*10187SKrishna.Elango@Sun.COM /* 2028*10187SKrishna.Elango@Sun.COM * CFG Access should always be down stream. Match the BDF in 2029*10187SKrishna.Elango@Sun.COM * the address phase. 2030*10187SKrishna.Elango@Sun.COM */ 2031*10187SKrishna.Elango@Sun.COM addr = 0; 2032*10187SKrishna.Elango@Sun.COM bdf = attr->rid; 2033*10187SKrishna.Elango@Sun.COM trans_type = PF_ADDR_CFG; 2034*10187SKrishna.Elango@Sun.COM break; 2035*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_SPL: 2036*10187SKrishna.Elango@Sun.COM /* 2037*10187SKrishna.Elango@Sun.COM * Check for DMA read completions. The requesting BDF is in the 2038*10187SKrishna.Elango@Sun.COM * Address phase. 2039*10187SKrishna.Elango@Sun.COM */ 2040*10187SKrishna.Elango@Sun.COM addr = 0; 2041*10187SKrishna.Elango@Sun.COM bdf = attr->rid; 2042*10187SKrishna.Elango@Sun.COM trans_type = PF_ADDR_DMA; 2043*10187SKrishna.Elango@Sun.COM break; 2044*10187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_DADR: 2045*10187SKrishna.Elango@Sun.COM /* 2046*10187SKrishna.Elango@Sun.COM * For Dual Address Cycles the transaction command is in the 2nd 2047*10187SKrishna.Elango@Sun.COM * address phase. 2048*10187SKrishna.Elango@Sun.COM */ 2049*10187SKrishna.Elango@Sun.COM *cmd = (PCIE_ADV_BDG_HDR(pfd_p, 1) >> 2050*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) & 2051*10187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_UP_MASK; 2052*10187SKrishna.Elango@Sun.COM if (*cmd != PCI_PCIX_CMD_DADR) 2053*10187SKrishna.Elango@Sun.COM goto cmd_switch; 2054*10187SKrishna.Elango@Sun.COM /* FALLTHROUGH */ 2055*10187SKrishna.Elango@Sun.COM default: 2056*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = 0; 2057*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = PCIE_INVALID_BDF; 2058*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = 0; 2059*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 2060*10187SKrishna.Elango@Sun.COM } 2061*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = trans_type; 2062*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = bdf; 2063*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = addr; 2064*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 2065*10187SKrishna.Elango@Sun.COM } 2066*10187SKrishna.Elango@Sun.COM 2067*10187SKrishna.Elango@Sun.COM /* 2068*10187SKrishna.Elango@Sun.COM * Based on either the BDF/ADDR find and mark the faulting DMA/ACC handler. 2069*10187SKrishna.Elango@Sun.COM * Returns either PF_HDL_NOTFOUND or PF_HDL_FOUND. 2070*10187SKrishna.Elango@Sun.COM */ 2071*10187SKrishna.Elango@Sun.COM int 2072*10187SKrishna.Elango@Sun.COM pf_hdl_lookup(dev_info_t *dip, uint64_t ena, uint32_t flag, uint64_t addr, 2073*10187SKrishna.Elango@Sun.COM pcie_req_id_t bdf) 2074*10187SKrishna.Elango@Sun.COM { 2075*10187SKrishna.Elango@Sun.COM ddi_fm_error_t derr; 2076*10187SKrishna.Elango@Sun.COM 2077*10187SKrishna.Elango@Sun.COM /* If we don't know the addr or rid just return with NOTFOUND */ 2078*10187SKrishna.Elango@Sun.COM if ((addr == NULL) && !PCIE_CHECK_VALID_BDF(bdf)) 2079*10187SKrishna.Elango@Sun.COM return (PF_HDL_NOTFOUND); 2080*10187SKrishna.Elango@Sun.COM 2081*10187SKrishna.Elango@Sun.COM if (!(flag & (PF_ADDR_DMA | PF_ADDR_PIO | PF_ADDR_CFG))) { 2082*10187SKrishna.Elango@Sun.COM return (PF_HDL_NOTFOUND); 2083*10187SKrishna.Elango@Sun.COM } 2084*10187SKrishna.Elango@Sun.COM 2085*10187SKrishna.Elango@Sun.COM bzero(&derr, sizeof (ddi_fm_error_t)); 2086*10187SKrishna.Elango@Sun.COM derr.fme_version = DDI_FME_VERSION; 2087*10187SKrishna.Elango@Sun.COM derr.fme_flag = DDI_FM_ERR_UNEXPECTED; 2088*10187SKrishna.Elango@Sun.COM derr.fme_ena = ena; 2089*10187SKrishna.Elango@Sun.COM 2090*10187SKrishna.Elango@Sun.COM return (pf_hdl_child_lookup(dip, &derr, flag, addr, bdf)); 2091*10187SKrishna.Elango@Sun.COM } 2092*10187SKrishna.Elango@Sun.COM 2093*10187SKrishna.Elango@Sun.COM static int 2094*10187SKrishna.Elango@Sun.COM pf_hdl_child_lookup(dev_info_t *dip, ddi_fm_error_t *derr, uint32_t flag, 2095*10187SKrishna.Elango@Sun.COM uint64_t addr, pcie_req_id_t bdf) 2096*10187SKrishna.Elango@Sun.COM { 2097*10187SKrishna.Elango@Sun.COM int status = PF_HDL_NOTFOUND; 2098*10187SKrishna.Elango@Sun.COM ndi_fmc_t *fcp = NULL; 2099*10187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 2100*10187SKrishna.Elango@Sun.COM pcie_req_id_t dip_bdf; 2101*10187SKrishna.Elango@Sun.COM boolean_t have_lock = B_FALSE; 2102*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 2103*10187SKrishna.Elango@Sun.COM dev_info_t *cdip; 2104*10187SKrishna.Elango@Sun.COM 2105*10187SKrishna.Elango@Sun.COM if (!(bus_p = pf_is_ready(dip))) { 2106*10187SKrishna.Elango@Sun.COM return (status); 2107*10187SKrishna.Elango@Sun.COM } 2108*10187SKrishna.Elango@Sun.COM 2109*10187SKrishna.Elango@Sun.COM ASSERT(fmhdl); 2110*10187SKrishna.Elango@Sun.COM if (!i_ddi_fm_handler_owned(dip)) { 2111*10187SKrishna.Elango@Sun.COM /* 2112*10187SKrishna.Elango@Sun.COM * pf_handler_enter always returns SUCCESS if the 'impl' arg is 2113*10187SKrishna.Elango@Sun.COM * NULL. 2114*10187SKrishna.Elango@Sun.COM */ 2115*10187SKrishna.Elango@Sun.COM (void) pf_handler_enter(dip, NULL); 2116*10187SKrishna.Elango@Sun.COM have_lock = B_TRUE; 2117*10187SKrishna.Elango@Sun.COM } 2118*10187SKrishna.Elango@Sun.COM 2119*10187SKrishna.Elango@Sun.COM dip_bdf = PCI_GET_BDF(dip); 2120*10187SKrishna.Elango@Sun.COM 2121*10187SKrishna.Elango@Sun.COM /* Check if dip and BDF match, if not recurse to it's children. */ 2122*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_RC(bus_p) && (!PCIE_CHECK_VALID_BDF(bdf) || 2123*10187SKrishna.Elango@Sun.COM dip_bdf == bdf)) { 2124*10187SKrishna.Elango@Sun.COM if ((flag & PF_ADDR_DMA) && DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap)) 2125*10187SKrishna.Elango@Sun.COM fcp = fmhdl->fh_dma_cache; 2126*10187SKrishna.Elango@Sun.COM else 2127*10187SKrishna.Elango@Sun.COM fcp = NULL; 2128*10187SKrishna.Elango@Sun.COM 2129*10187SKrishna.Elango@Sun.COM if (fcp) 2130*10187SKrishna.Elango@Sun.COM status = pf_hdl_compare(dip, derr, DMA_HANDLE, addr, 2131*10187SKrishna.Elango@Sun.COM bdf, fcp); 2132*10187SKrishna.Elango@Sun.COM 2133*10187SKrishna.Elango@Sun.COM 2134*10187SKrishna.Elango@Sun.COM if (((flag & PF_ADDR_PIO) || (flag & PF_ADDR_CFG)) && 2135*10187SKrishna.Elango@Sun.COM DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap)) 2136*10187SKrishna.Elango@Sun.COM fcp = fmhdl->fh_acc_cache; 2137*10187SKrishna.Elango@Sun.COM else 2138*10187SKrishna.Elango@Sun.COM fcp = NULL; 2139*10187SKrishna.Elango@Sun.COM 2140*10187SKrishna.Elango@Sun.COM if (fcp) 2141*10187SKrishna.Elango@Sun.COM status = pf_hdl_compare(dip, derr, ACC_HANDLE, addr, 2142*10187SKrishna.Elango@Sun.COM bdf, fcp); 2143*10187SKrishna.Elango@Sun.COM } 2144*10187SKrishna.Elango@Sun.COM 2145*10187SKrishna.Elango@Sun.COM /* If we found the handler or know it's this device, we're done */ 2146*10187SKrishna.Elango@Sun.COM if (!PCIE_IS_RC(bus_p) && ((dip_bdf == bdf) || 2147*10187SKrishna.Elango@Sun.COM (status == PF_HDL_FOUND))) 2148*10187SKrishna.Elango@Sun.COM goto done; 2149*10187SKrishna.Elango@Sun.COM 2150*10187SKrishna.Elango@Sun.COM /* 2151*10187SKrishna.Elango@Sun.COM * If the current devuce us a PCIe-PCI bridge need to check for special 2152*10187SKrishna.Elango@Sun.COM * cases: 2153*10187SKrishna.Elango@Sun.COM * 2154*10187SKrishna.Elango@Sun.COM * If it is a PIO and we don't have an address or this is a DMA, check 2155*10187SKrishna.Elango@Sun.COM * to see if the BDF = secondary bus. If so stop. The BDF isn't a real 2156*10187SKrishna.Elango@Sun.COM * BDF and the fault device could have come from any device in the PCI 2157*10187SKrishna.Elango@Sun.COM * bus. 2158*10187SKrishna.Elango@Sun.COM */ 2159*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && 2160*10187SKrishna.Elango@Sun.COM ((flag & PF_ADDR_DMA || flag & PF_ADDR_PIO)) && 2161*10187SKrishna.Elango@Sun.COM ((bus_p->bus_bdg_secbus << PCIE_REQ_ID_BUS_SHIFT) == bdf)) 2162*10187SKrishna.Elango@Sun.COM goto done; 2163*10187SKrishna.Elango@Sun.COM 2164*10187SKrishna.Elango@Sun.COM 2165*10187SKrishna.Elango@Sun.COM /* If we can't find the handler check it's children */ 2166*10187SKrishna.Elango@Sun.COM for (cdip = ddi_get_child(dip); cdip; 2167*10187SKrishna.Elango@Sun.COM cdip = ddi_get_next_sibling(cdip)) { 2168*10187SKrishna.Elango@Sun.COM if ((bus_p = PCIE_DIP2BUS(cdip)) == NULL) 2169*10187SKrishna.Elango@Sun.COM continue; 2170*10187SKrishna.Elango@Sun.COM 2171*10187SKrishna.Elango@Sun.COM if (pf_in_bus_range(bus_p, bdf) || 2172*10187SKrishna.Elango@Sun.COM pf_in_addr_range(bus_p, addr)) 2173*10187SKrishna.Elango@Sun.COM status = pf_hdl_child_lookup(cdip, derr, flag, addr, 2174*10187SKrishna.Elango@Sun.COM bdf); 2175*10187SKrishna.Elango@Sun.COM 2176*10187SKrishna.Elango@Sun.COM if (status == PF_HDL_FOUND) 2177*10187SKrishna.Elango@Sun.COM goto done; 2178*10187SKrishna.Elango@Sun.COM } 2179*10187SKrishna.Elango@Sun.COM 2180*10187SKrishna.Elango@Sun.COM done: 2181*10187SKrishna.Elango@Sun.COM if (have_lock == B_TRUE) 2182*10187SKrishna.Elango@Sun.COM pf_handler_exit(dip); 2183*10187SKrishna.Elango@Sun.COM 2184*10187SKrishna.Elango@Sun.COM return (status); 2185*10187SKrishna.Elango@Sun.COM } 2186*10187SKrishna.Elango@Sun.COM 2187*10187SKrishna.Elango@Sun.COM static int 2188*10187SKrishna.Elango@Sun.COM pf_hdl_compare(dev_info_t *dip, ddi_fm_error_t *derr, uint32_t flag, 2189*10187SKrishna.Elango@Sun.COM uint64_t addr, pcie_req_id_t bdf, ndi_fmc_t *fcp) { 2190*10187SKrishna.Elango@Sun.COM ndi_fmcentry_t *fep; 2191*10187SKrishna.Elango@Sun.COM int found = 0; 2192*10187SKrishna.Elango@Sun.COM int status; 2193*10187SKrishna.Elango@Sun.COM 2194*10187SKrishna.Elango@Sun.COM mutex_enter(&fcp->fc_lock); 2195*10187SKrishna.Elango@Sun.COM for (fep = fcp->fc_head; fep != NULL; fep = fep->fce_next) { 2196*10187SKrishna.Elango@Sun.COM ddi_fmcompare_t compare_func; 2197*10187SKrishna.Elango@Sun.COM 2198*10187SKrishna.Elango@Sun.COM /* 2199*10187SKrishna.Elango@Sun.COM * Compare captured error state with handle 2200*10187SKrishna.Elango@Sun.COM * resources. During the comparison and 2201*10187SKrishna.Elango@Sun.COM * subsequent error handling, we block 2202*10187SKrishna.Elango@Sun.COM * attempts to free the cache entry. 2203*10187SKrishna.Elango@Sun.COM */ 2204*10187SKrishna.Elango@Sun.COM compare_func = (flag == ACC_HANDLE) ? 2205*10187SKrishna.Elango@Sun.COM i_ddi_fm_acc_err_cf_get((ddi_acc_handle_t) 2206*10187SKrishna.Elango@Sun.COM fep->fce_resource) : 2207*10187SKrishna.Elango@Sun.COM i_ddi_fm_dma_err_cf_get((ddi_dma_handle_t) 2208*10187SKrishna.Elango@Sun.COM fep->fce_resource); 2209*10187SKrishna.Elango@Sun.COM 2210*10187SKrishna.Elango@Sun.COM status = compare_func(dip, fep->fce_resource, 2211*10187SKrishna.Elango@Sun.COM (void *)&addr, (void *)&bdf); 2212*10187SKrishna.Elango@Sun.COM 2213*10187SKrishna.Elango@Sun.COM if (status == DDI_FM_NONFATAL) { 2214*10187SKrishna.Elango@Sun.COM found++; 2215*10187SKrishna.Elango@Sun.COM 2216*10187SKrishna.Elango@Sun.COM /* Set the error for this resource handle */ 2217*10187SKrishna.Elango@Sun.COM if (flag == ACC_HANDLE) { 2218*10187SKrishna.Elango@Sun.COM ddi_acc_handle_t ap = fep->fce_resource; 2219*10187SKrishna.Elango@Sun.COM 2220*10187SKrishna.Elango@Sun.COM i_ddi_fm_acc_err_set(ap, derr->fme_ena, status, 2221*10187SKrishna.Elango@Sun.COM DDI_FM_ERR_UNEXPECTED); 2222*10187SKrishna.Elango@Sun.COM ddi_fm_acc_err_get(ap, derr, DDI_FME_VERSION); 2223*10187SKrishna.Elango@Sun.COM derr->fme_acc_handle = ap; 2224*10187SKrishna.Elango@Sun.COM } else { 2225*10187SKrishna.Elango@Sun.COM ddi_dma_handle_t dp = fep->fce_resource; 2226*10187SKrishna.Elango@Sun.COM 2227*10187SKrishna.Elango@Sun.COM i_ddi_fm_dma_err_set(dp, derr->fme_ena, status, 2228*10187SKrishna.Elango@Sun.COM DDI_FM_ERR_UNEXPECTED); 2229*10187SKrishna.Elango@Sun.COM ddi_fm_dma_err_get(dp, derr, DDI_FME_VERSION); 2230*10187SKrishna.Elango@Sun.COM derr->fme_dma_handle = dp; 2231*10187SKrishna.Elango@Sun.COM } 2232*10187SKrishna.Elango@Sun.COM } 2233*10187SKrishna.Elango@Sun.COM } 2234*10187SKrishna.Elango@Sun.COM mutex_exit(&fcp->fc_lock); 2235*10187SKrishna.Elango@Sun.COM 2236*10187SKrishna.Elango@Sun.COM /* 2237*10187SKrishna.Elango@Sun.COM * If a handler isn't found and we know this is the right device mark 2238*10187SKrishna.Elango@Sun.COM * them all failed. 2239*10187SKrishna.Elango@Sun.COM */ 2240*10187SKrishna.Elango@Sun.COM if ((addr != NULL) && PCIE_CHECK_VALID_BDF(bdf) && (found == 0)) { 2241*10187SKrishna.Elango@Sun.COM status = pf_hdl_compare(dip, derr, flag, addr, bdf, fcp); 2242*10187SKrishna.Elango@Sun.COM if (status == PF_HDL_FOUND) 2243*10187SKrishna.Elango@Sun.COM found++; 2244*10187SKrishna.Elango@Sun.COM } 2245*10187SKrishna.Elango@Sun.COM 2246*10187SKrishna.Elango@Sun.COM return ((found) ? PF_HDL_FOUND : PF_HDL_NOTFOUND); 2247*10187SKrishna.Elango@Sun.COM } 2248*10187SKrishna.Elango@Sun.COM 2249*10187SKrishna.Elango@Sun.COM /* 2250*10187SKrishna.Elango@Sun.COM * Automatically decode AER header logs and does a handling look up based on the 2251*10187SKrishna.Elango@Sun.COM * AER header decoding. 2252*10187SKrishna.Elango@Sun.COM * 2253*10187SKrishna.Elango@Sun.COM * For this function only the Primary/Secondary AER Header Logs need to be valid 2254*10187SKrishna.Elango@Sun.COM * in the pfd (PCIe Fault Data) arg. 2255*10187SKrishna.Elango@Sun.COM * 2256*10187SKrishna.Elango@Sun.COM * Returns either PF_HDL_NOTFOUND or PF_HDL_FOUND. 2257*10187SKrishna.Elango@Sun.COM */ 2258*10187SKrishna.Elango@Sun.COM static int 2259*10187SKrishna.Elango@Sun.COM pf_log_hdl_lookup(dev_info_t *rpdip, ddi_fm_error_t *derr, pf_data_t *pfd_p, 2260*10187SKrishna.Elango@Sun.COM boolean_t is_primary) 2261*10187SKrishna.Elango@Sun.COM { 2262*10187SKrishna.Elango@Sun.COM int lookup = PF_HDL_NOTFOUND; 2263*10187SKrishna.Elango@Sun.COM 2264*10187SKrishna.Elango@Sun.COM if (is_primary) { 2265*10187SKrishna.Elango@Sun.COM pf_pcie_adv_err_regs_t *reg_p = PCIE_ADV_REG(pfd_p); 2266*10187SKrishna.Elango@Sun.COM if (pf_tlp_decode(PCIE_PFD2BUS(pfd_p), reg_p) == DDI_SUCCESS) { 2267*10187SKrishna.Elango@Sun.COM lookup = pf_hdl_lookup(rpdip, derr->fme_ena, 2268*10187SKrishna.Elango@Sun.COM reg_p->pcie_ue_tgt_trans, 2269*10187SKrishna.Elango@Sun.COM reg_p->pcie_ue_tgt_addr, 2270*10187SKrishna.Elango@Sun.COM reg_p->pcie_ue_tgt_bdf); 2271*10187SKrishna.Elango@Sun.COM } 2272*10187SKrishna.Elango@Sun.COM } else { 2273*10187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *reg_p = PCIE_ADV_BDG_REG(pfd_p); 2274*10187SKrishna.Elango@Sun.COM uint16_t cmd; 2275*10187SKrishna.Elango@Sun.COM if (pf_pci_decode(pfd_p, &cmd) == DDI_SUCCESS) { 2276*10187SKrishna.Elango@Sun.COM lookup = pf_hdl_lookup(rpdip, derr->fme_ena, 2277*10187SKrishna.Elango@Sun.COM reg_p->pcie_sue_tgt_trans, 2278*10187SKrishna.Elango@Sun.COM reg_p->pcie_sue_tgt_addr, 2279*10187SKrishna.Elango@Sun.COM reg_p->pcie_sue_tgt_bdf); 2280*10187SKrishna.Elango@Sun.COM } 2281*10187SKrishna.Elango@Sun.COM } 2282*10187SKrishna.Elango@Sun.COM 2283*10187SKrishna.Elango@Sun.COM return (lookup); 2284*10187SKrishna.Elango@Sun.COM } 2285*10187SKrishna.Elango@Sun.COM 2286*10187SKrishna.Elango@Sun.COM /* 2287*10187SKrishna.Elango@Sun.COM * Decodes the TLP and returns the BDF of the handler, address and transaction 2288*10187SKrishna.Elango@Sun.COM * type if known. 2289*10187SKrishna.Elango@Sun.COM * 2290*10187SKrishna.Elango@Sun.COM * Types of TLP logs seen in RC, and what to extract: 2291*10187SKrishna.Elango@Sun.COM * 2292*10187SKrishna.Elango@Sun.COM * Memory(DMA) - Requester BDF, address, PF_DMA_ADDR 2293*10187SKrishna.Elango@Sun.COM * Memory(PIO) - address, PF_PIO_ADDR 2294*10187SKrishna.Elango@Sun.COM * CFG - Should not occur and result in UR 2295*10187SKrishna.Elango@Sun.COM * Completion(DMA) - Requester BDF, PF_DMA_ADDR 2296*10187SKrishna.Elango@Sun.COM * Completion(PIO) - Requester BDF, PF_PIO_ADDR 2297*10187SKrishna.Elango@Sun.COM * 2298*10187SKrishna.Elango@Sun.COM * Types of TLP logs seen in SW/Leaf, and what to extract: 2299*10187SKrishna.Elango@Sun.COM * 2300*10187SKrishna.Elango@Sun.COM * Memory(DMA) - Requester BDF, address, PF_DMA_ADDR 2301*10187SKrishna.Elango@Sun.COM * Memory(PIO) - address, PF_PIO_ADDR 2302*10187SKrishna.Elango@Sun.COM * CFG - Destined BDF, address, PF_CFG_ADDR 2303*10187SKrishna.Elango@Sun.COM * Completion(DMA) - Requester BDF, PF_DMA_ADDR 2304*10187SKrishna.Elango@Sun.COM * Completion(PIO) - Requester BDF, PF_PIO_ADDR 2305*10187SKrishna.Elango@Sun.COM * 2306*10187SKrishna.Elango@Sun.COM * The adv_reg_p must be passed in separately for use with SPARC RPs. A 2307*10187SKrishna.Elango@Sun.COM * SPARC RP could have multiple AER header logs which cannot be directly 2308*10187SKrishna.Elango@Sun.COM * accessed via the bus_p. 2309*10187SKrishna.Elango@Sun.COM */ 2310*10187SKrishna.Elango@Sun.COM int 2311*10187SKrishna.Elango@Sun.COM pf_tlp_decode(pcie_bus_t *bus_p, pf_pcie_adv_err_regs_t *adv_reg_p) { 2312*10187SKrishna.Elango@Sun.COM pcie_tlp_hdr_t *tlp_hdr = (pcie_tlp_hdr_t *)adv_reg_p->pcie_ue_hdr; 2313*10187SKrishna.Elango@Sun.COM pcie_req_id_t my_bdf, tlp_bdf, flt_bdf = PCIE_INVALID_BDF; 2314*10187SKrishna.Elango@Sun.COM uint64_t flt_addr = 0; 2315*10187SKrishna.Elango@Sun.COM uint32_t flt_trans_type = 0; 2316*10187SKrishna.Elango@Sun.COM 2317*10187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_addr = 0; 2318*10187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_bdf = PCIE_INVALID_BDF; 2319*10187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_trans = 0; 2320*10187SKrishna.Elango@Sun.COM 2321*10187SKrishna.Elango@Sun.COM my_bdf = bus_p->bus_bdf; 2322*10187SKrishna.Elango@Sun.COM switch (tlp_hdr->type) { 2323*10187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_IO: 2324*10187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_MEM: 2325*10187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_MEMLK: 2326*10187SKrishna.Elango@Sun.COM /* Grab the 32/64bit fault address */ 2327*10187SKrishna.Elango@Sun.COM if (tlp_hdr->fmt & 0x1) { 2328*10187SKrishna.Elango@Sun.COM flt_addr = ((uint64_t)adv_reg_p->pcie_ue_hdr[2] << 32); 2329*10187SKrishna.Elango@Sun.COM flt_addr |= adv_reg_p->pcie_ue_hdr[3]; 2330*10187SKrishna.Elango@Sun.COM } else { 2331*10187SKrishna.Elango@Sun.COM flt_addr = adv_reg_p->pcie_ue_hdr[2]; 2332*10187SKrishna.Elango@Sun.COM } 2333*10187SKrishna.Elango@Sun.COM 2334*10187SKrishna.Elango@Sun.COM tlp_bdf = (pcie_req_id_t)(adv_reg_p->pcie_ue_hdr[1] >> 16); 2335*10187SKrishna.Elango@Sun.COM 2336*10187SKrishna.Elango@Sun.COM /* 2337*10187SKrishna.Elango@Sun.COM * If the req bdf >= this.bdf, then it means the request is this 2338*10187SKrishna.Elango@Sun.COM * device or came from a device below it. Unless this device is 2339*10187SKrishna.Elango@Sun.COM * a PCIe root port then it means is a DMA, otherwise PIO. 2340*10187SKrishna.Elango@Sun.COM */ 2341*10187SKrishna.Elango@Sun.COM if ((tlp_bdf >= my_bdf) && !PCIE_IS_ROOT(bus_p)) { 2342*10187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_DMA; 2343*10187SKrishna.Elango@Sun.COM flt_bdf = tlp_bdf; 2344*10187SKrishna.Elango@Sun.COM } else if (PCIE_IS_ROOT(bus_p) && 2345*10187SKrishna.Elango@Sun.COM (PF_FIRST_AER_ERR(PCIE_AER_UCE_PTLP, adv_reg_p) || 2346*10187SKrishna.Elango@Sun.COM (PF_FIRST_AER_ERR(PCIE_AER_UCE_CA, adv_reg_p)))) { 2347*10187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_DMA; 2348*10187SKrishna.Elango@Sun.COM flt_bdf = tlp_bdf; 2349*10187SKrishna.Elango@Sun.COM } else { 2350*10187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_PIO; 2351*10187SKrishna.Elango@Sun.COM flt_bdf = PCIE_INVALID_BDF; 2352*10187SKrishna.Elango@Sun.COM } 2353*10187SKrishna.Elango@Sun.COM break; 2354*10187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_CFG0: 2355*10187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_CFG1: 2356*10187SKrishna.Elango@Sun.COM flt_addr = 0; 2357*10187SKrishna.Elango@Sun.COM flt_bdf = (pcie_req_id_t)(adv_reg_p->pcie_ue_hdr[2] >> 16); 2358*10187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_CFG; 2359*10187SKrishna.Elango@Sun.COM break; 2360*10187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_CPL: 2361*10187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_CPLLK: 2362*10187SKrishna.Elango@Sun.COM { 2363*10187SKrishna.Elango@Sun.COM pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)adv_reg_p->pcie_ue_hdr; 2364*10187SKrishna.Elango@Sun.COM 2365*10187SKrishna.Elango@Sun.COM flt_addr = NULL; 2366*10187SKrishna.Elango@Sun.COM flt_bdf = cpl_tlp->rid; 2367*10187SKrishna.Elango@Sun.COM 2368*10187SKrishna.Elango@Sun.COM /* 2369*10187SKrishna.Elango@Sun.COM * If the cpl bdf < this.bdf, then it means the request is this 2370*10187SKrishna.Elango@Sun.COM * device or came from a device below it. Unless this device is 2371*10187SKrishna.Elango@Sun.COM * a PCIe root port then it means is a DMA, otherwise PIO. 2372*10187SKrishna.Elango@Sun.COM */ 2373*10187SKrishna.Elango@Sun.COM if (cpl_tlp->rid > cpl_tlp->cid) { 2374*10187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_DMA; 2375*10187SKrishna.Elango@Sun.COM } else { 2376*10187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_PIO | PF_ADDR_CFG; 2377*10187SKrishna.Elango@Sun.COM } 2378*10187SKrishna.Elango@Sun.COM break; 2379*10187SKrishna.Elango@Sun.COM } 2380*10187SKrishna.Elango@Sun.COM default: 2381*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 2382*10187SKrishna.Elango@Sun.COM } 2383*10187SKrishna.Elango@Sun.COM 2384*10187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_addr = flt_addr; 2385*10187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_bdf = flt_bdf; 2386*10187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_trans = flt_trans_type; 2387*10187SKrishna.Elango@Sun.COM 2388*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 2389*10187SKrishna.Elango@Sun.COM } 2390*10187SKrishna.Elango@Sun.COM 2391*10187SKrishna.Elango@Sun.COM #define PCIE_EREPORT DDI_IO_CLASS "." PCI_ERROR_SUBCLASS "." PCIEX_FABRIC 2392*10187SKrishna.Elango@Sun.COM static int 2393*10187SKrishna.Elango@Sun.COM pf_ereport_setup(dev_info_t *dip, uint64_t ena, nvlist_t **ereport, 2394*10187SKrishna.Elango@Sun.COM nvlist_t **detector, errorq_elem_t **eqep) 2395*10187SKrishna.Elango@Sun.COM { 2396*10187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 2397*10187SKrishna.Elango@Sun.COM char device_path[MAXPATHLEN]; 2398*10187SKrishna.Elango@Sun.COM nv_alloc_t *nva; 2399*10187SKrishna.Elango@Sun.COM 2400*10187SKrishna.Elango@Sun.COM *eqep = errorq_reserve(fmhdl->fh_errorq); 2401*10187SKrishna.Elango@Sun.COM if (*eqep == NULL) { 2402*10187SKrishna.Elango@Sun.COM atomic_add_64(&fmhdl->fh_kstat.fek_erpt_dropped.value.ui64, 1); 2403*10187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 2404*10187SKrishna.Elango@Sun.COM } 2405*10187SKrishna.Elango@Sun.COM 2406*10187SKrishna.Elango@Sun.COM *ereport = errorq_elem_nvl(fmhdl->fh_errorq, *eqep); 2407*10187SKrishna.Elango@Sun.COM nva = errorq_elem_nva(fmhdl->fh_errorq, *eqep); 2408*10187SKrishna.Elango@Sun.COM 2409*10187SKrishna.Elango@Sun.COM ASSERT(*ereport); 2410*10187SKrishna.Elango@Sun.COM ASSERT(nva); 2411*10187SKrishna.Elango@Sun.COM 2412*10187SKrishna.Elango@Sun.COM /* 2413*10187SKrishna.Elango@Sun.COM * Use the dev_path/devid for this device instance. 2414*10187SKrishna.Elango@Sun.COM */ 2415*10187SKrishna.Elango@Sun.COM *detector = fm_nvlist_create(nva); 2416*10187SKrishna.Elango@Sun.COM if (dip == ddi_root_node()) { 2417*10187SKrishna.Elango@Sun.COM device_path[0] = '/'; 2418*10187SKrishna.Elango@Sun.COM device_path[1] = '\0'; 2419*10187SKrishna.Elango@Sun.COM } else { 2420*10187SKrishna.Elango@Sun.COM (void) ddi_pathname(dip, device_path); 2421*10187SKrishna.Elango@Sun.COM } 2422*10187SKrishna.Elango@Sun.COM 2423*10187SKrishna.Elango@Sun.COM fm_fmri_dev_set(*detector, FM_DEV_SCHEME_VERSION, NULL, 2424*10187SKrishna.Elango@Sun.COM device_path, NULL); 2425*10187SKrishna.Elango@Sun.COM 2426*10187SKrishna.Elango@Sun.COM if (ena == 0) 2427*10187SKrishna.Elango@Sun.COM ena = fm_ena_generate(0, FM_ENA_FMT1); 2428*10187SKrishna.Elango@Sun.COM 2429*10187SKrishna.Elango@Sun.COM fm_ereport_set(*ereport, 0, PCIE_EREPORT, ena, *detector, NULL); 2430*10187SKrishna.Elango@Sun.COM 2431*10187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 2432*10187SKrishna.Elango@Sun.COM } 2433*10187SKrishna.Elango@Sun.COM 2434*10187SKrishna.Elango@Sun.COM /* ARGSUSED */ 2435*10187SKrishna.Elango@Sun.COM static void 2436*10187SKrishna.Elango@Sun.COM pf_ereport_post(dev_info_t *dip, nvlist_t **ereport, nvlist_t **detector, 2437*10187SKrishna.Elango@Sun.COM errorq_elem_t **eqep) 2438*10187SKrishna.Elango@Sun.COM { 2439*10187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 2440*10187SKrishna.Elango@Sun.COM 2441*10187SKrishna.Elango@Sun.COM errorq_commit(fmhdl->fh_errorq, *eqep, ERRORQ_ASYNC); 2442*10187SKrishna.Elango@Sun.COM } 2443*10187SKrishna.Elango@Sun.COM 2444*10187SKrishna.Elango@Sun.COM static void 2445*10187SKrishna.Elango@Sun.COM pf_send_ereport(ddi_fm_error_t *derr, pf_impl_t *impl) 2446*10187SKrishna.Elango@Sun.COM { 2447*10187SKrishna.Elango@Sun.COM nvlist_t *ereport; 2448*10187SKrishna.Elango@Sun.COM nvlist_t *detector; 2449*10187SKrishna.Elango@Sun.COM errorq_elem_t *eqep; 2450*10187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 2451*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p; 2452*10187SKrishna.Elango@Sun.COM uint32_t total = impl->pf_total; 2453*10187SKrishna.Elango@Sun.COM 2454*10187SKrishna.Elango@Sun.COM /* 2455*10187SKrishna.Elango@Sun.COM * Ereports need to be sent in a top down fashion. The fabric translator 2456*10187SKrishna.Elango@Sun.COM * expects the ereports from the Root first. This is needed to tell if 2457*10187SKrishna.Elango@Sun.COM * the system contains a PCIe complaint RC/RP. 2458*10187SKrishna.Elango@Sun.COM */ 2459*10187SKrishna.Elango@Sun.COM for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) { 2460*10187SKrishna.Elango@Sun.COM bus_p = PCIE_PFD2BUS(pfd_p); 2461*10187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE; 2462*10187SKrishna.Elango@Sun.COM 2463*10187SKrishna.Elango@Sun.COM if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED || 2464*10187SKrishna.Elango@Sun.COM PFD_IS_RC(pfd_p) || 2465*10187SKrishna.Elango@Sun.COM !DDI_FM_EREPORT_CAP(ddi_fm_capable(PCIE_PFD2DIP(pfd_p)))) 2466*10187SKrishna.Elango@Sun.COM continue; 2467*10187SKrishna.Elango@Sun.COM 2468*10187SKrishna.Elango@Sun.COM if (pf_ereport_setup(PCIE_BUS2DIP(bus_p), derr->fme_ena, 2469*10187SKrishna.Elango@Sun.COM &ereport, &detector, &eqep) != DDI_SUCCESS) 2470*10187SKrishna.Elango@Sun.COM continue; 2471*10187SKrishna.Elango@Sun.COM 2472*10187SKrishna.Elango@Sun.COM /* Generic PCI device information */ 2473*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2474*10187SKrishna.Elango@Sun.COM "bdf", DATA_TYPE_UINT16, bus_p->bus_bdf, 2475*10187SKrishna.Elango@Sun.COM "device_id", DATA_TYPE_UINT16, 2476*10187SKrishna.Elango@Sun.COM (bus_p->bus_dev_ven_id >> 16), 2477*10187SKrishna.Elango@Sun.COM "vendor_id", DATA_TYPE_UINT16, 2478*10187SKrishna.Elango@Sun.COM (bus_p->bus_dev_ven_id & 0xFFFF), 2479*10187SKrishna.Elango@Sun.COM "rev_id", DATA_TYPE_UINT8, bus_p->bus_rev_id, 2480*10187SKrishna.Elango@Sun.COM "dev_type", DATA_TYPE_UINT16, bus_p->bus_dev_type, 2481*10187SKrishna.Elango@Sun.COM "pcie_off", DATA_TYPE_UINT16, bus_p->bus_pcie_off, 2482*10187SKrishna.Elango@Sun.COM "pcix_off", DATA_TYPE_UINT16, bus_p->bus_pcix_off, 2483*10187SKrishna.Elango@Sun.COM "aer_off", DATA_TYPE_UINT16, bus_p->bus_aer_off, 2484*10187SKrishna.Elango@Sun.COM "ecc_ver", DATA_TYPE_UINT16, bus_p->bus_ecc_ver, 2485*10187SKrishna.Elango@Sun.COM NULL); 2486*10187SKrishna.Elango@Sun.COM 2487*10187SKrishna.Elango@Sun.COM /* PCI registers */ 2488*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2489*10187SKrishna.Elango@Sun.COM "pci_status", DATA_TYPE_UINT16, 2490*10187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p)->pci_err_status, 2491*10187SKrishna.Elango@Sun.COM "pci_command", DATA_TYPE_UINT16, 2492*10187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p)->pci_cfg_comm, 2493*10187SKrishna.Elango@Sun.COM NULL); 2494*10187SKrishna.Elango@Sun.COM 2495*10187SKrishna.Elango@Sun.COM /* PCI bridge registers */ 2496*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 2497*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2498*10187SKrishna.Elango@Sun.COM "pci_bdg_sec_status", DATA_TYPE_UINT16, 2499*10187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat, 2500*10187SKrishna.Elango@Sun.COM "pci_bdg_ctrl", DATA_TYPE_UINT16, 2501*10187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p)->pci_bdg_ctrl, 2502*10187SKrishna.Elango@Sun.COM NULL); 2503*10187SKrishna.Elango@Sun.COM } 2504*10187SKrishna.Elango@Sun.COM 2505*10187SKrishna.Elango@Sun.COM /* PCIx registers */ 2506*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIX(bus_p) && !PCIE_IS_BDG(bus_p)) { 2507*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2508*10187SKrishna.Elango@Sun.COM "pcix_status", DATA_TYPE_UINT32, 2509*10187SKrishna.Elango@Sun.COM PCIX_ERR_REG(pfd_p)->pcix_status, 2510*10187SKrishna.Elango@Sun.COM "pcix_command", DATA_TYPE_UINT16, 2511*10187SKrishna.Elango@Sun.COM PCIX_ERR_REG(pfd_p)->pcix_command, 2512*10187SKrishna.Elango@Sun.COM NULL); 2513*10187SKrishna.Elango@Sun.COM } 2514*10187SKrishna.Elango@Sun.COM 2515*10187SKrishna.Elango@Sun.COM /* PCIx ECC Registers */ 2516*10187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 2517*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *ecc_bdg_reg; 2518*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *ecc_reg; 2519*10187SKrishna.Elango@Sun.COM 2520*10187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 2521*10187SKrishna.Elango@Sun.COM ecc_bdg_reg = PCIX_BDG_ECC_REG(pfd_p, 0); 2522*10187SKrishna.Elango@Sun.COM ecc_reg = PCIX_ECC_REG(pfd_p); 2523*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2524*10187SKrishna.Elango@Sun.COM "pcix_ecc_control_0", DATA_TYPE_UINT16, 2525*10187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ? 2526*10187SKrishna.Elango@Sun.COM (ecc_bdg_reg->pcix_ecc_ctlstat >> 16) : 2527*10187SKrishna.Elango@Sun.COM (ecc_reg->pcix_ecc_ctlstat >> 16), 2528*10187SKrishna.Elango@Sun.COM "pcix_ecc_status_0", DATA_TYPE_UINT16, 2529*10187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ? 2530*10187SKrishna.Elango@Sun.COM (ecc_bdg_reg->pcix_ecc_ctlstat & 0xFFFF) : 2531*10187SKrishna.Elango@Sun.COM (ecc_reg->pcix_ecc_ctlstat & 0xFFFF), 2532*10187SKrishna.Elango@Sun.COM "pcix_ecc_fst_addr_0", DATA_TYPE_UINT32, 2533*10187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ? 2534*10187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_fstaddr : 2535*10187SKrishna.Elango@Sun.COM ecc_reg->pcix_ecc_fstaddr, 2536*10187SKrishna.Elango@Sun.COM "pcix_ecc_sec_addr_0", DATA_TYPE_UINT32, 2537*10187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ? 2538*10187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_secaddr : 2539*10187SKrishna.Elango@Sun.COM ecc_reg->pcix_ecc_secaddr, 2540*10187SKrishna.Elango@Sun.COM "pcix_ecc_attr_0", DATA_TYPE_UINT32, 2541*10187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ? 2542*10187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_attr : 2543*10187SKrishna.Elango@Sun.COM ecc_reg->pcix_ecc_attr, 2544*10187SKrishna.Elango@Sun.COM NULL); 2545*10187SKrishna.Elango@Sun.COM } 2546*10187SKrishna.Elango@Sun.COM 2547*10187SKrishna.Elango@Sun.COM /* PCIx ECC Bridge Registers */ 2548*10187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p) && PCIE_IS_BDG(bus_p)) { 2549*10187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *ecc_bdg_reg; 2550*10187SKrishna.Elango@Sun.COM 2551*10187SKrishna.Elango@Sun.COM ecc_bdg_reg = PCIX_BDG_ECC_REG(pfd_p, 1); 2552*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2553*10187SKrishna.Elango@Sun.COM "pcix_ecc_control_1", DATA_TYPE_UINT16, 2554*10187SKrishna.Elango@Sun.COM (ecc_bdg_reg->pcix_ecc_ctlstat >> 16), 2555*10187SKrishna.Elango@Sun.COM "pcix_ecc_status_1", DATA_TYPE_UINT16, 2556*10187SKrishna.Elango@Sun.COM (ecc_bdg_reg->pcix_ecc_ctlstat & 0xFFFF), 2557*10187SKrishna.Elango@Sun.COM "pcix_ecc_fst_addr_1", DATA_TYPE_UINT32, 2558*10187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_fstaddr, 2559*10187SKrishna.Elango@Sun.COM "pcix_ecc_sec_addr_1", DATA_TYPE_UINT32, 2560*10187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_secaddr, 2561*10187SKrishna.Elango@Sun.COM "pcix_ecc_attr_1", DATA_TYPE_UINT32, 2562*10187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_attr, 2563*10187SKrishna.Elango@Sun.COM NULL); 2564*10187SKrishna.Elango@Sun.COM } 2565*10187SKrishna.Elango@Sun.COM 2566*10187SKrishna.Elango@Sun.COM /* PCIx Bridge */ 2567*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIX(bus_p) && PCIE_IS_BDG(bus_p)) { 2568*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2569*10187SKrishna.Elango@Sun.COM "pcix_bdg_status", DATA_TYPE_UINT32, 2570*10187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_stat, 2571*10187SKrishna.Elango@Sun.COM "pcix_bdg_sec_status", DATA_TYPE_UINT16, 2572*10187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_sec_stat, 2573*10187SKrishna.Elango@Sun.COM NULL); 2574*10187SKrishna.Elango@Sun.COM } 2575*10187SKrishna.Elango@Sun.COM 2576*10187SKrishna.Elango@Sun.COM /* PCIe registers */ 2577*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 2578*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2579*10187SKrishna.Elango@Sun.COM "pcie_status", DATA_TYPE_UINT16, 2580*10187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status, 2581*10187SKrishna.Elango@Sun.COM "pcie_command", DATA_TYPE_UINT16, 2582*10187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_ctl, 2583*10187SKrishna.Elango@Sun.COM "pcie_dev_cap", DATA_TYPE_UINT32, 2584*10187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_dev_cap, 2585*10187SKrishna.Elango@Sun.COM NULL); 2586*10187SKrishna.Elango@Sun.COM } 2587*10187SKrishna.Elango@Sun.COM 2588*10187SKrishna.Elango@Sun.COM /* PCIe AER registers */ 2589*10187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(bus_p)) { 2590*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2591*10187SKrishna.Elango@Sun.COM "pcie_adv_ctl", DATA_TYPE_UINT32, 2592*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_adv_ctl, 2593*10187SKrishna.Elango@Sun.COM "pcie_ue_status", DATA_TYPE_UINT32, 2594*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_status, 2595*10187SKrishna.Elango@Sun.COM "pcie_ue_mask", DATA_TYPE_UINT32, 2596*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_mask, 2597*10187SKrishna.Elango@Sun.COM "pcie_ue_sev", DATA_TYPE_UINT32, 2598*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_sev, 2599*10187SKrishna.Elango@Sun.COM "pcie_ue_hdr0", DATA_TYPE_UINT32, 2600*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[0], 2601*10187SKrishna.Elango@Sun.COM "pcie_ue_hdr1", DATA_TYPE_UINT32, 2602*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[1], 2603*10187SKrishna.Elango@Sun.COM "pcie_ue_hdr2", DATA_TYPE_UINT32, 2604*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[2], 2605*10187SKrishna.Elango@Sun.COM "pcie_ue_hdr3", DATA_TYPE_UINT32, 2606*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[3], 2607*10187SKrishna.Elango@Sun.COM "pcie_ce_status", DATA_TYPE_UINT32, 2608*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ce_status, 2609*10187SKrishna.Elango@Sun.COM "pcie_ce_mask", DATA_TYPE_UINT32, 2610*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ce_mask, 2611*10187SKrishna.Elango@Sun.COM NULL); 2612*10187SKrishna.Elango@Sun.COM } 2613*10187SKrishna.Elango@Sun.COM 2614*10187SKrishna.Elango@Sun.COM /* PCIe AER decoded header */ 2615*10187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, PCIE_ADV_REG(pfd_p)->pcie_ue_status)) { 2616*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2617*10187SKrishna.Elango@Sun.COM "pcie_ue_tgt_trans", DATA_TYPE_UINT32, 2618*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_trans, 2619*10187SKrishna.Elango@Sun.COM "pcie_ue_tgt_addr", DATA_TYPE_UINT64, 2620*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr, 2621*10187SKrishna.Elango@Sun.COM "pcie_ue_tgt_bdf", DATA_TYPE_UINT16, 2622*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf, 2623*10187SKrishna.Elango@Sun.COM NULL); 2624*10187SKrishna.Elango@Sun.COM /* Clear these values as they no longer valid */ 2625*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_trans = 0; 2626*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr = 0; 2627*10187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF; 2628*10187SKrishna.Elango@Sun.COM } 2629*10187SKrishna.Elango@Sun.COM 2630*10187SKrishna.Elango@Sun.COM /* PCIe BDG AER registers */ 2631*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_HAS_AER(bus_p)) { 2632*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2633*10187SKrishna.Elango@Sun.COM "pcie_sue_adv_ctl", DATA_TYPE_UINT32, 2634*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_ctl, 2635*10187SKrishna.Elango@Sun.COM "pcie_sue_status", DATA_TYPE_UINT32, 2636*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status, 2637*10187SKrishna.Elango@Sun.COM "pcie_sue_mask", DATA_TYPE_UINT32, 2638*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_mask, 2639*10187SKrishna.Elango@Sun.COM "pcie_sue_sev", DATA_TYPE_UINT32, 2640*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_sev, 2641*10187SKrishna.Elango@Sun.COM "pcie_sue_hdr0", DATA_TYPE_UINT32, 2642*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[0], 2643*10187SKrishna.Elango@Sun.COM "pcie_sue_hdr1", DATA_TYPE_UINT32, 2644*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[1], 2645*10187SKrishna.Elango@Sun.COM "pcie_sue_hdr2", DATA_TYPE_UINT32, 2646*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[2], 2647*10187SKrishna.Elango@Sun.COM "pcie_sue_hdr3", DATA_TYPE_UINT32, 2648*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[3], 2649*10187SKrishna.Elango@Sun.COM NULL); 2650*10187SKrishna.Elango@Sun.COM } 2651*10187SKrishna.Elango@Sun.COM 2652*10187SKrishna.Elango@Sun.COM /* PCIe BDG AER decoded header */ 2653*10187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && HAS_SAER_LOGS(pfd_p, 2654*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status)) { 2655*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2656*10187SKrishna.Elango@Sun.COM "pcie_sue_tgt_trans", DATA_TYPE_UINT32, 2657*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans, 2658*10187SKrishna.Elango@Sun.COM "pcie_sue_tgt_addr", DATA_TYPE_UINT64, 2659*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr, 2660*10187SKrishna.Elango@Sun.COM "pcie_sue_tgt_bdf", DATA_TYPE_UINT16, 2661*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf, 2662*10187SKrishna.Elango@Sun.COM NULL); 2663*10187SKrishna.Elango@Sun.COM /* Clear these values as they no longer valid */ 2664*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = 0; 2665*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = 0; 2666*10187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = 2667*10187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 2668*10187SKrishna.Elango@Sun.COM } 2669*10187SKrishna.Elango@Sun.COM 2670*10187SKrishna.Elango@Sun.COM /* PCIe RP registers */ 2671*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 2672*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2673*10187SKrishna.Elango@Sun.COM "pcie_rp_status", DATA_TYPE_UINT32, 2674*10187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p)->pcie_rp_status, 2675*10187SKrishna.Elango@Sun.COM "pcie_rp_control", DATA_TYPE_UINT16, 2676*10187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p)->pcie_rp_ctl, 2677*10187SKrishna.Elango@Sun.COM NULL); 2678*10187SKrishna.Elango@Sun.COM } 2679*10187SKrishna.Elango@Sun.COM 2680*10187SKrishna.Elango@Sun.COM /* PCIe RP AER registers */ 2681*10187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p)) { 2682*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2683*10187SKrishna.Elango@Sun.COM "pcie_adv_rp_status", DATA_TYPE_UINT32, 2684*10187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_err_status, 2685*10187SKrishna.Elango@Sun.COM "pcie_adv_rp_command", DATA_TYPE_UINT32, 2686*10187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_err_cmd, 2687*10187SKrishna.Elango@Sun.COM "pcie_adv_rp_ce_src_id", DATA_TYPE_UINT16, 2688*10187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id, 2689*10187SKrishna.Elango@Sun.COM "pcie_adv_rp_ue_src_id", DATA_TYPE_UINT16, 2690*10187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id, 2691*10187SKrishna.Elango@Sun.COM NULL); 2692*10187SKrishna.Elango@Sun.COM } 2693*10187SKrishna.Elango@Sun.COM 2694*10187SKrishna.Elango@Sun.COM /* Misc ereport information */ 2695*10187SKrishna.Elango@Sun.COM fm_payload_set(ereport, 2696*10187SKrishna.Elango@Sun.COM "remainder", DATA_TYPE_UINT32, total--, 2697*10187SKrishna.Elango@Sun.COM "severity", DATA_TYPE_UINT32, pfd_p->pe_severity_flags, 2698*10187SKrishna.Elango@Sun.COM NULL); 2699*10187SKrishna.Elango@Sun.COM 2700*10187SKrishna.Elango@Sun.COM pf_ereport_post(PCIE_BUS2DIP(bus_p), &ereport, &detector, 2701*10187SKrishna.Elango@Sun.COM &eqep); 2702*10187SKrishna.Elango@Sun.COM } 2703*10187SKrishna.Elango@Sun.COM 2704*10187SKrishna.Elango@Sun.COM /* Unlock all the devices in the queue */ 2705*10187SKrishna.Elango@Sun.COM for (pfd_p = impl->pf_dq_tail_p; pfd_p; pfd_p = pfd_p->pe_prev) { 2706*10187SKrishna.Elango@Sun.COM if (pfd_p->pe_lock) { 2707*10187SKrishna.Elango@Sun.COM pf_handler_exit(PCIE_PFD2DIP(pfd_p)); 2708*10187SKrishna.Elango@Sun.COM } 2709*10187SKrishna.Elango@Sun.COM } 2710*10187SKrishna.Elango@Sun.COM } 2711*10187SKrishna.Elango@Sun.COM 2712*10187SKrishna.Elango@Sun.COM /* 2713*10187SKrishna.Elango@Sun.COM * pf_handler_enter must be called to serial access to each device's pf_data_t. 2714*10187SKrishna.Elango@Sun.COM * Once error handling is finished with the device call pf_handler_exit to allow 2715*10187SKrishna.Elango@Sun.COM * other threads to access it. The same thread may call pf_handler_enter 2716*10187SKrishna.Elango@Sun.COM * several times without any consequences. 2717*10187SKrishna.Elango@Sun.COM * 2718*10187SKrishna.Elango@Sun.COM * The "impl" variable is passed in during scan fabric to double check that 2719*10187SKrishna.Elango@Sun.COM * there is not a recursive algorithm and to ensure only one thread is doing a 2720*10187SKrishna.Elango@Sun.COM * fabric scan at all times. 2721*10187SKrishna.Elango@Sun.COM * 2722*10187SKrishna.Elango@Sun.COM * In some cases "impl" is not available, such as "child lookup" being called 2723*10187SKrishna.Elango@Sun.COM * from outside of scan fabric, just pass in NULL for this variable and this 2724*10187SKrishna.Elango@Sun.COM * extra check will be skipped. 2725*10187SKrishna.Elango@Sun.COM */ 2726*10187SKrishna.Elango@Sun.COM static int 2727*10187SKrishna.Elango@Sun.COM pf_handler_enter(dev_info_t *dip, pf_impl_t *impl) 2728*10187SKrishna.Elango@Sun.COM { 2729*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip); 2730*10187SKrishna.Elango@Sun.COM 2731*10187SKrishna.Elango@Sun.COM ASSERT(pfd_p); 2732*10187SKrishna.Elango@Sun.COM 2733*10187SKrishna.Elango@Sun.COM /* 2734*10187SKrishna.Elango@Sun.COM * Check to see if the lock has already been taken by this 2735*10187SKrishna.Elango@Sun.COM * thread. If so just return and don't take lock again. 2736*10187SKrishna.Elango@Sun.COM */ 2737*10187SKrishna.Elango@Sun.COM if (!pfd_p->pe_lock || !impl) { 2738*10187SKrishna.Elango@Sun.COM i_ddi_fm_handler_enter(dip); 2739*10187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_TRUE; 2740*10187SKrishna.Elango@Sun.COM return (PF_SCAN_SUCCESS); 2741*10187SKrishna.Elango@Sun.COM } 2742*10187SKrishna.Elango@Sun.COM 2743*10187SKrishna.Elango@Sun.COM /* Check to see that this dip is already in the "impl" error queue */ 2744*10187SKrishna.Elango@Sun.COM for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) { 2745*10187SKrishna.Elango@Sun.COM if (PCIE_PFD2DIP(pfd_p) == dip) { 2746*10187SKrishna.Elango@Sun.COM return (PF_SCAN_SUCCESS); 2747*10187SKrishna.Elango@Sun.COM } 2748*10187SKrishna.Elango@Sun.COM } 2749*10187SKrishna.Elango@Sun.COM 2750*10187SKrishna.Elango@Sun.COM return (PF_SCAN_DEADLOCK); 2751*10187SKrishna.Elango@Sun.COM } 2752*10187SKrishna.Elango@Sun.COM 2753*10187SKrishna.Elango@Sun.COM static void 2754*10187SKrishna.Elango@Sun.COM pf_handler_exit(dev_info_t *dip) 2755*10187SKrishna.Elango@Sun.COM { 2756*10187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip); 2757*10187SKrishna.Elango@Sun.COM 2758*10187SKrishna.Elango@Sun.COM ASSERT(pfd_p); 2759*10187SKrishna.Elango@Sun.COM 2760*10187SKrishna.Elango@Sun.COM ASSERT(pfd_p->pe_lock == B_TRUE); 2761*10187SKrishna.Elango@Sun.COM i_ddi_fm_handler_exit(dip); 2762*10187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE; 2763*10187SKrishna.Elango@Sun.COM } 2764*10187SKrishna.Elango@Sun.COM 2765*10187SKrishna.Elango@Sun.COM /* 2766*10187SKrishna.Elango@Sun.COM * This function calls the driver's callback function (if it's FMA hardened 2767*10187SKrishna.Elango@Sun.COM * and callback capable). This function relies on the current thread already 2768*10187SKrishna.Elango@Sun.COM * owning the driver's fmhdl lock. 2769*10187SKrishna.Elango@Sun.COM */ 2770*10187SKrishna.Elango@Sun.COM static int 2771*10187SKrishna.Elango@Sun.COM pf_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr) 2772*10187SKrishna.Elango@Sun.COM { 2773*10187SKrishna.Elango@Sun.COM int cb_sts = DDI_FM_OK; 2774*10187SKrishna.Elango@Sun.COM 2775*10187SKrishna.Elango@Sun.COM if (DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 2776*10187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(dip); 2777*10187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *hdl = DEVI(pdip)->devi_fmhdl; 2778*10187SKrishna.Elango@Sun.COM struct i_ddi_fmtgt *tgt = hdl->fh_tgts; 2779*10187SKrishna.Elango@Sun.COM struct i_ddi_errhdl *errhdl; 2780*10187SKrishna.Elango@Sun.COM while (tgt != NULL) { 2781*10187SKrishna.Elango@Sun.COM if (dip == tgt->ft_dip) { 2782*10187SKrishna.Elango@Sun.COM errhdl = tgt->ft_errhdl; 2783*10187SKrishna.Elango@Sun.COM cb_sts = errhdl->eh_func(dip, derr, 2784*10187SKrishna.Elango@Sun.COM errhdl->eh_impl); 2785*10187SKrishna.Elango@Sun.COM break; 2786*10187SKrishna.Elango@Sun.COM } 2787*10187SKrishna.Elango@Sun.COM tgt = tgt->ft_next; 2788*10187SKrishna.Elango@Sun.COM } 2789*10187SKrishna.Elango@Sun.COM } 2790*10187SKrishna.Elango@Sun.COM return (cb_sts); 2791*10187SKrishna.Elango@Sun.COM } 2792