xref: /illumos-gate/usr/src/uts/sun4u/opl/io/drmach.c (revision 25cf1a30)
1*25cf1a30Sjl /*
2*25cf1a30Sjl  * CDDL HEADER START
3*25cf1a30Sjl  *
4*25cf1a30Sjl  * The contents of this file are subject to the terms of the
5*25cf1a30Sjl  * Common Development and Distribution License (the "License").
6*25cf1a30Sjl  * You may not use this file except in compliance with the License.
7*25cf1a30Sjl  *
8*25cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*25cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
10*25cf1a30Sjl  * See the License for the specific language governing permissions
11*25cf1a30Sjl  * and limitations under the License.
12*25cf1a30Sjl  *
13*25cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
14*25cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*25cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
16*25cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
17*25cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18*25cf1a30Sjl  *
19*25cf1a30Sjl  * CDDL HEADER END
20*25cf1a30Sjl  */
21*25cf1a30Sjl /*
22*25cf1a30Sjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*25cf1a30Sjl  * Use is subject to license terms.
24*25cf1a30Sjl  */
25*25cf1a30Sjl 
26*25cf1a30Sjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*25cf1a30Sjl 
28*25cf1a30Sjl #include <sys/debug.h>
29*25cf1a30Sjl #include <sys/types.h>
30*25cf1a30Sjl #include <sys/varargs.h>
31*25cf1a30Sjl #include <sys/errno.h>
32*25cf1a30Sjl #include <sys/cred.h>
33*25cf1a30Sjl #include <sys/dditypes.h>
34*25cf1a30Sjl #include <sys/devops.h>
35*25cf1a30Sjl #include <sys/modctl.h>
36*25cf1a30Sjl #include <sys/poll.h>
37*25cf1a30Sjl #include <sys/conf.h>
38*25cf1a30Sjl #include <sys/ddi.h>
39*25cf1a30Sjl #include <sys/sunddi.h>
40*25cf1a30Sjl #include <sys/sunndi.h>
41*25cf1a30Sjl #include <sys/ndi_impldefs.h>
42*25cf1a30Sjl #include <sys/stat.h>
43*25cf1a30Sjl #include <sys/kmem.h>
44*25cf1a30Sjl #include <sys/vmem.h>
45*25cf1a30Sjl #include <sys/opl_olympus_regs.h>
46*25cf1a30Sjl #include <sys/cpuvar.h>
47*25cf1a30Sjl #include <sys/cpupart.h>
48*25cf1a30Sjl #include <sys/mem_config.h>
49*25cf1a30Sjl #include <sys/ddi_impldefs.h>
50*25cf1a30Sjl #include <sys/systm.h>
51*25cf1a30Sjl #include <sys/machsystm.h>
52*25cf1a30Sjl #include <sys/autoconf.h>
53*25cf1a30Sjl #include <sys/cmn_err.h>
54*25cf1a30Sjl #include <sys/sysmacros.h>
55*25cf1a30Sjl #include <sys/x_call.h>
56*25cf1a30Sjl #include <sys/promif.h>
57*25cf1a30Sjl #include <sys/prom_plat.h>
58*25cf1a30Sjl #include <sys/membar.h>
59*25cf1a30Sjl #include <vm/seg_kmem.h>
60*25cf1a30Sjl #include <sys/mem_cage.h>
61*25cf1a30Sjl #include <sys/stack.h>
62*25cf1a30Sjl #include <sys/archsystm.h>
63*25cf1a30Sjl #include <vm/hat_sfmmu.h>
64*25cf1a30Sjl #include <sys/pte.h>
65*25cf1a30Sjl #include <sys/mmu.h>
66*25cf1a30Sjl #include <sys/cpu_module.h>
67*25cf1a30Sjl #include <sys/obpdefs.h>
68*25cf1a30Sjl #include <sys/note.h>
69*25cf1a30Sjl #include <sys/ontrap.h>
70*25cf1a30Sjl #include <sys/cpu_sgnblk_defs.h>
71*25cf1a30Sjl #include <sys/opl.h>
72*25cf1a30Sjl 
73*25cf1a30Sjl 
74*25cf1a30Sjl #include <sys/promimpl.h>
75*25cf1a30Sjl #include <sys/prom_plat.h>
76*25cf1a30Sjl #include <sys/kobj.h>
77*25cf1a30Sjl 
78*25cf1a30Sjl #include <sys/sysevent.h>
79*25cf1a30Sjl #include <sys/sysevent/dr.h>
80*25cf1a30Sjl #include <sys/sysevent/eventdefs.h>
81*25cf1a30Sjl 
82*25cf1a30Sjl #include <sys/drmach.h>
83*25cf1a30Sjl #include <sys/dr_util.h>
84*25cf1a30Sjl 
85*25cf1a30Sjl #include <sys/fcode.h>
86*25cf1a30Sjl #include <sys/opl_cfg.h>
87*25cf1a30Sjl 
88*25cf1a30Sjl extern void		bcopy32_il(uint64_t, uint64_t);
89*25cf1a30Sjl extern void		flush_cache_il(void);
90*25cf1a30Sjl extern void		drmach_sleep_il(void);
91*25cf1a30Sjl 
92*25cf1a30Sjl typedef struct {
93*25cf1a30Sjl 	struct drmach_node	*node;
94*25cf1a30Sjl 	void			*data;
95*25cf1a30Sjl } drmach_node_walk_args_t;
96*25cf1a30Sjl 
97*25cf1a30Sjl typedef struct drmach_node {
98*25cf1a30Sjl 	void		*here;
99*25cf1a30Sjl 
100*25cf1a30Sjl 	pnode_t		(*get_dnode)(struct drmach_node *node);
101*25cf1a30Sjl 	int		(*walk)(struct drmach_node *node, void *data,
102*25cf1a30Sjl 				int (*cb)(drmach_node_walk_args_t *args));
103*25cf1a30Sjl 	dev_info_t	*(*n_getdip)(struct drmach_node *node);
104*25cf1a30Sjl 	int		(*n_getproplen)(struct drmach_node *node, char *name,
105*25cf1a30Sjl 				int *len);
106*25cf1a30Sjl 	int		(*n_getprop)(struct drmach_node *node, char *name,
107*25cf1a30Sjl 				void *buf, int len);
108*25cf1a30Sjl 	int		(*get_parent)(struct drmach_node *node,
109*25cf1a30Sjl 				struct drmach_node *pnode);
110*25cf1a30Sjl } drmach_node_t;
111*25cf1a30Sjl 
112*25cf1a30Sjl typedef struct {
113*25cf1a30Sjl 	int		 min_index;
114*25cf1a30Sjl 	int		 max_index;
115*25cf1a30Sjl 	int		 arr_sz;
116*25cf1a30Sjl 	drmachid_t	*arr;
117*25cf1a30Sjl } drmach_array_t;
118*25cf1a30Sjl 
119*25cf1a30Sjl typedef struct {
120*25cf1a30Sjl 	void		*isa;
121*25cf1a30Sjl 
122*25cf1a30Sjl 	void		(*dispose)(drmachid_t);
123*25cf1a30Sjl 	sbd_error_t	*(*release)(drmachid_t);
124*25cf1a30Sjl 	sbd_error_t	*(*status)(drmachid_t, drmach_status_t *);
125*25cf1a30Sjl 
126*25cf1a30Sjl 	char		 name[MAXNAMELEN];
127*25cf1a30Sjl } drmach_common_t;
128*25cf1a30Sjl 
129*25cf1a30Sjl typedef	struct {
130*25cf1a30Sjl 	uint32_t	core_present;
131*25cf1a30Sjl 	uint32_t	core_hotadded;
132*25cf1a30Sjl 	uint32_t	core_started;
133*25cf1a30Sjl } drmach_cmp_t;
134*25cf1a30Sjl 
135*25cf1a30Sjl typedef struct {
136*25cf1a30Sjl 	drmach_common_t	 cm;
137*25cf1a30Sjl 	int		 bnum;
138*25cf1a30Sjl 	int		 assigned;
139*25cf1a30Sjl 	int		 powered;
140*25cf1a30Sjl 	int		 connected;
141*25cf1a30Sjl 	int		 cond;
142*25cf1a30Sjl 	drmach_node_t	*tree;
143*25cf1a30Sjl 	drmach_array_t	*devices;
144*25cf1a30Sjl 	int		boot_board;	/* if board exists on bootup */
145*25cf1a30Sjl 	drmach_cmp_t	cores[OPL_MAX_COREID_PER_BOARD];
146*25cf1a30Sjl } drmach_board_t;
147*25cf1a30Sjl 
148*25cf1a30Sjl typedef struct {
149*25cf1a30Sjl 	drmach_common_t	 cm;
150*25cf1a30Sjl 	drmach_board_t	*bp;
151*25cf1a30Sjl 	int		 unum;
152*25cf1a30Sjl 	int		portid;
153*25cf1a30Sjl 	int		 busy;
154*25cf1a30Sjl 	int		 powered;
155*25cf1a30Sjl 	const char	*type;
156*25cf1a30Sjl 	drmach_node_t	*node;
157*25cf1a30Sjl } drmach_device_t;
158*25cf1a30Sjl 
159*25cf1a30Sjl typedef struct drmach_cpu {
160*25cf1a30Sjl 	drmach_device_t  dev;
161*25cf1a30Sjl 	processorid_t    cpuid;
162*25cf1a30Sjl 	int		sb;
163*25cf1a30Sjl 	int		chipid;
164*25cf1a30Sjl 	int		coreid;
165*25cf1a30Sjl 	int		strandid;
166*25cf1a30Sjl 	int		status;
167*25cf1a30Sjl #define	OPL_CPU_HOTADDED	1
168*25cf1a30Sjl } drmach_cpu_t;
169*25cf1a30Sjl 
170*25cf1a30Sjl typedef struct drmach_mem {
171*25cf1a30Sjl 	drmach_device_t  dev;
172*25cf1a30Sjl 	uint64_t	slice_base;
173*25cf1a30Sjl 	uint64_t	slice_size;
174*25cf1a30Sjl 	uint64_t	base_pa;	/* lowest installed memory base */
175*25cf1a30Sjl 	uint64_t	nbytes;		/* size of installed memory */
176*25cf1a30Sjl 	struct memlist *memlist;
177*25cf1a30Sjl } drmach_mem_t;
178*25cf1a30Sjl 
179*25cf1a30Sjl typedef struct drmach_io {
180*25cf1a30Sjl 	drmach_device_t  dev;
181*25cf1a30Sjl 	int	channel;
182*25cf1a30Sjl 	int	leaf;
183*25cf1a30Sjl } drmach_io_t;
184*25cf1a30Sjl 
185*25cf1a30Sjl typedef struct drmach_domain_info {
186*25cf1a30Sjl 	uint32_t	floating;
187*25cf1a30Sjl 	int		allow_dr;
188*25cf1a30Sjl } drmach_domain_info_t;
189*25cf1a30Sjl 
190*25cf1a30Sjl drmach_domain_info_t drmach_domain;
191*25cf1a30Sjl 
192*25cf1a30Sjl typedef struct {
193*25cf1a30Sjl 	int		 flags;
194*25cf1a30Sjl 	drmach_device_t	*dp;
195*25cf1a30Sjl 	sbd_error_t	*err;
196*25cf1a30Sjl 	dev_info_t	*dip;
197*25cf1a30Sjl } drmach_config_args_t;
198*25cf1a30Sjl 
199*25cf1a30Sjl typedef struct {
200*25cf1a30Sjl 	drmach_board_t	*obj;
201*25cf1a30Sjl 	int		 ndevs;
202*25cf1a30Sjl 	void		*a;
203*25cf1a30Sjl 	sbd_error_t	*(*found)(void *a, const char *, int, drmachid_t);
204*25cf1a30Sjl 	sbd_error_t	*err;
205*25cf1a30Sjl } drmach_board_cb_data_t;
206*25cf1a30Sjl 
207*25cf1a30Sjl static drmach_array_t	*drmach_boards;
208*25cf1a30Sjl 
209*25cf1a30Sjl static sbd_error_t	*drmach_device_new(drmach_node_t *,
210*25cf1a30Sjl 				drmach_board_t *, int, drmachid_t *);
211*25cf1a30Sjl static sbd_error_t	*drmach_cpu_new(drmach_device_t *, drmachid_t *);
212*25cf1a30Sjl static sbd_error_t	*drmach_mem_new(drmach_device_t *, drmachid_t *);
213*25cf1a30Sjl static sbd_error_t	*drmach_io_new(drmach_device_t *, drmachid_t *);
214*25cf1a30Sjl 
215*25cf1a30Sjl static dev_info_t	*drmach_node_ddi_get_dip(drmach_node_t *np);
216*25cf1a30Sjl static int		 drmach_node_ddi_get_prop(drmach_node_t *np,
217*25cf1a30Sjl 				char *name, void *buf, int len);
218*25cf1a30Sjl static int		 drmach_node_ddi_get_proplen(drmach_node_t *np,
219*25cf1a30Sjl 				char *name, int *len);
220*25cf1a30Sjl 
221*25cf1a30Sjl static int 		drmach_get_portid(drmach_node_t *);
222*25cf1a30Sjl static	sbd_error_t	*drmach_i_status(drmachid_t, drmach_status_t *);
223*25cf1a30Sjl static int		opl_check_dr_status();
224*25cf1a30Sjl static void		drmach_io_dispose(drmachid_t);
225*25cf1a30Sjl static sbd_error_t	*drmach_io_release(drmachid_t);
226*25cf1a30Sjl static sbd_error_t	*drmach_io_status(drmachid_t, drmach_status_t *);
227*25cf1a30Sjl static int 		drmach_init(void);
228*25cf1a30Sjl static void 		drmach_fini(void);
229*25cf1a30Sjl static void		drmach_swap_pa(drmach_mem_t *, drmach_mem_t *);
230*25cf1a30Sjl static drmach_board_t	*drmach_get_board_by_bnum(int);
231*25cf1a30Sjl 
232*25cf1a30Sjl /* options for the second argument in drmach_add_remove_cpu() */
233*25cf1a30Sjl #define	HOTADD_CPU	1
234*25cf1a30Sjl #define	HOTREMOVE_CPU	2
235*25cf1a30Sjl 
236*25cf1a30Sjl #define	ON_BOARD_CORE_NUM(x)	(((uint_t)(x) / OPL_MAX_STRANDID_PER_CORE) & \
237*25cf1a30Sjl 	(OPL_MAX_COREID_PER_BOARD - 1))
238*25cf1a30Sjl 
239*25cf1a30Sjl extern struct cpu	*SIGBCPU;
240*25cf1a30Sjl 
241*25cf1a30Sjl static int		drmach_name2type_idx(char *);
242*25cf1a30Sjl static drmach_board_t	*drmach_board_new(int, int);
243*25cf1a30Sjl 
244*25cf1a30Sjl #ifdef DEBUG
245*25cf1a30Sjl 
246*25cf1a30Sjl #define	DRMACH_PR		if (drmach_debug) printf
247*25cf1a30Sjl int drmach_debug = 1;		 /* set to non-zero to enable debug messages */
248*25cf1a30Sjl #else
249*25cf1a30Sjl 
250*25cf1a30Sjl #define	DRMACH_PR		_NOTE(CONSTANTCONDITION) if (0) printf
251*25cf1a30Sjl #endif /* DEBUG */
252*25cf1a30Sjl 
253*25cf1a30Sjl 
254*25cf1a30Sjl #define	DRMACH_OBJ(id)		((drmach_common_t *)id)
255*25cf1a30Sjl 
256*25cf1a30Sjl #define	DRMACH_IS_BOARD_ID(id)	\
257*25cf1a30Sjl 	((id != 0) &&		\
258*25cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new))
259*25cf1a30Sjl 
260*25cf1a30Sjl #define	DRMACH_IS_CPU_ID(id)	\
261*25cf1a30Sjl 	((id != 0) &&		\
262*25cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new))
263*25cf1a30Sjl 
264*25cf1a30Sjl #define	DRMACH_IS_MEM_ID(id)	\
265*25cf1a30Sjl 	((id != 0) &&		\
266*25cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_mem_new))
267*25cf1a30Sjl 
268*25cf1a30Sjl #define	DRMACH_IS_IO_ID(id)	\
269*25cf1a30Sjl 	((id != 0) &&		\
270*25cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
271*25cf1a30Sjl 
272*25cf1a30Sjl #define	DRMACH_IS_DEVICE_ID(id)					\
273*25cf1a30Sjl 	((id != 0) &&						\
274*25cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
275*25cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
276*25cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
277*25cf1a30Sjl 
278*25cf1a30Sjl #define	DRMACH_IS_ID(id)					\
279*25cf1a30Sjl 	((id != 0) &&						\
280*25cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new ||	\
281*25cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
282*25cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
283*25cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
284*25cf1a30Sjl 
285*25cf1a30Sjl #define	DRMACH_INTERNAL_ERROR() \
286*25cf1a30Sjl 	drerr_new(1, EOPL_INTERNAL, drmach_ie_fmt, __LINE__)
287*25cf1a30Sjl 
288*25cf1a30Sjl static char		*drmach_ie_fmt = "drmach.c %d";
289*25cf1a30Sjl 
290*25cf1a30Sjl static struct {
291*25cf1a30Sjl 	const char	*name;
292*25cf1a30Sjl 	const char	*type;
293*25cf1a30Sjl 	sbd_error_t	*(*new)(drmach_device_t *, drmachid_t *);
294*25cf1a30Sjl } drmach_name2type[] = {
295*25cf1a30Sjl 	{ "cpu",	DRMACH_DEVTYPE_CPU,		drmach_cpu_new },
296*25cf1a30Sjl 	{ "pseudo-mc",	DRMACH_DEVTYPE_MEM,		drmach_mem_new },
297*25cf1a30Sjl 	{ "pci",	DRMACH_DEVTYPE_PCI,		drmach_io_new  },
298*25cf1a30Sjl };
299*25cf1a30Sjl 
300*25cf1a30Sjl /* utility */
301*25cf1a30Sjl #define	MBYTE	(1048576ull)
302*25cf1a30Sjl 
303*25cf1a30Sjl /*
304*25cf1a30Sjl  * drmach autoconfiguration data structures and interfaces
305*25cf1a30Sjl  */
306*25cf1a30Sjl 
307*25cf1a30Sjl extern struct mod_ops mod_miscops;
308*25cf1a30Sjl 
309*25cf1a30Sjl static struct modlmisc modlmisc = {
310*25cf1a30Sjl 	&mod_miscops,
311*25cf1a30Sjl 	"OPL DR 1.1"
312*25cf1a30Sjl };
313*25cf1a30Sjl 
314*25cf1a30Sjl static struct modlinkage modlinkage = {
315*25cf1a30Sjl 	MODREV_1,
316*25cf1a30Sjl 	(void *)&modlmisc,
317*25cf1a30Sjl 	NULL
318*25cf1a30Sjl };
319*25cf1a30Sjl 
320*25cf1a30Sjl static krwlock_t drmach_boards_rwlock;
321*25cf1a30Sjl 
322*25cf1a30Sjl typedef const char	*fn_t;
323*25cf1a30Sjl 
324*25cf1a30Sjl int
325*25cf1a30Sjl _init(void)
326*25cf1a30Sjl {
327*25cf1a30Sjl 	int err;
328*25cf1a30Sjl 
329*25cf1a30Sjl 	if ((err = drmach_init()) != 0) {
330*25cf1a30Sjl 		return (err);
331*25cf1a30Sjl 	}
332*25cf1a30Sjl 
333*25cf1a30Sjl 	if ((err = mod_install(&modlinkage)) != 0) {
334*25cf1a30Sjl 		drmach_fini();
335*25cf1a30Sjl 	}
336*25cf1a30Sjl 
337*25cf1a30Sjl 	return (err);
338*25cf1a30Sjl }
339*25cf1a30Sjl 
340*25cf1a30Sjl int
341*25cf1a30Sjl _fini(void)
342*25cf1a30Sjl {
343*25cf1a30Sjl 	int	err;
344*25cf1a30Sjl 
345*25cf1a30Sjl 	if ((err = mod_remove(&modlinkage)) == 0)
346*25cf1a30Sjl 		drmach_fini();
347*25cf1a30Sjl 
348*25cf1a30Sjl 	return (err);
349*25cf1a30Sjl }
350*25cf1a30Sjl 
351*25cf1a30Sjl int
352*25cf1a30Sjl _info(struct modinfo *modinfop)
353*25cf1a30Sjl {
354*25cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
355*25cf1a30Sjl }
356*25cf1a30Sjl 
357*25cf1a30Sjl /*
358*25cf1a30Sjl  * The following routines are used to set up the memory
359*25cf1a30Sjl  * properties in the board structure.
360*25cf1a30Sjl  */
361*25cf1a30Sjl 
362*25cf1a30Sjl struct drmach_mc_lookup {
363*25cf1a30Sjl 	int	bnum;
364*25cf1a30Sjl 	drmach_board_t	*bp;
365*25cf1a30Sjl 	dev_info_t *dip;	/* rv - set if found */
366*25cf1a30Sjl };
367*25cf1a30Sjl 
368*25cf1a30Sjl #define	_ptob64(p) ((uint64_t)(p) << PAGESHIFT)
369*25cf1a30Sjl #define	_b64top(b) ((pgcnt_t)((b) >> PAGESHIFT))
370*25cf1a30Sjl 
371*25cf1a30Sjl static int
372*25cf1a30Sjl drmach_setup_mc_info(dev_info_t *dip, drmach_mem_t *mp)
373*25cf1a30Sjl {
374*25cf1a30Sjl 	uint64_t	memory_ranges[128];
375*25cf1a30Sjl 	int len;
376*25cf1a30Sjl 	struct memlist	*ml;
377*25cf1a30Sjl 	int rv;
378*25cf1a30Sjl 	hwd_sb_t *hwd;
379*25cf1a30Sjl 	hwd_memory_t *pm;
380*25cf1a30Sjl 
381*25cf1a30Sjl 	len = sizeof (memory_ranges);
382*25cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
383*25cf1a30Sjl 		DDI_PROP_DONTPASS, "sb-mem-ranges",
384*25cf1a30Sjl 	    (caddr_t)&memory_ranges[0], &len) != DDI_PROP_SUCCESS) {
385*25cf1a30Sjl 		mp->slice_base = 0;
386*25cf1a30Sjl 		mp->slice_size = 0;
387*25cf1a30Sjl 		return (-1);
388*25cf1a30Sjl 	}
389*25cf1a30Sjl 	mp->slice_base = memory_ranges[0];
390*25cf1a30Sjl 	mp->slice_size = memory_ranges[1];
391*25cf1a30Sjl 
392*25cf1a30Sjl 	if (!mp->dev.bp->boot_board) {
393*25cf1a30Sjl 		int i;
394*25cf1a30Sjl 
395*25cf1a30Sjl 		rv = opl_read_hwd(mp->dev.bp->bnum, NULL,  NULL, NULL, &hwd);
396*25cf1a30Sjl 
397*25cf1a30Sjl 		if (rv != 0) {
398*25cf1a30Sjl 			return (-1);
399*25cf1a30Sjl 		}
400*25cf1a30Sjl 
401*25cf1a30Sjl 		ml = NULL;
402*25cf1a30Sjl 		pm = &hwd->sb_cmu.cmu_memory;
403*25cf1a30Sjl 		for (i = 0; i < HWD_MAX_MEM_CHUNKS; i++) {
404*25cf1a30Sjl 			if (pm->mem_chunks[i].chnk_size > 0) {
405*25cf1a30Sjl 				ml = memlist_add_span(ml,
406*25cf1a30Sjl 					pm->mem_chunks[i].chnk_start_address,
407*25cf1a30Sjl 					pm->mem_chunks[i].chnk_size);
408*25cf1a30Sjl 			}
409*25cf1a30Sjl 		}
410*25cf1a30Sjl 	} else {
411*25cf1a30Sjl 		/*
412*25cf1a30Sjl 		 * we intersect phys_install to get base_pa.
413*25cf1a30Sjl 		 * This only works at bootup time.
414*25cf1a30Sjl 		 */
415*25cf1a30Sjl 
416*25cf1a30Sjl 		memlist_read_lock();
417*25cf1a30Sjl 		ml = memlist_dup(phys_install);
418*25cf1a30Sjl 		memlist_read_unlock();
419*25cf1a30Sjl 
420*25cf1a30Sjl 		ml = memlist_del_span(ml, 0ull, mp->slice_base);
421*25cf1a30Sjl 		if (ml) {
422*25cf1a30Sjl 			uint64_t basepa, endpa;
423*25cf1a30Sjl 			endpa = _ptob64(physmax + 1);
424*25cf1a30Sjl 
425*25cf1a30Sjl 			basepa = mp->slice_base + mp->slice_size;
426*25cf1a30Sjl 
427*25cf1a30Sjl 			ml = memlist_del_span(ml, basepa, endpa - basepa);
428*25cf1a30Sjl 		}
429*25cf1a30Sjl 	}
430*25cf1a30Sjl 
431*25cf1a30Sjl 	if (ml) {
432*25cf1a30Sjl 		uint64_t nbytes = 0;
433*25cf1a30Sjl 		struct memlist *p;
434*25cf1a30Sjl 		for (p = ml; p; p = p->next) {
435*25cf1a30Sjl 			nbytes += p->size;
436*25cf1a30Sjl 		}
437*25cf1a30Sjl 		if ((mp->nbytes = nbytes) > 0)
438*25cf1a30Sjl 			mp->base_pa = ml->address;
439*25cf1a30Sjl 		else
440*25cf1a30Sjl 			mp->base_pa = 0;
441*25cf1a30Sjl 		mp->memlist = ml;
442*25cf1a30Sjl 	} else {
443*25cf1a30Sjl 		mp->base_pa = 0;
444*25cf1a30Sjl 		mp->nbytes = 0;
445*25cf1a30Sjl 	}
446*25cf1a30Sjl 	return (0);
447*25cf1a30Sjl }
448*25cf1a30Sjl 
449*25cf1a30Sjl 
450*25cf1a30Sjl struct drmach_hotcpu {
451*25cf1a30Sjl 	drmach_board_t *bp;
452*25cf1a30Sjl 	int	bnum;
453*25cf1a30Sjl 	int	core_id;
454*25cf1a30Sjl 	int 	rv;
455*25cf1a30Sjl 	int	option;
456*25cf1a30Sjl };
457*25cf1a30Sjl 
458*25cf1a30Sjl static int
459*25cf1a30Sjl drmach_cpu_cb(dev_info_t *dip, void *arg)
460*25cf1a30Sjl {
461*25cf1a30Sjl 	struct drmach_hotcpu *p = (struct drmach_hotcpu *)arg;
462*25cf1a30Sjl 	char name[OBP_MAXDRVNAME];
463*25cf1a30Sjl 	int len = OBP_MAXDRVNAME;
464*25cf1a30Sjl 	int bnum, core_id, strand_id;
465*25cf1a30Sjl 	drmach_board_t *bp;
466*25cf1a30Sjl 
467*25cf1a30Sjl 	if (dip == ddi_root_node()) {
468*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
469*25cf1a30Sjl 	}
470*25cf1a30Sjl 
471*25cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
472*25cf1a30Sjl 	    DDI_PROP_DONTPASS, "name",
473*25cf1a30Sjl 	    (caddr_t)name, &len) != DDI_PROP_SUCCESS) {
474*25cf1a30Sjl 		return (DDI_WALK_PRUNECHILD);
475*25cf1a30Sjl 	}
476*25cf1a30Sjl 
477*25cf1a30Sjl 	/* only cmp has board number */
478*25cf1a30Sjl 	bnum = -1;
479*25cf1a30Sjl 	len = sizeof (bnum);
480*25cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
481*25cf1a30Sjl 	    DDI_PROP_DONTPASS, OBP_BOARDNUM,
482*25cf1a30Sjl 	    (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) {
483*25cf1a30Sjl 		bnum = -1;
484*25cf1a30Sjl 	}
485*25cf1a30Sjl 
486*25cf1a30Sjl 	if (strcmp(name, "cmp") == 0) {
487*25cf1a30Sjl 		if (bnum != p->bnum)
488*25cf1a30Sjl 			return (DDI_WALK_PRUNECHILD);
489*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
490*25cf1a30Sjl 	}
491*25cf1a30Sjl 	/* we have already pruned all unwanted cores and cpu's above */
492*25cf1a30Sjl 	if (strcmp(name, "core") == 0) {
493*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
494*25cf1a30Sjl 	}
495*25cf1a30Sjl 	if (strcmp(name, "cpu") == 0) {
496*25cf1a30Sjl 		processorid_t cpuid;
497*25cf1a30Sjl 		len = sizeof (cpuid);
498*25cf1a30Sjl 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
499*25cf1a30Sjl 		    DDI_PROP_DONTPASS, "cpuid",
500*25cf1a30Sjl 		    (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) {
501*25cf1a30Sjl 			p->rv = -1;
502*25cf1a30Sjl 			return (DDI_WALK_TERMINATE);
503*25cf1a30Sjl 		}
504*25cf1a30Sjl 
505*25cf1a30Sjl 		core_id = p->core_id;
506*25cf1a30Sjl 
507*25cf1a30Sjl 		bnum = LSB_ID(cpuid);
508*25cf1a30Sjl 
509*25cf1a30Sjl 		if (ON_BOARD_CORE_NUM(cpuid) != core_id)
510*25cf1a30Sjl 			return (DDI_WALK_CONTINUE);
511*25cf1a30Sjl 
512*25cf1a30Sjl 		bp = p->bp;
513*25cf1a30Sjl 		ASSERT(bnum == bp->bnum);
514*25cf1a30Sjl 
515*25cf1a30Sjl 		if (p->option == HOTADD_CPU) {
516*25cf1a30Sjl 			if (prom_hotaddcpu(cpuid) != 0) {
517*25cf1a30Sjl 				p->rv = -1;
518*25cf1a30Sjl 				return (DDI_WALK_TERMINATE);
519*25cf1a30Sjl 			}
520*25cf1a30Sjl 			strand_id = STRAND_ID(cpuid);
521*25cf1a30Sjl 			bp->cores[core_id].core_hotadded |= (1 << strand_id);
522*25cf1a30Sjl 		} else if (p->option == HOTREMOVE_CPU) {
523*25cf1a30Sjl 			if (prom_hotremovecpu(cpuid) != 0) {
524*25cf1a30Sjl 				p->rv = -1;
525*25cf1a30Sjl 				return (DDI_WALK_TERMINATE);
526*25cf1a30Sjl 			}
527*25cf1a30Sjl 			strand_id = STRAND_ID(cpuid);
528*25cf1a30Sjl 			bp->cores[core_id].core_hotadded &= ~(1 << strand_id);
529*25cf1a30Sjl 		}
530*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
531*25cf1a30Sjl 	}
532*25cf1a30Sjl 
533*25cf1a30Sjl 	return (DDI_WALK_PRUNECHILD);
534*25cf1a30Sjl }
535*25cf1a30Sjl 
536*25cf1a30Sjl 
537*25cf1a30Sjl static int
538*25cf1a30Sjl drmach_add_remove_cpu(int bnum, int core_id, int option)
539*25cf1a30Sjl {
540*25cf1a30Sjl 	struct drmach_hotcpu arg;
541*25cf1a30Sjl 	drmach_board_t *bp;
542*25cf1a30Sjl 
543*25cf1a30Sjl 	bp = drmach_get_board_by_bnum(bnum);
544*25cf1a30Sjl 	ASSERT(bp);
545*25cf1a30Sjl 
546*25cf1a30Sjl 	arg.bp = bp;
547*25cf1a30Sjl 	arg.bnum = bnum;
548*25cf1a30Sjl 	arg.core_id = core_id;
549*25cf1a30Sjl 	arg.rv = 0;
550*25cf1a30Sjl 	arg.option = option;
551*25cf1a30Sjl 	ddi_walk_devs(ddi_root_node(), drmach_cpu_cb, (void *)&arg);
552*25cf1a30Sjl 	return (arg.rv);
553*25cf1a30Sjl }
554*25cf1a30Sjl 
555*25cf1a30Sjl struct drmach_setup_core_arg {
556*25cf1a30Sjl 	drmach_board_t *bp;
557*25cf1a30Sjl };
558*25cf1a30Sjl 
559*25cf1a30Sjl static int
560*25cf1a30Sjl drmach_setup_core_cb(dev_info_t *dip, void *arg)
561*25cf1a30Sjl {
562*25cf1a30Sjl 	struct drmach_setup_core_arg *p = (struct drmach_setup_core_arg *)arg;
563*25cf1a30Sjl 	char name[OBP_MAXDRVNAME];
564*25cf1a30Sjl 	int len = OBP_MAXDRVNAME;
565*25cf1a30Sjl 	int bnum;
566*25cf1a30Sjl 	int core_id, strand_id;
567*25cf1a30Sjl 
568*25cf1a30Sjl 	if (dip == ddi_root_node()) {
569*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
570*25cf1a30Sjl 	}
571*25cf1a30Sjl 
572*25cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
573*25cf1a30Sjl 	    DDI_PROP_DONTPASS, "name",
574*25cf1a30Sjl 	    (caddr_t)name, &len) != DDI_PROP_SUCCESS) {
575*25cf1a30Sjl 		return (DDI_WALK_PRUNECHILD);
576*25cf1a30Sjl 	}
577*25cf1a30Sjl 
578*25cf1a30Sjl 	/* only cmp has board number */
579*25cf1a30Sjl 	bnum = -1;
580*25cf1a30Sjl 	len = sizeof (bnum);
581*25cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
582*25cf1a30Sjl 	    DDI_PROP_DONTPASS, OBP_BOARDNUM,
583*25cf1a30Sjl 	    (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) {
584*25cf1a30Sjl 		bnum = -1;
585*25cf1a30Sjl 	}
586*25cf1a30Sjl 
587*25cf1a30Sjl 	if (strcmp(name, "cmp") == 0) {
588*25cf1a30Sjl 		if (bnum != p->bp->bnum)
589*25cf1a30Sjl 			return (DDI_WALK_PRUNECHILD);
590*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
591*25cf1a30Sjl 	}
592*25cf1a30Sjl 	/* we have already pruned all unwanted cores and cpu's above */
593*25cf1a30Sjl 	if (strcmp(name, "core") == 0) {
594*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
595*25cf1a30Sjl 	}
596*25cf1a30Sjl 	if (strcmp(name, "cpu") == 0) {
597*25cf1a30Sjl 		processorid_t cpuid;
598*25cf1a30Sjl 		len = sizeof (cpuid);
599*25cf1a30Sjl 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
600*25cf1a30Sjl 		    DDI_PROP_DONTPASS, "cpuid",
601*25cf1a30Sjl 		    (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) {
602*25cf1a30Sjl 			return (DDI_WALK_TERMINATE);
603*25cf1a30Sjl 		}
604*25cf1a30Sjl 		bnum = LSB_ID(cpuid);
605*25cf1a30Sjl 		ASSERT(bnum == p->bp->bnum);
606*25cf1a30Sjl 		core_id = ON_BOARD_CORE_NUM(cpuid);
607*25cf1a30Sjl 		strand_id = STRAND_ID(cpuid);
608*25cf1a30Sjl 		p->bp->cores[core_id].core_present |= (1 << strand_id);
609*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
610*25cf1a30Sjl 	}
611*25cf1a30Sjl 
612*25cf1a30Sjl 	return (DDI_WALK_PRUNECHILD);
613*25cf1a30Sjl }
614*25cf1a30Sjl 
615*25cf1a30Sjl 
616*25cf1a30Sjl static void
617*25cf1a30Sjl drmach_setup_core_info(drmach_board_t *obj)
618*25cf1a30Sjl {
619*25cf1a30Sjl 	struct drmach_setup_core_arg arg;
620*25cf1a30Sjl 	int i;
621*25cf1a30Sjl 
622*25cf1a30Sjl 	for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
623*25cf1a30Sjl 		obj->cores[i].core_present = 0;
624*25cf1a30Sjl 		obj->cores[i].core_hotadded = 0;
625*25cf1a30Sjl 		obj->cores[i].core_started = 0;
626*25cf1a30Sjl 	}
627*25cf1a30Sjl 	arg.bp = obj;
628*25cf1a30Sjl 	ddi_walk_devs(ddi_root_node(), drmach_setup_core_cb, (void *)&arg);
629*25cf1a30Sjl 
630*25cf1a30Sjl 	for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
631*25cf1a30Sjl 		if (obj->boot_board) {
632*25cf1a30Sjl 			obj->cores[i].core_hotadded =
633*25cf1a30Sjl 				obj->cores[i].core_started =
634*25cf1a30Sjl 				obj->cores[i].core_present;
635*25cf1a30Sjl 		}
636*25cf1a30Sjl 	}
637*25cf1a30Sjl }
638*25cf1a30Sjl 
639*25cf1a30Sjl /*
640*25cf1a30Sjl  * drmach_node_* routines serve the purpose of separating the
641*25cf1a30Sjl  * rest of the code from the device tree and OBP.  This is necessary
642*25cf1a30Sjl  * because of In-Kernel-Probing.  Devices probed after stod, are probed
643*25cf1a30Sjl  * by the in-kernel-prober, not OBP.  These devices, therefore, do not
644*25cf1a30Sjl  * have dnode ids.
645*25cf1a30Sjl  */
646*25cf1a30Sjl 
647*25cf1a30Sjl typedef struct {
648*25cf1a30Sjl 	drmach_node_walk_args_t	*nwargs;
649*25cf1a30Sjl 	int 			(*cb)(drmach_node_walk_args_t *args);
650*25cf1a30Sjl 	int			err;
651*25cf1a30Sjl } drmach_node_ddi_walk_args_t;
652*25cf1a30Sjl 
653*25cf1a30Sjl static int
654*25cf1a30Sjl drmach_node_ddi_walk_cb(dev_info_t *dip, void *arg)
655*25cf1a30Sjl {
656*25cf1a30Sjl 	drmach_node_ddi_walk_args_t	*nargs;
657*25cf1a30Sjl 
658*25cf1a30Sjl 	nargs = (drmach_node_ddi_walk_args_t *)arg;
659*25cf1a30Sjl 
660*25cf1a30Sjl 	/*
661*25cf1a30Sjl 	 * dip doesn't have to be held here as we are called
662*25cf1a30Sjl 	 * from ddi_walk_devs() which holds the dip.
663*25cf1a30Sjl 	 */
664*25cf1a30Sjl 	nargs->nwargs->node->here = (void *)dip;
665*25cf1a30Sjl 
666*25cf1a30Sjl 	nargs->err = nargs->cb(nargs->nwargs);
667*25cf1a30Sjl 
668*25cf1a30Sjl 
669*25cf1a30Sjl 	/*
670*25cf1a30Sjl 	 * Set "here" to NULL so that unheld dip is not accessible
671*25cf1a30Sjl 	 * outside ddi_walk_devs()
672*25cf1a30Sjl 	 */
673*25cf1a30Sjl 	nargs->nwargs->node->here = NULL;
674*25cf1a30Sjl 
675*25cf1a30Sjl 	if (nargs->err)
676*25cf1a30Sjl 		return (DDI_WALK_TERMINATE);
677*25cf1a30Sjl 	else
678*25cf1a30Sjl 		return (DDI_WALK_CONTINUE);
679*25cf1a30Sjl }
680*25cf1a30Sjl 
681*25cf1a30Sjl static int
682*25cf1a30Sjl drmach_node_ddi_walk(drmach_node_t *np, void *data,
683*25cf1a30Sjl 		int (*cb)(drmach_node_walk_args_t *args))
684*25cf1a30Sjl {
685*25cf1a30Sjl 	drmach_node_walk_args_t		args;
686*25cf1a30Sjl 	drmach_node_ddi_walk_args_t	nargs;
687*25cf1a30Sjl 
688*25cf1a30Sjl 
689*25cf1a30Sjl 	/* initialized args structure for callback */
690*25cf1a30Sjl 	args.node = np;
691*25cf1a30Sjl 	args.data = data;
692*25cf1a30Sjl 
693*25cf1a30Sjl 	nargs.nwargs = &args;
694*25cf1a30Sjl 	nargs.cb = cb;
695*25cf1a30Sjl 	nargs.err = 0;
696*25cf1a30Sjl 
697*25cf1a30Sjl 	/*
698*25cf1a30Sjl 	 * Root node doesn't have to be held in any way.
699*25cf1a30Sjl 	 */
700*25cf1a30Sjl 	ddi_walk_devs(ddi_root_node(), drmach_node_ddi_walk_cb,
701*25cf1a30Sjl 		(void *)&nargs);
702*25cf1a30Sjl 
703*25cf1a30Sjl 	return (nargs.err);
704*25cf1a30Sjl }
705*25cf1a30Sjl 
706*25cf1a30Sjl static int
707*25cf1a30Sjl drmach_node_ddi_get_parent(drmach_node_t *np, drmach_node_t *pp)
708*25cf1a30Sjl {
709*25cf1a30Sjl 	dev_info_t	*ndip;
710*25cf1a30Sjl 	static char	*fn = "drmach_node_ddi_get_parent";
711*25cf1a30Sjl 
712*25cf1a30Sjl 	ndip = np->n_getdip(np);
713*25cf1a30Sjl 	if (ndip == NULL) {
714*25cf1a30Sjl 		cmn_err(CE_WARN, "%s: NULL dip", fn);
715*25cf1a30Sjl 		return (-1);
716*25cf1a30Sjl 	}
717*25cf1a30Sjl 
718*25cf1a30Sjl 	bcopy(np, pp, sizeof (drmach_node_t));
719*25cf1a30Sjl 
720*25cf1a30Sjl 	pp->here = (void *)ddi_get_parent(ndip);
721*25cf1a30Sjl 	if (pp->here == NULL) {
722*25cf1a30Sjl 		cmn_err(CE_WARN, "%s: NULL parent dip", fn);
723*25cf1a30Sjl 		return (-1);
724*25cf1a30Sjl 	}
725*25cf1a30Sjl 
726*25cf1a30Sjl 	return (0);
727*25cf1a30Sjl }
728*25cf1a30Sjl 
729*25cf1a30Sjl /*ARGSUSED*/
730*25cf1a30Sjl static pnode_t
731*25cf1a30Sjl drmach_node_ddi_get_dnode(drmach_node_t *np)
732*25cf1a30Sjl {
733*25cf1a30Sjl 	return ((pnode_t)NULL);
734*25cf1a30Sjl }
735*25cf1a30Sjl 
736*25cf1a30Sjl static drmach_node_t *
737*25cf1a30Sjl drmach_node_new(void)
738*25cf1a30Sjl {
739*25cf1a30Sjl 	drmach_node_t *np;
740*25cf1a30Sjl 
741*25cf1a30Sjl 	np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP);
742*25cf1a30Sjl 
743*25cf1a30Sjl 	np->get_dnode = drmach_node_ddi_get_dnode;
744*25cf1a30Sjl 	np->walk = drmach_node_ddi_walk;
745*25cf1a30Sjl 	np->n_getdip = drmach_node_ddi_get_dip;
746*25cf1a30Sjl 	np->n_getproplen = drmach_node_ddi_get_proplen;
747*25cf1a30Sjl 	np->n_getprop = drmach_node_ddi_get_prop;
748*25cf1a30Sjl 	np->get_parent = drmach_node_ddi_get_parent;
749*25cf1a30Sjl 
750*25cf1a30Sjl 	return (np);
751*25cf1a30Sjl }
752*25cf1a30Sjl 
753*25cf1a30Sjl static void
754*25cf1a30Sjl drmach_node_dispose(drmach_node_t *np)
755*25cf1a30Sjl {
756*25cf1a30Sjl 	kmem_free(np, sizeof (*np));
757*25cf1a30Sjl }
758*25cf1a30Sjl 
759*25cf1a30Sjl static dev_info_t *
760*25cf1a30Sjl drmach_node_ddi_get_dip(drmach_node_t *np)
761*25cf1a30Sjl {
762*25cf1a30Sjl 	return ((dev_info_t *)np->here);
763*25cf1a30Sjl }
764*25cf1a30Sjl 
765*25cf1a30Sjl static int
766*25cf1a30Sjl drmach_node_walk(drmach_node_t *np, void *param,
767*25cf1a30Sjl 		int (*cb)(drmach_node_walk_args_t *args))
768*25cf1a30Sjl {
769*25cf1a30Sjl 	return (np->walk(np, param, cb));
770*25cf1a30Sjl }
771*25cf1a30Sjl 
772*25cf1a30Sjl static int
773*25cf1a30Sjl drmach_node_ddi_get_prop(drmach_node_t *np, char *name, void *buf, int len)
774*25cf1a30Sjl {
775*25cf1a30Sjl 	int		rv = 0;
776*25cf1a30Sjl 	dev_info_t	*ndip;
777*25cf1a30Sjl 	static char	*fn = "drmach_node_ddi_get_prop";
778*25cf1a30Sjl 
779*25cf1a30Sjl 
780*25cf1a30Sjl 	ndip = np->n_getdip(np);
781*25cf1a30Sjl 	if (ndip == NULL) {
782*25cf1a30Sjl 		cmn_err(CE_WARN, "%s: NULL dip", fn);
783*25cf1a30Sjl 		rv = -1;
784*25cf1a30Sjl 	} else if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ndip,
785*25cf1a30Sjl 	    DDI_PROP_DONTPASS, name,
786*25cf1a30Sjl 	    (caddr_t)buf, &len) != DDI_PROP_SUCCESS) {
787*25cf1a30Sjl 		rv = -1;
788*25cf1a30Sjl 	}
789*25cf1a30Sjl 
790*25cf1a30Sjl 	return (rv);
791*25cf1a30Sjl }
792*25cf1a30Sjl 
793*25cf1a30Sjl static int
794*25cf1a30Sjl drmach_node_ddi_get_proplen(drmach_node_t *np, char *name, int *len)
795*25cf1a30Sjl {
796*25cf1a30Sjl 	int		rv = 0;
797*25cf1a30Sjl 	dev_info_t	*ndip;
798*25cf1a30Sjl 
799*25cf1a30Sjl 	ndip = np->n_getdip(np);
800*25cf1a30Sjl 	if (ndip == NULL) {
801*25cf1a30Sjl 		rv = -1;
802*25cf1a30Sjl 	} else if (ddi_getproplen(DDI_DEV_T_ANY, ndip, DDI_PROP_DONTPASS,
803*25cf1a30Sjl 		name, len) != DDI_PROP_SUCCESS) {
804*25cf1a30Sjl 		rv = -1;
805*25cf1a30Sjl 	}
806*25cf1a30Sjl 
807*25cf1a30Sjl 	return (rv);
808*25cf1a30Sjl }
809*25cf1a30Sjl 
810*25cf1a30Sjl static drmachid_t
811*25cf1a30Sjl drmach_node_dup(drmach_node_t *np)
812*25cf1a30Sjl {
813*25cf1a30Sjl 	drmach_node_t *dup;
814*25cf1a30Sjl 
815*25cf1a30Sjl 	dup = drmach_node_new();
816*25cf1a30Sjl 	dup->here = np->here;
817*25cf1a30Sjl 	dup->get_dnode = np->get_dnode;
818*25cf1a30Sjl 	dup->walk = np->walk;
819*25cf1a30Sjl 	dup->n_getdip = np->n_getdip;
820*25cf1a30Sjl 	dup->n_getproplen = np->n_getproplen;
821*25cf1a30Sjl 	dup->n_getprop = np->n_getprop;
822*25cf1a30Sjl 	dup->get_parent = np->get_parent;
823*25cf1a30Sjl 
824*25cf1a30Sjl 	return (dup);
825*25cf1a30Sjl }
826*25cf1a30Sjl 
827*25cf1a30Sjl /*
828*25cf1a30Sjl  * drmach_array provides convenient array construction, access,
829*25cf1a30Sjl  * bounds checking and array destruction logic.
830*25cf1a30Sjl  */
831*25cf1a30Sjl 
832*25cf1a30Sjl static drmach_array_t *
833*25cf1a30Sjl drmach_array_new(int min_index, int max_index)
834*25cf1a30Sjl {
835*25cf1a30Sjl 	drmach_array_t *arr;
836*25cf1a30Sjl 
837*25cf1a30Sjl 	arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP);
838*25cf1a30Sjl 
839*25cf1a30Sjl 	arr->arr_sz = (max_index - min_index + 1) * sizeof (void *);
840*25cf1a30Sjl 	if (arr->arr_sz > 0) {
841*25cf1a30Sjl 		arr->min_index = min_index;
842*25cf1a30Sjl 		arr->max_index = max_index;
843*25cf1a30Sjl 
844*25cf1a30Sjl 		arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP);
845*25cf1a30Sjl 		return (arr);
846*25cf1a30Sjl 	} else {
847*25cf1a30Sjl 		kmem_free(arr, sizeof (*arr));
848*25cf1a30Sjl 		return (0);
849*25cf1a30Sjl 	}
850*25cf1a30Sjl }
851*25cf1a30Sjl 
852*25cf1a30Sjl static int
853*25cf1a30Sjl drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val)
854*25cf1a30Sjl {
855*25cf1a30Sjl 	if (idx < arr->min_index || idx > arr->max_index)
856*25cf1a30Sjl 		return (-1);
857*25cf1a30Sjl 	else {
858*25cf1a30Sjl 		arr->arr[idx - arr->min_index] = val;
859*25cf1a30Sjl 		return (0);
860*25cf1a30Sjl 	}
861*25cf1a30Sjl 	/*NOTREACHED*/
862*25cf1a30Sjl }
863*25cf1a30Sjl 
864*25cf1a30Sjl static int
865*25cf1a30Sjl drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val)
866*25cf1a30Sjl {
867*25cf1a30Sjl 	if (idx < arr->min_index || idx > arr->max_index)
868*25cf1a30Sjl 		return (-1);
869*25cf1a30Sjl 	else {
870*25cf1a30Sjl 		*val = arr->arr[idx - arr->min_index];
871*25cf1a30Sjl 		return (0);
872*25cf1a30Sjl 	}
873*25cf1a30Sjl 	/*NOTREACHED*/
874*25cf1a30Sjl }
875*25cf1a30Sjl 
876*25cf1a30Sjl static int
877*25cf1a30Sjl drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val)
878*25cf1a30Sjl {
879*25cf1a30Sjl 	int rv;
880*25cf1a30Sjl 
881*25cf1a30Sjl 	*idx = arr->min_index;
882*25cf1a30Sjl 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
883*25cf1a30Sjl 		*idx += 1;
884*25cf1a30Sjl 
885*25cf1a30Sjl 	return (rv);
886*25cf1a30Sjl }
887*25cf1a30Sjl 
888*25cf1a30Sjl static int
889*25cf1a30Sjl drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val)
890*25cf1a30Sjl {
891*25cf1a30Sjl 	int rv;
892*25cf1a30Sjl 
893*25cf1a30Sjl 	*idx += 1;
894*25cf1a30Sjl 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
895*25cf1a30Sjl 		*idx += 1;
896*25cf1a30Sjl 
897*25cf1a30Sjl 	return (rv);
898*25cf1a30Sjl }
899*25cf1a30Sjl 
900*25cf1a30Sjl static void
901*25cf1a30Sjl drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t))
902*25cf1a30Sjl {
903*25cf1a30Sjl 	drmachid_t	val;
904*25cf1a30Sjl 	int		idx;
905*25cf1a30Sjl 	int		rv;
906*25cf1a30Sjl 
907*25cf1a30Sjl 	rv = drmach_array_first(arr, &idx, &val);
908*25cf1a30Sjl 	while (rv == 0) {
909*25cf1a30Sjl 		(*disposer)(val);
910*25cf1a30Sjl 		rv = drmach_array_next(arr, &idx, &val);
911*25cf1a30Sjl 	}
912*25cf1a30Sjl 
913*25cf1a30Sjl 	kmem_free(arr->arr, arr->arr_sz);
914*25cf1a30Sjl 	kmem_free(arr, sizeof (*arr));
915*25cf1a30Sjl }
916*25cf1a30Sjl 
917*25cf1a30Sjl static drmach_board_t *
918*25cf1a30Sjl drmach_get_board_by_bnum(int bnum)
919*25cf1a30Sjl {
920*25cf1a30Sjl 	drmachid_t id;
921*25cf1a30Sjl 
922*25cf1a30Sjl 	if (drmach_array_get(drmach_boards, bnum, &id) == 0)
923*25cf1a30Sjl 		return ((drmach_board_t *)id);
924*25cf1a30Sjl 	else
925*25cf1a30Sjl 		return (NULL);
926*25cf1a30Sjl }
927*25cf1a30Sjl 
928*25cf1a30Sjl static pnode_t
929*25cf1a30Sjl drmach_node_get_dnode(drmach_node_t *np)
930*25cf1a30Sjl {
931*25cf1a30Sjl 	return (np->get_dnode(np));
932*25cf1a30Sjl }
933*25cf1a30Sjl 
934*25cf1a30Sjl /*ARGSUSED*/
935*25cf1a30Sjl sbd_error_t *
936*25cf1a30Sjl drmach_configure(drmachid_t id, int flags)
937*25cf1a30Sjl {
938*25cf1a30Sjl 	drmach_device_t		*dp;
939*25cf1a30Sjl 	sbd_error_t		*err = NULL;
940*25cf1a30Sjl 	dev_info_t		*rdip;
941*25cf1a30Sjl 	dev_info_t		*fdip = NULL;
942*25cf1a30Sjl 
943*25cf1a30Sjl 	if (DRMACH_IS_CPU_ID(id)) {
944*25cf1a30Sjl 		return (NULL);
945*25cf1a30Sjl 	}
946*25cf1a30Sjl 	if (!DRMACH_IS_DEVICE_ID(id))
947*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
948*25cf1a30Sjl 	dp = id;
949*25cf1a30Sjl 	rdip = dp->node->n_getdip(dp->node);
950*25cf1a30Sjl 
951*25cf1a30Sjl 	ASSERT(rdip);
952*25cf1a30Sjl 
953*25cf1a30Sjl 	ASSERT(e_ddi_branch_held(rdip));
954*25cf1a30Sjl 
955*25cf1a30Sjl 	if (e_ddi_branch_configure(rdip, &fdip, 0) != 0) {
956*25cf1a30Sjl 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
957*25cf1a30Sjl 		dev_info_t *dip = (fdip != NULL) ? fdip : rdip;
958*25cf1a30Sjl 
959*25cf1a30Sjl 		(void) ddi_pathname(dip, path);
960*25cf1a30Sjl 		err = drerr_new(1,  EOPL_DRVFAIL, path);
961*25cf1a30Sjl 
962*25cf1a30Sjl 		kmem_free(path, MAXPATHLEN);
963*25cf1a30Sjl 
964*25cf1a30Sjl 		/* If non-NULL, fdip is returned held and must be released */
965*25cf1a30Sjl 		if (fdip != NULL)
966*25cf1a30Sjl 			ddi_release_devi(fdip);
967*25cf1a30Sjl 	}
968*25cf1a30Sjl 
969*25cf1a30Sjl 	return (err);
970*25cf1a30Sjl }
971*25cf1a30Sjl 
972*25cf1a30Sjl 
973*25cf1a30Sjl static sbd_error_t *
974*25cf1a30Sjl drmach_device_new(drmach_node_t *node,
975*25cf1a30Sjl 	drmach_board_t *bp, int portid, drmachid_t *idp)
976*25cf1a30Sjl {
977*25cf1a30Sjl 	int		 i;
978*25cf1a30Sjl 	int		 rv;
979*25cf1a30Sjl 	drmach_device_t	proto;
980*25cf1a30Sjl 	sbd_error_t	*err;
981*25cf1a30Sjl 	char		 name[OBP_MAXDRVNAME];
982*25cf1a30Sjl 
983*25cf1a30Sjl 	rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME);
984*25cf1a30Sjl 	if (rv) {
985*25cf1a30Sjl 		/* every node is expected to have a name */
986*25cf1a30Sjl 		err = drerr_new(1, EOPL_GETPROP,
987*25cf1a30Sjl 			"device node %s: property %s",
988*25cf1a30Sjl 			ddi_node_name(node->n_getdip(node)), "name");
989*25cf1a30Sjl 		return (err);
990*25cf1a30Sjl 	}
991*25cf1a30Sjl 
992*25cf1a30Sjl 	/*
993*25cf1a30Sjl 	 * The node currently being examined is not listed in the name2type[]
994*25cf1a30Sjl 	 * array.  In this case, the node is no interest to drmach.  Both
995*25cf1a30Sjl 	 * dp and err are initialized here to yield nothing (no device or
996*25cf1a30Sjl 	 * error structure) for this case.
997*25cf1a30Sjl 	 */
998*25cf1a30Sjl 	i = drmach_name2type_idx(name);
999*25cf1a30Sjl 
1000*25cf1a30Sjl 
1001*25cf1a30Sjl 	if (i < 0) {
1002*25cf1a30Sjl 		*idp = (drmachid_t)0;
1003*25cf1a30Sjl 		return (NULL);
1004*25cf1a30Sjl 	}
1005*25cf1a30Sjl 
1006*25cf1a30Sjl 	/* device specific new function will set unum */
1007*25cf1a30Sjl 
1008*25cf1a30Sjl 	bzero(&proto, sizeof (proto));
1009*25cf1a30Sjl 	proto.type = drmach_name2type[i].type;
1010*25cf1a30Sjl 	proto.bp = bp;
1011*25cf1a30Sjl 	proto.node = node;
1012*25cf1a30Sjl 	proto.portid = portid;
1013*25cf1a30Sjl 
1014*25cf1a30Sjl 	return (drmach_name2type[i].new(&proto, idp));
1015*25cf1a30Sjl }
1016*25cf1a30Sjl 
1017*25cf1a30Sjl static void
1018*25cf1a30Sjl drmach_device_dispose(drmachid_t id)
1019*25cf1a30Sjl {
1020*25cf1a30Sjl 	drmach_device_t *self = id;
1021*25cf1a30Sjl 
1022*25cf1a30Sjl 	self->cm.dispose(id);
1023*25cf1a30Sjl }
1024*25cf1a30Sjl 
1025*25cf1a30Sjl 
1026*25cf1a30Sjl static drmach_board_t *
1027*25cf1a30Sjl drmach_board_new(int bnum, int boot_board)
1028*25cf1a30Sjl {
1029*25cf1a30Sjl 	static sbd_error_t *drmach_board_release(drmachid_t);
1030*25cf1a30Sjl 	static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *);
1031*25cf1a30Sjl 
1032*25cf1a30Sjl 	drmach_board_t	*bp;
1033*25cf1a30Sjl 
1034*25cf1a30Sjl 	bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP);
1035*25cf1a30Sjl 
1036*25cf1a30Sjl 	bp->cm.isa = (void *)drmach_board_new;
1037*25cf1a30Sjl 	bp->cm.release = drmach_board_release;
1038*25cf1a30Sjl 	bp->cm.status = drmach_board_status;
1039*25cf1a30Sjl 
1040*25cf1a30Sjl 	(void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name));
1041*25cf1a30Sjl 
1042*25cf1a30Sjl 	bp->bnum = bnum;
1043*25cf1a30Sjl 	bp->devices = NULL;
1044*25cf1a30Sjl 	bp->connected = boot_board;
1045*25cf1a30Sjl 	bp->tree = drmach_node_new();
1046*25cf1a30Sjl 	bp->assigned = boot_board;
1047*25cf1a30Sjl 	bp->powered = boot_board;
1048*25cf1a30Sjl 	bp->boot_board = boot_board;
1049*25cf1a30Sjl 
1050*25cf1a30Sjl 	/*
1051*25cf1a30Sjl 	 * If this is not bootup initialization, we have to wait till
1052*25cf1a30Sjl 	 * IKP sets up the device nodes in drmach_board_connect().
1053*25cf1a30Sjl 	 */
1054*25cf1a30Sjl 	if (boot_board)
1055*25cf1a30Sjl 		drmach_setup_core_info(bp);
1056*25cf1a30Sjl 
1057*25cf1a30Sjl 	drmach_array_set(drmach_boards, bnum, bp);
1058*25cf1a30Sjl 	return (bp);
1059*25cf1a30Sjl }
1060*25cf1a30Sjl 
1061*25cf1a30Sjl static void
1062*25cf1a30Sjl drmach_board_dispose(drmachid_t id)
1063*25cf1a30Sjl {
1064*25cf1a30Sjl 	drmach_board_t *bp;
1065*25cf1a30Sjl 
1066*25cf1a30Sjl 	ASSERT(DRMACH_IS_BOARD_ID(id));
1067*25cf1a30Sjl 	bp = id;
1068*25cf1a30Sjl 
1069*25cf1a30Sjl 	if (bp->tree)
1070*25cf1a30Sjl 		drmach_node_dispose(bp->tree);
1071*25cf1a30Sjl 
1072*25cf1a30Sjl 	if (bp->devices)
1073*25cf1a30Sjl 		drmach_array_dispose(bp->devices, drmach_device_dispose);
1074*25cf1a30Sjl 
1075*25cf1a30Sjl 	kmem_free(bp, sizeof (*bp));
1076*25cf1a30Sjl }
1077*25cf1a30Sjl 
1078*25cf1a30Sjl static sbd_error_t *
1079*25cf1a30Sjl drmach_board_status(drmachid_t id, drmach_status_t *stat)
1080*25cf1a30Sjl {
1081*25cf1a30Sjl 	sbd_error_t	*err = NULL;
1082*25cf1a30Sjl 	drmach_board_t	*bp;
1083*25cf1a30Sjl 
1084*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
1085*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1086*25cf1a30Sjl 	bp = id;
1087*25cf1a30Sjl 
1088*25cf1a30Sjl 	stat->assigned = bp->assigned;
1089*25cf1a30Sjl 	stat->powered = bp->powered;
1090*25cf1a30Sjl 	stat->busy = 0;			/* assume not busy */
1091*25cf1a30Sjl 	stat->configured = 0;		/* assume not configured */
1092*25cf1a30Sjl 	stat->empty = 0;
1093*25cf1a30Sjl 	stat->cond = bp->cond = SBD_COND_OK;
1094*25cf1a30Sjl 	strncpy(stat->type, "System Brd", sizeof (stat->type));
1095*25cf1a30Sjl 	stat->info[0] = '\0';
1096*25cf1a30Sjl 
1097*25cf1a30Sjl 	if (bp->devices) {
1098*25cf1a30Sjl 		int		 rv;
1099*25cf1a30Sjl 		int		 d_idx;
1100*25cf1a30Sjl 		drmachid_t	 d_id;
1101*25cf1a30Sjl 
1102*25cf1a30Sjl 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
1103*25cf1a30Sjl 		while (rv == 0) {
1104*25cf1a30Sjl 			drmach_status_t	d_stat;
1105*25cf1a30Sjl 
1106*25cf1a30Sjl 			err = drmach_i_status(d_id, &d_stat);
1107*25cf1a30Sjl 			if (err)
1108*25cf1a30Sjl 				break;
1109*25cf1a30Sjl 
1110*25cf1a30Sjl 			stat->busy |= d_stat.busy;
1111*25cf1a30Sjl 			stat->configured |= d_stat.configured;
1112*25cf1a30Sjl 
1113*25cf1a30Sjl 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
1114*25cf1a30Sjl 		}
1115*25cf1a30Sjl 	}
1116*25cf1a30Sjl 
1117*25cf1a30Sjl 	return (err);
1118*25cf1a30Sjl }
1119*25cf1a30Sjl 
1120*25cf1a30Sjl int
1121*25cf1a30Sjl drmach_board_is_floating(drmachid_t id)
1122*25cf1a30Sjl {
1123*25cf1a30Sjl 	drmach_board_t *bp;
1124*25cf1a30Sjl 
1125*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
1126*25cf1a30Sjl 		return (0);
1127*25cf1a30Sjl 
1128*25cf1a30Sjl 	bp = (drmach_board_t *)id;
1129*25cf1a30Sjl 
1130*25cf1a30Sjl 	return ((drmach_domain.floating & (1 << bp->bnum)) ? 1 : 0);
1131*25cf1a30Sjl }
1132*25cf1a30Sjl 
1133*25cf1a30Sjl static int
1134*25cf1a30Sjl drmach_init(void)
1135*25cf1a30Sjl {
1136*25cf1a30Sjl 	dev_info_t	*rdip;
1137*25cf1a30Sjl 	int		i, rv, len;
1138*25cf1a30Sjl 	int		*floating;
1139*25cf1a30Sjl 
1140*25cf1a30Sjl 	rw_init(&drmach_boards_rwlock, NULL, RW_DEFAULT, NULL);
1141*25cf1a30Sjl 
1142*25cf1a30Sjl 	drmach_boards = drmach_array_new(0, MAX_BOARDS - 1);
1143*25cf1a30Sjl 
1144*25cf1a30Sjl 	rdip = ddi_root_node();
1145*25cf1a30Sjl 
1146*25cf1a30Sjl 	if (ddi_getproplen(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
1147*25cf1a30Sjl 		"floating-boards", &len) != DDI_PROP_SUCCESS) {
1148*25cf1a30Sjl 		cmn_err(CE_WARN, "Cannot get floating-boards proplen\n");
1149*25cf1a30Sjl 	} else {
1150*25cf1a30Sjl 		floating = (int *)kmem_alloc(len, KM_SLEEP);
1151*25cf1a30Sjl 		rv = ddi_prop_op(DDI_DEV_T_ANY, rdip,
1152*25cf1a30Sjl 			PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS,
1153*25cf1a30Sjl 			"floating-boards", (caddr_t)floating, &len);
1154*25cf1a30Sjl 		if (rv != DDI_PROP_SUCCESS) {
1155*25cf1a30Sjl 			cmn_err(CE_WARN, "Cannot get floating-boards prop\n");
1156*25cf1a30Sjl 		} else {
1157*25cf1a30Sjl 			drmach_domain.floating = 0;
1158*25cf1a30Sjl 			for (i = 0; i < len / sizeof (int); i++) {
1159*25cf1a30Sjl 				drmach_domain.floating |= (1 << floating[i]);
1160*25cf1a30Sjl 			}
1161*25cf1a30Sjl 		}
1162*25cf1a30Sjl 		kmem_free(floating, len);
1163*25cf1a30Sjl 	}
1164*25cf1a30Sjl 	drmach_domain.allow_dr = opl_check_dr_status();
1165*25cf1a30Sjl 
1166*25cf1a30Sjl 	rdip = ddi_get_child(ddi_root_node());
1167*25cf1a30Sjl 	do {
1168*25cf1a30Sjl 		int		 bnum;
1169*25cf1a30Sjl 		drmachid_t	 id;
1170*25cf1a30Sjl 
1171*25cf1a30Sjl 		bnum = -1;
1172*25cf1a30Sjl 		bnum = ddi_getprop(DDI_DEV_T_ANY, rdip,
1173*25cf1a30Sjl 			DDI_PROP_DONTPASS, OBP_BOARDNUM, -1);
1174*25cf1a30Sjl 		if (bnum == -1)
1175*25cf1a30Sjl 			continue;
1176*25cf1a30Sjl 
1177*25cf1a30Sjl 		if (drmach_array_get(drmach_boards, bnum, &id) == -1) {
1178*25cf1a30Sjl 			cmn_err(CE_WARN, "Device node 0x%p has"
1179*25cf1a30Sjl 				" invalid property value, %s=%d",
1180*25cf1a30Sjl 					rdip, OBP_BOARDNUM, bnum);
1181*25cf1a30Sjl 			goto error;
1182*25cf1a30Sjl 		} else if (id == NULL) {
1183*25cf1a30Sjl 			(void) drmach_board_new(bnum, 1);
1184*25cf1a30Sjl 		}
1185*25cf1a30Sjl 	} while ((rdip = ddi_get_next_sibling(rdip)) != NULL);
1186*25cf1a30Sjl 
1187*25cf1a30Sjl 	opl_hold_devtree();
1188*25cf1a30Sjl 
1189*25cf1a30Sjl 	/*
1190*25cf1a30Sjl 	 * Initialize the IKP feature.
1191*25cf1a30Sjl 	 *
1192*25cf1a30Sjl 	 * This can be done only after DR has acquired a hold on all the
1193*25cf1a30Sjl 	 * device nodes that are interesting to IKP.
1194*25cf1a30Sjl 	 */
1195*25cf1a30Sjl 	if (opl_init_cfg() != 0) {
1196*25cf1a30Sjl 		cmn_err(CE_WARN, "DR - IKP initialization failed");
1197*25cf1a30Sjl 
1198*25cf1a30Sjl 		opl_release_devtree();
1199*25cf1a30Sjl 
1200*25cf1a30Sjl 		goto error;
1201*25cf1a30Sjl 	}
1202*25cf1a30Sjl 
1203*25cf1a30Sjl 	return (0);
1204*25cf1a30Sjl error:
1205*25cf1a30Sjl 	drmach_array_dispose(drmach_boards, drmach_board_dispose);
1206*25cf1a30Sjl 	rw_destroy(&drmach_boards_rwlock);
1207*25cf1a30Sjl 	return (ENXIO);
1208*25cf1a30Sjl }
1209*25cf1a30Sjl 
1210*25cf1a30Sjl static void
1211*25cf1a30Sjl drmach_fini(void)
1212*25cf1a30Sjl {
1213*25cf1a30Sjl 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
1214*25cf1a30Sjl 	drmach_array_dispose(drmach_boards, drmach_board_dispose);
1215*25cf1a30Sjl 	drmach_boards = NULL;
1216*25cf1a30Sjl 	rw_exit(&drmach_boards_rwlock);
1217*25cf1a30Sjl 
1218*25cf1a30Sjl 	/*
1219*25cf1a30Sjl 	 * Walk immediate children of the root devinfo node
1220*25cf1a30Sjl 	 * releasing holds acquired on branches in drmach_init()
1221*25cf1a30Sjl 	 */
1222*25cf1a30Sjl 
1223*25cf1a30Sjl 	opl_release_devtree();
1224*25cf1a30Sjl 
1225*25cf1a30Sjl 	rw_destroy(&drmach_boards_rwlock);
1226*25cf1a30Sjl }
1227*25cf1a30Sjl 
1228*25cf1a30Sjl /*
1229*25cf1a30Sjl  *	Each system board contains 2 Oberon PCI bridge and
1230*25cf1a30Sjl  *	1 CMUCH.
1231*25cf1a30Sjl  *	Each oberon has 2 channels.
1232*25cf1a30Sjl  *	Each channel has 2 pci-ex leaf.
1233*25cf1a30Sjl  *	Each CMUCH has 1 pci bus.
1234*25cf1a30Sjl  *
1235*25cf1a30Sjl  *
1236*25cf1a30Sjl  *	Device Path:
1237*25cf1a30Sjl  *	/pci@<portid>,reg
1238*25cf1a30Sjl  *
1239*25cf1a30Sjl  *	where
1240*25cf1a30Sjl  *	portid[10] = 0
1241*25cf1a30Sjl  *	portid[9:0] = LLEAF_ID[9:0] of the Oberon Channel
1242*25cf1a30Sjl  *
1243*25cf1a30Sjl  *	LLEAF_ID[9:8] = 0
1244*25cf1a30Sjl  *	LLEAF_ID[8:4] = LSB_ID[4:0]
1245*25cf1a30Sjl  *	LLEAF_ID[3:1] = IO Channel#[2:0] (0,1,2,3 for Oberon)
1246*25cf1a30Sjl  *			channel 4 is pcicmu
1247*25cf1a30Sjl  *	LLEAF_ID[0] = PCI Leaf Number (0 for leaf-A, 1 for leaf-B)
1248*25cf1a30Sjl  *
1249*25cf1a30Sjl  *	Properties:
1250*25cf1a30Sjl  *	name = pci
1251*25cf1a30Sjl  *	device_type = "pciex"
1252*25cf1a30Sjl  *	board# = LSBID
1253*25cf1a30Sjl  *	reg = int32 * 2, Oberon CSR space of the leaf and the UBC space
1254*25cf1a30Sjl  *	portid = Jupiter Bus Device ID ((LSB_ID << 3)|pciport#)
1255*25cf1a30Sjl  */
1256*25cf1a30Sjl 
1257*25cf1a30Sjl static sbd_error_t *
1258*25cf1a30Sjl drmach_io_new(drmach_device_t *proto, drmachid_t *idp)
1259*25cf1a30Sjl {
1260*25cf1a30Sjl 	drmach_io_t	*ip;
1261*25cf1a30Sjl 
1262*25cf1a30Sjl 	int		 portid;
1263*25cf1a30Sjl 
1264*25cf1a30Sjl 	portid = proto->portid;
1265*25cf1a30Sjl 	ASSERT(portid != -1);
1266*25cf1a30Sjl 	proto->unum = portid & (MAX_IO_UNITS_PER_BOARD - 1);
1267*25cf1a30Sjl 
1268*25cf1a30Sjl 	ip = kmem_zalloc(sizeof (drmach_io_t), KM_SLEEP);
1269*25cf1a30Sjl 	bcopy(proto, &ip->dev, sizeof (ip->dev));
1270*25cf1a30Sjl 	ip->dev.node = drmach_node_dup(proto->node);
1271*25cf1a30Sjl 	ip->dev.cm.isa = (void *)drmach_io_new;
1272*25cf1a30Sjl 	ip->dev.cm.dispose = drmach_io_dispose;
1273*25cf1a30Sjl 	ip->dev.cm.release = drmach_io_release;
1274*25cf1a30Sjl 	ip->dev.cm.status = drmach_io_status;
1275*25cf1a30Sjl 	ip->channel = (portid >> 1) & 0x7;
1276*25cf1a30Sjl 	ip->leaf = (portid & 0x1);
1277*25cf1a30Sjl 
1278*25cf1a30Sjl 	snprintf(ip->dev.cm.name, sizeof (ip->dev.cm.name), "%s%d",
1279*25cf1a30Sjl 		ip->dev.type, ip->dev.unum);
1280*25cf1a30Sjl 
1281*25cf1a30Sjl 	*idp = (drmachid_t)ip;
1282*25cf1a30Sjl 	return (NULL);
1283*25cf1a30Sjl }
1284*25cf1a30Sjl 
1285*25cf1a30Sjl 
1286*25cf1a30Sjl static void
1287*25cf1a30Sjl drmach_io_dispose(drmachid_t id)
1288*25cf1a30Sjl {
1289*25cf1a30Sjl 	drmach_io_t *self;
1290*25cf1a30Sjl 
1291*25cf1a30Sjl 	ASSERT(DRMACH_IS_IO_ID(id));
1292*25cf1a30Sjl 
1293*25cf1a30Sjl 	self = id;
1294*25cf1a30Sjl 	if (self->dev.node)
1295*25cf1a30Sjl 		drmach_node_dispose(self->dev.node);
1296*25cf1a30Sjl 
1297*25cf1a30Sjl 	kmem_free(self, sizeof (*self));
1298*25cf1a30Sjl }
1299*25cf1a30Sjl 
1300*25cf1a30Sjl /*ARGSUSED*/
1301*25cf1a30Sjl sbd_error_t *
1302*25cf1a30Sjl drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts)
1303*25cf1a30Sjl {
1304*25cf1a30Sjl 	drmach_board_t	*bp = (drmach_board_t *)id;
1305*25cf1a30Sjl 	sbd_error_t	*err = NULL;
1306*25cf1a30Sjl 
1307*25cf1a30Sjl 	/* allow status and ncm operations to always succeed */
1308*25cf1a30Sjl 	if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) {
1309*25cf1a30Sjl 		return (NULL);
1310*25cf1a30Sjl 	}
1311*25cf1a30Sjl 
1312*25cf1a30Sjl 	/* check all other commands for the required option string */
1313*25cf1a30Sjl 
1314*25cf1a30Sjl 	if ((opts->size > 0) && (opts->copts != NULL)) {
1315*25cf1a30Sjl 
1316*25cf1a30Sjl 		DRMACH_PR("platform options: %s\n", opts->copts);
1317*25cf1a30Sjl 
1318*25cf1a30Sjl 		if (strstr(opts->copts, "opldr") == NULL) {
1319*25cf1a30Sjl 			err = drerr_new(1, EOPL_SUPPORT, NULL);
1320*25cf1a30Sjl 		}
1321*25cf1a30Sjl 	} else {
1322*25cf1a30Sjl 		err = drerr_new(1, EOPL_SUPPORT, NULL);
1323*25cf1a30Sjl 	}
1324*25cf1a30Sjl 
1325*25cf1a30Sjl 	if (!err && id && DRMACH_IS_BOARD_ID(id)) {
1326*25cf1a30Sjl 		switch (cmd) {
1327*25cf1a30Sjl 			case SBD_CMD_TEST:
1328*25cf1a30Sjl 			case SBD_CMD_STATUS:
1329*25cf1a30Sjl 			case SBD_CMD_GETNCM:
1330*25cf1a30Sjl 				break;
1331*25cf1a30Sjl 			case SBD_CMD_CONNECT:
1332*25cf1a30Sjl 				if (bp->connected)
1333*25cf1a30Sjl 					err = drerr_new(0, ESBD_STATE, NULL);
1334*25cf1a30Sjl 				else if (!drmach_domain.allow_dr)
1335*25cf1a30Sjl 					err = drerr_new(1, EOPL_SUPPORT,
1336*25cf1a30Sjl 						NULL);
1337*25cf1a30Sjl 				break;
1338*25cf1a30Sjl 			case SBD_CMD_DISCONNECT:
1339*25cf1a30Sjl 				if (!bp->connected)
1340*25cf1a30Sjl 					err = drerr_new(0, ESBD_STATE, NULL);
1341*25cf1a30Sjl 				else if (!drmach_domain.allow_dr)
1342*25cf1a30Sjl 					err = drerr_new(1, EOPL_SUPPORT,
1343*25cf1a30Sjl 						NULL);
1344*25cf1a30Sjl 				break;
1345*25cf1a30Sjl 			default:
1346*25cf1a30Sjl 				if (!drmach_domain.allow_dr)
1347*25cf1a30Sjl 					err = drerr_new(1, EOPL_SUPPORT,
1348*25cf1a30Sjl 						NULL);
1349*25cf1a30Sjl 				break;
1350*25cf1a30Sjl 
1351*25cf1a30Sjl 		}
1352*25cf1a30Sjl 	}
1353*25cf1a30Sjl 
1354*25cf1a30Sjl 	return (err);
1355*25cf1a30Sjl }
1356*25cf1a30Sjl 
1357*25cf1a30Sjl /*ARGSUSED*/
1358*25cf1a30Sjl sbd_error_t *
1359*25cf1a30Sjl drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts)
1360*25cf1a30Sjl {
1361*25cf1a30Sjl 	return (NULL);
1362*25cf1a30Sjl }
1363*25cf1a30Sjl 
1364*25cf1a30Sjl sbd_error_t *
1365*25cf1a30Sjl drmach_board_assign(int bnum, drmachid_t *id)
1366*25cf1a30Sjl {
1367*25cf1a30Sjl 	sbd_error_t	*err = NULL;
1368*25cf1a30Sjl 
1369*25cf1a30Sjl 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
1370*25cf1a30Sjl 
1371*25cf1a30Sjl 	if (drmach_array_get(drmach_boards, bnum, id) == -1) {
1372*25cf1a30Sjl 		err = drerr_new(1, EOPL_BNUM, "%d", bnum);
1373*25cf1a30Sjl 	} else {
1374*25cf1a30Sjl 		drmach_board_t	*bp;
1375*25cf1a30Sjl 
1376*25cf1a30Sjl 		if (*id)
1377*25cf1a30Sjl 			rw_downgrade(&drmach_boards_rwlock);
1378*25cf1a30Sjl 
1379*25cf1a30Sjl 		bp = *id;
1380*25cf1a30Sjl 		if (!(*id))
1381*25cf1a30Sjl 			bp = *id  =
1382*25cf1a30Sjl 				(drmachid_t)drmach_board_new(bnum, 0);
1383*25cf1a30Sjl 		bp->assigned = 1;
1384*25cf1a30Sjl 	}
1385*25cf1a30Sjl 
1386*25cf1a30Sjl 	rw_exit(&drmach_boards_rwlock);
1387*25cf1a30Sjl 
1388*25cf1a30Sjl 	return (err);
1389*25cf1a30Sjl }
1390*25cf1a30Sjl 
1391*25cf1a30Sjl /*ARGSUSED*/
1392*25cf1a30Sjl sbd_error_t *
1393*25cf1a30Sjl drmach_board_connect(drmachid_t id, drmach_opts_t *opts)
1394*25cf1a30Sjl {
1395*25cf1a30Sjl 	drmach_board_t	*obj = (drmach_board_t *)id;
1396*25cf1a30Sjl 
1397*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
1398*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1399*25cf1a30Sjl 
1400*25cf1a30Sjl 	if (opl_probe_sb(obj->bnum) != 0)
1401*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
1402*25cf1a30Sjl 
1403*25cf1a30Sjl 	(void) prom_attach_notice(obj->bnum);
1404*25cf1a30Sjl 
1405*25cf1a30Sjl 	drmach_setup_core_info(obj);
1406*25cf1a30Sjl 
1407*25cf1a30Sjl 	obj->connected = 1;
1408*25cf1a30Sjl 
1409*25cf1a30Sjl 	return (NULL);
1410*25cf1a30Sjl }
1411*25cf1a30Sjl 
1412*25cf1a30Sjl static int drmach_cache_flush_flag[NCPU];
1413*25cf1a30Sjl 
1414*25cf1a30Sjl /*ARGSUSED*/
1415*25cf1a30Sjl static void
1416*25cf1a30Sjl drmach_flush_cache(uint64_t id, uint64_t dummy)
1417*25cf1a30Sjl {
1418*25cf1a30Sjl 	extern void cpu_flush_ecache(void);
1419*25cf1a30Sjl 
1420*25cf1a30Sjl 	cpu_flush_ecache();
1421*25cf1a30Sjl 	drmach_cache_flush_flag[id] = 0;
1422*25cf1a30Sjl }
1423*25cf1a30Sjl 
1424*25cf1a30Sjl static void
1425*25cf1a30Sjl drmach_flush_all()
1426*25cf1a30Sjl {
1427*25cf1a30Sjl 	cpuset_t	xc_cpuset;
1428*25cf1a30Sjl 	int		i;
1429*25cf1a30Sjl 
1430*25cf1a30Sjl 	xc_cpuset = cpu_ready_set;
1431*25cf1a30Sjl 	for (i = 0; i < NCPU; i++) {
1432*25cf1a30Sjl 		if (CPU_IN_SET(xc_cpuset, i)) {
1433*25cf1a30Sjl 			drmach_cache_flush_flag[i] = 1;
1434*25cf1a30Sjl 			xc_one(i, drmach_flush_cache, i, 0);
1435*25cf1a30Sjl 			while (drmach_cache_flush_flag[i]) {
1436*25cf1a30Sjl 				DELAY(1000);
1437*25cf1a30Sjl 			}
1438*25cf1a30Sjl 		}
1439*25cf1a30Sjl 	}
1440*25cf1a30Sjl }
1441*25cf1a30Sjl 
1442*25cf1a30Sjl static int
1443*25cf1a30Sjl drmach_disconnect_cpus(drmach_board_t *bp)
1444*25cf1a30Sjl {
1445*25cf1a30Sjl 	int i, bnum;
1446*25cf1a30Sjl 
1447*25cf1a30Sjl 	bnum = bp->bnum;
1448*25cf1a30Sjl 
1449*25cf1a30Sjl 	for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
1450*25cf1a30Sjl 	    if (bp->cores[i].core_present) {
1451*25cf1a30Sjl 		if (bp->cores[i].core_started)
1452*25cf1a30Sjl 		    return (-1);
1453*25cf1a30Sjl 		if (bp->cores[i].core_hotadded) {
1454*25cf1a30Sjl 		    if (drmach_add_remove_cpu(bnum, i, HOTREMOVE_CPU)) {
1455*25cf1a30Sjl 			cmn_err(CE_WARN,
1456*25cf1a30Sjl 			    "Failed to remove CMP %d on board %d\n",
1457*25cf1a30Sjl 			    i, bnum);
1458*25cf1a30Sjl 			return (-1);
1459*25cf1a30Sjl 		    }
1460*25cf1a30Sjl 		}
1461*25cf1a30Sjl 	    }
1462*25cf1a30Sjl 	}
1463*25cf1a30Sjl 	return (0);
1464*25cf1a30Sjl }
1465*25cf1a30Sjl 
1466*25cf1a30Sjl /*ARGSUSED*/
1467*25cf1a30Sjl sbd_error_t *
1468*25cf1a30Sjl drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts)
1469*25cf1a30Sjl {
1470*25cf1a30Sjl 	drmach_board_t *obj;
1471*25cf1a30Sjl 	int rv = 0;
1472*25cf1a30Sjl 	sbd_error_t		*err = NULL;
1473*25cf1a30Sjl 
1474*25cf1a30Sjl 
1475*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
1476*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1477*25cf1a30Sjl 
1478*25cf1a30Sjl 
1479*25cf1a30Sjl 
1480*25cf1a30Sjl 	obj = (drmach_board_t *)id;
1481*25cf1a30Sjl 
1482*25cf1a30Sjl 	if (drmach_disconnect_cpus(obj)) {
1483*25cf1a30Sjl 		err = drerr_new(0, EOPL_DEPROBE, obj->cm.name);
1484*25cf1a30Sjl 		return (err);
1485*25cf1a30Sjl 	}
1486*25cf1a30Sjl 
1487*25cf1a30Sjl 	rv = opl_unprobe_sb(obj->bnum);
1488*25cf1a30Sjl 
1489*25cf1a30Sjl 	if (rv == 0) {
1490*25cf1a30Sjl 		prom_detach_notice(obj->bnum);
1491*25cf1a30Sjl 		obj->connected = 0;
1492*25cf1a30Sjl 
1493*25cf1a30Sjl 	} else
1494*25cf1a30Sjl 		err = drerr_new(0, EOPL_DEPROBE, obj->cm.name);
1495*25cf1a30Sjl 
1496*25cf1a30Sjl 	return (err);
1497*25cf1a30Sjl }
1498*25cf1a30Sjl 
1499*25cf1a30Sjl static int
1500*25cf1a30Sjl drmach_get_portid(drmach_node_t *np)
1501*25cf1a30Sjl {
1502*25cf1a30Sjl 	int		portid;
1503*25cf1a30Sjl 	char		type[OBP_MAXPROPNAME];
1504*25cf1a30Sjl 
1505*25cf1a30Sjl 	if (np->n_getprop(np, "portid", &portid, sizeof (portid)) == 0)
1506*25cf1a30Sjl 		return (portid);
1507*25cf1a30Sjl 
1508*25cf1a30Sjl 	/*
1509*25cf1a30Sjl 	 * Get the device_type property to see if we should
1510*25cf1a30Sjl 	 * continue processing this node.
1511*25cf1a30Sjl 	 */
1512*25cf1a30Sjl 	if (np->n_getprop(np, "device_type", &type, sizeof (type)) != 0)
1513*25cf1a30Sjl 		return (-1);
1514*25cf1a30Sjl 
1515*25cf1a30Sjl 	if (strcmp(type, OPL_CPU_NODE) == 0) {
1516*25cf1a30Sjl 		/*
1517*25cf1a30Sjl 		 * We return cpuid because it has no portid
1518*25cf1a30Sjl 		 */
1519*25cf1a30Sjl 		if (np->n_getprop(np, "cpuid", &portid, sizeof (portid)) == 0)
1520*25cf1a30Sjl 			return (portid);
1521*25cf1a30Sjl 	}
1522*25cf1a30Sjl 
1523*25cf1a30Sjl 	return (-1);
1524*25cf1a30Sjl }
1525*25cf1a30Sjl 
1526*25cf1a30Sjl /*
1527*25cf1a30Sjl  * This is a helper function to determine if a given
1528*25cf1a30Sjl  * node should be considered for a dr operation according
1529*25cf1a30Sjl  * to predefined dr type nodes and the node's name.
1530*25cf1a30Sjl  * Formal Parameter : The name of a device node.
1531*25cf1a30Sjl  * Return Value: -1, name does not map to a valid dr type.
1532*25cf1a30Sjl  *		 A value greater or equal to 0, name is a valid dr type.
1533*25cf1a30Sjl  */
1534*25cf1a30Sjl static int
1535*25cf1a30Sjl drmach_name2type_idx(char *name)
1536*25cf1a30Sjl {
1537*25cf1a30Sjl 	int 	index, ntypes;
1538*25cf1a30Sjl 
1539*25cf1a30Sjl 	if (name == NULL)
1540*25cf1a30Sjl 		return (-1);
1541*25cf1a30Sjl 
1542*25cf1a30Sjl 	/*
1543*25cf1a30Sjl 	 * Determine how many possible types are currently supported
1544*25cf1a30Sjl 	 * for dr.
1545*25cf1a30Sjl 	 */
1546*25cf1a30Sjl 	ntypes = sizeof (drmach_name2type) / sizeof (drmach_name2type[0]);
1547*25cf1a30Sjl 
1548*25cf1a30Sjl 	/* Determine if the node's name correspond to a predefined type. */
1549*25cf1a30Sjl 	for (index = 0; index < ntypes; index++) {
1550*25cf1a30Sjl 		if (strcmp(drmach_name2type[index].name, name) == 0)
1551*25cf1a30Sjl 			/* The node is an allowed type for dr. */
1552*25cf1a30Sjl 			return (index);
1553*25cf1a30Sjl 	}
1554*25cf1a30Sjl 
1555*25cf1a30Sjl 	/*
1556*25cf1a30Sjl 	 * If the name of the node does not map to any of the
1557*25cf1a30Sjl 	 * types in the array drmach_name2type then the node is not of
1558*25cf1a30Sjl 	 * interest to dr.
1559*25cf1a30Sjl 	 */
1560*25cf1a30Sjl 	return (-1);
1561*25cf1a30Sjl }
1562*25cf1a30Sjl 
1563*25cf1a30Sjl /*
1564*25cf1a30Sjl  * there is some complication on OPL:
1565*25cf1a30Sjl  * - pseudo-mc nodes do not have portid property
1566*25cf1a30Sjl  * - portid[9:5] of cmp node is LSB #, portid[7:3] of pci is LSB#
1567*25cf1a30Sjl  * - cmp has board#
1568*25cf1a30Sjl  * - core and cpu nodes do not have portid and board# properties
1569*25cf1a30Sjl  * starcat uses portid to derive the board# but that does not work
1570*25cf1a30Sjl  * for us.  starfire reads board# property to filter the devices.
1571*25cf1a30Sjl  * That does not work either.  So for these specific device,
1572*25cf1a30Sjl  * we use specific hard coded methods to get the board# -
1573*25cf1a30Sjl  * cpu: LSB# = CPUID[9:5]
1574*25cf1a30Sjl  */
1575*25cf1a30Sjl 
1576*25cf1a30Sjl static int
1577*25cf1a30Sjl drmach_board_find_devices_cb(drmach_node_walk_args_t *args)
1578*25cf1a30Sjl {
1579*25cf1a30Sjl 	drmach_node_t			*node = args->node;
1580*25cf1a30Sjl 	drmach_board_cb_data_t		*data = args->data;
1581*25cf1a30Sjl 	drmach_board_t			*obj = data->obj;
1582*25cf1a30Sjl 
1583*25cf1a30Sjl 	int		rv, portid;
1584*25cf1a30Sjl 	int		bnum;
1585*25cf1a30Sjl 	drmachid_t	id;
1586*25cf1a30Sjl 	drmach_device_t	*device;
1587*25cf1a30Sjl 	char name[OBP_MAXDRVNAME];
1588*25cf1a30Sjl 
1589*25cf1a30Sjl 	portid = drmach_get_portid(node);
1590*25cf1a30Sjl 	/*
1591*25cf1a30Sjl 	 * core, cpu and pseudo-mc do not have portid
1592*25cf1a30Sjl 	 * we use cpuid as the portid of the cpu node
1593*25cf1a30Sjl 	 * for pseudo-mc, we do not use portid info.
1594*25cf1a30Sjl 	 */
1595*25cf1a30Sjl 
1596*25cf1a30Sjl 	rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME);
1597*25cf1a30Sjl 	if (rv)
1598*25cf1a30Sjl 		return (0);
1599*25cf1a30Sjl 
1600*25cf1a30Sjl 
1601*25cf1a30Sjl 	rv = node->n_getprop(node, OBP_BOARDNUM, &bnum, sizeof (bnum));
1602*25cf1a30Sjl 
1603*25cf1a30Sjl 	if (rv) {
1604*25cf1a30Sjl 		/*
1605*25cf1a30Sjl 		 * cpu does not have board# property.  We use
1606*25cf1a30Sjl 		 * CPUID[9:5]
1607*25cf1a30Sjl 		 */
1608*25cf1a30Sjl 		if (strcmp("cpu", name) == 0) {
1609*25cf1a30Sjl 			bnum = (portid >> 5) & 0x1f;
1610*25cf1a30Sjl 		} else
1611*25cf1a30Sjl 			return (0);
1612*25cf1a30Sjl 	}
1613*25cf1a30Sjl 
1614*25cf1a30Sjl 
1615*25cf1a30Sjl 	if (bnum != obj->bnum)
1616*25cf1a30Sjl 		return (0);
1617*25cf1a30Sjl 
1618*25cf1a30Sjl 	if (drmach_name2type_idx(name) < 0) {
1619*25cf1a30Sjl 		return (0);
1620*25cf1a30Sjl 	}
1621*25cf1a30Sjl 
1622*25cf1a30Sjl 	/*
1623*25cf1a30Sjl 	 * Create a device data structure from this node data.
1624*25cf1a30Sjl 	 * The call may yield nothing if the node is not of interest
1625*25cf1a30Sjl 	 * to drmach.
1626*25cf1a30Sjl 	 */
1627*25cf1a30Sjl 	data->err = drmach_device_new(node, obj, portid, &id);
1628*25cf1a30Sjl 	if (data->err)
1629*25cf1a30Sjl 		return (-1);
1630*25cf1a30Sjl 	else if (!id) {
1631*25cf1a30Sjl 		/*
1632*25cf1a30Sjl 		 * drmach_device_new examined the node we passed in
1633*25cf1a30Sjl 		 * and determined that it was one not of interest to
1634*25cf1a30Sjl 		 * drmach.  So, it is skipped.
1635*25cf1a30Sjl 		 */
1636*25cf1a30Sjl 		return (0);
1637*25cf1a30Sjl 	}
1638*25cf1a30Sjl 
1639*25cf1a30Sjl 	rv = drmach_array_set(obj->devices, data->ndevs++, id);
1640*25cf1a30Sjl 	if (rv) {
1641*25cf1a30Sjl 		data->err = DRMACH_INTERNAL_ERROR();
1642*25cf1a30Sjl 		return (-1);
1643*25cf1a30Sjl 	}
1644*25cf1a30Sjl 	device = id;
1645*25cf1a30Sjl 
1646*25cf1a30Sjl 	data->err = (*data->found)(data->a, device->type, device->unum, id);
1647*25cf1a30Sjl 	return (data->err == NULL ? 0 : -1);
1648*25cf1a30Sjl }
1649*25cf1a30Sjl 
1650*25cf1a30Sjl sbd_error_t *
1651*25cf1a30Sjl drmach_board_find_devices(drmachid_t id, void *a,
1652*25cf1a30Sjl 	sbd_error_t *(*found)(void *a, const char *, int, drmachid_t))
1653*25cf1a30Sjl {
1654*25cf1a30Sjl 	drmach_board_t		*bp = (drmach_board_t *)id;
1655*25cf1a30Sjl 	sbd_error_t		*err;
1656*25cf1a30Sjl 	int			 max_devices;
1657*25cf1a30Sjl 	int			 rv;
1658*25cf1a30Sjl 	drmach_board_cb_data_t	data;
1659*25cf1a30Sjl 
1660*25cf1a30Sjl 
1661*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
1662*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1663*25cf1a30Sjl 
1664*25cf1a30Sjl 	max_devices  = MAX_CPU_UNITS_PER_BOARD;
1665*25cf1a30Sjl 	max_devices += MAX_MEM_UNITS_PER_BOARD;
1666*25cf1a30Sjl 	max_devices += MAX_IO_UNITS_PER_BOARD;
1667*25cf1a30Sjl 
1668*25cf1a30Sjl 	bp->devices = drmach_array_new(0, max_devices);
1669*25cf1a30Sjl 
1670*25cf1a30Sjl 	if (bp->tree == NULL)
1671*25cf1a30Sjl 		bp->tree = drmach_node_new();
1672*25cf1a30Sjl 
1673*25cf1a30Sjl 	data.obj = bp;
1674*25cf1a30Sjl 	data.ndevs = 0;
1675*25cf1a30Sjl 	data.found = found;
1676*25cf1a30Sjl 	data.a = a;
1677*25cf1a30Sjl 	data.err = NULL;
1678*25cf1a30Sjl 
1679*25cf1a30Sjl 	rv = drmach_node_walk(bp->tree, &data, drmach_board_find_devices_cb);
1680*25cf1a30Sjl 	if (rv == 0)
1681*25cf1a30Sjl 		err = NULL;
1682*25cf1a30Sjl 	else {
1683*25cf1a30Sjl 		drmach_array_dispose(bp->devices, drmach_device_dispose);
1684*25cf1a30Sjl 		bp->devices = NULL;
1685*25cf1a30Sjl 
1686*25cf1a30Sjl 		if (data.err)
1687*25cf1a30Sjl 			err = data.err;
1688*25cf1a30Sjl 		else
1689*25cf1a30Sjl 			err = DRMACH_INTERNAL_ERROR();
1690*25cf1a30Sjl 	}
1691*25cf1a30Sjl 
1692*25cf1a30Sjl 	return (err);
1693*25cf1a30Sjl }
1694*25cf1a30Sjl 
1695*25cf1a30Sjl int
1696*25cf1a30Sjl drmach_board_lookup(int bnum, drmachid_t *id)
1697*25cf1a30Sjl {
1698*25cf1a30Sjl 	int	rv = 0;
1699*25cf1a30Sjl 
1700*25cf1a30Sjl 	rw_enter(&drmach_boards_rwlock, RW_READER);
1701*25cf1a30Sjl 	if (drmach_array_get(drmach_boards, bnum, id)) {
1702*25cf1a30Sjl 		*id = 0;
1703*25cf1a30Sjl 		rv = -1;
1704*25cf1a30Sjl 	}
1705*25cf1a30Sjl 	rw_exit(&drmach_boards_rwlock);
1706*25cf1a30Sjl 	return (rv);
1707*25cf1a30Sjl }
1708*25cf1a30Sjl 
1709*25cf1a30Sjl sbd_error_t *
1710*25cf1a30Sjl drmach_board_name(int bnum, char *buf, int buflen)
1711*25cf1a30Sjl {
1712*25cf1a30Sjl 	snprintf(buf, buflen, "SB%d", bnum);
1713*25cf1a30Sjl 	return (NULL);
1714*25cf1a30Sjl }
1715*25cf1a30Sjl 
1716*25cf1a30Sjl sbd_error_t *
1717*25cf1a30Sjl drmach_board_poweroff(drmachid_t id)
1718*25cf1a30Sjl {
1719*25cf1a30Sjl 	drmach_board_t	*bp;
1720*25cf1a30Sjl 	sbd_error_t	*err;
1721*25cf1a30Sjl 	drmach_status_t	 stat;
1722*25cf1a30Sjl 
1723*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
1724*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1725*25cf1a30Sjl 	bp = id;
1726*25cf1a30Sjl 
1727*25cf1a30Sjl 	err = drmach_board_status(id, &stat);
1728*25cf1a30Sjl 
1729*25cf1a30Sjl 	if (!err) {
1730*25cf1a30Sjl 		if (stat.configured || stat.busy)
1731*25cf1a30Sjl 			err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name);
1732*25cf1a30Sjl 		else {
1733*25cf1a30Sjl 			bp->powered = 0;
1734*25cf1a30Sjl 		}
1735*25cf1a30Sjl 	}
1736*25cf1a30Sjl 	return (err);
1737*25cf1a30Sjl }
1738*25cf1a30Sjl 
1739*25cf1a30Sjl sbd_error_t *
1740*25cf1a30Sjl drmach_board_poweron(drmachid_t id)
1741*25cf1a30Sjl {
1742*25cf1a30Sjl 	drmach_board_t	*bp;
1743*25cf1a30Sjl 
1744*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
1745*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1746*25cf1a30Sjl 	bp = id;
1747*25cf1a30Sjl 
1748*25cf1a30Sjl 	bp->powered = 1;
1749*25cf1a30Sjl 
1750*25cf1a30Sjl 	return (NULL);
1751*25cf1a30Sjl }
1752*25cf1a30Sjl 
1753*25cf1a30Sjl static sbd_error_t *
1754*25cf1a30Sjl drmach_board_release(drmachid_t id)
1755*25cf1a30Sjl {
1756*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
1757*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1758*25cf1a30Sjl 	return (NULL);
1759*25cf1a30Sjl }
1760*25cf1a30Sjl 
1761*25cf1a30Sjl /*ARGSUSED*/
1762*25cf1a30Sjl sbd_error_t *
1763*25cf1a30Sjl drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force)
1764*25cf1a30Sjl {
1765*25cf1a30Sjl 	return (NULL);
1766*25cf1a30Sjl }
1767*25cf1a30Sjl 
1768*25cf1a30Sjl sbd_error_t *
1769*25cf1a30Sjl drmach_board_unassign(drmachid_t id)
1770*25cf1a30Sjl {
1771*25cf1a30Sjl 	drmach_board_t	*bp;
1772*25cf1a30Sjl 	sbd_error_t	*err;
1773*25cf1a30Sjl 	drmach_status_t	 stat;
1774*25cf1a30Sjl 
1775*25cf1a30Sjl 
1776*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id)) {
1777*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1778*25cf1a30Sjl 	}
1779*25cf1a30Sjl 	bp = id;
1780*25cf1a30Sjl 
1781*25cf1a30Sjl 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
1782*25cf1a30Sjl 
1783*25cf1a30Sjl 	err = drmach_board_status(id, &stat);
1784*25cf1a30Sjl 	if (err) {
1785*25cf1a30Sjl 		rw_exit(&drmach_boards_rwlock);
1786*25cf1a30Sjl 		return (err);
1787*25cf1a30Sjl 	}
1788*25cf1a30Sjl 	if (stat.configured || stat.busy) {
1789*25cf1a30Sjl 		err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name);
1790*25cf1a30Sjl 	} else {
1791*25cf1a30Sjl 		if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0)
1792*25cf1a30Sjl 			err = DRMACH_INTERNAL_ERROR();
1793*25cf1a30Sjl 		else
1794*25cf1a30Sjl 			drmach_board_dispose(bp);
1795*25cf1a30Sjl 	}
1796*25cf1a30Sjl 	rw_exit(&drmach_boards_rwlock);
1797*25cf1a30Sjl 	return (err);
1798*25cf1a30Sjl }
1799*25cf1a30Sjl 
1800*25cf1a30Sjl /*
1801*25cf1a30Sjl  * We have to do more on OPL - e.g. set up sram tte, read cpuid, strand id,
1802*25cf1a30Sjl  * implementation #, etc
1803*25cf1a30Sjl  */
1804*25cf1a30Sjl 
1805*25cf1a30Sjl static sbd_error_t *
1806*25cf1a30Sjl drmach_cpu_new(drmach_device_t *proto, drmachid_t *idp)
1807*25cf1a30Sjl {
1808*25cf1a30Sjl 	static void drmach_cpu_dispose(drmachid_t);
1809*25cf1a30Sjl 	static sbd_error_t *drmach_cpu_release(drmachid_t);
1810*25cf1a30Sjl 	static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *);
1811*25cf1a30Sjl 
1812*25cf1a30Sjl 	int		 portid;
1813*25cf1a30Sjl 	drmach_cpu_t	*cp = NULL;
1814*25cf1a30Sjl 
1815*25cf1a30Sjl 	/* portid is CPUID of the node */
1816*25cf1a30Sjl 	portid = proto->portid;
1817*25cf1a30Sjl 	ASSERT(portid != -1);
1818*25cf1a30Sjl 
1819*25cf1a30Sjl 	/* unum = (CMP/CHIP ID) + (ON_BOARD_CORE_NUM * MAX_CMPID_PER_BOARD) */
1820*25cf1a30Sjl 	proto->unum = ((portid/OPL_MAX_CPUID_PER_CMP) &
1821*25cf1a30Sjl 		(OPL_MAX_CMPID_PER_BOARD - 1)) +
1822*25cf1a30Sjl 		((portid & (OPL_MAX_CPUID_PER_CMP - 1)) *
1823*25cf1a30Sjl 		(OPL_MAX_CMPID_PER_BOARD));
1824*25cf1a30Sjl 
1825*25cf1a30Sjl 	cp = kmem_zalloc(sizeof (drmach_cpu_t), KM_SLEEP);
1826*25cf1a30Sjl 	bcopy(proto, &cp->dev, sizeof (cp->dev));
1827*25cf1a30Sjl 	cp->dev.node = drmach_node_dup(proto->node);
1828*25cf1a30Sjl 	cp->dev.cm.isa = (void *)drmach_cpu_new;
1829*25cf1a30Sjl 	cp->dev.cm.dispose = drmach_cpu_dispose;
1830*25cf1a30Sjl 	cp->dev.cm.release = drmach_cpu_release;
1831*25cf1a30Sjl 	cp->dev.cm.status = drmach_cpu_status;
1832*25cf1a30Sjl 
1833*25cf1a30Sjl 	snprintf(cp->dev.cm.name, sizeof (cp->dev.cm.name), "%s%d",
1834*25cf1a30Sjl 		cp->dev.type, cp->dev.unum);
1835*25cf1a30Sjl 
1836*25cf1a30Sjl /*
1837*25cf1a30Sjl  *	CPU ID representation
1838*25cf1a30Sjl  *	CPUID[9:5] = SB#
1839*25cf1a30Sjl  *	CPUID[4:3] = Chip#
1840*25cf1a30Sjl  *	CPUID[2:1] = Core# (Only 2 core for OPL)
1841*25cf1a30Sjl  *	CPUID[0:0] = Strand#
1842*25cf1a30Sjl  */
1843*25cf1a30Sjl 
1844*25cf1a30Sjl /*
1845*25cf1a30Sjl  *	reg property of the strand contains strand ID
1846*25cf1a30Sjl  *	reg property of the parent node contains core ID
1847*25cf1a30Sjl  *	We should use them.
1848*25cf1a30Sjl  */
1849*25cf1a30Sjl 	cp->cpuid = portid;
1850*25cf1a30Sjl 	cp->sb = (portid >> 5) & 0x1f;
1851*25cf1a30Sjl 	cp->chipid = (portid >> 3) & 0x3;
1852*25cf1a30Sjl 	cp->coreid = (portid >> 1) & 0x3;
1853*25cf1a30Sjl 	cp->strandid = portid & 0x1;
1854*25cf1a30Sjl 
1855*25cf1a30Sjl 	*idp = (drmachid_t)cp;
1856*25cf1a30Sjl 	return (NULL);
1857*25cf1a30Sjl }
1858*25cf1a30Sjl 
1859*25cf1a30Sjl 
1860*25cf1a30Sjl static void
1861*25cf1a30Sjl drmach_cpu_dispose(drmachid_t id)
1862*25cf1a30Sjl {
1863*25cf1a30Sjl 	drmach_cpu_t	*self;
1864*25cf1a30Sjl 
1865*25cf1a30Sjl 	ASSERT(DRMACH_IS_CPU_ID(id));
1866*25cf1a30Sjl 
1867*25cf1a30Sjl 	self = id;
1868*25cf1a30Sjl 	if (self->dev.node)
1869*25cf1a30Sjl 		drmach_node_dispose(self->dev.node);
1870*25cf1a30Sjl 
1871*25cf1a30Sjl 	kmem_free(self, sizeof (*self));
1872*25cf1a30Sjl }
1873*25cf1a30Sjl 
1874*25cf1a30Sjl static int
1875*25cf1a30Sjl drmach_cpu_start(struct cpu *cp)
1876*25cf1a30Sjl {
1877*25cf1a30Sjl 	int		cpuid = cp->cpu_id;
1878*25cf1a30Sjl 	extern int	restart_other_cpu(int);
1879*25cf1a30Sjl 
1880*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&cpu_lock));
1881*25cf1a30Sjl 	ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0);
1882*25cf1a30Sjl 
1883*25cf1a30Sjl 	cp->cpu_flags &= ~CPU_POWEROFF;
1884*25cf1a30Sjl 
1885*25cf1a30Sjl 	/*
1886*25cf1a30Sjl 	 * NOTE: restart_other_cpu pauses cpus during the
1887*25cf1a30Sjl 	 *	 slave cpu start.  This helps to quiesce the
1888*25cf1a30Sjl 	 *	 bus traffic a bit which makes the tick sync
1889*25cf1a30Sjl 	 *	 routine in the prom more robust.
1890*25cf1a30Sjl 	 */
1891*25cf1a30Sjl 	DRMACH_PR("COLD START for cpu (%d)\n", cpuid);
1892*25cf1a30Sjl 
1893*25cf1a30Sjl 	restart_other_cpu(cpuid);
1894*25cf1a30Sjl 
1895*25cf1a30Sjl 	return (0);
1896*25cf1a30Sjl }
1897*25cf1a30Sjl 
1898*25cf1a30Sjl static sbd_error_t *
1899*25cf1a30Sjl drmach_cpu_release(drmachid_t id)
1900*25cf1a30Sjl {
1901*25cf1a30Sjl 	if (!DRMACH_IS_CPU_ID(id))
1902*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1903*25cf1a30Sjl 
1904*25cf1a30Sjl 	return (NULL);
1905*25cf1a30Sjl }
1906*25cf1a30Sjl 
1907*25cf1a30Sjl static sbd_error_t *
1908*25cf1a30Sjl drmach_cpu_status(drmachid_t id, drmach_status_t *stat)
1909*25cf1a30Sjl {
1910*25cf1a30Sjl 	drmach_cpu_t *cp;
1911*25cf1a30Sjl 	drmach_device_t *dp;
1912*25cf1a30Sjl 
1913*25cf1a30Sjl 	ASSERT(DRMACH_IS_CPU_ID(id));
1914*25cf1a30Sjl 	cp = (drmach_cpu_t *)id;
1915*25cf1a30Sjl 	dp = &cp->dev;
1916*25cf1a30Sjl 
1917*25cf1a30Sjl 	stat->assigned = dp->bp->assigned;
1918*25cf1a30Sjl 	stat->powered = dp->bp->powered;
1919*25cf1a30Sjl 	mutex_enter(&cpu_lock);
1920*25cf1a30Sjl 	stat->configured = (cpu_get(cp->cpuid) != NULL);
1921*25cf1a30Sjl 	mutex_exit(&cpu_lock);
1922*25cf1a30Sjl 	stat->busy = dp->busy;
1923*25cf1a30Sjl 	strncpy(stat->type, dp->type, sizeof (stat->type));
1924*25cf1a30Sjl 	stat->info[0] = '\0';
1925*25cf1a30Sjl 
1926*25cf1a30Sjl 	return (NULL);
1927*25cf1a30Sjl }
1928*25cf1a30Sjl 
1929*25cf1a30Sjl sbd_error_t *
1930*25cf1a30Sjl drmach_cpu_disconnect(drmachid_t id)
1931*25cf1a30Sjl {
1932*25cf1a30Sjl 
1933*25cf1a30Sjl 	if (!DRMACH_IS_CPU_ID(id))
1934*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1935*25cf1a30Sjl 
1936*25cf1a30Sjl 	return (NULL);
1937*25cf1a30Sjl }
1938*25cf1a30Sjl 
1939*25cf1a30Sjl sbd_error_t *
1940*25cf1a30Sjl drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid)
1941*25cf1a30Sjl {
1942*25cf1a30Sjl 	drmach_cpu_t *cpu;
1943*25cf1a30Sjl 
1944*25cf1a30Sjl 	if (!DRMACH_IS_CPU_ID(id))
1945*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1946*25cf1a30Sjl 	cpu = (drmach_cpu_t *)id;
1947*25cf1a30Sjl 
1948*25cf1a30Sjl 	/* get from cpu directly on OPL */
1949*25cf1a30Sjl 	*cpuid = cpu->cpuid;
1950*25cf1a30Sjl 	return (NULL);
1951*25cf1a30Sjl }
1952*25cf1a30Sjl 
1953*25cf1a30Sjl sbd_error_t *
1954*25cf1a30Sjl drmach_cpu_get_impl(drmachid_t id, int *ip)
1955*25cf1a30Sjl {
1956*25cf1a30Sjl 	drmach_device_t *cpu;
1957*25cf1a30Sjl 	drmach_node_t	*np;
1958*25cf1a30Sjl 	drmach_node_t	pp;
1959*25cf1a30Sjl 	int		impl;
1960*25cf1a30Sjl 	char		type[OBP_MAXPROPNAME];
1961*25cf1a30Sjl 
1962*25cf1a30Sjl 	if (!DRMACH_IS_CPU_ID(id))
1963*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1964*25cf1a30Sjl 
1965*25cf1a30Sjl 	cpu = id;
1966*25cf1a30Sjl 	np = cpu->node;
1967*25cf1a30Sjl 
1968*25cf1a30Sjl 	if (np->get_parent(np, &pp) != 0) {
1969*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
1970*25cf1a30Sjl 	}
1971*25cf1a30Sjl 
1972*25cf1a30Sjl 	/* the parent should be core */
1973*25cf1a30Sjl 
1974*25cf1a30Sjl 	if (pp.n_getprop(&pp, "device_type", &type, sizeof (type)) != 0) {
1975*25cf1a30Sjl 		return (drerr_new(0, EOPL_GETPROP, NULL));
1976*25cf1a30Sjl 	}
1977*25cf1a30Sjl 
1978*25cf1a30Sjl 	if (strcmp(type, OPL_CORE_NODE) == 0) {
1979*25cf1a30Sjl 		if (pp.n_getprop(&pp, "implementation#",
1980*25cf1a30Sjl 			&impl, sizeof (impl)) != 0) {
1981*25cf1a30Sjl 			return (drerr_new(0, EOPL_GETPROP, NULL));
1982*25cf1a30Sjl 		}
1983*25cf1a30Sjl 	} else {
1984*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
1985*25cf1a30Sjl 	}
1986*25cf1a30Sjl 
1987*25cf1a30Sjl 	*ip = impl;
1988*25cf1a30Sjl 
1989*25cf1a30Sjl 	return (NULL);
1990*25cf1a30Sjl }
1991*25cf1a30Sjl 
1992*25cf1a30Sjl sbd_error_t *
1993*25cf1a30Sjl drmach_get_dip(drmachid_t id, dev_info_t **dip)
1994*25cf1a30Sjl {
1995*25cf1a30Sjl 	drmach_device_t	*dp;
1996*25cf1a30Sjl 
1997*25cf1a30Sjl 	if (!DRMACH_IS_DEVICE_ID(id))
1998*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
1999*25cf1a30Sjl 	dp = id;
2000*25cf1a30Sjl 
2001*25cf1a30Sjl 	*dip = dp->node->n_getdip(dp->node);
2002*25cf1a30Sjl 	return (NULL);
2003*25cf1a30Sjl }
2004*25cf1a30Sjl 
2005*25cf1a30Sjl sbd_error_t *
2006*25cf1a30Sjl drmach_io_is_attached(drmachid_t id, int *yes)
2007*25cf1a30Sjl {
2008*25cf1a30Sjl 	drmach_device_t *dp;
2009*25cf1a30Sjl 	dev_info_t	*dip;
2010*25cf1a30Sjl 	int		state;
2011*25cf1a30Sjl 
2012*25cf1a30Sjl 	if (!DRMACH_IS_IO_ID(id))
2013*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2014*25cf1a30Sjl 	dp = id;
2015*25cf1a30Sjl 
2016*25cf1a30Sjl 	dip = dp->node->n_getdip(dp->node);
2017*25cf1a30Sjl 	if (dip == NULL) {
2018*25cf1a30Sjl 		*yes = 0;
2019*25cf1a30Sjl 		return (NULL);
2020*25cf1a30Sjl 	}
2021*25cf1a30Sjl 
2022*25cf1a30Sjl 	state = ddi_get_devstate(dip);
2023*25cf1a30Sjl 	*yes = ((i_ddi_node_state(dip) >= DS_ATTACHED) ||
2024*25cf1a30Sjl 	    (state == DDI_DEVSTATE_UP));
2025*25cf1a30Sjl 
2026*25cf1a30Sjl 	return (NULL);
2027*25cf1a30Sjl }
2028*25cf1a30Sjl 
2029*25cf1a30Sjl struct drmach_io_cb {
2030*25cf1a30Sjl 	char	*name;	/* name of the node */
2031*25cf1a30Sjl 	int	(*func)(dev_info_t *);
2032*25cf1a30Sjl 	int	rv;
2033*25cf1a30Sjl };
2034*25cf1a30Sjl 
2035*25cf1a30Sjl #define	DRMACH_IO_POST_ATTACH	0
2036*25cf1a30Sjl #define	DRMACH_IO_PRE_RELEASE	1
2037*25cf1a30Sjl 
2038*25cf1a30Sjl static int
2039*25cf1a30Sjl drmach_io_cb_check(dev_info_t *dip, void *arg)
2040*25cf1a30Sjl {
2041*25cf1a30Sjl 	struct drmach_io_cb *p = (struct drmach_io_cb *)arg;
2042*25cf1a30Sjl 	char name[OBP_MAXDRVNAME];
2043*25cf1a30Sjl 	int len = OBP_MAXDRVNAME;
2044*25cf1a30Sjl 
2045*25cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
2046*25cf1a30Sjl 		DDI_PROP_DONTPASS, "name",
2047*25cf1a30Sjl 	    (caddr_t)name, &len) != DDI_PROP_SUCCESS) {
2048*25cf1a30Sjl 		return (DDI_WALK_PRUNECHILD);
2049*25cf1a30Sjl 	}
2050*25cf1a30Sjl 
2051*25cf1a30Sjl 	if (strcmp(name, p->name) == 0) {
2052*25cf1a30Sjl 		p->rv = (*p->func)(dip);
2053*25cf1a30Sjl 		return (DDI_WALK_TERMINATE);
2054*25cf1a30Sjl 	}
2055*25cf1a30Sjl 
2056*25cf1a30Sjl 	return (DDI_WALK_CONTINUE);
2057*25cf1a30Sjl }
2058*25cf1a30Sjl 
2059*25cf1a30Sjl 
2060*25cf1a30Sjl static int
2061*25cf1a30Sjl drmach_console_ops(drmachid_t *id, int state)
2062*25cf1a30Sjl {
2063*25cf1a30Sjl 	drmach_io_t *obj = (drmach_io_t *)id;
2064*25cf1a30Sjl 	struct drmach_io_cb arg;
2065*25cf1a30Sjl 	int (*msudetp)(dev_info_t *);
2066*25cf1a30Sjl 	int (*msuattp)(dev_info_t *);
2067*25cf1a30Sjl 	dev_info_t *dip, *pdip;
2068*25cf1a30Sjl 	int circ;
2069*25cf1a30Sjl 
2070*25cf1a30Sjl 	/* 4 is pcicmu channel */
2071*25cf1a30Sjl 	if (obj->channel != 4)
2072*25cf1a30Sjl 		return (0);
2073*25cf1a30Sjl 
2074*25cf1a30Sjl 	arg.name = "serial";
2075*25cf1a30Sjl 	arg.func = NULL;
2076*25cf1a30Sjl 	if (state == DRMACH_IO_PRE_RELEASE) {
2077*25cf1a30Sjl 		msudetp = (int (*)(dev_info_t *))
2078*25cf1a30Sjl 		    modgetsymvalue("oplmsu_dr_detach", 0);
2079*25cf1a30Sjl 		if (msudetp != NULL)
2080*25cf1a30Sjl 			arg.func = msudetp;
2081*25cf1a30Sjl 	} else if (state == DRMACH_IO_POST_ATTACH) {
2082*25cf1a30Sjl 		msuattp = (int (*)(dev_info_t *))
2083*25cf1a30Sjl 		    modgetsymvalue("oplmsu_dr_attach", 0);
2084*25cf1a30Sjl 		if (msuattp != NULL)
2085*25cf1a30Sjl 			arg.func = msuattp;
2086*25cf1a30Sjl 	}
2087*25cf1a30Sjl 	else
2088*25cf1a30Sjl 		return (0);
2089*25cf1a30Sjl 
2090*25cf1a30Sjl 	if (arg.func == NULL) {
2091*25cf1a30Sjl 		return (0);
2092*25cf1a30Sjl 	}
2093*25cf1a30Sjl 
2094*25cf1a30Sjl 	arg.rv = 0;
2095*25cf1a30Sjl 
2096*25cf1a30Sjl 	dip = obj->dev.node->n_getdip(obj->dev.node);
2097*25cf1a30Sjl 	if (pdip = ddi_get_parent(dip)) {
2098*25cf1a30Sjl 		ndi_hold_devi(pdip);
2099*25cf1a30Sjl 		ndi_devi_enter(pdip, &circ);
2100*25cf1a30Sjl 	} else {
2101*25cf1a30Sjl 		/* this cannot happen unless something bad happens */
2102*25cf1a30Sjl 		return (-1);
2103*25cf1a30Sjl 	}
2104*25cf1a30Sjl 
2105*25cf1a30Sjl 	ddi_walk_devs(dip, drmach_io_cb_check, (void *)&arg);
2106*25cf1a30Sjl 
2107*25cf1a30Sjl 	if (pdip) {
2108*25cf1a30Sjl 		ndi_devi_exit(pdip, circ);
2109*25cf1a30Sjl 		ndi_rele_devi(pdip);
2110*25cf1a30Sjl 	}
2111*25cf1a30Sjl 
2112*25cf1a30Sjl 	return (arg.rv);
2113*25cf1a30Sjl }
2114*25cf1a30Sjl 
2115*25cf1a30Sjl sbd_error_t *
2116*25cf1a30Sjl drmach_io_pre_release(drmachid_t id)
2117*25cf1a30Sjl {
2118*25cf1a30Sjl 	int rv;
2119*25cf1a30Sjl 
2120*25cf1a30Sjl 	if (!DRMACH_IS_IO_ID(id))
2121*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2122*25cf1a30Sjl 
2123*25cf1a30Sjl 	rv = drmach_console_ops(id, DRMACH_IO_PRE_RELEASE);
2124*25cf1a30Sjl 
2125*25cf1a30Sjl 	if (rv != 0)
2126*25cf1a30Sjl 		cmn_err(CE_WARN, "IO callback failed in pre-release\n");
2127*25cf1a30Sjl 
2128*25cf1a30Sjl 	return (NULL);
2129*25cf1a30Sjl }
2130*25cf1a30Sjl 
2131*25cf1a30Sjl static sbd_error_t *
2132*25cf1a30Sjl drmach_io_release(drmachid_t id)
2133*25cf1a30Sjl {
2134*25cf1a30Sjl 	if (!DRMACH_IS_IO_ID(id))
2135*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2136*25cf1a30Sjl 	return (NULL);
2137*25cf1a30Sjl }
2138*25cf1a30Sjl 
2139*25cf1a30Sjl sbd_error_t *
2140*25cf1a30Sjl drmach_io_unrelease(drmachid_t id)
2141*25cf1a30Sjl {
2142*25cf1a30Sjl 	if (!DRMACH_IS_IO_ID(id))
2143*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2144*25cf1a30Sjl 	return (NULL);
2145*25cf1a30Sjl }
2146*25cf1a30Sjl 
2147*25cf1a30Sjl /*ARGSUSED*/
2148*25cf1a30Sjl sbd_error_t *
2149*25cf1a30Sjl drmach_io_post_release(drmachid_t id)
2150*25cf1a30Sjl {
2151*25cf1a30Sjl 	return (NULL);
2152*25cf1a30Sjl }
2153*25cf1a30Sjl 
2154*25cf1a30Sjl /*ARGSUSED*/
2155*25cf1a30Sjl sbd_error_t *
2156*25cf1a30Sjl drmach_io_post_attach(drmachid_t id)
2157*25cf1a30Sjl {
2158*25cf1a30Sjl 	int rv;
2159*25cf1a30Sjl 
2160*25cf1a30Sjl 	if (!DRMACH_IS_IO_ID(id))
2161*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2162*25cf1a30Sjl 
2163*25cf1a30Sjl 	rv = drmach_console_ops(id, DRMACH_IO_POST_ATTACH);
2164*25cf1a30Sjl 
2165*25cf1a30Sjl 	if (rv != 0)
2166*25cf1a30Sjl 		cmn_err(CE_WARN, "IO callback failed in post-attach\n");
2167*25cf1a30Sjl 
2168*25cf1a30Sjl 	return (0);
2169*25cf1a30Sjl }
2170*25cf1a30Sjl 
2171*25cf1a30Sjl static sbd_error_t *
2172*25cf1a30Sjl drmach_io_status(drmachid_t id, drmach_status_t *stat)
2173*25cf1a30Sjl {
2174*25cf1a30Sjl 	drmach_device_t *dp;
2175*25cf1a30Sjl 	sbd_error_t	*err;
2176*25cf1a30Sjl 	int		 configured;
2177*25cf1a30Sjl 
2178*25cf1a30Sjl 	ASSERT(DRMACH_IS_IO_ID(id));
2179*25cf1a30Sjl 	dp = id;
2180*25cf1a30Sjl 
2181*25cf1a30Sjl 	err = drmach_io_is_attached(id, &configured);
2182*25cf1a30Sjl 	if (err)
2183*25cf1a30Sjl 		return (err);
2184*25cf1a30Sjl 
2185*25cf1a30Sjl 	stat->assigned = dp->bp->assigned;
2186*25cf1a30Sjl 	stat->powered = dp->bp->powered;
2187*25cf1a30Sjl 	stat->configured = (configured != 0);
2188*25cf1a30Sjl 	stat->busy = dp->busy;
2189*25cf1a30Sjl 	strncpy(stat->type, dp->type, sizeof (stat->type));
2190*25cf1a30Sjl 	stat->info[0] = '\0';
2191*25cf1a30Sjl 
2192*25cf1a30Sjl 	return (NULL);
2193*25cf1a30Sjl }
2194*25cf1a30Sjl 
2195*25cf1a30Sjl static sbd_error_t *
2196*25cf1a30Sjl drmach_mem_new(drmach_device_t *proto, drmachid_t *idp)
2197*25cf1a30Sjl {
2198*25cf1a30Sjl 	static void drmach_mem_dispose(drmachid_t);
2199*25cf1a30Sjl 	static sbd_error_t *drmach_mem_release(drmachid_t);
2200*25cf1a30Sjl 	static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *);
2201*25cf1a30Sjl 	dev_info_t *dip;
2202*25cf1a30Sjl 
2203*25cf1a30Sjl 	drmach_mem_t	*mp;
2204*25cf1a30Sjl 
2205*25cf1a30Sjl 	mp = kmem_zalloc(sizeof (drmach_mem_t), KM_SLEEP);
2206*25cf1a30Sjl 	proto->unum = 0;
2207*25cf1a30Sjl 
2208*25cf1a30Sjl 	bcopy(proto, &mp->dev, sizeof (mp->dev));
2209*25cf1a30Sjl 	mp->dev.node = drmach_node_dup(proto->node);
2210*25cf1a30Sjl 	mp->dev.cm.isa = (void *)drmach_mem_new;
2211*25cf1a30Sjl 	mp->dev.cm.dispose = drmach_mem_dispose;
2212*25cf1a30Sjl 	mp->dev.cm.release = drmach_mem_release;
2213*25cf1a30Sjl 	mp->dev.cm.status = drmach_mem_status;
2214*25cf1a30Sjl 
2215*25cf1a30Sjl 	snprintf(mp->dev.cm.name,
2216*25cf1a30Sjl 		sizeof (mp->dev.cm.name), "%s", mp->dev.type);
2217*25cf1a30Sjl 
2218*25cf1a30Sjl 	dip = mp->dev.node->n_getdip(mp->dev.node);
2219*25cf1a30Sjl 	if (drmach_setup_mc_info(dip, mp) != 0) {
2220*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
2221*25cf1a30Sjl 	}
2222*25cf1a30Sjl 
2223*25cf1a30Sjl 	*idp = (drmachid_t)mp;
2224*25cf1a30Sjl 	return (NULL);
2225*25cf1a30Sjl }
2226*25cf1a30Sjl 
2227*25cf1a30Sjl static void
2228*25cf1a30Sjl drmach_mem_dispose(drmachid_t id)
2229*25cf1a30Sjl {
2230*25cf1a30Sjl 	drmach_mem_t *mp;
2231*25cf1a30Sjl 
2232*25cf1a30Sjl 	ASSERT(DRMACH_IS_MEM_ID(id));
2233*25cf1a30Sjl 
2234*25cf1a30Sjl 
2235*25cf1a30Sjl 	mp = id;
2236*25cf1a30Sjl 
2237*25cf1a30Sjl 	if (mp->dev.node)
2238*25cf1a30Sjl 		drmach_node_dispose(mp->dev.node);
2239*25cf1a30Sjl 
2240*25cf1a30Sjl 	if (mp->memlist) {
2241*25cf1a30Sjl 		memlist_delete(mp->memlist);
2242*25cf1a30Sjl 		mp->memlist = NULL;
2243*25cf1a30Sjl 	}
2244*25cf1a30Sjl }
2245*25cf1a30Sjl 
2246*25cf1a30Sjl sbd_error_t *
2247*25cf1a30Sjl drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size)
2248*25cf1a30Sjl {
2249*25cf1a30Sjl 	pfn_t		basepfn = (pfn_t)(basepa >> PAGESHIFT);
2250*25cf1a30Sjl 	pgcnt_t		npages = (pgcnt_t)(size >> PAGESHIFT);
2251*25cf1a30Sjl 	int		rv;
2252*25cf1a30Sjl 
2253*25cf1a30Sjl 	ASSERT(size != 0);
2254*25cf1a30Sjl 
2255*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2256*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2257*25cf1a30Sjl 
2258*25cf1a30Sjl 	kcage_range_lock();
2259*25cf1a30Sjl 	rv = kcage_range_add(basepfn, npages, 1);
2260*25cf1a30Sjl 	kcage_range_unlock();
2261*25cf1a30Sjl 	if (rv == ENOMEM) {
2262*25cf1a30Sjl 		cmn_err(CE_WARN, "%ld megabytes not available to kernel cage",
2263*25cf1a30Sjl 			(size == 0 ? 0 : size / MBYTE));
2264*25cf1a30Sjl 	} else if (rv != 0) {
2265*25cf1a30Sjl 		/* catch this in debug kernels */
2266*25cf1a30Sjl 		ASSERT(0);
2267*25cf1a30Sjl 
2268*25cf1a30Sjl 		cmn_err(CE_WARN, "unexpected kcage_range_add"
2269*25cf1a30Sjl 			" return value %d", rv);
2270*25cf1a30Sjl 	}
2271*25cf1a30Sjl 
2272*25cf1a30Sjl 	if (rv) {
2273*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
2274*25cf1a30Sjl 	}
2275*25cf1a30Sjl 	else
2276*25cf1a30Sjl 		return (NULL);
2277*25cf1a30Sjl }
2278*25cf1a30Sjl 
2279*25cf1a30Sjl sbd_error_t *
2280*25cf1a30Sjl drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size)
2281*25cf1a30Sjl {
2282*25cf1a30Sjl 	pfn_t		basepfn = (pfn_t)(basepa >> PAGESHIFT);
2283*25cf1a30Sjl 	pgcnt_t		npages = (pgcnt_t)(size >> PAGESHIFT);
2284*25cf1a30Sjl 	int		rv;
2285*25cf1a30Sjl 
2286*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2287*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2288*25cf1a30Sjl 
2289*25cf1a30Sjl 	if (size > 0) {
2290*25cf1a30Sjl 		kcage_range_lock();
2291*25cf1a30Sjl 		rv = kcage_range_delete_post_mem_del(basepfn, npages);
2292*25cf1a30Sjl 		kcage_range_unlock();
2293*25cf1a30Sjl 		if (rv != 0) {
2294*25cf1a30Sjl 			cmn_err(CE_WARN,
2295*25cf1a30Sjl 			    "unexpected kcage_range_delete_post_mem_del"
2296*25cf1a30Sjl 			    " return value %d", rv);
2297*25cf1a30Sjl 			return (DRMACH_INTERNAL_ERROR());
2298*25cf1a30Sjl 		}
2299*25cf1a30Sjl 	}
2300*25cf1a30Sjl 
2301*25cf1a30Sjl 	return (NULL);
2302*25cf1a30Sjl }
2303*25cf1a30Sjl 
2304*25cf1a30Sjl sbd_error_t *
2305*25cf1a30Sjl drmach_mem_disable(drmachid_t id)
2306*25cf1a30Sjl {
2307*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2308*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2309*25cf1a30Sjl 	else {
2310*25cf1a30Sjl 		drmach_flush_all();
2311*25cf1a30Sjl 		return (NULL);
2312*25cf1a30Sjl 	}
2313*25cf1a30Sjl }
2314*25cf1a30Sjl 
2315*25cf1a30Sjl sbd_error_t *
2316*25cf1a30Sjl drmach_mem_enable(drmachid_t id)
2317*25cf1a30Sjl {
2318*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2319*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2320*25cf1a30Sjl 	else
2321*25cf1a30Sjl 		return (NULL);
2322*25cf1a30Sjl }
2323*25cf1a30Sjl 
2324*25cf1a30Sjl sbd_error_t *
2325*25cf1a30Sjl drmach_mem_get_info(drmachid_t id, drmach_mem_info_t *mem)
2326*25cf1a30Sjl {
2327*25cf1a30Sjl 	drmach_mem_t *mp;
2328*25cf1a30Sjl 
2329*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2330*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2331*25cf1a30Sjl 
2332*25cf1a30Sjl 	mp = (drmach_mem_t *)id;
2333*25cf1a30Sjl 
2334*25cf1a30Sjl 	/*
2335*25cf1a30Sjl 	 * This is only used by dr to round up/down the memory
2336*25cf1a30Sjl 	 * for copying. Our unit of memory isolation is 64 MB.
2337*25cf1a30Sjl 	 */
2338*25cf1a30Sjl 
2339*25cf1a30Sjl 	mem->mi_alignment_mask = (64 * 1024 * 1024 - 1);
2340*25cf1a30Sjl 	mem->mi_basepa = mp->base_pa;
2341*25cf1a30Sjl 	mem->mi_size = mp->nbytes;
2342*25cf1a30Sjl 	mem->mi_slice_size = mp->slice_size;
2343*25cf1a30Sjl 
2344*25cf1a30Sjl 	return (NULL);
2345*25cf1a30Sjl }
2346*25cf1a30Sjl 
2347*25cf1a30Sjl sbd_error_t *
2348*25cf1a30Sjl drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa)
2349*25cf1a30Sjl {
2350*25cf1a30Sjl 	drmach_mem_t *mp;
2351*25cf1a30Sjl 
2352*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2353*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2354*25cf1a30Sjl 
2355*25cf1a30Sjl 	mp = (drmach_mem_t *)id;
2356*25cf1a30Sjl 
2357*25cf1a30Sjl 	*pa = mp->base_pa;
2358*25cf1a30Sjl 	return (NULL);
2359*25cf1a30Sjl }
2360*25cf1a30Sjl 
2361*25cf1a30Sjl sbd_error_t *
2362*25cf1a30Sjl drmach_mem_get_memlist(drmachid_t id, struct memlist **ml)
2363*25cf1a30Sjl {
2364*25cf1a30Sjl 	drmach_mem_t	*mem;
2365*25cf1a30Sjl 	int		rv;
2366*25cf1a30Sjl 	struct memlist	*mlist;
2367*25cf1a30Sjl 
2368*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2369*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2370*25cf1a30Sjl 
2371*25cf1a30Sjl 	mem = (drmach_mem_t *)id;
2372*25cf1a30Sjl 	mlist = memlist_dup(mem->memlist);
2373*25cf1a30Sjl 
2374*25cf1a30Sjl #ifdef DEBUG
2375*25cf1a30Sjl 	/*
2376*25cf1a30Sjl 	 * Make sure the incoming memlist doesn't already
2377*25cf1a30Sjl 	 * intersect with what's present in the system (phys_install).
2378*25cf1a30Sjl 	 */
2379*25cf1a30Sjl 	memlist_read_lock();
2380*25cf1a30Sjl 	rv = memlist_intersect(phys_install, mlist);
2381*25cf1a30Sjl 	memlist_read_unlock();
2382*25cf1a30Sjl 	if (rv) {
2383*25cf1a30Sjl 		DRMACH_PR("Derived memlist intersects"
2384*25cf1a30Sjl 			" with phys_install\n");
2385*25cf1a30Sjl 		memlist_dump(mlist);
2386*25cf1a30Sjl 
2387*25cf1a30Sjl 		DRMACH_PR("phys_install memlist:\n");
2388*25cf1a30Sjl 		memlist_dump(phys_install);
2389*25cf1a30Sjl 
2390*25cf1a30Sjl 		memlist_delete(mlist);
2391*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
2392*25cf1a30Sjl 	}
2393*25cf1a30Sjl 
2394*25cf1a30Sjl 	DRMACH_PR("Derived memlist:");
2395*25cf1a30Sjl 	memlist_dump(mlist);
2396*25cf1a30Sjl #endif
2397*25cf1a30Sjl 
2398*25cf1a30Sjl 	*ml = mlist;
2399*25cf1a30Sjl 
2400*25cf1a30Sjl 	return (NULL);
2401*25cf1a30Sjl }
2402*25cf1a30Sjl 
2403*25cf1a30Sjl sbd_error_t *
2404*25cf1a30Sjl drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes)
2405*25cf1a30Sjl {
2406*25cf1a30Sjl 	drmach_mem_t	*mem;
2407*25cf1a30Sjl 
2408*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2409*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2410*25cf1a30Sjl 
2411*25cf1a30Sjl 	mem = (drmach_mem_t *)id;
2412*25cf1a30Sjl 
2413*25cf1a30Sjl 	*bytes = mem->slice_size;
2414*25cf1a30Sjl 
2415*25cf1a30Sjl 	return (NULL);
2416*25cf1a30Sjl }
2417*25cf1a30Sjl 
2418*25cf1a30Sjl 
2419*25cf1a30Sjl /* ARGSUSED */
2420*25cf1a30Sjl processorid_t
2421*25cf1a30Sjl drmach_mem_cpu_affinity(drmachid_t id)
2422*25cf1a30Sjl {
2423*25cf1a30Sjl 	return (CPU_CURRENT);
2424*25cf1a30Sjl }
2425*25cf1a30Sjl 
2426*25cf1a30Sjl static sbd_error_t *
2427*25cf1a30Sjl drmach_mem_release(drmachid_t id)
2428*25cf1a30Sjl {
2429*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(id))
2430*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2431*25cf1a30Sjl 	return (NULL);
2432*25cf1a30Sjl }
2433*25cf1a30Sjl 
2434*25cf1a30Sjl static sbd_error_t *
2435*25cf1a30Sjl drmach_mem_status(drmachid_t id, drmach_status_t *stat)
2436*25cf1a30Sjl {
2437*25cf1a30Sjl 	drmach_mem_t *dp;
2438*25cf1a30Sjl 	uint64_t	 pa, slice_size;
2439*25cf1a30Sjl 	struct memlist	*ml;
2440*25cf1a30Sjl 
2441*25cf1a30Sjl 	ASSERT(DRMACH_IS_MEM_ID(id));
2442*25cf1a30Sjl 	dp = id;
2443*25cf1a30Sjl 
2444*25cf1a30Sjl 	/* get starting physical address of target memory */
2445*25cf1a30Sjl 	pa = dp->base_pa;
2446*25cf1a30Sjl 
2447*25cf1a30Sjl 	/* round down to slice boundary */
2448*25cf1a30Sjl 	slice_size = dp->slice_size;
2449*25cf1a30Sjl 	pa &= ~(slice_size - 1);
2450*25cf1a30Sjl 
2451*25cf1a30Sjl 	/* stop at first span that is in slice */
2452*25cf1a30Sjl 	memlist_read_lock();
2453*25cf1a30Sjl 	for (ml = phys_install; ml; ml = ml->next)
2454*25cf1a30Sjl 		if (ml->address >= pa && ml->address < pa + slice_size)
2455*25cf1a30Sjl 			break;
2456*25cf1a30Sjl 	memlist_read_unlock();
2457*25cf1a30Sjl 
2458*25cf1a30Sjl 	stat->assigned = dp->dev.bp->assigned;
2459*25cf1a30Sjl 	stat->powered = dp->dev.bp->powered;
2460*25cf1a30Sjl 	stat->configured = (ml != NULL);
2461*25cf1a30Sjl 	stat->busy = dp->dev.busy;
2462*25cf1a30Sjl 	strncpy(stat->type, dp->dev.type, sizeof (stat->type));
2463*25cf1a30Sjl 	stat->info[0] = '\0';
2464*25cf1a30Sjl 
2465*25cf1a30Sjl 	return (NULL);
2466*25cf1a30Sjl }
2467*25cf1a30Sjl 
2468*25cf1a30Sjl 
2469*25cf1a30Sjl sbd_error_t *
2470*25cf1a30Sjl drmach_board_deprobe(drmachid_t id)
2471*25cf1a30Sjl {
2472*25cf1a30Sjl 	drmach_board_t	*bp;
2473*25cf1a30Sjl 
2474*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
2475*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2476*25cf1a30Sjl 
2477*25cf1a30Sjl 	bp = id;
2478*25cf1a30Sjl 
2479*25cf1a30Sjl 	cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum);
2480*25cf1a30Sjl 
2481*25cf1a30Sjl 	if (bp->tree) {
2482*25cf1a30Sjl 		drmach_node_dispose(bp->tree);
2483*25cf1a30Sjl 		bp->tree = NULL;
2484*25cf1a30Sjl 	}
2485*25cf1a30Sjl 	if (bp->devices) {
2486*25cf1a30Sjl 		drmach_array_dispose(bp->devices, drmach_device_dispose);
2487*25cf1a30Sjl 		bp->devices = NULL;
2488*25cf1a30Sjl 	}
2489*25cf1a30Sjl 
2490*25cf1a30Sjl 	bp->boot_board = 0;
2491*25cf1a30Sjl 
2492*25cf1a30Sjl 	return (NULL);
2493*25cf1a30Sjl }
2494*25cf1a30Sjl 
2495*25cf1a30Sjl /*ARGSUSED*/
2496*25cf1a30Sjl static sbd_error_t *
2497*25cf1a30Sjl drmach_pt_ikprobe(drmachid_t id, drmach_opts_t *opts)
2498*25cf1a30Sjl {
2499*25cf1a30Sjl 	drmach_board_t		*bp = (drmach_board_t *)id;
2500*25cf1a30Sjl 	sbd_error_t		*err = NULL;
2501*25cf1a30Sjl 	int	rv;
2502*25cf1a30Sjl 
2503*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
2504*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2505*25cf1a30Sjl 
2506*25cf1a30Sjl 	DRMACH_PR("calling opl_probe_board for bnum=%d\n", bp->bnum);
2507*25cf1a30Sjl 	rv = opl_probe_sb(bp->bnum);
2508*25cf1a30Sjl 	if (rv != 0) {
2509*25cf1a30Sjl 		err = drerr_new(0, EOPL_PROBE, bp->cm.name);
2510*25cf1a30Sjl 		return (err);
2511*25cf1a30Sjl 	}
2512*25cf1a30Sjl 	return (err);
2513*25cf1a30Sjl }
2514*25cf1a30Sjl 
2515*25cf1a30Sjl /*ARGSUSED*/
2516*25cf1a30Sjl static sbd_error_t *
2517*25cf1a30Sjl drmach_pt_ikdeprobe(drmachid_t id, drmach_opts_t *opts)
2518*25cf1a30Sjl {
2519*25cf1a30Sjl 	drmach_board_t	*bp;
2520*25cf1a30Sjl 	sbd_error_t	*err = NULL;
2521*25cf1a30Sjl 	int	rv;
2522*25cf1a30Sjl 
2523*25cf1a30Sjl 	if (!DRMACH_IS_BOARD_ID(id))
2524*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2525*25cf1a30Sjl 	bp = (drmach_board_t *)id;
2526*25cf1a30Sjl 
2527*25cf1a30Sjl 	cmn_err(CE_CONT, "DR: in-kernel unprobe board %d\n", bp->bnum);
2528*25cf1a30Sjl 
2529*25cf1a30Sjl 	rv = opl_unprobe_sb(bp->bnum);
2530*25cf1a30Sjl 	if (rv != 0) {
2531*25cf1a30Sjl 		err = drerr_new(0, EOPL_DEPROBE, bp->cm.name);
2532*25cf1a30Sjl 	}
2533*25cf1a30Sjl 
2534*25cf1a30Sjl 	return (err);
2535*25cf1a30Sjl }
2536*25cf1a30Sjl 
2537*25cf1a30Sjl 
2538*25cf1a30Sjl /*ARGSUSED*/
2539*25cf1a30Sjl sbd_error_t *
2540*25cf1a30Sjl drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts)
2541*25cf1a30Sjl {
2542*25cf1a30Sjl 	struct memlist	*ml;
2543*25cf1a30Sjl 	uint64_t	src_pa;
2544*25cf1a30Sjl 	uint64_t	dst_pa;
2545*25cf1a30Sjl 	uint64_t	dst;
2546*25cf1a30Sjl 
2547*25cf1a30Sjl 	dst_pa = va_to_pa(&dst);
2548*25cf1a30Sjl 
2549*25cf1a30Sjl 	memlist_read_lock();
2550*25cf1a30Sjl 	for (ml = phys_install; ml; ml = ml->next) {
2551*25cf1a30Sjl 		uint64_t	nbytes;
2552*25cf1a30Sjl 
2553*25cf1a30Sjl 		src_pa = ml->address;
2554*25cf1a30Sjl 		nbytes = ml->size;
2555*25cf1a30Sjl 
2556*25cf1a30Sjl 		while (nbytes != 0ull) {
2557*25cf1a30Sjl 
2558*25cf1a30Sjl 			/* copy 32 bytes at arc_pa to dst_pa */
2559*25cf1a30Sjl 			bcopy32_il(src_pa, dst_pa);
2560*25cf1a30Sjl 
2561*25cf1a30Sjl 			/* increment by 32 bytes */
2562*25cf1a30Sjl 			src_pa += (4 * sizeof (uint64_t));
2563*25cf1a30Sjl 
2564*25cf1a30Sjl 			/* decrement by 32 bytes */
2565*25cf1a30Sjl 			nbytes -= (4 * sizeof (uint64_t));
2566*25cf1a30Sjl 		}
2567*25cf1a30Sjl 	}
2568*25cf1a30Sjl 	memlist_read_unlock();
2569*25cf1a30Sjl 
2570*25cf1a30Sjl 	return (NULL);
2571*25cf1a30Sjl }
2572*25cf1a30Sjl 
2573*25cf1a30Sjl static struct {
2574*25cf1a30Sjl 	const char	*name;
2575*25cf1a30Sjl 	sbd_error_t	*(*handler)(drmachid_t id, drmach_opts_t *opts);
2576*25cf1a30Sjl } drmach_pt_arr[] = {
2577*25cf1a30Sjl 	{ "readmem",		drmach_pt_readmem		},
2578*25cf1a30Sjl 	{ "ikprobe",	drmach_pt_ikprobe	},
2579*25cf1a30Sjl 	{ "ikdeprobe",	drmach_pt_ikdeprobe	},
2580*25cf1a30Sjl 
2581*25cf1a30Sjl 	/* the following line must always be last */
2582*25cf1a30Sjl 	{ NULL,			NULL				}
2583*25cf1a30Sjl };
2584*25cf1a30Sjl 
2585*25cf1a30Sjl /*ARGSUSED*/
2586*25cf1a30Sjl sbd_error_t *
2587*25cf1a30Sjl drmach_passthru(drmachid_t id, drmach_opts_t *opts)
2588*25cf1a30Sjl {
2589*25cf1a30Sjl 	int		i;
2590*25cf1a30Sjl 	sbd_error_t	*err;
2591*25cf1a30Sjl 
2592*25cf1a30Sjl 	i = 0;
2593*25cf1a30Sjl 	while (drmach_pt_arr[i].name != NULL) {
2594*25cf1a30Sjl 		int len = strlen(drmach_pt_arr[i].name);
2595*25cf1a30Sjl 
2596*25cf1a30Sjl 		if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0)
2597*25cf1a30Sjl 			break;
2598*25cf1a30Sjl 
2599*25cf1a30Sjl 		i += 1;
2600*25cf1a30Sjl 	}
2601*25cf1a30Sjl 
2602*25cf1a30Sjl 	if (drmach_pt_arr[i].name == NULL)
2603*25cf1a30Sjl 		err = drerr_new(0, EOPL_UNKPTCMD, opts->copts);
2604*25cf1a30Sjl 	else
2605*25cf1a30Sjl 		err = (*drmach_pt_arr[i].handler)(id, opts);
2606*25cf1a30Sjl 
2607*25cf1a30Sjl 	return (err);
2608*25cf1a30Sjl }
2609*25cf1a30Sjl 
2610*25cf1a30Sjl sbd_error_t *
2611*25cf1a30Sjl drmach_release(drmachid_t id)
2612*25cf1a30Sjl {
2613*25cf1a30Sjl 	drmach_common_t *cp;
2614*25cf1a30Sjl 
2615*25cf1a30Sjl 	if (!DRMACH_IS_DEVICE_ID(id))
2616*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2617*25cf1a30Sjl 	cp = id;
2618*25cf1a30Sjl 
2619*25cf1a30Sjl 	return (cp->release(id));
2620*25cf1a30Sjl }
2621*25cf1a30Sjl 
2622*25cf1a30Sjl sbd_error_t *
2623*25cf1a30Sjl drmach_status(drmachid_t id, drmach_status_t *stat)
2624*25cf1a30Sjl {
2625*25cf1a30Sjl 	drmach_common_t *cp;
2626*25cf1a30Sjl 	sbd_error_t	*err;
2627*25cf1a30Sjl 
2628*25cf1a30Sjl 	rw_enter(&drmach_boards_rwlock, RW_READER);
2629*25cf1a30Sjl 
2630*25cf1a30Sjl 	if (!DRMACH_IS_ID(id)) {
2631*25cf1a30Sjl 		rw_exit(&drmach_boards_rwlock);
2632*25cf1a30Sjl 		return (drerr_new(0, EOPL_NOTID, NULL));
2633*25cf1a30Sjl 	}
2634*25cf1a30Sjl 	cp = (drmach_common_t *)id;
2635*25cf1a30Sjl 	err = cp->status(id, stat);
2636*25cf1a30Sjl 
2637*25cf1a30Sjl 	rw_exit(&drmach_boards_rwlock);
2638*25cf1a30Sjl 
2639*25cf1a30Sjl 	return (err);
2640*25cf1a30Sjl }
2641*25cf1a30Sjl 
2642*25cf1a30Sjl static sbd_error_t *
2643*25cf1a30Sjl drmach_i_status(drmachid_t id, drmach_status_t *stat)
2644*25cf1a30Sjl {
2645*25cf1a30Sjl 	drmach_common_t *cp;
2646*25cf1a30Sjl 
2647*25cf1a30Sjl 	if (!DRMACH_IS_ID(id))
2648*25cf1a30Sjl 		return (drerr_new(0, EOPL_NOTID, NULL));
2649*25cf1a30Sjl 	cp = id;
2650*25cf1a30Sjl 
2651*25cf1a30Sjl 	return (cp->status(id, stat));
2652*25cf1a30Sjl }
2653*25cf1a30Sjl 
2654*25cf1a30Sjl /*ARGSUSED*/
2655*25cf1a30Sjl sbd_error_t *
2656*25cf1a30Sjl drmach_unconfigure(drmachid_t id, int flags)
2657*25cf1a30Sjl {
2658*25cf1a30Sjl 	drmach_device_t *dp;
2659*25cf1a30Sjl 	dev_info_t	*rdip, *fdip = NULL;
2660*25cf1a30Sjl 	char name[OBP_MAXDRVNAME];
2661*25cf1a30Sjl 	int rv;
2662*25cf1a30Sjl 
2663*25cf1a30Sjl 	if (DRMACH_IS_CPU_ID(id))
2664*25cf1a30Sjl 		return (NULL);
2665*25cf1a30Sjl 
2666*25cf1a30Sjl 	if (!DRMACH_IS_DEVICE_ID(id))
2667*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
2668*25cf1a30Sjl 
2669*25cf1a30Sjl 	dp = id;
2670*25cf1a30Sjl 
2671*25cf1a30Sjl 	rdip = dp->node->n_getdip(dp->node);
2672*25cf1a30Sjl 
2673*25cf1a30Sjl 	ASSERT(rdip);
2674*25cf1a30Sjl 
2675*25cf1a30Sjl 	rv = dp->node->n_getprop(dp->node, "name", name, OBP_MAXDRVNAME);
2676*25cf1a30Sjl 
2677*25cf1a30Sjl 	if (rv)
2678*25cf1a30Sjl 		return (NULL);
2679*25cf1a30Sjl 
2680*25cf1a30Sjl 	/*
2681*25cf1a30Sjl 	 * Note: FORCE flag is no longer necessary under devfs
2682*25cf1a30Sjl 	 */
2683*25cf1a30Sjl 
2684*25cf1a30Sjl 	ASSERT(e_ddi_branch_held(rdip));
2685*25cf1a30Sjl 	if (e_ddi_branch_unconfigure(rdip, &fdip, 0)) {
2686*25cf1a30Sjl 		sbd_error_t	*err;
2687*25cf1a30Sjl 		char		*path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2688*25cf1a30Sjl 
2689*25cf1a30Sjl 		/*
2690*25cf1a30Sjl 		 * If non-NULL, fdip is returned held and must be released.
2691*25cf1a30Sjl 		 */
2692*25cf1a30Sjl 		if (fdip != NULL) {
2693*25cf1a30Sjl 			(void) ddi_pathname(fdip, path);
2694*25cf1a30Sjl 			ndi_rele_devi(fdip);
2695*25cf1a30Sjl 		} else {
2696*25cf1a30Sjl 			(void) ddi_pathname(rdip, path);
2697*25cf1a30Sjl 		}
2698*25cf1a30Sjl 
2699*25cf1a30Sjl 		err = drerr_new(1, EOPL_DRVFAIL, path);
2700*25cf1a30Sjl 
2701*25cf1a30Sjl 		kmem_free(path, MAXPATHLEN);
2702*25cf1a30Sjl 
2703*25cf1a30Sjl 		return (err);
2704*25cf1a30Sjl 	}
2705*25cf1a30Sjl 
2706*25cf1a30Sjl 	return (NULL);
2707*25cf1a30Sjl }
2708*25cf1a30Sjl 
2709*25cf1a30Sjl 
2710*25cf1a30Sjl int
2711*25cf1a30Sjl drmach_cpu_poweron(struct cpu *cp)
2712*25cf1a30Sjl {
2713*25cf1a30Sjl 	int bnum, cpuid, onb_core_num, strand_id;
2714*25cf1a30Sjl 	drmach_board_t *bp;
2715*25cf1a30Sjl 
2716*25cf1a30Sjl 	DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id);
2717*25cf1a30Sjl 
2718*25cf1a30Sjl 	cpuid = cp->cpu_id;
2719*25cf1a30Sjl 	bnum = LSB_ID(cpuid);
2720*25cf1a30Sjl 	onb_core_num = ON_BOARD_CORE_NUM(cpuid);
2721*25cf1a30Sjl 	strand_id = STRAND_ID(cpuid);
2722*25cf1a30Sjl 	bp = drmach_get_board_by_bnum(bnum);
2723*25cf1a30Sjl 
2724*25cf1a30Sjl 	ASSERT(bp);
2725*25cf1a30Sjl 	if (bp->cores[onb_core_num].core_hotadded == 0) {
2726*25cf1a30Sjl 		if (drmach_add_remove_cpu(bnum, onb_core_num,
2727*25cf1a30Sjl 			HOTADD_CPU) != 0) {
2728*25cf1a30Sjl 			cmn_err(CE_WARN, "Failed to add CMP %d on board %d\n",
2729*25cf1a30Sjl 				onb_core_num, bnum);
2730*25cf1a30Sjl 			return (EIO);
2731*25cf1a30Sjl 		}
2732*25cf1a30Sjl 	}
2733*25cf1a30Sjl 
2734*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&cpu_lock));
2735*25cf1a30Sjl 
2736*25cf1a30Sjl 	if (drmach_cpu_start(cp) != 0) {
2737*25cf1a30Sjl 		if (bp->cores[onb_core_num].core_started == 0) {
2738*25cf1a30Sjl 			/*
2739*25cf1a30Sjl 			 * we must undo the hotadd or no one will do that
2740*25cf1a30Sjl 			 * If this fails, we will do this again in
2741*25cf1a30Sjl 			 * drmach_board_disconnect.
2742*25cf1a30Sjl 			 */
2743*25cf1a30Sjl 			if (drmach_add_remove_cpu(bnum, onb_core_num,
2744*25cf1a30Sjl 				HOTREMOVE_CPU) != 0) {
2745*25cf1a30Sjl 				cmn_err(CE_WARN, "Failed to remove CMP %d "
2746*25cf1a30Sjl 					"on board %d\n",
2747*25cf1a30Sjl 					onb_core_num, bnum);
2748*25cf1a30Sjl 			}
2749*25cf1a30Sjl 		}
2750*25cf1a30Sjl 		return (EBUSY);
2751*25cf1a30Sjl 	} else {
2752*25cf1a30Sjl 		bp->cores[onb_core_num].core_started |= (1 << strand_id);
2753*25cf1a30Sjl 		return (0);
2754*25cf1a30Sjl 	}
2755*25cf1a30Sjl }
2756*25cf1a30Sjl 
2757*25cf1a30Sjl int
2758*25cf1a30Sjl drmach_cpu_poweroff(struct cpu *cp)
2759*25cf1a30Sjl {
2760*25cf1a30Sjl 	int 		rv = 0;
2761*25cf1a30Sjl 	processorid_t	cpuid = cp->cpu_id;
2762*25cf1a30Sjl 
2763*25cf1a30Sjl 	DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id);
2764*25cf1a30Sjl 
2765*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&cpu_lock));
2766*25cf1a30Sjl 
2767*25cf1a30Sjl 	/*
2768*25cf1a30Sjl 	 * Capture all CPUs (except for detaching proc) to prevent
2769*25cf1a30Sjl 	 * crosscalls to the detaching proc until it has cleared its
2770*25cf1a30Sjl 	 * bit in cpu_ready_set.
2771*25cf1a30Sjl 	 *
2772*25cf1a30Sjl 	 * The CPU's remain paused and the prom_mutex is known to be free.
2773*25cf1a30Sjl 	 * This prevents the x-trap victim from blocking when doing prom
2774*25cf1a30Sjl 	 * IEEE-1275 calls at a high PIL level.
2775*25cf1a30Sjl 	 */
2776*25cf1a30Sjl 
2777*25cf1a30Sjl 	promsafe_pause_cpus();
2778*25cf1a30Sjl 
2779*25cf1a30Sjl 	/*
2780*25cf1a30Sjl 	 * Quiesce interrupts on the target CPU. We do this by setting
2781*25cf1a30Sjl 	 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
2782*25cf1a30Sjl 	 * prevent it from receiving cross calls and cross traps.
2783*25cf1a30Sjl 	 * This prevents the processor from receiving any new soft interrupts.
2784*25cf1a30Sjl 	 */
2785*25cf1a30Sjl 	mp_cpu_quiesce(cp);
2786*25cf1a30Sjl 
2787*25cf1a30Sjl 	rv = prom_stopcpu_bycpuid(cpuid);
2788*25cf1a30Sjl 	if (rv == 0)
2789*25cf1a30Sjl 		cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
2790*25cf1a30Sjl 
2791*25cf1a30Sjl 	start_cpus();
2792*25cf1a30Sjl 
2793*25cf1a30Sjl 	if (rv == 0) {
2794*25cf1a30Sjl 		int bnum, onb_core_num, strand_id;
2795*25cf1a30Sjl 		drmach_board_t *bp;
2796*25cf1a30Sjl 
2797*25cf1a30Sjl 		CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
2798*25cf1a30Sjl 
2799*25cf1a30Sjl 		bnum = LSB_ID(cpuid);
2800*25cf1a30Sjl 		onb_core_num = ON_BOARD_CORE_NUM(cpuid);
2801*25cf1a30Sjl 		strand_id = STRAND_ID(cpuid);
2802*25cf1a30Sjl 		bp = drmach_get_board_by_bnum(bnum);
2803*25cf1a30Sjl 		ASSERT(bp);
2804*25cf1a30Sjl 
2805*25cf1a30Sjl 		bp->cores[onb_core_num].core_started &= ~(1 << strand_id);
2806*25cf1a30Sjl 		if (bp->cores[onb_core_num].core_started == 0) {
2807*25cf1a30Sjl 			if (drmach_add_remove_cpu(bnum, onb_core_num,
2808*25cf1a30Sjl 				HOTREMOVE_CPU) != 0) {
2809*25cf1a30Sjl 				cmn_err(CE_WARN,
2810*25cf1a30Sjl 					"Failed to remove CMP %d LSB %d\n",
2811*25cf1a30Sjl 					onb_core_num, bnum);
2812*25cf1a30Sjl 				return (EIO);
2813*25cf1a30Sjl 			}
2814*25cf1a30Sjl 		}
2815*25cf1a30Sjl 	}
2816*25cf1a30Sjl 
2817*25cf1a30Sjl 	return (rv);
2818*25cf1a30Sjl }
2819*25cf1a30Sjl 
2820*25cf1a30Sjl /*ARGSUSED*/
2821*25cf1a30Sjl int
2822*25cf1a30Sjl drmach_verify_sr(dev_info_t *dip, int sflag)
2823*25cf1a30Sjl {
2824*25cf1a30Sjl 	return (0);
2825*25cf1a30Sjl }
2826*25cf1a30Sjl 
2827*25cf1a30Sjl void
2828*25cf1a30Sjl drmach_suspend_last(void)
2829*25cf1a30Sjl {
2830*25cf1a30Sjl }
2831*25cf1a30Sjl 
2832*25cf1a30Sjl void
2833*25cf1a30Sjl drmach_resume_first(void)
2834*25cf1a30Sjl {
2835*25cf1a30Sjl }
2836*25cf1a30Sjl 
2837*25cf1a30Sjl /*
2838*25cf1a30Sjl  * Log a DR sysevent.
2839*25cf1a30Sjl  * Return value: 0 success, non-zero failure.
2840*25cf1a30Sjl  */
2841*25cf1a30Sjl int
2842*25cf1a30Sjl drmach_log_sysevent(int board, char *hint, int flag, int verbose)
2843*25cf1a30Sjl {
2844*25cf1a30Sjl 	sysevent_t			*ev;
2845*25cf1a30Sjl 	sysevent_id_t			eid;
2846*25cf1a30Sjl 	int				rv, km_flag;
2847*25cf1a30Sjl 	sysevent_value_t		evnt_val;
2848*25cf1a30Sjl 	sysevent_attr_list_t		*evnt_attr_list = NULL;
2849*25cf1a30Sjl 	char				attach_pnt[MAXNAMELEN];
2850*25cf1a30Sjl 
2851*25cf1a30Sjl 	km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
2852*25cf1a30Sjl 	attach_pnt[0] = '\0';
2853*25cf1a30Sjl 	if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) {
2854*25cf1a30Sjl 		rv = -1;
2855*25cf1a30Sjl 		goto logexit;
2856*25cf1a30Sjl 	}
2857*25cf1a30Sjl 	if (verbose)
2858*25cf1a30Sjl 		DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n",
2859*25cf1a30Sjl 			attach_pnt, hint, flag, verbose);
2860*25cf1a30Sjl 
2861*25cf1a30Sjl 	if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE,
2862*25cf1a30Sjl 		SUNW_KERN_PUB"dr", km_flag)) == NULL) {
2863*25cf1a30Sjl 		rv = -2;
2864*25cf1a30Sjl 		goto logexit;
2865*25cf1a30Sjl 	}
2866*25cf1a30Sjl 	evnt_val.value_type = SE_DATA_TYPE_STRING;
2867*25cf1a30Sjl 	evnt_val.value.sv_string = attach_pnt;
2868*25cf1a30Sjl 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID,
2869*25cf1a30Sjl 		&evnt_val, km_flag)) != 0)
2870*25cf1a30Sjl 		goto logexit;
2871*25cf1a30Sjl 
2872*25cf1a30Sjl 	evnt_val.value_type = SE_DATA_TYPE_STRING;
2873*25cf1a30Sjl 	evnt_val.value.sv_string = hint;
2874*25cf1a30Sjl 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT,
2875*25cf1a30Sjl 		&evnt_val, km_flag)) != 0) {
2876*25cf1a30Sjl 		sysevent_free_attr(evnt_attr_list);
2877*25cf1a30Sjl 		goto logexit;
2878*25cf1a30Sjl 	}
2879*25cf1a30Sjl 
2880*25cf1a30Sjl 	(void) sysevent_attach_attributes(ev, evnt_attr_list);
2881*25cf1a30Sjl 
2882*25cf1a30Sjl 	/*
2883*25cf1a30Sjl 	 * Log the event but do not sleep waiting for its
2884*25cf1a30Sjl 	 * delivery. This provides insulation from syseventd.
2885*25cf1a30Sjl 	 */
2886*25cf1a30Sjl 	rv = log_sysevent(ev, SE_NOSLEEP, &eid);
2887*25cf1a30Sjl 
2888*25cf1a30Sjl logexit:
2889*25cf1a30Sjl 	if (ev)
2890*25cf1a30Sjl 		sysevent_free(ev);
2891*25cf1a30Sjl 	if ((rv != 0) && verbose)
2892*25cf1a30Sjl 		cmn_err(CE_WARN,
2893*25cf1a30Sjl 			"drmach_log_sysevent failed (rv %d) for %s  %s\n",
2894*25cf1a30Sjl 			rv, attach_pnt, hint);
2895*25cf1a30Sjl 
2896*25cf1a30Sjl 	return (rv);
2897*25cf1a30Sjl }
2898*25cf1a30Sjl 
2899*25cf1a30Sjl #define	OPL_DR_STATUS_PROP "dr-status"
2900*25cf1a30Sjl 
2901*25cf1a30Sjl static int
2902*25cf1a30Sjl opl_check_dr_status()
2903*25cf1a30Sjl {
2904*25cf1a30Sjl 	pnode_t	node;
2905*25cf1a30Sjl 	int	rtn, len;
2906*25cf1a30Sjl 	char	*str;
2907*25cf1a30Sjl 
2908*25cf1a30Sjl 	node = prom_rootnode();
2909*25cf1a30Sjl 	if (node == OBP_BADNODE) {
2910*25cf1a30Sjl 		return (1);
2911*25cf1a30Sjl 	}
2912*25cf1a30Sjl 
2913*25cf1a30Sjl 	len = prom_getproplen(node, OPL_DR_STATUS_PROP);
2914*25cf1a30Sjl 	if (len == -1) {
2915*25cf1a30Sjl 		/*
2916*25cf1a30Sjl 		 * dr-status doesn't exist when DR is activated and
2917*25cf1a30Sjl 		 * any warning messages aren't needed.
2918*25cf1a30Sjl 		 */
2919*25cf1a30Sjl 		return (1);
2920*25cf1a30Sjl 	}
2921*25cf1a30Sjl 
2922*25cf1a30Sjl 	str = (char *)kmem_zalloc(len+1, KM_SLEEP);
2923*25cf1a30Sjl 	rtn = prom_getprop(node, OPL_DR_STATUS_PROP, str);
2924*25cf1a30Sjl 	kmem_free(str, len + 1);
2925*25cf1a30Sjl 	if (rtn == -1) {
2926*25cf1a30Sjl 		return (1);
2927*25cf1a30Sjl 	} else {
2928*25cf1a30Sjl 		return (0);
2929*25cf1a30Sjl 	}
2930*25cf1a30Sjl }
2931*25cf1a30Sjl 
2932*25cf1a30Sjl static sbd_error_t *
2933*25cf1a30Sjl drmach_get_scf_addr(uint64_t *addr)
2934*25cf1a30Sjl {
2935*25cf1a30Sjl 	caddr_t *scf_cmd_addr;
2936*25cf1a30Sjl 	uint64_t pa;
2937*25cf1a30Sjl 	scf_cmd_addr = (caddr_t *)modgetsymvalue("scf_avail_cmd_reg_vaddr", 0);
2938*25cf1a30Sjl 	if (scf_cmd_addr != NULL) {
2939*25cf1a30Sjl 		pa = (uint64_t)va_to_pa(*scf_cmd_addr);
2940*25cf1a30Sjl 		*addr = pa;
2941*25cf1a30Sjl 		return (NULL);
2942*25cf1a30Sjl 	}
2943*25cf1a30Sjl 
2944*25cf1a30Sjl 	return (DRMACH_INTERNAL_ERROR());
2945*25cf1a30Sjl }
2946*25cf1a30Sjl 
2947*25cf1a30Sjl /* we are allocating memlist from TLB locked pages to avoid tlbmisses */
2948*25cf1a30Sjl 
2949*25cf1a30Sjl static struct memlist *
2950*25cf1a30Sjl drmach_memlist_add_span(drmach_copy_rename_program_t *p,
2951*25cf1a30Sjl 	struct memlist *mlist, uint64_t base, uint64_t len)
2952*25cf1a30Sjl {
2953*25cf1a30Sjl 	struct memlist	*ml, *tl, *nl;
2954*25cf1a30Sjl 
2955*25cf1a30Sjl 	if (len == 0ull)
2956*25cf1a30Sjl 		return (NULL);
2957*25cf1a30Sjl 
2958*25cf1a30Sjl 	if (mlist == NULL) {
2959*25cf1a30Sjl 		mlist = p->free_mlist;
2960*25cf1a30Sjl 		if (mlist == NULL)
2961*25cf1a30Sjl 			return (NULL);
2962*25cf1a30Sjl 		p->free_mlist = mlist->next;
2963*25cf1a30Sjl 		mlist->address = base;
2964*25cf1a30Sjl 		mlist->size = len;
2965*25cf1a30Sjl 		mlist->next = mlist->prev = NULL;
2966*25cf1a30Sjl 
2967*25cf1a30Sjl 		return (mlist);
2968*25cf1a30Sjl 	}
2969*25cf1a30Sjl 
2970*25cf1a30Sjl 	for (tl = ml = mlist; ml; tl = ml, ml = ml->next) {
2971*25cf1a30Sjl 		if (base < ml->address) {
2972*25cf1a30Sjl 			if ((base + len) < ml->address) {
2973*25cf1a30Sjl 				nl = p->free_mlist;
2974*25cf1a30Sjl 				if (nl == NULL)
2975*25cf1a30Sjl 					return (NULL);
2976*25cf1a30Sjl 				p->free_mlist = nl->next;
2977*25cf1a30Sjl 				nl->address = base;
2978*25cf1a30Sjl 				nl->size = len;
2979*25cf1a30Sjl 				nl->next = ml;
2980*25cf1a30Sjl 				if ((nl->prev = ml->prev) != NULL)
2981*25cf1a30Sjl 					nl->prev->next = nl;
2982*25cf1a30Sjl 				ml->prev = nl;
2983*25cf1a30Sjl 				if (mlist == ml)
2984*25cf1a30Sjl 					mlist = nl;
2985*25cf1a30Sjl 			} else {
2986*25cf1a30Sjl 				ml->size = MAX((base + len),
2987*25cf1a30Sjl 					(ml->address + ml->size)) -
2988*25cf1a30Sjl 					base;
2989*25cf1a30Sjl 				ml->address = base;
2990*25cf1a30Sjl 			}
2991*25cf1a30Sjl 			break;
2992*25cf1a30Sjl 
2993*25cf1a30Sjl 		} else if (base <= (ml->address + ml->size)) {
2994*25cf1a30Sjl 			ml->size = MAX((base + len),
2995*25cf1a30Sjl 				(ml->address + ml->size)) -
2996*25cf1a30Sjl 				MIN(ml->address, base);
2997*25cf1a30Sjl 			ml->address = MIN(ml->address, base);
2998*25cf1a30Sjl 			break;
2999*25cf1a30Sjl 		}
3000*25cf1a30Sjl 	}
3001*25cf1a30Sjl 	if (ml == NULL) {
3002*25cf1a30Sjl 		nl = p->free_mlist;
3003*25cf1a30Sjl 		if (nl == NULL)
3004*25cf1a30Sjl 			return (NULL);
3005*25cf1a30Sjl 		p->free_mlist = nl->next;
3006*25cf1a30Sjl 		nl->address = base;
3007*25cf1a30Sjl 		nl->size = len;
3008*25cf1a30Sjl 		nl->next = NULL;
3009*25cf1a30Sjl 		nl->prev = tl;
3010*25cf1a30Sjl 		tl->next = nl;
3011*25cf1a30Sjl 	}
3012*25cf1a30Sjl 
3013*25cf1a30Sjl 	return (mlist);
3014*25cf1a30Sjl }
3015*25cf1a30Sjl 
3016*25cf1a30Sjl /*
3017*25cf1a30Sjl  * The routine performs the necessary memory COPY and MC adr SWITCH.
3018*25cf1a30Sjl  * Both operations MUST be at the same "level" so that the stack is
3019*25cf1a30Sjl  * maintained correctly between the copy and switch.  The switch
3020*25cf1a30Sjl  * portion implements a caching mechanism to guarantee the code text
3021*25cf1a30Sjl  * is cached prior to execution.  This is to guard against possible
3022*25cf1a30Sjl  * memory access while the MC adr's are being modified.
3023*25cf1a30Sjl  *
3024*25cf1a30Sjl  * IMPORTANT: The _drmach_copy_rename_end() function must immediately
3025*25cf1a30Sjl  * follow drmach_copy_rename_prog__relocatable() so that the correct
3026*25cf1a30Sjl  * "length" of the drmach_copy_rename_prog__relocatable can be
3027*25cf1a30Sjl  * calculated.  This routine MUST be a LEAF function, i.e. it can
3028*25cf1a30Sjl  * make NO function calls, primarily for two reasons:
3029*25cf1a30Sjl  *
3030*25cf1a30Sjl  *	1. We must keep the stack consistent across the "switch".
3031*25cf1a30Sjl  *	2. Function calls are compiled to relative offsets, and
3032*25cf1a30Sjl  *	   we execute this function we'll be executing it from
3033*25cf1a30Sjl  *	   a copied version in a different area of memory, thus
3034*25cf1a30Sjl  *	   the relative offsets will be bogus.
3035*25cf1a30Sjl  *
3036*25cf1a30Sjl  * Moreover, it must have the "__relocatable" suffix to inform DTrace
3037*25cf1a30Sjl  * providers (and anything else, for that matter) that this
3038*25cf1a30Sjl  * function's text is manually relocated elsewhere before it is
3039*25cf1a30Sjl  * executed.  That is, it cannot be safely instrumented with any
3040*25cf1a30Sjl  * methodology that is PC-relative.
3041*25cf1a30Sjl  */
3042*25cf1a30Sjl 
3043*25cf1a30Sjl /*
3044*25cf1a30Sjl  * We multiply this to system_clock_frequency so we
3045*25cf1a30Sjl  * are setting a delay of fmem_timeout second for
3046*25cf1a30Sjl  * the rename command.  The spec says 15 second is
3047*25cf1a30Sjl  * enough but the Fujitsu HW team suggested 17 sec.
3048*25cf1a30Sjl  */
3049*25cf1a30Sjl static int	fmem_timeout = 17;
3050*25cf1a30Sjl static int	min_copy_size_per_sec = 20 * 1024 * 1024;
3051*25cf1a30Sjl int drmach_disable_mcopy = 0;
3052*25cf1a30Sjl 
3053*25cf1a30Sjl #define	DR_DELAY_IL(ms, freq)					\
3054*25cf1a30Sjl 	{							\
3055*25cf1a30Sjl 		uint64_t start;					\
3056*25cf1a30Sjl 		uint64_t nstick;				\
3057*25cf1a30Sjl 		volatile uint64_t now;				\
3058*25cf1a30Sjl 		nstick = ((uint64_t)ms * freq)/1000;		\
3059*25cf1a30Sjl 		start = drmach_get_stick_il();			\
3060*25cf1a30Sjl 		now = start;					\
3061*25cf1a30Sjl 		while ((now - start) <= nstick) {		\
3062*25cf1a30Sjl 			drmach_sleep_il();			\
3063*25cf1a30Sjl 			now = drmach_get_stick_il();		\
3064*25cf1a30Sjl 		}						\
3065*25cf1a30Sjl 	}
3066*25cf1a30Sjl 
3067*25cf1a30Sjl static int
3068*25cf1a30Sjl drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog,
3069*25cf1a30Sjl 	int cpuid)
3070*25cf1a30Sjl {
3071*25cf1a30Sjl 	struct memlist		*ml;
3072*25cf1a30Sjl 	register int		rtn;
3073*25cf1a30Sjl 	int			i;
3074*25cf1a30Sjl 	register uint64_t	curr, limit;
3075*25cf1a30Sjl 	extern uint64_t		drmach_get_stick_il();
3076*25cf1a30Sjl 	extern void		membar_sync_il();
3077*25cf1a30Sjl 	extern void		flush_instr_mem_il(void*);
3078*25cf1a30Sjl 	uint64_t		copy_start;
3079*25cf1a30Sjl 
3080*25cf1a30Sjl 	prog->critical->stat[cpuid] = FMEM_LOOP_COPY_READY;
3081*25cf1a30Sjl 	membar_sync_il();
3082*25cf1a30Sjl 
3083*25cf1a30Sjl 	if (prog->data->cpuid == cpuid) {
3084*25cf1a30Sjl 		limit = drmach_get_stick_il();
3085*25cf1a30Sjl 		limit += prog->critical->delay;
3086*25cf1a30Sjl 
3087*25cf1a30Sjl 		for (i = 0; i < NCPU; i++) {
3088*25cf1a30Sjl 			if (CPU_IN_SET(prog->data->cpu_slave_set, i)) {
3089*25cf1a30Sjl 			/* wait for all CPU's to be ready */
3090*25cf1a30Sjl 			    for (;;) {
3091*25cf1a30Sjl 				if (prog->critical->stat[i] ==
3092*25cf1a30Sjl 					FMEM_LOOP_COPY_READY) {
3093*25cf1a30Sjl 					break;
3094*25cf1a30Sjl 				}
3095*25cf1a30Sjl 			    }
3096*25cf1a30Sjl 			    curr = drmach_get_stick_il();
3097*25cf1a30Sjl 			    if (curr > limit) {
3098*25cf1a30Sjl 				prog->data->fmem_status.error =
3099*25cf1a30Sjl 					FMEM_XC_TIMEOUT;
3100*25cf1a30Sjl 				return (FMEM_XC_TIMEOUT);
3101*25cf1a30Sjl 			    }
3102*25cf1a30Sjl 			}
3103*25cf1a30Sjl 		}
3104*25cf1a30Sjl 		prog->data->fmem_status.stat = FMEM_LOOP_COPY_READY;
3105*25cf1a30Sjl 		membar_sync_il();
3106*25cf1a30Sjl 		copy_start = drmach_get_stick_il();
3107*25cf1a30Sjl 	} else {
3108*25cf1a30Sjl 		for (;;) {
3109*25cf1a30Sjl 			if (prog->data->fmem_status.stat ==
3110*25cf1a30Sjl 				FMEM_LOOP_COPY_READY) {
3111*25cf1a30Sjl 				break;
3112*25cf1a30Sjl 			}
3113*25cf1a30Sjl 			if (prog->data->fmem_status.error) {
3114*25cf1a30Sjl 				prog->data->error[cpuid] = FMEM_TERMINATE;
3115*25cf1a30Sjl 				return (FMEM_TERMINATE);
3116*25cf1a30Sjl 			}
3117*25cf1a30Sjl 		}
3118*25cf1a30Sjl 	}
3119*25cf1a30Sjl 
3120*25cf1a30Sjl 	/*
3121*25cf1a30Sjl 	 * DO COPY.
3122*25cf1a30Sjl 	 */
3123*25cf1a30Sjl 	if (CPU_IN_SET(prog->data->cpu_copy_set, cpuid)) {
3124*25cf1a30Sjl 	    for (ml = prog->data->cpu_ml[cpuid]; ml; ml = ml->next) {
3125*25cf1a30Sjl 		uint64_t	s_pa, t_pa;
3126*25cf1a30Sjl 		uint64_t	nbytes;
3127*25cf1a30Sjl 
3128*25cf1a30Sjl 		s_pa = prog->data->s_copybasepa + ml->address;
3129*25cf1a30Sjl 		t_pa = prog->data->t_copybasepa + ml->address;
3130*25cf1a30Sjl 		nbytes = ml->size;
3131*25cf1a30Sjl 
3132*25cf1a30Sjl 		while (nbytes != 0ull) {
3133*25cf1a30Sjl 			/* If the master has detected error, we just bail out */
3134*25cf1a30Sjl 			if (prog->data->fmem_status.error) {
3135*25cf1a30Sjl 				prog->data->error[cpuid] = FMEM_TERMINATE;
3136*25cf1a30Sjl 				return (FMEM_TERMINATE);
3137*25cf1a30Sjl 			}
3138*25cf1a30Sjl 			/*
3139*25cf1a30Sjl 			 * This copy does NOT use an ASI
3140*25cf1a30Sjl 			 * that avoids the Ecache, therefore
3141*25cf1a30Sjl 			 * the dst_pa addresses may remain
3142*25cf1a30Sjl 			 * in our Ecache after the dst_pa
3143*25cf1a30Sjl 			 * has been removed from the system.
3144*25cf1a30Sjl 			 * A subsequent write-back to memory
3145*25cf1a30Sjl 			 * will cause an ARB-stop because the
3146*25cf1a30Sjl 			 * physical address no longer exists
3147*25cf1a30Sjl 			 * in the system. Therefore we must
3148*25cf1a30Sjl 			 * flush out local Ecache after we
3149*25cf1a30Sjl 			 * finish the copy.
3150*25cf1a30Sjl 			 */
3151*25cf1a30Sjl 
3152*25cf1a30Sjl 			/* copy 32 bytes at src_pa to dst_pa */
3153*25cf1a30Sjl 			bcopy32_il(s_pa, t_pa);
3154*25cf1a30Sjl 
3155*25cf1a30Sjl 			/* increment the counter to signal that we are alive */
3156*25cf1a30Sjl 			prog->stat->nbytes[cpuid] += 32;
3157*25cf1a30Sjl 
3158*25cf1a30Sjl 			/* increment by 32 bytes */
3159*25cf1a30Sjl 			s_pa += (4 * sizeof (uint64_t));
3160*25cf1a30Sjl 			t_pa += (4 * sizeof (uint64_t));
3161*25cf1a30Sjl 
3162*25cf1a30Sjl 			/* decrement by 32 bytes */
3163*25cf1a30Sjl 			nbytes -= (4 * sizeof (uint64_t));
3164*25cf1a30Sjl 		}
3165*25cf1a30Sjl 	    }
3166*25cf1a30Sjl 	    prog->critical->stat[cpuid] = FMEM_LOOP_COPY_DONE;
3167*25cf1a30Sjl 	    membar_sync_il();
3168*25cf1a30Sjl 	}
3169*25cf1a30Sjl 
3170*25cf1a30Sjl 	/*
3171*25cf1a30Sjl 	 * Since bcopy32_il() does NOT use an ASI to bypass
3172*25cf1a30Sjl 	 * the Ecache, we need to flush our Ecache after
3173*25cf1a30Sjl 	 * the copy is complete.
3174*25cf1a30Sjl 	 */
3175*25cf1a30Sjl 	flush_cache_il();
3176*25cf1a30Sjl 
3177*25cf1a30Sjl 	/*
3178*25cf1a30Sjl 	 * drmach_fmem_exec_script()
3179*25cf1a30Sjl 	 */
3180*25cf1a30Sjl 	if (prog->data->cpuid == cpuid) {
3181*25cf1a30Sjl 		uint64_t	last, now;
3182*25cf1a30Sjl 
3183*25cf1a30Sjl 		limit = copy_start + prog->data->copy_delay;
3184*25cf1a30Sjl 		for (i = 0; i < NCPU; i++) {
3185*25cf1a30Sjl 			if (CPU_IN_SET(prog->data->cpu_slave_set, i)) {
3186*25cf1a30Sjl 			    for (;;) {
3187*25cf1a30Sjl 				/* we get FMEM_LOOP_FMEM_READY in normal case */
3188*25cf1a30Sjl 				if (prog->critical->stat[i] ==
3189*25cf1a30Sjl 					FMEM_LOOP_FMEM_READY) {
3190*25cf1a30Sjl 					break;
3191*25cf1a30Sjl 				}
3192*25cf1a30Sjl 				/* got error traps */
3193*25cf1a30Sjl 				if (prog->critical->stat[i] ==
3194*25cf1a30Sjl 					FMEM_COPY_ERROR) {
3195*25cf1a30Sjl 					prog->data->fmem_status.error =
3196*25cf1a30Sjl 						FMEM_COPY_ERROR;
3197*25cf1a30Sjl 					return (FMEM_COPY_ERROR);
3198*25cf1a30Sjl 				}
3199*25cf1a30Sjl 				/* if we have not reached limit, wait more */
3200*25cf1a30Sjl 				curr = drmach_get_stick_il();
3201*25cf1a30Sjl 				if (curr <= limit)
3202*25cf1a30Sjl 					continue;
3203*25cf1a30Sjl 
3204*25cf1a30Sjl 				prog->data->slowest_cpuid = i;
3205*25cf1a30Sjl 				prog->data->copy_wait_time =
3206*25cf1a30Sjl 					curr - copy_start;
3207*25cf1a30Sjl 
3208*25cf1a30Sjl 				/* now check if slave is alive */
3209*25cf1a30Sjl 				last = prog->stat->nbytes[i];
3210*25cf1a30Sjl 
3211*25cf1a30Sjl 				DR_DELAY_IL(1, prog->data->stick_freq);
3212*25cf1a30Sjl 
3213*25cf1a30Sjl 				now = prog->stat->nbytes[i];
3214*25cf1a30Sjl 				if (now <= last) {
3215*25cf1a30Sjl 					/* no progress, perhaps just finished */
3216*25cf1a30Sjl 					DR_DELAY_IL(1, prog->data->stick_freq);
3217*25cf1a30Sjl 					if (prog->critical->stat[i] ==
3218*25cf1a30Sjl 						FMEM_LOOP_FMEM_READY)
3219*25cf1a30Sjl 						break;
3220*25cf1a30Sjl 					/* copy error */
3221*25cf1a30Sjl 					if (prog->critical->stat[i] ==
3222*25cf1a30Sjl 						FMEM_COPY_ERROR) {
3223*25cf1a30Sjl 						prog->data->fmem_status.error =
3224*25cf1a30Sjl 							FMEM_COPY_ERROR;
3225*25cf1a30Sjl 						return (FMEM_COPY_ERROR);
3226*25cf1a30Sjl 					}
3227*25cf1a30Sjl 					prog->data->fmem_status.error =
3228*25cf1a30Sjl 					    FMEM_COPY_TIMEOUT;
3229*25cf1a30Sjl 					return (FMEM_COPY_TIMEOUT);
3230*25cf1a30Sjl 				}
3231*25cf1a30Sjl 			    }
3232*25cf1a30Sjl 			}
3233*25cf1a30Sjl 		}
3234*25cf1a30Sjl 		prog->critical->stat[cpuid] = FMEM_LOOP_FMEM_READY;
3235*25cf1a30Sjl 		prog->data->fmem_status.stat  = FMEM_LOOP_FMEM_READY;
3236*25cf1a30Sjl 
3237*25cf1a30Sjl 		membar_sync_il();
3238*25cf1a30Sjl 		flush_instr_mem_il((void*) (prog->critical));
3239*25cf1a30Sjl 		/*
3240*25cf1a30Sjl 		 * drmach_fmem_exec_script()
3241*25cf1a30Sjl 		 */
3242*25cf1a30Sjl 		rtn = prog->critical->fmem((void *)prog->critical, PAGESIZE);
3243*25cf1a30Sjl 		return (rtn);
3244*25cf1a30Sjl 	} else {
3245*25cf1a30Sjl 		flush_instr_mem_il((void*) (prog->critical));
3246*25cf1a30Sjl 		/*
3247*25cf1a30Sjl 		 * drmach_fmem_loop_script()
3248*25cf1a30Sjl 		 */
3249*25cf1a30Sjl 		rtn = prog->critical->loop((void *)(prog->critical),
3250*25cf1a30Sjl 			PAGESIZE, (void *)&(prog->critical->stat[cpuid]));
3251*25cf1a30Sjl 
3252*25cf1a30Sjl 		prog->data->error[cpuid] = rtn;
3253*25cf1a30Sjl 		/* slave thread does not care the rv */
3254*25cf1a30Sjl 		return (0);
3255*25cf1a30Sjl 	}
3256*25cf1a30Sjl }
3257*25cf1a30Sjl 
3258*25cf1a30Sjl static void
3259*25cf1a30Sjl drmach_copy_rename_end(void)
3260*25cf1a30Sjl {
3261*25cf1a30Sjl 	/*
3262*25cf1a30Sjl 	 * IMPORTANT:	This function's location MUST be located immediately
3263*25cf1a30Sjl 	 *		following drmach_copy_rename_prog__relocatable to
3264*25cf1a30Sjl 	 *		accurately estimate its size.  Note that this assumes
3265*25cf1a30Sjl 	 *		the compiler keeps these functions in the order in
3266*25cf1a30Sjl 	 *		which they appear :-o
3267*25cf1a30Sjl 	 */
3268*25cf1a30Sjl }
3269*25cf1a30Sjl 
3270*25cf1a30Sjl 
3271*25cf1a30Sjl static void
3272*25cf1a30Sjl drmach_setup_memlist(drmach_copy_rename_program_t *p)
3273*25cf1a30Sjl {
3274*25cf1a30Sjl 	struct memlist *ml;
3275*25cf1a30Sjl 	caddr_t buf;
3276*25cf1a30Sjl 	int nbytes, s;
3277*25cf1a30Sjl 
3278*25cf1a30Sjl 	nbytes = PAGESIZE;
3279*25cf1a30Sjl 	s = roundup(sizeof (struct memlist), sizeof (void *));
3280*25cf1a30Sjl 	p->free_mlist = NULL;
3281*25cf1a30Sjl 	buf = p->memlist_buffer;
3282*25cf1a30Sjl 	while (nbytes >= sizeof (struct memlist)) {
3283*25cf1a30Sjl 		ml = (struct memlist *)buf;
3284*25cf1a30Sjl 		ml->next = p->free_mlist;
3285*25cf1a30Sjl 		p->free_mlist = ml;
3286*25cf1a30Sjl 		buf += s;
3287*25cf1a30Sjl 		nbytes -= s;
3288*25cf1a30Sjl 	}
3289*25cf1a30Sjl }
3290*25cf1a30Sjl 
3291*25cf1a30Sjl sbd_error_t *
3292*25cf1a30Sjl drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id,
3293*25cf1a30Sjl 	struct memlist *c_ml, drmachid_t *pgm_id)
3294*25cf1a30Sjl {
3295*25cf1a30Sjl 	drmach_mem_t	*s_mem;
3296*25cf1a30Sjl 	drmach_mem_t	*t_mem;
3297*25cf1a30Sjl 	struct memlist	*x_ml;
3298*25cf1a30Sjl 	uint64_t	s_copybasepa, t_copybasepa;
3299*25cf1a30Sjl 	uint_t		len;
3300*25cf1a30Sjl 	caddr_t		bp, wp;
3301*25cf1a30Sjl 	int			s_bd, t_bd, cpuid, active_cpus, i;
3302*25cf1a30Sjl 	uint64_t		c_addr;
3303*25cf1a30Sjl 	size_t			c_size, copy_sz, sz;
3304*25cf1a30Sjl 	static sbd_error_t	*drmach_get_scf_addr(uint64_t *);
3305*25cf1a30Sjl 	extern void		drmach_fmem_loop_script();
3306*25cf1a30Sjl 	extern void		drmach_fmem_loop_script_rtn();
3307*25cf1a30Sjl 	extern int		drmach_fmem_exec_script();
3308*25cf1a30Sjl 	extern void		drmach_fmem_exec_script_end();
3309*25cf1a30Sjl 	sbd_error_t	*err;
3310*25cf1a30Sjl 	drmach_copy_rename_program_t *prog;
3311*25cf1a30Sjl 	void		(*mc_suspend)(void);
3312*25cf1a30Sjl 	void		(*mc_resume)(void);
3313*25cf1a30Sjl 	int		(*scf_fmem_start)(int, int);
3314*25cf1a30Sjl 	int		(*scf_fmem_end)(void);
3315*25cf1a30Sjl 	int		(*scf_fmem_cancel)(void);
3316*25cf1a30Sjl 
3317*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(s_id))
3318*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
3319*25cf1a30Sjl 	if (!DRMACH_IS_MEM_ID(t_id))
3320*25cf1a30Sjl 		return (drerr_new(0, EOPL_INAPPROP, NULL));
3321*25cf1a30Sjl 
3322*25cf1a30Sjl 	for (i = 0; i < NCPU; i++) {
3323*25cf1a30Sjl 		int lsb_id, onb_core_num, strand_id;
3324*25cf1a30Sjl 		drmach_board_t *bp;
3325*25cf1a30Sjl 
3326*25cf1a30Sjl 		/*
3327*25cf1a30Sjl 		 * this kind of CPU will spin in cache
3328*25cf1a30Sjl 		 */
3329*25cf1a30Sjl 		if (CPU_IN_SET(cpu_ready_set, i))
3330*25cf1a30Sjl 			continue;
3331*25cf1a30Sjl 
3332*25cf1a30Sjl 		/*
3333*25cf1a30Sjl 		 * Now check for any inactive CPU's that
3334*25cf1a30Sjl 		 * have been hotadded.  This can only occur in
3335*25cf1a30Sjl 		 * error condition in drmach_cpu_poweron().
3336*25cf1a30Sjl 		 */
3337*25cf1a30Sjl 		lsb_id = LSB_ID(i);
3338*25cf1a30Sjl 		onb_core_num = ON_BOARD_CORE_NUM(i);
3339*25cf1a30Sjl 		strand_id = STRAND_ID(i);
3340*25cf1a30Sjl 		bp = drmach_get_board_by_bnum(lsb_id);
3341*25cf1a30Sjl 		if (bp == NULL)
3342*25cf1a30Sjl 			continue;
3343*25cf1a30Sjl 		if (bp->cores[onb_core_num].core_hotadded &
3344*25cf1a30Sjl 		    (1 << strand_id)) {
3345*25cf1a30Sjl 		    if (!(bp->cores[onb_core_num].core_started &
3346*25cf1a30Sjl 			(1 << strand_id))) {
3347*25cf1a30Sjl 			return (DRMACH_INTERNAL_ERROR());
3348*25cf1a30Sjl 		    }
3349*25cf1a30Sjl 		}
3350*25cf1a30Sjl 	}
3351*25cf1a30Sjl 
3352*25cf1a30Sjl 	mc_suspend = (void (*)(void))
3353*25cf1a30Sjl 	    modgetsymvalue("opl_mc_suspend", 0);
3354*25cf1a30Sjl 	mc_resume = (void (*)(void))
3355*25cf1a30Sjl 	    modgetsymvalue("opl_mc_resume", 0);
3356*25cf1a30Sjl 
3357*25cf1a30Sjl 	if (mc_suspend == NULL || mc_resume == NULL) {
3358*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
3359*25cf1a30Sjl 	}
3360*25cf1a30Sjl 
3361*25cf1a30Sjl 	scf_fmem_start = (int (*)(int, int))
3362*25cf1a30Sjl 	    modgetsymvalue("scf_fmem_start", 0);
3363*25cf1a30Sjl 	if (scf_fmem_start == NULL) {
3364*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
3365*25cf1a30Sjl 	}
3366*25cf1a30Sjl 	scf_fmem_end = (int (*)(void))
3367*25cf1a30Sjl 	    modgetsymvalue("scf_fmem_end", 0);
3368*25cf1a30Sjl 	if (scf_fmem_end == NULL) {
3369*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
3370*25cf1a30Sjl 	}
3371*25cf1a30Sjl 	scf_fmem_cancel = (int (*)(void))
3372*25cf1a30Sjl 	    modgetsymvalue("scf_fmem_cancel", 0);
3373*25cf1a30Sjl 	if (scf_fmem_cancel == NULL) {
3374*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
3375*25cf1a30Sjl 	}
3376*25cf1a30Sjl 	s_mem = s_id;
3377*25cf1a30Sjl 	t_mem = t_id;
3378*25cf1a30Sjl 
3379*25cf1a30Sjl 	s_bd = s_mem->dev.bp->bnum;
3380*25cf1a30Sjl 	t_bd = t_mem->dev.bp->bnum;
3381*25cf1a30Sjl 
3382*25cf1a30Sjl 	/* calculate source and target base pa */
3383*25cf1a30Sjl 
3384*25cf1a30Sjl 	s_copybasepa = s_mem->slice_base;
3385*25cf1a30Sjl 	t_copybasepa = t_mem->slice_base;
3386*25cf1a30Sjl 
3387*25cf1a30Sjl 	/* adjust copy memlist addresses to be relative to copy base pa */
3388*25cf1a30Sjl 	x_ml = c_ml;
3389*25cf1a30Sjl 	while (x_ml != NULL) {
3390*25cf1a30Sjl 		x_ml->address -= s_copybasepa;
3391*25cf1a30Sjl 		x_ml = x_ml->next;
3392*25cf1a30Sjl 	}
3393*25cf1a30Sjl 
3394*25cf1a30Sjl 	/*
3395*25cf1a30Sjl 	 * bp will be page aligned, since we're calling
3396*25cf1a30Sjl 	 * kmem_zalloc() with an exact multiple of PAGESIZE.
3397*25cf1a30Sjl 	 */
3398*25cf1a30Sjl 	wp = bp = kmem_zalloc(DRMACH_FMEM_LOCKED_PAGES * PAGESIZE,
3399*25cf1a30Sjl 		KM_SLEEP);
3400*25cf1a30Sjl 
3401*25cf1a30Sjl 	prog = (drmach_copy_rename_program_t *)(wp +
3402*25cf1a30Sjl 		DRMACH_FMEM_DATA_PAGE * PAGESIZE);
3403*25cf1a30Sjl 	prog->data = (drmach_copy_rename_data_t *)roundup(((uint64_t)prog +
3404*25cf1a30Sjl 		sizeof (drmach_copy_rename_program_t)), sizeof (void *));
3405*25cf1a30Sjl 
3406*25cf1a30Sjl 	ASSERT(((uint64_t)prog->data + sizeof (drmach_copy_rename_data_t))
3407*25cf1a30Sjl 		<= ((uint64_t)prog + PAGESIZE));
3408*25cf1a30Sjl 
3409*25cf1a30Sjl 	prog->critical = (drmach_copy_rename_critical_t *)
3410*25cf1a30Sjl 		(wp + DRMACH_FMEM_CRITICAL_PAGE * PAGESIZE);
3411*25cf1a30Sjl 
3412*25cf1a30Sjl 	prog->memlist_buffer = (caddr_t)(wp +
3413*25cf1a30Sjl 		DRMACH_FMEM_MLIST_PAGE * PAGESIZE);
3414*25cf1a30Sjl 
3415*25cf1a30Sjl 	prog->stat = (drmach_cr_stat_t *)(wp +
3416*25cf1a30Sjl 		DRMACH_FMEM_STAT_PAGE * PAGESIZE);
3417*25cf1a30Sjl 
3418*25cf1a30Sjl 	/* LINTED */
3419*25cf1a30Sjl 	ASSERT(sizeof (drmach_cr_stat_t)
3420*25cf1a30Sjl 		<= ((DRMACH_FMEM_LOCKED_PAGES - DRMACH_FMEM_STAT_PAGE)
3421*25cf1a30Sjl 		* PAGESIZE));
3422*25cf1a30Sjl 
3423*25cf1a30Sjl 	prog->critical->scf_reg_base = (uint64_t)-1;
3424*25cf1a30Sjl 	err = drmach_get_scf_addr(&(prog->critical->scf_reg_base));
3425*25cf1a30Sjl 	if (err) {
3426*25cf1a30Sjl 		kmem_free(wp, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
3427*25cf1a30Sjl 		return (err);
3428*25cf1a30Sjl 	}
3429*25cf1a30Sjl 
3430*25cf1a30Sjl 	prog->critical->scf_td[0] = (s_bd & 0xff);
3431*25cf1a30Sjl 	prog->critical->scf_td[1] = (t_bd & 0xff);
3432*25cf1a30Sjl 	for (i = 2; i < 15; i++) {
3433*25cf1a30Sjl 		prog->critical->scf_td[i]   = 0;
3434*25cf1a30Sjl 	}
3435*25cf1a30Sjl 	prog->critical->scf_td[15] = ((0xaa + s_bd + t_bd) & 0xff);
3436*25cf1a30Sjl 
3437*25cf1a30Sjl 	bp = (caddr_t)prog->critical;
3438*25cf1a30Sjl 	len = sizeof (drmach_copy_rename_critical_t);
3439*25cf1a30Sjl 	wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *));
3440*25cf1a30Sjl 
3441*25cf1a30Sjl 	len = (uint_t)((ulong_t)drmach_copy_rename_end -
3442*25cf1a30Sjl 		(ulong_t)drmach_copy_rename_prog__relocatable);
3443*25cf1a30Sjl 
3444*25cf1a30Sjl 	/*
3445*25cf1a30Sjl 	 * We always leave 1K nop's to prevent the processor from
3446*25cf1a30Sjl 	 * speculative execution that causes memory access
3447*25cf1a30Sjl 	 */
3448*25cf1a30Sjl 	wp = wp + len + 1024;
3449*25cf1a30Sjl 
3450*25cf1a30Sjl 	len = (uint_t)((ulong_t)drmach_fmem_exec_script_end -
3451*25cf1a30Sjl 		(ulong_t)drmach_fmem_exec_script);
3452*25cf1a30Sjl 	/* this is the entry point of the loop script */
3453*25cf1a30Sjl 	wp = wp + len + 1024;
3454*25cf1a30Sjl 
3455*25cf1a30Sjl 	len = (uint_t)((ulong_t)drmach_fmem_exec_script -
3456*25cf1a30Sjl 		(ulong_t)drmach_fmem_loop_script);
3457*25cf1a30Sjl 	wp = wp + len + 1024;
3458*25cf1a30Sjl 
3459*25cf1a30Sjl 	/* now we make sure there is 1K extra */
3460*25cf1a30Sjl 
3461*25cf1a30Sjl 	if ((wp - bp) > PAGESIZE) {
3462*25cf1a30Sjl 		kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
3463*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
3464*25cf1a30Sjl 	}
3465*25cf1a30Sjl 
3466*25cf1a30Sjl 	bp = (caddr_t)prog->critical;
3467*25cf1a30Sjl 	len = sizeof (drmach_copy_rename_critical_t);
3468*25cf1a30Sjl 	wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *));
3469*25cf1a30Sjl 
3470*25cf1a30Sjl 	prog->critical->run = (int (*)())(wp);
3471*25cf1a30Sjl 	len = (uint_t)((ulong_t)drmach_copy_rename_end -
3472*25cf1a30Sjl 		(ulong_t)drmach_copy_rename_prog__relocatable);
3473*25cf1a30Sjl 
3474*25cf1a30Sjl 	bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len);
3475*25cf1a30Sjl 
3476*25cf1a30Sjl 	wp = (caddr_t)roundup((uint64_t)wp + len, 1024);
3477*25cf1a30Sjl 
3478*25cf1a30Sjl 	prog->critical->fmem = (int (*)())(wp);
3479*25cf1a30Sjl 	len = (int)((ulong_t)drmach_fmem_exec_script_end -
3480*25cf1a30Sjl 		(ulong_t)drmach_fmem_exec_script);
3481*25cf1a30Sjl 	bcopy((caddr_t)drmach_fmem_exec_script, wp, len);
3482*25cf1a30Sjl 
3483*25cf1a30Sjl 	len = (int)((ulong_t)drmach_fmem_exec_script_end -
3484*25cf1a30Sjl 		(ulong_t)drmach_fmem_exec_script);
3485*25cf1a30Sjl 	wp = (caddr_t)roundup((uint64_t)wp + len, 1024);
3486*25cf1a30Sjl 
3487*25cf1a30Sjl 	prog->critical->loop = (int (*)())(wp);
3488*25cf1a30Sjl 	len = (int)((ulong_t)drmach_fmem_exec_script -
3489*25cf1a30Sjl 		(ulong_t)drmach_fmem_loop_script);
3490*25cf1a30Sjl 	bcopy((caddr_t)drmach_fmem_loop_script, (void *)wp, len);
3491*25cf1a30Sjl 	len = (int)((ulong_t)drmach_fmem_loop_script_rtn-
3492*25cf1a30Sjl 		(ulong_t)drmach_fmem_loop_script);
3493*25cf1a30Sjl 	prog->critical->loop_rtn = (void (*)()) (wp+len);
3494*25cf1a30Sjl 
3495*25cf1a30Sjl 	/* now we are committed, call SCF, soft suspend mac patrol */
3496*25cf1a30Sjl 	if ((*scf_fmem_start)(s_bd, t_bd)) {
3497*25cf1a30Sjl 		kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
3498*25cf1a30Sjl 		return (DRMACH_INTERNAL_ERROR());
3499*25cf1a30Sjl 	}
3500*25cf1a30Sjl 	prog->data->scf_fmem_end = scf_fmem_end;
3501*25cf1a30Sjl 	prog->data->scf_fmem_cancel = scf_fmem_cancel;
3502*25cf1a30Sjl 	prog->data->fmem_status.op |= OPL_FMEM_SCF_START;
3503*25cf1a30Sjl 	/* soft suspend mac patrol */
3504*25cf1a30Sjl 	(*mc_suspend)();
3505*25cf1a30Sjl 	prog->data->fmem_status.op |= OPL_FMEM_MC_SUSPEND;
3506*25cf1a30Sjl 	prog->data->mc_resume = mc_resume;
3507*25cf1a30Sjl 
3508*25cf1a30Sjl 	prog->critical->inst_loop_ret  =
3509*25cf1a30Sjl 		*(uint64_t *)(prog->critical->loop_rtn);
3510*25cf1a30Sjl 
3511*25cf1a30Sjl 	/*
3512*25cf1a30Sjl 	 * 0x30800000 is op code "ba,a	+0"
3513*25cf1a30Sjl 	 */
3514*25cf1a30Sjl 
3515*25cf1a30Sjl 	*(uint_t *)(prog->critical->loop_rtn) = (uint_t)(0x30800000);
3516*25cf1a30Sjl 
3517*25cf1a30Sjl 	/*
3518*25cf1a30Sjl 	 * set the value of SCF FMEM TIMEOUT
3519*25cf1a30Sjl 	 */
3520*25cf1a30Sjl 	prog->critical->delay = fmem_timeout * system_clock_freq;
3521*25cf1a30Sjl 
3522*25cf1a30Sjl 	prog->data->s_mem = (drmachid_t)s_mem;
3523*25cf1a30Sjl 	prog->data->t_mem = (drmachid_t)t_mem;
3524*25cf1a30Sjl 
3525*25cf1a30Sjl 	cpuid = CPU->cpu_id;
3526*25cf1a30Sjl 	prog->data->cpuid = cpuid;
3527*25cf1a30Sjl 	prog->data->cpu_ready_set = cpu_ready_set;
3528*25cf1a30Sjl 	prog->data->cpu_slave_set = cpu_ready_set;
3529*25cf1a30Sjl 	prog->data->slowest_cpuid = (processorid_t)-1;
3530*25cf1a30Sjl 	prog->data->copy_wait_time = 0;
3531*25cf1a30Sjl 	CPUSET_DEL(prog->data->cpu_slave_set, cpuid);
3532*25cf1a30Sjl 
3533*25cf1a30Sjl 	for (i = 0; i < NCPU; i++) {
3534*25cf1a30Sjl 		prog->data->cpu_ml[i] = NULL;
3535*25cf1a30Sjl 	}
3536*25cf1a30Sjl 
3537*25cf1a30Sjl 	active_cpus = 0;
3538*25cf1a30Sjl 	if (drmach_disable_mcopy) {
3539*25cf1a30Sjl 		active_cpus = 1;
3540*25cf1a30Sjl 		CPUSET_ADD(prog->data->cpu_copy_set, cpuid);
3541*25cf1a30Sjl 	} else {
3542*25cf1a30Sjl 		for (i = 0; i < NCPU; i++) {
3543*25cf1a30Sjl 			if (CPU_IN_SET(cpu_ready_set, i) &&
3544*25cf1a30Sjl 				CPU_ACTIVE(cpu[i])) {
3545*25cf1a30Sjl 				CPUSET_ADD(prog->data->cpu_copy_set, i);
3546*25cf1a30Sjl 				active_cpus++;
3547*25cf1a30Sjl 			}
3548*25cf1a30Sjl 		}
3549*25cf1a30Sjl 	}
3550*25cf1a30Sjl 
3551*25cf1a30Sjl 	drmach_setup_memlist(prog);
3552*25cf1a30Sjl 
3553*25cf1a30Sjl 	x_ml = c_ml;
3554*25cf1a30Sjl 	sz = 0;
3555*25cf1a30Sjl 	while (x_ml != NULL) {
3556*25cf1a30Sjl 		sz += x_ml->size;
3557*25cf1a30Sjl 		x_ml = x_ml->next;
3558*25cf1a30Sjl 	}
3559*25cf1a30Sjl 
3560*25cf1a30Sjl 	copy_sz = sz/active_cpus;
3561*25cf1a30Sjl 	copy_sz = roundup(copy_sz, MMU_PAGESIZE4M);
3562*25cf1a30Sjl 
3563*25cf1a30Sjl 	while (sz > copy_sz*active_cpus) {
3564*25cf1a30Sjl 		copy_sz += MMU_PAGESIZE4M;
3565*25cf1a30Sjl 	}
3566*25cf1a30Sjl 
3567*25cf1a30Sjl 	prog->data->stick_freq = system_clock_freq;
3568*25cf1a30Sjl 	prog->data->copy_delay = ((copy_sz / min_copy_size_per_sec) + 2) *
3569*25cf1a30Sjl 		system_clock_freq;
3570*25cf1a30Sjl 
3571*25cf1a30Sjl 	x_ml = c_ml;
3572*25cf1a30Sjl 	c_addr = x_ml->address;
3573*25cf1a30Sjl 	c_size = x_ml->size;
3574*25cf1a30Sjl 
3575*25cf1a30Sjl 	for (i = 0; i < NCPU; i++) {
3576*25cf1a30Sjl 		prog->stat->nbytes[i] = 0;
3577*25cf1a30Sjl 		if (!CPU_IN_SET(prog->data->cpu_copy_set, i)) {
3578*25cf1a30Sjl 			continue;
3579*25cf1a30Sjl 		}
3580*25cf1a30Sjl 		sz = copy_sz;
3581*25cf1a30Sjl 
3582*25cf1a30Sjl 		while (sz) {
3583*25cf1a30Sjl 			if (c_size > sz) {
3584*25cf1a30Sjl 				prog->data->cpu_ml[i] =
3585*25cf1a30Sjl 					drmach_memlist_add_span(prog,
3586*25cf1a30Sjl 					prog->data->cpu_ml[i],
3587*25cf1a30Sjl 					c_addr, sz);
3588*25cf1a30Sjl 				c_addr += sz;
3589*25cf1a30Sjl 				c_size -= sz;
3590*25cf1a30Sjl 				break;
3591*25cf1a30Sjl 			} else {
3592*25cf1a30Sjl 				sz -= c_size;
3593*25cf1a30Sjl 				prog->data->cpu_ml[i] = drmach_memlist_add_span(
3594*25cf1a30Sjl 					prog, prog->data->cpu_ml[i],
3595*25cf1a30Sjl 						c_addr, c_size);
3596*25cf1a30Sjl 				x_ml = x_ml->next;
3597*25cf1a30Sjl 				if (x_ml != NULL) {
3598*25cf1a30Sjl 					c_addr = x_ml->address;
3599*25cf1a30Sjl 					c_size = x_ml->size;
3600*25cf1a30Sjl 				} else {
3601*25cf1a30Sjl 					goto end;
3602*25cf1a30Sjl 				}
3603*25cf1a30Sjl 			}
3604*25cf1a30Sjl 		}
3605*25cf1a30Sjl 	}
3606*25cf1a30Sjl end:
3607*25cf1a30Sjl 	prog->data->s_copybasepa = s_copybasepa;
3608*25cf1a30Sjl 	prog->data->t_copybasepa = t_copybasepa;
3609*25cf1a30Sjl 	prog->data->c_ml = c_ml;
3610*25cf1a30Sjl 	*pgm_id = prog;
3611*25cf1a30Sjl 
3612*25cf1a30Sjl 	return (NULL);
3613*25cf1a30Sjl }
3614*25cf1a30Sjl 
3615*25cf1a30Sjl sbd_error_t *
3616*25cf1a30Sjl drmach_copy_rename_fini(drmachid_t id)
3617*25cf1a30Sjl {
3618*25cf1a30Sjl 	drmach_copy_rename_program_t	*prog = id;
3619*25cf1a30Sjl 	sbd_error_t			*err = NULL;
3620*25cf1a30Sjl 	int				rv;
3621*25cf1a30Sjl 
3622*25cf1a30Sjl 	/*
3623*25cf1a30Sjl 	 * Note that we have to delay calling SCF to find out the
3624*25cf1a30Sjl 	 * status of the FMEM operation here because SCF cannot
3625*25cf1a30Sjl 	 * respond while it is suspended.
3626*25cf1a30Sjl 	 * This create a small window when we are sure about the
3627*25cf1a30Sjl 	 * base address of the system board.
3628*25cf1a30Sjl 	 * If there is any call to mc-opl to get memory unum,
3629*25cf1a30Sjl 	 * mc-opl will return UNKNOWN as the unum.
3630*25cf1a30Sjl 	 */
3631*25cf1a30Sjl 
3632*25cf1a30Sjl 	if (prog->data->c_ml != NULL)
3633*25cf1a30Sjl 		memlist_delete(prog->data->c_ml);
3634*25cf1a30Sjl 
3635*25cf1a30Sjl 	if ((prog->data->fmem_status.op &
3636*25cf1a30Sjl 		(OPL_FMEM_SCF_START| OPL_FMEM_MC_SUSPEND)) !=
3637*25cf1a30Sjl 		(OPL_FMEM_SCF_START | OPL_FMEM_MC_SUSPEND)) {
3638*25cf1a30Sjl 		cmn_err(CE_PANIC, "drmach_copy_rename_fini: "
3639*25cf1a30Sjl 			"invalid op code %x\n",
3640*25cf1a30Sjl 				prog->data->fmem_status.op);
3641*25cf1a30Sjl 	}
3642*25cf1a30Sjl 
3643*25cf1a30Sjl 	/* possible ops are SCF_START, MC_SUSPEND */
3644*25cf1a30Sjl 	if (prog->critical->fmem_issued) {
3645*25cf1a30Sjl 		if (prog->data->fmem_status.error != FMEM_NO_ERROR)
3646*25cf1a30Sjl 			cmn_err(CE_PANIC, "scf fmem request failed");
3647*25cf1a30Sjl 		rv = (*prog->data->scf_fmem_end)();
3648*25cf1a30Sjl 		if (rv) {
3649*25cf1a30Sjl 			cmn_err(CE_PANIC, "scf_fmem_end() failed");
3650*25cf1a30Sjl 		}
3651*25cf1a30Sjl 		/*
3652*25cf1a30Sjl 		 * If we get here, rename is successful.
3653*25cf1a30Sjl 		 * Do all the copy rename post processing.
3654*25cf1a30Sjl 		 */
3655*25cf1a30Sjl 		drmach_swap_pa((drmach_mem_t *)prog->data->s_mem,
3656*25cf1a30Sjl 			(drmach_mem_t *)prog->data->t_mem);
3657*25cf1a30Sjl 	} else {
3658*25cf1a30Sjl 		if (prog->data->fmem_status.error != 0) {
3659*25cf1a30Sjl 			cmn_err(CE_WARN, "Kernel Migration fails. 0x%x",
3660*25cf1a30Sjl 				prog->data->fmem_status.error);
3661*25cf1a30Sjl 			err = DRMACH_INTERNAL_ERROR();
3662*25cf1a30Sjl 		}
3663*25cf1a30Sjl 		rv = (*prog->data->scf_fmem_cancel)();
3664*25cf1a30Sjl 		if (rv) {
3665*25cf1a30Sjl 			cmn_err(CE_WARN, "scf_fmem_cancel() failed");
3666*25cf1a30Sjl 			if (!err)
3667*25cf1a30Sjl 				err = DRMACH_INTERNAL_ERROR();
3668*25cf1a30Sjl 		}
3669*25cf1a30Sjl 	}
3670*25cf1a30Sjl 	/* soft resume mac patrol */
3671*25cf1a30Sjl 	(*prog->data->mc_resume)();
3672*25cf1a30Sjl 
3673*25cf1a30Sjl 	kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE);
3674*25cf1a30Sjl 	return (err);
3675*25cf1a30Sjl }
3676*25cf1a30Sjl 
3677*25cf1a30Sjl static void
3678*25cf1a30Sjl drmach_lock_critical(caddr_t va)
3679*25cf1a30Sjl {
3680*25cf1a30Sjl 	tte_t tte;
3681*25cf1a30Sjl 	int i;
3682*25cf1a30Sjl 
3683*25cf1a30Sjl 	for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
3684*25cf1a30Sjl 		vtag_flushpage(va, KCONTEXT);
3685*25cf1a30Sjl 		sfmmu_memtte(&tte, va_to_pfn(va),
3686*25cf1a30Sjl 			PROC_DATA|HAT_NOSYNC, TTE8K);
3687*25cf1a30Sjl 		tte.tte_intlo |= TTE_LCK_INT;
3688*25cf1a30Sjl 		sfmmu_dtlb_ld(va, KCONTEXT, &tte);
3689*25cf1a30Sjl 		sfmmu_itlb_ld(va, KCONTEXT, &tte);
3690*25cf1a30Sjl 		va += PAGESIZE;
3691*25cf1a30Sjl 	}
3692*25cf1a30Sjl }
3693*25cf1a30Sjl 
3694*25cf1a30Sjl static void
3695*25cf1a30Sjl drmach_unlock_critical(caddr_t va)
3696*25cf1a30Sjl {
3697*25cf1a30Sjl 	int i;
3698*25cf1a30Sjl 
3699*25cf1a30Sjl 	for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) {
3700*25cf1a30Sjl 		vtag_flushpage(va, KCONTEXT);
3701*25cf1a30Sjl 		va += PAGESIZE;
3702*25cf1a30Sjl 	}
3703*25cf1a30Sjl }
3704*25cf1a30Sjl 
3705*25cf1a30Sjl /*ARGSUSED*/
3706*25cf1a30Sjl static void
3707*25cf1a30Sjl drmach_copy_rename_slave(struct regs *rp, drmachid_t id)
3708*25cf1a30Sjl {
3709*25cf1a30Sjl 	drmach_copy_rename_program_t	*prog = id;
3710*25cf1a30Sjl 	register int			cpuid;
3711*25cf1a30Sjl 	extern void			drmach_flush();
3712*25cf1a30Sjl 	extern void			membar_sync_il();
3713*25cf1a30Sjl 	extern void			drmach_flush_icache();
3714*25cf1a30Sjl 	on_trap_data_t			otd;
3715*25cf1a30Sjl 
3716*25cf1a30Sjl 	kpreempt_disable();
3717*25cf1a30Sjl 	cpuid = CPU->cpu_id;
3718*25cf1a30Sjl 
3719*25cf1a30Sjl 	if (on_trap(&otd, OT_DATA_EC)) {
3720*25cf1a30Sjl 		no_trap();
3721*25cf1a30Sjl 		drmach_unlock_critical((caddr_t)prog);
3722*25cf1a30Sjl 		kpreempt_enable();
3723*25cf1a30Sjl 		prog->data->error[cpuid] = FMEM_COPY_ERROR;
3724*25cf1a30Sjl 		prog->critical->stat[cpuid] = FMEM_LOOP_EXIT;
3725*25cf1a30Sjl 		return;
3726*25cf1a30Sjl 	}
3727*25cf1a30Sjl 
3728*25cf1a30Sjl 
3729*25cf1a30Sjl 	(void) drmach_lock_critical((caddr_t)prog);
3730*25cf1a30Sjl 
3731*25cf1a30Sjl 	flush_windows();
3732*25cf1a30Sjl 
3733*25cf1a30Sjl 	/*
3734*25cf1a30Sjl 	 * jmp drmach_copy_rename_prog().
3735*25cf1a30Sjl 	 */
3736*25cf1a30Sjl 
3737*25cf1a30Sjl 	drmach_flush(prog->critical, PAGESIZE);
3738*25cf1a30Sjl 	(void) prog->critical->run(prog, cpuid);
3739*25cf1a30Sjl 	drmach_flush_icache();
3740*25cf1a30Sjl 
3741*25cf1a30Sjl 	no_trap();
3742*25cf1a30Sjl 	drmach_unlock_critical((caddr_t)prog);
3743*25cf1a30Sjl 
3744*25cf1a30Sjl 	kpreempt_enable();
3745*25cf1a30Sjl 
3746*25cf1a30Sjl 	prog->critical->stat[cpuid] = FMEM_LOOP_EXIT;
3747*25cf1a30Sjl 	membar_sync_il();
3748*25cf1a30Sjl }
3749*25cf1a30Sjl 
3750*25cf1a30Sjl static void
3751*25cf1a30Sjl drmach_swap_pa(drmach_mem_t *s_mem, drmach_mem_t *t_mem)
3752*25cf1a30Sjl {
3753*25cf1a30Sjl 	uint64_t s_base, t_base;
3754*25cf1a30Sjl 	drmach_board_t *s_board, *t_board;
3755*25cf1a30Sjl 	struct memlist *ml;
3756*25cf1a30Sjl 
3757*25cf1a30Sjl 	s_board = s_mem->dev.bp;
3758*25cf1a30Sjl 	t_board = t_mem->dev.bp;
3759*25cf1a30Sjl 	if (s_board == NULL || t_board == NULL) {
3760*25cf1a30Sjl 		cmn_err(CE_PANIC, "Cannot locate source or target board\n");
3761*25cf1a30Sjl 		return;
3762*25cf1a30Sjl 	}
3763*25cf1a30Sjl 	s_base = s_mem->slice_base;
3764*25cf1a30Sjl 	t_base = t_mem->slice_base;
3765*25cf1a30Sjl 
3766*25cf1a30Sjl 	s_mem->slice_base = t_base;
3767*25cf1a30Sjl 	s_mem->base_pa = (s_mem->base_pa - s_base) + t_base;
3768*25cf1a30Sjl 
3769*25cf1a30Sjl 	for (ml = s_mem->memlist; ml; ml = ml->next) {
3770*25cf1a30Sjl 		ml->address = ml->address - s_base + t_base;
3771*25cf1a30Sjl 	}
3772*25cf1a30Sjl 
3773*25cf1a30Sjl 	t_mem->slice_base = s_base;
3774*25cf1a30Sjl 	t_mem->base_pa = (t_mem->base_pa - t_base) + s_base;
3775*25cf1a30Sjl 
3776*25cf1a30Sjl 	for (ml = t_mem->memlist; ml; ml = ml->next) {
3777*25cf1a30Sjl 		ml->address = ml->address - t_base + s_base;
3778*25cf1a30Sjl 	}
3779*25cf1a30Sjl 
3780*25cf1a30Sjl 	/*
3781*25cf1a30Sjl 	 * IKP has to update the sb-mem-ranges for mac patrol driver
3782*25cf1a30Sjl 	 * when it resumes, it will re-read the sb-mem-range property
3783*25cf1a30Sjl 	 * to get the new base address
3784*25cf1a30Sjl 	 */
3785*25cf1a30Sjl 	if (oplcfg_pa_swap(s_board->bnum, t_board->bnum) != 0)
3786*25cf1a30Sjl 		cmn_err(CE_PANIC, "Could not update device nodes\n");
3787*25cf1a30Sjl }
3788*25cf1a30Sjl 
3789*25cf1a30Sjl void
3790*25cf1a30Sjl drmach_copy_rename(drmachid_t id)
3791*25cf1a30Sjl {
3792*25cf1a30Sjl 	drmach_copy_rename_program_t	*prog = id;
3793*25cf1a30Sjl 	cpuset_t	cpuset;
3794*25cf1a30Sjl 	int		cpuid;
3795*25cf1a30Sjl 	uint64_t	inst;
3796*25cf1a30Sjl 	register int	rtn;
3797*25cf1a30Sjl 	extern int	in_sync;
3798*25cf1a30Sjl 	int		old_in_sync;
3799*25cf1a30Sjl 	extern void	drmach_sys_trap();
3800*25cf1a30Sjl 	extern void	drmach_flush();
3801*25cf1a30Sjl 	extern void	drmach_flush_icache();
3802*25cf1a30Sjl 	extern uint64_t	patch_inst(uint64_t *, uint64_t);
3803*25cf1a30Sjl 	on_trap_data_t	otd;
3804*25cf1a30Sjl 
3805*25cf1a30Sjl 	if (prog->critical->scf_reg_base == (uint64_t)-1) {
3806*25cf1a30Sjl 		prog->data->fmem_status.error = FMEM_SCF_ERR;
3807*25cf1a30Sjl 		return;
3808*25cf1a30Sjl 	}
3809*25cf1a30Sjl 
3810*25cf1a30Sjl 	kpreempt_disable();
3811*25cf1a30Sjl 	cpuset = prog->data->cpu_ready_set;
3812*25cf1a30Sjl 
3813*25cf1a30Sjl 	for (cpuid = 0; cpuid < NCPU; cpuid++) {
3814*25cf1a30Sjl 		if (CPU_IN_SET(cpuset, cpuid)) {
3815*25cf1a30Sjl 			prog->critical->stat[cpuid] = FMEM_LOOP_START;
3816*25cf1a30Sjl 			prog->data->error[cpuid] = FMEM_NO_ERROR;
3817*25cf1a30Sjl 		}
3818*25cf1a30Sjl 	}
3819*25cf1a30Sjl 
3820*25cf1a30Sjl 	old_in_sync = in_sync;
3821*25cf1a30Sjl 	in_sync = 1;
3822*25cf1a30Sjl 	cpuid = CPU->cpu_id;
3823*25cf1a30Sjl 
3824*25cf1a30Sjl 	CPUSET_DEL(cpuset, cpuid);
3825*25cf1a30Sjl 
3826*25cf1a30Sjl 	xc_some(cpuset, (xcfunc_t *)drmach_lock_critical,
3827*25cf1a30Sjl 		(uint64_t)prog, (uint64_t)0);
3828*25cf1a30Sjl 
3829*25cf1a30Sjl 	xt_some(cpuset, (xcfunc_t *)drmach_sys_trap,
3830*25cf1a30Sjl 		(uint64_t)drmach_copy_rename_slave, (uint64_t)prog);
3831*25cf1a30Sjl 	xt_sync(cpuset);
3832*25cf1a30Sjl 
3833*25cf1a30Sjl 	(void) drmach_lock_critical((caddr_t)prog);
3834*25cf1a30Sjl 
3835*25cf1a30Sjl 	if (on_trap(&otd, OT_DATA_EC)) {
3836*25cf1a30Sjl 		rtn = FMEM_COPY_ERROR;
3837*25cf1a30Sjl 		goto done;
3838*25cf1a30Sjl 	}
3839*25cf1a30Sjl 
3840*25cf1a30Sjl 	flush_windows();
3841*25cf1a30Sjl 
3842*25cf1a30Sjl 	/*
3843*25cf1a30Sjl 	 * jmp drmach_copy_rename_prog().
3844*25cf1a30Sjl 	 */
3845*25cf1a30Sjl 	drmach_flush(prog->critical, PAGESIZE);
3846*25cf1a30Sjl 	rtn = prog->critical->run(prog, cpuid);
3847*25cf1a30Sjl 	drmach_flush_icache();
3848*25cf1a30Sjl 
3849*25cf1a30Sjl 
3850*25cf1a30Sjl done:
3851*25cf1a30Sjl 	no_trap();
3852*25cf1a30Sjl 	if (rtn == FMEM_HW_ERROR) {
3853*25cf1a30Sjl 		kpreempt_enable();
3854*25cf1a30Sjl 		prom_panic("URGENT_ERROR_TRAP is "
3855*25cf1a30Sjl 			"detected during FMEM.\n");
3856*25cf1a30Sjl 	}
3857*25cf1a30Sjl 
3858*25cf1a30Sjl 	/*
3859*25cf1a30Sjl 	 * In normal case, all slave CPU's are still spinning in
3860*25cf1a30Sjl 	 * the assembly code.  The master has to patch the instruction
3861*25cf1a30Sjl 	 * to get them out.
3862*25cf1a30Sjl 	 * In error case, e.g. COPY_ERROR, some slave CPU's might
3863*25cf1a30Sjl 	 * have aborted and already returned and sset LOOP_EXIT status.
3864*25cf1a30Sjl 	 * Some CPU might still be copying.
3865*25cf1a30Sjl 	 * In any case, some delay is necessary to give them
3866*25cf1a30Sjl 	 * enough time to set the LOOP_EXIT status.
3867*25cf1a30Sjl 	 */
3868*25cf1a30Sjl 
3869*25cf1a30Sjl 	for (;;) {
3870*25cf1a30Sjl 		inst = patch_inst((uint64_t *)prog->critical->loop_rtn,
3871*25cf1a30Sjl 			prog->critical->inst_loop_ret);
3872*25cf1a30Sjl 		if (prog->critical->inst_loop_ret == inst) {
3873*25cf1a30Sjl 			break;
3874*25cf1a30Sjl 		}
3875*25cf1a30Sjl 	}
3876*25cf1a30Sjl 
3877*25cf1a30Sjl 	for (cpuid = 0; cpuid < NCPU; cpuid++) {
3878*25cf1a30Sjl 		uint64_t	last, now;
3879*25cf1a30Sjl 		if (!CPU_IN_SET(cpuset, cpuid)) {
3880*25cf1a30Sjl 			continue;
3881*25cf1a30Sjl 		}
3882*25cf1a30Sjl 		last = prog->stat->nbytes[cpuid];
3883*25cf1a30Sjl 		/*
3884*25cf1a30Sjl 		 * Wait for all CPU to exit.
3885*25cf1a30Sjl 		 * However we do not want an infinite loop
3886*25cf1a30Sjl 		 * so we detect hangup situation here.
3887*25cf1a30Sjl 		 * If the slave CPU is still copying data,
3888*25cf1a30Sjl 		 * we will continue to wait.
3889*25cf1a30Sjl 		 * In error cases, the master has already set
3890*25cf1a30Sjl 		 * fmem_status.error to abort the copying.
3891*25cf1a30Sjl 		 * 1 m.s delay for them to abort copying and
3892*25cf1a30Sjl 		 * return to drmach_copy_rename_slave to set
3893*25cf1a30Sjl 		 * FMEM_LOOP_EXIT status should be enough.
3894*25cf1a30Sjl 		 */
3895*25cf1a30Sjl 		for (;;) {
3896*25cf1a30Sjl 			if (prog->critical->stat[cpuid] == FMEM_LOOP_EXIT)
3897*25cf1a30Sjl 				break;
3898*25cf1a30Sjl 			drmach_sleep_il();
3899*25cf1a30Sjl 			drv_usecwait(1000);
3900*25cf1a30Sjl 			now = prog->stat->nbytes[cpuid];
3901*25cf1a30Sjl 			if (now <= last) {
3902*25cf1a30Sjl 			    drv_usecwait(1000);
3903*25cf1a30Sjl 			    if (prog->critical->stat[cpuid] == FMEM_LOOP_EXIT)
3904*25cf1a30Sjl 				break;
3905*25cf1a30Sjl 			    cmn_err(CE_PANIC,
3906*25cf1a30Sjl 				"CPU %d hang during Copy Rename", cpuid);
3907*25cf1a30Sjl 			}
3908*25cf1a30Sjl 			last = now;
3909*25cf1a30Sjl 		}
3910*25cf1a30Sjl 		if (prog->data->error[cpuid] == FMEM_HW_ERROR) {
3911*25cf1a30Sjl 			prom_panic("URGENT_ERROR_TRAP is "
3912*25cf1a30Sjl 				"detected during FMEM.\n");
3913*25cf1a30Sjl 		}
3914*25cf1a30Sjl 	}
3915*25cf1a30Sjl 	drmach_unlock_critical((caddr_t)prog);
3916*25cf1a30Sjl 
3917*25cf1a30Sjl 	in_sync = old_in_sync;
3918*25cf1a30Sjl 
3919*25cf1a30Sjl 	kpreempt_enable();
3920*25cf1a30Sjl 	if (prog->data->fmem_status.error == 0)
3921*25cf1a30Sjl 		prog->data->fmem_status.error = rtn;
3922*25cf1a30Sjl 
3923*25cf1a30Sjl 	if (prog->data->copy_wait_time > 0) {
3924*25cf1a30Sjl 		DRMACH_PR("Unexpected long wait time %ld seconds "
3925*25cf1a30Sjl 			"during copy rename on CPU %d\n",
3926*25cf1a30Sjl 			prog->data->copy_wait_time/prog->data->stick_freq,
3927*25cf1a30Sjl 			prog->data->slowest_cpuid);
3928*25cf1a30Sjl 	}
3929*25cf1a30Sjl }
3930