xref: /onnv-gate/usr/src/uts/sun4u/starfire/io/drmach.c (revision 11311:639e7bc0b42f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51366Spetede  * Common Development and Distribution License (the "License").
61366Spetede  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*11311SSurya.Prakki@Sun.COM 
220Sstevel@tonic-gate /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/debug.h>
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/varargs.h>
300Sstevel@tonic-gate #include <sys/errno.h>
310Sstevel@tonic-gate #include <sys/cred.h>
320Sstevel@tonic-gate #include <sys/dditypes.h>
330Sstevel@tonic-gate #include <sys/devops.h>
340Sstevel@tonic-gate #include <sys/modctl.h>
350Sstevel@tonic-gate #include <sys/poll.h>
360Sstevel@tonic-gate #include <sys/conf.h>
370Sstevel@tonic-gate #include <sys/ddi.h>
380Sstevel@tonic-gate #include <sys/sunddi.h>
390Sstevel@tonic-gate #include <sys/sunndi.h>
400Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
410Sstevel@tonic-gate #include <sys/stat.h>
420Sstevel@tonic-gate #include <sys/kmem.h>
430Sstevel@tonic-gate #include <sys/vmem.h>
440Sstevel@tonic-gate #include <sys/processor.h>
450Sstevel@tonic-gate #include <sys/spitregs.h>
460Sstevel@tonic-gate #include <sys/cpuvar.h>
470Sstevel@tonic-gate #include <sys/cpupart.h>
480Sstevel@tonic-gate #include <sys/mem_config.h>
490Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
500Sstevel@tonic-gate #include <sys/systm.h>
510Sstevel@tonic-gate #include <sys/machsystm.h>
520Sstevel@tonic-gate #include <sys/autoconf.h>
530Sstevel@tonic-gate #include <sys/cmn_err.h>
540Sstevel@tonic-gate #include <sys/sysmacros.h>
550Sstevel@tonic-gate #include <sys/x_call.h>
560Sstevel@tonic-gate #include <sys/promif.h>
570Sstevel@tonic-gate #include <sys/prom_plat.h>
580Sstevel@tonic-gate #include <sys/membar.h>
590Sstevel@tonic-gate #include <vm/seg_kmem.h>
600Sstevel@tonic-gate #include <sys/mem_cage.h>
610Sstevel@tonic-gate #include <sys/stack.h>
620Sstevel@tonic-gate #include <sys/archsystm.h>
630Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
640Sstevel@tonic-gate #include <sys/pte.h>
650Sstevel@tonic-gate #include <sys/mmu.h>
660Sstevel@tonic-gate #include <sys/cpu_module.h>
670Sstevel@tonic-gate #include <sys/obpdefs.h>
680Sstevel@tonic-gate #include <sys/note.h>
690Sstevel@tonic-gate 
700Sstevel@tonic-gate #include <sys/starfire.h>	/* plat_max_... decls */
710Sstevel@tonic-gate #include <sys/cvc.h>
720Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h>
730Sstevel@tonic-gate #include <sys/drmach.h>
740Sstevel@tonic-gate #include <sys/dr_util.h>
750Sstevel@tonic-gate #include <sys/pda.h>
760Sstevel@tonic-gate 
770Sstevel@tonic-gate #include <sys/sysevent.h>
780Sstevel@tonic-gate #include <sys/sysevent/dr.h>
790Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 
820Sstevel@tonic-gate extern void		bcopy32_il(uint64_t, uint64_t);
830Sstevel@tonic-gate extern void		flush_ecache_il(
840Sstevel@tonic-gate 				uint64_t physaddr, int size, int linesz);
850Sstevel@tonic-gate extern uint_t		ldphysio_il(uint64_t physaddr);
860Sstevel@tonic-gate extern void		stphysio_il(uint64_t physaddr, uint_t value);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate extern uint64_t		mc_get_mem_alignment(void);
89789Sahrens extern uint64_t		mc_get_asr_addr(pnode_t);
90789Sahrens extern uint64_t		mc_get_idle_addr(pnode_t);
91789Sahrens extern uint64_t		mc_get_alignment_mask(pnode_t);
92789Sahrens extern int		mc_read_asr(pnode_t, uint_t *);
93789Sahrens extern int		mc_write_asr(pnode_t, uint_t);
940Sstevel@tonic-gate extern uint64_t		mc_asr_to_pa(uint_t);
950Sstevel@tonic-gate extern uint_t		mc_pa_to_asr(uint_t, uint64_t);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate extern int		pc_madr_add(int, int, int, int);
980Sstevel@tonic-gate 
990Sstevel@tonic-gate typedef struct {
1000Sstevel@tonic-gate 	struct drmach_node	*node;
1010Sstevel@tonic-gate 	void			*data;
1020Sstevel@tonic-gate } drmach_node_walk_args_t;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate typedef struct drmach_node {
1050Sstevel@tonic-gate 	void		*here;
1060Sstevel@tonic-gate 
107789Sahrens 	pnode_t		 (*get_dnode)(struct drmach_node *node);
1080Sstevel@tonic-gate 	int		 (*walk)(struct drmach_node *node, void *data,
1090Sstevel@tonic-gate 				int (*cb)(drmach_node_walk_args_t *args));
1100Sstevel@tonic-gate } drmach_node_t;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate typedef struct {
1130Sstevel@tonic-gate 	int		 min_index;
1140Sstevel@tonic-gate 	int		 max_index;
1150Sstevel@tonic-gate 	int		 arr_sz;
1160Sstevel@tonic-gate 	drmachid_t	*arr;
1170Sstevel@tonic-gate } drmach_array_t;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate typedef struct {
1200Sstevel@tonic-gate 	void		*isa;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	sbd_error_t	*(*release)(drmachid_t);
1230Sstevel@tonic-gate 	sbd_error_t	*(*status)(drmachid_t, drmach_status_t *);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	char		 name[MAXNAMELEN];
1260Sstevel@tonic-gate } drmach_common_t;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate typedef struct {
1290Sstevel@tonic-gate 	drmach_common_t	 cm;
1300Sstevel@tonic-gate 	int		 bnum;
1310Sstevel@tonic-gate 	int		 assigned;
1320Sstevel@tonic-gate 	int		 powered;
1330Sstevel@tonic-gate 	int		 connect_cpuid;
1340Sstevel@tonic-gate 	int		 cond;
1350Sstevel@tonic-gate 	drmach_node_t	*tree;
1360Sstevel@tonic-gate 	drmach_array_t	*devices;
1370Sstevel@tonic-gate } drmach_board_t;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate typedef struct {
1400Sstevel@tonic-gate 	drmach_common_t	 cm;
1410Sstevel@tonic-gate 	drmach_board_t	*bp;
1420Sstevel@tonic-gate 	int		 unum;
1430Sstevel@tonic-gate 	int		 busy;
1440Sstevel@tonic-gate 	int		 powered;
1450Sstevel@tonic-gate 	const char	*type;
1460Sstevel@tonic-gate 	drmach_node_t	*node;
1470Sstevel@tonic-gate } drmach_device_t;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate typedef struct {
1500Sstevel@tonic-gate 	int		 flags;
1510Sstevel@tonic-gate 	drmach_device_t	*dp;
1520Sstevel@tonic-gate 	sbd_error_t	*err;
1530Sstevel@tonic-gate 	dev_info_t	*dip;
1540Sstevel@tonic-gate } drmach_config_args_t;
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate typedef struct {
1570Sstevel@tonic-gate 	uint64_t	 idle_addr;
1580Sstevel@tonic-gate 	drmach_device_t	*mem;
1590Sstevel@tonic-gate } drmach_mc_idle_script_t;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate typedef struct {
1620Sstevel@tonic-gate 	uint64_t	masr_addr;
1630Sstevel@tonic-gate 	uint_t		masr;
1640Sstevel@tonic-gate 	uint_t		_filler;
1650Sstevel@tonic-gate } drmach_rename_script_t;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate typedef struct {
1680Sstevel@tonic-gate 	void		(*run)(void *arg);
1690Sstevel@tonic-gate 	caddr_t		data;
1700Sstevel@tonic-gate 	pda_handle_t	*ph;
1710Sstevel@tonic-gate 	struct memlist	*c_ml;
1720Sstevel@tonic-gate 	uint64_t	s_copybasepa;
1730Sstevel@tonic-gate 	uint64_t	t_copybasepa;
1740Sstevel@tonic-gate 	drmach_device_t	*restless_mc;	/* diagnostic output */
1750Sstevel@tonic-gate } drmach_copy_rename_program_t;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate typedef enum {
1780Sstevel@tonic-gate 	DO_IDLE,
1790Sstevel@tonic-gate 	DO_UNIDLE,
1800Sstevel@tonic-gate 	DO_PAUSE,
1810Sstevel@tonic-gate 	DO_UNPAUSE
1820Sstevel@tonic-gate } drmach_iopc_op_t;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate typedef struct {
1850Sstevel@tonic-gate 	drmach_board_t	*obj;
1860Sstevel@tonic-gate 	int		 ndevs;
1870Sstevel@tonic-gate 	void		*a;
1880Sstevel@tonic-gate 	sbd_error_t	*(*found)(void *a, const char *, int, drmachid_t);
1890Sstevel@tonic-gate 	sbd_error_t	*err;
1900Sstevel@tonic-gate } drmach_board_cb_data_t;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate static caddr_t		 drmach_shutdown_va;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate static int		 drmach_initialized;
1950Sstevel@tonic-gate static drmach_array_t	*drmach_boards;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate static int		 drmach_cpu_delay = 100;
1980Sstevel@tonic-gate static int		 drmach_cpu_ntries = 50000;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate volatile uchar_t	*drmach_xt_mb;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * Do not change the drmach_shutdown_mbox structure without
2040Sstevel@tonic-gate  * considering the drmach_shutdown_asm assembly language code.
2050Sstevel@tonic-gate  */
2060Sstevel@tonic-gate struct drmach_shutdown_mbox {
2070Sstevel@tonic-gate 	uint64_t	estack;
2080Sstevel@tonic-gate 	uint64_t	flushaddr;
2090Sstevel@tonic-gate 	int		size;
2100Sstevel@tonic-gate 	int		linesize;
2110Sstevel@tonic-gate 	uint64_t	physaddr;
2120Sstevel@tonic-gate };
2130Sstevel@tonic-gate struct drmach_shutdown_mbox	*drmach_shutdown_asm_mbox;
2140Sstevel@tonic-gate static sbd_error_t	*drmach_device_new(drmach_node_t *,
2150Sstevel@tonic-gate 				drmach_board_t *, drmach_device_t **);
2160Sstevel@tonic-gate static sbd_error_t	*drmach_cpu_new(drmach_device_t *);
2170Sstevel@tonic-gate static sbd_error_t	*drmach_mem_new(drmach_device_t *);
2180Sstevel@tonic-gate static sbd_error_t	*drmach_io_new(drmach_device_t *);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate extern struct cpu	*SIGBCPU;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate #ifdef DEBUG
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate #define	DRMACH_PR		if (drmach_debug) printf
2250Sstevel@tonic-gate int drmach_debug = 0;		 /* set to non-zero to enable debug messages */
2260Sstevel@tonic-gate #else
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate #define	DRMACH_PR		_NOTE(CONSTANTCONDITION) if (0) printf
2290Sstevel@tonic-gate #endif /* DEBUG */
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate #define	DRMACH_OBJ(id)		((drmach_common_t *)id)
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate #define	DRMACH_IS_BOARD_ID(id)	\
2340Sstevel@tonic-gate 	((id != 0) &&		\
2350Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new))
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate #define	DRMACH_IS_CPU_ID(id)	\
2380Sstevel@tonic-gate 	((id != 0) &&		\
2390Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new))
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate #define	DRMACH_IS_MEM_ID(id)	\
2420Sstevel@tonic-gate 	((id != 0) &&		\
2430Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_mem_new))
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate #define	DRMACH_IS_IO_ID(id)	\
2460Sstevel@tonic-gate 	((id != 0) &&		\
2470Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate #define	DRMACH_IS_DEVICE_ID(id)					\
2500Sstevel@tonic-gate 	((id != 0) &&						\
2510Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
2520Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
2530Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate #define	DRMACH_IS_ID(id)					\
2560Sstevel@tonic-gate 	((id != 0) &&						\
2570Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new ||	\
2580Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
2590Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
2600Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate #define	DRMACH_CPUID2BNUM(cpuid) \
2630Sstevel@tonic-gate 	((cpuid) / MAX_CPU_UNITS_PER_BOARD)
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate #define	DRMACH_INTERNAL_ERROR() \
2660Sstevel@tonic-gate 	drerr_new(1, ESTF_INTERNAL, drmach_ie_fmt, __LINE__)
2670Sstevel@tonic-gate static char		*drmach_ie_fmt = "drmach.c %d";
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate static struct {
2700Sstevel@tonic-gate 	const char	 *name;
2710Sstevel@tonic-gate 	const char	 *type;
2720Sstevel@tonic-gate 	sbd_error_t	 *(*new)(drmach_device_t *);
2730Sstevel@tonic-gate } name2type[] = {
2740Sstevel@tonic-gate 	{ "SUNW,UltraSPARC",	DRMACH_DEVTYPE_CPU,  drmach_cpu_new },
2750Sstevel@tonic-gate 	{ "mem-unit",		DRMACH_DEVTYPE_MEM,  drmach_mem_new },
2760Sstevel@tonic-gate 	{ "pci",		DRMACH_DEVTYPE_PCI,  drmach_io_new  },
2770Sstevel@tonic-gate 	{ "sbus",		DRMACH_DEVTYPE_SBUS, drmach_io_new  },
2780Sstevel@tonic-gate };
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate /* node types to cleanup when a board is unconfigured */
2810Sstevel@tonic-gate #define	MISC_COUNTER_TIMER_DEVNAME	"counter-timer"
2820Sstevel@tonic-gate #define	MISC_PERF_COUNTER_DEVNAME	"perf-counter"
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /* utility */
2850Sstevel@tonic-gate #define	MBYTE	(1048576ull)
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate  * This is necessary because the CPU support needs
2890Sstevel@tonic-gate  * to call cvc_assign_iocpu.
2900Sstevel@tonic-gate  */
2910Sstevel@tonic-gate #ifndef lint
2921366Spetede char _depends_on[] = "drv/cvc";
2930Sstevel@tonic-gate #endif  /* lint */
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate /*
2960Sstevel@tonic-gate  * drmach autoconfiguration data structures and interfaces
2970Sstevel@tonic-gate  */
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate extern struct mod_ops mod_miscops;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate static struct modlmisc modlmisc = {
3020Sstevel@tonic-gate 	&mod_miscops,
3037799SRichard.Bean@Sun.COM 	"Sun Enterprise 10000 DR"
3040Sstevel@tonic-gate };
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate static struct modlinkage modlinkage = {
3070Sstevel@tonic-gate 	MODREV_1,
3080Sstevel@tonic-gate 	(void *)&modlmisc,
3090Sstevel@tonic-gate 	NULL
3100Sstevel@tonic-gate };
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate static kmutex_t drmach_i_lock;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate int
3150Sstevel@tonic-gate _init(void)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	int err;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	/* check that we have the correct version of obp */
3200Sstevel@tonic-gate 	if (prom_test("SUNW,UE10000,add-brd") != 0) {
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 		cmn_err(CE_WARN, "!OBP/SSP upgrade is required to enable "
3230Sstevel@tonic-gate 		    "DR Functionality");
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 		return (-1);
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	mutex_init(&drmach_i_lock, NULL, MUTEX_DRIVER, NULL);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	drmach_xt_mb = (uchar_t *)vmem_alloc(static_alloc_arena,
3310Sstevel@tonic-gate 	    NCPU * sizeof (uchar_t), VM_SLEEP);
3320Sstevel@tonic-gate 	drmach_shutdown_asm_mbox = (struct drmach_shutdown_mbox *)
3330Sstevel@tonic-gate 	    vmem_alloc(static_alloc_arena, sizeof (struct drmach_shutdown_mbox),
3340Sstevel@tonic-gate 	    VM_SLEEP);
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	if ((err = mod_install(&modlinkage)) != 0) {
3370Sstevel@tonic-gate 		mutex_destroy(&drmach_i_lock);
3380Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_xt_mb,
3390Sstevel@tonic-gate 		    NCPU * sizeof (uchar_t));
3400Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox,
3410Sstevel@tonic-gate 		    sizeof (struct drmach_shutdown_mbox));
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	return (err);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate int
3480Sstevel@tonic-gate _fini(void)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate 	static int drmach_fini(void);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	if (drmach_fini())
3530Sstevel@tonic-gate 		return (DDI_FAILURE);
3540Sstevel@tonic-gate 	else
3550Sstevel@tonic-gate 		return (mod_remove(&modlinkage));
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate int
3590Sstevel@tonic-gate _info(struct modinfo *modinfop)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate 
364789Sahrens static pnode_t
3650Sstevel@tonic-gate drmach_node_obp_get_dnode(drmach_node_t *np)
3660Sstevel@tonic-gate {
367930Smathue 	return ((pnode_t)(uintptr_t)np->here);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate static int
3710Sstevel@tonic-gate drmach_node_obp_walk(drmach_node_t *np, void *data,
3720Sstevel@tonic-gate 		int (*cb)(drmach_node_walk_args_t *args))
3730Sstevel@tonic-gate {
374789Sahrens 	pnode_t			nodeid;
3750Sstevel@tonic-gate 	int			rv;
3760Sstevel@tonic-gate 	drmach_node_walk_args_t	args;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/* initialized args structure for callback */
3790Sstevel@tonic-gate 	args.node = np;
3800Sstevel@tonic-gate 	args.data = data;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	nodeid = prom_childnode(prom_rootnode());
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	/* save our new position with in the tree */
385930Smathue 	np->here = (void *)(uintptr_t)nodeid;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	rv = 0;
3880Sstevel@tonic-gate 	while (nodeid != OBP_NONODE) {
3890Sstevel@tonic-gate 		rv = (*cb)(&args);
3900Sstevel@tonic-gate 		if (rv)
3910Sstevel@tonic-gate 			break;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 		nodeid = prom_nextnode(nodeid);
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		/* save our new position with in the tree */
396930Smathue 		np->here = (void *)(uintptr_t)nodeid;
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	return (rv);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate static drmach_node_t *
4030Sstevel@tonic-gate drmach_node_new(void)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	drmach_node_t *np;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP);
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	np->get_dnode = drmach_node_obp_get_dnode;
4100Sstevel@tonic-gate 	np->walk = drmach_node_obp_walk;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	return (np);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate static void
4160Sstevel@tonic-gate drmach_node_dispose(drmach_node_t *np)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	kmem_free(np, sizeof (*np));
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate static dev_info_t *
4220Sstevel@tonic-gate drmach_node_get_dip(drmach_node_t *np)
4230Sstevel@tonic-gate {
424789Sahrens 	pnode_t nodeid;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
4270Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
4280Sstevel@tonic-gate 		return (NULL);
4290Sstevel@tonic-gate 	else {
4300Sstevel@tonic-gate 		dev_info_t *dip;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 		/* The root node doesn't have to be held */
4330Sstevel@tonic-gate 		dip = e_ddi_nodeid_to_dip(nodeid);
4340Sstevel@tonic-gate 		if (dip) {
4350Sstevel@tonic-gate 			/*
4360Sstevel@tonic-gate 			 * Branch rooted at dip is already held, so release
4370Sstevel@tonic-gate 			 * hold acquired in e_ddi_nodeid_to_dip()
4380Sstevel@tonic-gate 			 */
4390Sstevel@tonic-gate 			ddi_release_devi(dip);
4400Sstevel@tonic-gate 			ASSERT(e_ddi_branch_held(dip));
4410Sstevel@tonic-gate 		}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 		return (dip);
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 	/*NOTREACHED*/
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
448789Sahrens static pnode_t
4490Sstevel@tonic-gate drmach_node_get_dnode(drmach_node_t *np)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	return (np->get_dnode(np));
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate static int
4550Sstevel@tonic-gate drmach_node_walk(drmach_node_t *np, void *param,
4560Sstevel@tonic-gate 		int (*cb)(drmach_node_walk_args_t *args))
4570Sstevel@tonic-gate {
4580Sstevel@tonic-gate 	return (np->walk(np, param, cb));
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate static int
4620Sstevel@tonic-gate drmach_node_get_prop(drmach_node_t *np, char *name, void *buf)
4630Sstevel@tonic-gate {
464789Sahrens 	pnode_t	nodeid;
4650Sstevel@tonic-gate 	int	rv;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
4680Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
4690Sstevel@tonic-gate 		rv = -1;
4700Sstevel@tonic-gate 	else if (prom_getproplen(nodeid, (caddr_t)name) < 0)
4710Sstevel@tonic-gate 		rv = -1;
4720Sstevel@tonic-gate 	else {
4730Sstevel@tonic-gate 		(void) prom_getprop(nodeid, (caddr_t)name, (caddr_t)buf);
4740Sstevel@tonic-gate 		rv = 0;
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	return (rv);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate static int
4810Sstevel@tonic-gate drmach_node_get_proplen(drmach_node_t *np, char *name, int *len)
4820Sstevel@tonic-gate {
483789Sahrens 	pnode_t	 nodeid;
4840Sstevel@tonic-gate 	int	 rv;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
4870Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
4880Sstevel@tonic-gate 		rv = -1;
4890Sstevel@tonic-gate 	else {
4900Sstevel@tonic-gate 		*len = prom_getproplen(nodeid, (caddr_t)name);
4910Sstevel@tonic-gate 		rv = (*len < 0 ? -1 : 0);
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	return (rv);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate static drmachid_t
4980Sstevel@tonic-gate drmach_node_dup(drmach_node_t *np)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	drmach_node_t *dup;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	dup = drmach_node_new();
5030Sstevel@tonic-gate 	dup->here = np->here;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	return (dup);
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate /*
5090Sstevel@tonic-gate  * drmach_array provides convenient array construction, access,
5100Sstevel@tonic-gate  * bounds checking and array destruction logic.
5110Sstevel@tonic-gate  */
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate static drmach_array_t *
5140Sstevel@tonic-gate drmach_array_new(int min_index, int max_index)
5150Sstevel@tonic-gate {
5160Sstevel@tonic-gate 	drmach_array_t *arr;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	arr->arr_sz = (max_index - min_index + 1) * sizeof (void *);
5210Sstevel@tonic-gate 	if (arr->arr_sz > 0) {
5220Sstevel@tonic-gate 		arr->min_index = min_index;
5230Sstevel@tonic-gate 		arr->max_index = max_index;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP);
5260Sstevel@tonic-gate 		return (arr);
5270Sstevel@tonic-gate 	} else {
5280Sstevel@tonic-gate 		kmem_free(arr, sizeof (*arr));
5290Sstevel@tonic-gate 		return (0);
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate static int
5340Sstevel@tonic-gate drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 	if (idx < arr->min_index || idx > arr->max_index)
5370Sstevel@tonic-gate 		return (-1);
5380Sstevel@tonic-gate 	else {
5390Sstevel@tonic-gate 		arr->arr[idx - arr->min_index] = val;
5400Sstevel@tonic-gate 		return (0);
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate 	/*NOTREACHED*/
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate static int
5460Sstevel@tonic-gate drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate 	if (idx < arr->min_index || idx > arr->max_index)
5490Sstevel@tonic-gate 		return (-1);
5500Sstevel@tonic-gate 	else {
5510Sstevel@tonic-gate 		*val = arr->arr[idx - arr->min_index];
5520Sstevel@tonic-gate 		return (0);
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 	/*NOTREACHED*/
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate static int
5580Sstevel@tonic-gate drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate 	int rv;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	*idx = arr->min_index;
5630Sstevel@tonic-gate 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
5640Sstevel@tonic-gate 		*idx += 1;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	return (rv);
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate static int
5700Sstevel@tonic-gate drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	int rv;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	*idx += 1;
5750Sstevel@tonic-gate 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
5760Sstevel@tonic-gate 		*idx += 1;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	return (rv);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate static void
5820Sstevel@tonic-gate drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t))
5830Sstevel@tonic-gate {
5840Sstevel@tonic-gate 	drmachid_t	val;
5850Sstevel@tonic-gate 	int		idx;
5860Sstevel@tonic-gate 	int		rv;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	rv = drmach_array_first(arr, &idx, &val);
5890Sstevel@tonic-gate 	while (rv == 0) {
5900Sstevel@tonic-gate 		(*disposer)(val);
5910Sstevel@tonic-gate 		rv = drmach_array_next(arr, &idx, &val);
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	kmem_free(arr->arr, arr->arr_sz);
5950Sstevel@tonic-gate 	kmem_free(arr, sizeof (*arr));
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate /*ARGSUSED*/
5990Sstevel@tonic-gate static int
600789Sahrens drmach_prom_select(pnode_t nodeid, void *arg, uint_t flags)
6010Sstevel@tonic-gate {
6020Sstevel@tonic-gate 	int			rprop[64];
603789Sahrens 	pnode_t			saved;
6040Sstevel@tonic-gate 	drmach_config_args_t	*ap = (drmach_config_args_t *)arg;
6050Sstevel@tonic-gate 	drmach_device_t		*dp = ap->dp;
6060Sstevel@tonic-gate 	sbd_error_t		*err;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	saved = drmach_node_get_dnode(dp->node);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (nodeid != saved)
6110Sstevel@tonic-gate 		return (DDI_FAILURE);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	if (saved == OBP_NONODE) {
6140Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
6150Sstevel@tonic-gate 		DRERR_SET_C(&ap->err, &err);
6160Sstevel@tonic-gate 		return (DDI_FAILURE);
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	if (prom_getprop(nodeid, OBP_REG, (caddr_t)rprop) <= 0) {
6200Sstevel@tonic-gate 		return (DDI_FAILURE);
6210Sstevel@tonic-gate 	}
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	return (DDI_SUCCESS);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate /*ARGSUSED*/
6270Sstevel@tonic-gate static void
6280Sstevel@tonic-gate drmach_branch_callback(dev_info_t *rdip, void *arg, uint_t flags)
6290Sstevel@tonic-gate {
6300Sstevel@tonic-gate 	drmach_config_args_t	*ap = (drmach_config_args_t *)arg;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	ASSERT(ap->dip == NULL);
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	ap->dip = rdip;
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate sbd_error_t *
6380Sstevel@tonic-gate drmach_configure(drmachid_t id, int flags)
6390Sstevel@tonic-gate {
6400Sstevel@tonic-gate 	drmach_device_t		*dp;
6410Sstevel@tonic-gate 	sbd_error_t		*err;
6420Sstevel@tonic-gate 	drmach_config_args_t	ca;
6430Sstevel@tonic-gate 	devi_branch_t		b = {0};
6440Sstevel@tonic-gate 	dev_info_t		*fdip = NULL;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
6470Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
6480Sstevel@tonic-gate 	dp = id;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	ca.dp = dp;
6510Sstevel@tonic-gate 	ca.flags = flags;
6520Sstevel@tonic-gate 	ca.err = NULL;		/* will be set if error detected */
6530Sstevel@tonic-gate 	ca.dip = NULL;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	b.arg = &ca;
6560Sstevel@tonic-gate 	b.type = DEVI_BRANCH_PROM;
6570Sstevel@tonic-gate 	b.create.prom_branch_select = drmach_prom_select;
6580Sstevel@tonic-gate 	b.devi_branch_callback = drmach_branch_callback;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	if (e_ddi_branch_create(ddi_root_node(), &b, &fdip,
6610Sstevel@tonic-gate 	    DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE) != 0) {
6620Sstevel@tonic-gate 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 		/*
6650Sstevel@tonic-gate 		 * If non-NULL, fdip is returned held and must be released.
6660Sstevel@tonic-gate 		 */
6670Sstevel@tonic-gate 		if (fdip != NULL) {
6680Sstevel@tonic-gate 			(void) ddi_pathname(fdip, path);
6690Sstevel@tonic-gate 			ddi_release_devi(fdip);
6700Sstevel@tonic-gate 		} else if (ca.dip != NULL) {
6710Sstevel@tonic-gate 			/* safe to call ddi_pathname as dip already held */
6720Sstevel@tonic-gate 			(void) ddi_pathname(ca.dip, path);
6730Sstevel@tonic-gate 		} else {
6740Sstevel@tonic-gate 			(void) strcpy(path, "<none>");
6750Sstevel@tonic-gate 		}
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 		err = drerr_new(1, ESTF_DRVFAIL, path);
6780Sstevel@tonic-gate 		DRERR_SET_C(&ca.err, &err);
6790Sstevel@tonic-gate 		kmem_free(path, MAXPATHLEN);
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	return (ca.err);
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate static sbd_error_t *
6860Sstevel@tonic-gate drmach_device_new(drmach_node_t *node,
6870Sstevel@tonic-gate 	drmach_board_t *bp, drmach_device_t **dpp)
6880Sstevel@tonic-gate {
6890Sstevel@tonic-gate 	int		 i;
6900Sstevel@tonic-gate 	int		 rv;
6910Sstevel@tonic-gate 	drmach_device_t	*dp;
6920Sstevel@tonic-gate 	sbd_error_t	*err;
6930Sstevel@tonic-gate 	char		 name[OBP_MAXDRVNAME];
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	rv = drmach_node_get_prop(node, OBP_NAME, name);
6960Sstevel@tonic-gate 	if (rv) {
6970Sstevel@tonic-gate 		/* every node is expected to have a name */
6980Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROP,
6990Sstevel@tonic-gate 			"PROM Node 0x%x: property %s",
7000Sstevel@tonic-gate 			(uint_t)node->get_dnode(node), OBP_NAME);
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 		return (err);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/*
7060Sstevel@tonic-gate 	 * The node currently being examined is not listed in the name2type[]
7070Sstevel@tonic-gate 	 * array.  In this case, the node is no interest to drmach.  Both
7080Sstevel@tonic-gate 	 * dp and err are initialized here to yield nothing (no device or
7090Sstevel@tonic-gate 	 * error structure) for this case.
7100Sstevel@tonic-gate 	 */
7110Sstevel@tonic-gate 	for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++)
7120Sstevel@tonic-gate 		if (strcmp(name2type[i].name, name) == 0)
7130Sstevel@tonic-gate 			break;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	if (i < sizeof (name2type) / sizeof (name2type[0])) {
7160Sstevel@tonic-gate 		dp = kmem_zalloc(sizeof (drmach_device_t), KM_SLEEP);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 		dp->bp = bp;
7190Sstevel@tonic-gate 		dp->unum = -1;
7200Sstevel@tonic-gate 		dp->node = drmach_node_dup(node);
7210Sstevel@tonic-gate 		dp->type = name2type[i].type;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 		err = (name2type[i].new)(dp);
7240Sstevel@tonic-gate 		if (err) {
7250Sstevel@tonic-gate 			drmach_node_dispose(node);
7260Sstevel@tonic-gate 			kmem_free(dp, sizeof (*dp));
7270Sstevel@tonic-gate 			dp = NULL;
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		*dpp = dp;
7310Sstevel@tonic-gate 		return (err);
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	/*
7350Sstevel@tonic-gate 	 * The node currently being examined is not listed in the name2type[]
7360Sstevel@tonic-gate 	 * array.  In this case, the node is no interest to drmach.  Both
7370Sstevel@tonic-gate 	 * dp and err are initialized here to yield nothing (no device or
7380Sstevel@tonic-gate 	 * error structure) for this case.
7390Sstevel@tonic-gate 	 */
7400Sstevel@tonic-gate 	*dpp = NULL;
7410Sstevel@tonic-gate 	return (NULL);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate static void
7450Sstevel@tonic-gate drmach_device_dispose(drmachid_t id)
7460Sstevel@tonic-gate {
7470Sstevel@tonic-gate 	drmach_device_t *self = id;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if (self->node)
7500Sstevel@tonic-gate 		drmach_node_dispose(self->node);
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	kmem_free(self, sizeof (*self));
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate static sbd_error_t *
7560Sstevel@tonic-gate drmach_device_get_prop(drmach_device_t *dp, char *name, void *buf)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
7590Sstevel@tonic-gate 	int		 rv;
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	rv = drmach_node_get_prop(dp->node, name, buf);
7620Sstevel@tonic-gate 	if (rv) {
7630Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROP,
7640Sstevel@tonic-gate 			"%s::%s: property %s",
7650Sstevel@tonic-gate 			dp->bp->cm.name, dp->cm.name, name);
7660Sstevel@tonic-gate 	}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	return (err);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate static sbd_error_t *
7720Sstevel@tonic-gate drmach_device_get_proplen(drmach_device_t *dp, char *name, int *len)
7730Sstevel@tonic-gate {
7740Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
7750Sstevel@tonic-gate 	int		 rv;
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	rv = drmach_node_get_proplen(dp->node, name, len);
7780Sstevel@tonic-gate 	if (rv) {
7790Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROPLEN,
7800Sstevel@tonic-gate 			"%s::%s: property %s",
7810Sstevel@tonic-gate 			dp->bp->cm.name, dp->cm.name, name);
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	return (err);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate static drmach_board_t *
7880Sstevel@tonic-gate drmach_board_new(int bnum)
7890Sstevel@tonic-gate {
7900Sstevel@tonic-gate 	static sbd_error_t *drmach_board_release(drmachid_t);
7910Sstevel@tonic-gate 	static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	drmach_board_t	*bp;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP);
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	bp->cm.isa = (void *)drmach_board_new;
7980Sstevel@tonic-gate 	bp->cm.release = drmach_board_release;
7990Sstevel@tonic-gate 	bp->cm.status = drmach_board_status;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	(void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name));
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	bp->bnum = bnum;
8040Sstevel@tonic-gate 	bp->devices = NULL;
8050Sstevel@tonic-gate 	bp->connect_cpuid = -1;
8060Sstevel@tonic-gate 	bp->tree = drmach_node_new();
8070Sstevel@tonic-gate 	bp->assigned = !drmach_initialized;
8080Sstevel@tonic-gate 	bp->powered = !drmach_initialized;
8090Sstevel@tonic-gate 
810*11311SSurya.Prakki@Sun.COM 	(void) drmach_array_set(drmach_boards, bnum, bp);
8110Sstevel@tonic-gate 	return (bp);
8120Sstevel@tonic-gate }
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate static void
8150Sstevel@tonic-gate drmach_board_dispose(drmachid_t id)
8160Sstevel@tonic-gate {
8170Sstevel@tonic-gate 	drmach_board_t *bp;
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	ASSERT(DRMACH_IS_BOARD_ID(id));
8200Sstevel@tonic-gate 	bp = id;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	if (bp->tree)
8230Sstevel@tonic-gate 		drmach_node_dispose(bp->tree);
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	if (bp->devices)
8260Sstevel@tonic-gate 		drmach_array_dispose(bp->devices, drmach_device_dispose);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	kmem_free(bp, sizeof (*bp));
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate static sbd_error_t *
8320Sstevel@tonic-gate drmach_board_status(drmachid_t id, drmach_status_t *stat)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
8350Sstevel@tonic-gate 	drmach_board_t	*bp;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
8380Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
8390Sstevel@tonic-gate 	bp = id;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	stat->assigned = bp->assigned;
8420Sstevel@tonic-gate 	stat->powered = bp->powered;
8430Sstevel@tonic-gate 	stat->busy = 0;			/* assume not busy */
8440Sstevel@tonic-gate 	stat->configured = 0;		/* assume not configured */
8450Sstevel@tonic-gate 	stat->empty = 0;
8460Sstevel@tonic-gate 	stat->cond = bp->cond = SBD_COND_OK;
847*11311SSurya.Prakki@Sun.COM 	(void) strncpy(stat->type, "System Brd", sizeof (stat->type));
8480Sstevel@tonic-gate 	stat->info[0] = '\0';
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	if (bp->devices) {
8510Sstevel@tonic-gate 		int		 rv;
8520Sstevel@tonic-gate 		int		 d_idx;
8530Sstevel@tonic-gate 		drmachid_t	 d_id;
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
8560Sstevel@tonic-gate 		while (rv == 0) {
8570Sstevel@tonic-gate 			drmach_status_t	d_stat;
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 			err = drmach_status(d_id, &d_stat);
8600Sstevel@tonic-gate 			if (err)
8610Sstevel@tonic-gate 				break;
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 			stat->busy |= d_stat.busy;
8640Sstevel@tonic-gate 			stat->configured |= d_stat.configured;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
8670Sstevel@tonic-gate 		}
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	return (err);
8710Sstevel@tonic-gate }
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate /* a simple routine to reduce redundancy of this common logic */
8740Sstevel@tonic-gate static pda_handle_t
8750Sstevel@tonic-gate drmach_pda_open(void)
8760Sstevel@tonic-gate {
8770Sstevel@tonic-gate 	pda_handle_t ph;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	ph = pda_open();
8800Sstevel@tonic-gate 	if (ph == NULL) {
8810Sstevel@tonic-gate 		/* catch in debug kernels */
8820Sstevel@tonic-gate 		ASSERT(0);
8830Sstevel@tonic-gate 		cmn_err(CE_WARN, "pda_open failed");
8840Sstevel@tonic-gate 	}
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	return (ph);
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate #ifdef DEBUG
8900Sstevel@tonic-gate int drmach_init_break = 0;
8910Sstevel@tonic-gate #endif
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate static int
8940Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg)
8950Sstevel@tonic-gate {
8960Sstevel@tonic-gate 	int	i;
8970Sstevel@tonic-gate 	int	*holdp = (int *)arg;
8980Sstevel@tonic-gate 	char	*name = ddi_node_name(rdip);
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	/*
9010Sstevel@tonic-gate 	 * For Starfire, we must be children of the root devinfo node
9020Sstevel@tonic-gate 	 */
9030Sstevel@tonic-gate 	ASSERT(ddi_get_parent(rdip) == ddi_root_node());
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++)
9060Sstevel@tonic-gate 		if (strcmp(name2type[i].name, name) == 0)
9070Sstevel@tonic-gate 			break;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	if (i == sizeof (name2type) / sizeof (name2type[0])) {
9100Sstevel@tonic-gate 		/* Not of interest to us */
9110Sstevel@tonic-gate 		return (DDI_WALK_PRUNECHILD);
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	if (*holdp) {
9150Sstevel@tonic-gate 		ASSERT(!e_ddi_branch_held(rdip));
9160Sstevel@tonic-gate 		e_ddi_branch_hold(rdip);
9170Sstevel@tonic-gate 	} else {
9180Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(rdip));
9190Sstevel@tonic-gate 		e_ddi_branch_rele(rdip);
9200Sstevel@tonic-gate 	}
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	return (DDI_WALK_PRUNECHILD);
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate static int
9260Sstevel@tonic-gate drmach_init(void)
9270Sstevel@tonic-gate {
928789Sahrens 	pnode_t		nodeid;
9290Sstevel@tonic-gate 	dev_info_t	*rdip;
9300Sstevel@tonic-gate 	int		hold, circ;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate #ifdef DEBUG
9330Sstevel@tonic-gate 	if (drmach_init_break)
9340Sstevel@tonic-gate 		debug_enter("drmach_init: drmach_init_break set\n");
9350Sstevel@tonic-gate #endif
9360Sstevel@tonic-gate 	mutex_enter(&drmach_i_lock);
9370Sstevel@tonic-gate 	if (drmach_initialized) {
9380Sstevel@tonic-gate 		mutex_exit(&drmach_i_lock);
9390Sstevel@tonic-gate 		return (0);
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	drmach_boards = drmach_array_new(0, MAX_BOARDS - 1);
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	nodeid = prom_childnode(prom_rootnode());
9450Sstevel@tonic-gate 	do {
9460Sstevel@tonic-gate 		int		 bnum;
9470Sstevel@tonic-gate 		drmachid_t	 id;
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 		bnum = -1;
9500Sstevel@tonic-gate 		(void) prom_getprop(nodeid, OBP_BOARDNUM, (caddr_t)&bnum);
9510Sstevel@tonic-gate 		if (bnum == -1)
9520Sstevel@tonic-gate 			continue;
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 		if (drmach_array_get(drmach_boards, bnum, &id) == -1) {
9550Sstevel@tonic-gate 			cmn_err(CE_WARN, "OBP node 0x%x has"
9560Sstevel@tonic-gate 				" invalid property value, %s=%d",
9570Sstevel@tonic-gate 				nodeid, OBP_BOARDNUM, bnum);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 			/* clean up */
9600Sstevel@tonic-gate 			drmach_array_dispose(
9610Sstevel@tonic-gate 				drmach_boards, drmach_board_dispose);
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 			mutex_exit(&drmach_i_lock);
9640Sstevel@tonic-gate 			return (-1);
9650Sstevel@tonic-gate 		} else if (id == NULL)
9660Sstevel@tonic-gate 			(void) drmach_board_new(bnum);
9670Sstevel@tonic-gate 	} while ((nodeid = prom_nextnode(nodeid)) != OBP_NONODE);
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	drmach_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	/*
9720Sstevel@tonic-gate 	 * Walk immediate children of devinfo root node and hold
9730Sstevel@tonic-gate 	 * all devinfo branches of interest.
9740Sstevel@tonic-gate 	 */
9750Sstevel@tonic-gate 	hold = 1;
9760Sstevel@tonic-gate 	rdip = ddi_root_node();
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	ndi_devi_enter(rdip, &circ);
9790Sstevel@tonic-gate 	ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold);
9800Sstevel@tonic-gate 	ndi_devi_exit(rdip, circ);
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	drmach_initialized = 1;
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	mutex_exit(&drmach_i_lock);
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	return (0);
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate static int
9900Sstevel@tonic-gate drmach_fini(void)
9910Sstevel@tonic-gate {
9920Sstevel@tonic-gate 	dev_info_t	*rdip;
9930Sstevel@tonic-gate 	int		hold, circ;
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	if (drmach_initialized) {
9960Sstevel@tonic-gate 		int		busy = 0;
9970Sstevel@tonic-gate 		int		rv;
9980Sstevel@tonic-gate 		int		idx;
9990Sstevel@tonic-gate 		drmachid_t	id;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 		ASSERT(drmach_boards != NULL);
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 		rv = drmach_array_first(drmach_boards, &idx, &id);
10040Sstevel@tonic-gate 		while (rv == 0) {
10050Sstevel@tonic-gate 			sbd_error_t	*err;
10060Sstevel@tonic-gate 			drmach_status_t stat;
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 			err = drmach_board_status(id, &stat);
10090Sstevel@tonic-gate 			if (err) {
10100Sstevel@tonic-gate 				/* catch in debug kernels */
10110Sstevel@tonic-gate 				ASSERT(0);
10120Sstevel@tonic-gate 				sbd_err_clear(&err);
10130Sstevel@tonic-gate 				busy = 1;
10140Sstevel@tonic-gate 			} else
10150Sstevel@tonic-gate 				busy |= stat.busy;
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 			rv = drmach_array_next(drmach_boards, &idx, &id);
10180Sstevel@tonic-gate 		}
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 		if (busy)
10210Sstevel@tonic-gate 			return (-1);
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 		drmach_array_dispose(drmach_boards, drmach_board_dispose);
10240Sstevel@tonic-gate 		drmach_boards = NULL;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 		vmem_free(heap_arena, drmach_shutdown_va, PAGESIZE);
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 		/*
10290Sstevel@tonic-gate 		 * Walk immediate children of the root devinfo node
10300Sstevel@tonic-gate 		 * releasing holds acquired on branches in drmach_init()
10310Sstevel@tonic-gate 		 */
10320Sstevel@tonic-gate 		hold = 0;
10330Sstevel@tonic-gate 		rdip = ddi_root_node();
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 		ndi_devi_enter(rdip, &circ);
10360Sstevel@tonic-gate 		ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold);
10370Sstevel@tonic-gate 		ndi_devi_exit(rdip, circ);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 		mutex_destroy(&drmach_i_lock);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 		drmach_initialized = 0;
10420Sstevel@tonic-gate 	}
10430Sstevel@tonic-gate 	if (drmach_xt_mb != NULL) {
10440Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_xt_mb,
10450Sstevel@tonic-gate 		    NCPU * sizeof (uchar_t));
10460Sstevel@tonic-gate 	}
10470Sstevel@tonic-gate 	if (drmach_shutdown_asm_mbox != NULL) {
10480Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox,
10490Sstevel@tonic-gate 		    sizeof (struct drmach_shutdown_mbox));
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate 	return (0);
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate static sbd_error_t *
10550Sstevel@tonic-gate drmach_get_mc_asr_addr(drmachid_t id, uint64_t *pa)
10560Sstevel@tonic-gate {
10570Sstevel@tonic-gate 	drmach_device_t	*dp;
1058789Sahrens 	pnode_t		nodeid;
10590Sstevel@tonic-gate 	uint64_t	addr;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
10620Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
10630Sstevel@tonic-gate 	dp = id;
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
10660Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
10670Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	addr = mc_get_asr_addr(nodeid);
10700Sstevel@tonic-gate 	if (addr == (uint64_t)-1)
10710Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	*pa = addr;
10740Sstevel@tonic-gate 	return (NULL);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate static sbd_error_t *
10780Sstevel@tonic-gate drmach_get_mc_idle_addr(drmachid_t id, uint64_t *pa)
10790Sstevel@tonic-gate {
10800Sstevel@tonic-gate 	drmach_device_t	*dp;
1081789Sahrens 	pnode_t		nodeid;
10820Sstevel@tonic-gate 	uint64_t	addr;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
10850Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
10860Sstevel@tonic-gate 	dp = id;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
10890Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
10900Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	addr = mc_get_idle_addr(nodeid);
10930Sstevel@tonic-gate 	if (addr == (uint64_t)-1)
10940Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	*pa = addr;
10970Sstevel@tonic-gate 	return (NULL);
10980Sstevel@tonic-gate }
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate static sbd_error_t *
11010Sstevel@tonic-gate drmach_read_mc_asr(drmachid_t id, uint_t *mcregp)
11020Sstevel@tonic-gate {
11030Sstevel@tonic-gate 	drmach_device_t	*dp;
1104789Sahrens 	pnode_t		 nodeid;
11050Sstevel@tonic-gate 	sbd_error_t	*err;
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
11080Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
11090Sstevel@tonic-gate 	dp = id;
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
11120Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
11130Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
11140Sstevel@tonic-gate 	else if (mc_read_asr(nodeid, mcregp) == -1)
11150Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
11160Sstevel@tonic-gate 	else
11170Sstevel@tonic-gate 		err = NULL;
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	return (err);
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate static sbd_error_t *
11230Sstevel@tonic-gate drmach_write_mc_asr(drmachid_t id, uint_t mcreg)
11240Sstevel@tonic-gate {
11250Sstevel@tonic-gate 	drmach_device_t	*dp;
1126789Sahrens 	pnode_t		 nodeid;
11270Sstevel@tonic-gate 	sbd_error_t	*err;
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
11300Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
11310Sstevel@tonic-gate 	dp = id;
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
11340Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
11350Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
11360Sstevel@tonic-gate 	else if (mc_write_asr(nodeid, mcreg) == -1)
11370Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
11380Sstevel@tonic-gate 	else
11390Sstevel@tonic-gate 		err = NULL;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	return (err);
11420Sstevel@tonic-gate }
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate static sbd_error_t *
11450Sstevel@tonic-gate drmach_prep_rename_script(drmach_device_t *s_mem, drmach_device_t *t_mem,
11460Sstevel@tonic-gate 	uint64_t t_slice_offset, caddr_t buf, int buflen)
11470Sstevel@tonic-gate {
11480Sstevel@tonic-gate 	int			i, b, m;
11490Sstevel@tonic-gate 	drmach_mc_idle_script_t	*isp;
11500Sstevel@tonic-gate 	drmach_rename_script_t	*rsp;
11510Sstevel@tonic-gate 	int			s_bd, t_bd;
11520Sstevel@tonic-gate 	uint_t			s_masr, t_masr;
11530Sstevel@tonic-gate 	uint64_t		s_new_basepa, t_new_basepa;
11540Sstevel@tonic-gate 	int			b_idx, rv;
11550Sstevel@tonic-gate 	sbd_error_t		*err;
11560Sstevel@tonic-gate 	drmachid_t		 b_id;
11570Sstevel@tonic-gate 	drmach_board_t		*brd;
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate #ifdef DEBUG
11600Sstevel@tonic-gate 	/*
11610Sstevel@tonic-gate 	 * Starfire CPU/MEM/IO boards have only one MC per board.
11620Sstevel@tonic-gate 	 * This function has been coded with that fact in mind.
11630Sstevel@tonic-gate 	 */
11640Sstevel@tonic-gate 	ASSERT(MAX_MEM_UNITS_PER_BOARD == 1);
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	/*
11670Sstevel@tonic-gate 	 * calculate the maximum space that could be consumed,
11680Sstevel@tonic-gate 	 * then verify the available buffer space is adequate.
11690Sstevel@tonic-gate 	 */
11700Sstevel@tonic-gate 	m  = sizeof (drmach_mc_idle_script_t *) * 2; /* two MCs */
11710Sstevel@tonic-gate 	b  = sizeof (drmach_rename_script_t *) * 3 * MAX_CPU_UNITS_PER_BOARD;
11720Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 3 * MAX_IO_UNITS_PER_BOARD;
11730Sstevel@tonic-gate 	b *= MAX_BOARDS;
11740Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 3;
11750Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 1;
11760Sstevel@tonic-gate 	ASSERT(m + b < buflen);
11770Sstevel@tonic-gate #endif
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	/*
11800Sstevel@tonic-gate 	 * construct an array of MC idle register addresses of
11810Sstevel@tonic-gate 	 * both MCs.  The array is zero terminated -- as expected
11820Sstevel@tonic-gate 	 * by drmach_copy_rename_prog__relocatable().
11830Sstevel@tonic-gate 	 */
11840Sstevel@tonic-gate 	isp = (drmach_mc_idle_script_t *)buf;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	/* source mc */
11870Sstevel@tonic-gate 	err = drmach_get_mc_idle_addr(s_mem, &isp->idle_addr);
11880Sstevel@tonic-gate 	if (err)
11890Sstevel@tonic-gate 		return (err);
11900Sstevel@tonic-gate 	isp->mem = s_mem;
11910Sstevel@tonic-gate 	isp += 1;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/* target mc */
11940Sstevel@tonic-gate 	err = drmach_get_mc_idle_addr(t_mem, &isp->idle_addr);
11950Sstevel@tonic-gate 	if (err)
11960Sstevel@tonic-gate 		return (err);
11970Sstevel@tonic-gate 	isp->mem = t_mem;
11980Sstevel@tonic-gate 	isp += 1;
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	/* terminator */
12010Sstevel@tonic-gate 	isp->idle_addr = 0;
12020Sstevel@tonic-gate 	isp->mem = NULL;
12030Sstevel@tonic-gate 	isp += 1;
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 	/* fetch source mc asr register value */
12060Sstevel@tonic-gate 	err = drmach_read_mc_asr(s_mem, &s_masr);
12070Sstevel@tonic-gate 	if (err)
12080Sstevel@tonic-gate 		return (err);
12090Sstevel@tonic-gate 	else if (s_masr & STARFIRE_MC_INTERLEAVE_MASK) {
12100Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
12110Sstevel@tonic-gate 				s_mem->bp->cm.name, s_mem->cm.name));
12120Sstevel@tonic-gate 	}
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	/* fetch target mc asr register value */
12150Sstevel@tonic-gate 	err = drmach_read_mc_asr(t_mem, &t_masr);
12160Sstevel@tonic-gate 	if (err)
12170Sstevel@tonic-gate 		return (err);
12180Sstevel@tonic-gate 	else if (t_masr & STARFIRE_MC_INTERLEAVE_MASK) {
12190Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
12200Sstevel@tonic-gate 				t_mem->bp->cm.name, t_mem->cm.name));
12210Sstevel@tonic-gate 	}
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 	/* get new source base pa from target's masr */
12240Sstevel@tonic-gate 	s_new_basepa = mc_asr_to_pa(t_masr);
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	/*
12270Sstevel@tonic-gate 	 * remove any existing slice offset to realign
12280Sstevel@tonic-gate 	 * memory with board's slice boundary
12290Sstevel@tonic-gate 	 */
12300Sstevel@tonic-gate 	s_new_basepa &= ~ (mc_get_mem_alignment() - 1);
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	/* get new target base pa from source's masr */
12330Sstevel@tonic-gate 	t_new_basepa  = mc_asr_to_pa(s_masr);
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	/* remove any existing slice offset, then apply new offset */
12360Sstevel@tonic-gate 	t_new_basepa &= ~ (mc_get_mem_alignment() - 1);
12370Sstevel@tonic-gate 	t_new_basepa += t_slice_offset;
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	/* encode new base pa into s_masr.  turn off mem present bit */
12400Sstevel@tonic-gate 	s_masr  = mc_pa_to_asr(s_masr, s_new_basepa);
12410Sstevel@tonic-gate 	s_masr &= ~STARFIRE_MC_MEM_PRESENT_MASK;
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	/* encode new base pa into t_masr.  turn on mem present bit */
12440Sstevel@tonic-gate 	t_masr  = mc_pa_to_asr(t_masr, t_new_basepa);
12450Sstevel@tonic-gate 	t_masr |= STARFIRE_MC_MEM_PRESENT_MASK;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	/*
12480Sstevel@tonic-gate 	 * Step 0:	Mark source memory as not present.
12490Sstevel@tonic-gate 	 */
12500Sstevel@tonic-gate 	m = 0;
12510Sstevel@tonic-gate 	rsp = (drmach_rename_script_t *)isp;
12520Sstevel@tonic-gate 	err = drmach_get_mc_asr_addr(s_mem, &rsp[m].masr_addr);
12530Sstevel@tonic-gate 	if (err)
12540Sstevel@tonic-gate 		return (err);
12550Sstevel@tonic-gate 	rsp[m].masr = s_masr;
12560Sstevel@tonic-gate 	m++;
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 	/*
12590Sstevel@tonic-gate 	 * Step 1:	Write source base address to target MC
12600Sstevel@tonic-gate 	 *		with present bit off.
12610Sstevel@tonic-gate 	 */
12620Sstevel@tonic-gate 	err = drmach_get_mc_asr_addr(t_mem, &rsp[m].masr_addr);
12630Sstevel@tonic-gate 	if (err)
12640Sstevel@tonic-gate 		return (err);
12650Sstevel@tonic-gate 	rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
12660Sstevel@tonic-gate 	m++;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	/*
12690Sstevel@tonic-gate 	 * Step 2:	Now rewrite target reg with present bit on.
12700Sstevel@tonic-gate 	 */
12710Sstevel@tonic-gate 	rsp[m].masr_addr = rsp[m-1].masr_addr;
12720Sstevel@tonic-gate 	rsp[m].masr = t_masr;
12730Sstevel@tonic-gate 	m++;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	s_bd = s_mem->bp->bnum;
12760Sstevel@tonic-gate 	t_bd = t_mem->bp->bnum;
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	DRMACH_PR("preparing script for CPU and IO units:\n");
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	rv = drmach_array_first(drmach_boards, &b_idx, &b_id);
12810Sstevel@tonic-gate 	if (rv) {
12820Sstevel@tonic-gate 		/* catch this in debug kernels */
12830Sstevel@tonic-gate 		ASSERT(0);
12840Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	do {
12880Sstevel@tonic-gate 		int			 d_idx;
12890Sstevel@tonic-gate 		drmachid_t		 d_id;
12900Sstevel@tonic-gate 		drmach_device_t		*device;
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 		ASSERT(DRMACH_IS_BOARD_ID(b_id));
12930Sstevel@tonic-gate 		brd = b_id;
12940Sstevel@tonic-gate 		b = brd->bnum;
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 		/*
12970Sstevel@tonic-gate 		 * Step 3:	Update PC MADR tables for CPUs.
12980Sstevel@tonic-gate 		 */
12993137Sjesusm 		if (brd->devices == NULL) {
13003137Sjesusm 			/* devices not initialized */
13013137Sjesusm 			continue;
13023137Sjesusm 		}
13033137Sjesusm 
13040Sstevel@tonic-gate 		rv = drmach_array_first(brd->devices, &d_idx, &d_id);
13050Sstevel@tonic-gate 		if (rv) {
13060Sstevel@tonic-gate 			/* must mean no devices on this board */
13070Sstevel@tonic-gate 			break;
13080Sstevel@tonic-gate 		}
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 		DRMACH_PR("\t%s\n", brd->cm.name);
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 		do {
13130Sstevel@tonic-gate 			ASSERT(DRMACH_IS_DEVICE_ID(d_id));
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 			if (!DRMACH_IS_CPU_ID(d_id))
13160Sstevel@tonic-gate 				continue;
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 			device = d_id;
13190Sstevel@tonic-gate 			i = device->unum;
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 			DRMACH_PR("\t\t%s\n", device->cm.name);
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 			/*
13240Sstevel@tonic-gate 			 * Disabled detaching mem node.
13250Sstevel@tonic-gate 			 */
13260Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i);
13270Sstevel@tonic-gate 			rsp[m].masr = s_masr;
13280Sstevel@tonic-gate 			m++;
13290Sstevel@tonic-gate 			/*
13300Sstevel@tonic-gate 			 * Always write masr with present bit
13310Sstevel@tonic-gate 			 * off and then again with it on.
13320Sstevel@tonic-gate 			 */
13330Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i);
13340Sstevel@tonic-gate 			rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
13350Sstevel@tonic-gate 			m++;
13360Sstevel@tonic-gate 			rsp[m].masr_addr = rsp[m-1].masr_addr;
13370Sstevel@tonic-gate 			rsp[m].masr = t_masr;
13380Sstevel@tonic-gate 			m++;
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 		} while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0);
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 		/*
13430Sstevel@tonic-gate 		 * Step 4:	Update PC MADR tables for IOs.
13440Sstevel@tonic-gate 		 */
13450Sstevel@tonic-gate 		rv = drmach_array_first(brd->devices, &d_idx, &d_id);
13460Sstevel@tonic-gate 		/* this worked for previous loop, must work here too */
13470Sstevel@tonic-gate 		ASSERT(rv == 0);
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 		do {
13500Sstevel@tonic-gate 			ASSERT(DRMACH_IS_DEVICE_ID(d_id));
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 			if (!DRMACH_IS_IO_ID(d_id))
13530Sstevel@tonic-gate 				continue;
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 			device = d_id;
13560Sstevel@tonic-gate 			i = device->unum;
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 			DRMACH_PR("\t\t%s\n", device->cm.name);
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 			/*
13610Sstevel@tonic-gate 			 * Disabled detaching mem node.
13620Sstevel@tonic-gate 			 */
13630Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i+4);
13640Sstevel@tonic-gate 			rsp[m].masr = s_masr;
13650Sstevel@tonic-gate 			m++;
13660Sstevel@tonic-gate 			/*
13670Sstevel@tonic-gate 			 * Always write masr with present bit
13680Sstevel@tonic-gate 			 * off and then again with it on.
13690Sstevel@tonic-gate 			 */
13700Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i+4);
13710Sstevel@tonic-gate 			rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
13720Sstevel@tonic-gate 			m++;
13730Sstevel@tonic-gate 			rsp[m].masr_addr = rsp[m-1].masr_addr;
13740Sstevel@tonic-gate 			rsp[m].masr = t_masr;
13750Sstevel@tonic-gate 			m++;
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 		} while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0);
13780Sstevel@tonic-gate 	} while (drmach_array_next(drmach_boards, &b_idx, &b_id) == 0);
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 	/*
13810Sstevel@tonic-gate 	 * Zero masr_addr value indicates the END.
13820Sstevel@tonic-gate 	 */
13830Sstevel@tonic-gate 	rsp[m].masr_addr = 0ull;
13840Sstevel@tonic-gate 	rsp[m].masr = 0;
13850Sstevel@tonic-gate 	DRMACH_PR("number of steps in rename script = %d\n", m);
13860Sstevel@tonic-gate 	m++;
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	/* paranoia */
13890Sstevel@tonic-gate 	ASSERT((caddr_t)&rsp[m] <= buf + buflen);
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate #ifdef DEBUG
13920Sstevel@tonic-gate 	{
13930Sstevel@tonic-gate 		int	j;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 		DRMACH_PR("mc idle register address list:");
13960Sstevel@tonic-gate 		isp = (drmach_mc_idle_script_t *)buf;
1397930Smathue 		DRMACH_PR("source mc idle addr 0x%lx, mem id %p",
1398*11311SSurya.Prakki@Sun.COM 			isp[0].idle_addr, (void *)isp[0].mem);
1399930Smathue 		DRMACH_PR("target mc idle addr 0x%lx, mem id %p",
1400*11311SSurya.Prakki@Sun.COM 			isp[1].idle_addr, (void *)isp[1].mem);
14010Sstevel@tonic-gate 		ASSERT(isp[2].idle_addr == 0);
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 		DRMACH_PR("copy-rename script:");
14040Sstevel@tonic-gate 		for (j = 0; j < m; j++) {
1405930Smathue 			DRMACH_PR("0x%lx = 0x%08x",
14060Sstevel@tonic-gate 				rsp[j].masr_addr, rsp[j].masr);
14070Sstevel@tonic-gate 		}
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 		DELAY(1000000);
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate #endif
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	/* return number of bytes consumed */
14140Sstevel@tonic-gate 	b = (caddr_t)&rsp[m] - buf;
14150Sstevel@tonic-gate 	DRMACH_PR("total number of bytes consumed is %d\n", b);
14160Sstevel@tonic-gate 	ASSERT(b <= buflen);
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate #ifdef lint
14190Sstevel@tonic-gate 	buflen = buflen;
14200Sstevel@tonic-gate #endif
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 	return (NULL);
14230Sstevel@tonic-gate }
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate /*
14260Sstevel@tonic-gate  * The routine performs the necessary memory COPY and MC adr SWITCH.
14270Sstevel@tonic-gate  * Both operations MUST be at the same "level" so that the stack is
14280Sstevel@tonic-gate  * maintained correctly between the copy and switch.  The switch
14290Sstevel@tonic-gate  * portion implements a caching mechanism to guarantee the code text
14300Sstevel@tonic-gate  * is cached prior to execution.  This is to guard against possible
14310Sstevel@tonic-gate  * memory access while the MC adr's are being modified.
14320Sstevel@tonic-gate  *
14330Sstevel@tonic-gate  * IMPORTANT: The _drmach_copy_rename_end() function must immediately
14340Sstevel@tonic-gate  * follow drmach_copy_rename_prog__relocatable() so that the correct
14350Sstevel@tonic-gate  * "length" of the drmach_copy_rename_prog__relocatable can be
14360Sstevel@tonic-gate  * calculated.  This routine MUST be a LEAF function, i.e. it can
14370Sstevel@tonic-gate  * make NO function calls, primarily for two reasons:
14380Sstevel@tonic-gate  *
14390Sstevel@tonic-gate  *	1. We must keep the stack consistent across the "switch".
14400Sstevel@tonic-gate  *	2. Function calls are compiled to relative offsets, and
14410Sstevel@tonic-gate  *	   we execute this function we'll be executing it from
14420Sstevel@tonic-gate  *	   a copied version in a different area of memory, thus
14430Sstevel@tonic-gate  *	   the relative offsets will be bogus.
14440Sstevel@tonic-gate  *
14450Sstevel@tonic-gate  * Moreover, it must have the "__relocatable" suffix to inform DTrace
14460Sstevel@tonic-gate  * providers (and anything else, for that matter) that this
14470Sstevel@tonic-gate  * function's text is manually relocated elsewhere before it is
14480Sstevel@tonic-gate  * executed.  That is, it cannot be safely instrumented with any
14490Sstevel@tonic-gate  * methodology that is PC-relative.
14500Sstevel@tonic-gate  */
14510Sstevel@tonic-gate static void
14520Sstevel@tonic-gate drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog)
14530Sstevel@tonic-gate {
14540Sstevel@tonic-gate 	extern void drmach_exec_script_il(drmach_rename_script_t *rsp);
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	drmach_mc_idle_script_t		*isp;
14570Sstevel@tonic-gate 	struct memlist			*ml;
14580Sstevel@tonic-gate 	int				csize;
14590Sstevel@tonic-gate 	int				lnsize;
14600Sstevel@tonic-gate 	uint64_t			caddr;
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	isp = (drmach_mc_idle_script_t *)prog->data;
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 	caddr = ecache_flushaddr;
14650Sstevel@tonic-gate 	csize = (cpunodes[CPU->cpu_id].ecache_size << 1);
14660Sstevel@tonic-gate 	lnsize = cpunodes[CPU->cpu_id].ecache_linesize;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	/*
14690Sstevel@tonic-gate 	 * DO COPY.
14700Sstevel@tonic-gate 	 */
14710Sstevel@tonic-gate 	for (ml = prog->c_ml; ml; ml = ml->next) {
14720Sstevel@tonic-gate 		uint64_t	s_pa, t_pa;
14730Sstevel@tonic-gate 		uint64_t	nbytes;
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 		s_pa = prog->s_copybasepa + ml->address;
14760Sstevel@tonic-gate 		t_pa = prog->t_copybasepa + ml->address;
14770Sstevel@tonic-gate 		nbytes = ml->size;
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 		while (nbytes != 0ull) {
14800Sstevel@tonic-gate 			/*
14810Sstevel@tonic-gate 			 * This copy does NOT use an ASI
14820Sstevel@tonic-gate 			 * that avoids the Ecache, therefore
14830Sstevel@tonic-gate 			 * the dst_pa addresses may remain
14840Sstevel@tonic-gate 			 * in our Ecache after the dst_pa
14850Sstevel@tonic-gate 			 * has been removed from the system.
14860Sstevel@tonic-gate 			 * A subsequent write-back to memory
14870Sstevel@tonic-gate 			 * will cause an ARB-stop because the
14880Sstevel@tonic-gate 			 * physical address no longer exists
14890Sstevel@tonic-gate 			 * in the system. Therefore we must
14900Sstevel@tonic-gate 			 * flush out local Ecache after we
14910Sstevel@tonic-gate 			 * finish the copy.
14920Sstevel@tonic-gate 			 */
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 			/* copy 32 bytes at src_pa to dst_pa */
14950Sstevel@tonic-gate 			bcopy32_il(s_pa, t_pa);
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 			/* increment by 32 bytes */
14980Sstevel@tonic-gate 			s_pa += (4 * sizeof (uint64_t));
14990Sstevel@tonic-gate 			t_pa += (4 * sizeof (uint64_t));
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 			/* decrement by 32 bytes */
15020Sstevel@tonic-gate 			nbytes -= (4 * sizeof (uint64_t));
15030Sstevel@tonic-gate 		}
15040Sstevel@tonic-gate 	}
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	/*
15070Sstevel@tonic-gate 	 * Since bcopy32_il() does NOT use an ASI to bypass
15080Sstevel@tonic-gate 	 * the Ecache, we need to flush our Ecache after
15090Sstevel@tonic-gate 	 * the copy is complete.
15100Sstevel@tonic-gate 	 */
15110Sstevel@tonic-gate 	flush_ecache_il(caddr, csize, lnsize);		/* inline version */
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	/*
15140Sstevel@tonic-gate 	 * Wait for MCs to go idle.
15150Sstevel@tonic-gate 	 */
15160Sstevel@tonic-gate 	do {
15170Sstevel@tonic-gate 		register int	t = 10;
15180Sstevel@tonic-gate 		register uint_t	v;
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 		/* loop t cycles waiting for each mc to indicate it's idle */
15210Sstevel@tonic-gate 		do {
15220Sstevel@tonic-gate 			v = ldphysio_il(isp->idle_addr)
15230Sstevel@tonic-gate 				& STARFIRE_MC_IDLE_MASK;
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 		} while (v != STARFIRE_MC_IDLE_MASK && t-- > 0);
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 		/* bailout if timedout */
15280Sstevel@tonic-gate 		if (t <= 0) {
15290Sstevel@tonic-gate 			prog->restless_mc = isp->mem;
15300Sstevel@tonic-gate 			return;
15310Sstevel@tonic-gate 		}
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 		isp += 1;
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 		/* stop if terminating zero has been reached */
15360Sstevel@tonic-gate 	} while (isp->idle_addr != 0);
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 	/* advance passed terminating zero */
15390Sstevel@tonic-gate 	isp += 1;
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	/*
15420Sstevel@tonic-gate 	 * The following inline assembly routine caches
15430Sstevel@tonic-gate 	 * the rename script and then caches the code that
15440Sstevel@tonic-gate 	 * will do the rename.  This is necessary
15450Sstevel@tonic-gate 	 * so that we don't have any memory references during
15460Sstevel@tonic-gate 	 * the reprogramming.  We accomplish this by first
15470Sstevel@tonic-gate 	 * jumping through the code to guarantee it's cached
15480Sstevel@tonic-gate 	 * before we actually execute it.
15490Sstevel@tonic-gate 	 */
15500Sstevel@tonic-gate 	drmach_exec_script_il((drmach_rename_script_t *)isp);
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate static void
15540Sstevel@tonic-gate drmach_copy_rename_end(void)
15550Sstevel@tonic-gate {
15560Sstevel@tonic-gate 	/*
15570Sstevel@tonic-gate 	 * IMPORTANT:	This function's location MUST be located immediately
15580Sstevel@tonic-gate 	 *		following drmach_copy_rename_prog__relocatable to
15590Sstevel@tonic-gate 	 *		accurately estimate its size.  Note that this assumes
15600Sstevel@tonic-gate 	 *		the compiler keeps these functions in the order in
15610Sstevel@tonic-gate 	 *		which they appear :-o
15620Sstevel@tonic-gate 	 */
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate sbd_error_t *
15660Sstevel@tonic-gate drmach_copy_rename_init(drmachid_t t_id, uint64_t t_slice_offset,
15670Sstevel@tonic-gate 	drmachid_t s_id, struct memlist *c_ml, drmachid_t *pgm_id)
15680Sstevel@tonic-gate {
15690Sstevel@tonic-gate 	drmach_device_t	*s_mem;
15700Sstevel@tonic-gate 	drmach_device_t	*t_mem;
15710Sstevel@tonic-gate 	struct memlist	*x_ml;
15720Sstevel@tonic-gate 	uint64_t	off_mask, s_copybasepa, t_copybasepa, t_basepa;
15730Sstevel@tonic-gate 	int		len;
15740Sstevel@tonic-gate 	caddr_t		bp, wp;
15750Sstevel@tonic-gate 	pda_handle_t	ph;
15760Sstevel@tonic-gate 	sbd_error_t	*err;
15770Sstevel@tonic-gate 	drmach_copy_rename_program_t *prog;
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(s_id))
15800Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
15810Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(t_id))
15820Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
15830Sstevel@tonic-gate 	s_mem = s_id;
15840Sstevel@tonic-gate 	t_mem = t_id;
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate 	/* get starting physical address of target memory */
15870Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(t_id, &t_basepa);
15880Sstevel@tonic-gate 	if (err)
15890Sstevel@tonic-gate 		return (err);
15900Sstevel@tonic-gate 
15910Sstevel@tonic-gate 	/* calculate slice offset mask from slice size */
15920Sstevel@tonic-gate 	off_mask = mc_get_mem_alignment() - 1;
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 	/* calculate source and target base pa */
15950Sstevel@tonic-gate 	s_copybasepa = c_ml->address;
15960Sstevel@tonic-gate 	t_copybasepa = t_basepa + ((c_ml->address & off_mask) - t_slice_offset);
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	/* paranoia */
15990Sstevel@tonic-gate 	ASSERT((c_ml->address & off_mask) >= t_slice_offset);
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	/* adjust copy memlist addresses to be relative to copy base pa */
16020Sstevel@tonic-gate 	x_ml = c_ml;
16030Sstevel@tonic-gate 	while (x_ml != NULL) {
16040Sstevel@tonic-gate 		x_ml->address -= s_copybasepa;
16050Sstevel@tonic-gate 		x_ml = x_ml->next;
16060Sstevel@tonic-gate 	}
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate #ifdef DEBUG
16090Sstevel@tonic-gate 	{
16100Sstevel@tonic-gate 	uint64_t s_basepa, s_size, t_size;
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	x_ml = c_ml;
16130Sstevel@tonic-gate 	while (x_ml->next != NULL)
16140Sstevel@tonic-gate 		x_ml = x_ml->next;
16150Sstevel@tonic-gate 
1616930Smathue 	DRMACH_PR("source copy span: base pa 0x%lx, end pa 0x%lx\n",
16170Sstevel@tonic-gate 		s_copybasepa,
16180Sstevel@tonic-gate 		s_copybasepa + x_ml->address + x_ml->size);
16190Sstevel@tonic-gate 
1620930Smathue 	DRMACH_PR("target copy span: base pa 0x%lx, end pa 0x%lx\n",
16210Sstevel@tonic-gate 		t_copybasepa,
16220Sstevel@tonic-gate 		t_copybasepa + x_ml->address + x_ml->size);
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	DRMACH_PR("copy memlist (relative to copy base pa):\n");
16250Sstevel@tonic-gate 	MEMLIST_DUMP(c_ml);
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(s_id, &s_basepa);
16280Sstevel@tonic-gate 	ASSERT(err == NULL);
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 	err = drmach_mem_get_size(s_id, &s_size);
16310Sstevel@tonic-gate 	ASSERT(err == NULL);
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	err = drmach_mem_get_size(t_id, &t_size);
16340Sstevel@tonic-gate 	ASSERT(err == NULL);
16350Sstevel@tonic-gate 
1636930Smathue 	DRMACH_PR("current source base pa 0x%lx, size 0x%lx\n",
16370Sstevel@tonic-gate 		s_basepa, s_size);
1638930Smathue 	DRMACH_PR("current target base pa 0x%lx, size 0x%lx\n",
16390Sstevel@tonic-gate 		t_basepa, t_size);
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	ASSERT(s_copybasepa + x_ml->address + x_ml->size <= s_basepa + s_size);
16420Sstevel@tonic-gate 	ASSERT(t_copybasepa + x_ml->address + x_ml->size <= t_basepa + t_size);
16430Sstevel@tonic-gate 	}
16440Sstevel@tonic-gate #endif
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 	ph = drmach_pda_open();
16470Sstevel@tonic-gate 	if (ph == NULL)
16480Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 	/*
16510Sstevel@tonic-gate 	 * bp will be page aligned, since we're calling
16520Sstevel@tonic-gate 	 * kmem_zalloc() with an exact multiple of PAGESIZE.
16530Sstevel@tonic-gate 	 */
16540Sstevel@tonic-gate 	wp = bp = kmem_zalloc(PAGESIZE, KM_SLEEP);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	/* allocate space for copy rename struct */
16570Sstevel@tonic-gate 	len = sizeof (drmach_copy_rename_program_t);
1658*11311SSurya.Prakki@Sun.COM 	DRMACH_PR("prog = 0x%p, header len %d\n", (void *)wp, len);
16590Sstevel@tonic-gate 	prog = (drmach_copy_rename_program_t *)wp;
16600Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	/*
16630Sstevel@tonic-gate 	 * Copy the code for the copy-rename routine into
16640Sstevel@tonic-gate 	 * a page aligned piece of memory.  We do this to guarantee
16650Sstevel@tonic-gate 	 * that we're executing within the same page and thus reduce
16660Sstevel@tonic-gate 	 * the possibility of cache collisions between different
16670Sstevel@tonic-gate 	 * pages.
16680Sstevel@tonic-gate 	 */
16690Sstevel@tonic-gate 	len = (int)((ulong_t)drmach_copy_rename_end -
16700Sstevel@tonic-gate 		    (ulong_t)drmach_copy_rename_prog__relocatable);
16710Sstevel@tonic-gate 	ASSERT(wp + len < bp + PAGESIZE);
16720Sstevel@tonic-gate 	bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len);
16730Sstevel@tonic-gate 
1674*11311SSurya.Prakki@Sun.COM 	DRMACH_PR("copy-rename function 0x%p, len %d\n", (void *)wp, len);
16750Sstevel@tonic-gate 	prog->run = (void (*)())wp;
16760Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 	/*
16790Sstevel@tonic-gate 	 * Prepare data page that will contain script of
16800Sstevel@tonic-gate 	 * operations to perform during copy-rename.
16810Sstevel@tonic-gate 	 * Allocate temporary buffer to hold script.
16820Sstevel@tonic-gate 	 */
16830Sstevel@tonic-gate 	err = drmach_prep_rename_script(s_mem, t_mem, t_slice_offset,
16840Sstevel@tonic-gate 		wp, PAGESIZE - (wp - bp));
16850Sstevel@tonic-gate 	if (err) {
16860Sstevel@tonic-gate 		(void) drmach_copy_rename_fini(prog);
16870Sstevel@tonic-gate 		return (err);
16880Sstevel@tonic-gate 	}
16890Sstevel@tonic-gate 
1690*11311SSurya.Prakki@Sun.COM 	DRMACH_PR("copy-rename script 0x%p, len %d\n", (void *)wp, len);
16910Sstevel@tonic-gate 	prog->data = wp;
16920Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 	prog->ph = ph;
16950Sstevel@tonic-gate 	prog->s_copybasepa = s_copybasepa;
16960Sstevel@tonic-gate 	prog->t_copybasepa = t_copybasepa;
16970Sstevel@tonic-gate 	prog->c_ml = c_ml;
16980Sstevel@tonic-gate 	*pgm_id = prog;
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 	return (NULL);
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate sbd_error_t *
17040Sstevel@tonic-gate drmach_copy_rename_fini(drmachid_t id)
17050Sstevel@tonic-gate {
17060Sstevel@tonic-gate 	drmach_copy_rename_program_t	*prog = id;
17070Sstevel@tonic-gate 	sbd_error_t			*err = NULL;
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 	if (prog->c_ml != NULL)
17100Sstevel@tonic-gate 		memlist_delete(prog->c_ml);
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	if (prog->ph != NULL)
17130Sstevel@tonic-gate 		pda_close(prog->ph);
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	if (prog->restless_mc != 0) {
17160Sstevel@tonic-gate 		cmn_err(CE_WARN, "MC did not idle; OBP Node 0x%x",
17170Sstevel@tonic-gate 			(uint_t)drmach_node_get_dnode(prog->restless_mc->node));
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
17200Sstevel@tonic-gate 	}
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 	kmem_free(prog, PAGESIZE);
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 	return (err);
17250Sstevel@tonic-gate }
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate static sbd_error_t *
17280Sstevel@tonic-gate drmach_io_new(drmach_device_t *dp)
17290Sstevel@tonic-gate {
17300Sstevel@tonic-gate 	static sbd_error_t *drmach_io_release(drmachid_t);
17310Sstevel@tonic-gate 	static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *);
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 	sbd_error_t	*err;
17340Sstevel@tonic-gate 	int		 portid;
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 	err = drmach_device_get_prop(dp, "upa-portid", &portid);
17370Sstevel@tonic-gate 	if (err == NULL) {
17380Sstevel@tonic-gate 		ASSERT(portid & 0x40);
17390Sstevel@tonic-gate 		dp->unum = portid & 1;
17400Sstevel@tonic-gate 	}
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_io_new;
17430Sstevel@tonic-gate 	dp->cm.release = drmach_io_release;
17440Sstevel@tonic-gate 	dp->cm.status = drmach_io_status;
17450Sstevel@tonic-gate 
1746*11311SSurya.Prakki@Sun.COM 	(void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type,
1747*11311SSurya.Prakki@Sun.COM 	    dp->unum);
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	return (err);
17500Sstevel@tonic-gate }
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate static void
17530Sstevel@tonic-gate drmach_iopc_op(pda_handle_t ph, drmach_iopc_op_t op)
17540Sstevel@tonic-gate {
17550Sstevel@tonic-gate 	register int b;
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 	for (b = 0; b < MAX_BOARDS; b++) {
17580Sstevel@tonic-gate 		int		p;
17590Sstevel@tonic-gate 		ushort_t	bda_ioc;
17600Sstevel@tonic-gate 		board_desc_t	*bdesc;
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 		if (pda_board_present(ph, b) == 0)
17630Sstevel@tonic-gate 			continue;
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 		bdesc = (board_desc_t *)pda_get_board_info(ph, b);
17660Sstevel@tonic-gate 		/*
17670Sstevel@tonic-gate 		 * Update PCs for IOCs.
17680Sstevel@tonic-gate 		 */
17690Sstevel@tonic-gate 		bda_ioc = bdesc->bda_ioc;
17700Sstevel@tonic-gate 		for (p = 0; p < MAX_IOCS; p++) {
17710Sstevel@tonic-gate 			u_longlong_t	idle_addr;
17720Sstevel@tonic-gate 			uchar_t		value;
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 			if (BDA_NBL(bda_ioc, p) != BDAN_GOOD)
17750Sstevel@tonic-gate 				continue;
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 			idle_addr = STARFIRE_BB_PC_ADDR(b, p, 1);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 			switch (op) {
17800Sstevel@tonic-gate 			case DO_PAUSE:
17810Sstevel@tonic-gate 				value = STARFIRE_BB_PC_PAUSE(p);
17820Sstevel@tonic-gate 				break;
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 			case DO_IDLE:
17850Sstevel@tonic-gate 				value = STARFIRE_BB_PC_IDLE(p);
17860Sstevel@tonic-gate 				break;
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 			case DO_UNPAUSE:
17890Sstevel@tonic-gate 				value = ldbphysio(idle_addr);
17900Sstevel@tonic-gate 				value &= ~STARFIRE_BB_PC_PAUSE(p);
17910Sstevel@tonic-gate 				break;
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 			case DO_UNIDLE:
17940Sstevel@tonic-gate 				value = ldbphysio(idle_addr);
17950Sstevel@tonic-gate 				value &= ~STARFIRE_BB_PC_IDLE(p);
17960Sstevel@tonic-gate 				break;
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 			default:
17990Sstevel@tonic-gate 				cmn_err(CE_PANIC,
18000Sstevel@tonic-gate 					"drmach_iopc_op: unknown op (%d)",
18010Sstevel@tonic-gate 					(int)op);
18020Sstevel@tonic-gate 				/*NOTREACHED*/
18030Sstevel@tonic-gate 			}
18040Sstevel@tonic-gate 			stbphysio(idle_addr, value);
18050Sstevel@tonic-gate 		}
18060Sstevel@tonic-gate 	}
18070Sstevel@tonic-gate }
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate void
18100Sstevel@tonic-gate drmach_copy_rename(drmachid_t id)
18110Sstevel@tonic-gate {
18120Sstevel@tonic-gate 	drmach_copy_rename_program_t	*prog = id;
18130Sstevel@tonic-gate 	uint64_t			neer;
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 	/*
18160Sstevel@tonic-gate 	 * UPA IDLE
18170Sstevel@tonic-gate 	 * Protocol = PAUSE -> IDLE -> UNPAUSE
18180Sstevel@tonic-gate 	 * In reality since we only "idle" the IOPCs it's sufficient
18190Sstevel@tonic-gate 	 * to just issue the IDLE operation since (in theory) all IOPCs
18200Sstevel@tonic-gate 	 * in the field are PC6.  However, we'll be robust and do the
18210Sstevel@tonic-gate 	 * proper workaround protocol so that we never have to worry!
18220Sstevel@tonic-gate 	 */
18230Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_PAUSE);
18240Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_IDLE);
18250Sstevel@tonic-gate 	DELAY(100);
18260Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_UNPAUSE);
18270Sstevel@tonic-gate 	DELAY(100);
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	/* disable CE reporting */
18300Sstevel@tonic-gate 	neer = get_error_enable();
18310Sstevel@tonic-gate 	set_error_enable(neer & ~EER_CEEN);
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 	/* run the copy/rename program */
18340Sstevel@tonic-gate 	prog->run(prog);
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 	/* enable CE reporting */
18370Sstevel@tonic-gate 	set_error_enable(neer);
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	/*
18400Sstevel@tonic-gate 	 * UPA UNIDLE
18410Sstevel@tonic-gate 	 * Protocol = UNIDLE
18420Sstevel@tonic-gate 	 */
18430Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_UNIDLE);
18440Sstevel@tonic-gate 	DELAY(100);
18450Sstevel@tonic-gate }
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate /*
18480Sstevel@tonic-gate  * The counter-timer and perf-counter nodes are not being cleaned
18490Sstevel@tonic-gate  * up after a board that was present at start of day is detached.
18500Sstevel@tonic-gate  * If the board has become unconfigured with this operation, walk
18510Sstevel@tonic-gate  * the prom tree and find all counter-timer and perf-counter nodes
18520Sstevel@tonic-gate  * that have the same board number as the board that was just
18530Sstevel@tonic-gate  * unconfigured and remove them.
18540Sstevel@tonic-gate  */
18550Sstevel@tonic-gate static sbd_error_t *
18560Sstevel@tonic-gate drmach_remove_counter_nodes(drmachid_t id)
18570Sstevel@tonic-gate {
18580Sstevel@tonic-gate 	int		num;
18590Sstevel@tonic-gate 	char		name[OBP_MAXDRVNAME];
1860789Sahrens 	pnode_t		child;
18610Sstevel@tonic-gate 	dev_info_t	*dip;
18620Sstevel@tonic-gate 	sbd_error_t	*err;
18630Sstevel@tonic-gate 	drmach_status_t	stat;
18640Sstevel@tonic-gate 	drmach_board_t	*bp;
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id)) {
18670Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
18680Sstevel@tonic-gate 	}
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 	if ((err = drmach_board_status(id, &stat)) != NULL) {
18710Sstevel@tonic-gate 		return (err);
18720Sstevel@tonic-gate 	}
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 	/*
18750Sstevel@tonic-gate 	 * Only clean up the counter-timer and perf-counter
18760Sstevel@tonic-gate 	 * nodes when the entire board is unconfigured.
18770Sstevel@tonic-gate 	 */
18780Sstevel@tonic-gate 	if (stat.configured) {
18790Sstevel@tonic-gate 		return (NULL);
18800Sstevel@tonic-gate 	}
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 	bp = (drmach_board_t *)id;
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 	err = NULL;
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	for (child = prom_childnode(prom_rootnode()); child != OBP_NONODE;
18870Sstevel@tonic-gate 	    child = prom_nextnode(child)) {
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 		if (prom_getprop(child, OBP_BOARDNUM, (caddr_t)&num) == -1) {
18900Sstevel@tonic-gate 			continue;
18910Sstevel@tonic-gate 		}
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 		if (bp->bnum != num) {
18940Sstevel@tonic-gate 			continue;
18950Sstevel@tonic-gate 		}
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 		if (prom_getprop(child, OBP_NAME, (caddr_t)name) == -1) {
18980Sstevel@tonic-gate 			continue;
18990Sstevel@tonic-gate 		}
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 		if (strncmp(name, MISC_COUNTER_TIMER_DEVNAME, OBP_MAXDRVNAME) &&
19020Sstevel@tonic-gate 		    strncmp(name, MISC_PERF_COUNTER_DEVNAME, OBP_MAXDRVNAME)) {
19030Sstevel@tonic-gate 				continue;
19040Sstevel@tonic-gate 		}
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 		/* Root node doesn't have to be held */
19070Sstevel@tonic-gate 		dip = e_ddi_nodeid_to_dip(child);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 		/*
19100Sstevel@tonic-gate 		 * If the node is only in the OBP tree, then
19110Sstevel@tonic-gate 		 * we don't have to remove it.
19120Sstevel@tonic-gate 		 */
19130Sstevel@tonic-gate 		if (dip) {
19140Sstevel@tonic-gate 			dev_info_t *fdip = NULL;
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate 			DRMACH_PR("removing %s devinfo node\n", name);
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 			e_ddi_branch_hold(dip);
19190Sstevel@tonic-gate 			ddi_release_devi(dip); /* held in e_ddi_nodeid_to_dip */
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 			if (e_ddi_branch_destroy(dip, &fdip, 0)) {
19220Sstevel@tonic-gate 				char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 				/*
19250Sstevel@tonic-gate 				 * If non-NULL, fdip is held and must be
19260Sstevel@tonic-gate 				 * released.
19270Sstevel@tonic-gate 				 */
19280Sstevel@tonic-gate 				if (fdip != NULL) {
19290Sstevel@tonic-gate 					(void) ddi_pathname(fdip, path);
19300Sstevel@tonic-gate 					ddi_release_devi(fdip);
19310Sstevel@tonic-gate 				} else {
19320Sstevel@tonic-gate 					(void) ddi_pathname(dip, path);
19330Sstevel@tonic-gate 				}
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 				err = drerr_new(1, ESTF_DRVFAIL, path);
19360Sstevel@tonic-gate 				kmem_free(path, MAXPATHLEN);
19370Sstevel@tonic-gate 				e_ddi_branch_rele(dip);
19380Sstevel@tonic-gate 				break;
19390Sstevel@tonic-gate 			}
19400Sstevel@tonic-gate 		}
19410Sstevel@tonic-gate 	}
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	return (err);
19440Sstevel@tonic-gate }
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate /*ARGSUSED*/
19470Sstevel@tonic-gate sbd_error_t *
19480Sstevel@tonic-gate drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts)
19490Sstevel@tonic-gate {
19500Sstevel@tonic-gate 	/* allow status and ncm operations to always succeed */
19510Sstevel@tonic-gate 	if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) {
19520Sstevel@tonic-gate 		return (NULL);
19530Sstevel@tonic-gate 	}
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	/* check all other commands for the required option string */
19560Sstevel@tonic-gate 	if ((opts->size > 0) && (opts->copts != NULL)) {
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 		DRMACH_PR("platform options: %s\n", opts->copts);
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 		if (strstr(opts->copts, "xfdr") != NULL) {
19610Sstevel@tonic-gate 			return (NULL);
19620Sstevel@tonic-gate 		}
19630Sstevel@tonic-gate 	}
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate 	return (drerr_new(0, ESTF_SUPPORT, NULL));
19660Sstevel@tonic-gate }
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate /*ARGSUSED*/
19690Sstevel@tonic-gate sbd_error_t *
19700Sstevel@tonic-gate drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts)
19710Sstevel@tonic-gate {
19720Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	switch (cmd) {
19750Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 		err = drmach_remove_counter_nodes(id);
19780Sstevel@tonic-gate 		break;
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
19810Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
19820Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
19830Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
19840Sstevel@tonic-gate 	case SBD_CMD_STATUS:
19850Sstevel@tonic-gate 		break;
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	default:
19880Sstevel@tonic-gate 		break;
19890Sstevel@tonic-gate 	}
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate 	return (err);
19920Sstevel@tonic-gate }
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate sbd_error_t *
19950Sstevel@tonic-gate drmach_board_assign(int bnum, drmachid_t *id)
19960Sstevel@tonic-gate {
19970Sstevel@tonic-gate 	sbd_error_t	*err;
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate 	if (!drmach_initialized && drmach_init() == -1) {
20000Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
20010Sstevel@tonic-gate 	} else if (drmach_array_get(drmach_boards, bnum, id) == -1) {
20020Sstevel@tonic-gate 		err = drerr_new(1, ESTF_BNUM, "%d", bnum);
20030Sstevel@tonic-gate 	} else if (*id != NULL) {
20040Sstevel@tonic-gate 		err = NULL;
20050Sstevel@tonic-gate 	} else {
20060Sstevel@tonic-gate 		drmach_board_t	*bp;
20070Sstevel@tonic-gate 
20080Sstevel@tonic-gate 		*id  = (drmachid_t)drmach_board_new(bnum);
20090Sstevel@tonic-gate 		bp = *id;
20100Sstevel@tonic-gate 		bp->assigned = 1;
20110Sstevel@tonic-gate 		err = NULL;
20120Sstevel@tonic-gate 	}
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 	return (err);
20150Sstevel@tonic-gate }
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate static int
20180Sstevel@tonic-gate drmach_attach_board(void *arg)
20190Sstevel@tonic-gate {
20200Sstevel@tonic-gate 	drmach_board_t	*obj = (drmach_board_t *)arg;
20210Sstevel@tonic-gate 	cpuset_t	cset;
20220Sstevel@tonic-gate 	int		retval;
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate 	/*
20250Sstevel@tonic-gate 	 * OBP disables traps during the board probe.
20260Sstevel@tonic-gate 	 * So, in order to prevent cross-call/cross-trap timeouts,
20270Sstevel@tonic-gate 	 * and thus panics, we effectively block anybody from
20280Sstevel@tonic-gate 	 * issuing xc's/xt's by doing a promsafe_xc_attention.
20290Sstevel@tonic-gate 	 * In the previous version of Starfire DR (2.6), a timeout
20300Sstevel@tonic-gate 	 * suspension mechanism was implemented in the send-mondo
20310Sstevel@tonic-gate 	 * assembly.  That mechanism is unnecessary with the
20320Sstevel@tonic-gate 	 * existence of xc_attention/xc_dismissed.
20330Sstevel@tonic-gate 	 */
20340Sstevel@tonic-gate 	cset = cpu_ready_set;
20350Sstevel@tonic-gate 	promsafe_xc_attention(cset);
20360Sstevel@tonic-gate 
20370Sstevel@tonic-gate 	retval = prom_starfire_add_brd(obj->connect_cpuid);
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 	xc_dismissed(cset);
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 	return (retval);
20420Sstevel@tonic-gate }
20430Sstevel@tonic-gate 
20440Sstevel@tonic-gate sbd_error_t *
20450Sstevel@tonic-gate drmach_board_connect(drmachid_t id, drmach_opts_t *opts)
20460Sstevel@tonic-gate {
20470Sstevel@tonic-gate 	drmach_board_t	*obj = (drmach_board_t *)id;
20480Sstevel@tonic-gate 	int		retval;
20490Sstevel@tonic-gate 	sbd_error_t	*err;
20500Sstevel@tonic-gate 	char		*cptr, *copts;
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
20530Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
20540Sstevel@tonic-gate 
20550Sstevel@tonic-gate 	if (opts->size > 0)
20560Sstevel@tonic-gate 		copts = opts->copts;
20570Sstevel@tonic-gate 
20580Sstevel@tonic-gate 	if ((cptr = strstr(copts, "cpuid=")) != NULL) {
20590Sstevel@tonic-gate 		int cpuid;
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 		cptr += strlen("cpuid=");
20620Sstevel@tonic-gate 		cpuid = stoi(&cptr);
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 		if (DRMACH_CPUID2BNUM(cpuid) == obj->bnum) {
20650Sstevel@tonic-gate 			obj->connect_cpuid = cpuid;
20660Sstevel@tonic-gate 			obj->assigned = 1;
20670Sstevel@tonic-gate 		} else
20680Sstevel@tonic-gate 			return (drerr_new(1, ESTF_SETCPUVAL, "%d", cpuid));
20690Sstevel@tonic-gate 	} else {
20700Sstevel@tonic-gate 		/* cpuid was not specified */
20710Sstevel@tonic-gate 		obj->connect_cpuid = -1;
20720Sstevel@tonic-gate 	}
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate 	if (obj->connect_cpuid == -1) {
20750Sstevel@tonic-gate 		err =  drerr_new(1, ESTF_NOCPUID, obj->cm.name);
20760Sstevel@tonic-gate 		return (err);
20770Sstevel@tonic-gate 	}
20780Sstevel@tonic-gate 
20790Sstevel@tonic-gate 	cmn_err(CE_CONT, "DRMACH: PROM attach %s CPU %d\n",
20800Sstevel@tonic-gate 		obj->cm.name, obj->connect_cpuid);
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 	retval = prom_tree_update(drmach_attach_board, obj);
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 	if (retval == 0)
20850Sstevel@tonic-gate 		err = NULL;
20860Sstevel@tonic-gate 	else {
20870Sstevel@tonic-gate 		cmn_err(CE_WARN, "prom error: prom_starfire_add_brd(%d) "
20880Sstevel@tonic-gate 			"returned %d", obj->connect_cpuid, retval);
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 		err = drerr_new(1, ESTF_PROBE, obj->cm.name);
20910Sstevel@tonic-gate 	}
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 	obj->connect_cpuid = -1;
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 	return (err);
20960Sstevel@tonic-gate }
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate /*ARGSUSED*/
20990Sstevel@tonic-gate sbd_error_t *
21000Sstevel@tonic-gate drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts)
21010Sstevel@tonic-gate {
210290Sha137994 	drmach_board_t		*bp;
210390Sha137994 	int			rv;
210490Sha137994 	int			d_idx;	/* device index */
210590Sha137994 	drmachid_t		d_id;	/* device ID */
210690Sha137994 	sbd_error_t		*err;
210790Sha137994 
210890Sha137994 	if (!DRMACH_IS_BOARD_ID(id))
210990Sha137994 		return (drerr_new(0, ESTF_INAPPROP, NULL));
211090Sha137994 
211190Sha137994 	bp = id;
211290Sha137994 
211390Sha137994 	/*
211490Sha137994 	 * We need to make sure all of the board's device nodes
211590Sha137994 	 * have been removed from the Solaris device tree before
211690Sha137994 	 * continuing with the disconnect. Otherwise, we could
211790Sha137994 	 * disconnect the board and remove the OBP device tree
211890Sha137994 	 * nodes with Solaris device tree nodes remaining.
211990Sha137994 	 *
212090Sha137994 	 * On Starfire, Solaris device tree nodes are deleted
212190Sha137994 	 * during unconfigure by drmach_unconfigure(). It's
212290Sha137994 	 * necessary to do this here because drmach_unconfigure()
212390Sha137994 	 * failures are not handled during unconfigure.
212490Sha137994 	 */
212590Sha137994 	if (bp->devices) {
212690Sha137994 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
212790Sha137994 		while (rv == 0) {
212890Sha137994 			err = drmach_unconfigure(d_id, DRMACH_DEVI_REMOVE);
212990Sha137994 			if (err)
213090Sha137994 				return (err);
213190Sha137994 
213290Sha137994 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
213390Sha137994 		}
213490Sha137994 	}
213590Sha137994 
213690Sha137994 	/*
213790Sha137994 	 * Starfire board Solaris device tree counter nodes,
213890Sha137994 	 * which are only present on start-of-day boards, are
213990Sha137994 	 * removed in the dr_post_op() code flow after the
214090Sha137994 	 * board is unconfigured. We call the counter node
214190Sha137994 	 * removal function here because unconfigure errors
214290Sha137994 	 * can cause the dr_post_op() function to be skipped
214390Sha137994 	 * after an unconfigure operation even though all of
214490Sha137994 	 * the board's devices have been transitioned to the
214590Sha137994 	 * unconfigured state.
214690Sha137994 	 */
214790Sha137994 	err = drmach_remove_counter_nodes(id);
214890Sha137994 	if (err)
214990Sha137994 		return (err);
215090Sha137994 
21510Sstevel@tonic-gate 	return (NULL);
21520Sstevel@tonic-gate }
21530Sstevel@tonic-gate 
21540Sstevel@tonic-gate static int
21550Sstevel@tonic-gate drmach_board_find_devices_cb(drmach_node_walk_args_t *args)
21560Sstevel@tonic-gate {
21570Sstevel@tonic-gate 	drmach_node_t			*node = args->node;
21580Sstevel@tonic-gate 	drmach_board_cb_data_t		*data = args->data;
21590Sstevel@tonic-gate 	drmach_board_t			*obj = data->obj;
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	int		 rv;
21620Sstevel@tonic-gate 	int		 bnum;
21630Sstevel@tonic-gate 	drmach_device_t	*device;
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	rv = drmach_node_get_prop(node, OBP_BOARDNUM, &bnum);
21660Sstevel@tonic-gate 	if (rv) {
21670Sstevel@tonic-gate 		/*
21680Sstevel@tonic-gate 		 * if the node does not have a board# property, then
21690Sstevel@tonic-gate 		 * by that information alone it is known that drmach
21700Sstevel@tonic-gate 		 * is not interested in it.
21710Sstevel@tonic-gate 		 */
21720Sstevel@tonic-gate 		return (0);
21730Sstevel@tonic-gate 	} else if (bnum != obj->bnum)
21740Sstevel@tonic-gate 		return (0);
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 	/*
21770Sstevel@tonic-gate 	 * Create a device data structure from this node data.
21780Sstevel@tonic-gate 	 * The call may yield nothing if the node is not of interest
21790Sstevel@tonic-gate 	 * to drmach.
21800Sstevel@tonic-gate 	 */
21810Sstevel@tonic-gate 	data->err = drmach_device_new(node, obj, &device);
21820Sstevel@tonic-gate 	if (data->err)
21830Sstevel@tonic-gate 		return (-1);
21840Sstevel@tonic-gate 	else if (device == NULL) {
21850Sstevel@tonic-gate 		/*
21860Sstevel@tonic-gate 		 * drmach_device_new examined the node we passed in
21870Sstevel@tonic-gate 		 * and determined that it was one not of interest to
21880Sstevel@tonic-gate 		 * drmach.  So, it is skipped.
21890Sstevel@tonic-gate 		 */
21900Sstevel@tonic-gate 		return (0);
21910Sstevel@tonic-gate 	}
21920Sstevel@tonic-gate 
21930Sstevel@tonic-gate 	rv = drmach_array_set(obj->devices, data->ndevs++, device);
21940Sstevel@tonic-gate 	if (rv) {
21950Sstevel@tonic-gate 		drmach_device_dispose(device);
21960Sstevel@tonic-gate 		data->err = DRMACH_INTERNAL_ERROR();
21970Sstevel@tonic-gate 		return (-1);
21980Sstevel@tonic-gate 	}
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 	data->err = (*data->found)(data->a, device->type, device->unum, device);
22010Sstevel@tonic-gate 	return (data->err == NULL ? 0 : -1);
22020Sstevel@tonic-gate }
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate sbd_error_t *
22050Sstevel@tonic-gate drmach_board_find_devices(drmachid_t id, void *a,
22060Sstevel@tonic-gate 	sbd_error_t *(*found)(void *a, const char *, int, drmachid_t))
22070Sstevel@tonic-gate {
22080Sstevel@tonic-gate 	extern int		 plat_max_cpu_units_per_board();
22090Sstevel@tonic-gate 	extern int		 plat_max_mem_units_per_board();
22100Sstevel@tonic-gate 	extern int		 plat_max_io_units_per_board();
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 	drmach_board_t		*obj = (drmach_board_t *)id;
22130Sstevel@tonic-gate 	sbd_error_t		*err;
22140Sstevel@tonic-gate 	int			 max_devices;
22150Sstevel@tonic-gate 	int			 rv;
22160Sstevel@tonic-gate 	drmach_board_cb_data_t	data;
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 	max_devices  = plat_max_cpu_units_per_board();
22190Sstevel@tonic-gate 	max_devices += plat_max_mem_units_per_board();
22200Sstevel@tonic-gate 	max_devices += plat_max_io_units_per_board();
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	obj->devices = drmach_array_new(0, max_devices);
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 	data.obj = obj;
22250Sstevel@tonic-gate 	data.ndevs = 0;
22260Sstevel@tonic-gate 	data.found = found;
22270Sstevel@tonic-gate 	data.a = a;
22280Sstevel@tonic-gate 	data.err = NULL;
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 	rv = drmach_node_walk(obj->tree, &data, drmach_board_find_devices_cb);
22310Sstevel@tonic-gate 	if (rv == 0)
22320Sstevel@tonic-gate 		err = NULL;
22330Sstevel@tonic-gate 	else {
22340Sstevel@tonic-gate 		drmach_array_dispose(obj->devices, drmach_device_dispose);
22350Sstevel@tonic-gate 		obj->devices = NULL;
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 		if (data.err)
22380Sstevel@tonic-gate 			err = data.err;
22390Sstevel@tonic-gate 		else
22400Sstevel@tonic-gate 			err = DRMACH_INTERNAL_ERROR();
22410Sstevel@tonic-gate 	}
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate 	return (err);
22440Sstevel@tonic-gate }
22450Sstevel@tonic-gate 
22460Sstevel@tonic-gate int
22470Sstevel@tonic-gate drmach_board_lookup(int bnum, drmachid_t *id)
22480Sstevel@tonic-gate {
22490Sstevel@tonic-gate 	int	rv = 0;
22500Sstevel@tonic-gate 
22510Sstevel@tonic-gate 	if (!drmach_initialized && drmach_init() == -1) {
22520Sstevel@tonic-gate 		*id = 0;
22530Sstevel@tonic-gate 		rv = -1;
22540Sstevel@tonic-gate 	} else if (drmach_array_get(drmach_boards, bnum, id)) {
22550Sstevel@tonic-gate 		*id = 0;
22560Sstevel@tonic-gate 		rv = -1;
22570Sstevel@tonic-gate 	}
22580Sstevel@tonic-gate 	return (rv);
22590Sstevel@tonic-gate }
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate sbd_error_t *
22620Sstevel@tonic-gate drmach_board_name(int bnum, char *buf, int buflen)
22630Sstevel@tonic-gate {
2264*11311SSurya.Prakki@Sun.COM 	(void) snprintf(buf, buflen, "SB%d", bnum);
22650Sstevel@tonic-gate 	return (NULL);
22660Sstevel@tonic-gate }
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate sbd_error_t *
22690Sstevel@tonic-gate drmach_board_poweroff(drmachid_t id)
22700Sstevel@tonic-gate {
22710Sstevel@tonic-gate 	drmach_board_t	*bp;
22720Sstevel@tonic-gate 	sbd_error_t	*err;
22730Sstevel@tonic-gate 	drmach_status_t	 stat;
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
22760Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
22770Sstevel@tonic-gate 	bp = id;
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 	err = drmach_board_status(id, &stat);
22800Sstevel@tonic-gate 	if (err)
22810Sstevel@tonic-gate 		return (err);
22820Sstevel@tonic-gate 	else if (stat.configured || stat.busy)
22830Sstevel@tonic-gate 		return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name));
22840Sstevel@tonic-gate 	else {
22850Sstevel@tonic-gate 		/* board power off is essentially a noop for Starfire */
22860Sstevel@tonic-gate 		bp->powered = 0;
22870Sstevel@tonic-gate 		return (NULL);
22880Sstevel@tonic-gate 	}
22890Sstevel@tonic-gate 	/*NOTREACHED*/
22900Sstevel@tonic-gate }
22910Sstevel@tonic-gate 
22920Sstevel@tonic-gate sbd_error_t *
22930Sstevel@tonic-gate drmach_board_poweron(drmachid_t id)
22940Sstevel@tonic-gate {
22950Sstevel@tonic-gate 	drmach_board_t	*bp;
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
22980Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
22990Sstevel@tonic-gate 	bp = id;
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	/* board power on is essentially a noop for Starfire */
23020Sstevel@tonic-gate 	bp->powered = 1;
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate 	return (NULL);
23050Sstevel@tonic-gate }
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate static sbd_error_t *
23080Sstevel@tonic-gate drmach_board_release(drmachid_t id)
23090Sstevel@tonic-gate {
23100Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
23110Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
23120Sstevel@tonic-gate 	return (NULL);
23130Sstevel@tonic-gate }
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate /*ARGSUSED*/
23160Sstevel@tonic-gate sbd_error_t *
23170Sstevel@tonic-gate drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force)
23180Sstevel@tonic-gate {
23190Sstevel@tonic-gate 	return (NULL);
23200Sstevel@tonic-gate }
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate sbd_error_t *
23230Sstevel@tonic-gate drmach_board_unassign(drmachid_t id)
23240Sstevel@tonic-gate {
23250Sstevel@tonic-gate 	drmach_board_t	*bp;
23260Sstevel@tonic-gate 	sbd_error_t	*err;
23270Sstevel@tonic-gate 	drmach_status_t	 stat;
23280Sstevel@tonic-gate 
23290Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
23300Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
23310Sstevel@tonic-gate 	bp = id;
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 	err = drmach_board_status(id, &stat);
23340Sstevel@tonic-gate 	if (err)
23350Sstevel@tonic-gate 		return (err);
23360Sstevel@tonic-gate 	else if (stat.configured || stat.busy)
23370Sstevel@tonic-gate 		return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name));
23380Sstevel@tonic-gate 	else if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0)
23390Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
23400Sstevel@tonic-gate 	else {
23410Sstevel@tonic-gate 		drmach_board_dispose(bp);
23420Sstevel@tonic-gate 		return (NULL);
23430Sstevel@tonic-gate 	}
23440Sstevel@tonic-gate 	/*NOTREACHED*/
23450Sstevel@tonic-gate }
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate static sbd_error_t *
23480Sstevel@tonic-gate drmach_cpu_new(drmach_device_t *dp)
23490Sstevel@tonic-gate {
23500Sstevel@tonic-gate 	static sbd_error_t *drmach_cpu_release(drmachid_t);
23510Sstevel@tonic-gate 	static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *);
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	sbd_error_t	*err;
23540Sstevel@tonic-gate 	int		 portid;
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate 	err = drmach_device_get_prop(dp, "upa-portid", &portid);
23570Sstevel@tonic-gate 	if (err == NULL)
23580Sstevel@tonic-gate 		dp->unum = portid & 3;
23590Sstevel@tonic-gate 
23600Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_cpu_new;
23610Sstevel@tonic-gate 	dp->cm.release = drmach_cpu_release;
23620Sstevel@tonic-gate 	dp->cm.status = drmach_cpu_status;
23630Sstevel@tonic-gate 
2364*11311SSurya.Prakki@Sun.COM 	(void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type,
2365*11311SSurya.Prakki@Sun.COM 	    dp->unum);
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 	return (err);
23680Sstevel@tonic-gate }
23690Sstevel@tonic-gate 
23700Sstevel@tonic-gate /*
23710Sstevel@tonic-gate  * drmach_cpu_obp_detach()
23720Sstevel@tonic-gate  *  This requires two steps, first, we must put the cpuid into the OBP
23730Sstevel@tonic-gate  *  idle loop (Idle in Program) state.  Then we call OBP to place the CPU
23740Sstevel@tonic-gate  *  into the "Detached" state, which does any special processing to
23750Sstevel@tonic-gate  *  actually detach the cpu, such as flushing ecache, and also ensures
23760Sstevel@tonic-gate  *  that a subsequent breakpoint won't restart the cpu (if it was just in
23770Sstevel@tonic-gate  *  Idle in Program state).
23780Sstevel@tonic-gate  */
23790Sstevel@tonic-gate static void
23800Sstevel@tonic-gate drmach_cpu_obp_detach(int cpuid)
23810Sstevel@tonic-gate {
23820Sstevel@tonic-gate 	/*
23830Sstevel@tonic-gate 	 * Cpu may not be under OBP's control. Eg, if cpu exited to download
23840Sstevel@tonic-gate 	 * helper on a prior attach.
23850Sstevel@tonic-gate 	 */
23860Sstevel@tonic-gate 	if (CPU_SGN_EXISTS(cpuid) &&
23870Sstevel@tonic-gate 			!SGN_CPU_IS_OS(cpuid) &&
23880Sstevel@tonic-gate 			!SGN_CPU_IS_OBP(cpuid)) {
23890Sstevel@tonic-gate 		cmn_err(CE_WARN,
23900Sstevel@tonic-gate 			"unexpected signature (0x%x) for cpu %d",
23910Sstevel@tonic-gate 			get_cpu_sgn(cpuid), cpuid);
23920Sstevel@tonic-gate 	}
23930Sstevel@tonic-gate 
23940Sstevel@tonic-gate 	/*
23950Sstevel@tonic-gate 	 * Now we place the CPU into the "Detached" idle loop in OBP.
23960Sstevel@tonic-gate 	 * This is so that the CPU won't be restarted if we break into
23970Sstevel@tonic-gate 	 * OBP with a breakpoint or BREAK key from the console, and also
23980Sstevel@tonic-gate 	 * if we need to do any special processing, such as flushing the
23990Sstevel@tonic-gate 	 * cpu's ecache, disabling interrupts (by turning of the ET bit in
24000Sstevel@tonic-gate 	 * the PSR) and/or spinning in BBSRAM rather than global memory.
24010Sstevel@tonic-gate 	 */
24020Sstevel@tonic-gate 	DRMACH_PR("prom_starfire_rm_cpu(%d)\n", cpuid);
24030Sstevel@tonic-gate 	prom_starfire_rm_cpu(cpuid);
24040Sstevel@tonic-gate }
24050Sstevel@tonic-gate 
24060Sstevel@tonic-gate /*
24070Sstevel@tonic-gate  * drmach_cpu_obp_is_detached() returns TRUE if the cpu sigblock signature state
24080Sstevel@tonic-gate  * is SIGBST_DETACHED; otherwise it returns FALSE. This routine should only
24090Sstevel@tonic-gate  * be called after we have asked OBP to detach the CPU. It should NOT be
24100Sstevel@tonic-gate  * called as a check during any other flow.
24110Sstevel@tonic-gate  */
24120Sstevel@tonic-gate static int
24130Sstevel@tonic-gate drmach_cpu_obp_is_detached(int cpuid)
24140Sstevel@tonic-gate {
24150Sstevel@tonic-gate 	if (!CPU_SGN_EXISTS(cpuid) ||
24160Sstevel@tonic-gate 		(SGN_CPU_IS_OS(cpuid) && SGN_CPU_STATE_IS_DETACHED(cpuid)))
24170Sstevel@tonic-gate 		return (1);
24180Sstevel@tonic-gate 	else
24190Sstevel@tonic-gate 		return (0);
24200Sstevel@tonic-gate }
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate static int
24230Sstevel@tonic-gate drmach_cpu_start(struct cpu *cp)
24240Sstevel@tonic-gate {
24250Sstevel@tonic-gate 	int		cpuid = cp->cpu_id;
24260Sstevel@tonic-gate 	int		ntries = drmach_cpu_ntries;
24270Sstevel@tonic-gate 	extern void	restart_other_cpu(int);
24280Sstevel@tonic-gate 
24290Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
2430789Sahrens 	ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0);
24310Sstevel@tonic-gate 
24320Sstevel@tonic-gate 	cp->cpu_flags &= ~CPU_POWEROFF;
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate 	/*
24350Sstevel@tonic-gate 	 * NOTE: restart_other_cpu pauses cpus during the
24360Sstevel@tonic-gate 	 *	 slave cpu start.  This helps to quiesce the
24370Sstevel@tonic-gate 	 *	 bus traffic a bit which makes the tick sync
24380Sstevel@tonic-gate 	 *	 routine in the prom more robust.
24390Sstevel@tonic-gate 	 */
24400Sstevel@tonic-gate 	DRMACH_PR("COLD START for cpu (%d)\n", cpuid);
24410Sstevel@tonic-gate 
24420Sstevel@tonic-gate 	prom_starfire_add_cpu(cpuid);
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 	restart_other_cpu(cpuid);
24450Sstevel@tonic-gate 
24460Sstevel@tonic-gate 	/*
24470Sstevel@tonic-gate 	 * Wait for the cpu to reach its idle thread before
24480Sstevel@tonic-gate 	 * we zap him with a request to blow away the mappings
24490Sstevel@tonic-gate 	 * he (might) have for the drmach_shutdown_asm code
24500Sstevel@tonic-gate 	 * he may have executed on unconfigure.
24510Sstevel@tonic-gate 	 */
24520Sstevel@tonic-gate 	while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) {
24530Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
24540Sstevel@tonic-gate 		ntries--;
24550Sstevel@tonic-gate 	}
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	DRMACH_PR("waited %d out of %d loops for cpu %d\n",
24580Sstevel@tonic-gate 		drmach_cpu_ntries - ntries, drmach_cpu_ntries, cpuid);
24590Sstevel@tonic-gate 
24600Sstevel@tonic-gate 	xt_one(cpuid, vtag_flushpage_tl1,
24612241Shuah 		(uint64_t)drmach_shutdown_va, (uint64_t)ksfmmup);
24620Sstevel@tonic-gate 
24630Sstevel@tonic-gate 	return (0);
24640Sstevel@tonic-gate }
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate /*
24670Sstevel@tonic-gate  * A detaching CPU is xcalled with an xtrap to drmach_cpu_stop_self() after
24680Sstevel@tonic-gate  * it has been offlined. The function of this routine is to get the cpu
24690Sstevel@tonic-gate  * spinning in a safe place. The requirement is that the system will not
24700Sstevel@tonic-gate  * reference anything on the detaching board (memory and i/o is detached
24710Sstevel@tonic-gate  * elsewhere) and that the CPU not reference anything on any other board
24720Sstevel@tonic-gate  * in the system.  This isolation is required during and after the writes
24730Sstevel@tonic-gate  * to the domain masks to remove the board from the domain.
24740Sstevel@tonic-gate  *
24750Sstevel@tonic-gate  * To accomplish this isolation the following is done:
24760Sstevel@tonic-gate  *	1) Create a locked mapping to a location in BBSRAM where
24770Sstevel@tonic-gate  *	   the cpu will execute.
24780Sstevel@tonic-gate  *	2) Copy the target function (drmach_shutdown_asm) in which
24790Sstevel@tonic-gate  *	   the cpu will execute into BBSRAM.
24800Sstevel@tonic-gate  *	3) Jump into function with BBSRAM.
24810Sstevel@tonic-gate  *	   Function will:
24820Sstevel@tonic-gate  *	   3.1) Flush its Ecache (displacement).
24830Sstevel@tonic-gate  *	   3.2) Flush its Dcache with HW mechanism.
24840Sstevel@tonic-gate  *	   3.3) Flush its Icache with HW mechanism.
24850Sstevel@tonic-gate  *	   3.4) Flush all valid and _unlocked_ D-TLB entries.
24860Sstevel@tonic-gate  *	   3.5) Flush all valid and _unlocked_ I-TLB entries.
24870Sstevel@tonic-gate  *	   3.6) Clear xt_mb to signal completion. Note: cache line is
24880Sstevel@tonic-gate  *		recovered by drmach_cpu_poweroff().
24890Sstevel@tonic-gate  *	4) Jump into a tight loop.
24900Sstevel@tonic-gate  */
24910Sstevel@tonic-gate #define	DRMACH_BBSRAM_OFFSET	0x1000
24920Sstevel@tonic-gate 
24930Sstevel@tonic-gate static void
24940Sstevel@tonic-gate drmach_cpu_stop_self(void)
24950Sstevel@tonic-gate {
24960Sstevel@tonic-gate 	int		cpuid = (int)CPU->cpu_id;
24970Sstevel@tonic-gate 	tte_t		tte;
24980Sstevel@tonic-gate 	volatile uint_t	*src, *dst;
24990Sstevel@tonic-gate 	uint_t		funclen;
25000Sstevel@tonic-gate 	uint64_t	bbsram_pa, bbsram_offset;
25010Sstevel@tonic-gate 	uint_t		bbsram_pfn;
25020Sstevel@tonic-gate 	uint64_t	bbsram_addr;
25030Sstevel@tonic-gate 	void		(*bbsram_func)(uint64_t);
25040Sstevel@tonic-gate 	extern void	drmach_shutdown_asm(uint64_t);
25050Sstevel@tonic-gate 	extern void	drmach_shutdown_asm_end(void);
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 	funclen = (uint_t)drmach_shutdown_asm_end - (uint_t)drmach_shutdown_asm;
25080Sstevel@tonic-gate 	ASSERT(funclen <= MMU_PAGESIZE);
25090Sstevel@tonic-gate 	/*
25100Sstevel@tonic-gate 	 * We'll start from the 0th's base.
25110Sstevel@tonic-gate 	 */
25120Sstevel@tonic-gate 	bbsram_pa = STARFIRE_UPAID2UPS(cpuid) | STARFIRE_PSI_BASE;
25130Sstevel@tonic-gate 	bbsram_offset = bbsram_pa | 0xfe0ULL;
25140Sstevel@tonic-gate 	bbsram_pa += ldphysio(bbsram_offset) + DRMACH_BBSRAM_OFFSET;
25150Sstevel@tonic-gate 
25160Sstevel@tonic-gate 	bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT);
25170Sstevel@tonic-gate 
25180Sstevel@tonic-gate 	bbsram_addr = (uint64_t)drmach_shutdown_va;
25190Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->estack = bbsram_addr + (uint64_t)funclen;
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate 	tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) |
25220Sstevel@tonic-gate 			TTE_PFN_INTHI(bbsram_pfn);
25230Sstevel@tonic-gate 	tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) |
25240Sstevel@tonic-gate 			TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT;
25252241Shuah 	sfmmu_dtlb_ld_kva(drmach_shutdown_va, &tte);	/* load dtlb */
25262241Shuah 	sfmmu_itlb_ld_kva(drmach_shutdown_va, &tte);	/* load itlb */
25270Sstevel@tonic-gate 
25280Sstevel@tonic-gate 	for (src = (uint_t *)drmach_shutdown_asm, dst = (uint_t *)bbsram_addr;
25290Sstevel@tonic-gate 		src < (uint_t *)drmach_shutdown_asm_end; src++, dst++)
25300Sstevel@tonic-gate 		*dst = *src;
25310Sstevel@tonic-gate 
25320Sstevel@tonic-gate 	bbsram_func = (void (*)())bbsram_addr;
25330Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->flushaddr = ecache_flushaddr;
25340Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->size = (cpunodes[cpuid].ecache_size << 1);
25350Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->linesize = cpunodes[cpuid].ecache_linesize;
25360Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->physaddr
25370Sstevel@tonic-gate 				    = va_to_pa((void *)&drmach_xt_mb[cpuid]);
25380Sstevel@tonic-gate 
25390Sstevel@tonic-gate 	/*
25400Sstevel@tonic-gate 	 * Signal to drmach_cpu_poweroff() is via drmach_xt_mb cleared
25410Sstevel@tonic-gate 	 * by asm code
25420Sstevel@tonic-gate 	 */
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 	(*bbsram_func)(va_to_pa((void *)drmach_shutdown_asm_mbox));
25450Sstevel@tonic-gate }
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate static void
25480Sstevel@tonic-gate drmach_cpu_shutdown_self(void)
25490Sstevel@tonic-gate {
25500Sstevel@tonic-gate 	cpu_t		*cp = CPU;
25510Sstevel@tonic-gate 	int		cpuid = cp->cpu_id;
25520Sstevel@tonic-gate 	extern void	flush_windows(void);
25530Sstevel@tonic-gate 
25540Sstevel@tonic-gate 	flush_windows();
25550Sstevel@tonic-gate 
25560Sstevel@tonic-gate 	(void) spl8();
25570Sstevel@tonic-gate 
25580Sstevel@tonic-gate 	ASSERT(cp->cpu_intr_actv == 0);
2559834Sandrei 	ASSERT(cp->cpu_thread == cp->cpu_idle_thread ||
2560834Sandrei 	    cp->cpu_thread == cp->cpu_startup_thread);
25610Sstevel@tonic-gate 
25620Sstevel@tonic-gate 	cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
25630Sstevel@tonic-gate 
25640Sstevel@tonic-gate 	drmach_cpu_stop_self();
25650Sstevel@tonic-gate 
25660Sstevel@tonic-gate 	cmn_err(CE_PANIC, "CPU %d FAILED TO SHUTDOWN", cpuid);
25670Sstevel@tonic-gate }
25680Sstevel@tonic-gate 
25690Sstevel@tonic-gate /* a helper routine to keep the math in one place */
25700Sstevel@tonic-gate static processorid_t
25710Sstevel@tonic-gate drmach_cpu_calc_id(drmach_device_t *dp)
25720Sstevel@tonic-gate {
25730Sstevel@tonic-gate 	return (dp->bp->bnum * MAX_CPU_UNITS_PER_BOARD + dp->unum);
25740Sstevel@tonic-gate }
25750Sstevel@tonic-gate 
25760Sstevel@tonic-gate /*
25770Sstevel@tonic-gate  * Move bootproc (SIGBCPU) to another cpu.  If dst_cpu is NULL, a
25780Sstevel@tonic-gate  * destination cpu is chosen from the set of cpus not located on the
25790Sstevel@tonic-gate  * same board as the current bootproc cpu.
25800Sstevel@tonic-gate  */
25810Sstevel@tonic-gate static sbd_error_t *
25820Sstevel@tonic-gate drmach_cpu_juggle_bootproc(drmach_device_t *dst_cpu)
25830Sstevel@tonic-gate {
25840Sstevel@tonic-gate 	processorid_t	 cpuid;
25850Sstevel@tonic-gate 	struct cpu	*cp;
25860Sstevel@tonic-gate 	sbd_error_t	*err;
25870Sstevel@tonic-gate 	int		 rv;
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
25900Sstevel@tonic-gate 
25910Sstevel@tonic-gate 	/* dst_cpu is NULL when target cpu is unspecified. So, pick one. */
25920Sstevel@tonic-gate 	if (dst_cpu == NULL) {
25930Sstevel@tonic-gate 		int avoid_board = DRMACH_CPUID2BNUM(SIGBCPU->cpu_id);
25940Sstevel@tonic-gate 		int max_cpuid = MAX_BOARDS * MAX_CPU_UNITS_PER_BOARD;
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate 		for (cpuid = 0; cpuid < max_cpuid; cpuid++)
25970Sstevel@tonic-gate 			if (DRMACH_CPUID2BNUM(cpuid) != avoid_board) {
25980Sstevel@tonic-gate 				cp = cpu_get(cpuid);
25990Sstevel@tonic-gate 				if (cp != NULL && cpu_is_online(cp))
26000Sstevel@tonic-gate 					break;
26010Sstevel@tonic-gate 			}
26020Sstevel@tonic-gate 
26030Sstevel@tonic-gate 		if (cpuid == max_cpuid) {
26040Sstevel@tonic-gate 			err = drerr_new(1, ESTF_JUGGLE, NULL);
26050Sstevel@tonic-gate 			return (err);
26060Sstevel@tonic-gate 		}
26070Sstevel@tonic-gate 
26080Sstevel@tonic-gate 		/* else, cp points to the selected target cpu */
26090Sstevel@tonic-gate 	} else {
26100Sstevel@tonic-gate 		cpuid = drmach_cpu_calc_id(dst_cpu);
26110Sstevel@tonic-gate 
26120Sstevel@tonic-gate 		if ((cp = cpu_get(cpuid)) == NULL) {
26130Sstevel@tonic-gate 			err = drerr_new(1, ESTF_NODEV, "%s::%s",
26140Sstevel@tonic-gate 				dst_cpu->bp->cm.name, dst_cpu->cm.name);
26150Sstevel@tonic-gate 			return (err);
26160Sstevel@tonic-gate 		}
26170Sstevel@tonic-gate 
26180Sstevel@tonic-gate 		if (cpuid == SIGBCPU->cpu_id) {
26190Sstevel@tonic-gate 			cmn_err(CE_WARN,
26200Sstevel@tonic-gate 				"SIGBCPU(%d) same as new selection(%d)",
26210Sstevel@tonic-gate 				SIGBCPU->cpu_id, cpuid);
26220Sstevel@tonic-gate 
26230Sstevel@tonic-gate 			/* technically not an error, but a no-op */
26240Sstevel@tonic-gate 			return (NULL);
26250Sstevel@tonic-gate 		}
26260Sstevel@tonic-gate 	}
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 	cmn_err(CE_NOTE, "?relocating SIGBCPU from %d to %d",
26290Sstevel@tonic-gate 		SIGBCPU->cpu_id, cpuid);
26300Sstevel@tonic-gate 
26310Sstevel@tonic-gate 	DRMACH_PR("moving SIGBCPU to CPU %d\n", cpuid);
26320Sstevel@tonic-gate 
26330Sstevel@tonic-gate 	/*
26340Sstevel@tonic-gate 	 * Tell OBP to initialize cvc-offset field of new CPU0
26350Sstevel@tonic-gate 	 * so that it's in sync with OBP and cvc_server
26360Sstevel@tonic-gate 	 */
26370Sstevel@tonic-gate 	prom_starfire_init_console(cpuid);
26380Sstevel@tonic-gate 
26390Sstevel@tonic-gate 	/*
26400Sstevel@tonic-gate 	 * Assign cvc to new cpu0's bbsram for I/O.  This has to be
26410Sstevel@tonic-gate 	 * done BEFORE cpu0 is moved via obp, since this logic
26420Sstevel@tonic-gate 	 * will cause obp_helper to switch to a different bbsram for
26430Sstevel@tonic-gate 	 * cvc I/O.  We don't want cvc writing to a buffer from which
26440Sstevel@tonic-gate 	 * nobody will pick up the data!
26450Sstevel@tonic-gate 	 */
26460Sstevel@tonic-gate 	cvc_assign_iocpu(cpuid);
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate 	rv = prom_starfire_move_cpu0(cpuid);
26490Sstevel@tonic-gate 
26500Sstevel@tonic-gate 	if (rv == 0) {
26510Sstevel@tonic-gate 		SIGBCPU = cp;
26520Sstevel@tonic-gate 
26530Sstevel@tonic-gate 		DRMACH_PR("successfully juggled to CPU %d\n", cpuid);
26540Sstevel@tonic-gate 		return (NULL);
26550Sstevel@tonic-gate 	} else {
26560Sstevel@tonic-gate 		DRMACH_PR("prom error: prom_starfire_move_cpu0(%d) "
26570Sstevel@tonic-gate 			"returned %d\n", cpuid, rv);
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate 		/*
26600Sstevel@tonic-gate 		 * The move failed, hopefully obp_helper is still back
26610Sstevel@tonic-gate 		 * at the old bootproc.  Move cvc back there.
26620Sstevel@tonic-gate 		 */
26630Sstevel@tonic-gate 		cvc_assign_iocpu(SIGBCPU->cpu_id);
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 
26660Sstevel@tonic-gate 		err = drerr_new(1, ESTF_MOVESIGB, "CPU %d", cpuid);
26670Sstevel@tonic-gate 		return (err);
26680Sstevel@tonic-gate 	}
26690Sstevel@tonic-gate 	/*NOTREACHED*/
26700Sstevel@tonic-gate }
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate static sbd_error_t *
26730Sstevel@tonic-gate drmach_cpu_release(drmachid_t id)
26740Sstevel@tonic-gate {
26750Sstevel@tonic-gate 	drmach_device_t	*dp;
26760Sstevel@tonic-gate 	processorid_t	 cpuid;
26770Sstevel@tonic-gate 	struct cpu	*cp;
26780Sstevel@tonic-gate 	sbd_error_t	*err;
26790Sstevel@tonic-gate 
26800Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
26810Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
26820Sstevel@tonic-gate 	dp = id;
26830Sstevel@tonic-gate 	cpuid = drmach_cpu_calc_id(dp);
26840Sstevel@tonic-gate 
26850Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
26860Sstevel@tonic-gate 
26870Sstevel@tonic-gate 	cp = cpu_get(cpuid);
26880Sstevel@tonic-gate 	if (cp == NULL)
26890Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
26900Sstevel@tonic-gate 	else if (SIGBCPU->cpu_id == cp->cpu_id)
26910Sstevel@tonic-gate 		err = drmach_cpu_juggle_bootproc(NULL);
26920Sstevel@tonic-gate 	else
26930Sstevel@tonic-gate 		err = NULL;
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	return (err);
26960Sstevel@tonic-gate }
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate static sbd_error_t *
26990Sstevel@tonic-gate drmach_cpu_status(drmachid_t id, drmach_status_t *stat)
27000Sstevel@tonic-gate {
27010Sstevel@tonic-gate 	drmach_device_t *dp;
27020Sstevel@tonic-gate 
27030Sstevel@tonic-gate 	ASSERT(DRMACH_IS_CPU_ID(id));
27040Sstevel@tonic-gate 	dp = id;
27050Sstevel@tonic-gate 
27060Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
27070Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
27080Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
27090Sstevel@tonic-gate 	stat->configured = (cpu_get(drmach_cpu_calc_id(dp)) != NULL);
27100Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
27110Sstevel@tonic-gate 	stat->busy = dp->busy;
2712*11311SSurya.Prakki@Sun.COM 	(void) strncpy(stat->type, dp->type, sizeof (stat->type));
27130Sstevel@tonic-gate 	stat->info[0] = '\0';
27140Sstevel@tonic-gate 
27150Sstevel@tonic-gate 	return (NULL);
27160Sstevel@tonic-gate }
27170Sstevel@tonic-gate 
27180Sstevel@tonic-gate sbd_error_t *
27190Sstevel@tonic-gate drmach_cpu_disconnect(drmachid_t id)
27200Sstevel@tonic-gate {
27210Sstevel@tonic-gate 	drmach_device_t	*cpu;
27220Sstevel@tonic-gate 	int		 cpuid;
27230Sstevel@tonic-gate 	int		 ntries;
27240Sstevel@tonic-gate 	int		 p;
27250Sstevel@tonic-gate 	u_longlong_t	 pc_addr;
27260Sstevel@tonic-gate 	uchar_t		 rvalue;
27270Sstevel@tonic-gate 
27280Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
27290Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
27300Sstevel@tonic-gate 	cpu = id;
27310Sstevel@tonic-gate 
27320Sstevel@tonic-gate 	cpuid = drmach_cpu_calc_id(cpu);
27330Sstevel@tonic-gate 	if (SIGBCPU->cpu_id == cpuid) {
27340Sstevel@tonic-gate 		/* this cpu is SIGBCPU, can't disconnect */
27350Sstevel@tonic-gate 		return (drerr_new(1, ESTF_HASSIGB, "%s::%s",
27360Sstevel@tonic-gate 				cpu->bp->cm.name, cpu->cm.name));
27370Sstevel@tonic-gate 	}
27380Sstevel@tonic-gate 
27390Sstevel@tonic-gate 	/*
27400Sstevel@tonic-gate 	 * Make sure SIGBST_DETACHED is set before
27410Sstevel@tonic-gate 	 * mapping out the sig block.
27420Sstevel@tonic-gate 	 */
27430Sstevel@tonic-gate 	ntries = drmach_cpu_ntries;
27440Sstevel@tonic-gate 	while (!drmach_cpu_obp_is_detached(cpuid) && ntries) {
27450Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
27460Sstevel@tonic-gate 		ntries--;
27470Sstevel@tonic-gate 	}
27480Sstevel@tonic-gate 	if (!drmach_cpu_obp_is_detached(cpuid)) {
27490Sstevel@tonic-gate 		cmn_err(CE_WARN, "failed to mark cpu %d detached in sigblock",
27500Sstevel@tonic-gate 			cpuid);
27510Sstevel@tonic-gate 	}
27520Sstevel@tonic-gate 
27530Sstevel@tonic-gate 	/* map out signature block */
27540Sstevel@tonic-gate 	if (CPU_SGN_EXISTS(cpuid)) {
27550Sstevel@tonic-gate 		CPU_SGN_MAPOUT(cpuid);
27560Sstevel@tonic-gate 	}
27570Sstevel@tonic-gate 
27580Sstevel@tonic-gate 	/*
27590Sstevel@tonic-gate 	 * We now PC IDLE the processor to guarantee we
27600Sstevel@tonic-gate 	 * stop any transactions from coming from it.
27610Sstevel@tonic-gate 	 */
27620Sstevel@tonic-gate 	p = cpu->unum & 1;
27630Sstevel@tonic-gate 	pc_addr = STARFIRE_BB_PC_ADDR(cpu->bp->bnum, cpu->unum, 0);
27640Sstevel@tonic-gate 
27650Sstevel@tonic-gate 	DRMACH_PR("PC idle cpu %d (addr = 0x%llx, port = %d, p = %d)",
27660Sstevel@tonic-gate 		drmach_cpu_calc_id(cpu), pc_addr, cpu->unum, p);
27670Sstevel@tonic-gate 
27680Sstevel@tonic-gate 	rvalue = ldbphysio(pc_addr);
27690Sstevel@tonic-gate 	rvalue |= STARFIRE_BB_PC_IDLE(p);
27700Sstevel@tonic-gate 	stbphysio(pc_addr, rvalue);
27710Sstevel@tonic-gate 	DELAY(50000);
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 	return (NULL);
27740Sstevel@tonic-gate }
27750Sstevel@tonic-gate 
27760Sstevel@tonic-gate sbd_error_t *
27770Sstevel@tonic-gate drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid)
27780Sstevel@tonic-gate {
27790Sstevel@tonic-gate 	drmach_device_t *cpu;
27800Sstevel@tonic-gate 
27810Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
27820Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
27830Sstevel@tonic-gate 	cpu = id;
27840Sstevel@tonic-gate 
27850Sstevel@tonic-gate 	*cpuid = drmach_cpu_calc_id(cpu);
27860Sstevel@tonic-gate 	return (NULL);
27870Sstevel@tonic-gate }
27880Sstevel@tonic-gate 
27890Sstevel@tonic-gate sbd_error_t *
27900Sstevel@tonic-gate drmach_cpu_get_impl(drmachid_t id, int *ip)
27910Sstevel@tonic-gate {
27920Sstevel@tonic-gate 	drmach_device_t *cpu;
27930Sstevel@tonic-gate 	int		impl;
27940Sstevel@tonic-gate 
27950Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
27960Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	cpu = id;
27990Sstevel@tonic-gate 
28000Sstevel@tonic-gate 	if (drmach_node_get_prop(cpu->node, "implementation#", &impl) == -1) {
28010Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
28020Sstevel@tonic-gate 	}
28030Sstevel@tonic-gate 
28040Sstevel@tonic-gate 	*ip = impl;
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate 	return (NULL);
28070Sstevel@tonic-gate }
28080Sstevel@tonic-gate 
28090Sstevel@tonic-gate void
28100Sstevel@tonic-gate drmach_cpu_flush_ecache_sync(void)
28110Sstevel@tonic-gate {
28120Sstevel@tonic-gate 	ASSERT(curthread->t_bound_cpu == CPU);
28130Sstevel@tonic-gate 
28140Sstevel@tonic-gate 	/*
28150Sstevel@tonic-gate 	 * Now let's flush our ecache thereby removing all references
28160Sstevel@tonic-gate 	 * to the target (detaching) memory from all ecache's in
28170Sstevel@tonic-gate 	 * system.
28180Sstevel@tonic-gate 	 */
28190Sstevel@tonic-gate 	cpu_flush_ecache();
28200Sstevel@tonic-gate 
28210Sstevel@tonic-gate 	/*
28220Sstevel@tonic-gate 	 * Delay 100 usec out of paranoia to insure everything
28230Sstevel@tonic-gate 	 * (hardware queues) has drained before we start reprogramming
28240Sstevel@tonic-gate 	 * the hardware.
28250Sstevel@tonic-gate 	 */
28260Sstevel@tonic-gate 	DELAY(100);
28270Sstevel@tonic-gate }
28280Sstevel@tonic-gate 
28290Sstevel@tonic-gate sbd_error_t *
28300Sstevel@tonic-gate drmach_get_dip(drmachid_t id, dev_info_t **dip)
28310Sstevel@tonic-gate {
28320Sstevel@tonic-gate 	drmach_device_t	*dp;
28330Sstevel@tonic-gate 
28340Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
28350Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28360Sstevel@tonic-gate 	dp = id;
28370Sstevel@tonic-gate 
28380Sstevel@tonic-gate 	*dip = drmach_node_get_dip(dp->node);
28390Sstevel@tonic-gate 	return (NULL);
28400Sstevel@tonic-gate }
28410Sstevel@tonic-gate 
28420Sstevel@tonic-gate sbd_error_t *
28430Sstevel@tonic-gate drmach_io_is_attached(drmachid_t id, int *yes)
28440Sstevel@tonic-gate {
28450Sstevel@tonic-gate 	drmach_device_t *dp;
28460Sstevel@tonic-gate 	dev_info_t	*dip;
28470Sstevel@tonic-gate 	int		state;
28480Sstevel@tonic-gate 
28490Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
28500Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28510Sstevel@tonic-gate 	dp = id;
28520Sstevel@tonic-gate 
28530Sstevel@tonic-gate 	dip = drmach_node_get_dip(dp->node);
28540Sstevel@tonic-gate 	if (dip == NULL) {
28550Sstevel@tonic-gate 		*yes = 0;
28560Sstevel@tonic-gate 		return (NULL);
28570Sstevel@tonic-gate 	}
28580Sstevel@tonic-gate 
28590Sstevel@tonic-gate 	state = ddi_get_devstate(dip);
28601333Scth 	*yes = (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP));
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	return (NULL);
28630Sstevel@tonic-gate }
28640Sstevel@tonic-gate 
28650Sstevel@tonic-gate sbd_error_t *
28660Sstevel@tonic-gate drmach_io_pre_release(drmachid_t id)
28670Sstevel@tonic-gate {
28680Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
28690Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28700Sstevel@tonic-gate 	return (NULL);
28710Sstevel@tonic-gate }
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate static sbd_error_t *
28740Sstevel@tonic-gate drmach_io_release(drmachid_t id)
28750Sstevel@tonic-gate {
28760Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
28770Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28780Sstevel@tonic-gate 	return (NULL);
28790Sstevel@tonic-gate }
28800Sstevel@tonic-gate 
28810Sstevel@tonic-gate sbd_error_t *
28820Sstevel@tonic-gate drmach_io_unrelease(drmachid_t id)
28830Sstevel@tonic-gate {
28840Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
28850Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28860Sstevel@tonic-gate 	return (NULL);
28870Sstevel@tonic-gate }
28880Sstevel@tonic-gate 
28890Sstevel@tonic-gate /*ARGSUSED*/
28900Sstevel@tonic-gate sbd_error_t *
28910Sstevel@tonic-gate drmach_io_post_release(drmachid_t id)
28920Sstevel@tonic-gate {
28930Sstevel@tonic-gate 	return (NULL);
28940Sstevel@tonic-gate }
28950Sstevel@tonic-gate 
28960Sstevel@tonic-gate /*ARGSUSED*/
28970Sstevel@tonic-gate sbd_error_t *
28980Sstevel@tonic-gate drmach_io_post_attach(drmachid_t id)
28990Sstevel@tonic-gate {
29000Sstevel@tonic-gate 	return (NULL);
29010Sstevel@tonic-gate }
29020Sstevel@tonic-gate 
29030Sstevel@tonic-gate static sbd_error_t *
29040Sstevel@tonic-gate drmach_io_status(drmachid_t id, drmach_status_t *stat)
29050Sstevel@tonic-gate {
29060Sstevel@tonic-gate 	drmach_device_t *dp;
29070Sstevel@tonic-gate 	sbd_error_t	*err;
29080Sstevel@tonic-gate 	int		 configured;
29090Sstevel@tonic-gate 
29100Sstevel@tonic-gate 	ASSERT(DRMACH_IS_IO_ID(id));
29110Sstevel@tonic-gate 	dp = id;
29120Sstevel@tonic-gate 
29130Sstevel@tonic-gate 	err = drmach_io_is_attached(id, &configured);
29140Sstevel@tonic-gate 	if (err)
29150Sstevel@tonic-gate 		return (err);
29160Sstevel@tonic-gate 
29170Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
29180Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
29190Sstevel@tonic-gate 	stat->configured = (configured != 0);
29200Sstevel@tonic-gate 	stat->busy = dp->busy;
2921*11311SSurya.Prakki@Sun.COM 	(void) strncpy(stat->type, dp->type, sizeof (stat->type));
29220Sstevel@tonic-gate 	stat->info[0] = '\0';
29230Sstevel@tonic-gate 
29240Sstevel@tonic-gate 	return (NULL);
29250Sstevel@tonic-gate }
29260Sstevel@tonic-gate 
29270Sstevel@tonic-gate static sbd_error_t *
29280Sstevel@tonic-gate drmach_mem_new(drmach_device_t *dp)
29290Sstevel@tonic-gate {
29300Sstevel@tonic-gate 	static sbd_error_t *drmach_mem_release(drmachid_t);
29310Sstevel@tonic-gate 	static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *);
29320Sstevel@tonic-gate 
29330Sstevel@tonic-gate 	dp->unum = 0;
29340Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_mem_new;
29350Sstevel@tonic-gate 	dp->cm.release = drmach_mem_release;
29360Sstevel@tonic-gate 	dp->cm.status = drmach_mem_status;
29370Sstevel@tonic-gate 
2938*11311SSurya.Prakki@Sun.COM 	(void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s", dp->type);
29390Sstevel@tonic-gate 
29400Sstevel@tonic-gate 	return (NULL);
29410Sstevel@tonic-gate }
29420Sstevel@tonic-gate 
29430Sstevel@tonic-gate sbd_error_t *
29440Sstevel@tonic-gate drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size)
29450Sstevel@tonic-gate {
29460Sstevel@tonic-gate 	pfn_t		basepfn = (pfn_t)(basepa >> PAGESHIFT);
29470Sstevel@tonic-gate 	pgcnt_t		npages = (pgcnt_t)(size >> PAGESHIFT);
29480Sstevel@tonic-gate 	pda_handle_t	ph;
29490Sstevel@tonic-gate 	int		rv;
29500Sstevel@tonic-gate 
29510Sstevel@tonic-gate 	ASSERT(size != 0);
29520Sstevel@tonic-gate 
29530Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
29540Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
29550Sstevel@tonic-gate 
29564266Sdp78419 	rv = kcage_range_add(basepfn, npages, KCAGE_DOWN);
29570Sstevel@tonic-gate 	if (rv == ENOMEM) {
2958*11311SSurya.Prakki@Sun.COM 		cmn_err(CE_WARN, "%lu megabytes not available to kernel cage",
2959*11311SSurya.Prakki@Sun.COM 			(ulong_t)(size == 0 ? 0 : size / MBYTE));
29600Sstevel@tonic-gate 	} else if (rv != 0) {
29610Sstevel@tonic-gate 		/* catch this in debug kernels */
29620Sstevel@tonic-gate 		ASSERT(0);
29630Sstevel@tonic-gate 
29640Sstevel@tonic-gate 		cmn_err(CE_WARN, "unexpected kcage_range_add"
29650Sstevel@tonic-gate 			" return value %d", rv);
29660Sstevel@tonic-gate 	}
29670Sstevel@tonic-gate 
29680Sstevel@tonic-gate 	/*
29690Sstevel@tonic-gate 	 * Update the PDA (post2obp) structure with the
29700Sstevel@tonic-gate 	 * range of the newly added memory.
29710Sstevel@tonic-gate 	 */
29720Sstevel@tonic-gate 	ph = drmach_pda_open();
29730Sstevel@tonic-gate 	if (ph != NULL) {
29740Sstevel@tonic-gate 		pda_mem_add_span(ph, basepa, size);
29750Sstevel@tonic-gate 		pda_close(ph);
29760Sstevel@tonic-gate 	}
29770Sstevel@tonic-gate 
29780Sstevel@tonic-gate 	return (NULL);
29790Sstevel@tonic-gate }
29800Sstevel@tonic-gate 
29810Sstevel@tonic-gate sbd_error_t *
29820Sstevel@tonic-gate drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size)
29830Sstevel@tonic-gate {
29840Sstevel@tonic-gate 	drmach_device_t	*mem = id;
29850Sstevel@tonic-gate 	pfn_t		basepfn = (pfn_t)(basepa >> PAGESHIFT);
29860Sstevel@tonic-gate 	pgcnt_t		npages = (pgcnt_t)(size >> PAGESHIFT);
29870Sstevel@tonic-gate 	uint_t		mcreg;
29880Sstevel@tonic-gate 	sbd_error_t	*err;
29890Sstevel@tonic-gate 	pda_handle_t	ph;
29900Sstevel@tonic-gate 	int		rv;
29910Sstevel@tonic-gate 
29920Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
29930Sstevel@tonic-gate 	if (err)
29940Sstevel@tonic-gate 		return (err);
29950Sstevel@tonic-gate 	else if (mcreg & STARFIRE_MC_INTERLEAVE_MASK) {
29960Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
29970Sstevel@tonic-gate 				mem->bp->cm.name, mem->cm.name));
29980Sstevel@tonic-gate 	}
29990Sstevel@tonic-gate 
30000Sstevel@tonic-gate 	if (size > 0) {
30010Sstevel@tonic-gate 		rv = kcage_range_delete_post_mem_del(basepfn, npages);
30020Sstevel@tonic-gate 		if (rv != 0) {
30030Sstevel@tonic-gate 			cmn_err(CE_WARN,
30040Sstevel@tonic-gate 			    "unexpected kcage_range_delete_post_mem_del"
30050Sstevel@tonic-gate 			    " return value %d", rv);
30060Sstevel@tonic-gate 			return (DRMACH_INTERNAL_ERROR());
30070Sstevel@tonic-gate 		}
30080Sstevel@tonic-gate 	}
30090Sstevel@tonic-gate 
30100Sstevel@tonic-gate 	/*
30110Sstevel@tonic-gate 	 * Update the PDA (post2obp) structure with the
30120Sstevel@tonic-gate 	 * range of removed memory.
30130Sstevel@tonic-gate 	 */
30140Sstevel@tonic-gate 	ph = drmach_pda_open();
30150Sstevel@tonic-gate 	if (ph != NULL) {
30160Sstevel@tonic-gate 		if (size > 0)
30170Sstevel@tonic-gate 			pda_mem_del_span(ph, basepa, size);
30180Sstevel@tonic-gate 
30190Sstevel@tonic-gate 		/* update PDA to board's new mc register settings */
30200Sstevel@tonic-gate 		pda_mem_sync(ph, mem->bp->bnum, 0);
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 		pda_close(ph);
30230Sstevel@tonic-gate 	}
30240Sstevel@tonic-gate 
30250Sstevel@tonic-gate 	return (NULL);
30260Sstevel@tonic-gate }
30270Sstevel@tonic-gate 
30280Sstevel@tonic-gate /* support routine for enable and disable */
30290Sstevel@tonic-gate static sbd_error_t *
30300Sstevel@tonic-gate drmach_mem_update_interconnect(drmachid_t id, uint_t mcreg)
30310Sstevel@tonic-gate {
30320Sstevel@tonic-gate 	drmach_device_t	*dp;
30330Sstevel@tonic-gate 	pda_handle_t	 ph;
30340Sstevel@tonic-gate 	int		 b;
30350Sstevel@tonic-gate 
30360Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
30370Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
30380Sstevel@tonic-gate 	dp = id;
30390Sstevel@tonic-gate 
30400Sstevel@tonic-gate 	ph = drmach_pda_open();
30410Sstevel@tonic-gate 	if (ph == NULL)
30420Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
30430Sstevel@tonic-gate 
30440Sstevel@tonic-gate 	for (b = 0; b < MAX_BOARDS; b++) {
30450Sstevel@tonic-gate 		int		p;
30460Sstevel@tonic-gate 		int		rv;
30470Sstevel@tonic-gate 		ushort_t	bda_proc, bda_ioc;
30480Sstevel@tonic-gate 		board_desc_t	*bdesc;
30490Sstevel@tonic-gate 
30500Sstevel@tonic-gate 		if (pda_board_present(ph, b) == 0)
30510Sstevel@tonic-gate 			continue;
30520Sstevel@tonic-gate 
30530Sstevel@tonic-gate 		bdesc = (board_desc_t *)pda_get_board_info(ph, b);
30540Sstevel@tonic-gate 
30550Sstevel@tonic-gate 		/*
30560Sstevel@tonic-gate 		 * Update PCs for CPUs.
30570Sstevel@tonic-gate 		 */
30580Sstevel@tonic-gate 
30590Sstevel@tonic-gate 		/* make sure definition in platmod is in sync with pda */
30600Sstevel@tonic-gate 		ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD);
30610Sstevel@tonic-gate 
30620Sstevel@tonic-gate 		bda_proc = bdesc->bda_proc;
30630Sstevel@tonic-gate 		for (p = 0; p < MAX_PROCMODS; p++) {
30640Sstevel@tonic-gate 			if (BDA_NBL(bda_proc, p) != BDAN_GOOD)
30650Sstevel@tonic-gate 				continue;
30660Sstevel@tonic-gate 
30670Sstevel@tonic-gate 			rv = pc_madr_add(b, dp->bp->bnum, p, mcreg);
30680Sstevel@tonic-gate 			if (rv) {
30690Sstevel@tonic-gate 				pda_close(ph);
30700Sstevel@tonic-gate 				return (DRMACH_INTERNAL_ERROR());
30710Sstevel@tonic-gate 			}
30720Sstevel@tonic-gate 		}
30730Sstevel@tonic-gate 
30740Sstevel@tonic-gate 		/*
30750Sstevel@tonic-gate 		 * Update PCs for IOCs.
30760Sstevel@tonic-gate 		 */
30770Sstevel@tonic-gate 
30780Sstevel@tonic-gate 		/* make sure definition in platmod is in sync with pda */
30790Sstevel@tonic-gate 		ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD);
30800Sstevel@tonic-gate 
30810Sstevel@tonic-gate 		bda_ioc = bdesc->bda_ioc;
30820Sstevel@tonic-gate 		for (p = 0; p < MAX_IOCS; p++) {
30830Sstevel@tonic-gate 			if (BDA_NBL(bda_ioc, p) != BDAN_GOOD)
30840Sstevel@tonic-gate 				continue;
30850Sstevel@tonic-gate 
30860Sstevel@tonic-gate 			rv = pc_madr_add(b, dp->bp->bnum, p + 4, mcreg);
30870Sstevel@tonic-gate 			if (rv) {
30880Sstevel@tonic-gate 				pda_close(ph);
30890Sstevel@tonic-gate 				return (DRMACH_INTERNAL_ERROR());
30900Sstevel@tonic-gate 			}
30910Sstevel@tonic-gate 		}
30920Sstevel@tonic-gate 	}
30930Sstevel@tonic-gate 
30940Sstevel@tonic-gate 	pda_close(ph);
30950Sstevel@tonic-gate 	return (NULL);
30960Sstevel@tonic-gate }
30970Sstevel@tonic-gate 
30980Sstevel@tonic-gate sbd_error_t *
30990Sstevel@tonic-gate drmach_mem_disable(drmachid_t id)
31000Sstevel@tonic-gate {
31010Sstevel@tonic-gate 	sbd_error_t	*err;
31020Sstevel@tonic-gate 	uint_t		 mcreg;
31030Sstevel@tonic-gate 
31040Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
31050Sstevel@tonic-gate 	if (err == NULL) {
31060Sstevel@tonic-gate 		ASSERT(mcreg & STARFIRE_MC_MEM_PRESENT_MASK);
31070Sstevel@tonic-gate 
31080Sstevel@tonic-gate 		/* Turn off presence bit. */
31090Sstevel@tonic-gate 		mcreg &= ~STARFIRE_MC_MEM_PRESENT_MASK;
31100Sstevel@tonic-gate 
31110Sstevel@tonic-gate 		err = drmach_mem_update_interconnect(id, mcreg);
31120Sstevel@tonic-gate 		if (err == NULL)
31130Sstevel@tonic-gate 			err = drmach_write_mc_asr(id, mcreg);
31140Sstevel@tonic-gate 	}
31150Sstevel@tonic-gate 
31160Sstevel@tonic-gate 	return (err);
31170Sstevel@tonic-gate }
31180Sstevel@tonic-gate 
31190Sstevel@tonic-gate sbd_error_t *
31200Sstevel@tonic-gate drmach_mem_enable(drmachid_t id)
31210Sstevel@tonic-gate {
31220Sstevel@tonic-gate 	sbd_error_t	*err;
31230Sstevel@tonic-gate 	uint_t		 mcreg;
31240Sstevel@tonic-gate 
31250Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
31260Sstevel@tonic-gate 	if (err == NULL) {
31270Sstevel@tonic-gate 		mcreg |= STARFIRE_MC_MEM_PRESENT_MASK;
31280Sstevel@tonic-gate 
31290Sstevel@tonic-gate 		err = drmach_write_mc_asr(id, mcreg);
31300Sstevel@tonic-gate 		if (err == NULL)
31310Sstevel@tonic-gate 			err = drmach_mem_update_interconnect(id, mcreg);
31320Sstevel@tonic-gate 	}
31330Sstevel@tonic-gate 
31340Sstevel@tonic-gate 	return (err);
31350Sstevel@tonic-gate }
31360Sstevel@tonic-gate 
31370Sstevel@tonic-gate sbd_error_t *
31380Sstevel@tonic-gate drmach_mem_get_alignment(drmachid_t id, uint64_t *mask)
31390Sstevel@tonic-gate {
31400Sstevel@tonic-gate 	drmach_device_t	*mem;
31410Sstevel@tonic-gate 	sbd_error_t	*err;
3142789Sahrens 	pnode_t		 nodeid;
31430Sstevel@tonic-gate 
31440Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
31450Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
31460Sstevel@tonic-gate 	mem = id;
31470Sstevel@tonic-gate 
31480Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(mem->node);
31490Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
31500Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
31510Sstevel@tonic-gate 	else {
31520Sstevel@tonic-gate 		uint64_t size;
31530Sstevel@tonic-gate 
31540Sstevel@tonic-gate 		size = mc_get_alignment_mask(nodeid);
31550Sstevel@tonic-gate 		if (size == (uint64_t)-1)
31560Sstevel@tonic-gate 			err = DRMACH_INTERNAL_ERROR();
31570Sstevel@tonic-gate 		else {
31580Sstevel@tonic-gate 			*mask = size - 1;
31590Sstevel@tonic-gate 			err = NULL;
31600Sstevel@tonic-gate 		}
31610Sstevel@tonic-gate 	}
31620Sstevel@tonic-gate 
31630Sstevel@tonic-gate 	return (err);
31640Sstevel@tonic-gate }
31650Sstevel@tonic-gate 
31660Sstevel@tonic-gate sbd_error_t *
31670Sstevel@tonic-gate drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa)
31680Sstevel@tonic-gate {
31690Sstevel@tonic-gate 	sbd_error_t	*err;
31700Sstevel@tonic-gate 	uint_t		 mcreg;
31710Sstevel@tonic-gate 
31720Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
31730Sstevel@tonic-gate 	if (err == NULL)
31740Sstevel@tonic-gate 		*pa = mc_asr_to_pa(mcreg);
31750Sstevel@tonic-gate 
31760Sstevel@tonic-gate 	return (err);
31770Sstevel@tonic-gate }
31780Sstevel@tonic-gate 
31790Sstevel@tonic-gate /*
31800Sstevel@tonic-gate  * Use of this routine after copy/rename will yield incorrect results,
31810Sstevel@tonic-gate  * because the OBP MEMAVAIL property will not correctly reflect the
31820Sstevel@tonic-gate  * programming of the MCs.
31830Sstevel@tonic-gate  */
31840Sstevel@tonic-gate sbd_error_t *
31850Sstevel@tonic-gate drmach_mem_get_memlist(drmachid_t id, struct memlist **ml)
31860Sstevel@tonic-gate {
31870Sstevel@tonic-gate 	drmach_device_t	*mem;
31880Sstevel@tonic-gate 	int		rv, i, rlen, rblks;
31890Sstevel@tonic-gate 	sbd_error_t	*err;
31900Sstevel@tonic-gate 	struct memlist	*mlist;
31910Sstevel@tonic-gate 	struct sf_memunit_regspec *rlist;
31920Sstevel@tonic-gate 
31930Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
31940Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
31950Sstevel@tonic-gate 	mem = id;
31960Sstevel@tonic-gate 
31970Sstevel@tonic-gate 	err = drmach_device_get_proplen(mem, "dr-available", &rlen);
31980Sstevel@tonic-gate 	if (err)
31990Sstevel@tonic-gate 		return (err);
32000Sstevel@tonic-gate 
32010Sstevel@tonic-gate 	rlist = kmem_zalloc(rlen, KM_SLEEP);
32020Sstevel@tonic-gate 
32030Sstevel@tonic-gate 	err = drmach_device_get_prop(mem, "dr-available", rlist);
32040Sstevel@tonic-gate 	if (err) {
32050Sstevel@tonic-gate 		kmem_free(rlist, rlen);
32060Sstevel@tonic-gate 		return (err);
32070Sstevel@tonic-gate 	}
32080Sstevel@tonic-gate 
32090Sstevel@tonic-gate 	mlist = NULL;
32100Sstevel@tonic-gate 	rblks = rlen / sizeof (struct sf_memunit_regspec);
32110Sstevel@tonic-gate 	for (i = 0; i < rblks; i++) {
32120Sstevel@tonic-gate 		uint64_t	addr, size;
32130Sstevel@tonic-gate 
32140Sstevel@tonic-gate 		addr  = (uint64_t)rlist[i].regspec_addr_hi << 32;
32150Sstevel@tonic-gate 		addr |= (uint64_t)rlist[i].regspec_addr_lo;
32160Sstevel@tonic-gate 		size  = (uint64_t)rlist[i].regspec_size_hi << 32;
32170Sstevel@tonic-gate 		size |= (uint64_t)rlist[i].regspec_size_lo;
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate 		mlist = memlist_add_span(mlist, addr, size);
32200Sstevel@tonic-gate 	}
32210Sstevel@tonic-gate 
32220Sstevel@tonic-gate 	kmem_free(rlist, rlen);
32230Sstevel@tonic-gate 
32240Sstevel@tonic-gate 	/*
32250Sstevel@tonic-gate 	 * Make sure the incoming memlist doesn't already
32260Sstevel@tonic-gate 	 * intersect with what's present in the system (phys_install).
32270Sstevel@tonic-gate 	 */
32280Sstevel@tonic-gate 	memlist_read_lock();
32290Sstevel@tonic-gate 	rv = memlist_intersect(phys_install, mlist);
32300Sstevel@tonic-gate 	memlist_read_unlock();
32310Sstevel@tonic-gate 	if (rv) {
32320Sstevel@tonic-gate #ifdef DEBUG
32330Sstevel@tonic-gate 		DRMACH_PR("OBP derived memlist intersects"
32340Sstevel@tonic-gate 			" with phys_install\n");
32350Sstevel@tonic-gate 		memlist_dump(mlist);
32360Sstevel@tonic-gate 
32370Sstevel@tonic-gate 		DRMACH_PR("phys_install memlist:\n");
32380Sstevel@tonic-gate 		memlist_dump(phys_install);
32390Sstevel@tonic-gate #endif
32400Sstevel@tonic-gate 
32410Sstevel@tonic-gate 		memlist_delete(mlist);
32420Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
32430Sstevel@tonic-gate 	}
32440Sstevel@tonic-gate 
32450Sstevel@tonic-gate #ifdef DEBUG
32460Sstevel@tonic-gate 	DRMACH_PR("OBP derived memlist:");
32470Sstevel@tonic-gate 	memlist_dump(mlist);
32480Sstevel@tonic-gate #endif
32490Sstevel@tonic-gate 
32500Sstevel@tonic-gate 	*ml = mlist;
32510Sstevel@tonic-gate 	return (NULL);
32520Sstevel@tonic-gate }
32530Sstevel@tonic-gate 
32540Sstevel@tonic-gate sbd_error_t *
32550Sstevel@tonic-gate drmach_mem_get_size(drmachid_t id, uint64_t *bytes)
32560Sstevel@tonic-gate {
32570Sstevel@tonic-gate 	drmach_device_t	*mem;
32580Sstevel@tonic-gate 	pda_handle_t	ph;
32590Sstevel@tonic-gate 	pgcnt_t		npages;
32600Sstevel@tonic-gate 
32610Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
32620Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
32630Sstevel@tonic-gate 	mem = id;
32640Sstevel@tonic-gate 
32650Sstevel@tonic-gate 	ph = drmach_pda_open();
32660Sstevel@tonic-gate 	if (ph == NULL)
32670Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
32680Sstevel@tonic-gate 
32690Sstevel@tonic-gate 	npages = pda_get_mem_size(ph, mem->bp->bnum);
32700Sstevel@tonic-gate 	*bytes = (uint64_t)npages << PAGESHIFT;
32710Sstevel@tonic-gate 
32720Sstevel@tonic-gate 	pda_close(ph);
32730Sstevel@tonic-gate 	return (NULL);
32740Sstevel@tonic-gate }
32750Sstevel@tonic-gate 
32760Sstevel@tonic-gate sbd_error_t *
32770Sstevel@tonic-gate drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes)
32780Sstevel@tonic-gate {
32790Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
32800Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
32810Sstevel@tonic-gate 
32820Sstevel@tonic-gate 	*bytes = mc_get_mem_alignment();
32830Sstevel@tonic-gate 	return (NULL);
32840Sstevel@tonic-gate }
32850Sstevel@tonic-gate 
32860Sstevel@tonic-gate /* field debugging tool */
32870Sstevel@tonic-gate processorid_t drmach_mem_cpu_affinity_nail = 0;
32880Sstevel@tonic-gate 
32890Sstevel@tonic-gate processorid_t
32900Sstevel@tonic-gate drmach_mem_cpu_affinity(drmachid_t id)
32910Sstevel@tonic-gate {
32920Sstevel@tonic-gate 	drmach_device_t	*mp;
32930Sstevel@tonic-gate 	drmach_board_t	*bp;
32940Sstevel@tonic-gate 	processorid_t	 cpuid;
32950Sstevel@tonic-gate 
32960Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
32970Sstevel@tonic-gate 		return (CPU_CURRENT);
32980Sstevel@tonic-gate 
32990Sstevel@tonic-gate 	if (drmach_mem_cpu_affinity_nail) {
33000Sstevel@tonic-gate 		cpuid = drmach_mem_cpu_affinity_nail;
33010Sstevel@tonic-gate 
33020Sstevel@tonic-gate 		if (cpuid < 0 || cpuid > NCPU)
33030Sstevel@tonic-gate 			return (CPU_CURRENT);
33040Sstevel@tonic-gate 
33050Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
33060Sstevel@tonic-gate 		if (cpu[cpuid] == NULL || !CPU_ACTIVE(cpu[cpuid]))
33070Sstevel@tonic-gate 			cpuid = CPU_CURRENT;
33080Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
33090Sstevel@tonic-gate 
33100Sstevel@tonic-gate 		return (cpuid);
33110Sstevel@tonic-gate 	}
33120Sstevel@tonic-gate 
33130Sstevel@tonic-gate 	/* try to choose a proc on the target board */
33140Sstevel@tonic-gate 	mp = id;
33150Sstevel@tonic-gate 	bp = mp->bp;
33160Sstevel@tonic-gate 	if (bp->devices) {
33170Sstevel@tonic-gate 		int		rv;
33180Sstevel@tonic-gate 		int		d_idx;
33190Sstevel@tonic-gate 		drmachid_t	d_id;
33200Sstevel@tonic-gate 
33210Sstevel@tonic-gate 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
33220Sstevel@tonic-gate 		while (rv == 0) {
33230Sstevel@tonic-gate 			if (DRMACH_IS_CPU_ID(d_id)) {
33240Sstevel@tonic-gate 				cpuid = drmach_cpu_calc_id(d_id);
33250Sstevel@tonic-gate 
33260Sstevel@tonic-gate 				mutex_enter(&cpu_lock);
33270Sstevel@tonic-gate 				if (cpu[cpuid] && CPU_ACTIVE(cpu[cpuid])) {
33280Sstevel@tonic-gate 					mutex_exit(&cpu_lock);
33290Sstevel@tonic-gate 					DRMACH_PR("drmach_mem_cpu_affinity: "
33300Sstevel@tonic-gate 					    "selected cpuid=%d\n", cpuid);
33310Sstevel@tonic-gate 					return (cpuid);
33320Sstevel@tonic-gate 				} else {
33330Sstevel@tonic-gate 					mutex_exit(&cpu_lock);
33340Sstevel@tonic-gate 				}
33350Sstevel@tonic-gate 			}
33360Sstevel@tonic-gate 
33370Sstevel@tonic-gate 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
33380Sstevel@tonic-gate 		}
33390Sstevel@tonic-gate 	}
33400Sstevel@tonic-gate 
33410Sstevel@tonic-gate 	/* otherwise, this proc, wherever it is */
33420Sstevel@tonic-gate 	DRMACH_PR("drmach_mem_cpu_affinity: using default CPU_CURRENT\n");
33430Sstevel@tonic-gate 
33440Sstevel@tonic-gate 	return (CPU_CURRENT);
33450Sstevel@tonic-gate }
33460Sstevel@tonic-gate 
33470Sstevel@tonic-gate static sbd_error_t *
33480Sstevel@tonic-gate drmach_mem_release(drmachid_t id)
33490Sstevel@tonic-gate {
33500Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
33510Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
33520Sstevel@tonic-gate 	return (NULL);
33530Sstevel@tonic-gate }
33540Sstevel@tonic-gate 
33550Sstevel@tonic-gate static sbd_error_t *
33560Sstevel@tonic-gate drmach_mem_status(drmachid_t id, drmach_status_t *stat)
33570Sstevel@tonic-gate {
33580Sstevel@tonic-gate 	drmach_device_t *dp;
33590Sstevel@tonic-gate 	sbd_error_t	*err;
33600Sstevel@tonic-gate 	uint64_t	 pa, slice_size;
33610Sstevel@tonic-gate 	struct memlist	*ml;
33620Sstevel@tonic-gate 
33630Sstevel@tonic-gate 	ASSERT(DRMACH_IS_MEM_ID(id));
33640Sstevel@tonic-gate 	dp = id;
33650Sstevel@tonic-gate 
33660Sstevel@tonic-gate 	/* get starting physical address of target memory */
33670Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(id, &pa);
33680Sstevel@tonic-gate 	if (err)
33690Sstevel@tonic-gate 		return (err);
33700Sstevel@tonic-gate 
33710Sstevel@tonic-gate 	/* round down to slice boundary */
33720Sstevel@tonic-gate 	slice_size = mc_get_mem_alignment();
33730Sstevel@tonic-gate 	pa &= ~ (slice_size - 1);
33740Sstevel@tonic-gate 
33750Sstevel@tonic-gate 	/* stop at first span that is in slice */
33760Sstevel@tonic-gate 	memlist_read_lock();
33770Sstevel@tonic-gate 	for (ml = phys_install; ml; ml = ml->next)
33780Sstevel@tonic-gate 		if (ml->address >= pa && ml->address < pa + slice_size)
33790Sstevel@tonic-gate 			break;
33800Sstevel@tonic-gate 	memlist_read_unlock();
33810Sstevel@tonic-gate 
33820Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
33830Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
33840Sstevel@tonic-gate 	stat->configured = (ml != NULL);
33850Sstevel@tonic-gate 	stat->busy = dp->busy;
3386*11311SSurya.Prakki@Sun.COM 	(void) strncpy(stat->type, dp->type, sizeof (stat->type));
33870Sstevel@tonic-gate 	stat->info[0] = '\0';
33880Sstevel@tonic-gate 
33890Sstevel@tonic-gate 	return (NULL);
33900Sstevel@tonic-gate }
33910Sstevel@tonic-gate 
33920Sstevel@tonic-gate static int
33930Sstevel@tonic-gate drmach_detach_board(void *arg)
33940Sstevel@tonic-gate {
33950Sstevel@tonic-gate 	cpuset_t	cset;
33960Sstevel@tonic-gate 	int		retval;
33970Sstevel@tonic-gate 	drmach_board_t	*bp = (drmach_board_t *)arg;
33980Sstevel@tonic-gate 
33990Sstevel@tonic-gate 	cset = cpu_ready_set;
34000Sstevel@tonic-gate 	promsafe_xc_attention(cset);
34010Sstevel@tonic-gate 
34020Sstevel@tonic-gate 	retval = prom_starfire_rm_brd(bp->bnum);
34030Sstevel@tonic-gate 
34040Sstevel@tonic-gate 	xc_dismissed(cset);
34050Sstevel@tonic-gate 
34060Sstevel@tonic-gate 	return (retval);
34070Sstevel@tonic-gate }
34080Sstevel@tonic-gate 
34090Sstevel@tonic-gate sbd_error_t *
34100Sstevel@tonic-gate drmach_board_deprobe(drmachid_t id)
34110Sstevel@tonic-gate {
34120Sstevel@tonic-gate 	drmach_board_t	*bp;
34130Sstevel@tonic-gate 	int		 retval;
34140Sstevel@tonic-gate 
34150Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
34160Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
34170Sstevel@tonic-gate 	bp = id;
34180Sstevel@tonic-gate 
34190Sstevel@tonic-gate 	cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum);
34200Sstevel@tonic-gate 
34210Sstevel@tonic-gate 	retval = prom_tree_update(drmach_detach_board, bp);
34220Sstevel@tonic-gate 
34230Sstevel@tonic-gate 	if (retval == 0)
34240Sstevel@tonic-gate 		return (NULL);
34250Sstevel@tonic-gate 	else {
34260Sstevel@tonic-gate 		cmn_err(CE_WARN, "prom error: prom_starfire_rm_brd(%d) "
34270Sstevel@tonic-gate 			"returned %d", bp->bnum, retval);
34280Sstevel@tonic-gate 		return (drerr_new(1, ESTF_DEPROBE, "%s", bp->cm.name));
34290Sstevel@tonic-gate 	}
34300Sstevel@tonic-gate }
34310Sstevel@tonic-gate 
34320Sstevel@tonic-gate /*ARGSUSED*/
34330Sstevel@tonic-gate static sbd_error_t *
34340Sstevel@tonic-gate drmach_pt_juggle_bootproc(drmachid_t id, drmach_opts_t *opts)
34350Sstevel@tonic-gate {
34360Sstevel@tonic-gate 	drmach_device_t	*cpu;
34370Sstevel@tonic-gate 	sbd_error_t	*err;
34380Sstevel@tonic-gate 
34390Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
34400Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
34410Sstevel@tonic-gate 	cpu = id;
34420Sstevel@tonic-gate 
34430Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
34440Sstevel@tonic-gate 
34450Sstevel@tonic-gate 	err = drmach_cpu_juggle_bootproc(cpu);
34460Sstevel@tonic-gate 
34470Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
34480Sstevel@tonic-gate 
34490Sstevel@tonic-gate 	return (err);
34500Sstevel@tonic-gate }
34510Sstevel@tonic-gate 
34520Sstevel@tonic-gate /*ARGSUSED*/
34530Sstevel@tonic-gate static sbd_error_t *
34540Sstevel@tonic-gate drmach_pt_dump_pdainfo(drmachid_t id, drmach_opts_t *opts)
34550Sstevel@tonic-gate {
34560Sstevel@tonic-gate 	drmach_board_t	*bp;
34570Sstevel@tonic-gate 	int		board;
34580Sstevel@tonic-gate 	int		i;
34590Sstevel@tonic-gate 	pda_handle_t	ph;
34600Sstevel@tonic-gate 	board_desc_t	*bdesc;
34610Sstevel@tonic-gate 
34620Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
34630Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
34640Sstevel@tonic-gate 	bp = id;
34650Sstevel@tonic-gate 	board = bp->bnum;
34660Sstevel@tonic-gate 
34670Sstevel@tonic-gate 	ph = drmach_pda_open();
34680Sstevel@tonic-gate 	if (ph == NULL)
34690Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
34700Sstevel@tonic-gate 
34710Sstevel@tonic-gate 	if (pda_board_present(ph, board) == 0) {
34720Sstevel@tonic-gate 		cmn_err(CE_CONT, "board %d is MISSING\n", board);
34730Sstevel@tonic-gate 		pda_close(ph);
34740Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
34750Sstevel@tonic-gate 	}
34760Sstevel@tonic-gate 
34770Sstevel@tonic-gate 	cmn_err(CE_CONT, "board %d is PRESENT\n", board);
34780Sstevel@tonic-gate 
34790Sstevel@tonic-gate 	bdesc = (board_desc_t *)pda_get_board_info(ph, board);
34800Sstevel@tonic-gate 	if (bdesc == NULL) {
34810Sstevel@tonic-gate 		cmn_err(CE_CONT,
34820Sstevel@tonic-gate 			"no board descriptor found for board %d\n",
34830Sstevel@tonic-gate 			board);
34840Sstevel@tonic-gate 		pda_close(ph);
34850Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
34860Sstevel@tonic-gate 	}
34870Sstevel@tonic-gate 
34880Sstevel@tonic-gate 	/* make sure definition in platmod is in sync with pda */
34890Sstevel@tonic-gate 	ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD);
34900Sstevel@tonic-gate 
34910Sstevel@tonic-gate 	for (i = 0; i < MAX_PROCMODS; i++) {
34920Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_proc, i) == BDAN_GOOD)
34930Sstevel@tonic-gate 			cmn_err(CE_CONT,
34940Sstevel@tonic-gate 				"proc %d.%d PRESENT\n", board, i);
34950Sstevel@tonic-gate 		else
34960Sstevel@tonic-gate 			cmn_err(CE_CONT,
34970Sstevel@tonic-gate 				"proc %d.%d MISSING\n", board, i);
34980Sstevel@tonic-gate 	}
34990Sstevel@tonic-gate 
35000Sstevel@tonic-gate 	for (i = 0; i < MAX_MGROUPS; i++) {
35010Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_mgroup, i) == BDAN_GOOD)
35020Sstevel@tonic-gate 			cmn_err(CE_CONT,
35030Sstevel@tonic-gate 				"mgroup %d.%d PRESENT\n", board, i);
35040Sstevel@tonic-gate 		else
35050Sstevel@tonic-gate 			cmn_err(CE_CONT,
35060Sstevel@tonic-gate 				"mgroup %d.%d MISSING\n", board, i);
35070Sstevel@tonic-gate 	}
35080Sstevel@tonic-gate 
35090Sstevel@tonic-gate 	/* make sure definition in platmod is in sync with pda */
35100Sstevel@tonic-gate 	ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD);
35110Sstevel@tonic-gate 
35120Sstevel@tonic-gate 	for (i = 0; i < MAX_IOCS; i++) {
35130Sstevel@tonic-gate 		int	s;
35140Sstevel@tonic-gate 
35150Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_ioc, i) == BDAN_GOOD) {
35160Sstevel@tonic-gate 			cmn_err(CE_CONT,
35170Sstevel@tonic-gate 				"ioc %d.%d PRESENT\n", board, i);
35180Sstevel@tonic-gate 			for (s = 0; s < MAX_SLOTS_PER_IOC; s++) {
35190Sstevel@tonic-gate 				if (BDA_NBL(bdesc->bda_ios[i], s) != BDAN_GOOD)
35200Sstevel@tonic-gate 					continue;
35210Sstevel@tonic-gate 				cmn_err(CE_CONT,
35220Sstevel@tonic-gate 					"..scard %d.%d.%d PRESENT\n",
35230Sstevel@tonic-gate 					board, i, s);
35240Sstevel@tonic-gate 			}
35250Sstevel@tonic-gate 		} else {
35260Sstevel@tonic-gate 			cmn_err(CE_CONT,
35270Sstevel@tonic-gate 				"ioc %d.%d MISSING\n",
35280Sstevel@tonic-gate 				board, i);
35290Sstevel@tonic-gate 		}
35300Sstevel@tonic-gate 	}
35310Sstevel@tonic-gate 
35320Sstevel@tonic-gate 	cmn_err(CE_CONT,
35330Sstevel@tonic-gate 		"board %d memsize = %d pages\n",
35340Sstevel@tonic-gate 		board, pda_get_mem_size(ph, board));
35350Sstevel@tonic-gate 
35360Sstevel@tonic-gate 	pda_close(ph);
35370Sstevel@tonic-gate 
35380Sstevel@tonic-gate 	return (NULL);
35390Sstevel@tonic-gate }
35400Sstevel@tonic-gate 
35410Sstevel@tonic-gate /*ARGSUSED*/
35420Sstevel@tonic-gate sbd_error_t *
35430Sstevel@tonic-gate drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts)
35440Sstevel@tonic-gate {
35450Sstevel@tonic-gate 	struct memlist	*ml;
35460Sstevel@tonic-gate 	uint64_t	src_pa;
35470Sstevel@tonic-gate 	uint64_t	dst_pa;
35480Sstevel@tonic-gate 	uint64_t	dst;
35490Sstevel@tonic-gate 
35500Sstevel@tonic-gate 	dst_pa = va_to_pa(&dst);
35510Sstevel@tonic-gate 
35520Sstevel@tonic-gate 	memlist_read_lock();
35530Sstevel@tonic-gate 	for (ml = phys_install; ml; ml = ml->next) {
35540Sstevel@tonic-gate 		uint64_t	nbytes;
35550Sstevel@tonic-gate 
35560Sstevel@tonic-gate 		src_pa = ml->address;
35570Sstevel@tonic-gate 		nbytes = ml->size;
35580Sstevel@tonic-gate 
35590Sstevel@tonic-gate 		while (nbytes != 0ull) {
35600Sstevel@tonic-gate 
35610Sstevel@tonic-gate 			/* copy 32 bytes at arc_pa to dst_pa */
35620Sstevel@tonic-gate 			bcopy32_il(src_pa, dst_pa);
35630Sstevel@tonic-gate 
35640Sstevel@tonic-gate 			/* increment by 32 bytes */
35650Sstevel@tonic-gate 			src_pa += (4 * sizeof (uint64_t));
35660Sstevel@tonic-gate 
35670Sstevel@tonic-gate 			/* decrement by 32 bytes */
35680Sstevel@tonic-gate 			nbytes -= (4 * sizeof (uint64_t));
35690Sstevel@tonic-gate 		}
35700Sstevel@tonic-gate 	}
35710Sstevel@tonic-gate 	memlist_read_unlock();
35720Sstevel@tonic-gate 
35730Sstevel@tonic-gate 	return (NULL);
35740Sstevel@tonic-gate }
35750Sstevel@tonic-gate 
35760Sstevel@tonic-gate static struct {
35770Sstevel@tonic-gate 	const char	*name;
35780Sstevel@tonic-gate 	sbd_error_t	*(*handler)(drmachid_t id, drmach_opts_t *opts);
35790Sstevel@tonic-gate } drmach_pt_arr[] = {
35800Sstevel@tonic-gate 	{ "juggle",		drmach_pt_juggle_bootproc	},
35810Sstevel@tonic-gate 	{ "pda",		drmach_pt_dump_pdainfo		},
35820Sstevel@tonic-gate 	{ "readmem",		drmach_pt_readmem		},
35830Sstevel@tonic-gate 
35840Sstevel@tonic-gate 	/* the following line must always be last */
35850Sstevel@tonic-gate 	{ NULL,			NULL				}
35860Sstevel@tonic-gate };
35870Sstevel@tonic-gate 
35880Sstevel@tonic-gate /*ARGSUSED*/
35890Sstevel@tonic-gate sbd_error_t *
35900Sstevel@tonic-gate drmach_passthru(drmachid_t id, drmach_opts_t *opts)
35910Sstevel@tonic-gate {
35920Sstevel@tonic-gate 	int		i;
35930Sstevel@tonic-gate 	sbd_error_t	*err;
35940Sstevel@tonic-gate 
35950Sstevel@tonic-gate 	i = 0;
35960Sstevel@tonic-gate 	while (drmach_pt_arr[i].name != NULL) {
35970Sstevel@tonic-gate 		int len = strlen(drmach_pt_arr[i].name);
35980Sstevel@tonic-gate 
35990Sstevel@tonic-gate 		if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0)
36000Sstevel@tonic-gate 			break;
36010Sstevel@tonic-gate 
36020Sstevel@tonic-gate 		i += 1;
36030Sstevel@tonic-gate 	}
36040Sstevel@tonic-gate 
36050Sstevel@tonic-gate 	if (drmach_pt_arr[i].name == NULL)
36060Sstevel@tonic-gate 		err = drerr_new(0, ESTF_UNKPTCMD, opts->copts);
36070Sstevel@tonic-gate 	else
36080Sstevel@tonic-gate 		err = (*drmach_pt_arr[i].handler)(id, opts);
36090Sstevel@tonic-gate 
36100Sstevel@tonic-gate 	return (err);
36110Sstevel@tonic-gate }
36120Sstevel@tonic-gate 
36130Sstevel@tonic-gate sbd_error_t *
36140Sstevel@tonic-gate drmach_release(drmachid_t id)
36150Sstevel@tonic-gate {
36160Sstevel@tonic-gate 	drmach_common_t *cp;
36170Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
36180Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
36190Sstevel@tonic-gate 	cp = id;
36200Sstevel@tonic-gate 
36210Sstevel@tonic-gate 	return (cp->release(id));
36220Sstevel@tonic-gate }
36230Sstevel@tonic-gate 
36240Sstevel@tonic-gate sbd_error_t *
36250Sstevel@tonic-gate drmach_status(drmachid_t id, drmach_status_t *stat)
36260Sstevel@tonic-gate {
36270Sstevel@tonic-gate 	drmach_common_t *cp;
36280Sstevel@tonic-gate 
36290Sstevel@tonic-gate 	if (!DRMACH_IS_ID(id))
36300Sstevel@tonic-gate 		return (drerr_new(0, ESTF_NOTID, NULL));
36310Sstevel@tonic-gate 	cp = id;
36320Sstevel@tonic-gate 
36330Sstevel@tonic-gate 	return (cp->status(id, stat));
36340Sstevel@tonic-gate }
36350Sstevel@tonic-gate 
36360Sstevel@tonic-gate sbd_error_t *
36370Sstevel@tonic-gate drmach_unconfigure(drmachid_t id, int flags)
36380Sstevel@tonic-gate {
36390Sstevel@tonic-gate 	drmach_device_t	*dp;
3640789Sahrens 	pnode_t		 nodeid;
36410Sstevel@tonic-gate 	dev_info_t	*dip, *fdip = NULL;
36420Sstevel@tonic-gate 
36430Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
36440Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
36450Sstevel@tonic-gate 
36460Sstevel@tonic-gate 	dp = id;
36470Sstevel@tonic-gate 
36480Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
36490Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
36500Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
36510Sstevel@tonic-gate 
36520Sstevel@tonic-gate 	dip = e_ddi_nodeid_to_dip(nodeid);
36530Sstevel@tonic-gate 	if (dip == NULL)
36540Sstevel@tonic-gate 		return (NULL);
36550Sstevel@tonic-gate 
36560Sstevel@tonic-gate 	/*
36570Sstevel@tonic-gate 	 * Branch already held, so hold acquired in
36580Sstevel@tonic-gate 	 * e_ddi_nodeid_to_dip() can be released
36590Sstevel@tonic-gate 	 */
36600Sstevel@tonic-gate 	ddi_release_devi(dip);
36610Sstevel@tonic-gate 
36621772Sjl139090 	if (flags & DEVI_BRANCH_DESTROY)
36631772Sjl139090 		flags |= DEVI_BRANCH_EVENT;
36640Sstevel@tonic-gate 
36650Sstevel@tonic-gate 	/*
36660Sstevel@tonic-gate 	 * Force flag is no longer necessary. See starcat/io/drmach.c
36670Sstevel@tonic-gate 	 * for details.
36680Sstevel@tonic-gate 	 */
36690Sstevel@tonic-gate 	ASSERT(e_ddi_branch_held(dip));
36701772Sjl139090 	if (e_ddi_branch_unconfigure(dip, &fdip, flags)) {
36710Sstevel@tonic-gate 		sbd_error_t	*err;
36720Sstevel@tonic-gate 		char		*path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
36730Sstevel@tonic-gate 
36740Sstevel@tonic-gate 		/*
36750Sstevel@tonic-gate 		 * If non-NULL, fdip is returned held and must be released.
36760Sstevel@tonic-gate 		 */
36770Sstevel@tonic-gate 		if (fdip != NULL) {
36780Sstevel@tonic-gate 			(void) ddi_pathname(fdip, path);
36790Sstevel@tonic-gate 			ndi_rele_devi(fdip);
36800Sstevel@tonic-gate 		} else {
36810Sstevel@tonic-gate 			(void) ddi_pathname(dip, path);
36820Sstevel@tonic-gate 		}
36830Sstevel@tonic-gate 
36840Sstevel@tonic-gate 		err = drerr_new(1, ESTF_DRVFAIL, path);
36850Sstevel@tonic-gate 
36860Sstevel@tonic-gate 		kmem_free(path, MAXPATHLEN);
36870Sstevel@tonic-gate 
36880Sstevel@tonic-gate 		return (err);
36890Sstevel@tonic-gate 	}
36900Sstevel@tonic-gate 
36910Sstevel@tonic-gate 	return (NULL);
36920Sstevel@tonic-gate }
36930Sstevel@tonic-gate 
36940Sstevel@tonic-gate /*
36950Sstevel@tonic-gate  * drmach interfaces to legacy Starfire platmod logic
36960Sstevel@tonic-gate  * linkage via runtime symbol look up, called from plat_cpu_power*
36970Sstevel@tonic-gate  */
36980Sstevel@tonic-gate 
36990Sstevel@tonic-gate /*
37000Sstevel@tonic-gate  * Start up a cpu.  It is possible that we're attempting to restart
37010Sstevel@tonic-gate  * the cpu after an UNCONFIGURE in which case the cpu will be
37020Sstevel@tonic-gate  * spinning in its cache.  So, all we have to do is wakeup him up.
37030Sstevel@tonic-gate  * Under normal circumstances the cpu will be coming from a previous
37040Sstevel@tonic-gate  * CONNECT and thus will be spinning in OBP.  In both cases, the
37050Sstevel@tonic-gate  * startup sequence is the same.
37060Sstevel@tonic-gate  */
37070Sstevel@tonic-gate int
37080Sstevel@tonic-gate drmach_cpu_poweron(struct cpu *cp)
37090Sstevel@tonic-gate {
37100Sstevel@tonic-gate 	DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id);
37110Sstevel@tonic-gate 
37120Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
37130Sstevel@tonic-gate 
37140Sstevel@tonic-gate 	if (drmach_cpu_start(cp) != 0)
37150Sstevel@tonic-gate 		return (EBUSY);
37160Sstevel@tonic-gate 	else
37170Sstevel@tonic-gate 		return (0);
37180Sstevel@tonic-gate }
37190Sstevel@tonic-gate 
37200Sstevel@tonic-gate int
37210Sstevel@tonic-gate drmach_cpu_poweroff(struct cpu *cp)
37220Sstevel@tonic-gate {
37230Sstevel@tonic-gate 	int		ntries, cnt;
37240Sstevel@tonic-gate 	processorid_t	cpuid = cp->cpu_id;
37250Sstevel@tonic-gate 	void		drmach_cpu_shutdown_self(void);
37260Sstevel@tonic-gate 
37270Sstevel@tonic-gate 	DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id);
37280Sstevel@tonic-gate 
37290Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
37300Sstevel@tonic-gate 
37310Sstevel@tonic-gate 	/*
37320Sstevel@tonic-gate 	 * Capture all CPUs (except for detaching proc) to prevent
37330Sstevel@tonic-gate 	 * crosscalls to the detaching proc until it has cleared its
37340Sstevel@tonic-gate 	 * bit in cpu_ready_set.
37350Sstevel@tonic-gate 	 *
37360Sstevel@tonic-gate 	 * The CPU's remain paused and the prom_mutex is known to be free.
37370Sstevel@tonic-gate 	 * This prevents the x-trap victim from blocking when doing prom
37380Sstevel@tonic-gate 	 * IEEE-1275 calls at a high PIL level.
37390Sstevel@tonic-gate 	 */
37400Sstevel@tonic-gate 	promsafe_pause_cpus();
37410Sstevel@tonic-gate 
37420Sstevel@tonic-gate 	/*
37430Sstevel@tonic-gate 	 * Quiesce interrupts on the target CPU. We do this by setting
37440Sstevel@tonic-gate 	 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
37450Sstevel@tonic-gate 	 * prevent it from receiving cross calls and cross traps.
37460Sstevel@tonic-gate 	 * This prevents the processor from receiving any new soft interrupts.
37470Sstevel@tonic-gate 	 */
37480Sstevel@tonic-gate 	mp_cpu_quiesce(cp);
37490Sstevel@tonic-gate 
37500Sstevel@tonic-gate 	/* setup xt_mb, will be cleared by drmach_shutdown_asm when ready */
37510Sstevel@tonic-gate 	drmach_xt_mb[cpuid] = 0x80;
37520Sstevel@tonic-gate 
37530Sstevel@tonic-gate 	xt_one_unchecked(cpuid, (xcfunc_t *)idle_stop_xcall,
37540Sstevel@tonic-gate 		(uint64_t)drmach_cpu_shutdown_self, NULL);
37550Sstevel@tonic-gate 
37560Sstevel@tonic-gate 	ntries = drmach_cpu_ntries;
37570Sstevel@tonic-gate 	cnt = 0;
37580Sstevel@tonic-gate 	while (drmach_xt_mb[cpuid] && ntries) {
37590Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
37600Sstevel@tonic-gate 		ntries--;
37610Sstevel@tonic-gate 		cnt++;
37620Sstevel@tonic-gate 	}
37630Sstevel@tonic-gate 
37640Sstevel@tonic-gate 	drmach_xt_mb[cpuid] = 0;	/* steal the cache line back */
37650Sstevel@tonic-gate 
37660Sstevel@tonic-gate 	start_cpus();
37670Sstevel@tonic-gate 
37680Sstevel@tonic-gate 	DRMACH_PR("waited %d out of %d tries for "
37690Sstevel@tonic-gate 		"drmach_cpu_shutdown_self on cpu%d",
37700Sstevel@tonic-gate 		drmach_cpu_ntries - ntries, drmach_cpu_ntries, cp->cpu_id);
37710Sstevel@tonic-gate 
37720Sstevel@tonic-gate 	drmach_cpu_obp_detach(cpuid);
37730Sstevel@tonic-gate 
37740Sstevel@tonic-gate 	CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
37750Sstevel@tonic-gate 
37760Sstevel@tonic-gate 	return (0);
37770Sstevel@tonic-gate }
37780Sstevel@tonic-gate 
37790Sstevel@tonic-gate /*ARGSUSED*/
37800Sstevel@tonic-gate int
37810Sstevel@tonic-gate drmach_verify_sr(dev_info_t *dip, int sflag)
37820Sstevel@tonic-gate {
37830Sstevel@tonic-gate 	return (0);
37840Sstevel@tonic-gate }
37850Sstevel@tonic-gate 
37860Sstevel@tonic-gate void
37870Sstevel@tonic-gate drmach_suspend_last(void)
37880Sstevel@tonic-gate {
37890Sstevel@tonic-gate }
37900Sstevel@tonic-gate 
37910Sstevel@tonic-gate void
37920Sstevel@tonic-gate drmach_resume_first(void)
37930Sstevel@tonic-gate {
37940Sstevel@tonic-gate }
37950Sstevel@tonic-gate 
37960Sstevel@tonic-gate /*
37970Sstevel@tonic-gate  * Log a DR sysevent.
37980Sstevel@tonic-gate  * Return value: 0 success, non-zero failure.
37990Sstevel@tonic-gate  */
38000Sstevel@tonic-gate int
38010Sstevel@tonic-gate drmach_log_sysevent(int board, char *hint, int flag, int verbose)
38020Sstevel@tonic-gate {
38030Sstevel@tonic-gate 	sysevent_t			*ev;
38040Sstevel@tonic-gate 	sysevent_id_t			eid;
38050Sstevel@tonic-gate 	int				rv, km_flag;
38060Sstevel@tonic-gate 	sysevent_value_t		evnt_val;
38070Sstevel@tonic-gate 	sysevent_attr_list_t		*evnt_attr_list = NULL;
38080Sstevel@tonic-gate 	char				attach_pnt[MAXNAMELEN];
38090Sstevel@tonic-gate 
38100Sstevel@tonic-gate 	km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
38110Sstevel@tonic-gate 	attach_pnt[0] = '\0';
38120Sstevel@tonic-gate 	if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) {
38130Sstevel@tonic-gate 		rv = -1;
38140Sstevel@tonic-gate 		goto logexit;
38150Sstevel@tonic-gate 	}
38160Sstevel@tonic-gate 	if (verbose)
38170Sstevel@tonic-gate 		DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n",
38180Sstevel@tonic-gate 			    attach_pnt, hint, flag, verbose);
38190Sstevel@tonic-gate 
38200Sstevel@tonic-gate 	if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE,
38210Sstevel@tonic-gate 				    SUNW_KERN_PUB"dr", km_flag)) == NULL) {
38220Sstevel@tonic-gate 		rv = -2;
38230Sstevel@tonic-gate 		goto logexit;
38240Sstevel@tonic-gate 	}
38250Sstevel@tonic-gate 	evnt_val.value_type = SE_DATA_TYPE_STRING;
38260Sstevel@tonic-gate 	evnt_val.value.sv_string = attach_pnt;
38270Sstevel@tonic-gate 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID,
38280Sstevel@tonic-gate 				    &evnt_val, km_flag)) != 0)
38290Sstevel@tonic-gate 		goto logexit;
38300Sstevel@tonic-gate 
38310Sstevel@tonic-gate 	evnt_val.value_type = SE_DATA_TYPE_STRING;
38320Sstevel@tonic-gate 	evnt_val.value.sv_string = hint;
38330Sstevel@tonic-gate 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT,
38340Sstevel@tonic-gate 				    &evnt_val, km_flag)) != 0) {
38350Sstevel@tonic-gate 		sysevent_free_attr(evnt_attr_list);
38360Sstevel@tonic-gate 		goto logexit;
38370Sstevel@tonic-gate 	}
38380Sstevel@tonic-gate 
38390Sstevel@tonic-gate 	(void) sysevent_attach_attributes(ev, evnt_attr_list);
38400Sstevel@tonic-gate 
38410Sstevel@tonic-gate 	/*
38420Sstevel@tonic-gate 	 * Log the event but do not sleep waiting for its
38430Sstevel@tonic-gate 	 * delivery. This provides insulation from syseventd.
38440Sstevel@tonic-gate 	 */
38450Sstevel@tonic-gate 	rv = log_sysevent(ev, SE_NOSLEEP, &eid);
38460Sstevel@tonic-gate 
38470Sstevel@tonic-gate logexit:
38480Sstevel@tonic-gate 	if (ev)
38490Sstevel@tonic-gate 		sysevent_free(ev);
38500Sstevel@tonic-gate 	if ((rv != 0) && verbose)
38510Sstevel@tonic-gate 		cmn_err(CE_WARN,
38520Sstevel@tonic-gate 			    "drmach_log_sysevent failed (rv %d) for %s  %s\n",
38530Sstevel@tonic-gate 			    rv, attach_pnt, hint);
38540Sstevel@tonic-gate 
38550Sstevel@tonic-gate 	return (rv);
38560Sstevel@tonic-gate }
38570Sstevel@tonic-gate 
38580Sstevel@tonic-gate /*ARGSUSED*/
38590Sstevel@tonic-gate int
38600Sstevel@tonic-gate drmach_allow_memrange_modify(drmachid_t id)
38610Sstevel@tonic-gate {
38620Sstevel@tonic-gate 	return (1);	/* TRUE */
38630Sstevel@tonic-gate }
3864