xref: /illumos-gate/usr/src/uts/sun4v/io/px/px_err.c (revision fc256490)
1f8d2de6bSjchu /*
2f8d2de6bSjchu  * CDDL HEADER START
3f8d2de6bSjchu  *
4f8d2de6bSjchu  * The contents of this file are subject to the terms of the
501689544Sjchu  * Common Development and Distribution License (the "License").
601689544Sjchu  * You may not use this file except in compliance with the License.
7f8d2de6bSjchu  *
8f8d2de6bSjchu  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f8d2de6bSjchu  * or http://www.opensolaris.org/os/licensing.
10f8d2de6bSjchu  * See the License for the specific language governing permissions
11f8d2de6bSjchu  * and limitations under the License.
12f8d2de6bSjchu  *
13f8d2de6bSjchu  * When distributing Covered Code, include this CDDL HEADER in each
14f8d2de6bSjchu  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f8d2de6bSjchu  * If applicable, add the following below this CDDL HEADER, with the
16f8d2de6bSjchu  * fields enclosed by brackets "[]" replaced with your own identifying
17f8d2de6bSjchu  * information: Portions Copyright [yyyy] [name of copyright owner]
18f8d2de6bSjchu  *
19f8d2de6bSjchu  * CDDL HEADER END
20f8d2de6bSjchu  */
21f8d2de6bSjchu /*
22*fc256490SJason Beloro  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23f8d2de6bSjchu  * Use is subject to license terms.
24f8d2de6bSjchu  */
25f8d2de6bSjchu 
26f8d2de6bSjchu /*
27f8d2de6bSjchu  * sun4v Fire Error Handling
28f8d2de6bSjchu  */
29f8d2de6bSjchu 
30f8d2de6bSjchu #include <sys/types.h>
31f8d2de6bSjchu #include <sys/ddi.h>
32f8d2de6bSjchu #include <sys/sunddi.h>
33eae2e508Skrishnae #include <sys/sunndi.h>
34f8d2de6bSjchu #include <sys/fm/protocol.h>
35f8d2de6bSjchu #include <sys/fm/util.h>
36f8d2de6bSjchu #include <sys/membar.h>
37f8d2de6bSjchu #include "px_obj.h"
38f8d2de6bSjchu #include "px_err.h"
39f8d2de6bSjchu 
40*fc256490SJason Beloro static void px_err_fill_pfd(dev_info_t *dip, pf_data_t *pfd_p,
41*fc256490SJason Beloro     px_rc_err_t *epkt);
42bf8fc234Set static uint_t px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt);
43bf8fc234Set static int  px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr,
44*fc256490SJason Beloro     px_rc_err_t *epkt, pf_data_t *pfd_p);
45f8d2de6bSjchu 
46bf8fc234Set static void px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt,
47bf8fc234Set     boolean_t is_block_pci, char *msg);
48eae2e508Skrishnae static void px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
49eae2e508Skrishnae     boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
50eae2e508Skrishnae     boolean_t is_valid_epkt);
51bf8fc234Set static int px_cb_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
52bf8fc234Set     px_rc_err_t *epkt);
53bf8fc234Set static int px_mmu_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
54bf8fc234Set     px_rc_err_t *epkt);
55bf8fc234Set static int px_intr_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
56bf8fc234Set     px_rc_err_t *epkt);
574df55fdeSJanie Lu static int px_port_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
58*fc256490SJason Beloro     px_rc_err_t *epkt, pf_data_t *pfd_p);
59bf8fc234Set static int px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
60bf8fc234Set     px_rc_err_t *epkt);
61bf8fc234Set static int px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
62bf8fc234Set     px_rc_err_t *epkt);
634df55fdeSJanie Lu static int px_port_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
64*fc256490SJason Beloro     px_rc_err_t *epkt, pf_data_t *pfd_p);
65bf8fc234Set static void px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr,
66bf8fc234Set     px_rc_err_t *epkt);
67bf8fc234Set static int px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr,
68bf8fc234Set     px_rc_err_t *epkt);
69bf8fc234Set 
70bf8fc234Set /* Include the code generated sun4v epkt checking code */
71bf8fc234Set #include "px_err_gen.c"
72bf8fc234Set 
73bf8fc234Set /*
74bf8fc234Set  * This variable indicates if we have a hypervisor that could potentially send
75bf8fc234Set  * incorrect epkts. We always set this to TRUE for now until we find a way to
76bf8fc234Set  * tell if this HV bug has been fixed.
77bf8fc234Set  */
78bf8fc234Set boolean_t px_legacy_epkt = B_TRUE;
79f8d2de6bSjchu 
80f8d2de6bSjchu /*
81f8d2de6bSjchu  * px_err_cb_intr:
82f8d2de6bSjchu  * Interrupt handler for the Host Bus Block.
83f8d2de6bSjchu  */
84f8d2de6bSjchu uint_t
85f8d2de6bSjchu px_err_cb_intr(caddr_t arg)
86f8d2de6bSjchu {
87f8d2de6bSjchu 	px_fault_t	*fault_p = (px_fault_t *)arg;
88f8d2de6bSjchu 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
89f8d2de6bSjchu 
90f8d2de6bSjchu 	if (epkt != NULL) {
91bf8fc234Set 		return (px_err_intr(fault_p, epkt));
92f8d2de6bSjchu 	}
93f8d2de6bSjchu 
94f8d2de6bSjchu 	return (DDI_INTR_UNCLAIMED);
95f8d2de6bSjchu }
96f8d2de6bSjchu 
97f8d2de6bSjchu /*
98f8d2de6bSjchu  * px_err_dmc_pec_intr:
99f8d2de6bSjchu  * Interrupt handler for the DMC/PEC block.
100f8d2de6bSjchu  */
101f8d2de6bSjchu uint_t
102f8d2de6bSjchu px_err_dmc_pec_intr(caddr_t arg)
103f8d2de6bSjchu {
104f8d2de6bSjchu 	px_fault_t	*fault_p = (px_fault_t *)arg;
105f8d2de6bSjchu 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
106f8d2de6bSjchu 
107f8d2de6bSjchu 	if (epkt != NULL) {
108bf8fc234Set 		return (px_err_intr(fault_p, epkt));
109f8d2de6bSjchu 	}
110f8d2de6bSjchu 
111f8d2de6bSjchu 	return (DDI_INTR_UNCLAIMED);
112f8d2de6bSjchu }
113f8d2de6bSjchu 
114f8d2de6bSjchu /*
115bf8fc234Set  * px_err_cmn_intr:
116f8d2de6bSjchu  * Common function called by trap, mondo and fabric intr.
117f8d2de6bSjchu  * This function is more meaningful in sun4u implementation.  Kept
118f8d2de6bSjchu  * to mirror sun4u call stack.
119f8d2de6bSjchu  * o check for safe access
120bf8fc234Set  * o create and queue RC info for later use in fabric scan.
121bf8fc234Set  *   o RUC/WUC, PTLP, MMU Errors(CA), UR
122f8d2de6bSjchu  *
123f8d2de6bSjchu  * @param px_p		leaf in which to check access
124f8d2de6bSjchu  * @param derr		fm err data structure to be updated
125f8d2de6bSjchu  * @param caller	PX_TRAP_CALL | PX_INTR_CALL
126f8d2de6bSjchu  * @param chkjbc	whether to handle hostbus registers (ignored)
127bf8fc234Set  * @return err		PX_NO_PANIC | PX_PROTECTED |
128bf8fc234Set  *                      PX_PANIC | PX_HW_RESET | PX_EXPECTED
129f8d2de6bSjchu  */
130f8d2de6bSjchu /* ARGSUSED */
131f8d2de6bSjchu int
132bf8fc234Set px_err_cmn_intr(px_t *px_p, ddi_fm_error_t *derr, int caller, int block)
133f8d2de6bSjchu {
134f8d2de6bSjchu 	px_err_safeacc_check(px_p, derr);
135e51949e6Sdduvall 	return (DDI_FM_OK);
1363d9c56a1Set }
1373d9c56a1Set 
1383d9c56a1Set /*
139bf8fc234Set  * fills RC specific fault data
140bf8fc234Set  */
141bf8fc234Set static void
142*fc256490SJason Beloro px_err_fill_pfd(dev_info_t *dip, pf_data_t *pfd_p, px_rc_err_t *epkt) {
143eae2e508Skrishnae 	pf_pcie_adv_err_regs_t adv_reg;
144bf8fc234Set 	int		sts = DDI_SUCCESS;
145c85864d8SKrishna Elango 	pcie_req_id_t	fault_bdf = PCIE_INVALID_BDF;
146eae2e508Skrishnae 	uint64_t	fault_addr = 0;
147bf8fc234Set 	uint16_t	s_status = 0;
148bf8fc234Set 
149bf8fc234Set 	/* Add an PCIE PF_DATA Entry */
150bf8fc234Set 	if (epkt->rc_descr.block == BLOCK_MMU) {
151bf8fc234Set 		/* Only PIO Fault Addresses are valid, this is DMA */
152bf8fc234Set 		s_status = PCI_STAT_S_TARG_AB;
153bf8fc234Set 		fault_addr = NULL;
154bf8fc234Set 
155*fc256490SJason Beloro 		if (epkt->rc_descr.H) {
156bf8fc234Set 			fault_bdf = (pcie_req_id_t)(epkt->hdr[0] >> 16);
157*fc256490SJason Beloro 			PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags =
158*fc256490SJason Beloro 			    PF_AFFECTED_BDF;
159*fc256490SJason Beloro 			PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf =
160*fc256490SJason Beloro 			    fault_bdf;
161*fc256490SJason Beloro 		} else
162bf8fc234Set 			sts = DDI_FAILURE;
163bf8fc234Set 	} else {
164bf8fc234Set 		px_pec_err_t	*pec_p = (px_pec_err_t *)epkt;
165bf8fc234Set 		uint32_t	dir = pec_p->pec_descr.dir;
166bf8fc234Set 
167eae2e508Skrishnae 		adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0]);
168eae2e508Skrishnae 		adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0] >> 32);
169eae2e508Skrishnae 		adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1]);
170eae2e508Skrishnae 		adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1] >> 32);
171bf8fc234Set 
172bf8fc234Set 		/* translate RC UR/CA to legacy secondary errors */
173bf8fc234Set 		if ((dir == DIR_READ || dir == DIR_WRITE) &&
174bf8fc234Set 		    pec_p->pec_descr.U) {
175bf8fc234Set 			if (pec_p->ue_reg_status & PCIE_AER_UCE_UR)
176bf8fc234Set 				s_status |= PCI_STAT_R_MAST_AB;
1771ff65112Segillett 			if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
178bf8fc234Set 				s_status |= PCI_STAT_R_TARG_AB;
179bf8fc234Set 		}
180bf8fc234Set 
181bf8fc234Set 		if (pec_p->ue_reg_status & PCIE_AER_UCE_PTLP)
182bf8fc234Set 			s_status |= PCI_STAT_PERROR;
183bf8fc234Set 
184bf8fc234Set 		if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
185bf8fc234Set 			s_status |= PCI_STAT_S_TARG_AB;
186bf8fc234Set 
187eae2e508Skrishnae 		sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
188eae2e508Skrishnae 		fault_bdf = adv_reg.pcie_ue_tgt_bdf;
189c85864d8SKrishna Elango 		fault_addr = adv_reg.pcie_ue_tgt_addr;
190*fc256490SJason Beloro 		/* affected BDF is to be filled in by px_scan_fabric */
191*fc256490SJason Beloro 	}
192*fc256490SJason Beloro 
193*fc256490SJason Beloro 	if (sts == DDI_SUCCESS) {
194*fc256490SJason Beloro 		PCIE_ROOT_FAULT(pfd_p)->scan_bdf = fault_bdf;
195*fc256490SJason Beloro 		PCIE_ROOT_FAULT(pfd_p)->scan_addr = (uint64_t)fault_addr;
196*fc256490SJason Beloro 		PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
197bf8fc234Set 	}
198*fc256490SJason Beloro }
199*fc256490SJason Beloro 
200*fc256490SJason Beloro /*
201*fc256490SJason Beloro  * Convert error severity from PX internal values to PCIe Fabric values.  Most
202*fc256490SJason Beloro  * are self explanitory, except PX_PROTECTED.  PX_PROTECTED will never be
203*fc256490SJason Beloro  * returned as is if forgivable.
204*fc256490SJason Beloro  */
205*fc256490SJason Beloro static int px_err_to_fab_sev(int rc_err) {
206*fc256490SJason Beloro 	int fab_err = 0;
207*fc256490SJason Beloro 
208*fc256490SJason Beloro 	if (rc_err & (PX_HW_RESET | PX_EXPECTED | PX_NO_PANIC))
209*fc256490SJason Beloro 		fab_err |= PF_ERR_NO_PANIC;
210bf8fc234Set 
211*fc256490SJason Beloro 	if (rc_err & (PX_PANIC | PX_PROTECTED))
212*fc256490SJason Beloro 		fab_err |= PF_ERR_PANIC;
213*fc256490SJason Beloro 
214*fc256490SJason Beloro 	if (rc_err & PX_NO_ERROR)
215*fc256490SJason Beloro 		fab_err |= PF_ERR_NO_ERROR;
216*fc256490SJason Beloro 
217*fc256490SJason Beloro 	return (fab_err);
218bf8fc234Set }
219bf8fc234Set 
220bf8fc234Set /*
221bf8fc234Set  * px_err_intr:
222f8d2de6bSjchu  * Interrupt handler for the JBC/DMC/PEC block.
223f8d2de6bSjchu  * o lock
224f8d2de6bSjchu  * o create derr
225f8d2de6bSjchu  * o check safe access
226bf8fc234Set  * o px_err_check_severity(epkt)
227bf8fc234Set  * o pcie_scan_fabric
228f8d2de6bSjchu  * o Idle intr state
229f8d2de6bSjchu  * o unlock
230f8d2de6bSjchu  * o handle error: fatal? fm_panic() : return INTR_CLAIMED)
231f8d2de6bSjchu  */
232f8d2de6bSjchu static uint_t
233bf8fc234Set px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt)
234f8d2de6bSjchu {
235f8d2de6bSjchu 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip);
236f8d2de6bSjchu 	dev_info_t	*rpdip = px_p->px_dip;
237eae2e508Skrishnae 	int		rc_err, fab_err, msg;
238f8d2de6bSjchu 	ddi_fm_error_t	derr;
239*fc256490SJason Beloro 	pf_data_t	*pfd_p;
240f8d2de6bSjchu 
241eae2e508Skrishnae 	if (px_fm_enter(px_p) != DDI_SUCCESS)
242eae2e508Skrishnae 		goto done;
243f8d2de6bSjchu 
244*fc256490SJason Beloro 	pfd_p = px_get_pfd(px_p);
245*fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_INTERNAL;
246*fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p)->intr_data = epkt;
247*fc256490SJason Beloro 
248f8d2de6bSjchu 	/* Create the derr */
249f8d2de6bSjchu 	bzero(&derr, sizeof (ddi_fm_error_t));
250f8d2de6bSjchu 	derr.fme_version = DDI_FME_VERSION;
251f8d2de6bSjchu 	derr.fme_ena = fm_ena_generate(epkt->stick, FM_ENA_FMT1);
252f8d2de6bSjchu 	derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
253f8d2de6bSjchu 
254f8d2de6bSjchu 	/* Basically check for safe access */
255bf8fc234Set 	(void) px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_ALL);
256f8d2de6bSjchu 
257f8d2de6bSjchu 	/* Check the severity of this error */
258*fc256490SJason Beloro 	rc_err = px_err_epkt_severity(px_p, &derr, epkt, pfd_p);
259*fc256490SJason Beloro 
260*fc256490SJason Beloro 	pfd_p->pe_severity_flags = px_err_to_fab_sev(rc_err);
261*fc256490SJason Beloro 	/*
262*fc256490SJason Beloro 	 * px_err_epkt_severity needs to populate affected dev
263*fc256490SJason Beloro 	 * Only MMU errors and PCIe errors need this.
264*fc256490SJason Beloro 	 * For MMU we will call pf_handle_lookup, using fault bdf
265*fc256490SJason Beloro 	 * - need to call bdf look up..
266*fc256490SJason Beloro 	 * For PCIe do not fill in affected..
267*fc256490SJason Beloro 	 */
268f8d2de6bSjchu 
269bf8fc234Set 	/* Scan the fabric if the root port is not in drain state. */
270eae2e508Skrishnae 	fab_err = px_scan_fabric(px_p, rpdip, &derr);
271f8d2de6bSjchu 
272f8d2de6bSjchu 	/* Set the intr state to idle for the leaf that received the mondo */
273f8d2de6bSjchu 	if (px_lib_intr_setstate(rpdip, fault_p->px_fh_sysino,
2741ff65112Segillett 	    INTR_IDLE_STATE) != DDI_SUCCESS) {
275eae2e508Skrishnae 		px_fm_exit(px_p);
276f8d2de6bSjchu 		return (DDI_INTR_UNCLAIMED);
277f8d2de6bSjchu 	}
278f8d2de6bSjchu 
279bf8fc234Set 	switch (epkt->rc_descr.block) {
280bf8fc234Set 	case BLOCK_MMU: /* FALLTHROUGH */
281bf8fc234Set 	case BLOCK_INTR:
282bf8fc234Set 		msg = PX_RC;
283bf8fc234Set 		break;
284bf8fc234Set 	case BLOCK_PCIE:
285bf8fc234Set 		msg = PX_RP;
286bf8fc234Set 		break;
287bf8fc234Set 	case BLOCK_HOSTBUS: /* FALLTHROUGH */
288bf8fc234Set 	default:
289bf8fc234Set 		msg = PX_HB;
290bf8fc234Set 		break;
291bf8fc234Set 	}
292bf8fc234Set 
293eae2e508Skrishnae 	px_err_panic(rc_err, msg, fab_err, B_TRUE);
294eae2e508Skrishnae 	px_fm_exit(px_p);
295eae2e508Skrishnae 	px_err_panic(rc_err, msg, fab_err, B_FALSE);
296f8d2de6bSjchu 
297eae2e508Skrishnae done:
298f8d2de6bSjchu 	return (DDI_INTR_CLAIMED);
299f8d2de6bSjchu }
300f8d2de6bSjchu 
301f8d2de6bSjchu /*
302bf8fc234Set  * px_err_epkt_severity:
303f8d2de6bSjchu  * Check the severity of the fire error based the epkt received
304f8d2de6bSjchu  *
305f8d2de6bSjchu  * @param px_p		leaf in which to take the snap shot.
306f8d2de6bSjchu  * @param derr		fm err in which the ereport is to be based on
307f8d2de6bSjchu  * @param epkt		epkt recevied from HV
308f8d2de6bSjchu  */
309f8d2de6bSjchu static int
310bf8fc234Set px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt,
311*fc256490SJason Beloro     pf_data_t *pfd_p)
312f8d2de6bSjchu {
313f8d2de6bSjchu 	px_pec_t 	*pec_p = px_p->px_pec_p;
314f8d2de6bSjchu 	dev_info_t	*dip = px_p->px_dip;
315bf8fc234Set 	boolean_t	is_safeacc = B_FALSE;
316bf8fc234Set 	boolean_t	is_block_pci = B_FALSE;
317eae2e508Skrishnae 	boolean_t	is_valid_epkt = B_FALSE;
318f8d2de6bSjchu 	int		err = 0;
319f8d2de6bSjchu 
320f8d2de6bSjchu 	/* Cautious access error handling  */
321bf8fc234Set 	switch (derr->fme_flag) {
322bf8fc234Set 	case DDI_FM_ERR_EXPECTED:
323*fc256490SJason Beloro 		/*
324*fc256490SJason Beloro 		 * For ddi_caut_put treat all events as nonfatal. Here
325*fc256490SJason Beloro 		 * we have the handle and can call ndi_fm_acc_err_set().
326*fc256490SJason Beloro 		 */
327*fc256490SJason Beloro 		derr->fme_status = DDI_FM_NONFATAL;
328*fc256490SJason Beloro 		ndi_fm_acc_err_set(pec_p->pec_acc_hdl, derr);
329*fc256490SJason Beloro 		is_safeacc = B_TRUE;
330bf8fc234Set 		break;
331bf8fc234Set 	case DDI_FM_ERR_PEEK:
332bf8fc234Set 	case DDI_FM_ERR_POKE:
333bf8fc234Set 		/*
334bf8fc234Set 		 * For ddi_peek/poke treat all events as nonfatal.
335bf8fc234Set 		 */
336bf8fc234Set 		is_safeacc = B_TRUE;
337bf8fc234Set 		break;
338bf8fc234Set 	default:
339bf8fc234Set 		is_safeacc = B_FALSE;
340f8d2de6bSjchu 	}
341f8d2de6bSjchu 
342bf8fc234Set 	/*
343bf8fc234Set 	 * Older hypervisors in some cases send epkts with incorrect fields.
344bf8fc234Set 	 * We have to handle these "special" epkts correctly.
345bf8fc234Set 	 */
346bf8fc234Set 	if (px_legacy_epkt)
347bf8fc234Set 		px_fix_legacy_epkt(dip, derr, epkt);
348bf8fc234Set 
349f8d2de6bSjchu 	switch (epkt->rc_descr.block) {
350f8d2de6bSjchu 	case BLOCK_HOSTBUS:
351bf8fc234Set 		err = px_cb_epkt_severity(dip, derr, epkt);
352*fc256490SJason Beloro 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
353f8d2de6bSjchu 		break;
354f8d2de6bSjchu 	case BLOCK_MMU:
355bf8fc234Set 		err = px_mmu_epkt_severity(dip, derr, epkt);
356*fc256490SJason Beloro 		px_err_fill_pfd(dip, pfd_p, epkt);
357f8d2de6bSjchu 		break;
358f8d2de6bSjchu 	case BLOCK_INTR:
359bf8fc234Set 		err = px_intr_epkt_severity(dip, derr, epkt);
360*fc256490SJason Beloro 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
361f8d2de6bSjchu 		break;
3624df55fdeSJanie Lu 	case BLOCK_PORT:
363*fc256490SJason Beloro 		err = px_port_epkt_severity(dip, derr, epkt, pfd_p);
3644df55fdeSJanie Lu 		break;
365f8d2de6bSjchu 	case BLOCK_PCIE:
366bf8fc234Set 		is_block_pci = B_TRUE;
367bf8fc234Set 		err = px_pcie_epkt_severity(dip, derr, epkt);
368*fc256490SJason Beloro 		px_err_fill_pfd(dip, pfd_p, epkt);
369f8d2de6bSjchu 		break;
370f8d2de6bSjchu 	default:
371bf8fc234Set 		err = 0;
372f8d2de6bSjchu 	}
373f8d2de6bSjchu 
374bf8fc234Set 	if ((err & PX_HW_RESET) || (err & PX_PANIC)) {
375bf8fc234Set 		if (px_log & PX_PANIC)
376bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "PANIC");
377eae2e508Skrishnae 		is_valid_epkt = B_TRUE;
378bf8fc234Set 	} else if (err & PX_PROTECTED) {
379bf8fc234Set 		if (px_log & PX_PROTECTED)
380bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "PROTECTED");
381eae2e508Skrishnae 		is_valid_epkt = B_TRUE;
382bf8fc234Set 	} else if (err & PX_NO_PANIC) {
383bf8fc234Set 		if (px_log & PX_NO_PANIC)
384bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "NO PANIC");
385eae2e508Skrishnae 		is_valid_epkt = B_TRUE;
386bf8fc234Set 	} else if (err & PX_NO_ERROR) {
387bf8fc234Set 		if (px_log & PX_NO_ERROR)
388bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "NO ERROR");
389eae2e508Skrishnae 		is_valid_epkt = B_TRUE;
390bf8fc234Set 	} else if (err == 0) {
391bf8fc234Set 		px_err_log_handle(dip, epkt, is_block_pci, "UNRECOGNIZED");
392eae2e508Skrishnae 		is_valid_epkt = B_FALSE;
393bf8fc234Set 
394eae2e508Skrishnae 		/* Panic on a unrecognized epkt */
395bf8fc234Set 		err = PX_PANIC;
396bf8fc234Set 	}
397bf8fc234Set 
398eae2e508Skrishnae 	px_err_send_epkt_erpt(dip, epkt, is_block_pci, err, derr,
399eae2e508Skrishnae 	    is_valid_epkt);
400eae2e508Skrishnae 
401bf8fc234Set 	/* Readjust the severity as a result of safe access */
402bf8fc234Set 	if (is_safeacc && !(err & PX_PANIC) && !(px_die & PX_PROTECTED))
403bf8fc234Set 		err = PX_NO_PANIC;
404bf8fc234Set 
405f8d2de6bSjchu 	return (err);
406f8d2de6bSjchu }
407f8d2de6bSjchu 
408eae2e508Skrishnae static void
409eae2e508Skrishnae px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
410eae2e508Skrishnae     boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
411eae2e508Skrishnae     boolean_t is_valid_epkt)
412eae2e508Skrishnae {
413eae2e508Skrishnae 	char buf[FM_MAX_CLASS], descr_buf[1024];
414eae2e508Skrishnae 
415eae2e508Skrishnae 	/* send ereport for debug purposes */
416eae2e508Skrishnae 	(void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_RC_UNRECOG);
417eae2e508Skrishnae 
418eae2e508Skrishnae 	if (is_block_pci) {
419eae2e508Skrishnae 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
420eae2e508Skrishnae 		(void) snprintf(descr_buf, sizeof (descr_buf),
421eae2e508Skrishnae 		    "%s Epkt contents:\n"
422eae2e508Skrishnae 		    "Block: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d\n"
423eae2e508Skrishnae 		    "I=%d, H=%d, C=%d, U=%d, E=%d, P=%d\n"
424eae2e508Skrishnae 		    "PCI Err Status: 0x%x, PCIe Err Status: 0x%x\n"
425eae2e508Skrishnae 		    "CE Status Reg: 0x%x, UE Status Reg: 0x%x\n"
426eae2e508Skrishnae 		    "HDR1: 0x%lx, HDR2: 0x%lx\n"
427eae2e508Skrishnae 		    "Err Src Reg: 0x%x, Root Err Status: 0x%x\n"
428eae2e508Skrishnae 		    "Err Severity: 0x%x\n",
429eae2e508Skrishnae 		    is_valid_epkt ? "Valid" : "Invalid",
430eae2e508Skrishnae 		    pec->pec_descr.block, pec->pec_descr.dir,
431eae2e508Skrishnae 		    pec->pec_descr.Z, pec->pec_descr.S,
432eae2e508Skrishnae 		    pec->pec_descr.R, pec->pec_descr.I,
433eae2e508Skrishnae 		    pec->pec_descr.H, pec->pec_descr.C,
434eae2e508Skrishnae 		    pec->pec_descr.U, pec->pec_descr.E,
435eae2e508Skrishnae 		    pec->pec_descr.P, pec->pci_err_status,
436eae2e508Skrishnae 		    pec->pcie_err_status, pec->ce_reg_status,
437eae2e508Skrishnae 		    pec->ue_reg_status, pec->hdr[0],
438eae2e508Skrishnae 		    pec->hdr[1], pec->err_src_reg,
439eae2e508Skrishnae 		    pec->root_err_status, err);
440eae2e508Skrishnae 
441eae2e508Skrishnae 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
442eae2e508Skrishnae 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
443eae2e508Skrishnae 		    EPKT_SYSINO, DATA_TYPE_UINT64,
444eae2e508Skrishnae 		    is_valid_epkt ? pec->sysino : 0,
445eae2e508Skrishnae 		    EPKT_EHDL, DATA_TYPE_UINT64,
446eae2e508Skrishnae 		    is_valid_epkt ? pec->ehdl : 0,
447eae2e508Skrishnae 		    EPKT_STICK, DATA_TYPE_UINT64,
448eae2e508Skrishnae 		    is_valid_epkt ? pec->stick : 0,
4494df55fdeSJanie Lu 		    EPKT_DW0, DATA_TYPE_UINT64, ((uint64_t *)pec)[3],
4504df55fdeSJanie Lu 		    EPKT_DW1, DATA_TYPE_UINT64, ((uint64_t *)pec)[4],
4514df55fdeSJanie Lu 		    EPKT_DW2, DATA_TYPE_UINT64, ((uint64_t *)pec)[5],
4524df55fdeSJanie Lu 		    EPKT_DW3, DATA_TYPE_UINT64, ((uint64_t *)pec)[6],
4534df55fdeSJanie Lu 		    EPKT_DW4, DATA_TYPE_UINT64, ((uint64_t *)pec)[7],
454eae2e508Skrishnae 		    EPKT_PEC_DESCR, DATA_TYPE_STRING, descr_buf);
455eae2e508Skrishnae 	} else {
456eae2e508Skrishnae 		(void) snprintf(descr_buf, sizeof (descr_buf),
457eae2e508Skrishnae 		    "%s Epkt contents:\n"
458eae2e508Skrishnae 		    "Block: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
459eae2e508Skrishnae 		    "Dir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d\n"
460eae2e508Skrishnae 		    "M=%d, S=%d, Size: 0x%x, Addr: 0x%lx\n"
461eae2e508Skrishnae 		    "Hdr1: 0x%lx, Hdr2: 0x%lx, Res: 0x%lx\n"
462eae2e508Skrishnae 		    "Err Severity: 0x%x\n",
463eae2e508Skrishnae 		    is_valid_epkt ? "Valid" : "Invalid",
464eae2e508Skrishnae 		    epkt->rc_descr.block, epkt->rc_descr.op,
465eae2e508Skrishnae 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
466eae2e508Skrishnae 		    epkt->rc_descr.dir, epkt->rc_descr.STOP,
467eae2e508Skrishnae 		    epkt->rc_descr.H, epkt->rc_descr.R,
468eae2e508Skrishnae 		    epkt->rc_descr.D, epkt->rc_descr.M,
469eae2e508Skrishnae 		    epkt->rc_descr.S, epkt->size, epkt->addr,
470eae2e508Skrishnae 		    epkt->hdr[0], epkt->hdr[1], epkt->reserved,
471eae2e508Skrishnae 		    err);
472eae2e508Skrishnae 
473eae2e508Skrishnae 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
474eae2e508Skrishnae 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
475eae2e508Skrishnae 		    EPKT_SYSINO, DATA_TYPE_UINT64,
476eae2e508Skrishnae 		    is_valid_epkt ? epkt->sysino : 0,
477eae2e508Skrishnae 		    EPKT_EHDL, DATA_TYPE_UINT64,
478eae2e508Skrishnae 		    is_valid_epkt ? epkt->ehdl : 0,
479eae2e508Skrishnae 		    EPKT_STICK, DATA_TYPE_UINT64,
480eae2e508Skrishnae 		    is_valid_epkt ? epkt->stick : 0,
4814df55fdeSJanie Lu 		    EPKT_DW0, DATA_TYPE_UINT64, ((uint64_t *)epkt)[3],
4824df55fdeSJanie Lu 		    EPKT_DW1, DATA_TYPE_UINT64, ((uint64_t *)epkt)[4],
4834df55fdeSJanie Lu 		    EPKT_DW2, DATA_TYPE_UINT64, ((uint64_t *)epkt)[5],
4844df55fdeSJanie Lu 		    EPKT_DW3, DATA_TYPE_UINT64, ((uint64_t *)epkt)[6],
4854df55fdeSJanie Lu 		    EPKT_DW4, DATA_TYPE_UINT64, ((uint64_t *)epkt)[7],
486eae2e508Skrishnae 		    EPKT_RC_DESCR, DATA_TYPE_STRING, descr_buf);
487eae2e508Skrishnae 	}
488eae2e508Skrishnae }
489eae2e508Skrishnae 
490bf8fc234Set static void
491bf8fc234Set px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt, boolean_t is_block_pci,
492bf8fc234Set     char *msg)
493bf8fc234Set {
494bf8fc234Set 	if (is_block_pci) {
495bf8fc234Set 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
496bf8fc234Set 		DBG(DBG_ERR_INTR, dip,
497bf8fc234Set 		    "A PCIe root port error has occured with a severity"
498bf8fc234Set 		    " \"%s\"\n"
499bf8fc234Set 		    "\tBlock: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d, I=%d\n"
500bf8fc234Set 		    "\tH=%d, C=%d, U=%d, E=%d, P=%d\n"
501bf8fc234Set 		    "\tpci_err: 0x%x, pcie_err=0x%x, ce_reg: 0x%x\n"
502bf8fc234Set 		    "\tue_reg: 0x%x, Hdr1: 0x%p, Hdr2: 0x%p\n"
503bf8fc234Set 		    "\terr_src: 0x%x, root_err: 0x%x\n",
504bf8fc234Set 		    msg, pec->pec_descr.block, pec->pec_descr.dir,
505bf8fc234Set 		    pec->pec_descr.Z, pec->pec_descr.S, pec->pec_descr.R,
506bf8fc234Set 		    pec->pec_descr.I, pec->pec_descr.H, pec->pec_descr.C,
507bf8fc234Set 		    pec->pec_descr.U, pec->pec_descr.E, pec->pec_descr.P,
508bf8fc234Set 		    pec->pci_err_status, pec->pcie_err_status,
509bf8fc234Set 		    pec->ce_reg_status, pec->ue_reg_status, pec->hdr[0],
510bf8fc234Set 		    pec->hdr[1], pec->err_src_reg, pec->root_err_status);
511bf8fc234Set 	} else {
512bf8fc234Set 		DBG(DBG_ERR_INTR, dip,
513bf8fc234Set 		    "A PCIe root complex error has occured with a severity"
514bf8fc234Set 		    " \"%s\"\n"
515bf8fc234Set 		    "\tBlock: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
516bf8fc234Set 		    "\tDir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d, M=%d\n"
517bf8fc234Set 		    "\tS=%d, Size: 0x%x, Addr: 0x%p\n"
518bf8fc234Set 		    "\tHdr1: 0x%p, Hdr2: 0x%p, Res: 0x%p\n",
519bf8fc234Set 		    msg, epkt->rc_descr.block, epkt->rc_descr.op,
520bf8fc234Set 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
521bf8fc234Set 		    epkt->rc_descr.dir, epkt->rc_descr.STOP, epkt->rc_descr.H,
522bf8fc234Set 		    epkt->rc_descr.R, epkt->rc_descr.D, epkt->rc_descr.M,
523bf8fc234Set 		    epkt->rc_descr.S, epkt->size, epkt->addr, epkt->hdr[0],
524bf8fc234Set 		    epkt->hdr[1], epkt->reserved);
525bf8fc234Set 	}
526bf8fc234Set }
527bf8fc234Set 
528f8d2de6bSjchu /* ARGSUSED */
529bf8fc234Set static void
530bf8fc234Set px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
531f8d2de6bSjchu {
532bf8fc234Set 	/*
533bf8fc234Set 	 * We don't have a default case for any of the below switch statements
534bf8fc234Set 	 * since we are ok with the code falling through.
535bf8fc234Set 	 */
536bf8fc234Set 	switch (epkt->rc_descr.block) {
537bf8fc234Set 	case BLOCK_HOSTBUS:
538bf8fc234Set 		switch (epkt->rc_descr.op) {
539bf8fc234Set 		case OP_DMA:
540bf8fc234Set 			switch (epkt->rc_descr.phase) {
541bf8fc234Set 			case PH_UNKNOWN:
542bf8fc234Set 				switch (epkt->rc_descr.cond) {
543bf8fc234Set 				case CND_UNKNOWN:
544bf8fc234Set 					switch (epkt->rc_descr.dir) {
545bf8fc234Set 					case DIR_RESERVED:
546bf8fc234Set 						epkt->rc_descr.dir = DIR_READ;
547bf8fc234Set 						break;
548bf8fc234Set 					} /* DIR */
549bf8fc234Set 				} /* CND */
550bf8fc234Set 			} /* PH */
551bf8fc234Set 		} /* OP */
552f8d2de6bSjchu 		break;
553bf8fc234Set 	case BLOCK_MMU:
554bf8fc234Set 		switch (epkt->rc_descr.op) {
555bf8fc234Set 		case OP_XLAT:
556bf8fc234Set 			switch (epkt->rc_descr.phase) {
557bf8fc234Set 			case PH_DATA:
558bf8fc234Set 				switch (epkt->rc_descr.cond) {
559bf8fc234Set 				case CND_PROT:
560bf8fc234Set 					switch (epkt->rc_descr.dir) {
561bf8fc234Set 					case DIR_UNKNOWN:
562bf8fc234Set 						epkt->rc_descr.dir = DIR_WRITE;
563bf8fc234Set 						break;
564bf8fc234Set 					} /* DIR */
565bf8fc234Set 				} /* CND */
5663d9c56a1Set 				break;
567bf8fc234Set 			case PH_IRR:
568bf8fc234Set 				switch (epkt->rc_descr.cond) {
569bf8fc234Set 				case CND_RESERVED:
570bf8fc234Set 					switch (epkt->rc_descr.dir) {
571bf8fc234Set 					case DIR_IRR:
572bf8fc234Set 						epkt->rc_descr.phase = PH_ADDR;
573bf8fc234Set 						epkt->rc_descr.cond = CND_IRR;
574bf8fc234Set 					} /* DIR */
575bf8fc234Set 				} /* CND */
576bf8fc234Set 			} /* PH */
577bf8fc234Set 		} /* OP */
578e51949e6Sdduvall 		break;
579bf8fc234Set 	case BLOCK_INTR:
580bf8fc234Set 		switch (epkt->rc_descr.op) {
581bf8fc234Set 		case OP_MSIQ:
582bf8fc234Set 			switch (epkt->rc_descr.phase) {
583bf8fc234Set 			case PH_UNKNOWN:
584bf8fc234Set 				switch (epkt->rc_descr.cond) {
585bf8fc234Set 				case CND_ILL:
586bf8fc234Set 					switch (epkt->rc_descr.dir) {
587bf8fc234Set 					case DIR_RESERVED:
588bf8fc234Set 						epkt->rc_descr.dir = DIR_IRR;
589bf8fc234Set 						break;
590bf8fc234Set 					} /* DIR */
591bf8fc234Set 					break;
592bf8fc234Set 				case CND_IRR:
593bf8fc234Set 					switch (epkt->rc_descr.dir) {
594bf8fc234Set 					case DIR_IRR:
595bf8fc234Set 						epkt->rc_descr.cond = CND_OV;
596bf8fc234Set 						break;
597bf8fc234Set 					} /* DIR */
598bf8fc234Set 				} /* CND */
599bf8fc234Set 			} /* PH */
600bf8fc234Set 			break;
601bf8fc234Set 		case OP_RESERVED:
602bf8fc234Set 			switch (epkt->rc_descr.phase) {
603bf8fc234Set 			case PH_UNKNOWN:
604bf8fc234Set 				switch (epkt->rc_descr.cond) {
605bf8fc234Set 				case CND_ILL:
606bf8fc234Set 					switch (epkt->rc_descr.dir) {
607bf8fc234Set 					case DIR_IRR:
608bf8fc234Set 						epkt->rc_descr.op = OP_MSI32;
609bf8fc234Set 						epkt->rc_descr.phase = PH_DATA;
610bf8fc234Set 						break;
611bf8fc234Set 					} /* DIR */
612bf8fc234Set 				} /* CND */
613bf8fc234Set 				break;
614bf8fc234Set 			case PH_DATA:
615bf8fc234Set 				switch (epkt->rc_descr.cond) {
616bf8fc234Set 				case CND_INT:
617bf8fc234Set 					switch (epkt->rc_descr.dir) {
618bf8fc234Set 					case DIR_UNKNOWN:
619bf8fc234Set 						epkt->rc_descr.op = OP_MSI32;
620bf8fc234Set 						break;
621bf8fc234Set 					} /* DIR */
622bf8fc234Set 				} /* CND */
623bf8fc234Set 			} /* PH */
624bf8fc234Set 		} /* OP */
625bf8fc234Set 	} /* BLOCK */
626bf8fc234Set }
6273d9c56a1Set 
628bf8fc234Set /* ARGSUSED */
629bf8fc234Set static int
630bf8fc234Set px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
631bf8fc234Set {
632bf8fc234Set 	return (px_err_check_eq(dip));
633bf8fc234Set }
634bf8fc234Set 
6354df55fdeSJanie Lu /* ARGSUSED */
6364df55fdeSJanie Lu static int
637*fc256490SJason Beloro px_port_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt,
638*fc256490SJason Beloro     pf_data_t *pfd_p)
6394df55fdeSJanie Lu {
6404df55fdeSJanie Lu 	pf_pcie_adv_err_regs_t	adv_reg;
6414df55fdeSJanie Lu 	uint16_t		s_status;
6424df55fdeSJanie Lu 	int			sts = PX_PANIC;
6434df55fdeSJanie Lu 
6444df55fdeSJanie Lu 	/*
6454df55fdeSJanie Lu 	 * Check for failed non-posted writes, which are errors that are not
6464df55fdeSJanie Lu 	 * defined in the PCIe spec.  If not return panic.
6474df55fdeSJanie Lu 	 */
6484df55fdeSJanie Lu 	if (!((epkt->rc_descr.op == OP_PIO) &&
6494df55fdeSJanie Lu 	    (epkt->rc_descr.phase == PH_IRR))) {
6504df55fdeSJanie Lu 		sts = (PX_PANIC);
651*fc256490SJason Beloro 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
6524df55fdeSJanie Lu 		goto done;
6534df55fdeSJanie Lu 	}
6544df55fdeSJanie Lu 
6554df55fdeSJanie Lu 	/*
6564df55fdeSJanie Lu 	 * Gather the error logs, if they do not exist just return with no panic
6574df55fdeSJanie Lu 	 * and let the fabric message take care of the error.
6584df55fdeSJanie Lu 	 */
6594df55fdeSJanie Lu 	if (!epkt->rc_descr.H) {
6604df55fdeSJanie Lu 		sts = (PX_NO_PANIC);
6614df55fdeSJanie Lu 		goto done;
6624df55fdeSJanie Lu 	}
6634df55fdeSJanie Lu 
6644df55fdeSJanie Lu 	adv_reg.pcie_ue_hdr[0] = (uint32_t)(epkt->hdr[0]);
6654df55fdeSJanie Lu 	adv_reg.pcie_ue_hdr[1] = (uint32_t)(epkt->hdr[0] >> 32);
6664df55fdeSJanie Lu 	adv_reg.pcie_ue_hdr[2] = (uint32_t)(epkt->hdr[1]);
6674df55fdeSJanie Lu 	adv_reg.pcie_ue_hdr[3] = (uint32_t)(epkt->hdr[1] >> 32);
6684df55fdeSJanie Lu 
6694df55fdeSJanie Lu 	sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
6704df55fdeSJanie Lu 
6714df55fdeSJanie Lu 	if (epkt->rc_descr.M)
6724df55fdeSJanie Lu 		adv_reg.pcie_ue_tgt_addr = epkt->addr;
6734df55fdeSJanie Lu 
6744df55fdeSJanie Lu 	if (!((sts == DDI_SUCCESS) || (epkt->rc_descr.M))) {
6754df55fdeSJanie Lu 		/* Let the fabric message take care of error */
6764df55fdeSJanie Lu 		sts = PX_NO_PANIC;
6774df55fdeSJanie Lu 		goto done;
6784df55fdeSJanie Lu 	}
6794df55fdeSJanie Lu 
6804df55fdeSJanie Lu 	/* See if the failed transaction belonged to a hardened driver */
6814df55fdeSJanie Lu 	if (pf_hdl_lookup(dip, derr->fme_ena,
6824df55fdeSJanie Lu 	    adv_reg.pcie_ue_tgt_trans, adv_reg.pcie_ue_tgt_addr,
6834df55fdeSJanie Lu 	    adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
6844df55fdeSJanie Lu 		sts = (PX_NO_PANIC);
6854df55fdeSJanie Lu 	else
6864df55fdeSJanie Lu 		sts = (PX_PANIC);
6874df55fdeSJanie Lu 
6884df55fdeSJanie Lu 	/* Add pfd to cause a fabric scan */
6894df55fdeSJanie Lu 	switch (epkt->rc_descr.cond) {
6904df55fdeSJanie Lu 	case CND_RCA:
6914df55fdeSJanie Lu 		s_status = PCI_STAT_R_TARG_AB;
6924df55fdeSJanie Lu 		break;
6934df55fdeSJanie Lu 	case CND_RUR:
6944df55fdeSJanie Lu 		s_status = PCI_STAT_R_MAST_AB;
6954df55fdeSJanie Lu 		break;
6964df55fdeSJanie Lu 	}
697*fc256490SJason Beloro 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = adv_reg.pcie_ue_tgt_bdf;
698*fc256490SJason Beloro 	PCIE_ROOT_FAULT(pfd_p)->scan_addr = adv_reg.pcie_ue_tgt_addr;
699*fc256490SJason Beloro 	PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
7004df55fdeSJanie Lu 
7014df55fdeSJanie Lu done:
7024df55fdeSJanie Lu 	return (sts);
7034df55fdeSJanie Lu }
7044df55fdeSJanie Lu 
705bf8fc234Set /* ARGSUSED */
706bf8fc234Set static int
707bf8fc234Set px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
708bf8fc234Set {
709eae2e508Skrishnae 	px_pec_err_t	*pec_p = (px_pec_err_t *)epkt;
710bf8fc234Set 	px_err_pcie_t	*pcie = (px_err_pcie_t *)epkt;
711eae2e508Skrishnae 	pf_pcie_adv_err_regs_t adv_reg;
712eae2e508Skrishnae 	int		sts;
713bf8fc234Set 	uint32_t	temp;
714f8d2de6bSjchu 
715f8d2de6bSjchu 	/*
716bf8fc234Set 	 * Check for failed PIO Read/Writes, which are errors that are not
717bf8fc234Set 	 * defined in the PCIe spec.
718f8d2de6bSjchu 	 */
719bf8fc234Set 	temp = PCIE_AER_UCE_UR | PCIE_AER_UCE_CA;
720eae2e508Skrishnae 	if (((pec_p->pec_descr.dir == DIR_READ) ||
721eae2e508Skrishnae 	    (pec_p->pec_descr.dir == DIR_WRITE)) &&
722eae2e508Skrishnae 	    pec_p->pec_descr.U && (pec_p->ue_reg_status & temp)) {
723eae2e508Skrishnae 		adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0]);
724eae2e508Skrishnae 		adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0] >> 32);
725eae2e508Skrishnae 		adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1]);
726eae2e508Skrishnae 		adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1] >> 32);
727eae2e508Skrishnae 
728eae2e508Skrishnae 		sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
729eae2e508Skrishnae 
730eae2e508Skrishnae 		if (sts == DDI_SUCCESS &&
731eae2e508Skrishnae 		    pf_hdl_lookup(dip, derr->fme_ena,
732eae2e508Skrishnae 		    adv_reg.pcie_ue_tgt_trans,
733eae2e508Skrishnae 		    adv_reg.pcie_ue_tgt_addr,
734eae2e508Skrishnae 		    adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
735bf8fc234Set 			return (PX_NO_PANIC);
736f8d2de6bSjchu 		else
737bf8fc234Set 			return (PX_PANIC);
738f8d2de6bSjchu 	}
739f8d2de6bSjchu 
740eae2e508Skrishnae 	if (!pec_p->pec_descr.C)
741eae2e508Skrishnae 		pec_p->ce_reg_status = 0;
742eae2e508Skrishnae 	if (!pec_p->pec_descr.U)
743eae2e508Skrishnae 		pec_p->ue_reg_status = 0;
744eae2e508Skrishnae 	if (!pec_p->pec_descr.H)
745eae2e508Skrishnae 		pec_p->hdr[0] = 0;
746eae2e508Skrishnae 	if (!pec_p->pec_descr.I)
747eae2e508Skrishnae 		pec_p->hdr[1] = 0;
748f8d2de6bSjchu 
749bf8fc234Set 	/*
750bf8fc234Set 	 * According to the PCIe spec, there is a first error pointer.  If there
751bf8fc234Set 	 * are header logs recorded and there are more than one error, the log
752bf8fc234Set 	 * will belong to the error that the first error pointer points to.
753bf8fc234Set 	 *
754bf8fc234Set 	 * The regs.primary_ue expects a bit number, go through the ue register
755bf8fc234Set 	 * and find the first error that occured.  Because the sun4v epkt spec
756bf8fc234Set 	 * does not define this value, the algorithm below gives the lower bit
757bf8fc234Set 	 * priority.
758bf8fc234Set 	 */
759bf8fc234Set 	temp = pcie->ue_reg;
760bf8fc234Set 	if (temp) {
761eae2e508Skrishnae 		int x;
762bf8fc234Set 		for (x = 0; !(temp & 0x1); x++) {
763bf8fc234Set 			temp = temp >> 1;
764bf8fc234Set 		}
765bf8fc234Set 		pcie->primary_ue = 1 << x;
766bf8fc234Set 	} else {
767bf8fc234Set 		pcie->primary_ue = 0;
7683d9c56a1Set 	}
769f8d2de6bSjchu 
770bf8fc234Set 	/* Sun4v doesn't log the TX hdr except for CTOs */
771bf8fc234Set 	if (pcie->primary_ue == PCIE_AER_UCE_TO) {
772bf8fc234Set 		pcie->tx_hdr1 = pcie->rx_hdr1;
773bf8fc234Set 		pcie->tx_hdr2 = pcie->rx_hdr2;
774bf8fc234Set 		pcie->tx_hdr3 = pcie->rx_hdr3;
775bf8fc234Set 		pcie->tx_hdr4 = pcie->rx_hdr4;
776bf8fc234Set 		pcie->rx_hdr1 = 0;
777bf8fc234Set 		pcie->rx_hdr2 = 0;
778bf8fc234Set 		pcie->rx_hdr3 = 0;
779bf8fc234Set 		pcie->rx_hdr4 = 0;
780bf8fc234Set 	} else {
781bf8fc234Set 		pcie->tx_hdr1 = 0;
782bf8fc234Set 		pcie->tx_hdr2 = 0;
783bf8fc234Set 		pcie->tx_hdr3 = 0;
784bf8fc234Set 		pcie->tx_hdr4 = 0;
785bf8fc234Set 	}
786e51949e6Sdduvall 
787bf8fc234Set 	return (px_err_check_pcie(dip, derr, pcie));
788f8d2de6bSjchu }
789f8d2de6bSjchu 
790f8d2de6bSjchu static int
791bf8fc234Set px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
792f8d2de6bSjchu {
793eae2e508Skrishnae 	uint64_t addr = (uint64_t)epkt->addr;
794c85864d8SKrishna Elango 	pcie_req_id_t bdf = PCIE_INVALID_BDF;
795f8d2de6bSjchu 
796bf8fc234Set 	if (epkt->rc_descr.H) {
797bf8fc234Set 		bdf = (uint32_t)((epkt->hdr[0] >> 16) && 0xFFFF);
798f8d2de6bSjchu 	}
799f8d2de6bSjchu 
800eae2e508Skrishnae 	return (pf_hdl_lookup(dip, derr->fme_ena, PF_ADDR_DMA, addr,
8011ff65112Segillett 	    bdf));
802f8d2de6bSjchu }
803