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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/cmn_err.h>
31 #include <sys/errno.h>
32 #include <sys/log.h>
33 #include <sys/systm.h>
34 #include <sys/modctl.h>
35 #include <sys/errorq.h>
36 #include <sys/controlregs.h>
37 #include <sys/fm/util.h>
38 #include <sys/fm/protocol.h>
39 #include <sys/sysevent.h>
40 #include <sys/pghw.h>
41 #include <sys/cyclic.h>
42 #include <sys/pci_cfgspace.h>
43 #include <sys/mc_intel.h>
44 #include <sys/cpu_module_impl.h>
45 #include <sys/smbios.h>
46 #include <sys/pci.h>
47 #include <sys/machsystm.h>
48 #include "nb5000.h"
49 #include "nb_log.h"
50 #include "dimm_phys.h"
51 #include "rank.h"
52 
53 int nb_hw_memory_scrub_enable = 1;
54 static int nb_sw_scrub_disabled = 0;
55 
56 int nb_5000_memory_controller = 0;
57 int nb_number_memory_controllers = NB_5000_MAX_MEM_CONTROLLERS;
58 int nb_dimms_per_channel = 0;
59 static int ndimms = 0;
60 
61 nb_dimm_t **nb_dimms;
62 int nb_ndimm;
63 uint32_t nb_chipset;
64 enum nb_memory_mode nb_mode;
65 bank_select_t nb_banks[NB_MAX_MEM_BRANCH_SELECT];
66 rank_select_t nb_ranks[NB_5000_MAX_MEM_CONTROLLERS][NB_MAX_MEM_RANK_SELECT];
67 uint32_t top_of_low_memory;
68 uint8_t spare_rank[NB_5000_MAX_MEM_CONTROLLERS];
69 
70 errorq_t *nb_queue;
71 kmutex_t nb_mutex;
72 
73 static uint8_t nb_err0_int;
74 static uint8_t nb_err1_int;
75 static uint8_t nb_err2_int;
76 static uint8_t nb_mcerr_int;
77 static uint32_t nb_emask_int;
78 
79 static uint32_t nb_err0_fbd;
80 static uint32_t nb_err1_fbd;
81 static uint32_t nb_err2_fbd;
82 static uint32_t nb_mcerr_fbd;
83 static uint32_t nb_emask_fbd;
84 
85 static uint16_t nb_err0_fsb;
86 static uint16_t nb_err1_fsb;
87 static uint16_t nb_err2_fsb;
88 static uint16_t nb_mcerr_fsb;
89 static uint16_t nb_emask_fsb;
90 
91 static uint16_t nb_err0_thr;
92 static uint16_t nb_err1_thr;
93 static uint16_t nb_err2_thr;
94 static uint16_t nb_mcerr_thr;
95 static uint16_t nb_emask_thr;
96 
97 static uint32_t	emask_uncor_pex[NB_PCI_DEV];
98 static uint32_t emask_cor_pex[NB_PCI_DEV];
99 static uint32_t emask_rp_pex[NB_PCI_DEV];
100 static uint32_t docmd_pex[NB_PCI_DEV];
101 static uint32_t uncerrsev[NB_PCI_DEV];
102 
103 static uint8_t l_mcerr_int;
104 static uint32_t l_mcerr_fbd;
105 static uint16_t l_mcerr_fsb;
106 static uint16_t l_mcerr_thr;
107 
108 uint_t nb5000_emask_fbd = EMASK_5000_FBD_RES;
109 uint_t nb5400_emask_fbd = 0;
110 int nb5000_reset_emask_fbd = 1;
111 uint_t nb5000_mask_poll_fbd = EMASK_FBD_NF;
112 uint_t nb5000_mask_bios_fbd = EMASK_FBD_FATAL;
113 uint_t nb5400_mask_poll_fbd = EMASK_5400_FBD_NF;
114 uint_t nb5400_mask_bios_fbd = EMASK_5400_FBD_FATAL;
115 
116 uint_t nb5000_emask_fsb = 0;
117 int nb5000_reset_emask_fsb = 1;
118 uint_t nb5000_mask_poll_fsb = EMASK_FSB_NF;
119 uint_t nb5000_mask_bios_fsb = EMASK_FSB_FATAL;
120 
121 uint_t nb5400_emask_int = 0;
122 
123 uint_t nb7300_emask_int = EMASK_INT_7300;
124 uint_t nb7300_emask_int_step0 = EMASK_INT_7300_STEP_0;
125 uint_t nb5000_emask_int = EMASK_INT_5000;
126 int nb5000_reset_emask_int = 1;
127 uint_t nb5000_mask_poll_int = EMASK_INT_NF;
128 uint_t nb5000_mask_bios_int = EMASK_INT_FATAL;
129 
130 uint_t nb_mask_poll_thr = EMASK_THR_NF;
131 uint_t nb_mask_bios_thr = EMASK_THR_FATAL;
132 
133 int nb5000_reset_uncor_pex = 0;
134 uint_t nb5000_mask_uncor_pex = 0;
135 int nb5000_reset_cor_pex = 0;
136 uint_t nb5000_mask_cor_pex = 0xffffffff;
137 int nb_set_docmd = 1;
138 uint32_t nb5000_docmd_pex_mask = DOCMD_PEX_MASK;
139 uint32_t nb5400_docmd_pex_mask = DOCMD_5400_PEX_MASK;
140 uint32_t nb5000_docmd_pex = DOCMD_PEX;
141 uint32_t nb5400_docmd_pex = DOCMD_5400_PEX;
142 
143 int nb_mask_mc_set;
144 
145 typedef struct find_dimm_label {
146 	void (*label_function)(int, char *, int);
147 } find_dimm_label_t;
148 
149 static void x8450_dimm_label(int, char *, int);
150 
151 static struct platform_label {
152 	const char *sys_vendor;		/* SMB_TYPE_SYSTEM vendor prefix */
153 	const char *sys_product;	/* SMB_TYPE_SYSTEM product prefix */
154 	find_dimm_label_t dimm_label;
155 	int dimms_per_channel;
156 } platform_label[] = {
157 	{ "SUN MICROSYSTEMS", "SUN BLADE X8450 SERVER MODULE",
158 	    x8450_dimm_label, 8 },
159 	{ NULL, NULL, NULL, 0 }
160 };
161 
162 static unsigned short
163 read_spd(int bus)
164 {
165 	unsigned short rt = 0;
166 	int branch = bus >> 1;
167 	int channel = bus & 1;
168 
169 	rt = SPD_RD(branch, channel);
170 
171 	return (rt);
172 }
173 
174 static void
175 write_spdcmd(int bus, uint32_t val)
176 {
177 	int branch = bus >> 1;
178 	int channel = bus & 1;
179 	SPDCMD_WR(branch, channel, val);
180 }
181 
182 static int
183 read_spd_eeprom(int bus, int slave, int addr)
184 {
185 	int retry = 4;
186 	int wait;
187 	int spd;
188 	uint32_t cmd;
189 
190 	for (;;) {
191 		wait = 1000;
192 		for (;;) {
193 			spd = read_spd(bus);
194 			if ((spd & SPD_BUSY) == 0)
195 				break;
196 			if (--wait == 0)
197 				return (-1);
198 			drv_usecwait(10);
199 		}
200 		cmd = SPD_EEPROM_WRITE | SPD_ADDR(slave, addr);
201 		write_spdcmd(bus, cmd);
202 		wait = 1000;
203 		for (;;) {
204 			spd = read_spd(bus);
205 			if ((spd & SPD_BUSY) == 0)
206 				break;
207 			if (--wait == 0) {
208 				spd = SPD_BUS_ERROR;
209 				break;
210 			}
211 			drv_usecwait(10);
212 		}
213 		while ((spd & SPD_BUS_ERROR) == 0 &&
214 		    (spd & (SPD_READ_DATA_VALID|SPD_BUSY)) !=
215 		    SPD_READ_DATA_VALID) {
216 			spd = read_spd(bus);
217 			if (--wait == 0)
218 				return (-1);
219 		}
220 		if ((spd & SPD_BUS_ERROR) == 0)
221 			break;
222 		if (--retry == 0)
223 			return (-1);
224 	}
225 	return (spd & 0xff);
226 }
227 
228 static void
229 nb_fini()
230 {
231 	int i, j;
232 	int nchannels = nb_number_memory_controllers * 2;
233 	nb_dimm_t **dimmpp;
234 	nb_dimm_t *dimmp;
235 
236 	dimmpp = nb_dimms;
237 	for (i = 0; i < nchannels; i++) {
238 		for (j = 0; j < nb_dimms_per_channel; j++) {
239 			dimmp = *dimmpp;
240 			if (dimmp) {
241 				kmem_free(dimmp, sizeof (nb_dimm_t));
242 				*dimmpp = NULL;
243 			}
244 			dimmp++;
245 		}
246 	}
247 	kmem_free(nb_dimms, sizeof (nb_dimm_t *) *
248 	    nb_number_memory_controllers * 2 * nb_dimms_per_channel);
249 	nb_dimms = NULL;
250 	dimm_fini();
251 }
252 
253 void
254 nb_scrubber_enable()
255 {
256 	uint32_t mc;
257 
258 	if (!nb_hw_memory_scrub_enable)
259 		return;
260 
261 	mc = MC_RD();
262 	if ((mc & MC_MIRROR) != 0) /* mirror mode */
263 		mc |= MC_PATROL_SCRUB;
264 	else
265 		mc |= MC_PATROL_SCRUB|MC_DEMAND_SCRUB;
266 	MC_WR(mc);
267 
268 	if (nb_sw_scrub_disabled++)
269 		memscrub_disable();
270 }
271 
272 static nb_dimm_t *
273 nb_dimm_init(int channel, int dimm, uint16_t mtr)
274 {
275 	nb_dimm_t *dp;
276 	int i, t;
277 	int spd_sz;
278 
279 	if (MTR_PRESENT(mtr) == 0)
280 		return (NULL);
281 	t = read_spd_eeprom(channel, dimm, 2) & 0xf;
282 
283 	if (t != 9)
284 		return (NULL);
285 
286 	dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP);
287 
288 	t = read_spd_eeprom(channel, dimm, 0) & 0xf;
289 	if (t == 1)
290 		spd_sz = 128;
291 	else if (t == 2)
292 		spd_sz = 176;
293 	else
294 		spd_sz = 256;
295 	dp->manufacture_id = read_spd_eeprom(channel, dimm, 117) |
296 	    (read_spd_eeprom(channel, dimm, 118) << 8);
297 	dp->manufacture_location = read_spd_eeprom(channel, dimm, 119);
298 	dp->serial_number =
299 	    (read_spd_eeprom(channel, dimm, 122) << 24) |
300 	    (read_spd_eeprom(channel, dimm, 123) << 16) |
301 	    (read_spd_eeprom(channel, dimm, 124) << 8) |
302 	    read_spd_eeprom(channel, dimm, 125);
303 	t = read_spd_eeprom(channel, dimm, 121);
304 	dp->manufacture_week = (t >> 4) * 10 + (t & 0xf);
305 	dp->manufacture_year = read_spd_eeprom(channel, dimm, 120);
306 	if (spd_sz > 128) {
307 		for (i = 0; i < sizeof (dp->part_number); i++) {
308 			dp->part_number[i] =
309 			    read_spd_eeprom(channel, dimm, 128 + i);
310 		}
311 		for (i = 0; i < sizeof (dp->revision); i++) {
312 			dp->revision[i] =
313 			    read_spd_eeprom(channel, dimm, 146 + i);
314 		}
315 	}
316 	dp->mtr_present = MTR_PRESENT(mtr);
317 	dp->nranks = MTR_NUMRANK(mtr);
318 	dp->nbanks = MTR_NUMBANK(mtr);
319 	dp->ncolumn = MTR_NUMCOL(mtr);
320 	dp->nrow = MTR_NUMROW(mtr);
321 	dp->width = MTR_WIDTH(mtr);
322 	dp->dimm_size = MTR_DIMMSIZE(mtr);
323 
324 	return (dp);
325 }
326 
327 static uint64_t
328 mc_range(int controller, uint64_t base)
329 {
330 	int i;
331 	uint64_t limit = 0;
332 
333 	for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
334 		if (nb_banks[i].way[controller] && base >= nb_banks[i].base &&
335 		    base < nb_banks[i].limit) {
336 			limit = nb_banks[i].limit;
337 			if (base <= top_of_low_memory &&
338 			    limit > top_of_low_memory) {
339 				limit -= TLOW_MAX - top_of_low_memory;
340 			}
341 			if (nb_banks[i].way[0] && nb_banks[i].way[1] &&
342 			    nb_mode != NB_MEMORY_MIRROR) {
343 				limit = limit / 2;
344 			}
345 		}
346 	}
347 	return (limit);
348 }
349 
350 void
351 nb_mc_init()
352 {
353 	uint16_t tolm;
354 	uint16_t mir;
355 	uint32_t hole_base;
356 	uint32_t hole_size;
357 	uint32_t dmir;
358 	uint64_t base;
359 	uint64_t limit;
360 	uint8_t way0, way1, rank0, rank1, rank2, rank3, branch_interleave;
361 	int i, j, k;
362 	uint8_t interleave;
363 
364 	base = 0;
365 	tolm = TOLM_RD();
366 	top_of_low_memory = ((uint32_t)(tolm >> 12) & 0xf) << 28;
367 	for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
368 		mir = MIR_RD(i);
369 		limit = (uint64_t)(mir >> 4) << 28;
370 		way0 = mir & 1;
371 		way1 = (mir >> 1) & 1;
372 		if (way0 == 0 && way1 == 0) {
373 			way0 = 1;
374 			way1 = 1;
375 		}
376 		if (limit > top_of_low_memory)
377 			limit += TLOW_MAX - top_of_low_memory;
378 		nb_banks[i].base = base;
379 		nb_banks[i].limit = limit;
380 		nb_banks[i].way[0] = way0;
381 		nb_banks[i].way[1] = way1;
382 		base = limit;
383 	}
384 	for (i = 0; i < nb_number_memory_controllers; i++) {
385 		base = 0;
386 
387 		for (j = 0; j < NB_MEM_RANK_SELECT; j++) {
388 			dmir = DMIR_RD(i, j);
389 			limit = ((uint64_t)(dmir >> 16) & 0xff) << 28;
390 			if (limit == 0) {
391 				limit = mc_range(i, base);
392 			}
393 			branch_interleave = 0;
394 			hole_base = 0;
395 			hole_size = 0;
396 			DMIR_RANKS(dmir, rank0, rank1, rank2, rank3);
397 			if (rank0 == rank1)
398 				interleave = 1;
399 			else if (rank0 == rank2)
400 				interleave = 2;
401 			else
402 				interleave = 4;
403 			if (nb_mode != NB_MEMORY_MIRROR &&
404 			    nb_mode != NB_MEMORY_SINGLE_CHANNEL) {
405 				for (k = 0; k < NB_MEM_BRANCH_SELECT; k++) {
406 					if (base >= nb_banks[k].base &&
407 					    base < nb_banks[k].limit) {
408 						if (nb_banks[i].way[0] &&
409 						    nb_banks[i].way[1]) {
410 							interleave *= 2;
411 							limit *= 2;
412 							branch_interleave = 1;
413 						}
414 						break;
415 					}
416 				}
417 			}
418 			if (base < top_of_low_memory &&
419 			    limit > top_of_low_memory) {
420 				hole_base = top_of_low_memory;
421 				hole_size = TLOW_MAX - top_of_low_memory;
422 				limit += hole_size;
423 			} else if (base > top_of_low_memory) {
424 				limit += TLOW_MAX - top_of_low_memory;
425 			}
426 			nb_ranks[i][j].base = base;
427 			nb_ranks[i][j].limit = limit;
428 			nb_ranks[i][j].rank[0] = rank0;
429 			nb_ranks[i][j].rank[1] = rank1;
430 			nb_ranks[i][j].rank[2] = rank2;
431 			nb_ranks[i][j].rank[3] = rank3;
432 			nb_ranks[i][j].interleave = interleave;
433 			nb_ranks[i][j].branch_interleave = branch_interleave;
434 			nb_ranks[i][j].hole_base = hole_base;
435 			nb_ranks[i][j].hole_size = hole_size;
436 			if (limit > base) {
437 				dimm_add_rank(i, rank0, branch_interleave, 0,
438 				    base, hole_base, hole_size, interleave,
439 				    limit);
440 				if (rank0 != rank1) {
441 					dimm_add_rank(i, rank1,
442 					    branch_interleave, 1, base,
443 					    hole_base, hole_size, interleave,
444 					    limit);
445 					if (rank0 != rank2) {
446 						dimm_add_rank(i, rank2,
447 						    branch_interleave, 2, base,
448 						    hole_base, hole_size,
449 						    interleave, limit);
450 						dimm_add_rank(i, rank3,
451 						    branch_interleave, 3, base,
452 						    hole_base, hole_size,
453 						    interleave, limit);
454 					}
455 				}
456 			}
457 			base = limit;
458 		}
459 	}
460 }
461 
462 void
463 nb_used_spare_rank(int branch, int bad_rank)
464 {
465 	int i;
466 	int j;
467 
468 	for (i = 0; i < NB_MEM_RANK_SELECT; i++) {
469 		for (j = 0; j < NB_RANKS_IN_SELECT; j++) {
470 			if (nb_ranks[branch][i].rank[j] == bad_rank) {
471 				nb_ranks[branch][i].rank[j] =
472 				    spare_rank[branch];
473 				i = NB_MEM_RANK_SELECT;
474 				break;
475 			}
476 		}
477 	}
478 }
479 
480 /*ARGSUSED*/
481 static int
482 memoryarray(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
483 {
484 	smbios_memarray_t ma;
485 
486 	if (sp->smbstr_type == SMB_TYPE_MEMARRAY &&
487 	    smbios_info_memarray(shp, sp->smbstr_id, &ma) == 0) {
488 		ndimms += ma.smbma_ndevs;
489 	}
490 	return (0);
491 }
492 
493 find_dimm_label_t *
494 find_dimms_per_channel()
495 {
496 	struct platform_label *pl;
497 	smbios_info_t si;
498 	smbios_system_t sy;
499 	id_t id;
500 	int read_memarray = 1;
501 	find_dimm_label_t *rt = NULL;
502 
503 	if (ksmbios != NULL) {
504 		if ((id = smbios_info_system(ksmbios, &sy)) != SMB_ERR &&
505 		    smbios_info_common(ksmbios, id, &si) != SMB_ERR) {
506 			for (pl = platform_label; pl->sys_vendor; pl++) {
507 				if (strncmp(pl->sys_vendor,
508 				    si.smbi_manufacturer,
509 				    strlen(pl->sys_vendor)) == 0 &&
510 				    strncmp(pl->sys_product, si.smbi_product,
511 				    strlen(pl->sys_product)) == 0) {
512 					nb_dimms_per_channel =
513 					    pl->dimms_per_channel;
514 					read_memarray = 0;
515 					rt = &pl->dimm_label;
516 					break;
517 				}
518 			}
519 		}
520 		if (read_memarray)
521 			(void) smbios_iter(ksmbios, memoryarray, 0);
522 	}
523 	if (nb_dimms_per_channel == 0) {
524 		if (ndimms) {
525 			nb_dimms_per_channel = ndimms /
526 			    (nb_number_memory_controllers * 2);
527 		} else {
528 			nb_dimms_per_channel = NB_MAX_DIMMS_PER_CHANNEL;
529 		}
530 	}
531 	return (rt);
532 }
533 
534 static int
535 dimm_label(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
536 {
537 	nb_dimm_t ***dimmpp = arg;
538 	nb_dimm_t *dimmp;
539 	smbios_memdevice_t md;
540 
541 	if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) {
542 		dimmp = **dimmpp;
543 		if (dimmp && smbios_info_memdevice(shp, sp->smbstr_id,
544 		    &md) == 0 && md.smbmd_dloc != NULL) {
545 			(void) snprintf(dimmp->label,
546 			    sizeof (dimmp->label), "%s", md.smbmd_dloc);
547 		}
548 		(*dimmpp)++;
549 	}
550 	return (0);
551 }
552 
553 void
554 nb_smbios()
555 {
556 	nb_dimm_t **dimmpp;
557 
558 	if (ksmbios != NULL) {
559 		dimmpp = nb_dimms;
560 		(void) smbios_iter(ksmbios, dimm_label, &dimmpp);
561 	}
562 }
563 
564 static void
565 x8450_dimm_label(int dimm, char *label, int label_sz)
566 {
567 	int channel = dimm >> 3;
568 
569 	dimm = dimm & 0x7;
570 	(void) snprintf(label, label_sz, "D%d", (dimm * 4) + channel);
571 }
572 
573 static void
574 nb_dimms_init(find_dimm_label_t *label_function)
575 {
576 	int i, j, k, l;
577 	uint16_t mtr;
578 	uint32_t mc, mca;
579 	uint32_t spcpc;
580 	uint8_t spcps;
581 	nb_dimm_t **dimmpp;
582 
583 	mca = MCA_RD();
584 	mc = MC_RD();
585 	if (mca & MCA_SCHDIMM)  /* single-channel mode */
586 		nb_mode = NB_MEMORY_SINGLE_CHANNEL;
587 	else if ((mc & MC_MIRROR) != 0) /* mirror mode */
588 		nb_mode = NB_MEMORY_MIRROR;
589 	else
590 		nb_mode = NB_MEMORY_NORMAL;
591 	nb_dimms = (nb_dimm_t **)kmem_zalloc(sizeof (nb_dimm_t *) *
592 	    nb_number_memory_controllers * 2 * nb_dimms_per_channel, KM_SLEEP);
593 	dimmpp = nb_dimms;
594 	for (i = 0; i < nb_number_memory_controllers; i++) {
595 		if (nb_mode == NB_MEMORY_NORMAL) {
596 			spcpc = SPCPC_RD(i);
597 			spcps = SPCPS_RD(i);
598 			if ((spcpc & SPCPC_SPARE_ENABLE) != 0 &&
599 			    (spcps & SPCPS_SPARE_DEPLOYED) != 0)
600 				nb_mode = NB_MEMORY_SPARE_RANK;
601 			spare_rank[i] = SPCPC_SPRANK(spcpc);
602 		}
603 		for (j = 0; j < nb_dimms_per_channel; j++) {
604 			mtr = MTR_RD(i, j);
605 			k = i * 2;
606 			dimmpp[j] = nb_dimm_init(k, j, mtr);
607 			if (dimmpp[j]) {
608 				nb_ndimm ++;
609 				dimm_add_geometry(i, j, dimmpp[j]->nbanks,
610 				    dimmpp[j]->width, dimmpp[j]->ncolumn,
611 				    dimmpp[j]->nrow);
612 				if (label_function) {
613 					label_function->label_function(
614 					    (k * nb_dimms_per_channel) + j,
615 					    dimmpp[j]->label,
616 					    sizeof (dimmpp[j]->label));
617 				}
618 			}
619 			dimmpp[j + nb_dimms_per_channel] =
620 			    nb_dimm_init(k + 1, j, mtr);
621 			l = j + nb_dimms_per_channel;
622 			if (dimmpp[l]) {
623 				if (label_function) {
624 					label_function->label_function(
625 					    (k * nb_dimms_per_channel) + l,
626 					    dimmpp[l]->label,
627 					    sizeof (dimmpp[l]->label));
628 				}
629 				nb_ndimm ++;
630 			}
631 		}
632 		dimmpp += nb_dimms_per_channel * 2;
633 	}
634 	if (label_function == NULL)
635 		nb_smbios();
636 }
637 
638 static void
639 nb_pex_init()
640 {
641 	int i;
642 	uint32_t mask;
643 
644 	for (i = 0; i < NB_PCI_DEV; i++) {
645 		switch (nb_chipset) {
646 		case INTEL_NB_5000P:
647 		case INTEL_NB_5000X:
648 			if (i == 1 || i > 8)
649 				continue;
650 			break;
651 		case INTEL_NB_5000V:
652 			if (i == 1 || i > 3)
653 				continue;
654 			break;
655 		case INTEL_NB_5000Z:
656 			if (i == 1 || i > 5)
657 				continue;
658 			break;
659 		case INTEL_NB_5400:
660 			break;
661 		case INTEL_NB_7300:
662 			if (i > 8)
663 				continue;
664 			break;
665 		}
666 		emask_uncor_pex[i] = EMASK_UNCOR_PEX_RD(i);
667 		emask_cor_pex[i] = EMASK_COR_PEX_RD(i);
668 		emask_rp_pex[i] = EMASK_RP_PEX_RD(i);
669 		docmd_pex[i] = PEX_ERR_DOCMD_RD(i);
670 		uncerrsev[i] = UNCERRSEV_RD(i);
671 
672 		if (nb5000_reset_uncor_pex)
673 			EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex);
674 		if (nb5000_reset_cor_pex)
675 			EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex);
676 		if (nb_set_docmd) {
677 			if (nb_chipset == INTEL_NB_5400) {
678 				mask = (docmd_pex[i] & nb5400_docmd_pex_mask) |
679 				    (nb5400_docmd_pex & ~nb5400_docmd_pex_mask);
680 			} else {
681 				mask = (docmd_pex[i] & nb5000_docmd_pex_mask) |
682 				    (nb5000_docmd_pex & ~nb5000_docmd_pex_mask);
683 			}
684 			PEX_ERR_DOCMD_WR(i, mask);
685 		}
686 	}
687 }
688 
689 static void
690 nb_pex_fini()
691 {
692 	int i;
693 
694 	for (i = 0; i < NB_PCI_DEV; i++) {
695 		switch (nb_chipset) {
696 		case INTEL_NB_5000P:
697 		case INTEL_NB_5000X:
698 			if (i == 1 && i > 8)
699 				continue;
700 			break;
701 		case INTEL_NB_5000V:
702 			if (i == 1 || i > 3)
703 				continue;
704 			break;
705 		case INTEL_NB_5000Z:
706 			if (i == 1 || i > 5)
707 				continue;
708 			break;
709 		case INTEL_NB_5400:
710 			break;
711 		case INTEL_NB_7300:
712 			if (i > 8)
713 				continue;
714 			break;
715 		}
716 		EMASK_UNCOR_PEX_WR(i, emask_uncor_pex[i]);
717 		EMASK_COR_PEX_WR(i, emask_cor_pex[i]);
718 		EMASK_RP_PEX_WR(i, emask_rp_pex[i]);
719 		PEX_ERR_DOCMD_WR(i, docmd_pex[i]);
720 
721 		if (nb5000_reset_uncor_pex)
722 			EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex);
723 		if (nb5000_reset_cor_pex)
724 			EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex);
725 	}
726 }
727 
728 void
729 nb_int_init()
730 {
731 	uint8_t err0_int;
732 	uint8_t err1_int;
733 	uint8_t err2_int;
734 	uint8_t mcerr_int;
735 	uint32_t emask_int;
736 	uint16_t stepping;
737 
738 	err0_int = ERR0_INT_RD();
739 	err1_int = ERR1_INT_RD();
740 	err2_int = ERR2_INT_RD();
741 	mcerr_int = MCERR_INT_RD();
742 	emask_int = EMASK_INT_RD();
743 
744 	nb_err0_int = err0_int;
745 	nb_err1_int = err1_int;
746 	nb_err2_int = err2_int;
747 	nb_mcerr_int = mcerr_int;
748 	nb_emask_int = emask_int;
749 
750 	ERR0_INT_WR(0xff);
751 	ERR1_INT_WR(0xff);
752 	ERR2_INT_WR(0xff);
753 	MCERR_INT_WR(0xff);
754 	EMASK_INT_WR(0xff);
755 
756 	mcerr_int &= ~nb5000_mask_bios_int;
757 	mcerr_int |= nb5000_mask_bios_int & (~err0_int | ~err1_int | ~err2_int);
758 	mcerr_int |= nb5000_mask_poll_int;
759 	err0_int |= nb5000_mask_poll_int;
760 	err1_int |= nb5000_mask_poll_int;
761 	err2_int |= nb5000_mask_poll_int;
762 
763 	l_mcerr_int = mcerr_int;
764 	ERR0_INT_WR(err0_int);
765 	ERR1_INT_WR(err1_int);
766 	ERR2_INT_WR(err2_int);
767 	MCERR_INT_WR(mcerr_int);
768 	if (nb5000_reset_emask_int) {
769 		if (nb_chipset == INTEL_NB_7300) {
770 			stepping = NB5000_STEPPING();
771 			if (stepping == 0)
772 				EMASK_5000_INT_WR(nb7300_emask_int_step0);
773 			else
774 				EMASK_5000_INT_WR(nb7300_emask_int);
775 		} else if (nb_chipset == INTEL_NB_5400) {
776 			EMASK_5400_INT_WR(nb5400_emask_int |
777 			    (emask_int & EMASK_INT_RES));
778 		} else {
779 			EMASK_5000_INT_WR(nb5000_emask_int);
780 		}
781 	} else {
782 		EMASK_INT_WR(nb_emask_int);
783 	}
784 }
785 
786 void
787 nb_int_fini()
788 {
789 	ERR0_INT_WR(0xff);
790 	ERR1_INT_WR(0xff);
791 	ERR2_INT_WR(0xff);
792 	MCERR_INT_WR(0xff);
793 	EMASK_INT_WR(0xff);
794 
795 	ERR0_INT_WR(nb_err0_int);
796 	ERR1_INT_WR(nb_err1_int);
797 	ERR2_INT_WR(nb_err2_int);
798 	MCERR_INT_WR(nb_mcerr_int);
799 	EMASK_INT_WR(nb_emask_int);
800 }
801 
802 void
803 nb_int_mask_mc(uint32_t mc_mask_int)
804 {
805 	uint32_t emask_int;
806 
807 	emask_int = MCERR_INT_RD();
808 	if ((emask_int & mc_mask_int) != mc_mask_int) {
809 		MCERR_INT_WR(emask_int|mc_mask_int);
810 		nb_mask_mc_set = 1;
811 	}
812 }
813 
814 void
815 nb_fbd_init()
816 {
817 	uint32_t err0_fbd;
818 	uint32_t err1_fbd;
819 	uint32_t err2_fbd;
820 	uint32_t mcerr_fbd;
821 	uint32_t emask_fbd;
822 	uint32_t emask_bios_fbd;
823 	uint32_t emask_poll_fbd;
824 
825 	err0_fbd = ERR0_FBD_RD();
826 	err1_fbd = ERR1_FBD_RD();
827 	err2_fbd = ERR2_FBD_RD();
828 	mcerr_fbd = MCERR_FBD_RD();
829 	emask_fbd = EMASK_FBD_RD();
830 
831 	nb_err0_fbd = err0_fbd;
832 	nb_err1_fbd = err1_fbd;
833 	nb_err2_fbd = err2_fbd;
834 	nb_mcerr_fbd = mcerr_fbd;
835 	nb_emask_fbd = emask_fbd;
836 
837 	ERR0_FBD_WR(0xffffffff);
838 	ERR1_FBD_WR(0xffffffff);
839 	ERR2_FBD_WR(0xffffffff);
840 	MCERR_FBD_WR(0xffffffff);
841 	EMASK_FBD_WR(0xffffffff);
842 
843 	if (nb_chipset == INTEL_NB_7300 && nb_mode == NB_MEMORY_MIRROR) {
844 		/* MCH 7300 errata 34 */
845 		emask_bios_fbd = nb5000_mask_bios_fbd & ~EMASK_FBD_M23;
846 		emask_poll_fbd = nb5000_mask_poll_fbd;
847 		mcerr_fbd |= EMASK_FBD_M23;
848 	} else if (nb_chipset == INTEL_NB_5400) {
849 		emask_bios_fbd = nb5400_mask_bios_fbd;
850 		emask_poll_fbd = nb5400_mask_poll_fbd;
851 	} else {
852 		emask_bios_fbd = nb5000_mask_bios_fbd;
853 		emask_poll_fbd = nb5000_mask_poll_fbd;
854 	}
855 	mcerr_fbd &= ~emask_bios_fbd;
856 	mcerr_fbd |= emask_bios_fbd & (~err0_fbd | ~err1_fbd | ~err2_fbd);
857 	mcerr_fbd |= emask_poll_fbd;
858 	err0_fbd |= emask_poll_fbd;
859 	err1_fbd |= emask_poll_fbd;
860 	err2_fbd |= emask_poll_fbd;
861 
862 	l_mcerr_fbd = mcerr_fbd;
863 	ERR0_FBD_WR(err0_fbd);
864 	ERR1_FBD_WR(err1_fbd);
865 	ERR2_FBD_WR(err2_fbd);
866 	MCERR_FBD_WR(mcerr_fbd);
867 	if (nb5000_reset_emask_fbd) {
868 		if (nb_chipset == INTEL_NB_5400)
869 			EMASK_FBD_WR(nb5400_emask_fbd);
870 		else
871 			EMASK_FBD_WR(nb5000_emask_fbd);
872 	} else {
873 		EMASK_FBD_WR(nb_emask_fbd);
874 	}
875 }
876 
877 void
878 nb_fbd_mask_mc(uint32_t mc_mask_fbd)
879 {
880 	uint32_t emask_fbd;
881 
882 	emask_fbd = MCERR_FBD_RD();
883 	if ((emask_fbd & mc_mask_fbd) != mc_mask_fbd) {
884 		MCERR_FBD_WR(emask_fbd|mc_mask_fbd);
885 		nb_mask_mc_set = 1;
886 	}
887 }
888 
889 void
890 nb_fbd_fini()
891 {
892 	ERR0_FBD_WR(0xffffffff);
893 	ERR1_FBD_WR(0xffffffff);
894 	ERR2_FBD_WR(0xffffffff);
895 	MCERR_FBD_WR(0xffffffff);
896 	EMASK_FBD_WR(0xffffffff);
897 
898 	ERR0_FBD_WR(nb_err0_fbd);
899 	ERR1_FBD_WR(nb_err1_fbd);
900 	ERR2_FBD_WR(nb_err2_fbd);
901 	MCERR_FBD_WR(nb_mcerr_fbd);
902 	EMASK_FBD_WR(nb_emask_fbd);
903 }
904 
905 static void
906 nb_fsb_init()
907 {
908 	uint16_t err0_fsb;
909 	uint16_t err1_fsb;
910 	uint16_t err2_fsb;
911 	uint16_t mcerr_fsb;
912 	uint16_t emask_fsb;
913 
914 	err0_fsb = ERR0_FSB_RD(0);
915 	err1_fsb = ERR1_FSB_RD(0);
916 	err2_fsb = ERR2_FSB_RD(0);
917 	mcerr_fsb = MCERR_FSB_RD(0);
918 	emask_fsb = EMASK_FSB_RD(0);
919 
920 	ERR0_FSB_WR(0, 0xffff);
921 	ERR1_FSB_WR(0, 0xffff);
922 	ERR2_FSB_WR(0, 0xffff);
923 	MCERR_FSB_WR(0, 0xffff);
924 	EMASK_FSB_WR(0, 0xffff);
925 
926 	ERR0_FSB_WR(1, 0xffff);
927 	ERR1_FSB_WR(1, 0xffff);
928 	ERR2_FSB_WR(1, 0xffff);
929 	MCERR_FSB_WR(1, 0xffff);
930 	EMASK_FSB_WR(1, 0xffff);
931 
932 	nb_err0_fsb = err0_fsb;
933 	nb_err1_fsb = err1_fsb;
934 	nb_err2_fsb = err2_fsb;
935 	nb_mcerr_fsb = mcerr_fsb;
936 	nb_emask_fsb = emask_fsb;
937 
938 	mcerr_fsb &= ~nb5000_mask_bios_fsb;
939 	mcerr_fsb |= nb5000_mask_bios_fsb & (~err2_fsb | ~err1_fsb | ~err0_fsb);
940 	mcerr_fsb |= nb5000_mask_poll_fsb;
941 	err0_fsb |= nb5000_mask_poll_fsb;
942 	err1_fsb |= nb5000_mask_poll_fsb;
943 	err2_fsb |= nb5000_mask_poll_fsb;
944 
945 	l_mcerr_fsb = mcerr_fsb;
946 	ERR0_FSB_WR(0, err0_fsb);
947 	ERR1_FSB_WR(0, err1_fsb);
948 	ERR2_FSB_WR(0, err2_fsb);
949 	MCERR_FSB_WR(0, mcerr_fsb);
950 	if (nb5000_reset_emask_fsb) {
951 		EMASK_FSB_WR(0, nb5000_emask_fsb);
952 	} else {
953 		EMASK_FSB_WR(0, nb_emask_fsb);
954 	}
955 
956 	ERR0_FSB_WR(1, err0_fsb);
957 	ERR1_FSB_WR(1, err1_fsb);
958 	ERR2_FSB_WR(1, err2_fsb);
959 	MCERR_FSB_WR(1, mcerr_fsb);
960 	if (nb5000_reset_emask_fsb) {
961 		EMASK_FSB_WR(1, nb5000_emask_fsb);
962 	} else {
963 		EMASK_FSB_WR(1, nb_emask_fsb);
964 	}
965 
966 	if (nb_chipset == INTEL_NB_7300) {
967 		ERR0_FSB_WR(2, 0xffff);
968 		ERR1_FSB_WR(2, 0xffff);
969 		ERR2_FSB_WR(2, 0xffff);
970 		MCERR_FSB_WR(2, 0xffff);
971 		EMASK_FSB_WR(2, 0xffff);
972 
973 		ERR0_FSB_WR(3, 0xffff);
974 		ERR1_FSB_WR(3, 0xffff);
975 		ERR2_FSB_WR(3, 0xffff);
976 		MCERR_FSB_WR(3, 0xffff);
977 		EMASK_FSB_WR(3, 0xffff);
978 
979 		ERR0_FSB_WR(2, err0_fsb);
980 		ERR1_FSB_WR(2, err1_fsb);
981 		ERR2_FSB_WR(2, err2_fsb);
982 		MCERR_FSB_WR(2, mcerr_fsb);
983 		if (nb5000_reset_emask_fsb) {
984 			EMASK_FSB_WR(2, nb5000_emask_fsb);
985 		} else {
986 			EMASK_FSB_WR(2, nb_emask_fsb);
987 		}
988 
989 		ERR0_FSB_WR(3, err0_fsb);
990 		ERR1_FSB_WR(3, err1_fsb);
991 		ERR2_FSB_WR(3, err2_fsb);
992 		MCERR_FSB_WR(3, mcerr_fsb);
993 		if (nb5000_reset_emask_fsb) {
994 			EMASK_FSB_WR(3, nb5000_emask_fsb);
995 		} else {
996 			EMASK_FSB_WR(3, nb_emask_fsb);
997 		}
998 	}
999 }
1000 
1001 static void
1002 nb_fsb_fini() {
1003 	ERR0_FSB_WR(0, 0xffff);
1004 	ERR1_FSB_WR(0, 0xffff);
1005 	ERR2_FSB_WR(0, 0xffff);
1006 	MCERR_FSB_WR(0, 0xffff);
1007 	EMASK_FSB_WR(0, 0xffff);
1008 
1009 	ERR0_FSB_WR(0, nb_err0_fsb);
1010 	ERR1_FSB_WR(0, nb_err1_fsb);
1011 	ERR2_FSB_WR(0, nb_err2_fsb);
1012 	MCERR_FSB_WR(0, nb_mcerr_fsb);
1013 	EMASK_FSB_WR(0, nb_emask_fsb);
1014 
1015 	ERR0_FSB_WR(1, 0xffff);
1016 	ERR1_FSB_WR(1, 0xffff);
1017 	ERR2_FSB_WR(1, 0xffff);
1018 	MCERR_FSB_WR(1, 0xffff);
1019 	EMASK_FSB_WR(1, 0xffff);
1020 
1021 	ERR0_FSB_WR(1, nb_err0_fsb);
1022 	ERR1_FSB_WR(1, nb_err1_fsb);
1023 	ERR2_FSB_WR(1, nb_err2_fsb);
1024 	MCERR_FSB_WR(1, nb_mcerr_fsb);
1025 	EMASK_FSB_WR(1, nb_emask_fsb);
1026 
1027 	if (nb_chipset == INTEL_NB_7300) {
1028 		ERR0_FSB_WR(2, 0xffff);
1029 		ERR1_FSB_WR(2, 0xffff);
1030 		ERR2_FSB_WR(2, 0xffff);
1031 		MCERR_FSB_WR(2, 0xffff);
1032 		EMASK_FSB_WR(2, 0xffff);
1033 
1034 		ERR0_FSB_WR(2, nb_err0_fsb);
1035 		ERR1_FSB_WR(2, nb_err1_fsb);
1036 		ERR2_FSB_WR(2, nb_err2_fsb);
1037 		MCERR_FSB_WR(2, nb_mcerr_fsb);
1038 		EMASK_FSB_WR(2, nb_emask_fsb);
1039 
1040 		ERR0_FSB_WR(3, 0xffff);
1041 		ERR1_FSB_WR(3, 0xffff);
1042 		ERR2_FSB_WR(3, 0xffff);
1043 		MCERR_FSB_WR(3, 0xffff);
1044 		EMASK_FSB_WR(3, 0xffff);
1045 
1046 		ERR0_FSB_WR(3, nb_err0_fsb);
1047 		ERR1_FSB_WR(3, nb_err1_fsb);
1048 		ERR2_FSB_WR(3, nb_err2_fsb);
1049 		MCERR_FSB_WR(3, nb_mcerr_fsb);
1050 		EMASK_FSB_WR(3, nb_emask_fsb);
1051 	}
1052 }
1053 
1054 void
1055 nb_fsb_mask_mc(int fsb, uint16_t mc_mask_fsb)
1056 {
1057 	uint16_t emask_fsb;
1058 
1059 	emask_fsb = MCERR_FSB_RD(fsb);
1060 	if ((emask_fsb & mc_mask_fsb) != mc_mask_fsb) {
1061 		MCERR_FSB_WR(fsb, emask_fsb|mc_mask_fsb|EMASK_FBD_RES);
1062 		nb_mask_mc_set = 1;
1063 	}
1064 }
1065 
1066 static void
1067 nb_thr_init()
1068 {
1069 	uint16_t err0_thr;
1070 	uint16_t err1_thr;
1071 	uint16_t err2_thr;
1072 	uint16_t mcerr_thr;
1073 	uint16_t emask_thr;
1074 
1075 	if (nb_chipset == INTEL_NB_5400) {
1076 		err0_thr = ERR0_THR_RD(0);
1077 		err1_thr = ERR1_THR_RD(0);
1078 		err2_thr = ERR2_THR_RD(0);
1079 		mcerr_thr = MCERR_THR_RD(0);
1080 		emask_thr = EMASK_THR_RD(0);
1081 
1082 		ERR0_THR_WR(0xffff);
1083 		ERR1_THR_WR(0xffff);
1084 		ERR2_THR_WR(0xffff);
1085 		MCERR_THR_WR(0xffff);
1086 		EMASK_THR_WR(0xffff);
1087 
1088 		nb_err0_thr = err0_thr;
1089 		nb_err1_thr = err1_thr;
1090 		nb_err2_thr = err2_thr;
1091 		nb_mcerr_thr = mcerr_thr;
1092 		nb_emask_thr = emask_thr;
1093 
1094 		mcerr_thr &= ~nb_mask_bios_thr;
1095 		mcerr_thr |= nb_mask_bios_thr &
1096 		    (~err2_thr | ~err1_thr | ~err0_thr);
1097 		mcerr_thr |= nb_mask_poll_thr;
1098 		err0_thr |= nb_mask_poll_thr;
1099 		err1_thr |= nb_mask_poll_thr;
1100 		err2_thr |= nb_mask_poll_thr;
1101 
1102 		l_mcerr_thr = mcerr_thr;
1103 		ERR0_THR_WR(err0_thr);
1104 		ERR1_THR_WR(err1_thr);
1105 		ERR2_THR_WR(err2_thr);
1106 		MCERR_THR_WR(mcerr_thr);
1107 		EMASK_THR_WR(nb_emask_thr);
1108 	}
1109 }
1110 
1111 static void
1112 nb_thr_fini()
1113 {
1114 	if (nb_chipset == INTEL_NB_5400) {
1115 		ERR0_THR_WR(0xffff);
1116 		ERR1_THR_WR(0xffff);
1117 		ERR2_THR_WR(0xffff);
1118 		MCERR_THR_WR(0xffff);
1119 		EMASK_THR_WR(0xffff);
1120 
1121 		ERR0_THR_WR(nb_err0_thr);
1122 		ERR1_THR_WR(nb_err1_thr);
1123 		ERR2_THR_WR(nb_err2_thr);
1124 		MCERR_THR_WR(nb_mcerr_thr);
1125 		EMASK_THR_WR(nb_emask_thr);
1126 	}
1127 }
1128 
1129 void
1130 nb_thr_mask_mc(uint16_t mc_mask_thr)
1131 {
1132 	uint16_t emask_thr;
1133 
1134 	emask_thr = MCERR_THR_RD(0);
1135 	if ((emask_thr & mc_mask_thr) != mc_mask_thr) {
1136 		MCERR_THR_WR(emask_thr|mc_mask_thr);
1137 		nb_mask_mc_set = 1;
1138 	}
1139 }
1140 
1141 void
1142 nb_mask_mc_reset()
1143 {
1144 	MCERR_FBD_WR(l_mcerr_fbd);
1145 	MCERR_INT_WR(l_mcerr_int);
1146 	MCERR_FSB_WR(0, l_mcerr_fsb);
1147 	MCERR_FSB_WR(1, l_mcerr_fsb);
1148 	if (nb_chipset == INTEL_NB_7300) {
1149 		MCERR_FSB_WR(2, l_mcerr_fsb);
1150 		MCERR_FSB_WR(3, l_mcerr_fsb);
1151 	}
1152 	if (nb_chipset == INTEL_NB_5400) {
1153 		MCERR_THR_WR(l_mcerr_thr);
1154 	}
1155 }
1156 
1157 int
1158 nb_dev_init()
1159 {
1160 	find_dimm_label_t *label_function_p;
1161 
1162 	label_function_p = find_dimms_per_channel();
1163 	mutex_init(&nb_mutex, NULL, MUTEX_DRIVER, NULL);
1164 	nb_queue = errorq_create("nb_queue", nb_drain, NULL, NB_MAX_ERRORS,
1165 	    sizeof (nb_logout_t), 1, ERRORQ_VITAL);
1166 	if (nb_queue == NULL) {
1167 		mutex_destroy(&nb_mutex);
1168 		return (EAGAIN);
1169 	}
1170 	nb_int_init();
1171 	nb_thr_init();
1172 	dimm_init();
1173 	nb_dimms_init(label_function_p);
1174 	nb_mc_init();
1175 	nb_pex_init();
1176 	nb_fbd_init();
1177 	nb_fsb_init();
1178 	nb_scrubber_enable();
1179 	return (0);
1180 }
1181 
1182 int
1183 nb_init()
1184 {
1185 	/* get vendor and device */
1186 	nb_chipset = (*pci_getl_func)(0, 0, 0, PCI_CONF_VENID);
1187 	switch (nb_chipset) {
1188 	default:
1189 		if (nb_5000_memory_controller == 0)
1190 			return (ENOTSUP);
1191 		break;
1192 	case INTEL_NB_7300:
1193 	case INTEL_NB_5000P:
1194 	case INTEL_NB_5000X:
1195 		break;
1196 	case INTEL_NB_5000V:
1197 	case INTEL_NB_5000Z:
1198 		nb_number_memory_controllers = 1;
1199 		break;
1200 	case INTEL_NB_5400:
1201 	case INTEL_NB_5400A:
1202 	case INTEL_NB_5400B:
1203 		nb_chipset = INTEL_NB_5400;
1204 		break;
1205 	}
1206 	return (0);
1207 }
1208 
1209 void
1210 nb_dev_reinit()
1211 {
1212 	int i, j;
1213 	int nchannels = nb_number_memory_controllers * 2;
1214 	nb_dimm_t **dimmpp;
1215 	nb_dimm_t *dimmp;
1216 	nb_dimm_t **old_nb_dimms;
1217 	int old_nb_dimms_per_channel;
1218 	find_dimm_label_t *label_function_p;
1219 
1220 	old_nb_dimms = nb_dimms;
1221 	old_nb_dimms_per_channel = nb_dimms_per_channel;
1222 
1223 	dimm_fini();
1224 	label_function_p = find_dimms_per_channel();
1225 	dimm_init();
1226 	nb_dimms_init(label_function_p);
1227 	nb_mc_init();
1228 	nb_pex_init();
1229 	nb_int_init();
1230 	nb_thr_init();
1231 	nb_fbd_init();
1232 	nb_fsb_init();
1233 	nb_scrubber_enable();
1234 
1235 	dimmpp = old_nb_dimms;
1236 	for (i = 0; i < nchannels; i++) {
1237 		for (j = 0; j < old_nb_dimms_per_channel; j++) {
1238 			dimmp = *dimmpp;
1239 			if (dimmp) {
1240 				kmem_free(dimmp, sizeof (nb_dimm_t));
1241 				*dimmpp = NULL;
1242 			}
1243 			dimmp++;
1244 		}
1245 	}
1246 	kmem_free(old_nb_dimms, sizeof (nb_dimm_t *) *
1247 	    nb_number_memory_controllers * 2 * old_nb_dimms_per_channel);
1248 }
1249 
1250 void
1251 nb_dev_unload()
1252 {
1253 	errorq_destroy(nb_queue);
1254 	nb_queue = NULL;
1255 	mutex_destroy(&nb_mutex);
1256 	nb_int_fini();
1257 	nb_thr_fini();
1258 	nb_fbd_fini();
1259 	nb_fsb_fini();
1260 	nb_pex_fini();
1261 	nb_fini();
1262 }
1263 
1264 void
1265 nb_unload()
1266 {
1267 }
1268