xref: /onnv-gate/usr/src/uts/sun4u/serengeti/io/sbdp.c (revision 11311:639e7bc0b42f)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel #include <sys/types.h>
281708Sstevel #include <sys/cmn_err.h>
291708Sstevel #include <sys/conf.h>
301708Sstevel #include <sys/ddi_impldefs.h>
311708Sstevel #include <sys/autoconf.h>
321708Sstevel #include <sys/systm.h>
331708Sstevel #include <sys/modctl.h>
341708Sstevel #include <sys/ddi.h>
351708Sstevel #include <sys/sunddi.h>
361708Sstevel #include <sys/sunndi.h>
371708Sstevel #include <sys/ndi_impldefs.h>
381708Sstevel #include <sys/promif.h>
391708Sstevel #include <sys/stat.h>
401708Sstevel #include <sys/kmem.h>
411708Sstevel #include <sys/promif.h>
421708Sstevel #include <sys/conf.h>
431708Sstevel #include <sys/obpdefs.h>
441708Sstevel #include <sys/cpuvar.h>
451708Sstevel #include <vm/seg_kmem.h>
461708Sstevel #include <sys/prom_plat.h>
471708Sstevel #include <sys/machsystm.h>
481708Sstevel #include <sys/note.h>
491708Sstevel #include <sys/memlist.h>
501708Sstevel #include <sys/ssm.h>
511708Sstevel 
521708Sstevel #include <sys/sbd_ioctl.h>
531708Sstevel #include <sys/sbd.h>
541708Sstevel #include <sys/sbdp_priv.h>
551708Sstevel #include <sys/sbdp_mem.h>
561708Sstevel #include <sys/sbdp_error.h>
571708Sstevel #include <sys/serengeti.h>
581708Sstevel 
591708Sstevel #include <sys/sgsbbc.h>		/* To get fn_t type definition */
601708Sstevel 
611708Sstevel /*
621708Sstevel  * Config information
631708Sstevel  */
641708Sstevel #ifdef DEBUG
651708Sstevel uint_t sbdp_debug = 0x0;
661708Sstevel #endif /* DEBUG */
671708Sstevel 
681708Sstevel /*
691708Sstevel  * Enable or disable dr
701708Sstevel  */
711708Sstevel int sbdp_dr_available = 1;
721708Sstevel 
731708Sstevel /* name properties for some Serengeti device nodes */
741708Sstevel #define	CMP_DEVNAME		"cmp"
751708Sstevel #define	MEM_DEVNAME		"memory"
761708Sstevel #define	CPU_DEVNAME		"cpu"
771708Sstevel #define	IO_PCI_DEVNAME		"pci"
781708Sstevel #define	IO_SGHSC_DEVNAME	"sghsc"
791708Sstevel #define	IO_WCI_DEVNAME		"wci"
801708Sstevel 
811708Sstevel static	sbd_devattr_t	sbdp_devattr[] = {
821708Sstevel 	{ CMP_DEVNAME,		"cmp",			SBD_COMP_CMP },
831708Sstevel 	{ MEM_DEVNAME,		"memory-controller",	SBD_COMP_MEM },
841708Sstevel 	{ CPU_DEVNAME,		"cpu",			SBD_COMP_CPU },
851708Sstevel 	{ IO_PCI_DEVNAME,	"pci",			SBD_COMP_IO },
861708Sstevel 	{ IO_SGHSC_DEVNAME,	"sghsc",		SBD_COMP_IO },
871708Sstevel 	{ IO_WCI_DEVNAME,	"wci",			SBD_COMP_IO },
881708Sstevel 	/* last item must be blank */
891708Sstevel 	{ NULL,			NULL,			SBD_COMP_UNKNOWN }
901708Sstevel };
911708Sstevel 
921708Sstevel /*
931708Sstevel  * In the case of a busy mbox, if a status cmd comes in we return a cached
941708Sstevel  * copy.  This cache is a link list of wnodes that contains bd structs with
951708Sstevel  * the appropriate info.  When a new wnode is created a whole entry is added
961708Sstevel  * to the list.
971708Sstevel  */
981708Sstevel sbdp_wnode_t	*first_node = NULL; /* first wnode. Entry to the link list */
991708Sstevel int		cur_num_wnodes = 0; /* how many nodes are currently running */
1001708Sstevel 
1011708Sstevel /* Macros to access fields in the previous array */
1021708Sstevel #define	SBDP_CT(i)		sbdp_devattr[i].s_dnodetype
1031708Sstevel #define	SBDP_DEVNAME(i)		sbdp_devattr[(i)].s_devname
1041708Sstevel #define	SBDP_OTYPE(i)		sbdp_devattr[(i)].s_obp_type
1051708Sstevel 
1061708Sstevel /*
1071708Sstevel  * Prototypes
1081708Sstevel  */
1091708Sstevel sbdp_wnode_t *sbdp_get_wnodep(int);
1101708Sstevel 
1111708Sstevel /*
1121708Sstevel  * Module linkage information for the kernel.
1131708Sstevel  */
1141708Sstevel 
1151708Sstevel static struct modlmisc modlmisc = {
1161708Sstevel 	&mod_miscops,
1171708Sstevel 	"Serengeti sbdp",
1181708Sstevel };
1191708Sstevel 
1201708Sstevel static struct modlinkage modlinkage = {
1211708Sstevel 	MODREV_1,
1221708Sstevel 	(void *)&modlmisc,
1231708Sstevel 	NULL
1241708Sstevel };
1251708Sstevel 
1261708Sstevel /*
1271708Sstevel  * VA area used during CPU shutdown.
1281708Sstevel  */
1291708Sstevel caddr_t	sbdp_shutdown_va;
1301708Sstevel 
1311708Sstevel /*
1321708Sstevel  * Mutex to protect our inventory
1331708Sstevel  */
1341708Sstevel kmutex_t	sbdp_wnode_mutex;
1351708Sstevel 
1361708Sstevel int
_init(void)1371708Sstevel _init(void)
1381708Sstevel {
1391708Sstevel 	int e;
1401708Sstevel 
1411708Sstevel 	e = mod_install(&modlinkage);
1421708Sstevel 	if (e != 0)
1431708Sstevel 		return (e);
1441708Sstevel 
1451708Sstevel 	sbdp_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
1461708Sstevel 	ASSERT(sbdp_shutdown_va != NULL);
1471708Sstevel 	sbdp_valp = (uint64_t *)vmem_alloc(static_alloc_arena,
1481708Sstevel 	    sizeof (uint64_t), VM_SLEEP);
1491708Sstevel 
1501708Sstevel 	mutex_init(&sbdp_wnode_mutex, NULL, MUTEX_DRIVER, NULL);
1511708Sstevel 	return (e);
1521708Sstevel }
1531708Sstevel 
1541708Sstevel int
_fini(void)1551708Sstevel _fini(void)
1561708Sstevel {
1571708Sstevel 	int e;
1581708Sstevel 
1591708Sstevel 	/*
1601708Sstevel 	 * Remove the module.
1611708Sstevel 	 */
1621708Sstevel 	e = mod_remove(&modlinkage);
1631708Sstevel 	if (e != 0)
1641708Sstevel 		return (e);
1651708Sstevel 
1661708Sstevel 	vmem_free(heap_arena, sbdp_shutdown_va, PAGESIZE);
1671708Sstevel 	sbdp_shutdown_va = NULL;
1681708Sstevel 	vmem_free(static_alloc_arena, (void *)sbdp_valp, sizeof (uint64_t));
1691708Sstevel 	sbdp_valp = NULL;
1701708Sstevel 
1711708Sstevel 	mutex_destroy(&sbdp_wnode_mutex);
1721708Sstevel 	return (e);
1731708Sstevel }
1741708Sstevel 
1751708Sstevel int
_info(struct modinfo * modinfop)1761708Sstevel _info(struct modinfo *modinfop)
1771708Sstevel {
1781708Sstevel 	return (mod_info(&modlinkage, modinfop));
1791708Sstevel }
1801708Sstevel 
1811708Sstevel int
sbdp_get_bd_and_wnode_num(pnode_t nodeid,int * bd,int * wnode)1821708Sstevel sbdp_get_bd_and_wnode_num(pnode_t nodeid, int *bd, int *wnode)
1831708Sstevel {
1841708Sstevel 	int portid;
1851708Sstevel 	static fn_t	f = "sbdp_get_bd_and_wnode_num";
1861708Sstevel 	extern int	get_portid(pnode_t node, pnode_t *cmpp);
1871708Sstevel 
1881708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
1891708Sstevel 
1901708Sstevel 	if (sbdp_is_node_bad(nodeid))
1911708Sstevel 		return (-1);
1921708Sstevel 
1931708Sstevel 	if ((portid = get_portid(nodeid, NULL)) == -1)
1941708Sstevel 		return (-1);
1951708Sstevel 
1961708Sstevel 	/*
1971708Sstevel 	 * decode the board number
1981708Sstevel 	 */
1991708Sstevel 	*bd = SG_PORTID_TO_BOARD_NUM(portid);
2001708Sstevel 	*wnode = SG_PORTID_TO_NODEID(portid);
2011708Sstevel 
2021708Sstevel 	return (0);
2031708Sstevel }
2041708Sstevel 
2051708Sstevel int
sbdp_get_board_num(sbdp_handle_t * hp,dev_info_t * dip)2061708Sstevel sbdp_get_board_num(sbdp_handle_t *hp, dev_info_t *dip)
2071708Sstevel {
2081708Sstevel 	_NOTE(ARGUNUSED(hp))
2091708Sstevel 
2101708Sstevel 	pnode_t		nodeid;
2111708Sstevel 	int		bd, wnode;
2121708Sstevel 	static fn_t	f = "sbdp_get_board_num";
2131708Sstevel 
2141708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
2151708Sstevel 
2161708Sstevel 	if (dip == NULL)
2171708Sstevel 		return (-1);
2181708Sstevel 
2191708Sstevel 	nodeid = ddi_get_nodeid(dip);
2201708Sstevel 
2211708Sstevel 	/*
2221708Sstevel 	 * Portid has encoded the nodeid and the agent id.  The top
2231708Sstevel 	 * 4 bits are correspond to the wcnodeid and the lower 5 are the
2241708Sstevel 	 * agent id.
2251708Sstevel 	 * Each agent id represents a physical location hence we can
2261708Sstevel 	 * obtain the board number
2271708Sstevel 	 */
2281708Sstevel 	if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0)
2291708Sstevel 		return (-1);
2301708Sstevel 
2311708Sstevel 	return (bd);
2321708Sstevel }
2331708Sstevel 
2341708Sstevel 
2351708Sstevel sbd_devattr_t *
sbdp_get_devattr(void)2361708Sstevel sbdp_get_devattr(void)
2371708Sstevel {
2381708Sstevel 	return (&sbdp_devattr[0]);
2391708Sstevel }
2401708Sstevel 
2411708Sstevel int
sbdp_portid_to_cpu_unit(int cmp,int core)2421708Sstevel sbdp_portid_to_cpu_unit(int cmp, int core)
2431708Sstevel {
2441708Sstevel 	return (SG_PORTID_TO_CPU_UNIT(cmp, core));
2451708Sstevel }
2461708Sstevel 
2471708Sstevel int
sbdp_get_unit_num(sbdp_handle_t * hp,dev_info_t * dip)2481708Sstevel sbdp_get_unit_num(sbdp_handle_t *hp, dev_info_t *dip)
2491708Sstevel {
2501708Sstevel 	int		unit = -1;
2511708Sstevel 	int		portid;
2521708Sstevel 	processorid_t	cpuid;
2531708Sstevel 	sbd_comp_type_t	type;
2541708Sstevel 	char		dev_type[OBP_MAXPROPNAME];
2551708Sstevel 	int		i;
2561708Sstevel 	pnode_t		nodeid;
2571708Sstevel 	static fn_t	f = "sbdp_get_unit_num";
2581708Sstevel 
2591708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
2601708Sstevel 
2611708Sstevel 	if (dip == NULL)
2621708Sstevel 		return (-1);
2631708Sstevel 
2641708Sstevel 	nodeid = ddi_get_nodeid(dip);
2651708Sstevel 
2661708Sstevel 	if (sbdp_is_node_bad(nodeid))
2671708Sstevel 		return (-1);
2681708Sstevel 
2691708Sstevel 	if (prom_getprop(nodeid, "device_type", (caddr_t)dev_type) < 0) {
2701708Sstevel 		SBDP_DBG_MISC("%s: couldn't get device_type\n", f);
2711708Sstevel 		return (-1);
2721708Sstevel 	}
2731708Sstevel 
2741708Sstevel 	for (i = 0; SBDP_CT(i) != SBD_COMP_UNKNOWN; i++) {
2751708Sstevel 		if (strcmp(dev_type, SBDP_OTYPE(i)) != 0)
2761708Sstevel 			continue;
2771708Sstevel 		type = SBDP_CT(i);
2781708Sstevel 	}
2791708Sstevel 
2801708Sstevel 	switch (type) {
2811708Sstevel 	case SBD_COMP_CPU:
2821708Sstevel 		if ((cpuid = sbdp_get_cpuid(hp, dip)) != -1) {
2831708Sstevel 			unit = SG_CPUID_TO_CPU_UNIT(cpuid);
2841708Sstevel 		}
2851708Sstevel 		break;
2861708Sstevel 	case SBD_COMP_MEM:
2871708Sstevel 		unit = 0;
2881708Sstevel 		break;
2891708Sstevel 	case SBD_COMP_IO: {
2901708Sstevel 		regspace_t	regs[3];
2911708Sstevel 		int		len = 0;
2921708Sstevel 
2931708Sstevel 		/*
2941708Sstevel 		 * Check to see if this is a cpci node
2951708Sstevel 		 * cpci nodes are assign unit nums of 5 for now
2961708Sstevel 		 * So they don't conflict with the pci unit nums
2971708Sstevel 		 */
2981708Sstevel 
2991708Sstevel 		if (strcmp(dev_type, "sghsc") == 0) {
3001708Sstevel 			SBDP_DBG_MISC("it is a sghsc\n");
3011708Sstevel 			return (4);
3021708Sstevel 		}
3031708Sstevel 
3041708Sstevel 		if (prom_getprop(nodeid, "portid", (caddr_t)&portid) <= 0) {
3051708Sstevel 			SBDP_DBG_MISC("%s: couldn't get portid\n", f);
3061708Sstevel 			return (-1);
3071708Sstevel 		}
3081708Sstevel 
3091708Sstevel 		len = prom_getproplen(nodeid, "reg");
3101708Sstevel 		if (len <= 0) {
3111708Sstevel 			SBDP_DBG_MISC("%s: couldn't get length\n", f);
3121708Sstevel 			return (-1);
3131708Sstevel 		}
3141708Sstevel 
3151708Sstevel 		if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0) {
3161708Sstevel 			SBDP_DBG_MISC("%s: couldn't get registers\n", f);
3171708Sstevel 			return (-1);
3181708Sstevel 		}
3191708Sstevel 
3201708Sstevel 		if ((portid % 2) != 0)
3211708Sstevel 			if ((regs[0].regspec_addr_lo & 0x700000) ==
322*11311SSurya.Prakki@Sun.COM 			    0x700000)
3231708Sstevel 				unit = 0;
3241708Sstevel 			else
3251708Sstevel 				unit = 1;
3261708Sstevel 		else
3271708Sstevel 			if ((regs[0].regspec_addr_lo & 0x700000) ==
3281708Sstevel 			    0x700000)
3291708Sstevel 				unit = 2;
3301708Sstevel 			else
3311708Sstevel 				unit = 3;
3321708Sstevel 
3331708Sstevel 		SBDP_DBG_MISC("unit is %d\n", unit);
3341708Sstevel 		break;
3351708Sstevel 	}
3361708Sstevel 	default:
3371708Sstevel 		break;
3381708Sstevel 
3391708Sstevel 	}
3401708Sstevel 
3411708Sstevel 	return (unit);
3421708Sstevel }
3431708Sstevel 
3441708Sstevel struct sbdp_mem_dip {
3451708Sstevel 	sbdp_bd_t	*bdp;
3461708Sstevel 	dev_info_t	*dip;
3471708Sstevel };
3481708Sstevel 
3491708Sstevel static int
sbdp_get_mem_dip(pnode_t node,void * arg,uint_t flags)3501708Sstevel sbdp_get_mem_dip(pnode_t node, void *arg, uint_t flags)
3511708Sstevel {
3521708Sstevel 	_NOTE(ARGUNUSED(flags))
3531708Sstevel 
3541708Sstevel 	struct sbdp_mem_dip	*smdp = (struct sbdp_mem_dip *)arg;
3551708Sstevel 	mem_op_t	mem = {0};
3561708Sstevel 
3571708Sstevel 	if (node == OBP_NONODE || node == OBP_BADNODE)
3581708Sstevel 		return (DDI_FAILURE);
3591708Sstevel 
3601708Sstevel 	mem.nodes = smdp->bdp->nodes;
3611708Sstevel 	mem.board = smdp->bdp->bd;
3621708Sstevel 	mem.nmem  = smdp->bdp->nnum;
3631708Sstevel 
3641708Sstevel 	(void) sbdp_is_mem(node, &mem);
3651708Sstevel 
3661708Sstevel 	/*
3671708Sstevel 	 * We need to find the dip only for the first nodeid
3681708Sstevel 	 */
3691708Sstevel 	if (smdp->bdp->nnum == 0 && mem.nmem == 1) {
3701708Sstevel 		ASSERT(smdp->dip == NULL);
3711708Sstevel 		smdp->dip = e_ddi_nodeid_to_dip(node);
3721708Sstevel 	}
3731708Sstevel 
3741708Sstevel 	smdp->bdp->nnum = mem.nmem;
3751708Sstevel 
3761708Sstevel 	return (DDI_SUCCESS);
3771708Sstevel }
3781708Sstevel 
3791708Sstevel 
3801708Sstevel /*
3811708Sstevel  * Update the board info.  Required after a copy rename
3821708Sstevel  */
3831708Sstevel void
sbdp_update_bd_info(sbdp_bd_t * bdp)3841708Sstevel sbdp_update_bd_info(sbdp_bd_t *bdp)
3851708Sstevel {
3861708Sstevel 	attach_pkt_t		apkt, *apktp = &apkt;
3871708Sstevel 	struct sbdp_mem_dip	smd = {0};
3881708Sstevel 	static fn_t	f = "sbdp_update_bd_info";
3891708Sstevel 
3901708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
3911708Sstevel 
3921708Sstevel 	if (bdp == NULL) {
3931708Sstevel 		return;
3941708Sstevel 	}
3951708Sstevel 	/*
3961708Sstevel 	 * Grab the lock
3971708Sstevel 	 */
3981708Sstevel 	mutex_enter(&bdp->bd_mutex);
3991708Sstevel 
4001708Sstevel 	/*
4011708Sstevel 	 * we get the top nodes here.  This will have a side effect of
4021708Sstevel 	 * updating the present bit for cpus
4031708Sstevel 	 */
4041708Sstevel 	apktp->node = bdp->wnode;
4051708Sstevel 	apktp->board = bdp->bd;
4061708Sstevel 	apktp->num_of_nodes = 0;
4071708Sstevel 	apktp->flags = 0;
4081708Sstevel 	sbdp_walk_prom_tree(prom_rootnode(), sbdp_select_top_nodes,
4091708Sstevel 	    (void *) apktp);
4101708Sstevel 
4111708Sstevel 	/*
4121708Sstevel 	 * We need to clear nnum since we are looking again for the
4131708Sstevel 	 * nodes
4141708Sstevel 	 */
4151708Sstevel 	bdp->nnum = 0;
4161708Sstevel 	smd.bdp = bdp;
4171708Sstevel 
4181708Sstevel 	/*
4191708Sstevel 	 * If a dip is found by sbdp_get_mem_dip(), it will be
4201708Sstevel 	 * returned held
4211708Sstevel 	 */
4221708Sstevel 	sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &smd);
4231708Sstevel 	if (smd.dip != NULL) {
4241708Sstevel 		sbdp_handle_t		*hp;
4251708Sstevel 
4261708Sstevel 		hp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP);
4271708Sstevel 		hp->h_board = bdp->bd;
4281708Sstevel 		hp->h_wnode = bdp->wnode;
4291708Sstevel 		hp->h_err = kmem_zalloc(sizeof (*hp->h_err), KM_SLEEP);
4301708Sstevel 		if (bdp->ml != NULL) {
431*11311SSurya.Prakki@Sun.COM 			(void) sbdp_del_memlist(hp, bdp->ml);
4321708Sstevel 		}
4331708Sstevel 		bdp->ml = sbdp_get_memlist(hp, (dev_info_t *)NULL);
4341708Sstevel 		/*
4351708Sstevel 		 * if the board doesn't have banks initialize them,
4361708Sstevel 		 * otherwise we assume they have been updated if
4371708Sstevel 		 * necessary
4381708Sstevel 		 */
4391708Sstevel 		if (bdp->banks == NULL) {
4401708Sstevel 			sbdp_init_bd_banks(bdp);
4411708Sstevel 		}
4421708Sstevel #ifdef DEBUG
4431708Sstevel 		sbdp_print_bd_banks(bdp);
4441708Sstevel #endif
4451708Sstevel 
4461708Sstevel 		if (sbdphw_get_base_physaddr(hp, smd.dip, &bdp->bpa))
4471708Sstevel 			bdp->bpa = -1;
4481708Sstevel 		ddi_release_devi(smd.dip);
4491708Sstevel 		kmem_free(hp->h_err, sizeof (*hp->h_err));
4501708Sstevel 		kmem_free(hp, sizeof (sbdp_handle_t));
4511708Sstevel 	}
4521708Sstevel 	mutex_exit(&bdp->bd_mutex);
4531708Sstevel }
4541708Sstevel 
4551708Sstevel /*
4561708Sstevel  * Initialize the board struct.  This remains cached.  We update it
4571708Sstevel  * every time we have a successful show_board and after a copy-rename
4581708Sstevel  */
4591708Sstevel void
sbdp_bd_init(sbdp_bd_t * bdp,int bd,int wnode)4601708Sstevel sbdp_bd_init(sbdp_bd_t *bdp, int bd, int wnode)
4611708Sstevel {
4621708Sstevel 	static fn_t	f = "sbdp_bd_init";
4631708Sstevel 
4641708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
4651708Sstevel 
4661708Sstevel 	bdp->bd = bd;
4671708Sstevel 	bdp->wnode = wnode;
4681708Sstevel 
4691708Sstevel 	SBDP_UNSET_ALL_CPUS_IN_RESET(bdp);
4701708Sstevel 
4711708Sstevel 	bdp->cpus_present = 0;
4721708Sstevel 
4731708Sstevel 	sbdp_update_bd_info(bdp);
4741708Sstevel 
4751708Sstevel 	mutex_init(&bdp->bd_mutex, NULL, MUTEX_DRIVER, NULL);
4761708Sstevel 	bdp->bd_sc = (show_board_t *)kmem_zalloc(sizeof (show_board_t),
4771708Sstevel 	    KM_SLEEP);
4781708Sstevel 	bdp->valid_cp = -1;
4791708Sstevel }
4801708Sstevel 
4811708Sstevel /*
4821708Sstevel  * This entry is going away.  Clean up
4831708Sstevel  */
4841708Sstevel void
sbdp_bd_fini(sbdp_bd_t * bdp)4851708Sstevel sbdp_bd_fini(sbdp_bd_t *bdp)
4861708Sstevel {
4871708Sstevel 	static fn_t	f = "sbdp_bd_fini";
4881708Sstevel 
4891708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
4901708Sstevel 
4911708Sstevel 	sbdp_cleanup_bd(bdp->wnode, bdp->bd);
4921708Sstevel 	kmem_free(bdp->bd_sc, sizeof (show_board_t));
4931708Sstevel 	bdp->bd_sc = NULL;
4941708Sstevel 	mutex_destroy(&bdp->bd_mutex);
4951708Sstevel #ifdef DEBUG
4961708Sstevel 	sbdp_print_all_segs();
4971708Sstevel #endif
4981708Sstevel }
4991708Sstevel 
5001708Sstevel /*
5011708Sstevel  * A new wnode has arrived.  Initialize the struct and create
5021708Sstevel  * the board structures.
5031708Sstevel  */
5041708Sstevel void
sbdp_wnode_init(sbdp_wnode_t * wnodep,int wnode,int boards)5051708Sstevel sbdp_wnode_init(sbdp_wnode_t *wnodep, int wnode, int boards)
5061708Sstevel {
5071708Sstevel 	int		i;
5081708Sstevel 	static fn_t	f = "sbdp_wnode_init";
5091708Sstevel 
5101708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
5111708Sstevel 
5121708Sstevel 	wnodep->wnode = wnode;
5131708Sstevel 	wnodep->nbds = boards;
5141708Sstevel 	wnodep->bds = kmem_zalloc(sizeof (sbdp_bd_t) * boards, KM_SLEEP);
5151708Sstevel 	wnodep->next = wnodep->prev = NULL;
5161708Sstevel 
5171708Sstevel 	for (i = 0; i < boards; i++)
5181708Sstevel 		sbdp_bd_init(&wnodep->bds[i], i, wnode);
5191708Sstevel }
5201708Sstevel 
5211708Sstevel /*
5221708Sstevel  * Wnode got DRed out.  Clean up all the node stuff including the boards
5231708Sstevel  */
5241708Sstevel void
sbdp_wnode_fini(sbdp_wnode_t * wnodep)5251708Sstevel sbdp_wnode_fini(sbdp_wnode_t *wnodep)
5261708Sstevel {
5271708Sstevel 	int	boards;
5281708Sstevel 	int	i;
5291708Sstevel 	static fn_t	f = "sbdp_wnode_fini";
5301708Sstevel 
5311708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
5321708Sstevel 
5331708Sstevel 	boards = wnodep->nbds;
5341708Sstevel 
5351708Sstevel 	for (i = 0; i < boards; i++)
5361708Sstevel 		sbdp_bd_fini(&wnodep->bds[i]);
5371708Sstevel 
5381708Sstevel 	kmem_free(wnodep->bds, sizeof (sbdp_bd_t) * boards);
5391708Sstevel 	wnodep->next = wnodep->prev = NULL;
5401708Sstevel 	kmem_free(wnodep, sizeof (sbdp_wnode_t));
5411708Sstevel }
5421708Sstevel 
5431708Sstevel /*
5441708Sstevel  * Add all the necessary fields to this board's struct
5451708Sstevel  */
5461708Sstevel void
sbdp_add_new_bd_info(int wnode,int board)5471708Sstevel sbdp_add_new_bd_info(int wnode, int board)
5481708Sstevel {
5491708Sstevel 	sbdp_wnode_t	*cur;
5501708Sstevel 	static fn_t	f = "sbdp_add_new_bd_info";
5511708Sstevel 
5521708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
5531708Sstevel 
5541708Sstevel 	cur = sbdp_get_wnodep(wnode);
5551708Sstevel 
5561708Sstevel 	SBDP_DBG_MISC("adding new board info %d\n", board);
5571708Sstevel 
5581708Sstevel 	sbdp_update_bd_info(&cur->bds[board]);
5591708Sstevel 
5601708Sstevel }
5611708Sstevel 
5621708Sstevel /*
5631708Sstevel  * This board has gone away.  Clean the necessary fields
5641708Sstevel  */
5651708Sstevel void
sbdp_cleanup_bd(int wnode,int board)5661708Sstevel sbdp_cleanup_bd(int wnode, int board)
5671708Sstevel {
5681708Sstevel 	sbdp_wnode_t	*cur;
5691708Sstevel 	sbdp_handle_t	handle, *hp;
5701708Sstevel 	sbdp_bd_t	*bdp;
5711708Sstevel 	int		i;
5721708Sstevel 	static fn_t	f = "sbdp_cleanup_bd";
5731708Sstevel 
5741708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
5751708Sstevel 
5761708Sstevel 	cur = sbdp_get_wnodep(wnode);
5771708Sstevel 
5781708Sstevel 	SBDP_DBG_MISC("cleaning up bd info for bd %d\n", board);
5791708Sstevel 	if (cur == NULL) {
5801708Sstevel 		SBDP_DBG_MISC("cur is null\n");
5811708Sstevel 		return;
5821708Sstevel 	}
5831708Sstevel 
5841708Sstevel 	bdp = &cur->bds[board];
5851708Sstevel 
5861708Sstevel 	/*
5871708Sstevel 	 * Grab the lock
5881708Sstevel 	 */
5891708Sstevel 	mutex_enter(&bdp->bd_mutex);
5901708Sstevel 
5911708Sstevel 	for (i = 0; i < bdp->nnum; i++)
5921708Sstevel 		bdp->nodes[i] = (pnode_t)0;
5931708Sstevel 	bdp->nnum = 0;
5941708Sstevel 
5951708Sstevel 	sbdp_fini_bd_banks(bdp);
5961708Sstevel 
5971708Sstevel 	hp = &handle;
5981708Sstevel 	hp->h_board = bdp->bd;
5991708Sstevel 	hp->h_wnode = bdp->wnode;
6001708Sstevel 	if (bdp->ml) {
601*11311SSurya.Prakki@Sun.COM 		(void) sbdp_del_memlist(hp, bdp->ml);
6021708Sstevel 	}
6031708Sstevel 
6041708Sstevel 	bdp->ml = NULL;
6051708Sstevel 
6061708Sstevel 	bdp->bpa = -1;
6071708Sstevel 
6081708Sstevel 	sbdp_cpu_in_reset(wnode, bdp->bd, SBDP_ALL_CPUS, 0);
6091708Sstevel 
6101708Sstevel 	bdp->cpus_present = 0;
6111708Sstevel 
6121708Sstevel 	mutex_exit(&bdp->bd_mutex);
6131708Sstevel }
6141708Sstevel 
6151708Sstevel /*
6161708Sstevel  *  Traverse the list looking for wnode. Return it when found
6171708Sstevel  */
6181708Sstevel sbdp_wnode_t *
sbdp_get_wnodep(int wnode)6191708Sstevel sbdp_get_wnodep(int wnode)
6201708Sstevel {
6211708Sstevel 	sbdp_wnode_t	*cur;
6221708Sstevel 	int		i;
6231708Sstevel 	static fn_t	f = "sbdp_get_wnodep";
6241708Sstevel 
6251708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
6261708Sstevel 
6271708Sstevel 	mutex_enter(&sbdp_wnode_mutex);
6281708Sstevel 	for (i = 0, cur = first_node; i < cur_num_wnodes; i++,
6291708Sstevel 	    cur = cur->next) {
6301708Sstevel 		if (cur->wnode == wnode) {
6311708Sstevel 			mutex_exit(&sbdp_wnode_mutex);
6321708Sstevel 			return (cur);
6331708Sstevel 		}
6341708Sstevel 	}
6351708Sstevel 	mutex_exit(&sbdp_wnode_mutex);
6361708Sstevel 
6371708Sstevel 	return (NULL);
6381708Sstevel }
6391708Sstevel 
6401708Sstevel /*
6411708Sstevel  * Insert this brand new node into our master list. It leaves it all
6421708Sstevel  * initialized
6431708Sstevel  */
6441708Sstevel void
sbdp_insert_wnode(int wnode,int max_boards)6451708Sstevel sbdp_insert_wnode(int wnode, int max_boards)
6461708Sstevel {
6471708Sstevel 	sbdp_wnode_t	*wnodep;
6481708Sstevel 	sbdp_wnode_t	*cur;
6491708Sstevel 	static fn_t	f = "sbdp_insert_wnode";
6501708Sstevel 
6511708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
6521708Sstevel 
6531708Sstevel 	wnodep = kmem_zalloc(sizeof (sbdp_wnode_t), KM_SLEEP);
6541708Sstevel 
6551708Sstevel 	mutex_enter(&sbdp_wnode_mutex);
6561708Sstevel 	if (first_node == NULL) {
6571708Sstevel 		first_node = wnodep;
6581708Sstevel 		cur_num_wnodes++;
6591708Sstevel 	} else {
6601708Sstevel 		cur = first_node + cur_num_wnodes++;
6611708Sstevel 		cur->next = wnodep;
6621708Sstevel 		wnodep->prev = cur;
6631708Sstevel 	}
6641708Sstevel 	mutex_exit(&sbdp_wnode_mutex);
6651708Sstevel 	sbdp_wnode_init(wnodep, wnode, max_boards);
6661708Sstevel }
6671708Sstevel 
6681708Sstevel /*
6691708Sstevel  * This node is gone.  Remove it from the list and also clean up
6701708Sstevel  */
6711708Sstevel void
sbdp_remove_wnode(sbdp_wnode_t * wnodep)6721708Sstevel sbdp_remove_wnode(sbdp_wnode_t *wnodep)
6731708Sstevel {
6741708Sstevel 	sbdp_wnode_t	*cur;
6751708Sstevel 	static fn_t	f = "sbdp_remove_wnode";
6761708Sstevel 
6771708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
6781708Sstevel 
6791708Sstevel 	if (wnodep != NULL) {
6801708Sstevel 		sbdp_wnode_fini(wnodep);
6811708Sstevel 		mutex_enter(&sbdp_wnode_mutex);
6821708Sstevel 
6831708Sstevel 		if (first_node == wnodep)
6841708Sstevel 			first_node = NULL;
6851708Sstevel 		else {
6861708Sstevel 			cur = wnodep->prev;
6871708Sstevel 			if (cur != NULL)
6881708Sstevel 				cur->next = wnodep->next;
6891708Sstevel 			if (wnodep->next != NULL)
6901708Sstevel 				wnodep->next->prev = cur;
6911708Sstevel 		}
6921708Sstevel 
6931708Sstevel 		cur_num_wnodes--;
6941708Sstevel 		mutex_exit(&sbdp_wnode_mutex);
6951708Sstevel 	}
6961708Sstevel }
6971708Sstevel 
6981708Sstevel /*
6991708Sstevel  * Entry point from sbd.  This is called when a new node is added.  We
7001708Sstevel  * create an entry in our inventory and initialize all the stuff that will be
7011708Sstevel  * needed
7021708Sstevel  */
7031708Sstevel int
sbdp_setup_instance(caddr_t arg)7041708Sstevel sbdp_setup_instance(caddr_t arg)
7051708Sstevel {
7061708Sstevel 	ssm_sbdp_info_t	*sbdp_info;
7071708Sstevel 	int		instance;
7081708Sstevel 	int		wnode;
7091708Sstevel 	int		max_boards;
7101708Sstevel 	static fn_t	f = "sbdp_setup_instance";
7111708Sstevel 
7121708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
7131708Sstevel 
7141708Sstevel 	/*
7151708Sstevel 	 * We get this directly from ssm
7161708Sstevel 	 */
7171708Sstevel 	sbdp_info = (ssm_sbdp_info_t *)arg;
7181708Sstevel 
7191708Sstevel 	instance = sbdp_info->instance;
7201708Sstevel 	wnode = sbdp_info->wnode;
7211708Sstevel 	max_boards = plat_max_boards();
7221708Sstevel 
7231708Sstevel 	SBDP_DBG_MISC("sbdp_setup_instance: instance %d wnode %d\n", instance,
7241708Sstevel 	    sbdp_info->wnode);
7251708Sstevel 
7261708Sstevel 	if (sbdp_get_wnodep(wnode) == NULL) {
7271708Sstevel 		/*
7281708Sstevel 		 * This node has not been instanstiated
7291708Sstevel 		 * create one
7301708Sstevel 		 */
7311708Sstevel 		sbdp_insert_wnode(wnode, max_boards);
7321708Sstevel 	}
7331708Sstevel 
7341708Sstevel 	return (DDI_SUCCESS);
7351708Sstevel }
7361708Sstevel 
7371708Sstevel /*
7381708Sstevel  * Entry point from sbd. This is called when a node has been removed (or is
7391708Sstevel  * going away. We do all the necessary cleanup
7401708Sstevel  */
7411708Sstevel int
sbdp_teardown_instance(caddr_t arg)7421708Sstevel sbdp_teardown_instance(caddr_t arg)
7431708Sstevel {
7441708Sstevel 	ssm_sbdp_info_t	*sbdp_info;
7451708Sstevel 	int		instance;
7461708Sstevel 	int		wnode;
7471708Sstevel 	sbdp_wnode_t	*wnodep;
7481708Sstevel 	static fn_t	f = "sbdp_teardown_instance";
7491708Sstevel 
7501708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
7511708Sstevel 
7521708Sstevel 	/*
7531708Sstevel 	 * ssm should have set this up
7541708Sstevel 	 */
7551708Sstevel 	sbdp_info = (ssm_sbdp_info_t *)arg;
7561708Sstevel 
7571708Sstevel 	instance = sbdp_info->instance;
7581708Sstevel 	wnode = sbdp_info->wnode;
7591708Sstevel 
7601708Sstevel 	SBDP_DBG_MISC("sbdp_teardown_instance: instance %d wnode %d\n",
7611708Sstevel 	    instance, wnode);
7621708Sstevel 
7631708Sstevel 	/*
7641708Sstevel 	 * Find this node and then remove it
7651708Sstevel 	 */
7661708Sstevel 	if ((wnodep = sbdp_get_wnodep(wnode)) != NULL) {
7671708Sstevel 		sbdp_remove_wnode(wnodep);
7681708Sstevel 	}
7691708Sstevel 	return (DDI_SUCCESS);
7701708Sstevel }
7711708Sstevel 
7721708Sstevel int
sbdp_disabled_component(sbdp_handle_t * hp)7731708Sstevel sbdp_disabled_component(sbdp_handle_t *hp)
7741708Sstevel {
7751708Sstevel #ifdef lint
7761708Sstevel 	hp = hp;
7771708Sstevel #endif
7781708Sstevel 	return (0);
7791708Sstevel }
7801708Sstevel 
7811708Sstevel /* ARGSUSED */
7821708Sstevel int
sbdp_release_component(sbdp_handle_t * hp,dev_info_t * dip)7831708Sstevel sbdp_release_component(sbdp_handle_t *hp, dev_info_t *dip)
7841708Sstevel {
7851708Sstevel 	return (0);
7861708Sstevel }
7871708Sstevel 
7881708Sstevel void
sbdp_set_err(sbd_error_t * ep,int ecode,char * rsc)7891708Sstevel sbdp_set_err(sbd_error_t *ep, int ecode, char *rsc)
7901708Sstevel {
7911708Sstevel 	static fn_t	f = "sbdp_set_err";
7921708Sstevel 
7931708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
7941708Sstevel 	ASSERT(ep != NULL);
7951708Sstevel 	ep->e_code = ecode;
7961708Sstevel 
7971708Sstevel 	if (rsc != NULL) {
7981708Sstevel 		(void) strcpy((caddr_t)(ep->e_rsc), (caddr_t)rsc);
7991708Sstevel 	}
8001708Sstevel }
8011708Sstevel 
8021708Sstevel /*
8031708Sstevel  * Serengeti DR passthrus are for debugging purposes only.
8041708Sstevel  */
8051708Sstevel static struct {
8061708Sstevel 	const char	*name;
8071708Sstevel 	int		(*handler)(sbdp_handle_t *, void *);
8081708Sstevel } sbdp_passthrus[] = {
8091708Sstevel #ifdef DEBUG
8101708Sstevel 	{ "readmem",		sbdp_passthru_readmem		},
8111708Sstevel 	{ "prep-script",	sbdp_passthru_prep_script	},
8121708Sstevel 	{ "test-quiesce",	sbdp_passthru_test_quiesce	},
8131708Sstevel 	{ "inject-error",	sbdp_passthru_inject_error	},
8141708Sstevel 	{ "reset-error",	sbdp_passthru_reset_error	},
8151708Sstevel #endif
8161708Sstevel 
8171708Sstevel 	/* the following line must always be last */
8181708Sstevel 	{ NULL,			NULL				}
8191708Sstevel };
8201708Sstevel 
8211708Sstevel 
8221708Sstevel /*ARGSUSED*/
8231708Sstevel int
sbdp_ioctl(sbdp_handle_t * hp,sbdp_ioctl_arg_t * sbdpi)8241708Sstevel sbdp_ioctl(sbdp_handle_t *hp, sbdp_ioctl_arg_t *sbdpi)
8251708Sstevel {
8261708Sstevel #ifdef DEBUG
8271708Sstevel 	char buf[512];
8281708Sstevel 	int rv;
8291708Sstevel 	sbd_ioctl_arg_t *sbdi   = (sbd_ioctl_arg_t *)sbdpi->h_iap;
8301708Sstevel 	int		i;
8311708Sstevel 	static fn_t	f = "sbdp_ioctl";
8321708Sstevel 
8331708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
8341708Sstevel 
8351708Sstevel 	if (sbdi->i_len >= sizeof (buf) ||
8361708Sstevel 	    ddi_copyin(sbdi->i_opts, buf, sbdi->i_len, sbdpi->h_mode)) {
8371708Sstevel 		sbdp_set_err(hp->h_err, ESBD_FAULT, NULL);
8381708Sstevel 		return (-1);
8391708Sstevel 	}
8401708Sstevel 
8411708Sstevel 	i = 0;
8421708Sstevel 	while (sbdp_passthrus[i].name != NULL) {
8431708Sstevel 		int	len;
8441708Sstevel 
8451708Sstevel 		len = strlen(sbdp_passthrus[i].name);
8461708Sstevel 		if (strncmp(sbdp_passthrus[i].name, buf, len) == 0)
8471708Sstevel 			break;
8481708Sstevel 		i++;
8491708Sstevel 	}
8501708Sstevel 
8511708Sstevel 	if (sbdp_passthrus[i].name == NULL) {
8521708Sstevel 		sbdp_set_err(hp->h_err, ESBD_INVAL, NULL);
8531708Sstevel 		rv = EIO;
8541708Sstevel 	} else {
8551708Sstevel 		rv = (*sbdp_passthrus[i].handler)(hp, buf);
8561708Sstevel 		if (rv != ESBD_NOERROR) {
8571708Sstevel 			sbdp_set_err(hp->h_err, rv, NULL);
8581708Sstevel 			rv = EIO;
8591708Sstevel 		}
8601708Sstevel 
8611708Sstevel 	}
8621708Sstevel 
8631708Sstevel 	return (rv);
8641708Sstevel #else
8651708Sstevel 	return (0);
8661708Sstevel #endif
8671708Sstevel }
8681708Sstevel 
8691708Sstevel /*
8701708Sstevel  * Check the dnode we obtained.  Need to find a better way to determine
8711708Sstevel  * if the node has the correct starting address
8721708Sstevel  */
8731708Sstevel int
sbdp_is_node_bad(pnode_t node)8741708Sstevel sbdp_is_node_bad(pnode_t node)
8751708Sstevel {
8761708Sstevel 	static fn_t	f = "sbdp_is_node_bad";
8771708Sstevel 
8781708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
8791708Sstevel 
8801708Sstevel 	return ((node == OBP_NONODE) || (node == OBP_BADNODE) ||
8811708Sstevel 	    ((node & 0x80000000u) != 0x80000000u));
8821708Sstevel }
8831708Sstevel 
8841708Sstevel /*
8851708Sstevel  * Retrieve the information we have on this board from
8861708Sstevel  * the inventory
8871708Sstevel  */
8881708Sstevel sbdp_bd_t *
sbdp_get_bd_info(int wnode,int board)8891708Sstevel sbdp_get_bd_info(int wnode, int board)
8901708Sstevel {
8911708Sstevel 	sbdp_wnode_t	*wnodep;
8921708Sstevel 	sbdp_bd_t	*bdp;
8931708Sstevel 	int		max_bds;
8941708Sstevel 	static fn_t	f = "sbdp_get_bd_info";
8951708Sstevel 
8961708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
8971708Sstevel 
8981708Sstevel 	wnodep = sbdp_get_wnodep(wnode);
8991708Sstevel 	max_bds = plat_max_boards();
9001708Sstevel 
9011708Sstevel 	if ((wnodep == NULL) || ((board < 0) && (board > max_bds))) {
9021708Sstevel 		return (NULL);
9031708Sstevel 	}
9041708Sstevel 
9051708Sstevel 	bdp = &wnodep->bds[board];
9061708Sstevel 
9071708Sstevel 	/*
9081708Sstevel 	 * We might not have the complete bd info.  With cheetah we
9091708Sstevel 	 * cannot access the memory decode registers when then cpu is
9101708Sstevel 	 * in reset. If the mem info is incomplete, then we try to gather it
9111708Sstevel 	 * here
9121708Sstevel 	 */
9131708Sstevel 	sbdp_update_bd_info(bdp);
9141708Sstevel 
9151708Sstevel 	return (bdp);
9161708Sstevel }
9171708Sstevel 
9181708Sstevel /*
9191708Sstevel  * There are certain cases where obp marks components as failed
9201708Sstevel  * If the status is ok the node won't have any status property. It
9211708Sstevel  * is only there if the status is other than ok.
9221708Sstevel  */
9231708Sstevel sbd_cond_t
sbdp_get_comp_status(pnode_t nodeid)9241708Sstevel sbdp_get_comp_status(pnode_t nodeid)
9251708Sstevel {
9261708Sstevel 	char			status_buf[OBP_MAXPROPNAME];
9271708Sstevel 	static const char	*status = "status";
9281708Sstevel 	static const char	*failed = "fail";
9291708Sstevel 	static const char	*disabled = "disabled";
9301708Sstevel 	static fn_t		f = "sbdp_get_comp_status";
9311708Sstevel 
9321708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
9331708Sstevel 
9341708Sstevel 	if (sbdp_is_node_bad(nodeid)) {
9351708Sstevel 		SBDP_DBG_STATE("node is not ok\n");
9361708Sstevel 		return (SBD_COND_UNKNOWN);
9371708Sstevel 	}
9381708Sstevel 
9391708Sstevel 	if (prom_getproplen(nodeid, (char *)status) <= 0) {
9401708Sstevel 		SBDP_DBG_STATE("status is ok\n");
9411708Sstevel 		return (SBD_COND_OK);
9421708Sstevel 	}
9431708Sstevel 
9441708Sstevel 	if (prom_getprop(nodeid, (char *)status, status_buf) < 0) {
9451708Sstevel 		SBDP_DBG_STATE("status is unknown\n");
9461708Sstevel 		return (SBD_COND_UNKNOWN);
9471708Sstevel 	}
9481708Sstevel 
9491708Sstevel 	if (strncmp(status_buf, failed, strlen(failed)) == 0) {
9501708Sstevel 		SBDP_DBG_STATE("status of failed\n");
9511708Sstevel 		return (SBD_COND_FAILED);
9521708Sstevel 	}
9531708Sstevel 
9541708Sstevel 	if (strcmp(status_buf, disabled) == 0) {
9551708Sstevel 		SBDP_DBG_STATE("status of unusable\n");
9561708Sstevel 		return (SBD_COND_UNUSABLE);
9571708Sstevel 	}
9581708Sstevel 
9591708Sstevel 	return (SBD_COND_OK);
9601708Sstevel }
9611708Sstevel 
9621708Sstevel void
sbdp_cpu_in_reset(int node,int bd,int unit,int reset)9631708Sstevel sbdp_cpu_in_reset(int node, int bd, int unit, int reset)
9641708Sstevel {
9651708Sstevel 	sbdp_wnode_t	*cur;
9661708Sstevel 	sbdp_bd_t	*bdp;
9671708Sstevel 	static fn_t	f = "sbdp_cpu_in_reset";
9681708Sstevel 
9691708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
9701708Sstevel 
9711708Sstevel 	if ((unit < -1) || (bd < 0) || (node < 0)) {
9721708Sstevel 		return;
9731708Sstevel 	}
9741708Sstevel 
9751708Sstevel 	cur = sbdp_get_wnodep(node);
9761708Sstevel 
9771708Sstevel 	SBDP_DBG_MISC("marking cpu %d %s for board %d\n", unit,
9781708Sstevel 	    (reset) ? "in reset" : "out of reset", bd);
9791708Sstevel 
9801708Sstevel 	if (cur == NULL) {
9811708Sstevel 		return;
9821708Sstevel 	}
9831708Sstevel 
9841708Sstevel 	bdp = &cur->bds[bd];
9851708Sstevel 
9861708Sstevel 	if (unit == SBDP_ALL_CPUS)
9871708Sstevel 		if (reset == 1)
9881708Sstevel 			SBDP_SET_ALL_CPUS_IN_RESET(bdp);
9891708Sstevel 		else
9901708Sstevel 			SBDP_UNSET_ALL_CPUS_IN_RESET(bdp);
9911708Sstevel 	else
9921708Sstevel 		if (reset == 1)
9931708Sstevel 			SBDP_SET_CPU_IN_RESET(bdp, unit);
9941708Sstevel 		else
9951708Sstevel 			SBDP_UNSET_CPU_IN_RESET(bdp, unit);
9961708Sstevel }
9971708Sstevel 
9981708Sstevel int
sbdp_set_cpu_present(int node,int bd,int unit)9991708Sstevel sbdp_set_cpu_present(int node, int bd, int unit)
10001708Sstevel {
10011708Sstevel 	sbdp_wnode_t	*cur;
10021708Sstevel 	sbdp_bd_t	*bdp;
10031708Sstevel 	static fn_t	f = "sbdp_set_cpu_present";
10041708Sstevel 
10051708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
10061708Sstevel 
10071708Sstevel 	if ((unit < 0) || (bd < 0) || (node < 0)) {
10081708Sstevel 		return (-1);
10091708Sstevel 	}
10101708Sstevel 
10111708Sstevel 	cur = sbdp_get_wnodep(node);
10121708Sstevel 	if (cur == NULL) {
10131708Sstevel 		return (-1);
10141708Sstevel 	}
10151708Sstevel 
10161708Sstevel 	bdp = &cur->bds[bd];
10171708Sstevel 
10181708Sstevel 	SBDP_SET_CPU_PRESENT(bdp, unit);
10191708Sstevel 
10201708Sstevel 	return (0);
10211708Sstevel }
10221708Sstevel 
10231708Sstevel int
sbdp_is_cpu_present(int node,int bd,int unit)10241708Sstevel sbdp_is_cpu_present(int node, int bd, int unit)
10251708Sstevel {
10261708Sstevel 	sbdp_wnode_t	*cur;
10271708Sstevel 	sbdp_bd_t	*bdp;
10281708Sstevel 	static fn_t	f = "sbdp_is_cpu_present";
10291708Sstevel 
10301708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
10311708Sstevel 
10321708Sstevel 	if ((unit < 0) || (bd < 0) || (node < 0)) {
10331708Sstevel 		return (-1);
10341708Sstevel 	}
10351708Sstevel 
10361708Sstevel 	cur = sbdp_get_wnodep(node);
10371708Sstevel 	if (cur == NULL) {
10381708Sstevel 		return (-1);
10391708Sstevel 	}
10401708Sstevel 
10411708Sstevel 	bdp = &cur->bds[bd];
10421708Sstevel 
10431708Sstevel 	return (SBDP_IS_CPU_PRESENT(bdp, unit));
10441708Sstevel }
10451708Sstevel 
10461708Sstevel int
sbdp_is_cpu_in_reset(int node,int bd,int unit)10471708Sstevel sbdp_is_cpu_in_reset(int node, int bd, int unit)
10481708Sstevel {
10491708Sstevel 	sbdp_wnode_t	*cur;
10501708Sstevel 	sbdp_bd_t	*bdp;
10511708Sstevel 	static fn_t	f = "sbdp_is_cpu_in_reset";
10521708Sstevel 
10531708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
10541708Sstevel 
10551708Sstevel 	if ((unit < 0) || (bd < 0) || (node < 0)) {
10561708Sstevel 		return (-1);
10571708Sstevel 	}
10581708Sstevel 
10591708Sstevel 	cur = sbdp_get_wnodep(node);
10601708Sstevel 
10611708Sstevel 	if (cur == NULL) {
10621708Sstevel 		return (-1);
10631708Sstevel 	}
10641708Sstevel 
10651708Sstevel 	bdp = &cur->bds[bd];
10661708Sstevel 
10671708Sstevel 	return (SBDP_IS_CPU_IN_RESET(bdp, unit));
10681708Sstevel }
10691708Sstevel 
10701708Sstevel int
sbdp_dr_avail(void)10711708Sstevel sbdp_dr_avail(void)
10721708Sstevel {
10731708Sstevel 	static fn_t	f = "sbdp_dr_avail";
10741708Sstevel 
10751708Sstevel 	SBDP_DBG_FUNC("%s\n", f);
10761708Sstevel 
10771708Sstevel 	if (sbdp_dr_available)
10781708Sstevel 		if (sg_prom_sb_dr_check() == 0)
10791708Sstevel 			return (1);
10801708Sstevel 	return (0);
10811708Sstevel }
1082