xref: /titanic_51/usr/src/uts/common/os/pcifm.c (revision 8aec91825357bbeaf2ab5d30fc97fe5051a6b8dd)
100d0963fSdilpreet /*
200d0963fSdilpreet  * CDDL HEADER START
300d0963fSdilpreet  *
400d0963fSdilpreet  * The contents of this file are subject to the terms of the
500d0963fSdilpreet  * Common Development and Distribution License (the "License").
600d0963fSdilpreet  * You may not use this file except in compliance with the License.
700d0963fSdilpreet  *
800d0963fSdilpreet  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
900d0963fSdilpreet  * or http://www.opensolaris.org/os/licensing.
1000d0963fSdilpreet  * See the License for the specific language governing permissions
1100d0963fSdilpreet  * and limitations under the License.
1200d0963fSdilpreet  *
1300d0963fSdilpreet  * When distributing Covered Code, include this CDDL HEADER in each
1400d0963fSdilpreet  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1500d0963fSdilpreet  * If applicable, add the following below this CDDL HEADER, with the
1600d0963fSdilpreet  * fields enclosed by brackets "[]" replaced with your own identifying
1700d0963fSdilpreet  * information: Portions Copyright [yyyy] [name of copyright owner]
1800d0963fSdilpreet  *
1900d0963fSdilpreet  * CDDL HEADER END
2000d0963fSdilpreet  */
2100d0963fSdilpreet 
2200d0963fSdilpreet /*
2300d0963fSdilpreet  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2400d0963fSdilpreet  * Use is subject to license terms.
2500d0963fSdilpreet  */
2600d0963fSdilpreet 
2700d0963fSdilpreet #pragma ident	"%Z%%M%	%I%	%E% SMI"
2800d0963fSdilpreet 
2900d0963fSdilpreet #include <sys/types.h>
3000d0963fSdilpreet #include <sys/sunndi.h>
3100d0963fSdilpreet #include <sys/sysmacros.h>
3200d0963fSdilpreet #include <sys/ddifm_impl.h>
3300d0963fSdilpreet #include <sys/fm/util.h>
3400d0963fSdilpreet #include <sys/fm/protocol.h>
3500d0963fSdilpreet #include <sys/fm/io/pci.h>
3600d0963fSdilpreet #include <sys/fm/io/ddi.h>
3700d0963fSdilpreet #include <sys/pci.h>
3800d0963fSdilpreet #include <sys/pcie.h>
3900d0963fSdilpreet #include <sys/pci_impl.h>
4000d0963fSdilpreet #include <sys/epm.h>
4100d0963fSdilpreet #include <sys/pcifm.h>
4200d0963fSdilpreet 
4300d0963fSdilpreet #define	PCIX_ECC_VER_CHECK(x)	(((x) == PCI_PCIX_VER_1) ||\
4400d0963fSdilpreet 				((x) == PCI_PCIX_VER_2))
4500d0963fSdilpreet 
4600d0963fSdilpreet /*
4700d0963fSdilpreet  * Expected PCI Express error mask values
4800d0963fSdilpreet  */
49*8aec9182Sstephh uint32_t pcie_expected_ce_mask = 0x0;
50*8aec9182Sstephh uint32_t pcie_expected_ue_mask = PCIE_AER_UCE_UC;
510c64a9b4Sanish #if defined(__sparc)
52*8aec9182Sstephh uint32_t pcie_expected_sue_mask = 0x0;
53*8aec9182Sstephh #else
54*8aec9182Sstephh uint32_t pcie_expected_sue_mask = PCIE_AER_SUCE_RCVD_MA;
55*8aec9182Sstephh #endif
560c64a9b4Sanish uint32_t pcie_aer_uce_log_bits = PCIE_AER_UCE_LOG_BITS;
57*8aec9182Sstephh #if defined(__sparc)
580c64a9b4Sanish uint32_t pcie_aer_suce_log_bits = PCIE_AER_SUCE_LOG_BITS;
590c64a9b4Sanish #else
600c64a9b4Sanish uint32_t pcie_aer_suce_log_bits = \
610c64a9b4Sanish 	    PCIE_AER_SUCE_LOG_BITS & ~PCIE_AER_SUCE_RCVD_MA;
620c64a9b4Sanish #endif
6300d0963fSdilpreet 
6400d0963fSdilpreet errorq_t *pci_target_queue = NULL;
6500d0963fSdilpreet 
6600d0963fSdilpreet pci_fm_err_t pci_err_tbl[] = {
6700d0963fSdilpreet 	PCI_DET_PERR,	PCI_STAT_PERROR,	NULL,		DDI_FM_UNKNOWN,
6800d0963fSdilpreet 	PCI_MDPE,	PCI_STAT_S_PERROR,	PCI_TARG_MDPE,	DDI_FM_UNKNOWN,
6900d0963fSdilpreet 	PCI_SIG_SERR,	PCI_STAT_S_SYSERR,	NULL,		DDI_FM_FATAL,
7000d0963fSdilpreet 	PCI_MA,		PCI_STAT_R_MAST_AB,	PCI_TARG_MA,	DDI_FM_UNKNOWN,
7100d0963fSdilpreet 	PCI_REC_TA,	PCI_STAT_R_TARG_AB,	PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
7200d0963fSdilpreet 	PCI_SIG_TA,	PCI_STAT_S_TARG_AB,	NULL,		DDI_FM_UNKNOWN,
7300d0963fSdilpreet 	NULL, NULL, NULL, NULL,
7400d0963fSdilpreet };
7500d0963fSdilpreet 
7600d0963fSdilpreet pci_fm_err_t pci_bdg_err_tbl[] = {
7700d0963fSdilpreet 	PCI_DET_PERR,	PCI_STAT_PERROR,	NULL,		DDI_FM_UNKNOWN,
7800d0963fSdilpreet 	PCI_MDPE,	PCI_STAT_S_PERROR,	PCI_TARG_MDPE,	DDI_FM_UNKNOWN,
7900d0963fSdilpreet 	PCI_REC_SERR,	PCI_STAT_S_SYSERR,	NULL,		DDI_FM_UNKNOWN,
80*8aec9182Sstephh #if defined(__sparc)
8100d0963fSdilpreet 	PCI_MA,		PCI_STAT_R_MAST_AB,	PCI_TARG_MA,	DDI_FM_UNKNOWN,
820c64a9b4Sanish #endif
8300d0963fSdilpreet 	PCI_REC_TA,	PCI_STAT_R_TARG_AB,	PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
8400d0963fSdilpreet 	PCI_SIG_TA,	PCI_STAT_S_TARG_AB,	NULL,		DDI_FM_UNKNOWN,
8500d0963fSdilpreet 	NULL, NULL, NULL, NULL,
8600d0963fSdilpreet };
8700d0963fSdilpreet 
8800d0963fSdilpreet static pci_fm_err_t pciex_ce_err_tbl[] = {
89ac4d633fSstephh 	PCIEX_RE,	PCIE_AER_CE_RECEIVER_ERR,	NULL,	DDI_FM_OK,
90ac4d633fSstephh 	PCIEX_RNR,	PCIE_AER_CE_REPLAY_ROLLOVER,	NULL,	DDI_FM_OK,
91ac4d633fSstephh 	PCIEX_RTO,	PCIE_AER_CE_REPLAY_TO,		NULL,	DDI_FM_OK,
92ac4d633fSstephh 	PCIEX_BDP,	PCIE_AER_CE_BAD_DLLP,		NULL,	DDI_FM_OK,
93ac4d633fSstephh 	PCIEX_BTP,	PCIE_AER_CE_BAD_TLP,		NULL,	DDI_FM_OK,
94ac4d633fSstephh 	PCIEX_ANFE,	PCIE_AER_CE_AD_NFE,		NULL,	DDI_FM_OK,
9500d0963fSdilpreet 	NULL, NULL, NULL, NULL,
9600d0963fSdilpreet };
9700d0963fSdilpreet 
9800d0963fSdilpreet static pci_fm_err_t pciex_ue_err_tbl[] = {
9900d0963fSdilpreet 	PCIEX_TE,	PCIE_AER_UCE_TRAINING,		NULL,	DDI_FM_FATAL,
10000d0963fSdilpreet 	PCIEX_DLP,	PCIE_AER_UCE_DLP,		NULL,	DDI_FM_FATAL,
10100d0963fSdilpreet 	PCIEX_SD,	PCIE_AER_UCE_SD,		NULL,   DDI_FM_FATAL,
10200d0963fSdilpreet 	PCIEX_ROF,	PCIE_AER_UCE_RO,		NULL,	DDI_FM_FATAL,
10300d0963fSdilpreet 	PCIEX_FCP,	PCIE_AER_UCE_FCP,		NULL,	DDI_FM_FATAL,
10400d0963fSdilpreet 	PCIEX_MFP,	PCIE_AER_UCE_MTLP,		NULL,	DDI_FM_FATAL,
105ac4d633fSstephh 	PCIEX_CTO,	PCIE_AER_UCE_TO,		NULL,	DDI_FM_UNKNOWN,
106ac4d633fSstephh 	PCIEX_UC,	PCIE_AER_UCE_UC,		NULL,	DDI_FM_OK,
10700d0963fSdilpreet 	PCIEX_ECRC,	PCIE_AER_UCE_ECRC,		NULL,	DDI_FM_UNKNOWN,
10800d0963fSdilpreet 	PCIEX_CA,	PCIE_AER_UCE_CA,		NULL,	DDI_FM_UNKNOWN,
109ac4d633fSstephh 	PCIEX_UR,	PCIE_AER_UCE_UR,		NULL,	DDI_FM_UNKNOWN,
11000d0963fSdilpreet 	PCIEX_POIS,	PCIE_AER_UCE_PTLP,		NULL,	DDI_FM_UNKNOWN,
11100d0963fSdilpreet 	NULL, NULL, NULL, NULL,
11200d0963fSdilpreet };
11300d0963fSdilpreet 
11400d0963fSdilpreet static pci_fm_err_t pcie_sue_err_tbl[] = {
11500d0963fSdilpreet 	PCIEX_S_TA_SC,	PCIE_AER_SUCE_TA_ON_SC,		NULL,	DDI_FM_UNKNOWN,
11600d0963fSdilpreet 	PCIEX_S_MA_SC,	PCIE_AER_SUCE_MA_ON_SC,		NULL,	DDI_FM_UNKNOWN,
11700d0963fSdilpreet 	PCIEX_S_RTA,	PCIE_AER_SUCE_RCVD_TA,		NULL,	DDI_FM_UNKNOWN,
118*8aec9182Sstephh #if defined(__sparc)
11900d0963fSdilpreet 	PCIEX_S_RMA,	PCIE_AER_SUCE_RCVD_MA,		NULL,	DDI_FM_UNKNOWN,
1200c64a9b4Sanish #endif
12100d0963fSdilpreet 	PCIEX_S_USC,	PCIE_AER_SUCE_USC_ERR,		NULL,	DDI_FM_UNKNOWN,
12200d0963fSdilpreet 	PCIEX_S_USCMD,	PCIE_AER_SUCE_USC_MSG_DATA_ERR,	NULL,	DDI_FM_FATAL,
12300d0963fSdilpreet 	PCIEX_S_UDE,	PCIE_AER_SUCE_UC_DATA_ERR,	NULL,	DDI_FM_UNKNOWN,
12400d0963fSdilpreet 	PCIEX_S_UAT,	PCIE_AER_SUCE_UC_ATTR_ERR,	NULL,	DDI_FM_FATAL,
12500d0963fSdilpreet 	PCIEX_S_UADR,	PCIE_AER_SUCE_UC_ADDR_ERR,	NULL,	DDI_FM_FATAL,
12600d0963fSdilpreet 	PCIEX_S_TEX,	PCIE_AER_SUCE_TIMER_EXPIRED,	NULL,	DDI_FM_FATAL,
12700d0963fSdilpreet 	PCIEX_S_PERR,	PCIE_AER_SUCE_PERR_ASSERT,	NULL,	DDI_FM_UNKNOWN,
12800d0963fSdilpreet 	PCIEX_S_SERR,	PCIE_AER_SUCE_SERR_ASSERT,	NULL,	DDI_FM_FATAL,
12900d0963fSdilpreet 	PCIEX_INTERR,	PCIE_AER_SUCE_INTERNAL_ERR,	NULL,	DDI_FM_FATAL,
13000d0963fSdilpreet 	NULL, NULL, NULL, NULL,
13100d0963fSdilpreet };
13200d0963fSdilpreet 
13300d0963fSdilpreet static pci_fm_err_t pcix_err_tbl[] = {
13400d0963fSdilpreet 	PCIX_SPL_DIS,		PCI_PCIX_SPL_DSCD,	NULL,	DDI_FM_UNKNOWN,
13500d0963fSdilpreet 	PCIX_UNEX_SPL,		PCI_PCIX_UNEX_SPL,	NULL,	DDI_FM_UNKNOWN,
13600d0963fSdilpreet 	PCIX_RX_SPL_MSG,	PCI_PCIX_RX_SPL_MSG,	NULL,   DDI_FM_UNKNOWN,
13700d0963fSdilpreet 	NULL, NULL, NULL, NULL,
13800d0963fSdilpreet };
13900d0963fSdilpreet 
14000d0963fSdilpreet static pci_fm_err_t pcix_sec_err_tbl[] = {
14100d0963fSdilpreet 	PCIX_SPL_DIS,		PCI_PCIX_BSS_SPL_DSCD,	NULL,	DDI_FM_UNKNOWN,
14200d0963fSdilpreet 	PCIX_UNEX_SPL,		PCI_PCIX_BSS_UNEX_SPL,	NULL,	DDI_FM_UNKNOWN,
143ac4d633fSstephh 	PCIX_BSS_SPL_OR,	PCI_PCIX_BSS_SPL_OR,	NULL,	DDI_FM_OK,
144ac4d633fSstephh 	PCIX_BSS_SPL_DLY,	PCI_PCIX_BSS_SPL_DLY,	NULL,	DDI_FM_OK,
14500d0963fSdilpreet 	NULL, NULL, NULL, NULL,
14600d0963fSdilpreet };
14700d0963fSdilpreet 
14800d0963fSdilpreet static pci_fm_err_t pciex_nadv_err_tbl[] = {
14900d0963fSdilpreet 	PCIEX_UR,	PCIE_DEVSTS_UR_DETECTED,	NULL,	DDI_FM_UNKNOWN,
15000d0963fSdilpreet 	PCIEX_FAT,	PCIE_DEVSTS_FE_DETECTED,	NULL,	DDI_FM_FATAL,
15100d0963fSdilpreet 	PCIEX_NONFAT,	PCIE_DEVSTS_NFE_DETECTED,	NULL,	DDI_FM_UNKNOWN,
152ac4d633fSstephh 	PCIEX_CORR,	PCIE_DEVSTS_CE_DETECTED,	NULL,	DDI_FM_OK,
15300d0963fSdilpreet 	NULL, NULL, NULL, NULL,
15400d0963fSdilpreet };
15500d0963fSdilpreet 
15600d0963fSdilpreet static int
157*8aec9182Sstephh pci_config_check(ddi_acc_handle_t handle, int fme_flag)
15800d0963fSdilpreet {
15900d0963fSdilpreet 	ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle);
16000d0963fSdilpreet 	ddi_fm_error_t de;
16100d0963fSdilpreet 
16200d0963fSdilpreet 	if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip))))
16300d0963fSdilpreet 		return (DDI_FM_OK);
16400d0963fSdilpreet 
16500d0963fSdilpreet 	de.fme_version = DDI_FME_VERSION;
16600d0963fSdilpreet 
16700d0963fSdilpreet 	ddi_fm_acc_err_get(handle, &de, de.fme_version);
16800d0963fSdilpreet 	if (de.fme_status != DDI_FM_OK) {
169*8aec9182Sstephh 		if (fme_flag == DDI_FM_ERR_UNEXPECTED) {
17000d0963fSdilpreet 			char buf[FM_MAX_CLASS];
17100d0963fSdilpreet 
172*8aec9182Sstephh 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
173*8aec9182Sstephh 			    PCI_ERROR_SUBCLASS, PCI_NR);
174*8aec9182Sstephh 			ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena,
175*8aec9182Sstephh 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL);
176*8aec9182Sstephh 		}
17700d0963fSdilpreet 		ddi_fm_acc_err_clear(handle, de.fme_version);
17800d0963fSdilpreet 	}
17900d0963fSdilpreet 	return (de.fme_status);
18000d0963fSdilpreet }
18100d0963fSdilpreet 
18200d0963fSdilpreet static void
18300d0963fSdilpreet pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs,
184*8aec9182Sstephh     uint8_t pcix_cap_ptr, int fme_flag)
18500d0963fSdilpreet {
18600d0963fSdilpreet 	int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV;
18700d0963fSdilpreet 
18800d0963fSdilpreet 	pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl,
18900d0963fSdilpreet 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS :
19000d0963fSdilpreet 	    PCI_PCIX_ECC_STATUS)));
191*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
19200d0963fSdilpreet 		pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID;
19300d0963fSdilpreet 	else
19400d0963fSdilpreet 		return;
19500d0963fSdilpreet 	pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl,
19600d0963fSdilpreet 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD :
19700d0963fSdilpreet 	    PCI_PCIX_ECC_FST_AD)));
19800d0963fSdilpreet 	pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl,
19900d0963fSdilpreet 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD :
20000d0963fSdilpreet 	    PCI_PCIX_ECC_SEC_AD)));
20100d0963fSdilpreet 	pcix_ecc_regs->pcix_ecc_attr = pci_config_get32((
20200d0963fSdilpreet 	    ddi_acc_handle_t)erpt_p->pe_hdl,
20300d0963fSdilpreet 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR)));
20400d0963fSdilpreet }
20500d0963fSdilpreet 
20600d0963fSdilpreet static void
207*8aec9182Sstephh pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs, int fme_flag)
20800d0963fSdilpreet {
20900d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
21000d0963fSdilpreet 		pcix_bdg_error_regs_t *pcix_bdg_regs =
21100d0963fSdilpreet 		    (pcix_bdg_error_regs_t *)pe_regs;
21200d0963fSdilpreet 		uint8_t pcix_bdg_cap_ptr;
21300d0963fSdilpreet 		int i;
21400d0963fSdilpreet 
21500d0963fSdilpreet 		pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
21600d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16(
21700d0963fSdilpreet 		    erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS));
218*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
21900d0963fSdilpreet 			pcix_bdg_regs->pcix_bdg_vflags |=
22000d0963fSdilpreet 			    PCIX_BDG_SEC_STATUS_VALID;
22100d0963fSdilpreet 		else
22200d0963fSdilpreet 			return;
22300d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl,
22400d0963fSdilpreet 		    (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS));
225*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
22600d0963fSdilpreet 			pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID;
22700d0963fSdilpreet 		else
22800d0963fSdilpreet 			return;
22900d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
23000d0963fSdilpreet 			pcix_ecc_regs_t *pcix_bdg_ecc_regs;
23100d0963fSdilpreet 			/*
23200d0963fSdilpreet 			 * PCI Express to PCI-X bridges only implement the
23300d0963fSdilpreet 			 * secondary side of the PCI-X ECC registers, bit one is
23400d0963fSdilpreet 			 * read-only so we make sure we do not write to it.
23500d0963fSdilpreet 			 */
23600d0963fSdilpreet 			if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
23700d0963fSdilpreet 				pcix_bdg_ecc_regs =
23800d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_ecc_regs[1];
23900d0963fSdilpreet 				pcix_ecc_regs_gather(erpt_p, pcix_bdg_ecc_regs,
240*8aec9182Sstephh 				    pcix_bdg_cap_ptr, fme_flag);
24100d0963fSdilpreet 			} else {
24200d0963fSdilpreet 				for (i = 0; i < 2; i++) {
24300d0963fSdilpreet 					pcix_bdg_ecc_regs =
24400d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_ecc_regs[i];
24500d0963fSdilpreet 					pci_config_put32(erpt_p->pe_hdl,
24600d0963fSdilpreet 					    (pcix_bdg_cap_ptr +
24700d0963fSdilpreet 					    PCI_PCIX_BDG_ECC_STATUS), i);
24800d0963fSdilpreet 					pcix_ecc_regs_gather(erpt_p,
24900d0963fSdilpreet 					    pcix_bdg_ecc_regs,
250*8aec9182Sstephh 					    pcix_bdg_cap_ptr, fme_flag);
25100d0963fSdilpreet 				}
25200d0963fSdilpreet 			}
25300d0963fSdilpreet 		}
25400d0963fSdilpreet 	} else {
25500d0963fSdilpreet 		pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
25600d0963fSdilpreet 		uint8_t pcix_cap_ptr;
25700d0963fSdilpreet 
25800d0963fSdilpreet 		pcix_cap_ptr = pcix_regs->pcix_cap_ptr;
25900d0963fSdilpreet 
26000d0963fSdilpreet 		pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl,
26100d0963fSdilpreet 		    (pcix_cap_ptr + PCI_PCIX_COMMAND));
26200d0963fSdilpreet 		pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl,
26300d0963fSdilpreet 		    (pcix_cap_ptr + PCI_PCIX_STATUS));
264*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
26500d0963fSdilpreet 			pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID;
26600d0963fSdilpreet 		else
26700d0963fSdilpreet 			return;
26800d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
26900d0963fSdilpreet 			pcix_ecc_regs_t *pcix_ecc_regs =
27000d0963fSdilpreet 			    pcix_regs->pcix_ecc_regs;
27100d0963fSdilpreet 
27200d0963fSdilpreet 			pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs,
273*8aec9182Sstephh 			    pcix_cap_ptr, fme_flag);
27400d0963fSdilpreet 		}
27500d0963fSdilpreet 	}
27600d0963fSdilpreet }
27700d0963fSdilpreet 
27800d0963fSdilpreet static void
279*8aec9182Sstephh pcie_regs_gather(pci_erpt_t *erpt_p, int fme_flag)
28000d0963fSdilpreet {
28100d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
28200d0963fSdilpreet 	uint8_t pcie_cap_ptr;
28300d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs;
28400d0963fSdilpreet 	uint16_t pcie_ecap_ptr;
28500d0963fSdilpreet 
28600d0963fSdilpreet 	pcie_cap_ptr = pcie_regs->pcie_cap_ptr;
28700d0963fSdilpreet 
28800d0963fSdilpreet 	pcie_regs->pcie_err_status = pci_config_get16(erpt_p->pe_hdl,
28900d0963fSdilpreet 	    pcie_cap_ptr + PCIE_DEVSTS);
290*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
29100d0963fSdilpreet 		pcie_regs->pcie_vflags |= PCIE_ERR_STATUS_VALID;
29200d0963fSdilpreet 	else
29300d0963fSdilpreet 		return;
29400d0963fSdilpreet 
29500d0963fSdilpreet 	pcie_regs->pcie_err_ctl = pci_config_get16(erpt_p->pe_hdl,
29600d0963fSdilpreet 	    (pcie_cap_ptr + PCIE_DEVCTL));
297*8aec9182Sstephh 	pcie_regs->pcie_dev_cap = pci_config_get16(erpt_p->pe_hdl,
298*8aec9182Sstephh 	    (pcie_cap_ptr + PCIE_DEVCAP));
29900d0963fSdilpreet 
30000d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && (erpt_p->pe_dflags &
30100d0963fSdilpreet 	    PCIX_DEV))
302*8aec9182Sstephh 		pcix_regs_gather(erpt_p, pcie_regs->pcix_bdg_regs, fme_flag);
30300d0963fSdilpreet 
30400d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV) {
30500d0963fSdilpreet 		pcie_rc_error_regs_t *pcie_rc_regs = pcie_regs->pcie_rc_regs;
30600d0963fSdilpreet 
30700d0963fSdilpreet 		pcie_rc_regs->pcie_rc_status = pci_config_get32(erpt_p->pe_hdl,
30800d0963fSdilpreet 		    (pcie_cap_ptr + PCIE_ROOTSTS));
30900d0963fSdilpreet 		pcie_rc_regs->pcie_rc_ctl = pci_config_get16(erpt_p->pe_hdl,
31000d0963fSdilpreet 		    (pcie_cap_ptr + PCIE_ROOTCTL));
31100d0963fSdilpreet 	}
31200d0963fSdilpreet 
31300d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV))
31400d0963fSdilpreet 		return;
31500d0963fSdilpreet 
31600d0963fSdilpreet 	pcie_adv_regs = pcie_regs->pcie_adv_regs;
31700d0963fSdilpreet 
31800d0963fSdilpreet 	pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr;
31900d0963fSdilpreet 
32000d0963fSdilpreet 	pcie_adv_regs->pcie_ue_status = pci_config_get32(erpt_p->pe_hdl,
32100d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_UCE_STS);
322*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
32300d0963fSdilpreet 		pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_STATUS_VALID;
32400d0963fSdilpreet 
32500d0963fSdilpreet 	pcie_adv_regs->pcie_ue_mask = pci_config_get32(erpt_p->pe_hdl,
32600d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_UCE_MASK);
32700d0963fSdilpreet 	pcie_adv_regs->pcie_ue_sev = pci_config_get32(erpt_p->pe_hdl,
32800d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_UCE_SERV);
32900d0963fSdilpreet 	pcie_adv_regs->pcie_adv_ctl = pci_config_get32(erpt_p->pe_hdl,
33000d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_CTL);
33100d0963fSdilpreet 	pcie_adv_regs->pcie_ue_hdr0 = pci_config_get32(erpt_p->pe_hdl,
33200d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_HDR_LOG);
333*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) {
33400d0963fSdilpreet 		int i;
33500d0963fSdilpreet 		pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_HDR_VALID;
33600d0963fSdilpreet 
33700d0963fSdilpreet 		for (i = 0; i < 3; i++) {
33800d0963fSdilpreet 			pcie_adv_regs->pcie_ue_hdr[i] = pci_config_get32(
33900d0963fSdilpreet 			    erpt_p->pe_hdl, pcie_ecap_ptr + PCIE_AER_HDR_LOG +
34000d0963fSdilpreet 			    (4 * (i + 1)));
34100d0963fSdilpreet 		}
34200d0963fSdilpreet 	}
34300d0963fSdilpreet 
34400d0963fSdilpreet 	pcie_adv_regs->pcie_ce_status = pci_config_get32(erpt_p->pe_hdl,
34500d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_CE_STS);
346*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
34700d0963fSdilpreet 		pcie_adv_regs->pcie_adv_vflags |= PCIE_CE_STATUS_VALID;
34800d0963fSdilpreet 
34900d0963fSdilpreet 	pcie_adv_regs->pcie_ce_mask = pci_config_get32(erpt_p->pe_hdl,
35000d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_CE_MASK);
35100d0963fSdilpreet 
35200d0963fSdilpreet 	/*
35300d0963fSdilpreet 	 * If pci express to pci bridge then grab the bridge
35400d0963fSdilpreet 	 * error registers.
35500d0963fSdilpreet 	 */
35600d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
35700d0963fSdilpreet 		pcie_adv_bdg_error_regs_t *pcie_bdg_regs =
35800d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_bdg_regs;
35900d0963fSdilpreet 
36000d0963fSdilpreet 		pcie_bdg_regs->pcie_sue_status =
36100d0963fSdilpreet 		    pci_config_get32(erpt_p->pe_hdl,
36200d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_SUCE_STS);
363*8aec9182Sstephh 		pcie_bdg_regs->pcie_sue_mask =
364*8aec9182Sstephh 		    pci_config_get32(erpt_p->pe_hdl,
365*8aec9182Sstephh 		    pcie_ecap_ptr + PCIE_AER_SUCE_MASK);
366*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
36700d0963fSdilpreet 			pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_STATUS_VALID;
36800d0963fSdilpreet 		pcie_bdg_regs->pcie_sue_hdr0 = pci_config_get32(erpt_p->pe_hdl,
36900d0963fSdilpreet 		    (pcie_ecap_ptr + PCIE_AER_SHDR_LOG));
37000d0963fSdilpreet 
371*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK) {
37200d0963fSdilpreet 			int i;
37300d0963fSdilpreet 
37400d0963fSdilpreet 			pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_HDR_VALID;
37500d0963fSdilpreet 
37600d0963fSdilpreet 			for (i = 0; i < 3; i++) {
37700d0963fSdilpreet 				pcie_bdg_regs->pcie_sue_hdr[i] =
37800d0963fSdilpreet 				    pci_config_get32(erpt_p->pe_hdl,
37900d0963fSdilpreet 					pcie_ecap_ptr + PCIE_AER_SHDR_LOG +
38000d0963fSdilpreet 					(4 * (i + 1)));
38100d0963fSdilpreet 			}
38200d0963fSdilpreet 		}
38300d0963fSdilpreet 	}
38400d0963fSdilpreet 	/*
38500d0963fSdilpreet 	 * If PCI Express root complex then grab the root complex
38600d0963fSdilpreet 	 * error registers.
38700d0963fSdilpreet 	 */
38800d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV) {
38900d0963fSdilpreet 		pcie_adv_rc_error_regs_t *pcie_rc_regs =
39000d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_rc_regs;
39100d0963fSdilpreet 
39200d0963fSdilpreet 		pcie_rc_regs->pcie_rc_err_cmd = pci_config_get32(erpt_p->pe_hdl,
39300d0963fSdilpreet 		    (pcie_ecap_ptr + PCIE_AER_RE_CMD));
39400d0963fSdilpreet 		pcie_rc_regs->pcie_rc_err_status =
39500d0963fSdilpreet 		    pci_config_get32(erpt_p->pe_hdl,
39600d0963fSdilpreet 			(pcie_ecap_ptr + PCIE_AER_RE_STS));
397*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
39800d0963fSdilpreet 			pcie_adv_regs->pcie_adv_vflags |=
39900d0963fSdilpreet 			    PCIE_RC_ERR_STATUS_VALID;
40000d0963fSdilpreet 		pcie_rc_regs->pcie_rc_ce_src_id =
40100d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl,
40200d0963fSdilpreet 			(pcie_ecap_ptr + PCIE_AER_CE_SRC_ID));
40300d0963fSdilpreet 		pcie_rc_regs->pcie_rc_ue_src_id =
40400d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl,
40500d0963fSdilpreet 			(pcie_ecap_ptr + PCIE_AER_ERR_SRC_ID));
406*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
40700d0963fSdilpreet 			pcie_adv_regs->pcie_adv_vflags |= PCIE_SRC_ID_VALID;
40800d0963fSdilpreet 	}
40900d0963fSdilpreet }
41000d0963fSdilpreet 
41100d0963fSdilpreet /*ARGSUSED*/
41200d0963fSdilpreet static void
413*8aec9182Sstephh pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p, int fme_flag)
41400d0963fSdilpreet {
41500d0963fSdilpreet 	pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs;
41600d0963fSdilpreet 
41700d0963fSdilpreet 	/*
41800d0963fSdilpreet 	 * Start by reading all the error registers that are available for
41900d0963fSdilpreet 	 * pci and pci express and for leaf devices and bridges/switches
42000d0963fSdilpreet 	 */
42100d0963fSdilpreet 	pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl,
42200d0963fSdilpreet 	    PCI_CONF_STAT);
423*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK)
42400d0963fSdilpreet 		return;
42500d0963fSdilpreet 	pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID;
42600d0963fSdilpreet 	pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl,
42700d0963fSdilpreet 	    PCI_CONF_COMM);
428*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK)
42900d0963fSdilpreet 		return;
43000d0963fSdilpreet 
43100d0963fSdilpreet 	/*
43200d0963fSdilpreet 	 * If pci-pci bridge grab PCI bridge specific error registers.
43300d0963fSdilpreet 	 */
43400d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
43500d0963fSdilpreet 		pci_regs->pci_bdg_regs->pci_bdg_sec_stat =
43600d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS);
437*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
43800d0963fSdilpreet 			pci_regs->pci_bdg_regs->pci_bdg_vflags |=
43900d0963fSdilpreet 			    PCI_BDG_SEC_STAT_VALID;
44000d0963fSdilpreet 		pci_regs->pci_bdg_regs->pci_bdg_ctrl =
44100d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL);
442*8aec9182Sstephh 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
44300d0963fSdilpreet 			pci_regs->pci_bdg_regs->pci_bdg_vflags |=
44400d0963fSdilpreet 			    PCI_BDG_CTRL_VALID;
44500d0963fSdilpreet 	}
44600d0963fSdilpreet 
44700d0963fSdilpreet 	/*
44800d0963fSdilpreet 	 * If pci express device grab pci express error registers and
44900d0963fSdilpreet 	 * check for advanced error reporting features and grab them if
45000d0963fSdilpreet 	 * available.
45100d0963fSdilpreet 	 */
45200d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_DEV)
453*8aec9182Sstephh 		pcie_regs_gather(erpt_p, fme_flag);
45400d0963fSdilpreet 	else if (erpt_p->pe_dflags & PCIX_DEV)
455*8aec9182Sstephh 		pcix_regs_gather(erpt_p, erpt_p->pe_regs, fme_flag);
45600d0963fSdilpreet 
45700d0963fSdilpreet }
45800d0963fSdilpreet 
45900d0963fSdilpreet static void
46000d0963fSdilpreet pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs)
46100d0963fSdilpreet {
46200d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
46300d0963fSdilpreet 		pcix_bdg_error_regs_t *pcix_bdg_regs =
46400d0963fSdilpreet 		    (pcix_bdg_error_regs_t *)pe_regs;
46500d0963fSdilpreet 		uint8_t pcix_bdg_cap_ptr;
46600d0963fSdilpreet 		int i;
46700d0963fSdilpreet 
46800d0963fSdilpreet 		pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
46900d0963fSdilpreet 
47000d0963fSdilpreet 		if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID)
47100d0963fSdilpreet 			pci_config_put16(erpt_p->pe_hdl,
47200d0963fSdilpreet 			    (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS),
47300d0963fSdilpreet 			    pcix_bdg_regs->pcix_bdg_sec_stat);
47400d0963fSdilpreet 
47500d0963fSdilpreet 		if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID)
47600d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
47700d0963fSdilpreet 			    (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS),
47800d0963fSdilpreet 			    pcix_bdg_regs->pcix_bdg_stat);
47900d0963fSdilpreet 
48000d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_vflags = 0x0;
48100d0963fSdilpreet 
48200d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
48300d0963fSdilpreet 			pcix_ecc_regs_t *pcix_bdg_ecc_regs;
48400d0963fSdilpreet 			/*
48500d0963fSdilpreet 			 * PCI Express to PCI-X bridges only implement the
48600d0963fSdilpreet 			 * secondary side of the PCI-X ECC registers, bit one is
48700d0963fSdilpreet 			 * read-only so we make sure we do not write to it.
48800d0963fSdilpreet 			 */
48900d0963fSdilpreet 			if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
49000d0963fSdilpreet 				pcix_bdg_ecc_regs =
49100d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_ecc_regs[1];
49200d0963fSdilpreet 
49300d0963fSdilpreet 				if (pcix_bdg_ecc_regs->pcix_ecc_vflags &
49400d0963fSdilpreet 				    PCIX_ERR_ECC_STS_VALID) {
49500d0963fSdilpreet 
49600d0963fSdilpreet 					pci_config_put32(erpt_p->pe_hdl,
49700d0963fSdilpreet 					    (pcix_bdg_cap_ptr +
49800d0963fSdilpreet 					    PCI_PCIX_BDG_ECC_STATUS),
49900d0963fSdilpreet 					    pcix_bdg_ecc_regs->
50000d0963fSdilpreet 					    pcix_ecc_ctlstat);
50100d0963fSdilpreet 				}
50200d0963fSdilpreet 				pcix_bdg_ecc_regs->pcix_ecc_vflags = 0x0;
50300d0963fSdilpreet 			} else {
50400d0963fSdilpreet 				for (i = 0; i < 2; i++) {
50500d0963fSdilpreet 					pcix_bdg_ecc_regs =
50600d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_ecc_regs[i];
50700d0963fSdilpreet 
50800d0963fSdilpreet 
50900d0963fSdilpreet 					if (pcix_bdg_ecc_regs->pcix_ecc_vflags &
51000d0963fSdilpreet 					    PCIX_ERR_ECC_STS_VALID) {
51100d0963fSdilpreet 						pci_config_put32(erpt_p->pe_hdl,
51200d0963fSdilpreet 						    (pcix_bdg_cap_ptr +
51300d0963fSdilpreet 						    PCI_PCIX_BDG_ECC_STATUS),
51400d0963fSdilpreet 						    i);
51500d0963fSdilpreet 
51600d0963fSdilpreet 						pci_config_put32(erpt_p->pe_hdl,
51700d0963fSdilpreet 						    (pcix_bdg_cap_ptr +
51800d0963fSdilpreet 						    PCI_PCIX_BDG_ECC_STATUS),
51900d0963fSdilpreet 						    pcix_bdg_ecc_regs->
52000d0963fSdilpreet 						    pcix_ecc_ctlstat);
52100d0963fSdilpreet 					}
52200d0963fSdilpreet 					pcix_bdg_ecc_regs->pcix_ecc_vflags =
52300d0963fSdilpreet 					    0x0;
52400d0963fSdilpreet 				}
52500d0963fSdilpreet 			}
52600d0963fSdilpreet 		}
52700d0963fSdilpreet 	} else {
52800d0963fSdilpreet 		pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
52900d0963fSdilpreet 		uint8_t pcix_cap_ptr;
53000d0963fSdilpreet 
53100d0963fSdilpreet 		pcix_cap_ptr = pcix_regs->pcix_cap_ptr;
53200d0963fSdilpreet 
53300d0963fSdilpreet 		if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID)
53400d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
53500d0963fSdilpreet 			    (pcix_cap_ptr + PCI_PCIX_STATUS),
53600d0963fSdilpreet 			    pcix_regs->pcix_status);
53700d0963fSdilpreet 
53800d0963fSdilpreet 		pcix_regs->pcix_vflags = 0x0;
53900d0963fSdilpreet 
54000d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
54100d0963fSdilpreet 			pcix_ecc_regs_t *pcix_ecc_regs =
54200d0963fSdilpreet 			    pcix_regs->pcix_ecc_regs;
54300d0963fSdilpreet 
54400d0963fSdilpreet 			if (pcix_ecc_regs->pcix_ecc_vflags &
54500d0963fSdilpreet 			    PCIX_ERR_ECC_STS_VALID)
54600d0963fSdilpreet 				pci_config_put32(erpt_p->pe_hdl,
54700d0963fSdilpreet 				    (pcix_cap_ptr + PCI_PCIX_ECC_STATUS),
54800d0963fSdilpreet 				    pcix_ecc_regs->pcix_ecc_ctlstat);
54900d0963fSdilpreet 
55000d0963fSdilpreet 			pcix_ecc_regs->pcix_ecc_vflags = 0x0;
55100d0963fSdilpreet 		}
55200d0963fSdilpreet 	}
55300d0963fSdilpreet }
55400d0963fSdilpreet 
55500d0963fSdilpreet static void
55600d0963fSdilpreet pcie_regs_clear(pci_erpt_t *erpt_p)
55700d0963fSdilpreet {
55800d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
55900d0963fSdilpreet 	uint8_t pcie_cap_ptr;
56000d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs;
56100d0963fSdilpreet 	uint16_t pcie_ecap_ptr;
56200d0963fSdilpreet 
56300d0963fSdilpreet 	pcie_cap_ptr = pcie_regs->pcie_cap_ptr;
56400d0963fSdilpreet 
56500d0963fSdilpreet 	if (pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID)
56600d0963fSdilpreet 		pci_config_put16(erpt_p->pe_hdl, pcie_cap_ptr + PCIE_DEVSTS,
56700d0963fSdilpreet 		    pcie_regs->pcie_err_status);
56800d0963fSdilpreet 
56900d0963fSdilpreet 	pcie_regs->pcie_vflags = 0x0;
57000d0963fSdilpreet 
57100d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) &&
57200d0963fSdilpreet 	    (erpt_p->pe_dflags & PCIX_DEV))
57300d0963fSdilpreet 		pcix_regs_clear(erpt_p, pcie_regs->pcix_bdg_regs);
57400d0963fSdilpreet 
57500d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV))
57600d0963fSdilpreet 		return;
57700d0963fSdilpreet 
57800d0963fSdilpreet 	pcie_adv_regs = pcie_regs->pcie_adv_regs;
57900d0963fSdilpreet 
58000d0963fSdilpreet 	pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr;
58100d0963fSdilpreet 
58200d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID)
58300d0963fSdilpreet 		pci_config_put32(erpt_p->pe_hdl,
58400d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_UCE_STS,
58500d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_status);
58600d0963fSdilpreet 
58700d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID)
58800d0963fSdilpreet 		pci_config_put32(erpt_p->pe_hdl,
58900d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_CE_STS,
59000d0963fSdilpreet 		    pcie_adv_regs->pcie_ce_status);
59100d0963fSdilpreet 
59200d0963fSdilpreet 
59300d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
59400d0963fSdilpreet 		pcie_adv_bdg_error_regs_t *pcie_bdg_regs =
59500d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_bdg_regs;
59600d0963fSdilpreet 
59700d0963fSdilpreet 
59800d0963fSdilpreet 		if (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID)
59900d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
60000d0963fSdilpreet 			    pcie_ecap_ptr + PCIE_AER_SUCE_STS,
60100d0963fSdilpreet 			    pcie_bdg_regs->pcie_sue_status);
60200d0963fSdilpreet 	}
60300d0963fSdilpreet 	/*
60400d0963fSdilpreet 	 * If PCI Express root complex then clear the root complex
60500d0963fSdilpreet 	 * error registers.
60600d0963fSdilpreet 	 */
60700d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV) {
60800d0963fSdilpreet 		pcie_adv_rc_error_regs_t *pcie_rc_regs =
60900d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_rc_regs;
61000d0963fSdilpreet 
61100d0963fSdilpreet 
61200d0963fSdilpreet 		if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID)
61300d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
61400d0963fSdilpreet 			    (pcie_ecap_ptr + PCIE_AER_RE_STS),
61500d0963fSdilpreet 			    pcie_rc_regs->pcie_rc_err_status);
61600d0963fSdilpreet 	}
61700d0963fSdilpreet 	pcie_adv_regs->pcie_adv_vflags = 0x0;
61800d0963fSdilpreet }
61900d0963fSdilpreet 
62000d0963fSdilpreet static void
62100d0963fSdilpreet pci_regs_clear(pci_erpt_t *erpt_p)
62200d0963fSdilpreet {
62300d0963fSdilpreet 	/*
62400d0963fSdilpreet 	 * Finally clear the error bits
62500d0963fSdilpreet 	 */
62600d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_DEV)
62700d0963fSdilpreet 		pcie_regs_clear(erpt_p);
62800d0963fSdilpreet 	else if (erpt_p->pe_dflags & PCIX_DEV)
62900d0963fSdilpreet 		pcix_regs_clear(erpt_p, erpt_p->pe_regs);
63000d0963fSdilpreet 
63100d0963fSdilpreet 	if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID)
63200d0963fSdilpreet 		pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT,
63300d0963fSdilpreet 		    erpt_p->pe_pci_regs->pci_err_status);
63400d0963fSdilpreet 
63500d0963fSdilpreet 	erpt_p->pe_pci_regs->pci_vflags = 0x0;
63600d0963fSdilpreet 
63700d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
63800d0963fSdilpreet 		if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
63900d0963fSdilpreet 		    PCI_BDG_SEC_STAT_VALID)
64000d0963fSdilpreet 			pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS,
64100d0963fSdilpreet 			    erpt_p->pe_pci_regs->pci_bdg_regs->
64200d0963fSdilpreet 			    pci_bdg_sec_stat);
64300d0963fSdilpreet 		if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
64400d0963fSdilpreet 		    PCI_BDG_CTRL_VALID)
64500d0963fSdilpreet 			pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL,
64600d0963fSdilpreet 			    erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl);
64700d0963fSdilpreet 
64800d0963fSdilpreet 		erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0;
64900d0963fSdilpreet 	}
65000d0963fSdilpreet }
65100d0963fSdilpreet 
65200d0963fSdilpreet /*
65300d0963fSdilpreet  * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport
65400d0963fSdilpreet  * generation.
65500d0963fSdilpreet  */
65600d0963fSdilpreet /* ARGSUSED */
65700d0963fSdilpreet static void
65800d0963fSdilpreet pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
65900d0963fSdilpreet {
66000d0963fSdilpreet 	uint8_t pcix_cap_ptr;
66100d0963fSdilpreet 	int i;
66200d0963fSdilpreet 
66300d0963fSdilpreet 	pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
66400d0963fSdilpreet 	    "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
66500d0963fSdilpreet 
66600d0963fSdilpreet 	if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL)
66700d0963fSdilpreet 		erpt_p->pe_dflags |= PCIX_DEV;
66800d0963fSdilpreet 	else
66900d0963fSdilpreet 		return;
67000d0963fSdilpreet 
67100d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
67200d0963fSdilpreet 		pcix_bdg_error_regs_t *pcix_bdg_regs;
67300d0963fSdilpreet 
67400d0963fSdilpreet 		erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t),
67500d0963fSdilpreet 		    KM_SLEEP);
67600d0963fSdilpreet 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
67700d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr;
67800d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl,
67900d0963fSdilpreet 		    pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
68000d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
68100d0963fSdilpreet 			for (i = 0; i < 2; i++) {
68200d0963fSdilpreet 				pcix_bdg_regs->pcix_bdg_ecc_regs[i] =
68300d0963fSdilpreet 				    kmem_zalloc(sizeof (pcix_ecc_regs_t),
68400d0963fSdilpreet 					KM_SLEEP);
68500d0963fSdilpreet 			}
68600d0963fSdilpreet 		}
68700d0963fSdilpreet 	} else {
68800d0963fSdilpreet 		pcix_error_regs_t *pcix_regs;
68900d0963fSdilpreet 
69000d0963fSdilpreet 		erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t),
69100d0963fSdilpreet 		    KM_SLEEP);
69200d0963fSdilpreet 		pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
69300d0963fSdilpreet 		pcix_regs->pcix_cap_ptr = pcix_cap_ptr;
69400d0963fSdilpreet 		pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl,
69500d0963fSdilpreet 		    pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
69600d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
69700d0963fSdilpreet 			pcix_regs->pcix_ecc_regs = kmem_zalloc(
69800d0963fSdilpreet 			    sizeof (pcix_ecc_regs_t), KM_SLEEP);
69900d0963fSdilpreet 		}
70000d0963fSdilpreet 	}
70100d0963fSdilpreet }
70200d0963fSdilpreet 
70300d0963fSdilpreet static void
70400d0963fSdilpreet pcie_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
70500d0963fSdilpreet {
70600d0963fSdilpreet 	pcie_error_regs_t *pcie_regs;
70700d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs;
70800d0963fSdilpreet 	uint8_t pcix_cap_ptr;
70900d0963fSdilpreet 	uint8_t pcie_cap_ptr;
71000d0963fSdilpreet 	uint16_t pcie_ecap_ptr;
71100d0963fSdilpreet 	uint16_t dev_type = 0;
71200d0963fSdilpreet 	uint32_t mask = pcie_expected_ue_mask;
71300d0963fSdilpreet 
71400d0963fSdilpreet 	/*
71500d0963fSdilpreet 	 * The following sparc specific code should be removed once the pci_cap
71600d0963fSdilpreet 	 * interfaces create the necessary properties for us.
71700d0963fSdilpreet 	 */
71800d0963fSdilpreet #if defined(__sparc)
71900d0963fSdilpreet 	ushort_t status;
72000d0963fSdilpreet 	uint32_t slot_cap;
72100d0963fSdilpreet 	uint8_t cap_ptr = 0;
72200d0963fSdilpreet 	uint8_t cap_id = 0;
72300d0963fSdilpreet 	uint32_t hdr, hdr_next_ptr, hdr_cap_id;
72400d0963fSdilpreet 	uint16_t offset = P2ALIGN(PCIE_EXT_CAP, 4);
72500d0963fSdilpreet 	uint16_t aer_ptr = 0;
72600d0963fSdilpreet 
72700d0963fSdilpreet 	cap_ptr = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_CAP_PTR);
728*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) ==
729*8aec9182Sstephh 	    DDI_FM_OK) {
73000d0963fSdilpreet 		while ((cap_id = pci_config_get8(erpt_p->pe_hdl, cap_ptr)) !=
73100d0963fSdilpreet 		    0xff) {
73200d0963fSdilpreet 			if (cap_id == PCI_CAP_ID_PCIX) {
73300d0963fSdilpreet 				(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
73400d0963fSdilpreet 				    "pcix-capid-pointer", cap_ptr);
73500d0963fSdilpreet 			}
73600d0963fSdilpreet 		if (cap_id == PCI_CAP_ID_PCI_E) {
73700d0963fSdilpreet 			status = pci_config_get16(erpt_p->pe_hdl, cap_ptr + 2);
73800d0963fSdilpreet 			if (status & PCIE_PCIECAP_SLOT_IMPL) {
73900d0963fSdilpreet 				/* offset 14h is Slot Cap Register */
74000d0963fSdilpreet 				slot_cap = pci_config_get32(erpt_p->pe_hdl,
74100d0963fSdilpreet 				    cap_ptr + PCIE_SLOTCAP);
74200d0963fSdilpreet 				(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
74300d0963fSdilpreet 				    "pcie-slotcap-reg", slot_cap);
74400d0963fSdilpreet 			}
74500d0963fSdilpreet 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
74600d0963fSdilpreet 			    "pcie-capid-reg", pci_config_get16(erpt_p->pe_hdl,
74700d0963fSdilpreet 			    cap_ptr + PCIE_PCIECAP));
74800d0963fSdilpreet 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
74900d0963fSdilpreet 			    "pcie-capid-pointer", cap_ptr);
75000d0963fSdilpreet 
75100d0963fSdilpreet 		}
75200d0963fSdilpreet 			if ((cap_ptr = pci_config_get8(erpt_p->pe_hdl,
75300d0963fSdilpreet 			    cap_ptr + 1)) == 0xff || cap_ptr == 0 ||
754*8aec9182Sstephh 			    (pci_config_check(erpt_p->pe_hdl,
755*8aec9182Sstephh 			    DDI_FM_ERR_UNEXPECTED) != DDI_FM_OK))
75600d0963fSdilpreet 				break;
75700d0963fSdilpreet 		}
75800d0963fSdilpreet 	}
75900d0963fSdilpreet 
76000d0963fSdilpreet #endif
76100d0963fSdilpreet 
76200d0963fSdilpreet 	pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
76300d0963fSdilpreet 	    "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
76400d0963fSdilpreet 
76500d0963fSdilpreet 	if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL)
76600d0963fSdilpreet 		erpt_p->pe_dflags |= PCIX_DEV;
76700d0963fSdilpreet 
76800d0963fSdilpreet 	pcie_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
76900d0963fSdilpreet 	    DDI_PROP_DONTPASS, "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
77000d0963fSdilpreet 
77100d0963fSdilpreet 	if (pcie_cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
77200d0963fSdilpreet 		erpt_p->pe_dflags |= PCIEX_DEV;
77300d0963fSdilpreet 		erpt_p->pe_regs = kmem_zalloc(sizeof (pcie_error_regs_t),
77400d0963fSdilpreet 		    KM_SLEEP);
77500d0963fSdilpreet 		pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
77600d0963fSdilpreet 		pcie_regs->pcie_cap_ptr = pcie_cap_ptr;
77700d0963fSdilpreet 	}
77800d0963fSdilpreet 
77900d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_DEV))
78000d0963fSdilpreet 		return;
78100d0963fSdilpreet 
78200d0963fSdilpreet 	/*
78300d0963fSdilpreet 	 * Don't currently need to check for version here because we are
78400d0963fSdilpreet 	 * compliant with PCIE 1.0a which is version 0 and is guaranteed
78500d0963fSdilpreet 	 * software compatibility with future versions.  We will need to
78600d0963fSdilpreet 	 * add errors for new detectors/features which are added in newer
78700d0963fSdilpreet 	 * revisions [sec 7.8.2].
78800d0963fSdilpreet 	 */
78900d0963fSdilpreet 	pcie_regs->pcie_cap = pci_config_get16(erpt_p->pe_hdl,
79000d0963fSdilpreet 	    pcie_regs->pcie_cap_ptr + PCIE_PCIECAP);
79100d0963fSdilpreet 
79200d0963fSdilpreet 	dev_type = pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK;
79300d0963fSdilpreet 
79400d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) &&
79500d0963fSdilpreet 	    (erpt_p->pe_dflags & PCIX_DEV)) {
79600d0963fSdilpreet 		int i;
79700d0963fSdilpreet 
79800d0963fSdilpreet 		pcie_regs->pcix_bdg_regs =
79900d0963fSdilpreet 		    kmem_zalloc(sizeof (pcix_bdg_error_regs_t), KM_SLEEP);
80000d0963fSdilpreet 
80100d0963fSdilpreet 		pcie_regs->pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr;
80200d0963fSdilpreet 		pcie_regs->pcix_bdg_regs->pcix_bdg_ver =
80300d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl,
80400d0963fSdilpreet 			pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
80500d0963fSdilpreet 
80600d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcie_regs->pcix_bdg_regs->pcix_bdg_ver))
80700d0963fSdilpreet 			for (i = 0; i < 2; i++)
80800d0963fSdilpreet 				pcie_regs->pcix_bdg_regs->pcix_bdg_ecc_regs[i] =
80900d0963fSdilpreet 				    kmem_zalloc(sizeof (pcix_ecc_regs_t),
81000d0963fSdilpreet 					KM_SLEEP);
81100d0963fSdilpreet 	}
81200d0963fSdilpreet 
81300d0963fSdilpreet 	if (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) {
81400d0963fSdilpreet 		erpt_p->pe_dflags |= PCIEX_RC_DEV;
81500d0963fSdilpreet 		pcie_regs->pcie_rc_regs = kmem_zalloc(
81600d0963fSdilpreet 		    sizeof (pcie_rc_error_regs_t), KM_SLEEP);
81700d0963fSdilpreet 	}
81800d0963fSdilpreet 	/*
81900d0963fSdilpreet 	 * The following sparc specific code should be removed once the pci_cap
82000d0963fSdilpreet 	 * interfaces create the necessary properties for us.
82100d0963fSdilpreet 	 */
82200d0963fSdilpreet #if defined(__sparc)
82300d0963fSdilpreet 
82400d0963fSdilpreet 	hdr = pci_config_get32(erpt_p->pe_hdl, offset);
82500d0963fSdilpreet 	hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
82600d0963fSdilpreet 	    PCIE_EXT_CAP_NEXT_PTR_MASK;
82700d0963fSdilpreet 	hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK;
82800d0963fSdilpreet 
82900d0963fSdilpreet 	while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) &&
83000d0963fSdilpreet 	    (hdr_cap_id != PCIE_EXT_CAP_ID_AER)) {
83100d0963fSdilpreet 		offset = P2ALIGN(hdr_next_ptr, 4);
83200d0963fSdilpreet 		hdr = pci_config_get32(erpt_p->pe_hdl, offset);
83300d0963fSdilpreet 		hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
83400d0963fSdilpreet 		    PCIE_EXT_CAP_NEXT_PTR_MASK;
83500d0963fSdilpreet 		hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) &
83600d0963fSdilpreet 		    PCIE_EXT_CAP_ID_MASK;
83700d0963fSdilpreet 	}
83800d0963fSdilpreet 
83900d0963fSdilpreet 	if (hdr_cap_id == PCIE_EXT_CAP_ID_AER)
84000d0963fSdilpreet 		aer_ptr = P2ALIGN(offset, 4);
84100d0963fSdilpreet 	if (aer_ptr != PCI_CAP_NEXT_PTR_NULL)
84200d0963fSdilpreet 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
84300d0963fSdilpreet 		    "pcie-aer-pointer", aer_ptr);
84400d0963fSdilpreet #endif
84500d0963fSdilpreet 
84600d0963fSdilpreet 	/*
84700d0963fSdilpreet 	 * Find and store if this device is capable of pci express
84800d0963fSdilpreet 	 * advanced errors, if not report an error against the device.
84900d0963fSdilpreet 	 */
85000d0963fSdilpreet 	pcie_ecap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
85100d0963fSdilpreet 	    "pcie-aer-pointer", PCI_CAP_NEXT_PTR_NULL);
85200d0963fSdilpreet 	if (pcie_ecap_ptr != PCI_CAP_NEXT_PTR_NULL) {
85300d0963fSdilpreet 		erpt_p->pe_dflags |= PCIEX_ADV_DEV;
85400d0963fSdilpreet 		pcie_regs->pcie_adv_regs = kmem_zalloc(
85500d0963fSdilpreet 		    sizeof (pcie_adv_error_regs_t), KM_SLEEP);
85600d0963fSdilpreet 		pcie_regs->pcie_adv_regs->pcie_adv_cap_ptr = pcie_ecap_ptr;
85700d0963fSdilpreet 	}
85800d0963fSdilpreet 
85900d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) {
86000d0963fSdilpreet 		return;
86100d0963fSdilpreet 	}
86200d0963fSdilpreet 
86300d0963fSdilpreet 	pcie_adv_regs = pcie_regs->pcie_adv_regs;
86400d0963fSdilpreet 
86500d0963fSdilpreet 	if (pcie_adv_regs == NULL)
86600d0963fSdilpreet 		return;
86700d0963fSdilpreet 	/*
86800d0963fSdilpreet 	 * Initialize structures for advanced PCI Express devices.
86900d0963fSdilpreet 	 */
87000d0963fSdilpreet 
87100d0963fSdilpreet 	/*
87200d0963fSdilpreet 	 * Advanced error registers exist for PCI Express to PCI(X) Bridges and
87300d0963fSdilpreet 	 * may also exist for PCI(X) to PCI Express Bridges, the latter is not
87400d0963fSdilpreet 	 * well explained in the PCI Express to PCI/PCI-X Bridge Specification
87500d0963fSdilpreet 	 * 1.0 and will be left out of the current gathering of these registers.
87600d0963fSdilpreet 	 */
87700d0963fSdilpreet 	if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
87800d0963fSdilpreet 		erpt_p->pe_dflags |= PCIEX_2PCI_DEV;
87900d0963fSdilpreet 		pcie_adv_regs->pcie_adv_bdg_regs = kmem_zalloc(
88000d0963fSdilpreet 		    sizeof (pcie_adv_bdg_error_regs_t), KM_SLEEP);
88100d0963fSdilpreet 	}
88200d0963fSdilpreet 
88300d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV)
88400d0963fSdilpreet 		pcie_adv_regs->pcie_adv_rc_regs = kmem_zalloc(
88500d0963fSdilpreet 		    sizeof (pcie_adv_rc_error_regs_t), KM_SLEEP);
88600d0963fSdilpreet 
88700d0963fSdilpreet 	/*
88800d0963fSdilpreet 	 * Check that mask values are as expected, if not
88900d0963fSdilpreet 	 * change them to what we desire.
89000d0963fSdilpreet 	 */
891*8aec9182Sstephh 	pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED);
89200d0963fSdilpreet 	pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
89300d0963fSdilpreet 	if (pcie_regs->pcie_adv_regs->pcie_ce_mask != pcie_expected_ce_mask) {
89400d0963fSdilpreet 		pci_config_put32(erpt_p->pe_hdl,
89500d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_CE_MASK, pcie_expected_ce_mask);
89600d0963fSdilpreet 	}
89700d0963fSdilpreet 
89800d0963fSdilpreet 	/* Disable PTLP/ECRC (or mask these two) for Switches */
89900d0963fSdilpreet 	if (dev_type == PCIE_PCIECAP_DEV_TYPE_UP ||
90000d0963fSdilpreet 	    dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN)
90100d0963fSdilpreet 		mask |= PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC;
90200d0963fSdilpreet 
90300d0963fSdilpreet 	if (pcie_regs->pcie_adv_regs->pcie_ue_mask != mask) {
90400d0963fSdilpreet 		pci_config_put32(erpt_p->pe_hdl,
90500d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_UCE_MASK, mask);
90600d0963fSdilpreet 	}
90700d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
90800d0963fSdilpreet 		if (pcie_regs->pcie_adv_regs->pcie_adv_bdg_regs->pcie_sue_mask
90900d0963fSdilpreet 		    != pcie_expected_sue_mask) {
91000d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
91100d0963fSdilpreet 			    pcie_ecap_ptr + PCIE_AER_SUCE_MASK,
91200d0963fSdilpreet 			    pcie_expected_sue_mask);
91300d0963fSdilpreet 		}
91400d0963fSdilpreet 	}
91500d0963fSdilpreet }
91600d0963fSdilpreet 
91700d0963fSdilpreet /*
91800d0963fSdilpreet  * pci_ereport_setup: Detect PCI device type and initialize structures to be
91900d0963fSdilpreet  * used to generate ereports based on detected generic device errors.
92000d0963fSdilpreet  */
92100d0963fSdilpreet void
92200d0963fSdilpreet pci_ereport_setup(dev_info_t *dip)
92300d0963fSdilpreet {
92400d0963fSdilpreet 	struct dev_info *devi = DEVI(dip);
92500d0963fSdilpreet 	struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl;
92600d0963fSdilpreet 	pci_erpt_t *erpt_p;
92700d0963fSdilpreet 	uint8_t pci_hdr_type;
92800d0963fSdilpreet 	uint16_t pci_status;
92900d0963fSdilpreet 	pci_regspec_t *pci_rp;
93000d0963fSdilpreet 	int32_t len;
93100d0963fSdilpreet 	uint32_t phys_hi;
93200d0963fSdilpreet 
93300d0963fSdilpreet 	/*
93400d0963fSdilpreet 	 * If device is not ereport capbable then report an error against the
93500d0963fSdilpreet 	 * driver for using this interface,
93600d0963fSdilpreet 	 */
93700d0963fSdilpreet 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
93800d0963fSdilpreet 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
93900d0963fSdilpreet 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
94000d0963fSdilpreet 		return;
94100d0963fSdilpreet 	}
94200d0963fSdilpreet 
94300d0963fSdilpreet 	/*
94400d0963fSdilpreet 	 * ASSERT fmhdl exists and fh_bus_specific is NULL.
94500d0963fSdilpreet 	 */
94600d0963fSdilpreet 	ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL));
94700d0963fSdilpreet 
94800d0963fSdilpreet 	erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP);
94900d0963fSdilpreet 
95000d0963fSdilpreet 	if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS)
95100d0963fSdilpreet 		goto error;
95200d0963fSdilpreet 
95300d0963fSdilpreet 	erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP);
95400d0963fSdilpreet 
95500d0963fSdilpreet 	pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT);
956*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) !=
957*8aec9182Sstephh 	    DDI_FM_OK)
95800d0963fSdilpreet 		goto error;
95900d0963fSdilpreet 
96000d0963fSdilpreet 	/*
96100d0963fSdilpreet 	 * Get header type and record if device is a bridge.
96200d0963fSdilpreet 	 */
96300d0963fSdilpreet 	pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER);
964*8aec9182Sstephh 	if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) !=
965*8aec9182Sstephh 	    DDI_FM_OK)
96600d0963fSdilpreet 		goto error;
96700d0963fSdilpreet 
96800d0963fSdilpreet 	/*
96900d0963fSdilpreet 	 * Check to see if PCI device is a bridge, if so allocate pci bridge
97000d0963fSdilpreet 	 * error register structure.
97100d0963fSdilpreet 	 */
97200d0963fSdilpreet 	if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
97300d0963fSdilpreet 		erpt_p->pe_dflags |= PCI_BRIDGE_DEV;
97400d0963fSdilpreet 		erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc(
97500d0963fSdilpreet 		    sizeof (pci_bdg_error_regs_t), KM_SLEEP);
97600d0963fSdilpreet 	}
97700d0963fSdilpreet 
97800d0963fSdilpreet 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
97900d0963fSdilpreet 	    (caddr_t)&pci_rp, &len) == DDI_SUCCESS) {
98000d0963fSdilpreet 		phys_hi = pci_rp->pci_phys_hi;
98100d0963fSdilpreet 		kmem_free(pci_rp, len);
98200d0963fSdilpreet 
98300d0963fSdilpreet 		erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >>
98400d0963fSdilpreet 		    PCI_REG_FUNC_SHIFT);
98500d0963fSdilpreet 	}
98600d0963fSdilpreet 
98700d0963fSdilpreet 
98800d0963fSdilpreet 	if (!(pci_status & PCI_STAT_CAP)) {
98900d0963fSdilpreet 		goto done;
99000d0963fSdilpreet 	}
99100d0963fSdilpreet 
99200d0963fSdilpreet 	/*
99300d0963fSdilpreet 	 * Initialize structures for PCI Express and PCI-X devices.
99400d0963fSdilpreet 	 * Order matters below and pcie_ereport_setup should preceed
99500d0963fSdilpreet 	 * pcix_ereport_setup.
99600d0963fSdilpreet 	 */
99700d0963fSdilpreet 	pcie_ereport_setup(dip, erpt_p);
99800d0963fSdilpreet 
99900d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_DEV)) {
100000d0963fSdilpreet 		pcix_ereport_setup(dip, erpt_p);
100100d0963fSdilpreet 	}
100200d0963fSdilpreet 
100300d0963fSdilpreet done:
1004*8aec9182Sstephh 	pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED);
100500d0963fSdilpreet 	pci_regs_clear(erpt_p);
100600d0963fSdilpreet 
100700d0963fSdilpreet 	/*
100800d0963fSdilpreet 	 * Before returning set fh_bus_specific to completed pci_erpt_t
100900d0963fSdilpreet 	 * structure
101000d0963fSdilpreet 	 */
101100d0963fSdilpreet 	fmhdl->fh_bus_specific = (void *)erpt_p;
101200d0963fSdilpreet 
101300d0963fSdilpreet 	return;
101400d0963fSdilpreet error:
101500d0963fSdilpreet 	if (erpt_p->pe_pci_regs)
101600d0963fSdilpreet 		kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
101700d0963fSdilpreet 	kmem_free(erpt_p, sizeof (pci_erpt_t));
101800d0963fSdilpreet 	erpt_p = NULL;
101900d0963fSdilpreet }
102000d0963fSdilpreet 
102100d0963fSdilpreet static void
102200d0963fSdilpreet pcix_ereport_teardown(pci_erpt_t *erpt_p)
102300d0963fSdilpreet {
102400d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
102500d0963fSdilpreet 		pcix_bdg_error_regs_t *pcix_bdg_regs;
102600d0963fSdilpreet 		uint16_t pcix_ver;
102700d0963fSdilpreet 
102800d0963fSdilpreet 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
102900d0963fSdilpreet 		pcix_ver = pcix_bdg_regs->pcix_bdg_ver;
103000d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_ver)) {
103100d0963fSdilpreet 			int i;
103200d0963fSdilpreet 			for (i = 0; i < 2; i++)
103300d0963fSdilpreet 				kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i],
103400d0963fSdilpreet 				    sizeof (pcix_ecc_regs_t));
103500d0963fSdilpreet 		}
103600d0963fSdilpreet 		kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t));
103700d0963fSdilpreet 	} else {
103800d0963fSdilpreet 		pcix_error_regs_t *pcix_regs;
103900d0963fSdilpreet 		uint16_t pcix_ver;
104000d0963fSdilpreet 
104100d0963fSdilpreet 		pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
104200d0963fSdilpreet 		pcix_ver = pcix_regs->pcix_ver;
104300d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_ver)) {
104400d0963fSdilpreet 			kmem_free(pcix_regs->pcix_ecc_regs,
104500d0963fSdilpreet 			    sizeof (pcix_ecc_regs_t));
104600d0963fSdilpreet 		}
104700d0963fSdilpreet 		kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t));
104800d0963fSdilpreet 	}
104900d0963fSdilpreet }
105000d0963fSdilpreet 
105100d0963fSdilpreet static void
105200d0963fSdilpreet pcie_ereport_teardown(pci_erpt_t *erpt_p)
105300d0963fSdilpreet {
105400d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
105500d0963fSdilpreet 
105600d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_ADV_DEV) {
105700d0963fSdilpreet 		pcie_adv_error_regs_t *pcie_adv = pcie_regs->pcie_adv_regs;
105800d0963fSdilpreet 
105900d0963fSdilpreet 		if (erpt_p->pe_dflags & PCIEX_2PCI_DEV)
106000d0963fSdilpreet 			kmem_free(pcie_adv->pcie_adv_bdg_regs,
106100d0963fSdilpreet 			    sizeof (pcie_adv_bdg_error_regs_t));
106200d0963fSdilpreet 		if (erpt_p->pe_dflags & PCIEX_RC_DEV)
106300d0963fSdilpreet 			kmem_free(pcie_adv->pcie_adv_rc_regs,
106400d0963fSdilpreet 			    sizeof (pcie_adv_rc_error_regs_t));
106500d0963fSdilpreet 		kmem_free(pcie_adv, sizeof (pcie_adv_error_regs_t));
106600d0963fSdilpreet 	}
106700d0963fSdilpreet 
106800d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV)
106900d0963fSdilpreet 		kmem_free(pcie_regs->pcie_rc_regs,
107000d0963fSdilpreet 		    sizeof (pcie_rc_error_regs_t));
107100d0963fSdilpreet 
107200d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
107300d0963fSdilpreet 		if (erpt_p->pe_dflags & PCIX_DEV) {
107400d0963fSdilpreet 			uint16_t pcix_ver = pcie_regs->pcix_bdg_regs->
107500d0963fSdilpreet 			    pcix_bdg_ver;
107600d0963fSdilpreet 
107700d0963fSdilpreet 			if (PCIX_ECC_VER_CHECK(pcix_ver)) {
107800d0963fSdilpreet 				int i;
107900d0963fSdilpreet 				for (i = 0; i < 2; i++)
108000d0963fSdilpreet 					kmem_free(pcie_regs->pcix_bdg_regs->
108100d0963fSdilpreet 					    pcix_bdg_ecc_regs[i],
108200d0963fSdilpreet 					    sizeof (pcix_ecc_regs_t));
108300d0963fSdilpreet 			}
108400d0963fSdilpreet 			kmem_free(pcie_regs->pcix_bdg_regs,
108500d0963fSdilpreet 			    sizeof (pcix_bdg_error_regs_t));
108600d0963fSdilpreet 		}
108700d0963fSdilpreet 	}
108800d0963fSdilpreet 	kmem_free(erpt_p->pe_regs, sizeof (pcie_error_regs_t));
108900d0963fSdilpreet }
109000d0963fSdilpreet 
109100d0963fSdilpreet void
109200d0963fSdilpreet pci_ereport_teardown(dev_info_t *dip)
109300d0963fSdilpreet {
109400d0963fSdilpreet 	struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
109500d0963fSdilpreet 	pci_erpt_t *erpt_p;
109600d0963fSdilpreet 
109700d0963fSdilpreet 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
109800d0963fSdilpreet 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
109900d0963fSdilpreet 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
110000d0963fSdilpreet 	}
110100d0963fSdilpreet 
110200d0963fSdilpreet 	ASSERT(fmhdl);
110300d0963fSdilpreet 
110400d0963fSdilpreet 	erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
110500d0963fSdilpreet 	if (erpt_p == NULL)
110600d0963fSdilpreet 		return;
110700d0963fSdilpreet 
110800d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_DEV)
110900d0963fSdilpreet 		pcie_ereport_teardown(erpt_p);
111000d0963fSdilpreet 	else if (erpt_p->pe_dflags & PCIX_DEV)
111100d0963fSdilpreet 		pcix_ereport_teardown(erpt_p);
111200d0963fSdilpreet 	pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl);
111300d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV)
111400d0963fSdilpreet 		kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs,
111500d0963fSdilpreet 		    sizeof (pci_bdg_error_regs_t));
111600d0963fSdilpreet 	kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
111700d0963fSdilpreet 	kmem_free(erpt_p, sizeof (pci_erpt_t));
111800d0963fSdilpreet 	fmhdl->fh_bus_specific = NULL;
111900d0963fSdilpreet 	/*
112000d0963fSdilpreet 	 * The following sparc specific code should be removed once the pci_cap
112100d0963fSdilpreet 	 * interfaces create the necessary properties for us.
112200d0963fSdilpreet 	 */
112300d0963fSdilpreet #if defined(__sparc)
112400d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcix-capid-pointer");
112500d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-slotcap-reg");
112600d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-reg");
112700d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-pointer");
112800d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-aer-pointer");
112900d0963fSdilpreet #endif
113000d0963fSdilpreet }
113100d0963fSdilpreet 
113200d0963fSdilpreet static void
113300d0963fSdilpreet pcie_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
113400d0963fSdilpreet     char *buf, int errtype)
113500d0963fSdilpreet {
113600d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
113700d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs;
1138390e643aSdilpreet 	pcie_adv_rc_error_regs_t *pcie_adv_rc_regs;
113900d0963fSdilpreet 
114000d0963fSdilpreet 	switch (errtype) {
114100d0963fSdilpreet 	    case PCIEX_TYPE_CE:
114200d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
114300d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
114400d0963fSdilpreet 		    PCIEX_DEVSTS_REG, DATA_TYPE_UINT16,
114500d0963fSdilpreet 		    pcie_regs->pcie_err_status,
114600d0963fSdilpreet 		    PCIEX_CE_STATUS_REG, DATA_TYPE_UINT32,
114700d0963fSdilpreet 		    pcie_adv_regs->pcie_ce_status, NULL);
114800d0963fSdilpreet 		break;
114900d0963fSdilpreet 	    case PCIEX_TYPE_UE:
115000d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
115100d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
115200d0963fSdilpreet 		    PCIEX_DEVSTS_REG, DATA_TYPE_UINT16,
115300d0963fSdilpreet 		    pcie_regs->pcie_err_status,
115400d0963fSdilpreet 		    PCIEX_UE_STATUS_REG, DATA_TYPE_UINT32,
115500d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_status, PCIEX_UE_SEV_REG,
115600d0963fSdilpreet 		    DATA_TYPE_UINT32, pcie_adv_regs->pcie_ue_sev,
115700d0963fSdilpreet 		    PCIEX_ADV_CTL, DATA_TYPE_UINT32,
115800d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_ctl,
115900d0963fSdilpreet 		    PCIEX_SRC_ID, DATA_TYPE_UINT16,
116000d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_bdf,
116100d0963fSdilpreet 		    PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE,
116200d0963fSdilpreet 		    (pcie_adv_regs->pcie_adv_bdf != NULL) ?
116300d0963fSdilpreet 		    1 : NULL,
116400d0963fSdilpreet #ifdef DEBUG
116500d0963fSdilpreet 		    PCIEX_UE_HDR0, DATA_TYPE_UINT32,
116600d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_hdr0,
116700d0963fSdilpreet 		    PCIEX_UE_HDR1, DATA_TYPE_UINT32,
116800d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_hdr[0],
116900d0963fSdilpreet 		    PCIEX_UE_HDR2, DATA_TYPE_UINT32,
117000d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_hdr[1],
117100d0963fSdilpreet 		    PCIEX_UE_HDR3, DATA_TYPE_UINT32,
117200d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_hdr[2],
117300d0963fSdilpreet #endif
117400d0963fSdilpreet 		    NULL);
117500d0963fSdilpreet 		break;
117600d0963fSdilpreet 	    case PCIEX_TYPE_GEN:
117700d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
117800d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8,
117900d0963fSdilpreet 		    0, PCIEX_DEVSTS_REG, DATA_TYPE_UINT16,
118000d0963fSdilpreet 		    pcie_regs->pcie_err_status, NULL);
118100d0963fSdilpreet 		break;
118200d0963fSdilpreet 	    case PCIEX_TYPE_RC_UE_MSG:
118300d0963fSdilpreet 	    case PCIEX_TYPE_RC_CE_MSG:
1184390e643aSdilpreet 		pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs;
1185390e643aSdilpreet 
118600d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
118700d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
118800d0963fSdilpreet 		    PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32,
118900d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_err_status,
119000d0963fSdilpreet 		    PCIEX_SRC_ID, DATA_TYPE_UINT16,
119100d0963fSdilpreet 		    (errtype == PCIEX_TYPE_RC_UE_MSG) ?
119200d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_ue_src_id :
119300d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_ce_src_id,
119400d0963fSdilpreet 		    PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE,
119500d0963fSdilpreet 		    (errtype == PCIEX_TYPE_RC_UE_MSG) ?
119600d0963fSdilpreet 		    (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID &&
119700d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_ue_src_id != 0) :
119800d0963fSdilpreet 		    (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID &&
119900d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_ce_src_id != 0), NULL);
120000d0963fSdilpreet 		break;
120100d0963fSdilpreet 	    case PCIEX_TYPE_RC_MULT_MSG:
1202390e643aSdilpreet 		pcie_adv_rc_regs = pcie_adv_regs->pcie_adv_rc_regs;
1203390e643aSdilpreet 
120400d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
120500d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
120600d0963fSdilpreet 		    PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32,
120700d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_err_status, NULL);
120800d0963fSdilpreet 		break;
120900d0963fSdilpreet 	    default:
121000d0963fSdilpreet 		break;
121100d0963fSdilpreet 	}
121200d0963fSdilpreet }
121300d0963fSdilpreet 
1214*8aec9182Sstephh /*ARGSUSED*/
121500d0963fSdilpreet static void
1216*8aec9182Sstephh pcie_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
121700d0963fSdilpreet {
1218*8aec9182Sstephh 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
121900d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs;
122000d0963fSdilpreet 	pcie_tlp_hdr_t *ue_hdr0;
122100d0963fSdilpreet 	uint32_t *ue_hdr;
122200d0963fSdilpreet 	uint64_t addr = NULL;
1223*8aec9182Sstephh 	int upstream = 0;
1224*8aec9182Sstephh 	pci_fme_bus_specific_t *pci_fme_bsp =
1225*8aec9182Sstephh 	    (pci_fme_bus_specific_t *)derr->fme_bus_specific;
122600d0963fSdilpreet 
1227*8aec9182Sstephh 	if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_UE_HDR_VALID))
122800d0963fSdilpreet 		return;
1229*8aec9182Sstephh 
123000d0963fSdilpreet 	ue_hdr0 = (pcie_tlp_hdr_t *)&pcie_adv_regs->pcie_ue_hdr0;
123100d0963fSdilpreet 	ue_hdr = pcie_adv_regs->pcie_ue_hdr;
123200d0963fSdilpreet 
1233*8aec9182Sstephh 	if ((pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) ==
1234*8aec9182Sstephh 	    PCIE_PCIECAP_DEV_TYPE_ROOT ||
1235*8aec9182Sstephh 	    (pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) ==
1236*8aec9182Sstephh 	    PCIE_PCIECAP_DEV_TYPE_DOWN)
1237*8aec9182Sstephh 		upstream = 1;
1238*8aec9182Sstephh 
123900d0963fSdilpreet 	switch (ue_hdr0->type) {
124000d0963fSdilpreet 	    case PCIE_TLP_TYPE_MEM:
124100d0963fSdilpreet 	    case PCIE_TLP_TYPE_MEMLK:
124200d0963fSdilpreet 		if ((ue_hdr0->fmt & 0x1) == 0x1) {
124300d0963fSdilpreet 			pcie_mem64_t *mem64_tlp = (pcie_mem64_t *)ue_hdr;
124400d0963fSdilpreet 
124500d0963fSdilpreet 			addr = (uint64_t)mem64_tlp->addr1 << 32 |
124600d0963fSdilpreet 			    (uint32_t)mem64_tlp->addr0 << 2;
124700d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = mem64_tlp->rid;
124800d0963fSdilpreet 		} else {
124900d0963fSdilpreet 			pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr;
125000d0963fSdilpreet 
125100d0963fSdilpreet 			addr = (uint32_t)memio32_tlp->addr0 << 2;
125200d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid;
125300d0963fSdilpreet 		}
1254*8aec9182Sstephh 		if (upstream) {
1255*8aec9182Sstephh 			pci_fme_bsp->pci_bs_bdf = pcie_adv_regs->pcie_adv_bdf;
1256*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
1257*8aec9182Sstephh 		} else if ((pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK) ==
1258*8aec9182Sstephh 		    PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
1259*8aec9182Sstephh 			pci_fme_bsp->pci_bs_bdf = erpt_p->pe_bdf;
1260*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
1261*8aec9182Sstephh 		}
1262*8aec9182Sstephh 		pci_fme_bsp->pci_bs_addr = addr;
1263*8aec9182Sstephh 		pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
1264*8aec9182Sstephh 		pci_fme_bsp->pci_bs_type = upstream ? DMA_HANDLE : ACC_HANDLE;
126500d0963fSdilpreet 		break;
126600d0963fSdilpreet 
126700d0963fSdilpreet 	    case PCIE_TLP_TYPE_IO:
126800d0963fSdilpreet 		{
126900d0963fSdilpreet 			pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr;
127000d0963fSdilpreet 
127100d0963fSdilpreet 			addr = (uint32_t)memio32_tlp->addr0 << 2;
127200d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid;
1273*8aec9182Sstephh 			if ((pcie_regs->pcie_cap &
1274*8aec9182Sstephh 			    PCIE_PCIECAP_DEV_TYPE_MASK) ==
1275*8aec9182Sstephh 			    PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
1276*8aec9182Sstephh 				pci_fme_bsp->pci_bs_bdf = erpt_p->pe_bdf;
1277*8aec9182Sstephh 				pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
1278*8aec9182Sstephh 			}
1279*8aec9182Sstephh 			pci_fme_bsp->pci_bs_addr = addr;
1280*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
1281*8aec9182Sstephh 			pci_fme_bsp->pci_bs_type = ACC_HANDLE;
128200d0963fSdilpreet 			break;
128300d0963fSdilpreet 		}
128400d0963fSdilpreet 	    case PCIE_TLP_TYPE_CFG0:
128500d0963fSdilpreet 	    case PCIE_TLP_TYPE_CFG1:
128600d0963fSdilpreet 		{
128700d0963fSdilpreet 			pcie_cfg_t *cfg_tlp = (pcie_cfg_t *)ue_hdr;
128800d0963fSdilpreet 
1289ac4d633fSstephh 			pcie_adv_regs->pcie_adv_bdf = cfg_tlp->rid;
1290*8aec9182Sstephh 			pci_fme_bsp->pci_bs_bdf = (uint16_t)cfg_tlp->bus << 8 |
1291*8aec9182Sstephh 			    (uint16_t)cfg_tlp->dev << 3 | cfg_tlp->func;
1292*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
1293*8aec9182Sstephh 			pci_fme_bsp->pci_bs_type = ACC_HANDLE;
129400d0963fSdilpreet 			break;
129500d0963fSdilpreet 		}
129600d0963fSdilpreet 	    case PCIE_TLP_TYPE_MSG:
129700d0963fSdilpreet 		{
129800d0963fSdilpreet 			pcie_msg_t *msg_tlp = (pcie_msg_t *)ue_hdr;
129900d0963fSdilpreet 
130000d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = msg_tlp->rid;
130100d0963fSdilpreet 			break;
130200d0963fSdilpreet 		}
130300d0963fSdilpreet 	    case PCIE_TLP_TYPE_CPL:
130400d0963fSdilpreet 	    case PCIE_TLP_TYPE_CPLLK:
130500d0963fSdilpreet 		{
130600d0963fSdilpreet 			pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)ue_hdr;
130700d0963fSdilpreet 
130800d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = cpl_tlp->cid;
1309*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
1310*8aec9182Sstephh 			if (upstream) {
1311*8aec9182Sstephh 				pci_fme_bsp->pci_bs_bdf = cpl_tlp->cid;
1312*8aec9182Sstephh 				pci_fme_bsp->pci_bs_type = ACC_HANDLE;
1313*8aec9182Sstephh 			} else {
1314*8aec9182Sstephh 				pci_fme_bsp->pci_bs_bdf = cpl_tlp->rid;
1315*8aec9182Sstephh 				pci_fme_bsp->pci_bs_type = DMA_HANDLE;
1316*8aec9182Sstephh 			}
131700d0963fSdilpreet 			break;
131800d0963fSdilpreet 		}
131900d0963fSdilpreet 	    case PCIE_TLP_TYPE_MSI:
132000d0963fSdilpreet 	    default:
1321*8aec9182Sstephh 		break;
1322*8aec9182Sstephh 	}
132300d0963fSdilpreet }
132400d0963fSdilpreet 
1325*8aec9182Sstephh /*ARGSUSED*/
132600d0963fSdilpreet static void
1327*8aec9182Sstephh pcie_pci_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
1328*8aec9182Sstephh     int type)
132900d0963fSdilpreet {
1330*8aec9182Sstephh 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
133100d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs;
133200d0963fSdilpreet 	pcie_adv_bdg_error_regs_t *pcie_bdg_regs =
133300d0963fSdilpreet 	    pcie_adv_regs->pcie_adv_bdg_regs;
133400d0963fSdilpreet 	uint64_t addr = NULL;
133500d0963fSdilpreet 	pcix_attr_t *pcie_pci_sue_attr;
133600d0963fSdilpreet 	int cmd;
133700d0963fSdilpreet 	int dual_addr = 0;
1338*8aec9182Sstephh 	pci_fme_bus_specific_t *pci_fme_bsp =
1339*8aec9182Sstephh 	    (pci_fme_bus_specific_t *)derr->fme_bus_specific;
134000d0963fSdilpreet 
1341*8aec9182Sstephh 	if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_HDR_VALID))
134200d0963fSdilpreet 		return;
134300d0963fSdilpreet 
134400d0963fSdilpreet 	pcie_pci_sue_attr = (pcix_attr_t *)&pcie_bdg_regs->pcie_sue_hdr0;
134500d0963fSdilpreet 	cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >>
134600d0963fSdilpreet 	    PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK;
1347*8aec9182Sstephh 
134800d0963fSdilpreet cmd_switch:
1349*8aec9182Sstephh 	addr = pcie_bdg_regs->pcie_sue_hdr[2];
1350*8aec9182Sstephh 	addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) |
1351*8aec9182Sstephh 	    pcie_bdg_regs->pcie_sue_hdr[1];
135200d0963fSdilpreet 	switch (cmd) {
135300d0963fSdilpreet 	    case PCI_PCIX_CMD_IORD:
135400d0963fSdilpreet 	    case PCI_PCIX_CMD_IOWR:
135500d0963fSdilpreet 		pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid;
1356*8aec9182Sstephh 		if (addr) {
1357*8aec9182Sstephh 			pci_fme_bsp->pci_bs_addr = addr;
1358*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
1359*8aec9182Sstephh 			pci_fme_bsp->pci_bs_type = ACC_HANDLE;
1360*8aec9182Sstephh 		}
136100d0963fSdilpreet 		break;
136200d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRD_DW:
136300d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWR:
136400d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRD_BL:
136500d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWR_BL:
136600d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRDBL:
136700d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWRBL:
136800d0963fSdilpreet 		pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid;
1369*8aec9182Sstephh 		if (addr) {
1370*8aec9182Sstephh 			pci_fme_bsp->pci_bs_addr = addr;
1371*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
1372*8aec9182Sstephh 			pci_fme_bsp->pci_bs_type = type;
1373*8aec9182Sstephh 		}
137400d0963fSdilpreet 		break;
137500d0963fSdilpreet 	    case PCI_PCIX_CMD_CFRD:
137600d0963fSdilpreet 	    case PCI_PCIX_CMD_CFWR:
1377ac4d633fSstephh 		pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid;
1378*8aec9182Sstephh 		/*
1379*8aec9182Sstephh 		 * for type 1 config transaction we can find bdf from address
1380*8aec9182Sstephh 		 */
1381*8aec9182Sstephh 		if ((addr & 3) == 1) {
1382*8aec9182Sstephh 			pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff;
1383*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
1384*8aec9182Sstephh 			pci_fme_bsp->pci_bs_type = ACC_HANDLE;
1385*8aec9182Sstephh 		}
1386*8aec9182Sstephh 		break;
1387*8aec9182Sstephh 	    case PCI_PCIX_CMD_SPL:
1388*8aec9182Sstephh 		pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid;
1389*8aec9182Sstephh 		if (type == ACC_HANDLE) {
1390*8aec9182Sstephh 			pci_fme_bsp->pci_bs_bdf = pcie_adv_regs->pcie_adv_bdf;
1391*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
1392*8aec9182Sstephh 			pci_fme_bsp->pci_bs_type = type;
1393*8aec9182Sstephh 		}
139400d0963fSdilpreet 		break;
139500d0963fSdilpreet 	    case PCI_PCIX_CMD_DADR:
139600d0963fSdilpreet 		cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >>
139700d0963fSdilpreet 		    PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) &
139800d0963fSdilpreet 		    PCIE_AER_SUCE_HDR_CMD_UP_MASK;
139900d0963fSdilpreet 		if (dual_addr)
140000d0963fSdilpreet 			break;
140100d0963fSdilpreet 		++dual_addr;
140200d0963fSdilpreet 		goto cmd_switch;
140300d0963fSdilpreet 	    default:
1404*8aec9182Sstephh 		break;
1405*8aec9182Sstephh 	}
140600d0963fSdilpreet }
140700d0963fSdilpreet 
1408*8aec9182Sstephh /*ARGSUSED*/
140900d0963fSdilpreet static int
141000d0963fSdilpreet pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr,
1411*8aec9182Sstephh     pcix_ecc_regs_t *pcix_ecc_regs, int type)
141200d0963fSdilpreet {
141300d0963fSdilpreet 	int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf;
141400d0963fSdilpreet 	uint64_t addr;
1415*8aec9182Sstephh 	pci_fme_bus_specific_t *pci_fme_bsp =
1416*8aec9182Sstephh 	    (pci_fme_bus_specific_t *)derr->fme_bus_specific;
141700d0963fSdilpreet 
141800d0963fSdilpreet 	addr = pcix_ecc_regs->pcix_ecc_secaddr;
141900d0963fSdilpreet 	addr = addr << 32;
142000d0963fSdilpreet 	addr |= pcix_ecc_regs->pcix_ecc_fstaddr;
142100d0963fSdilpreet 
142200d0963fSdilpreet 	switch (cmd) {
142300d0963fSdilpreet 	    case PCI_PCIX_CMD_INTR:
142400d0963fSdilpreet 	    case PCI_PCIX_CMD_SPEC:
142500d0963fSdilpreet 		return (DDI_FM_FATAL);
142600d0963fSdilpreet 	    case PCI_PCIX_CMD_IORD:
142700d0963fSdilpreet 	    case PCI_PCIX_CMD_IOWR:
1428*8aec9182Sstephh 		pci_fme_bsp->pci_bs_addr = addr;
1429*8aec9182Sstephh 		pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
1430*8aec9182Sstephh 		pci_fme_bsp->pci_bs_type = type;
1431*8aec9182Sstephh 		return (DDI_FM_UNKNOWN);
143200d0963fSdilpreet 	    case PCI_PCIX_CMD_DEVID:
143300d0963fSdilpreet 		return (DDI_FM_FATAL);
143400d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRD_DW:
143500d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWR:
143600d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRD_BL:
143700d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWR_BL:
1438*8aec9182Sstephh 		pci_fme_bsp->pci_bs_addr = addr;
1439*8aec9182Sstephh 		pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
1440*8aec9182Sstephh 		pci_fme_bsp->pci_bs_type = type;
1441*8aec9182Sstephh 		return (DDI_FM_UNKNOWN);
144200d0963fSdilpreet 	    case PCI_PCIX_CMD_CFRD:
144300d0963fSdilpreet 	    case PCI_PCIX_CMD_CFWR:
1444*8aec9182Sstephh 		/*
1445*8aec9182Sstephh 		 * for type 1 config transaction we can find bdf from address
1446*8aec9182Sstephh 		 */
1447*8aec9182Sstephh 		if ((addr & 3) == 1) {
1448*8aec9182Sstephh 			pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff;
1449*8aec9182Sstephh 			pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
1450*8aec9182Sstephh 			pci_fme_bsp->pci_bs_type = type;
1451*8aec9182Sstephh 		}
1452*8aec9182Sstephh 		return (DDI_FM_UNKNOWN);
145300d0963fSdilpreet 	    case PCI_PCIX_CMD_SPL:
145400d0963fSdilpreet 	    case PCI_PCIX_CMD_DADR:
1455*8aec9182Sstephh 		return (DDI_FM_UNKNOWN);
145600d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRDBL:
145700d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWRBL:
1458*8aec9182Sstephh 		pci_fme_bsp->pci_bs_addr = addr;
1459*8aec9182Sstephh 		pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
1460*8aec9182Sstephh 		pci_fme_bsp->pci_bs_type = type;
1461*8aec9182Sstephh 		return (DDI_FM_UNKNOWN);
146200d0963fSdilpreet 	    default:
146300d0963fSdilpreet 		return (DDI_FM_FATAL);
146400d0963fSdilpreet 	}
146500d0963fSdilpreet }
146600d0963fSdilpreet 
146700d0963fSdilpreet /*ARGSUSED*/
146800d0963fSdilpreet static int
146900d0963fSdilpreet pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
147000d0963fSdilpreet {
147100d0963fSdilpreet 	pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs;
147200d0963fSdilpreet 	int fatal = 0;
147300d0963fSdilpreet 	int nonfatal = 0;
147400d0963fSdilpreet 	int unknown = 0;
147500d0963fSdilpreet 	int ok = 0;
147600d0963fSdilpreet 	int ret = DDI_FM_OK;
147700d0963fSdilpreet 	char buf[FM_MAX_CLASS];
147800d0963fSdilpreet 	int i;
1479*8aec9182Sstephh 	pci_fme_bus_specific_t *pci_fme_bsp =
1480*8aec9182Sstephh 	    (pci_fme_bus_specific_t *)derr->fme_bus_specific;
148100d0963fSdilpreet 
148200d0963fSdilpreet 	if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED)
148300d0963fSdilpreet 		goto done;
148400d0963fSdilpreet 
148500d0963fSdilpreet 	if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) &&
148600d0963fSdilpreet 	    (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) {
148700d0963fSdilpreet 		(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
148800d0963fSdilpreet 		    PCI_ERROR_SUBCLASS, PCI_DTO);
148900d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
149000d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
149100d0963fSdilpreet 		    PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
149200d0963fSdilpreet 		    pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
149300d0963fSdilpreet 		    DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL);
149400d0963fSdilpreet 		unknown++;
149500d0963fSdilpreet 	}
149600d0963fSdilpreet 
149700d0963fSdilpreet 	if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) {
149800d0963fSdilpreet 		for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) {
149900d0963fSdilpreet 			if (pci_bdg_regs->pci_bdg_sec_stat &
150000d0963fSdilpreet 			    pci_bdg_err_tbl[i].reg_bit) {
150100d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s",
150200d0963fSdilpreet 				    PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS,
150300d0963fSdilpreet 				    pci_bdg_err_tbl[i].err_class);
150400d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
150500d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
150600d0963fSdilpreet 				    PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
150700d0963fSdilpreet 				    pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
150800d0963fSdilpreet 				    DATA_TYPE_UINT16,
150900d0963fSdilpreet 				    pci_bdg_regs->pci_bdg_ctrl, NULL);
1510ac4d633fSstephh 				PCI_FM_SEV_INC(pci_bdg_err_tbl[i].flags);
1511*8aec9182Sstephh 				if (pci_fme_bsp && (pci_fme_bsp->pci_bs_flags &
1512*8aec9182Sstephh 				    PCI_BS_ADDR_VALID) &&
1513*8aec9182Sstephh 				    pci_fme_bsp->pci_bs_type == ACC_HANDLE &&
151400d0963fSdilpreet 				    pci_bdg_err_tbl[i].terr_class)
151500d0963fSdilpreet 					pci_target_enqueue(derr->fme_ena,
151600d0963fSdilpreet 					    pci_bdg_err_tbl[i].terr_class,
151700d0963fSdilpreet 					    PCI_ERROR_SUBCLASS,
1518*8aec9182Sstephh 					    pci_fme_bsp->pci_bs_addr);
151900d0963fSdilpreet 			}
152000d0963fSdilpreet 		}
1521ac4d633fSstephh #if !defined(__sparc)
1522ac4d633fSstephh 		/*
1523ac4d633fSstephh 		 * For x86, many drivers and even user-level code currently get
1524ac4d633fSstephh 		 * away with accessing bad addresses, getting a UR and getting
1525ac4d633fSstephh 		 * -1 returned. Unfortunately, we have no control over this, so
1526ac4d633fSstephh 		 * we will have to treat all URs as nonfatal. Moreover, if the
1527ac4d633fSstephh 		 * leaf driver is non-hardened, then we don't actually see the
1528ac4d633fSstephh 		 * UR directly. All we see is a secondary bus master abort at
1529ac4d633fSstephh 		 * the root complex - so it's this condition that we actually
1530ac4d633fSstephh 		 * need to treat as nonfatal (providing no other unrelated nfe
1531ac4d633fSstephh 		 * conditions have also been seen by the root complex).
1532ac4d633fSstephh 		 */
1533ac4d633fSstephh 		if ((erpt_p->pe_dflags & PCIEX_RC_DEV) &&
1534ac4d633fSstephh 		    (pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_R_MAST_AB) &&
1535ac4d633fSstephh 		    !(pci_bdg_regs->pci_bdg_sec_stat & PCI_STAT_S_PERROR)) {
1536ac4d633fSstephh 			pcie_error_regs_t *pcie_regs =
1537ac4d633fSstephh 			    (pcie_error_regs_t *)erpt_p->pe_regs;
1538ac4d633fSstephh 			if ((pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID) &&
1539ac4d633fSstephh 			    !(pcie_regs->pcie_err_status &
1540ac4d633fSstephh 			    PCIE_DEVSTS_NFE_DETECTED))
1541ac4d633fSstephh 				nonfatal++;
1542*8aec9182Sstephh 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s",
1543*8aec9182Sstephh 			    PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, PCI_MA);
1544*8aec9182Sstephh 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1545*8aec9182Sstephh 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1546*8aec9182Sstephh 			    PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
1547*8aec9182Sstephh 			    pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
1548*8aec9182Sstephh 			    DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL);
1549ac4d633fSstephh 		}
1550ac4d633fSstephh #endif
155100d0963fSdilpreet 	}
155200d0963fSdilpreet 
155300d0963fSdilpreet done:
155400d0963fSdilpreet 	/*
155500d0963fSdilpreet 	 * Need to check for poke and cautious put. We already know peek
155600d0963fSdilpreet 	 * and cautious get errors occurred (as we got a trap) and we know
155700d0963fSdilpreet 	 * they are nonfatal.
155800d0963fSdilpreet 	 */
155900d0963fSdilpreet 	if (derr->fme_flag == DDI_FM_ERR_EXPECTED) {
156000d0963fSdilpreet 		/*
156100d0963fSdilpreet 		 * for cautious puts we treat all errors as nonfatal. Actually
156200d0963fSdilpreet 		 * we set nonfatal for cautious gets as well - doesn't do any
156300d0963fSdilpreet 		 * harm
156400d0963fSdilpreet 		 */
156500d0963fSdilpreet 		if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
156600d0963fSdilpreet 		    PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR))
156700d0963fSdilpreet 			nonfatal++;
156800d0963fSdilpreet 	}
156900d0963fSdilpreet 	if (derr->fme_flag == DDI_FM_ERR_POKE) {
157000d0963fSdilpreet 		/*
157100d0963fSdilpreet 		 * special case for pokes - we only consider master abort
157200d0963fSdilpreet 		 * and target abort as nonfatal. Sserr with no master abort is
157300d0963fSdilpreet 		 * fatal, but master/target abort can come in on separate
157400d0963fSdilpreet 		 * instance, so return unknown and parent will determine if
157500d0963fSdilpreet 		 * nonfatal (if another child returned nonfatal - ie master
157600d0963fSdilpreet 		 * or target abort) or fatal otherwise
157700d0963fSdilpreet 		 */
157800d0963fSdilpreet 		if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
157900d0963fSdilpreet 		    PCI_STAT_R_MAST_AB))
158000d0963fSdilpreet 			nonfatal++;
158100d0963fSdilpreet 		if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR)
158200d0963fSdilpreet 			unknown++;
158300d0963fSdilpreet 	}
158400d0963fSdilpreet 
158500d0963fSdilpreet 	/*
1586*8aec9182Sstephh 	 * now check children below the bridge
158700d0963fSdilpreet 	 */
158800d0963fSdilpreet 	ret = ndi_fm_handler_dispatch(dip, NULL, derr);
158900d0963fSdilpreet 	PCI_FM_SEV_INC(ret);
159000d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
159100d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
159200d0963fSdilpreet }
159300d0963fSdilpreet 
159400d0963fSdilpreet static int
159500d0963fSdilpreet pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
159600d0963fSdilpreet     void *pe_regs)
159700d0963fSdilpreet {
159800d0963fSdilpreet 	pcix_error_regs_t *pcix_regs;
159900d0963fSdilpreet 	pcix_bdg_error_regs_t *pcix_bdg_regs;
160000d0963fSdilpreet 	pcix_ecc_regs_t *pcix_ecc_regs;
160100d0963fSdilpreet 	int bridge;
160200d0963fSdilpreet 	int i;
160300d0963fSdilpreet 	int ecc_phase;
160400d0963fSdilpreet 	int ecc_corr;
160500d0963fSdilpreet 	int sec_ue;
160600d0963fSdilpreet 	int sec_ce;
160700d0963fSdilpreet 	int fatal = 0;
160800d0963fSdilpreet 	int nonfatal = 0;
160900d0963fSdilpreet 	int unknown = 0;
161000d0963fSdilpreet 	int ok = 0;
161100d0963fSdilpreet 	char buf[FM_MAX_CLASS];
161200d0963fSdilpreet 
161300d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
161400d0963fSdilpreet 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
161500d0963fSdilpreet 		bridge = 1;
161600d0963fSdilpreet 	} else {
161700d0963fSdilpreet 		pcix_regs = (pcix_error_regs_t *)pe_regs;
161800d0963fSdilpreet 		bridge = 0;
161900d0963fSdilpreet 	}
162000d0963fSdilpreet 
162100d0963fSdilpreet 	for (i = 0; i < (bridge ? 2 : 1); i++) {
162200d0963fSdilpreet 		int ret = DDI_FM_OK;
162300d0963fSdilpreet 		pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] :
162400d0963fSdilpreet 		    pcix_regs->pcix_ecc_regs;
162500d0963fSdilpreet 		if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) {
162600d0963fSdilpreet 			ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat &
162700d0963fSdilpreet 			    PCI_PCIX_ECC_PHASE) >> 0x4;
162800d0963fSdilpreet 			ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat &
162900d0963fSdilpreet 			    PCI_PCIX_ECC_CORR);
163000d0963fSdilpreet 			sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat &
163100d0963fSdilpreet 			    PCI_PCIX_ECC_S_UE);
163200d0963fSdilpreet 			sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat &
163300d0963fSdilpreet 			    PCI_PCIX_ECC_S_CE);
163400d0963fSdilpreet 
163500d0963fSdilpreet 			switch (ecc_phase) {
163600d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_NOERR:
163700d0963fSdilpreet 				break;
163800d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_FADDR:
163900d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_SADDR:
1640ac4d633fSstephh 				PCI_FM_SEV_INC(ecc_corr ?  DDI_FM_OK :
164100d0963fSdilpreet 				    DDI_FM_FATAL);
164200d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS,
164300d0963fSdilpreet 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
164400d0963fSdilpreet 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
164500d0963fSdilpreet 				    ecc_corr ? PCIX_ECC_CE_ADDR :
164600d0963fSdilpreet 				    PCIX_ECC_UE_ADDR);
164700d0963fSdilpreet 				break;
164800d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_ATTR:
164900d0963fSdilpreet 				PCI_FM_SEV_INC(ecc_corr ?
1650ac4d633fSstephh 				    DDI_FM_OK : DDI_FM_FATAL);
165100d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS,
165200d0963fSdilpreet 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
165300d0963fSdilpreet 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
165400d0963fSdilpreet 				    ecc_corr ? PCIX_ECC_CE_ATTR :
165500d0963fSdilpreet 				    PCIX_ECC_UE_ATTR);
165600d0963fSdilpreet 				break;
165700d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_DATA32:
165800d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_DATA64:
165900d0963fSdilpreet 				if (ecc_corr)
1660ac4d633fSstephh 					ret = DDI_FM_OK;
1661*8aec9182Sstephh 				else {
1662*8aec9182Sstephh 					int type;
1663*8aec9182Sstephh 					pci_error_regs_t *pci_regs =
1664*8aec9182Sstephh 					    erpt_p->pe_pci_regs;
1665*8aec9182Sstephh 
1666*8aec9182Sstephh 					if (i) {
1667*8aec9182Sstephh 						if (pci_regs->pci_bdg_regs->
1668*8aec9182Sstephh 						    pci_bdg_sec_stat &
1669*8aec9182Sstephh 						    PCI_STAT_S_PERROR)
1670*8aec9182Sstephh 							type = ACC_HANDLE;
167100d0963fSdilpreet 						else
1672*8aec9182Sstephh 							type = DMA_HANDLE;
1673*8aec9182Sstephh 					} else {
1674*8aec9182Sstephh 						if (pci_regs->pci_err_status &
1675*8aec9182Sstephh 						    PCI_STAT_S_PERROR)
1676*8aec9182Sstephh 							type = DMA_HANDLE;
1677*8aec9182Sstephh 						else
1678*8aec9182Sstephh 							type = ACC_HANDLE;
1679*8aec9182Sstephh 					}
168000d0963fSdilpreet 					ret = pcix_check_addr(dip, derr,
1681*8aec9182Sstephh 					    pcix_ecc_regs, type);
1682*8aec9182Sstephh 				}
168300d0963fSdilpreet 				PCI_FM_SEV_INC(ret);
168400d0963fSdilpreet 
168500d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS,
168600d0963fSdilpreet 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
168700d0963fSdilpreet 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
168800d0963fSdilpreet 				    ecc_corr ? PCIX_ECC_CE_DATA :
168900d0963fSdilpreet 				    PCIX_ECC_UE_DATA);
169000d0963fSdilpreet 				break;
169100d0963fSdilpreet 			}
169200d0963fSdilpreet 			if (ecc_phase)
169300d0963fSdilpreet 				if (bridge)
169400d0963fSdilpreet 					ddi_fm_ereport_post(dip, buf,
169500d0963fSdilpreet 					    derr->fme_ena,
169600d0963fSdilpreet 					    DDI_NOSLEEP, FM_VERSION,
169700d0963fSdilpreet 					    DATA_TYPE_UINT8, 0,
169800d0963fSdilpreet 					    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
169900d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_sec_stat,
170000d0963fSdilpreet 					    PCIX_BDG_STAT, DATA_TYPE_UINT32,
170100d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_stat,
170200d0963fSdilpreet 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
170300d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_ctlstat,
170400d0963fSdilpreet 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
170500d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
170600d0963fSdilpreet 				else
170700d0963fSdilpreet 					ddi_fm_ereport_post(dip, buf,
170800d0963fSdilpreet 					    derr->fme_ena,
170900d0963fSdilpreet 					    DDI_NOSLEEP, FM_VERSION,
171000d0963fSdilpreet 					    DATA_TYPE_UINT8, 0,
171100d0963fSdilpreet 					    PCIX_COMMAND, DATA_TYPE_UINT16,
171200d0963fSdilpreet 					    pcix_regs->pcix_command,
171300d0963fSdilpreet 					    PCIX_STATUS, DATA_TYPE_UINT32,
171400d0963fSdilpreet 					    pcix_regs->pcix_status,
171500d0963fSdilpreet 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
171600d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_ctlstat,
171700d0963fSdilpreet 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
171800d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
171900d0963fSdilpreet 			if (sec_ce || sec_ue) {
172000d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS,
172100d0963fSdilpreet 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
172200d0963fSdilpreet 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
172300d0963fSdilpreet 				    sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE);
172400d0963fSdilpreet 				if (bridge)
172500d0963fSdilpreet 					ddi_fm_ereport_post(dip, buf,
172600d0963fSdilpreet 					    derr->fme_ena,
172700d0963fSdilpreet 					    DDI_NOSLEEP, FM_VERSION,
172800d0963fSdilpreet 					    DATA_TYPE_UINT8, 0,
172900d0963fSdilpreet 					    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
173000d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_sec_stat,
173100d0963fSdilpreet 					    PCIX_BDG_STAT, DATA_TYPE_UINT32,
173200d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_stat,
173300d0963fSdilpreet 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
173400d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_ctlstat,
173500d0963fSdilpreet 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
173600d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
173700d0963fSdilpreet 				else
173800d0963fSdilpreet 					ddi_fm_ereport_post(dip, buf,
173900d0963fSdilpreet 					    derr->fme_ena,
174000d0963fSdilpreet 					    DDI_NOSLEEP, FM_VERSION,
174100d0963fSdilpreet 					    DATA_TYPE_UINT8, 0,
174200d0963fSdilpreet 					    PCIX_COMMAND, DATA_TYPE_UINT16,
174300d0963fSdilpreet 					    pcix_regs->pcix_command,
174400d0963fSdilpreet 					    PCIX_STATUS, DATA_TYPE_UINT32,
174500d0963fSdilpreet 					    pcix_regs->pcix_status,
174600d0963fSdilpreet 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
174700d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_ctlstat,
174800d0963fSdilpreet 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
174900d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
175000d0963fSdilpreet 				PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL :
1751ac4d633fSstephh 				    DDI_FM_OK);
175200d0963fSdilpreet 			}
175300d0963fSdilpreet 		}
175400d0963fSdilpreet 	}
175500d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
175600d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
175700d0963fSdilpreet }
175800d0963fSdilpreet 
175900d0963fSdilpreet static int
176000d0963fSdilpreet pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
176100d0963fSdilpreet     void *pe_regs)
176200d0963fSdilpreet {
176300d0963fSdilpreet 	pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
176400d0963fSdilpreet 	int fatal = 0;
176500d0963fSdilpreet 	int nonfatal = 0;
176600d0963fSdilpreet 	int unknown = 0;
176700d0963fSdilpreet 	int ok = 0;
176800d0963fSdilpreet 	char buf[FM_MAX_CLASS];
176900d0963fSdilpreet 	int i;
177000d0963fSdilpreet 
177100d0963fSdilpreet 	if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) {
177200d0963fSdilpreet 		for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
177300d0963fSdilpreet 			if ((pcix_bdg_regs->pcix_bdg_stat &
177400d0963fSdilpreet 			    pcix_err_tbl[i].reg_bit)) {
177500d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
177600d0963fSdilpreet 				    PCIX_ERROR_SUBCLASS,
177700d0963fSdilpreet 				    pcix_err_tbl[i].err_class);
177800d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
177900d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
178000d0963fSdilpreet 				    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
178100d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_sec_stat,
178200d0963fSdilpreet 				    PCIX_BDG_STAT, DATA_TYPE_UINT32,
178300d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_stat, NULL);
178400d0963fSdilpreet 				PCI_FM_SEV_INC(pcix_err_tbl[i].flags);
178500d0963fSdilpreet 			}
178600d0963fSdilpreet 		}
178700d0963fSdilpreet 	}
178800d0963fSdilpreet 
178900d0963fSdilpreet 	if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) {
179000d0963fSdilpreet 		for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) {
179100d0963fSdilpreet 			if ((pcix_bdg_regs->pcix_bdg_sec_stat &
179200d0963fSdilpreet 			    pcix_sec_err_tbl[i].reg_bit)) {
179300d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s",
179400d0963fSdilpreet 				    PCIX_ERROR_SUBCLASS,
179500d0963fSdilpreet 				    PCIX_SEC_ERROR_SUBCLASS,
179600d0963fSdilpreet 				    pcix_sec_err_tbl[i].err_class);
179700d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
179800d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
179900d0963fSdilpreet 				    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
180000d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_sec_stat,
180100d0963fSdilpreet 				    PCIX_BDG_STAT, DATA_TYPE_UINT32,
180200d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_stat, NULL);
180300d0963fSdilpreet 				PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags);
180400d0963fSdilpreet 			}
180500d0963fSdilpreet 		}
180600d0963fSdilpreet 	}
180700d0963fSdilpreet 
180800d0963fSdilpreet 	/* Log/Handle ECC errors */
180900d0963fSdilpreet 	if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
181000d0963fSdilpreet 		int ret;
181100d0963fSdilpreet 
181200d0963fSdilpreet 		ret = pcix_ecc_error_report(dip, derr, erpt_p,
181300d0963fSdilpreet 		    (void *)pcix_bdg_regs);
181400d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
181500d0963fSdilpreet 	}
181600d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
181700d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
181800d0963fSdilpreet }
181900d0963fSdilpreet 
182000d0963fSdilpreet static int
182100d0963fSdilpreet pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
182200d0963fSdilpreet {
182300d0963fSdilpreet 	pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
182400d0963fSdilpreet 	int fatal = 0;
182500d0963fSdilpreet 	int nonfatal = 0;
182600d0963fSdilpreet 	int unknown = 0;
182700d0963fSdilpreet 	int ok = 0;
182800d0963fSdilpreet 	char buf[FM_MAX_CLASS];
182900d0963fSdilpreet 	int i;
183000d0963fSdilpreet 
183100d0963fSdilpreet 	if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) {
183200d0963fSdilpreet 		for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
183300d0963fSdilpreet 			if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit))
183400d0963fSdilpreet 				continue;
183500d0963fSdilpreet 
183600d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
183700d0963fSdilpreet 			    PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class);
183800d0963fSdilpreet 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
183900d0963fSdilpreet 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
184000d0963fSdilpreet 			    PCIX_COMMAND, DATA_TYPE_UINT16,
184100d0963fSdilpreet 			    pcix_regs->pcix_command, PCIX_STATUS,
184200d0963fSdilpreet 			    DATA_TYPE_UINT32, pcix_regs->pcix_status,
184300d0963fSdilpreet 			    NULL);
184400d0963fSdilpreet 			PCI_FM_SEV_INC(pcix_err_tbl[i].flags);
184500d0963fSdilpreet 		}
184600d0963fSdilpreet 	}
184700d0963fSdilpreet 	/* Log/Handle ECC errors */
184800d0963fSdilpreet 	if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
184900d0963fSdilpreet 		int ret = pcix_ecc_error_report(dip, derr, erpt_p,
185000d0963fSdilpreet 		    (void *)pcix_regs);
185100d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
185200d0963fSdilpreet 	}
185300d0963fSdilpreet 
185400d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
185500d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
185600d0963fSdilpreet }
185700d0963fSdilpreet 
185800d0963fSdilpreet static int
185900d0963fSdilpreet pcie_rc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
186000d0963fSdilpreet     void *pe_regs)
186100d0963fSdilpreet {
186200d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs = (pcie_adv_error_regs_t *)pe_regs;
186300d0963fSdilpreet 	int fatal = 0;
186400d0963fSdilpreet 	int nonfatal = 0;
186500d0963fSdilpreet 	int unknown = 0;
186600d0963fSdilpreet 	char buf[FM_MAX_CLASS];
186700d0963fSdilpreet 
186800d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) {
186900d0963fSdilpreet 		pcie_adv_rc_error_regs_t *pcie_rc_regs =
187000d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_rc_regs;
187100d0963fSdilpreet 		int ce, ue, mult_ce, mult_ue, first_ue_fatal, nfe, fe;
187200d0963fSdilpreet 
187300d0963fSdilpreet 		ce = pcie_rc_regs->pcie_rc_err_status &
187400d0963fSdilpreet 		    PCIE_AER_RE_STS_CE_RCVD;
187500d0963fSdilpreet 		ue = pcie_rc_regs->pcie_rc_err_status &
187600d0963fSdilpreet 		    PCIE_AER_RE_STS_FE_NFE_RCVD;
187700d0963fSdilpreet 		mult_ce = pcie_rc_regs->pcie_rc_err_status &
187800d0963fSdilpreet 		    PCIE_AER_RE_STS_MUL_CE_RCVD;
187900d0963fSdilpreet 		mult_ue = pcie_rc_regs->pcie_rc_err_status &
188000d0963fSdilpreet 		    PCIE_AER_RE_STS_MUL_FE_NFE_RCVD;
188100d0963fSdilpreet 		first_ue_fatal = pcie_rc_regs->pcie_rc_err_status &
188200d0963fSdilpreet 		    PCIE_AER_RE_STS_FIRST_UC_FATAL;
188300d0963fSdilpreet 		nfe = pcie_rc_regs->pcie_rc_err_status &
188400d0963fSdilpreet 		    PCIE_AER_RE_STS_NFE_MSGS_RCVD;
188500d0963fSdilpreet 		fe = pcie_rc_regs->pcie_rc_err_status &
188600d0963fSdilpreet 		    PCIE_AER_RE_STS_FE_MSGS_RCVD;
188700d0963fSdilpreet 		/*
188800d0963fSdilpreet 		 * log fatal/nonfatal/corrected messages
188900d0963fSdilpreet 		 * recieved by root complex
189000d0963fSdilpreet 		 */
189100d0963fSdilpreet 		if (ue && fe)
189200d0963fSdilpreet 			fatal++;
189300d0963fSdilpreet 
189400d0963fSdilpreet 		if (fe && first_ue_fatal) {
189500d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
189600d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_FE_MSG);
189700d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
189800d0963fSdilpreet 			    PCIEX_TYPE_RC_UE_MSG);
189900d0963fSdilpreet 		}
190000d0963fSdilpreet 		if (nfe && !first_ue_fatal) {
190100d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
190200d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_NFE_MSG);
190300d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
190400d0963fSdilpreet 			    PCIEX_TYPE_RC_UE_MSG);
190500d0963fSdilpreet 		}
190600d0963fSdilpreet 		if (ce) {
190700d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
190800d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_CE_MSG);
190900d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
191000d0963fSdilpreet 			    PCIEX_TYPE_RC_CE_MSG);
191100d0963fSdilpreet 		}
191200d0963fSdilpreet 		if (mult_ce) {
191300d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
191400d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MCE_MSG);
191500d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
191600d0963fSdilpreet 			    PCIEX_TYPE_RC_MULT_MSG);
191700d0963fSdilpreet 		}
191800d0963fSdilpreet 		if (mult_ue) {
191900d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
192000d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MUE_MSG);
192100d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
192200d0963fSdilpreet 			    PCIEX_TYPE_RC_MULT_MSG);
192300d0963fSdilpreet 		}
192400d0963fSdilpreet 	}
192500d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
192600d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
192700d0963fSdilpreet }
192800d0963fSdilpreet 
192900d0963fSdilpreet static int
193000d0963fSdilpreet pcie_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
193100d0963fSdilpreet {
193200d0963fSdilpreet 	int fatal = 0;
193300d0963fSdilpreet 	int nonfatal = 0;
193400d0963fSdilpreet 	int unknown = 0;
193500d0963fSdilpreet 	int ok = 0;
1936*8aec9182Sstephh 	int type;
193700d0963fSdilpreet 	char buf[FM_MAX_CLASS];
193800d0963fSdilpreet 	int i;
193900d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
194000d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs;
194100d0963fSdilpreet 	pcie_adv_bdg_error_regs_t *pcie_bdg_regs;
194200d0963fSdilpreet 
194300d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) &&
194400d0963fSdilpreet 	    (erpt_p->pe_dflags & PCIX_DEV)) {
194500d0963fSdilpreet 		int ret = pcix_bdg_error_report(dip, derr, erpt_p,
194600d0963fSdilpreet 		    (void *)pcie_regs->pcix_bdg_regs);
194700d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
194800d0963fSdilpreet 	}
194900d0963fSdilpreet 
195000d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) {
195100d0963fSdilpreet 		if (!(pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID))
195200d0963fSdilpreet 			goto done;
1953*8aec9182Sstephh #if !defined(__sparc)
1954*8aec9182Sstephh 		/*
1955*8aec9182Sstephh 		 * On x86 ignore UR on non-RBER leaf devices and pciex-pci
1956*8aec9182Sstephh 		 * bridges.
1957*8aec9182Sstephh 		 */
1958*8aec9182Sstephh 		if ((pcie_regs->pcie_err_status & PCIE_DEVSTS_UR_DETECTED) &&
1959*8aec9182Sstephh 		    !(pcie_regs->pcie_err_status & PCIE_DEVSTS_FE_DETECTED) &&
1960*8aec9182Sstephh 		    ((erpt_p->pe_dflags & PCIEX_2PCI_DEV) ||
1961*8aec9182Sstephh 		    !(erpt_p->pe_dflags & PCI_BRIDGE_DEV)) &&
1962*8aec9182Sstephh 		    !(pcie_regs->pcie_dev_cap & PCIE_DEVCAP_ROLE_BASED_ERR_REP))
1963*8aec9182Sstephh 			goto done;
1964*8aec9182Sstephh #endif
196500d0963fSdilpreet 		for (i = 0; pciex_nadv_err_tbl[i].err_class != NULL; i++) {
196600d0963fSdilpreet 			if (!(pcie_regs->pcie_err_status &
196700d0963fSdilpreet 			    pciex_nadv_err_tbl[i].reg_bit))
196800d0963fSdilpreet 				continue;
196900d0963fSdilpreet 
197000d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
197100d0963fSdilpreet 			    PCIEX_ERROR_SUBCLASS,
197200d0963fSdilpreet 			    pciex_nadv_err_tbl[i].err_class);
197300d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
197400d0963fSdilpreet 			    PCIEX_TYPE_GEN);
197500d0963fSdilpreet 			PCI_FM_SEV_INC(pciex_nadv_err_tbl[i].flags);
197600d0963fSdilpreet 		}
197700d0963fSdilpreet 		goto done;
197800d0963fSdilpreet 	}
197900d0963fSdilpreet 
198000d0963fSdilpreet 	pcie_adv_regs = pcie_regs->pcie_adv_regs;
198100d0963fSdilpreet 
198200d0963fSdilpreet 	/*
198300d0963fSdilpreet 	 * Log PCI Express uncorrectable errors
198400d0963fSdilpreet 	 */
198500d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) {
198600d0963fSdilpreet 		for (i = 0; pciex_ue_err_tbl[i].err_class != NULL; i++) {
198700d0963fSdilpreet 			if (!(pcie_adv_regs->pcie_ue_status &
198800d0963fSdilpreet 			    pciex_ue_err_tbl[i].reg_bit))
198900d0963fSdilpreet 				continue;
199000d0963fSdilpreet 
199100d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
199200d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS,
199300d0963fSdilpreet 			    pciex_ue_err_tbl[i].err_class);
199400d0963fSdilpreet 
1995*8aec9182Sstephh 			/*
1996*8aec9182Sstephh 			 * First check for advisary nonfatal conditions
1997*8aec9182Sstephh 			 * - hardware endpoint successfully retrying a cto
1998*8aec9182Sstephh 			 * - hardware endpoint receiving poisoned tlp and
1999*8aec9182Sstephh 			 *   dealing with it itself (but not if root complex)
2000*8aec9182Sstephh 			 * If the device has declared these as correctable
2001*8aec9182Sstephh 			 * errors then treat them as such.
2002*8aec9182Sstephh 			 */
2003*8aec9182Sstephh 			if ((pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_TO ||
2004*8aec9182Sstephh 			    (pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_PTLP &&
2005*8aec9182Sstephh 			    !(erpt_p->pe_dflags & PCIEX_RC_DEV))) &&
2006*8aec9182Sstephh 			    (pcie_regs->pcie_err_status &
2007*8aec9182Sstephh 			    PCIE_DEVSTS_CE_DETECTED) &&
2008*8aec9182Sstephh 			    !(pcie_regs->pcie_err_status &
2009*8aec9182Sstephh 			    PCIE_DEVSTS_NFE_DETECTED)) {
2010*8aec9182Sstephh 				pcie_ereport_post(dip, derr, erpt_p, buf,
2011*8aec9182Sstephh 				    PCIEX_TYPE_UE);
2012*8aec9182Sstephh 				continue;
2013*8aec9182Sstephh 			}
2014*8aec9182Sstephh 
2015*8aec9182Sstephh #if !defined(__sparc)
2016*8aec9182Sstephh 			/*
2017*8aec9182Sstephh 			 * On x86 for leaf devices and pciex-pci bridges,
2018*8aec9182Sstephh 			 * ignore UR on non-RBER devices or on RBER devices when
2019*8aec9182Sstephh 			 * advisory nonfatal.
2020*8aec9182Sstephh 			 */
2021*8aec9182Sstephh 			if (pciex_ue_err_tbl[i].reg_bit == PCIE_AER_UCE_UR &&
2022*8aec9182Sstephh 			    ((erpt_p->pe_dflags & PCIEX_2PCI_DEV) ||
2023*8aec9182Sstephh 			    !(erpt_p->pe_dflags & PCI_BRIDGE_DEV))) {
2024*8aec9182Sstephh 				if (!(pcie_regs->pcie_dev_cap &
2025*8aec9182Sstephh 				    PCIE_DEVCAP_ROLE_BASED_ERR_REP))
2026*8aec9182Sstephh 					continue;
2027*8aec9182Sstephh 				if ((pcie_regs->pcie_err_status &
2028*8aec9182Sstephh 				    PCIE_DEVSTS_CE_DETECTED) &&
2029*8aec9182Sstephh 				    !(pcie_regs->pcie_err_status &
2030*8aec9182Sstephh 				    PCIE_DEVSTS_NFE_DETECTED))
2031*8aec9182Sstephh 					continue;
2032*8aec9182Sstephh 			}
2033*8aec9182Sstephh #endif
203400d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = 0;
2035*8aec9182Sstephh 			/*
2036*8aec9182Sstephh 			 * Now try and look up handle if
2037*8aec9182Sstephh 			 * - error bit is among PCIE_AER_UCE_LOG_BITS, and
2038*8aec9182Sstephh 			 * - no other PCIE_AER_UCE_LOG_BITS are set, and
2039*8aec9182Sstephh 			 * - error bit is not masked, and
2040*8aec9182Sstephh 			 * - flag is DDI_FM_UNKNOWN
2041*8aec9182Sstephh 			 */
204200d0963fSdilpreet 			if ((pcie_adv_regs->pcie_ue_status &
2043*8aec9182Sstephh 			    pcie_aer_uce_log_bits) ==
2044*8aec9182Sstephh 			    pciex_ue_err_tbl[i].reg_bit &&
2045*8aec9182Sstephh 			    !(pciex_ue_err_tbl[i].reg_bit &
2046*8aec9182Sstephh 			    pcie_adv_regs->pcie_ue_mask) &&
2047*8aec9182Sstephh 			    pciex_ue_err_tbl[i].flags == DDI_FM_UNKNOWN)
2048*8aec9182Sstephh 				pcie_check_addr(dip, derr, erpt_p);
2049*8aec9182Sstephh 
205000d0963fSdilpreet 			PCI_FM_SEV_INC(pciex_ue_err_tbl[i].flags);
205100d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
205200d0963fSdilpreet 			    PCIEX_TYPE_UE);
205300d0963fSdilpreet 		}
205400d0963fSdilpreet 	}
205500d0963fSdilpreet 
205600d0963fSdilpreet 	/*
205700d0963fSdilpreet 	 * Log PCI Express correctable errors
205800d0963fSdilpreet 	 */
205900d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) {
206000d0963fSdilpreet 		for (i = 0; pciex_ce_err_tbl[i].err_class != NULL; i++) {
206100d0963fSdilpreet 			if (!(pcie_adv_regs->pcie_ce_status &
206200d0963fSdilpreet 			    pciex_ce_err_tbl[i].reg_bit))
206300d0963fSdilpreet 				continue;
206400d0963fSdilpreet 
206500d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
206600d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS,
206700d0963fSdilpreet 			    pciex_ce_err_tbl[i].err_class);
206800d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
206900d0963fSdilpreet 			    PCIEX_TYPE_CE);
207000d0963fSdilpreet 		}
207100d0963fSdilpreet 	}
207200d0963fSdilpreet 
207300d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCI_BRIDGE_DEV))
207400d0963fSdilpreet 		goto done;
207500d0963fSdilpreet 
207600d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV) {
207700d0963fSdilpreet 		int ret = pcie_rc_error_report(dip, derr, erpt_p,
207800d0963fSdilpreet 		    (void *)pcie_adv_regs);
207900d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
208000d0963fSdilpreet 	}
208100d0963fSdilpreet 
208200d0963fSdilpreet 	if (!((erpt_p->pe_dflags & PCIEX_2PCI_DEV) &&
208300d0963fSdilpreet 	    (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID)))
208400d0963fSdilpreet 		goto done;
208500d0963fSdilpreet 
208600d0963fSdilpreet 	pcie_bdg_regs = pcie_adv_regs->pcie_adv_bdg_regs;
208700d0963fSdilpreet 
208800d0963fSdilpreet 	for (i = 0; pcie_sue_err_tbl[i].err_class != NULL; i++) {
208900d0963fSdilpreet 		if ((pcie_bdg_regs->pcie_sue_status &
209000d0963fSdilpreet 		    pcie_sue_err_tbl[i].reg_bit)) {
209100d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
209200d0963fSdilpreet 			    PCIEX_ERROR_SUBCLASS,
209300d0963fSdilpreet 			    pcie_sue_err_tbl[i].err_class);
209400d0963fSdilpreet 
209500d0963fSdilpreet 			if ((pcie_bdg_regs->pcie_sue_status &
20960c64a9b4Sanish 			    pcie_aer_suce_log_bits) !=
2097*8aec9182Sstephh 			    pcie_sue_err_tbl[i].reg_bit ||
2098*8aec9182Sstephh 			    pcie_sue_err_tbl[i].flags != DDI_FM_UNKNOWN) {
209900d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
210000d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
210100d0963fSdilpreet 				    PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32,
210200d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_status,
210300d0963fSdilpreet #ifdef DEBUG
210400d0963fSdilpreet 				    PCIEX_SUE_HDR0, DATA_TYPE_UINT32,
210500d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr0,
210600d0963fSdilpreet 				    PCIEX_SUE_HDR1, DATA_TYPE_UINT32,
210700d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[0],
210800d0963fSdilpreet 				    PCIEX_SUE_HDR2, DATA_TYPE_UINT32,
210900d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[1],
211000d0963fSdilpreet 				    PCIEX_SUE_HDR3, DATA_TYPE_UINT32,
211100d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[2],
211200d0963fSdilpreet #endif
211300d0963fSdilpreet 				    NULL);
211400d0963fSdilpreet 			} else {
211500d0963fSdilpreet 				pcie_adv_regs->pcie_adv_bdf = 0;
2116*8aec9182Sstephh 				switch (pcie_sue_err_tbl[i].reg_bit) {
2117*8aec9182Sstephh 				case PCIE_AER_SUCE_RCVD_TA:
2118*8aec9182Sstephh 				case PCIE_AER_SUCE_RCVD_MA:
2119*8aec9182Sstephh 				case PCIE_AER_SUCE_USC_ERR:
2120*8aec9182Sstephh 					type = ACC_HANDLE;
2121*8aec9182Sstephh 					break;
2122*8aec9182Sstephh 				case PCIE_AER_SUCE_TA_ON_SC:
2123*8aec9182Sstephh 				case PCIE_AER_SUCE_MA_ON_SC:
2124*8aec9182Sstephh 					type = DMA_HANDLE;
2125*8aec9182Sstephh 					break;
2126*8aec9182Sstephh 				case PCIE_AER_SUCE_UC_DATA_ERR:
2127*8aec9182Sstephh 				case PCIE_AER_SUCE_PERR_ASSERT:
2128*8aec9182Sstephh 					if (erpt_p->pe_pci_regs->pci_bdg_regs->
2129*8aec9182Sstephh 					    pci_bdg_sec_stat &
2130*8aec9182Sstephh 					    PCI_STAT_S_PERROR)
2131*8aec9182Sstephh 						type = ACC_HANDLE;
2132*8aec9182Sstephh 					else
2133*8aec9182Sstephh 						type = DMA_HANDLE;
2134*8aec9182Sstephh 					break;
2135*8aec9182Sstephh 				}
2136*8aec9182Sstephh 				pcie_pci_check_addr(dip, derr, erpt_p, type);
213700d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
213800d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
213900d0963fSdilpreet 				    PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32,
214000d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_status,
214100d0963fSdilpreet 				    PCIEX_SRC_ID, DATA_TYPE_UINT16,
214200d0963fSdilpreet 				    pcie_adv_regs->pcie_adv_bdf,
214300d0963fSdilpreet 				    PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE,
214400d0963fSdilpreet 				    (pcie_adv_regs->pcie_adv_bdf != NULL) ?
214500d0963fSdilpreet 				    1 : NULL,
214600d0963fSdilpreet #ifdef DEBUG
214700d0963fSdilpreet 				    PCIEX_SUE_HDR0, DATA_TYPE_UINT32,
214800d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr0,
214900d0963fSdilpreet 				    PCIEX_SUE_HDR1, DATA_TYPE_UINT32,
215000d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[0],
215100d0963fSdilpreet 				    PCIEX_SUE_HDR2, DATA_TYPE_UINT32,
215200d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[1],
215300d0963fSdilpreet 				    PCIEX_SUE_HDR3, DATA_TYPE_UINT32,
215400d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[2],
215500d0963fSdilpreet #endif
215600d0963fSdilpreet 				    NULL);
215700d0963fSdilpreet 			}
2158*8aec9182Sstephh 			PCI_FM_SEV_INC(pcie_sue_err_tbl[i].flags);
215900d0963fSdilpreet 		}
216000d0963fSdilpreet 	}
216100d0963fSdilpreet done:
216200d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
216300d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
216400d0963fSdilpreet }
216500d0963fSdilpreet 
216600d0963fSdilpreet static void
216700d0963fSdilpreet pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
216800d0963fSdilpreet {
216900d0963fSdilpreet 	int fatal = 0;
217000d0963fSdilpreet 	int nonfatal = 0;
217100d0963fSdilpreet 	int unknown = 0;
217200d0963fSdilpreet 	int ok = 0;
217300d0963fSdilpreet 	char buf[FM_MAX_CLASS];
217400d0963fSdilpreet 	int i;
217500d0963fSdilpreet 
217600d0963fSdilpreet 	if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) {
217700d0963fSdilpreet 		/*
217800d0963fSdilpreet 		 * Log generic PCI errors.
217900d0963fSdilpreet 		 */
218000d0963fSdilpreet 		for (i = 0; pci_err_tbl[i].err_class != NULL; i++) {
218100d0963fSdilpreet 			if (!(erpt_p->pe_pci_regs->pci_err_status &
218200d0963fSdilpreet 			    pci_err_tbl[i].reg_bit) ||
218300d0963fSdilpreet 			    !(erpt_p->pe_pci_regs->pci_vflags &
218400d0963fSdilpreet 			    PCI_ERR_STATUS_VALID))
218500d0963fSdilpreet 				continue;
218600d0963fSdilpreet 			/*
218700d0963fSdilpreet 			 * Generate an ereport for this error bit.
218800d0963fSdilpreet 			 */
218900d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
219000d0963fSdilpreet 			    PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class);
219100d0963fSdilpreet 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
219200d0963fSdilpreet 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
219300d0963fSdilpreet 			    PCI_CONFIG_STATUS, DATA_TYPE_UINT16,
219400d0963fSdilpreet 			    erpt_p->pe_pci_regs->pci_err_status,
219500d0963fSdilpreet 			    PCI_CONFIG_COMMAND, DATA_TYPE_UINT16,
219600d0963fSdilpreet 			    erpt_p->pe_pci_regs->pci_cfg_comm, NULL);
219700d0963fSdilpreet 
2198ac4d633fSstephh 			/*
2199ac4d633fSstephh 			 * The meaning of SERR is different for PCIEX (just
2200ac4d633fSstephh 			 * implies a message has been sent) so we don't want to
2201ac4d633fSstephh 			 * treat that one as fatal.
2202ac4d633fSstephh 			 */
2203ac4d633fSstephh 			if ((erpt_p->pe_dflags & PCIEX_DEV) &&
2204ac4d633fSstephh 			    pci_err_tbl[i].reg_bit == PCI_STAT_S_SYSERR) {
2205ac4d633fSstephh 				unknown++;
2206ac4d633fSstephh 			} else {
220700d0963fSdilpreet 				PCI_FM_SEV_INC(pci_err_tbl[i].flags);
220800d0963fSdilpreet 			}
2209ac4d633fSstephh 		}
221000d0963fSdilpreet 		if (erpt_p->pe_dflags & PCIEX_DEV) {
221100d0963fSdilpreet 			int ret = pcie_error_report(dip, derr, erpt_p);
221200d0963fSdilpreet 			PCI_FM_SEV_INC(ret);
221300d0963fSdilpreet 		} else if (erpt_p->pe_dflags & PCIX_DEV) {
221400d0963fSdilpreet 			if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
221500d0963fSdilpreet 				int ret = pcix_bdg_error_report(dip, derr,
221600d0963fSdilpreet 				    erpt_p, erpt_p->pe_regs);
221700d0963fSdilpreet 				PCI_FM_SEV_INC(ret);
221800d0963fSdilpreet 			} else {
221900d0963fSdilpreet 				int ret = pcix_error_report(dip, derr, erpt_p);
222000d0963fSdilpreet 				PCI_FM_SEV_INC(ret);
222100d0963fSdilpreet 			}
222200d0963fSdilpreet 		}
222300d0963fSdilpreet 	}
222400d0963fSdilpreet 
222500d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) {
222600d0963fSdilpreet 		int ret = pci_bdg_error_report(dip, derr, erpt_p);
222700d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
222800d0963fSdilpreet 	}
222900d0963fSdilpreet 
2230*8aec9182Sstephh 	if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) {
2231*8aec9182Sstephh 		pci_fme_bus_specific_t *pci_fme_bsp;
2232*8aec9182Sstephh 		int ret = DDI_FM_UNKNOWN;
2233*8aec9182Sstephh 
2234*8aec9182Sstephh 		pci_fme_bsp = (pci_fme_bus_specific_t *)derr->fme_bus_specific;
2235*8aec9182Sstephh 		if (pci_fme_bsp->pci_bs_flags & PCI_BS_ADDR_VALID) {
2236*8aec9182Sstephh 			ret = ndi_fmc_entry_error(dip,
2237*8aec9182Sstephh 			    pci_fme_bsp->pci_bs_type, derr,
2238*8aec9182Sstephh 			    (void *)&pci_fme_bsp->pci_bs_addr);
2239*8aec9182Sstephh 			PCI_FM_SEV_INC(ret);
2240*8aec9182Sstephh 		}
2241*8aec9182Sstephh 		/*
2242*8aec9182Sstephh 		 * If we didn't find the handle using an addr, try using bdf.
2243*8aec9182Sstephh 		 * Note we don't do this where the bdf is for a
2244*8aec9182Sstephh 		 * device behind a pciex/pci bridge as the bridge may have
2245*8aec9182Sstephh 		 * fabricated the bdf.
2246*8aec9182Sstephh 		 */
2247*8aec9182Sstephh 		if (ret == DDI_FM_UNKNOWN &&
2248*8aec9182Sstephh 		    (pci_fme_bsp->pci_bs_flags & PCI_BS_BDF_VALID) &&
2249*8aec9182Sstephh 		    pci_fme_bsp->pci_bs_bdf == erpt_p->pe_bdf &&
2250*8aec9182Sstephh 		    (erpt_p->pe_dflags & PCIEX_DEV) &&
2251*8aec9182Sstephh 		    !(erpt_p->pe_dflags & PCIEX_2PCI_DEV)) {
2252*8aec9182Sstephh 			ret = ndi_fmc_entry_error_all(dip,
2253*8aec9182Sstephh 			    pci_fme_bsp->pci_bs_type, derr);
2254*8aec9182Sstephh 			PCI_FM_SEV_INC(ret);
2255*8aec9182Sstephh 		}
2256*8aec9182Sstephh 	}
2257*8aec9182Sstephh 
225800d0963fSdilpreet 	derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
225900d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
226000d0963fSdilpreet }
226100d0963fSdilpreet 
226200d0963fSdilpreet void
226300d0963fSdilpreet pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status)
226400d0963fSdilpreet {
226500d0963fSdilpreet 	struct i_ddi_fmhdl *fmhdl;
226600d0963fSdilpreet 	pci_erpt_t *erpt_p;
2267*8aec9182Sstephh 	ddi_fm_error_t de;
2268*8aec9182Sstephh 	pci_fme_bus_specific_t pci_fme_bs;
226900d0963fSdilpreet 
227000d0963fSdilpreet 	fmhdl = DEVI(dip)->devi_fmhdl;
227100d0963fSdilpreet 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
227200d0963fSdilpreet 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
227300d0963fSdilpreet 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP);
227400d0963fSdilpreet 		return;
227500d0963fSdilpreet 	}
227600d0963fSdilpreet 
2277*8aec9182Sstephh 	/*
2278*8aec9182Sstephh 	 * copy in the ddi_fm_error_t structure in case it's VER0
2279*8aec9182Sstephh 	 */
2280*8aec9182Sstephh 	de.fme_version = derr->fme_version;
2281*8aec9182Sstephh 	de.fme_status = derr->fme_status;
2282*8aec9182Sstephh 	de.fme_flag = derr->fme_flag;
2283*8aec9182Sstephh 	de.fme_ena = derr->fme_ena;
2284*8aec9182Sstephh 	de.fme_acc_handle = derr->fme_acc_handle;
2285*8aec9182Sstephh 	de.fme_dma_handle = derr->fme_dma_handle;
2286*8aec9182Sstephh 	de.fme_bus_specific = derr->fme_bus_specific;
2287*8aec9182Sstephh 	if (derr->fme_version >= DDI_FME_VER1)
2288*8aec9182Sstephh 		de.fme_bus_type = derr->fme_bus_type;
2289*8aec9182Sstephh 	else
2290*8aec9182Sstephh 		de.fme_bus_type = DDI_FME_BUS_TYPE_DFLT;
2291*8aec9182Sstephh 	if (de.fme_bus_type == DDI_FME_BUS_TYPE_DFLT) {
2292*8aec9182Sstephh 		/*
2293*8aec9182Sstephh 		 * if this is the first pci device we've found convert
2294*8aec9182Sstephh 		 * fme_bus_specific to DDI_FME_BUS_TYPE_PCI
2295*8aec9182Sstephh 		 */
2296*8aec9182Sstephh 		bzero(&pci_fme_bs, sizeof (pci_fme_bs));
2297*8aec9182Sstephh 		if (de.fme_bus_specific) {
2298*8aec9182Sstephh 			/*
2299*8aec9182Sstephh 			 * the cpu passed us an addr - this can be used to look
2300*8aec9182Sstephh 			 * up an access handle
2301*8aec9182Sstephh 			 */
2302*8aec9182Sstephh 			pci_fme_bs.pci_bs_addr = (uintptr_t)de.fme_bus_specific;
2303*8aec9182Sstephh 			pci_fme_bs.pci_bs_type = ACC_HANDLE;
2304*8aec9182Sstephh 			pci_fme_bs.pci_bs_flags |= PCI_BS_ADDR_VALID;
2305*8aec9182Sstephh 		}
2306*8aec9182Sstephh 		de.fme_bus_specific = (void *)&pci_fme_bs;
2307*8aec9182Sstephh 		de.fme_bus_type = DDI_FME_BUS_TYPE_PCI;
2308*8aec9182Sstephh 	}
2309*8aec9182Sstephh 
231000d0963fSdilpreet 	ASSERT(fmhdl);
231100d0963fSdilpreet 
2312*8aec9182Sstephh 	if (de.fme_ena == NULL)
2313*8aec9182Sstephh 		de.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
231400d0963fSdilpreet 
231500d0963fSdilpreet 	erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
2316ac4d633fSstephh 	if (erpt_p == NULL)
231700d0963fSdilpreet 		return;
231800d0963fSdilpreet 
2319*8aec9182Sstephh 	pci_regs_gather(dip, erpt_p, de.fme_flag);
2320*8aec9182Sstephh 	pci_error_report(dip, &de, erpt_p);
232100d0963fSdilpreet 	pci_regs_clear(erpt_p);
232200d0963fSdilpreet 
2323*8aec9182Sstephh 	derr->fme_status = de.fme_status;
2324*8aec9182Sstephh 	derr->fme_ena = de.fme_ena;
2325*8aec9182Sstephh 	derr->fme_acc_handle = de.fme_acc_handle;
2326*8aec9182Sstephh 	derr->fme_dma_handle = de.fme_dma_handle;
232700d0963fSdilpreet 	if (xx_status != NULL)
232800d0963fSdilpreet 		*xx_status = erpt_p->pe_pci_regs->pci_err_status;
232900d0963fSdilpreet }
233000d0963fSdilpreet 
233100d0963fSdilpreet /*
233200d0963fSdilpreet  * private version of walk_devs() that can be used during panic. No
233300d0963fSdilpreet  * sleeping or locking required.
233400d0963fSdilpreet  */
233500d0963fSdilpreet static int
233600d0963fSdilpreet pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg)
233700d0963fSdilpreet {
233800d0963fSdilpreet 	while (dip) {
233900d0963fSdilpreet 		switch ((*f)(dip, arg)) {
234000d0963fSdilpreet 		case DDI_WALK_TERMINATE:
234100d0963fSdilpreet 			return (DDI_WALK_TERMINATE);
234200d0963fSdilpreet 		case DDI_WALK_CONTINUE:
234300d0963fSdilpreet 			if (pci_fm_walk_devs(ddi_get_child(dip), f,
234400d0963fSdilpreet 			    arg) == DDI_WALK_TERMINATE)
234500d0963fSdilpreet 				return (DDI_WALK_TERMINATE);
234600d0963fSdilpreet 			break;
234700d0963fSdilpreet 		case DDI_WALK_PRUNECHILD:
234800d0963fSdilpreet 			break;
234900d0963fSdilpreet 		}
235000d0963fSdilpreet 		dip = ddi_get_next_sibling(dip);
235100d0963fSdilpreet 	}
235200d0963fSdilpreet 	return (DDI_WALK_CONTINUE);
235300d0963fSdilpreet }
235400d0963fSdilpreet 
235500d0963fSdilpreet /*
235600d0963fSdilpreet  * need special version of ddi_fm_ereport_post() as the leaf driver may
235700d0963fSdilpreet  * not be hardened.
235800d0963fSdilpreet  */
235900d0963fSdilpreet static void
236000d0963fSdilpreet pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena,
236100d0963fSdilpreet     uint8_t version, ...)
236200d0963fSdilpreet {
236300d0963fSdilpreet 	char *name;
236400d0963fSdilpreet 	char device_path[MAXPATHLEN];
236500d0963fSdilpreet 	char ddi_error_class[FM_MAX_CLASS];
236600d0963fSdilpreet 	nvlist_t *ereport, *detector;
236700d0963fSdilpreet 	nv_alloc_t *nva;
236800d0963fSdilpreet 	errorq_elem_t *eqep;
236900d0963fSdilpreet 	va_list ap;
237000d0963fSdilpreet 
237100d0963fSdilpreet 	if (panicstr) {
237200d0963fSdilpreet 		eqep = errorq_reserve(ereport_errorq);
237300d0963fSdilpreet 		if (eqep == NULL)
237400d0963fSdilpreet 			return;
237500d0963fSdilpreet 		ereport = errorq_elem_nvl(ereport_errorq, eqep);
237600d0963fSdilpreet 		nva = errorq_elem_nva(ereport_errorq, eqep);
237700d0963fSdilpreet 		detector = fm_nvlist_create(nva);
237800d0963fSdilpreet 	} else {
237900d0963fSdilpreet 		ereport = fm_nvlist_create(NULL);
238000d0963fSdilpreet 		detector = fm_nvlist_create(NULL);
238100d0963fSdilpreet 	}
238200d0963fSdilpreet 
238300d0963fSdilpreet 	(void) ddi_pathname(dip, device_path);
238400d0963fSdilpreet 	fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
238500d0963fSdilpreet 	    device_path, NULL);
238600d0963fSdilpreet 	(void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s",
238700d0963fSdilpreet 	    DDI_IO_CLASS, error_class);
238800d0963fSdilpreet 	fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL);
238900d0963fSdilpreet 
239000d0963fSdilpreet 	va_start(ap, version);
239100d0963fSdilpreet 	name = va_arg(ap, char *);
239200d0963fSdilpreet 	(void) i_fm_payload_set(ereport, name, ap);
239300d0963fSdilpreet 	va_end(ap);
239400d0963fSdilpreet 
239500d0963fSdilpreet 	if (panicstr) {
239600d0963fSdilpreet 		errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
239700d0963fSdilpreet 	} else {
239800d0963fSdilpreet 		(void) fm_ereport_post(ereport, EVCH_TRYHARD);
239900d0963fSdilpreet 		fm_nvlist_destroy(ereport, FM_NVA_FREE);
240000d0963fSdilpreet 		fm_nvlist_destroy(detector, FM_NVA_FREE);
240100d0963fSdilpreet 	}
240200d0963fSdilpreet }
240300d0963fSdilpreet 
240400d0963fSdilpreet static int
240500d0963fSdilpreet pci_check_regs(dev_info_t *dip, void *arg)
240600d0963fSdilpreet {
240700d0963fSdilpreet 	int reglen;
240800d0963fSdilpreet 	int rn;
240900d0963fSdilpreet 	int totreg;
241000d0963fSdilpreet 	pci_regspec_t *drv_regp;
241100d0963fSdilpreet 	pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
241200d0963fSdilpreet 
241300d0963fSdilpreet 	if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
241400d0963fSdilpreet 		/*
241500d0963fSdilpreet 		 * for config space, we need to check if the given address
241600d0963fSdilpreet 		 * is a valid config space address for this device - based
241700d0963fSdilpreet 		 * on pci_phys_hi of the config space entry in reg property.
241800d0963fSdilpreet 		 */
241900d0963fSdilpreet 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
242000d0963fSdilpreet 		    "reg", (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
242100d0963fSdilpreet 			return (DDI_WALK_CONTINUE);
242200d0963fSdilpreet 
242300d0963fSdilpreet 		totreg = reglen / sizeof (pci_regspec_t);
242400d0963fSdilpreet 		for (rn = 0; rn < totreg; rn++) {
242500d0963fSdilpreet 			if (tgt_err->tgt_pci_space ==
242600d0963fSdilpreet 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) &&
242700d0963fSdilpreet 			    (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M |
242800d0963fSdilpreet 			    PCI_REG_DEV_M | PCI_REG_FUNC_M)) ==
242900d0963fSdilpreet 			    (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M |
243000d0963fSdilpreet 			    PCI_REG_DEV_M | PCI_REG_FUNC_M))) {
243100d0963fSdilpreet 				tgt_err->tgt_dip = dip;
243200d0963fSdilpreet 				kmem_free(drv_regp, reglen);
243300d0963fSdilpreet 				return (DDI_WALK_TERMINATE);
243400d0963fSdilpreet 			}
243500d0963fSdilpreet 		}
243600d0963fSdilpreet 		kmem_free(drv_regp, reglen);
243700d0963fSdilpreet 	} else {
243800d0963fSdilpreet 		/*
243900d0963fSdilpreet 		 * for non config space, need to check reg to look
244000d0963fSdilpreet 		 * for any non-relocable mapping, otherwise check
244100d0963fSdilpreet 		 * assigned-addresses.
244200d0963fSdilpreet 		 */
244300d0963fSdilpreet 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
244400d0963fSdilpreet 		    "reg", (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
244500d0963fSdilpreet 			return (DDI_WALK_CONTINUE);
244600d0963fSdilpreet 
244700d0963fSdilpreet 		totreg = reglen / sizeof (pci_regspec_t);
244800d0963fSdilpreet 		for (rn = 0; rn < totreg; rn++) {
244900d0963fSdilpreet 			if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) &&
245000d0963fSdilpreet 			    (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
245100d0963fSdilpreet 			    tgt_err->tgt_pci_space ==
245200d0963fSdilpreet 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) &&
245300d0963fSdilpreet 			    (tgt_err->tgt_pci_addr >=
245400d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_phys_low +
245500d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) &&
245600d0963fSdilpreet 			    (tgt_err->tgt_pci_addr <
245700d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_phys_low +
245800d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32) +
245900d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_size_low +
246000d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_size_hi << 32))) {
246100d0963fSdilpreet 				tgt_err->tgt_dip = dip;
246200d0963fSdilpreet 				kmem_free(drv_regp, reglen);
246300d0963fSdilpreet 				return (DDI_WALK_TERMINATE);
246400d0963fSdilpreet 			}
246500d0963fSdilpreet 		}
246600d0963fSdilpreet 		kmem_free(drv_regp, reglen);
246700d0963fSdilpreet 
246800d0963fSdilpreet 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
246900d0963fSdilpreet 		    "assigned-addresses", (caddr_t)&drv_regp, &reglen) !=
247000d0963fSdilpreet 		    DDI_SUCCESS)
247100d0963fSdilpreet 			return (DDI_WALK_CONTINUE);
247200d0963fSdilpreet 
247300d0963fSdilpreet 		totreg = reglen / sizeof (pci_regspec_t);
247400d0963fSdilpreet 		for (rn = 0; rn < totreg; rn++) {
247500d0963fSdilpreet 			if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
247600d0963fSdilpreet 			    tgt_err->tgt_pci_space ==
247700d0963fSdilpreet 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) &&
247800d0963fSdilpreet 			    (tgt_err->tgt_pci_addr >=
247900d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_phys_low +
248000d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) &&
248100d0963fSdilpreet 			    (tgt_err->tgt_pci_addr <
248200d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_phys_low +
248300d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32) +
248400d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_size_low +
248500d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_size_hi << 32))) {
248600d0963fSdilpreet 				tgt_err->tgt_dip = dip;
248700d0963fSdilpreet 				kmem_free(drv_regp, reglen);
248800d0963fSdilpreet 				return (DDI_WALK_TERMINATE);
248900d0963fSdilpreet 			}
249000d0963fSdilpreet 		}
249100d0963fSdilpreet 		kmem_free(drv_regp, reglen);
249200d0963fSdilpreet 	}
249300d0963fSdilpreet 	return (DDI_WALK_CONTINUE);
249400d0963fSdilpreet }
249500d0963fSdilpreet 
249600d0963fSdilpreet /*
249700d0963fSdilpreet  * impl_fix_ranges - fixes the config space entry of the "ranges"
249800d0963fSdilpreet  * property on psycho+ platforms.  (if changing this function please make sure
249900d0963fSdilpreet  * to change the pci_fix_ranges function in pcipsy.c)
250000d0963fSdilpreet  */
250100d0963fSdilpreet /*ARGSUSED*/
250200d0963fSdilpreet static void
250300d0963fSdilpreet pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange)
250400d0963fSdilpreet {
250500d0963fSdilpreet #if defined(__sparc)
250600d0963fSdilpreet 	char *name = ddi_binding_name(dip);
250700d0963fSdilpreet 
250800d0963fSdilpreet 	if ((strcmp(name, "pci108e,8000") == 0) ||
250900d0963fSdilpreet 	    (strcmp(name, "pci108e,a000") == 0) ||
251000d0963fSdilpreet 	    (strcmp(name, "pci108e,a001") == 0)) {
251100d0963fSdilpreet 		int i;
251200d0963fSdilpreet 		for (i = 0; i < nrange; i++, pci_ranges++)
251300d0963fSdilpreet 			if ((pci_ranges->child_high & PCI_REG_ADDR_M) ==
251400d0963fSdilpreet 			    PCI_ADDR_CONFIG)
251500d0963fSdilpreet 				pci_ranges->parent_low |=
251600d0963fSdilpreet 				    pci_ranges->child_high;
251700d0963fSdilpreet 	}
251800d0963fSdilpreet #endif
251900d0963fSdilpreet }
252000d0963fSdilpreet 
252100d0963fSdilpreet static int
252200d0963fSdilpreet pci_check_ranges(dev_info_t *dip, void *arg)
252300d0963fSdilpreet {
252400d0963fSdilpreet 	uint64_t range_parent_begin;
252500d0963fSdilpreet 	uint64_t range_parent_size;
252600d0963fSdilpreet 	uint64_t range_parent_end;
252700d0963fSdilpreet 	uint32_t space_type;
252800d0963fSdilpreet 	uint32_t bus_num;
252900d0963fSdilpreet 	uint32_t range_offset;
253000d0963fSdilpreet 	pci_ranges_t *pci_ranges, *rangep;
253100d0963fSdilpreet 	pci_bus_range_t *pci_bus_rangep;
253200d0963fSdilpreet 	int pci_ranges_length;
253300d0963fSdilpreet 	int nrange;
253400d0963fSdilpreet 	pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
253500d0963fSdilpreet 	int i, size;
253600d0963fSdilpreet 	if (strcmp(ddi_node_name(dip), "pci") != 0 &&
253700d0963fSdilpreet 	    strcmp(ddi_node_name(dip), "pciex") != 0)
253800d0963fSdilpreet 		return (DDI_WALK_CONTINUE);
253900d0963fSdilpreet 
254000d0963fSdilpreet 	/*
254100d0963fSdilpreet 	 * Get the ranges property. Note we only look at the top level pci
254200d0963fSdilpreet 	 * node (hostbridge) which has a ranges property of type pci_ranges_t
254300d0963fSdilpreet 	 * not at pci-pci bridges.
254400d0963fSdilpreet 	 */
254500d0963fSdilpreet 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
254600d0963fSdilpreet 	    (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) {
254700d0963fSdilpreet 		/*
254800d0963fSdilpreet 		 * no ranges property - no translation needed
254900d0963fSdilpreet 		 */
255000d0963fSdilpreet 		tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr;
255100d0963fSdilpreet 		tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN;
255200d0963fSdilpreet 		if (panicstr)
255300d0963fSdilpreet 			(void) pci_fm_walk_devs(ddi_get_child(dip),
255400d0963fSdilpreet 			    pci_check_regs, (void *)tgt_err);
255500d0963fSdilpreet 		else {
255600d0963fSdilpreet 			int circ = 0;
255700d0963fSdilpreet 			ndi_devi_enter(dip, &circ);
255800d0963fSdilpreet 			ddi_walk_devs(ddi_get_child(dip), pci_check_regs,
255900d0963fSdilpreet 			    (void *)tgt_err);
256000d0963fSdilpreet 			ndi_devi_exit(dip, circ);
256100d0963fSdilpreet 		}
256200d0963fSdilpreet 		if (tgt_err->tgt_dip != NULL)
256300d0963fSdilpreet 			return (DDI_WALK_TERMINATE);
256400d0963fSdilpreet 		return (DDI_WALK_PRUNECHILD);
256500d0963fSdilpreet 	}
256600d0963fSdilpreet 	nrange = pci_ranges_length / sizeof (pci_ranges_t);
256700d0963fSdilpreet 	rangep = pci_ranges;
256800d0963fSdilpreet 
256900d0963fSdilpreet 	/* Need to fix the pci ranges property for psycho based systems */
257000d0963fSdilpreet 	pci_fix_ranges(dip, pci_ranges, nrange);
257100d0963fSdilpreet 
257200d0963fSdilpreet 	for (i = 0; i < nrange; i++, rangep++) {
257300d0963fSdilpreet 		range_parent_begin = ((uint64_t)rangep->parent_high << 32) +
257400d0963fSdilpreet 		    rangep->parent_low;
257500d0963fSdilpreet 		range_parent_size = ((uint64_t)rangep->size_high << 32) +
257600d0963fSdilpreet 		    rangep->size_low;
257700d0963fSdilpreet 		range_parent_end = range_parent_begin + range_parent_size - 1;
257800d0963fSdilpreet 
257900d0963fSdilpreet 		if ((tgt_err->tgt_err_addr < range_parent_begin) ||
258000d0963fSdilpreet 		    (tgt_err->tgt_err_addr > range_parent_end)) {
258100d0963fSdilpreet 			/* Not in range */
258200d0963fSdilpreet 			continue;
258300d0963fSdilpreet 		}
258400d0963fSdilpreet 		space_type = PCI_REG_ADDR_G(rangep->child_high);
258500d0963fSdilpreet 		if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
258600d0963fSdilpreet 			/* Config space address - check bus range */
258700d0963fSdilpreet 			range_offset = tgt_err->tgt_err_addr -
258800d0963fSdilpreet 			    range_parent_begin;
258900d0963fSdilpreet 			bus_num = PCI_REG_BUS_G(range_offset);
259000d0963fSdilpreet 			if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
259100d0963fSdilpreet 			    DDI_PROP_DONTPASS, "bus-range",
259200d0963fSdilpreet 			    (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) {
259300d0963fSdilpreet 				continue;
259400d0963fSdilpreet 			}
259500d0963fSdilpreet 			if ((bus_num < pci_bus_rangep->lo) ||
259600d0963fSdilpreet 			    (bus_num > pci_bus_rangep->hi)) {
259700d0963fSdilpreet 				/*
259800d0963fSdilpreet 				 * Bus number not appropriate for this
259900d0963fSdilpreet 				 * pci nexus.
260000d0963fSdilpreet 				 */
260100d0963fSdilpreet 				kmem_free(pci_bus_rangep, size);
260200d0963fSdilpreet 				continue;
260300d0963fSdilpreet 			}
260400d0963fSdilpreet 			kmem_free(pci_bus_rangep, size);
260500d0963fSdilpreet 		}
260600d0963fSdilpreet 
260700d0963fSdilpreet 		/* We have a match if we get here - compute pci address */
260800d0963fSdilpreet 		tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr -
260900d0963fSdilpreet 		    range_parent_begin;
261000d0963fSdilpreet 		tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) +
261100d0963fSdilpreet 		    rangep->child_low);
261200d0963fSdilpreet 		tgt_err->tgt_pci_space = space_type;
261300d0963fSdilpreet 		if (panicstr)
261400d0963fSdilpreet 			(void) pci_fm_walk_devs(ddi_get_child(dip),
261500d0963fSdilpreet 			    pci_check_regs, (void *)tgt_err);
261600d0963fSdilpreet 		else {
261700d0963fSdilpreet 			int circ = 0;
261800d0963fSdilpreet 			ndi_devi_enter(dip, &circ);
261900d0963fSdilpreet 			ddi_walk_devs(ddi_get_child(dip), pci_check_regs,
262000d0963fSdilpreet 			    (void *)tgt_err);
262100d0963fSdilpreet 			ndi_devi_exit(dip, circ);
262200d0963fSdilpreet 		}
262300d0963fSdilpreet 		if (tgt_err->tgt_dip != NULL) {
262400d0963fSdilpreet 			kmem_free(pci_ranges, pci_ranges_length);
262500d0963fSdilpreet 			return (DDI_WALK_TERMINATE);
262600d0963fSdilpreet 		}
262700d0963fSdilpreet 	}
262800d0963fSdilpreet 	kmem_free(pci_ranges, pci_ranges_length);
262900d0963fSdilpreet 	return (DDI_WALK_PRUNECHILD);
263000d0963fSdilpreet }
263100d0963fSdilpreet 
263200d0963fSdilpreet /*
263300d0963fSdilpreet  * Function used to drain pci_target_queue, either during panic or after softint
263400d0963fSdilpreet  * is generated, to generate target device ereports based on captured physical
263500d0963fSdilpreet  * addresses
263600d0963fSdilpreet  */
263700d0963fSdilpreet /*ARGSUSED*/
263800d0963fSdilpreet static void
263900d0963fSdilpreet pci_target_drain(void *private_p, pci_target_err_t *tgt_err)
264000d0963fSdilpreet {
264100d0963fSdilpreet 	char buf[FM_MAX_CLASS];
264200d0963fSdilpreet 
264300d0963fSdilpreet 	/*
264400d0963fSdilpreet 	 * The following assumes that all pci_pci bridge devices
264500d0963fSdilpreet 	 * are configured as transparant. Find the top-level pci
264600d0963fSdilpreet 	 * nexus which has tgt_err_addr in one of its ranges, converting this
264700d0963fSdilpreet 	 * to a pci address in the process. Then starting at this node do
264800d0963fSdilpreet 	 * another tree walk to find a device with the pci address we've
264900d0963fSdilpreet 	 * found within range of one of it's assigned-addresses properties.
265000d0963fSdilpreet 	 */
265100d0963fSdilpreet 	tgt_err->tgt_dip = NULL;
265200d0963fSdilpreet 	if (panicstr)
265300d0963fSdilpreet 		(void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges,
265400d0963fSdilpreet 		    (void *)tgt_err);
265500d0963fSdilpreet 	else
265600d0963fSdilpreet 		ddi_walk_devs(ddi_root_node(), pci_check_ranges,
265700d0963fSdilpreet 		    (void *)tgt_err);
265800d0963fSdilpreet 	if (tgt_err->tgt_dip == NULL)
265900d0963fSdilpreet 		return;
266000d0963fSdilpreet 
266100d0963fSdilpreet 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type,
266200d0963fSdilpreet 	    tgt_err->tgt_err_class);
266300d0963fSdilpreet 	pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0,
266400d0963fSdilpreet 	    PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL);
266500d0963fSdilpreet }
266600d0963fSdilpreet 
266700d0963fSdilpreet void
266800d0963fSdilpreet pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr)
266900d0963fSdilpreet {
267000d0963fSdilpreet 	pci_target_err_t tgt_err;
267100d0963fSdilpreet 
267200d0963fSdilpreet 	tgt_err.tgt_err_ena = ena;
267300d0963fSdilpreet 	tgt_err.tgt_err_class = class;
267400d0963fSdilpreet 	tgt_err.tgt_bridge_type = bridge_type;
267500d0963fSdilpreet 	tgt_err.tgt_err_addr = addr;
267600d0963fSdilpreet 	errorq_dispatch(pci_target_queue, (void *)&tgt_err,
267700d0963fSdilpreet 	    sizeof (pci_target_err_t), ERRORQ_ASYNC);
267800d0963fSdilpreet }
267900d0963fSdilpreet 
268000d0963fSdilpreet void
268100d0963fSdilpreet pci_targetq_init(void)
268200d0963fSdilpreet {
268300d0963fSdilpreet 	/*
268400d0963fSdilpreet 	 * PCI target errorq, to schedule async handling of generation of
268500d0963fSdilpreet 	 * target device ereports based on captured physical address.
268600d0963fSdilpreet 	 * The errorq is created here but destroyed when _fini is called
268700d0963fSdilpreet 	 * for the pci module.
268800d0963fSdilpreet 	 */
268900d0963fSdilpreet 	if (pci_target_queue == NULL) {
269000d0963fSdilpreet 		pci_target_queue = errorq_create("pci_target_queue",
269100d0963fSdilpreet 		    (errorq_func_t)pci_target_drain, (void *)NULL,
269200d0963fSdilpreet 		    TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL,
269300d0963fSdilpreet 		    ERRORQ_VITAL);
269400d0963fSdilpreet 		if (pci_target_queue == NULL)
269500d0963fSdilpreet 			panic("failed to create required system error queue");
269600d0963fSdilpreet 	}
269700d0963fSdilpreet }
2698