120c794b3Sgavinm /*
220c794b3Sgavinm  * CDDL HEADER START
320c794b3Sgavinm  *
420c794b3Sgavinm  * The contents of this file are subject to the terms of the
520c794b3Sgavinm  * Common Development and Distribution License (the "License").
620c794b3Sgavinm  * You may not use this file except in compliance with the License.
720c794b3Sgavinm  *
820c794b3Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
920c794b3Sgavinm  * or http://www.opensolaris.org/os/licensing.
1020c794b3Sgavinm  * See the License for the specific language governing permissions
1120c794b3Sgavinm  * and limitations under the License.
1220c794b3Sgavinm  *
1320c794b3Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
1420c794b3Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1520c794b3Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
1620c794b3Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
1720c794b3Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
1820c794b3Sgavinm  *
1920c794b3Sgavinm  * CDDL HEADER END
2020c794b3Sgavinm  */
2120c794b3Sgavinm 
2220c794b3Sgavinm /*
23c84b7bbeSAdrian Frost  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2420c794b3Sgavinm  */
2520c794b3Sgavinm 
2620c794b3Sgavinm #include <sys/types.h>
2720c794b3Sgavinm #include <sys/cmn_err.h>
2820c794b3Sgavinm #include <sys/errno.h>
2920c794b3Sgavinm #include <sys/log.h>
3020c794b3Sgavinm #include <sys/systm.h>
3120c794b3Sgavinm #include <sys/modctl.h>
3220c794b3Sgavinm #include <sys/errorq.h>
3320c794b3Sgavinm #include <sys/controlregs.h>
3420c794b3Sgavinm #include <sys/fm/util.h>
3520c794b3Sgavinm #include <sys/fm/protocol.h>
3620c794b3Sgavinm #include <sys/sysevent.h>
3720c794b3Sgavinm #include <sys/pghw.h>
3820c794b3Sgavinm #include <sys/cyclic.h>
3920c794b3Sgavinm #include <sys/pci_cfgspace.h>
4020c794b3Sgavinm #include <sys/mc_intel.h>
4120c794b3Sgavinm #include <sys/smbios.h>
4220c794b3Sgavinm #include "nb5000.h"
4320c794b3Sgavinm #include "nb_log.h"
4420c794b3Sgavinm #include "dimm_phys.h"
4520c794b3Sgavinm 
4685738508SVuong Nguyen int nb_check_validlog = 1;
4785738508SVuong Nguyen 
4820c794b3Sgavinm static uint32_t uerrcnt[2];
495f28a827Saf static uint32_t cerrcnta[2][2];
505f28a827Saf static uint32_t cerrcntb[2][2];
515f28a827Saf static uint32_t cerrcntc[2][2];
525f28a827Saf static uint32_t cerrcntd[2][2];
5320c794b3Sgavinm static nb_logout_t nb_log;
5420c794b3Sgavinm 
5520c794b3Sgavinm struct mch_error_code {
5620c794b3Sgavinm 	int intel_error_list;	/* error number in Chipset Error List */
5720c794b3Sgavinm 	uint32_t emask;		/* mask for machine check */
5820c794b3Sgavinm 	uint32_t error_bit;	/* error bit in fault register */
5920c794b3Sgavinm };
6020c794b3Sgavinm 
6120c794b3Sgavinm static struct mch_error_code fat_fbd_error_code[] = {
6220c794b3Sgavinm 	{ 23, EMASK_FBD_M23, ERR_FAT_FBD_M23 },
6320c794b3Sgavinm 	{ 3, EMASK_FBD_M3, ERR_FAT_FBD_M3 },
6420c794b3Sgavinm 	{ 2, EMASK_FBD_M2, ERR_FAT_FBD_M2 },
6520c794b3Sgavinm 	{ 1, EMASK_FBD_M1, ERR_FAT_FBD_M1 }
6620c794b3Sgavinm };
6720c794b3Sgavinm 
6820c794b3Sgavinm static int
intel_fat_fbd_err(uint32_t fat_fbd)6920c794b3Sgavinm intel_fat_fbd_err(uint32_t fat_fbd)
7020c794b3Sgavinm {
7120c794b3Sgavinm 	int rt = -1;
7220c794b3Sgavinm 	int nerr = 0;
7320c794b3Sgavinm 	uint32_t emask_fbd = 0;
7420c794b3Sgavinm 	int i;
7520c794b3Sgavinm 	int sz;
7620c794b3Sgavinm 
7720c794b3Sgavinm 	sz = sizeof (fat_fbd_error_code) / sizeof (struct mch_error_code);
7820c794b3Sgavinm 
7920c794b3Sgavinm 	for (i = 0; i < sz; i++) {
8020c794b3Sgavinm 		if (fat_fbd & fat_fbd_error_code[i].error_bit) {
8120c794b3Sgavinm 			rt = fat_fbd_error_code[i].intel_error_list;
8220c794b3Sgavinm 			emask_fbd |= fat_fbd_error_code[i].emask;
8320c794b3Sgavinm 			nerr++;
8420c794b3Sgavinm 		}
8520c794b3Sgavinm 	}
8620c794b3Sgavinm 
8720c794b3Sgavinm 	if (emask_fbd)
8820c794b3Sgavinm 		nb_fbd_mask_mc(emask_fbd);
8920c794b3Sgavinm 	if (nerr > 1)
9020c794b3Sgavinm 		rt = -1;
9120c794b3Sgavinm 	return (rt);
9220c794b3Sgavinm }
9320c794b3Sgavinm 
9420c794b3Sgavinm static char *
fat_memory_error(const nb_regs_t * rp,void * data)9520c794b3Sgavinm fat_memory_error(const nb_regs_t *rp, void *data)
9620c794b3Sgavinm {
9720c794b3Sgavinm 	int channel;
9820c794b3Sgavinm 	uint32_t ferr_fat_fbd, nrecmemb;
995f28a827Saf 	uint32_t nrecmema;
10020c794b3Sgavinm 	char *intr = "nb.unknown";
10120c794b3Sgavinm 	nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms;
10220c794b3Sgavinm 
10320c794b3Sgavinm 	ferr_fat_fbd = rp->nb.fat_fbd_regs.ferr_fat_fbd;
1046cb1ca52Saf 	if ((ferr_fat_fbd & ERR_FAT_FBD_MASK) == 0) {
1056cb1ca52Saf 		sp->intel_error_list =
1066cb1ca52Saf 		    intel_fat_fbd_err(rp->nb.fat_fbd_regs.nerr_fat_fbd);
1076cb1ca52Saf 		sp->branch = -1;
1086cb1ca52Saf 		sp->channel = -1;
1096cb1ca52Saf 		sp->rank = -1;
1106cb1ca52Saf 		sp->dimm = -1;
1116cb1ca52Saf 		sp->bank = -1;
1126cb1ca52Saf 		sp->cas = -1;
1136cb1ca52Saf 		sp->ras = -1;
1146cb1ca52Saf 		sp->pa = -1LL;
1156cb1ca52Saf 		sp->offset = -1;
1166cb1ca52Saf 		return (intr);
1176cb1ca52Saf 	}
11820c794b3Sgavinm 	sp->intel_error_list = intel_fat_fbd_err(ferr_fat_fbd);
11920c794b3Sgavinm 	channel = (ferr_fat_fbd >> 28) & 3;
12020c794b3Sgavinm 	sp->branch = channel >> 1;
12120c794b3Sgavinm 	sp->channel = channel;
12220c794b3Sgavinm 	if ((ferr_fat_fbd & (ERR_FAT_FBD_M2|ERR_FAT_FBD_M1)) != 0) {
12320c794b3Sgavinm 		if ((ferr_fat_fbd & ERR_FAT_FBD_M1) != 0)
12420c794b3Sgavinm 			intr = "nb.fbd.alert";	/* Alert on FB-DIMM M1 */
12520c794b3Sgavinm 		else
12620c794b3Sgavinm 			intr = "nb.fbd.crc";	/* CRC error FB_DIMM M2 */
12720c794b3Sgavinm 		nrecmema = rp->nb.fat_fbd_regs.nrecmema;
12820c794b3Sgavinm 		nrecmemb = rp->nb.fat_fbd_regs.nrecmemb;
12920c794b3Sgavinm 		sp->rank = (nrecmema >> 8) & RANK_MASK;
13020c794b3Sgavinm 		sp->dimm = sp->rank >> 1;
13120c794b3Sgavinm 		sp->bank = (nrecmema >> 12) & BANK_MASK;
13220c794b3Sgavinm 		sp->cas = (nrecmemb >> 16) & CAS_MASK;
13320c794b3Sgavinm 		sp->ras = nrecmemb & RAS_MASK;
134f899e573SVuong Nguyen 		/*
135f899e573SVuong Nguyen 		 * If driver was built with closed tree present then we will
136f899e573SVuong Nguyen 		 * have Intel proprietary code for finding physaddr
137f899e573SVuong Nguyen 		 */
138f899e573SVuong Nguyen 		if (&dimm_getphys) {
139f899e573SVuong Nguyen 			sp->pa = dimm_getphys((uint16_t)sp->branch,
140f899e573SVuong Nguyen 			    (uint16_t)sp->rank, (uint64_t)sp->bank,
141f899e573SVuong Nguyen 			    (uint64_t)sp->ras, (uint64_t)sp->cas);
142f899e573SVuong Nguyen 			if (sp->pa >= MAXPHYS_ADDR)
143f899e573SVuong Nguyen 				sp->pa = -1ULL;
144f899e573SVuong Nguyen 		} else {
145f899e573SVuong Nguyen 			sp->pa = -1ULL;
146f899e573SVuong Nguyen 		}
147f899e573SVuong Nguyen 		/*
148f899e573SVuong Nguyen 		 * If there is an offset decoder use it otherwise encode
149f899e573SVuong Nguyen 		 * rank/bank/ras/cas
150f899e573SVuong Nguyen 		 */
151f899e573SVuong Nguyen 		if (&dimm_getoffset) {
152f899e573SVuong Nguyen 			sp->offset = dimm_getoffset(sp->branch, sp->rank,
153f899e573SVuong Nguyen 			    sp->bank, sp->ras, sp->cas);
154f899e573SVuong Nguyen 		} else {
155f899e573SVuong Nguyen 			sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras,
156f899e573SVuong Nguyen 			    sp->cas);
157f899e573SVuong Nguyen 		}
15820c794b3Sgavinm 	} else {
15920c794b3Sgavinm 		if ((ferr_fat_fbd & ERR_FAT_FBD_M3) != 0)
16020c794b3Sgavinm 			intr = "nb.fbd.otf";	/* thermal temp > Tmid M3 */
16120c794b3Sgavinm 		else if ((ferr_fat_fbd & ERR_FAT_FBD_M23) != 0) {
16220c794b3Sgavinm 			intr = "nb.fbd.reset_timeout";
16320c794b3Sgavinm 			sp->channel = -1;
16420c794b3Sgavinm 		}
16520c794b3Sgavinm 		sp->rank = -1;
16620c794b3Sgavinm 		sp->dimm = -1;
16720c794b3Sgavinm 		sp->bank = -1;
16820c794b3Sgavinm 		sp->cas = -1;
16920c794b3Sgavinm 		sp->ras = -1;
17020c794b3Sgavinm 		sp->pa = -1LL;
17120c794b3Sgavinm 		sp->offset = -1;
17220c794b3Sgavinm 	}
17320c794b3Sgavinm 	return (intr);
17420c794b3Sgavinm }
17520c794b3Sgavinm 
17620c794b3Sgavinm 
17720c794b3Sgavinm static struct mch_error_code nf_fbd_error_code[] = {
1785f28a827Saf 	{ 29, EMASK_FBD_M29, ERR_NF_FBD_M29 },
17920c794b3Sgavinm 	{ 28, EMASK_FBD_M28, ERR_NF_FBD_M28 },
18020c794b3Sgavinm 	{ 27, EMASK_FBD_M27, ERR_NF_FBD_M27 },
18120c794b3Sgavinm 	{ 26, EMASK_FBD_M26, ERR_NF_FBD_M26 },
18220c794b3Sgavinm 	{ 25, EMASK_FBD_M25, ERR_NF_FBD_M25 },
1835f28a827Saf 	{ 24, EMASK_FBD_M24, ERR_NF_FBD_M24 },
18420c794b3Sgavinm 	{ 22, EMASK_FBD_M22, ERR_NF_FBD_M22 },
18520c794b3Sgavinm 	{ 21, EMASK_FBD_M21, ERR_NF_FBD_M21 },
18620c794b3Sgavinm 	{ 20, EMASK_FBD_M20, ERR_NF_FBD_M20 },
18720c794b3Sgavinm 	{ 19, EMASK_FBD_M19, ERR_NF_FBD_M19 },
18820c794b3Sgavinm 	{ 18, EMASK_FBD_M18, ERR_NF_FBD_M18 },
18920c794b3Sgavinm 	{ 17, EMASK_FBD_M17, ERR_NF_FBD_M17 },
1905f28a827Saf 	{ 16, EMASK_FBD_M16, ERR_NF_FBD_M16 },
19120c794b3Sgavinm 	{ 15, EMASK_FBD_M15, ERR_NF_FBD_M15 },
19220c794b3Sgavinm 	{ 14, EMASK_FBD_M14, ERR_NF_FBD_M14 },
19320c794b3Sgavinm 	{ 13, EMASK_FBD_M13, ERR_NF_FBD_M13 },
19420c794b3Sgavinm 	{ 12, EMASK_FBD_M12, ERR_NF_FBD_M12 },
19520c794b3Sgavinm 	{ 11, EMASK_FBD_M11, ERR_NF_FBD_M11 },
19620c794b3Sgavinm 	{ 10, EMASK_FBD_M10, ERR_NF_FBD_M10 },
19720c794b3Sgavinm 	{ 9, EMASK_FBD_M9, ERR_NF_FBD_M9 },
19820c794b3Sgavinm 	{ 8, EMASK_FBD_M8, ERR_NF_FBD_M8 },
19920c794b3Sgavinm 	{ 7, EMASK_FBD_M7, ERR_NF_FBD_M7 },
20020c794b3Sgavinm 	{ 6, EMASK_FBD_M6, ERR_NF_FBD_M6 },
20120c794b3Sgavinm 	{ 5, EMASK_FBD_M5, ERR_NF_FBD_M5 },
20220c794b3Sgavinm 	{ 4, EMASK_FBD_M4, ERR_NF_FBD_M4 }
20320c794b3Sgavinm };
20420c794b3Sgavinm 
20520c794b3Sgavinm static int
intel_nf_fbd_err(uint32_t nf_fbd)20620c794b3Sgavinm intel_nf_fbd_err(uint32_t nf_fbd)
20720c794b3Sgavinm {
20820c794b3Sgavinm 	int rt = -1;
20920c794b3Sgavinm 	int nerr = 0;
21020c794b3Sgavinm 	uint32_t emask_fbd = 0;
21120c794b3Sgavinm 	int i;
21220c794b3Sgavinm 	int sz;
21320c794b3Sgavinm 
21420c794b3Sgavinm 	sz = sizeof (nf_fbd_error_code) / sizeof (struct mch_error_code);
21520c794b3Sgavinm 
21620c794b3Sgavinm 	for (i = 0; i < sz; i++) {
21720c794b3Sgavinm 		if (nf_fbd & nf_fbd_error_code[i].error_bit) {
21820c794b3Sgavinm 			rt = nf_fbd_error_code[i].intel_error_list;
21920c794b3Sgavinm 			emask_fbd |= nf_fbd_error_code[i].emask;
22020c794b3Sgavinm 			nerr++;
22120c794b3Sgavinm 		}
22220c794b3Sgavinm 	}
22320c794b3Sgavinm 	if (emask_fbd)
22420c794b3Sgavinm 		nb_fbd_mask_mc(emask_fbd);
22520c794b3Sgavinm 	if (nerr > 1)
22620c794b3Sgavinm 		rt = -1;
22720c794b3Sgavinm 	return (rt);
22820c794b3Sgavinm }
22920c794b3Sgavinm 
23020c794b3Sgavinm static char *
nf_memory_error(const nb_regs_t * rp,void * data)23120c794b3Sgavinm nf_memory_error(const nb_regs_t *rp, void *data)
23220c794b3Sgavinm {
23320c794b3Sgavinm 	uint32_t ferr_nf_fbd, recmemb, redmemb;
2345f28a827Saf 	uint32_t recmema;
23520c794b3Sgavinm 	int branch, channel, ecc_locator;
23620c794b3Sgavinm 	char *intr = "nb.unknown";
23720c794b3Sgavinm 	nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms;
23820c794b3Sgavinm 
23920c794b3Sgavinm 	sp->rank = -1;
24020c794b3Sgavinm 	sp->dimm = -1;
24120c794b3Sgavinm 	sp->bank = -1;
24220c794b3Sgavinm 	sp->cas = -1;
24320c794b3Sgavinm 	sp->ras = -1LL;
24420c794b3Sgavinm 	sp->pa = -1LL;
24520c794b3Sgavinm 	sp->offset = -1;
2466cb1ca52Saf 	ferr_nf_fbd = rp->nb.nf_fbd_regs.ferr_nf_fbd;
2476cb1ca52Saf 	if ((ferr_nf_fbd & ERR_NF_FBD_MASK) == 0) {
248339f53f3SVuong Nguyen 		/* unknown ereport if a recognizable error was not found */
2496cb1ca52Saf 		sp->branch = -1;
2506cb1ca52Saf 		sp->channel = -1;
251339f53f3SVuong Nguyen 		sp->intel_error_list = -1;
2526cb1ca52Saf 		return (intr);
2536cb1ca52Saf 	}
2546cb1ca52Saf 	sp->intel_error_list = intel_nf_fbd_err(ferr_nf_fbd);
2556cb1ca52Saf 	channel = (ferr_nf_fbd >> ERR_FBD_CH_SHIFT) & 3;
2566cb1ca52Saf 	branch = channel >> 1;
2576cb1ca52Saf 	sp->branch = branch;
2586cb1ca52Saf 	sp->channel = channel;
25920c794b3Sgavinm 	if (ferr_nf_fbd & ERR_NF_FBD_MASK) {
26020c794b3Sgavinm 		if (ferr_nf_fbd & ERR_NF_FBD_ECC_UE) {
26120c794b3Sgavinm 			/*
26220c794b3Sgavinm 			 * uncorrectable ECC M4 - M12
26320c794b3Sgavinm 			 * we can only isolate to pair of dimms
26420c794b3Sgavinm 			 * for single dimm configuration let eversholt
26520c794b3Sgavinm 			 * sort it out with out needing a special rule
26620c794b3Sgavinm 			 */
26720c794b3Sgavinm 			sp->channel = -1;
26820c794b3Sgavinm 			recmema = rp->nb.nf_fbd_regs.recmema;
26920c794b3Sgavinm 			recmemb = rp->nb.nf_fbd_regs.recmemb;
27020c794b3Sgavinm 			sp->rank = (recmema >> 8) & RANK_MASK;
27120c794b3Sgavinm 			sp->bank = (recmema >> 12) & BANK_MASK;
27220c794b3Sgavinm 			sp->cas = (recmemb >> 16) & CAS_MASK;
27320c794b3Sgavinm 			sp->ras = recmemb & RAS_MASK;
27420c794b3Sgavinm 			intr = "nb.mem_ue";
27520c794b3Sgavinm 		} else if (ferr_nf_fbd & ERR_NF_FBD_M13) {
27620c794b3Sgavinm 			/*
27720c794b3Sgavinm 			 * write error M13
27820c794b3Sgavinm 			 * we can only isolate to pair of dimms
27920c794b3Sgavinm 			 */
28020c794b3Sgavinm 			sp->channel = -1;
28120c794b3Sgavinm 			if (nb_mode != NB_MEMORY_MIRROR) {
28220c794b3Sgavinm 				recmema = rp->nb.nf_fbd_regs.recmema;
283*1a10a907SToomas Soome 				recmemb = rp->nb.nf_fbd_regs.recmemb;
28420c794b3Sgavinm 				sp->rank = (recmema >> 8) & RANK_MASK;
28520c794b3Sgavinm 				sp->bank = (recmema >> 12) & BANK_MASK;
28620c794b3Sgavinm 				sp->cas = (recmemb >> 16) & CAS_MASK;
28720c794b3Sgavinm 				sp->ras = recmemb & RAS_MASK;
28820c794b3Sgavinm 			}
28920c794b3Sgavinm 			intr = "nb.fbd.ma"; /* memory alert */
29020c794b3Sgavinm 		} else if (ferr_nf_fbd & ERR_NF_FBD_MA) { /* M14, M15 and M21 */
29120c794b3Sgavinm 			intr = "nb.fbd.ch"; /* FBD on channel */
29220c794b3Sgavinm 		} else if ((ferr_nf_fbd & ERR_NF_FBD_ECC_CE) != 0) {
29320c794b3Sgavinm 			/* correctable ECC M17-M20 */
29420c794b3Sgavinm 			recmema = rp->nb.nf_fbd_regs.recmema;
29520c794b3Sgavinm 			recmemb = rp->nb.nf_fbd_regs.recmemb;
29620c794b3Sgavinm 			sp->rank = (recmema >> 8) & RANK_MASK;
29720c794b3Sgavinm 			redmemb = rp->nb.nf_fbd_regs.redmemb;
29820c794b3Sgavinm 			ecc_locator = redmemb & 0x3ffff;
29920c794b3Sgavinm 			if (ecc_locator & 0x1ff)
30020c794b3Sgavinm 				sp->channel = branch << 1;
30120c794b3Sgavinm 			else if (ecc_locator & 0x3fe00)
30220c794b3Sgavinm 				sp->channel = (branch << 1) + 1;
30320c794b3Sgavinm 			sp->dimm = sp->rank >> 1;
30420c794b3Sgavinm 			sp->bank = (recmema >> 12) & BANK_MASK;
30520c794b3Sgavinm 			sp->cas = (recmemb >> 16) & CAS_MASK;
30620c794b3Sgavinm 			sp->ras = recmemb & RAS_MASK;
30720c794b3Sgavinm 			intr = "nb.mem_ce";
30820c794b3Sgavinm 		} else if ((ferr_nf_fbd & ERR_NF_FBD_SPARE) != 0) {
30920c794b3Sgavinm 			/* spare dimm M27, M28 */
31020c794b3Sgavinm 			intr = "nb.mem_ds";
31120c794b3Sgavinm 			sp->channel = -1;
31220c794b3Sgavinm 			if (rp->nb.nf_fbd_regs.spcps & SPCPS_SPARE_DEPLOYED) {
31320c794b3Sgavinm 				sp->rank =
31420c794b3Sgavinm 				    SPCPS_FAILED_RANK(rp->nb.nf_fbd_regs.spcps);
31520c794b3Sgavinm 				nb_used_spare_rank(sp->branch, sp->rank);
31620c794b3Sgavinm 				nb_config_gen++;
31720c794b3Sgavinm 			}
3185f28a827Saf 		} else if ((ferr_nf_fbd & ERR_NF_FBD_M22) != 0) {
3195f28a827Saf 			intr = "nb.spd";	/* SPD protocol */
32020c794b3Sgavinm 		}
32120c794b3Sgavinm 	}
32220c794b3Sgavinm 	if (sp->ras != -1) {
323f899e573SVuong Nguyen 		/*
324f899e573SVuong Nguyen 		 * If driver was built with closed tree present then we will
325f899e573SVuong Nguyen 		 * have Intel proprietary code for finding physaddr
326f899e573SVuong Nguyen 		 */
327f899e573SVuong Nguyen 		if (&dimm_getphys) {
328f899e573SVuong Nguyen 			sp->pa = dimm_getphys((uint16_t)sp->branch,
329f899e573SVuong Nguyen 			    (uint16_t)sp->rank, (uint64_t)sp->bank,
330f899e573SVuong Nguyen 			    (uint64_t)sp->ras, (uint64_t)sp->cas);
331f899e573SVuong Nguyen 			if (sp->pa >= MAXPHYS_ADDR)
332f899e573SVuong Nguyen 				sp->pa = -1ULL;
333f899e573SVuong Nguyen 		} else {
334f899e573SVuong Nguyen 			sp->pa = -1ULL;
335f899e573SVuong Nguyen 		}
336f899e573SVuong Nguyen 		if (&dimm_getoffset) {
337f899e573SVuong Nguyen 			sp->offset = dimm_getoffset(sp->branch, sp->rank,
338f899e573SVuong Nguyen 			    sp->bank, sp->ras, sp->cas);
339f899e573SVuong Nguyen 		} else {
340f899e573SVuong Nguyen 			sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras,
341f899e573SVuong Nguyen 			    sp->cas);
342f899e573SVuong Nguyen 		}
34320c794b3Sgavinm 	}
34420c794b3Sgavinm 	return (intr);
34520c794b3Sgavinm }
34620c794b3Sgavinm 
34785738508SVuong Nguyen static struct mch_error_code nf_mem_error_code[] = {
34885738508SVuong Nguyen 	{ 21, EMASK_MEM_M21, ERR_NF_MEM_M21 },
34985738508SVuong Nguyen 	{ 20, EMASK_MEM_M20, ERR_NF_MEM_M20 },
35085738508SVuong Nguyen 	{ 18, EMASK_MEM_M18, ERR_NF_MEM_M18 },
35185738508SVuong Nguyen 	{ 16, EMASK_MEM_M16, ERR_NF_MEM_M16 },
35285738508SVuong Nguyen 	{ 15, EMASK_MEM_M15, ERR_NF_MEM_M15 },
35385738508SVuong Nguyen 	{ 14, EMASK_MEM_M14, ERR_NF_MEM_M14 },
35485738508SVuong Nguyen 	{ 12, EMASK_MEM_M12, ERR_NF_MEM_M12 },
35585738508SVuong Nguyen 	{ 11, EMASK_MEM_M11, ERR_NF_MEM_M11 },
35685738508SVuong Nguyen 	{ 10, EMASK_MEM_M10, ERR_NF_MEM_M10 },
35785738508SVuong Nguyen 	{ 6, EMASK_MEM_M6, ERR_NF_MEM_M6 },
35885738508SVuong Nguyen 	{ 5, EMASK_MEM_M5, ERR_NF_MEM_M5 },
35985738508SVuong Nguyen 	{ 4, EMASK_MEM_M4, ERR_NF_MEM_M4 },
36085738508SVuong Nguyen 	{ 1, EMASK_MEM_M1, ERR_NF_MEM_M1 }
36185738508SVuong Nguyen };
36285738508SVuong Nguyen 
36385738508SVuong Nguyen static int
intel_nf_mem_err(uint32_t nf_mem)36485738508SVuong Nguyen intel_nf_mem_err(uint32_t nf_mem)
36585738508SVuong Nguyen {
36685738508SVuong Nguyen 	int rt = -1;
36785738508SVuong Nguyen 	int nerr = 0;
36885738508SVuong Nguyen 	uint32_t emask_mem = 0;
36985738508SVuong Nguyen 	int i;
37085738508SVuong Nguyen 	int sz;
37185738508SVuong Nguyen 
37285738508SVuong Nguyen 	sz = sizeof (nf_mem_error_code) / sizeof (struct mch_error_code);
37385738508SVuong Nguyen 
37485738508SVuong Nguyen 	for (i = 0; i < sz; i++) {
37585738508SVuong Nguyen 		if (nf_mem & nf_mem_error_code[i].error_bit) {
37685738508SVuong Nguyen 			rt = nf_mem_error_code[i].intel_error_list;
37785738508SVuong Nguyen 			emask_mem |= nf_mem_error_code[i].emask;
37885738508SVuong Nguyen 			nerr++;
37985738508SVuong Nguyen 		}
38085738508SVuong Nguyen 	}
38185738508SVuong Nguyen 	if (emask_mem)
38285738508SVuong Nguyen 		nb_mem_mask_mc(emask_mem);
38385738508SVuong Nguyen 	if (nerr > 1)
38485738508SVuong Nguyen 		rt = -1;
38585738508SVuong Nguyen 	return (rt);
38685738508SVuong Nguyen }
38785738508SVuong Nguyen 
38885738508SVuong Nguyen static char *
nf_mem_error(const nb_regs_t * rp,void * data)38985738508SVuong Nguyen nf_mem_error(const nb_regs_t *rp, void *data)
39085738508SVuong Nguyen {
39185738508SVuong Nguyen 	uint32_t ferr_nf_mem, recmema, recmemb;
39285738508SVuong Nguyen 	uint32_t nrecmema, nrecmemb, validlog;
39385738508SVuong Nguyen 	int channel;
39485738508SVuong Nguyen 	char *intr = "nb.unknown";
39585738508SVuong Nguyen 	nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms;
39685738508SVuong Nguyen 
39785738508SVuong Nguyen 	sp->rank = -1;
39885738508SVuong Nguyen 	sp->dimm = -1;
39985738508SVuong Nguyen 	sp->bank = -1;
40085738508SVuong Nguyen 	sp->cas = -1;
40185738508SVuong Nguyen 	sp->ras = -1LL;
40285738508SVuong Nguyen 	sp->pa = -1LL;
40385738508SVuong Nguyen 	sp->offset = -1;
40485738508SVuong Nguyen 	ferr_nf_mem = rp->nb.nf_mem_regs.ferr_nf_mem;
40585738508SVuong Nguyen 	if ((ferr_nf_mem & ERR_NF_MEM_MASK) == 0) {
40685738508SVuong Nguyen 		/* no first error found */
40785738508SVuong Nguyen 		sp->branch = -1;
40885738508SVuong Nguyen 		sp->channel = -1;
40985738508SVuong Nguyen 		sp->intel_error_list =
41085738508SVuong Nguyen 		    intel_nf_mem_err(rp->nb.nf_mem_regs.nerr_nf_mem);
41185738508SVuong Nguyen 		return (intr);
41285738508SVuong Nguyen 	}
41385738508SVuong Nguyen 	sp->intel_error_list = intel_nf_mem_err(ferr_nf_mem);
41485738508SVuong Nguyen 
41585738508SVuong Nguyen 	channel = (ferr_nf_mem >> ERR_MEM_CH_SHIFT) & 0x1;
41685738508SVuong Nguyen 	sp->branch = channel;
41785738508SVuong Nguyen 	sp->channel = -1;
41885738508SVuong Nguyen 	if (ferr_nf_mem & ERR_NF_MEM_MASK) {
41985738508SVuong Nguyen 		if (ferr_nf_mem & ERR_NF_MEM_ECC_UE) {
42085738508SVuong Nguyen 			/*
42185738508SVuong Nguyen 			 * uncorrectable ECC M1,M4-M6,M10-M12
42285738508SVuong Nguyen 			 * There is only channel per branch
42385738508SVuong Nguyen 			 * Invalidate the channel number so the mem ereport
42485738508SVuong Nguyen 			 * has the same detector with existing 5000 ereports.
42585738508SVuong Nguyen 			 * so we can leverage the existing Everhsolt rule.
42685738508SVuong Nguyen 			 */
42785738508SVuong Nguyen 			validlog = rp->nb.nf_mem_regs.validlog;
42885738508SVuong Nguyen 			if (ferr_nf_mem & ERR_NF_MEM_M1) {
42985738508SVuong Nguyen 				nrecmema = rp->nb.nf_mem_regs.nrecmema;
43085738508SVuong Nguyen 				nrecmemb = rp->nb.nf_mem_regs.nrecmemb;
43185738508SVuong Nguyen 				/* check if the nrecmem log is valid */
43285738508SVuong Nguyen 				if (validlog & 0x1 || nb_check_validlog == 0) {
43385738508SVuong Nguyen 					sp->rank = (nrecmema >> 8) & RANK_MASK;
43485738508SVuong Nguyen 					sp->bank = (nrecmema >> 12) & BANK_MASK;
43585738508SVuong Nguyen 					sp->cas = (nrecmemb >> 16) & CAS_MASK;
43685738508SVuong Nguyen 					sp->ras = nrecmemb & RAS_MASK;
43785738508SVuong Nguyen 				}
43885738508SVuong Nguyen 			} else {
43985738508SVuong Nguyen 				recmema = rp->nb.nf_mem_regs.recmema;
44085738508SVuong Nguyen 				recmemb = rp->nb.nf_mem_regs.recmemb;
44185738508SVuong Nguyen 				/* check if the recmem log is valid */
44285738508SVuong Nguyen 				if (validlog & 0x2 || nb_check_validlog == 0) {
44385738508SVuong Nguyen 					sp->rank = (recmema >> 8) & RANK_MASK;
44485738508SVuong Nguyen 					sp->bank = (recmema >> 12) & BANK_MASK;
44585738508SVuong Nguyen 					sp->cas = (recmemb >> 16) & CAS_MASK;
44685738508SVuong Nguyen 					sp->ras = recmemb & RAS_MASK;
44785738508SVuong Nguyen 				}
44885738508SVuong Nguyen 			}
44985738508SVuong Nguyen 			intr = "nb.ddr2_mem_ue";
45085738508SVuong Nguyen 		} else if ((ferr_nf_mem & ERR_NF_MEM_ECC_CE) != 0) {
45185738508SVuong Nguyen 			/* correctable ECC M14-M16 */
45285738508SVuong Nguyen 			recmema = rp->nb.nf_mem_regs.recmema;
45385738508SVuong Nguyen 			recmemb = rp->nb.nf_mem_regs.recmemb;
45485738508SVuong Nguyen 			validlog = rp->nb.nf_mem_regs.validlog;
45585738508SVuong Nguyen 			/* check if the recmem log is valid */
45685738508SVuong Nguyen 			if (validlog & 0x2 || nb_check_validlog == 0) {
45785738508SVuong Nguyen 				sp->channel = channel;
45885738508SVuong Nguyen 				sp->rank = (recmema >> 8) & RANK_MASK;
45985738508SVuong Nguyen 				sp->dimm = nb_rank2dimm(sp->channel, sp->rank);
46085738508SVuong Nguyen 				sp->bank = (recmema >> 12) & BANK_MASK;
46185738508SVuong Nguyen 				sp->cas = (recmemb >> 16) & CAS_MASK;
46285738508SVuong Nguyen 				sp->ras = recmemb & RAS_MASK;
46385738508SVuong Nguyen 			}
46485738508SVuong Nguyen 			intr = "nb.ddr2_mem_ce";
46585738508SVuong Nguyen 		} else if ((ferr_nf_mem & ERR_NF_MEM_SPARE) != 0) {
46685738508SVuong Nguyen 			/* spare dimm M20, M21 */
46785738508SVuong Nguyen 			intr = "nb.ddr2_mem_ds";
46885738508SVuong Nguyen 
46985738508SVuong Nguyen 			/*
47085738508SVuong Nguyen 			 * The channel can be valid here.
47185738508SVuong Nguyen 			 * However, there is only one channel per branch and
47285738508SVuong Nguyen 			 * to leverage the eversolt rules of other chipsets,
47385738508SVuong Nguyen 			 * the channel is ignored and let the rule find it out
47485738508SVuong Nguyen 			 * from the topology.
47585738508SVuong Nguyen 			 */
47685738508SVuong Nguyen 			if (rp->nb.nf_mem_regs.spcps & SPCPS_SPARE_DEPLOYED) {
47785738508SVuong Nguyen 				sp->rank =
47885738508SVuong Nguyen 				    SPCPS_FAILED_RANK(rp->nb.nf_mem_regs.spcps);
47985738508SVuong Nguyen 				nb_used_spare_rank(sp->branch, sp->rank);
48085738508SVuong Nguyen 				nb_config_gen++;
48185738508SVuong Nguyen 			}
48285738508SVuong Nguyen 		} else if ((ferr_nf_mem & ERR_NF_MEM_M18) != 0) {
48385738508SVuong Nguyen 			sp->channel = channel;
48485738508SVuong Nguyen 			intr = "nb.ddr2_spd";	/* SPD protocol */
48585738508SVuong Nguyen 
48685738508SVuong Nguyen 		}
48785738508SVuong Nguyen 	}
48885738508SVuong Nguyen 	if (sp->ras != -1) {
489f899e573SVuong Nguyen 		/*
490f899e573SVuong Nguyen 		 * If driver was built with closed tree present then we will
491f899e573SVuong Nguyen 		 * have Intel proprietary code for finding physaddr
492f899e573SVuong Nguyen 		 */
493f899e573SVuong Nguyen 		if (&dimm_getphys) {
494f899e573SVuong Nguyen 			sp->pa = dimm_getphys((uint16_t)sp->branch,
495f899e573SVuong Nguyen 			    (uint16_t)sp->rank, (uint64_t)sp->bank,
496f899e573SVuong Nguyen 			    (uint64_t)sp->ras, (uint64_t)sp->cas);
497f899e573SVuong Nguyen 			if (sp->pa >= MAXPHYS_ADDR)
498f899e573SVuong Nguyen 				sp->pa = -1ULL;
499f899e573SVuong Nguyen 		} else {
500f899e573SVuong Nguyen 			sp->pa = -1ULL;
501f899e573SVuong Nguyen 		}
502f899e573SVuong Nguyen 		if (&dimm_getoffset) {
503f899e573SVuong Nguyen 			sp->offset = dimm_getoffset(sp->branch, sp->rank,
504f899e573SVuong Nguyen 			    sp->bank, sp->ras, sp->cas);
505f899e573SVuong Nguyen 		} else {
506f899e573SVuong Nguyen 			sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras,
507f899e573SVuong Nguyen 			    sp->cas);
508f899e573SVuong Nguyen 		}
50985738508SVuong Nguyen 	}
51085738508SVuong Nguyen 	return (intr);
51185738508SVuong Nguyen }
51285738508SVuong Nguyen 
51320c794b3Sgavinm static struct mch_error_code fat_int_error_code[] = {
5145f28a827Saf 	{ 14, EMASK_INT_B14, ERR_FAT_INT_B14 },
5155f28a827Saf 	{ 12, EMASK_INT_B12, ERR_FAT_INT_B12 },
5165f28a827Saf 	{ 25, EMASK_INT_B25, ERR_FAT_INT_B25 },
5175f28a827Saf 	{ 23, EMASK_INT_B23, ERR_FAT_INT_B23 },
5185f28a827Saf 	{ 21, EMASK_INT_B21, ERR_FAT_INT_B21 },
5196cb1ca52Saf 	{ 7, EMASK_INT_B7, ERR_FAT_INT_B7 },
52020c794b3Sgavinm 	{ 4, EMASK_INT_B4, ERR_FAT_INT_B4 },
52120c794b3Sgavinm 	{ 3, EMASK_INT_B3, ERR_FAT_INT_B3 },
52220c794b3Sgavinm 	{ 2, EMASK_INT_B2, ERR_FAT_INT_B2 },
52320c794b3Sgavinm 	{ 1, EMASK_INT_B1, ERR_FAT_INT_B1 }
52420c794b3Sgavinm };
52520c794b3Sgavinm 
52620c794b3Sgavinm static struct mch_error_code nf_int_error_code[] = {
5275f28a827Saf 	{ 27, 0, ERR_NF_INT_B27 },
5285f28a827Saf 	{ 24, 0, ERR_NF_INT_B24 },
5295f28a827Saf 	{ 22, EMASK_INT_B22, ERR_NF_INT_B22 },
5305f28a827Saf 	{ 20, EMASK_INT_B20, ERR_NF_INT_B20 },
5315f28a827Saf 	{ 19, EMASK_INT_B19, ERR_NF_INT_B19 },
5325f28a827Saf 	{ 18, 0, ERR_NF_INT_B18 },
5335f28a827Saf 	{ 17, 0, ERR_NF_INT_B17 },
5345f28a827Saf 	{ 16, 0, ERR_NF_INT_B16 },
5355f28a827Saf 	{ 11, EMASK_INT_B11, ERR_NF_INT_B11 },
5365f28a827Saf 	{ 10, EMASK_INT_B10, ERR_NF_INT_B10 },
5375f28a827Saf 	{ 9, EMASK_INT_B9, ERR_NF_INT_B9 },
5386cb1ca52Saf 	{ 8, EMASK_INT_B8, ERR_NF_INT_B8 },
53920c794b3Sgavinm 	{ 6, EMASK_INT_B6, ERR_NF_INT_B6 },
54020c794b3Sgavinm 	{ 5, EMASK_INT_B5, ERR_NF_INT_B5 }
54120c794b3Sgavinm };
54220c794b3Sgavinm 
54320c794b3Sgavinm static int
intel_int_err(uint16_t err_fat_int,uint16_t err_nf_int)5445f28a827Saf intel_int_err(uint16_t err_fat_int, uint16_t err_nf_int)
54520c794b3Sgavinm {
54620c794b3Sgavinm 	int rt = -1;
54720c794b3Sgavinm 	int nerr = 0;
5485f28a827Saf 	uint32_t emask_int = 0;
54920c794b3Sgavinm 	int i;
55020c794b3Sgavinm 	int sz;
55120c794b3Sgavinm 
55220c794b3Sgavinm 	sz = sizeof (fat_int_error_code) / sizeof (struct mch_error_code);
55320c794b3Sgavinm 
55420c794b3Sgavinm 	for (i = 0; i < sz; i++) {
5556cb1ca52Saf 		if (err_fat_int & fat_int_error_code[i].error_bit) {
55620c794b3Sgavinm 			rt = fat_int_error_code[i].intel_error_list;
55720c794b3Sgavinm 			emask_int |= fat_int_error_code[i].emask;
55820c794b3Sgavinm 			nerr++;
55920c794b3Sgavinm 		}
56020c794b3Sgavinm 	}
56120c794b3Sgavinm 
5625f28a827Saf 	if (nb_chipset == INTEL_NB_5400 &&
5635f28a827Saf 	    (err_nf_int & NERR_NF_5400_INT_B26) != 0) {
5645f28a827Saf 		err_nf_int &= ~NERR_NF_5400_INT_B26;
5655f28a827Saf 		rt = 26;
5665f28a827Saf 		nerr++;
5675f28a827Saf 	}
5685f28a827Saf 
5699ff4cbe7SAdrian Frost 	if (rt)
5709ff4cbe7SAdrian Frost 		err_nf_int &= ~ERR_NF_INT_B18;
5719ff4cbe7SAdrian Frost 
57220c794b3Sgavinm 	sz = sizeof (nf_int_error_code) / sizeof (struct mch_error_code);
57320c794b3Sgavinm 
57420c794b3Sgavinm 	for (i = 0; i < sz; i++) {
5756cb1ca52Saf 		if (err_nf_int & nf_int_error_code[i].error_bit) {
57620c794b3Sgavinm 			rt = nf_int_error_code[i].intel_error_list;
57720c794b3Sgavinm 			emask_int |= nf_int_error_code[i].emask;
57820c794b3Sgavinm 			nerr++;
57920c794b3Sgavinm 		}
58020c794b3Sgavinm 	}
58120c794b3Sgavinm 
58220c794b3Sgavinm 	if (emask_int)
58320c794b3Sgavinm 		nb_int_mask_mc(emask_int);
58420c794b3Sgavinm 	if (nerr > 1)
58520c794b3Sgavinm 		rt = -1;
58620c794b3Sgavinm 	return (rt);
58720c794b3Sgavinm }
58820c794b3Sgavinm 
5899ff4cbe7SAdrian Frost static int
log_int_err(nb_regs_t * rp,int willpanic,int * interpose)5900ad0f0b2SAdrian Frost log_int_err(nb_regs_t *rp, int willpanic, int *interpose)
59120c794b3Sgavinm {
59220c794b3Sgavinm 	int t = 0;
5939ff4cbe7SAdrian Frost 	int rt = 0;
59420c794b3Sgavinm 
59520c794b3Sgavinm 	rp->flag = NB_REG_LOG_INT;
59620c794b3Sgavinm 	rp->nb.int_regs.ferr_fat_int = FERR_FAT_INT_RD(interpose);
59720c794b3Sgavinm 	rp->nb.int_regs.ferr_nf_int = FERR_NF_INT_RD(&t);
59820c794b3Sgavinm 	*interpose |= t;
59920c794b3Sgavinm 	rp->nb.int_regs.nerr_fat_int = NERR_FAT_INT_RD(&t);
60020c794b3Sgavinm 	*interpose |= t;
60120c794b3Sgavinm 	rp->nb.int_regs.nerr_nf_int = NERR_NF_INT_RD(&t);
60220c794b3Sgavinm 	*interpose |= t;
60320c794b3Sgavinm 	rp->nb.int_regs.nrecint = NRECINT_RD();
60420c794b3Sgavinm 	rp->nb.int_regs.recint = RECINT_RD();
60520c794b3Sgavinm 	rp->nb.int_regs.nrecsf = NRECSF_RD();
60620c794b3Sgavinm 	rp->nb.int_regs.recsf = RECSF_RD();
60720c794b3Sgavinm 
6080ad0f0b2SAdrian Frost 	if (!willpanic) {
6090ad0f0b2SAdrian Frost 		if (rp->nb.int_regs.ferr_fat_int || *interpose)
6100ad0f0b2SAdrian Frost 			FERR_FAT_INT_WR(rp->nb.int_regs.ferr_fat_int);
6110ad0f0b2SAdrian Frost 		if (rp->nb.int_regs.ferr_nf_int || *interpose)
6120ad0f0b2SAdrian Frost 			FERR_NF_INT_WR(rp->nb.int_regs.ferr_nf_int);
6130ad0f0b2SAdrian Frost 		if (rp->nb.int_regs.nerr_fat_int)
6140ad0f0b2SAdrian Frost 			NERR_FAT_INT_WR(rp->nb.int_regs.nerr_fat_int);
6150ad0f0b2SAdrian Frost 		if (rp->nb.int_regs.nerr_nf_int)
6160ad0f0b2SAdrian Frost 			NERR_NF_INT_WR(rp->nb.int_regs.nerr_nf_int);
6170ad0f0b2SAdrian Frost 		/*
6180ad0f0b2SAdrian Frost 		 * if interpose write read-only registers to clear from pcii
6190ad0f0b2SAdrian Frost 		 * cache
6200ad0f0b2SAdrian Frost 		 */
6210ad0f0b2SAdrian Frost 		if (*interpose) {
6220ad0f0b2SAdrian Frost 			NRECINT_WR();
6230ad0f0b2SAdrian Frost 			RECINT_WR();
6240ad0f0b2SAdrian Frost 			NRECSF_WR();
6250ad0f0b2SAdrian Frost 			RECSF_WR();
6260ad0f0b2SAdrian Frost 		}
62720c794b3Sgavinm 	}
6289ff4cbe7SAdrian Frost 	if (rp->nb.int_regs.ferr_fat_int == 0 &&
6299ff4cbe7SAdrian Frost 	    rp->nb.int_regs.nerr_fat_int == 0 &&
6309ff4cbe7SAdrian Frost 	    (rp->nb.int_regs.ferr_nf_int == ERR_NF_INT_B18 ||
6319ff4cbe7SAdrian Frost 	    (rp->nb.int_regs.ferr_nf_int == 0 &&
6329ff4cbe7SAdrian Frost 	    rp->nb.int_regs.nerr_nf_int == ERR_NF_INT_B18))) {
6339ff4cbe7SAdrian Frost 		rt = 1;
6349ff4cbe7SAdrian Frost 	}
6359ff4cbe7SAdrian Frost 	return (rt);
63620c794b3Sgavinm }
63720c794b3Sgavinm 
6385f28a827Saf static void
log_thermal_err(nb_regs_t * rp,int willpanic,int * interpose)6390ad0f0b2SAdrian Frost log_thermal_err(nb_regs_t *rp, int willpanic, int *interpose)
6405f28a827Saf {
6415f28a827Saf 	int t = 0;
6425f28a827Saf 
6435f28a827Saf 	rp->flag = NB_REG_LOG_THR;
6445f28a827Saf 	rp->nb.thr_regs.ferr_fat_thr = FERR_FAT_THR_RD(interpose);
6455f28a827Saf 	rp->nb.thr_regs.nerr_fat_thr = NERR_FAT_THR_RD(&t);
6465f28a827Saf 	*interpose |= t;
6475f28a827Saf 	rp->nb.thr_regs.ferr_nf_thr = FERR_NF_THR_RD(&t);
6485f28a827Saf 	*interpose |= t;
6495f28a827Saf 	rp->nb.thr_regs.nerr_nf_thr = NERR_NF_THR_RD(&t);
6505f28a827Saf 	*interpose |= t;
6515f28a827Saf 	rp->nb.thr_regs.ctsts = CTSTS_RD();
6525f28a827Saf 	rp->nb.thr_regs.thrtsts = THRTSTS_RD();
6535f28a827Saf 
6540ad0f0b2SAdrian Frost 	if (!willpanic) {
6550ad0f0b2SAdrian Frost 		if (rp->nb.thr_regs.ferr_fat_thr || *interpose)
6560ad0f0b2SAdrian Frost 			FERR_FAT_THR_WR(rp->nb.thr_regs.ferr_fat_thr);
6570ad0f0b2SAdrian Frost 		if (rp->nb.thr_regs.nerr_fat_thr || *interpose)
6580ad0f0b2SAdrian Frost 			NERR_FAT_THR_WR(rp->nb.thr_regs.nerr_fat_thr);
6590ad0f0b2SAdrian Frost 		if (rp->nb.thr_regs.ferr_nf_thr || *interpose)
6600ad0f0b2SAdrian Frost 			FERR_NF_THR_WR(rp->nb.thr_regs.ferr_nf_thr);
6610ad0f0b2SAdrian Frost 		if (rp->nb.thr_regs.nerr_nf_thr || *interpose)
6620ad0f0b2SAdrian Frost 			NERR_NF_THR_WR(rp->nb.thr_regs.nerr_nf_thr);
6630ad0f0b2SAdrian Frost 
6640ad0f0b2SAdrian Frost 		if (*interpose) {
6650ad0f0b2SAdrian Frost 			CTSTS_WR(rp->nb.thr_regs.ctsts);
6660ad0f0b2SAdrian Frost 			THRTSTS_WR(rp->nb.thr_regs.thrtsts);
6670ad0f0b2SAdrian Frost 		}
6685f28a827Saf 	}
6695f28a827Saf }
6705f28a827Saf 
67120c794b3Sgavinm static void
log_dma_err(nb_regs_t * rp,int * interpose)67220c794b3Sgavinm log_dma_err(nb_regs_t *rp, int *interpose)
67320c794b3Sgavinm {
67420c794b3Sgavinm 	rp->flag = NB_REG_LOG_DMA;
67520c794b3Sgavinm 
67620c794b3Sgavinm 	rp->nb.dma_regs.pcists = PCISTS_RD(interpose);
67720c794b3Sgavinm 	rp->nb.dma_regs.pexdevsts = PCIDEVSTS_RD();
67820c794b3Sgavinm }
67920c794b3Sgavinm 
6806cb1ca52Saf static struct mch_error_code fat_fsb_error_code[] = {
6816cb1ca52Saf 	{ 9, EMASK_FSB_F9, ERR_FAT_FSB_F9 },
6826cb1ca52Saf 	{ 2, EMASK_FSB_F2, ERR_FAT_FSB_F2 },
6836cb1ca52Saf 	{ 1, EMASK_FSB_F1, ERR_FAT_FSB_F1 }
6846cb1ca52Saf };
6856cb1ca52Saf 
6866cb1ca52Saf static struct mch_error_code nf_fsb_error_code[] = {
6876cb1ca52Saf 	{ 8, EMASK_FSB_F8, ERR_NF_FSB_F8 },
6886cb1ca52Saf 	{ 7, EMASK_FSB_F7, ERR_NF_FSB_F7 },
6896cb1ca52Saf 	{ 6, EMASK_FSB_F6, ERR_NF_FSB_F6 }
6906cb1ca52Saf };
6916cb1ca52Saf 
69220c794b3Sgavinm static int
intel_fsb_err(int fsb,uint8_t err_fat_fsb,uint8_t err_nf_fsb)6936cb1ca52Saf intel_fsb_err(int fsb, uint8_t err_fat_fsb, uint8_t err_nf_fsb)
69420c794b3Sgavinm {
69520c794b3Sgavinm 	int rt = -1;
69620c794b3Sgavinm 	int nerr = 0;
69720c794b3Sgavinm 	uint16_t emask_fsb = 0;
6986cb1ca52Saf 	int i;
6996cb1ca52Saf 	int sz;
70020c794b3Sgavinm 
7016cb1ca52Saf 	sz = sizeof (fat_fsb_error_code) / sizeof (struct mch_error_code);
7026cb1ca52Saf 
7036cb1ca52Saf 	for (i = 0; i < sz; i++) {
7046cb1ca52Saf 		if (err_fat_fsb & fat_fsb_error_code[i].error_bit) {
7056cb1ca52Saf 			rt = fat_fsb_error_code[i].intel_error_list;
7066cb1ca52Saf 			emask_fsb |= fat_fsb_error_code[i].emask;
7076cb1ca52Saf 			nerr++;
7086cb1ca52Saf 		}
70920c794b3Sgavinm 	}
7106cb1ca52Saf 
7116cb1ca52Saf 	sz = sizeof (nf_fsb_error_code) / sizeof (struct mch_error_code);
7126cb1ca52Saf 
7136cb1ca52Saf 	for (i = 0; i < sz; i++) {
7146cb1ca52Saf 		if (err_nf_fsb & nf_fsb_error_code[i].error_bit) {
7156cb1ca52Saf 			rt = nf_fsb_error_code[i].intel_error_list;
7166cb1ca52Saf 			emask_fsb |= nf_fsb_error_code[i].emask;
7176cb1ca52Saf 			nerr++;
7186cb1ca52Saf 		}
71920c794b3Sgavinm 	}
7206cb1ca52Saf 
72120c794b3Sgavinm 	if (emask_fsb)
72220c794b3Sgavinm 		nb_fsb_mask_mc(fsb, emask_fsb);
72320c794b3Sgavinm 	if (nerr > 1)
72420c794b3Sgavinm 		rt = -1;
72520c794b3Sgavinm 	return (rt);
72620c794b3Sgavinm }
72720c794b3Sgavinm 
72820c794b3Sgavinm static void
log_fsb_err(uint64_t ferr,nb_regs_t * rp,int willpanic,int * interpose)7290ad0f0b2SAdrian Frost log_fsb_err(uint64_t ferr, nb_regs_t *rp, int willpanic, int *interpose)
73020c794b3Sgavinm {
73120c794b3Sgavinm 	uint8_t fsb;
73220c794b3Sgavinm 	int t = 0;
73320c794b3Sgavinm 
73420c794b3Sgavinm 	fsb = GE_FERR_FSB(ferr);
73520c794b3Sgavinm 	rp->flag = NB_REG_LOG_FSB;
73620c794b3Sgavinm 
73720c794b3Sgavinm 	rp->nb.fsb_regs.fsb = fsb;
73820c794b3Sgavinm 	rp->nb.fsb_regs.ferr_fat_fsb = FERR_FAT_FSB_RD(fsb, interpose);
73920c794b3Sgavinm 	rp->nb.fsb_regs.ferr_nf_fsb = FERR_NF_FSB_RD(fsb, &t);
74020c794b3Sgavinm 	*interpose |= t;
74120c794b3Sgavinm 	rp->nb.fsb_regs.nerr_fat_fsb = NERR_FAT_FSB_RD(fsb, &t);
74220c794b3Sgavinm 	*interpose |= t;
74320c794b3Sgavinm 	rp->nb.fsb_regs.nerr_nf_fsb = NERR_NF_FSB_RD(fsb, &t);
74420c794b3Sgavinm 	*interpose |= t;
74520c794b3Sgavinm 	rp->nb.fsb_regs.nrecfsb = NRECFSB_RD(fsb);
74620c794b3Sgavinm 	rp->nb.fsb_regs.nrecfsb_addr = NRECADDR_RD(fsb);
74720c794b3Sgavinm 	rp->nb.fsb_regs.recfsb = RECFSB_RD(fsb);
7480ad0f0b2SAdrian Frost 	if (!willpanic) {
7492d532312SVuong Nguyen 		/* Clear the fatal/non-fatal first/next FSB errors */
7500ad0f0b2SAdrian Frost 		if (rp->nb.fsb_regs.ferr_fat_fsb || *interpose)
7510ad0f0b2SAdrian Frost 			FERR_FAT_FSB_WR(fsb, rp->nb.fsb_regs.ferr_fat_fsb);
7520ad0f0b2SAdrian Frost 		if (rp->nb.fsb_regs.ferr_nf_fsb || *interpose)
7530ad0f0b2SAdrian Frost 			FERR_NF_FSB_WR(fsb, rp->nb.fsb_regs.ferr_nf_fsb);
7542d532312SVuong Nguyen 		if (rp->nb.fsb_regs.nerr_fat_fsb || *interpose)
7552d532312SVuong Nguyen 			NERR_FAT_FSB_WR(fsb, rp->nb.fsb_regs.nerr_fat_fsb);
7562d532312SVuong Nguyen 		if (rp->nb.fsb_regs.nerr_nf_fsb || *interpose)
7572d532312SVuong Nguyen 			NERR_NF_FSB_WR(fsb, rp->nb.fsb_regs.nerr_nf_fsb);
7582d532312SVuong Nguyen 
7590ad0f0b2SAdrian Frost 		/*
7600ad0f0b2SAdrian Frost 		 * if interpose write read-only registers to clear from pcii
7610ad0f0b2SAdrian Frost 		 * cache
7620ad0f0b2SAdrian Frost 		 */
7630ad0f0b2SAdrian Frost 		if (*interpose) {
7640ad0f0b2SAdrian Frost 			NRECFSB_WR(fsb);
7650ad0f0b2SAdrian Frost 			NRECADDR_WR(fsb);
7660ad0f0b2SAdrian Frost 			RECFSB_WR(fsb);
7670ad0f0b2SAdrian Frost 		}
76820c794b3Sgavinm 	}
76920c794b3Sgavinm }
77020c794b3Sgavinm 
77120c794b3Sgavinm static struct mch_error_code fat_pex_error_code[] = {
77220c794b3Sgavinm 	{ 19, EMASK_UNCOR_PEX_IO19, PEX_FAT_IO19 },
77320c794b3Sgavinm 	{ 18, EMASK_UNCOR_PEX_IO18, PEX_FAT_IO18 },
77420c794b3Sgavinm 	{ 10, EMASK_UNCOR_PEX_IO10, PEX_FAT_IO10 },
77520c794b3Sgavinm 	{ 9, EMASK_UNCOR_PEX_IO9, PEX_FAT_IO9 },
77620c794b3Sgavinm 	{ 8, EMASK_UNCOR_PEX_IO8, PEX_FAT_IO8 },
77720c794b3Sgavinm 	{ 7, EMASK_UNCOR_PEX_IO7, PEX_FAT_IO7 },
77820c794b3Sgavinm 	{ 6, EMASK_UNCOR_PEX_IO6, PEX_FAT_IO6 },
77920c794b3Sgavinm 	{ 5, EMASK_UNCOR_PEX_IO5, PEX_FAT_IO5 },
78020c794b3Sgavinm 	{ 4, EMASK_UNCOR_PEX_IO4, PEX_FAT_IO4 },
78120c794b3Sgavinm 	{ 3, EMASK_UNCOR_PEX_IO3, PEX_FAT_IO3 },
78220c794b3Sgavinm 	{ 2, EMASK_UNCOR_PEX_IO2, PEX_FAT_IO2 },
78320c794b3Sgavinm 	{ 0, EMASK_UNCOR_PEX_IO0, PEX_FAT_IO0 }
78420c794b3Sgavinm };
78520c794b3Sgavinm 
7865f28a827Saf static struct mch_error_code fat_unit_pex_5400_error_code[] = {
7875f28a827Saf 	{ 32, EMASK_UNIT_PEX_IO32, PEX_5400_FAT_IO32 },
7885f28a827Saf 	{ 31, EMASK_UNIT_PEX_IO31, PEX_5400_FAT_IO31 },
7895f28a827Saf 	{ 30, EMASK_UNIT_PEX_IO30, PEX_5400_FAT_IO30 },
7905f28a827Saf 	{ 29, EMASK_UNIT_PEX_IO29, PEX_5400_FAT_IO29 },
7915f28a827Saf 	{ 27, EMASK_UNIT_PEX_IO27, PEX_5400_FAT_IO27 },
7925f28a827Saf 	{ 26, EMASK_UNIT_PEX_IO26, PEX_5400_FAT_IO26 },
7935f28a827Saf 	{ 25, EMASK_UNIT_PEX_IO25, PEX_5400_FAT_IO25 },
7945f28a827Saf 	{ 24, EMASK_UNIT_PEX_IO24, PEX_5400_FAT_IO24 },
7955f28a827Saf 	{ 23, EMASK_UNIT_PEX_IO23, PEX_5400_FAT_IO23 },
7965f28a827Saf 	{ 22, EMASK_UNIT_PEX_IO22, PEX_5400_FAT_IO22 },
7975f28a827Saf };
7985f28a827Saf 
7995f28a827Saf static struct mch_error_code fat_pex_5400_error_code[] = {
8005f28a827Saf 	{ 19, EMASK_UNCOR_PEX_IO19, PEX_5400_FAT_IO19 },
8015f28a827Saf 	{ 18, EMASK_UNCOR_PEX_IO18, PEX_5400_FAT_IO18 },
8025f28a827Saf 	{ 10, EMASK_UNCOR_PEX_IO10, PEX_5400_FAT_IO10 },
8035f28a827Saf 	{ 9, EMASK_UNCOR_PEX_IO9, PEX_5400_FAT_IO9 },
8045f28a827Saf 	{ 8, EMASK_UNCOR_PEX_IO8, PEX_5400_FAT_IO8 },
8055f28a827Saf 	{ 7, EMASK_UNCOR_PEX_IO7, PEX_5400_FAT_IO7 },
8065f28a827Saf 	{ 6, EMASK_UNCOR_PEX_IO6, PEX_5400_FAT_IO6 },
8075f28a827Saf 	{ 5, EMASK_UNCOR_PEX_IO5, PEX_5400_FAT_IO5 },
8085f28a827Saf 	{ 4, EMASK_UNCOR_PEX_IO4, PEX_5400_FAT_IO4 },
8095f28a827Saf 	{ 2, EMASK_UNCOR_PEX_IO2, PEX_5400_FAT_IO2 },
8105f28a827Saf 	{ 0, EMASK_UNCOR_PEX_IO0, PEX_5400_FAT_IO0 }
8115f28a827Saf };
8125f28a827Saf 
8135f28a827Saf static struct mch_error_code fat_rp_5400_error_code[] = {
8145f28a827Saf 	{ 1, EMASK_RP_PEX_IO1, PEX_5400_FAT_IO1 }
8155f28a827Saf };
8165f28a827Saf 
81720c794b3Sgavinm static struct mch_error_code fat_rp_error_code[] = {
81820c794b3Sgavinm 	{ 1, EMASK_RP_PEX_IO1, PEX_FAT_IO1 }
81920c794b3Sgavinm };
82020c794b3Sgavinm 
82120c794b3Sgavinm static struct mch_error_code uncor_pex_error_code[] = {
82220c794b3Sgavinm 	{ 19, EMASK_UNCOR_PEX_IO19, PEX_NF_IO19 },
82320c794b3Sgavinm 	{ 9, EMASK_UNCOR_PEX_IO9, PEX_NF_IO9 },
82420c794b3Sgavinm 	{ 8, EMASK_UNCOR_PEX_IO8, PEX_NF_IO8 },
82520c794b3Sgavinm 	{ 7, EMASK_UNCOR_PEX_IO7, PEX_NF_IO7 },
82620c794b3Sgavinm 	{ 6, EMASK_UNCOR_PEX_IO6, PEX_NF_IO6 },
82720c794b3Sgavinm 	{ 5, EMASK_UNCOR_PEX_IO5, PEX_NF_IO5 },
82820c794b3Sgavinm 	{ 4, EMASK_UNCOR_PEX_IO4, PEX_NF_IO4 },
82920c794b3Sgavinm 	{ 3, EMASK_UNCOR_PEX_IO3, PEX_NF_IO3 },
83020c794b3Sgavinm 	{ 0, EMASK_UNCOR_PEX_IO0, PEX_NF_IO0 }
83120c794b3Sgavinm };
83220c794b3Sgavinm 
8335f28a827Saf static struct mch_error_code uncor_pex_5400_error_code[] = {
8345f28a827Saf 	{ 33, EMASK_UNIT_PEX_IO33, PEX_5400_NF_IO33 },
8355f28a827Saf 	{ 32, EMASK_UNIT_PEX_IO32, PEX_5400_NF_IO32 },
8365f28a827Saf 	{ 31, EMASK_UNIT_PEX_IO31, PEX_5400_NF_IO31 },
8375f28a827Saf 	{ 30, EMASK_UNIT_PEX_IO30, PEX_5400_NF_IO30 },
8385f28a827Saf 	{ 29, EMASK_UNIT_PEX_IO29, PEX_5400_NF_IO29 },
8395f28a827Saf 	{ 28, EMASK_UNIT_PEX_IO28, PEX_5400_NF_IO28 },
8405f28a827Saf 	{ 27, EMASK_UNIT_PEX_IO27, PEX_5400_NF_IO27 },
8415f28a827Saf 	{ 26, EMASK_UNIT_PEX_IO26, PEX_5400_NF_IO26 },
8425f28a827Saf 	{ 25, EMASK_UNIT_PEX_IO25, PEX_5400_NF_IO25 },
8435f28a827Saf 	{ 24, EMASK_UNIT_PEX_IO24, PEX_5400_NF_IO24 },
8445f28a827Saf 	{ 23, EMASK_UNIT_PEX_IO23, PEX_5400_NF_IO23 },
8455f28a827Saf };
8465f28a827Saf 
84720c794b3Sgavinm static struct mch_error_code cor_pex_error_code[] = {
8485f28a827Saf 	{ 20, EMASK_COR_PEX_IO20, PEX_5400_NF_IO20 },
84920c794b3Sgavinm 	{ 16, EMASK_COR_PEX_IO16, PEX_NF_IO16 },
85020c794b3Sgavinm 	{ 15, EMASK_COR_PEX_IO15, PEX_NF_IO15 },
85120c794b3Sgavinm 	{ 14, EMASK_COR_PEX_IO14, PEX_NF_IO14 },
85220c794b3Sgavinm 	{ 13, EMASK_COR_PEX_IO13, PEX_NF_IO13 },
85320c794b3Sgavinm 	{ 12, EMASK_COR_PEX_IO12, PEX_NF_IO12 },
85420c794b3Sgavinm 	{ 10, 0, PEX_NF_IO10 },
85520c794b3Sgavinm 	{ 2, 0, PEX_NF_IO2 }
85620c794b3Sgavinm };
85720c794b3Sgavinm 
8585f28a827Saf static struct mch_error_code rp_pex_5400_error_code[] = {
8595f28a827Saf 	{ 17, EMASK_RP_PEX_IO17, PEX_5400_NF_IO17 },
8605f28a827Saf 	{ 11, EMASK_RP_PEX_IO11, PEX_5400_NF_IO11 }
8615f28a827Saf };
8625f28a827Saf 
8635f28a827Saf static struct mch_error_code cor_pex_5400_error_code1[] = {
8645f28a827Saf 	{ 19, EMASK_UNCOR_PEX_IO19, PEX_5400_NF_IO19 },
8655f28a827Saf 	{ 10, EMASK_UNCOR_PEX_IO10, PEX_5400_NF_IO10 },
8665f28a827Saf 	{ 9, EMASK_UNCOR_PEX_IO9, PEX_5400_NF_IO9 },
8675f28a827Saf 	{ 8, EMASK_UNCOR_PEX_IO8, PEX_5400_NF_IO8 },
8685f28a827Saf 	{ 7, EMASK_UNCOR_PEX_IO7, PEX_5400_NF_IO7 },
8695f28a827Saf 	{ 6, EMASK_UNCOR_PEX_IO6, PEX_5400_NF_IO6 },
8705f28a827Saf 	{ 5, EMASK_UNCOR_PEX_IO5, PEX_5400_NF_IO5 },
8715f28a827Saf 	{ 4, EMASK_UNCOR_PEX_IO4, PEX_5400_NF_IO4 },
8725f28a827Saf 	{ 2, EMASK_UNCOR_PEX_IO2, PEX_5400_NF_IO2 },
8735f28a827Saf 	{ 0, EMASK_UNCOR_PEX_IO0, PEX_5400_NF_IO0 }
8745f28a827Saf };
8755f28a827Saf 
8765f28a827Saf static struct mch_error_code cor_pex_5400_error_code2[] = {
8775f28a827Saf 	{ 20, EMASK_COR_PEX_IO20, PEX_5400_NF_IO20 },
8785f28a827Saf 	{ 16, EMASK_COR_PEX_IO16, PEX_5400_NF_IO16 },
8795f28a827Saf 	{ 15, EMASK_COR_PEX_IO15, PEX_5400_NF_IO15 },
8805f28a827Saf 	{ 14, EMASK_COR_PEX_IO14, PEX_5400_NF_IO14 },
8815f28a827Saf 	{ 13, EMASK_COR_PEX_IO13, PEX_5400_NF_IO13 },
8825f28a827Saf 	{ 12, EMASK_COR_PEX_IO12, PEX_5400_NF_IO12 }
8835f28a827Saf };
8845f28a827Saf 
8855f28a827Saf static struct mch_error_code cor_pex_5400_error_code3[] = {
8865f28a827Saf 	{ 33, EMASK_UNIT_PEX_IO33, PEX_5400_NF_IO33 },
8875f28a827Saf 	{ 32, EMASK_UNIT_PEX_IO32, PEX_5400_NF_IO32 },
8885f28a827Saf 	{ 31, EMASK_UNIT_PEX_IO31, PEX_5400_NF_IO31 },
8895f28a827Saf 	{ 30, EMASK_UNIT_PEX_IO30, PEX_5400_NF_IO30 },
8905f28a827Saf 	{ 29, EMASK_UNIT_PEX_IO29, PEX_5400_NF_IO29 },
8915f28a827Saf 	{ 28, EMASK_UNIT_PEX_IO28, PEX_5400_NF_IO28 },
8925f28a827Saf 	{ 27, EMASK_UNIT_PEX_IO27, PEX_5400_NF_IO27 },
8935f28a827Saf 	{ 26, EMASK_UNIT_PEX_IO26, PEX_5400_NF_IO26 },
8945f28a827Saf 	{ 25, EMASK_UNIT_PEX_IO25, PEX_5400_NF_IO25 },
8955f28a827Saf 	{ 24, EMASK_UNIT_PEX_IO24, PEX_5400_NF_IO24 },
8965f28a827Saf 	{ 23, EMASK_UNIT_PEX_IO23, PEX_5400_NF_IO23 }
8975f28a827Saf };
8985f28a827Saf 
89920c794b3Sgavinm static struct mch_error_code rp_pex_error_code[] = {
90020c794b3Sgavinm 	{ 17, EMASK_RP_PEX_IO17, PEX_NF_IO17 },
90120c794b3Sgavinm 	{ 11, EMASK_RP_PEX_IO11, PEX_NF_IO11 },
90220c794b3Sgavinm };
90320c794b3Sgavinm 
90420c794b3Sgavinm static int
intel_pex_err(uint32_t pex_fat,uint32_t pex_nf_cor)90520c794b3Sgavinm intel_pex_err(uint32_t pex_fat, uint32_t pex_nf_cor)
90620c794b3Sgavinm {
90720c794b3Sgavinm 	int rt = -1;
90820c794b3Sgavinm 	int nerr = 0;
90920c794b3Sgavinm 	int i;
91020c794b3Sgavinm 	int sz;
91120c794b3Sgavinm 
91220c794b3Sgavinm 	sz = sizeof (fat_pex_error_code) / sizeof (struct mch_error_code);
91320c794b3Sgavinm 
91420c794b3Sgavinm 	for (i = 0; i < sz; i++) {
91520c794b3Sgavinm 		if (pex_fat & fat_pex_error_code[i].error_bit) {
91620c794b3Sgavinm 			rt = fat_pex_error_code[i].intel_error_list;
91720c794b3Sgavinm 			nerr++;
91820c794b3Sgavinm 		}
91920c794b3Sgavinm 	}
92020c794b3Sgavinm 	sz = sizeof (fat_rp_error_code) / sizeof (struct mch_error_code);
92120c794b3Sgavinm 
92220c794b3Sgavinm 	for (i = 0; i < sz; i++) {
92320c794b3Sgavinm 		if (pex_fat & fat_rp_error_code[i].error_bit) {
92420c794b3Sgavinm 			rt = fat_rp_error_code[i].intel_error_list;
92520c794b3Sgavinm 			nerr++;
92620c794b3Sgavinm 		}
92720c794b3Sgavinm 	}
92820c794b3Sgavinm 	sz = sizeof (uncor_pex_error_code) / sizeof (struct mch_error_code);
92920c794b3Sgavinm 
93020c794b3Sgavinm 	for (i = 0; i < sz; i++) {
93120c794b3Sgavinm 		if (pex_nf_cor & uncor_pex_error_code[i].error_bit) {
93220c794b3Sgavinm 			rt = uncor_pex_error_code[i].intel_error_list;
93320c794b3Sgavinm 			nerr++;
93420c794b3Sgavinm 		}
93520c794b3Sgavinm 	}
93620c794b3Sgavinm 
93720c794b3Sgavinm 	sz = sizeof (cor_pex_error_code) / sizeof (struct mch_error_code);
93820c794b3Sgavinm 
93920c794b3Sgavinm 	for (i = 0; i < sz; i++) {
94020c794b3Sgavinm 		if (pex_nf_cor & cor_pex_error_code[i].error_bit) {
94120c794b3Sgavinm 			rt = cor_pex_error_code[i].intel_error_list;
94220c794b3Sgavinm 			nerr++;
94320c794b3Sgavinm 		}
94420c794b3Sgavinm 	}
94520c794b3Sgavinm 	sz = sizeof (rp_pex_error_code) / sizeof (struct mch_error_code);
94620c794b3Sgavinm 
94720c794b3Sgavinm 	for (i = 0; i < sz; i++) {
94820c794b3Sgavinm 		if (pex_nf_cor & rp_pex_error_code[i].error_bit) {
94920c794b3Sgavinm 			rt = rp_pex_error_code[i].intel_error_list;
95020c794b3Sgavinm 			nerr++;
95120c794b3Sgavinm 		}
95220c794b3Sgavinm 	}
95320c794b3Sgavinm 
95420c794b3Sgavinm 	if (nerr > 1)
95520c794b3Sgavinm 		rt = -1;
95620c794b3Sgavinm 	return (rt);
95720c794b3Sgavinm }
9585f28a827Saf 
9595f28a827Saf static struct mch_error_code fat_thr_error_code[] = {
9605f28a827Saf 	{ 2, EMASK_THR_F2, ERR_FAT_THR_F2 },
9615f28a827Saf 	{ 1, EMASK_THR_F1, ERR_FAT_THR_F1 }
9625f28a827Saf };
9635f28a827Saf 
9645f28a827Saf static struct mch_error_code nf_thr_error_code[] = {
9655f28a827Saf 	{ 5, EMASK_THR_F5, ERR_NF_THR_F5 },
9665f28a827Saf 	{ 4, EMASK_THR_F4, ERR_NF_THR_F4 },
9675f28a827Saf 	{ 3, EMASK_THR_F3, ERR_NF_THR_F3 }
9685f28a827Saf };
9695f28a827Saf 
9705f28a827Saf static int
intel_thr_err(uint8_t err_fat_thr,uint8_t err_nf_thr)9715f28a827Saf intel_thr_err(uint8_t err_fat_thr, uint8_t err_nf_thr)
9725f28a827Saf {
9735f28a827Saf 	int rt = -1;
9745f28a827Saf 	int nerr = 0;
9755f28a827Saf 	uint16_t emask_thr = 0;
9765f28a827Saf 	int i;
9775f28a827Saf 	int sz;
9785f28a827Saf 
9795f28a827Saf 	sz = sizeof (fat_thr_error_code) / sizeof (struct mch_error_code);
9805f28a827Saf 
9815f28a827Saf 	for (i = 0; i < sz; i++) {
9825f28a827Saf 		if (err_fat_thr & fat_thr_error_code[i].error_bit) {
9835f28a827Saf 			rt = fat_thr_error_code[i].intel_error_list;
9845f28a827Saf 			emask_thr |= fat_thr_error_code[i].emask;
9855f28a827Saf 			nerr++;
9865f28a827Saf 		}
9875f28a827Saf 	}
9885f28a827Saf 
9895f28a827Saf 	sz = sizeof (nf_thr_error_code) / sizeof (struct mch_error_code);
9905f28a827Saf 
9915f28a827Saf 	for (i = 0; i < sz; i++) {
9925f28a827Saf 		if (err_nf_thr & nf_thr_error_code[i].error_bit) {
9935f28a827Saf 			rt = nf_thr_error_code[i].intel_error_list;
9945f28a827Saf 			emask_thr |= nf_thr_error_code[i].emask;
9955f28a827Saf 			nerr++;
9965f28a827Saf 		}
9975f28a827Saf 	}
9985f28a827Saf 
9995f28a827Saf 	if (emask_thr)
10005f28a827Saf 		nb_thr_mask_mc(emask_thr);
10015f28a827Saf 	if (nerr > 1)
10025f28a827Saf 		rt = -1;
10035f28a827Saf 	return (rt);
10045f28a827Saf }
10055f28a827Saf 
10065f28a827Saf static int
intel_pex_5400_err(uint32_t pex_fat,uint32_t pex_nf_cor)10075f28a827Saf intel_pex_5400_err(uint32_t pex_fat, uint32_t pex_nf_cor)
10085f28a827Saf {
10095f28a827Saf 	int rt = -1;
10105f28a827Saf 	int nerr = 0;
10115f28a827Saf 	int i;
10125f28a827Saf 	int sz;
10135f28a827Saf 
10145f28a827Saf 	sz = sizeof (fat_pex_5400_error_code) / sizeof (struct mch_error_code);
10155f28a827Saf 
10165f28a827Saf 	for (i = 0; i < sz; i++) {
10175f28a827Saf 		if (pex_fat & fat_pex_5400_error_code[i].error_bit) {
10185f28a827Saf 			rt = fat_pex_5400_error_code[i].intel_error_list;
10195f28a827Saf 			nerr++;
10205f28a827Saf 		}
10215f28a827Saf 	}
10225f28a827Saf 	sz = sizeof (fat_rp_5400_error_code) / sizeof (struct mch_error_code);
10235f28a827Saf 
10245f28a827Saf 	for (i = 0; i < sz; i++) {
10255f28a827Saf 		if (pex_fat & fat_rp_5400_error_code[i].error_bit) {
10265f28a827Saf 			rt = fat_rp_5400_error_code[i].intel_error_list;
10275f28a827Saf 			nerr++;
10285f28a827Saf 		}
10295f28a827Saf 	}
10305f28a827Saf 	sz = sizeof (fat_unit_pex_5400_error_code) /
10315f28a827Saf 	    sizeof (struct mch_error_code);
10325f28a827Saf 
10335f28a827Saf 	for (i = 0; i < sz; i++) {
10345f28a827Saf 		if (pex_fat &
10355f28a827Saf 		    fat_unit_pex_5400_error_code[i].error_bit) {
10365f28a827Saf 			rt = fat_unit_pex_5400_error_code[i].intel_error_list;
10375f28a827Saf 			nerr++;
10385f28a827Saf 		}
10395f28a827Saf 	}
10405f28a827Saf 	sz = sizeof (uncor_pex_5400_error_code) /
10415f28a827Saf 	    sizeof (struct mch_error_code);
10425f28a827Saf 
10435f28a827Saf 	for (i = 0; i < sz; i++) {
10445f28a827Saf 		if (pex_fat & uncor_pex_5400_error_code[i].error_bit) {
10455f28a827Saf 			rt = uncor_pex_5400_error_code[i].intel_error_list;
10465f28a827Saf 			nerr++;
10475f28a827Saf 		}
10485f28a827Saf 	}
10495f28a827Saf 
10505f28a827Saf 	sz = sizeof (rp_pex_5400_error_code) / sizeof (struct mch_error_code);
10515f28a827Saf 
10525f28a827Saf 	for (i = 0; i < sz; i++) {
10535f28a827Saf 		if (pex_nf_cor & rp_pex_5400_error_code[i].error_bit) {
10545f28a827Saf 			rt = rp_pex_5400_error_code[i].intel_error_list;
10555f28a827Saf 			nerr++;
10565f28a827Saf 		}
10575f28a827Saf 	}
10585f28a827Saf 
10595f28a827Saf 	sz = sizeof (cor_pex_5400_error_code1) / sizeof (struct mch_error_code);
10605f28a827Saf 
10615f28a827Saf 	for (i = 0; i < sz; i++) {
10625f28a827Saf 		if (pex_nf_cor & cor_pex_5400_error_code1[i].error_bit) {
10635f28a827Saf 			rt = cor_pex_5400_error_code1[i].intel_error_list;
10645f28a827Saf 			nerr++;
10655f28a827Saf 		}
10665f28a827Saf 	}
10675f28a827Saf 
10685f28a827Saf 	sz = sizeof (cor_pex_5400_error_code2) / sizeof (struct mch_error_code);
10695f28a827Saf 
10705f28a827Saf 	for (i = 0; i < sz; i++) {
10715f28a827Saf 		if (pex_nf_cor & cor_pex_5400_error_code2[i].error_bit) {
10725f28a827Saf 			rt = cor_pex_5400_error_code2[i].intel_error_list;
10735f28a827Saf 			nerr++;
10745f28a827Saf 		}
10755f28a827Saf 	}
10765f28a827Saf 
10775f28a827Saf 	sz = sizeof (cor_pex_5400_error_code3) / sizeof (struct mch_error_code);
10785f28a827Saf 
10795f28a827Saf 	for (i = 0; i < sz; i++) {
10805f28a827Saf 		if (pex_nf_cor & cor_pex_5400_error_code3[i].error_bit) {
10815f28a827Saf 			rt = cor_pex_5400_error_code3[i].intel_error_list;
10825f28a827Saf 			nerr++;
10835f28a827Saf 		}
10845f28a827Saf 	}
10855f28a827Saf 
10865f28a827Saf 	if (nerr > 1)
10875f28a827Saf 		rt = -1;
10885f28a827Saf 	return (rt);
10895f28a827Saf }
10905f28a827Saf 
1091c84b7bbeSAdrian Frost static int
log_pex_err(uint64_t ferr,nb_regs_t * rp,int willpanic,int * interpose)10920ad0f0b2SAdrian Frost log_pex_err(uint64_t ferr, nb_regs_t *rp, int willpanic, int *interpose)
109320c794b3Sgavinm {
109420c794b3Sgavinm 	uint8_t pex = (uint8_t)-1;
109520c794b3Sgavinm 	int t = 0;
109620c794b3Sgavinm 
109720c794b3Sgavinm 	rp->flag = NB_REG_LOG_PEX;
109820c794b3Sgavinm 	pex = GE_ERR_PEX(ferr);
109920c794b3Sgavinm 
110020c794b3Sgavinm 	rp->nb.pex_regs.pex = pex;
110120c794b3Sgavinm 	rp->nb.pex_regs.pex_fat_ferr =  PEX_FAT_FERR_RD(pex, interpose);
110220c794b3Sgavinm 	rp->nb.pex_regs.pex_fat_nerr = PEX_FAT_NERR_RD(pex, &t);
110320c794b3Sgavinm 	*interpose |= t;
110420c794b3Sgavinm 	rp->nb.pex_regs.pex_nf_corr_ferr = PEX_NF_FERR_RD(pex, &t);
110520c794b3Sgavinm 	*interpose |= t;
110620c794b3Sgavinm 	rp->nb.pex_regs.pex_nf_corr_nerr = PEX_NF_NERR_RD(pex, &t);
110720c794b3Sgavinm 	*interpose |= t;
1108c84b7bbeSAdrian Frost 	if (rp->nb.pex_regs.pex_fat_ferr == 0 &&
1109c84b7bbeSAdrian Frost 	    rp->nb.pex_regs.pex_fat_nerr == 0 &&
1110c84b7bbeSAdrian Frost 	    rp->nb.pex_regs.pex_nf_corr_ferr == 0 &&
1111c84b7bbeSAdrian Frost 	    rp->nb.pex_regs.pex_nf_corr_nerr == 0)
1112c84b7bbeSAdrian Frost 		return (0);
111320c794b3Sgavinm 	rp->nb.pex_regs.uncerrsev = UNCERRSEV_RD(pex);
111420c794b3Sgavinm 	rp->nb.pex_regs.rperrsts = RPERRSTS_RD(pex);
111520c794b3Sgavinm 	rp->nb.pex_regs.rperrsid = RPERRSID_RD(pex);
111620c794b3Sgavinm 	if (pex != (uint8_t)-1)
111720c794b3Sgavinm 		rp->nb.pex_regs.uncerrsts = UNCERRSTS_RD(pex);
111820c794b3Sgavinm 	else
111920c794b3Sgavinm 		rp->nb.pex_regs.uncerrsts = 0;
112020c794b3Sgavinm 	rp->nb.pex_regs.aerrcapctrl = AERRCAPCTRL_RD(pex);
112120c794b3Sgavinm 	rp->nb.pex_regs.corerrsts = CORERRSTS_RD(pex);
112220c794b3Sgavinm 	rp->nb.pex_regs.pexdevsts = PEXDEVSTS_RD(pex);
112320c794b3Sgavinm 
11240ad0f0b2SAdrian Frost 	if (!willpanic) {
11250ad0f0b2SAdrian Frost 		if (rp->nb.pex_regs.pex_fat_ferr || *interpose)
11260ad0f0b2SAdrian Frost 			PEX_FAT_FERR_WR(pex, rp->nb.pex_regs.pex_fat_ferr);
11270ad0f0b2SAdrian Frost 		if (rp->nb.pex_regs.pex_fat_nerr)
11280ad0f0b2SAdrian Frost 			PEX_FAT_NERR_WR(pex, rp->nb.pex_regs.pex_fat_nerr);
11290ad0f0b2SAdrian Frost 		if (rp->nb.pex_regs.pex_nf_corr_ferr || *interpose)
11300ad0f0b2SAdrian Frost 			PEX_NF_FERR_WR(pex, rp->nb.pex_regs.pex_nf_corr_ferr);
11310ad0f0b2SAdrian Frost 		if (rp->nb.pex_regs.pex_nf_corr_nerr)
11320ad0f0b2SAdrian Frost 			PEX_NF_NERR_WR(pex, rp->nb.pex_regs.pex_nf_corr_nerr);
11330ad0f0b2SAdrian Frost 		if (*interpose)
11340ad0f0b2SAdrian Frost 			UNCERRSTS_WR(pex, rp->nb.pex_regs.uncerrsts);
11350ad0f0b2SAdrian Frost 		if (*interpose)
11360ad0f0b2SAdrian Frost 			RPERRSTS_WR(pex, rp->nb.pex_regs.rperrsts);
11370ad0f0b2SAdrian Frost 		if (*interpose)
11380ad0f0b2SAdrian Frost 			PEXDEVSTS_WR(pex, 0);
11390ad0f0b2SAdrian Frost 	}
1140c84b7bbeSAdrian Frost 	return (1);
114120c794b3Sgavinm }
114220c794b3Sgavinm 
114320c794b3Sgavinm static void
log_fat_fbd_err(nb_regs_t * rp,int willpanic,int * interpose)11440ad0f0b2SAdrian Frost log_fat_fbd_err(nb_regs_t *rp, int willpanic, int *interpose)
114520c794b3Sgavinm {
114620c794b3Sgavinm 	int channel, branch;
114720c794b3Sgavinm 	int t = 0;
114820c794b3Sgavinm 
114920c794b3Sgavinm 	rp->flag = NB_REG_LOG_FAT_FBD;
115020c794b3Sgavinm 	rp->nb.fat_fbd_regs.ferr_fat_fbd = FERR_FAT_FBD_RD(interpose);
115120c794b3Sgavinm 	channel = (rp->nb.fat_fbd_regs.ferr_fat_fbd >> 28) & 3;
115220c794b3Sgavinm 	branch = channel >> 1;
115320c794b3Sgavinm 	rp->nb.fat_fbd_regs.nerr_fat_fbd = NERR_FAT_FBD_RD(&t);
115420c794b3Sgavinm 	*interpose |= t;
11555f28a827Saf 	rp->nb.fat_fbd_regs.nrecmema = NRECMEMA_RD(branch);
11565f28a827Saf 	rp->nb.fat_fbd_regs.nrecmemb = NRECMEMB_RD(branch);
11575f28a827Saf 	rp->nb.fat_fbd_regs.nrecfglog = NRECFGLOG_RD(branch);
11585f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbda = NRECFBDA_RD(branch);
11595f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbdb = NRECFBDB_RD(branch);
11605f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbdc = NRECFBDC_RD(branch);
11615f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbdd = NRECFBDD_RD(branch);
11625f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbde = NRECFBDE_RD(branch);
11635f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbdf = NRECFBDF_RD(branch);
116420c794b3Sgavinm 	rp->nb.fat_fbd_regs.spcps = SPCPS_RD(branch);
116520c794b3Sgavinm 	rp->nb.fat_fbd_regs.spcpc = SPCPC_RD(branch);
116620c794b3Sgavinm 	rp->nb.fat_fbd_regs.uerrcnt = UERRCNT_RD(branch);
116720c794b3Sgavinm 	rp->nb.fat_fbd_regs.uerrcnt_last = uerrcnt[branch];
116820c794b3Sgavinm 	uerrcnt[branch] = rp->nb.fat_fbd_regs.uerrcnt;
116920c794b3Sgavinm 	rp->nb.fat_fbd_regs.badrama = BADRAMA_RD(branch);
117020c794b3Sgavinm 	rp->nb.fat_fbd_regs.badramb = BADRAMB_RD(branch);
117120c794b3Sgavinm 	rp->nb.fat_fbd_regs.badcnt = BADCNT_RD(branch);
11720ad0f0b2SAdrian Frost 	if (!willpanic) {
11730ad0f0b2SAdrian Frost 		if (rp->nb.fat_fbd_regs.ferr_fat_fbd || *interpose)
11740ad0f0b2SAdrian Frost 			FERR_FAT_FBD_WR(rp->nb.fat_fbd_regs.ferr_fat_fbd);
11750ad0f0b2SAdrian Frost 		if (rp->nb.fat_fbd_regs.nerr_fat_fbd)
11760ad0f0b2SAdrian Frost 			NERR_FAT_FBD_WR(rp->nb.fat_fbd_regs.nerr_fat_fbd);
11770ad0f0b2SAdrian Frost 		/*
11780ad0f0b2SAdrian Frost 		 * if interpose write read-only registers to clear from pcii
11790ad0f0b2SAdrian Frost 		 * cache
11800ad0f0b2SAdrian Frost 		 */
11810ad0f0b2SAdrian Frost 		if (*interpose) {
11820ad0f0b2SAdrian Frost 			NRECMEMA_WR(branch);
11830ad0f0b2SAdrian Frost 			NRECMEMB_WR(branch);
11840ad0f0b2SAdrian Frost 			NRECFGLOG_WR(branch);
11850ad0f0b2SAdrian Frost 			NRECFBDA_WR(branch);
11860ad0f0b2SAdrian Frost 			NRECFBDB_WR(branch);
11870ad0f0b2SAdrian Frost 			NRECFBDC_WR(branch);
11880ad0f0b2SAdrian Frost 			NRECFBDD_WR(branch);
11890ad0f0b2SAdrian Frost 			NRECFBDE_WR(branch);
11900ad0f0b2SAdrian Frost 			NRECFBDF_WR(branch);
11910ad0f0b2SAdrian Frost 		}
119220c794b3Sgavinm 	}
119320c794b3Sgavinm }
119420c794b3Sgavinm 
119520c794b3Sgavinm static void
log_nf_fbd_err(nb_regs_t * rp,int willpanic,int * interpose)11960ad0f0b2SAdrian Frost log_nf_fbd_err(nb_regs_t *rp, int willpanic, int *interpose)
119720c794b3Sgavinm {
119820c794b3Sgavinm 	int channel, branch;
119920c794b3Sgavinm 	int t = 0;
120020c794b3Sgavinm 
120120c794b3Sgavinm 	rp->flag = NB_REG_LOG_NF_FBD;
120220c794b3Sgavinm 	rp->nb.nf_fbd_regs.ferr_nf_fbd = FERR_NF_FBD_RD(interpose);
120320c794b3Sgavinm 	channel = (rp->nb.nf_fbd_regs.ferr_nf_fbd >> 28) & 3;
120420c794b3Sgavinm 	branch = channel >> 1;
120520c794b3Sgavinm 	rp->nb.nf_fbd_regs.nerr_nf_fbd = NERR_NF_FBD_RD(&t);
120620c794b3Sgavinm 	*interpose |= t;
120720c794b3Sgavinm 	rp->nb.nf_fbd_regs.redmemb = REDMEMB_RD();
12085f28a827Saf 	rp->nb.nf_fbd_regs.recmema = RECMEMA_RD(branch);
12095f28a827Saf 	rp->nb.nf_fbd_regs.recmemb = RECMEMB_RD(branch);
12105f28a827Saf 	rp->nb.nf_fbd_regs.recfglog = RECFGLOG_RD(branch);
12115f28a827Saf 	rp->nb.nf_fbd_regs.recfbda = RECFBDA_RD(branch);
12125f28a827Saf 	rp->nb.nf_fbd_regs.recfbdb = RECFBDB_RD(branch);
12135f28a827Saf 	rp->nb.nf_fbd_regs.recfbdc = RECFBDC_RD(branch);
12145f28a827Saf 	rp->nb.nf_fbd_regs.recfbdd = RECFBDD_RD(branch);
12155f28a827Saf 	rp->nb.nf_fbd_regs.recfbde = RECFBDE_RD(branch);
12165f28a827Saf 	rp->nb.nf_fbd_regs.recfbdf = RECFBDF_RD(branch);
121720c794b3Sgavinm 	rp->nb.nf_fbd_regs.spcps = SPCPS_RD(branch);
121820c794b3Sgavinm 	rp->nb.nf_fbd_regs.spcpc = SPCPC_RD(branch);
12195f28a827Saf 	if (nb_chipset == INTEL_NB_7300 || nb_chipset == INTEL_NB_5400) {
12205f28a827Saf 		rp->nb.nf_fbd_regs.cerrcnta = CERRCNTA_RD(branch, channel);
12215f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntb = CERRCNTB_RD(branch, channel);
12225f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntc = CERRCNTC_RD(branch, channel);
12235f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntd = CERRCNTD_RD(branch, channel);
12245f28a827Saf 	} else {
12255f28a827Saf 		rp->nb.nf_fbd_regs.cerrcnta = CERRCNT_RD(branch);
12265f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntb = 0;
12275f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntc = 0;
12285f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntd = 0;
12295f28a827Saf 	}
12305f28a827Saf 	rp->nb.nf_fbd_regs.cerrcnta_last = cerrcnta[branch][channel & 1];
12315f28a827Saf 	rp->nb.nf_fbd_regs.cerrcntb_last = cerrcntb[branch][channel & 1];
12325f28a827Saf 	rp->nb.nf_fbd_regs.cerrcntc_last = cerrcntc[branch][channel & 1];
12335f28a827Saf 	rp->nb.nf_fbd_regs.cerrcntd_last = cerrcntd[branch][channel & 1];
12345f28a827Saf 	cerrcnta[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcnta;
12355f28a827Saf 	cerrcntb[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntb;
12365f28a827Saf 	cerrcntc[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntc;
12375f28a827Saf 	cerrcntd[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntd;
123820c794b3Sgavinm 	rp->nb.nf_fbd_regs.badrama = BADRAMA_RD(branch);
123920c794b3Sgavinm 	rp->nb.nf_fbd_regs.badramb = BADRAMB_RD(branch);
124020c794b3Sgavinm 	rp->nb.nf_fbd_regs.badcnt = BADCNT_RD(branch);
12410ad0f0b2SAdrian Frost 	if (!willpanic) {
12420ad0f0b2SAdrian Frost 		if (rp->nb.nf_fbd_regs.ferr_nf_fbd || *interpose)
12430ad0f0b2SAdrian Frost 			FERR_NF_FBD_WR(rp->nb.nf_fbd_regs.ferr_nf_fbd);
12440ad0f0b2SAdrian Frost 		if (rp->nb.nf_fbd_regs.nerr_nf_fbd)
12450ad0f0b2SAdrian Frost 			NERR_NF_FBD_WR(rp->nb.nf_fbd_regs.nerr_nf_fbd);
12460ad0f0b2SAdrian Frost 		/*
12470ad0f0b2SAdrian Frost 		 * if interpose write read-only registers to clear from pcii
12480ad0f0b2SAdrian Frost 		 * cache
12490ad0f0b2SAdrian Frost 		 */
12500ad0f0b2SAdrian Frost 		if (*interpose) {
12510ad0f0b2SAdrian Frost 			RECMEMA_WR(branch);
12520ad0f0b2SAdrian Frost 			RECMEMB_WR(branch);
12530ad0f0b2SAdrian Frost 			RECFGLOG_WR(branch);
12540ad0f0b2SAdrian Frost 			RECFBDA_WR(branch);
12550ad0f0b2SAdrian Frost 			RECFBDB_WR(branch);
12560ad0f0b2SAdrian Frost 			RECFBDC_WR(branch);
12570ad0f0b2SAdrian Frost 			RECFBDD_WR(branch);
12580ad0f0b2SAdrian Frost 			RECFBDE_WR(branch);
12590ad0f0b2SAdrian Frost 			RECFBDF_WR(branch);
12600ad0f0b2SAdrian Frost 			SPCPS_WR(branch);
12610ad0f0b2SAdrian Frost 		}
126220c794b3Sgavinm 	}
126320c794b3Sgavinm }
126420c794b3Sgavinm 
1265a643d9fdSVuong Nguyen static int
log_nf_mem_err(nb_regs_t * rp,int willpanic,int * interpose)126685738508SVuong Nguyen log_nf_mem_err(nb_regs_t *rp, int willpanic, int *interpose)
126785738508SVuong Nguyen {
126885738508SVuong Nguyen 	int channel, branch;
126985738508SVuong Nguyen 	int t = 0;
1270a643d9fdSVuong Nguyen 	int rt = 0;
127185738508SVuong Nguyen 
127285738508SVuong Nguyen 	rp->flag = NB_REG_LOG_NF_MEM;
127385738508SVuong Nguyen 
127485738508SVuong Nguyen 	/* Memmory err registers */
127585738508SVuong Nguyen 	rp->nb.nf_mem_regs.ferr_nf_mem = FERR_NF_MEM_RD(interpose);
127685738508SVuong Nguyen 	channel = (rp->nb.nf_mem_regs.ferr_nf_mem >> 28) & 0x1;
127785738508SVuong Nguyen 	branch = channel;
127885738508SVuong Nguyen 	rp->nb.nf_mem_regs.nerr_nf_mem = NERR_NF_MEM_RD(&t);
127985738508SVuong Nguyen 	*interpose |= t;
128085738508SVuong Nguyen 	rp->nb.nf_mem_regs.redmema = MEM_REDMEMA_RD(branch);
128185738508SVuong Nguyen 	rp->nb.nf_mem_regs.redmemb = MEM_REDMEMB_RD(branch);
128285738508SVuong Nguyen 	rp->nb.nf_mem_regs.recmema = MEM_RECMEMA_RD(branch);
128385738508SVuong Nguyen 	rp->nb.nf_mem_regs.recmemb = MEM_RECMEMB_RD(branch);
128485738508SVuong Nguyen 	rp->nb.nf_mem_regs.nrecmema = MEM_NRECMEMA_RD(branch);
128585738508SVuong Nguyen 	rp->nb.nf_mem_regs.nrecmemb = MEM_NRECMEMB_RD(branch);
128685738508SVuong Nguyen 
128785738508SVuong Nguyen 	/* spare rank */
128885738508SVuong Nguyen 	rp->nb.nf_mem_regs.spcps = SPCPS_RD(branch);
128985738508SVuong Nguyen 	rp->nb.nf_mem_regs.spcpc = SPCPC_RD(branch);
129085738508SVuong Nguyen 
129185738508SVuong Nguyen 	/* RAS registers */
129285738508SVuong Nguyen 	rp->nb.nf_mem_regs.cerrcnt = MEM_CERRCNT_RD(branch);
129385738508SVuong Nguyen 	rp->nb.nf_mem_regs.cerrcnt_ext = (uint32_t)MEM_CERRCNT_EXT_RD(branch);
129485738508SVuong Nguyen 	rp->nb.nf_mem_regs.cerrcnt_last = cerrcnta[branch][channel & 1];
129585738508SVuong Nguyen 	rp->nb.nf_mem_regs.cerrcnt_ext_last = cerrcntb[branch][channel & 1];
129685738508SVuong Nguyen 	cerrcnta[branch][channel & 1] = rp->nb.nf_mem_regs.cerrcnt;
129785738508SVuong Nguyen 	cerrcntb[branch][channel & 1] = rp->nb.nf_mem_regs.cerrcnt_ext;
129885738508SVuong Nguyen 	rp->nb.nf_mem_regs.badram = BADRAMA_RD(branch);
129985738508SVuong Nguyen 	rp->nb.nf_mem_regs.badcnt = BADCNT_RD(branch);
130085738508SVuong Nguyen 	rp->nb.nf_mem_regs.validlog = VALIDLOG_RD(branch);
130185738508SVuong Nguyen 
130285738508SVuong Nguyen 	if (!willpanic) {
130385738508SVuong Nguyen 		if (rp->nb.nf_mem_regs.ferr_nf_mem || *interpose)
130485738508SVuong Nguyen 			FERR_NF_MEM_WR(rp->nb.nf_mem_regs.ferr_nf_mem);
130585738508SVuong Nguyen 		if (rp->nb.nf_mem_regs.nerr_nf_mem)
130685738508SVuong Nguyen 			NERR_NF_MEM_WR(rp->nb.nf_mem_regs.nerr_nf_mem);
130785738508SVuong Nguyen 		/*
130885738508SVuong Nguyen 		 * if interpose, write read-only registers to clear from pci
130985738508SVuong Nguyen 		 * cache
131085738508SVuong Nguyen 		 */
131185738508SVuong Nguyen 		if (*interpose) {
131285738508SVuong Nguyen 			MEM_NRECMEMA_WR(branch);
131385738508SVuong Nguyen 			MEM_NRECMEMB_WR(branch);
131485738508SVuong Nguyen 			MEM_REDMEMA_WR(branch);
131585738508SVuong Nguyen 			MEM_REDMEMB_WR(branch);
131685738508SVuong Nguyen 			MEM_RECMEMA_WR(branch);
131785738508SVuong Nguyen 			MEM_RECMEMB_WR(branch);
131885738508SVuong Nguyen 			SPCPS_WR(branch);
131985738508SVuong Nguyen 		}
132085738508SVuong Nguyen 	}
1321a643d9fdSVuong Nguyen 	if (nb_mode == NB_MEMORY_SINGLE_CHANNEL && channel != 0) {
1322a643d9fdSVuong Nguyen 		/*
1323a643d9fdSVuong Nguyen 		 * In the single channel mode, all dimms are on the channel 0.
1324a643d9fdSVuong Nguyen 		 * Invalidate this error if the channel number is invalid.
1325a643d9fdSVuong Nguyen 		 */
1326a643d9fdSVuong Nguyen 		rt = 1;
1327a643d9fdSVuong Nguyen 	}
1328a643d9fdSVuong Nguyen 	return (rt);
132985738508SVuong Nguyen }
133085738508SVuong Nguyen 
133120c794b3Sgavinm static void
log_ferr(uint64_t ferr,uint32_t * nerrp,nb_logout_t * log,int willpanic)133220c794b3Sgavinm log_ferr(uint64_t ferr, uint32_t *nerrp, nb_logout_t *log, int willpanic)
133320c794b3Sgavinm {
133420c794b3Sgavinm 	nb_regs_t *rp = &log->nb_regs;
133520c794b3Sgavinm 	uint32_t nerr = *nerrp;
133620c794b3Sgavinm 	int interpose = 0;
13379ff4cbe7SAdrian Frost 	int spurious = 0;
133820c794b3Sgavinm 
133920c794b3Sgavinm 	log->acl_timestamp = gethrtime_waitfree();
134020c794b3Sgavinm 	if ((ferr & (GE_PCIEX_FATAL | GE_PCIEX_NF)) != 0) {
134120c794b3Sgavinm 		*nerrp = nerr & ~(GE_PCIEX_FATAL | GE_PCIEX_NF);
1342c84b7bbeSAdrian Frost 		if (log_pex_err(ferr, rp, willpanic, &interpose) == 0)
1343c84b7bbeSAdrian Frost 			return;
134420c794b3Sgavinm 	} else if ((ferr & GE_FBD_FATAL) != 0) {
13450ad0f0b2SAdrian Frost 		log_fat_fbd_err(rp, willpanic, &interpose);
134620c794b3Sgavinm 		*nerrp = nerr & ~GE_NERR_FBD_FATAL;
134720c794b3Sgavinm 	} else if ((ferr & GE_FBD_NF) != 0) {
13480ad0f0b2SAdrian Frost 		log_nf_fbd_err(rp, willpanic, &interpose);
134920c794b3Sgavinm 		*nerrp = nerr & ~GE_NERR_FBD_NF;
135085738508SVuong Nguyen 	} else if ((ferr & GE_MEM_NF) != 0) {
1351a643d9fdSVuong Nguyen 		spurious = log_nf_mem_err(rp, willpanic, &interpose);
135285738508SVuong Nguyen 		*nerrp = nerr & ~GE_NERR_MEM_NF;
135320c794b3Sgavinm 	} else if ((ferr & (GE_FERR_FSB_FATAL | GE_FERR_FSB_NF)) != 0) {
13540ad0f0b2SAdrian Frost 		log_fsb_err(ferr, rp, willpanic, &interpose);
135520c794b3Sgavinm 		*nerrp = nerr & ~(GE_NERR_FSB_FATAL | GE_NERR_FSB_NF);
135620c794b3Sgavinm 	} else if ((ferr & (GE_DMA_FATAL | GE_DMA_NF)) != 0) {
135720c794b3Sgavinm 		log_dma_err(rp, &interpose);
135820c794b3Sgavinm 		*nerrp = nerr & ~(GE_DMA_FATAL | GE_DMA_NF);
135920c794b3Sgavinm 	} else if ((ferr & (GE_INT_FATAL | GE_INT_NF)) != 0) {
13600ad0f0b2SAdrian Frost 		spurious = log_int_err(rp, willpanic, &interpose);
136120c794b3Sgavinm 		*nerrp = nerr & ~(GE_INT_FATAL | GE_INT_NF);
13625f28a827Saf 	} else if (nb_chipset == INTEL_NB_5400 &&
13635f28a827Saf 	    (ferr & (GE_FERR_THERMAL_FATAL | GE_FERR_THERMAL_NF)) != 0) {
13640ad0f0b2SAdrian Frost 		log_thermal_err(rp, willpanic, &interpose);
13655f28a827Saf 		*nerrp = nerr & ~(GE_FERR_THERMAL_FATAL | GE_FERR_THERMAL_NF);
136620c794b3Sgavinm 	}
136720c794b3Sgavinm 	if (interpose)
136820c794b3Sgavinm 		log->type = "inject";
136920c794b3Sgavinm 	else
137020c794b3Sgavinm 		log->type = "error";
13719ff4cbe7SAdrian Frost 	if (!spurious) {
13729ff4cbe7SAdrian Frost 		errorq_dispatch(nb_queue, log, sizeof (nb_logout_t),
13739ff4cbe7SAdrian Frost 		    willpanic ? ERRORQ_SYNC : ERRORQ_ASYNC);
13749ff4cbe7SAdrian Frost 	}
137520c794b3Sgavinm }
137620c794b3Sgavinm 
137720c794b3Sgavinm static void
log_nerr(uint32_t * errp,nb_logout_t * log,int willpanic)137820c794b3Sgavinm log_nerr(uint32_t *errp, nb_logout_t *log, int willpanic)
137920c794b3Sgavinm {
138020c794b3Sgavinm 	uint32_t err;
138120c794b3Sgavinm 	nb_regs_t *rp = &log->nb_regs;
138220c794b3Sgavinm 	int interpose = 0;
13839ff4cbe7SAdrian Frost 	int spurious = 0;
138420c794b3Sgavinm 
138520c794b3Sgavinm 	err = *errp;
138620c794b3Sgavinm 	log->acl_timestamp = gethrtime_waitfree();
138720c794b3Sgavinm 	if ((err & (GE_PCIEX_FATAL | GE_PCIEX_NF)) != 0) {
138820c794b3Sgavinm 		*errp = err & ~(GE_PCIEX_FATAL | GE_PCIEX_NF);
1389c84b7bbeSAdrian Frost 		if (log_pex_err(err, rp, willpanic, &interpose) == 0)
1390c84b7bbeSAdrian Frost 			return;
139120c794b3Sgavinm 	} else if ((err & GE_NERR_FBD_FATAL) != 0) {
13920ad0f0b2SAdrian Frost 		log_fat_fbd_err(rp, willpanic, &interpose);
139320c794b3Sgavinm 		*errp = err & ~GE_NERR_FBD_FATAL;
139420c794b3Sgavinm 	} else if ((err & GE_NERR_FBD_NF) != 0) {
13950ad0f0b2SAdrian Frost 		log_nf_fbd_err(rp, willpanic, &interpose);
139620c794b3Sgavinm 		*errp = err & ~GE_NERR_FBD_NF;
139785738508SVuong Nguyen 	} else if ((err & GE_NERR_MEM_NF) != 0) {
1398a643d9fdSVuong Nguyen 		spurious = log_nf_mem_err(rp, willpanic, &interpose);
139985738508SVuong Nguyen 		*errp = err & ~GE_NERR_MEM_NF;
140020c794b3Sgavinm 	} else if ((err & (GE_NERR_FSB_FATAL | GE_NERR_FSB_NF)) != 0) {
14010ad0f0b2SAdrian Frost 		log_fsb_err(GE_NERR_TO_FERR_FSB(err), rp, willpanic,
14020ad0f0b2SAdrian Frost 		    &interpose);
140320c794b3Sgavinm 		*errp = err & ~(GE_NERR_FSB_FATAL | GE_NERR_FSB_NF);
140420c794b3Sgavinm 	} else if ((err & (GE_DMA_FATAL | GE_DMA_NF)) != 0) {
140520c794b3Sgavinm 		log_dma_err(rp, &interpose);
140620c794b3Sgavinm 		*errp = err & ~(GE_DMA_FATAL | GE_DMA_NF);
140720c794b3Sgavinm 	} else if ((err & (GE_INT_FATAL | GE_INT_NF)) != 0) {
14080ad0f0b2SAdrian Frost 		spurious = log_int_err(rp, willpanic, &interpose);
140920c794b3Sgavinm 		*errp = err & ~(GE_INT_FATAL | GE_INT_NF);
141020c794b3Sgavinm 	}
141120c794b3Sgavinm 	if (interpose)
141220c794b3Sgavinm 		log->type = "inject";
141320c794b3Sgavinm 	else
141420c794b3Sgavinm 		log->type = "error";
14159ff4cbe7SAdrian Frost 	if (!spurious) {
14169ff4cbe7SAdrian Frost 		errorq_dispatch(nb_queue, log, sizeof (nb_logout_t),
14179ff4cbe7SAdrian Frost 		    willpanic ? ERRORQ_SYNC : ERRORQ_ASYNC);
14189ff4cbe7SAdrian Frost 	}
141920c794b3Sgavinm }
142020c794b3Sgavinm 
142120c794b3Sgavinm /*ARGSUSED*/
142220c794b3Sgavinm void
nb_error_trap(cmi_hdl_t hdl,boolean_t ismc,boolean_t willpanic)142320c794b3Sgavinm nb_error_trap(cmi_hdl_t hdl, boolean_t ismc, boolean_t willpanic)
142420c794b3Sgavinm {
142520c794b3Sgavinm 	uint64_t ferr;
142620c794b3Sgavinm 	uint32_t nerr, err;
142720c794b3Sgavinm 	int nmc = 0;
142820c794b3Sgavinm 	int i;
142920c794b3Sgavinm 
143020c794b3Sgavinm 	if (mutex_tryenter(&nb_mutex) == 0)
143120c794b3Sgavinm 		return;
143220c794b3Sgavinm 
143320c794b3Sgavinm 	nerr = NERR_GLOBAL_RD();
143420c794b3Sgavinm 	err = nerr;
143520c794b3Sgavinm 	for (i = 0; i < NB_MAX_ERRORS; i++) {
143620c794b3Sgavinm 		ferr = FERR_GLOBAL_RD();
143720c794b3Sgavinm 		nb_log.nb_regs.chipset = nb_chipset;
143820c794b3Sgavinm 		nb_log.nb_regs.ferr = ferr;
143920c794b3Sgavinm 		nb_log.nb_regs.nerr = nerr;
144020c794b3Sgavinm 		if (ferr) {
144120c794b3Sgavinm 			log_ferr(ferr, &err, &nb_log, willpanic);
144220c794b3Sgavinm 			FERR_GLOBAL_WR(ferr);
144320c794b3Sgavinm 			nmc++;
144420c794b3Sgavinm 		} else if (err) {
144520c794b3Sgavinm 			log_nerr(&err, &nb_log, willpanic);
144620c794b3Sgavinm 			nmc++;
144720c794b3Sgavinm 		}
144820c794b3Sgavinm 	}
144920c794b3Sgavinm 	if (nerr) {
145020c794b3Sgavinm 		NERR_GLOBAL_WR(nerr);
145120c794b3Sgavinm 	}
145220c794b3Sgavinm 	if (nmc == 0 && nb_mask_mc_set)
145320c794b3Sgavinm 		nb_mask_mc_reset();
145420c794b3Sgavinm 	mutex_exit(&nb_mutex);
145520c794b3Sgavinm }
145620c794b3Sgavinm 
145720c794b3Sgavinm static void
nb_fsb_err_payload(const nb_regs_t * nb_regs,nvlist_t * payload,nb_scatchpad_t * data)145820c794b3Sgavinm nb_fsb_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
145920c794b3Sgavinm     nb_scatchpad_t *data)
146020c794b3Sgavinm {
146120c794b3Sgavinm 	int intel_error_list;
146220c794b3Sgavinm 	char buf[32];
146320c794b3Sgavinm 
146420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FSB,
146520c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.fsb, NULL);
146620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_FSB,
146720c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.ferr_fat_fsb, NULL);
146820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_FSB,
146920c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.nerr_fat_fsb, NULL);
147020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_FSB,
147120c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.ferr_nf_fsb, NULL);
147220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_FSB,
147320c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.nerr_nf_fsb, NULL);
147420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFSB,
147520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fsb_regs.nrecfsb, NULL);
147620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFSB_ADDR,
147720c794b3Sgavinm 	    DATA_TYPE_UINT64, nb_regs->nb.fsb_regs.nrecfsb_addr, NULL);
147820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFSB,
147920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fsb_regs.recfsb, NULL);
148020c794b3Sgavinm 	intel_error_list = data->intel_error_list;
148120c794b3Sgavinm 	if (intel_error_list >= 0)
148220c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "F%d", intel_error_list);
148320c794b3Sgavinm 	else
148420c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
148520c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
148620c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
148720c794b3Sgavinm }
148820c794b3Sgavinm 
148920c794b3Sgavinm static void
nb_pex_err_payload(const nb_regs_t * nb_regs,nvlist_t * payload,nb_scatchpad_t * data)149020c794b3Sgavinm nb_pex_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
149120c794b3Sgavinm     nb_scatchpad_t *data)
149220c794b3Sgavinm {
149320c794b3Sgavinm 	int intel_error_list;
149420c794b3Sgavinm 	char buf[32];
149520c794b3Sgavinm 
149620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX,
149720c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.pex_regs.pex, NULL);
149820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_FAT_FERR,
149920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_fat_ferr, NULL);
150020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_FAT_NERR,
150120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_fat_nerr, NULL);
150220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_NF_CORR_FERR,
150320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_nf_corr_ferr, NULL);
150420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_NF_CORR_NERR,
150520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_nf_corr_nerr, NULL);
150620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UNCERRSEV,
150720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.uncerrsev, NULL);
150820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RPERRSTS,
150920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.rperrsts, NULL);
151020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RPERRSID,
151120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.rperrsid, NULL);
151220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UNCERRSTS,
151320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.uncerrsts, NULL);
151420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_AERRCAPCTRL,
151520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.aerrcapctrl, NULL);
151620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CORERRSTS,
151720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.corerrsts, NULL);
151820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEXDEVSTS,
151920c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.pex_regs.pexdevsts, NULL);
152020c794b3Sgavinm 	intel_error_list = data->intel_error_list;
152120c794b3Sgavinm 	if (intel_error_list >= 0)
152220c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "IO%d", intel_error_list);
152320c794b3Sgavinm 	else
152420c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
152520c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
152620c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
152720c794b3Sgavinm }
152820c794b3Sgavinm 
152920c794b3Sgavinm static void
nb_int_err_payload(const nb_regs_t * nb_regs,nvlist_t * payload,nb_scatchpad_t * data)153020c794b3Sgavinm nb_int_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
153120c794b3Sgavinm     nb_scatchpad_t *data)
153220c794b3Sgavinm {
153320c794b3Sgavinm 	int intel_error_list;
153420c794b3Sgavinm 	char buf[32];
153520c794b3Sgavinm 
153620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_INT,
15375f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.int_regs.ferr_fat_int, NULL);
153820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_INT,
15395f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.int_regs.ferr_nf_int, NULL);
154020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_INT,
15415f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.int_regs.nerr_fat_int, NULL);
154220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_INT,
15435f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.int_regs.nerr_nf_int, NULL);
154420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECINT,
154520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.int_regs.nrecint, NULL);
154620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECINT,
154720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.int_regs.recint, NULL);
154820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECSF,
154920c794b3Sgavinm 	    DATA_TYPE_UINT64, nb_regs->nb.int_regs.nrecsf, NULL);
155020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECSF,
155120c794b3Sgavinm 	    DATA_TYPE_UINT64, nb_regs->nb.int_regs.recsf, NULL);
155220c794b3Sgavinm 	intel_error_list = data->intel_error_list;
155320c794b3Sgavinm 	if (intel_error_list >= 0)
155420c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "B%d", intel_error_list);
155520c794b3Sgavinm 	else
155620c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
155720c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
155820c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
155920c794b3Sgavinm }
156020c794b3Sgavinm 
156120c794b3Sgavinm static void
nb_fat_fbd_err_payload(const nb_regs_t * nb_regs,nvlist_t * payload,nb_scatchpad_t * data)156220c794b3Sgavinm nb_fat_fbd_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
156320c794b3Sgavinm     nb_scatchpad_t *data)
156420c794b3Sgavinm {
156520c794b3Sgavinm 	nb_mem_scatchpad_t *sp;
156620c794b3Sgavinm 	char buf[32];
156720c794b3Sgavinm 
156820c794b3Sgavinm 	sp = &((nb_scatchpad_t *)data)->ms;
156920c794b3Sgavinm 
157020c794b3Sgavinm 	if (sp->ras != -1) {
157120c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK,
157220c794b3Sgavinm 		    DATA_TYPE_INT32, sp->bank, NULL);
157320c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS,
157420c794b3Sgavinm 		    DATA_TYPE_INT32, sp->cas, NULL);
157520c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS,
157620c794b3Sgavinm 		    DATA_TYPE_INT32, sp->ras, NULL);
157720c794b3Sgavinm 		if (sp->offset != -1LL) {
157820c794b3Sgavinm 			fm_payload_set(payload, FM_FMRI_MEM_OFFSET,
157920c794b3Sgavinm 			    DATA_TYPE_UINT64, sp->offset, NULL);
158020c794b3Sgavinm 		}
158120c794b3Sgavinm 		if (sp->pa != -1LL) {
158220c794b3Sgavinm 			fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR,
158320c794b3Sgavinm 			    DATA_TYPE_UINT64, sp->pa, NULL);
158420c794b3Sgavinm 		}
158520c794b3Sgavinm 	}
158620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_FBD,
158720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.ferr_fat_fbd, NULL);
158820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_FBD,
158920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nerr_fat_fbd, NULL);
159020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMA,
15915f28a827Saf 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecmema, NULL);
159220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMB,
159320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecmemb, NULL);
159420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFGLOG,
159520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfglog, NULL);
159620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDA,
159720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbda, NULL);
159820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDB,
159920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdb, NULL);
160020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDC,
160120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdc, NULL);
160220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDD,
160320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdd, NULL);
160420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDE,
160520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbde, NULL);
16065de8e333Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDF,
16075de8e333Saf 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdf, NULL);
160820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS,
160920c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fat_fbd_regs.spcps, NULL);
161020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC,
161120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.spcpc, NULL);
161220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UERRCNT,
161320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.uerrcnt, NULL);
161420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UERRCNT_LAST,
161520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.uerrcnt_last, NULL);
161620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMA,
161720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.badrama, NULL);
161820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMB,
161920c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.fat_fbd_regs.badramb, NULL);
162020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT,
162120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.badcnt, NULL);
162220c794b3Sgavinm 
162320c794b3Sgavinm 	if (sp->intel_error_list >= 0)
162420c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list);
162520c794b3Sgavinm 	else
162620c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
162720c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
162820c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
162920c794b3Sgavinm }
163020c794b3Sgavinm 
163120c794b3Sgavinm static void
nb_nf_fbd_err_payload(const nb_regs_t * nb_regs,nvlist_t * payload,nb_scatchpad_t * data)163220c794b3Sgavinm nb_nf_fbd_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
163320c794b3Sgavinm     nb_scatchpad_t *data)
163420c794b3Sgavinm {
163520c794b3Sgavinm 	nb_mem_scatchpad_t *sp;
163620c794b3Sgavinm 	char buf[32];
163720c794b3Sgavinm 
163820c794b3Sgavinm 	sp = &((nb_scatchpad_t *)data)->ms;
163920c794b3Sgavinm 
164020c794b3Sgavinm 	if (sp->dimm == -1 && sp->rank != -1) {
164120c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RANK,
164220c794b3Sgavinm 		    DATA_TYPE_INT32, sp->rank, NULL);
164320c794b3Sgavinm 	}
164420c794b3Sgavinm 	if (sp->ras != -1) {
164520c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK,
164620c794b3Sgavinm 		    DATA_TYPE_INT32, sp->bank, NULL);
164720c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS,
164820c794b3Sgavinm 		    DATA_TYPE_INT32, sp->cas, NULL);
164920c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS,
165020c794b3Sgavinm 		    DATA_TYPE_INT32, sp->ras, NULL);
165120c794b3Sgavinm 		if (sp->offset != -1LL) {
165220c794b3Sgavinm 			fm_payload_set(payload, FM_FMRI_MEM_OFFSET,
165320c794b3Sgavinm 			    DATA_TYPE_UINT64, sp->offset, NULL);
165420c794b3Sgavinm 		}
165520c794b3Sgavinm 		if (sp->pa != -1LL) {
165620c794b3Sgavinm 			fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR,
165720c794b3Sgavinm 			    DATA_TYPE_UINT64, sp->pa, NULL);
165820c794b3Sgavinm 		}
165920c794b3Sgavinm 	}
166020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_FBD,
166120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.ferr_nf_fbd, NULL);
166220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_FBD,
166320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.nerr_nf_fbd, NULL);
166420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMA,
16655f28a827Saf 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recmema, NULL);
166620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMB,
166720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recmemb, NULL);
166820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFGLOG,
166920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfglog, NULL);
167020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDA,
167120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbda, NULL);
167220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDB,
167320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdb, NULL);
167420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDC,
167520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdc, NULL);
167620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDD,
167720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdd, NULL);
167820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDE,
167920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbde, NULL);
16805de8e333Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDF,
16815de8e333Saf 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdf, NULL);
168220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS,
168320c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.nf_fbd_regs.spcps, NULL);
168420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC,
168520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.spcpc, NULL);
16865f28a827Saf 	if (nb_chipset == INTEL_NB_7300 || nb_chipset == INTEL_NB_5400) {
16875f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTA,
16885f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta, NULL);
16895f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTB,
16905f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntb, NULL);
16915f28a827Saf 		if (nb_chipset == INTEL_NB_7300) {
16925f28a827Saf 			fm_payload_set(payload,
16935f28a827Saf 			    FM_EREPORT_PAYLOAD_NAME_CERRCNTC,
16945f28a827Saf 			    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntc,
16955f28a827Saf 			    NULL);
16965f28a827Saf 			fm_payload_set(payload,
16975f28a827Saf 			    FM_EREPORT_PAYLOAD_NAME_CERRCNTD,
16985f28a827Saf 			    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntd,
16995f28a827Saf 			    NULL);
17005f28a827Saf 		}
17015f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTA_LAST,
17025f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta_last,
17035f28a827Saf 		    NULL);
17045f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTB_LAST,
17055f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntb_last,
17065f28a827Saf 		    NULL);
17075f28a827Saf 		if (nb_chipset == INTEL_NB_7300) {
17085f28a827Saf 			fm_payload_set(payload,
17095f28a827Saf 			    FM_EREPORT_PAYLOAD_NAME_CERRCNTC_LAST,
17105f28a827Saf 			    DATA_TYPE_UINT32,
17115f28a827Saf 			    nb_regs->nb.nf_fbd_regs.cerrcntc_last, NULL);
17125f28a827Saf 			fm_payload_set(payload,
17135f28a827Saf 			    FM_EREPORT_PAYLOAD_NAME_CERRCNTD_LAST,
17145f28a827Saf 			    DATA_TYPE_UINT32,
17155f28a827Saf 			    nb_regs->nb.nf_fbd_regs.cerrcntd_last, NULL);
17165f28a827Saf 		}
17175f28a827Saf 	} else {
17185f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT,
17195f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta, NULL);
17205f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_LAST,
17215f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta_last,
17225f28a827Saf 		    NULL);
17235f28a827Saf 	}
172420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMA,
172520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.badrama, NULL);
172620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMB,
172720c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.nf_fbd_regs.badramb, NULL);
172820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT,
172920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.badcnt, NULL);
173020c794b3Sgavinm 
173120c794b3Sgavinm 	if (sp->intel_error_list >= 0)
173220c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list);
173320c794b3Sgavinm 	else
173420c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
173520c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
173620c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
173720c794b3Sgavinm }
173820c794b3Sgavinm 
173985738508SVuong Nguyen static void
nb_nf_mem_err_payload(const nb_regs_t * nb_regs,nvlist_t * payload,nb_scatchpad_t * data)174085738508SVuong Nguyen nb_nf_mem_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
174185738508SVuong Nguyen     nb_scatchpad_t *data)
174285738508SVuong Nguyen {
174385738508SVuong Nguyen 	nb_mem_scatchpad_t *sp;
174485738508SVuong Nguyen 	char buf[32];
174585738508SVuong Nguyen 
174685738508SVuong Nguyen 	sp = &((nb_scatchpad_t *)data)->ms;
174785738508SVuong Nguyen 
174885738508SVuong Nguyen 	if (sp->dimm == -1 && sp->rank != -1) {
174985738508SVuong Nguyen 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RANK,
175085738508SVuong Nguyen 		    DATA_TYPE_INT32, sp->rank, NULL);
175185738508SVuong Nguyen 	}
175285738508SVuong Nguyen 	if (sp->ras != -1) {
175385738508SVuong Nguyen 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK,
175485738508SVuong Nguyen 		    DATA_TYPE_INT32, sp->bank, NULL);
175585738508SVuong Nguyen 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS,
175685738508SVuong Nguyen 		    DATA_TYPE_INT32, sp->cas, NULL);
175785738508SVuong Nguyen 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS,
175885738508SVuong Nguyen 		    DATA_TYPE_INT32, sp->ras, NULL);
175985738508SVuong Nguyen 		if (sp->offset != -1LL) {
176085738508SVuong Nguyen 			fm_payload_set(payload, FM_FMRI_MEM_OFFSET,
176185738508SVuong Nguyen 			    DATA_TYPE_UINT64, sp->offset, NULL);
176285738508SVuong Nguyen 		}
176385738508SVuong Nguyen 		if (sp->pa != -1LL) {
176485738508SVuong Nguyen 			fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR,
176585738508SVuong Nguyen 			    DATA_TYPE_UINT64, sp->pa, NULL);
176685738508SVuong Nguyen 		}
176785738508SVuong Nguyen 	}
176885738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_MEM,
176985738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.ferr_nf_mem, NULL);
177085738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_MEM,
177185738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nerr_nf_mem, NULL);
177285738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMA,
177385738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.recmema, NULL);
177485738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMB,
177585738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.recmemb, NULL);
177685738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_REDMEMA,
177785738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.redmema, NULL);
177885738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_REDMEMB,
177985738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.redmemb, NULL);
178085738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMA,
178185738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nrecmema, NULL);
178285738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMB,
178385738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nrecmemb, NULL);
178485738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS,
178585738508SVuong Nguyen 	    DATA_TYPE_UINT8, nb_regs->nb.nf_mem_regs.spcps, NULL);
178685738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC,
178785738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.spcpc, NULL);
178885738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT,
178985738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt, NULL);
179085738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_LAST,
179185738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_last, NULL);
179285738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_EXT,
179385738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_ext, NULL);
179485738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_EXT_LAST,
179585738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_ext_last, NULL);
179685738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAM,
179785738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.badram, NULL);
179885738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT,
179985738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.badcnt, NULL);
180085738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_VALIDLOG,
180185738508SVuong Nguyen 	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.validlog, NULL);
180285738508SVuong Nguyen 
180385738508SVuong Nguyen 	if (sp->intel_error_list >= 0)
180485738508SVuong Nguyen 		(void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list);
180585738508SVuong Nguyen 	else
180685738508SVuong Nguyen 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
180785738508SVuong Nguyen 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
180885738508SVuong Nguyen 	    DATA_TYPE_STRING, buf, NULL);
180985738508SVuong Nguyen }
181085738508SVuong Nguyen 
181120c794b3Sgavinm static void
nb_dma_err_payload(const nb_regs_t * nb_regs,nvlist_t * payload)181220c794b3Sgavinm nb_dma_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload)
181320c794b3Sgavinm {
181420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PCISTS,
181520c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.dma_regs.pcists, NULL);
181620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEXDEVSTS,
181720c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.dma_regs.pexdevsts, NULL);
181820c794b3Sgavinm }
181920c794b3Sgavinm 
18205f28a827Saf static void
nb_thr_err_payload(const nb_regs_t * nb_regs,nvlist_t * payload,nb_scatchpad_t * data)18215f28a827Saf nb_thr_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
18225f28a827Saf     nb_scatchpad_t *data)
18235f28a827Saf {
18245f28a827Saf 	char buf[32];
18255f28a827Saf 
18265f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_THR,
18275f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ferr_fat_thr, NULL);
18285f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_THR,
18295f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.nerr_fat_thr, NULL);
18305f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_THR,
18315f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ferr_nf_thr, NULL);
18325f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_THR,
18335f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.nerr_nf_thr, NULL);
18345f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CTSTS,
18355f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ctsts, NULL);
18365f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_THRTSTS,
18375f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.thr_regs.thrtsts, NULL);
18385f28a827Saf 	if (data->intel_error_list >= 0) {
18395f28a827Saf 		(void) snprintf(buf, sizeof (buf), "TH%d",
18405f28a827Saf 		    data->intel_error_list);
18415f28a827Saf 	} else {
18425f28a827Saf 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
18435f28a827Saf 	}
18445f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
18455f28a827Saf 	    DATA_TYPE_STRING, buf, NULL);
18465f28a827Saf }
18475f28a827Saf 
184820c794b3Sgavinm static void
nb_ereport_add_logout(nvlist_t * payload,const nb_logout_t * acl,nb_scatchpad_t * data)184920c794b3Sgavinm nb_ereport_add_logout(nvlist_t *payload, const nb_logout_t *acl,
185020c794b3Sgavinm     nb_scatchpad_t *data)
185120c794b3Sgavinm {
185220c794b3Sgavinm 	const nb_regs_t *nb_regs = &acl->nb_regs;
185320c794b3Sgavinm 
185420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_MC_TYPE,
18556cb1ca52Saf 	    DATA_TYPE_STRING, acl->type, NULL);
185620c794b3Sgavinm 	switch (nb_regs->flag) {
185720c794b3Sgavinm 	case NB_REG_LOG_FSB:
185820c794b3Sgavinm 		nb_fsb_err_payload(nb_regs, payload, data);
185920c794b3Sgavinm 		break;
186020c794b3Sgavinm 	case NB_REG_LOG_PEX:
186120c794b3Sgavinm 		nb_pex_err_payload(nb_regs, payload, data);
186220c794b3Sgavinm 		break;
186320c794b3Sgavinm 	case NB_REG_LOG_INT:
186420c794b3Sgavinm 		nb_int_err_payload(nb_regs, payload, data);
186520c794b3Sgavinm 		break;
186620c794b3Sgavinm 	case NB_REG_LOG_FAT_FBD:
186720c794b3Sgavinm 		nb_fat_fbd_err_payload(nb_regs, payload, data);
186820c794b3Sgavinm 		break;
186920c794b3Sgavinm 	case NB_REG_LOG_NF_FBD:
187020c794b3Sgavinm 		nb_nf_fbd_err_payload(nb_regs, payload, data);
187120c794b3Sgavinm 		break;
187220c794b3Sgavinm 	case NB_REG_LOG_DMA:
187320c794b3Sgavinm 		nb_dma_err_payload(nb_regs, payload);
187420c794b3Sgavinm 		break;
18755f28a827Saf 	case NB_REG_LOG_THR:
18765f28a827Saf 		nb_thr_err_payload(nb_regs, payload, data);
18775f28a827Saf 		break;
187885738508SVuong Nguyen 	case NB_REG_LOG_NF_MEM:
187985738508SVuong Nguyen 		nb_nf_mem_err_payload(nb_regs, payload, data);
188085738508SVuong Nguyen 		break;
188120c794b3Sgavinm 	default:
188220c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_GLOBAL,
188320c794b3Sgavinm 		    DATA_TYPE_UINT64, nb_regs->ferr, NULL);
188420c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_GLOBAL,
188520c794b3Sgavinm 		    DATA_TYPE_UINT32, nb_regs->nerr, NULL);
188620c794b3Sgavinm 		break;
188720c794b3Sgavinm 	}
188820c794b3Sgavinm }
188920c794b3Sgavinm 
189020c794b3Sgavinm void
nb_fsb_report(const nb_regs_t * nb_regs,char * class,nvlist_t * detector,nb_scatchpad_t * data)189120c794b3Sgavinm nb_fsb_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
189220c794b3Sgavinm     nb_scatchpad_t *data)
189320c794b3Sgavinm {
189420c794b3Sgavinm 	int chip;
189520c794b3Sgavinm 
189620c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300)
189720c794b3Sgavinm 		chip = nb_regs->nb.fsb_regs.fsb * 2;
189820c794b3Sgavinm 	else
189920c794b3Sgavinm 		chip = nb_regs->nb.fsb_regs.fsb;
190020c794b3Sgavinm 	fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
190120c794b3Sgavinm 	    "motherboard", 0, "chip", chip);
190220c794b3Sgavinm 
19036cb1ca52Saf 	if (nb_regs->nb.fsb_regs.ferr_fat_fsb == 0 &&
19046cb1ca52Saf 	    nb_regs->nb.fsb_regs.ferr_nf_fsb == 0) {
19056cb1ca52Saf 		data->intel_error_list = intel_fsb_err(nb_regs->nb.fsb_regs.fsb,
19066cb1ca52Saf 		    nb_regs->nb.fsb_regs.nerr_fat_fsb,
19076cb1ca52Saf 		    nb_regs->nb.fsb_regs.nerr_nf_fsb);
19086cb1ca52Saf 	} else {
19096cb1ca52Saf 		data->intel_error_list = intel_fsb_err(nb_regs->nb.fsb_regs.fsb,
19106cb1ca52Saf 		    nb_regs->nb.fsb_regs.ferr_fat_fsb,
19116cb1ca52Saf 		    nb_regs->nb.fsb_regs.ferr_nf_fsb);
19126cb1ca52Saf 	}
191320c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
191420c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "fsb");
191520c794b3Sgavinm }
191620c794b3Sgavinm 
191720c794b3Sgavinm void
nb_pex_report(const nb_regs_t * nb_regs,char * class,nvlist_t * detector,nb_scatchpad_t * data)191820c794b3Sgavinm nb_pex_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
191920c794b3Sgavinm     nb_scatchpad_t *data)
192020c794b3Sgavinm {
192120c794b3Sgavinm 	int hostbridge;
192220c794b3Sgavinm 
192320c794b3Sgavinm 	if (nb_regs->nb.pex_regs.pex == 0) {
192420c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
192520c794b3Sgavinm 		    "motherboard", 0);
192620c794b3Sgavinm 	} else {
192720c794b3Sgavinm 		hostbridge = nb_regs->nb.pex_regs.pex - 1;
192820c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
192920c794b3Sgavinm 		    "motherboard", 0,
193020c794b3Sgavinm 		    "hostbridge", hostbridge);
193120c794b3Sgavinm 	}
193220c794b3Sgavinm 
19336cb1ca52Saf 	if (nb_regs->nb.pex_regs.pex_fat_ferr == 0 &&
19346cb1ca52Saf 	    nb_regs->nb.pex_regs.pex_nf_corr_ferr == 0) {
19355f28a827Saf 		if (nb_chipset == INTEL_NB_5400) {
19365f28a827Saf 			data->intel_error_list =
19375f28a827Saf 			    intel_pex_5400_err(
19385f28a827Saf 			    nb_regs->nb.pex_regs.pex_fat_nerr,
19395f28a827Saf 			    nb_regs->nb.pex_regs.pex_nf_corr_nerr);
19405f28a827Saf 		} else {
19415f28a827Saf 			data->intel_error_list =
19425f28a827Saf 			    intel_pex_err(nb_regs->nb.pex_regs.pex_fat_nerr,
19435f28a827Saf 			    nb_regs->nb.pex_regs.pex_nf_corr_nerr);
19445f28a827Saf 		}
19456cb1ca52Saf 	} else {
19465f28a827Saf 		if (nb_chipset == INTEL_NB_5400) {
19475f28a827Saf 			data->intel_error_list =
19485f28a827Saf 			    intel_pex_5400_err(
19495f28a827Saf 			    nb_regs->nb.pex_regs.pex_fat_ferr,
19505f28a827Saf 			    nb_regs->nb.pex_regs.pex_nf_corr_ferr);
19515f28a827Saf 		} else {
19525f28a827Saf 			data->intel_error_list =
19535f28a827Saf 			    intel_pex_err(nb_regs->nb.pex_regs.pex_fat_ferr,
19545f28a827Saf 			    nb_regs->nb.pex_regs.pex_nf_corr_ferr);
19555f28a827Saf 		}
19566cb1ca52Saf 	}
195720c794b3Sgavinm 
195820c794b3Sgavinm 	if (nb_regs->nb.pex_regs.pex == 0) {
195920c794b3Sgavinm 		(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
196020c794b3Sgavinm 		    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "esi");
196120c794b3Sgavinm 	} else {
196220c794b3Sgavinm 		(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
196320c794b3Sgavinm 		    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "pex");
196420c794b3Sgavinm 	}
196520c794b3Sgavinm }
196620c794b3Sgavinm 
196720c794b3Sgavinm void
nb_int_report(const nb_regs_t * nb_regs,char * class,nvlist_t * detector,void * data)196820c794b3Sgavinm nb_int_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
196920c794b3Sgavinm     void *data)
197020c794b3Sgavinm {
197120c794b3Sgavinm 	fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
197220c794b3Sgavinm 	    "motherboard", 0);
197320c794b3Sgavinm 
19746cb1ca52Saf 	if (nb_regs->nb.int_regs.ferr_fat_int == 0 &&
19756cb1ca52Saf 	    nb_regs->nb.int_regs.ferr_nf_int == 0) {
19766cb1ca52Saf 		((nb_scatchpad_t *)data)->intel_error_list =
19776cb1ca52Saf 		    intel_int_err(nb_regs->nb.int_regs.nerr_fat_int,
19786cb1ca52Saf 		    nb_regs->nb.int_regs.nerr_nf_int);
19796cb1ca52Saf 	} else {
19806cb1ca52Saf 		((nb_scatchpad_t *)data)->intel_error_list =
19816cb1ca52Saf 		    intel_int_err(nb_regs->nb.int_regs.ferr_fat_int,
19826cb1ca52Saf 		    nb_regs->nb.int_regs.ferr_nf_int);
19836cb1ca52Saf 	}
198420c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
198520c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "ie");
198620c794b3Sgavinm }
198720c794b3Sgavinm 
198820c794b3Sgavinm void
nb_fat_fbd_report(const nb_regs_t * nb_regs,char * class,nvlist_t * detector,void * data)198920c794b3Sgavinm nb_fat_fbd_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
199020c794b3Sgavinm     void *data)
199120c794b3Sgavinm {
199220c794b3Sgavinm 	char *intr;
199320c794b3Sgavinm 	nb_mem_scatchpad_t *sp;
199420c794b3Sgavinm 
199520c794b3Sgavinm 	intr = fat_memory_error(nb_regs, data);
199620c794b3Sgavinm 	sp = &((nb_scatchpad_t *)data)->ms;
199720c794b3Sgavinm 
199820c794b3Sgavinm 	if (sp->dimm != -1) {
199920c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5,
200020c794b3Sgavinm 		    "motherboard", 0,
200120c794b3Sgavinm 		    "memory-controller", sp->branch,
200220c794b3Sgavinm 		    "dram-channel", sp->channel,
200320c794b3Sgavinm 		    "dimm", sp->dimm,
200420c794b3Sgavinm 		    "rank", sp->rank);
200520c794b3Sgavinm 	} else if (sp->channel != -1) {
200620c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
200720c794b3Sgavinm 		    "motherboard", 0,
200820c794b3Sgavinm 		    "memory-controller", sp->branch,
200920c794b3Sgavinm 		    "dram-channel", sp->channel);
20106cb1ca52Saf 	} else if (sp->branch != -1) {
201120c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
201220c794b3Sgavinm 		    "motherboard", 0,
201320c794b3Sgavinm 		    "memory-controller", sp->branch);
20146cb1ca52Saf 	} else {
20156cb1ca52Saf 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
20166cb1ca52Saf 		    "motherboard", 0);
201720c794b3Sgavinm 	}
201820c794b3Sgavinm 
201920c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s",
202020c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr);
202120c794b3Sgavinm }
202220c794b3Sgavinm 
202320c794b3Sgavinm void
nb_nf_fbd_report(const nb_regs_t * nb_regs,char * class,nvlist_t * detector,void * data)202420c794b3Sgavinm nb_nf_fbd_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
202520c794b3Sgavinm     void *data)
202620c794b3Sgavinm {
202720c794b3Sgavinm 	char *intr;
202820c794b3Sgavinm 	nb_mem_scatchpad_t *sp;
202920c794b3Sgavinm 
203020c794b3Sgavinm 	intr = nf_memory_error(nb_regs, data);
203120c794b3Sgavinm 	sp = &((nb_scatchpad_t *)data)->ms;
203220c794b3Sgavinm 
203320c794b3Sgavinm 	if (sp->dimm != -1) {
203420c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5,
203520c794b3Sgavinm 		    "motherboard", 0,
203620c794b3Sgavinm 		    "memory-controller", sp->branch,
203720c794b3Sgavinm 		    "dram-channel", sp->channel,
203820c794b3Sgavinm 		    "dimm", sp->dimm,
203920c794b3Sgavinm 		    "rank", sp->rank);
204020c794b3Sgavinm 	} else if (sp->channel != -1) {
204120c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
204220c794b3Sgavinm 		    "motherboard", 0,
204320c794b3Sgavinm 		    "memory-controller", sp->branch,
204420c794b3Sgavinm 		    "dram-channel", sp->channel);
20456cb1ca52Saf 	} else if (sp->branch != -1) {
204620c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
204720c794b3Sgavinm 		    "motherboard", 0,
204820c794b3Sgavinm 		    "memory-controller", sp->branch);
20496cb1ca52Saf 	} else {
20506cb1ca52Saf 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
20516cb1ca52Saf 		    "motherboard", 0);
205220c794b3Sgavinm 	}
205320c794b3Sgavinm 
205420c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s",
205520c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr);
205620c794b3Sgavinm }
205720c794b3Sgavinm 
205820c794b3Sgavinm void
nb_dma_report(char * class,nvlist_t * detector)205920c794b3Sgavinm nb_dma_report(char *class, nvlist_t *detector)
206020c794b3Sgavinm {
206120c794b3Sgavinm 	fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
206220c794b3Sgavinm 	    "motherboard", 0);
206320c794b3Sgavinm 
206420c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
206520c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "dma");
206620c794b3Sgavinm }
206720c794b3Sgavinm 
20685f28a827Saf void
nb_thr_report(const nb_regs_t * nb_regs,char * class,nvlist_t * detector,void * data)20695f28a827Saf nb_thr_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
20705f28a827Saf     void *data)
20715f28a827Saf {
20725f28a827Saf 	((nb_scatchpad_t *)data)->intel_error_list =
20735f28a827Saf 	    intel_thr_err(nb_regs->nb.thr_regs.ferr_fat_thr,
20745f28a827Saf 	    nb_regs->nb.thr_regs.ferr_nf_thr);
20755f28a827Saf 	fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
20765f28a827Saf 	    "motherboard", 0);
20775f28a827Saf 
20785f28a827Saf 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
20795f28a827Saf 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "otf");
20805f28a827Saf }
20815f28a827Saf 
208285738508SVuong Nguyen void
nb_nf_mem_report(const nb_regs_t * nb_regs,char * class,nvlist_t * detector,void * data)208385738508SVuong Nguyen nb_nf_mem_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
208485738508SVuong Nguyen     void *data)
208585738508SVuong Nguyen {
208685738508SVuong Nguyen 	char *intr;
208785738508SVuong Nguyen 	nb_mem_scatchpad_t *sp;
208885738508SVuong Nguyen 
208985738508SVuong Nguyen 	intr = nf_mem_error(nb_regs, data);
209085738508SVuong Nguyen 	sp = &((nb_scatchpad_t *)data)->ms;
209185738508SVuong Nguyen 
209285738508SVuong Nguyen 	if (sp->dimm != -1) {
209385738508SVuong Nguyen 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5,
209485738508SVuong Nguyen 		    "motherboard", 0,
209585738508SVuong Nguyen 		    "memory-controller", sp->branch,
209685738508SVuong Nguyen 		    "dram-channel", sp->channel,
209785738508SVuong Nguyen 		    "dimm", sp->dimm,
209885738508SVuong Nguyen 		    "rank", sp->rank);
209985738508SVuong Nguyen 	} else if (sp->channel != -1) {
210085738508SVuong Nguyen 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
210185738508SVuong Nguyen 		    "motherboard", 0,
210285738508SVuong Nguyen 		    "memory-controller", sp->branch,
210385738508SVuong Nguyen 		    "dram-channel", sp->channel);
210485738508SVuong Nguyen 	} else if (sp->branch != -1) {
210585738508SVuong Nguyen 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
210685738508SVuong Nguyen 		    "motherboard", 0,
210785738508SVuong Nguyen 		    "memory-controller", sp->branch);
210885738508SVuong Nguyen 	} else {
210985738508SVuong Nguyen 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
211085738508SVuong Nguyen 		    "motherboard", 0);
211185738508SVuong Nguyen 	}
211285738508SVuong Nguyen 
211385738508SVuong Nguyen 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s",
211485738508SVuong Nguyen 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr);
211585738508SVuong Nguyen }
211685738508SVuong Nguyen 
211720c794b3Sgavinm 
211820c794b3Sgavinm nvlist_t *
nb_report(const nb_regs_t * nb_regs,char * class,nv_alloc_t * nva,void * scratch)211920c794b3Sgavinm nb_report(const nb_regs_t *nb_regs, char *class, nv_alloc_t *nva, void *scratch)
212020c794b3Sgavinm {
212120c794b3Sgavinm 	nvlist_t *detector = fm_nvlist_create(nva);
212220c794b3Sgavinm 
212320c794b3Sgavinm 	switch (nb_regs->flag) {
212420c794b3Sgavinm 	case NB_REG_LOG_FSB:
212520c794b3Sgavinm 		nb_fsb_report(nb_regs, class, detector, scratch);
212620c794b3Sgavinm 		break;
212720c794b3Sgavinm 	case NB_REG_LOG_PEX:
212820c794b3Sgavinm 		nb_pex_report(nb_regs, class, detector, scratch);
212920c794b3Sgavinm 		break;
213020c794b3Sgavinm 	case NB_REG_LOG_INT:
213120c794b3Sgavinm 		nb_int_report(nb_regs, class, detector, scratch);
213220c794b3Sgavinm 		break;
213320c794b3Sgavinm 	case NB_REG_LOG_FAT_FBD:
213420c794b3Sgavinm 		nb_fat_fbd_report(nb_regs, class, detector, scratch);
213520c794b3Sgavinm 		break;
213620c794b3Sgavinm 	case NB_REG_LOG_NF_FBD:
213720c794b3Sgavinm 		nb_nf_fbd_report(nb_regs, class, detector, scratch);
213820c794b3Sgavinm 		break;
213920c794b3Sgavinm 	case NB_REG_LOG_DMA:
214020c794b3Sgavinm 		nb_dma_report(class, detector);
214120c794b3Sgavinm 		break;
21425f28a827Saf 	case NB_REG_LOG_THR:
21435f28a827Saf 		nb_thr_report(nb_regs, class, detector, scratch);
21445f28a827Saf 		break;
214585738508SVuong Nguyen 	case NB_REG_LOG_NF_MEM:
214685738508SVuong Nguyen 		nb_nf_mem_report(nb_regs, class, detector, scratch);
214785738508SVuong Nguyen 		break;
214820c794b3Sgavinm 	default:
214920c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
215020c794b3Sgavinm 		    "motherboard", 0);
215120c794b3Sgavinm 
215220c794b3Sgavinm 		(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
215320c794b3Sgavinm 		    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "unknown");
215420c794b3Sgavinm 	}
215520c794b3Sgavinm 	return (detector);
215620c794b3Sgavinm }
215720c794b3Sgavinm 
215820c794b3Sgavinm /*ARGSUSED*/
215920c794b3Sgavinm void
nb_drain(void * ignored,const void * data,const errorq_elem_t * eqe)216020c794b3Sgavinm nb_drain(void *ignored, const void *data, const errorq_elem_t *eqe)
216120c794b3Sgavinm {
216220c794b3Sgavinm 	nb_logout_t *acl = (nb_logout_t *)data;
216320c794b3Sgavinm 	errorq_elem_t *eqep, *scr_eqep;
216420c794b3Sgavinm 	nvlist_t *ereport, *detector;
216520c794b3Sgavinm 	nv_alloc_t *nva = NULL;
216620c794b3Sgavinm 	char buf[FM_MAX_CLASS];
216720c794b3Sgavinm 	nb_scatchpad_t nb_scatchpad;
216820c794b3Sgavinm 
2169*1a10a907SToomas Soome 	eqep = NULL;
2170*1a10a907SToomas Soome 	scr_eqep = NULL;
217120c794b3Sgavinm 	if (panicstr) {
217220c794b3Sgavinm 		if ((eqep = errorq_reserve(ereport_errorq)) == NULL)
217320c794b3Sgavinm 			return;
217420c794b3Sgavinm 		ereport = errorq_elem_nvl(ereport_errorq, eqep);
217520c794b3Sgavinm 		/*
217620c794b3Sgavinm 		 * Now try to allocate another element for scratch space and
217720c794b3Sgavinm 		 * use that for further scratch space (eg for constructing
217820c794b3Sgavinm 		 * nvlists to add the main ereport).  If we can't reserve
217920c794b3Sgavinm 		 * a scratch element just fallback to working within the
218020c794b3Sgavinm 		 * element we already have, and hope for the best.  All this
218120c794b3Sgavinm 		 * is necessary because the fixed buffer nv allocator does
218220c794b3Sgavinm 		 * not reclaim freed space and nvlist construction is
218320c794b3Sgavinm 		 * expensive.
218420c794b3Sgavinm 		 */
218520c794b3Sgavinm 		if ((scr_eqep = errorq_reserve(ereport_errorq)) != NULL)
218620c794b3Sgavinm 			nva = errorq_elem_nva(ereport_errorq, scr_eqep);
218720c794b3Sgavinm 		else
218820c794b3Sgavinm 			nva = errorq_elem_nva(ereport_errorq, eqep);
218920c794b3Sgavinm 	} else {
219020c794b3Sgavinm 		ereport = fm_nvlist_create(NULL);
219120c794b3Sgavinm 	}
219220c794b3Sgavinm 	detector = nb_report(&acl->nb_regs, buf, nva, &nb_scatchpad);
219320c794b3Sgavinm 	if (detector == NULL)
219420c794b3Sgavinm 		return;
219520c794b3Sgavinm 	fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
219620c794b3Sgavinm 	    fm_ena_generate(acl->acl_timestamp, FM_ENA_FMT1), detector, NULL);
219720c794b3Sgavinm 	/*
219820c794b3Sgavinm 	 * We're done with 'detector' so reclaim the scratch space.
219920c794b3Sgavinm 	 */
220020c794b3Sgavinm 	if (panicstr) {
220120c794b3Sgavinm 		fm_nvlist_destroy(detector, FM_NVA_RETAIN);
220220c794b3Sgavinm 		nv_alloc_reset(nva);
220320c794b3Sgavinm 	} else {
220420c794b3Sgavinm 		fm_nvlist_destroy(detector, FM_NVA_FREE);
220520c794b3Sgavinm 	}
220620c794b3Sgavinm 
220720c794b3Sgavinm 	/*
220820c794b3Sgavinm 	 * Encode the error-specific data that was saved in the logout area.
220920c794b3Sgavinm 	 */
221020c794b3Sgavinm 	nb_ereport_add_logout(ereport, acl, &nb_scatchpad);
221120c794b3Sgavinm 
221220c794b3Sgavinm 	if (panicstr) {
221320c794b3Sgavinm 		errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
221420c794b3Sgavinm 		if (scr_eqep)
221520c794b3Sgavinm 			errorq_cancel(ereport_errorq, scr_eqep);
221620c794b3Sgavinm 	} else {
221720c794b3Sgavinm 		(void) fm_ereport_post(ereport, EVCH_TRYHARD);
221820c794b3Sgavinm 		fm_nvlist_destroy(ereport, FM_NVA_FREE);
221920c794b3Sgavinm 	}
222020c794b3Sgavinm }
2221