xref: /illumos-gate/usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c (revision f0b62587229842fad8c5df20795bf9bca17327bd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Intel model-specific support.  Right now all this conists of is
29  * to modify the ereport subclass to produce different ereport classes
30  * so that we can have different diagnosis rules and corresponding faults.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/cmn_err.h>
35 #include <sys/modctl.h>
36 #include <sys/mca_x86.h>
37 #include <sys/cpu_module_ms_impl.h>
38 #include <sys/mc_intel.h>
39 #include <sys/pci_cfgspace.h>
40 #include <sys/fm/protocol.h>
41 #include <sys/fm/util.h>
42 #include <sys/fm/smb/fmsmb.h>
43 
44 extern int x86gentopo_legacy;
45 
46 int gintel_ms_support_disable = 0;
47 int gintel_error_action_return = 0;
48 int gintel_ms_unconstrained = 0;
49 
50 int quickpath;
51 int max_bus_number = 0xff;
52 
53 #define	ERR_COUNTER_INDEX	2
54 #define	MAX_CPU_NODES		2
55 #define	N_MC_COR_ECC_CNT	6
56 uint32_t err_counter_array[MAX_CPU_NODES][ERR_COUNTER_INDEX][N_MC_COR_ECC_CNT];
57 uint8_t	err_counter_index[MAX_CPU_NODES];
58 
59 #define	MAX_BUS_NUMBER  max_bus_number
60 #define	SOCKET_BUS(cpu) (MAX_BUS_NUMBER - (cpu))
61 
62 #define	MC_COR_ECC_CNT(chipid, reg)	(*pci_getl_func)(SOCKET_BUS(chipid), \
63     NEHALEM_EP_MEMORY_CONTROLLER_DEV, NEHALEM_EP_MEMORY_CONTROLLER_FUNC, \
64     0x80 + (reg) * 4)
65 
66 #define	MSCOD_MEM_ECC_READ	0x1
67 #define	MSCOD_MEM_ECC_SCRUB	0x2
68 #define	MSCOD_MEM_WR_PARITY	0x4
69 #define	MSCOD_MEM_REDUNDANT_MEM	0x8
70 #define	MSCOD_MEM_SPARE_MEM	0x10
71 #define	MSCOD_MEM_ILLEGAL_ADDR	0x20
72 #define	MSCOD_MEM_BAD_ID	0x40
73 #define	MSCOD_MEM_ADDR_PARITY	0x80
74 #define	MSCOD_MEM_BYTE_PARITY	0x100
75 
76 #define	GINTEL_ERROR_MEM	0x1000
77 #define	GINTEL_ERROR_QUICKPATH	0x2000
78 
79 #define	GINTEL_ERR_SPARE_MEM	(GINTEL_ERROR_MEM | 1)
80 #define	GINTEL_ERR_MEM_UE	(GINTEL_ERROR_MEM | 2)
81 #define	GINTEL_ERR_MEM_CE	(GINTEL_ERROR_MEM | 3)
82 #define	GINTEL_ERR_MEM_PARITY	(GINTEL_ERROR_MEM | 4)
83 #define	GINTEL_ERR_MEM_ADDR_PARITY	(GINTEL_ERROR_MEM | 5)
84 #define	GINTEL_ERR_MEM_REDUNDANT (GINTEL_ERROR_MEM | 6)
85 #define	GINTEL_ERR_MEM_BAD_ADDR	(GINTEL_ERROR_MEM | 7)
86 #define	GINTEL_ERR_MEM_BAD_ID	(GINTEL_ERROR_MEM | 8)
87 #define	GINTEL_ERR_MEM_UNKNOWN	(GINTEL_ERROR_MEM | 0xfff)
88 
89 #define	MSR_MC_MISC_MEM_CHANNEL_MASK	0x00000000000c0000ULL
90 #define	MSR_MC_MISC_MEM_CHANNEL_SHIFT	18
91 #define	MSR_MC_MISC_MEM_DIMM_MASK	0x0000000000030000ULL
92 #define	MSR_MC_MISC_MEM_DIMM_SHIFT	16
93 #define	MSR_MC_MISC_MEM_SYNDROME_MASK	0xffffffff00000000ULL
94 #define	MSR_MC_MISC_MEM_SYNDROME_SHIFT	32
95 
96 #define	CPU_GENERATION_DONT_CARE	0
97 #define	CPU_GENERATION_NEHALEM_EP	1
98 
99 #define	INTEL_NEHALEM_CPU_FAMILY_ID	0x6
100 #define	INTEL_NEHALEM_CPU_MODEL_ID	0x1A
101 
102 #define	NEHALEM_EP_MEMORY_CONTROLLER_DEV	0x3
103 #define	NEHALEM_EP_MEMORY_CONTROLLER_FUNC	0x2
104 
105 /*ARGSUSED*/
106 int
107 gintel_init(cmi_hdl_t hdl, void **datap)
108 {
109 	uint32_t nb_chipset;
110 
111 	if (gintel_ms_support_disable)
112 		return (ENOTSUP);
113 
114 	if (!(x86_feature & X86_MCA))
115 		return (ENOTSUP);
116 
117 	nb_chipset = (*pci_getl_func)(0, 0, 0, 0x0);
118 	switch (nb_chipset) {
119 	case INTEL_NB_7300:
120 	case INTEL_NB_5000P:
121 	case INTEL_NB_5000X:
122 	case INTEL_NB_5000V:
123 	case INTEL_NB_5000Z:
124 	case INTEL_NB_5400:
125 	case INTEL_NB_5400A:
126 	case INTEL_NB_5400B:
127 		if (!gintel_ms_unconstrained)
128 			gintel_error_action_return |= CMS_ERRSCOPE_POISONED;
129 		break;
130 	case INTEL_QP_IO:
131 	case INTEL_QP_WP:
132 	case INTEL_QP_36D:
133 	case INTEL_QP_24D:
134 	case INTEL_QP_U1:
135 	case INTEL_QP_U2:
136 	case INTEL_QP_U3:
137 	case INTEL_QP_U4:
138 	case INTEL_QP_JF:
139 	case INTEL_QP_JF0:
140 	case INTEL_QP_JF1:
141 	case INTEL_QP_JF2:
142 	case INTEL_QP_JF3:
143 	case INTEL_QP_JF4:
144 	case INTEL_QP_JF5:
145 	case INTEL_QP_JF6:
146 	case INTEL_QP_JF7:
147 	case INTEL_QP_JF8:
148 	case INTEL_QP_JF9:
149 	case INTEL_QP_JFa:
150 	case INTEL_QP_JFb:
151 	case INTEL_QP_JFc:
152 	case INTEL_QP_JFd:
153 	case INTEL_QP_JFe:
154 	case INTEL_QP_JFf:
155 		quickpath = 1;
156 		break;
157 	default:
158 		break;
159 	}
160 	return (0);
161 }
162 
163 /*ARGSUSED*/
164 uint32_t
165 gintel_error_action(cmi_hdl_t hdl, int ismc, int bank,
166     uint64_t status, uint64_t addr, uint64_t misc, void *mslogout)
167 {
168 	if ((status & MSR_MC_STATUS_PCC) == 0)
169 		return (gintel_error_action_return);
170 	else
171 		return (gintel_error_action_return & ~CMS_ERRSCOPE_POISONED);
172 }
173 
174 /*ARGSUSED*/
175 cms_cookie_t
176 gintel_disp_match(cmi_hdl_t hdl, int bank, uint64_t status,
177     uint64_t addr, uint64_t misc, void *mslogout)
178 {
179 	cms_cookie_t rt = (cms_cookie_t)NULL;
180 	uint16_t mcacode = MCAX86_ERRCODE(status);
181 	uint16_t mscode = MCAX86_MSERRCODE(status);
182 
183 	if (MCAX86_ERRCODE_ISMEMORY_CONTROLLER(mcacode)) {
184 		/*
185 		 * memory controller errors
186 		 */
187 		if (mscode & MSCOD_MEM_SPARE_MEM) {
188 			rt = (cms_cookie_t)GINTEL_ERR_SPARE_MEM;
189 		} else if (mscode & (MSCOD_MEM_ECC_READ |
190 		    MSCOD_MEM_ECC_SCRUB)) {
191 			if (status & MSR_MC_STATUS_UC)
192 				rt = (cms_cookie_t)GINTEL_ERR_MEM_UE;
193 			else
194 				rt = (cms_cookie_t)GINTEL_ERR_MEM_CE;
195 		} else if (mscode & (MSCOD_MEM_WR_PARITY |
196 		    MSCOD_MEM_BYTE_PARITY)) {
197 			rt = (cms_cookie_t)GINTEL_ERR_MEM_PARITY;
198 		} else if (mscode & MSCOD_MEM_ADDR_PARITY) {
199 			rt = (cms_cookie_t)GINTEL_ERR_MEM_ADDR_PARITY;
200 		} else if (mscode & MSCOD_MEM_REDUNDANT_MEM) {
201 			rt = (cms_cookie_t)GINTEL_ERR_MEM_REDUNDANT;
202 		} else if (mscode & MSCOD_MEM_ILLEGAL_ADDR) {
203 			rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ADDR;
204 		} else if (mscode & MSCOD_MEM_BAD_ID) {
205 			rt = (cms_cookie_t)GINTEL_ERR_MEM_BAD_ID;
206 		} else {
207 			rt = (cms_cookie_t)GINTEL_ERR_MEM_UNKNOWN;
208 		}
209 	} else if (quickpath &&
210 	    MCAX86_ERRCODE_ISBUS_INTERCONNECT(MCAX86_ERRCODE(status))) {
211 		rt = (cms_cookie_t)GINTEL_ERROR_QUICKPATH;
212 	}
213 	return (rt);
214 }
215 
216 /*ARGSUSED*/
217 void
218 gintel_ereport_class(cmi_hdl_t hdl, cms_cookie_t mscookie,
219     const char **cpuclsp, const char **leafclsp)
220 {
221 	*cpuclsp = FM_EREPORT_CPU_INTEL;
222 	switch ((uintptr_t)mscookie) {
223 	case GINTEL_ERROR_QUICKPATH:
224 		*leafclsp = "quickpath.interconnect";
225 		break;
226 	case GINTEL_ERR_SPARE_MEM:
227 		*leafclsp = "quickpath.mem_spare";
228 		break;
229 	case GINTEL_ERR_MEM_UE:
230 		*leafclsp = "quickpath.mem_ue";
231 		break;
232 	case GINTEL_ERR_MEM_CE:
233 		*leafclsp = "quickpath.mem_ce";
234 		break;
235 	case GINTEL_ERR_MEM_PARITY:
236 		*leafclsp = "quickpath.mem_parity";
237 		break;
238 	case GINTEL_ERR_MEM_ADDR_PARITY:
239 		*leafclsp = "quickpath.mem_addr_parity";
240 		break;
241 	case GINTEL_ERR_MEM_REDUNDANT:
242 		*leafclsp = "quickpath.mem_redundant";
243 		break;
244 	case GINTEL_ERR_MEM_BAD_ADDR:
245 		*leafclsp = "quickpath.mem_bad_addr";
246 		break;
247 	case GINTEL_ERR_MEM_BAD_ID:
248 		*leafclsp = "quickpath.mem_bad_id";
249 		break;
250 	case GINTEL_ERR_MEM_UNKNOWN:
251 		*leafclsp = "quickpath.mem_unknown";
252 		break;
253 	}
254 }
255 
256 static nvlist_t *
257 gintel_gentopo_ereport_detector(cmi_hdl_t hdl, cms_cookie_t mscookie,
258     nv_alloc_t *nva)
259 {
260 	nvlist_t *nvl = (nvlist_t *)NULL;
261 	nvlist_t *board_list = (nvlist_t *)NULL;
262 
263 	if (mscookie) {
264 		board_list = cmi_hdl_smb_bboard(hdl);
265 
266 		if (board_list == NULL)
267 			return (NULL);
268 
269 		if ((nvl = fm_nvlist_create(nva)) == NULL)
270 			return (NULL);
271 
272 		if ((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) {
273 			fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION,
274 			    NULL, NULL, board_list, 1,
275 			    "chip", cmi_hdl_smb_chipid(hdl));
276 		} else {
277 			fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION,
278 			    NULL, NULL, board_list, 2,
279 			    "chip", cmi_hdl_smb_chipid(hdl),
280 			    "memory-controller", 0);
281 		}
282 	}
283 	return (nvl);
284 }
285 
286 /*ARGSUSED*/
287 nvlist_t *
288 gintel_ereport_detector(cmi_hdl_t hdl, int bankno, cms_cookie_t mscookie,
289     nv_alloc_t *nva)
290 {
291 	nvlist_t *nvl = (nvlist_t *)NULL;
292 
293 	if (!x86gentopo_legacy) {
294 		nvl = gintel_gentopo_ereport_detector(hdl, mscookie, nva);
295 		return (nvl);
296 	}
297 
298 	if (mscookie) {
299 		if ((nvl = fm_nvlist_create(nva)) == NULL)
300 			return (NULL);
301 		if ((uintptr_t)mscookie & GINTEL_ERROR_QUICKPATH) {
302 			fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
303 			    "motherboard", 0,
304 			    "chip", cmi_hdl_chipid(hdl));
305 		} else {
306 			fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
307 			    "motherboard", 0,
308 			    "chip", cmi_hdl_chipid(hdl),
309 			    "memory-controller", 0);
310 		}
311 	}
312 	return (nvl);
313 }
314 
315 static nvlist_t *
316 gintel_gentopo_ereport_create_resource_elem(cmi_hdl_t hdl, nv_alloc_t *nva,
317     mc_unum_t *unump)
318 {
319 	nvlist_t *nvl, *snvl;
320 	nvlist_t *board_list = NULL;
321 
322 	board_list = cmi_hdl_smb_bboard(hdl);
323 	if (board_list == NULL) {
324 		return (NULL);
325 	}
326 
327 	if ((nvl = fm_nvlist_create(nva)) == NULL)	/* freed by caller */
328 		return (NULL);
329 
330 	if ((snvl = fm_nvlist_create(nva)) == NULL) {
331 		fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
332 		return (NULL);
333 	}
334 
335 	(void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET,
336 	    unump->unum_offset);
337 
338 	if (unump->unum_chan == -1) {
339 		fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl,
340 		    board_list, 2,
341 		    "chip", cmi_hdl_smb_chipid(hdl),
342 		    "memory-controller", unump->unum_mc);
343 	} else if (unump->unum_cs == -1) {
344 		fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl,
345 		    board_list, 3,
346 		    "chip", cmi_hdl_smb_chipid(hdl),
347 		    "memory-controller", unump->unum_mc,
348 		    "dram-channel", unump->unum_chan);
349 	} else if (unump->unum_rank == -1) {
350 		fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl,
351 		    board_list, 4,
352 		    "chip", cmi_hdl_smb_chipid(hdl),
353 		    "memory-controller", unump->unum_mc,
354 		    "dram-channel", unump->unum_chan,
355 		    "dimm", unump->unum_cs);
356 	} else {
357 		fm_fmri_hc_create(nvl, FM_HC_SCHEME_VERSION, NULL, snvl,
358 		    board_list, 5,
359 		    "chip", cmi_hdl_smb_chipid(hdl),
360 		    "memory-controller", unump->unum_mc,
361 		    "dram-channel", unump->unum_chan,
362 		    "dimm", unump->unum_cs,
363 		    "rank", unump->unum_rank);
364 	}
365 
366 	fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
367 
368 	return (nvl);
369 }
370 
371 static nvlist_t *
372 gintel_ereport_create_resource_elem(nv_alloc_t *nva, mc_unum_t *unump)
373 {
374 	nvlist_t *nvl, *snvl;
375 
376 	if ((nvl = fm_nvlist_create(nva)) == NULL)	/* freed by caller */
377 		return (NULL);
378 
379 	if ((snvl = fm_nvlist_create(nva)) == NULL) {
380 		fm_nvlist_destroy(nvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
381 		return (NULL);
382 	}
383 
384 	(void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET,
385 	    unump->unum_offset);
386 
387 	if (unump->unum_chan == -1) {
388 		fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 3,
389 		    "motherboard", unump->unum_board,
390 		    "chip", unump->unum_chip,
391 		    "memory-controller", unump->unum_mc);
392 	} else if (unump->unum_cs == -1) {
393 		fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 4,
394 		    "motherboard", unump->unum_board,
395 		    "chip", unump->unum_chip,
396 		    "memory-controller", unump->unum_mc,
397 		    "dram-channel", unump->unum_chan);
398 	} else if (unump->unum_rank == -1) {
399 		fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 5,
400 		    "motherboard", unump->unum_board,
401 		    "chip", unump->unum_chip,
402 		    "memory-controller", unump->unum_mc,
403 		    "dram-channel", unump->unum_chan,
404 		    "dimm", unump->unum_cs);
405 	} else {
406 		fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, snvl, 6,
407 		    "motherboard", unump->unum_board,
408 		    "chip", unump->unum_chip,
409 		    "memory-controller", unump->unum_mc,
410 		    "dram-channel", unump->unum_chan,
411 		    "dimm", unump->unum_cs,
412 		    "rank", unump->unum_rank);
413 	}
414 
415 	fm_nvlist_destroy(snvl, nva ? FM_NVA_RETAIN : FM_NVA_FREE);
416 
417 	return (nvl);
418 }
419 
420 static void
421 nehalem_ep_ereport_add_memory_error_counter(uint_t  chipid,
422     uint32_t *this_err_counter_array)
423 {
424 	int	index;
425 
426 	for (index = 0; index < N_MC_COR_ECC_CNT; index ++)
427 		this_err_counter_array[index] = MC_COR_ECC_CNT(chipid, index);
428 }
429 
430 static int
431 gintel_cpu_generation(cmi_hdl_t hdl)
432 {
433 	int	cpu_generation = CPU_GENERATION_DONT_CARE;
434 
435 	if ((cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID) &&
436 	    (cmi_hdl_model(hdl) == INTEL_NEHALEM_CPU_MODEL_ID))
437 		cpu_generation = CPU_GENERATION_NEHALEM_EP;
438 
439 	return (cpu_generation);
440 }
441 
442 /*ARGSUSED*/
443 void
444 gintel_ereport_add_logout(cmi_hdl_t hdl, nvlist_t *ereport,
445     nv_alloc_t *nva, int banknum, uint64_t status, uint64_t addr,
446     uint64_t misc, void *mslogout, cms_cookie_t mscookie)
447 {
448 	mc_unum_t unum;
449 	nvlist_t *resource;
450 	uint32_t synd = 0;
451 	int  chan = MCAX86_ERRCODE_CCCC(status);
452 	uint8_t last_index, this_index;
453 	int chipid;
454 
455 	if (chan == 0xf)
456 		chan = -1;
457 
458 	if ((uintptr_t)mscookie & GINTEL_ERROR_MEM) {
459 		unum.unum_board = 0;
460 		unum.unum_chip = cmi_hdl_chipid(hdl);
461 		unum.unum_mc = 0;
462 		unum.unum_chan = chan;
463 		unum.unum_cs = -1;
464 		unum.unum_rank = -1;
465 		unum.unum_offset = -1ULL;
466 		if (status & MSR_MC_STATUS_MISCV) {
467 			unum.unum_chan =
468 			    (misc & MSR_MC_MISC_MEM_CHANNEL_MASK) >>
469 			    MSR_MC_MISC_MEM_CHANNEL_SHIFT;
470 			unum.unum_cs =
471 			    (misc & MSR_MC_MISC_MEM_DIMM_MASK) >>
472 			    MSR_MC_MISC_MEM_DIMM_SHIFT;
473 			synd = (misc & MSR_MC_MISC_MEM_SYNDROME_MASK) >>
474 			    MSR_MC_MISC_MEM_SYNDROME_SHIFT;
475 			fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ECC_SYND,
476 			    DATA_TYPE_UINT32, synd, 0);
477 		}
478 		if (status & MSR_MC_STATUS_ADDRV) {
479 			fm_payload_set(ereport, FM_FMRI_MEM_PHYSADDR,
480 			    DATA_TYPE_UINT64, addr, NULL);
481 			(void) cmi_mc_patounum(addr, 0, 0, synd, 0, &unum);
482 			if (unum.unum_offset != -1ULL &&
483 			    (unum.unum_offset & OFFSET_ROW_BANK_COL) != 0) {
484 				fm_payload_set(ereport,
485 				    FM_EREPORT_PAYLOAD_NAME_BANK,
486 				    DATA_TYPE_INT32,
487 				    TCODE_OFFSET_BANK(unum.unum_offset), NULL);
488 				fm_payload_set(ereport,
489 				    FM_EREPORT_PAYLOAD_NAME_CAS,
490 				    DATA_TYPE_INT32,
491 				    TCODE_OFFSET_CAS(unum.unum_offset), NULL);
492 				fm_payload_set(ereport,
493 				    FM_EREPORT_PAYLOAD_NAME_RAS,
494 				    DATA_TYPE_INT32,
495 				    TCODE_OFFSET_RAS(unum.unum_offset), NULL);
496 			}
497 		}
498 
499 		if (!x86gentopo_legacy) {
500 			resource = gintel_gentopo_ereport_create_resource_elem(
501 			    hdl, nva, &unum);
502 		} else {
503 			resource = gintel_ereport_create_resource_elem(nva,
504 			    &unum);
505 		}
506 
507 		fm_payload_set(ereport, FM_EREPORT_PAYLOAD_NAME_RESOURCE,
508 		    DATA_TYPE_NVLIST_ARRAY, 1, &resource, NULL);
509 		fm_nvlist_destroy(resource, nva ? FM_NVA_RETAIN:FM_NVA_FREE);
510 
511 		if (gintel_cpu_generation(hdl) == CPU_GENERATION_NEHALEM_EP) {
512 
513 			chipid = unum.unum_chip;
514 			if (chipid < MAX_CPU_NODES) {
515 				last_index = err_counter_index[chipid];
516 				this_index =
517 				    (last_index + 1) % ERR_COUNTER_INDEX;
518 				err_counter_index[chipid] = this_index;
519 				nehalem_ep_ereport_add_memory_error_counter(
520 				    chipid,
521 				    err_counter_array[chipid][this_index]);
522 				fm_payload_set(ereport,
523 				    FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_THIS,
524 				    DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT,
525 				    err_counter_array[chipid][this_index],
526 				    NULL);
527 				fm_payload_set(ereport,
528 				    FM_EREPORT_PAYLOAD_MEM_ECC_COUNTER_LAST,
529 				    DATA_TYPE_UINT32_ARRAY, N_MC_COR_ECC_CNT,
530 				    err_counter_array[chipid][last_index],
531 				    NULL);
532 			}
533 		}
534 	}
535 }
536 
537 boolean_t
538 gintel_bankctl_skipinit(cmi_hdl_t hdl, int banknum)
539 {
540 	/*
541 	 * On Intel family 6 before QuickPath we must not enable machine check
542 	 * from bank 0 detectors. bank 0 is reserved for the platform
543 	 */
544 
545 	if (banknum == 0 &&
546 	    cmi_hdl_family(hdl) == INTEL_NEHALEM_CPU_FAMILY_ID &&
547 	    cmi_hdl_model(hdl) < INTEL_NEHALEM_CPU_MODEL_ID)
548 		return (1);
549 	else
550 		return (0);
551 }
552 
553 cms_api_ver_t _cms_api_version = CMS_API_VERSION_1;
554 
555 const cms_ops_t _cms_ops = {
556 	gintel_init,		/* cms_init */
557 	NULL,			/* cms_post_startup */
558 	NULL,			/* cms_post_mpstartup */
559 	NULL,			/* cms_logout_size */
560 	NULL,			/* cms_mcgctl_val */
561 	gintel_bankctl_skipinit, /* cms_bankctl_skipinit */
562 	NULL,			/* cms_bankctl_val */
563 	NULL,			/* cms_bankstatus_skipinit */
564 	NULL,			/* cms_bankstatus_val */
565 	NULL,			/* cms_mca_init */
566 	NULL,			/* cms_poll_ownermask */
567 	NULL,			/* cms_bank_logout */
568 	gintel_error_action,	/* cms_error_action */
569 	gintel_disp_match,	/* cms_disp_match */
570 	gintel_ereport_class,	/* cms_ereport_class */
571 	gintel_ereport_detector,	/* cms_ereport_detector */
572 	NULL,			/* cms_ereport_includestack */
573 	gintel_ereport_add_logout,	/* cms_ereport_add_logout */
574 	NULL,			/* cms_msrinject */
575 	NULL,			/* cms_fini */
576 };
577 
578 static struct modlcpu modlcpu = {
579 	&mod_cpuops,
580 	"Generic Intel model-specific MCA"
581 };
582 
583 static struct modlinkage modlinkage = {
584 	MODREV_1,
585 	(void *)&modlcpu,
586 	NULL
587 };
588 
589 int
590 _init(void)
591 {
592 	return (mod_install(&modlinkage));
593 }
594 
595 int
596 _info(struct modinfo *modinfop)
597 {
598 	return (mod_info(&modlinkage, modinfop));
599 }
600 
601 int
602 _fini(void)
603 {
604 	return (mod_remove(&modlinkage));
605 }
606