10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * PCI ECC support 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/systm.h> /* for strrchr */ 350Sstevel@tonic-gate #include <sys/kmem.h> 360Sstevel@tonic-gate #include <sys/sunddi.h> 370Sstevel@tonic-gate #include <sys/intr.h> 380Sstevel@tonic-gate #include <sys/async.h> /* struct async_flt */ 390Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 400Sstevel@tonic-gate #include <sys/machsystm.h> 410Sstevel@tonic-gate #include <sys/sysmacros.h> 420Sstevel@tonic-gate #include <sys/fm/protocol.h> 430Sstevel@tonic-gate #include <sys/fm/util.h> 440Sstevel@tonic-gate #include <sys/fm/io/pci.h> 450Sstevel@tonic-gate #include <sys/fm/io/sun4upci.h> 460Sstevel@tonic-gate #include <sys/fm/io/ddi.h> 470Sstevel@tonic-gate #include <sys/pci/pci_obj.h> /* ld/st physio */ 480Sstevel@tonic-gate #include <sys/cpuvar.h> 490Sstevel@tonic-gate #include <sys/errclassify.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate /*LINTLIBRARY*/ 520Sstevel@tonic-gate 530Sstevel@tonic-gate static void ecc_disable(ecc_t *, int); 540Sstevel@tonic-gate static void ecc_delayed_ce(void *); 550Sstevel@tonic-gate static uint64_t ecc_read_afsr(ecc_intr_info_t *); 560Sstevel@tonic-gate static void ecc_ereport_post(dev_info_t *dip, ecc_errstate_t *ecc_err); 570Sstevel@tonic-gate 580Sstevel@tonic-gate clock_t pci_ecc_panic_delay = 200; 590Sstevel@tonic-gate int ecc_ce_delay_secs = 6; /* number of sec to delay reenabling of CEs */ 600Sstevel@tonic-gate int ecc_ce_delayed = 1; /* global for enabling/disabling CE delay */ 610Sstevel@tonic-gate 620Sstevel@tonic-gate void 630Sstevel@tonic-gate ecc_create(pci_t *pci_p) 640Sstevel@tonic-gate { 650Sstevel@tonic-gate #ifdef DEBUG 660Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip; 670Sstevel@tonic-gate #endif 680Sstevel@tonic-gate uint64_t cb_base_pa = pci_p->pci_cb_p->cb_base_pa; 690Sstevel@tonic-gate ecc_t *ecc_p; 700Sstevel@tonic-gate 710Sstevel@tonic-gate ecc_p = (ecc_t *)kmem_zalloc(sizeof (ecc_t), KM_SLEEP); 720Sstevel@tonic-gate ecc_p->ecc_pci_cmn_p = pci_p->pci_common_p; 730Sstevel@tonic-gate pci_p->pci_ecc_p = ecc_p; 740Sstevel@tonic-gate 750Sstevel@tonic-gate ecc_p->ecc_ue.ecc_p = ecc_p; 760Sstevel@tonic-gate ecc_p->ecc_ue.ecc_type = CBNINTR_UE; 770Sstevel@tonic-gate ecc_p->ecc_ce.ecc_p = ecc_p; 780Sstevel@tonic-gate ecc_p->ecc_ce.ecc_type = CBNINTR_CE; 790Sstevel@tonic-gate 800Sstevel@tonic-gate pci_ecc_setup(ecc_p); 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * Determine the virtual addresses of the streaming cache 840Sstevel@tonic-gate * control/status and flush registers. 850Sstevel@tonic-gate */ 860Sstevel@tonic-gate ecc_p->ecc_csr_pa = cb_base_pa + COMMON_ECC_CSR_OFFSET; 870Sstevel@tonic-gate ecc_p->ecc_ue.ecc_afsr_pa = cb_base_pa + COMMON_UE_AFSR_OFFSET; 880Sstevel@tonic-gate ecc_p->ecc_ue.ecc_afar_pa = cb_base_pa + COMMON_UE_AFAR_OFFSET; 890Sstevel@tonic-gate ecc_p->ecc_ce.ecc_afsr_pa = cb_base_pa + COMMON_CE_AFSR_OFFSET; 900Sstevel@tonic-gate ecc_p->ecc_ce.ecc_afar_pa = cb_base_pa + COMMON_CE_AFAR_OFFSET; 910Sstevel@tonic-gate 920Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "ecc_create: csr=%x\n", ecc_p->ecc_csr_pa); 930Sstevel@tonic-gate DEBUG2(DBG_ATTACH, dip, "ecc_create: ue_afsr=%x, ue_afar=%x\n", 940Sstevel@tonic-gate ecc_p->ecc_ue.ecc_afsr_pa, ecc_p->ecc_ue.ecc_afar_pa); 950Sstevel@tonic-gate DEBUG2(DBG_ATTACH, dip, "ecc_create: ce_afsr=%x, ce_afar=%x\n", 960Sstevel@tonic-gate ecc_p->ecc_ce.ecc_afsr_pa, ecc_p->ecc_ce.ecc_afar_pa); 970Sstevel@tonic-gate 980Sstevel@tonic-gate ecc_configure(pci_p); 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * Register routines to be called from system error handling code. 1020Sstevel@tonic-gate */ 1030Sstevel@tonic-gate bus_func_register(BF_TYPE_ERRDIS, (busfunc_t)ecc_disable_nowait, ecc_p); 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate int 1070Sstevel@tonic-gate ecc_register_intr(pci_t *pci_p) 1080Sstevel@tonic-gate { 1090Sstevel@tonic-gate ecc_t *ecc_p = pci_p->pci_ecc_p; 1100Sstevel@tonic-gate int ret; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate /* 1130Sstevel@tonic-gate * Install the UE and CE error interrupt handlers. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate if ((ret = pci_ecc_add_intr(pci_p, CBNINTR_UE, &ecc_p->ecc_ue)) != 1160Sstevel@tonic-gate DDI_SUCCESS) 1170Sstevel@tonic-gate return (ret); 1180Sstevel@tonic-gate if ((ret = pci_ecc_add_intr(pci_p, CBNINTR_CE, &ecc_p->ecc_ce)) != 1190Sstevel@tonic-gate DDI_SUCCESS) 1200Sstevel@tonic-gate return (ret); 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate return (DDI_SUCCESS); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate void 1260Sstevel@tonic-gate ecc_destroy(pci_t *pci_p) 1270Sstevel@tonic-gate { 1280Sstevel@tonic-gate ecc_t *ecc_p = pci_p->pci_ecc_p; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate DEBUG0(DBG_DETACH, pci_p->pci_dip, "ecc_destroy:\n"); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* 1330Sstevel@tonic-gate * Disable UE and CE ECC error interrupts. 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate ecc_disable_wait(ecc_p); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * Remove the ECC interrupt handlers. 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate pci_ecc_rem_intr(pci_p, CBNINTR_UE, &ecc_p->ecc_ue); 1410Sstevel@tonic-gate pci_ecc_rem_intr(pci_p, CBNINTR_CE, &ecc_p->ecc_ce); 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate /* 1440Sstevel@tonic-gate * Unregister our error handling functions. 1450Sstevel@tonic-gate */ 1460Sstevel@tonic-gate bus_func_unregister(BF_TYPE_ERRDIS, 1470Sstevel@tonic-gate (busfunc_t)ecc_disable_nowait, ecc_p); 1480Sstevel@tonic-gate /* 1490Sstevel@tonic-gate * If a timer has been set, unset it. 1500Sstevel@tonic-gate */ 1510Sstevel@tonic-gate (void) untimeout(ecc_p->ecc_to_id); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate kmem_free(ecc_p, sizeof (ecc_t)); 1540Sstevel@tonic-gate pci_p->pci_ecc_p = NULL; 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate void 1580Sstevel@tonic-gate ecc_configure(pci_t *pci_p) 1590Sstevel@tonic-gate { 1600Sstevel@tonic-gate ecc_t *ecc_p = pci_p->pci_ecc_p; 1610Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip; 1620Sstevel@tonic-gate uint64_t l; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* 1650Sstevel@tonic-gate * Clear any pending ECC errors. 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "ecc_configure: clearing UE and CE errors\n"); 1680Sstevel@tonic-gate l = (COMMON_ECC_UE_AFSR_E_MASK << COMMON_ECC_UE_AFSR_PE_SHIFT) | 1690Sstevel@tonic-gate (COMMON_ECC_UE_AFSR_E_MASK << COMMON_ECC_UE_AFSR_SE_SHIFT); 1700Sstevel@tonic-gate stdphysio(ecc_p->ecc_ue.ecc_afsr_pa, l); 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate l = (COMMON_ECC_CE_AFSR_E_MASK << COMMON_ECC_CE_AFSR_PE_SHIFT) | 1730Sstevel@tonic-gate (COMMON_ECC_CE_AFSR_E_MASK << COMMON_ECC_CE_AFSR_SE_SHIFT); 1740Sstevel@tonic-gate stdphysio(ecc_p->ecc_ce.ecc_afsr_pa, l); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /* 1770Sstevel@tonic-gate * Enable ECC error detections via the control register. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "ecc_configure: enabling UE CE detection\n"); 1800Sstevel@tonic-gate l = COMMON_ECC_CTRL_ECC_EN; 1810Sstevel@tonic-gate if (ecc_error_intr_enable) 1820Sstevel@tonic-gate l |= COMMON_ECC_CTRL_UE_INTEN | COMMON_ECC_CTRL_CE_INTEN; 1830Sstevel@tonic-gate stdphysio(ecc_p->ecc_csr_pa, l); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate void 1870Sstevel@tonic-gate ecc_enable_intr(pci_t *pci_p) 1880Sstevel@tonic-gate { 1890Sstevel@tonic-gate cb_enable_nintr(pci_p, CBNINTR_UE); 1900Sstevel@tonic-gate cb_enable_nintr(pci_p, CBNINTR_CE); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate void 1940Sstevel@tonic-gate ecc_disable_wait(ecc_t *ecc_p) 1950Sstevel@tonic-gate { 1960Sstevel@tonic-gate ecc_disable(ecc_p, IB_INTR_WAIT); 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate uint_t 2000Sstevel@tonic-gate ecc_disable_nowait(ecc_t *ecc_p) 2010Sstevel@tonic-gate { 2020Sstevel@tonic-gate ecc_disable(ecc_p, IB_INTR_NOWAIT); 2030Sstevel@tonic-gate return (BF_NONE); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate static void 2070Sstevel@tonic-gate ecc_disable(ecc_t *ecc_p, int wait) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate cb_t *cb_p = ecc_p->ecc_pci_cmn_p->pci_common_cb_p; 2100Sstevel@tonic-gate uint64_t csr_pa = ecc_p->ecc_csr_pa; 2110Sstevel@tonic-gate uint64_t csr = lddphysio(csr_pa); 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate csr &= ~(COMMON_ECC_CTRL_UE_INTEN | COMMON_ECC_CTRL_CE_INTEN); 2140Sstevel@tonic-gate stdphysio(csr_pa, csr); 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate cb_disable_nintr(cb_p, CBNINTR_UE, wait); 2170Sstevel@tonic-gate cb_disable_nintr(cb_p, CBNINTR_CE, wait); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate /* 2210Sstevel@tonic-gate * I/O ECC error handling: 2220Sstevel@tonic-gate * 2230Sstevel@tonic-gate * Below are the generic functions that handle PCI(pcisch, pcipsy) detected 2240Sstevel@tonic-gate * ECC errors. 2250Sstevel@tonic-gate * 2260Sstevel@tonic-gate * The registered interrupt handler for both pcisch and pcipsy is ecc_intr(), 2270Sstevel@tonic-gate * it's function is to receive the error, capture some state, and pass that on 2280Sstevel@tonic-gate * to the ecc_err_handler() for reporting purposes. 2290Sstevel@tonic-gate * 2300Sstevel@tonic-gate * ecc_err_handler() gathers more state(via ecc_errstate_get) and attempts 2310Sstevel@tonic-gate * to handle and report the error. ecc_err_handler() must determine if we need 2320Sstevel@tonic-gate * to panic due to this error (via pci_ecc_classify, which also decodes the 2330Sstevel@tonic-gate * ECC afsr), and if any side effects exist that may have caused or are due 2340Sstevel@tonic-gate * to this error. PBM errors related to the ECC error may exist, to report 2350Sstevel@tonic-gate * them we call pci_pbm_err_handler() and call ndi_fm_handler_dispatch() so 2360Sstevel@tonic-gate * that the child devices can log their pci errors. 2370Sstevel@tonic-gate * 2380Sstevel@tonic-gate * To report the error we must also get the syndrome and unum, which can not 2390Sstevel@tonic-gate * be done in high level interrupted context. Therefore we have an error 2400Sstevel@tonic-gate * queue(pci_ecc_queue) which we dispatch errors to, to report the errors 2410Sstevel@tonic-gate * (ecc_err_drain()). 2420Sstevel@tonic-gate * 2430Sstevel@tonic-gate * ecc_err_drain() will be called when either the softint is triggered 2440Sstevel@tonic-gate * or the system is panicing. Either way it will gather more information 2450Sstevel@tonic-gate * about the error from the CPU(via ecc_cpu_call(), ecc.c), attempt to 2460Sstevel@tonic-gate * retire the faulty page(if error is a UE), and report the detected error. 2470Sstevel@tonic-gate * 2480Sstevel@tonic-gate * ecc_delayed_ce() is called via timeout from ecc_err_handler() following 2490Sstevel@tonic-gate * the receipt of a CE interrupt. It will be called after 6ms and check to 2500Sstevel@tonic-gate * see if any new CEs are present, if so we will log and another timeout will 2510Sstevel@tonic-gate * be set by(ecc_err_handler()). If no CEs are present then it will re-enable 2520Sstevel@tonic-gate * CEs by clearing the previous interrupt. This is to keep the system going 2530Sstevel@tonic-gate * in the event of a CE storm. 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate /* 2570Sstevel@tonic-gate * Function used to get ECC AFSR register 2580Sstevel@tonic-gate */ 2590Sstevel@tonic-gate static uint64_t 2600Sstevel@tonic-gate ecc_read_afsr(ecc_intr_info_t *ecc_ii_p) 2610Sstevel@tonic-gate { 2620Sstevel@tonic-gate uint_t i; 2630Sstevel@tonic-gate uint64_t afsr = 0ull; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate ASSERT((ecc_ii_p->ecc_type == CBNINTR_UE) || 2660Sstevel@tonic-gate (ecc_ii_p->ecc_type == CBNINTR_CE)); 2670Sstevel@tonic-gate if (!ecc_ii_p->ecc_errpndg_mask) 2680Sstevel@tonic-gate return (lddphysio(ecc_ii_p->ecc_afsr_pa)); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate for (i = 0; i < pci_ecc_afsr_retries; i++) { 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* 2730Sstevel@tonic-gate * If we timeout, the logging routine will 2740Sstevel@tonic-gate * know because it will see the ERRPNDG bits 2750Sstevel@tonic-gate * set in the AFSR. 2760Sstevel@tonic-gate */ 2770Sstevel@tonic-gate afsr = lddphysio(ecc_ii_p->ecc_afsr_pa); 2780Sstevel@tonic-gate if ((afsr & ecc_ii_p->ecc_errpndg_mask) == 0) 2790Sstevel@tonic-gate break; 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate return (afsr); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate /* 2850Sstevel@tonic-gate * IO detected ECC error interrupt handler, calls ecc_err_handler to post 2860Sstevel@tonic-gate * error reports and handle the interrupt. Re-entry into ecc_err_handler 2870Sstevel@tonic-gate * is protected by the per-chip mutex pci_fm_mutex. 2880Sstevel@tonic-gate */ 2890Sstevel@tonic-gate uint_t 2900Sstevel@tonic-gate ecc_intr(caddr_t a) 2910Sstevel@tonic-gate { 2920Sstevel@tonic-gate ecc_intr_info_t *ecc_ii_p = (ecc_intr_info_t *)a; 2930Sstevel@tonic-gate ecc_t *ecc_p = ecc_ii_p->ecc_p; 2940Sstevel@tonic-gate pci_common_t *cmn_p = ecc_p->ecc_pci_cmn_p; 2950Sstevel@tonic-gate ecc_errstate_t ecc_err; 2960Sstevel@tonic-gate int ret = DDI_FM_OK; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate bzero(&ecc_err, sizeof (ecc_errstate_t)); 2990Sstevel@tonic-gate ecc_err.ecc_ena = fm_ena_generate(0, FM_ENA_FMT1); 3000Sstevel@tonic-gate ecc_err.ecc_ii_p = *ecc_ii_p; 3010Sstevel@tonic-gate ecc_err.ecc_p = ecc_p; 3020Sstevel@tonic-gate ecc_err.ecc_caller = PCI_ECC_CALL; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate mutex_enter(&cmn_p->pci_fm_mutex); 3050Sstevel@tonic-gate ret = ecc_err_handler(&ecc_err); 3060Sstevel@tonic-gate mutex_exit(&cmn_p->pci_fm_mutex); 3070Sstevel@tonic-gate if (ret == DDI_FM_FATAL) { 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * Need delay here to allow CPUs to handle related traps, 3100Sstevel@tonic-gate * such as FRUs for USIIIi systems. 3110Sstevel@tonic-gate */ 3120Sstevel@tonic-gate DELAY(pci_ecc_panic_delay); 3130Sstevel@tonic-gate fm_panic("Fatal PCI UE Error"); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate /* 3200Sstevel@tonic-gate * Function used to gather IO ECC error state. 3210Sstevel@tonic-gate */ 3220Sstevel@tonic-gate static void 3230Sstevel@tonic-gate ecc_errstate_get(ecc_errstate_t *ecc_err_p) 3240Sstevel@tonic-gate { 3250Sstevel@tonic-gate ecc_t *ecc_p; 3260Sstevel@tonic-gate uint_t bus_id; 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate ASSERT(ecc_err_p); 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate ecc_p = ecc_err_p->ecc_ii_p.ecc_p; 3310Sstevel@tonic-gate bus_id = ecc_p->ecc_pci_cmn_p->pci_common_id; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex)); 3340Sstevel@tonic-gate /* 3350Sstevel@tonic-gate * Read the fault registers. 3360Sstevel@tonic-gate */ 3370Sstevel@tonic-gate ecc_err_p->ecc_afsr = ecc_read_afsr(&ecc_err_p->ecc_ii_p); 3380Sstevel@tonic-gate ecc_err_p->ecc_afar = lddphysio(ecc_err_p->ecc_ii_p.ecc_afar_pa); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate ecc_err_p->ecc_offset = ((ecc_err_p->ecc_afsr & 3410Sstevel@tonic-gate ecc_err_p->ecc_ii_p.ecc_offset_mask) >> 3420Sstevel@tonic-gate ecc_err_p->ecc_ii_p.ecc_offset_shift) << 3430Sstevel@tonic-gate ecc_err_p->ecc_ii_p.ecc_size_log2; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_id = gethrtime(); 3460Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_stat = ecc_err_p->ecc_afsr; 3470Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_addr = P2ALIGN(ecc_err_p->ecc_afar, 64) + 3480Sstevel@tonic-gate ecc_err_p->ecc_offset; 3490Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_bus_id = bus_id; 3500Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_inst = CPU->cpu_id; 3510Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_status = ECC_IOBUS; 3520Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_in_memory = (pf_is_memory 3530Sstevel@tonic-gate (ecc_err_p->ecc_afar >> MMU_PAGESHIFT))? 1: 0; 3540Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_class = BUS_FAULT; 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /* 3580Sstevel@tonic-gate * ecc_pci_check: Called by ecc_err_handler() this function is responsible 3590Sstevel@tonic-gate * for calling pci_pbm_err_handler() for both sides of the schizo/psycho 3600Sstevel@tonic-gate * and calling their children error handlers(via ndi_fm_handler_dispatch()). 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate static int 3630Sstevel@tonic-gate ecc_pci_check(ecc_t *ecc_p, uint64_t fme_ena) 3640Sstevel@tonic-gate { 3650Sstevel@tonic-gate ddi_fm_error_t derr; 3660Sstevel@tonic-gate int i; 3670Sstevel@tonic-gate int ret; 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex)); 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate bzero(&derr, sizeof (ddi_fm_error_t)); 3720Sstevel@tonic-gate derr.fme_version = DDI_FME_VERSION; 3730Sstevel@tonic-gate derr.fme_ena = fme_ena; 3740Sstevel@tonic-gate ret = DDI_FM_NONFATAL; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * Need to report any PBM errors which may have caused or 3780Sstevel@tonic-gate * resulted from this error. 3790Sstevel@tonic-gate * 3800Sstevel@tonic-gate * Each psycho or schizo is represented by a pair of pci nodes 3810Sstevel@tonic-gate * in the device tree. 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate for (i = 0; i < 2; i++) { 3840Sstevel@tonic-gate dev_info_t *dip; 3850Sstevel@tonic-gate pci_t *pci_p; 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate /* Make sure PBM PCI node exists */ 3880Sstevel@tonic-gate pci_p = ecc_p->ecc_pci_cmn_p->pci_p[i]; 3890Sstevel@tonic-gate if (pci_p == NULL) 3900Sstevel@tonic-gate continue; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate dip = pci_p->pci_dip; 3930Sstevel@tonic-gate if (pci_pbm_err_handler(dip, &derr, (void *)pci_p, 3940Sstevel@tonic-gate PCI_ECC_CALL) == DDI_FM_FATAL) 3950Sstevel@tonic-gate ret = DDI_FM_FATAL; 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate if (ret == DDI_FM_FATAL) 3980Sstevel@tonic-gate return (DDI_FM_FATAL); 3990Sstevel@tonic-gate else 4000Sstevel@tonic-gate return (DDI_FM_NONFATAL); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* 4040Sstevel@tonic-gate * Function used to handle and log IO detected ECC errors, can be called by 4050Sstevel@tonic-gate * ecc_intr and pci_err_callback(trap callback). Protected by pci_fm_mutex. 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate int 4080Sstevel@tonic-gate ecc_err_handler(ecc_errstate_t *ecc_err_p) 4090Sstevel@tonic-gate { 4100Sstevel@tonic-gate uint64_t pri_err, sec_err; 4110Sstevel@tonic-gate ecc_intr_info_t *ecc_ii_p = &ecc_err_p->ecc_ii_p; 4120Sstevel@tonic-gate ecc_t *ecc_p = ecc_ii_p->ecc_p; 4130Sstevel@tonic-gate pci_t *pci_p; 4140Sstevel@tonic-gate cb_t *cb_p; 4150Sstevel@tonic-gate int fatal = 0; 4160Sstevel@tonic-gate int nonfatal = 0; 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ecc_p->ecc_pci_cmn_p->pci_fm_mutex)); 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate pci_p = ecc_p->ecc_pci_cmn_p->pci_p[0]; 4210Sstevel@tonic-gate if (pci_p == NULL) 4220Sstevel@tonic-gate pci_p = ecc_p->ecc_pci_cmn_p->pci_p[1]; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate cb_p = ecc_p->ecc_pci_cmn_p->pci_common_cb_p; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate ecc_errstate_get(ecc_err_p); 4270Sstevel@tonic-gate pri_err = (ecc_err_p->ecc_afsr >> COMMON_ECC_UE_AFSR_PE_SHIFT) & 4280Sstevel@tonic-gate COMMON_ECC_UE_AFSR_E_MASK; 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate sec_err = (ecc_err_p->ecc_afsr >> COMMON_ECC_UE_AFSR_SE_SHIFT) & 4310Sstevel@tonic-gate COMMON_ECC_UE_AFSR_E_MASK; 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate switch (ecc_ii_p->ecc_type) { 4340Sstevel@tonic-gate case CBNINTR_UE: 4350Sstevel@tonic-gate if (pri_err) { 4360Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_synd = 4370Sstevel@tonic-gate pci_ecc_get_synd(ecc_err_p->ecc_afsr); 4380Sstevel@tonic-gate ecc_err_p->ecc_pri = 1; 4390Sstevel@tonic-gate pci_ecc_classify(pri_err, ecc_err_p); 4400Sstevel@tonic-gate errorq_dispatch(pci_ecc_queue, (void *)ecc_err_p, 4410Sstevel@tonic-gate sizeof (ecc_errstate_t), 4420Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_panic); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate if (sec_err) { 4450Sstevel@tonic-gate ecc_errstate_t ecc_sec_err; 446815Sdilpreet uint64_t sec_tmp; 447815Sdilpreet int i; 448815Sdilpreet uint64_t afsr_err[] = {COMMON_ECC_UE_AFSR_E_PIO, 449815Sdilpreet COMMON_ECC_UE_AFSR_E_DRD, 450815Sdilpreet COMMON_ECC_UE_AFSR_E_DWR}; 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate ecc_sec_err = *ecc_err_p; 4530Sstevel@tonic-gate ecc_sec_err.ecc_pri = 0; 454815Sdilpreet /* 455815Sdilpreet * Secondary errors are cummulative so we need to loop 456815Sdilpreet * through to capture them all. 457815Sdilpreet */ 458815Sdilpreet for (i = 0; i < 3; i++) { 459815Sdilpreet sec_tmp = sec_err & afsr_err[i]; 460815Sdilpreet if (sec_tmp) { 461815Sdilpreet pci_ecc_classify(sec_tmp, &ecc_sec_err); 462815Sdilpreet ecc_ereport_post(pci_p->pci_dip, 463815Sdilpreet &ecc_sec_err); 464815Sdilpreet } 465815Sdilpreet } 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate /* 4680Sstevel@tonic-gate * Check for PCI bus errors that may have resulted from or 4690Sstevel@tonic-gate * caused this UE. 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate if (ecc_err_p->ecc_caller == PCI_ECC_CALL && 4720Sstevel@tonic-gate ecc_pci_check(ecc_p, ecc_err_p->ecc_ena) == DDI_FM_FATAL) 4730Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_panic = 1; 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate if (ecc_err_p->ecc_aflt.flt_panic && 4760Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_in_memory) 4770Sstevel@tonic-gate panic_aflt = ecc_err_p->ecc_aflt; 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate if (ecc_err_p->ecc_aflt.flt_panic) { 4800Sstevel@tonic-gate /* 4810Sstevel@tonic-gate * Disable all further errors since this will be 4820Sstevel@tonic-gate * treated as a fatal error. 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate (void) ecc_disable_nowait(ecc_p); 4850Sstevel@tonic-gate fatal++; 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate break; 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate case CBNINTR_CE: 4900Sstevel@tonic-gate if (pri_err) { 4910Sstevel@tonic-gate ecc_err_p->ecc_pri = 1; 4920Sstevel@tonic-gate pci_ecc_classify(pri_err, ecc_err_p); 4930Sstevel@tonic-gate ecc_err_p->ecc_aflt.flt_synd = 4940Sstevel@tonic-gate pci_ecc_get_synd(ecc_err_p->ecc_afsr); 4950Sstevel@tonic-gate ce_scrub(&ecc_err_p->ecc_aflt); 4960Sstevel@tonic-gate errorq_dispatch(pci_ecc_queue, (void *)ecc_err_p, 4970Sstevel@tonic-gate sizeof (ecc_errstate_t), ERRORQ_ASYNC); 4980Sstevel@tonic-gate nonfatal++; 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate if (sec_err) { 5010Sstevel@tonic-gate ecc_errstate_t ecc_sec_err; 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate ecc_sec_err = *ecc_err_p; 5040Sstevel@tonic-gate ecc_sec_err.ecc_pri = 0; 5050Sstevel@tonic-gate pci_ecc_classify(sec_err, &ecc_sec_err); 5060Sstevel@tonic-gate ecc_ereport_post(pci_p->pci_dip, &ecc_sec_err); 5070Sstevel@tonic-gate nonfatal++; 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate break; 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate default: 5120Sstevel@tonic-gate return (DDI_FM_OK); 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate /* Clear the errors */ 5150Sstevel@tonic-gate stdphysio(ecc_ii_p->ecc_afsr_pa, ecc_err_p->ecc_afsr); 5160Sstevel@tonic-gate /* 5170Sstevel@tonic-gate * Clear the interrupt if called by ecc_intr and UE error or if called 5180Sstevel@tonic-gate * by ecc_intr and CE error and delayed CE interrupt handling is 5190Sstevel@tonic-gate * turned off. 5200Sstevel@tonic-gate */ 5210Sstevel@tonic-gate if ((ecc_err_p->ecc_caller == PCI_ECC_CALL && 5220Sstevel@tonic-gate ecc_ii_p->ecc_type == CBNINTR_UE && !fatal) || 5230Sstevel@tonic-gate (ecc_err_p->ecc_caller == PCI_ECC_CALL && 5240Sstevel@tonic-gate ecc_ii_p->ecc_type == CBNINTR_CE && !ecc_ce_delayed)) 5250Sstevel@tonic-gate cb_clear_nintr(cb_p, ecc_ii_p->ecc_type); 5260Sstevel@tonic-gate if (!fatal && !nonfatal) 5270Sstevel@tonic-gate return (DDI_FM_OK); 5280Sstevel@tonic-gate else if (fatal) 5290Sstevel@tonic-gate return (DDI_FM_FATAL); 5300Sstevel@tonic-gate return (DDI_FM_NONFATAL); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate /* 5340Sstevel@tonic-gate * Called from ecc_err_drain below for CBINTR_CE case. 5350Sstevel@tonic-gate */ 5360Sstevel@tonic-gate static int 537*917Selowe ecc_err_cexdiag(ecc_errstate_t *ecc_err, errorq_elem_t *eqep) 5380Sstevel@tonic-gate { 5390Sstevel@tonic-gate struct async_flt *ecc = &ecc_err->ecc_aflt; 540*917Selowe uint64_t errors; 5410Sstevel@tonic-gate 542*917Selowe if (page_retire_check(ecc->flt_addr, &errors) == EINVAL) { 5430Sstevel@tonic-gate CE_XDIAG_SETSKIPCODE(ecc->flt_disp, CE_XDIAG_SKIP_NOPP); 5440Sstevel@tonic-gate return (0); 545*917Selowe } else if (errors != PR_OK) { 5460Sstevel@tonic-gate CE_XDIAG_SETSKIPCODE(ecc->flt_disp, CE_XDIAG_SKIP_PAGEDET); 5470Sstevel@tonic-gate return (0); 548*917Selowe } else { 549*917Selowe return (ce_scrub_xdiag_recirc(ecc, pci_ecc_queue, eqep, 550*917Selowe offsetof(ecc_errstate_t, ecc_aflt))); 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate /* 5550Sstevel@tonic-gate * Function used to drain pci_ecc_queue, either during panic or after softint 5560Sstevel@tonic-gate * is generated, to log IO detected ECC errors. 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate /*ARGSUSED*/ 5590Sstevel@tonic-gate void 5600Sstevel@tonic-gate ecc_err_drain(void *not_used, ecc_errstate_t *ecc_err, errorq_elem_t *eqep) 5610Sstevel@tonic-gate { 5620Sstevel@tonic-gate struct async_flt *ecc = &ecc_err->ecc_aflt; 5630Sstevel@tonic-gate pci_t *pci_p = ecc_err->ecc_p->ecc_pci_cmn_p->pci_p[0]; 5640Sstevel@tonic-gate int ecc_type = ecc_err->ecc_ii_p.ecc_type; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate if (pci_p == NULL) 5670Sstevel@tonic-gate pci_p = ecc_err->ecc_p->ecc_pci_cmn_p->pci_p[1]; 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate if (ecc->flt_class == RECIRC_BUS_FAULT) { 5700Sstevel@tonic-gate /* 5710Sstevel@tonic-gate * Perform any additional actions that occur after the 5720Sstevel@tonic-gate * ecc_err_cexdiag below and post the ereport. 5730Sstevel@tonic-gate */ 5740Sstevel@tonic-gate ecc->flt_class = BUS_FAULT; 5750Sstevel@tonic-gate ecc_err->ecc_err_type = flt_to_error_type(ecc); 5760Sstevel@tonic-gate ecc_ereport_post(pci_p->pci_dip, ecc_err); 5770Sstevel@tonic-gate return; 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate ecc_cpu_call(ecc, ecc_err->ecc_unum, (ecc_type == CBNINTR_UE) ? 5810Sstevel@tonic-gate ECC_IO_UE : ECC_IO_CE); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate switch (ecc_type) { 5840Sstevel@tonic-gate case CBNINTR_UE: 585*917Selowe if (ecc_err->ecc_pg_ret == 1) { 586*917Selowe (void) page_retire(ecc->flt_addr, PR_UE); 5870Sstevel@tonic-gate } 58849Sgavinm ecc_err->ecc_err_type = flt_to_error_type(ecc); 5890Sstevel@tonic-gate break; 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate case CBNINTR_CE: 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * Setup timeout (if CE detected via interrupt) to 5940Sstevel@tonic-gate * re-enable CE interrupts if no more CEs are detected. 5950Sstevel@tonic-gate * This is to protect against CE storms. 5960Sstevel@tonic-gate */ 5970Sstevel@tonic-gate if (ecc_ce_delayed && 5980Sstevel@tonic-gate ecc_err->ecc_caller == PCI_ECC_CALL && 5990Sstevel@tonic-gate ecc_err->ecc_p->ecc_to_id == 0) { 6000Sstevel@tonic-gate ecc_err->ecc_p->ecc_to_id = timeout(ecc_delayed_ce, 6010Sstevel@tonic-gate (void *)ecc_err->ecc_p, 6020Sstevel@tonic-gate drv_usectohz((clock_t)ecc_ce_delay_secs * 6030Sstevel@tonic-gate MICROSEC)); 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate /* ecc_err_cexdiag returns nonzero to recirculate */ 6070Sstevel@tonic-gate if (CE_XDIAG_EXT_ALG_APPLIED(ecc->flt_disp) && 608*917Selowe ecc_err_cexdiag(ecc_err, eqep)) 6090Sstevel@tonic-gate return; 6100Sstevel@tonic-gate ecc_err->ecc_err_type = flt_to_error_type(ecc); 6110Sstevel@tonic-gate break; 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate ecc_ereport_post(pci_p->pci_dip, ecc_err); 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate static void 6180Sstevel@tonic-gate ecc_delayed_ce(void *arg) 6190Sstevel@tonic-gate { 6200Sstevel@tonic-gate ecc_t *ecc_p = (ecc_t *)arg; 6210Sstevel@tonic-gate pci_common_t *cmn_p; 6220Sstevel@tonic-gate cb_t *cb_p; 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate ASSERT(ecc_p); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate cmn_p = ecc_p->ecc_pci_cmn_p; 6270Sstevel@tonic-gate cb_p = cmn_p->pci_common_cb_p; 6280Sstevel@tonic-gate /* 6290Sstevel@tonic-gate * If no more CE errors are found then enable interrupts(by 6300Sstevel@tonic-gate * clearing the previous interrupt), else send in for logging 6310Sstevel@tonic-gate * and the timeout should be set again. 6320Sstevel@tonic-gate */ 6330Sstevel@tonic-gate ecc_p->ecc_to_id = 0; 6340Sstevel@tonic-gate if (!((ecc_read_afsr(&ecc_p->ecc_ce) >> 6350Sstevel@tonic-gate COMMON_ECC_UE_AFSR_PE_SHIFT) & COMMON_ECC_UE_AFSR_E_MASK)) { 6360Sstevel@tonic-gate cb_clear_nintr(cb_p, ecc_p->ecc_ce.ecc_type); 6370Sstevel@tonic-gate } else { 6380Sstevel@tonic-gate ecc_errstate_t ecc_err; 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate bzero(&ecc_err, sizeof (ecc_errstate_t)); 6410Sstevel@tonic-gate ecc_err.ecc_ena = fm_ena_generate(0, FM_ENA_FMT1); 6420Sstevel@tonic-gate ecc_err.ecc_ii_p = ecc_p->ecc_ce; 6430Sstevel@tonic-gate ecc_err.ecc_p = ecc_p; 6440Sstevel@tonic-gate ecc_err.ecc_caller = PCI_ECC_CALL; 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate mutex_enter(&cmn_p->pci_fm_mutex); 6470Sstevel@tonic-gate (void) ecc_err_handler(&ecc_err); 6480Sstevel@tonic-gate mutex_exit(&cmn_p->pci_fm_mutex); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate /* 6530Sstevel@tonic-gate * Function used to post IO detected ECC ereports. 6540Sstevel@tonic-gate */ 6550Sstevel@tonic-gate static void 6560Sstevel@tonic-gate ecc_ereport_post(dev_info_t *dip, ecc_errstate_t *ecc_err) 6570Sstevel@tonic-gate { 6580Sstevel@tonic-gate char buf[FM_MAX_CLASS], dev_path[MAXPATHLEN], *ptr; 6590Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 6600Sstevel@tonic-gate nvlist_t *ereport, *detector; 6610Sstevel@tonic-gate nv_alloc_t *nva; 6620Sstevel@tonic-gate errorq_elem_t *eqep; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate /* 6650Sstevel@tonic-gate * We do not use ddi_fm_ereport_post because we need to set a 6660Sstevel@tonic-gate * special detector here. Since we do not have a device path for 6670Sstevel@tonic-gate * the bridge chip we use what we think it should be to aid in 6680Sstevel@tonic-gate * diagnosis. This path fmri is created by pci_fmri_create() 6690Sstevel@tonic-gate * during initialization. 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate (void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s", DDI_IO_CLASS, 6720Sstevel@tonic-gate ecc_err->ecc_bridge_type, ecc_err->ecc_aflt.flt_erpt_class); 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate ecc_err->ecc_ena = ecc_err->ecc_ena ? ecc_err->ecc_ena : 6750Sstevel@tonic-gate fm_ena_generate(0, FM_ENA_FMT1); 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate eqep = errorq_reserve(fmhdl->fh_errorq); 6780Sstevel@tonic-gate if (eqep == NULL) 6790Sstevel@tonic-gate return; 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate ereport = errorq_elem_nvl(fmhdl->fh_errorq, eqep); 6820Sstevel@tonic-gate nva = errorq_elem_nva(fmhdl->fh_errorq, eqep); 6830Sstevel@tonic-gate detector = fm_nvlist_create(nva); 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate ASSERT(ereport); 6860Sstevel@tonic-gate ASSERT(nva); 6870Sstevel@tonic-gate ASSERT(detector); 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate ddi_pathname(dip, dev_path); 6900Sstevel@tonic-gate ptr = strrchr(dev_path, (int)','); 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate if (ptr) 6930Sstevel@tonic-gate *ptr = '\0'; 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, dev_path, NULL); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate if (ecc_err->ecc_pri) { 6980Sstevel@tonic-gate if ((ecc_err->ecc_fmri = fm_nvlist_create(nva)) != NULL) 6990Sstevel@tonic-gate fm_fmri_mem_set(ecc_err->ecc_fmri, 7000Sstevel@tonic-gate FM_MEM_SCHEME_VERSION, NULL, ecc_err->ecc_unum, 7010Sstevel@tonic-gate NULL); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, 7040Sstevel@tonic-gate ecc_err->ecc_ena, detector, 7050Sstevel@tonic-gate PCI_ECC_AFSR, DATA_TYPE_UINT64, ecc_err->ecc_afsr, 7060Sstevel@tonic-gate PCI_ECC_AFAR, DATA_TYPE_UINT64, ecc_err->ecc_aflt.flt_addr, 7070Sstevel@tonic-gate PCI_ECC_CTRL, DATA_TYPE_UINT64, ecc_err->ecc_ctrl, 7080Sstevel@tonic-gate PCI_ECC_SYND, DATA_TYPE_UINT16, ecc_err->ecc_aflt.flt_synd, 7090Sstevel@tonic-gate PCI_ECC_TYPE, DATA_TYPE_STRING, ecc_err->ecc_err_type, 7100Sstevel@tonic-gate PCI_ECC_DISP, DATA_TYPE_UINT64, ecc_err->ecc_aflt.flt_disp, 7110Sstevel@tonic-gate PCI_ECC_RESOURCE, DATA_TYPE_NVLIST, ecc_err->ecc_fmri, 7120Sstevel@tonic-gate NULL); 7130Sstevel@tonic-gate } else { 7140Sstevel@tonic-gate fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, 7150Sstevel@tonic-gate ecc_err->ecc_ena, detector, 7160Sstevel@tonic-gate PCI_ECC_AFSR, DATA_TYPE_UINT64, ecc_err->ecc_afsr, 7170Sstevel@tonic-gate PCI_ECC_CTRL, DATA_TYPE_UINT64, ecc_err->ecc_ctrl, 7180Sstevel@tonic-gate NULL); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate errorq_commit(fmhdl->fh_errorq, eqep, ERRORQ_ASYNC); 7210Sstevel@tonic-gate } 722