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 /*
239ff4cbe7SAdrian Frost  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2420c794b3Sgavinm  * Use is subject to license terms.
2520c794b3Sgavinm  */
2620c794b3Sgavinm 
2720c794b3Sgavinm #include <sys/types.h>
2820c794b3Sgavinm #include <sys/cmn_err.h>
2920c794b3Sgavinm #include <sys/errno.h>
3020c794b3Sgavinm #include <sys/log.h>
3120c794b3Sgavinm #include <sys/systm.h>
3220c794b3Sgavinm #include <sys/modctl.h>
3320c794b3Sgavinm #include <sys/errorq.h>
3420c794b3Sgavinm #include <sys/controlregs.h>
3520c794b3Sgavinm #include <sys/fm/util.h>
3620c794b3Sgavinm #include <sys/fm/protocol.h>
3720c794b3Sgavinm #include <sys/sysevent.h>
3820c794b3Sgavinm #include <sys/pghw.h>
3920c794b3Sgavinm #include <sys/cyclic.h>
4020c794b3Sgavinm #include <sys/pci_cfgspace.h>
4120c794b3Sgavinm #include <sys/mc_intel.h>
4220c794b3Sgavinm #include <sys/smbios.h>
4320c794b3Sgavinm #include "nb5000.h"
4420c794b3Sgavinm #include "nb_log.h"
4520c794b3Sgavinm #include "dimm_phys.h"
4620c794b3Sgavinm 
4720c794b3Sgavinm static uint32_t uerrcnt[2];
485f28a827Saf static uint32_t cerrcnta[2][2];
495f28a827Saf static uint32_t cerrcntb[2][2];
505f28a827Saf static uint32_t cerrcntc[2][2];
515f28a827Saf static uint32_t cerrcntd[2][2];
5220c794b3Sgavinm static nb_logout_t nb_log;
5320c794b3Sgavinm 
5420c794b3Sgavinm struct mch_error_code {
5520c794b3Sgavinm 	int intel_error_list;	/* error number in Chipset Error List */
5620c794b3Sgavinm 	uint32_t emask;		/* mask for machine check */
5720c794b3Sgavinm 	uint32_t error_bit;	/* error bit in fault register */
5820c794b3Sgavinm };
5920c794b3Sgavinm 
6020c794b3Sgavinm static struct mch_error_code fat_fbd_error_code[] = {
6120c794b3Sgavinm 	{ 23, EMASK_FBD_M23, ERR_FAT_FBD_M23 },
6220c794b3Sgavinm 	{ 3, EMASK_FBD_M3, ERR_FAT_FBD_M3 },
6320c794b3Sgavinm 	{ 2, EMASK_FBD_M2, ERR_FAT_FBD_M2 },
6420c794b3Sgavinm 	{ 1, EMASK_FBD_M1, ERR_FAT_FBD_M1 }
6520c794b3Sgavinm };
6620c794b3Sgavinm 
6720c794b3Sgavinm static int
6820c794b3Sgavinm intel_fat_fbd_err(uint32_t fat_fbd)
6920c794b3Sgavinm {
7020c794b3Sgavinm 	int rt = -1;
7120c794b3Sgavinm 	int nerr = 0;
7220c794b3Sgavinm 	uint32_t emask_fbd = 0;
7320c794b3Sgavinm 	int i;
7420c794b3Sgavinm 	int sz;
7520c794b3Sgavinm 
7620c794b3Sgavinm 	sz = sizeof (fat_fbd_error_code) / sizeof (struct mch_error_code);
7720c794b3Sgavinm 
7820c794b3Sgavinm 	for (i = 0; i < sz; i++) {
7920c794b3Sgavinm 		if (fat_fbd & fat_fbd_error_code[i].error_bit) {
8020c794b3Sgavinm 			rt = fat_fbd_error_code[i].intel_error_list;
8120c794b3Sgavinm 			emask_fbd |= fat_fbd_error_code[i].emask;
8220c794b3Sgavinm 			nerr++;
8320c794b3Sgavinm 		}
8420c794b3Sgavinm 	}
8520c794b3Sgavinm 
8620c794b3Sgavinm 	if (emask_fbd)
8720c794b3Sgavinm 		nb_fbd_mask_mc(emask_fbd);
8820c794b3Sgavinm 	if (nerr > 1)
8920c794b3Sgavinm 		rt = -1;
9020c794b3Sgavinm 	return (rt);
9120c794b3Sgavinm }
9220c794b3Sgavinm 
9320c794b3Sgavinm static char *
9420c794b3Sgavinm fat_memory_error(const nb_regs_t *rp, void *data)
9520c794b3Sgavinm {
9620c794b3Sgavinm 	int channel;
9720c794b3Sgavinm 	uint32_t ferr_fat_fbd, nrecmemb;
985f28a827Saf 	uint32_t nrecmema;
9920c794b3Sgavinm 	char *intr = "nb.unknown";
10020c794b3Sgavinm 	nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms;
10120c794b3Sgavinm 
10220c794b3Sgavinm 	ferr_fat_fbd = rp->nb.fat_fbd_regs.ferr_fat_fbd;
1036cb1ca52Saf 	if ((ferr_fat_fbd & ERR_FAT_FBD_MASK) == 0) {
1046cb1ca52Saf 		sp->intel_error_list =
1056cb1ca52Saf 		    intel_fat_fbd_err(rp->nb.fat_fbd_regs.nerr_fat_fbd);
1066cb1ca52Saf 		sp->branch = -1;
1076cb1ca52Saf 		sp->channel = -1;
1086cb1ca52Saf 		sp->rank = -1;
1096cb1ca52Saf 		sp->dimm = -1;
1106cb1ca52Saf 		sp->bank = -1;
1116cb1ca52Saf 		sp->cas = -1;
1126cb1ca52Saf 		sp->ras = -1;
1136cb1ca52Saf 		sp->pa = -1LL;
1146cb1ca52Saf 		sp->offset = -1;
1156cb1ca52Saf 		return (intr);
1166cb1ca52Saf 	}
11720c794b3Sgavinm 	sp->intel_error_list = intel_fat_fbd_err(ferr_fat_fbd);
11820c794b3Sgavinm 	channel = (ferr_fat_fbd >> 28) & 3;
11920c794b3Sgavinm 	sp->branch = channel >> 1;
12020c794b3Sgavinm 	sp->channel = channel;
12120c794b3Sgavinm 	if ((ferr_fat_fbd & (ERR_FAT_FBD_M2|ERR_FAT_FBD_M1)) != 0) {
12220c794b3Sgavinm 		if ((ferr_fat_fbd & ERR_FAT_FBD_M1) != 0)
12320c794b3Sgavinm 			intr = "nb.fbd.alert";	/* Alert on FB-DIMM M1 */
12420c794b3Sgavinm 		else
12520c794b3Sgavinm 			intr = "nb.fbd.crc";	/* CRC error FB_DIMM M2 */
12620c794b3Sgavinm 		nrecmema = rp->nb.fat_fbd_regs.nrecmema;
12720c794b3Sgavinm 		nrecmemb = rp->nb.fat_fbd_regs.nrecmemb;
12820c794b3Sgavinm 		sp->rank = (nrecmema >> 8) & RANK_MASK;
12920c794b3Sgavinm 		sp->dimm = sp->rank >> 1;
13020c794b3Sgavinm 		sp->bank = (nrecmema >> 12) & BANK_MASK;
13120c794b3Sgavinm 		sp->cas = (nrecmemb >> 16) & CAS_MASK;
13220c794b3Sgavinm 		sp->ras = nrecmemb & RAS_MASK;
13320c794b3Sgavinm 		sp->pa = dimm_getphys(sp->branch, sp->rank, sp->bank, sp->ras,
13420c794b3Sgavinm 		    sp->cas);
13520c794b3Sgavinm 		sp->offset = dimm_getoffset(sp->branch, sp->rank, sp->bank,
13620c794b3Sgavinm 		    sp->ras, sp->cas);
13720c794b3Sgavinm 	} else {
13820c794b3Sgavinm 		if ((ferr_fat_fbd & ERR_FAT_FBD_M3) != 0)
13920c794b3Sgavinm 			intr = "nb.fbd.otf";	/* thermal temp > Tmid M3 */
14020c794b3Sgavinm 		else if ((ferr_fat_fbd & ERR_FAT_FBD_M23) != 0) {
14120c794b3Sgavinm 			intr = "nb.fbd.reset_timeout";
14220c794b3Sgavinm 			sp->channel = -1;
14320c794b3Sgavinm 		}
14420c794b3Sgavinm 		sp->rank = -1;
14520c794b3Sgavinm 		sp->dimm = -1;
14620c794b3Sgavinm 		sp->bank = -1;
14720c794b3Sgavinm 		sp->cas = -1;
14820c794b3Sgavinm 		sp->ras = -1;
14920c794b3Sgavinm 		sp->pa = -1LL;
15020c794b3Sgavinm 		sp->offset = -1;
15120c794b3Sgavinm 	}
15220c794b3Sgavinm 	return (intr);
15320c794b3Sgavinm }
15420c794b3Sgavinm 
15520c794b3Sgavinm 
15620c794b3Sgavinm static struct mch_error_code nf_fbd_error_code[] = {
1575f28a827Saf 	{ 29, EMASK_FBD_M29, ERR_NF_FBD_M29 },
15820c794b3Sgavinm 	{ 28, EMASK_FBD_M28, ERR_NF_FBD_M28 },
15920c794b3Sgavinm 	{ 27, EMASK_FBD_M27, ERR_NF_FBD_M27 },
16020c794b3Sgavinm 	{ 26, EMASK_FBD_M26, ERR_NF_FBD_M26 },
16120c794b3Sgavinm 	{ 25, EMASK_FBD_M25, ERR_NF_FBD_M25 },
1625f28a827Saf 	{ 24, EMASK_FBD_M24, ERR_NF_FBD_M24 },
16320c794b3Sgavinm 	{ 22, EMASK_FBD_M22, ERR_NF_FBD_M22 },
16420c794b3Sgavinm 	{ 21, EMASK_FBD_M21, ERR_NF_FBD_M21 },
16520c794b3Sgavinm 	{ 20, EMASK_FBD_M20, ERR_NF_FBD_M20 },
16620c794b3Sgavinm 	{ 19, EMASK_FBD_M19, ERR_NF_FBD_M19 },
16720c794b3Sgavinm 	{ 18, EMASK_FBD_M18, ERR_NF_FBD_M18 },
16820c794b3Sgavinm 	{ 17, EMASK_FBD_M17, ERR_NF_FBD_M17 },
1695f28a827Saf 	{ 16, EMASK_FBD_M16, ERR_NF_FBD_M16 },
17020c794b3Sgavinm 	{ 15, EMASK_FBD_M15, ERR_NF_FBD_M15 },
17120c794b3Sgavinm 	{ 14, EMASK_FBD_M14, ERR_NF_FBD_M14 },
17220c794b3Sgavinm 	{ 13, EMASK_FBD_M13, ERR_NF_FBD_M13 },
17320c794b3Sgavinm 	{ 12, EMASK_FBD_M12, ERR_NF_FBD_M12 },
17420c794b3Sgavinm 	{ 11, EMASK_FBD_M11, ERR_NF_FBD_M11 },
17520c794b3Sgavinm 	{ 10, EMASK_FBD_M10, ERR_NF_FBD_M10 },
17620c794b3Sgavinm 	{ 9, EMASK_FBD_M9, ERR_NF_FBD_M9 },
17720c794b3Sgavinm 	{ 8, EMASK_FBD_M8, ERR_NF_FBD_M8 },
17820c794b3Sgavinm 	{ 7, EMASK_FBD_M7, ERR_NF_FBD_M7 },
17920c794b3Sgavinm 	{ 6, EMASK_FBD_M6, ERR_NF_FBD_M6 },
18020c794b3Sgavinm 	{ 5, EMASK_FBD_M5, ERR_NF_FBD_M5 },
18120c794b3Sgavinm 	{ 4, EMASK_FBD_M4, ERR_NF_FBD_M4 }
18220c794b3Sgavinm };
18320c794b3Sgavinm 
18420c794b3Sgavinm static int
18520c794b3Sgavinm intel_nf_fbd_err(uint32_t nf_fbd)
18620c794b3Sgavinm {
18720c794b3Sgavinm 	int rt = -1;
18820c794b3Sgavinm 	int nerr = 0;
18920c794b3Sgavinm 	uint32_t emask_fbd = 0;
19020c794b3Sgavinm 	int i;
19120c794b3Sgavinm 	int sz;
19220c794b3Sgavinm 
19320c794b3Sgavinm 	sz = sizeof (nf_fbd_error_code) / sizeof (struct mch_error_code);
19420c794b3Sgavinm 
19520c794b3Sgavinm 	for (i = 0; i < sz; i++) {
19620c794b3Sgavinm 		if (nf_fbd & nf_fbd_error_code[i].error_bit) {
19720c794b3Sgavinm 			rt = nf_fbd_error_code[i].intel_error_list;
19820c794b3Sgavinm 			emask_fbd |= nf_fbd_error_code[i].emask;
19920c794b3Sgavinm 			nerr++;
20020c794b3Sgavinm 		}
20120c794b3Sgavinm 	}
20220c794b3Sgavinm 	if (emask_fbd)
20320c794b3Sgavinm 		nb_fbd_mask_mc(emask_fbd);
20420c794b3Sgavinm 	if (nerr > 1)
20520c794b3Sgavinm 		rt = -1;
20620c794b3Sgavinm 	return (rt);
20720c794b3Sgavinm }
20820c794b3Sgavinm 
20920c794b3Sgavinm static char *
21020c794b3Sgavinm nf_memory_error(const nb_regs_t *rp, void *data)
21120c794b3Sgavinm {
21220c794b3Sgavinm 	uint32_t ferr_nf_fbd, recmemb, redmemb;
2135f28a827Saf 	uint32_t recmema;
21420c794b3Sgavinm 	int branch, channel, ecc_locator;
21520c794b3Sgavinm 	char *intr = "nb.unknown";
21620c794b3Sgavinm 	nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms;
21720c794b3Sgavinm 
21820c794b3Sgavinm 	sp->rank = -1;
21920c794b3Sgavinm 	sp->dimm = -1;
22020c794b3Sgavinm 	sp->bank = -1;
22120c794b3Sgavinm 	sp->cas = -1;
22220c794b3Sgavinm 	sp->ras = -1LL;
22320c794b3Sgavinm 	sp->pa = -1LL;
22420c794b3Sgavinm 	sp->offset = -1;
2256cb1ca52Saf 	ferr_nf_fbd = rp->nb.nf_fbd_regs.ferr_nf_fbd;
2266cb1ca52Saf 	if ((ferr_nf_fbd & ERR_NF_FBD_MASK) == 0) {
2276cb1ca52Saf 		sp->branch = -1;
2286cb1ca52Saf 		sp->channel = -1;
2296cb1ca52Saf 		sp->intel_error_list =
2306cb1ca52Saf 		    intel_nf_fbd_err(rp->nb.nf_fbd_regs.nerr_nf_fbd);
2316cb1ca52Saf 		return (intr);
2326cb1ca52Saf 	}
2336cb1ca52Saf 	sp->intel_error_list = intel_nf_fbd_err(ferr_nf_fbd);
2346cb1ca52Saf 	channel = (ferr_nf_fbd >> ERR_FBD_CH_SHIFT) & 3;
2356cb1ca52Saf 	branch = channel >> 1;
2366cb1ca52Saf 	sp->branch = branch;
2376cb1ca52Saf 	sp->channel = channel;
23820c794b3Sgavinm 	if (ferr_nf_fbd & ERR_NF_FBD_MASK) {
23920c794b3Sgavinm 		if (ferr_nf_fbd & ERR_NF_FBD_ECC_UE) {
24020c794b3Sgavinm 			/*
24120c794b3Sgavinm 			 * uncorrectable ECC M4 - M12
24220c794b3Sgavinm 			 * we can only isolate to pair of dimms
24320c794b3Sgavinm 			 * for single dimm configuration let eversholt
24420c794b3Sgavinm 			 * sort it out with out needing a special rule
24520c794b3Sgavinm 			 */
24620c794b3Sgavinm 			sp->channel = -1;
24720c794b3Sgavinm 			recmema = rp->nb.nf_fbd_regs.recmema;
24820c794b3Sgavinm 			recmemb = rp->nb.nf_fbd_regs.recmemb;
24920c794b3Sgavinm 			sp->rank = (recmema >> 8) & RANK_MASK;
25020c794b3Sgavinm 			sp->bank = (recmema >> 12) & BANK_MASK;
25120c794b3Sgavinm 			sp->cas = (recmemb >> 16) & CAS_MASK;
25220c794b3Sgavinm 			sp->ras = recmemb & RAS_MASK;
25320c794b3Sgavinm 			intr = "nb.mem_ue";
25420c794b3Sgavinm 		} else if (ferr_nf_fbd & ERR_NF_FBD_M13) {
25520c794b3Sgavinm 			/*
25620c794b3Sgavinm 			 * write error M13
25720c794b3Sgavinm 			 * we can only isolate to pair of dimms
25820c794b3Sgavinm 			 */
25920c794b3Sgavinm 			sp->channel = -1;
26020c794b3Sgavinm 			if (nb_mode != NB_MEMORY_MIRROR) {
26120c794b3Sgavinm 				recmema = rp->nb.nf_fbd_regs.recmema;
26220c794b3Sgavinm 				sp->rank = (recmema >> 8) & RANK_MASK;
26320c794b3Sgavinm 				sp->bank = (recmema >> 12) & BANK_MASK;
26420c794b3Sgavinm 				sp->cas = (recmemb >> 16) & CAS_MASK;
26520c794b3Sgavinm 				sp->ras = recmemb & RAS_MASK;
26620c794b3Sgavinm 			}
26720c794b3Sgavinm 			intr = "nb.fbd.ma"; /* memory alert */
26820c794b3Sgavinm 		} else if (ferr_nf_fbd & ERR_NF_FBD_MA) { /* M14, M15 and M21 */
26920c794b3Sgavinm 			intr = "nb.fbd.ch"; /* FBD on channel */
27020c794b3Sgavinm 		} else if ((ferr_nf_fbd & ERR_NF_FBD_ECC_CE) != 0) {
27120c794b3Sgavinm 			/* correctable ECC M17-M20 */
27220c794b3Sgavinm 			recmema = rp->nb.nf_fbd_regs.recmema;
27320c794b3Sgavinm 			recmemb = rp->nb.nf_fbd_regs.recmemb;
27420c794b3Sgavinm 			sp->rank = (recmema >> 8) & RANK_MASK;
27520c794b3Sgavinm 			redmemb = rp->nb.nf_fbd_regs.redmemb;
27620c794b3Sgavinm 			ecc_locator = redmemb & 0x3ffff;
27720c794b3Sgavinm 			if (ecc_locator & 0x1ff)
27820c794b3Sgavinm 				sp->channel = branch << 1;
27920c794b3Sgavinm 			else if (ecc_locator & 0x3fe00)
28020c794b3Sgavinm 				sp->channel = (branch << 1) + 1;
28120c794b3Sgavinm 			sp->dimm = sp->rank >> 1;
28220c794b3Sgavinm 			sp->bank = (recmema >> 12) & BANK_MASK;
28320c794b3Sgavinm 			sp->cas = (recmemb >> 16) & CAS_MASK;
28420c794b3Sgavinm 			sp->ras = recmemb & RAS_MASK;
28520c794b3Sgavinm 			intr = "nb.mem_ce";
28620c794b3Sgavinm 		} else if ((ferr_nf_fbd & ERR_NF_FBD_SPARE) != 0) {
28720c794b3Sgavinm 			/* spare dimm M27, M28 */
28820c794b3Sgavinm 			intr = "nb.mem_ds";
28920c794b3Sgavinm 			sp->channel = -1;
29020c794b3Sgavinm 			if (rp->nb.nf_fbd_regs.spcps & SPCPS_SPARE_DEPLOYED) {
29120c794b3Sgavinm 				sp->rank =
29220c794b3Sgavinm 				    SPCPS_FAILED_RANK(rp->nb.nf_fbd_regs.spcps);
29320c794b3Sgavinm 				nb_used_spare_rank(sp->branch, sp->rank);
29420c794b3Sgavinm 				nb_config_gen++;
29520c794b3Sgavinm 			}
2965f28a827Saf 		} else if ((ferr_nf_fbd & ERR_NF_FBD_M22) != 0) {
2975f28a827Saf 			intr = "nb.spd";	/* SPD protocol */
29820c794b3Sgavinm 		}
29920c794b3Sgavinm 	}
30020c794b3Sgavinm 	if (sp->ras != -1) {
30120c794b3Sgavinm 		sp->pa = dimm_getphys(sp->branch, sp->rank, sp->bank, sp->ras,
30220c794b3Sgavinm 		    sp->cas);
30320c794b3Sgavinm 		sp->offset = dimm_getoffset(sp->branch, sp->rank, sp->bank,
30420c794b3Sgavinm 		    sp->ras, sp->cas);
30520c794b3Sgavinm 	}
30620c794b3Sgavinm 	return (intr);
30720c794b3Sgavinm }
30820c794b3Sgavinm 
30920c794b3Sgavinm static struct mch_error_code fat_int_error_code[] = {
3105f28a827Saf 	{ 14, EMASK_INT_B14, ERR_FAT_INT_B14 },
3115f28a827Saf 	{ 12, EMASK_INT_B12, ERR_FAT_INT_B12 },
3125f28a827Saf 	{ 25, EMASK_INT_B25, ERR_FAT_INT_B25 },
3135f28a827Saf 	{ 23, EMASK_INT_B23, ERR_FAT_INT_B23 },
3145f28a827Saf 	{ 21, EMASK_INT_B21, ERR_FAT_INT_B21 },
3156cb1ca52Saf 	{ 7, EMASK_INT_B7, ERR_FAT_INT_B7 },
31620c794b3Sgavinm 	{ 4, EMASK_INT_B4, ERR_FAT_INT_B4 },
31720c794b3Sgavinm 	{ 3, EMASK_INT_B3, ERR_FAT_INT_B3 },
31820c794b3Sgavinm 	{ 2, EMASK_INT_B2, ERR_FAT_INT_B2 },
31920c794b3Sgavinm 	{ 1, EMASK_INT_B1, ERR_FAT_INT_B1 }
32020c794b3Sgavinm };
32120c794b3Sgavinm 
32220c794b3Sgavinm static struct mch_error_code nf_int_error_code[] = {
3235f28a827Saf 	{ 27, 0, ERR_NF_INT_B27 },
3245f28a827Saf 	{ 24, 0, ERR_NF_INT_B24 },
3255f28a827Saf 	{ 22, EMASK_INT_B22, ERR_NF_INT_B22 },
3265f28a827Saf 	{ 20, EMASK_INT_B20, ERR_NF_INT_B20 },
3275f28a827Saf 	{ 19, EMASK_INT_B19, ERR_NF_INT_B19 },
3285f28a827Saf 	{ 18, 0, ERR_NF_INT_B18 },
3295f28a827Saf 	{ 17, 0, ERR_NF_INT_B17 },
3305f28a827Saf 	{ 16, 0, ERR_NF_INT_B16 },
3315f28a827Saf 	{ 11, EMASK_INT_B11, ERR_NF_INT_B11 },
3325f28a827Saf 	{ 10, EMASK_INT_B10, ERR_NF_INT_B10 },
3335f28a827Saf 	{ 9, EMASK_INT_B9, ERR_NF_INT_B9 },
3346cb1ca52Saf 	{ 8, EMASK_INT_B8, ERR_NF_INT_B8 },
33520c794b3Sgavinm 	{ 6, EMASK_INT_B6, ERR_NF_INT_B6 },
33620c794b3Sgavinm 	{ 5, EMASK_INT_B5, ERR_NF_INT_B5 }
33720c794b3Sgavinm };
33820c794b3Sgavinm 
33920c794b3Sgavinm static int
3405f28a827Saf intel_int_err(uint16_t err_fat_int, uint16_t err_nf_int)
34120c794b3Sgavinm {
34220c794b3Sgavinm 	int rt = -1;
34320c794b3Sgavinm 	int nerr = 0;
3445f28a827Saf 	uint32_t emask_int = 0;
34520c794b3Sgavinm 	int i;
34620c794b3Sgavinm 	int sz;
34720c794b3Sgavinm 
34820c794b3Sgavinm 	sz = sizeof (fat_int_error_code) / sizeof (struct mch_error_code);
34920c794b3Sgavinm 
35020c794b3Sgavinm 	for (i = 0; i < sz; i++) {
3516cb1ca52Saf 		if (err_fat_int & fat_int_error_code[i].error_bit) {
35220c794b3Sgavinm 			rt = fat_int_error_code[i].intel_error_list;
35320c794b3Sgavinm 			emask_int |= fat_int_error_code[i].emask;
35420c794b3Sgavinm 			nerr++;
35520c794b3Sgavinm 		}
35620c794b3Sgavinm 	}
35720c794b3Sgavinm 
3585f28a827Saf 	if (nb_chipset == INTEL_NB_5400 &&
3595f28a827Saf 	    (err_nf_int & NERR_NF_5400_INT_B26) != 0) {
3605f28a827Saf 		err_nf_int &= ~NERR_NF_5400_INT_B26;
3615f28a827Saf 		rt = 26;
3625f28a827Saf 		nerr++;
3635f28a827Saf 	}
3645f28a827Saf 
3659ff4cbe7SAdrian Frost 	if (rt)
3669ff4cbe7SAdrian Frost 		err_nf_int &= ~ERR_NF_INT_B18;
3679ff4cbe7SAdrian Frost 
36820c794b3Sgavinm 	sz = sizeof (nf_int_error_code) / sizeof (struct mch_error_code);
36920c794b3Sgavinm 
37020c794b3Sgavinm 	for (i = 0; i < sz; i++) {
3716cb1ca52Saf 		if (err_nf_int & nf_int_error_code[i].error_bit) {
37220c794b3Sgavinm 			rt = nf_int_error_code[i].intel_error_list;
37320c794b3Sgavinm 			emask_int |= nf_int_error_code[i].emask;
37420c794b3Sgavinm 			nerr++;
37520c794b3Sgavinm 		}
37620c794b3Sgavinm 	}
37720c794b3Sgavinm 
37820c794b3Sgavinm 	if (emask_int)
37920c794b3Sgavinm 		nb_int_mask_mc(emask_int);
38020c794b3Sgavinm 	if (nerr > 1)
38120c794b3Sgavinm 		rt = -1;
38220c794b3Sgavinm 	return (rt);
38320c794b3Sgavinm }
38420c794b3Sgavinm 
3859ff4cbe7SAdrian Frost static int
3860ad0f0b2SAdrian Frost log_int_err(nb_regs_t *rp, int willpanic, int *interpose)
38720c794b3Sgavinm {
38820c794b3Sgavinm 	int t = 0;
3899ff4cbe7SAdrian Frost 	int rt = 0;
39020c794b3Sgavinm 
39120c794b3Sgavinm 	rp->flag = NB_REG_LOG_INT;
39220c794b3Sgavinm 	rp->nb.int_regs.ferr_fat_int = FERR_FAT_INT_RD(interpose);
39320c794b3Sgavinm 	rp->nb.int_regs.ferr_nf_int = FERR_NF_INT_RD(&t);
39420c794b3Sgavinm 	*interpose |= t;
39520c794b3Sgavinm 	rp->nb.int_regs.nerr_fat_int = NERR_FAT_INT_RD(&t);
39620c794b3Sgavinm 	*interpose |= t;
39720c794b3Sgavinm 	rp->nb.int_regs.nerr_nf_int = NERR_NF_INT_RD(&t);
39820c794b3Sgavinm 	*interpose |= t;
39920c794b3Sgavinm 	rp->nb.int_regs.nrecint = NRECINT_RD();
40020c794b3Sgavinm 	rp->nb.int_regs.recint = RECINT_RD();
40120c794b3Sgavinm 	rp->nb.int_regs.nrecsf = NRECSF_RD();
40220c794b3Sgavinm 	rp->nb.int_regs.recsf = RECSF_RD();
40320c794b3Sgavinm 
4040ad0f0b2SAdrian Frost 	if (!willpanic) {
4050ad0f0b2SAdrian Frost 		if (rp->nb.int_regs.ferr_fat_int || *interpose)
4060ad0f0b2SAdrian Frost 			FERR_FAT_INT_WR(rp->nb.int_regs.ferr_fat_int);
4070ad0f0b2SAdrian Frost 		if (rp->nb.int_regs.ferr_nf_int || *interpose)
4080ad0f0b2SAdrian Frost 			FERR_NF_INT_WR(rp->nb.int_regs.ferr_nf_int);
4090ad0f0b2SAdrian Frost 		if (rp->nb.int_regs.nerr_fat_int)
4100ad0f0b2SAdrian Frost 			NERR_FAT_INT_WR(rp->nb.int_regs.nerr_fat_int);
4110ad0f0b2SAdrian Frost 		if (rp->nb.int_regs.nerr_nf_int)
4120ad0f0b2SAdrian Frost 			NERR_NF_INT_WR(rp->nb.int_regs.nerr_nf_int);
4130ad0f0b2SAdrian Frost 		/*
4140ad0f0b2SAdrian Frost 		 * if interpose write read-only registers to clear from pcii
4150ad0f0b2SAdrian Frost 		 * cache
4160ad0f0b2SAdrian Frost 		 */
4170ad0f0b2SAdrian Frost 		if (*interpose) {
4180ad0f0b2SAdrian Frost 			NRECINT_WR();
4190ad0f0b2SAdrian Frost 			RECINT_WR();
4200ad0f0b2SAdrian Frost 			NRECSF_WR();
4210ad0f0b2SAdrian Frost 			RECSF_WR();
4220ad0f0b2SAdrian Frost 		}
42320c794b3Sgavinm 	}
4249ff4cbe7SAdrian Frost 	if (rp->nb.int_regs.ferr_fat_int == 0 &&
4259ff4cbe7SAdrian Frost 	    rp->nb.int_regs.nerr_fat_int == 0 &&
4269ff4cbe7SAdrian Frost 	    (rp->nb.int_regs.ferr_nf_int == ERR_NF_INT_B18 ||
4279ff4cbe7SAdrian Frost 	    (rp->nb.int_regs.ferr_nf_int == 0 &&
4289ff4cbe7SAdrian Frost 	    rp->nb.int_regs.nerr_nf_int == ERR_NF_INT_B18))) {
4299ff4cbe7SAdrian Frost 		rt = 1;
4309ff4cbe7SAdrian Frost 	}
4319ff4cbe7SAdrian Frost 	return (rt);
43220c794b3Sgavinm }
43320c794b3Sgavinm 
4345f28a827Saf static void
4350ad0f0b2SAdrian Frost log_thermal_err(nb_regs_t *rp, int willpanic, int *interpose)
4365f28a827Saf {
4375f28a827Saf 	int t = 0;
4385f28a827Saf 
4395f28a827Saf 	rp->flag = NB_REG_LOG_THR;
4405f28a827Saf 	rp->nb.thr_regs.ferr_fat_thr = FERR_FAT_THR_RD(interpose);
4415f28a827Saf 	rp->nb.thr_regs.nerr_fat_thr = NERR_FAT_THR_RD(&t);
4425f28a827Saf 	*interpose |= t;
4435f28a827Saf 	rp->nb.thr_regs.ferr_nf_thr = FERR_NF_THR_RD(&t);
4445f28a827Saf 	*interpose |= t;
4455f28a827Saf 	rp->nb.thr_regs.nerr_nf_thr = NERR_NF_THR_RD(&t);
4465f28a827Saf 	*interpose |= t;
4475f28a827Saf 	rp->nb.thr_regs.ctsts = CTSTS_RD();
4485f28a827Saf 	rp->nb.thr_regs.thrtsts = THRTSTS_RD();
4495f28a827Saf 
4500ad0f0b2SAdrian Frost 	if (!willpanic) {
4510ad0f0b2SAdrian Frost 		if (rp->nb.thr_regs.ferr_fat_thr || *interpose)
4520ad0f0b2SAdrian Frost 			FERR_FAT_THR_WR(rp->nb.thr_regs.ferr_fat_thr);
4530ad0f0b2SAdrian Frost 		if (rp->nb.thr_regs.nerr_fat_thr || *interpose)
4540ad0f0b2SAdrian Frost 			NERR_FAT_THR_WR(rp->nb.thr_regs.nerr_fat_thr);
4550ad0f0b2SAdrian Frost 		if (rp->nb.thr_regs.ferr_nf_thr || *interpose)
4560ad0f0b2SAdrian Frost 			FERR_NF_THR_WR(rp->nb.thr_regs.ferr_nf_thr);
4570ad0f0b2SAdrian Frost 		if (rp->nb.thr_regs.nerr_nf_thr || *interpose)
4580ad0f0b2SAdrian Frost 			NERR_NF_THR_WR(rp->nb.thr_regs.nerr_nf_thr);
4590ad0f0b2SAdrian Frost 
4600ad0f0b2SAdrian Frost 		if (*interpose) {
4610ad0f0b2SAdrian Frost 			CTSTS_WR(rp->nb.thr_regs.ctsts);
4620ad0f0b2SAdrian Frost 			THRTSTS_WR(rp->nb.thr_regs.thrtsts);
4630ad0f0b2SAdrian Frost 		}
4645f28a827Saf 	}
4655f28a827Saf }
4665f28a827Saf 
46720c794b3Sgavinm static void
46820c794b3Sgavinm log_dma_err(nb_regs_t *rp, int *interpose)
46920c794b3Sgavinm {
47020c794b3Sgavinm 	rp->flag = NB_REG_LOG_DMA;
47120c794b3Sgavinm 
47220c794b3Sgavinm 	rp->nb.dma_regs.pcists = PCISTS_RD(interpose);
47320c794b3Sgavinm 	rp->nb.dma_regs.pexdevsts = PCIDEVSTS_RD();
47420c794b3Sgavinm }
47520c794b3Sgavinm 
4766cb1ca52Saf static struct mch_error_code fat_fsb_error_code[] = {
4776cb1ca52Saf 	{ 9, EMASK_FSB_F9, ERR_FAT_FSB_F9 },
4786cb1ca52Saf 	{ 2, EMASK_FSB_F2, ERR_FAT_FSB_F2 },
4796cb1ca52Saf 	{ 1, EMASK_FSB_F1, ERR_FAT_FSB_F1 }
4806cb1ca52Saf };
4816cb1ca52Saf 
4826cb1ca52Saf static struct mch_error_code nf_fsb_error_code[] = {
4836cb1ca52Saf 	{ 8, EMASK_FSB_F8, ERR_NF_FSB_F8 },
4846cb1ca52Saf 	{ 7, EMASK_FSB_F7, ERR_NF_FSB_F7 },
4856cb1ca52Saf 	{ 6, EMASK_FSB_F6, ERR_NF_FSB_F6 }
4866cb1ca52Saf };
4876cb1ca52Saf 
48820c794b3Sgavinm static int
4896cb1ca52Saf intel_fsb_err(int fsb, uint8_t err_fat_fsb, uint8_t err_nf_fsb)
49020c794b3Sgavinm {
49120c794b3Sgavinm 	int rt = -1;
49220c794b3Sgavinm 	int nerr = 0;
49320c794b3Sgavinm 	uint16_t emask_fsb = 0;
4946cb1ca52Saf 	int i;
4956cb1ca52Saf 	int sz;
49620c794b3Sgavinm 
4976cb1ca52Saf 	sz = sizeof (fat_fsb_error_code) / sizeof (struct mch_error_code);
4986cb1ca52Saf 
4996cb1ca52Saf 	for (i = 0; i < sz; i++) {
5006cb1ca52Saf 		if (err_fat_fsb & fat_fsb_error_code[i].error_bit) {
5016cb1ca52Saf 			rt = fat_fsb_error_code[i].intel_error_list;
5026cb1ca52Saf 			emask_fsb |= fat_fsb_error_code[i].emask;
5036cb1ca52Saf 			nerr++;
5046cb1ca52Saf 		}
50520c794b3Sgavinm 	}
5066cb1ca52Saf 
5076cb1ca52Saf 	sz = sizeof (nf_fsb_error_code) / sizeof (struct mch_error_code);
5086cb1ca52Saf 
5096cb1ca52Saf 	for (i = 0; i < sz; i++) {
5106cb1ca52Saf 		if (err_nf_fsb & nf_fsb_error_code[i].error_bit) {
5116cb1ca52Saf 			rt = nf_fsb_error_code[i].intel_error_list;
5126cb1ca52Saf 			emask_fsb |= nf_fsb_error_code[i].emask;
5136cb1ca52Saf 			nerr++;
5146cb1ca52Saf 		}
51520c794b3Sgavinm 	}
5166cb1ca52Saf 
51720c794b3Sgavinm 	if (emask_fsb)
51820c794b3Sgavinm 		nb_fsb_mask_mc(fsb, emask_fsb);
51920c794b3Sgavinm 	if (nerr > 1)
52020c794b3Sgavinm 		rt = -1;
52120c794b3Sgavinm 	return (rt);
52220c794b3Sgavinm }
52320c794b3Sgavinm 
52420c794b3Sgavinm static void
5250ad0f0b2SAdrian Frost log_fsb_err(uint64_t ferr, nb_regs_t *rp, int willpanic, int *interpose)
52620c794b3Sgavinm {
52720c794b3Sgavinm 	uint8_t fsb;
52820c794b3Sgavinm 	int t = 0;
52920c794b3Sgavinm 
53020c794b3Sgavinm 	fsb = GE_FERR_FSB(ferr);
53120c794b3Sgavinm 	rp->flag = NB_REG_LOG_FSB;
53220c794b3Sgavinm 
53320c794b3Sgavinm 	rp->nb.fsb_regs.fsb = fsb;
53420c794b3Sgavinm 	rp->nb.fsb_regs.ferr_fat_fsb = FERR_FAT_FSB_RD(fsb, interpose);
53520c794b3Sgavinm 	rp->nb.fsb_regs.ferr_nf_fsb = FERR_NF_FSB_RD(fsb, &t);
53620c794b3Sgavinm 	*interpose |= t;
53720c794b3Sgavinm 	rp->nb.fsb_regs.nerr_fat_fsb = NERR_FAT_FSB_RD(fsb, &t);
53820c794b3Sgavinm 	*interpose |= t;
53920c794b3Sgavinm 	rp->nb.fsb_regs.nerr_nf_fsb = NERR_NF_FSB_RD(fsb, &t);
54020c794b3Sgavinm 	*interpose |= t;
54120c794b3Sgavinm 	rp->nb.fsb_regs.nrecfsb = NRECFSB_RD(fsb);
54220c794b3Sgavinm 	rp->nb.fsb_regs.nrecfsb_addr = NRECADDR_RD(fsb);
54320c794b3Sgavinm 	rp->nb.fsb_regs.recfsb = RECFSB_RD(fsb);
5440ad0f0b2SAdrian Frost 	if (!willpanic) {
545*2d532312SVuong Nguyen 		/* Clear the fatal/non-fatal first/next FSB errors */
5460ad0f0b2SAdrian Frost 		if (rp->nb.fsb_regs.ferr_fat_fsb || *interpose)
5470ad0f0b2SAdrian Frost 			FERR_FAT_FSB_WR(fsb, rp->nb.fsb_regs.ferr_fat_fsb);
5480ad0f0b2SAdrian Frost 		if (rp->nb.fsb_regs.ferr_nf_fsb || *interpose)
5490ad0f0b2SAdrian Frost 			FERR_NF_FSB_WR(fsb, rp->nb.fsb_regs.ferr_nf_fsb);
550*2d532312SVuong Nguyen 		if (rp->nb.fsb_regs.nerr_fat_fsb || *interpose)
551*2d532312SVuong Nguyen 			NERR_FAT_FSB_WR(fsb, rp->nb.fsb_regs.nerr_fat_fsb);
552*2d532312SVuong Nguyen 		if (rp->nb.fsb_regs.nerr_nf_fsb || *interpose)
553*2d532312SVuong Nguyen 			NERR_NF_FSB_WR(fsb, rp->nb.fsb_regs.nerr_nf_fsb);
554*2d532312SVuong Nguyen 
5550ad0f0b2SAdrian Frost 		/*
5560ad0f0b2SAdrian Frost 		 * if interpose write read-only registers to clear from pcii
5570ad0f0b2SAdrian Frost 		 * cache
5580ad0f0b2SAdrian Frost 		 */
5590ad0f0b2SAdrian Frost 		if (*interpose) {
5600ad0f0b2SAdrian Frost 			NRECFSB_WR(fsb);
5610ad0f0b2SAdrian Frost 			NRECADDR_WR(fsb);
5620ad0f0b2SAdrian Frost 			RECFSB_WR(fsb);
5630ad0f0b2SAdrian Frost 		}
56420c794b3Sgavinm 	}
56520c794b3Sgavinm }
56620c794b3Sgavinm 
56720c794b3Sgavinm static struct mch_error_code fat_pex_error_code[] = {
56820c794b3Sgavinm 	{ 19, EMASK_UNCOR_PEX_IO19, PEX_FAT_IO19 },
56920c794b3Sgavinm 	{ 18, EMASK_UNCOR_PEX_IO18, PEX_FAT_IO18 },
57020c794b3Sgavinm 	{ 10, EMASK_UNCOR_PEX_IO10, PEX_FAT_IO10 },
57120c794b3Sgavinm 	{ 9, EMASK_UNCOR_PEX_IO9, PEX_FAT_IO9 },
57220c794b3Sgavinm 	{ 8, EMASK_UNCOR_PEX_IO8, PEX_FAT_IO8 },
57320c794b3Sgavinm 	{ 7, EMASK_UNCOR_PEX_IO7, PEX_FAT_IO7 },
57420c794b3Sgavinm 	{ 6, EMASK_UNCOR_PEX_IO6, PEX_FAT_IO6 },
57520c794b3Sgavinm 	{ 5, EMASK_UNCOR_PEX_IO5, PEX_FAT_IO5 },
57620c794b3Sgavinm 	{ 4, EMASK_UNCOR_PEX_IO4, PEX_FAT_IO4 },
57720c794b3Sgavinm 	{ 3, EMASK_UNCOR_PEX_IO3, PEX_FAT_IO3 },
57820c794b3Sgavinm 	{ 2, EMASK_UNCOR_PEX_IO2, PEX_FAT_IO2 },
57920c794b3Sgavinm 	{ 0, EMASK_UNCOR_PEX_IO0, PEX_FAT_IO0 }
58020c794b3Sgavinm };
58120c794b3Sgavinm 
5825f28a827Saf static struct mch_error_code fat_unit_pex_5400_error_code[] = {
5835f28a827Saf 	{ 32, EMASK_UNIT_PEX_IO32, PEX_5400_FAT_IO32 },
5845f28a827Saf 	{ 31, EMASK_UNIT_PEX_IO31, PEX_5400_FAT_IO31 },
5855f28a827Saf 	{ 30, EMASK_UNIT_PEX_IO30, PEX_5400_FAT_IO30 },
5865f28a827Saf 	{ 29, EMASK_UNIT_PEX_IO29, PEX_5400_FAT_IO29 },
5875f28a827Saf 	{ 27, EMASK_UNIT_PEX_IO27, PEX_5400_FAT_IO27 },
5885f28a827Saf 	{ 26, EMASK_UNIT_PEX_IO26, PEX_5400_FAT_IO26 },
5895f28a827Saf 	{ 25, EMASK_UNIT_PEX_IO25, PEX_5400_FAT_IO25 },
5905f28a827Saf 	{ 24, EMASK_UNIT_PEX_IO24, PEX_5400_FAT_IO24 },
5915f28a827Saf 	{ 23, EMASK_UNIT_PEX_IO23, PEX_5400_FAT_IO23 },
5925f28a827Saf 	{ 22, EMASK_UNIT_PEX_IO22, PEX_5400_FAT_IO22 },
5935f28a827Saf };
5945f28a827Saf 
5955f28a827Saf static struct mch_error_code fat_pex_5400_error_code[] = {
5965f28a827Saf 	{ 19, EMASK_UNCOR_PEX_IO19, PEX_5400_FAT_IO19 },
5975f28a827Saf 	{ 18, EMASK_UNCOR_PEX_IO18, PEX_5400_FAT_IO18 },
5985f28a827Saf 	{ 10, EMASK_UNCOR_PEX_IO10, PEX_5400_FAT_IO10 },
5995f28a827Saf 	{ 9, EMASK_UNCOR_PEX_IO9, PEX_5400_FAT_IO9 },
6005f28a827Saf 	{ 8, EMASK_UNCOR_PEX_IO8, PEX_5400_FAT_IO8 },
6015f28a827Saf 	{ 7, EMASK_UNCOR_PEX_IO7, PEX_5400_FAT_IO7 },
6025f28a827Saf 	{ 6, EMASK_UNCOR_PEX_IO6, PEX_5400_FAT_IO6 },
6035f28a827Saf 	{ 5, EMASK_UNCOR_PEX_IO5, PEX_5400_FAT_IO5 },
6045f28a827Saf 	{ 4, EMASK_UNCOR_PEX_IO4, PEX_5400_FAT_IO4 },
6055f28a827Saf 	{ 2, EMASK_UNCOR_PEX_IO2, PEX_5400_FAT_IO2 },
6065f28a827Saf 	{ 0, EMASK_UNCOR_PEX_IO0, PEX_5400_FAT_IO0 }
6075f28a827Saf };
6085f28a827Saf 
6095f28a827Saf static struct mch_error_code fat_rp_5400_error_code[] = {
6105f28a827Saf 	{ 1, EMASK_RP_PEX_IO1, PEX_5400_FAT_IO1 }
6115f28a827Saf };
6125f28a827Saf 
61320c794b3Sgavinm static struct mch_error_code fat_rp_error_code[] = {
61420c794b3Sgavinm 	{ 1, EMASK_RP_PEX_IO1, PEX_FAT_IO1 }
61520c794b3Sgavinm };
61620c794b3Sgavinm 
61720c794b3Sgavinm static struct mch_error_code uncor_pex_error_code[] = {
61820c794b3Sgavinm 	{ 19, EMASK_UNCOR_PEX_IO19, PEX_NF_IO19 },
61920c794b3Sgavinm 	{ 9, EMASK_UNCOR_PEX_IO9, PEX_NF_IO9 },
62020c794b3Sgavinm 	{ 8, EMASK_UNCOR_PEX_IO8, PEX_NF_IO8 },
62120c794b3Sgavinm 	{ 7, EMASK_UNCOR_PEX_IO7, PEX_NF_IO7 },
62220c794b3Sgavinm 	{ 6, EMASK_UNCOR_PEX_IO6, PEX_NF_IO6 },
62320c794b3Sgavinm 	{ 5, EMASK_UNCOR_PEX_IO5, PEX_NF_IO5 },
62420c794b3Sgavinm 	{ 4, EMASK_UNCOR_PEX_IO4, PEX_NF_IO4 },
62520c794b3Sgavinm 	{ 3, EMASK_UNCOR_PEX_IO3, PEX_NF_IO3 },
62620c794b3Sgavinm 	{ 0, EMASK_UNCOR_PEX_IO0, PEX_NF_IO0 }
62720c794b3Sgavinm };
62820c794b3Sgavinm 
6295f28a827Saf static struct mch_error_code uncor_pex_5400_error_code[] = {
6305f28a827Saf 	{ 33, EMASK_UNIT_PEX_IO33, PEX_5400_NF_IO33 },
6315f28a827Saf 	{ 32, EMASK_UNIT_PEX_IO32, PEX_5400_NF_IO32 },
6325f28a827Saf 	{ 31, EMASK_UNIT_PEX_IO31, PEX_5400_NF_IO31 },
6335f28a827Saf 	{ 30, EMASK_UNIT_PEX_IO30, PEX_5400_NF_IO30 },
6345f28a827Saf 	{ 29, EMASK_UNIT_PEX_IO29, PEX_5400_NF_IO29 },
6355f28a827Saf 	{ 28, EMASK_UNIT_PEX_IO28, PEX_5400_NF_IO28 },
6365f28a827Saf 	{ 27, EMASK_UNIT_PEX_IO27, PEX_5400_NF_IO27 },
6375f28a827Saf 	{ 26, EMASK_UNIT_PEX_IO26, PEX_5400_NF_IO26 },
6385f28a827Saf 	{ 25, EMASK_UNIT_PEX_IO25, PEX_5400_NF_IO25 },
6395f28a827Saf 	{ 24, EMASK_UNIT_PEX_IO24, PEX_5400_NF_IO24 },
6405f28a827Saf 	{ 23, EMASK_UNIT_PEX_IO23, PEX_5400_NF_IO23 },
6415f28a827Saf };
6425f28a827Saf 
64320c794b3Sgavinm static struct mch_error_code cor_pex_error_code[] = {
6445f28a827Saf 	{ 20, EMASK_COR_PEX_IO20, PEX_5400_NF_IO20 },
64520c794b3Sgavinm 	{ 16, EMASK_COR_PEX_IO16, PEX_NF_IO16 },
64620c794b3Sgavinm 	{ 15, EMASK_COR_PEX_IO15, PEX_NF_IO15 },
64720c794b3Sgavinm 	{ 14, EMASK_COR_PEX_IO14, PEX_NF_IO14 },
64820c794b3Sgavinm 	{ 13, EMASK_COR_PEX_IO13, PEX_NF_IO13 },
64920c794b3Sgavinm 	{ 12, EMASK_COR_PEX_IO12, PEX_NF_IO12 },
65020c794b3Sgavinm 	{ 10, 0, PEX_NF_IO10 },
65120c794b3Sgavinm 	{ 2, 0, PEX_NF_IO2 }
65220c794b3Sgavinm };
65320c794b3Sgavinm 
6545f28a827Saf static struct mch_error_code rp_pex_5400_error_code[] = {
6555f28a827Saf 	{ 17, EMASK_RP_PEX_IO17, PEX_5400_NF_IO17 },
6565f28a827Saf 	{ 11, EMASK_RP_PEX_IO11, PEX_5400_NF_IO11 }
6575f28a827Saf };
6585f28a827Saf 
6595f28a827Saf static struct mch_error_code cor_pex_5400_error_code1[] = {
6605f28a827Saf 	{ 19, EMASK_UNCOR_PEX_IO19, PEX_5400_NF_IO19 },
6615f28a827Saf 	{ 10, EMASK_UNCOR_PEX_IO10, PEX_5400_NF_IO10 },
6625f28a827Saf 	{ 9, EMASK_UNCOR_PEX_IO9, PEX_5400_NF_IO9 },
6635f28a827Saf 	{ 8, EMASK_UNCOR_PEX_IO8, PEX_5400_NF_IO8 },
6645f28a827Saf 	{ 7, EMASK_UNCOR_PEX_IO7, PEX_5400_NF_IO7 },
6655f28a827Saf 	{ 6, EMASK_UNCOR_PEX_IO6, PEX_5400_NF_IO6 },
6665f28a827Saf 	{ 5, EMASK_UNCOR_PEX_IO5, PEX_5400_NF_IO5 },
6675f28a827Saf 	{ 4, EMASK_UNCOR_PEX_IO4, PEX_5400_NF_IO4 },
6685f28a827Saf 	{ 2, EMASK_UNCOR_PEX_IO2, PEX_5400_NF_IO2 },
6695f28a827Saf 	{ 0, EMASK_UNCOR_PEX_IO0, PEX_5400_NF_IO0 }
6705f28a827Saf };
6715f28a827Saf 
6725f28a827Saf static struct mch_error_code cor_pex_5400_error_code2[] = {
6735f28a827Saf 	{ 20, EMASK_COR_PEX_IO20, PEX_5400_NF_IO20 },
6745f28a827Saf 	{ 16, EMASK_COR_PEX_IO16, PEX_5400_NF_IO16 },
6755f28a827Saf 	{ 15, EMASK_COR_PEX_IO15, PEX_5400_NF_IO15 },
6765f28a827Saf 	{ 14, EMASK_COR_PEX_IO14, PEX_5400_NF_IO14 },
6775f28a827Saf 	{ 13, EMASK_COR_PEX_IO13, PEX_5400_NF_IO13 },
6785f28a827Saf 	{ 12, EMASK_COR_PEX_IO12, PEX_5400_NF_IO12 }
6795f28a827Saf };
6805f28a827Saf 
6815f28a827Saf static struct mch_error_code cor_pex_5400_error_code3[] = {
6825f28a827Saf 	{ 33, EMASK_UNIT_PEX_IO33, PEX_5400_NF_IO33 },
6835f28a827Saf 	{ 32, EMASK_UNIT_PEX_IO32, PEX_5400_NF_IO32 },
6845f28a827Saf 	{ 31, EMASK_UNIT_PEX_IO31, PEX_5400_NF_IO31 },
6855f28a827Saf 	{ 30, EMASK_UNIT_PEX_IO30, PEX_5400_NF_IO30 },
6865f28a827Saf 	{ 29, EMASK_UNIT_PEX_IO29, PEX_5400_NF_IO29 },
6875f28a827Saf 	{ 28, EMASK_UNIT_PEX_IO28, PEX_5400_NF_IO28 },
6885f28a827Saf 	{ 27, EMASK_UNIT_PEX_IO27, PEX_5400_NF_IO27 },
6895f28a827Saf 	{ 26, EMASK_UNIT_PEX_IO26, PEX_5400_NF_IO26 },
6905f28a827Saf 	{ 25, EMASK_UNIT_PEX_IO25, PEX_5400_NF_IO25 },
6915f28a827Saf 	{ 24, EMASK_UNIT_PEX_IO24, PEX_5400_NF_IO24 },
6925f28a827Saf 	{ 23, EMASK_UNIT_PEX_IO23, PEX_5400_NF_IO23 }
6935f28a827Saf };
6945f28a827Saf 
69520c794b3Sgavinm static struct mch_error_code rp_pex_error_code[] = {
69620c794b3Sgavinm 	{ 17, EMASK_RP_PEX_IO17, PEX_NF_IO17 },
69720c794b3Sgavinm 	{ 11, EMASK_RP_PEX_IO11, PEX_NF_IO11 },
69820c794b3Sgavinm };
69920c794b3Sgavinm 
70020c794b3Sgavinm static int
70120c794b3Sgavinm intel_pex_err(uint32_t pex_fat, uint32_t pex_nf_cor)
70220c794b3Sgavinm {
70320c794b3Sgavinm 	int rt = -1;
70420c794b3Sgavinm 	int nerr = 0;
70520c794b3Sgavinm 	int i;
70620c794b3Sgavinm 	int sz;
70720c794b3Sgavinm 
70820c794b3Sgavinm 	sz = sizeof (fat_pex_error_code) / sizeof (struct mch_error_code);
70920c794b3Sgavinm 
71020c794b3Sgavinm 	for (i = 0; i < sz; i++) {
71120c794b3Sgavinm 		if (pex_fat & fat_pex_error_code[i].error_bit) {
71220c794b3Sgavinm 			rt = fat_pex_error_code[i].intel_error_list;
71320c794b3Sgavinm 			nerr++;
71420c794b3Sgavinm 		}
71520c794b3Sgavinm 	}
71620c794b3Sgavinm 	sz = sizeof (fat_rp_error_code) / sizeof (struct mch_error_code);
71720c794b3Sgavinm 
71820c794b3Sgavinm 	for (i = 0; i < sz; i++) {
71920c794b3Sgavinm 		if (pex_fat & fat_rp_error_code[i].error_bit) {
72020c794b3Sgavinm 			rt = fat_rp_error_code[i].intel_error_list;
72120c794b3Sgavinm 			nerr++;
72220c794b3Sgavinm 		}
72320c794b3Sgavinm 	}
72420c794b3Sgavinm 	sz = sizeof (uncor_pex_error_code) / sizeof (struct mch_error_code);
72520c794b3Sgavinm 
72620c794b3Sgavinm 	for (i = 0; i < sz; i++) {
72720c794b3Sgavinm 		if (pex_nf_cor & uncor_pex_error_code[i].error_bit) {
72820c794b3Sgavinm 			rt = uncor_pex_error_code[i].intel_error_list;
72920c794b3Sgavinm 			nerr++;
73020c794b3Sgavinm 		}
73120c794b3Sgavinm 	}
73220c794b3Sgavinm 
73320c794b3Sgavinm 	sz = sizeof (cor_pex_error_code) / sizeof (struct mch_error_code);
73420c794b3Sgavinm 
73520c794b3Sgavinm 	for (i = 0; i < sz; i++) {
73620c794b3Sgavinm 		if (pex_nf_cor & cor_pex_error_code[i].error_bit) {
73720c794b3Sgavinm 			rt = cor_pex_error_code[i].intel_error_list;
73820c794b3Sgavinm 			nerr++;
73920c794b3Sgavinm 		}
74020c794b3Sgavinm 	}
74120c794b3Sgavinm 	sz = sizeof (rp_pex_error_code) / sizeof (struct mch_error_code);
74220c794b3Sgavinm 
74320c794b3Sgavinm 	for (i = 0; i < sz; i++) {
74420c794b3Sgavinm 		if (pex_nf_cor & rp_pex_error_code[i].error_bit) {
74520c794b3Sgavinm 			rt = rp_pex_error_code[i].intel_error_list;
74620c794b3Sgavinm 			nerr++;
74720c794b3Sgavinm 		}
74820c794b3Sgavinm 	}
74920c794b3Sgavinm 
75020c794b3Sgavinm 	if (nerr > 1)
75120c794b3Sgavinm 		rt = -1;
75220c794b3Sgavinm 	return (rt);
75320c794b3Sgavinm }
7545f28a827Saf 
7555f28a827Saf static struct mch_error_code fat_thr_error_code[] = {
7565f28a827Saf 	{ 2, EMASK_THR_F2, ERR_FAT_THR_F2 },
7575f28a827Saf 	{ 1, EMASK_THR_F1, ERR_FAT_THR_F1 }
7585f28a827Saf };
7595f28a827Saf 
7605f28a827Saf static struct mch_error_code nf_thr_error_code[] = {
7615f28a827Saf 	{ 5, EMASK_THR_F5, ERR_NF_THR_F5 },
7625f28a827Saf 	{ 4, EMASK_THR_F4, ERR_NF_THR_F4 },
7635f28a827Saf 	{ 3, EMASK_THR_F3, ERR_NF_THR_F3 }
7645f28a827Saf };
7655f28a827Saf 
7665f28a827Saf static int
7675f28a827Saf intel_thr_err(uint8_t err_fat_thr, uint8_t err_nf_thr)
7685f28a827Saf {
7695f28a827Saf 	int rt = -1;
7705f28a827Saf 	int nerr = 0;
7715f28a827Saf 	uint16_t emask_thr = 0;
7725f28a827Saf 	int i;
7735f28a827Saf 	int sz;
7745f28a827Saf 
7755f28a827Saf 	sz = sizeof (fat_thr_error_code) / sizeof (struct mch_error_code);
7765f28a827Saf 
7775f28a827Saf 	for (i = 0; i < sz; i++) {
7785f28a827Saf 		if (err_fat_thr & fat_thr_error_code[i].error_bit) {
7795f28a827Saf 			rt = fat_thr_error_code[i].intel_error_list;
7805f28a827Saf 			emask_thr |= fat_thr_error_code[i].emask;
7815f28a827Saf 			nerr++;
7825f28a827Saf 		}
7835f28a827Saf 	}
7845f28a827Saf 
7855f28a827Saf 	sz = sizeof (nf_thr_error_code) / sizeof (struct mch_error_code);
7865f28a827Saf 
7875f28a827Saf 	for (i = 0; i < sz; i++) {
7885f28a827Saf 		if (err_nf_thr & nf_thr_error_code[i].error_bit) {
7895f28a827Saf 			rt = nf_thr_error_code[i].intel_error_list;
7905f28a827Saf 			emask_thr |= nf_thr_error_code[i].emask;
7915f28a827Saf 			nerr++;
7925f28a827Saf 		}
7935f28a827Saf 	}
7945f28a827Saf 
7955f28a827Saf 	if (emask_thr)
7965f28a827Saf 		nb_thr_mask_mc(emask_thr);
7975f28a827Saf 	if (nerr > 1)
7985f28a827Saf 		rt = -1;
7995f28a827Saf 	return (rt);
8005f28a827Saf }
8015f28a827Saf 
8025f28a827Saf static int
8035f28a827Saf intel_pex_5400_err(uint32_t pex_fat, uint32_t pex_nf_cor)
8045f28a827Saf {
8055f28a827Saf 	int rt = -1;
8065f28a827Saf 	int nerr = 0;
8075f28a827Saf 	int i;
8085f28a827Saf 	int sz;
8095f28a827Saf 
8105f28a827Saf 	sz = sizeof (fat_pex_5400_error_code) / sizeof (struct mch_error_code);
8115f28a827Saf 
8125f28a827Saf 	for (i = 0; i < sz; i++) {
8135f28a827Saf 		if (pex_fat & fat_pex_5400_error_code[i].error_bit) {
8145f28a827Saf 			rt = fat_pex_5400_error_code[i].intel_error_list;
8155f28a827Saf 			nerr++;
8165f28a827Saf 		}
8175f28a827Saf 	}
8185f28a827Saf 	sz = sizeof (fat_rp_5400_error_code) / sizeof (struct mch_error_code);
8195f28a827Saf 
8205f28a827Saf 	for (i = 0; i < sz; i++) {
8215f28a827Saf 		if (pex_fat & fat_rp_5400_error_code[i].error_bit) {
8225f28a827Saf 			rt = fat_rp_5400_error_code[i].intel_error_list;
8235f28a827Saf 			nerr++;
8245f28a827Saf 		}
8255f28a827Saf 	}
8265f28a827Saf 	sz = sizeof (fat_unit_pex_5400_error_code) /
8275f28a827Saf 	    sizeof (struct mch_error_code);
8285f28a827Saf 
8295f28a827Saf 	for (i = 0; i < sz; i++) {
8305f28a827Saf 		if (pex_fat &
8315f28a827Saf 		    fat_unit_pex_5400_error_code[i].error_bit) {
8325f28a827Saf 			rt = fat_unit_pex_5400_error_code[i].intel_error_list;
8335f28a827Saf 			nerr++;
8345f28a827Saf 		}
8355f28a827Saf 	}
8365f28a827Saf 	sz = sizeof (uncor_pex_5400_error_code) /
8375f28a827Saf 	    sizeof (struct mch_error_code);
8385f28a827Saf 
8395f28a827Saf 	for (i = 0; i < sz; i++) {
8405f28a827Saf 		if (pex_fat & uncor_pex_5400_error_code[i].error_bit) {
8415f28a827Saf 			rt = uncor_pex_5400_error_code[i].intel_error_list;
8425f28a827Saf 			nerr++;
8435f28a827Saf 		}
8445f28a827Saf 	}
8455f28a827Saf 
8465f28a827Saf 	sz = sizeof (rp_pex_5400_error_code) / sizeof (struct mch_error_code);
8475f28a827Saf 
8485f28a827Saf 	for (i = 0; i < sz; i++) {
8495f28a827Saf 		if (pex_nf_cor & rp_pex_5400_error_code[i].error_bit) {
8505f28a827Saf 			rt = rp_pex_5400_error_code[i].intel_error_list;
8515f28a827Saf 			nerr++;
8525f28a827Saf 		}
8535f28a827Saf 	}
8545f28a827Saf 
8555f28a827Saf 	sz = sizeof (cor_pex_5400_error_code1) / sizeof (struct mch_error_code);
8565f28a827Saf 
8575f28a827Saf 	for (i = 0; i < sz; i++) {
8585f28a827Saf 		if (pex_nf_cor & cor_pex_5400_error_code1[i].error_bit) {
8595f28a827Saf 			rt = cor_pex_5400_error_code1[i].intel_error_list;
8605f28a827Saf 			nerr++;
8615f28a827Saf 		}
8625f28a827Saf 	}
8635f28a827Saf 
8645f28a827Saf 	sz = sizeof (cor_pex_5400_error_code2) / sizeof (struct mch_error_code);
8655f28a827Saf 
8665f28a827Saf 	for (i = 0; i < sz; i++) {
8675f28a827Saf 		if (pex_nf_cor & cor_pex_5400_error_code2[i].error_bit) {
8685f28a827Saf 			rt = cor_pex_5400_error_code2[i].intel_error_list;
8695f28a827Saf 			nerr++;
8705f28a827Saf 		}
8715f28a827Saf 	}
8725f28a827Saf 
8735f28a827Saf 	sz = sizeof (cor_pex_5400_error_code3) / sizeof (struct mch_error_code);
8745f28a827Saf 
8755f28a827Saf 	for (i = 0; i < sz; i++) {
8765f28a827Saf 		if (pex_nf_cor & cor_pex_5400_error_code3[i].error_bit) {
8775f28a827Saf 			rt = cor_pex_5400_error_code3[i].intel_error_list;
8785f28a827Saf 			nerr++;
8795f28a827Saf 		}
8805f28a827Saf 	}
8815f28a827Saf 
8825f28a827Saf 	if (nerr > 1)
8835f28a827Saf 		rt = -1;
8845f28a827Saf 	return (rt);
8855f28a827Saf }
8865f28a827Saf 
88720c794b3Sgavinm static void
8880ad0f0b2SAdrian Frost log_pex_err(uint64_t ferr, nb_regs_t *rp, int willpanic, int *interpose)
88920c794b3Sgavinm {
89020c794b3Sgavinm 	uint8_t pex = (uint8_t)-1;
89120c794b3Sgavinm 	int t = 0;
89220c794b3Sgavinm 
89320c794b3Sgavinm 	rp->flag = NB_REG_LOG_PEX;
89420c794b3Sgavinm 	pex = GE_ERR_PEX(ferr);
89520c794b3Sgavinm 
89620c794b3Sgavinm 	rp->nb.pex_regs.pex = pex;
89720c794b3Sgavinm 	rp->nb.pex_regs.pex_fat_ferr =  PEX_FAT_FERR_RD(pex, interpose);
89820c794b3Sgavinm 	rp->nb.pex_regs.pex_fat_nerr = PEX_FAT_NERR_RD(pex, &t);
89920c794b3Sgavinm 	*interpose |= t;
90020c794b3Sgavinm 	rp->nb.pex_regs.pex_nf_corr_ferr = PEX_NF_FERR_RD(pex, &t);
90120c794b3Sgavinm 	*interpose |= t;
90220c794b3Sgavinm 	rp->nb.pex_regs.pex_nf_corr_nerr = PEX_NF_NERR_RD(pex, &t);
90320c794b3Sgavinm 	*interpose |= t;
90420c794b3Sgavinm 	rp->nb.pex_regs.uncerrsev = UNCERRSEV_RD(pex);
90520c794b3Sgavinm 	rp->nb.pex_regs.rperrsts = RPERRSTS_RD(pex);
90620c794b3Sgavinm 	rp->nb.pex_regs.rperrsid = RPERRSID_RD(pex);
90720c794b3Sgavinm 	if (pex != (uint8_t)-1)
90820c794b3Sgavinm 		rp->nb.pex_regs.uncerrsts = UNCERRSTS_RD(pex);
90920c794b3Sgavinm 	else
91020c794b3Sgavinm 		rp->nb.pex_regs.uncerrsts = 0;
91120c794b3Sgavinm 	rp->nb.pex_regs.aerrcapctrl = AERRCAPCTRL_RD(pex);
91220c794b3Sgavinm 	rp->nb.pex_regs.corerrsts = CORERRSTS_RD(pex);
91320c794b3Sgavinm 	rp->nb.pex_regs.pexdevsts = PEXDEVSTS_RD(pex);
91420c794b3Sgavinm 
9150ad0f0b2SAdrian Frost 	if (!willpanic) {
9160ad0f0b2SAdrian Frost 		if (rp->nb.pex_regs.pex_fat_ferr || *interpose)
9170ad0f0b2SAdrian Frost 			PEX_FAT_FERR_WR(pex, rp->nb.pex_regs.pex_fat_ferr);
9180ad0f0b2SAdrian Frost 		if (rp->nb.pex_regs.pex_fat_nerr)
9190ad0f0b2SAdrian Frost 			PEX_FAT_NERR_WR(pex, rp->nb.pex_regs.pex_fat_nerr);
9200ad0f0b2SAdrian Frost 		if (rp->nb.pex_regs.pex_nf_corr_ferr || *interpose)
9210ad0f0b2SAdrian Frost 			PEX_NF_FERR_WR(pex, rp->nb.pex_regs.pex_nf_corr_ferr);
9220ad0f0b2SAdrian Frost 		if (rp->nb.pex_regs.pex_nf_corr_nerr)
9230ad0f0b2SAdrian Frost 			PEX_NF_NERR_WR(pex, rp->nb.pex_regs.pex_nf_corr_nerr);
9240ad0f0b2SAdrian Frost 		if (*interpose)
9250ad0f0b2SAdrian Frost 			UNCERRSTS_WR(pex, rp->nb.pex_regs.uncerrsts);
9260ad0f0b2SAdrian Frost 		if (*interpose)
9270ad0f0b2SAdrian Frost 			RPERRSTS_WR(pex, rp->nb.pex_regs.rperrsts);
9280ad0f0b2SAdrian Frost 		if (*interpose)
9290ad0f0b2SAdrian Frost 			PEXDEVSTS_WR(pex, 0);
9300ad0f0b2SAdrian Frost 	}
93120c794b3Sgavinm }
93220c794b3Sgavinm 
93320c794b3Sgavinm static void
9340ad0f0b2SAdrian Frost log_fat_fbd_err(nb_regs_t *rp, int willpanic, int *interpose)
93520c794b3Sgavinm {
93620c794b3Sgavinm 	int channel, branch;
93720c794b3Sgavinm 	int t = 0;
93820c794b3Sgavinm 
93920c794b3Sgavinm 	rp->flag = NB_REG_LOG_FAT_FBD;
94020c794b3Sgavinm 	rp->nb.fat_fbd_regs.ferr_fat_fbd = FERR_FAT_FBD_RD(interpose);
94120c794b3Sgavinm 	channel = (rp->nb.fat_fbd_regs.ferr_fat_fbd >> 28) & 3;
94220c794b3Sgavinm 	branch = channel >> 1;
94320c794b3Sgavinm 	rp->nb.fat_fbd_regs.nerr_fat_fbd = NERR_FAT_FBD_RD(&t);
94420c794b3Sgavinm 	*interpose |= t;
9455f28a827Saf 	rp->nb.fat_fbd_regs.nrecmema = NRECMEMA_RD(branch);
9465f28a827Saf 	rp->nb.fat_fbd_regs.nrecmemb = NRECMEMB_RD(branch);
9475f28a827Saf 	rp->nb.fat_fbd_regs.nrecfglog = NRECFGLOG_RD(branch);
9485f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbda = NRECFBDA_RD(branch);
9495f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbdb = NRECFBDB_RD(branch);
9505f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbdc = NRECFBDC_RD(branch);
9515f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbdd = NRECFBDD_RD(branch);
9525f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbde = NRECFBDE_RD(branch);
9535f28a827Saf 	rp->nb.fat_fbd_regs.nrecfbdf = NRECFBDF_RD(branch);
95420c794b3Sgavinm 	rp->nb.fat_fbd_regs.spcps = SPCPS_RD(branch);
95520c794b3Sgavinm 	rp->nb.fat_fbd_regs.spcpc = SPCPC_RD(branch);
95620c794b3Sgavinm 	rp->nb.fat_fbd_regs.uerrcnt = UERRCNT_RD(branch);
95720c794b3Sgavinm 	rp->nb.fat_fbd_regs.uerrcnt_last = uerrcnt[branch];
95820c794b3Sgavinm 	uerrcnt[branch] = rp->nb.fat_fbd_regs.uerrcnt;
95920c794b3Sgavinm 	rp->nb.fat_fbd_regs.badrama = BADRAMA_RD(branch);
96020c794b3Sgavinm 	rp->nb.fat_fbd_regs.badramb = BADRAMB_RD(branch);
96120c794b3Sgavinm 	rp->nb.fat_fbd_regs.badcnt = BADCNT_RD(branch);
9620ad0f0b2SAdrian Frost 	if (!willpanic) {
9630ad0f0b2SAdrian Frost 		if (rp->nb.fat_fbd_regs.ferr_fat_fbd || *interpose)
9640ad0f0b2SAdrian Frost 			FERR_FAT_FBD_WR(rp->nb.fat_fbd_regs.ferr_fat_fbd);
9650ad0f0b2SAdrian Frost 		if (rp->nb.fat_fbd_regs.nerr_fat_fbd)
9660ad0f0b2SAdrian Frost 			NERR_FAT_FBD_WR(rp->nb.fat_fbd_regs.nerr_fat_fbd);
9670ad0f0b2SAdrian Frost 		/*
9680ad0f0b2SAdrian Frost 		 * if interpose write read-only registers to clear from pcii
9690ad0f0b2SAdrian Frost 		 * cache
9700ad0f0b2SAdrian Frost 		 */
9710ad0f0b2SAdrian Frost 		if (*interpose) {
9720ad0f0b2SAdrian Frost 			NRECMEMA_WR(branch);
9730ad0f0b2SAdrian Frost 			NRECMEMB_WR(branch);
9740ad0f0b2SAdrian Frost 			NRECFGLOG_WR(branch);
9750ad0f0b2SAdrian Frost 			NRECFBDA_WR(branch);
9760ad0f0b2SAdrian Frost 			NRECFBDB_WR(branch);
9770ad0f0b2SAdrian Frost 			NRECFBDC_WR(branch);
9780ad0f0b2SAdrian Frost 			NRECFBDD_WR(branch);
9790ad0f0b2SAdrian Frost 			NRECFBDE_WR(branch);
9800ad0f0b2SAdrian Frost 			NRECFBDF_WR(branch);
9810ad0f0b2SAdrian Frost 		}
98220c794b3Sgavinm 	}
98320c794b3Sgavinm }
98420c794b3Sgavinm 
98520c794b3Sgavinm static void
9860ad0f0b2SAdrian Frost log_nf_fbd_err(nb_regs_t *rp, int willpanic, int *interpose)
98720c794b3Sgavinm {
98820c794b3Sgavinm 	int channel, branch;
98920c794b3Sgavinm 	int t = 0;
99020c794b3Sgavinm 
99120c794b3Sgavinm 	rp->flag = NB_REG_LOG_NF_FBD;
99220c794b3Sgavinm 	rp->nb.nf_fbd_regs.ferr_nf_fbd = FERR_NF_FBD_RD(interpose);
99320c794b3Sgavinm 	channel = (rp->nb.nf_fbd_regs.ferr_nf_fbd >> 28) & 3;
99420c794b3Sgavinm 	branch = channel >> 1;
99520c794b3Sgavinm 	rp->nb.nf_fbd_regs.nerr_nf_fbd = NERR_NF_FBD_RD(&t);
99620c794b3Sgavinm 	*interpose |= t;
99720c794b3Sgavinm 	rp->nb.nf_fbd_regs.redmemb = REDMEMB_RD();
9985f28a827Saf 	rp->nb.nf_fbd_regs.recmema = RECMEMA_RD(branch);
9995f28a827Saf 	rp->nb.nf_fbd_regs.recmemb = RECMEMB_RD(branch);
10005f28a827Saf 	rp->nb.nf_fbd_regs.recfglog = RECFGLOG_RD(branch);
10015f28a827Saf 	rp->nb.nf_fbd_regs.recfbda = RECFBDA_RD(branch);
10025f28a827Saf 	rp->nb.nf_fbd_regs.recfbdb = RECFBDB_RD(branch);
10035f28a827Saf 	rp->nb.nf_fbd_regs.recfbdc = RECFBDC_RD(branch);
10045f28a827Saf 	rp->nb.nf_fbd_regs.recfbdd = RECFBDD_RD(branch);
10055f28a827Saf 	rp->nb.nf_fbd_regs.recfbde = RECFBDE_RD(branch);
10065f28a827Saf 	rp->nb.nf_fbd_regs.recfbdf = RECFBDF_RD(branch);
100720c794b3Sgavinm 	rp->nb.nf_fbd_regs.spcps = SPCPS_RD(branch);
100820c794b3Sgavinm 	rp->nb.nf_fbd_regs.spcpc = SPCPC_RD(branch);
10095f28a827Saf 	if (nb_chipset == INTEL_NB_7300 || nb_chipset == INTEL_NB_5400) {
10105f28a827Saf 		rp->nb.nf_fbd_regs.cerrcnta = CERRCNTA_RD(branch, channel);
10115f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntb = CERRCNTB_RD(branch, channel);
10125f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntc = CERRCNTC_RD(branch, channel);
10135f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntd = CERRCNTD_RD(branch, channel);
10145f28a827Saf 	} else {
10155f28a827Saf 		rp->nb.nf_fbd_regs.cerrcnta = CERRCNT_RD(branch);
10165f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntb = 0;
10175f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntc = 0;
10185f28a827Saf 		rp->nb.nf_fbd_regs.cerrcntd = 0;
10195f28a827Saf 	}
10205f28a827Saf 	rp->nb.nf_fbd_regs.cerrcnta_last = cerrcnta[branch][channel & 1];
10215f28a827Saf 	rp->nb.nf_fbd_regs.cerrcntb_last = cerrcntb[branch][channel & 1];
10225f28a827Saf 	rp->nb.nf_fbd_regs.cerrcntc_last = cerrcntc[branch][channel & 1];
10235f28a827Saf 	rp->nb.nf_fbd_regs.cerrcntd_last = cerrcntd[branch][channel & 1];
10245f28a827Saf 	cerrcnta[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcnta;
10255f28a827Saf 	cerrcntb[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntb;
10265f28a827Saf 	cerrcntc[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntc;
10275f28a827Saf 	cerrcntd[branch][channel & 1] = rp->nb.nf_fbd_regs.cerrcntd;
102820c794b3Sgavinm 	rp->nb.nf_fbd_regs.badrama = BADRAMA_RD(branch);
102920c794b3Sgavinm 	rp->nb.nf_fbd_regs.badramb = BADRAMB_RD(branch);
103020c794b3Sgavinm 	rp->nb.nf_fbd_regs.badcnt = BADCNT_RD(branch);
10310ad0f0b2SAdrian Frost 	if (!willpanic) {
10320ad0f0b2SAdrian Frost 		if (rp->nb.nf_fbd_regs.ferr_nf_fbd || *interpose)
10330ad0f0b2SAdrian Frost 			FERR_NF_FBD_WR(rp->nb.nf_fbd_regs.ferr_nf_fbd);
10340ad0f0b2SAdrian Frost 		if (rp->nb.nf_fbd_regs.nerr_nf_fbd)
10350ad0f0b2SAdrian Frost 			NERR_NF_FBD_WR(rp->nb.nf_fbd_regs.nerr_nf_fbd);
10360ad0f0b2SAdrian Frost 		/*
10370ad0f0b2SAdrian Frost 		 * if interpose write read-only registers to clear from pcii
10380ad0f0b2SAdrian Frost 		 * cache
10390ad0f0b2SAdrian Frost 		 */
10400ad0f0b2SAdrian Frost 		if (*interpose) {
10410ad0f0b2SAdrian Frost 			RECMEMA_WR(branch);
10420ad0f0b2SAdrian Frost 			RECMEMB_WR(branch);
10430ad0f0b2SAdrian Frost 			RECFGLOG_WR(branch);
10440ad0f0b2SAdrian Frost 			RECFBDA_WR(branch);
10450ad0f0b2SAdrian Frost 			RECFBDB_WR(branch);
10460ad0f0b2SAdrian Frost 			RECFBDC_WR(branch);
10470ad0f0b2SAdrian Frost 			RECFBDD_WR(branch);
10480ad0f0b2SAdrian Frost 			RECFBDE_WR(branch);
10490ad0f0b2SAdrian Frost 			RECFBDF_WR(branch);
10500ad0f0b2SAdrian Frost 			SPCPS_WR(branch);
10510ad0f0b2SAdrian Frost 		}
105220c794b3Sgavinm 	}
105320c794b3Sgavinm }
105420c794b3Sgavinm 
105520c794b3Sgavinm static void
105620c794b3Sgavinm log_ferr(uint64_t ferr, uint32_t *nerrp, nb_logout_t *log, int willpanic)
105720c794b3Sgavinm {
105820c794b3Sgavinm 	nb_regs_t *rp = &log->nb_regs;
105920c794b3Sgavinm 	uint32_t nerr = *nerrp;
106020c794b3Sgavinm 	int interpose = 0;
10619ff4cbe7SAdrian Frost 	int spurious = 0;
106220c794b3Sgavinm 
106320c794b3Sgavinm 	log->acl_timestamp = gethrtime_waitfree();
106420c794b3Sgavinm 	if ((ferr & (GE_PCIEX_FATAL | GE_PCIEX_NF)) != 0) {
10650ad0f0b2SAdrian Frost 		log_pex_err(ferr, rp, willpanic, &interpose);
106620c794b3Sgavinm 		*nerrp = nerr & ~(GE_PCIEX_FATAL | GE_PCIEX_NF);
106720c794b3Sgavinm 	} else if ((ferr & GE_FBD_FATAL) != 0) {
10680ad0f0b2SAdrian Frost 		log_fat_fbd_err(rp, willpanic, &interpose);
106920c794b3Sgavinm 		*nerrp = nerr & ~GE_NERR_FBD_FATAL;
107020c794b3Sgavinm 	} else if ((ferr & GE_FBD_NF) != 0) {
10710ad0f0b2SAdrian Frost 		log_nf_fbd_err(rp, willpanic, &interpose);
107220c794b3Sgavinm 		*nerrp = nerr & ~GE_NERR_FBD_NF;
107320c794b3Sgavinm 	} else if ((ferr & (GE_FERR_FSB_FATAL | GE_FERR_FSB_NF)) != 0) {
10740ad0f0b2SAdrian Frost 		log_fsb_err(ferr, rp, willpanic, &interpose);
107520c794b3Sgavinm 		*nerrp = nerr & ~(GE_NERR_FSB_FATAL | GE_NERR_FSB_NF);
107620c794b3Sgavinm 	} else if ((ferr & (GE_DMA_FATAL | GE_DMA_NF)) != 0) {
107720c794b3Sgavinm 		log_dma_err(rp, &interpose);
107820c794b3Sgavinm 		*nerrp = nerr & ~(GE_DMA_FATAL | GE_DMA_NF);
107920c794b3Sgavinm 	} else if ((ferr & (GE_INT_FATAL | GE_INT_NF)) != 0) {
10800ad0f0b2SAdrian Frost 		spurious = log_int_err(rp, willpanic, &interpose);
108120c794b3Sgavinm 		*nerrp = nerr & ~(GE_INT_FATAL | GE_INT_NF);
10825f28a827Saf 	} else if (nb_chipset == INTEL_NB_5400 &&
10835f28a827Saf 	    (ferr & (GE_FERR_THERMAL_FATAL | GE_FERR_THERMAL_NF)) != 0) {
10840ad0f0b2SAdrian Frost 		log_thermal_err(rp, willpanic, &interpose);
10855f28a827Saf 		*nerrp = nerr & ~(GE_FERR_THERMAL_FATAL | GE_FERR_THERMAL_NF);
108620c794b3Sgavinm 	}
108720c794b3Sgavinm 	if (interpose)
108820c794b3Sgavinm 		log->type = "inject";
108920c794b3Sgavinm 	else
109020c794b3Sgavinm 		log->type = "error";
10919ff4cbe7SAdrian Frost 	if (!spurious) {
10929ff4cbe7SAdrian Frost 		errorq_dispatch(nb_queue, log, sizeof (nb_logout_t),
10939ff4cbe7SAdrian Frost 		    willpanic ? ERRORQ_SYNC : ERRORQ_ASYNC);
10949ff4cbe7SAdrian Frost 	}
109520c794b3Sgavinm }
109620c794b3Sgavinm 
109720c794b3Sgavinm static void
109820c794b3Sgavinm log_nerr(uint32_t *errp, nb_logout_t *log, int willpanic)
109920c794b3Sgavinm {
110020c794b3Sgavinm 	uint32_t err;
110120c794b3Sgavinm 	nb_regs_t *rp = &log->nb_regs;
110220c794b3Sgavinm 	int interpose = 0;
11039ff4cbe7SAdrian Frost 	int spurious = 0;
110420c794b3Sgavinm 
110520c794b3Sgavinm 	err = *errp;
110620c794b3Sgavinm 	log->acl_timestamp = gethrtime_waitfree();
110720c794b3Sgavinm 	if ((err & (GE_PCIEX_FATAL | GE_PCIEX_NF)) != 0) {
11080ad0f0b2SAdrian Frost 		log_pex_err(err, rp, willpanic, &interpose);
110920c794b3Sgavinm 		*errp = err & ~(GE_PCIEX_FATAL | GE_PCIEX_NF);
111020c794b3Sgavinm 	} else if ((err & GE_NERR_FBD_FATAL) != 0) {
11110ad0f0b2SAdrian Frost 		log_fat_fbd_err(rp, willpanic, &interpose);
111220c794b3Sgavinm 		*errp = err & ~GE_NERR_FBD_FATAL;
111320c794b3Sgavinm 	} else if ((err & GE_NERR_FBD_NF) != 0) {
11140ad0f0b2SAdrian Frost 		log_nf_fbd_err(rp, willpanic, &interpose);
111520c794b3Sgavinm 		*errp = err & ~GE_NERR_FBD_NF;
111620c794b3Sgavinm 	} else if ((err & (GE_NERR_FSB_FATAL | GE_NERR_FSB_NF)) != 0) {
11170ad0f0b2SAdrian Frost 		log_fsb_err(GE_NERR_TO_FERR_FSB(err), rp, willpanic,
11180ad0f0b2SAdrian Frost 		    &interpose);
111920c794b3Sgavinm 		*errp = err & ~(GE_NERR_FSB_FATAL | GE_NERR_FSB_NF);
112020c794b3Sgavinm 	} else if ((err & (GE_DMA_FATAL | GE_DMA_NF)) != 0) {
112120c794b3Sgavinm 		log_dma_err(rp, &interpose);
112220c794b3Sgavinm 		*errp = err & ~(GE_DMA_FATAL | GE_DMA_NF);
112320c794b3Sgavinm 	} else if ((err & (GE_INT_FATAL | GE_INT_NF)) != 0) {
11240ad0f0b2SAdrian Frost 		spurious = log_int_err(rp, willpanic, &interpose);
112520c794b3Sgavinm 		*errp = err & ~(GE_INT_FATAL | GE_INT_NF);
112620c794b3Sgavinm 	}
112720c794b3Sgavinm 	if (interpose)
112820c794b3Sgavinm 		log->type = "inject";
112920c794b3Sgavinm 	else
113020c794b3Sgavinm 		log->type = "error";
11319ff4cbe7SAdrian Frost 	if (!spurious) {
11329ff4cbe7SAdrian Frost 		errorq_dispatch(nb_queue, log, sizeof (nb_logout_t),
11339ff4cbe7SAdrian Frost 		    willpanic ? ERRORQ_SYNC : ERRORQ_ASYNC);
11349ff4cbe7SAdrian Frost 	}
113520c794b3Sgavinm }
113620c794b3Sgavinm 
113720c794b3Sgavinm /*ARGSUSED*/
113820c794b3Sgavinm void
113920c794b3Sgavinm nb_error_trap(cmi_hdl_t hdl, boolean_t ismc, boolean_t willpanic)
114020c794b3Sgavinm {
114120c794b3Sgavinm 	uint64_t ferr;
114220c794b3Sgavinm 	uint32_t nerr, err;
114320c794b3Sgavinm 	int nmc = 0;
114420c794b3Sgavinm 	int i;
114520c794b3Sgavinm 
114620c794b3Sgavinm 	if (mutex_tryenter(&nb_mutex) == 0)
114720c794b3Sgavinm 		return;
114820c794b3Sgavinm 
114920c794b3Sgavinm 	nerr = NERR_GLOBAL_RD();
115020c794b3Sgavinm 	err = nerr;
115120c794b3Sgavinm 	for (i = 0; i < NB_MAX_ERRORS; i++) {
115220c794b3Sgavinm 		ferr = FERR_GLOBAL_RD();
115320c794b3Sgavinm 		nb_log.nb_regs.chipset = nb_chipset;
115420c794b3Sgavinm 		nb_log.nb_regs.ferr = ferr;
115520c794b3Sgavinm 		nb_log.nb_regs.nerr = nerr;
115620c794b3Sgavinm 		if (ferr) {
115720c794b3Sgavinm 			log_ferr(ferr, &err, &nb_log, willpanic);
115820c794b3Sgavinm 			FERR_GLOBAL_WR(ferr);
115920c794b3Sgavinm 			nmc++;
116020c794b3Sgavinm 		} else if (err) {
116120c794b3Sgavinm 			log_nerr(&err, &nb_log, willpanic);
116220c794b3Sgavinm 			nmc++;
116320c794b3Sgavinm 		}
116420c794b3Sgavinm 	}
116520c794b3Sgavinm 	if (nerr) {
116620c794b3Sgavinm 		NERR_GLOBAL_WR(nerr);
116720c794b3Sgavinm 	}
116820c794b3Sgavinm 	if (nmc == 0 && nb_mask_mc_set)
116920c794b3Sgavinm 		nb_mask_mc_reset();
117020c794b3Sgavinm 	mutex_exit(&nb_mutex);
117120c794b3Sgavinm }
117220c794b3Sgavinm 
117320c794b3Sgavinm static void
117420c794b3Sgavinm nb_fsb_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
117520c794b3Sgavinm     nb_scatchpad_t *data)
117620c794b3Sgavinm {
117720c794b3Sgavinm 	int intel_error_list;
117820c794b3Sgavinm 	char buf[32];
117920c794b3Sgavinm 
118020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FSB,
118120c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.fsb, NULL);
118220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_FSB,
118320c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.ferr_fat_fsb, NULL);
118420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_FSB,
118520c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.nerr_fat_fsb, NULL);
118620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_FSB,
118720c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.ferr_nf_fsb, NULL);
118820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_FSB,
118920c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fsb_regs.nerr_nf_fsb, NULL);
119020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFSB,
119120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fsb_regs.nrecfsb, NULL);
119220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFSB_ADDR,
119320c794b3Sgavinm 	    DATA_TYPE_UINT64, nb_regs->nb.fsb_regs.nrecfsb_addr, NULL);
119420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFSB,
119520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fsb_regs.recfsb, NULL);
119620c794b3Sgavinm 	intel_error_list = data->intel_error_list;
119720c794b3Sgavinm 	if (intel_error_list >= 0)
119820c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "F%d", intel_error_list);
119920c794b3Sgavinm 	else
120020c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
120120c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
120220c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
120320c794b3Sgavinm }
120420c794b3Sgavinm 
120520c794b3Sgavinm static void
120620c794b3Sgavinm nb_pex_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
120720c794b3Sgavinm     nb_scatchpad_t *data)
120820c794b3Sgavinm {
120920c794b3Sgavinm 	int intel_error_list;
121020c794b3Sgavinm 	char buf[32];
121120c794b3Sgavinm 
121220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX,
121320c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.pex_regs.pex, NULL);
121420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_FAT_FERR,
121520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_fat_ferr, NULL);
121620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_FAT_NERR,
121720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_fat_nerr, NULL);
121820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_NF_CORR_FERR,
121920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_nf_corr_ferr, NULL);
122020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEX_NF_CORR_NERR,
122120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.pex_nf_corr_nerr, NULL);
122220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UNCERRSEV,
122320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.uncerrsev, NULL);
122420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RPERRSTS,
122520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.rperrsts, NULL);
122620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RPERRSID,
122720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.rperrsid, NULL);
122820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UNCERRSTS,
122920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.uncerrsts, NULL);
123020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_AERRCAPCTRL,
123120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.aerrcapctrl, NULL);
123220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CORERRSTS,
123320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.pex_regs.corerrsts, NULL);
123420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEXDEVSTS,
123520c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.pex_regs.pexdevsts, NULL);
123620c794b3Sgavinm 	intel_error_list = data->intel_error_list;
123720c794b3Sgavinm 	if (intel_error_list >= 0)
123820c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "IO%d", intel_error_list);
123920c794b3Sgavinm 	else
124020c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
124120c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
124220c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
124320c794b3Sgavinm }
124420c794b3Sgavinm 
124520c794b3Sgavinm static void
124620c794b3Sgavinm nb_int_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
124720c794b3Sgavinm     nb_scatchpad_t *data)
124820c794b3Sgavinm {
124920c794b3Sgavinm 	int intel_error_list;
125020c794b3Sgavinm 	char buf[32];
125120c794b3Sgavinm 
125220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_INT,
12535f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.int_regs.ferr_fat_int, NULL);
125420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_INT,
12555f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.int_regs.ferr_nf_int, NULL);
125620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_INT,
12575f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.int_regs.nerr_fat_int, NULL);
125820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_INT,
12595f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.int_regs.nerr_nf_int, NULL);
126020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECINT,
126120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.int_regs.nrecint, NULL);
126220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECINT,
126320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.int_regs.recint, NULL);
126420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECSF,
126520c794b3Sgavinm 	    DATA_TYPE_UINT64, nb_regs->nb.int_regs.nrecsf, NULL);
126620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECSF,
126720c794b3Sgavinm 	    DATA_TYPE_UINT64, nb_regs->nb.int_regs.recsf, NULL);
126820c794b3Sgavinm 	intel_error_list = data->intel_error_list;
126920c794b3Sgavinm 	if (intel_error_list >= 0)
127020c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "B%d", intel_error_list);
127120c794b3Sgavinm 	else
127220c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
127320c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
127420c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
127520c794b3Sgavinm }
127620c794b3Sgavinm 
127720c794b3Sgavinm static void
127820c794b3Sgavinm nb_fat_fbd_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
127920c794b3Sgavinm     nb_scatchpad_t *data)
128020c794b3Sgavinm {
128120c794b3Sgavinm 	nb_mem_scatchpad_t *sp;
128220c794b3Sgavinm 	char buf[32];
128320c794b3Sgavinm 
128420c794b3Sgavinm 	sp = &((nb_scatchpad_t *)data)->ms;
128520c794b3Sgavinm 
128620c794b3Sgavinm 	if (sp->ras != -1) {
128720c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK,
128820c794b3Sgavinm 		    DATA_TYPE_INT32, sp->bank, NULL);
128920c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS,
129020c794b3Sgavinm 		    DATA_TYPE_INT32, sp->cas, NULL);
129120c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS,
129220c794b3Sgavinm 		    DATA_TYPE_INT32, sp->ras, NULL);
129320c794b3Sgavinm 		if (sp->offset != -1LL) {
129420c794b3Sgavinm 			fm_payload_set(payload, FM_FMRI_MEM_OFFSET,
129520c794b3Sgavinm 			    DATA_TYPE_UINT64, sp->offset, NULL);
129620c794b3Sgavinm 		}
129720c794b3Sgavinm 		if (sp->pa != -1LL) {
129820c794b3Sgavinm 			fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR,
129920c794b3Sgavinm 			    DATA_TYPE_UINT64, sp->pa, NULL);
130020c794b3Sgavinm 		}
130120c794b3Sgavinm 	}
130220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_FBD,
130320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.ferr_fat_fbd, NULL);
130420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_FBD,
130520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nerr_fat_fbd, NULL);
130620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMA,
13075f28a827Saf 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecmema, NULL);
130820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMB,
130920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecmemb, NULL);
131020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFGLOG,
131120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfglog, NULL);
131220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDA,
131320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbda, NULL);
131420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDB,
131520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdb, NULL);
131620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDC,
131720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdc, NULL);
131820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDD,
131920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdd, NULL);
132020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDE,
132120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbde, NULL);
13225de8e333Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECFBDF,
13235de8e333Saf 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.nrecfbdf, NULL);
132420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS,
132520c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.fat_fbd_regs.spcps, NULL);
132620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC,
132720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.spcpc, NULL);
132820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UERRCNT,
132920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.uerrcnt, NULL);
133020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UERRCNT_LAST,
133120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.uerrcnt_last, NULL);
133220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMA,
133320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.badrama, NULL);
133420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMB,
133520c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.fat_fbd_regs.badramb, NULL);
133620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT,
133720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.fat_fbd_regs.badcnt, NULL);
133820c794b3Sgavinm 
133920c794b3Sgavinm 	if (sp->intel_error_list >= 0)
134020c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list);
134120c794b3Sgavinm 	else
134220c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
134320c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
134420c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
134520c794b3Sgavinm }
134620c794b3Sgavinm 
134720c794b3Sgavinm static void
134820c794b3Sgavinm nb_nf_fbd_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
134920c794b3Sgavinm     nb_scatchpad_t *data)
135020c794b3Sgavinm {
135120c794b3Sgavinm 	nb_mem_scatchpad_t *sp;
135220c794b3Sgavinm 	char buf[32];
135320c794b3Sgavinm 
135420c794b3Sgavinm 	sp = &((nb_scatchpad_t *)data)->ms;
135520c794b3Sgavinm 
135620c794b3Sgavinm 	if (sp->dimm == -1 && sp->rank != -1) {
135720c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RANK,
135820c794b3Sgavinm 		    DATA_TYPE_INT32, sp->rank, NULL);
135920c794b3Sgavinm 	}
136020c794b3Sgavinm 	if (sp->ras != -1) {
136120c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK,
136220c794b3Sgavinm 		    DATA_TYPE_INT32, sp->bank, NULL);
136320c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS,
136420c794b3Sgavinm 		    DATA_TYPE_INT32, sp->cas, NULL);
136520c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS,
136620c794b3Sgavinm 		    DATA_TYPE_INT32, sp->ras, NULL);
136720c794b3Sgavinm 		if (sp->offset != -1LL) {
136820c794b3Sgavinm 			fm_payload_set(payload, FM_FMRI_MEM_OFFSET,
136920c794b3Sgavinm 			    DATA_TYPE_UINT64, sp->offset, NULL);
137020c794b3Sgavinm 		}
137120c794b3Sgavinm 		if (sp->pa != -1LL) {
137220c794b3Sgavinm 			fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR,
137320c794b3Sgavinm 			    DATA_TYPE_UINT64, sp->pa, NULL);
137420c794b3Sgavinm 		}
137520c794b3Sgavinm 	}
137620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_FBD,
137720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.ferr_nf_fbd, NULL);
137820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_FBD,
137920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.nerr_nf_fbd, NULL);
138020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMA,
13815f28a827Saf 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recmema, NULL);
138220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMB,
138320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recmemb, NULL);
138420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFGLOG,
138520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfglog, NULL);
138620c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDA,
138720c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbda, NULL);
138820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDB,
138920c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdb, NULL);
139020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDC,
139120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdc, NULL);
139220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDD,
139320c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdd, NULL);
139420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDE,
139520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbde, NULL);
13965de8e333Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECFBDF,
13975de8e333Saf 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.recfbdf, NULL);
139820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS,
139920c794b3Sgavinm 	    DATA_TYPE_UINT8, nb_regs->nb.nf_fbd_regs.spcps, NULL);
140020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC,
140120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.spcpc, NULL);
14025f28a827Saf 	if (nb_chipset == INTEL_NB_7300 || nb_chipset == INTEL_NB_5400) {
14035f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTA,
14045f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta, NULL);
14055f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTB,
14065f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntb, NULL);
14075f28a827Saf 		if (nb_chipset == INTEL_NB_7300) {
14085f28a827Saf 			fm_payload_set(payload,
14095f28a827Saf 			    FM_EREPORT_PAYLOAD_NAME_CERRCNTC,
14105f28a827Saf 			    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntc,
14115f28a827Saf 			    NULL);
14125f28a827Saf 			fm_payload_set(payload,
14135f28a827Saf 			    FM_EREPORT_PAYLOAD_NAME_CERRCNTD,
14145f28a827Saf 			    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntd,
14155f28a827Saf 			    NULL);
14165f28a827Saf 		}
14175f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTA_LAST,
14185f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta_last,
14195f28a827Saf 		    NULL);
14205f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNTB_LAST,
14215f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcntb_last,
14225f28a827Saf 		    NULL);
14235f28a827Saf 		if (nb_chipset == INTEL_NB_7300) {
14245f28a827Saf 			fm_payload_set(payload,
14255f28a827Saf 			    FM_EREPORT_PAYLOAD_NAME_CERRCNTC_LAST,
14265f28a827Saf 			    DATA_TYPE_UINT32,
14275f28a827Saf 			    nb_regs->nb.nf_fbd_regs.cerrcntc_last, NULL);
14285f28a827Saf 			fm_payload_set(payload,
14295f28a827Saf 			    FM_EREPORT_PAYLOAD_NAME_CERRCNTD_LAST,
14305f28a827Saf 			    DATA_TYPE_UINT32,
14315f28a827Saf 			    nb_regs->nb.nf_fbd_regs.cerrcntd_last, NULL);
14325f28a827Saf 		}
14335f28a827Saf 	} else {
14345f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT,
14355f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta, NULL);
14365f28a827Saf 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_LAST,
14375f28a827Saf 		    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.cerrcnta_last,
14385f28a827Saf 		    NULL);
14395f28a827Saf 	}
144020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMA,
144120c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.badrama, NULL);
144220c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAMB,
144320c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.nf_fbd_regs.badramb, NULL);
144420c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT,
144520c794b3Sgavinm 	    DATA_TYPE_UINT32, nb_regs->nb.nf_fbd_regs.badcnt, NULL);
144620c794b3Sgavinm 
144720c794b3Sgavinm 	if (sp->intel_error_list >= 0)
144820c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list);
144920c794b3Sgavinm 	else
145020c794b3Sgavinm 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
145120c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
145220c794b3Sgavinm 	    DATA_TYPE_STRING, buf, NULL);
145320c794b3Sgavinm }
145420c794b3Sgavinm 
145520c794b3Sgavinm static void
145620c794b3Sgavinm nb_dma_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload)
145720c794b3Sgavinm {
145820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PCISTS,
145920c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.dma_regs.pcists, NULL);
146020c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PEXDEVSTS,
146120c794b3Sgavinm 	    DATA_TYPE_UINT16, nb_regs->nb.dma_regs.pexdevsts, NULL);
146220c794b3Sgavinm }
146320c794b3Sgavinm 
14645f28a827Saf static void
14655f28a827Saf nb_thr_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
14665f28a827Saf     nb_scatchpad_t *data)
14675f28a827Saf {
14685f28a827Saf 	char buf[32];
14695f28a827Saf 
14705f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_FAT_THR,
14715f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ferr_fat_thr, NULL);
14725f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_FAT_THR,
14735f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.nerr_fat_thr, NULL);
14745f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_THR,
14755f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ferr_nf_thr, NULL);
14765f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_THR,
14775f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.nerr_nf_thr, NULL);
14785f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CTSTS,
14795f28a827Saf 	    DATA_TYPE_UINT8, nb_regs->nb.thr_regs.ctsts, NULL);
14805f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_THRTSTS,
14815f28a827Saf 	    DATA_TYPE_UINT16, nb_regs->nb.thr_regs.thrtsts, NULL);
14825f28a827Saf 	if (data->intel_error_list >= 0) {
14835f28a827Saf 		(void) snprintf(buf, sizeof (buf), "TH%d",
14845f28a827Saf 		    data->intel_error_list);
14855f28a827Saf 	} else {
14865f28a827Saf 		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
14875f28a827Saf 	}
14885f28a827Saf 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
14895f28a827Saf 	    DATA_TYPE_STRING, buf, NULL);
14905f28a827Saf }
14915f28a827Saf 
149220c794b3Sgavinm static void
149320c794b3Sgavinm nb_ereport_add_logout(nvlist_t *payload, const nb_logout_t *acl,
149420c794b3Sgavinm     nb_scatchpad_t *data)
149520c794b3Sgavinm {
149620c794b3Sgavinm 	const nb_regs_t *nb_regs = &acl->nb_regs;
149720c794b3Sgavinm 
149820c794b3Sgavinm 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_MC_TYPE,
14996cb1ca52Saf 	    DATA_TYPE_STRING, acl->type, NULL);
150020c794b3Sgavinm 	switch (nb_regs->flag) {
150120c794b3Sgavinm 	case NB_REG_LOG_FSB:
150220c794b3Sgavinm 		nb_fsb_err_payload(nb_regs, payload, data);
150320c794b3Sgavinm 		break;
150420c794b3Sgavinm 	case NB_REG_LOG_PEX:
150520c794b3Sgavinm 		nb_pex_err_payload(nb_regs, payload, data);
150620c794b3Sgavinm 		break;
150720c794b3Sgavinm 	case NB_REG_LOG_INT:
150820c794b3Sgavinm 		nb_int_err_payload(nb_regs, payload, data);
150920c794b3Sgavinm 		break;
151020c794b3Sgavinm 	case NB_REG_LOG_FAT_FBD:
151120c794b3Sgavinm 		nb_fat_fbd_err_payload(nb_regs, payload, data);
151220c794b3Sgavinm 		break;
151320c794b3Sgavinm 	case NB_REG_LOG_NF_FBD:
151420c794b3Sgavinm 		nb_nf_fbd_err_payload(nb_regs, payload, data);
151520c794b3Sgavinm 		break;
151620c794b3Sgavinm 	case NB_REG_LOG_DMA:
151720c794b3Sgavinm 		nb_dma_err_payload(nb_regs, payload);
151820c794b3Sgavinm 		break;
15195f28a827Saf 	case NB_REG_LOG_THR:
15205f28a827Saf 		nb_thr_err_payload(nb_regs, payload, data);
15215f28a827Saf 		break;
152220c794b3Sgavinm 	default:
152320c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_GLOBAL,
152420c794b3Sgavinm 		    DATA_TYPE_UINT64, nb_regs->ferr, NULL);
152520c794b3Sgavinm 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_GLOBAL,
152620c794b3Sgavinm 		    DATA_TYPE_UINT32, nb_regs->nerr, NULL);
152720c794b3Sgavinm 		break;
152820c794b3Sgavinm 	}
152920c794b3Sgavinm }
153020c794b3Sgavinm 
153120c794b3Sgavinm void
153220c794b3Sgavinm nb_fsb_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
153320c794b3Sgavinm     nb_scatchpad_t *data)
153420c794b3Sgavinm {
153520c794b3Sgavinm 	int chip;
153620c794b3Sgavinm 
153720c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300)
153820c794b3Sgavinm 		chip = nb_regs->nb.fsb_regs.fsb * 2;
153920c794b3Sgavinm 	else
154020c794b3Sgavinm 		chip = nb_regs->nb.fsb_regs.fsb;
154120c794b3Sgavinm 	fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
154220c794b3Sgavinm 	    "motherboard", 0, "chip", chip);
154320c794b3Sgavinm 
15446cb1ca52Saf 	if (nb_regs->nb.fsb_regs.ferr_fat_fsb == 0 &&
15456cb1ca52Saf 	    nb_regs->nb.fsb_regs.ferr_nf_fsb == 0) {
15466cb1ca52Saf 		data->intel_error_list = intel_fsb_err(nb_regs->nb.fsb_regs.fsb,
15476cb1ca52Saf 		    nb_regs->nb.fsb_regs.nerr_fat_fsb,
15486cb1ca52Saf 		    nb_regs->nb.fsb_regs.nerr_nf_fsb);
15496cb1ca52Saf 	} else {
15506cb1ca52Saf 		data->intel_error_list = intel_fsb_err(nb_regs->nb.fsb_regs.fsb,
15516cb1ca52Saf 		    nb_regs->nb.fsb_regs.ferr_fat_fsb,
15526cb1ca52Saf 		    nb_regs->nb.fsb_regs.ferr_nf_fsb);
15536cb1ca52Saf 	}
155420c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
155520c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "fsb");
155620c794b3Sgavinm }
155720c794b3Sgavinm 
155820c794b3Sgavinm void
155920c794b3Sgavinm nb_pex_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
156020c794b3Sgavinm     nb_scatchpad_t *data)
156120c794b3Sgavinm {
156220c794b3Sgavinm 	int hostbridge;
156320c794b3Sgavinm 
156420c794b3Sgavinm 	if (nb_regs->nb.pex_regs.pex == 0) {
156520c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
156620c794b3Sgavinm 		    "motherboard", 0);
156720c794b3Sgavinm 	} else {
156820c794b3Sgavinm 		hostbridge = nb_regs->nb.pex_regs.pex - 1;
156920c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
157020c794b3Sgavinm 		    "motherboard", 0,
157120c794b3Sgavinm 		    "hostbridge", hostbridge);
157220c794b3Sgavinm 	}
157320c794b3Sgavinm 
15746cb1ca52Saf 	if (nb_regs->nb.pex_regs.pex_fat_ferr == 0 &&
15756cb1ca52Saf 	    nb_regs->nb.pex_regs.pex_nf_corr_ferr == 0) {
15765f28a827Saf 		if (nb_chipset == INTEL_NB_5400) {
15775f28a827Saf 			data->intel_error_list =
15785f28a827Saf 			    intel_pex_5400_err(
15795f28a827Saf 			    nb_regs->nb.pex_regs.pex_fat_nerr,
15805f28a827Saf 			    nb_regs->nb.pex_regs.pex_nf_corr_nerr);
15815f28a827Saf 		} else {
15825f28a827Saf 			data->intel_error_list =
15835f28a827Saf 			    intel_pex_err(nb_regs->nb.pex_regs.pex_fat_nerr,
15845f28a827Saf 			    nb_regs->nb.pex_regs.pex_nf_corr_nerr);
15855f28a827Saf 		}
15866cb1ca52Saf 	} else {
15875f28a827Saf 		if (nb_chipset == INTEL_NB_5400) {
15885f28a827Saf 			data->intel_error_list =
15895f28a827Saf 			    intel_pex_5400_err(
15905f28a827Saf 			    nb_regs->nb.pex_regs.pex_fat_ferr,
15915f28a827Saf 			    nb_regs->nb.pex_regs.pex_nf_corr_ferr);
15925f28a827Saf 		} else {
15935f28a827Saf 			data->intel_error_list =
15945f28a827Saf 			    intel_pex_err(nb_regs->nb.pex_regs.pex_fat_ferr,
15955f28a827Saf 			    nb_regs->nb.pex_regs.pex_nf_corr_ferr);
15965f28a827Saf 		}
15976cb1ca52Saf 	}
159820c794b3Sgavinm 
159920c794b3Sgavinm 	if (nb_regs->nb.pex_regs.pex == 0) {
160020c794b3Sgavinm 		(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
160120c794b3Sgavinm 		    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "esi");
160220c794b3Sgavinm 	} else {
160320c794b3Sgavinm 		(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
160420c794b3Sgavinm 		    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "pex");
160520c794b3Sgavinm 	}
160620c794b3Sgavinm }
160720c794b3Sgavinm 
160820c794b3Sgavinm void
160920c794b3Sgavinm nb_int_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
161020c794b3Sgavinm     void *data)
161120c794b3Sgavinm {
161220c794b3Sgavinm 	fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
161320c794b3Sgavinm 	    "motherboard", 0);
161420c794b3Sgavinm 
16156cb1ca52Saf 	if (nb_regs->nb.int_regs.ferr_fat_int == 0 &&
16166cb1ca52Saf 	    nb_regs->nb.int_regs.ferr_nf_int == 0) {
16176cb1ca52Saf 		((nb_scatchpad_t *)data)->intel_error_list =
16186cb1ca52Saf 		    intel_int_err(nb_regs->nb.int_regs.nerr_fat_int,
16196cb1ca52Saf 		    nb_regs->nb.int_regs.nerr_nf_int);
16206cb1ca52Saf 	} else {
16216cb1ca52Saf 		((nb_scatchpad_t *)data)->intel_error_list =
16226cb1ca52Saf 		    intel_int_err(nb_regs->nb.int_regs.ferr_fat_int,
16236cb1ca52Saf 		    nb_regs->nb.int_regs.ferr_nf_int);
16246cb1ca52Saf 	}
162520c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
162620c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "ie");
162720c794b3Sgavinm }
162820c794b3Sgavinm 
162920c794b3Sgavinm void
163020c794b3Sgavinm nb_fat_fbd_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
163120c794b3Sgavinm     void *data)
163220c794b3Sgavinm {
163320c794b3Sgavinm 	char *intr;
163420c794b3Sgavinm 	nb_mem_scatchpad_t *sp;
163520c794b3Sgavinm 
163620c794b3Sgavinm 	intr = fat_memory_error(nb_regs, data);
163720c794b3Sgavinm 	sp = &((nb_scatchpad_t *)data)->ms;
163820c794b3Sgavinm 
163920c794b3Sgavinm 	if (sp->dimm != -1) {
164020c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5,
164120c794b3Sgavinm 		    "motherboard", 0,
164220c794b3Sgavinm 		    "memory-controller", sp->branch,
164320c794b3Sgavinm 		    "dram-channel", sp->channel,
164420c794b3Sgavinm 		    "dimm", sp->dimm,
164520c794b3Sgavinm 		    "rank", sp->rank);
164620c794b3Sgavinm 	} else if (sp->channel != -1) {
164720c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
164820c794b3Sgavinm 		    "motherboard", 0,
164920c794b3Sgavinm 		    "memory-controller", sp->branch,
165020c794b3Sgavinm 		    "dram-channel", sp->channel);
16516cb1ca52Saf 	} else if (sp->branch != -1) {
165220c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
165320c794b3Sgavinm 		    "motherboard", 0,
165420c794b3Sgavinm 		    "memory-controller", sp->branch);
16556cb1ca52Saf 	} else {
16566cb1ca52Saf 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
16576cb1ca52Saf 		    "motherboard", 0);
165820c794b3Sgavinm 	}
165920c794b3Sgavinm 
166020c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s",
166120c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr);
166220c794b3Sgavinm }
166320c794b3Sgavinm 
166420c794b3Sgavinm void
166520c794b3Sgavinm nb_nf_fbd_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
166620c794b3Sgavinm     void *data)
166720c794b3Sgavinm {
166820c794b3Sgavinm 	char *intr;
166920c794b3Sgavinm 	nb_mem_scatchpad_t *sp;
167020c794b3Sgavinm 
167120c794b3Sgavinm 	intr = nf_memory_error(nb_regs, data);
167220c794b3Sgavinm 	sp = &((nb_scatchpad_t *)data)->ms;
167320c794b3Sgavinm 
167420c794b3Sgavinm 	if (sp->dimm != -1) {
167520c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5,
167620c794b3Sgavinm 		    "motherboard", 0,
167720c794b3Sgavinm 		    "memory-controller", sp->branch,
167820c794b3Sgavinm 		    "dram-channel", sp->channel,
167920c794b3Sgavinm 		    "dimm", sp->dimm,
168020c794b3Sgavinm 		    "rank", sp->rank);
168120c794b3Sgavinm 	} else if (sp->channel != -1) {
168220c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
168320c794b3Sgavinm 		    "motherboard", 0,
168420c794b3Sgavinm 		    "memory-controller", sp->branch,
168520c794b3Sgavinm 		    "dram-channel", sp->channel);
16866cb1ca52Saf 	} else if (sp->branch != -1) {
168720c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
168820c794b3Sgavinm 		    "motherboard", 0,
168920c794b3Sgavinm 		    "memory-controller", sp->branch);
16906cb1ca52Saf 	} else {
16916cb1ca52Saf 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
16926cb1ca52Saf 		    "motherboard", 0);
169320c794b3Sgavinm 	}
169420c794b3Sgavinm 
169520c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s",
169620c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr);
169720c794b3Sgavinm }
169820c794b3Sgavinm 
169920c794b3Sgavinm void
170020c794b3Sgavinm nb_dma_report(char *class, nvlist_t *detector)
170120c794b3Sgavinm {
170220c794b3Sgavinm 	fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
170320c794b3Sgavinm 	    "motherboard", 0);
170420c794b3Sgavinm 
170520c794b3Sgavinm 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
170620c794b3Sgavinm 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "dma");
170720c794b3Sgavinm }
170820c794b3Sgavinm 
17095f28a827Saf void
17105f28a827Saf nb_thr_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
17115f28a827Saf     void *data)
17125f28a827Saf {
17135f28a827Saf 	((nb_scatchpad_t *)data)->intel_error_list =
17145f28a827Saf 	    intel_thr_err(nb_regs->nb.thr_regs.ferr_fat_thr,
17155f28a827Saf 	    nb_regs->nb.thr_regs.ferr_nf_thr);
17165f28a827Saf 	fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
17175f28a827Saf 	    "motherboard", 0);
17185f28a827Saf 
17195f28a827Saf 	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
17205f28a827Saf 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "otf");
17215f28a827Saf }
17225f28a827Saf 
172320c794b3Sgavinm 
172420c794b3Sgavinm nvlist_t *
172520c794b3Sgavinm nb_report(const nb_regs_t *nb_regs, char *class, nv_alloc_t *nva, void *scratch)
172620c794b3Sgavinm {
172720c794b3Sgavinm 	nvlist_t *detector = fm_nvlist_create(nva);
172820c794b3Sgavinm 
172920c794b3Sgavinm 	switch (nb_regs->flag) {
173020c794b3Sgavinm 	case NB_REG_LOG_FSB:
173120c794b3Sgavinm 		nb_fsb_report(nb_regs, class, detector, scratch);
173220c794b3Sgavinm 		break;
173320c794b3Sgavinm 	case NB_REG_LOG_PEX:
173420c794b3Sgavinm 		nb_pex_report(nb_regs, class, detector, scratch);
173520c794b3Sgavinm 		break;
173620c794b3Sgavinm 	case NB_REG_LOG_INT:
173720c794b3Sgavinm 		nb_int_report(nb_regs, class, detector, scratch);
173820c794b3Sgavinm 		break;
173920c794b3Sgavinm 	case NB_REG_LOG_FAT_FBD:
174020c794b3Sgavinm 		nb_fat_fbd_report(nb_regs, class, detector, scratch);
174120c794b3Sgavinm 		break;
174220c794b3Sgavinm 	case NB_REG_LOG_NF_FBD:
174320c794b3Sgavinm 		nb_nf_fbd_report(nb_regs, class, detector, scratch);
174420c794b3Sgavinm 		break;
174520c794b3Sgavinm 	case NB_REG_LOG_DMA:
174620c794b3Sgavinm 		nb_dma_report(class, detector);
174720c794b3Sgavinm 		break;
17485f28a827Saf 	case NB_REG_LOG_THR:
17495f28a827Saf 		nb_thr_report(nb_regs, class, detector, scratch);
17505f28a827Saf 		break;
175120c794b3Sgavinm 	default:
175220c794b3Sgavinm 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
175320c794b3Sgavinm 		    "motherboard", 0);
175420c794b3Sgavinm 
175520c794b3Sgavinm 		(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s.%s",
175620c794b3Sgavinm 		    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "unknown");
175720c794b3Sgavinm 	}
175820c794b3Sgavinm 	return (detector);
175920c794b3Sgavinm }
176020c794b3Sgavinm 
176120c794b3Sgavinm /*ARGSUSED*/
176220c794b3Sgavinm void
176320c794b3Sgavinm nb_drain(void *ignored, const void *data, const errorq_elem_t *eqe)
176420c794b3Sgavinm {
176520c794b3Sgavinm 	nb_logout_t *acl = (nb_logout_t *)data;
176620c794b3Sgavinm 	errorq_elem_t *eqep, *scr_eqep;
176720c794b3Sgavinm 	nvlist_t *ereport, *detector;
176820c794b3Sgavinm 	nv_alloc_t *nva = NULL;
176920c794b3Sgavinm 	char buf[FM_MAX_CLASS];
177020c794b3Sgavinm 	nb_scatchpad_t nb_scatchpad;
177120c794b3Sgavinm 
177220c794b3Sgavinm 	if (panicstr) {
177320c794b3Sgavinm 		if ((eqep = errorq_reserve(ereport_errorq)) == NULL)
177420c794b3Sgavinm 			return;
177520c794b3Sgavinm 		ereport = errorq_elem_nvl(ereport_errorq, eqep);
177620c794b3Sgavinm 		/*
177720c794b3Sgavinm 		 * Now try to allocate another element for scratch space and
177820c794b3Sgavinm 		 * use that for further scratch space (eg for constructing
177920c794b3Sgavinm 		 * nvlists to add the main ereport).  If we can't reserve
178020c794b3Sgavinm 		 * a scratch element just fallback to working within the
178120c794b3Sgavinm 		 * element we already have, and hope for the best.  All this
178220c794b3Sgavinm 		 * is necessary because the fixed buffer nv allocator does
178320c794b3Sgavinm 		 * not reclaim freed space and nvlist construction is
178420c794b3Sgavinm 		 * expensive.
178520c794b3Sgavinm 		 */
178620c794b3Sgavinm 		if ((scr_eqep = errorq_reserve(ereport_errorq)) != NULL)
178720c794b3Sgavinm 			nva = errorq_elem_nva(ereport_errorq, scr_eqep);
178820c794b3Sgavinm 		else
178920c794b3Sgavinm 			nva = errorq_elem_nva(ereport_errorq, eqep);
179020c794b3Sgavinm 	} else {
179120c794b3Sgavinm 		ereport = fm_nvlist_create(NULL);
179220c794b3Sgavinm 	}
179320c794b3Sgavinm 	detector = nb_report(&acl->nb_regs, buf, nva, &nb_scatchpad);
179420c794b3Sgavinm 	if (detector == NULL)
179520c794b3Sgavinm 		return;
179620c794b3Sgavinm 	fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
179720c794b3Sgavinm 	    fm_ena_generate(acl->acl_timestamp, FM_ENA_FMT1), detector, NULL);
179820c794b3Sgavinm 	/*
179920c794b3Sgavinm 	 * We're done with 'detector' so reclaim the scratch space.
180020c794b3Sgavinm 	 */
180120c794b3Sgavinm 	if (panicstr) {
180220c794b3Sgavinm 		fm_nvlist_destroy(detector, FM_NVA_RETAIN);
180320c794b3Sgavinm 		nv_alloc_reset(nva);
180420c794b3Sgavinm 	} else {
180520c794b3Sgavinm 		fm_nvlist_destroy(detector, FM_NVA_FREE);
180620c794b3Sgavinm 	}
180720c794b3Sgavinm 
180820c794b3Sgavinm 	/*
180920c794b3Sgavinm 	 * Encode the error-specific data that was saved in the logout area.
181020c794b3Sgavinm 	 */
181120c794b3Sgavinm 	nb_ereport_add_logout(ereport, acl, &nb_scatchpad);
181220c794b3Sgavinm 
181320c794b3Sgavinm 	if (panicstr) {
181420c794b3Sgavinm 		errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
181520c794b3Sgavinm 		if (scr_eqep)
181620c794b3Sgavinm 			errorq_cancel(ereport_errorq, scr_eqep);
181720c794b3Sgavinm 	} else {
181820c794b3Sgavinm 		(void) fm_ereport_post(ereport, EVCH_TRYHARD);
181920c794b3Sgavinm 		fm_nvlist_destroy(ereport, FM_NVA_FREE);
182020c794b3Sgavinm 	}
182120c794b3Sgavinm }
1822