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