xref: /illumos-gate/usr/src/uts/sun4v/io/px/px_err.c (revision e214b19e)
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 /*
22d0f40dc6SKrishna Elango  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23f8d2de6bSjchu  */
24f8d2de6bSjchu 
25f8d2de6bSjchu /*
26f8d2de6bSjchu  * sun4v Fire Error Handling
27f8d2de6bSjchu  */
28f8d2de6bSjchu 
29f8d2de6bSjchu #include <sys/types.h>
30f8d2de6bSjchu #include <sys/ddi.h>
31f8d2de6bSjchu #include <sys/sunddi.h>
32eae2e508Skrishnae #include <sys/sunndi.h>
33f8d2de6bSjchu #include <sys/fm/protocol.h>
34f8d2de6bSjchu #include <sys/fm/util.h>
35f8d2de6bSjchu #include <sys/membar.h>
36f8d2de6bSjchu #include "px_obj.h"
37f8d2de6bSjchu #include "px_err.h"
38f8d2de6bSjchu 
39fc256490SJason Beloro static void px_err_fill_pfd(dev_info_t *dip, pf_data_t *pfd_p,
40fc256490SJason Beloro     px_rc_err_t *epkt);
41bf8fc234Set static uint_t px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt);
42bf8fc234Set static int  px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr,
43fc256490SJason Beloro     px_rc_err_t *epkt, pf_data_t *pfd_p);
44f8d2de6bSjchu 
45bf8fc234Set static void px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt,
46bf8fc234Set     boolean_t is_block_pci, char *msg);
47eae2e508Skrishnae static void px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
48eae2e508Skrishnae     boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
49eae2e508Skrishnae     boolean_t is_valid_epkt);
50bf8fc234Set static int px_cb_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
51d0f40dc6SKrishna Elango     px_rc_err_t *epkt, pf_data_t *pfd_p);
52bf8fc234Set static int px_mmu_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
53d0f40dc6SKrishna Elango     px_rc_err_t *epkt, pf_data_t *pfd_p);
54bf8fc234Set static int px_intr_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
55d0f40dc6SKrishna Elango     px_rc_err_t *epkt, pf_data_t *pfd_p);
564df55fdeSJanie Lu static int px_port_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
57fc256490SJason Beloro     px_rc_err_t *epkt, pf_data_t *pfd_p);
58bf8fc234Set static int px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
59d0f40dc6SKrishna Elango     px_rc_err_t *epkt, pf_data_t *pfd_p);
60bf8fc234Set static int px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
61d0f40dc6SKrishna Elango     px_rc_err_t *epkt, pf_data_t *pfd_p);
624df55fdeSJanie Lu static int px_port_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
63fc256490SJason Beloro     px_rc_err_t *epkt, pf_data_t *pfd_p);
64bf8fc234Set static void px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr,
65bf8fc234Set     px_rc_err_t *epkt);
66bf8fc234Set static int px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr,
67bf8fc234Set     px_rc_err_t *epkt);
68bf8fc234Set 
69bf8fc234Set /* Include the code generated sun4v epkt checking code */
70bf8fc234Set #include "px_err_gen.c"
71bf8fc234Set 
72bf8fc234Set /*
73bf8fc234Set  * This variable indicates if we have a hypervisor that could potentially send
74bf8fc234Set  * incorrect epkts. We always set this to TRUE for now until we find a way to
75bf8fc234Set  * tell if this HV bug has been fixed.
76bf8fc234Set  */
77bf8fc234Set boolean_t px_legacy_epkt = B_TRUE;
78f8d2de6bSjchu 
79f8d2de6bSjchu /*
80f8d2de6bSjchu  * px_err_cb_intr:
81f8d2de6bSjchu  * Interrupt handler for the Host Bus Block.
82f8d2de6bSjchu  */
83f8d2de6bSjchu uint_t
px_err_cb_intr(caddr_t arg)84f8d2de6bSjchu px_err_cb_intr(caddr_t arg)
85f8d2de6bSjchu {
86f8d2de6bSjchu 	px_fault_t	*fault_p = (px_fault_t *)arg;
87f8d2de6bSjchu 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
88f8d2de6bSjchu 
89f8d2de6bSjchu 	if (epkt != NULL) {
90bf8fc234Set 		return (px_err_intr(fault_p, epkt));
91f8d2de6bSjchu 	}
92f8d2de6bSjchu 
93f8d2de6bSjchu 	return (DDI_INTR_UNCLAIMED);
94f8d2de6bSjchu }
95f8d2de6bSjchu 
96f8d2de6bSjchu /*
97f8d2de6bSjchu  * px_err_dmc_pec_intr:
98f8d2de6bSjchu  * Interrupt handler for the DMC/PEC block.
99f8d2de6bSjchu  */
100f8d2de6bSjchu uint_t
px_err_dmc_pec_intr(caddr_t arg)101f8d2de6bSjchu px_err_dmc_pec_intr(caddr_t arg)
102f8d2de6bSjchu {
103f8d2de6bSjchu 	px_fault_t	*fault_p = (px_fault_t *)arg;
104f8d2de6bSjchu 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
105f8d2de6bSjchu 
106f8d2de6bSjchu 	if (epkt != NULL) {
107bf8fc234Set 		return (px_err_intr(fault_p, epkt));
108f8d2de6bSjchu 	}
109f8d2de6bSjchu 
110f8d2de6bSjchu 	return (DDI_INTR_UNCLAIMED);
111f8d2de6bSjchu }
112f8d2de6bSjchu 
113f8d2de6bSjchu /*
114bf8fc234Set  * px_err_cmn_intr:
115f8d2de6bSjchu  * Common function called by trap, mondo and fabric intr.
116f8d2de6bSjchu  * This function is more meaningful in sun4u implementation.  Kept
117f8d2de6bSjchu  * to mirror sun4u call stack.
118f8d2de6bSjchu  * o check for safe access
119bf8fc234Set  * o create and queue RC info for later use in fabric scan.
120bf8fc234Set  *   o RUC/WUC, PTLP, MMU Errors(CA), UR
121f8d2de6bSjchu  *
122f8d2de6bSjchu  * @param px_p		leaf in which to check access
123f8d2de6bSjchu  * @param derr		fm err data structure to be updated
124f8d2de6bSjchu  * @param caller	PX_TRAP_CALL | PX_INTR_CALL
125f8d2de6bSjchu  * @param chkjbc	whether to handle hostbus registers (ignored)
126bf8fc234Set  * @return err		PX_NO_PANIC | PX_PROTECTED |
127bf8fc234Set  *                      PX_PANIC | PX_HW_RESET | PX_EXPECTED
128f8d2de6bSjchu  */
129f8d2de6bSjchu /* ARGSUSED */
130f8d2de6bSjchu int
px_err_cmn_intr(px_t * px_p,ddi_fm_error_t * derr,int caller,int block)131bf8fc234Set px_err_cmn_intr(px_t *px_p, ddi_fm_error_t *derr, int caller, int block)
132f8d2de6bSjchu {
133f8d2de6bSjchu 	px_err_safeacc_check(px_p, derr);
1345613d828SKrishna Elango 	return (PX_NO_ERROR);
1353d9c56a1Set }
1363d9c56a1Set 
1373d9c56a1Set /*
138bf8fc234Set  * fills RC specific fault data
139bf8fc234Set  */
140bf8fc234Set static void
px_err_fill_pfd(dev_info_t * dip,pf_data_t * pfd_p,px_rc_err_t * epkt)141fc256490SJason Beloro px_err_fill_pfd(dev_info_t *dip, pf_data_t *pfd_p, px_rc_err_t *epkt) {
142eae2e508Skrishnae 	pf_pcie_adv_err_regs_t adv_reg;
143c85864d8SKrishna Elango 	pcie_req_id_t	fault_bdf = PCIE_INVALID_BDF;
144eae2e508Skrishnae 	uint64_t	fault_addr = 0;
145bf8fc234Set 	uint16_t	s_status = 0;
146d0f40dc6SKrishna Elango 	px_pec_err_t	*pec_p;
147d0f40dc6SKrishna Elango 	uint32_t	dir;
148bf8fc234Set 
149bf8fc234Set 	/* Add an PCIE PF_DATA Entry */
150d0f40dc6SKrishna Elango 	switch (epkt->rc_descr.block) {
151d0f40dc6SKrishna Elango 	case BLOCK_MMU:
152bf8fc234Set 		/* Only PIO Fault Addresses are valid, this is DMA */
153bf8fc234Set 		s_status = PCI_STAT_S_TARG_AB;
154*e214b19eSToomas Soome 		fault_addr = 0;
155bf8fc234Set 
156fc256490SJason Beloro 		if (epkt->rc_descr.H) {
157bf8fc234Set 			fault_bdf = (pcie_req_id_t)(epkt->hdr[0] >> 16);
158fc256490SJason Beloro 			PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags =
159fc256490SJason Beloro 			    PF_AFFECTED_BDF;
160fc256490SJason Beloro 			PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf =
161fc256490SJason Beloro 			    fault_bdf;
1625613d828SKrishna Elango 		}
163d0f40dc6SKrishna Elango 		break;
164d0f40dc6SKrishna Elango 	case BLOCK_PCIE:
165d0f40dc6SKrishna Elango 		pec_p = (px_pec_err_t *)epkt;
166d0f40dc6SKrishna Elango 		dir = pec_p->pec_descr.dir;
167bf8fc234Set 
168bf8fc234Set 		/* translate RC UR/CA to legacy secondary errors */
169bf8fc234Set 		if ((dir == DIR_READ || dir == DIR_WRITE) &&
170bf8fc234Set 		    pec_p->pec_descr.U) {
171bf8fc234Set 			if (pec_p->ue_reg_status & PCIE_AER_UCE_UR)
172bf8fc234Set 				s_status |= PCI_STAT_R_MAST_AB;
1731ff65112Segillett 			if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
174bf8fc234Set 				s_status |= PCI_STAT_R_TARG_AB;
175bf8fc234Set 		}
176bf8fc234Set 
177bf8fc234Set 		if (pec_p->ue_reg_status & PCIE_AER_UCE_PTLP)
178bf8fc234Set 			s_status |= PCI_STAT_PERROR;
179bf8fc234Set 
180bf8fc234Set 		if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
181bf8fc234Set 			s_status |= PCI_STAT_S_TARG_AB;
182bf8fc234Set 
1835613d828SKrishna Elango 		if (pec_p->pec_descr.H) {
1845613d828SKrishna Elango 			adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0] >>32);
1855613d828SKrishna Elango 			adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0]);
1865613d828SKrishna Elango 			adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1] >>32);
1875613d828SKrishna Elango 			adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1]);
1885613d828SKrishna Elango 
1895613d828SKrishna Elango 			if (pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg) ==
1905613d828SKrishna Elango 			    DDI_SUCCESS) {
1915613d828SKrishna Elango 				fault_bdf = adv_reg.pcie_ue_tgt_bdf;
1925613d828SKrishna Elango 				fault_addr = adv_reg.pcie_ue_tgt_addr;
1935613d828SKrishna Elango 				/*
1945613d828SKrishna Elango 				 * affected BDF is to be filled in by
1955613d828SKrishna Elango 				 * px_scan_fabric
1965613d828SKrishna Elango 				 */
1975613d828SKrishna Elango 			}
1985613d828SKrishna Elango 		}
199d0f40dc6SKrishna Elango 		break;
200d0f40dc6SKrishna Elango 	case BLOCK_HOSTBUS:
201d0f40dc6SKrishna Elango 	case BLOCK_INTR:
202d0f40dc6SKrishna Elango 	case BLOCK_PORT:
203d0f40dc6SKrishna Elango 		/*
204d0f40dc6SKrishna Elango 		 *  If the affected device information is available then we
205d0f40dc6SKrishna Elango 		 *  add the affected_bdf to the pfd, so the affected device
206d0f40dc6SKrishna Elango 		 *  will be scanned and added to the error q. This will then
207d0f40dc6SKrishna Elango 		 *  go through the pciev_eh code path and forgive the error
208d0f40dc6SKrishna Elango 		 *  as needed.
209d0f40dc6SKrishna Elango 		 */
210d0f40dc6SKrishna Elango 		if (PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags ==
211d0f40dc6SKrishna Elango 		    PF_AFFECTED_BDF)
212d0f40dc6SKrishna Elango 			fault_bdf = PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf;
213d0f40dc6SKrishna Elango 
214d0f40dc6SKrishna Elango 		break;
215d0f40dc6SKrishna Elango 	default:
216d0f40dc6SKrishna Elango 		break;
217fc256490SJason Beloro 	}
218fc256490SJason Beloro 
2195613d828SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = fault_bdf;
2205613d828SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p)->scan_addr = (uint64_t)fault_addr;
2215613d828SKrishna Elango 	PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
222fc256490SJason Beloro }
223fc256490SJason Beloro 
224fc256490SJason Beloro /*
225fc256490SJason Beloro  * Convert error severity from PX internal values to PCIe Fabric values.  Most
226fc256490SJason Beloro  * are self explanitory, except PX_PROTECTED.  PX_PROTECTED will never be
227fc256490SJason Beloro  * returned as is if forgivable.
228fc256490SJason Beloro  */
229d0f40dc6SKrishna Elango static int
px_err_to_fab_sev(int * rc_err)230d0f40dc6SKrishna Elango px_err_to_fab_sev(int *rc_err) {
231fc256490SJason Beloro 	int fab_err = 0;
232fc256490SJason Beloro 
233d0f40dc6SKrishna Elango 	if (*rc_err & px_die) {
234d0f40dc6SKrishna Elango 		/*
235d0f40dc6SKrishna Elango 		 * Let fabric scan decide the final severity of the error.
236d0f40dc6SKrishna Elango 		 * This is needed incase IOV code needs to forgive the error.
237d0f40dc6SKrishna Elango 		 */
238d0f40dc6SKrishna Elango 		*rc_err = PX_FABRIC_SCAN;
239fc256490SJason Beloro 		fab_err |= PF_ERR_PANIC;
240d0f40dc6SKrishna Elango 	}
241fc256490SJason Beloro 
242d0f40dc6SKrishna Elango 	if (*rc_err & (PX_EXPECTED | PX_NO_PANIC))
243d0f40dc6SKrishna Elango 		fab_err |= PF_ERR_NO_PANIC;
244d0f40dc6SKrishna Elango 
245d0f40dc6SKrishna Elango 	if (*rc_err & PX_NO_ERROR)
246fc256490SJason Beloro 		fab_err |= PF_ERR_NO_ERROR;
247fc256490SJason Beloro 
248fc256490SJason Beloro 	return (fab_err);
249bf8fc234Set }
250bf8fc234Set 
251bf8fc234Set /*
252bf8fc234Set  * px_err_intr:
253f8d2de6bSjchu  * Interrupt handler for the JBC/DMC/PEC block.
254f8d2de6bSjchu  * o lock
255f8d2de6bSjchu  * o create derr
256f8d2de6bSjchu  * o check safe access
257bf8fc234Set  * o px_err_check_severity(epkt)
258bf8fc234Set  * o pcie_scan_fabric
259f8d2de6bSjchu  * o Idle intr state
260f8d2de6bSjchu  * o unlock
261f8d2de6bSjchu  * o handle error: fatal? fm_panic() : return INTR_CLAIMED)
262f8d2de6bSjchu  */
263f8d2de6bSjchu static uint_t
px_err_intr(px_fault_t * fault_p,px_rc_err_t * epkt)264bf8fc234Set px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt)
265f8d2de6bSjchu {
266f8d2de6bSjchu 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip);
267f8d2de6bSjchu 	dev_info_t	*rpdip = px_p->px_dip;
268d0f40dc6SKrishna Elango 	int		rc_err, tmp_rc_err, fab_err, msg;
269f8d2de6bSjchu 	ddi_fm_error_t	derr;
270fc256490SJason Beloro 	pf_data_t	*pfd_p;
271f8d2de6bSjchu 
272eae2e508Skrishnae 	if (px_fm_enter(px_p) != DDI_SUCCESS)
273eae2e508Skrishnae 		goto done;
274f8d2de6bSjchu 
275fc256490SJason Beloro 	pfd_p = px_get_pfd(px_p);
276fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_INTERNAL;
277fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p)->intr_data = epkt;
278fc256490SJason Beloro 
279f8d2de6bSjchu 	/* Create the derr */
280f8d2de6bSjchu 	bzero(&derr, sizeof (ddi_fm_error_t));
281f8d2de6bSjchu 	derr.fme_version = DDI_FME_VERSION;
282f8d2de6bSjchu 	derr.fme_ena = fm_ena_generate(epkt->stick, FM_ENA_FMT1);
283f8d2de6bSjchu 	derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
284f8d2de6bSjchu 
285f8d2de6bSjchu 	/* Basically check for safe access */
286bf8fc234Set 	(void) px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_ALL);
287f8d2de6bSjchu 
288f8d2de6bSjchu 	/* Check the severity of this error */
289fc256490SJason Beloro 	rc_err = px_err_epkt_severity(px_p, &derr, epkt, pfd_p);
290fc256490SJason Beloro 
291d0f40dc6SKrishna Elango 	/* Pass the 'rc_err' severity to the fabric scan code. */
292d0f40dc6SKrishna Elango 	tmp_rc_err = rc_err;
293d0f40dc6SKrishna Elango 	pfd_p->pe_severity_flags = px_err_to_fab_sev(&rc_err);
294f8d2de6bSjchu 
295d0f40dc6SKrishna Elango 	/* Scan the fabric */
296d0f40dc6SKrishna Elango 	if (!(fab_err = px_scan_fabric(px_p, rpdip, &derr))) {
297d0f40dc6SKrishna Elango 		/*
298d0f40dc6SKrishna Elango 		 * Fabric scan didn't occur because of some error condition
299d0f40dc6SKrishna Elango 		 * such as Root Port being in drain state, so reset rc_err.
300d0f40dc6SKrishna Elango 		 */
301d0f40dc6SKrishna Elango 		rc_err = tmp_rc_err;
302d0f40dc6SKrishna Elango 	}
303f8d2de6bSjchu 
304f8d2de6bSjchu 	/* Set the intr state to idle for the leaf that received the mondo */
305f8d2de6bSjchu 	if (px_lib_intr_setstate(rpdip, fault_p->px_fh_sysino,
3061ff65112Segillett 	    INTR_IDLE_STATE) != DDI_SUCCESS) {
307eae2e508Skrishnae 		px_fm_exit(px_p);
308f8d2de6bSjchu 		return (DDI_INTR_UNCLAIMED);
309f8d2de6bSjchu 	}
310f8d2de6bSjchu 
311bf8fc234Set 	switch (epkt->rc_descr.block) {
312bf8fc234Set 	case BLOCK_MMU: /* FALLTHROUGH */
313bf8fc234Set 	case BLOCK_INTR:
314bf8fc234Set 		msg = PX_RC;
315bf8fc234Set 		break;
316bf8fc234Set 	case BLOCK_PCIE:
317bf8fc234Set 		msg = PX_RP;
318bf8fc234Set 		break;
319bf8fc234Set 	case BLOCK_HOSTBUS: /* FALLTHROUGH */
320bf8fc234Set 	default:
321bf8fc234Set 		msg = PX_HB;
322bf8fc234Set 		break;
323bf8fc234Set 	}
324bf8fc234Set 
325eae2e508Skrishnae 	px_err_panic(rc_err, msg, fab_err, B_TRUE);
326eae2e508Skrishnae 	px_fm_exit(px_p);
327eae2e508Skrishnae 	px_err_panic(rc_err, msg, fab_err, B_FALSE);
328f8d2de6bSjchu 
329eae2e508Skrishnae done:
330f8d2de6bSjchu 	return (DDI_INTR_CLAIMED);
331f8d2de6bSjchu }
332f8d2de6bSjchu 
333f8d2de6bSjchu /*
334bf8fc234Set  * px_err_epkt_severity:
335f8d2de6bSjchu  * Check the severity of the fire error based the epkt received
336f8d2de6bSjchu  *
337f8d2de6bSjchu  * @param px_p		leaf in which to take the snap shot.
338f8d2de6bSjchu  * @param derr		fm err in which the ereport is to be based on
339f8d2de6bSjchu  * @param epkt		epkt recevied from HV
340f8d2de6bSjchu  */
341f8d2de6bSjchu static int
px_err_epkt_severity(px_t * px_p,ddi_fm_error_t * derr,px_rc_err_t * epkt,pf_data_t * pfd_p)342bf8fc234Set px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt,
343fc256490SJason Beloro     pf_data_t *pfd_p)
344f8d2de6bSjchu {
345f8d2de6bSjchu 	px_pec_t 	*pec_p = px_p->px_pec_p;
346f8d2de6bSjchu 	dev_info_t	*dip = px_p->px_dip;
347bf8fc234Set 	boolean_t	is_safeacc = B_FALSE;
348bf8fc234Set 	boolean_t	is_block_pci = B_FALSE;
349eae2e508Skrishnae 	boolean_t	is_valid_epkt = B_FALSE;
350f8d2de6bSjchu 	int		err = 0;
351f8d2de6bSjchu 
352f8d2de6bSjchu 	/* Cautious access error handling  */
353bf8fc234Set 	switch (derr->fme_flag) {
354bf8fc234Set 	case DDI_FM_ERR_EXPECTED:
355fc256490SJason Beloro 		/*
356fc256490SJason Beloro 		 * For ddi_caut_put treat all events as nonfatal. Here
357fc256490SJason Beloro 		 * we have the handle and can call ndi_fm_acc_err_set().
358fc256490SJason Beloro 		 */
359fc256490SJason Beloro 		derr->fme_status = DDI_FM_NONFATAL;
360fc256490SJason Beloro 		ndi_fm_acc_err_set(pec_p->pec_acc_hdl, derr);
361fc256490SJason Beloro 		is_safeacc = B_TRUE;
362bf8fc234Set 		break;
363bf8fc234Set 	case DDI_FM_ERR_PEEK:
364bf8fc234Set 	case DDI_FM_ERR_POKE:
365bf8fc234Set 		/*
366bf8fc234Set 		 * For ddi_peek/poke treat all events as nonfatal.
367bf8fc234Set 		 */
368bf8fc234Set 		is_safeacc = B_TRUE;
369bf8fc234Set 		break;
370bf8fc234Set 	default:
371bf8fc234Set 		is_safeacc = B_FALSE;
372f8d2de6bSjchu 	}
373f8d2de6bSjchu 
374bf8fc234Set 	/*
375bf8fc234Set 	 * Older hypervisors in some cases send epkts with incorrect fields.
376bf8fc234Set 	 * We have to handle these "special" epkts correctly.
377bf8fc234Set 	 */
378bf8fc234Set 	if (px_legacy_epkt)
379bf8fc234Set 		px_fix_legacy_epkt(dip, derr, epkt);
380bf8fc234Set 
381d0f40dc6SKrishna Elango 	/*
382d0f40dc6SKrishna Elango 	 * The affected device by default is set to 'SELF'. The 'block'
383d0f40dc6SKrishna Elango 	 * specific error handling below will update this as needed.
384d0f40dc6SKrishna Elango 	 */
385d0f40dc6SKrishna Elango 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
386d0f40dc6SKrishna Elango 
387f8d2de6bSjchu 	switch (epkt->rc_descr.block) {
388f8d2de6bSjchu 	case BLOCK_HOSTBUS:
389d0f40dc6SKrishna Elango 		err = px_cb_epkt_severity(dip, derr, epkt, pfd_p);
390f8d2de6bSjchu 		break;
391f8d2de6bSjchu 	case BLOCK_MMU:
392d0f40dc6SKrishna Elango 		err = px_mmu_epkt_severity(dip, derr, epkt, pfd_p);
393f8d2de6bSjchu 		break;
394f8d2de6bSjchu 	case BLOCK_INTR:
395d0f40dc6SKrishna Elango 		err = px_intr_epkt_severity(dip, derr, epkt, pfd_p);
396f8d2de6bSjchu 		break;
3974df55fdeSJanie Lu 	case BLOCK_PORT:
398fc256490SJason Beloro 		err = px_port_epkt_severity(dip, derr, epkt, pfd_p);
3994df55fdeSJanie Lu 		break;
400f8d2de6bSjchu 	case BLOCK_PCIE:
401bf8fc234Set 		is_block_pci = B_TRUE;
402d0f40dc6SKrishna Elango 		err = px_pcie_epkt_severity(dip, derr, epkt, pfd_p);
403f8d2de6bSjchu 		break;
404f8d2de6bSjchu 	default:
405bf8fc234Set 		err = 0;
406f8d2de6bSjchu 	}
407f8d2de6bSjchu 
408d0f40dc6SKrishna Elango 	px_err_fill_pfd(dip, pfd_p, epkt);
409d0f40dc6SKrishna Elango 
410bf8fc234Set 	if ((err & PX_HW_RESET) || (err & PX_PANIC)) {
411bf8fc234Set 		if (px_log & PX_PANIC)
412bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "PANIC");
413eae2e508Skrishnae 		is_valid_epkt = B_TRUE;
414bf8fc234Set 	} else if (err & PX_PROTECTED) {
415bf8fc234Set 		if (px_log & PX_PROTECTED)
416bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "PROTECTED");
417eae2e508Skrishnae 		is_valid_epkt = B_TRUE;
418bf8fc234Set 	} else if (err & PX_NO_PANIC) {
419bf8fc234Set 		if (px_log & PX_NO_PANIC)
420bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "NO PANIC");
421eae2e508Skrishnae 		is_valid_epkt = B_TRUE;
422bf8fc234Set 	} else if (err & PX_NO_ERROR) {
423bf8fc234Set 		if (px_log & PX_NO_ERROR)
424bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "NO ERROR");
425eae2e508Skrishnae 		is_valid_epkt = B_TRUE;
426bf8fc234Set 	} else if (err == 0) {
427bf8fc234Set 		px_err_log_handle(dip, epkt, is_block_pci, "UNRECOGNIZED");
428eae2e508Skrishnae 		is_valid_epkt = B_FALSE;
429bf8fc234Set 
430eae2e508Skrishnae 		/* Panic on a unrecognized epkt */
431bf8fc234Set 		err = PX_PANIC;
432bf8fc234Set 	}
433bf8fc234Set 
434eae2e508Skrishnae 	px_err_send_epkt_erpt(dip, epkt, is_block_pci, err, derr,
435eae2e508Skrishnae 	    is_valid_epkt);
436eae2e508Skrishnae 
437bf8fc234Set 	/* Readjust the severity as a result of safe access */
438bf8fc234Set 	if (is_safeacc && !(err & PX_PANIC) && !(px_die & PX_PROTECTED))
439bf8fc234Set 		err = PX_NO_PANIC;
440bf8fc234Set 
441f8d2de6bSjchu 	return (err);
442f8d2de6bSjchu }
443f8d2de6bSjchu 
444eae2e508Skrishnae static void
px_err_send_epkt_erpt(dev_info_t * dip,px_rc_err_t * epkt,boolean_t is_block_pci,int err,ddi_fm_error_t * derr,boolean_t is_valid_epkt)445eae2e508Skrishnae px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
446eae2e508Skrishnae     boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
447eae2e508Skrishnae     boolean_t is_valid_epkt)
448eae2e508Skrishnae {
449eae2e508Skrishnae 	char buf[FM_MAX_CLASS], descr_buf[1024];
450eae2e508Skrishnae 
451eae2e508Skrishnae 	/* send ereport for debug purposes */
452eae2e508Skrishnae 	(void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_RC_UNRECOG);
453eae2e508Skrishnae 
454eae2e508Skrishnae 	if (is_block_pci) {
455eae2e508Skrishnae 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
456eae2e508Skrishnae 		(void) snprintf(descr_buf, sizeof (descr_buf),
457eae2e508Skrishnae 		    "%s Epkt contents:\n"
458eae2e508Skrishnae 		    "Block: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d\n"
459eae2e508Skrishnae 		    "I=%d, H=%d, C=%d, U=%d, E=%d, P=%d\n"
460eae2e508Skrishnae 		    "PCI Err Status: 0x%x, PCIe Err Status: 0x%x\n"
461eae2e508Skrishnae 		    "CE Status Reg: 0x%x, UE Status Reg: 0x%x\n"
462eae2e508Skrishnae 		    "HDR1: 0x%lx, HDR2: 0x%lx\n"
463eae2e508Skrishnae 		    "Err Src Reg: 0x%x, Root Err Status: 0x%x\n"
464eae2e508Skrishnae 		    "Err Severity: 0x%x\n",
465eae2e508Skrishnae 		    is_valid_epkt ? "Valid" : "Invalid",
466eae2e508Skrishnae 		    pec->pec_descr.block, pec->pec_descr.dir,
467eae2e508Skrishnae 		    pec->pec_descr.Z, pec->pec_descr.S,
468eae2e508Skrishnae 		    pec->pec_descr.R, pec->pec_descr.I,
469eae2e508Skrishnae 		    pec->pec_descr.H, pec->pec_descr.C,
470eae2e508Skrishnae 		    pec->pec_descr.U, pec->pec_descr.E,
471eae2e508Skrishnae 		    pec->pec_descr.P, pec->pci_err_status,
472eae2e508Skrishnae 		    pec->pcie_err_status, pec->ce_reg_status,
473eae2e508Skrishnae 		    pec->ue_reg_status, pec->hdr[0],
474eae2e508Skrishnae 		    pec->hdr[1], pec->err_src_reg,
475eae2e508Skrishnae 		    pec->root_err_status, err);
476eae2e508Skrishnae 
477eae2e508Skrishnae 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
478eae2e508Skrishnae 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
479eae2e508Skrishnae 		    EPKT_SYSINO, DATA_TYPE_UINT64,
480eae2e508Skrishnae 		    is_valid_epkt ? pec->sysino : 0,
481eae2e508Skrishnae 		    EPKT_EHDL, DATA_TYPE_UINT64,
482eae2e508Skrishnae 		    is_valid_epkt ? pec->ehdl : 0,
483eae2e508Skrishnae 		    EPKT_STICK, DATA_TYPE_UINT64,
484eae2e508Skrishnae 		    is_valid_epkt ? pec->stick : 0,
4854df55fdeSJanie Lu 		    EPKT_DW0, DATA_TYPE_UINT64, ((uint64_t *)pec)[3],
4864df55fdeSJanie Lu 		    EPKT_DW1, DATA_TYPE_UINT64, ((uint64_t *)pec)[4],
4874df55fdeSJanie Lu 		    EPKT_DW2, DATA_TYPE_UINT64, ((uint64_t *)pec)[5],
4884df55fdeSJanie Lu 		    EPKT_DW3, DATA_TYPE_UINT64, ((uint64_t *)pec)[6],
4894df55fdeSJanie Lu 		    EPKT_DW4, DATA_TYPE_UINT64, ((uint64_t *)pec)[7],
490eae2e508Skrishnae 		    EPKT_PEC_DESCR, DATA_TYPE_STRING, descr_buf);
491eae2e508Skrishnae 	} else {
492eae2e508Skrishnae 		(void) snprintf(descr_buf, sizeof (descr_buf),
493eae2e508Skrishnae 		    "%s Epkt contents:\n"
494eae2e508Skrishnae 		    "Block: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
495eae2e508Skrishnae 		    "Dir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d\n"
496eae2e508Skrishnae 		    "M=%d, S=%d, Size: 0x%x, Addr: 0x%lx\n"
497eae2e508Skrishnae 		    "Hdr1: 0x%lx, Hdr2: 0x%lx, Res: 0x%lx\n"
498eae2e508Skrishnae 		    "Err Severity: 0x%x\n",
499eae2e508Skrishnae 		    is_valid_epkt ? "Valid" : "Invalid",
500eae2e508Skrishnae 		    epkt->rc_descr.block, epkt->rc_descr.op,
501eae2e508Skrishnae 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
502eae2e508Skrishnae 		    epkt->rc_descr.dir, epkt->rc_descr.STOP,
503eae2e508Skrishnae 		    epkt->rc_descr.H, epkt->rc_descr.R,
504eae2e508Skrishnae 		    epkt->rc_descr.D, epkt->rc_descr.M,
505eae2e508Skrishnae 		    epkt->rc_descr.S, epkt->size, epkt->addr,
506eae2e508Skrishnae 		    epkt->hdr[0], epkt->hdr[1], epkt->reserved,
507eae2e508Skrishnae 		    err);
508eae2e508Skrishnae 
509eae2e508Skrishnae 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
510eae2e508Skrishnae 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
511eae2e508Skrishnae 		    EPKT_SYSINO, DATA_TYPE_UINT64,
512eae2e508Skrishnae 		    is_valid_epkt ? epkt->sysino : 0,
513eae2e508Skrishnae 		    EPKT_EHDL, DATA_TYPE_UINT64,
514eae2e508Skrishnae 		    is_valid_epkt ? epkt->ehdl : 0,
515eae2e508Skrishnae 		    EPKT_STICK, DATA_TYPE_UINT64,
516eae2e508Skrishnae 		    is_valid_epkt ? epkt->stick : 0,
5174df55fdeSJanie Lu 		    EPKT_DW0, DATA_TYPE_UINT64, ((uint64_t *)epkt)[3],
5184df55fdeSJanie Lu 		    EPKT_DW1, DATA_TYPE_UINT64, ((uint64_t *)epkt)[4],
5194df55fdeSJanie Lu 		    EPKT_DW2, DATA_TYPE_UINT64, ((uint64_t *)epkt)[5],
5204df55fdeSJanie Lu 		    EPKT_DW3, DATA_TYPE_UINT64, ((uint64_t *)epkt)[6],
5214df55fdeSJanie Lu 		    EPKT_DW4, DATA_TYPE_UINT64, ((uint64_t *)epkt)[7],
522eae2e508Skrishnae 		    EPKT_RC_DESCR, DATA_TYPE_STRING, descr_buf);
523eae2e508Skrishnae 	}
524eae2e508Skrishnae }
525eae2e508Skrishnae 
526bf8fc234Set static void
px_err_log_handle(dev_info_t * dip,px_rc_err_t * epkt,boolean_t is_block_pci,char * msg)527bf8fc234Set px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt, boolean_t is_block_pci,
528bf8fc234Set     char *msg)
529bf8fc234Set {
530bf8fc234Set 	if (is_block_pci) {
531bf8fc234Set 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
532bf8fc234Set 		DBG(DBG_ERR_INTR, dip,
533bf8fc234Set 		    "A PCIe root port error has occured with a severity"
534bf8fc234Set 		    " \"%s\"\n"
535bf8fc234Set 		    "\tBlock: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d, I=%d\n"
536bf8fc234Set 		    "\tH=%d, C=%d, U=%d, E=%d, P=%d\n"
537bf8fc234Set 		    "\tpci_err: 0x%x, pcie_err=0x%x, ce_reg: 0x%x\n"
538bf8fc234Set 		    "\tue_reg: 0x%x, Hdr1: 0x%p, Hdr2: 0x%p\n"
539bf8fc234Set 		    "\terr_src: 0x%x, root_err: 0x%x\n",
540bf8fc234Set 		    msg, pec->pec_descr.block, pec->pec_descr.dir,
541bf8fc234Set 		    pec->pec_descr.Z, pec->pec_descr.S, pec->pec_descr.R,
542bf8fc234Set 		    pec->pec_descr.I, pec->pec_descr.H, pec->pec_descr.C,
543bf8fc234Set 		    pec->pec_descr.U, pec->pec_descr.E, pec->pec_descr.P,
544bf8fc234Set 		    pec->pci_err_status, pec->pcie_err_status,
545bf8fc234Set 		    pec->ce_reg_status, pec->ue_reg_status, pec->hdr[0],
546bf8fc234Set 		    pec->hdr[1], pec->err_src_reg, pec->root_err_status);
547bf8fc234Set 	} else {
548bf8fc234Set 		DBG(DBG_ERR_INTR, dip,
549bf8fc234Set 		    "A PCIe root complex error has occured with a severity"
550bf8fc234Set 		    " \"%s\"\n"
551bf8fc234Set 		    "\tBlock: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
552bf8fc234Set 		    "\tDir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d, M=%d\n"
553bf8fc234Set 		    "\tS=%d, Size: 0x%x, Addr: 0x%p\n"
554bf8fc234Set 		    "\tHdr1: 0x%p, Hdr2: 0x%p, Res: 0x%p\n",
555bf8fc234Set 		    msg, epkt->rc_descr.block, epkt->rc_descr.op,
556bf8fc234Set 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
557bf8fc234Set 		    epkt->rc_descr.dir, epkt->rc_descr.STOP, epkt->rc_descr.H,
558bf8fc234Set 		    epkt->rc_descr.R, epkt->rc_descr.D, epkt->rc_descr.M,
559bf8fc234Set 		    epkt->rc_descr.S, epkt->size, epkt->addr, epkt->hdr[0],
560bf8fc234Set 		    epkt->hdr[1], epkt->reserved);
561bf8fc234Set 	}
562bf8fc234Set }
563bf8fc234Set 
564f8d2de6bSjchu /* ARGSUSED */
565bf8fc234Set static void
px_fix_legacy_epkt(dev_info_t * dip,ddi_fm_error_t * derr,px_rc_err_t * epkt)566bf8fc234Set px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
567f8d2de6bSjchu {
568bf8fc234Set 	/*
569bf8fc234Set 	 * We don't have a default case for any of the below switch statements
570bf8fc234Set 	 * since we are ok with the code falling through.
571bf8fc234Set 	 */
572bf8fc234Set 	switch (epkt->rc_descr.block) {
573bf8fc234Set 	case BLOCK_HOSTBUS:
574bf8fc234Set 		switch (epkt->rc_descr.op) {
575bf8fc234Set 		case OP_DMA:
576bf8fc234Set 			switch (epkt->rc_descr.phase) {
577bf8fc234Set 			case PH_UNKNOWN:
578bf8fc234Set 				switch (epkt->rc_descr.cond) {
579bf8fc234Set 				case CND_UNKNOWN:
580bf8fc234Set 					switch (epkt->rc_descr.dir) {
581bf8fc234Set 					case DIR_RESERVED:
582bf8fc234Set 						epkt->rc_descr.dir = DIR_READ;
583bf8fc234Set 						break;
584bf8fc234Set 					} /* DIR */
585bf8fc234Set 				} /* CND */
586bf8fc234Set 			} /* PH */
587bf8fc234Set 		} /* OP */
588f8d2de6bSjchu 		break;
589bf8fc234Set 	case BLOCK_MMU:
590bf8fc234Set 		switch (epkt->rc_descr.op) {
591bf8fc234Set 		case OP_XLAT:
592bf8fc234Set 			switch (epkt->rc_descr.phase) {
593bf8fc234Set 			case PH_DATA:
594bf8fc234Set 				switch (epkt->rc_descr.cond) {
595bf8fc234Set 				case CND_PROT:
596bf8fc234Set 					switch (epkt->rc_descr.dir) {
597bf8fc234Set 					case DIR_UNKNOWN:
598bf8fc234Set 						epkt->rc_descr.dir = DIR_WRITE;
599bf8fc234Set 						break;
600bf8fc234Set 					} /* DIR */
601bf8fc234Set 				} /* CND */
6023d9c56a1Set 				break;
603bf8fc234Set 			case PH_IRR:
604bf8fc234Set 				switch (epkt->rc_descr.cond) {
605bf8fc234Set 				case CND_RESERVED:
606bf8fc234Set 					switch (epkt->rc_descr.dir) {
607bf8fc234Set 					case DIR_IRR:
608bf8fc234Set 						epkt->rc_descr.phase = PH_ADDR;
609bf8fc234Set 						epkt->rc_descr.cond = CND_IRR;
610bf8fc234Set 					} /* DIR */
611bf8fc234Set 				} /* CND */
612bf8fc234Set 			} /* PH */
613bf8fc234Set 		} /* OP */
614e51949e6Sdduvall 		break;
615bf8fc234Set 	case BLOCK_INTR:
616bf8fc234Set 		switch (epkt->rc_descr.op) {
617bf8fc234Set 		case OP_MSIQ:
618bf8fc234Set 			switch (epkt->rc_descr.phase) {
619bf8fc234Set 			case PH_UNKNOWN:
620bf8fc234Set 				switch (epkt->rc_descr.cond) {
621bf8fc234Set 				case CND_ILL:
622bf8fc234Set 					switch (epkt->rc_descr.dir) {
623bf8fc234Set 					case DIR_RESERVED:
624bf8fc234Set 						epkt->rc_descr.dir = DIR_IRR;
625bf8fc234Set 						break;
626bf8fc234Set 					} /* DIR */
627bf8fc234Set 					break;
628bf8fc234Set 				case CND_IRR:
629bf8fc234Set 					switch (epkt->rc_descr.dir) {
630bf8fc234Set 					case DIR_IRR:
631bf8fc234Set 						epkt->rc_descr.cond = CND_OV;
632bf8fc234Set 						break;
633bf8fc234Set 					} /* DIR */
634bf8fc234Set 				} /* CND */
635bf8fc234Set 			} /* PH */
636bf8fc234Set 			break;
637bf8fc234Set 		case OP_RESERVED:
638bf8fc234Set 			switch (epkt->rc_descr.phase) {
639bf8fc234Set 			case PH_UNKNOWN:
640bf8fc234Set 				switch (epkt->rc_descr.cond) {
641bf8fc234Set 				case CND_ILL:
642bf8fc234Set 					switch (epkt->rc_descr.dir) {
643bf8fc234Set 					case DIR_IRR:
644bf8fc234Set 						epkt->rc_descr.op = OP_MSI32;
645bf8fc234Set 						epkt->rc_descr.phase = PH_DATA;
646bf8fc234Set 						break;
647bf8fc234Set 					} /* DIR */
648bf8fc234Set 				} /* CND */
649bf8fc234Set 				break;
650bf8fc234Set 			case PH_DATA:
651bf8fc234Set 				switch (epkt->rc_descr.cond) {
652bf8fc234Set 				case CND_INT:
653bf8fc234Set 					switch (epkt->rc_descr.dir) {
654bf8fc234Set 					case DIR_UNKNOWN:
655bf8fc234Set 						epkt->rc_descr.op = OP_MSI32;
656bf8fc234Set 						break;
657bf8fc234Set 					} /* DIR */
658bf8fc234Set 				} /* CND */
659bf8fc234Set 			} /* PH */
660bf8fc234Set 		} /* OP */
661bf8fc234Set 	} /* BLOCK */
662bf8fc234Set }
6633d9c56a1Set 
664bf8fc234Set /* ARGSUSED */
665bf8fc234Set static int
px_intr_handle_errors(dev_info_t * dip,ddi_fm_error_t * derr,px_rc_err_t * epkt,pf_data_t * pfd_p)666d0f40dc6SKrishna Elango px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt,
667d0f40dc6SKrishna Elango     pf_data_t *pfd_p)
668bf8fc234Set {
669bf8fc234Set 	return (px_err_check_eq(dip));
670bf8fc234Set }
671bf8fc234Set 
6724df55fdeSJanie Lu /* ARGSUSED */
6734df55fdeSJanie Lu static int
px_port_handle_errors(dev_info_t * dip,ddi_fm_error_t * derr,px_rc_err_t * epkt,pf_data_t * pfd_p)674fc256490SJason Beloro px_port_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt,
675fc256490SJason Beloro     pf_data_t *pfd_p)
6764df55fdeSJanie Lu {
6774df55fdeSJanie Lu 	pf_pcie_adv_err_regs_t	adv_reg;
6784df55fdeSJanie Lu 	uint16_t		s_status;
6794df55fdeSJanie Lu 	int			sts = PX_PANIC;
6804df55fdeSJanie Lu 
6814df55fdeSJanie Lu 	/*
6824df55fdeSJanie Lu 	 * Check for failed non-posted writes, which are errors that are not
6834df55fdeSJanie Lu 	 * defined in the PCIe spec.  If not return panic.
6844df55fdeSJanie Lu 	 */
6854df55fdeSJanie Lu 	if (!((epkt->rc_descr.op == OP_PIO) &&
6864df55fdeSJanie Lu 	    (epkt->rc_descr.phase == PH_IRR))) {
6874df55fdeSJanie Lu 		sts = (PX_PANIC);
6884df55fdeSJanie Lu 		goto done;
6894df55fdeSJanie Lu 	}
6904df55fdeSJanie Lu 
6914df55fdeSJanie Lu 	/*
6924df55fdeSJanie Lu 	 * Gather the error logs, if they do not exist just return with no panic
6934df55fdeSJanie Lu 	 * and let the fabric message take care of the error.
6944df55fdeSJanie Lu 	 */
6954df55fdeSJanie Lu 	if (!epkt->rc_descr.H) {
6964df55fdeSJanie Lu 		sts = (PX_NO_PANIC);
6974df55fdeSJanie Lu 		goto done;
6984df55fdeSJanie Lu 	}
6994df55fdeSJanie Lu 
7005613d828SKrishna Elango 	adv_reg.pcie_ue_hdr[0] = (uint32_t)(epkt->hdr[0] >> 32);
7015613d828SKrishna Elango 	adv_reg.pcie_ue_hdr[1] = (uint32_t)(epkt->hdr[0]);
7025613d828SKrishna Elango 	adv_reg.pcie_ue_hdr[2] = (uint32_t)(epkt->hdr[1] >> 32);
7035613d828SKrishna Elango 	adv_reg.pcie_ue_hdr[3] = (uint32_t)(epkt->hdr[1]);
7044df55fdeSJanie Lu 
7054df55fdeSJanie Lu 	sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
7064df55fdeSJanie Lu 
7074df55fdeSJanie Lu 	if (epkt->rc_descr.M)
7084df55fdeSJanie Lu 		adv_reg.pcie_ue_tgt_addr = epkt->addr;
7094df55fdeSJanie Lu 
7104df55fdeSJanie Lu 	if (!((sts == DDI_SUCCESS) || (epkt->rc_descr.M))) {
7114df55fdeSJanie Lu 		/* Let the fabric message take care of error */
7124df55fdeSJanie Lu 		sts = PX_NO_PANIC;
7134df55fdeSJanie Lu 		goto done;
7144df55fdeSJanie Lu 	}
7154df55fdeSJanie Lu 
7164df55fdeSJanie Lu 	/* See if the failed transaction belonged to a hardened driver */
7174df55fdeSJanie Lu 	if (pf_hdl_lookup(dip, derr->fme_ena,
7184df55fdeSJanie Lu 	    adv_reg.pcie_ue_tgt_trans, adv_reg.pcie_ue_tgt_addr,
7194df55fdeSJanie Lu 	    adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
7204df55fdeSJanie Lu 		sts = (PX_NO_PANIC);
7214df55fdeSJanie Lu 	else
7224df55fdeSJanie Lu 		sts = (PX_PANIC);
7234df55fdeSJanie Lu 
7244df55fdeSJanie Lu 	/* Add pfd to cause a fabric scan */
7254df55fdeSJanie Lu 	switch (epkt->rc_descr.cond) {
7264df55fdeSJanie Lu 	case CND_RCA:
7274df55fdeSJanie Lu 		s_status = PCI_STAT_R_TARG_AB;
7284df55fdeSJanie Lu 		break;
7294df55fdeSJanie Lu 	case CND_RUR:
7304df55fdeSJanie Lu 		s_status = PCI_STAT_R_MAST_AB;
7314df55fdeSJanie Lu 		break;
7324df55fdeSJanie Lu 	}
733fc256490SJason Beloro 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = adv_reg.pcie_ue_tgt_bdf;
734fc256490SJason Beloro 	PCIE_ROOT_FAULT(pfd_p)->scan_addr = adv_reg.pcie_ue_tgt_addr;
735fc256490SJason Beloro 	PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
7364df55fdeSJanie Lu 
737d0f40dc6SKrishna Elango 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_BDF;
738d0f40dc6SKrishna Elango 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = adv_reg.pcie_ue_tgt_bdf;
739d0f40dc6SKrishna Elango 
7404df55fdeSJanie Lu done:
7414df55fdeSJanie Lu 	return (sts);
7424df55fdeSJanie Lu }
7434df55fdeSJanie Lu 
744bf8fc234Set /* ARGSUSED */
745bf8fc234Set static int
px_pcie_epkt_severity(dev_info_t * dip,ddi_fm_error_t * derr,px_rc_err_t * epkt,pf_data_t * pfd_p)746d0f40dc6SKrishna Elango px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt,
747d0f40dc6SKrishna Elango     pf_data_t *pfd_p)
748bf8fc234Set {
749eae2e508Skrishnae 	px_pec_err_t	*pec_p = (px_pec_err_t *)epkt;
750bf8fc234Set 	px_err_pcie_t	*pcie = (px_err_pcie_t *)epkt;
751eae2e508Skrishnae 	pf_pcie_adv_err_regs_t adv_reg;
752eae2e508Skrishnae 	int		sts;
753bf8fc234Set 	uint32_t	temp;
754f8d2de6bSjchu 
755f8d2de6bSjchu 	/*
756bf8fc234Set 	 * Check for failed PIO Read/Writes, which are errors that are not
757bf8fc234Set 	 * defined in the PCIe spec.
758f8d2de6bSjchu 	 */
7595613d828SKrishna Elango 
760bf8fc234Set 	temp = PCIE_AER_UCE_UR | PCIE_AER_UCE_CA;
761eae2e508Skrishnae 	if (((pec_p->pec_descr.dir == DIR_READ) ||
762eae2e508Skrishnae 	    (pec_p->pec_descr.dir == DIR_WRITE)) &&
763eae2e508Skrishnae 	    pec_p->pec_descr.U && (pec_p->ue_reg_status & temp)) {
7645613d828SKrishna Elango 
7655613d828SKrishna Elango 		adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0] >> 32);
7665613d828SKrishna Elango 		adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0]);
7675613d828SKrishna Elango 		adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1] >> 32);
7685613d828SKrishna Elango 		adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1]);
769eae2e508Skrishnae 
770eae2e508Skrishnae 		sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
771eae2e508Skrishnae 
772eae2e508Skrishnae 		if (sts == DDI_SUCCESS &&
773eae2e508Skrishnae 		    pf_hdl_lookup(dip, derr->fme_ena,
774eae2e508Skrishnae 		    adv_reg.pcie_ue_tgt_trans,
775eae2e508Skrishnae 		    adv_reg.pcie_ue_tgt_addr,
776eae2e508Skrishnae 		    adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
777bf8fc234Set 			return (PX_NO_PANIC);
778f8d2de6bSjchu 		else
779bf8fc234Set 			return (PX_PANIC);
780f8d2de6bSjchu 	}
781f8d2de6bSjchu 
782eae2e508Skrishnae 	if (!pec_p->pec_descr.C)
783eae2e508Skrishnae 		pec_p->ce_reg_status = 0;
784eae2e508Skrishnae 	if (!pec_p->pec_descr.U)
785eae2e508Skrishnae 		pec_p->ue_reg_status = 0;
786eae2e508Skrishnae 	if (!pec_p->pec_descr.H)
787eae2e508Skrishnae 		pec_p->hdr[0] = 0;
788eae2e508Skrishnae 	if (!pec_p->pec_descr.I)
789eae2e508Skrishnae 		pec_p->hdr[1] = 0;
790f8d2de6bSjchu 
791bf8fc234Set 	/*
792bf8fc234Set 	 * According to the PCIe spec, there is a first error pointer.  If there
793bf8fc234Set 	 * are header logs recorded and there are more than one error, the log
794bf8fc234Set 	 * will belong to the error that the first error pointer points to.
795bf8fc234Set 	 *
796bf8fc234Set 	 * The regs.primary_ue expects a bit number, go through the ue register
797bf8fc234Set 	 * and find the first error that occured.  Because the sun4v epkt spec
798bf8fc234Set 	 * does not define this value, the algorithm below gives the lower bit
799bf8fc234Set 	 * priority.
800bf8fc234Set 	 */
801bf8fc234Set 	temp = pcie->ue_reg;
802bf8fc234Set 	if (temp) {
803eae2e508Skrishnae 		int x;
804bf8fc234Set 		for (x = 0; !(temp & 0x1); x++) {
805bf8fc234Set 			temp = temp >> 1;
806bf8fc234Set 		}
807bf8fc234Set 		pcie->primary_ue = 1 << x;
808bf8fc234Set 	} else {
809bf8fc234Set 		pcie->primary_ue = 0;
8103d9c56a1Set 	}
811f8d2de6bSjchu 
812bf8fc234Set 	/* Sun4v doesn't log the TX hdr except for CTOs */
813bf8fc234Set 	if (pcie->primary_ue == PCIE_AER_UCE_TO) {
814bf8fc234Set 		pcie->tx_hdr1 = pcie->rx_hdr1;
815bf8fc234Set 		pcie->tx_hdr2 = pcie->rx_hdr2;
816bf8fc234Set 		pcie->tx_hdr3 = pcie->rx_hdr3;
817bf8fc234Set 		pcie->tx_hdr4 = pcie->rx_hdr4;
818bf8fc234Set 		pcie->rx_hdr1 = 0;
819bf8fc234Set 		pcie->rx_hdr2 = 0;
820bf8fc234Set 		pcie->rx_hdr3 = 0;
821bf8fc234Set 		pcie->rx_hdr4 = 0;
822bf8fc234Set 	} else {
823bf8fc234Set 		pcie->tx_hdr1 = 0;
824bf8fc234Set 		pcie->tx_hdr2 = 0;
825bf8fc234Set 		pcie->tx_hdr3 = 0;
826bf8fc234Set 		pcie->tx_hdr4 = 0;
827bf8fc234Set 	}
828e51949e6Sdduvall 
8295613d828SKrishna Elango 	return (px_err_check_pcie(dip, derr, pcie, PF_INTR_TYPE_INTERNAL));
830f8d2de6bSjchu }
831f8d2de6bSjchu 
832f8d2de6bSjchu static int
px_mmu_handle_lookup(dev_info_t * dip,ddi_fm_error_t * derr,px_rc_err_t * epkt)833bf8fc234Set px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
834f8d2de6bSjchu {
835eae2e508Skrishnae 	uint64_t addr = (uint64_t)epkt->addr;
836c85864d8SKrishna Elango 	pcie_req_id_t bdf = PCIE_INVALID_BDF;
837f8d2de6bSjchu 
838bf8fc234Set 	if (epkt->rc_descr.H) {
839*e214b19eSToomas Soome 		bdf = (uint32_t)((epkt->hdr[0] >> 16) & 0xFFFF);
840f8d2de6bSjchu 	}
841f8d2de6bSjchu 
842eae2e508Skrishnae 	return (pf_hdl_lookup(dip, derr->fme_ena, PF_ADDR_DMA, addr,
8431ff65112Segillett 	    bdf));
844f8d2de6bSjchu }
845