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 /* 23*2901c7f3Sstephh * Copyright 2008 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 */ 498aec9182Sstephh uint32_t pcie_expected_ce_mask = 0x0; 508aec9182Sstephh uint32_t pcie_expected_ue_mask = PCIE_AER_UCE_UC; 510c64a9b4Sanish #if defined(__sparc) 528aec9182Sstephh uint32_t pcie_expected_sue_mask = 0x0; 538aec9182Sstephh #else 548aec9182Sstephh uint32_t pcie_expected_sue_mask = PCIE_AER_SUCE_RCVD_MA; 558aec9182Sstephh #endif 560c64a9b4Sanish uint32_t pcie_aer_uce_log_bits = PCIE_AER_UCE_LOG_BITS; 578aec9182Sstephh #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, 808aec9182Sstephh #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, 1188aec9182Sstephh #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 1578aec9182Sstephh 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) { 1698aec9182Sstephh if (fme_flag == DDI_FM_ERR_UNEXPECTED) { 17000d0963fSdilpreet char buf[FM_MAX_CLASS]; 17100d0963fSdilpreet 1728aec9182Sstephh (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 1738aec9182Sstephh PCI_ERROR_SUBCLASS, PCI_NR); 1748aec9182Sstephh ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena, 1758aec9182Sstephh DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 1768aec9182Sstephh } 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, 1848aec9182Sstephh 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))); 1918aec9182Sstephh 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 2078aec9182Sstephh 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)); 2188aec9182Sstephh 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)); 2258aec9182Sstephh 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, 2408aec9182Sstephh 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, 2508aec9182Sstephh 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)); 2648aec9182Sstephh 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, 2738aec9182Sstephh pcix_cap_ptr, fme_flag); 27400d0963fSdilpreet } 27500d0963fSdilpreet } 27600d0963fSdilpreet } 27700d0963fSdilpreet 27800d0963fSdilpreet static void 2798aec9182Sstephh 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); 2908aec9182Sstephh 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)); 2978aec9182Sstephh pcie_regs->pcie_dev_cap = pci_config_get16(erpt_p->pe_hdl, 2988aec9182Sstephh (pcie_cap_ptr + PCIE_DEVCAP)); 29900d0963fSdilpreet 30000d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && (erpt_p->pe_dflags & 30100d0963fSdilpreet PCIX_DEV)) 3028aec9182Sstephh 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); 3228aec9182Sstephh 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); 3338aec9182Sstephh 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); 3468aec9182Sstephh 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); 3638aec9182Sstephh pcie_bdg_regs->pcie_sue_mask = 3648aec9182Sstephh pci_config_get32(erpt_p->pe_hdl, 3658aec9182Sstephh pcie_ecap_ptr + PCIE_AER_SUCE_MASK); 3668aec9182Sstephh 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 3718aec9182Sstephh 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)); 3978aec9182Sstephh 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)); 4068aec9182Sstephh 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 4138aec9182Sstephh 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); 4238aec9182Sstephh 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); 4288aec9182Sstephh 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); 4378aec9182Sstephh 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); 4428aec9182Sstephh 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) 4538aec9182Sstephh pcie_regs_gather(erpt_p, fme_flag); 45400d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 4558aec9182Sstephh 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); 7288aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) == 7298aec9182Sstephh 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 || 7548aec9182Sstephh (pci_config_check(erpt_p->pe_hdl, 7558aec9182Sstephh 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 */ 8918aec9182Sstephh 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 || 9005952c218Sanish dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) { 9015952c218Sanish erpt_p->pe_dflags |= PCIEX_SWITCH_DEV; 90200d0963fSdilpreet mask |= PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC; 9035952c218Sanish } 90400d0963fSdilpreet 90500d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_ue_mask != mask) { 90600d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 90700d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_MASK, mask); 90800d0963fSdilpreet } 90900d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 91000d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_adv_bdg_regs->pcie_sue_mask 91100d0963fSdilpreet != pcie_expected_sue_mask) { 91200d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 91300d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_MASK, 91400d0963fSdilpreet pcie_expected_sue_mask); 91500d0963fSdilpreet } 91600d0963fSdilpreet } 91700d0963fSdilpreet } 91800d0963fSdilpreet 91900d0963fSdilpreet /* 92000d0963fSdilpreet * pci_ereport_setup: Detect PCI device type and initialize structures to be 92100d0963fSdilpreet * used to generate ereports based on detected generic device errors. 92200d0963fSdilpreet */ 92300d0963fSdilpreet void 92400d0963fSdilpreet pci_ereport_setup(dev_info_t *dip) 92500d0963fSdilpreet { 92600d0963fSdilpreet struct dev_info *devi = DEVI(dip); 92700d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl; 92800d0963fSdilpreet pci_erpt_t *erpt_p; 92900d0963fSdilpreet uint8_t pci_hdr_type; 93000d0963fSdilpreet uint16_t pci_status; 93100d0963fSdilpreet pci_regspec_t *pci_rp; 93200d0963fSdilpreet int32_t len; 93300d0963fSdilpreet uint32_t phys_hi; 93400d0963fSdilpreet 93500d0963fSdilpreet /* 93600d0963fSdilpreet * If device is not ereport capbable then report an error against the 93700d0963fSdilpreet * driver for using this interface, 93800d0963fSdilpreet */ 93900d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 94000d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 94100d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 94200d0963fSdilpreet return; 94300d0963fSdilpreet } 94400d0963fSdilpreet 94500d0963fSdilpreet /* 94600d0963fSdilpreet * ASSERT fmhdl exists and fh_bus_specific is NULL. 94700d0963fSdilpreet */ 94800d0963fSdilpreet ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL)); 94900d0963fSdilpreet 95000d0963fSdilpreet erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP); 95100d0963fSdilpreet 95200d0963fSdilpreet if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS) 95300d0963fSdilpreet goto error; 95400d0963fSdilpreet 95500d0963fSdilpreet erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP); 95600d0963fSdilpreet 95700d0963fSdilpreet pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT); 9588aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) != 9598aec9182Sstephh DDI_FM_OK) 96000d0963fSdilpreet goto error; 96100d0963fSdilpreet 96200d0963fSdilpreet /* 96300d0963fSdilpreet * Get header type and record if device is a bridge. 96400d0963fSdilpreet */ 96500d0963fSdilpreet pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER); 9668aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) != 9678aec9182Sstephh DDI_FM_OK) 96800d0963fSdilpreet goto error; 96900d0963fSdilpreet 97000d0963fSdilpreet /* 97100d0963fSdilpreet * Check to see if PCI device is a bridge, if so allocate pci bridge 97200d0963fSdilpreet * error register structure. 97300d0963fSdilpreet */ 97400d0963fSdilpreet if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 97500d0963fSdilpreet erpt_p->pe_dflags |= PCI_BRIDGE_DEV; 97600d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc( 97700d0963fSdilpreet sizeof (pci_bdg_error_regs_t), KM_SLEEP); 97800d0963fSdilpreet } 97900d0963fSdilpreet 98000d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 98100d0963fSdilpreet (caddr_t)&pci_rp, &len) == DDI_SUCCESS) { 98200d0963fSdilpreet phys_hi = pci_rp->pci_phys_hi; 98300d0963fSdilpreet kmem_free(pci_rp, len); 98400d0963fSdilpreet 98500d0963fSdilpreet erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >> 98600d0963fSdilpreet PCI_REG_FUNC_SHIFT); 98700d0963fSdilpreet } 98800d0963fSdilpreet 98900d0963fSdilpreet 99000d0963fSdilpreet if (!(pci_status & PCI_STAT_CAP)) { 99100d0963fSdilpreet goto done; 99200d0963fSdilpreet } 99300d0963fSdilpreet 99400d0963fSdilpreet /* 99500d0963fSdilpreet * Initialize structures for PCI Express and PCI-X devices. 99600d0963fSdilpreet * Order matters below and pcie_ereport_setup should preceed 99700d0963fSdilpreet * pcix_ereport_setup. 99800d0963fSdilpreet */ 99900d0963fSdilpreet pcie_ereport_setup(dip, erpt_p); 100000d0963fSdilpreet 100100d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) { 100200d0963fSdilpreet pcix_ereport_setup(dip, erpt_p); 100300d0963fSdilpreet } 100400d0963fSdilpreet 100500d0963fSdilpreet done: 10068aec9182Sstephh pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED); 100700d0963fSdilpreet pci_regs_clear(erpt_p); 100800d0963fSdilpreet 100900d0963fSdilpreet /* 101000d0963fSdilpreet * Before returning set fh_bus_specific to completed pci_erpt_t 101100d0963fSdilpreet * structure 101200d0963fSdilpreet */ 101300d0963fSdilpreet fmhdl->fh_bus_specific = (void *)erpt_p; 101400d0963fSdilpreet 101500d0963fSdilpreet return; 101600d0963fSdilpreet error: 101700d0963fSdilpreet if (erpt_p->pe_pci_regs) 101800d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 101900d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 102000d0963fSdilpreet erpt_p = NULL; 102100d0963fSdilpreet } 102200d0963fSdilpreet 102300d0963fSdilpreet static void 102400d0963fSdilpreet pcix_ereport_teardown(pci_erpt_t *erpt_p) 102500d0963fSdilpreet { 102600d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 102700d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 102800d0963fSdilpreet uint16_t pcix_ver; 102900d0963fSdilpreet 103000d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 103100d0963fSdilpreet pcix_ver = pcix_bdg_regs->pcix_bdg_ver; 103200d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 103300d0963fSdilpreet int i; 103400d0963fSdilpreet for (i = 0; i < 2; i++) 103500d0963fSdilpreet kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i], 103600d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 103700d0963fSdilpreet } 103800d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t)); 103900d0963fSdilpreet } else { 104000d0963fSdilpreet pcix_error_regs_t *pcix_regs; 104100d0963fSdilpreet uint16_t pcix_ver; 104200d0963fSdilpreet 104300d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 104400d0963fSdilpreet pcix_ver = pcix_regs->pcix_ver; 104500d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 104600d0963fSdilpreet kmem_free(pcix_regs->pcix_ecc_regs, 104700d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 104800d0963fSdilpreet } 104900d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t)); 105000d0963fSdilpreet } 105100d0963fSdilpreet } 105200d0963fSdilpreet 105300d0963fSdilpreet static void 105400d0963fSdilpreet pcie_ereport_teardown(pci_erpt_t *erpt_p) 105500d0963fSdilpreet { 105600d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 105700d0963fSdilpreet 105800d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_ADV_DEV) { 105900d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv = pcie_regs->pcie_adv_regs; 106000d0963fSdilpreet 106100d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) 106200d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_bdg_regs, 106300d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t)); 106400d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 106500d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_rc_regs, 106600d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t)); 106700d0963fSdilpreet kmem_free(pcie_adv, sizeof (pcie_adv_error_regs_t)); 106800d0963fSdilpreet } 106900d0963fSdilpreet 107000d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 107100d0963fSdilpreet kmem_free(pcie_regs->pcie_rc_regs, 107200d0963fSdilpreet sizeof (pcie_rc_error_regs_t)); 107300d0963fSdilpreet 107400d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 107500d0963fSdilpreet if (erpt_p->pe_dflags & PCIX_DEV) { 107600d0963fSdilpreet uint16_t pcix_ver = pcie_regs->pcix_bdg_regs-> 107700d0963fSdilpreet pcix_bdg_ver; 107800d0963fSdilpreet 107900d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 108000d0963fSdilpreet int i; 108100d0963fSdilpreet for (i = 0; i < 2; i++) 108200d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs-> 108300d0963fSdilpreet pcix_bdg_ecc_regs[i], 108400d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 108500d0963fSdilpreet } 108600d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs, 108700d0963fSdilpreet sizeof (pcix_bdg_error_regs_t)); 108800d0963fSdilpreet } 108900d0963fSdilpreet } 109000d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcie_error_regs_t)); 109100d0963fSdilpreet } 109200d0963fSdilpreet 109300d0963fSdilpreet void 109400d0963fSdilpreet pci_ereport_teardown(dev_info_t *dip) 109500d0963fSdilpreet { 109600d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 109700d0963fSdilpreet pci_erpt_t *erpt_p; 109800d0963fSdilpreet 109900d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 110000d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 110100d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 110200d0963fSdilpreet } 110300d0963fSdilpreet 110400d0963fSdilpreet ASSERT(fmhdl); 110500d0963fSdilpreet 110600d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 110700d0963fSdilpreet if (erpt_p == NULL) 110800d0963fSdilpreet return; 110900d0963fSdilpreet 111000d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 111100d0963fSdilpreet pcie_ereport_teardown(erpt_p); 111200d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 111300d0963fSdilpreet pcix_ereport_teardown(erpt_p); 111400d0963fSdilpreet pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl); 111500d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) 111600d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs, 111700d0963fSdilpreet sizeof (pci_bdg_error_regs_t)); 111800d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 111900d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 112000d0963fSdilpreet fmhdl->fh_bus_specific = NULL; 112100d0963fSdilpreet /* 112200d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 112300d0963fSdilpreet * interfaces create the necessary properties for us. 112400d0963fSdilpreet */ 112500d0963fSdilpreet #if defined(__sparc) 112600d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcix-capid-pointer"); 112700d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-slotcap-reg"); 112800d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-reg"); 112900d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-pointer"); 113000d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-aer-pointer"); 113100d0963fSdilpreet #endif 113200d0963fSdilpreet } 113300d0963fSdilpreet 113400d0963fSdilpreet static void 113500d0963fSdilpreet pcie_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 113600d0963fSdilpreet char *buf, int errtype) 113700d0963fSdilpreet { 113800d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 113900d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 1140390e643aSdilpreet pcie_adv_rc_error_regs_t *pcie_adv_rc_regs; 114100d0963fSdilpreet 114200d0963fSdilpreet switch (errtype) { 114300d0963fSdilpreet case PCIEX_TYPE_CE: 114400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 114500d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 114600d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 114700d0963fSdilpreet pcie_regs->pcie_err_status, 114800d0963fSdilpreet PCIEX_CE_STATUS_REG, DATA_TYPE_UINT32, 114900d0963fSdilpreet pcie_adv_regs->pcie_ce_status, NULL); 115000d0963fSdilpreet break; 115100d0963fSdilpreet case PCIEX_TYPE_UE: 115200d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 115300d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 115400d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 115500d0963fSdilpreet pcie_regs->pcie_err_status, 115600d0963fSdilpreet PCIEX_UE_STATUS_REG, DATA_TYPE_UINT32, 115700d0963fSdilpreet pcie_adv_regs->pcie_ue_status, PCIEX_UE_SEV_REG, 115800d0963fSdilpreet DATA_TYPE_UINT32, pcie_adv_regs->pcie_ue_sev, 115900d0963fSdilpreet PCIEX_ADV_CTL, DATA_TYPE_UINT32, 116000d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl, 116100d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 116200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 116300d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 116400d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 116500d0963fSdilpreet 1 : NULL, 116600d0963fSdilpreet #ifdef DEBUG 116700d0963fSdilpreet PCIEX_UE_HDR0, DATA_TYPE_UINT32, 116800d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0, 116900d0963fSdilpreet PCIEX_UE_HDR1, DATA_TYPE_UINT32, 117000d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[0], 117100d0963fSdilpreet PCIEX_UE_HDR2, DATA_TYPE_UINT32, 117200d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[1], 117300d0963fSdilpreet PCIEX_UE_HDR3, DATA_TYPE_UINT32, 117400d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[2], 117500d0963fSdilpreet #endif 117600d0963fSdilpreet NULL); 117700d0963fSdilpreet break; 117800d0963fSdilpreet case PCIEX_TYPE_GEN: 117900d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 118000d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 118100d0963fSdilpreet 0, PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 118200d0963fSdilpreet pcie_regs->pcie_err_status, NULL); 118300d0963fSdilpreet break; 118400d0963fSdilpreet case PCIEX_TYPE_RC_UE_MSG: 118500d0963fSdilpreet case PCIEX_TYPE_RC_CE_MSG: 1186390e643aSdilpreet pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs; 1187390e643aSdilpreet 118800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 118900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 119000d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 119100d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, 119200d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 119300d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 119400d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id : 119500d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id, 119600d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 119700d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 119800d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 119900d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id != 0) : 120000d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 120100d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id != 0), NULL); 120200d0963fSdilpreet break; 120300d0963fSdilpreet case PCIEX_TYPE_RC_MULT_MSG: 1204390e643aSdilpreet pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs; 1205390e643aSdilpreet 120600d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 120700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 120800d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 120900d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, NULL); 121000d0963fSdilpreet break; 121100d0963fSdilpreet default: 121200d0963fSdilpreet break; 121300d0963fSdilpreet } 121400d0963fSdilpreet } 121500d0963fSdilpreet 12168aec9182Sstephh /*ARGSUSED*/ 121700d0963fSdilpreet static void 12188aec9182Sstephh pcie_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 121900d0963fSdilpreet { 12208aec9182Sstephh pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 122100d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 122200d0963fSdilpreet pcie_tlp_hdr_t *ue_hdr0; 122300d0963fSdilpreet uint32_t *ue_hdr; 122400d0963fSdilpreet uint64_t addr = NULL; 12258aec9182Sstephh int upstream = 0; 12268aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 12278aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 122800d0963fSdilpreet 12298aec9182Sstephh if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_UE_HDR_VALID)) 123000d0963fSdilpreet return; 12318aec9182Sstephh 123200d0963fSdilpreet ue_hdr0 = (pcie_tlp_hdr_t *)&pcie_adv_regs->pcie_ue_hdr0; 123300d0963fSdilpreet ue_hdr = pcie_adv_regs->pcie_ue_hdr; 123400d0963fSdilpreet 12358aec9182Sstephh if ((pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 12368aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_ROOT || 12378aec9182Sstephh (pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 12388aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_DOWN) 12398aec9182Sstephh upstream = 1; 12408aec9182Sstephh 124100d0963fSdilpreet switch (ue_hdr0->type) { 124200d0963fSdilpreet case PCIE_TLP_TYPE_MEM: 124300d0963fSdilpreet case PCIE_TLP_TYPE_MEMLK: 124400d0963fSdilpreet if ((ue_hdr0->fmt & 0x1) == 0x1) { 124500d0963fSdilpreet pcie_mem64_t *mem64_tlp = (pcie_mem64_t *)ue_hdr; 124600d0963fSdilpreet 124700d0963fSdilpreet addr = (uint64_t)mem64_tlp->addr1 << 32 | 124800d0963fSdilpreet (uint32_t)mem64_tlp->addr0 << 2; 124900d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = mem64_tlp->rid; 125000d0963fSdilpreet } else { 125100d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 125200d0963fSdilpreet 125300d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 125400d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 125500d0963fSdilpreet } 12568aec9182Sstephh if (upstream) { 12578aec9182Sstephh pci_fme_bsp->pci_bs_bdf = pcie_adv_regs->pcie_adv_bdf; 12588aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12598aec9182Sstephh } else if ((pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 12608aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { 12618aec9182Sstephh pci_fme_bsp->pci_bs_bdf = erpt_p->pe_bdf; 12628aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12638aec9182Sstephh } 12648aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 12658aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 12668aec9182Sstephh pci_fme_bsp->pci_bs_type = upstream ? DMA_HANDLE : ACC_HANDLE; 126700d0963fSdilpreet break; 126800d0963fSdilpreet 126900d0963fSdilpreet case PCIE_TLP_TYPE_IO: 127000d0963fSdilpreet { 127100d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 127200d0963fSdilpreet 127300d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 127400d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 12758aec9182Sstephh if ((pcie_regs->pcie_cap & 12768aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_MASK) == 12778aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { 12788aec9182Sstephh pci_fme_bsp->pci_bs_bdf = erpt_p->pe_bdf; 12798aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12808aec9182Sstephh } 12818aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 12828aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 12838aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 128400d0963fSdilpreet break; 128500d0963fSdilpreet } 128600d0963fSdilpreet case PCIE_TLP_TYPE_CFG0: 128700d0963fSdilpreet case PCIE_TLP_TYPE_CFG1: 128800d0963fSdilpreet { 128900d0963fSdilpreet pcie_cfg_t *cfg_tlp = (pcie_cfg_t *)ue_hdr; 129000d0963fSdilpreet 1291ac4d633fSstephh pcie_adv_regs->pcie_adv_bdf = cfg_tlp->rid; 12928aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (uint16_t)cfg_tlp->bus << 8 | 12938aec9182Sstephh (uint16_t)cfg_tlp->dev << 3 | cfg_tlp->func; 12948aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12958aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 129600d0963fSdilpreet break; 129700d0963fSdilpreet } 129800d0963fSdilpreet case PCIE_TLP_TYPE_MSG: 129900d0963fSdilpreet { 130000d0963fSdilpreet pcie_msg_t *msg_tlp = (pcie_msg_t *)ue_hdr; 130100d0963fSdilpreet 130200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = msg_tlp->rid; 130300d0963fSdilpreet break; 130400d0963fSdilpreet } 130500d0963fSdilpreet case PCIE_TLP_TYPE_CPL: 130600d0963fSdilpreet case PCIE_TLP_TYPE_CPLLK: 130700d0963fSdilpreet { 130800d0963fSdilpreet pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)ue_hdr; 130900d0963fSdilpreet 131000d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = cpl_tlp->cid; 13118aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 13128aec9182Sstephh if (upstream) { 13138aec9182Sstephh pci_fme_bsp->pci_bs_bdf = cpl_tlp->cid; 13148aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 13158aec9182Sstephh } else { 13168aec9182Sstephh pci_fme_bsp->pci_bs_bdf = cpl_tlp->rid; 13178aec9182Sstephh pci_fme_bsp->pci_bs_type = DMA_HANDLE; 13188aec9182Sstephh } 131900d0963fSdilpreet break; 132000d0963fSdilpreet } 132100d0963fSdilpreet case PCIE_TLP_TYPE_MSI: 132200d0963fSdilpreet default: 13238aec9182Sstephh break; 13248aec9182Sstephh } 132500d0963fSdilpreet } 132600d0963fSdilpreet 13278aec9182Sstephh /*ARGSUSED*/ 132800d0963fSdilpreet static void 13298aec9182Sstephh pcie_pci_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 13308aec9182Sstephh int type) 133100d0963fSdilpreet { 13328aec9182Sstephh pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 133300d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 133400d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 133500d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 133600d0963fSdilpreet uint64_t addr = NULL; 133700d0963fSdilpreet pcix_attr_t *pcie_pci_sue_attr; 133800d0963fSdilpreet int cmd; 133900d0963fSdilpreet int dual_addr = 0; 13408aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 13418aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 134200d0963fSdilpreet 13438aec9182Sstephh if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_HDR_VALID)) 134400d0963fSdilpreet return; 134500d0963fSdilpreet 134600d0963fSdilpreet pcie_pci_sue_attr = (pcix_attr_t *)&pcie_bdg_regs->pcie_sue_hdr0; 134700d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 134800d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK; 13498aec9182Sstephh 135000d0963fSdilpreet cmd_switch: 13518aec9182Sstephh addr = pcie_bdg_regs->pcie_sue_hdr[2]; 13528aec9182Sstephh addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) | 13538aec9182Sstephh pcie_bdg_regs->pcie_sue_hdr[1]; 135400d0963fSdilpreet switch (cmd) { 135500d0963fSdilpreet case PCI_PCIX_CMD_IORD: 135600d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 135700d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 13588aec9182Sstephh if (addr) { 13598aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 13608aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 13618aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 13628aec9182Sstephh } 136300d0963fSdilpreet break; 136400d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 136500d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 136600d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 136700d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 136800d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 136900d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 137000d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 13718aec9182Sstephh if (addr) { 13728aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 13738aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 13748aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 13758aec9182Sstephh } 137600d0963fSdilpreet break; 137700d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 137800d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 1379ac4d633fSstephh pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 13808aec9182Sstephh /* 13818aec9182Sstephh * for type 1 config transaction we can find bdf from address 13828aec9182Sstephh */ 13838aec9182Sstephh if ((addr & 3) == 1) { 13848aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff; 13858aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 13868aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 13878aec9182Sstephh } 13888aec9182Sstephh break; 13898aec9182Sstephh case PCI_PCIX_CMD_SPL: 13908aec9182Sstephh pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 13918aec9182Sstephh if (type == ACC_HANDLE) { 13928aec9182Sstephh pci_fme_bsp->pci_bs_bdf = pcie_adv_regs->pcie_adv_bdf; 13938aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 13948aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 13958aec9182Sstephh } 139600d0963fSdilpreet break; 139700d0963fSdilpreet case PCI_PCIX_CMD_DADR: 139800d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 139900d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) & 140000d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_MASK; 140100d0963fSdilpreet if (dual_addr) 140200d0963fSdilpreet break; 140300d0963fSdilpreet ++dual_addr; 140400d0963fSdilpreet goto cmd_switch; 140500d0963fSdilpreet default: 14068aec9182Sstephh break; 14078aec9182Sstephh } 140800d0963fSdilpreet } 140900d0963fSdilpreet 14108aec9182Sstephh /*ARGSUSED*/ 141100d0963fSdilpreet static int 141200d0963fSdilpreet pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, 14138aec9182Sstephh pcix_ecc_regs_t *pcix_ecc_regs, int type) 141400d0963fSdilpreet { 141500d0963fSdilpreet int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf; 141600d0963fSdilpreet uint64_t addr; 14178aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 14188aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 141900d0963fSdilpreet 142000d0963fSdilpreet addr = pcix_ecc_regs->pcix_ecc_secaddr; 142100d0963fSdilpreet addr = addr << 32; 142200d0963fSdilpreet addr |= pcix_ecc_regs->pcix_ecc_fstaddr; 142300d0963fSdilpreet 142400d0963fSdilpreet switch (cmd) { 142500d0963fSdilpreet case PCI_PCIX_CMD_INTR: 142600d0963fSdilpreet case PCI_PCIX_CMD_SPEC: 142700d0963fSdilpreet return (DDI_FM_FATAL); 142800d0963fSdilpreet case PCI_PCIX_CMD_IORD: 142900d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 14308aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 14318aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 14328aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 14338aec9182Sstephh return (DDI_FM_UNKNOWN); 143400d0963fSdilpreet case PCI_PCIX_CMD_DEVID: 143500d0963fSdilpreet return (DDI_FM_FATAL); 143600d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 143700d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 143800d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 143900d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 14408aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 14418aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 14428aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 14438aec9182Sstephh return (DDI_FM_UNKNOWN); 144400d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 144500d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 14468aec9182Sstephh /* 14478aec9182Sstephh * for type 1 config transaction we can find bdf from address 14488aec9182Sstephh */ 14498aec9182Sstephh if ((addr & 3) == 1) { 14508aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff; 14518aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 14528aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 14538aec9182Sstephh } 14548aec9182Sstephh return (DDI_FM_UNKNOWN); 145500d0963fSdilpreet case PCI_PCIX_CMD_SPL: 145600d0963fSdilpreet case PCI_PCIX_CMD_DADR: 14578aec9182Sstephh return (DDI_FM_UNKNOWN); 145800d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 145900d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 14608aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 14618aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 14628aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 14638aec9182Sstephh return (DDI_FM_UNKNOWN); 146400d0963fSdilpreet default: 146500d0963fSdilpreet return (DDI_FM_FATAL); 146600d0963fSdilpreet } 146700d0963fSdilpreet } 146800d0963fSdilpreet 146900d0963fSdilpreet /*ARGSUSED*/ 147000d0963fSdilpreet static int 147100d0963fSdilpreet pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 147200d0963fSdilpreet { 147300d0963fSdilpreet pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs; 147400d0963fSdilpreet int fatal = 0; 147500d0963fSdilpreet int nonfatal = 0; 147600d0963fSdilpreet int unknown = 0; 147700d0963fSdilpreet int ok = 0; 147800d0963fSdilpreet int ret = DDI_FM_OK; 147900d0963fSdilpreet char buf[FM_MAX_CLASS]; 148000d0963fSdilpreet int i; 14818aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 14828aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 148300d0963fSdilpreet 148400d0963fSdilpreet if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) 148500d0963fSdilpreet goto done; 148600d0963fSdilpreet 148700d0963fSdilpreet if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) && 148800d0963fSdilpreet (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) { 148900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 149000d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_DTO); 149100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 149200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 149300d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 149400d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 149500d0963fSdilpreet DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL); 149600d0963fSdilpreet unknown++; 149700d0963fSdilpreet } 149800d0963fSdilpreet 149900d0963fSdilpreet if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) { 150000d0963fSdilpreet for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) { 150100d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & 150200d0963fSdilpreet pci_bdg_err_tbl[i].reg_bit) { 150300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 150400d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, 150500d0963fSdilpreet pci_bdg_err_tbl[i].err_class); 150600d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 150700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 150800d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 150900d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 151000d0963fSdilpreet DATA_TYPE_UINT16, 151100d0963fSdilpreet pci_bdg_regs->pci_bdg_ctrl, NULL); 1512ac4d633fSstephh PCI_FM_SEV_INC(pci_bdg_err_tbl[i].flags); 15138aec9182Sstephh if (pci_fme_bsp && (pci_fme_bsp->pci_bs_flags & 15148aec9182Sstephh PCI_BS_ADDR_VALID) && 15158aec9182Sstephh pci_fme_bsp->pci_bs_type == ACC_HANDLE && 151600d0963fSdilpreet pci_bdg_err_tbl[i].terr_class) 151700d0963fSdilpreet pci_target_enqueue(derr->fme_ena, 151800d0963fSdilpreet pci_bdg_err_tbl[i].terr_class, 151900d0963fSdilpreet PCI_ERROR_SUBCLASS, 15208aec9182Sstephh pci_fme_bsp->pci_bs_addr); 152100d0963fSdilpreet } 152200d0963fSdilpreet } 1523ac4d633fSstephh #if !defined(__sparc) 1524ac4d633fSstephh /* 1525ac4d633fSstephh * For x86, many drivers and even user-level code currently get 1526ac4d633fSstephh * away with accessing bad addresses, getting a UR and getting 1527ac4d633fSstephh * -1 returned. Unfortunately, we have no control over this, so 1528ac4d633fSstephh * we will have to treat all URs as nonfatal. Moreover, if the 1529ac4d633fSstephh * leaf driver is non-hardened, then we don't actually see the 1530ac4d633fSstephh * UR directly. All we see is a secondary bus master abort at 1531ac4d633fSstephh * the root complex - so it's this condition that we actually 1532ac4d633fSstephh * need to treat as nonfatal (providing no other unrelated nfe 1533ac4d633fSstephh * conditions have also been seen by the root complex). 1534ac4d633fSstephh */ 1535ac4d633fSstephh if ((erpt_p->pe_dflags & PCIEX_RC_DEV) && 1536ac4d633fSstephh (pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_R_MAST_AB) && 1537ac4d633fSstephh !(pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_S_PERROR)) { 1538ac4d633fSstephh pcie_error_regs_t *pcie_regs = 1539ac4d633fSstephh (pcie_error_regs_t *)erpt_p->pe_regs; 1540ac4d633fSstephh if ((pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) && 1541ac4d633fSstephh !(pcie_regs->pcie_err_status & 1542ac4d633fSstephh PCIE_DEVSTS_NFE_DETECTED)) 1543ac4d633fSstephh nonfatal++; 1544*2901c7f3Sstephh if (erpt_p->pe_dflags & PCIEX_ADV_DEV) { 1545*2901c7f3Sstephh pcie_adv_error_regs_t *pcie_adv_regs = 1546*2901c7f3Sstephh pcie_regs->pcie_adv_regs; 1547*2901c7f3Sstephh pcie_adv_rc_error_regs_t *pcie_rc_regs = 1548*2901c7f3Sstephh pcie_adv_regs->pcie_adv_rc_regs; 1549*2901c7f3Sstephh if ((pcie_adv_regs->pcie_adv_vflags & 1550*2901c7f3Sstephh PCIE_RC_ERR_STATUS_VALID) && 1551*2901c7f3Sstephh (pcie_rc_regs->pcie_rc_err_status & 1552*2901c7f3Sstephh PCIE_AER_RE_STS_NFE_MSGS_RCVD)) { 1553*2901c7f3Sstephh (void) snprintf(buf, FM_MAX_CLASS, 1554*2901c7f3Sstephh "%s.%s-%s", PCI_ERROR_SUBCLASS, 1555*2901c7f3Sstephh PCI_SEC_ERROR_SUBCLASS, PCI_MA); 1556*2901c7f3Sstephh ddi_fm_ereport_post(dip, buf, 1557*2901c7f3Sstephh derr->fme_ena, DDI_NOSLEEP, 1558*2901c7f3Sstephh FM_VERSION, DATA_TYPE_UINT8, 0, 1559*2901c7f3Sstephh PCI_SEC_CONFIG_STATUS, 1560*2901c7f3Sstephh DATA_TYPE_UINT16, 1561*2901c7f3Sstephh pci_bdg_regs->pci_bdg_sec_stat, 1562*2901c7f3Sstephh PCI_BCNTRL, DATA_TYPE_UINT16, 1563*2901c7f3Sstephh pci_bdg_regs->pci_bdg_ctrl, NULL); 1564*2901c7f3Sstephh } 1565*2901c7f3Sstephh } 1566ac4d633fSstephh } 1567ac4d633fSstephh #endif 156800d0963fSdilpreet } 156900d0963fSdilpreet 157000d0963fSdilpreet done: 157100d0963fSdilpreet /* 157200d0963fSdilpreet * Need to check for poke and cautious put. We already know peek 157300d0963fSdilpreet * and cautious get errors occurred (as we got a trap) and we know 157400d0963fSdilpreet * they are nonfatal. 157500d0963fSdilpreet */ 157600d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_EXPECTED) { 157700d0963fSdilpreet /* 157800d0963fSdilpreet * for cautious puts we treat all errors as nonfatal. Actually 157900d0963fSdilpreet * we set nonfatal for cautious gets as well - doesn't do any 158000d0963fSdilpreet * harm 158100d0963fSdilpreet */ 158200d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 158300d0963fSdilpreet PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR)) 158400d0963fSdilpreet nonfatal++; 158500d0963fSdilpreet } 158600d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_POKE) { 158700d0963fSdilpreet /* 158800d0963fSdilpreet * special case for pokes - we only consider master abort 158900d0963fSdilpreet * and target abort as nonfatal. Sserr with no master abort is 159000d0963fSdilpreet * fatal, but master/target abort can come in on separate 159100d0963fSdilpreet * instance, so return unknown and parent will determine if 159200d0963fSdilpreet * nonfatal (if another child returned nonfatal - ie master 159300d0963fSdilpreet * or target abort) or fatal otherwise 159400d0963fSdilpreet */ 159500d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 159600d0963fSdilpreet PCI_STAT_R_MAST_AB)) 159700d0963fSdilpreet nonfatal++; 159800d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR) 159900d0963fSdilpreet unknown++; 160000d0963fSdilpreet } 160100d0963fSdilpreet 160200d0963fSdilpreet /* 16038aec9182Sstephh * now check children below the bridge 160400d0963fSdilpreet */ 160500d0963fSdilpreet ret = ndi_fm_handler_dispatch(dip, NULL, derr); 160600d0963fSdilpreet PCI_FM_SEV_INC(ret); 160700d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 160800d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 160900d0963fSdilpreet } 161000d0963fSdilpreet 161100d0963fSdilpreet static int 161200d0963fSdilpreet pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 161300d0963fSdilpreet void *pe_regs) 161400d0963fSdilpreet { 161500d0963fSdilpreet pcix_error_regs_t *pcix_regs; 161600d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 161700d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs; 161800d0963fSdilpreet int bridge; 161900d0963fSdilpreet int i; 162000d0963fSdilpreet int ecc_phase; 162100d0963fSdilpreet int ecc_corr; 162200d0963fSdilpreet int sec_ue; 162300d0963fSdilpreet int sec_ce; 162400d0963fSdilpreet int fatal = 0; 162500d0963fSdilpreet int nonfatal = 0; 162600d0963fSdilpreet int unknown = 0; 162700d0963fSdilpreet int ok = 0; 162800d0963fSdilpreet char buf[FM_MAX_CLASS]; 162900d0963fSdilpreet 163000d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 163100d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 163200d0963fSdilpreet bridge = 1; 163300d0963fSdilpreet } else { 163400d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)pe_regs; 163500d0963fSdilpreet bridge = 0; 163600d0963fSdilpreet } 163700d0963fSdilpreet 163800d0963fSdilpreet for (i = 0; i < (bridge ? 2 : 1); i++) { 163900d0963fSdilpreet int ret = DDI_FM_OK; 164000d0963fSdilpreet pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] : 164100d0963fSdilpreet pcix_regs->pcix_ecc_regs; 164200d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) { 164300d0963fSdilpreet ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat & 164400d0963fSdilpreet PCI_PCIX_ECC_PHASE) >> 0x4; 164500d0963fSdilpreet ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat & 164600d0963fSdilpreet PCI_PCIX_ECC_CORR); 164700d0963fSdilpreet sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat & 164800d0963fSdilpreet PCI_PCIX_ECC_S_UE); 164900d0963fSdilpreet sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat & 165000d0963fSdilpreet PCI_PCIX_ECC_S_CE); 165100d0963fSdilpreet 165200d0963fSdilpreet switch (ecc_phase) { 165300d0963fSdilpreet case PCI_PCIX_ECC_PHASE_NOERR: 165400d0963fSdilpreet break; 165500d0963fSdilpreet case PCI_PCIX_ECC_PHASE_FADDR: 165600d0963fSdilpreet case PCI_PCIX_ECC_PHASE_SADDR: 1657ac4d633fSstephh PCI_FM_SEV_INC(ecc_corr ? DDI_FM_OK : 165800d0963fSdilpreet DDI_FM_FATAL); 165900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 166000d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 166100d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 166200d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ADDR : 166300d0963fSdilpreet PCIX_ECC_UE_ADDR); 166400d0963fSdilpreet break; 166500d0963fSdilpreet case PCI_PCIX_ECC_PHASE_ATTR: 166600d0963fSdilpreet PCI_FM_SEV_INC(ecc_corr ? 1667ac4d633fSstephh DDI_FM_OK : DDI_FM_FATAL); 166800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 166900d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 167000d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 167100d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ATTR : 167200d0963fSdilpreet PCIX_ECC_UE_ATTR); 167300d0963fSdilpreet break; 167400d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA32: 167500d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA64: 167600d0963fSdilpreet if (ecc_corr) 1677ac4d633fSstephh ret = DDI_FM_OK; 16788aec9182Sstephh else { 16798aec9182Sstephh int type; 16808aec9182Sstephh pci_error_regs_t *pci_regs = 16818aec9182Sstephh erpt_p->pe_pci_regs; 16828aec9182Sstephh 16838aec9182Sstephh if (i) { 16848aec9182Sstephh if (pci_regs->pci_bdg_regs-> 16858aec9182Sstephh pci_bdg_sec_stat & 16868aec9182Sstephh PCI_STAT_S_PERROR) 16878aec9182Sstephh type = ACC_HANDLE; 168800d0963fSdilpreet else 16898aec9182Sstephh type = DMA_HANDLE; 16908aec9182Sstephh } else { 16918aec9182Sstephh if (pci_regs->pci_err_status & 16928aec9182Sstephh PCI_STAT_S_PERROR) 16938aec9182Sstephh type = DMA_HANDLE; 16948aec9182Sstephh else 16958aec9182Sstephh type = ACC_HANDLE; 16968aec9182Sstephh } 169700d0963fSdilpreet ret = pcix_check_addr(dip, derr, 16988aec9182Sstephh pcix_ecc_regs, type); 16998aec9182Sstephh } 170000d0963fSdilpreet PCI_FM_SEV_INC(ret); 170100d0963fSdilpreet 170200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 170300d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 170400d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 170500d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_DATA : 170600d0963fSdilpreet PCIX_ECC_UE_DATA); 170700d0963fSdilpreet break; 170800d0963fSdilpreet } 170900d0963fSdilpreet if (ecc_phase) 171000d0963fSdilpreet if (bridge) 171100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 171200d0963fSdilpreet derr->fme_ena, 171300d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 171400d0963fSdilpreet DATA_TYPE_UINT8, 0, 171500d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 171600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 171700d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 171800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 171900d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 172000d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 172100d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 172200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 172300d0963fSdilpreet else 172400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 172500d0963fSdilpreet derr->fme_ena, 172600d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 172700d0963fSdilpreet DATA_TYPE_UINT8, 0, 172800d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 172900d0963fSdilpreet pcix_regs->pcix_command, 173000d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 173100d0963fSdilpreet pcix_regs->pcix_status, 173200d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 173300d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 173400d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 173500d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 173600d0963fSdilpreet if (sec_ce || sec_ue) { 173700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 173800d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 173900d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 174000d0963fSdilpreet sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE); 174100d0963fSdilpreet if (bridge) 174200d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 174300d0963fSdilpreet derr->fme_ena, 174400d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 174500d0963fSdilpreet DATA_TYPE_UINT8, 0, 174600d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 174700d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 174800d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 174900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 175000d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 175100d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 175200d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 175300d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 175400d0963fSdilpreet else 175500d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 175600d0963fSdilpreet derr->fme_ena, 175700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 175800d0963fSdilpreet DATA_TYPE_UINT8, 0, 175900d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 176000d0963fSdilpreet pcix_regs->pcix_command, 176100d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 176200d0963fSdilpreet pcix_regs->pcix_status, 176300d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 176400d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 176500d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 176600d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 176700d0963fSdilpreet PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL : 1768ac4d633fSstephh DDI_FM_OK); 176900d0963fSdilpreet } 177000d0963fSdilpreet } 177100d0963fSdilpreet } 177200d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 177300d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 177400d0963fSdilpreet } 177500d0963fSdilpreet 177600d0963fSdilpreet static int 177700d0963fSdilpreet pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 177800d0963fSdilpreet void *pe_regs) 177900d0963fSdilpreet { 178000d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 178100d0963fSdilpreet int fatal = 0; 178200d0963fSdilpreet int nonfatal = 0; 178300d0963fSdilpreet int unknown = 0; 178400d0963fSdilpreet int ok = 0; 178500d0963fSdilpreet char buf[FM_MAX_CLASS]; 178600d0963fSdilpreet int i; 178700d0963fSdilpreet 178800d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) { 178900d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 179000d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_stat & 179100d0963fSdilpreet pcix_err_tbl[i].reg_bit)) { 179200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 179300d0963fSdilpreet PCIX_ERROR_SUBCLASS, 179400d0963fSdilpreet pcix_err_tbl[i].err_class); 179500d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 179600d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 179700d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 179800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 179900d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 180000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 180100d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 180200d0963fSdilpreet } 180300d0963fSdilpreet } 180400d0963fSdilpreet } 180500d0963fSdilpreet 180600d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) { 180700d0963fSdilpreet for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) { 180800d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_sec_stat & 180900d0963fSdilpreet pcix_sec_err_tbl[i].reg_bit)) { 181000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s", 181100d0963fSdilpreet PCIX_ERROR_SUBCLASS, 181200d0963fSdilpreet PCIX_SEC_ERROR_SUBCLASS, 181300d0963fSdilpreet pcix_sec_err_tbl[i].err_class); 181400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 181500d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 181600d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 181700d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 181800d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 181900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 182000d0963fSdilpreet PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags); 182100d0963fSdilpreet } 182200d0963fSdilpreet } 182300d0963fSdilpreet } 182400d0963fSdilpreet 182500d0963fSdilpreet /* Log/Handle ECC errors */ 182600d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 182700d0963fSdilpreet int ret; 182800d0963fSdilpreet 182900d0963fSdilpreet ret = pcix_ecc_error_report(dip, derr, erpt_p, 183000d0963fSdilpreet (void *)pcix_bdg_regs); 183100d0963fSdilpreet PCI_FM_SEV_INC(ret); 183200d0963fSdilpreet } 183300d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 183400d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 183500d0963fSdilpreet } 183600d0963fSdilpreet 183700d0963fSdilpreet static int 183800d0963fSdilpreet pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 183900d0963fSdilpreet { 184000d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 184100d0963fSdilpreet int fatal = 0; 184200d0963fSdilpreet int nonfatal = 0; 184300d0963fSdilpreet int unknown = 0; 184400d0963fSdilpreet int ok = 0; 184500d0963fSdilpreet char buf[FM_MAX_CLASS]; 184600d0963fSdilpreet int i; 184700d0963fSdilpreet 184800d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) { 184900d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 185000d0963fSdilpreet if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit)) 185100d0963fSdilpreet continue; 185200d0963fSdilpreet 185300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 185400d0963fSdilpreet PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class); 185500d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 185600d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 185700d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 185800d0963fSdilpreet pcix_regs->pcix_command, PCIX_STATUS, 185900d0963fSdilpreet DATA_TYPE_UINT32, pcix_regs->pcix_status, 186000d0963fSdilpreet NULL); 186100d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 186200d0963fSdilpreet } 186300d0963fSdilpreet } 186400d0963fSdilpreet /* Log/Handle ECC errors */ 186500d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 186600d0963fSdilpreet int ret = pcix_ecc_error_report(dip, derr, erpt_p, 186700d0963fSdilpreet (void *)pcix_regs); 186800d0963fSdilpreet PCI_FM_SEV_INC(ret); 186900d0963fSdilpreet } 187000d0963fSdilpreet 187100d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 187200d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 187300d0963fSdilpreet } 187400d0963fSdilpreet 187500d0963fSdilpreet static int 187600d0963fSdilpreet pcie_rc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 187700d0963fSdilpreet void *pe_regs) 187800d0963fSdilpreet { 187900d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = (pcie_adv_error_regs_t *)pe_regs; 188000d0963fSdilpreet int fatal = 0; 188100d0963fSdilpreet int nonfatal = 0; 188200d0963fSdilpreet int unknown = 0; 188300d0963fSdilpreet char buf[FM_MAX_CLASS]; 188400d0963fSdilpreet 188500d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) { 188600d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 188700d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 188800d0963fSdilpreet int ce, ue, mult_ce, mult_ue, first_ue_fatal, nfe, fe; 188900d0963fSdilpreet 189000d0963fSdilpreet ce = pcie_rc_regs->pcie_rc_err_status & 189100d0963fSdilpreet PCIE_AER_RE_STS_CE_RCVD; 189200d0963fSdilpreet ue = pcie_rc_regs->pcie_rc_err_status & 189300d0963fSdilpreet PCIE_AER_RE_STS_FE_NFE_RCVD; 189400d0963fSdilpreet mult_ce = pcie_rc_regs->pcie_rc_err_status & 189500d0963fSdilpreet PCIE_AER_RE_STS_MUL_CE_RCVD; 189600d0963fSdilpreet mult_ue = pcie_rc_regs->pcie_rc_err_status & 189700d0963fSdilpreet PCIE_AER_RE_STS_MUL_FE_NFE_RCVD; 189800d0963fSdilpreet first_ue_fatal = pcie_rc_regs->pcie_rc_err_status & 189900d0963fSdilpreet PCIE_AER_RE_STS_FIRST_UC_FATAL; 190000d0963fSdilpreet nfe = pcie_rc_regs->pcie_rc_err_status & 190100d0963fSdilpreet PCIE_AER_RE_STS_NFE_MSGS_RCVD; 190200d0963fSdilpreet fe = pcie_rc_regs->pcie_rc_err_status & 190300d0963fSdilpreet PCIE_AER_RE_STS_FE_MSGS_RCVD; 190400d0963fSdilpreet /* 190500d0963fSdilpreet * log fatal/nonfatal/corrected messages 190600d0963fSdilpreet * recieved by root complex 190700d0963fSdilpreet */ 190800d0963fSdilpreet if (ue && fe) 190900d0963fSdilpreet fatal++; 191000d0963fSdilpreet 191100d0963fSdilpreet if (fe && first_ue_fatal) { 191200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 191300d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_FE_MSG); 191400d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 191500d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 191600d0963fSdilpreet } 191700d0963fSdilpreet if (nfe && !first_ue_fatal) { 191800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 191900d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_NFE_MSG); 192000d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 192100d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 192200d0963fSdilpreet } 192300d0963fSdilpreet if (ce) { 192400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 192500d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_CE_MSG); 192600d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 192700d0963fSdilpreet PCIEX_TYPE_RC_CE_MSG); 192800d0963fSdilpreet } 192900d0963fSdilpreet if (mult_ce) { 193000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 193100d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MCE_MSG); 193200d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 193300d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 193400d0963fSdilpreet } 193500d0963fSdilpreet if (mult_ue) { 193600d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 193700d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MUE_MSG); 193800d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 193900d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 194000d0963fSdilpreet } 194100d0963fSdilpreet } 194200d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 194300d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 194400d0963fSdilpreet } 194500d0963fSdilpreet 194600d0963fSdilpreet static int 194700d0963fSdilpreet pcie_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 194800d0963fSdilpreet { 194900d0963fSdilpreet int fatal = 0; 195000d0963fSdilpreet int nonfatal = 0; 195100d0963fSdilpreet int unknown = 0; 195200d0963fSdilpreet int ok = 0; 19538aec9182Sstephh int type; 195400d0963fSdilpreet char buf[FM_MAX_CLASS]; 195500d0963fSdilpreet int i; 195600d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 195700d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 195800d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs; 195900d0963fSdilpreet 196000d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 196100d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 196200d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, erpt_p, 196300d0963fSdilpreet (void *)pcie_regs->pcix_bdg_regs); 196400d0963fSdilpreet PCI_FM_SEV_INC(ret); 196500d0963fSdilpreet } 196600d0963fSdilpreet 196700d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 196800d0963fSdilpreet if (!(pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID)) 196900d0963fSdilpreet goto done; 19708aec9182Sstephh #if !defined(__sparc) 19718aec9182Sstephh /* 19725952c218Sanish * On x86 ignore UR on non-RBER leaf devices, pciex-pci 19735952c218Sanish * bridges and switches. 19748aec9182Sstephh */ 19758aec9182Sstephh if ((pcie_regs->pcie_err_status & PCIE_DEVSTS_UR_DETECTED) && 19768aec9182Sstephh !(pcie_regs->pcie_err_status & PCIE_DEVSTS_FE_DETECTED) && 19775952c218Sanish ((erpt_p->pe_dflags & (PCIEX_2PCI_DEV|PCIEX_SWITCH_DEV)) || 19788aec9182Sstephh !(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) && 19798aec9182Sstephh !(pcie_regs->pcie_dev_cap & PCIE_DEVCAP_ROLE_BASED_ERR_REP)) 19808aec9182Sstephh goto done; 19818aec9182Sstephh #endif 198200d0963fSdilpreet for (i = 0; pciex_nadv_err_tbl[i].err_class != NULL; i++) { 198300d0963fSdilpreet if (!(pcie_regs->pcie_err_status & 198400d0963fSdilpreet pciex_nadv_err_tbl[i].reg_bit)) 198500d0963fSdilpreet continue; 198600d0963fSdilpreet 198700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 198800d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 198900d0963fSdilpreet pciex_nadv_err_tbl[i].err_class); 199000d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 199100d0963fSdilpreet PCIEX_TYPE_GEN); 199200d0963fSdilpreet PCI_FM_SEV_INC(pciex_nadv_err_tbl[i].flags); 199300d0963fSdilpreet } 199400d0963fSdilpreet goto done; 199500d0963fSdilpreet } 199600d0963fSdilpreet 199700d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 199800d0963fSdilpreet 199900d0963fSdilpreet /* 200000d0963fSdilpreet * Log PCI Express uncorrectable errors 200100d0963fSdilpreet */ 200200d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) { 200300d0963fSdilpreet for (i = 0; pciex_ue_err_tbl[i].err_class != NULL; i++) { 200400d0963fSdilpreet if (!(pcie_adv_regs->pcie_ue_status & 200500d0963fSdilpreet pciex_ue_err_tbl[i].reg_bit)) 200600d0963fSdilpreet continue; 200700d0963fSdilpreet 200800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 200900d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 201000d0963fSdilpreet pciex_ue_err_tbl[i].err_class); 201100d0963fSdilpreet 20128aec9182Sstephh /* 20138aec9182Sstephh * First check for advisary nonfatal conditions 20148aec9182Sstephh * - hardware endpoint successfully retrying a cto 20158aec9182Sstephh * - hardware endpoint receiving poisoned tlp and 20168aec9182Sstephh * dealing with it itself (but not if root complex) 20178aec9182Sstephh * If the device has declared these as correctable 20188aec9182Sstephh * errors then treat them as such. 20198aec9182Sstephh */ 20208aec9182Sstephh if ((pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_TO || 20218aec9182Sstephh (pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_PTLP && 20228aec9182Sstephh !(erpt_p->pe_dflags & PCIEX_RC_DEV))) && 20238aec9182Sstephh (pcie_regs->pcie_err_status & 20248aec9182Sstephh PCIE_DEVSTS_CE_DETECTED) && 20258aec9182Sstephh !(pcie_regs->pcie_err_status & 20268aec9182Sstephh PCIE_DEVSTS_NFE_DETECTED)) { 20278aec9182Sstephh pcie_ereport_post(dip, derr, erpt_p, buf, 20288aec9182Sstephh PCIEX_TYPE_UE); 20298aec9182Sstephh continue; 20308aec9182Sstephh } 20318aec9182Sstephh 20328aec9182Sstephh #if !defined(__sparc) 20338aec9182Sstephh /* 20348aec9182Sstephh * On x86 for leaf devices and pciex-pci bridges, 20358aec9182Sstephh * ignore UR on non-RBER devices or on RBER devices when 20368aec9182Sstephh * advisory nonfatal. 20378aec9182Sstephh */ 20388aec9182Sstephh if (pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_UR && 20395952c218Sanish ((erpt_p->pe_dflags & 20405952c218Sanish (PCIEX_2PCI_DEV|PCIEX_SWITCH_DEV)) || 20418aec9182Sstephh !(erpt_p->pe_dflags & PCI_BRIDGE_DEV))) { 20428aec9182Sstephh if (!(pcie_regs->pcie_dev_cap & 20438aec9182Sstephh PCIE_DEVCAP_ROLE_BASED_ERR_REP)) 20448aec9182Sstephh continue; 2045*2901c7f3Sstephh if (!(pcie_regs->pcie_err_status & 20468aec9182Sstephh PCIE_DEVSTS_NFE_DETECTED)) 20478aec9182Sstephh continue; 20488aec9182Sstephh } 20498aec9182Sstephh #endif 205000d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 20518aec9182Sstephh /* 20528aec9182Sstephh * Now try and look up handle if 20538aec9182Sstephh * - error bit is among PCIE_AER_UCE_LOG_BITS, and 20548aec9182Sstephh * - no other PCIE_AER_UCE_LOG_BITS are set, and 20558aec9182Sstephh * - error bit is not masked, and 20568aec9182Sstephh * - flag is DDI_FM_UNKNOWN 20578aec9182Sstephh */ 205800d0963fSdilpreet if ((pcie_adv_regs->pcie_ue_status & 20598aec9182Sstephh pcie_aer_uce_log_bits) == 20608aec9182Sstephh pciex_ue_err_tbl[i].reg_bit && 20618aec9182Sstephh !(pciex_ue_err_tbl[i].reg_bit & 20628aec9182Sstephh pcie_adv_regs->pcie_ue_mask) && 20638aec9182Sstephh pciex_ue_err_tbl[i].flags == DDI_FM_UNKNOWN) 20648aec9182Sstephh pcie_check_addr(dip, derr, erpt_p); 20658aec9182Sstephh 206600d0963fSdilpreet PCI_FM_SEV_INC(pciex_ue_err_tbl[i].flags); 206700d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 206800d0963fSdilpreet PCIEX_TYPE_UE); 206900d0963fSdilpreet } 207000d0963fSdilpreet } 207100d0963fSdilpreet 207200d0963fSdilpreet /* 207300d0963fSdilpreet * Log PCI Express correctable errors 207400d0963fSdilpreet */ 207500d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) { 207600d0963fSdilpreet for (i = 0; pciex_ce_err_tbl[i].err_class != NULL; i++) { 207700d0963fSdilpreet if (!(pcie_adv_regs->pcie_ce_status & 207800d0963fSdilpreet pciex_ce_err_tbl[i].reg_bit)) 207900d0963fSdilpreet continue; 208000d0963fSdilpreet 208100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 208200d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 208300d0963fSdilpreet pciex_ce_err_tbl[i].err_class); 208400d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 208500d0963fSdilpreet PCIEX_TYPE_CE); 208600d0963fSdilpreet } 208700d0963fSdilpreet } 208800d0963fSdilpreet 208900d0963fSdilpreet if (!(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) 209000d0963fSdilpreet goto done; 209100d0963fSdilpreet 209200d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 209300d0963fSdilpreet int ret = pcie_rc_error_report(dip, derr, erpt_p, 209400d0963fSdilpreet (void *)pcie_adv_regs); 209500d0963fSdilpreet PCI_FM_SEV_INC(ret); 209600d0963fSdilpreet } 209700d0963fSdilpreet 209800d0963fSdilpreet if (!((erpt_p->pe_dflags & PCIEX_2PCI_DEV) && 209900d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID))) 210000d0963fSdilpreet goto done; 210100d0963fSdilpreet 210200d0963fSdilpreet pcie_bdg_regs = pcie_adv_regs->pcie_adv_bdg_regs; 210300d0963fSdilpreet 210400d0963fSdilpreet for (i = 0; pcie_sue_err_tbl[i].err_class != NULL; i++) { 210500d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 210600d0963fSdilpreet pcie_sue_err_tbl[i].reg_bit)) { 210700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 210800d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 210900d0963fSdilpreet pcie_sue_err_tbl[i].err_class); 211000d0963fSdilpreet 211100d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 21120c64a9b4Sanish pcie_aer_suce_log_bits) != 21138aec9182Sstephh pcie_sue_err_tbl[i].reg_bit || 21148aec9182Sstephh pcie_sue_err_tbl[i].flags != DDI_FM_UNKNOWN) { 211500d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 211600d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 211700d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 211800d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 211900d0963fSdilpreet #ifdef DEBUG 212000d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 212100d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 212200d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 212300d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 212400d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 212500d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 212600d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 212700d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 212800d0963fSdilpreet #endif 212900d0963fSdilpreet NULL); 213000d0963fSdilpreet } else { 213100d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 21328aec9182Sstephh switch (pcie_sue_err_tbl[i].reg_bit) { 21338aec9182Sstephh case PCIE_AER_SUCE_RCVD_TA: 21348aec9182Sstephh case PCIE_AER_SUCE_RCVD_MA: 21358aec9182Sstephh case PCIE_AER_SUCE_USC_ERR: 21368aec9182Sstephh type = ACC_HANDLE; 21378aec9182Sstephh break; 21388aec9182Sstephh case PCIE_AER_SUCE_TA_ON_SC: 21398aec9182Sstephh case PCIE_AER_SUCE_MA_ON_SC: 21408aec9182Sstephh type = DMA_HANDLE; 21418aec9182Sstephh break; 21428aec9182Sstephh case PCIE_AER_SUCE_UC_DATA_ERR: 21438aec9182Sstephh case PCIE_AER_SUCE_PERR_ASSERT: 21448aec9182Sstephh if (erpt_p->pe_pci_regs->pci_bdg_regs-> 21458aec9182Sstephh pci_bdg_sec_stat & 21468aec9182Sstephh PCI_STAT_S_PERROR) 21478aec9182Sstephh type = ACC_HANDLE; 21488aec9182Sstephh else 21498aec9182Sstephh type = DMA_HANDLE; 21508aec9182Sstephh break; 21518aec9182Sstephh } 21528aec9182Sstephh pcie_pci_check_addr(dip, derr, erpt_p, type); 215300d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 215400d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 215500d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 215600d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 215700d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 215800d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 215900d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 216000d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 216100d0963fSdilpreet 1 : NULL, 216200d0963fSdilpreet #ifdef DEBUG 216300d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 216400d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 216500d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 216600d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 216700d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 216800d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 216900d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 217000d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 217100d0963fSdilpreet #endif 217200d0963fSdilpreet NULL); 217300d0963fSdilpreet } 21748aec9182Sstephh PCI_FM_SEV_INC(pcie_sue_err_tbl[i].flags); 217500d0963fSdilpreet } 217600d0963fSdilpreet } 217700d0963fSdilpreet done: 217800d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 217900d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 218000d0963fSdilpreet } 218100d0963fSdilpreet 218200d0963fSdilpreet static void 218300d0963fSdilpreet pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 218400d0963fSdilpreet { 218500d0963fSdilpreet int fatal = 0; 218600d0963fSdilpreet int nonfatal = 0; 218700d0963fSdilpreet int unknown = 0; 218800d0963fSdilpreet int ok = 0; 218900d0963fSdilpreet char buf[FM_MAX_CLASS]; 219000d0963fSdilpreet int i; 219100d0963fSdilpreet 219200d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 219300d0963fSdilpreet /* 219400d0963fSdilpreet * Log generic PCI errors. 219500d0963fSdilpreet */ 219600d0963fSdilpreet for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 219700d0963fSdilpreet if (!(erpt_p->pe_pci_regs->pci_err_status & 219800d0963fSdilpreet pci_err_tbl[i].reg_bit) || 219900d0963fSdilpreet !(erpt_p->pe_pci_regs->pci_vflags & 220000d0963fSdilpreet PCI_ERR_STATUS_VALID)) 220100d0963fSdilpreet continue; 220200d0963fSdilpreet /* 220300d0963fSdilpreet * Generate an ereport for this error bit. 220400d0963fSdilpreet */ 220500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 220600d0963fSdilpreet PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class); 220700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 220800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 220900d0963fSdilpreet PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 221000d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status, 221100d0963fSdilpreet PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 221200d0963fSdilpreet erpt_p->pe_pci_regs->pci_cfg_comm, NULL); 221300d0963fSdilpreet 2214ac4d633fSstephh /* 2215ac4d633fSstephh * The meaning of SERR is different for PCIEX (just 2216ac4d633fSstephh * implies a message has been sent) so we don't want to 2217ac4d633fSstephh * treat that one as fatal. 2218ac4d633fSstephh */ 2219ac4d633fSstephh if ((erpt_p->pe_dflags & PCIEX_DEV) && 2220ac4d633fSstephh pci_err_tbl[i].reg_bit == PCI_STAT_S_SYSERR) { 2221ac4d633fSstephh unknown++; 2222ac4d633fSstephh } else { 222300d0963fSdilpreet PCI_FM_SEV_INC(pci_err_tbl[i].flags); 222400d0963fSdilpreet } 2225ac4d633fSstephh } 222600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) { 222700d0963fSdilpreet int ret = pcie_error_report(dip, derr, erpt_p); 222800d0963fSdilpreet PCI_FM_SEV_INC(ret); 222900d0963fSdilpreet } else if (erpt_p->pe_dflags & PCIX_DEV) { 223000d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 223100d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, 223200d0963fSdilpreet erpt_p, erpt_p->pe_regs); 223300d0963fSdilpreet PCI_FM_SEV_INC(ret); 223400d0963fSdilpreet } else { 223500d0963fSdilpreet int ret = pcix_error_report(dip, derr, erpt_p); 223600d0963fSdilpreet PCI_FM_SEV_INC(ret); 223700d0963fSdilpreet } 223800d0963fSdilpreet } 223900d0963fSdilpreet } 224000d0963fSdilpreet 224100d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) { 224200d0963fSdilpreet int ret = pci_bdg_error_report(dip, derr, erpt_p); 224300d0963fSdilpreet PCI_FM_SEV_INC(ret); 224400d0963fSdilpreet } 224500d0963fSdilpreet 22468aec9182Sstephh if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 22478aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp; 22488aec9182Sstephh int ret = DDI_FM_UNKNOWN; 22498aec9182Sstephh 22508aec9182Sstephh pci_fme_bsp = (pci_fme_bus_specific_t *)derr->fme_bus_specific; 22518aec9182Sstephh if (pci_fme_bsp->pci_bs_flags & PCI_BS_ADDR_VALID) { 22528aec9182Sstephh ret = ndi_fmc_entry_error(dip, 22538aec9182Sstephh pci_fme_bsp->pci_bs_type, derr, 22548aec9182Sstephh (void *)&pci_fme_bsp->pci_bs_addr); 22558aec9182Sstephh PCI_FM_SEV_INC(ret); 22568aec9182Sstephh } 22578aec9182Sstephh /* 22588aec9182Sstephh * If we didn't find the handle using an addr, try using bdf. 22598aec9182Sstephh * Note we don't do this where the bdf is for a 22608aec9182Sstephh * device behind a pciex/pci bridge as the bridge may have 22618aec9182Sstephh * fabricated the bdf. 22628aec9182Sstephh */ 22638aec9182Sstephh if (ret == DDI_FM_UNKNOWN && 22648aec9182Sstephh (pci_fme_bsp->pci_bs_flags & PCI_BS_BDF_VALID) && 22658aec9182Sstephh pci_fme_bsp->pci_bs_bdf == erpt_p->pe_bdf && 22668aec9182Sstephh (erpt_p->pe_dflags & PCIEX_DEV) && 22678aec9182Sstephh !(erpt_p->pe_dflags & PCIEX_2PCI_DEV)) { 22688aec9182Sstephh ret = ndi_fmc_entry_error_all(dip, 22698aec9182Sstephh pci_fme_bsp->pci_bs_type, derr); 22708aec9182Sstephh PCI_FM_SEV_INC(ret); 22718aec9182Sstephh } 22728aec9182Sstephh } 22738aec9182Sstephh 227400d0963fSdilpreet derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 227500d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 227600d0963fSdilpreet } 227700d0963fSdilpreet 227800d0963fSdilpreet void 227900d0963fSdilpreet pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status) 228000d0963fSdilpreet { 228100d0963fSdilpreet struct i_ddi_fmhdl *fmhdl; 228200d0963fSdilpreet pci_erpt_t *erpt_p; 22838aec9182Sstephh ddi_fm_error_t de; 22848aec9182Sstephh pci_fme_bus_specific_t pci_fme_bs; 228500d0963fSdilpreet 228600d0963fSdilpreet fmhdl = DEVI(dip)->devi_fmhdl; 228700d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 228800d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 228900d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 229000d0963fSdilpreet return; 229100d0963fSdilpreet } 229200d0963fSdilpreet 22938aec9182Sstephh /* 22948aec9182Sstephh * copy in the ddi_fm_error_t structure in case it's VER0 22958aec9182Sstephh */ 22968aec9182Sstephh de.fme_version = derr->fme_version; 22978aec9182Sstephh de.fme_status = derr->fme_status; 22988aec9182Sstephh de.fme_flag = derr->fme_flag; 22998aec9182Sstephh de.fme_ena = derr->fme_ena; 23008aec9182Sstephh de.fme_acc_handle = derr->fme_acc_handle; 23018aec9182Sstephh de.fme_dma_handle = derr->fme_dma_handle; 23028aec9182Sstephh de.fme_bus_specific = derr->fme_bus_specific; 23038aec9182Sstephh if (derr->fme_version >= DDI_FME_VER1) 23048aec9182Sstephh de.fme_bus_type = derr->fme_bus_type; 23058aec9182Sstephh else 23068aec9182Sstephh de.fme_bus_type = DDI_FME_BUS_TYPE_DFLT; 23078aec9182Sstephh if (de.fme_bus_type == DDI_FME_BUS_TYPE_DFLT) { 23088aec9182Sstephh /* 23098aec9182Sstephh * if this is the first pci device we've found convert 23108aec9182Sstephh * fme_bus_specific to DDI_FME_BUS_TYPE_PCI 23118aec9182Sstephh */ 23128aec9182Sstephh bzero(&pci_fme_bs, sizeof (pci_fme_bs)); 23138aec9182Sstephh if (de.fme_bus_specific) { 23148aec9182Sstephh /* 23158aec9182Sstephh * the cpu passed us an addr - this can be used to look 23168aec9182Sstephh * up an access handle 23178aec9182Sstephh */ 23188aec9182Sstephh pci_fme_bs.pci_bs_addr = (uintptr_t)de.fme_bus_specific; 23198aec9182Sstephh pci_fme_bs.pci_bs_type = ACC_HANDLE; 23208aec9182Sstephh pci_fme_bs.pci_bs_flags |= PCI_BS_ADDR_VALID; 23218aec9182Sstephh } 23228aec9182Sstephh de.fme_bus_specific = (void *)&pci_fme_bs; 23238aec9182Sstephh de.fme_bus_type = DDI_FME_BUS_TYPE_PCI; 23248aec9182Sstephh } 23258aec9182Sstephh 232600d0963fSdilpreet ASSERT(fmhdl); 232700d0963fSdilpreet 23288aec9182Sstephh if (de.fme_ena == NULL) 23298aec9182Sstephh de.fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 233000d0963fSdilpreet 233100d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 2332ac4d633fSstephh if (erpt_p == NULL) 233300d0963fSdilpreet return; 233400d0963fSdilpreet 23358aec9182Sstephh pci_regs_gather(dip, erpt_p, de.fme_flag); 23368aec9182Sstephh pci_error_report(dip, &de, erpt_p); 233700d0963fSdilpreet pci_regs_clear(erpt_p); 233800d0963fSdilpreet 23398aec9182Sstephh derr->fme_status = de.fme_status; 23408aec9182Sstephh derr->fme_ena = de.fme_ena; 23418aec9182Sstephh derr->fme_acc_handle = de.fme_acc_handle; 23428aec9182Sstephh derr->fme_dma_handle = de.fme_dma_handle; 234300d0963fSdilpreet if (xx_status != NULL) 234400d0963fSdilpreet *xx_status = erpt_p->pe_pci_regs->pci_err_status; 234500d0963fSdilpreet } 234600d0963fSdilpreet 234700d0963fSdilpreet /* 234800d0963fSdilpreet * private version of walk_devs() that can be used during panic. No 234900d0963fSdilpreet * sleeping or locking required. 235000d0963fSdilpreet */ 235100d0963fSdilpreet static int 235200d0963fSdilpreet pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg) 235300d0963fSdilpreet { 235400d0963fSdilpreet while (dip) { 235500d0963fSdilpreet switch ((*f)(dip, arg)) { 235600d0963fSdilpreet case DDI_WALK_TERMINATE: 235700d0963fSdilpreet return (DDI_WALK_TERMINATE); 235800d0963fSdilpreet case DDI_WALK_CONTINUE: 235900d0963fSdilpreet if (pci_fm_walk_devs(ddi_get_child(dip), f, 236000d0963fSdilpreet arg) == DDI_WALK_TERMINATE) 236100d0963fSdilpreet return (DDI_WALK_TERMINATE); 236200d0963fSdilpreet break; 236300d0963fSdilpreet case DDI_WALK_PRUNECHILD: 236400d0963fSdilpreet break; 236500d0963fSdilpreet } 236600d0963fSdilpreet dip = ddi_get_next_sibling(dip); 236700d0963fSdilpreet } 236800d0963fSdilpreet return (DDI_WALK_CONTINUE); 236900d0963fSdilpreet } 237000d0963fSdilpreet 237100d0963fSdilpreet /* 237200d0963fSdilpreet * need special version of ddi_fm_ereport_post() as the leaf driver may 237300d0963fSdilpreet * not be hardened. 237400d0963fSdilpreet */ 237500d0963fSdilpreet static void 237600d0963fSdilpreet pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena, 237700d0963fSdilpreet uint8_t version, ...) 237800d0963fSdilpreet { 237900d0963fSdilpreet char *name; 238000d0963fSdilpreet char device_path[MAXPATHLEN]; 238100d0963fSdilpreet char ddi_error_class[FM_MAX_CLASS]; 238200d0963fSdilpreet nvlist_t *ereport, *detector; 238300d0963fSdilpreet nv_alloc_t *nva; 238400d0963fSdilpreet errorq_elem_t *eqep; 238500d0963fSdilpreet va_list ap; 238600d0963fSdilpreet 238700d0963fSdilpreet if (panicstr) { 238800d0963fSdilpreet eqep = errorq_reserve(ereport_errorq); 238900d0963fSdilpreet if (eqep == NULL) 239000d0963fSdilpreet return; 239100d0963fSdilpreet ereport = errorq_elem_nvl(ereport_errorq, eqep); 239200d0963fSdilpreet nva = errorq_elem_nva(ereport_errorq, eqep); 239300d0963fSdilpreet detector = fm_nvlist_create(nva); 239400d0963fSdilpreet } else { 239500d0963fSdilpreet ereport = fm_nvlist_create(NULL); 239600d0963fSdilpreet detector = fm_nvlist_create(NULL); 239700d0963fSdilpreet } 239800d0963fSdilpreet 239900d0963fSdilpreet (void) ddi_pathname(dip, device_path); 240000d0963fSdilpreet fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, 240100d0963fSdilpreet device_path, NULL); 240200d0963fSdilpreet (void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s", 240300d0963fSdilpreet DDI_IO_CLASS, error_class); 240400d0963fSdilpreet fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL); 240500d0963fSdilpreet 240600d0963fSdilpreet va_start(ap, version); 240700d0963fSdilpreet name = va_arg(ap, char *); 240800d0963fSdilpreet (void) i_fm_payload_set(ereport, name, ap); 240900d0963fSdilpreet va_end(ap); 241000d0963fSdilpreet 241100d0963fSdilpreet if (panicstr) { 241200d0963fSdilpreet errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); 241300d0963fSdilpreet } else { 241400d0963fSdilpreet (void) fm_ereport_post(ereport, EVCH_TRYHARD); 241500d0963fSdilpreet fm_nvlist_destroy(ereport, FM_NVA_FREE); 241600d0963fSdilpreet fm_nvlist_destroy(detector, FM_NVA_FREE); 241700d0963fSdilpreet } 241800d0963fSdilpreet } 241900d0963fSdilpreet 242000d0963fSdilpreet static int 242100d0963fSdilpreet pci_check_regs(dev_info_t *dip, void *arg) 242200d0963fSdilpreet { 242300d0963fSdilpreet int reglen; 242400d0963fSdilpreet int rn; 242500d0963fSdilpreet int totreg; 242600d0963fSdilpreet pci_regspec_t *drv_regp; 242700d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 242800d0963fSdilpreet 242900d0963fSdilpreet if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 243000d0963fSdilpreet /* 243100d0963fSdilpreet * for config space, we need to check if the given address 243200d0963fSdilpreet * is a valid config space address for this device - based 243300d0963fSdilpreet * on pci_phys_hi of the config space entry in reg property. 243400d0963fSdilpreet */ 243500d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 243600d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 243700d0963fSdilpreet return (DDI_WALK_CONTINUE); 243800d0963fSdilpreet 243900d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 244000d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 244100d0963fSdilpreet if (tgt_err->tgt_pci_space == 244200d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) && 244300d0963fSdilpreet (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M | 244400d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M)) == 244500d0963fSdilpreet (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M | 244600d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M))) { 244700d0963fSdilpreet tgt_err->tgt_dip = dip; 244800d0963fSdilpreet kmem_free(drv_regp, reglen); 244900d0963fSdilpreet return (DDI_WALK_TERMINATE); 245000d0963fSdilpreet } 245100d0963fSdilpreet } 245200d0963fSdilpreet kmem_free(drv_regp, reglen); 245300d0963fSdilpreet } else { 245400d0963fSdilpreet /* 245500d0963fSdilpreet * for non config space, need to check reg to look 245600d0963fSdilpreet * for any non-relocable mapping, otherwise check 245700d0963fSdilpreet * assigned-addresses. 245800d0963fSdilpreet */ 245900d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 246000d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 246100d0963fSdilpreet return (DDI_WALK_CONTINUE); 246200d0963fSdilpreet 246300d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 246400d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 246500d0963fSdilpreet if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) && 246600d0963fSdilpreet (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 246700d0963fSdilpreet tgt_err->tgt_pci_space == 246800d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 246900d0963fSdilpreet (tgt_err->tgt_pci_addr >= 247000d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 247100d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 247200d0963fSdilpreet (tgt_err->tgt_pci_addr < 247300d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 247400d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 247500d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 247600d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 247700d0963fSdilpreet tgt_err->tgt_dip = dip; 247800d0963fSdilpreet kmem_free(drv_regp, reglen); 247900d0963fSdilpreet return (DDI_WALK_TERMINATE); 248000d0963fSdilpreet } 248100d0963fSdilpreet } 248200d0963fSdilpreet kmem_free(drv_regp, reglen); 248300d0963fSdilpreet 248400d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 248500d0963fSdilpreet "assigned-addresses", (caddr_t)&drv_regp, ®len) != 248600d0963fSdilpreet DDI_SUCCESS) 248700d0963fSdilpreet return (DDI_WALK_CONTINUE); 248800d0963fSdilpreet 248900d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 249000d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 249100d0963fSdilpreet if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 249200d0963fSdilpreet tgt_err->tgt_pci_space == 249300d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 249400d0963fSdilpreet (tgt_err->tgt_pci_addr >= 249500d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 249600d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 249700d0963fSdilpreet (tgt_err->tgt_pci_addr < 249800d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 249900d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 250000d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 250100d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 250200d0963fSdilpreet tgt_err->tgt_dip = dip; 250300d0963fSdilpreet kmem_free(drv_regp, reglen); 250400d0963fSdilpreet return (DDI_WALK_TERMINATE); 250500d0963fSdilpreet } 250600d0963fSdilpreet } 250700d0963fSdilpreet kmem_free(drv_regp, reglen); 250800d0963fSdilpreet } 250900d0963fSdilpreet return (DDI_WALK_CONTINUE); 251000d0963fSdilpreet } 251100d0963fSdilpreet 251200d0963fSdilpreet /* 251300d0963fSdilpreet * impl_fix_ranges - fixes the config space entry of the "ranges" 251400d0963fSdilpreet * property on psycho+ platforms. (if changing this function please make sure 251500d0963fSdilpreet * to change the pci_fix_ranges function in pcipsy.c) 251600d0963fSdilpreet */ 251700d0963fSdilpreet /*ARGSUSED*/ 251800d0963fSdilpreet static void 251900d0963fSdilpreet pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange) 252000d0963fSdilpreet { 252100d0963fSdilpreet #if defined(__sparc) 252200d0963fSdilpreet char *name = ddi_binding_name(dip); 252300d0963fSdilpreet 252400d0963fSdilpreet if ((strcmp(name, "pci108e,8000") == 0) || 252500d0963fSdilpreet (strcmp(name, "pci108e,a000") == 0) || 252600d0963fSdilpreet (strcmp(name, "pci108e,a001") == 0)) { 252700d0963fSdilpreet int i; 252800d0963fSdilpreet for (i = 0; i < nrange; i++, pci_ranges++) 252900d0963fSdilpreet if ((pci_ranges->child_high & PCI_REG_ADDR_M) == 253000d0963fSdilpreet PCI_ADDR_CONFIG) 253100d0963fSdilpreet pci_ranges->parent_low |= 253200d0963fSdilpreet pci_ranges->child_high; 253300d0963fSdilpreet } 253400d0963fSdilpreet #endif 253500d0963fSdilpreet } 253600d0963fSdilpreet 253700d0963fSdilpreet static int 253800d0963fSdilpreet pci_check_ranges(dev_info_t *dip, void *arg) 253900d0963fSdilpreet { 254000d0963fSdilpreet uint64_t range_parent_begin; 254100d0963fSdilpreet uint64_t range_parent_size; 254200d0963fSdilpreet uint64_t range_parent_end; 254300d0963fSdilpreet uint32_t space_type; 254400d0963fSdilpreet uint32_t bus_num; 254500d0963fSdilpreet uint32_t range_offset; 254600d0963fSdilpreet pci_ranges_t *pci_ranges, *rangep; 254700d0963fSdilpreet pci_bus_range_t *pci_bus_rangep; 254800d0963fSdilpreet int pci_ranges_length; 254900d0963fSdilpreet int nrange; 255000d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 255100d0963fSdilpreet int i, size; 255200d0963fSdilpreet if (strcmp(ddi_node_name(dip), "pci") != 0 && 255300d0963fSdilpreet strcmp(ddi_node_name(dip), "pciex") != 0) 255400d0963fSdilpreet return (DDI_WALK_CONTINUE); 255500d0963fSdilpreet 255600d0963fSdilpreet /* 255700d0963fSdilpreet * Get the ranges property. Note we only look at the top level pci 255800d0963fSdilpreet * node (hostbridge) which has a ranges property of type pci_ranges_t 255900d0963fSdilpreet * not at pci-pci bridges. 256000d0963fSdilpreet */ 256100d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 256200d0963fSdilpreet (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) { 256300d0963fSdilpreet /* 256400d0963fSdilpreet * no ranges property - no translation needed 256500d0963fSdilpreet */ 256600d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr; 256700d0963fSdilpreet tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN; 256800d0963fSdilpreet if (panicstr) 256900d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 257000d0963fSdilpreet pci_check_regs, (void *)tgt_err); 257100d0963fSdilpreet else { 257200d0963fSdilpreet int circ = 0; 257300d0963fSdilpreet ndi_devi_enter(dip, &circ); 257400d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 257500d0963fSdilpreet (void *)tgt_err); 257600d0963fSdilpreet ndi_devi_exit(dip, circ); 257700d0963fSdilpreet } 257800d0963fSdilpreet if (tgt_err->tgt_dip != NULL) 257900d0963fSdilpreet return (DDI_WALK_TERMINATE); 258000d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 258100d0963fSdilpreet } 258200d0963fSdilpreet nrange = pci_ranges_length / sizeof (pci_ranges_t); 258300d0963fSdilpreet rangep = pci_ranges; 258400d0963fSdilpreet 258500d0963fSdilpreet /* Need to fix the pci ranges property for psycho based systems */ 258600d0963fSdilpreet pci_fix_ranges(dip, pci_ranges, nrange); 258700d0963fSdilpreet 258800d0963fSdilpreet for (i = 0; i < nrange; i++, rangep++) { 258900d0963fSdilpreet range_parent_begin = ((uint64_t)rangep->parent_high << 32) + 259000d0963fSdilpreet rangep->parent_low; 259100d0963fSdilpreet range_parent_size = ((uint64_t)rangep->size_high << 32) + 259200d0963fSdilpreet rangep->size_low; 259300d0963fSdilpreet range_parent_end = range_parent_begin + range_parent_size - 1; 259400d0963fSdilpreet 259500d0963fSdilpreet if ((tgt_err->tgt_err_addr < range_parent_begin) || 259600d0963fSdilpreet (tgt_err->tgt_err_addr > range_parent_end)) { 259700d0963fSdilpreet /* Not in range */ 259800d0963fSdilpreet continue; 259900d0963fSdilpreet } 260000d0963fSdilpreet space_type = PCI_REG_ADDR_G(rangep->child_high); 260100d0963fSdilpreet if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 260200d0963fSdilpreet /* Config space address - check bus range */ 260300d0963fSdilpreet range_offset = tgt_err->tgt_err_addr - 260400d0963fSdilpreet range_parent_begin; 260500d0963fSdilpreet bus_num = PCI_REG_BUS_G(range_offset); 260600d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 260700d0963fSdilpreet DDI_PROP_DONTPASS, "bus-range", 260800d0963fSdilpreet (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) { 260900d0963fSdilpreet continue; 261000d0963fSdilpreet } 261100d0963fSdilpreet if ((bus_num < pci_bus_rangep->lo) || 261200d0963fSdilpreet (bus_num > pci_bus_rangep->hi)) { 261300d0963fSdilpreet /* 261400d0963fSdilpreet * Bus number not appropriate for this 261500d0963fSdilpreet * pci nexus. 261600d0963fSdilpreet */ 261700d0963fSdilpreet kmem_free(pci_bus_rangep, size); 261800d0963fSdilpreet continue; 261900d0963fSdilpreet } 262000d0963fSdilpreet kmem_free(pci_bus_rangep, size); 262100d0963fSdilpreet } 262200d0963fSdilpreet 262300d0963fSdilpreet /* We have a match if we get here - compute pci address */ 262400d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr - 262500d0963fSdilpreet range_parent_begin; 262600d0963fSdilpreet tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) + 262700d0963fSdilpreet rangep->child_low); 262800d0963fSdilpreet tgt_err->tgt_pci_space = space_type; 262900d0963fSdilpreet if (panicstr) 263000d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 263100d0963fSdilpreet pci_check_regs, (void *)tgt_err); 263200d0963fSdilpreet else { 263300d0963fSdilpreet int circ = 0; 263400d0963fSdilpreet ndi_devi_enter(dip, &circ); 263500d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 263600d0963fSdilpreet (void *)tgt_err); 263700d0963fSdilpreet ndi_devi_exit(dip, circ); 263800d0963fSdilpreet } 263900d0963fSdilpreet if (tgt_err->tgt_dip != NULL) { 264000d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 264100d0963fSdilpreet return (DDI_WALK_TERMINATE); 264200d0963fSdilpreet } 264300d0963fSdilpreet } 264400d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 264500d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 264600d0963fSdilpreet } 264700d0963fSdilpreet 264800d0963fSdilpreet /* 264900d0963fSdilpreet * Function used to drain pci_target_queue, either during panic or after softint 265000d0963fSdilpreet * is generated, to generate target device ereports based on captured physical 265100d0963fSdilpreet * addresses 265200d0963fSdilpreet */ 265300d0963fSdilpreet /*ARGSUSED*/ 265400d0963fSdilpreet static void 265500d0963fSdilpreet pci_target_drain(void *private_p, pci_target_err_t *tgt_err) 265600d0963fSdilpreet { 265700d0963fSdilpreet char buf[FM_MAX_CLASS]; 265800d0963fSdilpreet 265900d0963fSdilpreet /* 266000d0963fSdilpreet * The following assumes that all pci_pci bridge devices 266100d0963fSdilpreet * are configured as transparant. Find the top-level pci 266200d0963fSdilpreet * nexus which has tgt_err_addr in one of its ranges, converting this 266300d0963fSdilpreet * to a pci address in the process. Then starting at this node do 266400d0963fSdilpreet * another tree walk to find a device with the pci address we've 266500d0963fSdilpreet * found within range of one of it's assigned-addresses properties. 266600d0963fSdilpreet */ 266700d0963fSdilpreet tgt_err->tgt_dip = NULL; 266800d0963fSdilpreet if (panicstr) 266900d0963fSdilpreet (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges, 267000d0963fSdilpreet (void *)tgt_err); 267100d0963fSdilpreet else 267200d0963fSdilpreet ddi_walk_devs(ddi_root_node(), pci_check_ranges, 267300d0963fSdilpreet (void *)tgt_err); 267400d0963fSdilpreet if (tgt_err->tgt_dip == NULL) 267500d0963fSdilpreet return; 267600d0963fSdilpreet 267700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type, 267800d0963fSdilpreet tgt_err->tgt_err_class); 267900d0963fSdilpreet pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0, 268000d0963fSdilpreet PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL); 268100d0963fSdilpreet } 268200d0963fSdilpreet 268300d0963fSdilpreet void 268400d0963fSdilpreet pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr) 268500d0963fSdilpreet { 268600d0963fSdilpreet pci_target_err_t tgt_err; 268700d0963fSdilpreet 268800d0963fSdilpreet tgt_err.tgt_err_ena = ena; 268900d0963fSdilpreet tgt_err.tgt_err_class = class; 269000d0963fSdilpreet tgt_err.tgt_bridge_type = bridge_type; 269100d0963fSdilpreet tgt_err.tgt_err_addr = addr; 269200d0963fSdilpreet errorq_dispatch(pci_target_queue, (void *)&tgt_err, 269300d0963fSdilpreet sizeof (pci_target_err_t), ERRORQ_ASYNC); 269400d0963fSdilpreet } 269500d0963fSdilpreet 269600d0963fSdilpreet void 269700d0963fSdilpreet pci_targetq_init(void) 269800d0963fSdilpreet { 269900d0963fSdilpreet /* 270000d0963fSdilpreet * PCI target errorq, to schedule async handling of generation of 270100d0963fSdilpreet * target device ereports based on captured physical address. 270200d0963fSdilpreet * The errorq is created here but destroyed when _fini is called 270300d0963fSdilpreet * for the pci module. 270400d0963fSdilpreet */ 270500d0963fSdilpreet if (pci_target_queue == NULL) { 270600d0963fSdilpreet pci_target_queue = errorq_create("pci_target_queue", 270700d0963fSdilpreet (errorq_func_t)pci_target_drain, (void *)NULL, 270800d0963fSdilpreet TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL, 270900d0963fSdilpreet ERRORQ_VITAL); 271000d0963fSdilpreet if (pci_target_queue == NULL) 271100d0963fSdilpreet panic("failed to create required system error queue"); 271200d0963fSdilpreet } 271300d0963fSdilpreet } 2714