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