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