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