pcifm.c revision 392e836b07e8da771953e4d64233b2abe4393efe
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * CDDL HEADER START
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * The contents of this file are subject to the terms of the
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Common Development and Distribution License (the "License").
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * You may not use this file except in compliance with the License.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * See the License for the specific language governing permissions
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * and limitations under the License.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * When distributing Covered Code, include this CDDL HEADER in each
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * If applicable, add the following below this CDDL HEADER, with the
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * fields enclosed by brackets "[]" replaced with your own identifying
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * information: Portions Copyright [yyyy] [name of copyright owner]
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * CDDL HEADER END
392e836b07e8da771953e4d64233b2abe4393efeGavin Maltby * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet#define PCIX_ECC_VER_CHECK(x) (((x) == PCI_PCIX_VER_1) ||\
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_SIG_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_FATAL,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_DET_PERR, PCI_STAT_PERROR, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_REC_SERR, PCI_STAT_S_SYSERR, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCIX_SPL_DIS, PCI_PCIX_SPL_DSCD, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCIX_UNEX_SPL, PCI_PCIX_UNEX_SPL, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCIX_RX_SPL_MSG, PCI_PCIX_RX_SPL_MSG, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCIX_SPL_DIS, PCI_PCIX_BSS_SPL_DSCD, NULL, DDI_FM_UNKNOWN,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCIX_UNEX_SPL, PCI_PCIX_BSS_UNEX_SPL, NULL, DDI_FM_UNKNOWN,
ac4d633f367252125bb35e97c5725d2aa68c1291stephh PCIX_BSS_SPL_OR, PCI_PCIX_BSS_SPL_OR, NULL, DDI_FM_OK,
ac4d633f367252125bb35e97c5725d2aa68c1291stephh PCIX_BSS_SPL_DLY, PCI_PCIX_BSS_SPL_DLY, NULL, DDI_FM_OK,
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephhpci_config_check(ddi_acc_handle_t handle, int fme_flag)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip))))
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl,
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR)));
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephhpcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs, int fme_flag)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16(
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS));
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl,
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur for (i = 0; i < 2; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl,
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet/*ARGSUSED*/
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephhpci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p, int fme_flag)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Start by reading all the error registers that are available for
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * pci and pci express and for leaf devices and bridges/switches
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl,
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl,
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * If pci-pci bridge grab PCI bridge specific error registers.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS);
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur /* If pci-x device grab error registers */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur for (i = 0; i < 2; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Finally clear the error bits
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * generation.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet/* ARGSUSED */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur uint16_t pcix_cap_ptr = PCI_CAP_NEXT_PTR_NULL;
be84494cdccacd78ec75f82fb1d837585975ffd2Krishna Elango if (pci_config_setup(dip, &eh) == DDI_SUCCESS) {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur (void) PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCIX, &pcix_cap_ptr);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t),
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet for (i = 0; i < 2; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t),
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * pci_ereport_setup: Detect PCI device type and initialize structures to be
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * used to generate ereports based on detected generic device errors.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * If device is not ereport capbable then report an error against the
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * driver for using this interface,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * ASSERT fmhdl exists and fh_bus_specific is NULL.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT);
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) !=
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Get header type and record if device is a bridge.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER);
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) !=
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Check to see if PCI device is a bridge, if so allocate pci bridge
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * error register structure.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >>
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur /* Initialize structures for PCI-X devices. */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Before returning set fh_bus_specific to completed pci_erpt_t
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * structure
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet for (i = 0; i < 2; i++)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t));
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t));
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * The following sparc specific code should be removed once the pci_cap
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * interfaces create the necessary properties for us.
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh/*ARGSUSED*/
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf;
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * for type 1 config transaction we can find bdf from address
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet/*ARGSUSED*/
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) &&
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Need to check for poke and cautious put. We already know peek
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * and cautious get errors occurred (as we got a trap) and we know
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * they are nonfatal.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * for cautious puts we treat all errors as nonfatal. Actually
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * we set nonfatal for cautious gets as well - doesn't do any
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR))
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * special case for pokes - we only consider master abort
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * and target abort as nonfatal. Sserr with no master abort is
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * fatal, but master/target abort can come in on separate
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * instance, so return unknown and parent will determine if
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * nonfatal (if another child returned nonfatal - ie master
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * or target abort) or fatal otherwise
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR)
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * now check children below the bridge
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] :
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* Log/Handle ECC errors */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit))
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* Log/Handle ECC errors */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Log generic PCI errors.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet for (i = 0; pci_err_tbl[i].err_class != NULL; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Generate an ereport for this error bit.
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh pci_fme_bsp = (pci_fme_bus_specific_t *)derr->fme_bus_specific;
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * If we didn't find the handle using an addr, try using bdf.
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * Note we don't do this where the bdf is for a
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * device behind a pciex/pci bridge as the bridge may have
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * fabricated the bdf.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status)
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * On PCI Express systems, all error handling and ereport are done via
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * the PCIe misc module. This function is a no-op for PCIe Systems. In
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * order to tell if a system is a PCI or PCIe system, check that the
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * bus_private_data exists. If it exists, this is a PCIe system.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP);
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * copy in the ddi_fm_error_t structure in case it's VER0
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * if this is the first pci device we've found convert
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * fme_bus_specific to DDI_FME_BUS_TYPE_PCI
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * the cpu passed us an addr - this can be used to look
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh * up an access handle
8aec91825357bbeaf2ab5d30fc97fe5051a6b8ddstephh pci_fme_bs.pci_bs_addr = (uintptr_t)de.fme_bus_specific;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * private version of walk_devs() that can be used during panic. No
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * sleeping or locking required.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * need special version of ddi_fm_ereport_post() as the leaf driver may
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * not be hardened.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s",
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * for config space, we need to check if the given address
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * is a valid config space address for this device - based
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * on pci_phys_hi of the config space entry in reg property.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * for non config space, need to check reg to look
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * for any non-relocable mapping, otherwise check
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * assigned-addresses.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet "assigned-addresses", (caddr_t)&drv_regp, ®len) !=
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * impl_fix_ranges - fixes the config space entry of the "ranges"
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * property on psycho+ platforms. (if changing this function please make sure
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * to change the pci_fix_ranges function in pcipsy.c)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet/*ARGSUSED*/
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Get the ranges property. Note we only look at the top level pci
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * node (hostbridge) which has a ranges property of type pci_ranges_t
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * not at pci-pci bridges.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * no ranges property - no translation needed
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet nrange = pci_ranges_length / sizeof (pci_ranges_t);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* Need to fix the pci ranges property for psycho based systems */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet range_parent_begin = ((uint64_t)rangep->parent_high << 32) +
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet range_parent_size = ((uint64_t)rangep->size_high << 32) +
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet range_parent_end = range_parent_begin + range_parent_size - 1;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if ((tgt_err->tgt_err_addr < range_parent_begin) ||
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* Not in range */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* Config space address - check bus range */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Bus number not appropriate for this
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * pci nexus.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* We have a match if we get here - compute pci address */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) +
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Function used to drain pci_target_queue, either during panic or after softint
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * is generated, to generate target device ereports based on captured physical
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * addresses
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet/*ARGSUSED*/
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpci_target_drain(void *private_p, pci_target_err_t *tgt_err)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * The following assumes that all pci_pci bridge devices
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * are configured as transparant. Find the top-level pci
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * nexus which has tgt_err_addr in one of its ranges, converting this
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * to a pci address in the process. Then starting at this node do
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * another tree walk to find a device with the pci address we've
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * found within range of one of it's assigned-addresses properties.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetpci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet errorq_dispatch(pci_target_queue, (void *)&tgt_err,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * PCI target errorq, to schedule async handling of generation of
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * target device ereports based on captured physical address.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * The errorq is created here but destroyed when _fini is called
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * for the pci module.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet pci_target_queue = errorq_create("pci_target_queue",
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet panic("failed to create required system error queue");