/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nb5000.h" #include "nb_log.h" #include "dimm_phys.h" int nb_check_validlog = 1; static uint32_t uerrcnt[2]; static uint32_t cerrcnta[2][2]; static uint32_t cerrcntb[2][2]; static uint32_t cerrcntc[2][2]; static uint32_t cerrcntd[2][2]; static nb_logout_t nb_log; struct mch_error_code { int intel_error_list; /* error number in Chipset Error List */ uint32_t emask; /* mask for machine check */ uint32_t error_bit; /* error bit in fault register */ }; static struct mch_error_code fat_fbd_error_code[] = { { 23, EMASK_FBD_M23, ERR_FAT_FBD_M23 }, { 3, EMASK_FBD_M3, ERR_FAT_FBD_M3 }, { 2, EMASK_FBD_M2, ERR_FAT_FBD_M2 }, { 1, EMASK_FBD_M1, ERR_FAT_FBD_M1 } }; static int intel_fat_fbd_err(uint32_t fat_fbd) { int rt = -1; int nerr = 0; uint32_t emask_fbd = 0; int i; int sz; sz = sizeof (fat_fbd_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (fat_fbd & fat_fbd_error_code[i].error_bit) { rt = fat_fbd_error_code[i].intel_error_list; emask_fbd |= fat_fbd_error_code[i].emask; nerr++; } } if (emask_fbd) nb_fbd_mask_mc(emask_fbd); if (nerr > 1) rt = -1; return (rt); } static char * fat_memory_error(const nb_regs_t *rp, void *data) { int channel; uint32_t ferr_fat_fbd, nrecmemb; uint32_t nrecmema; char *intr = "nb.unknown"; nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms; ferr_fat_fbd = rp->nb.fat_fbd_regs.ferr_fat_fbd; if ((ferr_fat_fbd & ERR_FAT_FBD_MASK) == 0) { sp->intel_error_list = intel_fat_fbd_err(rp->nb.fat_fbd_regs.nerr_fat_fbd); sp->branch = -1; sp->channel = -1; sp->rank = -1; sp->dimm = -1; sp->bank = -1; sp->cas = -1; sp->ras = -1; sp->pa = -1LL; sp->offset = -1; return (intr); } sp->intel_error_list = intel_fat_fbd_err(ferr_fat_fbd); channel = (ferr_fat_fbd >> 28) & 3; sp->branch = channel >> 1; sp->channel = channel; if ((ferr_fat_fbd & (ERR_FAT_FBD_M2|ERR_FAT_FBD_M1)) != 0) { if ((ferr_fat_fbd & ERR_FAT_FBD_M1) != 0) intr = "nb.fbd.alert"; /* Alert on FB-DIMM M1 */ else intr = "nb.fbd.crc"; /* CRC error FB_DIMM M2 */ nrecmema = rp->nb.fat_fbd_regs.nrecmema; nrecmemb = rp->nb.fat_fbd_regs.nrecmemb; sp->rank = (nrecmema >> 8) & RANK_MASK; sp->dimm = sp->rank >> 1; sp->bank = (nrecmema >> 12) & BANK_MASK; sp->cas = (nrecmemb >> 16) & CAS_MASK; sp->ras = nrecmemb & RAS_MASK; /* * If driver was built with closed tree present then we will * have Intel proprietary code for finding physaddr */ if (&dimm_getphys) { sp->pa = dimm_getphys((uint16_t)sp->branch, (uint16_t)sp->rank, (uint64_t)sp->bank, (uint64_t)sp->ras, (uint64_t)sp->cas); if (sp->pa >= MAXPHYS_ADDR) sp->pa = -1ULL; } else { sp->pa = -1ULL; } /* * If there is an offset decoder use it otherwise encode * rank/bank/ras/cas */ if (&dimm_getoffset) { sp->offset = dimm_getoffset(sp->branch, sp->rank, sp->bank, sp->ras, sp->cas); } else { sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras, sp->cas); } } else { if ((ferr_fat_fbd & ERR_FAT_FBD_M3) != 0) intr = "nb.fbd.otf"; /* thermal temp > Tmid M3 */ else if ((ferr_fat_fbd & ERR_FAT_FBD_M23) != 0) { intr = "nb.fbd.reset_timeout"; sp->channel = -1; } sp->rank = -1; sp->dimm = -1; sp->bank = -1; sp->cas = -1; sp->ras = -1; sp->pa = -1LL; sp->offset = -1; } return (intr); } static struct mch_error_code nf_fbd_error_code[] = { { 29, EMASK_FBD_M29, ERR_NF_FBD_M29 }, { 28, EMASK_FBD_M28, ERR_NF_FBD_M28 }, { 27, EMASK_FBD_M27, ERR_NF_FBD_M27 }, { 26, EMASK_FBD_M26, ERR_NF_FBD_M26 }, { 25, EMASK_FBD_M25, ERR_NF_FBD_M25 }, { 24, EMASK_FBD_M24, ERR_NF_FBD_M24 }, { 22, EMASK_FBD_M22, ERR_NF_FBD_M22 }, { 21, EMASK_FBD_M21, ERR_NF_FBD_M21 }, { 20, EMASK_FBD_M20, ERR_NF_FBD_M20 }, { 19, EMASK_FBD_M19, ERR_NF_FBD_M19 }, { 18, EMASK_FBD_M18, ERR_NF_FBD_M18 }, { 17, EMASK_FBD_M17, ERR_NF_FBD_M17 }, { 16, EMASK_FBD_M16, ERR_NF_FBD_M16 }, { 15, EMASK_FBD_M15, ERR_NF_FBD_M15 }, { 14, EMASK_FBD_M14, ERR_NF_FBD_M14 }, { 13, EMASK_FBD_M13, ERR_NF_FBD_M13 }, { 12, EMASK_FBD_M12, ERR_NF_FBD_M12 }, { 11, EMASK_FBD_M11, ERR_NF_FBD_M11 }, { 10, EMASK_FBD_M10, ERR_NF_FBD_M10 }, { 9, EMASK_FBD_M9, ERR_NF_FBD_M9 }, { 8, EMASK_FBD_M8, ERR_NF_FBD_M8 }, { 7, EMASK_FBD_M7, ERR_NF_FBD_M7 }, { 6, EMASK_FBD_M6, ERR_NF_FBD_M6 }, { 5, EMASK_FBD_M5, ERR_NF_FBD_M5 }, { 4, EMASK_FBD_M4, ERR_NF_FBD_M4 } }; static int intel_nf_fbd_err(uint32_t nf_fbd) { int rt = -1; int nerr = 0; uint32_t emask_fbd = 0; int i; int sz; sz = sizeof (nf_fbd_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (nf_fbd & nf_fbd_error_code[i].error_bit) { rt = nf_fbd_error_code[i].intel_error_list; emask_fbd |= nf_fbd_error_code[i].emask; nerr++; } } if (emask_fbd) nb_fbd_mask_mc(emask_fbd); if (nerr > 1) rt = -1; return (rt); } static char * nf_memory_error(const nb_regs_t *rp, void *data) { uint32_t ferr_nf_fbd, recmemb, redmemb; uint32_t recmema; int branch, channel, ecc_locator; char *intr = "nb.unknown"; nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms; sp->rank = -1; sp->dimm = -1; sp->bank = -1; sp->cas = -1; sp->ras = -1LL; sp->pa = -1LL; sp->offset = -1; ferr_nf_fbd = rp->nb.nf_fbd_regs.ferr_nf_fbd; if ((ferr_nf_fbd & ERR_NF_FBD_MASK) == 0) { /* unknown ereport if a recognizable error was not found */ sp->branch = -1; sp->channel = -1; sp->intel_error_list = -1; return (intr); } sp->intel_error_list = intel_nf_fbd_err(ferr_nf_fbd); channel = (ferr_nf_fbd >> ERR_FBD_CH_SHIFT) & 3; branch = channel >> 1; sp->branch = branch; sp->channel = channel; if (ferr_nf_fbd & ERR_NF_FBD_MASK) { if (ferr_nf_fbd & ERR_NF_FBD_ECC_UE) { /* * uncorrectable ECC M4 - M12 * we can only isolate to pair of dimms * for single dimm configuration let eversholt * sort it out with out needing a special rule */ sp->channel = -1; recmema = rp->nb.nf_fbd_regs.recmema; recmemb = rp->nb.nf_fbd_regs.recmemb; sp->rank = (recmema >> 8) & RANK_MASK; sp->bank = (recmema >> 12) & BANK_MASK; sp->cas = (recmemb >> 16) & CAS_MASK; sp->ras = recmemb & RAS_MASK; intr = "nb.mem_ue"; } else if (ferr_nf_fbd & ERR_NF_FBD_M13) { /* * write error M13 * we can only isolate to pair of dimms */ sp->channel = -1; if (nb_mode != NB_MEMORY_MIRROR) { recmema = rp->nb.nf_fbd_regs.recmema; recmemb = rp->nb.nf_fbd_regs.recmemb; sp->rank = (recmema >> 8) & RANK_MASK; sp->bank = (recmema >> 12) & BANK_MASK; sp->cas = (recmemb >> 16) & CAS_MASK; sp->ras = recmemb & RAS_MASK; } intr = "nb.fbd.ma"; /* memory alert */ } else if (ferr_nf_fbd & ERR_NF_FBD_MA) { /* M14, M15 and M21 */ intr = "nb.fbd.ch"; /* FBD on channel */ } else if ((ferr_nf_fbd & ERR_NF_FBD_ECC_CE) != 0) { /* correctable ECC M17-M20 */ recmema = rp->nb.nf_fbd_regs.recmema; recmemb = rp->nb.nf_fbd_regs.recmemb; sp->rank = (recmema >> 8) & RANK_MASK; redmemb = rp->nb.nf_fbd_regs.redmemb; ecc_locator = redmemb & 0x3ffff; if (ecc_locator & 0x1ff) sp->channel = branch << 1; else if (ecc_locator & 0x3fe00) sp->channel = (branch << 1) + 1; sp->dimm = sp->rank >> 1; sp->bank = (recmema >> 12) & BANK_MASK; sp->cas = (recmemb >> 16) & CAS_MASK; sp->ras = recmemb & RAS_MASK; intr = "nb.mem_ce"; } else if ((ferr_nf_fbd & ERR_NF_FBD_SPARE) != 0) { /* spare dimm M27, M28 */ intr = "nb.mem_ds"; sp->channel = -1; if (rp->nb.nf_fbd_regs.spcps & SPCPS_SPARE_DEPLOYED) { sp->rank = SPCPS_FAILED_RANK(rp->nb.nf_fbd_regs.spcps); nb_used_spare_rank(sp->branch, sp->rank); nb_config_gen++; } } else if ((ferr_nf_fbd & ERR_NF_FBD_M22) != 0) { intr = "nb.spd"; /* SPD protocol */ } } if (sp->ras != -1) { /* * If driver was built with closed tree present then we will * have Intel proprietary code for finding physaddr */ if (&dimm_getphys) { sp->pa = dimm_getphys((uint16_t)sp->branch, (uint16_t)sp->rank, (uint64_t)sp->bank, (uint64_t)sp->ras, (uint64_t)sp->cas); if (sp->pa >= MAXPHYS_ADDR) sp->pa = -1ULL; } else { sp->pa = -1ULL; } if (&dimm_getoffset) { sp->offset = dimm_getoffset(sp->branch, sp->rank, sp->bank, sp->ras, sp->cas); } else { sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras, sp->cas); } } return (intr); } static struct mch_error_code nf_mem_error_code[] = { { 21, EMASK_MEM_M21, ERR_NF_MEM_M21 }, { 20, EMASK_MEM_M20, ERR_NF_MEM_M20 }, { 18, EMASK_MEM_M18, ERR_NF_MEM_M18 }, { 16, EMASK_MEM_M16, ERR_NF_MEM_M16 }, { 15, EMASK_MEM_M15, ERR_NF_MEM_M15 }, { 14, EMASK_MEM_M14, ERR_NF_MEM_M14 }, { 12, EMASK_MEM_M12, ERR_NF_MEM_M12 }, { 11, EMASK_MEM_M11, ERR_NF_MEM_M11 }, { 10, EMASK_MEM_M10, ERR_NF_MEM_M10 }, { 6, EMASK_MEM_M6, ERR_NF_MEM_M6 }, { 5, EMASK_MEM_M5, ERR_NF_MEM_M5 }, { 4, EMASK_MEM_M4, ERR_NF_MEM_M4 }, { 1, EMASK_MEM_M1, ERR_NF_MEM_M1 } }; static int intel_nf_mem_err(uint32_t nf_mem) { int rt = -1; int nerr = 0; uint32_t emask_mem = 0; int i; int sz; sz = sizeof (nf_mem_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (nf_mem & nf_mem_error_code[i].error_bit) { rt = nf_mem_error_code[i].intel_error_list; emask_mem |= nf_mem_error_code[i].emask; nerr++; } } if (emask_mem) nb_mem_mask_mc(emask_mem); if (nerr > 1) rt = -1; return (rt); } static char * nf_mem_error(const nb_regs_t *rp, void *data) { uint32_t ferr_nf_mem, recmema, recmemb; uint32_t nrecmema, nrecmemb, validlog; int channel; char *intr = "nb.unknown"; nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms; sp->rank = -1; sp->dimm = -1; sp->bank = -1; sp->cas = -1; sp->ras = -1LL; sp->pa = -1LL; sp->offset = -1; ferr_nf_mem = rp->nb.nf_mem_regs.ferr_nf_mem; if ((ferr_nf_mem & ERR_NF_MEM_MASK) == 0) { /* no first error found */ sp->branch = -1; sp->channel = -1; sp->intel_error_list = intel_nf_mem_err(rp->nb.nf_mem_regs.nerr_nf_mem); return (intr); } sp->intel_error_list = intel_nf_mem_err(ferr_nf_mem); channel = (ferr_nf_mem >> ERR_MEM_CH_SHIFT) & 0x1; sp->branch = channel; sp->channel = -1; if (ferr_nf_mem & ERR_NF_MEM_MASK) { if (ferr_nf_mem & ERR_NF_MEM_ECC_UE) { /* * uncorrectable ECC M1,M4-M6,M10-M12 * There is only channel per branch * Invalidate the channel number so the mem ereport * has the same detector with existing 5000 ereports. * so we can leverage the existing Everhsolt rule. */ validlog = rp->nb.nf_mem_regs.validlog; if (ferr_nf_mem & ERR_NF_MEM_M1) { nrecmema = rp->nb.nf_mem_regs.nrecmema; nrecmemb = rp->nb.nf_mem_regs.nrecmemb; /* check if the nrecmem log is valid */ if (validlog & 0x1 || nb_check_validlog == 0) { sp->rank = (nrecmema >> 8) & RANK_MASK; sp->bank = (nrecmema >> 12) & BANK_MASK; sp->cas = (nrecmemb >> 16) & CAS_MASK; sp->ras = nrecmemb & RAS_MASK; } } else { recmema = rp->nb.nf_mem_regs.recmema; recmemb = rp->nb.nf_mem_regs.recmemb; /* check if the recmem log is valid */ if (validlog & 0x2 || nb_check_validlog == 0) { sp->rank = (recmema >> 8) & RANK_MASK; sp->bank = (recmema >> 12) & BANK_MASK; sp->cas = (recmemb >> 16) & CAS_MASK; sp->ras = recmemb & RAS_MASK; } } intr = "nb.ddr2_mem_ue"; } else if ((ferr_nf_mem & ERR_NF_MEM_ECC_CE) != 0) { /* correctable ECC M14-M16 */ recmema = rp->nb.nf_mem_regs.recmema; recmemb = rp->nb.nf_mem_regs.recmemb; validlog = rp->nb.nf_mem_regs.validlog; /* check if the recmem log is valid */ if (validlog & 0x2 || nb_check_validlog == 0) { sp->channel = channel; sp->rank = (recmema >> 8) & RANK_MASK; sp->dimm = nb_rank2dimm(sp->channel, sp->rank); sp->bank = (recmema >> 12) & BANK_MASK; sp->cas = (recmemb >> 16) & CAS_MASK; sp->ras = recmemb & RAS_MASK; } intr = "nb.ddr2_mem_ce"; } else if ((ferr_nf_mem & ERR_NF_MEM_SPARE) != 0) { /* spare dimm M20, M21 */ intr = "nb.ddr2_mem_ds"; /* * The channel can be valid here. * However, there is only one channel per branch and * to leverage the eversolt rules of other chipsets, * the channel is ignored and let the rule find it out * from the topology. */ if (rp->nb.nf_mem_regs.spcps & SPCPS_SPARE_DEPLOYED) { sp->rank = SPCPS_FAILED_RANK(rp->nb.nf_mem_regs.spcps); nb_used_spare_rank(sp->branch, sp->rank); nb_config_gen++; } } else if ((ferr_nf_mem & ERR_NF_MEM_M18) != 0) { sp->channel = channel; intr = "nb.ddr2_spd"; /* SPD protocol */ } } if (sp->ras != -1) { /* * If driver was built with closed tree present then we will * have Intel proprietary code for finding physaddr */ if (&dimm_getphys) { sp->pa = dimm_getphys((uint16_t)sp->branch, (uint16_t)sp->rank, (uint64_t)sp->bank, (uint64_t)sp->ras, (uint64_t)sp->cas); if (sp->pa >= MAXPHYS_ADDR) sp->pa = -1ULL; } else { sp->pa = -1ULL; } if (&dimm_getoffset) { sp->offset = dimm_getoffset(sp->branch, sp->rank, sp->bank, sp->ras, sp->cas); } else { sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras, sp->cas); } } return (intr); } static struct mch_error_code fat_int_error_code[] = { { 14, EMASK_INT_B14, ERR_FAT_INT_B14 }, { 12, EMASK_INT_B12, ERR_FAT_INT_B12 }, { 25, EMASK_INT_B25, ERR_FAT_INT_B25 }, { 23, EMASK_INT_B23, ERR_FAT_INT_B23 }, { 21, EMASK_INT_B21, ERR_FAT_INT_B21 }, { 7, EMASK_INT_B7, ERR_FAT_INT_B7 }, { 4, EMASK_INT_B4, ERR_FAT_INT_B4 }, { 3, EMASK_INT_B3, ERR_FAT_INT_B3 }, { 2, EMASK_INT_B2, ERR_FAT_INT_B2 }, { 1, EMASK_INT_B1, ERR_FAT_INT_B1 } }; static struct mch_error_code nf_int_error_code[] = { { 27, 0, ERR_NF_INT_B27 }, { 24, 0, ERR_NF_INT_B24 }, { 22, EMASK_INT_B22, ERR_NF_INT_B22 }, { 20, EMASK_INT_B20, ERR_NF_INT_B20 }, { 19, EMASK_INT_B19, ERR_NF_INT_B19 }, { 18, 0, ERR_NF_INT_B18 }, { 17, 0, ERR_NF_INT_B17 }, { 16, 0, ERR_NF_INT_B16 }, { 11, EMASK_INT_B11, ERR_NF_INT_B11 }, { 10, EMASK_INT_B10, ERR_NF_INT_B10 }, { 9, EMASK_INT_B9, ERR_NF_INT_B9 }, { 8, EMASK_INT_B8, ERR_NF_INT_B8 }, { 6, EMASK_INT_B6, ERR_NF_INT_B6 }, { 5, EMASK_INT_B5, ERR_NF_INT_B5 } }; static int intel_int_err(uint16_t err_fat_int, uint16_t err_nf_int) { int rt = -1; int nerr = 0; uint32_t emask_int = 0; int i; int sz; sz = sizeof (fat_int_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (err_fat_int & fat_int_error_code[i].error_bit) { rt = fat_int_error_code[i].intel_error_list; emask_int |= fat_int_error_code[i].emask; nerr++; } } if (nb_chipset == INTEL_NB_5400 && (err_nf_int & NERR_NF_5400_INT_B26) != 0) { err_nf_int &= ~NERR_NF_5400_INT_B26; rt = 26; nerr++; } if (rt) err_nf_int &= ~ERR_NF_INT_B18; sz = sizeof (nf_int_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (err_nf_int & nf_int_error_code[i].error_bit) { rt = nf_int_error_code[i].intel_error_list; emask_int |= nf_int_error_code[i].emask; nerr++; } } if (emask_int) nb_int_mask_mc(emask_int); if (nerr > 1) rt = -1; return (rt); } static int log_int_err(nb_regs_t *rp, int willpanic, int *interpose) { int t = 0; int rt = 0; rp->flag = NB_REG_LOG_INT; rp->nb.int_regs.ferr_fat_int = FERR_FAT_INT_RD(interpose); rp->nb.int_regs.ferr_nf_int = FERR_NF_INT_RD(&t); *interpose |= t; rp->nb.int_regs.nerr_fat_int = NERR_FAT_INT_RD(&t); *interpose |= t; rp->nb.int_regs.nerr_nf_int = NERR_NF_INT_RD(&t); *interpose |= t; rp->nb.int_regs.nrecint = NRECINT_RD(); rp->nb.int_regs.recint = RECINT_RD(); rp->nb.int_regs.nrecsf = NRECSF_RD(); rp->nb.int_regs.recsf = RECSF_RD(); if (!willpanic) { if (rp->nb.int_regs.ferr_fat_int || *interpose) FERR_FAT_INT_WR(rp->nb.int_regs.ferr_fat_int); if (rp->nb.int_regs.ferr_nf_int || *interpose) FERR_NF_INT_WR(rp->nb.int_regs.ferr_nf_int); if (rp->nb.int_regs.nerr_fat_int) NERR_FAT_INT_WR(rp->nb.int_regs.nerr_fat_int); if (rp->nb.int_regs.nerr_nf_int) NERR_NF_INT_WR(rp->nb.int_regs.nerr_nf_int); /* * if interpose write read-only registers to clear from pcii * cache */ if (*interpose) { NRECINT_WR(); RECINT_WR(); NRECSF_WR(); RECSF_WR(); } } if (rp->nb.int_regs.ferr_fat_int == 0 && rp->nb.int_regs.nerr_fat_int == 0 && (rp->nb.int_regs.ferr_nf_int == ERR_NF_INT_B18 || (rp->nb.int_regs.ferr_nf_int == 0 && rp->nb.int_regs.nerr_nf_int == ERR_NF_INT_B18))) { rt = 1; } return (rt); } static void log_thermal_err(nb_regs_t *rp, int willpanic, int *interpose) { int t = 0; rp->flag = NB_REG_LOG_THR; rp->nb.thr_regs.ferr_fat_thr = FERR_FAT_THR_RD(interpose); rp->nb.thr_regs.nerr_fat_thr = NERR_FAT_THR_RD(&t); *interpose |= t; rp->nb.thr_regs.ferr_nf_thr = FERR_NF_THR_RD(&t); *interpose |= t; rp->nb.thr_regs.nerr_nf_thr = NERR_NF_THR_RD(&t); *interpose |= t; rp->nb.thr_regs.ctsts = CTSTS_RD(); rp->nb.thr_regs.thrtsts = THRTSTS_RD(); if (!willpanic) { if (rp->nb.thr_regs.ferr_fat_thr || *interpose) FERR_FAT_THR_WR(rp->nb.thr_regs.ferr_fat_thr); if (rp->nb.thr_regs.nerr_fat_thr || *interpose) NERR_FAT_THR_WR(rp->nb.thr_regs.nerr_fat_thr); if (rp->nb.thr_regs.ferr_nf_thr || *interpose) FERR_NF_THR_WR(rp->nb.thr_regs.ferr_nf_thr); if (rp->nb.thr_regs.nerr_nf_thr || *interpose) NERR_NF_THR_WR(rp->nb.thr_regs.nerr_nf_thr); if (*interpose) { CTSTS_WR(rp->nb.thr_regs.ctsts); THRTSTS_WR(rp->nb.thr_regs.thrtsts); } } } static void log_dma_err(nb_regs_t *rp, int *interpose) { rp->flag = NB_REG_LOG_DMA; rp->nb.dma_regs.pcists = PCISTS_RD(interpose); rp->nb.dma_regs.pexdevsts = PCIDEVSTS_RD(); } static struct mch_error_code fat_fsb_error_code[] = { { 9, EMASK_FSB_F9, ERR_FAT_FSB_F9 }, { 2, EMASK_FSB_F2, ERR_FAT_FSB_F2 }, { 1, EMASK_FSB_F1, ERR_FAT_FSB_F1 } }; static struct mch_error_code nf_fsb_error_code[] = { { 8, EMASK_FSB_F8, ERR_NF_FSB_F8 }, { 7, EMASK_FSB_F7, ERR_NF_FSB_F7 }, { 6, EMASK_FSB_F6, ERR_NF_FSB_F6 } }; static int intel_fsb_err(int fsb, uint8_t err_fat_fsb, uint8_t err_nf_fsb) { int rt = -1; int nerr = 0; uint16_t emask_fsb = 0; int i; int sz; sz = sizeof (fat_fsb_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (err_fat_fsb & fat_fsb_error_code[i].error_bit) { rt = fat_fsb_error_code[i].intel_error_list; emask_fsb |= fat_fsb_error_code[i].emask; nerr++; } } sz = sizeof (nf_fsb_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (err_nf_fsb & nf_fsb_error_code[i].error_bit) { rt = nf_fsb_error_code[i].intel_error_list; emask_fsb |= nf_fsb_error_code[i].emask; nerr++; } } if (emask_fsb) nb_fsb_mask_mc(fsb, emask_fsb); if (nerr > 1) rt = -1; return (rt); } static void log_fsb_err(uint64_t ferr, nb_regs_t *rp, int willpanic, int *interpose) { uint8_t fsb; int t = 0; fsb = GE_FERR_FSB(ferr); rp->flag = NB_REG_LOG_FSB; rp->nb.fsb_regs.fsb = fsb; rp->nb.fsb_regs.ferr_fat_fsb = FERR_FAT_FSB_RD(fsb, interpose); rp->nb.fsb_regs.ferr_nf_fsb = FERR_NF_FSB_RD(fsb, &t); *interpose |= t; rp->nb.fsb_regs.nerr_fat_fsb = NERR_FAT_FSB_RD(fsb, &t); *interpose |= t; rp->nb.fsb_regs.nerr_nf_fsb = NERR_NF_FSB_RD(fsb, &t); *interpose |= t; rp->nb.fsb_regs.nrecfsb = NRECFSB_RD(fsb); rp->nb.fsb_regs.nrecfsb_addr = NRECADDR_RD(fsb); rp->nb.fsb_regs.recfsb = RECFSB_RD(fsb); if (!willpanic) { /* Clear the fatal/non-fatal first/next FSB errors */ if (rp->nb.fsb_regs.ferr_fat_fsb || *interpose) FERR_FAT_FSB_WR(fsb, rp->nb.fsb_regs.ferr_fat_fsb); if (rp->nb.fsb_regs.ferr_nf_fsb || *interpose) FERR_NF_FSB_WR(fsb, rp->nb.fsb_regs.ferr_nf_fsb); if (rp->nb.fsb_regs.nerr_fat_fsb || *interpose) NERR_FAT_FSB_WR(fsb, rp->nb.fsb_regs.nerr_fat_fsb); if (rp->nb.fsb_regs.nerr_nf_fsb || *interpose) NERR_NF_FSB_WR(fsb, rp->nb.fsb_regs.nerr_nf_fsb); /* * if interpose write read-only registers to clear from pcii * cache */ if (*interpose) { NRECFSB_WR(fsb); NRECADDR_WR(fsb); RECFSB_WR(fsb); } } } static struct mch_error_code fat_pex_error_code[] = { { 19, EMASK_UNCOR_PEX_IO19, PEX_FAT_IO19 }, { 18, EMASK_UNCOR_PEX_IO18, PEX_FAT_IO18 }, { 10, EMASK_UNCOR_PEX_IO10, PEX_FAT_IO10 }, { 9, EMASK_UNCOR_PEX_IO9, PEX_FAT_IO9 }, { 8, EMASK_UNCOR_PEX_IO8, PEX_FAT_IO8 }, { 7, EMASK_UNCOR_PEX_IO7, PEX_FAT_IO7 }, { 6, EMASK_UNCOR_PEX_IO6, PEX_FAT_IO6 }, { 5, EMASK_UNCOR_PEX_IO5, PEX_FAT_IO5 }, { 4, EMASK_UNCOR_PEX_IO4, PEX_FAT_IO4 }, { 3, EMASK_UNCOR_PEX_IO3, PEX_FAT_IO3 }, { 2, EMASK_UNCOR_PEX_IO2, PEX_FAT_IO2 }, { 0, EMASK_UNCOR_PEX_IO0, PEX_FAT_IO0 } }; static struct mch_error_code fat_unit_pex_5400_error_code[] = { { 32, EMASK_UNIT_PEX_IO32, PEX_5400_FAT_IO32 }, { 31, EMASK_UNIT_PEX_IO31, PEX_5400_FAT_IO31 }, { 30, EMASK_UNIT_PEX_IO30, PEX_5400_FAT_IO30 }, { 29, EMASK_UNIT_PEX_IO29, PEX_5400_FAT_IO29 }, { 27, EMASK_UNIT_PEX_IO27, PEX_5400_FAT_IO27 }, { 26, EMASK_UNIT_PEX_IO26, PEX_5400_FAT_IO26 }, { 25, EMASK_UNIT_PEX_IO25, PEX_5400_FAT_IO25 }, { 24, EMASK_UNIT_PEX_IO24, PEX_5400_FAT_IO24 }, { 23, EMASK_UNIT_PEX_IO23, PEX_5400_FAT_IO23 }, { 22, EMASK_UNIT_PEX_IO22, PEX_5400_FAT_IO22 }, }; static struct mch_error_code fat_pex_5400_error_code[] = { { 19, EMASK_UNCOR_PEX_IO19, PEX_5400_FAT_IO19 }, { 18, EMASK_UNCOR_PEX_IO18, PEX_5400_FAT_IO18 }, { 10, EMASK_UNCOR_PEX_IO10, PEX_5400_FAT_IO10 }, { 9, EMASK_UNCOR_PEX_IO9, PEX_5400_FAT_IO9 }, { 8, EMASK_UNCOR_PEX_IO8, PEX_5400_FAT_IO8 }, { 7, EMASK_UNCOR_PEX_IO7, PEX_5400_FAT_IO7 }, { 6, EMASK_UNCOR_PEX_IO6, PEX_5400_FAT_IO6 }, { 5, EMASK_UNCOR_PEX_IO5, PEX_5400_FAT_IO5 }, { 4, EMASK_UNCOR_PEX_IO4, PEX_5400_FAT_IO4 }, { 2, EMASK_UNCOR_PEX_IO2, PEX_5400_FAT_IO2 }, { 0, EMASK_UNCOR_PEX_IO0, PEX_5400_FAT_IO0 } }; static struct mch_error_code fat_rp_5400_error_code[] = { { 1, EMASK_RP_PEX_IO1, PEX_5400_FAT_IO1 } }; static struct mch_error_code fat_rp_error_code[] = { { 1, EMASK_RP_PEX_IO1, PEX_FAT_IO1 } }; static struct mch_error_code uncor_pex_error_code[] = { { 19, EMASK_UNCOR_PEX_IO19, PEX_NF_IO19 }, { 9, EMASK_UNCOR_PEX_IO9, PEX_NF_IO9 }, { 8, EMASK_UNCOR_PEX_IO8, PEX_NF_IO8 }, { 7, EMASK_UNCOR_PEX_IO7, PEX_NF_IO7 }, { 6, EMASK_UNCOR_PEX_IO6, PEX_NF_IO6 }, { 5, EMASK_UNCOR_PEX_IO5, PEX_NF_IO5 }, { 4, EMASK_UNCOR_PEX_IO4, PEX_NF_IO4 }, { 3, EMASK_UNCOR_PEX_IO3, PEX_NF_IO3 }, { 0, EMASK_UNCOR_PEX_IO0, PEX_NF_IO0 } }; static struct mch_error_code uncor_pex_5400_error_code[] = { { 33, EMASK_UNIT_PEX_IO33, PEX_5400_NF_IO33 }, { 32, EMASK_UNIT_PEX_IO32, PEX_5400_NF_IO32 }, { 31, EMASK_UNIT_PEX_IO31, PEX_5400_NF_IO31 }, { 30, EMASK_UNIT_PEX_IO30, PEX_5400_NF_IO30 }, { 29, EMASK_UNIT_PEX_IO29, PEX_5400_NF_IO29 }, { 28, EMASK_UNIT_PEX_IO28, PEX_5400_NF_IO28 }, { 27, EMASK_UNIT_PEX_IO27, PEX_5400_NF_IO27 }, { 26, EMASK_UNIT_PEX_IO26, PEX_5400_NF_IO26 }, { 25, EMASK_UNIT_PEX_IO25, PEX_5400_NF_IO25 }, { 24, EMASK_UNIT_PEX_IO24, PEX_5400_NF_IO24 }, { 23, EMASK_UNIT_PEX_IO23, PEX_5400_NF_IO23 }, }; static struct mch_error_code cor_pex_error_code[] = { { 20, EMASK_COR_PEX_IO20, PEX_5400_NF_IO20 }, { 16, EMASK_COR_PEX_IO16, PEX_NF_IO16 }, { 15, EMASK_COR_PEX_IO15, PEX_NF_IO15 }, { 14, EMASK_COR_PEX_IO14, PEX_NF_IO14 }, { 13, EMASK_COR_PEX_IO13, PEX_NF_IO13 }, { 12, EMASK_COR_PEX_IO12, PEX_NF_IO12 }, { 10, 0, PEX_NF_IO10 }, { 2, 0, PEX_NF_IO2 } }; static struct mch_error_code rp_pex_5400_error_code[] = { { 17, EMASK_RP_PEX_IO17, PEX_5400_NF_IO17 }, { 11, EMASK_RP_PEX_IO11, PEX_5400_NF_IO11 } }; static struct mch_error_code cor_pex_5400_error_code1[] = { { 19, EMASK_UNCOR_PEX_IO19, PEX_5400_NF_IO19 }, { 10, EMASK_UNCOR_PEX_IO10, PEX_5400_NF_IO10 }, { 9, EMASK_UNCOR_PEX_IO9, PEX_5400_NF_IO9 }, { 8, EMASK_UNCOR_PEX_IO8, PEX_5400_NF_IO8 }, { 7, EMASK_UNCOR_PEX_IO7, PEX_5400_NF_IO7 }, { 6, EMASK_UNCOR_PEX_IO6, PEX_5400_NF_IO6 }, { 5, EMASK_UNCOR_PEX_IO5, PEX_5400_NF_IO5 }, { 4, EMASK_UNCOR_PEX_IO4, PEX_5400_NF_IO4 }, { 2, EMASK_UNCOR_PEX_IO2, PEX_5400_NF_IO2 }, { 0, EMASK_UNCOR_PEX_IO0, PEX_5400_NF_IO0 } }; static struct mch_error_code cor_pex_5400_error_code2[] = { { 20, EMASK_COR_PEX_IO20, PEX_5400_NF_IO20 }, { 16, EMASK_COR_PEX_IO16, PEX_5400_NF_IO16 }, { 15, EMASK_COR_PEX_IO15, PEX_5400_NF_IO15 }, { 14, EMASK_COR_PEX_IO14, PEX_5400_NF_IO14 }, { 13, EMASK_COR_PEX_IO13, PEX_5400_NF_IO13 }, { 12, EMASK_COR_PEX_IO12, PEX_5400_NF_IO12 } }; static struct mch_error_code cor_pex_5400_error_code3[] = { { 33, EMASK_UNIT_PEX_IO33, PEX_5400_NF_IO33 }, { 32, EMASK_UNIT_PEX_IO32, PEX_5400_NF_IO32 }, { 31, EMASK_UNIT_PEX_IO31, PEX_5400_NF_IO31 }, { 30, EMASK_UNIT_PEX_IO30, PEX_5400_NF_IO30 }, { 29, EMASK_UNIT_PEX_IO29, PEX_5400_NF_IO29 }, { 28, EMASK_UNIT_PEX_IO28, PEX_5400_NF_IO28 }, { 27, EMASK_UNIT_PEX_IO27, PEX_5400_NF_IO27 }, { 26, EMASK_UNIT_PEX_IO26, PEX_5400_NF_IO26 }, { 25, EMASK_UNIT_PEX_IO25, PEX_5400_NF_IO25 }, { 24, EMASK_UNIT_PEX_IO24, PEX_5400_NF_IO24 }, { 23, EMASK_UNIT_PEX_IO23, PEX_5400_NF_IO23 } }; static struct mch_error_code rp_pex_error_code[] = { { 17, EMASK_RP_PEX_IO17, PEX_NF_IO17 }, { 11, EMASK_RP_PEX_IO11, PEX_NF_IO11 }, }; static int intel_pex_err(uint32_t pex_fat, uint32_t pex_nf_cor) { int rt = -1; int nerr = 0; int i; int sz; sz = sizeof (fat_pex_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_fat & fat_pex_error_code[i].error_bit) { rt = fat_pex_error_code[i].intel_error_list; nerr++; } } sz = sizeof (fat_rp_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_fat & fat_rp_error_code[i].error_bit) { rt = fat_rp_error_code[i].intel_error_list; nerr++; } } sz = sizeof (uncor_pex_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_nf_cor & uncor_pex_error_code[i].error_bit) { rt = uncor_pex_error_code[i].intel_error_list; nerr++; } } sz = sizeof (cor_pex_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_nf_cor & cor_pex_error_code[i].error_bit) { rt = cor_pex_error_code[i].intel_error_list; nerr++; } } sz = sizeof (rp_pex_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_nf_cor & rp_pex_error_code[i].error_bit) { rt = rp_pex_error_code[i].intel_error_list; nerr++; } } if (nerr > 1) rt = -1; return (rt); } static struct mch_error_code fat_thr_error_code[] = { { 2, EMASK_THR_F2, ERR_FAT_THR_F2 }, { 1, EMASK_THR_F1, ERR_FAT_THR_F1 } }; static struct mch_error_code nf_thr_error_code[] = { { 5, EMASK_THR_F5, ERR_NF_THR_F5 }, { 4, EMASK_THR_F4, ERR_NF_THR_F4 }, { 3, EMASK_THR_F3, ERR_NF_THR_F3 } }; static int intel_thr_err(uint8_t err_fat_thr, uint8_t err_nf_thr) { int rt = -1; int nerr = 0; uint16_t emask_thr = 0; int i; int sz; sz = sizeof (fat_thr_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (err_fat_thr & fat_thr_error_code[i].error_bit) { rt = fat_thr_error_code[i].intel_error_list; emask_thr |= fat_thr_error_code[i].emask; nerr++; } } sz = sizeof (nf_thr_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (err_nf_thr & nf_thr_error_code[i].error_bit) { rt = nf_thr_error_code[i].intel_error_list; emask_thr |= nf_thr_error_code[i].emask; nerr++; } } if (emask_thr) nb_thr_mask_mc(emask_thr); if (nerr > 1) rt = -1; return (rt); } static int intel_pex_5400_err(uint32_t pex_fat, uint32_t pex_nf_cor) { int rt = -1; int nerr = 0; int i; int sz; sz = sizeof (fat_pex_5400_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_fat & fat_pex_5400_error_code[i].error_bit) { rt = fat_pex_5400_error_code[i].intel_error_list; nerr++; } } sz = sizeof (fat_rp_5400_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_fat & fat_rp_5400_error_code[i].error_bit) { rt = fat_rp_5400_error_code[i].intel_error_list; nerr++; } } sz = sizeof (fat_unit_pex_5400_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_fat & fat_unit_pex_5400_error_code[i].error_bit) { rt = fat_unit_pex_5400_error_code[i].intel_error_list; nerr++; } } sz = sizeof (uncor_pex_5400_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_fat & uncor_pex_5400_error_code[i].error_bit) { rt = uncor_pex_5400_error_code[i].intel_error_list; nerr++; } } sz = sizeof (rp_pex_5400_error_code) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_nf_cor & rp_pex_5400_error_code[i].error_bit) { rt = rp_pex_5400_error_code[i].intel_error_list; nerr++; } } sz = sizeof (cor_pex_5400_error_code1) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_nf_cor & cor_pex_5400_error_code1[i].error_bit) { rt = cor_pex_5400_error_code1[i].intel_error_list; nerr++; } } sz = sizeof (cor_pex_5400_error_code2) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_nf_cor & cor_pex_5400_error_code2[i].error_bit) { rt = cor_pex_5400_error_code2[i].intel_error_list; nerr++; } } sz = sizeof (cor_pex_5400_error_code3) / sizeof (struct mch_error_code); for (i = 0; i < sz; i++) { if (pex_nf_cor & cor_pex_5400_error_code3[i].error_bit) { rt = cor_pex_5400_error_code3[i].intel_error_list; nerr++; } } if (nerr > 1) rt = -1; return (rt); } static int log_pex_err(uint64_t ferr, nb_regs_t *rp, int willpanic, int *interpose) { uint8_t pex = (uint8_t)-1; int t = 0; rp->flag = NB_REG_LOG_PEX; pex = GE_ERR_PEX(ferr); rp->nb.pex_regs.pex = pex; rp->nb.pex_regs.pex_fat_ferr = PEX_FAT_FERR_RD(pex, interpose); rp->nb.pex_regs.pex_fat_nerr = PEX_FAT_NERR_RD(pex, &t); *interpose |= t; rp->nb.pex_regs.pex_nf_corr_ferr = PEX_NF_FERR_RD(pex, &t); *interpose |= t; rp->nb.pex_regs.pex_nf_corr_nerr = PEX_NF_NERR_RD(pex, &t); *interpose |= t; if (rp->nb.pex_regs.pex_fat_ferr == 0 && rp->nb.pex_regs.pex_fat_nerr == 0 && rp->nb.pex_regs.pex_nf_corr_ferr == 0 && rp->nb.pex_regs.pex_nf_corr_nerr == 0) return (0); rp->nb.pex_regs.uncerrsev = UNCERRSEV_RD(pex); rp->nb.pex_regs.rperrsts = RPERRSTS_RD(pex); rp->nb.pex_regs.rperrsid = RPERRSID_RD(pex); if (pex != (uint8_t)-1) rp->nb.pex_regs.uncerrsts = UNCERRSTS_RD(pex); else rp->nb.pex_regs.uncerrsts = 0; rp->nb.pex_regs.aerrcapctrl = AERRCAPCTRL_RD(pex); rp->nb.pex_regs.corerrsts = CORERRSTS_RD(pex); rp->nb.pex_regs.pexdevsts = PEXDEVSTS_RD(pex); if (!willpanic) { if (rp->nb.pex_regs.pex_fat_ferr || *interpose) PEX_FAT_FERR_WR(pex, rp->nb.pex_regs.pex_fat_ferr); if (rp->nb.pex_regs.pex_fat_nerr) PEX_FAT_NERR_WR(pex, rp->nb.pex_regs.pex_fat_nerr); if (rp->nb.pex_regs.pex_nf_corr_ferr || *interpose) PEX_NF_FERR_WR(pex, rp->nb.pex_regs.pex_nf_corr_ferr); if (rp->nb.pex_regs.pex_nf_corr_nerr) PEX_NF_NERR_WR(pex, rp->nb.pex_regs.pex_nf_corr_nerr); if (*interpose) UNCERRSTS_WR(pex, rp->nb.pex_regs.uncerrsts); if (*interpose) RPERRSTS_WR(pex, rp->nb.pex_regs.rperrsts); if (*interpose) PEXDEVSTS_WR(pex, 0); } return (1); } static void log_fat_fbd_err(nb_regs_t *rp, int willpanic, int *interpose) { int channel, branch; int t = 0; rp->flag = NB_REG_LOG_FAT_FBD; rp->nb.fat_fbd_regs.ferr_fat_fbd = FERR_FAT_FBD_RD(interpose); channel = (rp->nb.fat_fbd_regs.ferr_fat_fbd >> 28) & 3; branch = channel >> 1; rp->nb.fat_fbd_regs.nerr_fat_fbd = NERR_FAT_FBD_RD(&t); *interpose |= t; rp->nb.fat_fbd_regs.nrecmema = NRECMEMA_RD(branch); rp->nb.fat_fbd_regs.nrecmemb = NRECMEMB_RD(branch); rp->nb.fat_fbd_regs.nrecfglog = NRECFGLOG_RD(branch); rp->nb.fat_fbd_regs.nrecfbda = NRECFBDA_RD(branch); rp->nb.fat_fbd_regs.nrecfbdb = NRECFBDB_RD(branch); rp->nb.fat_fbd_regs.nrecfbdc = NRECFBDC_RD(branch); rp->nb.fat_fbd_regs.nrecfbdd = NRECFBDD_RD(branch); rp->nb.fat_fbd_regs.nrecfbde = NRECFBDE_RD(branch); rp->nb.fat_fbd_regs.nrecfbdf = NRECFBDF_RD(branch); rp->nb.fat_fbd_regs.spcps = SPCPS_RD(branch); rp->nb.fat_fbd_regs.spcpc = SPCPC_RD(branch); rp->nb.fat_fbd_regs.uerrcnt = UERRCNT_RD(branch); rp->nb.fat_fbd_regs.uerrcnt_last = uerrcnt[branch]; uerrcnt[branch] = rp->nb.fat_fbd_regs.uerrcnt; rp->nb.fat_fbd_regs.badrama = BADRAMA_RD(branch); rp->nb.fat_fbd_regs.badramb = BADRAMB_RD(branch); rp->nb.fat_fbd_regs.badcnt = BADCNT_RD(branch); if (!willpanic) { if (rp->nb.fat_fbd_regs.ferr_fat_fbd || *interpose) FERR_FAT_FBD_WR(rp->nb.fat_fbd_regs.ferr_fat_fbd); if (rp->nb.fat_fbd_regs.nerr_fat_fbd) NERR_FAT_FBD_WR(rp->nb.fat_fbd_regs.nerr_fat_fbd); /* * if interpose write read-only registers to clear from pcii * cache */ if (*interpose) { NRECMEMA_WR(branch); NRECMEMB_WR(branch); NRECFGLOG_WR(branch); NRECFBDA_WR(branch); NRECFBDB_WR(branch); NRECFBDC_WR(branch); NRECFBDD_WR(branch); NRECFBDE_WR(branch); NRECFBDF_WR(branch); } } } static void log_nf_fbd_err(nb_regs_t *rp, int willpanic, int *interpose) { int channel, branch; int t = 0; rp->flag = NB_REG_LOG_NF_FBD; rp->nb.nf_fbd_regs.ferr_nf_fbd = FERR_NF_FBD_RD(interpose); channel = (rp->nb.nf_fbd_regs.ferr_nf_fbd >> 28) & 3; branch = channel >> 1; rp->nb.nf_fbd_regs.nerr_nf_fbd = NERR_NF_FBD_RD(&t); *interpose |= t; rp->nb.nf_fbd_regs.redmemb = REDMEMB_RD(); rp->nb.nf_fbd_regs.recmema = RECMEMA_RD(branch); rp->nb.nf_fbd_regs.recmemb = RECMEMB_RD(branch); rp->nb.nf_fbd_regs.recfglog = RECFGLOG_RD(branch); rp->nb.nf_fbd_regs.recfbda = RECFBDA_RD(branch); rp->nb.nf_fbd_regs.recfbdb = RECFBDB_RD(branch); rp->nb.nf_fbd_regs.recfbdc = RECFBDC_RD(branch); rp->nb.nf_fbd_regs.recfbdd = RECFBDD_RD(branch); rp->nb.nf_fbd_regs.recfbde = RECFBDE_RD(branch); rp->nb.nf_fbd_regs.recfbdf = RECFBDF_RD(branch); rp->nb.nf_fbd_regs.spcps = SPCPS_RD(branch); rp->nb.nf_fbd_regs.spcpc = SPCPC_RD(branch); if (nb_chipset == INTEL_NB_7300 || nb_chipset == INTEL_NB_5400) { rp->nb.nf_fbd_regs.cerrcnta = CERRCNTA_RD(branch, channel); rp->nb.nf_fbd_regs.cerrcntb = CERRCNTB_RD(branch, channel); rp->nb.nf_fbd_regs.cerrcntc = CERRCNTC_RD(branch, channel); rp->nb.nf_fbd_regs.cerrcntd = CERRCNTD_RD(branch, channel); } else { rp->nb.nf_fbd_regs.cerrcnta = CERRCNT_RD(branch); rp->nb.nf_fbd_regs.cerrcntb = 0; rp->nb.nf_fbd_regs.cerrcntc = 0; rp->nb.nf_fbd_regs.cerrcntd = 0; } rp->nb.nf_fbd_regs.cerrcnta_last = cerrcnta[branch][channel & 1]; rp->nb.nf_fbd_regs.cerrcntb_last = cerrcntb[branch][channel & 1]; rp->nb.nf_fbd_regs.cerrcntc_last = cerrcntc[branch][channel & 1]; rp->nb.nf_fbd_regs.cerrcntd_last = cerrcntd[branch][channel & 1]; cerrcnta[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcnta; cerrcntb[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntb; cerrcntc[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntc; cerrcntd[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntd; rp->nb.nf_fbd_regs.badrama = BADRAMA_RD(branch); rp->nb.nf_fbd_regs.badramb = BADRAMB_RD(branch); rp->nb.nf_fbd_regs.badcnt = BADCNT_RD(branch); if (!willpanic) { if (rp->nb.nf_fbd_regs.ferr_nf_fbd || *interpose) FERR_NF_FBD_WR(rp->nb.nf_fbd_regs.ferr_nf_fbd); if (rp->nb.nf_fbd_regs.nerr_nf_fbd) NERR_NF_FBD_WR(rp->nb.nf_fbd_regs.nerr_nf_fbd); /* * if interpose write read-only registers to clear from pcii * cache */ if (*interpose) { RECMEMA_WR(branch); RECMEMB_WR(branch); RECFGLOG_WR(branch); RECFBDA_WR(branch); RECFBDB_WR(branch); RECFBDC_WR(branch); RECFBDD_WR(branch); RECFBDE_WR(branch); RECFBDF_WR(branch); SPCPS_WR(branch); } } } static int log_nf_mem_err(nb_regs_t *rp, int willpanic, int *interpose) { int channel, branch; int t = 0; int rt = 0; rp->flag = NB_REG_LOG_NF_MEM; /* Memmory err registers */ rp->nb.nf_mem_regs.ferr_nf_mem = FERR_NF_MEM_RD(interpose); channel = (rp->nb.nf_mem_regs.ferr_nf_mem >> 28) & 0x1; branch = channel; rp->nb.nf_mem_regs.nerr_nf_mem = NERR_NF_MEM_RD(&t); *interpose |= t; rp->nb.nf_mem_regs.redmema = MEM_REDMEMA_RD(branch); rp->nb.nf_mem_regs.redmemb = MEM_REDMEMB_RD(branch); rp->nb.nf_mem_regs.recmema = MEM_RECMEMA_RD(branch); rp->nb.nf_mem_regs.recmemb = MEM_RECMEMB_RD(branch); rp->nb.nf_mem_regs.nrecmema = MEM_NRECMEMA_RD(branch); rp->nb.nf_mem_regs.nrecmemb = MEM_NRECMEMB_RD(branch); /* spare rank */ rp->nb.nf_mem_regs.spcps = SPCPS_RD(branch); rp->nb.nf_mem_regs.spcpc = SPCPC_RD(branch); /* RAS registers */ rp->nb.nf_mem_regs.cerrcnt = MEM_CERRCNT_RD(branch); rp->nb.nf_mem_regs.cerrcnt_ext = (uint32_t)MEM_CERRCNT_EXT_RD(branch); rp->nb.nf_mem_regs.cerrcnt_last = cerrcnta[branch][channel & 1]; rp->nb.nf_mem_regs.cerrcnt_ext_last = cerrcntb[branch][channel & 1]; cerrcnta[branch][channel & 1] = rp->nb.nf_mem_regs.cerrcnt; cerrcntb[branch][channel & 1] = rp->nb.nf_mem_regs.cerrcnt_ext; rp->nb.nf_mem_regs.badram = BADRAMA_RD(branch); rp->nb.nf_mem_regs.badcnt = BADCNT_RD(branch); rp->nb.nf_mem_regs.validlog = VALIDLOG_RD(branch); if (!willpanic) { if (rp->nb.nf_mem_regs.ferr_nf_mem || *interpose) FERR_NF_MEM_WR(rp->nb.nf_mem_regs.ferr_nf_mem); if (rp->nb.nf_mem_regs.nerr_nf_mem) NERR_NF_MEM_WR(rp->nb.nf_mem_regs.nerr_nf_mem); /* * if interpose, write read-only registers to clear from pci * cache */ if (*interpose) { MEM_NRECMEMA_WR(branch); MEM_NRECMEMB_WR(branch); MEM_REDMEMA_WR(branch); MEM_REDMEMB_WR(branch); MEM_RECMEMA_WR(branch); MEM_RECMEMB_WR(branch); SPCPS_WR(branch); } } if (nb_mode == NB_MEMORY_SINGLE_CHANNEL && channel != 0) { /* * In the single channel mode, all dimms are on the channel 0. * Invalidate this error if the channel number is invalid. */ rt = 1; } return (rt); } static void log_ferr(uint64_t ferr, uint32_t *nerrp, nb_logout_t *log, int willpanic) { nb_regs_t *rp = &log->nb_regs; uint32_t nerr = *nerrp; int interpose = 0; int spurious = 0; log->acl_timestamp = gethrtime_waitfree(); if ((ferr & (GE_PCIEX_FATAL | GE_PCIEX_NF)) != 0) { *nerrp = nerr & ~(GE_PCIEX_FATAL | GE_PCIEX_NF); if (log_pex_err(ferr, rp, willpanic, &interpose) == 0) return; } else if ((ferr & GE_FBD_FATAL) != 0) { log_fat_fbd_err(rp, willpanic, &interpose); *nerrp = nerr & ~GE_NERR_FBD_FATAL; } else if ((ferr & GE_FBD_NF) != 0) { log_nf_fbd_err(rp, willpanic, &interpose); *nerrp = nerr & ~GE_NERR_FBD_NF; } else if ((ferr & GE_MEM_NF) != 0) { spurious = log_nf_mem_err(rp, willpanic, &interpose); *nerrp = nerr & ~GE_NERR_MEM_NF; } else if ((ferr & (GE_FERR_FSB_FATAL | GE_FERR_FSB_NF)) != 0) { log_fsb_err(ferr, rp, willpanic, &interpose); *nerrp = nerr & ~(GE_NERR_FSB_FATAL | GE_NERR_FSB_NF); } else if ((ferr & (GE_DMA_FATAL | GE_DMA_NF)) != 0) { log_dma_err(rp, &interpose); *nerrp = nerr & ~(GE_DMA_FATAL | GE_DMA_NF); } else if ((ferr & (GE_INT_FATAL | GE_INT_NF)) != 0) { spurious = log_int_err(rp, willpanic, &interpose); *nerrp = nerr & ~(GE_INT_FATAL | GE_INT_NF); } else if (nb_chipset == INTEL_NB_5400 && (ferr & (GE_FERR_THERMAL_FATAL | GE_FERR_THERMAL_NF)) != 0) { log_thermal_err(rp, willpanic, &interpose); *nerrp = nerr & ~(GE_FERR_THERMAL_FATAL | GE_FERR_THERMAL_NF); } if (interpose) log->type = "inject"; else log->type = "error"; if (!spurious) { errorq_dispatch(nb_queue, log, sizeof (nb_logout_t), willpanic ? ERRORQ_SYNC : ERRORQ_ASYNC); } } static void log_nerr(uint32_t *errp, nb_logout_t *log, int willpanic) { uint32_t err; nb_regs_t *rp = &log->nb_regs; int interpose = 0; int spurious = 0; err = *errp; log->acl_timestamp = gethrtime_waitfree(); if ((err & (GE_PCIEX_FATAL | GE_PCIEX_NF)) != 0) { *errp = err & ~(GE_PCIEX_FATAL | GE_PCIEX_NF); if (log_pex_err(err, rp, willpanic, &interpose) == 0) return; } else if ((err & GE_NERR_FBD_FATAL) != 0) { log_fat_fbd_err(rp, willpanic, &interpose); *errp = err & ~GE_NERR_FBD_FATAL; } else if ((err & GE_NERR_FBD_NF) != 0) { log_nf_fbd_err(rp, willpanic, &interpose); *errp = err & ~GE_NERR_FBD_NF; } else if ((err & GE_NERR_MEM_NF) != 0) { spurious = log_nf_mem_err(rp, willpanic, &interpose); *errp = err & ~GE_NERR_MEM_NF; } else if ((err & (GE_NERR_FSB_FATAL | GE_NERR_FSB_NF)) != 0) { log_fsb_err(GE_NERR_TO_FERR_FSB(err), rp, willpanic, &interpose); *errp = err & ~(GE_NERR_FSB_FATAL | GE_NERR_FSB_NF); } else if ((err & (GE_DMA_FATAL | GE_DMA_NF)) != 0) { log_dma_err(rp, &interpose); *errp = err & ~(GE_DMA_FATAL | GE_DMA_NF); } else if ((err & (GE_INT_FATAL | GE_INT_NF)) != 0) { spurious = log_int_err(rp, willpanic, &interpose); *errp = err & ~(GE_INT_FATAL | GE_INT_NF); } if (interpose) log->type = "inject"; else log->type = "error"; if (!spurious) { errorq_dispatch(nb_queue, log, sizeof (nb_logout_t), willpanic ? ERRORQ_SYNC : ERRORQ_ASYNC); } } /*ARGSUSED*/ void nb_error_trap(cmi_hdl_t hdl, boolean_t ismc, boolean_t willpanic) { uint64_t ferr; uint32_t nerr, err; int nmc = 0; int i; if (mutex_tryenter(&nb_mutex) == 0) return; nerr = NERR_GLOBAL_RD(); err = nerr; for (i = 0; i < NB_MAX_ERRORS; i++) { ferr = FERR_GLOBAL_RD(); nb_log.nb_regs.chipset = nb_chipset; nb_log.nb_regs.ferr = ferr; nb_log.nb_regs.nerr = nerr; if (ferr) { log_ferr(ferr, &err, &nb_log, willpanic); FERR_GLOBAL_WR(ferr); nmc++; } else if (err) { log_nerr(&err, &nb_log, willpanic); nmc++; } } if (nerr) { NERR_GLOBAL_WR(nerr); } if (nmc == 0 && nb_mask_mc_set) nb_mask_mc_reset(); mutex_exit(&nb_mutex); } static void nb_fsb_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload, nb_scatchpad_t *data) { int intel_error_list; char buf[32]; fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FSB, DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.fsb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_FSB, DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.ferr_fat_fsb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_FSB, DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.nerr_fat_fsb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_FSB, DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.ferr_nf_fsb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_FSB, DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.nerr_nf_fsb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFSB, DATA_TYPE_UINT32, nb_regs->nb.fsb_regs.nrecfsb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFSB_ADDR, DATA_TYPE_UINT64, nb_regs->nb.fsb_regs.nrecfsb_addr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFSB, DATA_TYPE_UINT32, nb_regs->nb.fsb_regs.recfsb, NULL); intel_error_list = data->intel_error_list; if (intel_error_list >= 0) (void) snprintf(buf, sizeof (buf), "F%d", intel_error_list); else (void) snprintf(buf, sizeof (buf), "Multiple or unknown error"); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO, DATA_TYPE_STRING, buf, NULL); } static void nb_pex_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload, nb_scatchpad_t *data) { int intel_error_list; char buf[32]; fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX, DATA_TYPE_UINT8, nb_regs->nb.pex_regs.pex, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_FAT_FERR, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_fat_ferr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_FAT_NERR, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_fat_nerr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_NF_CORR_FERR, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_nf_corr_ferr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_NF_CORR_NERR, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_nf_corr_nerr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UNCERRSEV, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.uncerrsev, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RPERRSTS, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.rperrsts, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RPERRSID, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.rperrsid, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UNCERRSTS, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.uncerrsts, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_AERRCAPCTRL, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.aerrcapctrl, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CORERRSTS, DATA_TYPE_UINT32, nb_regs->nb.pex_regs.corerrsts, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEXDEVSTS, DATA_TYPE_UINT16, nb_regs->nb.pex_regs.pexdevsts, NULL); intel_error_list = data->intel_error_list; if (intel_error_list >= 0) (void) snprintf(buf, sizeof (buf), "IO%d", intel_error_list); else (void) snprintf(buf, sizeof (buf), "Multiple or unknown error"); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO, DATA_TYPE_STRING, buf, NULL); } static void nb_int_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload, nb_scatchpad_t *data) { int intel_error_list; char buf[32]; fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_INT, DATA_TYPE_UINT16, nb_regs->nb.int_regs.ferr_fat_int, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_INT, DATA_TYPE_UINT16, nb_regs->nb.int_regs.ferr_nf_int, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_INT, DATA_TYPE_UINT16, nb_regs->nb.int_regs.nerr_fat_int, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_INT, DATA_TYPE_UINT16, nb_regs->nb.int_regs.nerr_nf_int, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECINT, DATA_TYPE_UINT32, nb_regs->nb.int_regs.nrecint, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECINT, DATA_TYPE_UINT32, nb_regs->nb.int_regs.recint, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECSF, DATA_TYPE_UINT64, nb_regs->nb.int_regs.nrecsf, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECSF, DATA_TYPE_UINT64, nb_regs->nb.int_regs.recsf, NULL); intel_error_list = data->intel_error_list; if (intel_error_list >= 0) (void) snprintf(buf, sizeof (buf), "B%d", intel_error_list); else (void) snprintf(buf, sizeof (buf), "Multiple or unknown error"); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO, DATA_TYPE_STRING, buf, NULL); } static void nb_fat_fbd_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload, nb_scatchpad_t *data) { nb_mem_scatchpad_t *sp; char buf[32]; sp = &((nb_scatchpad_t *)data)->ms; if (sp->ras != -1) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK, DATA_TYPE_INT32, sp->bank, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS, DATA_TYPE_INT32, sp->cas, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS, DATA_TYPE_INT32, sp->ras, NULL); if (sp->offset != -1LL) { fm_payload_set(payload, FM_FMRI_MEM_OFFSET, DATA_TYPE_UINT64, sp->offset, NULL); } if (sp->pa != -1LL) { fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR, DATA_TYPE_UINT64, sp->pa, NULL); } } fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_FBD, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.ferr_fat_fbd, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_FBD, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nerr_fat_fbd, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMA, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecmema, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMB, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecmemb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFGLOG, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfglog, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDA, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbda, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDB, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDC, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdc, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDD, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdd, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDE, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbde, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDF, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdf, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS, DATA_TYPE_UINT8, nb_regs->nb.fat_fbd_regs.spcps, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.spcpc, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UERRCNT, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.uerrcnt, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UERRCNT_LAST, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.uerrcnt_last, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMA, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.badrama, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMB, DATA_TYPE_UINT16, nb_regs->nb.fat_fbd_regs.badramb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT, DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.badcnt, NULL); if (sp->intel_error_list >= 0) (void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list); else (void) snprintf(buf, sizeof (buf), "Multiple or unknown error"); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO, DATA_TYPE_STRING, buf, NULL); } static void nb_nf_fbd_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload, nb_scatchpad_t *data) { nb_mem_scatchpad_t *sp; char buf[32]; sp = &((nb_scatchpad_t *)data)->ms; if (sp->dimm == -1 && sp->rank != -1) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RANK, DATA_TYPE_INT32, sp->rank, NULL); } if (sp->ras != -1) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK, DATA_TYPE_INT32, sp->bank, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS, DATA_TYPE_INT32, sp->cas, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS, DATA_TYPE_INT32, sp->ras, NULL); if (sp->offset != -1LL) { fm_payload_set(payload, FM_FMRI_MEM_OFFSET, DATA_TYPE_UINT64, sp->offset, NULL); } if (sp->pa != -1LL) { fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR, DATA_TYPE_UINT64, sp->pa, NULL); } } fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_FBD, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.ferr_nf_fbd, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_FBD, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.nerr_nf_fbd, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMA, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recmema, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMB, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recmemb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFGLOG, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfglog, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDA, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbda, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDB, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDC, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdc, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDD, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdd, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDE, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbde, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDF, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdf, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS, DATA_TYPE_UINT8, nb_regs->nb.nf_fbd_regs.spcps, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.spcpc, NULL); if (nb_chipset == INTEL_NB_7300 || nb_chipset == INTEL_NB_5400) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTA, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTB, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntb, NULL); if (nb_chipset == INTEL_NB_7300) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTC, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntc, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTD, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntd, NULL); } fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTA_LAST, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta_last, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTB_LAST, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntb_last, NULL); if (nb_chipset == INTEL_NB_7300) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTC_LAST, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntc_last, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTD_LAST, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntd_last, NULL); } } else { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_LAST, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta_last, NULL); } fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMA, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.badrama, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMB, DATA_TYPE_UINT16, nb_regs->nb.nf_fbd_regs.badramb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT, DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.badcnt, NULL); if (sp->intel_error_list >= 0) (void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list); else (void) snprintf(buf, sizeof (buf), "Multiple or unknown error"); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO, DATA_TYPE_STRING, buf, NULL); } static void nb_nf_mem_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload, nb_scatchpad_t *data) { nb_mem_scatchpad_t *sp; char buf[32]; sp = &((nb_scatchpad_t *)data)->ms; if (sp->dimm == -1 && sp->rank != -1) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RANK, DATA_TYPE_INT32, sp->rank, NULL); } if (sp->ras != -1) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK, DATA_TYPE_INT32, sp->bank, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS, DATA_TYPE_INT32, sp->cas, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS, DATA_TYPE_INT32, sp->ras, NULL); if (sp->offset != -1LL) { fm_payload_set(payload, FM_FMRI_MEM_OFFSET, DATA_TYPE_UINT64, sp->offset, NULL); } if (sp->pa != -1LL) { fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR, DATA_TYPE_UINT64, sp->pa, NULL); } } fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_MEM, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.ferr_nf_mem, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_MEM, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nerr_nf_mem, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMA, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.recmema, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMB, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.recmemb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_REDMEMA, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.redmema, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_REDMEMB, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.redmemb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMA, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nrecmema, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMB, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nrecmemb, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS, DATA_TYPE_UINT8, nb_regs->nb.nf_mem_regs.spcps, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.spcpc, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_LAST, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_last, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_EXT, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_ext, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_EXT_LAST, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_ext_last, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAM, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.badram, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.badcnt, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_VALIDLOG, DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.validlog, NULL); if (sp->intel_error_list >= 0) (void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list); else (void) snprintf(buf, sizeof (buf), "Multiple or unknown error"); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO, DATA_TYPE_STRING, buf, NULL); } static void nb_dma_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload) { fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PCISTS, DATA_TYPE_UINT16, nb_regs->nb.dma_regs.pcists, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEXDEVSTS, DATA_TYPE_UINT16, nb_regs->nb.dma_regs.pexdevsts, NULL); } static void nb_thr_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload, nb_scatchpad_t *data) { char buf[32]; fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_THR, DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ferr_fat_thr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_THR, DATA_TYPE_UINT8, nb_regs->nb.thr_regs.nerr_fat_thr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_THR, DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ferr_nf_thr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_THR, DATA_TYPE_UINT8, nb_regs->nb.thr_regs.nerr_nf_thr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CTSTS, DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ctsts, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_THRTSTS, DATA_TYPE_UINT16, nb_regs->nb.thr_regs.thrtsts, NULL); if (data->intel_error_list >= 0) { (void) snprintf(buf, sizeof (buf), "TH%d", data->intel_error_list); } else { (void) snprintf(buf, sizeof (buf), "Multiple or unknown error"); } fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO, DATA_TYPE_STRING, buf, NULL); } static void nb_ereport_add_logout(nvlist_t *payload, const nb_logout_t *acl, nb_scatchpad_t *data) { const nb_regs_t *nb_regs = &acl->nb_regs; fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_MC_TYPE, DATA_TYPE_STRING, acl->type, NULL); switch (nb_regs->flag) { case NB_REG_LOG_FSB: nb_fsb_err_payload(nb_regs, payload, data); break; case NB_REG_LOG_PEX: nb_pex_err_payload(nb_regs, payload, data); break; case NB_REG_LOG_INT: nb_int_err_payload(nb_regs, payload, data); break; case NB_REG_LOG_FAT_FBD: nb_fat_fbd_err_payload(nb_regs, payload, data); break; case NB_REG_LOG_NF_FBD: nb_nf_fbd_err_payload(nb_regs, payload, data); break; case NB_REG_LOG_DMA: nb_dma_err_payload(nb_regs, payload); break; case NB_REG_LOG_THR: nb_thr_err_payload(nb_regs, payload, data); break; case NB_REG_LOG_NF_MEM: nb_nf_mem_err_payload(nb_regs, payload, data); break; default: fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_GLOBAL, DATA_TYPE_UINT64, nb_regs->ferr, NULL); fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_GLOBAL, DATA_TYPE_UINT32, nb_regs->nerr, NULL); break; } } void nb_fsb_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector, nb_scatchpad_t *data) { int chip; if (nb_chipset == INTEL_NB_7300) chip = nb_regs->nb.fsb_regs.fsb * 2; else chip = nb_regs->nb.fsb_regs.fsb; fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2, "motherboard", 0, "chip", chip); if (nb_regs->nb.fsb_regs.ferr_fat_fsb == 0 && nb_regs->nb.fsb_regs.ferr_nf_fsb == 0) { data->intel_error_list = intel_fsb_err(nb_regs->nb.fsb_regs.fsb, nb_regs->nb.fsb_regs.nerr_fat_fsb, nb_regs->nb.fsb_regs.nerr_nf_fsb); } else { data->intel_error_list = intel_fsb_err(nb_regs->nb.fsb_regs.fsb, nb_regs->nb.fsb_regs.ferr_fat_fsb, nb_regs->nb.fsb_regs.ferr_nf_fsb); } (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "fsb"); } void nb_pex_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector, nb_scatchpad_t *data) { int hostbridge; if (nb_regs->nb.pex_regs.pex == 0) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1, "motherboard", 0); } else { hostbridge = nb_regs->nb.pex_regs.pex - 1; fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2, "motherboard", 0, "hostbridge", hostbridge); } if (nb_regs->nb.pex_regs.pex_fat_ferr == 0 && nb_regs->nb.pex_regs.pex_nf_corr_ferr == 0) { if (nb_chipset == INTEL_NB_5400) { data->intel_error_list = intel_pex_5400_err( nb_regs->nb.pex_regs.pex_fat_nerr, nb_regs->nb.pex_regs.pex_nf_corr_nerr); } else { data->intel_error_list = intel_pex_err(nb_regs->nb.pex_regs.pex_fat_nerr, nb_regs->nb.pex_regs.pex_nf_corr_nerr); } } else { if (nb_chipset == INTEL_NB_5400) { data->intel_error_list = intel_pex_5400_err( nb_regs->nb.pex_regs.pex_fat_ferr, nb_regs->nb.pex_regs.pex_nf_corr_ferr); } else { data->intel_error_list = intel_pex_err(nb_regs->nb.pex_regs.pex_fat_ferr, nb_regs->nb.pex_regs.pex_nf_corr_ferr); } } if (nb_regs->nb.pex_regs.pex == 0) { (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "esi"); } else { (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "pex"); } } void nb_int_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector, void *data) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1, "motherboard", 0); if (nb_regs->nb.int_regs.ferr_fat_int == 0 && nb_regs->nb.int_regs.ferr_nf_int == 0) { ((nb_scatchpad_t *)data)->intel_error_list = intel_int_err(nb_regs->nb.int_regs.nerr_fat_int, nb_regs->nb.int_regs.nerr_nf_int); } else { ((nb_scatchpad_t *)data)->intel_error_list = intel_int_err(nb_regs->nb.int_regs.ferr_fat_int, nb_regs->nb.int_regs.ferr_nf_int); } (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "ie"); } void nb_fat_fbd_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector, void *data) { char *intr; nb_mem_scatchpad_t *sp; intr = fat_memory_error(nb_regs, data); sp = &((nb_scatchpad_t *)data)->ms; if (sp->dimm != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5, "motherboard", 0, "memory-controller", sp->branch, "dram-channel", sp->channel, "dimm", sp->dimm, "rank", sp->rank); } else if (sp->channel != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3, "motherboard", 0, "memory-controller", sp->branch, "dram-channel", sp->channel); } else if (sp->branch != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2, "motherboard", 0, "memory-controller", sp->branch); } else { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1, "motherboard", 0); } (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr); } void nb_nf_fbd_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector, void *data) { char *intr; nb_mem_scatchpad_t *sp; intr = nf_memory_error(nb_regs, data); sp = &((nb_scatchpad_t *)data)->ms; if (sp->dimm != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5, "motherboard", 0, "memory-controller", sp->branch, "dram-channel", sp->channel, "dimm", sp->dimm, "rank", sp->rank); } else if (sp->channel != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3, "motherboard", 0, "memory-controller", sp->branch, "dram-channel", sp->channel); } else if (sp->branch != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2, "motherboard", 0, "memory-controller", sp->branch); } else { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1, "motherboard", 0); } (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr); } void nb_dma_report(char *class, nvlist_t *detector) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1, "motherboard", 0); (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "dma"); } void nb_thr_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector, void *data) { ((nb_scatchpad_t *)data)->intel_error_list = intel_thr_err(nb_regs->nb.thr_regs.ferr_fat_thr, nb_regs->nb.thr_regs.ferr_nf_thr); fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1, "motherboard", 0); (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "otf"); } void nb_nf_mem_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector, void *data) { char *intr; nb_mem_scatchpad_t *sp; intr = nf_mem_error(nb_regs, data); sp = &((nb_scatchpad_t *)data)->ms; if (sp->dimm != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5, "motherboard", 0, "memory-controller", sp->branch, "dram-channel", sp->channel, "dimm", sp->dimm, "rank", sp->rank); } else if (sp->channel != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3, "motherboard", 0, "memory-controller", sp->branch, "dram-channel", sp->channel); } else if (sp->branch != -1) { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2, "motherboard", 0, "memory-controller", sp->branch); } else { fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1, "motherboard", 0); } (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr); } nvlist_t * nb_report(const nb_regs_t *nb_regs, char *class, nv_alloc_t *nva, void *scratch) { nvlist_t *detector = fm_nvlist_create(nva); switch (nb_regs->flag) { case NB_REG_LOG_FSB: nb_fsb_report(nb_regs, class, detector, scratch); break; case NB_REG_LOG_PEX: nb_pex_report(nb_regs, class, detector, scratch); break; case NB_REG_LOG_INT: nb_int_report(nb_regs, class, detector, scratch); break; case NB_REG_LOG_FAT_FBD: nb_fat_fbd_report(nb_regs, class, detector, scratch); break; case NB_REG_LOG_NF_FBD: nb_nf_fbd_report(nb_regs, class, detector, scratch); break; case NB_REG_LOG_DMA: nb_dma_report(class, detector); break; case NB_REG_LOG_THR: nb_thr_report(nb_regs, class, detector, scratch); break; case NB_REG_LOG_NF_MEM: nb_nf_mem_report(nb_regs, class, detector, scratch); break; default: fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1, "motherboard", 0); (void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s", FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "unknown"); } return (detector); } /*ARGSUSED*/ void nb_drain(void *ignored, const void *data, const errorq_elem_t *eqe) { nb_logout_t *acl = (nb_logout_t *)data; errorq_elem_t *eqep, *scr_eqep; nvlist_t *ereport, *detector; nv_alloc_t *nva = NULL; char buf[FM_MAX_CLASS]; nb_scatchpad_t nb_scatchpad; eqep = NULL; scr_eqep = NULL; if (panicstr) { if ((eqep = errorq_reserve(ereport_errorq)) == NULL) return; ereport = errorq_elem_nvl(ereport_errorq, eqep); /* * Now try to allocate another element for scratch space and * use that for further scratch space (eg for constructing * nvlists to add the main ereport). If we can't reserve * a scratch element just fallback to working within the * element we already have, and hope for the best. All this * is necessary because the fixed buffer nv allocator does * not reclaim freed space and nvlist construction is * expensive. */ if ((scr_eqep = errorq_reserve(ereport_errorq)) != NULL) nva = errorq_elem_nva(ereport_errorq, scr_eqep); else nva = errorq_elem_nva(ereport_errorq, eqep); } else { ereport = fm_nvlist_create(NULL); } detector = nb_report(&acl->nb_regs, buf, nva, &nb_scatchpad); if (detector == NULL) return; fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, fm_ena_generate(acl->acl_timestamp, FM_ENA_FMT1), detector, NULL); /* * We're done with 'detector' so reclaim the scratch space. */ if (panicstr) { fm_nvlist_destroy(detector, FM_NVA_RETAIN); nv_alloc_reset(nva); } else { fm_nvlist_destroy(detector, FM_NVA_FREE); } /* * Encode the error-specific data that was saved in the logout area. */ nb_ereport_add_logout(ereport, acl, &nb_scatchpad); if (panicstr) { errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); if (scr_eqep) errorq_cancel(ereport_errorq, scr_eqep); } else { (void) fm_ereport_post(ereport, EVCH_TRYHARD); fm_nvlist_destroy(ereport, FM_NVA_FREE); } }