100d0963fSdilpreet /* 200d0963fSdilpreet * CDDL HEADER START 300d0963fSdilpreet * 400d0963fSdilpreet * The contents of this file are subject to the terms of the 500d0963fSdilpreet * Common Development and Distribution License (the "License"). 600d0963fSdilpreet * You may not use this file except in compliance with the License. 700d0963fSdilpreet * 800d0963fSdilpreet * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 900d0963fSdilpreet * or http://www.opensolaris.org/os/licensing. 1000d0963fSdilpreet * See the License for the specific language governing permissions 1100d0963fSdilpreet * and limitations under the License. 1200d0963fSdilpreet * 1300d0963fSdilpreet * When distributing Covered Code, include this CDDL HEADER in each 1400d0963fSdilpreet * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1500d0963fSdilpreet * If applicable, add the following below this CDDL HEADER, with the 1600d0963fSdilpreet * fields enclosed by brackets "[]" replaced with your own identifying 1700d0963fSdilpreet * information: Portions Copyright [yyyy] [name of copyright owner] 1800d0963fSdilpreet * 1900d0963fSdilpreet * CDDL HEADER END 2000d0963fSdilpreet */ 2100d0963fSdilpreet 2200d0963fSdilpreet /* 2300d0963fSdilpreet * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2400d0963fSdilpreet * Use is subject to license terms. 2500d0963fSdilpreet */ 2600d0963fSdilpreet 2700d0963fSdilpreet #pragma ident "%Z%%M% %I% %E% SMI" 2800d0963fSdilpreet 2900d0963fSdilpreet #include <sys/types.h> 3000d0963fSdilpreet #include <sys/sunndi.h> 3100d0963fSdilpreet #include <sys/sysmacros.h> 3200d0963fSdilpreet #include <sys/ddifm_impl.h> 3300d0963fSdilpreet #include <sys/fm/util.h> 3400d0963fSdilpreet #include <sys/fm/protocol.h> 3500d0963fSdilpreet #include <sys/fm/io/pci.h> 3600d0963fSdilpreet #include <sys/fm/io/ddi.h> 3700d0963fSdilpreet #include <sys/pci.h> 3800d0963fSdilpreet #include <sys/pcie.h> 3900d0963fSdilpreet #include <sys/pci_impl.h> 4000d0963fSdilpreet #include <sys/epm.h> 4100d0963fSdilpreet #include <sys/pcifm.h> 4200d0963fSdilpreet 4300d0963fSdilpreet #define PCIX_ECC_VER_CHECK(x) (((x) == PCI_PCIX_VER_1) ||\ 4400d0963fSdilpreet ((x) == PCI_PCIX_VER_2)) 4500d0963fSdilpreet 4600d0963fSdilpreet /* 4700d0963fSdilpreet * Expected PCI Express error mask values 4800d0963fSdilpreet */ 49*8aec9182Sstephh uint32_t pcie_expected_ce_mask = 0x0; 50*8aec9182Sstephh uint32_t pcie_expected_ue_mask = PCIE_AER_UCE_UC; 510c64a9b4Sanish #if defined(__sparc) 52*8aec9182Sstephh uint32_t pcie_expected_sue_mask = 0x0; 53*8aec9182Sstephh #else 54*8aec9182Sstephh uint32_t pcie_expected_sue_mask = PCIE_AER_SUCE_RCVD_MA; 55*8aec9182Sstephh #endif 560c64a9b4Sanish uint32_t pcie_aer_uce_log_bits = PCIE_AER_UCE_LOG_BITS; 57*8aec9182Sstephh #if defined(__sparc) 580c64a9b4Sanish uint32_t pcie_aer_suce_log_bits = PCIE_AER_SUCE_LOG_BITS; 590c64a9b4Sanish #else 600c64a9b4Sanish uint32_t pcie_aer_suce_log_bits = \ 610c64a9b4Sanish PCIE_AER_SUCE_LOG_BITS & ~PCIE_AER_SUCE_RCVD_MA; 620c64a9b4Sanish #endif 6300d0963fSdilpreet 6400d0963fSdilpreet errorq_t *pci_target_queue = NULL; 6500d0963fSdilpreet 6600d0963fSdilpreet pci_fm_err_t pci_err_tbl[] = { 6700d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 6800d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 6900d0963fSdilpreet PCI_SIG_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_FATAL, 7000d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 7100d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 7200d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 7300d0963fSdilpreet NULL, NULL, NULL, NULL, 7400d0963fSdilpreet }; 7500d0963fSdilpreet 7600d0963fSdilpreet pci_fm_err_t pci_bdg_err_tbl[] = { 7700d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 7800d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 7900d0963fSdilpreet PCI_REC_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_UNKNOWN, 80*8aec9182Sstephh #if defined(__sparc) 8100d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 820c64a9b4Sanish #endif 8300d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 8400d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 8500d0963fSdilpreet NULL, NULL, NULL, NULL, 8600d0963fSdilpreet }; 8700d0963fSdilpreet 8800d0963fSdilpreet static pci_fm_err_t pciex_ce_err_tbl[] = { 89ac4d633fSstephh PCIEX_RE, PCIE_AER_CE_RECEIVER_ERR, NULL, DDI_FM_OK, 90ac4d633fSstephh PCIEX_RNR, PCIE_AER_CE_REPLAY_ROLLOVER, NULL, DDI_FM_OK, 91ac4d633fSstephh PCIEX_RTO, PCIE_AER_CE_REPLAY_TO, NULL, DDI_FM_OK, 92ac4d633fSstephh PCIEX_BDP, PCIE_AER_CE_BAD_DLLP, NULL, DDI_FM_OK, 93ac4d633fSstephh PCIEX_BTP, PCIE_AER_CE_BAD_TLP, NULL, DDI_FM_OK, 94ac4d633fSstephh PCIEX_ANFE, PCIE_AER_CE_AD_NFE, NULL, DDI_FM_OK, 9500d0963fSdilpreet NULL, NULL, NULL, NULL, 9600d0963fSdilpreet }; 9700d0963fSdilpreet 9800d0963fSdilpreet static pci_fm_err_t pciex_ue_err_tbl[] = { 9900d0963fSdilpreet PCIEX_TE, PCIE_AER_UCE_TRAINING, NULL, DDI_FM_FATAL, 10000d0963fSdilpreet PCIEX_DLP, PCIE_AER_UCE_DLP, NULL, DDI_FM_FATAL, 10100d0963fSdilpreet PCIEX_SD, PCIE_AER_UCE_SD, NULL, DDI_FM_FATAL, 10200d0963fSdilpreet PCIEX_ROF, PCIE_AER_UCE_RO, NULL, DDI_FM_FATAL, 10300d0963fSdilpreet PCIEX_FCP, PCIE_AER_UCE_FCP, NULL, DDI_FM_FATAL, 10400d0963fSdilpreet PCIEX_MFP, PCIE_AER_UCE_MTLP, NULL, DDI_FM_FATAL, 105ac4d633fSstephh PCIEX_CTO, PCIE_AER_UCE_TO, NULL, DDI_FM_UNKNOWN, 106ac4d633fSstephh PCIEX_UC, PCIE_AER_UCE_UC, NULL, DDI_FM_OK, 10700d0963fSdilpreet PCIEX_ECRC, PCIE_AER_UCE_ECRC, NULL, DDI_FM_UNKNOWN, 10800d0963fSdilpreet PCIEX_CA, PCIE_AER_UCE_CA, NULL, DDI_FM_UNKNOWN, 109ac4d633fSstephh PCIEX_UR, PCIE_AER_UCE_UR, NULL, DDI_FM_UNKNOWN, 11000d0963fSdilpreet PCIEX_POIS, PCIE_AER_UCE_PTLP, NULL, DDI_FM_UNKNOWN, 11100d0963fSdilpreet NULL, NULL, NULL, NULL, 11200d0963fSdilpreet }; 11300d0963fSdilpreet 11400d0963fSdilpreet static pci_fm_err_t pcie_sue_err_tbl[] = { 11500d0963fSdilpreet PCIEX_S_TA_SC, PCIE_AER_SUCE_TA_ON_SC, NULL, DDI_FM_UNKNOWN, 11600d0963fSdilpreet PCIEX_S_MA_SC, PCIE_AER_SUCE_MA_ON_SC, NULL, DDI_FM_UNKNOWN, 11700d0963fSdilpreet PCIEX_S_RTA, PCIE_AER_SUCE_RCVD_TA, NULL, DDI_FM_UNKNOWN, 118*8aec9182Sstephh #if defined(__sparc) 11900d0963fSdilpreet PCIEX_S_RMA, PCIE_AER_SUCE_RCVD_MA, NULL, DDI_FM_UNKNOWN, 1200c64a9b4Sanish #endif 12100d0963fSdilpreet PCIEX_S_USC, PCIE_AER_SUCE_USC_ERR, NULL, DDI_FM_UNKNOWN, 12200d0963fSdilpreet PCIEX_S_USCMD, PCIE_AER_SUCE_USC_MSG_DATA_ERR, NULL, DDI_FM_FATAL, 12300d0963fSdilpreet PCIEX_S_UDE, PCIE_AER_SUCE_UC_DATA_ERR, NULL, DDI_FM_UNKNOWN, 12400d0963fSdilpreet PCIEX_S_UAT, PCIE_AER_SUCE_UC_ATTR_ERR, NULL, DDI_FM_FATAL, 12500d0963fSdilpreet PCIEX_S_UADR, PCIE_AER_SUCE_UC_ADDR_ERR, NULL, DDI_FM_FATAL, 12600d0963fSdilpreet PCIEX_S_TEX, PCIE_AER_SUCE_TIMER_EXPIRED, NULL, DDI_FM_FATAL, 12700d0963fSdilpreet PCIEX_S_PERR, PCIE_AER_SUCE_PERR_ASSERT, NULL, DDI_FM_UNKNOWN, 12800d0963fSdilpreet PCIEX_S_SERR, PCIE_AER_SUCE_SERR_ASSERT, NULL, DDI_FM_FATAL, 12900d0963fSdilpreet PCIEX_INTERR, PCIE_AER_SUCE_INTERNAL_ERR, NULL, DDI_FM_FATAL, 13000d0963fSdilpreet NULL, NULL, NULL, NULL, 13100d0963fSdilpreet }; 13200d0963fSdilpreet 13300d0963fSdilpreet static pci_fm_err_t pcix_err_tbl[] = { 13400d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 13500d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 13600d0963fSdilpreet PCIX_RX_SPL_MSG, PCI_PCIX_RX_SPL_MSG, NULL, DDI_FM_UNKNOWN, 13700d0963fSdilpreet NULL, NULL, NULL, NULL, 13800d0963fSdilpreet }; 13900d0963fSdilpreet 14000d0963fSdilpreet static pci_fm_err_t pcix_sec_err_tbl[] = { 14100d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_BSS_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 14200d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_BSS_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 143ac4d633fSstephh PCIX_BSS_SPL_OR, PCI_PCIX_BSS_SPL_OR, NULL, DDI_FM_OK, 144ac4d633fSstephh PCIX_BSS_SPL_DLY, PCI_PCIX_BSS_SPL_DLY, NULL, DDI_FM_OK, 14500d0963fSdilpreet NULL, NULL, NULL, NULL, 14600d0963fSdilpreet }; 14700d0963fSdilpreet 14800d0963fSdilpreet static pci_fm_err_t pciex_nadv_err_tbl[] = { 14900d0963fSdilpreet PCIEX_UR, PCIE_DEVSTS_UR_DETECTED, NULL, DDI_FM_UNKNOWN, 15000d0963fSdilpreet PCIEX_FAT, PCIE_DEVSTS_FE_DETECTED, NULL, DDI_FM_FATAL, 15100d0963fSdilpreet PCIEX_NONFAT, PCIE_DEVSTS_NFE_DETECTED, NULL, DDI_FM_UNKNOWN, 152ac4d633fSstephh PCIEX_CORR, PCIE_DEVSTS_CE_DETECTED, NULL, DDI_FM_OK, 15300d0963fSdilpreet NULL, NULL, NULL, NULL, 15400d0963fSdilpreet }; 15500d0963fSdilpreet 15600d0963fSdilpreet static int 157*8aec9182Sstephh pci_config_check(ddi_acc_handle_t handle, int fme_flag) 15800d0963fSdilpreet { 15900d0963fSdilpreet ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle); 16000d0963fSdilpreet ddi_fm_error_t de; 16100d0963fSdilpreet 16200d0963fSdilpreet if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip)))) 16300d0963fSdilpreet return (DDI_FM_OK); 16400d0963fSdilpreet 16500d0963fSdilpreet de.fme_version = DDI_FME_VERSION; 16600d0963fSdilpreet 16700d0963fSdilpreet ddi_fm_acc_err_get(handle, &de, de.fme_version); 16800d0963fSdilpreet if (de.fme_status != DDI_FM_OK) { 169*8aec9182Sstephh if (fme_flag == DDI_FM_ERR_UNEXPECTED) { 17000d0963fSdilpreet char buf[FM_MAX_CLASS]; 17100d0963fSdilpreet 172*8aec9182Sstephh (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 173*8aec9182Sstephh PCI_ERROR_SUBCLASS, PCI_NR); 174*8aec9182Sstephh ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena, 175*8aec9182Sstephh DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 176*8aec9182Sstephh } 17700d0963fSdilpreet ddi_fm_acc_err_clear(handle, de.fme_version); 17800d0963fSdilpreet } 17900d0963fSdilpreet return (de.fme_status); 18000d0963fSdilpreet } 18100d0963fSdilpreet 18200d0963fSdilpreet static void 18300d0963fSdilpreet pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs, 184*8aec9182Sstephh uint8_t pcix_cap_ptr, int fme_flag) 18500d0963fSdilpreet { 18600d0963fSdilpreet int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV; 18700d0963fSdilpreet 18800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl, 18900d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS : 19000d0963fSdilpreet PCI_PCIX_ECC_STATUS))); 191*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 19200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID; 19300d0963fSdilpreet else 19400d0963fSdilpreet return; 19500d0963fSdilpreet pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl, 19600d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD : 19700d0963fSdilpreet PCI_PCIX_ECC_FST_AD))); 19800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl, 19900d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD : 20000d0963fSdilpreet PCI_PCIX_ECC_SEC_AD))); 20100d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr = pci_config_get32(( 20200d0963fSdilpreet ddi_acc_handle_t)erpt_p->pe_hdl, 20300d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR))); 20400d0963fSdilpreet } 20500d0963fSdilpreet 20600d0963fSdilpreet static void 207*8aec9182Sstephh pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs, int fme_flag) 20800d0963fSdilpreet { 20900d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 21000d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 21100d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 21200d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 21300d0963fSdilpreet int i; 21400d0963fSdilpreet 21500d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 21600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16( 21700d0963fSdilpreet erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS)); 218*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 21900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= 22000d0963fSdilpreet PCIX_BDG_SEC_STATUS_VALID; 22100d0963fSdilpreet else 22200d0963fSdilpreet return; 22300d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl, 22400d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS)); 225*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 22600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID; 22700d0963fSdilpreet else 22800d0963fSdilpreet return; 22900d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 23000d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 23100d0963fSdilpreet /* 23200d0963fSdilpreet * PCI Express to PCI-X bridges only implement the 23300d0963fSdilpreet * secondary side of the PCI-X ECC registers, bit one is 23400d0963fSdilpreet * read-only so we make sure we do not write to it. 23500d0963fSdilpreet */ 23600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 23700d0963fSdilpreet pcix_bdg_ecc_regs = 23800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[1]; 23900d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_bdg_ecc_regs, 240*8aec9182Sstephh pcix_bdg_cap_ptr, fme_flag); 24100d0963fSdilpreet } else { 24200d0963fSdilpreet for (i = 0; i < 2; i++) { 24300d0963fSdilpreet pcix_bdg_ecc_regs = 24400d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 24500d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 24600d0963fSdilpreet (pcix_bdg_cap_ptr + 24700d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), i); 24800d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, 24900d0963fSdilpreet pcix_bdg_ecc_regs, 250*8aec9182Sstephh pcix_bdg_cap_ptr, fme_flag); 25100d0963fSdilpreet } 25200d0963fSdilpreet } 25300d0963fSdilpreet } 25400d0963fSdilpreet } else { 25500d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 25600d0963fSdilpreet uint8_t pcix_cap_ptr; 25700d0963fSdilpreet 25800d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 25900d0963fSdilpreet 26000d0963fSdilpreet pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl, 26100d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_COMMAND)); 26200d0963fSdilpreet pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl, 26300d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS)); 264*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 26500d0963fSdilpreet pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID; 26600d0963fSdilpreet else 26700d0963fSdilpreet return; 26800d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 26900d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 27000d0963fSdilpreet pcix_regs->pcix_ecc_regs; 27100d0963fSdilpreet 27200d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs, 273*8aec9182Sstephh pcix_cap_ptr, fme_flag); 27400d0963fSdilpreet } 27500d0963fSdilpreet } 27600d0963fSdilpreet } 27700d0963fSdilpreet 27800d0963fSdilpreet static void 279*8aec9182Sstephh pcie_regs_gather(pci_erpt_t *erpt_p, int fme_flag) 28000d0963fSdilpreet { 28100d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 28200d0963fSdilpreet uint8_t pcie_cap_ptr; 28300d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 28400d0963fSdilpreet uint16_t pcie_ecap_ptr; 28500d0963fSdilpreet 28600d0963fSdilpreet pcie_cap_ptr = pcie_regs->pcie_cap_ptr; 28700d0963fSdilpreet 28800d0963fSdilpreet pcie_regs->pcie_err_status = pci_config_get16(erpt_p->pe_hdl, 28900d0963fSdilpreet pcie_cap_ptr + PCIE_DEVSTS); 290*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 29100d0963fSdilpreet pcie_regs->pcie_vflags |= PCIE_ERR_STATUS_VALID; 29200d0963fSdilpreet else 29300d0963fSdilpreet return; 29400d0963fSdilpreet 29500d0963fSdilpreet pcie_regs->pcie_err_ctl = pci_config_get16(erpt_p->pe_hdl, 29600d0963fSdilpreet (pcie_cap_ptr + PCIE_DEVCTL)); 297*8aec9182Sstephh pcie_regs->pcie_dev_cap = pci_config_get16(erpt_p->pe_hdl, 298*8aec9182Sstephh (pcie_cap_ptr + PCIE_DEVCAP)); 29900d0963fSdilpreet 30000d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && (erpt_p->pe_dflags & 30100d0963fSdilpreet PCIX_DEV)) 302*8aec9182Sstephh pcix_regs_gather(erpt_p, pcie_regs->pcix_bdg_regs, fme_flag); 30300d0963fSdilpreet 30400d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 30500d0963fSdilpreet pcie_rc_error_regs_t *pcie_rc_regs = pcie_regs->pcie_rc_regs; 30600d0963fSdilpreet 30700d0963fSdilpreet pcie_rc_regs->pcie_rc_status = pci_config_get32(erpt_p->pe_hdl, 30800d0963fSdilpreet (pcie_cap_ptr + PCIE_ROOTSTS)); 30900d0963fSdilpreet pcie_rc_regs->pcie_rc_ctl = pci_config_get16(erpt_p->pe_hdl, 31000d0963fSdilpreet (pcie_cap_ptr + PCIE_ROOTCTL)); 31100d0963fSdilpreet } 31200d0963fSdilpreet 31300d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) 31400d0963fSdilpreet return; 31500d0963fSdilpreet 31600d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 31700d0963fSdilpreet 31800d0963fSdilpreet pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr; 31900d0963fSdilpreet 32000d0963fSdilpreet pcie_adv_regs->pcie_ue_status = pci_config_get32(erpt_p->pe_hdl, 32100d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_STS); 322*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 32300d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_STATUS_VALID; 32400d0963fSdilpreet 32500d0963fSdilpreet pcie_adv_regs->pcie_ue_mask = pci_config_get32(erpt_p->pe_hdl, 32600d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_MASK); 32700d0963fSdilpreet pcie_adv_regs->pcie_ue_sev = pci_config_get32(erpt_p->pe_hdl, 32800d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_SERV); 32900d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl = pci_config_get32(erpt_p->pe_hdl, 33000d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CTL); 33100d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0 = pci_config_get32(erpt_p->pe_hdl, 33200d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_HDR_LOG); 333*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) { 33400d0963fSdilpreet int i; 33500d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_HDR_VALID; 33600d0963fSdilpreet 33700d0963fSdilpreet for (i = 0; i < 3; i++) { 33800d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[i] = pci_config_get32( 33900d0963fSdilpreet erpt_p->pe_hdl, pcie_ecap_ptr + PCIE_AER_HDR_LOG + 34000d0963fSdilpreet (4 * (i + 1))); 34100d0963fSdilpreet } 34200d0963fSdilpreet } 34300d0963fSdilpreet 34400d0963fSdilpreet pcie_adv_regs->pcie_ce_status = pci_config_get32(erpt_p->pe_hdl, 34500d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_STS); 346*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 34700d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_CE_STATUS_VALID; 34800d0963fSdilpreet 34900d0963fSdilpreet pcie_adv_regs->pcie_ce_mask = pci_config_get32(erpt_p->pe_hdl, 35000d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_MASK); 35100d0963fSdilpreet 35200d0963fSdilpreet /* 35300d0963fSdilpreet * If pci express to pci bridge then grab the bridge 35400d0963fSdilpreet * error registers. 35500d0963fSdilpreet */ 35600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 35700d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 35800d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 35900d0963fSdilpreet 36000d0963fSdilpreet pcie_bdg_regs->pcie_sue_status = 36100d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 36200d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_STS); 363*8aec9182Sstephh pcie_bdg_regs->pcie_sue_mask = 364*8aec9182Sstephh pci_config_get32(erpt_p->pe_hdl, 365*8aec9182Sstephh pcie_ecap_ptr + PCIE_AER_SUCE_MASK); 366*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 36700d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_STATUS_VALID; 36800d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0 = pci_config_get32(erpt_p->pe_hdl, 36900d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_SHDR_LOG)); 37000d0963fSdilpreet 371*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) { 37200d0963fSdilpreet int i; 37300d0963fSdilpreet 37400d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_HDR_VALID; 37500d0963fSdilpreet 37600d0963fSdilpreet for (i = 0; i < 3; i++) { 37700d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[i] = 37800d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 37900d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SHDR_LOG + 38000d0963fSdilpreet (4 * (i + 1))); 38100d0963fSdilpreet } 38200d0963fSdilpreet } 38300d0963fSdilpreet } 38400d0963fSdilpreet /* 38500d0963fSdilpreet * If PCI Express root complex then grab the root complex 38600d0963fSdilpreet * error registers. 38700d0963fSdilpreet */ 38800d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 38900d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 39000d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 39100d0963fSdilpreet 39200d0963fSdilpreet pcie_rc_regs->pcie_rc_err_cmd = pci_config_get32(erpt_p->pe_hdl, 39300d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_CMD)); 39400d0963fSdilpreet pcie_rc_regs->pcie_rc_err_status = 39500d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 39600d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_STS)); 397*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 39800d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= 39900d0963fSdilpreet PCIE_RC_ERR_STATUS_VALID; 40000d0963fSdilpreet pcie_rc_regs->pcie_rc_ce_src_id = 40100d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 40200d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_CE_SRC_ID)); 40300d0963fSdilpreet pcie_rc_regs->pcie_rc_ue_src_id = 40400d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 40500d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_ERR_SRC_ID)); 406*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 40700d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SRC_ID_VALID; 40800d0963fSdilpreet } 40900d0963fSdilpreet } 41000d0963fSdilpreet 41100d0963fSdilpreet /*ARGSUSED*/ 41200d0963fSdilpreet static void 413*8aec9182Sstephh pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p, int fme_flag) 41400d0963fSdilpreet { 41500d0963fSdilpreet pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs; 41600d0963fSdilpreet 41700d0963fSdilpreet /* 41800d0963fSdilpreet * Start by reading all the error registers that are available for 41900d0963fSdilpreet * pci and pci express and for leaf devices and bridges/switches 42000d0963fSdilpreet */ 42100d0963fSdilpreet pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl, 42200d0963fSdilpreet PCI_CONF_STAT); 423*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK) 42400d0963fSdilpreet return; 42500d0963fSdilpreet pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID; 42600d0963fSdilpreet pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl, 42700d0963fSdilpreet PCI_CONF_COMM); 428*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK) 42900d0963fSdilpreet return; 43000d0963fSdilpreet 43100d0963fSdilpreet /* 43200d0963fSdilpreet * If pci-pci bridge grab PCI bridge specific error registers. 43300d0963fSdilpreet */ 43400d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 43500d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_sec_stat = 43600d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS); 437*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 43800d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 43900d0963fSdilpreet PCI_BDG_SEC_STAT_VALID; 44000d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_ctrl = 44100d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL); 442*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 44300d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 44400d0963fSdilpreet PCI_BDG_CTRL_VALID; 44500d0963fSdilpreet } 44600d0963fSdilpreet 44700d0963fSdilpreet /* 44800d0963fSdilpreet * If pci express device grab pci express error registers and 44900d0963fSdilpreet * check for advanced error reporting features and grab them if 45000d0963fSdilpreet * available. 45100d0963fSdilpreet */ 45200d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 453*8aec9182Sstephh pcie_regs_gather(erpt_p, fme_flag); 45400d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 455*8aec9182Sstephh pcix_regs_gather(erpt_p, erpt_p->pe_regs, fme_flag); 45600d0963fSdilpreet 45700d0963fSdilpreet } 45800d0963fSdilpreet 45900d0963fSdilpreet static void 46000d0963fSdilpreet pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs) 46100d0963fSdilpreet { 46200d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 46300d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 46400d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 46500d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 46600d0963fSdilpreet int i; 46700d0963fSdilpreet 46800d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 46900d0963fSdilpreet 47000d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) 47100d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, 47200d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS), 47300d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat); 47400d0963fSdilpreet 47500d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) 47600d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 47700d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS), 47800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat); 47900d0963fSdilpreet 48000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags = 0x0; 48100d0963fSdilpreet 48200d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 48300d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 48400d0963fSdilpreet /* 48500d0963fSdilpreet * PCI Express to PCI-X bridges only implement the 48600d0963fSdilpreet * secondary side of the PCI-X ECC registers, bit one is 48700d0963fSdilpreet * read-only so we make sure we do not write to it. 48800d0963fSdilpreet */ 48900d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 49000d0963fSdilpreet pcix_bdg_ecc_regs = 49100d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[1]; 49200d0963fSdilpreet 49300d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 49400d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 49500d0963fSdilpreet 49600d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 49700d0963fSdilpreet (pcix_bdg_cap_ptr + 49800d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 49900d0963fSdilpreet pcix_bdg_ecc_regs-> 50000d0963fSdilpreet pcix_ecc_ctlstat); 50100d0963fSdilpreet } 50200d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 0x0; 50300d0963fSdilpreet } else { 50400d0963fSdilpreet for (i = 0; i < 2; i++) { 50500d0963fSdilpreet pcix_bdg_ecc_regs = 50600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 50700d0963fSdilpreet 50800d0963fSdilpreet 50900d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 51000d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 51100d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 51200d0963fSdilpreet (pcix_bdg_cap_ptr + 51300d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 51400d0963fSdilpreet i); 51500d0963fSdilpreet 51600d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 51700d0963fSdilpreet (pcix_bdg_cap_ptr + 51800d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 51900d0963fSdilpreet pcix_bdg_ecc_regs-> 52000d0963fSdilpreet pcix_ecc_ctlstat); 52100d0963fSdilpreet } 52200d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 52300d0963fSdilpreet 0x0; 52400d0963fSdilpreet } 52500d0963fSdilpreet } 52600d0963fSdilpreet } 52700d0963fSdilpreet } else { 52800d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 52900d0963fSdilpreet uint8_t pcix_cap_ptr; 53000d0963fSdilpreet 53100d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 53200d0963fSdilpreet 53300d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) 53400d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 53500d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS), 53600d0963fSdilpreet pcix_regs->pcix_status); 53700d0963fSdilpreet 53800d0963fSdilpreet pcix_regs->pcix_vflags = 0x0; 53900d0963fSdilpreet 54000d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 54100d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 54200d0963fSdilpreet pcix_regs->pcix_ecc_regs; 54300d0963fSdilpreet 54400d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & 54500d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) 54600d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 54700d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_ECC_STATUS), 54800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat); 54900d0963fSdilpreet 55000d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags = 0x0; 55100d0963fSdilpreet } 55200d0963fSdilpreet } 55300d0963fSdilpreet } 55400d0963fSdilpreet 55500d0963fSdilpreet static void 55600d0963fSdilpreet pcie_regs_clear(pci_erpt_t *erpt_p) 55700d0963fSdilpreet { 55800d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 55900d0963fSdilpreet uint8_t pcie_cap_ptr; 56000d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 56100d0963fSdilpreet uint16_t pcie_ecap_ptr; 56200d0963fSdilpreet 56300d0963fSdilpreet pcie_cap_ptr = pcie_regs->pcie_cap_ptr; 56400d0963fSdilpreet 56500d0963fSdilpreet if (pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) 56600d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, pcie_cap_ptr + PCIE_DEVSTS, 56700d0963fSdilpreet pcie_regs->pcie_err_status); 56800d0963fSdilpreet 56900d0963fSdilpreet pcie_regs->pcie_vflags = 0x0; 57000d0963fSdilpreet 57100d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 57200d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) 57300d0963fSdilpreet pcix_regs_clear(erpt_p, pcie_regs->pcix_bdg_regs); 57400d0963fSdilpreet 57500d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) 57600d0963fSdilpreet return; 57700d0963fSdilpreet 57800d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 57900d0963fSdilpreet 58000d0963fSdilpreet pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr; 58100d0963fSdilpreet 58200d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) 58300d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 58400d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_STS, 58500d0963fSdilpreet pcie_adv_regs->pcie_ue_status); 58600d0963fSdilpreet 58700d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) 58800d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 58900d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_STS, 59000d0963fSdilpreet pcie_adv_regs->pcie_ce_status); 59100d0963fSdilpreet 59200d0963fSdilpreet 59300d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 59400d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 59500d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 59600d0963fSdilpreet 59700d0963fSdilpreet 59800d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID) 59900d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 60000d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_STS, 60100d0963fSdilpreet pcie_bdg_regs->pcie_sue_status); 60200d0963fSdilpreet } 60300d0963fSdilpreet /* 60400d0963fSdilpreet * If PCI Express root complex then clear the root complex 60500d0963fSdilpreet * error registers. 60600d0963fSdilpreet */ 60700d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 60800d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 60900d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 61000d0963fSdilpreet 61100d0963fSdilpreet 61200d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) 61300d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 61400d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_STS), 61500d0963fSdilpreet pcie_rc_regs->pcie_rc_err_status); 61600d0963fSdilpreet } 61700d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags = 0x0; 61800d0963fSdilpreet } 61900d0963fSdilpreet 62000d0963fSdilpreet static void 62100d0963fSdilpreet pci_regs_clear(pci_erpt_t *erpt_p) 62200d0963fSdilpreet { 62300d0963fSdilpreet /* 62400d0963fSdilpreet * Finally clear the error bits 62500d0963fSdilpreet */ 62600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 62700d0963fSdilpreet pcie_regs_clear(erpt_p); 62800d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 62900d0963fSdilpreet pcix_regs_clear(erpt_p, erpt_p->pe_regs); 63000d0963fSdilpreet 63100d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID) 63200d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT, 63300d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status); 63400d0963fSdilpreet 63500d0963fSdilpreet erpt_p->pe_pci_regs->pci_vflags = 0x0; 63600d0963fSdilpreet 63700d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 63800d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 63900d0963fSdilpreet PCI_BDG_SEC_STAT_VALID) 64000d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS, 64100d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs-> 64200d0963fSdilpreet pci_bdg_sec_stat); 64300d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 64400d0963fSdilpreet PCI_BDG_CTRL_VALID) 64500d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL, 64600d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl); 64700d0963fSdilpreet 64800d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0; 64900d0963fSdilpreet } 65000d0963fSdilpreet } 65100d0963fSdilpreet 65200d0963fSdilpreet /* 65300d0963fSdilpreet * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport 65400d0963fSdilpreet * generation. 65500d0963fSdilpreet */ 65600d0963fSdilpreet /* ARGSUSED */ 65700d0963fSdilpreet static void 65800d0963fSdilpreet pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 65900d0963fSdilpreet { 66000d0963fSdilpreet uint8_t pcix_cap_ptr; 66100d0963fSdilpreet int i; 66200d0963fSdilpreet 66300d0963fSdilpreet pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 66400d0963fSdilpreet "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 66500d0963fSdilpreet 66600d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 66700d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 66800d0963fSdilpreet else 66900d0963fSdilpreet return; 67000d0963fSdilpreet 67100d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 67200d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 67300d0963fSdilpreet 67400d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t), 67500d0963fSdilpreet KM_SLEEP); 67600d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 67700d0963fSdilpreet pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 67800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl, 67900d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 68000d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 68100d0963fSdilpreet for (i = 0; i < 2; i++) { 68200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 68300d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 68400d0963fSdilpreet KM_SLEEP); 68500d0963fSdilpreet } 68600d0963fSdilpreet } 68700d0963fSdilpreet } else { 68800d0963fSdilpreet pcix_error_regs_t *pcix_regs; 68900d0963fSdilpreet 69000d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t), 69100d0963fSdilpreet KM_SLEEP); 69200d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 69300d0963fSdilpreet pcix_regs->pcix_cap_ptr = pcix_cap_ptr; 69400d0963fSdilpreet pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl, 69500d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 69600d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 69700d0963fSdilpreet pcix_regs->pcix_ecc_regs = kmem_zalloc( 69800d0963fSdilpreet sizeof (pcix_ecc_regs_t), KM_SLEEP); 69900d0963fSdilpreet } 70000d0963fSdilpreet } 70100d0963fSdilpreet } 70200d0963fSdilpreet 70300d0963fSdilpreet static void 70400d0963fSdilpreet pcie_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 70500d0963fSdilpreet { 70600d0963fSdilpreet pcie_error_regs_t *pcie_regs; 70700d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 70800d0963fSdilpreet uint8_t pcix_cap_ptr; 70900d0963fSdilpreet uint8_t pcie_cap_ptr; 71000d0963fSdilpreet uint16_t pcie_ecap_ptr; 71100d0963fSdilpreet uint16_t dev_type = 0; 71200d0963fSdilpreet uint32_t mask = pcie_expected_ue_mask; 71300d0963fSdilpreet 71400d0963fSdilpreet /* 71500d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 71600d0963fSdilpreet * interfaces create the necessary properties for us. 71700d0963fSdilpreet */ 71800d0963fSdilpreet #if defined(__sparc) 71900d0963fSdilpreet ushort_t status; 72000d0963fSdilpreet uint32_t slot_cap; 72100d0963fSdilpreet uint8_t cap_ptr = 0; 72200d0963fSdilpreet uint8_t cap_id = 0; 72300d0963fSdilpreet uint32_t hdr, hdr_next_ptr, hdr_cap_id; 72400d0963fSdilpreet uint16_t offset = P2ALIGN(PCIE_EXT_CAP, 4); 72500d0963fSdilpreet uint16_t aer_ptr = 0; 72600d0963fSdilpreet 72700d0963fSdilpreet cap_ptr = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_CAP_PTR); 728*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) == 729*8aec9182Sstephh DDI_FM_OK) { 73000d0963fSdilpreet while ((cap_id = pci_config_get8(erpt_p->pe_hdl, cap_ptr)) != 73100d0963fSdilpreet 0xff) { 73200d0963fSdilpreet if (cap_id == PCI_CAP_ID_PCIX) { 73300d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 73400d0963fSdilpreet "pcix-capid-pointer", cap_ptr); 73500d0963fSdilpreet } 73600d0963fSdilpreet if (cap_id == PCI_CAP_ID_PCI_E) { 73700d0963fSdilpreet status = pci_config_get16(erpt_p->pe_hdl, cap_ptr + 2); 73800d0963fSdilpreet if (status & PCIE_PCIECAP_SLOT_IMPL) { 73900d0963fSdilpreet /* offset 14h is Slot Cap Register */ 74000d0963fSdilpreet slot_cap = pci_config_get32(erpt_p->pe_hdl, 74100d0963fSdilpreet cap_ptr + PCIE_SLOTCAP); 74200d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 74300d0963fSdilpreet "pcie-slotcap-reg", slot_cap); 74400d0963fSdilpreet } 74500d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 74600d0963fSdilpreet "pcie-capid-reg", pci_config_get16(erpt_p->pe_hdl, 74700d0963fSdilpreet cap_ptr + PCIE_PCIECAP)); 74800d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 74900d0963fSdilpreet "pcie-capid-pointer", cap_ptr); 75000d0963fSdilpreet 75100d0963fSdilpreet } 75200d0963fSdilpreet if ((cap_ptr = pci_config_get8(erpt_p->pe_hdl, 75300d0963fSdilpreet cap_ptr + 1)) == 0xff || cap_ptr == 0 || 754*8aec9182Sstephh (pci_config_check(erpt_p->pe_hdl, 755*8aec9182Sstephh DDI_FM_ERR_UNEXPECTED) != DDI_FM_OK)) 75600d0963fSdilpreet break; 75700d0963fSdilpreet } 75800d0963fSdilpreet } 75900d0963fSdilpreet 76000d0963fSdilpreet #endif 76100d0963fSdilpreet 76200d0963fSdilpreet pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 76300d0963fSdilpreet "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 76400d0963fSdilpreet 76500d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 76600d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 76700d0963fSdilpreet 76800d0963fSdilpreet pcie_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 76900d0963fSdilpreet DDI_PROP_DONTPASS, "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 77000d0963fSdilpreet 77100d0963fSdilpreet if (pcie_cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 77200d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_DEV; 77300d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcie_error_regs_t), 77400d0963fSdilpreet KM_SLEEP); 77500d0963fSdilpreet pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 77600d0963fSdilpreet pcie_regs->pcie_cap_ptr = pcie_cap_ptr; 77700d0963fSdilpreet } 77800d0963fSdilpreet 77900d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) 78000d0963fSdilpreet return; 78100d0963fSdilpreet 78200d0963fSdilpreet /* 78300d0963fSdilpreet * Don't currently need to check for version here because we are 78400d0963fSdilpreet * compliant with PCIE 1.0a which is version 0 and is guaranteed 78500d0963fSdilpreet * software compatibility with future versions. We will need to 78600d0963fSdilpreet * add errors for new detectors/features which are added in newer 78700d0963fSdilpreet * revisions [sec 7.8.2]. 78800d0963fSdilpreet */ 78900d0963fSdilpreet pcie_regs->pcie_cap = pci_config_get16(erpt_p->pe_hdl, 79000d0963fSdilpreet pcie_regs->pcie_cap_ptr + PCIE_PCIECAP); 79100d0963fSdilpreet 79200d0963fSdilpreet dev_type = pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK; 79300d0963fSdilpreet 79400d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 79500d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 79600d0963fSdilpreet int i; 79700d0963fSdilpreet 79800d0963fSdilpreet pcie_regs->pcix_bdg_regs = 79900d0963fSdilpreet kmem_zalloc(sizeof (pcix_bdg_error_regs_t), KM_SLEEP); 80000d0963fSdilpreet 80100d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 80200d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_ver = 80300d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 80400d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 80500d0963fSdilpreet 80600d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcie_regs->pcix_bdg_regs->pcix_bdg_ver)) 80700d0963fSdilpreet for (i = 0; i < 2; i++) 80800d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 80900d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 81000d0963fSdilpreet KM_SLEEP); 81100d0963fSdilpreet } 81200d0963fSdilpreet 81300d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) { 81400d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_RC_DEV; 81500d0963fSdilpreet pcie_regs->pcie_rc_regs = kmem_zalloc( 81600d0963fSdilpreet sizeof (pcie_rc_error_regs_t), KM_SLEEP); 81700d0963fSdilpreet } 81800d0963fSdilpreet /* 81900d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 82000d0963fSdilpreet * interfaces create the necessary properties for us. 82100d0963fSdilpreet */ 82200d0963fSdilpreet #if defined(__sparc) 82300d0963fSdilpreet 82400d0963fSdilpreet hdr = pci_config_get32(erpt_p->pe_hdl, offset); 82500d0963fSdilpreet hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 82600d0963fSdilpreet PCIE_EXT_CAP_NEXT_PTR_MASK; 82700d0963fSdilpreet hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK; 82800d0963fSdilpreet 82900d0963fSdilpreet while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) && 83000d0963fSdilpreet (hdr_cap_id != PCIE_EXT_CAP_ID_AER)) { 83100d0963fSdilpreet offset = P2ALIGN(hdr_next_ptr, 4); 83200d0963fSdilpreet hdr = pci_config_get32(erpt_p->pe_hdl, offset); 83300d0963fSdilpreet hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 83400d0963fSdilpreet PCIE_EXT_CAP_NEXT_PTR_MASK; 83500d0963fSdilpreet hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & 83600d0963fSdilpreet PCIE_EXT_CAP_ID_MASK; 83700d0963fSdilpreet } 83800d0963fSdilpreet 83900d0963fSdilpreet if (hdr_cap_id == PCIE_EXT_CAP_ID_AER) 84000d0963fSdilpreet aer_ptr = P2ALIGN(offset, 4); 84100d0963fSdilpreet if (aer_ptr != PCI_CAP_NEXT_PTR_NULL) 84200d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 84300d0963fSdilpreet "pcie-aer-pointer", aer_ptr); 84400d0963fSdilpreet #endif 84500d0963fSdilpreet 84600d0963fSdilpreet /* 84700d0963fSdilpreet * Find and store if this device is capable of pci express 84800d0963fSdilpreet * advanced errors, if not report an error against the device. 84900d0963fSdilpreet */ 85000d0963fSdilpreet pcie_ecap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 85100d0963fSdilpreet "pcie-aer-pointer", PCI_CAP_NEXT_PTR_NULL); 85200d0963fSdilpreet if (pcie_ecap_ptr != PCI_CAP_NEXT_PTR_NULL) { 85300d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_ADV_DEV; 85400d0963fSdilpreet pcie_regs->pcie_adv_regs = kmem_zalloc( 85500d0963fSdilpreet sizeof (pcie_adv_error_regs_t), KM_SLEEP); 85600d0963fSdilpreet pcie_regs->pcie_adv_regs->pcie_adv_cap_ptr = pcie_ecap_ptr; 85700d0963fSdilpreet } 85800d0963fSdilpreet 85900d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 86000d0963fSdilpreet return; 86100d0963fSdilpreet } 86200d0963fSdilpreet 86300d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 86400d0963fSdilpreet 86500d0963fSdilpreet if (pcie_adv_regs == NULL) 86600d0963fSdilpreet return; 86700d0963fSdilpreet /* 86800d0963fSdilpreet * Initialize structures for advanced PCI Express devices. 86900d0963fSdilpreet */ 87000d0963fSdilpreet 87100d0963fSdilpreet /* 87200d0963fSdilpreet * Advanced error registers exist for PCI Express to PCI(X) Bridges and 87300d0963fSdilpreet * may also exist for PCI(X) to PCI Express Bridges, the latter is not 87400d0963fSdilpreet * well explained in the PCI Express to PCI/PCI-X Bridge Specification 87500d0963fSdilpreet * 1.0 and will be left out of the current gathering of these registers. 87600d0963fSdilpreet */ 87700d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) { 87800d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_2PCI_DEV; 87900d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs = kmem_zalloc( 88000d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t), KM_SLEEP); 88100d0963fSdilpreet } 88200d0963fSdilpreet 88300d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 88400d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs = kmem_zalloc( 88500d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t), KM_SLEEP); 88600d0963fSdilpreet 88700d0963fSdilpreet /* 88800d0963fSdilpreet * Check that mask values are as expected, if not 88900d0963fSdilpreet * change them to what we desire. 89000d0963fSdilpreet */ 891*8aec9182Sstephh pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED); 89200d0963fSdilpreet pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 89300d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_ce_mask != pcie_expected_ce_mask) { 89400d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 89500d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_MASK, pcie_expected_ce_mask); 89600d0963fSdilpreet } 89700d0963fSdilpreet 89800d0963fSdilpreet /* Disable PTLP/ECRC (or mask these two) for Switches */ 89900d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_UP || 90000d0963fSdilpreet dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) 90100d0963fSdilpreet mask |= PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC; 90200d0963fSdilpreet 90300d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_ue_mask != mask) { 90400d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 90500d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_MASK, mask); 90600d0963fSdilpreet } 90700d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 90800d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_adv_bdg_regs->pcie_sue_mask 90900d0963fSdilpreet != pcie_expected_sue_mask) { 91000d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 91100d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_MASK, 91200d0963fSdilpreet pcie_expected_sue_mask); 91300d0963fSdilpreet } 91400d0963fSdilpreet } 91500d0963fSdilpreet } 91600d0963fSdilpreet 91700d0963fSdilpreet /* 91800d0963fSdilpreet * pci_ereport_setup: Detect PCI device type and initialize structures to be 91900d0963fSdilpreet * used to generate ereports based on detected generic device errors. 92000d0963fSdilpreet */ 92100d0963fSdilpreet void 92200d0963fSdilpreet pci_ereport_setup(dev_info_t *dip) 92300d0963fSdilpreet { 92400d0963fSdilpreet struct dev_info *devi = DEVI(dip); 92500d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl; 92600d0963fSdilpreet pci_erpt_t *erpt_p; 92700d0963fSdilpreet uint8_t pci_hdr_type; 92800d0963fSdilpreet uint16_t pci_status; 92900d0963fSdilpreet pci_regspec_t *pci_rp; 93000d0963fSdilpreet int32_t len; 93100d0963fSdilpreet uint32_t phys_hi; 93200d0963fSdilpreet 93300d0963fSdilpreet /* 93400d0963fSdilpreet * If device is not ereport capbable then report an error against the 93500d0963fSdilpreet * driver for using this interface, 93600d0963fSdilpreet */ 93700d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 93800d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 93900d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 94000d0963fSdilpreet return; 94100d0963fSdilpreet } 94200d0963fSdilpreet 94300d0963fSdilpreet /* 94400d0963fSdilpreet * ASSERT fmhdl exists and fh_bus_specific is NULL. 94500d0963fSdilpreet */ 94600d0963fSdilpreet ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL)); 94700d0963fSdilpreet 94800d0963fSdilpreet erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP); 94900d0963fSdilpreet 95000d0963fSdilpreet if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS) 95100d0963fSdilpreet goto error; 95200d0963fSdilpreet 95300d0963fSdilpreet erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP); 95400d0963fSdilpreet 95500d0963fSdilpreet pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT); 956*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) != 957*8aec9182Sstephh DDI_FM_OK) 95800d0963fSdilpreet goto error; 95900d0963fSdilpreet 96000d0963fSdilpreet /* 96100d0963fSdilpreet * Get header type and record if device is a bridge. 96200d0963fSdilpreet */ 96300d0963fSdilpreet pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER); 964*8aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) != 965*8aec9182Sstephh DDI_FM_OK) 96600d0963fSdilpreet goto error; 96700d0963fSdilpreet 96800d0963fSdilpreet /* 96900d0963fSdilpreet * Check to see if PCI device is a bridge, if so allocate pci bridge 97000d0963fSdilpreet * error register structure. 97100d0963fSdilpreet */ 97200d0963fSdilpreet if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 97300d0963fSdilpreet erpt_p->pe_dflags |= PCI_BRIDGE_DEV; 97400d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc( 97500d0963fSdilpreet sizeof (pci_bdg_error_regs_t), KM_SLEEP); 97600d0963fSdilpreet } 97700d0963fSdilpreet 97800d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 97900d0963fSdilpreet (caddr_t)&pci_rp, &len) == DDI_SUCCESS) { 98000d0963fSdilpreet phys_hi = pci_rp->pci_phys_hi; 98100d0963fSdilpreet kmem_free(pci_rp, len); 98200d0963fSdilpreet 98300d0963fSdilpreet erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >> 98400d0963fSdilpreet PCI_REG_FUNC_SHIFT); 98500d0963fSdilpreet } 98600d0963fSdilpreet 98700d0963fSdilpreet 98800d0963fSdilpreet if (!(pci_status & PCI_STAT_CAP)) { 98900d0963fSdilpreet goto done; 99000d0963fSdilpreet } 99100d0963fSdilpreet 99200d0963fSdilpreet /* 99300d0963fSdilpreet * Initialize structures for PCI Express and PCI-X devices. 99400d0963fSdilpreet * Order matters below and pcie_ereport_setup should preceed 99500d0963fSdilpreet * pcix_ereport_setup. 99600d0963fSdilpreet */ 99700d0963fSdilpreet pcie_ereport_setup(dip, erpt_p); 99800d0963fSdilpreet 99900d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) { 100000d0963fSdilpreet pcix_ereport_setup(dip, erpt_p); 100100d0963fSdilpreet } 100200d0963fSdilpreet 100300d0963fSdilpreet done: 1004*8aec9182Sstephh pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED); 100500d0963fSdilpreet pci_regs_clear(erpt_p); 100600d0963fSdilpreet 100700d0963fSdilpreet /* 100800d0963fSdilpreet * Before returning set fh_bus_specific to completed pci_erpt_t 100900d0963fSdilpreet * structure 101000d0963fSdilpreet */ 101100d0963fSdilpreet fmhdl->fh_bus_specific = (void *)erpt_p; 101200d0963fSdilpreet 101300d0963fSdilpreet return; 101400d0963fSdilpreet error: 101500d0963fSdilpreet if (erpt_p->pe_pci_regs) 101600d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 101700d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 101800d0963fSdilpreet erpt_p = NULL; 101900d0963fSdilpreet } 102000d0963fSdilpreet 102100d0963fSdilpreet static void 102200d0963fSdilpreet pcix_ereport_teardown(pci_erpt_t *erpt_p) 102300d0963fSdilpreet { 102400d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 102500d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 102600d0963fSdilpreet uint16_t pcix_ver; 102700d0963fSdilpreet 102800d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 102900d0963fSdilpreet pcix_ver = pcix_bdg_regs->pcix_bdg_ver; 103000d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 103100d0963fSdilpreet int i; 103200d0963fSdilpreet for (i = 0; i < 2; i++) 103300d0963fSdilpreet kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i], 103400d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 103500d0963fSdilpreet } 103600d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t)); 103700d0963fSdilpreet } else { 103800d0963fSdilpreet pcix_error_regs_t *pcix_regs; 103900d0963fSdilpreet uint16_t pcix_ver; 104000d0963fSdilpreet 104100d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 104200d0963fSdilpreet pcix_ver = pcix_regs->pcix_ver; 104300d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 104400d0963fSdilpreet kmem_free(pcix_regs->pcix_ecc_regs, 104500d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 104600d0963fSdilpreet } 104700d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t)); 104800d0963fSdilpreet } 104900d0963fSdilpreet } 105000d0963fSdilpreet 105100d0963fSdilpreet static void 105200d0963fSdilpreet pcie_ereport_teardown(pci_erpt_t *erpt_p) 105300d0963fSdilpreet { 105400d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 105500d0963fSdilpreet 105600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_ADV_DEV) { 105700d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv = pcie_regs->pcie_adv_regs; 105800d0963fSdilpreet 105900d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) 106000d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_bdg_regs, 106100d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t)); 106200d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 106300d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_rc_regs, 106400d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t)); 106500d0963fSdilpreet kmem_free(pcie_adv, sizeof (pcie_adv_error_regs_t)); 106600d0963fSdilpreet } 106700d0963fSdilpreet 106800d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 106900d0963fSdilpreet kmem_free(pcie_regs->pcie_rc_regs, 107000d0963fSdilpreet sizeof (pcie_rc_error_regs_t)); 107100d0963fSdilpreet 107200d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 107300d0963fSdilpreet if (erpt_p->pe_dflags & PCIX_DEV) { 107400d0963fSdilpreet uint16_t pcix_ver = pcie_regs->pcix_bdg_regs-> 107500d0963fSdilpreet pcix_bdg_ver; 107600d0963fSdilpreet 107700d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 107800d0963fSdilpreet int i; 107900d0963fSdilpreet for (i = 0; i < 2; i++) 108000d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs-> 108100d0963fSdilpreet pcix_bdg_ecc_regs[i], 108200d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 108300d0963fSdilpreet } 108400d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs, 108500d0963fSdilpreet sizeof (pcix_bdg_error_regs_t)); 108600d0963fSdilpreet } 108700d0963fSdilpreet } 108800d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcie_error_regs_t)); 108900d0963fSdilpreet } 109000d0963fSdilpreet 109100d0963fSdilpreet void 109200d0963fSdilpreet pci_ereport_teardown(dev_info_t *dip) 109300d0963fSdilpreet { 109400d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 109500d0963fSdilpreet pci_erpt_t *erpt_p; 109600d0963fSdilpreet 109700d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 109800d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 109900d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 110000d0963fSdilpreet } 110100d0963fSdilpreet 110200d0963fSdilpreet ASSERT(fmhdl); 110300d0963fSdilpreet 110400d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 110500d0963fSdilpreet if (erpt_p == NULL) 110600d0963fSdilpreet return; 110700d0963fSdilpreet 110800d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 110900d0963fSdilpreet pcie_ereport_teardown(erpt_p); 111000d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 111100d0963fSdilpreet pcix_ereport_teardown(erpt_p); 111200d0963fSdilpreet pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl); 111300d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) 111400d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs, 111500d0963fSdilpreet sizeof (pci_bdg_error_regs_t)); 111600d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 111700d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 111800d0963fSdilpreet fmhdl->fh_bus_specific = NULL; 111900d0963fSdilpreet /* 112000d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 112100d0963fSdilpreet * interfaces create the necessary properties for us. 112200d0963fSdilpreet */ 112300d0963fSdilpreet #if defined(__sparc) 112400d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcix-capid-pointer"); 112500d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-slotcap-reg"); 112600d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-reg"); 112700d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-pointer"); 112800d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-aer-pointer"); 112900d0963fSdilpreet #endif 113000d0963fSdilpreet } 113100d0963fSdilpreet 113200d0963fSdilpreet static void 113300d0963fSdilpreet pcie_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 113400d0963fSdilpreet char *buf, int errtype) 113500d0963fSdilpreet { 113600d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 113700d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 1138390e643aSdilpreet pcie_adv_rc_error_regs_t *pcie_adv_rc_regs; 113900d0963fSdilpreet 114000d0963fSdilpreet switch (errtype) { 114100d0963fSdilpreet case PCIEX_TYPE_CE: 114200d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 114300d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 114400d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 114500d0963fSdilpreet pcie_regs->pcie_err_status, 114600d0963fSdilpreet PCIEX_CE_STATUS_REG, DATA_TYPE_UINT32, 114700d0963fSdilpreet pcie_adv_regs->pcie_ce_status, NULL); 114800d0963fSdilpreet break; 114900d0963fSdilpreet case PCIEX_TYPE_UE: 115000d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 115100d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 115200d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 115300d0963fSdilpreet pcie_regs->pcie_err_status, 115400d0963fSdilpreet PCIEX_UE_STATUS_REG, DATA_TYPE_UINT32, 115500d0963fSdilpreet pcie_adv_regs->pcie_ue_status, PCIEX_UE_SEV_REG, 115600d0963fSdilpreet DATA_TYPE_UINT32, pcie_adv_regs->pcie_ue_sev, 115700d0963fSdilpreet PCIEX_ADV_CTL, DATA_TYPE_UINT32, 115800d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl, 115900d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 116000d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 116100d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 116200d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 116300d0963fSdilpreet 1 : NULL, 116400d0963fSdilpreet #ifdef DEBUG 116500d0963fSdilpreet PCIEX_UE_HDR0, DATA_TYPE_UINT32, 116600d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0, 116700d0963fSdilpreet PCIEX_UE_HDR1, DATA_TYPE_UINT32, 116800d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[0], 116900d0963fSdilpreet PCIEX_UE_HDR2, DATA_TYPE_UINT32, 117000d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[1], 117100d0963fSdilpreet PCIEX_UE_HDR3, DATA_TYPE_UINT32, 117200d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[2], 117300d0963fSdilpreet #endif 117400d0963fSdilpreet NULL); 117500d0963fSdilpreet break; 117600d0963fSdilpreet case PCIEX_TYPE_GEN: 117700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 117800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 117900d0963fSdilpreet 0, PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 118000d0963fSdilpreet pcie_regs->pcie_err_status, NULL); 118100d0963fSdilpreet break; 118200d0963fSdilpreet case PCIEX_TYPE_RC_UE_MSG: 118300d0963fSdilpreet case PCIEX_TYPE_RC_CE_MSG: 1184390e643aSdilpreet pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs; 1185390e643aSdilpreet 118600d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 118700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 118800d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 118900d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, 119000d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 119100d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 119200d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id : 119300d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id, 119400d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 119500d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 119600d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 119700d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id != 0) : 119800d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 119900d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id != 0), NULL); 120000d0963fSdilpreet break; 120100d0963fSdilpreet case PCIEX_TYPE_RC_MULT_MSG: 1202390e643aSdilpreet pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs; 1203390e643aSdilpreet 120400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 120500d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 120600d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 120700d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, NULL); 120800d0963fSdilpreet break; 120900d0963fSdilpreet default: 121000d0963fSdilpreet break; 121100d0963fSdilpreet } 121200d0963fSdilpreet } 121300d0963fSdilpreet 1214*8aec9182Sstephh /*ARGSUSED*/ 121500d0963fSdilpreet static void 1216*8aec9182Sstephh pcie_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 121700d0963fSdilpreet { 1218*8aec9182Sstephh pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 121900d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 122000d0963fSdilpreet pcie_tlp_hdr_t *ue_hdr0; 122100d0963fSdilpreet uint32_t *ue_hdr; 122200d0963fSdilpreet uint64_t addr = NULL; 1223*8aec9182Sstephh int upstream = 0; 1224*8aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 1225*8aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 122600d0963fSdilpreet 1227*8aec9182Sstephh if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_UE_HDR_VALID)) 122800d0963fSdilpreet return; 1229*8aec9182Sstephh 123000d0963fSdilpreet ue_hdr0 = (pcie_tlp_hdr_t *)&pcie_adv_regs->pcie_ue_hdr0; 123100d0963fSdilpreet ue_hdr = pcie_adv_regs->pcie_ue_hdr; 123200d0963fSdilpreet 1233*8aec9182Sstephh if ((pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 1234*8aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_ROOT || 1235*8aec9182Sstephh (pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 1236*8aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_DOWN) 1237*8aec9182Sstephh upstream = 1; 1238*8aec9182Sstephh 123900d0963fSdilpreet switch (ue_hdr0->type) { 124000d0963fSdilpreet case PCIE_TLP_TYPE_MEM: 124100d0963fSdilpreet case PCIE_TLP_TYPE_MEMLK: 124200d0963fSdilpreet if ((ue_hdr0->fmt & 0x1) == 0x1) { 124300d0963fSdilpreet pcie_mem64_t *mem64_tlp = (pcie_mem64_t *)ue_hdr; 124400d0963fSdilpreet 124500d0963fSdilpreet addr = (uint64_t)mem64_tlp->addr1 << 32 | 124600d0963fSdilpreet (uint32_t)mem64_tlp->addr0 << 2; 124700d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = mem64_tlp->rid; 124800d0963fSdilpreet } else { 124900d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 125000d0963fSdilpreet 125100d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 125200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 125300d0963fSdilpreet } 1254*8aec9182Sstephh if (upstream) { 1255*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = pcie_adv_regs->pcie_adv_bdf; 1256*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 1257*8aec9182Sstephh } else if ((pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 1258*8aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { 1259*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = erpt_p->pe_bdf; 1260*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 1261*8aec9182Sstephh } 1262*8aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 1263*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 1264*8aec9182Sstephh pci_fme_bsp->pci_bs_type = upstream ? DMA_HANDLE : ACC_HANDLE; 126500d0963fSdilpreet break; 126600d0963fSdilpreet 126700d0963fSdilpreet case PCIE_TLP_TYPE_IO: 126800d0963fSdilpreet { 126900d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 127000d0963fSdilpreet 127100d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 127200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 1273*8aec9182Sstephh if ((pcie_regs->pcie_cap & 1274*8aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_MASK) == 1275*8aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { 1276*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = erpt_p->pe_bdf; 1277*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 1278*8aec9182Sstephh } 1279*8aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 1280*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 1281*8aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 128200d0963fSdilpreet break; 128300d0963fSdilpreet } 128400d0963fSdilpreet case PCIE_TLP_TYPE_CFG0: 128500d0963fSdilpreet case PCIE_TLP_TYPE_CFG1: 128600d0963fSdilpreet { 128700d0963fSdilpreet pcie_cfg_t *cfg_tlp = (pcie_cfg_t *)ue_hdr; 128800d0963fSdilpreet 1289ac4d633fSstephh pcie_adv_regs->pcie_adv_bdf = cfg_tlp->rid; 1290*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (uint16_t)cfg_tlp->bus << 8 | 1291*8aec9182Sstephh (uint16_t)cfg_tlp->dev << 3 | cfg_tlp->func; 1292*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 1293*8aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 129400d0963fSdilpreet break; 129500d0963fSdilpreet } 129600d0963fSdilpreet case PCIE_TLP_TYPE_MSG: 129700d0963fSdilpreet { 129800d0963fSdilpreet pcie_msg_t *msg_tlp = (pcie_msg_t *)ue_hdr; 129900d0963fSdilpreet 130000d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = msg_tlp->rid; 130100d0963fSdilpreet break; 130200d0963fSdilpreet } 130300d0963fSdilpreet case PCIE_TLP_TYPE_CPL: 130400d0963fSdilpreet case PCIE_TLP_TYPE_CPLLK: 130500d0963fSdilpreet { 130600d0963fSdilpreet pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)ue_hdr; 130700d0963fSdilpreet 130800d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = cpl_tlp->cid; 1309*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 1310*8aec9182Sstephh if (upstream) { 1311*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = cpl_tlp->cid; 1312*8aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 1313*8aec9182Sstephh } else { 1314*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = cpl_tlp->rid; 1315*8aec9182Sstephh pci_fme_bsp->pci_bs_type = DMA_HANDLE; 1316*8aec9182Sstephh } 131700d0963fSdilpreet break; 131800d0963fSdilpreet } 131900d0963fSdilpreet case PCIE_TLP_TYPE_MSI: 132000d0963fSdilpreet default: 1321*8aec9182Sstephh break; 1322*8aec9182Sstephh } 132300d0963fSdilpreet } 132400d0963fSdilpreet 1325*8aec9182Sstephh /*ARGSUSED*/ 132600d0963fSdilpreet static void 1327*8aec9182Sstephh pcie_pci_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 1328*8aec9182Sstephh int type) 132900d0963fSdilpreet { 1330*8aec9182Sstephh pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 133100d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 133200d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 133300d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 133400d0963fSdilpreet uint64_t addr = NULL; 133500d0963fSdilpreet pcix_attr_t *pcie_pci_sue_attr; 133600d0963fSdilpreet int cmd; 133700d0963fSdilpreet int dual_addr = 0; 1338*8aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 1339*8aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 134000d0963fSdilpreet 1341*8aec9182Sstephh if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_HDR_VALID)) 134200d0963fSdilpreet return; 134300d0963fSdilpreet 134400d0963fSdilpreet pcie_pci_sue_attr = (pcix_attr_t *)&pcie_bdg_regs->pcie_sue_hdr0; 134500d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 134600d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK; 1347*8aec9182Sstephh 134800d0963fSdilpreet cmd_switch: 1349*8aec9182Sstephh addr = pcie_bdg_regs->pcie_sue_hdr[2]; 1350*8aec9182Sstephh addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) | 1351*8aec9182Sstephh pcie_bdg_regs->pcie_sue_hdr[1]; 135200d0963fSdilpreet switch (cmd) { 135300d0963fSdilpreet case PCI_PCIX_CMD_IORD: 135400d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 135500d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 1356*8aec9182Sstephh if (addr) { 1357*8aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 1358*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 1359*8aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 1360*8aec9182Sstephh } 136100d0963fSdilpreet break; 136200d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 136300d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 136400d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 136500d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 136600d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 136700d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 136800d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 1369*8aec9182Sstephh if (addr) { 1370*8aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 1371*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 1372*8aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 1373*8aec9182Sstephh } 137400d0963fSdilpreet break; 137500d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 137600d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 1377ac4d633fSstephh pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 1378*8aec9182Sstephh /* 1379*8aec9182Sstephh * for type 1 config transaction we can find bdf from address 1380*8aec9182Sstephh */ 1381*8aec9182Sstephh if ((addr & 3) == 1) { 1382*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff; 1383*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 1384*8aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 1385*8aec9182Sstephh } 1386*8aec9182Sstephh break; 1387*8aec9182Sstephh case PCI_PCIX_CMD_SPL: 1388*8aec9182Sstephh pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 1389*8aec9182Sstephh if (type == ACC_HANDLE) { 1390*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = pcie_adv_regs->pcie_adv_bdf; 1391*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 1392*8aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 1393*8aec9182Sstephh } 139400d0963fSdilpreet break; 139500d0963fSdilpreet case PCI_PCIX_CMD_DADR: 139600d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 139700d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) & 139800d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_MASK; 139900d0963fSdilpreet if (dual_addr) 140000d0963fSdilpreet break; 140100d0963fSdilpreet ++dual_addr; 140200d0963fSdilpreet goto cmd_switch; 140300d0963fSdilpreet default: 1404*8aec9182Sstephh break; 1405*8aec9182Sstephh } 140600d0963fSdilpreet } 140700d0963fSdilpreet 1408*8aec9182Sstephh /*ARGSUSED*/ 140900d0963fSdilpreet static int 141000d0963fSdilpreet pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, 1411*8aec9182Sstephh pcix_ecc_regs_t *pcix_ecc_regs, int type) 141200d0963fSdilpreet { 141300d0963fSdilpreet int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf; 141400d0963fSdilpreet uint64_t addr; 1415*8aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 1416*8aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 141700d0963fSdilpreet 141800d0963fSdilpreet addr = pcix_ecc_regs->pcix_ecc_secaddr; 141900d0963fSdilpreet addr = addr << 32; 142000d0963fSdilpreet addr |= pcix_ecc_regs->pcix_ecc_fstaddr; 142100d0963fSdilpreet 142200d0963fSdilpreet switch (cmd) { 142300d0963fSdilpreet case PCI_PCIX_CMD_INTR: 142400d0963fSdilpreet case PCI_PCIX_CMD_SPEC: 142500d0963fSdilpreet return (DDI_FM_FATAL); 142600d0963fSdilpreet case PCI_PCIX_CMD_IORD: 142700d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 1428*8aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 1429*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 1430*8aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 1431*8aec9182Sstephh return (DDI_FM_UNKNOWN); 143200d0963fSdilpreet case PCI_PCIX_CMD_DEVID: 143300d0963fSdilpreet return (DDI_FM_FATAL); 143400d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 143500d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 143600d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 143700d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 1438*8aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 1439*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 1440*8aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 1441*8aec9182Sstephh return (DDI_FM_UNKNOWN); 144200d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 144300d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 1444*8aec9182Sstephh /* 1445*8aec9182Sstephh * for type 1 config transaction we can find bdf from address 1446*8aec9182Sstephh */ 1447*8aec9182Sstephh if ((addr & 3) == 1) { 1448*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff; 1449*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 1450*8aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 1451*8aec9182Sstephh } 1452*8aec9182Sstephh return (DDI_FM_UNKNOWN); 145300d0963fSdilpreet case PCI_PCIX_CMD_SPL: 145400d0963fSdilpreet case PCI_PCIX_CMD_DADR: 1455*8aec9182Sstephh return (DDI_FM_UNKNOWN); 145600d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 145700d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 1458*8aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 1459*8aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 1460*8aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 1461*8aec9182Sstephh return (DDI_FM_UNKNOWN); 146200d0963fSdilpreet default: 146300d0963fSdilpreet return (DDI_FM_FATAL); 146400d0963fSdilpreet } 146500d0963fSdilpreet } 146600d0963fSdilpreet 146700d0963fSdilpreet /*ARGSUSED*/ 146800d0963fSdilpreet static int 146900d0963fSdilpreet pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 147000d0963fSdilpreet { 147100d0963fSdilpreet pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs; 147200d0963fSdilpreet int fatal = 0; 147300d0963fSdilpreet int nonfatal = 0; 147400d0963fSdilpreet int unknown = 0; 147500d0963fSdilpreet int ok = 0; 147600d0963fSdilpreet int ret = DDI_FM_OK; 147700d0963fSdilpreet char buf[FM_MAX_CLASS]; 147800d0963fSdilpreet int i; 1479*8aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 1480*8aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 148100d0963fSdilpreet 148200d0963fSdilpreet if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) 148300d0963fSdilpreet goto done; 148400d0963fSdilpreet 148500d0963fSdilpreet if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) && 148600d0963fSdilpreet (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) { 148700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 148800d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_DTO); 148900d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 149000d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 149100d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 149200d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 149300d0963fSdilpreet DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL); 149400d0963fSdilpreet unknown++; 149500d0963fSdilpreet } 149600d0963fSdilpreet 149700d0963fSdilpreet if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) { 149800d0963fSdilpreet for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) { 149900d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & 150000d0963fSdilpreet pci_bdg_err_tbl[i].reg_bit) { 150100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 150200d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, 150300d0963fSdilpreet pci_bdg_err_tbl[i].err_class); 150400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 150500d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 150600d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 150700d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 150800d0963fSdilpreet DATA_TYPE_UINT16, 150900d0963fSdilpreet pci_bdg_regs->pci_bdg_ctrl, NULL); 1510ac4d633fSstephh PCI_FM_SEV_INC(pci_bdg_err_tbl[i].flags); 1511*8aec9182Sstephh if (pci_fme_bsp && (pci_fme_bsp->pci_bs_flags & 1512*8aec9182Sstephh PCI_BS_ADDR_VALID) && 1513*8aec9182Sstephh pci_fme_bsp->pci_bs_type == ACC_HANDLE && 151400d0963fSdilpreet pci_bdg_err_tbl[i].terr_class) 151500d0963fSdilpreet pci_target_enqueue(derr->fme_ena, 151600d0963fSdilpreet pci_bdg_err_tbl[i].terr_class, 151700d0963fSdilpreet PCI_ERROR_SUBCLASS, 1518*8aec9182Sstephh pci_fme_bsp->pci_bs_addr); 151900d0963fSdilpreet } 152000d0963fSdilpreet } 1521ac4d633fSstephh #if !defined(__sparc) 1522ac4d633fSstephh /* 1523ac4d633fSstephh * For x86, many drivers and even user-level code currently get 1524ac4d633fSstephh * away with accessing bad addresses, getting a UR and getting 1525ac4d633fSstephh * -1 returned. Unfortunately, we have no control over this, so 1526ac4d633fSstephh * we will have to treat all URs as nonfatal. Moreover, if the 1527ac4d633fSstephh * leaf driver is non-hardened, then we don't actually see the 1528ac4d633fSstephh * UR directly. All we see is a secondary bus master abort at 1529ac4d633fSstephh * the root complex - so it's this condition that we actually 1530ac4d633fSstephh * need to treat as nonfatal (providing no other unrelated nfe 1531ac4d633fSstephh * conditions have also been seen by the root complex). 1532ac4d633fSstephh */ 1533ac4d633fSstephh if ((erpt_p->pe_dflags & PCIEX_RC_DEV) && 1534ac4d633fSstephh (pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_R_MAST_AB) && 1535ac4d633fSstephh !(pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_S_PERROR)) { 1536ac4d633fSstephh pcie_error_regs_t *pcie_regs = 1537ac4d633fSstephh (pcie_error_regs_t *)erpt_p->pe_regs; 1538ac4d633fSstephh if ((pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) && 1539ac4d633fSstephh !(pcie_regs->pcie_err_status & 1540ac4d633fSstephh PCIE_DEVSTS_NFE_DETECTED)) 1541ac4d633fSstephh nonfatal++; 1542*8aec9182Sstephh (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 1543*8aec9182Sstephh PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, PCI_MA); 1544*8aec9182Sstephh ddi_fm_ereport_post(dip, buf, derr->fme_ena, 1545*8aec9182Sstephh DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 1546*8aec9182Sstephh PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 1547*8aec9182Sstephh pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 1548*8aec9182Sstephh DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL); 1549ac4d633fSstephh } 1550ac4d633fSstephh #endif 155100d0963fSdilpreet } 155200d0963fSdilpreet 155300d0963fSdilpreet done: 155400d0963fSdilpreet /* 155500d0963fSdilpreet * Need to check for poke and cautious put. We already know peek 155600d0963fSdilpreet * and cautious get errors occurred (as we got a trap) and we know 155700d0963fSdilpreet * they are nonfatal. 155800d0963fSdilpreet */ 155900d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_EXPECTED) { 156000d0963fSdilpreet /* 156100d0963fSdilpreet * for cautious puts we treat all errors as nonfatal. Actually 156200d0963fSdilpreet * we set nonfatal for cautious gets as well - doesn't do any 156300d0963fSdilpreet * harm 156400d0963fSdilpreet */ 156500d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 156600d0963fSdilpreet PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR)) 156700d0963fSdilpreet nonfatal++; 156800d0963fSdilpreet } 156900d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_POKE) { 157000d0963fSdilpreet /* 157100d0963fSdilpreet * special case for pokes - we only consider master abort 157200d0963fSdilpreet * and target abort as nonfatal. Sserr with no master abort is 157300d0963fSdilpreet * fatal, but master/target abort can come in on separate 157400d0963fSdilpreet * instance, so return unknown and parent will determine if 157500d0963fSdilpreet * nonfatal (if another child returned nonfatal - ie master 157600d0963fSdilpreet * or target abort) or fatal otherwise 157700d0963fSdilpreet */ 157800d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 157900d0963fSdilpreet PCI_STAT_R_MAST_AB)) 158000d0963fSdilpreet nonfatal++; 158100d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR) 158200d0963fSdilpreet unknown++; 158300d0963fSdilpreet } 158400d0963fSdilpreet 158500d0963fSdilpreet /* 1586*8aec9182Sstephh * now check children below the bridge 158700d0963fSdilpreet */ 158800d0963fSdilpreet ret = ndi_fm_handler_dispatch(dip, NULL, derr); 158900d0963fSdilpreet PCI_FM_SEV_INC(ret); 159000d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 159100d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 159200d0963fSdilpreet } 159300d0963fSdilpreet 159400d0963fSdilpreet static int 159500d0963fSdilpreet pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 159600d0963fSdilpreet void *pe_regs) 159700d0963fSdilpreet { 159800d0963fSdilpreet pcix_error_regs_t *pcix_regs; 159900d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 160000d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs; 160100d0963fSdilpreet int bridge; 160200d0963fSdilpreet int i; 160300d0963fSdilpreet int ecc_phase; 160400d0963fSdilpreet int ecc_corr; 160500d0963fSdilpreet int sec_ue; 160600d0963fSdilpreet int sec_ce; 160700d0963fSdilpreet int fatal = 0; 160800d0963fSdilpreet int nonfatal = 0; 160900d0963fSdilpreet int unknown = 0; 161000d0963fSdilpreet int ok = 0; 161100d0963fSdilpreet char buf[FM_MAX_CLASS]; 161200d0963fSdilpreet 161300d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 161400d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 161500d0963fSdilpreet bridge = 1; 161600d0963fSdilpreet } else { 161700d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)pe_regs; 161800d0963fSdilpreet bridge = 0; 161900d0963fSdilpreet } 162000d0963fSdilpreet 162100d0963fSdilpreet for (i = 0; i < (bridge ? 2 : 1); i++) { 162200d0963fSdilpreet int ret = DDI_FM_OK; 162300d0963fSdilpreet pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] : 162400d0963fSdilpreet pcix_regs->pcix_ecc_regs; 162500d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) { 162600d0963fSdilpreet ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat & 162700d0963fSdilpreet PCI_PCIX_ECC_PHASE) >> 0x4; 162800d0963fSdilpreet ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat & 162900d0963fSdilpreet PCI_PCIX_ECC_CORR); 163000d0963fSdilpreet sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat & 163100d0963fSdilpreet PCI_PCIX_ECC_S_UE); 163200d0963fSdilpreet sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat & 163300d0963fSdilpreet PCI_PCIX_ECC_S_CE); 163400d0963fSdilpreet 163500d0963fSdilpreet switch (ecc_phase) { 163600d0963fSdilpreet case PCI_PCIX_ECC_PHASE_NOERR: 163700d0963fSdilpreet break; 163800d0963fSdilpreet case PCI_PCIX_ECC_PHASE_FADDR: 163900d0963fSdilpreet case PCI_PCIX_ECC_PHASE_SADDR: 1640ac4d633fSstephh PCI_FM_SEV_INC(ecc_corr ? DDI_FM_OK : 164100d0963fSdilpreet DDI_FM_FATAL); 164200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 164300d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 164400d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 164500d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ADDR : 164600d0963fSdilpreet PCIX_ECC_UE_ADDR); 164700d0963fSdilpreet break; 164800d0963fSdilpreet case PCI_PCIX_ECC_PHASE_ATTR: 164900d0963fSdilpreet PCI_FM_SEV_INC(ecc_corr ? 1650ac4d633fSstephh DDI_FM_OK : DDI_FM_FATAL); 165100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 165200d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 165300d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 165400d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ATTR : 165500d0963fSdilpreet PCIX_ECC_UE_ATTR); 165600d0963fSdilpreet break; 165700d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA32: 165800d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA64: 165900d0963fSdilpreet if (ecc_corr) 1660ac4d633fSstephh ret = DDI_FM_OK; 1661*8aec9182Sstephh else { 1662*8aec9182Sstephh int type; 1663*8aec9182Sstephh pci_error_regs_t *pci_regs = 1664*8aec9182Sstephh erpt_p->pe_pci_regs; 1665*8aec9182Sstephh 1666*8aec9182Sstephh if (i) { 1667*8aec9182Sstephh if (pci_regs->pci_bdg_regs-> 1668*8aec9182Sstephh pci_bdg_sec_stat & 1669*8aec9182Sstephh PCI_STAT_S_PERROR) 1670*8aec9182Sstephh type = ACC_HANDLE; 167100d0963fSdilpreet else 1672*8aec9182Sstephh type = DMA_HANDLE; 1673*8aec9182Sstephh } else { 1674*8aec9182Sstephh if (pci_regs->pci_err_status & 1675*8aec9182Sstephh PCI_STAT_S_PERROR) 1676*8aec9182Sstephh type = DMA_HANDLE; 1677*8aec9182Sstephh else 1678*8aec9182Sstephh type = ACC_HANDLE; 1679*8aec9182Sstephh } 168000d0963fSdilpreet ret = pcix_check_addr(dip, derr, 1681*8aec9182Sstephh pcix_ecc_regs, type); 1682*8aec9182Sstephh } 168300d0963fSdilpreet PCI_FM_SEV_INC(ret); 168400d0963fSdilpreet 168500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 168600d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 168700d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 168800d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_DATA : 168900d0963fSdilpreet PCIX_ECC_UE_DATA); 169000d0963fSdilpreet break; 169100d0963fSdilpreet } 169200d0963fSdilpreet if (ecc_phase) 169300d0963fSdilpreet if (bridge) 169400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 169500d0963fSdilpreet derr->fme_ena, 169600d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 169700d0963fSdilpreet DATA_TYPE_UINT8, 0, 169800d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 169900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 170000d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 170100d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 170200d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 170300d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 170400d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 170500d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 170600d0963fSdilpreet else 170700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 170800d0963fSdilpreet derr->fme_ena, 170900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 171000d0963fSdilpreet DATA_TYPE_UINT8, 0, 171100d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 171200d0963fSdilpreet pcix_regs->pcix_command, 171300d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 171400d0963fSdilpreet pcix_regs->pcix_status, 171500d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 171600d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 171700d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 171800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 171900d0963fSdilpreet if (sec_ce || sec_ue) { 172000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 172100d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 172200d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 172300d0963fSdilpreet sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE); 172400d0963fSdilpreet if (bridge) 172500d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 172600d0963fSdilpreet derr->fme_ena, 172700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 172800d0963fSdilpreet DATA_TYPE_UINT8, 0, 172900d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 173000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 173100d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 173200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 173300d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 173400d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 173500d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 173600d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 173700d0963fSdilpreet else 173800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 173900d0963fSdilpreet derr->fme_ena, 174000d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 174100d0963fSdilpreet DATA_TYPE_UINT8, 0, 174200d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 174300d0963fSdilpreet pcix_regs->pcix_command, 174400d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 174500d0963fSdilpreet pcix_regs->pcix_status, 174600d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 174700d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 174800d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 174900d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 175000d0963fSdilpreet PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL : 1751ac4d633fSstephh DDI_FM_OK); 175200d0963fSdilpreet } 175300d0963fSdilpreet } 175400d0963fSdilpreet } 175500d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 175600d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 175700d0963fSdilpreet } 175800d0963fSdilpreet 175900d0963fSdilpreet static int 176000d0963fSdilpreet pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 176100d0963fSdilpreet void *pe_regs) 176200d0963fSdilpreet { 176300d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 176400d0963fSdilpreet int fatal = 0; 176500d0963fSdilpreet int nonfatal = 0; 176600d0963fSdilpreet int unknown = 0; 176700d0963fSdilpreet int ok = 0; 176800d0963fSdilpreet char buf[FM_MAX_CLASS]; 176900d0963fSdilpreet int i; 177000d0963fSdilpreet 177100d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) { 177200d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 177300d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_stat & 177400d0963fSdilpreet pcix_err_tbl[i].reg_bit)) { 177500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 177600d0963fSdilpreet PCIX_ERROR_SUBCLASS, 177700d0963fSdilpreet pcix_err_tbl[i].err_class); 177800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 177900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 178000d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 178100d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 178200d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 178300d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 178400d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 178500d0963fSdilpreet } 178600d0963fSdilpreet } 178700d0963fSdilpreet } 178800d0963fSdilpreet 178900d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) { 179000d0963fSdilpreet for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) { 179100d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_sec_stat & 179200d0963fSdilpreet pcix_sec_err_tbl[i].reg_bit)) { 179300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s", 179400d0963fSdilpreet PCIX_ERROR_SUBCLASS, 179500d0963fSdilpreet PCIX_SEC_ERROR_SUBCLASS, 179600d0963fSdilpreet pcix_sec_err_tbl[i].err_class); 179700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 179800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 179900d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 180000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 180100d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 180200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 180300d0963fSdilpreet PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags); 180400d0963fSdilpreet } 180500d0963fSdilpreet } 180600d0963fSdilpreet } 180700d0963fSdilpreet 180800d0963fSdilpreet /* Log/Handle ECC errors */ 180900d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 181000d0963fSdilpreet int ret; 181100d0963fSdilpreet 181200d0963fSdilpreet ret = pcix_ecc_error_report(dip, derr, erpt_p, 181300d0963fSdilpreet (void *)pcix_bdg_regs); 181400d0963fSdilpreet PCI_FM_SEV_INC(ret); 181500d0963fSdilpreet } 181600d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 181700d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 181800d0963fSdilpreet } 181900d0963fSdilpreet 182000d0963fSdilpreet static int 182100d0963fSdilpreet pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 182200d0963fSdilpreet { 182300d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 182400d0963fSdilpreet int fatal = 0; 182500d0963fSdilpreet int nonfatal = 0; 182600d0963fSdilpreet int unknown = 0; 182700d0963fSdilpreet int ok = 0; 182800d0963fSdilpreet char buf[FM_MAX_CLASS]; 182900d0963fSdilpreet int i; 183000d0963fSdilpreet 183100d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) { 183200d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 183300d0963fSdilpreet if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit)) 183400d0963fSdilpreet continue; 183500d0963fSdilpreet 183600d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 183700d0963fSdilpreet PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class); 183800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 183900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 184000d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 184100d0963fSdilpreet pcix_regs->pcix_command, PCIX_STATUS, 184200d0963fSdilpreet DATA_TYPE_UINT32, pcix_regs->pcix_status, 184300d0963fSdilpreet NULL); 184400d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 184500d0963fSdilpreet } 184600d0963fSdilpreet } 184700d0963fSdilpreet /* Log/Handle ECC errors */ 184800d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 184900d0963fSdilpreet int ret = pcix_ecc_error_report(dip, derr, erpt_p, 185000d0963fSdilpreet (void *)pcix_regs); 185100d0963fSdilpreet PCI_FM_SEV_INC(ret); 185200d0963fSdilpreet } 185300d0963fSdilpreet 185400d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 185500d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 185600d0963fSdilpreet } 185700d0963fSdilpreet 185800d0963fSdilpreet static int 185900d0963fSdilpreet pcie_rc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 186000d0963fSdilpreet void *pe_regs) 186100d0963fSdilpreet { 186200d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = (pcie_adv_error_regs_t *)pe_regs; 186300d0963fSdilpreet int fatal = 0; 186400d0963fSdilpreet int nonfatal = 0; 186500d0963fSdilpreet int unknown = 0; 186600d0963fSdilpreet char buf[FM_MAX_CLASS]; 186700d0963fSdilpreet 186800d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) { 186900d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 187000d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 187100d0963fSdilpreet int ce, ue, mult_ce, mult_ue, first_ue_fatal, nfe, fe; 187200d0963fSdilpreet 187300d0963fSdilpreet ce = pcie_rc_regs->pcie_rc_err_status & 187400d0963fSdilpreet PCIE_AER_RE_STS_CE_RCVD; 187500d0963fSdilpreet ue = pcie_rc_regs->pcie_rc_err_status & 187600d0963fSdilpreet PCIE_AER_RE_STS_FE_NFE_RCVD; 187700d0963fSdilpreet mult_ce = pcie_rc_regs->pcie_rc_err_status & 187800d0963fSdilpreet PCIE_AER_RE_STS_MUL_CE_RCVD; 187900d0963fSdilpreet mult_ue = pcie_rc_regs->pcie_rc_err_status & 188000d0963fSdilpreet PCIE_AER_RE_STS_MUL_FE_NFE_RCVD; 188100d0963fSdilpreet first_ue_fatal = pcie_rc_regs->pcie_rc_err_status & 188200d0963fSdilpreet PCIE_AER_RE_STS_FIRST_UC_FATAL; 188300d0963fSdilpreet nfe = pcie_rc_regs->pcie_rc_err_status & 188400d0963fSdilpreet PCIE_AER_RE_STS_NFE_MSGS_RCVD; 188500d0963fSdilpreet fe = pcie_rc_regs->pcie_rc_err_status & 188600d0963fSdilpreet PCIE_AER_RE_STS_FE_MSGS_RCVD; 188700d0963fSdilpreet /* 188800d0963fSdilpreet * log fatal/nonfatal/corrected messages 188900d0963fSdilpreet * recieved by root complex 189000d0963fSdilpreet */ 189100d0963fSdilpreet if (ue && fe) 189200d0963fSdilpreet fatal++; 189300d0963fSdilpreet 189400d0963fSdilpreet if (fe && first_ue_fatal) { 189500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 189600d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_FE_MSG); 189700d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 189800d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 189900d0963fSdilpreet } 190000d0963fSdilpreet if (nfe && !first_ue_fatal) { 190100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 190200d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_NFE_MSG); 190300d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 190400d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 190500d0963fSdilpreet } 190600d0963fSdilpreet if (ce) { 190700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 190800d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_CE_MSG); 190900d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 191000d0963fSdilpreet PCIEX_TYPE_RC_CE_MSG); 191100d0963fSdilpreet } 191200d0963fSdilpreet if (mult_ce) { 191300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 191400d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MCE_MSG); 191500d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 191600d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 191700d0963fSdilpreet } 191800d0963fSdilpreet if (mult_ue) { 191900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 192000d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MUE_MSG); 192100d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 192200d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 192300d0963fSdilpreet } 192400d0963fSdilpreet } 192500d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 192600d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 192700d0963fSdilpreet } 192800d0963fSdilpreet 192900d0963fSdilpreet static int 193000d0963fSdilpreet pcie_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 193100d0963fSdilpreet { 193200d0963fSdilpreet int fatal = 0; 193300d0963fSdilpreet int nonfatal = 0; 193400d0963fSdilpreet int unknown = 0; 193500d0963fSdilpreet int ok = 0; 1936*8aec9182Sstephh int type; 193700d0963fSdilpreet char buf[FM_MAX_CLASS]; 193800d0963fSdilpreet int i; 193900d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 194000d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 194100d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs; 194200d0963fSdilpreet 194300d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 194400d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 194500d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, erpt_p, 194600d0963fSdilpreet (void *)pcie_regs->pcix_bdg_regs); 194700d0963fSdilpreet PCI_FM_SEV_INC(ret); 194800d0963fSdilpreet } 194900d0963fSdilpreet 195000d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 195100d0963fSdilpreet if (!(pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID)) 195200d0963fSdilpreet goto done; 1953*8aec9182Sstephh #if !defined(__sparc) 1954*8aec9182Sstephh /* 1955*8aec9182Sstephh * On x86 ignore UR on non-RBER leaf devices and pciex-pci 1956*8aec9182Sstephh * bridges. 1957*8aec9182Sstephh */ 1958*8aec9182Sstephh if ((pcie_regs->pcie_err_status & PCIE_DEVSTS_UR_DETECTED) && 1959*8aec9182Sstephh !(pcie_regs->pcie_err_status & PCIE_DEVSTS_FE_DETECTED) && 1960*8aec9182Sstephh ((erpt_p->pe_dflags & PCIEX_2PCI_DEV) || 1961*8aec9182Sstephh !(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) && 1962*8aec9182Sstephh !(pcie_regs->pcie_dev_cap & PCIE_DEVCAP_ROLE_BASED_ERR_REP)) 1963*8aec9182Sstephh goto done; 1964*8aec9182Sstephh #endif 196500d0963fSdilpreet for (i = 0; pciex_nadv_err_tbl[i].err_class != NULL; i++) { 196600d0963fSdilpreet if (!(pcie_regs->pcie_err_status & 196700d0963fSdilpreet pciex_nadv_err_tbl[i].reg_bit)) 196800d0963fSdilpreet continue; 196900d0963fSdilpreet 197000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 197100d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 197200d0963fSdilpreet pciex_nadv_err_tbl[i].err_class); 197300d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 197400d0963fSdilpreet PCIEX_TYPE_GEN); 197500d0963fSdilpreet PCI_FM_SEV_INC(pciex_nadv_err_tbl[i].flags); 197600d0963fSdilpreet } 197700d0963fSdilpreet goto done; 197800d0963fSdilpreet } 197900d0963fSdilpreet 198000d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 198100d0963fSdilpreet 198200d0963fSdilpreet /* 198300d0963fSdilpreet * Log PCI Express uncorrectable errors 198400d0963fSdilpreet */ 198500d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) { 198600d0963fSdilpreet for (i = 0; pciex_ue_err_tbl[i].err_class != NULL; i++) { 198700d0963fSdilpreet if (!(pcie_adv_regs->pcie_ue_status & 198800d0963fSdilpreet pciex_ue_err_tbl[i].reg_bit)) 198900d0963fSdilpreet continue; 199000d0963fSdilpreet 199100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 199200d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 199300d0963fSdilpreet pciex_ue_err_tbl[i].err_class); 199400d0963fSdilpreet 1995*8aec9182Sstephh /* 1996*8aec9182Sstephh * First check for advisary nonfatal conditions 1997*8aec9182Sstephh * - hardware endpoint successfully retrying a cto 1998*8aec9182Sstephh * - hardware endpoint receiving poisoned tlp and 1999*8aec9182Sstephh * dealing with it itself (but not if root complex) 2000*8aec9182Sstephh * If the device has declared these as correctable 2001*8aec9182Sstephh * errors then treat them as such. 2002*8aec9182Sstephh */ 2003*8aec9182Sstephh if ((pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_TO || 2004*8aec9182Sstephh (pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_PTLP && 2005*8aec9182Sstephh !(erpt_p->pe_dflags & PCIEX_RC_DEV))) && 2006*8aec9182Sstephh (pcie_regs->pcie_err_status & 2007*8aec9182Sstephh PCIE_DEVSTS_CE_DETECTED) && 2008*8aec9182Sstephh !(pcie_regs->pcie_err_status & 2009*8aec9182Sstephh PCIE_DEVSTS_NFE_DETECTED)) { 2010*8aec9182Sstephh pcie_ereport_post(dip, derr, erpt_p, buf, 2011*8aec9182Sstephh PCIEX_TYPE_UE); 2012*8aec9182Sstephh continue; 2013*8aec9182Sstephh } 2014*8aec9182Sstephh 2015*8aec9182Sstephh #if !defined(__sparc) 2016*8aec9182Sstephh /* 2017*8aec9182Sstephh * On x86 for leaf devices and pciex-pci bridges, 2018*8aec9182Sstephh * ignore UR on non-RBER devices or on RBER devices when 2019*8aec9182Sstephh * advisory nonfatal. 2020*8aec9182Sstephh */ 2021*8aec9182Sstephh if (pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_UR && 2022*8aec9182Sstephh ((erpt_p->pe_dflags & PCIEX_2PCI_DEV) || 2023*8aec9182Sstephh !(erpt_p->pe_dflags & PCI_BRIDGE_DEV))) { 2024*8aec9182Sstephh if (!(pcie_regs->pcie_dev_cap & 2025*8aec9182Sstephh PCIE_DEVCAP_ROLE_BASED_ERR_REP)) 2026*8aec9182Sstephh continue; 2027*8aec9182Sstephh if ((pcie_regs->pcie_err_status & 2028*8aec9182Sstephh PCIE_DEVSTS_CE_DETECTED) && 2029*8aec9182Sstephh !(pcie_regs->pcie_err_status & 2030*8aec9182Sstephh PCIE_DEVSTS_NFE_DETECTED)) 2031*8aec9182Sstephh continue; 2032*8aec9182Sstephh } 2033*8aec9182Sstephh #endif 203400d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 2035*8aec9182Sstephh /* 2036*8aec9182Sstephh * Now try and look up handle if 2037*8aec9182Sstephh * - error bit is among PCIE_AER_UCE_LOG_BITS, and 2038*8aec9182Sstephh * - no other PCIE_AER_UCE_LOG_BITS are set, and 2039*8aec9182Sstephh * - error bit is not masked, and 2040*8aec9182Sstephh * - flag is DDI_FM_UNKNOWN 2041*8aec9182Sstephh */ 204200d0963fSdilpreet if ((pcie_adv_regs->pcie_ue_status & 2043*8aec9182Sstephh pcie_aer_uce_log_bits) == 2044*8aec9182Sstephh pciex_ue_err_tbl[i].reg_bit && 2045*8aec9182Sstephh !(pciex_ue_err_tbl[i].reg_bit & 2046*8aec9182Sstephh pcie_adv_regs->pcie_ue_mask) && 2047*8aec9182Sstephh pciex_ue_err_tbl[i].flags == DDI_FM_UNKNOWN) 2048*8aec9182Sstephh pcie_check_addr(dip, derr, erpt_p); 2049*8aec9182Sstephh 205000d0963fSdilpreet PCI_FM_SEV_INC(pciex_ue_err_tbl[i].flags); 205100d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 205200d0963fSdilpreet PCIEX_TYPE_UE); 205300d0963fSdilpreet } 205400d0963fSdilpreet } 205500d0963fSdilpreet 205600d0963fSdilpreet /* 205700d0963fSdilpreet * Log PCI Express correctable errors 205800d0963fSdilpreet */ 205900d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) { 206000d0963fSdilpreet for (i = 0; pciex_ce_err_tbl[i].err_class != NULL; i++) { 206100d0963fSdilpreet if (!(pcie_adv_regs->pcie_ce_status & 206200d0963fSdilpreet pciex_ce_err_tbl[i].reg_bit)) 206300d0963fSdilpreet continue; 206400d0963fSdilpreet 206500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 206600d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 206700d0963fSdilpreet pciex_ce_err_tbl[i].err_class); 206800d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 206900d0963fSdilpreet PCIEX_TYPE_CE); 207000d0963fSdilpreet } 207100d0963fSdilpreet } 207200d0963fSdilpreet 207300d0963fSdilpreet if (!(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) 207400d0963fSdilpreet goto done; 207500d0963fSdilpreet 207600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 207700d0963fSdilpreet int ret = pcie_rc_error_report(dip, derr, erpt_p, 207800d0963fSdilpreet (void *)pcie_adv_regs); 207900d0963fSdilpreet PCI_FM_SEV_INC(ret); 208000d0963fSdilpreet } 208100d0963fSdilpreet 208200d0963fSdilpreet if (!((erpt_p->pe_dflags & PCIEX_2PCI_DEV) && 208300d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID))) 208400d0963fSdilpreet goto done; 208500d0963fSdilpreet 208600d0963fSdilpreet pcie_bdg_regs = pcie_adv_regs->pcie_adv_bdg_regs; 208700d0963fSdilpreet 208800d0963fSdilpreet for (i = 0; pcie_sue_err_tbl[i].err_class != NULL; i++) { 208900d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 209000d0963fSdilpreet pcie_sue_err_tbl[i].reg_bit)) { 209100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 209200d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 209300d0963fSdilpreet pcie_sue_err_tbl[i].err_class); 209400d0963fSdilpreet 209500d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 20960c64a9b4Sanish pcie_aer_suce_log_bits) != 2097*8aec9182Sstephh pcie_sue_err_tbl[i].reg_bit || 2098*8aec9182Sstephh pcie_sue_err_tbl[i].flags != DDI_FM_UNKNOWN) { 209900d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 210000d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 210100d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 210200d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 210300d0963fSdilpreet #ifdef DEBUG 210400d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 210500d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 210600d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 210700d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 210800d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 210900d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 211000d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 211100d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 211200d0963fSdilpreet #endif 211300d0963fSdilpreet NULL); 211400d0963fSdilpreet } else { 211500d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 2116*8aec9182Sstephh switch (pcie_sue_err_tbl[i].reg_bit) { 2117*8aec9182Sstephh case PCIE_AER_SUCE_RCVD_TA: 2118*8aec9182Sstephh case PCIE_AER_SUCE_RCVD_MA: 2119*8aec9182Sstephh case PCIE_AER_SUCE_USC_ERR: 2120*8aec9182Sstephh type = ACC_HANDLE; 2121*8aec9182Sstephh break; 2122*8aec9182Sstephh case PCIE_AER_SUCE_TA_ON_SC: 2123*8aec9182Sstephh case PCIE_AER_SUCE_MA_ON_SC: 2124*8aec9182Sstephh type = DMA_HANDLE; 2125*8aec9182Sstephh break; 2126*8aec9182Sstephh case PCIE_AER_SUCE_UC_DATA_ERR: 2127*8aec9182Sstephh case PCIE_AER_SUCE_PERR_ASSERT: 2128*8aec9182Sstephh if (erpt_p->pe_pci_regs->pci_bdg_regs-> 2129*8aec9182Sstephh pci_bdg_sec_stat & 2130*8aec9182Sstephh PCI_STAT_S_PERROR) 2131*8aec9182Sstephh type = ACC_HANDLE; 2132*8aec9182Sstephh else 2133*8aec9182Sstephh type = DMA_HANDLE; 2134*8aec9182Sstephh break; 2135*8aec9182Sstephh } 2136*8aec9182Sstephh pcie_pci_check_addr(dip, derr, erpt_p, type); 213700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 213800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 213900d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 214000d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 214100d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 214200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 214300d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 214400d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 214500d0963fSdilpreet 1 : NULL, 214600d0963fSdilpreet #ifdef DEBUG 214700d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 214800d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 214900d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 215000d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 215100d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 215200d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 215300d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 215400d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 215500d0963fSdilpreet #endif 215600d0963fSdilpreet NULL); 215700d0963fSdilpreet } 2158*8aec9182Sstephh PCI_FM_SEV_INC(pcie_sue_err_tbl[i].flags); 215900d0963fSdilpreet } 216000d0963fSdilpreet } 216100d0963fSdilpreet done: 216200d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 216300d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 216400d0963fSdilpreet } 216500d0963fSdilpreet 216600d0963fSdilpreet static void 216700d0963fSdilpreet pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 216800d0963fSdilpreet { 216900d0963fSdilpreet int fatal = 0; 217000d0963fSdilpreet int nonfatal = 0; 217100d0963fSdilpreet int unknown = 0; 217200d0963fSdilpreet int ok = 0; 217300d0963fSdilpreet char buf[FM_MAX_CLASS]; 217400d0963fSdilpreet int i; 217500d0963fSdilpreet 217600d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 217700d0963fSdilpreet /* 217800d0963fSdilpreet * Log generic PCI errors. 217900d0963fSdilpreet */ 218000d0963fSdilpreet for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 218100d0963fSdilpreet if (!(erpt_p->pe_pci_regs->pci_err_status & 218200d0963fSdilpreet pci_err_tbl[i].reg_bit) || 218300d0963fSdilpreet !(erpt_p->pe_pci_regs->pci_vflags & 218400d0963fSdilpreet PCI_ERR_STATUS_VALID)) 218500d0963fSdilpreet continue; 218600d0963fSdilpreet /* 218700d0963fSdilpreet * Generate an ereport for this error bit. 218800d0963fSdilpreet */ 218900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 219000d0963fSdilpreet PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class); 219100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 219200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 219300d0963fSdilpreet PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 219400d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status, 219500d0963fSdilpreet PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 219600d0963fSdilpreet erpt_p->pe_pci_regs->pci_cfg_comm, NULL); 219700d0963fSdilpreet 2198ac4d633fSstephh /* 2199ac4d633fSstephh * The meaning of SERR is different for PCIEX (just 2200ac4d633fSstephh * implies a message has been sent) so we don't want to 2201ac4d633fSstephh * treat that one as fatal. 2202ac4d633fSstephh */ 2203ac4d633fSstephh if ((erpt_p->pe_dflags & PCIEX_DEV) && 2204ac4d633fSstephh pci_err_tbl[i].reg_bit == PCI_STAT_S_SYSERR) { 2205ac4d633fSstephh unknown++; 2206ac4d633fSstephh } else { 220700d0963fSdilpreet PCI_FM_SEV_INC(pci_err_tbl[i].flags); 220800d0963fSdilpreet } 2209ac4d633fSstephh } 221000d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) { 221100d0963fSdilpreet int ret = pcie_error_report(dip, derr, erpt_p); 221200d0963fSdilpreet PCI_FM_SEV_INC(ret); 221300d0963fSdilpreet } else if (erpt_p->pe_dflags & PCIX_DEV) { 221400d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 221500d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, 221600d0963fSdilpreet erpt_p, erpt_p->pe_regs); 221700d0963fSdilpreet PCI_FM_SEV_INC(ret); 221800d0963fSdilpreet } else { 221900d0963fSdilpreet int ret = pcix_error_report(dip, derr, erpt_p); 222000d0963fSdilpreet PCI_FM_SEV_INC(ret); 222100d0963fSdilpreet } 222200d0963fSdilpreet } 222300d0963fSdilpreet } 222400d0963fSdilpreet 222500d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) { 222600d0963fSdilpreet int ret = pci_bdg_error_report(dip, derr, erpt_p); 222700d0963fSdilpreet PCI_FM_SEV_INC(ret); 222800d0963fSdilpreet } 222900d0963fSdilpreet 2230*8aec9182Sstephh if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 2231*8aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp; 2232*8aec9182Sstephh int ret = DDI_FM_UNKNOWN; 2233*8aec9182Sstephh 2234*8aec9182Sstephh pci_fme_bsp = (pci_fme_bus_specific_t *)derr->fme_bus_specific; 2235*8aec9182Sstephh if (pci_fme_bsp->pci_bs_flags & PCI_BS_ADDR_VALID) { 2236*8aec9182Sstephh ret = ndi_fmc_entry_error(dip, 2237*8aec9182Sstephh pci_fme_bsp->pci_bs_type, derr, 2238*8aec9182Sstephh (void *)&pci_fme_bsp->pci_bs_addr); 2239*8aec9182Sstephh PCI_FM_SEV_INC(ret); 2240*8aec9182Sstephh } 2241*8aec9182Sstephh /* 2242*8aec9182Sstephh * If we didn't find the handle using an addr, try using bdf. 2243*8aec9182Sstephh * Note we don't do this where the bdf is for a 2244*8aec9182Sstephh * device behind a pciex/pci bridge as the bridge may have 2245*8aec9182Sstephh * fabricated the bdf. 2246*8aec9182Sstephh */ 2247*8aec9182Sstephh if (ret == DDI_FM_UNKNOWN && 2248*8aec9182Sstephh (pci_fme_bsp->pci_bs_flags & PCI_BS_BDF_VALID) && 2249*8aec9182Sstephh pci_fme_bsp->pci_bs_bdf == erpt_p->pe_bdf && 2250*8aec9182Sstephh (erpt_p->pe_dflags & PCIEX_DEV) && 2251*8aec9182Sstephh !(erpt_p->pe_dflags & PCIEX_2PCI_DEV)) { 2252*8aec9182Sstephh ret = ndi_fmc_entry_error_all(dip, 2253*8aec9182Sstephh pci_fme_bsp->pci_bs_type, derr); 2254*8aec9182Sstephh PCI_FM_SEV_INC(ret); 2255*8aec9182Sstephh } 2256*8aec9182Sstephh } 2257*8aec9182Sstephh 225800d0963fSdilpreet derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 225900d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 226000d0963fSdilpreet } 226100d0963fSdilpreet 226200d0963fSdilpreet void 226300d0963fSdilpreet pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status) 226400d0963fSdilpreet { 226500d0963fSdilpreet struct i_ddi_fmhdl *fmhdl; 226600d0963fSdilpreet pci_erpt_t *erpt_p; 2267*8aec9182Sstephh ddi_fm_error_t de; 2268*8aec9182Sstephh pci_fme_bus_specific_t pci_fme_bs; 226900d0963fSdilpreet 227000d0963fSdilpreet fmhdl = DEVI(dip)->devi_fmhdl; 227100d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 227200d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 227300d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 227400d0963fSdilpreet return; 227500d0963fSdilpreet } 227600d0963fSdilpreet 2277*8aec9182Sstephh /* 2278*8aec9182Sstephh * copy in the ddi_fm_error_t structure in case it's VER0 2279*8aec9182Sstephh */ 2280*8aec9182Sstephh de.fme_version = derr->fme_version; 2281*8aec9182Sstephh de.fme_status = derr->fme_status; 2282*8aec9182Sstephh de.fme_flag = derr->fme_flag; 2283*8aec9182Sstephh de.fme_ena = derr->fme_ena; 2284*8aec9182Sstephh de.fme_acc_handle = derr->fme_acc_handle; 2285*8aec9182Sstephh de.fme_dma_handle = derr->fme_dma_handle; 2286*8aec9182Sstephh de.fme_bus_specific = derr->fme_bus_specific; 2287*8aec9182Sstephh if (derr->fme_version >= DDI_FME_VER1) 2288*8aec9182Sstephh de.fme_bus_type = derr->fme_bus_type; 2289*8aec9182Sstephh else 2290*8aec9182Sstephh de.fme_bus_type = DDI_FME_BUS_TYPE_DFLT; 2291*8aec9182Sstephh if (de.fme_bus_type == DDI_FME_BUS_TYPE_DFLT) { 2292*8aec9182Sstephh /* 2293*8aec9182Sstephh * if this is the first pci device we've found convert 2294*8aec9182Sstephh * fme_bus_specific to DDI_FME_BUS_TYPE_PCI 2295*8aec9182Sstephh */ 2296*8aec9182Sstephh bzero(&pci_fme_bs, sizeof (pci_fme_bs)); 2297*8aec9182Sstephh if (de.fme_bus_specific) { 2298*8aec9182Sstephh /* 2299*8aec9182Sstephh * the cpu passed us an addr - this can be used to look 2300*8aec9182Sstephh * up an access handle 2301*8aec9182Sstephh */ 2302*8aec9182Sstephh pci_fme_bs.pci_bs_addr = (uintptr_t)de.fme_bus_specific; 2303*8aec9182Sstephh pci_fme_bs.pci_bs_type = ACC_HANDLE; 2304*8aec9182Sstephh pci_fme_bs.pci_bs_flags |= PCI_BS_ADDR_VALID; 2305*8aec9182Sstephh } 2306*8aec9182Sstephh de.fme_bus_specific = (void *)&pci_fme_bs; 2307*8aec9182Sstephh de.fme_bus_type = DDI_FME_BUS_TYPE_PCI; 2308*8aec9182Sstephh } 2309*8aec9182Sstephh 231000d0963fSdilpreet ASSERT(fmhdl); 231100d0963fSdilpreet 2312*8aec9182Sstephh if (de.fme_ena == NULL) 2313*8aec9182Sstephh de.fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 231400d0963fSdilpreet 231500d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 2316ac4d633fSstephh if (erpt_p == NULL) 231700d0963fSdilpreet return; 231800d0963fSdilpreet 2319*8aec9182Sstephh pci_regs_gather(dip, erpt_p, de.fme_flag); 2320*8aec9182Sstephh pci_error_report(dip, &de, erpt_p); 232100d0963fSdilpreet pci_regs_clear(erpt_p); 232200d0963fSdilpreet 2323*8aec9182Sstephh derr->fme_status = de.fme_status; 2324*8aec9182Sstephh derr->fme_ena = de.fme_ena; 2325*8aec9182Sstephh derr->fme_acc_handle = de.fme_acc_handle; 2326*8aec9182Sstephh derr->fme_dma_handle = de.fme_dma_handle; 232700d0963fSdilpreet if (xx_status != NULL) 232800d0963fSdilpreet *xx_status = erpt_p->pe_pci_regs->pci_err_status; 232900d0963fSdilpreet } 233000d0963fSdilpreet 233100d0963fSdilpreet /* 233200d0963fSdilpreet * private version of walk_devs() that can be used during panic. No 233300d0963fSdilpreet * sleeping or locking required. 233400d0963fSdilpreet */ 233500d0963fSdilpreet static int 233600d0963fSdilpreet pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg) 233700d0963fSdilpreet { 233800d0963fSdilpreet while (dip) { 233900d0963fSdilpreet switch ((*f)(dip, arg)) { 234000d0963fSdilpreet case DDI_WALK_TERMINATE: 234100d0963fSdilpreet return (DDI_WALK_TERMINATE); 234200d0963fSdilpreet case DDI_WALK_CONTINUE: 234300d0963fSdilpreet if (pci_fm_walk_devs(ddi_get_child(dip), f, 234400d0963fSdilpreet arg) == DDI_WALK_TERMINATE) 234500d0963fSdilpreet return (DDI_WALK_TERMINATE); 234600d0963fSdilpreet break; 234700d0963fSdilpreet case DDI_WALK_PRUNECHILD: 234800d0963fSdilpreet break; 234900d0963fSdilpreet } 235000d0963fSdilpreet dip = ddi_get_next_sibling(dip); 235100d0963fSdilpreet } 235200d0963fSdilpreet return (DDI_WALK_CONTINUE); 235300d0963fSdilpreet } 235400d0963fSdilpreet 235500d0963fSdilpreet /* 235600d0963fSdilpreet * need special version of ddi_fm_ereport_post() as the leaf driver may 235700d0963fSdilpreet * not be hardened. 235800d0963fSdilpreet */ 235900d0963fSdilpreet static void 236000d0963fSdilpreet pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena, 236100d0963fSdilpreet uint8_t version, ...) 236200d0963fSdilpreet { 236300d0963fSdilpreet char *name; 236400d0963fSdilpreet char device_path[MAXPATHLEN]; 236500d0963fSdilpreet char ddi_error_class[FM_MAX_CLASS]; 236600d0963fSdilpreet nvlist_t *ereport, *detector; 236700d0963fSdilpreet nv_alloc_t *nva; 236800d0963fSdilpreet errorq_elem_t *eqep; 236900d0963fSdilpreet va_list ap; 237000d0963fSdilpreet 237100d0963fSdilpreet if (panicstr) { 237200d0963fSdilpreet eqep = errorq_reserve(ereport_errorq); 237300d0963fSdilpreet if (eqep == NULL) 237400d0963fSdilpreet return; 237500d0963fSdilpreet ereport = errorq_elem_nvl(ereport_errorq, eqep); 237600d0963fSdilpreet nva = errorq_elem_nva(ereport_errorq, eqep); 237700d0963fSdilpreet detector = fm_nvlist_create(nva); 237800d0963fSdilpreet } else { 237900d0963fSdilpreet ereport = fm_nvlist_create(NULL); 238000d0963fSdilpreet detector = fm_nvlist_create(NULL); 238100d0963fSdilpreet } 238200d0963fSdilpreet 238300d0963fSdilpreet (void) ddi_pathname(dip, device_path); 238400d0963fSdilpreet fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, 238500d0963fSdilpreet device_path, NULL); 238600d0963fSdilpreet (void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s", 238700d0963fSdilpreet DDI_IO_CLASS, error_class); 238800d0963fSdilpreet fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL); 238900d0963fSdilpreet 239000d0963fSdilpreet va_start(ap, version); 239100d0963fSdilpreet name = va_arg(ap, char *); 239200d0963fSdilpreet (void) i_fm_payload_set(ereport, name, ap); 239300d0963fSdilpreet va_end(ap); 239400d0963fSdilpreet 239500d0963fSdilpreet if (panicstr) { 239600d0963fSdilpreet errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); 239700d0963fSdilpreet } else { 239800d0963fSdilpreet (void) fm_ereport_post(ereport, EVCH_TRYHARD); 239900d0963fSdilpreet fm_nvlist_destroy(ereport, FM_NVA_FREE); 240000d0963fSdilpreet fm_nvlist_destroy(detector, FM_NVA_FREE); 240100d0963fSdilpreet } 240200d0963fSdilpreet } 240300d0963fSdilpreet 240400d0963fSdilpreet static int 240500d0963fSdilpreet pci_check_regs(dev_info_t *dip, void *arg) 240600d0963fSdilpreet { 240700d0963fSdilpreet int reglen; 240800d0963fSdilpreet int rn; 240900d0963fSdilpreet int totreg; 241000d0963fSdilpreet pci_regspec_t *drv_regp; 241100d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 241200d0963fSdilpreet 241300d0963fSdilpreet if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 241400d0963fSdilpreet /* 241500d0963fSdilpreet * for config space, we need to check if the given address 241600d0963fSdilpreet * is a valid config space address for this device - based 241700d0963fSdilpreet * on pci_phys_hi of the config space entry in reg property. 241800d0963fSdilpreet */ 241900d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 242000d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 242100d0963fSdilpreet return (DDI_WALK_CONTINUE); 242200d0963fSdilpreet 242300d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 242400d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 242500d0963fSdilpreet if (tgt_err->tgt_pci_space == 242600d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) && 242700d0963fSdilpreet (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M | 242800d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M)) == 242900d0963fSdilpreet (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M | 243000d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M))) { 243100d0963fSdilpreet tgt_err->tgt_dip = dip; 243200d0963fSdilpreet kmem_free(drv_regp, reglen); 243300d0963fSdilpreet return (DDI_WALK_TERMINATE); 243400d0963fSdilpreet } 243500d0963fSdilpreet } 243600d0963fSdilpreet kmem_free(drv_regp, reglen); 243700d0963fSdilpreet } else { 243800d0963fSdilpreet /* 243900d0963fSdilpreet * for non config space, need to check reg to look 244000d0963fSdilpreet * for any non-relocable mapping, otherwise check 244100d0963fSdilpreet * assigned-addresses. 244200d0963fSdilpreet */ 244300d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 244400d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 244500d0963fSdilpreet return (DDI_WALK_CONTINUE); 244600d0963fSdilpreet 244700d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 244800d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 244900d0963fSdilpreet if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) && 245000d0963fSdilpreet (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 245100d0963fSdilpreet tgt_err->tgt_pci_space == 245200d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 245300d0963fSdilpreet (tgt_err->tgt_pci_addr >= 245400d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 245500d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 245600d0963fSdilpreet (tgt_err->tgt_pci_addr < 245700d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 245800d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 245900d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 246000d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 246100d0963fSdilpreet tgt_err->tgt_dip = dip; 246200d0963fSdilpreet kmem_free(drv_regp, reglen); 246300d0963fSdilpreet return (DDI_WALK_TERMINATE); 246400d0963fSdilpreet } 246500d0963fSdilpreet } 246600d0963fSdilpreet kmem_free(drv_regp, reglen); 246700d0963fSdilpreet 246800d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 246900d0963fSdilpreet "assigned-addresses", (caddr_t)&drv_regp, ®len) != 247000d0963fSdilpreet DDI_SUCCESS) 247100d0963fSdilpreet return (DDI_WALK_CONTINUE); 247200d0963fSdilpreet 247300d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 247400d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 247500d0963fSdilpreet if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 247600d0963fSdilpreet tgt_err->tgt_pci_space == 247700d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 247800d0963fSdilpreet (tgt_err->tgt_pci_addr >= 247900d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 248000d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 248100d0963fSdilpreet (tgt_err->tgt_pci_addr < 248200d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 248300d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 248400d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 248500d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 248600d0963fSdilpreet tgt_err->tgt_dip = dip; 248700d0963fSdilpreet kmem_free(drv_regp, reglen); 248800d0963fSdilpreet return (DDI_WALK_TERMINATE); 248900d0963fSdilpreet } 249000d0963fSdilpreet } 249100d0963fSdilpreet kmem_free(drv_regp, reglen); 249200d0963fSdilpreet } 249300d0963fSdilpreet return (DDI_WALK_CONTINUE); 249400d0963fSdilpreet } 249500d0963fSdilpreet 249600d0963fSdilpreet /* 249700d0963fSdilpreet * impl_fix_ranges - fixes the config space entry of the "ranges" 249800d0963fSdilpreet * property on psycho+ platforms. (if changing this function please make sure 249900d0963fSdilpreet * to change the pci_fix_ranges function in pcipsy.c) 250000d0963fSdilpreet */ 250100d0963fSdilpreet /*ARGSUSED*/ 250200d0963fSdilpreet static void 250300d0963fSdilpreet pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange) 250400d0963fSdilpreet { 250500d0963fSdilpreet #if defined(__sparc) 250600d0963fSdilpreet char *name = ddi_binding_name(dip); 250700d0963fSdilpreet 250800d0963fSdilpreet if ((strcmp(name, "pci108e,8000") == 0) || 250900d0963fSdilpreet (strcmp(name, "pci108e,a000") == 0) || 251000d0963fSdilpreet (strcmp(name, "pci108e,a001") == 0)) { 251100d0963fSdilpreet int i; 251200d0963fSdilpreet for (i = 0; i < nrange; i++, pci_ranges++) 251300d0963fSdilpreet if ((pci_ranges->child_high & PCI_REG_ADDR_M) == 251400d0963fSdilpreet PCI_ADDR_CONFIG) 251500d0963fSdilpreet pci_ranges->parent_low |= 251600d0963fSdilpreet pci_ranges->child_high; 251700d0963fSdilpreet } 251800d0963fSdilpreet #endif 251900d0963fSdilpreet } 252000d0963fSdilpreet 252100d0963fSdilpreet static int 252200d0963fSdilpreet pci_check_ranges(dev_info_t *dip, void *arg) 252300d0963fSdilpreet { 252400d0963fSdilpreet uint64_t range_parent_begin; 252500d0963fSdilpreet uint64_t range_parent_size; 252600d0963fSdilpreet uint64_t range_parent_end; 252700d0963fSdilpreet uint32_t space_type; 252800d0963fSdilpreet uint32_t bus_num; 252900d0963fSdilpreet uint32_t range_offset; 253000d0963fSdilpreet pci_ranges_t *pci_ranges, *rangep; 253100d0963fSdilpreet pci_bus_range_t *pci_bus_rangep; 253200d0963fSdilpreet int pci_ranges_length; 253300d0963fSdilpreet int nrange; 253400d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 253500d0963fSdilpreet int i, size; 253600d0963fSdilpreet if (strcmp(ddi_node_name(dip), "pci") != 0 && 253700d0963fSdilpreet strcmp(ddi_node_name(dip), "pciex") != 0) 253800d0963fSdilpreet return (DDI_WALK_CONTINUE); 253900d0963fSdilpreet 254000d0963fSdilpreet /* 254100d0963fSdilpreet * Get the ranges property. Note we only look at the top level pci 254200d0963fSdilpreet * node (hostbridge) which has a ranges property of type pci_ranges_t 254300d0963fSdilpreet * not at pci-pci bridges. 254400d0963fSdilpreet */ 254500d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 254600d0963fSdilpreet (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) { 254700d0963fSdilpreet /* 254800d0963fSdilpreet * no ranges property - no translation needed 254900d0963fSdilpreet */ 255000d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr; 255100d0963fSdilpreet tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN; 255200d0963fSdilpreet if (panicstr) 255300d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 255400d0963fSdilpreet pci_check_regs, (void *)tgt_err); 255500d0963fSdilpreet else { 255600d0963fSdilpreet int circ = 0; 255700d0963fSdilpreet ndi_devi_enter(dip, &circ); 255800d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 255900d0963fSdilpreet (void *)tgt_err); 256000d0963fSdilpreet ndi_devi_exit(dip, circ); 256100d0963fSdilpreet } 256200d0963fSdilpreet if (tgt_err->tgt_dip != NULL) 256300d0963fSdilpreet return (DDI_WALK_TERMINATE); 256400d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 256500d0963fSdilpreet } 256600d0963fSdilpreet nrange = pci_ranges_length / sizeof (pci_ranges_t); 256700d0963fSdilpreet rangep = pci_ranges; 256800d0963fSdilpreet 256900d0963fSdilpreet /* Need to fix the pci ranges property for psycho based systems */ 257000d0963fSdilpreet pci_fix_ranges(dip, pci_ranges, nrange); 257100d0963fSdilpreet 257200d0963fSdilpreet for (i = 0; i < nrange; i++, rangep++) { 257300d0963fSdilpreet range_parent_begin = ((uint64_t)rangep->parent_high << 32) + 257400d0963fSdilpreet rangep->parent_low; 257500d0963fSdilpreet range_parent_size = ((uint64_t)rangep->size_high << 32) + 257600d0963fSdilpreet rangep->size_low; 257700d0963fSdilpreet range_parent_end = range_parent_begin + range_parent_size - 1; 257800d0963fSdilpreet 257900d0963fSdilpreet if ((tgt_err->tgt_err_addr < range_parent_begin) || 258000d0963fSdilpreet (tgt_err->tgt_err_addr > range_parent_end)) { 258100d0963fSdilpreet /* Not in range */ 258200d0963fSdilpreet continue; 258300d0963fSdilpreet } 258400d0963fSdilpreet space_type = PCI_REG_ADDR_G(rangep->child_high); 258500d0963fSdilpreet if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 258600d0963fSdilpreet /* Config space address - check bus range */ 258700d0963fSdilpreet range_offset = tgt_err->tgt_err_addr - 258800d0963fSdilpreet range_parent_begin; 258900d0963fSdilpreet bus_num = PCI_REG_BUS_G(range_offset); 259000d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 259100d0963fSdilpreet DDI_PROP_DONTPASS, "bus-range", 259200d0963fSdilpreet (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) { 259300d0963fSdilpreet continue; 259400d0963fSdilpreet } 259500d0963fSdilpreet if ((bus_num < pci_bus_rangep->lo) || 259600d0963fSdilpreet (bus_num > pci_bus_rangep->hi)) { 259700d0963fSdilpreet /* 259800d0963fSdilpreet * Bus number not appropriate for this 259900d0963fSdilpreet * pci nexus. 260000d0963fSdilpreet */ 260100d0963fSdilpreet kmem_free(pci_bus_rangep, size); 260200d0963fSdilpreet continue; 260300d0963fSdilpreet } 260400d0963fSdilpreet kmem_free(pci_bus_rangep, size); 260500d0963fSdilpreet } 260600d0963fSdilpreet 260700d0963fSdilpreet /* We have a match if we get here - compute pci address */ 260800d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr - 260900d0963fSdilpreet range_parent_begin; 261000d0963fSdilpreet tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) + 261100d0963fSdilpreet rangep->child_low); 261200d0963fSdilpreet tgt_err->tgt_pci_space = space_type; 261300d0963fSdilpreet if (panicstr) 261400d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 261500d0963fSdilpreet pci_check_regs, (void *)tgt_err); 261600d0963fSdilpreet else { 261700d0963fSdilpreet int circ = 0; 261800d0963fSdilpreet ndi_devi_enter(dip, &circ); 261900d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 262000d0963fSdilpreet (void *)tgt_err); 262100d0963fSdilpreet ndi_devi_exit(dip, circ); 262200d0963fSdilpreet } 262300d0963fSdilpreet if (tgt_err->tgt_dip != NULL) { 262400d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 262500d0963fSdilpreet return (DDI_WALK_TERMINATE); 262600d0963fSdilpreet } 262700d0963fSdilpreet } 262800d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 262900d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 263000d0963fSdilpreet } 263100d0963fSdilpreet 263200d0963fSdilpreet /* 263300d0963fSdilpreet * Function used to drain pci_target_queue, either during panic or after softint 263400d0963fSdilpreet * is generated, to generate target device ereports based on captured physical 263500d0963fSdilpreet * addresses 263600d0963fSdilpreet */ 263700d0963fSdilpreet /*ARGSUSED*/ 263800d0963fSdilpreet static void 263900d0963fSdilpreet pci_target_drain(void *private_p, pci_target_err_t *tgt_err) 264000d0963fSdilpreet { 264100d0963fSdilpreet char buf[FM_MAX_CLASS]; 264200d0963fSdilpreet 264300d0963fSdilpreet /* 264400d0963fSdilpreet * The following assumes that all pci_pci bridge devices 264500d0963fSdilpreet * are configured as transparant. Find the top-level pci 264600d0963fSdilpreet * nexus which has tgt_err_addr in one of its ranges, converting this 264700d0963fSdilpreet * to a pci address in the process. Then starting at this node do 264800d0963fSdilpreet * another tree walk to find a device with the pci address we've 264900d0963fSdilpreet * found within range of one of it's assigned-addresses properties. 265000d0963fSdilpreet */ 265100d0963fSdilpreet tgt_err->tgt_dip = NULL; 265200d0963fSdilpreet if (panicstr) 265300d0963fSdilpreet (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges, 265400d0963fSdilpreet (void *)tgt_err); 265500d0963fSdilpreet else 265600d0963fSdilpreet ddi_walk_devs(ddi_root_node(), pci_check_ranges, 265700d0963fSdilpreet (void *)tgt_err); 265800d0963fSdilpreet if (tgt_err->tgt_dip == NULL) 265900d0963fSdilpreet return; 266000d0963fSdilpreet 266100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type, 266200d0963fSdilpreet tgt_err->tgt_err_class); 266300d0963fSdilpreet pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0, 266400d0963fSdilpreet PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL); 266500d0963fSdilpreet } 266600d0963fSdilpreet 266700d0963fSdilpreet void 266800d0963fSdilpreet pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr) 266900d0963fSdilpreet { 267000d0963fSdilpreet pci_target_err_t tgt_err; 267100d0963fSdilpreet 267200d0963fSdilpreet tgt_err.tgt_err_ena = ena; 267300d0963fSdilpreet tgt_err.tgt_err_class = class; 267400d0963fSdilpreet tgt_err.tgt_bridge_type = bridge_type; 267500d0963fSdilpreet tgt_err.tgt_err_addr = addr; 267600d0963fSdilpreet errorq_dispatch(pci_target_queue, (void *)&tgt_err, 267700d0963fSdilpreet sizeof (pci_target_err_t), ERRORQ_ASYNC); 267800d0963fSdilpreet } 267900d0963fSdilpreet 268000d0963fSdilpreet void 268100d0963fSdilpreet pci_targetq_init(void) 268200d0963fSdilpreet { 268300d0963fSdilpreet /* 268400d0963fSdilpreet * PCI target errorq, to schedule async handling of generation of 268500d0963fSdilpreet * target device ereports based on captured physical address. 268600d0963fSdilpreet * The errorq is created here but destroyed when _fini is called 268700d0963fSdilpreet * for the pci module. 268800d0963fSdilpreet */ 268900d0963fSdilpreet if (pci_target_queue == NULL) { 269000d0963fSdilpreet pci_target_queue = errorq_create("pci_target_queue", 269100d0963fSdilpreet (errorq_func_t)pci_target_drain, (void *)NULL, 269200d0963fSdilpreet TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL, 269300d0963fSdilpreet ERRORQ_VITAL); 269400d0963fSdilpreet if (pci_target_queue == NULL) 269500d0963fSdilpreet panic("failed to create required system error queue"); 269600d0963fSdilpreet } 269700d0963fSdilpreet } 2698