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