xref: /illumos-gate/usr/src/uts/common/os/pcifm.c (revision 00d0963faf2e861a4aef6b1bf28f99a5b2b20755)
1*00d0963fSdilpreet /*
2*00d0963fSdilpreet  * CDDL HEADER START
3*00d0963fSdilpreet  *
4*00d0963fSdilpreet  * The contents of this file are subject to the terms of the
5*00d0963fSdilpreet  * Common Development and Distribution License (the "License").
6*00d0963fSdilpreet  * You may not use this file except in compliance with the License.
7*00d0963fSdilpreet  *
8*00d0963fSdilpreet  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*00d0963fSdilpreet  * or http://www.opensolaris.org/os/licensing.
10*00d0963fSdilpreet  * See the License for the specific language governing permissions
11*00d0963fSdilpreet  * and limitations under the License.
12*00d0963fSdilpreet  *
13*00d0963fSdilpreet  * When distributing Covered Code, include this CDDL HEADER in each
14*00d0963fSdilpreet  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*00d0963fSdilpreet  * If applicable, add the following below this CDDL HEADER, with the
16*00d0963fSdilpreet  * fields enclosed by brackets "[]" replaced with your own identifying
17*00d0963fSdilpreet  * information: Portions Copyright [yyyy] [name of copyright owner]
18*00d0963fSdilpreet  *
19*00d0963fSdilpreet  * CDDL HEADER END
20*00d0963fSdilpreet  */
21*00d0963fSdilpreet 
22*00d0963fSdilpreet /*
23*00d0963fSdilpreet  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*00d0963fSdilpreet  * Use is subject to license terms.
25*00d0963fSdilpreet  */
26*00d0963fSdilpreet 
27*00d0963fSdilpreet #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*00d0963fSdilpreet 
29*00d0963fSdilpreet #include <sys/types.h>
30*00d0963fSdilpreet #include <sys/sunndi.h>
31*00d0963fSdilpreet #include <sys/sysmacros.h>
32*00d0963fSdilpreet #include <sys/ddifm_impl.h>
33*00d0963fSdilpreet #include <sys/fm/util.h>
34*00d0963fSdilpreet #include <sys/fm/protocol.h>
35*00d0963fSdilpreet #include <sys/fm/io/pci.h>
36*00d0963fSdilpreet #include <sys/fm/io/ddi.h>
37*00d0963fSdilpreet #include <sys/pci.h>
38*00d0963fSdilpreet #include <sys/pcie.h>
39*00d0963fSdilpreet #include <sys/pci_impl.h>
40*00d0963fSdilpreet #include <sys/epm.h>
41*00d0963fSdilpreet #include <sys/pcifm.h>
42*00d0963fSdilpreet 
43*00d0963fSdilpreet #define	PCIX_ECC_VER_CHECK(x)	(((x) == PCI_PCIX_VER_1) ||\
44*00d0963fSdilpreet 				((x) == PCI_PCIX_VER_2))
45*00d0963fSdilpreet 
46*00d0963fSdilpreet /*
47*00d0963fSdilpreet  * Expected PCI Express error mask values
48*00d0963fSdilpreet  */
49*00d0963fSdilpreet uint32_t pcie_expected_ce_mask = PCIE_AER_CE_AD_NFE;
50*00d0963fSdilpreet uint32_t pcie_expected_ue_mask = 0x0;
51*00d0963fSdilpreet uint32_t pcie_expected_sue_mask = 0x0;
52*00d0963fSdilpreet 
53*00d0963fSdilpreet errorq_t *pci_target_queue = NULL;
54*00d0963fSdilpreet 
55*00d0963fSdilpreet pci_fm_err_t pci_err_tbl[] = {
56*00d0963fSdilpreet 	PCI_DET_PERR,	PCI_STAT_PERROR,	NULL,		DDI_FM_UNKNOWN,
57*00d0963fSdilpreet 	PCI_MDPE,	PCI_STAT_S_PERROR,	PCI_TARG_MDPE,	DDI_FM_UNKNOWN,
58*00d0963fSdilpreet 	PCI_SIG_SERR,	PCI_STAT_S_SYSERR,	NULL,		DDI_FM_FATAL,
59*00d0963fSdilpreet 	PCI_MA,		PCI_STAT_R_MAST_AB,	PCI_TARG_MA,	DDI_FM_UNKNOWN,
60*00d0963fSdilpreet 	PCI_REC_TA,	PCI_STAT_R_TARG_AB,	PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
61*00d0963fSdilpreet 	PCI_SIG_TA,	PCI_STAT_S_TARG_AB,	NULL,		DDI_FM_UNKNOWN,
62*00d0963fSdilpreet 	NULL, NULL, NULL, NULL,
63*00d0963fSdilpreet };
64*00d0963fSdilpreet 
65*00d0963fSdilpreet pci_fm_err_t pci_bdg_err_tbl[] = {
66*00d0963fSdilpreet 	PCI_DET_PERR,	PCI_STAT_PERROR,	NULL,		DDI_FM_UNKNOWN,
67*00d0963fSdilpreet 	PCI_MDPE,	PCI_STAT_S_PERROR,	PCI_TARG_MDPE,	DDI_FM_UNKNOWN,
68*00d0963fSdilpreet 	PCI_REC_SERR,	PCI_STAT_S_SYSERR,	NULL,		DDI_FM_UNKNOWN,
69*00d0963fSdilpreet 	PCI_MA,		PCI_STAT_R_MAST_AB,	PCI_TARG_MA,	DDI_FM_UNKNOWN,
70*00d0963fSdilpreet 	PCI_REC_TA,	PCI_STAT_R_TARG_AB,	PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
71*00d0963fSdilpreet 	PCI_SIG_TA,	PCI_STAT_S_TARG_AB,	NULL,		DDI_FM_UNKNOWN,
72*00d0963fSdilpreet 	NULL, NULL, NULL, NULL,
73*00d0963fSdilpreet };
74*00d0963fSdilpreet 
75*00d0963fSdilpreet static pci_fm_err_t pciex_ce_err_tbl[] = {
76*00d0963fSdilpreet 	PCIEX_RE,	PCIE_AER_CE_RECEIVER_ERR,	NULL,	DDI_FM_NONFATAL,
77*00d0963fSdilpreet 	PCIEX_RNR,	PCIE_AER_CE_REPLAY_ROLLOVER,	NULL,	DDI_FM_NONFATAL,
78*00d0963fSdilpreet 	PCIEX_RTO,	PCIE_AER_CE_REPLAY_TO,		NULL,	DDI_FM_NONFATAL,
79*00d0963fSdilpreet 	PCIEX_BDP,	PCIE_AER_CE_BAD_DLLP,		NULL,	DDI_FM_NONFATAL,
80*00d0963fSdilpreet 	PCIEX_BTP,	PCIE_AER_CE_BAD_TLP,		NULL,	DDI_FM_NONFATAL,
81*00d0963fSdilpreet 	PCIEX_ANFE,	PCIE_AER_CE_AD_NFE,		NULL,	DDI_FM_NONFATAL,
82*00d0963fSdilpreet 	NULL, NULL, NULL, NULL,
83*00d0963fSdilpreet };
84*00d0963fSdilpreet 
85*00d0963fSdilpreet static pci_fm_err_t pciex_ue_err_tbl[] = {
86*00d0963fSdilpreet 	PCIEX_TE,	PCIE_AER_UCE_TRAINING,		NULL,	DDI_FM_FATAL,
87*00d0963fSdilpreet 	PCIEX_DLP,	PCIE_AER_UCE_DLP,		NULL,	DDI_FM_FATAL,
88*00d0963fSdilpreet 	PCIEX_SD,	PCIE_AER_UCE_SD,		NULL,   DDI_FM_FATAL,
89*00d0963fSdilpreet 	PCIEX_ROF,	PCIE_AER_UCE_RO,		NULL,	DDI_FM_FATAL,
90*00d0963fSdilpreet 	PCIEX_FCP,	PCIE_AER_UCE_FCP,		NULL,	DDI_FM_FATAL,
91*00d0963fSdilpreet 	PCIEX_MFP,	PCIE_AER_UCE_MTLP,		NULL,	DDI_FM_FATAL,
92*00d0963fSdilpreet 	PCIEX_CTO,	PCIE_AER_UCE_TO,		NULL,	DDI_FM_NONFATAL,
93*00d0963fSdilpreet 	PCIEX_UC,	PCIE_AER_UCE_UC,		NULL,	DDI_FM_NONFATAL,
94*00d0963fSdilpreet 	PCIEX_ECRC,	PCIE_AER_UCE_ECRC,		NULL,	DDI_FM_UNKNOWN,
95*00d0963fSdilpreet 	PCIEX_CA,	PCIE_AER_UCE_CA,		NULL,	DDI_FM_UNKNOWN,
96*00d0963fSdilpreet 	PCIEX_UR,	PCIE_AER_UCE_UR,		NULL,	DDI_FM_NONFATAL,
97*00d0963fSdilpreet 	PCIEX_POIS,	PCIE_AER_UCE_PTLP,		NULL,	DDI_FM_UNKNOWN,
98*00d0963fSdilpreet 	NULL, NULL, NULL, NULL,
99*00d0963fSdilpreet };
100*00d0963fSdilpreet 
101*00d0963fSdilpreet static pci_fm_err_t pcie_sue_err_tbl[] = {
102*00d0963fSdilpreet 	PCIEX_S_TA_SC,	PCIE_AER_SUCE_TA_ON_SC,		NULL,	DDI_FM_UNKNOWN,
103*00d0963fSdilpreet 	PCIEX_S_MA_SC,	PCIE_AER_SUCE_MA_ON_SC,		NULL,	DDI_FM_UNKNOWN,
104*00d0963fSdilpreet 	PCIEX_S_RTA,	PCIE_AER_SUCE_RCVD_TA,		NULL,	DDI_FM_UNKNOWN,
105*00d0963fSdilpreet 	PCIEX_S_RMA,	PCIE_AER_SUCE_RCVD_MA,		NULL,	DDI_FM_UNKNOWN,
106*00d0963fSdilpreet 	PCIEX_S_USC,	PCIE_AER_SUCE_USC_ERR,		NULL,	DDI_FM_UNKNOWN,
107*00d0963fSdilpreet 	PCIEX_S_USCMD,	PCIE_AER_SUCE_USC_MSG_DATA_ERR,	NULL,	DDI_FM_FATAL,
108*00d0963fSdilpreet 	PCIEX_S_UDE,	PCIE_AER_SUCE_UC_DATA_ERR,	NULL,	DDI_FM_UNKNOWN,
109*00d0963fSdilpreet 	PCIEX_S_UAT,	PCIE_AER_SUCE_UC_ATTR_ERR,	NULL,	DDI_FM_FATAL,
110*00d0963fSdilpreet 	PCIEX_S_UADR,	PCIE_AER_SUCE_UC_ADDR_ERR,	NULL,	DDI_FM_FATAL,
111*00d0963fSdilpreet 	PCIEX_S_TEX,	PCIE_AER_SUCE_TIMER_EXPIRED,	NULL,	DDI_FM_FATAL,
112*00d0963fSdilpreet 	PCIEX_S_PERR,	PCIE_AER_SUCE_PERR_ASSERT,	NULL,	DDI_FM_UNKNOWN,
113*00d0963fSdilpreet 	PCIEX_S_SERR,	PCIE_AER_SUCE_SERR_ASSERT,	NULL,	DDI_FM_FATAL,
114*00d0963fSdilpreet 	PCIEX_INTERR,	PCIE_AER_SUCE_INTERNAL_ERR,	NULL,	DDI_FM_FATAL,
115*00d0963fSdilpreet 	NULL, NULL, NULL, NULL,
116*00d0963fSdilpreet };
117*00d0963fSdilpreet 
118*00d0963fSdilpreet static pci_fm_err_t pcix_err_tbl[] = {
119*00d0963fSdilpreet 	PCIX_SPL_DIS,		PCI_PCIX_SPL_DSCD,	NULL,	DDI_FM_UNKNOWN,
120*00d0963fSdilpreet 	PCIX_UNEX_SPL,		PCI_PCIX_UNEX_SPL,	NULL,	DDI_FM_UNKNOWN,
121*00d0963fSdilpreet 	PCIX_RX_SPL_MSG,	PCI_PCIX_RX_SPL_MSG,	NULL,   DDI_FM_UNKNOWN,
122*00d0963fSdilpreet 	NULL, NULL, NULL, NULL,
123*00d0963fSdilpreet };
124*00d0963fSdilpreet 
125*00d0963fSdilpreet static pci_fm_err_t pcix_sec_err_tbl[] = {
126*00d0963fSdilpreet 	PCIX_SPL_DIS,		PCI_PCIX_BSS_SPL_DSCD,	NULL,	DDI_FM_UNKNOWN,
127*00d0963fSdilpreet 	PCIX_UNEX_SPL,		PCI_PCIX_BSS_UNEX_SPL,	NULL,	DDI_FM_UNKNOWN,
128*00d0963fSdilpreet 	PCIX_BSS_SPL_OR,	PCI_PCIX_BSS_SPL_OR,	NULL,	DDI_FM_NONFATAL,
129*00d0963fSdilpreet 	PCIX_BSS_SPL_DLY,	PCI_PCIX_BSS_SPL_DLY,	NULL,	DDI_FM_NONFATAL,
130*00d0963fSdilpreet 	NULL, NULL, NULL, NULL,
131*00d0963fSdilpreet };
132*00d0963fSdilpreet 
133*00d0963fSdilpreet static pci_fm_err_t pciex_nadv_err_tbl[] = {
134*00d0963fSdilpreet 	PCIEX_UR,	PCIE_DEVSTS_UR_DETECTED,	NULL,	DDI_FM_UNKNOWN,
135*00d0963fSdilpreet 	PCIEX_FAT,	PCIE_DEVSTS_FE_DETECTED,	NULL,	DDI_FM_FATAL,
136*00d0963fSdilpreet 	PCIEX_NONFAT,	PCIE_DEVSTS_NFE_DETECTED,	NULL,	DDI_FM_UNKNOWN,
137*00d0963fSdilpreet 	PCIEX_CORR,	PCIE_DEVSTS_CE_DETECTED,	NULL,	DDI_FM_NONFATAL,
138*00d0963fSdilpreet 	NULL, NULL, NULL, NULL,
139*00d0963fSdilpreet };
140*00d0963fSdilpreet 
141*00d0963fSdilpreet static int
142*00d0963fSdilpreet pci_config_check(ddi_acc_handle_t handle)
143*00d0963fSdilpreet {
144*00d0963fSdilpreet 	ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle);
145*00d0963fSdilpreet 	ddi_fm_error_t de;
146*00d0963fSdilpreet 
147*00d0963fSdilpreet 	if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip))))
148*00d0963fSdilpreet 		return (DDI_FM_OK);
149*00d0963fSdilpreet 
150*00d0963fSdilpreet 	de.fme_version = DDI_FME_VERSION;
151*00d0963fSdilpreet 
152*00d0963fSdilpreet 	ddi_fm_acc_err_get(handle, &de, de.fme_version);
153*00d0963fSdilpreet 	if (de.fme_status != DDI_FM_OK) {
154*00d0963fSdilpreet 		char buf[FM_MAX_CLASS];
155*00d0963fSdilpreet 
156*00d0963fSdilpreet 		(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", PCI_ERROR_SUBCLASS,
157*00d0963fSdilpreet 		    PCI_NR);
158*00d0963fSdilpreet 		ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena, DDI_NOSLEEP,
159*00d0963fSdilpreet 		    FM_VERSION, DATA_TYPE_UINT8, 0, NULL);
160*00d0963fSdilpreet 		ddi_fm_acc_err_clear(handle, de.fme_version);
161*00d0963fSdilpreet 	}
162*00d0963fSdilpreet 	return (de.fme_status);
163*00d0963fSdilpreet }
164*00d0963fSdilpreet 
165*00d0963fSdilpreet static void
166*00d0963fSdilpreet pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs,
167*00d0963fSdilpreet     uint8_t pcix_cap_ptr)
168*00d0963fSdilpreet {
169*00d0963fSdilpreet 	int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV;
170*00d0963fSdilpreet 
171*00d0963fSdilpreet 	pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl,
172*00d0963fSdilpreet 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS :
173*00d0963fSdilpreet 	    PCI_PCIX_ECC_STATUS)));
174*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
175*00d0963fSdilpreet 		pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID;
176*00d0963fSdilpreet 	else
177*00d0963fSdilpreet 		return;
178*00d0963fSdilpreet 	pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl,
179*00d0963fSdilpreet 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD :
180*00d0963fSdilpreet 	    PCI_PCIX_ECC_FST_AD)));
181*00d0963fSdilpreet 	pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl,
182*00d0963fSdilpreet 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD :
183*00d0963fSdilpreet 	    PCI_PCIX_ECC_SEC_AD)));
184*00d0963fSdilpreet 	pcix_ecc_regs->pcix_ecc_attr = pci_config_get32((
185*00d0963fSdilpreet 	    ddi_acc_handle_t)erpt_p->pe_hdl,
186*00d0963fSdilpreet 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR)));
187*00d0963fSdilpreet }
188*00d0963fSdilpreet 
189*00d0963fSdilpreet static void
190*00d0963fSdilpreet pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs)
191*00d0963fSdilpreet {
192*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
193*00d0963fSdilpreet 		pcix_bdg_error_regs_t *pcix_bdg_regs =
194*00d0963fSdilpreet 		    (pcix_bdg_error_regs_t *)pe_regs;
195*00d0963fSdilpreet 		uint8_t pcix_bdg_cap_ptr;
196*00d0963fSdilpreet 		int i;
197*00d0963fSdilpreet 
198*00d0963fSdilpreet 		pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
199*00d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16(
200*00d0963fSdilpreet 		    erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS));
201*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
202*00d0963fSdilpreet 			pcix_bdg_regs->pcix_bdg_vflags |=
203*00d0963fSdilpreet 			    PCIX_BDG_SEC_STATUS_VALID;
204*00d0963fSdilpreet 		else
205*00d0963fSdilpreet 			return;
206*00d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl,
207*00d0963fSdilpreet 		    (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS));
208*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
209*00d0963fSdilpreet 			pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID;
210*00d0963fSdilpreet 		else
211*00d0963fSdilpreet 			return;
212*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
213*00d0963fSdilpreet 			pcix_ecc_regs_t *pcix_bdg_ecc_regs;
214*00d0963fSdilpreet 			/*
215*00d0963fSdilpreet 			 * PCI Express to PCI-X bridges only implement the
216*00d0963fSdilpreet 			 * secondary side of the PCI-X ECC registers, bit one is
217*00d0963fSdilpreet 			 * read-only so we make sure we do not write to it.
218*00d0963fSdilpreet 			 */
219*00d0963fSdilpreet 			if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
220*00d0963fSdilpreet 				pcix_bdg_ecc_regs =
221*00d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_ecc_regs[1];
222*00d0963fSdilpreet 				pcix_ecc_regs_gather(erpt_p, pcix_bdg_ecc_regs,
223*00d0963fSdilpreet 				    pcix_bdg_cap_ptr);
224*00d0963fSdilpreet 			} else {
225*00d0963fSdilpreet 				for (i = 0; i < 2; i++) {
226*00d0963fSdilpreet 					pcix_bdg_ecc_regs =
227*00d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_ecc_regs[i];
228*00d0963fSdilpreet 					pci_config_put32(erpt_p->pe_hdl,
229*00d0963fSdilpreet 					    (pcix_bdg_cap_ptr +
230*00d0963fSdilpreet 					    PCI_PCIX_BDG_ECC_STATUS), i);
231*00d0963fSdilpreet 					pcix_ecc_regs_gather(erpt_p,
232*00d0963fSdilpreet 					    pcix_bdg_ecc_regs,
233*00d0963fSdilpreet 					    pcix_bdg_cap_ptr);
234*00d0963fSdilpreet 				}
235*00d0963fSdilpreet 			}
236*00d0963fSdilpreet 		}
237*00d0963fSdilpreet 	} else {
238*00d0963fSdilpreet 		pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
239*00d0963fSdilpreet 		uint8_t pcix_cap_ptr;
240*00d0963fSdilpreet 
241*00d0963fSdilpreet 		pcix_cap_ptr = pcix_regs->pcix_cap_ptr;
242*00d0963fSdilpreet 
243*00d0963fSdilpreet 		pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl,
244*00d0963fSdilpreet 		    (pcix_cap_ptr + PCI_PCIX_COMMAND));
245*00d0963fSdilpreet 		pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl,
246*00d0963fSdilpreet 		    (pcix_cap_ptr + PCI_PCIX_STATUS));
247*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
248*00d0963fSdilpreet 			pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID;
249*00d0963fSdilpreet 		else
250*00d0963fSdilpreet 			return;
251*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
252*00d0963fSdilpreet 			pcix_ecc_regs_t *pcix_ecc_regs =
253*00d0963fSdilpreet 			    pcix_regs->pcix_ecc_regs;
254*00d0963fSdilpreet 
255*00d0963fSdilpreet 			pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs,
256*00d0963fSdilpreet 			    pcix_cap_ptr);
257*00d0963fSdilpreet 		}
258*00d0963fSdilpreet 	}
259*00d0963fSdilpreet }
260*00d0963fSdilpreet 
261*00d0963fSdilpreet static void
262*00d0963fSdilpreet pcie_regs_gather(pci_erpt_t *erpt_p)
263*00d0963fSdilpreet {
264*00d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
265*00d0963fSdilpreet 	uint8_t pcie_cap_ptr;
266*00d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs;
267*00d0963fSdilpreet 	uint16_t pcie_ecap_ptr;
268*00d0963fSdilpreet 
269*00d0963fSdilpreet 	pcie_cap_ptr = pcie_regs->pcie_cap_ptr;
270*00d0963fSdilpreet 
271*00d0963fSdilpreet 	pcie_regs->pcie_err_status = pci_config_get16(erpt_p->pe_hdl,
272*00d0963fSdilpreet 	    pcie_cap_ptr + PCIE_DEVSTS);
273*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
274*00d0963fSdilpreet 		pcie_regs->pcie_vflags |= PCIE_ERR_STATUS_VALID;
275*00d0963fSdilpreet 	else
276*00d0963fSdilpreet 		return;
277*00d0963fSdilpreet 
278*00d0963fSdilpreet 	pcie_regs->pcie_err_ctl = pci_config_get16(erpt_p->pe_hdl,
279*00d0963fSdilpreet 	    (pcie_cap_ptr + PCIE_DEVCTL));
280*00d0963fSdilpreet 
281*00d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) && (erpt_p->pe_dflags &
282*00d0963fSdilpreet 	    PCIX_DEV))
283*00d0963fSdilpreet 		pcix_regs_gather(erpt_p, pcie_regs->pcix_bdg_regs);
284*00d0963fSdilpreet 
285*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV) {
286*00d0963fSdilpreet 		pcie_rc_error_regs_t *pcie_rc_regs = pcie_regs->pcie_rc_regs;
287*00d0963fSdilpreet 
288*00d0963fSdilpreet 		pcie_rc_regs->pcie_rc_status = pci_config_get32(erpt_p->pe_hdl,
289*00d0963fSdilpreet 		    (pcie_cap_ptr + PCIE_ROOTSTS));
290*00d0963fSdilpreet 		pcie_rc_regs->pcie_rc_ctl = pci_config_get16(erpt_p->pe_hdl,
291*00d0963fSdilpreet 		    (pcie_cap_ptr + PCIE_ROOTCTL));
292*00d0963fSdilpreet 	}
293*00d0963fSdilpreet 
294*00d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV))
295*00d0963fSdilpreet 		return;
296*00d0963fSdilpreet 
297*00d0963fSdilpreet 	pcie_adv_regs = pcie_regs->pcie_adv_regs;
298*00d0963fSdilpreet 
299*00d0963fSdilpreet 	pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr;
300*00d0963fSdilpreet 
301*00d0963fSdilpreet 	pcie_adv_regs->pcie_ue_status = pci_config_get32(erpt_p->pe_hdl,
302*00d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_UCE_STS);
303*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
304*00d0963fSdilpreet 		pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_STATUS_VALID;
305*00d0963fSdilpreet 
306*00d0963fSdilpreet 	pcie_adv_regs->pcie_ue_mask = pci_config_get32(erpt_p->pe_hdl,
307*00d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_UCE_MASK);
308*00d0963fSdilpreet 	pcie_adv_regs->pcie_ue_sev = pci_config_get32(erpt_p->pe_hdl,
309*00d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_UCE_SERV);
310*00d0963fSdilpreet 	pcie_adv_regs->pcie_adv_ctl = pci_config_get32(erpt_p->pe_hdl,
311*00d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_CTL);
312*00d0963fSdilpreet 	pcie_adv_regs->pcie_ue_hdr0 = pci_config_get32(erpt_p->pe_hdl,
313*00d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_HDR_LOG);
314*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) {
315*00d0963fSdilpreet 		int i;
316*00d0963fSdilpreet 		pcie_adv_regs->pcie_adv_vflags |= PCIE_UE_HDR_VALID;
317*00d0963fSdilpreet 
318*00d0963fSdilpreet 		for (i = 0; i < 3; i++) {
319*00d0963fSdilpreet 			pcie_adv_regs->pcie_ue_hdr[i] = pci_config_get32(
320*00d0963fSdilpreet 			    erpt_p->pe_hdl, pcie_ecap_ptr + PCIE_AER_HDR_LOG +
321*00d0963fSdilpreet 			    (4 * (i + 1)));
322*00d0963fSdilpreet 		}
323*00d0963fSdilpreet 	}
324*00d0963fSdilpreet 
325*00d0963fSdilpreet 	pcie_adv_regs->pcie_ce_status = pci_config_get32(erpt_p->pe_hdl,
326*00d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_CE_STS);
327*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
328*00d0963fSdilpreet 		pcie_adv_regs->pcie_adv_vflags |= PCIE_CE_STATUS_VALID;
329*00d0963fSdilpreet 
330*00d0963fSdilpreet 	pcie_adv_regs->pcie_ce_mask = pci_config_get32(erpt_p->pe_hdl,
331*00d0963fSdilpreet 	    pcie_ecap_ptr + PCIE_AER_CE_MASK);
332*00d0963fSdilpreet 
333*00d0963fSdilpreet 	/*
334*00d0963fSdilpreet 	 * If pci express to pci bridge then grab the bridge
335*00d0963fSdilpreet 	 * error registers.
336*00d0963fSdilpreet 	 */
337*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
338*00d0963fSdilpreet 		pcie_adv_bdg_error_regs_t *pcie_bdg_regs =
339*00d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_bdg_regs;
340*00d0963fSdilpreet 
341*00d0963fSdilpreet 		pcie_bdg_regs->pcie_sue_status =
342*00d0963fSdilpreet 		    pci_config_get32(erpt_p->pe_hdl,
343*00d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_SUCE_STS);
344*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
345*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_STATUS_VALID;
346*00d0963fSdilpreet 		pcie_bdg_regs->pcie_sue_hdr0 = pci_config_get32(erpt_p->pe_hdl,
347*00d0963fSdilpreet 		    (pcie_ecap_ptr + PCIE_AER_SHDR_LOG));
348*00d0963fSdilpreet 
349*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) {
350*00d0963fSdilpreet 			int i;
351*00d0963fSdilpreet 
352*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_vflags |= PCIE_SUE_HDR_VALID;
353*00d0963fSdilpreet 
354*00d0963fSdilpreet 			for (i = 0; i < 3; i++) {
355*00d0963fSdilpreet 				pcie_bdg_regs->pcie_sue_hdr[i] =
356*00d0963fSdilpreet 				    pci_config_get32(erpt_p->pe_hdl,
357*00d0963fSdilpreet 					pcie_ecap_ptr + PCIE_AER_SHDR_LOG +
358*00d0963fSdilpreet 					(4 * (i + 1)));
359*00d0963fSdilpreet 			}
360*00d0963fSdilpreet 		}
361*00d0963fSdilpreet 	}
362*00d0963fSdilpreet 	/*
363*00d0963fSdilpreet 	 * If PCI Express root complex then grab the root complex
364*00d0963fSdilpreet 	 * error registers.
365*00d0963fSdilpreet 	 */
366*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV) {
367*00d0963fSdilpreet 		pcie_adv_rc_error_regs_t *pcie_rc_regs =
368*00d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_rc_regs;
369*00d0963fSdilpreet 
370*00d0963fSdilpreet 		pcie_rc_regs->pcie_rc_err_cmd = pci_config_get32(erpt_p->pe_hdl,
371*00d0963fSdilpreet 		    (pcie_ecap_ptr + PCIE_AER_RE_CMD));
372*00d0963fSdilpreet 		pcie_rc_regs->pcie_rc_err_status =
373*00d0963fSdilpreet 		    pci_config_get32(erpt_p->pe_hdl,
374*00d0963fSdilpreet 			(pcie_ecap_ptr + PCIE_AER_RE_STS));
375*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
376*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_vflags |=
377*00d0963fSdilpreet 			    PCIE_RC_ERR_STATUS_VALID;
378*00d0963fSdilpreet 		pcie_rc_regs->pcie_rc_ce_src_id =
379*00d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl,
380*00d0963fSdilpreet 			(pcie_ecap_ptr + PCIE_AER_CE_SRC_ID));
381*00d0963fSdilpreet 		pcie_rc_regs->pcie_rc_ue_src_id =
382*00d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl,
383*00d0963fSdilpreet 			(pcie_ecap_ptr + PCIE_AER_ERR_SRC_ID));
384*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
385*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_vflags |= PCIE_SRC_ID_VALID;
386*00d0963fSdilpreet 	}
387*00d0963fSdilpreet }
388*00d0963fSdilpreet 
389*00d0963fSdilpreet /*ARGSUSED*/
390*00d0963fSdilpreet static void
391*00d0963fSdilpreet pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p)
392*00d0963fSdilpreet {
393*00d0963fSdilpreet 	pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs;
394*00d0963fSdilpreet 
395*00d0963fSdilpreet 	/*
396*00d0963fSdilpreet 	 * Start by reading all the error registers that are available for
397*00d0963fSdilpreet 	 * pci and pci express and for leaf devices and bridges/switches
398*00d0963fSdilpreet 	 */
399*00d0963fSdilpreet 	pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl,
400*00d0963fSdilpreet 	    PCI_CONF_STAT);
401*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK)
402*00d0963fSdilpreet 		return;
403*00d0963fSdilpreet 	pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID;
404*00d0963fSdilpreet 	pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl,
405*00d0963fSdilpreet 	    PCI_CONF_COMM);
406*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK)
407*00d0963fSdilpreet 		return;
408*00d0963fSdilpreet 
409*00d0963fSdilpreet 	/*
410*00d0963fSdilpreet 	 * If pci-pci bridge grab PCI bridge specific error registers.
411*00d0963fSdilpreet 	 */
412*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
413*00d0963fSdilpreet 		pci_regs->pci_bdg_regs->pci_bdg_sec_stat =
414*00d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS);
415*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
416*00d0963fSdilpreet 			pci_regs->pci_bdg_regs->pci_bdg_vflags |=
417*00d0963fSdilpreet 			    PCI_BDG_SEC_STAT_VALID;
418*00d0963fSdilpreet 		pci_regs->pci_bdg_regs->pci_bdg_ctrl =
419*00d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL);
420*00d0963fSdilpreet 		if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK)
421*00d0963fSdilpreet 			pci_regs->pci_bdg_regs->pci_bdg_vflags |=
422*00d0963fSdilpreet 			    PCI_BDG_CTRL_VALID;
423*00d0963fSdilpreet 	}
424*00d0963fSdilpreet 
425*00d0963fSdilpreet 	/*
426*00d0963fSdilpreet 	 * If pci express device grab pci express error registers and
427*00d0963fSdilpreet 	 * check for advanced error reporting features and grab them if
428*00d0963fSdilpreet 	 * available.
429*00d0963fSdilpreet 	 */
430*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_DEV)
431*00d0963fSdilpreet 		pcie_regs_gather(erpt_p);
432*00d0963fSdilpreet 	else if (erpt_p->pe_dflags & PCIX_DEV)
433*00d0963fSdilpreet 		pcix_regs_gather(erpt_p, erpt_p->pe_regs);
434*00d0963fSdilpreet 
435*00d0963fSdilpreet }
436*00d0963fSdilpreet 
437*00d0963fSdilpreet static void
438*00d0963fSdilpreet pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs)
439*00d0963fSdilpreet {
440*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
441*00d0963fSdilpreet 		pcix_bdg_error_regs_t *pcix_bdg_regs =
442*00d0963fSdilpreet 		    (pcix_bdg_error_regs_t *)pe_regs;
443*00d0963fSdilpreet 		uint8_t pcix_bdg_cap_ptr;
444*00d0963fSdilpreet 		int i;
445*00d0963fSdilpreet 
446*00d0963fSdilpreet 		pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
447*00d0963fSdilpreet 
448*00d0963fSdilpreet 		if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID)
449*00d0963fSdilpreet 			pci_config_put16(erpt_p->pe_hdl,
450*00d0963fSdilpreet 			    (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS),
451*00d0963fSdilpreet 			    pcix_bdg_regs->pcix_bdg_sec_stat);
452*00d0963fSdilpreet 
453*00d0963fSdilpreet 		if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID)
454*00d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
455*00d0963fSdilpreet 			    (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS),
456*00d0963fSdilpreet 			    pcix_bdg_regs->pcix_bdg_stat);
457*00d0963fSdilpreet 
458*00d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_vflags = 0x0;
459*00d0963fSdilpreet 
460*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
461*00d0963fSdilpreet 			pcix_ecc_regs_t *pcix_bdg_ecc_regs;
462*00d0963fSdilpreet 			/*
463*00d0963fSdilpreet 			 * PCI Express to PCI-X bridges only implement the
464*00d0963fSdilpreet 			 * secondary side of the PCI-X ECC registers, bit one is
465*00d0963fSdilpreet 			 * read-only so we make sure we do not write to it.
466*00d0963fSdilpreet 			 */
467*00d0963fSdilpreet 			if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
468*00d0963fSdilpreet 				pcix_bdg_ecc_regs =
469*00d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_ecc_regs[1];
470*00d0963fSdilpreet 
471*00d0963fSdilpreet 				if (pcix_bdg_ecc_regs->pcix_ecc_vflags &
472*00d0963fSdilpreet 				    PCIX_ERR_ECC_STS_VALID) {
473*00d0963fSdilpreet 
474*00d0963fSdilpreet 					pci_config_put32(erpt_p->pe_hdl,
475*00d0963fSdilpreet 					    (pcix_bdg_cap_ptr +
476*00d0963fSdilpreet 					    PCI_PCIX_BDG_ECC_STATUS),
477*00d0963fSdilpreet 					    pcix_bdg_ecc_regs->
478*00d0963fSdilpreet 					    pcix_ecc_ctlstat);
479*00d0963fSdilpreet 				}
480*00d0963fSdilpreet 				pcix_bdg_ecc_regs->pcix_ecc_vflags = 0x0;
481*00d0963fSdilpreet 			} else {
482*00d0963fSdilpreet 				for (i = 0; i < 2; i++) {
483*00d0963fSdilpreet 					pcix_bdg_ecc_regs =
484*00d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_ecc_regs[i];
485*00d0963fSdilpreet 
486*00d0963fSdilpreet 
487*00d0963fSdilpreet 					if (pcix_bdg_ecc_regs->pcix_ecc_vflags &
488*00d0963fSdilpreet 					    PCIX_ERR_ECC_STS_VALID) {
489*00d0963fSdilpreet 						pci_config_put32(erpt_p->pe_hdl,
490*00d0963fSdilpreet 						    (pcix_bdg_cap_ptr +
491*00d0963fSdilpreet 						    PCI_PCIX_BDG_ECC_STATUS),
492*00d0963fSdilpreet 						    i);
493*00d0963fSdilpreet 
494*00d0963fSdilpreet 						pci_config_put32(erpt_p->pe_hdl,
495*00d0963fSdilpreet 						    (pcix_bdg_cap_ptr +
496*00d0963fSdilpreet 						    PCI_PCIX_BDG_ECC_STATUS),
497*00d0963fSdilpreet 						    pcix_bdg_ecc_regs->
498*00d0963fSdilpreet 						    pcix_ecc_ctlstat);
499*00d0963fSdilpreet 					}
500*00d0963fSdilpreet 					pcix_bdg_ecc_regs->pcix_ecc_vflags =
501*00d0963fSdilpreet 					    0x0;
502*00d0963fSdilpreet 				}
503*00d0963fSdilpreet 			}
504*00d0963fSdilpreet 		}
505*00d0963fSdilpreet 	} else {
506*00d0963fSdilpreet 		pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
507*00d0963fSdilpreet 		uint8_t pcix_cap_ptr;
508*00d0963fSdilpreet 
509*00d0963fSdilpreet 		pcix_cap_ptr = pcix_regs->pcix_cap_ptr;
510*00d0963fSdilpreet 
511*00d0963fSdilpreet 		if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID)
512*00d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
513*00d0963fSdilpreet 			    (pcix_cap_ptr + PCI_PCIX_STATUS),
514*00d0963fSdilpreet 			    pcix_regs->pcix_status);
515*00d0963fSdilpreet 
516*00d0963fSdilpreet 		pcix_regs->pcix_vflags = 0x0;
517*00d0963fSdilpreet 
518*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
519*00d0963fSdilpreet 			pcix_ecc_regs_t *pcix_ecc_regs =
520*00d0963fSdilpreet 			    pcix_regs->pcix_ecc_regs;
521*00d0963fSdilpreet 
522*00d0963fSdilpreet 			if (pcix_ecc_regs->pcix_ecc_vflags &
523*00d0963fSdilpreet 			    PCIX_ERR_ECC_STS_VALID)
524*00d0963fSdilpreet 				pci_config_put32(erpt_p->pe_hdl,
525*00d0963fSdilpreet 				    (pcix_cap_ptr + PCI_PCIX_ECC_STATUS),
526*00d0963fSdilpreet 				    pcix_ecc_regs->pcix_ecc_ctlstat);
527*00d0963fSdilpreet 
528*00d0963fSdilpreet 			pcix_ecc_regs->pcix_ecc_vflags = 0x0;
529*00d0963fSdilpreet 		}
530*00d0963fSdilpreet 	}
531*00d0963fSdilpreet }
532*00d0963fSdilpreet 
533*00d0963fSdilpreet static void
534*00d0963fSdilpreet pcie_regs_clear(pci_erpt_t *erpt_p)
535*00d0963fSdilpreet {
536*00d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
537*00d0963fSdilpreet 	uint8_t pcie_cap_ptr;
538*00d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs;
539*00d0963fSdilpreet 	uint16_t pcie_ecap_ptr;
540*00d0963fSdilpreet 
541*00d0963fSdilpreet 	pcie_cap_ptr = pcie_regs->pcie_cap_ptr;
542*00d0963fSdilpreet 
543*00d0963fSdilpreet 	if (pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID)
544*00d0963fSdilpreet 		pci_config_put16(erpt_p->pe_hdl, pcie_cap_ptr + PCIE_DEVSTS,
545*00d0963fSdilpreet 		    pcie_regs->pcie_err_status);
546*00d0963fSdilpreet 
547*00d0963fSdilpreet 	pcie_regs->pcie_vflags = 0x0;
548*00d0963fSdilpreet 
549*00d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) &&
550*00d0963fSdilpreet 	    (erpt_p->pe_dflags & PCIX_DEV))
551*00d0963fSdilpreet 		pcix_regs_clear(erpt_p, pcie_regs->pcix_bdg_regs);
552*00d0963fSdilpreet 
553*00d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV))
554*00d0963fSdilpreet 		return;
555*00d0963fSdilpreet 
556*00d0963fSdilpreet 	pcie_adv_regs = pcie_regs->pcie_adv_regs;
557*00d0963fSdilpreet 
558*00d0963fSdilpreet 	pcie_ecap_ptr = pcie_adv_regs->pcie_adv_cap_ptr;
559*00d0963fSdilpreet 
560*00d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID)
561*00d0963fSdilpreet 		pci_config_put32(erpt_p->pe_hdl,
562*00d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_UCE_STS,
563*00d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_status);
564*00d0963fSdilpreet 
565*00d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID)
566*00d0963fSdilpreet 		pci_config_put32(erpt_p->pe_hdl,
567*00d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_CE_STS,
568*00d0963fSdilpreet 		    pcie_adv_regs->pcie_ce_status);
569*00d0963fSdilpreet 
570*00d0963fSdilpreet 
571*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
572*00d0963fSdilpreet 		pcie_adv_bdg_error_regs_t *pcie_bdg_regs =
573*00d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_bdg_regs;
574*00d0963fSdilpreet 
575*00d0963fSdilpreet 
576*00d0963fSdilpreet 		if (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID)
577*00d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
578*00d0963fSdilpreet 			    pcie_ecap_ptr + PCIE_AER_SUCE_STS,
579*00d0963fSdilpreet 			    pcie_bdg_regs->pcie_sue_status);
580*00d0963fSdilpreet 	}
581*00d0963fSdilpreet 	/*
582*00d0963fSdilpreet 	 * If PCI Express root complex then clear the root complex
583*00d0963fSdilpreet 	 * error registers.
584*00d0963fSdilpreet 	 */
585*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV) {
586*00d0963fSdilpreet 		pcie_adv_rc_error_regs_t *pcie_rc_regs =
587*00d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_rc_regs;
588*00d0963fSdilpreet 
589*00d0963fSdilpreet 
590*00d0963fSdilpreet 		if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID)
591*00d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
592*00d0963fSdilpreet 			    (pcie_ecap_ptr + PCIE_AER_RE_STS),
593*00d0963fSdilpreet 			    pcie_rc_regs->pcie_rc_err_status);
594*00d0963fSdilpreet 	}
595*00d0963fSdilpreet 	pcie_adv_regs->pcie_adv_vflags = 0x0;
596*00d0963fSdilpreet }
597*00d0963fSdilpreet 
598*00d0963fSdilpreet static void
599*00d0963fSdilpreet pci_regs_clear(pci_erpt_t *erpt_p)
600*00d0963fSdilpreet {
601*00d0963fSdilpreet 	/*
602*00d0963fSdilpreet 	 * Finally clear the error bits
603*00d0963fSdilpreet 	 */
604*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_DEV)
605*00d0963fSdilpreet 		pcie_regs_clear(erpt_p);
606*00d0963fSdilpreet 	else if (erpt_p->pe_dflags & PCIX_DEV)
607*00d0963fSdilpreet 		pcix_regs_clear(erpt_p, erpt_p->pe_regs);
608*00d0963fSdilpreet 
609*00d0963fSdilpreet 	if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID)
610*00d0963fSdilpreet 		pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT,
611*00d0963fSdilpreet 		    erpt_p->pe_pci_regs->pci_err_status);
612*00d0963fSdilpreet 
613*00d0963fSdilpreet 	erpt_p->pe_pci_regs->pci_vflags = 0x0;
614*00d0963fSdilpreet 
615*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
616*00d0963fSdilpreet 		if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
617*00d0963fSdilpreet 		    PCI_BDG_SEC_STAT_VALID)
618*00d0963fSdilpreet 			pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS,
619*00d0963fSdilpreet 			    erpt_p->pe_pci_regs->pci_bdg_regs->
620*00d0963fSdilpreet 			    pci_bdg_sec_stat);
621*00d0963fSdilpreet 		if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
622*00d0963fSdilpreet 		    PCI_BDG_CTRL_VALID)
623*00d0963fSdilpreet 			pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL,
624*00d0963fSdilpreet 			    erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl);
625*00d0963fSdilpreet 
626*00d0963fSdilpreet 		erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0;
627*00d0963fSdilpreet 	}
628*00d0963fSdilpreet }
629*00d0963fSdilpreet 
630*00d0963fSdilpreet /*
631*00d0963fSdilpreet  * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport
632*00d0963fSdilpreet  * generation.
633*00d0963fSdilpreet  */
634*00d0963fSdilpreet /* ARGSUSED */
635*00d0963fSdilpreet static void
636*00d0963fSdilpreet pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
637*00d0963fSdilpreet {
638*00d0963fSdilpreet 	uint8_t pcix_cap_ptr;
639*00d0963fSdilpreet 	int i;
640*00d0963fSdilpreet 
641*00d0963fSdilpreet 	pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
642*00d0963fSdilpreet 	    "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
643*00d0963fSdilpreet 
644*00d0963fSdilpreet 	if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL)
645*00d0963fSdilpreet 		erpt_p->pe_dflags |= PCIX_DEV;
646*00d0963fSdilpreet 	else
647*00d0963fSdilpreet 		return;
648*00d0963fSdilpreet 
649*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
650*00d0963fSdilpreet 		pcix_bdg_error_regs_t *pcix_bdg_regs;
651*00d0963fSdilpreet 
652*00d0963fSdilpreet 		erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t),
653*00d0963fSdilpreet 		    KM_SLEEP);
654*00d0963fSdilpreet 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
655*00d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr;
656*00d0963fSdilpreet 		pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl,
657*00d0963fSdilpreet 		    pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
658*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
659*00d0963fSdilpreet 			for (i = 0; i < 2; i++) {
660*00d0963fSdilpreet 				pcix_bdg_regs->pcix_bdg_ecc_regs[i] =
661*00d0963fSdilpreet 				    kmem_zalloc(sizeof (pcix_ecc_regs_t),
662*00d0963fSdilpreet 					KM_SLEEP);
663*00d0963fSdilpreet 			}
664*00d0963fSdilpreet 		}
665*00d0963fSdilpreet 	} else {
666*00d0963fSdilpreet 		pcix_error_regs_t *pcix_regs;
667*00d0963fSdilpreet 
668*00d0963fSdilpreet 		erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t),
669*00d0963fSdilpreet 		    KM_SLEEP);
670*00d0963fSdilpreet 		pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
671*00d0963fSdilpreet 		pcix_regs->pcix_cap_ptr = pcix_cap_ptr;
672*00d0963fSdilpreet 		pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl,
673*00d0963fSdilpreet 		    pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
674*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
675*00d0963fSdilpreet 			pcix_regs->pcix_ecc_regs = kmem_zalloc(
676*00d0963fSdilpreet 			    sizeof (pcix_ecc_regs_t), KM_SLEEP);
677*00d0963fSdilpreet 		}
678*00d0963fSdilpreet 	}
679*00d0963fSdilpreet }
680*00d0963fSdilpreet 
681*00d0963fSdilpreet static void
682*00d0963fSdilpreet pcie_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
683*00d0963fSdilpreet {
684*00d0963fSdilpreet 	pcie_error_regs_t *pcie_regs;
685*00d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs;
686*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
687*00d0963fSdilpreet 	uint8_t pcix_cap_ptr;
688*00d0963fSdilpreet 	uint8_t pcie_cap_ptr;
689*00d0963fSdilpreet 	uint16_t pcie_ecap_ptr;
690*00d0963fSdilpreet 	uint16_t dev_type = 0;
691*00d0963fSdilpreet 	uint32_t mask = pcie_expected_ue_mask;
692*00d0963fSdilpreet 
693*00d0963fSdilpreet 	/*
694*00d0963fSdilpreet 	 * The following sparc specific code should be removed once the pci_cap
695*00d0963fSdilpreet 	 * interfaces create the necessary properties for us.
696*00d0963fSdilpreet 	 */
697*00d0963fSdilpreet #if defined(__sparc)
698*00d0963fSdilpreet 	ushort_t status;
699*00d0963fSdilpreet 	uint32_t slot_cap;
700*00d0963fSdilpreet 	uint8_t cap_ptr = 0;
701*00d0963fSdilpreet 	uint8_t cap_id = 0;
702*00d0963fSdilpreet 	uint32_t hdr, hdr_next_ptr, hdr_cap_id;
703*00d0963fSdilpreet 	uint16_t offset = P2ALIGN(PCIE_EXT_CAP, 4);
704*00d0963fSdilpreet 	uint16_t aer_ptr = 0;
705*00d0963fSdilpreet 
706*00d0963fSdilpreet 	cap_ptr = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_CAP_PTR);
707*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) == DDI_FM_OK) {
708*00d0963fSdilpreet 		while ((cap_id = pci_config_get8(erpt_p->pe_hdl, cap_ptr)) !=
709*00d0963fSdilpreet 		    0xff) {
710*00d0963fSdilpreet 			if (cap_id == PCI_CAP_ID_PCIX) {
711*00d0963fSdilpreet 				(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
712*00d0963fSdilpreet 				    "pcix-capid-pointer", cap_ptr);
713*00d0963fSdilpreet 			}
714*00d0963fSdilpreet 		if (cap_id == PCI_CAP_ID_PCI_E) {
715*00d0963fSdilpreet 			status = pci_config_get16(erpt_p->pe_hdl, cap_ptr + 2);
716*00d0963fSdilpreet 			if (status & PCIE_PCIECAP_SLOT_IMPL) {
717*00d0963fSdilpreet 				/* offset 14h is Slot Cap Register */
718*00d0963fSdilpreet 				slot_cap = pci_config_get32(erpt_p->pe_hdl,
719*00d0963fSdilpreet 				    cap_ptr + PCIE_SLOTCAP);
720*00d0963fSdilpreet 				(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
721*00d0963fSdilpreet 				    "pcie-slotcap-reg", slot_cap);
722*00d0963fSdilpreet 			}
723*00d0963fSdilpreet 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
724*00d0963fSdilpreet 			    "pcie-capid-reg", pci_config_get16(erpt_p->pe_hdl,
725*00d0963fSdilpreet 			    cap_ptr + PCIE_PCIECAP));
726*00d0963fSdilpreet 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
727*00d0963fSdilpreet 			    "pcie-capid-pointer", cap_ptr);
728*00d0963fSdilpreet 
729*00d0963fSdilpreet 		}
730*00d0963fSdilpreet 			if ((cap_ptr = pci_config_get8(erpt_p->pe_hdl,
731*00d0963fSdilpreet 			    cap_ptr + 1)) == 0xff || cap_ptr == 0 ||
732*00d0963fSdilpreet 			    (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK))
733*00d0963fSdilpreet 				break;
734*00d0963fSdilpreet 		}
735*00d0963fSdilpreet 	}
736*00d0963fSdilpreet 
737*00d0963fSdilpreet #endif
738*00d0963fSdilpreet 
739*00d0963fSdilpreet 	pcix_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
740*00d0963fSdilpreet 	    "pcix-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
741*00d0963fSdilpreet 
742*00d0963fSdilpreet 	if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL)
743*00d0963fSdilpreet 		erpt_p->pe_dflags |= PCIX_DEV;
744*00d0963fSdilpreet 
745*00d0963fSdilpreet 	pcie_cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
746*00d0963fSdilpreet 	    DDI_PROP_DONTPASS, "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL);
747*00d0963fSdilpreet 
748*00d0963fSdilpreet 	if (pcie_cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
749*00d0963fSdilpreet 		erpt_p->pe_dflags |= PCIEX_DEV;
750*00d0963fSdilpreet 		erpt_p->pe_regs = kmem_zalloc(sizeof (pcie_error_regs_t),
751*00d0963fSdilpreet 		    KM_SLEEP);
752*00d0963fSdilpreet 		pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
753*00d0963fSdilpreet 		pcie_regs->pcie_cap_ptr = pcie_cap_ptr;
754*00d0963fSdilpreet 	}
755*00d0963fSdilpreet 
756*00d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_DEV))
757*00d0963fSdilpreet 		return;
758*00d0963fSdilpreet 
759*00d0963fSdilpreet 	/*
760*00d0963fSdilpreet 	 * Don't currently need to check for version here because we are
761*00d0963fSdilpreet 	 * compliant with PCIE 1.0a which is version 0 and is guaranteed
762*00d0963fSdilpreet 	 * software compatibility with future versions.  We will need to
763*00d0963fSdilpreet 	 * add errors for new detectors/features which are added in newer
764*00d0963fSdilpreet 	 * revisions [sec 7.8.2].
765*00d0963fSdilpreet 	 */
766*00d0963fSdilpreet 	pcie_regs->pcie_cap = pci_config_get16(erpt_p->pe_hdl,
767*00d0963fSdilpreet 	    pcie_regs->pcie_cap_ptr + PCIE_PCIECAP);
768*00d0963fSdilpreet 
769*00d0963fSdilpreet 	dev_type = pcie_regs->pcie_cap & PCIE_PCIECAP_DEV_TYPE_MASK;
770*00d0963fSdilpreet 
771*00d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) &&
772*00d0963fSdilpreet 	    (erpt_p->pe_dflags & PCIX_DEV)) {
773*00d0963fSdilpreet 		int i;
774*00d0963fSdilpreet 
775*00d0963fSdilpreet 		pcie_regs->pcix_bdg_regs =
776*00d0963fSdilpreet 		    kmem_zalloc(sizeof (pcix_bdg_error_regs_t), KM_SLEEP);
777*00d0963fSdilpreet 
778*00d0963fSdilpreet 		pcie_regs->pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr;
779*00d0963fSdilpreet 		pcie_regs->pcix_bdg_regs->pcix_bdg_ver =
780*00d0963fSdilpreet 		    pci_config_get16(erpt_p->pe_hdl,
781*00d0963fSdilpreet 			pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
782*00d0963fSdilpreet 
783*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcie_regs->pcix_bdg_regs->pcix_bdg_ver))
784*00d0963fSdilpreet 			for (i = 0; i < 2; i++)
785*00d0963fSdilpreet 				pcie_regs->pcix_bdg_regs->pcix_bdg_ecc_regs[i] =
786*00d0963fSdilpreet 				    kmem_zalloc(sizeof (pcix_ecc_regs_t),
787*00d0963fSdilpreet 					KM_SLEEP);
788*00d0963fSdilpreet 	}
789*00d0963fSdilpreet 
790*00d0963fSdilpreet 	if (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) {
791*00d0963fSdilpreet 		erpt_p->pe_dflags |= PCIEX_RC_DEV;
792*00d0963fSdilpreet 		pcie_regs->pcie_rc_regs = kmem_zalloc(
793*00d0963fSdilpreet 		    sizeof (pcie_rc_error_regs_t), KM_SLEEP);
794*00d0963fSdilpreet 	}
795*00d0963fSdilpreet 	/*
796*00d0963fSdilpreet 	 * The following sparc specific code should be removed once the pci_cap
797*00d0963fSdilpreet 	 * interfaces create the necessary properties for us.
798*00d0963fSdilpreet 	 */
799*00d0963fSdilpreet #if defined(__sparc)
800*00d0963fSdilpreet 
801*00d0963fSdilpreet 	hdr = pci_config_get32(erpt_p->pe_hdl, offset);
802*00d0963fSdilpreet 	hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
803*00d0963fSdilpreet 	    PCIE_EXT_CAP_NEXT_PTR_MASK;
804*00d0963fSdilpreet 	hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK;
805*00d0963fSdilpreet 
806*00d0963fSdilpreet 	while ((hdr_next_ptr != PCIE_EXT_CAP_NEXT_PTR_NULL) &&
807*00d0963fSdilpreet 	    (hdr_cap_id != PCIE_EXT_CAP_ID_AER)) {
808*00d0963fSdilpreet 		offset = P2ALIGN(hdr_next_ptr, 4);
809*00d0963fSdilpreet 		hdr = pci_config_get32(erpt_p->pe_hdl, offset);
810*00d0963fSdilpreet 		hdr_next_ptr = (hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) &
811*00d0963fSdilpreet 		    PCIE_EXT_CAP_NEXT_PTR_MASK;
812*00d0963fSdilpreet 		hdr_cap_id = (hdr >> PCIE_EXT_CAP_ID_SHIFT) &
813*00d0963fSdilpreet 		    PCIE_EXT_CAP_ID_MASK;
814*00d0963fSdilpreet 	}
815*00d0963fSdilpreet 
816*00d0963fSdilpreet 	if (hdr_cap_id == PCIE_EXT_CAP_ID_AER)
817*00d0963fSdilpreet 		aer_ptr = P2ALIGN(offset, 4);
818*00d0963fSdilpreet 	if (aer_ptr != PCI_CAP_NEXT_PTR_NULL)
819*00d0963fSdilpreet 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
820*00d0963fSdilpreet 		    "pcie-aer-pointer", aer_ptr);
821*00d0963fSdilpreet #endif
822*00d0963fSdilpreet 
823*00d0963fSdilpreet 	/*
824*00d0963fSdilpreet 	 * Find and store if this device is capable of pci express
825*00d0963fSdilpreet 	 * advanced errors, if not report an error against the device.
826*00d0963fSdilpreet 	 */
827*00d0963fSdilpreet 	pcie_ecap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
828*00d0963fSdilpreet 	    "pcie-aer-pointer", PCI_CAP_NEXT_PTR_NULL);
829*00d0963fSdilpreet 	if (pcie_ecap_ptr != PCI_CAP_NEXT_PTR_NULL) {
830*00d0963fSdilpreet 		erpt_p->pe_dflags |= PCIEX_ADV_DEV;
831*00d0963fSdilpreet 		pcie_regs->pcie_adv_regs = kmem_zalloc(
832*00d0963fSdilpreet 		    sizeof (pcie_adv_error_regs_t), KM_SLEEP);
833*00d0963fSdilpreet 		pcie_regs->pcie_adv_regs->pcie_adv_cap_ptr = pcie_ecap_ptr;
834*00d0963fSdilpreet 	}
835*00d0963fSdilpreet 
836*00d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) {
837*00d0963fSdilpreet 		(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
838*00d0963fSdilpreet 		    PCIEX_ERROR_SUBCLASS, PCIEX_NADV);
839*00d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, NULL, DDI_NOSLEEP,
840*00d0963fSdilpreet 		    FM_VERSION, DATA_TYPE_UINT8, 0, NULL);
841*00d0963fSdilpreet 		return;
842*00d0963fSdilpreet 	}
843*00d0963fSdilpreet 
844*00d0963fSdilpreet 	pcie_adv_regs = pcie_regs->pcie_adv_regs;
845*00d0963fSdilpreet 
846*00d0963fSdilpreet 	if (pcie_adv_regs == NULL)
847*00d0963fSdilpreet 		return;
848*00d0963fSdilpreet 	/*
849*00d0963fSdilpreet 	 * Initialize structures for advanced PCI Express devices.
850*00d0963fSdilpreet 	 */
851*00d0963fSdilpreet 
852*00d0963fSdilpreet 	/*
853*00d0963fSdilpreet 	 * Advanced error registers exist for PCI Express to PCI(X) Bridges and
854*00d0963fSdilpreet 	 * may also exist for PCI(X) to PCI Express Bridges, the latter is not
855*00d0963fSdilpreet 	 * well explained in the PCI Express to PCI/PCI-X Bridge Specification
856*00d0963fSdilpreet 	 * 1.0 and will be left out of the current gathering of these registers.
857*00d0963fSdilpreet 	 */
858*00d0963fSdilpreet 	if (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
859*00d0963fSdilpreet 		erpt_p->pe_dflags |= PCIEX_2PCI_DEV;
860*00d0963fSdilpreet 		pcie_adv_regs->pcie_adv_bdg_regs = kmem_zalloc(
861*00d0963fSdilpreet 		    sizeof (pcie_adv_bdg_error_regs_t), KM_SLEEP);
862*00d0963fSdilpreet 	}
863*00d0963fSdilpreet 
864*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV)
865*00d0963fSdilpreet 		pcie_adv_regs->pcie_adv_rc_regs = kmem_zalloc(
866*00d0963fSdilpreet 		    sizeof (pcie_adv_rc_error_regs_t), KM_SLEEP);
867*00d0963fSdilpreet 
868*00d0963fSdilpreet 	/*
869*00d0963fSdilpreet 	 * Check that mask values are as expected, if not
870*00d0963fSdilpreet 	 * change them to what we desire.
871*00d0963fSdilpreet 	 */
872*00d0963fSdilpreet 	pci_regs_gather(dip, erpt_p);
873*00d0963fSdilpreet 	pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
874*00d0963fSdilpreet 	if (pcie_regs->pcie_adv_regs->pcie_ce_mask != pcie_expected_ce_mask) {
875*00d0963fSdilpreet 		pci_config_put32(erpt_p->pe_hdl,
876*00d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_CE_MASK, pcie_expected_ce_mask);
877*00d0963fSdilpreet 	}
878*00d0963fSdilpreet 
879*00d0963fSdilpreet 	/* Disable PTLP/ECRC (or mask these two) for Switches */
880*00d0963fSdilpreet 	if (dev_type == PCIE_PCIECAP_DEV_TYPE_UP ||
881*00d0963fSdilpreet 	    dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN)
882*00d0963fSdilpreet 		mask |= PCIE_AER_UCE_PTLP | PCIE_AER_UCE_ECRC;
883*00d0963fSdilpreet 
884*00d0963fSdilpreet 	if (pcie_regs->pcie_adv_regs->pcie_ue_mask != mask) {
885*00d0963fSdilpreet 		pci_config_put32(erpt_p->pe_hdl,
886*00d0963fSdilpreet 		    pcie_ecap_ptr + PCIE_AER_UCE_MASK, mask);
887*00d0963fSdilpreet 	}
888*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_2PCI_DEV) {
889*00d0963fSdilpreet 		if (pcie_regs->pcie_adv_regs->pcie_adv_bdg_regs->pcie_sue_mask
890*00d0963fSdilpreet 		    != pcie_expected_sue_mask) {
891*00d0963fSdilpreet 			pci_config_put32(erpt_p->pe_hdl,
892*00d0963fSdilpreet 			    pcie_ecap_ptr + PCIE_AER_SUCE_MASK,
893*00d0963fSdilpreet 			    pcie_expected_sue_mask);
894*00d0963fSdilpreet 		}
895*00d0963fSdilpreet 	}
896*00d0963fSdilpreet }
897*00d0963fSdilpreet 
898*00d0963fSdilpreet /*
899*00d0963fSdilpreet  * pci_ereport_setup: Detect PCI device type and initialize structures to be
900*00d0963fSdilpreet  * used to generate ereports based on detected generic device errors.
901*00d0963fSdilpreet  */
902*00d0963fSdilpreet void
903*00d0963fSdilpreet pci_ereport_setup(dev_info_t *dip)
904*00d0963fSdilpreet {
905*00d0963fSdilpreet 	struct dev_info *devi = DEVI(dip);
906*00d0963fSdilpreet 	struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl;
907*00d0963fSdilpreet 	pci_erpt_t *erpt_p;
908*00d0963fSdilpreet 	uint8_t pci_hdr_type;
909*00d0963fSdilpreet 	uint16_t pci_status;
910*00d0963fSdilpreet 	pci_regspec_t *pci_rp;
911*00d0963fSdilpreet 	int32_t len;
912*00d0963fSdilpreet 	uint32_t phys_hi;
913*00d0963fSdilpreet 
914*00d0963fSdilpreet 	/*
915*00d0963fSdilpreet 	 * If device is not ereport capbable then report an error against the
916*00d0963fSdilpreet 	 * driver for using this interface,
917*00d0963fSdilpreet 	 */
918*00d0963fSdilpreet 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
919*00d0963fSdilpreet 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
920*00d0963fSdilpreet 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
921*00d0963fSdilpreet 		return;
922*00d0963fSdilpreet 	}
923*00d0963fSdilpreet 
924*00d0963fSdilpreet 	/*
925*00d0963fSdilpreet 	 * ASSERT fmhdl exists and fh_bus_specific is NULL.
926*00d0963fSdilpreet 	 */
927*00d0963fSdilpreet 	ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL));
928*00d0963fSdilpreet 
929*00d0963fSdilpreet 	erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP);
930*00d0963fSdilpreet 
931*00d0963fSdilpreet 	if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS)
932*00d0963fSdilpreet 		goto error;
933*00d0963fSdilpreet 
934*00d0963fSdilpreet 	erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP);
935*00d0963fSdilpreet 
936*00d0963fSdilpreet 	pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT);
937*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK)
938*00d0963fSdilpreet 		goto error;
939*00d0963fSdilpreet 
940*00d0963fSdilpreet 	/*
941*00d0963fSdilpreet 	 * Get header type and record if device is a bridge.
942*00d0963fSdilpreet 	 */
943*00d0963fSdilpreet 	pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER);
944*00d0963fSdilpreet 	if (pci_config_check(erpt_p->pe_hdl) != DDI_FM_OK)
945*00d0963fSdilpreet 		goto error;
946*00d0963fSdilpreet 
947*00d0963fSdilpreet 	/*
948*00d0963fSdilpreet 	 * Check to see if PCI device is a bridge, if so allocate pci bridge
949*00d0963fSdilpreet 	 * error register structure.
950*00d0963fSdilpreet 	 */
951*00d0963fSdilpreet 	if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
952*00d0963fSdilpreet 		erpt_p->pe_dflags |= PCI_BRIDGE_DEV;
953*00d0963fSdilpreet 		erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc(
954*00d0963fSdilpreet 		    sizeof (pci_bdg_error_regs_t), KM_SLEEP);
955*00d0963fSdilpreet 	}
956*00d0963fSdilpreet 
957*00d0963fSdilpreet 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
958*00d0963fSdilpreet 	    (caddr_t)&pci_rp, &len) == DDI_SUCCESS) {
959*00d0963fSdilpreet 		phys_hi = pci_rp->pci_phys_hi;
960*00d0963fSdilpreet 		kmem_free(pci_rp, len);
961*00d0963fSdilpreet 
962*00d0963fSdilpreet 		erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >>
963*00d0963fSdilpreet 		    PCI_REG_FUNC_SHIFT);
964*00d0963fSdilpreet 	}
965*00d0963fSdilpreet 
966*00d0963fSdilpreet 
967*00d0963fSdilpreet 	if (!(pci_status & PCI_STAT_CAP)) {
968*00d0963fSdilpreet 		goto done;
969*00d0963fSdilpreet 	}
970*00d0963fSdilpreet 
971*00d0963fSdilpreet 	/*
972*00d0963fSdilpreet 	 * Initialize structures for PCI Express and PCI-X devices.
973*00d0963fSdilpreet 	 * Order matters below and pcie_ereport_setup should preceed
974*00d0963fSdilpreet 	 * pcix_ereport_setup.
975*00d0963fSdilpreet 	 */
976*00d0963fSdilpreet 	pcie_ereport_setup(dip, erpt_p);
977*00d0963fSdilpreet 
978*00d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_DEV)) {
979*00d0963fSdilpreet 		pcix_ereport_setup(dip, erpt_p);
980*00d0963fSdilpreet 	}
981*00d0963fSdilpreet 
982*00d0963fSdilpreet done:
983*00d0963fSdilpreet 	pci_regs_gather(dip, erpt_p);
984*00d0963fSdilpreet 	pci_regs_clear(erpt_p);
985*00d0963fSdilpreet 
986*00d0963fSdilpreet 	/*
987*00d0963fSdilpreet 	 * Before returning set fh_bus_specific to completed pci_erpt_t
988*00d0963fSdilpreet 	 * structure
989*00d0963fSdilpreet 	 */
990*00d0963fSdilpreet 	fmhdl->fh_bus_specific = (void *)erpt_p;
991*00d0963fSdilpreet 
992*00d0963fSdilpreet 	return;
993*00d0963fSdilpreet error:
994*00d0963fSdilpreet 	if (erpt_p->pe_pci_regs)
995*00d0963fSdilpreet 		kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
996*00d0963fSdilpreet 	kmem_free(erpt_p, sizeof (pci_erpt_t));
997*00d0963fSdilpreet 	erpt_p = NULL;
998*00d0963fSdilpreet }
999*00d0963fSdilpreet 
1000*00d0963fSdilpreet static void
1001*00d0963fSdilpreet pcix_ereport_teardown(pci_erpt_t *erpt_p)
1002*00d0963fSdilpreet {
1003*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
1004*00d0963fSdilpreet 		pcix_bdg_error_regs_t *pcix_bdg_regs;
1005*00d0963fSdilpreet 		uint16_t pcix_ver;
1006*00d0963fSdilpreet 
1007*00d0963fSdilpreet 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
1008*00d0963fSdilpreet 		pcix_ver = pcix_bdg_regs->pcix_bdg_ver;
1009*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_ver)) {
1010*00d0963fSdilpreet 			int i;
1011*00d0963fSdilpreet 			for (i = 0; i < 2; i++)
1012*00d0963fSdilpreet 				kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i],
1013*00d0963fSdilpreet 				    sizeof (pcix_ecc_regs_t));
1014*00d0963fSdilpreet 		}
1015*00d0963fSdilpreet 		kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t));
1016*00d0963fSdilpreet 	} else {
1017*00d0963fSdilpreet 		pcix_error_regs_t *pcix_regs;
1018*00d0963fSdilpreet 		uint16_t pcix_ver;
1019*00d0963fSdilpreet 
1020*00d0963fSdilpreet 		pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
1021*00d0963fSdilpreet 		pcix_ver = pcix_regs->pcix_ver;
1022*00d0963fSdilpreet 		if (PCIX_ECC_VER_CHECK(pcix_ver)) {
1023*00d0963fSdilpreet 			kmem_free(pcix_regs->pcix_ecc_regs,
1024*00d0963fSdilpreet 			    sizeof (pcix_ecc_regs_t));
1025*00d0963fSdilpreet 		}
1026*00d0963fSdilpreet 		kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t));
1027*00d0963fSdilpreet 	}
1028*00d0963fSdilpreet }
1029*00d0963fSdilpreet 
1030*00d0963fSdilpreet static void
1031*00d0963fSdilpreet pcie_ereport_teardown(pci_erpt_t *erpt_p)
1032*00d0963fSdilpreet {
1033*00d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
1034*00d0963fSdilpreet 
1035*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_ADV_DEV) {
1036*00d0963fSdilpreet 		pcie_adv_error_regs_t *pcie_adv = pcie_regs->pcie_adv_regs;
1037*00d0963fSdilpreet 
1038*00d0963fSdilpreet 		if (erpt_p->pe_dflags & PCIEX_2PCI_DEV)
1039*00d0963fSdilpreet 			kmem_free(pcie_adv->pcie_adv_bdg_regs,
1040*00d0963fSdilpreet 			    sizeof (pcie_adv_bdg_error_regs_t));
1041*00d0963fSdilpreet 		if (erpt_p->pe_dflags & PCIEX_RC_DEV)
1042*00d0963fSdilpreet 			kmem_free(pcie_adv->pcie_adv_rc_regs,
1043*00d0963fSdilpreet 			    sizeof (pcie_adv_rc_error_regs_t));
1044*00d0963fSdilpreet 		kmem_free(pcie_adv, sizeof (pcie_adv_error_regs_t));
1045*00d0963fSdilpreet 	}
1046*00d0963fSdilpreet 
1047*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV)
1048*00d0963fSdilpreet 		kmem_free(pcie_regs->pcie_rc_regs,
1049*00d0963fSdilpreet 		    sizeof (pcie_rc_error_regs_t));
1050*00d0963fSdilpreet 
1051*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
1052*00d0963fSdilpreet 		if (erpt_p->pe_dflags & PCIX_DEV) {
1053*00d0963fSdilpreet 			uint16_t pcix_ver = pcie_regs->pcix_bdg_regs->
1054*00d0963fSdilpreet 			    pcix_bdg_ver;
1055*00d0963fSdilpreet 
1056*00d0963fSdilpreet 			if (PCIX_ECC_VER_CHECK(pcix_ver)) {
1057*00d0963fSdilpreet 				int i;
1058*00d0963fSdilpreet 				for (i = 0; i < 2; i++)
1059*00d0963fSdilpreet 					kmem_free(pcie_regs->pcix_bdg_regs->
1060*00d0963fSdilpreet 					    pcix_bdg_ecc_regs[i],
1061*00d0963fSdilpreet 					    sizeof (pcix_ecc_regs_t));
1062*00d0963fSdilpreet 			}
1063*00d0963fSdilpreet 			kmem_free(pcie_regs->pcix_bdg_regs,
1064*00d0963fSdilpreet 			    sizeof (pcix_bdg_error_regs_t));
1065*00d0963fSdilpreet 		}
1066*00d0963fSdilpreet 	}
1067*00d0963fSdilpreet 	kmem_free(erpt_p->pe_regs, sizeof (pcie_error_regs_t));
1068*00d0963fSdilpreet }
1069*00d0963fSdilpreet 
1070*00d0963fSdilpreet void
1071*00d0963fSdilpreet pci_ereport_teardown(dev_info_t *dip)
1072*00d0963fSdilpreet {
1073*00d0963fSdilpreet 	struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
1074*00d0963fSdilpreet 	pci_erpt_t *erpt_p;
1075*00d0963fSdilpreet 
1076*00d0963fSdilpreet 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
1077*00d0963fSdilpreet 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
1078*00d0963fSdilpreet 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
1079*00d0963fSdilpreet 	}
1080*00d0963fSdilpreet 
1081*00d0963fSdilpreet 	ASSERT(fmhdl);
1082*00d0963fSdilpreet 
1083*00d0963fSdilpreet 	erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
1084*00d0963fSdilpreet 	if (erpt_p == NULL)
1085*00d0963fSdilpreet 		return;
1086*00d0963fSdilpreet 
1087*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_DEV)
1088*00d0963fSdilpreet 		pcie_ereport_teardown(erpt_p);
1089*00d0963fSdilpreet 	else if (erpt_p->pe_dflags & PCIX_DEV)
1090*00d0963fSdilpreet 		pcix_ereport_teardown(erpt_p);
1091*00d0963fSdilpreet 	pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl);
1092*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV)
1093*00d0963fSdilpreet 		kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs,
1094*00d0963fSdilpreet 		    sizeof (pci_bdg_error_regs_t));
1095*00d0963fSdilpreet 	kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
1096*00d0963fSdilpreet 	kmem_free(erpt_p, sizeof (pci_erpt_t));
1097*00d0963fSdilpreet 	fmhdl->fh_bus_specific = NULL;
1098*00d0963fSdilpreet 	/*
1099*00d0963fSdilpreet 	 * The following sparc specific code should be removed once the pci_cap
1100*00d0963fSdilpreet 	 * interfaces create the necessary properties for us.
1101*00d0963fSdilpreet 	 */
1102*00d0963fSdilpreet #if defined(__sparc)
1103*00d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcix-capid-pointer");
1104*00d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-slotcap-reg");
1105*00d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-reg");
1106*00d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-capid-pointer");
1107*00d0963fSdilpreet 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "pcie-aer-pointer");
1108*00d0963fSdilpreet #endif
1109*00d0963fSdilpreet }
1110*00d0963fSdilpreet 
1111*00d0963fSdilpreet /*
1112*00d0963fSdilpreet  * Function used by PCI device and nexus error handlers to check if a
1113*00d0963fSdilpreet  * captured address resides in their DMA or ACC handle caches or the caches of
1114*00d0963fSdilpreet  * their children devices, respectively.
1115*00d0963fSdilpreet  */
1116*00d0963fSdilpreet static int
1117*00d0963fSdilpreet pci_dev_hdl_lookup(dev_info_t *dip, int type, ddi_fm_error_t *derr,
1118*00d0963fSdilpreet     void *addr)
1119*00d0963fSdilpreet {
1120*00d0963fSdilpreet 	struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
1121*00d0963fSdilpreet 	pci_erpt_t *erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
1122*00d0963fSdilpreet 
1123*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV)
1124*00d0963fSdilpreet 		return (ndi_fmc_error(dip, NULL, type, derr->fme_ena, addr));
1125*00d0963fSdilpreet 	else
1126*00d0963fSdilpreet 		return (ndi_fmc_entry_error(dip, type, derr, addr));
1127*00d0963fSdilpreet }
1128*00d0963fSdilpreet 
1129*00d0963fSdilpreet static void
1130*00d0963fSdilpreet pcie_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
1131*00d0963fSdilpreet     char *buf, int errtype)
1132*00d0963fSdilpreet {
1133*00d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
1134*00d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs;
1135*00d0963fSdilpreet 	pcie_adv_rc_error_regs_t *pcie_adv_rc_regs =
1136*00d0963fSdilpreet 	    pcie_adv_regs->pcie_adv_rc_regs;
1137*00d0963fSdilpreet 
1138*00d0963fSdilpreet 	switch (errtype) {
1139*00d0963fSdilpreet 	    case PCIEX_TYPE_CE:
1140*00d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1141*00d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1142*00d0963fSdilpreet 		    PCIEX_DEVSTS_REG, DATA_TYPE_UINT16,
1143*00d0963fSdilpreet 		    pcie_regs->pcie_err_status,
1144*00d0963fSdilpreet 		    PCIEX_CE_STATUS_REG, DATA_TYPE_UINT32,
1145*00d0963fSdilpreet 		    pcie_adv_regs->pcie_ce_status, NULL);
1146*00d0963fSdilpreet 		break;
1147*00d0963fSdilpreet 	    case PCIEX_TYPE_UE:
1148*00d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1149*00d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1150*00d0963fSdilpreet 		    PCIEX_DEVSTS_REG, DATA_TYPE_UINT16,
1151*00d0963fSdilpreet 		    pcie_regs->pcie_err_status,
1152*00d0963fSdilpreet 		    PCIEX_UE_STATUS_REG, DATA_TYPE_UINT32,
1153*00d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_status, PCIEX_UE_SEV_REG,
1154*00d0963fSdilpreet 		    DATA_TYPE_UINT32, pcie_adv_regs->pcie_ue_sev,
1155*00d0963fSdilpreet 		    PCIEX_ADV_CTL, DATA_TYPE_UINT32,
1156*00d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_ctl,
1157*00d0963fSdilpreet 		    PCIEX_SRC_ID, DATA_TYPE_UINT16,
1158*00d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_bdf,
1159*00d0963fSdilpreet 		    PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE,
1160*00d0963fSdilpreet 		    (pcie_adv_regs->pcie_adv_bdf != NULL) ?
1161*00d0963fSdilpreet 		    1 : NULL,
1162*00d0963fSdilpreet #ifdef DEBUG
1163*00d0963fSdilpreet 		    PCIEX_UE_HDR0, DATA_TYPE_UINT32,
1164*00d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_hdr0,
1165*00d0963fSdilpreet 		    PCIEX_UE_HDR1, DATA_TYPE_UINT32,
1166*00d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_hdr[0],
1167*00d0963fSdilpreet 		    PCIEX_UE_HDR2, DATA_TYPE_UINT32,
1168*00d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_hdr[1],
1169*00d0963fSdilpreet 		    PCIEX_UE_HDR3, DATA_TYPE_UINT32,
1170*00d0963fSdilpreet 		    pcie_adv_regs->pcie_ue_hdr[2],
1171*00d0963fSdilpreet #endif
1172*00d0963fSdilpreet 		    NULL);
1173*00d0963fSdilpreet 		break;
1174*00d0963fSdilpreet 	    case PCIEX_TYPE_GEN:
1175*00d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1176*00d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8,
1177*00d0963fSdilpreet 		    0, PCIEX_DEVSTS_REG, DATA_TYPE_UINT16,
1178*00d0963fSdilpreet 		    pcie_regs->pcie_err_status, NULL);
1179*00d0963fSdilpreet 		break;
1180*00d0963fSdilpreet 	    case PCIEX_TYPE_RC_UE_MSG:
1181*00d0963fSdilpreet 	    case PCIEX_TYPE_RC_CE_MSG:
1182*00d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1183*00d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1184*00d0963fSdilpreet 		    PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32,
1185*00d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_err_status,
1186*00d0963fSdilpreet 		    PCIEX_SRC_ID, DATA_TYPE_UINT16,
1187*00d0963fSdilpreet 		    (errtype == PCIEX_TYPE_RC_UE_MSG) ?
1188*00d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_ue_src_id :
1189*00d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_ce_src_id,
1190*00d0963fSdilpreet 		    PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE,
1191*00d0963fSdilpreet 		    (errtype == PCIEX_TYPE_RC_UE_MSG) ?
1192*00d0963fSdilpreet 		    (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID &&
1193*00d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_ue_src_id != 0) :
1194*00d0963fSdilpreet 		    (pcie_adv_regs->pcie_adv_vflags & PCIE_SRC_ID_VALID &&
1195*00d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_ce_src_id != 0), NULL);
1196*00d0963fSdilpreet 		break;
1197*00d0963fSdilpreet 	    case PCIEX_TYPE_RC_MULT_MSG:
1198*00d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1199*00d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1200*00d0963fSdilpreet 		    PCIEX_ROOT_ERRSTS_REG, DATA_TYPE_UINT32,
1201*00d0963fSdilpreet 		    pcie_adv_rc_regs->pcie_rc_err_status, NULL);
1202*00d0963fSdilpreet 		break;
1203*00d0963fSdilpreet 	    default:
1204*00d0963fSdilpreet 		break;
1205*00d0963fSdilpreet 	}
1206*00d0963fSdilpreet }
1207*00d0963fSdilpreet 
1208*00d0963fSdilpreet static void
1209*00d0963fSdilpreet pcie_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *eprt_p)
1210*00d0963fSdilpreet {
1211*00d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)eprt_p->pe_regs;
1212*00d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs;
1213*00d0963fSdilpreet 	pcie_tlp_hdr_t *ue_hdr0;
1214*00d0963fSdilpreet 	uint32_t *ue_hdr;
1215*00d0963fSdilpreet 	uint64_t addr = NULL;
1216*00d0963fSdilpreet 
1217*00d0963fSdilpreet 	if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_UE_HDR_VALID)) {
1218*00d0963fSdilpreet 		derr->fme_status = DDI_FM_UNKNOWN;
1219*00d0963fSdilpreet 		return;
1220*00d0963fSdilpreet 	}
1221*00d0963fSdilpreet 	ue_hdr0 = (pcie_tlp_hdr_t *)&pcie_adv_regs->pcie_ue_hdr0;
1222*00d0963fSdilpreet 	ue_hdr = pcie_adv_regs->pcie_ue_hdr;
1223*00d0963fSdilpreet 
1224*00d0963fSdilpreet 	switch (ue_hdr0->type) {
1225*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_MEM:
1226*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_MEMLK:
1227*00d0963fSdilpreet 		if ((ue_hdr0->fmt & 0x1) == 0x1) {
1228*00d0963fSdilpreet 			pcie_mem64_t *mem64_tlp = (pcie_mem64_t *)ue_hdr;
1229*00d0963fSdilpreet 
1230*00d0963fSdilpreet 			addr = (uint64_t)mem64_tlp->addr1 << 32 |
1231*00d0963fSdilpreet 			    (uint32_t)mem64_tlp->addr0 << 2;
1232*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = mem64_tlp->rid;
1233*00d0963fSdilpreet 		} else {
1234*00d0963fSdilpreet 			pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr;
1235*00d0963fSdilpreet 
1236*00d0963fSdilpreet 			addr = (uint32_t)memio32_tlp->addr0 << 2;
1237*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid;
1238*00d0963fSdilpreet 		}
1239*00d0963fSdilpreet 
1240*00d0963fSdilpreet 		derr->fme_status = pci_dev_hdl_lookup(dip, DMA_HANDLE, derr,
1241*00d0963fSdilpreet 		    (void *) &addr);
1242*00d0963fSdilpreet 		/*
1243*00d0963fSdilpreet 		 * If DMA handle is not found error could have been a memory
1244*00d0963fSdilpreet 		 * mapped IO address so check in the access cache
1245*00d0963fSdilpreet 		 */
1246*00d0963fSdilpreet 		if (derr->fme_status == DDI_FM_UNKNOWN)
1247*00d0963fSdilpreet 			derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE,
1248*00d0963fSdilpreet 			    derr, (void *) &addr);
1249*00d0963fSdilpreet 		break;
1250*00d0963fSdilpreet 
1251*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_IO:
1252*00d0963fSdilpreet 		{
1253*00d0963fSdilpreet 			pcie_memio32_t *memio32_tlp = (pcie_memio32_t *)ue_hdr;
1254*00d0963fSdilpreet 
1255*00d0963fSdilpreet 			addr = (uint32_t)memio32_tlp->addr0 << 2;
1256*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = memio32_tlp->rid;
1257*00d0963fSdilpreet 			derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE,
1258*00d0963fSdilpreet 			    derr, (void *) &addr);
1259*00d0963fSdilpreet 			break;
1260*00d0963fSdilpreet 		}
1261*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_CFG0:
1262*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_CFG1:
1263*00d0963fSdilpreet 		{
1264*00d0963fSdilpreet 			pcie_cfg_t *cfg_tlp = (pcie_cfg_t *)ue_hdr;
1265*00d0963fSdilpreet 
1266*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf =
1267*00d0963fSdilpreet 			    (uint16_t)cfg_tlp->bus << 8 |
1268*00d0963fSdilpreet 			    (uint16_t)cfg_tlp->dev << 3 | cfg_tlp->func;
1269*00d0963fSdilpreet 
1270*00d0963fSdilpreet 			derr->fme_status = DDI_FM_UNKNOWN;
1271*00d0963fSdilpreet 			break;
1272*00d0963fSdilpreet 		}
1273*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_MSG:
1274*00d0963fSdilpreet 		{
1275*00d0963fSdilpreet 			pcie_msg_t *msg_tlp = (pcie_msg_t *)ue_hdr;
1276*00d0963fSdilpreet 
1277*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = msg_tlp->rid;
1278*00d0963fSdilpreet 			derr->fme_status = DDI_FM_UNKNOWN;
1279*00d0963fSdilpreet 			break;
1280*00d0963fSdilpreet 		}
1281*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_CPL:
1282*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_CPLLK:
1283*00d0963fSdilpreet 		{
1284*00d0963fSdilpreet 			pcie_cpl_t *cpl_tlp = (pcie_cpl_t *)ue_hdr;
1285*00d0963fSdilpreet 
1286*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = cpl_tlp->cid;
1287*00d0963fSdilpreet 			derr->fme_status = DDI_FM_UNKNOWN;
1288*00d0963fSdilpreet 			break;
1289*00d0963fSdilpreet 		}
1290*00d0963fSdilpreet 	    case PCIE_TLP_TYPE_MSI:
1291*00d0963fSdilpreet 	    default:
1292*00d0963fSdilpreet 		derr->fme_status = DDI_FM_UNKNOWN;
1293*00d0963fSdilpreet 	}
1294*00d0963fSdilpreet 
1295*00d0963fSdilpreet 	/*
1296*00d0963fSdilpreet 	 * If no handle was found in the children caches and their is no
1297*00d0963fSdilpreet 	 * address infomation already stored and we have a captured address
1298*00d0963fSdilpreet 	 * then we need to store it away so that intermediate bridges can
1299*00d0963fSdilpreet 	 * check if the address exists in their handle caches.
1300*00d0963fSdilpreet 	 */
1301*00d0963fSdilpreet 	if (derr->fme_status == DDI_FM_UNKNOWN &&
1302*00d0963fSdilpreet 	    derr->fme_bus_specific == NULL &&
1303*00d0963fSdilpreet 	    addr != NULL)
1304*00d0963fSdilpreet 		derr->fme_bus_specific = (void *)(uintptr_t)addr;
1305*00d0963fSdilpreet }
1306*00d0963fSdilpreet 
1307*00d0963fSdilpreet static void
1308*00d0963fSdilpreet pcie_pci_check_addr(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *eprt_p)
1309*00d0963fSdilpreet {
1310*00d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)eprt_p->pe_regs;
1311*00d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs = pcie_regs->pcie_adv_regs;
1312*00d0963fSdilpreet 	pcie_adv_bdg_error_regs_t *pcie_bdg_regs =
1313*00d0963fSdilpreet 	    pcie_adv_regs->pcie_adv_bdg_regs;
1314*00d0963fSdilpreet 	uint64_t addr = NULL;
1315*00d0963fSdilpreet 	pcix_attr_t *pcie_pci_sue_attr;
1316*00d0963fSdilpreet 	int cmd;
1317*00d0963fSdilpreet 	int dual_addr = 0;
1318*00d0963fSdilpreet 
1319*00d0963fSdilpreet 	if (!(pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_HDR_VALID)) {
1320*00d0963fSdilpreet 		derr->fme_status = DDI_FM_UNKNOWN;
1321*00d0963fSdilpreet 		return;
1322*00d0963fSdilpreet 	}
1323*00d0963fSdilpreet 
1324*00d0963fSdilpreet 	pcie_pci_sue_attr = (pcix_attr_t *)&pcie_bdg_regs->pcie_sue_hdr0;
1325*00d0963fSdilpreet 	cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >>
1326*00d0963fSdilpreet 	    PCIE_AER_SUCE_HDR_CMD_LWR_SHIFT) & PCIE_AER_SUCE_HDR_CMD_LWR_MASK;
1327*00d0963fSdilpreet cmd_switch:
1328*00d0963fSdilpreet 	switch (cmd) {
1329*00d0963fSdilpreet 	    case PCI_PCIX_CMD_IORD:
1330*00d0963fSdilpreet 	    case PCI_PCIX_CMD_IOWR:
1331*00d0963fSdilpreet 		pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid;
1332*00d0963fSdilpreet 
1333*00d0963fSdilpreet 		addr = pcie_bdg_regs->pcie_sue_hdr[2];
1334*00d0963fSdilpreet 		addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) |
1335*00d0963fSdilpreet 		    pcie_bdg_regs->pcie_sue_hdr[1];
1336*00d0963fSdilpreet 
1337*00d0963fSdilpreet 		derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE,
1338*00d0963fSdilpreet 		    derr, (void *) &addr);
1339*00d0963fSdilpreet 		break;
1340*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRD_DW:
1341*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWR:
1342*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRD_BL:
1343*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWR_BL:
1344*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRDBL:
1345*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWRBL:
1346*00d0963fSdilpreet 		pcie_adv_regs->pcie_adv_bdf = pcie_pci_sue_attr->rid;
1347*00d0963fSdilpreet 
1348*00d0963fSdilpreet 		addr = pcie_bdg_regs->pcie_sue_hdr[2];
1349*00d0963fSdilpreet 		addr = (addr << PCIE_AER_SUCE_HDR_ADDR_SHIFT) |
1350*00d0963fSdilpreet 		    pcie_bdg_regs->pcie_sue_hdr[1];
1351*00d0963fSdilpreet 
1352*00d0963fSdilpreet 		derr->fme_status = pci_dev_hdl_lookup(dip, DMA_HANDLE,
1353*00d0963fSdilpreet 		    derr, (void *) &addr);
1354*00d0963fSdilpreet 		if (derr->fme_status == DDI_FM_UNKNOWN)
1355*00d0963fSdilpreet 			derr->fme_status = pci_dev_hdl_lookup(dip, ACC_HANDLE,
1356*00d0963fSdilpreet 			    derr, (void *) &addr);
1357*00d0963fSdilpreet 		break;
1358*00d0963fSdilpreet 	    case PCI_PCIX_CMD_CFRD:
1359*00d0963fSdilpreet 	    case PCI_PCIX_CMD_CFWR:
1360*00d0963fSdilpreet 		/*
1361*00d0963fSdilpreet 		 * If we want to store the bdf of the device being addressed we
1362*00d0963fSdilpreet 		 * will need to do some surgery
1363*00d0963fSdilpreet 		 */
1364*00d0963fSdilpreet 		derr->fme_status = DDI_FM_UNKNOWN;
1365*00d0963fSdilpreet 		break;
1366*00d0963fSdilpreet 	    case PCI_PCIX_CMD_DADR:
1367*00d0963fSdilpreet 		cmd = (pcie_bdg_regs->pcie_sue_hdr[0] >>
1368*00d0963fSdilpreet 		    PCIE_AER_SUCE_HDR_CMD_UP_SHIFT) &
1369*00d0963fSdilpreet 		    PCIE_AER_SUCE_HDR_CMD_UP_MASK;
1370*00d0963fSdilpreet 		if (dual_addr)
1371*00d0963fSdilpreet 			break;
1372*00d0963fSdilpreet 		++dual_addr;
1373*00d0963fSdilpreet 		goto cmd_switch;
1374*00d0963fSdilpreet 	    default:
1375*00d0963fSdilpreet 		derr->fme_status = DDI_FM_UNKNOWN;
1376*00d0963fSdilpreet 	}
1377*00d0963fSdilpreet 
1378*00d0963fSdilpreet 	/*
1379*00d0963fSdilpreet 	 * If no handle was found in the children caches and their is no
1380*00d0963fSdilpreet 	 * address infomation already stored and we have a captured address
1381*00d0963fSdilpreet 	 * then we need to store it away so that intermediate bridges can
1382*00d0963fSdilpreet 	 * check if the address exists in their handle caches.
1383*00d0963fSdilpreet 	 */
1384*00d0963fSdilpreet 	if (derr->fme_status == DDI_FM_UNKNOWN &&
1385*00d0963fSdilpreet 	    derr->fme_bus_specific == NULL &&
1386*00d0963fSdilpreet 	    addr != NULL)
1387*00d0963fSdilpreet 		derr->fme_bus_specific = (void *)(uintptr_t)addr;
1388*00d0963fSdilpreet }
1389*00d0963fSdilpreet 
1390*00d0963fSdilpreet static int
1391*00d0963fSdilpreet pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr,
1392*00d0963fSdilpreet     pcix_ecc_regs_t *pcix_ecc_regs)
1393*00d0963fSdilpreet {
1394*00d0963fSdilpreet 	int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf;
1395*00d0963fSdilpreet 	uint64_t addr;
1396*00d0963fSdilpreet 
1397*00d0963fSdilpreet 	addr = pcix_ecc_regs->pcix_ecc_secaddr;
1398*00d0963fSdilpreet 	addr = addr << 32;
1399*00d0963fSdilpreet 	addr |= pcix_ecc_regs->pcix_ecc_fstaddr;
1400*00d0963fSdilpreet 
1401*00d0963fSdilpreet 	switch (cmd) {
1402*00d0963fSdilpreet 	    case PCI_PCIX_CMD_INTR:
1403*00d0963fSdilpreet 	    case PCI_PCIX_CMD_SPEC:
1404*00d0963fSdilpreet 		return (DDI_FM_FATAL);
1405*00d0963fSdilpreet 	    case PCI_PCIX_CMD_IORD:
1406*00d0963fSdilpreet 	    case PCI_PCIX_CMD_IOWR:
1407*00d0963fSdilpreet 		return (pci_dev_hdl_lookup(dip, ACC_HANDLE, derr,
1408*00d0963fSdilpreet 		    (void *) &addr));
1409*00d0963fSdilpreet 	    case PCI_PCIX_CMD_DEVID:
1410*00d0963fSdilpreet 		return (DDI_FM_FATAL);
1411*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRD_DW:
1412*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWR:
1413*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRD_BL:
1414*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWR_BL:
1415*00d0963fSdilpreet 		return (pci_dev_hdl_lookup(dip, DMA_HANDLE, derr,
1416*00d0963fSdilpreet 		    (void *) &addr));
1417*00d0963fSdilpreet 	    case PCI_PCIX_CMD_CFRD:
1418*00d0963fSdilpreet 	    case PCI_PCIX_CMD_CFWR:
1419*00d0963fSdilpreet 		return (pci_dev_hdl_lookup(dip, ACC_HANDLE, derr,
1420*00d0963fSdilpreet 		    (void *) &addr));
1421*00d0963fSdilpreet 	    case PCI_PCIX_CMD_SPL:
1422*00d0963fSdilpreet 	    case PCI_PCIX_CMD_DADR:
1423*00d0963fSdilpreet 		return (DDI_FM_FATAL);
1424*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMRDBL:
1425*00d0963fSdilpreet 	    case PCI_PCIX_CMD_MEMWRBL:
1426*00d0963fSdilpreet 		return (pci_dev_hdl_lookup(dip, DMA_HANDLE, derr,
1427*00d0963fSdilpreet 		    (void *) &addr));
1428*00d0963fSdilpreet 	    default:
1429*00d0963fSdilpreet 		return (DDI_FM_FATAL);
1430*00d0963fSdilpreet 	}
1431*00d0963fSdilpreet }
1432*00d0963fSdilpreet 
1433*00d0963fSdilpreet /*ARGSUSED*/
1434*00d0963fSdilpreet static int
1435*00d0963fSdilpreet pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
1436*00d0963fSdilpreet {
1437*00d0963fSdilpreet 	pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs;
1438*00d0963fSdilpreet 	int fatal = 0;
1439*00d0963fSdilpreet 	int nonfatal = 0;
1440*00d0963fSdilpreet 	int unknown = 0;
1441*00d0963fSdilpreet 	int ok = 0;
1442*00d0963fSdilpreet 	int ret = DDI_FM_OK;
1443*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
1444*00d0963fSdilpreet 	int i;
1445*00d0963fSdilpreet 
1446*00d0963fSdilpreet 	if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED)
1447*00d0963fSdilpreet 		goto done;
1448*00d0963fSdilpreet 
1449*00d0963fSdilpreet 	if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) &&
1450*00d0963fSdilpreet 	    (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) {
1451*00d0963fSdilpreet 		(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
1452*00d0963fSdilpreet 		    PCI_ERROR_SUBCLASS, PCI_DTO);
1453*00d0963fSdilpreet 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1454*00d0963fSdilpreet 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1455*00d0963fSdilpreet 		    PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
1456*00d0963fSdilpreet 		    pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
1457*00d0963fSdilpreet 		    DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL);
1458*00d0963fSdilpreet 		unknown++;
1459*00d0963fSdilpreet 	}
1460*00d0963fSdilpreet 
1461*00d0963fSdilpreet 	if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) {
1462*00d0963fSdilpreet 		for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) {
1463*00d0963fSdilpreet 			if (pci_bdg_regs->pci_bdg_sec_stat &
1464*00d0963fSdilpreet 			    pci_bdg_err_tbl[i].reg_bit) {
1465*00d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s",
1466*00d0963fSdilpreet 				    PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS,
1467*00d0963fSdilpreet 				    pci_bdg_err_tbl[i].err_class);
1468*00d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1469*00d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1470*00d0963fSdilpreet 				    PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
1471*00d0963fSdilpreet 				    pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
1472*00d0963fSdilpreet 				    DATA_TYPE_UINT16,
1473*00d0963fSdilpreet 				    pci_bdg_regs->pci_bdg_ctrl, NULL);
1474*00d0963fSdilpreet 				/*
1475*00d0963fSdilpreet 				 * Increment severity based on flag if bridge
1476*00d0963fSdilpreet 				 * is PCI or PCI-X, if PCI Express and this is a
1477*00d0963fSdilpreet 				 * master abort then treat as nonfatal.
1478*00d0963fSdilpreet 				 * XXFM May need to check if all other errors
1479*00d0963fSdilpreet 				 * are related to MA?
1480*00d0963fSdilpreet 				 */
1481*00d0963fSdilpreet 				if (!(erpt_p->pe_dflags & PCIEX_DEV)) {
1482*00d0963fSdilpreet 					PCI_FM_SEV_INC(
1483*00d0963fSdilpreet 					    pci_bdg_err_tbl[i].flags);
1484*00d0963fSdilpreet 				} else if (pci_bdg_err_tbl[i].reg_bit ==
1485*00d0963fSdilpreet 				    PCI_STAT_R_MAST_AB) {
1486*00d0963fSdilpreet 					nonfatal++;
1487*00d0963fSdilpreet 				}
1488*00d0963fSdilpreet 
1489*00d0963fSdilpreet 				if (derr->fme_bus_specific &&
1490*00d0963fSdilpreet 				    pci_bdg_err_tbl[i].terr_class)
1491*00d0963fSdilpreet 					pci_target_enqueue(derr->fme_ena,
1492*00d0963fSdilpreet 					    pci_bdg_err_tbl[i].terr_class,
1493*00d0963fSdilpreet 					    PCI_ERROR_SUBCLASS,
1494*00d0963fSdilpreet 					    (uintptr_t)derr->fme_bus_specific);
1495*00d0963fSdilpreet 			}
1496*00d0963fSdilpreet 		}
1497*00d0963fSdilpreet 	}
1498*00d0963fSdilpreet 
1499*00d0963fSdilpreet done:
1500*00d0963fSdilpreet 
1501*00d0963fSdilpreet 	/*
1502*00d0963fSdilpreet 	 * Need to check for poke and cautious put. We already know peek
1503*00d0963fSdilpreet 	 * and cautious get errors occurred (as we got a trap) and we know
1504*00d0963fSdilpreet 	 * they are nonfatal.
1505*00d0963fSdilpreet 	 */
1506*00d0963fSdilpreet 	if (derr->fme_flag == DDI_FM_ERR_EXPECTED) {
1507*00d0963fSdilpreet 		/*
1508*00d0963fSdilpreet 		 * for cautious puts we treat all errors as nonfatal. Actually
1509*00d0963fSdilpreet 		 * we set nonfatal for cautious gets as well - doesn't do any
1510*00d0963fSdilpreet 		 * harm
1511*00d0963fSdilpreet 		 */
1512*00d0963fSdilpreet 		if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
1513*00d0963fSdilpreet 		    PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR))
1514*00d0963fSdilpreet 			nonfatal++;
1515*00d0963fSdilpreet 
1516*00d0963fSdilpreet 		/*
1517*00d0963fSdilpreet 		 * for cautious accesses we already have the acc_handle. Just
1518*00d0963fSdilpreet 		 * need to call children to clear their error bits
1519*00d0963fSdilpreet 		 */
1520*00d0963fSdilpreet 		ret = ndi_fm_handler_dispatch(dip, NULL, derr);
1521*00d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
1522*00d0963fSdilpreet 		return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
1523*00d0963fSdilpreet 		    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
1524*00d0963fSdilpreet 	}
1525*00d0963fSdilpreet 	if (derr->fme_flag == DDI_FM_ERR_POKE) {
1526*00d0963fSdilpreet 		/*
1527*00d0963fSdilpreet 		 * special case for pokes - we only consider master abort
1528*00d0963fSdilpreet 		 * and target abort as nonfatal. Sserr with no master abort is
1529*00d0963fSdilpreet 		 * fatal, but master/target abort can come in on separate
1530*00d0963fSdilpreet 		 * instance, so return unknown and parent will determine if
1531*00d0963fSdilpreet 		 * nonfatal (if another child returned nonfatal - ie master
1532*00d0963fSdilpreet 		 * or target abort) or fatal otherwise
1533*00d0963fSdilpreet 		 */
1534*00d0963fSdilpreet 		if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
1535*00d0963fSdilpreet 		    PCI_STAT_R_MAST_AB))
1536*00d0963fSdilpreet 			nonfatal++;
1537*00d0963fSdilpreet 		if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR)
1538*00d0963fSdilpreet 			unknown++;
1539*00d0963fSdilpreet 	}
1540*00d0963fSdilpreet 
1541*00d0963fSdilpreet 	/*
1542*00d0963fSdilpreet 	 * If errant address is passed in then attempt to find
1543*00d0963fSdilpreet 	 * ACC/DMA handle in caches.
1544*00d0963fSdilpreet 	 */
1545*00d0963fSdilpreet 	if (derr->fme_bus_specific) {
1546*00d0963fSdilpreet 		int i;
1547*00d0963fSdilpreet 
1548*00d0963fSdilpreet 		for (i = 0; i < 2; i++) {
1549*00d0963fSdilpreet 			ret = ndi_fmc_error(dip, NULL, i ? ACC_HANDLE :
1550*00d0963fSdilpreet 			    DMA_HANDLE, derr->fme_ena,
1551*00d0963fSdilpreet 			    (void *)&derr->fme_bus_specific);
1552*00d0963fSdilpreet 			PCI_FM_SEV_INC(ret);
1553*00d0963fSdilpreet 		}
1554*00d0963fSdilpreet 	}
1555*00d0963fSdilpreet 
1556*00d0963fSdilpreet 	/*
1557*00d0963fSdilpreet 	 * now check children below the bridge, only if errant handle was not
1558*00d0963fSdilpreet 	 * found
1559*00d0963fSdilpreet 	 */
1560*00d0963fSdilpreet 	if (!derr->fme_acc_handle && !derr->fme_dma_handle) {
1561*00d0963fSdilpreet 		ret = ndi_fm_handler_dispatch(dip, NULL, derr);
1562*00d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
1563*00d0963fSdilpreet 	}
1564*00d0963fSdilpreet 
1565*00d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
1566*00d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
1567*00d0963fSdilpreet }
1568*00d0963fSdilpreet 
1569*00d0963fSdilpreet static int
1570*00d0963fSdilpreet pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
1571*00d0963fSdilpreet     void *pe_regs)
1572*00d0963fSdilpreet {
1573*00d0963fSdilpreet 	pcix_error_regs_t *pcix_regs;
1574*00d0963fSdilpreet 	pcix_bdg_error_regs_t *pcix_bdg_regs;
1575*00d0963fSdilpreet 	pcix_ecc_regs_t *pcix_ecc_regs;
1576*00d0963fSdilpreet 	int bridge;
1577*00d0963fSdilpreet 	int i;
1578*00d0963fSdilpreet 	int ecc_phase;
1579*00d0963fSdilpreet 	int ecc_corr;
1580*00d0963fSdilpreet 	int sec_ue;
1581*00d0963fSdilpreet 	int sec_ce;
1582*00d0963fSdilpreet 	int fatal = 0;
1583*00d0963fSdilpreet 	int nonfatal = 0;
1584*00d0963fSdilpreet 	int unknown = 0;
1585*00d0963fSdilpreet 	int ok = 0;
1586*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
1587*00d0963fSdilpreet 
1588*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
1589*00d0963fSdilpreet 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
1590*00d0963fSdilpreet 		bridge = 1;
1591*00d0963fSdilpreet 	} else {
1592*00d0963fSdilpreet 		pcix_regs = (pcix_error_regs_t *)pe_regs;
1593*00d0963fSdilpreet 		bridge = 0;
1594*00d0963fSdilpreet 	}
1595*00d0963fSdilpreet 
1596*00d0963fSdilpreet 	for (i = 0; i < (bridge ? 2 : 1); i++) {
1597*00d0963fSdilpreet 		int ret = DDI_FM_OK;
1598*00d0963fSdilpreet 		pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] :
1599*00d0963fSdilpreet 		    pcix_regs->pcix_ecc_regs;
1600*00d0963fSdilpreet 		if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) {
1601*00d0963fSdilpreet 			ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat &
1602*00d0963fSdilpreet 			    PCI_PCIX_ECC_PHASE) >> 0x4;
1603*00d0963fSdilpreet 			ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat &
1604*00d0963fSdilpreet 			    PCI_PCIX_ECC_CORR);
1605*00d0963fSdilpreet 			sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat &
1606*00d0963fSdilpreet 			    PCI_PCIX_ECC_S_UE);
1607*00d0963fSdilpreet 			sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat &
1608*00d0963fSdilpreet 			    PCI_PCIX_ECC_S_CE);
1609*00d0963fSdilpreet 
1610*00d0963fSdilpreet 			switch (ecc_phase) {
1611*00d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_NOERR:
1612*00d0963fSdilpreet 				break;
1613*00d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_FADDR:
1614*00d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_SADDR:
1615*00d0963fSdilpreet 				PCI_FM_SEV_INC(ecc_corr ?  DDI_FM_NONFATAL :
1616*00d0963fSdilpreet 				    DDI_FM_FATAL);
1617*00d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS,
1618*00d0963fSdilpreet 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
1619*00d0963fSdilpreet 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
1620*00d0963fSdilpreet 				    ecc_corr ? PCIX_ECC_CE_ADDR :
1621*00d0963fSdilpreet 				    PCIX_ECC_UE_ADDR);
1622*00d0963fSdilpreet 				break;
1623*00d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_ATTR:
1624*00d0963fSdilpreet 				PCI_FM_SEV_INC(ecc_corr ?
1625*00d0963fSdilpreet 				    DDI_FM_NONFATAL : DDI_FM_FATAL);
1626*00d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS,
1627*00d0963fSdilpreet 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
1628*00d0963fSdilpreet 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
1629*00d0963fSdilpreet 				    ecc_corr ? PCIX_ECC_CE_ATTR :
1630*00d0963fSdilpreet 				    PCIX_ECC_UE_ATTR);
1631*00d0963fSdilpreet 				break;
1632*00d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_DATA32:
1633*00d0963fSdilpreet 			    case PCI_PCIX_ECC_PHASE_DATA64:
1634*00d0963fSdilpreet 				if (ecc_corr)
1635*00d0963fSdilpreet 					ret = DDI_FM_NONFATAL;
1636*00d0963fSdilpreet 				else
1637*00d0963fSdilpreet 					ret = pcix_check_addr(dip, derr,
1638*00d0963fSdilpreet 					    pcix_ecc_regs);
1639*00d0963fSdilpreet 				PCI_FM_SEV_INC(ret);
1640*00d0963fSdilpreet 
1641*00d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS,
1642*00d0963fSdilpreet 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
1643*00d0963fSdilpreet 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
1644*00d0963fSdilpreet 				    ecc_corr ? PCIX_ECC_CE_DATA :
1645*00d0963fSdilpreet 				    PCIX_ECC_UE_DATA);
1646*00d0963fSdilpreet 				break;
1647*00d0963fSdilpreet 			}
1648*00d0963fSdilpreet 			if (ecc_phase)
1649*00d0963fSdilpreet 				if (bridge)
1650*00d0963fSdilpreet 					ddi_fm_ereport_post(dip, buf,
1651*00d0963fSdilpreet 					    derr->fme_ena,
1652*00d0963fSdilpreet 					    DDI_NOSLEEP, FM_VERSION,
1653*00d0963fSdilpreet 					    DATA_TYPE_UINT8, 0,
1654*00d0963fSdilpreet 					    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
1655*00d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_sec_stat,
1656*00d0963fSdilpreet 					    PCIX_BDG_STAT, DATA_TYPE_UINT32,
1657*00d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_stat,
1658*00d0963fSdilpreet 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
1659*00d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_ctlstat,
1660*00d0963fSdilpreet 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
1661*00d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
1662*00d0963fSdilpreet 				else
1663*00d0963fSdilpreet 					ddi_fm_ereport_post(dip, buf,
1664*00d0963fSdilpreet 					    derr->fme_ena,
1665*00d0963fSdilpreet 					    DDI_NOSLEEP, FM_VERSION,
1666*00d0963fSdilpreet 					    DATA_TYPE_UINT8, 0,
1667*00d0963fSdilpreet 					    PCIX_COMMAND, DATA_TYPE_UINT16,
1668*00d0963fSdilpreet 					    pcix_regs->pcix_command,
1669*00d0963fSdilpreet 					    PCIX_STATUS, DATA_TYPE_UINT32,
1670*00d0963fSdilpreet 					    pcix_regs->pcix_status,
1671*00d0963fSdilpreet 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
1672*00d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_ctlstat,
1673*00d0963fSdilpreet 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
1674*00d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
1675*00d0963fSdilpreet 			if (sec_ce || sec_ue) {
1676*00d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS,
1677*00d0963fSdilpreet 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
1678*00d0963fSdilpreet 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
1679*00d0963fSdilpreet 				    sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE);
1680*00d0963fSdilpreet 				if (bridge)
1681*00d0963fSdilpreet 					ddi_fm_ereport_post(dip, buf,
1682*00d0963fSdilpreet 					    derr->fme_ena,
1683*00d0963fSdilpreet 					    DDI_NOSLEEP, FM_VERSION,
1684*00d0963fSdilpreet 					    DATA_TYPE_UINT8, 0,
1685*00d0963fSdilpreet 					    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
1686*00d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_sec_stat,
1687*00d0963fSdilpreet 					    PCIX_BDG_STAT, DATA_TYPE_UINT32,
1688*00d0963fSdilpreet 					    pcix_bdg_regs->pcix_bdg_stat,
1689*00d0963fSdilpreet 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
1690*00d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_ctlstat,
1691*00d0963fSdilpreet 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
1692*00d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
1693*00d0963fSdilpreet 				else
1694*00d0963fSdilpreet 					ddi_fm_ereport_post(dip, buf,
1695*00d0963fSdilpreet 					    derr->fme_ena,
1696*00d0963fSdilpreet 					    DDI_NOSLEEP, FM_VERSION,
1697*00d0963fSdilpreet 					    DATA_TYPE_UINT8, 0,
1698*00d0963fSdilpreet 					    PCIX_COMMAND, DATA_TYPE_UINT16,
1699*00d0963fSdilpreet 					    pcix_regs->pcix_command,
1700*00d0963fSdilpreet 					    PCIX_STATUS, DATA_TYPE_UINT32,
1701*00d0963fSdilpreet 					    pcix_regs->pcix_status,
1702*00d0963fSdilpreet 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
1703*00d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_ctlstat,
1704*00d0963fSdilpreet 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
1705*00d0963fSdilpreet 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
1706*00d0963fSdilpreet 				PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL :
1707*00d0963fSdilpreet 				    DDI_FM_NONFATAL);
1708*00d0963fSdilpreet 			}
1709*00d0963fSdilpreet 		}
1710*00d0963fSdilpreet 	}
1711*00d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
1712*00d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
1713*00d0963fSdilpreet }
1714*00d0963fSdilpreet 
1715*00d0963fSdilpreet static int
1716*00d0963fSdilpreet pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
1717*00d0963fSdilpreet     void *pe_regs)
1718*00d0963fSdilpreet {
1719*00d0963fSdilpreet 	pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
1720*00d0963fSdilpreet 	int fatal = 0;
1721*00d0963fSdilpreet 	int nonfatal = 0;
1722*00d0963fSdilpreet 	int unknown = 0;
1723*00d0963fSdilpreet 	int ok = 0;
1724*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
1725*00d0963fSdilpreet 	int i;
1726*00d0963fSdilpreet 
1727*00d0963fSdilpreet 	if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) {
1728*00d0963fSdilpreet 		for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
1729*00d0963fSdilpreet 			if ((pcix_bdg_regs->pcix_bdg_stat &
1730*00d0963fSdilpreet 			    pcix_err_tbl[i].reg_bit)) {
1731*00d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
1732*00d0963fSdilpreet 				    PCIX_ERROR_SUBCLASS,
1733*00d0963fSdilpreet 				    pcix_err_tbl[i].err_class);
1734*00d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1735*00d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1736*00d0963fSdilpreet 				    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
1737*00d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_sec_stat,
1738*00d0963fSdilpreet 				    PCIX_BDG_STAT, DATA_TYPE_UINT32,
1739*00d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_stat, NULL);
1740*00d0963fSdilpreet 				PCI_FM_SEV_INC(pcix_err_tbl[i].flags);
1741*00d0963fSdilpreet 			}
1742*00d0963fSdilpreet 		}
1743*00d0963fSdilpreet 	}
1744*00d0963fSdilpreet 
1745*00d0963fSdilpreet 	if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) {
1746*00d0963fSdilpreet 		for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) {
1747*00d0963fSdilpreet 			if ((pcix_bdg_regs->pcix_bdg_sec_stat &
1748*00d0963fSdilpreet 			    pcix_sec_err_tbl[i].reg_bit)) {
1749*00d0963fSdilpreet 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s",
1750*00d0963fSdilpreet 				    PCIX_ERROR_SUBCLASS,
1751*00d0963fSdilpreet 				    PCIX_SEC_ERROR_SUBCLASS,
1752*00d0963fSdilpreet 				    pcix_sec_err_tbl[i].err_class);
1753*00d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1754*00d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1755*00d0963fSdilpreet 				    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
1756*00d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_sec_stat,
1757*00d0963fSdilpreet 				    PCIX_BDG_STAT, DATA_TYPE_UINT32,
1758*00d0963fSdilpreet 				    pcix_bdg_regs->pcix_bdg_stat, NULL);
1759*00d0963fSdilpreet 				PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags);
1760*00d0963fSdilpreet 			}
1761*00d0963fSdilpreet 		}
1762*00d0963fSdilpreet 	}
1763*00d0963fSdilpreet 
1764*00d0963fSdilpreet 	/* Log/Handle ECC errors */
1765*00d0963fSdilpreet 	if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
1766*00d0963fSdilpreet 		int ret;
1767*00d0963fSdilpreet 
1768*00d0963fSdilpreet 		ret = pcix_ecc_error_report(dip, derr, erpt_p,
1769*00d0963fSdilpreet 		    (void *)pcix_bdg_regs);
1770*00d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
1771*00d0963fSdilpreet 	}
1772*00d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
1773*00d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
1774*00d0963fSdilpreet }
1775*00d0963fSdilpreet 
1776*00d0963fSdilpreet static int
1777*00d0963fSdilpreet pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
1778*00d0963fSdilpreet {
1779*00d0963fSdilpreet 	pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
1780*00d0963fSdilpreet 	int fatal = 0;
1781*00d0963fSdilpreet 	int nonfatal = 0;
1782*00d0963fSdilpreet 	int unknown = 0;
1783*00d0963fSdilpreet 	int ok = 0;
1784*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
1785*00d0963fSdilpreet 	int i;
1786*00d0963fSdilpreet 
1787*00d0963fSdilpreet 	if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) {
1788*00d0963fSdilpreet 		for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
1789*00d0963fSdilpreet 			if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit))
1790*00d0963fSdilpreet 				continue;
1791*00d0963fSdilpreet 
1792*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
1793*00d0963fSdilpreet 			    PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class);
1794*00d0963fSdilpreet 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
1795*00d0963fSdilpreet 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
1796*00d0963fSdilpreet 			    PCIX_COMMAND, DATA_TYPE_UINT16,
1797*00d0963fSdilpreet 			    pcix_regs->pcix_command, PCIX_STATUS,
1798*00d0963fSdilpreet 			    DATA_TYPE_UINT32, pcix_regs->pcix_status,
1799*00d0963fSdilpreet 			    NULL);
1800*00d0963fSdilpreet 			PCI_FM_SEV_INC(pcix_err_tbl[i].flags);
1801*00d0963fSdilpreet 		}
1802*00d0963fSdilpreet 	}
1803*00d0963fSdilpreet 	/* Log/Handle ECC errors */
1804*00d0963fSdilpreet 	if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
1805*00d0963fSdilpreet 		int ret = pcix_ecc_error_report(dip, derr, erpt_p,
1806*00d0963fSdilpreet 		    (void *)pcix_regs);
1807*00d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
1808*00d0963fSdilpreet 	}
1809*00d0963fSdilpreet 
1810*00d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
1811*00d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
1812*00d0963fSdilpreet }
1813*00d0963fSdilpreet 
1814*00d0963fSdilpreet static int
1815*00d0963fSdilpreet pcie_rc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
1816*00d0963fSdilpreet     void *pe_regs)
1817*00d0963fSdilpreet {
1818*00d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs = (pcie_adv_error_regs_t *)pe_regs;
1819*00d0963fSdilpreet 	int fatal = 0;
1820*00d0963fSdilpreet 	int nonfatal = 0;
1821*00d0963fSdilpreet 	int unknown = 0;
1822*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
1823*00d0963fSdilpreet 
1824*00d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_RC_ERR_STATUS_VALID) {
1825*00d0963fSdilpreet 		pcie_adv_rc_error_regs_t *pcie_rc_regs =
1826*00d0963fSdilpreet 		    pcie_adv_regs->pcie_adv_rc_regs;
1827*00d0963fSdilpreet 		int ce, ue, mult_ce, mult_ue, first_ue_fatal, nfe, fe;
1828*00d0963fSdilpreet 
1829*00d0963fSdilpreet 		ce = pcie_rc_regs->pcie_rc_err_status &
1830*00d0963fSdilpreet 		    PCIE_AER_RE_STS_CE_RCVD;
1831*00d0963fSdilpreet 		ue = pcie_rc_regs->pcie_rc_err_status &
1832*00d0963fSdilpreet 		    PCIE_AER_RE_STS_FE_NFE_RCVD;
1833*00d0963fSdilpreet 		mult_ce = pcie_rc_regs->pcie_rc_err_status &
1834*00d0963fSdilpreet 		    PCIE_AER_RE_STS_MUL_CE_RCVD;
1835*00d0963fSdilpreet 		mult_ue = pcie_rc_regs->pcie_rc_err_status &
1836*00d0963fSdilpreet 		    PCIE_AER_RE_STS_MUL_FE_NFE_RCVD;
1837*00d0963fSdilpreet 		first_ue_fatal = pcie_rc_regs->pcie_rc_err_status &
1838*00d0963fSdilpreet 		    PCIE_AER_RE_STS_FIRST_UC_FATAL;
1839*00d0963fSdilpreet 		nfe = pcie_rc_regs->pcie_rc_err_status &
1840*00d0963fSdilpreet 		    PCIE_AER_RE_STS_NFE_MSGS_RCVD;
1841*00d0963fSdilpreet 		fe = pcie_rc_regs->pcie_rc_err_status &
1842*00d0963fSdilpreet 		    PCIE_AER_RE_STS_FE_MSGS_RCVD;
1843*00d0963fSdilpreet 		/*
1844*00d0963fSdilpreet 		 * log fatal/nonfatal/corrected messages
1845*00d0963fSdilpreet 		 * recieved by root complex
1846*00d0963fSdilpreet 		 */
1847*00d0963fSdilpreet 		if (ue && fe)
1848*00d0963fSdilpreet 			fatal++;
1849*00d0963fSdilpreet 		else if (ce && !ue)
1850*00d0963fSdilpreet 			nonfatal++;
1851*00d0963fSdilpreet 
1852*00d0963fSdilpreet 		if (fe && first_ue_fatal) {
1853*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
1854*00d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_FE_MSG);
1855*00d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
1856*00d0963fSdilpreet 			    PCIEX_TYPE_RC_UE_MSG);
1857*00d0963fSdilpreet 		}
1858*00d0963fSdilpreet 		if (nfe && !first_ue_fatal) {
1859*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
1860*00d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_NFE_MSG);
1861*00d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
1862*00d0963fSdilpreet 			    PCIEX_TYPE_RC_UE_MSG);
1863*00d0963fSdilpreet 		}
1864*00d0963fSdilpreet 		if (ce) {
1865*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
1866*00d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_CE_MSG);
1867*00d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
1868*00d0963fSdilpreet 			    PCIEX_TYPE_RC_CE_MSG);
1869*00d0963fSdilpreet 		}
1870*00d0963fSdilpreet 		if (mult_ce) {
1871*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
1872*00d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MCE_MSG);
1873*00d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
1874*00d0963fSdilpreet 			    PCIEX_TYPE_RC_MULT_MSG);
1875*00d0963fSdilpreet 		}
1876*00d0963fSdilpreet 		if (mult_ue) {
1877*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
1878*00d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS, PCIEX_RC_MUE_MSG);
1879*00d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
1880*00d0963fSdilpreet 			    PCIEX_TYPE_RC_MULT_MSG);
1881*00d0963fSdilpreet 		}
1882*00d0963fSdilpreet 	}
1883*00d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
1884*00d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
1885*00d0963fSdilpreet }
1886*00d0963fSdilpreet 
1887*00d0963fSdilpreet static int
1888*00d0963fSdilpreet pcie_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
1889*00d0963fSdilpreet {
1890*00d0963fSdilpreet 	int fatal = 0;
1891*00d0963fSdilpreet 	int nonfatal = 0;
1892*00d0963fSdilpreet 	int unknown = 0;
1893*00d0963fSdilpreet 	int ok = 0;
1894*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
1895*00d0963fSdilpreet 	int i;
1896*00d0963fSdilpreet 	pcie_error_regs_t *pcie_regs = (pcie_error_regs_t *)erpt_p->pe_regs;
1897*00d0963fSdilpreet 	pcie_adv_error_regs_t *pcie_adv_regs;
1898*00d0963fSdilpreet 	pcie_adv_bdg_error_regs_t *pcie_bdg_regs;
1899*00d0963fSdilpreet 
1900*00d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV) &&
1901*00d0963fSdilpreet 	    (erpt_p->pe_dflags & PCIX_DEV)) {
1902*00d0963fSdilpreet 		int ret = pcix_bdg_error_report(dip, derr, erpt_p,
1903*00d0963fSdilpreet 		    (void *)pcie_regs->pcix_bdg_regs);
1904*00d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
1905*00d0963fSdilpreet 	}
1906*00d0963fSdilpreet 
1907*00d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCIEX_ADV_DEV)) {
1908*00d0963fSdilpreet 		if (!(pcie_regs->pcie_vflags & PCIE_ERR_STATUS_VALID))
1909*00d0963fSdilpreet 			goto done;
1910*00d0963fSdilpreet 		for (i = 0; pciex_nadv_err_tbl[i].err_class != NULL; i++) {
1911*00d0963fSdilpreet 			if (!(pcie_regs->pcie_err_status &
1912*00d0963fSdilpreet 			    pciex_nadv_err_tbl[i].reg_bit))
1913*00d0963fSdilpreet 				continue;
1914*00d0963fSdilpreet 
1915*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
1916*00d0963fSdilpreet 			    PCIEX_ERROR_SUBCLASS,
1917*00d0963fSdilpreet 			    pciex_nadv_err_tbl[i].err_class);
1918*00d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
1919*00d0963fSdilpreet 			    PCIEX_TYPE_GEN);
1920*00d0963fSdilpreet 			PCI_FM_SEV_INC(pciex_nadv_err_tbl[i].flags);
1921*00d0963fSdilpreet 		}
1922*00d0963fSdilpreet 		goto done;
1923*00d0963fSdilpreet 	}
1924*00d0963fSdilpreet 
1925*00d0963fSdilpreet 	pcie_adv_regs = pcie_regs->pcie_adv_regs;
1926*00d0963fSdilpreet 
1927*00d0963fSdilpreet 	/*
1928*00d0963fSdilpreet 	 * Log PCI Express uncorrectable errors
1929*00d0963fSdilpreet 	 */
1930*00d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_UE_STATUS_VALID) {
1931*00d0963fSdilpreet 		for (i = 0; pciex_ue_err_tbl[i].err_class != NULL; i++) {
1932*00d0963fSdilpreet 			if (!(pcie_adv_regs->pcie_ue_status &
1933*00d0963fSdilpreet 			    pciex_ue_err_tbl[i].reg_bit))
1934*00d0963fSdilpreet 				continue;
1935*00d0963fSdilpreet 
1936*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
1937*00d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS,
1938*00d0963fSdilpreet 			    pciex_ue_err_tbl[i].err_class);
1939*00d0963fSdilpreet 
1940*00d0963fSdilpreet 			pcie_adv_regs->pcie_adv_bdf = 0;
1941*00d0963fSdilpreet 			if ((pcie_adv_regs->pcie_ue_status &
1942*00d0963fSdilpreet 			    PCIE_AER_UCE_LOG_BITS) !=
1943*00d0963fSdilpreet 			    pciex_ue_err_tbl[i].reg_bit) {
1944*00d0963fSdilpreet 				PCI_FM_SEV_INC(pciex_ue_err_tbl[i].flags);
1945*00d0963fSdilpreet 				pcie_ereport_post(dip, derr, erpt_p, buf,
1946*00d0963fSdilpreet 				    PCIEX_TYPE_UE);
1947*00d0963fSdilpreet 			} else {
1948*00d0963fSdilpreet 				pcie_check_addr(dip, derr, erpt_p);
1949*00d0963fSdilpreet 				/*
1950*00d0963fSdilpreet 				 * fatal/nonfatal errors are fatal/nonfatal
1951*00d0963fSdilpreet 				 * regardless of if we find a handle
1952*00d0963fSdilpreet 				 */
1953*00d0963fSdilpreet 				if (pciex_ue_err_tbl[i].flags == DDI_FM_FATAL)
1954*00d0963fSdilpreet 					derr->fme_status = DDI_FM_FATAL;
1955*00d0963fSdilpreet 				else if (pciex_ue_err_tbl[i].flags ==
1956*00d0963fSdilpreet 				    DDI_FM_NONFATAL)
1957*00d0963fSdilpreet 					derr->fme_status = DDI_FM_NONFATAL;
1958*00d0963fSdilpreet 				pcie_ereport_post(dip, derr, erpt_p, buf,
1959*00d0963fSdilpreet 				    PCIEX_TYPE_UE);
1960*00d0963fSdilpreet 				PCI_FM_SEV_INC(derr->fme_status);
1961*00d0963fSdilpreet 			}
1962*00d0963fSdilpreet 		}
1963*00d0963fSdilpreet 	}
1964*00d0963fSdilpreet 
1965*00d0963fSdilpreet 	/*
1966*00d0963fSdilpreet 	 * Log PCI Express correctable errors
1967*00d0963fSdilpreet 	 */
1968*00d0963fSdilpreet 	if (pcie_adv_regs->pcie_adv_vflags & PCIE_CE_STATUS_VALID) {
1969*00d0963fSdilpreet 		for (i = 0; pciex_ce_err_tbl[i].err_class != NULL; i++) {
1970*00d0963fSdilpreet 			if (!(pcie_adv_regs->pcie_ce_status &
1971*00d0963fSdilpreet 			    pciex_ce_err_tbl[i].reg_bit))
1972*00d0963fSdilpreet 				continue;
1973*00d0963fSdilpreet 
1974*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS,
1975*00d0963fSdilpreet 			    "%s.%s", PCIEX_ERROR_SUBCLASS,
1976*00d0963fSdilpreet 			    pciex_ce_err_tbl[i].err_class);
1977*00d0963fSdilpreet 			pcie_ereport_post(dip, derr, erpt_p, buf,
1978*00d0963fSdilpreet 			    PCIEX_TYPE_CE);
1979*00d0963fSdilpreet 			if (!fatal && !unknown)
1980*00d0963fSdilpreet 				PCI_FM_SEV_INC(pciex_ce_err_tbl[i].flags);
1981*00d0963fSdilpreet 		}
1982*00d0963fSdilpreet 	}
1983*00d0963fSdilpreet 
1984*00d0963fSdilpreet 	if (!(erpt_p->pe_dflags & PCI_BRIDGE_DEV))
1985*00d0963fSdilpreet 		goto done;
1986*00d0963fSdilpreet 
1987*00d0963fSdilpreet 	if (erpt_p->pe_dflags & PCIEX_RC_DEV) {
1988*00d0963fSdilpreet 		int ret = pcie_rc_error_report(dip, derr, erpt_p,
1989*00d0963fSdilpreet 		    (void *)pcie_adv_regs);
1990*00d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
1991*00d0963fSdilpreet 	}
1992*00d0963fSdilpreet 
1993*00d0963fSdilpreet 	if (!((erpt_p->pe_dflags & PCIEX_2PCI_DEV) &&
1994*00d0963fSdilpreet 	    (pcie_adv_regs->pcie_adv_vflags & PCIE_SUE_STATUS_VALID)))
1995*00d0963fSdilpreet 		goto done;
1996*00d0963fSdilpreet 
1997*00d0963fSdilpreet 	pcie_bdg_regs = pcie_adv_regs->pcie_adv_bdg_regs;
1998*00d0963fSdilpreet 
1999*00d0963fSdilpreet 	for (i = 0; pcie_sue_err_tbl[i].err_class != NULL; i++) {
2000*00d0963fSdilpreet 		if ((pcie_bdg_regs->pcie_sue_status &
2001*00d0963fSdilpreet 		    pcie_sue_err_tbl[i].reg_bit)) {
2002*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
2003*00d0963fSdilpreet 			    PCIEX_ERROR_SUBCLASS,
2004*00d0963fSdilpreet 			    pcie_sue_err_tbl[i].err_class);
2005*00d0963fSdilpreet 
2006*00d0963fSdilpreet 			if ((pcie_bdg_regs->pcie_sue_status &
2007*00d0963fSdilpreet 			    PCIE_AER_SUCE_LOG_BITS) !=
2008*00d0963fSdilpreet 			    pcie_sue_err_tbl[i].reg_bit) {
2009*00d0963fSdilpreet 				PCI_FM_SEV_INC(pcie_sue_err_tbl[i].flags);
2010*00d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
2011*00d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
2012*00d0963fSdilpreet 				    PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32,
2013*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_status,
2014*00d0963fSdilpreet #ifdef DEBUG
2015*00d0963fSdilpreet 				    PCIEX_SUE_HDR0, DATA_TYPE_UINT32,
2016*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr0,
2017*00d0963fSdilpreet 				    PCIEX_SUE_HDR1, DATA_TYPE_UINT32,
2018*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[0],
2019*00d0963fSdilpreet 				    PCIEX_SUE_HDR2, DATA_TYPE_UINT32,
2020*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[1],
2021*00d0963fSdilpreet 				    PCIEX_SUE_HDR3, DATA_TYPE_UINT32,
2022*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[2],
2023*00d0963fSdilpreet #endif
2024*00d0963fSdilpreet 				    NULL);
2025*00d0963fSdilpreet 			} else {
2026*00d0963fSdilpreet 				pcie_adv_regs->pcie_adv_bdf = 0;
2027*00d0963fSdilpreet 				pcie_pci_check_addr(dip, derr, erpt_p);
2028*00d0963fSdilpreet 				/*
2029*00d0963fSdilpreet 				 * fatal/nonfatal errors are fatal/nonfatal
2030*00d0963fSdilpreet 				 * regardless of if we find a handle
2031*00d0963fSdilpreet 				 */
2032*00d0963fSdilpreet 				if (pcie_sue_err_tbl[i].flags == DDI_FM_FATAL)
2033*00d0963fSdilpreet 					derr->fme_status = DDI_FM_FATAL;
2034*00d0963fSdilpreet 				else if (pcie_sue_err_tbl[i].flags ==
2035*00d0963fSdilpreet 				    DDI_FM_NONFATAL)
2036*00d0963fSdilpreet 					derr->fme_status = DDI_FM_NONFATAL;
2037*00d0963fSdilpreet 
2038*00d0963fSdilpreet 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
2039*00d0963fSdilpreet 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
2040*00d0963fSdilpreet 				    PCIEX_SEC_UE_STATUS, DATA_TYPE_UINT32,
2041*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_status,
2042*00d0963fSdilpreet 				    PCIEX_SRC_ID, DATA_TYPE_UINT16,
2043*00d0963fSdilpreet 				    pcie_adv_regs->pcie_adv_bdf,
2044*00d0963fSdilpreet 				    PCIEX_SRC_VALID, DATA_TYPE_BOOLEAN_VALUE,
2045*00d0963fSdilpreet 				    (pcie_adv_regs->pcie_adv_bdf != NULL) ?
2046*00d0963fSdilpreet 				    1 : NULL,
2047*00d0963fSdilpreet #ifdef DEBUG
2048*00d0963fSdilpreet 				    PCIEX_SUE_HDR0, DATA_TYPE_UINT32,
2049*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr0,
2050*00d0963fSdilpreet 				    PCIEX_SUE_HDR1, DATA_TYPE_UINT32,
2051*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[0],
2052*00d0963fSdilpreet 				    PCIEX_SUE_HDR2, DATA_TYPE_UINT32,
2053*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[1],
2054*00d0963fSdilpreet 				    PCIEX_SUE_HDR3, DATA_TYPE_UINT32,
2055*00d0963fSdilpreet 				    pcie_bdg_regs->pcie_sue_hdr[2],
2056*00d0963fSdilpreet #endif
2057*00d0963fSdilpreet 				    NULL);
2058*00d0963fSdilpreet 				PCI_FM_SEV_INC(derr->fme_status);
2059*00d0963fSdilpreet 			}
2060*00d0963fSdilpreet 		}
2061*00d0963fSdilpreet 	}
2062*00d0963fSdilpreet done:
2063*00d0963fSdilpreet 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
2064*00d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
2065*00d0963fSdilpreet }
2066*00d0963fSdilpreet 
2067*00d0963fSdilpreet static void
2068*00d0963fSdilpreet pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
2069*00d0963fSdilpreet {
2070*00d0963fSdilpreet 	int fatal = 0;
2071*00d0963fSdilpreet 	int nonfatal = 0;
2072*00d0963fSdilpreet 	int unknown = 0;
2073*00d0963fSdilpreet 	int ok = 0;
2074*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
2075*00d0963fSdilpreet 	int i;
2076*00d0963fSdilpreet 
2077*00d0963fSdilpreet 	if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) {
2078*00d0963fSdilpreet 		/*
2079*00d0963fSdilpreet 		 * Log generic PCI errors.
2080*00d0963fSdilpreet 		 */
2081*00d0963fSdilpreet 		for (i = 0; pci_err_tbl[i].err_class != NULL; i++) {
2082*00d0963fSdilpreet 			if (!(erpt_p->pe_pci_regs->pci_err_status &
2083*00d0963fSdilpreet 			    pci_err_tbl[i].reg_bit) ||
2084*00d0963fSdilpreet 			    !(erpt_p->pe_pci_regs->pci_vflags &
2085*00d0963fSdilpreet 			    PCI_ERR_STATUS_VALID))
2086*00d0963fSdilpreet 				continue;
2087*00d0963fSdilpreet 			/*
2088*00d0963fSdilpreet 			 * Generate an ereport for this error bit.
2089*00d0963fSdilpreet 			 */
2090*00d0963fSdilpreet 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
2091*00d0963fSdilpreet 			    PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class);
2092*00d0963fSdilpreet 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
2093*00d0963fSdilpreet 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
2094*00d0963fSdilpreet 			    PCI_CONFIG_STATUS, DATA_TYPE_UINT16,
2095*00d0963fSdilpreet 			    erpt_p->pe_pci_regs->pci_err_status,
2096*00d0963fSdilpreet 			    PCI_CONFIG_COMMAND, DATA_TYPE_UINT16,
2097*00d0963fSdilpreet 			    erpt_p->pe_pci_regs->pci_cfg_comm, NULL);
2098*00d0963fSdilpreet 
2099*00d0963fSdilpreet 			if (!(erpt_p->pe_dflags & PCIEX_DEV))
2100*00d0963fSdilpreet 				PCI_FM_SEV_INC(pci_err_tbl[i].flags);
2101*00d0963fSdilpreet 		}
2102*00d0963fSdilpreet 		if (erpt_p->pe_dflags & PCIEX_DEV) {
2103*00d0963fSdilpreet 			int ret = pcie_error_report(dip, derr, erpt_p);
2104*00d0963fSdilpreet 			PCI_FM_SEV_INC(ret);
2105*00d0963fSdilpreet 		} else if (erpt_p->pe_dflags & PCIX_DEV) {
2106*00d0963fSdilpreet 			if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
2107*00d0963fSdilpreet 				int ret = pcix_bdg_error_report(dip, derr,
2108*00d0963fSdilpreet 				    erpt_p, erpt_p->pe_regs);
2109*00d0963fSdilpreet 				PCI_FM_SEV_INC(ret);
2110*00d0963fSdilpreet 			} else {
2111*00d0963fSdilpreet 				int ret = pcix_error_report(dip, derr, erpt_p);
2112*00d0963fSdilpreet 				PCI_FM_SEV_INC(ret);
2113*00d0963fSdilpreet 			}
2114*00d0963fSdilpreet 		}
2115*00d0963fSdilpreet 	}
2116*00d0963fSdilpreet 
2117*00d0963fSdilpreet 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) {
2118*00d0963fSdilpreet 		int ret = pci_bdg_error_report(dip, derr, erpt_p);
2119*00d0963fSdilpreet 		PCI_FM_SEV_INC(ret);
2120*00d0963fSdilpreet 	}
2121*00d0963fSdilpreet 
2122*00d0963fSdilpreet 	derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
2123*00d0963fSdilpreet 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
2124*00d0963fSdilpreet }
2125*00d0963fSdilpreet 
2126*00d0963fSdilpreet void
2127*00d0963fSdilpreet pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status)
2128*00d0963fSdilpreet {
2129*00d0963fSdilpreet 	struct i_ddi_fmhdl *fmhdl;
2130*00d0963fSdilpreet 	pci_erpt_t *erpt_p;
2131*00d0963fSdilpreet 
2132*00d0963fSdilpreet 	fmhdl = DEVI(dip)->devi_fmhdl;
2133*00d0963fSdilpreet 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
2134*00d0963fSdilpreet 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
2135*00d0963fSdilpreet 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP);
2136*00d0963fSdilpreet 		return;
2137*00d0963fSdilpreet 	}
2138*00d0963fSdilpreet 
2139*00d0963fSdilpreet 	ASSERT(fmhdl);
2140*00d0963fSdilpreet 
2141*00d0963fSdilpreet 	if (derr->fme_ena == NULL)
2142*00d0963fSdilpreet 		derr->fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
2143*00d0963fSdilpreet 
2144*00d0963fSdilpreet 	erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
2145*00d0963fSdilpreet 	if (erpt_p == NULL) {
2146*00d0963fSdilpreet 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP);
2147*00d0963fSdilpreet 		return;
2148*00d0963fSdilpreet 	}
2149*00d0963fSdilpreet 
2150*00d0963fSdilpreet 	pci_regs_gather(dip, erpt_p);
2151*00d0963fSdilpreet 	pci_error_report(dip, derr, erpt_p);
2152*00d0963fSdilpreet 	pci_regs_clear(erpt_p);
2153*00d0963fSdilpreet 
2154*00d0963fSdilpreet 	if (xx_status != NULL)
2155*00d0963fSdilpreet 		*xx_status = erpt_p->pe_pci_regs->pci_err_status;
2156*00d0963fSdilpreet }
2157*00d0963fSdilpreet 
2158*00d0963fSdilpreet /*
2159*00d0963fSdilpreet  * private version of walk_devs() that can be used during panic. No
2160*00d0963fSdilpreet  * sleeping or locking required.
2161*00d0963fSdilpreet  */
2162*00d0963fSdilpreet static int
2163*00d0963fSdilpreet pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg)
2164*00d0963fSdilpreet {
2165*00d0963fSdilpreet 	while (dip) {
2166*00d0963fSdilpreet 		switch ((*f)(dip, arg)) {
2167*00d0963fSdilpreet 		case DDI_WALK_TERMINATE:
2168*00d0963fSdilpreet 			return (DDI_WALK_TERMINATE);
2169*00d0963fSdilpreet 		case DDI_WALK_CONTINUE:
2170*00d0963fSdilpreet 			if (pci_fm_walk_devs(ddi_get_child(dip), f,
2171*00d0963fSdilpreet 			    arg) == DDI_WALK_TERMINATE)
2172*00d0963fSdilpreet 				return (DDI_WALK_TERMINATE);
2173*00d0963fSdilpreet 			break;
2174*00d0963fSdilpreet 		case DDI_WALK_PRUNECHILD:
2175*00d0963fSdilpreet 			break;
2176*00d0963fSdilpreet 		}
2177*00d0963fSdilpreet 		dip = ddi_get_next_sibling(dip);
2178*00d0963fSdilpreet 	}
2179*00d0963fSdilpreet 	return (DDI_WALK_CONTINUE);
2180*00d0963fSdilpreet }
2181*00d0963fSdilpreet 
2182*00d0963fSdilpreet /*
2183*00d0963fSdilpreet  * need special version of ddi_fm_ereport_post() as the leaf driver may
2184*00d0963fSdilpreet  * not be hardened.
2185*00d0963fSdilpreet  */
2186*00d0963fSdilpreet static void
2187*00d0963fSdilpreet pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena,
2188*00d0963fSdilpreet     uint8_t version, ...)
2189*00d0963fSdilpreet {
2190*00d0963fSdilpreet 	char *name;
2191*00d0963fSdilpreet 	char device_path[MAXPATHLEN];
2192*00d0963fSdilpreet 	char ddi_error_class[FM_MAX_CLASS];
2193*00d0963fSdilpreet 	nvlist_t *ereport, *detector;
2194*00d0963fSdilpreet 	nv_alloc_t *nva;
2195*00d0963fSdilpreet 	errorq_elem_t *eqep;
2196*00d0963fSdilpreet 	va_list ap;
2197*00d0963fSdilpreet 
2198*00d0963fSdilpreet 	if (panicstr) {
2199*00d0963fSdilpreet 		eqep = errorq_reserve(ereport_errorq);
2200*00d0963fSdilpreet 		if (eqep == NULL)
2201*00d0963fSdilpreet 			return;
2202*00d0963fSdilpreet 		ereport = errorq_elem_nvl(ereport_errorq, eqep);
2203*00d0963fSdilpreet 		nva = errorq_elem_nva(ereport_errorq, eqep);
2204*00d0963fSdilpreet 		detector = fm_nvlist_create(nva);
2205*00d0963fSdilpreet 	} else {
2206*00d0963fSdilpreet 		ereport = fm_nvlist_create(NULL);
2207*00d0963fSdilpreet 		detector = fm_nvlist_create(NULL);
2208*00d0963fSdilpreet 	}
2209*00d0963fSdilpreet 
2210*00d0963fSdilpreet 	(void) ddi_pathname(dip, device_path);
2211*00d0963fSdilpreet 	fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
2212*00d0963fSdilpreet 	    device_path, NULL);
2213*00d0963fSdilpreet 	(void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s",
2214*00d0963fSdilpreet 	    DDI_IO_CLASS, error_class);
2215*00d0963fSdilpreet 	fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL);
2216*00d0963fSdilpreet 
2217*00d0963fSdilpreet 	va_start(ap, version);
2218*00d0963fSdilpreet 	name = va_arg(ap, char *);
2219*00d0963fSdilpreet 	(void) i_fm_payload_set(ereport, name, ap);
2220*00d0963fSdilpreet 	va_end(ap);
2221*00d0963fSdilpreet 
2222*00d0963fSdilpreet 	if (panicstr) {
2223*00d0963fSdilpreet 		errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
2224*00d0963fSdilpreet 	} else {
2225*00d0963fSdilpreet 		(void) fm_ereport_post(ereport, EVCH_TRYHARD);
2226*00d0963fSdilpreet 		fm_nvlist_destroy(ereport, FM_NVA_FREE);
2227*00d0963fSdilpreet 		fm_nvlist_destroy(detector, FM_NVA_FREE);
2228*00d0963fSdilpreet 	}
2229*00d0963fSdilpreet }
2230*00d0963fSdilpreet 
2231*00d0963fSdilpreet static int
2232*00d0963fSdilpreet pci_check_regs(dev_info_t *dip, void *arg)
2233*00d0963fSdilpreet {
2234*00d0963fSdilpreet 	int reglen;
2235*00d0963fSdilpreet 	int rn;
2236*00d0963fSdilpreet 	int totreg;
2237*00d0963fSdilpreet 	pci_regspec_t *drv_regp;
2238*00d0963fSdilpreet 	pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
2239*00d0963fSdilpreet 
2240*00d0963fSdilpreet 	if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
2241*00d0963fSdilpreet 		/*
2242*00d0963fSdilpreet 		 * for config space, we need to check if the given address
2243*00d0963fSdilpreet 		 * is a valid config space address for this device - based
2244*00d0963fSdilpreet 		 * on pci_phys_hi of the config space entry in reg property.
2245*00d0963fSdilpreet 		 */
2246*00d0963fSdilpreet 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
2247*00d0963fSdilpreet 		    "reg", (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
2248*00d0963fSdilpreet 			return (DDI_WALK_CONTINUE);
2249*00d0963fSdilpreet 
2250*00d0963fSdilpreet 		totreg = reglen / sizeof (pci_regspec_t);
2251*00d0963fSdilpreet 		for (rn = 0; rn < totreg; rn++) {
2252*00d0963fSdilpreet 			if (tgt_err->tgt_pci_space ==
2253*00d0963fSdilpreet 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) &&
2254*00d0963fSdilpreet 			    (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M |
2255*00d0963fSdilpreet 			    PCI_REG_DEV_M | PCI_REG_FUNC_M)) ==
2256*00d0963fSdilpreet 			    (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M |
2257*00d0963fSdilpreet 			    PCI_REG_DEV_M | PCI_REG_FUNC_M))) {
2258*00d0963fSdilpreet 				tgt_err->tgt_dip = dip;
2259*00d0963fSdilpreet 				kmem_free(drv_regp, reglen);
2260*00d0963fSdilpreet 				return (DDI_WALK_TERMINATE);
2261*00d0963fSdilpreet 			}
2262*00d0963fSdilpreet 		}
2263*00d0963fSdilpreet 		kmem_free(drv_regp, reglen);
2264*00d0963fSdilpreet 	} else {
2265*00d0963fSdilpreet 		/*
2266*00d0963fSdilpreet 		 * for non config space, need to check reg to look
2267*00d0963fSdilpreet 		 * for any non-relocable mapping, otherwise check
2268*00d0963fSdilpreet 		 * assigned-addresses.
2269*00d0963fSdilpreet 		 */
2270*00d0963fSdilpreet 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
2271*00d0963fSdilpreet 		    "reg", (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
2272*00d0963fSdilpreet 			return (DDI_WALK_CONTINUE);
2273*00d0963fSdilpreet 
2274*00d0963fSdilpreet 		totreg = reglen / sizeof (pci_regspec_t);
2275*00d0963fSdilpreet 		for (rn = 0; rn < totreg; rn++) {
2276*00d0963fSdilpreet 			if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) &&
2277*00d0963fSdilpreet 			    (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
2278*00d0963fSdilpreet 			    tgt_err->tgt_pci_space ==
2279*00d0963fSdilpreet 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) &&
2280*00d0963fSdilpreet 			    (tgt_err->tgt_pci_addr >=
2281*00d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_phys_low +
2282*00d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) &&
2283*00d0963fSdilpreet 			    (tgt_err->tgt_pci_addr <
2284*00d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_phys_low +
2285*00d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32) +
2286*00d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_size_low +
2287*00d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_size_hi << 32))) {
2288*00d0963fSdilpreet 				tgt_err->tgt_dip = dip;
2289*00d0963fSdilpreet 				kmem_free(drv_regp, reglen);
2290*00d0963fSdilpreet 				return (DDI_WALK_TERMINATE);
2291*00d0963fSdilpreet 			}
2292*00d0963fSdilpreet 		}
2293*00d0963fSdilpreet 		kmem_free(drv_regp, reglen);
2294*00d0963fSdilpreet 
2295*00d0963fSdilpreet 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
2296*00d0963fSdilpreet 		    "assigned-addresses", (caddr_t)&drv_regp, &reglen) !=
2297*00d0963fSdilpreet 		    DDI_SUCCESS)
2298*00d0963fSdilpreet 			return (DDI_WALK_CONTINUE);
2299*00d0963fSdilpreet 
2300*00d0963fSdilpreet 		totreg = reglen / sizeof (pci_regspec_t);
2301*00d0963fSdilpreet 		for (rn = 0; rn < totreg; rn++) {
2302*00d0963fSdilpreet 			if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
2303*00d0963fSdilpreet 			    tgt_err->tgt_pci_space ==
2304*00d0963fSdilpreet 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) &&
2305*00d0963fSdilpreet 			    (tgt_err->tgt_pci_addr >=
2306*00d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_phys_low +
2307*00d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) &&
2308*00d0963fSdilpreet 			    (tgt_err->tgt_pci_addr <
2309*00d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_phys_low +
2310*00d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32) +
2311*00d0963fSdilpreet 			    (uint64_t)drv_regp[rn].pci_size_low +
2312*00d0963fSdilpreet 			    ((uint64_t)drv_regp[rn].pci_size_hi << 32))) {
2313*00d0963fSdilpreet 				tgt_err->tgt_dip = dip;
2314*00d0963fSdilpreet 				kmem_free(drv_regp, reglen);
2315*00d0963fSdilpreet 				return (DDI_WALK_TERMINATE);
2316*00d0963fSdilpreet 			}
2317*00d0963fSdilpreet 		}
2318*00d0963fSdilpreet 		kmem_free(drv_regp, reglen);
2319*00d0963fSdilpreet 	}
2320*00d0963fSdilpreet 	return (DDI_WALK_CONTINUE);
2321*00d0963fSdilpreet }
2322*00d0963fSdilpreet 
2323*00d0963fSdilpreet /*
2324*00d0963fSdilpreet  * impl_fix_ranges - fixes the config space entry of the "ranges"
2325*00d0963fSdilpreet  * property on psycho+ platforms.  (if changing this function please make sure
2326*00d0963fSdilpreet  * to change the pci_fix_ranges function in pcipsy.c)
2327*00d0963fSdilpreet  */
2328*00d0963fSdilpreet /*ARGSUSED*/
2329*00d0963fSdilpreet static void
2330*00d0963fSdilpreet pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange)
2331*00d0963fSdilpreet {
2332*00d0963fSdilpreet #if defined(__sparc)
2333*00d0963fSdilpreet 	char *name = ddi_binding_name(dip);
2334*00d0963fSdilpreet 
2335*00d0963fSdilpreet 	if ((strcmp(name, "pci108e,8000") == 0) ||
2336*00d0963fSdilpreet 	    (strcmp(name, "pci108e,a000") == 0) ||
2337*00d0963fSdilpreet 	    (strcmp(name, "pci108e,a001") == 0)) {
2338*00d0963fSdilpreet 		int i;
2339*00d0963fSdilpreet 		for (i = 0; i < nrange; i++, pci_ranges++)
2340*00d0963fSdilpreet 			if ((pci_ranges->child_high & PCI_REG_ADDR_M) ==
2341*00d0963fSdilpreet 			    PCI_ADDR_CONFIG)
2342*00d0963fSdilpreet 				pci_ranges->parent_low |=
2343*00d0963fSdilpreet 				    pci_ranges->child_high;
2344*00d0963fSdilpreet 	}
2345*00d0963fSdilpreet #endif
2346*00d0963fSdilpreet }
2347*00d0963fSdilpreet 
2348*00d0963fSdilpreet static int
2349*00d0963fSdilpreet pci_check_ranges(dev_info_t *dip, void *arg)
2350*00d0963fSdilpreet {
2351*00d0963fSdilpreet 	uint64_t range_parent_begin;
2352*00d0963fSdilpreet 	uint64_t range_parent_size;
2353*00d0963fSdilpreet 	uint64_t range_parent_end;
2354*00d0963fSdilpreet 	uint32_t space_type;
2355*00d0963fSdilpreet 	uint32_t bus_num;
2356*00d0963fSdilpreet 	uint32_t range_offset;
2357*00d0963fSdilpreet 	pci_ranges_t *pci_ranges, *rangep;
2358*00d0963fSdilpreet 	pci_bus_range_t *pci_bus_rangep;
2359*00d0963fSdilpreet 	int pci_ranges_length;
2360*00d0963fSdilpreet 	int nrange;
2361*00d0963fSdilpreet 	pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
2362*00d0963fSdilpreet 	int i, size;
2363*00d0963fSdilpreet 	if (strcmp(ddi_node_name(dip), "pci") != 0 &&
2364*00d0963fSdilpreet 	    strcmp(ddi_node_name(dip), "pciex") != 0)
2365*00d0963fSdilpreet 		return (DDI_WALK_CONTINUE);
2366*00d0963fSdilpreet 
2367*00d0963fSdilpreet 	/*
2368*00d0963fSdilpreet 	 * Get the ranges property. Note we only look at the top level pci
2369*00d0963fSdilpreet 	 * node (hostbridge) which has a ranges property of type pci_ranges_t
2370*00d0963fSdilpreet 	 * not at pci-pci bridges.
2371*00d0963fSdilpreet 	 */
2372*00d0963fSdilpreet 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
2373*00d0963fSdilpreet 	    (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) {
2374*00d0963fSdilpreet 		/*
2375*00d0963fSdilpreet 		 * no ranges property - no translation needed
2376*00d0963fSdilpreet 		 */
2377*00d0963fSdilpreet 		tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr;
2378*00d0963fSdilpreet 		tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN;
2379*00d0963fSdilpreet 		if (panicstr)
2380*00d0963fSdilpreet 			(void) pci_fm_walk_devs(ddi_get_child(dip),
2381*00d0963fSdilpreet 			    pci_check_regs, (void *)tgt_err);
2382*00d0963fSdilpreet 		else {
2383*00d0963fSdilpreet 			int circ = 0;
2384*00d0963fSdilpreet 			ndi_devi_enter(dip, &circ);
2385*00d0963fSdilpreet 			ddi_walk_devs(ddi_get_child(dip), pci_check_regs,
2386*00d0963fSdilpreet 			    (void *)tgt_err);
2387*00d0963fSdilpreet 			ndi_devi_exit(dip, circ);
2388*00d0963fSdilpreet 		}
2389*00d0963fSdilpreet 		if (tgt_err->tgt_dip != NULL)
2390*00d0963fSdilpreet 			return (DDI_WALK_TERMINATE);
2391*00d0963fSdilpreet 		return (DDI_WALK_PRUNECHILD);
2392*00d0963fSdilpreet 	}
2393*00d0963fSdilpreet 	nrange = pci_ranges_length / sizeof (pci_ranges_t);
2394*00d0963fSdilpreet 	rangep = pci_ranges;
2395*00d0963fSdilpreet 
2396*00d0963fSdilpreet 	/* Need to fix the pci ranges property for psycho based systems */
2397*00d0963fSdilpreet 	pci_fix_ranges(dip, pci_ranges, nrange);
2398*00d0963fSdilpreet 
2399*00d0963fSdilpreet 	for (i = 0; i < nrange; i++, rangep++) {
2400*00d0963fSdilpreet 		range_parent_begin = ((uint64_t)rangep->parent_high << 32) +
2401*00d0963fSdilpreet 		    rangep->parent_low;
2402*00d0963fSdilpreet 		range_parent_size = ((uint64_t)rangep->size_high << 32) +
2403*00d0963fSdilpreet 		    rangep->size_low;
2404*00d0963fSdilpreet 		range_parent_end = range_parent_begin + range_parent_size - 1;
2405*00d0963fSdilpreet 
2406*00d0963fSdilpreet 		if ((tgt_err->tgt_err_addr < range_parent_begin) ||
2407*00d0963fSdilpreet 		    (tgt_err->tgt_err_addr > range_parent_end)) {
2408*00d0963fSdilpreet 			/* Not in range */
2409*00d0963fSdilpreet 			continue;
2410*00d0963fSdilpreet 		}
2411*00d0963fSdilpreet 		space_type = PCI_REG_ADDR_G(rangep->child_high);
2412*00d0963fSdilpreet 		if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
2413*00d0963fSdilpreet 			/* Config space address - check bus range */
2414*00d0963fSdilpreet 			range_offset = tgt_err->tgt_err_addr -
2415*00d0963fSdilpreet 			    range_parent_begin;
2416*00d0963fSdilpreet 			bus_num = PCI_REG_BUS_G(range_offset);
2417*00d0963fSdilpreet 			if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
2418*00d0963fSdilpreet 			    DDI_PROP_DONTPASS, "bus-range",
2419*00d0963fSdilpreet 			    (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) {
2420*00d0963fSdilpreet 				continue;
2421*00d0963fSdilpreet 			}
2422*00d0963fSdilpreet 			if ((bus_num < pci_bus_rangep->lo) ||
2423*00d0963fSdilpreet 			    (bus_num > pci_bus_rangep->hi)) {
2424*00d0963fSdilpreet 				/*
2425*00d0963fSdilpreet 				 * Bus number not appropriate for this
2426*00d0963fSdilpreet 				 * pci nexus.
2427*00d0963fSdilpreet 				 */
2428*00d0963fSdilpreet 				kmem_free(pci_bus_rangep, size);
2429*00d0963fSdilpreet 				continue;
2430*00d0963fSdilpreet 			}
2431*00d0963fSdilpreet 			kmem_free(pci_bus_rangep, size);
2432*00d0963fSdilpreet 		}
2433*00d0963fSdilpreet 
2434*00d0963fSdilpreet 		/* We have a match if we get here - compute pci address */
2435*00d0963fSdilpreet 		tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr -
2436*00d0963fSdilpreet 		    range_parent_begin;
2437*00d0963fSdilpreet 		tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) +
2438*00d0963fSdilpreet 		    rangep->child_low);
2439*00d0963fSdilpreet 		tgt_err->tgt_pci_space = space_type;
2440*00d0963fSdilpreet 		if (panicstr)
2441*00d0963fSdilpreet 			(void) pci_fm_walk_devs(ddi_get_child(dip),
2442*00d0963fSdilpreet 			    pci_check_regs, (void *)tgt_err);
2443*00d0963fSdilpreet 		else {
2444*00d0963fSdilpreet 			int circ = 0;
2445*00d0963fSdilpreet 			ndi_devi_enter(dip, &circ);
2446*00d0963fSdilpreet 			ddi_walk_devs(ddi_get_child(dip), pci_check_regs,
2447*00d0963fSdilpreet 			    (void *)tgt_err);
2448*00d0963fSdilpreet 			ndi_devi_exit(dip, circ);
2449*00d0963fSdilpreet 		}
2450*00d0963fSdilpreet 		if (tgt_err->tgt_dip != NULL) {
2451*00d0963fSdilpreet 			kmem_free(pci_ranges, pci_ranges_length);
2452*00d0963fSdilpreet 			return (DDI_WALK_TERMINATE);
2453*00d0963fSdilpreet 		}
2454*00d0963fSdilpreet 	}
2455*00d0963fSdilpreet 	kmem_free(pci_ranges, pci_ranges_length);
2456*00d0963fSdilpreet 	return (DDI_WALK_PRUNECHILD);
2457*00d0963fSdilpreet }
2458*00d0963fSdilpreet 
2459*00d0963fSdilpreet /*
2460*00d0963fSdilpreet  * Function used to drain pci_target_queue, either during panic or after softint
2461*00d0963fSdilpreet  * is generated, to generate target device ereports based on captured physical
2462*00d0963fSdilpreet  * addresses
2463*00d0963fSdilpreet  */
2464*00d0963fSdilpreet /*ARGSUSED*/
2465*00d0963fSdilpreet static void
2466*00d0963fSdilpreet pci_target_drain(void *private_p, pci_target_err_t *tgt_err)
2467*00d0963fSdilpreet {
2468*00d0963fSdilpreet 	char buf[FM_MAX_CLASS];
2469*00d0963fSdilpreet 
2470*00d0963fSdilpreet 	/*
2471*00d0963fSdilpreet 	 * The following assumes that all pci_pci bridge devices
2472*00d0963fSdilpreet 	 * are configured as transparant. Find the top-level pci
2473*00d0963fSdilpreet 	 * nexus which has tgt_err_addr in one of its ranges, converting this
2474*00d0963fSdilpreet 	 * to a pci address in the process. Then starting at this node do
2475*00d0963fSdilpreet 	 * another tree walk to find a device with the pci address we've
2476*00d0963fSdilpreet 	 * found within range of one of it's assigned-addresses properties.
2477*00d0963fSdilpreet 	 */
2478*00d0963fSdilpreet 	tgt_err->tgt_dip = NULL;
2479*00d0963fSdilpreet 	if (panicstr)
2480*00d0963fSdilpreet 		(void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges,
2481*00d0963fSdilpreet 		    (void *)tgt_err);
2482*00d0963fSdilpreet 	else
2483*00d0963fSdilpreet 		ddi_walk_devs(ddi_root_node(), pci_check_ranges,
2484*00d0963fSdilpreet 		    (void *)tgt_err);
2485*00d0963fSdilpreet 	if (tgt_err->tgt_dip == NULL)
2486*00d0963fSdilpreet 		return;
2487*00d0963fSdilpreet 
2488*00d0963fSdilpreet 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type,
2489*00d0963fSdilpreet 	    tgt_err->tgt_err_class);
2490*00d0963fSdilpreet 	pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0,
2491*00d0963fSdilpreet 	    PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL);
2492*00d0963fSdilpreet }
2493*00d0963fSdilpreet 
2494*00d0963fSdilpreet void
2495*00d0963fSdilpreet pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr)
2496*00d0963fSdilpreet {
2497*00d0963fSdilpreet 	pci_target_err_t tgt_err;
2498*00d0963fSdilpreet 
2499*00d0963fSdilpreet 	tgt_err.tgt_err_ena = ena;
2500*00d0963fSdilpreet 	tgt_err.tgt_err_class = class;
2501*00d0963fSdilpreet 	tgt_err.tgt_bridge_type = bridge_type;
2502*00d0963fSdilpreet 	tgt_err.tgt_err_addr = addr;
2503*00d0963fSdilpreet 	errorq_dispatch(pci_target_queue, (void *)&tgt_err,
2504*00d0963fSdilpreet 	    sizeof (pci_target_err_t), ERRORQ_ASYNC);
2505*00d0963fSdilpreet }
2506*00d0963fSdilpreet 
2507*00d0963fSdilpreet void
2508*00d0963fSdilpreet pci_targetq_init(void)
2509*00d0963fSdilpreet {
2510*00d0963fSdilpreet 	/*
2511*00d0963fSdilpreet 	 * PCI target errorq, to schedule async handling of generation of
2512*00d0963fSdilpreet 	 * target device ereports based on captured physical address.
2513*00d0963fSdilpreet 	 * The errorq is created here but destroyed when _fini is called
2514*00d0963fSdilpreet 	 * for the pci module.
2515*00d0963fSdilpreet 	 */
2516*00d0963fSdilpreet 	if (pci_target_queue == NULL) {
2517*00d0963fSdilpreet 		pci_target_queue = errorq_create("pci_target_queue",
2518*00d0963fSdilpreet 		    (errorq_func_t)pci_target_drain, (void *)NULL,
2519*00d0963fSdilpreet 		    TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL,
2520*00d0963fSdilpreet 		    ERRORQ_VITAL);
2521*00d0963fSdilpreet 		if (pci_target_queue == NULL)
2522*00d0963fSdilpreet 			panic("failed to create required system error queue");
2523*00d0963fSdilpreet 	}
2524*00d0963fSdilpreet }
2525