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 /* 232901c7f3Sstephh * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2400d0963fSdilpreet * Use is subject to license terms. 2500d0963fSdilpreet */ 2600d0963fSdilpreet 2700d0963fSdilpreet #pragma ident "%Z%%M% %I% %E% SMI" 2800d0963fSdilpreet 2900d0963fSdilpreet #include <sys/types.h> 3000d0963fSdilpreet #include <sys/sunndi.h> 3100d0963fSdilpreet #include <sys/sysmacros.h> 3200d0963fSdilpreet #include <sys/ddifm_impl.h> 3300d0963fSdilpreet #include <sys/fm/util.h> 3400d0963fSdilpreet #include <sys/fm/protocol.h> 3500d0963fSdilpreet #include <sys/fm/io/pci.h> 3600d0963fSdilpreet #include <sys/fm/io/ddi.h> 3700d0963fSdilpreet #include <sys/pci.h> 3800d0963fSdilpreet #include <sys/pcie.h> 3900d0963fSdilpreet #include <sys/pci_impl.h> 4000d0963fSdilpreet #include <sys/epm.h> 4100d0963fSdilpreet #include <sys/pcifm.h> 4200d0963fSdilpreet 4300d0963fSdilpreet #define PCIX_ECC_VER_CHECK(x) (((x) == PCI_PCIX_VER_1) ||\ 4400d0963fSdilpreet ((x) == PCI_PCIX_VER_2)) 4500d0963fSdilpreet 4600d0963fSdilpreet /* 4700d0963fSdilpreet * Expected PCI Express error mask values 48*eae2e508Skrishnae * 49*eae2e508Skrishnae * !!NOTE!! All PCI Express functionality including PCIe initialization, PCIe 50*eae2e508Skrishnae * error handling has been moved to the common pcie misc module. All functions 51*eae2e508Skrishnae * and variables dealting with PCIe in this file have been deprecated and will 52*eae2e508Skrishnae * be eventually removed. All Legacy PCI and PCI-X related code should remain 53*eae2e508Skrishnae * as is. 5400d0963fSdilpreet */ 550c64a9b4Sanish uint32_t pcie_aer_uce_log_bits = PCIE_AER_UCE_LOG_BITS; 560c64a9b4Sanish uint32_t pcie_aer_suce_log_bits = PCIE_AER_SUCE_LOG_BITS; 5700d0963fSdilpreet 5800d0963fSdilpreet errorq_t *pci_target_queue = NULL; 5900d0963fSdilpreet 6000d0963fSdilpreet pci_fm_err_t pci_err_tbl[] = { 6100d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 6200d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 6300d0963fSdilpreet PCI_SIG_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_FATAL, 6400d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 6500d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 6600d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 6700d0963fSdilpreet NULL, NULL, NULL, NULL, 6800d0963fSdilpreet }; 6900d0963fSdilpreet 7000d0963fSdilpreet pci_fm_err_t pci_bdg_err_tbl[] = { 7100d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 7200d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 7300d0963fSdilpreet PCI_REC_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_UNKNOWN, 748aec9182Sstephh #if defined(__sparc) 7500d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 760c64a9b4Sanish #endif 7700d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 7800d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 7900d0963fSdilpreet NULL, NULL, NULL, NULL, 8000d0963fSdilpreet }; 8100d0963fSdilpreet 8200d0963fSdilpreet static pci_fm_err_t pciex_ce_err_tbl[] = { 83ac4d633fSstephh PCIEX_RE, PCIE_AER_CE_RECEIVER_ERR, NULL, DDI_FM_OK, 84ac4d633fSstephh PCIEX_RNR, PCIE_AER_CE_REPLAY_ROLLOVER, NULL, DDI_FM_OK, 85ac4d633fSstephh PCIEX_RTO, PCIE_AER_CE_REPLAY_TO, NULL, DDI_FM_OK, 86ac4d633fSstephh PCIEX_BDP, PCIE_AER_CE_BAD_DLLP, NULL, DDI_FM_OK, 87ac4d633fSstephh PCIEX_BTP, PCIE_AER_CE_BAD_TLP, NULL, DDI_FM_OK, 88ac4d633fSstephh PCIEX_ANFE, PCIE_AER_CE_AD_NFE, NULL, DDI_FM_OK, 8900d0963fSdilpreet NULL, NULL, NULL, NULL, 9000d0963fSdilpreet }; 9100d0963fSdilpreet 9200d0963fSdilpreet static pci_fm_err_t pciex_ue_err_tbl[] = { 9300d0963fSdilpreet PCIEX_TE, PCIE_AER_UCE_TRAINING, NULL, DDI_FM_FATAL, 9400d0963fSdilpreet PCIEX_DLP, PCIE_AER_UCE_DLP, NULL, DDI_FM_FATAL, 9500d0963fSdilpreet PCIEX_SD, PCIE_AER_UCE_SD, NULL, DDI_FM_FATAL, 9600d0963fSdilpreet PCIEX_ROF, PCIE_AER_UCE_RO, NULL, DDI_FM_FATAL, 9700d0963fSdilpreet PCIEX_FCP, PCIE_AER_UCE_FCP, NULL, DDI_FM_FATAL, 9800d0963fSdilpreet PCIEX_MFP, PCIE_AER_UCE_MTLP, NULL, DDI_FM_FATAL, 99ac4d633fSstephh PCIEX_CTO, PCIE_AER_UCE_TO, NULL, DDI_FM_UNKNOWN, 100ac4d633fSstephh PCIEX_UC, PCIE_AER_UCE_UC, NULL, DDI_FM_OK, 10100d0963fSdilpreet PCIEX_ECRC, PCIE_AER_UCE_ECRC, NULL, DDI_FM_UNKNOWN, 10200d0963fSdilpreet PCIEX_CA, PCIE_AER_UCE_CA, NULL, DDI_FM_UNKNOWN, 103ac4d633fSstephh PCIEX_UR, PCIE_AER_UCE_UR, NULL, DDI_FM_UNKNOWN, 10400d0963fSdilpreet PCIEX_POIS, PCIE_AER_UCE_PTLP, NULL, DDI_FM_UNKNOWN, 10500d0963fSdilpreet NULL, NULL, NULL, NULL, 10600d0963fSdilpreet }; 10700d0963fSdilpreet 10800d0963fSdilpreet static pci_fm_err_t pcie_sue_err_tbl[] = { 10900d0963fSdilpreet PCIEX_S_TA_SC, PCIE_AER_SUCE_TA_ON_SC, NULL, DDI_FM_UNKNOWN, 11000d0963fSdilpreet PCIEX_S_MA_SC, PCIE_AER_SUCE_MA_ON_SC, NULL, DDI_FM_UNKNOWN, 11100d0963fSdilpreet PCIEX_S_RTA, PCIE_AER_SUCE_RCVD_TA, NULL, DDI_FM_UNKNOWN, 1128aec9182Sstephh #if defined(__sparc) 11300d0963fSdilpreet PCIEX_S_RMA, PCIE_AER_SUCE_RCVD_MA, NULL, DDI_FM_UNKNOWN, 1140c64a9b4Sanish #endif 11500d0963fSdilpreet PCIEX_S_USC, PCIE_AER_SUCE_USC_ERR, NULL, DDI_FM_UNKNOWN, 11600d0963fSdilpreet PCIEX_S_USCMD, PCIE_AER_SUCE_USC_MSG_DATA_ERR, NULL, DDI_FM_FATAL, 11700d0963fSdilpreet PCIEX_S_UDE, PCIE_AER_SUCE_UC_DATA_ERR, NULL, DDI_FM_UNKNOWN, 11800d0963fSdilpreet PCIEX_S_UAT, PCIE_AER_SUCE_UC_ATTR_ERR, NULL, DDI_FM_FATAL, 11900d0963fSdilpreet PCIEX_S_UADR, PCIE_AER_SUCE_UC_ADDR_ERR, NULL, DDI_FM_FATAL, 12000d0963fSdilpreet PCIEX_S_TEX, PCIE_AER_SUCE_TIMER_EXPIRED, NULL, DDI_FM_FATAL, 12100d0963fSdilpreet PCIEX_S_PERR, PCIE_AER_SUCE_PERR_ASSERT, NULL, DDI_FM_UNKNOWN, 12200d0963fSdilpreet PCIEX_S_SERR, PCIE_AER_SUCE_SERR_ASSERT, NULL, DDI_FM_FATAL, 12300d0963fSdilpreet PCIEX_INTERR, PCIE_AER_SUCE_INTERNAL_ERR, NULL, DDI_FM_FATAL, 12400d0963fSdilpreet NULL, NULL, NULL, NULL, 12500d0963fSdilpreet }; 12600d0963fSdilpreet 12700d0963fSdilpreet static pci_fm_err_t pcix_err_tbl[] = { 12800d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 12900d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 13000d0963fSdilpreet PCIX_RX_SPL_MSG, PCI_PCIX_RX_SPL_MSG, NULL, DDI_FM_UNKNOWN, 13100d0963fSdilpreet NULL, NULL, NULL, NULL, 13200d0963fSdilpreet }; 13300d0963fSdilpreet 13400d0963fSdilpreet static pci_fm_err_t pcix_sec_err_tbl[] = { 13500d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_BSS_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 13600d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_BSS_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 137ac4d633fSstephh PCIX_BSS_SPL_OR, PCI_PCIX_BSS_SPL_OR, NULL, DDI_FM_OK, 138ac4d633fSstephh PCIX_BSS_SPL_DLY, PCI_PCIX_BSS_SPL_DLY, NULL, DDI_FM_OK, 13900d0963fSdilpreet NULL, NULL, NULL, NULL, 14000d0963fSdilpreet }; 14100d0963fSdilpreet 14200d0963fSdilpreet static pci_fm_err_t pciex_nadv_err_tbl[] = { 14300d0963fSdilpreet PCIEX_UR, PCIE_DEVSTS_UR_DETECTED, NULL, DDI_FM_UNKNOWN, 14400d0963fSdilpreet PCIEX_FAT, PCIE_DEVSTS_FE_DETECTED, NULL, DDI_FM_FATAL, 14500d0963fSdilpreet PCIEX_NONFAT, PCIE_DEVSTS_NFE_DETECTED, NULL, DDI_FM_UNKNOWN, 146ac4d633fSstephh PCIEX_CORR, PCIE_DEVSTS_CE_DETECTED, NULL, DDI_FM_OK, 14700d0963fSdilpreet NULL, NULL, NULL, NULL, 14800d0963fSdilpreet }; 14900d0963fSdilpreet 15000d0963fSdilpreet static int 1518aec9182Sstephh pci_config_check(ddi_acc_handle_t handle, int fme_flag) 15200d0963fSdilpreet { 15300d0963fSdilpreet ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle); 15400d0963fSdilpreet ddi_fm_error_t de; 15500d0963fSdilpreet 15600d0963fSdilpreet if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip)))) 15700d0963fSdilpreet return (DDI_FM_OK); 15800d0963fSdilpreet 15900d0963fSdilpreet de.fme_version = DDI_FME_VERSION; 16000d0963fSdilpreet 16100d0963fSdilpreet ddi_fm_acc_err_get(handle, &de, de.fme_version); 16200d0963fSdilpreet if (de.fme_status != DDI_FM_OK) { 1638aec9182Sstephh if (fme_flag == DDI_FM_ERR_UNEXPECTED) { 16400d0963fSdilpreet char buf[FM_MAX_CLASS]; 16500d0963fSdilpreet 1668aec9182Sstephh (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 1678aec9182Sstephh PCI_ERROR_SUBCLASS, PCI_NR); 1688aec9182Sstephh ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena, 1698aec9182Sstephh DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 1708aec9182Sstephh } 17100d0963fSdilpreet ddi_fm_acc_err_clear(handle, de.fme_version); 17200d0963fSdilpreet } 17300d0963fSdilpreet return (de.fme_status); 17400d0963fSdilpreet } 17500d0963fSdilpreet 17600d0963fSdilpreet static void 17700d0963fSdilpreet pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs, 1788aec9182Sstephh uint8_t pcix_cap_ptr, int fme_flag) 17900d0963fSdilpreet { 18000d0963fSdilpreet int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV; 18100d0963fSdilpreet 18200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl, 18300d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS : 18400d0963fSdilpreet PCI_PCIX_ECC_STATUS))); 1858aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 18600d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID; 18700d0963fSdilpreet else 18800d0963fSdilpreet return; 18900d0963fSdilpreet pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl, 19000d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD : 19100d0963fSdilpreet PCI_PCIX_ECC_FST_AD))); 19200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl, 19300d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD : 19400d0963fSdilpreet PCI_PCIX_ECC_SEC_AD))); 19500d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr = pci_config_get32(( 19600d0963fSdilpreet ddi_acc_handle_t)erpt_p->pe_hdl, 19700d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR))); 19800d0963fSdilpreet } 19900d0963fSdilpreet 20000d0963fSdilpreet static void 2018aec9182Sstephh pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs, int fme_flag) 20200d0963fSdilpreet { 20300d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 20400d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 20500d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 20600d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 20700d0963fSdilpreet int i; 20800d0963fSdilpreet 20900d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 21000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16( 21100d0963fSdilpreet erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS)); 2128aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 21300d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= 21400d0963fSdilpreet PCIX_BDG_SEC_STATUS_VALID; 21500d0963fSdilpreet else 21600d0963fSdilpreet return; 21700d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl, 21800d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS)); 2198aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 22000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID; 22100d0963fSdilpreet else 22200d0963fSdilpreet return; 22300d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 22400d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 22500d0963fSdilpreet /* 22600d0963fSdilpreet * PCI Express to PCI-X bridges only implement the 22700d0963fSdilpreet * secondary side of the PCI-X ECC registers, bit one is 22800d0963fSdilpreet * read-only so we make sure we do not write to it. 22900d0963fSdilpreet */ 23000d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 23100d0963fSdilpreet pcix_bdg_ecc_regs = 23200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[1]; 23300d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_bdg_ecc_regs, 2348aec9182Sstephh pcix_bdg_cap_ptr, fme_flag); 23500d0963fSdilpreet } else { 23600d0963fSdilpreet for (i = 0; i < 2; i++) { 23700d0963fSdilpreet pcix_bdg_ecc_regs = 23800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 23900d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 24000d0963fSdilpreet (pcix_bdg_cap_ptr + 24100d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), i); 24200d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, 24300d0963fSdilpreet pcix_bdg_ecc_regs, 2448aec9182Sstephh pcix_bdg_cap_ptr, fme_flag); 24500d0963fSdilpreet } 24600d0963fSdilpreet } 24700d0963fSdilpreet } 24800d0963fSdilpreet } else { 24900d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 25000d0963fSdilpreet uint8_t pcix_cap_ptr; 25100d0963fSdilpreet 25200d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 25300d0963fSdilpreet 25400d0963fSdilpreet pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl, 25500d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_COMMAND)); 25600d0963fSdilpreet pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl, 25700d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS)); 2588aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 25900d0963fSdilpreet pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID; 26000d0963fSdilpreet else 26100d0963fSdilpreet return; 26200d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 26300d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 26400d0963fSdilpreet pcix_regs->pcix_ecc_regs; 26500d0963fSdilpreet 26600d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs, 2678aec9182Sstephh pcix_cap_ptr, fme_flag); 26800d0963fSdilpreet } 26900d0963fSdilpreet } 27000d0963fSdilpreet } 27100d0963fSdilpreet 27200d0963fSdilpreet static void 2738aec9182Sstephh pcie_regs_gather(pci_erpt_t *erpt_p, int fme_flag) 27400d0963fSdilpreet { 27500d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 27600d0963fSdilpreet uint8_t pcie_cap_ptr; 27700d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 27800d0963fSdilpreet uint16_t pcie_ecap_ptr; 27900d0963fSdilpreet 28000d0963fSdilpreet pcie_cap_ptr = pcie_regs->pcie_cap_ptr; 28100d0963fSdilpreet 28200d0963fSdilpreet pcie_regs->pcie_err_status = pci_config_get16(erpt_p->pe_hdl, 28300d0963fSdilpreet pcie_cap_ptr + PCIE_DEVSTS); 2848aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 28500d0963fSdilpreet pcie_regs->pcie_vflags |= PCIE_ERR_STATUS_VALID; 28600d0963fSdilpreet else 28700d0963fSdilpreet return; 28800d0963fSdilpreet 28900d0963fSdilpreet pcie_regs->pcie_err_ctl = pci_config_get16(erpt_p->pe_hdl, 29000d0963fSdilpreet (pcie_cap_ptr + PCIE_DEVCTL)); 2918aec9182Sstephh pcie_regs->pcie_dev_cap = pci_config_get16(erpt_p->pe_hdl, 2928aec9182Sstephh (pcie_cap_ptr + PCIE_DEVCAP)); 29300d0963fSdilpreet 29400d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && (erpt_p->pe_dflags & 29500d0963fSdilpreet PCIX_DEV)) 2968aec9182Sstephh pcix_regs_gather(erpt_p, pcie_regs->pcix_bdg_regs, fme_flag); 29700d0963fSdilpreet 29800d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 29900d0963fSdilpreet pcie_rc_error_regs_t *pcie_rc_regs = pcie_regs->pcie_rc_regs; 30000d0963fSdilpreet 30100d0963fSdilpreet pcie_rc_regs->pcie_rc_status = pci_config_get32(erpt_p->pe_hdl, 30200d0963fSdilpreet (pcie_cap_ptr + PCIE_ROOTSTS)); 30300d0963fSdilpreet pcie_rc_regs->pcie_rc_ctl = pci_config_get16(erpt_p->pe_hdl, 30400d0963fSdilpreet (pcie_cap_ptr + PCIE_ROOTCTL)); 30500d0963fSdilpreet } 30600d0963fSdilpreet 30700d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) 30800d0963fSdilpreet return; 30900d0963fSdilpreet 31000d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 31100d0963fSdilpreet 31200d0963fSdilpreet pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr; 31300d0963fSdilpreet 31400d0963fSdilpreet pcie_adv_regs->pcie_ue_status = pci_config_get32(erpt_p->pe_hdl, 31500d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_STS); 3168aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 31700d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_STATUS_VALID; 31800d0963fSdilpreet 31900d0963fSdilpreet pcie_adv_regs->pcie_ue_mask = pci_config_get32(erpt_p->pe_hdl, 32000d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_MASK); 32100d0963fSdilpreet pcie_adv_regs->pcie_ue_sev = pci_config_get32(erpt_p->pe_hdl, 32200d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_SERV); 32300d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl = pci_config_get32(erpt_p->pe_hdl, 32400d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CTL); 32500d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0 = pci_config_get32(erpt_p->pe_hdl, 32600d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_HDR_LOG); 3278aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) { 32800d0963fSdilpreet int i; 32900d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_HDR_VALID; 33000d0963fSdilpreet 33100d0963fSdilpreet for (i = 0; i < 3; i++) { 33200d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[i] = pci_config_get32( 33300d0963fSdilpreet erpt_p->pe_hdl, pcie_ecap_ptr + PCIE_AER_HDR_LOG + 33400d0963fSdilpreet (4 * (i + 1))); 33500d0963fSdilpreet } 33600d0963fSdilpreet } 33700d0963fSdilpreet 33800d0963fSdilpreet pcie_adv_regs->pcie_ce_status = pci_config_get32(erpt_p->pe_hdl, 33900d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_STS); 3408aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 34100d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_CE_STATUS_VALID; 34200d0963fSdilpreet 34300d0963fSdilpreet pcie_adv_regs->pcie_ce_mask = pci_config_get32(erpt_p->pe_hdl, 34400d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_MASK); 34500d0963fSdilpreet 34600d0963fSdilpreet /* 34700d0963fSdilpreet * If pci express to pci bridge then grab the bridge 34800d0963fSdilpreet * error registers. 34900d0963fSdilpreet */ 35000d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 35100d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 35200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 35300d0963fSdilpreet 35400d0963fSdilpreet pcie_bdg_regs->pcie_sue_status = 35500d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 35600d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_STS); 3578aec9182Sstephh pcie_bdg_regs->pcie_sue_mask = 3588aec9182Sstephh pci_config_get32(erpt_p->pe_hdl, 3598aec9182Sstephh pcie_ecap_ptr + PCIE_AER_SUCE_MASK); 3608aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 36100d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_STATUS_VALID; 36200d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0 = pci_config_get32(erpt_p->pe_hdl, 36300d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_SHDR_LOG)); 36400d0963fSdilpreet 3658aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) { 36600d0963fSdilpreet int i; 36700d0963fSdilpreet 36800d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_HDR_VALID; 36900d0963fSdilpreet 37000d0963fSdilpreet for (i = 0; i < 3; i++) { 37100d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[i] = 37200d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 37300d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SHDR_LOG + 37400d0963fSdilpreet (4 * (i + 1))); 37500d0963fSdilpreet } 37600d0963fSdilpreet } 37700d0963fSdilpreet } 37800d0963fSdilpreet /* 37900d0963fSdilpreet * If PCI Express root complex then grab the root complex 38000d0963fSdilpreet * error registers. 38100d0963fSdilpreet */ 38200d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 38300d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 38400d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 38500d0963fSdilpreet 38600d0963fSdilpreet pcie_rc_regs->pcie_rc_err_cmd = pci_config_get32(erpt_p->pe_hdl, 38700d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_CMD)); 38800d0963fSdilpreet pcie_rc_regs->pcie_rc_err_status = 38900d0963fSdilpreet pci_config_get32(erpt_p->pe_hdl, 39000d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_STS)); 3918aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 39200d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= 39300d0963fSdilpreet PCIE_RC_ERR_STATUS_VALID; 39400d0963fSdilpreet pcie_rc_regs->pcie_rc_ce_src_id = 39500d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 39600d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_CE_SRC_ID)); 39700d0963fSdilpreet pcie_rc_regs->pcie_rc_ue_src_id = 39800d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 39900d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_ERR_SRC_ID)); 4008aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 40100d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags |= PCIE_SRC_ID_VALID; 40200d0963fSdilpreet } 40300d0963fSdilpreet } 40400d0963fSdilpreet 40500d0963fSdilpreet /*ARGSUSED*/ 40600d0963fSdilpreet static void 4078aec9182Sstephh pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p, int fme_flag) 40800d0963fSdilpreet { 40900d0963fSdilpreet pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs; 41000d0963fSdilpreet 41100d0963fSdilpreet /* 41200d0963fSdilpreet * Start by reading all the error registers that are available for 41300d0963fSdilpreet * pci and pci express and for leaf devices and bridges/switches 41400d0963fSdilpreet */ 41500d0963fSdilpreet pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl, 41600d0963fSdilpreet PCI_CONF_STAT); 4178aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK) 41800d0963fSdilpreet return; 41900d0963fSdilpreet pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID; 42000d0963fSdilpreet pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl, 42100d0963fSdilpreet PCI_CONF_COMM); 4228aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK) 42300d0963fSdilpreet return; 42400d0963fSdilpreet 42500d0963fSdilpreet /* 42600d0963fSdilpreet * If pci-pci bridge grab PCI bridge specific error registers. 42700d0963fSdilpreet */ 42800d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 42900d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_sec_stat = 43000d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS); 4318aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 43200d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 43300d0963fSdilpreet PCI_BDG_SEC_STAT_VALID; 43400d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_ctrl = 43500d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL); 4368aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 43700d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 43800d0963fSdilpreet PCI_BDG_CTRL_VALID; 43900d0963fSdilpreet } 44000d0963fSdilpreet 44100d0963fSdilpreet /* 44200d0963fSdilpreet * If pci express device grab pci express error registers and 44300d0963fSdilpreet * check for advanced error reporting features and grab them if 44400d0963fSdilpreet * available. 44500d0963fSdilpreet */ 44600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 4478aec9182Sstephh pcie_regs_gather(erpt_p, fme_flag); 44800d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 4498aec9182Sstephh pcix_regs_gather(erpt_p, erpt_p->pe_regs, fme_flag); 45000d0963fSdilpreet 45100d0963fSdilpreet } 45200d0963fSdilpreet 45300d0963fSdilpreet static void 45400d0963fSdilpreet pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs) 45500d0963fSdilpreet { 45600d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 45700d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 45800d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 45900d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 46000d0963fSdilpreet int i; 46100d0963fSdilpreet 46200d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 46300d0963fSdilpreet 46400d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) 46500d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, 46600d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS), 46700d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat); 46800d0963fSdilpreet 46900d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) 47000d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 47100d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS), 47200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat); 47300d0963fSdilpreet 47400d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags = 0x0; 47500d0963fSdilpreet 47600d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 47700d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 47800d0963fSdilpreet /* 47900d0963fSdilpreet * PCI Express to PCI-X bridges only implement the 48000d0963fSdilpreet * secondary side of the PCI-X ECC registers, bit one is 48100d0963fSdilpreet * read-only so we make sure we do not write to it. 48200d0963fSdilpreet */ 48300d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 48400d0963fSdilpreet pcix_bdg_ecc_regs = 48500d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[1]; 48600d0963fSdilpreet 48700d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 48800d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 48900d0963fSdilpreet 49000d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 49100d0963fSdilpreet (pcix_bdg_cap_ptr + 49200d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 49300d0963fSdilpreet pcix_bdg_ecc_regs-> 49400d0963fSdilpreet pcix_ecc_ctlstat); 49500d0963fSdilpreet } 49600d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 0x0; 49700d0963fSdilpreet } else { 49800d0963fSdilpreet for (i = 0; i < 2; i++) { 49900d0963fSdilpreet pcix_bdg_ecc_regs = 50000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 50100d0963fSdilpreet 50200d0963fSdilpreet 50300d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 50400d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 50500d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 50600d0963fSdilpreet (pcix_bdg_cap_ptr + 50700d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 50800d0963fSdilpreet i); 50900d0963fSdilpreet 51000d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 51100d0963fSdilpreet (pcix_bdg_cap_ptr + 51200d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 51300d0963fSdilpreet pcix_bdg_ecc_regs-> 51400d0963fSdilpreet pcix_ecc_ctlstat); 51500d0963fSdilpreet } 51600d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 51700d0963fSdilpreet 0x0; 51800d0963fSdilpreet } 51900d0963fSdilpreet } 52000d0963fSdilpreet } 52100d0963fSdilpreet } else { 52200d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 52300d0963fSdilpreet uint8_t pcix_cap_ptr; 52400d0963fSdilpreet 52500d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 52600d0963fSdilpreet 52700d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) 52800d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 52900d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS), 53000d0963fSdilpreet pcix_regs->pcix_status); 53100d0963fSdilpreet 53200d0963fSdilpreet pcix_regs->pcix_vflags = 0x0; 53300d0963fSdilpreet 53400d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 53500d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 53600d0963fSdilpreet pcix_regs->pcix_ecc_regs; 53700d0963fSdilpreet 53800d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & 53900d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) 54000d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 54100d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_ECC_STATUS), 54200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat); 54300d0963fSdilpreet 54400d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags = 0x0; 54500d0963fSdilpreet } 54600d0963fSdilpreet } 54700d0963fSdilpreet } 54800d0963fSdilpreet 54900d0963fSdilpreet static void 55000d0963fSdilpreet pcie_regs_clear(pci_erpt_t *erpt_p) 55100d0963fSdilpreet { 55200d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 55300d0963fSdilpreet uint8_t pcie_cap_ptr; 55400d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 55500d0963fSdilpreet uint16_t pcie_ecap_ptr; 55600d0963fSdilpreet 55700d0963fSdilpreet pcie_cap_ptr = pcie_regs->pcie_cap_ptr; 55800d0963fSdilpreet 55900d0963fSdilpreet if (pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) 56000d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, pcie_cap_ptr + PCIE_DEVSTS, 56100d0963fSdilpreet pcie_regs->pcie_err_status); 56200d0963fSdilpreet 56300d0963fSdilpreet pcie_regs->pcie_vflags = 0x0; 56400d0963fSdilpreet 56500d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 56600d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) 56700d0963fSdilpreet pcix_regs_clear(erpt_p, pcie_regs->pcix_bdg_regs); 56800d0963fSdilpreet 56900d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) 57000d0963fSdilpreet return; 57100d0963fSdilpreet 57200d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 57300d0963fSdilpreet 57400d0963fSdilpreet pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr; 57500d0963fSdilpreet 57600d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) 57700d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 57800d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_UCE_STS, 57900d0963fSdilpreet pcie_adv_regs->pcie_ue_status); 58000d0963fSdilpreet 58100d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) 58200d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 58300d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_CE_STS, 58400d0963fSdilpreet pcie_adv_regs->pcie_ce_status); 58500d0963fSdilpreet 58600d0963fSdilpreet 58700d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) { 58800d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 58900d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 59000d0963fSdilpreet 59100d0963fSdilpreet 59200d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID) 59300d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 59400d0963fSdilpreet pcie_ecap_ptr + PCIE_AER_SUCE_STS, 59500d0963fSdilpreet pcie_bdg_regs->pcie_sue_status); 59600d0963fSdilpreet } 59700d0963fSdilpreet /* 59800d0963fSdilpreet * If PCI Express root complex then clear the root complex 59900d0963fSdilpreet * error registers. 60000d0963fSdilpreet */ 60100d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 60200d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 60300d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 60400d0963fSdilpreet 60500d0963fSdilpreet 60600d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) 60700d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 60800d0963fSdilpreet (pcie_ecap_ptr + PCIE_AER_RE_STS), 60900d0963fSdilpreet pcie_rc_regs->pcie_rc_err_status); 61000d0963fSdilpreet } 61100d0963fSdilpreet pcie_adv_regs->pcie_adv_vflags = 0x0; 61200d0963fSdilpreet } 61300d0963fSdilpreet 61400d0963fSdilpreet static void 61500d0963fSdilpreet pci_regs_clear(pci_erpt_t *erpt_p) 61600d0963fSdilpreet { 61700d0963fSdilpreet /* 61800d0963fSdilpreet * Finally clear the error bits 61900d0963fSdilpreet */ 62000d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 62100d0963fSdilpreet pcie_regs_clear(erpt_p); 62200d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 62300d0963fSdilpreet pcix_regs_clear(erpt_p, erpt_p->pe_regs); 62400d0963fSdilpreet 62500d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID) 62600d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT, 62700d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status); 62800d0963fSdilpreet 62900d0963fSdilpreet erpt_p->pe_pci_regs->pci_vflags = 0x0; 63000d0963fSdilpreet 63100d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 63200d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 63300d0963fSdilpreet PCI_BDG_SEC_STAT_VALID) 63400d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS, 63500d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs-> 63600d0963fSdilpreet pci_bdg_sec_stat); 63700d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 63800d0963fSdilpreet PCI_BDG_CTRL_VALID) 63900d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL, 64000d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl); 64100d0963fSdilpreet 64200d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0; 64300d0963fSdilpreet } 64400d0963fSdilpreet } 64500d0963fSdilpreet 64600d0963fSdilpreet /* 64700d0963fSdilpreet * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport 64800d0963fSdilpreet * generation. 64900d0963fSdilpreet */ 65000d0963fSdilpreet /* ARGSUSED */ 65100d0963fSdilpreet static void 65200d0963fSdilpreet pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 65300d0963fSdilpreet { 65400d0963fSdilpreet uint8_t pcix_cap_ptr; 65500d0963fSdilpreet int i; 65600d0963fSdilpreet 65700d0963fSdilpreet pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 65800d0963fSdilpreet "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 65900d0963fSdilpreet 66000d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 66100d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 66200d0963fSdilpreet else 66300d0963fSdilpreet return; 66400d0963fSdilpreet 66500d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 66600d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 66700d0963fSdilpreet 66800d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t), 66900d0963fSdilpreet KM_SLEEP); 67000d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 67100d0963fSdilpreet pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 67200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl, 67300d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 67400d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 67500d0963fSdilpreet for (i = 0; i < 2; i++) { 67600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 67700d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 67800d0963fSdilpreet KM_SLEEP); 67900d0963fSdilpreet } 68000d0963fSdilpreet } 68100d0963fSdilpreet } else { 68200d0963fSdilpreet pcix_error_regs_t *pcix_regs; 68300d0963fSdilpreet 68400d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t), 68500d0963fSdilpreet KM_SLEEP); 68600d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 68700d0963fSdilpreet pcix_regs->pcix_cap_ptr = pcix_cap_ptr; 68800d0963fSdilpreet pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl, 68900d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 69000d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 69100d0963fSdilpreet pcix_regs->pcix_ecc_regs = kmem_zalloc( 69200d0963fSdilpreet sizeof (pcix_ecc_regs_t), KM_SLEEP); 69300d0963fSdilpreet } 69400d0963fSdilpreet } 69500d0963fSdilpreet } 69600d0963fSdilpreet 69700d0963fSdilpreet static void 69800d0963fSdilpreet pcie_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 69900d0963fSdilpreet { 70000d0963fSdilpreet pcie_error_regs_t *pcie_regs; 70100d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 70200d0963fSdilpreet uint8_t pcix_cap_ptr; 70300d0963fSdilpreet uint8_t pcie_cap_ptr; 70400d0963fSdilpreet uint16_t pcie_ecap_ptr; 70500d0963fSdilpreet uint16_t dev_type = 0; 70600d0963fSdilpreet 70700d0963fSdilpreet /* 70800d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 70900d0963fSdilpreet * interfaces create the necessary properties for us. 71000d0963fSdilpreet */ 71100d0963fSdilpreet #if defined(__sparc) 71200d0963fSdilpreet ushort_t status; 71300d0963fSdilpreet uint32_t slot_cap; 71400d0963fSdilpreet uint8_t cap_ptr = 0; 71500d0963fSdilpreet uint8_t cap_id = 0; 71600d0963fSdilpreet uint32_t hdr, hdr_next_ptr, hdr_cap_id; 71700d0963fSdilpreet uint16_t offset = P2ALIGN(PCIE_EXT_CAP, 4); 71800d0963fSdilpreet uint16_t aer_ptr = 0; 71900d0963fSdilpreet 72000d0963fSdilpreet cap_ptr = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_CAP_PTR); 7218aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) == 7228aec9182Sstephh DDI_FM_OK) { 72300d0963fSdilpreet while ((cap_id = pci_config_get8(erpt_p->pe_hdl, cap_ptr)) != 72400d0963fSdilpreet 0xff) { 72500d0963fSdilpreet if (cap_id == PCI_CAP_ID_PCIX) { 72600d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 72700d0963fSdilpreet "pcix-capid-pointer", cap_ptr); 72800d0963fSdilpreet } 72900d0963fSdilpreet if (cap_id == PCI_CAP_ID_PCI_E) { 73000d0963fSdilpreet status = pci_config_get16(erpt_p->pe_hdl, cap_ptr + 2); 73100d0963fSdilpreet if (status & PCIE_PCIECAP_SLOT_IMPL) { 73200d0963fSdilpreet /* offset 14h is Slot Cap Register */ 73300d0963fSdilpreet slot_cap = pci_config_get32(erpt_p->pe_hdl, 73400d0963fSdilpreet cap_ptr + PCIE_SLOTCAP); 73500d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 73600d0963fSdilpreet "pcie-slotcap-reg", slot_cap); 73700d0963fSdilpreet } 73800d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 73900d0963fSdilpreet "pcie-capid-reg", pci_config_get16(erpt_p->pe_hdl, 74000d0963fSdilpreet cap_ptr + PCIE_PCIECAP)); 74100d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 74200d0963fSdilpreet "pcie-capid-pointer", cap_ptr); 74300d0963fSdilpreet 74400d0963fSdilpreet } 74500d0963fSdilpreet if ((cap_ptr = pci_config_get8(erpt_p->pe_hdl, 74600d0963fSdilpreet cap_ptr + 1)) == 0xff || cap_ptr == 0 || 7478aec9182Sstephh (pci_config_check(erpt_p->pe_hdl, 7488aec9182Sstephh DDI_FM_ERR_UNEXPECTED) != DDI_FM_OK)) 74900d0963fSdilpreet break; 75000d0963fSdilpreet } 75100d0963fSdilpreet } 75200d0963fSdilpreet 75300d0963fSdilpreet #endif 75400d0963fSdilpreet 75500d0963fSdilpreet pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 75600d0963fSdilpreet "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 75700d0963fSdilpreet 75800d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 75900d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 76000d0963fSdilpreet 76100d0963fSdilpreet pcie_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 76200d0963fSdilpreet DDI_PROP_DONTPASS, "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL); 76300d0963fSdilpreet 76400d0963fSdilpreet if (pcie_cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 76500d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_DEV; 76600d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcie_error_regs_t), 76700d0963fSdilpreet KM_SLEEP); 76800d0963fSdilpreet pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 76900d0963fSdilpreet pcie_regs->pcie_cap_ptr = pcie_cap_ptr; 77000d0963fSdilpreet } 77100d0963fSdilpreet 77200d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) 77300d0963fSdilpreet return; 77400d0963fSdilpreet 77500d0963fSdilpreet /* 77600d0963fSdilpreet * Don't currently need to check for version here because we are 77700d0963fSdilpreet * compliant with PCIE 1.0a which is version 0 and is guaranteed 77800d0963fSdilpreet * software compatibility with future versions. We will need to 77900d0963fSdilpreet * add errors for new detectors/features which are added in newer 78000d0963fSdilpreet * revisions [sec 7.8.2]. 78100d0963fSdilpreet */ 78200d0963fSdilpreet pcie_regs->pcie_cap = pci_config_get16(erpt_p->pe_hdl, 78300d0963fSdilpreet pcie_regs->pcie_cap_ptr + PCIE_PCIECAP); 78400d0963fSdilpreet 78500d0963fSdilpreet dev_type = pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK; 78600d0963fSdilpreet 78700d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 78800d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 78900d0963fSdilpreet int i; 79000d0963fSdilpreet 79100d0963fSdilpreet pcie_regs->pcix_bdg_regs = 79200d0963fSdilpreet kmem_zalloc(sizeof (pcix_bdg_error_regs_t), KM_SLEEP); 79300d0963fSdilpreet 79400d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 79500d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_ver = 79600d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, 79700d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 79800d0963fSdilpreet 79900d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcie_regs->pcix_bdg_regs->pcix_bdg_ver)) 80000d0963fSdilpreet for (i = 0; i < 2; i++) 80100d0963fSdilpreet pcie_regs->pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 80200d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 80300d0963fSdilpreet KM_SLEEP); 80400d0963fSdilpreet } 80500d0963fSdilpreet 80600d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) { 80700d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_RC_DEV; 80800d0963fSdilpreet pcie_regs->pcie_rc_regs = kmem_zalloc( 80900d0963fSdilpreet sizeof (pcie_rc_error_regs_t), KM_SLEEP); 81000d0963fSdilpreet } 81100d0963fSdilpreet /* 81200d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 81300d0963fSdilpreet * interfaces create the necessary properties for us. 81400d0963fSdilpreet */ 81500d0963fSdilpreet #if defined(__sparc) 81600d0963fSdilpreet 81700d0963fSdilpreet hdr = pci_config_get32(erpt_p->pe_hdl, offset); 81800d0963fSdilpreet hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 81900d0963fSdilpreet PCIE_EXT_CAP_NEXT_PTR_MASK; 82000d0963fSdilpreet hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK; 82100d0963fSdilpreet 82200d0963fSdilpreet while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) && 82300d0963fSdilpreet (hdr_cap_id != PCIE_EXT_CAP_ID_AER)) { 82400d0963fSdilpreet offset = P2ALIGN(hdr_next_ptr, 4); 82500d0963fSdilpreet hdr = pci_config_get32(erpt_p->pe_hdl, offset); 82600d0963fSdilpreet hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) & 82700d0963fSdilpreet PCIE_EXT_CAP_NEXT_PTR_MASK; 82800d0963fSdilpreet hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & 82900d0963fSdilpreet PCIE_EXT_CAP_ID_MASK; 83000d0963fSdilpreet } 83100d0963fSdilpreet 83200d0963fSdilpreet if (hdr_cap_id == PCIE_EXT_CAP_ID_AER) 83300d0963fSdilpreet aer_ptr = P2ALIGN(offset, 4); 83400d0963fSdilpreet if (aer_ptr != PCI_CAP_NEXT_PTR_NULL) 83500d0963fSdilpreet (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 83600d0963fSdilpreet "pcie-aer-pointer", aer_ptr); 83700d0963fSdilpreet #endif 83800d0963fSdilpreet 83900d0963fSdilpreet /* 84000d0963fSdilpreet * Find and store if this device is capable of pci express 84100d0963fSdilpreet * advanced errors, if not report an error against the device. 84200d0963fSdilpreet */ 84300d0963fSdilpreet pcie_ecap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 84400d0963fSdilpreet "pcie-aer-pointer", PCI_CAP_NEXT_PTR_NULL); 84500d0963fSdilpreet if (pcie_ecap_ptr != PCI_CAP_NEXT_PTR_NULL) { 84600d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_ADV_DEV; 84700d0963fSdilpreet pcie_regs->pcie_adv_regs = kmem_zalloc( 84800d0963fSdilpreet sizeof (pcie_adv_error_regs_t), KM_SLEEP); 84900d0963fSdilpreet pcie_regs->pcie_adv_regs->pcie_adv_cap_ptr = pcie_ecap_ptr; 85000d0963fSdilpreet } 85100d0963fSdilpreet 85200d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 85300d0963fSdilpreet return; 85400d0963fSdilpreet } 85500d0963fSdilpreet 85600d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 85700d0963fSdilpreet 85800d0963fSdilpreet if (pcie_adv_regs == NULL) 85900d0963fSdilpreet return; 86000d0963fSdilpreet /* 86100d0963fSdilpreet * Initialize structures for advanced PCI Express devices. 86200d0963fSdilpreet */ 86300d0963fSdilpreet 86400d0963fSdilpreet /* 86500d0963fSdilpreet * Advanced error registers exist for PCI Express to PCI(X) Bridges and 86600d0963fSdilpreet * may also exist for PCI(X) to PCI Express Bridges, the latter is not 86700d0963fSdilpreet * well explained in the PCI Express to PCI/PCI-X Bridge Specification 86800d0963fSdilpreet * 1.0 and will be left out of the current gathering of these registers. 86900d0963fSdilpreet */ 87000d0963fSdilpreet if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) { 87100d0963fSdilpreet erpt_p->pe_dflags |= PCIEX_2PCI_DEV; 87200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs = kmem_zalloc( 87300d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t), KM_SLEEP); 87400d0963fSdilpreet } 87500d0963fSdilpreet 87600d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 87700d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs = kmem_zalloc( 87800d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t), KM_SLEEP); 87900d0963fSdilpreet } 88000d0963fSdilpreet 88100d0963fSdilpreet /* 88200d0963fSdilpreet * pci_ereport_setup: Detect PCI device type and initialize structures to be 88300d0963fSdilpreet * used to generate ereports based on detected generic device errors. 88400d0963fSdilpreet */ 88500d0963fSdilpreet void 88600d0963fSdilpreet pci_ereport_setup(dev_info_t *dip) 88700d0963fSdilpreet { 88800d0963fSdilpreet struct dev_info *devi = DEVI(dip); 88900d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl; 89000d0963fSdilpreet pci_erpt_t *erpt_p; 89100d0963fSdilpreet uint8_t pci_hdr_type; 89200d0963fSdilpreet uint16_t pci_status; 89300d0963fSdilpreet pci_regspec_t *pci_rp; 89400d0963fSdilpreet int32_t len; 89500d0963fSdilpreet uint32_t phys_hi; 89600d0963fSdilpreet 89700d0963fSdilpreet /* 89800d0963fSdilpreet * If device is not ereport capbable then report an error against the 89900d0963fSdilpreet * driver for using this interface, 90000d0963fSdilpreet */ 90100d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 90200d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 90300d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 90400d0963fSdilpreet return; 90500d0963fSdilpreet } 90600d0963fSdilpreet 90700d0963fSdilpreet /* 90800d0963fSdilpreet * ASSERT fmhdl exists and fh_bus_specific is NULL. 90900d0963fSdilpreet */ 91000d0963fSdilpreet ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL)); 91100d0963fSdilpreet 91200d0963fSdilpreet erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP); 91300d0963fSdilpreet 91400d0963fSdilpreet if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS) 91500d0963fSdilpreet goto error; 91600d0963fSdilpreet 91700d0963fSdilpreet erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP); 91800d0963fSdilpreet 91900d0963fSdilpreet pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT); 9208aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) != 9218aec9182Sstephh DDI_FM_OK) 92200d0963fSdilpreet goto error; 92300d0963fSdilpreet 92400d0963fSdilpreet /* 92500d0963fSdilpreet * Get header type and record if device is a bridge. 92600d0963fSdilpreet */ 92700d0963fSdilpreet pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER); 9288aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) != 9298aec9182Sstephh DDI_FM_OK) 93000d0963fSdilpreet goto error; 93100d0963fSdilpreet 93200d0963fSdilpreet /* 93300d0963fSdilpreet * Check to see if PCI device is a bridge, if so allocate pci bridge 93400d0963fSdilpreet * error register structure. 93500d0963fSdilpreet */ 93600d0963fSdilpreet if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 93700d0963fSdilpreet erpt_p->pe_dflags |= PCI_BRIDGE_DEV; 93800d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc( 93900d0963fSdilpreet sizeof (pci_bdg_error_regs_t), KM_SLEEP); 94000d0963fSdilpreet } 94100d0963fSdilpreet 94200d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 94300d0963fSdilpreet (caddr_t)&pci_rp, &len) == DDI_SUCCESS) { 94400d0963fSdilpreet phys_hi = pci_rp->pci_phys_hi; 94500d0963fSdilpreet kmem_free(pci_rp, len); 94600d0963fSdilpreet 94700d0963fSdilpreet erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >> 94800d0963fSdilpreet PCI_REG_FUNC_SHIFT); 94900d0963fSdilpreet } 95000d0963fSdilpreet 95100d0963fSdilpreet if (!(pci_status & PCI_STAT_CAP)) { 95200d0963fSdilpreet goto done; 95300d0963fSdilpreet } 95400d0963fSdilpreet 95500d0963fSdilpreet /* 95600d0963fSdilpreet * Initialize structures for PCI Express and PCI-X devices. 95700d0963fSdilpreet * Order matters below and pcie_ereport_setup should preceed 95800d0963fSdilpreet * pcix_ereport_setup. 95900d0963fSdilpreet */ 96000d0963fSdilpreet pcie_ereport_setup(dip, erpt_p); 96100d0963fSdilpreet 96200d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_DEV)) { 96300d0963fSdilpreet pcix_ereport_setup(dip, erpt_p); 96400d0963fSdilpreet } 96500d0963fSdilpreet 96600d0963fSdilpreet done: 9678aec9182Sstephh pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED); 96800d0963fSdilpreet pci_regs_clear(erpt_p); 96900d0963fSdilpreet 97000d0963fSdilpreet /* 97100d0963fSdilpreet * Before returning set fh_bus_specific to completed pci_erpt_t 97200d0963fSdilpreet * structure 97300d0963fSdilpreet */ 97400d0963fSdilpreet fmhdl->fh_bus_specific = (void *)erpt_p; 97500d0963fSdilpreet 97600d0963fSdilpreet return; 97700d0963fSdilpreet error: 97800d0963fSdilpreet if (erpt_p->pe_pci_regs) 97900d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 98000d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 98100d0963fSdilpreet erpt_p = NULL; 98200d0963fSdilpreet } 98300d0963fSdilpreet 98400d0963fSdilpreet static void 98500d0963fSdilpreet pcix_ereport_teardown(pci_erpt_t *erpt_p) 98600d0963fSdilpreet { 98700d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 98800d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 98900d0963fSdilpreet uint16_t pcix_ver; 99000d0963fSdilpreet 99100d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 99200d0963fSdilpreet pcix_ver = pcix_bdg_regs->pcix_bdg_ver; 99300d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 99400d0963fSdilpreet int i; 99500d0963fSdilpreet for (i = 0; i < 2; i++) 99600d0963fSdilpreet kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i], 99700d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 99800d0963fSdilpreet } 99900d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t)); 100000d0963fSdilpreet } else { 100100d0963fSdilpreet pcix_error_regs_t *pcix_regs; 100200d0963fSdilpreet uint16_t pcix_ver; 100300d0963fSdilpreet 100400d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 100500d0963fSdilpreet pcix_ver = pcix_regs->pcix_ver; 100600d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 100700d0963fSdilpreet kmem_free(pcix_regs->pcix_ecc_regs, 100800d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 100900d0963fSdilpreet } 101000d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t)); 101100d0963fSdilpreet } 101200d0963fSdilpreet } 101300d0963fSdilpreet 101400d0963fSdilpreet static void 101500d0963fSdilpreet pcie_ereport_teardown(pci_erpt_t *erpt_p) 101600d0963fSdilpreet { 101700d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 101800d0963fSdilpreet 101900d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_ADV_DEV) { 102000d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv = pcie_regs->pcie_adv_regs; 102100d0963fSdilpreet 102200d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) 102300d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_bdg_regs, 102400d0963fSdilpreet sizeof (pcie_adv_bdg_error_regs_t)); 102500d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 102600d0963fSdilpreet kmem_free(pcie_adv->pcie_adv_rc_regs, 102700d0963fSdilpreet sizeof (pcie_adv_rc_error_regs_t)); 102800d0963fSdilpreet kmem_free(pcie_adv, sizeof (pcie_adv_error_regs_t)); 102900d0963fSdilpreet } 103000d0963fSdilpreet 103100d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) 103200d0963fSdilpreet kmem_free(pcie_regs->pcie_rc_regs, 103300d0963fSdilpreet sizeof (pcie_rc_error_regs_t)); 103400d0963fSdilpreet 103500d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 103600d0963fSdilpreet if (erpt_p->pe_dflags & PCIX_DEV) { 103700d0963fSdilpreet uint16_t pcix_ver = pcie_regs->pcix_bdg_regs-> 103800d0963fSdilpreet pcix_bdg_ver; 103900d0963fSdilpreet 104000d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 104100d0963fSdilpreet int i; 104200d0963fSdilpreet for (i = 0; i < 2; i++) 104300d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs-> 104400d0963fSdilpreet pcix_bdg_ecc_regs[i], 104500d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 104600d0963fSdilpreet } 104700d0963fSdilpreet kmem_free(pcie_regs->pcix_bdg_regs, 104800d0963fSdilpreet sizeof (pcix_bdg_error_regs_t)); 104900d0963fSdilpreet } 105000d0963fSdilpreet } 105100d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcie_error_regs_t)); 105200d0963fSdilpreet } 105300d0963fSdilpreet 105400d0963fSdilpreet void 105500d0963fSdilpreet pci_ereport_teardown(dev_info_t *dip) 105600d0963fSdilpreet { 105700d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 105800d0963fSdilpreet pci_erpt_t *erpt_p; 105900d0963fSdilpreet 106000d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 106100d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 106200d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 106300d0963fSdilpreet } 106400d0963fSdilpreet 106500d0963fSdilpreet ASSERT(fmhdl); 106600d0963fSdilpreet 106700d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 106800d0963fSdilpreet if (erpt_p == NULL) 106900d0963fSdilpreet return; 107000d0963fSdilpreet 107100d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) 107200d0963fSdilpreet pcie_ereport_teardown(erpt_p); 107300d0963fSdilpreet else if (erpt_p->pe_dflags & PCIX_DEV) 107400d0963fSdilpreet pcix_ereport_teardown(erpt_p); 107500d0963fSdilpreet pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl); 107600d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) 107700d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs, 107800d0963fSdilpreet sizeof (pci_bdg_error_regs_t)); 107900d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 108000d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 108100d0963fSdilpreet fmhdl->fh_bus_specific = NULL; 1082*eae2e508Skrishnae 108300d0963fSdilpreet /* 108400d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 108500d0963fSdilpreet * interfaces create the necessary properties for us. 108600d0963fSdilpreet */ 108700d0963fSdilpreet #if defined(__sparc) 108800d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcix-capid-pointer"); 108900d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-slotcap-reg"); 109000d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-reg"); 109100d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-pointer"); 109200d0963fSdilpreet (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-aer-pointer"); 109300d0963fSdilpreet #endif 109400d0963fSdilpreet } 109500d0963fSdilpreet 109600d0963fSdilpreet static void 109700d0963fSdilpreet pcie_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 109800d0963fSdilpreet char *buf, int errtype) 109900d0963fSdilpreet { 110000d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 110100d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 1102390e643aSdilpreet pcie_adv_rc_error_regs_t *pcie_adv_rc_regs; 110300d0963fSdilpreet 110400d0963fSdilpreet switch (errtype) { 110500d0963fSdilpreet case PCIEX_TYPE_CE: 110600d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 110700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 110800d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 110900d0963fSdilpreet pcie_regs->pcie_err_status, 111000d0963fSdilpreet PCIEX_CE_STATUS_REG, DATA_TYPE_UINT32, 111100d0963fSdilpreet pcie_adv_regs->pcie_ce_status, NULL); 111200d0963fSdilpreet break; 111300d0963fSdilpreet case PCIEX_TYPE_UE: 111400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 111500d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 111600d0963fSdilpreet PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 111700d0963fSdilpreet pcie_regs->pcie_err_status, 111800d0963fSdilpreet PCIEX_UE_STATUS_REG, DATA_TYPE_UINT32, 111900d0963fSdilpreet pcie_adv_regs->pcie_ue_status, PCIEX_UE_SEV_REG, 112000d0963fSdilpreet DATA_TYPE_UINT32, pcie_adv_regs->pcie_ue_sev, 112100d0963fSdilpreet PCIEX_ADV_CTL, DATA_TYPE_UINT32, 112200d0963fSdilpreet pcie_adv_regs->pcie_adv_ctl, 112300d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 112400d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 112500d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 112600d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 112700d0963fSdilpreet 1 : NULL, 112800d0963fSdilpreet #ifdef DEBUG 112900d0963fSdilpreet PCIEX_UE_HDR0, DATA_TYPE_UINT32, 113000d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr0, 113100d0963fSdilpreet PCIEX_UE_HDR1, DATA_TYPE_UINT32, 113200d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[0], 113300d0963fSdilpreet PCIEX_UE_HDR2, DATA_TYPE_UINT32, 113400d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[1], 113500d0963fSdilpreet PCIEX_UE_HDR3, DATA_TYPE_UINT32, 113600d0963fSdilpreet pcie_adv_regs->pcie_ue_hdr[2], 113700d0963fSdilpreet #endif 113800d0963fSdilpreet NULL); 113900d0963fSdilpreet break; 114000d0963fSdilpreet case PCIEX_TYPE_GEN: 114100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 114200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 114300d0963fSdilpreet 0, PCIEX_DEVSTS_REG, DATA_TYPE_UINT16, 114400d0963fSdilpreet pcie_regs->pcie_err_status, NULL); 114500d0963fSdilpreet break; 114600d0963fSdilpreet case PCIEX_TYPE_RC_UE_MSG: 114700d0963fSdilpreet case PCIEX_TYPE_RC_CE_MSG: 1148390e643aSdilpreet pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs; 1149390e643aSdilpreet 115000d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 115100d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 115200d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 115300d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, 115400d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 115500d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 115600d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id : 115700d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id, 115800d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 115900d0963fSdilpreet (errtype == PCIEX_TYPE_RC_UE_MSG) ? 116000d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 116100d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ue_src_id != 0) : 116200d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID && 116300d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_ce_src_id != 0), NULL); 116400d0963fSdilpreet break; 116500d0963fSdilpreet case PCIEX_TYPE_RC_MULT_MSG: 1166390e643aSdilpreet pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs; 1167390e643aSdilpreet 116800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 116900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 117000d0963fSdilpreet PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32, 117100d0963fSdilpreet pcie_adv_rc_regs->pcie_rc_err_status, NULL); 117200d0963fSdilpreet break; 117300d0963fSdilpreet default: 117400d0963fSdilpreet break; 117500d0963fSdilpreet } 117600d0963fSdilpreet } 117700d0963fSdilpreet 11788aec9182Sstephh /*ARGSUSED*/ 117900d0963fSdilpreet static void 11808aec9182Sstephh pcie_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 118100d0963fSdilpreet { 11828aec9182Sstephh pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 118300d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 118400d0963fSdilpreet pcie_tlp_hdr_t *ue_hdr0; 118500d0963fSdilpreet uint32_t *ue_hdr; 118600d0963fSdilpreet uint64_t addr = NULL; 11878aec9182Sstephh int upstream = 0; 11888aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 11898aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 119000d0963fSdilpreet 11918aec9182Sstephh if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_UE_HDR_VALID)) 119200d0963fSdilpreet return; 11938aec9182Sstephh 119400d0963fSdilpreet ue_hdr0 = (pcie_tlp_hdr_t *)&pcie_adv_regs->pcie_ue_hdr0; 119500d0963fSdilpreet ue_hdr = pcie_adv_regs->pcie_ue_hdr; 119600d0963fSdilpreet 11978aec9182Sstephh if ((pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 11988aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_ROOT || 11998aec9182Sstephh (pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 12008aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_DOWN) 12018aec9182Sstephh upstream = 1; 12028aec9182Sstephh 120300d0963fSdilpreet switch (ue_hdr0->type) { 120400d0963fSdilpreet case PCIE_TLP_TYPE_MEM: 120500d0963fSdilpreet case PCIE_TLP_TYPE_MEMLK: 120600d0963fSdilpreet if ((ue_hdr0->fmt & 0x1) == 0x1) { 120700d0963fSdilpreet pcie_mem64_t *mem64_tlp = (pcie_mem64_t *)ue_hdr; 120800d0963fSdilpreet 120900d0963fSdilpreet addr = (uint64_t)mem64_tlp->addr1 << 32 | 121000d0963fSdilpreet (uint32_t)mem64_tlp->addr0 << 2; 121100d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = mem64_tlp->rid; 121200d0963fSdilpreet } else { 121300d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 121400d0963fSdilpreet 121500d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 121600d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 121700d0963fSdilpreet } 12188aec9182Sstephh if (upstream) { 12198aec9182Sstephh pci_fme_bsp->pci_bs_bdf = pcie_adv_regs->pcie_adv_bdf; 12208aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12218aec9182Sstephh } else if ((pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) == 12228aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { 12238aec9182Sstephh pci_fme_bsp->pci_bs_bdf = erpt_p->pe_bdf; 12248aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12258aec9182Sstephh } 12268aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 12278aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 12288aec9182Sstephh pci_fme_bsp->pci_bs_type = upstream ? DMA_HANDLE : ACC_HANDLE; 122900d0963fSdilpreet break; 123000d0963fSdilpreet 123100d0963fSdilpreet case PCIE_TLP_TYPE_IO: 123200d0963fSdilpreet { 123300d0963fSdilpreet pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr; 123400d0963fSdilpreet 123500d0963fSdilpreet addr = (uint32_t)memio32_tlp->addr0 << 2; 123600d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid; 12378aec9182Sstephh if ((pcie_regs->pcie_cap & 12388aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_MASK) == 12398aec9182Sstephh PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { 12408aec9182Sstephh pci_fme_bsp->pci_bs_bdf = erpt_p->pe_bdf; 12418aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12428aec9182Sstephh } 12438aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 12448aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 12458aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 124600d0963fSdilpreet break; 124700d0963fSdilpreet } 124800d0963fSdilpreet case PCIE_TLP_TYPE_CFG0: 124900d0963fSdilpreet case PCIE_TLP_TYPE_CFG1: 125000d0963fSdilpreet { 125100d0963fSdilpreet pcie_cfg_t *cfg_tlp = (pcie_cfg_t *)ue_hdr; 125200d0963fSdilpreet 1253ac4d633fSstephh pcie_adv_regs->pcie_adv_bdf = cfg_tlp->rid; 12548aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (uint16_t)cfg_tlp->bus << 8 | 12558aec9182Sstephh (uint16_t)cfg_tlp->dev << 3 | cfg_tlp->func; 12568aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12578aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 125800d0963fSdilpreet break; 125900d0963fSdilpreet } 126000d0963fSdilpreet case PCIE_TLP_TYPE_MSG: 126100d0963fSdilpreet { 126200d0963fSdilpreet pcie_msg_t *msg_tlp = (pcie_msg_t *)ue_hdr; 126300d0963fSdilpreet 126400d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = msg_tlp->rid; 126500d0963fSdilpreet break; 126600d0963fSdilpreet } 126700d0963fSdilpreet case PCIE_TLP_TYPE_CPL: 126800d0963fSdilpreet case PCIE_TLP_TYPE_CPLLK: 126900d0963fSdilpreet { 127000d0963fSdilpreet pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)ue_hdr; 127100d0963fSdilpreet 127200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = cpl_tlp->cid; 12738aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 12748aec9182Sstephh if (upstream) { 12758aec9182Sstephh pci_fme_bsp->pci_bs_bdf = cpl_tlp->cid; 12768aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 12778aec9182Sstephh } else { 12788aec9182Sstephh pci_fme_bsp->pci_bs_bdf = cpl_tlp->rid; 12798aec9182Sstephh pci_fme_bsp->pci_bs_type = DMA_HANDLE; 12808aec9182Sstephh } 128100d0963fSdilpreet break; 128200d0963fSdilpreet } 128300d0963fSdilpreet case PCIE_TLP_TYPE_MSI: 128400d0963fSdilpreet default: 12858aec9182Sstephh break; 12868aec9182Sstephh } 128700d0963fSdilpreet } 128800d0963fSdilpreet 12898aec9182Sstephh /*ARGSUSED*/ 129000d0963fSdilpreet static void 12918aec9182Sstephh pcie_pci_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 12928aec9182Sstephh int type) 129300d0963fSdilpreet { 12948aec9182Sstephh pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 129500d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs; 129600d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs = 129700d0963fSdilpreet pcie_adv_regs->pcie_adv_bdg_regs; 129800d0963fSdilpreet uint64_t addr = NULL; 129900d0963fSdilpreet pcix_attr_t *pcie_pci_sue_attr; 130000d0963fSdilpreet int cmd; 130100d0963fSdilpreet int dual_addr = 0; 13028aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 13038aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 130400d0963fSdilpreet 13058aec9182Sstephh if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_HDR_VALID)) 130600d0963fSdilpreet return; 130700d0963fSdilpreet 130800d0963fSdilpreet pcie_pci_sue_attr = (pcix_attr_t *)&pcie_bdg_regs->pcie_sue_hdr0; 130900d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 131000d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK; 13118aec9182Sstephh 131200d0963fSdilpreet cmd_switch: 13138aec9182Sstephh addr = pcie_bdg_regs->pcie_sue_hdr[2]; 13148aec9182Sstephh addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) | 13158aec9182Sstephh pcie_bdg_regs->pcie_sue_hdr[1]; 131600d0963fSdilpreet switch (cmd) { 131700d0963fSdilpreet case PCI_PCIX_CMD_IORD: 131800d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 131900d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 13208aec9182Sstephh if (addr) { 13218aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 13228aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 13238aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 13248aec9182Sstephh } 132500d0963fSdilpreet break; 132600d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 132700d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 132800d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 132900d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 133000d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 133100d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 133200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 13338aec9182Sstephh if (addr) { 13348aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 13358aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 13368aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 13378aec9182Sstephh } 133800d0963fSdilpreet break; 133900d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 134000d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 1341ac4d633fSstephh pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 13428aec9182Sstephh /* 13438aec9182Sstephh * for type 1 config transaction we can find bdf from address 13448aec9182Sstephh */ 13458aec9182Sstephh if ((addr & 3) == 1) { 13468aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff; 13478aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 13488aec9182Sstephh pci_fme_bsp->pci_bs_type = ACC_HANDLE; 13498aec9182Sstephh } 13508aec9182Sstephh break; 13518aec9182Sstephh case PCI_PCIX_CMD_SPL: 13528aec9182Sstephh pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid; 13538aec9182Sstephh if (type == ACC_HANDLE) { 13548aec9182Sstephh pci_fme_bsp->pci_bs_bdf = pcie_adv_regs->pcie_adv_bdf; 13558aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 13568aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 13578aec9182Sstephh } 135800d0963fSdilpreet break; 135900d0963fSdilpreet case PCI_PCIX_CMD_DADR: 136000d0963fSdilpreet cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >> 136100d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) & 136200d0963fSdilpreet PCIE_AER_SUCE_HDR_CMD_UP_MASK; 136300d0963fSdilpreet if (dual_addr) 136400d0963fSdilpreet break; 136500d0963fSdilpreet ++dual_addr; 136600d0963fSdilpreet goto cmd_switch; 136700d0963fSdilpreet default: 13688aec9182Sstephh break; 13698aec9182Sstephh } 137000d0963fSdilpreet } 137100d0963fSdilpreet 13728aec9182Sstephh /*ARGSUSED*/ 137300d0963fSdilpreet static int 137400d0963fSdilpreet pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, 13758aec9182Sstephh pcix_ecc_regs_t *pcix_ecc_regs, int type) 137600d0963fSdilpreet { 137700d0963fSdilpreet int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf; 137800d0963fSdilpreet uint64_t addr; 13798aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 13808aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 138100d0963fSdilpreet 138200d0963fSdilpreet addr = pcix_ecc_regs->pcix_ecc_secaddr; 138300d0963fSdilpreet addr = addr << 32; 138400d0963fSdilpreet addr |= pcix_ecc_regs->pcix_ecc_fstaddr; 138500d0963fSdilpreet 138600d0963fSdilpreet switch (cmd) { 138700d0963fSdilpreet case PCI_PCIX_CMD_INTR: 138800d0963fSdilpreet case PCI_PCIX_CMD_SPEC: 138900d0963fSdilpreet return (DDI_FM_FATAL); 139000d0963fSdilpreet case PCI_PCIX_CMD_IORD: 139100d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 13928aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 13938aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 13948aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 13958aec9182Sstephh return (DDI_FM_UNKNOWN); 139600d0963fSdilpreet case PCI_PCIX_CMD_DEVID: 139700d0963fSdilpreet return (DDI_FM_FATAL); 139800d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 139900d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 140000d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 140100d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 14028aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 14038aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 14048aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 14058aec9182Sstephh return (DDI_FM_UNKNOWN); 140600d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 140700d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 14088aec9182Sstephh /* 14098aec9182Sstephh * for type 1 config transaction we can find bdf from address 14108aec9182Sstephh */ 14118aec9182Sstephh if ((addr & 3) == 1) { 14128aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff; 14138aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 14148aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 14158aec9182Sstephh } 14168aec9182Sstephh return (DDI_FM_UNKNOWN); 141700d0963fSdilpreet case PCI_PCIX_CMD_SPL: 141800d0963fSdilpreet case PCI_PCIX_CMD_DADR: 14198aec9182Sstephh return (DDI_FM_UNKNOWN); 142000d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 142100d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 14228aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 14238aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 14248aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 14258aec9182Sstephh return (DDI_FM_UNKNOWN); 142600d0963fSdilpreet default: 142700d0963fSdilpreet return (DDI_FM_FATAL); 142800d0963fSdilpreet } 142900d0963fSdilpreet } 143000d0963fSdilpreet 143100d0963fSdilpreet /*ARGSUSED*/ 143200d0963fSdilpreet static int 143300d0963fSdilpreet pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 143400d0963fSdilpreet { 143500d0963fSdilpreet pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs; 143600d0963fSdilpreet int fatal = 0; 143700d0963fSdilpreet int nonfatal = 0; 143800d0963fSdilpreet int unknown = 0; 143900d0963fSdilpreet int ok = 0; 144000d0963fSdilpreet int ret = DDI_FM_OK; 144100d0963fSdilpreet char buf[FM_MAX_CLASS]; 144200d0963fSdilpreet int i; 14438aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 14448aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 144500d0963fSdilpreet 144600d0963fSdilpreet if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) 144700d0963fSdilpreet goto done; 144800d0963fSdilpreet 144900d0963fSdilpreet if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) && 145000d0963fSdilpreet (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) { 145100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 145200d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_DTO); 145300d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 145400d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 145500d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 145600d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 145700d0963fSdilpreet DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL); 145800d0963fSdilpreet unknown++; 145900d0963fSdilpreet } 146000d0963fSdilpreet 146100d0963fSdilpreet if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) { 146200d0963fSdilpreet for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) { 146300d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & 146400d0963fSdilpreet pci_bdg_err_tbl[i].reg_bit) { 146500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 146600d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, 146700d0963fSdilpreet pci_bdg_err_tbl[i].err_class); 146800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 146900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 147000d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 147100d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 147200d0963fSdilpreet DATA_TYPE_UINT16, 147300d0963fSdilpreet pci_bdg_regs->pci_bdg_ctrl, NULL); 1474ac4d633fSstephh PCI_FM_SEV_INC(pci_bdg_err_tbl[i].flags); 14758aec9182Sstephh if (pci_fme_bsp && (pci_fme_bsp->pci_bs_flags & 14768aec9182Sstephh PCI_BS_ADDR_VALID) && 14778aec9182Sstephh pci_fme_bsp->pci_bs_type == ACC_HANDLE && 147800d0963fSdilpreet pci_bdg_err_tbl[i].terr_class) 147900d0963fSdilpreet pci_target_enqueue(derr->fme_ena, 148000d0963fSdilpreet pci_bdg_err_tbl[i].terr_class, 148100d0963fSdilpreet PCI_ERROR_SUBCLASS, 14828aec9182Sstephh pci_fme_bsp->pci_bs_addr); 148300d0963fSdilpreet } 148400d0963fSdilpreet } 1485ac4d633fSstephh #if !defined(__sparc) 1486ac4d633fSstephh /* 1487ac4d633fSstephh * For x86, many drivers and even user-level code currently get 1488ac4d633fSstephh * away with accessing bad addresses, getting a UR and getting 1489ac4d633fSstephh * -1 returned. Unfortunately, we have no control over this, so 1490ac4d633fSstephh * we will have to treat all URs as nonfatal. Moreover, if the 1491ac4d633fSstephh * leaf driver is non-hardened, then we don't actually see the 1492ac4d633fSstephh * UR directly. All we see is a secondary bus master abort at 1493ac4d633fSstephh * the root complex - so it's this condition that we actually 1494ac4d633fSstephh * need to treat as nonfatal (providing no other unrelated nfe 1495ac4d633fSstephh * conditions have also been seen by the root complex). 1496ac4d633fSstephh */ 1497ac4d633fSstephh if ((erpt_p->pe_dflags & PCIEX_RC_DEV) && 1498ac4d633fSstephh (pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_R_MAST_AB) && 1499ac4d633fSstephh !(pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_S_PERROR)) { 1500ac4d633fSstephh pcie_error_regs_t *pcie_regs = 1501ac4d633fSstephh (pcie_error_regs_t *)erpt_p->pe_regs; 1502ac4d633fSstephh if ((pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) && 1503ac4d633fSstephh !(pcie_regs->pcie_err_status & 1504ac4d633fSstephh PCIE_DEVSTS_NFE_DETECTED)) 1505ac4d633fSstephh nonfatal++; 15062901c7f3Sstephh if (erpt_p->pe_dflags & PCIEX_ADV_DEV) { 15072901c7f3Sstephh pcie_adv_error_regs_t *pcie_adv_regs = 15082901c7f3Sstephh pcie_regs->pcie_adv_regs; 15092901c7f3Sstephh pcie_adv_rc_error_regs_t *pcie_rc_regs = 15102901c7f3Sstephh pcie_adv_regs->pcie_adv_rc_regs; 15112901c7f3Sstephh if ((pcie_adv_regs->pcie_adv_vflags & 15122901c7f3Sstephh PCIE_RC_ERR_STATUS_VALID) && 15132901c7f3Sstephh (pcie_rc_regs->pcie_rc_err_status & 15142901c7f3Sstephh PCIE_AER_RE_STS_NFE_MSGS_RCVD)) { 15152901c7f3Sstephh (void) snprintf(buf, FM_MAX_CLASS, 15162901c7f3Sstephh "%s.%s-%s", PCI_ERROR_SUBCLASS, 15172901c7f3Sstephh PCI_SEC_ERROR_SUBCLASS, PCI_MA); 15182901c7f3Sstephh ddi_fm_ereport_post(dip, buf, 15192901c7f3Sstephh derr->fme_ena, DDI_NOSLEEP, 15202901c7f3Sstephh FM_VERSION, DATA_TYPE_UINT8, 0, 15212901c7f3Sstephh PCI_SEC_CONFIG_STATUS, 15222901c7f3Sstephh DATA_TYPE_UINT16, 15232901c7f3Sstephh pci_bdg_regs->pci_bdg_sec_stat, 15242901c7f3Sstephh PCI_BCNTRL, DATA_TYPE_UINT16, 15252901c7f3Sstephh pci_bdg_regs->pci_bdg_ctrl, NULL); 15262901c7f3Sstephh } 15272901c7f3Sstephh } 1528ac4d633fSstephh } 1529ac4d633fSstephh #endif 153000d0963fSdilpreet } 153100d0963fSdilpreet 153200d0963fSdilpreet done: 153300d0963fSdilpreet /* 153400d0963fSdilpreet * Need to check for poke and cautious put. We already know peek 153500d0963fSdilpreet * and cautious get errors occurred (as we got a trap) and we know 153600d0963fSdilpreet * they are nonfatal. 153700d0963fSdilpreet */ 153800d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_EXPECTED) { 153900d0963fSdilpreet /* 154000d0963fSdilpreet * for cautious puts we treat all errors as nonfatal. Actually 154100d0963fSdilpreet * we set nonfatal for cautious gets as well - doesn't do any 154200d0963fSdilpreet * harm 154300d0963fSdilpreet */ 154400d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 154500d0963fSdilpreet PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR)) 154600d0963fSdilpreet nonfatal++; 154700d0963fSdilpreet } 154800d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_POKE) { 154900d0963fSdilpreet /* 155000d0963fSdilpreet * special case for pokes - we only consider master abort 155100d0963fSdilpreet * and target abort as nonfatal. Sserr with no master abort is 155200d0963fSdilpreet * fatal, but master/target abort can come in on separate 155300d0963fSdilpreet * instance, so return unknown and parent will determine if 155400d0963fSdilpreet * nonfatal (if another child returned nonfatal - ie master 155500d0963fSdilpreet * or target abort) or fatal otherwise 155600d0963fSdilpreet */ 155700d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 155800d0963fSdilpreet PCI_STAT_R_MAST_AB)) 155900d0963fSdilpreet nonfatal++; 156000d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR) 156100d0963fSdilpreet unknown++; 156200d0963fSdilpreet } 156300d0963fSdilpreet 156400d0963fSdilpreet /* 15658aec9182Sstephh * now check children below the bridge 156600d0963fSdilpreet */ 156700d0963fSdilpreet ret = ndi_fm_handler_dispatch(dip, NULL, derr); 156800d0963fSdilpreet PCI_FM_SEV_INC(ret); 156900d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 157000d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 157100d0963fSdilpreet } 157200d0963fSdilpreet 157300d0963fSdilpreet static int 157400d0963fSdilpreet pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 157500d0963fSdilpreet void *pe_regs) 157600d0963fSdilpreet { 157700d0963fSdilpreet pcix_error_regs_t *pcix_regs; 157800d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 157900d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs; 158000d0963fSdilpreet int bridge; 158100d0963fSdilpreet int i; 158200d0963fSdilpreet int ecc_phase; 158300d0963fSdilpreet int ecc_corr; 158400d0963fSdilpreet int sec_ue; 158500d0963fSdilpreet int sec_ce; 158600d0963fSdilpreet int fatal = 0; 158700d0963fSdilpreet int nonfatal = 0; 158800d0963fSdilpreet int unknown = 0; 158900d0963fSdilpreet int ok = 0; 159000d0963fSdilpreet char buf[FM_MAX_CLASS]; 159100d0963fSdilpreet 159200d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 159300d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 159400d0963fSdilpreet bridge = 1; 159500d0963fSdilpreet } else { 159600d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)pe_regs; 159700d0963fSdilpreet bridge = 0; 159800d0963fSdilpreet } 159900d0963fSdilpreet 160000d0963fSdilpreet for (i = 0; i < (bridge ? 2 : 1); i++) { 160100d0963fSdilpreet int ret = DDI_FM_OK; 160200d0963fSdilpreet pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] : 160300d0963fSdilpreet pcix_regs->pcix_ecc_regs; 160400d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) { 160500d0963fSdilpreet ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat & 160600d0963fSdilpreet PCI_PCIX_ECC_PHASE) >> 0x4; 160700d0963fSdilpreet ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat & 160800d0963fSdilpreet PCI_PCIX_ECC_CORR); 160900d0963fSdilpreet sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat & 161000d0963fSdilpreet PCI_PCIX_ECC_S_UE); 161100d0963fSdilpreet sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat & 161200d0963fSdilpreet PCI_PCIX_ECC_S_CE); 161300d0963fSdilpreet 161400d0963fSdilpreet switch (ecc_phase) { 161500d0963fSdilpreet case PCI_PCIX_ECC_PHASE_NOERR: 161600d0963fSdilpreet break; 161700d0963fSdilpreet case PCI_PCIX_ECC_PHASE_FADDR: 161800d0963fSdilpreet case PCI_PCIX_ECC_PHASE_SADDR: 1619ac4d633fSstephh PCI_FM_SEV_INC(ecc_corr ? DDI_FM_OK : 162000d0963fSdilpreet DDI_FM_FATAL); 162100d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 162200d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 162300d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 162400d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ADDR : 162500d0963fSdilpreet PCIX_ECC_UE_ADDR); 162600d0963fSdilpreet break; 162700d0963fSdilpreet case PCI_PCIX_ECC_PHASE_ATTR: 162800d0963fSdilpreet PCI_FM_SEV_INC(ecc_corr ? 1629ac4d633fSstephh DDI_FM_OK : DDI_FM_FATAL); 163000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 163100d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 163200d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 163300d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ATTR : 163400d0963fSdilpreet PCIX_ECC_UE_ATTR); 163500d0963fSdilpreet break; 163600d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA32: 163700d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA64: 163800d0963fSdilpreet if (ecc_corr) 1639ac4d633fSstephh ret = DDI_FM_OK; 16408aec9182Sstephh else { 16418aec9182Sstephh int type; 16428aec9182Sstephh pci_error_regs_t *pci_regs = 16438aec9182Sstephh erpt_p->pe_pci_regs; 16448aec9182Sstephh 16458aec9182Sstephh if (i) { 16468aec9182Sstephh if (pci_regs->pci_bdg_regs-> 16478aec9182Sstephh pci_bdg_sec_stat & 16488aec9182Sstephh PCI_STAT_S_PERROR) 16498aec9182Sstephh type = ACC_HANDLE; 165000d0963fSdilpreet else 16518aec9182Sstephh type = DMA_HANDLE; 16528aec9182Sstephh } else { 16538aec9182Sstephh if (pci_regs->pci_err_status & 16548aec9182Sstephh PCI_STAT_S_PERROR) 16558aec9182Sstephh type = DMA_HANDLE; 16568aec9182Sstephh else 16578aec9182Sstephh type = ACC_HANDLE; 16588aec9182Sstephh } 165900d0963fSdilpreet ret = pcix_check_addr(dip, derr, 16608aec9182Sstephh pcix_ecc_regs, type); 16618aec9182Sstephh } 166200d0963fSdilpreet PCI_FM_SEV_INC(ret); 166300d0963fSdilpreet 166400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 166500d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 166600d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 166700d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_DATA : 166800d0963fSdilpreet PCIX_ECC_UE_DATA); 166900d0963fSdilpreet break; 167000d0963fSdilpreet } 167100d0963fSdilpreet if (ecc_phase) 167200d0963fSdilpreet if (bridge) 167300d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 167400d0963fSdilpreet derr->fme_ena, 167500d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 167600d0963fSdilpreet DATA_TYPE_UINT8, 0, 167700d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 167800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 167900d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 168000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 168100d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 168200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 168300d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 168400d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 168500d0963fSdilpreet else 168600d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 168700d0963fSdilpreet derr->fme_ena, 168800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 168900d0963fSdilpreet DATA_TYPE_UINT8, 0, 169000d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 169100d0963fSdilpreet pcix_regs->pcix_command, 169200d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 169300d0963fSdilpreet pcix_regs->pcix_status, 169400d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 169500d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 169600d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 169700d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 169800d0963fSdilpreet if (sec_ce || sec_ue) { 169900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 170000d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 170100d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 170200d0963fSdilpreet sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE); 170300d0963fSdilpreet if (bridge) 170400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 170500d0963fSdilpreet derr->fme_ena, 170600d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 170700d0963fSdilpreet DATA_TYPE_UINT8, 0, 170800d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 170900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 171000d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 171100d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 171200d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 171300d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 171400d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 171500d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 171600d0963fSdilpreet else 171700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 171800d0963fSdilpreet derr->fme_ena, 171900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 172000d0963fSdilpreet DATA_TYPE_UINT8, 0, 172100d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 172200d0963fSdilpreet pcix_regs->pcix_command, 172300d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 172400d0963fSdilpreet pcix_regs->pcix_status, 172500d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 172600d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 172700d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 172800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 172900d0963fSdilpreet PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL : 1730ac4d633fSstephh DDI_FM_OK); 173100d0963fSdilpreet } 173200d0963fSdilpreet } 173300d0963fSdilpreet } 173400d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 173500d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 173600d0963fSdilpreet } 173700d0963fSdilpreet 173800d0963fSdilpreet static int 173900d0963fSdilpreet pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 174000d0963fSdilpreet void *pe_regs) 174100d0963fSdilpreet { 174200d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 174300d0963fSdilpreet int fatal = 0; 174400d0963fSdilpreet int nonfatal = 0; 174500d0963fSdilpreet int unknown = 0; 174600d0963fSdilpreet int ok = 0; 174700d0963fSdilpreet char buf[FM_MAX_CLASS]; 174800d0963fSdilpreet int i; 174900d0963fSdilpreet 175000d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) { 175100d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 175200d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_stat & 175300d0963fSdilpreet pcix_err_tbl[i].reg_bit)) { 175400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 175500d0963fSdilpreet PCIX_ERROR_SUBCLASS, 175600d0963fSdilpreet pcix_err_tbl[i].err_class); 175700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 175800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 175900d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 176000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 176100d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 176200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 176300d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 176400d0963fSdilpreet } 176500d0963fSdilpreet } 176600d0963fSdilpreet } 176700d0963fSdilpreet 176800d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) { 176900d0963fSdilpreet for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) { 177000d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_sec_stat & 177100d0963fSdilpreet pcix_sec_err_tbl[i].reg_bit)) { 177200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s", 177300d0963fSdilpreet PCIX_ERROR_SUBCLASS, 177400d0963fSdilpreet PCIX_SEC_ERROR_SUBCLASS, 177500d0963fSdilpreet pcix_sec_err_tbl[i].err_class); 177600d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 177700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 177800d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 177900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 178000d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 178100d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 178200d0963fSdilpreet PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags); 178300d0963fSdilpreet } 178400d0963fSdilpreet } 178500d0963fSdilpreet } 178600d0963fSdilpreet 178700d0963fSdilpreet /* Log/Handle ECC errors */ 178800d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 178900d0963fSdilpreet int ret; 179000d0963fSdilpreet 179100d0963fSdilpreet ret = pcix_ecc_error_report(dip, derr, erpt_p, 179200d0963fSdilpreet (void *)pcix_bdg_regs); 179300d0963fSdilpreet PCI_FM_SEV_INC(ret); 179400d0963fSdilpreet } 179500d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 179600d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 179700d0963fSdilpreet } 179800d0963fSdilpreet 179900d0963fSdilpreet static int 180000d0963fSdilpreet pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 180100d0963fSdilpreet { 180200d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 180300d0963fSdilpreet int fatal = 0; 180400d0963fSdilpreet int nonfatal = 0; 180500d0963fSdilpreet int unknown = 0; 180600d0963fSdilpreet int ok = 0; 180700d0963fSdilpreet char buf[FM_MAX_CLASS]; 180800d0963fSdilpreet int i; 180900d0963fSdilpreet 181000d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) { 181100d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 181200d0963fSdilpreet if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit)) 181300d0963fSdilpreet continue; 181400d0963fSdilpreet 181500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 181600d0963fSdilpreet PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class); 181700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 181800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 181900d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 182000d0963fSdilpreet pcix_regs->pcix_command, PCIX_STATUS, 182100d0963fSdilpreet DATA_TYPE_UINT32, pcix_regs->pcix_status, 182200d0963fSdilpreet NULL); 182300d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 182400d0963fSdilpreet } 182500d0963fSdilpreet } 182600d0963fSdilpreet /* Log/Handle ECC errors */ 182700d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 182800d0963fSdilpreet int ret = pcix_ecc_error_report(dip, derr, erpt_p, 182900d0963fSdilpreet (void *)pcix_regs); 183000d0963fSdilpreet PCI_FM_SEV_INC(ret); 183100d0963fSdilpreet } 183200d0963fSdilpreet 183300d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 183400d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 183500d0963fSdilpreet } 183600d0963fSdilpreet 183700d0963fSdilpreet static int 183800d0963fSdilpreet pcie_rc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 183900d0963fSdilpreet void *pe_regs) 184000d0963fSdilpreet { 184100d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs = (pcie_adv_error_regs_t *)pe_regs; 184200d0963fSdilpreet int fatal = 0; 184300d0963fSdilpreet int nonfatal = 0; 184400d0963fSdilpreet int unknown = 0; 184500d0963fSdilpreet char buf[FM_MAX_CLASS]; 184600d0963fSdilpreet 184700d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) { 184800d0963fSdilpreet pcie_adv_rc_error_regs_t *pcie_rc_regs = 184900d0963fSdilpreet pcie_adv_regs->pcie_adv_rc_regs; 185000d0963fSdilpreet int ce, ue, mult_ce, mult_ue, first_ue_fatal, nfe, fe; 185100d0963fSdilpreet 185200d0963fSdilpreet ce = pcie_rc_regs->pcie_rc_err_status & 185300d0963fSdilpreet PCIE_AER_RE_STS_CE_RCVD; 185400d0963fSdilpreet ue = pcie_rc_regs->pcie_rc_err_status & 185500d0963fSdilpreet PCIE_AER_RE_STS_FE_NFE_RCVD; 185600d0963fSdilpreet mult_ce = pcie_rc_regs->pcie_rc_err_status & 185700d0963fSdilpreet PCIE_AER_RE_STS_MUL_CE_RCVD; 185800d0963fSdilpreet mult_ue = pcie_rc_regs->pcie_rc_err_status & 185900d0963fSdilpreet PCIE_AER_RE_STS_MUL_FE_NFE_RCVD; 186000d0963fSdilpreet first_ue_fatal = pcie_rc_regs->pcie_rc_err_status & 186100d0963fSdilpreet PCIE_AER_RE_STS_FIRST_UC_FATAL; 186200d0963fSdilpreet nfe = pcie_rc_regs->pcie_rc_err_status & 186300d0963fSdilpreet PCIE_AER_RE_STS_NFE_MSGS_RCVD; 186400d0963fSdilpreet fe = pcie_rc_regs->pcie_rc_err_status & 186500d0963fSdilpreet PCIE_AER_RE_STS_FE_MSGS_RCVD; 186600d0963fSdilpreet /* 186700d0963fSdilpreet * log fatal/nonfatal/corrected messages 186800d0963fSdilpreet * recieved by root complex 186900d0963fSdilpreet */ 187000d0963fSdilpreet if (ue && fe) 187100d0963fSdilpreet fatal++; 187200d0963fSdilpreet 187300d0963fSdilpreet if (fe && first_ue_fatal) { 187400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 187500d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_FE_MSG); 187600d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 187700d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 187800d0963fSdilpreet } 187900d0963fSdilpreet if (nfe && !first_ue_fatal) { 188000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 188100d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_NFE_MSG); 188200d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 188300d0963fSdilpreet PCIEX_TYPE_RC_UE_MSG); 188400d0963fSdilpreet } 188500d0963fSdilpreet if (ce) { 188600d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 188700d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_CE_MSG); 188800d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 188900d0963fSdilpreet PCIEX_TYPE_RC_CE_MSG); 189000d0963fSdilpreet } 189100d0963fSdilpreet if (mult_ce) { 189200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 189300d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MCE_MSG); 189400d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 189500d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 189600d0963fSdilpreet } 189700d0963fSdilpreet if (mult_ue) { 189800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 189900d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MUE_MSG); 190000d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 190100d0963fSdilpreet PCIEX_TYPE_RC_MULT_MSG); 190200d0963fSdilpreet } 190300d0963fSdilpreet } 190400d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 190500d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 190600d0963fSdilpreet } 190700d0963fSdilpreet 190800d0963fSdilpreet static int 190900d0963fSdilpreet pcie_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 191000d0963fSdilpreet { 191100d0963fSdilpreet int fatal = 0; 191200d0963fSdilpreet int nonfatal = 0; 191300d0963fSdilpreet int unknown = 0; 191400d0963fSdilpreet int ok = 0; 19158aec9182Sstephh int type; 191600d0963fSdilpreet char buf[FM_MAX_CLASS]; 191700d0963fSdilpreet int i; 191800d0963fSdilpreet pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs; 191900d0963fSdilpreet pcie_adv_error_regs_t *pcie_adv_regs; 192000d0963fSdilpreet pcie_adv_bdg_error_regs_t *pcie_bdg_regs; 192100d0963fSdilpreet 192200d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && 192300d0963fSdilpreet (erpt_p->pe_dflags & PCIX_DEV)) { 192400d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, erpt_p, 192500d0963fSdilpreet (void *)pcie_regs->pcix_bdg_regs); 192600d0963fSdilpreet PCI_FM_SEV_INC(ret); 192700d0963fSdilpreet } 192800d0963fSdilpreet 192900d0963fSdilpreet if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) { 193000d0963fSdilpreet if (!(pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID)) 193100d0963fSdilpreet goto done; 19328aec9182Sstephh #if !defined(__sparc) 19338aec9182Sstephh /* 19345952c218Sanish * On x86 ignore UR on non-RBER leaf devices, pciex-pci 19355952c218Sanish * bridges and switches. 19368aec9182Sstephh */ 19378aec9182Sstephh if ((pcie_regs->pcie_err_status & PCIE_DEVSTS_UR_DETECTED) && 19388aec9182Sstephh !(pcie_regs->pcie_err_status & PCIE_DEVSTS_FE_DETECTED) && 19395952c218Sanish ((erpt_p->pe_dflags & (PCIEX_2PCI_DEV|PCIEX_SWITCH_DEV)) || 19408aec9182Sstephh !(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) && 19418aec9182Sstephh !(pcie_regs->pcie_dev_cap & PCIE_DEVCAP_ROLE_BASED_ERR_REP)) 19428aec9182Sstephh goto done; 19438aec9182Sstephh #endif 194400d0963fSdilpreet for (i = 0; pciex_nadv_err_tbl[i].err_class != NULL; i++) { 194500d0963fSdilpreet if (!(pcie_regs->pcie_err_status & 194600d0963fSdilpreet pciex_nadv_err_tbl[i].reg_bit)) 194700d0963fSdilpreet continue; 194800d0963fSdilpreet 194900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 195000d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 195100d0963fSdilpreet pciex_nadv_err_tbl[i].err_class); 195200d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 195300d0963fSdilpreet PCIEX_TYPE_GEN); 195400d0963fSdilpreet PCI_FM_SEV_INC(pciex_nadv_err_tbl[i].flags); 195500d0963fSdilpreet } 195600d0963fSdilpreet goto done; 195700d0963fSdilpreet } 195800d0963fSdilpreet 195900d0963fSdilpreet pcie_adv_regs = pcie_regs->pcie_adv_regs; 196000d0963fSdilpreet 196100d0963fSdilpreet /* 196200d0963fSdilpreet * Log PCI Express uncorrectable errors 196300d0963fSdilpreet */ 196400d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) { 196500d0963fSdilpreet for (i = 0; pciex_ue_err_tbl[i].err_class != NULL; i++) { 196600d0963fSdilpreet if (!(pcie_adv_regs->pcie_ue_status & 196700d0963fSdilpreet pciex_ue_err_tbl[i].reg_bit)) 196800d0963fSdilpreet continue; 196900d0963fSdilpreet 197000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 197100d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 197200d0963fSdilpreet pciex_ue_err_tbl[i].err_class); 197300d0963fSdilpreet 19748aec9182Sstephh /* 19758aec9182Sstephh * First check for advisary nonfatal conditions 19768aec9182Sstephh * - hardware endpoint successfully retrying a cto 19778aec9182Sstephh * - hardware endpoint receiving poisoned tlp and 19788aec9182Sstephh * dealing with it itself (but not if root complex) 19798aec9182Sstephh * If the device has declared these as correctable 19808aec9182Sstephh * errors then treat them as such. 19818aec9182Sstephh */ 19828aec9182Sstephh if ((pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_TO || 19838aec9182Sstephh (pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_PTLP && 19848aec9182Sstephh !(erpt_p->pe_dflags & PCIEX_RC_DEV))) && 19858aec9182Sstephh (pcie_regs->pcie_err_status & 19868aec9182Sstephh PCIE_DEVSTS_CE_DETECTED) && 19878aec9182Sstephh !(pcie_regs->pcie_err_status & 19888aec9182Sstephh PCIE_DEVSTS_NFE_DETECTED)) { 19898aec9182Sstephh pcie_ereport_post(dip, derr, erpt_p, buf, 19908aec9182Sstephh PCIEX_TYPE_UE); 19918aec9182Sstephh continue; 19928aec9182Sstephh } 19938aec9182Sstephh 19948aec9182Sstephh #if !defined(__sparc) 19958aec9182Sstephh /* 19968aec9182Sstephh * On x86 for leaf devices and pciex-pci bridges, 19978aec9182Sstephh * ignore UR on non-RBER devices or on RBER devices when 19988aec9182Sstephh * advisory nonfatal. 19998aec9182Sstephh */ 20008aec9182Sstephh if (pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_UR && 20015952c218Sanish ((erpt_p->pe_dflags & 20025952c218Sanish (PCIEX_2PCI_DEV|PCIEX_SWITCH_DEV)) || 20038aec9182Sstephh !(erpt_p->pe_dflags & PCI_BRIDGE_DEV))) { 20048aec9182Sstephh if (!(pcie_regs->pcie_dev_cap & 20058aec9182Sstephh PCIE_DEVCAP_ROLE_BASED_ERR_REP)) 20068aec9182Sstephh continue; 20072901c7f3Sstephh if (!(pcie_regs->pcie_err_status & 20088aec9182Sstephh PCIE_DEVSTS_NFE_DETECTED)) 20098aec9182Sstephh continue; 20108aec9182Sstephh } 20118aec9182Sstephh #endif 201200d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 20138aec9182Sstephh /* 20148aec9182Sstephh * Now try and look up handle if 20158aec9182Sstephh * - error bit is among PCIE_AER_UCE_LOG_BITS, and 20168aec9182Sstephh * - no other PCIE_AER_UCE_LOG_BITS are set, and 20178aec9182Sstephh * - error bit is not masked, and 20188aec9182Sstephh * - flag is DDI_FM_UNKNOWN 20198aec9182Sstephh */ 202000d0963fSdilpreet if ((pcie_adv_regs->pcie_ue_status & 20218aec9182Sstephh pcie_aer_uce_log_bits) == 20228aec9182Sstephh pciex_ue_err_tbl[i].reg_bit && 20238aec9182Sstephh !(pciex_ue_err_tbl[i].reg_bit & 20248aec9182Sstephh pcie_adv_regs->pcie_ue_mask) && 20258aec9182Sstephh pciex_ue_err_tbl[i].flags == DDI_FM_UNKNOWN) 20268aec9182Sstephh pcie_check_addr(dip, derr, erpt_p); 20278aec9182Sstephh 202800d0963fSdilpreet PCI_FM_SEV_INC(pciex_ue_err_tbl[i].flags); 202900d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 203000d0963fSdilpreet PCIEX_TYPE_UE); 203100d0963fSdilpreet } 203200d0963fSdilpreet } 203300d0963fSdilpreet 203400d0963fSdilpreet /* 203500d0963fSdilpreet * Log PCI Express correctable errors 203600d0963fSdilpreet */ 203700d0963fSdilpreet if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) { 203800d0963fSdilpreet for (i = 0; pciex_ce_err_tbl[i].err_class != NULL; i++) { 203900d0963fSdilpreet if (!(pcie_adv_regs->pcie_ce_status & 204000d0963fSdilpreet pciex_ce_err_tbl[i].reg_bit)) 204100d0963fSdilpreet continue; 204200d0963fSdilpreet 204300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 204400d0963fSdilpreet "%s.%s", PCIEX_ERROR_SUBCLASS, 204500d0963fSdilpreet pciex_ce_err_tbl[i].err_class); 204600d0963fSdilpreet pcie_ereport_post(dip, derr, erpt_p, buf, 204700d0963fSdilpreet PCIEX_TYPE_CE); 204800d0963fSdilpreet } 204900d0963fSdilpreet } 205000d0963fSdilpreet 205100d0963fSdilpreet if (!(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) 205200d0963fSdilpreet goto done; 205300d0963fSdilpreet 205400d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_RC_DEV) { 205500d0963fSdilpreet int ret = pcie_rc_error_report(dip, derr, erpt_p, 205600d0963fSdilpreet (void *)pcie_adv_regs); 205700d0963fSdilpreet PCI_FM_SEV_INC(ret); 205800d0963fSdilpreet } 205900d0963fSdilpreet 206000d0963fSdilpreet if (!((erpt_p->pe_dflags & PCIEX_2PCI_DEV) && 206100d0963fSdilpreet (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID))) 206200d0963fSdilpreet goto done; 206300d0963fSdilpreet 206400d0963fSdilpreet pcie_bdg_regs = pcie_adv_regs->pcie_adv_bdg_regs; 206500d0963fSdilpreet 206600d0963fSdilpreet for (i = 0; pcie_sue_err_tbl[i].err_class != NULL; i++) { 206700d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 206800d0963fSdilpreet pcie_sue_err_tbl[i].reg_bit)) { 206900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 207000d0963fSdilpreet PCIEX_ERROR_SUBCLASS, 207100d0963fSdilpreet pcie_sue_err_tbl[i].err_class); 207200d0963fSdilpreet 207300d0963fSdilpreet if ((pcie_bdg_regs->pcie_sue_status & 20740c64a9b4Sanish pcie_aer_suce_log_bits) != 20758aec9182Sstephh pcie_sue_err_tbl[i].reg_bit || 20768aec9182Sstephh pcie_sue_err_tbl[i].flags != DDI_FM_UNKNOWN) { 207700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 207800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 207900d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 208000d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 208100d0963fSdilpreet #ifdef DEBUG 208200d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 208300d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 208400d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 208500d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 208600d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 208700d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 208800d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 208900d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 209000d0963fSdilpreet #endif 209100d0963fSdilpreet NULL); 209200d0963fSdilpreet } else { 209300d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf = 0; 20948aec9182Sstephh switch (pcie_sue_err_tbl[i].reg_bit) { 20958aec9182Sstephh case PCIE_AER_SUCE_RCVD_TA: 20968aec9182Sstephh case PCIE_AER_SUCE_RCVD_MA: 20978aec9182Sstephh case PCIE_AER_SUCE_USC_ERR: 20988aec9182Sstephh type = ACC_HANDLE; 20998aec9182Sstephh break; 21008aec9182Sstephh case PCIE_AER_SUCE_TA_ON_SC: 21018aec9182Sstephh case PCIE_AER_SUCE_MA_ON_SC: 21028aec9182Sstephh type = DMA_HANDLE; 21038aec9182Sstephh break; 21048aec9182Sstephh case PCIE_AER_SUCE_UC_DATA_ERR: 21058aec9182Sstephh case PCIE_AER_SUCE_PERR_ASSERT: 21068aec9182Sstephh if (erpt_p->pe_pci_regs->pci_bdg_regs-> 21078aec9182Sstephh pci_bdg_sec_stat & 21088aec9182Sstephh PCI_STAT_S_PERROR) 21098aec9182Sstephh type = ACC_HANDLE; 21108aec9182Sstephh else 21118aec9182Sstephh type = DMA_HANDLE; 21128aec9182Sstephh break; 21138aec9182Sstephh } 21148aec9182Sstephh pcie_pci_check_addr(dip, derr, erpt_p, type); 211500d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 211600d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 211700d0963fSdilpreet PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32, 211800d0963fSdilpreet pcie_bdg_regs->pcie_sue_status, 211900d0963fSdilpreet PCIEX_SRC_ID, DATA_TYPE_UINT16, 212000d0963fSdilpreet pcie_adv_regs->pcie_adv_bdf, 212100d0963fSdilpreet PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE, 212200d0963fSdilpreet (pcie_adv_regs->pcie_adv_bdf != NULL) ? 212300d0963fSdilpreet 1 : NULL, 212400d0963fSdilpreet #ifdef DEBUG 212500d0963fSdilpreet PCIEX_SUE_HDR0, DATA_TYPE_UINT32, 212600d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr0, 212700d0963fSdilpreet PCIEX_SUE_HDR1, DATA_TYPE_UINT32, 212800d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[0], 212900d0963fSdilpreet PCIEX_SUE_HDR2, DATA_TYPE_UINT32, 213000d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[1], 213100d0963fSdilpreet PCIEX_SUE_HDR3, DATA_TYPE_UINT32, 213200d0963fSdilpreet pcie_bdg_regs->pcie_sue_hdr[2], 213300d0963fSdilpreet #endif 213400d0963fSdilpreet NULL); 213500d0963fSdilpreet } 21368aec9182Sstephh PCI_FM_SEV_INC(pcie_sue_err_tbl[i].flags); 213700d0963fSdilpreet } 213800d0963fSdilpreet } 213900d0963fSdilpreet done: 214000d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 214100d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 214200d0963fSdilpreet } 214300d0963fSdilpreet 214400d0963fSdilpreet static void 214500d0963fSdilpreet pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 214600d0963fSdilpreet { 214700d0963fSdilpreet int fatal = 0; 214800d0963fSdilpreet int nonfatal = 0; 214900d0963fSdilpreet int unknown = 0; 215000d0963fSdilpreet int ok = 0; 215100d0963fSdilpreet char buf[FM_MAX_CLASS]; 215200d0963fSdilpreet int i; 215300d0963fSdilpreet 215400d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 215500d0963fSdilpreet /* 215600d0963fSdilpreet * Log generic PCI errors. 215700d0963fSdilpreet */ 215800d0963fSdilpreet for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 215900d0963fSdilpreet if (!(erpt_p->pe_pci_regs->pci_err_status & 216000d0963fSdilpreet pci_err_tbl[i].reg_bit) || 216100d0963fSdilpreet !(erpt_p->pe_pci_regs->pci_vflags & 216200d0963fSdilpreet PCI_ERR_STATUS_VALID)) 216300d0963fSdilpreet continue; 216400d0963fSdilpreet /* 216500d0963fSdilpreet * Generate an ereport for this error bit. 216600d0963fSdilpreet */ 216700d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 216800d0963fSdilpreet PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class); 216900d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 217000d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 217100d0963fSdilpreet PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 217200d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status, 217300d0963fSdilpreet PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 217400d0963fSdilpreet erpt_p->pe_pci_regs->pci_cfg_comm, NULL); 217500d0963fSdilpreet 2176ac4d633fSstephh /* 2177ac4d633fSstephh * The meaning of SERR is different for PCIEX (just 2178ac4d633fSstephh * implies a message has been sent) so we don't want to 2179ac4d633fSstephh * treat that one as fatal. 2180ac4d633fSstephh */ 2181ac4d633fSstephh if ((erpt_p->pe_dflags & PCIEX_DEV) && 2182ac4d633fSstephh pci_err_tbl[i].reg_bit == PCI_STAT_S_SYSERR) { 2183ac4d633fSstephh unknown++; 2184ac4d633fSstephh } else { 218500d0963fSdilpreet PCI_FM_SEV_INC(pci_err_tbl[i].flags); 218600d0963fSdilpreet } 2187ac4d633fSstephh } 218800d0963fSdilpreet if (erpt_p->pe_dflags & PCIEX_DEV) { 218900d0963fSdilpreet int ret = pcie_error_report(dip, derr, erpt_p); 219000d0963fSdilpreet PCI_FM_SEV_INC(ret); 219100d0963fSdilpreet } else if (erpt_p->pe_dflags & PCIX_DEV) { 219200d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 219300d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, 219400d0963fSdilpreet erpt_p, erpt_p->pe_regs); 219500d0963fSdilpreet PCI_FM_SEV_INC(ret); 219600d0963fSdilpreet } else { 219700d0963fSdilpreet int ret = pcix_error_report(dip, derr, erpt_p); 219800d0963fSdilpreet PCI_FM_SEV_INC(ret); 219900d0963fSdilpreet } 220000d0963fSdilpreet } 220100d0963fSdilpreet } 220200d0963fSdilpreet 220300d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) { 220400d0963fSdilpreet int ret = pci_bdg_error_report(dip, derr, erpt_p); 220500d0963fSdilpreet PCI_FM_SEV_INC(ret); 220600d0963fSdilpreet } 220700d0963fSdilpreet 22088aec9182Sstephh if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 22098aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp; 22108aec9182Sstephh int ret = DDI_FM_UNKNOWN; 22118aec9182Sstephh 22128aec9182Sstephh pci_fme_bsp = (pci_fme_bus_specific_t *)derr->fme_bus_specific; 22138aec9182Sstephh if (pci_fme_bsp->pci_bs_flags & PCI_BS_ADDR_VALID) { 22148aec9182Sstephh ret = ndi_fmc_entry_error(dip, 22158aec9182Sstephh pci_fme_bsp->pci_bs_type, derr, 22168aec9182Sstephh (void *)&pci_fme_bsp->pci_bs_addr); 22178aec9182Sstephh PCI_FM_SEV_INC(ret); 22188aec9182Sstephh } 22198aec9182Sstephh /* 22208aec9182Sstephh * If we didn't find the handle using an addr, try using bdf. 22218aec9182Sstephh * Note we don't do this where the bdf is for a 22228aec9182Sstephh * device behind a pciex/pci bridge as the bridge may have 22238aec9182Sstephh * fabricated the bdf. 22248aec9182Sstephh */ 22258aec9182Sstephh if (ret == DDI_FM_UNKNOWN && 22268aec9182Sstephh (pci_fme_bsp->pci_bs_flags & PCI_BS_BDF_VALID) && 22278aec9182Sstephh pci_fme_bsp->pci_bs_bdf == erpt_p->pe_bdf && 22288aec9182Sstephh (erpt_p->pe_dflags & PCIEX_DEV) && 22298aec9182Sstephh !(erpt_p->pe_dflags & PCIEX_2PCI_DEV)) { 22308aec9182Sstephh ret = ndi_fmc_entry_error_all(dip, 22318aec9182Sstephh pci_fme_bsp->pci_bs_type, derr); 22328aec9182Sstephh PCI_FM_SEV_INC(ret); 22338aec9182Sstephh } 22348aec9182Sstephh } 22358aec9182Sstephh 223600d0963fSdilpreet derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 223700d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 223800d0963fSdilpreet } 223900d0963fSdilpreet 224000d0963fSdilpreet void 224100d0963fSdilpreet pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status) 224200d0963fSdilpreet { 224300d0963fSdilpreet struct i_ddi_fmhdl *fmhdl; 224400d0963fSdilpreet pci_erpt_t *erpt_p; 22458aec9182Sstephh ddi_fm_error_t de; 22468aec9182Sstephh pci_fme_bus_specific_t pci_fme_bs; 224700d0963fSdilpreet 2248*eae2e508Skrishnae /* 2249*eae2e508Skrishnae * On PCI Express systems, all error handling and ereport are done via 2250*eae2e508Skrishnae * the PCIe misc module. This function is a no-op for PCIe Systems. In 2251*eae2e508Skrishnae * order to tell if a system is a PCI or PCIe system, check that the 2252*eae2e508Skrishnae * bus_private_data exists. If it exists, this is a PCIe system. 2253*eae2e508Skrishnae */ 2254*eae2e508Skrishnae if (ndi_get_bus_private(dip, B_TRUE)) { 2255*eae2e508Skrishnae derr->fme_status = DDI_FM_OK; 2256*eae2e508Skrishnae if (xx_status != NULL) 2257*eae2e508Skrishnae *xx_status = 0x0; 2258*eae2e508Skrishnae 2259*eae2e508Skrishnae return; 2260*eae2e508Skrishnae } 2261*eae2e508Skrishnae 226200d0963fSdilpreet fmhdl = DEVI(dip)->devi_fmhdl; 226300d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 226400d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 226500d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 226600d0963fSdilpreet return; 226700d0963fSdilpreet } 226800d0963fSdilpreet 22698aec9182Sstephh /* 22708aec9182Sstephh * copy in the ddi_fm_error_t structure in case it's VER0 22718aec9182Sstephh */ 22728aec9182Sstephh de.fme_version = derr->fme_version; 22738aec9182Sstephh de.fme_status = derr->fme_status; 22748aec9182Sstephh de.fme_flag = derr->fme_flag; 22758aec9182Sstephh de.fme_ena = derr->fme_ena; 22768aec9182Sstephh de.fme_acc_handle = derr->fme_acc_handle; 22778aec9182Sstephh de.fme_dma_handle = derr->fme_dma_handle; 22788aec9182Sstephh de.fme_bus_specific = derr->fme_bus_specific; 22798aec9182Sstephh if (derr->fme_version >= DDI_FME_VER1) 22808aec9182Sstephh de.fme_bus_type = derr->fme_bus_type; 22818aec9182Sstephh else 22828aec9182Sstephh de.fme_bus_type = DDI_FME_BUS_TYPE_DFLT; 22838aec9182Sstephh if (de.fme_bus_type == DDI_FME_BUS_TYPE_DFLT) { 22848aec9182Sstephh /* 22858aec9182Sstephh * if this is the first pci device we've found convert 22868aec9182Sstephh * fme_bus_specific to DDI_FME_BUS_TYPE_PCI 22878aec9182Sstephh */ 22888aec9182Sstephh bzero(&pci_fme_bs, sizeof (pci_fme_bs)); 22898aec9182Sstephh if (de.fme_bus_specific) { 22908aec9182Sstephh /* 22918aec9182Sstephh * the cpu passed us an addr - this can be used to look 22928aec9182Sstephh * up an access handle 22938aec9182Sstephh */ 22948aec9182Sstephh pci_fme_bs.pci_bs_addr = (uintptr_t)de.fme_bus_specific; 22958aec9182Sstephh pci_fme_bs.pci_bs_type = ACC_HANDLE; 22968aec9182Sstephh pci_fme_bs.pci_bs_flags |= PCI_BS_ADDR_VALID; 22978aec9182Sstephh } 22988aec9182Sstephh de.fme_bus_specific = (void *)&pci_fme_bs; 22998aec9182Sstephh de.fme_bus_type = DDI_FME_BUS_TYPE_PCI; 23008aec9182Sstephh } 23018aec9182Sstephh 230200d0963fSdilpreet ASSERT(fmhdl); 230300d0963fSdilpreet 23048aec9182Sstephh if (de.fme_ena == NULL) 23058aec9182Sstephh de.fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 230600d0963fSdilpreet 230700d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 2308ac4d633fSstephh if (erpt_p == NULL) 230900d0963fSdilpreet return; 231000d0963fSdilpreet 23118aec9182Sstephh pci_regs_gather(dip, erpt_p, de.fme_flag); 23128aec9182Sstephh pci_error_report(dip, &de, erpt_p); 231300d0963fSdilpreet pci_regs_clear(erpt_p); 231400d0963fSdilpreet 23158aec9182Sstephh derr->fme_status = de.fme_status; 23168aec9182Sstephh derr->fme_ena = de.fme_ena; 23178aec9182Sstephh derr->fme_acc_handle = de.fme_acc_handle; 23188aec9182Sstephh derr->fme_dma_handle = de.fme_dma_handle; 231900d0963fSdilpreet if (xx_status != NULL) 232000d0963fSdilpreet *xx_status = erpt_p->pe_pci_regs->pci_err_status; 232100d0963fSdilpreet } 232200d0963fSdilpreet 232300d0963fSdilpreet /* 232400d0963fSdilpreet * private version of walk_devs() that can be used during panic. No 232500d0963fSdilpreet * sleeping or locking required. 232600d0963fSdilpreet */ 232700d0963fSdilpreet static int 232800d0963fSdilpreet pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg) 232900d0963fSdilpreet { 233000d0963fSdilpreet while (dip) { 233100d0963fSdilpreet switch ((*f)(dip, arg)) { 233200d0963fSdilpreet case DDI_WALK_TERMINATE: 233300d0963fSdilpreet return (DDI_WALK_TERMINATE); 233400d0963fSdilpreet case DDI_WALK_CONTINUE: 233500d0963fSdilpreet if (pci_fm_walk_devs(ddi_get_child(dip), f, 233600d0963fSdilpreet arg) == DDI_WALK_TERMINATE) 233700d0963fSdilpreet return (DDI_WALK_TERMINATE); 233800d0963fSdilpreet break; 233900d0963fSdilpreet case DDI_WALK_PRUNECHILD: 234000d0963fSdilpreet break; 234100d0963fSdilpreet } 234200d0963fSdilpreet dip = ddi_get_next_sibling(dip); 234300d0963fSdilpreet } 234400d0963fSdilpreet return (DDI_WALK_CONTINUE); 234500d0963fSdilpreet } 234600d0963fSdilpreet 234700d0963fSdilpreet /* 234800d0963fSdilpreet * need special version of ddi_fm_ereport_post() as the leaf driver may 234900d0963fSdilpreet * not be hardened. 235000d0963fSdilpreet */ 235100d0963fSdilpreet static void 235200d0963fSdilpreet pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena, 235300d0963fSdilpreet uint8_t version, ...) 235400d0963fSdilpreet { 235500d0963fSdilpreet char *name; 235600d0963fSdilpreet char device_path[MAXPATHLEN]; 235700d0963fSdilpreet char ddi_error_class[FM_MAX_CLASS]; 235800d0963fSdilpreet nvlist_t *ereport, *detector; 235900d0963fSdilpreet nv_alloc_t *nva; 236000d0963fSdilpreet errorq_elem_t *eqep; 236100d0963fSdilpreet va_list ap; 236200d0963fSdilpreet 236300d0963fSdilpreet if (panicstr) { 236400d0963fSdilpreet eqep = errorq_reserve(ereport_errorq); 236500d0963fSdilpreet if (eqep == NULL) 236600d0963fSdilpreet return; 236700d0963fSdilpreet ereport = errorq_elem_nvl(ereport_errorq, eqep); 236800d0963fSdilpreet nva = errorq_elem_nva(ereport_errorq, eqep); 236900d0963fSdilpreet detector = fm_nvlist_create(nva); 237000d0963fSdilpreet } else { 237100d0963fSdilpreet ereport = fm_nvlist_create(NULL); 237200d0963fSdilpreet detector = fm_nvlist_create(NULL); 237300d0963fSdilpreet } 237400d0963fSdilpreet 237500d0963fSdilpreet (void) ddi_pathname(dip, device_path); 237600d0963fSdilpreet fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, 237700d0963fSdilpreet device_path, NULL); 237800d0963fSdilpreet (void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s", 237900d0963fSdilpreet DDI_IO_CLASS, error_class); 238000d0963fSdilpreet fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL); 238100d0963fSdilpreet 238200d0963fSdilpreet va_start(ap, version); 238300d0963fSdilpreet name = va_arg(ap, char *); 238400d0963fSdilpreet (void) i_fm_payload_set(ereport, name, ap); 238500d0963fSdilpreet va_end(ap); 238600d0963fSdilpreet 238700d0963fSdilpreet if (panicstr) { 238800d0963fSdilpreet errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); 238900d0963fSdilpreet } else { 239000d0963fSdilpreet (void) fm_ereport_post(ereport, EVCH_TRYHARD); 239100d0963fSdilpreet fm_nvlist_destroy(ereport, FM_NVA_FREE); 239200d0963fSdilpreet fm_nvlist_destroy(detector, FM_NVA_FREE); 239300d0963fSdilpreet } 239400d0963fSdilpreet } 239500d0963fSdilpreet 239600d0963fSdilpreet static int 239700d0963fSdilpreet pci_check_regs(dev_info_t *dip, void *arg) 239800d0963fSdilpreet { 239900d0963fSdilpreet int reglen; 240000d0963fSdilpreet int rn; 240100d0963fSdilpreet int totreg; 240200d0963fSdilpreet pci_regspec_t *drv_regp; 240300d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 240400d0963fSdilpreet 240500d0963fSdilpreet if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 240600d0963fSdilpreet /* 240700d0963fSdilpreet * for config space, we need to check if the given address 240800d0963fSdilpreet * is a valid config space address for this device - based 240900d0963fSdilpreet * on pci_phys_hi of the config space entry in reg property. 241000d0963fSdilpreet */ 241100d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 241200d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 241300d0963fSdilpreet return (DDI_WALK_CONTINUE); 241400d0963fSdilpreet 241500d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 241600d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 241700d0963fSdilpreet if (tgt_err->tgt_pci_space == 241800d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) && 241900d0963fSdilpreet (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M | 242000d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M)) == 242100d0963fSdilpreet (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M | 242200d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M))) { 242300d0963fSdilpreet tgt_err->tgt_dip = dip; 242400d0963fSdilpreet kmem_free(drv_regp, reglen); 242500d0963fSdilpreet return (DDI_WALK_TERMINATE); 242600d0963fSdilpreet } 242700d0963fSdilpreet } 242800d0963fSdilpreet kmem_free(drv_regp, reglen); 242900d0963fSdilpreet } else { 243000d0963fSdilpreet /* 243100d0963fSdilpreet * for non config space, need to check reg to look 243200d0963fSdilpreet * for any non-relocable mapping, otherwise check 243300d0963fSdilpreet * assigned-addresses. 243400d0963fSdilpreet */ 243500d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 243600d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 243700d0963fSdilpreet return (DDI_WALK_CONTINUE); 243800d0963fSdilpreet 243900d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 244000d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 244100d0963fSdilpreet if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) && 244200d0963fSdilpreet (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 244300d0963fSdilpreet tgt_err->tgt_pci_space == 244400d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 244500d0963fSdilpreet (tgt_err->tgt_pci_addr >= 244600d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 244700d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 244800d0963fSdilpreet (tgt_err->tgt_pci_addr < 244900d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 245000d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 245100d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 245200d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 245300d0963fSdilpreet tgt_err->tgt_dip = dip; 245400d0963fSdilpreet kmem_free(drv_regp, reglen); 245500d0963fSdilpreet return (DDI_WALK_TERMINATE); 245600d0963fSdilpreet } 245700d0963fSdilpreet } 245800d0963fSdilpreet kmem_free(drv_regp, reglen); 245900d0963fSdilpreet 246000d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 246100d0963fSdilpreet "assigned-addresses", (caddr_t)&drv_regp, ®len) != 246200d0963fSdilpreet DDI_SUCCESS) 246300d0963fSdilpreet return (DDI_WALK_CONTINUE); 246400d0963fSdilpreet 246500d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 246600d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 246700d0963fSdilpreet if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 246800d0963fSdilpreet tgt_err->tgt_pci_space == 246900d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 247000d0963fSdilpreet (tgt_err->tgt_pci_addr >= 247100d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 247200d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 247300d0963fSdilpreet (tgt_err->tgt_pci_addr < 247400d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 247500d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 247600d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 247700d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 247800d0963fSdilpreet tgt_err->tgt_dip = dip; 247900d0963fSdilpreet kmem_free(drv_regp, reglen); 248000d0963fSdilpreet return (DDI_WALK_TERMINATE); 248100d0963fSdilpreet } 248200d0963fSdilpreet } 248300d0963fSdilpreet kmem_free(drv_regp, reglen); 248400d0963fSdilpreet } 248500d0963fSdilpreet return (DDI_WALK_CONTINUE); 248600d0963fSdilpreet } 248700d0963fSdilpreet 248800d0963fSdilpreet /* 248900d0963fSdilpreet * impl_fix_ranges - fixes the config space entry of the "ranges" 249000d0963fSdilpreet * property on psycho+ platforms. (if changing this function please make sure 249100d0963fSdilpreet * to change the pci_fix_ranges function in pcipsy.c) 249200d0963fSdilpreet */ 249300d0963fSdilpreet /*ARGSUSED*/ 249400d0963fSdilpreet static void 249500d0963fSdilpreet pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange) 249600d0963fSdilpreet { 249700d0963fSdilpreet #if defined(__sparc) 249800d0963fSdilpreet char *name = ddi_binding_name(dip); 249900d0963fSdilpreet 250000d0963fSdilpreet if ((strcmp(name, "pci108e,8000") == 0) || 250100d0963fSdilpreet (strcmp(name, "pci108e,a000") == 0) || 250200d0963fSdilpreet (strcmp(name, "pci108e,a001") == 0)) { 250300d0963fSdilpreet int i; 250400d0963fSdilpreet for (i = 0; i < nrange; i++, pci_ranges++) 250500d0963fSdilpreet if ((pci_ranges->child_high & PCI_REG_ADDR_M) == 250600d0963fSdilpreet PCI_ADDR_CONFIG) 250700d0963fSdilpreet pci_ranges->parent_low |= 250800d0963fSdilpreet pci_ranges->child_high; 250900d0963fSdilpreet } 251000d0963fSdilpreet #endif 251100d0963fSdilpreet } 251200d0963fSdilpreet 251300d0963fSdilpreet static int 251400d0963fSdilpreet pci_check_ranges(dev_info_t *dip, void *arg) 251500d0963fSdilpreet { 251600d0963fSdilpreet uint64_t range_parent_begin; 251700d0963fSdilpreet uint64_t range_parent_size; 251800d0963fSdilpreet uint64_t range_parent_end; 251900d0963fSdilpreet uint32_t space_type; 252000d0963fSdilpreet uint32_t bus_num; 252100d0963fSdilpreet uint32_t range_offset; 252200d0963fSdilpreet pci_ranges_t *pci_ranges, *rangep; 252300d0963fSdilpreet pci_bus_range_t *pci_bus_rangep; 252400d0963fSdilpreet int pci_ranges_length; 252500d0963fSdilpreet int nrange; 252600d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 252700d0963fSdilpreet int i, size; 252800d0963fSdilpreet if (strcmp(ddi_node_name(dip), "pci") != 0 && 252900d0963fSdilpreet strcmp(ddi_node_name(dip), "pciex") != 0) 253000d0963fSdilpreet return (DDI_WALK_CONTINUE); 253100d0963fSdilpreet 253200d0963fSdilpreet /* 253300d0963fSdilpreet * Get the ranges property. Note we only look at the top level pci 253400d0963fSdilpreet * node (hostbridge) which has a ranges property of type pci_ranges_t 253500d0963fSdilpreet * not at pci-pci bridges. 253600d0963fSdilpreet */ 253700d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 253800d0963fSdilpreet (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) { 253900d0963fSdilpreet /* 254000d0963fSdilpreet * no ranges property - no translation needed 254100d0963fSdilpreet */ 254200d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr; 254300d0963fSdilpreet tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN; 254400d0963fSdilpreet if (panicstr) 254500d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 254600d0963fSdilpreet pci_check_regs, (void *)tgt_err); 254700d0963fSdilpreet else { 254800d0963fSdilpreet int circ = 0; 254900d0963fSdilpreet ndi_devi_enter(dip, &circ); 255000d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 255100d0963fSdilpreet (void *)tgt_err); 255200d0963fSdilpreet ndi_devi_exit(dip, circ); 255300d0963fSdilpreet } 255400d0963fSdilpreet if (tgt_err->tgt_dip != NULL) 255500d0963fSdilpreet return (DDI_WALK_TERMINATE); 255600d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 255700d0963fSdilpreet } 255800d0963fSdilpreet nrange = pci_ranges_length / sizeof (pci_ranges_t); 255900d0963fSdilpreet rangep = pci_ranges; 256000d0963fSdilpreet 256100d0963fSdilpreet /* Need to fix the pci ranges property for psycho based systems */ 256200d0963fSdilpreet pci_fix_ranges(dip, pci_ranges, nrange); 256300d0963fSdilpreet 256400d0963fSdilpreet for (i = 0; i < nrange; i++, rangep++) { 256500d0963fSdilpreet range_parent_begin = ((uint64_t)rangep->parent_high << 32) + 256600d0963fSdilpreet rangep->parent_low; 256700d0963fSdilpreet range_parent_size = ((uint64_t)rangep->size_high << 32) + 256800d0963fSdilpreet rangep->size_low; 256900d0963fSdilpreet range_parent_end = range_parent_begin + range_parent_size - 1; 257000d0963fSdilpreet 257100d0963fSdilpreet if ((tgt_err->tgt_err_addr < range_parent_begin) || 257200d0963fSdilpreet (tgt_err->tgt_err_addr > range_parent_end)) { 257300d0963fSdilpreet /* Not in range */ 257400d0963fSdilpreet continue; 257500d0963fSdilpreet } 257600d0963fSdilpreet space_type = PCI_REG_ADDR_G(rangep->child_high); 257700d0963fSdilpreet if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 257800d0963fSdilpreet /* Config space address - check bus range */ 257900d0963fSdilpreet range_offset = tgt_err->tgt_err_addr - 258000d0963fSdilpreet range_parent_begin; 258100d0963fSdilpreet bus_num = PCI_REG_BUS_G(range_offset); 258200d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 258300d0963fSdilpreet DDI_PROP_DONTPASS, "bus-range", 258400d0963fSdilpreet (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) { 258500d0963fSdilpreet continue; 258600d0963fSdilpreet } 258700d0963fSdilpreet if ((bus_num < pci_bus_rangep->lo) || 258800d0963fSdilpreet (bus_num > pci_bus_rangep->hi)) { 258900d0963fSdilpreet /* 259000d0963fSdilpreet * Bus number not appropriate for this 259100d0963fSdilpreet * pci nexus. 259200d0963fSdilpreet */ 259300d0963fSdilpreet kmem_free(pci_bus_rangep, size); 259400d0963fSdilpreet continue; 259500d0963fSdilpreet } 259600d0963fSdilpreet kmem_free(pci_bus_rangep, size); 259700d0963fSdilpreet } 259800d0963fSdilpreet 259900d0963fSdilpreet /* We have a match if we get here - compute pci address */ 260000d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr - 260100d0963fSdilpreet range_parent_begin; 260200d0963fSdilpreet tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) + 260300d0963fSdilpreet rangep->child_low); 260400d0963fSdilpreet tgt_err->tgt_pci_space = space_type; 260500d0963fSdilpreet if (panicstr) 260600d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 260700d0963fSdilpreet pci_check_regs, (void *)tgt_err); 260800d0963fSdilpreet else { 260900d0963fSdilpreet int circ = 0; 261000d0963fSdilpreet ndi_devi_enter(dip, &circ); 261100d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 261200d0963fSdilpreet (void *)tgt_err); 261300d0963fSdilpreet ndi_devi_exit(dip, circ); 261400d0963fSdilpreet } 261500d0963fSdilpreet if (tgt_err->tgt_dip != NULL) { 261600d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 261700d0963fSdilpreet return (DDI_WALK_TERMINATE); 261800d0963fSdilpreet } 261900d0963fSdilpreet } 262000d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 262100d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 262200d0963fSdilpreet } 262300d0963fSdilpreet 262400d0963fSdilpreet /* 262500d0963fSdilpreet * Function used to drain pci_target_queue, either during panic or after softint 262600d0963fSdilpreet * is generated, to generate target device ereports based on captured physical 262700d0963fSdilpreet * addresses 262800d0963fSdilpreet */ 262900d0963fSdilpreet /*ARGSUSED*/ 263000d0963fSdilpreet static void 263100d0963fSdilpreet pci_target_drain(void *private_p, pci_target_err_t *tgt_err) 263200d0963fSdilpreet { 263300d0963fSdilpreet char buf[FM_MAX_CLASS]; 263400d0963fSdilpreet 263500d0963fSdilpreet /* 263600d0963fSdilpreet * The following assumes that all pci_pci bridge devices 263700d0963fSdilpreet * are configured as transparant. Find the top-level pci 263800d0963fSdilpreet * nexus which has tgt_err_addr in one of its ranges, converting this 263900d0963fSdilpreet * to a pci address in the process. Then starting at this node do 264000d0963fSdilpreet * another tree walk to find a device with the pci address we've 264100d0963fSdilpreet * found within range of one of it's assigned-addresses properties. 264200d0963fSdilpreet */ 264300d0963fSdilpreet tgt_err->tgt_dip = NULL; 264400d0963fSdilpreet if (panicstr) 264500d0963fSdilpreet (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges, 264600d0963fSdilpreet (void *)tgt_err); 264700d0963fSdilpreet else 264800d0963fSdilpreet ddi_walk_devs(ddi_root_node(), pci_check_ranges, 264900d0963fSdilpreet (void *)tgt_err); 265000d0963fSdilpreet if (tgt_err->tgt_dip == NULL) 265100d0963fSdilpreet return; 265200d0963fSdilpreet 265300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type, 265400d0963fSdilpreet tgt_err->tgt_err_class); 265500d0963fSdilpreet pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0, 265600d0963fSdilpreet PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL); 265700d0963fSdilpreet } 265800d0963fSdilpreet 265900d0963fSdilpreet void 266000d0963fSdilpreet pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr) 266100d0963fSdilpreet { 266200d0963fSdilpreet pci_target_err_t tgt_err; 266300d0963fSdilpreet 266400d0963fSdilpreet tgt_err.tgt_err_ena = ena; 266500d0963fSdilpreet tgt_err.tgt_err_class = class; 266600d0963fSdilpreet tgt_err.tgt_bridge_type = bridge_type; 266700d0963fSdilpreet tgt_err.tgt_err_addr = addr; 266800d0963fSdilpreet errorq_dispatch(pci_target_queue, (void *)&tgt_err, 266900d0963fSdilpreet sizeof (pci_target_err_t), ERRORQ_ASYNC); 267000d0963fSdilpreet } 267100d0963fSdilpreet 267200d0963fSdilpreet void 267300d0963fSdilpreet pci_targetq_init(void) 267400d0963fSdilpreet { 267500d0963fSdilpreet /* 267600d0963fSdilpreet * PCI target errorq, to schedule async handling of generation of 267700d0963fSdilpreet * target device ereports based on captured physical address. 267800d0963fSdilpreet * The errorq is created here but destroyed when _fini is called 267900d0963fSdilpreet * for the pci module. 268000d0963fSdilpreet */ 268100d0963fSdilpreet if (pci_target_queue == NULL) { 268200d0963fSdilpreet pci_target_queue = errorq_create("pci_target_queue", 268300d0963fSdilpreet (errorq_func_t)pci_target_drain, (void *)NULL, 268400d0963fSdilpreet TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL, 268500d0963fSdilpreet ERRORQ_VITAL); 268600d0963fSdilpreet if (pci_target_queue == NULL) 268700d0963fSdilpreet panic("failed to create required system error queue"); 268800d0963fSdilpreet } 268900d0963fSdilpreet } 2690