110187SKrishna.Elango@Sun.COM /*
210187SKrishna.Elango@Sun.COM * CDDL HEADER START
310187SKrishna.Elango@Sun.COM *
410187SKrishna.Elango@Sun.COM * The contents of this file are subject to the terms of the
510187SKrishna.Elango@Sun.COM * Common Development and Distribution License (the "License").
610187SKrishna.Elango@Sun.COM * You may not use this file except in compliance with the License.
710187SKrishna.Elango@Sun.COM *
810187SKrishna.Elango@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910187SKrishna.Elango@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010187SKrishna.Elango@Sun.COM * See the License for the specific language governing permissions
1110187SKrishna.Elango@Sun.COM * and limitations under the License.
1210187SKrishna.Elango@Sun.COM *
1310187SKrishna.Elango@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410187SKrishna.Elango@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510187SKrishna.Elango@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610187SKrishna.Elango@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710187SKrishna.Elango@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810187SKrishna.Elango@Sun.COM *
1910187SKrishna.Elango@Sun.COM * CDDL HEADER END
2010187SKrishna.Elango@Sun.COM */
2110187SKrishna.Elango@Sun.COM /*
2212213SGavin.Maltby@Sun.COM * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2310187SKrishna.Elango@Sun.COM */
2410187SKrishna.Elango@Sun.COM
2510187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h>
2610187SKrishna.Elango@Sun.COM #include <sys/types.h>
2710187SKrishna.Elango@Sun.COM #include <sys/kmem.h>
2810187SKrishna.Elango@Sun.COM #include <sys/modctl.h>
2910187SKrishna.Elango@Sun.COM #include <sys/ddi.h>
3010187SKrishna.Elango@Sun.COM #include <sys/sunddi.h>
3110187SKrishna.Elango@Sun.COM #include <sys/sunndi.h>
3210187SKrishna.Elango@Sun.COM #include <sys/fm/protocol.h>
3310187SKrishna.Elango@Sun.COM #include <sys/fm/util.h>
3410187SKrishna.Elango@Sun.COM #include <sys/fm/io/ddi.h>
3510187SKrishna.Elango@Sun.COM #include <sys/fm/io/pci.h>
3610187SKrishna.Elango@Sun.COM #include <sys/promif.h>
3710187SKrishna.Elango@Sun.COM #include <sys/disp.h>
3810187SKrishna.Elango@Sun.COM #include <sys/atomic.h>
3910187SKrishna.Elango@Sun.COM #include <sys/pcie.h>
4010187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h>
4110187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h>
4210187SKrishna.Elango@Sun.COM
4310187SKrishna.Elango@Sun.COM #define PF_PCIE_BDG_ERR (PCIE_DEVSTS_FE_DETECTED | PCIE_DEVSTS_NFE_DETECTED | \
4410187SKrishna.Elango@Sun.COM PCIE_DEVSTS_CE_DETECTED)
4510187SKrishna.Elango@Sun.COM
4610187SKrishna.Elango@Sun.COM #define PF_PCI_BDG_ERR (PCI_STAT_S_SYSERR | PCI_STAT_S_TARG_AB | \
4710187SKrishna.Elango@Sun.COM PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB | PCI_STAT_S_PERROR)
4810187SKrishna.Elango@Sun.COM
4910187SKrishna.Elango@Sun.COM #define PF_AER_FATAL_ERR (PCIE_AER_UCE_DLP | PCIE_AER_UCE_SD |\
5010187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP)
5110187SKrishna.Elango@Sun.COM #define PF_AER_NON_FATAL_ERR (PCIE_AER_UCE_PTLP | PCIE_AER_UCE_TO | \
5210187SKrishna.Elango@Sun.COM PCIE_AER_UCE_CA | PCIE_AER_UCE_ECRC | PCIE_AER_UCE_UR)
5310187SKrishna.Elango@Sun.COM
5410187SKrishna.Elango@Sun.COM #define PF_SAER_FATAL_ERR (PCIE_AER_SUCE_USC_MSG_DATA_ERR | \
5510187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_ATTR_ERR | PCIE_AER_SUCE_UC_ADDR_ERR | \
5610187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_SERR_ASSERT)
5710187SKrishna.Elango@Sun.COM #define PF_SAER_NON_FATAL_ERR (PCIE_AER_SUCE_TA_ON_SC | \
5810187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MA_ON_SC | PCIE_AER_SUCE_RCVD_TA | \
5910187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_RCVD_MA | PCIE_AER_SUCE_USC_ERR | \
6010187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_DATA_ERR | PCIE_AER_SUCE_TIMER_EXPIRED | \
6110187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_PERR_ASSERT | PCIE_AER_SUCE_INTERNAL_ERR)
6210187SKrishna.Elango@Sun.COM
6310187SKrishna.Elango@Sun.COM #define PF_PCI_PARITY_ERR (PCI_STAT_S_PERROR | PCI_STAT_PERROR)
6410187SKrishna.Elango@Sun.COM
6510187SKrishna.Elango@Sun.COM #define PF_FIRST_AER_ERR(bit, adv) \
6610187SKrishna.Elango@Sun.COM (bit & (1 << (adv->pcie_adv_ctl & PCIE_AER_CTL_FST_ERR_PTR_MASK)))
6710187SKrishna.Elango@Sun.COM
6810187SKrishna.Elango@Sun.COM #define HAS_AER_LOGS(pfd_p, bit) \
6910187SKrishna.Elango@Sun.COM (PCIE_HAS_AER(pfd_p->pe_bus_p) && \
7010187SKrishna.Elango@Sun.COM PF_FIRST_AER_ERR(bit, PCIE_ADV_REG(pfd_p)))
7110187SKrishna.Elango@Sun.COM
7210187SKrishna.Elango@Sun.COM #define PF_FIRST_SAER_ERR(bit, adv) \
7310187SKrishna.Elango@Sun.COM (bit & (1 << (adv->pcie_sue_ctl & PCIE_AER_SCTL_FST_ERR_PTR_MASK)))
7410187SKrishna.Elango@Sun.COM
7510187SKrishna.Elango@Sun.COM #define HAS_SAER_LOGS(pfd_p, bit) \
7610187SKrishna.Elango@Sun.COM (PCIE_HAS_AER(pfd_p->pe_bus_p) && \
7710187SKrishna.Elango@Sun.COM PF_FIRST_SAER_ERR(bit, PCIE_ADV_BDG_REG(pfd_p)))
7810187SKrishna.Elango@Sun.COM
7910187SKrishna.Elango@Sun.COM #define GET_SAER_CMD(pfd_p) \
8010187SKrishna.Elango@Sun.COM ((PCIE_ADV_BDG_HDR(pfd_p, 1) >> \
8110187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK)
8210187SKrishna.Elango@Sun.COM
8310187SKrishna.Elango@Sun.COM #define CE_ADVISORY(pfd_p) \
8410187SKrishna.Elango@Sun.COM (PCIE_ADV_REG(pfd_p)->pcie_ce_status & PCIE_AER_CE_AD_NFE)
8510187SKrishna.Elango@Sun.COM
8610187SKrishna.Elango@Sun.COM /* PCIe Fault Fabric Error analysis table */
8710187SKrishna.Elango@Sun.COM typedef struct pf_fab_err_tbl {
8810187SKrishna.Elango@Sun.COM uint32_t bit; /* Error bit */
8910187SKrishna.Elango@Sun.COM int (*handler)(); /* Error handling fuction */
9011596SJason.Beloro@Sun.COM uint16_t affected_flags; /* Primary affected flag */
9111596SJason.Beloro@Sun.COM /*
9211596SJason.Beloro@Sun.COM * Secondary affected flag, effective when the information
9311596SJason.Beloro@Sun.COM * indicated by the primary flag is not available, eg.
9411596SJason.Beloro@Sun.COM * PF_AFFECTED_AER/SAER/ADDR
9511596SJason.Beloro@Sun.COM */
9611596SJason.Beloro@Sun.COM uint16_t sec_affected_flags;
9710187SKrishna.Elango@Sun.COM } pf_fab_err_tbl_t;
9810187SKrishna.Elango@Sun.COM
9910187SKrishna.Elango@Sun.COM static pcie_bus_t *pf_is_ready(dev_info_t *);
10010187SKrishna.Elango@Sun.COM /* Functions for scanning errors */
10110187SKrishna.Elango@Sun.COM static int pf_default_hdl(dev_info_t *, pf_impl_t *);
10210187SKrishna.Elango@Sun.COM static int pf_dispatch(dev_info_t *, pf_impl_t *, boolean_t);
10310187SKrishna.Elango@Sun.COM static boolean_t pf_in_addr_range(pcie_bus_t *, uint64_t);
10410187SKrishna.Elango@Sun.COM
10510187SKrishna.Elango@Sun.COM /* Functions for gathering errors */
10610187SKrishna.Elango@Sun.COM static void pf_pcix_ecc_regs_gather(pf_pcix_ecc_regs_t *pcix_ecc_regs,
10710187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p, boolean_t bdg);
10810187SKrishna.Elango@Sun.COM static void pf_pcix_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p);
10910187SKrishna.Elango@Sun.COM static void pf_pcie_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p);
11010187SKrishna.Elango@Sun.COM static void pf_pci_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p);
11110187SKrishna.Elango@Sun.COM static int pf_dummy_cb(dev_info_t *, ddi_fm_error_t *, const void *);
11210187SKrishna.Elango@Sun.COM static void pf_en_dq(pf_data_t *pfd_p, pf_impl_t *impl_p);
11310187SKrishna.Elango@Sun.COM
11410187SKrishna.Elango@Sun.COM /* Functions for analysing errors */
11510187SKrishna.Elango@Sun.COM static int pf_analyse_error(ddi_fm_error_t *, pf_impl_t *);
11610187SKrishna.Elango@Sun.COM static void pf_adjust_for_no_aer(pf_data_t *);
11710187SKrishna.Elango@Sun.COM static void pf_adjust_for_no_saer(pf_data_t *);
11810187SKrishna.Elango@Sun.COM static pf_data_t *pf_get_pcie_bridge(pf_data_t *, pcie_req_id_t);
11910187SKrishna.Elango@Sun.COM static pf_data_t *pf_get_parent_pcie_bridge(pf_data_t *);
12010187SKrishna.Elango@Sun.COM static boolean_t pf_matched_in_rc(pf_data_t *, pf_data_t *,
12110187SKrishna.Elango@Sun.COM uint32_t);
12210187SKrishna.Elango@Sun.COM static int pf_analyse_error_tbl(ddi_fm_error_t *, pf_impl_t *,
12310187SKrishna.Elango@Sun.COM pf_data_t *, const pf_fab_err_tbl_t *, uint32_t);
12410187SKrishna.Elango@Sun.COM static int pf_analyse_ca_ur(ddi_fm_error_t *, uint32_t,
12510187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
12610187SKrishna.Elango@Sun.COM static int pf_analyse_ma_ta(ddi_fm_error_t *, uint32_t,
12710187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
12810187SKrishna.Elango@Sun.COM static int pf_analyse_pci(ddi_fm_error_t *, uint32_t,
12910187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
13010187SKrishna.Elango@Sun.COM static int pf_analyse_perr_assert(ddi_fm_error_t *, uint32_t,
13110187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
13210187SKrishna.Elango@Sun.COM static int pf_analyse_ptlp(ddi_fm_error_t *, uint32_t,
13310187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
13410187SKrishna.Elango@Sun.COM static int pf_analyse_sc(ddi_fm_error_t *, uint32_t,
13510187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
13610187SKrishna.Elango@Sun.COM static int pf_analyse_to(ddi_fm_error_t *, uint32_t,
13710187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
13810187SKrishna.Elango@Sun.COM static int pf_analyse_uc(ddi_fm_error_t *, uint32_t,
13910187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
14010187SKrishna.Elango@Sun.COM static int pf_analyse_uc_data(ddi_fm_error_t *, uint32_t,
14110187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
14210187SKrishna.Elango@Sun.COM static int pf_no_panic(ddi_fm_error_t *, uint32_t,
14310187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
14410187SKrishna.Elango@Sun.COM static int pf_panic(ddi_fm_error_t *, uint32_t,
14510187SKrishna.Elango@Sun.COM pf_data_t *, pf_data_t *);
14610187SKrishna.Elango@Sun.COM static void pf_send_ereport(ddi_fm_error_t *, pf_impl_t *);
14710187SKrishna.Elango@Sun.COM static int pf_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr);
14810187SKrishna.Elango@Sun.COM
14910187SKrishna.Elango@Sun.COM /* PCIe Fabric Handle Lookup Support Functions. */
15010187SKrishna.Elango@Sun.COM static int pf_hdl_child_lookup(dev_info_t *, ddi_fm_error_t *, uint32_t,
15110187SKrishna.Elango@Sun.COM uint64_t, pcie_req_id_t);
15210187SKrishna.Elango@Sun.COM static int pf_hdl_compare(dev_info_t *, ddi_fm_error_t *, uint32_t, uint64_t,
15310187SKrishna.Elango@Sun.COM pcie_req_id_t, ndi_fmc_t *);
15410187SKrishna.Elango@Sun.COM static int pf_log_hdl_lookup(dev_info_t *, ddi_fm_error_t *, pf_data_t *,
15510187SKrishna.Elango@Sun.COM boolean_t);
15610187SKrishna.Elango@Sun.COM
15710187SKrishna.Elango@Sun.COM static int pf_handler_enter(dev_info_t *, pf_impl_t *);
15810187SKrishna.Elango@Sun.COM static void pf_handler_exit(dev_info_t *);
15911596SJason.Beloro@Sun.COM static void pf_reset_pfd(pf_data_t *);
16010187SKrishna.Elango@Sun.COM
16110187SKrishna.Elango@Sun.COM boolean_t pcie_full_scan = B_FALSE; /* Force to always do a full scan */
16210187SKrishna.Elango@Sun.COM int pcie_disable_scan = 0; /* Disable fabric scan */
16310187SKrishna.Elango@Sun.COM
16411596SJason.Beloro@Sun.COM /* Inform interested parties that error handling is about to begin. */
16511596SJason.Beloro@Sun.COM /* ARGSUSED */
16611596SJason.Beloro@Sun.COM void
pf_eh_enter(pcie_bus_t * bus_p)16711596SJason.Beloro@Sun.COM pf_eh_enter(pcie_bus_t *bus_p) {
16811596SJason.Beloro@Sun.COM }
16911596SJason.Beloro@Sun.COM
17011596SJason.Beloro@Sun.COM /* Inform interested parties that error handling has ended. */
17111596SJason.Beloro@Sun.COM void
pf_eh_exit(pcie_bus_t * bus_p)17211596SJason.Beloro@Sun.COM pf_eh_exit(pcie_bus_t *bus_p)
17311596SJason.Beloro@Sun.COM {
17411596SJason.Beloro@Sun.COM pcie_bus_t *rbus_p = PCIE_DIP2BUS(bus_p->bus_rp_dip);
17511596SJason.Beloro@Sun.COM pf_data_t *root_pfd_p = PCIE_BUS2PFD(rbus_p);
17611596SJason.Beloro@Sun.COM pf_data_t *pfd_p;
17711596SJason.Beloro@Sun.COM uint_t intr_type = PCIE_ROOT_EH_SRC(root_pfd_p)->intr_type;
17811596SJason.Beloro@Sun.COM
17911596SJason.Beloro@Sun.COM pciev_eh_exit(root_pfd_p, intr_type);
18011596SJason.Beloro@Sun.COM
18111596SJason.Beloro@Sun.COM /* Clear affected device info and INTR SRC */
18211596SJason.Beloro@Sun.COM for (pfd_p = root_pfd_p; pfd_p; pfd_p = pfd_p->pe_next) {
18311596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = 0;
18411596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
18511596SJason.Beloro@Sun.COM if (PCIE_IS_ROOT(PCIE_PFD2BUS(pfd_p))) {
18611596SJason.Beloro@Sun.COM PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_NONE;
18711596SJason.Beloro@Sun.COM PCIE_ROOT_EH_SRC(pfd_p)->intr_data = NULL;
18811596SJason.Beloro@Sun.COM }
18911596SJason.Beloro@Sun.COM }
19011596SJason.Beloro@Sun.COM }
19111596SJason.Beloro@Sun.COM
19210187SKrishna.Elango@Sun.COM /*
19310187SKrishna.Elango@Sun.COM * Scan Fabric is the entry point for PCI/PCIe IO fabric errors. The
19410187SKrishna.Elango@Sun.COM * caller may create a local pf_data_t with the "root fault"
19510187SKrishna.Elango@Sun.COM * information populated to either do a precise or full scan. More
19610187SKrishna.Elango@Sun.COM * than one pf_data_t maybe linked together if there are multiple
19710187SKrishna.Elango@Sun.COM * errors. Only a PCIe compliant Root Port device may pass in NULL
19810187SKrishna.Elango@Sun.COM * for the root_pfd_p.
19910187SKrishna.Elango@Sun.COM *
20010187SKrishna.Elango@Sun.COM * "Root Complexes" such as NPE and PX should call scan_fabric using itself as
20110187SKrishna.Elango@Sun.COM * the rdip. PCIe Root ports should call pf_scan_fabric using it's parent as
20210187SKrishna.Elango@Sun.COM * the rdip.
20310187SKrishna.Elango@Sun.COM *
20410187SKrishna.Elango@Sun.COM * Scan fabric initiated from RCs are likely due to a fabric message, traps or
20510187SKrishna.Elango@Sun.COM * any RC detected errors that propagated to/from the fabric.
20610187SKrishna.Elango@Sun.COM *
20710187SKrishna.Elango@Sun.COM * This code assumes that by the time pf_scan_fabric is
20810187SKrishna.Elango@Sun.COM * called, pf_handler_enter has NOT been called on the rdip.
20910187SKrishna.Elango@Sun.COM */
21010187SKrishna.Elango@Sun.COM int
pf_scan_fabric(dev_info_t * rdip,ddi_fm_error_t * derr,pf_data_t * root_pfd_p)21110187SKrishna.Elango@Sun.COM pf_scan_fabric(dev_info_t *rdip, ddi_fm_error_t *derr, pf_data_t *root_pfd_p)
21210187SKrishna.Elango@Sun.COM {
21310187SKrishna.Elango@Sun.COM pf_impl_t impl;
21410187SKrishna.Elango@Sun.COM pf_data_t *pfd_p, *pfd_head_p, *pfd_tail_p;
21510187SKrishna.Elango@Sun.COM int scan_flag = PF_SCAN_SUCCESS;
21610187SKrishna.Elango@Sun.COM int analyse_flag = PF_ERR_NO_ERROR;
21710187SKrishna.Elango@Sun.COM boolean_t full_scan = pcie_full_scan;
21810187SKrishna.Elango@Sun.COM
21910187SKrishna.Elango@Sun.COM if (pcie_disable_scan)
22010187SKrishna.Elango@Sun.COM return (analyse_flag);
22110187SKrishna.Elango@Sun.COM
22210187SKrishna.Elango@Sun.COM /* Find the head and tail of this link list */
22310187SKrishna.Elango@Sun.COM pfd_head_p = root_pfd_p;
22410187SKrishna.Elango@Sun.COM for (pfd_tail_p = root_pfd_p; pfd_tail_p && pfd_tail_p->pe_next;
22510187SKrishna.Elango@Sun.COM pfd_tail_p = pfd_tail_p->pe_next)
22610187SKrishna.Elango@Sun.COM ;
22710187SKrishna.Elango@Sun.COM
22810187SKrishna.Elango@Sun.COM /* Save head/tail */
22910187SKrishna.Elango@Sun.COM impl.pf_total = 0;
23010187SKrishna.Elango@Sun.COM impl.pf_derr = derr;
23110187SKrishna.Elango@Sun.COM impl.pf_dq_head_p = pfd_head_p;
23210187SKrishna.Elango@Sun.COM impl.pf_dq_tail_p = pfd_tail_p;
23310187SKrishna.Elango@Sun.COM
23410187SKrishna.Elango@Sun.COM /* If scan is initiated from RP then RP itself must be scanned. */
23510187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(PCIE_DIP2BUS(rdip)) && pf_is_ready(rdip) &&
23610187SKrishna.Elango@Sun.COM !root_pfd_p) {
23710187SKrishna.Elango@Sun.COM scan_flag = pf_handler_enter(rdip, &impl);
23810187SKrishna.Elango@Sun.COM if (scan_flag & PF_SCAN_DEADLOCK)
23910187SKrishna.Elango@Sun.COM goto done;
24010187SKrishna.Elango@Sun.COM
24110187SKrishna.Elango@Sun.COM scan_flag = pf_default_hdl(rdip, &impl);
24210187SKrishna.Elango@Sun.COM if (scan_flag & PF_SCAN_NO_ERR_IN_CHILD)
24310187SKrishna.Elango@Sun.COM goto done;
24410187SKrishna.Elango@Sun.COM }
24510187SKrishna.Elango@Sun.COM
24610187SKrishna.Elango@Sun.COM /*
24710187SKrishna.Elango@Sun.COM * Scan the fabric using the scan_bdf and scan_addr in error q.
24810187SKrishna.Elango@Sun.COM * scan_bdf will be valid in the following cases:
24910187SKrishna.Elango@Sun.COM * - Fabric message
25010187SKrishna.Elango@Sun.COM * - Poisoned TLP
25110187SKrishna.Elango@Sun.COM * - Signaled UR/CA
25210187SKrishna.Elango@Sun.COM * - Received UR/CA
25310187SKrishna.Elango@Sun.COM * - PIO load failures
25410187SKrishna.Elango@Sun.COM */
25510187SKrishna.Elango@Sun.COM for (pfd_p = impl.pf_dq_head_p; pfd_p && PFD_IS_ROOT(pfd_p);
25610187SKrishna.Elango@Sun.COM pfd_p = pfd_p->pe_next) {
25710187SKrishna.Elango@Sun.COM impl.pf_fault = PCIE_ROOT_FAULT(pfd_p);
25810187SKrishna.Elango@Sun.COM
25911654SKrishna.Elango@Sun.COM if (PFD_IS_RC(pfd_p))
26011654SKrishna.Elango@Sun.COM impl.pf_total++;
26111654SKrishna.Elango@Sun.COM
26210187SKrishna.Elango@Sun.COM if (impl.pf_fault->full_scan)
26310187SKrishna.Elango@Sun.COM full_scan = B_TRUE;
26410187SKrishna.Elango@Sun.COM
26510187SKrishna.Elango@Sun.COM if (full_scan ||
26610187SKrishna.Elango@Sun.COM PCIE_CHECK_VALID_BDF(impl.pf_fault->scan_bdf) ||
26710187SKrishna.Elango@Sun.COM impl.pf_fault->scan_addr)
26810187SKrishna.Elango@Sun.COM scan_flag |= pf_dispatch(rdip, &impl, full_scan);
26910187SKrishna.Elango@Sun.COM
27010187SKrishna.Elango@Sun.COM if (full_scan)
27110187SKrishna.Elango@Sun.COM break;
27210187SKrishna.Elango@Sun.COM }
27310187SKrishna.Elango@Sun.COM
27410187SKrishna.Elango@Sun.COM done:
27510187SKrishna.Elango@Sun.COM /*
27610187SKrishna.Elango@Sun.COM * If this is due to safe access, don't analyze the errors and return
27710187SKrishna.Elango@Sun.COM * success regardless of how scan fabric went.
27810187SKrishna.Elango@Sun.COM */
27910187SKrishna.Elango@Sun.COM if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) {
28010187SKrishna.Elango@Sun.COM analyse_flag = PF_ERR_NO_PANIC;
28110187SKrishna.Elango@Sun.COM } else {
28210187SKrishna.Elango@Sun.COM analyse_flag = pf_analyse_error(derr, &impl);
28310187SKrishna.Elango@Sun.COM }
28410187SKrishna.Elango@Sun.COM
28510187SKrishna.Elango@Sun.COM pf_send_ereport(derr, &impl);
28610187SKrishna.Elango@Sun.COM
28710187SKrishna.Elango@Sun.COM /*
28811596SJason.Beloro@Sun.COM * Check if any hardened driver's callback reported a panic.
28911596SJason.Beloro@Sun.COM * If so panic.
29010187SKrishna.Elango@Sun.COM */
29111596SJason.Beloro@Sun.COM if (scan_flag & PF_SCAN_CB_FAILURE)
29210187SKrishna.Elango@Sun.COM analyse_flag |= PF_ERR_PANIC;
29310187SKrishna.Elango@Sun.COM
29410187SKrishna.Elango@Sun.COM /*
29510187SKrishna.Elango@Sun.COM * If a deadlock was detected, panic the system as error analysis has
29610187SKrishna.Elango@Sun.COM * been compromised.
29710187SKrishna.Elango@Sun.COM */
29810187SKrishna.Elango@Sun.COM if (scan_flag & PF_SCAN_DEADLOCK)
29910187SKrishna.Elango@Sun.COM analyse_flag |= PF_ERR_PANIC_DEADLOCK;
30010187SKrishna.Elango@Sun.COM
30110187SKrishna.Elango@Sun.COM derr->fme_status = PF_ERR2DDIFM_ERR(scan_flag);
30210187SKrishna.Elango@Sun.COM
30310187SKrishna.Elango@Sun.COM return (analyse_flag);
30410187SKrishna.Elango@Sun.COM }
30510187SKrishna.Elango@Sun.COM
30611040SPavel.Potoplyak@Sun.COM void
pcie_force_fullscan()30711040SPavel.Potoplyak@Sun.COM pcie_force_fullscan() {
30811040SPavel.Potoplyak@Sun.COM pcie_full_scan = B_TRUE;
30911040SPavel.Potoplyak@Sun.COM }
31011040SPavel.Potoplyak@Sun.COM
31110187SKrishna.Elango@Sun.COM /*
31210187SKrishna.Elango@Sun.COM * pf_dispatch walks the device tree and calls the pf_default_hdl if the device
31310187SKrishna.Elango@Sun.COM * falls in the error path.
31410187SKrishna.Elango@Sun.COM *
31510187SKrishna.Elango@Sun.COM * Returns PF_SCAN_* flags
31610187SKrishna.Elango@Sun.COM */
31710187SKrishna.Elango@Sun.COM static int
pf_dispatch(dev_info_t * pdip,pf_impl_t * impl,boolean_t full_scan)31810187SKrishna.Elango@Sun.COM pf_dispatch(dev_info_t *pdip, pf_impl_t *impl, boolean_t full_scan)
31910187SKrishna.Elango@Sun.COM {
32010187SKrishna.Elango@Sun.COM dev_info_t *dip;
32110187SKrishna.Elango@Sun.COM pcie_req_id_t rid = impl->pf_fault->scan_bdf;
32210187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p;
32310187SKrishna.Elango@Sun.COM int scan_flag = PF_SCAN_SUCCESS;
32410187SKrishna.Elango@Sun.COM
32510187SKrishna.Elango@Sun.COM for (dip = ddi_get_child(pdip); dip; dip = ddi_get_next_sibling(dip)) {
32610187SKrishna.Elango@Sun.COM /* Make sure dip is attached and ready */
32710187SKrishna.Elango@Sun.COM if (!(bus_p = pf_is_ready(dip)))
32810187SKrishna.Elango@Sun.COM continue;
32910187SKrishna.Elango@Sun.COM
33010187SKrishna.Elango@Sun.COM scan_flag |= pf_handler_enter(dip, impl);
33110187SKrishna.Elango@Sun.COM if (scan_flag & PF_SCAN_DEADLOCK)
33210187SKrishna.Elango@Sun.COM break;
33310187SKrishna.Elango@Sun.COM
33410187SKrishna.Elango@Sun.COM /*
33510187SKrishna.Elango@Sun.COM * Handle this device if it is a:
33610187SKrishna.Elango@Sun.COM * o Full Scan
33710187SKrishna.Elango@Sun.COM * o PCI/PCI-X Device
33810187SKrishna.Elango@Sun.COM * o Fault BDF = Device BDF
33910187SKrishna.Elango@Sun.COM * o BDF/ADDR is in range of the Bridge/Switch
34010187SKrishna.Elango@Sun.COM */
34110187SKrishna.Elango@Sun.COM if (full_scan ||
34210187SKrishna.Elango@Sun.COM (bus_p->bus_bdf == rid) ||
34310187SKrishna.Elango@Sun.COM pf_in_bus_range(bus_p, rid) ||
34410187SKrishna.Elango@Sun.COM pf_in_addr_range(bus_p, impl->pf_fault->scan_addr)) {
34510187SKrishna.Elango@Sun.COM int hdl_flag = pf_default_hdl(dip, impl);
34610187SKrishna.Elango@Sun.COM scan_flag |= hdl_flag;
34710187SKrishna.Elango@Sun.COM
34810187SKrishna.Elango@Sun.COM /*
34910187SKrishna.Elango@Sun.COM * A bridge may have detected no errors in which case
35010187SKrishna.Elango@Sun.COM * there is no need to scan further down.
35110187SKrishna.Elango@Sun.COM */
35210187SKrishna.Elango@Sun.COM if (hdl_flag & PF_SCAN_NO_ERR_IN_CHILD)
35310187SKrishna.Elango@Sun.COM continue;
35410187SKrishna.Elango@Sun.COM } else {
35510187SKrishna.Elango@Sun.COM pf_handler_exit(dip);
35610187SKrishna.Elango@Sun.COM continue;
35710187SKrishna.Elango@Sun.COM }
35810187SKrishna.Elango@Sun.COM
35910187SKrishna.Elango@Sun.COM /* match or in bridge bus-range */
36010187SKrishna.Elango@Sun.COM switch (bus_p->bus_dev_type) {
36110187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
36210187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE:
36310187SKrishna.Elango@Sun.COM scan_flag |= pf_dispatch(dip, impl, B_TRUE);
36410187SKrishna.Elango@Sun.COM break;
36510187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_UP:
36610187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_DOWN:
36710187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_ROOT:
36810187SKrishna.Elango@Sun.COM {
36910187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_BUS2PFD(bus_p);
37010187SKrishna.Elango@Sun.COM pf_pci_err_regs_t *err_p = PCI_ERR_REG(pfd_p);
37110187SKrishna.Elango@Sun.COM pf_pci_bdg_err_regs_t *serr_p = PCI_BDG_ERR_REG(pfd_p);
37210187SKrishna.Elango@Sun.COM /*
37310187SKrishna.Elango@Sun.COM * Continue if the fault BDF != the switch or there is a
37410187SKrishna.Elango@Sun.COM * parity error
37510187SKrishna.Elango@Sun.COM */
37610187SKrishna.Elango@Sun.COM if ((bus_p->bus_bdf != rid) ||
37710187SKrishna.Elango@Sun.COM (err_p->pci_err_status & PF_PCI_PARITY_ERR) ||
37810187SKrishna.Elango@Sun.COM (serr_p->pci_bdg_sec_stat & PF_PCI_PARITY_ERR))
37910187SKrishna.Elango@Sun.COM scan_flag |= pf_dispatch(dip, impl, full_scan);
38010187SKrishna.Elango@Sun.COM break;
38110187SKrishna.Elango@Sun.COM }
38210187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
38310187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI_DEV:
38410187SKrishna.Elango@Sun.COM /*
38510187SKrishna.Elango@Sun.COM * Reached a PCIe end point so stop. Note dev_type
38610187SKrishna.Elango@Sun.COM * PCI_DEV is just a PCIe device that requires IO Space
38710187SKrishna.Elango@Sun.COM */
38810187SKrishna.Elango@Sun.COM break;
38910187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO:
39010187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p))
39110187SKrishna.Elango@Sun.COM scan_flag |= pf_dispatch(dip, impl, B_TRUE);
39210187SKrishna.Elango@Sun.COM break;
39310187SKrishna.Elango@Sun.COM default:
39410187SKrishna.Elango@Sun.COM ASSERT(B_FALSE);
39510187SKrishna.Elango@Sun.COM }
39610187SKrishna.Elango@Sun.COM }
39710187SKrishna.Elango@Sun.COM return (scan_flag);
39810187SKrishna.Elango@Sun.COM }
39910187SKrishna.Elango@Sun.COM
40010187SKrishna.Elango@Sun.COM /* Returns whether the "bdf" is in the bus range of a switch/bridge */
40111596SJason.Beloro@Sun.COM boolean_t
pf_in_bus_range(pcie_bus_t * bus_p,pcie_req_id_t bdf)40210187SKrishna.Elango@Sun.COM pf_in_bus_range(pcie_bus_t *bus_p, pcie_req_id_t bdf)
40310187SKrishna.Elango@Sun.COM {
40410187SKrishna.Elango@Sun.COM pci_bus_range_t *br_p = &bus_p->bus_bus_range;
40510187SKrishna.Elango@Sun.COM uint8_t bus_no = (bdf & PCIE_REQ_ID_BUS_MASK) >>
40610187SKrishna.Elango@Sun.COM PCIE_REQ_ID_BUS_SHIFT;
40710187SKrishna.Elango@Sun.COM
40810187SKrishna.Elango@Sun.COM /* check if given bdf falls within bridge's bus range */
40910187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p) &&
41010187SKrishna.Elango@Sun.COM ((bus_no >= br_p->lo) && (bus_no <= br_p->hi)))
41110187SKrishna.Elango@Sun.COM return (B_TRUE);
41210187SKrishna.Elango@Sun.COM else
41310187SKrishna.Elango@Sun.COM return (B_FALSE);
41410187SKrishna.Elango@Sun.COM }
41510187SKrishna.Elango@Sun.COM
41610187SKrishna.Elango@Sun.COM /*
41711596SJason.Beloro@Sun.COM * Return whether the "addr" is in the assigned addr of a device.
41811596SJason.Beloro@Sun.COM */
41911596SJason.Beloro@Sun.COM boolean_t
pf_in_assigned_addr(pcie_bus_t * bus_p,uint64_t addr)42011596SJason.Beloro@Sun.COM pf_in_assigned_addr(pcie_bus_t *bus_p, uint64_t addr)
42111596SJason.Beloro@Sun.COM {
42211596SJason.Beloro@Sun.COM uint_t i;
42311596SJason.Beloro@Sun.COM uint64_t low, hi;
42411596SJason.Beloro@Sun.COM pci_regspec_t *assign_p = bus_p->bus_assigned_addr;
42511596SJason.Beloro@Sun.COM
42611596SJason.Beloro@Sun.COM for (i = 0; i < bus_p->bus_assigned_entries; i++, assign_p++) {
42711596SJason.Beloro@Sun.COM low = assign_p->pci_phys_low;
42811596SJason.Beloro@Sun.COM hi = low + assign_p->pci_size_low;
42911596SJason.Beloro@Sun.COM if ((addr < hi) && (addr >= low))
43011596SJason.Beloro@Sun.COM return (B_TRUE);
43111596SJason.Beloro@Sun.COM }
43211596SJason.Beloro@Sun.COM return (B_FALSE);
43311596SJason.Beloro@Sun.COM }
43411596SJason.Beloro@Sun.COM
43511596SJason.Beloro@Sun.COM /*
43610187SKrishna.Elango@Sun.COM * Returns whether the "addr" is in the addr range of a switch/bridge, or if the
43710187SKrishna.Elango@Sun.COM * "addr" is in the assigned addr of a device.
43810187SKrishna.Elango@Sun.COM */
43910187SKrishna.Elango@Sun.COM static boolean_t
pf_in_addr_range(pcie_bus_t * bus_p,uint64_t addr)44010187SKrishna.Elango@Sun.COM pf_in_addr_range(pcie_bus_t *bus_p, uint64_t addr)
44110187SKrishna.Elango@Sun.COM {
44210187SKrishna.Elango@Sun.COM uint_t i;
44310187SKrishna.Elango@Sun.COM uint64_t low, hi;
44410187SKrishna.Elango@Sun.COM ppb_ranges_t *ranges_p = bus_p->bus_addr_ranges;
44510187SKrishna.Elango@Sun.COM
44612076SKrishna.Elango@Sun.COM if (!addr)
44712076SKrishna.Elango@Sun.COM return (B_FALSE);
44812076SKrishna.Elango@Sun.COM
44910187SKrishna.Elango@Sun.COM /* check if given address belongs to this device */
45011596SJason.Beloro@Sun.COM if (pf_in_assigned_addr(bus_p, addr))
45111596SJason.Beloro@Sun.COM return (B_TRUE);
45210187SKrishna.Elango@Sun.COM
45310187SKrishna.Elango@Sun.COM /* check if given address belongs to a child below this device */
45410187SKrishna.Elango@Sun.COM if (!PCIE_IS_BDG(bus_p))
45510187SKrishna.Elango@Sun.COM return (B_FALSE);
45610187SKrishna.Elango@Sun.COM
45710187SKrishna.Elango@Sun.COM for (i = 0; i < bus_p->bus_addr_entries; i++, ranges_p++) {
45810187SKrishna.Elango@Sun.COM switch (ranges_p->child_high & PCI_ADDR_MASK) {
45910187SKrishna.Elango@Sun.COM case PCI_ADDR_IO:
46010187SKrishna.Elango@Sun.COM case PCI_ADDR_MEM32:
46110187SKrishna.Elango@Sun.COM low = ranges_p->child_low;
46210187SKrishna.Elango@Sun.COM hi = ranges_p->size_low + low;
46310187SKrishna.Elango@Sun.COM if ((addr < hi) && (addr >= low))
46410187SKrishna.Elango@Sun.COM return (B_TRUE);
46510187SKrishna.Elango@Sun.COM break;
46610187SKrishna.Elango@Sun.COM case PCI_ADDR_MEM64:
46710187SKrishna.Elango@Sun.COM low = ((uint64_t)ranges_p->child_mid << 32) |
46810187SKrishna.Elango@Sun.COM (uint64_t)ranges_p->child_low;
46910187SKrishna.Elango@Sun.COM hi = (((uint64_t)ranges_p->size_high << 32) |
47010187SKrishna.Elango@Sun.COM (uint64_t)ranges_p->size_low) + low;
47110187SKrishna.Elango@Sun.COM if ((addr < hi) && (addr >= low))
47210187SKrishna.Elango@Sun.COM return (B_TRUE);
47310187SKrishna.Elango@Sun.COM break;
47410187SKrishna.Elango@Sun.COM }
47510187SKrishna.Elango@Sun.COM }
47610187SKrishna.Elango@Sun.COM return (B_FALSE);
47710187SKrishna.Elango@Sun.COM }
47810187SKrishna.Elango@Sun.COM
47910187SKrishna.Elango@Sun.COM static pcie_bus_t *
pf_is_ready(dev_info_t * dip)48010187SKrishna.Elango@Sun.COM pf_is_ready(dev_info_t *dip)
48110187SKrishna.Elango@Sun.COM {
48210187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
48310187SKrishna.Elango@Sun.COM if (!bus_p)
48410187SKrishna.Elango@Sun.COM return (NULL);
48510187SKrishna.Elango@Sun.COM
48610187SKrishna.Elango@Sun.COM if (!(bus_p->bus_fm_flags & PF_FM_READY))
48710187SKrishna.Elango@Sun.COM return (NULL);
48810187SKrishna.Elango@Sun.COM return (bus_p);
48910187SKrishna.Elango@Sun.COM }
49010187SKrishna.Elango@Sun.COM
49110187SKrishna.Elango@Sun.COM static void
pf_pcix_ecc_regs_gather(pf_pcix_ecc_regs_t * pcix_ecc_regs,pcie_bus_t * bus_p,boolean_t bdg)49210187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_gather(pf_pcix_ecc_regs_t *pcix_ecc_regs,
49310187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p, boolean_t bdg)
49410187SKrishna.Elango@Sun.COM {
49510187SKrishna.Elango@Sun.COM if (bdg) {
49610187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_ctlstat = PCIX_CAP_GET(32, bus_p,
49710187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_ECC_STATUS);
49810187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_fstaddr = PCIX_CAP_GET(32, bus_p,
49910187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_ECC_FST_AD);
50010187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_secaddr = PCIX_CAP_GET(32, bus_p,
50110187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_ECC_SEC_AD);
50210187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_attr = PCIX_CAP_GET(32, bus_p,
50310187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_ECC_ATTR);
50410187SKrishna.Elango@Sun.COM } else {
50510187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_ctlstat = PCIX_CAP_GET(32, bus_p,
50610187SKrishna.Elango@Sun.COM PCI_PCIX_ECC_STATUS);
50710187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_fstaddr = PCIX_CAP_GET(32, bus_p,
50810187SKrishna.Elango@Sun.COM PCI_PCIX_ECC_FST_AD);
50910187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_secaddr = PCIX_CAP_GET(32, bus_p,
51010187SKrishna.Elango@Sun.COM PCI_PCIX_ECC_SEC_AD);
51110187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_attr = PCIX_CAP_GET(32, bus_p,
51210187SKrishna.Elango@Sun.COM PCI_PCIX_ECC_ATTR);
51310187SKrishna.Elango@Sun.COM }
51410187SKrishna.Elango@Sun.COM }
51510187SKrishna.Elango@Sun.COM
51610187SKrishna.Elango@Sun.COM
51710187SKrishna.Elango@Sun.COM static void
pf_pcix_regs_gather(pf_data_t * pfd_p,pcie_bus_t * bus_p)51810187SKrishna.Elango@Sun.COM pf_pcix_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p)
51910187SKrishna.Elango@Sun.COM {
52010187SKrishna.Elango@Sun.COM /*
52110187SKrishna.Elango@Sun.COM * For PCI-X device PCI-X Capability only exists for Type 0 Headers.
52210187SKrishna.Elango@Sun.COM * PCI-X Bridge Capability only exists for Type 1 Headers.
52310187SKrishna.Elango@Sun.COM * Both capabilities do not exist at the same time.
52410187SKrishna.Elango@Sun.COM */
52510187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) {
52610187SKrishna.Elango@Sun.COM pf_pcix_bdg_err_regs_t *pcix_bdg_regs;
52710187SKrishna.Elango@Sun.COM
52810187SKrishna.Elango@Sun.COM pcix_bdg_regs = PCIX_BDG_ERR_REG(pfd_p);
52910187SKrishna.Elango@Sun.COM
53010187SKrishna.Elango@Sun.COM pcix_bdg_regs->pcix_bdg_sec_stat = PCIX_CAP_GET(16, bus_p,
53110187SKrishna.Elango@Sun.COM PCI_PCIX_SEC_STATUS);
53210187SKrishna.Elango@Sun.COM pcix_bdg_regs->pcix_bdg_stat = PCIX_CAP_GET(32, bus_p,
53310187SKrishna.Elango@Sun.COM PCI_PCIX_BDG_STATUS);
53410187SKrishna.Elango@Sun.COM
53510187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
53610187SKrishna.Elango@Sun.COM /*
53710187SKrishna.Elango@Sun.COM * PCI Express to PCI-X bridges only implement the
53810187SKrishna.Elango@Sun.COM * secondary side of the PCI-X ECC registers, bit one is
53910187SKrishna.Elango@Sun.COM * read-only so we make sure we do not write to it.
54010187SKrishna.Elango@Sun.COM */
54110187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) {
54210187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS,
54310187SKrishna.Elango@Sun.COM 0);
54410187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_gather(
54510187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0), bus_p, B_TRUE);
54610187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS,
54710187SKrishna.Elango@Sun.COM 1);
54810187SKrishna.Elango@Sun.COM }
54910187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_gather(PCIX_BDG_ECC_REG(pfd_p, 0),
55010187SKrishna.Elango@Sun.COM bus_p, B_TRUE);
55110187SKrishna.Elango@Sun.COM }
55210187SKrishna.Elango@Sun.COM } else {
55310187SKrishna.Elango@Sun.COM pf_pcix_err_regs_t *pcix_regs = PCIX_ERR_REG(pfd_p);
55410187SKrishna.Elango@Sun.COM
55510187SKrishna.Elango@Sun.COM pcix_regs->pcix_command = PCIX_CAP_GET(16, bus_p,
55610187SKrishna.Elango@Sun.COM PCI_PCIX_COMMAND);
55710187SKrishna.Elango@Sun.COM pcix_regs->pcix_status = PCIX_CAP_GET(32, bus_p,
55810187SKrishna.Elango@Sun.COM PCI_PCIX_STATUS);
55910187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p))
56010187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_gather(PCIX_ECC_REG(pfd_p), bus_p,
56110187SKrishna.Elango@Sun.COM B_TRUE);
56210187SKrishna.Elango@Sun.COM }
56310187SKrishna.Elango@Sun.COM }
56410187SKrishna.Elango@Sun.COM
56510187SKrishna.Elango@Sun.COM static void
pf_pcie_regs_gather(pf_data_t * pfd_p,pcie_bus_t * bus_p)56610187SKrishna.Elango@Sun.COM pf_pcie_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p)
56710187SKrishna.Elango@Sun.COM {
56810187SKrishna.Elango@Sun.COM pf_pcie_err_regs_t *pcie_regs = PCIE_ERR_REG(pfd_p);
56910187SKrishna.Elango@Sun.COM pf_pcie_adv_err_regs_t *pcie_adv_regs = PCIE_ADV_REG(pfd_p);
57010187SKrishna.Elango@Sun.COM
57110187SKrishna.Elango@Sun.COM pcie_regs->pcie_err_status = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS);
57210187SKrishna.Elango@Sun.COM pcie_regs->pcie_err_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
57310187SKrishna.Elango@Sun.COM pcie_regs->pcie_dev_cap = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP);
57410187SKrishna.Elango@Sun.COM
57510187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p) && PCIE_IS_PCIX(bus_p))
57610187SKrishna.Elango@Sun.COM pf_pcix_regs_gather(pfd_p, bus_p);
57710187SKrishna.Elango@Sun.COM
57810187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) {
57910187SKrishna.Elango@Sun.COM pf_pcie_rp_err_regs_t *pcie_rp_regs = PCIE_RP_REG(pfd_p);
58010187SKrishna.Elango@Sun.COM
58110187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_status = PCIE_CAP_GET(32, bus_p,
58210187SKrishna.Elango@Sun.COM PCIE_ROOTSTS);
58310187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_ctl = PCIE_CAP_GET(16, bus_p,
58410187SKrishna.Elango@Sun.COM PCIE_ROOTCTL);
58510187SKrishna.Elango@Sun.COM }
58610187SKrishna.Elango@Sun.COM
58710187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p))
58810187SKrishna.Elango@Sun.COM return;
58910187SKrishna.Elango@Sun.COM
59010187SKrishna.Elango@Sun.COM /* Gather UE AERs */
59110187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_adv_ctl = PCIE_AER_GET(32, bus_p,
59210187SKrishna.Elango@Sun.COM PCIE_AER_CTL);
59310187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ue_status = PCIE_AER_GET(32, bus_p,
59410187SKrishna.Elango@Sun.COM PCIE_AER_UCE_STS);
59510187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ue_mask = PCIE_AER_GET(32, bus_p,
59610187SKrishna.Elango@Sun.COM PCIE_AER_UCE_MASK);
59710187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ue_sev = PCIE_AER_GET(32, bus_p,
59810187SKrishna.Elango@Sun.COM PCIE_AER_UCE_SERV);
59910187SKrishna.Elango@Sun.COM PCIE_ADV_HDR(pfd_p, 0) = PCIE_AER_GET(32, bus_p,
60010187SKrishna.Elango@Sun.COM PCIE_AER_HDR_LOG);
60110187SKrishna.Elango@Sun.COM PCIE_ADV_HDR(pfd_p, 1) = PCIE_AER_GET(32, bus_p,
60210187SKrishna.Elango@Sun.COM PCIE_AER_HDR_LOG + 0x4);
60310187SKrishna.Elango@Sun.COM PCIE_ADV_HDR(pfd_p, 2) = PCIE_AER_GET(32, bus_p,
60410187SKrishna.Elango@Sun.COM PCIE_AER_HDR_LOG + 0x8);
60510187SKrishna.Elango@Sun.COM PCIE_ADV_HDR(pfd_p, 3) = PCIE_AER_GET(32, bus_p,
60610187SKrishna.Elango@Sun.COM PCIE_AER_HDR_LOG + 0xc);
60710187SKrishna.Elango@Sun.COM
60810187SKrishna.Elango@Sun.COM /* Gather CE AERs */
60910187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ce_status = PCIE_AER_GET(32, bus_p,
61010187SKrishna.Elango@Sun.COM PCIE_AER_CE_STS);
61110187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ce_mask = PCIE_AER_GET(32, bus_p,
61210187SKrishna.Elango@Sun.COM PCIE_AER_CE_MASK);
61310187SKrishna.Elango@Sun.COM
61410187SKrishna.Elango@Sun.COM /*
61510187SKrishna.Elango@Sun.COM * If pci express to pci bridge then grab the bridge
61610187SKrishna.Elango@Sun.COM * error registers.
61710187SKrishna.Elango@Sun.COM */
61810187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p)) {
61910187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *pcie_bdg_regs =
62010187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p);
62110187SKrishna.Elango@Sun.COM
62210187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_ctl = PCIE_AER_GET(32, bus_p,
62310187SKrishna.Elango@Sun.COM PCIE_AER_SCTL);
62410187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_status = PCIE_AER_GET(32, bus_p,
62510187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_STS);
62610187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_mask = PCIE_AER_GET(32, bus_p,
62710187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MASK);
62810187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_sev = PCIE_AER_GET(32, bus_p,
62910187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_SERV);
63010187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_HDR(pfd_p, 0) = PCIE_AER_GET(32, bus_p,
63110187SKrishna.Elango@Sun.COM PCIE_AER_SHDR_LOG);
63210187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_HDR(pfd_p, 1) = PCIE_AER_GET(32, bus_p,
63310187SKrishna.Elango@Sun.COM PCIE_AER_SHDR_LOG + 0x4);
63410187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_HDR(pfd_p, 2) = PCIE_AER_GET(32, bus_p,
63510187SKrishna.Elango@Sun.COM PCIE_AER_SHDR_LOG + 0x8);
63610187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_HDR(pfd_p, 3) = PCIE_AER_GET(32, bus_p,
63710187SKrishna.Elango@Sun.COM PCIE_AER_SHDR_LOG + 0xc);
63810187SKrishna.Elango@Sun.COM }
63910187SKrishna.Elango@Sun.COM
64010187SKrishna.Elango@Sun.COM /*
64110187SKrishna.Elango@Sun.COM * If PCI Express root port then grab the root port
64210187SKrishna.Elango@Sun.COM * error registers.
64310187SKrishna.Elango@Sun.COM */
64410187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) {
64510187SKrishna.Elango@Sun.COM pf_pcie_adv_rp_err_regs_t *pcie_rp_regs =
64610187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p);
64710187SKrishna.Elango@Sun.COM
64810187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_err_cmd = PCIE_AER_GET(32, bus_p,
64910187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD);
65010187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_err_status = PCIE_AER_GET(32, bus_p,
65110187SKrishna.Elango@Sun.COM PCIE_AER_RE_STS);
65210187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_ce_src_id = PCIE_AER_GET(16, bus_p,
65310187SKrishna.Elango@Sun.COM PCIE_AER_CE_SRC_ID);
65410187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_ue_src_id = PCIE_AER_GET(16, bus_p,
65510187SKrishna.Elango@Sun.COM PCIE_AER_ERR_SRC_ID);
65610187SKrishna.Elango@Sun.COM }
65710187SKrishna.Elango@Sun.COM }
65810187SKrishna.Elango@Sun.COM
65910187SKrishna.Elango@Sun.COM static void
pf_pci_regs_gather(pf_data_t * pfd_p,pcie_bus_t * bus_p)66010187SKrishna.Elango@Sun.COM pf_pci_regs_gather(pf_data_t *pfd_p, pcie_bus_t *bus_p)
66110187SKrishna.Elango@Sun.COM {
66210187SKrishna.Elango@Sun.COM pf_pci_err_regs_t *pci_regs = PCI_ERR_REG(pfd_p);
66310187SKrishna.Elango@Sun.COM
66410187SKrishna.Elango@Sun.COM /*
66510187SKrishna.Elango@Sun.COM * Start by reading all the error registers that are available for
66610187SKrishna.Elango@Sun.COM * pci and pci express and for leaf devices and bridges/switches
66710187SKrishna.Elango@Sun.COM */
66810187SKrishna.Elango@Sun.COM pci_regs->pci_err_status = PCIE_GET(16, bus_p, PCI_CONF_STAT);
66910187SKrishna.Elango@Sun.COM pci_regs->pci_cfg_comm = PCIE_GET(16, bus_p, PCI_CONF_COMM);
67010187SKrishna.Elango@Sun.COM
67110187SKrishna.Elango@Sun.COM /*
67210187SKrishna.Elango@Sun.COM * If pci-pci bridge grab PCI bridge specific error registers.
67310187SKrishna.Elango@Sun.COM */
67410187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) {
67510187SKrishna.Elango@Sun.COM pf_pci_bdg_err_regs_t *pci_bdg_regs = PCI_BDG_ERR_REG(pfd_p);
67610187SKrishna.Elango@Sun.COM pci_bdg_regs->pci_bdg_sec_stat =
67710187SKrishna.Elango@Sun.COM PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
67810187SKrishna.Elango@Sun.COM pci_bdg_regs->pci_bdg_ctrl =
67910187SKrishna.Elango@Sun.COM PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
68010187SKrishna.Elango@Sun.COM }
68110187SKrishna.Elango@Sun.COM
68210187SKrishna.Elango@Sun.COM /*
68310187SKrishna.Elango@Sun.COM * If pci express device grab pci express error registers and
68410187SKrishna.Elango@Sun.COM * check for advanced error reporting features and grab them if
68510187SKrishna.Elango@Sun.COM * available.
68610187SKrishna.Elango@Sun.COM */
68710187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p))
68810187SKrishna.Elango@Sun.COM pf_pcie_regs_gather(pfd_p, bus_p);
68910187SKrishna.Elango@Sun.COM else if (PCIE_IS_PCIX(bus_p))
69010187SKrishna.Elango@Sun.COM pf_pcix_regs_gather(pfd_p, bus_p);
69110187SKrishna.Elango@Sun.COM
69210187SKrishna.Elango@Sun.COM }
69310187SKrishna.Elango@Sun.COM
69410187SKrishna.Elango@Sun.COM static void
pf_pcix_regs_clear(pf_data_t * pfd_p,pcie_bus_t * bus_p)69510187SKrishna.Elango@Sun.COM pf_pcix_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p)
69610187SKrishna.Elango@Sun.COM {
69710187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) {
69810187SKrishna.Elango@Sun.COM pf_pcix_bdg_err_regs_t *pcix_bdg_regs;
69910187SKrishna.Elango@Sun.COM
70010187SKrishna.Elango@Sun.COM pcix_bdg_regs = PCIX_BDG_ERR_REG(pfd_p);
70110187SKrishna.Elango@Sun.COM
70210187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(16, bus_p, PCI_PCIX_SEC_STATUS,
70310187SKrishna.Elango@Sun.COM pcix_bdg_regs->pcix_bdg_sec_stat);
70410187SKrishna.Elango@Sun.COM
70510187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_STATUS,
70610187SKrishna.Elango@Sun.COM pcix_bdg_regs->pcix_bdg_stat);
70710187SKrishna.Elango@Sun.COM
70810187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
70910187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *pcix_bdg_ecc_regs;
71010187SKrishna.Elango@Sun.COM /*
71110187SKrishna.Elango@Sun.COM * PCI Express to PCI-X bridges only implement the
71210187SKrishna.Elango@Sun.COM * secondary side of the PCI-X ECC registers. For
71310187SKrishna.Elango@Sun.COM * clearing, there is no need to "select" the ECC
71410187SKrishna.Elango@Sun.COM * register, just write what was originally read.
71510187SKrishna.Elango@Sun.COM */
71610187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) {
71710187SKrishna.Elango@Sun.COM pcix_bdg_ecc_regs = PCIX_BDG_ECC_REG(pfd_p, 0);
71810187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS,
71910187SKrishna.Elango@Sun.COM pcix_bdg_ecc_regs->pcix_ecc_ctlstat);
72010187SKrishna.Elango@Sun.COM
72110187SKrishna.Elango@Sun.COM }
72210187SKrishna.Elango@Sun.COM pcix_bdg_ecc_regs = PCIX_BDG_ECC_REG(pfd_p, 1);
72310187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_BDG_ECC_STATUS,
72410187SKrishna.Elango@Sun.COM pcix_bdg_ecc_regs->pcix_ecc_ctlstat);
72510187SKrishna.Elango@Sun.COM }
72610187SKrishna.Elango@Sun.COM } else {
72710187SKrishna.Elango@Sun.COM pf_pcix_err_regs_t *pcix_regs = PCIX_ERR_REG(pfd_p);
72810187SKrishna.Elango@Sun.COM
72910187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_STATUS,
73010187SKrishna.Elango@Sun.COM pcix_regs->pcix_status);
73110187SKrishna.Elango@Sun.COM
73210187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
73310187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *pcix_ecc_regs = PCIX_ECC_REG(pfd_p);
73410187SKrishna.Elango@Sun.COM
73510187SKrishna.Elango@Sun.COM PCIX_CAP_PUT(32, bus_p, PCI_PCIX_ECC_STATUS,
73610187SKrishna.Elango@Sun.COM pcix_ecc_regs->pcix_ecc_ctlstat);
73710187SKrishna.Elango@Sun.COM }
73810187SKrishna.Elango@Sun.COM }
73910187SKrishna.Elango@Sun.COM }
74010187SKrishna.Elango@Sun.COM
74110187SKrishna.Elango@Sun.COM static void
pf_pcie_regs_clear(pf_data_t * pfd_p,pcie_bus_t * bus_p)74210187SKrishna.Elango@Sun.COM pf_pcie_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p)
74310187SKrishna.Elango@Sun.COM {
74410187SKrishna.Elango@Sun.COM pf_pcie_err_regs_t *pcie_regs = PCIE_ERR_REG(pfd_p);
74510187SKrishna.Elango@Sun.COM pf_pcie_adv_err_regs_t *pcie_adv_regs = PCIE_ADV_REG(pfd_p);
74610187SKrishna.Elango@Sun.COM
74710187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS, pcie_regs->pcie_err_status);
74810187SKrishna.Elango@Sun.COM
74910187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p) && PCIE_IS_PCIX(bus_p))
75010187SKrishna.Elango@Sun.COM pf_pcix_regs_clear(pfd_p, bus_p);
75110187SKrishna.Elango@Sun.COM
75210187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p))
75310187SKrishna.Elango@Sun.COM return;
75410187SKrishna.Elango@Sun.COM
75510187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_STS,
75610187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ue_status);
75710187SKrishna.Elango@Sun.COM
75810187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS,
75910187SKrishna.Elango@Sun.COM pcie_adv_regs->pcie_ce_status);
76010187SKrishna.Elango@Sun.COM
76110187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p)) {
76210187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *pcie_bdg_regs =
76310187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p);
76410187SKrishna.Elango@Sun.COM
76510187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_STS,
76610187SKrishna.Elango@Sun.COM pcie_bdg_regs->pcie_sue_status);
76710187SKrishna.Elango@Sun.COM }
76810187SKrishna.Elango@Sun.COM
76910187SKrishna.Elango@Sun.COM /*
77010187SKrishna.Elango@Sun.COM * If PCI Express root complex then clear the root complex
77110187SKrishna.Elango@Sun.COM * error registers.
77210187SKrishna.Elango@Sun.COM */
77310187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) {
77410187SKrishna.Elango@Sun.COM pf_pcie_adv_rp_err_regs_t *pcie_rp_regs;
77510187SKrishna.Elango@Sun.COM
77610187SKrishna.Elango@Sun.COM pcie_rp_regs = PCIE_ADV_RP_REG(pfd_p);
77710187SKrishna.Elango@Sun.COM
77810187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_RE_STS,
77910187SKrishna.Elango@Sun.COM pcie_rp_regs->pcie_rp_err_status);
78010187SKrishna.Elango@Sun.COM }
78110187SKrishna.Elango@Sun.COM }
78210187SKrishna.Elango@Sun.COM
78310187SKrishna.Elango@Sun.COM static void
pf_pci_regs_clear(pf_data_t * pfd_p,pcie_bus_t * bus_p)78410187SKrishna.Elango@Sun.COM pf_pci_regs_clear(pf_data_t *pfd_p, pcie_bus_t *bus_p)
78510187SKrishna.Elango@Sun.COM {
78610187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p))
78710187SKrishna.Elango@Sun.COM pf_pcie_regs_clear(pfd_p, bus_p);
78810187SKrishna.Elango@Sun.COM else if (PCIE_IS_PCIX(bus_p))
78910187SKrishna.Elango@Sun.COM pf_pcix_regs_clear(pfd_p, bus_p);
79010187SKrishna.Elango@Sun.COM
79110187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_STAT, pfd_p->pe_pci_regs->pci_err_status);
79210187SKrishna.Elango@Sun.COM
79310187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) {
79410187SKrishna.Elango@Sun.COM pf_pci_bdg_err_regs_t *pci_bdg_regs = PCI_BDG_ERR_REG(pfd_p);
79510187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS,
79610187SKrishna.Elango@Sun.COM pci_bdg_regs->pci_bdg_sec_stat);
79710187SKrishna.Elango@Sun.COM }
79810187SKrishna.Elango@Sun.COM }
79910187SKrishna.Elango@Sun.COM
80010187SKrishna.Elango@Sun.COM /* ARGSUSED */
80110187SKrishna.Elango@Sun.COM void
pcie_clear_errors(dev_info_t * dip)80210187SKrishna.Elango@Sun.COM pcie_clear_errors(dev_info_t *dip)
80310187SKrishna.Elango@Sun.COM {
80410187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
80510187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
80610187SKrishna.Elango@Sun.COM
80710187SKrishna.Elango@Sun.COM ASSERT(bus_p);
80810187SKrishna.Elango@Sun.COM
80910187SKrishna.Elango@Sun.COM pf_pci_regs_gather(pfd_p, bus_p);
81010187SKrishna.Elango@Sun.COM pf_pci_regs_clear(pfd_p, bus_p);
81110187SKrishna.Elango@Sun.COM }
81210187SKrishna.Elango@Sun.COM
81310187SKrishna.Elango@Sun.COM /* Find the fault BDF, fault Addr or full scan on a PCIe Root Port. */
81410187SKrishna.Elango@Sun.COM static void
pf_pci_find_rp_fault(pf_data_t * pfd_p,pcie_bus_t * bus_p)81510187SKrishna.Elango@Sun.COM pf_pci_find_rp_fault(pf_data_t *pfd_p, pcie_bus_t *bus_p)
81610187SKrishna.Elango@Sun.COM {
81710187SKrishna.Elango@Sun.COM pf_root_fault_t *root_fault = PCIE_ROOT_FAULT(pfd_p);
81810187SKrishna.Elango@Sun.COM pf_pcie_adv_rp_err_regs_t *rp_regs = PCIE_ADV_RP_REG(pfd_p);
81910187SKrishna.Elango@Sun.COM uint32_t root_err = rp_regs->pcie_rp_err_status;
82010187SKrishna.Elango@Sun.COM uint32_t ue_err = PCIE_ADV_REG(pfd_p)->pcie_ue_status;
82110187SKrishna.Elango@Sun.COM int num_faults = 0;
82210187SKrishna.Elango@Sun.COM
82310187SKrishna.Elango@Sun.COM /* Since this data structure is reused, make sure to reset it */
82410187SKrishna.Elango@Sun.COM root_fault->full_scan = B_FALSE;
82510187SKrishna.Elango@Sun.COM root_fault->scan_bdf = PCIE_INVALID_BDF;
82610187SKrishna.Elango@Sun.COM root_fault->scan_addr = 0;
82710187SKrishna.Elango@Sun.COM
82810187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p) &&
82910187SKrishna.Elango@Sun.COM (PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR)) {
83010187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE;
83110187SKrishna.Elango@Sun.COM return;
83210187SKrishna.Elango@Sun.COM }
83310187SKrishna.Elango@Sun.COM
83410187SKrishna.Elango@Sun.COM /*
83510187SKrishna.Elango@Sun.COM * Check to see if an error has been received that
83610187SKrishna.Elango@Sun.COM * requires a scan of the fabric. Count the number of
83710187SKrishna.Elango@Sun.COM * faults seen. If MUL CE/FE_NFE that counts for
83810187SKrishna.Elango@Sun.COM * atleast 2 faults, so just return with full_scan.
83910187SKrishna.Elango@Sun.COM */
84010187SKrishna.Elango@Sun.COM if ((root_err & PCIE_AER_RE_STS_MUL_CE_RCVD) ||
84110187SKrishna.Elango@Sun.COM (root_err & PCIE_AER_RE_STS_MUL_FE_NFE_RCVD)) {
84210187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE;
84310187SKrishna.Elango@Sun.COM return;
84410187SKrishna.Elango@Sun.COM }
84510187SKrishna.Elango@Sun.COM
84610187SKrishna.Elango@Sun.COM if (root_err & PCIE_AER_RE_STS_CE_RCVD)
84710187SKrishna.Elango@Sun.COM num_faults++;
84810187SKrishna.Elango@Sun.COM
84910187SKrishna.Elango@Sun.COM if (root_err & PCIE_AER_RE_STS_FE_NFE_RCVD)
85010187SKrishna.Elango@Sun.COM num_faults++;
85110187SKrishna.Elango@Sun.COM
85210187SKrishna.Elango@Sun.COM if (ue_err & PCIE_AER_UCE_CA)
85310187SKrishna.Elango@Sun.COM num_faults++;
85410187SKrishna.Elango@Sun.COM
85510187SKrishna.Elango@Sun.COM if (ue_err & PCIE_AER_UCE_UR)
85610187SKrishna.Elango@Sun.COM num_faults++;
85710187SKrishna.Elango@Sun.COM
85810187SKrishna.Elango@Sun.COM /* If no faults just return */
85910187SKrishna.Elango@Sun.COM if (num_faults == 0)
86010187SKrishna.Elango@Sun.COM return;
86110187SKrishna.Elango@Sun.COM
86210187SKrishna.Elango@Sun.COM /* If faults > 1 do full scan */
86310187SKrishna.Elango@Sun.COM if (num_faults > 1) {
86410187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE;
86510187SKrishna.Elango@Sun.COM return;
86610187SKrishna.Elango@Sun.COM }
86710187SKrishna.Elango@Sun.COM
86810187SKrishna.Elango@Sun.COM /* By this point, there is only 1 fault detected */
86910187SKrishna.Elango@Sun.COM if (root_err & PCIE_AER_RE_STS_CE_RCVD) {
87010187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = rp_regs->pcie_rp_ce_src_id;
87110187SKrishna.Elango@Sun.COM num_faults--;
87210187SKrishna.Elango@Sun.COM } else if (root_err & PCIE_AER_RE_STS_FE_NFE_RCVD) {
87310187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = rp_regs->pcie_rp_ue_src_id;
87410187SKrishna.Elango@Sun.COM num_faults--;
87510187SKrishna.Elango@Sun.COM } else if ((HAS_AER_LOGS(pfd_p, PCIE_AER_UCE_CA) ||
87610187SKrishna.Elango@Sun.COM HAS_AER_LOGS(pfd_p, PCIE_AER_UCE_UR)) &&
87710187SKrishna.Elango@Sun.COM (pf_tlp_decode(PCIE_PFD2BUS(pfd_p), PCIE_ADV_REG(pfd_p)) ==
87810187SKrishna.Elango@Sun.COM DDI_SUCCESS)) {
87910187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_addr =
88010187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr;
88110187SKrishna.Elango@Sun.COM num_faults--;
88210187SKrishna.Elango@Sun.COM }
88310187SKrishna.Elango@Sun.COM
88410187SKrishna.Elango@Sun.COM /*
88510187SKrishna.Elango@Sun.COM * This means an error did occur, but we couldn't extract the fault BDF
88610187SKrishna.Elango@Sun.COM */
88710187SKrishna.Elango@Sun.COM if (num_faults > 0)
88810187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_TRUE;
88910187SKrishna.Elango@Sun.COM
89010187SKrishna.Elango@Sun.COM }
89110187SKrishna.Elango@Sun.COM
89210187SKrishna.Elango@Sun.COM
89310187SKrishna.Elango@Sun.COM /*
89410187SKrishna.Elango@Sun.COM * Load PCIe Fault Data for PCI/PCIe devices into PCIe Fault Data Queue
89510187SKrishna.Elango@Sun.COM *
89610187SKrishna.Elango@Sun.COM * Returns a scan flag.
89710187SKrishna.Elango@Sun.COM * o PF_SCAN_SUCCESS - Error gathered and cleared sucessfuly, data added to
89810187SKrishna.Elango@Sun.COM * Fault Q
89911596SJason.Beloro@Sun.COM * o PF_SCAN_BAD_RESPONSE - Unable to talk to device, item added to fault Q
90010187SKrishna.Elango@Sun.COM * o PF_SCAN_CB_FAILURE - A hardened device deemed that the error was fatal.
90110187SKrishna.Elango@Sun.COM * o PF_SCAN_NO_ERR_IN_CHILD - Only applies to bridge to prevent further
90210187SKrishna.Elango@Sun.COM * unnecessary scanning
90310187SKrishna.Elango@Sun.COM * o PF_SCAN_IN_DQ - This device has already been scanned; it was skipped this
90410187SKrishna.Elango@Sun.COM * time.
90510187SKrishna.Elango@Sun.COM */
90610187SKrishna.Elango@Sun.COM static int
pf_default_hdl(dev_info_t * dip,pf_impl_t * impl)90710187SKrishna.Elango@Sun.COM pf_default_hdl(dev_info_t *dip, pf_impl_t *impl)
90810187SKrishna.Elango@Sun.COM {
90910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
91010187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
91110187SKrishna.Elango@Sun.COM int cb_sts, scan_flag = PF_SCAN_SUCCESS;
91210187SKrishna.Elango@Sun.COM
91310187SKrishna.Elango@Sun.COM /* Make sure this device hasn't already been snapshotted and cleared */
91410187SKrishna.Elango@Sun.COM if (pfd_p->pe_valid == B_TRUE) {
91510187SKrishna.Elango@Sun.COM scan_flag |= PF_SCAN_IN_DQ;
91610187SKrishna.Elango@Sun.COM goto done;
91710187SKrishna.Elango@Sun.COM }
91810187SKrishna.Elango@Sun.COM
91910187SKrishna.Elango@Sun.COM /*
92010187SKrishna.Elango@Sun.COM * Read vendor/device ID and check with cached data, if it doesn't match
92110187SKrishna.Elango@Sun.COM * could very well be a device that isn't responding anymore. Just
92210187SKrishna.Elango@Sun.COM * stop. Save the basic info in the error q for post mortem debugging
92310187SKrishna.Elango@Sun.COM * purposes.
92410187SKrishna.Elango@Sun.COM */
92510187SKrishna.Elango@Sun.COM if (PCIE_GET(32, bus_p, PCI_CONF_VENID) != bus_p->bus_dev_ven_id) {
92610187SKrishna.Elango@Sun.COM char buf[FM_MAX_CLASS];
92710187SKrishna.Elango@Sun.COM
92810187SKrishna.Elango@Sun.COM (void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
92910187SKrishna.Elango@Sun.COM PCI_ERROR_SUBCLASS, PCI_NR);
93010187SKrishna.Elango@Sun.COM ddi_fm_ereport_post(dip, buf, fm_ena_generate(0, FM_ENA_FMT1),
93110187SKrishna.Elango@Sun.COM DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL);
93210187SKrishna.Elango@Sun.COM
93311596SJason.Beloro@Sun.COM /*
93411596SJason.Beloro@Sun.COM * For IOV/Hotplug purposes skip gathering info fo this device,
93511596SJason.Beloro@Sun.COM * but populate affected info and severity. Clear out any data
93611596SJason.Beloro@Sun.COM * that maybe been saved in the last fabric scan.
93711596SJason.Beloro@Sun.COM */
93811596SJason.Beloro@Sun.COM pf_reset_pfd(pfd_p);
93911596SJason.Beloro@Sun.COM pfd_p->pe_severity_flags = PF_ERR_PANIC_BAD_RESPONSE;
94011596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
94111596SJason.Beloro@Sun.COM
94211596SJason.Beloro@Sun.COM /* Add the snapshot to the error q */
94311596SJason.Beloro@Sun.COM pf_en_dq(pfd_p, impl);
94411596SJason.Beloro@Sun.COM pfd_p->pe_valid = B_TRUE;
94511596SJason.Beloro@Sun.COM
94610187SKrishna.Elango@Sun.COM return (PF_SCAN_BAD_RESPONSE);
94710187SKrishna.Elango@Sun.COM }
94810187SKrishna.Elango@Sun.COM
94910187SKrishna.Elango@Sun.COM pf_pci_regs_gather(pfd_p, bus_p);
95010187SKrishna.Elango@Sun.COM pf_pci_regs_clear(pfd_p, bus_p);
95110187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p))
95210187SKrishna.Elango@Sun.COM pf_pci_find_rp_fault(pfd_p, bus_p);
95310187SKrishna.Elango@Sun.COM
95410187SKrishna.Elango@Sun.COM cb_sts = pf_fm_callback(dip, impl->pf_derr);
95510187SKrishna.Elango@Sun.COM
95610187SKrishna.Elango@Sun.COM if (cb_sts == DDI_FM_FATAL || cb_sts == DDI_FM_UNKNOWN)
95710187SKrishna.Elango@Sun.COM scan_flag |= PF_SCAN_CB_FAILURE;
95810187SKrishna.Elango@Sun.COM
95910187SKrishna.Elango@Sun.COM /* Add the snapshot to the error q */
96010187SKrishna.Elango@Sun.COM pf_en_dq(pfd_p, impl);
96110187SKrishna.Elango@Sun.COM
96210187SKrishna.Elango@Sun.COM done:
96310187SKrishna.Elango@Sun.COM /*
96410187SKrishna.Elango@Sun.COM * If a bridge does not have any error no need to scan any further down.
96510187SKrishna.Elango@Sun.COM * For PCIe devices, check the PCIe device status and PCI secondary
96610187SKrishna.Elango@Sun.COM * status.
96710187SKrishna.Elango@Sun.COM * - Some non-compliant PCIe devices do not utilize PCIe
96810187SKrishna.Elango@Sun.COM * error registers. If so rely on legacy PCI error registers.
96910187SKrishna.Elango@Sun.COM * For PCI devices, check the PCI secondary status.
97010187SKrishna.Elango@Sun.COM */
97110187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) &&
97210187SKrishna.Elango@Sun.COM !(PCIE_ERR_REG(pfd_p)->pcie_err_status & PF_PCIE_BDG_ERR) &&
97310187SKrishna.Elango@Sun.COM !(PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR))
97410187SKrishna.Elango@Sun.COM scan_flag |= PF_SCAN_NO_ERR_IN_CHILD;
97510187SKrishna.Elango@Sun.COM
97610187SKrishna.Elango@Sun.COM if (PCIE_IS_PCI_BDG(bus_p) &&
97710187SKrishna.Elango@Sun.COM !(PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat & PF_PCI_BDG_ERR))
97810187SKrishna.Elango@Sun.COM scan_flag |= PF_SCAN_NO_ERR_IN_CHILD;
97910187SKrishna.Elango@Sun.COM
98010187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_TRUE;
98110187SKrishna.Elango@Sun.COM return (scan_flag);
98210187SKrishna.Elango@Sun.COM }
98310187SKrishna.Elango@Sun.COM
98410187SKrishna.Elango@Sun.COM /*
98510187SKrishna.Elango@Sun.COM * Called during postattach to initialize a device's error handling
98610187SKrishna.Elango@Sun.COM * capabilities. If the devices has already been hardened, then there isn't
98710187SKrishna.Elango@Sun.COM * much needed. Otherwise initialize the device's default FMA capabilities.
98810187SKrishna.Elango@Sun.COM *
98910187SKrishna.Elango@Sun.COM * In a future project where PCIe support is removed from pcifm, several
99010187SKrishna.Elango@Sun.COM * "properties" that are setup in ddi_fm_init and pci_ereport_setup need to be
99110187SKrishna.Elango@Sun.COM * created here so that the PCI/PCIe eversholt rules will work properly.
99210187SKrishna.Elango@Sun.COM */
99310187SKrishna.Elango@Sun.COM void
pf_init(dev_info_t * dip,ddi_iblock_cookie_t ibc,ddi_attach_cmd_t cmd)99410187SKrishna.Elango@Sun.COM pf_init(dev_info_t *dip, ddi_iblock_cookie_t ibc, ddi_attach_cmd_t cmd)
99510187SKrishna.Elango@Sun.COM {
99610187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
99710187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
99810187SKrishna.Elango@Sun.COM boolean_t need_cb_register = B_FALSE;
99910187SKrishna.Elango@Sun.COM
100010187SKrishna.Elango@Sun.COM if (!bus_p) {
100110187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, "devi_bus information is not set for %s%d.\n",
100210187SKrishna.Elango@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip));
100310187SKrishna.Elango@Sun.COM return;
100410187SKrishna.Elango@Sun.COM }
100510187SKrishna.Elango@Sun.COM
100610187SKrishna.Elango@Sun.COM if (fmhdl) {
100710187SKrishna.Elango@Sun.COM /*
100810187SKrishna.Elango@Sun.COM * If device is only ereport capable and not callback capable
100910187SKrishna.Elango@Sun.COM * make it callback capable. The only downside is that the
101010187SKrishna.Elango@Sun.COM * "fm-errcb-capable" property is not created for this device
101110187SKrishna.Elango@Sun.COM * which should be ok since it's not used anywhere.
101210187SKrishna.Elango@Sun.COM */
101310187SKrishna.Elango@Sun.COM if (!(fmhdl->fh_cap & DDI_FM_ERRCB_CAPABLE))
101410187SKrishna.Elango@Sun.COM need_cb_register = B_TRUE;
101510187SKrishna.Elango@Sun.COM } else {
101610187SKrishna.Elango@Sun.COM int cap;
101710187SKrishna.Elango@Sun.COM /*
101810187SKrishna.Elango@Sun.COM * fm-capable in driver.conf can be used to set fm_capabilities.
101910187SKrishna.Elango@Sun.COM * If fm-capable is not defined, set the default
102010187SKrishna.Elango@Sun.COM * DDI_FM_EREPORT_CAPABLE and DDI_FM_ERRCB_CAPABLE.
102110187SKrishna.Elango@Sun.COM */
102210187SKrishna.Elango@Sun.COM cap = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
102310187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "fm-capable",
102410187SKrishna.Elango@Sun.COM DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE);
102510187SKrishna.Elango@Sun.COM cap &= (DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE);
102610187SKrishna.Elango@Sun.COM
102710187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags |= PF_FM_IS_NH;
102810187SKrishna.Elango@Sun.COM
102910187SKrishna.Elango@Sun.COM if (cmd == DDI_ATTACH) {
103010187SKrishna.Elango@Sun.COM ddi_fm_init(dip, &cap, &ibc);
103110187SKrishna.Elango@Sun.COM pci_ereport_setup(dip);
103210187SKrishna.Elango@Sun.COM }
103310187SKrishna.Elango@Sun.COM
103410187SKrishna.Elango@Sun.COM if (cap & DDI_FM_ERRCB_CAPABLE)
103510187SKrishna.Elango@Sun.COM need_cb_register = B_TRUE;
103610187SKrishna.Elango@Sun.COM
103710187SKrishna.Elango@Sun.COM fmhdl = DEVI(dip)->devi_fmhdl;
103810187SKrishna.Elango@Sun.COM }
103910187SKrishna.Elango@Sun.COM
104010187SKrishna.Elango@Sun.COM /* If ddi_fm_init fails for any reason RETURN */
104110187SKrishna.Elango@Sun.COM if (!fmhdl) {
104210187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags = 0;
104310187SKrishna.Elango@Sun.COM return;
104410187SKrishna.Elango@Sun.COM }
104510187SKrishna.Elango@Sun.COM
104610187SKrishna.Elango@Sun.COM fmhdl->fh_cap |= DDI_FM_ERRCB_CAPABLE;
104710187SKrishna.Elango@Sun.COM if (cmd == DDI_ATTACH) {
104810187SKrishna.Elango@Sun.COM if (need_cb_register)
104910187SKrishna.Elango@Sun.COM ddi_fm_handler_register(dip, pf_dummy_cb, NULL);
105010187SKrishna.Elango@Sun.COM }
105110187SKrishna.Elango@Sun.COM
105210187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags |= PF_FM_READY;
105310187SKrishna.Elango@Sun.COM }
105410187SKrishna.Elango@Sun.COM
105510187SKrishna.Elango@Sun.COM /* undo FMA lock, called at predetach */
105610187SKrishna.Elango@Sun.COM void
pf_fini(dev_info_t * dip,ddi_detach_cmd_t cmd)105710187SKrishna.Elango@Sun.COM pf_fini(dev_info_t *dip, ddi_detach_cmd_t cmd)
105810187SKrishna.Elango@Sun.COM {
105910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
106010187SKrishna.Elango@Sun.COM
106110187SKrishna.Elango@Sun.COM if (!bus_p)
106210187SKrishna.Elango@Sun.COM return;
106310187SKrishna.Elango@Sun.COM
106410187SKrishna.Elango@Sun.COM /* Don't fini anything if device isn't FM Ready */
106510187SKrishna.Elango@Sun.COM if (!(bus_p->bus_fm_flags & PF_FM_READY))
106610187SKrishna.Elango@Sun.COM return;
106710187SKrishna.Elango@Sun.COM
106810187SKrishna.Elango@Sun.COM /* no other code should set the flag to false */
106910187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags &= ~PF_FM_READY;
107010187SKrishna.Elango@Sun.COM
107110187SKrishna.Elango@Sun.COM /*
107210187SKrishna.Elango@Sun.COM * Grab the mutex to make sure device isn't in the middle of
107310187SKrishna.Elango@Sun.COM * error handling. Setting the bus_fm_flag to ~PF_FM_READY
107410187SKrishna.Elango@Sun.COM * should prevent this device from being error handled after
107510187SKrishna.Elango@Sun.COM * the mutex has been released.
107610187SKrishna.Elango@Sun.COM */
107710187SKrishna.Elango@Sun.COM (void) pf_handler_enter(dip, NULL);
107810187SKrishna.Elango@Sun.COM pf_handler_exit(dip);
107910187SKrishna.Elango@Sun.COM
108010187SKrishna.Elango@Sun.COM /* undo non-hardened drivers */
108110187SKrishna.Elango@Sun.COM if (bus_p->bus_fm_flags & PF_FM_IS_NH) {
108210187SKrishna.Elango@Sun.COM if (cmd == DDI_DETACH) {
108310187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags &= ~PF_FM_IS_NH;
108410187SKrishna.Elango@Sun.COM pci_ereport_teardown(dip);
108510187SKrishna.Elango@Sun.COM /*
108610187SKrishna.Elango@Sun.COM * ddi_fini itself calls ddi_handler_unregister,
108710187SKrishna.Elango@Sun.COM * so no need to explicitly call unregister.
108810187SKrishna.Elango@Sun.COM */
108910187SKrishna.Elango@Sun.COM ddi_fm_fini(dip);
109010187SKrishna.Elango@Sun.COM }
109110187SKrishna.Elango@Sun.COM }
109210187SKrishna.Elango@Sun.COM }
109310187SKrishna.Elango@Sun.COM
109410187SKrishna.Elango@Sun.COM /*ARGSUSED*/
109510187SKrishna.Elango@Sun.COM static int
pf_dummy_cb(dev_info_t * dip,ddi_fm_error_t * derr,const void * not_used)109610187SKrishna.Elango@Sun.COM pf_dummy_cb(dev_info_t *dip, ddi_fm_error_t *derr, const void *not_used)
109710187SKrishna.Elango@Sun.COM {
109810187SKrishna.Elango@Sun.COM return (DDI_FM_OK);
109910187SKrishna.Elango@Sun.COM }
110010187SKrishna.Elango@Sun.COM
110110187SKrishna.Elango@Sun.COM /*
110210187SKrishna.Elango@Sun.COM * Add PFD to queue. If it is an RC add it to the beginning,
110310187SKrishna.Elango@Sun.COM * otherwise add it to the end.
110410187SKrishna.Elango@Sun.COM */
110510187SKrishna.Elango@Sun.COM static void
pf_en_dq(pf_data_t * pfd_p,pf_impl_t * impl)110610187SKrishna.Elango@Sun.COM pf_en_dq(pf_data_t *pfd_p, pf_impl_t *impl)
110710187SKrishna.Elango@Sun.COM {
110810187SKrishna.Elango@Sun.COM pf_data_t *head_p = impl->pf_dq_head_p;
110910187SKrishna.Elango@Sun.COM pf_data_t *tail_p = impl->pf_dq_tail_p;
111010187SKrishna.Elango@Sun.COM
111110187SKrishna.Elango@Sun.COM impl->pf_total++;
111210187SKrishna.Elango@Sun.COM
111310187SKrishna.Elango@Sun.COM if (!head_p) {
111410187SKrishna.Elango@Sun.COM ASSERT(PFD_IS_ROOT(pfd_p));
111510187SKrishna.Elango@Sun.COM impl->pf_dq_head_p = pfd_p;
111610187SKrishna.Elango@Sun.COM impl->pf_dq_tail_p = pfd_p;
111710187SKrishna.Elango@Sun.COM pfd_p->pe_prev = NULL;
111810187SKrishna.Elango@Sun.COM pfd_p->pe_next = NULL;
111910187SKrishna.Elango@Sun.COM return;
112010187SKrishna.Elango@Sun.COM }
112110187SKrishna.Elango@Sun.COM
112210187SKrishna.Elango@Sun.COM /* Check if this is a Root Port eprt */
112310187SKrishna.Elango@Sun.COM if (PFD_IS_ROOT(pfd_p)) {
112410187SKrishna.Elango@Sun.COM pf_data_t *root_p, *last_p = NULL;
112510187SKrishna.Elango@Sun.COM
112610187SKrishna.Elango@Sun.COM /* The first item must be a RP */
112710187SKrishna.Elango@Sun.COM root_p = head_p;
112810187SKrishna.Elango@Sun.COM for (last_p = head_p; last_p && PFD_IS_ROOT(last_p);
112910187SKrishna.Elango@Sun.COM last_p = last_p->pe_next)
113010187SKrishna.Elango@Sun.COM root_p = last_p;
113110187SKrishna.Elango@Sun.COM
113210187SKrishna.Elango@Sun.COM /* root_p is the last RP pfd. last_p is the first non-RP pfd. */
113310187SKrishna.Elango@Sun.COM root_p->pe_next = pfd_p;
113410187SKrishna.Elango@Sun.COM pfd_p->pe_prev = root_p;
113510187SKrishna.Elango@Sun.COM pfd_p->pe_next = last_p;
113610187SKrishna.Elango@Sun.COM
113710187SKrishna.Elango@Sun.COM if (last_p)
113810187SKrishna.Elango@Sun.COM last_p->pe_prev = pfd_p;
113910187SKrishna.Elango@Sun.COM else
114010187SKrishna.Elango@Sun.COM tail_p = pfd_p;
114110187SKrishna.Elango@Sun.COM } else {
114210187SKrishna.Elango@Sun.COM tail_p->pe_next = pfd_p;
114310187SKrishna.Elango@Sun.COM pfd_p->pe_prev = tail_p;
114410187SKrishna.Elango@Sun.COM pfd_p->pe_next = NULL;
114510187SKrishna.Elango@Sun.COM tail_p = pfd_p;
114610187SKrishna.Elango@Sun.COM }
114710187SKrishna.Elango@Sun.COM
114810187SKrishna.Elango@Sun.COM impl->pf_dq_head_p = head_p;
114910187SKrishna.Elango@Sun.COM impl->pf_dq_tail_p = tail_p;
115010187SKrishna.Elango@Sun.COM }
115110187SKrishna.Elango@Sun.COM
115210187SKrishna.Elango@Sun.COM /*
115310187SKrishna.Elango@Sun.COM * Ignore:
115410187SKrishna.Elango@Sun.COM * - TRAINING: as leaves do not have children
115510187SKrishna.Elango@Sun.COM * - SD: as leaves do not have children
115610187SKrishna.Elango@Sun.COM */
115710187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_pcie_tbl[] = {
115811596SJason.Beloro@Sun.COM {PCIE_AER_UCE_DLP, pf_panic,
115911596SJason.Beloro@Sun.COM PF_AFFECTED_PARENT, 0},
116011596SJason.Beloro@Sun.COM
116111596SJason.Beloro@Sun.COM {PCIE_AER_UCE_PTLP, pf_analyse_ptlp,
116211596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
116311596SJason.Beloro@Sun.COM
116411596SJason.Beloro@Sun.COM {PCIE_AER_UCE_FCP, pf_panic,
116511596SJason.Beloro@Sun.COM PF_AFFECTED_PARENT, 0},
116611596SJason.Beloro@Sun.COM
116711596SJason.Beloro@Sun.COM {PCIE_AER_UCE_TO, pf_analyse_to,
116811596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
116911596SJason.Beloro@Sun.COM
117011596SJason.Beloro@Sun.COM {PCIE_AER_UCE_CA, pf_analyse_ca_ur,
117111596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
117211596SJason.Beloro@Sun.COM
117311596SJason.Beloro@Sun.COM {PCIE_AER_UCE_UC, pf_analyse_uc,
117411596SJason.Beloro@Sun.COM 0, 0},
117511596SJason.Beloro@Sun.COM
117611596SJason.Beloro@Sun.COM {PCIE_AER_UCE_RO, pf_panic,
117711596SJason.Beloro@Sun.COM PF_AFFECTED_PARENT, 0},
117811596SJason.Beloro@Sun.COM
117911596SJason.Beloro@Sun.COM {PCIE_AER_UCE_MTLP, pf_panic,
118011596SJason.Beloro@Sun.COM PF_AFFECTED_PARENT, 0},
118111596SJason.Beloro@Sun.COM
118211596SJason.Beloro@Sun.COM {PCIE_AER_UCE_ECRC, pf_panic,
118311596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
118411596SJason.Beloro@Sun.COM
118511596SJason.Beloro@Sun.COM {PCIE_AER_UCE_UR, pf_analyse_ca_ur,
118611596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
118711596SJason.Beloro@Sun.COM
118811596SJason.Beloro@Sun.COM {NULL, NULL, NULL, NULL}
118910187SKrishna.Elango@Sun.COM };
119010187SKrishna.Elango@Sun.COM
119110187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_rp_tbl[] = {
119211596SJason.Beloro@Sun.COM {PCIE_AER_UCE_TRAINING, pf_no_panic,
119311596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
119411596SJason.Beloro@Sun.COM
119511596SJason.Beloro@Sun.COM {PCIE_AER_UCE_DLP, pf_panic,
119611596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
119711596SJason.Beloro@Sun.COM
119811596SJason.Beloro@Sun.COM {PCIE_AER_UCE_SD, pf_no_panic,
119911596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
120011596SJason.Beloro@Sun.COM
120111596SJason.Beloro@Sun.COM {PCIE_AER_UCE_PTLP, pf_analyse_ptlp,
120211596SJason.Beloro@Sun.COM PF_AFFECTED_AER, PF_AFFECTED_CHILDREN},
120311596SJason.Beloro@Sun.COM
120411596SJason.Beloro@Sun.COM {PCIE_AER_UCE_FCP, pf_panic,
120511596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
120611596SJason.Beloro@Sun.COM
120711596SJason.Beloro@Sun.COM {PCIE_AER_UCE_TO, pf_panic,
120811596SJason.Beloro@Sun.COM PF_AFFECTED_ADDR, PF_AFFECTED_CHILDREN},
120911596SJason.Beloro@Sun.COM
121011596SJason.Beloro@Sun.COM {PCIE_AER_UCE_CA, pf_no_panic,
121111596SJason.Beloro@Sun.COM PF_AFFECTED_AER, PF_AFFECTED_CHILDREN},
121211596SJason.Beloro@Sun.COM
121311596SJason.Beloro@Sun.COM {PCIE_AER_UCE_UC, pf_analyse_uc,
121411596SJason.Beloro@Sun.COM 0, 0},
121511596SJason.Beloro@Sun.COM
121611596SJason.Beloro@Sun.COM {PCIE_AER_UCE_RO, pf_panic,
121711596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
121811596SJason.Beloro@Sun.COM
121911596SJason.Beloro@Sun.COM {PCIE_AER_UCE_MTLP, pf_panic,
122011596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_AER,
122111596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN},
122211596SJason.Beloro@Sun.COM
122311596SJason.Beloro@Sun.COM {PCIE_AER_UCE_ECRC, pf_panic,
122411596SJason.Beloro@Sun.COM PF_AFFECTED_AER, PF_AFFECTED_CHILDREN},
122511596SJason.Beloro@Sun.COM
122611596SJason.Beloro@Sun.COM {PCIE_AER_UCE_UR, pf_no_panic,
122711596SJason.Beloro@Sun.COM PF_AFFECTED_AER, PF_AFFECTED_CHILDREN},
122811596SJason.Beloro@Sun.COM
122911596SJason.Beloro@Sun.COM {NULL, NULL, NULL, NULL}
123010187SKrishna.Elango@Sun.COM };
123110187SKrishna.Elango@Sun.COM
123210187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_sw_tbl[] = {
123311596SJason.Beloro@Sun.COM {PCIE_AER_UCE_TRAINING, pf_no_panic,
123411596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
123511596SJason.Beloro@Sun.COM
123611596SJason.Beloro@Sun.COM {PCIE_AER_UCE_DLP, pf_panic,
123711596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
123811596SJason.Beloro@Sun.COM
123911596SJason.Beloro@Sun.COM {PCIE_AER_UCE_SD, pf_no_panic,
124011596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
124111596SJason.Beloro@Sun.COM
124211596SJason.Beloro@Sun.COM {PCIE_AER_UCE_PTLP, pf_analyse_ptlp,
124311596SJason.Beloro@Sun.COM PF_AFFECTED_AER, PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN},
124411596SJason.Beloro@Sun.COM
124511596SJason.Beloro@Sun.COM {PCIE_AER_UCE_FCP, pf_panic,
124611596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
124711596SJason.Beloro@Sun.COM
124811596SJason.Beloro@Sun.COM {PCIE_AER_UCE_TO, pf_analyse_to,
124911596SJason.Beloro@Sun.COM PF_AFFECTED_CHILDREN, 0},
125011596SJason.Beloro@Sun.COM
125111596SJason.Beloro@Sun.COM {PCIE_AER_UCE_CA, pf_analyse_ca_ur,
125211596SJason.Beloro@Sun.COM PF_AFFECTED_AER, PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN},
125311596SJason.Beloro@Sun.COM
125411596SJason.Beloro@Sun.COM {PCIE_AER_UCE_UC, pf_analyse_uc,
125511596SJason.Beloro@Sun.COM 0, 0},
125611596SJason.Beloro@Sun.COM
125711596SJason.Beloro@Sun.COM {PCIE_AER_UCE_RO, pf_panic,
125811596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
125911596SJason.Beloro@Sun.COM
126011596SJason.Beloro@Sun.COM {PCIE_AER_UCE_MTLP, pf_panic,
126111596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_AER,
126211596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN},
126311596SJason.Beloro@Sun.COM
126411596SJason.Beloro@Sun.COM {PCIE_AER_UCE_ECRC, pf_panic,
126511596SJason.Beloro@Sun.COM PF_AFFECTED_AER, PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN},
126611596SJason.Beloro@Sun.COM
126711596SJason.Beloro@Sun.COM {PCIE_AER_UCE_UR, pf_analyse_ca_ur,
126811596SJason.Beloro@Sun.COM PF_AFFECTED_AER, PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN},
126911596SJason.Beloro@Sun.COM
127011596SJason.Beloro@Sun.COM {NULL, NULL, NULL, NULL}
127110187SKrishna.Elango@Sun.COM };
127210187SKrishna.Elango@Sun.COM
127310187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_pcie_bdg_tbl[] = {
127411596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_TA_ON_SC, pf_analyse_sc,
127511596SJason.Beloro@Sun.COM 0, 0},
127611596SJason.Beloro@Sun.COM
127711596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_MA_ON_SC, pf_analyse_sc,
127811596SJason.Beloro@Sun.COM 0, 0},
127911596SJason.Beloro@Sun.COM
128011596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_RCVD_TA, pf_analyse_ma_ta,
128111596SJason.Beloro@Sun.COM 0, 0},
128211596SJason.Beloro@Sun.COM
128311596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_RCVD_MA, pf_analyse_ma_ta,
128411596SJason.Beloro@Sun.COM 0, 0},
128511596SJason.Beloro@Sun.COM
128611596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_USC_ERR, pf_panic,
128711596SJason.Beloro@Sun.COM PF_AFFECTED_SAER, PF_AFFECTED_CHILDREN},
128811596SJason.Beloro@Sun.COM
128911596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_USC_MSG_DATA_ERR, pf_analyse_ma_ta,
129011596SJason.Beloro@Sun.COM PF_AFFECTED_SAER, PF_AFFECTED_CHILDREN},
129111596SJason.Beloro@Sun.COM
129211596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_UC_DATA_ERR, pf_analyse_uc_data,
129311596SJason.Beloro@Sun.COM PF_AFFECTED_SAER, PF_AFFECTED_CHILDREN},
129411596SJason.Beloro@Sun.COM
129511596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_UC_ATTR_ERR, pf_panic,
129611596SJason.Beloro@Sun.COM PF_AFFECTED_CHILDREN, 0},
129711596SJason.Beloro@Sun.COM
129811596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_UC_ADDR_ERR, pf_panic,
129911596SJason.Beloro@Sun.COM PF_AFFECTED_CHILDREN, 0},
130011596SJason.Beloro@Sun.COM
130111596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_TIMER_EXPIRED, pf_panic,
130211596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
130311596SJason.Beloro@Sun.COM
130411596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_PERR_ASSERT, pf_analyse_perr_assert,
130511596SJason.Beloro@Sun.COM 0, 0},
130611596SJason.Beloro@Sun.COM
130711596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_SERR_ASSERT, pf_no_panic,
130811596SJason.Beloro@Sun.COM 0, 0},
130911596SJason.Beloro@Sun.COM
131011596SJason.Beloro@Sun.COM {PCIE_AER_SUCE_INTERNAL_ERR, pf_panic,
131111596SJason.Beloro@Sun.COM PF_AFFECTED_SELF | PF_AFFECTED_CHILDREN, 0},
131211596SJason.Beloro@Sun.COM
131311596SJason.Beloro@Sun.COM {NULL, NULL, NULL, NULL}
131410187SKrishna.Elango@Sun.COM };
131510187SKrishna.Elango@Sun.COM
131610187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_pci_bdg_tbl[] = {
131711596SJason.Beloro@Sun.COM {PCI_STAT_PERROR, pf_analyse_pci,
131811596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
131911596SJason.Beloro@Sun.COM
132011596SJason.Beloro@Sun.COM {PCI_STAT_S_PERROR, pf_analyse_pci,
132111596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
132211596SJason.Beloro@Sun.COM
132311596SJason.Beloro@Sun.COM {PCI_STAT_S_SYSERR, pf_panic,
132411596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
132511596SJason.Beloro@Sun.COM
132611596SJason.Beloro@Sun.COM {PCI_STAT_R_MAST_AB, pf_analyse_pci,
132711596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
132811596SJason.Beloro@Sun.COM
132911596SJason.Beloro@Sun.COM {PCI_STAT_R_TARG_AB, pf_analyse_pci,
133011596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
133111596SJason.Beloro@Sun.COM
133211596SJason.Beloro@Sun.COM {PCI_STAT_S_TARG_AB, pf_analyse_pci,
133311596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
133411596SJason.Beloro@Sun.COM
133511596SJason.Beloro@Sun.COM {NULL, NULL, NULL, NULL}
133610187SKrishna.Elango@Sun.COM };
133710187SKrishna.Elango@Sun.COM
133810187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t pcie_pci_tbl[] = {
133911596SJason.Beloro@Sun.COM {PCI_STAT_PERROR, pf_analyse_pci,
134011596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
134111596SJason.Beloro@Sun.COM
134211596SJason.Beloro@Sun.COM {PCI_STAT_S_PERROR, pf_analyse_pci,
134311596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
134411596SJason.Beloro@Sun.COM
134511596SJason.Beloro@Sun.COM {PCI_STAT_S_SYSERR, pf_panic,
134611596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
134711596SJason.Beloro@Sun.COM
134811596SJason.Beloro@Sun.COM {PCI_STAT_R_MAST_AB, pf_analyse_pci,
134911596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
135011596SJason.Beloro@Sun.COM
135111596SJason.Beloro@Sun.COM {PCI_STAT_R_TARG_AB, pf_analyse_pci,
135211596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
135311596SJason.Beloro@Sun.COM
135411596SJason.Beloro@Sun.COM {PCI_STAT_S_TARG_AB, pf_analyse_pci,
135511596SJason.Beloro@Sun.COM PF_AFFECTED_SELF, 0},
135611596SJason.Beloro@Sun.COM
135711596SJason.Beloro@Sun.COM {NULL, NULL, NULL, NULL}
135810187SKrishna.Elango@Sun.COM };
135910187SKrishna.Elango@Sun.COM
136010187SKrishna.Elango@Sun.COM #define PF_MASKED_AER_ERR(pfd_p) \
136110187SKrishna.Elango@Sun.COM (PCIE_ADV_REG(pfd_p)->pcie_ue_status & \
136210187SKrishna.Elango@Sun.COM ((PCIE_ADV_REG(pfd_p)->pcie_ue_mask) ^ 0xFFFFFFFF))
136310187SKrishna.Elango@Sun.COM #define PF_MASKED_SAER_ERR(pfd_p) \
136410187SKrishna.Elango@Sun.COM (PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status & \
136510187SKrishna.Elango@Sun.COM ((PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_mask) ^ 0xFFFFFFFF))
136610187SKrishna.Elango@Sun.COM /*
136710187SKrishna.Elango@Sun.COM * Analyse all the PCIe Fault Data (erpt) gathered during dispatch in the erpt
136810187SKrishna.Elango@Sun.COM * Queue.
136910187SKrishna.Elango@Sun.COM */
137010187SKrishna.Elango@Sun.COM static int
pf_analyse_error(ddi_fm_error_t * derr,pf_impl_t * impl)137110187SKrishna.Elango@Sun.COM pf_analyse_error(ddi_fm_error_t *derr, pf_impl_t *impl)
137210187SKrishna.Elango@Sun.COM {
137310187SKrishna.Elango@Sun.COM int sts_flags, error_flags = 0;
137410187SKrishna.Elango@Sun.COM pf_data_t *pfd_p;
137510187SKrishna.Elango@Sun.COM
137610187SKrishna.Elango@Sun.COM for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) {
137710187SKrishna.Elango@Sun.COM sts_flags = 0;
137810187SKrishna.Elango@Sun.COM
137911596SJason.Beloro@Sun.COM /* skip analysing error when no error info is gathered */
138011596SJason.Beloro@Sun.COM if (pfd_p->pe_severity_flags == PF_ERR_PANIC_BAD_RESPONSE)
138111596SJason.Beloro@Sun.COM goto done;
138211596SJason.Beloro@Sun.COM
138310187SKrishna.Elango@Sun.COM switch (PCIE_PFD2BUS(pfd_p)->bus_dev_type) {
138410187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
138510187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI_DEV:
138610187SKrishna.Elango@Sun.COM if (PCIE_DEVSTS_CE_DETECTED &
138710187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status)
138810187SKrishna.Elango@Sun.COM sts_flags |= PF_ERR_CE;
138910187SKrishna.Elango@Sun.COM
139010187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pfd_p);
139110187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl,
139210187SKrishna.Elango@Sun.COM pfd_p, pcie_pcie_tbl, PF_MASKED_AER_ERR(pfd_p));
139310187SKrishna.Elango@Sun.COM break;
139410187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_ROOT:
139510187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pfd_p);
139610187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl,
139710187SKrishna.Elango@Sun.COM pfd_p, pcie_rp_tbl, PF_MASKED_AER_ERR(pfd_p));
139810187SKrishna.Elango@Sun.COM break;
139910187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO:
140010187SKrishna.Elango@Sun.COM /* no adjust_for_aer for pseudo RC */
140111596SJason.Beloro@Sun.COM /* keep the severity passed on from RC if any */
140211596SJason.Beloro@Sun.COM sts_flags |= pfd_p->pe_severity_flags;
140310187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl, pfd_p,
140410187SKrishna.Elango@Sun.COM pcie_rp_tbl, PF_MASKED_AER_ERR(pfd_p));
140510187SKrishna.Elango@Sun.COM break;
140610187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_UP:
140710187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_DOWN:
140810187SKrishna.Elango@Sun.COM if (PCIE_DEVSTS_CE_DETECTED &
140910187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status)
141010187SKrishna.Elango@Sun.COM sts_flags |= PF_ERR_CE;
141110187SKrishna.Elango@Sun.COM
141210187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pfd_p);
141310187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl,
141410187SKrishna.Elango@Sun.COM pfd_p, pcie_sw_tbl, PF_MASKED_AER_ERR(pfd_p));
141510187SKrishna.Elango@Sun.COM break;
141610187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
141710187SKrishna.Elango@Sun.COM if (PCIE_DEVSTS_CE_DETECTED &
141810187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status)
141910187SKrishna.Elango@Sun.COM sts_flags |= PF_ERR_CE;
142010187SKrishna.Elango@Sun.COM
142110187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pfd_p);
142210187SKrishna.Elango@Sun.COM pf_adjust_for_no_saer(pfd_p);
142310187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr,
142410187SKrishna.Elango@Sun.COM impl, pfd_p, pcie_pcie_tbl,
142510187SKrishna.Elango@Sun.COM PF_MASKED_AER_ERR(pfd_p));
142610187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr,
142710187SKrishna.Elango@Sun.COM impl, pfd_p, pcie_pcie_bdg_tbl,
142810187SKrishna.Elango@Sun.COM PF_MASKED_SAER_ERR(pfd_p));
142910187SKrishna.Elango@Sun.COM /*
143010187SKrishna.Elango@Sun.COM * Some non-compliant PCIe devices do not utilize PCIe
143110187SKrishna.Elango@Sun.COM * error registers. So fallthrough and rely on legacy
143210187SKrishna.Elango@Sun.COM * PCI error registers.
143310187SKrishna.Elango@Sun.COM */
143410187SKrishna.Elango@Sun.COM if ((PCIE_DEVSTS_NFE_DETECTED | PCIE_DEVSTS_FE_DETECTED)
143510187SKrishna.Elango@Sun.COM & PCIE_ERR_REG(pfd_p)->pcie_err_status)
143610187SKrishna.Elango@Sun.COM break;
143710187SKrishna.Elango@Sun.COM /* FALLTHROUGH */
143810187SKrishna.Elango@Sun.COM case PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO:
143910187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr, impl,
144010187SKrishna.Elango@Sun.COM pfd_p, pcie_pci_tbl,
144110187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p)->pci_err_status);
144210187SKrishna.Elango@Sun.COM
144310187SKrishna.Elango@Sun.COM if (!PCIE_IS_BDG(PCIE_PFD2BUS(pfd_p)))
144410187SKrishna.Elango@Sun.COM break;
144510187SKrishna.Elango@Sun.COM
144610187SKrishna.Elango@Sun.COM sts_flags |= pf_analyse_error_tbl(derr,
144710187SKrishna.Elango@Sun.COM impl, pfd_p, pcie_pci_bdg_tbl,
144810187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat);
144910187SKrishna.Elango@Sun.COM }
145010187SKrishna.Elango@Sun.COM
145110187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = sts_flags;
145211596SJason.Beloro@Sun.COM
145311596SJason.Beloro@Sun.COM done:
145411596SJason.Beloro@Sun.COM pfd_p->pe_orig_severity_flags = pfd_p->pe_severity_flags;
145511596SJason.Beloro@Sun.COM /* Have pciev_eh adjust the severity */
145611596SJason.Beloro@Sun.COM pfd_p->pe_severity_flags = pciev_eh(pfd_p, impl);
145711596SJason.Beloro@Sun.COM
145810187SKrishna.Elango@Sun.COM error_flags |= pfd_p->pe_severity_flags;
145910187SKrishna.Elango@Sun.COM }
146010187SKrishna.Elango@Sun.COM
146110187SKrishna.Elango@Sun.COM return (error_flags);
146210187SKrishna.Elango@Sun.COM }
146310187SKrishna.Elango@Sun.COM
146410187SKrishna.Elango@Sun.COM static int
pf_analyse_error_tbl(ddi_fm_error_t * derr,pf_impl_t * impl,pf_data_t * pfd_p,const pf_fab_err_tbl_t * tbl,uint32_t err_reg)146510187SKrishna.Elango@Sun.COM pf_analyse_error_tbl(ddi_fm_error_t *derr, pf_impl_t *impl,
146611596SJason.Beloro@Sun.COM pf_data_t *pfd_p, const pf_fab_err_tbl_t *tbl, uint32_t err_reg)
146711596SJason.Beloro@Sun.COM {
146810187SKrishna.Elango@Sun.COM const pf_fab_err_tbl_t *row;
146910187SKrishna.Elango@Sun.COM int err = 0;
147011596SJason.Beloro@Sun.COM uint16_t flags;
147111596SJason.Beloro@Sun.COM uint32_t bit;
147211596SJason.Beloro@Sun.COM
147311596SJason.Beloro@Sun.COM for (row = tbl; err_reg && (row->bit != NULL); row++) {
147411596SJason.Beloro@Sun.COM bit = row->bit;
147511596SJason.Beloro@Sun.COM if (!(err_reg & bit))
147611596SJason.Beloro@Sun.COM continue;
147711596SJason.Beloro@Sun.COM err |= row->handler(derr, bit, impl->pf_dq_head_p, pfd_p);
147811596SJason.Beloro@Sun.COM
147911596SJason.Beloro@Sun.COM flags = row->affected_flags;
148011596SJason.Beloro@Sun.COM /*
148111596SJason.Beloro@Sun.COM * check if the primary flag is valid;
148211596SJason.Beloro@Sun.COM * if not, use the secondary flag
148311596SJason.Beloro@Sun.COM */
148411596SJason.Beloro@Sun.COM if (flags & PF_AFFECTED_AER) {
148511596SJason.Beloro@Sun.COM if (!HAS_AER_LOGS(pfd_p, bit)) {
148611596SJason.Beloro@Sun.COM flags = row->sec_affected_flags;
148711596SJason.Beloro@Sun.COM }
148811596SJason.Beloro@Sun.COM } else if (flags & PF_AFFECTED_SAER) {
148911596SJason.Beloro@Sun.COM if (!HAS_SAER_LOGS(pfd_p, bit)) {
149011596SJason.Beloro@Sun.COM flags = row->sec_affected_flags;
149111596SJason.Beloro@Sun.COM }
149211596SJason.Beloro@Sun.COM } else if (flags & PF_AFFECTED_ADDR) {
149311596SJason.Beloro@Sun.COM /* only Root has this flag */
149411596SJason.Beloro@Sun.COM if (PCIE_ROOT_FAULT(pfd_p)->scan_addr == 0) {
149511596SJason.Beloro@Sun.COM flags = row->sec_affected_flags;
149611596SJason.Beloro@Sun.COM }
149711596SJason.Beloro@Sun.COM }
149811596SJason.Beloro@Sun.COM
149911596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags |= flags;
150010187SKrishna.Elango@Sun.COM }
150110187SKrishna.Elango@Sun.COM
150210187SKrishna.Elango@Sun.COM if (!err)
150310187SKrishna.Elango@Sun.COM err = PF_ERR_NO_ERROR;
150410187SKrishna.Elango@Sun.COM
150510187SKrishna.Elango@Sun.COM return (err);
150610187SKrishna.Elango@Sun.COM }
150710187SKrishna.Elango@Sun.COM
150810187SKrishna.Elango@Sun.COM /*
150910187SKrishna.Elango@Sun.COM * PCIe Completer Abort and Unsupport Request error analyser. If a PCIe device
151010187SKrishna.Elango@Sun.COM * issues a CA/UR a corresponding Received CA/UR should have been seen in the
151110187SKrishna.Elango@Sun.COM * PCIe root complex. Check to see if RC did indeed receive a CA/UR, if so then
151210187SKrishna.Elango@Sun.COM * this error may be safely ignored. If not check the logs and see if an
151310187SKrishna.Elango@Sun.COM * associated handler for this transaction can be found.
151410187SKrishna.Elango@Sun.COM */
151510187SKrishna.Elango@Sun.COM /* ARGSUSED */
151610187SKrishna.Elango@Sun.COM static int
pf_analyse_ca_ur(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)151710187SKrishna.Elango@Sun.COM pf_analyse_ca_ur(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
151810187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
151910187SKrishna.Elango@Sun.COM {
152010187SKrishna.Elango@Sun.COM uint32_t abort_type;
152110187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
152210187SKrishna.Elango@Sun.COM
152310187SKrishna.Elango@Sun.COM /* If UR's are masked forgive this error */
152410187SKrishna.Elango@Sun.COM if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) &&
152510187SKrishna.Elango@Sun.COM (bit == PCIE_AER_UCE_UR))
152610187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC);
152710187SKrishna.Elango@Sun.COM
152810187SKrishna.Elango@Sun.COM /*
152910187SKrishna.Elango@Sun.COM * If a RP has an CA/UR it means a leaf sent a bad request to the RP
153010187SKrishna.Elango@Sun.COM * such as a config read or a bad DMA address.
153110187SKrishna.Elango@Sun.COM */
153210187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(PCIE_PFD2BUS(pfd_p)))
153310187SKrishna.Elango@Sun.COM goto handle_lookup;
153410187SKrishna.Elango@Sun.COM
153510187SKrishna.Elango@Sun.COM if (bit == PCIE_AER_UCE_UR)
153610187SKrishna.Elango@Sun.COM abort_type = PCI_STAT_R_MAST_AB;
153710187SKrishna.Elango@Sun.COM else
153810187SKrishna.Elango@Sun.COM abort_type = PCI_STAT_R_TARG_AB;
153910187SKrishna.Elango@Sun.COM
154010187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, abort_type))
154110187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_RC);
154210187SKrishna.Elango@Sun.COM
154310187SKrishna.Elango@Sun.COM handle_lookup:
154410187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, bit) &&
154510187SKrishna.Elango@Sun.COM pf_log_hdl_lookup(rpdip, derr, pfd_p, B_TRUE) == PF_HDL_FOUND)
154610187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE);
154710187SKrishna.Elango@Sun.COM
154810187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
154910187SKrishna.Elango@Sun.COM }
155010187SKrishna.Elango@Sun.COM
155110187SKrishna.Elango@Sun.COM /*
155210187SKrishna.Elango@Sun.COM * PCIe-PCI Bridge Received Master Abort and Target error analyser. If a PCIe
155310187SKrishna.Elango@Sun.COM * Bridge receives a MA/TA a corresponding sent CA/UR should have been seen in
155410187SKrishna.Elango@Sun.COM * the PCIe root complex. Check to see if RC did indeed receive a CA/UR, if so
155510187SKrishna.Elango@Sun.COM * then this error may be safely ignored. If not check the logs and see if an
155610187SKrishna.Elango@Sun.COM * associated handler for this transaction can be found.
155710187SKrishna.Elango@Sun.COM */
155810187SKrishna.Elango@Sun.COM /* ARGSUSED */
155910187SKrishna.Elango@Sun.COM static int
pf_analyse_ma_ta(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)156010187SKrishna.Elango@Sun.COM pf_analyse_ma_ta(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
156110187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
156210187SKrishna.Elango@Sun.COM {
156310187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
156410187SKrishna.Elango@Sun.COM uint32_t abort_type;
156510187SKrishna.Elango@Sun.COM
156610187SKrishna.Elango@Sun.COM /* If UR's are masked forgive this error */
156710187SKrishna.Elango@Sun.COM if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) &&
156810187SKrishna.Elango@Sun.COM (bit == PCIE_AER_SUCE_RCVD_MA))
156910187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC);
157010187SKrishna.Elango@Sun.COM
157110187SKrishna.Elango@Sun.COM if (bit == PCIE_AER_SUCE_RCVD_MA)
157210187SKrishna.Elango@Sun.COM abort_type = PCI_STAT_R_MAST_AB;
157310187SKrishna.Elango@Sun.COM else
157410187SKrishna.Elango@Sun.COM abort_type = PCI_STAT_R_TARG_AB;
157510187SKrishna.Elango@Sun.COM
157610187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, abort_type))
157710187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_RC);
157810187SKrishna.Elango@Sun.COM
157910187SKrishna.Elango@Sun.COM if (!HAS_SAER_LOGS(pfd_p, bit))
158010187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
158110187SKrishna.Elango@Sun.COM
158210187SKrishna.Elango@Sun.COM if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE) == PF_HDL_FOUND)
158310187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE);
158410187SKrishna.Elango@Sun.COM
158510187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
158610187SKrishna.Elango@Sun.COM }
158710187SKrishna.Elango@Sun.COM
158810187SKrishna.Elango@Sun.COM /*
158910187SKrishna.Elango@Sun.COM * Generic PCI error analyser. This function is used for Parity Errors,
159010187SKrishna.Elango@Sun.COM * Received Master Aborts, Received Target Aborts, and Signaled Target Aborts.
159110187SKrishna.Elango@Sun.COM * In general PCI devices do not have error logs, it is very difficult to figure
159210187SKrishna.Elango@Sun.COM * out what transaction caused the error. Instead find the nearest PCIe-PCI
159310187SKrishna.Elango@Sun.COM * Bridge and check to see if it has logs and if it has an error associated with
159410187SKrishna.Elango@Sun.COM * this PCI Device.
159510187SKrishna.Elango@Sun.COM */
159610187SKrishna.Elango@Sun.COM /* ARGSUSED */
159710187SKrishna.Elango@Sun.COM static int
pf_analyse_pci(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)159810187SKrishna.Elango@Sun.COM pf_analyse_pci(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
159910187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
160010187SKrishna.Elango@Sun.COM {
160110187SKrishna.Elango@Sun.COM pf_data_t *parent_pfd_p;
160210187SKrishna.Elango@Sun.COM uint16_t cmd;
160310187SKrishna.Elango@Sun.COM uint32_t aer_ue_status;
160410187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_PFD2BUS(pfd_p);
160510187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *parent_saer_p;
160610187SKrishna.Elango@Sun.COM
160710187SKrishna.Elango@Sun.COM if (PCI_ERR_REG(pfd_p)->pci_err_status & PCI_STAT_S_SYSERR)
160810187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
160910187SKrishna.Elango@Sun.COM
161010187SKrishna.Elango@Sun.COM /* If UR's are masked forgive this error */
161110187SKrishna.Elango@Sun.COM if ((pcie_get_aer_uce_mask() & PCIE_AER_UCE_UR) &&
161210187SKrishna.Elango@Sun.COM (bit == PCI_STAT_R_MAST_AB))
161310187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC);
161410187SKrishna.Elango@Sun.COM
161510187SKrishna.Elango@Sun.COM
161610187SKrishna.Elango@Sun.COM if (bit & (PCI_STAT_PERROR | PCI_STAT_S_PERROR)) {
161710187SKrishna.Elango@Sun.COM aer_ue_status = PCIE_AER_SUCE_PERR_ASSERT;
161810187SKrishna.Elango@Sun.COM } else {
161910187SKrishna.Elango@Sun.COM aer_ue_status = (PCIE_AER_SUCE_TA_ON_SC |
162010187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MA_ON_SC | PCIE_AER_SUCE_RCVD_TA |
162110187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_RCVD_MA);
162210187SKrishna.Elango@Sun.COM }
162310187SKrishna.Elango@Sun.COM
162410187SKrishna.Elango@Sun.COM parent_pfd_p = pf_get_parent_pcie_bridge(pfd_p);
162510187SKrishna.Elango@Sun.COM if (parent_pfd_p == NULL)
162610187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
162710187SKrishna.Elango@Sun.COM
162810187SKrishna.Elango@Sun.COM /* Check if parent bridge has seen this error */
162910187SKrishna.Elango@Sun.COM parent_saer_p = PCIE_ADV_BDG_REG(parent_pfd_p);
163010187SKrishna.Elango@Sun.COM if (!(parent_saer_p->pcie_sue_status & aer_ue_status) ||
163110187SKrishna.Elango@Sun.COM !HAS_SAER_LOGS(parent_pfd_p, aer_ue_status))
163210187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
163310187SKrishna.Elango@Sun.COM
163410187SKrishna.Elango@Sun.COM /*
163510187SKrishna.Elango@Sun.COM * If the addr or bdf from the parent PCIe bridge logs belong to this
163610187SKrishna.Elango@Sun.COM * PCI device, assume the PCIe bridge's error handling has already taken
163710187SKrishna.Elango@Sun.COM * care of this PCI device's error.
163810187SKrishna.Elango@Sun.COM */
163910187SKrishna.Elango@Sun.COM if (pf_pci_decode(parent_pfd_p, &cmd) != DDI_SUCCESS)
164010187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
164110187SKrishna.Elango@Sun.COM
164210187SKrishna.Elango@Sun.COM if ((parent_saer_p->pcie_sue_tgt_bdf == bus_p->bus_bdf) ||
164310187SKrishna.Elango@Sun.COM pf_in_addr_range(bus_p, parent_saer_p->pcie_sue_tgt_addr))
164410187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_PARENT);
164510187SKrishna.Elango@Sun.COM
164610187SKrishna.Elango@Sun.COM /*
164710187SKrishna.Elango@Sun.COM * If this device is a PCI-PCI bridge, check if the bdf in the parent
164810187SKrishna.Elango@Sun.COM * PCIe bridge logs is in the range of this PCI-PCI Bridge's bus ranges.
164910187SKrishna.Elango@Sun.COM * If they are, then assume the PCIe bridge's error handling has already
165010187SKrishna.Elango@Sun.COM * taken care of this PCI-PCI bridge device's error.
165110187SKrishna.Elango@Sun.COM */
165210187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p) &&
165310187SKrishna.Elango@Sun.COM pf_in_bus_range(bus_p, parent_saer_p->pcie_sue_tgt_bdf))
165410187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_PARENT);
165510187SKrishna.Elango@Sun.COM
165610187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
165710187SKrishna.Elango@Sun.COM }
165810187SKrishna.Elango@Sun.COM
165910187SKrishna.Elango@Sun.COM /*
166010187SKrishna.Elango@Sun.COM * PCIe Bridge transactions associated with PERR.
166110187SKrishna.Elango@Sun.COM * o Bridge received a poisoned Non-Posted Write (CFG Writes) from PCIe
166210187SKrishna.Elango@Sun.COM * o Bridge received a poisoned Posted Write from (MEM Writes) from PCIe
166310187SKrishna.Elango@Sun.COM * o Bridge received a poisoned Completion on a Split Transction from PCIe
166410187SKrishna.Elango@Sun.COM * o Bridge received a poisoned Completion on a Delayed Transction from PCIe
166510187SKrishna.Elango@Sun.COM *
166610187SKrishna.Elango@Sun.COM * Check for non-poisoned PCIe transactions that got forwarded to the secondary
166710187SKrishna.Elango@Sun.COM * side and detects a PERR#. Except for delayed read completions, a poisoned
166810187SKrishna.Elango@Sun.COM * TLP will be forwarded to the secondary bus and PERR# will be asserted.
166910187SKrishna.Elango@Sun.COM */
167010187SKrishna.Elango@Sun.COM /* ARGSUSED */
167110187SKrishna.Elango@Sun.COM static int
pf_analyse_perr_assert(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)167210187SKrishna.Elango@Sun.COM pf_analyse_perr_assert(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
167310187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
167410187SKrishna.Elango@Sun.COM {
167510187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
167610187SKrishna.Elango@Sun.COM uint16_t cmd;
167710187SKrishna.Elango@Sun.COM int hdl_sts = PF_HDL_NOTFOUND;
167810187SKrishna.Elango@Sun.COM int err = PF_ERR_NO_ERROR;
167910187SKrishna.Elango@Sun.COM pf_pcie_adv_bdg_err_regs_t *saer_p;
168010187SKrishna.Elango@Sun.COM
168110187SKrishna.Elango@Sun.COM
168210187SKrishna.Elango@Sun.COM if (HAS_SAER_LOGS(pfd_p, bit)) {
168310187SKrishna.Elango@Sun.COM saer_p = PCIE_ADV_BDG_REG(pfd_p);
168410187SKrishna.Elango@Sun.COM if (pf_pci_decode(pfd_p, &cmd) != DDI_SUCCESS)
168510187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
168610187SKrishna.Elango@Sun.COM
168710187SKrishna.Elango@Sun.COM cmd_switch:
168810187SKrishna.Elango@Sun.COM switch (cmd) {
168910187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_IOWR:
169010187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWR:
169110187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWR_BL:
169210187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWRBL:
169310187SKrishna.Elango@Sun.COM /* Posted Writes Transactions */
169410187SKrishna.Elango@Sun.COM if (saer_p->pcie_sue_tgt_trans == PF_ADDR_PIO)
169510187SKrishna.Elango@Sun.COM hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p,
169610187SKrishna.Elango@Sun.COM B_FALSE);
169710187SKrishna.Elango@Sun.COM break;
169810187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_CFWR:
169910187SKrishna.Elango@Sun.COM /*
170010187SKrishna.Elango@Sun.COM * Check to see if it is a non-posted write. If so, a
170110187SKrishna.Elango@Sun.COM * UR Completion would have been sent.
170210187SKrishna.Elango@Sun.COM */
170310187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p,
170410187SKrishna.Elango@Sun.COM PCI_STAT_R_MAST_AB)) {
170510187SKrishna.Elango@Sun.COM hdl_sts = PF_HDL_FOUND;
170610187SKrishna.Elango@Sun.COM err = PF_ERR_MATCHED_RC;
170710187SKrishna.Elango@Sun.COM goto done;
170810187SKrishna.Elango@Sun.COM }
170910187SKrishna.Elango@Sun.COM hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p,
171010187SKrishna.Elango@Sun.COM B_FALSE);
171110187SKrishna.Elango@Sun.COM break;
171210187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_SPL:
171310187SKrishna.Elango@Sun.COM hdl_sts = pf_log_hdl_lookup(rpdip, derr, pfd_p,
171410187SKrishna.Elango@Sun.COM B_FALSE);
171510187SKrishna.Elango@Sun.COM break;
171610187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_DADR:
171710187SKrishna.Elango@Sun.COM cmd = (PCIE_ADV_BDG_HDR(pfd_p, 1) >>
171810187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) &
171910187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_UP_MASK;
172010187SKrishna.Elango@Sun.COM if (cmd != PCI_PCIX_CMD_DADR)
172110187SKrishna.Elango@Sun.COM goto cmd_switch;
172210187SKrishna.Elango@Sun.COM /* FALLTHROUGH */
172310187SKrishna.Elango@Sun.COM default:
172410187SKrishna.Elango@Sun.COM /* Unexpected situation, panic */
172510187SKrishna.Elango@Sun.COM hdl_sts = PF_HDL_NOTFOUND;
172610187SKrishna.Elango@Sun.COM }
172710187SKrishna.Elango@Sun.COM
172810187SKrishna.Elango@Sun.COM if (hdl_sts == PF_HDL_FOUND)
172910187SKrishna.Elango@Sun.COM err = PF_ERR_MATCHED_DEVICE;
173010187SKrishna.Elango@Sun.COM else
173110187SKrishna.Elango@Sun.COM err = PF_ERR_PANIC;
173210187SKrishna.Elango@Sun.COM } else {
173310187SKrishna.Elango@Sun.COM /*
173410187SKrishna.Elango@Sun.COM * Check to see if it is a non-posted write. If so, a UR
173510187SKrishna.Elango@Sun.COM * Completion would have been sent.
173610187SKrishna.Elango@Sun.COM */
173710187SKrishna.Elango@Sun.COM if ((PCIE_ERR_REG(pfd_p)->pcie_err_status &
173810187SKrishna.Elango@Sun.COM PCIE_DEVSTS_UR_DETECTED) &&
173910187SKrishna.Elango@Sun.COM pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_R_MAST_AB))
174010187SKrishna.Elango@Sun.COM err = PF_ERR_MATCHED_RC;
174110187SKrishna.Elango@Sun.COM
174210187SKrishna.Elango@Sun.COM /* Check for posted writes. Transaction is lost. */
174310187SKrishna.Elango@Sun.COM if (PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat &
174410187SKrishna.Elango@Sun.COM PCI_STAT_S_PERROR)
174510187SKrishna.Elango@Sun.COM err = PF_ERR_PANIC;
174610187SKrishna.Elango@Sun.COM
174710187SKrishna.Elango@Sun.COM /*
174810187SKrishna.Elango@Sun.COM * All other scenarios are due to read completions. Check for
174910187SKrishna.Elango@Sun.COM * PERR on the primary side. If found the primary side error
175010187SKrishna.Elango@Sun.COM * handling will take care of this error.
175110187SKrishna.Elango@Sun.COM */
175210187SKrishna.Elango@Sun.COM if (err == PF_ERR_NO_ERROR) {
175310187SKrishna.Elango@Sun.COM if (PCI_ERR_REG(pfd_p)->pci_err_status &
175410187SKrishna.Elango@Sun.COM PCI_STAT_PERROR)
175510187SKrishna.Elango@Sun.COM err = PF_ERR_MATCHED_PARENT;
175610187SKrishna.Elango@Sun.COM else
175710187SKrishna.Elango@Sun.COM err = PF_ERR_PANIC;
175810187SKrishna.Elango@Sun.COM }
175910187SKrishna.Elango@Sun.COM }
176010187SKrishna.Elango@Sun.COM
176110187SKrishna.Elango@Sun.COM done:
176210187SKrishna.Elango@Sun.COM return (err);
176310187SKrishna.Elango@Sun.COM }
176410187SKrishna.Elango@Sun.COM
176510187SKrishna.Elango@Sun.COM /*
176610187SKrishna.Elango@Sun.COM * PCIe Poisoned TLP error analyser. If a PCIe device receives a Poisoned TLP,
176710187SKrishna.Elango@Sun.COM * check the logs and see if an associated handler for this transaction can be
176810187SKrishna.Elango@Sun.COM * found.
176910187SKrishna.Elango@Sun.COM */
177010187SKrishna.Elango@Sun.COM /* ARGSUSED */
177110187SKrishna.Elango@Sun.COM static int
pf_analyse_ptlp(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)177210187SKrishna.Elango@Sun.COM pf_analyse_ptlp(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
177310187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
177410187SKrishna.Elango@Sun.COM {
177510187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
177610187SKrishna.Elango@Sun.COM
177710187SKrishna.Elango@Sun.COM /*
177810187SKrishna.Elango@Sun.COM * If AERs are supported find the logs in this device, otherwise look in
177910187SKrishna.Elango@Sun.COM * it's parent's logs.
178010187SKrishna.Elango@Sun.COM */
178110187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, bit)) {
178210187SKrishna.Elango@Sun.COM pcie_tlp_hdr_t *hdr = (pcie_tlp_hdr_t *)&PCIE_ADV_HDR(pfd_p, 0);
178310187SKrishna.Elango@Sun.COM
178410187SKrishna.Elango@Sun.COM /*
178510187SKrishna.Elango@Sun.COM * Double check that the log contains a poisoned TLP.
178610187SKrishna.Elango@Sun.COM * Some devices like PLX switch do not log poison TLP headers.
178710187SKrishna.Elango@Sun.COM */
178810187SKrishna.Elango@Sun.COM if (hdr->ep) {
178910187SKrishna.Elango@Sun.COM if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_TRUE) ==
179010187SKrishna.Elango@Sun.COM PF_HDL_FOUND)
179110187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE);
179210187SKrishna.Elango@Sun.COM }
179310187SKrishna.Elango@Sun.COM
179410187SKrishna.Elango@Sun.COM /*
179510187SKrishna.Elango@Sun.COM * If an address is found and hdl lookup failed panic.
179610187SKrishna.Elango@Sun.COM * Otherwise check parents to see if there was enough
179710187SKrishna.Elango@Sun.COM * information recover.
179810187SKrishna.Elango@Sun.COM */
179910187SKrishna.Elango@Sun.COM if (PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr)
180010187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
180110187SKrishna.Elango@Sun.COM }
180210187SKrishna.Elango@Sun.COM
180310187SKrishna.Elango@Sun.COM /*
180410187SKrishna.Elango@Sun.COM * Check to see if the rc has already handled this error or a parent has
180510187SKrishna.Elango@Sun.COM * already handled this error.
180610187SKrishna.Elango@Sun.COM *
180710187SKrishna.Elango@Sun.COM * If the error info in the RC wasn't enough to find the fault device,
180810187SKrishna.Elango@Sun.COM * such as if the faulting device lies behind a PCIe-PCI bridge from a
180910187SKrishna.Elango@Sun.COM * poisoned completion, check to see if the PCIe-PCI bridge has enough
181010187SKrishna.Elango@Sun.COM * info to recover. For completion TLP's, the AER header logs only
181110187SKrishna.Elango@Sun.COM * contain the faulting BDF in the Root Port. For PCIe device the fault
181210187SKrishna.Elango@Sun.COM * BDF is the fault device. But if the fault device is behind a
181310187SKrishna.Elango@Sun.COM * PCIe-PCI bridge the fault BDF could turn out just to be a PCIe-PCI
181410187SKrishna.Elango@Sun.COM * bridge's secondary bus number.
181510187SKrishna.Elango@Sun.COM */
181610187SKrishna.Elango@Sun.COM if (!PFD_IS_ROOT(pfd_p)) {
181710187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(PCIE_PFD2DIP(pfd_p));
181810187SKrishna.Elango@Sun.COM pf_data_t *parent_pfd_p;
181910187SKrishna.Elango@Sun.COM
182010187SKrishna.Elango@Sun.COM if (PCIE_PFD2BUS(pfd_p)->bus_rp_dip == pdip) {
182110187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_PERROR))
182210187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_RC);
182310187SKrishna.Elango@Sun.COM }
182410187SKrishna.Elango@Sun.COM
182510187SKrishna.Elango@Sun.COM parent_pfd_p = PCIE_DIP2PFD(pdip);
182610187SKrishna.Elango@Sun.COM
182710187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(parent_pfd_p, bit))
182810187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_PARENT);
182910187SKrishna.Elango@Sun.COM } else {
183010187SKrishna.Elango@Sun.COM pf_data_t *bdg_pfd_p;
183110187SKrishna.Elango@Sun.COM pcie_req_id_t secbus;
183210187SKrishna.Elango@Sun.COM
183310187SKrishna.Elango@Sun.COM /*
183410187SKrishna.Elango@Sun.COM * Looking for a pcie bridge only makes sense if the BDF
183510187SKrishna.Elango@Sun.COM * Dev/Func = 0/0
183610187SKrishna.Elango@Sun.COM */
183710187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p)))
183810187SKrishna.Elango@Sun.COM goto done;
183910187SKrishna.Elango@Sun.COM
184010187SKrishna.Elango@Sun.COM secbus = PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf;
184110187SKrishna.Elango@Sun.COM
184210187SKrishna.Elango@Sun.COM if (!PCIE_CHECK_VALID_BDF(secbus) || (secbus & 0xFF))
184310187SKrishna.Elango@Sun.COM goto done;
184410187SKrishna.Elango@Sun.COM
184510187SKrishna.Elango@Sun.COM bdg_pfd_p = pf_get_pcie_bridge(pfd_p, secbus);
184610187SKrishna.Elango@Sun.COM
184710187SKrishna.Elango@Sun.COM if (bdg_pfd_p && HAS_SAER_LOGS(bdg_pfd_p,
184810187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_PERR_ASSERT)) {
184910187SKrishna.Elango@Sun.COM return pf_analyse_perr_assert(derr,
185010187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_PERR_ASSERT, dq_head_p, pfd_p);
185110187SKrishna.Elango@Sun.COM }
185210187SKrishna.Elango@Sun.COM }
185310187SKrishna.Elango@Sun.COM done:
185410187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
185510187SKrishna.Elango@Sun.COM }
185610187SKrishna.Elango@Sun.COM
185710187SKrishna.Elango@Sun.COM /*
185810187SKrishna.Elango@Sun.COM * PCIe-PCI Bridge Received Master and Target abort error analyser on Split
185910187SKrishna.Elango@Sun.COM * Completions. If a PCIe Bridge receives a MA/TA check logs and see if an
186010187SKrishna.Elango@Sun.COM * associated handler for this transaction can be found.
186110187SKrishna.Elango@Sun.COM */
186210187SKrishna.Elango@Sun.COM /* ARGSUSED */
186310187SKrishna.Elango@Sun.COM static int
pf_analyse_sc(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)186410187SKrishna.Elango@Sun.COM pf_analyse_sc(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
186510187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
186610187SKrishna.Elango@Sun.COM {
186710187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
186810187SKrishna.Elango@Sun.COM uint16_t cmd;
186910187SKrishna.Elango@Sun.COM int sts = PF_HDL_NOTFOUND;
187010187SKrishna.Elango@Sun.COM
187110187SKrishna.Elango@Sun.COM if (!HAS_SAER_LOGS(pfd_p, bit))
187210187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
187310187SKrishna.Elango@Sun.COM
187410187SKrishna.Elango@Sun.COM if (pf_pci_decode(pfd_p, &cmd) != DDI_SUCCESS)
187510187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
187610187SKrishna.Elango@Sun.COM
187710187SKrishna.Elango@Sun.COM if (cmd == PCI_PCIX_CMD_SPL)
187810187SKrishna.Elango@Sun.COM sts = pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE);
187910187SKrishna.Elango@Sun.COM
188010187SKrishna.Elango@Sun.COM if (sts == PF_HDL_FOUND)
188110187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE);
188210187SKrishna.Elango@Sun.COM
188310187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
188410187SKrishna.Elango@Sun.COM }
188510187SKrishna.Elango@Sun.COM
188610187SKrishna.Elango@Sun.COM /*
188710187SKrishna.Elango@Sun.COM * PCIe Timeout error analyser. This error can be forgiven if it is marked as
188810187SKrishna.Elango@Sun.COM * CE Advisory. If it is marked as advisory, this means the HW can recover
188910187SKrishna.Elango@Sun.COM * and/or retry the transaction automatically.
189010187SKrishna.Elango@Sun.COM */
189110187SKrishna.Elango@Sun.COM /* ARGSUSED */
189210187SKrishna.Elango@Sun.COM static int
pf_analyse_to(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)189310187SKrishna.Elango@Sun.COM pf_analyse_to(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
189410187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
189510187SKrishna.Elango@Sun.COM {
189610187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, bit) && CE_ADVISORY(pfd_p))
189710187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC);
189810187SKrishna.Elango@Sun.COM
189910187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
190010187SKrishna.Elango@Sun.COM }
190110187SKrishna.Elango@Sun.COM
190210187SKrishna.Elango@Sun.COM /*
190310187SKrishna.Elango@Sun.COM * PCIe Unexpected Completion. Check to see if this TLP was misrouted by
190410187SKrishna.Elango@Sun.COM * matching the device BDF with the TLP Log. If misrouting panic, otherwise
190510187SKrishna.Elango@Sun.COM * don't panic.
190610187SKrishna.Elango@Sun.COM */
190710187SKrishna.Elango@Sun.COM /* ARGSUSED */
190810187SKrishna.Elango@Sun.COM static int
pf_analyse_uc(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)190910187SKrishna.Elango@Sun.COM pf_analyse_uc(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
191010187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
191110187SKrishna.Elango@Sun.COM {
191210187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, bit) &&
191310187SKrishna.Elango@Sun.COM (PCIE_PFD2BUS(pfd_p)->bus_bdf == (PCIE_ADV_HDR(pfd_p, 2) >> 16)))
191410187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC);
191510187SKrishna.Elango@Sun.COM
191611596SJason.Beloro@Sun.COM /*
191711596SJason.Beloro@Sun.COM * This is a case of mis-routing. Any of the switches above this
191811596SJason.Beloro@Sun.COM * device could be at fault.
191911596SJason.Beloro@Sun.COM */
192011596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_ROOT;
192111596SJason.Beloro@Sun.COM
192210187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
192310187SKrishna.Elango@Sun.COM }
192410187SKrishna.Elango@Sun.COM
192510187SKrishna.Elango@Sun.COM /*
192610187SKrishna.Elango@Sun.COM * PCIe-PCI Bridge Uncorrectable Data error analyser. All Uncorrectable Data
192710187SKrishna.Elango@Sun.COM * errors should have resulted in a PCIe Poisoned TLP to the RC, except for
192810187SKrishna.Elango@Sun.COM * Posted Writes. Check the logs for Posted Writes and if the RC did not see a
192910187SKrishna.Elango@Sun.COM * Poisoned TLP.
193010187SKrishna.Elango@Sun.COM *
193110187SKrishna.Elango@Sun.COM * Non-Posted Writes will also generate a UR in the completion status, which the
193210187SKrishna.Elango@Sun.COM * RC should also see.
193310187SKrishna.Elango@Sun.COM */
193410187SKrishna.Elango@Sun.COM /* ARGSUSED */
193510187SKrishna.Elango@Sun.COM static int
pf_analyse_uc_data(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)193610187SKrishna.Elango@Sun.COM pf_analyse_uc_data(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
193710187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
193810187SKrishna.Elango@Sun.COM {
193910187SKrishna.Elango@Sun.COM dev_info_t *rpdip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
194010187SKrishna.Elango@Sun.COM
194110187SKrishna.Elango@Sun.COM if (!HAS_SAER_LOGS(pfd_p, bit))
194210187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
194310187SKrishna.Elango@Sun.COM
194410187SKrishna.Elango@Sun.COM if (pf_matched_in_rc(dq_head_p, pfd_p, PCI_STAT_PERROR))
194510187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_RC);
194610187SKrishna.Elango@Sun.COM
194710187SKrishna.Elango@Sun.COM if (pf_log_hdl_lookup(rpdip, derr, pfd_p, B_FALSE) == PF_HDL_FOUND)
194810187SKrishna.Elango@Sun.COM return (PF_ERR_MATCHED_DEVICE);
194910187SKrishna.Elango@Sun.COM
195010187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
195110187SKrishna.Elango@Sun.COM }
195210187SKrishna.Elango@Sun.COM
195310187SKrishna.Elango@Sun.COM /* ARGSUSED */
195410187SKrishna.Elango@Sun.COM static int
pf_no_panic(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)195510187SKrishna.Elango@Sun.COM pf_no_panic(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
195610187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
195710187SKrishna.Elango@Sun.COM {
195810187SKrishna.Elango@Sun.COM return (PF_ERR_NO_PANIC);
195910187SKrishna.Elango@Sun.COM }
196010187SKrishna.Elango@Sun.COM
196110187SKrishna.Elango@Sun.COM /* ARGSUSED */
196210187SKrishna.Elango@Sun.COM static int
pf_panic(ddi_fm_error_t * derr,uint32_t bit,pf_data_t * dq_head_p,pf_data_t * pfd_p)196310187SKrishna.Elango@Sun.COM pf_panic(ddi_fm_error_t *derr, uint32_t bit, pf_data_t *dq_head_p,
196410187SKrishna.Elango@Sun.COM pf_data_t *pfd_p)
196510187SKrishna.Elango@Sun.COM {
196610187SKrishna.Elango@Sun.COM return (PF_ERR_PANIC);
196710187SKrishna.Elango@Sun.COM }
196810187SKrishna.Elango@Sun.COM
196910187SKrishna.Elango@Sun.COM /*
197010187SKrishna.Elango@Sun.COM * If a PCIe device does not support AER, assume all AER statuses have been set,
197110187SKrishna.Elango@Sun.COM * unless other registers do not indicate a certain error occuring.
197210187SKrishna.Elango@Sun.COM */
197310187SKrishna.Elango@Sun.COM static void
pf_adjust_for_no_aer(pf_data_t * pfd_p)197410187SKrishna.Elango@Sun.COM pf_adjust_for_no_aer(pf_data_t *pfd_p)
197510187SKrishna.Elango@Sun.COM {
197610187SKrishna.Elango@Sun.COM uint32_t aer_ue = 0;
197710187SKrishna.Elango@Sun.COM uint16_t status;
197810187SKrishna.Elango@Sun.COM
197910187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p)))
198010187SKrishna.Elango@Sun.COM return;
198110187SKrishna.Elango@Sun.COM
198210187SKrishna.Elango@Sun.COM if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_FE_DETECTED)
198310187SKrishna.Elango@Sun.COM aer_ue = PF_AER_FATAL_ERR;
198410187SKrishna.Elango@Sun.COM
198510187SKrishna.Elango@Sun.COM if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_NFE_DETECTED) {
198610187SKrishna.Elango@Sun.COM aer_ue = PF_AER_NON_FATAL_ERR;
198710187SKrishna.Elango@Sun.COM status = PCI_ERR_REG(pfd_p)->pci_err_status;
198810187SKrishna.Elango@Sun.COM
198910187SKrishna.Elango@Sun.COM /* Check if the device received a PTLP */
199010187SKrishna.Elango@Sun.COM if (!(status & PCI_STAT_PERROR))
199110187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_PTLP;
199210187SKrishna.Elango@Sun.COM
199310187SKrishna.Elango@Sun.COM /* Check if the device signaled a CA */
199410187SKrishna.Elango@Sun.COM if (!(status & PCI_STAT_S_TARG_AB))
199510187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_CA;
199610187SKrishna.Elango@Sun.COM
199710187SKrishna.Elango@Sun.COM /* Check if the device sent a UR */
199810187SKrishna.Elango@Sun.COM if (!(PCIE_ERR_REG(pfd_p)->pcie_err_status &
199910187SKrishna.Elango@Sun.COM PCIE_DEVSTS_UR_DETECTED))
200010187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_UR;
200110187SKrishna.Elango@Sun.COM
200210187SKrishna.Elango@Sun.COM /*
200310187SKrishna.Elango@Sun.COM * Ignore ECRCs as it is optional and will manefest itself as
200410187SKrishna.Elango@Sun.COM * another error like PTLP and MFP
200510187SKrishna.Elango@Sun.COM */
200610187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_ECRC;
200710187SKrishna.Elango@Sun.COM
200810187SKrishna.Elango@Sun.COM /*
200910187SKrishna.Elango@Sun.COM * Generally if NFE is set, SERR should also be set. Exception:
201010187SKrishna.Elango@Sun.COM * When certain non-fatal errors are masked, and some of them
201110187SKrishna.Elango@Sun.COM * happened to be the cause of the NFE, SERR will not be set and
201210187SKrishna.Elango@Sun.COM * they can not be the source of this interrupt.
201310187SKrishna.Elango@Sun.COM *
201410187SKrishna.Elango@Sun.COM * On x86, URs are masked (NFE + UR can be set), if any other
201510187SKrishna.Elango@Sun.COM * non-fatal errors (i.e, PTLP, CTO, CA, UC, ECRC, ACS) did
201610187SKrishna.Elango@Sun.COM * occur, SERR should be set since they are not masked. So if
201710187SKrishna.Elango@Sun.COM * SERR is not set, none of them occurred.
201810187SKrishna.Elango@Sun.COM */
201910187SKrishna.Elango@Sun.COM if (!(status & PCI_STAT_S_SYSERR))
202010187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_TO;
202110187SKrishna.Elango@Sun.COM }
202210187SKrishna.Elango@Sun.COM
202310187SKrishna.Elango@Sun.COM if (!PCIE_IS_BDG(PCIE_PFD2BUS(pfd_p))) {
202410187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_TRAINING;
202510187SKrishna.Elango@Sun.COM aer_ue &= ~PCIE_AER_UCE_SD;
202610187SKrishna.Elango@Sun.COM }
202710187SKrishna.Elango@Sun.COM
202810187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_status = aer_ue;
202910187SKrishna.Elango@Sun.COM }
203010187SKrishna.Elango@Sun.COM
203110187SKrishna.Elango@Sun.COM static void
pf_adjust_for_no_saer(pf_data_t * pfd_p)203210187SKrishna.Elango@Sun.COM pf_adjust_for_no_saer(pf_data_t *pfd_p)
203310187SKrishna.Elango@Sun.COM {
203410187SKrishna.Elango@Sun.COM uint32_t s_aer_ue = 0;
203510187SKrishna.Elango@Sun.COM uint16_t status;
203610187SKrishna.Elango@Sun.COM
203710187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(PCIE_PFD2BUS(pfd_p)))
203810187SKrishna.Elango@Sun.COM return;
203910187SKrishna.Elango@Sun.COM
204010187SKrishna.Elango@Sun.COM if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_FE_DETECTED)
204110187SKrishna.Elango@Sun.COM s_aer_ue = PF_SAER_FATAL_ERR;
204210187SKrishna.Elango@Sun.COM
204310187SKrishna.Elango@Sun.COM if (PCIE_ERR_REG(pfd_p)->pcie_err_status & PCIE_DEVSTS_NFE_DETECTED) {
204410187SKrishna.Elango@Sun.COM s_aer_ue = PF_SAER_NON_FATAL_ERR;
204510187SKrishna.Elango@Sun.COM status = PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat;
204610187SKrishna.Elango@Sun.COM
204710187SKrishna.Elango@Sun.COM /* Check if the device received a UC_DATA */
204810187SKrishna.Elango@Sun.COM if (!(status & PCI_STAT_PERROR))
204910187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_UC_DATA_ERR;
205010187SKrishna.Elango@Sun.COM
205110187SKrishna.Elango@Sun.COM /* Check if the device received a RCVD_MA/MA_ON_SC */
205210187SKrishna.Elango@Sun.COM if (!(status & (PCI_STAT_R_MAST_AB))) {
205310187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_RCVD_MA;
205410187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_MA_ON_SC;
205510187SKrishna.Elango@Sun.COM }
205610187SKrishna.Elango@Sun.COM
205710187SKrishna.Elango@Sun.COM /* Check if the device received a RCVD_TA/TA_ON_SC */
205810187SKrishna.Elango@Sun.COM if (!(status & (PCI_STAT_R_TARG_AB))) {
205910187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_RCVD_TA;
206010187SKrishna.Elango@Sun.COM s_aer_ue &= ~PCIE_AER_SUCE_TA_ON_SC;
206110187SKrishna.Elango@Sun.COM }
206210187SKrishna.Elango@Sun.COM }
206310187SKrishna.Elango@Sun.COM
206410187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status = s_aer_ue;
206510187SKrishna.Elango@Sun.COM }
206610187SKrishna.Elango@Sun.COM
206710187SKrishna.Elango@Sun.COM /* Find the PCIe-PCI bridge based on secondary bus number */
206810187SKrishna.Elango@Sun.COM static pf_data_t *
pf_get_pcie_bridge(pf_data_t * pfd_p,pcie_req_id_t secbus)206910187SKrishna.Elango@Sun.COM pf_get_pcie_bridge(pf_data_t *pfd_p, pcie_req_id_t secbus)
207010187SKrishna.Elango@Sun.COM {
207110187SKrishna.Elango@Sun.COM pf_data_t *bdg_pfd_p;
207210187SKrishna.Elango@Sun.COM
207310187SKrishna.Elango@Sun.COM /* Search down for the PCIe-PCI device. */
207410187SKrishna.Elango@Sun.COM for (bdg_pfd_p = pfd_p->pe_next; bdg_pfd_p;
207510187SKrishna.Elango@Sun.COM bdg_pfd_p = bdg_pfd_p->pe_next) {
207610187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(PCIE_PFD2BUS(bdg_pfd_p)) &&
207710187SKrishna.Elango@Sun.COM PCIE_PFD2BUS(bdg_pfd_p)->bus_bdg_secbus == secbus)
207810187SKrishna.Elango@Sun.COM return (bdg_pfd_p);
207910187SKrishna.Elango@Sun.COM }
208010187SKrishna.Elango@Sun.COM
208110187SKrishna.Elango@Sun.COM return (NULL);
208210187SKrishna.Elango@Sun.COM }
208310187SKrishna.Elango@Sun.COM
208410187SKrishna.Elango@Sun.COM /* Find the PCIe-PCI bridge of a PCI device */
208510187SKrishna.Elango@Sun.COM static pf_data_t *
pf_get_parent_pcie_bridge(pf_data_t * pfd_p)208610187SKrishna.Elango@Sun.COM pf_get_parent_pcie_bridge(pf_data_t *pfd_p)
208710187SKrishna.Elango@Sun.COM {
208810187SKrishna.Elango@Sun.COM dev_info_t *dip, *rp_dip = PCIE_PFD2BUS(pfd_p)->bus_rp_dip;
208910187SKrishna.Elango@Sun.COM
209010187SKrishna.Elango@Sun.COM /* This only makes sense if the device is a PCI device */
209110187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCI(PCIE_PFD2BUS(pfd_p)))
209210187SKrishna.Elango@Sun.COM return (NULL);
209310187SKrishna.Elango@Sun.COM
209410187SKrishna.Elango@Sun.COM /*
209510187SKrishna.Elango@Sun.COM * Search up for the PCIe-PCI device. Watchout for x86 where pci
209610187SKrishna.Elango@Sun.COM * devices hang directly off of NPE.
209710187SKrishna.Elango@Sun.COM */
209810187SKrishna.Elango@Sun.COM for (dip = PCIE_PFD2DIP(pfd_p); dip; dip = ddi_get_parent(dip)) {
209910187SKrishna.Elango@Sun.COM if (dip == rp_dip)
210010187SKrishna.Elango@Sun.COM dip = NULL;
210110187SKrishna.Elango@Sun.COM
210210187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(dip)))
210310187SKrishna.Elango@Sun.COM return (PCIE_DIP2PFD(dip));
210410187SKrishna.Elango@Sun.COM }
210510187SKrishna.Elango@Sun.COM
210610187SKrishna.Elango@Sun.COM return (NULL);
210710187SKrishna.Elango@Sun.COM }
210810187SKrishna.Elango@Sun.COM
210910187SKrishna.Elango@Sun.COM /*
211010187SKrishna.Elango@Sun.COM * See if a leaf error was bubbled up to the Root Complex (RC) and handled.
211110187SKrishna.Elango@Sun.COM * As of right now only RC's have enough information to have errors found in the
211210187SKrishna.Elango@Sun.COM * fabric to be matched to the RC. Note that Root Port's (RP) do not carry
211310187SKrishna.Elango@Sun.COM * enough information. Currently known RC's are SPARC Fire architecture and
211410187SKrishna.Elango@Sun.COM * it's equivalents, and x86's NPE.
211510187SKrishna.Elango@Sun.COM * SPARC Fire architectures have a plethora of error registers, while currently
211610187SKrishna.Elango@Sun.COM * NPE only have the address of a failed load.
211710187SKrishna.Elango@Sun.COM *
211810187SKrishna.Elango@Sun.COM * Check if the RC logged an error with the appropriate status type/abort type.
211910187SKrishna.Elango@Sun.COM * Ex: Parity Error, Received Master/Target Abort
212010187SKrishna.Elango@Sun.COM * Check if either the fault address found in the rc matches the device's
212110187SKrishna.Elango@Sun.COM * assigned address range (PIO's only) or the fault BDF in the rc matches the
212210187SKrishna.Elango@Sun.COM * device's BDF or Secondary Bus/Bus Range.
212310187SKrishna.Elango@Sun.COM */
212410187SKrishna.Elango@Sun.COM static boolean_t
pf_matched_in_rc(pf_data_t * dq_head_p,pf_data_t * pfd_p,uint32_t abort_type)212510187SKrishna.Elango@Sun.COM pf_matched_in_rc(pf_data_t *dq_head_p, pf_data_t *pfd_p,
212610187SKrishna.Elango@Sun.COM uint32_t abort_type)
212710187SKrishna.Elango@Sun.COM {
212810187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_PFD2BUS(pfd_p);
212910187SKrishna.Elango@Sun.COM pf_data_t *rc_pfd_p;
213010187SKrishna.Elango@Sun.COM pcie_req_id_t fault_bdf;
213110187SKrishna.Elango@Sun.COM
213210187SKrishna.Elango@Sun.COM for (rc_pfd_p = dq_head_p; PFD_IS_ROOT(rc_pfd_p);
213310187SKrishna.Elango@Sun.COM rc_pfd_p = rc_pfd_p->pe_next) {
213410187SKrishna.Elango@Sun.COM /* Only root complex's have enough information to match */
213510187SKrishna.Elango@Sun.COM if (!PCIE_IS_RC(PCIE_PFD2BUS(rc_pfd_p)))
213610187SKrishna.Elango@Sun.COM continue;
213710187SKrishna.Elango@Sun.COM
213810187SKrishna.Elango@Sun.COM /* If device and rc abort type does not match continue */
213910187SKrishna.Elango@Sun.COM if (!(PCI_BDG_ERR_REG(rc_pfd_p)->pci_bdg_sec_stat & abort_type))
214010187SKrishna.Elango@Sun.COM continue;
214110187SKrishna.Elango@Sun.COM
214210187SKrishna.Elango@Sun.COM fault_bdf = PCIE_ROOT_FAULT(rc_pfd_p)->scan_bdf;
214310187SKrishna.Elango@Sun.COM
214410187SKrishna.Elango@Sun.COM /* The Fault BDF = Device's BDF */
214510187SKrishna.Elango@Sun.COM if (fault_bdf == bus_p->bus_bdf)
214610187SKrishna.Elango@Sun.COM return (B_TRUE);
214710187SKrishna.Elango@Sun.COM
214810187SKrishna.Elango@Sun.COM /* The Fault Addr is in device's address range */
214910187SKrishna.Elango@Sun.COM if (pf_in_addr_range(bus_p,
215010187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(rc_pfd_p)->scan_addr))
215110187SKrishna.Elango@Sun.COM return (B_TRUE);
215210187SKrishna.Elango@Sun.COM
215310187SKrishna.Elango@Sun.COM /* The Fault BDF is from PCIe-PCI Bridge's secondary bus */
215410187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) &&
215510187SKrishna.Elango@Sun.COM pf_in_bus_range(bus_p, fault_bdf))
215610187SKrishna.Elango@Sun.COM return (B_TRUE);
215710187SKrishna.Elango@Sun.COM }
215810187SKrishna.Elango@Sun.COM
215910187SKrishna.Elango@Sun.COM return (B_FALSE);
216010187SKrishna.Elango@Sun.COM }
216110187SKrishna.Elango@Sun.COM
216210187SKrishna.Elango@Sun.COM /*
216310187SKrishna.Elango@Sun.COM * Check the RP and see if the error is PIO/DMA. If the RP also has a PERR then
216410187SKrishna.Elango@Sun.COM * it is a DMA, otherwise it's a PIO
216510187SKrishna.Elango@Sun.COM */
216610187SKrishna.Elango@Sun.COM static void
pf_pci_find_trans_type(pf_data_t * pfd_p,uint64_t * addr,uint32_t * trans_type,pcie_req_id_t * bdf)216710187SKrishna.Elango@Sun.COM pf_pci_find_trans_type(pf_data_t *pfd_p, uint64_t *addr, uint32_t *trans_type,
216810187SKrishna.Elango@Sun.COM pcie_req_id_t *bdf) {
216910187SKrishna.Elango@Sun.COM pf_data_t *rc_pfd_p;
217010187SKrishna.Elango@Sun.COM
217110187SKrishna.Elango@Sun.COM /* Could be DMA or PIO. Find out by look at error type. */
217210187SKrishna.Elango@Sun.COM switch (PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status) {
217310187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_TA_ON_SC:
217410187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_MA_ON_SC:
217510187SKrishna.Elango@Sun.COM *trans_type = PF_ADDR_DMA;
217610187SKrishna.Elango@Sun.COM return;
217710187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_RCVD_TA:
217810187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_RCVD_MA:
217910187SKrishna.Elango@Sun.COM *bdf = PCIE_INVALID_BDF;
218010187SKrishna.Elango@Sun.COM *trans_type = PF_ADDR_PIO;
218110187SKrishna.Elango@Sun.COM return;
218210187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_USC_ERR:
218310187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_UC_DATA_ERR:
218410187SKrishna.Elango@Sun.COM case PCIE_AER_SUCE_PERR_ASSERT:
218510187SKrishna.Elango@Sun.COM break;
218610187SKrishna.Elango@Sun.COM default:
218710187SKrishna.Elango@Sun.COM *addr = 0;
218810187SKrishna.Elango@Sun.COM *bdf = PCIE_INVALID_BDF;
218910187SKrishna.Elango@Sun.COM *trans_type = 0;
219010187SKrishna.Elango@Sun.COM return;
219110187SKrishna.Elango@Sun.COM }
219210187SKrishna.Elango@Sun.COM
219310187SKrishna.Elango@Sun.COM *bdf = PCIE_INVALID_BDF;
219410187SKrishna.Elango@Sun.COM *trans_type = PF_ADDR_PIO;
219510187SKrishna.Elango@Sun.COM for (rc_pfd_p = pfd_p->pe_prev; rc_pfd_p;
219610187SKrishna.Elango@Sun.COM rc_pfd_p = rc_pfd_p->pe_prev) {
219710187SKrishna.Elango@Sun.COM if (PFD_IS_ROOT(rc_pfd_p) &&
219810187SKrishna.Elango@Sun.COM (PCI_BDG_ERR_REG(rc_pfd_p)->pci_bdg_sec_stat &
219910187SKrishna.Elango@Sun.COM PCI_STAT_PERROR)) {
220010187SKrishna.Elango@Sun.COM *trans_type = PF_ADDR_DMA;
220110187SKrishna.Elango@Sun.COM return;
220210187SKrishna.Elango@Sun.COM }
220310187SKrishna.Elango@Sun.COM }
220410187SKrishna.Elango@Sun.COM }
220510187SKrishna.Elango@Sun.COM
220610187SKrishna.Elango@Sun.COM /*
220710187SKrishna.Elango@Sun.COM * pf_pci_decode function decodes the secondary aer transaction logs in
220810187SKrishna.Elango@Sun.COM * PCIe-PCI bridges.
220910187SKrishna.Elango@Sun.COM *
221010187SKrishna.Elango@Sun.COM * The log is 128 bits long and arranged in this manner.
221110187SKrishna.Elango@Sun.COM * [0:35] Transaction Attribute (s_aer_h0-saer_h1)
221210187SKrishna.Elango@Sun.COM * [36:39] Transaction lower command (saer_h1)
221310187SKrishna.Elango@Sun.COM * [40:43] Transaction upper command (saer_h1)
221410187SKrishna.Elango@Sun.COM * [44:63] Reserved
221510187SKrishna.Elango@Sun.COM * [64:127] Address (saer_h2-saer_h3)
221610187SKrishna.Elango@Sun.COM */
221710187SKrishna.Elango@Sun.COM /* ARGSUSED */
221811596SJason.Beloro@Sun.COM int
pf_pci_decode(pf_data_t * pfd_p,uint16_t * cmd)221910187SKrishna.Elango@Sun.COM pf_pci_decode(pf_data_t *pfd_p, uint16_t *cmd) {
222010187SKrishna.Elango@Sun.COM pcix_attr_t *attr;
222110187SKrishna.Elango@Sun.COM uint64_t addr;
222210187SKrishna.Elango@Sun.COM uint32_t trans_type;
222310187SKrishna.Elango@Sun.COM pcie_req_id_t bdf = PCIE_INVALID_BDF;
222410187SKrishna.Elango@Sun.COM
222510187SKrishna.Elango@Sun.COM attr = (pcix_attr_t *)&PCIE_ADV_BDG_HDR(pfd_p, 0);
222610187SKrishna.Elango@Sun.COM *cmd = GET_SAER_CMD(pfd_p);
222710187SKrishna.Elango@Sun.COM
222810187SKrishna.Elango@Sun.COM cmd_switch:
222910187SKrishna.Elango@Sun.COM switch (*cmd) {
223010187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_IORD:
223110187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_IOWR:
223210187SKrishna.Elango@Sun.COM /* IO Access should always be down stream */
223310187SKrishna.Elango@Sun.COM addr = PCIE_ADV_BDG_HDR(pfd_p, 2);
223410187SKrishna.Elango@Sun.COM bdf = attr->rid;
223510187SKrishna.Elango@Sun.COM trans_type = PF_ADDR_PIO;
223610187SKrishna.Elango@Sun.COM break;
223710187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMRD_DW:
223810187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMRD_BL:
223910187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMRDBL:
224010187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWR:
224110187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWR_BL:
224210187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_MEMWRBL:
224310187SKrishna.Elango@Sun.COM addr = ((uint64_t)PCIE_ADV_BDG_HDR(pfd_p, 3) <<
224410187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_ADDR_SHIFT) | PCIE_ADV_BDG_HDR(pfd_p, 2);
224510187SKrishna.Elango@Sun.COM bdf = attr->rid;
224610187SKrishna.Elango@Sun.COM
224710187SKrishna.Elango@Sun.COM pf_pci_find_trans_type(pfd_p, &addr, &trans_type, &bdf);
224810187SKrishna.Elango@Sun.COM break;
224910187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_CFRD:
225010187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_CFWR:
225110187SKrishna.Elango@Sun.COM /*
225210187SKrishna.Elango@Sun.COM * CFG Access should always be down stream. Match the BDF in
225310187SKrishna.Elango@Sun.COM * the address phase.
225410187SKrishna.Elango@Sun.COM */
225510187SKrishna.Elango@Sun.COM addr = 0;
225610187SKrishna.Elango@Sun.COM bdf = attr->rid;
225710187SKrishna.Elango@Sun.COM trans_type = PF_ADDR_CFG;
225810187SKrishna.Elango@Sun.COM break;
225910187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_SPL:
226010187SKrishna.Elango@Sun.COM /*
226110187SKrishna.Elango@Sun.COM * Check for DMA read completions. The requesting BDF is in the
226210187SKrishna.Elango@Sun.COM * Address phase.
226310187SKrishna.Elango@Sun.COM */
226410187SKrishna.Elango@Sun.COM addr = 0;
226510187SKrishna.Elango@Sun.COM bdf = attr->rid;
226610187SKrishna.Elango@Sun.COM trans_type = PF_ADDR_DMA;
226710187SKrishna.Elango@Sun.COM break;
226810187SKrishna.Elango@Sun.COM case PCI_PCIX_CMD_DADR:
226910187SKrishna.Elango@Sun.COM /*
227010187SKrishna.Elango@Sun.COM * For Dual Address Cycles the transaction command is in the 2nd
227110187SKrishna.Elango@Sun.COM * address phase.
227210187SKrishna.Elango@Sun.COM */
227310187SKrishna.Elango@Sun.COM *cmd = (PCIE_ADV_BDG_HDR(pfd_p, 1) >>
227410187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) &
227510187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_HDR_CMD_UP_MASK;
227610187SKrishna.Elango@Sun.COM if (*cmd != PCI_PCIX_CMD_DADR)
227710187SKrishna.Elango@Sun.COM goto cmd_switch;
227810187SKrishna.Elango@Sun.COM /* FALLTHROUGH */
227910187SKrishna.Elango@Sun.COM default:
228010187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = 0;
228110187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = PCIE_INVALID_BDF;
228210187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = 0;
228310187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
228410187SKrishna.Elango@Sun.COM }
228510187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = trans_type;
228610187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = bdf;
228710187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = addr;
228810187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
228910187SKrishna.Elango@Sun.COM }
229010187SKrishna.Elango@Sun.COM
229110187SKrishna.Elango@Sun.COM /*
229210187SKrishna.Elango@Sun.COM * Based on either the BDF/ADDR find and mark the faulting DMA/ACC handler.
229310187SKrishna.Elango@Sun.COM * Returns either PF_HDL_NOTFOUND or PF_HDL_FOUND.
229410187SKrishna.Elango@Sun.COM */
229510187SKrishna.Elango@Sun.COM int
pf_hdl_lookup(dev_info_t * dip,uint64_t ena,uint32_t flag,uint64_t addr,pcie_req_id_t bdf)229610187SKrishna.Elango@Sun.COM pf_hdl_lookup(dev_info_t *dip, uint64_t ena, uint32_t flag, uint64_t addr,
229710187SKrishna.Elango@Sun.COM pcie_req_id_t bdf)
229810187SKrishna.Elango@Sun.COM {
229910187SKrishna.Elango@Sun.COM ddi_fm_error_t derr;
230010187SKrishna.Elango@Sun.COM
230110187SKrishna.Elango@Sun.COM /* If we don't know the addr or rid just return with NOTFOUND */
230210187SKrishna.Elango@Sun.COM if ((addr == NULL) && !PCIE_CHECK_VALID_BDF(bdf))
230310187SKrishna.Elango@Sun.COM return (PF_HDL_NOTFOUND);
230410187SKrishna.Elango@Sun.COM
2305*12458SErwin.Tsaur@Sun.COM /*
2306*12458SErwin.Tsaur@Sun.COM * Disable DMA handle lookup until DMA errors can be handled and
2307*12458SErwin.Tsaur@Sun.COM * reported synchronously. When enabled again, check for the
2308*12458SErwin.Tsaur@Sun.COM * PF_ADDR_DMA flag
2309*12458SErwin.Tsaur@Sun.COM */
2310*12458SErwin.Tsaur@Sun.COM if (!(flag & (PF_ADDR_PIO | PF_ADDR_CFG))) {
231110187SKrishna.Elango@Sun.COM return (PF_HDL_NOTFOUND);
231210187SKrishna.Elango@Sun.COM }
231310187SKrishna.Elango@Sun.COM
231410187SKrishna.Elango@Sun.COM bzero(&derr, sizeof (ddi_fm_error_t));
231510187SKrishna.Elango@Sun.COM derr.fme_version = DDI_FME_VERSION;
231610187SKrishna.Elango@Sun.COM derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
231710187SKrishna.Elango@Sun.COM derr.fme_ena = ena;
231810187SKrishna.Elango@Sun.COM
231910187SKrishna.Elango@Sun.COM return (pf_hdl_child_lookup(dip, &derr, flag, addr, bdf));
232010187SKrishna.Elango@Sun.COM }
232110187SKrishna.Elango@Sun.COM
232210187SKrishna.Elango@Sun.COM static int
pf_hdl_child_lookup(dev_info_t * dip,ddi_fm_error_t * derr,uint32_t flag,uint64_t addr,pcie_req_id_t bdf)232310187SKrishna.Elango@Sun.COM pf_hdl_child_lookup(dev_info_t *dip, ddi_fm_error_t *derr, uint32_t flag,
232410187SKrishna.Elango@Sun.COM uint64_t addr, pcie_req_id_t bdf)
232510187SKrishna.Elango@Sun.COM {
232610187SKrishna.Elango@Sun.COM int status = PF_HDL_NOTFOUND;
232710187SKrishna.Elango@Sun.COM ndi_fmc_t *fcp = NULL;
232810187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
232910187SKrishna.Elango@Sun.COM pcie_req_id_t dip_bdf;
233010187SKrishna.Elango@Sun.COM boolean_t have_lock = B_FALSE;
233110187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p;
233210187SKrishna.Elango@Sun.COM dev_info_t *cdip;
233310187SKrishna.Elango@Sun.COM
233410187SKrishna.Elango@Sun.COM if (!(bus_p = pf_is_ready(dip))) {
233510187SKrishna.Elango@Sun.COM return (status);
233610187SKrishna.Elango@Sun.COM }
233710187SKrishna.Elango@Sun.COM
233810187SKrishna.Elango@Sun.COM ASSERT(fmhdl);
233910187SKrishna.Elango@Sun.COM if (!i_ddi_fm_handler_owned(dip)) {
234010187SKrishna.Elango@Sun.COM /*
234110187SKrishna.Elango@Sun.COM * pf_handler_enter always returns SUCCESS if the 'impl' arg is
234210187SKrishna.Elango@Sun.COM * NULL.
234310187SKrishna.Elango@Sun.COM */
234410187SKrishna.Elango@Sun.COM (void) pf_handler_enter(dip, NULL);
234510187SKrishna.Elango@Sun.COM have_lock = B_TRUE;
234610187SKrishna.Elango@Sun.COM }
234710187SKrishna.Elango@Sun.COM
234810187SKrishna.Elango@Sun.COM dip_bdf = PCI_GET_BDF(dip);
234910187SKrishna.Elango@Sun.COM
235010187SKrishna.Elango@Sun.COM /* Check if dip and BDF match, if not recurse to it's children. */
235110187SKrishna.Elango@Sun.COM if (!PCIE_IS_RC(bus_p) && (!PCIE_CHECK_VALID_BDF(bdf) ||
235210187SKrishna.Elango@Sun.COM dip_bdf == bdf)) {
235310187SKrishna.Elango@Sun.COM if ((flag & PF_ADDR_DMA) && DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap))
235410187SKrishna.Elango@Sun.COM fcp = fmhdl->fh_dma_cache;
235510187SKrishna.Elango@Sun.COM else
235610187SKrishna.Elango@Sun.COM fcp = NULL;
235710187SKrishna.Elango@Sun.COM
235810187SKrishna.Elango@Sun.COM if (fcp)
235910187SKrishna.Elango@Sun.COM status = pf_hdl_compare(dip, derr, DMA_HANDLE, addr,
236010187SKrishna.Elango@Sun.COM bdf, fcp);
236110187SKrishna.Elango@Sun.COM
236210187SKrishna.Elango@Sun.COM
236310187SKrishna.Elango@Sun.COM if (((flag & PF_ADDR_PIO) || (flag & PF_ADDR_CFG)) &&
236410187SKrishna.Elango@Sun.COM DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap))
236510187SKrishna.Elango@Sun.COM fcp = fmhdl->fh_acc_cache;
236610187SKrishna.Elango@Sun.COM else
236710187SKrishna.Elango@Sun.COM fcp = NULL;
236810187SKrishna.Elango@Sun.COM
236910187SKrishna.Elango@Sun.COM if (fcp)
237010187SKrishna.Elango@Sun.COM status = pf_hdl_compare(dip, derr, ACC_HANDLE, addr,
237110187SKrishna.Elango@Sun.COM bdf, fcp);
237210187SKrishna.Elango@Sun.COM }
237310187SKrishna.Elango@Sun.COM
237410187SKrishna.Elango@Sun.COM /* If we found the handler or know it's this device, we're done */
237510187SKrishna.Elango@Sun.COM if (!PCIE_IS_RC(bus_p) && ((dip_bdf == bdf) ||
237610187SKrishna.Elango@Sun.COM (status == PF_HDL_FOUND)))
237710187SKrishna.Elango@Sun.COM goto done;
237810187SKrishna.Elango@Sun.COM
237910187SKrishna.Elango@Sun.COM /*
238010187SKrishna.Elango@Sun.COM * If the current devuce us a PCIe-PCI bridge need to check for special
238110187SKrishna.Elango@Sun.COM * cases:
238210187SKrishna.Elango@Sun.COM *
238310187SKrishna.Elango@Sun.COM * If it is a PIO and we don't have an address or this is a DMA, check
238410187SKrishna.Elango@Sun.COM * to see if the BDF = secondary bus. If so stop. The BDF isn't a real
238510187SKrishna.Elango@Sun.COM * BDF and the fault device could have come from any device in the PCI
238610187SKrishna.Elango@Sun.COM * bus.
238710187SKrishna.Elango@Sun.COM */
238810187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) &&
238910187SKrishna.Elango@Sun.COM ((flag & PF_ADDR_DMA || flag & PF_ADDR_PIO)) &&
239010187SKrishna.Elango@Sun.COM ((bus_p->bus_bdg_secbus << PCIE_REQ_ID_BUS_SHIFT) == bdf))
239110187SKrishna.Elango@Sun.COM goto done;
239210187SKrishna.Elango@Sun.COM
239310187SKrishna.Elango@Sun.COM
239410187SKrishna.Elango@Sun.COM /* If we can't find the handler check it's children */
239510187SKrishna.Elango@Sun.COM for (cdip = ddi_get_child(dip); cdip;
239610187SKrishna.Elango@Sun.COM cdip = ddi_get_next_sibling(cdip)) {
239710187SKrishna.Elango@Sun.COM if ((bus_p = PCIE_DIP2BUS(cdip)) == NULL)
239810187SKrishna.Elango@Sun.COM continue;
239910187SKrishna.Elango@Sun.COM
240010187SKrishna.Elango@Sun.COM if (pf_in_bus_range(bus_p, bdf) ||
240110187SKrishna.Elango@Sun.COM pf_in_addr_range(bus_p, addr))
240210187SKrishna.Elango@Sun.COM status = pf_hdl_child_lookup(cdip, derr, flag, addr,
240310187SKrishna.Elango@Sun.COM bdf);
240410187SKrishna.Elango@Sun.COM
240510187SKrishna.Elango@Sun.COM if (status == PF_HDL_FOUND)
240610187SKrishna.Elango@Sun.COM goto done;
240710187SKrishna.Elango@Sun.COM }
240810187SKrishna.Elango@Sun.COM
240910187SKrishna.Elango@Sun.COM done:
241010187SKrishna.Elango@Sun.COM if (have_lock == B_TRUE)
241110187SKrishna.Elango@Sun.COM pf_handler_exit(dip);
241210187SKrishna.Elango@Sun.COM
241310187SKrishna.Elango@Sun.COM return (status);
241410187SKrishna.Elango@Sun.COM }
241510187SKrishna.Elango@Sun.COM
241610187SKrishna.Elango@Sun.COM static int
pf_hdl_compare(dev_info_t * dip,ddi_fm_error_t * derr,uint32_t flag,uint64_t addr,pcie_req_id_t bdf,ndi_fmc_t * fcp)241710187SKrishna.Elango@Sun.COM pf_hdl_compare(dev_info_t *dip, ddi_fm_error_t *derr, uint32_t flag,
241810187SKrishna.Elango@Sun.COM uint64_t addr, pcie_req_id_t bdf, ndi_fmc_t *fcp) {
241910187SKrishna.Elango@Sun.COM ndi_fmcentry_t *fep;
242010187SKrishna.Elango@Sun.COM int found = 0;
242110187SKrishna.Elango@Sun.COM int status;
242210187SKrishna.Elango@Sun.COM
242310187SKrishna.Elango@Sun.COM mutex_enter(&fcp->fc_lock);
242410187SKrishna.Elango@Sun.COM for (fep = fcp->fc_head; fep != NULL; fep = fep->fce_next) {
242510187SKrishna.Elango@Sun.COM ddi_fmcompare_t compare_func;
242610187SKrishna.Elango@Sun.COM
242710187SKrishna.Elango@Sun.COM /*
242810187SKrishna.Elango@Sun.COM * Compare captured error state with handle
242910187SKrishna.Elango@Sun.COM * resources. During the comparison and
243010187SKrishna.Elango@Sun.COM * subsequent error handling, we block
243110187SKrishna.Elango@Sun.COM * attempts to free the cache entry.
243210187SKrishna.Elango@Sun.COM */
243310187SKrishna.Elango@Sun.COM compare_func = (flag == ACC_HANDLE) ?
243410187SKrishna.Elango@Sun.COM i_ddi_fm_acc_err_cf_get((ddi_acc_handle_t)
243510187SKrishna.Elango@Sun.COM fep->fce_resource) :
243610187SKrishna.Elango@Sun.COM i_ddi_fm_dma_err_cf_get((ddi_dma_handle_t)
243710187SKrishna.Elango@Sun.COM fep->fce_resource);
243810187SKrishna.Elango@Sun.COM
243912027SStephen.Hanson@Sun.COM if (compare_func == NULL) /* unbound or not FLAGERR */
244012027SStephen.Hanson@Sun.COM continue;
244112027SStephen.Hanson@Sun.COM
244210187SKrishna.Elango@Sun.COM status = compare_func(dip, fep->fce_resource,
244310187SKrishna.Elango@Sun.COM (void *)&addr, (void *)&bdf);
244410187SKrishna.Elango@Sun.COM
244510187SKrishna.Elango@Sun.COM if (status == DDI_FM_NONFATAL) {
244610187SKrishna.Elango@Sun.COM found++;
244710187SKrishna.Elango@Sun.COM
244810187SKrishna.Elango@Sun.COM /* Set the error for this resource handle */
244910187SKrishna.Elango@Sun.COM if (flag == ACC_HANDLE) {
245010187SKrishna.Elango@Sun.COM ddi_acc_handle_t ap = fep->fce_resource;
245110187SKrishna.Elango@Sun.COM
245210187SKrishna.Elango@Sun.COM i_ddi_fm_acc_err_set(ap, derr->fme_ena, status,
245310187SKrishna.Elango@Sun.COM DDI_FM_ERR_UNEXPECTED);
245410187SKrishna.Elango@Sun.COM ddi_fm_acc_err_get(ap, derr, DDI_FME_VERSION);
245510187SKrishna.Elango@Sun.COM derr->fme_acc_handle = ap;
245610187SKrishna.Elango@Sun.COM } else {
245710187SKrishna.Elango@Sun.COM ddi_dma_handle_t dp = fep->fce_resource;
245810187SKrishna.Elango@Sun.COM
245910187SKrishna.Elango@Sun.COM i_ddi_fm_dma_err_set(dp, derr->fme_ena, status,
246010187SKrishna.Elango@Sun.COM DDI_FM_ERR_UNEXPECTED);
246110187SKrishna.Elango@Sun.COM ddi_fm_dma_err_get(dp, derr, DDI_FME_VERSION);
246210187SKrishna.Elango@Sun.COM derr->fme_dma_handle = dp;
246310187SKrishna.Elango@Sun.COM }
246410187SKrishna.Elango@Sun.COM }
246510187SKrishna.Elango@Sun.COM }
246610187SKrishna.Elango@Sun.COM mutex_exit(&fcp->fc_lock);
246710187SKrishna.Elango@Sun.COM
246810187SKrishna.Elango@Sun.COM /*
246910187SKrishna.Elango@Sun.COM * If a handler isn't found and we know this is the right device mark
247010187SKrishna.Elango@Sun.COM * them all failed.
247110187SKrishna.Elango@Sun.COM */
247210187SKrishna.Elango@Sun.COM if ((addr != NULL) && PCIE_CHECK_VALID_BDF(bdf) && (found == 0)) {
247310187SKrishna.Elango@Sun.COM status = pf_hdl_compare(dip, derr, flag, addr, bdf, fcp);
247410187SKrishna.Elango@Sun.COM if (status == PF_HDL_FOUND)
247510187SKrishna.Elango@Sun.COM found++;
247610187SKrishna.Elango@Sun.COM }
247710187SKrishna.Elango@Sun.COM
247810187SKrishna.Elango@Sun.COM return ((found) ? PF_HDL_FOUND : PF_HDL_NOTFOUND);
247910187SKrishna.Elango@Sun.COM }
248010187SKrishna.Elango@Sun.COM
248110187SKrishna.Elango@Sun.COM /*
248210187SKrishna.Elango@Sun.COM * Automatically decode AER header logs and does a handling look up based on the
248310187SKrishna.Elango@Sun.COM * AER header decoding.
248410187SKrishna.Elango@Sun.COM *
248510187SKrishna.Elango@Sun.COM * For this function only the Primary/Secondary AER Header Logs need to be valid
248610187SKrishna.Elango@Sun.COM * in the pfd (PCIe Fault Data) arg.
248710187SKrishna.Elango@Sun.COM *
248810187SKrishna.Elango@Sun.COM * Returns either PF_HDL_NOTFOUND or PF_HDL_FOUND.
248910187SKrishna.Elango@Sun.COM */
2490*12458SErwin.Tsaur@Sun.COM /* ARGSUSED */
249110187SKrishna.Elango@Sun.COM static int
pf_log_hdl_lookup(dev_info_t * rpdip,ddi_fm_error_t * derr,pf_data_t * pfd_p,boolean_t is_primary)249210187SKrishna.Elango@Sun.COM pf_log_hdl_lookup(dev_info_t *rpdip, ddi_fm_error_t *derr, pf_data_t *pfd_p,
249310187SKrishna.Elango@Sun.COM boolean_t is_primary)
249410187SKrishna.Elango@Sun.COM {
2495*12458SErwin.Tsaur@Sun.COM /*
2496*12458SErwin.Tsaur@Sun.COM * Disabling this function temporarily until errors can be handled
2497*12458SErwin.Tsaur@Sun.COM * synchronously.
2498*12458SErwin.Tsaur@Sun.COM *
2499*12458SErwin.Tsaur@Sun.COM * This function is currently only called during the middle of a fabric
2500*12458SErwin.Tsaur@Sun.COM * scan. If the fabric scan is called synchronously with an error seen
2501*12458SErwin.Tsaur@Sun.COM * in the RP/RC, then the related errors in the fabric will have a
2502*12458SErwin.Tsaur@Sun.COM * PF_ERR_MATCHED_RC error severity. pf_log_hdl_lookup code will be by
2503*12458SErwin.Tsaur@Sun.COM * passed when the severity is PF_ERR_MATCHED_RC. Handle lookup would
2504*12458SErwin.Tsaur@Sun.COM * have already happened in RP/RC error handling in a synchronous
2505*12458SErwin.Tsaur@Sun.COM * manner. Errors unrelated should panic, because they are being
2506*12458SErwin.Tsaur@Sun.COM * handled asynchronously.
2507*12458SErwin.Tsaur@Sun.COM *
2508*12458SErwin.Tsaur@Sun.COM * If fabric scan is called asynchronously from any RP/RC error, then
2509*12458SErwin.Tsaur@Sun.COM * DMA/PIO UE errors seen in the fabric should panic. pf_lop_hdl_lookup
2510*12458SErwin.Tsaur@Sun.COM * will return PF_HDL_NOTFOUND to ensure that the system panics.
2511*12458SErwin.Tsaur@Sun.COM */
2512*12458SErwin.Tsaur@Sun.COM return (PF_HDL_NOTFOUND);
251310187SKrishna.Elango@Sun.COM }
251410187SKrishna.Elango@Sun.COM
251510187SKrishna.Elango@Sun.COM /*
251610187SKrishna.Elango@Sun.COM * Decodes the TLP and returns the BDF of the handler, address and transaction
251710187SKrishna.Elango@Sun.COM * type if known.
251810187SKrishna.Elango@Sun.COM *
251910187SKrishna.Elango@Sun.COM * Types of TLP logs seen in RC, and what to extract:
252010187SKrishna.Elango@Sun.COM *
252110187SKrishna.Elango@Sun.COM * Memory(DMA) - Requester BDF, address, PF_DMA_ADDR
252210187SKrishna.Elango@Sun.COM * Memory(PIO) - address, PF_PIO_ADDR
252310187SKrishna.Elango@Sun.COM * CFG - Should not occur and result in UR
252410187SKrishna.Elango@Sun.COM * Completion(DMA) - Requester BDF, PF_DMA_ADDR
252510187SKrishna.Elango@Sun.COM * Completion(PIO) - Requester BDF, PF_PIO_ADDR
252610187SKrishna.Elango@Sun.COM *
252710187SKrishna.Elango@Sun.COM * Types of TLP logs seen in SW/Leaf, and what to extract:
252810187SKrishna.Elango@Sun.COM *
252910187SKrishna.Elango@Sun.COM * Memory(DMA) - Requester BDF, address, PF_DMA_ADDR
253010187SKrishna.Elango@Sun.COM * Memory(PIO) - address, PF_PIO_ADDR
253110187SKrishna.Elango@Sun.COM * CFG - Destined BDF, address, PF_CFG_ADDR
253210187SKrishna.Elango@Sun.COM * Completion(DMA) - Requester BDF, PF_DMA_ADDR
253310187SKrishna.Elango@Sun.COM * Completion(PIO) - Requester BDF, PF_PIO_ADDR
253410187SKrishna.Elango@Sun.COM *
253510187SKrishna.Elango@Sun.COM * The adv_reg_p must be passed in separately for use with SPARC RPs. A
253610187SKrishna.Elango@Sun.COM * SPARC RP could have multiple AER header logs which cannot be directly
253710187SKrishna.Elango@Sun.COM * accessed via the bus_p.
253810187SKrishna.Elango@Sun.COM */
253910187SKrishna.Elango@Sun.COM int
pf_tlp_decode(pcie_bus_t * bus_p,pf_pcie_adv_err_regs_t * adv_reg_p)254010187SKrishna.Elango@Sun.COM pf_tlp_decode(pcie_bus_t *bus_p, pf_pcie_adv_err_regs_t *adv_reg_p) {
254110187SKrishna.Elango@Sun.COM pcie_tlp_hdr_t *tlp_hdr = (pcie_tlp_hdr_t *)adv_reg_p->pcie_ue_hdr;
254210187SKrishna.Elango@Sun.COM pcie_req_id_t my_bdf, tlp_bdf, flt_bdf = PCIE_INVALID_BDF;
254310187SKrishna.Elango@Sun.COM uint64_t flt_addr = 0;
254410187SKrishna.Elango@Sun.COM uint32_t flt_trans_type = 0;
254510187SKrishna.Elango@Sun.COM
254610187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_addr = 0;
254710187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
254810187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_trans = 0;
254910187SKrishna.Elango@Sun.COM
255010187SKrishna.Elango@Sun.COM my_bdf = bus_p->bus_bdf;
255110187SKrishna.Elango@Sun.COM switch (tlp_hdr->type) {
255210187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_IO:
255310187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_MEM:
255410187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_MEMLK:
255510187SKrishna.Elango@Sun.COM /* Grab the 32/64bit fault address */
255610187SKrishna.Elango@Sun.COM if (tlp_hdr->fmt & 0x1) {
255710187SKrishna.Elango@Sun.COM flt_addr = ((uint64_t)adv_reg_p->pcie_ue_hdr[2] << 32);
255810187SKrishna.Elango@Sun.COM flt_addr |= adv_reg_p->pcie_ue_hdr[3];
255910187SKrishna.Elango@Sun.COM } else {
256010187SKrishna.Elango@Sun.COM flt_addr = adv_reg_p->pcie_ue_hdr[2];
256110187SKrishna.Elango@Sun.COM }
256210187SKrishna.Elango@Sun.COM
256310187SKrishna.Elango@Sun.COM tlp_bdf = (pcie_req_id_t)(adv_reg_p->pcie_ue_hdr[1] >> 16);
256410187SKrishna.Elango@Sun.COM
256510187SKrishna.Elango@Sun.COM /*
256610187SKrishna.Elango@Sun.COM * If the req bdf >= this.bdf, then it means the request is this
256710187SKrishna.Elango@Sun.COM * device or came from a device below it. Unless this device is
256810187SKrishna.Elango@Sun.COM * a PCIe root port then it means is a DMA, otherwise PIO.
256910187SKrishna.Elango@Sun.COM */
257010187SKrishna.Elango@Sun.COM if ((tlp_bdf >= my_bdf) && !PCIE_IS_ROOT(bus_p)) {
257110187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_DMA;
257210187SKrishna.Elango@Sun.COM flt_bdf = tlp_bdf;
257310187SKrishna.Elango@Sun.COM } else if (PCIE_IS_ROOT(bus_p) &&
257410187SKrishna.Elango@Sun.COM (PF_FIRST_AER_ERR(PCIE_AER_UCE_PTLP, adv_reg_p) ||
257510187SKrishna.Elango@Sun.COM (PF_FIRST_AER_ERR(PCIE_AER_UCE_CA, adv_reg_p)))) {
257610187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_DMA;
257710187SKrishna.Elango@Sun.COM flt_bdf = tlp_bdf;
257810187SKrishna.Elango@Sun.COM } else {
257910187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_PIO;
258010187SKrishna.Elango@Sun.COM flt_bdf = PCIE_INVALID_BDF;
258110187SKrishna.Elango@Sun.COM }
258210187SKrishna.Elango@Sun.COM break;
258310187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_CFG0:
258410187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_CFG1:
258510187SKrishna.Elango@Sun.COM flt_addr = 0;
258610187SKrishna.Elango@Sun.COM flt_bdf = (pcie_req_id_t)(adv_reg_p->pcie_ue_hdr[2] >> 16);
258710187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_CFG;
258810187SKrishna.Elango@Sun.COM break;
258910187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_CPL:
259010187SKrishna.Elango@Sun.COM case PCIE_TLP_TYPE_CPLLK:
259110187SKrishna.Elango@Sun.COM {
259211596SJason.Beloro@Sun.COM pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)&adv_reg_p->pcie_ue_hdr[1];
259310187SKrishna.Elango@Sun.COM
259410187SKrishna.Elango@Sun.COM flt_addr = NULL;
259511654SKrishna.Elango@Sun.COM flt_bdf = (cpl_tlp->rid > cpl_tlp->cid) ? cpl_tlp->rid :
259611654SKrishna.Elango@Sun.COM cpl_tlp->cid;
259710187SKrishna.Elango@Sun.COM
259810187SKrishna.Elango@Sun.COM /*
259910187SKrishna.Elango@Sun.COM * If the cpl bdf < this.bdf, then it means the request is this
260010187SKrishna.Elango@Sun.COM * device or came from a device below it. Unless this device is
260110187SKrishna.Elango@Sun.COM * a PCIe root port then it means is a DMA, otherwise PIO.
260210187SKrishna.Elango@Sun.COM */
260310187SKrishna.Elango@Sun.COM if (cpl_tlp->rid > cpl_tlp->cid) {
260410187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_DMA;
260510187SKrishna.Elango@Sun.COM } else {
260610187SKrishna.Elango@Sun.COM flt_trans_type = PF_ADDR_PIO | PF_ADDR_CFG;
260710187SKrishna.Elango@Sun.COM }
260810187SKrishna.Elango@Sun.COM break;
260910187SKrishna.Elango@Sun.COM }
261010187SKrishna.Elango@Sun.COM default:
261110187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
261210187SKrishna.Elango@Sun.COM }
261310187SKrishna.Elango@Sun.COM
261410187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_addr = flt_addr;
261510187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_bdf = flt_bdf;
261610187SKrishna.Elango@Sun.COM adv_reg_p->pcie_ue_tgt_trans = flt_trans_type;
261710187SKrishna.Elango@Sun.COM
261810187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
261910187SKrishna.Elango@Sun.COM }
262010187SKrishna.Elango@Sun.COM
262110187SKrishna.Elango@Sun.COM #define PCIE_EREPORT DDI_IO_CLASS "." PCI_ERROR_SUBCLASS "." PCIEX_FABRIC
262210187SKrishna.Elango@Sun.COM static int
pf_ereport_setup(dev_info_t * dip,uint64_t ena,nvlist_t ** ereport,nvlist_t ** detector,errorq_elem_t ** eqep)262310187SKrishna.Elango@Sun.COM pf_ereport_setup(dev_info_t *dip, uint64_t ena, nvlist_t **ereport,
262410187SKrishna.Elango@Sun.COM nvlist_t **detector, errorq_elem_t **eqep)
262510187SKrishna.Elango@Sun.COM {
262610187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
262710187SKrishna.Elango@Sun.COM char device_path[MAXPATHLEN];
262810187SKrishna.Elango@Sun.COM nv_alloc_t *nva;
262910187SKrishna.Elango@Sun.COM
263010187SKrishna.Elango@Sun.COM *eqep = errorq_reserve(fmhdl->fh_errorq);
263110187SKrishna.Elango@Sun.COM if (*eqep == NULL) {
263210187SKrishna.Elango@Sun.COM atomic_add_64(&fmhdl->fh_kstat.fek_erpt_dropped.value.ui64, 1);
263310187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
263410187SKrishna.Elango@Sun.COM }
263510187SKrishna.Elango@Sun.COM
263610187SKrishna.Elango@Sun.COM *ereport = errorq_elem_nvl(fmhdl->fh_errorq, *eqep);
263710187SKrishna.Elango@Sun.COM nva = errorq_elem_nva(fmhdl->fh_errorq, *eqep);
263810187SKrishna.Elango@Sun.COM
263910187SKrishna.Elango@Sun.COM ASSERT(*ereport);
264010187SKrishna.Elango@Sun.COM ASSERT(nva);
264110187SKrishna.Elango@Sun.COM
264210187SKrishna.Elango@Sun.COM /*
264310187SKrishna.Elango@Sun.COM * Use the dev_path/devid for this device instance.
264410187SKrishna.Elango@Sun.COM */
264510187SKrishna.Elango@Sun.COM *detector = fm_nvlist_create(nva);
264610187SKrishna.Elango@Sun.COM if (dip == ddi_root_node()) {
264710187SKrishna.Elango@Sun.COM device_path[0] = '/';
264810187SKrishna.Elango@Sun.COM device_path[1] = '\0';
264910187SKrishna.Elango@Sun.COM } else {
265010187SKrishna.Elango@Sun.COM (void) ddi_pathname(dip, device_path);
265110187SKrishna.Elango@Sun.COM }
265210187SKrishna.Elango@Sun.COM
265310187SKrishna.Elango@Sun.COM fm_fmri_dev_set(*detector, FM_DEV_SCHEME_VERSION, NULL,
265412213SGavin.Maltby@Sun.COM device_path, NULL, NULL);
265510187SKrishna.Elango@Sun.COM
265610187SKrishna.Elango@Sun.COM if (ena == 0)
265710187SKrishna.Elango@Sun.COM ena = fm_ena_generate(0, FM_ENA_FMT1);
265810187SKrishna.Elango@Sun.COM
265910187SKrishna.Elango@Sun.COM fm_ereport_set(*ereport, 0, PCIE_EREPORT, ena, *detector, NULL);
266010187SKrishna.Elango@Sun.COM
266110187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
266210187SKrishna.Elango@Sun.COM }
266310187SKrishna.Elango@Sun.COM
266410187SKrishna.Elango@Sun.COM /* ARGSUSED */
266510187SKrishna.Elango@Sun.COM static void
pf_ereport_post(dev_info_t * dip,nvlist_t ** ereport,nvlist_t ** detector,errorq_elem_t ** eqep)266610187SKrishna.Elango@Sun.COM pf_ereport_post(dev_info_t *dip, nvlist_t **ereport, nvlist_t **detector,
266710187SKrishna.Elango@Sun.COM errorq_elem_t **eqep)
266810187SKrishna.Elango@Sun.COM {
266910187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
267010187SKrishna.Elango@Sun.COM
267110187SKrishna.Elango@Sun.COM errorq_commit(fmhdl->fh_errorq, *eqep, ERRORQ_ASYNC);
267210187SKrishna.Elango@Sun.COM }
267310187SKrishna.Elango@Sun.COM
267410187SKrishna.Elango@Sun.COM static void
pf_send_ereport(ddi_fm_error_t * derr,pf_impl_t * impl)267510187SKrishna.Elango@Sun.COM pf_send_ereport(ddi_fm_error_t *derr, pf_impl_t *impl)
267610187SKrishna.Elango@Sun.COM {
267710187SKrishna.Elango@Sun.COM nvlist_t *ereport;
267810187SKrishna.Elango@Sun.COM nvlist_t *detector;
267910187SKrishna.Elango@Sun.COM errorq_elem_t *eqep;
268010187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p;
268110187SKrishna.Elango@Sun.COM pf_data_t *pfd_p;
268210187SKrishna.Elango@Sun.COM uint32_t total = impl->pf_total;
268310187SKrishna.Elango@Sun.COM
268410187SKrishna.Elango@Sun.COM /*
268510187SKrishna.Elango@Sun.COM * Ereports need to be sent in a top down fashion. The fabric translator
268610187SKrishna.Elango@Sun.COM * expects the ereports from the Root first. This is needed to tell if
268710187SKrishna.Elango@Sun.COM * the system contains a PCIe complaint RC/RP.
268810187SKrishna.Elango@Sun.COM */
268910187SKrishna.Elango@Sun.COM for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) {
269010187SKrishna.Elango@Sun.COM bus_p = PCIE_PFD2BUS(pfd_p);
269110187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE;
269210187SKrishna.Elango@Sun.COM
269310187SKrishna.Elango@Sun.COM if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED ||
269410187SKrishna.Elango@Sun.COM !DDI_FM_EREPORT_CAP(ddi_fm_capable(PCIE_PFD2DIP(pfd_p))))
269510187SKrishna.Elango@Sun.COM continue;
269610187SKrishna.Elango@Sun.COM
269710187SKrishna.Elango@Sun.COM if (pf_ereport_setup(PCIE_BUS2DIP(bus_p), derr->fme_ena,
269810187SKrishna.Elango@Sun.COM &ereport, &detector, &eqep) != DDI_SUCCESS)
269910187SKrishna.Elango@Sun.COM continue;
270010187SKrishna.Elango@Sun.COM
270111654SKrishna.Elango@Sun.COM if (PFD_IS_RC(pfd_p)) {
270211654SKrishna.Elango@Sun.COM fm_payload_set(ereport,
270311654SKrishna.Elango@Sun.COM "scan_bdf", DATA_TYPE_UINT16,
270411654SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf,
270511654SKrishna.Elango@Sun.COM "scan_addr", DATA_TYPE_UINT64,
270611654SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_addr,
270711654SKrishna.Elango@Sun.COM "intr_src", DATA_TYPE_UINT16,
270811654SKrishna.Elango@Sun.COM PCIE_ROOT_EH_SRC(pfd_p)->intr_type,
270911654SKrishna.Elango@Sun.COM NULL);
271011654SKrishna.Elango@Sun.COM goto generic;
271111654SKrishna.Elango@Sun.COM }
271211654SKrishna.Elango@Sun.COM
271310187SKrishna.Elango@Sun.COM /* Generic PCI device information */
271410187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
271510187SKrishna.Elango@Sun.COM "bdf", DATA_TYPE_UINT16, bus_p->bus_bdf,
271610187SKrishna.Elango@Sun.COM "device_id", DATA_TYPE_UINT16,
271710187SKrishna.Elango@Sun.COM (bus_p->bus_dev_ven_id >> 16),
271810187SKrishna.Elango@Sun.COM "vendor_id", DATA_TYPE_UINT16,
271910187SKrishna.Elango@Sun.COM (bus_p->bus_dev_ven_id & 0xFFFF),
272010187SKrishna.Elango@Sun.COM "rev_id", DATA_TYPE_UINT8, bus_p->bus_rev_id,
272110187SKrishna.Elango@Sun.COM "dev_type", DATA_TYPE_UINT16, bus_p->bus_dev_type,
272210187SKrishna.Elango@Sun.COM "pcie_off", DATA_TYPE_UINT16, bus_p->bus_pcie_off,
272310187SKrishna.Elango@Sun.COM "pcix_off", DATA_TYPE_UINT16, bus_p->bus_pcix_off,
272410187SKrishna.Elango@Sun.COM "aer_off", DATA_TYPE_UINT16, bus_p->bus_aer_off,
272510187SKrishna.Elango@Sun.COM "ecc_ver", DATA_TYPE_UINT16, bus_p->bus_ecc_ver,
272610187SKrishna.Elango@Sun.COM NULL);
272710187SKrishna.Elango@Sun.COM
272810187SKrishna.Elango@Sun.COM /* PCI registers */
272910187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
273010187SKrishna.Elango@Sun.COM "pci_status", DATA_TYPE_UINT16,
273110187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p)->pci_err_status,
273210187SKrishna.Elango@Sun.COM "pci_command", DATA_TYPE_UINT16,
273310187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p)->pci_cfg_comm,
273410187SKrishna.Elango@Sun.COM NULL);
273510187SKrishna.Elango@Sun.COM
273610187SKrishna.Elango@Sun.COM /* PCI bridge registers */
273710187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) {
273810187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
273910187SKrishna.Elango@Sun.COM "pci_bdg_sec_status", DATA_TYPE_UINT16,
274010187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat,
274110187SKrishna.Elango@Sun.COM "pci_bdg_ctrl", DATA_TYPE_UINT16,
274210187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p)->pci_bdg_ctrl,
274310187SKrishna.Elango@Sun.COM NULL);
274410187SKrishna.Elango@Sun.COM }
274510187SKrishna.Elango@Sun.COM
274610187SKrishna.Elango@Sun.COM /* PCIx registers */
274710187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIX(bus_p) && !PCIE_IS_BDG(bus_p)) {
274810187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
274910187SKrishna.Elango@Sun.COM "pcix_status", DATA_TYPE_UINT32,
275010187SKrishna.Elango@Sun.COM PCIX_ERR_REG(pfd_p)->pcix_status,
275110187SKrishna.Elango@Sun.COM "pcix_command", DATA_TYPE_UINT16,
275210187SKrishna.Elango@Sun.COM PCIX_ERR_REG(pfd_p)->pcix_command,
275310187SKrishna.Elango@Sun.COM NULL);
275410187SKrishna.Elango@Sun.COM }
275510187SKrishna.Elango@Sun.COM
275610187SKrishna.Elango@Sun.COM /* PCIx ECC Registers */
275710187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
275810187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *ecc_bdg_reg;
275910187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *ecc_reg;
276010187SKrishna.Elango@Sun.COM
276110187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p))
276210187SKrishna.Elango@Sun.COM ecc_bdg_reg = PCIX_BDG_ECC_REG(pfd_p, 0);
276310187SKrishna.Elango@Sun.COM ecc_reg = PCIX_ECC_REG(pfd_p);
276410187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
276510187SKrishna.Elango@Sun.COM "pcix_ecc_control_0", DATA_TYPE_UINT16,
276610187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ?
276710187SKrishna.Elango@Sun.COM (ecc_bdg_reg->pcix_ecc_ctlstat >> 16) :
276810187SKrishna.Elango@Sun.COM (ecc_reg->pcix_ecc_ctlstat >> 16),
276910187SKrishna.Elango@Sun.COM "pcix_ecc_status_0", DATA_TYPE_UINT16,
277010187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ?
277110187SKrishna.Elango@Sun.COM (ecc_bdg_reg->pcix_ecc_ctlstat & 0xFFFF) :
277210187SKrishna.Elango@Sun.COM (ecc_reg->pcix_ecc_ctlstat & 0xFFFF),
277310187SKrishna.Elango@Sun.COM "pcix_ecc_fst_addr_0", DATA_TYPE_UINT32,
277410187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ?
277510187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_fstaddr :
277610187SKrishna.Elango@Sun.COM ecc_reg->pcix_ecc_fstaddr,
277710187SKrishna.Elango@Sun.COM "pcix_ecc_sec_addr_0", DATA_TYPE_UINT32,
277810187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ?
277910187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_secaddr :
278010187SKrishna.Elango@Sun.COM ecc_reg->pcix_ecc_secaddr,
278110187SKrishna.Elango@Sun.COM "pcix_ecc_attr_0", DATA_TYPE_UINT32,
278210187SKrishna.Elango@Sun.COM PCIE_IS_BDG(bus_p) ?
278310187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_attr :
278410187SKrishna.Elango@Sun.COM ecc_reg->pcix_ecc_attr,
278510187SKrishna.Elango@Sun.COM NULL);
278610187SKrishna.Elango@Sun.COM }
278710187SKrishna.Elango@Sun.COM
278810187SKrishna.Elango@Sun.COM /* PCIx ECC Bridge Registers */
278910187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p) && PCIE_IS_BDG(bus_p)) {
279010187SKrishna.Elango@Sun.COM pf_pcix_ecc_regs_t *ecc_bdg_reg;
279110187SKrishna.Elango@Sun.COM
279210187SKrishna.Elango@Sun.COM ecc_bdg_reg = PCIX_BDG_ECC_REG(pfd_p, 1);
279310187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
279410187SKrishna.Elango@Sun.COM "pcix_ecc_control_1", DATA_TYPE_UINT16,
279510187SKrishna.Elango@Sun.COM (ecc_bdg_reg->pcix_ecc_ctlstat >> 16),
279610187SKrishna.Elango@Sun.COM "pcix_ecc_status_1", DATA_TYPE_UINT16,
279710187SKrishna.Elango@Sun.COM (ecc_bdg_reg->pcix_ecc_ctlstat & 0xFFFF),
279810187SKrishna.Elango@Sun.COM "pcix_ecc_fst_addr_1", DATA_TYPE_UINT32,
279910187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_fstaddr,
280010187SKrishna.Elango@Sun.COM "pcix_ecc_sec_addr_1", DATA_TYPE_UINT32,
280110187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_secaddr,
280210187SKrishna.Elango@Sun.COM "pcix_ecc_attr_1", DATA_TYPE_UINT32,
280310187SKrishna.Elango@Sun.COM ecc_bdg_reg->pcix_ecc_attr,
280410187SKrishna.Elango@Sun.COM NULL);
280510187SKrishna.Elango@Sun.COM }
280610187SKrishna.Elango@Sun.COM
280710187SKrishna.Elango@Sun.COM /* PCIx Bridge */
280810187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIX(bus_p) && PCIE_IS_BDG(bus_p)) {
280910187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
281010187SKrishna.Elango@Sun.COM "pcix_bdg_status", DATA_TYPE_UINT32,
281110187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_stat,
281210187SKrishna.Elango@Sun.COM "pcix_bdg_sec_status", DATA_TYPE_UINT16,
281310187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_sec_stat,
281410187SKrishna.Elango@Sun.COM NULL);
281510187SKrishna.Elango@Sun.COM }
281610187SKrishna.Elango@Sun.COM
281710187SKrishna.Elango@Sun.COM /* PCIe registers */
281810187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) {
281910187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
282010187SKrishna.Elango@Sun.COM "pcie_status", DATA_TYPE_UINT16,
282110187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status,
282210187SKrishna.Elango@Sun.COM "pcie_command", DATA_TYPE_UINT16,
282310187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_ctl,
282410187SKrishna.Elango@Sun.COM "pcie_dev_cap", DATA_TYPE_UINT32,
282510187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_dev_cap,
282610187SKrishna.Elango@Sun.COM NULL);
282710187SKrishna.Elango@Sun.COM }
282810187SKrishna.Elango@Sun.COM
282910187SKrishna.Elango@Sun.COM /* PCIe AER registers */
283010187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(bus_p)) {
283110187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
283210187SKrishna.Elango@Sun.COM "pcie_adv_ctl", DATA_TYPE_UINT32,
283310187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_adv_ctl,
283410187SKrishna.Elango@Sun.COM "pcie_ue_status", DATA_TYPE_UINT32,
283510187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_status,
283610187SKrishna.Elango@Sun.COM "pcie_ue_mask", DATA_TYPE_UINT32,
283710187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_mask,
283810187SKrishna.Elango@Sun.COM "pcie_ue_sev", DATA_TYPE_UINT32,
283910187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_sev,
284010187SKrishna.Elango@Sun.COM "pcie_ue_hdr0", DATA_TYPE_UINT32,
284110187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[0],
284210187SKrishna.Elango@Sun.COM "pcie_ue_hdr1", DATA_TYPE_UINT32,
284310187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[1],
284410187SKrishna.Elango@Sun.COM "pcie_ue_hdr2", DATA_TYPE_UINT32,
284510187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[2],
284610187SKrishna.Elango@Sun.COM "pcie_ue_hdr3", DATA_TYPE_UINT32,
284710187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_hdr[3],
284810187SKrishna.Elango@Sun.COM "pcie_ce_status", DATA_TYPE_UINT32,
284910187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ce_status,
285010187SKrishna.Elango@Sun.COM "pcie_ce_mask", DATA_TYPE_UINT32,
285110187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ce_mask,
285210187SKrishna.Elango@Sun.COM NULL);
285310187SKrishna.Elango@Sun.COM }
285410187SKrishna.Elango@Sun.COM
285510187SKrishna.Elango@Sun.COM /* PCIe AER decoded header */
285610187SKrishna.Elango@Sun.COM if (HAS_AER_LOGS(pfd_p, PCIE_ADV_REG(pfd_p)->pcie_ue_status)) {
285710187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
285810187SKrishna.Elango@Sun.COM "pcie_ue_tgt_trans", DATA_TYPE_UINT32,
285910187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_trans,
286010187SKrishna.Elango@Sun.COM "pcie_ue_tgt_addr", DATA_TYPE_UINT64,
286110187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr,
286210187SKrishna.Elango@Sun.COM "pcie_ue_tgt_bdf", DATA_TYPE_UINT16,
286310187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf,
286410187SKrishna.Elango@Sun.COM NULL);
286510187SKrishna.Elango@Sun.COM /* Clear these values as they no longer valid */
286610187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_trans = 0;
286710187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr = 0;
286810187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
286910187SKrishna.Elango@Sun.COM }
287010187SKrishna.Elango@Sun.COM
287110187SKrishna.Elango@Sun.COM /* PCIe BDG AER registers */
287210187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_HAS_AER(bus_p)) {
287310187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
287410187SKrishna.Elango@Sun.COM "pcie_sue_adv_ctl", DATA_TYPE_UINT32,
287510187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_ctl,
287610187SKrishna.Elango@Sun.COM "pcie_sue_status", DATA_TYPE_UINT32,
287710187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status,
287810187SKrishna.Elango@Sun.COM "pcie_sue_mask", DATA_TYPE_UINT32,
287910187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_mask,
288010187SKrishna.Elango@Sun.COM "pcie_sue_sev", DATA_TYPE_UINT32,
288110187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_sev,
288210187SKrishna.Elango@Sun.COM "pcie_sue_hdr0", DATA_TYPE_UINT32,
288310187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[0],
288410187SKrishna.Elango@Sun.COM "pcie_sue_hdr1", DATA_TYPE_UINT32,
288510187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[1],
288610187SKrishna.Elango@Sun.COM "pcie_sue_hdr2", DATA_TYPE_UINT32,
288710187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[2],
288810187SKrishna.Elango@Sun.COM "pcie_sue_hdr3", DATA_TYPE_UINT32,
288910187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_hdr[3],
289010187SKrishna.Elango@Sun.COM NULL);
289110187SKrishna.Elango@Sun.COM }
289210187SKrishna.Elango@Sun.COM
289310187SKrishna.Elango@Sun.COM /* PCIe BDG AER decoded header */
289410187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && HAS_SAER_LOGS(pfd_p,
289510187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_status)) {
289610187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
289710187SKrishna.Elango@Sun.COM "pcie_sue_tgt_trans", DATA_TYPE_UINT32,
289810187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans,
289910187SKrishna.Elango@Sun.COM "pcie_sue_tgt_addr", DATA_TYPE_UINT64,
290010187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr,
290110187SKrishna.Elango@Sun.COM "pcie_sue_tgt_bdf", DATA_TYPE_UINT16,
290210187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf,
290310187SKrishna.Elango@Sun.COM NULL);
290410187SKrishna.Elango@Sun.COM /* Clear these values as they no longer valid */
290510187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_trans = 0;
290610187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_addr = 0;
290710187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf =
290810187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF;
290910187SKrishna.Elango@Sun.COM }
291010187SKrishna.Elango@Sun.COM
291110187SKrishna.Elango@Sun.COM /* PCIe RP registers */
291210187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) {
291310187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
291410187SKrishna.Elango@Sun.COM "pcie_rp_status", DATA_TYPE_UINT32,
291510187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p)->pcie_rp_status,
291610187SKrishna.Elango@Sun.COM "pcie_rp_control", DATA_TYPE_UINT16,
291710187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p)->pcie_rp_ctl,
291810187SKrishna.Elango@Sun.COM NULL);
291910187SKrishna.Elango@Sun.COM }
292010187SKrishna.Elango@Sun.COM
292110187SKrishna.Elango@Sun.COM /* PCIe RP AER registers */
292210187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p)) {
292310187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
292410187SKrishna.Elango@Sun.COM "pcie_adv_rp_status", DATA_TYPE_UINT32,
292510187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_err_status,
292610187SKrishna.Elango@Sun.COM "pcie_adv_rp_command", DATA_TYPE_UINT32,
292710187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_err_cmd,
292810187SKrishna.Elango@Sun.COM "pcie_adv_rp_ce_src_id", DATA_TYPE_UINT16,
292910187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id,
293010187SKrishna.Elango@Sun.COM "pcie_adv_rp_ue_src_id", DATA_TYPE_UINT16,
293110187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id,
293210187SKrishna.Elango@Sun.COM NULL);
293310187SKrishna.Elango@Sun.COM }
293410187SKrishna.Elango@Sun.COM
293511654SKrishna.Elango@Sun.COM generic:
293611596SJason.Beloro@Sun.COM /* IOV related information */
293711596SJason.Beloro@Sun.COM if (!PCIE_BDG_IS_UNASSIGNED(PCIE_PFD2BUS(impl->pf_dq_head_p))) {
293811596SJason.Beloro@Sun.COM fm_payload_set(ereport,
293911596SJason.Beloro@Sun.COM "pcie_aff_flags", DATA_TYPE_UINT16,
294011596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags,
294111596SJason.Beloro@Sun.COM "pcie_aff_bdf", DATA_TYPE_UINT16,
294211596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf,
294311596SJason.Beloro@Sun.COM "orig_sev", DATA_TYPE_UINT32,
294411596SJason.Beloro@Sun.COM pfd_p->pe_orig_severity_flags,
294511596SJason.Beloro@Sun.COM NULL);
294611596SJason.Beloro@Sun.COM }
294711596SJason.Beloro@Sun.COM
294810187SKrishna.Elango@Sun.COM /* Misc ereport information */
294910187SKrishna.Elango@Sun.COM fm_payload_set(ereport,
295011654SKrishna.Elango@Sun.COM "remainder", DATA_TYPE_UINT32, --total,
295110187SKrishna.Elango@Sun.COM "severity", DATA_TYPE_UINT32, pfd_p->pe_severity_flags,
295210187SKrishna.Elango@Sun.COM NULL);
295310187SKrishna.Elango@Sun.COM
295410187SKrishna.Elango@Sun.COM pf_ereport_post(PCIE_BUS2DIP(bus_p), &ereport, &detector,
295510187SKrishna.Elango@Sun.COM &eqep);
295610187SKrishna.Elango@Sun.COM }
295710187SKrishna.Elango@Sun.COM
295810187SKrishna.Elango@Sun.COM /* Unlock all the devices in the queue */
295910187SKrishna.Elango@Sun.COM for (pfd_p = impl->pf_dq_tail_p; pfd_p; pfd_p = pfd_p->pe_prev) {
296010187SKrishna.Elango@Sun.COM if (pfd_p->pe_lock) {
296110187SKrishna.Elango@Sun.COM pf_handler_exit(PCIE_PFD2DIP(pfd_p));
296210187SKrishna.Elango@Sun.COM }
296310187SKrishna.Elango@Sun.COM }
296410187SKrishna.Elango@Sun.COM }
296510187SKrishna.Elango@Sun.COM
296610187SKrishna.Elango@Sun.COM /*
296710187SKrishna.Elango@Sun.COM * pf_handler_enter must be called to serial access to each device's pf_data_t.
296810187SKrishna.Elango@Sun.COM * Once error handling is finished with the device call pf_handler_exit to allow
296910187SKrishna.Elango@Sun.COM * other threads to access it. The same thread may call pf_handler_enter
297010187SKrishna.Elango@Sun.COM * several times without any consequences.
297110187SKrishna.Elango@Sun.COM *
297210187SKrishna.Elango@Sun.COM * The "impl" variable is passed in during scan fabric to double check that
297310187SKrishna.Elango@Sun.COM * there is not a recursive algorithm and to ensure only one thread is doing a
297410187SKrishna.Elango@Sun.COM * fabric scan at all times.
297510187SKrishna.Elango@Sun.COM *
297610187SKrishna.Elango@Sun.COM * In some cases "impl" is not available, such as "child lookup" being called
297710187SKrishna.Elango@Sun.COM * from outside of scan fabric, just pass in NULL for this variable and this
297810187SKrishna.Elango@Sun.COM * extra check will be skipped.
297910187SKrishna.Elango@Sun.COM */
298010187SKrishna.Elango@Sun.COM static int
pf_handler_enter(dev_info_t * dip,pf_impl_t * impl)298110187SKrishna.Elango@Sun.COM pf_handler_enter(dev_info_t *dip, pf_impl_t *impl)
298210187SKrishna.Elango@Sun.COM {
298310187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
298410187SKrishna.Elango@Sun.COM
298510187SKrishna.Elango@Sun.COM ASSERT(pfd_p);
298610187SKrishna.Elango@Sun.COM
298710187SKrishna.Elango@Sun.COM /*
298810187SKrishna.Elango@Sun.COM * Check to see if the lock has already been taken by this
298910187SKrishna.Elango@Sun.COM * thread. If so just return and don't take lock again.
299010187SKrishna.Elango@Sun.COM */
299110187SKrishna.Elango@Sun.COM if (!pfd_p->pe_lock || !impl) {
299210187SKrishna.Elango@Sun.COM i_ddi_fm_handler_enter(dip);
299310187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_TRUE;
299410187SKrishna.Elango@Sun.COM return (PF_SCAN_SUCCESS);
299510187SKrishna.Elango@Sun.COM }
299610187SKrishna.Elango@Sun.COM
299710187SKrishna.Elango@Sun.COM /* Check to see that this dip is already in the "impl" error queue */
299810187SKrishna.Elango@Sun.COM for (pfd_p = impl->pf_dq_head_p; pfd_p; pfd_p = pfd_p->pe_next) {
299910187SKrishna.Elango@Sun.COM if (PCIE_PFD2DIP(pfd_p) == dip) {
300010187SKrishna.Elango@Sun.COM return (PF_SCAN_SUCCESS);
300110187SKrishna.Elango@Sun.COM }
300210187SKrishna.Elango@Sun.COM }
300310187SKrishna.Elango@Sun.COM
300410187SKrishna.Elango@Sun.COM return (PF_SCAN_DEADLOCK);
300510187SKrishna.Elango@Sun.COM }
300610187SKrishna.Elango@Sun.COM
300710187SKrishna.Elango@Sun.COM static void
pf_handler_exit(dev_info_t * dip)300810187SKrishna.Elango@Sun.COM pf_handler_exit(dev_info_t *dip)
300910187SKrishna.Elango@Sun.COM {
301010187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
301110187SKrishna.Elango@Sun.COM
301210187SKrishna.Elango@Sun.COM ASSERT(pfd_p);
301310187SKrishna.Elango@Sun.COM
301410187SKrishna.Elango@Sun.COM ASSERT(pfd_p->pe_lock == B_TRUE);
301510187SKrishna.Elango@Sun.COM i_ddi_fm_handler_exit(dip);
301610187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE;
301710187SKrishna.Elango@Sun.COM }
301810187SKrishna.Elango@Sun.COM
301910187SKrishna.Elango@Sun.COM /*
302010187SKrishna.Elango@Sun.COM * This function calls the driver's callback function (if it's FMA hardened
302110187SKrishna.Elango@Sun.COM * and callback capable). This function relies on the current thread already
302210187SKrishna.Elango@Sun.COM * owning the driver's fmhdl lock.
302310187SKrishna.Elango@Sun.COM */
302410187SKrishna.Elango@Sun.COM static int
pf_fm_callback(dev_info_t * dip,ddi_fm_error_t * derr)302510187SKrishna.Elango@Sun.COM pf_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr)
302610187SKrishna.Elango@Sun.COM {
302710187SKrishna.Elango@Sun.COM int cb_sts = DDI_FM_OK;
302810187SKrishna.Elango@Sun.COM
302910187SKrishna.Elango@Sun.COM if (DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
303010187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(dip);
303110187SKrishna.Elango@Sun.COM struct i_ddi_fmhdl *hdl = DEVI(pdip)->devi_fmhdl;
303210187SKrishna.Elango@Sun.COM struct i_ddi_fmtgt *tgt = hdl->fh_tgts;
303310187SKrishna.Elango@Sun.COM struct i_ddi_errhdl *errhdl;
303410187SKrishna.Elango@Sun.COM while (tgt != NULL) {
303510187SKrishna.Elango@Sun.COM if (dip == tgt->ft_dip) {
303610187SKrishna.Elango@Sun.COM errhdl = tgt->ft_errhdl;
303710187SKrishna.Elango@Sun.COM cb_sts = errhdl->eh_func(dip, derr,
303810187SKrishna.Elango@Sun.COM errhdl->eh_impl);
303910187SKrishna.Elango@Sun.COM break;
304010187SKrishna.Elango@Sun.COM }
304110187SKrishna.Elango@Sun.COM tgt = tgt->ft_next;
304210187SKrishna.Elango@Sun.COM }
304310187SKrishna.Elango@Sun.COM }
304410187SKrishna.Elango@Sun.COM return (cb_sts);
304510187SKrishna.Elango@Sun.COM }
304611596SJason.Beloro@Sun.COM
304711596SJason.Beloro@Sun.COM static void
pf_reset_pfd(pf_data_t * pfd_p)304811596SJason.Beloro@Sun.COM pf_reset_pfd(pf_data_t *pfd_p)
304911596SJason.Beloro@Sun.COM {
305011596SJason.Beloro@Sun.COM pcie_bus_t *bus_p = PCIE_PFD2BUS(pfd_p);
305111596SJason.Beloro@Sun.COM
305211596SJason.Beloro@Sun.COM pfd_p->pe_severity_flags = 0;
305311596SJason.Beloro@Sun.COM pfd_p->pe_orig_severity_flags = 0;
305411596SJason.Beloro@Sun.COM /* pe_lock and pe_valid were reset in pf_send_ereport */
305511596SJason.Beloro@Sun.COM
305611596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = 0;
305711596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
305811596SJason.Beloro@Sun.COM
305911596SJason.Beloro@Sun.COM if (PCIE_IS_ROOT(bus_p)) {
306011596SJason.Beloro@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
306111596SJason.Beloro@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_addr = 0;
306211596SJason.Beloro@Sun.COM PCIE_ROOT_FAULT(pfd_p)->full_scan = B_FALSE;
306311596SJason.Beloro@Sun.COM PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_NONE;
306411596SJason.Beloro@Sun.COM PCIE_ROOT_EH_SRC(pfd_p)->intr_data = NULL;
306511596SJason.Beloro@Sun.COM }
306611596SJason.Beloro@Sun.COM
306711596SJason.Beloro@Sun.COM if (PCIE_IS_BDG(bus_p)) {
306811596SJason.Beloro@Sun.COM bzero(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t));
306911596SJason.Beloro@Sun.COM }
307011596SJason.Beloro@Sun.COM
307111596SJason.Beloro@Sun.COM PCI_ERR_REG(pfd_p)->pci_err_status = 0;
307211596SJason.Beloro@Sun.COM PCI_ERR_REG(pfd_p)->pci_cfg_comm = 0;
307311596SJason.Beloro@Sun.COM
307411596SJason.Beloro@Sun.COM if (PCIE_IS_PCIE(bus_p)) {
307511596SJason.Beloro@Sun.COM if (PCIE_IS_ROOT(bus_p)) {
307611596SJason.Beloro@Sun.COM bzero(PCIE_RP_REG(pfd_p),
307711596SJason.Beloro@Sun.COM sizeof (pf_pcie_rp_err_regs_t));
307811596SJason.Beloro@Sun.COM bzero(PCIE_ADV_RP_REG(pfd_p),
307911596SJason.Beloro@Sun.COM sizeof (pf_pcie_adv_rp_err_regs_t));
308011596SJason.Beloro@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id =
308111596SJason.Beloro@Sun.COM PCIE_INVALID_BDF;
308211596SJason.Beloro@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id =
308311596SJason.Beloro@Sun.COM PCIE_INVALID_BDF;
308411596SJason.Beloro@Sun.COM } else if (PCIE_IS_PCIE_BDG(bus_p)) {
308511596SJason.Beloro@Sun.COM bzero(PCIE_ADV_BDG_REG(pfd_p),
308611596SJason.Beloro@Sun.COM sizeof (pf_pcie_adv_bdg_err_regs_t));
308711596SJason.Beloro@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf =
308811596SJason.Beloro@Sun.COM PCIE_INVALID_BDF;
308911596SJason.Beloro@Sun.COM }
309011596SJason.Beloro@Sun.COM
309111596SJason.Beloro@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
309211596SJason.Beloro@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
309311596SJason.Beloro@Sun.COM bzero(PCIX_BDG_ECC_REG(pfd_p, 0),
309411596SJason.Beloro@Sun.COM sizeof (pf_pcix_ecc_regs_t));
309511596SJason.Beloro@Sun.COM bzero(PCIX_BDG_ECC_REG(pfd_p, 1),
309611596SJason.Beloro@Sun.COM sizeof (pf_pcix_ecc_regs_t));
309711596SJason.Beloro@Sun.COM }
309811596SJason.Beloro@Sun.COM PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_sec_stat = 0;
309911596SJason.Beloro@Sun.COM PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_stat = 0;
310011596SJason.Beloro@Sun.COM }
310111596SJason.Beloro@Sun.COM
310211596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_adv_ctl = 0;
310311596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_status = 0;
310411596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_mask = 0;
310511596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_sev = 0;
310611596SJason.Beloro@Sun.COM PCIE_ADV_HDR(pfd_p, 0) = 0;
310711596SJason.Beloro@Sun.COM PCIE_ADV_HDR(pfd_p, 1) = 0;
310811596SJason.Beloro@Sun.COM PCIE_ADV_HDR(pfd_p, 2) = 0;
310911596SJason.Beloro@Sun.COM PCIE_ADV_HDR(pfd_p, 3) = 0;
311011596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ce_status = 0;
311111596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ce_mask = 0;
311211596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_trans = 0;
311311596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_addr = 0;
311411596SJason.Beloro@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
311511596SJason.Beloro@Sun.COM
311611596SJason.Beloro@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_status = 0;
311711596SJason.Beloro@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_err_ctl = 0;
311811596SJason.Beloro@Sun.COM PCIE_ERR_REG(pfd_p)->pcie_dev_cap = 0;
311911596SJason.Beloro@Sun.COM
312011596SJason.Beloro@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) {
312111596SJason.Beloro@Sun.COM if (PCIE_IS_BDG(bus_p)) {
312211596SJason.Beloro@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
312311596SJason.Beloro@Sun.COM bzero(PCIX_BDG_ECC_REG(pfd_p, 0),
312411596SJason.Beloro@Sun.COM sizeof (pf_pcix_ecc_regs_t));
312511596SJason.Beloro@Sun.COM bzero(PCIX_BDG_ECC_REG(pfd_p, 1),
312611596SJason.Beloro@Sun.COM sizeof (pf_pcix_ecc_regs_t));
312711596SJason.Beloro@Sun.COM }
312811596SJason.Beloro@Sun.COM PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_sec_stat = 0;
312911596SJason.Beloro@Sun.COM PCIX_BDG_ERR_REG(pfd_p)->pcix_bdg_stat = 0;
313011596SJason.Beloro@Sun.COM } else {
313111596SJason.Beloro@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
313211596SJason.Beloro@Sun.COM bzero(PCIX_ECC_REG(pfd_p),
313311596SJason.Beloro@Sun.COM sizeof (pf_pcix_ecc_regs_t));
313411596SJason.Beloro@Sun.COM }
313511596SJason.Beloro@Sun.COM PCIX_ERR_REG(pfd_p)->pcix_command = 0;
313611596SJason.Beloro@Sun.COM PCIX_ERR_REG(pfd_p)->pcix_status = 0;
313711596SJason.Beloro@Sun.COM }
313811596SJason.Beloro@Sun.COM }
313911596SJason.Beloro@Sun.COM
314011596SJason.Beloro@Sun.COM pfd_p->pe_prev = NULL;
314111596SJason.Beloro@Sun.COM pfd_p->pe_next = NULL;
314211596SJason.Beloro@Sun.COM pfd_p->pe_rber_fatal = B_FALSE;
314311596SJason.Beloro@Sun.COM }
314411596SJason.Beloro@Sun.COM
314511596SJason.Beloro@Sun.COM pcie_bus_t *
pf_find_busp_by_bdf(pf_impl_t * impl,pcie_req_id_t bdf)314611596SJason.Beloro@Sun.COM pf_find_busp_by_bdf(pf_impl_t *impl, pcie_req_id_t bdf)
314711596SJason.Beloro@Sun.COM {
314811596SJason.Beloro@Sun.COM pcie_bus_t *temp_bus_p;
314911596SJason.Beloro@Sun.COM pf_data_t *temp_pfd_p;
315011596SJason.Beloro@Sun.COM
315111596SJason.Beloro@Sun.COM for (temp_pfd_p = impl->pf_dq_head_p;
315211596SJason.Beloro@Sun.COM temp_pfd_p;
315311596SJason.Beloro@Sun.COM temp_pfd_p = temp_pfd_p->pe_next) {
315411596SJason.Beloro@Sun.COM temp_bus_p = PCIE_PFD2BUS(temp_pfd_p);
315511596SJason.Beloro@Sun.COM
315611596SJason.Beloro@Sun.COM if (bdf == temp_bus_p->bus_bdf) {
315711596SJason.Beloro@Sun.COM return (temp_bus_p);
315811596SJason.Beloro@Sun.COM }
315911596SJason.Beloro@Sun.COM }
316011596SJason.Beloro@Sun.COM
316111596SJason.Beloro@Sun.COM return (NULL);
316211596SJason.Beloro@Sun.COM }
316311596SJason.Beloro@Sun.COM
316411596SJason.Beloro@Sun.COM pcie_bus_t *
pf_find_busp_by_addr(pf_impl_t * impl,uint64_t addr)316511596SJason.Beloro@Sun.COM pf_find_busp_by_addr(pf_impl_t *impl, uint64_t addr)
316611596SJason.Beloro@Sun.COM {
316711596SJason.Beloro@Sun.COM pcie_bus_t *temp_bus_p;
316811596SJason.Beloro@Sun.COM pf_data_t *temp_pfd_p;
316911596SJason.Beloro@Sun.COM
317011596SJason.Beloro@Sun.COM for (temp_pfd_p = impl->pf_dq_head_p;
317111596SJason.Beloro@Sun.COM temp_pfd_p;
317211596SJason.Beloro@Sun.COM temp_pfd_p = temp_pfd_p->pe_next) {
317311596SJason.Beloro@Sun.COM temp_bus_p = PCIE_PFD2BUS(temp_pfd_p);
317411596SJason.Beloro@Sun.COM
317511596SJason.Beloro@Sun.COM if (pf_in_assigned_addr(temp_bus_p, addr)) {
317611596SJason.Beloro@Sun.COM return (temp_bus_p);
317711596SJason.Beloro@Sun.COM }
317811596SJason.Beloro@Sun.COM }
317911596SJason.Beloro@Sun.COM
318011596SJason.Beloro@Sun.COM return (NULL);
318111596SJason.Beloro@Sun.COM }
318211596SJason.Beloro@Sun.COM
318311596SJason.Beloro@Sun.COM pcie_bus_t *
pf_find_busp_by_aer(pf_impl_t * impl,pf_data_t * pfd_p)318411596SJason.Beloro@Sun.COM pf_find_busp_by_aer(pf_impl_t *impl, pf_data_t *pfd_p)
318511596SJason.Beloro@Sun.COM {
318611596SJason.Beloro@Sun.COM pf_pcie_adv_err_regs_t *reg_p = PCIE_ADV_REG(pfd_p);
318711596SJason.Beloro@Sun.COM pcie_bus_t *temp_bus_p = NULL;
318811596SJason.Beloro@Sun.COM pcie_req_id_t bdf;
318911596SJason.Beloro@Sun.COM uint64_t addr;
319011596SJason.Beloro@Sun.COM pcie_tlp_hdr_t *tlp_hdr = (pcie_tlp_hdr_t *)reg_p->pcie_ue_hdr;
319111596SJason.Beloro@Sun.COM uint32_t trans_type = reg_p->pcie_ue_tgt_trans;
319211596SJason.Beloro@Sun.COM
319311596SJason.Beloro@Sun.COM if ((tlp_hdr->type == PCIE_TLP_TYPE_CPL) ||
319411596SJason.Beloro@Sun.COM (tlp_hdr->type == PCIE_TLP_TYPE_CPLLK)) {
319511596SJason.Beloro@Sun.COM pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)®_p->pcie_ue_hdr[1];
319611596SJason.Beloro@Sun.COM
319711596SJason.Beloro@Sun.COM bdf = (cpl_tlp->rid > cpl_tlp->cid) ? cpl_tlp->rid :
319811596SJason.Beloro@Sun.COM cpl_tlp->cid;
319911596SJason.Beloro@Sun.COM temp_bus_p = pf_find_busp_by_bdf(impl, bdf);
320011596SJason.Beloro@Sun.COM } else if (trans_type == PF_ADDR_PIO) {
320111596SJason.Beloro@Sun.COM addr = reg_p->pcie_ue_tgt_addr;
320211596SJason.Beloro@Sun.COM temp_bus_p = pf_find_busp_by_addr(impl, addr);
320311596SJason.Beloro@Sun.COM } else {
320411596SJason.Beloro@Sun.COM /* PF_ADDR_DMA type */
320511596SJason.Beloro@Sun.COM bdf = reg_p->pcie_ue_tgt_bdf;
320611596SJason.Beloro@Sun.COM temp_bus_p = pf_find_busp_by_bdf(impl, bdf);
320711596SJason.Beloro@Sun.COM }
320811596SJason.Beloro@Sun.COM
320911596SJason.Beloro@Sun.COM return (temp_bus_p);
321011596SJason.Beloro@Sun.COM }
321111596SJason.Beloro@Sun.COM
321211596SJason.Beloro@Sun.COM pcie_bus_t *
pf_find_busp_by_saer(pf_impl_t * impl,pf_data_t * pfd_p)321311596SJason.Beloro@Sun.COM pf_find_busp_by_saer(pf_impl_t *impl, pf_data_t *pfd_p)
321411596SJason.Beloro@Sun.COM {
321511596SJason.Beloro@Sun.COM pf_pcie_adv_bdg_err_regs_t *reg_p = PCIE_ADV_BDG_REG(pfd_p);
321611596SJason.Beloro@Sun.COM pcie_bus_t *temp_bus_p = NULL;
321711596SJason.Beloro@Sun.COM pcie_req_id_t bdf;
321811596SJason.Beloro@Sun.COM uint64_t addr;
321911596SJason.Beloro@Sun.COM
322011596SJason.Beloro@Sun.COM addr = reg_p->pcie_sue_tgt_addr;
322111596SJason.Beloro@Sun.COM bdf = reg_p->pcie_sue_tgt_bdf;
322211596SJason.Beloro@Sun.COM
322311596SJason.Beloro@Sun.COM if (addr != NULL) {
322411596SJason.Beloro@Sun.COM temp_bus_p = pf_find_busp_by_addr(impl, addr);
322511596SJason.Beloro@Sun.COM } else if (PCIE_CHECK_VALID_BDF(bdf)) {
322611596SJason.Beloro@Sun.COM temp_bus_p = pf_find_busp_by_bdf(impl, bdf);
322711596SJason.Beloro@Sun.COM }
322811596SJason.Beloro@Sun.COM
322911596SJason.Beloro@Sun.COM return (temp_bus_p);
323011596SJason.Beloro@Sun.COM }
3231