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"
538