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