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