xref: /illumos-gate/usr/src/uts/sun4v/io/px/px_err.c (revision fc256490)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * sun4v Fire Error Handling
28  */
29 
30 #include <sys/types.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/sunndi.h>
34 #include <sys/fm/protocol.h>
35 #include <sys/fm/util.h>
36 #include <sys/membar.h>
37 #include "px_obj.h"
38 #include "px_err.h"
39 
40 static void px_err_fill_pfd(dev_info_t *dip, pf_data_t *pfd_p,
41     px_rc_err_t *epkt);
42 static uint_t px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt);
43 static int  px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr,
44     px_rc_err_t *epkt, pf_data_t *pfd_p);
45 
46 static void px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt,
47     boolean_t is_block_pci, char *msg);
48 static void px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
49     boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
50     boolean_t is_valid_epkt);
51 static int px_cb_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
52     px_rc_err_t *epkt);
53 static int px_mmu_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
54     px_rc_err_t *epkt);
55 static int px_intr_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
56     px_rc_err_t *epkt);
57 static int px_port_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
58     px_rc_err_t *epkt, pf_data_t *pfd_p);
59 static int px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr,
60     px_rc_err_t *epkt);
61 static int px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
62     px_rc_err_t *epkt);
63 static int px_port_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr,
64     px_rc_err_t *epkt, pf_data_t *pfd_p);
65 static void px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr,
66     px_rc_err_t *epkt);
67 static int px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr,
68     px_rc_err_t *epkt);
69 
70 /* Include the code generated sun4v epkt checking code */
71 #include "px_err_gen.c"
72 
73 /*
74  * This variable indicates if we have a hypervisor that could potentially send
75  * incorrect epkts. We always set this to TRUE for now until we find a way to
76  * tell if this HV bug has been fixed.
77  */
78 boolean_t px_legacy_epkt = B_TRUE;
79 
80 /*
81  * px_err_cb_intr:
82  * Interrupt handler for the Host Bus Block.
83  */
84 uint_t
85 px_err_cb_intr(caddr_t arg)
86 {
87 	px_fault_t	*fault_p = (px_fault_t *)arg;
88 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
89 
90 	if (epkt != NULL) {
91 		return (px_err_intr(fault_p, epkt));
92 	}
93 
94 	return (DDI_INTR_UNCLAIMED);
95 }
96 
97 /*
98  * px_err_dmc_pec_intr:
99  * Interrupt handler for the DMC/PEC block.
100  */
101 uint_t
102 px_err_dmc_pec_intr(caddr_t arg)
103 {
104 	px_fault_t	*fault_p = (px_fault_t *)arg;
105 	px_rc_err_t	*epkt = (px_rc_err_t *)fault_p->px_intr_payload;
106 
107 	if (epkt != NULL) {
108 		return (px_err_intr(fault_p, epkt));
109 	}
110 
111 	return (DDI_INTR_UNCLAIMED);
112 }
113 
114 /*
115  * px_err_cmn_intr:
116  * Common function called by trap, mondo and fabric intr.
117  * This function is more meaningful in sun4u implementation.  Kept
118  * to mirror sun4u call stack.
119  * o check for safe access
120  * o create and queue RC info for later use in fabric scan.
121  *   o RUC/WUC, PTLP, MMU Errors(CA), UR
122  *
123  * @param px_p		leaf in which to check access
124  * @param derr		fm err data structure to be updated
125  * @param caller	PX_TRAP_CALL | PX_INTR_CALL
126  * @param chkjbc	whether to handle hostbus registers (ignored)
127  * @return err		PX_NO_PANIC | PX_PROTECTED |
128  *                      PX_PANIC | PX_HW_RESET | PX_EXPECTED
129  */
130 /* ARGSUSED */
131 int
132 px_err_cmn_intr(px_t *px_p, ddi_fm_error_t *derr, int caller, int block)
133 {
134 	px_err_safeacc_check(px_p, derr);
135 	return (DDI_FM_OK);
136 }
137 
138 /*
139  * fills RC specific fault data
140  */
141 static void
142 px_err_fill_pfd(dev_info_t *dip, pf_data_t *pfd_p, px_rc_err_t *epkt) {
143 	pf_pcie_adv_err_regs_t adv_reg;
144 	int		sts = DDI_SUCCESS;
145 	pcie_req_id_t	fault_bdf = PCIE_INVALID_BDF;
146 	uint64_t	fault_addr = 0;
147 	uint16_t	s_status = 0;
148 
149 	/* Add an PCIE PF_DATA Entry */
150 	if (epkt->rc_descr.block == BLOCK_MMU) {
151 		/* Only PIO Fault Addresses are valid, this is DMA */
152 		s_status = PCI_STAT_S_TARG_AB;
153 		fault_addr = NULL;
154 
155 		if (epkt->rc_descr.H) {
156 			fault_bdf = (pcie_req_id_t)(epkt->hdr[0] >> 16);
157 			PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags =
158 			    PF_AFFECTED_BDF;
159 			PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf =
160 			    fault_bdf;
161 		} else
162 			sts = DDI_FAILURE;
163 	} else {
164 		px_pec_err_t	*pec_p = (px_pec_err_t *)epkt;
165 		uint32_t	dir = pec_p->pec_descr.dir;
166 
167 		adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0]);
168 		adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0] >> 32);
169 		adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1]);
170 		adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1] >> 32);
171 
172 		/* translate RC UR/CA to legacy secondary errors */
173 		if ((dir == DIR_READ || dir == DIR_WRITE) &&
174 		    pec_p->pec_descr.U) {
175 			if (pec_p->ue_reg_status & PCIE_AER_UCE_UR)
176 				s_status |= PCI_STAT_R_MAST_AB;
177 			if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
178 				s_status |= PCI_STAT_R_TARG_AB;
179 		}
180 
181 		if (pec_p->ue_reg_status & PCIE_AER_UCE_PTLP)
182 			s_status |= PCI_STAT_PERROR;
183 
184 		if (pec_p->ue_reg_status & PCIE_AER_UCE_CA)
185 			s_status |= PCI_STAT_S_TARG_AB;
186 
187 		sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
188 		fault_bdf = adv_reg.pcie_ue_tgt_bdf;
189 		fault_addr = adv_reg.pcie_ue_tgt_addr;
190 		/* affected BDF is to be filled in by px_scan_fabric */
191 	}
192 
193 	if (sts == DDI_SUCCESS) {
194 		PCIE_ROOT_FAULT(pfd_p)->scan_bdf = fault_bdf;
195 		PCIE_ROOT_FAULT(pfd_p)->scan_addr = (uint64_t)fault_addr;
196 		PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
197 	}
198 }
199 
200 /*
201  * Convert error severity from PX internal values to PCIe Fabric values.  Most
202  * are self explanitory, except PX_PROTECTED.  PX_PROTECTED will never be
203  * returned as is if forgivable.
204  */
205 static int px_err_to_fab_sev(int rc_err) {
206 	int fab_err = 0;
207 
208 	if (rc_err & (PX_HW_RESET | PX_EXPECTED | PX_NO_PANIC))
209 		fab_err |= PF_ERR_NO_PANIC;
210 
211 	if (rc_err & (PX_PANIC | PX_PROTECTED))
212 		fab_err |= PF_ERR_PANIC;
213 
214 	if (rc_err & PX_NO_ERROR)
215 		fab_err |= PF_ERR_NO_ERROR;
216 
217 	return (fab_err);
218 }
219 
220 /*
221  * px_err_intr:
222  * Interrupt handler for the JBC/DMC/PEC block.
223  * o lock
224  * o create derr
225  * o check safe access
226  * o px_err_check_severity(epkt)
227  * o pcie_scan_fabric
228  * o Idle intr state
229  * o unlock
230  * o handle error: fatal? fm_panic() : return INTR_CLAIMED)
231  */
232 static uint_t
233 px_err_intr(px_fault_t *fault_p, px_rc_err_t *epkt)
234 {
235 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip);
236 	dev_info_t	*rpdip = px_p->px_dip;
237 	int		rc_err, fab_err, msg;
238 	ddi_fm_error_t	derr;
239 	pf_data_t	*pfd_p;
240 
241 	if (px_fm_enter(px_p) != DDI_SUCCESS)
242 		goto done;
243 
244 	pfd_p = px_get_pfd(px_p);
245 	PCIE_ROOT_EH_SRC(pfd_p)->intr_type = PF_INTR_TYPE_INTERNAL;
246 	PCIE_ROOT_EH_SRC(pfd_p)->intr_data = epkt;
247 
248 	/* Create the derr */
249 	bzero(&derr, sizeof (ddi_fm_error_t));
250 	derr.fme_version = DDI_FME_VERSION;
251 	derr.fme_ena = fm_ena_generate(epkt->stick, FM_ENA_FMT1);
252 	derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
253 
254 	/* Basically check for safe access */
255 	(void) px_err_cmn_intr(px_p, &derr, PX_INTR_CALL, PX_FM_BLOCK_ALL);
256 
257 	/* Check the severity of this error */
258 	rc_err = px_err_epkt_severity(px_p, &derr, epkt, pfd_p);
259 
260 	pfd_p->pe_severity_flags = px_err_to_fab_sev(rc_err);
261 	/*
262 	 * px_err_epkt_severity needs to populate affected dev
263 	 * Only MMU errors and PCIe errors need this.
264 	 * For MMU we will call pf_handle_lookup, using fault bdf
265 	 * - need to call bdf look up..
266 	 * For PCIe do not fill in affected..
267 	 */
268 
269 	/* Scan the fabric if the root port is not in drain state. */
270 	fab_err = px_scan_fabric(px_p, rpdip, &derr);
271 
272 	/* Set the intr state to idle for the leaf that received the mondo */
273 	if (px_lib_intr_setstate(rpdip, fault_p->px_fh_sysino,
274 	    INTR_IDLE_STATE) != DDI_SUCCESS) {
275 		px_fm_exit(px_p);
276 		return (DDI_INTR_UNCLAIMED);
277 	}
278 
279 	switch (epkt->rc_descr.block) {
280 	case BLOCK_MMU: /* FALLTHROUGH */
281 	case BLOCK_INTR:
282 		msg = PX_RC;
283 		break;
284 	case BLOCK_PCIE:
285 		msg = PX_RP;
286 		break;
287 	case BLOCK_HOSTBUS: /* FALLTHROUGH */
288 	default:
289 		msg = PX_HB;
290 		break;
291 	}
292 
293 	px_err_panic(rc_err, msg, fab_err, B_TRUE);
294 	px_fm_exit(px_p);
295 	px_err_panic(rc_err, msg, fab_err, B_FALSE);
296 
297 done:
298 	return (DDI_INTR_CLAIMED);
299 }
300 
301 /*
302  * px_err_epkt_severity:
303  * Check the severity of the fire error based the epkt received
304  *
305  * @param px_p		leaf in which to take the snap shot.
306  * @param derr		fm err in which the ereport is to be based on
307  * @param epkt		epkt recevied from HV
308  */
309 static int
310 px_err_epkt_severity(px_t *px_p, ddi_fm_error_t *derr, px_rc_err_t *epkt,
311     pf_data_t *pfd_p)
312 {
313 	px_pec_t 	*pec_p = px_p->px_pec_p;
314 	dev_info_t	*dip = px_p->px_dip;
315 	boolean_t	is_safeacc = B_FALSE;
316 	boolean_t	is_block_pci = B_FALSE;
317 	boolean_t	is_valid_epkt = B_FALSE;
318 	int		err = 0;
319 
320 	/* Cautious access error handling  */
321 	switch (derr->fme_flag) {
322 	case DDI_FM_ERR_EXPECTED:
323 		/*
324 		 * For ddi_caut_put treat all events as nonfatal. Here
325 		 * we have the handle and can call ndi_fm_acc_err_set().
326 		 */
327 		derr->fme_status = DDI_FM_NONFATAL;
328 		ndi_fm_acc_err_set(pec_p->pec_acc_hdl, derr);
329 		is_safeacc = B_TRUE;
330 		break;
331 	case DDI_FM_ERR_PEEK:
332 	case DDI_FM_ERR_POKE:
333 		/*
334 		 * For ddi_peek/poke treat all events as nonfatal.
335 		 */
336 		is_safeacc = B_TRUE;
337 		break;
338 	default:
339 		is_safeacc = B_FALSE;
340 	}
341 
342 	/*
343 	 * Older hypervisors in some cases send epkts with incorrect fields.
344 	 * We have to handle these "special" epkts correctly.
345 	 */
346 	if (px_legacy_epkt)
347 		px_fix_legacy_epkt(dip, derr, epkt);
348 
349 	switch (epkt->rc_descr.block) {
350 	case BLOCK_HOSTBUS:
351 		err = px_cb_epkt_severity(dip, derr, epkt);
352 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
353 		break;
354 	case BLOCK_MMU:
355 		err = px_mmu_epkt_severity(dip, derr, epkt);
356 		px_err_fill_pfd(dip, pfd_p, epkt);
357 		break;
358 	case BLOCK_INTR:
359 		err = px_intr_epkt_severity(dip, derr, epkt);
360 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
361 		break;
362 	case BLOCK_PORT:
363 		err = px_port_epkt_severity(dip, derr, epkt, pfd_p);
364 		break;
365 	case BLOCK_PCIE:
366 		is_block_pci = B_TRUE;
367 		err = px_pcie_epkt_severity(dip, derr, epkt);
368 		px_err_fill_pfd(dip, pfd_p, epkt);
369 		break;
370 	default:
371 		err = 0;
372 	}
373 
374 	if ((err & PX_HW_RESET) || (err & PX_PANIC)) {
375 		if (px_log & PX_PANIC)
376 			px_err_log_handle(dip, epkt, is_block_pci, "PANIC");
377 		is_valid_epkt = B_TRUE;
378 	} else if (err & PX_PROTECTED) {
379 		if (px_log & PX_PROTECTED)
380 			px_err_log_handle(dip, epkt, is_block_pci, "PROTECTED");
381 		is_valid_epkt = B_TRUE;
382 	} else if (err & PX_NO_PANIC) {
383 		if (px_log & PX_NO_PANIC)
384 			px_err_log_handle(dip, epkt, is_block_pci, "NO PANIC");
385 		is_valid_epkt = B_TRUE;
386 	} else if (err & PX_NO_ERROR) {
387 		if (px_log & PX_NO_ERROR)
388 			px_err_log_handle(dip, epkt, is_block_pci, "NO ERROR");
389 		is_valid_epkt = B_TRUE;
390 	} else if (err == 0) {
391 		px_err_log_handle(dip, epkt, is_block_pci, "UNRECOGNIZED");
392 		is_valid_epkt = B_FALSE;
393 
394 		/* Panic on a unrecognized epkt */
395 		err = PX_PANIC;
396 	}
397 
398 	px_err_send_epkt_erpt(dip, epkt, is_block_pci, err, derr,
399 	    is_valid_epkt);
400 
401 	/* Readjust the severity as a result of safe access */
402 	if (is_safeacc && !(err & PX_PANIC) && !(px_die & PX_PROTECTED))
403 		err = PX_NO_PANIC;
404 
405 	return (err);
406 }
407 
408 static void
409 px_err_send_epkt_erpt(dev_info_t *dip, px_rc_err_t *epkt,
410     boolean_t is_block_pci, int err, ddi_fm_error_t *derr,
411     boolean_t is_valid_epkt)
412 {
413 	char buf[FM_MAX_CLASS], descr_buf[1024];
414 
415 	/* send ereport for debug purposes */
416 	(void) snprintf(buf, FM_MAX_CLASS, "%s", PX_FM_RC_UNRECOG);
417 
418 	if (is_block_pci) {
419 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
420 		(void) snprintf(descr_buf, sizeof (descr_buf),
421 		    "%s Epkt contents:\n"
422 		    "Block: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d\n"
423 		    "I=%d, H=%d, C=%d, U=%d, E=%d, P=%d\n"
424 		    "PCI Err Status: 0x%x, PCIe Err Status: 0x%x\n"
425 		    "CE Status Reg: 0x%x, UE Status Reg: 0x%x\n"
426 		    "HDR1: 0x%lx, HDR2: 0x%lx\n"
427 		    "Err Src Reg: 0x%x, Root Err Status: 0x%x\n"
428 		    "Err Severity: 0x%x\n",
429 		    is_valid_epkt ? "Valid" : "Invalid",
430 		    pec->pec_descr.block, pec->pec_descr.dir,
431 		    pec->pec_descr.Z, pec->pec_descr.S,
432 		    pec->pec_descr.R, pec->pec_descr.I,
433 		    pec->pec_descr.H, pec->pec_descr.C,
434 		    pec->pec_descr.U, pec->pec_descr.E,
435 		    pec->pec_descr.P, pec->pci_err_status,
436 		    pec->pcie_err_status, pec->ce_reg_status,
437 		    pec->ue_reg_status, pec->hdr[0],
438 		    pec->hdr[1], pec->err_src_reg,
439 		    pec->root_err_status, err);
440 
441 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
442 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
443 		    EPKT_SYSINO, DATA_TYPE_UINT64,
444 		    is_valid_epkt ? pec->sysino : 0,
445 		    EPKT_EHDL, DATA_TYPE_UINT64,
446 		    is_valid_epkt ? pec->ehdl : 0,
447 		    EPKT_STICK, DATA_TYPE_UINT64,
448 		    is_valid_epkt ? pec->stick : 0,
449 		    EPKT_DW0, DATA_TYPE_UINT64, ((uint64_t *)pec)[3],
450 		    EPKT_DW1, DATA_TYPE_UINT64, ((uint64_t *)pec)[4],
451 		    EPKT_DW2, DATA_TYPE_UINT64, ((uint64_t *)pec)[5],
452 		    EPKT_DW3, DATA_TYPE_UINT64, ((uint64_t *)pec)[6],
453 		    EPKT_DW4, DATA_TYPE_UINT64, ((uint64_t *)pec)[7],
454 		    EPKT_PEC_DESCR, DATA_TYPE_STRING, descr_buf);
455 	} else {
456 		(void) snprintf(descr_buf, sizeof (descr_buf),
457 		    "%s Epkt contents:\n"
458 		    "Block: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
459 		    "Dir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d\n"
460 		    "M=%d, S=%d, Size: 0x%x, Addr: 0x%lx\n"
461 		    "Hdr1: 0x%lx, Hdr2: 0x%lx, Res: 0x%lx\n"
462 		    "Err Severity: 0x%x\n",
463 		    is_valid_epkt ? "Valid" : "Invalid",
464 		    epkt->rc_descr.block, epkt->rc_descr.op,
465 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
466 		    epkt->rc_descr.dir, epkt->rc_descr.STOP,
467 		    epkt->rc_descr.H, epkt->rc_descr.R,
468 		    epkt->rc_descr.D, epkt->rc_descr.M,
469 		    epkt->rc_descr.S, epkt->size, epkt->addr,
470 		    epkt->hdr[0], epkt->hdr[1], epkt->reserved,
471 		    err);
472 
473 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
474 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
475 		    EPKT_SYSINO, DATA_TYPE_UINT64,
476 		    is_valid_epkt ? epkt->sysino : 0,
477 		    EPKT_EHDL, DATA_TYPE_UINT64,
478 		    is_valid_epkt ? epkt->ehdl : 0,
479 		    EPKT_STICK, DATA_TYPE_UINT64,
480 		    is_valid_epkt ? epkt->stick : 0,
481 		    EPKT_DW0, DATA_TYPE_UINT64, ((uint64_t *)epkt)[3],
482 		    EPKT_DW1, DATA_TYPE_UINT64, ((uint64_t *)epkt)[4],
483 		    EPKT_DW2, DATA_TYPE_UINT64, ((uint64_t *)epkt)[5],
484 		    EPKT_DW3, DATA_TYPE_UINT64, ((uint64_t *)epkt)[6],
485 		    EPKT_DW4, DATA_TYPE_UINT64, ((uint64_t *)epkt)[7],
486 		    EPKT_RC_DESCR, DATA_TYPE_STRING, descr_buf);
487 	}
488 }
489 
490 static void
491 px_err_log_handle(dev_info_t *dip, px_rc_err_t *epkt, boolean_t is_block_pci,
492     char *msg)
493 {
494 	if (is_block_pci) {
495 		px_pec_err_t *pec = (px_pec_err_t *)epkt;
496 		DBG(DBG_ERR_INTR, dip,
497 		    "A PCIe root port error has occured with a severity"
498 		    " \"%s\"\n"
499 		    "\tBlock: 0x%x, Dir: 0x%x, Flags: Z=%d, S=%d, R=%d, I=%d\n"
500 		    "\tH=%d, C=%d, U=%d, E=%d, P=%d\n"
501 		    "\tpci_err: 0x%x, pcie_err=0x%x, ce_reg: 0x%x\n"
502 		    "\tue_reg: 0x%x, Hdr1: 0x%p, Hdr2: 0x%p\n"
503 		    "\terr_src: 0x%x, root_err: 0x%x\n",
504 		    msg, pec->pec_descr.block, pec->pec_descr.dir,
505 		    pec->pec_descr.Z, pec->pec_descr.S, pec->pec_descr.R,
506 		    pec->pec_descr.I, pec->pec_descr.H, pec->pec_descr.C,
507 		    pec->pec_descr.U, pec->pec_descr.E, pec->pec_descr.P,
508 		    pec->pci_err_status, pec->pcie_err_status,
509 		    pec->ce_reg_status, pec->ue_reg_status, pec->hdr[0],
510 		    pec->hdr[1], pec->err_src_reg, pec->root_err_status);
511 	} else {
512 		DBG(DBG_ERR_INTR, dip,
513 		    "A PCIe root complex error has occured with a severity"
514 		    " \"%s\"\n"
515 		    "\tBlock: 0x%x, Op: 0x%x, Phase: 0x%x, Cond: 0x%x\n"
516 		    "\tDir: 0x%x, Flags: STOP=%d, H=%d, R=%d, D=%d, M=%d\n"
517 		    "\tS=%d, Size: 0x%x, Addr: 0x%p\n"
518 		    "\tHdr1: 0x%p, Hdr2: 0x%p, Res: 0x%p\n",
519 		    msg, epkt->rc_descr.block, epkt->rc_descr.op,
520 		    epkt->rc_descr.phase, epkt->rc_descr.cond,
521 		    epkt->rc_descr.dir, epkt->rc_descr.STOP, epkt->rc_descr.H,
522 		    epkt->rc_descr.R, epkt->rc_descr.D, epkt->rc_descr.M,
523 		    epkt->rc_descr.S, epkt->size, epkt->addr, epkt->hdr[0],
524 		    epkt->hdr[1], epkt->reserved);
525 	}
526 }
527 
528 /* ARGSUSED */
529 static void
530 px_fix_legacy_epkt(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
531 {
532 	/*
533 	 * We don't have a default case for any of the below switch statements
534 	 * since we are ok with the code falling through.
535 	 */
536 	switch (epkt->rc_descr.block) {
537 	case BLOCK_HOSTBUS:
538 		switch (epkt->rc_descr.op) {
539 		case OP_DMA:
540 			switch (epkt->rc_descr.phase) {
541 			case PH_UNKNOWN:
542 				switch (epkt->rc_descr.cond) {
543 				case CND_UNKNOWN:
544 					switch (epkt->rc_descr.dir) {
545 					case DIR_RESERVED:
546 						epkt->rc_descr.dir = DIR_READ;
547 						break;
548 					} /* DIR */
549 				} /* CND */
550 			} /* PH */
551 		} /* OP */
552 		break;
553 	case BLOCK_MMU:
554 		switch (epkt->rc_descr.op) {
555 		case OP_XLAT:
556 			switch (epkt->rc_descr.phase) {
557 			case PH_DATA:
558 				switch (epkt->rc_descr.cond) {
559 				case CND_PROT:
560 					switch (epkt->rc_descr.dir) {
561 					case DIR_UNKNOWN:
562 						epkt->rc_descr.dir = DIR_WRITE;
563 						break;
564 					} /* DIR */
565 				} /* CND */
566 				break;
567 			case PH_IRR:
568 				switch (epkt->rc_descr.cond) {
569 				case CND_RESERVED:
570 					switch (epkt->rc_descr.dir) {
571 					case DIR_IRR:
572 						epkt->rc_descr.phase = PH_ADDR;
573 						epkt->rc_descr.cond = CND_IRR;
574 					} /* DIR */
575 				} /* CND */
576 			} /* PH */
577 		} /* OP */
578 		break;
579 	case BLOCK_INTR:
580 		switch (epkt->rc_descr.op) {
581 		case OP_MSIQ:
582 			switch (epkt->rc_descr.phase) {
583 			case PH_UNKNOWN:
584 				switch (epkt->rc_descr.cond) {
585 				case CND_ILL:
586 					switch (epkt->rc_descr.dir) {
587 					case DIR_RESERVED:
588 						epkt->rc_descr.dir = DIR_IRR;
589 						break;
590 					} /* DIR */
591 					break;
592 				case CND_IRR:
593 					switch (epkt->rc_descr.dir) {
594 					case DIR_IRR:
595 						epkt->rc_descr.cond = CND_OV;
596 						break;
597 					} /* DIR */
598 				} /* CND */
599 			} /* PH */
600 			break;
601 		case OP_RESERVED:
602 			switch (epkt->rc_descr.phase) {
603 			case PH_UNKNOWN:
604 				switch (epkt->rc_descr.cond) {
605 				case CND_ILL:
606 					switch (epkt->rc_descr.dir) {
607 					case DIR_IRR:
608 						epkt->rc_descr.op = OP_MSI32;
609 						epkt->rc_descr.phase = PH_DATA;
610 						break;
611 					} /* DIR */
612 				} /* CND */
613 				break;
614 			case PH_DATA:
615 				switch (epkt->rc_descr.cond) {
616 				case CND_INT:
617 					switch (epkt->rc_descr.dir) {
618 					case DIR_UNKNOWN:
619 						epkt->rc_descr.op = OP_MSI32;
620 						break;
621 					} /* DIR */
622 				} /* CND */
623 			} /* PH */
624 		} /* OP */
625 	} /* BLOCK */
626 }
627 
628 /* ARGSUSED */
629 static int
630 px_intr_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
631 {
632 	return (px_err_check_eq(dip));
633 }
634 
635 /* ARGSUSED */
636 static int
637 px_port_handle_errors(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt,
638     pf_data_t *pfd_p)
639 {
640 	pf_pcie_adv_err_regs_t	adv_reg;
641 	uint16_t		s_status;
642 	int			sts = PX_PANIC;
643 
644 	/*
645 	 * Check for failed non-posted writes, which are errors that are not
646 	 * defined in the PCIe spec.  If not return panic.
647 	 */
648 	if (!((epkt->rc_descr.op == OP_PIO) &&
649 	    (epkt->rc_descr.phase == PH_IRR))) {
650 		sts = (PX_PANIC);
651 		PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags = PF_AFFECTED_SELF;
652 		goto done;
653 	}
654 
655 	/*
656 	 * Gather the error logs, if they do not exist just return with no panic
657 	 * and let the fabric message take care of the error.
658 	 */
659 	if (!epkt->rc_descr.H) {
660 		sts = (PX_NO_PANIC);
661 		goto done;
662 	}
663 
664 	adv_reg.pcie_ue_hdr[0] = (uint32_t)(epkt->hdr[0]);
665 	adv_reg.pcie_ue_hdr[1] = (uint32_t)(epkt->hdr[0] >> 32);
666 	adv_reg.pcie_ue_hdr[2] = (uint32_t)(epkt->hdr[1]);
667 	adv_reg.pcie_ue_hdr[3] = (uint32_t)(epkt->hdr[1] >> 32);
668 
669 	sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
670 
671 	if (epkt->rc_descr.M)
672 		adv_reg.pcie_ue_tgt_addr = epkt->addr;
673 
674 	if (!((sts == DDI_SUCCESS) || (epkt->rc_descr.M))) {
675 		/* Let the fabric message take care of error */
676 		sts = PX_NO_PANIC;
677 		goto done;
678 	}
679 
680 	/* See if the failed transaction belonged to a hardened driver */
681 	if (pf_hdl_lookup(dip, derr->fme_ena,
682 	    adv_reg.pcie_ue_tgt_trans, adv_reg.pcie_ue_tgt_addr,
683 	    adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
684 		sts = (PX_NO_PANIC);
685 	else
686 		sts = (PX_PANIC);
687 
688 	/* Add pfd to cause a fabric scan */
689 	switch (epkt->rc_descr.cond) {
690 	case CND_RCA:
691 		s_status = PCI_STAT_R_TARG_AB;
692 		break;
693 	case CND_RUR:
694 		s_status = PCI_STAT_R_MAST_AB;
695 		break;
696 	}
697 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = adv_reg.pcie_ue_tgt_bdf;
698 	PCIE_ROOT_FAULT(pfd_p)->scan_addr = adv_reg.pcie_ue_tgt_addr;
699 	PCI_BDG_ERR_REG(pfd_p)->pci_bdg_sec_stat = s_status;
700 
701 done:
702 	return (sts);
703 }
704 
705 /* ARGSUSED */
706 static int
707 px_pcie_epkt_severity(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
708 {
709 	px_pec_err_t	*pec_p = (px_pec_err_t *)epkt;
710 	px_err_pcie_t	*pcie = (px_err_pcie_t *)epkt;
711 	pf_pcie_adv_err_regs_t adv_reg;
712 	int		sts;
713 	uint32_t	temp;
714 
715 	/*
716 	 * Check for failed PIO Read/Writes, which are errors that are not
717 	 * defined in the PCIe spec.
718 	 */
719 	temp = PCIE_AER_UCE_UR | PCIE_AER_UCE_CA;
720 	if (((pec_p->pec_descr.dir == DIR_READ) ||
721 	    (pec_p->pec_descr.dir == DIR_WRITE)) &&
722 	    pec_p->pec_descr.U && (pec_p->ue_reg_status & temp)) {
723 		adv_reg.pcie_ue_hdr[0] = (uint32_t)(pec_p->hdr[0]);
724 		adv_reg.pcie_ue_hdr[1] = (uint32_t)(pec_p->hdr[0] >> 32);
725 		adv_reg.pcie_ue_hdr[2] = (uint32_t)(pec_p->hdr[1]);
726 		adv_reg.pcie_ue_hdr[3] = (uint32_t)(pec_p->hdr[1] >> 32);
727 
728 		sts = pf_tlp_decode(PCIE_DIP2BUS(dip), &adv_reg);
729 
730 		if (sts == DDI_SUCCESS &&
731 		    pf_hdl_lookup(dip, derr->fme_ena,
732 		    adv_reg.pcie_ue_tgt_trans,
733 		    adv_reg.pcie_ue_tgt_addr,
734 		    adv_reg.pcie_ue_tgt_bdf) == PF_HDL_FOUND)
735 			return (PX_NO_PANIC);
736 		else
737 			return (PX_PANIC);
738 	}
739 
740 	if (!pec_p->pec_descr.C)
741 		pec_p->ce_reg_status = 0;
742 	if (!pec_p->pec_descr.U)
743 		pec_p->ue_reg_status = 0;
744 	if (!pec_p->pec_descr.H)
745 		pec_p->hdr[0] = 0;
746 	if (!pec_p->pec_descr.I)
747 		pec_p->hdr[1] = 0;
748 
749 	/*
750 	 * According to the PCIe spec, there is a first error pointer.  If there
751 	 * are header logs recorded and there are more than one error, the log
752 	 * will belong to the error that the first error pointer points to.
753 	 *
754 	 * The regs.primary_ue expects a bit number, go through the ue register
755 	 * and find the first error that occured.  Because the sun4v epkt spec
756 	 * does not define this value, the algorithm below gives the lower bit
757 	 * priority.
758 	 */
759 	temp = pcie->ue_reg;
760 	if (temp) {
761 		int x;
762 		for (x = 0; !(temp & 0x1); x++) {
763 			temp = temp >> 1;
764 		}
765 		pcie->primary_ue = 1 << x;
766 	} else {
767 		pcie->primary_ue = 0;
768 	}
769 
770 	/* Sun4v doesn't log the TX hdr except for CTOs */
771 	if (pcie->primary_ue == PCIE_AER_UCE_TO) {
772 		pcie->tx_hdr1 = pcie->rx_hdr1;
773 		pcie->tx_hdr2 = pcie->rx_hdr2;
774 		pcie->tx_hdr3 = pcie->rx_hdr3;
775 		pcie->tx_hdr4 = pcie->rx_hdr4;
776 		pcie->rx_hdr1 = 0;
777 		pcie->rx_hdr2 = 0;
778 		pcie->rx_hdr3 = 0;
779 		pcie->rx_hdr4 = 0;
780 	} else {
781 		pcie->tx_hdr1 = 0;
782 		pcie->tx_hdr2 = 0;
783 		pcie->tx_hdr3 = 0;
784 		pcie->tx_hdr4 = 0;
785 	}
786 
787 	return (px_err_check_pcie(dip, derr, pcie));
788 }
789 
790 static int
791 px_mmu_handle_lookup(dev_info_t *dip, ddi_fm_error_t *derr, px_rc_err_t *epkt)
792 {
793 	uint64_t addr = (uint64_t)epkt->addr;
794 	pcie_req_id_t bdf = PCIE_INVALID_BDF;
795 
796 	if (epkt->rc_descr.H) {
797 		bdf = (uint32_t)((epkt->hdr[0] >> 16) && 0xFFFF);
798 	}
799 
800 	return (pf_hdl_lookup(dip, derr->fme_ena, PF_ADDR_DMA, addr,
801 	    bdf));
802 }
803