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