xref: /illumos-gate/usr/src/uts/sun4v/io/px/px_err.c (revision bf8fc234)
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 /*
2201689544Sjchu  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23f8d2de6bSjchu  * Use is subject to license terms.
24f8d2de6bSjchu  */
25f8d2de6bSjchu 
26f8d2de6bSjchu #pragma ident	"%Z%%M%	%I%	%E% SMI"
27f8d2de6bSjchu 
28f8d2de6bSjchu /*
29f8d2de6bSjchu  * sun4v Fire Error Handling
30f8d2de6bSjchu  */
31f8d2de6bSjchu 
32f8d2de6bSjchu #include <sys/types.h>
33f8d2de6bSjchu #include <sys/ddi.h>
34f8d2de6bSjchu #include <sys/sunddi.h>
35f8d2de6bSjchu #include <sys/fm/protocol.h>
36f8d2de6bSjchu #include <sys/fm/util.h>
37f8d2de6bSjchu #include <sys/membar.h>
38f8d2de6bSjchu #include "px_obj.h"
39f8d2de6bSjchu #include "px_err.h"
40f8d2de6bSjchu 
41*bf8fc234Set static void px_err_fill_pf_data(dev_info_t *dip, px_t *px_p, px_rc_err_t *epkt);
42*bf8fc234Set static uint_t px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt);
43*bf8fc234Set static int  px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr,
44f8d2de6bSjchu     px_rc_err_t *epkt, int caller);
45f8d2de6bSjchu 
46*bf8fc234Set static void px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt,
47*bf8fc234Set     boolean_t is_block_pci, char *msg);
48*bf8fc234Set static int px_cb_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
49*bf8fc234Set     px_rc_err_t *epkt);
50*bf8fc234Set static int px_mmu_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
51*bf8fc234Set     px_rc_err_t *epkt);
52*bf8fc234Set static int px_intr_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
53*bf8fc234Set     px_rc_err_t *epkt);
54*bf8fc234Set static int px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
55*bf8fc234Set     px_rc_err_t *epkt);
56*bf8fc234Set static int px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
57*bf8fc234Set     px_rc_err_t *epkt);
58*bf8fc234Set static void px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr,
59*bf8fc234Set     px_rc_err_t *epkt);
60*bf8fc234Set static int px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr,
61*bf8fc234Set     px_rc_err_t *epkt);
62*bf8fc234Set 
63*bf8fc234Set /* Include the code generated sun4v epkt checking code */
64*bf8fc234Set #include "px_err_gen.c"
65*bf8fc234Set 
66*bf8fc234Set /*
67*bf8fc234Set  * This variable indicates if we have a hypervisor that could potentially send
68*bf8fc234Set  * incorrect epkts. We always set this to TRUE for now until we find a way to
69*bf8fc234Set  * tell if this HV bug has been fixed.
70*bf8fc234Set  */
71*bf8fc234Set boolean_t px_legacy_epkt = B_TRUE;
72f8d2de6bSjchu 
73f8d2de6bSjchu /*
74f8d2de6bSjchu  * px_err_cb_intr:
75f8d2de6bSjchu  * Interrupt handler for the Host Bus Block.
76f8d2de6bSjchu  */
77f8d2de6bSjchu uint_t
78f8d2de6bSjchu px_err_cb_intr(caddr_t arg)
79f8d2de6bSjchu {
80f8d2de6bSjchu 	px_fault_t	*fault_p = (px_fault_t *)arg;
81f8d2de6bSjchu 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
82f8d2de6bSjchu 
83f8d2de6bSjchu 	if (epkt != NULL) {
84*bf8fc234Set 		return (px_err_intr(fault_p, epkt));
85f8d2de6bSjchu 	}
86f8d2de6bSjchu 
87f8d2de6bSjchu 	return (DDI_INTR_UNCLAIMED);
88f8d2de6bSjchu }
89f8d2de6bSjchu 
90f8d2de6bSjchu /*
91f8d2de6bSjchu  * px_err_dmc_pec_intr:
92f8d2de6bSjchu  * Interrupt handler for the DMC/PEC block.
93f8d2de6bSjchu  */
94f8d2de6bSjchu uint_t
95f8d2de6bSjchu px_err_dmc_pec_intr(caddr_t arg)
96f8d2de6bSjchu {
97f8d2de6bSjchu 	px_fault_t	*fault_p = (px_fault_t *)arg;
98f8d2de6bSjchu 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
99f8d2de6bSjchu 
100f8d2de6bSjchu 	if (epkt != NULL) {
101*bf8fc234Set 		return (px_err_intr(fault_p, epkt));
102f8d2de6bSjchu 	}
103f8d2de6bSjchu 
104f8d2de6bSjchu 	return (DDI_INTR_UNCLAIMED);
105f8d2de6bSjchu }
106f8d2de6bSjchu 
107f8d2de6bSjchu /*
108*bf8fc234Set  * px_err_cmn_intr:
109f8d2de6bSjchu  * Common function called by trap, mondo and fabric intr.
110f8d2de6bSjchu  * This function is more meaningful in sun4u implementation.  Kept
111f8d2de6bSjchu  * to mirror sun4u call stack.
112f8d2de6bSjchu  * o check for safe access
113*bf8fc234Set  * o create and queue RC info for later use in fabric scan.
114*bf8fc234Set  *   o RUC/WUC, PTLP, MMU Errors(CA), UR
115f8d2de6bSjchu  *
116f8d2de6bSjchu  * @param px_p		leaf in which to check access
117f8d2de6bSjchu  * @param derr		fm err data structure to be updated
118f8d2de6bSjchu  * @param caller	PX_TRAP_CALL | PX_INTR_CALL
119f8d2de6bSjchu  * @param chkjbc	whether to handle hostbus registers (ignored)
120*bf8fc234Set  * @return err		PX_NO_PANIC | PX_PROTECTED |
121*bf8fc234Set  *                      PX_PANIC | PX_HW_RESET | PX_EXPECTED
122f8d2de6bSjchu  */
123f8d2de6bSjchu /* ARGSUSED */
124f8d2de6bSjchu int
125*bf8fc234Set px_err_cmn_intr(px_t *px_p, ddi_fm_error_t *derr, int caller, int block)
126f8d2de6bSjchu {
127f8d2de6bSjchu 	px_err_safeacc_check(px_p, derr);
128e51949e6Sdduvall 	return (DDI_FM_OK);
1293d9c56a1Set }
1303d9c56a1Set 
1313d9c56a1Set /*
132*bf8fc234Set  * fills RC specific fault data
133*bf8fc234Set  */
134*bf8fc234Set static void
135*bf8fc234Set px_err_fill_pfd(dev_info_t *dip, px_t *px_p, px_rc_err_t *epkt) {
136*bf8fc234Set 	pf_data_t	pf_data = {0};
137*bf8fc234Set 	int		sts = DDI_SUCCESS;
138*bf8fc234Set 	pcie_req_id_t	fault_bdf = 0;
139*bf8fc234Set 	uint32_t	fault_addr = 0;
140*bf8fc234Set 	uint16_t	s_status = 0;
141*bf8fc234Set 
142*bf8fc234Set 	/* Add an PCIE PF_DATA Entry */
143*bf8fc234Set 	if (epkt->rc_descr.block == BLOCK_MMU) {
144*bf8fc234Set 		/* Only PIO Fault Addresses are valid, this is DMA */
145*bf8fc234Set 		s_status = PCI_STAT_S_TARG_AB;
146*bf8fc234Set 		fault_addr = NULL;
147*bf8fc234Set 
148*bf8fc234Set 		if (epkt->rc_descr.H)
149*bf8fc234Set 			fault_bdf = (pcie_req_id_t)(epkt->hdr[0] >> 16);
150*bf8fc234Set 		else
151*bf8fc234Set 			sts = DDI_FAILURE;
152*bf8fc234Set 	} else {
153*bf8fc234Set 		px_pec_err_t	*pec_p = (px_pec_err_t *)epkt;
154*bf8fc234Set 		uint32_t	trans_type;
155*bf8fc234Set 		uint32_t	dir = pec_p->pec_descr.dir;
156*bf8fc234Set 
157*bf8fc234Set 		pf_data.aer_h0 = (uint32_t)(pec_p->hdr[0]);
158*bf8fc234Set 		pf_data.aer_h1 = (uint32_t)(pec_p->hdr[0] >> 32);
159*bf8fc234Set 		pf_data.aer_h2 = (uint32_t)(pec_p->hdr[1]);
160*bf8fc234Set 		pf_data.aer_h3 = (uint32_t)(pec_p->hdr[1] >> 32);
161*bf8fc234Set 
162*bf8fc234Set 		/* translate RC UR/CA to legacy secondary errors */
163*bf8fc234Set 		if ((dir == DIR_READ || dir == DIR_WRITE) &&
164*bf8fc234Set 		    pec_p->pec_descr.U) {
165*bf8fc234Set 			if (pec_p->ue_reg_status & PCIE_AER_UCE_UR)
166*bf8fc234Set 				s_status |= PCI_STAT_R_MAST_AB;
167*bf8fc234Set 			if (pec_p->ue_reg_status | PCIE_AER_UCE_CA)
168*bf8fc234Set 				s_status |= PCI_STAT_R_TARG_AB;
169*bf8fc234Set 		}
170*bf8fc234Set 
171*bf8fc234Set 		if (pec_p->ue_reg_status & PCIE_AER_UCE_PTLP)
172*bf8fc234Set 			s_status |= PCI_STAT_PERROR;
173*bf8fc234Set 
174*bf8fc234Set 		if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
175*bf8fc234Set 			s_status |= PCI_STAT_S_TARG_AB;
176*bf8fc234Set 
177*bf8fc234Set 		sts = pf_tlp_decode(dip, &pf_data, &fault_bdf, &fault_addr,
178*bf8fc234Set 		    &trans_type);
179*bf8fc234Set 	}
180*bf8fc234Set 
181*bf8fc234Set 	if (sts == DDI_SUCCESS)
182*bf8fc234Set 		px_rp_en_q(px_p, fault_bdf, fault_addr, s_status);
183*bf8fc234Set }
184*bf8fc234Set 
185*bf8fc234Set /*
186*bf8fc234Set  * px_err_intr:
187f8d2de6bSjchu  * Interrupt handler for the JBC/DMC/PEC block.
188f8d2de6bSjchu  * o lock
189f8d2de6bSjchu  * o create derr
190f8d2de6bSjchu  * o check safe access
191*bf8fc234Set  * o px_err_check_severity(epkt)
192*bf8fc234Set  * o pcie_scan_fabric
193f8d2de6bSjchu  * o Idle intr state
194f8d2de6bSjchu  * o unlock
195f8d2de6bSjchu  * o handle error: fatal? fm_panic() : return INTR_CLAIMED)
196f8d2de6bSjchu  */
197f8d2de6bSjchu static uint_t
198*bf8fc234Set px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt)
199f8d2de6bSjchu {
200f8d2de6bSjchu 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip);
201f8d2de6bSjchu 	dev_info_t	*rpdip = px_p->px_dip;
202*bf8fc234Set 	int		rc_err, fab_err = PF_NO_PANIC, msg;
203f8d2de6bSjchu 	ddi_fm_error_t	derr;
204f8d2de6bSjchu 
20501689544Sjchu 	mutex_enter(&px_p->px_fm_mutex);
206f8d2de6bSjchu 
207f8d2de6bSjchu 	/* Create the derr */
208f8d2de6bSjchu 	bzero(&derr, sizeof (ddi_fm_error_t));
209f8d2de6bSjchu 	derr.fme_version = DDI_FME_VERSION;
210f8d2de6bSjchu 	derr.fme_ena = fm_ena_generate(epkt->stick, FM_ENA_FMT1);
211f8d2de6bSjchu 	derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
212f8d2de6bSjchu 
213f8d2de6bSjchu 	/* Basically check for safe access */
214*bf8fc234Set 	(void) px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_ALL);
215f8d2de6bSjchu 
216f8d2de6bSjchu 	/* Check the severity of this error */
217*bf8fc234Set 	rc_err = px_err_epkt_severity(px_p, &derr, epkt, PX_INTR_CALL);
218f8d2de6bSjchu 
219*bf8fc234Set 	/* Scan the fabric if the root port is not in drain state. */
220*bf8fc234Set 	if (!px_lib_is_in_drain_state(px_p))
221*bf8fc234Set 		fab_err = pf_scan_fabric(rpdip, &derr, px_p->px_dq_p,
222*bf8fc234Set 		    &px_p->px_dq_tail);
223f8d2de6bSjchu 
224f8d2de6bSjchu 	/* Set the intr state to idle for the leaf that received the mondo */
225f8d2de6bSjchu 	if (px_lib_intr_setstate(rpdip, fault_p->px_fh_sysino,
226f8d2de6bSjchu 		INTR_IDLE_STATE) != DDI_SUCCESS) {
22701689544Sjchu 		mutex_exit(&px_p->px_fm_mutex);
228f8d2de6bSjchu 		return (DDI_INTR_UNCLAIMED);
229f8d2de6bSjchu 	}
230f8d2de6bSjchu 
23101689544Sjchu 	mutex_exit(&px_p->px_fm_mutex);
232f8d2de6bSjchu 
233*bf8fc234Set 	switch (epkt->rc_descr.block) {
234*bf8fc234Set 	case BLOCK_MMU: /* FALLTHROUGH */
235*bf8fc234Set 	case BLOCK_INTR:
236*bf8fc234Set 		msg = PX_RC;
237*bf8fc234Set 		break;
238*bf8fc234Set 	case BLOCK_PCIE:
239*bf8fc234Set 		msg = PX_RP;
240*bf8fc234Set 		break;
241*bf8fc234Set 	case BLOCK_HOSTBUS: /* FALLTHROUGH */
242*bf8fc234Set 	default:
243*bf8fc234Set 		msg = PX_HB;
244*bf8fc234Set 		break;
245*bf8fc234Set 	}
246*bf8fc234Set 
247*bf8fc234Set 	px_err_panic(rc_err, msg, fab_err);
248f8d2de6bSjchu 
249f8d2de6bSjchu 	return (DDI_INTR_CLAIMED);
250f8d2de6bSjchu }
251f8d2de6bSjchu 
252f8d2de6bSjchu /*
253*bf8fc234Set  * px_err_epkt_severity:
254f8d2de6bSjchu  * Check the severity of the fire error based the epkt received
255f8d2de6bSjchu  *
256f8d2de6bSjchu  * @param px_p		leaf in which to take the snap shot.
257f8d2de6bSjchu  * @param derr		fm err in which the ereport is to be based on
258f8d2de6bSjchu  * @param epkt		epkt recevied from HV
259f8d2de6bSjchu  */
260f8d2de6bSjchu static int
261*bf8fc234Set px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt,
262f8d2de6bSjchu     int caller)
263f8d2de6bSjchu {
264f8d2de6bSjchu 	px_pec_t 	*pec_p = px_p->px_pec_p;
265f8d2de6bSjchu 	dev_info_t	*dip = px_p->px_dip;
266*bf8fc234Set 	boolean_t	is_safeacc = B_FALSE;
267*bf8fc234Set 	boolean_t	is_block_pci = B_FALSE;
268*bf8fc234Set 	char		buf[FM_MAX_CLASS], descr_buf[1024];
269f8d2de6bSjchu 	int		err = 0;
270f8d2de6bSjchu 
271f8d2de6bSjchu 	/* Cautious access error handling  */
272*bf8fc234Set 	switch (derr->fme_flag) {
273*bf8fc234Set 	case DDI_FM_ERR_EXPECTED:
274f8d2de6bSjchu 		if (caller == PX_TRAP_CALL) {
275f8d2de6bSjchu 			/*
276f8d2de6bSjchu 			 * for ddi_caut_get treat all events as nonfatal
277f8d2de6bSjchu 			 * The trampoline will set err_ena = 0,
278f8d2de6bSjchu 			 * err_status = NONFATAL.
279f8d2de6bSjchu 			 */
280f8d2de6bSjchu 			derr->fme_status = DDI_FM_NONFATAL;
281*bf8fc234Set 			is_safeacc = B_TRUE;
282f8d2de6bSjchu 		} else {
283f8d2de6bSjchu 			/*
284f8d2de6bSjchu 			 * For ddi_caut_put treat all events as nonfatal. Here
285f8d2de6bSjchu 			 * we have the handle and can call ndi_fm_acc_err_set().
286f8d2de6bSjchu 			 */
287f8d2de6bSjchu 			derr->fme_status = DDI_FM_NONFATAL;
288f8d2de6bSjchu 			ndi_fm_acc_err_set(pec_p->pec_acc_hdl, derr);
289*bf8fc234Set 			is_safeacc = B_TRUE;
290f8d2de6bSjchu 		}
291*bf8fc234Set 		break;
292*bf8fc234Set 	case DDI_FM_ERR_PEEK:
293*bf8fc234Set 	case DDI_FM_ERR_POKE:
294*bf8fc234Set 		/*
295*bf8fc234Set 		 * For ddi_peek/poke treat all events as nonfatal.
296*bf8fc234Set 		 */
297*bf8fc234Set 		is_safeacc = B_TRUE;
298*bf8fc234Set 		break;
299*bf8fc234Set 	default:
300*bf8fc234Set 		is_safeacc = B_FALSE;
301f8d2de6bSjchu 	}
302f8d2de6bSjchu 
303*bf8fc234Set 	/*
304*bf8fc234Set 	 * Older hypervisors in some cases send epkts with incorrect fields.
305*bf8fc234Set 	 * We have to handle these "special" epkts correctly.
306*bf8fc234Set 	 */
307*bf8fc234Set 	if (px_legacy_epkt)
308*bf8fc234Set 		px_fix_legacy_epkt(dip, derr, epkt);
309*bf8fc234Set 
310f8d2de6bSjchu 	switch (epkt->rc_descr.block) {
311f8d2de6bSjchu 	case BLOCK_HOSTBUS:
312*bf8fc234Set 		err = px_cb_epkt_severity(dip, derr, epkt);
313f8d2de6bSjchu 		break;
314f8d2de6bSjchu 	case BLOCK_MMU:
315*bf8fc234Set 		err = px_mmu_epkt_severity(dip, derr, epkt);
316*bf8fc234Set 		px_err_fill_pfd(dip, px_p, epkt);
317f8d2de6bSjchu 		break;
318f8d2de6bSjchu 	case BLOCK_INTR:
319*bf8fc234Set 		err = px_intr_epkt_severity(dip, derr, epkt);
320f8d2de6bSjchu 		break;
321f8d2de6bSjchu 	case BLOCK_PCIE:
322*bf8fc234Set 		is_block_pci = B_TRUE;
323*bf8fc234Set 		err = px_pcie_epkt_severity(dip, derr, epkt);
324*bf8fc234Set 		px_err_fill_pfd(dip, px_p, epkt);
325f8d2de6bSjchu 		break;
326f8d2de6bSjchu 	default:
327*bf8fc234Set 		err = 0;
328f8d2de6bSjchu 	}
329f8d2de6bSjchu 
330*bf8fc234Set 	if ((err & PX_HW_RESET) || (err & PX_PANIC)) {
331*bf8fc234Set 		if (px_log & PX_PANIC)
332*bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "PANIC");
333*bf8fc234Set 	} else if (err & PX_PROTECTED) {
334*bf8fc234Set 		if (px_log & PX_PROTECTED)
335*bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "PROTECTED");
336*bf8fc234Set 	} else if (err & PX_NO_PANIC) {
337*bf8fc234Set 		if (px_log & PX_NO_PANIC)
338*bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "NO PANIC");
339*bf8fc234Set 	} else if (err & PX_NO_ERROR) {
340*bf8fc234Set 		if (px_log & PX_NO_ERROR)
341*bf8fc234Set 			px_err_log_handle(dip, epkt, is_block_pci, "NO ERROR");
342*bf8fc234Set 	} else if (err == 0) {
343*bf8fc234Set 		px_err_log_handle(dip, epkt, is_block_pci, "UNRECOGNIZED");
344*bf8fc234Set 
345*bf8fc234Set 		/* Unrecognized epkt. send ereport */
346*bf8fc234Set 		(void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_RC_UNRECOG);
347*bf8fc234Set 
348*bf8fc234Set 		if (is_block_pci) {
349*bf8fc234Set 			px_pec_err_t	*pec = (px_pec_err_t *)epkt;
350*bf8fc234Set 
351*bf8fc234Set 			(void) snprintf(descr_buf, sizeof (descr_buf),
352*bf8fc234Set 			    "Epkt contents:\n"
353*bf8fc234Set 			    "Block: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d\n"
354*bf8fc234Set 			    "I=%d, H=%d, C=%d, U=%d, E=%d, P=%d\n"
355*bf8fc234Set 			    "PCI Err Status: 0x%x, PCIe Err Status: 0x%x\n"
356*bf8fc234Set 			    "CE Status Reg: 0x%x, UE Status Reg: 0x%x\n"
357*bf8fc234Set 			    "HDR1: 0x%lx, HDR2: 0x%lx\n"
358*bf8fc234Set 			    "Err Src Reg: 0x%x, Root Err Status: 0x%x\n",
359*bf8fc234Set 			    pec->pec_descr.block, pec->pec_descr.dir,
360*bf8fc234Set 			    pec->pec_descr.Z, pec->pec_descr.S,
361*bf8fc234Set 			    pec->pec_descr.R, pec->pec_descr.I,
362*bf8fc234Set 			    pec->pec_descr.H, pec->pec_descr.C,
363*bf8fc234Set 			    pec->pec_descr.U, pec->pec_descr.E,
364*bf8fc234Set 			    pec->pec_descr.P, pec->pci_err_status,
365*bf8fc234Set 			    pec->pcie_err_status, pec->ce_reg_status,
366*bf8fc234Set 			    pec->ue_reg_status, pec->hdr[0],
367*bf8fc234Set 			    pec->hdr[1], pec->err_src_reg,
368*bf8fc234Set 			    pec->root_err_status);
369*bf8fc234Set 
370*bf8fc234Set 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
371*bf8fc234Set 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
372*bf8fc234Set 			    EPKT_SYSINO, DATA_TYPE_UINT64, pec->sysino,
373*bf8fc234Set 			    EPKT_EHDL, DATA_TYPE_UINT64, pec->ehdl,
374*bf8fc234Set 			    EPKT_STICK, DATA_TYPE_UINT64, pec->stick,
375*bf8fc234Set 			    EPKT_PEC_DESCR, DATA_TYPE_STRING, descr_buf);
376*bf8fc234Set 		} else {
377*bf8fc234Set 			(void) snprintf(descr_buf, sizeof (descr_buf),
378*bf8fc234Set 			    "Epkt contents:\n"
379*bf8fc234Set 			    "Block: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
380*bf8fc234Set 			    "Dir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d\n"
381*bf8fc234Set 			    "M=%d, S=%d, Size: 0x%x, Addr: 0x%lx\n"
382*bf8fc234Set 			    "Hdr1: 0x%lx, Hdr2: 0x%lx, Res: 0x%lx\n",
383*bf8fc234Set 			    epkt->rc_descr.block, epkt->rc_descr.op,
384*bf8fc234Set 			    epkt->rc_descr.phase, epkt->rc_descr.cond,
385*bf8fc234Set 			    epkt->rc_descr.dir, epkt->rc_descr.STOP,
386*bf8fc234Set 			    epkt->rc_descr.H, epkt->rc_descr.R,
387*bf8fc234Set 			    epkt->rc_descr.D, epkt->rc_descr.M,
388*bf8fc234Set 			    epkt->rc_descr.S, epkt->size, epkt->addr,
389*bf8fc234Set 			    epkt->hdr[0], epkt->hdr[1], epkt->reserved);
390*bf8fc234Set 
391*bf8fc234Set 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
392*bf8fc234Set 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
393*bf8fc234Set 			    EPKT_SYSINO, DATA_TYPE_UINT64, epkt->sysino,
394*bf8fc234Set 			    EPKT_EHDL, DATA_TYPE_UINT64, epkt->ehdl,
395*bf8fc234Set 			    EPKT_STICK, DATA_TYPE_UINT64, epkt->stick,
396*bf8fc234Set 			    EPKT_RC_DESCR, DATA_TYPE_STRING, descr_buf);
397*bf8fc234Set 		}
398*bf8fc234Set 
399*bf8fc234Set 		err = PX_PANIC;
400*bf8fc234Set 	}
401*bf8fc234Set 
402*bf8fc234Set 	/* Readjust the severity as a result of safe access */
403*bf8fc234Set 	if (is_safeacc && !(err & PX_PANIC) && !(px_die & PX_PROTECTED))
404*bf8fc234Set 		err = PX_NO_PANIC;
405*bf8fc234Set 
406f8d2de6bSjchu 	return (err);
407f8d2de6bSjchu }
408f8d2de6bSjchu 
409*bf8fc234Set static void
410*bf8fc234Set px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt, boolean_t is_block_pci,
411*bf8fc234Set     char *msg)
412*bf8fc234Set {
413*bf8fc234Set 	if (is_block_pci) {
414*bf8fc234Set 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
415*bf8fc234Set 		DBG(DBG_ERR_INTR, dip,
416*bf8fc234Set 		    "A PCIe root port error has occured with a severity"
417*bf8fc234Set 		    " \"%s\"\n"
418*bf8fc234Set 		    "\tBlock: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d, I=%d\n"
419*bf8fc234Set 		    "\tH=%d, C=%d, U=%d, E=%d, P=%d\n"
420*bf8fc234Set 		    "\tpci_err: 0x%x, pcie_err=0x%x, ce_reg: 0x%x\n"
421*bf8fc234Set 		    "\tue_reg: 0x%x, Hdr1: 0x%p, Hdr2: 0x%p\n"
422*bf8fc234Set 		    "\terr_src: 0x%x, root_err: 0x%x\n",
423*bf8fc234Set 		    msg, pec->pec_descr.block, pec->pec_descr.dir,
424*bf8fc234Set 		    pec->pec_descr.Z, pec->pec_descr.S, pec->pec_descr.R,
425*bf8fc234Set 		    pec->pec_descr.I, pec->pec_descr.H, pec->pec_descr.C,
426*bf8fc234Set 		    pec->pec_descr.U, pec->pec_descr.E, pec->pec_descr.P,
427*bf8fc234Set 		    pec->pci_err_status, pec->pcie_err_status,
428*bf8fc234Set 		    pec->ce_reg_status, pec->ue_reg_status, pec->hdr[0],
429*bf8fc234Set 		    pec->hdr[1], pec->err_src_reg, pec->root_err_status);
430*bf8fc234Set 	} else {
431*bf8fc234Set 		DBG(DBG_ERR_INTR, dip,
432*bf8fc234Set 		    "A PCIe root complex error has occured with a severity"
433*bf8fc234Set 		    " \"%s\"\n"
434*bf8fc234Set 		    "\tBlock: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
435*bf8fc234Set 		    "\tDir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d, M=%d\n"
436*bf8fc234Set 		    "\tS=%d, Size: 0x%x, Addr: 0x%p\n"
437*bf8fc234Set 		    "\tHdr1: 0x%p, Hdr2: 0x%p, Res: 0x%p\n",
438*bf8fc234Set 		    msg, epkt->rc_descr.block, epkt->rc_descr.op,
439*bf8fc234Set 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
440*bf8fc234Set 		    epkt->rc_descr.dir, epkt->rc_descr.STOP, epkt->rc_descr.H,
441*bf8fc234Set 		    epkt->rc_descr.R, epkt->rc_descr.D, epkt->rc_descr.M,
442*bf8fc234Set 		    epkt->rc_descr.S, epkt->size, epkt->addr, epkt->hdr[0],
443*bf8fc234Set 		    epkt->hdr[1], epkt->reserved);
444*bf8fc234Set 	}
445*bf8fc234Set }
446*bf8fc234Set 
447f8d2de6bSjchu /* ARGSUSED */
448*bf8fc234Set static void
449*bf8fc234Set px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
450f8d2de6bSjchu {
451*bf8fc234Set 	/*
452*bf8fc234Set 	 * We don't have a default case for any of the below switch statements
453*bf8fc234Set 	 * since we are ok with the code falling through.
454*bf8fc234Set 	 */
455*bf8fc234Set 	switch (epkt->rc_descr.block) {
456*bf8fc234Set 	case BLOCK_HOSTBUS:
457*bf8fc234Set 		switch (epkt->rc_descr.op) {
458*bf8fc234Set 		case OP_DMA:
459*bf8fc234Set 			switch (epkt->rc_descr.phase) {
460*bf8fc234Set 			case PH_UNKNOWN:
461*bf8fc234Set 				switch (epkt->rc_descr.cond) {
462*bf8fc234Set 				case CND_UNKNOWN:
463*bf8fc234Set 					switch (epkt->rc_descr.dir) {
464*bf8fc234Set 					case DIR_RESERVED:
465*bf8fc234Set 						epkt->rc_descr.dir = DIR_READ;
466*bf8fc234Set 						break;
467*bf8fc234Set 					} /* DIR */
468*bf8fc234Set 				} /* CND */
469*bf8fc234Set 			} /* PH */
470*bf8fc234Set 		} /* OP */
471f8d2de6bSjchu 		break;
472*bf8fc234Set 	case BLOCK_MMU:
473*bf8fc234Set 		switch (epkt->rc_descr.op) {
474*bf8fc234Set 		case OP_XLAT:
475*bf8fc234Set 			switch (epkt->rc_descr.phase) {
476*bf8fc234Set 			case PH_DATA:
477*bf8fc234Set 				switch (epkt->rc_descr.cond) {
478*bf8fc234Set 				case CND_PROT:
479*bf8fc234Set 					switch (epkt->rc_descr.dir) {
480*bf8fc234Set 					case DIR_UNKNOWN:
481*bf8fc234Set 						epkt->rc_descr.dir = DIR_WRITE;
482*bf8fc234Set 						break;
483*bf8fc234Set 					} /* DIR */
484*bf8fc234Set 				} /* CND */
4853d9c56a1Set 				break;
486*bf8fc234Set 			case PH_IRR:
487*bf8fc234Set 				switch (epkt->rc_descr.cond) {
488*bf8fc234Set 				case CND_RESERVED:
489*bf8fc234Set 					switch (epkt->rc_descr.dir) {
490*bf8fc234Set 					case DIR_IRR:
491*bf8fc234Set 						epkt->rc_descr.phase = PH_ADDR;
492*bf8fc234Set 						epkt->rc_descr.cond = CND_IRR;
493*bf8fc234Set 					} /* DIR */
494*bf8fc234Set 				} /* CND */
495*bf8fc234Set 			} /* PH */
496*bf8fc234Set 		} /* OP */
497e51949e6Sdduvall 		break;
498*bf8fc234Set 	case BLOCK_INTR:
499*bf8fc234Set 		switch (epkt->rc_descr.op) {
500*bf8fc234Set 		case OP_MSIQ:
501*bf8fc234Set 			switch (epkt->rc_descr.phase) {
502*bf8fc234Set 			case PH_UNKNOWN:
503*bf8fc234Set 				switch (epkt->rc_descr.cond) {
504*bf8fc234Set 				case CND_ILL:
505*bf8fc234Set 					switch (epkt->rc_descr.dir) {
506*bf8fc234Set 					case DIR_RESERVED:
507*bf8fc234Set 						epkt->rc_descr.dir = DIR_IRR;
508*bf8fc234Set 						break;
509*bf8fc234Set 					} /* DIR */
510*bf8fc234Set 					break;
511*bf8fc234Set 				case CND_IRR:
512*bf8fc234Set 					switch (epkt->rc_descr.dir) {
513*bf8fc234Set 					case DIR_IRR:
514*bf8fc234Set 						epkt->rc_descr.cond = CND_OV;
515*bf8fc234Set 						break;
516*bf8fc234Set 					} /* DIR */
517*bf8fc234Set 				} /* CND */
518*bf8fc234Set 			} /* PH */
519*bf8fc234Set 			break;
520*bf8fc234Set 		case OP_RESERVED:
521*bf8fc234Set 			switch (epkt->rc_descr.phase) {
522*bf8fc234Set 			case PH_UNKNOWN:
523*bf8fc234Set 				switch (epkt->rc_descr.cond) {
524*bf8fc234Set 				case CND_ILL:
525*bf8fc234Set 					switch (epkt->rc_descr.dir) {
526*bf8fc234Set 					case DIR_IRR:
527*bf8fc234Set 						epkt->rc_descr.op = OP_MSI32;
528*bf8fc234Set 						epkt->rc_descr.phase = PH_DATA;
529*bf8fc234Set 						break;
530*bf8fc234Set 					} /* DIR */
531*bf8fc234Set 				} /* CND */
532*bf8fc234Set 				break;
533*bf8fc234Set 			case PH_DATA:
534*bf8fc234Set 				switch (epkt->rc_descr.cond) {
535*bf8fc234Set 				case CND_INT:
536*bf8fc234Set 					switch (epkt->rc_descr.dir) {
537*bf8fc234Set 					case DIR_UNKNOWN:
538*bf8fc234Set 						epkt->rc_descr.op = OP_MSI32;
539*bf8fc234Set 						break;
540*bf8fc234Set 					} /* DIR */
541*bf8fc234Set 				} /* CND */
542*bf8fc234Set 			} /* PH */
543*bf8fc234Set 		} /* OP */
544*bf8fc234Set 	} /* BLOCK */
545*bf8fc234Set }
5463d9c56a1Set 
547*bf8fc234Set /* ARGSUSED */
548*bf8fc234Set static int
549*bf8fc234Set px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
550*bf8fc234Set {
551*bf8fc234Set 	return (px_err_check_eq(dip));
552*bf8fc234Set }
553*bf8fc234Set 
554*bf8fc234Set /* ARGSUSED */
555*bf8fc234Set static int
556*bf8fc234Set px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
557*bf8fc234Set {
558*bf8fc234Set 	px_pec_err_t	*pec = (px_pec_err_t *)epkt;
559*bf8fc234Set 	px_err_pcie_t	*pcie = (px_err_pcie_t *)epkt;
560*bf8fc234Set 	pf_data_t	pf_data;
561*bf8fc234Set 	int		x;
562*bf8fc234Set 	uint32_t	temp;
563f8d2de6bSjchu 
564f8d2de6bSjchu 	/*
565*bf8fc234Set 	 * Check for failed PIO Read/Writes, which are errors that are not
566*bf8fc234Set 	 * defined in the PCIe spec.
567f8d2de6bSjchu 	 */
568*bf8fc234Set 	temp = PCIE_AER_UCE_UR | PCIE_AER_UCE_CA;
569*bf8fc234Set 	if (((pec->pec_descr.dir == DIR_READ) || (pec->pec_descr.dir ==
570*bf8fc234Set 	    DIR_WRITE)) && pec->pec_descr.U && (pec->ue_reg_status == temp)) {
571*bf8fc234Set 		pf_data.aer_h0 = (uint32_t)(pec->hdr[0]);
572*bf8fc234Set 		pf_data.aer_h1 = (uint32_t)(pec->hdr[0] >> 32);
573*bf8fc234Set 		pf_data.aer_h2 = (uint32_t)(pec->hdr[1]);
574*bf8fc234Set 		pf_data.aer_h3 = (uint32_t)(pec->hdr[1] >> 32);
575*bf8fc234Set 
576*bf8fc234Set 		if (pf_tlp_hdl_lookup(dip, derr, &pf_data) != DDI_FM_UNKNOWN)
577*bf8fc234Set 			return (PX_NO_PANIC);
578f8d2de6bSjchu 		else
579*bf8fc234Set 			return (PX_PANIC);
580f8d2de6bSjchu 	}
581f8d2de6bSjchu 
582*bf8fc234Set 	if (!pec->pec_descr.C)
583*bf8fc234Set 		pec->ce_reg_status = 0;
584*bf8fc234Set 	if (!pec->pec_descr.U)
585*bf8fc234Set 		pec->ue_reg_status = 0;
586*bf8fc234Set 	if (!pec->pec_descr.H)
587*bf8fc234Set 		pec->hdr[0] = 0;
588*bf8fc234Set 	if (!pec->pec_descr.I)
589*bf8fc234Set 		pec->hdr[1] = 0;
590f8d2de6bSjchu 
591*bf8fc234Set 	/*
592*bf8fc234Set 	 * According to the PCIe spec, there is a first error pointer.  If there
593*bf8fc234Set 	 * are header logs recorded and there are more than one error, the log
594*bf8fc234Set 	 * will belong to the error that the first error pointer points to.
595*bf8fc234Set 	 *
596*bf8fc234Set 	 * The regs.primary_ue expects a bit number, go through the ue register
597*bf8fc234Set 	 * and find the first error that occured.  Because the sun4v epkt spec
598*bf8fc234Set 	 * does not define this value, the algorithm below gives the lower bit
599*bf8fc234Set 	 * priority.
600*bf8fc234Set 	 */
601*bf8fc234Set 	temp = pcie->ue_reg;
602*bf8fc234Set 	if (temp) {
603*bf8fc234Set 		for (x = 0; !(temp & 0x1); x++) {
604*bf8fc234Set 			temp = temp >> 1;
605*bf8fc234Set 		}
606*bf8fc234Set 		pcie->primary_ue = 1 << x;
607*bf8fc234Set 	} else {
608*bf8fc234Set 		pcie->primary_ue = 0;
6093d9c56a1Set 	}
610f8d2de6bSjchu 
611*bf8fc234Set 	/* Sun4v doesn't log the TX hdr except for CTOs */
612*bf8fc234Set 	if (pcie->primary_ue == PCIE_AER_UCE_TO) {
613*bf8fc234Set 		pcie->tx_hdr1 = pcie->rx_hdr1;
614*bf8fc234Set 		pcie->tx_hdr2 = pcie->rx_hdr2;
615*bf8fc234Set 		pcie->tx_hdr3 = pcie->rx_hdr3;
616*bf8fc234Set 		pcie->tx_hdr4 = pcie->rx_hdr4;
617*bf8fc234Set 		pcie->rx_hdr1 = 0;
618*bf8fc234Set 		pcie->rx_hdr2 = 0;
619*bf8fc234Set 		pcie->rx_hdr3 = 0;
620*bf8fc234Set 		pcie->rx_hdr4 = 0;
621*bf8fc234Set 	} else {
622*bf8fc234Set 		pcie->tx_hdr1 = 0;
623*bf8fc234Set 		pcie->tx_hdr2 = 0;
624*bf8fc234Set 		pcie->tx_hdr3 = 0;
625*bf8fc234Set 		pcie->tx_hdr4 = 0;
626*bf8fc234Set 	}
627e51949e6Sdduvall 
628*bf8fc234Set 	return (px_err_check_pcie(dip, derr, pcie));
629f8d2de6bSjchu }
630f8d2de6bSjchu 
631f8d2de6bSjchu static int
632*bf8fc234Set px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
633f8d2de6bSjchu {
634*bf8fc234Set 	uint32_t addr = (uint32_t)epkt->addr;
635*bf8fc234Set 	pcie_req_id_t bdf = NULL;
636f8d2de6bSjchu 
637*bf8fc234Set 	if (epkt->rc_descr.H) {
638*bf8fc234Set 		bdf = (uint32_t)((epkt->hdr[0] >> 16) && 0xFFFF);
639f8d2de6bSjchu 	}
640f8d2de6bSjchu 
641*bf8fc234Set 	return (pf_hdl_lookup(dip, derr->fme_ena, PF_DMA_ADDR, addr,
642*bf8fc234Set 		    bdf));
643f8d2de6bSjchu }
644