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