xref: /onnv-gate/usr/src/uts/sun4u/io/pci/pci_ecc.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PCI ECC support
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/systm.h>		/* for strrchr */
35*0Sstevel@tonic-gate #include <sys/kmem.h>
36*0Sstevel@tonic-gate #include <sys/sunddi.h>
37*0Sstevel@tonic-gate #include <sys/intr.h>
38*0Sstevel@tonic-gate #include <sys/async.h>		/* struct async_flt */
39*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
40*0Sstevel@tonic-gate #include <sys/machsystm.h>
41*0Sstevel@tonic-gate #include <sys/sysmacros.h>
42*0Sstevel@tonic-gate #include <sys/fm/protocol.h>
43*0Sstevel@tonic-gate #include <sys/fm/util.h>
44*0Sstevel@tonic-gate #include <sys/fm/io/pci.h>
45*0Sstevel@tonic-gate #include <sys/fm/io/sun4upci.h>
46*0Sstevel@tonic-gate #include <sys/fm/io/ddi.h>
47*0Sstevel@tonic-gate #include <sys/pci/pci_obj.h>	/* ld/st physio */
48*0Sstevel@tonic-gate #include <sys/cpuvar.h>
49*0Sstevel@tonic-gate #include <sys/errclassify.h>
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /*LINTLIBRARY*/
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate static void ecc_disable(ecc_t *, int);
54*0Sstevel@tonic-gate static void ecc_delayed_ce(void *);
55*0Sstevel@tonic-gate static uint64_t ecc_read_afsr(ecc_intr_info_t *);
56*0Sstevel@tonic-gate static void ecc_ereport_post(dev_info_t *dip, ecc_errstate_t *ecc_err);
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate clock_t pci_ecc_panic_delay = 200;
59*0Sstevel@tonic-gate int ecc_ce_delay_secs = 6;	/* number of sec to delay reenabling of CEs */
60*0Sstevel@tonic-gate int ecc_ce_delayed = 1;		/* global for enabling/disabling CE delay */
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate void
63*0Sstevel@tonic-gate ecc_create(pci_t *pci_p)
64*0Sstevel@tonic-gate {
65*0Sstevel@tonic-gate #ifdef DEBUG
66*0Sstevel@tonic-gate 	dev_info_t *dip = pci_p->pci_dip;
67*0Sstevel@tonic-gate #endif
68*0Sstevel@tonic-gate 	uint64_t cb_base_pa = pci_p->pci_cb_p->cb_base_pa;
69*0Sstevel@tonic-gate 	ecc_t *ecc_p;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	ecc_p = (ecc_t *)kmem_zalloc(sizeof (ecc_t), KM_SLEEP);
72*0Sstevel@tonic-gate 	ecc_p->ecc_pci_cmn_p = pci_p->pci_common_p;
73*0Sstevel@tonic-gate 	pci_p->pci_ecc_p = ecc_p;
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	ecc_p->ecc_ue.ecc_p = ecc_p;
76*0Sstevel@tonic-gate 	ecc_p->ecc_ue.ecc_type = CBNINTR_UE;
77*0Sstevel@tonic-gate 	ecc_p->ecc_ce.ecc_p = ecc_p;
78*0Sstevel@tonic-gate 	ecc_p->ecc_ce.ecc_type = CBNINTR_CE;
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 	pci_ecc_setup(ecc_p);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	/*
83*0Sstevel@tonic-gate 	 * Determine the virtual addresses of the streaming cache
84*0Sstevel@tonic-gate 	 * control/status and flush registers.
85*0Sstevel@tonic-gate 	 */
86*0Sstevel@tonic-gate 	ecc_p->ecc_csr_pa = cb_base_pa + COMMON_ECC_CSR_OFFSET;
87*0Sstevel@tonic-gate 	ecc_p->ecc_ue.ecc_afsr_pa = cb_base_pa + COMMON_UE_AFSR_OFFSET;
88*0Sstevel@tonic-gate 	ecc_p->ecc_ue.ecc_afar_pa = cb_base_pa + COMMON_UE_AFAR_OFFSET;
89*0Sstevel@tonic-gate 	ecc_p->ecc_ce.ecc_afsr_pa = cb_base_pa + COMMON_CE_AFSR_OFFSET;
90*0Sstevel@tonic-gate 	ecc_p->ecc_ce.ecc_afar_pa = cb_base_pa + COMMON_CE_AFAR_OFFSET;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	DEBUG1(DBG_ATTACH, dip, "ecc_create: csr=%x\n", ecc_p->ecc_csr_pa);
93*0Sstevel@tonic-gate 	DEBUG2(DBG_ATTACH, dip, "ecc_create: ue_afsr=%x, ue_afar=%x\n",
94*0Sstevel@tonic-gate 		ecc_p->ecc_ue.ecc_afsr_pa, ecc_p->ecc_ue.ecc_afar_pa);
95*0Sstevel@tonic-gate 	DEBUG2(DBG_ATTACH, dip, "ecc_create: ce_afsr=%x, ce_afar=%x\n",
96*0Sstevel@tonic-gate 		ecc_p->ecc_ce.ecc_afsr_pa, ecc_p->ecc_ce.ecc_afar_pa);
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	ecc_configure(pci_p);
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	/*
101*0Sstevel@tonic-gate 	 * Register routines to be called from system error handling code.
102*0Sstevel@tonic-gate 	 */
103*0Sstevel@tonic-gate 	bus_func_register(BF_TYPE_ERRDIS, (busfunc_t)ecc_disable_nowait, ecc_p);
104*0Sstevel@tonic-gate }
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate int
107*0Sstevel@tonic-gate ecc_register_intr(pci_t *pci_p)
108*0Sstevel@tonic-gate {
109*0Sstevel@tonic-gate 	ecc_t *ecc_p = pci_p->pci_ecc_p;
110*0Sstevel@tonic-gate 	int ret;
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	/*
113*0Sstevel@tonic-gate 	 * Install the UE and CE error interrupt handlers.
114*0Sstevel@tonic-gate 	 */
115*0Sstevel@tonic-gate 	if ((ret = pci_ecc_add_intr(pci_p, CBNINTR_UE, &ecc_p->ecc_ue)) !=
116*0Sstevel@tonic-gate 	    DDI_SUCCESS)
117*0Sstevel@tonic-gate 		return (ret);
118*0Sstevel@tonic-gate 	if ((ret = pci_ecc_add_intr(pci_p, CBNINTR_CE, &ecc_p->ecc_ce)) !=
119*0Sstevel@tonic-gate 	    DDI_SUCCESS)
120*0Sstevel@tonic-gate 		return (ret);
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
123*0Sstevel@tonic-gate }
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate void
126*0Sstevel@tonic-gate ecc_destroy(pci_t *pci_p)
127*0Sstevel@tonic-gate {
128*0Sstevel@tonic-gate 	ecc_t *ecc_p = pci_p->pci_ecc_p;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	DEBUG0(DBG_DETACH, pci_p->pci_dip, "ecc_destroy:\n");
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	/*
133*0Sstevel@tonic-gate 	 * Disable UE and CE ECC error interrupts.
134*0Sstevel@tonic-gate 	 */
135*0Sstevel@tonic-gate 	ecc_disable_wait(ecc_p);
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	/*
138*0Sstevel@tonic-gate 	 * Remove the ECC interrupt handlers.
139*0Sstevel@tonic-gate 	 */
140*0Sstevel@tonic-gate 	pci_ecc_rem_intr(pci_p, CBNINTR_UE, &ecc_p->ecc_ue);
141*0Sstevel@tonic-gate 	pci_ecc_rem_intr(pci_p, CBNINTR_CE, &ecc_p->ecc_ce);
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	/*
144*0Sstevel@tonic-gate 	 * Unregister our error handling functions.
145*0Sstevel@tonic-gate 	 */
146*0Sstevel@tonic-gate 	bus_func_unregister(BF_TYPE_ERRDIS,
147*0Sstevel@tonic-gate 	    (busfunc_t)ecc_disable_nowait, ecc_p);
148*0Sstevel@tonic-gate 	/*
149*0Sstevel@tonic-gate 	 * If a timer has been set, unset it.
150*0Sstevel@tonic-gate 	 */
151*0Sstevel@tonic-gate 	(void) untimeout(ecc_p->ecc_to_id);
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	kmem_free(ecc_p, sizeof (ecc_t));
154*0Sstevel@tonic-gate 	pci_p->pci_ecc_p = NULL;
155*0Sstevel@tonic-gate }
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate void
158*0Sstevel@tonic-gate ecc_configure(pci_t *pci_p)
159*0Sstevel@tonic-gate {
160*0Sstevel@tonic-gate 	ecc_t *ecc_p = pci_p->pci_ecc_p;
161*0Sstevel@tonic-gate 	dev_info_t *dip = pci_p->pci_dip;
162*0Sstevel@tonic-gate 	uint64_t l;
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	/*
165*0Sstevel@tonic-gate 	 * Clear any pending ECC errors.
166*0Sstevel@tonic-gate 	 */
167*0Sstevel@tonic-gate 	DEBUG0(DBG_ATTACH, dip, "ecc_configure: clearing UE and CE errors\n");
168*0Sstevel@tonic-gate 	l = (COMMON_ECC_UE_AFSR_E_MASK << COMMON_ECC_UE_AFSR_PE_SHIFT) |
169*0Sstevel@tonic-gate 		(COMMON_ECC_UE_AFSR_E_MASK << COMMON_ECC_UE_AFSR_SE_SHIFT);
170*0Sstevel@tonic-gate 	stdphysio(ecc_p->ecc_ue.ecc_afsr_pa, l);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	l = (COMMON_ECC_CE_AFSR_E_MASK << COMMON_ECC_CE_AFSR_PE_SHIFT) |
173*0Sstevel@tonic-gate 		(COMMON_ECC_CE_AFSR_E_MASK << COMMON_ECC_CE_AFSR_SE_SHIFT);
174*0Sstevel@tonic-gate 	stdphysio(ecc_p->ecc_ce.ecc_afsr_pa, l);
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	/*
177*0Sstevel@tonic-gate 	 * Enable ECC error detections via the control register.
178*0Sstevel@tonic-gate 	 */
179*0Sstevel@tonic-gate 	DEBUG0(DBG_ATTACH, dip, "ecc_configure: enabling UE CE detection\n");
180*0Sstevel@tonic-gate 	l = COMMON_ECC_CTRL_ECC_EN;
181*0Sstevel@tonic-gate 	if (ecc_error_intr_enable)
182*0Sstevel@tonic-gate 		l |= COMMON_ECC_CTRL_UE_INTEN | COMMON_ECC_CTRL_CE_INTEN;
183*0Sstevel@tonic-gate 	stdphysio(ecc_p->ecc_csr_pa, l);
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate void
187*0Sstevel@tonic-gate ecc_enable_intr(pci_t *pci_p)
188*0Sstevel@tonic-gate {
189*0Sstevel@tonic-gate 	cb_enable_nintr(pci_p, CBNINTR_UE);
190*0Sstevel@tonic-gate 	cb_enable_nintr(pci_p, CBNINTR_CE);
191*0Sstevel@tonic-gate }
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate void
194*0Sstevel@tonic-gate ecc_disable_wait(ecc_t *ecc_p)
195*0Sstevel@tonic-gate {
196*0Sstevel@tonic-gate 	ecc_disable(ecc_p, IB_INTR_WAIT);
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate uint_t
200*0Sstevel@tonic-gate ecc_disable_nowait(ecc_t *ecc_p)
201*0Sstevel@tonic-gate {
202*0Sstevel@tonic-gate 	ecc_disable(ecc_p, IB_INTR_NOWAIT);
203*0Sstevel@tonic-gate 	return (BF_NONE);
204*0Sstevel@tonic-gate }
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate static void
207*0Sstevel@tonic-gate ecc_disable(ecc_t *ecc_p, int wait)
208*0Sstevel@tonic-gate {
209*0Sstevel@tonic-gate 	cb_t *cb_p = ecc_p->ecc_pci_cmn_p->pci_common_cb_p;
210*0Sstevel@tonic-gate 	uint64_t csr_pa = ecc_p->ecc_csr_pa;
211*0Sstevel@tonic-gate 	uint64_t csr = lddphysio(csr_pa);
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	csr &= ~(COMMON_ECC_CTRL_UE_INTEN | COMMON_ECC_CTRL_CE_INTEN);
214*0Sstevel@tonic-gate 	stdphysio(csr_pa, csr);
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	cb_disable_nintr(cb_p, CBNINTR_UE, wait);
217*0Sstevel@tonic-gate 	cb_disable_nintr(cb_p, CBNINTR_CE, wait);
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate /*
221*0Sstevel@tonic-gate  * I/O ECC error handling:
222*0Sstevel@tonic-gate  *
223*0Sstevel@tonic-gate  * Below are the generic functions that handle PCI(pcisch, pcipsy) detected
224*0Sstevel@tonic-gate  * ECC errors.
225*0Sstevel@tonic-gate  *
226*0Sstevel@tonic-gate  * The registered interrupt handler for both pcisch and pcipsy is ecc_intr(),
227*0Sstevel@tonic-gate  * it's function is to receive the error, capture some state, and pass that on
228*0Sstevel@tonic-gate  * to the ecc_err_handler() for reporting purposes.
229*0Sstevel@tonic-gate  *
230*0Sstevel@tonic-gate  * ecc_err_handler() gathers more state(via ecc_errstate_get) and attempts
231*0Sstevel@tonic-gate  * to handle and report the error. ecc_err_handler() must determine if we need
232*0Sstevel@tonic-gate  * to panic due to this error (via pci_ecc_classify, which also decodes the
233*0Sstevel@tonic-gate  * ECC afsr), and if any side effects exist that may have caused or are due
234*0Sstevel@tonic-gate  * to this error. PBM errors related to the ECC error may exist, to report
235*0Sstevel@tonic-gate  * them we call pci_pbm_err_handler() and call ndi_fm_handler_dispatch() so
236*0Sstevel@tonic-gate  * that the child devices can log their pci errors.
237*0Sstevel@tonic-gate  *
238*0Sstevel@tonic-gate  * To report the error we must also get the syndrome and unum, which can not
239*0Sstevel@tonic-gate  * be done in high level interrupted context. Therefore we have an error
240*0Sstevel@tonic-gate  * queue(pci_ecc_queue) which we dispatch errors to, to report the errors
241*0Sstevel@tonic-gate  * (ecc_err_drain()).
242*0Sstevel@tonic-gate  *
243*0Sstevel@tonic-gate  * ecc_err_drain() will be called when either the softint is triggered
244*0Sstevel@tonic-gate  * or the system is panicing. Either way it will gather more information
245*0Sstevel@tonic-gate  * about the error from the CPU(via ecc_cpu_call(), ecc.c), attempt to
246*0Sstevel@tonic-gate  * retire the faulty page(if error is a UE), and report the detected error.
247*0Sstevel@tonic-gate  *
248*0Sstevel@tonic-gate  * ecc_delayed_ce() is called via timeout from ecc_err_handler() following
249*0Sstevel@tonic-gate  * the receipt of a CE interrupt.  It will be called after 6ms and check to
250*0Sstevel@tonic-gate  * see if any new CEs are present, if so we will log and another timeout will
251*0Sstevel@tonic-gate  * be set by(ecc_err_handler()).  If no CEs are present then it will re-enable
252*0Sstevel@tonic-gate  * CEs by clearing the previous interrupt.  This is to keep the system going
253*0Sstevel@tonic-gate  * in the event of a CE storm.
254*0Sstevel@tonic-gate  */
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate /*
257*0Sstevel@tonic-gate  * Function used to get ECC AFSR register
258*0Sstevel@tonic-gate  */
259*0Sstevel@tonic-gate static uint64_t
260*0Sstevel@tonic-gate ecc_read_afsr(ecc_intr_info_t *ecc_ii_p)
261*0Sstevel@tonic-gate {
262*0Sstevel@tonic-gate 	uint_t i;
263*0Sstevel@tonic-gate 	uint64_t afsr = 0ull;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	ASSERT((ecc_ii_p->ecc_type == CBNINTR_UE) ||
266*0Sstevel@tonic-gate 	    (ecc_ii_p->ecc_type == CBNINTR_CE));
267*0Sstevel@tonic-gate 	if (!ecc_ii_p->ecc_errpndg_mask)
268*0Sstevel@tonic-gate 		return (lddphysio(ecc_ii_p->ecc_afsr_pa));
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	for (i = 0; i < pci_ecc_afsr_retries; i++) {
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 		/*
273*0Sstevel@tonic-gate 		 * If we timeout, the logging routine will
274*0Sstevel@tonic-gate 		 * know because it will see the ERRPNDG bits
275*0Sstevel@tonic-gate 		 * set in the AFSR.
276*0Sstevel@tonic-gate 		 */
277*0Sstevel@tonic-gate 		afsr = lddphysio(ecc_ii_p->ecc_afsr_pa);
278*0Sstevel@tonic-gate 		if ((afsr & ecc_ii_p->ecc_errpndg_mask) == 0)
279*0Sstevel@tonic-gate 			break;
280*0Sstevel@tonic-gate 	}
281*0Sstevel@tonic-gate 	return (afsr);
282*0Sstevel@tonic-gate }
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate /*
285*0Sstevel@tonic-gate  * IO detected ECC error interrupt handler, calls ecc_err_handler to post
286*0Sstevel@tonic-gate  * error reports and handle the interrupt. Re-entry into ecc_err_handler
287*0Sstevel@tonic-gate  * is protected by the per-chip mutex pci_fm_mutex.
288*0Sstevel@tonic-gate  */
289*0Sstevel@tonic-gate uint_t
290*0Sstevel@tonic-gate ecc_intr(caddr_t a)
291*0Sstevel@tonic-gate {
292*0Sstevel@tonic-gate 	ecc_intr_info_t *ecc_ii_p = (ecc_intr_info_t *)a;
293*0Sstevel@tonic-gate 	ecc_t *ecc_p = ecc_ii_p->ecc_p;
294*0Sstevel@tonic-gate 	pci_common_t *cmn_p = ecc_p->ecc_pci_cmn_p;
295*0Sstevel@tonic-gate 	ecc_errstate_t ecc_err;
296*0Sstevel@tonic-gate 	int ret = DDI_FM_OK;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	bzero(&ecc_err, sizeof (ecc_errstate_t));
299*0Sstevel@tonic-gate 	ecc_err.ecc_ena = fm_ena_generate(0, FM_ENA_FMT1);
300*0Sstevel@tonic-gate 	ecc_err.ecc_ii_p = *ecc_ii_p;
301*0Sstevel@tonic-gate 	ecc_err.ecc_p = ecc_p;
302*0Sstevel@tonic-gate 	ecc_err.ecc_caller = PCI_ECC_CALL;
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	mutex_enter(&cmn_p->pci_fm_mutex);
305*0Sstevel@tonic-gate 	ret = ecc_err_handler(&ecc_err);
306*0Sstevel@tonic-gate 	mutex_exit(&cmn_p->pci_fm_mutex);
307*0Sstevel@tonic-gate 	if (ret == DDI_FM_FATAL) {
308*0Sstevel@tonic-gate 		/*
309*0Sstevel@tonic-gate 		 * Need delay here to allow CPUs to handle related traps,
310*0Sstevel@tonic-gate 		 * such as FRUs for USIIIi systems.
311*0Sstevel@tonic-gate 		 */
312*0Sstevel@tonic-gate 		DELAY(pci_ecc_panic_delay);
313*0Sstevel@tonic-gate 		fm_panic("Fatal PCI UE Error");
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
317*0Sstevel@tonic-gate }
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate /*
320*0Sstevel@tonic-gate  * Function used to gather IO ECC error state.
321*0Sstevel@tonic-gate  */
322*0Sstevel@tonic-gate static void
323*0Sstevel@tonic-gate ecc_errstate_get(ecc_errstate_t *ecc_err_p)
324*0Sstevel@tonic-gate {
325*0Sstevel@tonic-gate 	ecc_t *ecc_p;
326*0Sstevel@tonic-gate 	uint_t bus_id;
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	ASSERT(ecc_err_p);
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	ecc_p = ecc_err_p->ecc_ii_p.ecc_p;
331*0Sstevel@tonic-gate 	bus_id = ecc_p->ecc_pci_cmn_p->pci_common_id;
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex));
334*0Sstevel@tonic-gate 	/*
335*0Sstevel@tonic-gate 	 * Read the fault registers.
336*0Sstevel@tonic-gate 	 */
337*0Sstevel@tonic-gate 	ecc_err_p->ecc_afsr = ecc_read_afsr(&ecc_err_p->ecc_ii_p);
338*0Sstevel@tonic-gate 	ecc_err_p->ecc_afar = lddphysio(ecc_err_p->ecc_ii_p.ecc_afar_pa);
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	ecc_err_p->ecc_offset = ((ecc_err_p->ecc_afsr &
341*0Sstevel@tonic-gate 				ecc_err_p->ecc_ii_p.ecc_offset_mask) >>
342*0Sstevel@tonic-gate 			ecc_err_p->ecc_ii_p.ecc_offset_shift) <<
343*0Sstevel@tonic-gate 		ecc_err_p->ecc_ii_p.ecc_size_log2;
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	ecc_err_p->ecc_aflt.flt_id = gethrtime();
346*0Sstevel@tonic-gate 	ecc_err_p->ecc_aflt.flt_stat = ecc_err_p->ecc_afsr;
347*0Sstevel@tonic-gate 	ecc_err_p->ecc_aflt.flt_addr = P2ALIGN(ecc_err_p->ecc_afar, 64) +
348*0Sstevel@tonic-gate 		ecc_err_p->ecc_offset;
349*0Sstevel@tonic-gate 	ecc_err_p->ecc_aflt.flt_bus_id = bus_id;
350*0Sstevel@tonic-gate 	ecc_err_p->ecc_aflt.flt_inst = CPU->cpu_id;
351*0Sstevel@tonic-gate 	ecc_err_p->ecc_aflt.flt_status = ECC_IOBUS;
352*0Sstevel@tonic-gate 	ecc_err_p->ecc_aflt.flt_in_memory = (pf_is_memory
353*0Sstevel@tonic-gate 			(ecc_err_p->ecc_afar >> MMU_PAGESHIFT))? 1: 0;
354*0Sstevel@tonic-gate 	ecc_err_p->ecc_aflt.flt_class = BUS_FAULT;
355*0Sstevel@tonic-gate }
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate /*
358*0Sstevel@tonic-gate  * ecc_pci_check: Called by ecc_err_handler() this function is responsible
359*0Sstevel@tonic-gate  * for calling pci_pbm_err_handler() for both sides of the schizo/psycho
360*0Sstevel@tonic-gate  * and calling their children error handlers(via ndi_fm_handler_dispatch()).
361*0Sstevel@tonic-gate  */
362*0Sstevel@tonic-gate static int
363*0Sstevel@tonic-gate ecc_pci_check(ecc_t *ecc_p, uint64_t fme_ena)
364*0Sstevel@tonic-gate {
365*0Sstevel@tonic-gate 	ddi_fm_error_t derr;
366*0Sstevel@tonic-gate 	int i;
367*0Sstevel@tonic-gate 	int ret;
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex));
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	bzero(&derr, sizeof (ddi_fm_error_t));
372*0Sstevel@tonic-gate 	derr.fme_version = DDI_FME_VERSION;
373*0Sstevel@tonic-gate 	derr.fme_ena = fme_ena;
374*0Sstevel@tonic-gate 	ret = DDI_FM_NONFATAL;
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	/*
377*0Sstevel@tonic-gate 	 * Need to report any PBM errors which may have caused or
378*0Sstevel@tonic-gate 	 * resulted from this error.
379*0Sstevel@tonic-gate 	 *
380*0Sstevel@tonic-gate 	 * Each psycho or schizo is represented by a pair of pci nodes
381*0Sstevel@tonic-gate 	 * in the device tree.
382*0Sstevel@tonic-gate 	 */
383*0Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
384*0Sstevel@tonic-gate 		dev_info_t *dip;
385*0Sstevel@tonic-gate 		pci_t *pci_p;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 		/* Make sure PBM PCI node exists */
388*0Sstevel@tonic-gate 		pci_p = ecc_p->ecc_pci_cmn_p->pci_p[i];
389*0Sstevel@tonic-gate 		if (pci_p == NULL)
390*0Sstevel@tonic-gate 			continue;
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 		dip = pci_p->pci_dip;
393*0Sstevel@tonic-gate 		if (pci_pbm_err_handler(dip, &derr, (void *)pci_p,
394*0Sstevel@tonic-gate 		    PCI_ECC_CALL) == DDI_FM_FATAL)
395*0Sstevel@tonic-gate 			ret = DDI_FM_FATAL;
396*0Sstevel@tonic-gate 	}
397*0Sstevel@tonic-gate 	if (ret == DDI_FM_FATAL)
398*0Sstevel@tonic-gate 		return (DDI_FM_FATAL);
399*0Sstevel@tonic-gate 	else
400*0Sstevel@tonic-gate 		return (DDI_FM_NONFATAL);
401*0Sstevel@tonic-gate }
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate /*
404*0Sstevel@tonic-gate  * Function used to handle and log IO detected ECC errors, can be called by
405*0Sstevel@tonic-gate  * ecc_intr and pci_err_callback(trap callback). Protected by pci_fm_mutex.
406*0Sstevel@tonic-gate  */
407*0Sstevel@tonic-gate int
408*0Sstevel@tonic-gate ecc_err_handler(ecc_errstate_t *ecc_err_p)
409*0Sstevel@tonic-gate {
410*0Sstevel@tonic-gate 	uint64_t pri_err, sec_err;
411*0Sstevel@tonic-gate 	ecc_intr_info_t *ecc_ii_p = &ecc_err_p->ecc_ii_p;
412*0Sstevel@tonic-gate 	ecc_t *ecc_p = ecc_ii_p->ecc_p;
413*0Sstevel@tonic-gate 	pci_t *pci_p;
414*0Sstevel@tonic-gate 	cb_t *cb_p;
415*0Sstevel@tonic-gate 	int fatal = 0;
416*0Sstevel@tonic-gate 	int nonfatal = 0;
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex));
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	pci_p = ecc_p->ecc_pci_cmn_p->pci_p[0];
421*0Sstevel@tonic-gate 	if (pci_p == NULL)
422*0Sstevel@tonic-gate 		pci_p = ecc_p->ecc_pci_cmn_p->pci_p[1];
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	cb_p = ecc_p->ecc_pci_cmn_p->pci_common_cb_p;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	ecc_errstate_get(ecc_err_p);
427*0Sstevel@tonic-gate 	pri_err = (ecc_err_p->ecc_afsr >> COMMON_ECC_UE_AFSR_PE_SHIFT) &
428*0Sstevel@tonic-gate 		COMMON_ECC_UE_AFSR_E_MASK;
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	sec_err = (ecc_err_p->ecc_afsr >> COMMON_ECC_UE_AFSR_SE_SHIFT) &
431*0Sstevel@tonic-gate 		COMMON_ECC_UE_AFSR_E_MASK;
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	switch (ecc_ii_p->ecc_type) {
434*0Sstevel@tonic-gate 	case CBNINTR_UE:
435*0Sstevel@tonic-gate 		if (pri_err) {
436*0Sstevel@tonic-gate 			ecc_err_p->ecc_aflt.flt_synd =
437*0Sstevel@tonic-gate 				pci_ecc_get_synd(ecc_err_p->ecc_afsr);
438*0Sstevel@tonic-gate 			ecc_err_p->ecc_pri = 1;
439*0Sstevel@tonic-gate 			pci_ecc_classify(pri_err, ecc_err_p);
440*0Sstevel@tonic-gate 			errorq_dispatch(pci_ecc_queue, (void *)ecc_err_p,
441*0Sstevel@tonic-gate 				sizeof (ecc_errstate_t),
442*0Sstevel@tonic-gate 				ecc_err_p->ecc_aflt.flt_panic);
443*0Sstevel@tonic-gate 		}
444*0Sstevel@tonic-gate 		if (sec_err) {
445*0Sstevel@tonic-gate 			ecc_errstate_t ecc_sec_err;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 			ecc_sec_err = *ecc_err_p;
448*0Sstevel@tonic-gate 			ecc_sec_err.ecc_pri = 0;
449*0Sstevel@tonic-gate 			pci_ecc_classify(sec_err, &ecc_sec_err);
450*0Sstevel@tonic-gate 			ecc_ereport_post(pci_p->pci_dip,
451*0Sstevel@tonic-gate 					&ecc_sec_err);
452*0Sstevel@tonic-gate 		}
453*0Sstevel@tonic-gate 		/*
454*0Sstevel@tonic-gate 		 * Check for PCI bus errors that may have resulted from or
455*0Sstevel@tonic-gate 		 * caused this UE.
456*0Sstevel@tonic-gate 		 */
457*0Sstevel@tonic-gate 		if (ecc_err_p->ecc_caller == PCI_ECC_CALL &&
458*0Sstevel@tonic-gate 		    ecc_pci_check(ecc_p, ecc_err_p->ecc_ena) == DDI_FM_FATAL)
459*0Sstevel@tonic-gate 			ecc_err_p->ecc_aflt.flt_panic = 1;
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 		if (ecc_err_p->ecc_aflt.flt_panic &&
462*0Sstevel@tonic-gate 				ecc_err_p->ecc_aflt.flt_in_memory)
463*0Sstevel@tonic-gate 			panic_aflt = ecc_err_p->ecc_aflt;
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 		if (ecc_err_p->ecc_aflt.flt_panic) {
466*0Sstevel@tonic-gate 			/*
467*0Sstevel@tonic-gate 			 * Disable all further errors since this will be
468*0Sstevel@tonic-gate 			 * treated as a fatal error.
469*0Sstevel@tonic-gate 			 */
470*0Sstevel@tonic-gate 			(void) ecc_disable_nowait(ecc_p);
471*0Sstevel@tonic-gate 			fatal++;
472*0Sstevel@tonic-gate 		}
473*0Sstevel@tonic-gate 		break;
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	case CBNINTR_CE:
476*0Sstevel@tonic-gate 		if (pri_err) {
477*0Sstevel@tonic-gate 			ecc_err_p->ecc_pri = 1;
478*0Sstevel@tonic-gate 			pci_ecc_classify(pri_err, ecc_err_p);
479*0Sstevel@tonic-gate 			ecc_err_p->ecc_aflt.flt_synd =
480*0Sstevel@tonic-gate 				pci_ecc_get_synd(ecc_err_p->ecc_afsr);
481*0Sstevel@tonic-gate 			ce_scrub(&ecc_err_p->ecc_aflt);
482*0Sstevel@tonic-gate 			errorq_dispatch(pci_ecc_queue, (void *)ecc_err_p,
483*0Sstevel@tonic-gate 					sizeof (ecc_errstate_t), ERRORQ_ASYNC);
484*0Sstevel@tonic-gate 			nonfatal++;
485*0Sstevel@tonic-gate 		}
486*0Sstevel@tonic-gate 		if (sec_err) {
487*0Sstevel@tonic-gate 			ecc_errstate_t ecc_sec_err;
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 			ecc_sec_err = *ecc_err_p;
490*0Sstevel@tonic-gate 			ecc_sec_err.ecc_pri = 0;
491*0Sstevel@tonic-gate 			pci_ecc_classify(sec_err, &ecc_sec_err);
492*0Sstevel@tonic-gate 			ecc_ereport_post(pci_p->pci_dip, &ecc_sec_err);
493*0Sstevel@tonic-gate 			nonfatal++;
494*0Sstevel@tonic-gate 		}
495*0Sstevel@tonic-gate 		break;
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	default:
498*0Sstevel@tonic-gate 		return (DDI_FM_OK);
499*0Sstevel@tonic-gate 	}
500*0Sstevel@tonic-gate 	/* Clear the errors */
501*0Sstevel@tonic-gate 	stdphysio(ecc_ii_p->ecc_afsr_pa, ecc_err_p->ecc_afsr);
502*0Sstevel@tonic-gate 	/*
503*0Sstevel@tonic-gate 	 * Clear the interrupt if called by ecc_intr and UE error or if called
504*0Sstevel@tonic-gate 	 * by ecc_intr and CE error and delayed CE interrupt handling is
505*0Sstevel@tonic-gate 	 * turned off.
506*0Sstevel@tonic-gate 	 */
507*0Sstevel@tonic-gate 	if ((ecc_err_p->ecc_caller == PCI_ECC_CALL &&
508*0Sstevel@tonic-gate 	    ecc_ii_p->ecc_type == CBNINTR_UE && !fatal) ||
509*0Sstevel@tonic-gate 	    (ecc_err_p->ecc_caller == PCI_ECC_CALL &&
510*0Sstevel@tonic-gate 	    ecc_ii_p->ecc_type == CBNINTR_CE && !ecc_ce_delayed))
511*0Sstevel@tonic-gate 		cb_clear_nintr(cb_p, ecc_ii_p->ecc_type);
512*0Sstevel@tonic-gate 	if (!fatal && !nonfatal)
513*0Sstevel@tonic-gate 		return (DDI_FM_OK);
514*0Sstevel@tonic-gate 	else if (fatal)
515*0Sstevel@tonic-gate 		return (DDI_FM_FATAL);
516*0Sstevel@tonic-gate 	return (DDI_FM_NONFATAL);
517*0Sstevel@tonic-gate }
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate /*
520*0Sstevel@tonic-gate  * Called from ecc_err_drain below for CBINTR_CE case.
521*0Sstevel@tonic-gate  */
522*0Sstevel@tonic-gate static int
523*0Sstevel@tonic-gate ecc_err_cexdiag(page_t *pp, ecc_errstate_t *ecc_err,
524*0Sstevel@tonic-gate 		errorq_elem_t *eqep)
525*0Sstevel@tonic-gate {
526*0Sstevel@tonic-gate 	struct async_flt *ecc = &ecc_err->ecc_aflt;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	if (!pp) {
529*0Sstevel@tonic-gate 		CE_XDIAG_SETSKIPCODE(ecc->flt_disp, CE_XDIAG_SKIP_NOPP);
530*0Sstevel@tonic-gate 		return (0);
531*0Sstevel@tonic-gate 	} else if (page_isretired(pp) || page_deteriorating(pp)) {
532*0Sstevel@tonic-gate 		CE_XDIAG_SETSKIPCODE(ecc->flt_disp, CE_XDIAG_SKIP_PAGEDET);
533*0Sstevel@tonic-gate 		return (0);
534*0Sstevel@tonic-gate 	}
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 	return (ce_scrub_xdiag_recirc(ecc, pci_ecc_queue, eqep,
537*0Sstevel@tonic-gate 	    offsetof(ecc_errstate_t, ecc_aflt)));
538*0Sstevel@tonic-gate }
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate /*
541*0Sstevel@tonic-gate  * Function used to drain pci_ecc_queue, either during panic or after softint
542*0Sstevel@tonic-gate  * is generated, to log IO detected ECC errors.
543*0Sstevel@tonic-gate  */
544*0Sstevel@tonic-gate /*ARGSUSED*/
545*0Sstevel@tonic-gate void
546*0Sstevel@tonic-gate ecc_err_drain(void *not_used, ecc_errstate_t *ecc_err, errorq_elem_t *eqep)
547*0Sstevel@tonic-gate {
548*0Sstevel@tonic-gate 	struct async_flt *ecc = &ecc_err->ecc_aflt;
549*0Sstevel@tonic-gate 	pci_t *pci_p = ecc_err->ecc_p->ecc_pci_cmn_p->pci_p[0];
550*0Sstevel@tonic-gate 	page_t *pp;
551*0Sstevel@tonic-gate 	int ecc_type = ecc_err->ecc_ii_p.ecc_type;
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 	if (pci_p == NULL)
554*0Sstevel@tonic-gate 		pci_p = ecc_err->ecc_p->ecc_pci_cmn_p->pci_p[1];
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	if (ecc->flt_class == RECIRC_BUS_FAULT) {
557*0Sstevel@tonic-gate 		/*
558*0Sstevel@tonic-gate 		 * Perform any additional actions that occur after the
559*0Sstevel@tonic-gate 		 * ecc_err_cexdiag below and post the ereport.
560*0Sstevel@tonic-gate 		 */
561*0Sstevel@tonic-gate 		ecc->flt_class = BUS_FAULT;
562*0Sstevel@tonic-gate 		ecc_err->ecc_err_type = flt_to_error_type(ecc);
563*0Sstevel@tonic-gate 		ecc_ereport_post(pci_p->pci_dip, ecc_err);
564*0Sstevel@tonic-gate 		return;
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	ecc_cpu_call(ecc, ecc_err->ecc_unum, (ecc_type == CBNINTR_UE) ?
568*0Sstevel@tonic-gate 			ECC_IO_UE : ECC_IO_CE);
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	pp = page_numtopp_nolock(ecc->flt_addr >> MMU_PAGESHIFT);
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	switch (ecc_type) {
573*0Sstevel@tonic-gate 	case CBNINTR_UE:
574*0Sstevel@tonic-gate 		if (pp && ecc_err->ecc_pg_ret == 1) {
575*0Sstevel@tonic-gate 			page_settoxic(pp, PAGE_IS_FAULTY);
576*0Sstevel@tonic-gate 			(void) page_retire(pp, PAGE_IS_TOXIC);
577*0Sstevel@tonic-gate 		}
578*0Sstevel@tonic-gate 		ecc_err->ecc_err_type = CE_DISP_UNKNOWN;
579*0Sstevel@tonic-gate 		break;
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 	case CBNINTR_CE:
582*0Sstevel@tonic-gate 		/*
583*0Sstevel@tonic-gate 		 * Setup timeout (if CE detected via interrupt) to
584*0Sstevel@tonic-gate 		 * re-enable CE interrupts if no more CEs are detected.
585*0Sstevel@tonic-gate 		 * This is to protect against CE storms.
586*0Sstevel@tonic-gate 		 */
587*0Sstevel@tonic-gate 		if (ecc_ce_delayed &&
588*0Sstevel@tonic-gate 		    ecc_err->ecc_caller == PCI_ECC_CALL &&
589*0Sstevel@tonic-gate 		    ecc_err->ecc_p->ecc_to_id == 0) {
590*0Sstevel@tonic-gate 			ecc_err->ecc_p->ecc_to_id = timeout(ecc_delayed_ce,
591*0Sstevel@tonic-gate 			    (void *)ecc_err->ecc_p,
592*0Sstevel@tonic-gate 			    drv_usectohz((clock_t)ecc_ce_delay_secs *
593*0Sstevel@tonic-gate 			    MICROSEC));
594*0Sstevel@tonic-gate 		}
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 		/* ecc_err_cexdiag returns nonzero to recirculate */
597*0Sstevel@tonic-gate 		if (CE_XDIAG_EXT_ALG_APPLIED(ecc->flt_disp) &&
598*0Sstevel@tonic-gate 		    ecc_err_cexdiag(pp, ecc_err, eqep))
599*0Sstevel@tonic-gate 			return;
600*0Sstevel@tonic-gate 		ecc_err->ecc_err_type = flt_to_error_type(ecc);
601*0Sstevel@tonic-gate 		break;
602*0Sstevel@tonic-gate 	}
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	ecc_ereport_post(pci_p->pci_dip, ecc_err);
605*0Sstevel@tonic-gate }
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate static void
608*0Sstevel@tonic-gate ecc_delayed_ce(void *arg)
609*0Sstevel@tonic-gate {
610*0Sstevel@tonic-gate 	ecc_t *ecc_p = (ecc_t *)arg;
611*0Sstevel@tonic-gate 	pci_common_t *cmn_p;
612*0Sstevel@tonic-gate 	cb_t *cb_p;
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	ASSERT(ecc_p);
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	cmn_p = ecc_p->ecc_pci_cmn_p;
617*0Sstevel@tonic-gate 	cb_p = cmn_p->pci_common_cb_p;
618*0Sstevel@tonic-gate 	/*
619*0Sstevel@tonic-gate 	 * If no more CE errors are found then enable interrupts(by
620*0Sstevel@tonic-gate 	 * clearing the previous interrupt), else send in for logging
621*0Sstevel@tonic-gate 	 * and the timeout should be set again.
622*0Sstevel@tonic-gate 	 */
623*0Sstevel@tonic-gate 	ecc_p->ecc_to_id = 0;
624*0Sstevel@tonic-gate 	if (!((ecc_read_afsr(&ecc_p->ecc_ce) >>
625*0Sstevel@tonic-gate 	    COMMON_ECC_UE_AFSR_PE_SHIFT) & COMMON_ECC_UE_AFSR_E_MASK)) {
626*0Sstevel@tonic-gate 		cb_clear_nintr(cb_p, ecc_p->ecc_ce.ecc_type);
627*0Sstevel@tonic-gate 	} else {
628*0Sstevel@tonic-gate 		ecc_errstate_t ecc_err;
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 		bzero(&ecc_err, sizeof (ecc_errstate_t));
631*0Sstevel@tonic-gate 		ecc_err.ecc_ena = fm_ena_generate(0, FM_ENA_FMT1);
632*0Sstevel@tonic-gate 		ecc_err.ecc_ii_p = ecc_p->ecc_ce;
633*0Sstevel@tonic-gate 		ecc_err.ecc_p = ecc_p;
634*0Sstevel@tonic-gate 		ecc_err.ecc_caller = PCI_ECC_CALL;
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 		mutex_enter(&cmn_p->pci_fm_mutex);
637*0Sstevel@tonic-gate 		(void) ecc_err_handler(&ecc_err);
638*0Sstevel@tonic-gate 		mutex_exit(&cmn_p->pci_fm_mutex);
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate }
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate /*
643*0Sstevel@tonic-gate  * Function used to post IO detected ECC ereports.
644*0Sstevel@tonic-gate  */
645*0Sstevel@tonic-gate static void
646*0Sstevel@tonic-gate ecc_ereport_post(dev_info_t *dip, ecc_errstate_t *ecc_err)
647*0Sstevel@tonic-gate {
648*0Sstevel@tonic-gate 	char buf[FM_MAX_CLASS], dev_path[MAXPATHLEN], *ptr;
649*0Sstevel@tonic-gate 	struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
650*0Sstevel@tonic-gate 	nvlist_t *ereport, *detector;
651*0Sstevel@tonic-gate 	nv_alloc_t *nva;
652*0Sstevel@tonic-gate 	errorq_elem_t *eqep;
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 	/*
655*0Sstevel@tonic-gate 	 * We do not use ddi_fm_ereport_post because we need to set a
656*0Sstevel@tonic-gate 	 * special detector here. Since we do not have a device path for
657*0Sstevel@tonic-gate 	 * the bridge chip we use what we think it should be to aid in
658*0Sstevel@tonic-gate 	 * diagnosis. This path fmri is created by pci_fmri_create()
659*0Sstevel@tonic-gate 	 * during initialization.
660*0Sstevel@tonic-gate 	 */
661*0Sstevel@tonic-gate 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s", DDI_IO_CLASS,
662*0Sstevel@tonic-gate 	    ecc_err->ecc_bridge_type, ecc_err->ecc_aflt.flt_erpt_class);
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	ecc_err->ecc_ena = ecc_err->ecc_ena ? ecc_err->ecc_ena :
665*0Sstevel@tonic-gate 		fm_ena_generate(0, FM_ENA_FMT1);
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	eqep = errorq_reserve(fmhdl->fh_errorq);
668*0Sstevel@tonic-gate 	if (eqep == NULL)
669*0Sstevel@tonic-gate 		return;
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	ereport = errorq_elem_nvl(fmhdl->fh_errorq, eqep);
672*0Sstevel@tonic-gate 	nva = errorq_elem_nva(fmhdl->fh_errorq, eqep);
673*0Sstevel@tonic-gate 	detector = fm_nvlist_create(nva);
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	ASSERT(ereport);
676*0Sstevel@tonic-gate 	ASSERT(nva);
677*0Sstevel@tonic-gate 	ASSERT(detector);
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	ddi_pathname(dip, dev_path);
680*0Sstevel@tonic-gate 	ptr = strrchr(dev_path, (int)',');
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	if (ptr)
683*0Sstevel@tonic-gate 		*ptr = '\0';
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, dev_path, NULL);
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	if (ecc_err->ecc_pri) {
688*0Sstevel@tonic-gate 		if ((ecc_err->ecc_fmri = fm_nvlist_create(nva)) != NULL)
689*0Sstevel@tonic-gate 			fm_fmri_mem_set(ecc_err->ecc_fmri,
690*0Sstevel@tonic-gate 			    FM_MEM_SCHEME_VERSION, NULL, ecc_err->ecc_unum,
691*0Sstevel@tonic-gate 			    NULL);
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 		fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
694*0Sstevel@tonic-gate 		    ecc_err->ecc_ena, detector,
695*0Sstevel@tonic-gate 		    PCI_ECC_AFSR, DATA_TYPE_UINT64, ecc_err->ecc_afsr,
696*0Sstevel@tonic-gate 		    PCI_ECC_AFAR, DATA_TYPE_UINT64, ecc_err->ecc_aflt.flt_addr,
697*0Sstevel@tonic-gate 		    PCI_ECC_CTRL, DATA_TYPE_UINT64, ecc_err->ecc_ctrl,
698*0Sstevel@tonic-gate 		    PCI_ECC_SYND, DATA_TYPE_UINT16, ecc_err->ecc_aflt.flt_synd,
699*0Sstevel@tonic-gate 		    PCI_ECC_TYPE, DATA_TYPE_STRING, ecc_err->ecc_err_type,
700*0Sstevel@tonic-gate 		    PCI_ECC_DISP, DATA_TYPE_UINT64, ecc_err->ecc_aflt.flt_disp,
701*0Sstevel@tonic-gate 		    PCI_ECC_RESOURCE, DATA_TYPE_NVLIST, ecc_err->ecc_fmri,
702*0Sstevel@tonic-gate 		    NULL);
703*0Sstevel@tonic-gate 	} else {
704*0Sstevel@tonic-gate 		fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
705*0Sstevel@tonic-gate 		    ecc_err->ecc_ena, detector,
706*0Sstevel@tonic-gate 		    PCI_ECC_AFSR, DATA_TYPE_UINT64, ecc_err->ecc_afsr,
707*0Sstevel@tonic-gate 		    PCI_ECC_CTRL, DATA_TYPE_UINT64, ecc_err->ecc_ctrl,
708*0Sstevel@tonic-gate 		    NULL);
709*0Sstevel@tonic-gate 	}
710*0Sstevel@tonic-gate 	errorq_commit(fmhdl->fh_errorq, eqep, ERRORQ_ASYNC);
711*0Sstevel@tonic-gate }
712