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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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