xref: /illumos-gate/usr/src/uts/sun4u/opl/io/mc-opl.c (revision 25cf1a30)
1*25cf1a30Sjl /*
2*25cf1a30Sjl  * CDDL HEADER START
3*25cf1a30Sjl  *
4*25cf1a30Sjl  * The contents of this file are subject to the terms of the
5*25cf1a30Sjl  * Common Development and Distribution License (the "License").
6*25cf1a30Sjl  * You may not use this file except in compliance with the License.
7*25cf1a30Sjl  *
8*25cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*25cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
10*25cf1a30Sjl  * See the License for the specific language governing permissions
11*25cf1a30Sjl  * and limitations under the License.
12*25cf1a30Sjl  *
13*25cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
14*25cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*25cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
16*25cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
17*25cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18*25cf1a30Sjl  *
19*25cf1a30Sjl  * CDDL HEADER END
20*25cf1a30Sjl  */
21*25cf1a30Sjl /*
22*25cf1a30Sjl  * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006
23*25cf1a30Sjl  */
24*25cf1a30Sjl 
25*25cf1a30Sjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
26*25cf1a30Sjl 
27*25cf1a30Sjl #include <sys/types.h>
28*25cf1a30Sjl #include <sys/sysmacros.h>
29*25cf1a30Sjl #include <sys/conf.h>
30*25cf1a30Sjl #include <sys/modctl.h>
31*25cf1a30Sjl #include <sys/stat.h>
32*25cf1a30Sjl #include <sys/async.h>
33*25cf1a30Sjl #include <sys/machsystm.h>
34*25cf1a30Sjl #include <sys/ksynch.h>
35*25cf1a30Sjl #include <sys/ddi.h>
36*25cf1a30Sjl #include <sys/sunddi.h>
37*25cf1a30Sjl #include <sys/ddifm.h>
38*25cf1a30Sjl #include <sys/fm/protocol.h>
39*25cf1a30Sjl #include <sys/fm/util.h>
40*25cf1a30Sjl #include <sys/kmem.h>
41*25cf1a30Sjl #include <sys/fm/io/opl_mc_fm.h>
42*25cf1a30Sjl #include <sys/memlist.h>
43*25cf1a30Sjl #include <sys/param.h>
44*25cf1a30Sjl #include <sys/ontrap.h>
45*25cf1a30Sjl #include <vm/page.h>
46*25cf1a30Sjl #include <sys/mc-opl.h>
47*25cf1a30Sjl 
48*25cf1a30Sjl /*
49*25cf1a30Sjl  * Function prototypes
50*25cf1a30Sjl  */
51*25cf1a30Sjl static int mc_open(dev_t *, int, int, cred_t *);
52*25cf1a30Sjl static int mc_close(dev_t, int, int, cred_t *);
53*25cf1a30Sjl static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
54*25cf1a30Sjl static int mc_attach(dev_info_t *, ddi_attach_cmd_t);
55*25cf1a30Sjl static int mc_detach(dev_info_t *, ddi_detach_cmd_t);
56*25cf1a30Sjl 
57*25cf1a30Sjl static int mc_board_add(mc_opl_t *mcp);
58*25cf1a30Sjl static int mc_board_del(mc_opl_t *mcp);
59*25cf1a30Sjl static int mc_suspend(mc_opl_t *mcp, uint32_t flag);
60*25cf1a30Sjl static int mc_resume(mc_opl_t *mcp, uint32_t flag);
61*25cf1a30Sjl 
62*25cf1a30Sjl static void insert_mcp(mc_opl_t *mcp);
63*25cf1a30Sjl static void delete_mcp(mc_opl_t *mcp);
64*25cf1a30Sjl 
65*25cf1a30Sjl static int pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr);
66*25cf1a30Sjl 
67*25cf1a30Sjl static int mc_valid_pa(mc_opl_t *mcp, uint64_t pa);
68*25cf1a30Sjl 
69*25cf1a30Sjl int mc_get_mem_unum(int, uint64_t, char *, int, int *);
70*25cf1a30Sjl extern int plat_max_boards(void);
71*25cf1a30Sjl 
72*25cf1a30Sjl static void mc_get_mlist(mc_opl_t *);
73*25cf1a30Sjl 
74*25cf1a30Sjl #pragma weak opl_get_physical_board
75*25cf1a30Sjl extern int opl_get_physical_board(int);
76*25cf1a30Sjl static int mc_opl_get_physical_board(int);
77*25cf1a30Sjl 
78*25cf1a30Sjl /*
79*25cf1a30Sjl  * Configuration data structures
80*25cf1a30Sjl  */
81*25cf1a30Sjl static struct cb_ops mc_cb_ops = {
82*25cf1a30Sjl 	mc_open,			/* open */
83*25cf1a30Sjl 	mc_close,			/* close */
84*25cf1a30Sjl 	nulldev,			/* strategy */
85*25cf1a30Sjl 	nulldev,			/* print */
86*25cf1a30Sjl 	nodev,				/* dump */
87*25cf1a30Sjl 	nulldev,			/* read */
88*25cf1a30Sjl 	nulldev,			/* write */
89*25cf1a30Sjl 	mc_ioctl,			/* ioctl */
90*25cf1a30Sjl 	nodev,				/* devmap */
91*25cf1a30Sjl 	nodev,				/* mmap */
92*25cf1a30Sjl 	nodev,				/* segmap */
93*25cf1a30Sjl 	nochpoll,			/* poll */
94*25cf1a30Sjl 	ddi_prop_op,			/* cb_prop_op */
95*25cf1a30Sjl 	0,				/* streamtab */
96*25cf1a30Sjl 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
97*25cf1a30Sjl 	CB_REV,				/* rev */
98*25cf1a30Sjl 	nodev,				/* cb_aread */
99*25cf1a30Sjl 	nodev				/* cb_awrite */
100*25cf1a30Sjl };
101*25cf1a30Sjl 
102*25cf1a30Sjl static struct dev_ops mc_ops = {
103*25cf1a30Sjl 	DEVO_REV,			/* rev */
104*25cf1a30Sjl 	0,				/* refcnt  */
105*25cf1a30Sjl 	ddi_getinfo_1to1,		/* getinfo */
106*25cf1a30Sjl 	nulldev,			/* identify */
107*25cf1a30Sjl 	nulldev,			/* probe */
108*25cf1a30Sjl 	mc_attach,			/* attach */
109*25cf1a30Sjl 	mc_detach,			/* detach */
110*25cf1a30Sjl 	nulldev,			/* reset */
111*25cf1a30Sjl 	&mc_cb_ops,			/* cb_ops */
112*25cf1a30Sjl 	(struct bus_ops *)0,		/* bus_ops */
113*25cf1a30Sjl 	nulldev				/* power */
114*25cf1a30Sjl };
115*25cf1a30Sjl 
116*25cf1a30Sjl /*
117*25cf1a30Sjl  * Driver globals
118*25cf1a30Sjl  */
119*25cf1a30Sjl int mc_patrol_interval_sec = 10;
120*25cf1a30Sjl 
121*25cf1a30Sjl int inject_op_delay = 5;
122*25cf1a30Sjl 
123*25cf1a30Sjl mc_inst_list_t *mc_instances;
124*25cf1a30Sjl static kmutex_t mcmutex;
125*25cf1a30Sjl 
126*25cf1a30Sjl void *mc_statep;
127*25cf1a30Sjl 
128*25cf1a30Sjl #ifdef	DEBUG
129*25cf1a30Sjl int oplmc_debug = 1;
130*25cf1a30Sjl #endif
131*25cf1a30Sjl 
132*25cf1a30Sjl static int mc_debug_show_all;
133*25cf1a30Sjl 
134*25cf1a30Sjl extern struct mod_ops mod_driverops;
135*25cf1a30Sjl 
136*25cf1a30Sjl static struct modldrv modldrv = {
137*25cf1a30Sjl 	&mod_driverops,			/* module type, this one is a driver */
138*25cf1a30Sjl 	"OPL Memory-controller 1.1",	/* module name */
139*25cf1a30Sjl 	&mc_ops,			/* driver ops */
140*25cf1a30Sjl };
141*25cf1a30Sjl 
142*25cf1a30Sjl static struct modlinkage modlinkage = {
143*25cf1a30Sjl 	MODREV_1,		/* rev */
144*25cf1a30Sjl 	(void *)&modldrv,
145*25cf1a30Sjl 	NULL
146*25cf1a30Sjl };
147*25cf1a30Sjl 
148*25cf1a30Sjl #pragma weak opl_get_mem_unum
149*25cf1a30Sjl extern int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *);
150*25cf1a30Sjl 
151*25cf1a30Sjl /*
152*25cf1a30Sjl  * pseudo-mc node portid format
153*25cf1a30Sjl  *
154*25cf1a30Sjl  *		[10]   = 0
155*25cf1a30Sjl  *		[9]    = 1
156*25cf1a30Sjl  *		[8]    = LSB_ID[4] = 0
157*25cf1a30Sjl  *		[7:4]  = LSB_ID[3:0]
158*25cf1a30Sjl  *		[3:0]  = 0
159*25cf1a30Sjl  *
160*25cf1a30Sjl  */
161*25cf1a30Sjl 
162*25cf1a30Sjl /*
163*25cf1a30Sjl  * These are the module initialization routines.
164*25cf1a30Sjl  */
165*25cf1a30Sjl int
166*25cf1a30Sjl _init(void)
167*25cf1a30Sjl {
168*25cf1a30Sjl 	int error;
169*25cf1a30Sjl 
170*25cf1a30Sjl 
171*25cf1a30Sjl 	if ((error = ddi_soft_state_init(&mc_statep,
172*25cf1a30Sjl 	    sizeof (mc_opl_t), 1)) != 0)
173*25cf1a30Sjl 		return (error);
174*25cf1a30Sjl 
175*25cf1a30Sjl 	mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL);
176*25cf1a30Sjl 	if (&opl_get_mem_unum)
177*25cf1a30Sjl 		opl_get_mem_unum = mc_get_mem_unum;
178*25cf1a30Sjl 
179*25cf1a30Sjl 	error =  mod_install(&modlinkage);
180*25cf1a30Sjl 	if (error != 0) {
181*25cf1a30Sjl 		if (&opl_get_mem_unum)
182*25cf1a30Sjl 			opl_get_mem_unum = NULL;
183*25cf1a30Sjl 		mutex_destroy(&mcmutex);
184*25cf1a30Sjl 		ddi_soft_state_fini(&mc_statep);
185*25cf1a30Sjl 	}
186*25cf1a30Sjl 
187*25cf1a30Sjl 	return (error);
188*25cf1a30Sjl }
189*25cf1a30Sjl 
190*25cf1a30Sjl int
191*25cf1a30Sjl _fini(void)
192*25cf1a30Sjl {
193*25cf1a30Sjl 	int error;
194*25cf1a30Sjl 
195*25cf1a30Sjl 	if ((error = mod_remove(&modlinkage)) != 0)
196*25cf1a30Sjl 		return (error);
197*25cf1a30Sjl 
198*25cf1a30Sjl 	mutex_destroy(&mcmutex);
199*25cf1a30Sjl 
200*25cf1a30Sjl 	if (&opl_get_mem_unum)
201*25cf1a30Sjl 		opl_get_mem_unum = NULL;
202*25cf1a30Sjl 
203*25cf1a30Sjl 	ddi_soft_state_fini(&mc_statep);
204*25cf1a30Sjl 
205*25cf1a30Sjl 	return (0);
206*25cf1a30Sjl }
207*25cf1a30Sjl 
208*25cf1a30Sjl int
209*25cf1a30Sjl _info(struct modinfo *modinfop)
210*25cf1a30Sjl {
211*25cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
212*25cf1a30Sjl }
213*25cf1a30Sjl 
214*25cf1a30Sjl static int
215*25cf1a30Sjl mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
216*25cf1a30Sjl {
217*25cf1a30Sjl 	mc_opl_t *mcp;
218*25cf1a30Sjl 	int instance;
219*25cf1a30Sjl 
220*25cf1a30Sjl 	/* get the instance of this devi */
221*25cf1a30Sjl 	instance = ddi_get_instance(devi);
222*25cf1a30Sjl 
223*25cf1a30Sjl 	switch (cmd) {
224*25cf1a30Sjl 	case DDI_ATTACH:
225*25cf1a30Sjl 		break;
226*25cf1a30Sjl 	case DDI_RESUME:
227*25cf1a30Sjl 		mcp = ddi_get_soft_state(mc_statep, instance);
228*25cf1a30Sjl 		return (mc_resume(mcp, MC_DRIVER_SUSPENDED));
229*25cf1a30Sjl 	default:
230*25cf1a30Sjl 		return (DDI_FAILURE);
231*25cf1a30Sjl 	}
232*25cf1a30Sjl 
233*25cf1a30Sjl 
234*25cf1a30Sjl 	if (ddi_soft_state_zalloc(mc_statep, instance) != DDI_SUCCESS)
235*25cf1a30Sjl 		return (DDI_FAILURE);
236*25cf1a30Sjl 
237*25cf1a30Sjl 	if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) {
238*25cf1a30Sjl 		goto bad;
239*25cf1a30Sjl 	}
240*25cf1a30Sjl 
241*25cf1a30Sjl 	/* set informations in mc state */
242*25cf1a30Sjl 	mcp->mc_dip = devi;
243*25cf1a30Sjl 
244*25cf1a30Sjl 	if (mc_board_add(mcp))
245*25cf1a30Sjl 		goto bad;
246*25cf1a30Sjl 
247*25cf1a30Sjl 	insert_mcp(mcp);
248*25cf1a30Sjl 	ddi_report_dev(devi);
249*25cf1a30Sjl 
250*25cf1a30Sjl 	return (DDI_SUCCESS);
251*25cf1a30Sjl 
252*25cf1a30Sjl bad:
253*25cf1a30Sjl 	ddi_soft_state_free(mc_statep, instance);
254*25cf1a30Sjl 	return (DDI_FAILURE);
255*25cf1a30Sjl }
256*25cf1a30Sjl 
257*25cf1a30Sjl /* ARGSUSED */
258*25cf1a30Sjl static int
259*25cf1a30Sjl mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
260*25cf1a30Sjl {
261*25cf1a30Sjl 	int instance;
262*25cf1a30Sjl 	mc_opl_t *mcp;
263*25cf1a30Sjl 
264*25cf1a30Sjl 	/* get the instance of this devi */
265*25cf1a30Sjl 	instance = ddi_get_instance(devi);
266*25cf1a30Sjl 	if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) {
267*25cf1a30Sjl 		return (DDI_FAILURE);
268*25cf1a30Sjl 	}
269*25cf1a30Sjl 
270*25cf1a30Sjl 	switch (cmd) {
271*25cf1a30Sjl 	case DDI_SUSPEND:
272*25cf1a30Sjl 		return (mc_suspend(mcp, MC_DRIVER_SUSPENDED));
273*25cf1a30Sjl 	case DDI_DETACH:
274*25cf1a30Sjl 		break;
275*25cf1a30Sjl 	default:
276*25cf1a30Sjl 		return (DDI_FAILURE);
277*25cf1a30Sjl 	}
278*25cf1a30Sjl 
279*25cf1a30Sjl 	mutex_enter(&mcmutex);
280*25cf1a30Sjl 	if (mc_board_del(mcp) != DDI_SUCCESS) {
281*25cf1a30Sjl 		mutex_exit(&mcmutex);
282*25cf1a30Sjl 		return (DDI_FAILURE);
283*25cf1a30Sjl 	}
284*25cf1a30Sjl 
285*25cf1a30Sjl 	delete_mcp(mcp);
286*25cf1a30Sjl 	mutex_exit(&mcmutex);
287*25cf1a30Sjl 
288*25cf1a30Sjl 	/* free up the soft state */
289*25cf1a30Sjl 	ddi_soft_state_free(mc_statep, instance);
290*25cf1a30Sjl 
291*25cf1a30Sjl 	return (DDI_SUCCESS);
292*25cf1a30Sjl }
293*25cf1a30Sjl 
294*25cf1a30Sjl /* ARGSUSED */
295*25cf1a30Sjl static int
296*25cf1a30Sjl mc_open(dev_t *devp, int flag, int otyp, cred_t *credp)
297*25cf1a30Sjl {
298*25cf1a30Sjl 	return (0);
299*25cf1a30Sjl }
300*25cf1a30Sjl 
301*25cf1a30Sjl /* ARGSUSED */
302*25cf1a30Sjl static int
303*25cf1a30Sjl mc_close(dev_t devp, int flag, int otyp, cred_t *credp)
304*25cf1a30Sjl {
305*25cf1a30Sjl 	return (0);
306*25cf1a30Sjl }
307*25cf1a30Sjl 
308*25cf1a30Sjl /* ARGSUSED */
309*25cf1a30Sjl static int
310*25cf1a30Sjl mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
311*25cf1a30Sjl 	int *rvalp)
312*25cf1a30Sjl {
313*25cf1a30Sjl 	return (ENXIO);
314*25cf1a30Sjl }
315*25cf1a30Sjl 
316*25cf1a30Sjl /*
317*25cf1a30Sjl  * PA validity check:
318*25cf1a30Sjl  * This function return 1 if the PA is valid, otherwise
319*25cf1a30Sjl  * return 0.
320*25cf1a30Sjl  */
321*25cf1a30Sjl 
322*25cf1a30Sjl /* ARGSUSED */
323*25cf1a30Sjl static int
324*25cf1a30Sjl pa_is_valid(mc_opl_t *mcp, uint64_t addr)
325*25cf1a30Sjl {
326*25cf1a30Sjl 	/*
327*25cf1a30Sjl 	 * Check if the addr is on the board.
328*25cf1a30Sjl 	 */
329*25cf1a30Sjl 	if ((addr < mcp->mc_start_address) ||
330*25cf1a30Sjl 	    (mcp->mc_start_address + mcp->mc_size <= addr))
331*25cf1a30Sjl 		return (0);
332*25cf1a30Sjl 
333*25cf1a30Sjl 	if (mcp->mlist == NULL)
334*25cf1a30Sjl 		mc_get_mlist(mcp);
335*25cf1a30Sjl 
336*25cf1a30Sjl 	if (mcp->mlist && address_in_memlist(mcp->mlist, addr, 0)) {
337*25cf1a30Sjl 		return (1);
338*25cf1a30Sjl 	}
339*25cf1a30Sjl 	return (0);
340*25cf1a30Sjl }
341*25cf1a30Sjl 
342*25cf1a30Sjl /*
343*25cf1a30Sjl  * mac-pa translation routines.
344*25cf1a30Sjl  *
345*25cf1a30Sjl  *    Input: mc driver state, (LSB#, Bank#, DIMM address)
346*25cf1a30Sjl  *    Output: physical address
347*25cf1a30Sjl  *
348*25cf1a30Sjl  *    Valid   - return value:  0
349*25cf1a30Sjl  *    Invalid - return value: -1
350*25cf1a30Sjl  */
351*25cf1a30Sjl static int
352*25cf1a30Sjl mcaddr_to_pa(mc_opl_t *mcp, mc_addr_t *maddr, uint64_t *pa)
353*25cf1a30Sjl {
354*25cf1a30Sjl 	int i;
355*25cf1a30Sjl 	uint64_t pa_offset = 0;
356*25cf1a30Sjl 	int cs = (maddr->ma_dimm_addr >> CS_SHIFT) & 1;
357*25cf1a30Sjl 	int bank = maddr->ma_bank;
358*25cf1a30Sjl 	mc_addr_t maddr1;
359*25cf1a30Sjl 	int bank0, bank1;
360*25cf1a30Sjl 
361*25cf1a30Sjl 	MC_LOG("mcaddr /LSB%d/B%d/%x\n", maddr->ma_bd, bank,
362*25cf1a30Sjl 		maddr->ma_dimm_addr);
363*25cf1a30Sjl 
364*25cf1a30Sjl 	/* loc validity check */
365*25cf1a30Sjl 	ASSERT(maddr->ma_bd >= 0 && OPL_BOARD_MAX > maddr->ma_bd);
366*25cf1a30Sjl 	ASSERT(bank >= 0 && OPL_BANK_MAX > bank);
367*25cf1a30Sjl 
368*25cf1a30Sjl 	/* Do translation */
369*25cf1a30Sjl 	for (i = 0; i < PA_BITS_FOR_MAC; i++) {
370*25cf1a30Sjl 		int pa_bit = 0;
371*25cf1a30Sjl 		int mc_bit = mcp->mc_trans_table[cs][i];
372*25cf1a30Sjl 		if (mc_bit < MC_ADDRESS_BITS) {
373*25cf1a30Sjl 			pa_bit = (maddr->ma_dimm_addr >> mc_bit) & 1;
374*25cf1a30Sjl 		} else if (mc_bit == MP_NONE) {
375*25cf1a30Sjl 			pa_bit = 0;
376*25cf1a30Sjl 		} else if (mc_bit == MP_BANK_0) {
377*25cf1a30Sjl 			pa_bit = bank & 1;
378*25cf1a30Sjl 		} else if (mc_bit == MP_BANK_1) {
379*25cf1a30Sjl 			pa_bit = (bank >> 1) & 1;
380*25cf1a30Sjl 		} else if (mc_bit == MP_BANK_2) {
381*25cf1a30Sjl 			pa_bit = (bank >> 2) & 1;
382*25cf1a30Sjl 		}
383*25cf1a30Sjl 		pa_offset |= ((uint64_t)pa_bit) << i;
384*25cf1a30Sjl 	}
385*25cf1a30Sjl 	*pa = mcp->mc_start_address + pa_offset;
386*25cf1a30Sjl 	MC_LOG("pa = %lx\n", *pa);
387*25cf1a30Sjl 
388*25cf1a30Sjl 	if (pa_to_maddr(mcp, *pa, &maddr1) == -1) {
389*25cf1a30Sjl 		return (-1);
390*25cf1a30Sjl 	}
391*25cf1a30Sjl 
392*25cf1a30Sjl 
393*25cf1a30Sjl 	if (IS_MIRROR(mcp, maddr->ma_bank)) {
394*25cf1a30Sjl 		bank0 = maddr->ma_bank & ~(1);
395*25cf1a30Sjl 		bank1 = maddr1.ma_bank & ~(1);
396*25cf1a30Sjl 	} else {
397*25cf1a30Sjl 		bank0 = maddr->ma_bank;
398*25cf1a30Sjl 		bank1 = maddr1.ma_bank;
399*25cf1a30Sjl 	}
400*25cf1a30Sjl 	/*
401*25cf1a30Sjl 	 * there is no need to check ma_bd because it is generated from
402*25cf1a30Sjl 	 * mcp.  They are the same.
403*25cf1a30Sjl 	 */
404*25cf1a30Sjl 	if ((bank0 == bank1) &&
405*25cf1a30Sjl 		(maddr->ma_dimm_addr == maddr1.ma_dimm_addr)) {
406*25cf1a30Sjl 		return (0);
407*25cf1a30Sjl 	} else {
408*25cf1a30Sjl 		cmn_err(CE_WARN, "Translation error source /LSB%d/B%d/%x, "
409*25cf1a30Sjl 			"PA %lx, target /LSB%d/B%d/%x\n",
410*25cf1a30Sjl 			maddr->ma_bd, bank, maddr->ma_dimm_addr,
411*25cf1a30Sjl 			*pa, maddr1.ma_bd, maddr1.ma_bank,
412*25cf1a30Sjl 			maddr1.ma_dimm_addr);
413*25cf1a30Sjl 		return (-1);
414*25cf1a30Sjl 	}
415*25cf1a30Sjl }
416*25cf1a30Sjl 
417*25cf1a30Sjl /*
418*25cf1a30Sjl  * PA to CS (used by pa_to_maddr).
419*25cf1a30Sjl  */
420*25cf1a30Sjl static int
421*25cf1a30Sjl pa_to_cs(mc_opl_t *mcp, uint64_t pa_offset)
422*25cf1a30Sjl {
423*25cf1a30Sjl 	int i;
424*25cf1a30Sjl 	int cs = 0;
425*25cf1a30Sjl 
426*25cf1a30Sjl 	for (i = 0; i < PA_BITS_FOR_MAC; i++) {
427*25cf1a30Sjl 		/* MAC address bit<29> is arranged on the same PA bit */
428*25cf1a30Sjl 		/* on both table. So we may use any table. */
429*25cf1a30Sjl 		if (mcp->mc_trans_table[0][i] == CS_SHIFT) {
430*25cf1a30Sjl 			cs = (pa_offset >> i) & 1;
431*25cf1a30Sjl 			break;
432*25cf1a30Sjl 		}
433*25cf1a30Sjl 	}
434*25cf1a30Sjl 	return (cs);
435*25cf1a30Sjl }
436*25cf1a30Sjl 
437*25cf1a30Sjl /*
438*25cf1a30Sjl  * PA to DIMM (used by pa_to_maddr).
439*25cf1a30Sjl  */
440*25cf1a30Sjl /* ARGSUSED */
441*25cf1a30Sjl static uint32_t
442*25cf1a30Sjl pa_to_dimm(mc_opl_t *mcp, uint64_t pa_offset)
443*25cf1a30Sjl {
444*25cf1a30Sjl 	int i;
445*25cf1a30Sjl 	int cs = pa_to_cs(mcp, pa_offset);
446*25cf1a30Sjl 	uint32_t dimm_addr = 0;
447*25cf1a30Sjl 
448*25cf1a30Sjl 	for (i = 0; i < PA_BITS_FOR_MAC; i++) {
449*25cf1a30Sjl 		int pa_bit_value = (pa_offset >> i) & 1;
450*25cf1a30Sjl 		int mc_bit = mcp->mc_trans_table[cs][i];
451*25cf1a30Sjl 		if (mc_bit < MC_ADDRESS_BITS) {
452*25cf1a30Sjl 			dimm_addr |= pa_bit_value << mc_bit;
453*25cf1a30Sjl 		}
454*25cf1a30Sjl 	}
455*25cf1a30Sjl 	return (dimm_addr);
456*25cf1a30Sjl }
457*25cf1a30Sjl 
458*25cf1a30Sjl /*
459*25cf1a30Sjl  * PA to Bank (used by pa_to_maddr).
460*25cf1a30Sjl  */
461*25cf1a30Sjl static int
462*25cf1a30Sjl pa_to_bank(mc_opl_t *mcp, uint64_t pa_offset)
463*25cf1a30Sjl {
464*25cf1a30Sjl 	int i;
465*25cf1a30Sjl 	int cs = pa_to_cs(mcp, pa_offset);
466*25cf1a30Sjl 	int bankno = mcp->mc_trans_table[cs][INDEX_OF_BANK_SUPPLEMENT_BIT];
467*25cf1a30Sjl 
468*25cf1a30Sjl 
469*25cf1a30Sjl 	for (i = 0; i < PA_BITS_FOR_MAC; i++) {
470*25cf1a30Sjl 		int pa_bit_value = (pa_offset >> i) & 1;
471*25cf1a30Sjl 		int mc_bit = mcp->mc_trans_table[cs][i];
472*25cf1a30Sjl 		switch (mc_bit) {
473*25cf1a30Sjl 		case MP_BANK_0:
474*25cf1a30Sjl 			bankno |= pa_bit_value;
475*25cf1a30Sjl 			break;
476*25cf1a30Sjl 		case MP_BANK_1:
477*25cf1a30Sjl 			bankno |= pa_bit_value << 1;
478*25cf1a30Sjl 			break;
479*25cf1a30Sjl 		case MP_BANK_2:
480*25cf1a30Sjl 			bankno |= pa_bit_value << 2;
481*25cf1a30Sjl 			break;
482*25cf1a30Sjl 		}
483*25cf1a30Sjl 	}
484*25cf1a30Sjl 
485*25cf1a30Sjl 	return (bankno);
486*25cf1a30Sjl }
487*25cf1a30Sjl 
488*25cf1a30Sjl /*
489*25cf1a30Sjl  * PA to MAC address translation
490*25cf1a30Sjl  *
491*25cf1a30Sjl  *   Input: MAC driver state, physicall adress
492*25cf1a30Sjl  *   Output: LSB#, Bank id, mac address
493*25cf1a30Sjl  *
494*25cf1a30Sjl  *    Valid   - return value:  0
495*25cf1a30Sjl  *    Invalid - return value: -1
496*25cf1a30Sjl  */
497*25cf1a30Sjl 
498*25cf1a30Sjl int
499*25cf1a30Sjl pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr)
500*25cf1a30Sjl {
501*25cf1a30Sjl 	uint64_t pa_offset;
502*25cf1a30Sjl 
503*25cf1a30Sjl 	/* PA validity check */
504*25cf1a30Sjl 	if (!pa_is_valid(mcp, pa))
505*25cf1a30Sjl 		return (-1);
506*25cf1a30Sjl 
507*25cf1a30Sjl 
508*25cf1a30Sjl 	/* Do translation */
509*25cf1a30Sjl 	pa_offset = pa - mcp->mc_start_address;
510*25cf1a30Sjl 
511*25cf1a30Sjl 	maddr->ma_bd = mcp->mc_board_num;
512*25cf1a30Sjl 	maddr->ma_bank = pa_to_bank(mcp, pa_offset);
513*25cf1a30Sjl 	maddr->ma_dimm_addr = pa_to_dimm(mcp, pa_offset);
514*25cf1a30Sjl 	MC_LOG("pa %lx -> mcaddr /LSB%d/B%d/%x\n",
515*25cf1a30Sjl 		pa_offset, maddr->ma_bd, maddr->ma_bank, maddr->ma_dimm_addr);
516*25cf1a30Sjl 	return (0);
517*25cf1a30Sjl }
518*25cf1a30Sjl 
519*25cf1a30Sjl static void
520*25cf1a30Sjl mc_ereport_post(mc_aflt_t *mc_aflt)
521*25cf1a30Sjl {
522*25cf1a30Sjl 	char buf[FM_MAX_CLASS];
523*25cf1a30Sjl 	char device_path[MAXPATHLEN];
524*25cf1a30Sjl 	nv_alloc_t *nva = NULL;
525*25cf1a30Sjl 	nvlist_t *ereport, *detector, *resource;
526*25cf1a30Sjl 	errorq_elem_t *eqep;
527*25cf1a30Sjl 	int nflts;
528*25cf1a30Sjl 	mc_flt_stat_t *flt_stat;
529*25cf1a30Sjl 	int i, n, blen;
530*25cf1a30Sjl 	char *p;
531*25cf1a30Sjl 	uint32_t values[2], synd[2], dslot[2];
532*25cf1a30Sjl 
533*25cf1a30Sjl 	if (panicstr) {
534*25cf1a30Sjl 		eqep = errorq_reserve(ereport_errorq);
535*25cf1a30Sjl 		if (eqep == NULL)
536*25cf1a30Sjl 			return;
537*25cf1a30Sjl 		ereport = errorq_elem_nvl(ereport_errorq, eqep);
538*25cf1a30Sjl 		nva = errorq_elem_nva(ereport_errorq, eqep);
539*25cf1a30Sjl 	} else {
540*25cf1a30Sjl 		ereport = fm_nvlist_create(nva);
541*25cf1a30Sjl 	}
542*25cf1a30Sjl 
543*25cf1a30Sjl 	/*
544*25cf1a30Sjl 	 * Create the scheme "dev" FMRI.
545*25cf1a30Sjl 	 */
546*25cf1a30Sjl 	detector = fm_nvlist_create(nva);
547*25cf1a30Sjl 	resource = fm_nvlist_create(nva);
548*25cf1a30Sjl 
549*25cf1a30Sjl 	nflts = mc_aflt->mflt_nflts;
550*25cf1a30Sjl 
551*25cf1a30Sjl 	ASSERT(nflts >= 1 && nflts <= 2);
552*25cf1a30Sjl 
553*25cf1a30Sjl 	flt_stat = mc_aflt->mflt_stat[0];
554*25cf1a30Sjl 	(void) ddi_pathname(mc_aflt->mflt_mcp->mc_dip, device_path);
555*25cf1a30Sjl 	(void) fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
556*25cf1a30Sjl 	    device_path, NULL);
557*25cf1a30Sjl 
558*25cf1a30Sjl 	/*
559*25cf1a30Sjl 	 * Encode all the common data into the ereport.
560*25cf1a30Sjl 	 */
561*25cf1a30Sjl 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s",
562*25cf1a30Sjl 		MC_OPL_ERROR_CLASS,
563*25cf1a30Sjl 		mc_aflt->mflt_is_ptrl ? MC_OPL_PTRL_SUBCLASS :
564*25cf1a30Sjl 		MC_OPL_MI_SUBCLASS,
565*25cf1a30Sjl 		mc_aflt->mflt_erpt_class);
566*25cf1a30Sjl 
567*25cf1a30Sjl 	MC_LOG("mc_ereport_post: ereport %s\n", buf);
568*25cf1a30Sjl 
569*25cf1a30Sjl 
570*25cf1a30Sjl 	fm_ereport_set(ereport, FM_EREPORT_VERSION, buf,
571*25cf1a30Sjl 		fm_ena_generate(mc_aflt->mflt_id, FM_ENA_FMT1),
572*25cf1a30Sjl 		detector, NULL);
573*25cf1a30Sjl 
574*25cf1a30Sjl 	/*
575*25cf1a30Sjl 	 * Set payload.
576*25cf1a30Sjl 	 */
577*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_BOARD, DATA_TYPE_UINT32,
578*25cf1a30Sjl 		flt_stat->mf_flt_maddr.ma_bd, NULL);
579*25cf1a30Sjl 
580*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_PA, DATA_TYPE_UINT64,
581*25cf1a30Sjl 		flt_stat->mf_flt_paddr, NULL);
582*25cf1a30Sjl 
583*25cf1a30Sjl 	if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
584*25cf1a30Sjl 		fm_payload_set(ereport, MC_OPL_FLT_TYPE,
585*25cf1a30Sjl 			DATA_TYPE_UINT8, ECC_STICKY, NULL);
586*25cf1a30Sjl 	}
587*25cf1a30Sjl 
588*25cf1a30Sjl 	for (i = 0; i < nflts; i++)
589*25cf1a30Sjl 		values[i] = mc_aflt->mflt_stat[i]->mf_flt_maddr.ma_bank;
590*25cf1a30Sjl 
591*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_BANK, DATA_TYPE_UINT32_ARRAY,
592*25cf1a30Sjl 		nflts, values, NULL);
593*25cf1a30Sjl 
594*25cf1a30Sjl 	for (i = 0; i < nflts; i++)
595*25cf1a30Sjl 		values[i] = mc_aflt->mflt_stat[i]->mf_cntl;
596*25cf1a30Sjl 
597*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_STATUS, DATA_TYPE_UINT32_ARRAY,
598*25cf1a30Sjl 		nflts, values, NULL);
599*25cf1a30Sjl 
600*25cf1a30Sjl 	for (i = 0; i < nflts; i++)
601*25cf1a30Sjl 		values[i] = mc_aflt->mflt_stat[i]->mf_err_add;
602*25cf1a30Sjl 
603*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_ERR_ADD, DATA_TYPE_UINT32_ARRAY,
604*25cf1a30Sjl 		nflts, values, NULL);
605*25cf1a30Sjl 
606*25cf1a30Sjl 	for (i = 0; i < nflts; i++)
607*25cf1a30Sjl 		values[i] = mc_aflt->mflt_stat[i]->mf_err_log;
608*25cf1a30Sjl 
609*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_ERR_LOG, DATA_TYPE_UINT32_ARRAY,
610*25cf1a30Sjl 		nflts, values, NULL);
611*25cf1a30Sjl 
612*25cf1a30Sjl 	for (i = 0; i < nflts; i++) {
613*25cf1a30Sjl 		flt_stat = mc_aflt->mflt_stat[i];
614*25cf1a30Sjl 		if (flt_stat->mf_errlog_valid) {
615*25cf1a30Sjl 			synd[i] = flt_stat->mf_synd;
616*25cf1a30Sjl 			dslot[i] = flt_stat->mf_dimm_slot;
617*25cf1a30Sjl 			values[i] = flt_stat->mf_dram_place;
618*25cf1a30Sjl 		} else {
619*25cf1a30Sjl 			synd[i] = 0;
620*25cf1a30Sjl 			dslot[i] = 0;
621*25cf1a30Sjl 			values[i] = 0;
622*25cf1a30Sjl 		}
623*25cf1a30Sjl 	}
624*25cf1a30Sjl 
625*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_ERR_SYND,
626*25cf1a30Sjl 		DATA_TYPE_UINT32_ARRAY, nflts, synd, NULL);
627*25cf1a30Sjl 
628*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_ERR_DIMMSLOT,
629*25cf1a30Sjl 		DATA_TYPE_UINT32_ARRAY, nflts, dslot, NULL);
630*25cf1a30Sjl 
631*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_ERR_DRAM,
632*25cf1a30Sjl 		DATA_TYPE_UINT32_ARRAY, nflts, values, NULL);
633*25cf1a30Sjl 
634*25cf1a30Sjl 	blen = MAXPATHLEN;
635*25cf1a30Sjl 	device_path[0] = 0;
636*25cf1a30Sjl 	p = &device_path[0];
637*25cf1a30Sjl 
638*25cf1a30Sjl 	for (i = 0; i < nflts; i++) {
639*25cf1a30Sjl 		int bank = flt_stat->mf_flt_maddr.ma_bank;
640*25cf1a30Sjl 		int psb = -1;
641*25cf1a30Sjl 
642*25cf1a30Sjl 		flt_stat = mc_aflt->mflt_stat[i];
643*25cf1a30Sjl 		psb = mc_opl_get_physical_board(
644*25cf1a30Sjl 		    flt_stat->mf_flt_maddr.ma_bd);
645*25cf1a30Sjl 
646*25cf1a30Sjl 		if (psb != -1) {
647*25cf1a30Sjl 			snprintf(p, blen, "/CMU%d/B%d", psb, bank);
648*25cf1a30Sjl 		} else {
649*25cf1a30Sjl 			snprintf(p, blen, "/CMU/B%d", bank);
650*25cf1a30Sjl 		}
651*25cf1a30Sjl 
652*25cf1a30Sjl 		if (flt_stat->mf_errlog_valid) {
653*25cf1a30Sjl 			snprintf(p + strlen(p), blen, "/MEM%d%d%c",
654*25cf1a30Sjl 			    bank/2, (bank & 0x1) * 2 + dslot[i] & 1,
655*25cf1a30Sjl 			    (dslot[i] & 0x2) ? 'B' : 'A');
656*25cf1a30Sjl 		}
657*25cf1a30Sjl 
658*25cf1a30Sjl 		n = strlen(&device_path[0]);
659*25cf1a30Sjl 		blen = MAXPATHLEN - n;
660*25cf1a30Sjl 		p = &device_path[n];
661*25cf1a30Sjl 		if (i < (nflts - 1)) {
662*25cf1a30Sjl 			snprintf(p, blen, " ");
663*25cf1a30Sjl 			n += 1; blen -= 1; p += 1;
664*25cf1a30Sjl 		}
665*25cf1a30Sjl 	}
666*25cf1a30Sjl 
667*25cf1a30Sjl 	/*
668*25cf1a30Sjl 	 * UNUM format /LSB#/B#/MEMxyZ
669*25cf1a30Sjl 	 * where x is the MAC# = Bank#/2
670*25cf1a30Sjl 	 * y is slot info = (Bank# & 0x1)*2 + {0, 1} 0 for DIMM-L, 1 for DIMM-H
671*25cf1a30Sjl 	 * DIMM-L is 0 in bit 13, DIMM-H is 1 in bit 13.
672*25cf1a30Sjl 	 * Z is A(CS0) or B(CS1) given by bit 14
673*25cf1a30Sjl 	 */
674*25cf1a30Sjl 	(void) fm_fmri_mem_set(resource, FM_MEM_SCHEME_VERSION,
675*25cf1a30Sjl 		NULL, device_path, NULL, 0);
676*25cf1a30Sjl 
677*25cf1a30Sjl 	fm_payload_set(ereport, MC_OPL_RESOURCE, DATA_TYPE_NVLIST,
678*25cf1a30Sjl 		resource, NULL);
679*25cf1a30Sjl 
680*25cf1a30Sjl 	if (panicstr) {
681*25cf1a30Sjl 		errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
682*25cf1a30Sjl 	} else {
683*25cf1a30Sjl 		(void) fm_ereport_post(ereport, EVCH_TRYHARD);
684*25cf1a30Sjl 		fm_nvlist_destroy(ereport, FM_NVA_FREE);
685*25cf1a30Sjl 		fm_nvlist_destroy(detector, FM_NVA_FREE);
686*25cf1a30Sjl 		fm_nvlist_destroy(resource, FM_NVA_FREE);
687*25cf1a30Sjl 	}
688*25cf1a30Sjl }
689*25cf1a30Sjl 
690*25cf1a30Sjl static void
691*25cf1a30Sjl mc_err_drain(mc_aflt_t *mc_aflt)
692*25cf1a30Sjl {
693*25cf1a30Sjl 	int rv;
694*25cf1a30Sjl 	page_t *pp;
695*25cf1a30Sjl 	uint64_t errors;
696*25cf1a30Sjl 	uint64_t pa = (uint64_t)(-1);
697*25cf1a30Sjl 
698*25cf1a30Sjl 	MC_LOG("mc_err_drain: %s\n",
699*25cf1a30Sjl 		mc_aflt->mflt_erpt_class);
700*25cf1a30Sjl 	/*
701*25cf1a30Sjl 	 * we come here only when we have:
702*25cf1a30Sjl 	 * In mirror mode: CMPE, MUE, SUE
703*25cf1a30Sjl 	 * In normal mode: UE, Permanent CE
704*25cf1a30Sjl 	 */
705*25cf1a30Sjl 	rv = mcaddr_to_pa(mc_aflt->mflt_mcp,
706*25cf1a30Sjl 		&(mc_aflt->mflt_stat[0]->mf_flt_maddr), &pa);
707*25cf1a30Sjl 	if (rv == 0)
708*25cf1a30Sjl 		mc_aflt->mflt_stat[0]->mf_flt_paddr = pa;
709*25cf1a30Sjl 	else
710*25cf1a30Sjl 		mc_aflt->mflt_stat[0]->mf_flt_paddr = (uint64_t)-1;
711*25cf1a30Sjl 	if (rv == 0) {
712*25cf1a30Sjl 		MC_LOG("mc_err_drain:pa = %lx\n", pa);
713*25cf1a30Sjl 		pp = page_numtopp_nolock(pa >> PAGESHIFT);
714*25cf1a30Sjl 
715*25cf1a30Sjl 		if (pp) {
716*25cf1a30Sjl 			/*
717*25cf1a30Sjl 			 * Don't keep retiring and make ereports
718*25cf1a30Sjl 			 * on bad pages in PTRL case
719*25cf1a30Sjl 			 */
720*25cf1a30Sjl 			MC_LOG("mc_err_drain:pp = %p\n", pp);
721*25cf1a30Sjl 			if (mc_aflt->mflt_is_ptrl) {
722*25cf1a30Sjl 				errors = 0;
723*25cf1a30Sjl 				if (page_retire_check(pa, &errors) == 0) {
724*25cf1a30Sjl 					MC_LOG("Page retired\n");
725*25cf1a30Sjl 					return;
726*25cf1a30Sjl 				}
727*25cf1a30Sjl 				if (errors & mc_aflt->mflt_pr) {
728*25cf1a30Sjl 					MC_LOG("errors %lx, mflt_pr %x\n",
729*25cf1a30Sjl 						errors, mc_aflt->mflt_pr);
730*25cf1a30Sjl 					return;
731*25cf1a30Sjl 				}
732*25cf1a30Sjl 			}
733*25cf1a30Sjl 			MC_LOG("offline page %p error %x\n", pp,
734*25cf1a30Sjl 				mc_aflt->mflt_pr);
735*25cf1a30Sjl 			(void) page_retire(pa, mc_aflt->mflt_pr);
736*25cf1a30Sjl 		}
737*25cf1a30Sjl 	}
738*25cf1a30Sjl 	mc_ereport_post(mc_aflt);
739*25cf1a30Sjl }
740*25cf1a30Sjl 
741*25cf1a30Sjl #define	DIMM_SIZE 0x80000000
742*25cf1a30Sjl 
743*25cf1a30Sjl #define	INC_DIMM_ADDR(p, n) \
744*25cf1a30Sjl 	(p)->ma_dimm_addr += n; \
745*25cf1a30Sjl 	(p)->ma_dimm_addr &= (DIMM_SIZE - 1)
746*25cf1a30Sjl 
747*25cf1a30Sjl /*
748*25cf1a30Sjl  * The restart address is actually defined in unit of PA[37:6]
749*25cf1a30Sjl  * the mac patrol will convert that to dimm offset.  If the
750*25cf1a30Sjl  * address is not in the bank, it will continue to search for
751*25cf1a30Sjl  * the next PA that is within the bank.
752*25cf1a30Sjl  *
753*25cf1a30Sjl  * Also the mac patrol scans the dimms based on PA, not
754*25cf1a30Sjl  * dimm offset.
755*25cf1a30Sjl  */
756*25cf1a30Sjl 
757*25cf1a30Sjl static int
758*25cf1a30Sjl restart_patrol(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr_info)
759*25cf1a30Sjl {
760*25cf1a30Sjl 	page_t *pp;
761*25cf1a30Sjl 	uint32_t reg;
762*25cf1a30Sjl 	uint64_t pa;
763*25cf1a30Sjl 	int rv;
764*25cf1a30Sjl 	int loop_count = 0;
765*25cf1a30Sjl 
766*25cf1a30Sjl 	reg = ldphysio(MAC_PTRL_CNTL(mcp, bank));
767*25cf1a30Sjl 
768*25cf1a30Sjl 	/* already running, so we just return */
769*25cf1a30Sjl 	if (reg & MAC_CNTL_PTRL_START)
770*25cf1a30Sjl 		return (0);
771*25cf1a30Sjl 
772*25cf1a30Sjl 	if (maddr_info == NULL || (maddr_info->mi_valid == 0)) {
773*25cf1a30Sjl 		MAC_PTRL_START(mcp, bank);
774*25cf1a30Sjl 		return (0);
775*25cf1a30Sjl 	}
776*25cf1a30Sjl 
777*25cf1a30Sjl 
778*25cf1a30Sjl 	rv = mcaddr_to_pa(mcp, &maddr_info->mi_maddr, &pa);
779*25cf1a30Sjl 	if (rv != 0) {
780*25cf1a30Sjl 		MC_LOG("cannot convert mcaddr to pa. use auto restart\n");
781*25cf1a30Sjl 		MAC_PTRL_START(mcp, bank);
782*25cf1a30Sjl 		return (0);
783*25cf1a30Sjl 	}
784*25cf1a30Sjl 
785*25cf1a30Sjl 	/*
786*25cf1a30Sjl 	 * pa is the last address scanned by the mac patrol
787*25cf1a30Sjl 	 * we  calculate the next restart address as follows:
788*25cf1a30Sjl 	 * first we always advance it by 64 byte. Then begin the loop.
789*25cf1a30Sjl 	 * loop {
790*25cf1a30Sjl 	 * if it is not in phys_install, we advance to next 64 MB boundary
791*25cf1a30Sjl 	 * if it is not backed by a page structure, done
792*25cf1a30Sjl 	 * if the page is bad, advance to the next page boundary.
793*25cf1a30Sjl 	 * else done
794*25cf1a30Sjl 	 * if the new address exceeds the board, wrap around.
795*25cf1a30Sjl 	 * } <stop if we come back to the same page>
796*25cf1a30Sjl 	 */
797*25cf1a30Sjl 
798*25cf1a30Sjl 	if (pa < mcp->mc_start_address || pa >= (mcp->mc_start_address
799*25cf1a30Sjl 		+ mcp->mc_size)) {
800*25cf1a30Sjl 		/* pa is not on this board, just retry */
801*25cf1a30Sjl 		cmn_err(CE_WARN, "restart_patrol: invalid address %lx "
802*25cf1a30Sjl 			"on board %d\n", pa, mcp->mc_board_num);
803*25cf1a30Sjl 		MAC_PTRL_START(mcp, bank);
804*25cf1a30Sjl 		return (0);
805*25cf1a30Sjl 	}
806*25cf1a30Sjl 
807*25cf1a30Sjl 	MC_LOG("restart_patrol: pa = %lx\n", pa);
808*25cf1a30Sjl 	if (maddr_info->mi_advance) {
809*25cf1a30Sjl 		uint64_t new_pa;
810*25cf1a30Sjl 
811*25cf1a30Sjl 		if (IS_MIRROR(mcp, bank))
812*25cf1a30Sjl 			new_pa = pa + 64 * 2;
813*25cf1a30Sjl 		else
814*25cf1a30Sjl 			new_pa = pa + 64;
815*25cf1a30Sjl 
816*25cf1a30Sjl 		if (!mc_valid_pa(mcp, new_pa)) {
817*25cf1a30Sjl 			/* Isolation unit size is 64 MB */
818*25cf1a30Sjl #define	MC_ISOLATION_BSIZE	(64 * 1024 * 1024)
819*25cf1a30Sjl 			MC_LOG("Invalid PA\n");
820*25cf1a30Sjl 			pa = roundup(new_pa + 1, MC_ISOLATION_BSIZE);
821*25cf1a30Sjl 		} else {
822*25cf1a30Sjl 			pp = page_numtopp_nolock(new_pa >> PAGESHIFT);
823*25cf1a30Sjl 			if (pp != NULL) {
824*25cf1a30Sjl 				uint64_t errors = 0;
825*25cf1a30Sjl 				if (page_retire_check(new_pa, &errors) &&
826*25cf1a30Sjl 					(errors == 0)) {
827*25cf1a30Sjl 					MC_LOG("Page has no error\n");
828*25cf1a30Sjl 					MAC_PTRL_START(mcp, bank);
829*25cf1a30Sjl 					return (0);
830*25cf1a30Sjl 				}
831*25cf1a30Sjl 				/*
832*25cf1a30Sjl 				 * skip bad pages
833*25cf1a30Sjl 				 * and let the following loop to take care
834*25cf1a30Sjl 				 */
835*25cf1a30Sjl 				pa = roundup(new_pa + 1, PAGESIZE);
836*25cf1a30Sjl 				MC_LOG("Skipping bad page to %lx\n", pa);
837*25cf1a30Sjl 			} else {
838*25cf1a30Sjl 				MC_LOG("Page has no page structure\n");
839*25cf1a30Sjl 				MAC_PTRL_START(mcp, bank);
840*25cf1a30Sjl 				return (0);
841*25cf1a30Sjl 			}
842*25cf1a30Sjl 		}
843*25cf1a30Sjl 	}
844*25cf1a30Sjl 
845*25cf1a30Sjl 	/*
846*25cf1a30Sjl 	 * if we wrap around twice, we just give up and let
847*25cf1a30Sjl 	 * mac patrol decide.
848*25cf1a30Sjl 	 */
849*25cf1a30Sjl 	MC_LOG("pa is now %lx\n", pa);
850*25cf1a30Sjl 	while (loop_count <= 1) {
851*25cf1a30Sjl 		if (!mc_valid_pa(mcp, pa)) {
852*25cf1a30Sjl 			MC_LOG("pa is not valid. round up to 64 MB\n");
853*25cf1a30Sjl 			pa = roundup(pa + 1, 64 * 1024 * 1024);
854*25cf1a30Sjl 		} else {
855*25cf1a30Sjl 			pp = page_numtopp_nolock(pa >> PAGESHIFT);
856*25cf1a30Sjl 			if (pp != NULL) {
857*25cf1a30Sjl 				uint64_t errors = 0;
858*25cf1a30Sjl 				if (page_retire_check(pa, &errors) &&
859*25cf1a30Sjl 					(errors == 0)) {
860*25cf1a30Sjl 					MC_LOG("Page has no error\n");
861*25cf1a30Sjl 					break;
862*25cf1a30Sjl 				}
863*25cf1a30Sjl 				/* skip bad pages */
864*25cf1a30Sjl 				pa = roundup(pa + 1, PAGESIZE);
865*25cf1a30Sjl 				MC_LOG("Skipping bad page to %lx\n", pa);
866*25cf1a30Sjl 			} else {
867*25cf1a30Sjl 				MC_LOG("Page has no page structure\n");
868*25cf1a30Sjl 				break;
869*25cf1a30Sjl 			}
870*25cf1a30Sjl 		}
871*25cf1a30Sjl 		if (pa >= (mcp->mc_start_address + mcp->mc_size)) {
872*25cf1a30Sjl 			MC_LOG("Wrap around\n");
873*25cf1a30Sjl 			pa = mcp->mc_start_address;
874*25cf1a30Sjl 			loop_count++;
875*25cf1a30Sjl 		}
876*25cf1a30Sjl 	}
877*25cf1a30Sjl 
878*25cf1a30Sjl 	/* retstart MAC patrol: PA[37:6] */
879*25cf1a30Sjl 	MC_LOG("restart at pa = %lx\n", pa);
880*25cf1a30Sjl 	ST_MAC_REG(MAC_RESTART_ADD(mcp, bank), MAC_RESTART_PA(pa));
881*25cf1a30Sjl 	MAC_PTRL_START_ADD(mcp, bank);
882*25cf1a30Sjl 
883*25cf1a30Sjl 	return (0);
884*25cf1a30Sjl }
885*25cf1a30Sjl 
886*25cf1a30Sjl /*
887*25cf1a30Sjl  * Rewriting is used for two purposes.
888*25cf1a30Sjl  *  - to correct the error in memory.
889*25cf1a30Sjl  *  - to determine whether the error is permanent or intermittent.
890*25cf1a30Sjl  * It's done by writing the address in MAC_BANKm_REWRITE_ADD
891*25cf1a30Sjl  * and issuing REW_REQ command in MAC_BANKm_PTRL_CNRL. After that,
892*25cf1a30Sjl  * REW_END (and REW_CE/REW_UE if some error detected) is set when
893*25cf1a30Sjl  * rewrite operation is done. See 4.7.3 and 4.7.11 in Columbus2 PRM.
894*25cf1a30Sjl  *
895*25cf1a30Sjl  * Note that rewrite operation doesn't change RAW_UE to Marked UE.
896*25cf1a30Sjl  * Therefore, we use it only CE case.
897*25cf1a30Sjl  */
898*25cf1a30Sjl static uint32_t
899*25cf1a30Sjl do_rewrite(mc_opl_t *mcp, int bank, uint32_t dimm_addr)
900*25cf1a30Sjl {
901*25cf1a30Sjl 	uint32_t cntl;
902*25cf1a30Sjl 	int count = 0;
903*25cf1a30Sjl 
904*25cf1a30Sjl 	/* first wait to make sure PTRL_STATUS is 0 */
905*25cf1a30Sjl 	while (count++ < MAX_MC_LOOP_COUNT) {
906*25cf1a30Sjl 		cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
907*25cf1a30Sjl 		if (!(cntl & MAC_CNTL_PTRL_STATUS))
908*25cf1a30Sjl 			break;
909*25cf1a30Sjl 		delay(drv_usectohz(10 * 1000));	/* 10 m.s. */
910*25cf1a30Sjl 	}
911*25cf1a30Sjl 	if (count >= MAX_MC_LOOP_COUNT)
912*25cf1a30Sjl 		goto bad;
913*25cf1a30Sjl 
914*25cf1a30Sjl 	count = 0;
915*25cf1a30Sjl 
916*25cf1a30Sjl 	ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), dimm_addr);
917*25cf1a30Sjl 	MAC_REW_REQ(mcp, bank);
918*25cf1a30Sjl 
919*25cf1a30Sjl 	do {
920*25cf1a30Sjl 		cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
921*25cf1a30Sjl 		if (count++ >= MAX_MC_LOOP_COUNT) {
922*25cf1a30Sjl 			goto bad;
923*25cf1a30Sjl 		} else
924*25cf1a30Sjl 			delay(drv_usectohz(10 * 1000));	/* 10 m.s. */
925*25cf1a30Sjl 	/*
926*25cf1a30Sjl 	 * If there are other MEMORY or PCI activities, this
927*25cf1a30Sjl 	 * will be BUSY, else it should be set immediately
928*25cf1a30Sjl 	 */
929*25cf1a30Sjl 	} while (!(cntl & MAC_CNTL_REW_END));
930*25cf1a30Sjl 
931*25cf1a30Sjl 	MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS);
932*25cf1a30Sjl 	return (cntl);
933*25cf1a30Sjl bad:
934*25cf1a30Sjl 	/* This is bad.  Just reset the circuit */
935*25cf1a30Sjl 	cmn_err(CE_WARN, "mc-opl rewrite timeout on /LSB%d/B%d\n",
936*25cf1a30Sjl 		mcp->mc_board_num, bank);
937*25cf1a30Sjl 	cntl = MAC_CNTL_REW_END;
938*25cf1a30Sjl 	MAC_CMD(mcp, bank, MAC_CNTL_PTRL_RESET);
939*25cf1a30Sjl 	MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS);
940*25cf1a30Sjl 	return (cntl);
941*25cf1a30Sjl }
942*25cf1a30Sjl 
943*25cf1a30Sjl void
944*25cf1a30Sjl mc_process_scf_log(mc_opl_t *mcp)
945*25cf1a30Sjl {
946*25cf1a30Sjl 	int count = 0;
947*25cf1a30Sjl 	scf_log_t *p;
948*25cf1a30Sjl 	int bank;
949*25cf1a30Sjl 
950*25cf1a30Sjl 	while ((p = mcp->mc_scf_log) != NULL) {
951*25cf1a30Sjl 		bank = p->sl_bank;
952*25cf1a30Sjl 		while ((LD_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank))
953*25cf1a30Sjl 			& MAC_STATIC_ERR_VLD)) {
954*25cf1a30Sjl 			if (count++ >= (MAX_MC_LOOP_COUNT)) {
955*25cf1a30Sjl 				break;
956*25cf1a30Sjl 			}
957*25cf1a30Sjl 			delay(drv_usectohz(10 * 1000));	/* 10 m.s. */
958*25cf1a30Sjl 		}
959*25cf1a30Sjl 
960*25cf1a30Sjl 		if (count < MAX_MC_LOOP_COUNT) {
961*25cf1a30Sjl 			ST_MAC_REG(MAC_STATIC_ERR_LOG(mcp, p->sl_bank),
962*25cf1a30Sjl 				p->sl_err_log);
963*25cf1a30Sjl 
964*25cf1a30Sjl 			ST_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank),
965*25cf1a30Sjl 				p->sl_err_add|MAC_STATIC_ERR_VLD);
966*25cf1a30Sjl 			mcp->mc_scf_retry[bank] = 0;
967*25cf1a30Sjl 		} else {
968*25cf1a30Sjl 			/* if we try too many times, just drop the req */
969*25cf1a30Sjl 			if (mcp->mc_scf_retry[bank]++ <= MAX_SCF_RETRY) {
970*25cf1a30Sjl 				return;
971*25cf1a30Sjl 			} else {
972*25cf1a30Sjl 				cmn_err(CE_WARN, "SCF is not responding. "
973*25cf1a30Sjl 					"Dropping the SCF LOG\n");
974*25cf1a30Sjl 			}
975*25cf1a30Sjl 		}
976*25cf1a30Sjl 		mcp->mc_scf_log = p->sl_next;
977*25cf1a30Sjl 		mcp->mc_scf_total--;
978*25cf1a30Sjl 		ASSERT(mcp->mc_scf_total >= 0);
979*25cf1a30Sjl 		kmem_free(p, sizeof (scf_log_t));
980*25cf1a30Sjl 	}
981*25cf1a30Sjl }
982*25cf1a30Sjl 
983*25cf1a30Sjl void
984*25cf1a30Sjl mc_queue_scf_log(mc_opl_t *mcp, mc_flt_stat_t *flt_stat, int bank)
985*25cf1a30Sjl {
986*25cf1a30Sjl 	scf_log_t *p;
987*25cf1a30Sjl 
988*25cf1a30Sjl 	if (mcp->mc_scf_total >= MAX_SCF_LOGS) {
989*25cf1a30Sjl 		cmn_err(CE_WARN,
990*25cf1a30Sjl 			"Max# SCF logs excceded on /LSB%d/B%d\n",
991*25cf1a30Sjl 			mcp->mc_board_num, bank);
992*25cf1a30Sjl 		return;
993*25cf1a30Sjl 	}
994*25cf1a30Sjl 	p = kmem_zalloc(sizeof (scf_log_t), KM_SLEEP);
995*25cf1a30Sjl 	p->sl_next = 0;
996*25cf1a30Sjl 	p->sl_err_add = flt_stat->mf_err_add;
997*25cf1a30Sjl 	p->sl_err_log = flt_stat->mf_err_log;
998*25cf1a30Sjl 	p->sl_bank = bank;
999*25cf1a30Sjl 
1000*25cf1a30Sjl 	if (mcp->mc_scf_log == NULL) {
1001*25cf1a30Sjl 		/*
1002*25cf1a30Sjl 		 * we rely on mc_scf_log to detect NULL queue.
1003*25cf1a30Sjl 		 * mc_scf_log_tail is irrelevant is such case.
1004*25cf1a30Sjl 		 */
1005*25cf1a30Sjl 		mcp->mc_scf_log_tail = mcp->mc_scf_log = p;
1006*25cf1a30Sjl 	} else {
1007*25cf1a30Sjl 		mcp->mc_scf_log_tail->sl_next = p;
1008*25cf1a30Sjl 		mcp->mc_scf_log_tail = p;
1009*25cf1a30Sjl 	}
1010*25cf1a30Sjl 	mcp->mc_scf_total++;
1011*25cf1a30Sjl }
1012*25cf1a30Sjl 
1013*25cf1a30Sjl /*
1014*25cf1a30Sjl  * This routine determines what kind of CE happens, intermittent
1015*25cf1a30Sjl  * or permanent as follows. (See 4.7.3 in Columbus2 PRM.)
1016*25cf1a30Sjl  * - Do rewrite by issuing REW_REQ command to MAC_PTRL_CNTL register.
1017*25cf1a30Sjl  * - If CE is still detected on the same address even after doing
1018*25cf1a30Sjl  *   rewrite operation twice, it is determined as permanent error.
1019*25cf1a30Sjl  * - If error is not detected anymore, it is determined as intermittent
1020*25cf1a30Sjl  *   error.
1021*25cf1a30Sjl  * - If UE is detected due to rewrite operation, it should be treated
1022*25cf1a30Sjl  *   as UE.
1023*25cf1a30Sjl  */
1024*25cf1a30Sjl 
1025*25cf1a30Sjl /* ARGSUSED */
1026*25cf1a30Sjl static void
1027*25cf1a30Sjl mc_scrub_ce(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat, int ptrl_error)
1028*25cf1a30Sjl {
1029*25cf1a30Sjl 	uint32_t cntl;
1030*25cf1a30Sjl 	int i;
1031*25cf1a30Sjl 
1032*25cf1a30Sjl 	flt_stat->mf_type = FLT_TYPE_PERMANENT_CE;
1033*25cf1a30Sjl 	/*
1034*25cf1a30Sjl 	 * rewrite request 1st time reads and correct error data
1035*25cf1a30Sjl 	 * and write to DIMM.  2nd rewrite request must be issued
1036*25cf1a30Sjl 	 * after REW_CE/UE/END is 0.  When the 2nd request is completed,
1037*25cf1a30Sjl 	 * if REW_CE = 1, then it is permanent CE.
1038*25cf1a30Sjl 	 */
1039*25cf1a30Sjl 	for (i = 0; i < 2; i++) {
1040*25cf1a30Sjl 		cntl = do_rewrite(mcp, bank, flt_stat->mf_err_add);
1041*25cf1a30Sjl 		/*
1042*25cf1a30Sjl 		 * If the error becomes UE or CMPE
1043*25cf1a30Sjl 		 * we return to the caller immediately.
1044*25cf1a30Sjl 		 */
1045*25cf1a30Sjl 		if (cntl & MAC_CNTL_REW_UE) {
1046*25cf1a30Sjl 			if (ptrl_error)
1047*25cf1a30Sjl 				flt_stat->mf_cntl |= MAC_CNTL_PTRL_UE;
1048*25cf1a30Sjl 			else
1049*25cf1a30Sjl 				flt_stat->mf_cntl |= MAC_CNTL_MI_UE;
1050*25cf1a30Sjl 			flt_stat->mf_type = FLT_TYPE_UE;
1051*25cf1a30Sjl 			return;
1052*25cf1a30Sjl 		}
1053*25cf1a30Sjl 		if (cntl & MAC_CNTL_REW_CMPE) {
1054*25cf1a30Sjl 			if (ptrl_error)
1055*25cf1a30Sjl 				flt_stat->mf_cntl |= MAC_CNTL_PTRL_CMPE;
1056*25cf1a30Sjl 			else
1057*25cf1a30Sjl 				flt_stat->mf_cntl |= MAC_CNTL_MI_CMPE;
1058*25cf1a30Sjl 			flt_stat->mf_type = FLT_TYPE_CMPE;
1059*25cf1a30Sjl 			return;
1060*25cf1a30Sjl 		}
1061*25cf1a30Sjl 	}
1062*25cf1a30Sjl 	if (!(cntl & MAC_CNTL_REW_CE)) {
1063*25cf1a30Sjl 		flt_stat->mf_type = FLT_TYPE_INTERMITTENT_CE;
1064*25cf1a30Sjl 	}
1065*25cf1a30Sjl 
1066*25cf1a30Sjl 	if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
1067*25cf1a30Sjl 		/* report PERMANENT_CE to SP via SCF */
1068*25cf1a30Sjl 		if (!(flt_stat->mf_err_log & MAC_ERR_LOG_INVALID)) {
1069*25cf1a30Sjl 			mc_queue_scf_log(mcp, flt_stat, bank);
1070*25cf1a30Sjl 		}
1071*25cf1a30Sjl 	}
1072*25cf1a30Sjl }
1073*25cf1a30Sjl 
1074*25cf1a30Sjl #define	IS_CMPE(cntl, f)	((cntl) & ((f) ? MAC_CNTL_PTRL_CMPE :\
1075*25cf1a30Sjl 				MAC_CNTL_MI_CMPE))
1076*25cf1a30Sjl #define	IS_UE(cntl, f)	((cntl) & ((f) ? MAC_CNTL_PTRL_UE : MAC_CNTL_MI_UE))
1077*25cf1a30Sjl #define	IS_CE(cntl, f)	((cntl) & ((f) ? MAC_CNTL_PTRL_CE : MAC_CNTL_MI_CE))
1078*25cf1a30Sjl #define	IS_OK(cntl, f)	(!((cntl) & ((f) ? MAC_CNTL_PTRL_ERRS : \
1079*25cf1a30Sjl 			MAC_CNTL_MI_ERRS)))
1080*25cf1a30Sjl 
1081*25cf1a30Sjl 
1082*25cf1a30Sjl static int
1083*25cf1a30Sjl IS_CE_ONLY(uint32_t cntl, int ptrl_error)
1084*25cf1a30Sjl {
1085*25cf1a30Sjl 	if (ptrl_error) {
1086*25cf1a30Sjl 		return ((cntl & MAC_CNTL_PTRL_ERRS) == MAC_CNTL_PTRL_CE);
1087*25cf1a30Sjl 	} else {
1088*25cf1a30Sjl 		return ((cntl & MAC_CNTL_MI_ERRS) == MAC_CNTL_MI_CE);
1089*25cf1a30Sjl 	}
1090*25cf1a30Sjl }
1091*25cf1a30Sjl 
1092*25cf1a30Sjl void
1093*25cf1a30Sjl mc_write_cntl(mc_opl_t *mcp, int bank, uint32_t value)
1094*25cf1a30Sjl {
1095*25cf1a30Sjl 	value |= mcp->mc_bank[bank].mcb_ptrl_cntl;
1096*25cf1a30Sjl 	ST_MAC_REG(MAC_PTRL_CNTL(mcp, bank), value);
1097*25cf1a30Sjl }
1098*25cf1a30Sjl 
1099*25cf1a30Sjl static int
1100*25cf1a30Sjl mc_stop(mc_opl_t *mcp, int bank)
1101*25cf1a30Sjl {
1102*25cf1a30Sjl 	uint32_t reg;
1103*25cf1a30Sjl 	int count = 0;
1104*25cf1a30Sjl 
1105*25cf1a30Sjl 	reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
1106*25cf1a30Sjl 
1107*25cf1a30Sjl 	if (reg & MAC_CNTL_PTRL_START)
1108*25cf1a30Sjl 		MAC_PTRL_STOP(mcp, bank);
1109*25cf1a30Sjl 
1110*25cf1a30Sjl 	while (count++ <= MAX_MC_LOOP_COUNT) {
1111*25cf1a30Sjl 		reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
1112*25cf1a30Sjl 		if ((reg & MAC_CNTL_PTRL_STATUS) == 0)
1113*25cf1a30Sjl 			return (0);
1114*25cf1a30Sjl 		delay(drv_usectohz(10 * 1000));	/* 10 m.s. */
1115*25cf1a30Sjl 	}
1116*25cf1a30Sjl 	return (-1);
1117*25cf1a30Sjl }
1118*25cf1a30Sjl 
1119*25cf1a30Sjl static void
1120*25cf1a30Sjl mc_read_ptrl_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat)
1121*25cf1a30Sjl {
1122*25cf1a30Sjl 	flt_stat->mf_cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) &
1123*25cf1a30Sjl 		MAC_CNTL_PTRL_ERRS;
1124*25cf1a30Sjl 	flt_stat->mf_err_add = LD_MAC_REG(MAC_PTRL_ERR_ADD(mcp, bank));
1125*25cf1a30Sjl 	flt_stat->mf_err_log = LD_MAC_REG(MAC_PTRL_ERR_LOG(mcp, bank));
1126*25cf1a30Sjl 	flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num;
1127*25cf1a30Sjl 	flt_stat->mf_flt_maddr.ma_bank = bank;
1128*25cf1a30Sjl 	flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add;
1129*25cf1a30Sjl }
1130*25cf1a30Sjl 
1131*25cf1a30Sjl static void
1132*25cf1a30Sjl mc_read_mi_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat)
1133*25cf1a30Sjl {
1134*25cf1a30Sjl 	uint32_t status, old_status;
1135*25cf1a30Sjl 
1136*25cf1a30Sjl 	status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) &
1137*25cf1a30Sjl 		MAC_CNTL_MI_ERRS;
1138*25cf1a30Sjl 	old_status = 0;
1139*25cf1a30Sjl 
1140*25cf1a30Sjl 	/* we keep reading until the status is stable */
1141*25cf1a30Sjl 	while (old_status != status) {
1142*25cf1a30Sjl 		old_status = status;
1143*25cf1a30Sjl 		flt_stat->mf_err_add =
1144*25cf1a30Sjl 			LD_MAC_REG(MAC_MI_ERR_ADD(mcp, bank));
1145*25cf1a30Sjl 		flt_stat->mf_err_log =
1146*25cf1a30Sjl 			LD_MAC_REG(MAC_MI_ERR_LOG(mcp, bank));
1147*25cf1a30Sjl 		status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) &
1148*25cf1a30Sjl 			MAC_CNTL_MI_ERRS;
1149*25cf1a30Sjl 		if (status == old_status) {
1150*25cf1a30Sjl 			break;
1151*25cf1a30Sjl 		}
1152*25cf1a30Sjl 	}
1153*25cf1a30Sjl 
1154*25cf1a30Sjl 	flt_stat->mf_cntl = status;
1155*25cf1a30Sjl 	flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num;
1156*25cf1a30Sjl 	flt_stat->mf_flt_maddr.ma_bank = bank;
1157*25cf1a30Sjl 	flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add;
1158*25cf1a30Sjl }
1159*25cf1a30Sjl 
1160*25cf1a30Sjl 
1161*25cf1a30Sjl /*
1162*25cf1a30Sjl  * Error philosophy for mirror mode:
1163*25cf1a30Sjl  *
1164*25cf1a30Sjl  * PTRL (The error address for both banks are same, since ptrl stops if it
1165*25cf1a30Sjl  * detects error.)
1166*25cf1a30Sjl  * - Compaire error  Report CMPE.
1167*25cf1a30Sjl  *
1168*25cf1a30Sjl  * - UE-UE           Report MUE.  No rewrite.
1169*25cf1a30Sjl  *
1170*25cf1a30Sjl  * - UE-*	     UE-(CE/OK). Rewrite to scrub UE.  Report SUE.
1171*25cf1a30Sjl  *
1172*25cf1a30Sjl  * - CE-*            CE-(CE/OK). Scrub to determine if CE is permanent.
1173*25cf1a30Sjl  *                   If CE is permanent, inform SCF.  Once for each
1174*25cf1a30Sjl  *		     Dimm.  If CE becomes UE or CMPE, go back to above.
1175*25cf1a30Sjl  *
1176*25cf1a30Sjl  *
1177*25cf1a30Sjl  * MI (The error addresses for each bank are the same or different.)
1178*25cf1a30Sjl  * - Compair  error  If addresses are the same.  Just CMPE.
1179*25cf1a30Sjl  *		     If addresses are different (this could happen
1180*25cf1a30Sjl  *		     as a result of scrubbing.  Report each seperately.
1181*25cf1a30Sjl  *		     Only report error info on each side.
1182*25cf1a30Sjl  *
1183*25cf1a30Sjl  * - UE-UE           Addresses are the same.  Report MUE.
1184*25cf1a30Sjl  *		     Addresses are different.  Report SUE on each bank.
1185*25cf1a30Sjl  *		     Rewrite to clear UE.
1186*25cf1a30Sjl  *
1187*25cf1a30Sjl  * - UE-*	     UE-(CE/OK)
1188*25cf1a30Sjl  *		     Rewrite to clear UE.  Report SUE for the bank.
1189*25cf1a30Sjl  *
1190*25cf1a30Sjl  * - CE-*            CE-(CE/OK).  Scrub to determine if CE is permanent.
1191*25cf1a30Sjl  *                   If CE becomes UE or CMPE, go back to above.
1192*25cf1a30Sjl  *
1193*25cf1a30Sjl  */
1194*25cf1a30Sjl 
1195*25cf1a30Sjl static int
1196*25cf1a30Sjl mc_process_error_mir(mc_opl_t *mcp, mc_aflt_t *mc_aflt, mc_flt_stat_t *flt_stat)
1197*25cf1a30Sjl {
1198*25cf1a30Sjl 	int ptrl_error = mc_aflt->mflt_is_ptrl;
1199*25cf1a30Sjl 	int i;
1200*25cf1a30Sjl 	int rv = 0;
1201*25cf1a30Sjl 
1202*25cf1a30Sjl 	MC_LOG("process mirror errors cntl[0] = %x, cntl[1] = %x\n",
1203*25cf1a30Sjl 		flt_stat[0].mf_cntl, flt_stat[1].mf_cntl);
1204*25cf1a30Sjl 
1205*25cf1a30Sjl 	if (ptrl_error) {
1206*25cf1a30Sjl 		if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl)
1207*25cf1a30Sjl 			& MAC_CNTL_PTRL_ERRS) == 0)
1208*25cf1a30Sjl 			return (0);
1209*25cf1a30Sjl 	} else {
1210*25cf1a30Sjl 		if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl)
1211*25cf1a30Sjl 			& MAC_CNTL_MI_ERRS) == 0)
1212*25cf1a30Sjl 			return (0);
1213*25cf1a30Sjl 	}
1214*25cf1a30Sjl 
1215*25cf1a30Sjl 	/*
1216*25cf1a30Sjl 	 * First we take care of the case of CE
1217*25cf1a30Sjl 	 * because they can become UE or CMPE
1218*25cf1a30Sjl 	 */
1219*25cf1a30Sjl 	for (i = 0; i < 2; i++) {
1220*25cf1a30Sjl 		if (IS_CE_ONLY(flt_stat[i].mf_cntl, ptrl_error)) {
1221*25cf1a30Sjl 			MC_LOG("CE detected on bank %d\n",
1222*25cf1a30Sjl 				flt_stat[i].mf_flt_maddr.ma_bank);
1223*25cf1a30Sjl 			mc_scrub_ce(mcp, flt_stat[i].mf_flt_maddr.ma_bank,
1224*25cf1a30Sjl 				&flt_stat[i], ptrl_error);
1225*25cf1a30Sjl 			rv = 1;
1226*25cf1a30Sjl 		}
1227*25cf1a30Sjl 	}
1228*25cf1a30Sjl 
1229*25cf1a30Sjl 	/* The above scrubbing can turn CE into UE or CMPE */
1230*25cf1a30Sjl 
1231*25cf1a30Sjl 	/*
1232*25cf1a30Sjl 	 * Now we distinguish two cases: same address or not
1233*25cf1a30Sjl 	 * the same address.  It might seem more intuitive to
1234*25cf1a30Sjl 	 * distinguish PTRL v.s. MI error but it is more
1235*25cf1a30Sjl 	 * complicated that way.
1236*25cf1a30Sjl 	 */
1237*25cf1a30Sjl 
1238*25cf1a30Sjl 	if (flt_stat[0].mf_err_add == flt_stat[1].mf_err_add) {
1239*25cf1a30Sjl 
1240*25cf1a30Sjl 		if (IS_CMPE(flt_stat[0].mf_cntl, ptrl_error) ||
1241*25cf1a30Sjl 		    IS_CMPE(flt_stat[1].mf_cntl, ptrl_error)) {
1242*25cf1a30Sjl 			flt_stat[0].mf_type = FLT_TYPE_CMPE;
1243*25cf1a30Sjl 			flt_stat[1].mf_type = FLT_TYPE_CMPE;
1244*25cf1a30Sjl 			mc_aflt->mflt_erpt_class = MC_OPL_CMPE;
1245*25cf1a30Sjl 			MC_LOG("cmpe error detected\n");
1246*25cf1a30Sjl 			mc_aflt->mflt_nflts = 2;
1247*25cf1a30Sjl 			mc_aflt->mflt_stat[0] = &flt_stat[0];
1248*25cf1a30Sjl 			mc_aflt->mflt_stat[1] = &flt_stat[1];
1249*25cf1a30Sjl 			mc_aflt->mflt_pr = PR_UE;
1250*25cf1a30Sjl 			mc_err_drain(mc_aflt);
1251*25cf1a30Sjl 			return (1);
1252*25cf1a30Sjl 		}
1253*25cf1a30Sjl 
1254*25cf1a30Sjl 		if (IS_UE(flt_stat[0].mf_cntl, ptrl_error) &&
1255*25cf1a30Sjl 			IS_UE(flt_stat[1].mf_cntl, ptrl_error)) {
1256*25cf1a30Sjl 			/* Both side are UE's */
1257*25cf1a30Sjl 
1258*25cf1a30Sjl 			MAC_SET_ERRLOG_INFO(&flt_stat[0]);
1259*25cf1a30Sjl 			MAC_SET_ERRLOG_INFO(&flt_stat[1]);
1260*25cf1a30Sjl 			MC_LOG("MUE detected\n");
1261*25cf1a30Sjl 			flt_stat[0].mf_type = flt_stat[1].mf_type =
1262*25cf1a30Sjl 				FLT_TYPE_MUE;
1263*25cf1a30Sjl 			mc_aflt->mflt_erpt_class = MC_OPL_MUE;
1264*25cf1a30Sjl 			mc_aflt->mflt_nflts = 2;
1265*25cf1a30Sjl 			mc_aflt->mflt_stat[0] = &flt_stat[0];
1266*25cf1a30Sjl 			mc_aflt->mflt_stat[1] = &flt_stat[1];
1267*25cf1a30Sjl 			mc_aflt->mflt_pr = PR_UE;
1268*25cf1a30Sjl 			mc_err_drain(mc_aflt);
1269*25cf1a30Sjl 			return (1);
1270*25cf1a30Sjl 		}
1271*25cf1a30Sjl 
1272*25cf1a30Sjl 		/* Now the only case is UE/CE, UE/OK, or don't care */
1273*25cf1a30Sjl 		for (i = 0; i < 2; i++) {
1274*25cf1a30Sjl 		    if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) {
1275*25cf1a30Sjl 			/* If we have CE, we would have done REW */
1276*25cf1a30Sjl 			if (IS_OK(flt_stat[i^1].mf_cntl, ptrl_error)) {
1277*25cf1a30Sjl 				(void) do_rewrite(mcp,
1278*25cf1a30Sjl 				    flt_stat[i].mf_flt_maddr.ma_bank,
1279*25cf1a30Sjl 				    flt_stat[i].mf_flt_maddr.ma_dimm_addr);
1280*25cf1a30Sjl 			}
1281*25cf1a30Sjl 			flt_stat[i].mf_type = FLT_TYPE_UE;
1282*25cf1a30Sjl 			MAC_SET_ERRLOG_INFO(&flt_stat[i]);
1283*25cf1a30Sjl 			mc_aflt->mflt_erpt_class = MC_OPL_SUE;
1284*25cf1a30Sjl 			mc_aflt->mflt_stat[0] = &flt_stat[i];
1285*25cf1a30Sjl 			mc_aflt->mflt_nflts = 1;
1286*25cf1a30Sjl 			mc_aflt->mflt_pr = PR_MCE;
1287*25cf1a30Sjl 			mc_err_drain(mc_aflt);
1288*25cf1a30Sjl 			/* Once we hit a UE/CE or UE/OK case, done */
1289*25cf1a30Sjl 			return (1);
1290*25cf1a30Sjl 		    }
1291*25cf1a30Sjl 		}
1292*25cf1a30Sjl 
1293*25cf1a30Sjl 	} else {
1294*25cf1a30Sjl 		/*
1295*25cf1a30Sjl 		 * addresses are different. That means errors
1296*25cf1a30Sjl 		 * on the 2 banks are not related at all.
1297*25cf1a30Sjl 		 */
1298*25cf1a30Sjl 		for (i = 0; i < 2; i++) {
1299*25cf1a30Sjl 		    if (IS_CMPE(flt_stat[i].mf_cntl, ptrl_error)) {
1300*25cf1a30Sjl 			flt_stat[i].mf_type = FLT_TYPE_CMPE;
1301*25cf1a30Sjl 			mc_aflt->mflt_erpt_class = MC_OPL_CMPE;
1302*25cf1a30Sjl 			MC_LOG("cmpe error detected\n");
1303*25cf1a30Sjl 			mc_aflt->mflt_nflts = 1;
1304*25cf1a30Sjl 			mc_aflt->mflt_stat[0] = &flt_stat[i];
1305*25cf1a30Sjl 			mc_aflt->mflt_pr = PR_UE;
1306*25cf1a30Sjl 			mc_err_drain(mc_aflt);
1307*25cf1a30Sjl 			/* no more report on this bank */
1308*25cf1a30Sjl 			flt_stat[i].mf_cntl = 0;
1309*25cf1a30Sjl 			rv = 1;
1310*25cf1a30Sjl 		    }
1311*25cf1a30Sjl 		}
1312*25cf1a30Sjl 
1313*25cf1a30Sjl 		for (i = 0; i < 2; i++) {
1314*25cf1a30Sjl 		    if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) {
1315*25cf1a30Sjl 			(void) do_rewrite(mcp,
1316*25cf1a30Sjl 				flt_stat[i].mf_flt_maddr.ma_bank,
1317*25cf1a30Sjl 				flt_stat[i].mf_flt_maddr.ma_dimm_addr);
1318*25cf1a30Sjl 			flt_stat[i].mf_type = FLT_TYPE_UE;
1319*25cf1a30Sjl 			MAC_SET_ERRLOG_INFO(&flt_stat[i]);
1320*25cf1a30Sjl 			mc_aflt->mflt_erpt_class = MC_OPL_SUE;
1321*25cf1a30Sjl 			mc_aflt->mflt_stat[0] = &flt_stat[i];
1322*25cf1a30Sjl 			mc_aflt->mflt_nflts = 1;
1323*25cf1a30Sjl 			mc_aflt->mflt_pr = PR_MCE;
1324*25cf1a30Sjl 			mc_err_drain(mc_aflt);
1325*25cf1a30Sjl 			rv = 1;
1326*25cf1a30Sjl 		    }
1327*25cf1a30Sjl 		}
1328*25cf1a30Sjl 	}
1329*25cf1a30Sjl 	return (rv);
1330*25cf1a30Sjl }
1331*25cf1a30Sjl 
1332*25cf1a30Sjl static void
1333*25cf1a30Sjl mc_error_handler_mir(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr)
1334*25cf1a30Sjl {
1335*25cf1a30Sjl 	mc_aflt_t mc_aflt;
1336*25cf1a30Sjl 	mc_flt_stat_t flt_stat[2], mi_flt_stat[2];
1337*25cf1a30Sjl 	int other_bank;
1338*25cf1a30Sjl 
1339*25cf1a30Sjl 	if (mc_stop(mcp, bank)) {
1340*25cf1a30Sjl 		cmn_err(CE_WARN, "Cannot stop Memory Patrol at /LSB%d/B%d\n",
1341*25cf1a30Sjl 			mcp->mc_board_num, bank);
1342*25cf1a30Sjl 		return;
1343*25cf1a30Sjl 	}
1344*25cf1a30Sjl 	bzero(&mc_aflt, sizeof (mc_aflt_t));
1345*25cf1a30Sjl 	bzero(&flt_stat, 2 * sizeof (mc_flt_stat_t));
1346*25cf1a30Sjl 	bzero(&mi_flt_stat, 2 * sizeof (mc_flt_stat_t));
1347*25cf1a30Sjl 
1348*25cf1a30Sjl 	mc_aflt.mflt_mcp = mcp;
1349*25cf1a30Sjl 	mc_aflt.mflt_id = gethrtime();
1350*25cf1a30Sjl 
1351*25cf1a30Sjl 	/* Now read all the registers into flt_stat */
1352*25cf1a30Sjl 
1353*25cf1a30Sjl 	MC_LOG("Reading registers of bank %d\n", bank);
1354*25cf1a30Sjl 	/* patrol registers */
1355*25cf1a30Sjl 	mc_read_ptrl_reg(mcp, bank, &flt_stat[0]);
1356*25cf1a30Sjl 
1357*25cf1a30Sjl 	ASSERT(maddr);
1358*25cf1a30Sjl 	maddr->mi_maddr = flt_stat[0].mf_flt_maddr;
1359*25cf1a30Sjl 
1360*25cf1a30Sjl 	MC_LOG("ptrl registers cntl %x add %x log %x\n",
1361*25cf1a30Sjl 		flt_stat[0].mf_cntl,
1362*25cf1a30Sjl 		flt_stat[0].mf_err_add,
1363*25cf1a30Sjl 		flt_stat[0].mf_err_log);
1364*25cf1a30Sjl 
1365*25cf1a30Sjl 	/* MI registers */
1366*25cf1a30Sjl 	mc_read_mi_reg(mcp, bank, &mi_flt_stat[0]);
1367*25cf1a30Sjl 
1368*25cf1a30Sjl 	MC_LOG("MI registers cntl %x add %x log %x\n",
1369*25cf1a30Sjl 		mi_flt_stat[0].mf_cntl,
1370*25cf1a30Sjl 		mi_flt_stat[0].mf_err_add,
1371*25cf1a30Sjl 		mi_flt_stat[0].mf_err_log);
1372*25cf1a30Sjl 
1373*25cf1a30Sjl 	other_bank = bank^1;
1374*25cf1a30Sjl 
1375*25cf1a30Sjl 	MC_LOG("Reading registers of bank %d\n", other_bank);
1376*25cf1a30Sjl 
1377*25cf1a30Sjl 	ASSERT(mcp->mc_bank[other_bank].mcb_status & BANK_INSTALLED);
1378*25cf1a30Sjl 
1379*25cf1a30Sjl 	mc_read_ptrl_reg(mcp, other_bank, &flt_stat[1]);
1380*25cf1a30Sjl 	MC_LOG("ptrl registers cntl %x add %x log %x\n",
1381*25cf1a30Sjl 		flt_stat[1].mf_cntl,
1382*25cf1a30Sjl 		flt_stat[1].mf_err_add,
1383*25cf1a30Sjl 		flt_stat[1].mf_err_log);
1384*25cf1a30Sjl 
1385*25cf1a30Sjl 	/* MI registers */
1386*25cf1a30Sjl 	mc_read_mi_reg(mcp, other_bank, &mi_flt_stat[1]);
1387*25cf1a30Sjl 	MC_LOG("MI registers cntl %x add %x log %x\n",
1388*25cf1a30Sjl 		mi_flt_stat[1].mf_cntl,
1389*25cf1a30Sjl 		mi_flt_stat[1].mf_err_add,
1390*25cf1a30Sjl 		mi_flt_stat[1].mf_err_log);
1391*25cf1a30Sjl 
1392*25cf1a30Sjl 	/* clear errors once we read all the registers */
1393*25cf1a30Sjl 	MAC_CLEAR_ERRS(mcp, other_bank,
1394*25cf1a30Sjl 		(MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
1395*25cf1a30Sjl 
1396*25cf1a30Sjl 	MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
1397*25cf1a30Sjl 
1398*25cf1a30Sjl 	/* Process PTRL errors first */
1399*25cf1a30Sjl 
1400*25cf1a30Sjl 	/* if not error mode, cntl1 is 0 */
1401*25cf1a30Sjl 	if ((flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) ||
1402*25cf1a30Sjl 		(flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID))
1403*25cf1a30Sjl 		flt_stat[0].mf_cntl = 0;
1404*25cf1a30Sjl 
1405*25cf1a30Sjl 	if ((flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) ||
1406*25cf1a30Sjl 		(flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID))
1407*25cf1a30Sjl 		flt_stat[1].mf_cntl = 0;
1408*25cf1a30Sjl 
1409*25cf1a30Sjl 	mc_aflt.mflt_is_ptrl = 1;
1410*25cf1a30Sjl 	maddr->mi_valid = mc_process_error_mir(mcp, &mc_aflt, &flt_stat[0]);
1411*25cf1a30Sjl 
1412*25cf1a30Sjl 	mc_aflt.mflt_is_ptrl = 0;
1413*25cf1a30Sjl 	mc_process_error_mir(mcp, &mc_aflt, &mi_flt_stat[0]);
1414*25cf1a30Sjl }
1415*25cf1a30Sjl 
1416*25cf1a30Sjl static int
1417*25cf1a30Sjl mc_process_error(mc_opl_t *mcp, int bank, mc_aflt_t *mc_aflt,
1418*25cf1a30Sjl 	mc_flt_stat_t *flt_stat)
1419*25cf1a30Sjl {
1420*25cf1a30Sjl 	int ptrl_error = mc_aflt->mflt_is_ptrl;
1421*25cf1a30Sjl 	int rv = 0;
1422*25cf1a30Sjl 
1423*25cf1a30Sjl 	mc_aflt->mflt_erpt_class = NULL;
1424*25cf1a30Sjl 	if (IS_UE(flt_stat->mf_cntl, ptrl_error)) {
1425*25cf1a30Sjl 		MC_LOG("UE deteceted\n");
1426*25cf1a30Sjl 		flt_stat->mf_type = FLT_TYPE_UE;
1427*25cf1a30Sjl 		mc_aflt->mflt_erpt_class = MC_OPL_UE;
1428*25cf1a30Sjl 		mc_aflt->mflt_pr = PR_UE;
1429*25cf1a30Sjl 		MAC_SET_ERRLOG_INFO(flt_stat);
1430*25cf1a30Sjl 		rv = 1;
1431*25cf1a30Sjl 	} else if (IS_CE(flt_stat->mf_cntl, ptrl_error)) {
1432*25cf1a30Sjl 		MC_LOG("CE deteceted\n");
1433*25cf1a30Sjl 		MAC_SET_ERRLOG_INFO(flt_stat);
1434*25cf1a30Sjl 
1435*25cf1a30Sjl 		/* Error type can change after scrubing */
1436*25cf1a30Sjl 		mc_scrub_ce(mcp, bank, flt_stat, ptrl_error);
1437*25cf1a30Sjl 
1438*25cf1a30Sjl 		if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) {
1439*25cf1a30Sjl 			mc_aflt->mflt_erpt_class = MC_OPL_CE;
1440*25cf1a30Sjl 			mc_aflt->mflt_pr = PR_MCE;
1441*25cf1a30Sjl 		} else if (flt_stat->mf_type == FLT_TYPE_UE) {
1442*25cf1a30Sjl 			mc_aflt->mflt_erpt_class = MC_OPL_UE;
1443*25cf1a30Sjl 			mc_aflt->mflt_pr = PR_UE;
1444*25cf1a30Sjl 		}
1445*25cf1a30Sjl 		rv = 1;
1446*25cf1a30Sjl 	}
1447*25cf1a30Sjl 	MC_LOG("mc_process_error: fault type %x erpt %s\n",
1448*25cf1a30Sjl 		flt_stat->mf_type,
1449*25cf1a30Sjl 		mc_aflt->mflt_erpt_class);
1450*25cf1a30Sjl 	if (mc_aflt->mflt_erpt_class) {
1451*25cf1a30Sjl 		mc_aflt->mflt_stat[0] = flt_stat;
1452*25cf1a30Sjl 		mc_aflt->mflt_nflts = 1;
1453*25cf1a30Sjl 		mc_err_drain(mc_aflt);
1454*25cf1a30Sjl 	}
1455*25cf1a30Sjl 	return (rv);
1456*25cf1a30Sjl }
1457*25cf1a30Sjl 
1458*25cf1a30Sjl static void
1459*25cf1a30Sjl mc_error_handler(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr)
1460*25cf1a30Sjl {
1461*25cf1a30Sjl 	mc_aflt_t mc_aflt;
1462*25cf1a30Sjl 	mc_flt_stat_t flt_stat, mi_flt_stat;
1463*25cf1a30Sjl 
1464*25cf1a30Sjl 	if (mc_stop(mcp, bank)) {
1465*25cf1a30Sjl 		cmn_err(CE_WARN, "Cannot stop Memory Patrol at /LSB%d/B%d\n",
1466*25cf1a30Sjl 			mcp->mc_board_num, bank);
1467*25cf1a30Sjl 		return;
1468*25cf1a30Sjl 	}
1469*25cf1a30Sjl 
1470*25cf1a30Sjl 	bzero(&mc_aflt, sizeof (mc_aflt_t));
1471*25cf1a30Sjl 	bzero(&flt_stat, sizeof (mc_flt_stat_t));
1472*25cf1a30Sjl 	bzero(&mi_flt_stat, sizeof (mc_flt_stat_t));
1473*25cf1a30Sjl 
1474*25cf1a30Sjl 	mc_aflt.mflt_mcp = mcp;
1475*25cf1a30Sjl 	mc_aflt.mflt_id = gethrtime();
1476*25cf1a30Sjl 
1477*25cf1a30Sjl 	/* patrol registers */
1478*25cf1a30Sjl 	mc_read_ptrl_reg(mcp, bank, &flt_stat);
1479*25cf1a30Sjl 
1480*25cf1a30Sjl 	ASSERT(maddr);
1481*25cf1a30Sjl 	maddr->mi_maddr = flt_stat.mf_flt_maddr;
1482*25cf1a30Sjl 
1483*25cf1a30Sjl 	MC_LOG("ptrl registers cntl %x add %x log %x\n",
1484*25cf1a30Sjl 		flt_stat.mf_cntl,
1485*25cf1a30Sjl 		flt_stat.mf_err_add,
1486*25cf1a30Sjl 		flt_stat.mf_err_log);
1487*25cf1a30Sjl 
1488*25cf1a30Sjl 	/* MI registers */
1489*25cf1a30Sjl 	mc_read_mi_reg(mcp, bank, &mi_flt_stat);
1490*25cf1a30Sjl 
1491*25cf1a30Sjl 	MC_LOG("MI registers cntl %x add %x log %x\n",
1492*25cf1a30Sjl 		mi_flt_stat.mf_cntl,
1493*25cf1a30Sjl 		mi_flt_stat.mf_err_add,
1494*25cf1a30Sjl 		mi_flt_stat.mf_err_log);
1495*25cf1a30Sjl 
1496*25cf1a30Sjl 	/* clear errors once we read all the registers */
1497*25cf1a30Sjl 	MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS));
1498*25cf1a30Sjl 
1499*25cf1a30Sjl 	mc_aflt.mflt_is_ptrl = 1;
1500*25cf1a30Sjl 	if ((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) &&
1501*25cf1a30Sjl 		((flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) &&
1502*25cf1a30Sjl 		((flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) {
1503*25cf1a30Sjl 		maddr->mi_valid = mc_process_error(mcp, bank,
1504*25cf1a30Sjl 			&mc_aflt, &flt_stat);
1505*25cf1a30Sjl 	}
1506*25cf1a30Sjl 	mc_aflt.mflt_is_ptrl = 0;
1507*25cf1a30Sjl 	if ((mi_flt_stat.mf_cntl & MAC_CNTL_MI_ERRS) &&
1508*25cf1a30Sjl 		((mi_flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) &&
1509*25cf1a30Sjl 		((mi_flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) {
1510*25cf1a30Sjl 		mc_process_error(mcp, bank, &mc_aflt, &mi_flt_stat);
1511*25cf1a30Sjl 	}
1512*25cf1a30Sjl }
1513*25cf1a30Sjl 
1514*25cf1a30Sjl /*
1515*25cf1a30Sjl  *	memory patrol error handling algorithm:
1516*25cf1a30Sjl  *	timeout() is used to do periodic polling
1517*25cf1a30Sjl  *	This is the flow chart.
1518*25cf1a30Sjl  *	timeout ->
1519*25cf1a30Sjl  *	mc_check_errors()
1520*25cf1a30Sjl  *	    if memory bank is installed, read the status register
1521*25cf1a30Sjl  *	    if any error bit is set,
1522*25cf1a30Sjl  *	    -> mc_error_handler()
1523*25cf1a30Sjl  *	        -> mc_stop()
1524*25cf1a30Sjl  *		-> read all error regsiters
1525*25cf1a30Sjl  *	        -> mc_process_error()
1526*25cf1a30Sjl  *	            determine error type
1527*25cf1a30Sjl  *	            rewrite to clear error or scrub to determine CE type
1528*25cf1a30Sjl  *	            inform SCF on permanent CE
1529*25cf1a30Sjl  *	        -> mc_err_drain
1530*25cf1a30Sjl  *	            page offline processing
1531*25cf1a30Sjl  *	            -> mc_ereport_post()
1532*25cf1a30Sjl  */
1533*25cf1a30Sjl 
1534*25cf1a30Sjl static void
1535*25cf1a30Sjl mc_check_errors_func(mc_opl_t *mcp)
1536*25cf1a30Sjl {
1537*25cf1a30Sjl 	mc_addr_info_t maddr_info;
1538*25cf1a30Sjl 	int i, error_count = 0;
1539*25cf1a30Sjl 	uint32_t stat, cntl;
1540*25cf1a30Sjl 
1541*25cf1a30Sjl 	/*
1542*25cf1a30Sjl 	 * scan errors.
1543*25cf1a30Sjl 	 */
1544*25cf1a30Sjl 	for (i = 0; i < BANKNUM_PER_SB; i++) {
1545*25cf1a30Sjl 		if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
1546*25cf1a30Sjl 			stat = ldphysio(MAC_PTRL_STAT(mcp, i));
1547*25cf1a30Sjl 			cntl = ldphysio(MAC_PTRL_CNTL(mcp, i));
1548*25cf1a30Sjl 			if (cntl & MAC_CNTL_PTRL_ADD_MAX) {
1549*25cf1a30Sjl 				mcp->mc_period++;
1550*25cf1a30Sjl 				MC_LOG("mc period %ld on "
1551*25cf1a30Sjl 				    "/LSB%d/B%d\n", mcp->mc_period,
1552*25cf1a30Sjl 				    mcp->mc_board_num, i);
1553*25cf1a30Sjl 				MAC_CLEAR_MAX(mcp, i);
1554*25cf1a30Sjl 			}
1555*25cf1a30Sjl 			if (mc_debug_show_all) {
1556*25cf1a30Sjl 				MC_LOG("/LSB%d/B%d stat %x cntl %x\n",
1557*25cf1a30Sjl 					mcp->mc_board_num, i,
1558*25cf1a30Sjl 					stat, cntl);
1559*25cf1a30Sjl 			}
1560*25cf1a30Sjl 			if (stat & (MAC_STAT_PTRL_ERRS|MAC_STAT_MI_ERRS)) {
1561*25cf1a30Sjl 				maddr_info.mi_valid = 0;
1562*25cf1a30Sjl 				maddr_info.mi_advance = 1;
1563*25cf1a30Sjl 				if (IS_MIRROR(mcp, i))
1564*25cf1a30Sjl 					mc_error_handler_mir(mcp, i,
1565*25cf1a30Sjl 						&maddr_info);
1566*25cf1a30Sjl 				else
1567*25cf1a30Sjl 					mc_error_handler(mcp, i, &maddr_info);
1568*25cf1a30Sjl 
1569*25cf1a30Sjl 				error_count++;
1570*25cf1a30Sjl 				restart_patrol(mcp, i, &maddr_info);
1571*25cf1a30Sjl 			} else {
1572*25cf1a30Sjl 				restart_patrol(mcp, i, NULL);
1573*25cf1a30Sjl 			}
1574*25cf1a30Sjl 		}
1575*25cf1a30Sjl 	}
1576*25cf1a30Sjl 	mc_process_scf_log(mcp);
1577*25cf1a30Sjl 	if (error_count > 0)
1578*25cf1a30Sjl 		mcp->mc_last_error += error_count;
1579*25cf1a30Sjl 	else
1580*25cf1a30Sjl 		mcp->mc_last_error = 0;
1581*25cf1a30Sjl }
1582*25cf1a30Sjl 
1583*25cf1a30Sjl /* this is just a wrapper for the above func */
1584*25cf1a30Sjl 
1585*25cf1a30Sjl static void
1586*25cf1a30Sjl mc_check_errors(void *arg)
1587*25cf1a30Sjl {
1588*25cf1a30Sjl 	mc_opl_t *mcp = (mc_opl_t *)arg;
1589*25cf1a30Sjl 	clock_t interval;
1590*25cf1a30Sjl 
1591*25cf1a30Sjl 	/*
1592*25cf1a30Sjl 	 * scan errors.
1593*25cf1a30Sjl 	 */
1594*25cf1a30Sjl 	mutex_enter(&mcp->mc_lock);
1595*25cf1a30Sjl 	mcp->mc_tid = 0;
1596*25cf1a30Sjl 	if ((mcp->mc_status & MC_POLL_RUNNING) &&
1597*25cf1a30Sjl 		!(mcp->mc_status & MC_SOFT_SUSPENDED)) {
1598*25cf1a30Sjl 		mc_check_errors_func(mcp);
1599*25cf1a30Sjl 
1600*25cf1a30Sjl 		if (mcp->mc_last_error > 0) {
1601*25cf1a30Sjl 			interval = (mcp->mc_interval_hz) >> mcp->mc_last_error;
1602*25cf1a30Sjl 			if (interval < 1)
1603*25cf1a30Sjl 				interval = 1;
1604*25cf1a30Sjl 		} else
1605*25cf1a30Sjl 			interval = mcp->mc_interval_hz;
1606*25cf1a30Sjl 
1607*25cf1a30Sjl 		mcp->mc_tid = timeout(mc_check_errors, mcp,
1608*25cf1a30Sjl 		    interval);
1609*25cf1a30Sjl 	}
1610*25cf1a30Sjl 	mutex_exit(&mcp->mc_lock);
1611*25cf1a30Sjl }
1612*25cf1a30Sjl 
1613*25cf1a30Sjl static void
1614*25cf1a30Sjl get_ptrl_start_address(mc_opl_t *mcp, int bank, mc_addr_t *maddr)
1615*25cf1a30Sjl {
1616*25cf1a30Sjl 	maddr->ma_bd = mcp->mc_board_num;
1617*25cf1a30Sjl 	maddr->ma_bank = bank;
1618*25cf1a30Sjl 	maddr->ma_dimm_addr = 0;
1619*25cf1a30Sjl }
1620*25cf1a30Sjl 
1621*25cf1a30Sjl typedef struct mc_mem_range {
1622*25cf1a30Sjl 	uint64_t	addr;
1623*25cf1a30Sjl 	uint64_t	size;
1624*25cf1a30Sjl } mc_mem_range_t;
1625*25cf1a30Sjl 
1626*25cf1a30Sjl static int
1627*25cf1a30Sjl get_base_address(mc_opl_t *mcp)
1628*25cf1a30Sjl {
1629*25cf1a30Sjl 	mc_mem_range_t *mem_range;
1630*25cf1a30Sjl 	int len;
1631*25cf1a30Sjl 
1632*25cf1a30Sjl 	if (ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS,
1633*25cf1a30Sjl 		"sb-mem-ranges", (caddr_t)&mem_range, &len) != DDI_SUCCESS) {
1634*25cf1a30Sjl 		return (DDI_FAILURE);
1635*25cf1a30Sjl 	}
1636*25cf1a30Sjl 
1637*25cf1a30Sjl 	mcp->mc_start_address = mem_range->addr;
1638*25cf1a30Sjl 	mcp->mc_size = mem_range->size;
1639*25cf1a30Sjl 
1640*25cf1a30Sjl 	kmem_free(mem_range, len);
1641*25cf1a30Sjl 	return (DDI_SUCCESS);
1642*25cf1a30Sjl }
1643*25cf1a30Sjl 
1644*25cf1a30Sjl struct mc_addr_spec {
1645*25cf1a30Sjl 	uint32_t bank;
1646*25cf1a30Sjl 	uint32_t phys_hi;
1647*25cf1a30Sjl 	uint32_t phys_lo;
1648*25cf1a30Sjl };
1649*25cf1a30Sjl 
1650*25cf1a30Sjl #define	REGS_PA(m, i) ((((uint64_t)m[i].phys_hi)<<32) | m[i].phys_lo)
1651*25cf1a30Sjl 
1652*25cf1a30Sjl static char *mc_tbl_name[] = {
1653*25cf1a30Sjl 	"cs0-mc-pa-trans-table",
1654*25cf1a30Sjl 	"cs1-mc-pa-trans-table"
1655*25cf1a30Sjl };
1656*25cf1a30Sjl 
1657*25cf1a30Sjl static int
1658*25cf1a30Sjl mc_valid_pa(mc_opl_t *mcp, uint64_t pa)
1659*25cf1a30Sjl {
1660*25cf1a30Sjl 	struct memlist *ml;
1661*25cf1a30Sjl 
1662*25cf1a30Sjl 	if (mcp->mlist == NULL)
1663*25cf1a30Sjl 		mc_get_mlist(mcp);
1664*25cf1a30Sjl 
1665*25cf1a30Sjl 	for (ml = mcp->mlist; ml; ml = ml->next) {
1666*25cf1a30Sjl 		if (ml->address <= pa && pa < (ml->address + ml->size))
1667*25cf1a30Sjl 			return (1);
1668*25cf1a30Sjl 	}
1669*25cf1a30Sjl 	return (0);
1670*25cf1a30Sjl }
1671*25cf1a30Sjl 
1672*25cf1a30Sjl static void
1673*25cf1a30Sjl mc_memlist_delete(struct memlist *mlist)
1674*25cf1a30Sjl {
1675*25cf1a30Sjl 	struct memlist *ml;
1676*25cf1a30Sjl 
1677*25cf1a30Sjl 	for (ml = mlist; ml; ml = mlist) {
1678*25cf1a30Sjl 		mlist = ml->next;
1679*25cf1a30Sjl 		kmem_free(ml, sizeof (struct memlist));
1680*25cf1a30Sjl 	}
1681*25cf1a30Sjl }
1682*25cf1a30Sjl 
1683*25cf1a30Sjl static struct memlist *
1684*25cf1a30Sjl mc_memlist_dup(struct memlist *mlist)
1685*25cf1a30Sjl {
1686*25cf1a30Sjl 	struct memlist *hl = NULL, *tl, **mlp;
1687*25cf1a30Sjl 
1688*25cf1a30Sjl 	if (mlist == NULL)
1689*25cf1a30Sjl 		return (NULL);
1690*25cf1a30Sjl 
1691*25cf1a30Sjl 	mlp = &hl;
1692*25cf1a30Sjl 	tl = *mlp;
1693*25cf1a30Sjl 	for (; mlist; mlist = mlist->next) {
1694*25cf1a30Sjl 		*mlp = kmem_alloc(sizeof (struct memlist), KM_SLEEP);
1695*25cf1a30Sjl 		(*mlp)->address = mlist->address;
1696*25cf1a30Sjl 		(*mlp)->size = mlist->size;
1697*25cf1a30Sjl 		(*mlp)->prev = tl;
1698*25cf1a30Sjl 		tl = *mlp;
1699*25cf1a30Sjl 		mlp = &((*mlp)->next);
1700*25cf1a30Sjl 	}
1701*25cf1a30Sjl 	*mlp = NULL;
1702*25cf1a30Sjl 
1703*25cf1a30Sjl 	return (hl);
1704*25cf1a30Sjl }
1705*25cf1a30Sjl 
1706*25cf1a30Sjl 
1707*25cf1a30Sjl static struct memlist *
1708*25cf1a30Sjl mc_memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len)
1709*25cf1a30Sjl {
1710*25cf1a30Sjl 	uint64_t	end;
1711*25cf1a30Sjl 	struct memlist	*ml, *tl, *nlp;
1712*25cf1a30Sjl 
1713*25cf1a30Sjl 	if (mlist == NULL)
1714*25cf1a30Sjl 		return (NULL);
1715*25cf1a30Sjl 
1716*25cf1a30Sjl 	end = base + len;
1717*25cf1a30Sjl 	if ((end <= mlist->address) || (base == end))
1718*25cf1a30Sjl 		return (mlist);
1719*25cf1a30Sjl 
1720*25cf1a30Sjl 	for (tl = ml = mlist; ml; tl = ml, ml = nlp) {
1721*25cf1a30Sjl 		uint64_t	mend;
1722*25cf1a30Sjl 
1723*25cf1a30Sjl 		nlp = ml->next;
1724*25cf1a30Sjl 
1725*25cf1a30Sjl 		if (end <= ml->address)
1726*25cf1a30Sjl 			break;
1727*25cf1a30Sjl 
1728*25cf1a30Sjl 		mend = ml->address + ml->size;
1729*25cf1a30Sjl 		if (base < mend) {
1730*25cf1a30Sjl 			if (base <= ml->address) {
1731*25cf1a30Sjl 				ml->address = end;
1732*25cf1a30Sjl 				if (end >= mend)
1733*25cf1a30Sjl 					ml->size = 0ull;
1734*25cf1a30Sjl 				else
1735*25cf1a30Sjl 					ml->size = mend - ml->address;
1736*25cf1a30Sjl 			} else {
1737*25cf1a30Sjl 				ml->size = base - ml->address;
1738*25cf1a30Sjl 				if (end < mend) {
1739*25cf1a30Sjl 					struct memlist	*nl;
1740*25cf1a30Sjl 					/*
1741*25cf1a30Sjl 					 * splitting an memlist entry.
1742*25cf1a30Sjl 					 */
1743*25cf1a30Sjl 					nl = kmem_alloc(sizeof (struct memlist),
1744*25cf1a30Sjl 						KM_SLEEP);
1745*25cf1a30Sjl 					nl->address = end;
1746*25cf1a30Sjl 					nl->size = mend - nl->address;
1747*25cf1a30Sjl 					if ((nl->next = nlp) != NULL)
1748*25cf1a30Sjl 						nlp->prev = nl;
1749*25cf1a30Sjl 					nl->prev = ml;
1750*25cf1a30Sjl 					ml->next = nl;
1751*25cf1a30Sjl 					nlp = nl;
1752*25cf1a30Sjl 				}
1753*25cf1a30Sjl 			}
1754*25cf1a30Sjl 			if (ml->size == 0ull) {
1755*25cf1a30Sjl 				if (ml == mlist) {
1756*25cf1a30Sjl 					if ((mlist = nlp) != NULL)
1757*25cf1a30Sjl 						nlp->prev = NULL;
1758*25cf1a30Sjl 					kmem_free(ml, sizeof (struct memlist));
1759*25cf1a30Sjl 					if (mlist == NULL)
1760*25cf1a30Sjl 						break;
1761*25cf1a30Sjl 					ml = nlp;
1762*25cf1a30Sjl 				} else {
1763*25cf1a30Sjl 					if ((tl->next = nlp) != NULL)
1764*25cf1a30Sjl 						nlp->prev = tl;
1765*25cf1a30Sjl 					kmem_free(ml, sizeof (struct memlist));
1766*25cf1a30Sjl 					ml = tl;
1767*25cf1a30Sjl 				}
1768*25cf1a30Sjl 			}
1769*25cf1a30Sjl 		}
1770*25cf1a30Sjl 	}
1771*25cf1a30Sjl 
1772*25cf1a30Sjl 	return (mlist);
1773*25cf1a30Sjl }
1774*25cf1a30Sjl 
1775*25cf1a30Sjl static void
1776*25cf1a30Sjl mc_get_mlist(mc_opl_t *mcp)
1777*25cf1a30Sjl {
1778*25cf1a30Sjl 	struct memlist *mlist;
1779*25cf1a30Sjl 
1780*25cf1a30Sjl 	memlist_read_lock();
1781*25cf1a30Sjl 	mlist = mc_memlist_dup(phys_install);
1782*25cf1a30Sjl 	memlist_read_unlock();
1783*25cf1a30Sjl 
1784*25cf1a30Sjl 	if (mlist) {
1785*25cf1a30Sjl 		mlist = mc_memlist_del_span(mlist, 0ull, mcp->mc_start_address);
1786*25cf1a30Sjl 	}
1787*25cf1a30Sjl 
1788*25cf1a30Sjl 	if (mlist) {
1789*25cf1a30Sjl 		uint64_t startpa, endpa;
1790*25cf1a30Sjl 
1791*25cf1a30Sjl 		startpa = mcp->mc_start_address + mcp->mc_size;
1792*25cf1a30Sjl 		endpa = ptob(physmax + 1);
1793*25cf1a30Sjl 		if (endpa > startpa) {
1794*25cf1a30Sjl 			mlist = mc_memlist_del_span(mlist,
1795*25cf1a30Sjl 				startpa, endpa - startpa);
1796*25cf1a30Sjl 		}
1797*25cf1a30Sjl 	}
1798*25cf1a30Sjl 
1799*25cf1a30Sjl 	if (mlist) {
1800*25cf1a30Sjl 		mcp->mlist = mlist;
1801*25cf1a30Sjl 	}
1802*25cf1a30Sjl }
1803*25cf1a30Sjl 
1804*25cf1a30Sjl int
1805*25cf1a30Sjl mc_board_add(mc_opl_t *mcp)
1806*25cf1a30Sjl {
1807*25cf1a30Sjl 	struct mc_addr_spec *macaddr;
1808*25cf1a30Sjl 	int len, i, bk, cc;
1809*25cf1a30Sjl 	mc_addr_info_t maddr;
1810*25cf1a30Sjl 	uint32_t mirr;
1811*25cf1a30Sjl 
1812*25cf1a30Sjl 	mutex_init(&mcp->mc_lock, NULL, MUTEX_DRIVER, NULL);
1813*25cf1a30Sjl 
1814*25cf1a30Sjl 	/*
1815*25cf1a30Sjl 	 * Get configurations from "pseudo-mc" node which includes:
1816*25cf1a30Sjl 	 * board# : LSB number
1817*25cf1a30Sjl 	 * mac-addr : physical base address of MAC registers
1818*25cf1a30Sjl 	 * csX-mac-pa-trans-table: translation table from DIMM address
1819*25cf1a30Sjl 	 *			to physical address or vice versa.
1820*25cf1a30Sjl 	 */
1821*25cf1a30Sjl 	mcp->mc_board_num = (int)ddi_getprop(DDI_DEV_T_ANY, mcp->mc_dip,
1822*25cf1a30Sjl 		DDI_PROP_DONTPASS, "board#", -1);
1823*25cf1a30Sjl 
1824*25cf1a30Sjl 	/*
1825*25cf1a30Sjl 	 * Get start address in this CAB. It can be gotten from
1826*25cf1a30Sjl 	 * "sb-mem-ranges" property.
1827*25cf1a30Sjl 	 */
1828*25cf1a30Sjl 
1829*25cf1a30Sjl 	if (get_base_address(mcp) == DDI_FAILURE) {
1830*25cf1a30Sjl 		mutex_destroy(&mcp->mc_lock);
1831*25cf1a30Sjl 		return (DDI_FAILURE);
1832*25cf1a30Sjl 	}
1833*25cf1a30Sjl 	/* get mac-pa trans tables */
1834*25cf1a30Sjl 	for (i = 0; i < MC_TT_CS; i++) {
1835*25cf1a30Sjl 		len = MC_TT_ENTRIES;
1836*25cf1a30Sjl 		cc = ddi_getlongprop_buf(DDI_DEV_T_ANY, mcp->mc_dip,
1837*25cf1a30Sjl 			DDI_PROP_DONTPASS, mc_tbl_name[i],
1838*25cf1a30Sjl 			(caddr_t)mcp->mc_trans_table[i], &len);
1839*25cf1a30Sjl 
1840*25cf1a30Sjl 		if (cc != DDI_SUCCESS) {
1841*25cf1a30Sjl 			bzero(mcp->mc_trans_table[i], MC_TT_ENTRIES);
1842*25cf1a30Sjl 		}
1843*25cf1a30Sjl 	}
1844*25cf1a30Sjl 	mcp->mlist = NULL;
1845*25cf1a30Sjl 
1846*25cf1a30Sjl 	mc_get_mlist(mcp);
1847*25cf1a30Sjl 
1848*25cf1a30Sjl 	/* initialize bank informations */
1849*25cf1a30Sjl 	cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS,
1850*25cf1a30Sjl 		"mc-addr", (caddr_t)&macaddr, &len);
1851*25cf1a30Sjl 	if (cc != DDI_SUCCESS) {
1852*25cf1a30Sjl 		cmn_err(CE_WARN, "Cannot get mc-addr. err=%d\n", cc);
1853*25cf1a30Sjl 		mutex_destroy(&mcp->mc_lock);
1854*25cf1a30Sjl 		return (DDI_FAILURE);
1855*25cf1a30Sjl 	}
1856*25cf1a30Sjl 
1857*25cf1a30Sjl 	for (i = 0; i < len / sizeof (struct mc_addr_spec); i++) {
1858*25cf1a30Sjl 		struct mc_bank *bankp;
1859*25cf1a30Sjl 		uint32_t reg;
1860*25cf1a30Sjl 
1861*25cf1a30Sjl 		/*
1862*25cf1a30Sjl 		 * setup bank
1863*25cf1a30Sjl 		 */
1864*25cf1a30Sjl 		bk = macaddr[i].bank;
1865*25cf1a30Sjl 		bankp = &(mcp->mc_bank[bk]);
1866*25cf1a30Sjl 		bankp->mcb_status = BANK_INSTALLED;
1867*25cf1a30Sjl 		bankp->mcb_reg_base = REGS_PA(macaddr, i);
1868*25cf1a30Sjl 
1869*25cf1a30Sjl 		reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bk));
1870*25cf1a30Sjl 		bankp->mcb_ptrl_cntl = (reg & MAC_CNTL_PTRL_PRESERVE_BITS);
1871*25cf1a30Sjl 
1872*25cf1a30Sjl 		/*
1873*25cf1a30Sjl 		 * check if mirror mode
1874*25cf1a30Sjl 		 */
1875*25cf1a30Sjl 		mirr = LD_MAC_REG(MAC_MIRR(mcp, bk));
1876*25cf1a30Sjl 
1877*25cf1a30Sjl 		if (mirr & MAC_MIRR_MIRROR_MODE) {
1878*25cf1a30Sjl 			MC_LOG("Mirror -> /LSB%d/B%d\n",
1879*25cf1a30Sjl 				mcp->mc_board_num, bk);
1880*25cf1a30Sjl 			bankp->mcb_status |= BANK_MIRROR_MODE;
1881*25cf1a30Sjl 			/*
1882*25cf1a30Sjl 			 * The following bit is only used for
1883*25cf1a30Sjl 			 * error injection.  We should clear it
1884*25cf1a30Sjl 			 */
1885*25cf1a30Sjl 			if (mirr & MAC_MIRR_BANK_EXCLUSIVE)
1886*25cf1a30Sjl 				ST_MAC_REG(MAC_MIRR(mcp, bk),
1887*25cf1a30Sjl 					0);
1888*25cf1a30Sjl 		}
1889*25cf1a30Sjl 
1890*25cf1a30Sjl 		/*
1891*25cf1a30Sjl 		 * restart if not mirror mode or the other bank
1892*25cf1a30Sjl 		 * of the mirror is not running
1893*25cf1a30Sjl 		 */
1894*25cf1a30Sjl 		if (!(mirr & MAC_MIRR_MIRROR_MODE) ||
1895*25cf1a30Sjl 			!(mcp->mc_bank[bk^1].mcb_status &
1896*25cf1a30Sjl 			BANK_PTRL_RUNNING)) {
1897*25cf1a30Sjl 			MC_LOG("Starting up /LSB%d/B%d\n",
1898*25cf1a30Sjl 				mcp->mc_board_num, bk);
1899*25cf1a30Sjl 			get_ptrl_start_address(mcp, bk, &maddr.mi_maddr);
1900*25cf1a30Sjl 			maddr.mi_valid = 1;
1901*25cf1a30Sjl 			maddr.mi_advance = 0;
1902*25cf1a30Sjl 			restart_patrol(mcp, bk, &maddr);
1903*25cf1a30Sjl 		} else {
1904*25cf1a30Sjl 			MC_LOG("Not starting up /LSB%d/B%d\n",
1905*25cf1a30Sjl 				mcp->mc_board_num, bk);
1906*25cf1a30Sjl 		}
1907*25cf1a30Sjl 		bankp->mcb_status |= BANK_PTRL_RUNNING;
1908*25cf1a30Sjl 	}
1909*25cf1a30Sjl 	kmem_free(macaddr, len);
1910*25cf1a30Sjl 
1911*25cf1a30Sjl 	/*
1912*25cf1a30Sjl 	 * set interval in HZ.
1913*25cf1a30Sjl 	 */
1914*25cf1a30Sjl 	for (i = 0; i < BANKNUM_PER_SB; i++) {
1915*25cf1a30Sjl 		mcp->mc_scf_retry[i] = 0;
1916*25cf1a30Sjl 	}
1917*25cf1a30Sjl 	mcp->mc_last_error = 0;
1918*25cf1a30Sjl 	mcp->mc_period = 0;
1919*25cf1a30Sjl 
1920*25cf1a30Sjl 	mcp->mc_interval_hz = drv_usectohz(mc_patrol_interval_sec * 1000000);
1921*25cf1a30Sjl 	/* restart memory patrol checking */
1922*25cf1a30Sjl 	mcp->mc_status |= MC_POLL_RUNNING;
1923*25cf1a30Sjl 	mcp->mc_tid = timeout(mc_check_errors, mcp, mcp->mc_interval_hz);
1924*25cf1a30Sjl 
1925*25cf1a30Sjl 	return (DDI_SUCCESS);
1926*25cf1a30Sjl }
1927*25cf1a30Sjl 
1928*25cf1a30Sjl int
1929*25cf1a30Sjl mc_board_del(mc_opl_t *mcp)
1930*25cf1a30Sjl {
1931*25cf1a30Sjl 	int i;
1932*25cf1a30Sjl 	scf_log_t *p;
1933*25cf1a30Sjl 	timeout_id_t tid = 0;
1934*25cf1a30Sjl 
1935*25cf1a30Sjl 	/*
1936*25cf1a30Sjl 	 * cleanup mac state
1937*25cf1a30Sjl 	 */
1938*25cf1a30Sjl 	mutex_enter(&mcp->mc_lock);
1939*25cf1a30Sjl 	for (i = 0; i < BANKNUM_PER_SB; i++) {
1940*25cf1a30Sjl 		if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
1941*25cf1a30Sjl 			if (mc_stop(mcp, i)) {
1942*25cf1a30Sjl 				mutex_exit(&mcp->mc_lock);
1943*25cf1a30Sjl 				return (-1);
1944*25cf1a30Sjl 			}
1945*25cf1a30Sjl 			mcp->mc_bank[i].mcb_status &= ~BANK_INSTALLED;
1946*25cf1a30Sjl 		}
1947*25cf1a30Sjl 	}
1948*25cf1a30Sjl 
1949*25cf1a30Sjl 	/* stop memory patrol checking */
1950*25cf1a30Sjl 	if (mcp->mc_status & MC_POLL_RUNNING) {
1951*25cf1a30Sjl 		mcp->mc_status &= ~MC_POLL_RUNNING;
1952*25cf1a30Sjl 		tid = mcp->mc_tid;
1953*25cf1a30Sjl 		mcp->mc_tid = 0;
1954*25cf1a30Sjl 	}
1955*25cf1a30Sjl 
1956*25cf1a30Sjl 	/* just throw away all the scf logs */
1957*25cf1a30Sjl 	while ((p = mcp->mc_scf_log) != NULL) {
1958*25cf1a30Sjl 		mcp->mc_scf_log = p->sl_next;
1959*25cf1a30Sjl 		mcp->mc_scf_total--;
1960*25cf1a30Sjl 		kmem_free(p, sizeof (scf_log_t));
1961*25cf1a30Sjl 	}
1962*25cf1a30Sjl 
1963*25cf1a30Sjl 	if (mcp->mlist)
1964*25cf1a30Sjl 		mc_memlist_delete(mcp->mlist);
1965*25cf1a30Sjl 
1966*25cf1a30Sjl 	mutex_exit(&mcp->mc_lock);
1967*25cf1a30Sjl 	if (tid)
1968*25cf1a30Sjl 		(void) untimeout(tid);
1969*25cf1a30Sjl 
1970*25cf1a30Sjl 	mutex_destroy(&mcp->mc_lock);
1971*25cf1a30Sjl 	return (DDI_SUCCESS);
1972*25cf1a30Sjl }
1973*25cf1a30Sjl 
1974*25cf1a30Sjl int
1975*25cf1a30Sjl mc_suspend(mc_opl_t *mcp, uint32_t flag)
1976*25cf1a30Sjl {
1977*25cf1a30Sjl 	timeout_id_t tid = 0;
1978*25cf1a30Sjl 	int i;
1979*25cf1a30Sjl 	/* stop memory patrol checking */
1980*25cf1a30Sjl 	mutex_enter(&mcp->mc_lock);
1981*25cf1a30Sjl 	if (mcp->mc_status & MC_POLL_RUNNING) {
1982*25cf1a30Sjl 		for (i = 0; i < BANKNUM_PER_SB; i++) {
1983*25cf1a30Sjl 			if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
1984*25cf1a30Sjl 				if (mc_stop(mcp, i)) {
1985*25cf1a30Sjl 					mutex_exit(&mcp->mc_lock);
1986*25cf1a30Sjl 					return (-1);
1987*25cf1a30Sjl 				}
1988*25cf1a30Sjl 			}
1989*25cf1a30Sjl 		}
1990*25cf1a30Sjl 		mcp->mc_status &= ~MC_POLL_RUNNING;
1991*25cf1a30Sjl 		tid = mcp->mc_tid;
1992*25cf1a30Sjl 	}
1993*25cf1a30Sjl 	mcp->mc_status |= flag;
1994*25cf1a30Sjl 	mcp->mc_tid = 0;
1995*25cf1a30Sjl 	mutex_exit(&mcp->mc_lock);
1996*25cf1a30Sjl 	if (tid)
1997*25cf1a30Sjl 		(void) untimeout(tid);
1998*25cf1a30Sjl 
1999*25cf1a30Sjl 	return (DDI_SUCCESS);
2000*25cf1a30Sjl }
2001*25cf1a30Sjl 
2002*25cf1a30Sjl /* caller must clear the SUSPEND bits or this will do nothing */
2003*25cf1a30Sjl 
2004*25cf1a30Sjl int
2005*25cf1a30Sjl mc_resume(mc_opl_t *mcp, uint32_t flag)
2006*25cf1a30Sjl {
2007*25cf1a30Sjl 	int i;
2008*25cf1a30Sjl 	uint64_t basepa;
2009*25cf1a30Sjl 
2010*25cf1a30Sjl 	mutex_enter(&mcp->mc_lock);
2011*25cf1a30Sjl 	basepa = mcp->mc_start_address;
2012*25cf1a30Sjl 	if (get_base_address(mcp) == DDI_FAILURE) {
2013*25cf1a30Sjl 		mutex_exit(&mcp->mc_lock);
2014*25cf1a30Sjl 		return (DDI_FAILURE);
2015*25cf1a30Sjl 	}
2016*25cf1a30Sjl 
2017*25cf1a30Sjl 	if (basepa != mcp->mc_start_address) {
2018*25cf1a30Sjl 		if (mcp->mlist)
2019*25cf1a30Sjl 			mc_memlist_delete(mcp->mlist);
2020*25cf1a30Sjl 		mcp->mlist = NULL;
2021*25cf1a30Sjl 		mc_get_mlist(mcp);
2022*25cf1a30Sjl 	}
2023*25cf1a30Sjl 
2024*25cf1a30Sjl 	mcp->mc_status &= ~flag;
2025*25cf1a30Sjl 	mcp->mc_list->mc_start_address = mcp->mc_start_address;
2026*25cf1a30Sjl 
2027*25cf1a30Sjl 	if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) {
2028*25cf1a30Sjl 		mutex_exit(&mcp->mc_lock);
2029*25cf1a30Sjl 		return (DDI_SUCCESS);
2030*25cf1a30Sjl 	}
2031*25cf1a30Sjl 
2032*25cf1a30Sjl 	if (!(mcp->mc_status & MC_POLL_RUNNING)) {
2033*25cf1a30Sjl 		/* restart memory patrol checking */
2034*25cf1a30Sjl 		mcp->mc_status |= MC_POLL_RUNNING;
2035*25cf1a30Sjl 		for (i = 0; i < BANKNUM_PER_SB; i++) {
2036*25cf1a30Sjl 			if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) {
2037*25cf1a30Sjl 				restart_patrol(mcp, i, NULL);
2038*25cf1a30Sjl 			}
2039*25cf1a30Sjl 		}
2040*25cf1a30Sjl 		/* check error asap */
2041*25cf1a30Sjl 		mcp->mc_tid = timeout(mc_check_errors, mcp, 1);
2042*25cf1a30Sjl 	}
2043*25cf1a30Sjl 	mutex_exit(&mcp->mc_lock);
2044*25cf1a30Sjl 
2045*25cf1a30Sjl 	return (DDI_SUCCESS);
2046*25cf1a30Sjl }
2047*25cf1a30Sjl 
2048*25cf1a30Sjl static mc_opl_t *
2049*25cf1a30Sjl mc_pa_to_mcp(uint64_t pa)
2050*25cf1a30Sjl {
2051*25cf1a30Sjl 	mc_inst_list_t *p;
2052*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&mcmutex));
2053*25cf1a30Sjl 	for (p = mc_instances; p; p = p->next) {
2054*25cf1a30Sjl 		/* if mac patrol is suspended, we cannot rely on it */
2055*25cf1a30Sjl 		if (!(p->mc_opl->mc_status & MC_POLL_RUNNING) ||
2056*25cf1a30Sjl 			(p->mc_opl->mc_status & MC_SOFT_SUSPENDED))
2057*25cf1a30Sjl 			continue;
2058*25cf1a30Sjl 		if ((p->mc_start_address <= pa) &&
2059*25cf1a30Sjl 			(pa < (p->mc_start_address + p->mc_size))) {
2060*25cf1a30Sjl 			return (p->mc_opl);
2061*25cf1a30Sjl 		}
2062*25cf1a30Sjl 	}
2063*25cf1a30Sjl 	return (NULL);
2064*25cf1a30Sjl }
2065*25cf1a30Sjl 
2066*25cf1a30Sjl /*
2067*25cf1a30Sjl  * Get Physical Board number from Logical one.
2068*25cf1a30Sjl  */
2069*25cf1a30Sjl static int
2070*25cf1a30Sjl mc_opl_get_physical_board(int sb)
2071*25cf1a30Sjl {
2072*25cf1a30Sjl 	if (&opl_get_physical_board) {
2073*25cf1a30Sjl 		return (opl_get_physical_board(sb));
2074*25cf1a30Sjl 	}
2075*25cf1a30Sjl 
2076*25cf1a30Sjl 	cmn_err(CE_NOTE, "!opl_get_physical_board() not loaded\n");
2077*25cf1a30Sjl 	return (-1);
2078*25cf1a30Sjl }
2079*25cf1a30Sjl 
2080*25cf1a30Sjl /* ARGSUSED */
2081*25cf1a30Sjl int
2082*25cf1a30Sjl mc_get_mem_unum(int synd_code, uint64_t flt_addr, char *buf, int buflen,
2083*25cf1a30Sjl 	int *lenp)
2084*25cf1a30Sjl {
2085*25cf1a30Sjl 	mc_opl_t *mcp;
2086*25cf1a30Sjl 	int bank;
2087*25cf1a30Sjl 	int sb;
2088*25cf1a30Sjl 
2089*25cf1a30Sjl 	mutex_enter(&mcmutex);
2090*25cf1a30Sjl 
2091*25cf1a30Sjl 	if (((mcp = mc_pa_to_mcp(flt_addr)) == NULL) ||
2092*25cf1a30Sjl 		(!pa_is_valid(mcp, flt_addr))) {
2093*25cf1a30Sjl 		mutex_exit(&mcmutex);
2094*25cf1a30Sjl 		if (snprintf(buf, buflen, "UNKNOWN") >= buflen) {
2095*25cf1a30Sjl 			return (ENOSPC);
2096*25cf1a30Sjl 		} else {
2097*25cf1a30Sjl 			if (lenp)
2098*25cf1a30Sjl 				*lenp = strlen(buf);
2099*25cf1a30Sjl 		}
2100*25cf1a30Sjl 		return (0);
2101*25cf1a30Sjl 	}
2102*25cf1a30Sjl 
2103*25cf1a30Sjl 	bank = pa_to_bank(mcp, flt_addr - mcp->mc_start_address);
2104*25cf1a30Sjl 	sb = mc_opl_get_physical_board(mcp->mc_board_num);
2105*25cf1a30Sjl 
2106*25cf1a30Sjl 	if (sb == -1) {
2107*25cf1a30Sjl 		mutex_exit(&mcmutex);
2108*25cf1a30Sjl 		return (ENXIO);
2109*25cf1a30Sjl 	}
2110*25cf1a30Sjl 
2111*25cf1a30Sjl 	if (snprintf(buf, buflen, "/CMU%d/B%d", sb, bank) >= buflen) {
2112*25cf1a30Sjl 		mutex_exit(&mcmutex);
2113*25cf1a30Sjl 		return (ENOSPC);
2114*25cf1a30Sjl 	} else {
2115*25cf1a30Sjl 		if (lenp)
2116*25cf1a30Sjl 			*lenp = strlen(buf);
2117*25cf1a30Sjl 	}
2118*25cf1a30Sjl 	mutex_exit(&mcmutex);
2119*25cf1a30Sjl 	return (0);
2120*25cf1a30Sjl }
2121*25cf1a30Sjl 
2122*25cf1a30Sjl int
2123*25cf1a30Sjl opl_mc_suspend()
2124*25cf1a30Sjl {
2125*25cf1a30Sjl 	mc_opl_t *mcp;
2126*25cf1a30Sjl 	mc_inst_list_t *p;
2127*25cf1a30Sjl 
2128*25cf1a30Sjl 	mutex_enter(&mcmutex);
2129*25cf1a30Sjl 
2130*25cf1a30Sjl 	for (p = mc_instances; p; p = p->next) {
2131*25cf1a30Sjl 		mcp = p->mc_opl;
2132*25cf1a30Sjl 		(void) mc_suspend(mcp, MC_SOFT_SUSPENDED);
2133*25cf1a30Sjl 	}
2134*25cf1a30Sjl 
2135*25cf1a30Sjl 	mutex_exit(&mcmutex);
2136*25cf1a30Sjl 	return (0);
2137*25cf1a30Sjl }
2138*25cf1a30Sjl 
2139*25cf1a30Sjl int
2140*25cf1a30Sjl opl_mc_resume()
2141*25cf1a30Sjl {
2142*25cf1a30Sjl 	mc_opl_t *mcp;
2143*25cf1a30Sjl 	mc_inst_list_t *p;
2144*25cf1a30Sjl 
2145*25cf1a30Sjl 	mutex_enter(&mcmutex);
2146*25cf1a30Sjl 
2147*25cf1a30Sjl 	for (p = mc_instances; p; p = p->next) {
2148*25cf1a30Sjl 		mcp = p->mc_opl;
2149*25cf1a30Sjl 		(void) mc_resume(mcp, MC_SOFT_SUSPENDED);
2150*25cf1a30Sjl 	}
2151*25cf1a30Sjl 
2152*25cf1a30Sjl 	mutex_exit(&mcmutex);
2153*25cf1a30Sjl 	return (0);
2154*25cf1a30Sjl }
2155*25cf1a30Sjl 
2156*25cf1a30Sjl static void
2157*25cf1a30Sjl insert_mcp(mc_opl_t *mcp)
2158*25cf1a30Sjl {
2159*25cf1a30Sjl 	mc_inst_list_t	*p;
2160*25cf1a30Sjl 
2161*25cf1a30Sjl 	p = kmem_zalloc(sizeof (mc_inst_list_t), KM_SLEEP);
2162*25cf1a30Sjl 	p->mc_opl = mcp;
2163*25cf1a30Sjl 	p->mc_board_num = mcp->mc_board_num;
2164*25cf1a30Sjl 	p->mc_start_address = mcp->mc_start_address;
2165*25cf1a30Sjl 	p->mc_size = mcp->mc_size;
2166*25cf1a30Sjl 	mcp->mc_list = p;
2167*25cf1a30Sjl 
2168*25cf1a30Sjl 	mutex_enter(&mcmutex);
2169*25cf1a30Sjl 
2170*25cf1a30Sjl 	p->next = mc_instances;
2171*25cf1a30Sjl 	mc_instances = p;
2172*25cf1a30Sjl 
2173*25cf1a30Sjl 	mutex_exit(&mcmutex);
2174*25cf1a30Sjl }
2175*25cf1a30Sjl 
2176*25cf1a30Sjl static void
2177*25cf1a30Sjl delete_mcp(mc_opl_t *mcp)
2178*25cf1a30Sjl {
2179*25cf1a30Sjl 	mc_inst_list_t *prev, *current;
2180*25cf1a30Sjl 	mc_inst_list_t *p;
2181*25cf1a30Sjl 
2182*25cf1a30Sjl 	p = mcp->mc_list;
2183*25cf1a30Sjl 
2184*25cf1a30Sjl 	if (mc_instances == p) {
2185*25cf1a30Sjl 		mc_instances = p->next;
2186*25cf1a30Sjl 		kmem_free(p, sizeof (mc_inst_list_t));
2187*25cf1a30Sjl 		return;
2188*25cf1a30Sjl 	}
2189*25cf1a30Sjl 	prev = mc_instances;
2190*25cf1a30Sjl 	for (current = mc_instances; current != NULL; current = current->next) {
2191*25cf1a30Sjl 		if (current == p) {
2192*25cf1a30Sjl 			prev->next = p->next;
2193*25cf1a30Sjl 			kmem_free(p, sizeof (mc_inst_list_t));
2194*25cf1a30Sjl 			return;
2195*25cf1a30Sjl 		}
2196*25cf1a30Sjl 		prev = current;
2197*25cf1a30Sjl 	}
2198*25cf1a30Sjl }
2199*25cf1a30Sjl 
2200*25cf1a30Sjl /* Error injection interface */
2201*25cf1a30Sjl 
2202*25cf1a30Sjl /* ARGSUSED */
2203*25cf1a30Sjl int
2204*25cf1a30Sjl mc_inject_error(int error_type, uint64_t pa, uint32_t flags)
2205*25cf1a30Sjl {
2206*25cf1a30Sjl 	mc_opl_t *mcp;
2207*25cf1a30Sjl 	int bank;
2208*25cf1a30Sjl 	uint32_t dimm_addr;
2209*25cf1a30Sjl 	uint32_t cntl;
2210*25cf1a30Sjl 	mc_addr_info_t maddr;
2211*25cf1a30Sjl 	uint32_t data, stat;
2212*25cf1a30Sjl 	int both_sides = 0;
2213*25cf1a30Sjl 	uint64_t pa0;
2214*25cf1a30Sjl 	on_trap_data_t otd;
2215*25cf1a30Sjl 	extern void cpu_flush_ecache(void);
2216*25cf1a30Sjl 
2217*25cf1a30Sjl 	MC_LOG("HW mc_inject_error(%x, %lx, %x)\n", error_type, pa, flags);
2218*25cf1a30Sjl 
2219*25cf1a30Sjl 	mutex_enter(&mcmutex);
2220*25cf1a30Sjl 
2221*25cf1a30Sjl 	if ((mcp = mc_pa_to_mcp(pa)) == NULL) {
2222*25cf1a30Sjl 		mutex_exit(&mcmutex);
2223*25cf1a30Sjl 		MC_LOG("mc_inject_error: invalid pa\n");
2224*25cf1a30Sjl 		return (ENOTSUP);
2225*25cf1a30Sjl 	}
2226*25cf1a30Sjl 
2227*25cf1a30Sjl 	mutex_enter(&mcp->mc_lock);
2228*25cf1a30Sjl 	mutex_exit(&mcmutex);
2229*25cf1a30Sjl 
2230*25cf1a30Sjl 	if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) {
2231*25cf1a30Sjl 		mutex_exit(&mcp->mc_lock);
2232*25cf1a30Sjl 		MC_LOG("mc-opl has been suspended.  No error injection.\n");
2233*25cf1a30Sjl 		return (EBUSY);
2234*25cf1a30Sjl 	}
2235*25cf1a30Sjl 
2236*25cf1a30Sjl 	/* convert pa to offset within the board */
2237*25cf1a30Sjl 	MC_LOG("pa %lx, offset %lx\n", pa, pa - mcp->mc_start_address);
2238*25cf1a30Sjl 
2239*25cf1a30Sjl 	if (!pa_is_valid(mcp, pa)) {
2240*25cf1a30Sjl 		mutex_exit(&mcp->mc_lock);
2241*25cf1a30Sjl 		return (EINVAL);
2242*25cf1a30Sjl 	}
2243*25cf1a30Sjl 
2244*25cf1a30Sjl 	pa0 = pa - mcp->mc_start_address;
2245*25cf1a30Sjl 
2246*25cf1a30Sjl 	bank = pa_to_bank(mcp, pa0);
2247*25cf1a30Sjl 
2248*25cf1a30Sjl 	if (flags & MC_INJECT_FLAG_OTHER)
2249*25cf1a30Sjl 		bank = bank ^ 1;
2250*25cf1a30Sjl 
2251*25cf1a30Sjl 	if (MC_INJECT_MIRROR(error_type) && !IS_MIRROR(mcp, bank)) {
2252*25cf1a30Sjl 		mutex_exit(&mcp->mc_lock);
2253*25cf1a30Sjl 		MC_LOG("Not mirror mode\n");
2254*25cf1a30Sjl 		return (EINVAL);
2255*25cf1a30Sjl 	}
2256*25cf1a30Sjl 
2257*25cf1a30Sjl 	dimm_addr = pa_to_dimm(mcp, pa0);
2258*25cf1a30Sjl 
2259*25cf1a30Sjl 	MC_LOG("injecting error to /LSB%d/B%d/D%x\n",
2260*25cf1a30Sjl 		mcp->mc_board_num, bank, dimm_addr);
2261*25cf1a30Sjl 
2262*25cf1a30Sjl 
2263*25cf1a30Sjl 	switch (error_type) {
2264*25cf1a30Sjl 	case MC_INJECT_INTERMITTENT_MCE:
2265*25cf1a30Sjl 	case MC_INJECT_PERMANENT_MCE:
2266*25cf1a30Sjl 	case MC_INJECT_MUE:
2267*25cf1a30Sjl 		both_sides = 1;
2268*25cf1a30Sjl 	}
2269*25cf1a30Sjl 
2270*25cf1a30Sjl 	if (flags & MC_INJECT_FLAG_RESET)
2271*25cf1a30Sjl 		ST_MAC_REG(MAC_EG_CNTL(mcp, bank), 0);
2272*25cf1a30Sjl 
2273*25cf1a30Sjl 	ST_MAC_REG(MAC_EG_ADD(mcp, bank), dimm_addr & MAC_EG_ADD_MASK);
2274*25cf1a30Sjl 
2275*25cf1a30Sjl 	if (both_sides) {
2276*25cf1a30Sjl 		ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), 0);
2277*25cf1a30Sjl 		ST_MAC_REG(MAC_EG_ADD(mcp, bank^1),
2278*25cf1a30Sjl 			dimm_addr & MAC_EG_ADD_MASK);
2279*25cf1a30Sjl 	}
2280*25cf1a30Sjl 
2281*25cf1a30Sjl 	switch (error_type) {
2282*25cf1a30Sjl 	case MC_INJECT_UE:
2283*25cf1a30Sjl 	case MC_INJECT_SUE:
2284*25cf1a30Sjl 	case MC_INJECT_MUE:
2285*25cf1a30Sjl 		if (flags & MC_INJECT_FLAG_PATH) {
2286*25cf1a30Sjl 			cntl = MAC_EG_ADD_FIX
2287*25cf1a30Sjl 				|MAC_EG_FORCE_READ00|MAC_EG_FORCE_READ16
2288*25cf1a30Sjl 				|MAC_EG_DERR_ONCE;
2289*25cf1a30Sjl 		} else {
2290*25cf1a30Sjl 			cntl = MAC_EG_ADD_FIX|MAC_EG_FORCE_DERR00
2291*25cf1a30Sjl 				|MAC_EG_FORCE_DERR16|MAC_EG_DERR_ONCE;
2292*25cf1a30Sjl 		}
2293*25cf1a30Sjl 		flags |= MC_INJECT_FLAG_ST;
2294*25cf1a30Sjl 		break;
2295*25cf1a30Sjl 	case MC_INJECT_INTERMITTENT_CE:
2296*25cf1a30Sjl 	case MC_INJECT_INTERMITTENT_MCE:
2297*25cf1a30Sjl 		if (flags & MC_INJECT_FLAG_PATH) {
2298*25cf1a30Sjl 			cntl = MAC_EG_ADD_FIX
2299*25cf1a30Sjl 				|MAC_EG_FORCE_READ00
2300*25cf1a30Sjl 				|MAC_EG_DERR_ONCE;
2301*25cf1a30Sjl 		} else {
2302*25cf1a30Sjl 			cntl = MAC_EG_ADD_FIX
2303*25cf1a30Sjl 				|MAC_EG_FORCE_DERR16
2304*25cf1a30Sjl 				|MAC_EG_DERR_ONCE;
2305*25cf1a30Sjl 		}
2306*25cf1a30Sjl 		flags |= MC_INJECT_FLAG_ST;
2307*25cf1a30Sjl 		break;
2308*25cf1a30Sjl 	case MC_INJECT_PERMANENT_CE:
2309*25cf1a30Sjl 	case MC_INJECT_PERMANENT_MCE:
2310*25cf1a30Sjl 		if (flags & MC_INJECT_FLAG_PATH) {
2311*25cf1a30Sjl 			cntl = MAC_EG_ADD_FIX
2312*25cf1a30Sjl 				|MAC_EG_FORCE_READ00
2313*25cf1a30Sjl 				|MAC_EG_DERR_ALWAYS;
2314*25cf1a30Sjl 		} else {
2315*25cf1a30Sjl 			cntl = MAC_EG_ADD_FIX
2316*25cf1a30Sjl 				|MAC_EG_FORCE_DERR16
2317*25cf1a30Sjl 				|MAC_EG_DERR_ALWAYS;
2318*25cf1a30Sjl 		}
2319*25cf1a30Sjl 		flags |= MC_INJECT_FLAG_ST;
2320*25cf1a30Sjl 		break;
2321*25cf1a30Sjl 	case MC_INJECT_CMPE:
2322*25cf1a30Sjl 		data = 0xabcdefab;
2323*25cf1a30Sjl 		stphys(pa, data);
2324*25cf1a30Sjl 		cpu_flush_ecache();
2325*25cf1a30Sjl 		MC_LOG("CMPE: writing data %x to %lx\n", data, pa);
2326*25cf1a30Sjl 		ST_MAC_REG(MAC_MIRR(mcp, bank), MAC_MIRR_BANK_EXCLUSIVE);
2327*25cf1a30Sjl 		stphys(pa, data ^ 0xffffffff);
2328*25cf1a30Sjl 		cpu_flush_ecache();
2329*25cf1a30Sjl 		ST_MAC_REG(MAC_MIRR(mcp, bank), 0);
2330*25cf1a30Sjl 		MC_LOG("CMPE: write new data %xto %lx\n", data, pa);
2331*25cf1a30Sjl 		cntl = 0;
2332*25cf1a30Sjl 		break;
2333*25cf1a30Sjl 	case MC_INJECT_NOP:
2334*25cf1a30Sjl 		cntl = 0;
2335*25cf1a30Sjl 		break;
2336*25cf1a30Sjl 	default:
2337*25cf1a30Sjl 		MC_LOG("mc_inject_error: invalid option\n");
2338*25cf1a30Sjl 		cntl = 0;
2339*25cf1a30Sjl 	}
2340*25cf1a30Sjl 
2341*25cf1a30Sjl 	if (cntl) {
2342*25cf1a30Sjl 		ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl & MAC_EG_SETUP_MASK);
2343*25cf1a30Sjl 		ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl);
2344*25cf1a30Sjl 
2345*25cf1a30Sjl 		if (both_sides) {
2346*25cf1a30Sjl 			ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl &
2347*25cf1a30Sjl 				MAC_EG_SETUP_MASK);
2348*25cf1a30Sjl 			ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl);
2349*25cf1a30Sjl 		}
2350*25cf1a30Sjl 	}
2351*25cf1a30Sjl 
2352*25cf1a30Sjl 	/*
2353*25cf1a30Sjl 	 * For all injection cases except compare error, we
2354*25cf1a30Sjl 	 * must write to the PA to trigger the error.
2355*25cf1a30Sjl 	 */
2356*25cf1a30Sjl 
2357*25cf1a30Sjl 	if (flags & MC_INJECT_FLAG_ST) {
2358*25cf1a30Sjl 		data = 0xf0e0d0c0;
2359*25cf1a30Sjl 		MC_LOG("Writing %x to %lx\n", data, pa);
2360*25cf1a30Sjl 		stphys(pa, data);
2361*25cf1a30Sjl 		cpu_flush_ecache();
2362*25cf1a30Sjl 	}
2363*25cf1a30Sjl 
2364*25cf1a30Sjl 	delay(inject_op_delay * drv_usectohz(1000 * 1000));
2365*25cf1a30Sjl 
2366*25cf1a30Sjl 
2367*25cf1a30Sjl 	if (flags & MC_INJECT_FLAG_LD) {
2368*25cf1a30Sjl 		if (flags & MC_INJECT_FLAG_NO_TRAP) {
2369*25cf1a30Sjl 			if (on_trap(&otd, OT_DATA_EC)) {
2370*25cf1a30Sjl 				no_trap();
2371*25cf1a30Sjl 				MC_LOG("Trap occurred\n");
2372*25cf1a30Sjl 			} else {
2373*25cf1a30Sjl 				MC_LOG("On-trap Reading from %lx\n", pa);
2374*25cf1a30Sjl 				data = ldphys(pa);
2375*25cf1a30Sjl 				no_trap();
2376*25cf1a30Sjl 				MC_LOG("data = %x\n", data);
2377*25cf1a30Sjl 			}
2378*25cf1a30Sjl 		} else {
2379*25cf1a30Sjl 			MC_LOG("Reading from %lx\n", pa);
2380*25cf1a30Sjl 			data = ldphys(pa);
2381*25cf1a30Sjl 			MC_LOG("data = %x\n", data);
2382*25cf1a30Sjl 		}
2383*25cf1a30Sjl 	}
2384*25cf1a30Sjl 
2385*25cf1a30Sjl 	if (flags & MC_INJECT_FLAG_RESTART) {
2386*25cf1a30Sjl 		delay(inject_op_delay * drv_usectohz(1000 * 1000));
2387*25cf1a30Sjl 
2388*25cf1a30Sjl 		MC_LOG("Restart patrol\n");
2389*25cf1a30Sjl 		if (mc_stop(mcp, bank)) {
2390*25cf1a30Sjl 			cmn_err(CE_WARN, "Cannot stop Memory Patrol at "
2391*25cf1a30Sjl 				"/LSB%d/B%d\n", mcp->mc_board_num, bank);
2392*25cf1a30Sjl 			mutex_exit(&mcp->mc_lock);
2393*25cf1a30Sjl 			return (EIO);
2394*25cf1a30Sjl 		}
2395*25cf1a30Sjl 		maddr.mi_maddr.ma_bd = mcp->mc_board_num;
2396*25cf1a30Sjl 		maddr.mi_maddr.ma_bank = bank;
2397*25cf1a30Sjl 		maddr.mi_maddr.ma_dimm_addr = dimm_addr;
2398*25cf1a30Sjl 		maddr.mi_valid = 1;
2399*25cf1a30Sjl 		maddr.mi_advance = 0;
2400*25cf1a30Sjl 		restart_patrol(mcp, bank, &maddr);
2401*25cf1a30Sjl 	}
2402*25cf1a30Sjl 
2403*25cf1a30Sjl 	if (flags & MC_INJECT_FLAG_POLL) {
2404*25cf1a30Sjl 		delay(inject_op_delay * drv_usectohz(1000 * 1000));
2405*25cf1a30Sjl 
2406*25cf1a30Sjl 		MC_LOG("Poll patrol error\n");
2407*25cf1a30Sjl 		stat = LD_MAC_REG(MAC_PTRL_STAT(mcp, bank));
2408*25cf1a30Sjl 		cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank));
2409*25cf1a30Sjl 		if (stat & (MAC_STAT_PTRL_ERRS|MAC_STAT_MI_ERRS)) {
2410*25cf1a30Sjl 			maddr.mi_valid = 0;
2411*25cf1a30Sjl 			maddr.mi_advance = 1;
2412*25cf1a30Sjl 			if (IS_MIRROR(mcp, bank))
2413*25cf1a30Sjl 				mc_error_handler_mir(mcp, bank,
2414*25cf1a30Sjl 					&maddr);
2415*25cf1a30Sjl 			else
2416*25cf1a30Sjl 				mc_error_handler(mcp, bank, &maddr);
2417*25cf1a30Sjl 
2418*25cf1a30Sjl 			restart_patrol(mcp, bank, &maddr);
2419*25cf1a30Sjl 		} else
2420*25cf1a30Sjl 			restart_patrol(mcp, bank, NULL);
2421*25cf1a30Sjl 	}
2422*25cf1a30Sjl 
2423*25cf1a30Sjl 	mutex_exit(&mcp->mc_lock);
2424*25cf1a30Sjl 	return (0);
2425*25cf1a30Sjl }
2426*25cf1a30Sjl 
2427*25cf1a30Sjl void
2428*25cf1a30Sjl mc_stphysio(uint64_t pa, uint32_t data)
2429*25cf1a30Sjl {
2430*25cf1a30Sjl 	MC_LOG("0x%x -> pa(%lx)\n", data, pa);
2431*25cf1a30Sjl 	stphysio(pa, data);
2432*25cf1a30Sjl }
2433*25cf1a30Sjl 
2434*25cf1a30Sjl uint32_t
2435*25cf1a30Sjl mc_ldphysio(uint64_t pa)
2436*25cf1a30Sjl {
2437*25cf1a30Sjl 	uint32_t rv;
2438*25cf1a30Sjl 
2439*25cf1a30Sjl 	rv = ldphysio(pa);
2440*25cf1a30Sjl 	MC_LOG("pa(%lx) = 0x%x\n", pa, rv);
2441*25cf1a30Sjl 	return (rv);
2442*25cf1a30Sjl }
2443