1*00d0963fSdilpreet /* 2*00d0963fSdilpreet * CDDL HEADER START 3*00d0963fSdilpreet * 4*00d0963fSdilpreet * The contents of this file are subject to the terms of the 5*00d0963fSdilpreet * Common Development and Distribution License (the "License"). 6*00d0963fSdilpreet * You may not use this file except in compliance with the License. 7*00d0963fSdilpreet * 8*00d0963fSdilpreet * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*00d0963fSdilpreet * or http://www.opensolaris.org/os/licensing. 10*00d0963fSdilpreet * See the License for the specific language governing permissions 11*00d0963fSdilpreet * and limitations under the License. 12*00d0963fSdilpreet * 13*00d0963fSdilpreet * When distributing Covered Code, include this CDDL HEADER in each 14*00d0963fSdilpreet * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*00d0963fSdilpreet * If applicable, add the following below this CDDL HEADER, with the 16*00d0963fSdilpreet * fields enclosed by brackets "[]" replaced with your own identifying 17*00d0963fSdilpreet * information: Portions Copyright [yyyy] [name of copyright owner] 18*00d0963fSdilpreet * 19*00d0963fSdilpreet * CDDL HEADER END 20*00d0963fSdilpreet */ 21*00d0963fSdilpreet 22*00d0963fSdilpreet /* 23*00d0963fSdilpreet * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*00d0963fSdilpreet * Use is subject to license terms. 25*00d0963fSdilpreet */ 26*00d0963fSdilpreet 27*00d0963fSdilpreet #pragma ident "%Z%%M% %I% %E% SMI" 28*00d0963fSdilpreet 29*00d0963fSdilpreet #include <sys/types.h> 30*00d0963fSdilpreet #include <sys/sunndi.h> 31*00d0963fSdilpreet #include <sys/sysmacros.h> 32*00d0963fSdilpreet #include <sys/ddifm_impl.h> 33*00d0963fSdilpreet #include <sys/fm/util.h> 34*00d0963fSdilpreet #include <sys/fm/protocol.h> 35*00d0963fSdilpreet #include <sys/fm/io/pci.h> 36*00d0963fSdilpreet #include <sys/fm/io/ddi.h> 37*00d0963fSdilpreet #include <sys/pci.h> 38*00d0963fSdilpreet #include <sys/pcie.h> 39*00d0963fSdilpreet #include <sys/pci_impl.h> 40*00d0963fSdilpreet #include <sys/epm.h> 41*00d0963fSdilpreet #include <sys/pcifm.h> 42*00d0963fSdilpreet 43*00d0963fSdilpreet #define PCIX_ECC_VER_CHECK(x) (((x) == PCI_PCIX_VER_1) ||\ 44*00d0963fSdilpreet ((x) == PCI_PCIX_VER_2)) 45*00d0963fSdilpreet 46*00d0963fSdilpreet /* 47*00d0963fSdilpreet * Expected PCI Express error mask values 48*00d0963fSdilpreet */ 49*00d0963fSdilpreet uint32_t pcie_expected_ce_mask = PCIE_AER_CE_AD_NFE; 50*00d0963fSdilpreet uint32_t pcie_expected_ue_mask = 0x0; 51*00d0963fSdilpreet uint32_t pcie_expected_sue_mask = 0x0; 52*00d0963fSdilpreet 53*00d0963fSdilpreet errorq_t *pci_target_queue = NULL; 54*00d0963fSdilpreet 55*00d0963fSdilpreet pci_fm_err_t pci_err_tbl[] = { 56*00d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 57*00d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 58*00d0963fSdilpreet PCI_SIG_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_FATAL, 59*00d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 60*00d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 61*00d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 62*00d0963fSdilpreet NULL, NULL, NULL, NULL, 63*00d0963fSdilpreet }; 64*00d0963fSdilpreet 65*00d0963fSdilpreet pci_fm_err_t pci_bdg_err_tbl[] = { 66*00d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 67*00d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 68*00d0963fSdilpreet PCI_REC_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_UNKNOWN, 69*00d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 70*00d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 71*00d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 72*00d0963fSdilpreet NULL, NULL, NULL, NULL, 73*00d0963fSdilpreet }; 74*00d0963fSdilpreet 75*00d0963fSdilpreet static pci_fm_err_t pciex_ce_err_tbl[] = { 76*00d0963fSdilpreet PCIEX_RE, PCIE_AER_CE_RECEIVER_ERR, NULL, DDI_FM_NONFATAL, 77*00d0963fSdilpreet PCIEX_RNR, PCIE_AER_CE_REPLAY_ROLLOVER, NULL, DDI_FM_NONFATAL, 78*00d0963fSdilpreet PCIEX_RTO, PCIE_AER_CE_REPLAY_TO, NULL, DDI_FM_NONFATAL, 79*00d0963fSdilpreet PCIEX_BDP, PCIE_AER_CE_BAD_DLLP, NULL, DDI_FM_NONFATAL, 80*00d0963fSdilpreet PCIEX_BTP, PCIE_AER_CE_BAD_TLP, NULL, DDI_FM_NONFATAL, 81*00d0963fSdilpreet PCIEX_ANFE, PCIE_AER_CE_AD_NFE, NULL, DDI_FM_NONFATAL, 82*00d0963fSdilpreet NULL, NULL, NULL, NULL, 83*00d0963fSdilpreet }; 84*00d0963fSdilpreet 85*00d0963fSdilpreet static pci_fm_err_t pciex_ue_err_tbl[] = { 86*00d0963fSdilpreet PCIEX_TE, PCIE_AER_UCE_TRAINING, NULL, DDI_FM_FATAL, 87*00d0963fSdilpreet PCIEX_DLP, PCIE_AER_UCE_DLP, NULL, DDI_FM_FATAL, 88*00d0963fSdilpreet PCIEX_SD, PCIE_AER_UCE_SD, NULL, DDI_FM_FATAL, 89*00d0963fSdilpreet PCIEX_ROF, PCIE_AER_UCE_RO, NULL, DDI_FM_FATAL, 90*00d0963fSdilpreet PCIEX_FCP, PCIE_AER_UCE_FCP, NULL, DDI_FM_FATAL, 91*00d0963fSdilpreet PCIEX_MFP, PCIE_AER_UCE_MTLP, NULL, DDI_FM_FATAL, 92*00d0963fSdilpreet PCIEX_CTO, PCIE_AER_UCE_TO, NULL, DDI_FM_NONFATAL, 93*00d0963fSdilpreet PCIEX_UC, PCIE_AER_UCE_UC, NULL, DDI_FM_NONFATAL, 94*00d0963fSdilpreet PCIEX_ECRC, PCIE_AER_UCE_ECRC, NULL, DDI_FM_UNKNOWN, 95*00d0963fSdilpreet PCIEX_CA, PCIE_AER_UCE_CA, NULL, DDI_FM_UNKNOWN, 96*00d0963fSdilpreet PCIEX_UR, PCIE_AER_UCE_UR, NULL, DDI_FM_NONFATAL, 97*00d0963fSdilpreet PCIEX_POIS, PCIE_AER_UCE_PTLP, NULL, DDI_FM_UNKNOWN, 98*00d0963fSdilpreet NULL, NULL, NULL, NULL, 99*00d0963fSdilpreet }; 100*00d0963fSdilpreet 101*00d0963fSdilpreet static pci_fm_err_t pcie_sue_err_tbl[] = { 102*00d0963fSdilpreet PCIEX_S_TA_SC, PCIE_AER_SUCE_TA_ON_SC, NULL, DDI_FM_UNKNOWN, 103*00d0963fSdilpreet PCIEX_S_MA_SC, PCIE_AER_SUCE_MA_ON_SC, NULL, DDI_FM_UNKNOWN, 104*00d0963fSdilpreet PCIEX_S_RTA, PCIE_AER_SUCE_RCVD_TA, NULL, DDI_FM_UNKNOWN, 105*00d0963fSdilpreet PCIEX_S_RMA, PCIE_AER_SUCE_RCVD_MA, NULL, DDI_FM_UNKNOWN, 106*00d0963fSdilpreet PCIEX_S_USC, PCIE_AER_SUCE_USC_ERR, NULL, DDI_FM_UNKNOWN, 107*00d0963fSdilpreet PCIEX_S_USCMD, PCIE_AER_SUCE_USC_MSG_DATA_ERR, NULL, DDI_FM_FATAL, 108*00d0963fSdilpreet PCIEX_S_UDE, PCIE_AER_SUCE_UC_DATA_ERR, NULL, DDI_FM_UNKNOWN, 109*00d0963fSdilpreet PCIEX_S_UAT, PCIE_AER_SUCE_UC_ATTR_ERR, NULL, DDI_FM_FATAL, 110*00d0963fSdilpreet PCIEX_S_UADR, PCIE_AER_SUCE_UC_ADDR_ERR, NULL, DDI_FM_FATAL, 111*00d0963fSdilpreet PCIEX_S_TEX, PCIE_AER_SUCE_TIMER_EXPIRED, NULL, DDI_FM_FATAL, 112*00d0963fSdilpreet PCIEX_S_PERR, PCIE_AER_SUCE_PERR_ASSERT, NULL, DDI_FM_UNKNOWN, 113*00d0963fSdilpreet PCIEX_S_SERR, PCIE_AER_SUCE_SERR_ASSERT, NULL, DDI_FM_FATAL, 114*00d0963fSdilpreet PCIEX_INTERR, PCIE_AER_SUCE_INTERNAL_ERR, NULL, DDI_FM_FATAL, 115*00d0963fSdilpreet NULL, NULL, NULL, NULL, 116*00d0963fSdilpreet }; 117*00d0963fSdilpreet 118*00d0963fSdilpreet static pci_fm_err_t pcix_err_tbl[] = { 119*00d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 120*00d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 121*00d0963fSdilpreet PCIX_RX_SPL_MSG, PCI_PCIX_RX_SPL_MSG, NULL, DDI_FM_UNKNOWN, 122*00d0963fSdilpreet NULL, NULL, NULL, NULL, 123*00d0963fSdilpreet }; 124*00d0963fSdilpreet 125*00d0963fSdilpreet static pci_fm_err_t pcix_sec_err_tbl[] = { 126*00d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_BSS_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 127*00d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_BSS_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 128*00d0963fSdilpreet PCIX_BSS_SPL_OR, PCI_PCIX_BSS_SPL_OR, NULL, DDI_FM_NONFATAL, 129*00d0963fSdilpreet PCIX_BSS_SPL_DLY, PCI_PCIX_BSS_SPL_DLY, NULL, DDI_FM_NONFATAL, 130*00d0963fSdilpreet NULL, NULL, NULL, NULL, 131*00d0963fSdilpreet }; 132*00d0963fSdilpreet 133*00d0963fSdilpreet static pci_fm_err_t pciex_nadv_err_tbl[] = { 134*00d0963fSdilpreet PCIEX_UR, PCIE_DEVSTS_UR_DETECTED, NULL, DDI_FM_UNKNOWN, 135*00d0963fSdilpreet PCIEX_FAT, PCIE_DEVSTS_FE_DETECTED, NULL, DDI_FM_FATAL, 136*00d0963fSdilpreet PCIEX_NONFAT, PCIE_DEVSTS_NFE_DETECTED, NULL, DDI_FM_UNKNOWN, 137*00d0963fSdilpreet PCIEX_CORR, PCIE_DEVSTS_CE_DETECTED, NULL, DDI_FM_NONFATAL, 138*00d0963fSdilpreet NULL, NULL, NULL, NULL, 139*00d0963fSdilpreet }; 140*00d0963fSdilpreet 141*00d0963fSdilpreet static int 142*00d0963fSdilpreet pci_config_check(ddi_acc_handle_t handle) 143*00d0963fSdilpreet { 144*00d0963fSdilpreet ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle); 145*00d0963fSdilpreet ddi_fm_error_t de; 146*00d0963fSdilpreet 147*00d0963fSdilpreet if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip)))) 148*00d0963fSdilpreet return (DDI_FM_OK); 149*00d0963fSdilpreet 150*00d0963fSdilpreet de.fme_version = DDI_FME_VERSION; 151*00d0963fSdilpreet 152*00d0963fSdilpreet ddi_fm_acc_err_get(handle, &de, de.fme_version); 153*00d0963fSdilpreet if (de.fme_status != DDI_FM_OK) { 154*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 155*00d0963fSdilpreet 156*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", PCI_ERROR_SUBCLASS, 157*00d0963fSdilpreet PCI_NR); 158*00d0963fSdilpreet ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena, DDI_NOSLEEP, 159*00d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 160*00d0963fSdilpreet ddi_fm_acc_err_clear(handle, de.fme_version); 161*00d0963fSdilpreet } 162*00d0963fSdilpreet return (de.fme_status); 163*00d0963fSdilpreet } 164*00d0963fSdilpreet 165*00d0963fSdilpreet static void 166*00d0963fSdilpreet pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs, 167*00d0963fSdilpreet uint8_t pcix_cap_ptr) 168*00d0963fSdilpreet { 169*00d0963fSdilpreet int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV; 170*00d0963fSdilpreet 171*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl, 172*00d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS : 173*00d0963fSdilpreet PCI_PCIX_ECC_STATUS))); 174*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 175*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID; 176*00d0963fSdilpreet else 177*00d0963fSdilpreet return; 178*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl, 179*00d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD : 180*00d0963fSdilpreet PCI_PCIX_ECC_FST_AD))); 181*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl, 182*00d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD : 183*00d0963fSdilpreet PCI_PCIX_ECC_SEC_AD))); 184*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr = pci_config_get32(( 185*00d0963fSdilpreet ddi_acc_handle_t)erpt_p->pe_hdl, 186*00d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR))); 187*00d0963fSdilpreet } 188*00d0963fSdilpreet 189*00d0963fSdilpreet static void 190*00d0963fSdilpreet pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs) 191*00d0963fSdilpreet { 192*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 193*00d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 194*00d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 195*00d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 196*00d0963fSdilpreet int i; 197*00d0963fSdilpreet 198*00d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 199*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16( 200*00d0963fSdilpreet erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS)); 201*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 202*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= 203*00d0963fSdilpreet PCIX_BDG_SEC_STATUS_VALID; 204*00d0963fSdilpreet else 205*00d0963fSdilpreet return; 206*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl, 207*00d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS)); 208*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 209*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID; 210*00d0963fSdilpreet else 211*00d0963fSdilpreet return; 212*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 213*00d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 214*00d0963fSdilpreet /* 215*00d0963fSdilpreet * PCI Express to PCI-X bridges only implement the 216*00d0963fSdilpreet * secondary side of the PCI-X ECC registers, bit one is 217*00d0963fSdilpreet * read-only so we make sure we do not write to it. 218*00d0963fSdilpreet */ 219*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 220*00d0963fSdilpreet pcix_bdg_ecc_regs = 221*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[1]; 222*00d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_bdg_ecc_regs, 223*00d0963fSdilpreet pcix_bdg_cap_ptr); 224*00d0963fSdilpreet } else { 225*00d0963fSdilpreet for (i = 0; i < 2; i++) { 226*00d0963fSdilpreet pcix_bdg_ecc_regs = 227*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 228*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 229*00d0963fSdilpreet (pcix_bdg_cap_ptr + 230*00d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), i); 231*00d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, 232*00d0963fSdilpreet pcix_bdg_ecc_regs, 233*00d0963fSdilpreet pcix_bdg_cap_ptr); 234*00d0963fSdilpreet } 235*00d0963fSdilpreet } 236*00d0963fSdilpreet } 237*00d0963fSdilpreet } else { 238*00d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 239*00d0963fSdilpreet uint8_t pcix_cap_ptr; 240*00d0963fSdilpreet 241*00d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 242*00d0963fSdilpreet 243*00d0963fSdilpreet pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl, 244*00d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_COMMAND)); 245*00d0963fSdilpreet pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl, 246*00d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS)); 247*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 248*00d0963fSdilpreet pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID; 249*00d0963fSdilpreet else 250*00d0963fSdilpreet return; 251*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 252*00d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 253*00d0963fSdilpreet pcix_regs->pcix_ecc_regs; 254*00d0963fSdilpreet 255*00d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs, 256*00d0963fSdilpreet pcix_cap_ptr); 257*00d0963fSdilpreet } 258*00d0963fSdilpreet } 259*00d0963fSdilpreet } 260*00d0963fSdilpreet 261*00d0963fSdilpreet static void 262*00d0963fSdilpreet pcie_regs_gather(pci_erpt_t *erpt_p) 263*00d0963fSdilpreet { 264*00d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 265*00d0963fSdilpreet uint8_t pcie_cap_ptr; 266*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 267*00d0963fSdilpreet uint16_t pcie_ecap_ptr; 268*00d0963fSdilpreet 269*00d0963fSdilpreet pcie_cap_ptr = pcie_regs->pcie_cap_ptr; 270*00d0963fSdilpreet 271*00d0963fSdilpreet pcie_regs->pcie_err_status = pci_config_get16(erpt_p->pe_hdl, 272*00d0963fSdilpreet pcie_cap_ptr + PCIE_DEVSTS); 273*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 274*00d0963fSdilpreet pcie_regs->pcie_vflags |= PCIE_ERR_STATUS_VALID; 275*00d0963fSdilpreet else 276*00d0963fSdilpreet return; 277*00d0963fSdilpreet 278*00d0963fSdilpreet pcie_regs->pcie_err_ctl = pci_config_get16(erpt_p->pe_hdl, 279*00d0963fSdilpreet (pcie_cap_ptr + PCIE_DEVCTL)); 280*00d0963fSdilpreet 281*00d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && (erpt_p->pe_dflags & 282*00d0963fSdilpreet PCIX_DEV)) 283*00d0963fSdilpreet pcix_regs_gather(erpt_p, pcie_regs->pcix_bdg_regs); 284*00d0963fSdilpreet 285*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 286*00d0963fSdilpreet pcie_rc_error_regs_t *pcie_rc_regs = pcie_regs->pcie_rc_regs; 287*00d0963fSdilpreet 288*00d0963fSdilpreet pcie_rc_regs->pcie_rc_status = pci_config_get32(erpt_p->pe_hdl, 289*00d0963fSdilpreet (pcie_cap_ptr + PCIE_ROOTSTS)); 290*00d0963fSdilpreet pcie_rc_regs->pcie_rc_ctl = pci_config_get16(erpt_p->pe_hdl, 291*00d0963fSdilpreet (pcie_cap_ptr + PCIE_ROOTCTL)); 292*00d0963fSdilpreet } 293*00d0963fSdilpreet 294*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) 295*00d0963fSdilpreet return; 296*00d0963fSdilpreet 297*00d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 298*00d0963fSdilpreet 299*00d0963fSdilpreet pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr; 300*00d0963fSdilpreet 301*00d0963fSdilpreet pcie_adv_regs->pcie_ue_status = pci_config_get32(erpt_p->pe_hdl, 302*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_STS); 303*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 304*00d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_STATUS_VALID; 305*00d0963fSdilpreet 306*00d0963fSdilpreet pcie_adv_regs->pcie_ue_mask = pci_config_get32(erpt_p->pe_hdl, 307*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_MASK); 308*00d0963fSdilpreet pcie_adv_regs->pcie_ue_sev = pci_config_get32(erpt_p->pe_hdl, 309*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_SERV); 310*00d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl = pci_config_get32(erpt_p->pe_hdl, 311*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CTL); 312*00d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0 = pci_config_get32(erpt_p->pe_hdl, 313*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_HDR_LOG); 314*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) { 315*00d0963fSdilpreet int i; 316*00d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_HDR_VALID; 317*00d0963fSdilpreet 318*00d0963fSdilpreet for (i = 0; i < 3; i++) { 319*00d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[i] = pci_config_get32( 320*00d0963fSdilpreet erpt_p->pe_hdl, pcie_ecap_ptr + PCIE_AER_HDR_LOG + 321*00d0963fSdilpreet (4 * (i + 1))); 322*00d0963fSdilpreet } 323*00d0963fSdilpreet } 324*00d0963fSdilpreet 325*00d0963fSdilpreet pcie_adv_regs->pcie_ce_status = pci_config_get32(erpt_p->pe_hdl, 326*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_STS); 327*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 328*00d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_CE_STATUS_VALID; 329*00d0963fSdilpreet 330*00d0963fSdilpreet pcie_adv_regs->pcie_ce_mask = pci_config_get32(erpt_p->pe_hdl, 331*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_MASK); 332*00d0963fSdilpreet 333*00d0963fSdilpreet /* 334*00d0963fSdilpreet * If pci express to pci bridge then grab the bridge 335*00d0963fSdilpreet * error registers. 336*00d0963fSdilpreet */ 337*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 338*00d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 339*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 340*00d0963fSdilpreet 341*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_status = 342*00d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 343*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_STS); 344*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 345*00d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_STATUS_VALID; 346*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0 = pci_config_get32(erpt_p->pe_hdl, 347*00d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_SHDR_LOG)); 348*00d0963fSdilpreet 349*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) { 350*00d0963fSdilpreet int i; 351*00d0963fSdilpreet 352*00d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_HDR_VALID; 353*00d0963fSdilpreet 354*00d0963fSdilpreet for (i = 0; i < 3; i++) { 355*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[i] = 356*00d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 357*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SHDR_LOG + 358*00d0963fSdilpreet (4 * (i + 1))); 359*00d0963fSdilpreet } 360*00d0963fSdilpreet } 361*00d0963fSdilpreet } 362*00d0963fSdilpreet /* 363*00d0963fSdilpreet * If PCI Express root complex then grab the root complex 364*00d0963fSdilpreet * error registers. 365*00d0963fSdilpreet */ 366*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 367*00d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 368*00d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 369*00d0963fSdilpreet 370*00d0963fSdilpreet pcie_rc_regs->pcie_rc_err_cmd = pci_config_get32(erpt_p->pe_hdl, 371*00d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_CMD)); 372*00d0963fSdilpreet pcie_rc_regs->pcie_rc_err_status = 373*00d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 374*00d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_STS)); 375*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 376*00d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= 377*00d0963fSdilpreet PCIE_RC_ERR_STATUS_VALID; 378*00d0963fSdilpreet pcie_rc_regs->pcie_rc_ce_src_id = 379*00d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 380*00d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_CE_SRC_ID)); 381*00d0963fSdilpreet pcie_rc_regs->pcie_rc_ue_src_id = 382*00d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 383*00d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_ERR_SRC_ID)); 384*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 385*00d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SRC_ID_VALID; 386*00d0963fSdilpreet } 387*00d0963fSdilpreet } 388*00d0963fSdilpreet 389*00d0963fSdilpreet /*ARGSUSED*/ 390*00d0963fSdilpreet static void 391*00d0963fSdilpreet pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p) 392*00d0963fSdilpreet { 393*00d0963fSdilpreet pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs; 394*00d0963fSdilpreet 395*00d0963fSdilpreet /* 396*00d0963fSdilpreet * Start by reading all the error registers that are available for 397*00d0963fSdilpreet * pci and pci express and for leaf devices and bridges/switches 398*00d0963fSdilpreet */ 399*00d0963fSdilpreet pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl, 400*00d0963fSdilpreet PCI_CONF_STAT); 401*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK) 402*00d0963fSdilpreet return; 403*00d0963fSdilpreet pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID; 404*00d0963fSdilpreet pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl, 405*00d0963fSdilpreet PCI_CONF_COMM); 406*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK) 407*00d0963fSdilpreet return; 408*00d0963fSdilpreet 409*00d0963fSdilpreet /* 410*00d0963fSdilpreet * If pci-pci bridge grab PCI bridge specific error registers. 411*00d0963fSdilpreet */ 412*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 413*00d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_sec_stat = 414*00d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS); 415*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 416*00d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 417*00d0963fSdilpreet PCI_BDG_SEC_STAT_VALID; 418*00d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_ctrl = 419*00d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL); 420*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 421*00d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 422*00d0963fSdilpreet PCI_BDG_CTRL_VALID; 423*00d0963fSdilpreet } 424*00d0963fSdilpreet 425*00d0963fSdilpreet /* 426*00d0963fSdilpreet * If pci express device grab pci express error registers and 427*00d0963fSdilpreet * check for advanced error reporting features and grab them if 428*00d0963fSdilpreet * available. 429*00d0963fSdilpreet */ 430*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 431*00d0963fSdilpreet pcie_regs_gather(erpt_p); 432*00d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 433*00d0963fSdilpreet pcix_regs_gather(erpt_p, erpt_p->pe_regs); 434*00d0963fSdilpreet 435*00d0963fSdilpreet } 436*00d0963fSdilpreet 437*00d0963fSdilpreet static void 438*00d0963fSdilpreet pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs) 439*00d0963fSdilpreet { 440*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 441*00d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 442*00d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 443*00d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 444*00d0963fSdilpreet int i; 445*00d0963fSdilpreet 446*00d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 447*00d0963fSdilpreet 448*00d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) 449*00d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, 450*00d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS), 451*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat); 452*00d0963fSdilpreet 453*00d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) 454*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 455*00d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS), 456*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat); 457*00d0963fSdilpreet 458*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags = 0x0; 459*00d0963fSdilpreet 460*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 461*00d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 462*00d0963fSdilpreet /* 463*00d0963fSdilpreet * PCI Express to PCI-X bridges only implement the 464*00d0963fSdilpreet * secondary side of the PCI-X ECC registers, bit one is 465*00d0963fSdilpreet * read-only so we make sure we do not write to it. 466*00d0963fSdilpreet */ 467*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 468*00d0963fSdilpreet pcix_bdg_ecc_regs = 469*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[1]; 470*00d0963fSdilpreet 471*00d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 472*00d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 473*00d0963fSdilpreet 474*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 475*00d0963fSdilpreet (pcix_bdg_cap_ptr + 476*00d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 477*00d0963fSdilpreet pcix_bdg_ecc_regs-> 478*00d0963fSdilpreet pcix_ecc_ctlstat); 479*00d0963fSdilpreet } 480*00d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 0x0; 481*00d0963fSdilpreet } else { 482*00d0963fSdilpreet for (i = 0; i < 2; i++) { 483*00d0963fSdilpreet pcix_bdg_ecc_regs = 484*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 485*00d0963fSdilpreet 486*00d0963fSdilpreet 487*00d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 488*00d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 489*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 490*00d0963fSdilpreet (pcix_bdg_cap_ptr + 491*00d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 492*00d0963fSdilpreet i); 493*00d0963fSdilpreet 494*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 495*00d0963fSdilpreet (pcix_bdg_cap_ptr + 496*00d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 497*00d0963fSdilpreet pcix_bdg_ecc_regs-> 498*00d0963fSdilpreet pcix_ecc_ctlstat); 499*00d0963fSdilpreet } 500*00d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 501*00d0963fSdilpreet 0x0; 502*00d0963fSdilpreet } 503*00d0963fSdilpreet } 504*00d0963fSdilpreet } 505*00d0963fSdilpreet } else { 506*00d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 507*00d0963fSdilpreet uint8_t pcix_cap_ptr; 508*00d0963fSdilpreet 509*00d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 510*00d0963fSdilpreet 511*00d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) 512*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 513*00d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS), 514*00d0963fSdilpreet pcix_regs->pcix_status); 515*00d0963fSdilpreet 516*00d0963fSdilpreet pcix_regs->pcix_vflags = 0x0; 517*00d0963fSdilpreet 518*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 519*00d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 520*00d0963fSdilpreet pcix_regs->pcix_ecc_regs; 521*00d0963fSdilpreet 522*00d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & 523*00d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) 524*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 525*00d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_ECC_STATUS), 526*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat); 527*00d0963fSdilpreet 528*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags = 0x0; 529*00d0963fSdilpreet } 530*00d0963fSdilpreet } 531*00d0963fSdilpreet } 532*00d0963fSdilpreet 533*00d0963fSdilpreet static void 534*00d0963fSdilpreet pcie_regs_clear(pci_erpt_t *erpt_p) 535*00d0963fSdilpreet { 536*00d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 537*00d0963fSdilpreet uint8_t pcie_cap_ptr; 538*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 539*00d0963fSdilpreet uint16_t pcie_ecap_ptr; 540*00d0963fSdilpreet 541*00d0963fSdilpreet pcie_cap_ptr = pcie_regs->pcie_cap_ptr; 542*00d0963fSdilpreet 543*00d0963fSdilpreet if (pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) 544*00d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, pcie_cap_ptr + PCIE_DEVSTS, 545*00d0963fSdilpreet pcie_regs->pcie_err_status); 546*00d0963fSdilpreet 547*00d0963fSdilpreet pcie_regs->pcie_vflags = 0x0; 548*00d0963fSdilpreet 549*00d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 550*00d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) 551*00d0963fSdilpreet pcix_regs_clear(erpt_p, pcie_regs->pcix_bdg_regs); 552*00d0963fSdilpreet 553*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) 554*00d0963fSdilpreet return; 555*00d0963fSdilpreet 556*00d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 557*00d0963fSdilpreet 558*00d0963fSdilpreet pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr; 559*00d0963fSdilpreet 560*00d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) 561*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 562*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_STS, 563*00d0963fSdilpreet pcie_adv_regs->pcie_ue_status); 564*00d0963fSdilpreet 565*00d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) 566*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 567*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_STS, 568*00d0963fSdilpreet pcie_adv_regs->pcie_ce_status); 569*00d0963fSdilpreet 570*00d0963fSdilpreet 571*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 572*00d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 573*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 574*00d0963fSdilpreet 575*00d0963fSdilpreet 576*00d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID) 577*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 578*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_STS, 579*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_status); 580*00d0963fSdilpreet } 581*00d0963fSdilpreet /* 582*00d0963fSdilpreet * If PCI Express root complex then clear the root complex 583*00d0963fSdilpreet * error registers. 584*00d0963fSdilpreet */ 585*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 586*00d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 587*00d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 588*00d0963fSdilpreet 589*00d0963fSdilpreet 590*00d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) 591*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 592*00d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_STS), 593*00d0963fSdilpreet pcie_rc_regs->pcie_rc_err_status); 594*00d0963fSdilpreet } 595*00d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags = 0x0; 596*00d0963fSdilpreet } 597*00d0963fSdilpreet 598*00d0963fSdilpreet static void 599*00d0963fSdilpreet pci_regs_clear(pci_erpt_t *erpt_p) 600*00d0963fSdilpreet { 601*00d0963fSdilpreet /* 602*00d0963fSdilpreet * Finally clear the error bits 603*00d0963fSdilpreet */ 604*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 605*00d0963fSdilpreet pcie_regs_clear(erpt_p); 606*00d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 607*00d0963fSdilpreet pcix_regs_clear(erpt_p, erpt_p->pe_regs); 608*00d0963fSdilpreet 609*00d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID) 610*00d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT, 611*00d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status); 612*00d0963fSdilpreet 613*00d0963fSdilpreet erpt_p->pe_pci_regs->pci_vflags = 0x0; 614*00d0963fSdilpreet 615*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 616*00d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 617*00d0963fSdilpreet PCI_BDG_SEC_STAT_VALID) 618*00d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS, 619*00d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs-> 620*00d0963fSdilpreet pci_bdg_sec_stat); 621*00d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 622*00d0963fSdilpreet PCI_BDG_CTRL_VALID) 623*00d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL, 624*00d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl); 625*00d0963fSdilpreet 626*00d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0; 627*00d0963fSdilpreet } 628*00d0963fSdilpreet } 629*00d0963fSdilpreet 630*00d0963fSdilpreet /* 631*00d0963fSdilpreet * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport 632*00d0963fSdilpreet * generation. 633*00d0963fSdilpreet */ 634*00d0963fSdilpreet /* ARGSUSED */ 635*00d0963fSdilpreet static void 636*00d0963fSdilpreet pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 637*00d0963fSdilpreet { 638*00d0963fSdilpreet uint8_t pcix_cap_ptr; 639*00d0963fSdilpreet int i; 640*00d0963fSdilpreet 641*00d0963fSdilpreet pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 642*00d0963fSdilpreet "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 643*00d0963fSdilpreet 644*00d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 645*00d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 646*00d0963fSdilpreet else 647*00d0963fSdilpreet return; 648*00d0963fSdilpreet 649*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 650*00d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 651*00d0963fSdilpreet 652*00d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t), 653*00d0963fSdilpreet KM_SLEEP); 654*00d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 655*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 656*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl, 657*00d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 658*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 659*00d0963fSdilpreet for (i = 0; i < 2; i++) { 660*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 661*00d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 662*00d0963fSdilpreet KM_SLEEP); 663*00d0963fSdilpreet } 664*00d0963fSdilpreet } 665*00d0963fSdilpreet } else { 666*00d0963fSdilpreet pcix_error_regs_t *pcix_regs; 667*00d0963fSdilpreet 668*00d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t), 669*00d0963fSdilpreet KM_SLEEP); 670*00d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 671*00d0963fSdilpreet pcix_regs->pcix_cap_ptr = pcix_cap_ptr; 672*00d0963fSdilpreet pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl, 673*00d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 674*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 675*00d0963fSdilpreet pcix_regs->pcix_ecc_regs = kmem_zalloc( 676*00d0963fSdilpreet sizeof (pcix_ecc_regs_t), KM_SLEEP); 677*00d0963fSdilpreet } 678*00d0963fSdilpreet } 679*00d0963fSdilpreet } 680*00d0963fSdilpreet 681*00d0963fSdilpreet static void 682*00d0963fSdilpreet pcie_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 683*00d0963fSdilpreet { 684*00d0963fSdilpreet pcie_error_regs_t *pcie_regs; 685*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 686*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 687*00d0963fSdilpreet uint8_t pcix_cap_ptr; 688*00d0963fSdilpreet uint8_t pcie_cap_ptr; 689*00d0963fSdilpreet uint16_t pcie_ecap_ptr; 690*00d0963fSdilpreet uint16_t dev_type = 0; 691*00d0963fSdilpreet uint32_t mask = pcie_expected_ue_mask; 692*00d0963fSdilpreet 693*00d0963fSdilpreet /* 694*00d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 695*00d0963fSdilpreet * interfaces create the necessary properties for us. 696*00d0963fSdilpreet */ 697*00d0963fSdilpreet #if defined(__sparc) 698*00d0963fSdilpreet ushort_t status; 699*00d0963fSdilpreet uint32_t slot_cap; 700*00d0963fSdilpreet uint8_t cap_ptr = 0; 701*00d0963fSdilpreet uint8_t cap_id = 0; 702*00d0963fSdilpreet uint32_t hdr, hdr_next_ptr, hdr_cap_id; 703*00d0963fSdilpreet uint16_t offset = P2ALIGN(PCIE_EXT_CAP, 4); 704*00d0963fSdilpreet uint16_t aer_ptr = 0; 705*00d0963fSdilpreet 706*00d0963fSdilpreet cap_ptr = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_CAP_PTR); 707*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) { 708*00d0963fSdilpreet while ((cap_id = pci_config_get8(erpt_p->pe_hdl, cap_ptr)) != 709*00d0963fSdilpreet 0xff) { 710*00d0963fSdilpreet if (cap_id == PCI_CAP_ID_PCIX) { 711*00d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 712*00d0963fSdilpreet "pcix-capid-pointer", cap_ptr); 713*00d0963fSdilpreet } 714*00d0963fSdilpreet if (cap_id == PCI_CAP_ID_PCI_E) { 715*00d0963fSdilpreet status = pci_config_get16(erpt_p->pe_hdl, cap_ptr + 2); 716*00d0963fSdilpreet if (status & PCIE_PCIECAP_SLOT_IMPL) { 717*00d0963fSdilpreet /* offset 14h is Slot Cap Register */ 718*00d0963fSdilpreet slot_cap = pci_config_get32(erpt_p->pe_hdl, 719*00d0963fSdilpreet cap_ptr + PCIE_SLOTCAP); 720*00d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 721*00d0963fSdilpreet "pcie-slotcap-reg", slot_cap); 722*00d0963fSdilpreet } 723*00d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 724*00d0963fSdilpreet "pcie-capid-reg", pci_config_get16(erpt_p->pe_hdl, 725*00d0963fSdilpreet cap_ptr + PCIE_PCIECAP)); 726*00d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 727*00d0963fSdilpreet "pcie-capid-pointer", cap_ptr); 728*00d0963fSdilpreet 729*00d0963fSdilpreet } 730*00d0963fSdilpreet if ((cap_ptr = pci_config_get8(erpt_p->pe_hdl, 731*00d0963fSdilpreet cap_ptr + 1)) == 0xff || cap_ptr == 0 || 732*00d0963fSdilpreet (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK)) 733*00d0963fSdilpreet break; 734*00d0963fSdilpreet } 735*00d0963fSdilpreet } 736*00d0963fSdilpreet 737*00d0963fSdilpreet #endif 738*00d0963fSdilpreet 739*00d0963fSdilpreet pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 740*00d0963fSdilpreet "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 741*00d0963fSdilpreet 742*00d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 743*00d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 744*00d0963fSdilpreet 745*00d0963fSdilpreet pcie_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 746*00d0963fSdilpreet DDI_PROP_DONTPASS, "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 747*00d0963fSdilpreet 748*00d0963fSdilpreet if (pcie_cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 749*00d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_DEV; 750*00d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcie_error_regs_t), 751*00d0963fSdilpreet KM_SLEEP); 752*00d0963fSdilpreet pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 753*00d0963fSdilpreet pcie_regs->pcie_cap_ptr = pcie_cap_ptr; 754*00d0963fSdilpreet } 755*00d0963fSdilpreet 756*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) 757*00d0963fSdilpreet return; 758*00d0963fSdilpreet 759*00d0963fSdilpreet /* 760*00d0963fSdilpreet * Don't currently need to check for version here because we are 761*00d0963fSdilpreet * compliant with PCIE 1.0a which is version 0 and is guaranteed 762*00d0963fSdilpreet * software compatibility with future versions. We will need to 763*00d0963fSdilpreet * add errors for new detectors/features which are added in newer 764*00d0963fSdilpreet * revisions [sec 7.8.2]. 765*00d0963fSdilpreet */ 766*00d0963fSdilpreet pcie_regs->pcie_cap = pci_config_get16(erpt_p->pe_hdl, 767*00d0963fSdilpreet pcie_regs->pcie_cap_ptr + PCIE_PCIECAP); 768*00d0963fSdilpreet 769*00d0963fSdilpreet dev_type = pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK; 770*00d0963fSdilpreet 771*00d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 772*00d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 773*00d0963fSdilpreet int i; 774*00d0963fSdilpreet 775*00d0963fSdilpreet pcie_regs->pcix_bdg_regs = 776*00d0963fSdilpreet kmem_zalloc(sizeof (pcix_bdg_error_regs_t), KM_SLEEP); 777*00d0963fSdilpreet 778*00d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 779*00d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_ver = 780*00d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 781*00d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 782*00d0963fSdilpreet 783*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcie_regs->pcix_bdg_regs->pcix_bdg_ver)) 784*00d0963fSdilpreet for (i = 0; i < 2; i++) 785*00d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 786*00d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 787*00d0963fSdilpreet KM_SLEEP); 788*00d0963fSdilpreet } 789*00d0963fSdilpreet 790*00d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) { 791*00d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_RC_DEV; 792*00d0963fSdilpreet pcie_regs->pcie_rc_regs = kmem_zalloc( 793*00d0963fSdilpreet sizeof (pcie_rc_error_regs_t), KM_SLEEP); 794*00d0963fSdilpreet } 795*00d0963fSdilpreet /* 796*00d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 797*00d0963fSdilpreet * interfaces create the necessary properties for us. 798*00d0963fSdilpreet */ 799*00d0963fSdilpreet #if defined(__sparc) 800*00d0963fSdilpreet 801*00d0963fSdilpreet hdr = pci_config_get32(erpt_p->pe_hdl, offset); 802*00d0963fSdilpreet hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 803*00d0963fSdilpreet PCIE_EXT_CAP_NEXT_PTR_MASK; 804*00d0963fSdilpreet hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK; 805*00d0963fSdilpreet 806*00d0963fSdilpreet while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) && 807*00d0963fSdilpreet (hdr_cap_id != PCIE_EXT_CAP_ID_AER)) { 808*00d0963fSdilpreet offset = P2ALIGN(hdr_next_ptr, 4); 809*00d0963fSdilpreet hdr = pci_config_get32(erpt_p->pe_hdl, offset); 810*00d0963fSdilpreet hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 811*00d0963fSdilpreet PCIE_EXT_CAP_NEXT_PTR_MASK; 812*00d0963fSdilpreet hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & 813*00d0963fSdilpreet PCIE_EXT_CAP_ID_MASK; 814*00d0963fSdilpreet } 815*00d0963fSdilpreet 816*00d0963fSdilpreet if (hdr_cap_id == PCIE_EXT_CAP_ID_AER) 817*00d0963fSdilpreet aer_ptr = P2ALIGN(offset, 4); 818*00d0963fSdilpreet if (aer_ptr != PCI_CAP_NEXT_PTR_NULL) 819*00d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 820*00d0963fSdilpreet "pcie-aer-pointer", aer_ptr); 821*00d0963fSdilpreet #endif 822*00d0963fSdilpreet 823*00d0963fSdilpreet /* 824*00d0963fSdilpreet * Find and store if this device is capable of pci express 825*00d0963fSdilpreet * advanced errors, if not report an error against the device. 826*00d0963fSdilpreet */ 827*00d0963fSdilpreet pcie_ecap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 828*00d0963fSdilpreet "pcie-aer-pointer", PCI_CAP_NEXT_PTR_NULL); 829*00d0963fSdilpreet if (pcie_ecap_ptr != PCI_CAP_NEXT_PTR_NULL) { 830*00d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_ADV_DEV; 831*00d0963fSdilpreet pcie_regs->pcie_adv_regs = kmem_zalloc( 832*00d0963fSdilpreet sizeof (pcie_adv_error_regs_t), KM_SLEEP); 833*00d0963fSdilpreet pcie_regs->pcie_adv_regs->pcie_adv_cap_ptr = pcie_ecap_ptr; 834*00d0963fSdilpreet } 835*00d0963fSdilpreet 836*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 837*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 838*00d0963fSdilpreet PCIEX_ERROR_SUBCLASS, PCIEX_NADV); 839*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, NULL, DDI_NOSLEEP, 840*00d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 841*00d0963fSdilpreet return; 842*00d0963fSdilpreet } 843*00d0963fSdilpreet 844*00d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 845*00d0963fSdilpreet 846*00d0963fSdilpreet if (pcie_adv_regs == NULL) 847*00d0963fSdilpreet return; 848*00d0963fSdilpreet /* 849*00d0963fSdilpreet * Initialize structures for advanced PCI Express devices. 850*00d0963fSdilpreet */ 851*00d0963fSdilpreet 852*00d0963fSdilpreet /* 853*00d0963fSdilpreet * Advanced error registers exist for PCI Express to PCI(X) Bridges and 854*00d0963fSdilpreet * may also exist for PCI(X) to PCI Express Bridges, the latter is not 855*00d0963fSdilpreet * well explained in the PCI Express to PCI/PCI-X Bridge Specification 856*00d0963fSdilpreet * 1.0 and will be left out of the current gathering of these registers. 857*00d0963fSdilpreet */ 858*00d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) { 859*00d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_2PCI_DEV; 860*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs = kmem_zalloc( 861*00d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t), KM_SLEEP); 862*00d0963fSdilpreet } 863*00d0963fSdilpreet 864*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 865*00d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs = kmem_zalloc( 866*00d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t), KM_SLEEP); 867*00d0963fSdilpreet 868*00d0963fSdilpreet /* 869*00d0963fSdilpreet * Check that mask values are as expected, if not 870*00d0963fSdilpreet * change them to what we desire. 871*00d0963fSdilpreet */ 872*00d0963fSdilpreet pci_regs_gather(dip, erpt_p); 873*00d0963fSdilpreet pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 874*00d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_ce_mask != pcie_expected_ce_mask) { 875*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 876*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_MASK, pcie_expected_ce_mask); 877*00d0963fSdilpreet } 878*00d0963fSdilpreet 879*00d0963fSdilpreet /* Disable PTLP/ECRC (or mask these two) for Switches */ 880*00d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_UP || 881*00d0963fSdilpreet dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) 882*00d0963fSdilpreet mask |= PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC; 883*00d0963fSdilpreet 884*00d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_ue_mask != mask) { 885*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 886*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_MASK, mask); 887*00d0963fSdilpreet } 888*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 889*00d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_adv_bdg_regs->pcie_sue_mask 890*00d0963fSdilpreet != pcie_expected_sue_mask) { 891*00d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 892*00d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_MASK, 893*00d0963fSdilpreet pcie_expected_sue_mask); 894*00d0963fSdilpreet } 895*00d0963fSdilpreet } 896*00d0963fSdilpreet } 897*00d0963fSdilpreet 898*00d0963fSdilpreet /* 899*00d0963fSdilpreet * pci_ereport_setup: Detect PCI device type and initialize structures to be 900*00d0963fSdilpreet * used to generate ereports based on detected generic device errors. 901*00d0963fSdilpreet */ 902*00d0963fSdilpreet void 903*00d0963fSdilpreet pci_ereport_setup(dev_info_t *dip) 904*00d0963fSdilpreet { 905*00d0963fSdilpreet struct dev_info *devi = DEVI(dip); 906*00d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl; 907*00d0963fSdilpreet pci_erpt_t *erpt_p; 908*00d0963fSdilpreet uint8_t pci_hdr_type; 909*00d0963fSdilpreet uint16_t pci_status; 910*00d0963fSdilpreet pci_regspec_t *pci_rp; 911*00d0963fSdilpreet int32_t len; 912*00d0963fSdilpreet uint32_t phys_hi; 913*00d0963fSdilpreet 914*00d0963fSdilpreet /* 915*00d0963fSdilpreet * If device is not ereport capbable then report an error against the 916*00d0963fSdilpreet * driver for using this interface, 917*00d0963fSdilpreet */ 918*00d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 919*00d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 920*00d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 921*00d0963fSdilpreet return; 922*00d0963fSdilpreet } 923*00d0963fSdilpreet 924*00d0963fSdilpreet /* 925*00d0963fSdilpreet * ASSERT fmhdl exists and fh_bus_specific is NULL. 926*00d0963fSdilpreet */ 927*00d0963fSdilpreet ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL)); 928*00d0963fSdilpreet 929*00d0963fSdilpreet erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP); 930*00d0963fSdilpreet 931*00d0963fSdilpreet if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS) 932*00d0963fSdilpreet goto error; 933*00d0963fSdilpreet 934*00d0963fSdilpreet erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP); 935*00d0963fSdilpreet 936*00d0963fSdilpreet pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT); 937*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK) 938*00d0963fSdilpreet goto error; 939*00d0963fSdilpreet 940*00d0963fSdilpreet /* 941*00d0963fSdilpreet * Get header type and record if device is a bridge. 942*00d0963fSdilpreet */ 943*00d0963fSdilpreet pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER); 944*00d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK) 945*00d0963fSdilpreet goto error; 946*00d0963fSdilpreet 947*00d0963fSdilpreet /* 948*00d0963fSdilpreet * Check to see if PCI device is a bridge, if so allocate pci bridge 949*00d0963fSdilpreet * error register structure. 950*00d0963fSdilpreet */ 951*00d0963fSdilpreet if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 952*00d0963fSdilpreet erpt_p->pe_dflags |= PCI_BRIDGE_DEV; 953*00d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc( 954*00d0963fSdilpreet sizeof (pci_bdg_error_regs_t), KM_SLEEP); 955*00d0963fSdilpreet } 956*00d0963fSdilpreet 957*00d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 958*00d0963fSdilpreet (caddr_t)&pci_rp, &len) == DDI_SUCCESS) { 959*00d0963fSdilpreet phys_hi = pci_rp->pci_phys_hi; 960*00d0963fSdilpreet kmem_free(pci_rp, len); 961*00d0963fSdilpreet 962*00d0963fSdilpreet erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >> 963*00d0963fSdilpreet PCI_REG_FUNC_SHIFT); 964*00d0963fSdilpreet } 965*00d0963fSdilpreet 966*00d0963fSdilpreet 967*00d0963fSdilpreet if (!(pci_status & PCI_STAT_CAP)) { 968*00d0963fSdilpreet goto done; 969*00d0963fSdilpreet } 970*00d0963fSdilpreet 971*00d0963fSdilpreet /* 972*00d0963fSdilpreet * Initialize structures for PCI Express and PCI-X devices. 973*00d0963fSdilpreet * Order matters below and pcie_ereport_setup should preceed 974*00d0963fSdilpreet * pcix_ereport_setup. 975*00d0963fSdilpreet */ 976*00d0963fSdilpreet pcie_ereport_setup(dip, erpt_p); 977*00d0963fSdilpreet 978*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) { 979*00d0963fSdilpreet pcix_ereport_setup(dip, erpt_p); 980*00d0963fSdilpreet } 981*00d0963fSdilpreet 982*00d0963fSdilpreet done: 983*00d0963fSdilpreet pci_regs_gather(dip, erpt_p); 984*00d0963fSdilpreet pci_regs_clear(erpt_p); 985*00d0963fSdilpreet 986*00d0963fSdilpreet /* 987*00d0963fSdilpreet * Before returning set fh_bus_specific to completed pci_erpt_t 988*00d0963fSdilpreet * structure 989*00d0963fSdilpreet */ 990*00d0963fSdilpreet fmhdl->fh_bus_specific = (void *)erpt_p; 991*00d0963fSdilpreet 992*00d0963fSdilpreet return; 993*00d0963fSdilpreet error: 994*00d0963fSdilpreet if (erpt_p->pe_pci_regs) 995*00d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 996*00d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 997*00d0963fSdilpreet erpt_p = NULL; 998*00d0963fSdilpreet } 999*00d0963fSdilpreet 1000*00d0963fSdilpreet static void 1001*00d0963fSdilpreet pcix_ereport_teardown(pci_erpt_t *erpt_p) 1002*00d0963fSdilpreet { 1003*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 1004*00d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 1005*00d0963fSdilpreet uint16_t pcix_ver; 1006*00d0963fSdilpreet 1007*00d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 1008*00d0963fSdilpreet pcix_ver = pcix_bdg_regs->pcix_bdg_ver; 1009*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 1010*00d0963fSdilpreet int i; 1011*00d0963fSdilpreet for (i = 0; i < 2; i++) 1012*00d0963fSdilpreet kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i], 1013*00d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 1014*00d0963fSdilpreet } 1015*00d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t)); 1016*00d0963fSdilpreet } else { 1017*00d0963fSdilpreet pcix_error_regs_t *pcix_regs; 1018*00d0963fSdilpreet uint16_t pcix_ver; 1019*00d0963fSdilpreet 1020*00d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 1021*00d0963fSdilpreet pcix_ver = pcix_regs->pcix_ver; 1022*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 1023*00d0963fSdilpreet kmem_free(pcix_regs->pcix_ecc_regs, 1024*00d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 1025*00d0963fSdilpreet } 1026*00d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t)); 1027*00d0963fSdilpreet } 1028*00d0963fSdilpreet } 1029*00d0963fSdilpreet 1030*00d0963fSdilpreet static void 1031*00d0963fSdilpreet pcie_ereport_teardown(pci_erpt_t *erpt_p) 1032*00d0963fSdilpreet { 1033*00d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 1034*00d0963fSdilpreet 1035*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_ADV_DEV) { 1036*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv = pcie_regs->pcie_adv_regs; 1037*00d0963fSdilpreet 1038*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) 1039*00d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_bdg_regs, 1040*00d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t)); 1041*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 1042*00d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_rc_regs, 1043*00d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t)); 1044*00d0963fSdilpreet kmem_free(pcie_adv, sizeof (pcie_adv_error_regs_t)); 1045*00d0963fSdilpreet } 1046*00d0963fSdilpreet 1047*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 1048*00d0963fSdilpreet kmem_free(pcie_regs->pcie_rc_regs, 1049*00d0963fSdilpreet sizeof (pcie_rc_error_regs_t)); 1050*00d0963fSdilpreet 1051*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 1052*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIX_DEV) { 1053*00d0963fSdilpreet uint16_t pcix_ver = pcie_regs->pcix_bdg_regs-> 1054*00d0963fSdilpreet pcix_bdg_ver; 1055*00d0963fSdilpreet 1056*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 1057*00d0963fSdilpreet int i; 1058*00d0963fSdilpreet for (i = 0; i < 2; i++) 1059*00d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs-> 1060*00d0963fSdilpreet pcix_bdg_ecc_regs[i], 1061*00d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 1062*00d0963fSdilpreet } 1063*00d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs, 1064*00d0963fSdilpreet sizeof (pcix_bdg_error_regs_t)); 1065*00d0963fSdilpreet } 1066*00d0963fSdilpreet } 1067*00d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcie_error_regs_t)); 1068*00d0963fSdilpreet } 1069*00d0963fSdilpreet 1070*00d0963fSdilpreet void 1071*00d0963fSdilpreet pci_ereport_teardown(dev_info_t *dip) 1072*00d0963fSdilpreet { 1073*00d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 1074*00d0963fSdilpreet pci_erpt_t *erpt_p; 1075*00d0963fSdilpreet 1076*00d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 1077*00d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 1078*00d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 1079*00d0963fSdilpreet } 1080*00d0963fSdilpreet 1081*00d0963fSdilpreet ASSERT(fmhdl); 1082*00d0963fSdilpreet 1083*00d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 1084*00d0963fSdilpreet if (erpt_p == NULL) 1085*00d0963fSdilpreet return; 1086*00d0963fSdilpreet 1087*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 1088*00d0963fSdilpreet pcie_ereport_teardown(erpt_p); 1089*00d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 1090*00d0963fSdilpreet pcix_ereport_teardown(erpt_p); 1091*00d0963fSdilpreet pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl); 1092*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) 1093*00d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs, 1094*00d0963fSdilpreet sizeof (pci_bdg_error_regs_t)); 1095*00d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 1096*00d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 1097*00d0963fSdilpreet fmhdl->fh_bus_specific = NULL; 1098*00d0963fSdilpreet /* 1099*00d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 1100*00d0963fSdilpreet * interfaces create the necessary properties for us. 1101*00d0963fSdilpreet */ 1102*00d0963fSdilpreet #if defined(__sparc) 1103*00d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcix-capid-pointer"); 1104*00d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-slotcap-reg"); 1105*00d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-reg"); 1106*00d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-pointer"); 1107*00d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-aer-pointer"); 1108*00d0963fSdilpreet #endif 1109*00d0963fSdilpreet } 1110*00d0963fSdilpreet 1111*00d0963fSdilpreet /* 1112*00d0963fSdilpreet * Function used by PCI device and nexus error handlers to check if a 1113*00d0963fSdilpreet * captured address resides in their DMA or ACC handle caches or the caches of 1114*00d0963fSdilpreet * their children devices, respectively. 1115*00d0963fSdilpreet */ 1116*00d0963fSdilpreet static int 1117*00d0963fSdilpreet pci_dev_hdl_lookup(dev_info_t *dip, int type, ddi_fm_error_t *derr, 1118*00d0963fSdilpreet void *addr) 1119*00d0963fSdilpreet { 1120*00d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 1121*00d0963fSdilpreet pci_erpt_t *erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 1122*00d0963fSdilpreet 1123*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) 1124*00d0963fSdilpreet return (ndi_fmc_error(dip, NULL, type, derr->fme_ena, addr)); 1125*00d0963fSdilpreet else 1126*00d0963fSdilpreet return (ndi_fmc_entry_error(dip, type, derr, addr)); 1127*00d0963fSdilpreet } 1128*00d0963fSdilpreet 1129*00d0963fSdilpreet static void 1130*00d0963fSdilpreet pcie_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 1131*00d0963fSdilpreet char *buf, int errtype) 1132*00d0963fSdilpreet { 1133*00d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 1134*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 1135*00d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_adv_rc_regs = 1136*00d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 1137*00d0963fSdilpreet 1138*00d0963fSdilpreet switch (errtype) { 1139*00d0963fSdilpreet case PCIEX_TYPE_CE: 1140*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1141*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1142*00d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 1143*00d0963fSdilpreet pcie_regs->pcie_err_status, 1144*00d0963fSdilpreet PCIEX_CE_STATUS_REG, DATA_TYPE_UINT32, 1145*00d0963fSdilpreet pcie_adv_regs->pcie_ce_status, NULL); 1146*00d0963fSdilpreet break; 1147*00d0963fSdilpreet case PCIEX_TYPE_UE: 1148*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1149*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1150*00d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 1151*00d0963fSdilpreet pcie_regs->pcie_err_status, 1152*00d0963fSdilpreet PCIEX_UE_STATUS_REG, DATA_TYPE_UINT32, 1153*00d0963fSdilpreet pcie_adv_regs->pcie_ue_status, PCIEX_UE_SEV_REG, 1154*00d0963fSdilpreet DATA_TYPE_UINT32, pcie_adv_regs->pcie_ue_sev, 1155*00d0963fSdilpreet PCIEX_ADV_CTL, DATA_TYPE_UINT32, 1156*00d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl, 1157*00d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 1158*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 1159*00d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 1160*00d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 1161*00d0963fSdilpreet 1 : NULL, 1162*00d0963fSdilpreet #ifdef DEBUG 1163*00d0963fSdilpreet PCIEX_UE_HDR0, DATA_TYPE_UINT32, 1164*00d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0, 1165*00d0963fSdilpreet PCIEX_UE_HDR1, DATA_TYPE_UINT32, 1166*00d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[0], 1167*00d0963fSdilpreet PCIEX_UE_HDR2, DATA_TYPE_UINT32, 1168*00d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[1], 1169*00d0963fSdilpreet PCIEX_UE_HDR3, DATA_TYPE_UINT32, 1170*00d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[2], 1171*00d0963fSdilpreet #endif 1172*00d0963fSdilpreet NULL); 1173*00d0963fSdilpreet break; 1174*00d0963fSdilpreet case PCIEX_TYPE_GEN: 1175*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1176*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 1177*00d0963fSdilpreet 0, PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 1178*00d0963fSdilpreet pcie_regs->pcie_err_status, NULL); 1179*00d0963fSdilpreet break; 1180*00d0963fSdilpreet case PCIEX_TYPE_RC_UE_MSG: 1181*00d0963fSdilpreet case PCIEX_TYPE_RC_CE_MSG: 1182*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1183*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1184*00d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 1185*00d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, 1186*00d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 1187*00d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 1188*00d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id : 1189*00d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id, 1190*00d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 1191*00d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 1192*00d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 1193*00d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id != 0) : 1194*00d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 1195*00d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id != 0), NULL); 1196*00d0963fSdilpreet break; 1197*00d0963fSdilpreet case PCIEX_TYPE_RC_MULT_MSG: 1198*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1199*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1200*00d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 1201*00d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, NULL); 1202*00d0963fSdilpreet break; 1203*00d0963fSdilpreet default: 1204*00d0963fSdilpreet break; 1205*00d0963fSdilpreet } 1206*00d0963fSdilpreet } 1207*00d0963fSdilpreet 1208*00d0963fSdilpreet static void 1209*00d0963fSdilpreet pcie_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *eprt_p) 1210*00d0963fSdilpreet { 1211*00d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)eprt_p->pe_regs; 1212*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 1213*00d0963fSdilpreet pcie_tlp_hdr_t *ue_hdr0; 1214*00d0963fSdilpreet uint32_t *ue_hdr; 1215*00d0963fSdilpreet uint64_t addr = NULL; 1216*00d0963fSdilpreet 1217*00d0963fSdilpreet if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_UE_HDR_VALID)) { 1218*00d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 1219*00d0963fSdilpreet return; 1220*00d0963fSdilpreet } 1221*00d0963fSdilpreet ue_hdr0 = (pcie_tlp_hdr_t *)&pcie_adv_regs->pcie_ue_hdr0; 1222*00d0963fSdilpreet ue_hdr = pcie_adv_regs->pcie_ue_hdr; 1223*00d0963fSdilpreet 1224*00d0963fSdilpreet switch (ue_hdr0->type) { 1225*00d0963fSdilpreet case PCIE_TLP_TYPE_MEM: 1226*00d0963fSdilpreet case PCIE_TLP_TYPE_MEMLK: 1227*00d0963fSdilpreet if ((ue_hdr0->fmt & 0x1) == 0x1) { 1228*00d0963fSdilpreet pcie_mem64_t *mem64_tlp = (pcie_mem64_t *)ue_hdr; 1229*00d0963fSdilpreet 1230*00d0963fSdilpreet addr = (uint64_t)mem64_tlp->addr1 << 32 | 1231*00d0963fSdilpreet (uint32_t)mem64_tlp->addr0 << 2; 1232*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = mem64_tlp->rid; 1233*00d0963fSdilpreet } else { 1234*00d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 1235*00d0963fSdilpreet 1236*00d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 1237*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 1238*00d0963fSdilpreet } 1239*00d0963fSdilpreet 1240*00d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, DMA_HANDLE, derr, 1241*00d0963fSdilpreet (void *) &addr); 1242*00d0963fSdilpreet /* 1243*00d0963fSdilpreet * If DMA handle is not found error could have been a memory 1244*00d0963fSdilpreet * mapped IO address so check in the access cache 1245*00d0963fSdilpreet */ 1246*00d0963fSdilpreet if (derr->fme_status == DDI_FM_UNKNOWN) 1247*00d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE, 1248*00d0963fSdilpreet derr, (void *) &addr); 1249*00d0963fSdilpreet break; 1250*00d0963fSdilpreet 1251*00d0963fSdilpreet case PCIE_TLP_TYPE_IO: 1252*00d0963fSdilpreet { 1253*00d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 1254*00d0963fSdilpreet 1255*00d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 1256*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 1257*00d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE, 1258*00d0963fSdilpreet derr, (void *) &addr); 1259*00d0963fSdilpreet break; 1260*00d0963fSdilpreet } 1261*00d0963fSdilpreet case PCIE_TLP_TYPE_CFG0: 1262*00d0963fSdilpreet case PCIE_TLP_TYPE_CFG1: 1263*00d0963fSdilpreet { 1264*00d0963fSdilpreet pcie_cfg_t *cfg_tlp = (pcie_cfg_t *)ue_hdr; 1265*00d0963fSdilpreet 1266*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 1267*00d0963fSdilpreet (uint16_t)cfg_tlp->bus << 8 | 1268*00d0963fSdilpreet (uint16_t)cfg_tlp->dev << 3 | cfg_tlp->func; 1269*00d0963fSdilpreet 1270*00d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 1271*00d0963fSdilpreet break; 1272*00d0963fSdilpreet } 1273*00d0963fSdilpreet case PCIE_TLP_TYPE_MSG: 1274*00d0963fSdilpreet { 1275*00d0963fSdilpreet pcie_msg_t *msg_tlp = (pcie_msg_t *)ue_hdr; 1276*00d0963fSdilpreet 1277*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = msg_tlp->rid; 1278*00d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 1279*00d0963fSdilpreet break; 1280*00d0963fSdilpreet } 1281*00d0963fSdilpreet case PCIE_TLP_TYPE_CPL: 1282*00d0963fSdilpreet case PCIE_TLP_TYPE_CPLLK: 1283*00d0963fSdilpreet { 1284*00d0963fSdilpreet pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)ue_hdr; 1285*00d0963fSdilpreet 1286*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = cpl_tlp->cid; 1287*00d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 1288*00d0963fSdilpreet break; 1289*00d0963fSdilpreet } 1290*00d0963fSdilpreet case PCIE_TLP_TYPE_MSI: 1291*00d0963fSdilpreet default: 1292*00d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 1293*00d0963fSdilpreet } 1294*00d0963fSdilpreet 1295*00d0963fSdilpreet /* 1296*00d0963fSdilpreet * If no handle was found in the children caches and their is no 1297*00d0963fSdilpreet * address infomation already stored and we have a captured address 1298*00d0963fSdilpreet * then we need to store it away so that intermediate bridges can 1299*00d0963fSdilpreet * check if the address exists in their handle caches. 1300*00d0963fSdilpreet */ 1301*00d0963fSdilpreet if (derr->fme_status == DDI_FM_UNKNOWN && 1302*00d0963fSdilpreet derr->fme_bus_specific == NULL && 1303*00d0963fSdilpreet addr != NULL) 1304*00d0963fSdilpreet derr->fme_bus_specific = (void *)(uintptr_t)addr; 1305*00d0963fSdilpreet } 1306*00d0963fSdilpreet 1307*00d0963fSdilpreet static void 1308*00d0963fSdilpreet pcie_pci_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *eprt_p) 1309*00d0963fSdilpreet { 1310*00d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)eprt_p->pe_regs; 1311*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 1312*00d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 1313*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 1314*00d0963fSdilpreet uint64_t addr = NULL; 1315*00d0963fSdilpreet pcix_attr_t *pcie_pci_sue_attr; 1316*00d0963fSdilpreet int cmd; 1317*00d0963fSdilpreet int dual_addr = 0; 1318*00d0963fSdilpreet 1319*00d0963fSdilpreet if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_HDR_VALID)) { 1320*00d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 1321*00d0963fSdilpreet return; 1322*00d0963fSdilpreet } 1323*00d0963fSdilpreet 1324*00d0963fSdilpreet pcie_pci_sue_attr = (pcix_attr_t *)&pcie_bdg_regs->pcie_sue_hdr0; 1325*00d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 1326*00d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK; 1327*00d0963fSdilpreet cmd_switch: 1328*00d0963fSdilpreet switch (cmd) { 1329*00d0963fSdilpreet case PCI_PCIX_CMD_IORD: 1330*00d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 1331*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 1332*00d0963fSdilpreet 1333*00d0963fSdilpreet addr = pcie_bdg_regs->pcie_sue_hdr[2]; 1334*00d0963fSdilpreet addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) | 1335*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1]; 1336*00d0963fSdilpreet 1337*00d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE, 1338*00d0963fSdilpreet derr, (void *) &addr); 1339*00d0963fSdilpreet break; 1340*00d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 1341*00d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 1342*00d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 1343*00d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 1344*00d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 1345*00d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 1346*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 1347*00d0963fSdilpreet 1348*00d0963fSdilpreet addr = pcie_bdg_regs->pcie_sue_hdr[2]; 1349*00d0963fSdilpreet addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) | 1350*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1]; 1351*00d0963fSdilpreet 1352*00d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, DMA_HANDLE, 1353*00d0963fSdilpreet derr, (void *) &addr); 1354*00d0963fSdilpreet if (derr->fme_status == DDI_FM_UNKNOWN) 1355*00d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE, 1356*00d0963fSdilpreet derr, (void *) &addr); 1357*00d0963fSdilpreet break; 1358*00d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 1359*00d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 1360*00d0963fSdilpreet /* 1361*00d0963fSdilpreet * If we want to store the bdf of the device being addressed we 1362*00d0963fSdilpreet * will need to do some surgery 1363*00d0963fSdilpreet */ 1364*00d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 1365*00d0963fSdilpreet break; 1366*00d0963fSdilpreet case PCI_PCIX_CMD_DADR: 1367*00d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 1368*00d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) & 1369*00d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_MASK; 1370*00d0963fSdilpreet if (dual_addr) 1371*00d0963fSdilpreet break; 1372*00d0963fSdilpreet ++dual_addr; 1373*00d0963fSdilpreet goto cmd_switch; 1374*00d0963fSdilpreet default: 1375*00d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 1376*00d0963fSdilpreet } 1377*00d0963fSdilpreet 1378*00d0963fSdilpreet /* 1379*00d0963fSdilpreet * If no handle was found in the children caches and their is no 1380*00d0963fSdilpreet * address infomation already stored and we have a captured address 1381*00d0963fSdilpreet * then we need to store it away so that intermediate bridges can 1382*00d0963fSdilpreet * check if the address exists in their handle caches. 1383*00d0963fSdilpreet */ 1384*00d0963fSdilpreet if (derr->fme_status == DDI_FM_UNKNOWN && 1385*00d0963fSdilpreet derr->fme_bus_specific == NULL && 1386*00d0963fSdilpreet addr != NULL) 1387*00d0963fSdilpreet derr->fme_bus_specific = (void *)(uintptr_t)addr; 1388*00d0963fSdilpreet } 1389*00d0963fSdilpreet 1390*00d0963fSdilpreet static int 1391*00d0963fSdilpreet pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, 1392*00d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs) 1393*00d0963fSdilpreet { 1394*00d0963fSdilpreet int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf; 1395*00d0963fSdilpreet uint64_t addr; 1396*00d0963fSdilpreet 1397*00d0963fSdilpreet addr = pcix_ecc_regs->pcix_ecc_secaddr; 1398*00d0963fSdilpreet addr = addr << 32; 1399*00d0963fSdilpreet addr |= pcix_ecc_regs->pcix_ecc_fstaddr; 1400*00d0963fSdilpreet 1401*00d0963fSdilpreet switch (cmd) { 1402*00d0963fSdilpreet case PCI_PCIX_CMD_INTR: 1403*00d0963fSdilpreet case PCI_PCIX_CMD_SPEC: 1404*00d0963fSdilpreet return (DDI_FM_FATAL); 1405*00d0963fSdilpreet case PCI_PCIX_CMD_IORD: 1406*00d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 1407*00d0963fSdilpreet return (pci_dev_hdl_lookup(dip, ACC_HANDLE, derr, 1408*00d0963fSdilpreet (void *) &addr)); 1409*00d0963fSdilpreet case PCI_PCIX_CMD_DEVID: 1410*00d0963fSdilpreet return (DDI_FM_FATAL); 1411*00d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 1412*00d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 1413*00d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 1414*00d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 1415*00d0963fSdilpreet return (pci_dev_hdl_lookup(dip, DMA_HANDLE, derr, 1416*00d0963fSdilpreet (void *) &addr)); 1417*00d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 1418*00d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 1419*00d0963fSdilpreet return (pci_dev_hdl_lookup(dip, ACC_HANDLE, derr, 1420*00d0963fSdilpreet (void *) &addr)); 1421*00d0963fSdilpreet case PCI_PCIX_CMD_SPL: 1422*00d0963fSdilpreet case PCI_PCIX_CMD_DADR: 1423*00d0963fSdilpreet return (DDI_FM_FATAL); 1424*00d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 1425*00d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 1426*00d0963fSdilpreet return (pci_dev_hdl_lookup(dip, DMA_HANDLE, derr, 1427*00d0963fSdilpreet (void *) &addr)); 1428*00d0963fSdilpreet default: 1429*00d0963fSdilpreet return (DDI_FM_FATAL); 1430*00d0963fSdilpreet } 1431*00d0963fSdilpreet } 1432*00d0963fSdilpreet 1433*00d0963fSdilpreet /*ARGSUSED*/ 1434*00d0963fSdilpreet static int 1435*00d0963fSdilpreet pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 1436*00d0963fSdilpreet { 1437*00d0963fSdilpreet pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs; 1438*00d0963fSdilpreet int fatal = 0; 1439*00d0963fSdilpreet int nonfatal = 0; 1440*00d0963fSdilpreet int unknown = 0; 1441*00d0963fSdilpreet int ok = 0; 1442*00d0963fSdilpreet int ret = DDI_FM_OK; 1443*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 1444*00d0963fSdilpreet int i; 1445*00d0963fSdilpreet 1446*00d0963fSdilpreet if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) 1447*00d0963fSdilpreet goto done; 1448*00d0963fSdilpreet 1449*00d0963fSdilpreet if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) && 1450*00d0963fSdilpreet (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) { 1451*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 1452*00d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_DTO); 1453*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1454*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1455*00d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 1456*00d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 1457*00d0963fSdilpreet DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL); 1458*00d0963fSdilpreet unknown++; 1459*00d0963fSdilpreet } 1460*00d0963fSdilpreet 1461*00d0963fSdilpreet if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) { 1462*00d0963fSdilpreet for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) { 1463*00d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & 1464*00d0963fSdilpreet pci_bdg_err_tbl[i].reg_bit) { 1465*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 1466*00d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, 1467*00d0963fSdilpreet pci_bdg_err_tbl[i].err_class); 1468*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1469*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1470*00d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 1471*00d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 1472*00d0963fSdilpreet DATA_TYPE_UINT16, 1473*00d0963fSdilpreet pci_bdg_regs->pci_bdg_ctrl, NULL); 1474*00d0963fSdilpreet /* 1475*00d0963fSdilpreet * Increment severity based on flag if bridge 1476*00d0963fSdilpreet * is PCI or PCI-X, if PCI Express and this is a 1477*00d0963fSdilpreet * master abort then treat as nonfatal. 1478*00d0963fSdilpreet * XXFM May need to check if all other errors 1479*00d0963fSdilpreet * are related to MA? 1480*00d0963fSdilpreet */ 1481*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) { 1482*00d0963fSdilpreet PCI_FM_SEV_INC( 1483*00d0963fSdilpreet pci_bdg_err_tbl[i].flags); 1484*00d0963fSdilpreet } else if (pci_bdg_err_tbl[i].reg_bit == 1485*00d0963fSdilpreet PCI_STAT_R_MAST_AB) { 1486*00d0963fSdilpreet nonfatal++; 1487*00d0963fSdilpreet } 1488*00d0963fSdilpreet 1489*00d0963fSdilpreet if (derr->fme_bus_specific && 1490*00d0963fSdilpreet pci_bdg_err_tbl[i].terr_class) 1491*00d0963fSdilpreet pci_target_enqueue(derr->fme_ena, 1492*00d0963fSdilpreet pci_bdg_err_tbl[i].terr_class, 1493*00d0963fSdilpreet PCI_ERROR_SUBCLASS, 1494*00d0963fSdilpreet (uintptr_t)derr->fme_bus_specific); 1495*00d0963fSdilpreet } 1496*00d0963fSdilpreet } 1497*00d0963fSdilpreet } 1498*00d0963fSdilpreet 1499*00d0963fSdilpreet done: 1500*00d0963fSdilpreet 1501*00d0963fSdilpreet /* 1502*00d0963fSdilpreet * Need to check for poke and cautious put. We already know peek 1503*00d0963fSdilpreet * and cautious get errors occurred (as we got a trap) and we know 1504*00d0963fSdilpreet * they are nonfatal. 1505*00d0963fSdilpreet */ 1506*00d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_EXPECTED) { 1507*00d0963fSdilpreet /* 1508*00d0963fSdilpreet * for cautious puts we treat all errors as nonfatal. Actually 1509*00d0963fSdilpreet * we set nonfatal for cautious gets as well - doesn't do any 1510*00d0963fSdilpreet * harm 1511*00d0963fSdilpreet */ 1512*00d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 1513*00d0963fSdilpreet PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR)) 1514*00d0963fSdilpreet nonfatal++; 1515*00d0963fSdilpreet 1516*00d0963fSdilpreet /* 1517*00d0963fSdilpreet * for cautious accesses we already have the acc_handle. Just 1518*00d0963fSdilpreet * need to call children to clear their error bits 1519*00d0963fSdilpreet */ 1520*00d0963fSdilpreet ret = ndi_fm_handler_dispatch(dip, NULL, derr); 1521*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 1522*00d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 1523*00d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 1524*00d0963fSdilpreet } 1525*00d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_POKE) { 1526*00d0963fSdilpreet /* 1527*00d0963fSdilpreet * special case for pokes - we only consider master abort 1528*00d0963fSdilpreet * and target abort as nonfatal. Sserr with no master abort is 1529*00d0963fSdilpreet * fatal, but master/target abort can come in on separate 1530*00d0963fSdilpreet * instance, so return unknown and parent will determine if 1531*00d0963fSdilpreet * nonfatal (if another child returned nonfatal - ie master 1532*00d0963fSdilpreet * or target abort) or fatal otherwise 1533*00d0963fSdilpreet */ 1534*00d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 1535*00d0963fSdilpreet PCI_STAT_R_MAST_AB)) 1536*00d0963fSdilpreet nonfatal++; 1537*00d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR) 1538*00d0963fSdilpreet unknown++; 1539*00d0963fSdilpreet } 1540*00d0963fSdilpreet 1541*00d0963fSdilpreet /* 1542*00d0963fSdilpreet * If errant address is passed in then attempt to find 1543*00d0963fSdilpreet * ACC/DMA handle in caches. 1544*00d0963fSdilpreet */ 1545*00d0963fSdilpreet if (derr->fme_bus_specific) { 1546*00d0963fSdilpreet int i; 1547*00d0963fSdilpreet 1548*00d0963fSdilpreet for (i = 0; i < 2; i++) { 1549*00d0963fSdilpreet ret = ndi_fmc_error(dip, NULL, i ? ACC_HANDLE : 1550*00d0963fSdilpreet DMA_HANDLE, derr->fme_ena, 1551*00d0963fSdilpreet (void *)&derr->fme_bus_specific); 1552*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 1553*00d0963fSdilpreet } 1554*00d0963fSdilpreet } 1555*00d0963fSdilpreet 1556*00d0963fSdilpreet /* 1557*00d0963fSdilpreet * now check children below the bridge, only if errant handle was not 1558*00d0963fSdilpreet * found 1559*00d0963fSdilpreet */ 1560*00d0963fSdilpreet if (!derr->fme_acc_handle && !derr->fme_dma_handle) { 1561*00d0963fSdilpreet ret = ndi_fm_handler_dispatch(dip, NULL, derr); 1562*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 1563*00d0963fSdilpreet } 1564*00d0963fSdilpreet 1565*00d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 1566*00d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 1567*00d0963fSdilpreet } 1568*00d0963fSdilpreet 1569*00d0963fSdilpreet static int 1570*00d0963fSdilpreet pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 1571*00d0963fSdilpreet void *pe_regs) 1572*00d0963fSdilpreet { 1573*00d0963fSdilpreet pcix_error_regs_t *pcix_regs; 1574*00d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 1575*00d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs; 1576*00d0963fSdilpreet int bridge; 1577*00d0963fSdilpreet int i; 1578*00d0963fSdilpreet int ecc_phase; 1579*00d0963fSdilpreet int ecc_corr; 1580*00d0963fSdilpreet int sec_ue; 1581*00d0963fSdilpreet int sec_ce; 1582*00d0963fSdilpreet int fatal = 0; 1583*00d0963fSdilpreet int nonfatal = 0; 1584*00d0963fSdilpreet int unknown = 0; 1585*00d0963fSdilpreet int ok = 0; 1586*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 1587*00d0963fSdilpreet 1588*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 1589*00d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 1590*00d0963fSdilpreet bridge = 1; 1591*00d0963fSdilpreet } else { 1592*00d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)pe_regs; 1593*00d0963fSdilpreet bridge = 0; 1594*00d0963fSdilpreet } 1595*00d0963fSdilpreet 1596*00d0963fSdilpreet for (i = 0; i < (bridge ? 2 : 1); i++) { 1597*00d0963fSdilpreet int ret = DDI_FM_OK; 1598*00d0963fSdilpreet pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] : 1599*00d0963fSdilpreet pcix_regs->pcix_ecc_regs; 1600*00d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) { 1601*00d0963fSdilpreet ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat & 1602*00d0963fSdilpreet PCI_PCIX_ECC_PHASE) >> 0x4; 1603*00d0963fSdilpreet ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat & 1604*00d0963fSdilpreet PCI_PCIX_ECC_CORR); 1605*00d0963fSdilpreet sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat & 1606*00d0963fSdilpreet PCI_PCIX_ECC_S_UE); 1607*00d0963fSdilpreet sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat & 1608*00d0963fSdilpreet PCI_PCIX_ECC_S_CE); 1609*00d0963fSdilpreet 1610*00d0963fSdilpreet switch (ecc_phase) { 1611*00d0963fSdilpreet case PCI_PCIX_ECC_PHASE_NOERR: 1612*00d0963fSdilpreet break; 1613*00d0963fSdilpreet case PCI_PCIX_ECC_PHASE_FADDR: 1614*00d0963fSdilpreet case PCI_PCIX_ECC_PHASE_SADDR: 1615*00d0963fSdilpreet PCI_FM_SEV_INC(ecc_corr ? DDI_FM_NONFATAL : 1616*00d0963fSdilpreet DDI_FM_FATAL); 1617*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1618*00d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 1619*00d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 1620*00d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ADDR : 1621*00d0963fSdilpreet PCIX_ECC_UE_ADDR); 1622*00d0963fSdilpreet break; 1623*00d0963fSdilpreet case PCI_PCIX_ECC_PHASE_ATTR: 1624*00d0963fSdilpreet PCI_FM_SEV_INC(ecc_corr ? 1625*00d0963fSdilpreet DDI_FM_NONFATAL : DDI_FM_FATAL); 1626*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1627*00d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 1628*00d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 1629*00d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ATTR : 1630*00d0963fSdilpreet PCIX_ECC_UE_ATTR); 1631*00d0963fSdilpreet break; 1632*00d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA32: 1633*00d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA64: 1634*00d0963fSdilpreet if (ecc_corr) 1635*00d0963fSdilpreet ret = DDI_FM_NONFATAL; 1636*00d0963fSdilpreet else 1637*00d0963fSdilpreet ret = pcix_check_addr(dip, derr, 1638*00d0963fSdilpreet pcix_ecc_regs); 1639*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 1640*00d0963fSdilpreet 1641*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1642*00d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 1643*00d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 1644*00d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_DATA : 1645*00d0963fSdilpreet PCIX_ECC_UE_DATA); 1646*00d0963fSdilpreet break; 1647*00d0963fSdilpreet } 1648*00d0963fSdilpreet if (ecc_phase) 1649*00d0963fSdilpreet if (bridge) 1650*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 1651*00d0963fSdilpreet derr->fme_ena, 1652*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 1653*00d0963fSdilpreet DATA_TYPE_UINT8, 0, 1654*00d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 1655*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 1656*00d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 1657*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 1658*00d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 1659*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 1660*00d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 1661*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 1662*00d0963fSdilpreet else 1663*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 1664*00d0963fSdilpreet derr->fme_ena, 1665*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 1666*00d0963fSdilpreet DATA_TYPE_UINT8, 0, 1667*00d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 1668*00d0963fSdilpreet pcix_regs->pcix_command, 1669*00d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 1670*00d0963fSdilpreet pcix_regs->pcix_status, 1671*00d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 1672*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 1673*00d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 1674*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 1675*00d0963fSdilpreet if (sec_ce || sec_ue) { 1676*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1677*00d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 1678*00d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 1679*00d0963fSdilpreet sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE); 1680*00d0963fSdilpreet if (bridge) 1681*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 1682*00d0963fSdilpreet derr->fme_ena, 1683*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 1684*00d0963fSdilpreet DATA_TYPE_UINT8, 0, 1685*00d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 1686*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 1687*00d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 1688*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 1689*00d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 1690*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 1691*00d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 1692*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 1693*00d0963fSdilpreet else 1694*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 1695*00d0963fSdilpreet derr->fme_ena, 1696*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 1697*00d0963fSdilpreet DATA_TYPE_UINT8, 0, 1698*00d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 1699*00d0963fSdilpreet pcix_regs->pcix_command, 1700*00d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 1701*00d0963fSdilpreet pcix_regs->pcix_status, 1702*00d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 1703*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 1704*00d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 1705*00d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 1706*00d0963fSdilpreet PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL : 1707*00d0963fSdilpreet DDI_FM_NONFATAL); 1708*00d0963fSdilpreet } 1709*00d0963fSdilpreet } 1710*00d0963fSdilpreet } 1711*00d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 1712*00d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 1713*00d0963fSdilpreet } 1714*00d0963fSdilpreet 1715*00d0963fSdilpreet static int 1716*00d0963fSdilpreet pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 1717*00d0963fSdilpreet void *pe_regs) 1718*00d0963fSdilpreet { 1719*00d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 1720*00d0963fSdilpreet int fatal = 0; 1721*00d0963fSdilpreet int nonfatal = 0; 1722*00d0963fSdilpreet int unknown = 0; 1723*00d0963fSdilpreet int ok = 0; 1724*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 1725*00d0963fSdilpreet int i; 1726*00d0963fSdilpreet 1727*00d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) { 1728*00d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 1729*00d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_stat & 1730*00d0963fSdilpreet pcix_err_tbl[i].reg_bit)) { 1731*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 1732*00d0963fSdilpreet PCIX_ERROR_SUBCLASS, 1733*00d0963fSdilpreet pcix_err_tbl[i].err_class); 1734*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1735*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1736*00d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 1737*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 1738*00d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 1739*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 1740*00d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 1741*00d0963fSdilpreet } 1742*00d0963fSdilpreet } 1743*00d0963fSdilpreet } 1744*00d0963fSdilpreet 1745*00d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) { 1746*00d0963fSdilpreet for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) { 1747*00d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_sec_stat & 1748*00d0963fSdilpreet pcix_sec_err_tbl[i].reg_bit)) { 1749*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s", 1750*00d0963fSdilpreet PCIX_ERROR_SUBCLASS, 1751*00d0963fSdilpreet PCIX_SEC_ERROR_SUBCLASS, 1752*00d0963fSdilpreet pcix_sec_err_tbl[i].err_class); 1753*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1754*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1755*00d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 1756*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 1757*00d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 1758*00d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 1759*00d0963fSdilpreet PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags); 1760*00d0963fSdilpreet } 1761*00d0963fSdilpreet } 1762*00d0963fSdilpreet } 1763*00d0963fSdilpreet 1764*00d0963fSdilpreet /* Log/Handle ECC errors */ 1765*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 1766*00d0963fSdilpreet int ret; 1767*00d0963fSdilpreet 1768*00d0963fSdilpreet ret = pcix_ecc_error_report(dip, derr, erpt_p, 1769*00d0963fSdilpreet (void *)pcix_bdg_regs); 1770*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 1771*00d0963fSdilpreet } 1772*00d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 1773*00d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 1774*00d0963fSdilpreet } 1775*00d0963fSdilpreet 1776*00d0963fSdilpreet static int 1777*00d0963fSdilpreet pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 1778*00d0963fSdilpreet { 1779*00d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 1780*00d0963fSdilpreet int fatal = 0; 1781*00d0963fSdilpreet int nonfatal = 0; 1782*00d0963fSdilpreet int unknown = 0; 1783*00d0963fSdilpreet int ok = 0; 1784*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 1785*00d0963fSdilpreet int i; 1786*00d0963fSdilpreet 1787*00d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) { 1788*00d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 1789*00d0963fSdilpreet if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit)) 1790*00d0963fSdilpreet continue; 1791*00d0963fSdilpreet 1792*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 1793*00d0963fSdilpreet PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class); 1794*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1795*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1796*00d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 1797*00d0963fSdilpreet pcix_regs->pcix_command, PCIX_STATUS, 1798*00d0963fSdilpreet DATA_TYPE_UINT32, pcix_regs->pcix_status, 1799*00d0963fSdilpreet NULL); 1800*00d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 1801*00d0963fSdilpreet } 1802*00d0963fSdilpreet } 1803*00d0963fSdilpreet /* Log/Handle ECC errors */ 1804*00d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 1805*00d0963fSdilpreet int ret = pcix_ecc_error_report(dip, derr, erpt_p, 1806*00d0963fSdilpreet (void *)pcix_regs); 1807*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 1808*00d0963fSdilpreet } 1809*00d0963fSdilpreet 1810*00d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 1811*00d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 1812*00d0963fSdilpreet } 1813*00d0963fSdilpreet 1814*00d0963fSdilpreet static int 1815*00d0963fSdilpreet pcie_rc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 1816*00d0963fSdilpreet void *pe_regs) 1817*00d0963fSdilpreet { 1818*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = (pcie_adv_error_regs_t *)pe_regs; 1819*00d0963fSdilpreet int fatal = 0; 1820*00d0963fSdilpreet int nonfatal = 0; 1821*00d0963fSdilpreet int unknown = 0; 1822*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 1823*00d0963fSdilpreet 1824*00d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) { 1825*00d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 1826*00d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 1827*00d0963fSdilpreet int ce, ue, mult_ce, mult_ue, first_ue_fatal, nfe, fe; 1828*00d0963fSdilpreet 1829*00d0963fSdilpreet ce = pcie_rc_regs->pcie_rc_err_status & 1830*00d0963fSdilpreet PCIE_AER_RE_STS_CE_RCVD; 1831*00d0963fSdilpreet ue = pcie_rc_regs->pcie_rc_err_status & 1832*00d0963fSdilpreet PCIE_AER_RE_STS_FE_NFE_RCVD; 1833*00d0963fSdilpreet mult_ce = pcie_rc_regs->pcie_rc_err_status & 1834*00d0963fSdilpreet PCIE_AER_RE_STS_MUL_CE_RCVD; 1835*00d0963fSdilpreet mult_ue = pcie_rc_regs->pcie_rc_err_status & 1836*00d0963fSdilpreet PCIE_AER_RE_STS_MUL_FE_NFE_RCVD; 1837*00d0963fSdilpreet first_ue_fatal = pcie_rc_regs->pcie_rc_err_status & 1838*00d0963fSdilpreet PCIE_AER_RE_STS_FIRST_UC_FATAL; 1839*00d0963fSdilpreet nfe = pcie_rc_regs->pcie_rc_err_status & 1840*00d0963fSdilpreet PCIE_AER_RE_STS_NFE_MSGS_RCVD; 1841*00d0963fSdilpreet fe = pcie_rc_regs->pcie_rc_err_status & 1842*00d0963fSdilpreet PCIE_AER_RE_STS_FE_MSGS_RCVD; 1843*00d0963fSdilpreet /* 1844*00d0963fSdilpreet * log fatal/nonfatal/corrected messages 1845*00d0963fSdilpreet * recieved by root complex 1846*00d0963fSdilpreet */ 1847*00d0963fSdilpreet if (ue && fe) 1848*00d0963fSdilpreet fatal++; 1849*00d0963fSdilpreet else if (ce && !ue) 1850*00d0963fSdilpreet nonfatal++; 1851*00d0963fSdilpreet 1852*00d0963fSdilpreet if (fe && first_ue_fatal) { 1853*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1854*00d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_FE_MSG); 1855*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1856*00d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 1857*00d0963fSdilpreet } 1858*00d0963fSdilpreet if (nfe && !first_ue_fatal) { 1859*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1860*00d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_NFE_MSG); 1861*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1862*00d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 1863*00d0963fSdilpreet } 1864*00d0963fSdilpreet if (ce) { 1865*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1866*00d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_CE_MSG); 1867*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1868*00d0963fSdilpreet PCIEX_TYPE_RC_CE_MSG); 1869*00d0963fSdilpreet } 1870*00d0963fSdilpreet if (mult_ce) { 1871*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1872*00d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MCE_MSG); 1873*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1874*00d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 1875*00d0963fSdilpreet } 1876*00d0963fSdilpreet if (mult_ue) { 1877*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1878*00d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MUE_MSG); 1879*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1880*00d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 1881*00d0963fSdilpreet } 1882*00d0963fSdilpreet } 1883*00d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 1884*00d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 1885*00d0963fSdilpreet } 1886*00d0963fSdilpreet 1887*00d0963fSdilpreet static int 1888*00d0963fSdilpreet pcie_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 1889*00d0963fSdilpreet { 1890*00d0963fSdilpreet int fatal = 0; 1891*00d0963fSdilpreet int nonfatal = 0; 1892*00d0963fSdilpreet int unknown = 0; 1893*00d0963fSdilpreet int ok = 0; 1894*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 1895*00d0963fSdilpreet int i; 1896*00d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 1897*00d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 1898*00d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs; 1899*00d0963fSdilpreet 1900*00d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 1901*00d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 1902*00d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, erpt_p, 1903*00d0963fSdilpreet (void *)pcie_regs->pcix_bdg_regs); 1904*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 1905*00d0963fSdilpreet } 1906*00d0963fSdilpreet 1907*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 1908*00d0963fSdilpreet if (!(pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID)) 1909*00d0963fSdilpreet goto done; 1910*00d0963fSdilpreet for (i = 0; pciex_nadv_err_tbl[i].err_class != NULL; i++) { 1911*00d0963fSdilpreet if (!(pcie_regs->pcie_err_status & 1912*00d0963fSdilpreet pciex_nadv_err_tbl[i].reg_bit)) 1913*00d0963fSdilpreet continue; 1914*00d0963fSdilpreet 1915*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 1916*00d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 1917*00d0963fSdilpreet pciex_nadv_err_tbl[i].err_class); 1918*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1919*00d0963fSdilpreet PCIEX_TYPE_GEN); 1920*00d0963fSdilpreet PCI_FM_SEV_INC(pciex_nadv_err_tbl[i].flags); 1921*00d0963fSdilpreet } 1922*00d0963fSdilpreet goto done; 1923*00d0963fSdilpreet } 1924*00d0963fSdilpreet 1925*00d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 1926*00d0963fSdilpreet 1927*00d0963fSdilpreet /* 1928*00d0963fSdilpreet * Log PCI Express uncorrectable errors 1929*00d0963fSdilpreet */ 1930*00d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) { 1931*00d0963fSdilpreet for (i = 0; pciex_ue_err_tbl[i].err_class != NULL; i++) { 1932*00d0963fSdilpreet if (!(pcie_adv_regs->pcie_ue_status & 1933*00d0963fSdilpreet pciex_ue_err_tbl[i].reg_bit)) 1934*00d0963fSdilpreet continue; 1935*00d0963fSdilpreet 1936*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1937*00d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 1938*00d0963fSdilpreet pciex_ue_err_tbl[i].err_class); 1939*00d0963fSdilpreet 1940*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 1941*00d0963fSdilpreet if ((pcie_adv_regs->pcie_ue_status & 1942*00d0963fSdilpreet PCIE_AER_UCE_LOG_BITS) != 1943*00d0963fSdilpreet pciex_ue_err_tbl[i].reg_bit) { 1944*00d0963fSdilpreet PCI_FM_SEV_INC(pciex_ue_err_tbl[i].flags); 1945*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1946*00d0963fSdilpreet PCIEX_TYPE_UE); 1947*00d0963fSdilpreet } else { 1948*00d0963fSdilpreet pcie_check_addr(dip, derr, erpt_p); 1949*00d0963fSdilpreet /* 1950*00d0963fSdilpreet * fatal/nonfatal errors are fatal/nonfatal 1951*00d0963fSdilpreet * regardless of if we find a handle 1952*00d0963fSdilpreet */ 1953*00d0963fSdilpreet if (pciex_ue_err_tbl[i].flags == DDI_FM_FATAL) 1954*00d0963fSdilpreet derr->fme_status = DDI_FM_FATAL; 1955*00d0963fSdilpreet else if (pciex_ue_err_tbl[i].flags == 1956*00d0963fSdilpreet DDI_FM_NONFATAL) 1957*00d0963fSdilpreet derr->fme_status = DDI_FM_NONFATAL; 1958*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1959*00d0963fSdilpreet PCIEX_TYPE_UE); 1960*00d0963fSdilpreet PCI_FM_SEV_INC(derr->fme_status); 1961*00d0963fSdilpreet } 1962*00d0963fSdilpreet } 1963*00d0963fSdilpreet } 1964*00d0963fSdilpreet 1965*00d0963fSdilpreet /* 1966*00d0963fSdilpreet * Log PCI Express correctable errors 1967*00d0963fSdilpreet */ 1968*00d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) { 1969*00d0963fSdilpreet for (i = 0; pciex_ce_err_tbl[i].err_class != NULL; i++) { 1970*00d0963fSdilpreet if (!(pcie_adv_regs->pcie_ce_status & 1971*00d0963fSdilpreet pciex_ce_err_tbl[i].reg_bit)) 1972*00d0963fSdilpreet continue; 1973*00d0963fSdilpreet 1974*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 1975*00d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 1976*00d0963fSdilpreet pciex_ce_err_tbl[i].err_class); 1977*00d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 1978*00d0963fSdilpreet PCIEX_TYPE_CE); 1979*00d0963fSdilpreet if (!fatal && !unknown) 1980*00d0963fSdilpreet PCI_FM_SEV_INC(pciex_ce_err_tbl[i].flags); 1981*00d0963fSdilpreet } 1982*00d0963fSdilpreet } 1983*00d0963fSdilpreet 1984*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) 1985*00d0963fSdilpreet goto done; 1986*00d0963fSdilpreet 1987*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 1988*00d0963fSdilpreet int ret = pcie_rc_error_report(dip, derr, erpt_p, 1989*00d0963fSdilpreet (void *)pcie_adv_regs); 1990*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 1991*00d0963fSdilpreet } 1992*00d0963fSdilpreet 1993*00d0963fSdilpreet if (!((erpt_p->pe_dflags & PCIEX_2PCI_DEV) && 1994*00d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID))) 1995*00d0963fSdilpreet goto done; 1996*00d0963fSdilpreet 1997*00d0963fSdilpreet pcie_bdg_regs = pcie_adv_regs->pcie_adv_bdg_regs; 1998*00d0963fSdilpreet 1999*00d0963fSdilpreet for (i = 0; pcie_sue_err_tbl[i].err_class != NULL; i++) { 2000*00d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 2001*00d0963fSdilpreet pcie_sue_err_tbl[i].reg_bit)) { 2002*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 2003*00d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 2004*00d0963fSdilpreet pcie_sue_err_tbl[i].err_class); 2005*00d0963fSdilpreet 2006*00d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 2007*00d0963fSdilpreet PCIE_AER_SUCE_LOG_BITS) != 2008*00d0963fSdilpreet pcie_sue_err_tbl[i].reg_bit) { 2009*00d0963fSdilpreet PCI_FM_SEV_INC(pcie_sue_err_tbl[i].flags); 2010*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 2011*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 2012*00d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 2013*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 2014*00d0963fSdilpreet #ifdef DEBUG 2015*00d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 2016*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 2017*00d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 2018*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 2019*00d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 2020*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 2021*00d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 2022*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 2023*00d0963fSdilpreet #endif 2024*00d0963fSdilpreet NULL); 2025*00d0963fSdilpreet } else { 2026*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 2027*00d0963fSdilpreet pcie_pci_check_addr(dip, derr, erpt_p); 2028*00d0963fSdilpreet /* 2029*00d0963fSdilpreet * fatal/nonfatal errors are fatal/nonfatal 2030*00d0963fSdilpreet * regardless of if we find a handle 2031*00d0963fSdilpreet */ 2032*00d0963fSdilpreet if (pcie_sue_err_tbl[i].flags == DDI_FM_FATAL) 2033*00d0963fSdilpreet derr->fme_status = DDI_FM_FATAL; 2034*00d0963fSdilpreet else if (pcie_sue_err_tbl[i].flags == 2035*00d0963fSdilpreet DDI_FM_NONFATAL) 2036*00d0963fSdilpreet derr->fme_status = DDI_FM_NONFATAL; 2037*00d0963fSdilpreet 2038*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 2039*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 2040*00d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 2041*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 2042*00d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 2043*00d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 2044*00d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 2045*00d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 2046*00d0963fSdilpreet 1 : NULL, 2047*00d0963fSdilpreet #ifdef DEBUG 2048*00d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 2049*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 2050*00d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 2051*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 2052*00d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 2053*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 2054*00d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 2055*00d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 2056*00d0963fSdilpreet #endif 2057*00d0963fSdilpreet NULL); 2058*00d0963fSdilpreet PCI_FM_SEV_INC(derr->fme_status); 2059*00d0963fSdilpreet } 2060*00d0963fSdilpreet } 2061*00d0963fSdilpreet } 2062*00d0963fSdilpreet done: 2063*00d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 2064*00d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 2065*00d0963fSdilpreet } 2066*00d0963fSdilpreet 2067*00d0963fSdilpreet static void 2068*00d0963fSdilpreet pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 2069*00d0963fSdilpreet { 2070*00d0963fSdilpreet int fatal = 0; 2071*00d0963fSdilpreet int nonfatal = 0; 2072*00d0963fSdilpreet int unknown = 0; 2073*00d0963fSdilpreet int ok = 0; 2074*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 2075*00d0963fSdilpreet int i; 2076*00d0963fSdilpreet 2077*00d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 2078*00d0963fSdilpreet /* 2079*00d0963fSdilpreet * Log generic PCI errors. 2080*00d0963fSdilpreet */ 2081*00d0963fSdilpreet for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 2082*00d0963fSdilpreet if (!(erpt_p->pe_pci_regs->pci_err_status & 2083*00d0963fSdilpreet pci_err_tbl[i].reg_bit) || 2084*00d0963fSdilpreet !(erpt_p->pe_pci_regs->pci_vflags & 2085*00d0963fSdilpreet PCI_ERR_STATUS_VALID)) 2086*00d0963fSdilpreet continue; 2087*00d0963fSdilpreet /* 2088*00d0963fSdilpreet * Generate an ereport for this error bit. 2089*00d0963fSdilpreet */ 2090*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 2091*00d0963fSdilpreet PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class); 2092*00d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 2093*00d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 2094*00d0963fSdilpreet PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 2095*00d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status, 2096*00d0963fSdilpreet PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 2097*00d0963fSdilpreet erpt_p->pe_pci_regs->pci_cfg_comm, NULL); 2098*00d0963fSdilpreet 2099*00d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) 2100*00d0963fSdilpreet PCI_FM_SEV_INC(pci_err_tbl[i].flags); 2101*00d0963fSdilpreet } 2102*00d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) { 2103*00d0963fSdilpreet int ret = pcie_error_report(dip, derr, erpt_p); 2104*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 2105*00d0963fSdilpreet } else if (erpt_p->pe_dflags & PCIX_DEV) { 2106*00d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 2107*00d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, 2108*00d0963fSdilpreet erpt_p, erpt_p->pe_regs); 2109*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 2110*00d0963fSdilpreet } else { 2111*00d0963fSdilpreet int ret = pcix_error_report(dip, derr, erpt_p); 2112*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 2113*00d0963fSdilpreet } 2114*00d0963fSdilpreet } 2115*00d0963fSdilpreet } 2116*00d0963fSdilpreet 2117*00d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) { 2118*00d0963fSdilpreet int ret = pci_bdg_error_report(dip, derr, erpt_p); 2119*00d0963fSdilpreet PCI_FM_SEV_INC(ret); 2120*00d0963fSdilpreet } 2121*00d0963fSdilpreet 2122*00d0963fSdilpreet derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 2123*00d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 2124*00d0963fSdilpreet } 2125*00d0963fSdilpreet 2126*00d0963fSdilpreet void 2127*00d0963fSdilpreet pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status) 2128*00d0963fSdilpreet { 2129*00d0963fSdilpreet struct i_ddi_fmhdl *fmhdl; 2130*00d0963fSdilpreet pci_erpt_t *erpt_p; 2131*00d0963fSdilpreet 2132*00d0963fSdilpreet fmhdl = DEVI(dip)->devi_fmhdl; 2133*00d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 2134*00d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 2135*00d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 2136*00d0963fSdilpreet return; 2137*00d0963fSdilpreet } 2138*00d0963fSdilpreet 2139*00d0963fSdilpreet ASSERT(fmhdl); 2140*00d0963fSdilpreet 2141*00d0963fSdilpreet if (derr->fme_ena == NULL) 2142*00d0963fSdilpreet derr->fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 2143*00d0963fSdilpreet 2144*00d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 2145*00d0963fSdilpreet if (erpt_p == NULL) { 2146*00d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 2147*00d0963fSdilpreet return; 2148*00d0963fSdilpreet } 2149*00d0963fSdilpreet 2150*00d0963fSdilpreet pci_regs_gather(dip, erpt_p); 2151*00d0963fSdilpreet pci_error_report(dip, derr, erpt_p); 2152*00d0963fSdilpreet pci_regs_clear(erpt_p); 2153*00d0963fSdilpreet 2154*00d0963fSdilpreet if (xx_status != NULL) 2155*00d0963fSdilpreet *xx_status = erpt_p->pe_pci_regs->pci_err_status; 2156*00d0963fSdilpreet } 2157*00d0963fSdilpreet 2158*00d0963fSdilpreet /* 2159*00d0963fSdilpreet * private version of walk_devs() that can be used during panic. No 2160*00d0963fSdilpreet * sleeping or locking required. 2161*00d0963fSdilpreet */ 2162*00d0963fSdilpreet static int 2163*00d0963fSdilpreet pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg) 2164*00d0963fSdilpreet { 2165*00d0963fSdilpreet while (dip) { 2166*00d0963fSdilpreet switch ((*f)(dip, arg)) { 2167*00d0963fSdilpreet case DDI_WALK_TERMINATE: 2168*00d0963fSdilpreet return (DDI_WALK_TERMINATE); 2169*00d0963fSdilpreet case DDI_WALK_CONTINUE: 2170*00d0963fSdilpreet if (pci_fm_walk_devs(ddi_get_child(dip), f, 2171*00d0963fSdilpreet arg) == DDI_WALK_TERMINATE) 2172*00d0963fSdilpreet return (DDI_WALK_TERMINATE); 2173*00d0963fSdilpreet break; 2174*00d0963fSdilpreet case DDI_WALK_PRUNECHILD: 2175*00d0963fSdilpreet break; 2176*00d0963fSdilpreet } 2177*00d0963fSdilpreet dip = ddi_get_next_sibling(dip); 2178*00d0963fSdilpreet } 2179*00d0963fSdilpreet return (DDI_WALK_CONTINUE); 2180*00d0963fSdilpreet } 2181*00d0963fSdilpreet 2182*00d0963fSdilpreet /* 2183*00d0963fSdilpreet * need special version of ddi_fm_ereport_post() as the leaf driver may 2184*00d0963fSdilpreet * not be hardened. 2185*00d0963fSdilpreet */ 2186*00d0963fSdilpreet static void 2187*00d0963fSdilpreet pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena, 2188*00d0963fSdilpreet uint8_t version, ...) 2189*00d0963fSdilpreet { 2190*00d0963fSdilpreet char *name; 2191*00d0963fSdilpreet char device_path[MAXPATHLEN]; 2192*00d0963fSdilpreet char ddi_error_class[FM_MAX_CLASS]; 2193*00d0963fSdilpreet nvlist_t *ereport, *detector; 2194*00d0963fSdilpreet nv_alloc_t *nva; 2195*00d0963fSdilpreet errorq_elem_t *eqep; 2196*00d0963fSdilpreet va_list ap; 2197*00d0963fSdilpreet 2198*00d0963fSdilpreet if (panicstr) { 2199*00d0963fSdilpreet eqep = errorq_reserve(ereport_errorq); 2200*00d0963fSdilpreet if (eqep == NULL) 2201*00d0963fSdilpreet return; 2202*00d0963fSdilpreet ereport = errorq_elem_nvl(ereport_errorq, eqep); 2203*00d0963fSdilpreet nva = errorq_elem_nva(ereport_errorq, eqep); 2204*00d0963fSdilpreet detector = fm_nvlist_create(nva); 2205*00d0963fSdilpreet } else { 2206*00d0963fSdilpreet ereport = fm_nvlist_create(NULL); 2207*00d0963fSdilpreet detector = fm_nvlist_create(NULL); 2208*00d0963fSdilpreet } 2209*00d0963fSdilpreet 2210*00d0963fSdilpreet (void) ddi_pathname(dip, device_path); 2211*00d0963fSdilpreet fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, 2212*00d0963fSdilpreet device_path, NULL); 2213*00d0963fSdilpreet (void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s", 2214*00d0963fSdilpreet DDI_IO_CLASS, error_class); 2215*00d0963fSdilpreet fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL); 2216*00d0963fSdilpreet 2217*00d0963fSdilpreet va_start(ap, version); 2218*00d0963fSdilpreet name = va_arg(ap, char *); 2219*00d0963fSdilpreet (void) i_fm_payload_set(ereport, name, ap); 2220*00d0963fSdilpreet va_end(ap); 2221*00d0963fSdilpreet 2222*00d0963fSdilpreet if (panicstr) { 2223*00d0963fSdilpreet errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); 2224*00d0963fSdilpreet } else { 2225*00d0963fSdilpreet (void) fm_ereport_post(ereport, EVCH_TRYHARD); 2226*00d0963fSdilpreet fm_nvlist_destroy(ereport, FM_NVA_FREE); 2227*00d0963fSdilpreet fm_nvlist_destroy(detector, FM_NVA_FREE); 2228*00d0963fSdilpreet } 2229*00d0963fSdilpreet } 2230*00d0963fSdilpreet 2231*00d0963fSdilpreet static int 2232*00d0963fSdilpreet pci_check_regs(dev_info_t *dip, void *arg) 2233*00d0963fSdilpreet { 2234*00d0963fSdilpreet int reglen; 2235*00d0963fSdilpreet int rn; 2236*00d0963fSdilpreet int totreg; 2237*00d0963fSdilpreet pci_regspec_t *drv_regp; 2238*00d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 2239*00d0963fSdilpreet 2240*00d0963fSdilpreet if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 2241*00d0963fSdilpreet /* 2242*00d0963fSdilpreet * for config space, we need to check if the given address 2243*00d0963fSdilpreet * is a valid config space address for this device - based 2244*00d0963fSdilpreet * on pci_phys_hi of the config space entry in reg property. 2245*00d0963fSdilpreet */ 2246*00d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 2247*00d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 2248*00d0963fSdilpreet return (DDI_WALK_CONTINUE); 2249*00d0963fSdilpreet 2250*00d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 2251*00d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 2252*00d0963fSdilpreet if (tgt_err->tgt_pci_space == 2253*00d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) && 2254*00d0963fSdilpreet (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M | 2255*00d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M)) == 2256*00d0963fSdilpreet (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M | 2257*00d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M))) { 2258*00d0963fSdilpreet tgt_err->tgt_dip = dip; 2259*00d0963fSdilpreet kmem_free(drv_regp, reglen); 2260*00d0963fSdilpreet return (DDI_WALK_TERMINATE); 2261*00d0963fSdilpreet } 2262*00d0963fSdilpreet } 2263*00d0963fSdilpreet kmem_free(drv_regp, reglen); 2264*00d0963fSdilpreet } else { 2265*00d0963fSdilpreet /* 2266*00d0963fSdilpreet * for non config space, need to check reg to look 2267*00d0963fSdilpreet * for any non-relocable mapping, otherwise check 2268*00d0963fSdilpreet * assigned-addresses. 2269*00d0963fSdilpreet */ 2270*00d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 2271*00d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 2272*00d0963fSdilpreet return (DDI_WALK_CONTINUE); 2273*00d0963fSdilpreet 2274*00d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 2275*00d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 2276*00d0963fSdilpreet if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) && 2277*00d0963fSdilpreet (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 2278*00d0963fSdilpreet tgt_err->tgt_pci_space == 2279*00d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 2280*00d0963fSdilpreet (tgt_err->tgt_pci_addr >= 2281*00d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 2282*00d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 2283*00d0963fSdilpreet (tgt_err->tgt_pci_addr < 2284*00d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 2285*00d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 2286*00d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 2287*00d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 2288*00d0963fSdilpreet tgt_err->tgt_dip = dip; 2289*00d0963fSdilpreet kmem_free(drv_regp, reglen); 2290*00d0963fSdilpreet return (DDI_WALK_TERMINATE); 2291*00d0963fSdilpreet } 2292*00d0963fSdilpreet } 2293*00d0963fSdilpreet kmem_free(drv_regp, reglen); 2294*00d0963fSdilpreet 2295*00d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 2296*00d0963fSdilpreet "assigned-addresses", (caddr_t)&drv_regp, ®len) != 2297*00d0963fSdilpreet DDI_SUCCESS) 2298*00d0963fSdilpreet return (DDI_WALK_CONTINUE); 2299*00d0963fSdilpreet 2300*00d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 2301*00d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 2302*00d0963fSdilpreet if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 2303*00d0963fSdilpreet tgt_err->tgt_pci_space == 2304*00d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 2305*00d0963fSdilpreet (tgt_err->tgt_pci_addr >= 2306*00d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 2307*00d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 2308*00d0963fSdilpreet (tgt_err->tgt_pci_addr < 2309*00d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 2310*00d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 2311*00d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 2312*00d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 2313*00d0963fSdilpreet tgt_err->tgt_dip = dip; 2314*00d0963fSdilpreet kmem_free(drv_regp, reglen); 2315*00d0963fSdilpreet return (DDI_WALK_TERMINATE); 2316*00d0963fSdilpreet } 2317*00d0963fSdilpreet } 2318*00d0963fSdilpreet kmem_free(drv_regp, reglen); 2319*00d0963fSdilpreet } 2320*00d0963fSdilpreet return (DDI_WALK_CONTINUE); 2321*00d0963fSdilpreet } 2322*00d0963fSdilpreet 2323*00d0963fSdilpreet /* 2324*00d0963fSdilpreet * impl_fix_ranges - fixes the config space entry of the "ranges" 2325*00d0963fSdilpreet * property on psycho+ platforms. (if changing this function please make sure 2326*00d0963fSdilpreet * to change the pci_fix_ranges function in pcipsy.c) 2327*00d0963fSdilpreet */ 2328*00d0963fSdilpreet /*ARGSUSED*/ 2329*00d0963fSdilpreet static void 2330*00d0963fSdilpreet pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange) 2331*00d0963fSdilpreet { 2332*00d0963fSdilpreet #if defined(__sparc) 2333*00d0963fSdilpreet char *name = ddi_binding_name(dip); 2334*00d0963fSdilpreet 2335*00d0963fSdilpreet if ((strcmp(name, "pci108e,8000") == 0) || 2336*00d0963fSdilpreet (strcmp(name, "pci108e,a000") == 0) || 2337*00d0963fSdilpreet (strcmp(name, "pci108e,a001") == 0)) { 2338*00d0963fSdilpreet int i; 2339*00d0963fSdilpreet for (i = 0; i < nrange; i++, pci_ranges++) 2340*00d0963fSdilpreet if ((pci_ranges->child_high & PCI_REG_ADDR_M) == 2341*00d0963fSdilpreet PCI_ADDR_CONFIG) 2342*00d0963fSdilpreet pci_ranges->parent_low |= 2343*00d0963fSdilpreet pci_ranges->child_high; 2344*00d0963fSdilpreet } 2345*00d0963fSdilpreet #endif 2346*00d0963fSdilpreet } 2347*00d0963fSdilpreet 2348*00d0963fSdilpreet static int 2349*00d0963fSdilpreet pci_check_ranges(dev_info_t *dip, void *arg) 2350*00d0963fSdilpreet { 2351*00d0963fSdilpreet uint64_t range_parent_begin; 2352*00d0963fSdilpreet uint64_t range_parent_size; 2353*00d0963fSdilpreet uint64_t range_parent_end; 2354*00d0963fSdilpreet uint32_t space_type; 2355*00d0963fSdilpreet uint32_t bus_num; 2356*00d0963fSdilpreet uint32_t range_offset; 2357*00d0963fSdilpreet pci_ranges_t *pci_ranges, *rangep; 2358*00d0963fSdilpreet pci_bus_range_t *pci_bus_rangep; 2359*00d0963fSdilpreet int pci_ranges_length; 2360*00d0963fSdilpreet int nrange; 2361*00d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 2362*00d0963fSdilpreet int i, size; 2363*00d0963fSdilpreet if (strcmp(ddi_node_name(dip), "pci") != 0 && 2364*00d0963fSdilpreet strcmp(ddi_node_name(dip), "pciex") != 0) 2365*00d0963fSdilpreet return (DDI_WALK_CONTINUE); 2366*00d0963fSdilpreet 2367*00d0963fSdilpreet /* 2368*00d0963fSdilpreet * Get the ranges property. Note we only look at the top level pci 2369*00d0963fSdilpreet * node (hostbridge) which has a ranges property of type pci_ranges_t 2370*00d0963fSdilpreet * not at pci-pci bridges. 2371*00d0963fSdilpreet */ 2372*00d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 2373*00d0963fSdilpreet (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) { 2374*00d0963fSdilpreet /* 2375*00d0963fSdilpreet * no ranges property - no translation needed 2376*00d0963fSdilpreet */ 2377*00d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr; 2378*00d0963fSdilpreet tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN; 2379*00d0963fSdilpreet if (panicstr) 2380*00d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 2381*00d0963fSdilpreet pci_check_regs, (void *)tgt_err); 2382*00d0963fSdilpreet else { 2383*00d0963fSdilpreet int circ = 0; 2384*00d0963fSdilpreet ndi_devi_enter(dip, &circ); 2385*00d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 2386*00d0963fSdilpreet (void *)tgt_err); 2387*00d0963fSdilpreet ndi_devi_exit(dip, circ); 2388*00d0963fSdilpreet } 2389*00d0963fSdilpreet if (tgt_err->tgt_dip != NULL) 2390*00d0963fSdilpreet return (DDI_WALK_TERMINATE); 2391*00d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 2392*00d0963fSdilpreet } 2393*00d0963fSdilpreet nrange = pci_ranges_length / sizeof (pci_ranges_t); 2394*00d0963fSdilpreet rangep = pci_ranges; 2395*00d0963fSdilpreet 2396*00d0963fSdilpreet /* Need to fix the pci ranges property for psycho based systems */ 2397*00d0963fSdilpreet pci_fix_ranges(dip, pci_ranges, nrange); 2398*00d0963fSdilpreet 2399*00d0963fSdilpreet for (i = 0; i < nrange; i++, rangep++) { 2400*00d0963fSdilpreet range_parent_begin = ((uint64_t)rangep->parent_high << 32) + 2401*00d0963fSdilpreet rangep->parent_low; 2402*00d0963fSdilpreet range_parent_size = ((uint64_t)rangep->size_high << 32) + 2403*00d0963fSdilpreet rangep->size_low; 2404*00d0963fSdilpreet range_parent_end = range_parent_begin + range_parent_size - 1; 2405*00d0963fSdilpreet 2406*00d0963fSdilpreet if ((tgt_err->tgt_err_addr < range_parent_begin) || 2407*00d0963fSdilpreet (tgt_err->tgt_err_addr > range_parent_end)) { 2408*00d0963fSdilpreet /* Not in range */ 2409*00d0963fSdilpreet continue; 2410*00d0963fSdilpreet } 2411*00d0963fSdilpreet space_type = PCI_REG_ADDR_G(rangep->child_high); 2412*00d0963fSdilpreet if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 2413*00d0963fSdilpreet /* Config space address - check bus range */ 2414*00d0963fSdilpreet range_offset = tgt_err->tgt_err_addr - 2415*00d0963fSdilpreet range_parent_begin; 2416*00d0963fSdilpreet bus_num = PCI_REG_BUS_G(range_offset); 2417*00d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2418*00d0963fSdilpreet DDI_PROP_DONTPASS, "bus-range", 2419*00d0963fSdilpreet (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) { 2420*00d0963fSdilpreet continue; 2421*00d0963fSdilpreet } 2422*00d0963fSdilpreet if ((bus_num < pci_bus_rangep->lo) || 2423*00d0963fSdilpreet (bus_num > pci_bus_rangep->hi)) { 2424*00d0963fSdilpreet /* 2425*00d0963fSdilpreet * Bus number not appropriate for this 2426*00d0963fSdilpreet * pci nexus. 2427*00d0963fSdilpreet */ 2428*00d0963fSdilpreet kmem_free(pci_bus_rangep, size); 2429*00d0963fSdilpreet continue; 2430*00d0963fSdilpreet } 2431*00d0963fSdilpreet kmem_free(pci_bus_rangep, size); 2432*00d0963fSdilpreet } 2433*00d0963fSdilpreet 2434*00d0963fSdilpreet /* We have a match if we get here - compute pci address */ 2435*00d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr - 2436*00d0963fSdilpreet range_parent_begin; 2437*00d0963fSdilpreet tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) + 2438*00d0963fSdilpreet rangep->child_low); 2439*00d0963fSdilpreet tgt_err->tgt_pci_space = space_type; 2440*00d0963fSdilpreet if (panicstr) 2441*00d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 2442*00d0963fSdilpreet pci_check_regs, (void *)tgt_err); 2443*00d0963fSdilpreet else { 2444*00d0963fSdilpreet int circ = 0; 2445*00d0963fSdilpreet ndi_devi_enter(dip, &circ); 2446*00d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 2447*00d0963fSdilpreet (void *)tgt_err); 2448*00d0963fSdilpreet ndi_devi_exit(dip, circ); 2449*00d0963fSdilpreet } 2450*00d0963fSdilpreet if (tgt_err->tgt_dip != NULL) { 2451*00d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 2452*00d0963fSdilpreet return (DDI_WALK_TERMINATE); 2453*00d0963fSdilpreet } 2454*00d0963fSdilpreet } 2455*00d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 2456*00d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 2457*00d0963fSdilpreet } 2458*00d0963fSdilpreet 2459*00d0963fSdilpreet /* 2460*00d0963fSdilpreet * Function used to drain pci_target_queue, either during panic or after softint 2461*00d0963fSdilpreet * is generated, to generate target device ereports based on captured physical 2462*00d0963fSdilpreet * addresses 2463*00d0963fSdilpreet */ 2464*00d0963fSdilpreet /*ARGSUSED*/ 2465*00d0963fSdilpreet static void 2466*00d0963fSdilpreet pci_target_drain(void *private_p, pci_target_err_t *tgt_err) 2467*00d0963fSdilpreet { 2468*00d0963fSdilpreet char buf[FM_MAX_CLASS]; 2469*00d0963fSdilpreet 2470*00d0963fSdilpreet /* 2471*00d0963fSdilpreet * The following assumes that all pci_pci bridge devices 2472*00d0963fSdilpreet * are configured as transparant. Find the top-level pci 2473*00d0963fSdilpreet * nexus which has tgt_err_addr in one of its ranges, converting this 2474*00d0963fSdilpreet * to a pci address in the process. Then starting at this node do 2475*00d0963fSdilpreet * another tree walk to find a device with the pci address we've 2476*00d0963fSdilpreet * found within range of one of it's assigned-addresses properties. 2477*00d0963fSdilpreet */ 2478*00d0963fSdilpreet tgt_err->tgt_dip = NULL; 2479*00d0963fSdilpreet if (panicstr) 2480*00d0963fSdilpreet (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges, 2481*00d0963fSdilpreet (void *)tgt_err); 2482*00d0963fSdilpreet else 2483*00d0963fSdilpreet ddi_walk_devs(ddi_root_node(), pci_check_ranges, 2484*00d0963fSdilpreet (void *)tgt_err); 2485*00d0963fSdilpreet if (tgt_err->tgt_dip == NULL) 2486*00d0963fSdilpreet return; 2487*00d0963fSdilpreet 2488*00d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type, 2489*00d0963fSdilpreet tgt_err->tgt_err_class); 2490*00d0963fSdilpreet pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0, 2491*00d0963fSdilpreet PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL); 2492*00d0963fSdilpreet } 2493*00d0963fSdilpreet 2494*00d0963fSdilpreet void 2495*00d0963fSdilpreet pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr) 2496*00d0963fSdilpreet { 2497*00d0963fSdilpreet pci_target_err_t tgt_err; 2498*00d0963fSdilpreet 2499*00d0963fSdilpreet tgt_err.tgt_err_ena = ena; 2500*00d0963fSdilpreet tgt_err.tgt_err_class = class; 2501*00d0963fSdilpreet tgt_err.tgt_bridge_type = bridge_type; 2502*00d0963fSdilpreet tgt_err.tgt_err_addr = addr; 2503*00d0963fSdilpreet errorq_dispatch(pci_target_queue, (void *)&tgt_err, 2504*00d0963fSdilpreet sizeof (pci_target_err_t), ERRORQ_ASYNC); 2505*00d0963fSdilpreet } 2506*00d0963fSdilpreet 2507*00d0963fSdilpreet void 2508*00d0963fSdilpreet pci_targetq_init(void) 2509*00d0963fSdilpreet { 2510*00d0963fSdilpreet /* 2511*00d0963fSdilpreet * PCI target errorq, to schedule async handling of generation of 2512*00d0963fSdilpreet * target device ereports based on captured physical address. 2513*00d0963fSdilpreet * The errorq is created here but destroyed when _fini is called 2514*00d0963fSdilpreet * for the pci module. 2515*00d0963fSdilpreet */ 2516*00d0963fSdilpreet if (pci_target_queue == NULL) { 2517*00d0963fSdilpreet pci_target_queue = errorq_create("pci_target_queue", 2518*00d0963fSdilpreet (errorq_func_t)pci_target_drain, (void *)NULL, 2519*00d0963fSdilpreet TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL, 2520*00d0963fSdilpreet ERRORQ_VITAL); 2521*00d0963fSdilpreet if (pci_target_queue == NULL) 2522*00d0963fSdilpreet panic("failed to create required system error queue"); 2523*00d0963fSdilpreet } 2524*00d0963fSdilpreet } 2525