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