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
40bf8fc234Set142600 #define PX_PCIE_PANIC_BITS \
41bf8fc234Set142600 (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)
43bf8fc234Set142600 #define PX_PCIE_NO_PANIC_BITS \
44bf8fc234Set142600 (PCIE_AER_UCE_TRAINING | PCIE_AER_UCE_SD | PCIE_AER_UCE_CA | \
451ff65112Segillett PCIE_AER_UCE_UC | PCIE_AER_UCE_UR)
468bc7d88aSet142600
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
55bf8fc234Set142600 static int px_pcie_ptlp(dev_info_t *dip, ddi_fm_error_t *derr,
56bf8fc234Set142600 px_err_pcie_t *regs);
578bc7d88aSet142600
58bf8fc234Set142600 #if defined(DEBUG)
59eae2e508Skrishnae static void px_pcie_log(dev_info_t *dip, px_err_pcie_t *regs);
60bf8fc234Set142600 #else /* DEBUG */
61bf8fc234Set142600 #define px_pcie_log 0 &&
62bf8fc234Set142600 #endif /* DEBUG */
638bc7d88aSet142600
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 |
75f8d2de6bSjchu 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
88f8d2de6bSjchu /*
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
1207c478bd9Sstevel@tonic-gate /*
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
135e6b21d58SErwin T Tsaur /*
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;
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate /*
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);
263f8d2de6bSjchu }
264f8d2de6bSjchu
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
284f8d2de6bSjchu /*
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
287bf8fc234Set142600 * 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)
2927c478bd9Sstevel@tonic-gate {
293c2a75729Sdwoods dev_info_t *pdip = ddi_get_parent(dip);
2947c478bd9Sstevel@tonic-gate px_t *px_p = (px_t *)impl_data;
295bf8fc234Set142600 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;
301bf8fc234Set142600 int range_len;
302fc256490SJason Beloro pf_data_t *pfd_p;
303f8d2de6bSjchu
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 }
319d60bae31Sdwoods
320bf8fc234Set142600 /*
321bf8fc234Set142600 * Make sure this failed load came from this PCIe port. Check by
322bf8fc234Set142600 * matching the upper 32 bits of the address with the ranges property.
323bf8fc234Set142600 */
32426947304SEvan Yan range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
325bf8fc234Set142600 i = 0;
326bf8fc234Set142600 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) {
329bf8fc234Set142600 switch (ranges_p->child_high & PCI_ADDR_MASK) {
330bf8fc234Set142600 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);
335bf8fc234Set142600 break;
3361ff65112Segillett case PCI_ADDR_IO:
337eae2e508Skrishnae case PCI_ADDR_MEM64:
338bf8fc234Set142600 case PCI_ADDR_MEM32:
339eae2e508Skrishnae acc_type = PF_ADDR_PIO;
340eae2e508Skrishnae addr = fault_addr - base_addr;
341c85864d8SKrishna Elango bdf = PCIE_INVALID_BDF;
342bf8fc234Set142600 break;
343bf8fc234Set142600 }
344bf8fc234Set142600 break;
345bf8fc234Set142600 }
346bf8fc234Set142600 }
347bf8fc234Set142600
348bf8fc234Set142600 /* This address doesn't belong to this leaf, just return with OK */
349bf8fc234Set142600 if (!acc_type) {
350eae2e508Skrishnae px_fm_exit(px_p);
351c2a75729Sdwoods i_ddi_fm_handler_enter(pdip);
352bf8fc234Set142600 return (DDI_FM_OK);
353bf8fc234Set142600 }
354bf8fc234Set142600
355bf8fc234Set142600 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);
358bf8fc234Set142600
359fc256490SJason Beloro pfd_p = px_rp_en_q(px_p, bdf, addr,
360bf8fc234Set142600 (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 }
37001689544Sjchu
371eae2e508Skrishnae fab_err = px_scan_fabric(px_p, dip, derr);
372eae2e508Skrishnae
373eae2e508Skrishnae px_fm_exit(px_p);
374c2a75729Sdwoods i_ddi_fm_handler_enter(pdip);
37501689544Sjchu
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) ||
381bf8fc234Set142600 (lookup == PF_HDL_NOTFOUND))
3828bc7d88aSet142600 return (DDI_FM_FATAL);
383eae2e508Skrishnae else if ((rc_err == PX_NO_ERROR) && (fab_err == PF_ERR_NO_ERROR))
384bf8fc234Set142600 return (DDI_FM_OK);
3858bc7d88aSet142600
386bf8fc234Set142600 return (DDI_FM_NONFATAL);
3878bc7d88aSet142600 }
3888bc7d88aSet142600
3898bc7d88aSet142600 /*
3908bc7d88aSet142600 * px_err_fabric_intr:
3918bc7d88aSet142600 * Interrupt handler for PCIE fabric block.
392f8d2de6bSjchu * o lock
393f8d2de6bSjchu * o create derr
394bf8fc234Set142600 * 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)
3997c478bd9Sstevel@tonic-gate */
400f8d2de6bSjchu /* ARGSUSED */
401f8d2de6bSjchu uint_t
px_err_fabric_intr(px_t * px_p,msgcode_t msg_code,pcie_req_id_t rid)402bf8fc234Set142600 px_err_fabric_intr(px_t *px_p, msgcode_t msg_code, pcie_req_id_t rid)
403f8d2de6bSjchu {
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;
4107c478bd9Sstevel@tonic-gate
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
450bf8fc234Set142600 /* 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
454bf8fc234Set142600 rc_err = px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_PCIE);
4558bc7d88aSet142600
456bf8fc234Set142600 /* call rootport dispatch */
457eae2e508Skrishnae fab_err = px_scan_fabric(px_p, rpdip, &derr);
458eae2e508Skrishnae
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);
462eae2e508Skrishnae
463eae2e508Skrishnae done:
464eae2e508Skrishnae return (DDI_INTR_CLAIMED);
465c333dd99Sdm120769 }
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;
490f41150baSkrishnae
491eae2e508Skrishnae ASSERT(MUTEX_HELD(&px_p->px_fm_mutex));
492c333dd99Sdm120769
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);
498bf8fc234Set142600 }
499f8d2de6bSjchu
500f41150baSkrishnae /*
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 }
560bf8fc234Set142600
561bf8fc234Set142600 /*
562bf8fc234Set142600 * Suggest panic if any EQ (except CE q) has overflown.
563bf8fc234Set142600 */
564bf8fc234Set142600 int
px_err_check_eq(dev_info_t * dip)565bf8fc234Set142600 px_err_check_eq(dev_info_t *dip)
566bf8fc234Set142600 {
567bf8fc234Set142600 px_t *px_p = DIP_TO_STATE(dip);
568bf8fc234Set142600 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
569bf8fc234Set142600 px_pec_t *pec_p = px_p->px_pec_p;
570bf8fc234Set142600 msiqid_t eq_no = msiq_state_p->msiq_1st_msiq_id;
571bf8fc234Set142600 pci_msiq_state_t msiq_state;
572bf8fc234Set142600 int i;
573bf8fc234Set142600
574bf8fc234Set142600 for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
575bf8fc234Set142600 if (i + eq_no == pec_p->pec_corr_msg_msiq_id) /* skip CE q */
576bf8fc234Set142600 continue;
577bf8fc234Set142600 if ((px_lib_msiq_getstate(dip, i + eq_no, &msiq_state) !=
578bf8fc234Set142600 DDI_SUCCESS) || msiq_state == PCI_MSIQ_STATE_ERROR)
579bf8fc234Set142600 return (PX_PANIC);
580bf8fc234Set142600 }
581bf8fc234Set142600 return (PX_NO_PANIC);
582bf8fc234Set142600 }
583bf8fc234Set142600
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)
588bf8fc234Set142600 {
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);
5937ea9b230Set142600
5945613d828SKrishna Elango PCIE_ROOT_EH_SRC(pfd_p)->intr_type = intr_type;
5955613d828SKrishna Elango
596bf8fc234Set142600 /*
597bf8fc234Set142600 * set RC s_status in PCI term to coordinate with downstream fabric
598bf8fc234Set142600 * errors ananlysis.
599bf8fc234Set142600 */
600bf8fc234Set142600 if (regs->primary_ue & PCIE_AER_UCE_UR)
601eae2e508Skrishnae PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = PCI_STAT_R_MAST_AB;
602bf8fc234Set142600 if (regs->primary_ue & PCIE_AER_UCE_CA)
603eae2e508Skrishnae PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = PCI_STAT_R_TARG_AB;
604bf8fc234Set142600 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;
606bf8fc234Set142600
607eae2e508Skrishnae if (!regs->primary_ue)
608c333dd99Sdm120769 goto done;
609c333dd99Sdm120769
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++;
618c333dd99Sdm120769
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 }
632c333dd99Sdm120769
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 }
639c333dd99Sdm120769
640c333dd99Sdm120769 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);
645bf8fc234Set142600 }
646bf8fc234Set142600
647bf8fc234Set142600 #if defined(DEBUG)
648bf8fc234Set142600 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)
650bf8fc234Set142600 {
651bf8fc234Set142600 DBG(DBG_ERR_INTR, dip,
652eae2e508Skrishnae "A PCIe RC error has occured\n"
653bf8fc234Set142600 "\tCE: 0x%x UE: 0x%x Primary UE: 0x%x\n"
654bf8fc234Set142600 "\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);
658bf8fc234Set142600 }
659eae2e508Skrishnae #endif
660bf8fc234Set142600
661bf8fc234Set142600 /*
662bf8fc234Set142600 * look through poisoned TLP cases and suggest panic/no panic depend on
663bf8fc234Set142600 * handle lookup.
664bf8fc234Set142600 */
665bf8fc234Set142600 static int
px_pcie_ptlp(dev_info_t * dip,ddi_fm_error_t * derr,px_err_pcie_t * regs)666bf8fc234Set142600 px_pcie_ptlp(dev_info_t *dip, ddi_fm_error_t *derr, px_err_pcie_t *regs)
667bf8fc234Set142600 {
668eae2e508Skrishnae pf_pcie_adv_err_regs_t adv_reg;
669bf8fc234Set142600 pcie_req_id_t bdf;
670eae2e508Skrishnae uint64_t addr;
671eae2e508Skrishnae uint32_t trans_type;
672bf8fc234Set142600 int tlp_sts, tlp_cmd;
673eae2e508Skrishnae int lookup = PF_HDL_NOTFOUND;
674bf8fc234Set142600
675bf8fc234Set142600 if (regs->primary_ue != PCIE_AER_UCE_PTLP)
676bf8fc234Set142600 return (PX_PANIC);
677bf8fc234Set142600
678bf8fc234Set142600 if (!regs->rx_hdr1)
679bf8fc234Set142600 goto done;
680bf8fc234Set142600
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;
685bf8fc234Set142600
686eae2e508Skrishnae tlp_sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
687eae2e508Skrishnae tlp_cmd = ((pcie_tlp_hdr_t *)(adv_reg.pcie_ue_hdr))->type;
688bf8fc234Set142600
689bf8fc234Set142600 if (tlp_sts == DDI_FAILURE)
690bf8fc234Set142600 goto done;
691bf8fc234Set142600
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
696bf8fc234Set142600 switch (tlp_cmd) {
697bf8fc234Set142600 case PCIE_TLP_TYPE_CPL:
698bf8fc234Set142600 case PCIE_TLP_TYPE_CPLLK:
699bf8fc234Set142600 /*
700bf8fc234Set142600 * Usually a PTLP is a CPL with data. Grab the completer BDF
701bf8fc234Set142600 * from the RX TLP, and the original address from the TX TLP.
702bf8fc234Set142600 */
703bf8fc234Set142600 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;
708bf8fc234Set142600
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;
714bf8fc234Set142600 } /* FALLTHRU */
715bf8fc234Set142600 case PCIE_TLP_TYPE_IO:
716bf8fc234Set142600 case PCIE_TLP_TYPE_MEM:
717bf8fc234Set142600 case PCIE_TLP_TYPE_MEMLK:
718eae2e508Skrishnae lookup = pf_hdl_lookup(dip, derr->fme_ena, trans_type, addr,
719eae2e508Skrishnae bdf);
720bf8fc234Set142600 break;
721bf8fc234Set142600 default:
722eae2e508Skrishnae lookup = PF_HDL_NOTFOUND;
723bf8fc234Set142600 }
724bf8fc234Set142600 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);
764bf8fc234Set142600 }
765bf8fc234Set142600
766bf8fc234Set142600 /*
767bf8fc234Set142600 * This function appends a pf_data structure to the error q which is used later
768bf8fc234Set142600 * during PCIe fabric scan. It signifies:
769bf8fc234Set142600 * o errs rcvd in RC, that may have been propagated to/from the fabric
770bf8fc234Set142600 * o the fabric scan code should scan the device path of fault bdf/addr
771bf8fc234Set142600 *
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
774bf8fc234Set142600 * failed DMAs.
775bf8fc234Set142600 * s_status: Secondary Status equivalent to why the fault occured.
776bf8fc234Set142600 * (ie S-TA/MA, R-TA)
777c85864d8SKrishna Elango * Either the scan bdf or addr may be NULL, but not both.
778bf8fc234Set142600 */
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,
781bf8fc234Set142600 uint16_t s_status)
782bf8fc234Set142600 {
783eae2e508Skrishnae pf_data_t *pfd_p;
784bf8fc234Set142600
785c85864d8SKrishna Elango if (!PCIE_CHECK_VALID_BDF(scan_bdf) && !scan_addr)
786fc256490SJason Beloro return (NULL);
787bf8fc234Set142600
788eae2e508Skrishnae pfd_p = px_get_pfd(px_p);
789bf8fc234Set142600
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 }
796bf8fc234Set142600
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);
815eae2e508Skrishnae
816eae2e508Skrishnae bus_p = PCIE_DIP2BUS(dip);
817eae2e508Skrishnae
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);
1023bf8fc234Set142600 }
1024bf8fc234Set142600
1025bf8fc234Set142600 /*
1026bf8fc234Set142600 * Panic if the err tunable is set and that we are not already in the middle
1027bf8fc234Set142600 * 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
1033bf8fc234Set142600 */
1034bf8fc234Set142600 #define MSZ (sizeof (fm_msg) -strlen(fm_msg) - 1)
1035bf8fc234Set142600 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)
1037bf8fc234Set142600 {
1038bf8fc234Set142600 char fm_msg[96] = "";
1039bf8fc234Set142600 int ferr = PX_NO_ERROR;
1040bf8fc234Set142600
1041eae2e508Skrishnae if (panicstr) {
1042eae2e508Skrishnae px_panicing = B_TRUE;
1043bf8fc234Set142600 return;
1044eae2e508Skrishnae }
1045bf8fc234Set142600
1046eae2e508Skrishnae if (!(rc_err & px_die))
1047bf8fc234Set142600 goto fabric;
1048bf8fc234Set142600 if (msg & PX_RC)
1049bf8fc234Set142600 (void) strncat(fm_msg, px_panic_rc_msg, MSZ);
1050bf8fc234Set142600 if (msg & PX_RP)
1051bf8fc234Set142600 (void) strncat(fm_msg, px_panic_rp_msg, MSZ);
1052bf8fc234Set142600 if (msg & PX_HB)
1053bf8fc234Set142600 (void) strncat(fm_msg, px_panic_hb_msg, MSZ);
1054bf8fc234Set142600
1055bf8fc234Set142600 fabric:
1056eae2e508Skrishnae if (fabric_err & PF_ERR_FATAL_FLAGS)
1057bf8fc234Set142600 ferr = PX_PANIC;
1058eae2e508Skrishnae else if (fabric_err & ~(PF_ERR_FATAL_FLAGS | PF_ERR_NO_ERROR))
1059bf8fc234Set142600 ferr = PX_NO_PANIC;
10606aa97eabSkrishnae
1061bf8fc234Set142600 if (ferr & px_die) {
1062eae2e508Skrishnae if (strlen(fm_msg)) {
1063bf8fc234Set142600 (void) strncat(fm_msg, " and", MSZ);
1064eae2e508Skrishnae }
1065bf8fc234Set142600 (void) strncat(fm_msg, px_panic_fab_msg, MSZ);
1066bf8fc234Set142600 }
1067bf8fc234Set142600
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 }
1074bf8fc234Set142600 }
1075