xref: /onnv-gate/usr/src/uts/sun4u/io/mc-us3i.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/conf.h>
31*0Sstevel@tonic-gate #include <sys/ddi.h>
32*0Sstevel@tonic-gate #include <sys/stat.h>
33*0Sstevel@tonic-gate #include <sys/sunddi.h>
34*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
35*0Sstevel@tonic-gate #include <sys/obpdefs.h>
36*0Sstevel@tonic-gate #include <sys/cmn_err.h>
37*0Sstevel@tonic-gate #include <sys/errno.h>
38*0Sstevel@tonic-gate #include <sys/kmem.h>
39*0Sstevel@tonic-gate #include <sys/open.h>
40*0Sstevel@tonic-gate #include <sys/thread.h>
41*0Sstevel@tonic-gate #include <sys/cpuvar.h>
42*0Sstevel@tonic-gate #include <sys/x_call.h>
43*0Sstevel@tonic-gate #include <sys/debug.h>
44*0Sstevel@tonic-gate #include <sys/sysmacros.h>
45*0Sstevel@tonic-gate #include <sys/ivintr.h>
46*0Sstevel@tonic-gate #include <sys/intr.h>
47*0Sstevel@tonic-gate #include <sys/intreg.h>
48*0Sstevel@tonic-gate #include <sys/autoconf.h>
49*0Sstevel@tonic-gate #include <sys/modctl.h>
50*0Sstevel@tonic-gate #include <sys/spl.h>
51*0Sstevel@tonic-gate #include <sys/async.h>
52*0Sstevel@tonic-gate #include <sys/mc.h>
53*0Sstevel@tonic-gate #include <sys/mc-us3i.h>
54*0Sstevel@tonic-gate #include <sys/note.h>
55*0Sstevel@tonic-gate #include <sys/cpu_module.h>
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate /*
58*0Sstevel@tonic-gate  * pm-hardware-state value
59*0Sstevel@tonic-gate  */
60*0Sstevel@tonic-gate #define	NO_SUSPEND_RESUME	"no-suspend-resume"
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate /*
63*0Sstevel@tonic-gate  * Function prototypes
64*0Sstevel@tonic-gate  */
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate static int mc_open(dev_t *, int, int, cred_t *);
67*0Sstevel@tonic-gate static int mc_close(dev_t, int, int, cred_t *);
68*0Sstevel@tonic-gate static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
69*0Sstevel@tonic-gate static int mc_attach(dev_info_t *, ddi_attach_cmd_t);
70*0Sstevel@tonic-gate static int mc_detach(dev_info_t *, ddi_detach_cmd_t);
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * Configuration data structures
74*0Sstevel@tonic-gate  */
75*0Sstevel@tonic-gate static struct cb_ops mc_cb_ops = {
76*0Sstevel@tonic-gate 	mc_open,			/* open */
77*0Sstevel@tonic-gate 	mc_close,			/* close */
78*0Sstevel@tonic-gate 	nulldev,			/* strategy */
79*0Sstevel@tonic-gate 	nulldev,			/* print */
80*0Sstevel@tonic-gate 	nodev,				/* dump */
81*0Sstevel@tonic-gate 	nulldev,			/* read */
82*0Sstevel@tonic-gate 	nulldev,			/* write */
83*0Sstevel@tonic-gate 	mc_ioctl,			/* ioctl */
84*0Sstevel@tonic-gate 	nodev,				/* devmap */
85*0Sstevel@tonic-gate 	nodev,				/* mmap */
86*0Sstevel@tonic-gate 	nodev,				/* segmap */
87*0Sstevel@tonic-gate 	nochpoll,			/* poll */
88*0Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
89*0Sstevel@tonic-gate 	0,				/* streamtab */
90*0Sstevel@tonic-gate 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
91*0Sstevel@tonic-gate 	CB_REV,				/* rev */
92*0Sstevel@tonic-gate 	nodev,				/* cb_aread */
93*0Sstevel@tonic-gate 	nodev				/* cb_awrite */
94*0Sstevel@tonic-gate };
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate static struct dev_ops mc_ops = {
97*0Sstevel@tonic-gate 	DEVO_REV,			/* rev */
98*0Sstevel@tonic-gate 	0,				/* refcnt  */
99*0Sstevel@tonic-gate 	ddi_no_info,			/* getinfo */
100*0Sstevel@tonic-gate 	nulldev,			/* identify */
101*0Sstevel@tonic-gate 	nulldev,			/* probe */
102*0Sstevel@tonic-gate 	mc_attach,			/* attach */
103*0Sstevel@tonic-gate 	mc_detach,			/* detach */
104*0Sstevel@tonic-gate 	nulldev,			/* reset */
105*0Sstevel@tonic-gate 	&mc_cb_ops,			/* cb_ops */
106*0Sstevel@tonic-gate 	(struct bus_ops *)0,		/* bus_ops */
107*0Sstevel@tonic-gate 	nulldev				/* power */
108*0Sstevel@tonic-gate };
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate /*
111*0Sstevel@tonic-gate  * Driver globals
112*0Sstevel@tonic-gate  */
113*0Sstevel@tonic-gate static void *mcp;
114*0Sstevel@tonic-gate static int nmcs = 0;
115*0Sstevel@tonic-gate static int seg_id;
116*0Sstevel@tonic-gate static int nsegments;
117*0Sstevel@tonic-gate static uint64_t	memsize;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate static uint_t	mc_debug = 0;
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate static int getreg;
122*0Sstevel@tonic-gate static int nregs;
123*0Sstevel@tonic-gate struct memory_reg_info *reg_info;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate static mc_dlist_t *seg_head, *seg_tail, *bank_head, *bank_tail;
126*0Sstevel@tonic-gate static mc_dlist_t *mctrl_head, *mctrl_tail, *dgrp_head, *dgrp_tail;
127*0Sstevel@tonic-gate static mc_dlist_t *device_head, *device_tail;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate static kmutex_t	mcmutex;
130*0Sstevel@tonic-gate static kmutex_t	mcdatamutex;
131*0Sstevel@tonic-gate static int mc_is_open = 0;
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate extern struct mod_ops mod_driverops;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate static struct modldrv modldrv = {
136*0Sstevel@tonic-gate 	&mod_driverops,			/* module type, this one is a driver */
137*0Sstevel@tonic-gate 	"Memory-controller: %I%",	/* module name */
138*0Sstevel@tonic-gate 	&mc_ops,			/* driver ops */
139*0Sstevel@tonic-gate };
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
142*0Sstevel@tonic-gate 	MODREV_1,		/* rev */
143*0Sstevel@tonic-gate 	(void *)&modldrv,
144*0Sstevel@tonic-gate 	NULL
145*0Sstevel@tonic-gate };
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate static int mc_get_memory_reg_info(struct mc_soft_state *softsp);
148*0Sstevel@tonic-gate static void mc_construct(struct mc_soft_state *softsp);
149*0Sstevel@tonic-gate static void mc_delete(int mc_id);
150*0Sstevel@tonic-gate static void mc_node_add(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail);
151*0Sstevel@tonic-gate static void mc_node_del(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail);
152*0Sstevel@tonic-gate static void *mc_node_get(int id, mc_dlist_t *head);
153*0Sstevel@tonic-gate static void mc_add_mem_unum_label(char *unum, int mcid, int bank, int dimm);
154*0Sstevel@tonic-gate static int mc_get_mem_unum(int synd_code, uint64_t paddr, char *buf,
155*0Sstevel@tonic-gate     int buflen, int *lenp);
156*0Sstevel@tonic-gate static int mc_get_mem_info(int synd_code, uint64_t paddr,
157*0Sstevel@tonic-gate     uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep,
158*0Sstevel@tonic-gate     int *segsp, int *banksp, int *mcidp);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate #pragma weak p2get_mem_unum
161*0Sstevel@tonic-gate #pragma weak p2get_mem_info
162*0Sstevel@tonic-gate #pragma weak plat_add_mem_unum_label
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate /* For testing only */
165*0Sstevel@tonic-gate struct test_unum {
166*0Sstevel@tonic-gate 	int		synd_code;
167*0Sstevel@tonic-gate 	uint64_t	paddr;
168*0Sstevel@tonic-gate 	char 		unum[UNUM_NAMLEN];
169*0Sstevel@tonic-gate 	int		len;
170*0Sstevel@tonic-gate };
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate /*
173*0Sstevel@tonic-gate  * These are the module initialization routines.
174*0Sstevel@tonic-gate  */
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate int
177*0Sstevel@tonic-gate _init(void)
178*0Sstevel@tonic-gate {
179*0Sstevel@tonic-gate 	int error;
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	if ((error = ddi_soft_state_init(&mcp,
182*0Sstevel@tonic-gate 	    sizeof (struct mc_soft_state), 1)) != 0)
183*0Sstevel@tonic-gate 		return (error);
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	error =  mod_install(&modlinkage);
186*0Sstevel@tonic-gate 	if (error == 0) {
187*0Sstevel@tonic-gate 		mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL);
188*0Sstevel@tonic-gate 		mutex_init(&mcdatamutex, NULL, MUTEX_DRIVER, NULL);
189*0Sstevel@tonic-gate 	}
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	return (error);
192*0Sstevel@tonic-gate }
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate int
195*0Sstevel@tonic-gate _fini(void)
196*0Sstevel@tonic-gate {
197*0Sstevel@tonic-gate 	int error;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	if ((error = mod_remove(&modlinkage)) != 0)
200*0Sstevel@tonic-gate 		return (error);
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	ddi_soft_state_fini(&mcp);
203*0Sstevel@tonic-gate 	mutex_destroy(&mcmutex);
204*0Sstevel@tonic-gate 	mutex_destroy(&mcdatamutex);
205*0Sstevel@tonic-gate 	return (0);
206*0Sstevel@tonic-gate }
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate int
209*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
210*0Sstevel@tonic-gate {
211*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
212*0Sstevel@tonic-gate }
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate static int
215*0Sstevel@tonic-gate mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
216*0Sstevel@tonic-gate {
217*0Sstevel@tonic-gate 	struct mc_soft_state *softsp;
218*0Sstevel@tonic-gate 	struct dimm_info *dimminfop;
219*0Sstevel@tonic-gate 	int instance, len, err;
220*0Sstevel@tonic-gate 	int mcreg1_len;
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	switch (cmd) {
223*0Sstevel@tonic-gate 	case DDI_ATTACH:
224*0Sstevel@tonic-gate 		break;
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	case DDI_RESUME:
227*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	default:
230*0Sstevel@tonic-gate 		return (DDI_FAILURE);
231*0Sstevel@tonic-gate 	}
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	instance = ddi_get_instance(devi);
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(mcp, instance) != DDI_SUCCESS)
236*0Sstevel@tonic-gate 		return (DDI_FAILURE);
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	softsp = ddi_get_soft_state(mcp, instance);
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	/* Set the dip in the soft state */
241*0Sstevel@tonic-gate 	softsp->dip = devi;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	if ((softsp->portid = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->dip,
244*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "portid", -1)) == -1) {
245*0Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc%d: unable to get %s property\n",
246*0Sstevel@tonic-gate 		    instance, "portid"));
247*0Sstevel@tonic-gate 		goto bad;
248*0Sstevel@tonic-gate 	}
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	DPRINTF(MC_ATTACH_DEBUG, ("mc_attach: mc %d portid %d, cpuid %d\n",
251*0Sstevel@tonic-gate 	    instance, softsp->portid, CPU->cpu_id));
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/* Get the content of Memory Control Register I from obp */
254*0Sstevel@tonic-gate 	mcreg1_len = sizeof (uint64_t);
255*0Sstevel@tonic-gate 	if ((ddi_getlongprop_buf(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS,
256*0Sstevel@tonic-gate 	    "memory-control-register-1", (caddr_t)&(softsp->mcreg1),
257*0Sstevel@tonic-gate 	    &mcreg1_len) == DDI_PROP_SUCCESS) &&
258*0Sstevel@tonic-gate 	    (mcreg1_len == sizeof (uint64_t))) {
259*0Sstevel@tonic-gate 		softsp->mcr_read_ok = 1;
260*0Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc%d from obp: Reg1: 0x%lx\n",
261*0Sstevel@tonic-gate 		instance, softsp->mcreg1));
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	/* attach fails if mcreg1 cannot be accessed */
265*0Sstevel@tonic-gate 	if (!softsp->mcr_read_ok) {
266*0Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc%d: unable to get mcreg1\n",
267*0Sstevel@tonic-gate 		    instance));
268*0Sstevel@tonic-gate 		goto bad;
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	/* nothing to suspend/resume here */
272*0Sstevel@tonic-gate 	(void) ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP,
273*0Sstevel@tonic-gate 	    "pm-hardware-state", NO_SUSPEND_RESUME,
274*0Sstevel@tonic-gate 	    sizeof (NO_SUSPEND_RESUME));
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	/*
277*0Sstevel@tonic-gate 	 * Get the label of dimms and pin routing information from the
278*0Sstevel@tonic-gate 	 * memory-layout property of the memory controller.
279*0Sstevel@tonic-gate 	 */
280*0Sstevel@tonic-gate 	err = ddi_getlongprop(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS,
281*0Sstevel@tonic-gate 	    "memory-layout", (caddr_t)&dimminfop, &len);
282*0Sstevel@tonic-gate 	if (err == DDI_PROP_SUCCESS && dimminfop->table_width == 1) {
283*0Sstevel@tonic-gate 		/* Set the pointer and size of property in the soft state */
284*0Sstevel@tonic-gate 		softsp->memlayoutp = dimminfop;
285*0Sstevel@tonic-gate 		softsp->memlayoutlen = len;
286*0Sstevel@tonic-gate 	} else {
287*0Sstevel@tonic-gate 		/*
288*0Sstevel@tonic-gate 		 * memory-layout property was not found or some other
289*0Sstevel@tonic-gate 		 * error occured, plat_get_mem_unum() will not work
290*0Sstevel@tonic-gate 		 * for this mc.
291*0Sstevel@tonic-gate 		 */
292*0Sstevel@tonic-gate 		softsp->memlayoutp = NULL;
293*0Sstevel@tonic-gate 		softsp->memlayoutlen = 0;
294*0Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG,
295*0Sstevel@tonic-gate 		    ("mc %d: missing or unsupported memory-layout property\n",
296*0Sstevel@tonic-gate 		    instance));
297*0Sstevel@tonic-gate 	}
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	mutex_enter(&mcmutex);
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	/* Get the physical segments from memory/reg, just once for all MC */
302*0Sstevel@tonic-gate 	if (!getreg) {
303*0Sstevel@tonic-gate 		if (mc_get_memory_reg_info(softsp) != 0) {
304*0Sstevel@tonic-gate 			goto bad1;
305*0Sstevel@tonic-gate 		}
306*0Sstevel@tonic-gate 		getreg = 1;
307*0Sstevel@tonic-gate 	}
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	/* Construct the physical and logical layout of the MC */
310*0Sstevel@tonic-gate 	mc_construct(softsp);
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	if (nmcs == 1) {
313*0Sstevel@tonic-gate 		if (&p2get_mem_unum)
314*0Sstevel@tonic-gate 			p2get_mem_unum = mc_get_mem_unum;
315*0Sstevel@tonic-gate 		if (&p2get_mem_info)
316*0Sstevel@tonic-gate 			p2get_mem_info = mc_get_mem_info;
317*0Sstevel@tonic-gate 	}
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "mc-us3i", S_IFCHR, instance,
320*0Sstevel@tonic-gate 	    "ddi_mem_ctrl", 0) != DDI_SUCCESS) {
321*0Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc_attach: create_minor_node"
322*0Sstevel@tonic-gate 		    " failed \n"));
323*0Sstevel@tonic-gate 		goto bad1;
324*0Sstevel@tonic-gate 	}
325*0Sstevel@tonic-gate 	mutex_exit(&mcmutex);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	ddi_report_dev(devi);
328*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate bad1:
331*0Sstevel@tonic-gate 	/* release all allocated data struture for this MC */
332*0Sstevel@tonic-gate 	mc_delete(softsp->portid);
333*0Sstevel@tonic-gate 	mutex_exit(&mcmutex);
334*0Sstevel@tonic-gate 	if (softsp->memlayoutp != NULL)
335*0Sstevel@tonic-gate 		kmem_free(softsp->memlayoutp, softsp->memlayoutlen);
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate bad:
338*0Sstevel@tonic-gate 	cmn_err(CE_WARN, "mc-us3i: attach failed for instance %d\n", instance);
339*0Sstevel@tonic-gate 	ddi_soft_state_free(mcp, instance);
340*0Sstevel@tonic-gate 	return (DDI_FAILURE);
341*0Sstevel@tonic-gate }
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate /* ARGSUSED */
344*0Sstevel@tonic-gate static int
345*0Sstevel@tonic-gate mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
346*0Sstevel@tonic-gate {
347*0Sstevel@tonic-gate 	int instance;
348*0Sstevel@tonic-gate 	struct mc_soft_state *softsp;
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	/* get the instance of this devi */
351*0Sstevel@tonic-gate 	instance = ddi_get_instance(devi);
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 	/* get the soft state pointer for this device node */
354*0Sstevel@tonic-gate 	softsp = ddi_get_soft_state(mcp, instance);
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	switch (cmd) {
357*0Sstevel@tonic-gate 	case DDI_SUSPEND:
358*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	case DDI_DETACH:
361*0Sstevel@tonic-gate 		break;
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	default:
364*0Sstevel@tonic-gate 		return (DDI_FAILURE);
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	DPRINTF(MC_DETACH_DEBUG, ("mc %d DETACH: portid %d\n", instance,
368*0Sstevel@tonic-gate 	    softsp->portid));
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	mutex_enter(&mcmutex);
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	/* release all allocated data struture for this MC */
373*0Sstevel@tonic-gate 	mc_delete(softsp->portid);
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	if (softsp->memlayoutp != NULL)
376*0Sstevel@tonic-gate 		kmem_free(softsp->memlayoutp, softsp->memlayoutlen);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	if (nmcs == 0) {
379*0Sstevel@tonic-gate 		if (&p2get_mem_unum)
380*0Sstevel@tonic-gate 			p2get_mem_unum = NULL;
381*0Sstevel@tonic-gate 		if (&p2get_mem_info)
382*0Sstevel@tonic-gate 			p2get_mem_info = NULL;
383*0Sstevel@tonic-gate 	}
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	mutex_exit(&mcmutex);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	ddi_remove_minor_node(devi, NULL);
388*0Sstevel@tonic-gate 	/* free up the soft state */
389*0Sstevel@tonic-gate 	ddi_soft_state_free(mcp, instance);
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
392*0Sstevel@tonic-gate }
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate /* ARGSUSED */
395*0Sstevel@tonic-gate static int
396*0Sstevel@tonic-gate mc_open(dev_t *devp, int flag, int otyp, cred_t *credp)
397*0Sstevel@tonic-gate {
398*0Sstevel@tonic-gate 	int status = 0;
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	/* verify that otyp is appropriate */
401*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR) {
402*0Sstevel@tonic-gate 		return (EINVAL);
403*0Sstevel@tonic-gate 	}
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	mutex_enter(&mcmutex);
406*0Sstevel@tonic-gate 	/* At least one attached? */
407*0Sstevel@tonic-gate 	if (nmcs == 0) {
408*0Sstevel@tonic-gate 		status = ENXIO;
409*0Sstevel@tonic-gate 		goto bad;
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	if (mc_is_open) {
413*0Sstevel@tonic-gate 		status = EBUSY;
414*0Sstevel@tonic-gate 		goto bad;
415*0Sstevel@tonic-gate 	}
416*0Sstevel@tonic-gate 	mc_is_open = 1;
417*0Sstevel@tonic-gate bad:
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	mutex_exit(&mcmutex);
420*0Sstevel@tonic-gate 	return (status);
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate /* ARGSUSED */
424*0Sstevel@tonic-gate static int
425*0Sstevel@tonic-gate mc_close(dev_t devp, int flag, int otyp, cred_t *credp)
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate 	mutex_enter(&mcmutex);
428*0Sstevel@tonic-gate 	mc_is_open = 0;
429*0Sstevel@tonic-gate 	mutex_exit(&mcmutex);
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	return (0);
432*0Sstevel@tonic-gate }
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate /*
435*0Sstevel@tonic-gate  * cmd includes MCIOC_MEMCONF, MCIOC_MEM, MCIOC_SEG, MCIOC_BANK, MCIOC_DEVGRP,
436*0Sstevel@tonic-gate  * MCIOC_CTRLCONF, MCIOC_CONTROL.
437*0Sstevel@tonic-gate  *
438*0Sstevel@tonic-gate  * MCIOC_MEM, MCIOC_SEG, MCIOC_CTRLCONF, and MCIOC_CONTROL are
439*0Sstevel@tonic-gate  * associated with various length struct. If given number is less than the
440*0Sstevel@tonic-gate  * number in kernel, update the number and return EINVAL so that user could
441*0Sstevel@tonic-gate  * allocate enough space for it.
442*0Sstevel@tonic-gate  *
443*0Sstevel@tonic-gate  */
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate /* ARGSUSED */
446*0Sstevel@tonic-gate static int
447*0Sstevel@tonic-gate mc_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
448*0Sstevel@tonic-gate 	int *rval_p)
449*0Sstevel@tonic-gate {
450*0Sstevel@tonic-gate 	size_t	size;
451*0Sstevel@tonic-gate 	struct mc_memconf mcmconf;
452*0Sstevel@tonic-gate 	struct mc_memory *mcmem, mcmem_in;
453*0Sstevel@tonic-gate 	struct mc_segment *mcseg, mcseg_in;
454*0Sstevel@tonic-gate 	struct mc_bank mcbank;
455*0Sstevel@tonic-gate 	struct mc_devgrp mcdevgrp;
456*0Sstevel@tonic-gate 	struct mc_ctrlconf *mcctrlconf, mcctrlconf_in;
457*0Sstevel@tonic-gate 	struct mc_control *mccontrol, mccontrol_in;
458*0Sstevel@tonic-gate 	struct seg_info *seg = NULL;
459*0Sstevel@tonic-gate 	struct bank_info *bank = NULL;
460*0Sstevel@tonic-gate 	struct dgrp_info *dgrp = NULL;
461*0Sstevel@tonic-gate 	struct mctrl_info *mcport;
462*0Sstevel@tonic-gate 	mc_dlist_t *mctrl;
463*0Sstevel@tonic-gate 	int i, status = 0;
464*0Sstevel@tonic-gate 	cpu_t *cpu;
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	switch (cmd) {
467*0Sstevel@tonic-gate 	case MCIOC_MEMCONF:
468*0Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 		mcmconf.nmcs = nmcs;
471*0Sstevel@tonic-gate 		mcmconf.nsegments = nsegments;
472*0Sstevel@tonic-gate 		mcmconf.nbanks = NLOGBANKS_PER_SEG;
473*0Sstevel@tonic-gate 		mcmconf.ndevgrps = NDGRPS_PER_MC;
474*0Sstevel@tonic-gate 		mcmconf.ndevs = NDIMMS_PER_DGRP;
475*0Sstevel@tonic-gate 		mcmconf.len_dev = MAX_DEVLEN;
476*0Sstevel@tonic-gate 		mcmconf.xfer_size = TRANSFER_SIZE;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 		if (copyout(&mcmconf, (void *)arg, sizeof (mcmconf)))
481*0Sstevel@tonic-gate 			return (EFAULT);
482*0Sstevel@tonic-gate 		return (0);
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	/*
485*0Sstevel@tonic-gate 	 * input: nsegments and allocate space for various length of segmentids
486*0Sstevel@tonic-gate 	 *
487*0Sstevel@tonic-gate 	 * return    0: size, number of segments, and all segment ids,
488*0Sstevel@tonic-gate 	 *		where glocal and local ids are identical.
489*0Sstevel@tonic-gate 	 *	EINVAL: if the given nsegments is less than that in kernel and
490*0Sstevel@tonic-gate 	 *		nsegments of struct will be updated.
491*0Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
492*0Sstevel@tonic-gate 	 */
493*0Sstevel@tonic-gate 	case MCIOC_MEM:
494*0Sstevel@tonic-gate 		if (copyin((void *)arg, &mcmem_in, sizeof (mcmem_in)) != 0)
495*0Sstevel@tonic-gate 			return (EFAULT);
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
498*0Sstevel@tonic-gate 		if (mcmem_in.nsegments < nsegments) {
499*0Sstevel@tonic-gate 			mcmem_in.nsegments = nsegments;
500*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
501*0Sstevel@tonic-gate 			if (copyout(&mcmem_in, (void *)arg, sizeof (mcmem_in)))
502*0Sstevel@tonic-gate 				status = EFAULT;
503*0Sstevel@tonic-gate 			else
504*0Sstevel@tonic-gate 				status = EINVAL;
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 			return (status);
507*0Sstevel@tonic-gate 		}
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 		size = sizeof (*mcmem) + (nsegments - 1) *
510*0Sstevel@tonic-gate 		    sizeof (mcmem->segmentids[0]);
511*0Sstevel@tonic-gate 		mcmem = kmem_zalloc(size, KM_SLEEP);
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 		mcmem->size = memsize;
514*0Sstevel@tonic-gate 		mcmem->nsegments = nsegments;
515*0Sstevel@tonic-gate 		seg = (struct seg_info *)seg_head;
516*0Sstevel@tonic-gate 		for (i = 0; i < nsegments; i++) {
517*0Sstevel@tonic-gate 			ASSERT(seg != NULL);
518*0Sstevel@tonic-gate 			mcmem->segmentids[i].globalid = seg->seg_node.id;
519*0Sstevel@tonic-gate 			mcmem->segmentids[i].localid = seg->seg_node.id;
520*0Sstevel@tonic-gate 			seg = (struct seg_info *)seg->seg_node.next;
521*0Sstevel@tonic-gate 		}
522*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 		if (copyout(mcmem, (void *)arg, size))
525*0Sstevel@tonic-gate 			status = EFAULT;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 		kmem_free(mcmem, size);
528*0Sstevel@tonic-gate 		return (status);
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	/*
531*0Sstevel@tonic-gate 	 * input: id, nbanks and allocate space for various length of bankids
532*0Sstevel@tonic-gate 	 *
533*0Sstevel@tonic-gate 	 * return    0: base, size, number of banks, and all bank ids,
534*0Sstevel@tonic-gate 	 *		where global id is unique of all banks and local id
535*0Sstevel@tonic-gate 	 *		is only unique for mc.
536*0Sstevel@tonic-gate 	 *	EINVAL: either id isn't found or if given nbanks is less than
537*0Sstevel@tonic-gate 	 *		that in kernel and nbanks of struct will be updated.
538*0Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
539*0Sstevel@tonic-gate 	 */
540*0Sstevel@tonic-gate 	case MCIOC_SEG:
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 		if (copyin((void *)arg, &mcseg_in, sizeof (mcseg_in)) != 0)
543*0Sstevel@tonic-gate 			return (EFAULT);
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
546*0Sstevel@tonic-gate 		if ((seg = mc_node_get(mcseg_in.id, seg_head)) == NULL) {
547*0Sstevel@tonic-gate 			DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG: seg not match, "
548*0Sstevel@tonic-gate 			    "id %d\n", mcseg_in.id));
549*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
550*0Sstevel@tonic-gate 			return (EFAULT);
551*0Sstevel@tonic-gate 		}
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 		if (mcseg_in.nbanks < seg->nbanks) {
554*0Sstevel@tonic-gate 			mcseg_in.nbanks = seg->nbanks;
555*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
556*0Sstevel@tonic-gate 			if (copyout(&mcseg_in, (void *)arg, sizeof (mcseg_in)))
557*0Sstevel@tonic-gate 				status = EFAULT;
558*0Sstevel@tonic-gate 			else
559*0Sstevel@tonic-gate 				status = EINVAL;
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 			return (status);
562*0Sstevel@tonic-gate 		}
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 		size = sizeof (*mcseg) + (seg->nbanks - 1) *
565*0Sstevel@tonic-gate 		    sizeof (mcseg->bankids[0]);
566*0Sstevel@tonic-gate 		mcseg = kmem_zalloc(size, KM_SLEEP);
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 		mcseg->id = seg->seg_node.id;
569*0Sstevel@tonic-gate 		mcseg->ifactor = seg->ifactor;
570*0Sstevel@tonic-gate 		mcseg->base = seg->base;
571*0Sstevel@tonic-gate 		mcseg->size = seg->size;
572*0Sstevel@tonic-gate 		mcseg->nbanks = seg->nbanks;
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 		bank = seg->head;
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 		DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG:nbanks %d seg %p bank %p\n",
577*0Sstevel@tonic-gate 		    seg->nbanks, (void *) seg, (void *) bank));
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 		i = 0;
580*0Sstevel@tonic-gate 		while (bank != NULL) {
581*0Sstevel@tonic-gate 			DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG:idx %d bank_id %d\n",
582*0Sstevel@tonic-gate 			    i, bank->bank_node.id));
583*0Sstevel@tonic-gate 			mcseg->bankids[i].globalid = bank->bank_node.id;
584*0Sstevel@tonic-gate 			mcseg->bankids[i++].localid = bank->local_id;
585*0Sstevel@tonic-gate 			bank = bank->next;
586*0Sstevel@tonic-gate 		}
587*0Sstevel@tonic-gate 		ASSERT(i == seg->nbanks);
588*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 		if (copyout(mcseg, (void *)arg, size))
591*0Sstevel@tonic-gate 			status = EFAULT;
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 		kmem_free(mcseg, size);
594*0Sstevel@tonic-gate 		return (status);
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	/*
597*0Sstevel@tonic-gate 	 * input: id
598*0Sstevel@tonic-gate 	 *
599*0Sstevel@tonic-gate 	 * return    0: mask, match, size, and devgrpid,
600*0Sstevel@tonic-gate 	 *		where global id is unique of all devgrps and local id
601*0Sstevel@tonic-gate 	 *		is only unique for mc.
602*0Sstevel@tonic-gate 	 *	EINVAL: if id isn't found
603*0Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
604*0Sstevel@tonic-gate 	 */
605*0Sstevel@tonic-gate 	case MCIOC_BANK:
606*0Sstevel@tonic-gate 		if (copyin((void *)arg, &mcbank, sizeof (mcbank)) != 0)
607*0Sstevel@tonic-gate 			return (EFAULT);
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 		DPRINTF(MC_CMD_DEBUG, ("MCIOC_BANK: bank id %d\n", mcbank.id));
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 		if ((bank = mc_node_get(mcbank.id, bank_head)) == NULL) {
614*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
615*0Sstevel@tonic-gate 			return (EINVAL);
616*0Sstevel@tonic-gate 		}
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 		mcbank.mask = bank->mask;
619*0Sstevel@tonic-gate 		mcbank.match = bank->match;
620*0Sstevel@tonic-gate 		mcbank.size = bank->size;
621*0Sstevel@tonic-gate 		mcbank.devgrpid.globalid = bank->devgrp_id;
622*0Sstevel@tonic-gate 		mcbank.devgrpid.localid =
623*0Sstevel@tonic-gate 		    bank->bank_node.id % NLOGBANKS_PER_SEG;
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 		if (copyout(&mcbank, (void *)arg, sizeof (mcbank)))
628*0Sstevel@tonic-gate 			return (EFAULT);
629*0Sstevel@tonic-gate 		return (0);
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	/*
632*0Sstevel@tonic-gate 	 * input:id and allocate space for various length of deviceids
633*0Sstevel@tonic-gate 	 *
634*0Sstevel@tonic-gate 	 * return    0: size and number of devices.
635*0Sstevel@tonic-gate 	 *	EINVAL: id isn't found
636*0Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
637*0Sstevel@tonic-gate 	 */
638*0Sstevel@tonic-gate 	case MCIOC_DEVGRP:
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 		if (copyin((void *)arg, &mcdevgrp, sizeof (mcdevgrp)) != 0)
641*0Sstevel@tonic-gate 			return (EFAULT);
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
644*0Sstevel@tonic-gate 		if ((dgrp = mc_node_get(mcdevgrp.id, dgrp_head)) == NULL) {
645*0Sstevel@tonic-gate 			DPRINTF(MC_CMD_DEBUG, ("MCIOC_DEVGRP: not match, id "
646*0Sstevel@tonic-gate 			    "%d\n", mcdevgrp.id));
647*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
648*0Sstevel@tonic-gate 			return (EINVAL);
649*0Sstevel@tonic-gate 		}
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 		mcdevgrp.ndevices = dgrp->ndevices;
652*0Sstevel@tonic-gate 		mcdevgrp.size = dgrp->size;
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 		if (copyout(&mcdevgrp, (void *)arg, sizeof (mcdevgrp)))
657*0Sstevel@tonic-gate 			status = EFAULT;
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 		return (status);
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 	/*
662*0Sstevel@tonic-gate 	 * input: nmcs and allocate space for various length of mcids
663*0Sstevel@tonic-gate 	 *
664*0Sstevel@tonic-gate 	 * return    0: number of mc, and all mcids,
665*0Sstevel@tonic-gate 	 *		where glocal and local ids are identical.
666*0Sstevel@tonic-gate 	 *	EINVAL: if the given nmcs is less than that in kernel and
667*0Sstevel@tonic-gate 	 *		nmcs of struct will be updated.
668*0Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
669*0Sstevel@tonic-gate 	 */
670*0Sstevel@tonic-gate 	case MCIOC_CTRLCONF:
671*0Sstevel@tonic-gate 		if (copyin((void *)arg, &mcctrlconf_in,
672*0Sstevel@tonic-gate 		    sizeof (mcctrlconf_in)) != 0)
673*0Sstevel@tonic-gate 			return (EFAULT);
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
676*0Sstevel@tonic-gate 		if (mcctrlconf_in.nmcs < nmcs) {
677*0Sstevel@tonic-gate 			mcctrlconf_in.nmcs = nmcs;
678*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
679*0Sstevel@tonic-gate 			if (copyout(&mcctrlconf_in, (void *)arg,
680*0Sstevel@tonic-gate 			    sizeof (mcctrlconf_in)))
681*0Sstevel@tonic-gate 				status = EFAULT;
682*0Sstevel@tonic-gate 			else
683*0Sstevel@tonic-gate 				status = EINVAL;
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 			return (status);
686*0Sstevel@tonic-gate 		}
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 		/*
689*0Sstevel@tonic-gate 		 * Cannot just use the size of the struct because of the various
690*0Sstevel@tonic-gate 		 * length struct
691*0Sstevel@tonic-gate 		 */
692*0Sstevel@tonic-gate 		size = sizeof (*mcctrlconf) + ((nmcs - 1) *
693*0Sstevel@tonic-gate 		    sizeof (mcctrlconf->mcids[0]));
694*0Sstevel@tonic-gate 		mcctrlconf = kmem_zalloc(size, KM_SLEEP);
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 		mcctrlconf->nmcs = nmcs;
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 		/* Get all MC ids and add to mcctrlconf */
699*0Sstevel@tonic-gate 		mctrl = mctrl_head;
700*0Sstevel@tonic-gate 		i = 0;
701*0Sstevel@tonic-gate 		while (mctrl != NULL) {
702*0Sstevel@tonic-gate 			mcctrlconf->mcids[i].globalid = mctrl->id;
703*0Sstevel@tonic-gate 			mcctrlconf->mcids[i].localid = mctrl->id;
704*0Sstevel@tonic-gate 			i++;
705*0Sstevel@tonic-gate 			mctrl = mctrl->next;
706*0Sstevel@tonic-gate 		}
707*0Sstevel@tonic-gate 		ASSERT(i == nmcs);
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 		if (copyout(mcctrlconf, (void *)arg, size))
712*0Sstevel@tonic-gate 			status = EFAULT;
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 		kmem_free(mcctrlconf, size);
715*0Sstevel@tonic-gate 		return (status);
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	/*
718*0Sstevel@tonic-gate 	 * input:id, ndevgrps and allocate space for various length of devgrpids
719*0Sstevel@tonic-gate 	 *
720*0Sstevel@tonic-gate 	 * return    0: number of devgrp, and all devgrpids,
721*0Sstevel@tonic-gate 	 *		is unique of all devgrps and local id is only unique
722*0Sstevel@tonic-gate 	 *		for mc.
723*0Sstevel@tonic-gate 	 *	EINVAL: either if id isn't found or if the given ndevgrps is
724*0Sstevel@tonic-gate 	 *		less than that in kernel and ndevgrps of struct will
725*0Sstevel@tonic-gate 	 *		be updated.
726*0Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
727*0Sstevel@tonic-gate 	 */
728*0Sstevel@tonic-gate 	case MCIOC_CONTROL:
729*0Sstevel@tonic-gate 		if (copyin((void *)arg, &mccontrol_in,
730*0Sstevel@tonic-gate 		    sizeof (mccontrol_in)) != 0)
731*0Sstevel@tonic-gate 			return (EFAULT);
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
734*0Sstevel@tonic-gate 		if ((mcport = mc_node_get(mccontrol_in.id,
735*0Sstevel@tonic-gate 		    mctrl_head)) == NULL) {
736*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
737*0Sstevel@tonic-gate 			return (EINVAL);
738*0Sstevel@tonic-gate 		}
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 		/*
741*0Sstevel@tonic-gate 		 * mcport->ndevgrps zero means Memory Controller is disable.
742*0Sstevel@tonic-gate 		 */
743*0Sstevel@tonic-gate 		if ((mccontrol_in.ndevgrps < mcport->ndevgrps) ||
744*0Sstevel@tonic-gate 		    (mcport->ndevgrps == 0)) {
745*0Sstevel@tonic-gate 			mccontrol_in.ndevgrps = mcport->ndevgrps;
746*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
747*0Sstevel@tonic-gate 			if (copyout(&mccontrol_in, (void *)arg,
748*0Sstevel@tonic-gate 			    sizeof (mccontrol_in)))
749*0Sstevel@tonic-gate 				status = EFAULT;
750*0Sstevel@tonic-gate 			else if (mcport->ndevgrps != 0)
751*0Sstevel@tonic-gate 				status = EINVAL;
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 			return (status);
754*0Sstevel@tonic-gate 		}
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 		size = sizeof (*mccontrol) + (mcport->ndevgrps - 1) *
757*0Sstevel@tonic-gate 		    sizeof (mccontrol->devgrpids[0]);
758*0Sstevel@tonic-gate 		mccontrol = kmem_zalloc(size, KM_SLEEP);
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 		mccontrol->id = mcport->mctrl_node.id;
761*0Sstevel@tonic-gate 		mccontrol->ndevgrps = mcport->ndevgrps;
762*0Sstevel@tonic-gate 		for (i = 0; i < mcport->ndevgrps; i++) {
763*0Sstevel@tonic-gate 			mccontrol->devgrpids[i].globalid = mcport->devgrpids[i];
764*0Sstevel@tonic-gate 			mccontrol->devgrpids[i].localid =
765*0Sstevel@tonic-gate 			    mcport->devgrpids[i] % NDGRPS_PER_MC;
766*0Sstevel@tonic-gate 			DPRINTF(MC_CMD_DEBUG, ("MCIOC_CONTROL: devgrp id %d\n",
767*0Sstevel@tonic-gate 			    i));
768*0Sstevel@tonic-gate 		}
769*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 		if (copyout(mccontrol, (void *)arg, size))
772*0Sstevel@tonic-gate 			status = EFAULT;
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 		kmem_free(mccontrol, size);
775*0Sstevel@tonic-gate 		return (status);
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	/*
778*0Sstevel@tonic-gate 	 * input:id
779*0Sstevel@tonic-gate 	 *
780*0Sstevel@tonic-gate 	 * return    0: CPU flushed successfully.
781*0Sstevel@tonic-gate 	 *	EINVAL: the id wasn't found
782*0Sstevel@tonic-gate 	 */
783*0Sstevel@tonic-gate 	case MCIOC_ECFLUSH:
784*0Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
785*0Sstevel@tonic-gate 		cpu = cpu_get((processorid_t)arg);
786*0Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
787*0Sstevel@tonic-gate 		if (cpu == NULL)
788*0Sstevel@tonic-gate 			return (EINVAL);
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 		xc_one(arg, (xcfunc_t *)cpu_flush_ecache, 0, 0);
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 		return (0);
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 	default:
795*0Sstevel@tonic-gate 		DPRINTF(MC_CMD_DEBUG, ("DEFAULT: cmd is wrong\n"));
796*0Sstevel@tonic-gate 		return (EFAULT);
797*0Sstevel@tonic-gate 	}
798*0Sstevel@tonic-gate }
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate /*
801*0Sstevel@tonic-gate  * Gets the reg property from the memory node. This provides the various
802*0Sstevel@tonic-gate  * memory segments, at bank-boundries, dimm-pair boundries, in the form
803*0Sstevel@tonic-gate  * of [base, size] pairs. Continuous segments, spanning boundries are
804*0Sstevel@tonic-gate  * merged into one.
805*0Sstevel@tonic-gate  * Returns 0 for success and -1 for failure.
806*0Sstevel@tonic-gate  */
807*0Sstevel@tonic-gate static int
808*0Sstevel@tonic-gate mc_get_memory_reg_info(struct mc_soft_state *softsp)
809*0Sstevel@tonic-gate {
810*0Sstevel@tonic-gate 	dev_info_t *devi;
811*0Sstevel@tonic-gate 	int len;
812*0Sstevel@tonic-gate 	int i;
813*0Sstevel@tonic-gate 	struct memory_reg_info *mregi;
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(softsp))
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 	if ((devi = ddi_find_devinfo("memory", -1, 0)) == NULL) {
818*0Sstevel@tonic-gate 		DPRINTF(MC_REG_DEBUG,
819*0Sstevel@tonic-gate 		    ("mc-us3i: cannot find memory node under root\n"));
820*0Sstevel@tonic-gate 		return (-1);
821*0Sstevel@tonic-gate 	}
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
824*0Sstevel@tonic-gate 	    "reg", (caddr_t)&reg_info, &len) != DDI_PROP_SUCCESS) {
825*0Sstevel@tonic-gate 		DPRINTF(MC_REG_DEBUG,
826*0Sstevel@tonic-gate 		    ("mc-us3i: reg undefined under memory\n"));
827*0Sstevel@tonic-gate 		return (-1);
828*0Sstevel@tonic-gate 	}
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 	nregs = len/sizeof (*mregi);
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 	DPRINTF(MC_REG_DEBUG, ("mc_get_memory_reg_info: nregs %d"
833*0Sstevel@tonic-gate 	    "reg_info %p\n", nregs, (void *) reg_info));
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	mregi = reg_info;
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate 	/* debug printfs  */
838*0Sstevel@tonic-gate 	for (i = 0; i < nregs; i++) {
839*0Sstevel@tonic-gate 		DPRINTF(MC_REG_DEBUG, (" [0x%lx, 0x%lx] ",
840*0Sstevel@tonic-gate 		    mregi->base, mregi->size));
841*0Sstevel@tonic-gate 		mregi++;
842*0Sstevel@tonic-gate 	}
843*0Sstevel@tonic-gate 
844*0Sstevel@tonic-gate 	return (0);
845*0Sstevel@tonic-gate }
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate /*
848*0Sstevel@tonic-gate  * Initialize a logical bank
849*0Sstevel@tonic-gate  */
850*0Sstevel@tonic-gate static struct bank_info *
851*0Sstevel@tonic-gate mc_add_bank(int bankid, uint64_t mask, uint64_t match, uint64_t size,
852*0Sstevel@tonic-gate     int dgrpid)
853*0Sstevel@tonic-gate {
854*0Sstevel@tonic-gate 	struct bank_info *banki;
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 	if ((banki = mc_node_get(bankid, bank_head)) != NULL) {
857*0Sstevel@tonic-gate 		DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_bank: bank %d exists\n",
858*0Sstevel@tonic-gate 		    bankid));
859*0Sstevel@tonic-gate 		return (banki);
860*0Sstevel@tonic-gate 	}
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 	banki = kmem_zalloc(sizeof (*banki), KM_SLEEP);
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 	banki->bank_node.id = bankid;
865*0Sstevel@tonic-gate 	banki->devgrp_id = dgrpid;
866*0Sstevel@tonic-gate 	banki->mask = mask;
867*0Sstevel@tonic-gate 	banki->match = match;
868*0Sstevel@tonic-gate 	banki->base = match;
869*0Sstevel@tonic-gate 	banki->size = size;
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	mc_node_add((mc_dlist_t *)banki, &bank_head, &bank_tail);
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_bank: id %d mask 0x%lx match 0x%lx"
874*0Sstevel@tonic-gate 	    " base 0x%lx size 0x%lx\n", bankid, mask, match,
875*0Sstevel@tonic-gate 	    banki->base, banki->size));
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 	return (banki);
878*0Sstevel@tonic-gate }
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate /*
881*0Sstevel@tonic-gate  * Use the bank's base address to find out whether to initialize a new segment,
882*0Sstevel@tonic-gate  * or weave the bank into an existing segment. If the tail bank of a previous
883*0Sstevel@tonic-gate  * segment is not continuous with the new bank, the new bank goes into a new
884*0Sstevel@tonic-gate  * segment.
885*0Sstevel@tonic-gate  */
886*0Sstevel@tonic-gate static void
887*0Sstevel@tonic-gate mc_add_segment(struct bank_info *banki)
888*0Sstevel@tonic-gate {
889*0Sstevel@tonic-gate 	struct seg_info *segi;
890*0Sstevel@tonic-gate 	struct bank_info *tb;
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 	/* does this bank start a new segment? */
893*0Sstevel@tonic-gate 	if ((segi = mc_node_get(seg_id, seg_head)) == NULL) {
894*0Sstevel@tonic-gate 		/* this should happen for the first segment only */
895*0Sstevel@tonic-gate 		goto new_seg;
896*0Sstevel@tonic-gate 	}
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 	tb = segi->tail;
899*0Sstevel@tonic-gate 	/* discontiguous banks go into a new segment, increment the seg_id */
900*0Sstevel@tonic-gate 	if (banki->base > (tb->base + tb->size)) {
901*0Sstevel@tonic-gate 		seg_id++;
902*0Sstevel@tonic-gate 		goto new_seg;
903*0Sstevel@tonic-gate 	}
904*0Sstevel@tonic-gate 
905*0Sstevel@tonic-gate 	/* weave the bank into the segment */
906*0Sstevel@tonic-gate 	segi->nbanks++;
907*0Sstevel@tonic-gate 	tb->next = banki;
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate 	banki->seg_id = segi->seg_node.id;
910*0Sstevel@tonic-gate 	banki->local_id = tb->local_id + 1;
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 	/* contiguous or interleaved? */
913*0Sstevel@tonic-gate 	if (banki->base != (tb->base + tb->size))
914*0Sstevel@tonic-gate 		segi->ifactor++;
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate 	segi->size += banki->size;
917*0Sstevel@tonic-gate 	segi->tail = banki;
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 	memsize += banki->size;
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_segment: id %d add bank: id %d"
922*0Sstevel@tonic-gate 	    "size 0x%lx\n", segi->seg_node.id, banki->bank_node.id,
923*0Sstevel@tonic-gate 	    banki->size));
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate 	return;
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate new_seg:
928*0Sstevel@tonic-gate 	segi = kmem_zalloc(sizeof (*segi), KM_SLEEP);
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 	segi->seg_node.id = seg_id;
931*0Sstevel@tonic-gate 	segi->nbanks = 1;
932*0Sstevel@tonic-gate 	segi->ifactor = 1;
933*0Sstevel@tonic-gate 	segi->base = banki->base;
934*0Sstevel@tonic-gate 	segi->size = banki->size;
935*0Sstevel@tonic-gate 	segi->head = banki;
936*0Sstevel@tonic-gate 	segi->tail = banki;
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 	banki->seg_id = segi->seg_node.id;
939*0Sstevel@tonic-gate 	banki->local_id = 0;
940*0Sstevel@tonic-gate 
941*0Sstevel@tonic-gate 	mc_node_add((mc_dlist_t *)segi, &seg_head, &seg_tail);
942*0Sstevel@tonic-gate 	nsegments++;
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	memsize += banki->size;
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_segment: id %d new bank: id %d"
947*0Sstevel@tonic-gate 	    "size 0x%lx\n", segi->seg_node.id, banki->bank_node.id,
948*0Sstevel@tonic-gate 	    banki->size));
949*0Sstevel@tonic-gate }
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate /*
952*0Sstevel@tonic-gate  * Returns the address bit number (row index) that controls the logical/external
953*0Sstevel@tonic-gate  * bank assignment in interleave of kind internal-external same dimm-pair,
954*0Sstevel@tonic-gate  * internal-external both dimm-pair. This is done by using the dimm-densities
955*0Sstevel@tonic-gate  * and part-type.
956*0Sstevel@tonic-gate  */
957*0Sstevel@tonic-gate static int
958*0Sstevel@tonic-gate get_row_shift(int row_index, struct dgrp_info *dgrp)
959*0Sstevel@tonic-gate {
960*0Sstevel@tonic-gate 	int shift;
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate 	switch (dgrp->base_device) {
963*0Sstevel@tonic-gate 	case BASE_DEVICE_128Mb:
964*0Sstevel@tonic-gate 	case BASE_DEVICE_256Mb:
965*0Sstevel@tonic-gate 		/* 128Mb and 256Mb devices have same bank select mask */
966*0Sstevel@tonic-gate 		shift = ADDR_GEN_128Mb_X8_ROW_0;
967*0Sstevel@tonic-gate 		break;
968*0Sstevel@tonic-gate 	case BASE_DEVICE_512Mb:
969*0Sstevel@tonic-gate 	case BASE_DEVICE_1Gb:
970*0Sstevel@tonic-gate 		/* 512 and 1Gb devices have same bank select mask */
971*0Sstevel@tonic-gate 		shift = ADDR_GEN_512Mb_X8_ROW_0;
972*0Sstevel@tonic-gate 		break;
973*0Sstevel@tonic-gate 	}
974*0Sstevel@tonic-gate 
975*0Sstevel@tonic-gate 	if (dgrp->part_type == PART_TYPE_X4)
976*0Sstevel@tonic-gate 		shift += 1;
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	shift += row_index;
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 	return (shift);
981*0Sstevel@tonic-gate }
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate static void
985*0Sstevel@tonic-gate get_device_select(int interleave, struct dgrp_info *dgrp,
986*0Sstevel@tonic-gate     int *ds_shift, int *bs_shift)
987*0Sstevel@tonic-gate {
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 	switch (interleave) {
990*0Sstevel@tonic-gate 	case INTERLEAVE_DISABLE:
991*0Sstevel@tonic-gate 	/* Fall Through */
992*0Sstevel@tonic-gate 	case INTERLEAVE_INTERNAL:
993*0Sstevel@tonic-gate 		/* Bit 33 selects the dimm group/pair */
994*0Sstevel@tonic-gate 		*ds_shift = DIMM_PAIR_SELECT_SHIFT;
995*0Sstevel@tonic-gate 		if (dgrp->nlogbanks == 2) {
996*0Sstevel@tonic-gate 			/* Bit 32 selects the logical bank */
997*0Sstevel@tonic-gate 			*bs_shift = LOG_BANK_SELECT_SHIFT;
998*0Sstevel@tonic-gate 		}
999*0Sstevel@tonic-gate 		break;
1000*0Sstevel@tonic-gate 	case INTERLEAVE_INTEXT_SAME_DIMM_PAIR:
1001*0Sstevel@tonic-gate 		/* Bit 33 selects the dimm group/pair */
1002*0Sstevel@tonic-gate 		*ds_shift =  DIMM_PAIR_SELECT_SHIFT;
1003*0Sstevel@tonic-gate 		if (dgrp->nlogbanks == 2) {
1004*0Sstevel@tonic-gate 			/* Row[2] selects the logical bank */
1005*0Sstevel@tonic-gate 			*bs_shift = get_row_shift(2, dgrp);
1006*0Sstevel@tonic-gate 		}
1007*0Sstevel@tonic-gate 		break;
1008*0Sstevel@tonic-gate 	case INTERLEAVE_INTEXT_BOTH_DIMM_PAIR:
1009*0Sstevel@tonic-gate 		if (dgrp->nlogbanks == 2) {
1010*0Sstevel@tonic-gate 			/* Row[3] selects the dimm group/pair */
1011*0Sstevel@tonic-gate 			*ds_shift = get_row_shift(3, dgrp);
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate 			/* Row[2] selects the logical bank */
1014*0Sstevel@tonic-gate 			*bs_shift = get_row_shift(2, dgrp);
1015*0Sstevel@tonic-gate 		} else {
1016*0Sstevel@tonic-gate 			/* Row[2] selects the dimm group/pair */
1017*0Sstevel@tonic-gate 			*ds_shift = get_row_shift(2, dgrp);
1018*0Sstevel@tonic-gate 		}
1019*0Sstevel@tonic-gate 		break;
1020*0Sstevel@tonic-gate 	}
1021*0Sstevel@tonic-gate }
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate static void
1024*0Sstevel@tonic-gate mc_add_xor_banks(struct mctrl_info *mctrl,
1025*0Sstevel@tonic-gate     uint64_t mask, uint64_t match, int interleave)
1026*0Sstevel@tonic-gate {
1027*0Sstevel@tonic-gate 	int i, j, nbits, nbanks;
1028*0Sstevel@tonic-gate 	int bankid;
1029*0Sstevel@tonic-gate 	int dselect[4];
1030*0Sstevel@tonic-gate 	int ds_shift = -1, bs_shift = -1;
1031*0Sstevel@tonic-gate 	uint64_t id, size, xmatch;
1032*0Sstevel@tonic-gate 	struct bank_info *banki;
1033*0Sstevel@tonic-gate 	struct dgrp_info *dgrp;
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 	/* xor mode - assume 2 identical dimm-pairs */
1036*0Sstevel@tonic-gate 	if ((dgrp = mc_node_get(mctrl->devgrpids[0], dgrp_head)) == NULL) {
1037*0Sstevel@tonic-gate 		return;
1038*0Sstevel@tonic-gate 	}
1039*0Sstevel@tonic-gate 
1040*0Sstevel@tonic-gate 	get_device_select(interleave, dgrp, &ds_shift, &bs_shift);
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate 	mask |= (ds_shift == -1 ? 0 : (1ULL << ds_shift));
1043*0Sstevel@tonic-gate 	mask |= (bs_shift == -1 ? 0 : (1ULL << bs_shift));
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 	/* xor enable means, bit 21 is used for dimm-pair select */
1046*0Sstevel@tonic-gate 	mask |= XOR_DEVICE_SELECT_MASK;
1047*0Sstevel@tonic-gate 	if (dgrp->nlogbanks == NLOGBANKS_PER_DGRP) {
1048*0Sstevel@tonic-gate 		/* bit 20 is used for logbank select */
1049*0Sstevel@tonic-gate 		mask |= XOR_BANK_SELECT_MASK;
1050*0Sstevel@tonic-gate 	}
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate 	/* find out the bits set to 1 in mask, nbits can be 2 or 4 */
1053*0Sstevel@tonic-gate 	nbits = 0;
1054*0Sstevel@tonic-gate 	for (i = 0; i <= DIMM_PAIR_SELECT_SHIFT; i++) {
1055*0Sstevel@tonic-gate 		if ((((mask >> i) & 1) == 1) && (nbits < 4)) {
1056*0Sstevel@tonic-gate 			dselect[nbits] = i;
1057*0Sstevel@tonic-gate 			nbits++;
1058*0Sstevel@tonic-gate 		}
1059*0Sstevel@tonic-gate 	}
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	/* number or banks can be 4 or 16 */
1062*0Sstevel@tonic-gate 	nbanks = 1 << nbits;
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 	size = (dgrp->size * 2)/nbanks;
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate 	bankid = mctrl->mctrl_node.id * NLOGBANKS_PER_MC;
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 	/* each bit position of the mask decides the match & base for bank */
1069*0Sstevel@tonic-gate 	for (i = 0; i < nbanks; i++) {
1070*0Sstevel@tonic-gate 		xmatch = 0;
1071*0Sstevel@tonic-gate 		for (j = 0; j < nbits; j++) {
1072*0Sstevel@tonic-gate 			xmatch |= (i & (1ULL << j)) << (dselect[j] - j);
1073*0Sstevel@tonic-gate 		}
1074*0Sstevel@tonic-gate 		/* xor ds bits to get the dimm-pair */
1075*0Sstevel@tonic-gate 		id = ((xmatch & (1ULL << ds_shift)) >> ds_shift) ^
1076*0Sstevel@tonic-gate 			((xmatch & (1ULL << XOR_DEVICE_SELECT_SHIFT)) >>
1077*0Sstevel@tonic-gate 			XOR_DEVICE_SELECT_SHIFT);
1078*0Sstevel@tonic-gate 		banki = mc_add_bank(bankid, mask, match | xmatch, size,
1079*0Sstevel@tonic-gate 		    mctrl->devgrpids[id]);
1080*0Sstevel@tonic-gate 		mc_add_segment(banki);
1081*0Sstevel@tonic-gate 		bankid++;
1082*0Sstevel@tonic-gate 	}
1083*0Sstevel@tonic-gate }
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate /*
1086*0Sstevel@tonic-gate  * Based on interleave, dimm-densities, part-type determine the mask
1087*0Sstevel@tonic-gate  * and match per bank, construct the logical layout by adding segments
1088*0Sstevel@tonic-gate  * and banks
1089*0Sstevel@tonic-gate  */
1090*0Sstevel@tonic-gate static int
1091*0Sstevel@tonic-gate mc_add_dgrp_banks(uint64_t bankid, uint64_t dgrpid,
1092*0Sstevel@tonic-gate     uint64_t mask, uint64_t match, int interleave)
1093*0Sstevel@tonic-gate {
1094*0Sstevel@tonic-gate 	int nbanks = 0;
1095*0Sstevel@tonic-gate 	struct bank_info *banki;
1096*0Sstevel@tonic-gate 	struct dgrp_info *dgrp;
1097*0Sstevel@tonic-gate 	int ds_shift = -1, bs_shift = -1;
1098*0Sstevel@tonic-gate 	uint64_t size;
1099*0Sstevel@tonic-gate 	uint64_t match_save;
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate 	if ((dgrp = mc_node_get(dgrpid, dgrp_head)) == NULL) {
1102*0Sstevel@tonic-gate 		return (0);
1103*0Sstevel@tonic-gate 	}
1104*0Sstevel@tonic-gate 
1105*0Sstevel@tonic-gate 	get_device_select(interleave, dgrp, &ds_shift, &bs_shift);
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate 	mask |= (ds_shift == -1 ? 0 : (1ULL << ds_shift));
1108*0Sstevel@tonic-gate 	mask |= (bs_shift == -1 ? 0 : (1ULL << bs_shift));
1109*0Sstevel@tonic-gate 	match |= (ds_shift == -1 ? 0 : ((dgrpid & 1) << ds_shift));
1110*0Sstevel@tonic-gate 	match_save = match;
1111*0Sstevel@tonic-gate 	size = dgrp->size/dgrp->nlogbanks;
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	/* for bankid 0, 2, 4 .. */
1114*0Sstevel@tonic-gate 	match |= (bs_shift == -1 ? 0 : ((bankid & 1) << bs_shift));
1115*0Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_segments: interleave %d"
1116*0Sstevel@tonic-gate 	    " mask 0x%lx bs_shift %d match 0x%lx\n",
1117*0Sstevel@tonic-gate 	    interleave, mask, bs_shift, match));
1118*0Sstevel@tonic-gate 	banki = mc_add_bank(bankid, mask, match, size, dgrpid);
1119*0Sstevel@tonic-gate 	nbanks++;
1120*0Sstevel@tonic-gate 	mc_add_segment(banki);
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 	if (dgrp->nlogbanks == 2) {
1123*0Sstevel@tonic-gate 		/*
1124*0Sstevel@tonic-gate 		 * Set match value to original before adding second
1125*0Sstevel@tonic-gate 		 * logical bank interleaving information.
1126*0Sstevel@tonic-gate 		 */
1127*0Sstevel@tonic-gate 		match = match_save;
1128*0Sstevel@tonic-gate 		bankid++;
1129*0Sstevel@tonic-gate 		match |= (bs_shift == -1 ? 0 : ((bankid & 1) << bs_shift));
1130*0Sstevel@tonic-gate 		DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_segments: interleave %d"
1131*0Sstevel@tonic-gate 		    " mask 0x%lx shift %d match 0x%lx\n",
1132*0Sstevel@tonic-gate 		    interleave, mask, bs_shift, match));
1133*0Sstevel@tonic-gate 		banki = mc_add_bank(bankid, mask, match, size, dgrpid);
1134*0Sstevel@tonic-gate 		nbanks++;
1135*0Sstevel@tonic-gate 		mc_add_segment(banki);
1136*0Sstevel@tonic-gate 	}
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 	return (nbanks);
1139*0Sstevel@tonic-gate }
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate /*
1142*0Sstevel@tonic-gate  * Construct the logical layout
1143*0Sstevel@tonic-gate  */
1144*0Sstevel@tonic-gate static void
1145*0Sstevel@tonic-gate mc_logical_layout(struct mctrl_info *mctrl, struct mc_soft_state *softsp)
1146*0Sstevel@tonic-gate {
1147*0Sstevel@tonic-gate 	int i;
1148*0Sstevel@tonic-gate 	uint64_t mcid, bankid, interleave, mask, match;
1149*0Sstevel@tonic-gate 
1150*0Sstevel@tonic-gate 	if (mctrl->ndevgrps == 0)
1151*0Sstevel@tonic-gate 		return;
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate 	mcid = mctrl->mctrl_node.id;
1154*0Sstevel@tonic-gate 	mask = MC_SELECT_MASK;
1155*0Sstevel@tonic-gate 	match = mcid << MC_SELECT_SHIFT;
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 	interleave = (softsp->mcreg1 & MCREG1_INTERLEAVE_MASK) >>
1158*0Sstevel@tonic-gate 	    MCREG1_INTERLEAVE_SHIFT;
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate 	/* Two dimm pairs and xor bit set */
1161*0Sstevel@tonic-gate 	if (mctrl->ndevgrps == NDGRPS_PER_MC &&
1162*0Sstevel@tonic-gate 	    (softsp->mcreg1 & MCREG1_XOR_ENABLE)) {
1163*0Sstevel@tonic-gate 		mc_add_xor_banks(mctrl, mask, match, interleave);
1164*0Sstevel@tonic-gate 		return;
1165*0Sstevel@tonic-gate 	}
1166*0Sstevel@tonic-gate 
1167*0Sstevel@tonic-gate 	/*
1168*0Sstevel@tonic-gate 	 * For xor bit unset or only one dimm pair.
1169*0Sstevel@tonic-gate 	 * In one dimm pair case, even if xor bit is set, xor
1170*0Sstevel@tonic-gate 	 * interleaving is only taking place in dimm's internal
1171*0Sstevel@tonic-gate 	 * banks. Dimm and external bank select bits are the
1172*0Sstevel@tonic-gate 	 * same as those without xor bit set.
1173*0Sstevel@tonic-gate 	 */
1174*0Sstevel@tonic-gate 	bankid = mcid * NLOGBANKS_PER_MC;
1175*0Sstevel@tonic-gate 	for (i = 0; i < mctrl->ndevgrps; i++) {
1176*0Sstevel@tonic-gate 		bankid += mc_add_dgrp_banks(bankid, mctrl->devgrpids[i],
1177*0Sstevel@tonic-gate 				mask, match, interleave);
1178*0Sstevel@tonic-gate 	}
1179*0Sstevel@tonic-gate }
1180*0Sstevel@tonic-gate 
1181*0Sstevel@tonic-gate /*
1182*0Sstevel@tonic-gate  * Get the dimm-pair's size from the reg_info
1183*0Sstevel@tonic-gate  */
1184*0Sstevel@tonic-gate static uint64_t
1185*0Sstevel@tonic-gate get_devgrp_size(uint64_t start)
1186*0Sstevel@tonic-gate {
1187*0Sstevel@tonic-gate 	int i;
1188*0Sstevel@tonic-gate 	uint64_t size;
1189*0Sstevel@tonic-gate 	uint64_t end, reg_start, reg_end;
1190*0Sstevel@tonic-gate 	struct memory_reg_info *regi;
1191*0Sstevel@tonic-gate 
1192*0Sstevel@tonic-gate 	/* dgrp end address */
1193*0Sstevel@tonic-gate 	end = start + DGRP_SIZE_MAX - 1;
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate 	regi = reg_info;
1196*0Sstevel@tonic-gate 	size = 0;
1197*0Sstevel@tonic-gate 	for (i = 0; i < nregs; i++) {
1198*0Sstevel@tonic-gate 		reg_start = regi->base;
1199*0Sstevel@tonic-gate 		reg_end = regi->base + regi->size - 1;
1200*0Sstevel@tonic-gate 
1201*0Sstevel@tonic-gate 		/* completely outside */
1202*0Sstevel@tonic-gate 		if ((reg_end < start) || (reg_start > end)) {
1203*0Sstevel@tonic-gate 			regi++;
1204*0Sstevel@tonic-gate 			continue;
1205*0Sstevel@tonic-gate 		}
1206*0Sstevel@tonic-gate 
1207*0Sstevel@tonic-gate 		/* completely inside */
1208*0Sstevel@tonic-gate 		if ((reg_start <= start) && (reg_end >= end)) {
1209*0Sstevel@tonic-gate 			return (DGRP_SIZE_MAX);
1210*0Sstevel@tonic-gate 		}
1211*0Sstevel@tonic-gate 
1212*0Sstevel@tonic-gate 		/* start is inside, but not the end, get the remainder */
1213*0Sstevel@tonic-gate 		if (reg_start < start) {
1214*0Sstevel@tonic-gate 			size = regi->size - (start - reg_start);
1215*0Sstevel@tonic-gate 			regi++;
1216*0Sstevel@tonic-gate 			continue;
1217*0Sstevel@tonic-gate 		}
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 		/* add up size for all within range */
1220*0Sstevel@tonic-gate 		size += regi->size;
1221*0Sstevel@tonic-gate 		regi++;
1222*0Sstevel@tonic-gate 	}
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate 	return (size);
1225*0Sstevel@tonic-gate }
1226*0Sstevel@tonic-gate 
1227*0Sstevel@tonic-gate /*
1228*0Sstevel@tonic-gate  * Each device group is a pair (dimm-pair) of identical single/dual dimms.
1229*0Sstevel@tonic-gate  * Determine the dimm-pair's dimm-densities and part-type using the MCR-I.
1230*0Sstevel@tonic-gate  */
1231*0Sstevel@tonic-gate static void
1232*0Sstevel@tonic-gate mc_add_devgrp(int dgrpid, struct mc_soft_state *softsp)
1233*0Sstevel@tonic-gate {
1234*0Sstevel@tonic-gate 	int i, mcid, devid, dgrpoffset;
1235*0Sstevel@tonic-gate 	struct dgrp_info *dgrp;
1236*0Sstevel@tonic-gate 	struct device_info *dev;
1237*0Sstevel@tonic-gate 	struct dimm_info *dimmp = (struct dimm_info *)softsp->memlayoutp;
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate 	mcid = softsp->portid;
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate 	/* add the entry on dgrp_info list */
1242*0Sstevel@tonic-gate 	if ((dgrp = mc_node_get(dgrpid, dgrp_head)) != NULL) {
1243*0Sstevel@tonic-gate 		DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_devgrp: devgrp %d exists\n",
1244*0Sstevel@tonic-gate 		    dgrpid));
1245*0Sstevel@tonic-gate 		return;
1246*0Sstevel@tonic-gate 	}
1247*0Sstevel@tonic-gate 
1248*0Sstevel@tonic-gate 	dgrp = kmem_zalloc(sizeof (*dgrp), KM_SLEEP);
1249*0Sstevel@tonic-gate 
1250*0Sstevel@tonic-gate 	dgrp->dgrp_node.id = dgrpid;
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate 	/* a devgrp has identical (type & size) pair */
1253*0Sstevel@tonic-gate 	if ((dgrpid & 1) == 0) {
1254*0Sstevel@tonic-gate 		/* dimm-pair 0, 2, 4, 6 */
1255*0Sstevel@tonic-gate 		if (softsp->mcreg1 & MCREG1_DIMM1_BANK1)
1256*0Sstevel@tonic-gate 			dgrp->nlogbanks = 2;
1257*0Sstevel@tonic-gate 		else
1258*0Sstevel@tonic-gate 			dgrp->nlogbanks = 1;
1259*0Sstevel@tonic-gate 		dgrp->base_device = (softsp->mcreg1 & MCREG1_ADDRGEN1_MASK) >>
1260*0Sstevel@tonic-gate 		    MCREG1_ADDRGEN1_SHIFT;
1261*0Sstevel@tonic-gate 		dgrp->part_type = (softsp->mcreg1 & MCREG1_X4DIMM1_MASK) >>
1262*0Sstevel@tonic-gate 		    MCREG1_X4DIMM1_SHIFT;
1263*0Sstevel@tonic-gate 	} else {
1264*0Sstevel@tonic-gate 		/* dimm-pair 1, 3, 5, 7 */
1265*0Sstevel@tonic-gate 		if (softsp->mcreg1 & MCREG1_DIMM2_BANK3)
1266*0Sstevel@tonic-gate 			dgrp->nlogbanks = 2;
1267*0Sstevel@tonic-gate 		else
1268*0Sstevel@tonic-gate 			dgrp->nlogbanks = 1;
1269*0Sstevel@tonic-gate 		dgrp->base_device = (softsp->mcreg1 & MCREG1_ADDRGEN2_MASK) >>
1270*0Sstevel@tonic-gate 		    MCREG1_ADDRGEN2_SHIFT;
1271*0Sstevel@tonic-gate 		dgrp->part_type = (softsp->mcreg1 & MCREG1_X4DIMM2_MASK) >>
1272*0Sstevel@tonic-gate 		    MCREG1_X4DIMM2_SHIFT;
1273*0Sstevel@tonic-gate 	}
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate 	dgrp->base = MC_BASE(mcid) + DGRP_BASE(dgrpid);
1276*0Sstevel@tonic-gate 	dgrp->size = get_devgrp_size(dgrp->base);
1277*0Sstevel@tonic-gate 
1278*0Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_devgrp: id %d size %ld logbanks %d"
1279*0Sstevel@tonic-gate 	    " base_device %d part_type %d\n", dgrpid, dgrp->size,
1280*0Sstevel@tonic-gate 	    dgrp->nlogbanks, dgrp->base_device, dgrp->part_type));
1281*0Sstevel@tonic-gate 
1282*0Sstevel@tonic-gate 	dgrpoffset = dgrpid % NDGRPS_PER_MC;
1283*0Sstevel@tonic-gate 	dgrp->ndevices = NDIMMS_PER_DGRP;
1284*0Sstevel@tonic-gate 	/* add the entry for the (identical) pair of dimms/device */
1285*0Sstevel@tonic-gate 	for (i = 0; i < NDIMMS_PER_DGRP; i++) {
1286*0Sstevel@tonic-gate 		devid = dgrpid * NDIMMS_PER_DGRP + i;
1287*0Sstevel@tonic-gate 		dgrp->deviceids[i] = devid;
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate 		if ((dev = mc_node_get(devid, device_head)) != NULL) {
1290*0Sstevel@tonic-gate 			DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_devgrp: device %d "
1291*0Sstevel@tonic-gate 			    "exists\n", devid));
1292*0Sstevel@tonic-gate 			continue;
1293*0Sstevel@tonic-gate 		}
1294*0Sstevel@tonic-gate 
1295*0Sstevel@tonic-gate 		dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate 		dev->dev_node.id = devid;
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate 		dev->size = dgrp->size/2;
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate 		if (dimmp) {
1302*0Sstevel@tonic-gate 			(void) strncpy(dev->label, (char *)dimmp->label[
1303*0Sstevel@tonic-gate 			    i + NDIMMS_PER_DGRP * dgrpoffset],
1304*0Sstevel@tonic-gate 			    MAX_DEVLEN);
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate 			DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_devgrp: dimm %d %s\n",
1307*0Sstevel@tonic-gate 			    dev->dev_node.id, dev->label));
1308*0Sstevel@tonic-gate 		}
1309*0Sstevel@tonic-gate 
1310*0Sstevel@tonic-gate 		mc_node_add((mc_dlist_t *)dev, &device_head, &device_tail);
1311*0Sstevel@tonic-gate 	}
1312*0Sstevel@tonic-gate 
1313*0Sstevel@tonic-gate 	mc_node_add((mc_dlist_t *)dgrp, &dgrp_head, &dgrp_tail);
1314*0Sstevel@tonic-gate }
1315*0Sstevel@tonic-gate 
1316*0Sstevel@tonic-gate /*
1317*0Sstevel@tonic-gate  * Construct the physical and logical layout
1318*0Sstevel@tonic-gate  */
1319*0Sstevel@tonic-gate static void
1320*0Sstevel@tonic-gate mc_construct(struct mc_soft_state *softsp)
1321*0Sstevel@tonic-gate {
1322*0Sstevel@tonic-gate 	int i, mcid, dgrpid;
1323*0Sstevel@tonic-gate 	struct mctrl_info *mctrl;
1324*0Sstevel@tonic-gate 
1325*0Sstevel@tonic-gate 	mcid = softsp->portid;
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mc_construct: mcid %d, mcreg1 0x%lx\n",
1328*0Sstevel@tonic-gate 	    mcid, softsp->mcreg1));
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate 	/*
1331*0Sstevel@tonic-gate 	 * Construct the Physical & Logical Layout
1332*0Sstevel@tonic-gate 	 */
1333*0Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 	/* allocate for mctrl_info */
1336*0Sstevel@tonic-gate 	if ((mctrl = mc_node_get(mcid, mctrl_head)) != NULL) {
1337*0Sstevel@tonic-gate 		DPRINTF(MC_CNSTRC_DEBUG, ("mc_construct: mctrl %d exists\n",
1338*0Sstevel@tonic-gate 		    mcid));
1339*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
1340*0Sstevel@tonic-gate 		return;
1341*0Sstevel@tonic-gate 	}
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 	mctrl = kmem_zalloc(sizeof (*mctrl), KM_SLEEP);
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 	mctrl->mctrl_node.id = mcid;
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 	i = 0;
1348*0Sstevel@tonic-gate 	dgrpid = mcid * NDGRPS_PER_MC;
1349*0Sstevel@tonic-gate 	if (softsp->mcreg1 & MCREG1_DIMM1_BANK0) {
1350*0Sstevel@tonic-gate 		mc_add_devgrp(dgrpid, softsp);
1351*0Sstevel@tonic-gate 		mctrl->devgrpids[i] = dgrpid;
1352*0Sstevel@tonic-gate 		mctrl->ndevgrps++;
1353*0Sstevel@tonic-gate 		i++;
1354*0Sstevel@tonic-gate 	}
1355*0Sstevel@tonic-gate 
1356*0Sstevel@tonic-gate 	if (softsp->mcreg1 & MCREG1_DIMM2_BANK2) {
1357*0Sstevel@tonic-gate 		dgrpid++;
1358*0Sstevel@tonic-gate 		mc_add_devgrp(dgrpid, softsp);
1359*0Sstevel@tonic-gate 		mctrl->devgrpids[i] = dgrpid;
1360*0Sstevel@tonic-gate 		mctrl->ndevgrps++;
1361*0Sstevel@tonic-gate 	}
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 	mc_logical_layout(mctrl, softsp);
1364*0Sstevel@tonic-gate 
1365*0Sstevel@tonic-gate 	mctrl->dimminfop = (struct dimm_info *)softsp->memlayoutp;
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	nmcs++;
1368*0Sstevel@tonic-gate 	mc_node_add((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail);
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1371*0Sstevel@tonic-gate 
1372*0Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mc_construct: nmcs %d memsize %ld"
1373*0Sstevel@tonic-gate 	    "nsegments %d\n", nmcs, memsize, nsegments));
1374*0Sstevel@tonic-gate }
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate /*
1377*0Sstevel@tonic-gate  * Delete nodes related to the given MC on mc, device group, device,
1378*0Sstevel@tonic-gate  * and bank lists. Moreover, delete corresponding segment if its connected
1379*0Sstevel@tonic-gate  * banks are all removed.
1380*0Sstevel@tonic-gate  */
1381*0Sstevel@tonic-gate static void
1382*0Sstevel@tonic-gate mc_delete(int mc_id)
1383*0Sstevel@tonic-gate {
1384*0Sstevel@tonic-gate 	int i, j, dgrpid, devid, bankid;
1385*0Sstevel@tonic-gate 	struct mctrl_info *mctrl;
1386*0Sstevel@tonic-gate 	struct dgrp_info *dgrp;
1387*0Sstevel@tonic-gate 	struct device_info *devp;
1388*0Sstevel@tonic-gate 	struct seg_info *segi;
1389*0Sstevel@tonic-gate 	struct bank_info *banki;
1390*0Sstevel@tonic-gate 
1391*0Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
1392*0Sstevel@tonic-gate 
1393*0Sstevel@tonic-gate 	/* delete mctrl_info */
1394*0Sstevel@tonic-gate 	if ((mctrl = mc_node_get(mc_id, mctrl_head)) != NULL) {
1395*0Sstevel@tonic-gate 		mc_node_del((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail);
1396*0Sstevel@tonic-gate 		kmem_free(mctrl, sizeof (*mctrl));
1397*0Sstevel@tonic-gate 		nmcs--;
1398*0Sstevel@tonic-gate 	} else
1399*0Sstevel@tonic-gate 		DPRINTF(MC_DESTRC_DEBUG, ("mc_delete: mctrl is not found\n"));
1400*0Sstevel@tonic-gate 
1401*0Sstevel@tonic-gate 	/* delete device groups and devices of the detached MC */
1402*0Sstevel@tonic-gate 	for (i = 0; i < NDGRPS_PER_MC; i++) {
1403*0Sstevel@tonic-gate 		dgrpid = mc_id * NDGRPS_PER_MC + i;
1404*0Sstevel@tonic-gate 		if (!(dgrp = mc_node_get(dgrpid, dgrp_head))) {
1405*0Sstevel@tonic-gate 			continue;
1406*0Sstevel@tonic-gate 		}
1407*0Sstevel@tonic-gate 
1408*0Sstevel@tonic-gate 		for (j = 0; j < NDIMMS_PER_DGRP; j++) {
1409*0Sstevel@tonic-gate 			devid = dgrpid * NDIMMS_PER_DGRP + j;
1410*0Sstevel@tonic-gate 			if (devp = mc_node_get(devid, device_head)) {
1411*0Sstevel@tonic-gate 				mc_node_del((mc_dlist_t *)devp,
1412*0Sstevel@tonic-gate 				    &device_head, &device_tail);
1413*0Sstevel@tonic-gate 				kmem_free(devp, sizeof (*devp));
1414*0Sstevel@tonic-gate 			} else
1415*0Sstevel@tonic-gate 				DPRINTF(MC_DESTRC_DEBUG,
1416*0Sstevel@tonic-gate 				    ("mc_delete: no dev %d\n", devid));
1417*0Sstevel@tonic-gate 		}
1418*0Sstevel@tonic-gate 
1419*0Sstevel@tonic-gate 		mc_node_del((mc_dlist_t *)dgrp, &dgrp_head, &dgrp_tail);
1420*0Sstevel@tonic-gate 		kmem_free(dgrp, sizeof (*dgrp));
1421*0Sstevel@tonic-gate 	}
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 	/* delete all banks and associated segments */
1424*0Sstevel@tonic-gate 	for (i = 0; i < NLOGBANKS_PER_MC; i++) {
1425*0Sstevel@tonic-gate 		bankid = mc_id * NLOGBANKS_PER_MC + i;
1426*0Sstevel@tonic-gate 		if (!(banki = mc_node_get(bankid, bank_head))) {
1427*0Sstevel@tonic-gate 			continue;
1428*0Sstevel@tonic-gate 		}
1429*0Sstevel@tonic-gate 
1430*0Sstevel@tonic-gate 		/* bank and segments go together */
1431*0Sstevel@tonic-gate 		if (!(segi = mc_node_get(banki->seg_id, seg_head))) {
1432*0Sstevel@tonic-gate 			mc_node_del((mc_dlist_t *)segi, &seg_head, &seg_tail);
1433*0Sstevel@tonic-gate 			kmem_free(segi, sizeof (*segi));
1434*0Sstevel@tonic-gate 			nsegments--;
1435*0Sstevel@tonic-gate 		}
1436*0Sstevel@tonic-gate 
1437*0Sstevel@tonic-gate 		mc_node_del((mc_dlist_t *)banki, &bank_head, &bank_tail);
1438*0Sstevel@tonic-gate 		kmem_free(banki, sizeof (*banki));
1439*0Sstevel@tonic-gate 	}
1440*0Sstevel@tonic-gate 
1441*0Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1442*0Sstevel@tonic-gate }
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate /*
1445*0Sstevel@tonic-gate  * mc_dlist is a double linking list, including unique id, and pointers to
1446*0Sstevel@tonic-gate  * next, and previous nodes. seg_info, bank_info, dgrp_info, device_info,
1447*0Sstevel@tonic-gate  * and mctrl_info has it at the top to share the operations, add, del, and get.
1448*0Sstevel@tonic-gate  *
1449*0Sstevel@tonic-gate  * The new node is added at the tail and is not sorted.
1450*0Sstevel@tonic-gate  *
1451*0Sstevel@tonic-gate  * Input: The pointer of node to be added, head and tail of the list
1452*0Sstevel@tonic-gate  */
1453*0Sstevel@tonic-gate 
1454*0Sstevel@tonic-gate static void
1455*0Sstevel@tonic-gate mc_node_add(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail)
1456*0Sstevel@tonic-gate {
1457*0Sstevel@tonic-gate 	DPRINTF(MC_LIST_DEBUG, ("mc_node_add: node->id %d head %p tail %p\n",
1458*0Sstevel@tonic-gate 	    node->id, (void *) *head, (void *) *tail));
1459*0Sstevel@tonic-gate 
1460*0Sstevel@tonic-gate 	if (*head != NULL) {
1461*0Sstevel@tonic-gate 		node->prev = *tail;
1462*0Sstevel@tonic-gate 		node->next = (*tail)->next;
1463*0Sstevel@tonic-gate 		(*tail)->next = node;
1464*0Sstevel@tonic-gate 		*tail = node;
1465*0Sstevel@tonic-gate 	} else {
1466*0Sstevel@tonic-gate 		node->next = node->prev = NULL;
1467*0Sstevel@tonic-gate 		*head = *tail = node;
1468*0Sstevel@tonic-gate 	}
1469*0Sstevel@tonic-gate }
1470*0Sstevel@tonic-gate 
1471*0Sstevel@tonic-gate /*
1472*0Sstevel@tonic-gate  * Input: The pointer of node to be deleted, head and tail of the list
1473*0Sstevel@tonic-gate  *
1474*0Sstevel@tonic-gate  * Deleted node will be at the following positions
1475*0Sstevel@tonic-gate  * 1. At the tail of the list
1476*0Sstevel@tonic-gate  * 2. At the head of the list
1477*0Sstevel@tonic-gate  * 3. At the head and tail of the list, i.e. only one left.
1478*0Sstevel@tonic-gate  * 4. At the middle of the list
1479*0Sstevel@tonic-gate  */
1480*0Sstevel@tonic-gate 
1481*0Sstevel@tonic-gate static void
1482*0Sstevel@tonic-gate mc_node_del(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail)
1483*0Sstevel@tonic-gate {
1484*0Sstevel@tonic-gate 	if (node->next == NULL) {
1485*0Sstevel@tonic-gate 		/* deleted node is at the tail of list */
1486*0Sstevel@tonic-gate 		*tail = node->prev;
1487*0Sstevel@tonic-gate 	} else {
1488*0Sstevel@tonic-gate 		node->next->prev = node->prev;
1489*0Sstevel@tonic-gate 	}
1490*0Sstevel@tonic-gate 
1491*0Sstevel@tonic-gate 	if (node->prev == NULL) {
1492*0Sstevel@tonic-gate 		/* deleted node is at the head of list */
1493*0Sstevel@tonic-gate 		*head = node->next;
1494*0Sstevel@tonic-gate 	} else {
1495*0Sstevel@tonic-gate 		node->prev->next = node->next;
1496*0Sstevel@tonic-gate 	}
1497*0Sstevel@tonic-gate }
1498*0Sstevel@tonic-gate 
1499*0Sstevel@tonic-gate /*
1500*0Sstevel@tonic-gate  * Search the list from the head of the list to match the given id
1501*0Sstevel@tonic-gate  * Input: id and the head of the list
1502*0Sstevel@tonic-gate  * Return: pointer of found node
1503*0Sstevel@tonic-gate  */
1504*0Sstevel@tonic-gate static void *
1505*0Sstevel@tonic-gate mc_node_get(int id, mc_dlist_t *head)
1506*0Sstevel@tonic-gate {
1507*0Sstevel@tonic-gate 	mc_dlist_t *node;
1508*0Sstevel@tonic-gate 
1509*0Sstevel@tonic-gate 	node = head;
1510*0Sstevel@tonic-gate 	while (node != NULL) {
1511*0Sstevel@tonic-gate 		DPRINTF(MC_LIST_DEBUG, ("mc_node_get: id %d, given id %d\n",
1512*0Sstevel@tonic-gate 		    node->id, id));
1513*0Sstevel@tonic-gate 		if (node->id == id)
1514*0Sstevel@tonic-gate 			break;
1515*0Sstevel@tonic-gate 		node = node->next;
1516*0Sstevel@tonic-gate 	}
1517*0Sstevel@tonic-gate 	return (node);
1518*0Sstevel@tonic-gate }
1519*0Sstevel@tonic-gate 
1520*0Sstevel@tonic-gate /*
1521*0Sstevel@tonic-gate  * Memory subsystem provides 144 bits (128 Data bits, 9 ECC bits and 7
1522*0Sstevel@tonic-gate  * unused bits) interface via a pair of DIMMs. Mapping of Data/ECC bits
1523*0Sstevel@tonic-gate  * to a specific DIMM pin is described by the memory-layout property
1524*0Sstevel@tonic-gate  * via two tables: dimm table and pin table.
1525*0Sstevel@tonic-gate  *
1526*0Sstevel@tonic-gate  * Memory-layout property arranges data/ecc bits in the following order:
1527*0Sstevel@tonic-gate  *
1528*0Sstevel@tonic-gate  *   Bit#  143                          16 15       7 6           0
1529*0Sstevel@tonic-gate  *        |      Data[127:0]              | ECC[8:0] | Unused[6:0] |
1530*0Sstevel@tonic-gate  *
1531*0Sstevel@tonic-gate  * dimm table: 1 bit is used to store DIMM number (2 possible DIMMs) for
1532*0Sstevel@tonic-gate  *	each Data/ECC bit. Thus, it needs 18 bytes (144/8) to represent
1533*0Sstevel@tonic-gate  *	all Data/ECC bits in this table. Information is stored in big
1534*0Sstevel@tonic-gate  *	endian order, i.e. dimm_table[0] represents information for
1535*0Sstevel@tonic-gate  *	logical bit# 143 to 136.
1536*0Sstevel@tonic-gate  *
1537*0Sstevel@tonic-gate  * pin table: 1 byte is used to store pin position for each Data/ECC bit.
1538*0Sstevel@tonic-gate  *	Thus, this table is 144 bytes long. Information is stored in little
1539*0Sstevel@tonic-gate  *	endian order, i.e, pin_table[0] represents pin number of logical
1540*0Sstevel@tonic-gate  *	bit 0 and pin_table[143] contains pin number for logical bit 143
1541*0Sstevel@tonic-gate  *	(i.e. data bit# 127).
1542*0Sstevel@tonic-gate  *
1543*0Sstevel@tonic-gate  * qwordmap table below is used to map mc_get_mem_unum "synd_code" value into
1544*0Sstevel@tonic-gate  * logical bit position assigned above by the memory-layout property.
1545*0Sstevel@tonic-gate  */
1546*0Sstevel@tonic-gate 
1547*0Sstevel@tonic-gate #define	QWORD_SIZE	144
1548*0Sstevel@tonic-gate static uint8_t qwordmap[QWORD_SIZE] =
1549*0Sstevel@tonic-gate {
1550*0Sstevel@tonic-gate 16,   17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
1551*0Sstevel@tonic-gate 32,   33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
1552*0Sstevel@tonic-gate 48,   49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
1553*0Sstevel@tonic-gate 64,   65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
1554*0Sstevel@tonic-gate 80,   81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
1555*0Sstevel@tonic-gate 96,   97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
1556*0Sstevel@tonic-gate 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
1557*0Sstevel@tonic-gate 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
1558*0Sstevel@tonic-gate 7,    8,   9,  10,  11,  12,  13,  14,  15,   4,   5,   6,   0,   1,   2,   3
1559*0Sstevel@tonic-gate };
1560*0Sstevel@tonic-gate 
1561*0Sstevel@tonic-gate 
1562*0Sstevel@tonic-gate /* ARGSUSED */
1563*0Sstevel@tonic-gate static int
1564*0Sstevel@tonic-gate mc_get_mem_unum(int synd_code, uint64_t paddr, char *buf, int buflen, int *lenp)
1565*0Sstevel@tonic-gate {
1566*0Sstevel@tonic-gate 	int i;
1567*0Sstevel@tonic-gate 	int pos_cacheline, position, index, idx4dimm;
1568*0Sstevel@tonic-gate 	int qwlayout = synd_code;
1569*0Sstevel@tonic-gate 	short offset, data;
1570*0Sstevel@tonic-gate 	char unum[UNUM_NAMLEN];
1571*0Sstevel@tonic-gate 	struct dimm_info *dimmp;
1572*0Sstevel@tonic-gate 	struct pin_info *pinp;
1573*0Sstevel@tonic-gate 	struct bank_info *bank;
1574*0Sstevel@tonic-gate 	struct mctrl_info *mctrl;
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate 	/*
1577*0Sstevel@tonic-gate 	 * Enforce old Openboot requirement for synd code, either a single-bit
1578*0Sstevel@tonic-gate 	 * code from 0..QWORD_SIZE-1 or -1 (multi-bit error).
1579*0Sstevel@tonic-gate 	 */
1580*0Sstevel@tonic-gate 	if (qwlayout < -1 || qwlayout >= QWORD_SIZE)
1581*0Sstevel@tonic-gate 		return (EINVAL);
1582*0Sstevel@tonic-gate 
1583*0Sstevel@tonic-gate 	unum[0] = '\0';
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate 	DPRINTF(MC_GUNUM_DEBUG, ("mc_get_mem_unum:qwlayout %d phyaddr 0x%lx\n",
1586*0Sstevel@tonic-gate 	    qwlayout, paddr));
1587*0Sstevel@tonic-gate 
1588*0Sstevel@tonic-gate 	/*
1589*0Sstevel@tonic-gate 	 * Scan all logical banks to get one responding to the physical
1590*0Sstevel@tonic-gate 	 * address. Then compute the index to look up dimm and pin tables
1591*0Sstevel@tonic-gate 	 * to generate the unmuber.
1592*0Sstevel@tonic-gate 	 */
1593*0Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
1594*0Sstevel@tonic-gate 	bank = (struct bank_info *)bank_head;
1595*0Sstevel@tonic-gate 	while (bank != NULL) {
1596*0Sstevel@tonic-gate 		int mcid, mcdgrpid, dimmoffset;
1597*0Sstevel@tonic-gate 
1598*0Sstevel@tonic-gate 		/*
1599*0Sstevel@tonic-gate 		 * Physical Address is in a bank if (Addr & Mask) == Match
1600*0Sstevel@tonic-gate 		 */
1601*0Sstevel@tonic-gate 		if ((paddr & bank->mask) != bank->match) {
1602*0Sstevel@tonic-gate 			bank = (struct bank_info *)bank->bank_node.next;
1603*0Sstevel@tonic-gate 			continue;
1604*0Sstevel@tonic-gate 		}
1605*0Sstevel@tonic-gate 
1606*0Sstevel@tonic-gate 		mcid = bank->bank_node.id / NLOGBANKS_PER_MC;
1607*0Sstevel@tonic-gate 		mctrl = mc_node_get(mcid, mctrl_head);
1608*0Sstevel@tonic-gate 		ASSERT(mctrl != NULL);
1609*0Sstevel@tonic-gate 
1610*0Sstevel@tonic-gate 		DPRINTF(MC_GUNUM_DEBUG, ("mc_get_mem_unum:mc %d bank %d "
1611*0Sstevel@tonic-gate 		    "dgrp %d\n", mcid, bank->bank_node.id, bank->devgrp_id));
1612*0Sstevel@tonic-gate 
1613*0Sstevel@tonic-gate 		mcdgrpid = bank->devgrp_id % NDGRPS_PER_MC;
1614*0Sstevel@tonic-gate 		dimmoffset = mcdgrpid * NDIMMS_PER_DGRP;
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate 		dimmp = (struct dimm_info *)mctrl->dimminfop;
1617*0Sstevel@tonic-gate 		if (dimmp == NULL) {
1618*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
1619*0Sstevel@tonic-gate 			return (ENXIO);
1620*0Sstevel@tonic-gate 		}
1621*0Sstevel@tonic-gate 
1622*0Sstevel@tonic-gate 		if ((qwlayout >= 0) && (qwlayout < QWORD_SIZE)) {
1623*0Sstevel@tonic-gate 			/*
1624*0Sstevel@tonic-gate 			 * single-bit error handling, we can identify specific
1625*0Sstevel@tonic-gate 			 * DIMM.
1626*0Sstevel@tonic-gate 			 */
1627*0Sstevel@tonic-gate 
1628*0Sstevel@tonic-gate 			pinp = (struct pin_info *)&dimmp->data[0];
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 			pos_cacheline = qwordmap[qwlayout];
1631*0Sstevel@tonic-gate 			position = 143 - pos_cacheline;
1632*0Sstevel@tonic-gate 			index = position / 8;
1633*0Sstevel@tonic-gate 			offset = 7 - (position % 8);
1634*0Sstevel@tonic-gate 
1635*0Sstevel@tonic-gate 			DPRINTF(MC_GUNUM_DEBUG, ("mc_get_mem_unum:position "
1636*0Sstevel@tonic-gate 			    "%d\n", position));
1637*0Sstevel@tonic-gate 			/*
1638*0Sstevel@tonic-gate 			 * Trade-off: We cound't add pin number to
1639*0Sstevel@tonic-gate 			 * unumber string because statistic number
1640*0Sstevel@tonic-gate 			 * pumps up at the corresponding dimm not pin.
1641*0Sstevel@tonic-gate 			 * (void) sprintf(unum, "Pin %1u ", (uint_t)
1642*0Sstevel@tonic-gate 			 * pinp->pintable[pos_cacheline]);
1643*0Sstevel@tonic-gate 			 */
1644*0Sstevel@tonic-gate 			DPRINTF(MC_GUNUM_DEBUG, ("mc_get_mem_unum:pin number "
1645*0Sstevel@tonic-gate 			    "%1u\n", (uint_t)pinp->pintable[pos_cacheline]));
1646*0Sstevel@tonic-gate 			data = pinp->dimmtable[index];
1647*0Sstevel@tonic-gate 			idx4dimm = (data >> offset) & 1;
1648*0Sstevel@tonic-gate 
1649*0Sstevel@tonic-gate 			(void) strncpy(unum,
1650*0Sstevel@tonic-gate 			    (char *)dimmp->label[dimmoffset + idx4dimm],
1651*0Sstevel@tonic-gate 			    UNUM_NAMLEN);
1652*0Sstevel@tonic-gate 
1653*0Sstevel@tonic-gate 			DPRINTF(MC_GUNUM_DEBUG,
1654*0Sstevel@tonic-gate 				("mc_get_mem_unum:unum %s\n", unum));
1655*0Sstevel@tonic-gate 
1656*0Sstevel@tonic-gate 			/*
1657*0Sstevel@tonic-gate 			 * platform hook for adding label information to unum.
1658*0Sstevel@tonic-gate 			 */
1659*0Sstevel@tonic-gate 			mc_add_mem_unum_label(unum, mcid, mcdgrpid, idx4dimm);
1660*0Sstevel@tonic-gate 		} else {
1661*0Sstevel@tonic-gate 			char *p = unum;
1662*0Sstevel@tonic-gate 			size_t res = UNUM_NAMLEN;
1663*0Sstevel@tonic-gate 
1664*0Sstevel@tonic-gate 			/*
1665*0Sstevel@tonic-gate 			 * multi-bit error handling, we can only identify
1666*0Sstevel@tonic-gate 			 * bank of DIMMs.
1667*0Sstevel@tonic-gate 			 */
1668*0Sstevel@tonic-gate 
1669*0Sstevel@tonic-gate 			for (i = 0; (i < NDIMMS_PER_DGRP) && (res > 0); i++) {
1670*0Sstevel@tonic-gate 				(void) snprintf(p, res, "%s%s",
1671*0Sstevel@tonic-gate 				    i == 0 ? "" : " ",
1672*0Sstevel@tonic-gate 				    (char *)dimmp->label[dimmoffset + i]);
1673*0Sstevel@tonic-gate 				res -= strlen(p);
1674*0Sstevel@tonic-gate 				p += strlen(p);
1675*0Sstevel@tonic-gate 			}
1676*0Sstevel@tonic-gate 
1677*0Sstevel@tonic-gate 			/*
1678*0Sstevel@tonic-gate 			 * platform hook for adding label information
1679*0Sstevel@tonic-gate 			 * to unum.
1680*0Sstevel@tonic-gate 			 */
1681*0Sstevel@tonic-gate 			mc_add_mem_unum_label(unum, mcid, mcdgrpid, -1);
1682*0Sstevel@tonic-gate 		}
1683*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
1684*0Sstevel@tonic-gate 		if ((strlen(unum) >= UNUM_NAMLEN) ||
1685*0Sstevel@tonic-gate 		    (strlen(unum) >= buflen)) {
1686*0Sstevel@tonic-gate 			return (ENOSPC);
1687*0Sstevel@tonic-gate 		} else {
1688*0Sstevel@tonic-gate 			(void) strncpy(buf, unum, UNUM_NAMLEN);
1689*0Sstevel@tonic-gate 			*lenp = strlen(buf);
1690*0Sstevel@tonic-gate 			return (0);
1691*0Sstevel@tonic-gate 		}
1692*0Sstevel@tonic-gate 	}	/* end of while loop for logic bank list */
1693*0Sstevel@tonic-gate 
1694*0Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1695*0Sstevel@tonic-gate 	return (ENXIO);
1696*0Sstevel@tonic-gate }
1697*0Sstevel@tonic-gate 
1698*0Sstevel@tonic-gate static int
1699*0Sstevel@tonic-gate mc_get_mem_info(int synd_code, uint64_t paddr,
1700*0Sstevel@tonic-gate     uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep,
1701*0Sstevel@tonic-gate     int *segsp, int *banksp, int *mcidp)
1702*0Sstevel@tonic-gate {
1703*0Sstevel@tonic-gate 	struct bank_info *bankp;
1704*0Sstevel@tonic-gate 
1705*0Sstevel@tonic-gate 	if (synd_code < -1 || synd_code >= QWORD_SIZE)
1706*0Sstevel@tonic-gate 		return (EINVAL);
1707*0Sstevel@tonic-gate 
1708*0Sstevel@tonic-gate 	/*
1709*0Sstevel@tonic-gate 	 * Scan all logical banks to get one responding to the physical
1710*0Sstevel@tonic-gate 	 * address. Then compute the index to look up dimm and pin tables
1711*0Sstevel@tonic-gate 	 * to generate the unmuber.
1712*0Sstevel@tonic-gate 	 */
1713*0Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
1714*0Sstevel@tonic-gate 	bankp = (struct bank_info *)bank_head;
1715*0Sstevel@tonic-gate 	while (bankp != NULL) {
1716*0Sstevel@tonic-gate 		struct seg_info *segp;
1717*0Sstevel@tonic-gate 		int mcid;
1718*0Sstevel@tonic-gate 
1719*0Sstevel@tonic-gate 		/*
1720*0Sstevel@tonic-gate 		 * Physical Address is in a bank if (Addr & Mask) == Match
1721*0Sstevel@tonic-gate 		 */
1722*0Sstevel@tonic-gate 		if ((paddr & bankp->mask) != bankp->match) {
1723*0Sstevel@tonic-gate 			bankp = (struct bank_info *)bankp->bank_node.next;
1724*0Sstevel@tonic-gate 			continue;
1725*0Sstevel@tonic-gate 		}
1726*0Sstevel@tonic-gate 
1727*0Sstevel@tonic-gate 		mcid = bankp->bank_node.id / NLOGBANKS_PER_MC;
1728*0Sstevel@tonic-gate 
1729*0Sstevel@tonic-gate 		/*
1730*0Sstevel@tonic-gate 		 * Get the corresponding segment.
1731*0Sstevel@tonic-gate 		 */
1732*0Sstevel@tonic-gate 		if ((segp = (struct seg_info *)mc_node_get(bankp->seg_id,
1733*0Sstevel@tonic-gate 		    seg_head)) == NULL) {
1734*0Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
1735*0Sstevel@tonic-gate 			return (EFAULT);
1736*0Sstevel@tonic-gate 		}
1737*0Sstevel@tonic-gate 
1738*0Sstevel@tonic-gate 		*mem_sizep = memsize;
1739*0Sstevel@tonic-gate 		*seg_sizep = segp->size;
1740*0Sstevel@tonic-gate 		*bank_sizep = bankp->size;
1741*0Sstevel@tonic-gate 		*segsp = nsegments;
1742*0Sstevel@tonic-gate 		*banksp = segp->nbanks;
1743*0Sstevel@tonic-gate 		*mcidp = mcid;
1744*0Sstevel@tonic-gate 
1745*0Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
1746*0Sstevel@tonic-gate 		return (0);
1747*0Sstevel@tonic-gate 
1748*0Sstevel@tonic-gate 	}	/* end of while loop for logic bank list */
1749*0Sstevel@tonic-gate 
1750*0Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1751*0Sstevel@tonic-gate 	return (ENXIO);
1752*0Sstevel@tonic-gate }
1753*0Sstevel@tonic-gate /*
1754*0Sstevel@tonic-gate  * mc-us3i driver allows a platform to add extra label
1755*0Sstevel@tonic-gate  * information to the unum string. If a platform implements a
1756*0Sstevel@tonic-gate  * kernel function called plat_add_mem_unum_label() it will be
1757*0Sstevel@tonic-gate  * executed. This would typically be implemented in the platmod.
1758*0Sstevel@tonic-gate  */
1759*0Sstevel@tonic-gate static void
1760*0Sstevel@tonic-gate mc_add_mem_unum_label(char *unum, int mcid, int bank, int dimm)
1761*0Sstevel@tonic-gate {
1762*0Sstevel@tonic-gate 	if (&plat_add_mem_unum_label)
1763*0Sstevel@tonic-gate 		plat_add_mem_unum_label(unum, mcid, bank, dimm);
1764*0Sstevel@tonic-gate }
1765