xref: /onnv-gate/usr/src/uts/common/io/pciex/pcie_fault.c (revision 12458:8a6b6f4699c0)
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 *)&reg_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