xref: /illumos-gate/usr/src/uts/sun4/io/px/px_fm.c (revision e214b19e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57aadd8d4Skini  * Common Development and Distribution License (the "License").
67aadd8d4Skini  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21e6b21d58SErwin T Tsaur 
227c478bd9Sstevel@tonic-gate /*
23e6b21d58SErwin T Tsaur  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
27f8d2de6bSjchu  * PX Fault Management Architecture
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
31f8d2de6bSjchu #include <sys/sunddi.h>
32f8d2de6bSjchu #include <sys/fm/protocol.h>
33f8d2de6bSjchu #include <sys/fm/util.h>
34eae2e508Skrishnae #include <sys/fm/io/pci.h>
35f8d2de6bSjchu #include <sys/membar.h>
367c478bd9Sstevel@tonic-gate #include "px_obj.h"
377c478bd9Sstevel@tonic-gate 
3849fbdd30SErwin T Tsaur extern uint_t px_ranges_phi_mask;
3949fbdd30SErwin T Tsaur 
40bf8fc234Set #define	PX_PCIE_PANIC_BITS \
41bf8fc234Set 	(PCIE_AER_UCE_DLP | PCIE_AER_UCE_FCP | PCIE_AER_UCE_TO | \
421ff65112Segillett 	PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP | PCIE_AER_UCE_ECRC)
43bf8fc234Set #define	PX_PCIE_NO_PANIC_BITS \
44bf8fc234Set 	(PCIE_AER_UCE_TRAINING | PCIE_AER_UCE_SD | PCIE_AER_UCE_CA | \
451ff65112Segillett 	PCIE_AER_UCE_UC | PCIE_AER_UCE_UR)
46bf8fc234Set 
47eae2e508Skrishnae /*
48eae2e508Skrishnae  * Global panicing state variabled used to control if further error handling
49eae2e508Skrishnae  * should occur.  If the system is already panic'ing or if PX itself has
50eae2e508Skrishnae  * recommended panic'ing the system, no further error handling should occur to
51eae2e508Skrishnae  * prevent the system from hanging.
52eae2e508Skrishnae  */
53eae2e508Skrishnae boolean_t px_panicing = B_FALSE;
54eae2e508Skrishnae 
55bf8fc234Set static int px_pcie_ptlp(dev_info_t *dip, ddi_fm_error_t *derr,
56bf8fc234Set     px_err_pcie_t *regs);
57bf8fc234Set 
58bf8fc234Set #if defined(DEBUG)
59eae2e508Skrishnae static void px_pcie_log(dev_info_t *dip, px_err_pcie_t *regs);
60bf8fc234Set #else	/* DEBUG */
61bf8fc234Set #define	px_pcie_log 0 &&
62bf8fc234Set #endif	/* DEBUG */
63bf8fc234Set 
64f8d2de6bSjchu /*
65f8d2de6bSjchu  * Initialize px FMA support
66f8d2de6bSjchu  */
677c478bd9Sstevel@tonic-gate int
px_fm_attach(px_t * px_p)687c478bd9Sstevel@tonic-gate px_fm_attach(px_t *px_p)
697c478bd9Sstevel@tonic-gate {
70eae2e508Skrishnae 	int		i;
71eae2e508Skrishnae 	dev_info_t	*dip = px_p->px_dip;
72eae2e508Skrishnae 	pcie_bus_t	*bus_p;
73eae2e508Skrishnae 
747c478bd9Sstevel@tonic-gate 	px_p->px_fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
751ff65112Segillett 	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
767c478bd9Sstevel@tonic-gate 
77f8d2de6bSjchu 	/*
78f8d2de6bSjchu 	 * check parents' capability
79f8d2de6bSjchu 	 */
80eae2e508Skrishnae 	ddi_fm_init(dip, &px_p->px_fm_cap, &px_p->px_fm_ibc);
817c478bd9Sstevel@tonic-gate 
82f8d2de6bSjchu 	/*
83f8d2de6bSjchu 	 * parents need to be ereport and error handling capable
84f8d2de6bSjchu 	 */
85f8d2de6bSjchu 	ASSERT(px_p->px_fm_cap &&
86f8d2de6bSjchu 	    (DDI_FM_ERRCB_CAPABLE | DDI_FM_EREPORT_CAPABLE));
87f8d2de6bSjchu 
8801689544Sjchu 	/*
8901689544Sjchu 	 * Initialize lock to synchronize fabric error handling
9001689544Sjchu 	 */
9101689544Sjchu 	mutex_init(&px_p->px_fm_mutex, NULL, MUTEX_DRIVER,
9201689544Sjchu 	    (void *)px_p->px_fm_ibc);
9301689544Sjchu 
94eae2e508Skrishnae 	px_p->px_pfd_idx = 0;
95eae2e508Skrishnae 	for (i = 0; i < 5; i++)
96eae2e508Skrishnae 		pcie_rc_init_pfd(dip, &px_p->px_pfd_arr[i]);
97eae2e508Skrishnae 	PCIE_DIP2PFD(dip) = px_p->px_pfd_arr;
98eae2e508Skrishnae 
99eae2e508Skrishnae 	bus_p = PCIE_DIP2BUS(dip);
100eae2e508Skrishnae 	bus_p->bus_rp_bdf = px_p->px_bdf;
101eae2e508Skrishnae 	bus_p->bus_rp_dip = dip;
102eae2e508Skrishnae 
1037c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate 
106f8d2de6bSjchu /*
107f8d2de6bSjchu  * Deregister FMA
108f8d2de6bSjchu  */
1097c478bd9Sstevel@tonic-gate void
px_fm_detach(px_t * px_p)1107c478bd9Sstevel@tonic-gate px_fm_detach(px_t *px_p)
1117c478bd9Sstevel@tonic-gate {
112eae2e508Skrishnae 	int i;
113eae2e508Skrishnae 
11401689544Sjchu 	mutex_destroy(&px_p->px_fm_mutex);
1157c478bd9Sstevel@tonic-gate 	ddi_fm_fini(px_p->px_dip);
116eae2e508Skrishnae 	for (i = 0; i < 5; i++)
117eae2e508Skrishnae 		pcie_rc_fini_pfd(&px_p->px_pfd_arr[i]);
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
120e6b21d58SErwin T Tsaur /*
121e6b21d58SErwin T Tsaur  * register error callback in parent
122e6b21d58SErwin T Tsaur  */
123e6b21d58SErwin T Tsaur void
px_fm_cb_enable(px_t * px_p)124e6b21d58SErwin T Tsaur px_fm_cb_enable(px_t *px_p)
125e6b21d58SErwin T Tsaur {
126e6b21d58SErwin T Tsaur 	ddi_fm_handler_register(px_p->px_dip, px_fm_callback, px_p);
127e6b21d58SErwin T Tsaur }
128e6b21d58SErwin T Tsaur 
129e6b21d58SErwin T Tsaur void
px_fm_cb_disable(px_t * px_p)130e6b21d58SErwin T Tsaur px_fm_cb_disable(px_t *px_p)
131e6b21d58SErwin T Tsaur {
132e6b21d58SErwin T Tsaur 	ddi_fm_handler_unregister(px_p->px_dip);
133e6b21d58SErwin T Tsaur }
134e6b21d58SErwin T Tsaur 
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate  * Function used to setup access functions depending on level of desired
1377c478bd9Sstevel@tonic-gate  * protection.
1387c478bd9Sstevel@tonic-gate  */
1397c478bd9Sstevel@tonic-gate void
px_fm_acc_setup(ddi_map_req_t * mp,dev_info_t * rdip,pci_regspec_t * rp)140eae2e508Skrishnae px_fm_acc_setup(ddi_map_req_t *mp, dev_info_t *rdip, pci_regspec_t *rp)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate 	uchar_t fflag;
143eae2e508Skrishnae 	ndi_err_t *errp;
1447c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
1457c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *ap;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	hp = mp->map_handlep;
1487c478bd9Sstevel@tonic-gate 	ap = (ddi_acc_impl_t *)hp->ah_platform_private;
1497c478bd9Sstevel@tonic-gate 	fflag = ap->ahi_common.ah_acc.devacc_attr_access;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	if (mp->map_op == DDI_MO_MAP_LOCKED) {
1527c478bd9Sstevel@tonic-gate 		ndi_fmc_insert(rdip, ACC_HANDLE, (void *)hp, NULL);
1537c478bd9Sstevel@tonic-gate 		switch (fflag) {
1547c478bd9Sstevel@tonic-gate 		case DDI_FLAGERR_ACC:
1557c478bd9Sstevel@tonic-gate 			ap->ahi_get8 = i_ddi_prot_get8;
1567c478bd9Sstevel@tonic-gate 			ap->ahi_get16 = i_ddi_prot_get16;
1577c478bd9Sstevel@tonic-gate 			ap->ahi_get32 = i_ddi_prot_get32;
1587c478bd9Sstevel@tonic-gate 			ap->ahi_get64 = i_ddi_prot_get64;
1597c478bd9Sstevel@tonic-gate 			ap->ahi_put8 = i_ddi_prot_put8;
1607c478bd9Sstevel@tonic-gate 			ap->ahi_put16 = i_ddi_prot_put16;
1617c478bd9Sstevel@tonic-gate 			ap->ahi_put32 = i_ddi_prot_put32;
1627c478bd9Sstevel@tonic-gate 			ap->ahi_put64 = i_ddi_prot_put64;
1637c478bd9Sstevel@tonic-gate 			ap->ahi_rep_get8 = i_ddi_prot_rep_get8;
1647c478bd9Sstevel@tonic-gate 			ap->ahi_rep_get16 = i_ddi_prot_rep_get16;
1657c478bd9Sstevel@tonic-gate 			ap->ahi_rep_get32 = i_ddi_prot_rep_get32;
1667c478bd9Sstevel@tonic-gate 			ap->ahi_rep_get64 = i_ddi_prot_rep_get64;
1677c478bd9Sstevel@tonic-gate 			ap->ahi_rep_put8 = i_ddi_prot_rep_put8;
1687c478bd9Sstevel@tonic-gate 			ap->ahi_rep_put16 = i_ddi_prot_rep_put16;
1697c478bd9Sstevel@tonic-gate 			ap->ahi_rep_put32 = i_ddi_prot_rep_put32;
1707c478bd9Sstevel@tonic-gate 			ap->ahi_rep_put64 = i_ddi_prot_rep_put64;
171eae2e508Skrishnae 			impl_acc_err_init(hp);
172eae2e508Skrishnae 			errp = ((ddi_acc_impl_t *)hp)->ahi_err;
173eae2e508Skrishnae 			if ((rp->pci_phys_hi & PCI_REG_ADDR_M) ==
174eae2e508Skrishnae 			    PCI_ADDR_CONFIG)
175eae2e508Skrishnae 				errp->err_cf = px_err_cfg_hdl_check;
176eae2e508Skrishnae 			else
177eae2e508Skrishnae 				errp->err_cf = px_err_pio_hdl_check;
1787c478bd9Sstevel@tonic-gate 			break;
1797c478bd9Sstevel@tonic-gate 		case DDI_CAUTIOUS_ACC :
1807c478bd9Sstevel@tonic-gate 			ap->ahi_get8 = i_ddi_caut_get8;
1817c478bd9Sstevel@tonic-gate 			ap->ahi_get16 = i_ddi_caut_get16;
1827c478bd9Sstevel@tonic-gate 			ap->ahi_get32 = i_ddi_caut_get32;
1837c478bd9Sstevel@tonic-gate 			ap->ahi_get64 = i_ddi_caut_get64;
1847c478bd9Sstevel@tonic-gate 			ap->ahi_put8 = i_ddi_caut_put8;
1857c478bd9Sstevel@tonic-gate 			ap->ahi_put16 = i_ddi_caut_put16;
1867c478bd9Sstevel@tonic-gate 			ap->ahi_put32 = i_ddi_caut_put32;
1877c478bd9Sstevel@tonic-gate 			ap->ahi_put64 = i_ddi_caut_put64;
1887c478bd9Sstevel@tonic-gate 			ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
1897c478bd9Sstevel@tonic-gate 			ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
1907c478bd9Sstevel@tonic-gate 			ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
1917c478bd9Sstevel@tonic-gate 			ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
1927c478bd9Sstevel@tonic-gate 			ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
1937c478bd9Sstevel@tonic-gate 			ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
1947c478bd9Sstevel@tonic-gate 			ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
1957c478bd9Sstevel@tonic-gate 			ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
196eae2e508Skrishnae 			impl_acc_err_init(hp);
197eae2e508Skrishnae 			errp = ((ddi_acc_impl_t *)hp)->ahi_err;
198eae2e508Skrishnae 			if ((rp->pci_phys_hi & PCI_REG_ADDR_M) ==
199eae2e508Skrishnae 			    PCI_ADDR_CONFIG)
200eae2e508Skrishnae 				errp->err_cf = px_err_cfg_hdl_check;
201eae2e508Skrishnae 			else
202eae2e508Skrishnae 				errp->err_cf = px_err_pio_hdl_check;
2037c478bd9Sstevel@tonic-gate 			break;
2047c478bd9Sstevel@tonic-gate 		default:
20549fbdd30SErwin T Tsaur 			/* Illegal state, remove the handle from cache */
20649fbdd30SErwin T Tsaur 			ndi_fmc_remove(rdip, ACC_HANDLE, (void *)hp);
2077c478bd9Sstevel@tonic-gate 			break;
2087c478bd9Sstevel@tonic-gate 		}
2097c478bd9Sstevel@tonic-gate 	} else if (mp->map_op == DDI_MO_UNMAP) {
2107c478bd9Sstevel@tonic-gate 		ndi_fmc_remove(rdip, ACC_HANDLE, (void *)hp);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate  * Function used to initialize FMA for our children nodes. Called
2167c478bd9Sstevel@tonic-gate  * through pci busops when child node calls ddi_fm_init.
2177c478bd9Sstevel@tonic-gate  */
2187c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2197c478bd9Sstevel@tonic-gate int
px_fm_init_child(dev_info_t * dip,dev_info_t * cdip,int cap,ddi_iblock_cookie_t * ibc_p)2207c478bd9Sstevel@tonic-gate px_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
2217c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *ibc_p)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	px_t *px_p = DIP_TO_STATE(dip);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	ASSERT(ibc_p != NULL);
2267c478bd9Sstevel@tonic-gate 	*ibc_p = px_p->px_fm_ibc;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	return (px_p->px_fm_cap);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate /*
232f8d2de6bSjchu  * lock access for exclusive PCIe access
2337c478bd9Sstevel@tonic-gate  */
234f8d2de6bSjchu void
px_bus_enter(dev_info_t * dip,ddi_acc_handle_t handle)235f8d2de6bSjchu px_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle)
2367c478bd9Sstevel@tonic-gate {
237f8d2de6bSjchu 	px_pec_t	*pec_p = ((px_t *)DIP_TO_STATE(dip))->px_pec_p;
238f8d2de6bSjchu 
239f8d2de6bSjchu 	/*
240f8d2de6bSjchu 	 * Exclusive access has been used for cautious put/get,
241f8d2de6bSjchu 	 * Both utilize i_ddi_ontrap which, on sparcv9, implements
242f8d2de6bSjchu 	 * similar protection as what on_trap() does, and which calls
243f8d2de6bSjchu 	 * membar  #Sync to flush out all cpu deferred errors
244f8d2de6bSjchu 	 * prior to get/put operation, so here we're not calling
245f8d2de6bSjchu 	 * membar  #Sync - a difference from what's in pci_bus_enter().
246f8d2de6bSjchu 	 */
247f8d2de6bSjchu 	mutex_enter(&pec_p->pec_pokefault_mutex);
248f8d2de6bSjchu 	pec_p->pec_acc_hdl = handle;
249f8d2de6bSjchu }
250f8d2de6bSjchu 
251f8d2de6bSjchu /*
252f8d2de6bSjchu  * unlock access for exclusive PCIe access
253f8d2de6bSjchu  */
254f8d2de6bSjchu /* ARGSUSED */
255f8d2de6bSjchu void
px_bus_exit(dev_info_t * dip,ddi_acc_handle_t handle)256f8d2de6bSjchu px_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle)
257f8d2de6bSjchu {
258f8d2de6bSjchu 	px_t		*px_p = DIP_TO_STATE(dip);
259f8d2de6bSjchu 	px_pec_t	*pec_p = px_p->px_pec_p;
260f8d2de6bSjchu 
261f8d2de6bSjchu 	pec_p->pec_acc_hdl = NULL;
262f8d2de6bSjchu 	mutex_exit(&pec_p->pec_pokefault_mutex);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
265eae2e508Skrishnae static uint64_t
px_in_addr_range(dev_info_t * dip,pci_ranges_t * ranges_p,uint64_t addr)26626947304SEvan Yan px_in_addr_range(dev_info_t *dip, pci_ranges_t *ranges_p, uint64_t addr)
267eae2e508Skrishnae {
268eae2e508Skrishnae 	uint64_t	addr_low, addr_high;
269eae2e508Skrishnae 
27049fbdd30SErwin T Tsaur 	addr_low = (uint64_t)(ranges_p->parent_high & px_ranges_phi_mask) << 32;
27149fbdd30SErwin T Tsaur 	addr_low |= (uint64_t)ranges_p->parent_low;
272eae2e508Skrishnae 	addr_high = addr_low + ((uint64_t)ranges_p->size_high << 32) +
273eae2e508Skrishnae 	    (uint64_t)ranges_p->size_low;
274eae2e508Skrishnae 
275eae2e508Skrishnae 	DBG(DBG_ERR_INTR, dip, "Addr: 0x%llx high: 0x%llx low: 0x%llx\n",
276eae2e508Skrishnae 	    addr, addr_high, addr_low);
277eae2e508Skrishnae 
278eae2e508Skrishnae 	if ((addr < addr_high) && (addr >= addr_low))
279eae2e508Skrishnae 		return (addr_low);
280eae2e508Skrishnae 
281eae2e508Skrishnae 	return (0);
282eae2e508Skrishnae }
283f8d2de6bSjchu 
2847c478bd9Sstevel@tonic-gate /*
285f8d2de6bSjchu  * PCI error callback which is registered with our parent to call
286f8d2de6bSjchu  * for PCIe logging when the CPU traps due to PCIe Uncorrectable Errors
287bf8fc234Set  * and PCI BERR/TO/UE on IO Loads.
2887c478bd9Sstevel@tonic-gate  */
2897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2907c478bd9Sstevel@tonic-gate int
px_fm_callback(dev_info_t * dip,ddi_fm_error_t * derr,const void * impl_data)291f8d2de6bSjchu px_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data)
292f8d2de6bSjchu {
293c2a75729Sdwoods 	dev_info_t	*pdip = ddi_get_parent(dip);
294bf8fc234Set 	px_t		*px_p = (px_t *)impl_data;
295bf8fc234Set 	int		i, acc_type = 0;
296eae2e508Skrishnae 	int		lookup, rc_err, fab_err;
297eae2e508Skrishnae 	uint64_t	addr, base_addr;
298eae2e508Skrishnae 	uint64_t	fault_addr = (uint64_t)derr->fme_bus_specific;
299c85864d8SKrishna Elango 	pcie_req_id_t	bdf = PCIE_INVALID_BDF;
30026947304SEvan Yan 	pci_ranges_t	*ranges_p;
301bf8fc234Set 	int		range_len;
302fc256490SJason Beloro 	pf_data_t	*pfd_p;
303e51949e6Sdduvall 
304c2a75729Sdwoods 	/*
305c2a75729Sdwoods 	 * If the current thread already owns the px_fm_mutex, then we
306c2a75729Sdwoods 	 * have encountered an error while processing a previous
307c2a75729Sdwoods 	 * error.  Attempting to take the mutex again will cause the
308c2a75729Sdwoods 	 * system to deadlock.
309c2a75729Sdwoods 	 */
310c2a75729Sdwoods 	if (px_p->px_fm_mutex_owner == curthread)
311c2a75729Sdwoods 		return (DDI_FM_FATAL);
312c2a75729Sdwoods 
313c2a75729Sdwoods 	i_ddi_fm_handler_exit(pdip);
314fc256490SJason Beloro 
315eae2e508Skrishnae 	if (px_fm_enter(px_p) != DDI_SUCCESS) {
316eae2e508Skrishnae 		i_ddi_fm_handler_enter(pdip);
317eae2e508Skrishnae 		return (DDI_FM_FATAL);
318eae2e508Skrishnae 	}
319e51949e6Sdduvall 
320bf8fc234Set 	/*
321c2a75729Sdwoods 	 * Make sure this failed load came from this PCIe port.	 Check by
322bf8fc234Set 	 * matching the upper 32 bits of the address with the ranges property.
323bf8fc234Set 	 */
32426947304SEvan Yan 	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
325bf8fc234Set 	i = 0;
326bf8fc234Set 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
327eae2e508Skrishnae 		base_addr = px_in_addr_range(dip, ranges_p, fault_addr);
328eae2e508Skrishnae 		if (base_addr) {
329bf8fc234Set 			switch (ranges_p->child_high & PCI_ADDR_MASK) {
330bf8fc234Set 			case PCI_ADDR_CONFIG:
331eae2e508Skrishnae 				acc_type = PF_ADDR_CFG;
332*e214b19eSToomas Soome 				addr = 0;
333eae2e508Skrishnae 				bdf = (pcie_req_id_t)((fault_addr >> 12) &
334eae2e508Skrishnae 				    0xFFFF);
335bf8fc234Set 				break;
3361ff65112Segillett 			case PCI_ADDR_IO:
337eae2e508Skrishnae 			case PCI_ADDR_MEM64:
338bf8fc234Set 			case PCI_ADDR_MEM32:
339eae2e508Skrishnae 				acc_type = PF_ADDR_PIO;
340eae2e508Skrishnae 				addr = fault_addr - base_addr;
341c85864d8SKrishna Elango 				bdf = PCIE_INVALID_BDF;
342bf8fc234Set 				break;
343bf8fc234Set 			}
344e51949e6Sdduvall 			break;
345e51949e6Sdduvall 		}
3463d9c56a1Set 	}
3478bc7d88aSet 
348bf8fc234Set 	/* This address doesn't belong to this leaf, just return with OK */
349bf8fc234Set 	if (!acc_type) {
350eae2e508Skrishnae 		px_fm_exit(px_p);
351c2a75729Sdwoods 		i_ddi_fm_handler_enter(pdip);
352bf8fc234Set 		return (DDI_FM_OK);
353bf8fc234Set 	}
354e51949e6Sdduvall 
355bf8fc234Set 	rc_err = px_err_cmn_intr(px_p, derr, PX_TRAP_CALL, PX_FM_BLOCK_ALL);
356eae2e508Skrishnae 	lookup = pf_hdl_lookup(dip, derr->fme_ena, acc_type, (uint64_t)addr,
357eae2e508Skrishnae 	    bdf);
358e51949e6Sdduvall 
359fc256490SJason Beloro 	pfd_p = px_rp_en_q(px_p, bdf, addr,
360eae2e508Skrishnae 	    (PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB));
361fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_DATA;
362fc256490SJason Beloro 
363fc256490SJason Beloro 	/* Update affected info, either addr or bdf is not NULL */
364fc256490SJason Beloro 	if (addr) {
365fc256490SJason Beloro 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_ADDR;
366fc256490SJason Beloro 	} else if (PCIE_CHECK_VALID_BDF(bdf)) {
367fc256490SJason Beloro 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_BDF;
368fc256490SJason Beloro 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = bdf;
369fc256490SJason Beloro 	}
370f41150baSkrishnae 
371eae2e508Skrishnae 	fab_err = px_scan_fabric(px_p, dip, derr);
372eae2e508Skrishnae 
373eae2e508Skrishnae 	px_fm_exit(px_p);
374c2a75729Sdwoods 	i_ddi_fm_handler_enter(pdip);
3758bc7d88aSet 
376eae2e508Skrishnae 	if (!px_die)
377eae2e508Skrishnae 		return (DDI_FM_OK);
378eae2e508Skrishnae 
379eae2e508Skrishnae 	if ((rc_err & (PX_PANIC | PX_PROTECTED)) ||
380eae2e508Skrishnae 	    (fab_err & PF_ERR_FATAL_FLAGS) ||
381bf8fc234Set 	    (lookup == PF_HDL_NOTFOUND))
3828bc7d88aSet 		return (DDI_FM_FATAL);
383eae2e508Skrishnae 	else if ((rc_err == PX_NO_ERROR) && (fab_err == PF_ERR_NO_ERROR))
384bf8fc234Set 		return (DDI_FM_OK);
3858bc7d88aSet 
386bf8fc234Set 	return (DDI_FM_NONFATAL);
3878bc7d88aSet }
3888bc7d88aSet 
3898bc7d88aSet /*
3908bc7d88aSet  * px_err_fabric_intr:
3918bc7d88aSet  * Interrupt handler for PCIE fabric block.
392f8d2de6bSjchu  * o lock
393f8d2de6bSjchu  * o create derr
394bf8fc234Set  * o px_err_cmn_intr(leaf, with jbc)
395f8d2de6bSjchu  * o send ereport(fire fmri, derr, payload = BDF)
396f8d2de6bSjchu  * o dispatch (leaf)
397f8d2de6bSjchu  * o unlock
398f8d2de6bSjchu  * o handle error: fatal? fm_panic() : return INTR_CLAIMED)
399f8d2de6bSjchu  */
400f8d2de6bSjchu /* ARGSUSED */
401f8d2de6bSjchu uint_t
px_err_fabric_intr(px_t * px_p,msgcode_t msg_code,pcie_req_id_t rid)402bf8fc234Set px_err_fabric_intr(px_t *px_p, msgcode_t msg_code, pcie_req_id_t rid)
4037c478bd9Sstevel@tonic-gate {
404f8d2de6bSjchu 	dev_info_t	*rpdip = px_p->px_dip;
405eae2e508Skrishnae 	int		rc_err, fab_err;
406f8d2de6bSjchu 	ddi_fm_error_t	derr;
407eae2e508Skrishnae 	uint32_t	rp_status;
408eae2e508Skrishnae 	uint16_t	ce_source, ue_source;
409fc256490SJason Beloro 	pf_data_t	*pfd_p;
410f8d2de6bSjchu 
411eae2e508Skrishnae 	if (px_fm_enter(px_p) != DDI_SUCCESS)
412eae2e508Skrishnae 		goto done;
413f8d2de6bSjchu 
414f8d2de6bSjchu 	/* Create the derr */
415f8d2de6bSjchu 	bzero(&derr, sizeof (ddi_fm_error_t));
416f8d2de6bSjchu 	derr.fme_version = DDI_FME_VERSION;
417f8d2de6bSjchu 	derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
418f8d2de6bSjchu 	derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
419f8d2de6bSjchu 
420eae2e508Skrishnae 	px_err_safeacc_check(px_p, &derr);
421eae2e508Skrishnae 
422eae2e508Skrishnae 	if (msg_code == PCIE_MSG_CODE_ERR_COR) {
423eae2e508Skrishnae 		rp_status = PCIE_AER_RE_STS_CE_RCVD;
424eae2e508Skrishnae 		ce_source = rid;
425eae2e508Skrishnae 		ue_source = 0;
426eae2e508Skrishnae 	} else {
427eae2e508Skrishnae 		rp_status = PCIE_AER_RE_STS_FE_NFE_RCVD;
428eae2e508Skrishnae 		ce_source = 0;
429eae2e508Skrishnae 		ue_source = rid;
430eae2e508Skrishnae 		if (msg_code == PCIE_MSG_CODE_ERR_NONFATAL)
431eae2e508Skrishnae 			rp_status |= PCIE_AER_RE_STS_NFE_MSGS_RCVD;
432eae2e508Skrishnae 		else {
433eae2e508Skrishnae 			rp_status |= PCIE_AER_RE_STS_FE_MSGS_RCVD;
434eae2e508Skrishnae 			rp_status |= PCIE_AER_RE_STS_FIRST_UC_FATAL;
435eae2e508Skrishnae 		}
436eae2e508Skrishnae 	}
437eae2e508Skrishnae 
438eae2e508Skrishnae 	if (derr.fme_flag == DDI_FM_ERR_UNEXPECTED) {
439eae2e508Skrishnae 		ddi_fm_ereport_post(rpdip, PCI_ERROR_SUBCLASS "." PCIEX_FABRIC,
440eae2e508Skrishnae 		    derr.fme_ena,
441eae2e508Skrishnae 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
442eae2e508Skrishnae 		    FIRE_PRIMARY, DATA_TYPE_BOOLEAN_VALUE, B_TRUE,
443eae2e508Skrishnae 		    "pcie_adv_rp_status", DATA_TYPE_UINT32, rp_status,
444eae2e508Skrishnae 		    "pcie_adv_rp_command", DATA_TYPE_UINT32, 0,
445eae2e508Skrishnae 		    "pcie_adv_rp_ce_src_id", DATA_TYPE_UINT16, ce_source,
446eae2e508Skrishnae 		    "pcie_adv_rp_ue_src_id", DATA_TYPE_UINT16, ue_source,
447eae2e508Skrishnae 		    NULL);
448eae2e508Skrishnae 	}
449eae2e508Skrishnae 
450bf8fc234Set 	/* Ensure that the rid of the fabric message will get scanned. */
451*e214b19eSToomas Soome 	pfd_p = px_rp_en_q(px_p, rid, 0, 0);
452fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_FABRIC;
453f8d2de6bSjchu 
454bf8fc234Set 	rc_err = px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_PCIE);
4558bc7d88aSet 
456bf8fc234Set 	/* call rootport dispatch */
457eae2e508Skrishnae 	fab_err = px_scan_fabric(px_p, rpdip, &derr);
458f41150baSkrishnae 
459eae2e508Skrishnae 	px_err_panic(rc_err, PX_RC, fab_err, B_TRUE);
460eae2e508Skrishnae 	px_fm_exit(px_p);
461eae2e508Skrishnae 	px_err_panic(rc_err, PX_RC, fab_err, B_FALSE);
462f41150baSkrishnae 
463eae2e508Skrishnae done:
464c333dd99Sdm 	return (DDI_INTR_CLAIMED);
465f41150baSkrishnae }
466f41150baSkrishnae 
467eae2e508Skrishnae /*
468eae2e508Skrishnae  * px_scan_fabric:
469eae2e508Skrishnae  *
470eae2e508Skrishnae  * Check for drain state and if there is anything to scan.
471fc256490SJason Beloro  *
472fc256490SJason Beloro  * Note on pfd: Different interrupts will populate the pfd's differently.  The
473fc256490SJason Beloro  * px driver can have a total of 5 different error sources, so it has a queue of
474fc256490SJason Beloro  * 5 pfds.  Each valid PDF is linked together and passed to pf_scan_fabric.
475fc256490SJason Beloro  *
476fc256490SJason Beloro  * Each error handling will populate the following info in the pfd
477fc256490SJason Beloro  *
478fc256490SJason Beloro  *			Root Fault	 Intr Src	 Affected BDF
479fc256490SJason Beloro  *			----------------+---------------+------------
480fc256490SJason Beloro  * Callback/CPU Trap	Address/BDF	|DATA		|Lookup Addr
481fc256490SJason Beloro  * Mondo 62/63 (sun4u)	decode error	|N/A		|N/A
482fc256490SJason Beloro  * EPKT (sun4v)		decode epkt	|INTERNAL	|decode epkt
483fc256490SJason Beloro  * Fabric Message	fabric payload	|FABRIC		|NULL
484fc256490SJason Beloro  * Peek/Poke		Address/BDF	|NULL		|NULL
485fc256490SJason Beloro  *			----------------+---------------+------------
486eae2e508Skrishnae  */
487eae2e508Skrishnae int
px_scan_fabric(px_t * px_p,dev_info_t * rpdip,ddi_fm_error_t * derr)488eae2e508Skrishnae px_scan_fabric(px_t *px_p, dev_info_t *rpdip, ddi_fm_error_t *derr) {
489eae2e508Skrishnae 	int fab_err = 0;
490eae2e508Skrishnae 
491eae2e508Skrishnae 	ASSERT(MUTEX_HELD(&px_p->px_fm_mutex));
492eae2e508Skrishnae 
493eae2e508Skrishnae 	if (!px_lib_is_in_drain_state(px_p) && px_p->px_pfd_idx) {
494eae2e508Skrishnae 		fab_err = pf_scan_fabric(rpdip, derr, px_p->px_pfd_arr);
495eae2e508Skrishnae 	}
496eae2e508Skrishnae 
497eae2e508Skrishnae 	return (fab_err);
498eae2e508Skrishnae }
499eae2e508Skrishnae 
500f8d2de6bSjchu /*
501f8d2de6bSjchu  * px_err_safeacc_check:
502f8d2de6bSjchu  * Check to see if a peek/poke and cautious access is currently being
503f8d2de6bSjchu  * done on a particular leaf.
504f8d2de6bSjchu  *
505f8d2de6bSjchu  * Safe access reads induced fire errors will be handled by cpu trap handler
506f8d2de6bSjchu  * which will call px_fm_callback() which calls this function. In that
507f8d2de6bSjchu  * case, the derr fields will be set by trap handler with the correct values.
508f8d2de6bSjchu  *
509f8d2de6bSjchu  * Safe access writes induced errors will be handled by px interrupt
510f8d2de6bSjchu  * handlers, this function will fill in the derr fields.
511f8d2de6bSjchu  *
512f8d2de6bSjchu  * If a cpu trap does occur, it will quiesce all other interrupts allowing
513f8d2de6bSjchu  * the cpu trap error handling to finish before Fire receives an interrupt.
514f8d2de6bSjchu  *
515f8d2de6bSjchu  * If fire does indeed have an error when a cpu trap occurs as a result of
516f8d2de6bSjchu  * a safe access, a trap followed by a Mondo/Fabric interrupt will occur.
517f8d2de6bSjchu  * In which case derr will be initialized as "UNEXPECTED" by the interrupt
518f8d2de6bSjchu  * handler and this function will need to find if this error occured in the
519f8d2de6bSjchu  * middle of a safe access operation.
520f8d2de6bSjchu  *
521f8d2de6bSjchu  * @param px_p		leaf in which to check access
522f8d2de6bSjchu  * @param derr		fm err data structure to be updated
523f8d2de6bSjchu  */
524f8d2de6bSjchu void
px_err_safeacc_check(px_t * px_p,ddi_fm_error_t * derr)525f8d2de6bSjchu px_err_safeacc_check(px_t *px_p, ddi_fm_error_t *derr)
526f8d2de6bSjchu {
527f8d2de6bSjchu 	px_pec_t 	*pec_p = px_p->px_pec_p;
528f8d2de6bSjchu 	int		acctype = pec_p->pec_safeacc_type;
529f8d2de6bSjchu 
53001689544Sjchu 	ASSERT(MUTEX_HELD(&px_p->px_fm_mutex));
531f8d2de6bSjchu 
532f8d2de6bSjchu 	if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) {
533f8d2de6bSjchu 		return;
534f8d2de6bSjchu 	}
535f8d2de6bSjchu 
536f8d2de6bSjchu 	/* safe access checking */
537f8d2de6bSjchu 	switch (acctype) {
538f8d2de6bSjchu 	case DDI_FM_ERR_EXPECTED:
539f8d2de6bSjchu 		/*
540f8d2de6bSjchu 		 * cautious access protection, protected from all err.
541f8d2de6bSjchu 		 */
542f8d2de6bSjchu 		ddi_fm_acc_err_get(pec_p->pec_acc_hdl, derr,
543f8d2de6bSjchu 		    DDI_FME_VERSION);
544f8d2de6bSjchu 		derr->fme_flag = acctype;
545f8d2de6bSjchu 		derr->fme_acc_handle = pec_p->pec_acc_hdl;
546f8d2de6bSjchu 		break;
547f8d2de6bSjchu 	case DDI_FM_ERR_POKE:
548f8d2de6bSjchu 		/*
549f8d2de6bSjchu 		 * ddi_poke protection, check nexus and children for
550f8d2de6bSjchu 		 * expected errors.
551f8d2de6bSjchu 		 */
552f8d2de6bSjchu 		membar_sync();
553f8d2de6bSjchu 		derr->fme_flag = acctype;
554f8d2de6bSjchu 		break;
555f8d2de6bSjchu 	case DDI_FM_ERR_PEEK:
556f8d2de6bSjchu 		derr->fme_flag = acctype;
557f8d2de6bSjchu 		break;
558f8d2de6bSjchu 	}
5597c478bd9Sstevel@tonic-gate }
560bf8fc234Set 
561bf8fc234Set /*
562bf8fc234Set  * Suggest panic if any EQ (except CE q) has overflown.
563bf8fc234Set  */
564bf8fc234Set int
px_err_check_eq(dev_info_t * dip)565bf8fc234Set px_err_check_eq(dev_info_t *dip)
566bf8fc234Set {
567bf8fc234Set 	px_t			*px_p = DIP_TO_STATE(dip);
568bf8fc234Set 	px_msiq_state_t 	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
569bf8fc234Set 	px_pec_t		*pec_p = px_p->px_pec_p;
570bf8fc234Set 	msiqid_t		eq_no = msiq_state_p->msiq_1st_msiq_id;
571bf8fc234Set 	pci_msiq_state_t	msiq_state;
572bf8fc234Set 	int			i;
573bf8fc234Set 
574bf8fc234Set 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
575bf8fc234Set 		if (i + eq_no == pec_p->pec_corr_msg_msiq_id) /* skip CE q */
576bf8fc234Set 			continue;
577bf8fc234Set 		if ((px_lib_msiq_getstate(dip, i + eq_no, &msiq_state) !=
5781ff65112Segillett 		    DDI_SUCCESS) || msiq_state == PCI_MSIQ_STATE_ERROR)
579bf8fc234Set 			return (PX_PANIC);
580bf8fc234Set 	}
581bf8fc234Set 	return (PX_NO_PANIC);
582bf8fc234Set }
583bf8fc234Set 
584eae2e508Skrishnae /* ARGSUSED */
585eae2e508Skrishnae int
px_err_check_pcie(dev_info_t * dip,ddi_fm_error_t * derr,px_err_pcie_t * regs,pf_intr_type_t intr_type)5865613d828SKrishna Elango px_err_check_pcie(dev_info_t *dip, ddi_fm_error_t *derr, px_err_pcie_t *regs,
5875613d828SKrishna Elango     pf_intr_type_t intr_type)
588bf8fc234Set {
589eae2e508Skrishnae 	px_t		*px_p = DIP_TO_STATE(dip);
590eae2e508Skrishnae 	pf_data_t	*pfd_p = px_get_pfd(px_p);
591eae2e508Skrishnae 	int		i;
592eae2e508Skrishnae 	pf_pcie_adv_err_regs_t *adv_reg = PCIE_ADV_REG(pfd_p);
5937ea9b230Set 
5945613d828SKrishna Elango 	PCIE_ROOT_EH_SRC(pfd_p)->intr_type = intr_type;
5955613d828SKrishna Elango 
596bf8fc234Set 	/*
597bf8fc234Set 	 * set RC s_status in PCI term to coordinate with downstream fabric
598bf8fc234Set 	 * errors ananlysis.
599bf8fc234Set 	 */
600bf8fc234Set 	if (regs->primary_ue & PCIE_AER_UCE_UR)
601eae2e508Skrishnae 		PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = PCI_STAT_R_MAST_AB;
602bf8fc234Set 	if (regs->primary_ue & PCIE_AER_UCE_CA)
603eae2e508Skrishnae 		PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = PCI_STAT_R_TARG_AB;
604bf8fc234Set 	if (regs->primary_ue & (PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC))
605eae2e508Skrishnae 		PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = PCI_STAT_PERROR;
606bf8fc234Set 
607eae2e508Skrishnae 	if (!regs->primary_ue)
608c333dd99Sdm 		goto done;
609c333dd99Sdm 
610eae2e508Skrishnae 	adv_reg->pcie_ce_status = regs->ce_reg;
611eae2e508Skrishnae 	adv_reg->pcie_ue_status = regs->ue_reg | regs->primary_ue;
612eae2e508Skrishnae 	PCIE_ADV_HDR(pfd_p, 0) = regs->rx_hdr1;
613eae2e508Skrishnae 	PCIE_ADV_HDR(pfd_p, 1) = regs->rx_hdr2;
614eae2e508Skrishnae 	PCIE_ADV_HDR(pfd_p, 2) = regs->rx_hdr3;
615eae2e508Skrishnae 	PCIE_ADV_HDR(pfd_p, 3) = regs->rx_hdr4;
616eae2e508Skrishnae 	for (i = regs->primary_ue; i != 1; i = i >> 1)
617eae2e508Skrishnae 		adv_reg->pcie_adv_ctl++;
618bf8fc234Set 
619eae2e508Skrishnae 	if (regs->primary_ue & (PCIE_AER_UCE_UR | PCIE_AER_UCE_CA)) {
620eae2e508Skrishnae 		if (pf_tlp_decode(PCIE_DIP2BUS(dip), adv_reg) == DDI_SUCCESS)
621c85864d8SKrishna Elango 			PCIE_ROOT_FAULT(pfd_p)->scan_bdf =
622eae2e508Skrishnae 			    adv_reg->pcie_ue_tgt_bdf;
623eae2e508Skrishnae 	} else if (regs->primary_ue & PCIE_AER_UCE_PTLP) {
624eae2e508Skrishnae 		if (pf_tlp_decode(PCIE_DIP2BUS(dip), adv_reg) == DDI_SUCCESS) {
625c85864d8SKrishna Elango 			PCIE_ROOT_FAULT(pfd_p)->scan_bdf =
626eae2e508Skrishnae 			    adv_reg->pcie_ue_tgt_bdf;
627eae2e508Skrishnae 			if (adv_reg->pcie_ue_tgt_trans ==
628eae2e508Skrishnae 			    PF_ADDR_PIO)
629c85864d8SKrishna Elango 				PCIE_ROOT_FAULT(pfd_p)->scan_addr =
630eae2e508Skrishnae 				    adv_reg->pcie_ue_tgt_addr;
631eae2e508Skrishnae 		}
632c333dd99Sdm 
633eae2e508Skrishnae 		/*
634eae2e508Skrishnae 		 * Normally for Poisoned Completion TLPs we can look at the
635eae2e508Skrishnae 		 * transmit log header for the original request and the original
636eae2e508Skrishnae 		 * address, however this doesn't seem to be working.  HW BUG.
637eae2e508Skrishnae 		 */
638eae2e508Skrishnae 	}
639c333dd99Sdm 
640c333dd99Sdm done:
641eae2e508Skrishnae 	px_pcie_log(dip, regs);
642eae2e508Skrishnae 
643eae2e508Skrishnae 	/* Return No Error here and let the pcie misc module analyse it */
644eae2e508Skrishnae 	return (PX_NO_ERROR);
645bf8fc234Set }
646bf8fc234Set 
647bf8fc234Set #if defined(DEBUG)
648bf8fc234Set static void
px_pcie_log(dev_info_t * dip,px_err_pcie_t * regs)649eae2e508Skrishnae px_pcie_log(dev_info_t *dip, px_err_pcie_t *regs)
650bf8fc234Set {
651bf8fc234Set 	DBG(DBG_ERR_INTR, dip,
652eae2e508Skrishnae 	    "A PCIe RC error has occured\n"
653bf8fc234Set 	    "\tCE: 0x%x UE: 0x%x Primary UE: 0x%x\n"
654bf8fc234Set 	    "\tTX Hdr: 0x%x 0x%x 0x%x 0x%x\n\tRX Hdr: 0x%x 0x%x 0x%x 0x%x\n",
655eae2e508Skrishnae 	    regs->ce_reg, regs->ue_reg, regs->primary_ue,
656eae2e508Skrishnae 	    regs->tx_hdr1, regs->tx_hdr2, regs->tx_hdr3, regs->tx_hdr4,
657eae2e508Skrishnae 	    regs->rx_hdr1, regs->rx_hdr2, regs->rx_hdr3, regs->rx_hdr4);
658bf8fc234Set }
659eae2e508Skrishnae #endif
660bf8fc234Set 
661bf8fc234Set /*
662bf8fc234Set  * look through poisoned TLP cases and suggest panic/no panic depend on
663bf8fc234Set  * handle lookup.
664bf8fc234Set  */
665bf8fc234Set static int
px_pcie_ptlp(dev_info_t * dip,ddi_fm_error_t * derr,px_err_pcie_t * regs)666bf8fc234Set px_pcie_ptlp(dev_info_t *dip, ddi_fm_error_t *derr, px_err_pcie_t *regs)
667bf8fc234Set {
668eae2e508Skrishnae 	pf_pcie_adv_err_regs_t adv_reg;
669bf8fc234Set 	pcie_req_id_t	bdf;
670eae2e508Skrishnae 	uint64_t	addr;
671eae2e508Skrishnae 	uint32_t	trans_type;
672bf8fc234Set 	int		tlp_sts, tlp_cmd;
673eae2e508Skrishnae 	int		lookup = PF_HDL_NOTFOUND;
674bf8fc234Set 
675bf8fc234Set 	if (regs->primary_ue != PCIE_AER_UCE_PTLP)
676bf8fc234Set 		return (PX_PANIC);
677bf8fc234Set 
678bf8fc234Set 	if (!regs->rx_hdr1)
679bf8fc234Set 		goto done;
680bf8fc234Set 
681eae2e508Skrishnae 	adv_reg.pcie_ue_hdr[0] = regs->rx_hdr1;
682eae2e508Skrishnae 	adv_reg.pcie_ue_hdr[1] = regs->rx_hdr2;
683eae2e508Skrishnae 	adv_reg.pcie_ue_hdr[2] = regs->rx_hdr3;
684eae2e508Skrishnae 	adv_reg.pcie_ue_hdr[3] = regs->rx_hdr4;
685bf8fc234Set 
686eae2e508Skrishnae 	tlp_sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
687eae2e508Skrishnae 	tlp_cmd = ((pcie_tlp_hdr_t *)(adv_reg.pcie_ue_hdr))->type;
688bf8fc234Set 
689bf8fc234Set 	if (tlp_sts == DDI_FAILURE)
690bf8fc234Set 		goto done;
691bf8fc234Set 
692eae2e508Skrishnae 	bdf = adv_reg.pcie_ue_tgt_bdf;
693eae2e508Skrishnae 	addr = adv_reg.pcie_ue_tgt_addr;
694eae2e508Skrishnae 	trans_type = adv_reg.pcie_ue_tgt_trans;
695eae2e508Skrishnae 
696bf8fc234Set 	switch (tlp_cmd) {
697bf8fc234Set 	case PCIE_TLP_TYPE_CPL:
698bf8fc234Set 	case PCIE_TLP_TYPE_CPLLK:
699bf8fc234Set 		/*
700bf8fc234Set 		 * Usually a PTLP is a CPL with data.  Grab the completer BDF
701bf8fc234Set 		 * from the RX TLP, and the original address from the TX TLP.
702bf8fc234Set 		 */
703bf8fc234Set 		if (regs->tx_hdr1) {
704eae2e508Skrishnae 			adv_reg.pcie_ue_hdr[0] = regs->tx_hdr1;
705eae2e508Skrishnae 			adv_reg.pcie_ue_hdr[1] = regs->tx_hdr2;
706eae2e508Skrishnae 			adv_reg.pcie_ue_hdr[2] = regs->tx_hdr3;
707eae2e508Skrishnae 			adv_reg.pcie_ue_hdr[3] = regs->tx_hdr4;
708bf8fc234Set 
709eae2e508Skrishnae 			lookup = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
710eae2e508Skrishnae 			if (lookup != DDI_SUCCESS)
711eae2e508Skrishnae 				break;
712eae2e508Skrishnae 			addr = adv_reg.pcie_ue_tgt_addr;
713eae2e508Skrishnae 			trans_type = adv_reg.pcie_ue_tgt_trans;
714bf8fc234Set 		} /* FALLTHRU */
715bf8fc234Set 	case PCIE_TLP_TYPE_IO:
716bf8fc234Set 	case PCIE_TLP_TYPE_MEM:
717bf8fc234Set 	case PCIE_TLP_TYPE_MEMLK:
718eae2e508Skrishnae 		lookup = pf_hdl_lookup(dip, derr->fme_ena, trans_type, addr,
719eae2e508Skrishnae 		    bdf);
720bf8fc234Set 		break;
721bf8fc234Set 	default:
722eae2e508Skrishnae 		lookup = PF_HDL_NOTFOUND;
723bf8fc234Set 	}
724bf8fc234Set done:
725eae2e508Skrishnae 	return (lookup == PF_HDL_FOUND ? PX_NO_PANIC : PX_PANIC);
726eae2e508Skrishnae }
727eae2e508Skrishnae 
728eae2e508Skrishnae /*
729eae2e508Skrishnae  * px_get_pdf automatically allocates a RC pf_data_t and returns a pointer to
730eae2e508Skrishnae  * it.  This function should be used when an error requires a fabric scan.
731eae2e508Skrishnae  */
732fc256490SJason Beloro pf_data_t *
px_get_pfd(px_t * px_p)733eae2e508Skrishnae px_get_pfd(px_t *px_p) {
734eae2e508Skrishnae 	int		idx = px_p->px_pfd_idx++;
735eae2e508Skrishnae 	pf_data_t	*pfd_p = &px_p->px_pfd_arr[idx];
736eae2e508Skrishnae 
737eae2e508Skrishnae 	/* Clear Old Data */
738c85864d8SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
739c85864d8SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p)->scan_addr = 0;
740fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_NONE;
741fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p)->intr_data = NULL;
742*e214b19eSToomas Soome 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = 0;
743fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
744eae2e508Skrishnae 	PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = 0;
745eae2e508Skrishnae 	PCIE_ADV_REG(pfd_p)->pcie_ce_status = 0;
746eae2e508Skrishnae 	PCIE_ADV_REG(pfd_p)->pcie_ue_status = 0;
7475613d828SKrishna Elango 	PCIE_ADV_REG(pfd_p)->pcie_adv_ctl = 0;
748eae2e508Skrishnae 
749eae2e508Skrishnae 	pfd_p->pe_next = NULL;
750eae2e508Skrishnae 
751eae2e508Skrishnae 	if (idx > 0) {
752eae2e508Skrishnae 		px_p->px_pfd_arr[idx - 1].pe_next = pfd_p;
753eae2e508Skrishnae 		pfd_p->pe_prev = &px_p->px_pfd_arr[idx - 1];
754eae2e508Skrishnae 	} else {
755eae2e508Skrishnae 		pfd_p->pe_prev = NULL;
756eae2e508Skrishnae 	}
757eae2e508Skrishnae 
758fc256490SJason Beloro 	pfd_p->pe_severity_flags = 0;
75979bed773SHans Rosenfeld 	pfd_p->pe_severity_mask = 0;
760fc256490SJason Beloro 	pfd_p->pe_orig_severity_flags = 0;
761eae2e508Skrishnae 	pfd_p->pe_valid = B_TRUE;
762eae2e508Skrishnae 
763eae2e508Skrishnae 	return (pfd_p);
764bf8fc234Set }
765bf8fc234Set 
766bf8fc234Set /*
767bf8fc234Set  * This function appends a pf_data structure to the error q which is used later
768bf8fc234Set  * during PCIe fabric scan.  It signifies:
769bf8fc234Set  * o errs rcvd in RC, that may have been propagated to/from the fabric
770bf8fc234Set  * o the fabric scan code should scan the device path of fault bdf/addr
771bf8fc234Set  *
772c85864d8SKrishna Elango  * scan_bdf: The bdf that caused the fault, which may have error bits set.
773c85864d8SKrishna Elango  * scan_addr: The PIO addr that caused the fault, such as failed PIO, but not
774bf8fc234Set  *	       failed DMAs.
775bf8fc234Set  * s_status: Secondary Status equivalent to why the fault occured.
776bf8fc234Set  *	     (ie S-TA/MA, R-TA)
777c85864d8SKrishna Elango  * Either the scan bdf or addr may be NULL, but not both.
778bf8fc234Set  */
779fc256490SJason Beloro pf_data_t *
px_rp_en_q(px_t * px_p,pcie_req_id_t scan_bdf,uint32_t scan_addr,uint16_t s_status)780c85864d8SKrishna Elango px_rp_en_q(px_t *px_p, pcie_req_id_t scan_bdf, uint32_t scan_addr,
781bf8fc234Set     uint16_t s_status)
782bf8fc234Set {
783eae2e508Skrishnae 	pf_data_t	*pfd_p;
784bf8fc234Set 
785c85864d8SKrishna Elango 	if (!PCIE_CHECK_VALID_BDF(scan_bdf) && !scan_addr)
786fc256490SJason Beloro 		return (NULL);
787bf8fc234Set 
788eae2e508Skrishnae 	pfd_p = px_get_pfd(px_p);
789eae2e508Skrishnae 
790c85864d8SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = scan_bdf;
791c85864d8SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p)->scan_addr = (uint64_t)scan_addr;
792eae2e508Skrishnae 	PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
793fc256490SJason Beloro 
794fc256490SJason Beloro 	return (pfd_p);
795eae2e508Skrishnae }
796eae2e508Skrishnae 
797eae2e508Skrishnae 
798eae2e508Skrishnae /*
799eae2e508Skrishnae  * Find and Mark CFG Handles as failed associated with the given BDF. We should
800eae2e508Skrishnae  * always know the BDF for CFG accesses, since it is encoded in the address of
801eae2e508Skrishnae  * the TLP.  Since there can be multiple cfg handles, mark them all as failed.
802eae2e508Skrishnae  */
803eae2e508Skrishnae /* ARGSUSED */
804eae2e508Skrishnae int
px_err_cfg_hdl_check(dev_info_t * dip,const void * handle,const void * arg1,const void * arg2)805eae2e508Skrishnae px_err_cfg_hdl_check(dev_info_t *dip, const void *handle, const void *arg1,
806eae2e508Skrishnae     const void *arg2)
807eae2e508Skrishnae {
808eae2e508Skrishnae 	int			status = DDI_FM_FATAL;
809eae2e508Skrishnae 	uint32_t		addr = *(uint32_t *)arg1;
810eae2e508Skrishnae 	uint16_t		bdf = *(uint16_t *)arg2;
811eae2e508Skrishnae 	pcie_bus_t		*bus_p;
812eae2e508Skrishnae 
813eae2e508Skrishnae 	DBG(DBG_ERR_INTR, dip, "Check CFG Hdl: dip 0x%p addr 0x%x bdf=0x%x\n",
814eae2e508Skrishnae 	    dip, addr, bdf);
815bf8fc234Set 
816eae2e508Skrishnae 	bus_p = PCIE_DIP2BUS(dip);
817bf8fc234Set 
818eae2e508Skrishnae 	/*
819eae2e508Skrishnae 	 * Because CFG and IO Acc Handlers are on the same cache list and both
820eae2e508Skrishnae 	 * types of hdls gets called for both types of errors.  For this checker
821eae2e508Skrishnae 	 * only mark the device as "Non-Fatal" if the addr == NULL and bdf !=
822eae2e508Skrishnae 	 * NULL.
823eae2e508Skrishnae 	 */
824c85864d8SKrishna Elango 	status = (!addr && (PCIE_CHECK_VALID_BDF(bdf) &&
825c85864d8SKrishna Elango 	    (bus_p->bus_bdf == bdf))) ? DDI_FM_NONFATAL : DDI_FM_FATAL;
826eae2e508Skrishnae 
827eae2e508Skrishnae 	return (status);
828eae2e508Skrishnae }
829eae2e508Skrishnae 
830eae2e508Skrishnae /*
831eae2e508Skrishnae  * Find and Mark all ACC Handles associated with a give address and BDF as
832eae2e508Skrishnae  * failed.  If the BDF != NULL, then check to see if the device has a ACC Handle
833eae2e508Skrishnae  * associated with ADDR.  If the handle is not found, mark all the handles as
834eae2e508Skrishnae  * failed.  If the BDF == NULL, mark the handle as failed if it is associated
835eae2e508Skrishnae  * with ADDR.
836eae2e508Skrishnae  */
837eae2e508Skrishnae int
px_err_pio_hdl_check(dev_info_t * dip,const void * handle,const void * arg1,const void * arg2)838eae2e508Skrishnae px_err_pio_hdl_check(dev_info_t *dip, const void *handle, const void *arg1,
839eae2e508Skrishnae     const void *arg2)
840eae2e508Skrishnae {
8419f539a12SErwin T Tsaur 	dev_info_t		*px_dip;
8429f539a12SErwin T Tsaur 	px_t			*px_p;
84326947304SEvan Yan 	pci_ranges_t		*ranges_p;
844eae2e508Skrishnae 	int			range_len;
845eae2e508Skrishnae 	ddi_acc_handle_t	ap = (ddi_acc_handle_t)handle;
846eae2e508Skrishnae 	ddi_acc_hdl_t		*hp = impl_acc_hdl_get(ap);
847eae2e508Skrishnae 	int			i, status = DDI_FM_FATAL;
848eae2e508Skrishnae 	uint64_t		fault_addr = *(uint64_t *)arg1;
849eae2e508Skrishnae 	uint16_t		bdf = *(uint16_t *)arg2;
850eae2e508Skrishnae 	uint64_t		base_addr, range_addr;
851eae2e508Skrishnae 	uint_t			size;
852eae2e508Skrishnae 
8539f539a12SErwin T Tsaur 	/*
8549f539a12SErwin T Tsaur 	 * Find the correct px dip.  On system with a real Root Port, it's the
8559f539a12SErwin T Tsaur 	 * node above the root port.  On systems without a real Root Port the px
8569f539a12SErwin T Tsaur 	 * dip is the bus_rp_dip.
8579f539a12SErwin T Tsaur 	 */
8589f539a12SErwin T Tsaur 	px_dip = PCIE_DIP2BUS(dip)->bus_rp_dip;
8599f539a12SErwin T Tsaur 
8609f539a12SErwin T Tsaur 	if (!PCIE_IS_RC(PCIE_DIP2BUS(px_dip)))
8619f539a12SErwin T Tsaur 		px_dip = ddi_get_parent(px_dip);
8629f539a12SErwin T Tsaur 
8639f539a12SErwin T Tsaur 	ASSERT(PCIE_IS_RC(PCIE_DIP2BUS(px_dip)));
8649f539a12SErwin T Tsaur 	px_p = INST_TO_STATE(ddi_get_instance(px_dip));
8659f539a12SErwin T Tsaur 
866eae2e508Skrishnae 	DBG(DBG_ERR_INTR, dip, "Check PIO Hdl: dip 0x%x addr 0x%x bdf=0x%x\n",
867eae2e508Skrishnae 	    dip, fault_addr, bdf);
868eae2e508Skrishnae 
869eae2e508Skrishnae 	/* Normalize the base addr to the addr and strip off the HB info. */
870eae2e508Skrishnae 	base_addr = (hp->ah_pfn << MMU_PAGESHIFT) + hp->ah_offset;
87126947304SEvan Yan 	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
872eae2e508Skrishnae 	i = 0;
873eae2e508Skrishnae 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
874eae2e508Skrishnae 		range_addr = px_in_addr_range(dip, ranges_p, base_addr);
875eae2e508Skrishnae 		if (range_addr) {
876eae2e508Skrishnae 			switch (ranges_p->child_high & PCI_ADDR_MASK) {
877eae2e508Skrishnae 			case PCI_ADDR_IO:
878eae2e508Skrishnae 			case PCI_ADDR_MEM64:
879eae2e508Skrishnae 			case PCI_ADDR_MEM32:
880eae2e508Skrishnae 				base_addr = base_addr - range_addr;
881eae2e508Skrishnae 				break;
882eae2e508Skrishnae 			}
883eae2e508Skrishnae 			break;
884eae2e508Skrishnae 		}
885eae2e508Skrishnae 	}
886eae2e508Skrishnae 
887eae2e508Skrishnae 	/*
888eae2e508Skrishnae 	 * Mark the handle as failed if the ADDR is mapped, or if we
889eae2e508Skrishnae 	 * know the BDF and ADDR == 0.
890eae2e508Skrishnae 	 */
891eae2e508Skrishnae 	size = hp->ah_len;
892eae2e508Skrishnae 	if (((fault_addr >= base_addr) && (fault_addr < (base_addr + size))) ||
893*e214b19eSToomas Soome 	    ((fault_addr == 0) && (PCIE_CHECK_VALID_BDF(bdf) &&
894c85864d8SKrishna Elango 	    (bdf == PCIE_DIP2BUS(dip)->bus_bdf))))
895eae2e508Skrishnae 		status = DDI_FM_NONFATAL;
896eae2e508Skrishnae 
897eae2e508Skrishnae 	return (status);
898eae2e508Skrishnae }
899eae2e508Skrishnae 
900eae2e508Skrishnae /*
901eae2e508Skrishnae  * Find and Mark all DNA Handles associated with a give address and BDF as
902eae2e508Skrishnae  * failed.  If the BDF != NULL, then check to see if the device has a DMA Handle
903eae2e508Skrishnae  * associated with ADDR.  If the handle is not found, mark all the handles as
904eae2e508Skrishnae  * failed.  If the BDF == NULL, mark the handle as failed if it is associated
905eae2e508Skrishnae  * with ADDR.
906eae2e508Skrishnae  */
907eae2e508Skrishnae int
px_err_dma_hdl_check(dev_info_t * dip,const void * handle,const void * arg1,const void * arg2)908eae2e508Skrishnae px_err_dma_hdl_check(dev_info_t *dip, const void *handle, const void *arg1,
909eae2e508Skrishnae     const void *arg2)
910eae2e508Skrishnae {
911eae2e508Skrishnae 	ddi_dma_impl_t		*pcie_dp;
912eae2e508Skrishnae 	int			status = DDI_FM_FATAL;
913eae2e508Skrishnae 	uint32_t		addr = *(uint32_t *)arg1;
914eae2e508Skrishnae 	uint16_t		bdf = *(uint16_t *)arg2;
915eae2e508Skrishnae 	uint32_t		base_addr;
916eae2e508Skrishnae 	uint_t			size;
917eae2e508Skrishnae 
918eae2e508Skrishnae 	DBG(DBG_ERR_INTR, dip, "Check PIO Hdl: dip 0x%x addr 0x%x bdf=0x%x\n",
919eae2e508Skrishnae 	    dip, addr, bdf);
920eae2e508Skrishnae 
921eae2e508Skrishnae 	pcie_dp = (ddi_dma_impl_t *)handle;
922eae2e508Skrishnae 	base_addr = (uint32_t)pcie_dp->dmai_mapping;
923eae2e508Skrishnae 	size = pcie_dp->dmai_size;
924eae2e508Skrishnae 
925eae2e508Skrishnae 	/*
926eae2e508Skrishnae 	 * Mark the handle as failed if the ADDR is mapped, or if we
927eae2e508Skrishnae 	 * know the BDF and ADDR == 0.
928eae2e508Skrishnae 	 */
929eae2e508Skrishnae 	if (((addr >= base_addr) && (addr < (base_addr + size))) ||
930*e214b19eSToomas Soome 	    ((addr == 0) && PCIE_CHECK_VALID_BDF(bdf)))
931eae2e508Skrishnae 		status = DDI_FM_NONFATAL;
932eae2e508Skrishnae 
933eae2e508Skrishnae 	return (status);
934eae2e508Skrishnae }
935eae2e508Skrishnae 
936eae2e508Skrishnae int
px_fm_enter(px_t * px_p)937eae2e508Skrishnae px_fm_enter(px_t *px_p) {
938eae2e508Skrishnae 	if (px_panicing || (px_p->px_fm_mutex_owner == curthread))
939eae2e508Skrishnae 		return (DDI_FAILURE);
940eae2e508Skrishnae 
941eae2e508Skrishnae 	mutex_enter(&px_p->px_fm_mutex);
942eae2e508Skrishnae 	/*
943eae2e508Skrishnae 	 * In rare cases when trap occurs and in the middle of scanning the
944eae2e508Skrishnae 	 * fabric, a PIO will fail in the scan fabric.  The CPU error handling
945eae2e508Skrishnae 	 * code will correctly panic the system, while a mondo for the failed
946eae2e508Skrishnae 	 * PIO may also show up.  Normally the mondo will try to grab the mutex
947eae2e508Skrishnae 	 * and wait until the callback finishes.  But in this rare case,
948eae2e508Skrishnae 	 * mutex_enter actually suceeds also continues to scan the fabric.
949eae2e508Skrishnae 	 *
950eae2e508Skrishnae 	 * This code below is designed specifically to check for this case.  If
951eae2e508Skrishnae 	 * we successfully grab the px_fm_mutex, the px_fm_mutex_owner better be
952eae2e508Skrishnae 	 * NULL.  If it isn't that means we are in the rare corner case.  Return
953eae2e508Skrishnae 	 * DDI_FAILURE, this should prevent PX from doing anymore error
954eae2e508Skrishnae 	 * handling.
955eae2e508Skrishnae 	 */
956eae2e508Skrishnae 	if (px_p->px_fm_mutex_owner) {
957eae2e508Skrishnae 		return (DDI_FAILURE);
958eae2e508Skrishnae 	}
959eae2e508Skrishnae 
960eae2e508Skrishnae 	px_p->px_fm_mutex_owner = curthread;
961eae2e508Skrishnae 
962eae2e508Skrishnae 	if (px_panicing) {
963eae2e508Skrishnae 		px_fm_exit(px_p);
964eae2e508Skrishnae 		return (DDI_FAILURE);
965eae2e508Skrishnae 	}
966fc256490SJason Beloro 
967fc256490SJason Beloro 	/* Signal the PCIe error handling module error handling is starting */
968fc256490SJason Beloro 	pf_eh_enter(PCIE_DIP2BUS(px_p->px_dip));
969fc256490SJason Beloro 
970eae2e508Skrishnae 	return (DDI_SUCCESS);
971eae2e508Skrishnae }
972eae2e508Skrishnae 
973fc256490SJason Beloro static void
px_guest_panic(px_t * px_p)974fc256490SJason Beloro px_guest_panic(px_t *px_p)
975fc256490SJason Beloro {
976fc256490SJason Beloro 	pf_data_t *root_pfd_p = PCIE_DIP2PFD(px_p->px_dip);
977fc256490SJason Beloro 	pf_data_t *pfd_p;
978fc256490SJason Beloro 	pcie_bus_t *bus_p, *root_bus_p;
979fc256490SJason Beloro 	pcie_req_id_list_t *rl;
980fc256490SJason Beloro 
981fc256490SJason Beloro 	/*
982fc256490SJason Beloro 	 * check if all devices under the root device are unassigned.
983fc256490SJason Beloro 	 * this function should quickly return in non-IOV environment.
984fc256490SJason Beloro 	 */
985fc256490SJason Beloro 	root_bus_p = PCIE_PFD2BUS(root_pfd_p);
986fc256490SJason Beloro 	if (PCIE_BDG_IS_UNASSIGNED(root_bus_p))
987fc256490SJason Beloro 		return;
988fc256490SJason Beloro 
989fc256490SJason Beloro 	for (pfd_p = root_pfd_p; pfd_p; pfd_p = pfd_p->pe_next) {
990fc256490SJason Beloro 		bus_p = PCIE_PFD2BUS(pfd_p);
991fc256490SJason Beloro 
992fc256490SJason Beloro 		/* assume all affected devs were in the error Q */
993fc256490SJason Beloro 		if (!PCIE_BUS2DOM(bus_p)->nfma_panic)
994fc256490SJason Beloro 			continue;
995fc256490SJason Beloro 
996fc256490SJason Beloro 		if (PCIE_IS_BDG(bus_p)) {
997fc256490SJason Beloro 			rl = PCIE_BDF_LIST_GET(bus_p);
998fc256490SJason Beloro 			while (rl) {
999fc256490SJason Beloro 				px_panic_domain(px_p, rl->bdf);
1000fc256490SJason Beloro 				rl = rl->next;
1001fc256490SJason Beloro 			}
1002fc256490SJason Beloro 		} else {
1003fc256490SJason Beloro 			px_panic_domain(px_p, bus_p->bus_bdf);
1004fc256490SJason Beloro 		}
1005fc256490SJason Beloro 		/* clear panic flag */
1006fc256490SJason Beloro 		PCIE_BUS2DOM(bus_p)->nfma_panic = B_FALSE;
1007fc256490SJason Beloro 	}
1008fc256490SJason Beloro }
1009fc256490SJason Beloro 
1010eae2e508Skrishnae void
px_fm_exit(px_t * px_p)1011eae2e508Skrishnae px_fm_exit(px_t *px_p) {
1012eae2e508Skrishnae 	px_p->px_fm_mutex_owner = NULL;
1013fc256490SJason Beloro 	if (px_p->px_pfd_idx == 0) {
1014fc256490SJason Beloro 		mutex_exit(&px_p->px_fm_mutex);
1015fc256490SJason Beloro 		return;
1016fc256490SJason Beloro 	}
1017fc256490SJason Beloro 	/* panic the affected domains that are non-fma-capable */
1018fc256490SJason Beloro 	px_guest_panic(px_p);
1019fc256490SJason Beloro 	/* Signal the PCIe error handling module error handling is ending */
1020fc256490SJason Beloro 	pf_eh_exit(PCIE_DIP2BUS(px_p->px_dip));
1021fc256490SJason Beloro 	px_p->px_pfd_idx = 0;
1022eae2e508Skrishnae 	mutex_exit(&px_p->px_fm_mutex);
1023bf8fc234Set }
1024bf8fc234Set 
1025bf8fc234Set /*
1026bf8fc234Set  * Panic if the err tunable is set and that we are not already in the middle
1027bf8fc234Set  * of panic'ing.
1028eae2e508Skrishnae  *
1029eae2e508Skrishnae  * rc_err = Error severity of PX specific errors
1030eae2e508Skrishnae  * msg = Where the error was detected
1031eae2e508Skrishnae  * fabric_err = Error severity of PCIe Fabric errors
1032eae2e508Skrishnae  * isTest = Test if error severity causes panic
1033bf8fc234Set  */
1034bf8fc234Set #define	MSZ (sizeof (fm_msg) -strlen(fm_msg) - 1)
1035bf8fc234Set void
px_err_panic(int rc_err,int msg,int fabric_err,boolean_t isTest)1036eae2e508Skrishnae px_err_panic(int rc_err, int msg, int fabric_err, boolean_t isTest)
1037bf8fc234Set {
1038bf8fc234Set 	char fm_msg[96] = "";
1039bf8fc234Set 	int ferr = PX_NO_ERROR;
1040bf8fc234Set 
1041eae2e508Skrishnae 	if (panicstr) {
1042eae2e508Skrishnae 		px_panicing = B_TRUE;
1043bf8fc234Set 		return;
1044eae2e508Skrishnae 	}
1045bf8fc234Set 
1046eae2e508Skrishnae 	if (!(rc_err & px_die))
1047bf8fc234Set 		goto fabric;
1048bf8fc234Set 	if (msg & PX_RC)
1049bf8fc234Set 		(void) strncat(fm_msg, px_panic_rc_msg, MSZ);
1050bf8fc234Set 	if (msg & PX_RP)
1051bf8fc234Set 		(void) strncat(fm_msg, px_panic_rp_msg, MSZ);
1052bf8fc234Set 	if (msg & PX_HB)
1053bf8fc234Set 		(void) strncat(fm_msg, px_panic_hb_msg, MSZ);
1054bf8fc234Set 
1055bf8fc234Set fabric:
1056eae2e508Skrishnae 	if (fabric_err & PF_ERR_FATAL_FLAGS)
1057bf8fc234Set 		ferr = PX_PANIC;
1058eae2e508Skrishnae 	else if (fabric_err & ~(PF_ERR_FATAL_FLAGS | PF_ERR_NO_ERROR))
1059bf8fc234Set 		ferr = PX_NO_PANIC;
10606aa97eabSkrishnae 
1061bf8fc234Set 	if (ferr & px_die) {
1062eae2e508Skrishnae 		if (strlen(fm_msg)) {
1063bf8fc234Set 			(void) strncat(fm_msg, " and", MSZ);
1064eae2e508Skrishnae 		}
1065bf8fc234Set 		(void) strncat(fm_msg, px_panic_fab_msg, MSZ);
1066bf8fc234Set 	}
1067bf8fc234Set 
1068eae2e508Skrishnae 	if (strlen(fm_msg)) {
1069eae2e508Skrishnae 		px_panicing = B_TRUE;
1070eae2e508Skrishnae 		if (!isTest)
1071eae2e508Skrishnae 			fm_panic("Fatal error has occured in:%s.(0x%x)(0x%x)",
1072eae2e508Skrishnae 			    fm_msg, rc_err, fabric_err);
1073eae2e508Skrishnae 	}
1074bf8fc234Set }
1075