xref: /onnv-gate/usr/src/uts/sun4u/starfire/io/drmach.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/debug.h>
30*0Sstevel@tonic-gate #include <sys/types.h>
31*0Sstevel@tonic-gate #include <sys/varargs.h>
32*0Sstevel@tonic-gate #include <sys/errno.h>
33*0Sstevel@tonic-gate #include <sys/cred.h>
34*0Sstevel@tonic-gate #include <sys/dditypes.h>
35*0Sstevel@tonic-gate #include <sys/devops.h>
36*0Sstevel@tonic-gate #include <sys/modctl.h>
37*0Sstevel@tonic-gate #include <sys/poll.h>
38*0Sstevel@tonic-gate #include <sys/conf.h>
39*0Sstevel@tonic-gate #include <sys/ddi.h>
40*0Sstevel@tonic-gate #include <sys/sunddi.h>
41*0Sstevel@tonic-gate #include <sys/sunndi.h>
42*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
43*0Sstevel@tonic-gate #include <sys/stat.h>
44*0Sstevel@tonic-gate #include <sys/kmem.h>
45*0Sstevel@tonic-gate #include <sys/vmem.h>
46*0Sstevel@tonic-gate #include <sys/processor.h>
47*0Sstevel@tonic-gate #include <sys/spitregs.h>
48*0Sstevel@tonic-gate #include <sys/cpuvar.h>
49*0Sstevel@tonic-gate #include <sys/cpupart.h>
50*0Sstevel@tonic-gate #include <sys/mem_config.h>
51*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
52*0Sstevel@tonic-gate #include <sys/systm.h>
53*0Sstevel@tonic-gate #include <sys/machsystm.h>
54*0Sstevel@tonic-gate #include <sys/autoconf.h>
55*0Sstevel@tonic-gate #include <sys/cmn_err.h>
56*0Sstevel@tonic-gate #include <sys/sysmacros.h>
57*0Sstevel@tonic-gate #include <sys/x_call.h>
58*0Sstevel@tonic-gate #include <sys/promif.h>
59*0Sstevel@tonic-gate #include <sys/prom_plat.h>
60*0Sstevel@tonic-gate #include <sys/membar.h>
61*0Sstevel@tonic-gate #include <vm/seg_kmem.h>
62*0Sstevel@tonic-gate #include <sys/mem_cage.h>
63*0Sstevel@tonic-gate #include <sys/stack.h>
64*0Sstevel@tonic-gate #include <sys/archsystm.h>
65*0Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
66*0Sstevel@tonic-gate #include <sys/pte.h>
67*0Sstevel@tonic-gate #include <sys/mmu.h>
68*0Sstevel@tonic-gate #include <sys/cpu_module.h>
69*0Sstevel@tonic-gate #include <sys/obpdefs.h>
70*0Sstevel@tonic-gate #include <sys/note.h>
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate #include <sys/starfire.h>	/* plat_max_... decls */
73*0Sstevel@tonic-gate #include <sys/cvc.h>
74*0Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h>
75*0Sstevel@tonic-gate #include <sys/drmach.h>
76*0Sstevel@tonic-gate #include <sys/dr_util.h>
77*0Sstevel@tonic-gate #include <sys/pda.h>
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate #include <sys/sysevent.h>
80*0Sstevel@tonic-gate #include <sys/sysevent/dr.h>
81*0Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate extern void		bcopy32_il(uint64_t, uint64_t);
85*0Sstevel@tonic-gate extern void		flush_ecache_il(
86*0Sstevel@tonic-gate 				uint64_t physaddr, int size, int linesz);
87*0Sstevel@tonic-gate extern uint_t		ldphysio_il(uint64_t physaddr);
88*0Sstevel@tonic-gate extern void		stphysio_il(uint64_t physaddr, uint_t value);
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate extern uint64_t		mc_get_mem_alignment(void);
91*0Sstevel@tonic-gate extern uint64_t		mc_get_asr_addr(dnode_t);
92*0Sstevel@tonic-gate extern uint64_t		mc_get_idle_addr(dnode_t);
93*0Sstevel@tonic-gate extern uint64_t		mc_get_alignment_mask(dnode_t);
94*0Sstevel@tonic-gate extern int		mc_read_asr(dnode_t, uint_t *);
95*0Sstevel@tonic-gate extern int		mc_write_asr(dnode_t, uint_t);
96*0Sstevel@tonic-gate extern uint64_t		mc_asr_to_pa(uint_t);
97*0Sstevel@tonic-gate extern uint_t		mc_pa_to_asr(uint_t, uint64_t);
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate extern int		pc_madr_add(int, int, int, int);
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate typedef struct {
102*0Sstevel@tonic-gate 	struct drmach_node	*node;
103*0Sstevel@tonic-gate 	void			*data;
104*0Sstevel@tonic-gate } drmach_node_walk_args_t;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate typedef struct drmach_node {
107*0Sstevel@tonic-gate 	void		*here;
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	dnode_t		 (*get_dnode)(struct drmach_node *node);
110*0Sstevel@tonic-gate 	int		 (*walk)(struct drmach_node *node, void *data,
111*0Sstevel@tonic-gate 				int (*cb)(drmach_node_walk_args_t *args));
112*0Sstevel@tonic-gate } drmach_node_t;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate typedef struct {
115*0Sstevel@tonic-gate 	int		 min_index;
116*0Sstevel@tonic-gate 	int		 max_index;
117*0Sstevel@tonic-gate 	int		 arr_sz;
118*0Sstevel@tonic-gate 	drmachid_t	*arr;
119*0Sstevel@tonic-gate } drmach_array_t;
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate typedef struct {
122*0Sstevel@tonic-gate 	void		*isa;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	sbd_error_t	*(*release)(drmachid_t);
125*0Sstevel@tonic-gate 	sbd_error_t	*(*status)(drmachid_t, drmach_status_t *);
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	char		 name[MAXNAMELEN];
128*0Sstevel@tonic-gate } drmach_common_t;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate typedef struct {
131*0Sstevel@tonic-gate 	drmach_common_t	 cm;
132*0Sstevel@tonic-gate 	int		 bnum;
133*0Sstevel@tonic-gate 	int		 assigned;
134*0Sstevel@tonic-gate 	int		 powered;
135*0Sstevel@tonic-gate 	int		 connect_cpuid;
136*0Sstevel@tonic-gate 	int		 cond;
137*0Sstevel@tonic-gate 	drmach_node_t	*tree;
138*0Sstevel@tonic-gate 	drmach_array_t	*devices;
139*0Sstevel@tonic-gate } drmach_board_t;
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate typedef struct {
142*0Sstevel@tonic-gate 	drmach_common_t	 cm;
143*0Sstevel@tonic-gate 	drmach_board_t	*bp;
144*0Sstevel@tonic-gate 	int		 unum;
145*0Sstevel@tonic-gate 	int		 busy;
146*0Sstevel@tonic-gate 	int		 powered;
147*0Sstevel@tonic-gate 	const char	*type;
148*0Sstevel@tonic-gate 	drmach_node_t	*node;
149*0Sstevel@tonic-gate } drmach_device_t;
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate typedef struct {
152*0Sstevel@tonic-gate 	int		 flags;
153*0Sstevel@tonic-gate 	drmach_device_t	*dp;
154*0Sstevel@tonic-gate 	sbd_error_t	*err;
155*0Sstevel@tonic-gate 	dev_info_t	*dip;
156*0Sstevel@tonic-gate } drmach_config_args_t;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate typedef struct {
159*0Sstevel@tonic-gate 	uint64_t	 idle_addr;
160*0Sstevel@tonic-gate 	drmach_device_t	*mem;
161*0Sstevel@tonic-gate } drmach_mc_idle_script_t;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate typedef struct {
164*0Sstevel@tonic-gate 	uint64_t	masr_addr;
165*0Sstevel@tonic-gate 	uint_t		masr;
166*0Sstevel@tonic-gate 	uint_t		_filler;
167*0Sstevel@tonic-gate } drmach_rename_script_t;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate typedef struct {
170*0Sstevel@tonic-gate 	void		(*run)(void *arg);
171*0Sstevel@tonic-gate 	caddr_t		data;
172*0Sstevel@tonic-gate 	pda_handle_t	*ph;
173*0Sstevel@tonic-gate 	struct memlist	*c_ml;
174*0Sstevel@tonic-gate 	uint64_t	s_copybasepa;
175*0Sstevel@tonic-gate 	uint64_t	t_copybasepa;
176*0Sstevel@tonic-gate 	drmach_device_t	*restless_mc;	/* diagnostic output */
177*0Sstevel@tonic-gate } drmach_copy_rename_program_t;
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate typedef enum {
180*0Sstevel@tonic-gate 	DO_IDLE,
181*0Sstevel@tonic-gate 	DO_UNIDLE,
182*0Sstevel@tonic-gate 	DO_PAUSE,
183*0Sstevel@tonic-gate 	DO_UNPAUSE
184*0Sstevel@tonic-gate } drmach_iopc_op_t;
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate typedef struct {
187*0Sstevel@tonic-gate 	drmach_board_t	*obj;
188*0Sstevel@tonic-gate 	int		 ndevs;
189*0Sstevel@tonic-gate 	void		*a;
190*0Sstevel@tonic-gate 	sbd_error_t	*(*found)(void *a, const char *, int, drmachid_t);
191*0Sstevel@tonic-gate 	sbd_error_t	*err;
192*0Sstevel@tonic-gate } drmach_board_cb_data_t;
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate static caddr_t		 drmach_shutdown_va;
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate static int		 drmach_initialized;
197*0Sstevel@tonic-gate static drmach_array_t	*drmach_boards;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate static int		 drmach_cpu_delay = 100;
200*0Sstevel@tonic-gate static int		 drmach_cpu_ntries = 50000;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate volatile uchar_t	*drmach_xt_mb;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate /*
205*0Sstevel@tonic-gate  * Do not change the drmach_shutdown_mbox structure without
206*0Sstevel@tonic-gate  * considering the drmach_shutdown_asm assembly language code.
207*0Sstevel@tonic-gate  */
208*0Sstevel@tonic-gate struct drmach_shutdown_mbox {
209*0Sstevel@tonic-gate 	uint64_t	estack;
210*0Sstevel@tonic-gate 	uint64_t	flushaddr;
211*0Sstevel@tonic-gate 	int		size;
212*0Sstevel@tonic-gate 	int		linesize;
213*0Sstevel@tonic-gate 	uint64_t	physaddr;
214*0Sstevel@tonic-gate };
215*0Sstevel@tonic-gate struct drmach_shutdown_mbox	*drmach_shutdown_asm_mbox;
216*0Sstevel@tonic-gate static sbd_error_t	*drmach_device_new(drmach_node_t *,
217*0Sstevel@tonic-gate 				drmach_board_t *, drmach_device_t **);
218*0Sstevel@tonic-gate static sbd_error_t	*drmach_cpu_new(drmach_device_t *);
219*0Sstevel@tonic-gate static sbd_error_t	*drmach_mem_new(drmach_device_t *);
220*0Sstevel@tonic-gate static sbd_error_t	*drmach_io_new(drmach_device_t *);
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate extern struct cpu	*SIGBCPU;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate #ifdef DEBUG
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate #define	DRMACH_PR		if (drmach_debug) printf
227*0Sstevel@tonic-gate int drmach_debug = 0;		 /* set to non-zero to enable debug messages */
228*0Sstevel@tonic-gate #else
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate #define	DRMACH_PR		_NOTE(CONSTANTCONDITION) if (0) printf
231*0Sstevel@tonic-gate #endif /* DEBUG */
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate #define	DRMACH_OBJ(id)		((drmach_common_t *)id)
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate #define	DRMACH_IS_BOARD_ID(id)	\
236*0Sstevel@tonic-gate 	((id != 0) &&		\
237*0Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new))
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate #define	DRMACH_IS_CPU_ID(id)	\
240*0Sstevel@tonic-gate 	((id != 0) &&		\
241*0Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new))
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate #define	DRMACH_IS_MEM_ID(id)	\
244*0Sstevel@tonic-gate 	((id != 0) &&		\
245*0Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_mem_new))
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate #define	DRMACH_IS_IO_ID(id)	\
248*0Sstevel@tonic-gate 	((id != 0) &&		\
249*0Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate #define	DRMACH_IS_DEVICE_ID(id)					\
252*0Sstevel@tonic-gate 	((id != 0) &&						\
253*0Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
254*0Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
255*0Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate #define	DRMACH_IS_ID(id)					\
258*0Sstevel@tonic-gate 	((id != 0) &&						\
259*0Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new ||	\
260*0Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
261*0Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
262*0Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate #define	DRMACH_CPUID2BNUM(cpuid) \
265*0Sstevel@tonic-gate 	((cpuid) / MAX_CPU_UNITS_PER_BOARD)
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate #define	DRMACH_INTERNAL_ERROR() \
268*0Sstevel@tonic-gate 	drerr_new(1, ESTF_INTERNAL, drmach_ie_fmt, __LINE__)
269*0Sstevel@tonic-gate static char		*drmach_ie_fmt = "drmach.c %d";
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate static struct {
272*0Sstevel@tonic-gate 	const char	 *name;
273*0Sstevel@tonic-gate 	const char	 *type;
274*0Sstevel@tonic-gate 	sbd_error_t	 *(*new)(drmach_device_t *);
275*0Sstevel@tonic-gate } name2type[] = {
276*0Sstevel@tonic-gate 	{ "SUNW,UltraSPARC",	DRMACH_DEVTYPE_CPU,  drmach_cpu_new },
277*0Sstevel@tonic-gate 	{ "mem-unit",		DRMACH_DEVTYPE_MEM,  drmach_mem_new },
278*0Sstevel@tonic-gate 	{ "pci",		DRMACH_DEVTYPE_PCI,  drmach_io_new  },
279*0Sstevel@tonic-gate 	{ "sbus",		DRMACH_DEVTYPE_SBUS, drmach_io_new  },
280*0Sstevel@tonic-gate };
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate /* node types to cleanup when a board is unconfigured */
283*0Sstevel@tonic-gate #define	MISC_COUNTER_TIMER_DEVNAME	"counter-timer"
284*0Sstevel@tonic-gate #define	MISC_PERF_COUNTER_DEVNAME	"perf-counter"
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate /* utility */
287*0Sstevel@tonic-gate #define	MBYTE	(1048576ull)
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate /*
290*0Sstevel@tonic-gate  * This is necessary because the CPU support needs
291*0Sstevel@tonic-gate  * to call cvc_assign_iocpu.
292*0Sstevel@tonic-gate  */
293*0Sstevel@tonic-gate #ifndef lint
294*0Sstevel@tonic-gate static char _depends_on[] = "drv/cvc";
295*0Sstevel@tonic-gate #endif  /* lint */
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate /*
298*0Sstevel@tonic-gate  * drmach autoconfiguration data structures and interfaces
299*0Sstevel@tonic-gate  */
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate extern struct mod_ops mod_miscops;
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate static struct modlmisc modlmisc = {
304*0Sstevel@tonic-gate 	&mod_miscops,
305*0Sstevel@tonic-gate 	"Sun Enterprise 10000 DR %I%"
306*0Sstevel@tonic-gate };
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
309*0Sstevel@tonic-gate 	MODREV_1,
310*0Sstevel@tonic-gate 	(void *)&modlmisc,
311*0Sstevel@tonic-gate 	NULL
312*0Sstevel@tonic-gate };
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate static kmutex_t drmach_i_lock;
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate int
317*0Sstevel@tonic-gate _init(void)
318*0Sstevel@tonic-gate {
319*0Sstevel@tonic-gate 	int err;
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	/* check that we have the correct version of obp */
322*0Sstevel@tonic-gate 	if (prom_test("SUNW,UE10000,add-brd") != 0) {
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "!OBP/SSP upgrade is required to enable "
325*0Sstevel@tonic-gate 		    "DR Functionality");
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 		return (-1);
328*0Sstevel@tonic-gate 	}
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	mutex_init(&drmach_i_lock, NULL, MUTEX_DRIVER, NULL);
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	drmach_xt_mb = (uchar_t *)vmem_alloc(static_alloc_arena,
333*0Sstevel@tonic-gate 	    NCPU * sizeof (uchar_t), VM_SLEEP);
334*0Sstevel@tonic-gate 	drmach_shutdown_asm_mbox = (struct drmach_shutdown_mbox *)
335*0Sstevel@tonic-gate 	    vmem_alloc(static_alloc_arena, sizeof (struct drmach_shutdown_mbox),
336*0Sstevel@tonic-gate 	    VM_SLEEP);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	if ((err = mod_install(&modlinkage)) != 0) {
339*0Sstevel@tonic-gate 		mutex_destroy(&drmach_i_lock);
340*0Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_xt_mb,
341*0Sstevel@tonic-gate 		    NCPU * sizeof (uchar_t));
342*0Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox,
343*0Sstevel@tonic-gate 		    sizeof (struct drmach_shutdown_mbox));
344*0Sstevel@tonic-gate 	}
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	return (err);
347*0Sstevel@tonic-gate }
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate int
350*0Sstevel@tonic-gate _fini(void)
351*0Sstevel@tonic-gate {
352*0Sstevel@tonic-gate 	static int drmach_fini(void);
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	if (drmach_fini())
355*0Sstevel@tonic-gate 		return (DDI_FAILURE);
356*0Sstevel@tonic-gate 	else
357*0Sstevel@tonic-gate 		return (mod_remove(&modlinkage));
358*0Sstevel@tonic-gate }
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate int
361*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
362*0Sstevel@tonic-gate {
363*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
364*0Sstevel@tonic-gate }
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate static dnode_t
367*0Sstevel@tonic-gate drmach_node_obp_get_dnode(drmach_node_t *np)
368*0Sstevel@tonic-gate {
369*0Sstevel@tonic-gate 	return ((dnode_t)np->here);
370*0Sstevel@tonic-gate }
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate static int
373*0Sstevel@tonic-gate drmach_node_obp_walk(drmach_node_t *np, void *data,
374*0Sstevel@tonic-gate 		int (*cb)(drmach_node_walk_args_t *args))
375*0Sstevel@tonic-gate {
376*0Sstevel@tonic-gate 	dnode_t			nodeid;
377*0Sstevel@tonic-gate 	int			rv;
378*0Sstevel@tonic-gate 	drmach_node_walk_args_t	args;
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	/* initialized args structure for callback */
381*0Sstevel@tonic-gate 	args.node = np;
382*0Sstevel@tonic-gate 	args.data = data;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	nodeid = prom_childnode(prom_rootnode());
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	/* save our new position with in the tree */
387*0Sstevel@tonic-gate 	np->here = (void *)nodeid;
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	rv = 0;
390*0Sstevel@tonic-gate 	while (nodeid != OBP_NONODE) {
391*0Sstevel@tonic-gate 		rv = (*cb)(&args);
392*0Sstevel@tonic-gate 		if (rv)
393*0Sstevel@tonic-gate 			break;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 		nodeid = prom_nextnode(nodeid);
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 		/* save our new position with in the tree */
398*0Sstevel@tonic-gate 		np->here = (void *)nodeid;
399*0Sstevel@tonic-gate 	}
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 	return (rv);
402*0Sstevel@tonic-gate }
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate static drmach_node_t *
405*0Sstevel@tonic-gate drmach_node_new(void)
406*0Sstevel@tonic-gate {
407*0Sstevel@tonic-gate 	drmach_node_t *np;
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP);
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	np->get_dnode = drmach_node_obp_get_dnode;
412*0Sstevel@tonic-gate 	np->walk = drmach_node_obp_walk;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	return (np);
415*0Sstevel@tonic-gate }
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate static void
418*0Sstevel@tonic-gate drmach_node_dispose(drmach_node_t *np)
419*0Sstevel@tonic-gate {
420*0Sstevel@tonic-gate 	kmem_free(np, sizeof (*np));
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate static dev_info_t *
424*0Sstevel@tonic-gate drmach_node_get_dip(drmach_node_t *np)
425*0Sstevel@tonic-gate {
426*0Sstevel@tonic-gate 	dnode_t nodeid;
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
429*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
430*0Sstevel@tonic-gate 		return (NULL);
431*0Sstevel@tonic-gate 	else {
432*0Sstevel@tonic-gate 		dev_info_t *dip;
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 		/* The root node doesn't have to be held */
435*0Sstevel@tonic-gate 		dip = e_ddi_nodeid_to_dip(nodeid);
436*0Sstevel@tonic-gate 		if (dip) {
437*0Sstevel@tonic-gate 			/*
438*0Sstevel@tonic-gate 			 * Branch rooted at dip is already held, so release
439*0Sstevel@tonic-gate 			 * hold acquired in e_ddi_nodeid_to_dip()
440*0Sstevel@tonic-gate 			 */
441*0Sstevel@tonic-gate 			ddi_release_devi(dip);
442*0Sstevel@tonic-gate 			ASSERT(e_ddi_branch_held(dip));
443*0Sstevel@tonic-gate 		}
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 		return (dip);
446*0Sstevel@tonic-gate 	}
447*0Sstevel@tonic-gate 	/*NOTREACHED*/
448*0Sstevel@tonic-gate }
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate static dnode_t
451*0Sstevel@tonic-gate drmach_node_get_dnode(drmach_node_t *np)
452*0Sstevel@tonic-gate {
453*0Sstevel@tonic-gate 	return (np->get_dnode(np));
454*0Sstevel@tonic-gate }
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate static int
457*0Sstevel@tonic-gate drmach_node_walk(drmach_node_t *np, void *param,
458*0Sstevel@tonic-gate 		int (*cb)(drmach_node_walk_args_t *args))
459*0Sstevel@tonic-gate {
460*0Sstevel@tonic-gate 	return (np->walk(np, param, cb));
461*0Sstevel@tonic-gate }
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate static int
464*0Sstevel@tonic-gate drmach_node_get_prop(drmach_node_t *np, char *name, void *buf)
465*0Sstevel@tonic-gate {
466*0Sstevel@tonic-gate 	dnode_t	nodeid;
467*0Sstevel@tonic-gate 	int	rv;
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
470*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
471*0Sstevel@tonic-gate 		rv = -1;
472*0Sstevel@tonic-gate 	else if (prom_getproplen(nodeid, (caddr_t)name) < 0)
473*0Sstevel@tonic-gate 		rv = -1;
474*0Sstevel@tonic-gate 	else {
475*0Sstevel@tonic-gate 		(void) prom_getprop(nodeid, (caddr_t)name, (caddr_t)buf);
476*0Sstevel@tonic-gate 		rv = 0;
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	return (rv);
480*0Sstevel@tonic-gate }
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate static int
483*0Sstevel@tonic-gate drmach_node_get_proplen(drmach_node_t *np, char *name, int *len)
484*0Sstevel@tonic-gate {
485*0Sstevel@tonic-gate 	dnode_t	 nodeid;
486*0Sstevel@tonic-gate 	int	 rv;
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
489*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
490*0Sstevel@tonic-gate 		rv = -1;
491*0Sstevel@tonic-gate 	else {
492*0Sstevel@tonic-gate 		*len = prom_getproplen(nodeid, (caddr_t)name);
493*0Sstevel@tonic-gate 		rv = (*len < 0 ? -1 : 0);
494*0Sstevel@tonic-gate 	}
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	return (rv);
497*0Sstevel@tonic-gate }
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate static drmachid_t
500*0Sstevel@tonic-gate drmach_node_dup(drmach_node_t *np)
501*0Sstevel@tonic-gate {
502*0Sstevel@tonic-gate 	drmach_node_t *dup;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	dup = drmach_node_new();
505*0Sstevel@tonic-gate 	dup->here = np->here;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	return (dup);
508*0Sstevel@tonic-gate }
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate /*
511*0Sstevel@tonic-gate  * drmach_array provides convenient array construction, access,
512*0Sstevel@tonic-gate  * bounds checking and array destruction logic.
513*0Sstevel@tonic-gate  */
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate static drmach_array_t *
516*0Sstevel@tonic-gate drmach_array_new(int min_index, int max_index)
517*0Sstevel@tonic-gate {
518*0Sstevel@tonic-gate 	drmach_array_t *arr;
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP);
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	arr->arr_sz = (max_index - min_index + 1) * sizeof (void *);
523*0Sstevel@tonic-gate 	if (arr->arr_sz > 0) {
524*0Sstevel@tonic-gate 		arr->min_index = min_index;
525*0Sstevel@tonic-gate 		arr->max_index = max_index;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 		arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP);
528*0Sstevel@tonic-gate 		return (arr);
529*0Sstevel@tonic-gate 	} else {
530*0Sstevel@tonic-gate 		kmem_free(arr, sizeof (*arr));
531*0Sstevel@tonic-gate 		return (0);
532*0Sstevel@tonic-gate 	}
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate static int
536*0Sstevel@tonic-gate drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val)
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	if (idx < arr->min_index || idx > arr->max_index)
539*0Sstevel@tonic-gate 		return (-1);
540*0Sstevel@tonic-gate 	else {
541*0Sstevel@tonic-gate 		arr->arr[idx - arr->min_index] = val;
542*0Sstevel@tonic-gate 		return (0);
543*0Sstevel@tonic-gate 	}
544*0Sstevel@tonic-gate 	/*NOTREACHED*/
545*0Sstevel@tonic-gate }
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate static int
548*0Sstevel@tonic-gate drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val)
549*0Sstevel@tonic-gate {
550*0Sstevel@tonic-gate 	if (idx < arr->min_index || idx > arr->max_index)
551*0Sstevel@tonic-gate 		return (-1);
552*0Sstevel@tonic-gate 	else {
553*0Sstevel@tonic-gate 		*val = arr->arr[idx - arr->min_index];
554*0Sstevel@tonic-gate 		return (0);
555*0Sstevel@tonic-gate 	}
556*0Sstevel@tonic-gate 	/*NOTREACHED*/
557*0Sstevel@tonic-gate }
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate static int
560*0Sstevel@tonic-gate drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val)
561*0Sstevel@tonic-gate {
562*0Sstevel@tonic-gate 	int rv;
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	*idx = arr->min_index;
565*0Sstevel@tonic-gate 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
566*0Sstevel@tonic-gate 		*idx += 1;
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	return (rv);
569*0Sstevel@tonic-gate }
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate static int
572*0Sstevel@tonic-gate drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val)
573*0Sstevel@tonic-gate {
574*0Sstevel@tonic-gate 	int rv;
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	*idx += 1;
577*0Sstevel@tonic-gate 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
578*0Sstevel@tonic-gate 		*idx += 1;
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	return (rv);
581*0Sstevel@tonic-gate }
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate static void
584*0Sstevel@tonic-gate drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t))
585*0Sstevel@tonic-gate {
586*0Sstevel@tonic-gate 	drmachid_t	val;
587*0Sstevel@tonic-gate 	int		idx;
588*0Sstevel@tonic-gate 	int		rv;
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	rv = drmach_array_first(arr, &idx, &val);
591*0Sstevel@tonic-gate 	while (rv == 0) {
592*0Sstevel@tonic-gate 		(*disposer)(val);
593*0Sstevel@tonic-gate 		rv = drmach_array_next(arr, &idx, &val);
594*0Sstevel@tonic-gate 	}
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	kmem_free(arr->arr, arr->arr_sz);
597*0Sstevel@tonic-gate 	kmem_free(arr, sizeof (*arr));
598*0Sstevel@tonic-gate }
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate /*ARGSUSED*/
601*0Sstevel@tonic-gate static int
602*0Sstevel@tonic-gate drmach_prom_select(dnode_t nodeid, void *arg, uint_t flags)
603*0Sstevel@tonic-gate {
604*0Sstevel@tonic-gate 	int			rprop[64];
605*0Sstevel@tonic-gate 	dnode_t			saved;
606*0Sstevel@tonic-gate 	drmach_config_args_t	*ap = (drmach_config_args_t *)arg;
607*0Sstevel@tonic-gate 	drmach_device_t		*dp = ap->dp;
608*0Sstevel@tonic-gate 	sbd_error_t		*err;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	saved = drmach_node_get_dnode(dp->node);
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	if (nodeid != saved)
613*0Sstevel@tonic-gate 		return (DDI_FAILURE);
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	if (saved == OBP_NONODE) {
616*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
617*0Sstevel@tonic-gate 		DRERR_SET_C(&ap->err, &err);
618*0Sstevel@tonic-gate 		return (DDI_FAILURE);
619*0Sstevel@tonic-gate 	}
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	if (prom_getprop(nodeid, OBP_REG, (caddr_t)rprop) <= 0) {
622*0Sstevel@tonic-gate 		return (DDI_FAILURE);
623*0Sstevel@tonic-gate 	}
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
626*0Sstevel@tonic-gate }
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate /*ARGSUSED*/
629*0Sstevel@tonic-gate static void
630*0Sstevel@tonic-gate drmach_branch_callback(dev_info_t *rdip, void *arg, uint_t flags)
631*0Sstevel@tonic-gate {
632*0Sstevel@tonic-gate 	drmach_config_args_t	*ap = (drmach_config_args_t *)arg;
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	ASSERT(ap->dip == NULL);
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	ap->dip = rdip;
637*0Sstevel@tonic-gate }
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate sbd_error_t *
640*0Sstevel@tonic-gate drmach_configure(drmachid_t id, int flags)
641*0Sstevel@tonic-gate {
642*0Sstevel@tonic-gate 	drmach_device_t		*dp;
643*0Sstevel@tonic-gate 	sbd_error_t		*err;
644*0Sstevel@tonic-gate 	drmach_config_args_t	ca;
645*0Sstevel@tonic-gate 	devi_branch_t		b = {0};
646*0Sstevel@tonic-gate 	dev_info_t		*fdip = NULL;
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
649*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
650*0Sstevel@tonic-gate 	dp = id;
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	ca.dp = dp;
653*0Sstevel@tonic-gate 	ca.flags = flags;
654*0Sstevel@tonic-gate 	ca.err = NULL;		/* will be set if error detected */
655*0Sstevel@tonic-gate 	ca.dip = NULL;
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	b.arg = &ca;
658*0Sstevel@tonic-gate 	b.type = DEVI_BRANCH_PROM;
659*0Sstevel@tonic-gate 	b.create.prom_branch_select = drmach_prom_select;
660*0Sstevel@tonic-gate 	b.devi_branch_callback = drmach_branch_callback;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	if (e_ddi_branch_create(ddi_root_node(), &b, &fdip,
663*0Sstevel@tonic-gate 	    DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE) != 0) {
664*0Sstevel@tonic-gate 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 		/*
667*0Sstevel@tonic-gate 		 * If non-NULL, fdip is returned held and must be released.
668*0Sstevel@tonic-gate 		 */
669*0Sstevel@tonic-gate 		if (fdip != NULL) {
670*0Sstevel@tonic-gate 			(void) ddi_pathname(fdip, path);
671*0Sstevel@tonic-gate 			ddi_release_devi(fdip);
672*0Sstevel@tonic-gate 		} else if (ca.dip != NULL) {
673*0Sstevel@tonic-gate 			/* safe to call ddi_pathname as dip already held */
674*0Sstevel@tonic-gate 			(void) ddi_pathname(ca.dip, path);
675*0Sstevel@tonic-gate 		} else {
676*0Sstevel@tonic-gate 			(void) strcpy(path, "<none>");
677*0Sstevel@tonic-gate 		}
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 		err = drerr_new(1, ESTF_DRVFAIL, path);
680*0Sstevel@tonic-gate 		DRERR_SET_C(&ca.err, &err);
681*0Sstevel@tonic-gate 		kmem_free(path, MAXPATHLEN);
682*0Sstevel@tonic-gate 	}
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 	return (ca.err);
685*0Sstevel@tonic-gate }
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate static sbd_error_t *
688*0Sstevel@tonic-gate drmach_device_new(drmach_node_t *node,
689*0Sstevel@tonic-gate 	drmach_board_t *bp, drmach_device_t **dpp)
690*0Sstevel@tonic-gate {
691*0Sstevel@tonic-gate 	int		 i;
692*0Sstevel@tonic-gate 	int		 rv;
693*0Sstevel@tonic-gate 	drmach_device_t	*dp;
694*0Sstevel@tonic-gate 	sbd_error_t	*err;
695*0Sstevel@tonic-gate 	char		 name[OBP_MAXDRVNAME];
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	rv = drmach_node_get_prop(node, OBP_NAME, name);
698*0Sstevel@tonic-gate 	if (rv) {
699*0Sstevel@tonic-gate 		/* every node is expected to have a name */
700*0Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROP,
701*0Sstevel@tonic-gate 			"PROM Node 0x%x: property %s",
702*0Sstevel@tonic-gate 			(uint_t)node->get_dnode(node), OBP_NAME);
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 		return (err);
705*0Sstevel@tonic-gate 	}
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	/*
708*0Sstevel@tonic-gate 	 * The node currently being examined is not listed in the name2type[]
709*0Sstevel@tonic-gate 	 * array.  In this case, the node is no interest to drmach.  Both
710*0Sstevel@tonic-gate 	 * dp and err are initialized here to yield nothing (no device or
711*0Sstevel@tonic-gate 	 * error structure) for this case.
712*0Sstevel@tonic-gate 	 */
713*0Sstevel@tonic-gate 	for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++)
714*0Sstevel@tonic-gate 		if (strcmp(name2type[i].name, name) == 0)
715*0Sstevel@tonic-gate 			break;
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	if (i < sizeof (name2type) / sizeof (name2type[0])) {
718*0Sstevel@tonic-gate 		dp = kmem_zalloc(sizeof (drmach_device_t), KM_SLEEP);
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 		dp->bp = bp;
721*0Sstevel@tonic-gate 		dp->unum = -1;
722*0Sstevel@tonic-gate 		dp->node = drmach_node_dup(node);
723*0Sstevel@tonic-gate 		dp->type = name2type[i].type;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		err = (name2type[i].new)(dp);
726*0Sstevel@tonic-gate 		if (err) {
727*0Sstevel@tonic-gate 			drmach_node_dispose(node);
728*0Sstevel@tonic-gate 			kmem_free(dp, sizeof (*dp));
729*0Sstevel@tonic-gate 			dp = NULL;
730*0Sstevel@tonic-gate 		}
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 		*dpp = dp;
733*0Sstevel@tonic-gate 		return (err);
734*0Sstevel@tonic-gate 	}
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	/*
737*0Sstevel@tonic-gate 	 * The node currently being examined is not listed in the name2type[]
738*0Sstevel@tonic-gate 	 * array.  In this case, the node is no interest to drmach.  Both
739*0Sstevel@tonic-gate 	 * dp and err are initialized here to yield nothing (no device or
740*0Sstevel@tonic-gate 	 * error structure) for this case.
741*0Sstevel@tonic-gate 	 */
742*0Sstevel@tonic-gate 	*dpp = NULL;
743*0Sstevel@tonic-gate 	return (NULL);
744*0Sstevel@tonic-gate }
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate static void
747*0Sstevel@tonic-gate drmach_device_dispose(drmachid_t id)
748*0Sstevel@tonic-gate {
749*0Sstevel@tonic-gate 	drmach_device_t *self = id;
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 	if (self->node)
752*0Sstevel@tonic-gate 		drmach_node_dispose(self->node);
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	kmem_free(self, sizeof (*self));
755*0Sstevel@tonic-gate }
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate static sbd_error_t *
758*0Sstevel@tonic-gate drmach_device_get_prop(drmach_device_t *dp, char *name, void *buf)
759*0Sstevel@tonic-gate {
760*0Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
761*0Sstevel@tonic-gate 	int		 rv;
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	rv = drmach_node_get_prop(dp->node, name, buf);
764*0Sstevel@tonic-gate 	if (rv) {
765*0Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROP,
766*0Sstevel@tonic-gate 			"%s::%s: property %s",
767*0Sstevel@tonic-gate 			dp->bp->cm.name, dp->cm.name, name);
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	return (err);
771*0Sstevel@tonic-gate }
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate static sbd_error_t *
774*0Sstevel@tonic-gate drmach_device_get_proplen(drmach_device_t *dp, char *name, int *len)
775*0Sstevel@tonic-gate {
776*0Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
777*0Sstevel@tonic-gate 	int		 rv;
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 	rv = drmach_node_get_proplen(dp->node, name, len);
780*0Sstevel@tonic-gate 	if (rv) {
781*0Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROPLEN,
782*0Sstevel@tonic-gate 			"%s::%s: property %s",
783*0Sstevel@tonic-gate 			dp->bp->cm.name, dp->cm.name, name);
784*0Sstevel@tonic-gate 	}
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	return (err);
787*0Sstevel@tonic-gate }
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate static drmach_board_t *
790*0Sstevel@tonic-gate drmach_board_new(int bnum)
791*0Sstevel@tonic-gate {
792*0Sstevel@tonic-gate 	static sbd_error_t *drmach_board_release(drmachid_t);
793*0Sstevel@tonic-gate 	static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *);
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate 	drmach_board_t	*bp;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP);
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 	bp->cm.isa = (void *)drmach_board_new;
800*0Sstevel@tonic-gate 	bp->cm.release = drmach_board_release;
801*0Sstevel@tonic-gate 	bp->cm.status = drmach_board_status;
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	(void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name));
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate 	bp->bnum = bnum;
806*0Sstevel@tonic-gate 	bp->devices = NULL;
807*0Sstevel@tonic-gate 	bp->connect_cpuid = -1;
808*0Sstevel@tonic-gate 	bp->tree = drmach_node_new();
809*0Sstevel@tonic-gate 	bp->assigned = !drmach_initialized;
810*0Sstevel@tonic-gate 	bp->powered = !drmach_initialized;
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	drmach_array_set(drmach_boards, bnum, bp);
813*0Sstevel@tonic-gate 	return (bp);
814*0Sstevel@tonic-gate }
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate static void
817*0Sstevel@tonic-gate drmach_board_dispose(drmachid_t id)
818*0Sstevel@tonic-gate {
819*0Sstevel@tonic-gate 	drmach_board_t *bp;
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	ASSERT(DRMACH_IS_BOARD_ID(id));
822*0Sstevel@tonic-gate 	bp = id;
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	if (bp->tree)
825*0Sstevel@tonic-gate 		drmach_node_dispose(bp->tree);
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 	if (bp->devices)
828*0Sstevel@tonic-gate 		drmach_array_dispose(bp->devices, drmach_device_dispose);
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 	kmem_free(bp, sizeof (*bp));
831*0Sstevel@tonic-gate }
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate static sbd_error_t *
834*0Sstevel@tonic-gate drmach_board_status(drmachid_t id, drmach_status_t *stat)
835*0Sstevel@tonic-gate {
836*0Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
837*0Sstevel@tonic-gate 	drmach_board_t	*bp;
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
840*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
841*0Sstevel@tonic-gate 	bp = id;
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 	stat->assigned = bp->assigned;
844*0Sstevel@tonic-gate 	stat->powered = bp->powered;
845*0Sstevel@tonic-gate 	stat->busy = 0;			/* assume not busy */
846*0Sstevel@tonic-gate 	stat->configured = 0;		/* assume not configured */
847*0Sstevel@tonic-gate 	stat->empty = 0;
848*0Sstevel@tonic-gate 	stat->cond = bp->cond = SBD_COND_OK;
849*0Sstevel@tonic-gate 	strncpy(stat->type, "System Brd", sizeof (stat->type));
850*0Sstevel@tonic-gate 	stat->info[0] = '\0';
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate 	if (bp->devices) {
853*0Sstevel@tonic-gate 		int		 rv;
854*0Sstevel@tonic-gate 		int		 d_idx;
855*0Sstevel@tonic-gate 		drmachid_t	 d_id;
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
858*0Sstevel@tonic-gate 		while (rv == 0) {
859*0Sstevel@tonic-gate 			drmach_status_t	d_stat;
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 			err = drmach_status(d_id, &d_stat);
862*0Sstevel@tonic-gate 			if (err)
863*0Sstevel@tonic-gate 				break;
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 			stat->busy |= d_stat.busy;
866*0Sstevel@tonic-gate 			stat->configured |= d_stat.configured;
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
869*0Sstevel@tonic-gate 		}
870*0Sstevel@tonic-gate 	}
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	return (err);
873*0Sstevel@tonic-gate }
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate /* a simple routine to reduce redundancy of this common logic */
876*0Sstevel@tonic-gate static pda_handle_t
877*0Sstevel@tonic-gate drmach_pda_open(void)
878*0Sstevel@tonic-gate {
879*0Sstevel@tonic-gate 	pda_handle_t ph;
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	ph = pda_open();
882*0Sstevel@tonic-gate 	if (ph == NULL) {
883*0Sstevel@tonic-gate 		/* catch in debug kernels */
884*0Sstevel@tonic-gate 		ASSERT(0);
885*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "pda_open failed");
886*0Sstevel@tonic-gate 	}
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 	return (ph);
889*0Sstevel@tonic-gate }
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate #ifdef DEBUG
892*0Sstevel@tonic-gate int drmach_init_break = 0;
893*0Sstevel@tonic-gate #endif
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate static int
896*0Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg)
897*0Sstevel@tonic-gate {
898*0Sstevel@tonic-gate 	int	i;
899*0Sstevel@tonic-gate 	int	*holdp = (int *)arg;
900*0Sstevel@tonic-gate 	char	*name = ddi_node_name(rdip);
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	/*
903*0Sstevel@tonic-gate 	 * For Starfire, we must be children of the root devinfo node
904*0Sstevel@tonic-gate 	 */
905*0Sstevel@tonic-gate 	ASSERT(ddi_get_parent(rdip) == ddi_root_node());
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++)
908*0Sstevel@tonic-gate 		if (strcmp(name2type[i].name, name) == 0)
909*0Sstevel@tonic-gate 			break;
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 	if (i == sizeof (name2type) / sizeof (name2type[0])) {
912*0Sstevel@tonic-gate 		/* Not of interest to us */
913*0Sstevel@tonic-gate 		return (DDI_WALK_PRUNECHILD);
914*0Sstevel@tonic-gate 	}
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate 	if (*holdp) {
917*0Sstevel@tonic-gate 		ASSERT(!e_ddi_branch_held(rdip));
918*0Sstevel@tonic-gate 		e_ddi_branch_hold(rdip);
919*0Sstevel@tonic-gate 	} else {
920*0Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(rdip));
921*0Sstevel@tonic-gate 		e_ddi_branch_rele(rdip);
922*0Sstevel@tonic-gate 	}
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	return (DDI_WALK_PRUNECHILD);
925*0Sstevel@tonic-gate }
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate static int
928*0Sstevel@tonic-gate drmach_init(void)
929*0Sstevel@tonic-gate {
930*0Sstevel@tonic-gate 	dnode_t		nodeid;
931*0Sstevel@tonic-gate 	dev_info_t	*rdip;
932*0Sstevel@tonic-gate 	int		hold, circ;
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate #ifdef DEBUG
935*0Sstevel@tonic-gate 	if (drmach_init_break)
936*0Sstevel@tonic-gate 		debug_enter("drmach_init: drmach_init_break set\n");
937*0Sstevel@tonic-gate #endif
938*0Sstevel@tonic-gate 	mutex_enter(&drmach_i_lock);
939*0Sstevel@tonic-gate 	if (drmach_initialized) {
940*0Sstevel@tonic-gate 		mutex_exit(&drmach_i_lock);
941*0Sstevel@tonic-gate 		return (0);
942*0Sstevel@tonic-gate 	}
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	drmach_boards = drmach_array_new(0, MAX_BOARDS - 1);
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 	nodeid = prom_childnode(prom_rootnode());
947*0Sstevel@tonic-gate 	do {
948*0Sstevel@tonic-gate 		int		 bnum;
949*0Sstevel@tonic-gate 		drmachid_t	 id;
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 		bnum = -1;
952*0Sstevel@tonic-gate 		(void) prom_getprop(nodeid, OBP_BOARDNUM, (caddr_t)&bnum);
953*0Sstevel@tonic-gate 		if (bnum == -1)
954*0Sstevel@tonic-gate 			continue;
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 		if (drmach_array_get(drmach_boards, bnum, &id) == -1) {
957*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "OBP node 0x%x has"
958*0Sstevel@tonic-gate 				" invalid property value, %s=%d",
959*0Sstevel@tonic-gate 				nodeid, OBP_BOARDNUM, bnum);
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 			/* clean up */
962*0Sstevel@tonic-gate 			drmach_array_dispose(
963*0Sstevel@tonic-gate 				drmach_boards, drmach_board_dispose);
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 			mutex_exit(&drmach_i_lock);
966*0Sstevel@tonic-gate 			return (-1);
967*0Sstevel@tonic-gate 		} else if (id == NULL)
968*0Sstevel@tonic-gate 			(void) drmach_board_new(bnum);
969*0Sstevel@tonic-gate 	} while ((nodeid = prom_nextnode(nodeid)) != OBP_NONODE);
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	drmach_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	/*
974*0Sstevel@tonic-gate 	 * Walk immediate children of devinfo root node and hold
975*0Sstevel@tonic-gate 	 * all devinfo branches of interest.
976*0Sstevel@tonic-gate 	 */
977*0Sstevel@tonic-gate 	hold = 1;
978*0Sstevel@tonic-gate 	rdip = ddi_root_node();
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 	ndi_devi_enter(rdip, &circ);
981*0Sstevel@tonic-gate 	ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold);
982*0Sstevel@tonic-gate 	ndi_devi_exit(rdip, circ);
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	drmach_initialized = 1;
985*0Sstevel@tonic-gate 
986*0Sstevel@tonic-gate 	mutex_exit(&drmach_i_lock);
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 	return (0);
989*0Sstevel@tonic-gate }
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate static int
992*0Sstevel@tonic-gate drmach_fini(void)
993*0Sstevel@tonic-gate {
994*0Sstevel@tonic-gate 	dev_info_t	*rdip;
995*0Sstevel@tonic-gate 	int		hold, circ;
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 	if (drmach_initialized) {
998*0Sstevel@tonic-gate 		int		busy = 0;
999*0Sstevel@tonic-gate 		int		rv;
1000*0Sstevel@tonic-gate 		int		idx;
1001*0Sstevel@tonic-gate 		drmachid_t	id;
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 		ASSERT(drmach_boards != NULL);
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 		rv = drmach_array_first(drmach_boards, &idx, &id);
1006*0Sstevel@tonic-gate 		while (rv == 0) {
1007*0Sstevel@tonic-gate 			sbd_error_t	*err;
1008*0Sstevel@tonic-gate 			drmach_status_t stat;
1009*0Sstevel@tonic-gate 
1010*0Sstevel@tonic-gate 			err = drmach_board_status(id, &stat);
1011*0Sstevel@tonic-gate 			if (err) {
1012*0Sstevel@tonic-gate 				/* catch in debug kernels */
1013*0Sstevel@tonic-gate 				ASSERT(0);
1014*0Sstevel@tonic-gate 				sbd_err_clear(&err);
1015*0Sstevel@tonic-gate 				busy = 1;
1016*0Sstevel@tonic-gate 			} else
1017*0Sstevel@tonic-gate 				busy |= stat.busy;
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate 			rv = drmach_array_next(drmach_boards, &idx, &id);
1020*0Sstevel@tonic-gate 		}
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate 		if (busy)
1023*0Sstevel@tonic-gate 			return (-1);
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate 		drmach_array_dispose(drmach_boards, drmach_board_dispose);
1026*0Sstevel@tonic-gate 		drmach_boards = NULL;
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 		vmem_free(heap_arena, drmach_shutdown_va, PAGESIZE);
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 		/*
1031*0Sstevel@tonic-gate 		 * Walk immediate children of the root devinfo node
1032*0Sstevel@tonic-gate 		 * releasing holds acquired on branches in drmach_init()
1033*0Sstevel@tonic-gate 		 */
1034*0Sstevel@tonic-gate 		hold = 0;
1035*0Sstevel@tonic-gate 		rdip = ddi_root_node();
1036*0Sstevel@tonic-gate 
1037*0Sstevel@tonic-gate 		ndi_devi_enter(rdip, &circ);
1038*0Sstevel@tonic-gate 		ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold);
1039*0Sstevel@tonic-gate 		ndi_devi_exit(rdip, circ);
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 		mutex_destroy(&drmach_i_lock);
1042*0Sstevel@tonic-gate 
1043*0Sstevel@tonic-gate 		drmach_initialized = 0;
1044*0Sstevel@tonic-gate 	}
1045*0Sstevel@tonic-gate 	if (drmach_xt_mb != NULL) {
1046*0Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_xt_mb,
1047*0Sstevel@tonic-gate 		    NCPU * sizeof (uchar_t));
1048*0Sstevel@tonic-gate 	}
1049*0Sstevel@tonic-gate 	if (drmach_shutdown_asm_mbox != NULL) {
1050*0Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox,
1051*0Sstevel@tonic-gate 		    sizeof (struct drmach_shutdown_mbox));
1052*0Sstevel@tonic-gate 	}
1053*0Sstevel@tonic-gate 	return (0);
1054*0Sstevel@tonic-gate }
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate static sbd_error_t *
1057*0Sstevel@tonic-gate drmach_get_mc_asr_addr(drmachid_t id, uint64_t *pa)
1058*0Sstevel@tonic-gate {
1059*0Sstevel@tonic-gate 	drmach_device_t	*dp;
1060*0Sstevel@tonic-gate 	dnode_t		nodeid;
1061*0Sstevel@tonic-gate 	uint64_t	addr;
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
1064*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
1065*0Sstevel@tonic-gate 	dp = id;
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
1068*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
1069*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 	addr = mc_get_asr_addr(nodeid);
1072*0Sstevel@tonic-gate 	if (addr == (uint64_t)-1)
1073*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	*pa = addr;
1076*0Sstevel@tonic-gate 	return (NULL);
1077*0Sstevel@tonic-gate }
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate static sbd_error_t *
1080*0Sstevel@tonic-gate drmach_get_mc_idle_addr(drmachid_t id, uint64_t *pa)
1081*0Sstevel@tonic-gate {
1082*0Sstevel@tonic-gate 	drmach_device_t	*dp;
1083*0Sstevel@tonic-gate 	dnode_t		nodeid;
1084*0Sstevel@tonic-gate 	uint64_t	addr;
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
1087*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
1088*0Sstevel@tonic-gate 	dp = id;
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
1091*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
1092*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate 	addr = mc_get_idle_addr(nodeid);
1095*0Sstevel@tonic-gate 	if (addr == (uint64_t)-1)
1096*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	*pa = addr;
1099*0Sstevel@tonic-gate 	return (NULL);
1100*0Sstevel@tonic-gate }
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate static sbd_error_t *
1103*0Sstevel@tonic-gate drmach_read_mc_asr(drmachid_t id, uint_t *mcregp)
1104*0Sstevel@tonic-gate {
1105*0Sstevel@tonic-gate 	drmach_device_t	*dp;
1106*0Sstevel@tonic-gate 	dnode_t		 nodeid;
1107*0Sstevel@tonic-gate 	sbd_error_t	*err;
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
1110*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
1111*0Sstevel@tonic-gate 	dp = id;
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
1114*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
1115*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
1116*0Sstevel@tonic-gate 	else if (mc_read_asr(nodeid, mcregp) == -1)
1117*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
1118*0Sstevel@tonic-gate 	else
1119*0Sstevel@tonic-gate 		err = NULL;
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate 	return (err);
1122*0Sstevel@tonic-gate }
1123*0Sstevel@tonic-gate 
1124*0Sstevel@tonic-gate static sbd_error_t *
1125*0Sstevel@tonic-gate drmach_write_mc_asr(drmachid_t id, uint_t mcreg)
1126*0Sstevel@tonic-gate {
1127*0Sstevel@tonic-gate 	drmach_device_t	*dp;
1128*0Sstevel@tonic-gate 	dnode_t		 nodeid;
1129*0Sstevel@tonic-gate 	sbd_error_t	*err;
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
1132*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
1133*0Sstevel@tonic-gate 	dp = id;
1134*0Sstevel@tonic-gate 
1135*0Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
1136*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
1137*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
1138*0Sstevel@tonic-gate 	else if (mc_write_asr(nodeid, mcreg) == -1)
1139*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
1140*0Sstevel@tonic-gate 	else
1141*0Sstevel@tonic-gate 		err = NULL;
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate 	return (err);
1144*0Sstevel@tonic-gate }
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate static struct memlist *
1147*0Sstevel@tonic-gate memlist_add_span(struct memlist *mlist, uint64_t base, uint64_t len)
1148*0Sstevel@tonic-gate {
1149*0Sstevel@tonic-gate 	struct memlist	*ml, *tl, *nl;
1150*0Sstevel@tonic-gate 
1151*0Sstevel@tonic-gate 	if (len == 0ull)
1152*0Sstevel@tonic-gate 		return (NULL);
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate 	if (mlist == NULL) {
1155*0Sstevel@tonic-gate 		mlist = GETSTRUCT(struct memlist, 1);
1156*0Sstevel@tonic-gate 		mlist->address = base;
1157*0Sstevel@tonic-gate 		mlist->size = len;
1158*0Sstevel@tonic-gate 		mlist->next = mlist->prev = NULL;
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate 		return (mlist);
1161*0Sstevel@tonic-gate 	}
1162*0Sstevel@tonic-gate 
1163*0Sstevel@tonic-gate 	for (tl = ml = mlist; ml; tl = ml, ml = ml->next) {
1164*0Sstevel@tonic-gate 		if (base < ml->address) {
1165*0Sstevel@tonic-gate 			if ((base + len) < ml->address) {
1166*0Sstevel@tonic-gate 				nl = GETSTRUCT(struct memlist, 1);
1167*0Sstevel@tonic-gate 				nl->address = base;
1168*0Sstevel@tonic-gate 				nl->size = len;
1169*0Sstevel@tonic-gate 				nl->next = ml;
1170*0Sstevel@tonic-gate 				if ((nl->prev = ml->prev) != NULL)
1171*0Sstevel@tonic-gate 					nl->prev->next = nl;
1172*0Sstevel@tonic-gate 				ml->prev = nl;
1173*0Sstevel@tonic-gate 				if (mlist == ml)
1174*0Sstevel@tonic-gate 					mlist = nl;
1175*0Sstevel@tonic-gate 			} else {
1176*0Sstevel@tonic-gate 				ml->size = MAX((base + len),
1177*0Sstevel@tonic-gate 						(ml->address + ml->size)) -
1178*0Sstevel@tonic-gate 						base;
1179*0Sstevel@tonic-gate 				ml->address = base;
1180*0Sstevel@tonic-gate 			}
1181*0Sstevel@tonic-gate 			break;
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 		} else if (base <= (ml->address + ml->size)) {
1184*0Sstevel@tonic-gate 			ml->size = MAX((base + len),
1185*0Sstevel@tonic-gate 					(ml->address + ml->size)) -
1186*0Sstevel@tonic-gate 					MIN(ml->address, base);
1187*0Sstevel@tonic-gate 			ml->address = MIN(ml->address, base);
1188*0Sstevel@tonic-gate 			break;
1189*0Sstevel@tonic-gate 		}
1190*0Sstevel@tonic-gate 	}
1191*0Sstevel@tonic-gate 	if (ml == NULL) {
1192*0Sstevel@tonic-gate 		nl = GETSTRUCT(struct memlist, 1);
1193*0Sstevel@tonic-gate 		nl->address = base;
1194*0Sstevel@tonic-gate 		nl->size = len;
1195*0Sstevel@tonic-gate 		nl->next = NULL;
1196*0Sstevel@tonic-gate 		nl->prev = tl;
1197*0Sstevel@tonic-gate 		tl->next = nl;
1198*0Sstevel@tonic-gate 	}
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate 	memlist_coalesce(mlist);
1201*0Sstevel@tonic-gate 
1202*0Sstevel@tonic-gate 	return (mlist);
1203*0Sstevel@tonic-gate }
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate static sbd_error_t *
1206*0Sstevel@tonic-gate drmach_prep_rename_script(drmach_device_t *s_mem, drmach_device_t *t_mem,
1207*0Sstevel@tonic-gate 	uint64_t t_slice_offset, caddr_t buf, int buflen)
1208*0Sstevel@tonic-gate {
1209*0Sstevel@tonic-gate 	int			i, b, m;
1210*0Sstevel@tonic-gate 	drmach_mc_idle_script_t	*isp;
1211*0Sstevel@tonic-gate 	drmach_rename_script_t	*rsp;
1212*0Sstevel@tonic-gate 	int			s_bd, t_bd;
1213*0Sstevel@tonic-gate 	uint_t			s_masr, t_masr;
1214*0Sstevel@tonic-gate 	uint64_t		s_new_basepa, t_new_basepa;
1215*0Sstevel@tonic-gate 	int			b_idx, rv;
1216*0Sstevel@tonic-gate 	sbd_error_t		*err;
1217*0Sstevel@tonic-gate 	drmachid_t		 b_id;
1218*0Sstevel@tonic-gate 	drmach_board_t		*brd;
1219*0Sstevel@tonic-gate 
1220*0Sstevel@tonic-gate #ifdef DEBUG
1221*0Sstevel@tonic-gate 	/*
1222*0Sstevel@tonic-gate 	 * Starfire CPU/MEM/IO boards have only one MC per board.
1223*0Sstevel@tonic-gate 	 * This function has been coded with that fact in mind.
1224*0Sstevel@tonic-gate 	 */
1225*0Sstevel@tonic-gate 	ASSERT(MAX_MEM_UNITS_PER_BOARD == 1);
1226*0Sstevel@tonic-gate 
1227*0Sstevel@tonic-gate 	/*
1228*0Sstevel@tonic-gate 	 * calculate the maximum space that could be consumed,
1229*0Sstevel@tonic-gate 	 * then verify the available buffer space is adequate.
1230*0Sstevel@tonic-gate 	 */
1231*0Sstevel@tonic-gate 	m  = sizeof (drmach_mc_idle_script_t *) * 2; /* two MCs */
1232*0Sstevel@tonic-gate 	b  = sizeof (drmach_rename_script_t *) * 3 * MAX_CPU_UNITS_PER_BOARD;
1233*0Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 3 * MAX_IO_UNITS_PER_BOARD;
1234*0Sstevel@tonic-gate 	b *= MAX_BOARDS;
1235*0Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 3;
1236*0Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 1;
1237*0Sstevel@tonic-gate 	ASSERT(m + b < buflen);
1238*0Sstevel@tonic-gate #endif
1239*0Sstevel@tonic-gate 
1240*0Sstevel@tonic-gate 	/*
1241*0Sstevel@tonic-gate 	 * construct an array of MC idle register addresses of
1242*0Sstevel@tonic-gate 	 * both MCs.  The array is zero terminated -- as expected
1243*0Sstevel@tonic-gate 	 * by drmach_copy_rename_prog__relocatable().
1244*0Sstevel@tonic-gate 	 */
1245*0Sstevel@tonic-gate 	isp = (drmach_mc_idle_script_t *)buf;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 	/* source mc */
1248*0Sstevel@tonic-gate 	err = drmach_get_mc_idle_addr(s_mem, &isp->idle_addr);
1249*0Sstevel@tonic-gate 	if (err)
1250*0Sstevel@tonic-gate 		return (err);
1251*0Sstevel@tonic-gate 	isp->mem = s_mem;
1252*0Sstevel@tonic-gate 	isp += 1;
1253*0Sstevel@tonic-gate 
1254*0Sstevel@tonic-gate 	/* target mc */
1255*0Sstevel@tonic-gate 	err = drmach_get_mc_idle_addr(t_mem, &isp->idle_addr);
1256*0Sstevel@tonic-gate 	if (err)
1257*0Sstevel@tonic-gate 		return (err);
1258*0Sstevel@tonic-gate 	isp->mem = t_mem;
1259*0Sstevel@tonic-gate 	isp += 1;
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate 	/* terminator */
1262*0Sstevel@tonic-gate 	isp->idle_addr = 0;
1263*0Sstevel@tonic-gate 	isp->mem = NULL;
1264*0Sstevel@tonic-gate 	isp += 1;
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate 	/* fetch source mc asr register value */
1267*0Sstevel@tonic-gate 	err = drmach_read_mc_asr(s_mem, &s_masr);
1268*0Sstevel@tonic-gate 	if (err)
1269*0Sstevel@tonic-gate 		return (err);
1270*0Sstevel@tonic-gate 	else if (s_masr & STARFIRE_MC_INTERLEAVE_MASK) {
1271*0Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
1272*0Sstevel@tonic-gate 				s_mem->bp->cm.name, s_mem->cm.name));
1273*0Sstevel@tonic-gate 	}
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate 	/* fetch target mc asr register value */
1276*0Sstevel@tonic-gate 	err = drmach_read_mc_asr(t_mem, &t_masr);
1277*0Sstevel@tonic-gate 	if (err)
1278*0Sstevel@tonic-gate 		return (err);
1279*0Sstevel@tonic-gate 	else if (t_masr & STARFIRE_MC_INTERLEAVE_MASK) {
1280*0Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
1281*0Sstevel@tonic-gate 				t_mem->bp->cm.name, t_mem->cm.name));
1282*0Sstevel@tonic-gate 	}
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 	/* get new source base pa from target's masr */
1285*0Sstevel@tonic-gate 	s_new_basepa = mc_asr_to_pa(t_masr);
1286*0Sstevel@tonic-gate 
1287*0Sstevel@tonic-gate 	/*
1288*0Sstevel@tonic-gate 	 * remove any existing slice offset to realign
1289*0Sstevel@tonic-gate 	 * memory with board's slice boundary
1290*0Sstevel@tonic-gate 	 */
1291*0Sstevel@tonic-gate 	s_new_basepa &= ~ (mc_get_mem_alignment() - 1);
1292*0Sstevel@tonic-gate 
1293*0Sstevel@tonic-gate 	/* get new target base pa from source's masr */
1294*0Sstevel@tonic-gate 	t_new_basepa  = mc_asr_to_pa(s_masr);
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 	/* remove any existing slice offset, then apply new offset */
1297*0Sstevel@tonic-gate 	t_new_basepa &= ~ (mc_get_mem_alignment() - 1);
1298*0Sstevel@tonic-gate 	t_new_basepa += t_slice_offset;
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate 	/* encode new base pa into s_masr.  turn off mem present bit */
1301*0Sstevel@tonic-gate 	s_masr  = mc_pa_to_asr(s_masr, s_new_basepa);
1302*0Sstevel@tonic-gate 	s_masr &= ~STARFIRE_MC_MEM_PRESENT_MASK;
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate 	/* encode new base pa into t_masr.  turn on mem present bit */
1305*0Sstevel@tonic-gate 	t_masr  = mc_pa_to_asr(t_masr, t_new_basepa);
1306*0Sstevel@tonic-gate 	t_masr |= STARFIRE_MC_MEM_PRESENT_MASK;
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate 	/*
1309*0Sstevel@tonic-gate 	 * Step 0:	Mark source memory as not present.
1310*0Sstevel@tonic-gate 	 */
1311*0Sstevel@tonic-gate 	m = 0;
1312*0Sstevel@tonic-gate 	rsp = (drmach_rename_script_t *)isp;
1313*0Sstevel@tonic-gate 	err = drmach_get_mc_asr_addr(s_mem, &rsp[m].masr_addr);
1314*0Sstevel@tonic-gate 	if (err)
1315*0Sstevel@tonic-gate 		return (err);
1316*0Sstevel@tonic-gate 	rsp[m].masr = s_masr;
1317*0Sstevel@tonic-gate 	m++;
1318*0Sstevel@tonic-gate 
1319*0Sstevel@tonic-gate 	/*
1320*0Sstevel@tonic-gate 	 * Step 1:	Write source base address to target MC
1321*0Sstevel@tonic-gate 	 *		with present bit off.
1322*0Sstevel@tonic-gate 	 */
1323*0Sstevel@tonic-gate 	err = drmach_get_mc_asr_addr(t_mem, &rsp[m].masr_addr);
1324*0Sstevel@tonic-gate 	if (err)
1325*0Sstevel@tonic-gate 		return (err);
1326*0Sstevel@tonic-gate 	rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
1327*0Sstevel@tonic-gate 	m++;
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 	/*
1330*0Sstevel@tonic-gate 	 * Step 2:	Now rewrite target reg with present bit on.
1331*0Sstevel@tonic-gate 	 */
1332*0Sstevel@tonic-gate 	rsp[m].masr_addr = rsp[m-1].masr_addr;
1333*0Sstevel@tonic-gate 	rsp[m].masr = t_masr;
1334*0Sstevel@tonic-gate 	m++;
1335*0Sstevel@tonic-gate 
1336*0Sstevel@tonic-gate 	s_bd = s_mem->bp->bnum;
1337*0Sstevel@tonic-gate 	t_bd = t_mem->bp->bnum;
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 	DRMACH_PR("preparing script for CPU and IO units:\n");
1340*0Sstevel@tonic-gate 
1341*0Sstevel@tonic-gate 	rv = drmach_array_first(drmach_boards, &b_idx, &b_id);
1342*0Sstevel@tonic-gate 	if (rv) {
1343*0Sstevel@tonic-gate 		/* catch this in debug kernels */
1344*0Sstevel@tonic-gate 		ASSERT(0);
1345*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
1346*0Sstevel@tonic-gate 	}
1347*0Sstevel@tonic-gate 
1348*0Sstevel@tonic-gate 	do {
1349*0Sstevel@tonic-gate 		int			 d_idx;
1350*0Sstevel@tonic-gate 		drmachid_t		 d_id;
1351*0Sstevel@tonic-gate 		drmach_device_t		*device;
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate 		ASSERT(DRMACH_IS_BOARD_ID(b_id));
1354*0Sstevel@tonic-gate 		brd = b_id;
1355*0Sstevel@tonic-gate 		b = brd->bnum;
1356*0Sstevel@tonic-gate 
1357*0Sstevel@tonic-gate 		/*
1358*0Sstevel@tonic-gate 		 * Step 3:	Update PC MADR tables for CPUs.
1359*0Sstevel@tonic-gate 		 */
1360*0Sstevel@tonic-gate 		rv = drmach_array_first(brd->devices, &d_idx, &d_id);
1361*0Sstevel@tonic-gate 		if (rv) {
1362*0Sstevel@tonic-gate 			/* must mean no devices on this board */
1363*0Sstevel@tonic-gate 			break;
1364*0Sstevel@tonic-gate 		}
1365*0Sstevel@tonic-gate 
1366*0Sstevel@tonic-gate 		DRMACH_PR("\t%s\n", brd->cm.name);
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate 		do {
1369*0Sstevel@tonic-gate 			ASSERT(DRMACH_IS_DEVICE_ID(d_id));
1370*0Sstevel@tonic-gate 
1371*0Sstevel@tonic-gate 			if (!DRMACH_IS_CPU_ID(d_id))
1372*0Sstevel@tonic-gate 				continue;
1373*0Sstevel@tonic-gate 
1374*0Sstevel@tonic-gate 			device = d_id;
1375*0Sstevel@tonic-gate 			i = device->unum;
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate 			DRMACH_PR("\t\t%s\n", device->cm.name);
1378*0Sstevel@tonic-gate 
1379*0Sstevel@tonic-gate 			/*
1380*0Sstevel@tonic-gate 			 * Disabled detaching mem node.
1381*0Sstevel@tonic-gate 			 */
1382*0Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i);
1383*0Sstevel@tonic-gate 			rsp[m].masr = s_masr;
1384*0Sstevel@tonic-gate 			m++;
1385*0Sstevel@tonic-gate 			/*
1386*0Sstevel@tonic-gate 			 * Always write masr with present bit
1387*0Sstevel@tonic-gate 			 * off and then again with it on.
1388*0Sstevel@tonic-gate 			 */
1389*0Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i);
1390*0Sstevel@tonic-gate 			rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
1391*0Sstevel@tonic-gate 			m++;
1392*0Sstevel@tonic-gate 			rsp[m].masr_addr = rsp[m-1].masr_addr;
1393*0Sstevel@tonic-gate 			rsp[m].masr = t_masr;
1394*0Sstevel@tonic-gate 			m++;
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate 		} while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0);
1397*0Sstevel@tonic-gate 
1398*0Sstevel@tonic-gate 		/*
1399*0Sstevel@tonic-gate 		 * Step 4:	Update PC MADR tables for IOs.
1400*0Sstevel@tonic-gate 		 */
1401*0Sstevel@tonic-gate 		rv = drmach_array_first(brd->devices, &d_idx, &d_id);
1402*0Sstevel@tonic-gate 		/* this worked for previous loop, must work here too */
1403*0Sstevel@tonic-gate 		ASSERT(rv == 0);
1404*0Sstevel@tonic-gate 
1405*0Sstevel@tonic-gate 		do {
1406*0Sstevel@tonic-gate 			ASSERT(DRMACH_IS_DEVICE_ID(d_id));
1407*0Sstevel@tonic-gate 
1408*0Sstevel@tonic-gate 			if (!DRMACH_IS_IO_ID(d_id))
1409*0Sstevel@tonic-gate 				continue;
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 			device = d_id;
1412*0Sstevel@tonic-gate 			i = device->unum;
1413*0Sstevel@tonic-gate 
1414*0Sstevel@tonic-gate 			DRMACH_PR("\t\t%s\n", device->cm.name);
1415*0Sstevel@tonic-gate 
1416*0Sstevel@tonic-gate 			/*
1417*0Sstevel@tonic-gate 			 * Disabled detaching mem node.
1418*0Sstevel@tonic-gate 			 */
1419*0Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i+4);
1420*0Sstevel@tonic-gate 			rsp[m].masr = s_masr;
1421*0Sstevel@tonic-gate 			m++;
1422*0Sstevel@tonic-gate 			/*
1423*0Sstevel@tonic-gate 			 * Always write masr with present bit
1424*0Sstevel@tonic-gate 			 * off and then again with it on.
1425*0Sstevel@tonic-gate 			 */
1426*0Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i+4);
1427*0Sstevel@tonic-gate 			rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
1428*0Sstevel@tonic-gate 			m++;
1429*0Sstevel@tonic-gate 			rsp[m].masr_addr = rsp[m-1].masr_addr;
1430*0Sstevel@tonic-gate 			rsp[m].masr = t_masr;
1431*0Sstevel@tonic-gate 			m++;
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 		} while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0);
1434*0Sstevel@tonic-gate 	} while (drmach_array_next(drmach_boards, &b_idx, &b_id) == 0);
1435*0Sstevel@tonic-gate 
1436*0Sstevel@tonic-gate 	/*
1437*0Sstevel@tonic-gate 	 * Zero masr_addr value indicates the END.
1438*0Sstevel@tonic-gate 	 */
1439*0Sstevel@tonic-gate 	rsp[m].masr_addr = 0ull;
1440*0Sstevel@tonic-gate 	rsp[m].masr = 0;
1441*0Sstevel@tonic-gate 	DRMACH_PR("number of steps in rename script = %d\n", m);
1442*0Sstevel@tonic-gate 	m++;
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 	/* paranoia */
1445*0Sstevel@tonic-gate 	ASSERT((caddr_t)&rsp[m] <= buf + buflen);
1446*0Sstevel@tonic-gate 
1447*0Sstevel@tonic-gate #ifdef DEBUG
1448*0Sstevel@tonic-gate 	{
1449*0Sstevel@tonic-gate 		int	j;
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 		DRMACH_PR("mc idle register address list:");
1452*0Sstevel@tonic-gate 		isp = (drmach_mc_idle_script_t *)buf;
1453*0Sstevel@tonic-gate 		DRMACH_PR("source mc idle addr 0x%llx, mem id %p",
1454*0Sstevel@tonic-gate 			isp[0].idle_addr, isp[0].mem);
1455*0Sstevel@tonic-gate 		DRMACH_PR("target mc idle addr 0x%llx, mem id %p",
1456*0Sstevel@tonic-gate 			isp[1].idle_addr, isp[1].mem);
1457*0Sstevel@tonic-gate 		ASSERT(isp[2].idle_addr == 0);
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 		DRMACH_PR("copy-rename script:");
1460*0Sstevel@tonic-gate 		for (j = 0; j < m; j++) {
1461*0Sstevel@tonic-gate 			DRMACH_PR("0x%llx = 0x%08x",
1462*0Sstevel@tonic-gate 				rsp[j].masr_addr, rsp[j].masr);
1463*0Sstevel@tonic-gate 		}
1464*0Sstevel@tonic-gate 
1465*0Sstevel@tonic-gate 		DELAY(1000000);
1466*0Sstevel@tonic-gate 	}
1467*0Sstevel@tonic-gate #endif
1468*0Sstevel@tonic-gate 
1469*0Sstevel@tonic-gate 	/* return number of bytes consumed */
1470*0Sstevel@tonic-gate 	b = (caddr_t)&rsp[m] - buf;
1471*0Sstevel@tonic-gate 	DRMACH_PR("total number of bytes consumed is %d\n", b);
1472*0Sstevel@tonic-gate 	ASSERT(b <= buflen);
1473*0Sstevel@tonic-gate 
1474*0Sstevel@tonic-gate #ifdef lint
1475*0Sstevel@tonic-gate 	buflen = buflen;
1476*0Sstevel@tonic-gate #endif
1477*0Sstevel@tonic-gate 
1478*0Sstevel@tonic-gate 	return (NULL);
1479*0Sstevel@tonic-gate }
1480*0Sstevel@tonic-gate 
1481*0Sstevel@tonic-gate /*
1482*0Sstevel@tonic-gate  * The routine performs the necessary memory COPY and MC adr SWITCH.
1483*0Sstevel@tonic-gate  * Both operations MUST be at the same "level" so that the stack is
1484*0Sstevel@tonic-gate  * maintained correctly between the copy and switch.  The switch
1485*0Sstevel@tonic-gate  * portion implements a caching mechanism to guarantee the code text
1486*0Sstevel@tonic-gate  * is cached prior to execution.  This is to guard against possible
1487*0Sstevel@tonic-gate  * memory access while the MC adr's are being modified.
1488*0Sstevel@tonic-gate  *
1489*0Sstevel@tonic-gate  * IMPORTANT: The _drmach_copy_rename_end() function must immediately
1490*0Sstevel@tonic-gate  * follow drmach_copy_rename_prog__relocatable() so that the correct
1491*0Sstevel@tonic-gate  * "length" of the drmach_copy_rename_prog__relocatable can be
1492*0Sstevel@tonic-gate  * calculated.  This routine MUST be a LEAF function, i.e. it can
1493*0Sstevel@tonic-gate  * make NO function calls, primarily for two reasons:
1494*0Sstevel@tonic-gate  *
1495*0Sstevel@tonic-gate  *	1. We must keep the stack consistent across the "switch".
1496*0Sstevel@tonic-gate  *	2. Function calls are compiled to relative offsets, and
1497*0Sstevel@tonic-gate  *	   we execute this function we'll be executing it from
1498*0Sstevel@tonic-gate  *	   a copied version in a different area of memory, thus
1499*0Sstevel@tonic-gate  *	   the relative offsets will be bogus.
1500*0Sstevel@tonic-gate  *
1501*0Sstevel@tonic-gate  * Moreover, it must have the "__relocatable" suffix to inform DTrace
1502*0Sstevel@tonic-gate  * providers (and anything else, for that matter) that this
1503*0Sstevel@tonic-gate  * function's text is manually relocated elsewhere before it is
1504*0Sstevel@tonic-gate  * executed.  That is, it cannot be safely instrumented with any
1505*0Sstevel@tonic-gate  * methodology that is PC-relative.
1506*0Sstevel@tonic-gate  */
1507*0Sstevel@tonic-gate static void
1508*0Sstevel@tonic-gate drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog)
1509*0Sstevel@tonic-gate {
1510*0Sstevel@tonic-gate 	extern void drmach_exec_script_il(drmach_rename_script_t *rsp);
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate 	drmach_mc_idle_script_t		*isp;
1513*0Sstevel@tonic-gate 	struct memlist			*ml;
1514*0Sstevel@tonic-gate 	int				csize;
1515*0Sstevel@tonic-gate 	int				lnsize;
1516*0Sstevel@tonic-gate 	uint64_t			caddr;
1517*0Sstevel@tonic-gate 
1518*0Sstevel@tonic-gate 	isp = (drmach_mc_idle_script_t *)prog->data;
1519*0Sstevel@tonic-gate 
1520*0Sstevel@tonic-gate 	caddr = ecache_flushaddr;
1521*0Sstevel@tonic-gate 	csize = (cpunodes[CPU->cpu_id].ecache_size << 1);
1522*0Sstevel@tonic-gate 	lnsize = cpunodes[CPU->cpu_id].ecache_linesize;
1523*0Sstevel@tonic-gate 
1524*0Sstevel@tonic-gate 	/*
1525*0Sstevel@tonic-gate 	 * DO COPY.
1526*0Sstevel@tonic-gate 	 */
1527*0Sstevel@tonic-gate 	for (ml = prog->c_ml; ml; ml = ml->next) {
1528*0Sstevel@tonic-gate 		uint64_t	s_pa, t_pa;
1529*0Sstevel@tonic-gate 		uint64_t	nbytes;
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate 		s_pa = prog->s_copybasepa + ml->address;
1532*0Sstevel@tonic-gate 		t_pa = prog->t_copybasepa + ml->address;
1533*0Sstevel@tonic-gate 		nbytes = ml->size;
1534*0Sstevel@tonic-gate 
1535*0Sstevel@tonic-gate 		while (nbytes != 0ull) {
1536*0Sstevel@tonic-gate 			/*
1537*0Sstevel@tonic-gate 			 * This copy does NOT use an ASI
1538*0Sstevel@tonic-gate 			 * that avoids the Ecache, therefore
1539*0Sstevel@tonic-gate 			 * the dst_pa addresses may remain
1540*0Sstevel@tonic-gate 			 * in our Ecache after the dst_pa
1541*0Sstevel@tonic-gate 			 * has been removed from the system.
1542*0Sstevel@tonic-gate 			 * A subsequent write-back to memory
1543*0Sstevel@tonic-gate 			 * will cause an ARB-stop because the
1544*0Sstevel@tonic-gate 			 * physical address no longer exists
1545*0Sstevel@tonic-gate 			 * in the system. Therefore we must
1546*0Sstevel@tonic-gate 			 * flush out local Ecache after we
1547*0Sstevel@tonic-gate 			 * finish the copy.
1548*0Sstevel@tonic-gate 			 */
1549*0Sstevel@tonic-gate 
1550*0Sstevel@tonic-gate 			/* copy 32 bytes at src_pa to dst_pa */
1551*0Sstevel@tonic-gate 			bcopy32_il(s_pa, t_pa);
1552*0Sstevel@tonic-gate 
1553*0Sstevel@tonic-gate 			/* increment by 32 bytes */
1554*0Sstevel@tonic-gate 			s_pa += (4 * sizeof (uint64_t));
1555*0Sstevel@tonic-gate 			t_pa += (4 * sizeof (uint64_t));
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate 			/* decrement by 32 bytes */
1558*0Sstevel@tonic-gate 			nbytes -= (4 * sizeof (uint64_t));
1559*0Sstevel@tonic-gate 		}
1560*0Sstevel@tonic-gate 	}
1561*0Sstevel@tonic-gate 
1562*0Sstevel@tonic-gate 	/*
1563*0Sstevel@tonic-gate 	 * Since bcopy32_il() does NOT use an ASI to bypass
1564*0Sstevel@tonic-gate 	 * the Ecache, we need to flush our Ecache after
1565*0Sstevel@tonic-gate 	 * the copy is complete.
1566*0Sstevel@tonic-gate 	 */
1567*0Sstevel@tonic-gate 	flush_ecache_il(caddr, csize, lnsize);		/* inline version */
1568*0Sstevel@tonic-gate 
1569*0Sstevel@tonic-gate 	/*
1570*0Sstevel@tonic-gate 	 * Wait for MCs to go idle.
1571*0Sstevel@tonic-gate 	 */
1572*0Sstevel@tonic-gate 	do {
1573*0Sstevel@tonic-gate 		register int	t = 10;
1574*0Sstevel@tonic-gate 		register uint_t	v;
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate 		/* loop t cycles waiting for each mc to indicate it's idle */
1577*0Sstevel@tonic-gate 		do {
1578*0Sstevel@tonic-gate 			v = ldphysio_il(isp->idle_addr)
1579*0Sstevel@tonic-gate 				& STARFIRE_MC_IDLE_MASK;
1580*0Sstevel@tonic-gate 
1581*0Sstevel@tonic-gate 		} while (v != STARFIRE_MC_IDLE_MASK && t-- > 0);
1582*0Sstevel@tonic-gate 
1583*0Sstevel@tonic-gate 		/* bailout if timedout */
1584*0Sstevel@tonic-gate 		if (t <= 0) {
1585*0Sstevel@tonic-gate 			prog->restless_mc = isp->mem;
1586*0Sstevel@tonic-gate 			return;
1587*0Sstevel@tonic-gate 		}
1588*0Sstevel@tonic-gate 
1589*0Sstevel@tonic-gate 		isp += 1;
1590*0Sstevel@tonic-gate 
1591*0Sstevel@tonic-gate 		/* stop if terminating zero has been reached */
1592*0Sstevel@tonic-gate 	} while (isp->idle_addr != 0);
1593*0Sstevel@tonic-gate 
1594*0Sstevel@tonic-gate 	/* advance passed terminating zero */
1595*0Sstevel@tonic-gate 	isp += 1;
1596*0Sstevel@tonic-gate 
1597*0Sstevel@tonic-gate 	/*
1598*0Sstevel@tonic-gate 	 * The following inline assembly routine caches
1599*0Sstevel@tonic-gate 	 * the rename script and then caches the code that
1600*0Sstevel@tonic-gate 	 * will do the rename.  This is necessary
1601*0Sstevel@tonic-gate 	 * so that we don't have any memory references during
1602*0Sstevel@tonic-gate 	 * the reprogramming.  We accomplish this by first
1603*0Sstevel@tonic-gate 	 * jumping through the code to guarantee it's cached
1604*0Sstevel@tonic-gate 	 * before we actually execute it.
1605*0Sstevel@tonic-gate 	 */
1606*0Sstevel@tonic-gate 	drmach_exec_script_il((drmach_rename_script_t *)isp);
1607*0Sstevel@tonic-gate }
1608*0Sstevel@tonic-gate 
1609*0Sstevel@tonic-gate static void
1610*0Sstevel@tonic-gate drmach_copy_rename_end(void)
1611*0Sstevel@tonic-gate {
1612*0Sstevel@tonic-gate 	/*
1613*0Sstevel@tonic-gate 	 * IMPORTANT:	This function's location MUST be located immediately
1614*0Sstevel@tonic-gate 	 *		following drmach_copy_rename_prog__relocatable to
1615*0Sstevel@tonic-gate 	 *		accurately estimate its size.  Note that this assumes
1616*0Sstevel@tonic-gate 	 *		the compiler keeps these functions in the order in
1617*0Sstevel@tonic-gate 	 *		which they appear :-o
1618*0Sstevel@tonic-gate 	 */
1619*0Sstevel@tonic-gate }
1620*0Sstevel@tonic-gate 
1621*0Sstevel@tonic-gate sbd_error_t *
1622*0Sstevel@tonic-gate drmach_copy_rename_init(drmachid_t t_id, uint64_t t_slice_offset,
1623*0Sstevel@tonic-gate 	drmachid_t s_id, struct memlist *c_ml, drmachid_t *pgm_id)
1624*0Sstevel@tonic-gate {
1625*0Sstevel@tonic-gate 	drmach_device_t	*s_mem;
1626*0Sstevel@tonic-gate 	drmach_device_t	*t_mem;
1627*0Sstevel@tonic-gate 	struct memlist	*x_ml;
1628*0Sstevel@tonic-gate 	uint64_t	off_mask, s_copybasepa, t_copybasepa, t_basepa;
1629*0Sstevel@tonic-gate 	int		len;
1630*0Sstevel@tonic-gate 	caddr_t		bp, wp;
1631*0Sstevel@tonic-gate 	pda_handle_t	ph;
1632*0Sstevel@tonic-gate 	sbd_error_t	*err;
1633*0Sstevel@tonic-gate 	drmach_copy_rename_program_t *prog;
1634*0Sstevel@tonic-gate 
1635*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(s_id))
1636*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
1637*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(t_id))
1638*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
1639*0Sstevel@tonic-gate 	s_mem = s_id;
1640*0Sstevel@tonic-gate 	t_mem = t_id;
1641*0Sstevel@tonic-gate 
1642*0Sstevel@tonic-gate 	/* get starting physical address of target memory */
1643*0Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(t_id, &t_basepa);
1644*0Sstevel@tonic-gate 	if (err)
1645*0Sstevel@tonic-gate 		return (err);
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate 	/* calculate slice offset mask from slice size */
1648*0Sstevel@tonic-gate 	off_mask = mc_get_mem_alignment() - 1;
1649*0Sstevel@tonic-gate 
1650*0Sstevel@tonic-gate 	/* calculate source and target base pa */
1651*0Sstevel@tonic-gate 	s_copybasepa = c_ml->address;
1652*0Sstevel@tonic-gate 	t_copybasepa = t_basepa + ((c_ml->address & off_mask) - t_slice_offset);
1653*0Sstevel@tonic-gate 
1654*0Sstevel@tonic-gate 	/* paranoia */
1655*0Sstevel@tonic-gate 	ASSERT((c_ml->address & off_mask) >= t_slice_offset);
1656*0Sstevel@tonic-gate 
1657*0Sstevel@tonic-gate 	/* adjust copy memlist addresses to be relative to copy base pa */
1658*0Sstevel@tonic-gate 	x_ml = c_ml;
1659*0Sstevel@tonic-gate 	while (x_ml != NULL) {
1660*0Sstevel@tonic-gate 		x_ml->address -= s_copybasepa;
1661*0Sstevel@tonic-gate 		x_ml = x_ml->next;
1662*0Sstevel@tonic-gate 	}
1663*0Sstevel@tonic-gate 
1664*0Sstevel@tonic-gate #ifdef DEBUG
1665*0Sstevel@tonic-gate 	{
1666*0Sstevel@tonic-gate 	uint64_t s_basepa, s_size, t_size;
1667*0Sstevel@tonic-gate 
1668*0Sstevel@tonic-gate 	x_ml = c_ml;
1669*0Sstevel@tonic-gate 	while (x_ml->next != NULL)
1670*0Sstevel@tonic-gate 		x_ml = x_ml->next;
1671*0Sstevel@tonic-gate 
1672*0Sstevel@tonic-gate 	DRMACH_PR("source copy span: base pa 0x%llx, end pa 0x%llx\n",
1673*0Sstevel@tonic-gate 		s_copybasepa,
1674*0Sstevel@tonic-gate 		s_copybasepa + x_ml->address + x_ml->size);
1675*0Sstevel@tonic-gate 
1676*0Sstevel@tonic-gate 	DRMACH_PR("target copy span: base pa 0x%llx, end pa 0x%llx\n",
1677*0Sstevel@tonic-gate 		t_copybasepa,
1678*0Sstevel@tonic-gate 		t_copybasepa + x_ml->address + x_ml->size);
1679*0Sstevel@tonic-gate 
1680*0Sstevel@tonic-gate 	DRMACH_PR("copy memlist (relative to copy base pa):\n");
1681*0Sstevel@tonic-gate 	MEMLIST_DUMP(c_ml);
1682*0Sstevel@tonic-gate 
1683*0Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(s_id, &s_basepa);
1684*0Sstevel@tonic-gate 	ASSERT(err == NULL);
1685*0Sstevel@tonic-gate 
1686*0Sstevel@tonic-gate 	err = drmach_mem_get_size(s_id, &s_size);
1687*0Sstevel@tonic-gate 	ASSERT(err == NULL);
1688*0Sstevel@tonic-gate 
1689*0Sstevel@tonic-gate 	err = drmach_mem_get_size(t_id, &t_size);
1690*0Sstevel@tonic-gate 	ASSERT(err == NULL);
1691*0Sstevel@tonic-gate 
1692*0Sstevel@tonic-gate 	DRMACH_PR("current source base pa 0x%llx, size 0x%llx\n",
1693*0Sstevel@tonic-gate 		s_basepa, s_size);
1694*0Sstevel@tonic-gate 	DRMACH_PR("current target base pa 0x%llx, size 0x%llx\n",
1695*0Sstevel@tonic-gate 		t_basepa, t_size);
1696*0Sstevel@tonic-gate 
1697*0Sstevel@tonic-gate 	ASSERT(s_copybasepa + x_ml->address + x_ml->size <= s_basepa + s_size);
1698*0Sstevel@tonic-gate 	ASSERT(t_copybasepa + x_ml->address + x_ml->size <= t_basepa + t_size);
1699*0Sstevel@tonic-gate 	}
1700*0Sstevel@tonic-gate #endif
1701*0Sstevel@tonic-gate 
1702*0Sstevel@tonic-gate 	ph = drmach_pda_open();
1703*0Sstevel@tonic-gate 	if (ph == NULL)
1704*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
1705*0Sstevel@tonic-gate 
1706*0Sstevel@tonic-gate 	/*
1707*0Sstevel@tonic-gate 	 * bp will be page aligned, since we're calling
1708*0Sstevel@tonic-gate 	 * kmem_zalloc() with an exact multiple of PAGESIZE.
1709*0Sstevel@tonic-gate 	 */
1710*0Sstevel@tonic-gate 	wp = bp = kmem_zalloc(PAGESIZE, KM_SLEEP);
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 	/* allocate space for copy rename struct */
1713*0Sstevel@tonic-gate 	len = sizeof (drmach_copy_rename_program_t);
1714*0Sstevel@tonic-gate 	DRMACH_PR("prog = 0x%p, header len %d\n", wp, len);
1715*0Sstevel@tonic-gate 	prog = (drmach_copy_rename_program_t *)wp;
1716*0Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
1717*0Sstevel@tonic-gate 
1718*0Sstevel@tonic-gate 	/*
1719*0Sstevel@tonic-gate 	 * Copy the code for the copy-rename routine into
1720*0Sstevel@tonic-gate 	 * a page aligned piece of memory.  We do this to guarantee
1721*0Sstevel@tonic-gate 	 * that we're executing within the same page and thus reduce
1722*0Sstevel@tonic-gate 	 * the possibility of cache collisions between different
1723*0Sstevel@tonic-gate 	 * pages.
1724*0Sstevel@tonic-gate 	 */
1725*0Sstevel@tonic-gate 	len = (int)((ulong_t)drmach_copy_rename_end -
1726*0Sstevel@tonic-gate 		    (ulong_t)drmach_copy_rename_prog__relocatable);
1727*0Sstevel@tonic-gate 	ASSERT(wp + len < bp + PAGESIZE);
1728*0Sstevel@tonic-gate 	bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len);
1729*0Sstevel@tonic-gate 
1730*0Sstevel@tonic-gate 	DRMACH_PR("copy-rename function 0x%p, len %d\n", wp, len);
1731*0Sstevel@tonic-gate 	prog->run = (void (*)())wp;
1732*0Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
1733*0Sstevel@tonic-gate 
1734*0Sstevel@tonic-gate 	/*
1735*0Sstevel@tonic-gate 	 * Prepare data page that will contain script of
1736*0Sstevel@tonic-gate 	 * operations to perform during copy-rename.
1737*0Sstevel@tonic-gate 	 * Allocate temporary buffer to hold script.
1738*0Sstevel@tonic-gate 	 */
1739*0Sstevel@tonic-gate 	err = drmach_prep_rename_script(s_mem, t_mem, t_slice_offset,
1740*0Sstevel@tonic-gate 		wp, PAGESIZE - (wp - bp));
1741*0Sstevel@tonic-gate 	if (err) {
1742*0Sstevel@tonic-gate 		(void) drmach_copy_rename_fini(prog);
1743*0Sstevel@tonic-gate 		return (err);
1744*0Sstevel@tonic-gate 	}
1745*0Sstevel@tonic-gate 
1746*0Sstevel@tonic-gate 	DRMACH_PR("copy-rename script 0x%p, len %d\n", wp, len);
1747*0Sstevel@tonic-gate 	prog->data = wp;
1748*0Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
1749*0Sstevel@tonic-gate 
1750*0Sstevel@tonic-gate 	prog->ph = ph;
1751*0Sstevel@tonic-gate 	prog->s_copybasepa = s_copybasepa;
1752*0Sstevel@tonic-gate 	prog->t_copybasepa = t_copybasepa;
1753*0Sstevel@tonic-gate 	prog->c_ml = c_ml;
1754*0Sstevel@tonic-gate 	*pgm_id = prog;
1755*0Sstevel@tonic-gate 
1756*0Sstevel@tonic-gate 	return (NULL);
1757*0Sstevel@tonic-gate }
1758*0Sstevel@tonic-gate 
1759*0Sstevel@tonic-gate sbd_error_t *
1760*0Sstevel@tonic-gate drmach_copy_rename_fini(drmachid_t id)
1761*0Sstevel@tonic-gate {
1762*0Sstevel@tonic-gate 	drmach_copy_rename_program_t	*prog = id;
1763*0Sstevel@tonic-gate 	sbd_error_t			*err = NULL;
1764*0Sstevel@tonic-gate 
1765*0Sstevel@tonic-gate 	if (prog->c_ml != NULL)
1766*0Sstevel@tonic-gate 		memlist_delete(prog->c_ml);
1767*0Sstevel@tonic-gate 
1768*0Sstevel@tonic-gate 	if (prog->ph != NULL)
1769*0Sstevel@tonic-gate 		pda_close(prog->ph);
1770*0Sstevel@tonic-gate 
1771*0Sstevel@tonic-gate 	if (prog->restless_mc != 0) {
1772*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "MC did not idle; OBP Node 0x%x",
1773*0Sstevel@tonic-gate 			(uint_t)drmach_node_get_dnode(prog->restless_mc->node));
1774*0Sstevel@tonic-gate 
1775*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
1776*0Sstevel@tonic-gate 	}
1777*0Sstevel@tonic-gate 
1778*0Sstevel@tonic-gate 	kmem_free(prog, PAGESIZE);
1779*0Sstevel@tonic-gate 
1780*0Sstevel@tonic-gate 	return (err);
1781*0Sstevel@tonic-gate }
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate static sbd_error_t *
1784*0Sstevel@tonic-gate drmach_io_new(drmach_device_t *dp)
1785*0Sstevel@tonic-gate {
1786*0Sstevel@tonic-gate 	static sbd_error_t *drmach_io_release(drmachid_t);
1787*0Sstevel@tonic-gate 	static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *);
1788*0Sstevel@tonic-gate 
1789*0Sstevel@tonic-gate 	sbd_error_t	*err;
1790*0Sstevel@tonic-gate 	int		 portid;
1791*0Sstevel@tonic-gate 
1792*0Sstevel@tonic-gate 	err = drmach_device_get_prop(dp, "upa-portid", &portid);
1793*0Sstevel@tonic-gate 	if (err == NULL) {
1794*0Sstevel@tonic-gate 		ASSERT(portid & 0x40);
1795*0Sstevel@tonic-gate 		dp->unum = portid & 1;
1796*0Sstevel@tonic-gate 	}
1797*0Sstevel@tonic-gate 
1798*0Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_io_new;
1799*0Sstevel@tonic-gate 	dp->cm.release = drmach_io_release;
1800*0Sstevel@tonic-gate 	dp->cm.status = drmach_io_status;
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 	snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type, dp->unum);
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate 	return (err);
1805*0Sstevel@tonic-gate }
1806*0Sstevel@tonic-gate 
1807*0Sstevel@tonic-gate static void
1808*0Sstevel@tonic-gate drmach_iopc_op(pda_handle_t ph, drmach_iopc_op_t op)
1809*0Sstevel@tonic-gate {
1810*0Sstevel@tonic-gate 	register int b;
1811*0Sstevel@tonic-gate 
1812*0Sstevel@tonic-gate 	for (b = 0; b < MAX_BOARDS; b++) {
1813*0Sstevel@tonic-gate 		int		p;
1814*0Sstevel@tonic-gate 		ushort_t	bda_ioc;
1815*0Sstevel@tonic-gate 		board_desc_t	*bdesc;
1816*0Sstevel@tonic-gate 
1817*0Sstevel@tonic-gate 		if (pda_board_present(ph, b) == 0)
1818*0Sstevel@tonic-gate 			continue;
1819*0Sstevel@tonic-gate 
1820*0Sstevel@tonic-gate 		bdesc = (board_desc_t *)pda_get_board_info(ph, b);
1821*0Sstevel@tonic-gate 		/*
1822*0Sstevel@tonic-gate 		 * Update PCs for IOCs.
1823*0Sstevel@tonic-gate 		 */
1824*0Sstevel@tonic-gate 		bda_ioc = bdesc->bda_ioc;
1825*0Sstevel@tonic-gate 		for (p = 0; p < MAX_IOCS; p++) {
1826*0Sstevel@tonic-gate 			u_longlong_t	idle_addr;
1827*0Sstevel@tonic-gate 			uchar_t		value;
1828*0Sstevel@tonic-gate 
1829*0Sstevel@tonic-gate 			if (BDA_NBL(bda_ioc, p) != BDAN_GOOD)
1830*0Sstevel@tonic-gate 				continue;
1831*0Sstevel@tonic-gate 
1832*0Sstevel@tonic-gate 			idle_addr = STARFIRE_BB_PC_ADDR(b, p, 1);
1833*0Sstevel@tonic-gate 
1834*0Sstevel@tonic-gate 			switch (op) {
1835*0Sstevel@tonic-gate 			case DO_PAUSE:
1836*0Sstevel@tonic-gate 				value = STARFIRE_BB_PC_PAUSE(p);
1837*0Sstevel@tonic-gate 				break;
1838*0Sstevel@tonic-gate 
1839*0Sstevel@tonic-gate 			case DO_IDLE:
1840*0Sstevel@tonic-gate 				value = STARFIRE_BB_PC_IDLE(p);
1841*0Sstevel@tonic-gate 				break;
1842*0Sstevel@tonic-gate 
1843*0Sstevel@tonic-gate 			case DO_UNPAUSE:
1844*0Sstevel@tonic-gate 				value = ldbphysio(idle_addr);
1845*0Sstevel@tonic-gate 				value &= ~STARFIRE_BB_PC_PAUSE(p);
1846*0Sstevel@tonic-gate 				break;
1847*0Sstevel@tonic-gate 
1848*0Sstevel@tonic-gate 			case DO_UNIDLE:
1849*0Sstevel@tonic-gate 				value = ldbphysio(idle_addr);
1850*0Sstevel@tonic-gate 				value &= ~STARFIRE_BB_PC_IDLE(p);
1851*0Sstevel@tonic-gate 				break;
1852*0Sstevel@tonic-gate 
1853*0Sstevel@tonic-gate 			default:
1854*0Sstevel@tonic-gate 				cmn_err(CE_PANIC,
1855*0Sstevel@tonic-gate 					"drmach_iopc_op: unknown op (%d)",
1856*0Sstevel@tonic-gate 					(int)op);
1857*0Sstevel@tonic-gate 				/*NOTREACHED*/
1858*0Sstevel@tonic-gate 			}
1859*0Sstevel@tonic-gate 			stbphysio(idle_addr, value);
1860*0Sstevel@tonic-gate 		}
1861*0Sstevel@tonic-gate 	}
1862*0Sstevel@tonic-gate }
1863*0Sstevel@tonic-gate 
1864*0Sstevel@tonic-gate void
1865*0Sstevel@tonic-gate drmach_copy_rename(drmachid_t id)
1866*0Sstevel@tonic-gate {
1867*0Sstevel@tonic-gate 	drmach_copy_rename_program_t	*prog = id;
1868*0Sstevel@tonic-gate 	uint64_t			neer;
1869*0Sstevel@tonic-gate 
1870*0Sstevel@tonic-gate 	/*
1871*0Sstevel@tonic-gate 	 * UPA IDLE
1872*0Sstevel@tonic-gate 	 * Protocol = PAUSE -> IDLE -> UNPAUSE
1873*0Sstevel@tonic-gate 	 * In reality since we only "idle" the IOPCs it's sufficient
1874*0Sstevel@tonic-gate 	 * to just issue the IDLE operation since (in theory) all IOPCs
1875*0Sstevel@tonic-gate 	 * in the field are PC6.  However, we'll be robust and do the
1876*0Sstevel@tonic-gate 	 * proper workaround protocol so that we never have to worry!
1877*0Sstevel@tonic-gate 	 */
1878*0Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_PAUSE);
1879*0Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_IDLE);
1880*0Sstevel@tonic-gate 	DELAY(100);
1881*0Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_UNPAUSE);
1882*0Sstevel@tonic-gate 	DELAY(100);
1883*0Sstevel@tonic-gate 
1884*0Sstevel@tonic-gate 	/* disable CE reporting */
1885*0Sstevel@tonic-gate 	neer = get_error_enable();
1886*0Sstevel@tonic-gate 	set_error_enable(neer & ~EER_CEEN);
1887*0Sstevel@tonic-gate 
1888*0Sstevel@tonic-gate 	/* run the copy/rename program */
1889*0Sstevel@tonic-gate 	prog->run(prog);
1890*0Sstevel@tonic-gate 
1891*0Sstevel@tonic-gate 	/* enable CE reporting */
1892*0Sstevel@tonic-gate 	set_error_enable(neer);
1893*0Sstevel@tonic-gate 
1894*0Sstevel@tonic-gate 	/*
1895*0Sstevel@tonic-gate 	 * UPA UNIDLE
1896*0Sstevel@tonic-gate 	 * Protocol = UNIDLE
1897*0Sstevel@tonic-gate 	 */
1898*0Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_UNIDLE);
1899*0Sstevel@tonic-gate 	DELAY(100);
1900*0Sstevel@tonic-gate }
1901*0Sstevel@tonic-gate 
1902*0Sstevel@tonic-gate /*
1903*0Sstevel@tonic-gate  * The counter-timer and perf-counter nodes are not being cleaned
1904*0Sstevel@tonic-gate  * up after a board that was present at start of day is detached.
1905*0Sstevel@tonic-gate  * If the board has become unconfigured with this operation, walk
1906*0Sstevel@tonic-gate  * the prom tree and find all counter-timer and perf-counter nodes
1907*0Sstevel@tonic-gate  * that have the same board number as the board that was just
1908*0Sstevel@tonic-gate  * unconfigured and remove them.
1909*0Sstevel@tonic-gate  */
1910*0Sstevel@tonic-gate static sbd_error_t *
1911*0Sstevel@tonic-gate drmach_remove_counter_nodes(drmachid_t id)
1912*0Sstevel@tonic-gate {
1913*0Sstevel@tonic-gate 	int		num;
1914*0Sstevel@tonic-gate 	char		name[OBP_MAXDRVNAME];
1915*0Sstevel@tonic-gate 	dnode_t		child;
1916*0Sstevel@tonic-gate 	dev_info_t	*dip;
1917*0Sstevel@tonic-gate 	sbd_error_t	*err;
1918*0Sstevel@tonic-gate 	drmach_status_t	stat;
1919*0Sstevel@tonic-gate 	drmach_board_t	*bp;
1920*0Sstevel@tonic-gate 
1921*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id)) {
1922*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
1923*0Sstevel@tonic-gate 	}
1924*0Sstevel@tonic-gate 
1925*0Sstevel@tonic-gate 	if ((err = drmach_board_status(id, &stat)) != NULL) {
1926*0Sstevel@tonic-gate 		return (err);
1927*0Sstevel@tonic-gate 	}
1928*0Sstevel@tonic-gate 
1929*0Sstevel@tonic-gate 	/*
1930*0Sstevel@tonic-gate 	 * Only clean up the counter-timer and perf-counter
1931*0Sstevel@tonic-gate 	 * nodes when the entire board is unconfigured.
1932*0Sstevel@tonic-gate 	 */
1933*0Sstevel@tonic-gate 	if (stat.configured) {
1934*0Sstevel@tonic-gate 		return (NULL);
1935*0Sstevel@tonic-gate 	}
1936*0Sstevel@tonic-gate 
1937*0Sstevel@tonic-gate 	bp = (drmach_board_t *)id;
1938*0Sstevel@tonic-gate 
1939*0Sstevel@tonic-gate 	err = NULL;
1940*0Sstevel@tonic-gate 
1941*0Sstevel@tonic-gate 	for (child = prom_childnode(prom_rootnode()); child != OBP_NONODE;
1942*0Sstevel@tonic-gate 	    child = prom_nextnode(child)) {
1943*0Sstevel@tonic-gate 
1944*0Sstevel@tonic-gate 		if (prom_getprop(child, OBP_BOARDNUM, (caddr_t)&num) == -1) {
1945*0Sstevel@tonic-gate 			continue;
1946*0Sstevel@tonic-gate 		}
1947*0Sstevel@tonic-gate 
1948*0Sstevel@tonic-gate 		if (bp->bnum != num) {
1949*0Sstevel@tonic-gate 			continue;
1950*0Sstevel@tonic-gate 		}
1951*0Sstevel@tonic-gate 
1952*0Sstevel@tonic-gate 		if (prom_getprop(child, OBP_NAME, (caddr_t)name) == -1) {
1953*0Sstevel@tonic-gate 			continue;
1954*0Sstevel@tonic-gate 		}
1955*0Sstevel@tonic-gate 
1956*0Sstevel@tonic-gate 		if (strncmp(name, MISC_COUNTER_TIMER_DEVNAME, OBP_MAXDRVNAME) &&
1957*0Sstevel@tonic-gate 		    strncmp(name, MISC_PERF_COUNTER_DEVNAME, OBP_MAXDRVNAME)) {
1958*0Sstevel@tonic-gate 				continue;
1959*0Sstevel@tonic-gate 		}
1960*0Sstevel@tonic-gate 
1961*0Sstevel@tonic-gate 		/* Root node doesn't have to be held */
1962*0Sstevel@tonic-gate 		dip = e_ddi_nodeid_to_dip(child);
1963*0Sstevel@tonic-gate 
1964*0Sstevel@tonic-gate 		/*
1965*0Sstevel@tonic-gate 		 * If the node is only in the OBP tree, then
1966*0Sstevel@tonic-gate 		 * we don't have to remove it.
1967*0Sstevel@tonic-gate 		 */
1968*0Sstevel@tonic-gate 		if (dip) {
1969*0Sstevel@tonic-gate 			dev_info_t *fdip = NULL;
1970*0Sstevel@tonic-gate 
1971*0Sstevel@tonic-gate 			DRMACH_PR("removing %s devinfo node\n", name);
1972*0Sstevel@tonic-gate 
1973*0Sstevel@tonic-gate 			e_ddi_branch_hold(dip);
1974*0Sstevel@tonic-gate 			ddi_release_devi(dip); /* held in e_ddi_nodeid_to_dip */
1975*0Sstevel@tonic-gate 
1976*0Sstevel@tonic-gate 			if (e_ddi_branch_destroy(dip, &fdip, 0)) {
1977*0Sstevel@tonic-gate 				char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1978*0Sstevel@tonic-gate 
1979*0Sstevel@tonic-gate 				/*
1980*0Sstevel@tonic-gate 				 * If non-NULL, fdip is held and must be
1981*0Sstevel@tonic-gate 				 * released.
1982*0Sstevel@tonic-gate 				 */
1983*0Sstevel@tonic-gate 				if (fdip != NULL) {
1984*0Sstevel@tonic-gate 					(void) ddi_pathname(fdip, path);
1985*0Sstevel@tonic-gate 					ddi_release_devi(fdip);
1986*0Sstevel@tonic-gate 				} else {
1987*0Sstevel@tonic-gate 					(void) ddi_pathname(dip, path);
1988*0Sstevel@tonic-gate 				}
1989*0Sstevel@tonic-gate 
1990*0Sstevel@tonic-gate 				err = drerr_new(1, ESTF_DRVFAIL, path);
1991*0Sstevel@tonic-gate 				kmem_free(path, MAXPATHLEN);
1992*0Sstevel@tonic-gate 				e_ddi_branch_rele(dip);
1993*0Sstevel@tonic-gate 				break;
1994*0Sstevel@tonic-gate 			}
1995*0Sstevel@tonic-gate 		}
1996*0Sstevel@tonic-gate 	}
1997*0Sstevel@tonic-gate 
1998*0Sstevel@tonic-gate 	return (err);
1999*0Sstevel@tonic-gate }
2000*0Sstevel@tonic-gate 
2001*0Sstevel@tonic-gate /*ARGSUSED*/
2002*0Sstevel@tonic-gate sbd_error_t *
2003*0Sstevel@tonic-gate drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts)
2004*0Sstevel@tonic-gate {
2005*0Sstevel@tonic-gate 	/* allow status and ncm operations to always succeed */
2006*0Sstevel@tonic-gate 	if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) {
2007*0Sstevel@tonic-gate 		return (NULL);
2008*0Sstevel@tonic-gate 	}
2009*0Sstevel@tonic-gate 
2010*0Sstevel@tonic-gate 	/* check all other commands for the required option string */
2011*0Sstevel@tonic-gate 	if ((opts->size > 0) && (opts->copts != NULL)) {
2012*0Sstevel@tonic-gate 
2013*0Sstevel@tonic-gate 		DRMACH_PR("platform options: %s\n", opts->copts);
2014*0Sstevel@tonic-gate 
2015*0Sstevel@tonic-gate 		if (strstr(opts->copts, "xfdr") != NULL) {
2016*0Sstevel@tonic-gate 			return (NULL);
2017*0Sstevel@tonic-gate 		}
2018*0Sstevel@tonic-gate 	}
2019*0Sstevel@tonic-gate 
2020*0Sstevel@tonic-gate 	return (drerr_new(0, ESTF_SUPPORT, NULL));
2021*0Sstevel@tonic-gate }
2022*0Sstevel@tonic-gate 
2023*0Sstevel@tonic-gate /*ARGSUSED*/
2024*0Sstevel@tonic-gate sbd_error_t *
2025*0Sstevel@tonic-gate drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts)
2026*0Sstevel@tonic-gate {
2027*0Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
2028*0Sstevel@tonic-gate 
2029*0Sstevel@tonic-gate 	switch (cmd) {
2030*0Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
2031*0Sstevel@tonic-gate 
2032*0Sstevel@tonic-gate 		err = drmach_remove_counter_nodes(id);
2033*0Sstevel@tonic-gate 		break;
2034*0Sstevel@tonic-gate 
2035*0Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
2036*0Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
2037*0Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
2038*0Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
2039*0Sstevel@tonic-gate 	case SBD_CMD_STATUS:
2040*0Sstevel@tonic-gate 		break;
2041*0Sstevel@tonic-gate 
2042*0Sstevel@tonic-gate 	default:
2043*0Sstevel@tonic-gate 		break;
2044*0Sstevel@tonic-gate 	}
2045*0Sstevel@tonic-gate 
2046*0Sstevel@tonic-gate 	return (err);
2047*0Sstevel@tonic-gate }
2048*0Sstevel@tonic-gate 
2049*0Sstevel@tonic-gate sbd_error_t *
2050*0Sstevel@tonic-gate drmach_board_assign(int bnum, drmachid_t *id)
2051*0Sstevel@tonic-gate {
2052*0Sstevel@tonic-gate 	sbd_error_t	*err;
2053*0Sstevel@tonic-gate 
2054*0Sstevel@tonic-gate 	if (!drmach_initialized && drmach_init() == -1) {
2055*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
2056*0Sstevel@tonic-gate 	} else if (drmach_array_get(drmach_boards, bnum, id) == -1) {
2057*0Sstevel@tonic-gate 		err = drerr_new(1, ESTF_BNUM, "%d", bnum);
2058*0Sstevel@tonic-gate 	} else if (*id != NULL) {
2059*0Sstevel@tonic-gate 		err = NULL;
2060*0Sstevel@tonic-gate 	} else {
2061*0Sstevel@tonic-gate 		drmach_board_t	*bp;
2062*0Sstevel@tonic-gate 
2063*0Sstevel@tonic-gate 		*id  = (drmachid_t)drmach_board_new(bnum);
2064*0Sstevel@tonic-gate 		bp = *id;
2065*0Sstevel@tonic-gate 		bp->assigned = 1;
2066*0Sstevel@tonic-gate 		err = NULL;
2067*0Sstevel@tonic-gate 	}
2068*0Sstevel@tonic-gate 
2069*0Sstevel@tonic-gate 	return (err);
2070*0Sstevel@tonic-gate }
2071*0Sstevel@tonic-gate 
2072*0Sstevel@tonic-gate static int
2073*0Sstevel@tonic-gate drmach_attach_board(void *arg)
2074*0Sstevel@tonic-gate {
2075*0Sstevel@tonic-gate 	drmach_board_t	*obj = (drmach_board_t *)arg;
2076*0Sstevel@tonic-gate 	cpuset_t	cset;
2077*0Sstevel@tonic-gate 	int		retval;
2078*0Sstevel@tonic-gate 
2079*0Sstevel@tonic-gate 	/*
2080*0Sstevel@tonic-gate 	 * OBP disables traps during the board probe.
2081*0Sstevel@tonic-gate 	 * So, in order to prevent cross-call/cross-trap timeouts,
2082*0Sstevel@tonic-gate 	 * and thus panics, we effectively block anybody from
2083*0Sstevel@tonic-gate 	 * issuing xc's/xt's by doing a promsafe_xc_attention.
2084*0Sstevel@tonic-gate 	 * In the previous version of Starfire DR (2.6), a timeout
2085*0Sstevel@tonic-gate 	 * suspension mechanism was implemented in the send-mondo
2086*0Sstevel@tonic-gate 	 * assembly.  That mechanism is unnecessary with the
2087*0Sstevel@tonic-gate 	 * existence of xc_attention/xc_dismissed.
2088*0Sstevel@tonic-gate 	 */
2089*0Sstevel@tonic-gate 	cset = cpu_ready_set;
2090*0Sstevel@tonic-gate 	promsafe_xc_attention(cset);
2091*0Sstevel@tonic-gate 
2092*0Sstevel@tonic-gate 	retval = prom_starfire_add_brd(obj->connect_cpuid);
2093*0Sstevel@tonic-gate 
2094*0Sstevel@tonic-gate 	xc_dismissed(cset);
2095*0Sstevel@tonic-gate 
2096*0Sstevel@tonic-gate 	return (retval);
2097*0Sstevel@tonic-gate }
2098*0Sstevel@tonic-gate 
2099*0Sstevel@tonic-gate sbd_error_t *
2100*0Sstevel@tonic-gate drmach_board_connect(drmachid_t id, drmach_opts_t *opts)
2101*0Sstevel@tonic-gate {
2102*0Sstevel@tonic-gate 	drmach_board_t	*obj = (drmach_board_t *)id;
2103*0Sstevel@tonic-gate 	int		retval;
2104*0Sstevel@tonic-gate 	sbd_error_t	*err;
2105*0Sstevel@tonic-gate 	char		*cptr, *copts;
2106*0Sstevel@tonic-gate 
2107*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
2108*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2109*0Sstevel@tonic-gate 
2110*0Sstevel@tonic-gate 	if (opts->size > 0)
2111*0Sstevel@tonic-gate 		copts = opts->copts;
2112*0Sstevel@tonic-gate 
2113*0Sstevel@tonic-gate 	if ((cptr = strstr(copts, "cpuid=")) != NULL) {
2114*0Sstevel@tonic-gate 		int cpuid;
2115*0Sstevel@tonic-gate 
2116*0Sstevel@tonic-gate 		cptr += strlen("cpuid=");
2117*0Sstevel@tonic-gate 		cpuid = stoi(&cptr);
2118*0Sstevel@tonic-gate 
2119*0Sstevel@tonic-gate 		if (DRMACH_CPUID2BNUM(cpuid) == obj->bnum) {
2120*0Sstevel@tonic-gate 			obj->connect_cpuid = cpuid;
2121*0Sstevel@tonic-gate 			obj->assigned = 1;
2122*0Sstevel@tonic-gate 		} else
2123*0Sstevel@tonic-gate 			return (drerr_new(1, ESTF_SETCPUVAL, "%d", cpuid));
2124*0Sstevel@tonic-gate 	} else {
2125*0Sstevel@tonic-gate 		/* cpuid was not specified */
2126*0Sstevel@tonic-gate 		obj->connect_cpuid = -1;
2127*0Sstevel@tonic-gate 	}
2128*0Sstevel@tonic-gate 
2129*0Sstevel@tonic-gate 	if (obj->connect_cpuid == -1) {
2130*0Sstevel@tonic-gate 		err =  drerr_new(1, ESTF_NOCPUID, obj->cm.name);
2131*0Sstevel@tonic-gate 		return (err);
2132*0Sstevel@tonic-gate 	}
2133*0Sstevel@tonic-gate 
2134*0Sstevel@tonic-gate 	cmn_err(CE_CONT, "DRMACH: PROM attach %s CPU %d\n",
2135*0Sstevel@tonic-gate 		obj->cm.name, obj->connect_cpuid);
2136*0Sstevel@tonic-gate 
2137*0Sstevel@tonic-gate 	retval = prom_tree_update(drmach_attach_board, obj);
2138*0Sstevel@tonic-gate 
2139*0Sstevel@tonic-gate 	if (retval == 0)
2140*0Sstevel@tonic-gate 		err = NULL;
2141*0Sstevel@tonic-gate 	else {
2142*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "prom error: prom_starfire_add_brd(%d) "
2143*0Sstevel@tonic-gate 			"returned %d", obj->connect_cpuid, retval);
2144*0Sstevel@tonic-gate 
2145*0Sstevel@tonic-gate 		err = drerr_new(1, ESTF_PROBE, obj->cm.name);
2146*0Sstevel@tonic-gate 	}
2147*0Sstevel@tonic-gate 
2148*0Sstevel@tonic-gate 	obj->connect_cpuid = -1;
2149*0Sstevel@tonic-gate 
2150*0Sstevel@tonic-gate 	return (err);
2151*0Sstevel@tonic-gate }
2152*0Sstevel@tonic-gate 
2153*0Sstevel@tonic-gate /*ARGSUSED*/
2154*0Sstevel@tonic-gate sbd_error_t *
2155*0Sstevel@tonic-gate drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts)
2156*0Sstevel@tonic-gate {
2157*0Sstevel@tonic-gate 	return (NULL);
2158*0Sstevel@tonic-gate }
2159*0Sstevel@tonic-gate 
2160*0Sstevel@tonic-gate static int
2161*0Sstevel@tonic-gate drmach_board_find_devices_cb(drmach_node_walk_args_t *args)
2162*0Sstevel@tonic-gate {
2163*0Sstevel@tonic-gate 	drmach_node_t			*node = args->node;
2164*0Sstevel@tonic-gate 	drmach_board_cb_data_t		*data = args->data;
2165*0Sstevel@tonic-gate 	drmach_board_t			*obj = data->obj;
2166*0Sstevel@tonic-gate 
2167*0Sstevel@tonic-gate 	int		 rv;
2168*0Sstevel@tonic-gate 	int		 bnum;
2169*0Sstevel@tonic-gate 	drmach_device_t	*device;
2170*0Sstevel@tonic-gate 
2171*0Sstevel@tonic-gate 	rv = drmach_node_get_prop(node, OBP_BOARDNUM, &bnum);
2172*0Sstevel@tonic-gate 	if (rv) {
2173*0Sstevel@tonic-gate 		/*
2174*0Sstevel@tonic-gate 		 * if the node does not have a board# property, then
2175*0Sstevel@tonic-gate 		 * by that information alone it is known that drmach
2176*0Sstevel@tonic-gate 		 * is not interested in it.
2177*0Sstevel@tonic-gate 		 */
2178*0Sstevel@tonic-gate 		return (0);
2179*0Sstevel@tonic-gate 	} else if (bnum != obj->bnum)
2180*0Sstevel@tonic-gate 		return (0);
2181*0Sstevel@tonic-gate 
2182*0Sstevel@tonic-gate 	/*
2183*0Sstevel@tonic-gate 	 * Create a device data structure from this node data.
2184*0Sstevel@tonic-gate 	 * The call may yield nothing if the node is not of interest
2185*0Sstevel@tonic-gate 	 * to drmach.
2186*0Sstevel@tonic-gate 	 */
2187*0Sstevel@tonic-gate 	data->err = drmach_device_new(node, obj, &device);
2188*0Sstevel@tonic-gate 	if (data->err)
2189*0Sstevel@tonic-gate 		return (-1);
2190*0Sstevel@tonic-gate 	else if (device == NULL) {
2191*0Sstevel@tonic-gate 		/*
2192*0Sstevel@tonic-gate 		 * drmach_device_new examined the node we passed in
2193*0Sstevel@tonic-gate 		 * and determined that it was one not of interest to
2194*0Sstevel@tonic-gate 		 * drmach.  So, it is skipped.
2195*0Sstevel@tonic-gate 		 */
2196*0Sstevel@tonic-gate 		return (0);
2197*0Sstevel@tonic-gate 	}
2198*0Sstevel@tonic-gate 
2199*0Sstevel@tonic-gate 	rv = drmach_array_set(obj->devices, data->ndevs++, device);
2200*0Sstevel@tonic-gate 	if (rv) {
2201*0Sstevel@tonic-gate 		drmach_device_dispose(device);
2202*0Sstevel@tonic-gate 		data->err = DRMACH_INTERNAL_ERROR();
2203*0Sstevel@tonic-gate 		return (-1);
2204*0Sstevel@tonic-gate 	}
2205*0Sstevel@tonic-gate 
2206*0Sstevel@tonic-gate 	data->err = (*data->found)(data->a, device->type, device->unum, device);
2207*0Sstevel@tonic-gate 	return (data->err == NULL ? 0 : -1);
2208*0Sstevel@tonic-gate }
2209*0Sstevel@tonic-gate 
2210*0Sstevel@tonic-gate sbd_error_t *
2211*0Sstevel@tonic-gate drmach_board_find_devices(drmachid_t id, void *a,
2212*0Sstevel@tonic-gate 	sbd_error_t *(*found)(void *a, const char *, int, drmachid_t))
2213*0Sstevel@tonic-gate {
2214*0Sstevel@tonic-gate 	extern int		 plat_max_cpu_units_per_board();
2215*0Sstevel@tonic-gate 	extern int		 plat_max_mem_units_per_board();
2216*0Sstevel@tonic-gate 	extern int		 plat_max_io_units_per_board();
2217*0Sstevel@tonic-gate 
2218*0Sstevel@tonic-gate 	drmach_board_t		*obj = (drmach_board_t *)id;
2219*0Sstevel@tonic-gate 	sbd_error_t		*err;
2220*0Sstevel@tonic-gate 	int			 max_devices;
2221*0Sstevel@tonic-gate 	int			 rv;
2222*0Sstevel@tonic-gate 	drmach_board_cb_data_t	data;
2223*0Sstevel@tonic-gate 
2224*0Sstevel@tonic-gate 	max_devices  = plat_max_cpu_units_per_board();
2225*0Sstevel@tonic-gate 	max_devices += plat_max_mem_units_per_board();
2226*0Sstevel@tonic-gate 	max_devices += plat_max_io_units_per_board();
2227*0Sstevel@tonic-gate 
2228*0Sstevel@tonic-gate 	obj->devices = drmach_array_new(0, max_devices);
2229*0Sstevel@tonic-gate 
2230*0Sstevel@tonic-gate 	data.obj = obj;
2231*0Sstevel@tonic-gate 	data.ndevs = 0;
2232*0Sstevel@tonic-gate 	data.found = found;
2233*0Sstevel@tonic-gate 	data.a = a;
2234*0Sstevel@tonic-gate 	data.err = NULL;
2235*0Sstevel@tonic-gate 
2236*0Sstevel@tonic-gate 	rv = drmach_node_walk(obj->tree, &data, drmach_board_find_devices_cb);
2237*0Sstevel@tonic-gate 	if (rv == 0)
2238*0Sstevel@tonic-gate 		err = NULL;
2239*0Sstevel@tonic-gate 	else {
2240*0Sstevel@tonic-gate 		drmach_array_dispose(obj->devices, drmach_device_dispose);
2241*0Sstevel@tonic-gate 		obj->devices = NULL;
2242*0Sstevel@tonic-gate 
2243*0Sstevel@tonic-gate 		if (data.err)
2244*0Sstevel@tonic-gate 			err = data.err;
2245*0Sstevel@tonic-gate 		else
2246*0Sstevel@tonic-gate 			err = DRMACH_INTERNAL_ERROR();
2247*0Sstevel@tonic-gate 	}
2248*0Sstevel@tonic-gate 
2249*0Sstevel@tonic-gate 	return (err);
2250*0Sstevel@tonic-gate }
2251*0Sstevel@tonic-gate 
2252*0Sstevel@tonic-gate int
2253*0Sstevel@tonic-gate drmach_board_lookup(int bnum, drmachid_t *id)
2254*0Sstevel@tonic-gate {
2255*0Sstevel@tonic-gate 	int	rv = 0;
2256*0Sstevel@tonic-gate 
2257*0Sstevel@tonic-gate 	if (!drmach_initialized && drmach_init() == -1) {
2258*0Sstevel@tonic-gate 		*id = 0;
2259*0Sstevel@tonic-gate 		rv = -1;
2260*0Sstevel@tonic-gate 	} else if (drmach_array_get(drmach_boards, bnum, id)) {
2261*0Sstevel@tonic-gate 		*id = 0;
2262*0Sstevel@tonic-gate 		rv = -1;
2263*0Sstevel@tonic-gate 	}
2264*0Sstevel@tonic-gate 	return (rv);
2265*0Sstevel@tonic-gate }
2266*0Sstevel@tonic-gate 
2267*0Sstevel@tonic-gate sbd_error_t *
2268*0Sstevel@tonic-gate drmach_board_name(int bnum, char *buf, int buflen)
2269*0Sstevel@tonic-gate {
2270*0Sstevel@tonic-gate 	snprintf(buf, buflen, "SB%d", bnum);
2271*0Sstevel@tonic-gate 	return (NULL);
2272*0Sstevel@tonic-gate }
2273*0Sstevel@tonic-gate 
2274*0Sstevel@tonic-gate sbd_error_t *
2275*0Sstevel@tonic-gate drmach_board_poweroff(drmachid_t id)
2276*0Sstevel@tonic-gate {
2277*0Sstevel@tonic-gate 	drmach_board_t	*bp;
2278*0Sstevel@tonic-gate 	sbd_error_t	*err;
2279*0Sstevel@tonic-gate 	drmach_status_t	 stat;
2280*0Sstevel@tonic-gate 
2281*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
2282*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2283*0Sstevel@tonic-gate 	bp = id;
2284*0Sstevel@tonic-gate 
2285*0Sstevel@tonic-gate 	err = drmach_board_status(id, &stat);
2286*0Sstevel@tonic-gate 	if (err)
2287*0Sstevel@tonic-gate 		return (err);
2288*0Sstevel@tonic-gate 	else if (stat.configured || stat.busy)
2289*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name));
2290*0Sstevel@tonic-gate 	else {
2291*0Sstevel@tonic-gate 		/* board power off is essentially a noop for Starfire */
2292*0Sstevel@tonic-gate 		bp->powered = 0;
2293*0Sstevel@tonic-gate 		return (NULL);
2294*0Sstevel@tonic-gate 	}
2295*0Sstevel@tonic-gate 	/*NOTREACHED*/
2296*0Sstevel@tonic-gate }
2297*0Sstevel@tonic-gate 
2298*0Sstevel@tonic-gate sbd_error_t *
2299*0Sstevel@tonic-gate drmach_board_poweron(drmachid_t id)
2300*0Sstevel@tonic-gate {
2301*0Sstevel@tonic-gate 	drmach_board_t	*bp;
2302*0Sstevel@tonic-gate 
2303*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
2304*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2305*0Sstevel@tonic-gate 	bp = id;
2306*0Sstevel@tonic-gate 
2307*0Sstevel@tonic-gate 	/* board power on is essentially a noop for Starfire */
2308*0Sstevel@tonic-gate 	bp->powered = 1;
2309*0Sstevel@tonic-gate 
2310*0Sstevel@tonic-gate 	return (NULL);
2311*0Sstevel@tonic-gate }
2312*0Sstevel@tonic-gate 
2313*0Sstevel@tonic-gate static sbd_error_t *
2314*0Sstevel@tonic-gate drmach_board_release(drmachid_t id)
2315*0Sstevel@tonic-gate {
2316*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
2317*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2318*0Sstevel@tonic-gate 	return (NULL);
2319*0Sstevel@tonic-gate }
2320*0Sstevel@tonic-gate 
2321*0Sstevel@tonic-gate /*ARGSUSED*/
2322*0Sstevel@tonic-gate sbd_error_t *
2323*0Sstevel@tonic-gate drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force)
2324*0Sstevel@tonic-gate {
2325*0Sstevel@tonic-gate 	return (NULL);
2326*0Sstevel@tonic-gate }
2327*0Sstevel@tonic-gate 
2328*0Sstevel@tonic-gate sbd_error_t *
2329*0Sstevel@tonic-gate drmach_board_unassign(drmachid_t id)
2330*0Sstevel@tonic-gate {
2331*0Sstevel@tonic-gate 	drmach_board_t	*bp;
2332*0Sstevel@tonic-gate 	sbd_error_t	*err;
2333*0Sstevel@tonic-gate 	drmach_status_t	 stat;
2334*0Sstevel@tonic-gate 
2335*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
2336*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2337*0Sstevel@tonic-gate 	bp = id;
2338*0Sstevel@tonic-gate 
2339*0Sstevel@tonic-gate 	err = drmach_board_status(id, &stat);
2340*0Sstevel@tonic-gate 	if (err)
2341*0Sstevel@tonic-gate 		return (err);
2342*0Sstevel@tonic-gate 	else if (stat.configured || stat.busy)
2343*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name));
2344*0Sstevel@tonic-gate 	else if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0)
2345*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
2346*0Sstevel@tonic-gate 	else {
2347*0Sstevel@tonic-gate 		drmach_board_dispose(bp);
2348*0Sstevel@tonic-gate 		return (NULL);
2349*0Sstevel@tonic-gate 	}
2350*0Sstevel@tonic-gate 	/*NOTREACHED*/
2351*0Sstevel@tonic-gate }
2352*0Sstevel@tonic-gate 
2353*0Sstevel@tonic-gate static sbd_error_t *
2354*0Sstevel@tonic-gate drmach_cpu_new(drmach_device_t *dp)
2355*0Sstevel@tonic-gate {
2356*0Sstevel@tonic-gate 	static sbd_error_t *drmach_cpu_release(drmachid_t);
2357*0Sstevel@tonic-gate 	static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *);
2358*0Sstevel@tonic-gate 
2359*0Sstevel@tonic-gate 	sbd_error_t	*err;
2360*0Sstevel@tonic-gate 	int		 portid;
2361*0Sstevel@tonic-gate 
2362*0Sstevel@tonic-gate 	err = drmach_device_get_prop(dp, "upa-portid", &portid);
2363*0Sstevel@tonic-gate 	if (err == NULL)
2364*0Sstevel@tonic-gate 		dp->unum = portid & 3;
2365*0Sstevel@tonic-gate 
2366*0Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_cpu_new;
2367*0Sstevel@tonic-gate 	dp->cm.release = drmach_cpu_release;
2368*0Sstevel@tonic-gate 	dp->cm.status = drmach_cpu_status;
2369*0Sstevel@tonic-gate 
2370*0Sstevel@tonic-gate 	snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type, dp->unum);
2371*0Sstevel@tonic-gate 
2372*0Sstevel@tonic-gate 	return (err);
2373*0Sstevel@tonic-gate }
2374*0Sstevel@tonic-gate 
2375*0Sstevel@tonic-gate /*
2376*0Sstevel@tonic-gate  * drmach_cpu_obp_detach()
2377*0Sstevel@tonic-gate  *  This requires two steps, first, we must put the cpuid into the OBP
2378*0Sstevel@tonic-gate  *  idle loop (Idle in Program) state.  Then we call OBP to place the CPU
2379*0Sstevel@tonic-gate  *  into the "Detached" state, which does any special processing to
2380*0Sstevel@tonic-gate  *  actually detach the cpu, such as flushing ecache, and also ensures
2381*0Sstevel@tonic-gate  *  that a subsequent breakpoint won't restart the cpu (if it was just in
2382*0Sstevel@tonic-gate  *  Idle in Program state).
2383*0Sstevel@tonic-gate  */
2384*0Sstevel@tonic-gate static void
2385*0Sstevel@tonic-gate drmach_cpu_obp_detach(int cpuid)
2386*0Sstevel@tonic-gate {
2387*0Sstevel@tonic-gate 	/*
2388*0Sstevel@tonic-gate 	 * Cpu may not be under OBP's control. Eg, if cpu exited to download
2389*0Sstevel@tonic-gate 	 * helper on a prior attach.
2390*0Sstevel@tonic-gate 	 */
2391*0Sstevel@tonic-gate 	if (CPU_SGN_EXISTS(cpuid) &&
2392*0Sstevel@tonic-gate 			!SGN_CPU_IS_OS(cpuid) &&
2393*0Sstevel@tonic-gate 			!SGN_CPU_IS_OBP(cpuid)) {
2394*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
2395*0Sstevel@tonic-gate 			"unexpected signature (0x%x) for cpu %d",
2396*0Sstevel@tonic-gate 			get_cpu_sgn(cpuid), cpuid);
2397*0Sstevel@tonic-gate 	}
2398*0Sstevel@tonic-gate 
2399*0Sstevel@tonic-gate 	/*
2400*0Sstevel@tonic-gate 	 * Now we place the CPU into the "Detached" idle loop in OBP.
2401*0Sstevel@tonic-gate 	 * This is so that the CPU won't be restarted if we break into
2402*0Sstevel@tonic-gate 	 * OBP with a breakpoint or BREAK key from the console, and also
2403*0Sstevel@tonic-gate 	 * if we need to do any special processing, such as flushing the
2404*0Sstevel@tonic-gate 	 * cpu's ecache, disabling interrupts (by turning of the ET bit in
2405*0Sstevel@tonic-gate 	 * the PSR) and/or spinning in BBSRAM rather than global memory.
2406*0Sstevel@tonic-gate 	 */
2407*0Sstevel@tonic-gate 	DRMACH_PR("prom_starfire_rm_cpu(%d)\n", cpuid);
2408*0Sstevel@tonic-gate 	prom_starfire_rm_cpu(cpuid);
2409*0Sstevel@tonic-gate }
2410*0Sstevel@tonic-gate 
2411*0Sstevel@tonic-gate /*
2412*0Sstevel@tonic-gate  * drmach_cpu_obp_is_detached() returns TRUE if the cpu sigblock signature state
2413*0Sstevel@tonic-gate  * is SIGBST_DETACHED; otherwise it returns FALSE. This routine should only
2414*0Sstevel@tonic-gate  * be called after we have asked OBP to detach the CPU. It should NOT be
2415*0Sstevel@tonic-gate  * called as a check during any other flow.
2416*0Sstevel@tonic-gate  */
2417*0Sstevel@tonic-gate static int
2418*0Sstevel@tonic-gate drmach_cpu_obp_is_detached(int cpuid)
2419*0Sstevel@tonic-gate {
2420*0Sstevel@tonic-gate 	if (!CPU_SGN_EXISTS(cpuid) ||
2421*0Sstevel@tonic-gate 		(SGN_CPU_IS_OS(cpuid) && SGN_CPU_STATE_IS_DETACHED(cpuid)))
2422*0Sstevel@tonic-gate 		return (1);
2423*0Sstevel@tonic-gate 	else
2424*0Sstevel@tonic-gate 		return (0);
2425*0Sstevel@tonic-gate }
2426*0Sstevel@tonic-gate 
2427*0Sstevel@tonic-gate static int
2428*0Sstevel@tonic-gate drmach_cpu_start(struct cpu *cp)
2429*0Sstevel@tonic-gate {
2430*0Sstevel@tonic-gate 	int		cpuid = cp->cpu_id;
2431*0Sstevel@tonic-gate 	int		ntries = drmach_cpu_ntries;
2432*0Sstevel@tonic-gate 	extern void	restart_other_cpu(int);
2433*0Sstevel@tonic-gate 
2434*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
2435*0Sstevel@tonic-gate 	ASSERT(cpunodes[cpuid].nodeid != (dnode_t)0);
2436*0Sstevel@tonic-gate 
2437*0Sstevel@tonic-gate 	cp->cpu_flags &= ~CPU_POWEROFF;
2438*0Sstevel@tonic-gate 
2439*0Sstevel@tonic-gate 	/*
2440*0Sstevel@tonic-gate 	 * NOTE: restart_other_cpu pauses cpus during the
2441*0Sstevel@tonic-gate 	 *	 slave cpu start.  This helps to quiesce the
2442*0Sstevel@tonic-gate 	 *	 bus traffic a bit which makes the tick sync
2443*0Sstevel@tonic-gate 	 *	 routine in the prom more robust.
2444*0Sstevel@tonic-gate 	 */
2445*0Sstevel@tonic-gate 	DRMACH_PR("COLD START for cpu (%d)\n", cpuid);
2446*0Sstevel@tonic-gate 
2447*0Sstevel@tonic-gate 	prom_starfire_add_cpu(cpuid);
2448*0Sstevel@tonic-gate 
2449*0Sstevel@tonic-gate 	restart_other_cpu(cpuid);
2450*0Sstevel@tonic-gate 
2451*0Sstevel@tonic-gate 	/*
2452*0Sstevel@tonic-gate 	 * Wait for the cpu to reach its idle thread before
2453*0Sstevel@tonic-gate 	 * we zap him with a request to blow away the mappings
2454*0Sstevel@tonic-gate 	 * he (might) have for the drmach_shutdown_asm code
2455*0Sstevel@tonic-gate 	 * he may have executed on unconfigure.
2456*0Sstevel@tonic-gate 	 */
2457*0Sstevel@tonic-gate 	while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) {
2458*0Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
2459*0Sstevel@tonic-gate 		ntries--;
2460*0Sstevel@tonic-gate 	}
2461*0Sstevel@tonic-gate 
2462*0Sstevel@tonic-gate 	DRMACH_PR("waited %d out of %d loops for cpu %d\n",
2463*0Sstevel@tonic-gate 		drmach_cpu_ntries - ntries, drmach_cpu_ntries, cpuid);
2464*0Sstevel@tonic-gate 
2465*0Sstevel@tonic-gate 	xt_one(cpuid, vtag_flushpage_tl1,
2466*0Sstevel@tonic-gate 		(uint64_t)drmach_shutdown_va, (uint64_t)KCONTEXT);
2467*0Sstevel@tonic-gate 
2468*0Sstevel@tonic-gate 	return (0);
2469*0Sstevel@tonic-gate }
2470*0Sstevel@tonic-gate 
2471*0Sstevel@tonic-gate /*
2472*0Sstevel@tonic-gate  * A detaching CPU is xcalled with an xtrap to drmach_cpu_stop_self() after
2473*0Sstevel@tonic-gate  * it has been offlined. The function of this routine is to get the cpu
2474*0Sstevel@tonic-gate  * spinning in a safe place. The requirement is that the system will not
2475*0Sstevel@tonic-gate  * reference anything on the detaching board (memory and i/o is detached
2476*0Sstevel@tonic-gate  * elsewhere) and that the CPU not reference anything on any other board
2477*0Sstevel@tonic-gate  * in the system.  This isolation is required during and after the writes
2478*0Sstevel@tonic-gate  * to the domain masks to remove the board from the domain.
2479*0Sstevel@tonic-gate  *
2480*0Sstevel@tonic-gate  * To accomplish this isolation the following is done:
2481*0Sstevel@tonic-gate  *	1) Create a locked mapping to a location in BBSRAM where
2482*0Sstevel@tonic-gate  *	   the cpu will execute.
2483*0Sstevel@tonic-gate  *	2) Copy the target function (drmach_shutdown_asm) in which
2484*0Sstevel@tonic-gate  *	   the cpu will execute into BBSRAM.
2485*0Sstevel@tonic-gate  *	3) Jump into function with BBSRAM.
2486*0Sstevel@tonic-gate  *	   Function will:
2487*0Sstevel@tonic-gate  *	   3.1) Flush its Ecache (displacement).
2488*0Sstevel@tonic-gate  *	   3.2) Flush its Dcache with HW mechanism.
2489*0Sstevel@tonic-gate  *	   3.3) Flush its Icache with HW mechanism.
2490*0Sstevel@tonic-gate  *	   3.4) Flush all valid and _unlocked_ D-TLB entries.
2491*0Sstevel@tonic-gate  *	   3.5) Flush all valid and _unlocked_ I-TLB entries.
2492*0Sstevel@tonic-gate  *	   3.6) Clear xt_mb to signal completion. Note: cache line is
2493*0Sstevel@tonic-gate  *		recovered by drmach_cpu_poweroff().
2494*0Sstevel@tonic-gate  *	4) Jump into a tight loop.
2495*0Sstevel@tonic-gate  */
2496*0Sstevel@tonic-gate #define	DRMACH_BBSRAM_OFFSET	0x1000
2497*0Sstevel@tonic-gate 
2498*0Sstevel@tonic-gate static void
2499*0Sstevel@tonic-gate drmach_cpu_stop_self(void)
2500*0Sstevel@tonic-gate {
2501*0Sstevel@tonic-gate 	int		cpuid = (int)CPU->cpu_id;
2502*0Sstevel@tonic-gate 	tte_t		tte;
2503*0Sstevel@tonic-gate 	volatile uint_t	*src, *dst;
2504*0Sstevel@tonic-gate 	uint_t		funclen;
2505*0Sstevel@tonic-gate 	uint64_t	bbsram_pa, bbsram_offset;
2506*0Sstevel@tonic-gate 	uint_t		bbsram_pfn;
2507*0Sstevel@tonic-gate 	uint64_t	bbsram_addr;
2508*0Sstevel@tonic-gate 	void		(*bbsram_func)(uint64_t);
2509*0Sstevel@tonic-gate 	extern void	drmach_shutdown_asm(uint64_t);
2510*0Sstevel@tonic-gate 	extern void	drmach_shutdown_asm_end(void);
2511*0Sstevel@tonic-gate 
2512*0Sstevel@tonic-gate 	funclen = (uint_t)drmach_shutdown_asm_end - (uint_t)drmach_shutdown_asm;
2513*0Sstevel@tonic-gate 	ASSERT(funclen <= MMU_PAGESIZE);
2514*0Sstevel@tonic-gate 	/*
2515*0Sstevel@tonic-gate 	 * We'll start from the 0th's base.
2516*0Sstevel@tonic-gate 	 */
2517*0Sstevel@tonic-gate 	bbsram_pa = STARFIRE_UPAID2UPS(cpuid) | STARFIRE_PSI_BASE;
2518*0Sstevel@tonic-gate 	bbsram_offset = bbsram_pa | 0xfe0ULL;
2519*0Sstevel@tonic-gate 	bbsram_pa += ldphysio(bbsram_offset) + DRMACH_BBSRAM_OFFSET;
2520*0Sstevel@tonic-gate 
2521*0Sstevel@tonic-gate 	bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT);
2522*0Sstevel@tonic-gate 
2523*0Sstevel@tonic-gate 	bbsram_addr = (uint64_t)drmach_shutdown_va;
2524*0Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->estack = bbsram_addr + (uint64_t)funclen;
2525*0Sstevel@tonic-gate 
2526*0Sstevel@tonic-gate 	tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) |
2527*0Sstevel@tonic-gate 			TTE_PFN_INTHI(bbsram_pfn);
2528*0Sstevel@tonic-gate 	tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) |
2529*0Sstevel@tonic-gate 			TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT;
2530*0Sstevel@tonic-gate 	sfmmu_dtlb_ld(drmach_shutdown_va, KCONTEXT, &tte);	/* load dtlb */
2531*0Sstevel@tonic-gate 	sfmmu_itlb_ld(drmach_shutdown_va, KCONTEXT, &tte);	/* load itlb */
2532*0Sstevel@tonic-gate 
2533*0Sstevel@tonic-gate 	for (src = (uint_t *)drmach_shutdown_asm, dst = (uint_t *)bbsram_addr;
2534*0Sstevel@tonic-gate 		src < (uint_t *)drmach_shutdown_asm_end; src++, dst++)
2535*0Sstevel@tonic-gate 		*dst = *src;
2536*0Sstevel@tonic-gate 
2537*0Sstevel@tonic-gate 	bbsram_func = (void (*)())bbsram_addr;
2538*0Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->flushaddr = ecache_flushaddr;
2539*0Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->size = (cpunodes[cpuid].ecache_size << 1);
2540*0Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->linesize = cpunodes[cpuid].ecache_linesize;
2541*0Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->physaddr
2542*0Sstevel@tonic-gate 				    = va_to_pa((void *)&drmach_xt_mb[cpuid]);
2543*0Sstevel@tonic-gate 
2544*0Sstevel@tonic-gate 	/*
2545*0Sstevel@tonic-gate 	 * Signal to drmach_cpu_poweroff() is via drmach_xt_mb cleared
2546*0Sstevel@tonic-gate 	 * by asm code
2547*0Sstevel@tonic-gate 	 */
2548*0Sstevel@tonic-gate 
2549*0Sstevel@tonic-gate 	(*bbsram_func)(va_to_pa((void *)drmach_shutdown_asm_mbox));
2550*0Sstevel@tonic-gate }
2551*0Sstevel@tonic-gate 
2552*0Sstevel@tonic-gate static void
2553*0Sstevel@tonic-gate drmach_cpu_shutdown_self(void)
2554*0Sstevel@tonic-gate {
2555*0Sstevel@tonic-gate 	cpu_t		*cp = CPU;
2556*0Sstevel@tonic-gate 	int		cpuid = cp->cpu_id;
2557*0Sstevel@tonic-gate 	extern void	flush_windows(void);
2558*0Sstevel@tonic-gate 
2559*0Sstevel@tonic-gate 	flush_windows();
2560*0Sstevel@tonic-gate 
2561*0Sstevel@tonic-gate 	(void) spl8();
2562*0Sstevel@tonic-gate 
2563*0Sstevel@tonic-gate 	ASSERT(cp->cpu_intr_actv == 0);
2564*0Sstevel@tonic-gate 	ASSERT(cp->cpu_thread == cp->cpu_idle_thread);
2565*0Sstevel@tonic-gate 
2566*0Sstevel@tonic-gate 	cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
2567*0Sstevel@tonic-gate 
2568*0Sstevel@tonic-gate 	drmach_cpu_stop_self();
2569*0Sstevel@tonic-gate 
2570*0Sstevel@tonic-gate 	cmn_err(CE_PANIC, "CPU %d FAILED TO SHUTDOWN", cpuid);
2571*0Sstevel@tonic-gate }
2572*0Sstevel@tonic-gate 
2573*0Sstevel@tonic-gate /* a helper routine to keep the math in one place */
2574*0Sstevel@tonic-gate static processorid_t
2575*0Sstevel@tonic-gate drmach_cpu_calc_id(drmach_device_t *dp)
2576*0Sstevel@tonic-gate {
2577*0Sstevel@tonic-gate 	return (dp->bp->bnum * MAX_CPU_UNITS_PER_BOARD + dp->unum);
2578*0Sstevel@tonic-gate }
2579*0Sstevel@tonic-gate 
2580*0Sstevel@tonic-gate /*
2581*0Sstevel@tonic-gate  * Move bootproc (SIGBCPU) to another cpu.  If dst_cpu is NULL, a
2582*0Sstevel@tonic-gate  * destination cpu is chosen from the set of cpus not located on the
2583*0Sstevel@tonic-gate  * same board as the current bootproc cpu.
2584*0Sstevel@tonic-gate  */
2585*0Sstevel@tonic-gate static sbd_error_t *
2586*0Sstevel@tonic-gate drmach_cpu_juggle_bootproc(drmach_device_t *dst_cpu)
2587*0Sstevel@tonic-gate {
2588*0Sstevel@tonic-gate 	processorid_t	 cpuid;
2589*0Sstevel@tonic-gate 	struct cpu	*cp;
2590*0Sstevel@tonic-gate 	sbd_error_t	*err;
2591*0Sstevel@tonic-gate 	int		 rv;
2592*0Sstevel@tonic-gate 
2593*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
2594*0Sstevel@tonic-gate 
2595*0Sstevel@tonic-gate 	/* dst_cpu is NULL when target cpu is unspecified. So, pick one. */
2596*0Sstevel@tonic-gate 	if (dst_cpu == NULL) {
2597*0Sstevel@tonic-gate 		int avoid_board = DRMACH_CPUID2BNUM(SIGBCPU->cpu_id);
2598*0Sstevel@tonic-gate 		int max_cpuid = MAX_BOARDS * MAX_CPU_UNITS_PER_BOARD;
2599*0Sstevel@tonic-gate 
2600*0Sstevel@tonic-gate 		for (cpuid = 0; cpuid < max_cpuid; cpuid++)
2601*0Sstevel@tonic-gate 			if (DRMACH_CPUID2BNUM(cpuid) != avoid_board) {
2602*0Sstevel@tonic-gate 				cp = cpu_get(cpuid);
2603*0Sstevel@tonic-gate 				if (cp != NULL && cpu_is_online(cp))
2604*0Sstevel@tonic-gate 					break;
2605*0Sstevel@tonic-gate 			}
2606*0Sstevel@tonic-gate 
2607*0Sstevel@tonic-gate 		if (cpuid == max_cpuid) {
2608*0Sstevel@tonic-gate 			err = drerr_new(1, ESTF_JUGGLE, NULL);
2609*0Sstevel@tonic-gate 			return (err);
2610*0Sstevel@tonic-gate 		}
2611*0Sstevel@tonic-gate 
2612*0Sstevel@tonic-gate 		/* else, cp points to the selected target cpu */
2613*0Sstevel@tonic-gate 	} else {
2614*0Sstevel@tonic-gate 		cpuid = drmach_cpu_calc_id(dst_cpu);
2615*0Sstevel@tonic-gate 
2616*0Sstevel@tonic-gate 		if ((cp = cpu_get(cpuid)) == NULL) {
2617*0Sstevel@tonic-gate 			err = drerr_new(1, ESTF_NODEV, "%s::%s",
2618*0Sstevel@tonic-gate 				dst_cpu->bp->cm.name, dst_cpu->cm.name);
2619*0Sstevel@tonic-gate 			return (err);
2620*0Sstevel@tonic-gate 		}
2621*0Sstevel@tonic-gate 
2622*0Sstevel@tonic-gate 		if (cpuid == SIGBCPU->cpu_id) {
2623*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
2624*0Sstevel@tonic-gate 				"SIGBCPU(%d) same as new selection(%d)",
2625*0Sstevel@tonic-gate 				SIGBCPU->cpu_id, cpuid);
2626*0Sstevel@tonic-gate 
2627*0Sstevel@tonic-gate 			/* technically not an error, but a no-op */
2628*0Sstevel@tonic-gate 			return (NULL);
2629*0Sstevel@tonic-gate 		}
2630*0Sstevel@tonic-gate 	}
2631*0Sstevel@tonic-gate 
2632*0Sstevel@tonic-gate 	cmn_err(CE_NOTE, "?relocating SIGBCPU from %d to %d",
2633*0Sstevel@tonic-gate 		SIGBCPU->cpu_id, cpuid);
2634*0Sstevel@tonic-gate 
2635*0Sstevel@tonic-gate 	DRMACH_PR("moving SIGBCPU to CPU %d\n", cpuid);
2636*0Sstevel@tonic-gate 
2637*0Sstevel@tonic-gate 	/*
2638*0Sstevel@tonic-gate 	 * Tell OBP to initialize cvc-offset field of new CPU0
2639*0Sstevel@tonic-gate 	 * so that it's in sync with OBP and cvc_server
2640*0Sstevel@tonic-gate 	 */
2641*0Sstevel@tonic-gate 	prom_starfire_init_console(cpuid);
2642*0Sstevel@tonic-gate 
2643*0Sstevel@tonic-gate 	/*
2644*0Sstevel@tonic-gate 	 * Assign cvc to new cpu0's bbsram for I/O.  This has to be
2645*0Sstevel@tonic-gate 	 * done BEFORE cpu0 is moved via obp, since this logic
2646*0Sstevel@tonic-gate 	 * will cause obp_helper to switch to a different bbsram for
2647*0Sstevel@tonic-gate 	 * cvc I/O.  We don't want cvc writing to a buffer from which
2648*0Sstevel@tonic-gate 	 * nobody will pick up the data!
2649*0Sstevel@tonic-gate 	 */
2650*0Sstevel@tonic-gate 	cvc_assign_iocpu(cpuid);
2651*0Sstevel@tonic-gate 
2652*0Sstevel@tonic-gate 	rv = prom_starfire_move_cpu0(cpuid);
2653*0Sstevel@tonic-gate 
2654*0Sstevel@tonic-gate 	if (rv == 0) {
2655*0Sstevel@tonic-gate 		SIGBCPU = cp;
2656*0Sstevel@tonic-gate 
2657*0Sstevel@tonic-gate 		DRMACH_PR("successfully juggled to CPU %d\n", cpuid);
2658*0Sstevel@tonic-gate 		return (NULL);
2659*0Sstevel@tonic-gate 	} else {
2660*0Sstevel@tonic-gate 		DRMACH_PR("prom error: prom_starfire_move_cpu0(%d) "
2661*0Sstevel@tonic-gate 			"returned %d\n", cpuid, rv);
2662*0Sstevel@tonic-gate 
2663*0Sstevel@tonic-gate 		/*
2664*0Sstevel@tonic-gate 		 * The move failed, hopefully obp_helper is still back
2665*0Sstevel@tonic-gate 		 * at the old bootproc.  Move cvc back there.
2666*0Sstevel@tonic-gate 		 */
2667*0Sstevel@tonic-gate 		cvc_assign_iocpu(SIGBCPU->cpu_id);
2668*0Sstevel@tonic-gate 
2669*0Sstevel@tonic-gate 
2670*0Sstevel@tonic-gate 		err = drerr_new(1, ESTF_MOVESIGB, "CPU %d", cpuid);
2671*0Sstevel@tonic-gate 		return (err);
2672*0Sstevel@tonic-gate 	}
2673*0Sstevel@tonic-gate 	/*NOTREACHED*/
2674*0Sstevel@tonic-gate }
2675*0Sstevel@tonic-gate 
2676*0Sstevel@tonic-gate static sbd_error_t *
2677*0Sstevel@tonic-gate drmach_cpu_release(drmachid_t id)
2678*0Sstevel@tonic-gate {
2679*0Sstevel@tonic-gate 	drmach_device_t	*dp;
2680*0Sstevel@tonic-gate 	processorid_t	 cpuid;
2681*0Sstevel@tonic-gate 	struct cpu	*cp;
2682*0Sstevel@tonic-gate 	sbd_error_t	*err;
2683*0Sstevel@tonic-gate 
2684*0Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
2685*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2686*0Sstevel@tonic-gate 	dp = id;
2687*0Sstevel@tonic-gate 	cpuid = drmach_cpu_calc_id(dp);
2688*0Sstevel@tonic-gate 
2689*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
2690*0Sstevel@tonic-gate 
2691*0Sstevel@tonic-gate 	cp = cpu_get(cpuid);
2692*0Sstevel@tonic-gate 	if (cp == NULL)
2693*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
2694*0Sstevel@tonic-gate 	else if (SIGBCPU->cpu_id == cp->cpu_id)
2695*0Sstevel@tonic-gate 		err = drmach_cpu_juggle_bootproc(NULL);
2696*0Sstevel@tonic-gate 	else
2697*0Sstevel@tonic-gate 		err = NULL;
2698*0Sstevel@tonic-gate 
2699*0Sstevel@tonic-gate 	return (err);
2700*0Sstevel@tonic-gate }
2701*0Sstevel@tonic-gate 
2702*0Sstevel@tonic-gate static sbd_error_t *
2703*0Sstevel@tonic-gate drmach_cpu_status(drmachid_t id, drmach_status_t *stat)
2704*0Sstevel@tonic-gate {
2705*0Sstevel@tonic-gate 	drmach_device_t *dp;
2706*0Sstevel@tonic-gate 
2707*0Sstevel@tonic-gate 	ASSERT(DRMACH_IS_CPU_ID(id));
2708*0Sstevel@tonic-gate 	dp = id;
2709*0Sstevel@tonic-gate 
2710*0Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
2711*0Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
2712*0Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
2713*0Sstevel@tonic-gate 	stat->configured = (cpu_get(drmach_cpu_calc_id(dp)) != NULL);
2714*0Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
2715*0Sstevel@tonic-gate 	stat->busy = dp->busy;
2716*0Sstevel@tonic-gate 	strncpy(stat->type, dp->type, sizeof (stat->type));
2717*0Sstevel@tonic-gate 	stat->info[0] = '\0';
2718*0Sstevel@tonic-gate 
2719*0Sstevel@tonic-gate 	return (NULL);
2720*0Sstevel@tonic-gate }
2721*0Sstevel@tonic-gate 
2722*0Sstevel@tonic-gate sbd_error_t *
2723*0Sstevel@tonic-gate drmach_cpu_disconnect(drmachid_t id)
2724*0Sstevel@tonic-gate {
2725*0Sstevel@tonic-gate 	drmach_device_t	*cpu;
2726*0Sstevel@tonic-gate 	int		 cpuid;
2727*0Sstevel@tonic-gate 	int		 ntries;
2728*0Sstevel@tonic-gate 	int		 p;
2729*0Sstevel@tonic-gate 	u_longlong_t	 pc_addr;
2730*0Sstevel@tonic-gate 	uchar_t		 rvalue;
2731*0Sstevel@tonic-gate 
2732*0Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
2733*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2734*0Sstevel@tonic-gate 	cpu = id;
2735*0Sstevel@tonic-gate 
2736*0Sstevel@tonic-gate 	cpuid = drmach_cpu_calc_id(cpu);
2737*0Sstevel@tonic-gate 	if (SIGBCPU->cpu_id == cpuid) {
2738*0Sstevel@tonic-gate 		/* this cpu is SIGBCPU, can't disconnect */
2739*0Sstevel@tonic-gate 		return (drerr_new(1, ESTF_HASSIGB, "%s::%s",
2740*0Sstevel@tonic-gate 				cpu->bp->cm.name, cpu->cm.name));
2741*0Sstevel@tonic-gate 	}
2742*0Sstevel@tonic-gate 
2743*0Sstevel@tonic-gate 	/*
2744*0Sstevel@tonic-gate 	 * Make sure SIGBST_DETACHED is set before
2745*0Sstevel@tonic-gate 	 * mapping out the sig block.
2746*0Sstevel@tonic-gate 	 */
2747*0Sstevel@tonic-gate 	ntries = drmach_cpu_ntries;
2748*0Sstevel@tonic-gate 	while (!drmach_cpu_obp_is_detached(cpuid) && ntries) {
2749*0Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
2750*0Sstevel@tonic-gate 		ntries--;
2751*0Sstevel@tonic-gate 	}
2752*0Sstevel@tonic-gate 	if (!drmach_cpu_obp_is_detached(cpuid)) {
2753*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "failed to mark cpu %d detached in sigblock",
2754*0Sstevel@tonic-gate 			cpuid);
2755*0Sstevel@tonic-gate 	}
2756*0Sstevel@tonic-gate 
2757*0Sstevel@tonic-gate 	/* map out signature block */
2758*0Sstevel@tonic-gate 	if (CPU_SGN_EXISTS(cpuid)) {
2759*0Sstevel@tonic-gate 		CPU_SGN_MAPOUT(cpuid);
2760*0Sstevel@tonic-gate 	}
2761*0Sstevel@tonic-gate 
2762*0Sstevel@tonic-gate 	/*
2763*0Sstevel@tonic-gate 	 * We now PC IDLE the processor to guarantee we
2764*0Sstevel@tonic-gate 	 * stop any transactions from coming from it.
2765*0Sstevel@tonic-gate 	 */
2766*0Sstevel@tonic-gate 	p = cpu->unum & 1;
2767*0Sstevel@tonic-gate 	pc_addr = STARFIRE_BB_PC_ADDR(cpu->bp->bnum, cpu->unum, 0);
2768*0Sstevel@tonic-gate 
2769*0Sstevel@tonic-gate 	DRMACH_PR("PC idle cpu %d (addr = 0x%llx, port = %d, p = %d)",
2770*0Sstevel@tonic-gate 		drmach_cpu_calc_id(cpu), pc_addr, cpu->unum, p);
2771*0Sstevel@tonic-gate 
2772*0Sstevel@tonic-gate 	rvalue = ldbphysio(pc_addr);
2773*0Sstevel@tonic-gate 	rvalue |= STARFIRE_BB_PC_IDLE(p);
2774*0Sstevel@tonic-gate 	stbphysio(pc_addr, rvalue);
2775*0Sstevel@tonic-gate 	DELAY(50000);
2776*0Sstevel@tonic-gate 
2777*0Sstevel@tonic-gate 	return (NULL);
2778*0Sstevel@tonic-gate }
2779*0Sstevel@tonic-gate 
2780*0Sstevel@tonic-gate sbd_error_t *
2781*0Sstevel@tonic-gate drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid)
2782*0Sstevel@tonic-gate {
2783*0Sstevel@tonic-gate 	drmach_device_t *cpu;
2784*0Sstevel@tonic-gate 
2785*0Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
2786*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2787*0Sstevel@tonic-gate 	cpu = id;
2788*0Sstevel@tonic-gate 
2789*0Sstevel@tonic-gate 	*cpuid = drmach_cpu_calc_id(cpu);
2790*0Sstevel@tonic-gate 	return (NULL);
2791*0Sstevel@tonic-gate }
2792*0Sstevel@tonic-gate 
2793*0Sstevel@tonic-gate sbd_error_t *
2794*0Sstevel@tonic-gate drmach_cpu_get_impl(drmachid_t id, int *ip)
2795*0Sstevel@tonic-gate {
2796*0Sstevel@tonic-gate 	drmach_device_t *cpu;
2797*0Sstevel@tonic-gate 	int		impl;
2798*0Sstevel@tonic-gate 
2799*0Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
2800*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2801*0Sstevel@tonic-gate 
2802*0Sstevel@tonic-gate 	cpu = id;
2803*0Sstevel@tonic-gate 
2804*0Sstevel@tonic-gate 	if (drmach_node_get_prop(cpu->node, "implementation#", &impl) == -1) {
2805*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
2806*0Sstevel@tonic-gate 	}
2807*0Sstevel@tonic-gate 
2808*0Sstevel@tonic-gate 	*ip = impl;
2809*0Sstevel@tonic-gate 
2810*0Sstevel@tonic-gate 	return (NULL);
2811*0Sstevel@tonic-gate }
2812*0Sstevel@tonic-gate 
2813*0Sstevel@tonic-gate void
2814*0Sstevel@tonic-gate drmach_cpu_flush_ecache_sync(void)
2815*0Sstevel@tonic-gate {
2816*0Sstevel@tonic-gate 	ASSERT(curthread->t_bound_cpu == CPU);
2817*0Sstevel@tonic-gate 
2818*0Sstevel@tonic-gate 	/*
2819*0Sstevel@tonic-gate 	 * Now let's flush our ecache thereby removing all references
2820*0Sstevel@tonic-gate 	 * to the target (detaching) memory from all ecache's in
2821*0Sstevel@tonic-gate 	 * system.
2822*0Sstevel@tonic-gate 	 */
2823*0Sstevel@tonic-gate 	cpu_flush_ecache();
2824*0Sstevel@tonic-gate 
2825*0Sstevel@tonic-gate 	/*
2826*0Sstevel@tonic-gate 	 * Delay 100 usec out of paranoia to insure everything
2827*0Sstevel@tonic-gate 	 * (hardware queues) has drained before we start reprogramming
2828*0Sstevel@tonic-gate 	 * the hardware.
2829*0Sstevel@tonic-gate 	 */
2830*0Sstevel@tonic-gate 	DELAY(100);
2831*0Sstevel@tonic-gate }
2832*0Sstevel@tonic-gate 
2833*0Sstevel@tonic-gate sbd_error_t *
2834*0Sstevel@tonic-gate drmach_get_dip(drmachid_t id, dev_info_t **dip)
2835*0Sstevel@tonic-gate {
2836*0Sstevel@tonic-gate 	drmach_device_t	*dp;
2837*0Sstevel@tonic-gate 
2838*0Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
2839*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2840*0Sstevel@tonic-gate 	dp = id;
2841*0Sstevel@tonic-gate 
2842*0Sstevel@tonic-gate 	*dip = drmach_node_get_dip(dp->node);
2843*0Sstevel@tonic-gate 	return (NULL);
2844*0Sstevel@tonic-gate }
2845*0Sstevel@tonic-gate 
2846*0Sstevel@tonic-gate sbd_error_t *
2847*0Sstevel@tonic-gate drmach_io_is_attached(drmachid_t id, int *yes)
2848*0Sstevel@tonic-gate {
2849*0Sstevel@tonic-gate 	drmach_device_t *dp;
2850*0Sstevel@tonic-gate 	dev_info_t	*dip;
2851*0Sstevel@tonic-gate 	int		state;
2852*0Sstevel@tonic-gate 
2853*0Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
2854*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2855*0Sstevel@tonic-gate 	dp = id;
2856*0Sstevel@tonic-gate 
2857*0Sstevel@tonic-gate 	dip = drmach_node_get_dip(dp->node);
2858*0Sstevel@tonic-gate 	if (dip == NULL) {
2859*0Sstevel@tonic-gate 		*yes = 0;
2860*0Sstevel@tonic-gate 		return (NULL);
2861*0Sstevel@tonic-gate 	}
2862*0Sstevel@tonic-gate 
2863*0Sstevel@tonic-gate 	state = ddi_get_devstate(dip);
2864*0Sstevel@tonic-gate 	*yes = ((i_ddi_node_state(dip) >= DS_ATTACHED) ||
2865*0Sstevel@tonic-gate 	    (state == DDI_DEVSTATE_UP));
2866*0Sstevel@tonic-gate 
2867*0Sstevel@tonic-gate 	return (NULL);
2868*0Sstevel@tonic-gate }
2869*0Sstevel@tonic-gate 
2870*0Sstevel@tonic-gate sbd_error_t *
2871*0Sstevel@tonic-gate drmach_io_pre_release(drmachid_t id)
2872*0Sstevel@tonic-gate {
2873*0Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
2874*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2875*0Sstevel@tonic-gate 	return (NULL);
2876*0Sstevel@tonic-gate }
2877*0Sstevel@tonic-gate 
2878*0Sstevel@tonic-gate static sbd_error_t *
2879*0Sstevel@tonic-gate drmach_io_release(drmachid_t id)
2880*0Sstevel@tonic-gate {
2881*0Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
2882*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2883*0Sstevel@tonic-gate 	return (NULL);
2884*0Sstevel@tonic-gate }
2885*0Sstevel@tonic-gate 
2886*0Sstevel@tonic-gate sbd_error_t *
2887*0Sstevel@tonic-gate drmach_io_unrelease(drmachid_t id)
2888*0Sstevel@tonic-gate {
2889*0Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
2890*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2891*0Sstevel@tonic-gate 	return (NULL);
2892*0Sstevel@tonic-gate }
2893*0Sstevel@tonic-gate 
2894*0Sstevel@tonic-gate /*ARGSUSED*/
2895*0Sstevel@tonic-gate sbd_error_t *
2896*0Sstevel@tonic-gate drmach_io_post_release(drmachid_t id)
2897*0Sstevel@tonic-gate {
2898*0Sstevel@tonic-gate 	return (NULL);
2899*0Sstevel@tonic-gate }
2900*0Sstevel@tonic-gate 
2901*0Sstevel@tonic-gate /*ARGSUSED*/
2902*0Sstevel@tonic-gate sbd_error_t *
2903*0Sstevel@tonic-gate drmach_io_post_attach(drmachid_t id)
2904*0Sstevel@tonic-gate {
2905*0Sstevel@tonic-gate 	return (NULL);
2906*0Sstevel@tonic-gate }
2907*0Sstevel@tonic-gate 
2908*0Sstevel@tonic-gate static sbd_error_t *
2909*0Sstevel@tonic-gate drmach_io_status(drmachid_t id, drmach_status_t *stat)
2910*0Sstevel@tonic-gate {
2911*0Sstevel@tonic-gate 	drmach_device_t *dp;
2912*0Sstevel@tonic-gate 	sbd_error_t	*err;
2913*0Sstevel@tonic-gate 	int		 configured;
2914*0Sstevel@tonic-gate 
2915*0Sstevel@tonic-gate 	ASSERT(DRMACH_IS_IO_ID(id));
2916*0Sstevel@tonic-gate 	dp = id;
2917*0Sstevel@tonic-gate 
2918*0Sstevel@tonic-gate 	err = drmach_io_is_attached(id, &configured);
2919*0Sstevel@tonic-gate 	if (err)
2920*0Sstevel@tonic-gate 		return (err);
2921*0Sstevel@tonic-gate 
2922*0Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
2923*0Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
2924*0Sstevel@tonic-gate 	stat->configured = (configured != 0);
2925*0Sstevel@tonic-gate 	stat->busy = dp->busy;
2926*0Sstevel@tonic-gate 	strncpy(stat->type, dp->type, sizeof (stat->type));
2927*0Sstevel@tonic-gate 	stat->info[0] = '\0';
2928*0Sstevel@tonic-gate 
2929*0Sstevel@tonic-gate 	return (NULL);
2930*0Sstevel@tonic-gate }
2931*0Sstevel@tonic-gate 
2932*0Sstevel@tonic-gate static sbd_error_t *
2933*0Sstevel@tonic-gate drmach_mem_new(drmach_device_t *dp)
2934*0Sstevel@tonic-gate {
2935*0Sstevel@tonic-gate 	static sbd_error_t *drmach_mem_release(drmachid_t);
2936*0Sstevel@tonic-gate 	static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *);
2937*0Sstevel@tonic-gate 
2938*0Sstevel@tonic-gate 	dp->unum = 0;
2939*0Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_mem_new;
2940*0Sstevel@tonic-gate 	dp->cm.release = drmach_mem_release;
2941*0Sstevel@tonic-gate 	dp->cm.status = drmach_mem_status;
2942*0Sstevel@tonic-gate 
2943*0Sstevel@tonic-gate 	snprintf(dp->cm.name, sizeof (dp->cm.name), "%s", dp->type);
2944*0Sstevel@tonic-gate 
2945*0Sstevel@tonic-gate 	return (NULL);
2946*0Sstevel@tonic-gate }
2947*0Sstevel@tonic-gate 
2948*0Sstevel@tonic-gate sbd_error_t *
2949*0Sstevel@tonic-gate drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size)
2950*0Sstevel@tonic-gate {
2951*0Sstevel@tonic-gate 	pfn_t		basepfn = (pfn_t)(basepa >> PAGESHIFT);
2952*0Sstevel@tonic-gate 	pgcnt_t		npages = (pgcnt_t)(size >> PAGESHIFT);
2953*0Sstevel@tonic-gate 	pda_handle_t	ph;
2954*0Sstevel@tonic-gate 	int		rv;
2955*0Sstevel@tonic-gate 
2956*0Sstevel@tonic-gate 	ASSERT(size != 0);
2957*0Sstevel@tonic-gate 
2958*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
2959*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2960*0Sstevel@tonic-gate 
2961*0Sstevel@tonic-gate 	kcage_range_lock();
2962*0Sstevel@tonic-gate 	rv = kcage_range_add(basepfn, npages, 1);
2963*0Sstevel@tonic-gate 	kcage_range_unlock();
2964*0Sstevel@tonic-gate 	if (rv == ENOMEM) {
2965*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%lld megabytes not available to kernel cage",
2966*0Sstevel@tonic-gate 			(size == 0 ? 0 : size / MBYTE));
2967*0Sstevel@tonic-gate 	} else if (rv != 0) {
2968*0Sstevel@tonic-gate 		/* catch this in debug kernels */
2969*0Sstevel@tonic-gate 		ASSERT(0);
2970*0Sstevel@tonic-gate 
2971*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "unexpected kcage_range_add"
2972*0Sstevel@tonic-gate 			" return value %d", rv);
2973*0Sstevel@tonic-gate 	}
2974*0Sstevel@tonic-gate 
2975*0Sstevel@tonic-gate 	/*
2976*0Sstevel@tonic-gate 	 * Update the PDA (post2obp) structure with the
2977*0Sstevel@tonic-gate 	 * range of the newly added memory.
2978*0Sstevel@tonic-gate 	 */
2979*0Sstevel@tonic-gate 	ph = drmach_pda_open();
2980*0Sstevel@tonic-gate 	if (ph != NULL) {
2981*0Sstevel@tonic-gate 		pda_mem_add_span(ph, basepa, size);
2982*0Sstevel@tonic-gate 		pda_close(ph);
2983*0Sstevel@tonic-gate 	}
2984*0Sstevel@tonic-gate 
2985*0Sstevel@tonic-gate 	return (NULL);
2986*0Sstevel@tonic-gate }
2987*0Sstevel@tonic-gate 
2988*0Sstevel@tonic-gate sbd_error_t *
2989*0Sstevel@tonic-gate drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size)
2990*0Sstevel@tonic-gate {
2991*0Sstevel@tonic-gate 	drmach_device_t	*mem = id;
2992*0Sstevel@tonic-gate 	pfn_t		basepfn = (pfn_t)(basepa >> PAGESHIFT);
2993*0Sstevel@tonic-gate 	pgcnt_t		npages = (pgcnt_t)(size >> PAGESHIFT);
2994*0Sstevel@tonic-gate 	uint_t		mcreg;
2995*0Sstevel@tonic-gate 	sbd_error_t	*err;
2996*0Sstevel@tonic-gate 	pda_handle_t	ph;
2997*0Sstevel@tonic-gate 	int		rv;
2998*0Sstevel@tonic-gate 
2999*0Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
3000*0Sstevel@tonic-gate 	if (err)
3001*0Sstevel@tonic-gate 		return (err);
3002*0Sstevel@tonic-gate 	else if (mcreg & STARFIRE_MC_INTERLEAVE_MASK) {
3003*0Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
3004*0Sstevel@tonic-gate 				mem->bp->cm.name, mem->cm.name));
3005*0Sstevel@tonic-gate 	}
3006*0Sstevel@tonic-gate 
3007*0Sstevel@tonic-gate 	if (size > 0) {
3008*0Sstevel@tonic-gate 		kcage_range_lock();
3009*0Sstevel@tonic-gate 		rv = kcage_range_delete_post_mem_del(basepfn, npages);
3010*0Sstevel@tonic-gate 		kcage_range_unlock();
3011*0Sstevel@tonic-gate 		if (rv != 0) {
3012*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
3013*0Sstevel@tonic-gate 			    "unexpected kcage_range_delete_post_mem_del"
3014*0Sstevel@tonic-gate 			    " return value %d", rv);
3015*0Sstevel@tonic-gate 			return (DRMACH_INTERNAL_ERROR());
3016*0Sstevel@tonic-gate 		}
3017*0Sstevel@tonic-gate 	}
3018*0Sstevel@tonic-gate 
3019*0Sstevel@tonic-gate 	/*
3020*0Sstevel@tonic-gate 	 * Update the PDA (post2obp) structure with the
3021*0Sstevel@tonic-gate 	 * range of removed memory.
3022*0Sstevel@tonic-gate 	 */
3023*0Sstevel@tonic-gate 	ph = drmach_pda_open();
3024*0Sstevel@tonic-gate 	if (ph != NULL) {
3025*0Sstevel@tonic-gate 		if (size > 0)
3026*0Sstevel@tonic-gate 			pda_mem_del_span(ph, basepa, size);
3027*0Sstevel@tonic-gate 
3028*0Sstevel@tonic-gate 		/* update PDA to board's new mc register settings */
3029*0Sstevel@tonic-gate 		pda_mem_sync(ph, mem->bp->bnum, 0);
3030*0Sstevel@tonic-gate 
3031*0Sstevel@tonic-gate 		pda_close(ph);
3032*0Sstevel@tonic-gate 	}
3033*0Sstevel@tonic-gate 
3034*0Sstevel@tonic-gate 	return (NULL);
3035*0Sstevel@tonic-gate }
3036*0Sstevel@tonic-gate 
3037*0Sstevel@tonic-gate /* support routine for enable and disable */
3038*0Sstevel@tonic-gate static sbd_error_t *
3039*0Sstevel@tonic-gate drmach_mem_update_interconnect(drmachid_t id, uint_t mcreg)
3040*0Sstevel@tonic-gate {
3041*0Sstevel@tonic-gate 	drmach_device_t	*dp;
3042*0Sstevel@tonic-gate 	pda_handle_t	 ph;
3043*0Sstevel@tonic-gate 	int		 b;
3044*0Sstevel@tonic-gate 
3045*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
3046*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3047*0Sstevel@tonic-gate 	dp = id;
3048*0Sstevel@tonic-gate 
3049*0Sstevel@tonic-gate 	ph = drmach_pda_open();
3050*0Sstevel@tonic-gate 	if (ph == NULL)
3051*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
3052*0Sstevel@tonic-gate 
3053*0Sstevel@tonic-gate 	for (b = 0; b < MAX_BOARDS; b++) {
3054*0Sstevel@tonic-gate 		int		p;
3055*0Sstevel@tonic-gate 		int		rv;
3056*0Sstevel@tonic-gate 		ushort_t	bda_proc, bda_ioc;
3057*0Sstevel@tonic-gate 		board_desc_t	*bdesc;
3058*0Sstevel@tonic-gate 
3059*0Sstevel@tonic-gate 		if (pda_board_present(ph, b) == 0)
3060*0Sstevel@tonic-gate 			continue;
3061*0Sstevel@tonic-gate 
3062*0Sstevel@tonic-gate 		bdesc = (board_desc_t *)pda_get_board_info(ph, b);
3063*0Sstevel@tonic-gate 
3064*0Sstevel@tonic-gate 		/*
3065*0Sstevel@tonic-gate 		 * Update PCs for CPUs.
3066*0Sstevel@tonic-gate 		 */
3067*0Sstevel@tonic-gate 
3068*0Sstevel@tonic-gate 		/* make sure definition in platmod is in sync with pda */
3069*0Sstevel@tonic-gate 		ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD);
3070*0Sstevel@tonic-gate 
3071*0Sstevel@tonic-gate 		bda_proc = bdesc->bda_proc;
3072*0Sstevel@tonic-gate 		for (p = 0; p < MAX_PROCMODS; p++) {
3073*0Sstevel@tonic-gate 			if (BDA_NBL(bda_proc, p) != BDAN_GOOD)
3074*0Sstevel@tonic-gate 				continue;
3075*0Sstevel@tonic-gate 
3076*0Sstevel@tonic-gate 			rv = pc_madr_add(b, dp->bp->bnum, p, mcreg);
3077*0Sstevel@tonic-gate 			if (rv) {
3078*0Sstevel@tonic-gate 				pda_close(ph);
3079*0Sstevel@tonic-gate 				return (DRMACH_INTERNAL_ERROR());
3080*0Sstevel@tonic-gate 			}
3081*0Sstevel@tonic-gate 		}
3082*0Sstevel@tonic-gate 
3083*0Sstevel@tonic-gate 		/*
3084*0Sstevel@tonic-gate 		 * Update PCs for IOCs.
3085*0Sstevel@tonic-gate 		 */
3086*0Sstevel@tonic-gate 
3087*0Sstevel@tonic-gate 		/* make sure definition in platmod is in sync with pda */
3088*0Sstevel@tonic-gate 		ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD);
3089*0Sstevel@tonic-gate 
3090*0Sstevel@tonic-gate 		bda_ioc = bdesc->bda_ioc;
3091*0Sstevel@tonic-gate 		for (p = 0; p < MAX_IOCS; p++) {
3092*0Sstevel@tonic-gate 			if (BDA_NBL(bda_ioc, p) != BDAN_GOOD)
3093*0Sstevel@tonic-gate 				continue;
3094*0Sstevel@tonic-gate 
3095*0Sstevel@tonic-gate 			rv = pc_madr_add(b, dp->bp->bnum, p + 4, mcreg);
3096*0Sstevel@tonic-gate 			if (rv) {
3097*0Sstevel@tonic-gate 				pda_close(ph);
3098*0Sstevel@tonic-gate 				return (DRMACH_INTERNAL_ERROR());
3099*0Sstevel@tonic-gate 			}
3100*0Sstevel@tonic-gate 		}
3101*0Sstevel@tonic-gate 	}
3102*0Sstevel@tonic-gate 
3103*0Sstevel@tonic-gate 	pda_close(ph);
3104*0Sstevel@tonic-gate 	return (NULL);
3105*0Sstevel@tonic-gate }
3106*0Sstevel@tonic-gate 
3107*0Sstevel@tonic-gate sbd_error_t *
3108*0Sstevel@tonic-gate drmach_mem_disable(drmachid_t id)
3109*0Sstevel@tonic-gate {
3110*0Sstevel@tonic-gate 	sbd_error_t	*err;
3111*0Sstevel@tonic-gate 	uint_t		 mcreg;
3112*0Sstevel@tonic-gate 
3113*0Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
3114*0Sstevel@tonic-gate 	if (err == NULL) {
3115*0Sstevel@tonic-gate 		ASSERT(mcreg & STARFIRE_MC_MEM_PRESENT_MASK);
3116*0Sstevel@tonic-gate 
3117*0Sstevel@tonic-gate 		/* Turn off presence bit. */
3118*0Sstevel@tonic-gate 		mcreg &= ~STARFIRE_MC_MEM_PRESENT_MASK;
3119*0Sstevel@tonic-gate 
3120*0Sstevel@tonic-gate 		err = drmach_mem_update_interconnect(id, mcreg);
3121*0Sstevel@tonic-gate 		if (err == NULL)
3122*0Sstevel@tonic-gate 			err = drmach_write_mc_asr(id, mcreg);
3123*0Sstevel@tonic-gate 	}
3124*0Sstevel@tonic-gate 
3125*0Sstevel@tonic-gate 	return (err);
3126*0Sstevel@tonic-gate }
3127*0Sstevel@tonic-gate 
3128*0Sstevel@tonic-gate sbd_error_t *
3129*0Sstevel@tonic-gate drmach_mem_enable(drmachid_t id)
3130*0Sstevel@tonic-gate {
3131*0Sstevel@tonic-gate 	sbd_error_t	*err;
3132*0Sstevel@tonic-gate 	uint_t		 mcreg;
3133*0Sstevel@tonic-gate 
3134*0Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
3135*0Sstevel@tonic-gate 	if (err == NULL) {
3136*0Sstevel@tonic-gate 		mcreg |= STARFIRE_MC_MEM_PRESENT_MASK;
3137*0Sstevel@tonic-gate 
3138*0Sstevel@tonic-gate 		err = drmach_write_mc_asr(id, mcreg);
3139*0Sstevel@tonic-gate 		if (err == NULL)
3140*0Sstevel@tonic-gate 			err = drmach_mem_update_interconnect(id, mcreg);
3141*0Sstevel@tonic-gate 	}
3142*0Sstevel@tonic-gate 
3143*0Sstevel@tonic-gate 	return (err);
3144*0Sstevel@tonic-gate }
3145*0Sstevel@tonic-gate 
3146*0Sstevel@tonic-gate sbd_error_t *
3147*0Sstevel@tonic-gate drmach_mem_get_alignment(drmachid_t id, uint64_t *mask)
3148*0Sstevel@tonic-gate {
3149*0Sstevel@tonic-gate 	drmach_device_t	*mem;
3150*0Sstevel@tonic-gate 	sbd_error_t	*err;
3151*0Sstevel@tonic-gate 	dnode_t		 nodeid;
3152*0Sstevel@tonic-gate 
3153*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
3154*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3155*0Sstevel@tonic-gate 	mem = id;
3156*0Sstevel@tonic-gate 
3157*0Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(mem->node);
3158*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
3159*0Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
3160*0Sstevel@tonic-gate 	else {
3161*0Sstevel@tonic-gate 		uint64_t size;
3162*0Sstevel@tonic-gate 
3163*0Sstevel@tonic-gate 		size = mc_get_alignment_mask(nodeid);
3164*0Sstevel@tonic-gate 		if (size == (uint64_t)-1)
3165*0Sstevel@tonic-gate 			err = DRMACH_INTERNAL_ERROR();
3166*0Sstevel@tonic-gate 		else {
3167*0Sstevel@tonic-gate 			*mask = size - 1;
3168*0Sstevel@tonic-gate 			err = NULL;
3169*0Sstevel@tonic-gate 		}
3170*0Sstevel@tonic-gate 	}
3171*0Sstevel@tonic-gate 
3172*0Sstevel@tonic-gate 	return (err);
3173*0Sstevel@tonic-gate }
3174*0Sstevel@tonic-gate 
3175*0Sstevel@tonic-gate sbd_error_t *
3176*0Sstevel@tonic-gate drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa)
3177*0Sstevel@tonic-gate {
3178*0Sstevel@tonic-gate 	sbd_error_t	*err;
3179*0Sstevel@tonic-gate 	uint_t		 mcreg;
3180*0Sstevel@tonic-gate 
3181*0Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
3182*0Sstevel@tonic-gate 	if (err == NULL)
3183*0Sstevel@tonic-gate 		*pa = mc_asr_to_pa(mcreg);
3184*0Sstevel@tonic-gate 
3185*0Sstevel@tonic-gate 	return (err);
3186*0Sstevel@tonic-gate }
3187*0Sstevel@tonic-gate 
3188*0Sstevel@tonic-gate /*
3189*0Sstevel@tonic-gate  * Use of this routine after copy/rename will yield incorrect results,
3190*0Sstevel@tonic-gate  * because the OBP MEMAVAIL property will not correctly reflect the
3191*0Sstevel@tonic-gate  * programming of the MCs.
3192*0Sstevel@tonic-gate  */
3193*0Sstevel@tonic-gate sbd_error_t *
3194*0Sstevel@tonic-gate drmach_mem_get_memlist(drmachid_t id, struct memlist **ml)
3195*0Sstevel@tonic-gate {
3196*0Sstevel@tonic-gate 	drmach_device_t	*mem;
3197*0Sstevel@tonic-gate 	int		rv, i, rlen, rblks;
3198*0Sstevel@tonic-gate 	sbd_error_t	*err;
3199*0Sstevel@tonic-gate 	struct memlist	*mlist;
3200*0Sstevel@tonic-gate 	struct sf_memunit_regspec *rlist;
3201*0Sstevel@tonic-gate 
3202*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
3203*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3204*0Sstevel@tonic-gate 	mem = id;
3205*0Sstevel@tonic-gate 
3206*0Sstevel@tonic-gate 	err = drmach_device_get_proplen(mem, "dr-available", &rlen);
3207*0Sstevel@tonic-gate 	if (err)
3208*0Sstevel@tonic-gate 		return (err);
3209*0Sstevel@tonic-gate 
3210*0Sstevel@tonic-gate 	rlist = kmem_zalloc(rlen, KM_SLEEP);
3211*0Sstevel@tonic-gate 
3212*0Sstevel@tonic-gate 	err = drmach_device_get_prop(mem, "dr-available", rlist);
3213*0Sstevel@tonic-gate 	if (err) {
3214*0Sstevel@tonic-gate 		kmem_free(rlist, rlen);
3215*0Sstevel@tonic-gate 		return (err);
3216*0Sstevel@tonic-gate 	}
3217*0Sstevel@tonic-gate 
3218*0Sstevel@tonic-gate 	mlist = NULL;
3219*0Sstevel@tonic-gate 	rblks = rlen / sizeof (struct sf_memunit_regspec);
3220*0Sstevel@tonic-gate 	for (i = 0; i < rblks; i++) {
3221*0Sstevel@tonic-gate 		uint64_t	addr, size;
3222*0Sstevel@tonic-gate 
3223*0Sstevel@tonic-gate 		addr  = (uint64_t)rlist[i].regspec_addr_hi << 32;
3224*0Sstevel@tonic-gate 		addr |= (uint64_t)rlist[i].regspec_addr_lo;
3225*0Sstevel@tonic-gate 		size  = (uint64_t)rlist[i].regspec_size_hi << 32;
3226*0Sstevel@tonic-gate 		size |= (uint64_t)rlist[i].regspec_size_lo;
3227*0Sstevel@tonic-gate 
3228*0Sstevel@tonic-gate 		mlist = memlist_add_span(mlist, addr, size);
3229*0Sstevel@tonic-gate 	}
3230*0Sstevel@tonic-gate 
3231*0Sstevel@tonic-gate 	kmem_free(rlist, rlen);
3232*0Sstevel@tonic-gate 
3233*0Sstevel@tonic-gate 	/*
3234*0Sstevel@tonic-gate 	 * Make sure the incoming memlist doesn't already
3235*0Sstevel@tonic-gate 	 * intersect with what's present in the system (phys_install).
3236*0Sstevel@tonic-gate 	 */
3237*0Sstevel@tonic-gate 	memlist_read_lock();
3238*0Sstevel@tonic-gate 	rv = memlist_intersect(phys_install, mlist);
3239*0Sstevel@tonic-gate 	memlist_read_unlock();
3240*0Sstevel@tonic-gate 	if (rv) {
3241*0Sstevel@tonic-gate #ifdef DEBUG
3242*0Sstevel@tonic-gate 		DRMACH_PR("OBP derived memlist intersects"
3243*0Sstevel@tonic-gate 			" with phys_install\n");
3244*0Sstevel@tonic-gate 		memlist_dump(mlist);
3245*0Sstevel@tonic-gate 
3246*0Sstevel@tonic-gate 		DRMACH_PR("phys_install memlist:\n");
3247*0Sstevel@tonic-gate 		memlist_dump(phys_install);
3248*0Sstevel@tonic-gate #endif
3249*0Sstevel@tonic-gate 
3250*0Sstevel@tonic-gate 		memlist_delete(mlist);
3251*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
3252*0Sstevel@tonic-gate 	}
3253*0Sstevel@tonic-gate 
3254*0Sstevel@tonic-gate #ifdef DEBUG
3255*0Sstevel@tonic-gate 	DRMACH_PR("OBP derived memlist:");
3256*0Sstevel@tonic-gate 	memlist_dump(mlist);
3257*0Sstevel@tonic-gate #endif
3258*0Sstevel@tonic-gate 
3259*0Sstevel@tonic-gate 	*ml = mlist;
3260*0Sstevel@tonic-gate 	return (NULL);
3261*0Sstevel@tonic-gate }
3262*0Sstevel@tonic-gate 
3263*0Sstevel@tonic-gate sbd_error_t *
3264*0Sstevel@tonic-gate drmach_mem_get_size(drmachid_t id, uint64_t *bytes)
3265*0Sstevel@tonic-gate {
3266*0Sstevel@tonic-gate 	drmach_device_t	*mem;
3267*0Sstevel@tonic-gate 	pda_handle_t	ph;
3268*0Sstevel@tonic-gate 	pgcnt_t		npages;
3269*0Sstevel@tonic-gate 
3270*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
3271*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3272*0Sstevel@tonic-gate 	mem = id;
3273*0Sstevel@tonic-gate 
3274*0Sstevel@tonic-gate 	ph = drmach_pda_open();
3275*0Sstevel@tonic-gate 	if (ph == NULL)
3276*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
3277*0Sstevel@tonic-gate 
3278*0Sstevel@tonic-gate 	npages = pda_get_mem_size(ph, mem->bp->bnum);
3279*0Sstevel@tonic-gate 	*bytes = (uint64_t)npages << PAGESHIFT;
3280*0Sstevel@tonic-gate 
3281*0Sstevel@tonic-gate 	pda_close(ph);
3282*0Sstevel@tonic-gate 	return (NULL);
3283*0Sstevel@tonic-gate }
3284*0Sstevel@tonic-gate 
3285*0Sstevel@tonic-gate sbd_error_t *
3286*0Sstevel@tonic-gate drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes)
3287*0Sstevel@tonic-gate {
3288*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
3289*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3290*0Sstevel@tonic-gate 
3291*0Sstevel@tonic-gate 	*bytes = mc_get_mem_alignment();
3292*0Sstevel@tonic-gate 	return (NULL);
3293*0Sstevel@tonic-gate }
3294*0Sstevel@tonic-gate 
3295*0Sstevel@tonic-gate /* field debugging tool */
3296*0Sstevel@tonic-gate processorid_t drmach_mem_cpu_affinity_nail = 0;
3297*0Sstevel@tonic-gate 
3298*0Sstevel@tonic-gate processorid_t
3299*0Sstevel@tonic-gate drmach_mem_cpu_affinity(drmachid_t id)
3300*0Sstevel@tonic-gate {
3301*0Sstevel@tonic-gate 	drmach_device_t	*mp;
3302*0Sstevel@tonic-gate 	drmach_board_t	*bp;
3303*0Sstevel@tonic-gate 	processorid_t	 cpuid;
3304*0Sstevel@tonic-gate 
3305*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
3306*0Sstevel@tonic-gate 		return (CPU_CURRENT);
3307*0Sstevel@tonic-gate 
3308*0Sstevel@tonic-gate 	if (drmach_mem_cpu_affinity_nail) {
3309*0Sstevel@tonic-gate 		cpuid = drmach_mem_cpu_affinity_nail;
3310*0Sstevel@tonic-gate 
3311*0Sstevel@tonic-gate 		if (cpuid < 0 || cpuid > NCPU)
3312*0Sstevel@tonic-gate 			return (CPU_CURRENT);
3313*0Sstevel@tonic-gate 
3314*0Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
3315*0Sstevel@tonic-gate 		if (cpu[cpuid] == NULL || !CPU_ACTIVE(cpu[cpuid]))
3316*0Sstevel@tonic-gate 			cpuid = CPU_CURRENT;
3317*0Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
3318*0Sstevel@tonic-gate 
3319*0Sstevel@tonic-gate 		return (cpuid);
3320*0Sstevel@tonic-gate 	}
3321*0Sstevel@tonic-gate 
3322*0Sstevel@tonic-gate 	/* try to choose a proc on the target board */
3323*0Sstevel@tonic-gate 	mp = id;
3324*0Sstevel@tonic-gate 	bp = mp->bp;
3325*0Sstevel@tonic-gate 	if (bp->devices) {
3326*0Sstevel@tonic-gate 		int		rv;
3327*0Sstevel@tonic-gate 		int		d_idx;
3328*0Sstevel@tonic-gate 		drmachid_t	d_id;
3329*0Sstevel@tonic-gate 
3330*0Sstevel@tonic-gate 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
3331*0Sstevel@tonic-gate 		while (rv == 0) {
3332*0Sstevel@tonic-gate 			if (DRMACH_IS_CPU_ID(d_id)) {
3333*0Sstevel@tonic-gate 				cpuid = drmach_cpu_calc_id(d_id);
3334*0Sstevel@tonic-gate 
3335*0Sstevel@tonic-gate 				mutex_enter(&cpu_lock);
3336*0Sstevel@tonic-gate 				if (cpu[cpuid] && CPU_ACTIVE(cpu[cpuid])) {
3337*0Sstevel@tonic-gate 					mutex_exit(&cpu_lock);
3338*0Sstevel@tonic-gate 					DRMACH_PR("drmach_mem_cpu_affinity: "
3339*0Sstevel@tonic-gate 					    "selected cpuid=%d\n", cpuid);
3340*0Sstevel@tonic-gate 					return (cpuid);
3341*0Sstevel@tonic-gate 				} else {
3342*0Sstevel@tonic-gate 					mutex_exit(&cpu_lock);
3343*0Sstevel@tonic-gate 				}
3344*0Sstevel@tonic-gate 			}
3345*0Sstevel@tonic-gate 
3346*0Sstevel@tonic-gate 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
3347*0Sstevel@tonic-gate 		}
3348*0Sstevel@tonic-gate 	}
3349*0Sstevel@tonic-gate 
3350*0Sstevel@tonic-gate 	/* otherwise, this proc, wherever it is */
3351*0Sstevel@tonic-gate 	DRMACH_PR("drmach_mem_cpu_affinity: using default CPU_CURRENT\n");
3352*0Sstevel@tonic-gate 
3353*0Sstevel@tonic-gate 	return (CPU_CURRENT);
3354*0Sstevel@tonic-gate }
3355*0Sstevel@tonic-gate 
3356*0Sstevel@tonic-gate static sbd_error_t *
3357*0Sstevel@tonic-gate drmach_mem_release(drmachid_t id)
3358*0Sstevel@tonic-gate {
3359*0Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
3360*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3361*0Sstevel@tonic-gate 	return (NULL);
3362*0Sstevel@tonic-gate }
3363*0Sstevel@tonic-gate 
3364*0Sstevel@tonic-gate static sbd_error_t *
3365*0Sstevel@tonic-gate drmach_mem_status(drmachid_t id, drmach_status_t *stat)
3366*0Sstevel@tonic-gate {
3367*0Sstevel@tonic-gate 	drmach_device_t *dp;
3368*0Sstevel@tonic-gate 	sbd_error_t	*err;
3369*0Sstevel@tonic-gate 	uint64_t	 pa, slice_size;
3370*0Sstevel@tonic-gate 	struct memlist	*ml;
3371*0Sstevel@tonic-gate 
3372*0Sstevel@tonic-gate 	ASSERT(DRMACH_IS_MEM_ID(id));
3373*0Sstevel@tonic-gate 	dp = id;
3374*0Sstevel@tonic-gate 
3375*0Sstevel@tonic-gate 	/* get starting physical address of target memory */
3376*0Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(id, &pa);
3377*0Sstevel@tonic-gate 	if (err)
3378*0Sstevel@tonic-gate 		return (err);
3379*0Sstevel@tonic-gate 
3380*0Sstevel@tonic-gate 	/* round down to slice boundary */
3381*0Sstevel@tonic-gate 	slice_size = mc_get_mem_alignment();
3382*0Sstevel@tonic-gate 	pa &= ~ (slice_size - 1);
3383*0Sstevel@tonic-gate 
3384*0Sstevel@tonic-gate 	/* stop at first span that is in slice */
3385*0Sstevel@tonic-gate 	memlist_read_lock();
3386*0Sstevel@tonic-gate 	for (ml = phys_install; ml; ml = ml->next)
3387*0Sstevel@tonic-gate 		if (ml->address >= pa && ml->address < pa + slice_size)
3388*0Sstevel@tonic-gate 			break;
3389*0Sstevel@tonic-gate 	memlist_read_unlock();
3390*0Sstevel@tonic-gate 
3391*0Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
3392*0Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
3393*0Sstevel@tonic-gate 	stat->configured = (ml != NULL);
3394*0Sstevel@tonic-gate 	stat->busy = dp->busy;
3395*0Sstevel@tonic-gate 	strncpy(stat->type, dp->type, sizeof (stat->type));
3396*0Sstevel@tonic-gate 	stat->info[0] = '\0';
3397*0Sstevel@tonic-gate 
3398*0Sstevel@tonic-gate 	return (NULL);
3399*0Sstevel@tonic-gate }
3400*0Sstevel@tonic-gate 
3401*0Sstevel@tonic-gate static int
3402*0Sstevel@tonic-gate drmach_detach_board(void *arg)
3403*0Sstevel@tonic-gate {
3404*0Sstevel@tonic-gate 	cpuset_t	cset;
3405*0Sstevel@tonic-gate 	int		retval;
3406*0Sstevel@tonic-gate 	drmach_board_t	*bp = (drmach_board_t *)arg;
3407*0Sstevel@tonic-gate 
3408*0Sstevel@tonic-gate 	cset = cpu_ready_set;
3409*0Sstevel@tonic-gate 	promsafe_xc_attention(cset);
3410*0Sstevel@tonic-gate 
3411*0Sstevel@tonic-gate 	retval = prom_starfire_rm_brd(bp->bnum);
3412*0Sstevel@tonic-gate 
3413*0Sstevel@tonic-gate 	xc_dismissed(cset);
3414*0Sstevel@tonic-gate 
3415*0Sstevel@tonic-gate 	return (retval);
3416*0Sstevel@tonic-gate }
3417*0Sstevel@tonic-gate 
3418*0Sstevel@tonic-gate sbd_error_t *
3419*0Sstevel@tonic-gate drmach_board_deprobe(drmachid_t id)
3420*0Sstevel@tonic-gate {
3421*0Sstevel@tonic-gate 	drmach_board_t	*bp;
3422*0Sstevel@tonic-gate 	int		 retval;
3423*0Sstevel@tonic-gate 
3424*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
3425*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3426*0Sstevel@tonic-gate 	bp = id;
3427*0Sstevel@tonic-gate 
3428*0Sstevel@tonic-gate 	cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum);
3429*0Sstevel@tonic-gate 
3430*0Sstevel@tonic-gate 	retval = prom_tree_update(drmach_detach_board, bp);
3431*0Sstevel@tonic-gate 
3432*0Sstevel@tonic-gate 	if (retval == 0)
3433*0Sstevel@tonic-gate 		return (NULL);
3434*0Sstevel@tonic-gate 	else {
3435*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "prom error: prom_starfire_rm_brd(%d) "
3436*0Sstevel@tonic-gate 			"returned %d", bp->bnum, retval);
3437*0Sstevel@tonic-gate 		return (drerr_new(1, ESTF_DEPROBE, "%s", bp->cm.name));
3438*0Sstevel@tonic-gate 	}
3439*0Sstevel@tonic-gate }
3440*0Sstevel@tonic-gate 
3441*0Sstevel@tonic-gate /*ARGSUSED*/
3442*0Sstevel@tonic-gate static sbd_error_t *
3443*0Sstevel@tonic-gate drmach_pt_juggle_bootproc(drmachid_t id, drmach_opts_t *opts)
3444*0Sstevel@tonic-gate {
3445*0Sstevel@tonic-gate 	drmach_device_t	*cpu;
3446*0Sstevel@tonic-gate 	sbd_error_t	*err;
3447*0Sstevel@tonic-gate 
3448*0Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
3449*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3450*0Sstevel@tonic-gate 	cpu = id;
3451*0Sstevel@tonic-gate 
3452*0Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
3453*0Sstevel@tonic-gate 
3454*0Sstevel@tonic-gate 	err = drmach_cpu_juggle_bootproc(cpu);
3455*0Sstevel@tonic-gate 
3456*0Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
3457*0Sstevel@tonic-gate 
3458*0Sstevel@tonic-gate 	return (err);
3459*0Sstevel@tonic-gate }
3460*0Sstevel@tonic-gate 
3461*0Sstevel@tonic-gate /*ARGSUSED*/
3462*0Sstevel@tonic-gate static sbd_error_t *
3463*0Sstevel@tonic-gate drmach_pt_dump_pdainfo(drmachid_t id, drmach_opts_t *opts)
3464*0Sstevel@tonic-gate {
3465*0Sstevel@tonic-gate 	drmach_board_t	*bp;
3466*0Sstevel@tonic-gate 	int		board;
3467*0Sstevel@tonic-gate 	int		i;
3468*0Sstevel@tonic-gate 	pda_handle_t	ph;
3469*0Sstevel@tonic-gate 	board_desc_t	*bdesc;
3470*0Sstevel@tonic-gate 
3471*0Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
3472*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3473*0Sstevel@tonic-gate 	bp = id;
3474*0Sstevel@tonic-gate 	board = bp->bnum;
3475*0Sstevel@tonic-gate 
3476*0Sstevel@tonic-gate 	ph = drmach_pda_open();
3477*0Sstevel@tonic-gate 	if (ph == NULL)
3478*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
3479*0Sstevel@tonic-gate 
3480*0Sstevel@tonic-gate 	if (pda_board_present(ph, board) == 0) {
3481*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "board %d is MISSING\n", board);
3482*0Sstevel@tonic-gate 		pda_close(ph);
3483*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
3484*0Sstevel@tonic-gate 	}
3485*0Sstevel@tonic-gate 
3486*0Sstevel@tonic-gate 	cmn_err(CE_CONT, "board %d is PRESENT\n", board);
3487*0Sstevel@tonic-gate 
3488*0Sstevel@tonic-gate 	bdesc = (board_desc_t *)pda_get_board_info(ph, board);
3489*0Sstevel@tonic-gate 	if (bdesc == NULL) {
3490*0Sstevel@tonic-gate 		cmn_err(CE_CONT,
3491*0Sstevel@tonic-gate 			"no board descriptor found for board %d\n",
3492*0Sstevel@tonic-gate 			board);
3493*0Sstevel@tonic-gate 		pda_close(ph);
3494*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
3495*0Sstevel@tonic-gate 	}
3496*0Sstevel@tonic-gate 
3497*0Sstevel@tonic-gate 	/* make sure definition in platmod is in sync with pda */
3498*0Sstevel@tonic-gate 	ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD);
3499*0Sstevel@tonic-gate 
3500*0Sstevel@tonic-gate 	for (i = 0; i < MAX_PROCMODS; i++) {
3501*0Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_proc, i) == BDAN_GOOD)
3502*0Sstevel@tonic-gate 			cmn_err(CE_CONT,
3503*0Sstevel@tonic-gate 				"proc %d.%d PRESENT\n", board, i);
3504*0Sstevel@tonic-gate 		else
3505*0Sstevel@tonic-gate 			cmn_err(CE_CONT,
3506*0Sstevel@tonic-gate 				"proc %d.%d MISSING\n", board, i);
3507*0Sstevel@tonic-gate 	}
3508*0Sstevel@tonic-gate 
3509*0Sstevel@tonic-gate 	for (i = 0; i < MAX_MGROUPS; i++) {
3510*0Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_mgroup, i) == BDAN_GOOD)
3511*0Sstevel@tonic-gate 			cmn_err(CE_CONT,
3512*0Sstevel@tonic-gate 				"mgroup %d.%d PRESENT\n", board, i);
3513*0Sstevel@tonic-gate 		else
3514*0Sstevel@tonic-gate 			cmn_err(CE_CONT,
3515*0Sstevel@tonic-gate 				"mgroup %d.%d MISSING\n", board, i);
3516*0Sstevel@tonic-gate 	}
3517*0Sstevel@tonic-gate 
3518*0Sstevel@tonic-gate 	/* make sure definition in platmod is in sync with pda */
3519*0Sstevel@tonic-gate 	ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD);
3520*0Sstevel@tonic-gate 
3521*0Sstevel@tonic-gate 	for (i = 0; i < MAX_IOCS; i++) {
3522*0Sstevel@tonic-gate 		int	s;
3523*0Sstevel@tonic-gate 
3524*0Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_ioc, i) == BDAN_GOOD) {
3525*0Sstevel@tonic-gate 			cmn_err(CE_CONT,
3526*0Sstevel@tonic-gate 				"ioc %d.%d PRESENT\n", board, i);
3527*0Sstevel@tonic-gate 			for (s = 0; s < MAX_SLOTS_PER_IOC; s++) {
3528*0Sstevel@tonic-gate 				if (BDA_NBL(bdesc->bda_ios[i], s) != BDAN_GOOD)
3529*0Sstevel@tonic-gate 					continue;
3530*0Sstevel@tonic-gate 				cmn_err(CE_CONT,
3531*0Sstevel@tonic-gate 					"..scard %d.%d.%d PRESENT\n",
3532*0Sstevel@tonic-gate 					board, i, s);
3533*0Sstevel@tonic-gate 			}
3534*0Sstevel@tonic-gate 		} else {
3535*0Sstevel@tonic-gate 			cmn_err(CE_CONT,
3536*0Sstevel@tonic-gate 				"ioc %d.%d MISSING\n",
3537*0Sstevel@tonic-gate 				board, i);
3538*0Sstevel@tonic-gate 		}
3539*0Sstevel@tonic-gate 	}
3540*0Sstevel@tonic-gate 
3541*0Sstevel@tonic-gate 	cmn_err(CE_CONT,
3542*0Sstevel@tonic-gate 		"board %d memsize = %d pages\n",
3543*0Sstevel@tonic-gate 		board, pda_get_mem_size(ph, board));
3544*0Sstevel@tonic-gate 
3545*0Sstevel@tonic-gate 	pda_close(ph);
3546*0Sstevel@tonic-gate 
3547*0Sstevel@tonic-gate 	return (NULL);
3548*0Sstevel@tonic-gate }
3549*0Sstevel@tonic-gate 
3550*0Sstevel@tonic-gate /*ARGSUSED*/
3551*0Sstevel@tonic-gate sbd_error_t *
3552*0Sstevel@tonic-gate drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts)
3553*0Sstevel@tonic-gate {
3554*0Sstevel@tonic-gate 	struct memlist	*ml;
3555*0Sstevel@tonic-gate 	uint64_t	src_pa;
3556*0Sstevel@tonic-gate 	uint64_t	dst_pa;
3557*0Sstevel@tonic-gate 	uint64_t	dst;
3558*0Sstevel@tonic-gate 
3559*0Sstevel@tonic-gate 	dst_pa = va_to_pa(&dst);
3560*0Sstevel@tonic-gate 
3561*0Sstevel@tonic-gate 	memlist_read_lock();
3562*0Sstevel@tonic-gate 	for (ml = phys_install; ml; ml = ml->next) {
3563*0Sstevel@tonic-gate 		uint64_t	nbytes;
3564*0Sstevel@tonic-gate 
3565*0Sstevel@tonic-gate 		src_pa = ml->address;
3566*0Sstevel@tonic-gate 		nbytes = ml->size;
3567*0Sstevel@tonic-gate 
3568*0Sstevel@tonic-gate 		while (nbytes != 0ull) {
3569*0Sstevel@tonic-gate 
3570*0Sstevel@tonic-gate 			/* copy 32 bytes at arc_pa to dst_pa */
3571*0Sstevel@tonic-gate 			bcopy32_il(src_pa, dst_pa);
3572*0Sstevel@tonic-gate 
3573*0Sstevel@tonic-gate 			/* increment by 32 bytes */
3574*0Sstevel@tonic-gate 			src_pa += (4 * sizeof (uint64_t));
3575*0Sstevel@tonic-gate 
3576*0Sstevel@tonic-gate 			/* decrement by 32 bytes */
3577*0Sstevel@tonic-gate 			nbytes -= (4 * sizeof (uint64_t));
3578*0Sstevel@tonic-gate 		}
3579*0Sstevel@tonic-gate 	}
3580*0Sstevel@tonic-gate 	memlist_read_unlock();
3581*0Sstevel@tonic-gate 
3582*0Sstevel@tonic-gate 	return (NULL);
3583*0Sstevel@tonic-gate }
3584*0Sstevel@tonic-gate 
3585*0Sstevel@tonic-gate static struct {
3586*0Sstevel@tonic-gate 	const char	*name;
3587*0Sstevel@tonic-gate 	sbd_error_t	*(*handler)(drmachid_t id, drmach_opts_t *opts);
3588*0Sstevel@tonic-gate } drmach_pt_arr[] = {
3589*0Sstevel@tonic-gate 	{ "juggle",		drmach_pt_juggle_bootproc	},
3590*0Sstevel@tonic-gate 	{ "pda",		drmach_pt_dump_pdainfo		},
3591*0Sstevel@tonic-gate 	{ "readmem",		drmach_pt_readmem		},
3592*0Sstevel@tonic-gate 
3593*0Sstevel@tonic-gate 	/* the following line must always be last */
3594*0Sstevel@tonic-gate 	{ NULL,			NULL				}
3595*0Sstevel@tonic-gate };
3596*0Sstevel@tonic-gate 
3597*0Sstevel@tonic-gate /*ARGSUSED*/
3598*0Sstevel@tonic-gate sbd_error_t *
3599*0Sstevel@tonic-gate drmach_passthru(drmachid_t id, drmach_opts_t *opts)
3600*0Sstevel@tonic-gate {
3601*0Sstevel@tonic-gate 	int		i;
3602*0Sstevel@tonic-gate 	sbd_error_t	*err;
3603*0Sstevel@tonic-gate 
3604*0Sstevel@tonic-gate 	i = 0;
3605*0Sstevel@tonic-gate 	while (drmach_pt_arr[i].name != NULL) {
3606*0Sstevel@tonic-gate 		int len = strlen(drmach_pt_arr[i].name);
3607*0Sstevel@tonic-gate 
3608*0Sstevel@tonic-gate 		if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0)
3609*0Sstevel@tonic-gate 			break;
3610*0Sstevel@tonic-gate 
3611*0Sstevel@tonic-gate 		i += 1;
3612*0Sstevel@tonic-gate 	}
3613*0Sstevel@tonic-gate 
3614*0Sstevel@tonic-gate 	if (drmach_pt_arr[i].name == NULL)
3615*0Sstevel@tonic-gate 		err = drerr_new(0, ESTF_UNKPTCMD, opts->copts);
3616*0Sstevel@tonic-gate 	else
3617*0Sstevel@tonic-gate 		err = (*drmach_pt_arr[i].handler)(id, opts);
3618*0Sstevel@tonic-gate 
3619*0Sstevel@tonic-gate 	return (err);
3620*0Sstevel@tonic-gate }
3621*0Sstevel@tonic-gate 
3622*0Sstevel@tonic-gate sbd_error_t *
3623*0Sstevel@tonic-gate drmach_release(drmachid_t id)
3624*0Sstevel@tonic-gate {
3625*0Sstevel@tonic-gate 	drmach_common_t *cp;
3626*0Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
3627*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3628*0Sstevel@tonic-gate 	cp = id;
3629*0Sstevel@tonic-gate 
3630*0Sstevel@tonic-gate 	return (cp->release(id));
3631*0Sstevel@tonic-gate }
3632*0Sstevel@tonic-gate 
3633*0Sstevel@tonic-gate sbd_error_t *
3634*0Sstevel@tonic-gate drmach_status(drmachid_t id, drmach_status_t *stat)
3635*0Sstevel@tonic-gate {
3636*0Sstevel@tonic-gate 	drmach_common_t *cp;
3637*0Sstevel@tonic-gate 
3638*0Sstevel@tonic-gate 	if (!DRMACH_IS_ID(id))
3639*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_NOTID, NULL));
3640*0Sstevel@tonic-gate 	cp = id;
3641*0Sstevel@tonic-gate 
3642*0Sstevel@tonic-gate 	return (cp->status(id, stat));
3643*0Sstevel@tonic-gate }
3644*0Sstevel@tonic-gate 
3645*0Sstevel@tonic-gate sbd_error_t *
3646*0Sstevel@tonic-gate drmach_unconfigure(drmachid_t id, int flags)
3647*0Sstevel@tonic-gate {
3648*0Sstevel@tonic-gate 	drmach_device_t	*dp;
3649*0Sstevel@tonic-gate 	dnode_t		 nodeid;
3650*0Sstevel@tonic-gate 	dev_info_t	*dip, *fdip = NULL;
3651*0Sstevel@tonic-gate 	uint_t 		ddi_flags;
3652*0Sstevel@tonic-gate 
3653*0Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
3654*0Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
3655*0Sstevel@tonic-gate 
3656*0Sstevel@tonic-gate 	dp = id;
3657*0Sstevel@tonic-gate 
3658*0Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
3659*0Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
3660*0Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
3661*0Sstevel@tonic-gate 
3662*0Sstevel@tonic-gate 	dip = e_ddi_nodeid_to_dip(nodeid);
3663*0Sstevel@tonic-gate 	if (dip == NULL)
3664*0Sstevel@tonic-gate 		return (NULL);
3665*0Sstevel@tonic-gate 
3666*0Sstevel@tonic-gate 	/*
3667*0Sstevel@tonic-gate 	 * Branch already held, so hold acquired in
3668*0Sstevel@tonic-gate 	 * e_ddi_nodeid_to_dip() can be released
3669*0Sstevel@tonic-gate 	 */
3670*0Sstevel@tonic-gate 	ddi_release_devi(dip);
3671*0Sstevel@tonic-gate 
3672*0Sstevel@tonic-gate 	ddi_flags = 0;
3673*0Sstevel@tonic-gate 
3674*0Sstevel@tonic-gate 	if (flags & DRMACH_DEVI_REMOVE)
3675*0Sstevel@tonic-gate 		ddi_flags |= DEVI_BRANCH_DESTROY | DEVI_BRANCH_EVENT;
3676*0Sstevel@tonic-gate 
3677*0Sstevel@tonic-gate 	/*
3678*0Sstevel@tonic-gate 	 * Force flag is no longer necessary. See starcat/io/drmach.c
3679*0Sstevel@tonic-gate 	 * for details.
3680*0Sstevel@tonic-gate 	 */
3681*0Sstevel@tonic-gate 	ASSERT(e_ddi_branch_held(dip));
3682*0Sstevel@tonic-gate 	if (e_ddi_branch_unconfigure(dip, &fdip, ddi_flags)) {
3683*0Sstevel@tonic-gate 		sbd_error_t	*err;
3684*0Sstevel@tonic-gate 		char		*path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
3685*0Sstevel@tonic-gate 
3686*0Sstevel@tonic-gate 		/*
3687*0Sstevel@tonic-gate 		 * If non-NULL, fdip is returned held and must be released.
3688*0Sstevel@tonic-gate 		 */
3689*0Sstevel@tonic-gate 		if (fdip != NULL) {
3690*0Sstevel@tonic-gate 			(void) ddi_pathname(fdip, path);
3691*0Sstevel@tonic-gate 			ndi_rele_devi(fdip);
3692*0Sstevel@tonic-gate 		} else {
3693*0Sstevel@tonic-gate 			(void) ddi_pathname(dip, path);
3694*0Sstevel@tonic-gate 		}
3695*0Sstevel@tonic-gate 
3696*0Sstevel@tonic-gate 		err = drerr_new(1, ESTF_DRVFAIL, path);
3697*0Sstevel@tonic-gate 
3698*0Sstevel@tonic-gate 		kmem_free(path, MAXPATHLEN);
3699*0Sstevel@tonic-gate 
3700*0Sstevel@tonic-gate 		return (err);
3701*0Sstevel@tonic-gate 	}
3702*0Sstevel@tonic-gate 
3703*0Sstevel@tonic-gate 	return (NULL);
3704*0Sstevel@tonic-gate }
3705*0Sstevel@tonic-gate 
3706*0Sstevel@tonic-gate /*
3707*0Sstevel@tonic-gate  * drmach interfaces to legacy Starfire platmod logic
3708*0Sstevel@tonic-gate  * linkage via runtime symbol look up, called from plat_cpu_power*
3709*0Sstevel@tonic-gate  */
3710*0Sstevel@tonic-gate 
3711*0Sstevel@tonic-gate /*
3712*0Sstevel@tonic-gate  * Start up a cpu.  It is possible that we're attempting to restart
3713*0Sstevel@tonic-gate  * the cpu after an UNCONFIGURE in which case the cpu will be
3714*0Sstevel@tonic-gate  * spinning in its cache.  So, all we have to do is wakeup him up.
3715*0Sstevel@tonic-gate  * Under normal circumstances the cpu will be coming from a previous
3716*0Sstevel@tonic-gate  * CONNECT and thus will be spinning in OBP.  In both cases, the
3717*0Sstevel@tonic-gate  * startup sequence is the same.
3718*0Sstevel@tonic-gate  */
3719*0Sstevel@tonic-gate int
3720*0Sstevel@tonic-gate drmach_cpu_poweron(struct cpu *cp)
3721*0Sstevel@tonic-gate {
3722*0Sstevel@tonic-gate 	DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id);
3723*0Sstevel@tonic-gate 
3724*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
3725*0Sstevel@tonic-gate 
3726*0Sstevel@tonic-gate 	if (drmach_cpu_start(cp) != 0)
3727*0Sstevel@tonic-gate 		return (EBUSY);
3728*0Sstevel@tonic-gate 	else
3729*0Sstevel@tonic-gate 		return (0);
3730*0Sstevel@tonic-gate }
3731*0Sstevel@tonic-gate 
3732*0Sstevel@tonic-gate int
3733*0Sstevel@tonic-gate drmach_cpu_poweroff(struct cpu *cp)
3734*0Sstevel@tonic-gate {
3735*0Sstevel@tonic-gate 	int		ntries, cnt;
3736*0Sstevel@tonic-gate 	processorid_t	cpuid = cp->cpu_id;
3737*0Sstevel@tonic-gate 	void		drmach_cpu_shutdown_self(void);
3738*0Sstevel@tonic-gate 
3739*0Sstevel@tonic-gate 	DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id);
3740*0Sstevel@tonic-gate 
3741*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
3742*0Sstevel@tonic-gate 
3743*0Sstevel@tonic-gate 	/*
3744*0Sstevel@tonic-gate 	 * Capture all CPUs (except for detaching proc) to prevent
3745*0Sstevel@tonic-gate 	 * crosscalls to the detaching proc until it has cleared its
3746*0Sstevel@tonic-gate 	 * bit in cpu_ready_set.
3747*0Sstevel@tonic-gate 	 *
3748*0Sstevel@tonic-gate 	 * The CPU's remain paused and the prom_mutex is known to be free.
3749*0Sstevel@tonic-gate 	 * This prevents the x-trap victim from blocking when doing prom
3750*0Sstevel@tonic-gate 	 * IEEE-1275 calls at a high PIL level.
3751*0Sstevel@tonic-gate 	 */
3752*0Sstevel@tonic-gate 	promsafe_pause_cpus();
3753*0Sstevel@tonic-gate 
3754*0Sstevel@tonic-gate 	/*
3755*0Sstevel@tonic-gate 	 * Quiesce interrupts on the target CPU. We do this by setting
3756*0Sstevel@tonic-gate 	 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
3757*0Sstevel@tonic-gate 	 * prevent it from receiving cross calls and cross traps.
3758*0Sstevel@tonic-gate 	 * This prevents the processor from receiving any new soft interrupts.
3759*0Sstevel@tonic-gate 	 */
3760*0Sstevel@tonic-gate 	mp_cpu_quiesce(cp);
3761*0Sstevel@tonic-gate 
3762*0Sstevel@tonic-gate 	/* setup xt_mb, will be cleared by drmach_shutdown_asm when ready */
3763*0Sstevel@tonic-gate 	drmach_xt_mb[cpuid] = 0x80;
3764*0Sstevel@tonic-gate 
3765*0Sstevel@tonic-gate 	xt_one_unchecked(cpuid, (xcfunc_t *)idle_stop_xcall,
3766*0Sstevel@tonic-gate 		(uint64_t)drmach_cpu_shutdown_self, NULL);
3767*0Sstevel@tonic-gate 
3768*0Sstevel@tonic-gate 	ntries = drmach_cpu_ntries;
3769*0Sstevel@tonic-gate 	cnt = 0;
3770*0Sstevel@tonic-gate 	while (drmach_xt_mb[cpuid] && ntries) {
3771*0Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
3772*0Sstevel@tonic-gate 		ntries--;
3773*0Sstevel@tonic-gate 		cnt++;
3774*0Sstevel@tonic-gate 	}
3775*0Sstevel@tonic-gate 
3776*0Sstevel@tonic-gate 	drmach_xt_mb[cpuid] = 0;	/* steal the cache line back */
3777*0Sstevel@tonic-gate 
3778*0Sstevel@tonic-gate 	start_cpus();
3779*0Sstevel@tonic-gate 
3780*0Sstevel@tonic-gate 	DRMACH_PR("waited %d out of %d tries for "
3781*0Sstevel@tonic-gate 		"drmach_cpu_shutdown_self on cpu%d",
3782*0Sstevel@tonic-gate 		drmach_cpu_ntries - ntries, drmach_cpu_ntries, cp->cpu_id);
3783*0Sstevel@tonic-gate 
3784*0Sstevel@tonic-gate 	drmach_cpu_obp_detach(cpuid);
3785*0Sstevel@tonic-gate 
3786*0Sstevel@tonic-gate 	CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
3787*0Sstevel@tonic-gate 
3788*0Sstevel@tonic-gate 	return (0);
3789*0Sstevel@tonic-gate }
3790*0Sstevel@tonic-gate 
3791*0Sstevel@tonic-gate /*ARGSUSED*/
3792*0Sstevel@tonic-gate int
3793*0Sstevel@tonic-gate drmach_verify_sr(dev_info_t *dip, int sflag)
3794*0Sstevel@tonic-gate {
3795*0Sstevel@tonic-gate 	return (0);
3796*0Sstevel@tonic-gate }
3797*0Sstevel@tonic-gate 
3798*0Sstevel@tonic-gate void
3799*0Sstevel@tonic-gate drmach_suspend_last(void)
3800*0Sstevel@tonic-gate {
3801*0Sstevel@tonic-gate }
3802*0Sstevel@tonic-gate 
3803*0Sstevel@tonic-gate void
3804*0Sstevel@tonic-gate drmach_resume_first(void)
3805*0Sstevel@tonic-gate {
3806*0Sstevel@tonic-gate }
3807*0Sstevel@tonic-gate 
3808*0Sstevel@tonic-gate /*
3809*0Sstevel@tonic-gate  * Log a DR sysevent.
3810*0Sstevel@tonic-gate  * Return value: 0 success, non-zero failure.
3811*0Sstevel@tonic-gate  */
3812*0Sstevel@tonic-gate int
3813*0Sstevel@tonic-gate drmach_log_sysevent(int board, char *hint, int flag, int verbose)
3814*0Sstevel@tonic-gate {
3815*0Sstevel@tonic-gate 	sysevent_t			*ev;
3816*0Sstevel@tonic-gate 	sysevent_id_t			eid;
3817*0Sstevel@tonic-gate 	int				rv, km_flag;
3818*0Sstevel@tonic-gate 	sysevent_value_t		evnt_val;
3819*0Sstevel@tonic-gate 	sysevent_attr_list_t		*evnt_attr_list = NULL;
3820*0Sstevel@tonic-gate 	char				attach_pnt[MAXNAMELEN];
3821*0Sstevel@tonic-gate 
3822*0Sstevel@tonic-gate 	km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
3823*0Sstevel@tonic-gate 	attach_pnt[0] = '\0';
3824*0Sstevel@tonic-gate 	if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) {
3825*0Sstevel@tonic-gate 		rv = -1;
3826*0Sstevel@tonic-gate 		goto logexit;
3827*0Sstevel@tonic-gate 	}
3828*0Sstevel@tonic-gate 	if (verbose)
3829*0Sstevel@tonic-gate 		DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n",
3830*0Sstevel@tonic-gate 			    attach_pnt, hint, flag, verbose);
3831*0Sstevel@tonic-gate 
3832*0Sstevel@tonic-gate 	if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE,
3833*0Sstevel@tonic-gate 				    SUNW_KERN_PUB"dr", km_flag)) == NULL) {
3834*0Sstevel@tonic-gate 		rv = -2;
3835*0Sstevel@tonic-gate 		goto logexit;
3836*0Sstevel@tonic-gate 	}
3837*0Sstevel@tonic-gate 	evnt_val.value_type = SE_DATA_TYPE_STRING;
3838*0Sstevel@tonic-gate 	evnt_val.value.sv_string = attach_pnt;
3839*0Sstevel@tonic-gate 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID,
3840*0Sstevel@tonic-gate 				    &evnt_val, km_flag)) != 0)
3841*0Sstevel@tonic-gate 		goto logexit;
3842*0Sstevel@tonic-gate 
3843*0Sstevel@tonic-gate 	evnt_val.value_type = SE_DATA_TYPE_STRING;
3844*0Sstevel@tonic-gate 	evnt_val.value.sv_string = hint;
3845*0Sstevel@tonic-gate 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT,
3846*0Sstevel@tonic-gate 				    &evnt_val, km_flag)) != 0) {
3847*0Sstevel@tonic-gate 		sysevent_free_attr(evnt_attr_list);
3848*0Sstevel@tonic-gate 		goto logexit;
3849*0Sstevel@tonic-gate 	}
3850*0Sstevel@tonic-gate 
3851*0Sstevel@tonic-gate 	(void) sysevent_attach_attributes(ev, evnt_attr_list);
3852*0Sstevel@tonic-gate 
3853*0Sstevel@tonic-gate 	/*
3854*0Sstevel@tonic-gate 	 * Log the event but do not sleep waiting for its
3855*0Sstevel@tonic-gate 	 * delivery. This provides insulation from syseventd.
3856*0Sstevel@tonic-gate 	 */
3857*0Sstevel@tonic-gate 	rv = log_sysevent(ev, SE_NOSLEEP, &eid);
3858*0Sstevel@tonic-gate 
3859*0Sstevel@tonic-gate logexit:
3860*0Sstevel@tonic-gate 	if (ev)
3861*0Sstevel@tonic-gate 		sysevent_free(ev);
3862*0Sstevel@tonic-gate 	if ((rv != 0) && verbose)
3863*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
3864*0Sstevel@tonic-gate 			    "drmach_log_sysevent failed (rv %d) for %s  %s\n",
3865*0Sstevel@tonic-gate 			    rv, attach_pnt, hint);
3866*0Sstevel@tonic-gate 
3867*0Sstevel@tonic-gate 	return (rv);
3868*0Sstevel@tonic-gate }
3869*0Sstevel@tonic-gate 
3870*0Sstevel@tonic-gate /*ARGSUSED*/
3871*0Sstevel@tonic-gate int
3872*0Sstevel@tonic-gate drmach_allow_memrange_modify(drmachid_t id)
3873*0Sstevel@tonic-gate {
3874*0Sstevel@tonic-gate 	return (1);	/* TRUE */
3875*0Sstevel@tonic-gate }
3876