xref: /onnv-gate/usr/src/uts/sun4v/io/px/px_err.c (revision 12076:f531e5ff251f)
127Sjchu /*
227Sjchu  * CDDL HEADER START
327Sjchu  *
427Sjchu  * The contents of this file are subject to the terms of the
51648Sjchu  * Common Development and Distribution License (the "License").
61648Sjchu  * You may not use this file except in compliance with the License.
727Sjchu  *
827Sjchu  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
927Sjchu  * or http://www.opensolaris.org/os/licensing.
1027Sjchu  * See the License for the specific language governing permissions
1127Sjchu  * and limitations under the License.
1227Sjchu  *
1327Sjchu  * When distributing Covered Code, include this CDDL HEADER in each
1427Sjchu  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1527Sjchu  * If applicable, add the following below this CDDL HEADER, with the
1627Sjchu  * fields enclosed by brackets "[]" replaced with your own identifying
1727Sjchu  * information: Portions Copyright [yyyy] [name of copyright owner]
1827Sjchu  *
1927Sjchu  * CDDL HEADER END
2027Sjchu  */
2127Sjchu /*
22*12076SKrishna.Elango@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2327Sjchu  */
2427Sjchu 
2527Sjchu /*
2627Sjchu  * sun4v Fire Error Handling
2727Sjchu  */
2827Sjchu 
2927Sjchu #include <sys/types.h>
3027Sjchu #include <sys/ddi.h>
3127Sjchu #include <sys/sunddi.h>
326313Skrishnae #include <sys/sunndi.h>
3327Sjchu #include <sys/fm/protocol.h>
3427Sjchu #include <sys/fm/util.h>
3527Sjchu #include <sys/membar.h>
3627Sjchu #include "px_obj.h"
3727Sjchu #include "px_err.h"
3827Sjchu 
3911596SJason.Beloro@Sun.COM static void px_err_fill_pfd(dev_info_t *dip, pf_data_t *pfd_p,
4011596SJason.Beloro@Sun.COM     px_rc_err_t *epkt);
413274Set142600 static uint_t px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt);
423274Set142600 static int  px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr,
4311596SJason.Beloro@Sun.COM     px_rc_err_t *epkt, pf_data_t *pfd_p);
4427Sjchu 
453274Set142600 static void px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt,
463274Set142600     boolean_t is_block_pci, char *msg);
476313Skrishnae static void px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
486313Skrishnae     boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
496313Skrishnae     boolean_t is_valid_epkt);
503274Set142600 static int px_cb_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
51*12076SKrishna.Elango@Sun.COM     px_rc_err_t *epkt, pf_data_t *pfd_p);
523274Set142600 static int px_mmu_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
53*12076SKrishna.Elango@Sun.COM     px_rc_err_t *epkt, pf_data_t *pfd_p);
543274Set142600 static int px_intr_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
55*12076SKrishna.Elango@Sun.COM     px_rc_err_t *epkt, pf_data_t *pfd_p);
5611304SJanie.Lu@Sun.COM static int px_port_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
5711596SJason.Beloro@Sun.COM     px_rc_err_t *epkt, pf_data_t *pfd_p);
583274Set142600 static int px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
59*12076SKrishna.Elango@Sun.COM     px_rc_err_t *epkt, pf_data_t *pfd_p);
603274Set142600 static int px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
61*12076SKrishna.Elango@Sun.COM     px_rc_err_t *epkt, pf_data_t *pfd_p);
6211304SJanie.Lu@Sun.COM static int px_port_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
6311596SJason.Beloro@Sun.COM     px_rc_err_t *epkt, pf_data_t *pfd_p);
643274Set142600 static void px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr,
653274Set142600     px_rc_err_t *epkt);
663274Set142600 static int px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr,
673274Set142600     px_rc_err_t *epkt);
683274Set142600 
693274Set142600 /* Include the code generated sun4v epkt checking code */
703274Set142600 #include "px_err_gen.c"
713274Set142600 
723274Set142600 /*
733274Set142600  * This variable indicates if we have a hypervisor that could potentially send
743274Set142600  * incorrect epkts. We always set this to TRUE for now until we find a way to
753274Set142600  * tell if this HV bug has been fixed.
763274Set142600  */
773274Set142600 boolean_t px_legacy_epkt = B_TRUE;
7827Sjchu 
7927Sjchu /*
8027Sjchu  * px_err_cb_intr:
8127Sjchu  * Interrupt handler for the Host Bus Block.
8227Sjchu  */
8327Sjchu uint_t
px_err_cb_intr(caddr_t arg)8427Sjchu px_err_cb_intr(caddr_t arg)
8527Sjchu {
8627Sjchu 	px_fault_t	*fault_p = (px_fault_t *)arg;
8727Sjchu 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
8827Sjchu 
8927Sjchu 	if (epkt != NULL) {
903274Set142600 		return (px_err_intr(fault_p, epkt));
9127Sjchu 	}
9227Sjchu 
9327Sjchu 	return (DDI_INTR_UNCLAIMED);
9427Sjchu }
9527Sjchu 
9627Sjchu /*
9727Sjchu  * px_err_dmc_pec_intr:
9827Sjchu  * Interrupt handler for the DMC/PEC block.
9927Sjchu  */
10027Sjchu uint_t
px_err_dmc_pec_intr(caddr_t arg)10127Sjchu px_err_dmc_pec_intr(caddr_t arg)
10227Sjchu {
10327Sjchu 	px_fault_t	*fault_p = (px_fault_t *)arg;
10427Sjchu 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
10527Sjchu 
10627Sjchu 	if (epkt != NULL) {
1073274Set142600 		return (px_err_intr(fault_p, epkt));
10827Sjchu 	}
10927Sjchu 
11027Sjchu 	return (DDI_INTR_UNCLAIMED);
11127Sjchu }
11227Sjchu 
11327Sjchu /*
1143274Set142600  * px_err_cmn_intr:
11527Sjchu  * Common function called by trap, mondo and fabric intr.
11627Sjchu  * This function is more meaningful in sun4u implementation.  Kept
11727Sjchu  * to mirror sun4u call stack.
11827Sjchu  * o check for safe access
1193274Set142600  * o create and queue RC info for later use in fabric scan.
1203274Set142600  *   o RUC/WUC, PTLP, MMU Errors(CA), UR
12127Sjchu  *
12227Sjchu  * @param px_p		leaf in which to check access
12327Sjchu  * @param derr		fm err data structure to be updated
12427Sjchu  * @param caller	PX_TRAP_CALL | PX_INTR_CALL
12527Sjchu  * @param chkjbc	whether to handle hostbus registers (ignored)
1263274Set142600  * @return err		PX_NO_PANIC | PX_PROTECTED |
1273274Set142600  *                      PX_PANIC | PX_HW_RESET | PX_EXPECTED
12827Sjchu  */
12927Sjchu /* ARGSUSED */
13027Sjchu int
px_err_cmn_intr(px_t * px_p,ddi_fm_error_t * derr,int caller,int block)1313274Set142600 px_err_cmn_intr(px_t *px_p, ddi_fm_error_t *derr, int caller, int block)
13227Sjchu {
13327Sjchu 	px_err_safeacc_check(px_p, derr);
13411654SKrishna.Elango@Sun.COM 	return (PX_NO_ERROR);
13527Sjchu }
13627Sjchu 
13727Sjchu /*
1383274Set142600  * fills RC specific fault data
1393274Set142600  */
1403274Set142600 static void
px_err_fill_pfd(dev_info_t * dip,pf_data_t * pfd_p,px_rc_err_t * epkt)14111596SJason.Beloro@Sun.COM px_err_fill_pfd(dev_info_t *dip, pf_data_t *pfd_p, px_rc_err_t *epkt) {
1426313Skrishnae 	pf_pcie_adv_err_regs_t adv_reg;
1439921SKrishna.Elango@Sun.COM 	pcie_req_id_t	fault_bdf = PCIE_INVALID_BDF;
1446313Skrishnae 	uint64_t	fault_addr = 0;
1453274Set142600 	uint16_t	s_status = 0;
146*12076SKrishna.Elango@Sun.COM 	px_pec_err_t	*pec_p;
147*12076SKrishna.Elango@Sun.COM 	uint32_t	dir;
1483274Set142600 
1493274Set142600 	/* Add an PCIE PF_DATA Entry */
150*12076SKrishna.Elango@Sun.COM 	switch (epkt->rc_descr.block) {
151*12076SKrishna.Elango@Sun.COM 	case BLOCK_MMU:
1523274Set142600 		/* Only PIO Fault Addresses are valid, this is DMA */
1533274Set142600 		s_status = PCI_STAT_S_TARG_AB;
1543274Set142600 		fault_addr = NULL;
1553274Set142600 
15611596SJason.Beloro@Sun.COM 		if (epkt->rc_descr.H) {
1573274Set142600 			fault_bdf = (pcie_req_id_t)(epkt->hdr[0] >> 16);
15811596SJason.Beloro@Sun.COM 			PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags =
15911596SJason.Beloro@Sun.COM 			    PF_AFFECTED_BDF;
16011596SJason.Beloro@Sun.COM 			PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf =
16111596SJason.Beloro@Sun.COM 			    fault_bdf;
16211654SKrishna.Elango@Sun.COM 		}
163*12076SKrishna.Elango@Sun.COM 		break;
164*12076SKrishna.Elango@Sun.COM 	case BLOCK_PCIE:
165*12076SKrishna.Elango@Sun.COM 		pec_p = (px_pec_err_t *)epkt;
166*12076SKrishna.Elango@Sun.COM 		dir = pec_p->pec_descr.dir;
1673274Set142600 
1683274Set142600 		/* translate RC UR/CA to legacy secondary errors */
1693274Set142600 		if ((dir == DIR_READ || dir == DIR_WRITE) &&
1703274Set142600 		    pec_p->pec_descr.U) {
1713274Set142600 			if (pec_p->ue_reg_status & PCIE_AER_UCE_UR)
1723274Set142600 				s_status |= PCI_STAT_R_MAST_AB;
1734853Segillett 			if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
1743274Set142600 				s_status |= PCI_STAT_R_TARG_AB;
1753274Set142600 		}
1763274Set142600 
1773274Set142600 		if (pec_p->ue_reg_status & PCIE_AER_UCE_PTLP)
1783274Set142600 			s_status |= PCI_STAT_PERROR;
1793274Set142600 
1803274Set142600 		if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
1813274Set142600 			s_status |= PCI_STAT_S_TARG_AB;
1823274Set142600 
18311654SKrishna.Elango@Sun.COM 		if (pec_p->pec_descr.H) {
18411654SKrishna.Elango@Sun.COM 			adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0] >>32);
18511654SKrishna.Elango@Sun.COM 			adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0]);
18611654SKrishna.Elango@Sun.COM 			adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1] >>32);
18711654SKrishna.Elango@Sun.COM 			adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1]);
18811654SKrishna.Elango@Sun.COM 
18911654SKrishna.Elango@Sun.COM 			if (pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg) ==
19011654SKrishna.Elango@Sun.COM 			    DDI_SUCCESS) {
19111654SKrishna.Elango@Sun.COM 				fault_bdf = adv_reg.pcie_ue_tgt_bdf;
19211654SKrishna.Elango@Sun.COM 				fault_addr = adv_reg.pcie_ue_tgt_addr;
19311654SKrishna.Elango@Sun.COM 				/*
19411654SKrishna.Elango@Sun.COM 				 * affected BDF is to be filled in by
19511654SKrishna.Elango@Sun.COM 				 * px_scan_fabric
19611654SKrishna.Elango@Sun.COM 				 */
19711654SKrishna.Elango@Sun.COM 			}
19811654SKrishna.Elango@Sun.COM 		}
199*12076SKrishna.Elango@Sun.COM 		break;
200*12076SKrishna.Elango@Sun.COM 	case BLOCK_HOSTBUS:
201*12076SKrishna.Elango@Sun.COM 	case BLOCK_INTR:
202*12076SKrishna.Elango@Sun.COM 	case BLOCK_PORT:
203*12076SKrishna.Elango@Sun.COM 		/*
204*12076SKrishna.Elango@Sun.COM 		 *  If the affected device information is available then we
205*12076SKrishna.Elango@Sun.COM 		 *  add the affected_bdf to the pfd, so the affected device
206*12076SKrishna.Elango@Sun.COM 		 *  will be scanned and added to the error q. This will then
207*12076SKrishna.Elango@Sun.COM 		 *  go through the pciev_eh code path and forgive the error
208*12076SKrishna.Elango@Sun.COM 		 *  as needed.
209*12076SKrishna.Elango@Sun.COM 		 */
210*12076SKrishna.Elango@Sun.COM 		if (PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags ==
211*12076SKrishna.Elango@Sun.COM 		    PF_AFFECTED_BDF)
212*12076SKrishna.Elango@Sun.COM 			fault_bdf = PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf;
213*12076SKrishna.Elango@Sun.COM 
214*12076SKrishna.Elango@Sun.COM 		break;
215*12076SKrishna.Elango@Sun.COM 	default:
216*12076SKrishna.Elango@Sun.COM 		break;
2173274Set142600 	}
2183274Set142600 
21911654SKrishna.Elango@Sun.COM 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = fault_bdf;
22011654SKrishna.Elango@Sun.COM 	PCIE_ROOT_FAULT(pfd_p)->scan_addr = (uint64_t)fault_addr;
22111654SKrishna.Elango@Sun.COM 	PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
22211596SJason.Beloro@Sun.COM }
22311596SJason.Beloro@Sun.COM 
22411596SJason.Beloro@Sun.COM /*
22511596SJason.Beloro@Sun.COM  * Convert error severity from PX internal values to PCIe Fabric values.  Most
22611596SJason.Beloro@Sun.COM  * are self explanitory, except PX_PROTECTED.  PX_PROTECTED will never be
22711596SJason.Beloro@Sun.COM  * returned as is if forgivable.
22811596SJason.Beloro@Sun.COM  */
229*12076SKrishna.Elango@Sun.COM static int
px_err_to_fab_sev(int * rc_err)230*12076SKrishna.Elango@Sun.COM px_err_to_fab_sev(int *rc_err) {
23111596SJason.Beloro@Sun.COM 	int fab_err = 0;
23211596SJason.Beloro@Sun.COM 
233*12076SKrishna.Elango@Sun.COM 	if (*rc_err & px_die) {
234*12076SKrishna.Elango@Sun.COM 		/*
235*12076SKrishna.Elango@Sun.COM 		 * Let fabric scan decide the final severity of the error.
236*12076SKrishna.Elango@Sun.COM 		 * This is needed incase IOV code needs to forgive the error.
237*12076SKrishna.Elango@Sun.COM 		 */
238*12076SKrishna.Elango@Sun.COM 		*rc_err = PX_FABRIC_SCAN;
239*12076SKrishna.Elango@Sun.COM 		fab_err |= PF_ERR_PANIC;
240*12076SKrishna.Elango@Sun.COM 	}
241*12076SKrishna.Elango@Sun.COM 
242*12076SKrishna.Elango@Sun.COM 	if (*rc_err & (PX_EXPECTED | PX_NO_PANIC))
24311596SJason.Beloro@Sun.COM 		fab_err |= PF_ERR_NO_PANIC;
24411596SJason.Beloro@Sun.COM 
245*12076SKrishna.Elango@Sun.COM 	if (*rc_err & PX_NO_ERROR)
24611596SJason.Beloro@Sun.COM 		fab_err |= PF_ERR_NO_ERROR;
24711596SJason.Beloro@Sun.COM 
24811596SJason.Beloro@Sun.COM 	return (fab_err);
2493274Set142600 }
2503274Set142600 
2513274Set142600 /*
2523274Set142600  * px_err_intr:
25327Sjchu  * Interrupt handler for the JBC/DMC/PEC block.
25427Sjchu  * o lock
25527Sjchu  * o create derr
25627Sjchu  * o check safe access
2573274Set142600  * o px_err_check_severity(epkt)
2583274Set142600  * o pcie_scan_fabric
25927Sjchu  * o Idle intr state
26027Sjchu  * o unlock
26127Sjchu  * o handle error: fatal? fm_panic() : return INTR_CLAIMED)
26227Sjchu  */
26327Sjchu static uint_t
px_err_intr(px_fault_t * fault_p,px_rc_err_t * epkt)2643274Set142600 px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt)
26527Sjchu {
26627Sjchu 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip);
26727Sjchu 	dev_info_t	*rpdip = px_p->px_dip;
268*12076SKrishna.Elango@Sun.COM 	int		rc_err, tmp_rc_err, fab_err, msg;
26927Sjchu 	ddi_fm_error_t	derr;
27011596SJason.Beloro@Sun.COM 	pf_data_t	*pfd_p;
27127Sjchu 
2726313Skrishnae 	if (px_fm_enter(px_p) != DDI_SUCCESS)
2736313Skrishnae 		goto done;
27427Sjchu 
27511596SJason.Beloro@Sun.COM 	pfd_p = px_get_pfd(px_p);
27611596SJason.Beloro@Sun.COM 	PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_INTERNAL;
27711596SJason.Beloro@Sun.COM 	PCIE_ROOT_EH_SRC(pfd_p)->intr_data = epkt;
27811596SJason.Beloro@Sun.COM 
27927Sjchu 	/* Create the derr */
28027Sjchu 	bzero(&derr, sizeof (ddi_fm_error_t));
28127Sjchu 	derr.fme_version = DDI_FME_VERSION;
28227Sjchu 	derr.fme_ena = fm_ena_generate(epkt->stick, FM_ENA_FMT1);
28327Sjchu 	derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
28427Sjchu 
28527Sjchu 	/* Basically check for safe access */
2863274Set142600 	(void) px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_ALL);
28727Sjchu 
28827Sjchu 	/* Check the severity of this error */
28911596SJason.Beloro@Sun.COM 	rc_err = px_err_epkt_severity(px_p, &derr, epkt, pfd_p);
29011596SJason.Beloro@Sun.COM 
291*12076SKrishna.Elango@Sun.COM 	/* Pass the 'rc_err' severity to the fabric scan code. */
292*12076SKrishna.Elango@Sun.COM 	tmp_rc_err = rc_err;
293*12076SKrishna.Elango@Sun.COM 	pfd_p->pe_severity_flags = px_err_to_fab_sev(&rc_err);
29427Sjchu 
295*12076SKrishna.Elango@Sun.COM 	/* Scan the fabric */
296*12076SKrishna.Elango@Sun.COM 	if (!(fab_err = px_scan_fabric(px_p, rpdip, &derr))) {
297*12076SKrishna.Elango@Sun.COM 		/*
298*12076SKrishna.Elango@Sun.COM 		 * Fabric scan didn't occur because of some error condition
299*12076SKrishna.Elango@Sun.COM 		 * such as Root Port being in drain state, so reset rc_err.
300*12076SKrishna.Elango@Sun.COM 		 */
301*12076SKrishna.Elango@Sun.COM 		rc_err = tmp_rc_err;
302*12076SKrishna.Elango@Sun.COM 	}
30327Sjchu 
30427Sjchu 	/* Set the intr state to idle for the leaf that received the mondo */
30527Sjchu 	if (px_lib_intr_setstate(rpdip, fault_p->px_fh_sysino,
3064853Segillett 	    INTR_IDLE_STATE) != DDI_SUCCESS) {
3076313Skrishnae 		px_fm_exit(px_p);
30827Sjchu 		return (DDI_INTR_UNCLAIMED);
30927Sjchu 	}
31027Sjchu 
3113274Set142600 	switch (epkt->rc_descr.block) {
3123274Set142600 	case BLOCK_MMU: /* FALLTHROUGH */
3133274Set142600 	case BLOCK_INTR:
3143274Set142600 		msg = PX_RC;
3153274Set142600 		break;
3163274Set142600 	case BLOCK_PCIE:
3173274Set142600 		msg = PX_RP;
3183274Set142600 		break;
3193274Set142600 	case BLOCK_HOSTBUS: /* FALLTHROUGH */
3203274Set142600 	default:
3213274Set142600 		msg = PX_HB;
3223274Set142600 		break;
3233274Set142600 	}
3243274Set142600 
3256313Skrishnae 	px_err_panic(rc_err, msg, fab_err, B_TRUE);
3266313Skrishnae 	px_fm_exit(px_p);
3276313Skrishnae 	px_err_panic(rc_err, msg, fab_err, B_FALSE);
32827Sjchu 
3296313Skrishnae done:
33027Sjchu 	return (DDI_INTR_CLAIMED);
33127Sjchu }
33227Sjchu 
33327Sjchu /*
3343274Set142600  * px_err_epkt_severity:
33527Sjchu  * Check the severity of the fire error based the epkt received
33627Sjchu  *
33727Sjchu  * @param px_p		leaf in which to take the snap shot.
33827Sjchu  * @param derr		fm err in which the ereport is to be based on
33927Sjchu  * @param epkt		epkt recevied from HV
34027Sjchu  */
34127Sjchu 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)3423274Set142600 px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt,
34311596SJason.Beloro@Sun.COM     pf_data_t *pfd_p)
34427Sjchu {
34527Sjchu 	px_pec_t 	*pec_p = px_p->px_pec_p;
34627Sjchu 	dev_info_t	*dip = px_p->px_dip;
3473274Set142600 	boolean_t	is_safeacc = B_FALSE;
3483274Set142600 	boolean_t	is_block_pci = B_FALSE;
3496313Skrishnae 	boolean_t	is_valid_epkt = B_FALSE;
35027Sjchu 	int		err = 0;
35127Sjchu 
35227Sjchu 	/* Cautious access error handling  */
3533274Set142600 	switch (derr->fme_flag) {
3543274Set142600 	case DDI_FM_ERR_EXPECTED:
35511596SJason.Beloro@Sun.COM 		/*
35611596SJason.Beloro@Sun.COM 		 * For ddi_caut_put treat all events as nonfatal. Here
35711596SJason.Beloro@Sun.COM 		 * we have the handle and can call ndi_fm_acc_err_set().
35811596SJason.Beloro@Sun.COM 		 */
35911596SJason.Beloro@Sun.COM 		derr->fme_status = DDI_FM_NONFATAL;
36011596SJason.Beloro@Sun.COM 		ndi_fm_acc_err_set(pec_p->pec_acc_hdl, derr);
36111596SJason.Beloro@Sun.COM 		is_safeacc = B_TRUE;
3623274Set142600 		break;
3633274Set142600 	case DDI_FM_ERR_PEEK:
3643274Set142600 	case DDI_FM_ERR_POKE:
3653274Set142600 		/*
3663274Set142600 		 * For ddi_peek/poke treat all events as nonfatal.
3673274Set142600 		 */
3683274Set142600 		is_safeacc = B_TRUE;
3693274Set142600 		break;
3703274Set142600 	default:
3713274Set142600 		is_safeacc = B_FALSE;
37227Sjchu 	}
37327Sjchu 
3743274Set142600 	/*
3753274Set142600 	 * Older hypervisors in some cases send epkts with incorrect fields.
3763274Set142600 	 * We have to handle these "special" epkts correctly.
3773274Set142600 	 */
3783274Set142600 	if (px_legacy_epkt)
3793274Set142600 		px_fix_legacy_epkt(dip, derr, epkt);
3803274Set142600 
381*12076SKrishna.Elango@Sun.COM 	/*
382*12076SKrishna.Elango@Sun.COM 	 * The affected device by default is set to 'SELF'. The 'block'
383*12076SKrishna.Elango@Sun.COM 	 * specific error handling below will update this as needed.
384*12076SKrishna.Elango@Sun.COM 	 */
385*12076SKrishna.Elango@Sun.COM 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
386*12076SKrishna.Elango@Sun.COM 
38727Sjchu 	switch (epkt->rc_descr.block) {
38827Sjchu 	case BLOCK_HOSTBUS:
389*12076SKrishna.Elango@Sun.COM 		err = px_cb_epkt_severity(dip, derr, epkt, pfd_p);
39027Sjchu 		break;
39127Sjchu 	case BLOCK_MMU:
392*12076SKrishna.Elango@Sun.COM 		err = px_mmu_epkt_severity(dip, derr, epkt, pfd_p);
39327Sjchu 		break;
39427Sjchu 	case BLOCK_INTR:
395*12076SKrishna.Elango@Sun.COM 		err = px_intr_epkt_severity(dip, derr, epkt, pfd_p);
39627Sjchu 		break;
39711304SJanie.Lu@Sun.COM 	case BLOCK_PORT:
39811596SJason.Beloro@Sun.COM 		err = px_port_epkt_severity(dip, derr, epkt, pfd_p);
39911304SJanie.Lu@Sun.COM 		break;
40027Sjchu 	case BLOCK_PCIE:
4013274Set142600 		is_block_pci = B_TRUE;
402*12076SKrishna.Elango@Sun.COM 		err = px_pcie_epkt_severity(dip, derr, epkt, pfd_p);
40327Sjchu 		break;
40427Sjchu 	default:
4053274Set142600 		err = 0;
4063274Set142600 	}
4073274Set142600 
408*12076SKrishna.Elango@Sun.COM 	px_err_fill_pfd(dip, pfd_p, epkt);
409*12076SKrishna.Elango@Sun.COM 
4103274Set142600 	if ((err & PX_HW_RESET) || (err & PX_PANIC)) {
4113274Set142600 		if (px_log & PX_PANIC)
4123274Set142600 			px_err_log_handle(dip, epkt, is_block_pci, "PANIC");
4136313Skrishnae 		is_valid_epkt = B_TRUE;
4143274Set142600 	} else if (err & PX_PROTECTED) {
4153274Set142600 		if (px_log & PX_PROTECTED)
4163274Set142600 			px_err_log_handle(dip, epkt, is_block_pci, "PROTECTED");
4176313Skrishnae 		is_valid_epkt = B_TRUE;
4183274Set142600 	} else if (err & PX_NO_PANIC) {
4193274Set142600 		if (px_log & PX_NO_PANIC)
4203274Set142600 			px_err_log_handle(dip, epkt, is_block_pci, "NO PANIC");
4216313Skrishnae 		is_valid_epkt = B_TRUE;
4223274Set142600 	} else if (err & PX_NO_ERROR) {
4233274Set142600 		if (px_log & PX_NO_ERROR)
4243274Set142600 			px_err_log_handle(dip, epkt, is_block_pci, "NO ERROR");
4256313Skrishnae 		is_valid_epkt = B_TRUE;
4263274Set142600 	} else if (err == 0) {
4273274Set142600 		px_err_log_handle(dip, epkt, is_block_pci, "UNRECOGNIZED");
4286313Skrishnae 		is_valid_epkt = B_FALSE;
4293274Set142600 
4306313Skrishnae 		/* Panic on a unrecognized epkt */
4313274Set142600 		err = PX_PANIC;
4323270Set142600 	}
4333270Set142600 
4346313Skrishnae 	px_err_send_epkt_erpt(dip, epkt, is_block_pci, err, derr,
4356313Skrishnae 	    is_valid_epkt);
4366313Skrishnae 
4373274Set142600 	/* Readjust the severity as a result of safe access */
4383274Set142600 	if (is_safeacc && !(err & PX_PANIC) && !(px_die & PX_PROTECTED))
4393274Set142600 		err = PX_NO_PANIC;
4403274Set142600 
44127Sjchu 	return (err);
44227Sjchu }
44327Sjchu 
4443274Set142600 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)4456313Skrishnae px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
4466313Skrishnae     boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
4476313Skrishnae     boolean_t is_valid_epkt)
4486313Skrishnae {
4496313Skrishnae 	char buf[FM_MAX_CLASS], descr_buf[1024];
4506313Skrishnae 
4516313Skrishnae 	/* send ereport for debug purposes */
4526313Skrishnae 	(void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_RC_UNRECOG);
4536313Skrishnae 
4546313Skrishnae 	if (is_block_pci) {
4556313Skrishnae 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
4566313Skrishnae 		(void) snprintf(descr_buf, sizeof (descr_buf),
4576313Skrishnae 		    "%s Epkt contents:\n"
4586313Skrishnae 		    "Block: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d\n"
4596313Skrishnae 		    "I=%d, H=%d, C=%d, U=%d, E=%d, P=%d\n"
4606313Skrishnae 		    "PCI Err Status: 0x%x, PCIe Err Status: 0x%x\n"
4616313Skrishnae 		    "CE Status Reg: 0x%x, UE Status Reg: 0x%x\n"
4626313Skrishnae 		    "HDR1: 0x%lx, HDR2: 0x%lx\n"
4636313Skrishnae 		    "Err Src Reg: 0x%x, Root Err Status: 0x%x\n"
4646313Skrishnae 		    "Err Severity: 0x%x\n",
4656313Skrishnae 		    is_valid_epkt ? "Valid" : "Invalid",
4666313Skrishnae 		    pec->pec_descr.block, pec->pec_descr.dir,
4676313Skrishnae 		    pec->pec_descr.Z, pec->pec_descr.S,
4686313Skrishnae 		    pec->pec_descr.R, pec->pec_descr.I,
4696313Skrishnae 		    pec->pec_descr.H, pec->pec_descr.C,
4706313Skrishnae 		    pec->pec_descr.U, pec->pec_descr.E,
4716313Skrishnae 		    pec->pec_descr.P, pec->pci_err_status,
4726313Skrishnae 		    pec->pcie_err_status, pec->ce_reg_status,
4736313Skrishnae 		    pec->ue_reg_status, pec->hdr[0],
4746313Skrishnae 		    pec->hdr[1], pec->err_src_reg,
4756313Skrishnae 		    pec->root_err_status, err);
4766313Skrishnae 
4776313Skrishnae 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
4786313Skrishnae 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
4796313Skrishnae 		    EPKT_SYSINO, DATA_TYPE_UINT64,
4806313Skrishnae 		    is_valid_epkt ? pec->sysino : 0,
4816313Skrishnae 		    EPKT_EHDL, DATA_TYPE_UINT64,
4826313Skrishnae 		    is_valid_epkt ? pec->ehdl : 0,
4836313Skrishnae 		    EPKT_STICK, DATA_TYPE_UINT64,
4846313Skrishnae 		    is_valid_epkt ? pec->stick : 0,
48511304SJanie.Lu@Sun.COM 		    EPKT_DW0, DATA_TYPE_UINT64, ((uint64_t *)pec)[3],
48611304SJanie.Lu@Sun.COM 		    EPKT_DW1, DATA_TYPE_UINT64, ((uint64_t *)pec)[4],
48711304SJanie.Lu@Sun.COM 		    EPKT_DW2, DATA_TYPE_UINT64, ((uint64_t *)pec)[5],
48811304SJanie.Lu@Sun.COM 		    EPKT_DW3, DATA_TYPE_UINT64, ((uint64_t *)pec)[6],
48911304SJanie.Lu@Sun.COM 		    EPKT_DW4, DATA_TYPE_UINT64, ((uint64_t *)pec)[7],
4906313Skrishnae 		    EPKT_PEC_DESCR, DATA_TYPE_STRING, descr_buf);
4916313Skrishnae 	} else {
4926313Skrishnae 		(void) snprintf(descr_buf, sizeof (descr_buf),
4936313Skrishnae 		    "%s Epkt contents:\n"
4946313Skrishnae 		    "Block: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
4956313Skrishnae 		    "Dir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d\n"
4966313Skrishnae 		    "M=%d, S=%d, Size: 0x%x, Addr: 0x%lx\n"
4976313Skrishnae 		    "Hdr1: 0x%lx, Hdr2: 0x%lx, Res: 0x%lx\n"
4986313Skrishnae 		    "Err Severity: 0x%x\n",
4996313Skrishnae 		    is_valid_epkt ? "Valid" : "Invalid",
5006313Skrishnae 		    epkt->rc_descr.block, epkt->rc_descr.op,
5016313Skrishnae 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
5026313Skrishnae 		    epkt->rc_descr.dir, epkt->rc_descr.STOP,
5036313Skrishnae 		    epkt->rc_descr.H, epkt->rc_descr.R,
5046313Skrishnae 		    epkt->rc_descr.D, epkt->rc_descr.M,
5056313Skrishnae 		    epkt->rc_descr.S, epkt->size, epkt->addr,
5066313Skrishnae 		    epkt->hdr[0], epkt->hdr[1], epkt->reserved,
5076313Skrishnae 		    err);
5086313Skrishnae 
5096313Skrishnae 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
5106313Skrishnae 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
5116313Skrishnae 		    EPKT_SYSINO, DATA_TYPE_UINT64,
5126313Skrishnae 		    is_valid_epkt ? epkt->sysino : 0,
5136313Skrishnae 		    EPKT_EHDL, DATA_TYPE_UINT64,
5146313Skrishnae 		    is_valid_epkt ? epkt->ehdl : 0,
5156313Skrishnae 		    EPKT_STICK, DATA_TYPE_UINT64,
5166313Skrishnae 		    is_valid_epkt ? epkt->stick : 0,
51711304SJanie.Lu@Sun.COM 		    EPKT_DW0, DATA_TYPE_UINT64, ((uint64_t *)epkt)[3],
51811304SJanie.Lu@Sun.COM 		    EPKT_DW1, DATA_TYPE_UINT64, ((uint64_t *)epkt)[4],
51911304SJanie.Lu@Sun.COM 		    EPKT_DW2, DATA_TYPE_UINT64, ((uint64_t *)epkt)[5],
52011304SJanie.Lu@Sun.COM 		    EPKT_DW3, DATA_TYPE_UINT64, ((uint64_t *)epkt)[6],
52111304SJanie.Lu@Sun.COM 		    EPKT_DW4, DATA_TYPE_UINT64, ((uint64_t *)epkt)[7],
5226313Skrishnae 		    EPKT_RC_DESCR, DATA_TYPE_STRING, descr_buf);
5236313Skrishnae 	}
5246313Skrishnae }
5256313Skrishnae 
5266313Skrishnae static void
px_err_log_handle(dev_info_t * dip,px_rc_err_t * epkt,boolean_t is_block_pci,char * msg)5273274Set142600 px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt, boolean_t is_block_pci,
5283274Set142600     char *msg)
5293274Set142600 {
5303274Set142600 	if (is_block_pci) {
5313274Set142600 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
5323274Set142600 		DBG(DBG_ERR_INTR, dip,
5333274Set142600 		    "A PCIe root port error has occured with a severity"
5343274Set142600 		    " \"%s\"\n"
5353274Set142600 		    "\tBlock: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d, I=%d\n"
5363274Set142600 		    "\tH=%d, C=%d, U=%d, E=%d, P=%d\n"
5373274Set142600 		    "\tpci_err: 0x%x, pcie_err=0x%x, ce_reg: 0x%x\n"
5383274Set142600 		    "\tue_reg: 0x%x, Hdr1: 0x%p, Hdr2: 0x%p\n"
5393274Set142600 		    "\terr_src: 0x%x, root_err: 0x%x\n",
5403274Set142600 		    msg, pec->pec_descr.block, pec->pec_descr.dir,
5413274Set142600 		    pec->pec_descr.Z, pec->pec_descr.S, pec->pec_descr.R,
5423274Set142600 		    pec->pec_descr.I, pec->pec_descr.H, pec->pec_descr.C,
5433274Set142600 		    pec->pec_descr.U, pec->pec_descr.E, pec->pec_descr.P,
5443274Set142600 		    pec->pci_err_status, pec->pcie_err_status,
5453274Set142600 		    pec->ce_reg_status, pec->ue_reg_status, pec->hdr[0],
5463274Set142600 		    pec->hdr[1], pec->err_src_reg, pec->root_err_status);
5473274Set142600 	} else {
5483274Set142600 		DBG(DBG_ERR_INTR, dip,
5493274Set142600 		    "A PCIe root complex error has occured with a severity"
5503274Set142600 		    " \"%s\"\n"
5513274Set142600 		    "\tBlock: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
5523274Set142600 		    "\tDir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d, M=%d\n"
5533274Set142600 		    "\tS=%d, Size: 0x%x, Addr: 0x%p\n"
5543274Set142600 		    "\tHdr1: 0x%p, Hdr2: 0x%p, Res: 0x%p\n",
5553274Set142600 		    msg, epkt->rc_descr.block, epkt->rc_descr.op,
5563274Set142600 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
5573274Set142600 		    epkt->rc_descr.dir, epkt->rc_descr.STOP, epkt->rc_descr.H,
5583274Set142600 		    epkt->rc_descr.R, epkt->rc_descr.D, epkt->rc_descr.M,
5593274Set142600 		    epkt->rc_descr.S, epkt->size, epkt->addr, epkt->hdr[0],
5603274Set142600 		    epkt->hdr[1], epkt->reserved);
5613274Set142600 	}
5623274Set142600 }
5633274Set142600 
5643274Set142600 /* ARGSUSED */
5653274Set142600 static void
px_fix_legacy_epkt(dev_info_t * dip,ddi_fm_error_t * derr,px_rc_err_t * epkt)5663274Set142600 px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
5673274Set142600 {
5683274Set142600 	/*
5693274Set142600 	 * We don't have a default case for any of the below switch statements
5703274Set142600 	 * since we are ok with the code falling through.
5713274Set142600 	 */
5723274Set142600 	switch (epkt->rc_descr.block) {
5733274Set142600 	case BLOCK_HOSTBUS:
5743274Set142600 		switch (epkt->rc_descr.op) {
5753274Set142600 		case OP_DMA:
5763274Set142600 			switch (epkt->rc_descr.phase) {
5773274Set142600 			case PH_UNKNOWN:
5783274Set142600 				switch (epkt->rc_descr.cond) {
5793274Set142600 				case CND_UNKNOWN:
5803274Set142600 					switch (epkt->rc_descr.dir) {
5813274Set142600 					case DIR_RESERVED:
5823274Set142600 						epkt->rc_descr.dir = DIR_READ;
5833274Set142600 						break;
5843274Set142600 					} /* DIR */
5853274Set142600 				} /* CND */
5863274Set142600 			} /* PH */
5873274Set142600 		} /* OP */
5883274Set142600 		break;
5893274Set142600 	case BLOCK_MMU:
5903274Set142600 		switch (epkt->rc_descr.op) {
5913274Set142600 		case OP_XLAT:
5923274Set142600 			switch (epkt->rc_descr.phase) {
5933274Set142600 			case PH_DATA:
5943274Set142600 				switch (epkt->rc_descr.cond) {
5953274Set142600 				case CND_PROT:
5963274Set142600 					switch (epkt->rc_descr.dir) {
5973274Set142600 					case DIR_UNKNOWN:
5983274Set142600 						epkt->rc_descr.dir = DIR_WRITE;
5993274Set142600 						break;
6003274Set142600 					} /* DIR */
6013274Set142600 				} /* CND */
6023274Set142600 				break;
6033274Set142600 			case PH_IRR:
6043274Set142600 				switch (epkt->rc_descr.cond) {
6053274Set142600 				case CND_RESERVED:
6063274Set142600 					switch (epkt->rc_descr.dir) {
6073274Set142600 					case DIR_IRR:
6083274Set142600 						epkt->rc_descr.phase = PH_ADDR;
6093274Set142600 						epkt->rc_descr.cond = CND_IRR;
6103274Set142600 					} /* DIR */
6113274Set142600 				} /* CND */
6123274Set142600 			} /* PH */
6133274Set142600 		} /* OP */
6143274Set142600 		break;
6153274Set142600 	case BLOCK_INTR:
6163274Set142600 		switch (epkt->rc_descr.op) {
6173274Set142600 		case OP_MSIQ:
6183274Set142600 			switch (epkt->rc_descr.phase) {
6193274Set142600 			case PH_UNKNOWN:
6203274Set142600 				switch (epkt->rc_descr.cond) {
6213274Set142600 				case CND_ILL:
6223274Set142600 					switch (epkt->rc_descr.dir) {
6233274Set142600 					case DIR_RESERVED:
6243274Set142600 						epkt->rc_descr.dir = DIR_IRR;
6253274Set142600 						break;
6263274Set142600 					} /* DIR */
6273274Set142600 					break;
6283274Set142600 				case CND_IRR:
6293274Set142600 					switch (epkt->rc_descr.dir) {
6303274Set142600 					case DIR_IRR:
6313274Set142600 						epkt->rc_descr.cond = CND_OV;
6323274Set142600 						break;
6333274Set142600 					} /* DIR */
6343274Set142600 				} /* CND */
6353274Set142600 			} /* PH */
6363274Set142600 			break;
6373274Set142600 		case OP_RESERVED:
6383274Set142600 			switch (epkt->rc_descr.phase) {
6393274Set142600 			case PH_UNKNOWN:
6403274Set142600 				switch (epkt->rc_descr.cond) {
6413274Set142600 				case CND_ILL:
6423274Set142600 					switch (epkt->rc_descr.dir) {
6433274Set142600 					case DIR_IRR:
6443274Set142600 						epkt->rc_descr.op = OP_MSI32;
6453274Set142600 						epkt->rc_descr.phase = PH_DATA;
6463274Set142600 						break;
6473274Set142600 					} /* DIR */
6483274Set142600 				} /* CND */
6493274Set142600 				break;
6503274Set142600 			case PH_DATA:
6513274Set142600 				switch (epkt->rc_descr.cond) {
6523274Set142600 				case CND_INT:
6533274Set142600 					switch (epkt->rc_descr.dir) {
6543274Set142600 					case DIR_UNKNOWN:
6553274Set142600 						epkt->rc_descr.op = OP_MSI32;
6563274Set142600 						break;
6573274Set142600 					} /* DIR */
6583274Set142600 				} /* CND */
6593274Set142600 			} /* PH */
6603274Set142600 		} /* OP */
6613274Set142600 	} /* BLOCK */
6623274Set142600 }
6633274Set142600 
6643272Sdduvall /* ARGSUSED */
6653272Sdduvall 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)666*12076SKrishna.Elango@Sun.COM px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt,
667*12076SKrishna.Elango@Sun.COM     pf_data_t *pfd_p)
6683270Set142600 {
6693274Set142600 	return (px_err_check_eq(dip));
6703270Set142600 }
6713270Set142600 
67227Sjchu /* ARGSUSED */
67327Sjchu 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)67411596SJason.Beloro@Sun.COM px_port_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt,
67511596SJason.Beloro@Sun.COM     pf_data_t *pfd_p)
67611304SJanie.Lu@Sun.COM {
67711304SJanie.Lu@Sun.COM 	pf_pcie_adv_err_regs_t	adv_reg;
67811304SJanie.Lu@Sun.COM 	uint16_t		s_status;
67911304SJanie.Lu@Sun.COM 	int			sts = PX_PANIC;
68011304SJanie.Lu@Sun.COM 
68111304SJanie.Lu@Sun.COM 	/*
68211304SJanie.Lu@Sun.COM 	 * Check for failed non-posted writes, which are errors that are not
68311304SJanie.Lu@Sun.COM 	 * defined in the PCIe spec.  If not return panic.
68411304SJanie.Lu@Sun.COM 	 */
68511304SJanie.Lu@Sun.COM 	if (!((epkt->rc_descr.op == OP_PIO) &&
68611304SJanie.Lu@Sun.COM 	    (epkt->rc_descr.phase == PH_IRR))) {
68711304SJanie.Lu@Sun.COM 		sts = (PX_PANIC);
68811304SJanie.Lu@Sun.COM 		goto done;
68911304SJanie.Lu@Sun.COM 	}
69011304SJanie.Lu@Sun.COM 
69111304SJanie.Lu@Sun.COM 	/*
69211304SJanie.Lu@Sun.COM 	 * Gather the error logs, if they do not exist just return with no panic
69311304SJanie.Lu@Sun.COM 	 * and let the fabric message take care of the error.
69411304SJanie.Lu@Sun.COM 	 */
69511304SJanie.Lu@Sun.COM 	if (!epkt->rc_descr.H) {
69611304SJanie.Lu@Sun.COM 		sts = (PX_NO_PANIC);
69711304SJanie.Lu@Sun.COM 		goto done;
69811304SJanie.Lu@Sun.COM 	}
69911304SJanie.Lu@Sun.COM 
70011654SKrishna.Elango@Sun.COM 	adv_reg.pcie_ue_hdr[0] = (uint32_t)(epkt->hdr[0] >> 32);
70111654SKrishna.Elango@Sun.COM 	adv_reg.pcie_ue_hdr[1] = (uint32_t)(epkt->hdr[0]);
70211654SKrishna.Elango@Sun.COM 	adv_reg.pcie_ue_hdr[2] = (uint32_t)(epkt->hdr[1] >> 32);
70311654SKrishna.Elango@Sun.COM 	adv_reg.pcie_ue_hdr[3] = (uint32_t)(epkt->hdr[1]);
70411304SJanie.Lu@Sun.COM 
70511304SJanie.Lu@Sun.COM 	sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
70611304SJanie.Lu@Sun.COM 
70711304SJanie.Lu@Sun.COM 	if (epkt->rc_descr.M)
70811304SJanie.Lu@Sun.COM 		adv_reg.pcie_ue_tgt_addr = epkt->addr;
70911304SJanie.Lu@Sun.COM 
71011304SJanie.Lu@Sun.COM 	if (!((sts == DDI_SUCCESS) || (epkt->rc_descr.M))) {
71111304SJanie.Lu@Sun.COM 		/* Let the fabric message take care of error */
71211304SJanie.Lu@Sun.COM 		sts = PX_NO_PANIC;
71311304SJanie.Lu@Sun.COM 		goto done;
71411304SJanie.Lu@Sun.COM 	}
71511304SJanie.Lu@Sun.COM 
71611304SJanie.Lu@Sun.COM 	/* See if the failed transaction belonged to a hardened driver */
71711304SJanie.Lu@Sun.COM 	if (pf_hdl_lookup(dip, derr->fme_ena,
71811304SJanie.Lu@Sun.COM 	    adv_reg.pcie_ue_tgt_trans, adv_reg.pcie_ue_tgt_addr,
71911304SJanie.Lu@Sun.COM 	    adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
72011304SJanie.Lu@Sun.COM 		sts = (PX_NO_PANIC);
72111304SJanie.Lu@Sun.COM 	else
72211304SJanie.Lu@Sun.COM 		sts = (PX_PANIC);
72311304SJanie.Lu@Sun.COM 
72411304SJanie.Lu@Sun.COM 	/* Add pfd to cause a fabric scan */
72511304SJanie.Lu@Sun.COM 	switch (epkt->rc_descr.cond) {
72611304SJanie.Lu@Sun.COM 	case CND_RCA:
72711304SJanie.Lu@Sun.COM 		s_status = PCI_STAT_R_TARG_AB;
72811304SJanie.Lu@Sun.COM 		break;
72911304SJanie.Lu@Sun.COM 	case CND_RUR:
73011304SJanie.Lu@Sun.COM 		s_status = PCI_STAT_R_MAST_AB;
73111304SJanie.Lu@Sun.COM 		break;
73211304SJanie.Lu@Sun.COM 	}
73311596SJason.Beloro@Sun.COM 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = adv_reg.pcie_ue_tgt_bdf;
73411596SJason.Beloro@Sun.COM 	PCIE_ROOT_FAULT(pfd_p)->scan_addr = adv_reg.pcie_ue_tgt_addr;
73511596SJason.Beloro@Sun.COM 	PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
73611304SJanie.Lu@Sun.COM 
737*12076SKrishna.Elango@Sun.COM 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_BDF;
738*12076SKrishna.Elango@Sun.COM 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = adv_reg.pcie_ue_tgt_bdf;
739*12076SKrishna.Elango@Sun.COM 
74011304SJanie.Lu@Sun.COM done:
74111304SJanie.Lu@Sun.COM 	return (sts);
74211304SJanie.Lu@Sun.COM }
74311304SJanie.Lu@Sun.COM 
74411304SJanie.Lu@Sun.COM /* ARGSUSED */
74511304SJanie.Lu@Sun.COM 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)746*12076SKrishna.Elango@Sun.COM px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt,
747*12076SKrishna.Elango@Sun.COM     pf_data_t *pfd_p)
74827Sjchu {
7496313Skrishnae 	px_pec_err_t	*pec_p = (px_pec_err_t *)epkt;
7503274Set142600 	px_err_pcie_t	*pcie = (px_err_pcie_t *)epkt;
7516313Skrishnae 	pf_pcie_adv_err_regs_t adv_reg;
7526313Skrishnae 	int		sts;
7533274Set142600 	uint32_t	temp;
7543272Sdduvall 
7553274Set142600 	/*
7563274Set142600 	 * Check for failed PIO Read/Writes, which are errors that are not
7573274Set142600 	 * defined in the PCIe spec.
7583274Set142600 	 */
75911654SKrishna.Elango@Sun.COM 
7603274Set142600 	temp = PCIE_AER_UCE_UR | PCIE_AER_UCE_CA;
7616313Skrishnae 	if (((pec_p->pec_descr.dir == DIR_READ) ||
7626313Skrishnae 	    (pec_p->pec_descr.dir == DIR_WRITE)) &&
7636313Skrishnae 	    pec_p->pec_descr.U && (pec_p->ue_reg_status & temp)) {
76411654SKrishna.Elango@Sun.COM 
76511654SKrishna.Elango@Sun.COM 		adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0] >> 32);
76611654SKrishna.Elango@Sun.COM 		adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0]);
76711654SKrishna.Elango@Sun.COM 		adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1] >> 32);
76811654SKrishna.Elango@Sun.COM 		adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1]);
7693274Set142600 
7706313Skrishnae 		sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
7716313Skrishnae 
7726313Skrishnae 		if (sts == DDI_SUCCESS &&
7736313Skrishnae 		    pf_hdl_lookup(dip, derr->fme_ena,
7746313Skrishnae 		    adv_reg.pcie_ue_tgt_trans,
7756313Skrishnae 		    adv_reg.pcie_ue_tgt_addr,
7766313Skrishnae 		    adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
7773274Set142600 			return (PX_NO_PANIC);
7783274Set142600 		else
7793274Set142600 			return (PX_PANIC);
7803272Sdduvall 	}
7813272Sdduvall 
7826313Skrishnae 	if (!pec_p->pec_descr.C)
7836313Skrishnae 		pec_p->ce_reg_status = 0;
7846313Skrishnae 	if (!pec_p->pec_descr.U)
7856313Skrishnae 		pec_p->ue_reg_status = 0;
7866313Skrishnae 	if (!pec_p->pec_descr.H)
7876313Skrishnae 		pec_p->hdr[0] = 0;
7886313Skrishnae 	if (!pec_p->pec_descr.I)
7896313Skrishnae 		pec_p->hdr[1] = 0;
7903272Sdduvall 
7913274Set142600 	/*
7923274Set142600 	 * According to the PCIe spec, there is a first error pointer.  If there
7933274Set142600 	 * are header logs recorded and there are more than one error, the log
7943274Set142600 	 * will belong to the error that the first error pointer points to.
7953274Set142600 	 *
7963274Set142600 	 * The regs.primary_ue expects a bit number, go through the ue register
7973274Set142600 	 * and find the first error that occured.  Because the sun4v epkt spec
7983274Set142600 	 * does not define this value, the algorithm below gives the lower bit
7993274Set142600 	 * priority.
8003274Set142600 	 */
8013274Set142600 	temp = pcie->ue_reg;
8023274Set142600 	if (temp) {
8036313Skrishnae 		int x;
8043274Set142600 		for (x = 0; !(temp & 0x1); x++) {
8053274Set142600 			temp = temp >> 1;
8063274Set142600 		}
8073274Set142600 		pcie->primary_ue = 1 << x;
8083274Set142600 	} else {
8093274Set142600 		pcie->primary_ue = 0;
8103274Set142600 	}
8113274Set142600 
8123274Set142600 	/* Sun4v doesn't log the TX hdr except for CTOs */
8133274Set142600 	if (pcie->primary_ue == PCIE_AER_UCE_TO) {
8143274Set142600 		pcie->tx_hdr1 = pcie->rx_hdr1;
8153274Set142600 		pcie->tx_hdr2 = pcie->rx_hdr2;
8163274Set142600 		pcie->tx_hdr3 = pcie->rx_hdr3;
8173274Set142600 		pcie->tx_hdr4 = pcie->rx_hdr4;
8183274Set142600 		pcie->rx_hdr1 = 0;
8193274Set142600 		pcie->rx_hdr2 = 0;
8203274Set142600 		pcie->rx_hdr3 = 0;
8213274Set142600 		pcie->rx_hdr4 = 0;
8223274Set142600 	} else {
8233274Set142600 		pcie->tx_hdr1 = 0;
8243274Set142600 		pcie->tx_hdr2 = 0;
8253274Set142600 		pcie->tx_hdr3 = 0;
8263274Set142600 		pcie->tx_hdr4 = 0;
8273274Set142600 	}
8283274Set142600 
82911654SKrishna.Elango@Sun.COM 	return (px_err_check_pcie(dip, derr, pcie, PF_INTR_TYPE_INTERNAL));
83027Sjchu }
83127Sjchu 
83227Sjchu static int
px_mmu_handle_lookup(dev_info_t * dip,ddi_fm_error_t * derr,px_rc_err_t * epkt)8333274Set142600 px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
83427Sjchu {
8356313Skrishnae 	uint64_t addr = (uint64_t)epkt->addr;
8369921SKrishna.Elango@Sun.COM 	pcie_req_id_t bdf = PCIE_INVALID_BDF;
83727Sjchu 
8383274Set142600 	if (epkt->rc_descr.H) {
8393274Set142600 		bdf = (uint32_t)((epkt->hdr[0] >> 16) && 0xFFFF);
84027Sjchu 	}
84127Sjchu 
8426313Skrishnae 	return (pf_hdl_lookup(dip, derr->fme_ena, PF_ADDR_DMA, addr,
8434853Segillett 	    bdf));
84427Sjchu }
845