100d0963fSdilpreet /* 200d0963fSdilpreet * CDDL HEADER START 300d0963fSdilpreet * 400d0963fSdilpreet * The contents of this file are subject to the terms of the 500d0963fSdilpreet * Common Development and Distribution License (the "License"). 600d0963fSdilpreet * You may not use this file except in compliance with the License. 700d0963fSdilpreet * 800d0963fSdilpreet * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 900d0963fSdilpreet * or http://www.opensolaris.org/os/licensing. 1000d0963fSdilpreet * See the License for the specific language governing permissions 1100d0963fSdilpreet * and limitations under the License. 1200d0963fSdilpreet * 1300d0963fSdilpreet * When distributing Covered Code, include this CDDL HEADER in each 1400d0963fSdilpreet * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1500d0963fSdilpreet * If applicable, add the following below this CDDL HEADER, with the 1600d0963fSdilpreet * fields enclosed by brackets "[]" replaced with your own identifying 1700d0963fSdilpreet * information: Portions Copyright [yyyy] [name of copyright owner] 1800d0963fSdilpreet * 1900d0963fSdilpreet * CDDL HEADER END 2000d0963fSdilpreet */ 2100d0963fSdilpreet 2200d0963fSdilpreet /* 23*392e836bSGavin Maltby * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 2400d0963fSdilpreet */ 2500d0963fSdilpreet 2600d0963fSdilpreet #include <sys/types.h> 2700d0963fSdilpreet #include <sys/sunndi.h> 2800d0963fSdilpreet #include <sys/sysmacros.h> 2900d0963fSdilpreet #include <sys/ddifm_impl.h> 3000d0963fSdilpreet #include <sys/fm/util.h> 3100d0963fSdilpreet #include <sys/fm/protocol.h> 3200d0963fSdilpreet #include <sys/fm/io/pci.h> 3300d0963fSdilpreet #include <sys/fm/io/ddi.h> 3400d0963fSdilpreet #include <sys/pci.h> 3549fbdd30SErwin T Tsaur #include <sys/pci_cap.h> 3600d0963fSdilpreet #include <sys/pci_impl.h> 3700d0963fSdilpreet #include <sys/epm.h> 3800d0963fSdilpreet #include <sys/pcifm.h> 3900d0963fSdilpreet 4000d0963fSdilpreet #define PCIX_ECC_VER_CHECK(x) (((x) == PCI_PCIX_VER_1) ||\ 4100d0963fSdilpreet ((x) == PCI_PCIX_VER_2)) 4200d0963fSdilpreet 4300d0963fSdilpreet errorq_t *pci_target_queue = NULL; 4400d0963fSdilpreet 4500d0963fSdilpreet pci_fm_err_t pci_err_tbl[] = { 4600d0963fSdilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN, 4700d0963fSdilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN, 4800d0963fSdilpreet PCI_SIG_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_FATAL, 4900d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 5000d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 5100d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 5200d0963fSdilpreet NULL, NULL, NULL, NULL, 5300d0963fSdilpreet }; 5400d0963fSdilpreet 5500d0963fSdilpreet pci_fm_err_t pci_bdg_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_REC_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_UNKNOWN, 598aec9182Sstephh #if defined(__sparc) 6000d0963fSdilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN, 610c64a9b4Sanish #endif 6200d0963fSdilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN, 6300d0963fSdilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN, 6400d0963fSdilpreet NULL, NULL, NULL, NULL, 6500d0963fSdilpreet }; 6600d0963fSdilpreet 6700d0963fSdilpreet static pci_fm_err_t pcix_err_tbl[] = { 6800d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 6900d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 7000d0963fSdilpreet PCIX_RX_SPL_MSG, PCI_PCIX_RX_SPL_MSG, NULL, DDI_FM_UNKNOWN, 7100d0963fSdilpreet NULL, NULL, NULL, NULL, 7200d0963fSdilpreet }; 7300d0963fSdilpreet 7400d0963fSdilpreet static pci_fm_err_t pcix_sec_err_tbl[] = { 7500d0963fSdilpreet PCIX_SPL_DIS, PCI_PCIX_BSS_SPL_DSCD, NULL, DDI_FM_UNKNOWN, 7600d0963fSdilpreet PCIX_UNEX_SPL, PCI_PCIX_BSS_UNEX_SPL, NULL, DDI_FM_UNKNOWN, 77ac4d633fSstephh PCIX_BSS_SPL_OR, PCI_PCIX_BSS_SPL_OR, NULL, DDI_FM_OK, 78ac4d633fSstephh PCIX_BSS_SPL_DLY, PCI_PCIX_BSS_SPL_DLY, NULL, DDI_FM_OK, 7900d0963fSdilpreet NULL, NULL, NULL, NULL, 8000d0963fSdilpreet }; 8100d0963fSdilpreet 8200d0963fSdilpreet static int 838aec9182Sstephh pci_config_check(ddi_acc_handle_t handle, int fme_flag) 8400d0963fSdilpreet { 8500d0963fSdilpreet ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle); 8600d0963fSdilpreet ddi_fm_error_t de; 8700d0963fSdilpreet 8800d0963fSdilpreet if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip)))) 8900d0963fSdilpreet return (DDI_FM_OK); 9000d0963fSdilpreet 9100d0963fSdilpreet de.fme_version = DDI_FME_VERSION; 9200d0963fSdilpreet 9300d0963fSdilpreet ddi_fm_acc_err_get(handle, &de, de.fme_version); 9400d0963fSdilpreet if (de.fme_status != DDI_FM_OK) { 958aec9182Sstephh if (fme_flag == DDI_FM_ERR_UNEXPECTED) { 9600d0963fSdilpreet char buf[FM_MAX_CLASS]; 9700d0963fSdilpreet 988aec9182Sstephh (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 998aec9182Sstephh PCI_ERROR_SUBCLASS, PCI_NR); 1008aec9182Sstephh ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena, 1018aec9182Sstephh DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 1028aec9182Sstephh } 10300d0963fSdilpreet ddi_fm_acc_err_clear(handle, de.fme_version); 10400d0963fSdilpreet } 10500d0963fSdilpreet return (de.fme_status); 10600d0963fSdilpreet } 10700d0963fSdilpreet 10800d0963fSdilpreet static void 10900d0963fSdilpreet pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs, 1108aec9182Sstephh uint8_t pcix_cap_ptr, int fme_flag) 11100d0963fSdilpreet { 11200d0963fSdilpreet int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV; 11300d0963fSdilpreet 11400d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl, 11500d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS : 11600d0963fSdilpreet PCI_PCIX_ECC_STATUS))); 1178aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 11800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID; 11900d0963fSdilpreet else 12000d0963fSdilpreet return; 12100d0963fSdilpreet pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl, 12200d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD : 12300d0963fSdilpreet PCI_PCIX_ECC_FST_AD))); 12400d0963fSdilpreet pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl, 12500d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD : 12600d0963fSdilpreet PCI_PCIX_ECC_SEC_AD))); 12700d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr = pci_config_get32(( 12800d0963fSdilpreet ddi_acc_handle_t)erpt_p->pe_hdl, 12900d0963fSdilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR))); 13000d0963fSdilpreet } 13100d0963fSdilpreet 13200d0963fSdilpreet static void 1338aec9182Sstephh pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs, int fme_flag) 13400d0963fSdilpreet { 13500d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 13600d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 13700d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 13800d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 13900d0963fSdilpreet int i; 14000d0963fSdilpreet 14100d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 14200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16( 14300d0963fSdilpreet erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS)); 1448aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 14500d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= 14600d0963fSdilpreet PCIX_BDG_SEC_STATUS_VALID; 14700d0963fSdilpreet else 14800d0963fSdilpreet return; 14900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl, 15000d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS)); 1518aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 15200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID; 15300d0963fSdilpreet else 15400d0963fSdilpreet return; 15500d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 15600d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 15749fbdd30SErwin T Tsaur 15800d0963fSdilpreet for (i = 0; i < 2; i++) { 15900d0963fSdilpreet pcix_bdg_ecc_regs = 16000d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 16100d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 16200d0963fSdilpreet (pcix_bdg_cap_ptr + 16300d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), i); 16400d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, 16500d0963fSdilpreet pcix_bdg_ecc_regs, 1668aec9182Sstephh pcix_bdg_cap_ptr, fme_flag); 16700d0963fSdilpreet } 16800d0963fSdilpreet } 16900d0963fSdilpreet } else { 17000d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 17100d0963fSdilpreet uint8_t pcix_cap_ptr; 17200d0963fSdilpreet 17300d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 17400d0963fSdilpreet 17500d0963fSdilpreet pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl, 17600d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_COMMAND)); 17700d0963fSdilpreet pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl, 17800d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS)); 1798aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 18000d0963fSdilpreet pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID; 18100d0963fSdilpreet else 18200d0963fSdilpreet return; 18300d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 18400d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 18500d0963fSdilpreet pcix_regs->pcix_ecc_regs; 18600d0963fSdilpreet 18700d0963fSdilpreet pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs, 1888aec9182Sstephh pcix_cap_ptr, fme_flag); 18900d0963fSdilpreet } 19000d0963fSdilpreet } 19100d0963fSdilpreet } 19200d0963fSdilpreet 19300d0963fSdilpreet /*ARGSUSED*/ 19400d0963fSdilpreet static void 1958aec9182Sstephh pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p, int fme_flag) 19600d0963fSdilpreet { 19700d0963fSdilpreet pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs; 19800d0963fSdilpreet 19900d0963fSdilpreet /* 20000d0963fSdilpreet * Start by reading all the error registers that are available for 20100d0963fSdilpreet * pci and pci express and for leaf devices and bridges/switches 20200d0963fSdilpreet */ 20300d0963fSdilpreet pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl, 20400d0963fSdilpreet PCI_CONF_STAT); 2058aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK) 20600d0963fSdilpreet return; 20700d0963fSdilpreet pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID; 20800d0963fSdilpreet pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl, 20900d0963fSdilpreet PCI_CONF_COMM); 2108aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK) 21100d0963fSdilpreet return; 21200d0963fSdilpreet 21300d0963fSdilpreet /* 21400d0963fSdilpreet * If pci-pci bridge grab PCI bridge specific error registers. 21500d0963fSdilpreet */ 21600d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 21700d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_sec_stat = 21800d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS); 2198aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 22000d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 22100d0963fSdilpreet PCI_BDG_SEC_STAT_VALID; 22200d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_ctrl = 22300d0963fSdilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL); 2248aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) 22500d0963fSdilpreet pci_regs->pci_bdg_regs->pci_bdg_vflags |= 22600d0963fSdilpreet PCI_BDG_CTRL_VALID; 22700d0963fSdilpreet } 22800d0963fSdilpreet 22949fbdd30SErwin T Tsaur /* If pci-x device grab error registers */ 23049fbdd30SErwin T Tsaur if (erpt_p->pe_dflags & PCIX_DEV) 2318aec9182Sstephh pcix_regs_gather(erpt_p, erpt_p->pe_regs, fme_flag); 23200d0963fSdilpreet 23300d0963fSdilpreet } 23400d0963fSdilpreet 23500d0963fSdilpreet static void 23600d0963fSdilpreet pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs) 23700d0963fSdilpreet { 23800d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 23900d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = 24000d0963fSdilpreet (pcix_bdg_error_regs_t *)pe_regs; 24100d0963fSdilpreet uint8_t pcix_bdg_cap_ptr; 24200d0963fSdilpreet int i; 24300d0963fSdilpreet 24400d0963fSdilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr; 24500d0963fSdilpreet 24600d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) 24700d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, 24800d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS), 24900d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat); 25000d0963fSdilpreet 25100d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) 25200d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 25300d0963fSdilpreet (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS), 25400d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat); 25500d0963fSdilpreet 25600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_vflags = 0x0; 25700d0963fSdilpreet 25800d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 25900d0963fSdilpreet pcix_ecc_regs_t *pcix_bdg_ecc_regs; 26000d0963fSdilpreet for (i = 0; i < 2; i++) { 26100d0963fSdilpreet pcix_bdg_ecc_regs = 26200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i]; 26300d0963fSdilpreet 26400d0963fSdilpreet if (pcix_bdg_ecc_regs->pcix_ecc_vflags & 26500d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) { 26600d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 26700d0963fSdilpreet (pcix_bdg_cap_ptr + 26800d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 26900d0963fSdilpreet i); 27000d0963fSdilpreet 27100d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 27200d0963fSdilpreet (pcix_bdg_cap_ptr + 27300d0963fSdilpreet PCI_PCIX_BDG_ECC_STATUS), 27400d0963fSdilpreet pcix_bdg_ecc_regs-> 27500d0963fSdilpreet pcix_ecc_ctlstat); 27600d0963fSdilpreet } 27700d0963fSdilpreet pcix_bdg_ecc_regs->pcix_ecc_vflags = 27800d0963fSdilpreet 0x0; 27900d0963fSdilpreet } 28000d0963fSdilpreet } 28100d0963fSdilpreet } else { 28200d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs; 28300d0963fSdilpreet uint8_t pcix_cap_ptr; 28400d0963fSdilpreet 28500d0963fSdilpreet pcix_cap_ptr = pcix_regs->pcix_cap_ptr; 28600d0963fSdilpreet 28700d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) 28800d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 28900d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_STATUS), 29000d0963fSdilpreet pcix_regs->pcix_status); 29100d0963fSdilpreet 29200d0963fSdilpreet pcix_regs->pcix_vflags = 0x0; 29300d0963fSdilpreet 29400d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 29500d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs = 29600d0963fSdilpreet pcix_regs->pcix_ecc_regs; 29700d0963fSdilpreet 29800d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & 29900d0963fSdilpreet PCIX_ERR_ECC_STS_VALID) 30000d0963fSdilpreet pci_config_put32(erpt_p->pe_hdl, 30100d0963fSdilpreet (pcix_cap_ptr + PCI_PCIX_ECC_STATUS), 30200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat); 30300d0963fSdilpreet 30400d0963fSdilpreet pcix_ecc_regs->pcix_ecc_vflags = 0x0; 30500d0963fSdilpreet } 30600d0963fSdilpreet } 30700d0963fSdilpreet } 30800d0963fSdilpreet 30900d0963fSdilpreet static void 31000d0963fSdilpreet pci_regs_clear(pci_erpt_t *erpt_p) 31100d0963fSdilpreet { 31200d0963fSdilpreet /* 31300d0963fSdilpreet * Finally clear the error bits 31400d0963fSdilpreet */ 31549fbdd30SErwin T Tsaur if (erpt_p->pe_dflags & PCIX_DEV) 31600d0963fSdilpreet pcix_regs_clear(erpt_p, erpt_p->pe_regs); 31700d0963fSdilpreet 31800d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID) 31900d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT, 32000d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status); 32100d0963fSdilpreet 32200d0963fSdilpreet erpt_p->pe_pci_regs->pci_vflags = 0x0; 32300d0963fSdilpreet 32400d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 32500d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 32600d0963fSdilpreet PCI_BDG_SEC_STAT_VALID) 32700d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS, 32800d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs-> 32900d0963fSdilpreet pci_bdg_sec_stat); 33000d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags & 33100d0963fSdilpreet PCI_BDG_CTRL_VALID) 33200d0963fSdilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL, 33300d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl); 33400d0963fSdilpreet 33500d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0; 33600d0963fSdilpreet } 33700d0963fSdilpreet } 33800d0963fSdilpreet 33900d0963fSdilpreet /* 34000d0963fSdilpreet * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport 34100d0963fSdilpreet * generation. 34200d0963fSdilpreet */ 34300d0963fSdilpreet /* ARGSUSED */ 34400d0963fSdilpreet static void 34500d0963fSdilpreet pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p) 34600d0963fSdilpreet { 34749fbdd30SErwin T Tsaur uint16_t pcix_cap_ptr = PCI_CAP_NEXT_PTR_NULL; 34849fbdd30SErwin T Tsaur ddi_acc_handle_t eh; 34900d0963fSdilpreet int i; 35000d0963fSdilpreet 351be84494cSKrishna Elango if (pci_config_setup(dip, &eh) == DDI_SUCCESS) { 35249fbdd30SErwin T Tsaur (void) PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCIX, &pcix_cap_ptr); 353be84494cSKrishna Elango pci_config_teardown(&eh); 35449fbdd30SErwin T Tsaur } 35500d0963fSdilpreet 35600d0963fSdilpreet if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL) 35700d0963fSdilpreet erpt_p->pe_dflags |= PCIX_DEV; 35800d0963fSdilpreet else 35900d0963fSdilpreet return; 36000d0963fSdilpreet 36100d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 36200d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 36300d0963fSdilpreet 36400d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t), 36500d0963fSdilpreet KM_SLEEP); 36600d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 36700d0963fSdilpreet pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr; 36800d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl, 36900d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 37000d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 37100d0963fSdilpreet for (i = 0; i < 2; i++) { 37200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_ecc_regs[i] = 37300d0963fSdilpreet kmem_zalloc(sizeof (pcix_ecc_regs_t), 37400d0963fSdilpreet KM_SLEEP); 37500d0963fSdilpreet } 37600d0963fSdilpreet } 37700d0963fSdilpreet } else { 37800d0963fSdilpreet pcix_error_regs_t *pcix_regs; 37900d0963fSdilpreet 38000d0963fSdilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t), 38100d0963fSdilpreet KM_SLEEP); 38200d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 38300d0963fSdilpreet pcix_regs->pcix_cap_ptr = pcix_cap_ptr; 38400d0963fSdilpreet pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl, 38500d0963fSdilpreet pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 38600d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 38700d0963fSdilpreet pcix_regs->pcix_ecc_regs = kmem_zalloc( 38800d0963fSdilpreet sizeof (pcix_ecc_regs_t), KM_SLEEP); 38900d0963fSdilpreet } 39000d0963fSdilpreet } 39100d0963fSdilpreet } 39200d0963fSdilpreet 39300d0963fSdilpreet /* 39400d0963fSdilpreet * pci_ereport_setup: Detect PCI device type and initialize structures to be 39500d0963fSdilpreet * used to generate ereports based on detected generic device errors. 39600d0963fSdilpreet */ 39700d0963fSdilpreet void 39800d0963fSdilpreet pci_ereport_setup(dev_info_t *dip) 39900d0963fSdilpreet { 40000d0963fSdilpreet struct dev_info *devi = DEVI(dip); 40100d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl; 40200d0963fSdilpreet pci_erpt_t *erpt_p; 40300d0963fSdilpreet uint8_t pci_hdr_type; 40400d0963fSdilpreet uint16_t pci_status; 40500d0963fSdilpreet pci_regspec_t *pci_rp; 40600d0963fSdilpreet int32_t len; 40700d0963fSdilpreet uint32_t phys_hi; 40800d0963fSdilpreet 40900d0963fSdilpreet /* 41000d0963fSdilpreet * If device is not ereport capbable then report an error against the 41100d0963fSdilpreet * driver for using this interface, 41200d0963fSdilpreet */ 41300d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 41400d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 41500d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 41600d0963fSdilpreet return; 41700d0963fSdilpreet } 41800d0963fSdilpreet 41900d0963fSdilpreet /* 42000d0963fSdilpreet * ASSERT fmhdl exists and fh_bus_specific is NULL. 42100d0963fSdilpreet */ 42200d0963fSdilpreet ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL)); 42300d0963fSdilpreet 42400d0963fSdilpreet erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP); 42500d0963fSdilpreet 42600d0963fSdilpreet if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS) 42700d0963fSdilpreet goto error; 42800d0963fSdilpreet 42900d0963fSdilpreet erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP); 43000d0963fSdilpreet 43100d0963fSdilpreet pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT); 4328aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) != 4338aec9182Sstephh DDI_FM_OK) 43400d0963fSdilpreet goto error; 43500d0963fSdilpreet 43600d0963fSdilpreet /* 43700d0963fSdilpreet * Get header type and record if device is a bridge. 43800d0963fSdilpreet */ 43900d0963fSdilpreet pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER); 4408aec9182Sstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) != 4418aec9182Sstephh DDI_FM_OK) 44200d0963fSdilpreet goto error; 44300d0963fSdilpreet 44400d0963fSdilpreet /* 44500d0963fSdilpreet * Check to see if PCI device is a bridge, if so allocate pci bridge 44600d0963fSdilpreet * error register structure. 44700d0963fSdilpreet */ 44800d0963fSdilpreet if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 44900d0963fSdilpreet erpt_p->pe_dflags |= PCI_BRIDGE_DEV; 45000d0963fSdilpreet erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc( 45100d0963fSdilpreet sizeof (pci_bdg_error_regs_t), KM_SLEEP); 45200d0963fSdilpreet } 45300d0963fSdilpreet 45400d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 45500d0963fSdilpreet (caddr_t)&pci_rp, &len) == DDI_SUCCESS) { 45600d0963fSdilpreet phys_hi = pci_rp->pci_phys_hi; 45700d0963fSdilpreet kmem_free(pci_rp, len); 45800d0963fSdilpreet 45900d0963fSdilpreet erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >> 46000d0963fSdilpreet PCI_REG_FUNC_SHIFT); 46100d0963fSdilpreet } 46200d0963fSdilpreet 46300d0963fSdilpreet if (!(pci_status & PCI_STAT_CAP)) { 46400d0963fSdilpreet goto done; 46500d0963fSdilpreet } 46600d0963fSdilpreet 46749fbdd30SErwin T Tsaur /* Initialize structures for PCI-X devices. */ 46800d0963fSdilpreet pcix_ereport_setup(dip, erpt_p); 46900d0963fSdilpreet 47000d0963fSdilpreet done: 4718aec9182Sstephh pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED); 47200d0963fSdilpreet pci_regs_clear(erpt_p); 47300d0963fSdilpreet 47400d0963fSdilpreet /* 47500d0963fSdilpreet * Before returning set fh_bus_specific to completed pci_erpt_t 47600d0963fSdilpreet * structure 47700d0963fSdilpreet */ 47800d0963fSdilpreet fmhdl->fh_bus_specific = (void *)erpt_p; 47900d0963fSdilpreet 48000d0963fSdilpreet return; 48100d0963fSdilpreet error: 48200d0963fSdilpreet if (erpt_p->pe_pci_regs) 48300d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 48400d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 48500d0963fSdilpreet erpt_p = NULL; 48600d0963fSdilpreet } 48700d0963fSdilpreet 48800d0963fSdilpreet static void 48900d0963fSdilpreet pcix_ereport_teardown(pci_erpt_t *erpt_p) 49000d0963fSdilpreet { 49100d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 49200d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 49300d0963fSdilpreet uint16_t pcix_ver; 49400d0963fSdilpreet 49500d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs; 49600d0963fSdilpreet pcix_ver = pcix_bdg_regs->pcix_bdg_ver; 49700d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 49800d0963fSdilpreet int i; 49900d0963fSdilpreet for (i = 0; i < 2; i++) 50000d0963fSdilpreet kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i], 50100d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 50200d0963fSdilpreet } 50300d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t)); 50400d0963fSdilpreet } else { 50500d0963fSdilpreet pcix_error_regs_t *pcix_regs; 50600d0963fSdilpreet uint16_t pcix_ver; 50700d0963fSdilpreet 50800d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 50900d0963fSdilpreet pcix_ver = pcix_regs->pcix_ver; 51000d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_ver)) { 51100d0963fSdilpreet kmem_free(pcix_regs->pcix_ecc_regs, 51200d0963fSdilpreet sizeof (pcix_ecc_regs_t)); 51300d0963fSdilpreet } 51400d0963fSdilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t)); 51500d0963fSdilpreet } 51600d0963fSdilpreet } 51700d0963fSdilpreet 51800d0963fSdilpreet void 51900d0963fSdilpreet pci_ereport_teardown(dev_info_t *dip) 52000d0963fSdilpreet { 52100d0963fSdilpreet struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 52200d0963fSdilpreet pci_erpt_t *erpt_p; 52300d0963fSdilpreet 52400d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 52500d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 52600d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 52700d0963fSdilpreet } 52800d0963fSdilpreet 52900d0963fSdilpreet ASSERT(fmhdl); 53000d0963fSdilpreet 53100d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 53200d0963fSdilpreet if (erpt_p == NULL) 53300d0963fSdilpreet return; 53400d0963fSdilpreet 53549fbdd30SErwin T Tsaur if (erpt_p->pe_dflags & PCIX_DEV) 53600d0963fSdilpreet pcix_ereport_teardown(erpt_p); 53700d0963fSdilpreet pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl); 53800d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) 53900d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs, 54000d0963fSdilpreet sizeof (pci_bdg_error_regs_t)); 54100d0963fSdilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t)); 54200d0963fSdilpreet kmem_free(erpt_p, sizeof (pci_erpt_t)); 54300d0963fSdilpreet fmhdl->fh_bus_specific = NULL; 544eae2e508Skrishnae 54500d0963fSdilpreet /* 54600d0963fSdilpreet * The following sparc specific code should be removed once the pci_cap 54700d0963fSdilpreet * interfaces create the necessary properties for us. 54800d0963fSdilpreet */ 54900d0963fSdilpreet } 55000d0963fSdilpreet 5518aec9182Sstephh /*ARGSUSED*/ 55200d0963fSdilpreet static int 55300d0963fSdilpreet pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, 5548aec9182Sstephh pcix_ecc_regs_t *pcix_ecc_regs, int type) 55500d0963fSdilpreet { 55600d0963fSdilpreet int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf; 55700d0963fSdilpreet uint64_t addr; 5588aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 5598aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 56000d0963fSdilpreet 56100d0963fSdilpreet addr = pcix_ecc_regs->pcix_ecc_secaddr; 56200d0963fSdilpreet addr = addr << 32; 56300d0963fSdilpreet addr |= pcix_ecc_regs->pcix_ecc_fstaddr; 56400d0963fSdilpreet 56500d0963fSdilpreet switch (cmd) { 56600d0963fSdilpreet case PCI_PCIX_CMD_INTR: 56700d0963fSdilpreet case PCI_PCIX_CMD_SPEC: 56800d0963fSdilpreet return (DDI_FM_FATAL); 56900d0963fSdilpreet case PCI_PCIX_CMD_IORD: 57000d0963fSdilpreet case PCI_PCIX_CMD_IOWR: 5718aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 5728aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 5738aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 5748aec9182Sstephh return (DDI_FM_UNKNOWN); 57500d0963fSdilpreet case PCI_PCIX_CMD_DEVID: 57600d0963fSdilpreet return (DDI_FM_FATAL); 57700d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_DW: 57800d0963fSdilpreet case PCI_PCIX_CMD_MEMWR: 57900d0963fSdilpreet case PCI_PCIX_CMD_MEMRD_BL: 58000d0963fSdilpreet case PCI_PCIX_CMD_MEMWR_BL: 5818aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 5828aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 5838aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 5848aec9182Sstephh return (DDI_FM_UNKNOWN); 58500d0963fSdilpreet case PCI_PCIX_CMD_CFRD: 58600d0963fSdilpreet case PCI_PCIX_CMD_CFWR: 5878aec9182Sstephh /* 5888aec9182Sstephh * for type 1 config transaction we can find bdf from address 5898aec9182Sstephh */ 5908aec9182Sstephh if ((addr & 3) == 1) { 5918aec9182Sstephh pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff; 5928aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID; 5938aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 5948aec9182Sstephh } 5958aec9182Sstephh return (DDI_FM_UNKNOWN); 59600d0963fSdilpreet case PCI_PCIX_CMD_SPL: 59700d0963fSdilpreet case PCI_PCIX_CMD_DADR: 5988aec9182Sstephh return (DDI_FM_UNKNOWN); 59900d0963fSdilpreet case PCI_PCIX_CMD_MEMRDBL: 60000d0963fSdilpreet case PCI_PCIX_CMD_MEMWRBL: 6018aec9182Sstephh pci_fme_bsp->pci_bs_addr = addr; 6028aec9182Sstephh pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID; 6038aec9182Sstephh pci_fme_bsp->pci_bs_type = type; 6048aec9182Sstephh return (DDI_FM_UNKNOWN); 60500d0963fSdilpreet default: 60600d0963fSdilpreet return (DDI_FM_FATAL); 60700d0963fSdilpreet } 60800d0963fSdilpreet } 60900d0963fSdilpreet 61000d0963fSdilpreet /*ARGSUSED*/ 61100d0963fSdilpreet static int 61200d0963fSdilpreet pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 61300d0963fSdilpreet { 61400d0963fSdilpreet pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs; 61500d0963fSdilpreet int fatal = 0; 61600d0963fSdilpreet int nonfatal = 0; 61700d0963fSdilpreet int unknown = 0; 61800d0963fSdilpreet int ok = 0; 61900d0963fSdilpreet int ret = DDI_FM_OK; 62000d0963fSdilpreet char buf[FM_MAX_CLASS]; 62100d0963fSdilpreet int i; 6228aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp = 6238aec9182Sstephh (pci_fme_bus_specific_t *)derr->fme_bus_specific; 62400d0963fSdilpreet 62500d0963fSdilpreet if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED) 62600d0963fSdilpreet goto done; 62700d0963fSdilpreet 62800d0963fSdilpreet if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) && 62900d0963fSdilpreet (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) { 63000d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 63100d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_DTO); 63200d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 63300d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 63400d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 63500d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 63600d0963fSdilpreet DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL); 63700d0963fSdilpreet unknown++; 63800d0963fSdilpreet } 63900d0963fSdilpreet 64000d0963fSdilpreet if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) { 64100d0963fSdilpreet for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) { 64200d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & 64300d0963fSdilpreet pci_bdg_err_tbl[i].reg_bit) { 64400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 64500d0963fSdilpreet PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, 64600d0963fSdilpreet pci_bdg_err_tbl[i].err_class); 64700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 64800d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 64900d0963fSdilpreet PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 65000d0963fSdilpreet pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL, 65100d0963fSdilpreet DATA_TYPE_UINT16, 65200d0963fSdilpreet pci_bdg_regs->pci_bdg_ctrl, NULL); 653ac4d633fSstephh PCI_FM_SEV_INC(pci_bdg_err_tbl[i].flags); 6548aec9182Sstephh if (pci_fme_bsp && (pci_fme_bsp->pci_bs_flags & 6558aec9182Sstephh PCI_BS_ADDR_VALID) && 6568aec9182Sstephh pci_fme_bsp->pci_bs_type == ACC_HANDLE && 65700d0963fSdilpreet pci_bdg_err_tbl[i].terr_class) 65800d0963fSdilpreet pci_target_enqueue(derr->fme_ena, 65900d0963fSdilpreet pci_bdg_err_tbl[i].terr_class, 66000d0963fSdilpreet PCI_ERROR_SUBCLASS, 6618aec9182Sstephh pci_fme_bsp->pci_bs_addr); 66200d0963fSdilpreet } 66300d0963fSdilpreet } 66400d0963fSdilpreet } 66500d0963fSdilpreet 66600d0963fSdilpreet done: 66700d0963fSdilpreet /* 66800d0963fSdilpreet * Need to check for poke and cautious put. We already know peek 66900d0963fSdilpreet * and cautious get errors occurred (as we got a trap) and we know 67000d0963fSdilpreet * they are nonfatal. 67100d0963fSdilpreet */ 67200d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_EXPECTED) { 67300d0963fSdilpreet /* 67400d0963fSdilpreet * for cautious puts we treat all errors as nonfatal. Actually 67500d0963fSdilpreet * we set nonfatal for cautious gets as well - doesn't do any 67600d0963fSdilpreet * harm 67700d0963fSdilpreet */ 67800d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 67900d0963fSdilpreet PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR)) 68000d0963fSdilpreet nonfatal++; 68100d0963fSdilpreet } 68200d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_POKE) { 68300d0963fSdilpreet /* 68400d0963fSdilpreet * special case for pokes - we only consider master abort 68500d0963fSdilpreet * and target abort as nonfatal. Sserr with no master abort is 68600d0963fSdilpreet * fatal, but master/target abort can come in on separate 68700d0963fSdilpreet * instance, so return unknown and parent will determine if 68800d0963fSdilpreet * nonfatal (if another child returned nonfatal - ie master 68900d0963fSdilpreet * or target abort) or fatal otherwise 69000d0963fSdilpreet */ 69100d0963fSdilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB | 69200d0963fSdilpreet PCI_STAT_R_MAST_AB)) 69300d0963fSdilpreet nonfatal++; 69400d0963fSdilpreet if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR) 69500d0963fSdilpreet unknown++; 69600d0963fSdilpreet } 69700d0963fSdilpreet 69800d0963fSdilpreet /* 6998aec9182Sstephh * now check children below the bridge 70000d0963fSdilpreet */ 70100d0963fSdilpreet ret = ndi_fm_handler_dispatch(dip, NULL, derr); 70200d0963fSdilpreet PCI_FM_SEV_INC(ret); 70300d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 70400d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 70500d0963fSdilpreet } 70600d0963fSdilpreet 70700d0963fSdilpreet static int 70800d0963fSdilpreet pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 70900d0963fSdilpreet void *pe_regs) 71000d0963fSdilpreet { 71100d0963fSdilpreet pcix_error_regs_t *pcix_regs; 71200d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs; 71300d0963fSdilpreet pcix_ecc_regs_t *pcix_ecc_regs; 71400d0963fSdilpreet int bridge; 71500d0963fSdilpreet int i; 71600d0963fSdilpreet int ecc_phase; 71700d0963fSdilpreet int ecc_corr; 71800d0963fSdilpreet int sec_ue; 71900d0963fSdilpreet int sec_ce; 72000d0963fSdilpreet int fatal = 0; 72100d0963fSdilpreet int nonfatal = 0; 72200d0963fSdilpreet int unknown = 0; 72300d0963fSdilpreet int ok = 0; 72400d0963fSdilpreet char buf[FM_MAX_CLASS]; 72500d0963fSdilpreet 72600d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 72700d0963fSdilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 72800d0963fSdilpreet bridge = 1; 72900d0963fSdilpreet } else { 73000d0963fSdilpreet pcix_regs = (pcix_error_regs_t *)pe_regs; 73100d0963fSdilpreet bridge = 0; 73200d0963fSdilpreet } 73300d0963fSdilpreet 73400d0963fSdilpreet for (i = 0; i < (bridge ? 2 : 1); i++) { 73500d0963fSdilpreet int ret = DDI_FM_OK; 73600d0963fSdilpreet pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] : 73700d0963fSdilpreet pcix_regs->pcix_ecc_regs; 73800d0963fSdilpreet if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) { 73900d0963fSdilpreet ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat & 74000d0963fSdilpreet PCI_PCIX_ECC_PHASE) >> 0x4; 74100d0963fSdilpreet ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat & 74200d0963fSdilpreet PCI_PCIX_ECC_CORR); 74300d0963fSdilpreet sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat & 74400d0963fSdilpreet PCI_PCIX_ECC_S_UE); 74500d0963fSdilpreet sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat & 74600d0963fSdilpreet PCI_PCIX_ECC_S_CE); 74700d0963fSdilpreet 74800d0963fSdilpreet switch (ecc_phase) { 74900d0963fSdilpreet case PCI_PCIX_ECC_PHASE_NOERR: 75000d0963fSdilpreet break; 75100d0963fSdilpreet case PCI_PCIX_ECC_PHASE_FADDR: 75200d0963fSdilpreet case PCI_PCIX_ECC_PHASE_SADDR: 753ac4d633fSstephh PCI_FM_SEV_INC(ecc_corr ? DDI_FM_OK : 75400d0963fSdilpreet DDI_FM_FATAL); 75500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 75600d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 75700d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 75800d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ADDR : 75900d0963fSdilpreet PCIX_ECC_UE_ADDR); 76000d0963fSdilpreet break; 76100d0963fSdilpreet case PCI_PCIX_ECC_PHASE_ATTR: 76200d0963fSdilpreet PCI_FM_SEV_INC(ecc_corr ? 763ac4d633fSstephh DDI_FM_OK : DDI_FM_FATAL); 76400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 76500d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 76600d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 76700d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_ATTR : 76800d0963fSdilpreet PCIX_ECC_UE_ATTR); 76900d0963fSdilpreet break; 77000d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA32: 77100d0963fSdilpreet case PCI_PCIX_ECC_PHASE_DATA64: 77200d0963fSdilpreet if (ecc_corr) 773ac4d633fSstephh ret = DDI_FM_OK; 7748aec9182Sstephh else { 7758aec9182Sstephh int type; 7768aec9182Sstephh pci_error_regs_t *pci_regs = 7778aec9182Sstephh erpt_p->pe_pci_regs; 7788aec9182Sstephh 7798aec9182Sstephh if (i) { 7808aec9182Sstephh if (pci_regs->pci_bdg_regs-> 7818aec9182Sstephh pci_bdg_sec_stat & 7828aec9182Sstephh PCI_STAT_S_PERROR) 7838aec9182Sstephh type = ACC_HANDLE; 78400d0963fSdilpreet else 7858aec9182Sstephh type = DMA_HANDLE; 7868aec9182Sstephh } else { 7878aec9182Sstephh if (pci_regs->pci_err_status & 7888aec9182Sstephh PCI_STAT_S_PERROR) 7898aec9182Sstephh type = DMA_HANDLE; 7908aec9182Sstephh else 7918aec9182Sstephh type = ACC_HANDLE; 7928aec9182Sstephh } 79300d0963fSdilpreet ret = pcix_check_addr(dip, derr, 7948aec9182Sstephh pcix_ecc_regs, type); 7958aec9182Sstephh } 79600d0963fSdilpreet PCI_FM_SEV_INC(ret); 79700d0963fSdilpreet 79800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 79900d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 80000d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 80100d0963fSdilpreet ecc_corr ? PCIX_ECC_CE_DATA : 80200d0963fSdilpreet PCIX_ECC_UE_DATA); 80300d0963fSdilpreet break; 80400d0963fSdilpreet } 80500d0963fSdilpreet if (ecc_phase) 80600d0963fSdilpreet if (bridge) 80700d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 80800d0963fSdilpreet derr->fme_ena, 80900d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 81000d0963fSdilpreet DATA_TYPE_UINT8, 0, 81100d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 81200d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 81300d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 81400d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 81500d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 81600d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 81700d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 81800d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 81900d0963fSdilpreet else 82000d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 82100d0963fSdilpreet derr->fme_ena, 82200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 82300d0963fSdilpreet DATA_TYPE_UINT8, 0, 82400d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 82500d0963fSdilpreet pcix_regs->pcix_command, 82600d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 82700d0963fSdilpreet pcix_regs->pcix_status, 82800d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 82900d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 83000d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 83100d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 83200d0963fSdilpreet if (sec_ce || sec_ue) { 83300d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, 83400d0963fSdilpreet "%s.%s%s", PCIX_ERROR_SUBCLASS, 83500d0963fSdilpreet i ? PCIX_SEC_ERROR_SUBCLASS : "", 83600d0963fSdilpreet sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE); 83700d0963fSdilpreet if (bridge) 83800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 83900d0963fSdilpreet derr->fme_ena, 84000d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 84100d0963fSdilpreet DATA_TYPE_UINT8, 0, 84200d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 84300d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 84400d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 84500d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, 84600d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 84700d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 84800d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 84900d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 85000d0963fSdilpreet else 85100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, 85200d0963fSdilpreet derr->fme_ena, 85300d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, 85400d0963fSdilpreet DATA_TYPE_UINT8, 0, 85500d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 85600d0963fSdilpreet pcix_regs->pcix_command, 85700d0963fSdilpreet PCIX_STATUS, DATA_TYPE_UINT32, 85800d0963fSdilpreet pcix_regs->pcix_status, 85900d0963fSdilpreet PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32, 86000d0963fSdilpreet pcix_ecc_regs->pcix_ecc_ctlstat, 86100d0963fSdilpreet PCIX_ECC_ATTR, DATA_TYPE_UINT32, 86200d0963fSdilpreet pcix_ecc_regs->pcix_ecc_attr, NULL); 86300d0963fSdilpreet PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL : 864ac4d633fSstephh DDI_FM_OK); 86500d0963fSdilpreet } 86600d0963fSdilpreet } 86700d0963fSdilpreet } 86800d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 86900d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 87000d0963fSdilpreet } 87100d0963fSdilpreet 87200d0963fSdilpreet static int 87300d0963fSdilpreet pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p, 87400d0963fSdilpreet void *pe_regs) 87500d0963fSdilpreet { 87600d0963fSdilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs; 87700d0963fSdilpreet int fatal = 0; 87800d0963fSdilpreet int nonfatal = 0; 87900d0963fSdilpreet int unknown = 0; 88000d0963fSdilpreet int ok = 0; 88100d0963fSdilpreet char buf[FM_MAX_CLASS]; 88200d0963fSdilpreet int i; 88300d0963fSdilpreet 88400d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) { 88500d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 88600d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_stat & 88700d0963fSdilpreet pcix_err_tbl[i].reg_bit)) { 88800d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 88900d0963fSdilpreet PCIX_ERROR_SUBCLASS, 89000d0963fSdilpreet pcix_err_tbl[i].err_class); 89100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 89200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 89300d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 89400d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 89500d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 89600d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 89700d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 89800d0963fSdilpreet } 89900d0963fSdilpreet } 90000d0963fSdilpreet } 90100d0963fSdilpreet 90200d0963fSdilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) { 90300d0963fSdilpreet for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) { 90400d0963fSdilpreet if ((pcix_bdg_regs->pcix_bdg_sec_stat & 90500d0963fSdilpreet pcix_sec_err_tbl[i].reg_bit)) { 90600d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s", 90700d0963fSdilpreet PCIX_ERROR_SUBCLASS, 90800d0963fSdilpreet PCIX_SEC_ERROR_SUBCLASS, 90900d0963fSdilpreet pcix_sec_err_tbl[i].err_class); 91000d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 91100d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 91200d0963fSdilpreet PCIX_SEC_STATUS, DATA_TYPE_UINT16, 91300d0963fSdilpreet pcix_bdg_regs->pcix_bdg_sec_stat, 91400d0963fSdilpreet PCIX_BDG_STAT, DATA_TYPE_UINT32, 91500d0963fSdilpreet pcix_bdg_regs->pcix_bdg_stat, NULL); 91600d0963fSdilpreet PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags); 91700d0963fSdilpreet } 91800d0963fSdilpreet } 91900d0963fSdilpreet } 92000d0963fSdilpreet 92100d0963fSdilpreet /* Log/Handle ECC errors */ 92200d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) { 92300d0963fSdilpreet int ret; 92400d0963fSdilpreet 92500d0963fSdilpreet ret = pcix_ecc_error_report(dip, derr, erpt_p, 92600d0963fSdilpreet (void *)pcix_bdg_regs); 92700d0963fSdilpreet PCI_FM_SEV_INC(ret); 92800d0963fSdilpreet } 92900d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 93000d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 93100d0963fSdilpreet } 93200d0963fSdilpreet 93300d0963fSdilpreet static int 93400d0963fSdilpreet pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 93500d0963fSdilpreet { 93600d0963fSdilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs; 93700d0963fSdilpreet int fatal = 0; 93800d0963fSdilpreet int nonfatal = 0; 93900d0963fSdilpreet int unknown = 0; 94000d0963fSdilpreet int ok = 0; 94100d0963fSdilpreet char buf[FM_MAX_CLASS]; 94200d0963fSdilpreet int i; 94300d0963fSdilpreet 94400d0963fSdilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) { 94500d0963fSdilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) { 94600d0963fSdilpreet if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit)) 94700d0963fSdilpreet continue; 94800d0963fSdilpreet 94900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 95000d0963fSdilpreet PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class); 95100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 95200d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 95300d0963fSdilpreet PCIX_COMMAND, DATA_TYPE_UINT16, 95400d0963fSdilpreet pcix_regs->pcix_command, PCIX_STATUS, 95500d0963fSdilpreet DATA_TYPE_UINT32, pcix_regs->pcix_status, 95600d0963fSdilpreet NULL); 95700d0963fSdilpreet PCI_FM_SEV_INC(pcix_err_tbl[i].flags); 95800d0963fSdilpreet } 95900d0963fSdilpreet } 96000d0963fSdilpreet /* Log/Handle ECC errors */ 96100d0963fSdilpreet if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) { 96200d0963fSdilpreet int ret = pcix_ecc_error_report(dip, derr, erpt_p, 96300d0963fSdilpreet (void *)pcix_regs); 96400d0963fSdilpreet PCI_FM_SEV_INC(ret); 96500d0963fSdilpreet } 96600d0963fSdilpreet 96700d0963fSdilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 96800d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 96900d0963fSdilpreet } 97000d0963fSdilpreet 97100d0963fSdilpreet static void 97200d0963fSdilpreet pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p) 97300d0963fSdilpreet { 97400d0963fSdilpreet int fatal = 0; 97500d0963fSdilpreet int nonfatal = 0; 97600d0963fSdilpreet int unknown = 0; 97700d0963fSdilpreet int ok = 0; 97800d0963fSdilpreet char buf[FM_MAX_CLASS]; 97900d0963fSdilpreet int i; 98000d0963fSdilpreet 98100d0963fSdilpreet if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 98200d0963fSdilpreet /* 98300d0963fSdilpreet * Log generic PCI errors. 98400d0963fSdilpreet */ 98500d0963fSdilpreet for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 98600d0963fSdilpreet if (!(erpt_p->pe_pci_regs->pci_err_status & 98700d0963fSdilpreet pci_err_tbl[i].reg_bit) || 98800d0963fSdilpreet !(erpt_p->pe_pci_regs->pci_vflags & 98900d0963fSdilpreet PCI_ERR_STATUS_VALID)) 99000d0963fSdilpreet continue; 99100d0963fSdilpreet /* 99200d0963fSdilpreet * Generate an ereport for this error bit. 99300d0963fSdilpreet */ 99400d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 99500d0963fSdilpreet PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class); 99600d0963fSdilpreet ddi_fm_ereport_post(dip, buf, derr->fme_ena, 99700d0963fSdilpreet DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 99800d0963fSdilpreet PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 99900d0963fSdilpreet erpt_p->pe_pci_regs->pci_err_status, 100000d0963fSdilpreet PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 100100d0963fSdilpreet erpt_p->pe_pci_regs->pci_cfg_comm, NULL); 100200d0963fSdilpreet 100300d0963fSdilpreet PCI_FM_SEV_INC(pci_err_tbl[i].flags); 100400d0963fSdilpreet } 100549fbdd30SErwin T Tsaur if (erpt_p->pe_dflags & PCIX_DEV) { 100600d0963fSdilpreet if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) { 100700d0963fSdilpreet int ret = pcix_bdg_error_report(dip, derr, 100800d0963fSdilpreet erpt_p, erpt_p->pe_regs); 100900d0963fSdilpreet PCI_FM_SEV_INC(ret); 101000d0963fSdilpreet } else { 101100d0963fSdilpreet int ret = pcix_error_report(dip, derr, erpt_p); 101200d0963fSdilpreet PCI_FM_SEV_INC(ret); 101300d0963fSdilpreet } 101400d0963fSdilpreet } 101500d0963fSdilpreet } 101600d0963fSdilpreet 101700d0963fSdilpreet if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) { 101800d0963fSdilpreet int ret = pci_bdg_error_report(dip, derr, erpt_p); 101900d0963fSdilpreet PCI_FM_SEV_INC(ret); 102000d0963fSdilpreet } 102100d0963fSdilpreet 10228aec9182Sstephh if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 10238aec9182Sstephh pci_fme_bus_specific_t *pci_fme_bsp; 10248aec9182Sstephh int ret = DDI_FM_UNKNOWN; 10258aec9182Sstephh 10268aec9182Sstephh pci_fme_bsp = (pci_fme_bus_specific_t *)derr->fme_bus_specific; 10278aec9182Sstephh if (pci_fme_bsp->pci_bs_flags & PCI_BS_ADDR_VALID) { 10288aec9182Sstephh ret = ndi_fmc_entry_error(dip, 10298aec9182Sstephh pci_fme_bsp->pci_bs_type, derr, 10308aec9182Sstephh (void *)&pci_fme_bsp->pci_bs_addr); 10318aec9182Sstephh PCI_FM_SEV_INC(ret); 10328aec9182Sstephh } 10338aec9182Sstephh /* 10348aec9182Sstephh * If we didn't find the handle using an addr, try using bdf. 10358aec9182Sstephh * Note we don't do this where the bdf is for a 10368aec9182Sstephh * device behind a pciex/pci bridge as the bridge may have 10378aec9182Sstephh * fabricated the bdf. 10388aec9182Sstephh */ 10398aec9182Sstephh if (ret == DDI_FM_UNKNOWN && 10408aec9182Sstephh (pci_fme_bsp->pci_bs_flags & PCI_BS_BDF_VALID) && 104149fbdd30SErwin T Tsaur pci_fme_bsp->pci_bs_bdf == erpt_p->pe_bdf) { 10428aec9182Sstephh ret = ndi_fmc_entry_error_all(dip, 10438aec9182Sstephh pci_fme_bsp->pci_bs_type, derr); 10448aec9182Sstephh PCI_FM_SEV_INC(ret); 10458aec9182Sstephh } 10468aec9182Sstephh } 10478aec9182Sstephh 104800d0963fSdilpreet derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 104900d0963fSdilpreet (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 105000d0963fSdilpreet } 105100d0963fSdilpreet 105200d0963fSdilpreet void 105300d0963fSdilpreet pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status) 105400d0963fSdilpreet { 105500d0963fSdilpreet struct i_ddi_fmhdl *fmhdl; 105600d0963fSdilpreet pci_erpt_t *erpt_p; 10578aec9182Sstephh ddi_fm_error_t de; 10588aec9182Sstephh pci_fme_bus_specific_t pci_fme_bs; 105900d0963fSdilpreet 1060eae2e508Skrishnae /* 1061eae2e508Skrishnae * On PCI Express systems, all error handling and ereport are done via 1062eae2e508Skrishnae * the PCIe misc module. This function is a no-op for PCIe Systems. In 1063eae2e508Skrishnae * order to tell if a system is a PCI or PCIe system, check that the 1064eae2e508Skrishnae * bus_private_data exists. If it exists, this is a PCIe system. 1065eae2e508Skrishnae */ 1066eae2e508Skrishnae if (ndi_get_bus_private(dip, B_TRUE)) { 1067eae2e508Skrishnae derr->fme_status = DDI_FM_OK; 1068eae2e508Skrishnae if (xx_status != NULL) 1069eae2e508Skrishnae *xx_status = 0x0; 1070eae2e508Skrishnae 1071eae2e508Skrishnae return; 1072eae2e508Skrishnae } 1073eae2e508Skrishnae 107400d0963fSdilpreet fmhdl = DEVI(dip)->devi_fmhdl; 107500d0963fSdilpreet if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) && 107600d0963fSdilpreet !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) { 107700d0963fSdilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 107800d0963fSdilpreet return; 107900d0963fSdilpreet } 108000d0963fSdilpreet 10818aec9182Sstephh /* 10828aec9182Sstephh * copy in the ddi_fm_error_t structure in case it's VER0 10838aec9182Sstephh */ 10848aec9182Sstephh de.fme_version = derr->fme_version; 10858aec9182Sstephh de.fme_status = derr->fme_status; 10868aec9182Sstephh de.fme_flag = derr->fme_flag; 10878aec9182Sstephh de.fme_ena = derr->fme_ena; 10888aec9182Sstephh de.fme_acc_handle = derr->fme_acc_handle; 10898aec9182Sstephh de.fme_dma_handle = derr->fme_dma_handle; 10908aec9182Sstephh de.fme_bus_specific = derr->fme_bus_specific; 10918aec9182Sstephh if (derr->fme_version >= DDI_FME_VER1) 10928aec9182Sstephh de.fme_bus_type = derr->fme_bus_type; 10938aec9182Sstephh else 10948aec9182Sstephh de.fme_bus_type = DDI_FME_BUS_TYPE_DFLT; 10958aec9182Sstephh if (de.fme_bus_type == DDI_FME_BUS_TYPE_DFLT) { 10968aec9182Sstephh /* 10978aec9182Sstephh * if this is the first pci device we've found convert 10988aec9182Sstephh * fme_bus_specific to DDI_FME_BUS_TYPE_PCI 10998aec9182Sstephh */ 11008aec9182Sstephh bzero(&pci_fme_bs, sizeof (pci_fme_bs)); 11018aec9182Sstephh if (de.fme_bus_specific) { 11028aec9182Sstephh /* 11038aec9182Sstephh * the cpu passed us an addr - this can be used to look 11048aec9182Sstephh * up an access handle 11058aec9182Sstephh */ 11068aec9182Sstephh pci_fme_bs.pci_bs_addr = (uintptr_t)de.fme_bus_specific; 11078aec9182Sstephh pci_fme_bs.pci_bs_type = ACC_HANDLE; 11088aec9182Sstephh pci_fme_bs.pci_bs_flags |= PCI_BS_ADDR_VALID; 11098aec9182Sstephh } 11108aec9182Sstephh de.fme_bus_specific = (void *)&pci_fme_bs; 11118aec9182Sstephh de.fme_bus_type = DDI_FME_BUS_TYPE_PCI; 11128aec9182Sstephh } 11138aec9182Sstephh 111400d0963fSdilpreet ASSERT(fmhdl); 111500d0963fSdilpreet 11168aec9182Sstephh if (de.fme_ena == NULL) 11178aec9182Sstephh de.fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 111800d0963fSdilpreet 111900d0963fSdilpreet erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 1120ac4d633fSstephh if (erpt_p == NULL) 112100d0963fSdilpreet return; 112200d0963fSdilpreet 11238aec9182Sstephh pci_regs_gather(dip, erpt_p, de.fme_flag); 11248aec9182Sstephh pci_error_report(dip, &de, erpt_p); 112500d0963fSdilpreet pci_regs_clear(erpt_p); 112600d0963fSdilpreet 11278aec9182Sstephh derr->fme_status = de.fme_status; 11288aec9182Sstephh derr->fme_ena = de.fme_ena; 11298aec9182Sstephh derr->fme_acc_handle = de.fme_acc_handle; 11308aec9182Sstephh derr->fme_dma_handle = de.fme_dma_handle; 113100d0963fSdilpreet if (xx_status != NULL) 113200d0963fSdilpreet *xx_status = erpt_p->pe_pci_regs->pci_err_status; 113300d0963fSdilpreet } 113400d0963fSdilpreet 113500d0963fSdilpreet /* 113600d0963fSdilpreet * private version of walk_devs() that can be used during panic. No 113700d0963fSdilpreet * sleeping or locking required. 113800d0963fSdilpreet */ 113900d0963fSdilpreet static int 114000d0963fSdilpreet pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg) 114100d0963fSdilpreet { 114200d0963fSdilpreet while (dip) { 114300d0963fSdilpreet switch ((*f)(dip, arg)) { 114400d0963fSdilpreet case DDI_WALK_TERMINATE: 114500d0963fSdilpreet return (DDI_WALK_TERMINATE); 114600d0963fSdilpreet case DDI_WALK_CONTINUE: 114700d0963fSdilpreet if (pci_fm_walk_devs(ddi_get_child(dip), f, 114800d0963fSdilpreet arg) == DDI_WALK_TERMINATE) 114900d0963fSdilpreet return (DDI_WALK_TERMINATE); 115000d0963fSdilpreet break; 115100d0963fSdilpreet case DDI_WALK_PRUNECHILD: 115200d0963fSdilpreet break; 115300d0963fSdilpreet } 115400d0963fSdilpreet dip = ddi_get_next_sibling(dip); 115500d0963fSdilpreet } 115600d0963fSdilpreet return (DDI_WALK_CONTINUE); 115700d0963fSdilpreet } 115800d0963fSdilpreet 115900d0963fSdilpreet /* 116000d0963fSdilpreet * need special version of ddi_fm_ereport_post() as the leaf driver may 116100d0963fSdilpreet * not be hardened. 116200d0963fSdilpreet */ 116300d0963fSdilpreet static void 116400d0963fSdilpreet pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena, 116500d0963fSdilpreet uint8_t version, ...) 116600d0963fSdilpreet { 116700d0963fSdilpreet char *name; 116800d0963fSdilpreet char device_path[MAXPATHLEN]; 116900d0963fSdilpreet char ddi_error_class[FM_MAX_CLASS]; 117000d0963fSdilpreet nvlist_t *ereport, *detector; 117100d0963fSdilpreet nv_alloc_t *nva; 117200d0963fSdilpreet errorq_elem_t *eqep; 117300d0963fSdilpreet va_list ap; 117400d0963fSdilpreet 117500d0963fSdilpreet if (panicstr) { 117600d0963fSdilpreet eqep = errorq_reserve(ereport_errorq); 117700d0963fSdilpreet if (eqep == NULL) 117800d0963fSdilpreet return; 117900d0963fSdilpreet ereport = errorq_elem_nvl(ereport_errorq, eqep); 118000d0963fSdilpreet nva = errorq_elem_nva(ereport_errorq, eqep); 118100d0963fSdilpreet detector = fm_nvlist_create(nva); 118200d0963fSdilpreet } else { 118300d0963fSdilpreet ereport = fm_nvlist_create(NULL); 118400d0963fSdilpreet detector = fm_nvlist_create(NULL); 118500d0963fSdilpreet } 118600d0963fSdilpreet 118700d0963fSdilpreet (void) ddi_pathname(dip, device_path); 118800d0963fSdilpreet fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, 1189*392e836bSGavin Maltby device_path, NULL, NULL); 119000d0963fSdilpreet (void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s", 119100d0963fSdilpreet DDI_IO_CLASS, error_class); 119200d0963fSdilpreet fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL); 119300d0963fSdilpreet 119400d0963fSdilpreet va_start(ap, version); 119500d0963fSdilpreet name = va_arg(ap, char *); 119600d0963fSdilpreet (void) i_fm_payload_set(ereport, name, ap); 119700d0963fSdilpreet va_end(ap); 119800d0963fSdilpreet 119900d0963fSdilpreet if (panicstr) { 120000d0963fSdilpreet errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); 120100d0963fSdilpreet } else { 120200d0963fSdilpreet (void) fm_ereport_post(ereport, EVCH_TRYHARD); 120300d0963fSdilpreet fm_nvlist_destroy(ereport, FM_NVA_FREE); 120400d0963fSdilpreet fm_nvlist_destroy(detector, FM_NVA_FREE); 120500d0963fSdilpreet } 120600d0963fSdilpreet } 120700d0963fSdilpreet 120800d0963fSdilpreet static int 120900d0963fSdilpreet pci_check_regs(dev_info_t *dip, void *arg) 121000d0963fSdilpreet { 121100d0963fSdilpreet int reglen; 121200d0963fSdilpreet int rn; 121300d0963fSdilpreet int totreg; 121400d0963fSdilpreet pci_regspec_t *drv_regp; 121500d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 121600d0963fSdilpreet 121700d0963fSdilpreet if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 121800d0963fSdilpreet /* 121900d0963fSdilpreet * for config space, we need to check if the given address 122000d0963fSdilpreet * is a valid config space address for this device - based 122100d0963fSdilpreet * on pci_phys_hi of the config space entry in reg property. 122200d0963fSdilpreet */ 122300d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 122400d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 122500d0963fSdilpreet return (DDI_WALK_CONTINUE); 122600d0963fSdilpreet 122700d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 122800d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 122900d0963fSdilpreet if (tgt_err->tgt_pci_space == 123000d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) && 123100d0963fSdilpreet (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M | 123200d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M)) == 123300d0963fSdilpreet (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M | 123400d0963fSdilpreet PCI_REG_DEV_M | PCI_REG_FUNC_M))) { 123500d0963fSdilpreet tgt_err->tgt_dip = dip; 123600d0963fSdilpreet kmem_free(drv_regp, reglen); 123700d0963fSdilpreet return (DDI_WALK_TERMINATE); 123800d0963fSdilpreet } 123900d0963fSdilpreet } 124000d0963fSdilpreet kmem_free(drv_regp, reglen); 124100d0963fSdilpreet } else { 124200d0963fSdilpreet /* 124300d0963fSdilpreet * for non config space, need to check reg to look 124400d0963fSdilpreet * for any non-relocable mapping, otherwise check 124500d0963fSdilpreet * assigned-addresses. 124600d0963fSdilpreet */ 124700d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 124800d0963fSdilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 124900d0963fSdilpreet return (DDI_WALK_CONTINUE); 125000d0963fSdilpreet 125100d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 125200d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 125300d0963fSdilpreet if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) && 125400d0963fSdilpreet (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 125500d0963fSdilpreet tgt_err->tgt_pci_space == 125600d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 125700d0963fSdilpreet (tgt_err->tgt_pci_addr >= 125800d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 125900d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 126000d0963fSdilpreet (tgt_err->tgt_pci_addr < 126100d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 126200d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 126300d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 126400d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 126500d0963fSdilpreet tgt_err->tgt_dip = dip; 126600d0963fSdilpreet kmem_free(drv_regp, reglen); 126700d0963fSdilpreet return (DDI_WALK_TERMINATE); 126800d0963fSdilpreet } 126900d0963fSdilpreet } 127000d0963fSdilpreet kmem_free(drv_regp, reglen); 127100d0963fSdilpreet 127200d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 127300d0963fSdilpreet "assigned-addresses", (caddr_t)&drv_regp, ®len) != 127400d0963fSdilpreet DDI_SUCCESS) 127500d0963fSdilpreet return (DDI_WALK_CONTINUE); 127600d0963fSdilpreet 127700d0963fSdilpreet totreg = reglen / sizeof (pci_regspec_t); 127800d0963fSdilpreet for (rn = 0; rn < totreg; rn++) { 127900d0963fSdilpreet if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN || 128000d0963fSdilpreet tgt_err->tgt_pci_space == 128100d0963fSdilpreet PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) && 128200d0963fSdilpreet (tgt_err->tgt_pci_addr >= 128300d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 128400d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) && 128500d0963fSdilpreet (tgt_err->tgt_pci_addr < 128600d0963fSdilpreet (uint64_t)drv_regp[rn].pci_phys_low + 128700d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_phys_mid << 32) + 128800d0963fSdilpreet (uint64_t)drv_regp[rn].pci_size_low + 128900d0963fSdilpreet ((uint64_t)drv_regp[rn].pci_size_hi << 32))) { 129000d0963fSdilpreet tgt_err->tgt_dip = dip; 129100d0963fSdilpreet kmem_free(drv_regp, reglen); 129200d0963fSdilpreet return (DDI_WALK_TERMINATE); 129300d0963fSdilpreet } 129400d0963fSdilpreet } 129500d0963fSdilpreet kmem_free(drv_regp, reglen); 129600d0963fSdilpreet } 129700d0963fSdilpreet return (DDI_WALK_CONTINUE); 129800d0963fSdilpreet } 129900d0963fSdilpreet 130000d0963fSdilpreet /* 130100d0963fSdilpreet * impl_fix_ranges - fixes the config space entry of the "ranges" 130200d0963fSdilpreet * property on psycho+ platforms. (if changing this function please make sure 130300d0963fSdilpreet * to change the pci_fix_ranges function in pcipsy.c) 130400d0963fSdilpreet */ 130500d0963fSdilpreet /*ARGSUSED*/ 130600d0963fSdilpreet static void 130700d0963fSdilpreet pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange) 130800d0963fSdilpreet { 130900d0963fSdilpreet #if defined(__sparc) 131000d0963fSdilpreet char *name = ddi_binding_name(dip); 131100d0963fSdilpreet 131200d0963fSdilpreet if ((strcmp(name, "pci108e,8000") == 0) || 131300d0963fSdilpreet (strcmp(name, "pci108e,a000") == 0) || 131400d0963fSdilpreet (strcmp(name, "pci108e,a001") == 0)) { 131500d0963fSdilpreet int i; 131600d0963fSdilpreet for (i = 0; i < nrange; i++, pci_ranges++) 131700d0963fSdilpreet if ((pci_ranges->child_high & PCI_REG_ADDR_M) == 131800d0963fSdilpreet PCI_ADDR_CONFIG) 131900d0963fSdilpreet pci_ranges->parent_low |= 132000d0963fSdilpreet pci_ranges->child_high; 132100d0963fSdilpreet } 132200d0963fSdilpreet #endif 132300d0963fSdilpreet } 132400d0963fSdilpreet 132500d0963fSdilpreet static int 132600d0963fSdilpreet pci_check_ranges(dev_info_t *dip, void *arg) 132700d0963fSdilpreet { 132800d0963fSdilpreet uint64_t range_parent_begin; 132900d0963fSdilpreet uint64_t range_parent_size; 133000d0963fSdilpreet uint64_t range_parent_end; 133100d0963fSdilpreet uint32_t space_type; 133200d0963fSdilpreet uint32_t bus_num; 133300d0963fSdilpreet uint32_t range_offset; 133400d0963fSdilpreet pci_ranges_t *pci_ranges, *rangep; 133500d0963fSdilpreet pci_bus_range_t *pci_bus_rangep; 133600d0963fSdilpreet int pci_ranges_length; 133700d0963fSdilpreet int nrange; 133800d0963fSdilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg; 133900d0963fSdilpreet int i, size; 134000d0963fSdilpreet if (strcmp(ddi_node_name(dip), "pci") != 0 && 134100d0963fSdilpreet strcmp(ddi_node_name(dip), "pciex") != 0) 134200d0963fSdilpreet return (DDI_WALK_CONTINUE); 134300d0963fSdilpreet 134400d0963fSdilpreet /* 134500d0963fSdilpreet * Get the ranges property. Note we only look at the top level pci 134600d0963fSdilpreet * node (hostbridge) which has a ranges property of type pci_ranges_t 134700d0963fSdilpreet * not at pci-pci bridges. 134800d0963fSdilpreet */ 134900d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 135000d0963fSdilpreet (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) { 135100d0963fSdilpreet /* 135200d0963fSdilpreet * no ranges property - no translation needed 135300d0963fSdilpreet */ 135400d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr; 135500d0963fSdilpreet tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN; 135600d0963fSdilpreet if (panicstr) 135700d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 135800d0963fSdilpreet pci_check_regs, (void *)tgt_err); 135900d0963fSdilpreet else { 136000d0963fSdilpreet int circ = 0; 136100d0963fSdilpreet ndi_devi_enter(dip, &circ); 136200d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 136300d0963fSdilpreet (void *)tgt_err); 136400d0963fSdilpreet ndi_devi_exit(dip, circ); 136500d0963fSdilpreet } 136600d0963fSdilpreet if (tgt_err->tgt_dip != NULL) 136700d0963fSdilpreet return (DDI_WALK_TERMINATE); 136800d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 136900d0963fSdilpreet } 137000d0963fSdilpreet nrange = pci_ranges_length / sizeof (pci_ranges_t); 137100d0963fSdilpreet rangep = pci_ranges; 137200d0963fSdilpreet 137300d0963fSdilpreet /* Need to fix the pci ranges property for psycho based systems */ 137400d0963fSdilpreet pci_fix_ranges(dip, pci_ranges, nrange); 137500d0963fSdilpreet 137600d0963fSdilpreet for (i = 0; i < nrange; i++, rangep++) { 137700d0963fSdilpreet range_parent_begin = ((uint64_t)rangep->parent_high << 32) + 137800d0963fSdilpreet rangep->parent_low; 137900d0963fSdilpreet range_parent_size = ((uint64_t)rangep->size_high << 32) + 138000d0963fSdilpreet rangep->size_low; 138100d0963fSdilpreet range_parent_end = range_parent_begin + range_parent_size - 1; 138200d0963fSdilpreet 138300d0963fSdilpreet if ((tgt_err->tgt_err_addr < range_parent_begin) || 138400d0963fSdilpreet (tgt_err->tgt_err_addr > range_parent_end)) { 138500d0963fSdilpreet /* Not in range */ 138600d0963fSdilpreet continue; 138700d0963fSdilpreet } 138800d0963fSdilpreet space_type = PCI_REG_ADDR_G(rangep->child_high); 138900d0963fSdilpreet if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 139000d0963fSdilpreet /* Config space address - check bus range */ 139100d0963fSdilpreet range_offset = tgt_err->tgt_err_addr - 139200d0963fSdilpreet range_parent_begin; 139300d0963fSdilpreet bus_num = PCI_REG_BUS_G(range_offset); 139400d0963fSdilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 139500d0963fSdilpreet DDI_PROP_DONTPASS, "bus-range", 139600d0963fSdilpreet (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) { 139700d0963fSdilpreet continue; 139800d0963fSdilpreet } 139900d0963fSdilpreet if ((bus_num < pci_bus_rangep->lo) || 140000d0963fSdilpreet (bus_num > pci_bus_rangep->hi)) { 140100d0963fSdilpreet /* 140200d0963fSdilpreet * Bus number not appropriate for this 140300d0963fSdilpreet * pci nexus. 140400d0963fSdilpreet */ 140500d0963fSdilpreet kmem_free(pci_bus_rangep, size); 140600d0963fSdilpreet continue; 140700d0963fSdilpreet } 140800d0963fSdilpreet kmem_free(pci_bus_rangep, size); 140900d0963fSdilpreet } 141000d0963fSdilpreet 141100d0963fSdilpreet /* We have a match if we get here - compute pci address */ 141200d0963fSdilpreet tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr - 141300d0963fSdilpreet range_parent_begin; 141400d0963fSdilpreet tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) + 141500d0963fSdilpreet rangep->child_low); 141600d0963fSdilpreet tgt_err->tgt_pci_space = space_type; 141700d0963fSdilpreet if (panicstr) 141800d0963fSdilpreet (void) pci_fm_walk_devs(ddi_get_child(dip), 141900d0963fSdilpreet pci_check_regs, (void *)tgt_err); 142000d0963fSdilpreet else { 142100d0963fSdilpreet int circ = 0; 142200d0963fSdilpreet ndi_devi_enter(dip, &circ); 142300d0963fSdilpreet ddi_walk_devs(ddi_get_child(dip), pci_check_regs, 142400d0963fSdilpreet (void *)tgt_err); 142500d0963fSdilpreet ndi_devi_exit(dip, circ); 142600d0963fSdilpreet } 142700d0963fSdilpreet if (tgt_err->tgt_dip != NULL) { 142800d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 142900d0963fSdilpreet return (DDI_WALK_TERMINATE); 143000d0963fSdilpreet } 143100d0963fSdilpreet } 143200d0963fSdilpreet kmem_free(pci_ranges, pci_ranges_length); 143300d0963fSdilpreet return (DDI_WALK_PRUNECHILD); 143400d0963fSdilpreet } 143500d0963fSdilpreet 143600d0963fSdilpreet /* 143700d0963fSdilpreet * Function used to drain pci_target_queue, either during panic or after softint 143800d0963fSdilpreet * is generated, to generate target device ereports based on captured physical 143900d0963fSdilpreet * addresses 144000d0963fSdilpreet */ 144100d0963fSdilpreet /*ARGSUSED*/ 144200d0963fSdilpreet static void 144300d0963fSdilpreet pci_target_drain(void *private_p, pci_target_err_t *tgt_err) 144400d0963fSdilpreet { 144500d0963fSdilpreet char buf[FM_MAX_CLASS]; 144600d0963fSdilpreet 144700d0963fSdilpreet /* 144800d0963fSdilpreet * The following assumes that all pci_pci bridge devices 144900d0963fSdilpreet * are configured as transparant. Find the top-level pci 145000d0963fSdilpreet * nexus which has tgt_err_addr in one of its ranges, converting this 145100d0963fSdilpreet * to a pci address in the process. Then starting at this node do 145200d0963fSdilpreet * another tree walk to find a device with the pci address we've 145300d0963fSdilpreet * found within range of one of it's assigned-addresses properties. 145400d0963fSdilpreet */ 145500d0963fSdilpreet tgt_err->tgt_dip = NULL; 145600d0963fSdilpreet if (panicstr) 145700d0963fSdilpreet (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges, 145800d0963fSdilpreet (void *)tgt_err); 145900d0963fSdilpreet else 146000d0963fSdilpreet ddi_walk_devs(ddi_root_node(), pci_check_ranges, 146100d0963fSdilpreet (void *)tgt_err); 146200d0963fSdilpreet if (tgt_err->tgt_dip == NULL) 146300d0963fSdilpreet return; 146400d0963fSdilpreet 146500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type, 146600d0963fSdilpreet tgt_err->tgt_err_class); 146700d0963fSdilpreet pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0, 146800d0963fSdilpreet PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL); 146900d0963fSdilpreet } 147000d0963fSdilpreet 147100d0963fSdilpreet void 147200d0963fSdilpreet pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr) 147300d0963fSdilpreet { 147400d0963fSdilpreet pci_target_err_t tgt_err; 147500d0963fSdilpreet 147600d0963fSdilpreet tgt_err.tgt_err_ena = ena; 147700d0963fSdilpreet tgt_err.tgt_err_class = class; 147800d0963fSdilpreet tgt_err.tgt_bridge_type = bridge_type; 147900d0963fSdilpreet tgt_err.tgt_err_addr = addr; 148000d0963fSdilpreet errorq_dispatch(pci_target_queue, (void *)&tgt_err, 148100d0963fSdilpreet sizeof (pci_target_err_t), ERRORQ_ASYNC); 148200d0963fSdilpreet } 148300d0963fSdilpreet 148400d0963fSdilpreet void 148500d0963fSdilpreet pci_targetq_init(void) 148600d0963fSdilpreet { 148700d0963fSdilpreet /* 148800d0963fSdilpreet * PCI target errorq, to schedule async handling of generation of 148900d0963fSdilpreet * target device ereports based on captured physical address. 149000d0963fSdilpreet * The errorq is created here but destroyed when _fini is called 149100d0963fSdilpreet * for the pci module. 149200d0963fSdilpreet */ 149300d0963fSdilpreet if (pci_target_queue == NULL) { 149400d0963fSdilpreet pci_target_queue = errorq_create("pci_target_queue", 149500d0963fSdilpreet (errorq_func_t)pci_target_drain, (void *)NULL, 149600d0963fSdilpreet TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL, 149700d0963fSdilpreet ERRORQ_VITAL); 149800d0963fSdilpreet if (pci_target_queue == NULL) 149900d0963fSdilpreet panic("failed to create required system error queue"); 150000d0963fSdilpreet } 150100d0963fSdilpreet } 1502