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