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