17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
539470729Skd93003 * Common Development and Distribution License (the "License").
639470729Skd93003 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*392e836bSGavin Maltby * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate * PCI ECC support
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/systm.h> /* for strrchr */
317c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
327c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
337c478bd9Sstevel@tonic-gate #include <sys/intr.h>
347c478bd9Sstevel@tonic-gate #include <sys/async.h> /* struct async_flt */
357c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
367c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h>
397c478bd9Sstevel@tonic-gate #include <sys/fm/util.h>
407c478bd9Sstevel@tonic-gate #include <sys/fm/io/pci.h>
417c478bd9Sstevel@tonic-gate #include <sys/fm/io/sun4upci.h>
427c478bd9Sstevel@tonic-gate #include <sys/fm/io/ddi.h>
437c478bd9Sstevel@tonic-gate #include <sys/pci/pci_obj.h> /* ld/st physio */
447c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
457c478bd9Sstevel@tonic-gate #include <sys/errclassify.h>
46d00f0155Sayznaga #include <sys/cpu_module.h>
47d00f0155Sayznaga #include <sys/async.h>
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate static void ecc_disable(ecc_t *, int);
527c478bd9Sstevel@tonic-gate static void ecc_delayed_ce(void *);
537c478bd9Sstevel@tonic-gate static uint64_t ecc_read_afsr(ecc_intr_info_t *);
547c478bd9Sstevel@tonic-gate static void ecc_ereport_post(dev_info_t *dip, ecc_errstate_t *ecc_err);
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate clock_t pci_ecc_panic_delay = 200;
577c478bd9Sstevel@tonic-gate int ecc_ce_delay_secs = 6; /* number of sec to delay reenabling of CEs */
587c478bd9Sstevel@tonic-gate int ecc_ce_delayed = 1; /* global for enabling/disabling CE delay */
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate void
ecc_create(pci_t * pci_p)617c478bd9Sstevel@tonic-gate ecc_create(pci_t *pci_p)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate #ifdef DEBUG
647c478bd9Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip;
657c478bd9Sstevel@tonic-gate #endif
667c478bd9Sstevel@tonic-gate uint64_t cb_base_pa = pci_p->pci_cb_p->cb_base_pa;
677c478bd9Sstevel@tonic-gate ecc_t *ecc_p;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate ecc_p = (ecc_t *)kmem_zalloc(sizeof (ecc_t), KM_SLEEP);
707c478bd9Sstevel@tonic-gate ecc_p->ecc_pci_cmn_p = pci_p->pci_common_p;
717c478bd9Sstevel@tonic-gate pci_p->pci_ecc_p = ecc_p;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_p = ecc_p;
747c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_type = CBNINTR_UE;
757c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_p = ecc_p;
767c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_type = CBNINTR_CE;
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate pci_ecc_setup(ecc_p);
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate * Determine the virtual addresses of the streaming cache
827c478bd9Sstevel@tonic-gate * control/status and flush registers.
837c478bd9Sstevel@tonic-gate */
847c478bd9Sstevel@tonic-gate ecc_p->ecc_csr_pa = cb_base_pa + COMMON_ECC_CSR_OFFSET;
857c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_afsr_pa = cb_base_pa + COMMON_UE_AFSR_OFFSET;
867c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_afar_pa = cb_base_pa + COMMON_UE_AFAR_OFFSET;
877c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_afsr_pa = cb_base_pa + COMMON_CE_AFSR_OFFSET;
887c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_afar_pa = cb_base_pa + COMMON_CE_AFAR_OFFSET;
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "ecc_create: csr=%x\n", ecc_p->ecc_csr_pa);
917c478bd9Sstevel@tonic-gate DEBUG2(DBG_ATTACH, dip, "ecc_create: ue_afsr=%x, ue_afar=%x\n",
927c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_afsr_pa, ecc_p->ecc_ue.ecc_afar_pa);
937c478bd9Sstevel@tonic-gate DEBUG2(DBG_ATTACH, dip, "ecc_create: ce_afsr=%x, ce_afar=%x\n",
947c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_afsr_pa, ecc_p->ecc_ce.ecc_afar_pa);
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate ecc_configure(pci_p);
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate * Register routines to be called from system error handling code.
1007c478bd9Sstevel@tonic-gate */
1017c478bd9Sstevel@tonic-gate bus_func_register(BF_TYPE_ERRDIS, (busfunc_t)ecc_disable_nowait, ecc_p);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate int
ecc_register_intr(pci_t * pci_p)1057c478bd9Sstevel@tonic-gate ecc_register_intr(pci_t *pci_p)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate ecc_t *ecc_p = pci_p->pci_ecc_p;
1087c478bd9Sstevel@tonic-gate int ret;
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate * Install the UE and CE error interrupt handlers.
1127c478bd9Sstevel@tonic-gate */
1137c478bd9Sstevel@tonic-gate if ((ret = pci_ecc_add_intr(pci_p, CBNINTR_UE, &ecc_p->ecc_ue)) !=
1147c478bd9Sstevel@tonic-gate DDI_SUCCESS)
1157c478bd9Sstevel@tonic-gate return (ret);
1167c478bd9Sstevel@tonic-gate if ((ret = pci_ecc_add_intr(pci_p, CBNINTR_CE, &ecc_p->ecc_ce)) !=
1177c478bd9Sstevel@tonic-gate DDI_SUCCESS)
1187c478bd9Sstevel@tonic-gate return (ret);
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate void
ecc_destroy(pci_t * pci_p)1247c478bd9Sstevel@tonic-gate ecc_destroy(pci_t *pci_p)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate ecc_t *ecc_p = pci_p->pci_ecc_p;
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate DEBUG0(DBG_DETACH, pci_p->pci_dip, "ecc_destroy:\n");
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate * Disable UE and CE ECC error interrupts.
1327c478bd9Sstevel@tonic-gate */
1337c478bd9Sstevel@tonic-gate ecc_disable_wait(ecc_p);
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate * Remove the ECC interrupt handlers.
1377c478bd9Sstevel@tonic-gate */
1387c478bd9Sstevel@tonic-gate pci_ecc_rem_intr(pci_p, CBNINTR_UE, &ecc_p->ecc_ue);
1397c478bd9Sstevel@tonic-gate pci_ecc_rem_intr(pci_p, CBNINTR_CE, &ecc_p->ecc_ce);
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate * Unregister our error handling functions.
1437c478bd9Sstevel@tonic-gate */
1447c478bd9Sstevel@tonic-gate bus_func_unregister(BF_TYPE_ERRDIS,
1457c478bd9Sstevel@tonic-gate (busfunc_t)ecc_disable_nowait, ecc_p);
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate * If a timer has been set, unset it.
1487c478bd9Sstevel@tonic-gate */
1497c478bd9Sstevel@tonic-gate (void) untimeout(ecc_p->ecc_to_id);
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate kmem_free(ecc_p, sizeof (ecc_t));
1527c478bd9Sstevel@tonic-gate pci_p->pci_ecc_p = NULL;
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate void
ecc_configure(pci_t * pci_p)1567c478bd9Sstevel@tonic-gate ecc_configure(pci_t *pci_p)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate ecc_t *ecc_p = pci_p->pci_ecc_p;
1597c478bd9Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip;
1607c478bd9Sstevel@tonic-gate uint64_t l;
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate * Clear any pending ECC errors.
1647c478bd9Sstevel@tonic-gate */
1657c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "ecc_configure: clearing UE and CE errors\n");
1667c478bd9Sstevel@tonic-gate l = (COMMON_ECC_UE_AFSR_E_MASK << COMMON_ECC_UE_AFSR_PE_SHIFT) |
1677c478bd9Sstevel@tonic-gate (COMMON_ECC_UE_AFSR_E_MASK << COMMON_ECC_UE_AFSR_SE_SHIFT);
1687c478bd9Sstevel@tonic-gate stdphysio(ecc_p->ecc_ue.ecc_afsr_pa, l);
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate l = (COMMON_ECC_CE_AFSR_E_MASK << COMMON_ECC_CE_AFSR_PE_SHIFT) |
1717c478bd9Sstevel@tonic-gate (COMMON_ECC_CE_AFSR_E_MASK << COMMON_ECC_CE_AFSR_SE_SHIFT);
1727c478bd9Sstevel@tonic-gate stdphysio(ecc_p->ecc_ce.ecc_afsr_pa, l);
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate * Enable ECC error detections via the control register.
1767c478bd9Sstevel@tonic-gate */
1777c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "ecc_configure: enabling UE CE detection\n");
1787c478bd9Sstevel@tonic-gate l = COMMON_ECC_CTRL_ECC_EN;
1797c478bd9Sstevel@tonic-gate if (ecc_error_intr_enable)
1807c478bd9Sstevel@tonic-gate l |= COMMON_ECC_CTRL_UE_INTEN | COMMON_ECC_CTRL_CE_INTEN;
1817c478bd9Sstevel@tonic-gate stdphysio(ecc_p->ecc_csr_pa, l);
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate void
ecc_enable_intr(pci_t * pci_p)1857c478bd9Sstevel@tonic-gate ecc_enable_intr(pci_t *pci_p)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate cb_enable_nintr(pci_p, CBNINTR_UE);
1887c478bd9Sstevel@tonic-gate cb_enable_nintr(pci_p, CBNINTR_CE);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate void
ecc_disable_wait(ecc_t * ecc_p)1927c478bd9Sstevel@tonic-gate ecc_disable_wait(ecc_t *ecc_p)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate ecc_disable(ecc_p, IB_INTR_WAIT);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate uint_t
ecc_disable_nowait(ecc_t * ecc_p)1987c478bd9Sstevel@tonic-gate ecc_disable_nowait(ecc_t *ecc_p)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate ecc_disable(ecc_p, IB_INTR_NOWAIT);
2017c478bd9Sstevel@tonic-gate return (BF_NONE);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate static void
ecc_disable(ecc_t * ecc_p,int wait)2057c478bd9Sstevel@tonic-gate ecc_disable(ecc_t *ecc_p, int wait)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate cb_t *cb_p = ecc_p->ecc_pci_cmn_p->pci_common_cb_p;
2087c478bd9Sstevel@tonic-gate uint64_t csr_pa = ecc_p->ecc_csr_pa;
2097c478bd9Sstevel@tonic-gate uint64_t csr = lddphysio(csr_pa);
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate csr &= ~(COMMON_ECC_CTRL_UE_INTEN | COMMON_ECC_CTRL_CE_INTEN);
2127c478bd9Sstevel@tonic-gate stdphysio(csr_pa, csr);
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate cb_disable_nintr(cb_p, CBNINTR_UE, wait);
2157c478bd9Sstevel@tonic-gate cb_disable_nintr(cb_p, CBNINTR_CE, wait);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate * I/O ECC error handling:
2207c478bd9Sstevel@tonic-gate *
2217c478bd9Sstevel@tonic-gate * Below are the generic functions that handle PCI(pcisch, pcipsy) detected
2227c478bd9Sstevel@tonic-gate * ECC errors.
2237c478bd9Sstevel@tonic-gate *
2247c478bd9Sstevel@tonic-gate * The registered interrupt handler for both pcisch and pcipsy is ecc_intr(),
2257c478bd9Sstevel@tonic-gate * it's function is to receive the error, capture some state, and pass that on
2267c478bd9Sstevel@tonic-gate * to the ecc_err_handler() for reporting purposes.
2277c478bd9Sstevel@tonic-gate *
2287c478bd9Sstevel@tonic-gate * ecc_err_handler() gathers more state(via ecc_errstate_get) and attempts
2297c478bd9Sstevel@tonic-gate * to handle and report the error. ecc_err_handler() must determine if we need
2307c478bd9Sstevel@tonic-gate * to panic due to this error (via pci_ecc_classify, which also decodes the
2317c478bd9Sstevel@tonic-gate * ECC afsr), and if any side effects exist that may have caused or are due
2327c478bd9Sstevel@tonic-gate * to this error. PBM errors related to the ECC error may exist, to report
2337c478bd9Sstevel@tonic-gate * them we call pci_pbm_err_handler() and call ndi_fm_handler_dispatch() so
2347c478bd9Sstevel@tonic-gate * that the child devices can log their pci errors.
2357c478bd9Sstevel@tonic-gate *
2367c478bd9Sstevel@tonic-gate * To report the error we must also get the syndrome and unum, which can not
2377c478bd9Sstevel@tonic-gate * be done in high level interrupted context. Therefore we have an error
2387c478bd9Sstevel@tonic-gate * queue(pci_ecc_queue) which we dispatch errors to, to report the errors
2397c478bd9Sstevel@tonic-gate * (ecc_err_drain()).
2407c478bd9Sstevel@tonic-gate *
2417c478bd9Sstevel@tonic-gate * ecc_err_drain() will be called when either the softint is triggered
2427c478bd9Sstevel@tonic-gate * or the system is panicing. Either way it will gather more information
2437c478bd9Sstevel@tonic-gate * about the error from the CPU(via ecc_cpu_call(), ecc.c), attempt to
2447c478bd9Sstevel@tonic-gate * retire the faulty page(if error is a UE), and report the detected error.
2457c478bd9Sstevel@tonic-gate *
2467c478bd9Sstevel@tonic-gate * ecc_delayed_ce() is called via timeout from ecc_err_handler() following
2477c478bd9Sstevel@tonic-gate * the receipt of a CE interrupt. It will be called after 6ms and check to
2487c478bd9Sstevel@tonic-gate * see if any new CEs are present, if so we will log and another timeout will
2497c478bd9Sstevel@tonic-gate * be set by(ecc_err_handler()). If no CEs are present then it will re-enable
2507c478bd9Sstevel@tonic-gate * CEs by clearing the previous interrupt. This is to keep the system going
2517c478bd9Sstevel@tonic-gate * in the event of a CE storm.
2527c478bd9Sstevel@tonic-gate */
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate * Function used to get ECC AFSR register
2567c478bd9Sstevel@tonic-gate */
2577c478bd9Sstevel@tonic-gate static uint64_t
ecc_read_afsr(ecc_intr_info_t * ecc_ii_p)2587c478bd9Sstevel@tonic-gate ecc_read_afsr(ecc_intr_info_t *ecc_ii_p)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate uint_t i;
2617c478bd9Sstevel@tonic-gate uint64_t afsr = 0ull;
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate ASSERT((ecc_ii_p->ecc_type == CBNINTR_UE) ||
2647c478bd9Sstevel@tonic-gate (ecc_ii_p->ecc_type == CBNINTR_CE));
2657c478bd9Sstevel@tonic-gate if (!ecc_ii_p->ecc_errpndg_mask)
2667c478bd9Sstevel@tonic-gate return (lddphysio(ecc_ii_p->ecc_afsr_pa));
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate for (i = 0; i < pci_ecc_afsr_retries; i++) {
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate * If we timeout, the logging routine will
2727c478bd9Sstevel@tonic-gate * know because it will see the ERRPNDG bits
2737c478bd9Sstevel@tonic-gate * set in the AFSR.
2747c478bd9Sstevel@tonic-gate */
2757c478bd9Sstevel@tonic-gate afsr = lddphysio(ecc_ii_p->ecc_afsr_pa);
2767c478bd9Sstevel@tonic-gate if ((afsr & ecc_ii_p->ecc_errpndg_mask) == 0)
2777c478bd9Sstevel@tonic-gate break;
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate return (afsr);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate * IO detected ECC error interrupt handler, calls ecc_err_handler to post
2847c478bd9Sstevel@tonic-gate * error reports and handle the interrupt. Re-entry into ecc_err_handler
2857c478bd9Sstevel@tonic-gate * is protected by the per-chip mutex pci_fm_mutex.
2867c478bd9Sstevel@tonic-gate */
2877c478bd9Sstevel@tonic-gate uint_t
ecc_intr(caddr_t a)2887c478bd9Sstevel@tonic-gate ecc_intr(caddr_t a)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate ecc_intr_info_t *ecc_ii_p = (ecc_intr_info_t *)a;
2917c478bd9Sstevel@tonic-gate ecc_t *ecc_p = ecc_ii_p->ecc_p;
2927c478bd9Sstevel@tonic-gate pci_common_t *cmn_p = ecc_p->ecc_pci_cmn_p;
2937c478bd9Sstevel@tonic-gate ecc_errstate_t ecc_err;
2947c478bd9Sstevel@tonic-gate int ret = DDI_FM_OK;
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate bzero(&ecc_err, sizeof (ecc_errstate_t));
2977c478bd9Sstevel@tonic-gate ecc_err.ecc_ena = fm_ena_generate(0, FM_ENA_FMT1);
2987c478bd9Sstevel@tonic-gate ecc_err.ecc_ii_p = *ecc_ii_p;
2997c478bd9Sstevel@tonic-gate ecc_err.ecc_p = ecc_p;
3007c478bd9Sstevel@tonic-gate ecc_err.ecc_caller = PCI_ECC_CALL;
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate mutex_enter(&cmn_p->pci_fm_mutex);
3037c478bd9Sstevel@tonic-gate ret = ecc_err_handler(&ecc_err);
3047c478bd9Sstevel@tonic-gate mutex_exit(&cmn_p->pci_fm_mutex);
3057c478bd9Sstevel@tonic-gate if (ret == DDI_FM_FATAL) {
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate * Need delay here to allow CPUs to handle related traps,
3087c478bd9Sstevel@tonic-gate * such as FRUs for USIIIi systems.
3097c478bd9Sstevel@tonic-gate */
3107c478bd9Sstevel@tonic-gate DELAY(pci_ecc_panic_delay);
3117c478bd9Sstevel@tonic-gate fm_panic("Fatal PCI UE Error");
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate * Function used to gather IO ECC error state.
3197c478bd9Sstevel@tonic-gate */
3207c478bd9Sstevel@tonic-gate static void
ecc_errstate_get(ecc_errstate_t * ecc_err_p)3217c478bd9Sstevel@tonic-gate ecc_errstate_get(ecc_errstate_t *ecc_err_p)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate ecc_t *ecc_p;
3247c478bd9Sstevel@tonic-gate uint_t bus_id;
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate ASSERT(ecc_err_p);
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate ecc_p = ecc_err_p->ecc_ii_p.ecc_p;
3297c478bd9Sstevel@tonic-gate bus_id = ecc_p->ecc_pci_cmn_p->pci_common_id;
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex));
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate * Read the fault registers.
3347c478bd9Sstevel@tonic-gate */
3357c478bd9Sstevel@tonic-gate ecc_err_p->ecc_afsr = ecc_read_afsr(&ecc_err_p->ecc_ii_p);
3367c478bd9Sstevel@tonic-gate ecc_err_p->ecc_afar = lddphysio(ecc_err_p->ecc_ii_p.ecc_afar_pa);
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate ecc_err_p->ecc_offset = ((ecc_err_p->ecc_afsr &
3397c478bd9Sstevel@tonic-gate ecc_err_p->ecc_ii_p.ecc_offset_mask) >>
3407c478bd9Sstevel@tonic-gate ecc_err_p->ecc_ii_p.ecc_offset_shift) <<
3417c478bd9Sstevel@tonic-gate ecc_err_p->ecc_ii_p.ecc_size_log2;
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_id = gethrtime();
3447c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_stat = ecc_err_p->ecc_afsr;
3457c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_addr = P2ALIGN(ecc_err_p->ecc_afar, 64) +
3467c478bd9Sstevel@tonic-gate ecc_err_p->ecc_offset;
3477c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_bus_id = bus_id;
3487c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_inst = CPU->cpu_id;
3497c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_status = ECC_IOBUS;
350*392e836bSGavin Maltby ecc_err_p->ecc_aflt.flt_in_memory =
351*392e836bSGavin Maltby (pf_is_memory(ecc_err_p->ecc_afar >> MMU_PAGESHIFT))? 1: 0;
3527c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_class = BUS_FAULT;
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate /*
3567c478bd9Sstevel@tonic-gate * ecc_pci_check: Called by ecc_err_handler() this function is responsible
3577c478bd9Sstevel@tonic-gate * for calling pci_pbm_err_handler() for both sides of the schizo/psycho
3587c478bd9Sstevel@tonic-gate * and calling their children error handlers(via ndi_fm_handler_dispatch()).
3597c478bd9Sstevel@tonic-gate */
3607c478bd9Sstevel@tonic-gate static int
ecc_pci_check(ecc_t * ecc_p,uint64_t fme_ena)3617c478bd9Sstevel@tonic-gate ecc_pci_check(ecc_t *ecc_p, uint64_t fme_ena)
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate ddi_fm_error_t derr;
3647c478bd9Sstevel@tonic-gate int i;
3657c478bd9Sstevel@tonic-gate int ret;
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex));
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate bzero(&derr, sizeof (ddi_fm_error_t));
3707c478bd9Sstevel@tonic-gate derr.fme_version = DDI_FME_VERSION;
3717c478bd9Sstevel@tonic-gate derr.fme_ena = fme_ena;
3727c478bd9Sstevel@tonic-gate ret = DDI_FM_NONFATAL;
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate * Need to report any PBM errors which may have caused or
3767c478bd9Sstevel@tonic-gate * resulted from this error.
3777c478bd9Sstevel@tonic-gate *
3787c478bd9Sstevel@tonic-gate * Each psycho or schizo is represented by a pair of pci nodes
3797c478bd9Sstevel@tonic-gate * in the device tree.
3807c478bd9Sstevel@tonic-gate */
3817c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) {
3827c478bd9Sstevel@tonic-gate dev_info_t *dip;
3837c478bd9Sstevel@tonic-gate pci_t *pci_p;
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate /* Make sure PBM PCI node exists */
3867c478bd9Sstevel@tonic-gate pci_p = ecc_p->ecc_pci_cmn_p->pci_p[i];
3877c478bd9Sstevel@tonic-gate if (pci_p == NULL)
3887c478bd9Sstevel@tonic-gate continue;
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate dip = pci_p->pci_dip;
3917c478bd9Sstevel@tonic-gate if (pci_pbm_err_handler(dip, &derr, (void *)pci_p,
3927c478bd9Sstevel@tonic-gate PCI_ECC_CALL) == DDI_FM_FATAL)
3937c478bd9Sstevel@tonic-gate ret = DDI_FM_FATAL;
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate if (ret == DDI_FM_FATAL)
3967c478bd9Sstevel@tonic-gate return (DDI_FM_FATAL);
3977c478bd9Sstevel@tonic-gate else
3987c478bd9Sstevel@tonic-gate return (DDI_FM_NONFATAL);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate * Function used to handle and log IO detected ECC errors, can be called by
4037c478bd9Sstevel@tonic-gate * ecc_intr and pci_err_callback(trap callback). Protected by pci_fm_mutex.
4047c478bd9Sstevel@tonic-gate */
4057c478bd9Sstevel@tonic-gate int
ecc_err_handler(ecc_errstate_t * ecc_err_p)4067c478bd9Sstevel@tonic-gate ecc_err_handler(ecc_errstate_t *ecc_err_p)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate uint64_t pri_err, sec_err;
4097c478bd9Sstevel@tonic-gate ecc_intr_info_t *ecc_ii_p = &ecc_err_p->ecc_ii_p;
4107c478bd9Sstevel@tonic-gate ecc_t *ecc_p = ecc_ii_p->ecc_p;
4117c478bd9Sstevel@tonic-gate pci_t *pci_p;
4127c478bd9Sstevel@tonic-gate cb_t *cb_p;
4137c478bd9Sstevel@tonic-gate int fatal = 0;
4147c478bd9Sstevel@tonic-gate int nonfatal = 0;
41539470729Skd93003 ecc_errstate_t ecc_sec_err;
41639470729Skd93003 uint64_t sec_tmp;
41739470729Skd93003 int i;
41839470729Skd93003 uint64_t afsr_err[] = { COMMON_ECC_AFSR_E_PIO,
41939470729Skd93003 COMMON_ECC_AFSR_E_DRD,
42039470729Skd93003 COMMON_ECC_AFSR_E_DWR };
42139470729Skd93003
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex));
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate pci_p = ecc_p->ecc_pci_cmn_p->pci_p[0];
4267c478bd9Sstevel@tonic-gate if (pci_p == NULL)
4277c478bd9Sstevel@tonic-gate pci_p = ecc_p->ecc_pci_cmn_p->pci_p[1];
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate cb_p = ecc_p->ecc_pci_cmn_p->pci_common_cb_p;
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate ecc_errstate_get(ecc_err_p);
4327c478bd9Sstevel@tonic-gate pri_err = (ecc_err_p->ecc_afsr >> COMMON_ECC_UE_AFSR_PE_SHIFT) &
4337c478bd9Sstevel@tonic-gate COMMON_ECC_UE_AFSR_E_MASK;
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate sec_err = (ecc_err_p->ecc_afsr >> COMMON_ECC_UE_AFSR_SE_SHIFT) &
4367c478bd9Sstevel@tonic-gate COMMON_ECC_UE_AFSR_E_MASK;
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate switch (ecc_ii_p->ecc_type) {
4397c478bd9Sstevel@tonic-gate case CBNINTR_UE:
4407c478bd9Sstevel@tonic-gate if (pri_err) {
4417c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_synd =
4427c478bd9Sstevel@tonic-gate pci_ecc_get_synd(ecc_err_p->ecc_afsr);
4437c478bd9Sstevel@tonic-gate ecc_err_p->ecc_pri = 1;
4447c478bd9Sstevel@tonic-gate pci_ecc_classify(pri_err, ecc_err_p);
4457c478bd9Sstevel@tonic-gate errorq_dispatch(pci_ecc_queue, (void *)ecc_err_p,
4467c478bd9Sstevel@tonic-gate sizeof (ecc_errstate_t),
4477c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_panic);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate if (sec_err) {
4507c478bd9Sstevel@tonic-gate ecc_sec_err = *ecc_err_p;
4517c478bd9Sstevel@tonic-gate ecc_sec_err.ecc_pri = 0;
4524fd7ecabSdilpreet /*
45339470729Skd93003 * Secondary errors are cumulative so we need to loop
4544fd7ecabSdilpreet * through to capture them all.
4554fd7ecabSdilpreet */
4564fd7ecabSdilpreet for (i = 0; i < 3; i++) {
4574fd7ecabSdilpreet sec_tmp = sec_err & afsr_err[i];
4584fd7ecabSdilpreet if (sec_tmp) {
4594fd7ecabSdilpreet pci_ecc_classify(sec_tmp, &ecc_sec_err);
4607c478bd9Sstevel@tonic-gate ecc_ereport_post(pci_p->pci_dip,
4617c478bd9Sstevel@tonic-gate &ecc_sec_err);
4627c478bd9Sstevel@tonic-gate }
4634fd7ecabSdilpreet }
4644fd7ecabSdilpreet }
4657c478bd9Sstevel@tonic-gate /*
4667c478bd9Sstevel@tonic-gate * Check for PCI bus errors that may have resulted from or
4677c478bd9Sstevel@tonic-gate * caused this UE.
4687c478bd9Sstevel@tonic-gate */
4697c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_caller == PCI_ECC_CALL &&
4707c478bd9Sstevel@tonic-gate ecc_pci_check(ecc_p, ecc_err_p->ecc_ena) == DDI_FM_FATAL)
4717c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_panic = 1;
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_aflt.flt_panic &&
4747c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_in_memory)
4757c478bd9Sstevel@tonic-gate panic_aflt = ecc_err_p->ecc_aflt;
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_aflt.flt_panic) {
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate * Disable all further errors since this will be
4807c478bd9Sstevel@tonic-gate * treated as a fatal error.
4817c478bd9Sstevel@tonic-gate */
4827c478bd9Sstevel@tonic-gate (void) ecc_disable_nowait(ecc_p);
4837c478bd9Sstevel@tonic-gate fatal++;
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate break;
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate case CBNINTR_CE:
4887c478bd9Sstevel@tonic-gate if (pri_err) {
4897c478bd9Sstevel@tonic-gate ecc_err_p->ecc_pri = 1;
4907c478bd9Sstevel@tonic-gate pci_ecc_classify(pri_err, ecc_err_p);
4917c478bd9Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_synd =
4927c478bd9Sstevel@tonic-gate pci_ecc_get_synd(ecc_err_p->ecc_afsr);
4937c478bd9Sstevel@tonic-gate ce_scrub(&ecc_err_p->ecc_aflt);
4947c478bd9Sstevel@tonic-gate errorq_dispatch(pci_ecc_queue, (void *)ecc_err_p,
4957c478bd9Sstevel@tonic-gate sizeof (ecc_errstate_t), ERRORQ_ASYNC);
4967c478bd9Sstevel@tonic-gate nonfatal++;
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate if (sec_err) {
4997c478bd9Sstevel@tonic-gate ecc_sec_err = *ecc_err_p;
5007c478bd9Sstevel@tonic-gate ecc_sec_err.ecc_pri = 0;
50139470729Skd93003 /*
50239470729Skd93003 * Secondary errors are cumulative so we need to loop
50339470729Skd93003 * through to capture them all.
50439470729Skd93003 */
50539470729Skd93003 for (i = 0; i < 3; i++) {
50639470729Skd93003 sec_tmp = sec_err & afsr_err[i];
50739470729Skd93003 if (sec_tmp) {
50839470729Skd93003 pci_ecc_classify(sec_tmp, &ecc_sec_err);
50939470729Skd93003 ecc_ereport_post(pci_p->pci_dip,
51039470729Skd93003 &ecc_sec_err);
51139470729Skd93003 }
51239470729Skd93003 }
5137c478bd9Sstevel@tonic-gate nonfatal++;
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate break;
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate default:
5187c478bd9Sstevel@tonic-gate return (DDI_FM_OK);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate /* Clear the errors */
5217c478bd9Sstevel@tonic-gate stdphysio(ecc_ii_p->ecc_afsr_pa, ecc_err_p->ecc_afsr);
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate * Clear the interrupt if called by ecc_intr and UE error or if called
5247c478bd9Sstevel@tonic-gate * by ecc_intr and CE error and delayed CE interrupt handling is
5257c478bd9Sstevel@tonic-gate * turned off.
5267c478bd9Sstevel@tonic-gate */
5277c478bd9Sstevel@tonic-gate if ((ecc_err_p->ecc_caller == PCI_ECC_CALL &&
5287c478bd9Sstevel@tonic-gate ecc_ii_p->ecc_type == CBNINTR_UE && !fatal) ||
5297c478bd9Sstevel@tonic-gate (ecc_err_p->ecc_caller == PCI_ECC_CALL &&
5307c478bd9Sstevel@tonic-gate ecc_ii_p->ecc_type == CBNINTR_CE && !ecc_ce_delayed))
5317c478bd9Sstevel@tonic-gate cb_clear_nintr(cb_p, ecc_ii_p->ecc_type);
5327c478bd9Sstevel@tonic-gate if (!fatal && !nonfatal)
5337c478bd9Sstevel@tonic-gate return (DDI_FM_OK);
5347c478bd9Sstevel@tonic-gate else if (fatal)
5357c478bd9Sstevel@tonic-gate return (DDI_FM_FATAL);
5367c478bd9Sstevel@tonic-gate return (DDI_FM_NONFATAL);
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate /*
5407c478bd9Sstevel@tonic-gate * Called from ecc_err_drain below for CBINTR_CE case.
5417c478bd9Sstevel@tonic-gate */
5427c478bd9Sstevel@tonic-gate static int
ecc_err_cexdiag(ecc_errstate_t * ecc_err,errorq_elem_t * eqep)543db874c57Selowe ecc_err_cexdiag(ecc_errstate_t *ecc_err, errorq_elem_t *eqep)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate struct async_flt *ecc = &ecc_err->ecc_aflt;
546db874c57Selowe uint64_t errors;
5477c478bd9Sstevel@tonic-gate
548db874c57Selowe if (page_retire_check(ecc->flt_addr, &errors) == EINVAL) {
5497c478bd9Sstevel@tonic-gate CE_XDIAG_SETSKIPCODE(ecc->flt_disp, CE_XDIAG_SKIP_NOPP);
5507c478bd9Sstevel@tonic-gate return (0);
551db874c57Selowe } else if (errors != PR_OK) {
5527c478bd9Sstevel@tonic-gate CE_XDIAG_SETSKIPCODE(ecc->flt_disp, CE_XDIAG_SKIP_PAGEDET);
5537c478bd9Sstevel@tonic-gate return (0);
554db874c57Selowe } else {
5557c478bd9Sstevel@tonic-gate return (ce_scrub_xdiag_recirc(ecc, pci_ecc_queue, eqep,
5567c478bd9Sstevel@tonic-gate offsetof(ecc_errstate_t, ecc_aflt)));
5577c478bd9Sstevel@tonic-gate }
558db874c57Selowe }
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate /*
5617c478bd9Sstevel@tonic-gate * Function used to drain pci_ecc_queue, either during panic or after softint
5627c478bd9Sstevel@tonic-gate * is generated, to log IO detected ECC errors.
5637c478bd9Sstevel@tonic-gate */
5647c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5657c478bd9Sstevel@tonic-gate void
ecc_err_drain(void * not_used,ecc_errstate_t * ecc_err,errorq_elem_t * eqep)5667c478bd9Sstevel@tonic-gate ecc_err_drain(void *not_used, ecc_errstate_t *ecc_err, errorq_elem_t *eqep)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate struct async_flt *ecc = &ecc_err->ecc_aflt;
5697c478bd9Sstevel@tonic-gate pci_t *pci_p = ecc_err->ecc_p->ecc_pci_cmn_p->pci_p[0];
5707c478bd9Sstevel@tonic-gate int ecc_type = ecc_err->ecc_ii_p.ecc_type;
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate if (pci_p == NULL)
5737c478bd9Sstevel@tonic-gate pci_p = ecc_err->ecc_p->ecc_pci_cmn_p->pci_p[1];
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate if (ecc->flt_class == RECIRC_BUS_FAULT) {
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate * Perform any additional actions that occur after the
5787c478bd9Sstevel@tonic-gate * ecc_err_cexdiag below and post the ereport.
5797c478bd9Sstevel@tonic-gate */
5807c478bd9Sstevel@tonic-gate ecc->flt_class = BUS_FAULT;
5817c478bd9Sstevel@tonic-gate ecc_err->ecc_err_type = flt_to_error_type(ecc);
5827c478bd9Sstevel@tonic-gate ecc_ereport_post(pci_p->pci_dip, ecc_err);
5837c478bd9Sstevel@tonic-gate return;
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate ecc_cpu_call(ecc, ecc_err->ecc_unum, (ecc_type == CBNINTR_UE) ?
5877c478bd9Sstevel@tonic-gate ECC_IO_UE : ECC_IO_CE);
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate switch (ecc_type) {
5907c478bd9Sstevel@tonic-gate case CBNINTR_UE:
591db874c57Selowe if (ecc_err->ecc_pg_ret == 1) {
592db874c57Selowe (void) page_retire(ecc->flt_addr, PR_UE);
5937c478bd9Sstevel@tonic-gate }
594b7abd578Sgavinm ecc_err->ecc_err_type = flt_to_error_type(ecc);
5957c478bd9Sstevel@tonic-gate break;
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate case CBNINTR_CE:
5987c478bd9Sstevel@tonic-gate /*
5997c478bd9Sstevel@tonic-gate * Setup timeout (if CE detected via interrupt) to
6007c478bd9Sstevel@tonic-gate * re-enable CE interrupts if no more CEs are detected.
6017c478bd9Sstevel@tonic-gate * This is to protect against CE storms.
6027c478bd9Sstevel@tonic-gate */
6037c478bd9Sstevel@tonic-gate if (ecc_ce_delayed &&
6047c478bd9Sstevel@tonic-gate ecc_err->ecc_caller == PCI_ECC_CALL &&
6057c478bd9Sstevel@tonic-gate ecc_err->ecc_p->ecc_to_id == 0) {
6067c478bd9Sstevel@tonic-gate ecc_err->ecc_p->ecc_to_id = timeout(ecc_delayed_ce,
6077c478bd9Sstevel@tonic-gate (void *)ecc_err->ecc_p,
6087c478bd9Sstevel@tonic-gate drv_usectohz((clock_t)ecc_ce_delay_secs *
6097c478bd9Sstevel@tonic-gate MICROSEC));
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate /* ecc_err_cexdiag returns nonzero to recirculate */
6137c478bd9Sstevel@tonic-gate if (CE_XDIAG_EXT_ALG_APPLIED(ecc->flt_disp) &&
614db874c57Selowe ecc_err_cexdiag(ecc_err, eqep))
6157c478bd9Sstevel@tonic-gate return;
6167c478bd9Sstevel@tonic-gate ecc_err->ecc_err_type = flt_to_error_type(ecc);
6177c478bd9Sstevel@tonic-gate break;
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate ecc_ereport_post(pci_p->pci_dip, ecc_err);
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate static void
ecc_delayed_ce(void * arg)6247c478bd9Sstevel@tonic-gate ecc_delayed_ce(void *arg)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate ecc_t *ecc_p = (ecc_t *)arg;
6277c478bd9Sstevel@tonic-gate pci_common_t *cmn_p;
6287c478bd9Sstevel@tonic-gate cb_t *cb_p;
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate ASSERT(ecc_p);
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate cmn_p = ecc_p->ecc_pci_cmn_p;
6337c478bd9Sstevel@tonic-gate cb_p = cmn_p->pci_common_cb_p;
6347c478bd9Sstevel@tonic-gate /*
6357c478bd9Sstevel@tonic-gate * If no more CE errors are found then enable interrupts(by
6367c478bd9Sstevel@tonic-gate * clearing the previous interrupt), else send in for logging
6377c478bd9Sstevel@tonic-gate * and the timeout should be set again.
6387c478bd9Sstevel@tonic-gate */
6397c478bd9Sstevel@tonic-gate ecc_p->ecc_to_id = 0;
6407c478bd9Sstevel@tonic-gate if (!((ecc_read_afsr(&ecc_p->ecc_ce) >>
6417c478bd9Sstevel@tonic-gate COMMON_ECC_UE_AFSR_PE_SHIFT) & COMMON_ECC_UE_AFSR_E_MASK)) {
6427c478bd9Sstevel@tonic-gate cb_clear_nintr(cb_p, ecc_p->ecc_ce.ecc_type);
6437c478bd9Sstevel@tonic-gate } else {
6447c478bd9Sstevel@tonic-gate ecc_errstate_t ecc_err;
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate bzero(&ecc_err, sizeof (ecc_errstate_t));
6477c478bd9Sstevel@tonic-gate ecc_err.ecc_ena = fm_ena_generate(0, FM_ENA_FMT1);
6487c478bd9Sstevel@tonic-gate ecc_err.ecc_ii_p = ecc_p->ecc_ce;
6497c478bd9Sstevel@tonic-gate ecc_err.ecc_p = ecc_p;
6507c478bd9Sstevel@tonic-gate ecc_err.ecc_caller = PCI_ECC_CALL;
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate mutex_enter(&cmn_p->pci_fm_mutex);
6537c478bd9Sstevel@tonic-gate (void) ecc_err_handler(&ecc_err);
6547c478bd9Sstevel@tonic-gate mutex_exit(&cmn_p->pci_fm_mutex);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate * Function used to post IO detected ECC ereports.
6607c478bd9Sstevel@tonic-gate */
6617c478bd9Sstevel@tonic-gate static void
ecc_ereport_post(dev_info_t * dip,ecc_errstate_t * ecc_err)6627c478bd9Sstevel@tonic-gate ecc_ereport_post(dev_info_t *dip, ecc_errstate_t *ecc_err)
6637c478bd9Sstevel@tonic-gate {
6647c478bd9Sstevel@tonic-gate char buf[FM_MAX_CLASS], dev_path[MAXPATHLEN], *ptr;
6657c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
6667c478bd9Sstevel@tonic-gate nvlist_t *ereport, *detector;
6677c478bd9Sstevel@tonic-gate nv_alloc_t *nva;
6687c478bd9Sstevel@tonic-gate errorq_elem_t *eqep;
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate * We do not use ddi_fm_ereport_post because we need to set a
6727c478bd9Sstevel@tonic-gate * special detector here. Since we do not have a device path for
6737c478bd9Sstevel@tonic-gate * the bridge chip we use what we think it should be to aid in
6747c478bd9Sstevel@tonic-gate * diagnosis. This path fmri is created by pci_fmri_create()
6757c478bd9Sstevel@tonic-gate * during initialization.
6767c478bd9Sstevel@tonic-gate */
6777c478bd9Sstevel@tonic-gate (void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s", DDI_IO_CLASS,
6787c478bd9Sstevel@tonic-gate ecc_err->ecc_bridge_type, ecc_err->ecc_aflt.flt_erpt_class);
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate ecc_err->ecc_ena = ecc_err->ecc_ena ? ecc_err->ecc_ena :
6817c478bd9Sstevel@tonic-gate fm_ena_generate(0, FM_ENA_FMT1);
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate eqep = errorq_reserve(fmhdl->fh_errorq);
6847c478bd9Sstevel@tonic-gate if (eqep == NULL)
6857c478bd9Sstevel@tonic-gate return;
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate ereport = errorq_elem_nvl(fmhdl->fh_errorq, eqep);
6887c478bd9Sstevel@tonic-gate nva = errorq_elem_nva(fmhdl->fh_errorq, eqep);
6897c478bd9Sstevel@tonic-gate detector = fm_nvlist_create(nva);
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate ASSERT(ereport);
6927c478bd9Sstevel@tonic-gate ASSERT(nva);
6937c478bd9Sstevel@tonic-gate ASSERT(detector);
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate ddi_pathname(dip, dev_path);
6967c478bd9Sstevel@tonic-gate ptr = strrchr(dev_path, (int)',');
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate if (ptr)
6997c478bd9Sstevel@tonic-gate *ptr = '\0';
7007c478bd9Sstevel@tonic-gate
701*392e836bSGavin Maltby fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, dev_path,
702*392e836bSGavin Maltby NULL, NULL);
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate if (ecc_err->ecc_pri) {
705d00f0155Sayznaga if ((ecc_err->ecc_fmri = fm_nvlist_create(nva)) != NULL) {
706d00f0155Sayznaga char sid[DIMM_SERIAL_ID_LEN] = "";
707d00f0155Sayznaga uint64_t offset = (uint64_t)-1;
708d00f0155Sayznaga int len;
709d00f0155Sayznaga int ret;
710d00f0155Sayznaga
711d00f0155Sayznaga ret = cpu_get_mem_sid(ecc_err->ecc_unum, sid,
712d00f0155Sayznaga DIMM_SERIAL_ID_LEN, &len);
713d00f0155Sayznaga
714d00f0155Sayznaga if (ret == 0) {
715d00f0155Sayznaga (void) cpu_get_mem_offset(
716d00f0155Sayznaga ecc_err->ecc_aflt.flt_addr, &offset);
717d00f0155Sayznaga }
718d00f0155Sayznaga
7197c478bd9Sstevel@tonic-gate fm_fmri_mem_set(ecc_err->ecc_fmri,
7207c478bd9Sstevel@tonic-gate FM_MEM_SCHEME_VERSION, NULL, ecc_err->ecc_unum,
721d00f0155Sayznaga (ret == 0) ? sid : NULL, offset);
722d00f0155Sayznaga }
7237c478bd9Sstevel@tonic-gate fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
7247c478bd9Sstevel@tonic-gate ecc_err->ecc_ena, detector,
7257c478bd9Sstevel@tonic-gate PCI_ECC_AFSR, DATA_TYPE_UINT64, ecc_err->ecc_afsr,
7267c478bd9Sstevel@tonic-gate PCI_ECC_AFAR, DATA_TYPE_UINT64, ecc_err->ecc_aflt.flt_addr,
7277c478bd9Sstevel@tonic-gate PCI_ECC_CTRL, DATA_TYPE_UINT64, ecc_err->ecc_ctrl,
7287c478bd9Sstevel@tonic-gate PCI_ECC_SYND, DATA_TYPE_UINT16, ecc_err->ecc_aflt.flt_synd,
7297c478bd9Sstevel@tonic-gate PCI_ECC_TYPE, DATA_TYPE_STRING, ecc_err->ecc_err_type,
7307c478bd9Sstevel@tonic-gate PCI_ECC_DISP, DATA_TYPE_UINT64, ecc_err->ecc_aflt.flt_disp,
7317c478bd9Sstevel@tonic-gate PCI_ECC_RESOURCE, DATA_TYPE_NVLIST, ecc_err->ecc_fmri,
7327c478bd9Sstevel@tonic-gate NULL);
7337c478bd9Sstevel@tonic-gate } else {
7347c478bd9Sstevel@tonic-gate fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
7357c478bd9Sstevel@tonic-gate ecc_err->ecc_ena, detector,
7367c478bd9Sstevel@tonic-gate PCI_ECC_AFSR, DATA_TYPE_UINT64, ecc_err->ecc_afsr,
7377c478bd9Sstevel@tonic-gate PCI_ECC_CTRL, DATA_TYPE_UINT64, ecc_err->ecc_ctrl,
7387c478bd9Sstevel@tonic-gate NULL);
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate errorq_commit(fmhdl->fh_errorq, eqep, ERRORQ_ASYNC);
7417c478bd9Sstevel@tonic-gate }
742