xref: /titanic_52/usr/src/uts/sun4u/starfire/io/drmach.c (revision e0731422366620894c16c1ee6515551c5f00733d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5447e4a63Spetede  * Common Development and Distribution License (the "License").
6447e4a63Spetede  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2107d06da5SSurya Prakki 
227c478bd9Sstevel@tonic-gate /*
2356f33205SJonathan Adams  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2589b43686SBayard Bell  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/debug.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
317c478bd9Sstevel@tonic-gate #include <sys/errno.h>
327c478bd9Sstevel@tonic-gate #include <sys/cred.h>
337c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
347c478bd9Sstevel@tonic-gate #include <sys/devops.h>
357c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
367c478bd9Sstevel@tonic-gate #include <sys/poll.h>
377c478bd9Sstevel@tonic-gate #include <sys/conf.h>
387c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
407c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
417c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
427c478bd9Sstevel@tonic-gate #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
457c478bd9Sstevel@tonic-gate #include <sys/processor.h>
467c478bd9Sstevel@tonic-gate #include <sys/spitregs.h>
477c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
487c478bd9Sstevel@tonic-gate #include <sys/cpupart.h>
497c478bd9Sstevel@tonic-gate #include <sys/mem_config.h>
507c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
517c478bd9Sstevel@tonic-gate #include <sys/systm.h>
527c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
537c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
557c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
567c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
577c478bd9Sstevel@tonic-gate #include <sys/promif.h>
587c478bd9Sstevel@tonic-gate #include <sys/prom_plat.h>
597c478bd9Sstevel@tonic-gate #include <sys/membar.h>
607c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
617c478bd9Sstevel@tonic-gate #include <sys/mem_cage.h>
627c478bd9Sstevel@tonic-gate #include <sys/stack.h>
637c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
647c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
657c478bd9Sstevel@tonic-gate #include <sys/pte.h>
667c478bd9Sstevel@tonic-gate #include <sys/mmu.h>
677c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h>
687c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h>
697c478bd9Sstevel@tonic-gate #include <sys/note.h>
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate #include <sys/starfire.h>	/* plat_max_... decls */
727c478bd9Sstevel@tonic-gate #include <sys/cvc.h>
737c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h>
747c478bd9Sstevel@tonic-gate #include <sys/drmach.h>
757c478bd9Sstevel@tonic-gate #include <sys/dr_util.h>
767c478bd9Sstevel@tonic-gate #include <sys/pda.h>
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #include <sys/sysevent.h>
797c478bd9Sstevel@tonic-gate #include <sys/sysevent/dr.h>
807c478bd9Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate extern void		bcopy32_il(uint64_t, uint64_t);
847c478bd9Sstevel@tonic-gate extern void		flush_ecache_il(
857c478bd9Sstevel@tonic-gate 				uint64_t physaddr, int size, int linesz);
867c478bd9Sstevel@tonic-gate extern uint_t		ldphysio_il(uint64_t physaddr);
877c478bd9Sstevel@tonic-gate extern void		stphysio_il(uint64_t physaddr, uint_t value);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate extern uint64_t		mc_get_mem_alignment(void);
90fa9e4066Sahrens extern uint64_t		mc_get_asr_addr(pnode_t);
91fa9e4066Sahrens extern uint64_t		mc_get_idle_addr(pnode_t);
92fa9e4066Sahrens extern uint64_t		mc_get_alignment_mask(pnode_t);
93fa9e4066Sahrens extern int		mc_read_asr(pnode_t, uint_t *);
94fa9e4066Sahrens extern int		mc_write_asr(pnode_t, uint_t);
957c478bd9Sstevel@tonic-gate extern uint64_t		mc_asr_to_pa(uint_t);
967c478bd9Sstevel@tonic-gate extern uint_t		mc_pa_to_asr(uint_t, uint64_t);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate extern int		pc_madr_add(int, int, int, int);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate typedef struct {
1017c478bd9Sstevel@tonic-gate 	struct drmach_node	*node;
1027c478bd9Sstevel@tonic-gate 	void			*data;
1037c478bd9Sstevel@tonic-gate } drmach_node_walk_args_t;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate typedef struct drmach_node {
1067c478bd9Sstevel@tonic-gate 	void		*here;
1077c478bd9Sstevel@tonic-gate 
108fa9e4066Sahrens 	pnode_t		 (*get_dnode)(struct drmach_node *node);
1097c478bd9Sstevel@tonic-gate 	int		 (*walk)(struct drmach_node *node, void *data,
1107c478bd9Sstevel@tonic-gate 				int (*cb)(drmach_node_walk_args_t *args));
1117c478bd9Sstevel@tonic-gate } drmach_node_t;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate typedef struct {
1147c478bd9Sstevel@tonic-gate 	int		 min_index;
1157c478bd9Sstevel@tonic-gate 	int		 max_index;
1167c478bd9Sstevel@tonic-gate 	int		 arr_sz;
1177c478bd9Sstevel@tonic-gate 	drmachid_t	*arr;
1187c478bd9Sstevel@tonic-gate } drmach_array_t;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate typedef struct {
1217c478bd9Sstevel@tonic-gate 	void		*isa;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	sbd_error_t	*(*release)(drmachid_t);
1247c478bd9Sstevel@tonic-gate 	sbd_error_t	*(*status)(drmachid_t, drmach_status_t *);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	char		 name[MAXNAMELEN];
1277c478bd9Sstevel@tonic-gate } drmach_common_t;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate typedef struct {
1307c478bd9Sstevel@tonic-gate 	drmach_common_t	 cm;
1317c478bd9Sstevel@tonic-gate 	int		 bnum;
1327c478bd9Sstevel@tonic-gate 	int		 assigned;
1337c478bd9Sstevel@tonic-gate 	int		 powered;
1347c478bd9Sstevel@tonic-gate 	int		 connect_cpuid;
1357c478bd9Sstevel@tonic-gate 	int		 cond;
1367c478bd9Sstevel@tonic-gate 	drmach_node_t	*tree;
1377c478bd9Sstevel@tonic-gate 	drmach_array_t	*devices;
1387c478bd9Sstevel@tonic-gate } drmach_board_t;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate typedef struct {
1417c478bd9Sstevel@tonic-gate 	drmach_common_t	 cm;
1427c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
1437c478bd9Sstevel@tonic-gate 	int		 unum;
1447c478bd9Sstevel@tonic-gate 	int		 busy;
1457c478bd9Sstevel@tonic-gate 	int		 powered;
1467c478bd9Sstevel@tonic-gate 	const char	*type;
1477c478bd9Sstevel@tonic-gate 	drmach_node_t	*node;
1487c478bd9Sstevel@tonic-gate } drmach_device_t;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate typedef struct {
1517c478bd9Sstevel@tonic-gate 	int		 flags;
1527c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
1537c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
1547c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
1557c478bd9Sstevel@tonic-gate } drmach_config_args_t;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate typedef struct {
1587c478bd9Sstevel@tonic-gate 	uint64_t	 idle_addr;
1597c478bd9Sstevel@tonic-gate 	drmach_device_t	*mem;
1607c478bd9Sstevel@tonic-gate } drmach_mc_idle_script_t;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate typedef struct {
1637c478bd9Sstevel@tonic-gate 	uint64_t	masr_addr;
1647c478bd9Sstevel@tonic-gate 	uint_t		masr;
1657c478bd9Sstevel@tonic-gate 	uint_t		_filler;
1667c478bd9Sstevel@tonic-gate } drmach_rename_script_t;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate typedef struct {
1697c478bd9Sstevel@tonic-gate 	void		(*run)(void *arg);
1707c478bd9Sstevel@tonic-gate 	caddr_t		data;
1717c478bd9Sstevel@tonic-gate 	pda_handle_t	*ph;
1727c478bd9Sstevel@tonic-gate 	struct memlist	*c_ml;
1737c478bd9Sstevel@tonic-gate 	uint64_t	s_copybasepa;
1747c478bd9Sstevel@tonic-gate 	uint64_t	t_copybasepa;
1757c478bd9Sstevel@tonic-gate 	drmach_device_t	*restless_mc;	/* diagnostic output */
1767c478bd9Sstevel@tonic-gate } drmach_copy_rename_program_t;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate typedef enum {
1797c478bd9Sstevel@tonic-gate 	DO_IDLE,
1807c478bd9Sstevel@tonic-gate 	DO_UNIDLE,
1817c478bd9Sstevel@tonic-gate 	DO_PAUSE,
1827c478bd9Sstevel@tonic-gate 	DO_UNPAUSE
1837c478bd9Sstevel@tonic-gate } drmach_iopc_op_t;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate typedef struct {
1867c478bd9Sstevel@tonic-gate 	drmach_board_t	*obj;
1877c478bd9Sstevel@tonic-gate 	int		 ndevs;
1887c478bd9Sstevel@tonic-gate 	void		*a;
1897c478bd9Sstevel@tonic-gate 	sbd_error_t	*(*found)(void *a, const char *, int, drmachid_t);
1907c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
1917c478bd9Sstevel@tonic-gate } drmach_board_cb_data_t;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate static caddr_t		 drmach_shutdown_va;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate static int		 drmach_initialized;
1967c478bd9Sstevel@tonic-gate static drmach_array_t	*drmach_boards;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate static int		 drmach_cpu_delay = 100;
1997c478bd9Sstevel@tonic-gate static int		 drmach_cpu_ntries = 50000;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate volatile uchar_t	*drmach_xt_mb;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate /*
2047c478bd9Sstevel@tonic-gate  * Do not change the drmach_shutdown_mbox structure without
2057c478bd9Sstevel@tonic-gate  * considering the drmach_shutdown_asm assembly language code.
2067c478bd9Sstevel@tonic-gate  */
2077c478bd9Sstevel@tonic-gate struct drmach_shutdown_mbox {
2087c478bd9Sstevel@tonic-gate 	uint64_t	estack;
2097c478bd9Sstevel@tonic-gate 	uint64_t	flushaddr;
2107c478bd9Sstevel@tonic-gate 	int		size;
2117c478bd9Sstevel@tonic-gate 	int		linesize;
2127c478bd9Sstevel@tonic-gate 	uint64_t	physaddr;
2137c478bd9Sstevel@tonic-gate };
2147c478bd9Sstevel@tonic-gate struct drmach_shutdown_mbox	*drmach_shutdown_asm_mbox;
2158682d1efSRichard Lowe 
2168682d1efSRichard Lowe static int		drmach_fini(void);
2177c478bd9Sstevel@tonic-gate static sbd_error_t	*drmach_device_new(drmach_node_t *,
2187c478bd9Sstevel@tonic-gate 				drmach_board_t *, drmach_device_t **);
2197c478bd9Sstevel@tonic-gate static sbd_error_t	*drmach_cpu_new(drmach_device_t *);
2207c478bd9Sstevel@tonic-gate static sbd_error_t	*drmach_mem_new(drmach_device_t *);
2217c478bd9Sstevel@tonic-gate static sbd_error_t	*drmach_io_new(drmach_device_t *);
2228682d1efSRichard Lowe static sbd_error_t	*drmach_board_release(drmachid_t);
2238682d1efSRichard Lowe static sbd_error_t	*drmach_board_status(drmachid_t, drmach_status_t *);
2248682d1efSRichard Lowe static sbd_error_t	*drmach_cpu_release(drmachid_t);
2258682d1efSRichard Lowe static sbd_error_t	*drmach_cpu_status(drmachid_t, drmach_status_t *);
2268682d1efSRichard Lowe static sbd_error_t	*drmach_io_release(drmachid_t);
2278682d1efSRichard Lowe static sbd_error_t	*drmach_io_status(drmachid_t, drmach_status_t *);
2288682d1efSRichard Lowe static sbd_error_t	*drmach_mem_release(drmachid_t);
2298682d1efSRichard Lowe static sbd_error_t	*drmach_mem_status(drmachid_t, drmach_status_t *);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate extern struct cpu	*SIGBCPU;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate #ifdef DEBUG
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate #define	DRMACH_PR		if (drmach_debug) printf
2367c478bd9Sstevel@tonic-gate int drmach_debug = 0;		 /* set to non-zero to enable debug messages */
2377c478bd9Sstevel@tonic-gate #else
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate #define	DRMACH_PR		_NOTE(CONSTANTCONDITION) if (0) printf
2407c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate #define	DRMACH_OBJ(id)		((drmach_common_t *)id)
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate #define	DRMACH_IS_BOARD_ID(id)	\
2457c478bd9Sstevel@tonic-gate 	((id != 0) &&		\
2467c478bd9Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new))
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate #define	DRMACH_IS_CPU_ID(id)	\
2497c478bd9Sstevel@tonic-gate 	((id != 0) &&		\
2507c478bd9Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new))
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate #define	DRMACH_IS_MEM_ID(id)	\
2537c478bd9Sstevel@tonic-gate 	((id != 0) &&		\
2547c478bd9Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_mem_new))
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate #define	DRMACH_IS_IO_ID(id)	\
2577c478bd9Sstevel@tonic-gate 	((id != 0) &&		\
2587c478bd9Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate #define	DRMACH_IS_DEVICE_ID(id)					\
2617c478bd9Sstevel@tonic-gate 	((id != 0) &&						\
2627c478bd9Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
2637c478bd9Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
2647c478bd9Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate #define	DRMACH_IS_ID(id)					\
2677c478bd9Sstevel@tonic-gate 	((id != 0) &&						\
2687c478bd9Sstevel@tonic-gate 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new ||	\
2697c478bd9Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
2707c478bd9Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
2717c478bd9Sstevel@tonic-gate 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate #define	DRMACH_CPUID2BNUM(cpuid) \
2747c478bd9Sstevel@tonic-gate 	((cpuid) / MAX_CPU_UNITS_PER_BOARD)
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate #define	DRMACH_INTERNAL_ERROR() \
2777c478bd9Sstevel@tonic-gate 	drerr_new(1, ESTF_INTERNAL, drmach_ie_fmt, __LINE__)
2787c478bd9Sstevel@tonic-gate static char		*drmach_ie_fmt = "drmach.c %d";
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate static struct {
2817c478bd9Sstevel@tonic-gate 	const char	 *name;
2827c478bd9Sstevel@tonic-gate 	const char	 *type;
2837c478bd9Sstevel@tonic-gate 	sbd_error_t	 *(*new)(drmach_device_t *);
2847c478bd9Sstevel@tonic-gate } name2type[] = {
2857c478bd9Sstevel@tonic-gate 	{ "SUNW,UltraSPARC",	DRMACH_DEVTYPE_CPU,  drmach_cpu_new },
2867c478bd9Sstevel@tonic-gate 	{ "mem-unit",		DRMACH_DEVTYPE_MEM,  drmach_mem_new },
2877c478bd9Sstevel@tonic-gate 	{ "pci",		DRMACH_DEVTYPE_PCI,  drmach_io_new  },
2887c478bd9Sstevel@tonic-gate 	{ "sbus",		DRMACH_DEVTYPE_SBUS, drmach_io_new  },
2897c478bd9Sstevel@tonic-gate };
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /* node types to cleanup when a board is unconfigured */
2927c478bd9Sstevel@tonic-gate #define	MISC_COUNTER_TIMER_DEVNAME	"counter-timer"
2937c478bd9Sstevel@tonic-gate #define	MISC_PERF_COUNTER_DEVNAME	"perf-counter"
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate /* utility */
2967c478bd9Sstevel@tonic-gate #define	MBYTE	(1048576ull)
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate /*
2997c478bd9Sstevel@tonic-gate  * drmach autoconfiguration data structures and interfaces
3007c478bd9Sstevel@tonic-gate  */
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
3057c478bd9Sstevel@tonic-gate 	&mod_miscops,
306f500b196SRichard Bean 	"Sun Enterprise 10000 DR"
3077c478bd9Sstevel@tonic-gate };
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
3107c478bd9Sstevel@tonic-gate 	MODREV_1,
3117c478bd9Sstevel@tonic-gate 	(void *)&modlmisc,
3127c478bd9Sstevel@tonic-gate 	NULL
3137c478bd9Sstevel@tonic-gate };
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate static kmutex_t drmach_i_lock;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate int
3187c478bd9Sstevel@tonic-gate _init(void)
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	int err;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/* check that we have the correct version of obp */
3237c478bd9Sstevel@tonic-gate 	if (prom_test("SUNW,UE10000,add-brd") != 0) {
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!OBP/SSP upgrade is required to enable "
3267c478bd9Sstevel@tonic-gate 		    "DR Functionality");
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 		return (-1);
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	mutex_init(&drmach_i_lock, NULL, MUTEX_DRIVER, NULL);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	drmach_xt_mb = (uchar_t *)vmem_alloc(static_alloc_arena,
3347c478bd9Sstevel@tonic-gate 	    NCPU * sizeof (uchar_t), VM_SLEEP);
3357c478bd9Sstevel@tonic-gate 	drmach_shutdown_asm_mbox = (struct drmach_shutdown_mbox *)
3367c478bd9Sstevel@tonic-gate 	    vmem_alloc(static_alloc_arena, sizeof (struct drmach_shutdown_mbox),
3377c478bd9Sstevel@tonic-gate 	    VM_SLEEP);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if ((err = mod_install(&modlinkage)) != 0) {
3407c478bd9Sstevel@tonic-gate 		mutex_destroy(&drmach_i_lock);
3417c478bd9Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_xt_mb,
3427c478bd9Sstevel@tonic-gate 		    NCPU * sizeof (uchar_t));
3437c478bd9Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox,
3447c478bd9Sstevel@tonic-gate 		    sizeof (struct drmach_shutdown_mbox));
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	return (err);
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate int
3517c478bd9Sstevel@tonic-gate _fini(void)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	if (drmach_fini())
3547c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3557c478bd9Sstevel@tonic-gate 	else
3567c478bd9Sstevel@tonic-gate 		return (mod_remove(&modlinkage));
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate int
3607c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
365fa9e4066Sahrens static pnode_t
3667c478bd9Sstevel@tonic-gate drmach_node_obp_get_dnode(drmach_node_t *np)
3677c478bd9Sstevel@tonic-gate {
36804580fdfSmathue 	return ((pnode_t)(uintptr_t)np->here);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate static int
3727c478bd9Sstevel@tonic-gate drmach_node_obp_walk(drmach_node_t *np, void *data,
3737c478bd9Sstevel@tonic-gate 		int (*cb)(drmach_node_walk_args_t *args))
3747c478bd9Sstevel@tonic-gate {
375fa9e4066Sahrens 	pnode_t			nodeid;
3767c478bd9Sstevel@tonic-gate 	int			rv;
3777c478bd9Sstevel@tonic-gate 	drmach_node_walk_args_t	args;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	/* initialized args structure for callback */
3807c478bd9Sstevel@tonic-gate 	args.node = np;
3817c478bd9Sstevel@tonic-gate 	args.data = data;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	nodeid = prom_childnode(prom_rootnode());
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	/* save our new position with in the tree */
38604580fdfSmathue 	np->here = (void *)(uintptr_t)nodeid;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	rv = 0;
3897c478bd9Sstevel@tonic-gate 	while (nodeid != OBP_NONODE) {
3907c478bd9Sstevel@tonic-gate 		rv = (*cb)(&args);
3917c478bd9Sstevel@tonic-gate 		if (rv)
3927c478bd9Sstevel@tonic-gate 			break;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		nodeid = prom_nextnode(nodeid);
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 		/* save our new position with in the tree */
39704580fdfSmathue 		np->here = (void *)(uintptr_t)nodeid;
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	return (rv);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate static drmach_node_t *
4047c478bd9Sstevel@tonic-gate drmach_node_new(void)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	drmach_node_t *np;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	np->get_dnode = drmach_node_obp_get_dnode;
4117c478bd9Sstevel@tonic-gate 	np->walk = drmach_node_obp_walk;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	return (np);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate static void
4177c478bd9Sstevel@tonic-gate drmach_node_dispose(drmach_node_t *np)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	kmem_free(np, sizeof (*np));
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate static dev_info_t *
4237c478bd9Sstevel@tonic-gate drmach_node_get_dip(drmach_node_t *np)
4247c478bd9Sstevel@tonic-gate {
425fa9e4066Sahrens 	pnode_t nodeid;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
4287c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
4297c478bd9Sstevel@tonic-gate 		return (NULL);
4307c478bd9Sstevel@tonic-gate 	else {
4317c478bd9Sstevel@tonic-gate 		dev_info_t *dip;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		/* The root node doesn't have to be held */
4347c478bd9Sstevel@tonic-gate 		dip = e_ddi_nodeid_to_dip(nodeid);
4357c478bd9Sstevel@tonic-gate 		if (dip) {
4367c478bd9Sstevel@tonic-gate 			/*
4377c478bd9Sstevel@tonic-gate 			 * Branch rooted at dip is already held, so release
4387c478bd9Sstevel@tonic-gate 			 * hold acquired in e_ddi_nodeid_to_dip()
4397c478bd9Sstevel@tonic-gate 			 */
4407c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
4417c478bd9Sstevel@tonic-gate 			ASSERT(e_ddi_branch_held(dip));
4427c478bd9Sstevel@tonic-gate 		}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 		return (dip);
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate 
449fa9e4066Sahrens static pnode_t
4507c478bd9Sstevel@tonic-gate drmach_node_get_dnode(drmach_node_t *np)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	return (np->get_dnode(np));
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate static int
4567c478bd9Sstevel@tonic-gate drmach_node_walk(drmach_node_t *np, void *param,
4577c478bd9Sstevel@tonic-gate 		int (*cb)(drmach_node_walk_args_t *args))
4587c478bd9Sstevel@tonic-gate {
4597c478bd9Sstevel@tonic-gate 	return (np->walk(np, param, cb));
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate static int
4637c478bd9Sstevel@tonic-gate drmach_node_get_prop(drmach_node_t *np, char *name, void *buf)
4647c478bd9Sstevel@tonic-gate {
465fa9e4066Sahrens 	pnode_t	nodeid;
4667c478bd9Sstevel@tonic-gate 	int	rv;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
4697c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
4707c478bd9Sstevel@tonic-gate 		rv = -1;
4717c478bd9Sstevel@tonic-gate 	else if (prom_getproplen(nodeid, (caddr_t)name) < 0)
4727c478bd9Sstevel@tonic-gate 		rv = -1;
4737c478bd9Sstevel@tonic-gate 	else {
4747c478bd9Sstevel@tonic-gate 		(void) prom_getprop(nodeid, (caddr_t)name, (caddr_t)buf);
4757c478bd9Sstevel@tonic-gate 		rv = 0;
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	return (rv);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate static int
4827c478bd9Sstevel@tonic-gate drmach_node_get_proplen(drmach_node_t *np, char *name, int *len)
4837c478bd9Sstevel@tonic-gate {
484fa9e4066Sahrens 	pnode_t	 nodeid;
4857c478bd9Sstevel@tonic-gate 	int	 rv;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	nodeid = np->get_dnode(np);
4887c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
4897c478bd9Sstevel@tonic-gate 		rv = -1;
4907c478bd9Sstevel@tonic-gate 	else {
4917c478bd9Sstevel@tonic-gate 		*len = prom_getproplen(nodeid, (caddr_t)name);
4927c478bd9Sstevel@tonic-gate 		rv = (*len < 0 ? -1 : 0);
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	return (rv);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate static drmachid_t
4997c478bd9Sstevel@tonic-gate drmach_node_dup(drmach_node_t *np)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	drmach_node_t *dup;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	dup = drmach_node_new();
5047c478bd9Sstevel@tonic-gate 	dup->here = np->here;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	return (dup);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate /*
5107c478bd9Sstevel@tonic-gate  * drmach_array provides convenient array construction, access,
5117c478bd9Sstevel@tonic-gate  * bounds checking and array destruction logic.
5127c478bd9Sstevel@tonic-gate  */
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate static drmach_array_t *
5157c478bd9Sstevel@tonic-gate drmach_array_new(int min_index, int max_index)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	drmach_array_t *arr;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP);
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	arr->arr_sz = (max_index - min_index + 1) * sizeof (void *);
5227c478bd9Sstevel@tonic-gate 	if (arr->arr_sz > 0) {
5237c478bd9Sstevel@tonic-gate 		arr->min_index = min_index;
5247c478bd9Sstevel@tonic-gate 		arr->max_index = max_index;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 		arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP);
5277c478bd9Sstevel@tonic-gate 		return (arr);
5287c478bd9Sstevel@tonic-gate 	} else {
5297c478bd9Sstevel@tonic-gate 		kmem_free(arr, sizeof (*arr));
5307c478bd9Sstevel@tonic-gate 		return (0);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate static int
5357c478bd9Sstevel@tonic-gate drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	if (idx < arr->min_index || idx > arr->max_index)
5387c478bd9Sstevel@tonic-gate 		return (-1);
5397c478bd9Sstevel@tonic-gate 	else {
5407c478bd9Sstevel@tonic-gate 		arr->arr[idx - arr->min_index] = val;
5417c478bd9Sstevel@tonic-gate 		return (0);
5427c478bd9Sstevel@tonic-gate 	}
5437c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate static int
5477c478bd9Sstevel@tonic-gate drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate 	if (idx < arr->min_index || idx > arr->max_index)
5507c478bd9Sstevel@tonic-gate 		return (-1);
5517c478bd9Sstevel@tonic-gate 	else {
5527c478bd9Sstevel@tonic-gate 		*val = arr->arr[idx - arr->min_index];
5537c478bd9Sstevel@tonic-gate 		return (0);
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate static int
5597c478bd9Sstevel@tonic-gate drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val)
5607c478bd9Sstevel@tonic-gate {
5617c478bd9Sstevel@tonic-gate 	int rv;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	*idx = arr->min_index;
5647c478bd9Sstevel@tonic-gate 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
5657c478bd9Sstevel@tonic-gate 		*idx += 1;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	return (rv);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate static int
5717c478bd9Sstevel@tonic-gate drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	int rv;
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	*idx += 1;
5767c478bd9Sstevel@tonic-gate 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
5777c478bd9Sstevel@tonic-gate 		*idx += 1;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	return (rv);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate static void
5837c478bd9Sstevel@tonic-gate drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t))
5847c478bd9Sstevel@tonic-gate {
5857c478bd9Sstevel@tonic-gate 	drmachid_t	val;
5867c478bd9Sstevel@tonic-gate 	int		idx;
5877c478bd9Sstevel@tonic-gate 	int		rv;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	rv = drmach_array_first(arr, &idx, &val);
5907c478bd9Sstevel@tonic-gate 	while (rv == 0) {
5917c478bd9Sstevel@tonic-gate 		(*disposer)(val);
5927c478bd9Sstevel@tonic-gate 		rv = drmach_array_next(arr, &idx, &val);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	kmem_free(arr->arr, arr->arr_sz);
5967c478bd9Sstevel@tonic-gate 	kmem_free(arr, sizeof (*arr));
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6007c478bd9Sstevel@tonic-gate static int
601fa9e4066Sahrens drmach_prom_select(pnode_t nodeid, void *arg, uint_t flags)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate 	int			rprop[64];
604fa9e4066Sahrens 	pnode_t			saved;
6057c478bd9Sstevel@tonic-gate 	drmach_config_args_t	*ap = (drmach_config_args_t *)arg;
6067c478bd9Sstevel@tonic-gate 	drmach_device_t		*dp = ap->dp;
6077c478bd9Sstevel@tonic-gate 	sbd_error_t		*err;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	saved = drmach_node_get_dnode(dp->node);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	if (nodeid != saved)
6127c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	if (saved == OBP_NONODE) {
6157c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
6167c478bd9Sstevel@tonic-gate 		DRERR_SET_C(&ap->err, &err);
6177c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (prom_getprop(nodeid, OBP_REG, (caddr_t)rprop) <= 0) {
6217c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6287c478bd9Sstevel@tonic-gate static void
6297c478bd9Sstevel@tonic-gate drmach_branch_callback(dev_info_t *rdip, void *arg, uint_t flags)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	drmach_config_args_t	*ap = (drmach_config_args_t *)arg;
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	ASSERT(ap->dip == NULL);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	ap->dip = rdip;
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate sbd_error_t *
6397c478bd9Sstevel@tonic-gate drmach_configure(drmachid_t id, int flags)
6407c478bd9Sstevel@tonic-gate {
6417c478bd9Sstevel@tonic-gate 	drmach_device_t		*dp;
6427c478bd9Sstevel@tonic-gate 	sbd_error_t		*err;
6437c478bd9Sstevel@tonic-gate 	drmach_config_args_t	ca;
6447c478bd9Sstevel@tonic-gate 	devi_branch_t		b = {0};
6457c478bd9Sstevel@tonic-gate 	dev_info_t		*fdip = NULL;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
6487c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
6497c478bd9Sstevel@tonic-gate 	dp = id;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	ca.dp = dp;
6527c478bd9Sstevel@tonic-gate 	ca.flags = flags;
6537c478bd9Sstevel@tonic-gate 	ca.err = NULL;		/* will be set if error detected */
6547c478bd9Sstevel@tonic-gate 	ca.dip = NULL;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	b.arg = &ca;
6577c478bd9Sstevel@tonic-gate 	b.type = DEVI_BRANCH_PROM;
6587c478bd9Sstevel@tonic-gate 	b.create.prom_branch_select = drmach_prom_select;
6597c478bd9Sstevel@tonic-gate 	b.devi_branch_callback = drmach_branch_callback;
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	if (e_ddi_branch_create(ddi_root_node(), &b, &fdip,
6627c478bd9Sstevel@tonic-gate 	    DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE) != 0) {
6637c478bd9Sstevel@tonic-gate 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 		/*
6667c478bd9Sstevel@tonic-gate 		 * If non-NULL, fdip is returned held and must be released.
6677c478bd9Sstevel@tonic-gate 		 */
6687c478bd9Sstevel@tonic-gate 		if (fdip != NULL) {
6697c478bd9Sstevel@tonic-gate 			(void) ddi_pathname(fdip, path);
6707c478bd9Sstevel@tonic-gate 			ddi_release_devi(fdip);
6717c478bd9Sstevel@tonic-gate 		} else if (ca.dip != NULL) {
6727c478bd9Sstevel@tonic-gate 			/* safe to call ddi_pathname as dip already held */
6737c478bd9Sstevel@tonic-gate 			(void) ddi_pathname(ca.dip, path);
6747c478bd9Sstevel@tonic-gate 		} else {
6757c478bd9Sstevel@tonic-gate 			(void) strcpy(path, "<none>");
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 		err = drerr_new(1, ESTF_DRVFAIL, path);
6797c478bd9Sstevel@tonic-gate 		DRERR_SET_C(&ca.err, &err);
6807c478bd9Sstevel@tonic-gate 		kmem_free(path, MAXPATHLEN);
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	return (ca.err);
6847c478bd9Sstevel@tonic-gate }
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate static sbd_error_t *
6877c478bd9Sstevel@tonic-gate drmach_device_new(drmach_node_t *node,
6887c478bd9Sstevel@tonic-gate 	drmach_board_t *bp, drmach_device_t **dpp)
6897c478bd9Sstevel@tonic-gate {
6907c478bd9Sstevel@tonic-gate 	int		 i;
6917c478bd9Sstevel@tonic-gate 	int		 rv;
6927c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
6937c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
6947c478bd9Sstevel@tonic-gate 	char		 name[OBP_MAXDRVNAME];
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	rv = drmach_node_get_prop(node, OBP_NAME, name);
6977c478bd9Sstevel@tonic-gate 	if (rv) {
6987c478bd9Sstevel@tonic-gate 		/* every node is expected to have a name */
6997c478bd9Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROP,
7007c478bd9Sstevel@tonic-gate 		    "PROM Node 0x%x: property %s",
7017c478bd9Sstevel@tonic-gate 		    (uint_t)node->get_dnode(node), OBP_NAME);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 		return (err);
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/*
7077c478bd9Sstevel@tonic-gate 	 * The node currently being examined is not listed in the name2type[]
7087c478bd9Sstevel@tonic-gate 	 * array.  In this case, the node is no interest to drmach.  Both
7097c478bd9Sstevel@tonic-gate 	 * dp and err are initialized here to yield nothing (no device or
7107c478bd9Sstevel@tonic-gate 	 * error structure) for this case.
7117c478bd9Sstevel@tonic-gate 	 */
7127c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++)
7137c478bd9Sstevel@tonic-gate 		if (strcmp(name2type[i].name, name) == 0)
7147c478bd9Sstevel@tonic-gate 			break;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	if (i < sizeof (name2type) / sizeof (name2type[0])) {
7177c478bd9Sstevel@tonic-gate 		dp = kmem_zalloc(sizeof (drmach_device_t), KM_SLEEP);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 		dp->bp = bp;
7207c478bd9Sstevel@tonic-gate 		dp->unum = -1;
7217c478bd9Sstevel@tonic-gate 		dp->node = drmach_node_dup(node);
7227c478bd9Sstevel@tonic-gate 		dp->type = name2type[i].type;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 		err = (name2type[i].new)(dp);
7257c478bd9Sstevel@tonic-gate 		if (err) {
7267c478bd9Sstevel@tonic-gate 			drmach_node_dispose(node);
7277c478bd9Sstevel@tonic-gate 			kmem_free(dp, sizeof (*dp));
7287c478bd9Sstevel@tonic-gate 			dp = NULL;
7297c478bd9Sstevel@tonic-gate 		}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		*dpp = dp;
7327c478bd9Sstevel@tonic-gate 		return (err);
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	/*
7367c478bd9Sstevel@tonic-gate 	 * The node currently being examined is not listed in the name2type[]
7377c478bd9Sstevel@tonic-gate 	 * array.  In this case, the node is no interest to drmach.  Both
7387c478bd9Sstevel@tonic-gate 	 * dp and err are initialized here to yield nothing (no device or
7397c478bd9Sstevel@tonic-gate 	 * error structure) for this case.
7407c478bd9Sstevel@tonic-gate 	 */
7417c478bd9Sstevel@tonic-gate 	*dpp = NULL;
7427c478bd9Sstevel@tonic-gate 	return (NULL);
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate static void
7467c478bd9Sstevel@tonic-gate drmach_device_dispose(drmachid_t id)
7477c478bd9Sstevel@tonic-gate {
7487c478bd9Sstevel@tonic-gate 	drmach_device_t *self = id;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (self->node)
7517c478bd9Sstevel@tonic-gate 		drmach_node_dispose(self->node);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	kmem_free(self, sizeof (*self));
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate static sbd_error_t *
7577c478bd9Sstevel@tonic-gate drmach_device_get_prop(drmach_device_t *dp, char *name, void *buf)
7587c478bd9Sstevel@tonic-gate {
7597c478bd9Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
7607c478bd9Sstevel@tonic-gate 	int		 rv;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	rv = drmach_node_get_prop(dp->node, name, buf);
7637c478bd9Sstevel@tonic-gate 	if (rv) {
7647c478bd9Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROP,
7657c478bd9Sstevel@tonic-gate 		    "%s::%s: property %s",
7667c478bd9Sstevel@tonic-gate 		    dp->bp->cm.name, dp->cm.name, name);
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	return (err);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate static sbd_error_t *
7737c478bd9Sstevel@tonic-gate drmach_device_get_proplen(drmach_device_t *dp, char *name, int *len)
7747c478bd9Sstevel@tonic-gate {
7757c478bd9Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
7767c478bd9Sstevel@tonic-gate 	int		 rv;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	rv = drmach_node_get_proplen(dp->node, name, len);
7797c478bd9Sstevel@tonic-gate 	if (rv) {
7807c478bd9Sstevel@tonic-gate 		err = drerr_new(1, ESTF_GETPROPLEN,
7817c478bd9Sstevel@tonic-gate 		    "%s::%s: property %s",
7827c478bd9Sstevel@tonic-gate 		    dp->bp->cm.name, dp->cm.name, name);
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	return (err);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate static drmach_board_t *
7897c478bd9Sstevel@tonic-gate drmach_board_new(int bnum)
7907c478bd9Sstevel@tonic-gate {
7917c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	bp->cm.isa = (void *)drmach_board_new;
7967c478bd9Sstevel@tonic-gate 	bp->cm.release = drmach_board_release;
7977c478bd9Sstevel@tonic-gate 	bp->cm.status = drmach_board_status;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	(void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name));
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	bp->bnum = bnum;
8027c478bd9Sstevel@tonic-gate 	bp->devices = NULL;
8037c478bd9Sstevel@tonic-gate 	bp->connect_cpuid = -1;
8047c478bd9Sstevel@tonic-gate 	bp->tree = drmach_node_new();
8057c478bd9Sstevel@tonic-gate 	bp->assigned = !drmach_initialized;
8067c478bd9Sstevel@tonic-gate 	bp->powered = !drmach_initialized;
8077c478bd9Sstevel@tonic-gate 
80807d06da5SSurya Prakki 	(void) drmach_array_set(drmach_boards, bnum, bp);
8097c478bd9Sstevel@tonic-gate 	return (bp);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate static void
8137c478bd9Sstevel@tonic-gate drmach_board_dispose(drmachid_t id)
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate 	drmach_board_t *bp;
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	ASSERT(DRMACH_IS_BOARD_ID(id));
8187c478bd9Sstevel@tonic-gate 	bp = id;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	if (bp->tree)
8217c478bd9Sstevel@tonic-gate 		drmach_node_dispose(bp->tree);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	if (bp->devices)
8247c478bd9Sstevel@tonic-gate 		drmach_array_dispose(bp->devices, drmach_device_dispose);
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	kmem_free(bp, sizeof (*bp));
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate static sbd_error_t *
8307c478bd9Sstevel@tonic-gate drmach_board_status(drmachid_t id, drmach_status_t *stat)
8317c478bd9Sstevel@tonic-gate {
8327c478bd9Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
8337c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
8367c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
8377c478bd9Sstevel@tonic-gate 	bp = id;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	stat->assigned = bp->assigned;
8407c478bd9Sstevel@tonic-gate 	stat->powered = bp->powered;
8417c478bd9Sstevel@tonic-gate 	stat->busy = 0;			/* assume not busy */
8427c478bd9Sstevel@tonic-gate 	stat->configured = 0;		/* assume not configured */
8437c478bd9Sstevel@tonic-gate 	stat->empty = 0;
8447c478bd9Sstevel@tonic-gate 	stat->cond = bp->cond = SBD_COND_OK;
84507d06da5SSurya Prakki 	(void) strncpy(stat->type, "System Brd", sizeof (stat->type));
8467c478bd9Sstevel@tonic-gate 	stat->info[0] = '\0';
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	if (bp->devices) {
8497c478bd9Sstevel@tonic-gate 		int		 rv;
8507c478bd9Sstevel@tonic-gate 		int		 d_idx;
8517c478bd9Sstevel@tonic-gate 		drmachid_t	 d_id;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
8547c478bd9Sstevel@tonic-gate 		while (rv == 0) {
8557c478bd9Sstevel@tonic-gate 			drmach_status_t	d_stat;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 			err = drmach_status(d_id, &d_stat);
8587c478bd9Sstevel@tonic-gate 			if (err)
8597c478bd9Sstevel@tonic-gate 				break;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 			stat->busy |= d_stat.busy;
8627c478bd9Sstevel@tonic-gate 			stat->configured |= d_stat.configured;
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
8657c478bd9Sstevel@tonic-gate 		}
8667c478bd9Sstevel@tonic-gate 	}
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	return (err);
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate /* a simple routine to reduce redundancy of this common logic */
8727c478bd9Sstevel@tonic-gate static pda_handle_t
8737c478bd9Sstevel@tonic-gate drmach_pda_open(void)
8747c478bd9Sstevel@tonic-gate {
8757c478bd9Sstevel@tonic-gate 	pda_handle_t ph;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	ph = pda_open();
8787c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
8797c478bd9Sstevel@tonic-gate 		/* catch in debug kernels */
8807c478bd9Sstevel@tonic-gate 		ASSERT(0);
8817c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pda_open failed");
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	return (ph);
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate #ifdef DEBUG
8887c478bd9Sstevel@tonic-gate int drmach_init_break = 0;
8897c478bd9Sstevel@tonic-gate #endif
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate static int
8927c478bd9Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg)
8937c478bd9Sstevel@tonic-gate {
8947c478bd9Sstevel@tonic-gate 	int	i;
8957c478bd9Sstevel@tonic-gate 	int	*holdp = (int *)arg;
8967c478bd9Sstevel@tonic-gate 	char	*name = ddi_node_name(rdip);
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	/*
8997c478bd9Sstevel@tonic-gate 	 * For Starfire, we must be children of the root devinfo node
9007c478bd9Sstevel@tonic-gate 	 */
9017c478bd9Sstevel@tonic-gate 	ASSERT(ddi_get_parent(rdip) == ddi_root_node());
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (name2type) / sizeof (name2type[0]); i++)
9047c478bd9Sstevel@tonic-gate 		if (strcmp(name2type[i].name, name) == 0)
9057c478bd9Sstevel@tonic-gate 			break;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	if (i == sizeof (name2type) / sizeof (name2type[0])) {
9087c478bd9Sstevel@tonic-gate 		/* Not of interest to us */
9097c478bd9Sstevel@tonic-gate 		return (DDI_WALK_PRUNECHILD);
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	if (*holdp) {
9137c478bd9Sstevel@tonic-gate 		ASSERT(!e_ddi_branch_held(rdip));
9147c478bd9Sstevel@tonic-gate 		e_ddi_branch_hold(rdip);
9157c478bd9Sstevel@tonic-gate 	} else {
9167c478bd9Sstevel@tonic-gate 		ASSERT(e_ddi_branch_held(rdip));
9177c478bd9Sstevel@tonic-gate 		e_ddi_branch_rele(rdip);
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	return (DDI_WALK_PRUNECHILD);
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate static int
9247c478bd9Sstevel@tonic-gate drmach_init(void)
9257c478bd9Sstevel@tonic-gate {
926fa9e4066Sahrens 	pnode_t		nodeid;
9277c478bd9Sstevel@tonic-gate 	dev_info_t	*rdip;
9287c478bd9Sstevel@tonic-gate 	int		hold, circ;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate #ifdef DEBUG
9317c478bd9Sstevel@tonic-gate 	if (drmach_init_break)
9327c478bd9Sstevel@tonic-gate 		debug_enter("drmach_init: drmach_init_break set\n");
9337c478bd9Sstevel@tonic-gate #endif
9347c478bd9Sstevel@tonic-gate 	mutex_enter(&drmach_i_lock);
9357c478bd9Sstevel@tonic-gate 	if (drmach_initialized) {
9367c478bd9Sstevel@tonic-gate 		mutex_exit(&drmach_i_lock);
9377c478bd9Sstevel@tonic-gate 		return (0);
9387c478bd9Sstevel@tonic-gate 	}
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	drmach_boards = drmach_array_new(0, MAX_BOARDS - 1);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	nodeid = prom_childnode(prom_rootnode());
9437c478bd9Sstevel@tonic-gate 	do {
9447c478bd9Sstevel@tonic-gate 		int		 bnum;
9457c478bd9Sstevel@tonic-gate 		drmachid_t	 id;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 		bnum = -1;
9487c478bd9Sstevel@tonic-gate 		(void) prom_getprop(nodeid, OBP_BOARDNUM, (caddr_t)&bnum);
9497c478bd9Sstevel@tonic-gate 		if (bnum == -1)
9507c478bd9Sstevel@tonic-gate 			continue;
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 		if (drmach_array_get(drmach_boards, bnum, &id) == -1) {
9537c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "OBP node 0x%x has"
9547c478bd9Sstevel@tonic-gate 			    " invalid property value, %s=%d",
9557c478bd9Sstevel@tonic-gate 			    nodeid, OBP_BOARDNUM, bnum);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 			/* clean up */
9587c478bd9Sstevel@tonic-gate 			drmach_array_dispose(
9597c478bd9Sstevel@tonic-gate 			    drmach_boards, drmach_board_dispose);
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 			mutex_exit(&drmach_i_lock);
9627c478bd9Sstevel@tonic-gate 			return (-1);
9637c478bd9Sstevel@tonic-gate 		} else if (id == NULL)
9647c478bd9Sstevel@tonic-gate 			(void) drmach_board_new(bnum);
9657c478bd9Sstevel@tonic-gate 	} while ((nodeid = prom_nextnode(nodeid)) != OBP_NONODE);
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	drmach_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	/*
9707c478bd9Sstevel@tonic-gate 	 * Walk immediate children of devinfo root node and hold
9717c478bd9Sstevel@tonic-gate 	 * all devinfo branches of interest.
9727c478bd9Sstevel@tonic-gate 	 */
9737c478bd9Sstevel@tonic-gate 	hold = 1;
9747c478bd9Sstevel@tonic-gate 	rdip = ddi_root_node();
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	ndi_devi_enter(rdip, &circ);
9777c478bd9Sstevel@tonic-gate 	ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold);
9787c478bd9Sstevel@tonic-gate 	ndi_devi_exit(rdip, circ);
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	drmach_initialized = 1;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	mutex_exit(&drmach_i_lock);
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	return (0);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate static int
9887c478bd9Sstevel@tonic-gate drmach_fini(void)
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate 	dev_info_t	*rdip;
9917c478bd9Sstevel@tonic-gate 	int		hold, circ;
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	if (drmach_initialized) {
9947c478bd9Sstevel@tonic-gate 		int		busy = 0;
9957c478bd9Sstevel@tonic-gate 		int		rv;
9967c478bd9Sstevel@tonic-gate 		int		idx;
9977c478bd9Sstevel@tonic-gate 		drmachid_t	id;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 		ASSERT(drmach_boards != NULL);
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		rv = drmach_array_first(drmach_boards, &idx, &id);
10027c478bd9Sstevel@tonic-gate 		while (rv == 0) {
10037c478bd9Sstevel@tonic-gate 			sbd_error_t	*err;
10047c478bd9Sstevel@tonic-gate 			drmach_status_t stat;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 			err = drmach_board_status(id, &stat);
10077c478bd9Sstevel@tonic-gate 			if (err) {
10087c478bd9Sstevel@tonic-gate 				/* catch in debug kernels */
10097c478bd9Sstevel@tonic-gate 				ASSERT(0);
10107c478bd9Sstevel@tonic-gate 				sbd_err_clear(&err);
10117c478bd9Sstevel@tonic-gate 				busy = 1;
10127c478bd9Sstevel@tonic-gate 			} else
10137c478bd9Sstevel@tonic-gate 				busy |= stat.busy;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 			rv = drmach_array_next(drmach_boards, &idx, &id);
10167c478bd9Sstevel@tonic-gate 		}
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 		if (busy)
10197c478bd9Sstevel@tonic-gate 			return (-1);
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		drmach_array_dispose(drmach_boards, drmach_board_dispose);
10227c478bd9Sstevel@tonic-gate 		drmach_boards = NULL;
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 		vmem_free(heap_arena, drmach_shutdown_va, PAGESIZE);
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 		/*
10277c478bd9Sstevel@tonic-gate 		 * Walk immediate children of the root devinfo node
10287c478bd9Sstevel@tonic-gate 		 * releasing holds acquired on branches in drmach_init()
10297c478bd9Sstevel@tonic-gate 		 */
10307c478bd9Sstevel@tonic-gate 		hold = 0;
10317c478bd9Sstevel@tonic-gate 		rdip = ddi_root_node();
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 		ndi_devi_enter(rdip, &circ);
10347c478bd9Sstevel@tonic-gate 		ddi_walk_devs(ddi_get_child(rdip), hold_rele_branch, &hold);
10357c478bd9Sstevel@tonic-gate 		ndi_devi_exit(rdip, circ);
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 		mutex_destroy(&drmach_i_lock);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 		drmach_initialized = 0;
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 	if (drmach_xt_mb != NULL) {
10427c478bd9Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_xt_mb,
10437c478bd9Sstevel@tonic-gate 		    NCPU * sizeof (uchar_t));
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 	if (drmach_shutdown_asm_mbox != NULL) {
10467c478bd9Sstevel@tonic-gate 		vmem_free(static_alloc_arena, (void *)drmach_shutdown_asm_mbox,
10477c478bd9Sstevel@tonic-gate 		    sizeof (struct drmach_shutdown_mbox));
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 	return (0);
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate static sbd_error_t *
10537c478bd9Sstevel@tonic-gate drmach_get_mc_asr_addr(drmachid_t id, uint64_t *pa)
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
1056fa9e4066Sahrens 	pnode_t		nodeid;
10577c478bd9Sstevel@tonic-gate 	uint64_t	addr;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
10607c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
10617c478bd9Sstevel@tonic-gate 	dp = id;
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
10647c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
10657c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	addr = mc_get_asr_addr(nodeid);
10687c478bd9Sstevel@tonic-gate 	if (addr == (uint64_t)-1)
10697c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	*pa = addr;
10727c478bd9Sstevel@tonic-gate 	return (NULL);
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate static sbd_error_t *
10767c478bd9Sstevel@tonic-gate drmach_get_mc_idle_addr(drmachid_t id, uint64_t *pa)
10777c478bd9Sstevel@tonic-gate {
10787c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
1079fa9e4066Sahrens 	pnode_t		nodeid;
10807c478bd9Sstevel@tonic-gate 	uint64_t	addr;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
10837c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
10847c478bd9Sstevel@tonic-gate 	dp = id;
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
10877c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
10887c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	addr = mc_get_idle_addr(nodeid);
10917c478bd9Sstevel@tonic-gate 	if (addr == (uint64_t)-1)
10927c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	*pa = addr;
10957c478bd9Sstevel@tonic-gate 	return (NULL);
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate static sbd_error_t *
10997c478bd9Sstevel@tonic-gate drmach_read_mc_asr(drmachid_t id, uint_t *mcregp)
11007c478bd9Sstevel@tonic-gate {
11017c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
1102fa9e4066Sahrens 	pnode_t		 nodeid;
11037c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
11067c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
11077c478bd9Sstevel@tonic-gate 	dp = id;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
11107c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
11117c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
11127c478bd9Sstevel@tonic-gate 	else if (mc_read_asr(nodeid, mcregp) == -1)
11137c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
11147c478bd9Sstevel@tonic-gate 	else
11157c478bd9Sstevel@tonic-gate 		err = NULL;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	return (err);
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate static sbd_error_t *
11217c478bd9Sstevel@tonic-gate drmach_write_mc_asr(drmachid_t id, uint_t mcreg)
11227c478bd9Sstevel@tonic-gate {
11237c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
1124fa9e4066Sahrens 	pnode_t		 nodeid;
11257c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
11287c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
11297c478bd9Sstevel@tonic-gate 	dp = id;
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
11327c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
11337c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
11347c478bd9Sstevel@tonic-gate 	else if (mc_write_asr(nodeid, mcreg) == -1)
11357c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
11367c478bd9Sstevel@tonic-gate 	else
11377c478bd9Sstevel@tonic-gate 		err = NULL;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	return (err);
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate static sbd_error_t *
11437c478bd9Sstevel@tonic-gate drmach_prep_rename_script(drmach_device_t *s_mem, drmach_device_t *t_mem,
11447c478bd9Sstevel@tonic-gate 	uint64_t t_slice_offset, caddr_t buf, int buflen)
11457c478bd9Sstevel@tonic-gate {
11467c478bd9Sstevel@tonic-gate 	int			i, b, m;
11477c478bd9Sstevel@tonic-gate 	drmach_mc_idle_script_t	*isp;
11487c478bd9Sstevel@tonic-gate 	drmach_rename_script_t	*rsp;
11497c478bd9Sstevel@tonic-gate 	int			s_bd, t_bd;
11507c478bd9Sstevel@tonic-gate 	uint_t			s_masr, t_masr;
11517c478bd9Sstevel@tonic-gate 	uint64_t		s_new_basepa, t_new_basepa;
11527c478bd9Sstevel@tonic-gate 	int			b_idx, rv;
11537c478bd9Sstevel@tonic-gate 	sbd_error_t		*err;
11547c478bd9Sstevel@tonic-gate 	drmachid_t		 b_id;
11557c478bd9Sstevel@tonic-gate 	drmach_board_t		*brd;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate #ifdef DEBUG
11587c478bd9Sstevel@tonic-gate 	/*
11597c478bd9Sstevel@tonic-gate 	 * Starfire CPU/MEM/IO boards have only one MC per board.
11607c478bd9Sstevel@tonic-gate 	 * This function has been coded with that fact in mind.
11617c478bd9Sstevel@tonic-gate 	 */
11627c478bd9Sstevel@tonic-gate 	ASSERT(MAX_MEM_UNITS_PER_BOARD == 1);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	/*
11657c478bd9Sstevel@tonic-gate 	 * calculate the maximum space that could be consumed,
11667c478bd9Sstevel@tonic-gate 	 * then verify the available buffer space is adequate.
11677c478bd9Sstevel@tonic-gate 	 */
11687c478bd9Sstevel@tonic-gate 	m  = sizeof (drmach_mc_idle_script_t *) * 2; /* two MCs */
11697c478bd9Sstevel@tonic-gate 	b  = sizeof (drmach_rename_script_t *) * 3 * MAX_CPU_UNITS_PER_BOARD;
11707c478bd9Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 3 * MAX_IO_UNITS_PER_BOARD;
11717c478bd9Sstevel@tonic-gate 	b *= MAX_BOARDS;
11727c478bd9Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 3;
11737c478bd9Sstevel@tonic-gate 	b += sizeof (drmach_rename_script_t *) * 1;
11747c478bd9Sstevel@tonic-gate 	ASSERT(m + b < buflen);
11757c478bd9Sstevel@tonic-gate #endif
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	/*
11787c478bd9Sstevel@tonic-gate 	 * construct an array of MC idle register addresses of
11797c478bd9Sstevel@tonic-gate 	 * both MCs.  The array is zero terminated -- as expected
11807c478bd9Sstevel@tonic-gate 	 * by drmach_copy_rename_prog__relocatable().
11817c478bd9Sstevel@tonic-gate 	 */
11827c478bd9Sstevel@tonic-gate 	isp = (drmach_mc_idle_script_t *)buf;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	/* source mc */
11857c478bd9Sstevel@tonic-gate 	err = drmach_get_mc_idle_addr(s_mem, &isp->idle_addr);
11867c478bd9Sstevel@tonic-gate 	if (err)
11877c478bd9Sstevel@tonic-gate 		return (err);
11887c478bd9Sstevel@tonic-gate 	isp->mem = s_mem;
11897c478bd9Sstevel@tonic-gate 	isp += 1;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	/* target mc */
11927c478bd9Sstevel@tonic-gate 	err = drmach_get_mc_idle_addr(t_mem, &isp->idle_addr);
11937c478bd9Sstevel@tonic-gate 	if (err)
11947c478bd9Sstevel@tonic-gate 		return (err);
11957c478bd9Sstevel@tonic-gate 	isp->mem = t_mem;
11967c478bd9Sstevel@tonic-gate 	isp += 1;
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	/* terminator */
11997c478bd9Sstevel@tonic-gate 	isp->idle_addr = 0;
12007c478bd9Sstevel@tonic-gate 	isp->mem = NULL;
12017c478bd9Sstevel@tonic-gate 	isp += 1;
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	/* fetch source mc asr register value */
12047c478bd9Sstevel@tonic-gate 	err = drmach_read_mc_asr(s_mem, &s_masr);
12057c478bd9Sstevel@tonic-gate 	if (err)
12067c478bd9Sstevel@tonic-gate 		return (err);
12077c478bd9Sstevel@tonic-gate 	else if (s_masr & STARFIRE_MC_INTERLEAVE_MASK) {
12087c478bd9Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
12097c478bd9Sstevel@tonic-gate 		    s_mem->bp->cm.name, s_mem->cm.name));
12107c478bd9Sstevel@tonic-gate 	}
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	/* fetch target mc asr register value */
12137c478bd9Sstevel@tonic-gate 	err = drmach_read_mc_asr(t_mem, &t_masr);
12147c478bd9Sstevel@tonic-gate 	if (err)
12157c478bd9Sstevel@tonic-gate 		return (err);
12167c478bd9Sstevel@tonic-gate 	else if (t_masr & STARFIRE_MC_INTERLEAVE_MASK) {
12177c478bd9Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
12187c478bd9Sstevel@tonic-gate 		    t_mem->bp->cm.name, t_mem->cm.name));
12197c478bd9Sstevel@tonic-gate 	}
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	/* get new source base pa from target's masr */
12227c478bd9Sstevel@tonic-gate 	s_new_basepa = mc_asr_to_pa(t_masr);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	/*
12257c478bd9Sstevel@tonic-gate 	 * remove any existing slice offset to realign
12267c478bd9Sstevel@tonic-gate 	 * memory with board's slice boundary
12277c478bd9Sstevel@tonic-gate 	 */
12287c478bd9Sstevel@tonic-gate 	s_new_basepa &= ~ (mc_get_mem_alignment() - 1);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	/* get new target base pa from source's masr */
12317c478bd9Sstevel@tonic-gate 	t_new_basepa  = mc_asr_to_pa(s_masr);
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	/* remove any existing slice offset, then apply new offset */
12347c478bd9Sstevel@tonic-gate 	t_new_basepa &= ~ (mc_get_mem_alignment() - 1);
12357c478bd9Sstevel@tonic-gate 	t_new_basepa += t_slice_offset;
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	/* encode new base pa into s_masr.  turn off mem present bit */
12387c478bd9Sstevel@tonic-gate 	s_masr  = mc_pa_to_asr(s_masr, s_new_basepa);
12397c478bd9Sstevel@tonic-gate 	s_masr &= ~STARFIRE_MC_MEM_PRESENT_MASK;
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	/* encode new base pa into t_masr.  turn on mem present bit */
12427c478bd9Sstevel@tonic-gate 	t_masr  = mc_pa_to_asr(t_masr, t_new_basepa);
12437c478bd9Sstevel@tonic-gate 	t_masr |= STARFIRE_MC_MEM_PRESENT_MASK;
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	/*
12467c478bd9Sstevel@tonic-gate 	 * Step 0:	Mark source memory as not present.
12477c478bd9Sstevel@tonic-gate 	 */
12487c478bd9Sstevel@tonic-gate 	m = 0;
12497c478bd9Sstevel@tonic-gate 	rsp = (drmach_rename_script_t *)isp;
12507c478bd9Sstevel@tonic-gate 	err = drmach_get_mc_asr_addr(s_mem, &rsp[m].masr_addr);
12517c478bd9Sstevel@tonic-gate 	if (err)
12527c478bd9Sstevel@tonic-gate 		return (err);
12537c478bd9Sstevel@tonic-gate 	rsp[m].masr = s_masr;
12547c478bd9Sstevel@tonic-gate 	m++;
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	/*
12577c478bd9Sstevel@tonic-gate 	 * Step 1:	Write source base address to target MC
12587c478bd9Sstevel@tonic-gate 	 *		with present bit off.
12597c478bd9Sstevel@tonic-gate 	 */
12607c478bd9Sstevel@tonic-gate 	err = drmach_get_mc_asr_addr(t_mem, &rsp[m].masr_addr);
12617c478bd9Sstevel@tonic-gate 	if (err)
12627c478bd9Sstevel@tonic-gate 		return (err);
12637c478bd9Sstevel@tonic-gate 	rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
12647c478bd9Sstevel@tonic-gate 	m++;
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 	/*
12677c478bd9Sstevel@tonic-gate 	 * Step 2:	Now rewrite target reg with present bit on.
12687c478bd9Sstevel@tonic-gate 	 */
12697c478bd9Sstevel@tonic-gate 	rsp[m].masr_addr = rsp[m-1].masr_addr;
12707c478bd9Sstevel@tonic-gate 	rsp[m].masr = t_masr;
12717c478bd9Sstevel@tonic-gate 	m++;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	s_bd = s_mem->bp->bnum;
12747c478bd9Sstevel@tonic-gate 	t_bd = t_mem->bp->bnum;
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	DRMACH_PR("preparing script for CPU and IO units:\n");
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	rv = drmach_array_first(drmach_boards, &b_idx, &b_id);
12797c478bd9Sstevel@tonic-gate 	if (rv) {
12807c478bd9Sstevel@tonic-gate 		/* catch this in debug kernels */
12817c478bd9Sstevel@tonic-gate 		ASSERT(0);
12827c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
12837c478bd9Sstevel@tonic-gate 	}
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	do {
12867c478bd9Sstevel@tonic-gate 		int			 d_idx;
12877c478bd9Sstevel@tonic-gate 		drmachid_t		 d_id;
12887c478bd9Sstevel@tonic-gate 		drmach_device_t		*device;
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 		ASSERT(DRMACH_IS_BOARD_ID(b_id));
12917c478bd9Sstevel@tonic-gate 		brd = b_id;
12927c478bd9Sstevel@tonic-gate 		b = brd->bnum;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 		/*
12957c478bd9Sstevel@tonic-gate 		 * Step 3:	Update PC MADR tables for CPUs.
12967c478bd9Sstevel@tonic-gate 		 */
1297141f8dd3Sjesusm 		if (brd->devices == NULL) {
1298141f8dd3Sjesusm 			/* devices not initialized */
1299141f8dd3Sjesusm 			continue;
1300141f8dd3Sjesusm 		}
1301141f8dd3Sjesusm 
13027c478bd9Sstevel@tonic-gate 		rv = drmach_array_first(brd->devices, &d_idx, &d_id);
13037c478bd9Sstevel@tonic-gate 		if (rv) {
13047c478bd9Sstevel@tonic-gate 			/* must mean no devices on this board */
13057c478bd9Sstevel@tonic-gate 			break;
13067c478bd9Sstevel@tonic-gate 		}
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 		DRMACH_PR("\t%s\n", brd->cm.name);
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 		do {
13117c478bd9Sstevel@tonic-gate 			ASSERT(DRMACH_IS_DEVICE_ID(d_id));
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 			if (!DRMACH_IS_CPU_ID(d_id))
13147c478bd9Sstevel@tonic-gate 				continue;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 			device = d_id;
13177c478bd9Sstevel@tonic-gate 			i = device->unum;
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 			DRMACH_PR("\t\t%s\n", device->cm.name);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 			/*
13227c478bd9Sstevel@tonic-gate 			 * Disabled detaching mem node.
13237c478bd9Sstevel@tonic-gate 			 */
13247c478bd9Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i);
13257c478bd9Sstevel@tonic-gate 			rsp[m].masr = s_masr;
13267c478bd9Sstevel@tonic-gate 			m++;
13277c478bd9Sstevel@tonic-gate 			/*
13287c478bd9Sstevel@tonic-gate 			 * Always write masr with present bit
13297c478bd9Sstevel@tonic-gate 			 * off and then again with it on.
13307c478bd9Sstevel@tonic-gate 			 */
13317c478bd9Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i);
13327c478bd9Sstevel@tonic-gate 			rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
13337c478bd9Sstevel@tonic-gate 			m++;
13347c478bd9Sstevel@tonic-gate 			rsp[m].masr_addr = rsp[m-1].masr_addr;
13357c478bd9Sstevel@tonic-gate 			rsp[m].masr = t_masr;
13367c478bd9Sstevel@tonic-gate 			m++;
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 		} while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0);
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 		/*
13417c478bd9Sstevel@tonic-gate 		 * Step 4:	Update PC MADR tables for IOs.
13427c478bd9Sstevel@tonic-gate 		 */
13437c478bd9Sstevel@tonic-gate 		rv = drmach_array_first(brd->devices, &d_idx, &d_id);
13447c478bd9Sstevel@tonic-gate 		/* this worked for previous loop, must work here too */
13457c478bd9Sstevel@tonic-gate 		ASSERT(rv == 0);
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 		do {
13487c478bd9Sstevel@tonic-gate 			ASSERT(DRMACH_IS_DEVICE_ID(d_id));
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 			if (!DRMACH_IS_IO_ID(d_id))
13517c478bd9Sstevel@tonic-gate 				continue;
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 			device = d_id;
13547c478bd9Sstevel@tonic-gate 			i = device->unum;
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 			DRMACH_PR("\t\t%s\n", device->cm.name);
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 			/*
13597c478bd9Sstevel@tonic-gate 			 * Disabled detaching mem node.
13607c478bd9Sstevel@tonic-gate 			 */
13617c478bd9Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, s_bd, i+4);
13627c478bd9Sstevel@tonic-gate 			rsp[m].masr = s_masr;
13637c478bd9Sstevel@tonic-gate 			m++;
13647c478bd9Sstevel@tonic-gate 			/*
13657c478bd9Sstevel@tonic-gate 			 * Always write masr with present bit
13667c478bd9Sstevel@tonic-gate 			 * off and then again with it on.
13677c478bd9Sstevel@tonic-gate 			 */
13687c478bd9Sstevel@tonic-gate 			rsp[m].masr_addr = STARFIRE_PC_MADR_ADDR(b, t_bd, i+4);
13697c478bd9Sstevel@tonic-gate 			rsp[m].masr = t_masr & ~STARFIRE_MC_MEM_PRESENT_MASK;
13707c478bd9Sstevel@tonic-gate 			m++;
13717c478bd9Sstevel@tonic-gate 			rsp[m].masr_addr = rsp[m-1].masr_addr;
13727c478bd9Sstevel@tonic-gate 			rsp[m].masr = t_masr;
13737c478bd9Sstevel@tonic-gate 			m++;
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 		} while (drmach_array_next(brd->devices, &d_idx, &d_id) == 0);
13767c478bd9Sstevel@tonic-gate 	} while (drmach_array_next(drmach_boards, &b_idx, &b_id) == 0);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	/*
13797c478bd9Sstevel@tonic-gate 	 * Zero masr_addr value indicates the END.
13807c478bd9Sstevel@tonic-gate 	 */
13817c478bd9Sstevel@tonic-gate 	rsp[m].masr_addr = 0ull;
13827c478bd9Sstevel@tonic-gate 	rsp[m].masr = 0;
13837c478bd9Sstevel@tonic-gate 	DRMACH_PR("number of steps in rename script = %d\n", m);
13847c478bd9Sstevel@tonic-gate 	m++;
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	/* paranoia */
13877c478bd9Sstevel@tonic-gate 	ASSERT((caddr_t)&rsp[m] <= buf + buflen);
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate #ifdef DEBUG
13907c478bd9Sstevel@tonic-gate 	{
13917c478bd9Sstevel@tonic-gate 		int	j;
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 		DRMACH_PR("mc idle register address list:");
13947c478bd9Sstevel@tonic-gate 		isp = (drmach_mc_idle_script_t *)buf;
139504580fdfSmathue 		DRMACH_PR("source mc idle addr 0x%lx, mem id %p",
139607d06da5SSurya Prakki 		    isp[0].idle_addr, (void *)isp[0].mem);
139704580fdfSmathue 		DRMACH_PR("target mc idle addr 0x%lx, mem id %p",
139807d06da5SSurya Prakki 		    isp[1].idle_addr, (void *)isp[1].mem);
13997c478bd9Sstevel@tonic-gate 		ASSERT(isp[2].idle_addr == 0);
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 		DRMACH_PR("copy-rename script:");
14027c478bd9Sstevel@tonic-gate 		for (j = 0; j < m; j++) {
140304580fdfSmathue 			DRMACH_PR("0x%lx = 0x%08x",
14047c478bd9Sstevel@tonic-gate 			    rsp[j].masr_addr, rsp[j].masr);
14057c478bd9Sstevel@tonic-gate 		}
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 		DELAY(1000000);
14087c478bd9Sstevel@tonic-gate 	}
14097c478bd9Sstevel@tonic-gate #endif
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	/* return number of bytes consumed */
14127c478bd9Sstevel@tonic-gate 	b = (caddr_t)&rsp[m] - buf;
14137c478bd9Sstevel@tonic-gate 	DRMACH_PR("total number of bytes consumed is %d\n", b);
14147c478bd9Sstevel@tonic-gate 	ASSERT(b <= buflen);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate #ifdef lint
14177c478bd9Sstevel@tonic-gate 	buflen = buflen;
14187c478bd9Sstevel@tonic-gate #endif
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	return (NULL);
14217c478bd9Sstevel@tonic-gate }
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate /*
14247c478bd9Sstevel@tonic-gate  * The routine performs the necessary memory COPY and MC adr SWITCH.
14257c478bd9Sstevel@tonic-gate  * Both operations MUST be at the same "level" so that the stack is
14267c478bd9Sstevel@tonic-gate  * maintained correctly between the copy and switch.  The switch
14277c478bd9Sstevel@tonic-gate  * portion implements a caching mechanism to guarantee the code text
14287c478bd9Sstevel@tonic-gate  * is cached prior to execution.  This is to guard against possible
14297c478bd9Sstevel@tonic-gate  * memory access while the MC adr's are being modified.
14307c478bd9Sstevel@tonic-gate  *
14317c478bd9Sstevel@tonic-gate  * IMPORTANT: The _drmach_copy_rename_end() function must immediately
14327c478bd9Sstevel@tonic-gate  * follow drmach_copy_rename_prog__relocatable() so that the correct
14337c478bd9Sstevel@tonic-gate  * "length" of the drmach_copy_rename_prog__relocatable can be
14347c478bd9Sstevel@tonic-gate  * calculated.  This routine MUST be a LEAF function, i.e. it can
14357c478bd9Sstevel@tonic-gate  * make NO function calls, primarily for two reasons:
14367c478bd9Sstevel@tonic-gate  *
14377c478bd9Sstevel@tonic-gate  *	1. We must keep the stack consistent across the "switch".
14387c478bd9Sstevel@tonic-gate  *	2. Function calls are compiled to relative offsets, and
14397c478bd9Sstevel@tonic-gate  *	   we execute this function we'll be executing it from
14407c478bd9Sstevel@tonic-gate  *	   a copied version in a different area of memory, thus
14417c478bd9Sstevel@tonic-gate  *	   the relative offsets will be bogus.
14427c478bd9Sstevel@tonic-gate  *
14437c478bd9Sstevel@tonic-gate  * Moreover, it must have the "__relocatable" suffix to inform DTrace
14447c478bd9Sstevel@tonic-gate  * providers (and anything else, for that matter) that this
14457c478bd9Sstevel@tonic-gate  * function's text is manually relocated elsewhere before it is
14467c478bd9Sstevel@tonic-gate  * executed.  That is, it cannot be safely instrumented with any
14477c478bd9Sstevel@tonic-gate  * methodology that is PC-relative.
14487c478bd9Sstevel@tonic-gate  */
14497c478bd9Sstevel@tonic-gate static void
14507c478bd9Sstevel@tonic-gate drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog)
14517c478bd9Sstevel@tonic-gate {
14527c478bd9Sstevel@tonic-gate 	extern void drmach_exec_script_il(drmach_rename_script_t *rsp);
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	drmach_mc_idle_script_t		*isp;
14557c478bd9Sstevel@tonic-gate 	struct memlist			*ml;
14567c478bd9Sstevel@tonic-gate 	int				csize;
14577c478bd9Sstevel@tonic-gate 	int				lnsize;
14587c478bd9Sstevel@tonic-gate 	uint64_t			caddr;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	isp = (drmach_mc_idle_script_t *)prog->data;
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	caddr = ecache_flushaddr;
14637c478bd9Sstevel@tonic-gate 	csize = (cpunodes[CPU->cpu_id].ecache_size << 1);
14647c478bd9Sstevel@tonic-gate 	lnsize = cpunodes[CPU->cpu_id].ecache_linesize;
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	/*
14677c478bd9Sstevel@tonic-gate 	 * DO COPY.
14687c478bd9Sstevel@tonic-gate 	 */
146956f33205SJonathan Adams 	for (ml = prog->c_ml; ml; ml = ml->ml_next) {
14707c478bd9Sstevel@tonic-gate 		uint64_t	s_pa, t_pa;
14717c478bd9Sstevel@tonic-gate 		uint64_t	nbytes;
14727c478bd9Sstevel@tonic-gate 
147356f33205SJonathan Adams 		s_pa = prog->s_copybasepa + ml->ml_address;
147456f33205SJonathan Adams 		t_pa = prog->t_copybasepa + ml->ml_address;
147556f33205SJonathan Adams 		nbytes = ml->ml_size;
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 		while (nbytes != 0ull) {
14787c478bd9Sstevel@tonic-gate 			/*
14797c478bd9Sstevel@tonic-gate 			 * This copy does NOT use an ASI
14807c478bd9Sstevel@tonic-gate 			 * that avoids the Ecache, therefore
14817c478bd9Sstevel@tonic-gate 			 * the dst_pa addresses may remain
14827c478bd9Sstevel@tonic-gate 			 * in our Ecache after the dst_pa
14837c478bd9Sstevel@tonic-gate 			 * has been removed from the system.
14847c478bd9Sstevel@tonic-gate 			 * A subsequent write-back to memory
14857c478bd9Sstevel@tonic-gate 			 * will cause an ARB-stop because the
14867c478bd9Sstevel@tonic-gate 			 * physical address no longer exists
14877c478bd9Sstevel@tonic-gate 			 * in the system. Therefore we must
14887c478bd9Sstevel@tonic-gate 			 * flush out local Ecache after we
14897c478bd9Sstevel@tonic-gate 			 * finish the copy.
14907c478bd9Sstevel@tonic-gate 			 */
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 			/* copy 32 bytes at src_pa to dst_pa */
14937c478bd9Sstevel@tonic-gate 			bcopy32_il(s_pa, t_pa);
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 			/* increment by 32 bytes */
14967c478bd9Sstevel@tonic-gate 			s_pa += (4 * sizeof (uint64_t));
14977c478bd9Sstevel@tonic-gate 			t_pa += (4 * sizeof (uint64_t));
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 			/* decrement by 32 bytes */
15007c478bd9Sstevel@tonic-gate 			nbytes -= (4 * sizeof (uint64_t));
15017c478bd9Sstevel@tonic-gate 		}
15027c478bd9Sstevel@tonic-gate 	}
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	/*
15057c478bd9Sstevel@tonic-gate 	 * Since bcopy32_il() does NOT use an ASI to bypass
15067c478bd9Sstevel@tonic-gate 	 * the Ecache, we need to flush our Ecache after
15077c478bd9Sstevel@tonic-gate 	 * the copy is complete.
15087c478bd9Sstevel@tonic-gate 	 */
15097c478bd9Sstevel@tonic-gate 	flush_ecache_il(caddr, csize, lnsize);		/* inline version */
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 	/*
15127c478bd9Sstevel@tonic-gate 	 * Wait for MCs to go idle.
15137c478bd9Sstevel@tonic-gate 	 */
15147c478bd9Sstevel@tonic-gate 	do {
15157c478bd9Sstevel@tonic-gate 		register int	t = 10;
15167c478bd9Sstevel@tonic-gate 		register uint_t	v;
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 		/* loop t cycles waiting for each mc to indicate it's idle */
15197c478bd9Sstevel@tonic-gate 		do {
15207c478bd9Sstevel@tonic-gate 			v = ldphysio_il(isp->idle_addr)
15217c478bd9Sstevel@tonic-gate 			    & STARFIRE_MC_IDLE_MASK;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 		} while (v != STARFIRE_MC_IDLE_MASK && t-- > 0);
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 		/* bailout if timedout */
15267c478bd9Sstevel@tonic-gate 		if (t <= 0) {
15277c478bd9Sstevel@tonic-gate 			prog->restless_mc = isp->mem;
15287c478bd9Sstevel@tonic-gate 			return;
15297c478bd9Sstevel@tonic-gate 		}
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 		isp += 1;
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 		/* stop if terminating zero has been reached */
15347c478bd9Sstevel@tonic-gate 	} while (isp->idle_addr != 0);
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 	/* advance passed terminating zero */
15377c478bd9Sstevel@tonic-gate 	isp += 1;
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	/*
15407c478bd9Sstevel@tonic-gate 	 * The following inline assembly routine caches
15417c478bd9Sstevel@tonic-gate 	 * the rename script and then caches the code that
15427c478bd9Sstevel@tonic-gate 	 * will do the rename.  This is necessary
15437c478bd9Sstevel@tonic-gate 	 * so that we don't have any memory references during
15447c478bd9Sstevel@tonic-gate 	 * the reprogramming.  We accomplish this by first
15457c478bd9Sstevel@tonic-gate 	 * jumping through the code to guarantee it's cached
15467c478bd9Sstevel@tonic-gate 	 * before we actually execute it.
15477c478bd9Sstevel@tonic-gate 	 */
15487c478bd9Sstevel@tonic-gate 	drmach_exec_script_il((drmach_rename_script_t *)isp);
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate static void
15527c478bd9Sstevel@tonic-gate drmach_copy_rename_end(void)
15537c478bd9Sstevel@tonic-gate {
15547c478bd9Sstevel@tonic-gate 	/*
15557c478bd9Sstevel@tonic-gate 	 * IMPORTANT:	This function's location MUST be located immediately
15567c478bd9Sstevel@tonic-gate 	 *		following drmach_copy_rename_prog__relocatable to
15577c478bd9Sstevel@tonic-gate 	 *		accurately estimate its size.  Note that this assumes
15587c478bd9Sstevel@tonic-gate 	 *		the compiler keeps these functions in the order in
15597c478bd9Sstevel@tonic-gate 	 *		which they appear :-o
15607c478bd9Sstevel@tonic-gate 	 */
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate sbd_error_t *
15647c478bd9Sstevel@tonic-gate drmach_copy_rename_init(drmachid_t t_id, uint64_t t_slice_offset,
15657c478bd9Sstevel@tonic-gate 	drmachid_t s_id, struct memlist *c_ml, drmachid_t *pgm_id)
15667c478bd9Sstevel@tonic-gate {
15677c478bd9Sstevel@tonic-gate 	drmach_device_t	*s_mem;
15687c478bd9Sstevel@tonic-gate 	drmach_device_t	*t_mem;
15697c478bd9Sstevel@tonic-gate 	struct memlist	*x_ml;
15707c478bd9Sstevel@tonic-gate 	uint64_t	off_mask, s_copybasepa, t_copybasepa, t_basepa;
15717c478bd9Sstevel@tonic-gate 	int		len;
15727c478bd9Sstevel@tonic-gate 	caddr_t		bp, wp;
15737c478bd9Sstevel@tonic-gate 	pda_handle_t	ph;
15747c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
15757c478bd9Sstevel@tonic-gate 	drmach_copy_rename_program_t *prog;
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(s_id))
15787c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
15797c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(t_id))
15807c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
15817c478bd9Sstevel@tonic-gate 	s_mem = s_id;
15827c478bd9Sstevel@tonic-gate 	t_mem = t_id;
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	/* get starting physical address of target memory */
15857c478bd9Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(t_id, &t_basepa);
15867c478bd9Sstevel@tonic-gate 	if (err)
15877c478bd9Sstevel@tonic-gate 		return (err);
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	/* calculate slice offset mask from slice size */
15907c478bd9Sstevel@tonic-gate 	off_mask = mc_get_mem_alignment() - 1;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	/* calculate source and target base pa */
159356f33205SJonathan Adams 	s_copybasepa = c_ml->ml_address;
159456f33205SJonathan Adams 	t_copybasepa =
159556f33205SJonathan Adams 	    t_basepa + ((c_ml->ml_address & off_mask) - t_slice_offset);
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	/* paranoia */
159856f33205SJonathan Adams 	ASSERT((c_ml->ml_address & off_mask) >= t_slice_offset);
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	/* adjust copy memlist addresses to be relative to copy base pa */
16017c478bd9Sstevel@tonic-gate 	x_ml = c_ml;
16027c478bd9Sstevel@tonic-gate 	while (x_ml != NULL) {
160356f33205SJonathan Adams 		x_ml->ml_address -= s_copybasepa;
160456f33205SJonathan Adams 		x_ml = x_ml->ml_next;
16057c478bd9Sstevel@tonic-gate 	}
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate #ifdef DEBUG
16087c478bd9Sstevel@tonic-gate 	{
16097c478bd9Sstevel@tonic-gate 	uint64_t s_basepa, s_size, t_size;
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 	x_ml = c_ml;
161256f33205SJonathan Adams 	while (x_ml->ml_next != NULL)
161356f33205SJonathan Adams 		x_ml = x_ml->ml_next;
16147c478bd9Sstevel@tonic-gate 
161504580fdfSmathue 	DRMACH_PR("source copy span: base pa 0x%lx, end pa 0x%lx\n",
16167c478bd9Sstevel@tonic-gate 	    s_copybasepa,
161756f33205SJonathan Adams 	    s_copybasepa + x_ml->ml_address + x_ml->ml_size);
16187c478bd9Sstevel@tonic-gate 
161904580fdfSmathue 	DRMACH_PR("target copy span: base pa 0x%lx, end pa 0x%lx\n",
16207c478bd9Sstevel@tonic-gate 	    t_copybasepa,
162156f33205SJonathan Adams 	    t_copybasepa + x_ml->ml_address + x_ml->ml_size);
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	DRMACH_PR("copy memlist (relative to copy base pa):\n");
16247c478bd9Sstevel@tonic-gate 	MEMLIST_DUMP(c_ml);
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(s_id, &s_basepa);
16277c478bd9Sstevel@tonic-gate 	ASSERT(err == NULL);
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	err = drmach_mem_get_size(s_id, &s_size);
16307c478bd9Sstevel@tonic-gate 	ASSERT(err == NULL);
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	err = drmach_mem_get_size(t_id, &t_size);
16337c478bd9Sstevel@tonic-gate 	ASSERT(err == NULL);
16347c478bd9Sstevel@tonic-gate 
163504580fdfSmathue 	DRMACH_PR("current source base pa 0x%lx, size 0x%lx\n",
16367c478bd9Sstevel@tonic-gate 	    s_basepa, s_size);
163704580fdfSmathue 	DRMACH_PR("current target base pa 0x%lx, size 0x%lx\n",
16387c478bd9Sstevel@tonic-gate 	    t_basepa, t_size);
16397c478bd9Sstevel@tonic-gate 
164056f33205SJonathan Adams 	ASSERT(s_copybasepa + x_ml->ml_address + x_ml->ml_size <=
164156f33205SJonathan Adams 	    s_basepa + s_size);
164256f33205SJonathan Adams 	ASSERT(t_copybasepa + x_ml->ml_address + x_ml->ml_size <=
164356f33205SJonathan Adams 	    t_basepa + t_size);
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate #endif
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	ph = drmach_pda_open();
16487c478bd9Sstevel@tonic-gate 	if (ph == NULL)
16497c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	/*
16527c478bd9Sstevel@tonic-gate 	 * bp will be page aligned, since we're calling
16537c478bd9Sstevel@tonic-gate 	 * kmem_zalloc() with an exact multiple of PAGESIZE.
16547c478bd9Sstevel@tonic-gate 	 */
16557c478bd9Sstevel@tonic-gate 	wp = bp = kmem_zalloc(PAGESIZE, KM_SLEEP);
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 	/* allocate space for copy rename struct */
16587c478bd9Sstevel@tonic-gate 	len = sizeof (drmach_copy_rename_program_t);
165907d06da5SSurya Prakki 	DRMACH_PR("prog = 0x%p, header len %d\n", (void *)wp, len);
16607c478bd9Sstevel@tonic-gate 	prog = (drmach_copy_rename_program_t *)wp;
16617c478bd9Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	/*
16647c478bd9Sstevel@tonic-gate 	 * Copy the code for the copy-rename routine into
16657c478bd9Sstevel@tonic-gate 	 * a page aligned piece of memory.  We do this to guarantee
16667c478bd9Sstevel@tonic-gate 	 * that we're executing within the same page and thus reduce
16677c478bd9Sstevel@tonic-gate 	 * the possibility of cache collisions between different
16687c478bd9Sstevel@tonic-gate 	 * pages.
16697c478bd9Sstevel@tonic-gate 	 */
16707c478bd9Sstevel@tonic-gate 	len = (int)((ulong_t)drmach_copy_rename_end -
16717c478bd9Sstevel@tonic-gate 	    (ulong_t)drmach_copy_rename_prog__relocatable);
16727c478bd9Sstevel@tonic-gate 	ASSERT(wp + len < bp + PAGESIZE);
16737c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len);
16747c478bd9Sstevel@tonic-gate 
167507d06da5SSurya Prakki 	DRMACH_PR("copy-rename function 0x%p, len %d\n", (void *)wp, len);
16767c478bd9Sstevel@tonic-gate 	prog->run = (void (*)())wp;
16777c478bd9Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	/*
16807c478bd9Sstevel@tonic-gate 	 * Prepare data page that will contain script of
16817c478bd9Sstevel@tonic-gate 	 * operations to perform during copy-rename.
16827c478bd9Sstevel@tonic-gate 	 * Allocate temporary buffer to hold script.
16837c478bd9Sstevel@tonic-gate 	 */
16847c478bd9Sstevel@tonic-gate 	err = drmach_prep_rename_script(s_mem, t_mem, t_slice_offset,
16857c478bd9Sstevel@tonic-gate 	    wp, PAGESIZE - (wp - bp));
16867c478bd9Sstevel@tonic-gate 	if (err) {
16877c478bd9Sstevel@tonic-gate 		(void) drmach_copy_rename_fini(prog);
16887c478bd9Sstevel@tonic-gate 		return (err);
16897c478bd9Sstevel@tonic-gate 	}
16907c478bd9Sstevel@tonic-gate 
169107d06da5SSurya Prakki 	DRMACH_PR("copy-rename script 0x%p, len %d\n", (void *)wp, len);
16927c478bd9Sstevel@tonic-gate 	prog->data = wp;
16937c478bd9Sstevel@tonic-gate 	wp += (len + ecache_alignsize - 1) & ~ (ecache_alignsize - 1);
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 	prog->ph = ph;
16967c478bd9Sstevel@tonic-gate 	prog->s_copybasepa = s_copybasepa;
16977c478bd9Sstevel@tonic-gate 	prog->t_copybasepa = t_copybasepa;
16987c478bd9Sstevel@tonic-gate 	prog->c_ml = c_ml;
16997c478bd9Sstevel@tonic-gate 	*pgm_id = prog;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	return (NULL);
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate sbd_error_t *
17057c478bd9Sstevel@tonic-gate drmach_copy_rename_fini(drmachid_t id)
17067c478bd9Sstevel@tonic-gate {
17077c478bd9Sstevel@tonic-gate 	drmach_copy_rename_program_t	*prog = id;
17087c478bd9Sstevel@tonic-gate 	sbd_error_t			*err = NULL;
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	if (prog->c_ml != NULL)
17117c478bd9Sstevel@tonic-gate 		memlist_delete(prog->c_ml);
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 	if (prog->ph != NULL)
17147c478bd9Sstevel@tonic-gate 		pda_close(prog->ph);
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	if (prog->restless_mc != 0) {
17177c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "MC did not idle; OBP Node 0x%x",
17187c478bd9Sstevel@tonic-gate 		    (uint_t)drmach_node_get_dnode(prog->restless_mc->node));
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
17217c478bd9Sstevel@tonic-gate 	}
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	kmem_free(prog, PAGESIZE);
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	return (err);
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate static sbd_error_t *
17297c478bd9Sstevel@tonic-gate drmach_io_new(drmach_device_t *dp)
17307c478bd9Sstevel@tonic-gate {
17317c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
17327c478bd9Sstevel@tonic-gate 	int		 portid;
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	err = drmach_device_get_prop(dp, "upa-portid", &portid);
17357c478bd9Sstevel@tonic-gate 	if (err == NULL) {
17367c478bd9Sstevel@tonic-gate 		ASSERT(portid & 0x40);
17377c478bd9Sstevel@tonic-gate 		dp->unum = portid & 1;
17387c478bd9Sstevel@tonic-gate 	}
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_io_new;
17417c478bd9Sstevel@tonic-gate 	dp->cm.release = drmach_io_release;
17427c478bd9Sstevel@tonic-gate 	dp->cm.status = drmach_io_status;
17437c478bd9Sstevel@tonic-gate 
174407d06da5SSurya Prakki 	(void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type,
174507d06da5SSurya Prakki 	    dp->unum);
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	return (err);
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate static void
17517c478bd9Sstevel@tonic-gate drmach_iopc_op(pda_handle_t ph, drmach_iopc_op_t op)
17527c478bd9Sstevel@tonic-gate {
17537c478bd9Sstevel@tonic-gate 	register int b;
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	for (b = 0; b < MAX_BOARDS; b++) {
17567c478bd9Sstevel@tonic-gate 		int		p;
17577c478bd9Sstevel@tonic-gate 		ushort_t	bda_ioc;
17587c478bd9Sstevel@tonic-gate 		board_desc_t	*bdesc;
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 		if (pda_board_present(ph, b) == 0)
17617c478bd9Sstevel@tonic-gate 			continue;
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 		bdesc = (board_desc_t *)pda_get_board_info(ph, b);
17647c478bd9Sstevel@tonic-gate 		/*
17657c478bd9Sstevel@tonic-gate 		 * Update PCs for IOCs.
17667c478bd9Sstevel@tonic-gate 		 */
17677c478bd9Sstevel@tonic-gate 		bda_ioc = bdesc->bda_ioc;
17687c478bd9Sstevel@tonic-gate 		for (p = 0; p < MAX_IOCS; p++) {
17697c478bd9Sstevel@tonic-gate 			u_longlong_t	idle_addr;
17707c478bd9Sstevel@tonic-gate 			uchar_t		value;
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 			if (BDA_NBL(bda_ioc, p) != BDAN_GOOD)
17737c478bd9Sstevel@tonic-gate 				continue;
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 			idle_addr = STARFIRE_BB_PC_ADDR(b, p, 1);
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 			switch (op) {
17787c478bd9Sstevel@tonic-gate 			case DO_PAUSE:
17797c478bd9Sstevel@tonic-gate 				value = STARFIRE_BB_PC_PAUSE(p);
17807c478bd9Sstevel@tonic-gate 				break;
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 			case DO_IDLE:
17837c478bd9Sstevel@tonic-gate 				value = STARFIRE_BB_PC_IDLE(p);
17847c478bd9Sstevel@tonic-gate 				break;
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 			case DO_UNPAUSE:
17877c478bd9Sstevel@tonic-gate 				value = ldbphysio(idle_addr);
17887c478bd9Sstevel@tonic-gate 				value &= ~STARFIRE_BB_PC_PAUSE(p);
17897c478bd9Sstevel@tonic-gate 				break;
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 			case DO_UNIDLE:
17927c478bd9Sstevel@tonic-gate 				value = ldbphysio(idle_addr);
17937c478bd9Sstevel@tonic-gate 				value &= ~STARFIRE_BB_PC_IDLE(p);
17947c478bd9Sstevel@tonic-gate 				break;
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 			default:
17977c478bd9Sstevel@tonic-gate 				cmn_err(CE_PANIC,
17987c478bd9Sstevel@tonic-gate 				    "drmach_iopc_op: unknown op (%d)",
17997c478bd9Sstevel@tonic-gate 				    (int)op);
18007c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
18017c478bd9Sstevel@tonic-gate 			}
18027c478bd9Sstevel@tonic-gate 			stbphysio(idle_addr, value);
18037c478bd9Sstevel@tonic-gate 		}
18047c478bd9Sstevel@tonic-gate 	}
18057c478bd9Sstevel@tonic-gate }
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate void
18087c478bd9Sstevel@tonic-gate drmach_copy_rename(drmachid_t id)
18097c478bd9Sstevel@tonic-gate {
18107c478bd9Sstevel@tonic-gate 	drmach_copy_rename_program_t	*prog = id;
18117c478bd9Sstevel@tonic-gate 	uint64_t			neer;
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 	/*
18147c478bd9Sstevel@tonic-gate 	 * UPA IDLE
18157c478bd9Sstevel@tonic-gate 	 * Protocol = PAUSE -> IDLE -> UNPAUSE
18167c478bd9Sstevel@tonic-gate 	 * In reality since we only "idle" the IOPCs it's sufficient
18177c478bd9Sstevel@tonic-gate 	 * to just issue the IDLE operation since (in theory) all IOPCs
18187c478bd9Sstevel@tonic-gate 	 * in the field are PC6.  However, we'll be robust and do the
18197c478bd9Sstevel@tonic-gate 	 * proper workaround protocol so that we never have to worry!
18207c478bd9Sstevel@tonic-gate 	 */
18217c478bd9Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_PAUSE);
18227c478bd9Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_IDLE);
18237c478bd9Sstevel@tonic-gate 	DELAY(100);
18247c478bd9Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_UNPAUSE);
18257c478bd9Sstevel@tonic-gate 	DELAY(100);
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	/* disable CE reporting */
18287c478bd9Sstevel@tonic-gate 	neer = get_error_enable();
18297c478bd9Sstevel@tonic-gate 	set_error_enable(neer & ~EER_CEEN);
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	/* run the copy/rename program */
18327c478bd9Sstevel@tonic-gate 	prog->run(prog);
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 	/* enable CE reporting */
18357c478bd9Sstevel@tonic-gate 	set_error_enable(neer);
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	/*
18387c478bd9Sstevel@tonic-gate 	 * UPA UNIDLE
18397c478bd9Sstevel@tonic-gate 	 * Protocol = UNIDLE
18407c478bd9Sstevel@tonic-gate 	 */
18417c478bd9Sstevel@tonic-gate 	drmach_iopc_op(prog->ph, DO_UNIDLE);
18427c478bd9Sstevel@tonic-gate 	DELAY(100);
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate /*
18467c478bd9Sstevel@tonic-gate  * The counter-timer and perf-counter nodes are not being cleaned
18477c478bd9Sstevel@tonic-gate  * up after a board that was present at start of day is detached.
18487c478bd9Sstevel@tonic-gate  * If the board has become unconfigured with this operation, walk
18497c478bd9Sstevel@tonic-gate  * the prom tree and find all counter-timer and perf-counter nodes
18507c478bd9Sstevel@tonic-gate  * that have the same board number as the board that was just
18517c478bd9Sstevel@tonic-gate  * unconfigured and remove them.
18527c478bd9Sstevel@tonic-gate  */
18537c478bd9Sstevel@tonic-gate static sbd_error_t *
18547c478bd9Sstevel@tonic-gate drmach_remove_counter_nodes(drmachid_t id)
18557c478bd9Sstevel@tonic-gate {
18567c478bd9Sstevel@tonic-gate 	int		num;
18577c478bd9Sstevel@tonic-gate 	char		name[OBP_MAXDRVNAME];
1858fa9e4066Sahrens 	pnode_t		child;
18597c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
18607c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
18617c478bd9Sstevel@tonic-gate 	drmach_status_t	stat;
18627c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id)) {
18657c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
18667c478bd9Sstevel@tonic-gate 	}
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	if ((err = drmach_board_status(id, &stat)) != NULL) {
18697c478bd9Sstevel@tonic-gate 		return (err);
18707c478bd9Sstevel@tonic-gate 	}
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	/*
18737c478bd9Sstevel@tonic-gate 	 * Only clean up the counter-timer and perf-counter
18747c478bd9Sstevel@tonic-gate 	 * nodes when the entire board is unconfigured.
18757c478bd9Sstevel@tonic-gate 	 */
18767c478bd9Sstevel@tonic-gate 	if (stat.configured) {
18777c478bd9Sstevel@tonic-gate 		return (NULL);
18787c478bd9Sstevel@tonic-gate 	}
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 	bp = (drmach_board_t *)id;
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 	err = NULL;
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	for (child = prom_childnode(prom_rootnode()); child != OBP_NONODE;
18857c478bd9Sstevel@tonic-gate 	    child = prom_nextnode(child)) {
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 		if (prom_getprop(child, OBP_BOARDNUM, (caddr_t)&num) == -1) {
18887c478bd9Sstevel@tonic-gate 			continue;
18897c478bd9Sstevel@tonic-gate 		}
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 		if (bp->bnum != num) {
18927c478bd9Sstevel@tonic-gate 			continue;
18937c478bd9Sstevel@tonic-gate 		}
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 		if (prom_getprop(child, OBP_NAME, (caddr_t)name) == -1) {
18967c478bd9Sstevel@tonic-gate 			continue;
18977c478bd9Sstevel@tonic-gate 		}
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 		if (strncmp(name, MISC_COUNTER_TIMER_DEVNAME, OBP_MAXDRVNAME) &&
19007c478bd9Sstevel@tonic-gate 		    strncmp(name, MISC_PERF_COUNTER_DEVNAME, OBP_MAXDRVNAME)) {
19017c478bd9Sstevel@tonic-gate 				continue;
19027c478bd9Sstevel@tonic-gate 		}
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 		/* Root node doesn't have to be held */
19057c478bd9Sstevel@tonic-gate 		dip = e_ddi_nodeid_to_dip(child);
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 		/*
19087c478bd9Sstevel@tonic-gate 		 * If the node is only in the OBP tree, then
19097c478bd9Sstevel@tonic-gate 		 * we don't have to remove it.
19107c478bd9Sstevel@tonic-gate 		 */
19117c478bd9Sstevel@tonic-gate 		if (dip) {
19127c478bd9Sstevel@tonic-gate 			dev_info_t *fdip = NULL;
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 			DRMACH_PR("removing %s devinfo node\n", name);
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 			e_ddi_branch_hold(dip);
19177c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip); /* held in e_ddi_nodeid_to_dip */
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 			if (e_ddi_branch_destroy(dip, &fdip, 0)) {
19207c478bd9Sstevel@tonic-gate 				char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 				/*
19237c478bd9Sstevel@tonic-gate 				 * If non-NULL, fdip is held and must be
19247c478bd9Sstevel@tonic-gate 				 * released.
19257c478bd9Sstevel@tonic-gate 				 */
19267c478bd9Sstevel@tonic-gate 				if (fdip != NULL) {
19277c478bd9Sstevel@tonic-gate 					(void) ddi_pathname(fdip, path);
19287c478bd9Sstevel@tonic-gate 					ddi_release_devi(fdip);
19297c478bd9Sstevel@tonic-gate 				} else {
19307c478bd9Sstevel@tonic-gate 					(void) ddi_pathname(dip, path);
19317c478bd9Sstevel@tonic-gate 				}
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 				err = drerr_new(1, ESTF_DRVFAIL, path);
19347c478bd9Sstevel@tonic-gate 				kmem_free(path, MAXPATHLEN);
19357c478bd9Sstevel@tonic-gate 				e_ddi_branch_rele(dip);
19367c478bd9Sstevel@tonic-gate 				break;
19377c478bd9Sstevel@tonic-gate 			}
19387c478bd9Sstevel@tonic-gate 		}
19397c478bd9Sstevel@tonic-gate 	}
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate 	return (err);
19427c478bd9Sstevel@tonic-gate }
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19457c478bd9Sstevel@tonic-gate sbd_error_t *
19467c478bd9Sstevel@tonic-gate drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts)
19477c478bd9Sstevel@tonic-gate {
19487c478bd9Sstevel@tonic-gate 	/* allow status and ncm operations to always succeed */
19497c478bd9Sstevel@tonic-gate 	if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) {
19507c478bd9Sstevel@tonic-gate 		return (NULL);
19517c478bd9Sstevel@tonic-gate 	}
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	/* check all other commands for the required option string */
19547c478bd9Sstevel@tonic-gate 	if ((opts->size > 0) && (opts->copts != NULL)) {
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 		DRMACH_PR("platform options: %s\n", opts->copts);
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 		if (strstr(opts->copts, "xfdr") != NULL) {
19597c478bd9Sstevel@tonic-gate 			return (NULL);
19607c478bd9Sstevel@tonic-gate 		}
19617c478bd9Sstevel@tonic-gate 	}
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate 	return (drerr_new(0, ESTF_SUPPORT, NULL));
19647c478bd9Sstevel@tonic-gate }
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19677c478bd9Sstevel@tonic-gate sbd_error_t *
19687c478bd9Sstevel@tonic-gate drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts)
19697c478bd9Sstevel@tonic-gate {
19707c478bd9Sstevel@tonic-gate 	sbd_error_t	*err = NULL;
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	switch (cmd) {
19737c478bd9Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate 		err = drmach_remove_counter_nodes(id);
19767c478bd9Sstevel@tonic-gate 		break;
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
19797c478bd9Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
19807c478bd9Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
19817c478bd9Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
19827c478bd9Sstevel@tonic-gate 	case SBD_CMD_STATUS:
19837c478bd9Sstevel@tonic-gate 		break;
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 	default:
19867c478bd9Sstevel@tonic-gate 		break;
19877c478bd9Sstevel@tonic-gate 	}
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate 	return (err);
19907c478bd9Sstevel@tonic-gate }
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate sbd_error_t *
19937c478bd9Sstevel@tonic-gate drmach_board_assign(int bnum, drmachid_t *id)
19947c478bd9Sstevel@tonic-gate {
19957c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	if (!drmach_initialized && drmach_init() == -1) {
19987c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
19997c478bd9Sstevel@tonic-gate 	} else if (drmach_array_get(drmach_boards, bnum, id) == -1) {
20007c478bd9Sstevel@tonic-gate 		err = drerr_new(1, ESTF_BNUM, "%d", bnum);
20017c478bd9Sstevel@tonic-gate 	} else if (*id != NULL) {
20027c478bd9Sstevel@tonic-gate 		err = NULL;
20037c478bd9Sstevel@tonic-gate 	} else {
20047c478bd9Sstevel@tonic-gate 		drmach_board_t	*bp;
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 		*id  = (drmachid_t)drmach_board_new(bnum);
20077c478bd9Sstevel@tonic-gate 		bp = *id;
20087c478bd9Sstevel@tonic-gate 		bp->assigned = 1;
20097c478bd9Sstevel@tonic-gate 		err = NULL;
20107c478bd9Sstevel@tonic-gate 	}
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate 	return (err);
20137c478bd9Sstevel@tonic-gate }
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate static int
20167c478bd9Sstevel@tonic-gate drmach_attach_board(void *arg)
20177c478bd9Sstevel@tonic-gate {
20187c478bd9Sstevel@tonic-gate 	drmach_board_t	*obj = (drmach_board_t *)arg;
20197c478bd9Sstevel@tonic-gate 	cpuset_t	cset;
20207c478bd9Sstevel@tonic-gate 	int		retval;
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 	/*
20237c478bd9Sstevel@tonic-gate 	 * OBP disables traps during the board probe.
20247c478bd9Sstevel@tonic-gate 	 * So, in order to prevent cross-call/cross-trap timeouts,
20257c478bd9Sstevel@tonic-gate 	 * and thus panics, we effectively block anybody from
20267c478bd9Sstevel@tonic-gate 	 * issuing xc's/xt's by doing a promsafe_xc_attention.
20277c478bd9Sstevel@tonic-gate 	 * In the previous version of Starfire DR (2.6), a timeout
20287c478bd9Sstevel@tonic-gate 	 * suspension mechanism was implemented in the send-mondo
20297c478bd9Sstevel@tonic-gate 	 * assembly.  That mechanism is unnecessary with the
20307c478bd9Sstevel@tonic-gate 	 * existence of xc_attention/xc_dismissed.
20317c478bd9Sstevel@tonic-gate 	 */
20327c478bd9Sstevel@tonic-gate 	cset = cpu_ready_set;
20337c478bd9Sstevel@tonic-gate 	promsafe_xc_attention(cset);
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	retval = prom_starfire_add_brd(obj->connect_cpuid);
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 	xc_dismissed(cset);
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 	return (retval);
20407c478bd9Sstevel@tonic-gate }
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate sbd_error_t *
20437c478bd9Sstevel@tonic-gate drmach_board_connect(drmachid_t id, drmach_opts_t *opts)
20447c478bd9Sstevel@tonic-gate {
20457c478bd9Sstevel@tonic-gate 	drmach_board_t	*obj = (drmach_board_t *)id;
20467c478bd9Sstevel@tonic-gate 	int		retval;
20477c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
20487c478bd9Sstevel@tonic-gate 	char		*cptr, *copts;
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
20517c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	if (opts->size > 0)
20547c478bd9Sstevel@tonic-gate 		copts = opts->copts;
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	if ((cptr = strstr(copts, "cpuid=")) != NULL) {
20577c478bd9Sstevel@tonic-gate 		int cpuid;
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 		cptr += strlen("cpuid=");
20607c478bd9Sstevel@tonic-gate 		cpuid = stoi(&cptr);
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 		if (DRMACH_CPUID2BNUM(cpuid) == obj->bnum) {
20637c478bd9Sstevel@tonic-gate 			obj->connect_cpuid = cpuid;
20647c478bd9Sstevel@tonic-gate 			obj->assigned = 1;
20657c478bd9Sstevel@tonic-gate 		} else
20667c478bd9Sstevel@tonic-gate 			return (drerr_new(1, ESTF_SETCPUVAL, "%d", cpuid));
20677c478bd9Sstevel@tonic-gate 	} else {
20687c478bd9Sstevel@tonic-gate 		/* cpuid was not specified */
20697c478bd9Sstevel@tonic-gate 		obj->connect_cpuid = -1;
20707c478bd9Sstevel@tonic-gate 	}
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	if (obj->connect_cpuid == -1) {
20737c478bd9Sstevel@tonic-gate 		err =  drerr_new(1, ESTF_NOCPUID, obj->cm.name);
20747c478bd9Sstevel@tonic-gate 		return (err);
20757c478bd9Sstevel@tonic-gate 	}
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "DRMACH: PROM attach %s CPU %d\n",
20787c478bd9Sstevel@tonic-gate 	    obj->cm.name, obj->connect_cpuid);
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	retval = prom_tree_update(drmach_attach_board, obj);
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 	if (retval == 0)
20837c478bd9Sstevel@tonic-gate 		err = NULL;
20847c478bd9Sstevel@tonic-gate 	else {
20857c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "prom error: prom_starfire_add_brd(%d) "
20867c478bd9Sstevel@tonic-gate 		    "returned %d", obj->connect_cpuid, retval);
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 		err = drerr_new(1, ESTF_PROBE, obj->cm.name);
20897c478bd9Sstevel@tonic-gate 	}
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 	obj->connect_cpuid = -1;
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	return (err);
20947c478bd9Sstevel@tonic-gate }
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20977c478bd9Sstevel@tonic-gate sbd_error_t *
20987c478bd9Sstevel@tonic-gate drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts)
20997c478bd9Sstevel@tonic-gate {
2100d8995facSha137994 	drmach_board_t		*bp;
2101d8995facSha137994 	int			rv;
2102d8995facSha137994 	int			d_idx;	/* device index */
2103d8995facSha137994 	drmachid_t		d_id;	/* device ID */
2104d8995facSha137994 	sbd_error_t		*err;
2105d8995facSha137994 
2106d8995facSha137994 	if (!DRMACH_IS_BOARD_ID(id))
2107d8995facSha137994 		return (drerr_new(0, ESTF_INAPPROP, NULL));
2108d8995facSha137994 
2109d8995facSha137994 	bp = id;
2110d8995facSha137994 
2111d8995facSha137994 	/*
2112d8995facSha137994 	 * We need to make sure all of the board's device nodes
2113d8995facSha137994 	 * have been removed from the Solaris device tree before
2114d8995facSha137994 	 * continuing with the disconnect. Otherwise, we could
2115d8995facSha137994 	 * disconnect the board and remove the OBP device tree
2116d8995facSha137994 	 * nodes with Solaris device tree nodes remaining.
2117d8995facSha137994 	 *
2118d8995facSha137994 	 * On Starfire, Solaris device tree nodes are deleted
2119d8995facSha137994 	 * during unconfigure by drmach_unconfigure(). It's
2120d8995facSha137994 	 * necessary to do this here because drmach_unconfigure()
2121d8995facSha137994 	 * failures are not handled during unconfigure.
2122d8995facSha137994 	 */
2123d8995facSha137994 	if (bp->devices) {
2124d8995facSha137994 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
2125d8995facSha137994 		while (rv == 0) {
2126d8995facSha137994 			err = drmach_unconfigure(d_id, DRMACH_DEVI_REMOVE);
2127d8995facSha137994 			if (err)
2128d8995facSha137994 				return (err);
2129d8995facSha137994 
2130d8995facSha137994 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
2131d8995facSha137994 		}
2132d8995facSha137994 	}
2133d8995facSha137994 
2134d8995facSha137994 	/*
2135d8995facSha137994 	 * Starfire board Solaris device tree counter nodes,
2136d8995facSha137994 	 * which are only present on start-of-day boards, are
2137d8995facSha137994 	 * removed in the dr_post_op() code flow after the
2138d8995facSha137994 	 * board is unconfigured. We call the counter node
2139d8995facSha137994 	 * removal function here because unconfigure errors
2140d8995facSha137994 	 * can cause the dr_post_op() function to be skipped
2141d8995facSha137994 	 * after an unconfigure operation even though all of
2142d8995facSha137994 	 * the board's devices have been transitioned to the
2143d8995facSha137994 	 * unconfigured state.
2144d8995facSha137994 	 */
2145d8995facSha137994 	err = drmach_remove_counter_nodes(id);
2146d8995facSha137994 	if (err)
2147d8995facSha137994 		return (err);
2148d8995facSha137994 
21497c478bd9Sstevel@tonic-gate 	return (NULL);
21507c478bd9Sstevel@tonic-gate }
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate static int
21537c478bd9Sstevel@tonic-gate drmach_board_find_devices_cb(drmach_node_walk_args_t *args)
21547c478bd9Sstevel@tonic-gate {
21557c478bd9Sstevel@tonic-gate 	drmach_node_t			*node = args->node;
21567c478bd9Sstevel@tonic-gate 	drmach_board_cb_data_t		*data = args->data;
21577c478bd9Sstevel@tonic-gate 	drmach_board_t			*obj = data->obj;
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	int		 rv;
21607c478bd9Sstevel@tonic-gate 	int		 bnum;
21617c478bd9Sstevel@tonic-gate 	drmach_device_t	*device;
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	rv = drmach_node_get_prop(node, OBP_BOARDNUM, &bnum);
21647c478bd9Sstevel@tonic-gate 	if (rv) {
21657c478bd9Sstevel@tonic-gate 		/*
21667c478bd9Sstevel@tonic-gate 		 * if the node does not have a board# property, then
21677c478bd9Sstevel@tonic-gate 		 * by that information alone it is known that drmach
21687c478bd9Sstevel@tonic-gate 		 * is not interested in it.
21697c478bd9Sstevel@tonic-gate 		 */
21707c478bd9Sstevel@tonic-gate 		return (0);
21717c478bd9Sstevel@tonic-gate 	} else if (bnum != obj->bnum)
21727c478bd9Sstevel@tonic-gate 		return (0);
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 	/*
21757c478bd9Sstevel@tonic-gate 	 * Create a device data structure from this node data.
21767c478bd9Sstevel@tonic-gate 	 * The call may yield nothing if the node is not of interest
21777c478bd9Sstevel@tonic-gate 	 * to drmach.
21787c478bd9Sstevel@tonic-gate 	 */
21797c478bd9Sstevel@tonic-gate 	data->err = drmach_device_new(node, obj, &device);
21807c478bd9Sstevel@tonic-gate 	if (data->err)
21817c478bd9Sstevel@tonic-gate 		return (-1);
21827c478bd9Sstevel@tonic-gate 	else if (device == NULL) {
21837c478bd9Sstevel@tonic-gate 		/*
21847c478bd9Sstevel@tonic-gate 		 * drmach_device_new examined the node we passed in
21857c478bd9Sstevel@tonic-gate 		 * and determined that it was one not of interest to
21867c478bd9Sstevel@tonic-gate 		 * drmach.  So, it is skipped.
21877c478bd9Sstevel@tonic-gate 		 */
21887c478bd9Sstevel@tonic-gate 		return (0);
21897c478bd9Sstevel@tonic-gate 	}
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	rv = drmach_array_set(obj->devices, data->ndevs++, device);
21927c478bd9Sstevel@tonic-gate 	if (rv) {
21937c478bd9Sstevel@tonic-gate 		drmach_device_dispose(device);
21947c478bd9Sstevel@tonic-gate 		data->err = DRMACH_INTERNAL_ERROR();
21957c478bd9Sstevel@tonic-gate 		return (-1);
21967c478bd9Sstevel@tonic-gate 	}
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 	data->err = (*data->found)(data->a, device->type, device->unum, device);
21997c478bd9Sstevel@tonic-gate 	return (data->err == NULL ? 0 : -1);
22007c478bd9Sstevel@tonic-gate }
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate sbd_error_t *
22037c478bd9Sstevel@tonic-gate drmach_board_find_devices(drmachid_t id, void *a,
22047c478bd9Sstevel@tonic-gate 	sbd_error_t *(*found)(void *a, const char *, int, drmachid_t))
22057c478bd9Sstevel@tonic-gate {
22067c478bd9Sstevel@tonic-gate 	extern int		 plat_max_cpu_units_per_board();
22077c478bd9Sstevel@tonic-gate 	extern int		 plat_max_mem_units_per_board();
22087c478bd9Sstevel@tonic-gate 	extern int		 plat_max_io_units_per_board();
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 	drmach_board_t		*obj = (drmach_board_t *)id;
22117c478bd9Sstevel@tonic-gate 	sbd_error_t		*err;
22127c478bd9Sstevel@tonic-gate 	int			 max_devices;
22137c478bd9Sstevel@tonic-gate 	int			 rv;
22147c478bd9Sstevel@tonic-gate 	drmach_board_cb_data_t	data;
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 	max_devices  = plat_max_cpu_units_per_board();
22177c478bd9Sstevel@tonic-gate 	max_devices += plat_max_mem_units_per_board();
22187c478bd9Sstevel@tonic-gate 	max_devices += plat_max_io_units_per_board();
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	obj->devices = drmach_array_new(0, max_devices);
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 	data.obj = obj;
22237c478bd9Sstevel@tonic-gate 	data.ndevs = 0;
22247c478bd9Sstevel@tonic-gate 	data.found = found;
22257c478bd9Sstevel@tonic-gate 	data.a = a;
22267c478bd9Sstevel@tonic-gate 	data.err = NULL;
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 	rv = drmach_node_walk(obj->tree, &data, drmach_board_find_devices_cb);
22297c478bd9Sstevel@tonic-gate 	if (rv == 0)
22307c478bd9Sstevel@tonic-gate 		err = NULL;
22317c478bd9Sstevel@tonic-gate 	else {
22327c478bd9Sstevel@tonic-gate 		drmach_array_dispose(obj->devices, drmach_device_dispose);
22337c478bd9Sstevel@tonic-gate 		obj->devices = NULL;
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate 		if (data.err)
22367c478bd9Sstevel@tonic-gate 			err = data.err;
22377c478bd9Sstevel@tonic-gate 		else
22387c478bd9Sstevel@tonic-gate 			err = DRMACH_INTERNAL_ERROR();
22397c478bd9Sstevel@tonic-gate 	}
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	return (err);
22427c478bd9Sstevel@tonic-gate }
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate int
22457c478bd9Sstevel@tonic-gate drmach_board_lookup(int bnum, drmachid_t *id)
22467c478bd9Sstevel@tonic-gate {
22477c478bd9Sstevel@tonic-gate 	int	rv = 0;
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	if (!drmach_initialized && drmach_init() == -1) {
22507c478bd9Sstevel@tonic-gate 		*id = 0;
22517c478bd9Sstevel@tonic-gate 		rv = -1;
22527c478bd9Sstevel@tonic-gate 	} else if (drmach_array_get(drmach_boards, bnum, id)) {
22537c478bd9Sstevel@tonic-gate 		*id = 0;
22547c478bd9Sstevel@tonic-gate 		rv = -1;
22557c478bd9Sstevel@tonic-gate 	}
22567c478bd9Sstevel@tonic-gate 	return (rv);
22577c478bd9Sstevel@tonic-gate }
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate sbd_error_t *
22607c478bd9Sstevel@tonic-gate drmach_board_name(int bnum, char *buf, int buflen)
22617c478bd9Sstevel@tonic-gate {
226207d06da5SSurya Prakki 	(void) snprintf(buf, buflen, "SB%d", bnum);
22637c478bd9Sstevel@tonic-gate 	return (NULL);
22647c478bd9Sstevel@tonic-gate }
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate sbd_error_t *
22677c478bd9Sstevel@tonic-gate drmach_board_poweroff(drmachid_t id)
22687c478bd9Sstevel@tonic-gate {
22697c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
22707c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
22717c478bd9Sstevel@tonic-gate 	drmach_status_t	 stat;
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
22747c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
22757c478bd9Sstevel@tonic-gate 	bp = id;
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	err = drmach_board_status(id, &stat);
22787c478bd9Sstevel@tonic-gate 	if (err)
22797c478bd9Sstevel@tonic-gate 		return (err);
22807c478bd9Sstevel@tonic-gate 	else if (stat.configured || stat.busy)
22817c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name));
22827c478bd9Sstevel@tonic-gate 	else {
22837c478bd9Sstevel@tonic-gate 		/* board power off is essentially a noop for Starfire */
22847c478bd9Sstevel@tonic-gate 		bp->powered = 0;
22857c478bd9Sstevel@tonic-gate 		return (NULL);
22867c478bd9Sstevel@tonic-gate 	}
22877c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
22887c478bd9Sstevel@tonic-gate }
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate sbd_error_t *
22917c478bd9Sstevel@tonic-gate drmach_board_poweron(drmachid_t id)
22927c478bd9Sstevel@tonic-gate {
22937c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
22967c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
22977c478bd9Sstevel@tonic-gate 	bp = id;
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 	/* board power on is essentially a noop for Starfire */
23007c478bd9Sstevel@tonic-gate 	bp->powered = 1;
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	return (NULL);
23037c478bd9Sstevel@tonic-gate }
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate static sbd_error_t *
23067c478bd9Sstevel@tonic-gate drmach_board_release(drmachid_t id)
23077c478bd9Sstevel@tonic-gate {
23087c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
23097c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
23107c478bd9Sstevel@tonic-gate 	return (NULL);
23117c478bd9Sstevel@tonic-gate }
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
23147c478bd9Sstevel@tonic-gate sbd_error_t *
23157c478bd9Sstevel@tonic-gate drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force)
23167c478bd9Sstevel@tonic-gate {
23177c478bd9Sstevel@tonic-gate 	return (NULL);
23187c478bd9Sstevel@tonic-gate }
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate sbd_error_t *
23217c478bd9Sstevel@tonic-gate drmach_board_unassign(drmachid_t id)
23227c478bd9Sstevel@tonic-gate {
23237c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
23247c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
23257c478bd9Sstevel@tonic-gate 	drmach_status_t	 stat;
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
23287c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
23297c478bd9Sstevel@tonic-gate 	bp = id;
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate 	err = drmach_board_status(id, &stat);
23327c478bd9Sstevel@tonic-gate 	if (err)
23337c478bd9Sstevel@tonic-gate 		return (err);
23347c478bd9Sstevel@tonic-gate 	else if (stat.configured || stat.busy)
23357c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_CONFIGBUSY, bp->cm.name));
23367c478bd9Sstevel@tonic-gate 	else if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0)
23377c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
23387c478bd9Sstevel@tonic-gate 	else {
23397c478bd9Sstevel@tonic-gate 		drmach_board_dispose(bp);
23407c478bd9Sstevel@tonic-gate 		return (NULL);
23417c478bd9Sstevel@tonic-gate 	}
23427c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
23437c478bd9Sstevel@tonic-gate }
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate static sbd_error_t *
23467c478bd9Sstevel@tonic-gate drmach_cpu_new(drmach_device_t *dp)
23477c478bd9Sstevel@tonic-gate {
23487c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
23497c478bd9Sstevel@tonic-gate 	int		 portid;
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 	err = drmach_device_get_prop(dp, "upa-portid", &portid);
23527c478bd9Sstevel@tonic-gate 	if (err == NULL)
23537c478bd9Sstevel@tonic-gate 		dp->unum = portid & 3;
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_cpu_new;
23567c478bd9Sstevel@tonic-gate 	dp->cm.release = drmach_cpu_release;
23577c478bd9Sstevel@tonic-gate 	dp->cm.status = drmach_cpu_status;
23587c478bd9Sstevel@tonic-gate 
235907d06da5SSurya Prakki 	(void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s%d", dp->type,
236007d06da5SSurya Prakki 	    dp->unum);
23617c478bd9Sstevel@tonic-gate 
23627c478bd9Sstevel@tonic-gate 	return (err);
23637c478bd9Sstevel@tonic-gate }
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate /*
23667c478bd9Sstevel@tonic-gate  * drmach_cpu_obp_detach()
23677c478bd9Sstevel@tonic-gate  *  This requires two steps, first, we must put the cpuid into the OBP
23687c478bd9Sstevel@tonic-gate  *  idle loop (Idle in Program) state.  Then we call OBP to place the CPU
23697c478bd9Sstevel@tonic-gate  *  into the "Detached" state, which does any special processing to
23707c478bd9Sstevel@tonic-gate  *  actually detach the cpu, such as flushing ecache, and also ensures
23717c478bd9Sstevel@tonic-gate  *  that a subsequent breakpoint won't restart the cpu (if it was just in
23727c478bd9Sstevel@tonic-gate  *  Idle in Program state).
23737c478bd9Sstevel@tonic-gate  */
23747c478bd9Sstevel@tonic-gate static void
23757c478bd9Sstevel@tonic-gate drmach_cpu_obp_detach(int cpuid)
23767c478bd9Sstevel@tonic-gate {
23777c478bd9Sstevel@tonic-gate 	/*
23787c478bd9Sstevel@tonic-gate 	 * Cpu may not be under OBP's control. Eg, if cpu exited to download
23797c478bd9Sstevel@tonic-gate 	 * helper on a prior attach.
23807c478bd9Sstevel@tonic-gate 	 */
23817c478bd9Sstevel@tonic-gate 	if (CPU_SGN_EXISTS(cpuid) &&
23827c478bd9Sstevel@tonic-gate 	    !SGN_CPU_IS_OS(cpuid) &&
23837c478bd9Sstevel@tonic-gate 	    !SGN_CPU_IS_OBP(cpuid)) {
23847c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
23857c478bd9Sstevel@tonic-gate 		    "unexpected signature (0x%x) for cpu %d",
23867c478bd9Sstevel@tonic-gate 		    get_cpu_sgn(cpuid), cpuid);
23877c478bd9Sstevel@tonic-gate 	}
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 	/*
23907c478bd9Sstevel@tonic-gate 	 * Now we place the CPU into the "Detached" idle loop in OBP.
23917c478bd9Sstevel@tonic-gate 	 * This is so that the CPU won't be restarted if we break into
23927c478bd9Sstevel@tonic-gate 	 * OBP with a breakpoint or BREAK key from the console, and also
23937c478bd9Sstevel@tonic-gate 	 * if we need to do any special processing, such as flushing the
23947c478bd9Sstevel@tonic-gate 	 * cpu's ecache, disabling interrupts (by turning of the ET bit in
23957c478bd9Sstevel@tonic-gate 	 * the PSR) and/or spinning in BBSRAM rather than global memory.
23967c478bd9Sstevel@tonic-gate 	 */
23977c478bd9Sstevel@tonic-gate 	DRMACH_PR("prom_starfire_rm_cpu(%d)\n", cpuid);
23987c478bd9Sstevel@tonic-gate 	prom_starfire_rm_cpu(cpuid);
23997c478bd9Sstevel@tonic-gate }
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate /*
24027c478bd9Sstevel@tonic-gate  * drmach_cpu_obp_is_detached() returns TRUE if the cpu sigblock signature state
24037c478bd9Sstevel@tonic-gate  * is SIGBST_DETACHED; otherwise it returns FALSE. This routine should only
24047c478bd9Sstevel@tonic-gate  * be called after we have asked OBP to detach the CPU. It should NOT be
24057c478bd9Sstevel@tonic-gate  * called as a check during any other flow.
24067c478bd9Sstevel@tonic-gate  */
24077c478bd9Sstevel@tonic-gate static int
24087c478bd9Sstevel@tonic-gate drmach_cpu_obp_is_detached(int cpuid)
24097c478bd9Sstevel@tonic-gate {
24107c478bd9Sstevel@tonic-gate 	if (!CPU_SGN_EXISTS(cpuid) ||
24117c478bd9Sstevel@tonic-gate 	    (SGN_CPU_IS_OS(cpuid) && SGN_CPU_STATE_IS_DETACHED(cpuid)))
24127c478bd9Sstevel@tonic-gate 		return (1);
24137c478bd9Sstevel@tonic-gate 	else
24147c478bd9Sstevel@tonic-gate 		return (0);
24157c478bd9Sstevel@tonic-gate }
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate static int
24187c478bd9Sstevel@tonic-gate drmach_cpu_start(struct cpu *cp)
24197c478bd9Sstevel@tonic-gate {
24207c478bd9Sstevel@tonic-gate 	int		cpuid = cp->cpu_id;
24217c478bd9Sstevel@tonic-gate 	int		ntries = drmach_cpu_ntries;
24227c478bd9Sstevel@tonic-gate 	extern void	restart_other_cpu(int);
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
2425fa9e4066Sahrens 	ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0);
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	cp->cpu_flags &= ~CPU_POWEROFF;
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate 	/*
24307c478bd9Sstevel@tonic-gate 	 * NOTE: restart_other_cpu pauses cpus during the
24317c478bd9Sstevel@tonic-gate 	 *	 slave cpu start.  This helps to quiesce the
24327c478bd9Sstevel@tonic-gate 	 *	 bus traffic a bit which makes the tick sync
24337c478bd9Sstevel@tonic-gate 	 *	 routine in the prom more robust.
24347c478bd9Sstevel@tonic-gate 	 */
24357c478bd9Sstevel@tonic-gate 	DRMACH_PR("COLD START for cpu (%d)\n", cpuid);
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate 	prom_starfire_add_cpu(cpuid);
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 	restart_other_cpu(cpuid);
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate 	/*
24427c478bd9Sstevel@tonic-gate 	 * Wait for the cpu to reach its idle thread before
24437c478bd9Sstevel@tonic-gate 	 * we zap him with a request to blow away the mappings
24447c478bd9Sstevel@tonic-gate 	 * he (might) have for the drmach_shutdown_asm code
24457c478bd9Sstevel@tonic-gate 	 * he may have executed on unconfigure.
24467c478bd9Sstevel@tonic-gate 	 */
24477c478bd9Sstevel@tonic-gate 	while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) {
24487c478bd9Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
24497c478bd9Sstevel@tonic-gate 		ntries--;
24507c478bd9Sstevel@tonic-gate 	}
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	DRMACH_PR("waited %d out of %d loops for cpu %d\n",
24537c478bd9Sstevel@tonic-gate 	    drmach_cpu_ntries - ntries, drmach_cpu_ntries, cpuid);
24547c478bd9Sstevel@tonic-gate 
24557c478bd9Sstevel@tonic-gate 	xt_one(cpuid, vtag_flushpage_tl1,
24561e2e7a75Shuah 	    (uint64_t)drmach_shutdown_va, (uint64_t)ksfmmup);
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 	return (0);
24597c478bd9Sstevel@tonic-gate }
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate /*
24627c478bd9Sstevel@tonic-gate  * A detaching CPU is xcalled with an xtrap to drmach_cpu_stop_self() after
24637c478bd9Sstevel@tonic-gate  * it has been offlined. The function of this routine is to get the cpu
24647c478bd9Sstevel@tonic-gate  * spinning in a safe place. The requirement is that the system will not
24657c478bd9Sstevel@tonic-gate  * reference anything on the detaching board (memory and i/o is detached
24667c478bd9Sstevel@tonic-gate  * elsewhere) and that the CPU not reference anything on any other board
24677c478bd9Sstevel@tonic-gate  * in the system.  This isolation is required during and after the writes
24687c478bd9Sstevel@tonic-gate  * to the domain masks to remove the board from the domain.
24697c478bd9Sstevel@tonic-gate  *
24707c478bd9Sstevel@tonic-gate  * To accomplish this isolation the following is done:
24717c478bd9Sstevel@tonic-gate  *	1) Create a locked mapping to a location in BBSRAM where
24727c478bd9Sstevel@tonic-gate  *	   the cpu will execute.
24737c478bd9Sstevel@tonic-gate  *	2) Copy the target function (drmach_shutdown_asm) in which
24747c478bd9Sstevel@tonic-gate  *	   the cpu will execute into BBSRAM.
24757c478bd9Sstevel@tonic-gate  *	3) Jump into function with BBSRAM.
24767c478bd9Sstevel@tonic-gate  *	   Function will:
24777c478bd9Sstevel@tonic-gate  *	   3.1) Flush its Ecache (displacement).
24787c478bd9Sstevel@tonic-gate  *	   3.2) Flush its Dcache with HW mechanism.
24797c478bd9Sstevel@tonic-gate  *	   3.3) Flush its Icache with HW mechanism.
24807c478bd9Sstevel@tonic-gate  *	   3.4) Flush all valid and _unlocked_ D-TLB entries.
24817c478bd9Sstevel@tonic-gate  *	   3.5) Flush all valid and _unlocked_ I-TLB entries.
24827c478bd9Sstevel@tonic-gate  *	   3.6) Clear xt_mb to signal completion. Note: cache line is
24837c478bd9Sstevel@tonic-gate  *		recovered by drmach_cpu_poweroff().
24847c478bd9Sstevel@tonic-gate  *	4) Jump into a tight loop.
24857c478bd9Sstevel@tonic-gate  */
24867c478bd9Sstevel@tonic-gate #define	DRMACH_BBSRAM_OFFSET	0x1000
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate static void
24897c478bd9Sstevel@tonic-gate drmach_cpu_stop_self(void)
24907c478bd9Sstevel@tonic-gate {
24917c478bd9Sstevel@tonic-gate 	int		cpuid = (int)CPU->cpu_id;
24927c478bd9Sstevel@tonic-gate 	tte_t		tte;
24937c478bd9Sstevel@tonic-gate 	volatile uint_t	*src, *dst;
2494*e0731422SRichard Lowe 	size_t		funclen;
24957c478bd9Sstevel@tonic-gate 	uint64_t	bbsram_pa, bbsram_offset;
24967c478bd9Sstevel@tonic-gate 	uint_t		bbsram_pfn;
24977c478bd9Sstevel@tonic-gate 	uint64_t	bbsram_addr;
24987c478bd9Sstevel@tonic-gate 	void		(*bbsram_func)(uint64_t);
24997c478bd9Sstevel@tonic-gate 	extern void	drmach_shutdown_asm(uint64_t);
25007c478bd9Sstevel@tonic-gate 	extern void	drmach_shutdown_asm_end(void);
25017c478bd9Sstevel@tonic-gate 
2502*e0731422SRichard Lowe 	funclen = (uintptr_t)drmach_shutdown_asm_end -
2503*e0731422SRichard Lowe 	    (uintptr_t)drmach_shutdown_asm;
25047c478bd9Sstevel@tonic-gate 	ASSERT(funclen <= MMU_PAGESIZE);
25057c478bd9Sstevel@tonic-gate 	/*
25067c478bd9Sstevel@tonic-gate 	 * We'll start from the 0th's base.
25077c478bd9Sstevel@tonic-gate 	 */
25087c478bd9Sstevel@tonic-gate 	bbsram_pa = STARFIRE_UPAID2UPS(cpuid) | STARFIRE_PSI_BASE;
25097c478bd9Sstevel@tonic-gate 	bbsram_offset = bbsram_pa | 0xfe0ULL;
25107c478bd9Sstevel@tonic-gate 	bbsram_pa += ldphysio(bbsram_offset) + DRMACH_BBSRAM_OFFSET;
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 	bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT);
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	bbsram_addr = (uint64_t)drmach_shutdown_va;
2515*e0731422SRichard Lowe 	drmach_shutdown_asm_mbox->estack = bbsram_addr + funclen;
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate 	tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) |
25187c478bd9Sstevel@tonic-gate 	    TTE_PFN_INTHI(bbsram_pfn);
25197c478bd9Sstevel@tonic-gate 	tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) |
25207c478bd9Sstevel@tonic-gate 	    TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT;
25211e2e7a75Shuah 	sfmmu_dtlb_ld_kva(drmach_shutdown_va, &tte);	/* load dtlb */
25221e2e7a75Shuah 	sfmmu_itlb_ld_kva(drmach_shutdown_va, &tte);	/* load itlb */
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	for (src = (uint_t *)drmach_shutdown_asm, dst = (uint_t *)bbsram_addr;
25257c478bd9Sstevel@tonic-gate 	    src < (uint_t *)drmach_shutdown_asm_end; src++, dst++)
25267c478bd9Sstevel@tonic-gate 		*dst = *src;
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate 	bbsram_func = (void (*)())bbsram_addr;
25297c478bd9Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->flushaddr = ecache_flushaddr;
25307c478bd9Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->size = (cpunodes[cpuid].ecache_size << 1);
25317c478bd9Sstevel@tonic-gate 	drmach_shutdown_asm_mbox->linesize = cpunodes[cpuid].ecache_linesize;
253256f33205SJonathan Adams 	drmach_shutdown_asm_mbox->physaddr =
253356f33205SJonathan Adams 	    va_to_pa((void *)&drmach_xt_mb[cpuid]);
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 	/*
25367c478bd9Sstevel@tonic-gate 	 * Signal to drmach_cpu_poweroff() is via drmach_xt_mb cleared
25377c478bd9Sstevel@tonic-gate 	 * by asm code
25387c478bd9Sstevel@tonic-gate 	 */
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	(*bbsram_func)(va_to_pa((void *)drmach_shutdown_asm_mbox));
25417c478bd9Sstevel@tonic-gate }
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate static void
25447c478bd9Sstevel@tonic-gate drmach_cpu_shutdown_self(void)
25457c478bd9Sstevel@tonic-gate {
25467c478bd9Sstevel@tonic-gate 	cpu_t		*cp = CPU;
25477c478bd9Sstevel@tonic-gate 	int		cpuid = cp->cpu_id;
25487c478bd9Sstevel@tonic-gate 	extern void	flush_windows(void);
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	flush_windows();
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate 	(void) spl8();
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	ASSERT(cp->cpu_intr_actv == 0);
25559d7041eeSandrei 	ASSERT(cp->cpu_thread == cp->cpu_idle_thread ||
25569d7041eeSandrei 	    cp->cpu_thread == cp->cpu_startup_thread);
25577c478bd9Sstevel@tonic-gate 
25587c478bd9Sstevel@tonic-gate 	cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	drmach_cpu_stop_self();
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate 	cmn_err(CE_PANIC, "CPU %d FAILED TO SHUTDOWN", cpuid);
25637c478bd9Sstevel@tonic-gate }
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate /* a helper routine to keep the math in one place */
25667c478bd9Sstevel@tonic-gate static processorid_t
25677c478bd9Sstevel@tonic-gate drmach_cpu_calc_id(drmach_device_t *dp)
25687c478bd9Sstevel@tonic-gate {
25697c478bd9Sstevel@tonic-gate 	return (dp->bp->bnum * MAX_CPU_UNITS_PER_BOARD + dp->unum);
25707c478bd9Sstevel@tonic-gate }
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate /*
25737c478bd9Sstevel@tonic-gate  * Move bootproc (SIGBCPU) to another cpu.  If dst_cpu is NULL, a
25747c478bd9Sstevel@tonic-gate  * destination cpu is chosen from the set of cpus not located on the
25757c478bd9Sstevel@tonic-gate  * same board as the current bootproc cpu.
25767c478bd9Sstevel@tonic-gate  */
25777c478bd9Sstevel@tonic-gate static sbd_error_t *
25787c478bd9Sstevel@tonic-gate drmach_cpu_juggle_bootproc(drmach_device_t *dst_cpu)
25797c478bd9Sstevel@tonic-gate {
25807c478bd9Sstevel@tonic-gate 	processorid_t	 cpuid;
25817c478bd9Sstevel@tonic-gate 	struct cpu	*cp;
25827c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
25837c478bd9Sstevel@tonic-gate 	int		 rv;
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
25867c478bd9Sstevel@tonic-gate 
25877c478bd9Sstevel@tonic-gate 	/* dst_cpu is NULL when target cpu is unspecified. So, pick one. */
25887c478bd9Sstevel@tonic-gate 	if (dst_cpu == NULL) {
25897c478bd9Sstevel@tonic-gate 		int avoid_board = DRMACH_CPUID2BNUM(SIGBCPU->cpu_id);
25907c478bd9Sstevel@tonic-gate 		int max_cpuid = MAX_BOARDS * MAX_CPU_UNITS_PER_BOARD;
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 		for (cpuid = 0; cpuid < max_cpuid; cpuid++)
25937c478bd9Sstevel@tonic-gate 			if (DRMACH_CPUID2BNUM(cpuid) != avoid_board) {
25947c478bd9Sstevel@tonic-gate 				cp = cpu_get(cpuid);
25957c478bd9Sstevel@tonic-gate 				if (cp != NULL && cpu_is_online(cp))
25967c478bd9Sstevel@tonic-gate 					break;
25977c478bd9Sstevel@tonic-gate 			}
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate 		if (cpuid == max_cpuid) {
26007c478bd9Sstevel@tonic-gate 			err = drerr_new(1, ESTF_JUGGLE, NULL);
26017c478bd9Sstevel@tonic-gate 			return (err);
26027c478bd9Sstevel@tonic-gate 		}
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 		/* else, cp points to the selected target cpu */
26057c478bd9Sstevel@tonic-gate 	} else {
26067c478bd9Sstevel@tonic-gate 		cpuid = drmach_cpu_calc_id(dst_cpu);
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 		if ((cp = cpu_get(cpuid)) == NULL) {
26097c478bd9Sstevel@tonic-gate 			err = drerr_new(1, ESTF_NODEV, "%s::%s",
26107c478bd9Sstevel@tonic-gate 			    dst_cpu->bp->cm.name, dst_cpu->cm.name);
26117c478bd9Sstevel@tonic-gate 			return (err);
26127c478bd9Sstevel@tonic-gate 		}
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate 		if (cpuid == SIGBCPU->cpu_id) {
26157c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
26167c478bd9Sstevel@tonic-gate 			    "SIGBCPU(%d) same as new selection(%d)",
26177c478bd9Sstevel@tonic-gate 			    SIGBCPU->cpu_id, cpuid);
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 			/* technically not an error, but a no-op */
26207c478bd9Sstevel@tonic-gate 			return (NULL);
26217c478bd9Sstevel@tonic-gate 		}
26227c478bd9Sstevel@tonic-gate 	}
26237c478bd9Sstevel@tonic-gate 
26247c478bd9Sstevel@tonic-gate 	cmn_err(CE_NOTE, "?relocating SIGBCPU from %d to %d",
26257c478bd9Sstevel@tonic-gate 	    SIGBCPU->cpu_id, cpuid);
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 	DRMACH_PR("moving SIGBCPU to CPU %d\n", cpuid);
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate 	/*
26307c478bd9Sstevel@tonic-gate 	 * Tell OBP to initialize cvc-offset field of new CPU0
26317c478bd9Sstevel@tonic-gate 	 * so that it's in sync with OBP and cvc_server
26327c478bd9Sstevel@tonic-gate 	 */
26337c478bd9Sstevel@tonic-gate 	prom_starfire_init_console(cpuid);
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	/*
26367c478bd9Sstevel@tonic-gate 	 * Assign cvc to new cpu0's bbsram for I/O.  This has to be
26377c478bd9Sstevel@tonic-gate 	 * done BEFORE cpu0 is moved via obp, since this logic
26387c478bd9Sstevel@tonic-gate 	 * will cause obp_helper to switch to a different bbsram for
26397c478bd9Sstevel@tonic-gate 	 * cvc I/O.  We don't want cvc writing to a buffer from which
26407c478bd9Sstevel@tonic-gate 	 * nobody will pick up the data!
26417c478bd9Sstevel@tonic-gate 	 */
26427c478bd9Sstevel@tonic-gate 	cvc_assign_iocpu(cpuid);
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 	rv = prom_starfire_move_cpu0(cpuid);
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 	if (rv == 0) {
26477c478bd9Sstevel@tonic-gate 		SIGBCPU = cp;
26487c478bd9Sstevel@tonic-gate 
26497c478bd9Sstevel@tonic-gate 		DRMACH_PR("successfully juggled to CPU %d\n", cpuid);
26507c478bd9Sstevel@tonic-gate 		return (NULL);
26517c478bd9Sstevel@tonic-gate 	} else {
26527c478bd9Sstevel@tonic-gate 		DRMACH_PR("prom error: prom_starfire_move_cpu0(%d) "
26537c478bd9Sstevel@tonic-gate 		    "returned %d\n", cpuid, rv);
26547c478bd9Sstevel@tonic-gate 
26557c478bd9Sstevel@tonic-gate 		/*
26567c478bd9Sstevel@tonic-gate 		 * The move failed, hopefully obp_helper is still back
26577c478bd9Sstevel@tonic-gate 		 * at the old bootproc.  Move cvc back there.
26587c478bd9Sstevel@tonic-gate 		 */
26597c478bd9Sstevel@tonic-gate 		cvc_assign_iocpu(SIGBCPU->cpu_id);
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate 		err = drerr_new(1, ESTF_MOVESIGB, "CPU %d", cpuid);
26637c478bd9Sstevel@tonic-gate 		return (err);
26647c478bd9Sstevel@tonic-gate 	}
26657c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
26667c478bd9Sstevel@tonic-gate }
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate static sbd_error_t *
26697c478bd9Sstevel@tonic-gate drmach_cpu_release(drmachid_t id)
26707c478bd9Sstevel@tonic-gate {
26717c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
26727c478bd9Sstevel@tonic-gate 	processorid_t	 cpuid;
26737c478bd9Sstevel@tonic-gate 	struct cpu	*cp;
26747c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
26777c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
26787c478bd9Sstevel@tonic-gate 	dp = id;
26797c478bd9Sstevel@tonic-gate 	cpuid = drmach_cpu_calc_id(dp);
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
26827c478bd9Sstevel@tonic-gate 
26837c478bd9Sstevel@tonic-gate 	cp = cpu_get(cpuid);
26847c478bd9Sstevel@tonic-gate 	if (cp == NULL)
26857c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
26867c478bd9Sstevel@tonic-gate 	else if (SIGBCPU->cpu_id == cp->cpu_id)
26877c478bd9Sstevel@tonic-gate 		err = drmach_cpu_juggle_bootproc(NULL);
26887c478bd9Sstevel@tonic-gate 	else
26897c478bd9Sstevel@tonic-gate 		err = NULL;
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate 	return (err);
26927c478bd9Sstevel@tonic-gate }
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate static sbd_error_t *
26957c478bd9Sstevel@tonic-gate drmach_cpu_status(drmachid_t id, drmach_status_t *stat)
26967c478bd9Sstevel@tonic-gate {
26977c478bd9Sstevel@tonic-gate 	drmach_device_t *dp;
26987c478bd9Sstevel@tonic-gate 
26997c478bd9Sstevel@tonic-gate 	ASSERT(DRMACH_IS_CPU_ID(id));
27007c478bd9Sstevel@tonic-gate 	dp = id;
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
27037c478bd9Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
27047c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
27057c478bd9Sstevel@tonic-gate 	stat->configured = (cpu_get(drmach_cpu_calc_id(dp)) != NULL);
27067c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
27077c478bd9Sstevel@tonic-gate 	stat->busy = dp->busy;
270807d06da5SSurya Prakki 	(void) strncpy(stat->type, dp->type, sizeof (stat->type));
27097c478bd9Sstevel@tonic-gate 	stat->info[0] = '\0';
27107c478bd9Sstevel@tonic-gate 
27117c478bd9Sstevel@tonic-gate 	return (NULL);
27127c478bd9Sstevel@tonic-gate }
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate sbd_error_t *
27157c478bd9Sstevel@tonic-gate drmach_cpu_disconnect(drmachid_t id)
27167c478bd9Sstevel@tonic-gate {
27177c478bd9Sstevel@tonic-gate 	drmach_device_t	*cpu;
27187c478bd9Sstevel@tonic-gate 	int		 cpuid;
27197c478bd9Sstevel@tonic-gate 	int		 ntries;
27207c478bd9Sstevel@tonic-gate 	int		 p;
27217c478bd9Sstevel@tonic-gate 	u_longlong_t	 pc_addr;
27227c478bd9Sstevel@tonic-gate 	uchar_t		 rvalue;
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
27257c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
27267c478bd9Sstevel@tonic-gate 	cpu = id;
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate 	cpuid = drmach_cpu_calc_id(cpu);
27297c478bd9Sstevel@tonic-gate 	if (SIGBCPU->cpu_id == cpuid) {
27307c478bd9Sstevel@tonic-gate 		/* this cpu is SIGBCPU, can't disconnect */
27317c478bd9Sstevel@tonic-gate 		return (drerr_new(1, ESTF_HASSIGB, "%s::%s",
27327c478bd9Sstevel@tonic-gate 		    cpu->bp->cm.name, cpu->cm.name));
27337c478bd9Sstevel@tonic-gate 	}
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 	/*
27367c478bd9Sstevel@tonic-gate 	 * Make sure SIGBST_DETACHED is set before
27377c478bd9Sstevel@tonic-gate 	 * mapping out the sig block.
27387c478bd9Sstevel@tonic-gate 	 */
27397c478bd9Sstevel@tonic-gate 	ntries = drmach_cpu_ntries;
27407c478bd9Sstevel@tonic-gate 	while (!drmach_cpu_obp_is_detached(cpuid) && ntries) {
27417c478bd9Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
27427c478bd9Sstevel@tonic-gate 		ntries--;
27437c478bd9Sstevel@tonic-gate 	}
27447c478bd9Sstevel@tonic-gate 	if (!drmach_cpu_obp_is_detached(cpuid)) {
27457c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "failed to mark cpu %d detached in sigblock",
27467c478bd9Sstevel@tonic-gate 		    cpuid);
27477c478bd9Sstevel@tonic-gate 	}
27487c478bd9Sstevel@tonic-gate 
27497c478bd9Sstevel@tonic-gate 	/* map out signature block */
27507c478bd9Sstevel@tonic-gate 	if (CPU_SGN_EXISTS(cpuid)) {
27517c478bd9Sstevel@tonic-gate 		CPU_SGN_MAPOUT(cpuid);
27527c478bd9Sstevel@tonic-gate 	}
27537c478bd9Sstevel@tonic-gate 
27547c478bd9Sstevel@tonic-gate 	/*
27557c478bd9Sstevel@tonic-gate 	 * We now PC IDLE the processor to guarantee we
27567c478bd9Sstevel@tonic-gate 	 * stop any transactions from coming from it.
27577c478bd9Sstevel@tonic-gate 	 */
27587c478bd9Sstevel@tonic-gate 	p = cpu->unum & 1;
27597c478bd9Sstevel@tonic-gate 	pc_addr = STARFIRE_BB_PC_ADDR(cpu->bp->bnum, cpu->unum, 0);
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 	DRMACH_PR("PC idle cpu %d (addr = 0x%llx, port = %d, p = %d)",
27627c478bd9Sstevel@tonic-gate 	    drmach_cpu_calc_id(cpu), pc_addr, cpu->unum, p);
27637c478bd9Sstevel@tonic-gate 
27647c478bd9Sstevel@tonic-gate 	rvalue = ldbphysio(pc_addr);
27657c478bd9Sstevel@tonic-gate 	rvalue |= STARFIRE_BB_PC_IDLE(p);
27667c478bd9Sstevel@tonic-gate 	stbphysio(pc_addr, rvalue);
27677c478bd9Sstevel@tonic-gate 	DELAY(50000);
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate 	return (NULL);
27707c478bd9Sstevel@tonic-gate }
27717c478bd9Sstevel@tonic-gate 
27727c478bd9Sstevel@tonic-gate sbd_error_t *
27737c478bd9Sstevel@tonic-gate drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid)
27747c478bd9Sstevel@tonic-gate {
27757c478bd9Sstevel@tonic-gate 	drmach_device_t *cpu;
27767c478bd9Sstevel@tonic-gate 
27777c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
27787c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
27797c478bd9Sstevel@tonic-gate 	cpu = id;
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 	*cpuid = drmach_cpu_calc_id(cpu);
27827c478bd9Sstevel@tonic-gate 	return (NULL);
27837c478bd9Sstevel@tonic-gate }
27847c478bd9Sstevel@tonic-gate 
27857c478bd9Sstevel@tonic-gate sbd_error_t *
27867c478bd9Sstevel@tonic-gate drmach_cpu_get_impl(drmachid_t id, int *ip)
27877c478bd9Sstevel@tonic-gate {
27887c478bd9Sstevel@tonic-gate 	drmach_device_t *cpu;
27897c478bd9Sstevel@tonic-gate 	int		impl;
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
27927c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate 	cpu = id;
27957c478bd9Sstevel@tonic-gate 
27967c478bd9Sstevel@tonic-gate 	if (drmach_node_get_prop(cpu->node, "implementation#", &impl) == -1) {
27977c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
27987c478bd9Sstevel@tonic-gate 	}
27997c478bd9Sstevel@tonic-gate 
28007c478bd9Sstevel@tonic-gate 	*ip = impl;
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 	return (NULL);
28037c478bd9Sstevel@tonic-gate }
28047c478bd9Sstevel@tonic-gate 
28057c478bd9Sstevel@tonic-gate void
28067c478bd9Sstevel@tonic-gate drmach_cpu_flush_ecache_sync(void)
28077c478bd9Sstevel@tonic-gate {
28087c478bd9Sstevel@tonic-gate 	ASSERT(curthread->t_bound_cpu == CPU);
28097c478bd9Sstevel@tonic-gate 
28107c478bd9Sstevel@tonic-gate 	/*
28117c478bd9Sstevel@tonic-gate 	 * Now let's flush our ecache thereby removing all references
28127c478bd9Sstevel@tonic-gate 	 * to the target (detaching) memory from all ecache's in
28137c478bd9Sstevel@tonic-gate 	 * system.
28147c478bd9Sstevel@tonic-gate 	 */
28157c478bd9Sstevel@tonic-gate 	cpu_flush_ecache();
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	/*
28187c478bd9Sstevel@tonic-gate 	 * Delay 100 usec out of paranoia to insure everything
28197c478bd9Sstevel@tonic-gate 	 * (hardware queues) has drained before we start reprogramming
28207c478bd9Sstevel@tonic-gate 	 * the hardware.
28217c478bd9Sstevel@tonic-gate 	 */
28227c478bd9Sstevel@tonic-gate 	DELAY(100);
28237c478bd9Sstevel@tonic-gate }
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate sbd_error_t *
28267c478bd9Sstevel@tonic-gate drmach_get_dip(drmachid_t id, dev_info_t **dip)
28277c478bd9Sstevel@tonic-gate {
28287c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
28317c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28327c478bd9Sstevel@tonic-gate 	dp = id;
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate 	*dip = drmach_node_get_dip(dp->node);
28357c478bd9Sstevel@tonic-gate 	return (NULL);
28367c478bd9Sstevel@tonic-gate }
28377c478bd9Sstevel@tonic-gate 
28387c478bd9Sstevel@tonic-gate sbd_error_t *
28397c478bd9Sstevel@tonic-gate drmach_io_is_attached(drmachid_t id, int *yes)
28407c478bd9Sstevel@tonic-gate {
28417c478bd9Sstevel@tonic-gate 	drmach_device_t *dp;
28427c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
28437c478bd9Sstevel@tonic-gate 	int		state;
28447c478bd9Sstevel@tonic-gate 
28457c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
28467c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28477c478bd9Sstevel@tonic-gate 	dp = id;
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 	dip = drmach_node_get_dip(dp->node);
28507c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
28517c478bd9Sstevel@tonic-gate 		*yes = 0;
28527c478bd9Sstevel@tonic-gate 		return (NULL);
28537c478bd9Sstevel@tonic-gate 	}
28547c478bd9Sstevel@tonic-gate 
28557c478bd9Sstevel@tonic-gate 	state = ddi_get_devstate(dip);
2856737d277aScth 	*yes = (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP));
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 	return (NULL);
28597c478bd9Sstevel@tonic-gate }
28607c478bd9Sstevel@tonic-gate 
28617c478bd9Sstevel@tonic-gate sbd_error_t *
28627c478bd9Sstevel@tonic-gate drmach_io_pre_release(drmachid_t id)
28637c478bd9Sstevel@tonic-gate {
28647c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
28657c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28667c478bd9Sstevel@tonic-gate 	return (NULL);
28677c478bd9Sstevel@tonic-gate }
28687c478bd9Sstevel@tonic-gate 
28697c478bd9Sstevel@tonic-gate static sbd_error_t *
28707c478bd9Sstevel@tonic-gate drmach_io_release(drmachid_t id)
28717c478bd9Sstevel@tonic-gate {
28727c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
28737c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28747c478bd9Sstevel@tonic-gate 	return (NULL);
28757c478bd9Sstevel@tonic-gate }
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate sbd_error_t *
28787c478bd9Sstevel@tonic-gate drmach_io_unrelease(drmachid_t id)
28797c478bd9Sstevel@tonic-gate {
28807c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_IO_ID(id))
28817c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
28827c478bd9Sstevel@tonic-gate 	return (NULL);
28837c478bd9Sstevel@tonic-gate }
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
28867c478bd9Sstevel@tonic-gate sbd_error_t *
28877c478bd9Sstevel@tonic-gate drmach_io_post_release(drmachid_t id)
28887c478bd9Sstevel@tonic-gate {
28897c478bd9Sstevel@tonic-gate 	return (NULL);
28907c478bd9Sstevel@tonic-gate }
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
28937c478bd9Sstevel@tonic-gate sbd_error_t *
28947c478bd9Sstevel@tonic-gate drmach_io_post_attach(drmachid_t id)
28957c478bd9Sstevel@tonic-gate {
28967c478bd9Sstevel@tonic-gate 	return (NULL);
28977c478bd9Sstevel@tonic-gate }
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate static sbd_error_t *
29007c478bd9Sstevel@tonic-gate drmach_io_status(drmachid_t id, drmach_status_t *stat)
29017c478bd9Sstevel@tonic-gate {
29027c478bd9Sstevel@tonic-gate 	drmach_device_t *dp;
29037c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
29047c478bd9Sstevel@tonic-gate 	int		 configured;
29057c478bd9Sstevel@tonic-gate 
29067c478bd9Sstevel@tonic-gate 	ASSERT(DRMACH_IS_IO_ID(id));
29077c478bd9Sstevel@tonic-gate 	dp = id;
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate 	err = drmach_io_is_attached(id, &configured);
29107c478bd9Sstevel@tonic-gate 	if (err)
29117c478bd9Sstevel@tonic-gate 		return (err);
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
29147c478bd9Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
29157c478bd9Sstevel@tonic-gate 	stat->configured = (configured != 0);
29167c478bd9Sstevel@tonic-gate 	stat->busy = dp->busy;
291707d06da5SSurya Prakki 	(void) strncpy(stat->type, dp->type, sizeof (stat->type));
29187c478bd9Sstevel@tonic-gate 	stat->info[0] = '\0';
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate 	return (NULL);
29217c478bd9Sstevel@tonic-gate }
29227c478bd9Sstevel@tonic-gate 
29237c478bd9Sstevel@tonic-gate static sbd_error_t *
29247c478bd9Sstevel@tonic-gate drmach_mem_new(drmach_device_t *dp)
29257c478bd9Sstevel@tonic-gate {
29267c478bd9Sstevel@tonic-gate 	dp->unum = 0;
29277c478bd9Sstevel@tonic-gate 	dp->cm.isa = (void *)drmach_mem_new;
29287c478bd9Sstevel@tonic-gate 	dp->cm.release = drmach_mem_release;
29297c478bd9Sstevel@tonic-gate 	dp->cm.status = drmach_mem_status;
29307c478bd9Sstevel@tonic-gate 
293107d06da5SSurya Prakki 	(void) snprintf(dp->cm.name, sizeof (dp->cm.name), "%s", dp->type);
29327c478bd9Sstevel@tonic-gate 
29337c478bd9Sstevel@tonic-gate 	return (NULL);
29347c478bd9Sstevel@tonic-gate }
29357c478bd9Sstevel@tonic-gate 
29367c478bd9Sstevel@tonic-gate sbd_error_t *
29377c478bd9Sstevel@tonic-gate drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size)
29387c478bd9Sstevel@tonic-gate {
29397c478bd9Sstevel@tonic-gate 	pfn_t		basepfn = (pfn_t)(basepa >> PAGESHIFT);
29407c478bd9Sstevel@tonic-gate 	pgcnt_t		npages = (pgcnt_t)(size >> PAGESHIFT);
29417c478bd9Sstevel@tonic-gate 	pda_handle_t	ph;
29427c478bd9Sstevel@tonic-gate 	int		rv;
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate 	ASSERT(size != 0);
29457c478bd9Sstevel@tonic-gate 
29467c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
29477c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
29487c478bd9Sstevel@tonic-gate 
294985f58038Sdp78419 	rv = kcage_range_add(basepfn, npages, KCAGE_DOWN);
29507c478bd9Sstevel@tonic-gate 	if (rv == ENOMEM) {
295107d06da5SSurya Prakki 		cmn_err(CE_WARN, "%lu megabytes not available to kernel cage",
295207d06da5SSurya Prakki 		    (ulong_t)(size == 0 ? 0 : size / MBYTE));
29537c478bd9Sstevel@tonic-gate 	} else if (rv != 0) {
29547c478bd9Sstevel@tonic-gate 		/* catch this in debug kernels */
29557c478bd9Sstevel@tonic-gate 		ASSERT(0);
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "unexpected kcage_range_add"
29587c478bd9Sstevel@tonic-gate 		    " return value %d", rv);
29597c478bd9Sstevel@tonic-gate 	}
29607c478bd9Sstevel@tonic-gate 
29617c478bd9Sstevel@tonic-gate 	/*
29627c478bd9Sstevel@tonic-gate 	 * Update the PDA (post2obp) structure with the
29637c478bd9Sstevel@tonic-gate 	 * range of the newly added memory.
29647c478bd9Sstevel@tonic-gate 	 */
29657c478bd9Sstevel@tonic-gate 	ph = drmach_pda_open();
29667c478bd9Sstevel@tonic-gate 	if (ph != NULL) {
29677c478bd9Sstevel@tonic-gate 		pda_mem_add_span(ph, basepa, size);
29687c478bd9Sstevel@tonic-gate 		pda_close(ph);
29697c478bd9Sstevel@tonic-gate 	}
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 	return (NULL);
29727c478bd9Sstevel@tonic-gate }
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate sbd_error_t *
29757c478bd9Sstevel@tonic-gate drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size)
29767c478bd9Sstevel@tonic-gate {
29777c478bd9Sstevel@tonic-gate 	drmach_device_t	*mem = id;
29787c478bd9Sstevel@tonic-gate 	pfn_t		basepfn = (pfn_t)(basepa >> PAGESHIFT);
29797c478bd9Sstevel@tonic-gate 	pgcnt_t		npages = (pgcnt_t)(size >> PAGESHIFT);
29807c478bd9Sstevel@tonic-gate 	uint_t		mcreg;
29817c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
29827c478bd9Sstevel@tonic-gate 	pda_handle_t	ph;
29837c478bd9Sstevel@tonic-gate 	int		rv;
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
29867c478bd9Sstevel@tonic-gate 	if (err)
29877c478bd9Sstevel@tonic-gate 		return (err);
29887c478bd9Sstevel@tonic-gate 	else if (mcreg & STARFIRE_MC_INTERLEAVE_MASK) {
29897c478bd9Sstevel@tonic-gate 		return (drerr_new(1, ESTF_INTERBOARD, "%s::%s",
29907c478bd9Sstevel@tonic-gate 		    mem->bp->cm.name, mem->cm.name));
29917c478bd9Sstevel@tonic-gate 	}
29927c478bd9Sstevel@tonic-gate 
29937c478bd9Sstevel@tonic-gate 	if (size > 0) {
29947c478bd9Sstevel@tonic-gate 		rv = kcage_range_delete_post_mem_del(basepfn, npages);
29957c478bd9Sstevel@tonic-gate 		if (rv != 0) {
29967c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
29977c478bd9Sstevel@tonic-gate 			    "unexpected kcage_range_delete_post_mem_del"
29987c478bd9Sstevel@tonic-gate 			    " return value %d", rv);
29997c478bd9Sstevel@tonic-gate 			return (DRMACH_INTERNAL_ERROR());
30007c478bd9Sstevel@tonic-gate 		}
30017c478bd9Sstevel@tonic-gate 	}
30027c478bd9Sstevel@tonic-gate 
30037c478bd9Sstevel@tonic-gate 	/*
30047c478bd9Sstevel@tonic-gate 	 * Update the PDA (post2obp) structure with the
30057c478bd9Sstevel@tonic-gate 	 * range of removed memory.
30067c478bd9Sstevel@tonic-gate 	 */
30077c478bd9Sstevel@tonic-gate 	ph = drmach_pda_open();
30087c478bd9Sstevel@tonic-gate 	if (ph != NULL) {
30097c478bd9Sstevel@tonic-gate 		if (size > 0)
30107c478bd9Sstevel@tonic-gate 			pda_mem_del_span(ph, basepa, size);
30117c478bd9Sstevel@tonic-gate 
30127c478bd9Sstevel@tonic-gate 		/* update PDA to board's new mc register settings */
30137c478bd9Sstevel@tonic-gate 		pda_mem_sync(ph, mem->bp->bnum, 0);
30147c478bd9Sstevel@tonic-gate 
30157c478bd9Sstevel@tonic-gate 		pda_close(ph);
30167c478bd9Sstevel@tonic-gate 	}
30177c478bd9Sstevel@tonic-gate 
30187c478bd9Sstevel@tonic-gate 	return (NULL);
30197c478bd9Sstevel@tonic-gate }
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate /* support routine for enable and disable */
30227c478bd9Sstevel@tonic-gate static sbd_error_t *
30237c478bd9Sstevel@tonic-gate drmach_mem_update_interconnect(drmachid_t id, uint_t mcreg)
30247c478bd9Sstevel@tonic-gate {
30257c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
30267c478bd9Sstevel@tonic-gate 	pda_handle_t	 ph;
30277c478bd9Sstevel@tonic-gate 	int		 b;
30287c478bd9Sstevel@tonic-gate 
30297c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
30307c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
30317c478bd9Sstevel@tonic-gate 	dp = id;
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate 	ph = drmach_pda_open();
30347c478bd9Sstevel@tonic-gate 	if (ph == NULL)
30357c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
30367c478bd9Sstevel@tonic-gate 
30377c478bd9Sstevel@tonic-gate 	for (b = 0; b < MAX_BOARDS; b++) {
30387c478bd9Sstevel@tonic-gate 		int		p;
30397c478bd9Sstevel@tonic-gate 		int		rv;
30407c478bd9Sstevel@tonic-gate 		ushort_t	bda_proc, bda_ioc;
30417c478bd9Sstevel@tonic-gate 		board_desc_t	*bdesc;
30427c478bd9Sstevel@tonic-gate 
30437c478bd9Sstevel@tonic-gate 		if (pda_board_present(ph, b) == 0)
30447c478bd9Sstevel@tonic-gate 			continue;
30457c478bd9Sstevel@tonic-gate 
30467c478bd9Sstevel@tonic-gate 		bdesc = (board_desc_t *)pda_get_board_info(ph, b);
30477c478bd9Sstevel@tonic-gate 
30487c478bd9Sstevel@tonic-gate 		/*
30497c478bd9Sstevel@tonic-gate 		 * Update PCs for CPUs.
30507c478bd9Sstevel@tonic-gate 		 */
30517c478bd9Sstevel@tonic-gate 
30527c478bd9Sstevel@tonic-gate 		/* make sure definition in platmod is in sync with pda */
30537c478bd9Sstevel@tonic-gate 		ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD);
30547c478bd9Sstevel@tonic-gate 
30557c478bd9Sstevel@tonic-gate 		bda_proc = bdesc->bda_proc;
30567c478bd9Sstevel@tonic-gate 		for (p = 0; p < MAX_PROCMODS; p++) {
30577c478bd9Sstevel@tonic-gate 			if (BDA_NBL(bda_proc, p) != BDAN_GOOD)
30587c478bd9Sstevel@tonic-gate 				continue;
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate 			rv = pc_madr_add(b, dp->bp->bnum, p, mcreg);
30617c478bd9Sstevel@tonic-gate 			if (rv) {
30627c478bd9Sstevel@tonic-gate 				pda_close(ph);
30637c478bd9Sstevel@tonic-gate 				return (DRMACH_INTERNAL_ERROR());
30647c478bd9Sstevel@tonic-gate 			}
30657c478bd9Sstevel@tonic-gate 		}
30667c478bd9Sstevel@tonic-gate 
30677c478bd9Sstevel@tonic-gate 		/*
30687c478bd9Sstevel@tonic-gate 		 * Update PCs for IOCs.
30697c478bd9Sstevel@tonic-gate 		 */
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate 		/* make sure definition in platmod is in sync with pda */
30727c478bd9Sstevel@tonic-gate 		ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD);
30737c478bd9Sstevel@tonic-gate 
30747c478bd9Sstevel@tonic-gate 		bda_ioc = bdesc->bda_ioc;
30757c478bd9Sstevel@tonic-gate 		for (p = 0; p < MAX_IOCS; p++) {
30767c478bd9Sstevel@tonic-gate 			if (BDA_NBL(bda_ioc, p) != BDAN_GOOD)
30777c478bd9Sstevel@tonic-gate 				continue;
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate 			rv = pc_madr_add(b, dp->bp->bnum, p + 4, mcreg);
30807c478bd9Sstevel@tonic-gate 			if (rv) {
30817c478bd9Sstevel@tonic-gate 				pda_close(ph);
30827c478bd9Sstevel@tonic-gate 				return (DRMACH_INTERNAL_ERROR());
30837c478bd9Sstevel@tonic-gate 			}
30847c478bd9Sstevel@tonic-gate 		}
30857c478bd9Sstevel@tonic-gate 	}
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate 	pda_close(ph);
30887c478bd9Sstevel@tonic-gate 	return (NULL);
30897c478bd9Sstevel@tonic-gate }
30907c478bd9Sstevel@tonic-gate 
30917c478bd9Sstevel@tonic-gate sbd_error_t *
30927c478bd9Sstevel@tonic-gate drmach_mem_disable(drmachid_t id)
30937c478bd9Sstevel@tonic-gate {
30947c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
30957c478bd9Sstevel@tonic-gate 	uint_t		 mcreg;
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
30987c478bd9Sstevel@tonic-gate 	if (err == NULL) {
30997c478bd9Sstevel@tonic-gate 		ASSERT(mcreg & STARFIRE_MC_MEM_PRESENT_MASK);
31007c478bd9Sstevel@tonic-gate 
31017c478bd9Sstevel@tonic-gate 		/* Turn off presence bit. */
31027c478bd9Sstevel@tonic-gate 		mcreg &= ~STARFIRE_MC_MEM_PRESENT_MASK;
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 		err = drmach_mem_update_interconnect(id, mcreg);
31057c478bd9Sstevel@tonic-gate 		if (err == NULL)
31067c478bd9Sstevel@tonic-gate 			err = drmach_write_mc_asr(id, mcreg);
31077c478bd9Sstevel@tonic-gate 	}
31087c478bd9Sstevel@tonic-gate 
31097c478bd9Sstevel@tonic-gate 	return (err);
31107c478bd9Sstevel@tonic-gate }
31117c478bd9Sstevel@tonic-gate 
31127c478bd9Sstevel@tonic-gate sbd_error_t *
31137c478bd9Sstevel@tonic-gate drmach_mem_enable(drmachid_t id)
31147c478bd9Sstevel@tonic-gate {
31157c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
31167c478bd9Sstevel@tonic-gate 	uint_t		 mcreg;
31177c478bd9Sstevel@tonic-gate 
31187c478bd9Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
31197c478bd9Sstevel@tonic-gate 	if (err == NULL) {
31207c478bd9Sstevel@tonic-gate 		mcreg |= STARFIRE_MC_MEM_PRESENT_MASK;
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate 		err = drmach_write_mc_asr(id, mcreg);
31237c478bd9Sstevel@tonic-gate 		if (err == NULL)
31247c478bd9Sstevel@tonic-gate 			err = drmach_mem_update_interconnect(id, mcreg);
31257c478bd9Sstevel@tonic-gate 	}
31267c478bd9Sstevel@tonic-gate 
31277c478bd9Sstevel@tonic-gate 	return (err);
31287c478bd9Sstevel@tonic-gate }
31297c478bd9Sstevel@tonic-gate 
31307c478bd9Sstevel@tonic-gate sbd_error_t *
31317c478bd9Sstevel@tonic-gate drmach_mem_get_alignment(drmachid_t id, uint64_t *mask)
31327c478bd9Sstevel@tonic-gate {
31337c478bd9Sstevel@tonic-gate 	drmach_device_t	*mem;
31347c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
3135fa9e4066Sahrens 	pnode_t		 nodeid;
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
31387c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
31397c478bd9Sstevel@tonic-gate 	mem = id;
31407c478bd9Sstevel@tonic-gate 
31417c478bd9Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(mem->node);
31427c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE)
31437c478bd9Sstevel@tonic-gate 		err = DRMACH_INTERNAL_ERROR();
31447c478bd9Sstevel@tonic-gate 	else {
31457c478bd9Sstevel@tonic-gate 		uint64_t size;
31467c478bd9Sstevel@tonic-gate 
31477c478bd9Sstevel@tonic-gate 		size = mc_get_alignment_mask(nodeid);
31487c478bd9Sstevel@tonic-gate 		if (size == (uint64_t)-1)
31497c478bd9Sstevel@tonic-gate 			err = DRMACH_INTERNAL_ERROR();
31507c478bd9Sstevel@tonic-gate 		else {
31517c478bd9Sstevel@tonic-gate 			*mask = size - 1;
31527c478bd9Sstevel@tonic-gate 			err = NULL;
31537c478bd9Sstevel@tonic-gate 		}
31547c478bd9Sstevel@tonic-gate 	}
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 	return (err);
31577c478bd9Sstevel@tonic-gate }
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate sbd_error_t *
31607c478bd9Sstevel@tonic-gate drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa)
31617c478bd9Sstevel@tonic-gate {
31627c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
31637c478bd9Sstevel@tonic-gate 	uint_t		 mcreg;
31647c478bd9Sstevel@tonic-gate 
31657c478bd9Sstevel@tonic-gate 	err = drmach_read_mc_asr(id, &mcreg);
31667c478bd9Sstevel@tonic-gate 	if (err == NULL)
31677c478bd9Sstevel@tonic-gate 		*pa = mc_asr_to_pa(mcreg);
31687c478bd9Sstevel@tonic-gate 
31697c478bd9Sstevel@tonic-gate 	return (err);
31707c478bd9Sstevel@tonic-gate }
31717c478bd9Sstevel@tonic-gate 
31727c478bd9Sstevel@tonic-gate /*
31737c478bd9Sstevel@tonic-gate  * Use of this routine after copy/rename will yield incorrect results,
31747c478bd9Sstevel@tonic-gate  * because the OBP MEMAVAIL property will not correctly reflect the
31757c478bd9Sstevel@tonic-gate  * programming of the MCs.
31767c478bd9Sstevel@tonic-gate  */
31777c478bd9Sstevel@tonic-gate sbd_error_t *
31787c478bd9Sstevel@tonic-gate drmach_mem_get_memlist(drmachid_t id, struct memlist **ml)
31797c478bd9Sstevel@tonic-gate {
31807c478bd9Sstevel@tonic-gate 	drmach_device_t	*mem;
31817c478bd9Sstevel@tonic-gate 	int		rv, i, rlen, rblks;
31827c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
31837c478bd9Sstevel@tonic-gate 	struct memlist	*mlist;
31847c478bd9Sstevel@tonic-gate 	struct sf_memunit_regspec *rlist;
31857c478bd9Sstevel@tonic-gate 
31867c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
31877c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
31887c478bd9Sstevel@tonic-gate 	mem = id;
31897c478bd9Sstevel@tonic-gate 
31907c478bd9Sstevel@tonic-gate 	err = drmach_device_get_proplen(mem, "dr-available", &rlen);
31917c478bd9Sstevel@tonic-gate 	if (err)
31927c478bd9Sstevel@tonic-gate 		return (err);
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 	rlist = kmem_zalloc(rlen, KM_SLEEP);
31957c478bd9Sstevel@tonic-gate 
31967c478bd9Sstevel@tonic-gate 	err = drmach_device_get_prop(mem, "dr-available", rlist);
31977c478bd9Sstevel@tonic-gate 	if (err) {
31987c478bd9Sstevel@tonic-gate 		kmem_free(rlist, rlen);
31997c478bd9Sstevel@tonic-gate 		return (err);
32007c478bd9Sstevel@tonic-gate 	}
32017c478bd9Sstevel@tonic-gate 
32027c478bd9Sstevel@tonic-gate 	mlist = NULL;
32037c478bd9Sstevel@tonic-gate 	rblks = rlen / sizeof (struct sf_memunit_regspec);
32047c478bd9Sstevel@tonic-gate 	for (i = 0; i < rblks; i++) {
32057c478bd9Sstevel@tonic-gate 		uint64_t	addr, size;
32067c478bd9Sstevel@tonic-gate 
32077c478bd9Sstevel@tonic-gate 		addr  = (uint64_t)rlist[i].regspec_addr_hi << 32;
32087c478bd9Sstevel@tonic-gate 		addr |= (uint64_t)rlist[i].regspec_addr_lo;
32097c478bd9Sstevel@tonic-gate 		size  = (uint64_t)rlist[i].regspec_size_hi << 32;
32107c478bd9Sstevel@tonic-gate 		size |= (uint64_t)rlist[i].regspec_size_lo;
32117c478bd9Sstevel@tonic-gate 
32127c478bd9Sstevel@tonic-gate 		mlist = memlist_add_span(mlist, addr, size);
32137c478bd9Sstevel@tonic-gate 	}
32147c478bd9Sstevel@tonic-gate 
32157c478bd9Sstevel@tonic-gate 	kmem_free(rlist, rlen);
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 	/*
32187c478bd9Sstevel@tonic-gate 	 * Make sure the incoming memlist doesn't already
32197c478bd9Sstevel@tonic-gate 	 * intersect with what's present in the system (phys_install).
32207c478bd9Sstevel@tonic-gate 	 */
32217c478bd9Sstevel@tonic-gate 	memlist_read_lock();
32227c478bd9Sstevel@tonic-gate 	rv = memlist_intersect(phys_install, mlist);
32237c478bd9Sstevel@tonic-gate 	memlist_read_unlock();
32247c478bd9Sstevel@tonic-gate 	if (rv) {
32257c478bd9Sstevel@tonic-gate #ifdef DEBUG
32267c478bd9Sstevel@tonic-gate 		DRMACH_PR("OBP derived memlist intersects"
32277c478bd9Sstevel@tonic-gate 		    " with phys_install\n");
32287c478bd9Sstevel@tonic-gate 		memlist_dump(mlist);
32297c478bd9Sstevel@tonic-gate 
32307c478bd9Sstevel@tonic-gate 		DRMACH_PR("phys_install memlist:\n");
32317c478bd9Sstevel@tonic-gate 		memlist_dump(phys_install);
32327c478bd9Sstevel@tonic-gate #endif
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 		memlist_delete(mlist);
32357c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
32367c478bd9Sstevel@tonic-gate 	}
32377c478bd9Sstevel@tonic-gate 
32387c478bd9Sstevel@tonic-gate #ifdef DEBUG
32397c478bd9Sstevel@tonic-gate 	DRMACH_PR("OBP derived memlist:");
32407c478bd9Sstevel@tonic-gate 	memlist_dump(mlist);
32417c478bd9Sstevel@tonic-gate #endif
32427c478bd9Sstevel@tonic-gate 
32437c478bd9Sstevel@tonic-gate 	*ml = mlist;
32447c478bd9Sstevel@tonic-gate 	return (NULL);
32457c478bd9Sstevel@tonic-gate }
32467c478bd9Sstevel@tonic-gate 
32477c478bd9Sstevel@tonic-gate sbd_error_t *
32487c478bd9Sstevel@tonic-gate drmach_mem_get_size(drmachid_t id, uint64_t *bytes)
32497c478bd9Sstevel@tonic-gate {
32507c478bd9Sstevel@tonic-gate 	drmach_device_t	*mem;
32517c478bd9Sstevel@tonic-gate 	pda_handle_t	ph;
32527c478bd9Sstevel@tonic-gate 	pgcnt_t		npages;
32537c478bd9Sstevel@tonic-gate 
32547c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
32557c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
32567c478bd9Sstevel@tonic-gate 	mem = id;
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate 	ph = drmach_pda_open();
32597c478bd9Sstevel@tonic-gate 	if (ph == NULL)
32607c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
32617c478bd9Sstevel@tonic-gate 
32627c478bd9Sstevel@tonic-gate 	npages = pda_get_mem_size(ph, mem->bp->bnum);
32637c478bd9Sstevel@tonic-gate 	*bytes = (uint64_t)npages << PAGESHIFT;
32647c478bd9Sstevel@tonic-gate 
32657c478bd9Sstevel@tonic-gate 	pda_close(ph);
32667c478bd9Sstevel@tonic-gate 	return (NULL);
32677c478bd9Sstevel@tonic-gate }
32687c478bd9Sstevel@tonic-gate 
32697c478bd9Sstevel@tonic-gate sbd_error_t *
32707c478bd9Sstevel@tonic-gate drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes)
32717c478bd9Sstevel@tonic-gate {
32727c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
32737c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
32747c478bd9Sstevel@tonic-gate 
32757c478bd9Sstevel@tonic-gate 	*bytes = mc_get_mem_alignment();
32767c478bd9Sstevel@tonic-gate 	return (NULL);
32777c478bd9Sstevel@tonic-gate }
32787c478bd9Sstevel@tonic-gate 
32797c478bd9Sstevel@tonic-gate /* field debugging tool */
32807c478bd9Sstevel@tonic-gate processorid_t drmach_mem_cpu_affinity_nail = 0;
32817c478bd9Sstevel@tonic-gate 
32827c478bd9Sstevel@tonic-gate processorid_t
32837c478bd9Sstevel@tonic-gate drmach_mem_cpu_affinity(drmachid_t id)
32847c478bd9Sstevel@tonic-gate {
32857c478bd9Sstevel@tonic-gate 	drmach_device_t	*mp;
32867c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
32877c478bd9Sstevel@tonic-gate 	processorid_t	 cpuid;
32887c478bd9Sstevel@tonic-gate 
32897c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
32907c478bd9Sstevel@tonic-gate 		return (CPU_CURRENT);
32917c478bd9Sstevel@tonic-gate 
32927c478bd9Sstevel@tonic-gate 	if (drmach_mem_cpu_affinity_nail) {
32937c478bd9Sstevel@tonic-gate 		cpuid = drmach_mem_cpu_affinity_nail;
32947c478bd9Sstevel@tonic-gate 
32957c478bd9Sstevel@tonic-gate 		if (cpuid < 0 || cpuid > NCPU)
32967c478bd9Sstevel@tonic-gate 			return (CPU_CURRENT);
32977c478bd9Sstevel@tonic-gate 
32987c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
32997c478bd9Sstevel@tonic-gate 		if (cpu[cpuid] == NULL || !CPU_ACTIVE(cpu[cpuid]))
33007c478bd9Sstevel@tonic-gate 			cpuid = CPU_CURRENT;
33017c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate 		return (cpuid);
33047c478bd9Sstevel@tonic-gate 	}
33057c478bd9Sstevel@tonic-gate 
33067c478bd9Sstevel@tonic-gate 	/* try to choose a proc on the target board */
33077c478bd9Sstevel@tonic-gate 	mp = id;
33087c478bd9Sstevel@tonic-gate 	bp = mp->bp;
33097c478bd9Sstevel@tonic-gate 	if (bp->devices) {
33107c478bd9Sstevel@tonic-gate 		int		rv;
33117c478bd9Sstevel@tonic-gate 		int		d_idx;
33127c478bd9Sstevel@tonic-gate 		drmachid_t	d_id;
33137c478bd9Sstevel@tonic-gate 
33147c478bd9Sstevel@tonic-gate 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
33157c478bd9Sstevel@tonic-gate 		while (rv == 0) {
33167c478bd9Sstevel@tonic-gate 			if (DRMACH_IS_CPU_ID(d_id)) {
33177c478bd9Sstevel@tonic-gate 				cpuid = drmach_cpu_calc_id(d_id);
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate 				mutex_enter(&cpu_lock);
33207c478bd9Sstevel@tonic-gate 				if (cpu[cpuid] && CPU_ACTIVE(cpu[cpuid])) {
33217c478bd9Sstevel@tonic-gate 					mutex_exit(&cpu_lock);
33227c478bd9Sstevel@tonic-gate 					DRMACH_PR("drmach_mem_cpu_affinity: "
33237c478bd9Sstevel@tonic-gate 					    "selected cpuid=%d\n", cpuid);
33247c478bd9Sstevel@tonic-gate 					return (cpuid);
33257c478bd9Sstevel@tonic-gate 				} else {
33267c478bd9Sstevel@tonic-gate 					mutex_exit(&cpu_lock);
33277c478bd9Sstevel@tonic-gate 				}
33287c478bd9Sstevel@tonic-gate 			}
33297c478bd9Sstevel@tonic-gate 
33307c478bd9Sstevel@tonic-gate 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
33317c478bd9Sstevel@tonic-gate 		}
33327c478bd9Sstevel@tonic-gate 	}
33337c478bd9Sstevel@tonic-gate 
33347c478bd9Sstevel@tonic-gate 	/* otherwise, this proc, wherever it is */
33357c478bd9Sstevel@tonic-gate 	DRMACH_PR("drmach_mem_cpu_affinity: using default CPU_CURRENT\n");
33367c478bd9Sstevel@tonic-gate 
33377c478bd9Sstevel@tonic-gate 	return (CPU_CURRENT);
33387c478bd9Sstevel@tonic-gate }
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate static sbd_error_t *
33417c478bd9Sstevel@tonic-gate drmach_mem_release(drmachid_t id)
33427c478bd9Sstevel@tonic-gate {
33437c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_MEM_ID(id))
33447c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
33457c478bd9Sstevel@tonic-gate 	return (NULL);
33467c478bd9Sstevel@tonic-gate }
33477c478bd9Sstevel@tonic-gate 
33487c478bd9Sstevel@tonic-gate static sbd_error_t *
33497c478bd9Sstevel@tonic-gate drmach_mem_status(drmachid_t id, drmach_status_t *stat)
33507c478bd9Sstevel@tonic-gate {
33517c478bd9Sstevel@tonic-gate 	drmach_device_t *dp;
33527c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
33537c478bd9Sstevel@tonic-gate 	uint64_t	 pa, slice_size;
33547c478bd9Sstevel@tonic-gate 	struct memlist	*ml;
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate 	ASSERT(DRMACH_IS_MEM_ID(id));
33577c478bd9Sstevel@tonic-gate 	dp = id;
33587c478bd9Sstevel@tonic-gate 
33597c478bd9Sstevel@tonic-gate 	/* get starting physical address of target memory */
33607c478bd9Sstevel@tonic-gate 	err = drmach_mem_get_base_physaddr(id, &pa);
33617c478bd9Sstevel@tonic-gate 	if (err)
33627c478bd9Sstevel@tonic-gate 		return (err);
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate 	/* round down to slice boundary */
33657c478bd9Sstevel@tonic-gate 	slice_size = mc_get_mem_alignment();
33667c478bd9Sstevel@tonic-gate 	pa &= ~ (slice_size - 1);
33677c478bd9Sstevel@tonic-gate 
33687c478bd9Sstevel@tonic-gate 	/* stop at first span that is in slice */
33697c478bd9Sstevel@tonic-gate 	memlist_read_lock();
337056f33205SJonathan Adams 	for (ml = phys_install; ml; ml = ml->ml_next)
337156f33205SJonathan Adams 		if (ml->ml_address >= pa && ml->ml_address < pa + slice_size)
33727c478bd9Sstevel@tonic-gate 			break;
33737c478bd9Sstevel@tonic-gate 	memlist_read_unlock();
33747c478bd9Sstevel@tonic-gate 
33757c478bd9Sstevel@tonic-gate 	stat->assigned = dp->bp->assigned;
33767c478bd9Sstevel@tonic-gate 	stat->powered = dp->bp->powered;
33777c478bd9Sstevel@tonic-gate 	stat->configured = (ml != NULL);
33787c478bd9Sstevel@tonic-gate 	stat->busy = dp->busy;
337907d06da5SSurya Prakki 	(void) strncpy(stat->type, dp->type, sizeof (stat->type));
33807c478bd9Sstevel@tonic-gate 	stat->info[0] = '\0';
33817c478bd9Sstevel@tonic-gate 
33827c478bd9Sstevel@tonic-gate 	return (NULL);
33837c478bd9Sstevel@tonic-gate }
33847c478bd9Sstevel@tonic-gate 
33857c478bd9Sstevel@tonic-gate static int
33867c478bd9Sstevel@tonic-gate drmach_detach_board(void *arg)
33877c478bd9Sstevel@tonic-gate {
33887c478bd9Sstevel@tonic-gate 	cpuset_t	cset;
33897c478bd9Sstevel@tonic-gate 	int		retval;
33907c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp = (drmach_board_t *)arg;
33917c478bd9Sstevel@tonic-gate 
33927c478bd9Sstevel@tonic-gate 	cset = cpu_ready_set;
33937c478bd9Sstevel@tonic-gate 	promsafe_xc_attention(cset);
33947c478bd9Sstevel@tonic-gate 
33957c478bd9Sstevel@tonic-gate 	retval = prom_starfire_rm_brd(bp->bnum);
33967c478bd9Sstevel@tonic-gate 
33977c478bd9Sstevel@tonic-gate 	xc_dismissed(cset);
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate 	return (retval);
34007c478bd9Sstevel@tonic-gate }
34017c478bd9Sstevel@tonic-gate 
34027c478bd9Sstevel@tonic-gate sbd_error_t *
34037c478bd9Sstevel@tonic-gate drmach_board_deprobe(drmachid_t id)
34047c478bd9Sstevel@tonic-gate {
34057c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
34067c478bd9Sstevel@tonic-gate 	int		 retval;
34077c478bd9Sstevel@tonic-gate 
34087c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
34097c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
34107c478bd9Sstevel@tonic-gate 	bp = id;
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum);
34137c478bd9Sstevel@tonic-gate 
34147c478bd9Sstevel@tonic-gate 	retval = prom_tree_update(drmach_detach_board, bp);
34157c478bd9Sstevel@tonic-gate 
34167c478bd9Sstevel@tonic-gate 	if (retval == 0)
34177c478bd9Sstevel@tonic-gate 		return (NULL);
34187c478bd9Sstevel@tonic-gate 	else {
34197c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "prom error: prom_starfire_rm_brd(%d) "
34207c478bd9Sstevel@tonic-gate 		    "returned %d", bp->bnum, retval);
34217c478bd9Sstevel@tonic-gate 		return (drerr_new(1, ESTF_DEPROBE, "%s", bp->cm.name));
34227c478bd9Sstevel@tonic-gate 	}
34237c478bd9Sstevel@tonic-gate }
34247c478bd9Sstevel@tonic-gate 
34257c478bd9Sstevel@tonic-gate /*ARGSUSED*/
34267c478bd9Sstevel@tonic-gate static sbd_error_t *
34277c478bd9Sstevel@tonic-gate drmach_pt_juggle_bootproc(drmachid_t id, drmach_opts_t *opts)
34287c478bd9Sstevel@tonic-gate {
34297c478bd9Sstevel@tonic-gate 	drmach_device_t	*cpu;
34307c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
34317c478bd9Sstevel@tonic-gate 
34327c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_CPU_ID(id))
34337c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
34347c478bd9Sstevel@tonic-gate 	cpu = id;
34357c478bd9Sstevel@tonic-gate 
34367c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
34377c478bd9Sstevel@tonic-gate 
34387c478bd9Sstevel@tonic-gate 	err = drmach_cpu_juggle_bootproc(cpu);
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
34417c478bd9Sstevel@tonic-gate 
34427c478bd9Sstevel@tonic-gate 	return (err);
34437c478bd9Sstevel@tonic-gate }
34447c478bd9Sstevel@tonic-gate 
34457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
34467c478bd9Sstevel@tonic-gate static sbd_error_t *
34477c478bd9Sstevel@tonic-gate drmach_pt_dump_pdainfo(drmachid_t id, drmach_opts_t *opts)
34487c478bd9Sstevel@tonic-gate {
34497c478bd9Sstevel@tonic-gate 	drmach_board_t	*bp;
34507c478bd9Sstevel@tonic-gate 	int		board;
34517c478bd9Sstevel@tonic-gate 	int		i;
34527c478bd9Sstevel@tonic-gate 	pda_handle_t	ph;
34537c478bd9Sstevel@tonic-gate 	board_desc_t	*bdesc;
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_BOARD_ID(id))
34567c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
34577c478bd9Sstevel@tonic-gate 	bp = id;
34587c478bd9Sstevel@tonic-gate 	board = bp->bnum;
34597c478bd9Sstevel@tonic-gate 
34607c478bd9Sstevel@tonic-gate 	ph = drmach_pda_open();
34617c478bd9Sstevel@tonic-gate 	if (ph == NULL)
34627c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
34637c478bd9Sstevel@tonic-gate 
34647c478bd9Sstevel@tonic-gate 	if (pda_board_present(ph, board) == 0) {
34657c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "board %d is MISSING\n", board);
34667c478bd9Sstevel@tonic-gate 		pda_close(ph);
34677c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
34687c478bd9Sstevel@tonic-gate 	}
34697c478bd9Sstevel@tonic-gate 
34707c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "board %d is PRESENT\n", board);
34717c478bd9Sstevel@tonic-gate 
34727c478bd9Sstevel@tonic-gate 	bdesc = (board_desc_t *)pda_get_board_info(ph, board);
34737c478bd9Sstevel@tonic-gate 	if (bdesc == NULL) {
34747c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
34757c478bd9Sstevel@tonic-gate 		    "no board descriptor found for board %d\n",
34767c478bd9Sstevel@tonic-gate 		    board);
34777c478bd9Sstevel@tonic-gate 		pda_close(ph);
34787c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
34797c478bd9Sstevel@tonic-gate 	}
34807c478bd9Sstevel@tonic-gate 
34817c478bd9Sstevel@tonic-gate 	/* make sure definition in platmod is in sync with pda */
34827c478bd9Sstevel@tonic-gate 	ASSERT(MAX_PROCMODS == MAX_CPU_UNITS_PER_BOARD);
34837c478bd9Sstevel@tonic-gate 
34847c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_PROCMODS; i++) {
34857c478bd9Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_proc, i) == BDAN_GOOD)
34867c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
34877c478bd9Sstevel@tonic-gate 			    "proc %d.%d PRESENT\n", board, i);
34887c478bd9Sstevel@tonic-gate 		else
34897c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
34907c478bd9Sstevel@tonic-gate 			    "proc %d.%d MISSING\n", board, i);
34917c478bd9Sstevel@tonic-gate 	}
34927c478bd9Sstevel@tonic-gate 
34937c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_MGROUPS; i++) {
34947c478bd9Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_mgroup, i) == BDAN_GOOD)
34957c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
34967c478bd9Sstevel@tonic-gate 			    "mgroup %d.%d PRESENT\n", board, i);
34977c478bd9Sstevel@tonic-gate 		else
34987c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
34997c478bd9Sstevel@tonic-gate 			    "mgroup %d.%d MISSING\n", board, i);
35007c478bd9Sstevel@tonic-gate 	}
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 	/* make sure definition in platmod is in sync with pda */
35037c478bd9Sstevel@tonic-gate 	ASSERT(MAX_IOCS == MAX_IO_UNITS_PER_BOARD);
35047c478bd9Sstevel@tonic-gate 
35057c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_IOCS; i++) {
35067c478bd9Sstevel@tonic-gate 		int	s;
35077c478bd9Sstevel@tonic-gate 
35087c478bd9Sstevel@tonic-gate 		if (BDA_NBL(bdesc->bda_ioc, i) == BDAN_GOOD) {
35097c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
35107c478bd9Sstevel@tonic-gate 			    "ioc %d.%d PRESENT\n", board, i);
35117c478bd9Sstevel@tonic-gate 			for (s = 0; s < MAX_SLOTS_PER_IOC; s++) {
35127c478bd9Sstevel@tonic-gate 				if (BDA_NBL(bdesc->bda_ios[i], s) != BDAN_GOOD)
35137c478bd9Sstevel@tonic-gate 					continue;
35147c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
35157c478bd9Sstevel@tonic-gate 				    "..scard %d.%d.%d PRESENT\n",
35167c478bd9Sstevel@tonic-gate 				    board, i, s);
35177c478bd9Sstevel@tonic-gate 			}
35187c478bd9Sstevel@tonic-gate 		} else {
35197c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
35207c478bd9Sstevel@tonic-gate 			    "ioc %d.%d MISSING\n",
35217c478bd9Sstevel@tonic-gate 			    board, i);
35227c478bd9Sstevel@tonic-gate 		}
35237c478bd9Sstevel@tonic-gate 	}
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT,
35267c478bd9Sstevel@tonic-gate 	    "board %d memsize = %d pages\n",
35277c478bd9Sstevel@tonic-gate 	    board, pda_get_mem_size(ph, board));
35287c478bd9Sstevel@tonic-gate 
35297c478bd9Sstevel@tonic-gate 	pda_close(ph);
35307c478bd9Sstevel@tonic-gate 
35317c478bd9Sstevel@tonic-gate 	return (NULL);
35327c478bd9Sstevel@tonic-gate }
35337c478bd9Sstevel@tonic-gate 
35347c478bd9Sstevel@tonic-gate /*ARGSUSED*/
35357c478bd9Sstevel@tonic-gate sbd_error_t *
35367c478bd9Sstevel@tonic-gate drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts)
35377c478bd9Sstevel@tonic-gate {
35387c478bd9Sstevel@tonic-gate 	struct memlist	*ml;
35397c478bd9Sstevel@tonic-gate 	uint64_t	src_pa;
35407c478bd9Sstevel@tonic-gate 	uint64_t	dst_pa;
35417c478bd9Sstevel@tonic-gate 	uint64_t	dst;
35427c478bd9Sstevel@tonic-gate 
35437c478bd9Sstevel@tonic-gate 	dst_pa = va_to_pa(&dst);
35447c478bd9Sstevel@tonic-gate 
35457c478bd9Sstevel@tonic-gate 	memlist_read_lock();
354656f33205SJonathan Adams 	for (ml = phys_install; ml; ml = ml->ml_next) {
35477c478bd9Sstevel@tonic-gate 		uint64_t	nbytes;
35487c478bd9Sstevel@tonic-gate 
354956f33205SJonathan Adams 		src_pa = ml->ml_address;
355056f33205SJonathan Adams 		nbytes = ml->ml_size;
35517c478bd9Sstevel@tonic-gate 
35527c478bd9Sstevel@tonic-gate 		while (nbytes != 0ull) {
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate 			/* copy 32 bytes at arc_pa to dst_pa */
35557c478bd9Sstevel@tonic-gate 			bcopy32_il(src_pa, dst_pa);
35567c478bd9Sstevel@tonic-gate 
35577c478bd9Sstevel@tonic-gate 			/* increment by 32 bytes */
35587c478bd9Sstevel@tonic-gate 			src_pa += (4 * sizeof (uint64_t));
35597c478bd9Sstevel@tonic-gate 
35607c478bd9Sstevel@tonic-gate 			/* decrement by 32 bytes */
35617c478bd9Sstevel@tonic-gate 			nbytes -= (4 * sizeof (uint64_t));
35627c478bd9Sstevel@tonic-gate 		}
35637c478bd9Sstevel@tonic-gate 	}
35647c478bd9Sstevel@tonic-gate 	memlist_read_unlock();
35657c478bd9Sstevel@tonic-gate 
35667c478bd9Sstevel@tonic-gate 	return (NULL);
35677c478bd9Sstevel@tonic-gate }
35687c478bd9Sstevel@tonic-gate 
35697c478bd9Sstevel@tonic-gate static struct {
35707c478bd9Sstevel@tonic-gate 	const char	*name;
35717c478bd9Sstevel@tonic-gate 	sbd_error_t	*(*handler)(drmachid_t id, drmach_opts_t *opts);
35727c478bd9Sstevel@tonic-gate } drmach_pt_arr[] = {
35737c478bd9Sstevel@tonic-gate 	{ "juggle",		drmach_pt_juggle_bootproc	},
35747c478bd9Sstevel@tonic-gate 	{ "pda",		drmach_pt_dump_pdainfo		},
35757c478bd9Sstevel@tonic-gate 	{ "readmem",		drmach_pt_readmem		},
35767c478bd9Sstevel@tonic-gate 
35777c478bd9Sstevel@tonic-gate 	/* the following line must always be last */
35787c478bd9Sstevel@tonic-gate 	{ NULL,			NULL				}
35797c478bd9Sstevel@tonic-gate };
35807c478bd9Sstevel@tonic-gate 
35817c478bd9Sstevel@tonic-gate /*ARGSUSED*/
35827c478bd9Sstevel@tonic-gate sbd_error_t *
35837c478bd9Sstevel@tonic-gate drmach_passthru(drmachid_t id, drmach_opts_t *opts)
35847c478bd9Sstevel@tonic-gate {
35857c478bd9Sstevel@tonic-gate 	int		i;
35867c478bd9Sstevel@tonic-gate 	sbd_error_t	*err;
35877c478bd9Sstevel@tonic-gate 
35887c478bd9Sstevel@tonic-gate 	i = 0;
35897c478bd9Sstevel@tonic-gate 	while (drmach_pt_arr[i].name != NULL) {
35907c478bd9Sstevel@tonic-gate 		int len = strlen(drmach_pt_arr[i].name);
35917c478bd9Sstevel@tonic-gate 
35927c478bd9Sstevel@tonic-gate 		if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0)
35937c478bd9Sstevel@tonic-gate 			break;
35947c478bd9Sstevel@tonic-gate 
35957c478bd9Sstevel@tonic-gate 		i += 1;
35967c478bd9Sstevel@tonic-gate 	}
35977c478bd9Sstevel@tonic-gate 
35987c478bd9Sstevel@tonic-gate 	if (drmach_pt_arr[i].name == NULL)
35997c478bd9Sstevel@tonic-gate 		err = drerr_new(0, ESTF_UNKPTCMD, opts->copts);
36007c478bd9Sstevel@tonic-gate 	else
36017c478bd9Sstevel@tonic-gate 		err = (*drmach_pt_arr[i].handler)(id, opts);
36027c478bd9Sstevel@tonic-gate 
36037c478bd9Sstevel@tonic-gate 	return (err);
36047c478bd9Sstevel@tonic-gate }
36057c478bd9Sstevel@tonic-gate 
36067c478bd9Sstevel@tonic-gate sbd_error_t *
36077c478bd9Sstevel@tonic-gate drmach_release(drmachid_t id)
36087c478bd9Sstevel@tonic-gate {
36097c478bd9Sstevel@tonic-gate 	drmach_common_t *cp;
36107c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
36117c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
36127c478bd9Sstevel@tonic-gate 	cp = id;
36137c478bd9Sstevel@tonic-gate 
36147c478bd9Sstevel@tonic-gate 	return (cp->release(id));
36157c478bd9Sstevel@tonic-gate }
36167c478bd9Sstevel@tonic-gate 
36177c478bd9Sstevel@tonic-gate sbd_error_t *
36187c478bd9Sstevel@tonic-gate drmach_status(drmachid_t id, drmach_status_t *stat)
36197c478bd9Sstevel@tonic-gate {
36207c478bd9Sstevel@tonic-gate 	drmach_common_t *cp;
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_ID(id))
36237c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_NOTID, NULL));
36247c478bd9Sstevel@tonic-gate 	cp = id;
36257c478bd9Sstevel@tonic-gate 
36267c478bd9Sstevel@tonic-gate 	return (cp->status(id, stat));
36277c478bd9Sstevel@tonic-gate }
36287c478bd9Sstevel@tonic-gate 
36297c478bd9Sstevel@tonic-gate sbd_error_t *
36307c478bd9Sstevel@tonic-gate drmach_unconfigure(drmachid_t id, int flags)
36317c478bd9Sstevel@tonic-gate {
36327c478bd9Sstevel@tonic-gate 	drmach_device_t	*dp;
3633fa9e4066Sahrens 	pnode_t		 nodeid;
36347c478bd9Sstevel@tonic-gate 	dev_info_t	*dip, *fdip = NULL;
36357c478bd9Sstevel@tonic-gate 
36367c478bd9Sstevel@tonic-gate 	if (!DRMACH_IS_DEVICE_ID(id))
36377c478bd9Sstevel@tonic-gate 		return (drerr_new(0, ESTF_INAPPROP, NULL));
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 	dp = id;
36407c478bd9Sstevel@tonic-gate 
36417c478bd9Sstevel@tonic-gate 	nodeid = drmach_node_get_dnode(dp->node);
36427c478bd9Sstevel@tonic-gate 	if (nodeid == OBP_NONODE)
36437c478bd9Sstevel@tonic-gate 		return (DRMACH_INTERNAL_ERROR());
36447c478bd9Sstevel@tonic-gate 
36457c478bd9Sstevel@tonic-gate 	dip = e_ddi_nodeid_to_dip(nodeid);
36467c478bd9Sstevel@tonic-gate 	if (dip == NULL)
36477c478bd9Sstevel@tonic-gate 		return (NULL);
36487c478bd9Sstevel@tonic-gate 
36497c478bd9Sstevel@tonic-gate 	/*
36507c478bd9Sstevel@tonic-gate 	 * Branch already held, so hold acquired in
36517c478bd9Sstevel@tonic-gate 	 * e_ddi_nodeid_to_dip() can be released
36527c478bd9Sstevel@tonic-gate 	 */
36537c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
36547c478bd9Sstevel@tonic-gate 
365525cf1a30Sjl139090 	if (flags & DEVI_BRANCH_DESTROY)
365625cf1a30Sjl139090 		flags |= DEVI_BRANCH_EVENT;
36577c478bd9Sstevel@tonic-gate 
36587c478bd9Sstevel@tonic-gate 	/*
36597c478bd9Sstevel@tonic-gate 	 * Force flag is no longer necessary. See starcat/io/drmach.c
36607c478bd9Sstevel@tonic-gate 	 * for details.
36617c478bd9Sstevel@tonic-gate 	 */
36627c478bd9Sstevel@tonic-gate 	ASSERT(e_ddi_branch_held(dip));
366325cf1a30Sjl139090 	if (e_ddi_branch_unconfigure(dip, &fdip, flags)) {
36647c478bd9Sstevel@tonic-gate 		sbd_error_t	*err;
36657c478bd9Sstevel@tonic-gate 		char		*path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
36667c478bd9Sstevel@tonic-gate 
36677c478bd9Sstevel@tonic-gate 		/*
36687c478bd9Sstevel@tonic-gate 		 * If non-NULL, fdip is returned held and must be released.
36697c478bd9Sstevel@tonic-gate 		 */
36707c478bd9Sstevel@tonic-gate 		if (fdip != NULL) {
36717c478bd9Sstevel@tonic-gate 			(void) ddi_pathname(fdip, path);
36727c478bd9Sstevel@tonic-gate 			ndi_rele_devi(fdip);
36737c478bd9Sstevel@tonic-gate 		} else {
36747c478bd9Sstevel@tonic-gate 			(void) ddi_pathname(dip, path);
36757c478bd9Sstevel@tonic-gate 		}
36767c478bd9Sstevel@tonic-gate 
36777c478bd9Sstevel@tonic-gate 		err = drerr_new(1, ESTF_DRVFAIL, path);
36787c478bd9Sstevel@tonic-gate 
36797c478bd9Sstevel@tonic-gate 		kmem_free(path, MAXPATHLEN);
36807c478bd9Sstevel@tonic-gate 
36817c478bd9Sstevel@tonic-gate 		return (err);
36827c478bd9Sstevel@tonic-gate 	}
36837c478bd9Sstevel@tonic-gate 
36847c478bd9Sstevel@tonic-gate 	return (NULL);
36857c478bd9Sstevel@tonic-gate }
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate /*
36887c478bd9Sstevel@tonic-gate  * drmach interfaces to legacy Starfire platmod logic
36897c478bd9Sstevel@tonic-gate  * linkage via runtime symbol look up, called from plat_cpu_power*
36907c478bd9Sstevel@tonic-gate  */
36917c478bd9Sstevel@tonic-gate 
36927c478bd9Sstevel@tonic-gate /*
36937c478bd9Sstevel@tonic-gate  * Start up a cpu.  It is possible that we're attempting to restart
36947c478bd9Sstevel@tonic-gate  * the cpu after an UNCONFIGURE in which case the cpu will be
36957c478bd9Sstevel@tonic-gate  * spinning in its cache.  So, all we have to do is wakeup him up.
36967c478bd9Sstevel@tonic-gate  * Under normal circumstances the cpu will be coming from a previous
36977c478bd9Sstevel@tonic-gate  * CONNECT and thus will be spinning in OBP.  In both cases, the
36987c478bd9Sstevel@tonic-gate  * startup sequence is the same.
36997c478bd9Sstevel@tonic-gate  */
37007c478bd9Sstevel@tonic-gate int
37017c478bd9Sstevel@tonic-gate drmach_cpu_poweron(struct cpu *cp)
37027c478bd9Sstevel@tonic-gate {
37037c478bd9Sstevel@tonic-gate 	DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id);
37047c478bd9Sstevel@tonic-gate 
37057c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
37067c478bd9Sstevel@tonic-gate 
37077c478bd9Sstevel@tonic-gate 	if (drmach_cpu_start(cp) != 0)
37087c478bd9Sstevel@tonic-gate 		return (EBUSY);
37097c478bd9Sstevel@tonic-gate 	else
37107c478bd9Sstevel@tonic-gate 		return (0);
37117c478bd9Sstevel@tonic-gate }
37127c478bd9Sstevel@tonic-gate 
37137c478bd9Sstevel@tonic-gate int
37147c478bd9Sstevel@tonic-gate drmach_cpu_poweroff(struct cpu *cp)
37157c478bd9Sstevel@tonic-gate {
37167c478bd9Sstevel@tonic-gate 	int		ntries, cnt;
37177c478bd9Sstevel@tonic-gate 	processorid_t	cpuid = cp->cpu_id;
37187c478bd9Sstevel@tonic-gate 	void		drmach_cpu_shutdown_self(void);
37197c478bd9Sstevel@tonic-gate 
37207c478bd9Sstevel@tonic-gate 	DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id);
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
37237c478bd9Sstevel@tonic-gate 
37247c478bd9Sstevel@tonic-gate 	/*
37257c478bd9Sstevel@tonic-gate 	 * Capture all CPUs (except for detaching proc) to prevent
37267c478bd9Sstevel@tonic-gate 	 * crosscalls to the detaching proc until it has cleared its
37277c478bd9Sstevel@tonic-gate 	 * bit in cpu_ready_set.
37287c478bd9Sstevel@tonic-gate 	 *
37297c478bd9Sstevel@tonic-gate 	 * The CPU's remain paused and the prom_mutex is known to be free.
37307c478bd9Sstevel@tonic-gate 	 * This prevents the x-trap victim from blocking when doing prom
37317c478bd9Sstevel@tonic-gate 	 * IEEE-1275 calls at a high PIL level.
37327c478bd9Sstevel@tonic-gate 	 */
37337c478bd9Sstevel@tonic-gate 	promsafe_pause_cpus();
37347c478bd9Sstevel@tonic-gate 
37357c478bd9Sstevel@tonic-gate 	/*
37367c478bd9Sstevel@tonic-gate 	 * Quiesce interrupts on the target CPU. We do this by setting
37377c478bd9Sstevel@tonic-gate 	 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
37387c478bd9Sstevel@tonic-gate 	 * prevent it from receiving cross calls and cross traps.
37397c478bd9Sstevel@tonic-gate 	 * This prevents the processor from receiving any new soft interrupts.
37407c478bd9Sstevel@tonic-gate 	 */
37417c478bd9Sstevel@tonic-gate 	mp_cpu_quiesce(cp);
37427c478bd9Sstevel@tonic-gate 
37437c478bd9Sstevel@tonic-gate 	/* setup xt_mb, will be cleared by drmach_shutdown_asm when ready */
37447c478bd9Sstevel@tonic-gate 	drmach_xt_mb[cpuid] = 0x80;
37457c478bd9Sstevel@tonic-gate 
37467c478bd9Sstevel@tonic-gate 	xt_one_unchecked(cpuid, (xcfunc_t *)idle_stop_xcall,
37477c478bd9Sstevel@tonic-gate 	    (uint64_t)drmach_cpu_shutdown_self, NULL);
37487c478bd9Sstevel@tonic-gate 
37497c478bd9Sstevel@tonic-gate 	ntries = drmach_cpu_ntries;
37507c478bd9Sstevel@tonic-gate 	cnt = 0;
37517c478bd9Sstevel@tonic-gate 	while (drmach_xt_mb[cpuid] && ntries) {
37527c478bd9Sstevel@tonic-gate 		DELAY(drmach_cpu_delay);
37537c478bd9Sstevel@tonic-gate 		ntries--;
37547c478bd9Sstevel@tonic-gate 		cnt++;
37557c478bd9Sstevel@tonic-gate 	}
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate 	drmach_xt_mb[cpuid] = 0;	/* steal the cache line back */
37587c478bd9Sstevel@tonic-gate 
37597c478bd9Sstevel@tonic-gate 	start_cpus();
37607c478bd9Sstevel@tonic-gate 
37617c478bd9Sstevel@tonic-gate 	DRMACH_PR("waited %d out of %d tries for "
37627c478bd9Sstevel@tonic-gate 	    "drmach_cpu_shutdown_self on cpu%d",
37637c478bd9Sstevel@tonic-gate 	    drmach_cpu_ntries - ntries, drmach_cpu_ntries, cp->cpu_id);
37647c478bd9Sstevel@tonic-gate 
37657c478bd9Sstevel@tonic-gate 	drmach_cpu_obp_detach(cpuid);
37667c478bd9Sstevel@tonic-gate 
37677c478bd9Sstevel@tonic-gate 	CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
37687c478bd9Sstevel@tonic-gate 
37697c478bd9Sstevel@tonic-gate 	return (0);
37707c478bd9Sstevel@tonic-gate }
37717c478bd9Sstevel@tonic-gate 
37727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
37737c478bd9Sstevel@tonic-gate int
37747c478bd9Sstevel@tonic-gate drmach_verify_sr(dev_info_t *dip, int sflag)
37757c478bd9Sstevel@tonic-gate {
37767c478bd9Sstevel@tonic-gate 	return (0);
37777c478bd9Sstevel@tonic-gate }
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate void
37807c478bd9Sstevel@tonic-gate drmach_suspend_last(void)
37817c478bd9Sstevel@tonic-gate {
37827c478bd9Sstevel@tonic-gate }
37837c478bd9Sstevel@tonic-gate 
37847c478bd9Sstevel@tonic-gate void
37857c478bd9Sstevel@tonic-gate drmach_resume_first(void)
37867c478bd9Sstevel@tonic-gate {
37877c478bd9Sstevel@tonic-gate }
37887c478bd9Sstevel@tonic-gate 
37897c478bd9Sstevel@tonic-gate /*
37907c478bd9Sstevel@tonic-gate  * Log a DR sysevent.
37917c478bd9Sstevel@tonic-gate  * Return value: 0 success, non-zero failure.
37927c478bd9Sstevel@tonic-gate  */
37937c478bd9Sstevel@tonic-gate int
37947c478bd9Sstevel@tonic-gate drmach_log_sysevent(int board, char *hint, int flag, int verbose)
37957c478bd9Sstevel@tonic-gate {
37967c478bd9Sstevel@tonic-gate 	sysevent_t			*ev;
37977c478bd9Sstevel@tonic-gate 	sysevent_id_t			eid;
37987c478bd9Sstevel@tonic-gate 	int				rv, km_flag;
37997c478bd9Sstevel@tonic-gate 	sysevent_value_t		evnt_val;
38007c478bd9Sstevel@tonic-gate 	sysevent_attr_list_t		*evnt_attr_list = NULL;
38017c478bd9Sstevel@tonic-gate 	char				attach_pnt[MAXNAMELEN];
38027c478bd9Sstevel@tonic-gate 
38037c478bd9Sstevel@tonic-gate 	km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
38047c478bd9Sstevel@tonic-gate 	attach_pnt[0] = '\0';
38057c478bd9Sstevel@tonic-gate 	if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) {
38067c478bd9Sstevel@tonic-gate 		rv = -1;
38077c478bd9Sstevel@tonic-gate 		goto logexit;
38087c478bd9Sstevel@tonic-gate 	}
38097c478bd9Sstevel@tonic-gate 	if (verbose)
38107c478bd9Sstevel@tonic-gate 		DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n",
38117c478bd9Sstevel@tonic-gate 		    attach_pnt, hint, flag, verbose);
38127c478bd9Sstevel@tonic-gate 
38137c478bd9Sstevel@tonic-gate 	if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE,
38147c478bd9Sstevel@tonic-gate 	    SUNW_KERN_PUB"dr", km_flag)) == NULL) {
38157c478bd9Sstevel@tonic-gate 		rv = -2;
38167c478bd9Sstevel@tonic-gate 		goto logexit;
38177c478bd9Sstevel@tonic-gate 	}
38187c478bd9Sstevel@tonic-gate 	evnt_val.value_type = SE_DATA_TYPE_STRING;
38197c478bd9Sstevel@tonic-gate 	evnt_val.value.sv_string = attach_pnt;
38207c478bd9Sstevel@tonic-gate 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID,
38217c478bd9Sstevel@tonic-gate 	    &evnt_val, km_flag)) != 0)
38227c478bd9Sstevel@tonic-gate 		goto logexit;
38237c478bd9Sstevel@tonic-gate 
38247c478bd9Sstevel@tonic-gate 	evnt_val.value_type = SE_DATA_TYPE_STRING;
38257c478bd9Sstevel@tonic-gate 	evnt_val.value.sv_string = hint;
38267c478bd9Sstevel@tonic-gate 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT,
38277c478bd9Sstevel@tonic-gate 	    &evnt_val, km_flag)) != 0) {
38287c478bd9Sstevel@tonic-gate 		sysevent_free_attr(evnt_attr_list);
38297c478bd9Sstevel@tonic-gate 		goto logexit;
38307c478bd9Sstevel@tonic-gate 	}
38317c478bd9Sstevel@tonic-gate 
38327c478bd9Sstevel@tonic-gate 	(void) sysevent_attach_attributes(ev, evnt_attr_list);
38337c478bd9Sstevel@tonic-gate 
38347c478bd9Sstevel@tonic-gate 	/*
38357c478bd9Sstevel@tonic-gate 	 * Log the event but do not sleep waiting for its
38367c478bd9Sstevel@tonic-gate 	 * delivery. This provides insulation from syseventd.
38377c478bd9Sstevel@tonic-gate 	 */
38387c478bd9Sstevel@tonic-gate 	rv = log_sysevent(ev, SE_NOSLEEP, &eid);
38397c478bd9Sstevel@tonic-gate 
38407c478bd9Sstevel@tonic-gate logexit:
38417c478bd9Sstevel@tonic-gate 	if (ev)
38427c478bd9Sstevel@tonic-gate 		sysevent_free(ev);
38437c478bd9Sstevel@tonic-gate 	if ((rv != 0) && verbose)
38447c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
38457c478bd9Sstevel@tonic-gate 		    "drmach_log_sysevent failed (rv %d) for %s  %s\n",
38467c478bd9Sstevel@tonic-gate 		    rv, attach_pnt, hint);
38477c478bd9Sstevel@tonic-gate 
38487c478bd9Sstevel@tonic-gate 	return (rv);
38497c478bd9Sstevel@tonic-gate }
38507c478bd9Sstevel@tonic-gate 
38517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
38527c478bd9Sstevel@tonic-gate int
38537c478bd9Sstevel@tonic-gate drmach_allow_memrange_modify(drmachid_t id)
38547c478bd9Sstevel@tonic-gate {
38557c478bd9Sstevel@tonic-gate 	return (1);	/* TRUE */
38567c478bd9Sstevel@tonic-gate }
3857