100d0963fSdilpreet /* 200d0963fSdilpreet * CDDL HEADER START 300d0963fSdilpreet * 400d0963fSdilpreet * The contents of this file are subject to the terms of the 500d0963fSdilpreet * Common Development and Distribution License (the "License"). 600d0963fSdilpreet * You may not use this file except in compliance with the License. 700d0963fSdilpreet * 800d0963fSdilpreet * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 900d0963fSdilpreet * or http://www.opensolaris.org/os/licensing. 1000d0963fSdilpreet * See the License for the specific language governing permissions 1100d0963fSdilpreet * and limitations under the License. 1200d0963fSdilpreet * 1300d0963fSdilpreet * When distributing Covered Code, include this CDDL HEADER in each 1400d0963fSdilpreet * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1500d0963fSdilpreet * If applicable, add the following below this CDDL HEADER, with the 1600d0963fSdilpreet * fields enclosed by brackets "[]" replaced with your own identifying 1700d0963fSdilpreet * information: Portions Copyright [yyyy] [name of copyright owner] 1800d0963fSdilpreet * 1900d0963fSdilpreet * CDDL HEADER END 2000d0963fSdilpreet */ 2100d0963fSdilpreet 2200d0963fSdilpreet /* 2300d0963fSdilpreet * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2400d0963fSdilpreet * Use is subject to license terms. 2500d0963fSdilpreet */ 2600d0963fSdilpreet 2700d0963fSdilpreet #pragma ident "%Z%%M% %I% %E% SMI" 2800d0963fSdilpreet 2900d0963fSdilpreet #include <sys/types.h> 3000d0963fSdilpreet #include <sys/sunndi.h> 3100d0963fSdilpreet #include <sys/sysmacros.h> 3200d0963fSdilpreet #include <sys/ddifm_impl.h> 3300d0963fSdilpreet #include <sys/fm/util.h> 3400d0963fSdilpreet #include <sys/fm/protocol.h> 3500d0963fSdilpreet #include <sys/fm/io/pci.h> 3600d0963fSdilpreet #include <sys/fm/io/ddi.h> 3700d0963fSdilpreet #include <sys/pci.h> 3800d0963fSdilpreet #include <sys/pcie.h> 3900d0963fSdilpreet #include <sys/pci_impl.h> 4000d0963fSdilpreet #include <sys/epm.h> 4100d0963fSdilpreet #include <sys/pcifm.h> 4200d0963fSdilpreet 4300d0963fSdilpreet #define PCIX_ECC_VER_CHECK(x) (((x) == PCI_PCIX_VER_1) ||\ 4400d0963fSdilpreet ((x) == PCI_PCIX_VER_2)) 4500d0963fSdilpreet 4600d0963fSdilpreet /* 4700d0963fSdilpreet * Expected PCI Express error mask values 4800d0963fSdilpreet */ 4900d0963fSdilpreet uint32_t pcie_expected_ce_mask = PCIE_AER_CE_AD_NFE; 5000d0963fSdilpreet uint32_t pcie_expected_ue_mask = 0x0; 5100d0963fSdilpreet uint32_t pcie_expected_sue_mask = 0x0; 52*0c64a9b4Sanish #if defined(__sparc) 53*0c64a9b4Sanish uint32_t pcie_aer_uce_log_bits = PCIE_AER_UCE_LOG_BITS; 54*0c64a9b4Sanish uint32_t pcie_aer_suce_log_bits = PCIE_AER_SUCE_LOG_BITS; 55*0c64a9b4Sanish #else 56*0c64a9b4Sanish uint32_t pcie_aer_uce_log_bits = PCIE_AER_UCE_LOG_BITS & ~PCIE_AER_UCE_UR; 57*0c64a9b4Sanish uint32_t pcie_aer_suce_log_bits = \ 58*0c64a9b4Sanish PCIE_AER_SUCE_LOG_BITS & ~PCIE_AER_SUCE_RCVD_MA; 59*0c64a9b4Sanish #endif 6000d0963fSdilpreet 6100d0963fSdilpreet errorq_t *pci_target_queue = NULL; 6200d0963fSdilpreet 6300d0963fSdilpreet pci_fm_err_t pci_err_tbl[] = { 6400d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 6500d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 6600d0963fSdilpreet PCI_SIG_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_FATAL, 6700d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 6800d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 6900d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 7000d0963fSdilpreet NULL, NULL, NULL, NULL, 7100d0963fSdilpreet }; 7200d0963fSdilpreet 7300d0963fSdilpreet pci_fm_err_t pci_bdg_err_tbl[] = { 7400d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 7500d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 7600d0963fSdilpreet PCI_REC_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_UNKNOWN, 77*0c64a9b4Sanish #if !defined(__sparc) 78*0c64a9b4Sanish PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_OK, 79*0c64a9b4Sanish #else 8000d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 81*0c64a9b4Sanish #endif 8200d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 8300d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 8400d0963fSdilpreet NULL, NULL, NULL, NULL, 8500d0963fSdilpreet }; 8600d0963fSdilpreet 8700d0963fSdilpreet static pci_fm_err_t pciex_ce_err_tbl[] = { 88ac4d633fSstephh PCIEX_RE, PCIE_AER_CE_RECEIVER_ERR, NULL, DDI_FM_OK, 89ac4d633fSstephh PCIEX_RNR, PCIE_AER_CE_REPLAY_ROLLOVER, NULL, DDI_FM_OK, 90ac4d633fSstephh PCIEX_RTO, PCIE_AER_CE_REPLAY_TO, NULL, DDI_FM_OK, 91ac4d633fSstephh PCIEX_BDP, PCIE_AER_CE_BAD_DLLP, NULL, DDI_FM_OK, 92ac4d633fSstephh PCIEX_BTP, PCIE_AER_CE_BAD_TLP, NULL, DDI_FM_OK, 93ac4d633fSstephh PCIEX_ANFE, PCIE_AER_CE_AD_NFE, NULL, DDI_FM_OK, 9400d0963fSdilpreet NULL, NULL, NULL, NULL, 9500d0963fSdilpreet }; 9600d0963fSdilpreet 9700d0963fSdilpreet static pci_fm_err_t pciex_ue_err_tbl[] = { 9800d0963fSdilpreet PCIEX_TE, PCIE_AER_UCE_TRAINING, NULL, DDI_FM_FATAL, 9900d0963fSdilpreet PCIEX_DLP, PCIE_AER_UCE_DLP, NULL, DDI_FM_FATAL, 10000d0963fSdilpreet PCIEX_SD, PCIE_AER_UCE_SD, NULL, DDI_FM_FATAL, 10100d0963fSdilpreet PCIEX_ROF, PCIE_AER_UCE_RO, NULL, DDI_FM_FATAL, 10200d0963fSdilpreet PCIEX_FCP, PCIE_AER_UCE_FCP, NULL, DDI_FM_FATAL, 10300d0963fSdilpreet PCIEX_MFP, PCIE_AER_UCE_MTLP, NULL, DDI_FM_FATAL, 104ac4d633fSstephh PCIEX_CTO, PCIE_AER_UCE_TO, NULL, DDI_FM_UNKNOWN, 105ac4d633fSstephh PCIEX_UC, PCIE_AER_UCE_UC, NULL, DDI_FM_OK, 10600d0963fSdilpreet PCIEX_ECRC, PCIE_AER_UCE_ECRC, NULL, DDI_FM_UNKNOWN, 10700d0963fSdilpreet PCIEX_CA, PCIE_AER_UCE_CA, NULL, DDI_FM_UNKNOWN, 108*0c64a9b4Sanish #if !defined(__sparc) 109*0c64a9b4Sanish PCIEX_UR, PCIE_AER_UCE_UR, NULL, DDI_FM_OK, 110*0c64a9b4Sanish #else 111ac4d633fSstephh PCIEX_UR, PCIE_AER_UCE_UR, NULL, DDI_FM_UNKNOWN, 112*0c64a9b4Sanish #endif 11300d0963fSdilpreet PCIEX_POIS, PCIE_AER_UCE_PTLP, NULL, DDI_FM_UNKNOWN, 11400d0963fSdilpreet NULL, NULL, NULL, NULL, 11500d0963fSdilpreet }; 11600d0963fSdilpreet 11700d0963fSdilpreet static pci_fm_err_t pcie_sue_err_tbl[] = { 11800d0963fSdilpreet PCIEX_S_TA_SC, PCIE_AER_SUCE_TA_ON_SC, NULL, DDI_FM_UNKNOWN, 11900d0963fSdilpreet PCIEX_S_MA_SC, PCIE_AER_SUCE_MA_ON_SC, NULL, DDI_FM_UNKNOWN, 12000d0963fSdilpreet PCIEX_S_RTA, PCIE_AER_SUCE_RCVD_TA, NULL, DDI_FM_UNKNOWN, 121*0c64a9b4Sanish #if !defined(__sparc) 122*0c64a9b4Sanish PCIEX_S_RMA, PCIE_AER_SUCE_RCVD_MA, NULL, DDI_FM_OK, 123*0c64a9b4Sanish #else 12400d0963fSdilpreet PCIEX_S_RMA, PCIE_AER_SUCE_RCVD_MA, NULL, DDI_FM_UNKNOWN, 125*0c64a9b4Sanish #endif 12600d0963fSdilpreet PCIEX_S_USC, PCIE_AER_SUCE_USC_ERR, NULL, DDI_FM_UNKNOWN, 12700d0963fSdilpreet PCIEX_S_USCMD, PCIE_AER_SUCE_USC_MSG_DATA_ERR, NULL, DDI_FM_FATAL, 12800d0963fSdilpreet PCIEX_S_UDE, PCIE_AER_SUCE_UC_DATA_ERR, NULL, DDI_FM_UNKNOWN, 12900d0963fSdilpreet PCIEX_S_UAT, PCIE_AER_SUCE_UC_ATTR_ERR, NULL, DDI_FM_FATAL, 13000d0963fSdilpreet PCIEX_S_UADR, PCIE_AER_SUCE_UC_ADDR_ERR, NULL, DDI_FM_FATAL, 13100d0963fSdilpreet PCIEX_S_TEX, PCIE_AER_SUCE_TIMER_EXPIRED, NULL, DDI_FM_FATAL, 13200d0963fSdilpreet PCIEX_S_PERR, PCIE_AER_SUCE_PERR_ASSERT, NULL, DDI_FM_UNKNOWN, 13300d0963fSdilpreet PCIEX_S_SERR, PCIE_AER_SUCE_SERR_ASSERT, NULL, DDI_FM_FATAL, 13400d0963fSdilpreet PCIEX_INTERR, PCIE_AER_SUCE_INTERNAL_ERR, NULL, DDI_FM_FATAL, 13500d0963fSdilpreet NULL, NULL, NULL, NULL, 13600d0963fSdilpreet }; 13700d0963fSdilpreet 13800d0963fSdilpreet static pci_fm_err_t pcix_err_tbl[] = { 13900d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 14000d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 14100d0963fSdilpreet PCIX_RX_SPL_MSG, PCI_PCIX_RX_SPL_MSG, NULL, DDI_FM_UNKNOWN, 14200d0963fSdilpreet NULL, NULL, NULL, NULL, 14300d0963fSdilpreet }; 14400d0963fSdilpreet 14500d0963fSdilpreet static pci_fm_err_t pcix_sec_err_tbl[] = { 14600d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_BSS_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 14700d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_BSS_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 148ac4d633fSstephh PCIX_BSS_SPL_OR, PCI_PCIX_BSS_SPL_OR, NULL, DDI_FM_OK, 149ac4d633fSstephh PCIX_BSS_SPL_DLY, PCI_PCIX_BSS_SPL_DLY, NULL, DDI_FM_OK, 15000d0963fSdilpreet NULL, NULL, NULL, NULL, 15100d0963fSdilpreet }; 15200d0963fSdilpreet 15300d0963fSdilpreet static pci_fm_err_t pciex_nadv_err_tbl[] = { 15400d0963fSdilpreet PCIEX_UR, PCIE_DEVSTS_UR_DETECTED, NULL, DDI_FM_UNKNOWN, 15500d0963fSdilpreet PCIEX_FAT, PCIE_DEVSTS_FE_DETECTED, NULL, DDI_FM_FATAL, 15600d0963fSdilpreet PCIEX_NONFAT, PCIE_DEVSTS_NFE_DETECTED, NULL, DDI_FM_UNKNOWN, 157ac4d633fSstephh PCIEX_CORR, PCIE_DEVSTS_CE_DETECTED, NULL, DDI_FM_OK, 15800d0963fSdilpreet NULL, NULL, NULL, NULL, 15900d0963fSdilpreet }; 16000d0963fSdilpreet 16100d0963fSdilpreet static int 16200d0963fSdilpreet pci_config_check(ddi_acc_handle_t handle) 16300d0963fSdilpreet { 16400d0963fSdilpreet ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle); 16500d0963fSdilpreet ddi_fm_error_t de; 16600d0963fSdilpreet 16700d0963fSdilpreet if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip)))) 16800d0963fSdilpreet return (DDI_FM_OK); 16900d0963fSdilpreet 17000d0963fSdilpreet de.fme_version = DDI_FME_VERSION; 17100d0963fSdilpreet 17200d0963fSdilpreet ddi_fm_acc_err_get(handle, &de, de.fme_version); 17300d0963fSdilpreet if (de.fme_status != DDI_FM_OK) { 17400d0963fSdilpreet char buf[FM_MAX_CLASS]; 17500d0963fSdilpreet 17600d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", PCI_ERROR_SUBCLASS, 17700d0963fSdilpreet PCI_NR); 17800d0963fSdilpreet ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena, DDI_NOSLEEP, 17900d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 18000d0963fSdilpreet ddi_fm_acc_err_clear(handle, de.fme_version); 18100d0963fSdilpreet } 18200d0963fSdilpreet return (de.fme_status); 18300d0963fSdilpreet } 18400d0963fSdilpreet 18500d0963fSdilpreet static void 18600d0963fSdilpreet pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs, 18700d0963fSdilpreet uint8_t pcix_cap_ptr) 18800d0963fSdilpreet { 18900d0963fSdilpreet int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV; 19000d0963fSdilpreet 19100d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl, 19200d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS : 19300d0963fSdilpreet PCI_PCIX_ECC_STATUS))); 19400d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 19500d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID; 19600d0963fSdilpreet else 19700d0963fSdilpreet return; 19800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl, 19900d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD : 20000d0963fSdilpreet PCI_PCIX_ECC_FST_AD))); 20100d0963fSdilpreet pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl, 20200d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD : 20300d0963fSdilpreet PCI_PCIX_ECC_SEC_AD))); 20400d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr = pci_config_get32(( 20500d0963fSdilpreet ddi_acc_handle_t)erpt_p->pe_hdl, 20600d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR))); 20700d0963fSdilpreet } 20800d0963fSdilpreet 20900d0963fSdilpreet static void 21000d0963fSdilpreet pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs) 21100d0963fSdilpreet { 21200d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 21300d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 21400d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 21500d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 21600d0963fSdilpreet int i; 21700d0963fSdilpreet 21800d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 21900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16( 22000d0963fSdilpreet erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS)); 22100d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 22200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= 22300d0963fSdilpreet PCIX_BDG_SEC_STATUS_VALID; 22400d0963fSdilpreet else 22500d0963fSdilpreet return; 22600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl, 22700d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS)); 22800d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 22900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID; 23000d0963fSdilpreet else 23100d0963fSdilpreet return; 23200d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 23300d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 23400d0963fSdilpreet /* 23500d0963fSdilpreet * PCI Express to PCI-X bridges only implement the 23600d0963fSdilpreet * secondary side of the PCI-X ECC registers, bit one is 23700d0963fSdilpreet * read-only so we make sure we do not write to it. 23800d0963fSdilpreet */ 23900d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 24000d0963fSdilpreet pcix_bdg_ecc_regs = 24100d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[1]; 24200d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_bdg_ecc_regs, 24300d0963fSdilpreet pcix_bdg_cap_ptr); 24400d0963fSdilpreet } else { 24500d0963fSdilpreet for (i = 0; i < 2; i++) { 24600d0963fSdilpreet pcix_bdg_ecc_regs = 24700d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 24800d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 24900d0963fSdilpreet (pcix_bdg_cap_ptr + 25000d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), i); 25100d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, 25200d0963fSdilpreet pcix_bdg_ecc_regs, 25300d0963fSdilpreet pcix_bdg_cap_ptr); 25400d0963fSdilpreet } 25500d0963fSdilpreet } 25600d0963fSdilpreet } 25700d0963fSdilpreet } else { 25800d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 25900d0963fSdilpreet uint8_t pcix_cap_ptr; 26000d0963fSdilpreet 26100d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 26200d0963fSdilpreet 26300d0963fSdilpreet pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl, 26400d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_COMMAND)); 26500d0963fSdilpreet pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl, 26600d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS)); 26700d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 26800d0963fSdilpreet pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID; 26900d0963fSdilpreet else 27000d0963fSdilpreet return; 27100d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 27200d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 27300d0963fSdilpreet pcix_regs->pcix_ecc_regs; 27400d0963fSdilpreet 27500d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs, 27600d0963fSdilpreet pcix_cap_ptr); 27700d0963fSdilpreet } 27800d0963fSdilpreet } 27900d0963fSdilpreet } 28000d0963fSdilpreet 28100d0963fSdilpreet static void 28200d0963fSdilpreet pcie_regs_gather(pci_erpt_t *erpt_p) 28300d0963fSdilpreet { 28400d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 28500d0963fSdilpreet uint8_t pcie_cap_ptr; 28600d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 28700d0963fSdilpreet uint16_t pcie_ecap_ptr; 28800d0963fSdilpreet 28900d0963fSdilpreet pcie_cap_ptr = pcie_regs->pcie_cap_ptr; 29000d0963fSdilpreet 29100d0963fSdilpreet pcie_regs->pcie_err_status = pci_config_get16(erpt_p->pe_hdl, 29200d0963fSdilpreet pcie_cap_ptr + PCIE_DEVSTS); 29300d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 29400d0963fSdilpreet pcie_regs->pcie_vflags |= PCIE_ERR_STATUS_VALID; 29500d0963fSdilpreet else 29600d0963fSdilpreet return; 29700d0963fSdilpreet 29800d0963fSdilpreet pcie_regs->pcie_err_ctl = pci_config_get16(erpt_p->pe_hdl, 29900d0963fSdilpreet (pcie_cap_ptr + PCIE_DEVCTL)); 30000d0963fSdilpreet 30100d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && (erpt_p->pe_dflags & 30200d0963fSdilpreet PCIX_DEV)) 30300d0963fSdilpreet pcix_regs_gather(erpt_p, pcie_regs->pcix_bdg_regs); 30400d0963fSdilpreet 30500d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 30600d0963fSdilpreet pcie_rc_error_regs_t *pcie_rc_regs = pcie_regs->pcie_rc_regs; 30700d0963fSdilpreet 30800d0963fSdilpreet pcie_rc_regs->pcie_rc_status = pci_config_get32(erpt_p->pe_hdl, 30900d0963fSdilpreet (pcie_cap_ptr + PCIE_ROOTSTS)); 31000d0963fSdilpreet pcie_rc_regs->pcie_rc_ctl = pci_config_get16(erpt_p->pe_hdl, 31100d0963fSdilpreet (pcie_cap_ptr + PCIE_ROOTCTL)); 31200d0963fSdilpreet } 31300d0963fSdilpreet 31400d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) 31500d0963fSdilpreet return; 31600d0963fSdilpreet 31700d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 31800d0963fSdilpreet 31900d0963fSdilpreet pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr; 32000d0963fSdilpreet 32100d0963fSdilpreet pcie_adv_regs->pcie_ue_status = pci_config_get32(erpt_p->pe_hdl, 32200d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_STS); 32300d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 32400d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_STATUS_VALID; 32500d0963fSdilpreet 32600d0963fSdilpreet pcie_adv_regs->pcie_ue_mask = pci_config_get32(erpt_p->pe_hdl, 32700d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_MASK); 32800d0963fSdilpreet pcie_adv_regs->pcie_ue_sev = pci_config_get32(erpt_p->pe_hdl, 32900d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_SERV); 33000d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl = pci_config_get32(erpt_p->pe_hdl, 33100d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CTL); 33200d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0 = pci_config_get32(erpt_p->pe_hdl, 33300d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_HDR_LOG); 33400d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) { 33500d0963fSdilpreet int i; 33600d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_HDR_VALID; 33700d0963fSdilpreet 33800d0963fSdilpreet for (i = 0; i < 3; i++) { 33900d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[i] = pci_config_get32( 34000d0963fSdilpreet erpt_p->pe_hdl, pcie_ecap_ptr + PCIE_AER_HDR_LOG + 34100d0963fSdilpreet (4 * (i + 1))); 34200d0963fSdilpreet } 34300d0963fSdilpreet } 34400d0963fSdilpreet 34500d0963fSdilpreet pcie_adv_regs->pcie_ce_status = pci_config_get32(erpt_p->pe_hdl, 34600d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_STS); 34700d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 34800d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_CE_STATUS_VALID; 34900d0963fSdilpreet 35000d0963fSdilpreet pcie_adv_regs->pcie_ce_mask = pci_config_get32(erpt_p->pe_hdl, 35100d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_MASK); 35200d0963fSdilpreet 35300d0963fSdilpreet /* 35400d0963fSdilpreet * If pci express to pci bridge then grab the bridge 35500d0963fSdilpreet * error registers. 35600d0963fSdilpreet */ 35700d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 35800d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 35900d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 36000d0963fSdilpreet 36100d0963fSdilpreet pcie_bdg_regs->pcie_sue_status = 36200d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 36300d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_STS); 36400d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 36500d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_STATUS_VALID; 36600d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0 = pci_config_get32(erpt_p->pe_hdl, 36700d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_SHDR_LOG)); 36800d0963fSdilpreet 36900d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) { 37000d0963fSdilpreet int i; 37100d0963fSdilpreet 37200d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_HDR_VALID; 37300d0963fSdilpreet 37400d0963fSdilpreet for (i = 0; i < 3; i++) { 37500d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[i] = 37600d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 37700d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SHDR_LOG + 37800d0963fSdilpreet (4 * (i + 1))); 37900d0963fSdilpreet } 38000d0963fSdilpreet } 38100d0963fSdilpreet } 38200d0963fSdilpreet /* 38300d0963fSdilpreet * If PCI Express root complex then grab the root complex 38400d0963fSdilpreet * error registers. 38500d0963fSdilpreet */ 38600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 38700d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 38800d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 38900d0963fSdilpreet 39000d0963fSdilpreet pcie_rc_regs->pcie_rc_err_cmd = pci_config_get32(erpt_p->pe_hdl, 39100d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_CMD)); 39200d0963fSdilpreet pcie_rc_regs->pcie_rc_err_status = 39300d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 39400d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_STS)); 39500d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 39600d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= 39700d0963fSdilpreet PCIE_RC_ERR_STATUS_VALID; 39800d0963fSdilpreet pcie_rc_regs->pcie_rc_ce_src_id = 39900d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 40000d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_CE_SRC_ID)); 40100d0963fSdilpreet pcie_rc_regs->pcie_rc_ue_src_id = 40200d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 40300d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_ERR_SRC_ID)); 40400d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 40500d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SRC_ID_VALID; 40600d0963fSdilpreet } 40700d0963fSdilpreet } 40800d0963fSdilpreet 40900d0963fSdilpreet /*ARGSUSED*/ 41000d0963fSdilpreet static void 41100d0963fSdilpreet pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p) 41200d0963fSdilpreet { 41300d0963fSdilpreet pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs; 41400d0963fSdilpreet 41500d0963fSdilpreet /* 41600d0963fSdilpreet * Start by reading all the error registers that are available for 41700d0963fSdilpreet * pci and pci express and for leaf devices and bridges/switches 41800d0963fSdilpreet */ 41900d0963fSdilpreet pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl, 42000d0963fSdilpreet PCI_CONF_STAT); 42100d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK) 42200d0963fSdilpreet return; 42300d0963fSdilpreet pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID; 42400d0963fSdilpreet pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl, 42500d0963fSdilpreet PCI_CONF_COMM); 42600d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK) 42700d0963fSdilpreet return; 42800d0963fSdilpreet 42900d0963fSdilpreet /* 43000d0963fSdilpreet * If pci-pci bridge grab PCI bridge specific error registers. 43100d0963fSdilpreet */ 43200d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 43300d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_sec_stat = 43400d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS); 43500d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 43600d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 43700d0963fSdilpreet PCI_BDG_SEC_STAT_VALID; 43800d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_ctrl = 43900d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL); 44000d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) 44100d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 44200d0963fSdilpreet PCI_BDG_CTRL_VALID; 44300d0963fSdilpreet } 44400d0963fSdilpreet 44500d0963fSdilpreet /* 44600d0963fSdilpreet * If pci express device grab pci express error registers and 44700d0963fSdilpreet * check for advanced error reporting features and grab them if 44800d0963fSdilpreet * available. 44900d0963fSdilpreet */ 45000d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 45100d0963fSdilpreet pcie_regs_gather(erpt_p); 45200d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 45300d0963fSdilpreet pcix_regs_gather(erpt_p, erpt_p->pe_regs); 45400d0963fSdilpreet 45500d0963fSdilpreet } 45600d0963fSdilpreet 45700d0963fSdilpreet static void 45800d0963fSdilpreet pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs) 45900d0963fSdilpreet { 46000d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 46100d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 46200d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 46300d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 46400d0963fSdilpreet int i; 46500d0963fSdilpreet 46600d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 46700d0963fSdilpreet 46800d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) 46900d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, 47000d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS), 47100d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat); 47200d0963fSdilpreet 47300d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) 47400d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 47500d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS), 47600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat); 47700d0963fSdilpreet 47800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags = 0x0; 47900d0963fSdilpreet 48000d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 48100d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 48200d0963fSdilpreet /* 48300d0963fSdilpreet * PCI Express to PCI-X bridges only implement the 48400d0963fSdilpreet * secondary side of the PCI-X ECC registers, bit one is 48500d0963fSdilpreet * read-only so we make sure we do not write to it. 48600d0963fSdilpreet */ 48700d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 48800d0963fSdilpreet pcix_bdg_ecc_regs = 48900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[1]; 49000d0963fSdilpreet 49100d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 49200d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 49300d0963fSdilpreet 49400d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 49500d0963fSdilpreet (pcix_bdg_cap_ptr + 49600d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 49700d0963fSdilpreet pcix_bdg_ecc_regs-> 49800d0963fSdilpreet pcix_ecc_ctlstat); 49900d0963fSdilpreet } 50000d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 0x0; 50100d0963fSdilpreet } else { 50200d0963fSdilpreet for (i = 0; i < 2; i++) { 50300d0963fSdilpreet pcix_bdg_ecc_regs = 50400d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 50500d0963fSdilpreet 50600d0963fSdilpreet 50700d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 50800d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 50900d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 51000d0963fSdilpreet (pcix_bdg_cap_ptr + 51100d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 51200d0963fSdilpreet i); 51300d0963fSdilpreet 51400d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 51500d0963fSdilpreet (pcix_bdg_cap_ptr + 51600d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 51700d0963fSdilpreet pcix_bdg_ecc_regs-> 51800d0963fSdilpreet pcix_ecc_ctlstat); 51900d0963fSdilpreet } 52000d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 52100d0963fSdilpreet 0x0; 52200d0963fSdilpreet } 52300d0963fSdilpreet } 52400d0963fSdilpreet } 52500d0963fSdilpreet } else { 52600d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 52700d0963fSdilpreet uint8_t pcix_cap_ptr; 52800d0963fSdilpreet 52900d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 53000d0963fSdilpreet 53100d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) 53200d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 53300d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS), 53400d0963fSdilpreet pcix_regs->pcix_status); 53500d0963fSdilpreet 53600d0963fSdilpreet pcix_regs->pcix_vflags = 0x0; 53700d0963fSdilpreet 53800d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 53900d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 54000d0963fSdilpreet pcix_regs->pcix_ecc_regs; 54100d0963fSdilpreet 54200d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & 54300d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) 54400d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 54500d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_ECC_STATUS), 54600d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat); 54700d0963fSdilpreet 54800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags = 0x0; 54900d0963fSdilpreet } 55000d0963fSdilpreet } 55100d0963fSdilpreet } 55200d0963fSdilpreet 55300d0963fSdilpreet static void 55400d0963fSdilpreet pcie_regs_clear(pci_erpt_t *erpt_p) 55500d0963fSdilpreet { 55600d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 55700d0963fSdilpreet uint8_t pcie_cap_ptr; 55800d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 55900d0963fSdilpreet uint16_t pcie_ecap_ptr; 56000d0963fSdilpreet 56100d0963fSdilpreet pcie_cap_ptr = pcie_regs->pcie_cap_ptr; 56200d0963fSdilpreet 56300d0963fSdilpreet if (pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) 56400d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, pcie_cap_ptr + PCIE_DEVSTS, 56500d0963fSdilpreet pcie_regs->pcie_err_status); 56600d0963fSdilpreet 56700d0963fSdilpreet pcie_regs->pcie_vflags = 0x0; 56800d0963fSdilpreet 56900d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 57000d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) 57100d0963fSdilpreet pcix_regs_clear(erpt_p, pcie_regs->pcix_bdg_regs); 57200d0963fSdilpreet 57300d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) 57400d0963fSdilpreet return; 57500d0963fSdilpreet 57600d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 57700d0963fSdilpreet 57800d0963fSdilpreet pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr; 57900d0963fSdilpreet 58000d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) 58100d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 58200d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_STS, 58300d0963fSdilpreet pcie_adv_regs->pcie_ue_status); 58400d0963fSdilpreet 58500d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) 58600d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 58700d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_STS, 58800d0963fSdilpreet pcie_adv_regs->pcie_ce_status); 58900d0963fSdilpreet 59000d0963fSdilpreet 59100d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 59200d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 59300d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 59400d0963fSdilpreet 59500d0963fSdilpreet 59600d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID) 59700d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 59800d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_STS, 59900d0963fSdilpreet pcie_bdg_regs->pcie_sue_status); 60000d0963fSdilpreet } 60100d0963fSdilpreet /* 60200d0963fSdilpreet * If PCI Express root complex then clear the root complex 60300d0963fSdilpreet * error registers. 60400d0963fSdilpreet */ 60500d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 60600d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 60700d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 60800d0963fSdilpreet 60900d0963fSdilpreet 61000d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) 61100d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 61200d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_STS), 61300d0963fSdilpreet pcie_rc_regs->pcie_rc_err_status); 61400d0963fSdilpreet } 61500d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags = 0x0; 61600d0963fSdilpreet } 61700d0963fSdilpreet 61800d0963fSdilpreet static void 61900d0963fSdilpreet pci_regs_clear(pci_erpt_t *erpt_p) 62000d0963fSdilpreet { 62100d0963fSdilpreet /* 62200d0963fSdilpreet * Finally clear the error bits 62300d0963fSdilpreet */ 62400d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 62500d0963fSdilpreet pcie_regs_clear(erpt_p); 62600d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 62700d0963fSdilpreet pcix_regs_clear(erpt_p, erpt_p->pe_regs); 62800d0963fSdilpreet 62900d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID) 63000d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT, 63100d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status); 63200d0963fSdilpreet 63300d0963fSdilpreet erpt_p->pe_pci_regs->pci_vflags = 0x0; 63400d0963fSdilpreet 63500d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 63600d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 63700d0963fSdilpreet PCI_BDG_SEC_STAT_VALID) 63800d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS, 63900d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs-> 64000d0963fSdilpreet pci_bdg_sec_stat); 64100d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 64200d0963fSdilpreet PCI_BDG_CTRL_VALID) 64300d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL, 64400d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl); 64500d0963fSdilpreet 64600d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0; 64700d0963fSdilpreet } 64800d0963fSdilpreet } 64900d0963fSdilpreet 65000d0963fSdilpreet /* 65100d0963fSdilpreet * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport 65200d0963fSdilpreet * generation. 65300d0963fSdilpreet */ 65400d0963fSdilpreet /* ARGSUSED */ 65500d0963fSdilpreet static void 65600d0963fSdilpreet pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 65700d0963fSdilpreet { 65800d0963fSdilpreet uint8_t pcix_cap_ptr; 65900d0963fSdilpreet int i; 66000d0963fSdilpreet 66100d0963fSdilpreet pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 66200d0963fSdilpreet "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 66300d0963fSdilpreet 66400d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 66500d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 66600d0963fSdilpreet else 66700d0963fSdilpreet return; 66800d0963fSdilpreet 66900d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 67000d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 67100d0963fSdilpreet 67200d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t), 67300d0963fSdilpreet KM_SLEEP); 67400d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 67500d0963fSdilpreet pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 67600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl, 67700d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 67800d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 67900d0963fSdilpreet for (i = 0; i < 2; i++) { 68000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 68100d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 68200d0963fSdilpreet KM_SLEEP); 68300d0963fSdilpreet } 68400d0963fSdilpreet } 68500d0963fSdilpreet } else { 68600d0963fSdilpreet pcix_error_regs_t *pcix_regs; 68700d0963fSdilpreet 68800d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t), 68900d0963fSdilpreet KM_SLEEP); 69000d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 69100d0963fSdilpreet pcix_regs->pcix_cap_ptr = pcix_cap_ptr; 69200d0963fSdilpreet pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl, 69300d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 69400d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 69500d0963fSdilpreet pcix_regs->pcix_ecc_regs = kmem_zalloc( 69600d0963fSdilpreet sizeof (pcix_ecc_regs_t), KM_SLEEP); 69700d0963fSdilpreet } 69800d0963fSdilpreet } 69900d0963fSdilpreet } 70000d0963fSdilpreet 70100d0963fSdilpreet static void 70200d0963fSdilpreet pcie_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 70300d0963fSdilpreet { 70400d0963fSdilpreet pcie_error_regs_t *pcie_regs; 70500d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 70600d0963fSdilpreet char buf[FM_MAX_CLASS]; 70700d0963fSdilpreet uint8_t pcix_cap_ptr; 70800d0963fSdilpreet uint8_t pcie_cap_ptr; 70900d0963fSdilpreet uint16_t pcie_ecap_ptr; 71000d0963fSdilpreet uint16_t dev_type = 0; 71100d0963fSdilpreet uint32_t mask = pcie_expected_ue_mask; 71200d0963fSdilpreet 71300d0963fSdilpreet /* 71400d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 71500d0963fSdilpreet * interfaces create the necessary properties for us. 71600d0963fSdilpreet */ 71700d0963fSdilpreet #if defined(__sparc) 71800d0963fSdilpreet ushort_t status; 71900d0963fSdilpreet uint32_t slot_cap; 72000d0963fSdilpreet uint8_t cap_ptr = 0; 72100d0963fSdilpreet uint8_t cap_id = 0; 72200d0963fSdilpreet uint32_t hdr, hdr_next_ptr, hdr_cap_id; 72300d0963fSdilpreet uint16_t offset = P2ALIGN(PCIE_EXT_CAP, 4); 72400d0963fSdilpreet uint16_t aer_ptr = 0; 72500d0963fSdilpreet 72600d0963fSdilpreet cap_ptr = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_CAP_PTR); 72700d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) { 72800d0963fSdilpreet while ((cap_id = pci_config_get8(erpt_p->pe_hdl, cap_ptr)) != 72900d0963fSdilpreet 0xff) { 73000d0963fSdilpreet if (cap_id == PCI_CAP_ID_PCIX) { 73100d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 73200d0963fSdilpreet "pcix-capid-pointer", cap_ptr); 73300d0963fSdilpreet } 73400d0963fSdilpreet if (cap_id == PCI_CAP_ID_PCI_E) { 73500d0963fSdilpreet status = pci_config_get16(erpt_p->pe_hdl, cap_ptr + 2); 73600d0963fSdilpreet if (status & PCIE_PCIECAP_SLOT_IMPL) { 73700d0963fSdilpreet /* offset 14h is Slot Cap Register */ 73800d0963fSdilpreet slot_cap = pci_config_get32(erpt_p->pe_hdl, 73900d0963fSdilpreet cap_ptr + PCIE_SLOTCAP); 74000d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 74100d0963fSdilpreet "pcie-slotcap-reg", slot_cap); 74200d0963fSdilpreet } 74300d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 74400d0963fSdilpreet "pcie-capid-reg", pci_config_get16(erpt_p->pe_hdl, 74500d0963fSdilpreet cap_ptr + PCIE_PCIECAP)); 74600d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 74700d0963fSdilpreet "pcie-capid-pointer", cap_ptr); 74800d0963fSdilpreet 74900d0963fSdilpreet } 75000d0963fSdilpreet if ((cap_ptr = pci_config_get8(erpt_p->pe_hdl, 75100d0963fSdilpreet cap_ptr + 1)) == 0xff || cap_ptr == 0 || 75200d0963fSdilpreet (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK)) 75300d0963fSdilpreet break; 75400d0963fSdilpreet } 75500d0963fSdilpreet } 75600d0963fSdilpreet 75700d0963fSdilpreet #endif 75800d0963fSdilpreet 75900d0963fSdilpreet pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 76000d0963fSdilpreet "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 76100d0963fSdilpreet 76200d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 76300d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 76400d0963fSdilpreet 76500d0963fSdilpreet pcie_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 76600d0963fSdilpreet DDI_PROP_DONTPASS, "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 76700d0963fSdilpreet 76800d0963fSdilpreet if (pcie_cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 76900d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_DEV; 77000d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcie_error_regs_t), 77100d0963fSdilpreet KM_SLEEP); 77200d0963fSdilpreet pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 77300d0963fSdilpreet pcie_regs->pcie_cap_ptr = pcie_cap_ptr; 77400d0963fSdilpreet } 77500d0963fSdilpreet 77600d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) 77700d0963fSdilpreet return; 77800d0963fSdilpreet 77900d0963fSdilpreet /* 78000d0963fSdilpreet * Don't currently need to check for version here because we are 78100d0963fSdilpreet * compliant with PCIE 1.0a which is version 0 and is guaranteed 78200d0963fSdilpreet * software compatibility with future versions. We will need to 78300d0963fSdilpreet * add errors for new detectors/features which are added in newer 78400d0963fSdilpreet * revisions [sec 7.8.2]. 78500d0963fSdilpreet */ 78600d0963fSdilpreet pcie_regs->pcie_cap = pci_config_get16(erpt_p->pe_hdl, 78700d0963fSdilpreet pcie_regs->pcie_cap_ptr + PCIE_PCIECAP); 78800d0963fSdilpreet 78900d0963fSdilpreet dev_type = pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK; 79000d0963fSdilpreet 79100d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 79200d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 79300d0963fSdilpreet int i; 79400d0963fSdilpreet 79500d0963fSdilpreet pcie_regs->pcix_bdg_regs = 79600d0963fSdilpreet kmem_zalloc(sizeof (pcix_bdg_error_regs_t), KM_SLEEP); 79700d0963fSdilpreet 79800d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 79900d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_ver = 80000d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 80100d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 80200d0963fSdilpreet 80300d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcie_regs->pcix_bdg_regs->pcix_bdg_ver)) 80400d0963fSdilpreet for (i = 0; i < 2; i++) 80500d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 80600d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 80700d0963fSdilpreet KM_SLEEP); 80800d0963fSdilpreet } 80900d0963fSdilpreet 81000d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) { 81100d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_RC_DEV; 81200d0963fSdilpreet pcie_regs->pcie_rc_regs = kmem_zalloc( 81300d0963fSdilpreet sizeof (pcie_rc_error_regs_t), KM_SLEEP); 81400d0963fSdilpreet } 81500d0963fSdilpreet /* 81600d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 81700d0963fSdilpreet * interfaces create the necessary properties for us. 81800d0963fSdilpreet */ 81900d0963fSdilpreet #if defined(__sparc) 82000d0963fSdilpreet 82100d0963fSdilpreet hdr = pci_config_get32(erpt_p->pe_hdl, offset); 82200d0963fSdilpreet hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 82300d0963fSdilpreet PCIE_EXT_CAP_NEXT_PTR_MASK; 82400d0963fSdilpreet hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK; 82500d0963fSdilpreet 82600d0963fSdilpreet while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) && 82700d0963fSdilpreet (hdr_cap_id != PCIE_EXT_CAP_ID_AER)) { 82800d0963fSdilpreet offset = P2ALIGN(hdr_next_ptr, 4); 82900d0963fSdilpreet hdr = pci_config_get32(erpt_p->pe_hdl, offset); 83000d0963fSdilpreet hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 83100d0963fSdilpreet PCIE_EXT_CAP_NEXT_PTR_MASK; 83200d0963fSdilpreet hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & 83300d0963fSdilpreet PCIE_EXT_CAP_ID_MASK; 83400d0963fSdilpreet } 83500d0963fSdilpreet 83600d0963fSdilpreet if (hdr_cap_id == PCIE_EXT_CAP_ID_AER) 83700d0963fSdilpreet aer_ptr = P2ALIGN(offset, 4); 83800d0963fSdilpreet if (aer_ptr != PCI_CAP_NEXT_PTR_NULL) 83900d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 84000d0963fSdilpreet "pcie-aer-pointer", aer_ptr); 84100d0963fSdilpreet #endif 84200d0963fSdilpreet 84300d0963fSdilpreet /* 84400d0963fSdilpreet * Find and store if this device is capable of pci express 84500d0963fSdilpreet * advanced errors, if not report an error against the device. 84600d0963fSdilpreet */ 84700d0963fSdilpreet pcie_ecap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 84800d0963fSdilpreet "pcie-aer-pointer", PCI_CAP_NEXT_PTR_NULL); 84900d0963fSdilpreet if (pcie_ecap_ptr != PCI_CAP_NEXT_PTR_NULL) { 85000d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_ADV_DEV; 85100d0963fSdilpreet pcie_regs->pcie_adv_regs = kmem_zalloc( 85200d0963fSdilpreet sizeof (pcie_adv_error_regs_t), KM_SLEEP); 85300d0963fSdilpreet pcie_regs->pcie_adv_regs->pcie_adv_cap_ptr = pcie_ecap_ptr; 85400d0963fSdilpreet } 85500d0963fSdilpreet 85600d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 85700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 85800d0963fSdilpreet PCIEX_ERROR_SUBCLASS, PCIEX_NADV); 85900d0963fSdilpreet ddi_fm_ereport_post(dip, buf, NULL, DDI_NOSLEEP, 86000d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 86100d0963fSdilpreet return; 86200d0963fSdilpreet } 86300d0963fSdilpreet 86400d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 86500d0963fSdilpreet 86600d0963fSdilpreet if (pcie_adv_regs == NULL) 86700d0963fSdilpreet return; 86800d0963fSdilpreet /* 86900d0963fSdilpreet * Initialize structures for advanced PCI Express devices. 87000d0963fSdilpreet */ 87100d0963fSdilpreet 87200d0963fSdilpreet /* 87300d0963fSdilpreet * Advanced error registers exist for PCI Express to PCI(X) Bridges and 87400d0963fSdilpreet * may also exist for PCI(X) to PCI Express Bridges, the latter is not 87500d0963fSdilpreet * well explained in the PCI Express to PCI/PCI-X Bridge Specification 87600d0963fSdilpreet * 1.0 and will be left out of the current gathering of these registers. 87700d0963fSdilpreet */ 87800d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) { 87900d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_2PCI_DEV; 88000d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs = kmem_zalloc( 88100d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t), KM_SLEEP); 88200d0963fSdilpreet } 88300d0963fSdilpreet 88400d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 88500d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs = kmem_zalloc( 88600d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t), KM_SLEEP); 88700d0963fSdilpreet 88800d0963fSdilpreet /* 88900d0963fSdilpreet * Check that mask values are as expected, if not 89000d0963fSdilpreet * change them to what we desire. 89100d0963fSdilpreet */ 89200d0963fSdilpreet pci_regs_gather(dip, erpt_p); 89300d0963fSdilpreet pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 89400d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_ce_mask != pcie_expected_ce_mask) { 89500d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 89600d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_MASK, pcie_expected_ce_mask); 89700d0963fSdilpreet } 89800d0963fSdilpreet 89900d0963fSdilpreet /* Disable PTLP/ECRC (or mask these two) for Switches */ 90000d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_UP || 90100d0963fSdilpreet dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) 90200d0963fSdilpreet mask |= PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC; 90300d0963fSdilpreet 90400d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_ue_mask != mask) { 90500d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 90600d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_MASK, mask); 90700d0963fSdilpreet } 90800d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 90900d0963fSdilpreet if (pcie_regs->pcie_adv_regs->pcie_adv_bdg_regs->pcie_sue_mask 91000d0963fSdilpreet != pcie_expected_sue_mask) { 91100d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 91200d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_MASK, 91300d0963fSdilpreet pcie_expected_sue_mask); 91400d0963fSdilpreet } 91500d0963fSdilpreet } 91600d0963fSdilpreet } 91700d0963fSdilpreet 91800d0963fSdilpreet /* 91900d0963fSdilpreet * pci_ereport_setup: Detect PCI device type and initialize structures to be 92000d0963fSdilpreet * used to generate ereports based on detected generic device errors. 92100d0963fSdilpreet */ 92200d0963fSdilpreet void 92300d0963fSdilpreet pci_ereport_setup(dev_info_t *dip) 92400d0963fSdilpreet { 92500d0963fSdilpreet struct dev_info *devi = DEVI(dip); 92600d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl; 92700d0963fSdilpreet pci_erpt_t *erpt_p; 92800d0963fSdilpreet uint8_t pci_hdr_type; 92900d0963fSdilpreet uint16_t pci_status; 93000d0963fSdilpreet pci_regspec_t *pci_rp; 93100d0963fSdilpreet int32_t len; 93200d0963fSdilpreet uint32_t phys_hi; 93300d0963fSdilpreet 93400d0963fSdilpreet /* 93500d0963fSdilpreet * If device is not ereport capbable then report an error against the 93600d0963fSdilpreet * driver for using this interface, 93700d0963fSdilpreet */ 93800d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 93900d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 94000d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 94100d0963fSdilpreet return; 94200d0963fSdilpreet } 94300d0963fSdilpreet 94400d0963fSdilpreet /* 94500d0963fSdilpreet * ASSERT fmhdl exists and fh_bus_specific is NULL. 94600d0963fSdilpreet */ 94700d0963fSdilpreet ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL)); 94800d0963fSdilpreet 94900d0963fSdilpreet erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP); 95000d0963fSdilpreet 95100d0963fSdilpreet if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS) 95200d0963fSdilpreet goto error; 95300d0963fSdilpreet 95400d0963fSdilpreet erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP); 95500d0963fSdilpreet 95600d0963fSdilpreet pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT); 95700d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK) 95800d0963fSdilpreet goto error; 95900d0963fSdilpreet 96000d0963fSdilpreet /* 96100d0963fSdilpreet * Get header type and record if device is a bridge. 96200d0963fSdilpreet */ 96300d0963fSdilpreet pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER); 96400d0963fSdilpreet if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK) 96500d0963fSdilpreet goto error; 96600d0963fSdilpreet 96700d0963fSdilpreet /* 96800d0963fSdilpreet * Check to see if PCI device is a bridge, if so allocate pci bridge 96900d0963fSdilpreet * error register structure. 97000d0963fSdilpreet */ 97100d0963fSdilpreet if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 97200d0963fSdilpreet erpt_p->pe_dflags |= PCI_BRIDGE_DEV; 97300d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc( 97400d0963fSdilpreet sizeof (pci_bdg_error_regs_t), KM_SLEEP); 97500d0963fSdilpreet } 97600d0963fSdilpreet 97700d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 97800d0963fSdilpreet (caddr_t)&pci_rp, &len) == DDI_SUCCESS) { 97900d0963fSdilpreet phys_hi = pci_rp->pci_phys_hi; 98000d0963fSdilpreet kmem_free(pci_rp, len); 98100d0963fSdilpreet 98200d0963fSdilpreet erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >> 98300d0963fSdilpreet PCI_REG_FUNC_SHIFT); 98400d0963fSdilpreet } 98500d0963fSdilpreet 98600d0963fSdilpreet 98700d0963fSdilpreet if (!(pci_status & PCI_STAT_CAP)) { 98800d0963fSdilpreet goto done; 98900d0963fSdilpreet } 99000d0963fSdilpreet 99100d0963fSdilpreet /* 99200d0963fSdilpreet * Initialize structures for PCI Express and PCI-X devices. 99300d0963fSdilpreet * Order matters below and pcie_ereport_setup should preceed 99400d0963fSdilpreet * pcix_ereport_setup. 99500d0963fSdilpreet */ 99600d0963fSdilpreet pcie_ereport_setup(dip, erpt_p); 99700d0963fSdilpreet 99800d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) { 99900d0963fSdilpreet pcix_ereport_setup(dip, erpt_p); 100000d0963fSdilpreet } 100100d0963fSdilpreet 100200d0963fSdilpreet done: 100300d0963fSdilpreet pci_regs_gather(dip, erpt_p); 100400d0963fSdilpreet pci_regs_clear(erpt_p); 100500d0963fSdilpreet 100600d0963fSdilpreet /* 100700d0963fSdilpreet * Before returning set fh_bus_specific to completed pci_erpt_t 100800d0963fSdilpreet * structure 100900d0963fSdilpreet */ 101000d0963fSdilpreet fmhdl->fh_bus_specific = (void *)erpt_p; 101100d0963fSdilpreet 101200d0963fSdilpreet return; 101300d0963fSdilpreet error: 101400d0963fSdilpreet if (erpt_p->pe_pci_regs) 101500d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 101600d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 101700d0963fSdilpreet erpt_p = NULL; 101800d0963fSdilpreet } 101900d0963fSdilpreet 102000d0963fSdilpreet static void 102100d0963fSdilpreet pcix_ereport_teardown(pci_erpt_t *erpt_p) 102200d0963fSdilpreet { 102300d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 102400d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 102500d0963fSdilpreet uint16_t pcix_ver; 102600d0963fSdilpreet 102700d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 102800d0963fSdilpreet pcix_ver = pcix_bdg_regs->pcix_bdg_ver; 102900d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 103000d0963fSdilpreet int i; 103100d0963fSdilpreet for (i = 0; i < 2; i++) 103200d0963fSdilpreet kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i], 103300d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 103400d0963fSdilpreet } 103500d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t)); 103600d0963fSdilpreet } else { 103700d0963fSdilpreet pcix_error_regs_t *pcix_regs; 103800d0963fSdilpreet uint16_t pcix_ver; 103900d0963fSdilpreet 104000d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 104100d0963fSdilpreet pcix_ver = pcix_regs->pcix_ver; 104200d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 104300d0963fSdilpreet kmem_free(pcix_regs->pcix_ecc_regs, 104400d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 104500d0963fSdilpreet } 104600d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t)); 104700d0963fSdilpreet } 104800d0963fSdilpreet } 104900d0963fSdilpreet 105000d0963fSdilpreet static void 105100d0963fSdilpreet pcie_ereport_teardown(pci_erpt_t *erpt_p) 105200d0963fSdilpreet { 105300d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 105400d0963fSdilpreet 105500d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_ADV_DEV) { 105600d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv = pcie_regs->pcie_adv_regs; 105700d0963fSdilpreet 105800d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) 105900d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_bdg_regs, 106000d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t)); 106100d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 106200d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_rc_regs, 106300d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t)); 106400d0963fSdilpreet kmem_free(pcie_adv, sizeof (pcie_adv_error_regs_t)); 106500d0963fSdilpreet } 106600d0963fSdilpreet 106700d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 106800d0963fSdilpreet kmem_free(pcie_regs->pcie_rc_regs, 106900d0963fSdilpreet sizeof (pcie_rc_error_regs_t)); 107000d0963fSdilpreet 107100d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 107200d0963fSdilpreet if (erpt_p->pe_dflags & PCIX_DEV) { 107300d0963fSdilpreet uint16_t pcix_ver = pcie_regs->pcix_bdg_regs-> 107400d0963fSdilpreet pcix_bdg_ver; 107500d0963fSdilpreet 107600d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 107700d0963fSdilpreet int i; 107800d0963fSdilpreet for (i = 0; i < 2; i++) 107900d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs-> 108000d0963fSdilpreet pcix_bdg_ecc_regs[i], 108100d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 108200d0963fSdilpreet } 108300d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs, 108400d0963fSdilpreet sizeof (pcix_bdg_error_regs_t)); 108500d0963fSdilpreet } 108600d0963fSdilpreet } 108700d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcie_error_regs_t)); 108800d0963fSdilpreet } 108900d0963fSdilpreet 109000d0963fSdilpreet void 109100d0963fSdilpreet pci_ereport_teardown(dev_info_t *dip) 109200d0963fSdilpreet { 109300d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 109400d0963fSdilpreet pci_erpt_t *erpt_p; 109500d0963fSdilpreet 109600d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 109700d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 109800d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 109900d0963fSdilpreet } 110000d0963fSdilpreet 110100d0963fSdilpreet ASSERT(fmhdl); 110200d0963fSdilpreet 110300d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 110400d0963fSdilpreet if (erpt_p == NULL) 110500d0963fSdilpreet return; 110600d0963fSdilpreet 110700d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 110800d0963fSdilpreet pcie_ereport_teardown(erpt_p); 110900d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 111000d0963fSdilpreet pcix_ereport_teardown(erpt_p); 111100d0963fSdilpreet pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl); 111200d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) 111300d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs, 111400d0963fSdilpreet sizeof (pci_bdg_error_regs_t)); 111500d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 111600d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 111700d0963fSdilpreet fmhdl->fh_bus_specific = NULL; 111800d0963fSdilpreet /* 111900d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 112000d0963fSdilpreet * interfaces create the necessary properties for us. 112100d0963fSdilpreet */ 112200d0963fSdilpreet #if defined(__sparc) 112300d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcix-capid-pointer"); 112400d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-slotcap-reg"); 112500d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-reg"); 112600d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-pointer"); 112700d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-aer-pointer"); 112800d0963fSdilpreet #endif 112900d0963fSdilpreet } 113000d0963fSdilpreet 113100d0963fSdilpreet /* 113200d0963fSdilpreet * Function used by PCI device and nexus error handlers to check if a 113300d0963fSdilpreet * captured address resides in their DMA or ACC handle caches or the caches of 113400d0963fSdilpreet * their children devices, respectively. 113500d0963fSdilpreet */ 113600d0963fSdilpreet static int 113700d0963fSdilpreet pci_dev_hdl_lookup(dev_info_t *dip, int type, ddi_fm_error_t *derr, 113800d0963fSdilpreet void *addr) 113900d0963fSdilpreet { 114000d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 114100d0963fSdilpreet pci_erpt_t *erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 114200d0963fSdilpreet 114300d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) 114400d0963fSdilpreet return (ndi_fmc_error(dip, NULL, type, derr->fme_ena, addr)); 114500d0963fSdilpreet else 114600d0963fSdilpreet return (ndi_fmc_entry_error(dip, type, derr, addr)); 114700d0963fSdilpreet } 114800d0963fSdilpreet 114900d0963fSdilpreet static void 115000d0963fSdilpreet pcie_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 115100d0963fSdilpreet char *buf, int errtype) 115200d0963fSdilpreet { 115300d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 115400d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 1155390e643aSdilpreet pcie_adv_rc_error_regs_t *pcie_adv_rc_regs; 115600d0963fSdilpreet 115700d0963fSdilpreet switch (errtype) { 115800d0963fSdilpreet case PCIEX_TYPE_CE: 115900d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 116000d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 116100d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 116200d0963fSdilpreet pcie_regs->pcie_err_status, 116300d0963fSdilpreet PCIEX_CE_STATUS_REG, DATA_TYPE_UINT32, 116400d0963fSdilpreet pcie_adv_regs->pcie_ce_status, NULL); 116500d0963fSdilpreet break; 116600d0963fSdilpreet case PCIEX_TYPE_UE: 116700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 116800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 116900d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 117000d0963fSdilpreet pcie_regs->pcie_err_status, 117100d0963fSdilpreet PCIEX_UE_STATUS_REG, DATA_TYPE_UINT32, 117200d0963fSdilpreet pcie_adv_regs->pcie_ue_status, PCIEX_UE_SEV_REG, 117300d0963fSdilpreet DATA_TYPE_UINT32, pcie_adv_regs->pcie_ue_sev, 117400d0963fSdilpreet PCIEX_ADV_CTL, DATA_TYPE_UINT32, 117500d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl, 117600d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 117700d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 117800d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 117900d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 118000d0963fSdilpreet 1 : NULL, 118100d0963fSdilpreet #ifdef DEBUG 118200d0963fSdilpreet PCIEX_UE_HDR0, DATA_TYPE_UINT32, 118300d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0, 118400d0963fSdilpreet PCIEX_UE_HDR1, DATA_TYPE_UINT32, 118500d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[0], 118600d0963fSdilpreet PCIEX_UE_HDR2, DATA_TYPE_UINT32, 118700d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[1], 118800d0963fSdilpreet PCIEX_UE_HDR3, DATA_TYPE_UINT32, 118900d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[2], 119000d0963fSdilpreet #endif 119100d0963fSdilpreet NULL); 119200d0963fSdilpreet break; 119300d0963fSdilpreet case PCIEX_TYPE_GEN: 119400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 119500d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 119600d0963fSdilpreet 0, PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 119700d0963fSdilpreet pcie_regs->pcie_err_status, NULL); 119800d0963fSdilpreet break; 119900d0963fSdilpreet case PCIEX_TYPE_RC_UE_MSG: 120000d0963fSdilpreet case PCIEX_TYPE_RC_CE_MSG: 1201390e643aSdilpreet pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs; 1202390e643aSdilpreet 120300d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 120400d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 120500d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 120600d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, 120700d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 120800d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 120900d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id : 121000d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id, 121100d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 121200d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 121300d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 121400d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id != 0) : 121500d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 121600d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id != 0), NULL); 121700d0963fSdilpreet break; 121800d0963fSdilpreet case PCIEX_TYPE_RC_MULT_MSG: 1219390e643aSdilpreet pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs; 1220390e643aSdilpreet 122100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 122200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 122300d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 122400d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, NULL); 122500d0963fSdilpreet break; 122600d0963fSdilpreet default: 122700d0963fSdilpreet break; 122800d0963fSdilpreet } 122900d0963fSdilpreet } 123000d0963fSdilpreet 123100d0963fSdilpreet static void 123200d0963fSdilpreet pcie_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *eprt_p) 123300d0963fSdilpreet { 123400d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)eprt_p->pe_regs; 123500d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 123600d0963fSdilpreet pcie_tlp_hdr_t *ue_hdr0; 123700d0963fSdilpreet uint32_t *ue_hdr; 123800d0963fSdilpreet uint64_t addr = NULL; 123900d0963fSdilpreet 124000d0963fSdilpreet if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_UE_HDR_VALID)) { 124100d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 124200d0963fSdilpreet return; 124300d0963fSdilpreet } 124400d0963fSdilpreet ue_hdr0 = (pcie_tlp_hdr_t *)&pcie_adv_regs->pcie_ue_hdr0; 124500d0963fSdilpreet ue_hdr = pcie_adv_regs->pcie_ue_hdr; 124600d0963fSdilpreet 124700d0963fSdilpreet switch (ue_hdr0->type) { 124800d0963fSdilpreet case PCIE_TLP_TYPE_MEM: 124900d0963fSdilpreet case PCIE_TLP_TYPE_MEMLK: 125000d0963fSdilpreet if ((ue_hdr0->fmt & 0x1) == 0x1) { 125100d0963fSdilpreet pcie_mem64_t *mem64_tlp = (pcie_mem64_t *)ue_hdr; 125200d0963fSdilpreet 125300d0963fSdilpreet addr = (uint64_t)mem64_tlp->addr1 << 32 | 125400d0963fSdilpreet (uint32_t)mem64_tlp->addr0 << 2; 125500d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = mem64_tlp->rid; 125600d0963fSdilpreet } else { 125700d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 125800d0963fSdilpreet 125900d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 126000d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 126100d0963fSdilpreet } 126200d0963fSdilpreet 126300d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, DMA_HANDLE, derr, 126400d0963fSdilpreet (void *) &addr); 126500d0963fSdilpreet /* 126600d0963fSdilpreet * If DMA handle is not found error could have been a memory 126700d0963fSdilpreet * mapped IO address so check in the access cache 126800d0963fSdilpreet */ 126900d0963fSdilpreet if (derr->fme_status == DDI_FM_UNKNOWN) 127000d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE, 127100d0963fSdilpreet derr, (void *) &addr); 127200d0963fSdilpreet break; 127300d0963fSdilpreet 127400d0963fSdilpreet case PCIE_TLP_TYPE_IO: 127500d0963fSdilpreet { 127600d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 127700d0963fSdilpreet 127800d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 127900d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 128000d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE, 128100d0963fSdilpreet derr, (void *) &addr); 128200d0963fSdilpreet break; 128300d0963fSdilpreet } 128400d0963fSdilpreet case PCIE_TLP_TYPE_CFG0: 128500d0963fSdilpreet case PCIE_TLP_TYPE_CFG1: 128600d0963fSdilpreet { 128700d0963fSdilpreet pcie_cfg_t *cfg_tlp = (pcie_cfg_t *)ue_hdr; 128800d0963fSdilpreet 1289ac4d633fSstephh pcie_adv_regs->pcie_adv_bdf = cfg_tlp->rid; 129000d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 129100d0963fSdilpreet break; 129200d0963fSdilpreet } 129300d0963fSdilpreet case PCIE_TLP_TYPE_MSG: 129400d0963fSdilpreet { 129500d0963fSdilpreet pcie_msg_t *msg_tlp = (pcie_msg_t *)ue_hdr; 129600d0963fSdilpreet 129700d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = msg_tlp->rid; 129800d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 129900d0963fSdilpreet break; 130000d0963fSdilpreet } 130100d0963fSdilpreet case PCIE_TLP_TYPE_CPL: 130200d0963fSdilpreet case PCIE_TLP_TYPE_CPLLK: 130300d0963fSdilpreet { 130400d0963fSdilpreet pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)ue_hdr; 130500d0963fSdilpreet 130600d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = cpl_tlp->cid; 130700d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 130800d0963fSdilpreet break; 130900d0963fSdilpreet } 131000d0963fSdilpreet case PCIE_TLP_TYPE_MSI: 131100d0963fSdilpreet default: 131200d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 131300d0963fSdilpreet } 131400d0963fSdilpreet 131500d0963fSdilpreet /* 131600d0963fSdilpreet * If no handle was found in the children caches and their is no 131700d0963fSdilpreet * address infomation already stored and we have a captured address 131800d0963fSdilpreet * then we need to store it away so that intermediate bridges can 131900d0963fSdilpreet * check if the address exists in their handle caches. 132000d0963fSdilpreet */ 132100d0963fSdilpreet if (derr->fme_status == DDI_FM_UNKNOWN && 132200d0963fSdilpreet derr->fme_bus_specific == NULL && 132300d0963fSdilpreet addr != NULL) 132400d0963fSdilpreet derr->fme_bus_specific = (void *)(uintptr_t)addr; 132500d0963fSdilpreet } 132600d0963fSdilpreet 132700d0963fSdilpreet static void 132800d0963fSdilpreet pcie_pci_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *eprt_p) 132900d0963fSdilpreet { 133000d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)eprt_p->pe_regs; 133100d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 133200d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 133300d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 133400d0963fSdilpreet uint64_t addr = NULL; 133500d0963fSdilpreet pcix_attr_t *pcie_pci_sue_attr; 133600d0963fSdilpreet int cmd; 133700d0963fSdilpreet int dual_addr = 0; 133800d0963fSdilpreet 133900d0963fSdilpreet if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_HDR_VALID)) { 134000d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 134100d0963fSdilpreet return; 134200d0963fSdilpreet } 134300d0963fSdilpreet 134400d0963fSdilpreet pcie_pci_sue_attr = (pcix_attr_t *)&pcie_bdg_regs->pcie_sue_hdr0; 134500d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 134600d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK; 134700d0963fSdilpreet cmd_switch: 134800d0963fSdilpreet switch (cmd) { 134900d0963fSdilpreet case PCI_PCIX_CMD_IORD: 135000d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 135100d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 135200d0963fSdilpreet 135300d0963fSdilpreet addr = pcie_bdg_regs->pcie_sue_hdr[2]; 135400d0963fSdilpreet addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) | 135500d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1]; 135600d0963fSdilpreet 135700d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE, 135800d0963fSdilpreet derr, (void *) &addr); 135900d0963fSdilpreet break; 136000d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 136100d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 136200d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 136300d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 136400d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 136500d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 136600d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 136700d0963fSdilpreet 136800d0963fSdilpreet addr = pcie_bdg_regs->pcie_sue_hdr[2]; 136900d0963fSdilpreet addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) | 137000d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1]; 137100d0963fSdilpreet 137200d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, DMA_HANDLE, 137300d0963fSdilpreet derr, (void *) &addr); 137400d0963fSdilpreet if (derr->fme_status == DDI_FM_UNKNOWN) 137500d0963fSdilpreet derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE, 137600d0963fSdilpreet derr, (void *) &addr); 137700d0963fSdilpreet break; 137800d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 137900d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 1380ac4d633fSstephh pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 1381ac4d633fSstephh 138200d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 138300d0963fSdilpreet break; 138400d0963fSdilpreet case PCI_PCIX_CMD_DADR: 138500d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 138600d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) & 138700d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_MASK; 138800d0963fSdilpreet if (dual_addr) 138900d0963fSdilpreet break; 139000d0963fSdilpreet ++dual_addr; 139100d0963fSdilpreet goto cmd_switch; 139200d0963fSdilpreet default: 139300d0963fSdilpreet derr->fme_status = DDI_FM_UNKNOWN; 139400d0963fSdilpreet } 139500d0963fSdilpreet 139600d0963fSdilpreet /* 139700d0963fSdilpreet * If no handle was found in the children caches and their is no 139800d0963fSdilpreet * address infomation already stored and we have a captured address 139900d0963fSdilpreet * then we need to store it away so that intermediate bridges can 140000d0963fSdilpreet * check if the address exists in their handle caches. 140100d0963fSdilpreet */ 140200d0963fSdilpreet if (derr->fme_status == DDI_FM_UNKNOWN && 140300d0963fSdilpreet derr->fme_bus_specific == NULL && 140400d0963fSdilpreet addr != NULL) 140500d0963fSdilpreet derr->fme_bus_specific = (void *)(uintptr_t)addr; 140600d0963fSdilpreet } 140700d0963fSdilpreet 140800d0963fSdilpreet static int 140900d0963fSdilpreet pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, 141000d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs) 141100d0963fSdilpreet { 141200d0963fSdilpreet int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf; 141300d0963fSdilpreet uint64_t addr; 141400d0963fSdilpreet 141500d0963fSdilpreet addr = pcix_ecc_regs->pcix_ecc_secaddr; 141600d0963fSdilpreet addr = addr << 32; 141700d0963fSdilpreet addr |= pcix_ecc_regs->pcix_ecc_fstaddr; 141800d0963fSdilpreet 141900d0963fSdilpreet switch (cmd) { 142000d0963fSdilpreet case PCI_PCIX_CMD_INTR: 142100d0963fSdilpreet case PCI_PCIX_CMD_SPEC: 142200d0963fSdilpreet return (DDI_FM_FATAL); 142300d0963fSdilpreet case PCI_PCIX_CMD_IORD: 142400d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 142500d0963fSdilpreet return (pci_dev_hdl_lookup(dip, ACC_HANDLE, derr, 142600d0963fSdilpreet (void *) &addr)); 142700d0963fSdilpreet case PCI_PCIX_CMD_DEVID: 142800d0963fSdilpreet return (DDI_FM_FATAL); 142900d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 143000d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 143100d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 143200d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 143300d0963fSdilpreet return (pci_dev_hdl_lookup(dip, DMA_HANDLE, derr, 143400d0963fSdilpreet (void *) &addr)); 143500d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 143600d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 143700d0963fSdilpreet return (pci_dev_hdl_lookup(dip, ACC_HANDLE, derr, 143800d0963fSdilpreet (void *) &addr)); 143900d0963fSdilpreet case PCI_PCIX_CMD_SPL: 144000d0963fSdilpreet case PCI_PCIX_CMD_DADR: 144100d0963fSdilpreet return (DDI_FM_FATAL); 144200d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 144300d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 144400d0963fSdilpreet return (pci_dev_hdl_lookup(dip, DMA_HANDLE, derr, 144500d0963fSdilpreet (void *) &addr)); 144600d0963fSdilpreet default: 144700d0963fSdilpreet return (DDI_FM_FATAL); 144800d0963fSdilpreet } 144900d0963fSdilpreet } 145000d0963fSdilpreet 145100d0963fSdilpreet /*ARGSUSED*/ 145200d0963fSdilpreet static int 145300d0963fSdilpreet pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 145400d0963fSdilpreet { 145500d0963fSdilpreet pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs; 145600d0963fSdilpreet int fatal = 0; 145700d0963fSdilpreet int nonfatal = 0; 145800d0963fSdilpreet int unknown = 0; 145900d0963fSdilpreet int ok = 0; 146000d0963fSdilpreet int ret = DDI_FM_OK; 146100d0963fSdilpreet char buf[FM_MAX_CLASS]; 146200d0963fSdilpreet int i; 146300d0963fSdilpreet 146400d0963fSdilpreet if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) 146500d0963fSdilpreet goto done; 146600d0963fSdilpreet 146700d0963fSdilpreet if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) && 146800d0963fSdilpreet (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) { 146900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 147000d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_DTO); 147100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 147200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 147300d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 147400d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 147500d0963fSdilpreet DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL); 147600d0963fSdilpreet unknown++; 147700d0963fSdilpreet } 147800d0963fSdilpreet 147900d0963fSdilpreet if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) { 148000d0963fSdilpreet for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) { 148100d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & 148200d0963fSdilpreet pci_bdg_err_tbl[i].reg_bit) { 148300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 148400d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, 148500d0963fSdilpreet pci_bdg_err_tbl[i].err_class); 148600d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 148700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 148800d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 148900d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 149000d0963fSdilpreet DATA_TYPE_UINT16, 149100d0963fSdilpreet pci_bdg_regs->pci_bdg_ctrl, NULL); 1492ac4d633fSstephh PCI_FM_SEV_INC(pci_bdg_err_tbl[i].flags); 149300d0963fSdilpreet if (derr->fme_bus_specific && 149400d0963fSdilpreet pci_bdg_err_tbl[i].terr_class) 149500d0963fSdilpreet pci_target_enqueue(derr->fme_ena, 149600d0963fSdilpreet pci_bdg_err_tbl[i].terr_class, 149700d0963fSdilpreet PCI_ERROR_SUBCLASS, 149800d0963fSdilpreet (uintptr_t)derr->fme_bus_specific); 149900d0963fSdilpreet } 150000d0963fSdilpreet } 1501ac4d633fSstephh #if !defined(__sparc) 1502ac4d633fSstephh /* 1503ac4d633fSstephh * For x86, many drivers and even user-level code currently get 1504ac4d633fSstephh * away with accessing bad addresses, getting a UR and getting 1505ac4d633fSstephh * -1 returned. Unfortunately, we have no control over this, so 1506ac4d633fSstephh * we will have to treat all URs as nonfatal. Moreover, if the 1507ac4d633fSstephh * leaf driver is non-hardened, then we don't actually see the 1508ac4d633fSstephh * UR directly. All we see is a secondary bus master abort at 1509ac4d633fSstephh * the root complex - so it's this condition that we actually 1510ac4d633fSstephh * need to treat as nonfatal (providing no other unrelated nfe 1511ac4d633fSstephh * conditions have also been seen by the root complex). 1512ac4d633fSstephh */ 1513ac4d633fSstephh if ((erpt_p->pe_dflags & PCIEX_RC_DEV) && 1514ac4d633fSstephh (pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_R_MAST_AB) && 1515ac4d633fSstephh !(pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_S_PERROR)) { 1516ac4d633fSstephh pcie_error_regs_t *pcie_regs = 1517ac4d633fSstephh (pcie_error_regs_t *)erpt_p->pe_regs; 1518ac4d633fSstephh if ((pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) && 1519ac4d633fSstephh !(pcie_regs->pcie_err_status & 1520ac4d633fSstephh PCIE_DEVSTS_NFE_DETECTED)) 1521ac4d633fSstephh nonfatal++; 1522ac4d633fSstephh } 1523ac4d633fSstephh #endif 152400d0963fSdilpreet } 152500d0963fSdilpreet 152600d0963fSdilpreet done: 152700d0963fSdilpreet 152800d0963fSdilpreet /* 152900d0963fSdilpreet * Need to check for poke and cautious put. We already know peek 153000d0963fSdilpreet * and cautious get errors occurred (as we got a trap) and we know 153100d0963fSdilpreet * they are nonfatal. 153200d0963fSdilpreet */ 153300d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_EXPECTED) { 153400d0963fSdilpreet /* 153500d0963fSdilpreet * for cautious puts we treat all errors as nonfatal. Actually 153600d0963fSdilpreet * we set nonfatal for cautious gets as well - doesn't do any 153700d0963fSdilpreet * harm 153800d0963fSdilpreet */ 153900d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 154000d0963fSdilpreet PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR)) 154100d0963fSdilpreet nonfatal++; 154200d0963fSdilpreet 154300d0963fSdilpreet /* 154400d0963fSdilpreet * for cautious accesses we already have the acc_handle. Just 154500d0963fSdilpreet * need to call children to clear their error bits 154600d0963fSdilpreet */ 154700d0963fSdilpreet ret = ndi_fm_handler_dispatch(dip, NULL, derr); 154800d0963fSdilpreet PCI_FM_SEV_INC(ret); 154900d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 155000d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 155100d0963fSdilpreet } 155200d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_POKE) { 155300d0963fSdilpreet /* 155400d0963fSdilpreet * special case for pokes - we only consider master abort 155500d0963fSdilpreet * and target abort as nonfatal. Sserr with no master abort is 155600d0963fSdilpreet * fatal, but master/target abort can come in on separate 155700d0963fSdilpreet * instance, so return unknown and parent will determine if 155800d0963fSdilpreet * nonfatal (if another child returned nonfatal - ie master 155900d0963fSdilpreet * or target abort) or fatal otherwise 156000d0963fSdilpreet */ 156100d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 156200d0963fSdilpreet PCI_STAT_R_MAST_AB)) 156300d0963fSdilpreet nonfatal++; 156400d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR) 156500d0963fSdilpreet unknown++; 156600d0963fSdilpreet } 156700d0963fSdilpreet 156800d0963fSdilpreet /* 156900d0963fSdilpreet * If errant address is passed in then attempt to find 157000d0963fSdilpreet * ACC/DMA handle in caches. 157100d0963fSdilpreet */ 157200d0963fSdilpreet if (derr->fme_bus_specific) { 157300d0963fSdilpreet int i; 157400d0963fSdilpreet 157500d0963fSdilpreet for (i = 0; i < 2; i++) { 157600d0963fSdilpreet ret = ndi_fmc_error(dip, NULL, i ? ACC_HANDLE : 157700d0963fSdilpreet DMA_HANDLE, derr->fme_ena, 157800d0963fSdilpreet (void *)&derr->fme_bus_specific); 157900d0963fSdilpreet PCI_FM_SEV_INC(ret); 158000d0963fSdilpreet } 158100d0963fSdilpreet } 158200d0963fSdilpreet 158300d0963fSdilpreet /* 158400d0963fSdilpreet * now check children below the bridge, only if errant handle was not 158500d0963fSdilpreet * found 158600d0963fSdilpreet */ 158700d0963fSdilpreet if (!derr->fme_acc_handle && !derr->fme_dma_handle) { 158800d0963fSdilpreet ret = ndi_fm_handler_dispatch(dip, NULL, derr); 158900d0963fSdilpreet PCI_FM_SEV_INC(ret); 159000d0963fSdilpreet } 159100d0963fSdilpreet 159200d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 159300d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 159400d0963fSdilpreet } 159500d0963fSdilpreet 159600d0963fSdilpreet static int 159700d0963fSdilpreet pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 159800d0963fSdilpreet void *pe_regs) 159900d0963fSdilpreet { 160000d0963fSdilpreet pcix_error_regs_t *pcix_regs; 160100d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 160200d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs; 160300d0963fSdilpreet int bridge; 160400d0963fSdilpreet int i; 160500d0963fSdilpreet int ecc_phase; 160600d0963fSdilpreet int ecc_corr; 160700d0963fSdilpreet int sec_ue; 160800d0963fSdilpreet int sec_ce; 160900d0963fSdilpreet int fatal = 0; 161000d0963fSdilpreet int nonfatal = 0; 161100d0963fSdilpreet int unknown = 0; 161200d0963fSdilpreet int ok = 0; 161300d0963fSdilpreet char buf[FM_MAX_CLASS]; 161400d0963fSdilpreet 161500d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 161600d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 161700d0963fSdilpreet bridge = 1; 161800d0963fSdilpreet } else { 161900d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)pe_regs; 162000d0963fSdilpreet bridge = 0; 162100d0963fSdilpreet } 162200d0963fSdilpreet 162300d0963fSdilpreet for (i = 0; i < (bridge ? 2 : 1); i++) { 162400d0963fSdilpreet int ret = DDI_FM_OK; 162500d0963fSdilpreet pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] : 162600d0963fSdilpreet pcix_regs->pcix_ecc_regs; 162700d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) { 162800d0963fSdilpreet ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat & 162900d0963fSdilpreet PCI_PCIX_ECC_PHASE) >> 0x4; 163000d0963fSdilpreet ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat & 163100d0963fSdilpreet PCI_PCIX_ECC_CORR); 163200d0963fSdilpreet sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat & 163300d0963fSdilpreet PCI_PCIX_ECC_S_UE); 163400d0963fSdilpreet sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat & 163500d0963fSdilpreet PCI_PCIX_ECC_S_CE); 163600d0963fSdilpreet 163700d0963fSdilpreet switch (ecc_phase) { 163800d0963fSdilpreet case PCI_PCIX_ECC_PHASE_NOERR: 163900d0963fSdilpreet break; 164000d0963fSdilpreet case PCI_PCIX_ECC_PHASE_FADDR: 164100d0963fSdilpreet case PCI_PCIX_ECC_PHASE_SADDR: 1642ac4d633fSstephh PCI_FM_SEV_INC(ecc_corr ? DDI_FM_OK : 164300d0963fSdilpreet DDI_FM_FATAL); 164400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 164500d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 164600d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 164700d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ADDR : 164800d0963fSdilpreet PCIX_ECC_UE_ADDR); 164900d0963fSdilpreet break; 165000d0963fSdilpreet case PCI_PCIX_ECC_PHASE_ATTR: 165100d0963fSdilpreet PCI_FM_SEV_INC(ecc_corr ? 1652ac4d633fSstephh DDI_FM_OK : DDI_FM_FATAL); 165300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 165400d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 165500d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 165600d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ATTR : 165700d0963fSdilpreet PCIX_ECC_UE_ATTR); 165800d0963fSdilpreet break; 165900d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA32: 166000d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA64: 166100d0963fSdilpreet if (ecc_corr) 1662ac4d633fSstephh ret = DDI_FM_OK; 166300d0963fSdilpreet else 166400d0963fSdilpreet ret = pcix_check_addr(dip, derr, 166500d0963fSdilpreet pcix_ecc_regs); 166600d0963fSdilpreet PCI_FM_SEV_INC(ret); 166700d0963fSdilpreet 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_DATA : 167200d0963fSdilpreet PCIX_ECC_UE_DATA); 167300d0963fSdilpreet break; 167400d0963fSdilpreet } 167500d0963fSdilpreet if (ecc_phase) 167600d0963fSdilpreet if (bridge) 167700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 167800d0963fSdilpreet derr->fme_ena, 167900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 168000d0963fSdilpreet DATA_TYPE_UINT8, 0, 168100d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 168200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 168300d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 168400d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 168500d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 168600d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 168700d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 168800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 168900d0963fSdilpreet else 169000d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 169100d0963fSdilpreet derr->fme_ena, 169200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 169300d0963fSdilpreet DATA_TYPE_UINT8, 0, 169400d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 169500d0963fSdilpreet pcix_regs->pcix_command, 169600d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 169700d0963fSdilpreet pcix_regs->pcix_status, 169800d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 169900d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 170000d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 170100d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 170200d0963fSdilpreet if (sec_ce || sec_ue) { 170300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 170400d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 170500d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 170600d0963fSdilpreet sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE); 170700d0963fSdilpreet if (bridge) 170800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 170900d0963fSdilpreet derr->fme_ena, 171000d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 171100d0963fSdilpreet DATA_TYPE_UINT8, 0, 171200d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 171300d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 171400d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 171500d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 171600d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 171700d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 171800d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 171900d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 172000d0963fSdilpreet else 172100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 172200d0963fSdilpreet derr->fme_ena, 172300d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 172400d0963fSdilpreet DATA_TYPE_UINT8, 0, 172500d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 172600d0963fSdilpreet pcix_regs->pcix_command, 172700d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 172800d0963fSdilpreet pcix_regs->pcix_status, 172900d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 173000d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 173100d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 173200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 173300d0963fSdilpreet PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL : 1734ac4d633fSstephh DDI_FM_OK); 173500d0963fSdilpreet } 173600d0963fSdilpreet } 173700d0963fSdilpreet } 173800d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 173900d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 174000d0963fSdilpreet } 174100d0963fSdilpreet 174200d0963fSdilpreet static int 174300d0963fSdilpreet pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 174400d0963fSdilpreet void *pe_regs) 174500d0963fSdilpreet { 174600d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 174700d0963fSdilpreet int fatal = 0; 174800d0963fSdilpreet int nonfatal = 0; 174900d0963fSdilpreet int unknown = 0; 175000d0963fSdilpreet int ok = 0; 175100d0963fSdilpreet char buf[FM_MAX_CLASS]; 175200d0963fSdilpreet int i; 175300d0963fSdilpreet 175400d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) { 175500d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 175600d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_stat & 175700d0963fSdilpreet pcix_err_tbl[i].reg_bit)) { 175800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 175900d0963fSdilpreet PCIX_ERROR_SUBCLASS, 176000d0963fSdilpreet pcix_err_tbl[i].err_class); 176100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 176200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 176300d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 176400d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 176500d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 176600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 176700d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 176800d0963fSdilpreet } 176900d0963fSdilpreet } 177000d0963fSdilpreet } 177100d0963fSdilpreet 177200d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) { 177300d0963fSdilpreet for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) { 177400d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_sec_stat & 177500d0963fSdilpreet pcix_sec_err_tbl[i].reg_bit)) { 177600d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s", 177700d0963fSdilpreet PCIX_ERROR_SUBCLASS, 177800d0963fSdilpreet PCIX_SEC_ERROR_SUBCLASS, 177900d0963fSdilpreet pcix_sec_err_tbl[i].err_class); 178000d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 178100d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 178200d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 178300d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 178400d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 178500d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 178600d0963fSdilpreet PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags); 178700d0963fSdilpreet } 178800d0963fSdilpreet } 178900d0963fSdilpreet } 179000d0963fSdilpreet 179100d0963fSdilpreet /* Log/Handle ECC errors */ 179200d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 179300d0963fSdilpreet int ret; 179400d0963fSdilpreet 179500d0963fSdilpreet ret = pcix_ecc_error_report(dip, derr, erpt_p, 179600d0963fSdilpreet (void *)pcix_bdg_regs); 179700d0963fSdilpreet PCI_FM_SEV_INC(ret); 179800d0963fSdilpreet } 179900d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 180000d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 180100d0963fSdilpreet } 180200d0963fSdilpreet 180300d0963fSdilpreet static int 180400d0963fSdilpreet pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 180500d0963fSdilpreet { 180600d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 180700d0963fSdilpreet int fatal = 0; 180800d0963fSdilpreet int nonfatal = 0; 180900d0963fSdilpreet int unknown = 0; 181000d0963fSdilpreet int ok = 0; 181100d0963fSdilpreet char buf[FM_MAX_CLASS]; 181200d0963fSdilpreet int i; 181300d0963fSdilpreet 181400d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) { 181500d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 181600d0963fSdilpreet if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit)) 181700d0963fSdilpreet continue; 181800d0963fSdilpreet 181900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 182000d0963fSdilpreet PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class); 182100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 182200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 182300d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 182400d0963fSdilpreet pcix_regs->pcix_command, PCIX_STATUS, 182500d0963fSdilpreet DATA_TYPE_UINT32, pcix_regs->pcix_status, 182600d0963fSdilpreet NULL); 182700d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 182800d0963fSdilpreet } 182900d0963fSdilpreet } 183000d0963fSdilpreet /* Log/Handle ECC errors */ 183100d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 183200d0963fSdilpreet int ret = pcix_ecc_error_report(dip, derr, erpt_p, 183300d0963fSdilpreet (void *)pcix_regs); 183400d0963fSdilpreet PCI_FM_SEV_INC(ret); 183500d0963fSdilpreet } 183600d0963fSdilpreet 183700d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 183800d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 183900d0963fSdilpreet } 184000d0963fSdilpreet 184100d0963fSdilpreet static int 184200d0963fSdilpreet pcie_rc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 184300d0963fSdilpreet void *pe_regs) 184400d0963fSdilpreet { 184500d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = (pcie_adv_error_regs_t *)pe_regs; 184600d0963fSdilpreet int fatal = 0; 184700d0963fSdilpreet int nonfatal = 0; 184800d0963fSdilpreet int unknown = 0; 184900d0963fSdilpreet char buf[FM_MAX_CLASS]; 185000d0963fSdilpreet 185100d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) { 185200d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 185300d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 185400d0963fSdilpreet int ce, ue, mult_ce, mult_ue, first_ue_fatal, nfe, fe; 185500d0963fSdilpreet 185600d0963fSdilpreet ce = pcie_rc_regs->pcie_rc_err_status & 185700d0963fSdilpreet PCIE_AER_RE_STS_CE_RCVD; 185800d0963fSdilpreet ue = pcie_rc_regs->pcie_rc_err_status & 185900d0963fSdilpreet PCIE_AER_RE_STS_FE_NFE_RCVD; 186000d0963fSdilpreet mult_ce = pcie_rc_regs->pcie_rc_err_status & 186100d0963fSdilpreet PCIE_AER_RE_STS_MUL_CE_RCVD; 186200d0963fSdilpreet mult_ue = pcie_rc_regs->pcie_rc_err_status & 186300d0963fSdilpreet PCIE_AER_RE_STS_MUL_FE_NFE_RCVD; 186400d0963fSdilpreet first_ue_fatal = pcie_rc_regs->pcie_rc_err_status & 186500d0963fSdilpreet PCIE_AER_RE_STS_FIRST_UC_FATAL; 186600d0963fSdilpreet nfe = pcie_rc_regs->pcie_rc_err_status & 186700d0963fSdilpreet PCIE_AER_RE_STS_NFE_MSGS_RCVD; 186800d0963fSdilpreet fe = pcie_rc_regs->pcie_rc_err_status & 186900d0963fSdilpreet PCIE_AER_RE_STS_FE_MSGS_RCVD; 187000d0963fSdilpreet /* 187100d0963fSdilpreet * log fatal/nonfatal/corrected messages 187200d0963fSdilpreet * recieved by root complex 187300d0963fSdilpreet */ 187400d0963fSdilpreet if (ue && fe) 187500d0963fSdilpreet fatal++; 187600d0963fSdilpreet 187700d0963fSdilpreet if (fe && first_ue_fatal) { 187800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 187900d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_FE_MSG); 188000d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 188100d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 188200d0963fSdilpreet } 188300d0963fSdilpreet if (nfe && !first_ue_fatal) { 188400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 188500d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_NFE_MSG); 188600d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 188700d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 188800d0963fSdilpreet } 188900d0963fSdilpreet if (ce) { 189000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 189100d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_CE_MSG); 189200d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 189300d0963fSdilpreet PCIEX_TYPE_RC_CE_MSG); 189400d0963fSdilpreet } 189500d0963fSdilpreet if (mult_ce) { 189600d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 189700d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MCE_MSG); 189800d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 189900d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 190000d0963fSdilpreet } 190100d0963fSdilpreet if (mult_ue) { 190200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 190300d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MUE_MSG); 190400d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 190500d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 190600d0963fSdilpreet } 190700d0963fSdilpreet } 190800d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 190900d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 191000d0963fSdilpreet } 191100d0963fSdilpreet 191200d0963fSdilpreet static int 191300d0963fSdilpreet pcie_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 191400d0963fSdilpreet { 191500d0963fSdilpreet int fatal = 0; 191600d0963fSdilpreet int nonfatal = 0; 191700d0963fSdilpreet int unknown = 0; 191800d0963fSdilpreet int ok = 0; 191900d0963fSdilpreet char buf[FM_MAX_CLASS]; 192000d0963fSdilpreet int i; 192100d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 192200d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 192300d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs; 192400d0963fSdilpreet 192500d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 192600d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 192700d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, erpt_p, 192800d0963fSdilpreet (void *)pcie_regs->pcix_bdg_regs); 192900d0963fSdilpreet PCI_FM_SEV_INC(ret); 193000d0963fSdilpreet } 193100d0963fSdilpreet 193200d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 193300d0963fSdilpreet if (!(pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID)) 193400d0963fSdilpreet goto done; 193500d0963fSdilpreet for (i = 0; pciex_nadv_err_tbl[i].err_class != NULL; i++) { 193600d0963fSdilpreet if (!(pcie_regs->pcie_err_status & 193700d0963fSdilpreet pciex_nadv_err_tbl[i].reg_bit)) 193800d0963fSdilpreet continue; 193900d0963fSdilpreet 194000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 194100d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 194200d0963fSdilpreet pciex_nadv_err_tbl[i].err_class); 194300d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 194400d0963fSdilpreet PCIEX_TYPE_GEN); 194500d0963fSdilpreet PCI_FM_SEV_INC(pciex_nadv_err_tbl[i].flags); 194600d0963fSdilpreet } 194700d0963fSdilpreet goto done; 194800d0963fSdilpreet } 194900d0963fSdilpreet 195000d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 195100d0963fSdilpreet 195200d0963fSdilpreet /* 195300d0963fSdilpreet * Log PCI Express uncorrectable errors 195400d0963fSdilpreet */ 195500d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) { 195600d0963fSdilpreet for (i = 0; pciex_ue_err_tbl[i].err_class != NULL; i++) { 195700d0963fSdilpreet if (!(pcie_adv_regs->pcie_ue_status & 195800d0963fSdilpreet pciex_ue_err_tbl[i].reg_bit)) 195900d0963fSdilpreet continue; 196000d0963fSdilpreet 196100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 196200d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 196300d0963fSdilpreet pciex_ue_err_tbl[i].err_class); 196400d0963fSdilpreet 196500d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 196600d0963fSdilpreet if ((pcie_adv_regs->pcie_ue_status & 1967*0c64a9b4Sanish pcie_aer_uce_log_bits) != 196800d0963fSdilpreet pciex_ue_err_tbl[i].reg_bit) { 196900d0963fSdilpreet PCI_FM_SEV_INC(pciex_ue_err_tbl[i].flags); 197000d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 197100d0963fSdilpreet PCIEX_TYPE_UE); 197200d0963fSdilpreet } else { 197300d0963fSdilpreet pcie_check_addr(dip, derr, erpt_p); 197400d0963fSdilpreet /* 1975ac4d633fSstephh * fatal/ok errors are fatal/ok 197600d0963fSdilpreet * regardless of if we find a handle 197700d0963fSdilpreet */ 197800d0963fSdilpreet if (pciex_ue_err_tbl[i].flags == DDI_FM_FATAL) 197900d0963fSdilpreet derr->fme_status = DDI_FM_FATAL; 1980ac4d633fSstephh else if (pciex_ue_err_tbl[i].flags == DDI_FM_OK) 1981ac4d633fSstephh derr->fme_status = DDI_FM_OK; 198200d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 198300d0963fSdilpreet PCIEX_TYPE_UE); 198400d0963fSdilpreet PCI_FM_SEV_INC(derr->fme_status); 198500d0963fSdilpreet } 198600d0963fSdilpreet } 198700d0963fSdilpreet } 198800d0963fSdilpreet 198900d0963fSdilpreet /* 199000d0963fSdilpreet * Log PCI Express correctable errors 199100d0963fSdilpreet */ 199200d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) { 199300d0963fSdilpreet for (i = 0; pciex_ce_err_tbl[i].err_class != NULL; i++) { 199400d0963fSdilpreet if (!(pcie_adv_regs->pcie_ce_status & 199500d0963fSdilpreet pciex_ce_err_tbl[i].reg_bit)) 199600d0963fSdilpreet continue; 199700d0963fSdilpreet 199800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 199900d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 200000d0963fSdilpreet pciex_ce_err_tbl[i].err_class); 200100d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 200200d0963fSdilpreet PCIEX_TYPE_CE); 200300d0963fSdilpreet } 200400d0963fSdilpreet } 200500d0963fSdilpreet 200600d0963fSdilpreet if (!(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) 200700d0963fSdilpreet goto done; 200800d0963fSdilpreet 200900d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 201000d0963fSdilpreet int ret = pcie_rc_error_report(dip, derr, erpt_p, 201100d0963fSdilpreet (void *)pcie_adv_regs); 201200d0963fSdilpreet PCI_FM_SEV_INC(ret); 201300d0963fSdilpreet } 201400d0963fSdilpreet 201500d0963fSdilpreet if (!((erpt_p->pe_dflags & PCIEX_2PCI_DEV) && 201600d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID))) 201700d0963fSdilpreet goto done; 201800d0963fSdilpreet 201900d0963fSdilpreet pcie_bdg_regs = pcie_adv_regs->pcie_adv_bdg_regs; 202000d0963fSdilpreet 202100d0963fSdilpreet for (i = 0; pcie_sue_err_tbl[i].err_class != NULL; i++) { 202200d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 202300d0963fSdilpreet pcie_sue_err_tbl[i].reg_bit)) { 202400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 202500d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 202600d0963fSdilpreet pcie_sue_err_tbl[i].err_class); 202700d0963fSdilpreet 202800d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 2029*0c64a9b4Sanish pcie_aer_suce_log_bits) != 203000d0963fSdilpreet pcie_sue_err_tbl[i].reg_bit) { 203100d0963fSdilpreet PCI_FM_SEV_INC(pcie_sue_err_tbl[i].flags); 203200d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 203300d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 203400d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 203500d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 203600d0963fSdilpreet #ifdef DEBUG 203700d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 203800d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 203900d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 204000d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 204100d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 204200d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 204300d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 204400d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 204500d0963fSdilpreet #endif 204600d0963fSdilpreet NULL); 204700d0963fSdilpreet } else { 204800d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 204900d0963fSdilpreet pcie_pci_check_addr(dip, derr, erpt_p); 205000d0963fSdilpreet /* 205100d0963fSdilpreet * fatal/nonfatal errors are fatal/nonfatal 205200d0963fSdilpreet * regardless of if we find a handle 205300d0963fSdilpreet */ 205400d0963fSdilpreet if (pcie_sue_err_tbl[i].flags == DDI_FM_FATAL) 205500d0963fSdilpreet derr->fme_status = DDI_FM_FATAL; 205600d0963fSdilpreet else if (pcie_sue_err_tbl[i].flags == 205700d0963fSdilpreet DDI_FM_NONFATAL) 205800d0963fSdilpreet derr->fme_status = DDI_FM_NONFATAL; 205900d0963fSdilpreet 206000d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 206100d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 206200d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 206300d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 206400d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 206500d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 206600d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 206700d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 206800d0963fSdilpreet 1 : NULL, 206900d0963fSdilpreet #ifdef DEBUG 207000d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 207100d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 207200d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 207300d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 207400d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 207500d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 207600d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 207700d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 207800d0963fSdilpreet #endif 207900d0963fSdilpreet NULL); 208000d0963fSdilpreet PCI_FM_SEV_INC(derr->fme_status); 208100d0963fSdilpreet } 208200d0963fSdilpreet } 208300d0963fSdilpreet } 208400d0963fSdilpreet done: 208500d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 208600d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 208700d0963fSdilpreet } 208800d0963fSdilpreet 208900d0963fSdilpreet static void 209000d0963fSdilpreet pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 209100d0963fSdilpreet { 209200d0963fSdilpreet int fatal = 0; 209300d0963fSdilpreet int nonfatal = 0; 209400d0963fSdilpreet int unknown = 0; 209500d0963fSdilpreet int ok = 0; 209600d0963fSdilpreet char buf[FM_MAX_CLASS]; 209700d0963fSdilpreet int i; 209800d0963fSdilpreet 209900d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 210000d0963fSdilpreet /* 210100d0963fSdilpreet * Log generic PCI errors. 210200d0963fSdilpreet */ 210300d0963fSdilpreet for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 210400d0963fSdilpreet if (!(erpt_p->pe_pci_regs->pci_err_status & 210500d0963fSdilpreet pci_err_tbl[i].reg_bit) || 210600d0963fSdilpreet !(erpt_p->pe_pci_regs->pci_vflags & 210700d0963fSdilpreet PCI_ERR_STATUS_VALID)) 210800d0963fSdilpreet continue; 210900d0963fSdilpreet /* 211000d0963fSdilpreet * Generate an ereport for this error bit. 211100d0963fSdilpreet */ 211200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 211300d0963fSdilpreet PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class); 211400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 211500d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 211600d0963fSdilpreet PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 211700d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status, 211800d0963fSdilpreet PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 211900d0963fSdilpreet erpt_p->pe_pci_regs->pci_cfg_comm, NULL); 212000d0963fSdilpreet 2121ac4d633fSstephh /* 2122ac4d633fSstephh * The meaning of SERR is different for PCIEX (just 2123ac4d633fSstephh * implies a message has been sent) so we don't want to 2124ac4d633fSstephh * treat that one as fatal. 2125ac4d633fSstephh */ 2126ac4d633fSstephh if ((erpt_p->pe_dflags & PCIEX_DEV) && 2127ac4d633fSstephh pci_err_tbl[i].reg_bit == PCI_STAT_S_SYSERR) { 2128ac4d633fSstephh unknown++; 2129ac4d633fSstephh } else { 213000d0963fSdilpreet PCI_FM_SEV_INC(pci_err_tbl[i].flags); 213100d0963fSdilpreet } 2132ac4d633fSstephh } 213300d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) { 213400d0963fSdilpreet int ret = pcie_error_report(dip, derr, erpt_p); 213500d0963fSdilpreet PCI_FM_SEV_INC(ret); 213600d0963fSdilpreet } else if (erpt_p->pe_dflags & PCIX_DEV) { 213700d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 213800d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, 213900d0963fSdilpreet erpt_p, erpt_p->pe_regs); 214000d0963fSdilpreet PCI_FM_SEV_INC(ret); 214100d0963fSdilpreet } else { 214200d0963fSdilpreet int ret = pcix_error_report(dip, derr, erpt_p); 214300d0963fSdilpreet PCI_FM_SEV_INC(ret); 214400d0963fSdilpreet } 214500d0963fSdilpreet } 214600d0963fSdilpreet } 214700d0963fSdilpreet 214800d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) { 214900d0963fSdilpreet int ret = pci_bdg_error_report(dip, derr, erpt_p); 215000d0963fSdilpreet PCI_FM_SEV_INC(ret); 215100d0963fSdilpreet } 215200d0963fSdilpreet 215300d0963fSdilpreet derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 215400d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 215500d0963fSdilpreet } 215600d0963fSdilpreet 215700d0963fSdilpreet void 215800d0963fSdilpreet pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status) 215900d0963fSdilpreet { 216000d0963fSdilpreet struct i_ddi_fmhdl *fmhdl; 216100d0963fSdilpreet pci_erpt_t *erpt_p; 216200d0963fSdilpreet 216300d0963fSdilpreet fmhdl = DEVI(dip)->devi_fmhdl; 216400d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 216500d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 216600d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 216700d0963fSdilpreet return; 216800d0963fSdilpreet } 216900d0963fSdilpreet 217000d0963fSdilpreet ASSERT(fmhdl); 217100d0963fSdilpreet 217200d0963fSdilpreet if (derr->fme_ena == NULL) 217300d0963fSdilpreet derr->fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 217400d0963fSdilpreet 217500d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 2176ac4d633fSstephh if (erpt_p == NULL) 217700d0963fSdilpreet return; 217800d0963fSdilpreet 217900d0963fSdilpreet pci_regs_gather(dip, erpt_p); 218000d0963fSdilpreet pci_error_report(dip, derr, erpt_p); 218100d0963fSdilpreet pci_regs_clear(erpt_p); 218200d0963fSdilpreet 218300d0963fSdilpreet if (xx_status != NULL) 218400d0963fSdilpreet *xx_status = erpt_p->pe_pci_regs->pci_err_status; 218500d0963fSdilpreet } 218600d0963fSdilpreet 218700d0963fSdilpreet /* 218800d0963fSdilpreet * private version of walk_devs() that can be used during panic. No 218900d0963fSdilpreet * sleeping or locking required. 219000d0963fSdilpreet */ 219100d0963fSdilpreet static int 219200d0963fSdilpreet pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg) 219300d0963fSdilpreet { 219400d0963fSdilpreet while (dip) { 219500d0963fSdilpreet switch ((*f)(dip, arg)) { 219600d0963fSdilpreet case DDI_WALK_TERMINATE: 219700d0963fSdilpreet return (DDI_WALK_TERMINATE); 219800d0963fSdilpreet case DDI_WALK_CONTINUE: 219900d0963fSdilpreet if (pci_fm_walk_devs(ddi_get_child(dip), f, 220000d0963fSdilpreet arg) == DDI_WALK_TERMINATE) 220100d0963fSdilpreet return (DDI_WALK_TERMINATE); 220200d0963fSdilpreet break; 220300d0963fSdilpreet case DDI_WALK_PRUNECHILD: 220400d0963fSdilpreet break; 220500d0963fSdilpreet } 220600d0963fSdilpreet dip = ddi_get_next_sibling(dip); 220700d0963fSdilpreet } 220800d0963fSdilpreet return (DDI_WALK_CONTINUE); 220900d0963fSdilpreet } 221000d0963fSdilpreet 221100d0963fSdilpreet /* 221200d0963fSdilpreet * need special version of ddi_fm_ereport_post() as the leaf driver may 221300d0963fSdilpreet * not be hardened. 221400d0963fSdilpreet */ 221500d0963fSdilpreet static void 221600d0963fSdilpreet pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena, 221700d0963fSdilpreet uint8_t version, ...) 221800d0963fSdilpreet { 221900d0963fSdilpreet char *name; 222000d0963fSdilpreet char device_path[MAXPATHLEN]; 222100d0963fSdilpreet char ddi_error_class[FM_MAX_CLASS]; 222200d0963fSdilpreet nvlist_t *ereport, *detector; 222300d0963fSdilpreet nv_alloc_t *nva; 222400d0963fSdilpreet errorq_elem_t *eqep; 222500d0963fSdilpreet va_list ap; 222600d0963fSdilpreet 222700d0963fSdilpreet if (panicstr) { 222800d0963fSdilpreet eqep = errorq_reserve(ereport_errorq); 222900d0963fSdilpreet if (eqep == NULL) 223000d0963fSdilpreet return; 223100d0963fSdilpreet ereport = errorq_elem_nvl(ereport_errorq, eqep); 223200d0963fSdilpreet nva = errorq_elem_nva(ereport_errorq, eqep); 223300d0963fSdilpreet detector = fm_nvlist_create(nva); 223400d0963fSdilpreet } else { 223500d0963fSdilpreet ereport = fm_nvlist_create(NULL); 223600d0963fSdilpreet detector = fm_nvlist_create(NULL); 223700d0963fSdilpreet } 223800d0963fSdilpreet 223900d0963fSdilpreet (void) ddi_pathname(dip, device_path); 224000d0963fSdilpreet fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, 224100d0963fSdilpreet device_path, NULL); 224200d0963fSdilpreet (void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s", 224300d0963fSdilpreet DDI_IO_CLASS, error_class); 224400d0963fSdilpreet fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL); 224500d0963fSdilpreet 224600d0963fSdilpreet va_start(ap, version); 224700d0963fSdilpreet name = va_arg(ap, char *); 224800d0963fSdilpreet (void) i_fm_payload_set(ereport, name, ap); 224900d0963fSdilpreet va_end(ap); 225000d0963fSdilpreet 225100d0963fSdilpreet if (panicstr) { 225200d0963fSdilpreet errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); 225300d0963fSdilpreet } else { 225400d0963fSdilpreet (void) fm_ereport_post(ereport, EVCH_TRYHARD); 225500d0963fSdilpreet fm_nvlist_destroy(ereport, FM_NVA_FREE); 225600d0963fSdilpreet fm_nvlist_destroy(detector, FM_NVA_FREE); 225700d0963fSdilpreet } 225800d0963fSdilpreet } 225900d0963fSdilpreet 226000d0963fSdilpreet static int 226100d0963fSdilpreet pci_check_regs(dev_info_t *dip, void *arg) 226200d0963fSdilpreet { 226300d0963fSdilpreet int reglen; 226400d0963fSdilpreet int rn; 226500d0963fSdilpreet int totreg; 226600d0963fSdilpreet pci_regspec_t *drv_regp; 226700d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 226800d0963fSdilpreet 226900d0963fSdilpreet if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 227000d0963fSdilpreet /* 227100d0963fSdilpreet * for config space, we need to check if the given address 227200d0963fSdilpreet * is a valid config space address for this device - based 227300d0963fSdilpreet * on pci_phys_hi of the config space entry in reg property. 227400d0963fSdilpreet */ 227500d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 227600d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 227700d0963fSdilpreet return (DDI_WALK_CONTINUE); 227800d0963fSdilpreet 227900d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 228000d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 228100d0963fSdilpreet if (tgt_err->tgt_pci_space == 228200d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) && 228300d0963fSdilpreet (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M | 228400d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M)) == 228500d0963fSdilpreet (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M | 228600d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M))) { 228700d0963fSdilpreet tgt_err->tgt_dip = dip; 228800d0963fSdilpreet kmem_free(drv_regp, reglen); 228900d0963fSdilpreet return (DDI_WALK_TERMINATE); 229000d0963fSdilpreet } 229100d0963fSdilpreet } 229200d0963fSdilpreet kmem_free(drv_regp, reglen); 229300d0963fSdilpreet } else { 229400d0963fSdilpreet /* 229500d0963fSdilpreet * for non config space, need to check reg to look 229600d0963fSdilpreet * for any non-relocable mapping, otherwise check 229700d0963fSdilpreet * assigned-addresses. 229800d0963fSdilpreet */ 229900d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 230000d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 230100d0963fSdilpreet return (DDI_WALK_CONTINUE); 230200d0963fSdilpreet 230300d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 230400d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 230500d0963fSdilpreet if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) && 230600d0963fSdilpreet (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 230700d0963fSdilpreet tgt_err->tgt_pci_space == 230800d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 230900d0963fSdilpreet (tgt_err->tgt_pci_addr >= 231000d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 231100d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 231200d0963fSdilpreet (tgt_err->tgt_pci_addr < 231300d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 231400d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 231500d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 231600d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 231700d0963fSdilpreet tgt_err->tgt_dip = dip; 231800d0963fSdilpreet kmem_free(drv_regp, reglen); 231900d0963fSdilpreet return (DDI_WALK_TERMINATE); 232000d0963fSdilpreet } 232100d0963fSdilpreet } 232200d0963fSdilpreet kmem_free(drv_regp, reglen); 232300d0963fSdilpreet 232400d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 232500d0963fSdilpreet "assigned-addresses", (caddr_t)&drv_regp, ®len) != 232600d0963fSdilpreet DDI_SUCCESS) 232700d0963fSdilpreet return (DDI_WALK_CONTINUE); 232800d0963fSdilpreet 232900d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 233000d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 233100d0963fSdilpreet if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 233200d0963fSdilpreet tgt_err->tgt_pci_space == 233300d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 233400d0963fSdilpreet (tgt_err->tgt_pci_addr >= 233500d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 233600d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 233700d0963fSdilpreet (tgt_err->tgt_pci_addr < 233800d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 233900d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 234000d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 234100d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 234200d0963fSdilpreet tgt_err->tgt_dip = dip; 234300d0963fSdilpreet kmem_free(drv_regp, reglen); 234400d0963fSdilpreet return (DDI_WALK_TERMINATE); 234500d0963fSdilpreet } 234600d0963fSdilpreet } 234700d0963fSdilpreet kmem_free(drv_regp, reglen); 234800d0963fSdilpreet } 234900d0963fSdilpreet return (DDI_WALK_CONTINUE); 235000d0963fSdilpreet } 235100d0963fSdilpreet 235200d0963fSdilpreet /* 235300d0963fSdilpreet * impl_fix_ranges - fixes the config space entry of the "ranges" 235400d0963fSdilpreet * property on psycho+ platforms. (if changing this function please make sure 235500d0963fSdilpreet * to change the pci_fix_ranges function in pcipsy.c) 235600d0963fSdilpreet */ 235700d0963fSdilpreet /*ARGSUSED*/ 235800d0963fSdilpreet static void 235900d0963fSdilpreet pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange) 236000d0963fSdilpreet { 236100d0963fSdilpreet #if defined(__sparc) 236200d0963fSdilpreet char *name = ddi_binding_name(dip); 236300d0963fSdilpreet 236400d0963fSdilpreet if ((strcmp(name, "pci108e,8000") == 0) || 236500d0963fSdilpreet (strcmp(name, "pci108e,a000") == 0) || 236600d0963fSdilpreet (strcmp(name, "pci108e,a001") == 0)) { 236700d0963fSdilpreet int i; 236800d0963fSdilpreet for (i = 0; i < nrange; i++, pci_ranges++) 236900d0963fSdilpreet if ((pci_ranges->child_high & PCI_REG_ADDR_M) == 237000d0963fSdilpreet PCI_ADDR_CONFIG) 237100d0963fSdilpreet pci_ranges->parent_low |= 237200d0963fSdilpreet pci_ranges->child_high; 237300d0963fSdilpreet } 237400d0963fSdilpreet #endif 237500d0963fSdilpreet } 237600d0963fSdilpreet 237700d0963fSdilpreet static int 237800d0963fSdilpreet pci_check_ranges(dev_info_t *dip, void *arg) 237900d0963fSdilpreet { 238000d0963fSdilpreet uint64_t range_parent_begin; 238100d0963fSdilpreet uint64_t range_parent_size; 238200d0963fSdilpreet uint64_t range_parent_end; 238300d0963fSdilpreet uint32_t space_type; 238400d0963fSdilpreet uint32_t bus_num; 238500d0963fSdilpreet uint32_t range_offset; 238600d0963fSdilpreet pci_ranges_t *pci_ranges, *rangep; 238700d0963fSdilpreet pci_bus_range_t *pci_bus_rangep; 238800d0963fSdilpreet int pci_ranges_length; 238900d0963fSdilpreet int nrange; 239000d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 239100d0963fSdilpreet int i, size; 239200d0963fSdilpreet if (strcmp(ddi_node_name(dip), "pci") != 0 && 239300d0963fSdilpreet strcmp(ddi_node_name(dip), "pciex") != 0) 239400d0963fSdilpreet return (DDI_WALK_CONTINUE); 239500d0963fSdilpreet 239600d0963fSdilpreet /* 239700d0963fSdilpreet * Get the ranges property. Note we only look at the top level pci 239800d0963fSdilpreet * node (hostbridge) which has a ranges property of type pci_ranges_t 239900d0963fSdilpreet * not at pci-pci bridges. 240000d0963fSdilpreet */ 240100d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 240200d0963fSdilpreet (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) { 240300d0963fSdilpreet /* 240400d0963fSdilpreet * no ranges property - no translation needed 240500d0963fSdilpreet */ 240600d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr; 240700d0963fSdilpreet tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN; 240800d0963fSdilpreet if (panicstr) 240900d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 241000d0963fSdilpreet pci_check_regs, (void *)tgt_err); 241100d0963fSdilpreet else { 241200d0963fSdilpreet int circ = 0; 241300d0963fSdilpreet ndi_devi_enter(dip, &circ); 241400d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 241500d0963fSdilpreet (void *)tgt_err); 241600d0963fSdilpreet ndi_devi_exit(dip, circ); 241700d0963fSdilpreet } 241800d0963fSdilpreet if (tgt_err->tgt_dip != NULL) 241900d0963fSdilpreet return (DDI_WALK_TERMINATE); 242000d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 242100d0963fSdilpreet } 242200d0963fSdilpreet nrange = pci_ranges_length / sizeof (pci_ranges_t); 242300d0963fSdilpreet rangep = pci_ranges; 242400d0963fSdilpreet 242500d0963fSdilpreet /* Need to fix the pci ranges property for psycho based systems */ 242600d0963fSdilpreet pci_fix_ranges(dip, pci_ranges, nrange); 242700d0963fSdilpreet 242800d0963fSdilpreet for (i = 0; i < nrange; i++, rangep++) { 242900d0963fSdilpreet range_parent_begin = ((uint64_t)rangep->parent_high << 32) + 243000d0963fSdilpreet rangep->parent_low; 243100d0963fSdilpreet range_parent_size = ((uint64_t)rangep->size_high << 32) + 243200d0963fSdilpreet rangep->size_low; 243300d0963fSdilpreet range_parent_end = range_parent_begin + range_parent_size - 1; 243400d0963fSdilpreet 243500d0963fSdilpreet if ((tgt_err->tgt_err_addr < range_parent_begin) || 243600d0963fSdilpreet (tgt_err->tgt_err_addr > range_parent_end)) { 243700d0963fSdilpreet /* Not in range */ 243800d0963fSdilpreet continue; 243900d0963fSdilpreet } 244000d0963fSdilpreet space_type = PCI_REG_ADDR_G(rangep->child_high); 244100d0963fSdilpreet if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 244200d0963fSdilpreet /* Config space address - check bus range */ 244300d0963fSdilpreet range_offset = tgt_err->tgt_err_addr - 244400d0963fSdilpreet range_parent_begin; 244500d0963fSdilpreet bus_num = PCI_REG_BUS_G(range_offset); 244600d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 244700d0963fSdilpreet DDI_PROP_DONTPASS, "bus-range", 244800d0963fSdilpreet (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) { 244900d0963fSdilpreet continue; 245000d0963fSdilpreet } 245100d0963fSdilpreet if ((bus_num < pci_bus_rangep->lo) || 245200d0963fSdilpreet (bus_num > pci_bus_rangep->hi)) { 245300d0963fSdilpreet /* 245400d0963fSdilpreet * Bus number not appropriate for this 245500d0963fSdilpreet * pci nexus. 245600d0963fSdilpreet */ 245700d0963fSdilpreet kmem_free(pci_bus_rangep, size); 245800d0963fSdilpreet continue; 245900d0963fSdilpreet } 246000d0963fSdilpreet kmem_free(pci_bus_rangep, size); 246100d0963fSdilpreet } 246200d0963fSdilpreet 246300d0963fSdilpreet /* We have a match if we get here - compute pci address */ 246400d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr - 246500d0963fSdilpreet range_parent_begin; 246600d0963fSdilpreet tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) + 246700d0963fSdilpreet rangep->child_low); 246800d0963fSdilpreet tgt_err->tgt_pci_space = space_type; 246900d0963fSdilpreet if (panicstr) 247000d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 247100d0963fSdilpreet pci_check_regs, (void *)tgt_err); 247200d0963fSdilpreet else { 247300d0963fSdilpreet int circ = 0; 247400d0963fSdilpreet ndi_devi_enter(dip, &circ); 247500d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 247600d0963fSdilpreet (void *)tgt_err); 247700d0963fSdilpreet ndi_devi_exit(dip, circ); 247800d0963fSdilpreet } 247900d0963fSdilpreet if (tgt_err->tgt_dip != NULL) { 248000d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 248100d0963fSdilpreet return (DDI_WALK_TERMINATE); 248200d0963fSdilpreet } 248300d0963fSdilpreet } 248400d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 248500d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 248600d0963fSdilpreet } 248700d0963fSdilpreet 248800d0963fSdilpreet /* 248900d0963fSdilpreet * Function used to drain pci_target_queue, either during panic or after softint 249000d0963fSdilpreet * is generated, to generate target device ereports based on captured physical 249100d0963fSdilpreet * addresses 249200d0963fSdilpreet */ 249300d0963fSdilpreet /*ARGSUSED*/ 249400d0963fSdilpreet static void 249500d0963fSdilpreet pci_target_drain(void *private_p, pci_target_err_t *tgt_err) 249600d0963fSdilpreet { 249700d0963fSdilpreet char buf[FM_MAX_CLASS]; 249800d0963fSdilpreet 249900d0963fSdilpreet /* 250000d0963fSdilpreet * The following assumes that all pci_pci bridge devices 250100d0963fSdilpreet * are configured as transparant. Find the top-level pci 250200d0963fSdilpreet * nexus which has tgt_err_addr in one of its ranges, converting this 250300d0963fSdilpreet * to a pci address in the process. Then starting at this node do 250400d0963fSdilpreet * another tree walk to find a device with the pci address we've 250500d0963fSdilpreet * found within range of one of it's assigned-addresses properties. 250600d0963fSdilpreet */ 250700d0963fSdilpreet tgt_err->tgt_dip = NULL; 250800d0963fSdilpreet if (panicstr) 250900d0963fSdilpreet (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges, 251000d0963fSdilpreet (void *)tgt_err); 251100d0963fSdilpreet else 251200d0963fSdilpreet ddi_walk_devs(ddi_root_node(), pci_check_ranges, 251300d0963fSdilpreet (void *)tgt_err); 251400d0963fSdilpreet if (tgt_err->tgt_dip == NULL) 251500d0963fSdilpreet return; 251600d0963fSdilpreet 251700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type, 251800d0963fSdilpreet tgt_err->tgt_err_class); 251900d0963fSdilpreet pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0, 252000d0963fSdilpreet PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL); 252100d0963fSdilpreet } 252200d0963fSdilpreet 252300d0963fSdilpreet void 252400d0963fSdilpreet pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr) 252500d0963fSdilpreet { 252600d0963fSdilpreet pci_target_err_t tgt_err; 252700d0963fSdilpreet 252800d0963fSdilpreet tgt_err.tgt_err_ena = ena; 252900d0963fSdilpreet tgt_err.tgt_err_class = class; 253000d0963fSdilpreet tgt_err.tgt_bridge_type = bridge_type; 253100d0963fSdilpreet tgt_err.tgt_err_addr = addr; 253200d0963fSdilpreet errorq_dispatch(pci_target_queue, (void *)&tgt_err, 253300d0963fSdilpreet sizeof (pci_target_err_t), ERRORQ_ASYNC); 253400d0963fSdilpreet } 253500d0963fSdilpreet 253600d0963fSdilpreet void 253700d0963fSdilpreet pci_targetq_init(void) 253800d0963fSdilpreet { 253900d0963fSdilpreet /* 254000d0963fSdilpreet * PCI target errorq, to schedule async handling of generation of 254100d0963fSdilpreet * target device ereports based on captured physical address. 254200d0963fSdilpreet * The errorq is created here but destroyed when _fini is called 254300d0963fSdilpreet * for the pci module. 254400d0963fSdilpreet */ 254500d0963fSdilpreet if (pci_target_queue == NULL) { 254600d0963fSdilpreet pci_target_queue = errorq_create("pci_target_queue", 254700d0963fSdilpreet (errorq_func_t)pci_target_drain, (void *)NULL, 254800d0963fSdilpreet TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL, 254900d0963fSdilpreet ERRORQ_VITAL); 255000d0963fSdilpreet if (pci_target_queue == NULL) 255100d0963fSdilpreet panic("failed to create required system error queue"); 255200d0963fSdilpreet } 255300d0963fSdilpreet } 2554