xref: /illumos-gate/usr/src/uts/sun4u/serengeti/io/sbdp.c (revision 07d06da5)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
23*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel #include <sys/types.h>
2803831d35Sstevel #include <sys/cmn_err.h>
2903831d35Sstevel #include <sys/conf.h>
3003831d35Sstevel #include <sys/ddi_impldefs.h>
3103831d35Sstevel #include <sys/autoconf.h>
3203831d35Sstevel #include <sys/systm.h>
3303831d35Sstevel #include <sys/modctl.h>
3403831d35Sstevel #include <sys/ddi.h>
3503831d35Sstevel #include <sys/sunddi.h>
3603831d35Sstevel #include <sys/sunndi.h>
3703831d35Sstevel #include <sys/ndi_impldefs.h>
3803831d35Sstevel #include <sys/promif.h>
3903831d35Sstevel #include <sys/stat.h>
4003831d35Sstevel #include <sys/kmem.h>
4103831d35Sstevel #include <sys/promif.h>
4203831d35Sstevel #include <sys/conf.h>
4303831d35Sstevel #include <sys/obpdefs.h>
4403831d35Sstevel #include <sys/cpuvar.h>
4503831d35Sstevel #include <vm/seg_kmem.h>
4603831d35Sstevel #include <sys/prom_plat.h>
4703831d35Sstevel #include <sys/machsystm.h>
4803831d35Sstevel #include <sys/note.h>
4903831d35Sstevel #include <sys/memlist.h>
5003831d35Sstevel #include <sys/ssm.h>
5103831d35Sstevel 
5203831d35Sstevel #include <sys/sbd_ioctl.h>
5303831d35Sstevel #include <sys/sbd.h>
5403831d35Sstevel #include <sys/sbdp_priv.h>
5503831d35Sstevel #include <sys/sbdp_mem.h>
5603831d35Sstevel #include <sys/sbdp_error.h>
5703831d35Sstevel #include <sys/serengeti.h>
5803831d35Sstevel 
5903831d35Sstevel #include <sys/sgsbbc.h>		/* To get fn_t type definition */
6003831d35Sstevel 
6103831d35Sstevel /*
6203831d35Sstevel  * Config information
6303831d35Sstevel  */
6403831d35Sstevel #ifdef DEBUG
6503831d35Sstevel uint_t sbdp_debug = 0x0;
6603831d35Sstevel #endif /* DEBUG */
6703831d35Sstevel 
6803831d35Sstevel /*
6903831d35Sstevel  * Enable or disable dr
7003831d35Sstevel  */
7103831d35Sstevel int sbdp_dr_available = 1;
7203831d35Sstevel 
7303831d35Sstevel /* name properties for some Serengeti device nodes */
7403831d35Sstevel #define	CMP_DEVNAME		"cmp"
7503831d35Sstevel #define	MEM_DEVNAME		"memory"
7603831d35Sstevel #define	CPU_DEVNAME		"cpu"
7703831d35Sstevel #define	IO_PCI_DEVNAME		"pci"
7803831d35Sstevel #define	IO_SGHSC_DEVNAME	"sghsc"
7903831d35Sstevel #define	IO_WCI_DEVNAME		"wci"
8003831d35Sstevel 
8103831d35Sstevel static	sbd_devattr_t	sbdp_devattr[] = {
8203831d35Sstevel 	{ CMP_DEVNAME,		"cmp",			SBD_COMP_CMP },
8303831d35Sstevel 	{ MEM_DEVNAME,		"memory-controller",	SBD_COMP_MEM },
8403831d35Sstevel 	{ CPU_DEVNAME,		"cpu",			SBD_COMP_CPU },
8503831d35Sstevel 	{ IO_PCI_DEVNAME,	"pci",			SBD_COMP_IO },
8603831d35Sstevel 	{ IO_SGHSC_DEVNAME,	"sghsc",		SBD_COMP_IO },
8703831d35Sstevel 	{ IO_WCI_DEVNAME,	"wci",			SBD_COMP_IO },
8803831d35Sstevel 	/* last item must be blank */
8903831d35Sstevel 	{ NULL,			NULL,			SBD_COMP_UNKNOWN }
9003831d35Sstevel };
9103831d35Sstevel 
9203831d35Sstevel /*
9303831d35Sstevel  * In the case of a busy mbox, if a status cmd comes in we return a cached
9403831d35Sstevel  * copy.  This cache is a link list of wnodes that contains bd structs with
9503831d35Sstevel  * the appropriate info.  When a new wnode is created a whole entry is added
9603831d35Sstevel  * to the list.
9703831d35Sstevel  */
9803831d35Sstevel sbdp_wnode_t	*first_node = NULL; /* first wnode. Entry to the link list */
9903831d35Sstevel int		cur_num_wnodes = 0; /* how many nodes are currently running */
10003831d35Sstevel 
10103831d35Sstevel /* Macros to access fields in the previous array */
10203831d35Sstevel #define	SBDP_CT(i)		sbdp_devattr[i].s_dnodetype
10303831d35Sstevel #define	SBDP_DEVNAME(i)		sbdp_devattr[(i)].s_devname
10403831d35Sstevel #define	SBDP_OTYPE(i)		sbdp_devattr[(i)].s_obp_type
10503831d35Sstevel 
10603831d35Sstevel /*
10703831d35Sstevel  * Prototypes
10803831d35Sstevel  */
10903831d35Sstevel sbdp_wnode_t *sbdp_get_wnodep(int);
11003831d35Sstevel 
11103831d35Sstevel /*
11203831d35Sstevel  * Module linkage information for the kernel.
11303831d35Sstevel  */
11403831d35Sstevel 
11503831d35Sstevel static struct modlmisc modlmisc = {
11603831d35Sstevel 	&mod_miscops,
11703831d35Sstevel 	"Serengeti sbdp",
11803831d35Sstevel };
11903831d35Sstevel 
12003831d35Sstevel static struct modlinkage modlinkage = {
12103831d35Sstevel 	MODREV_1,
12203831d35Sstevel 	(void *)&modlmisc,
12303831d35Sstevel 	NULL
12403831d35Sstevel };
12503831d35Sstevel 
12603831d35Sstevel /*
12703831d35Sstevel  * VA area used during CPU shutdown.
12803831d35Sstevel  */
12903831d35Sstevel caddr_t	sbdp_shutdown_va;
13003831d35Sstevel 
13103831d35Sstevel /*
13203831d35Sstevel  * Mutex to protect our inventory
13303831d35Sstevel  */
13403831d35Sstevel kmutex_t	sbdp_wnode_mutex;
13503831d35Sstevel 
13603831d35Sstevel int
_init(void)13703831d35Sstevel _init(void)
13803831d35Sstevel {
13903831d35Sstevel 	int e;
14003831d35Sstevel 
14103831d35Sstevel 	e = mod_install(&modlinkage);
14203831d35Sstevel 	if (e != 0)
14303831d35Sstevel 		return (e);
14403831d35Sstevel 
14503831d35Sstevel 	sbdp_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
14603831d35Sstevel 	ASSERT(sbdp_shutdown_va != NULL);
14703831d35Sstevel 	sbdp_valp = (uint64_t *)vmem_alloc(static_alloc_arena,
14803831d35Sstevel 	    sizeof (uint64_t), VM_SLEEP);
14903831d35Sstevel 
15003831d35Sstevel 	mutex_init(&sbdp_wnode_mutex, NULL, MUTEX_DRIVER, NULL);
15103831d35Sstevel 	return (e);
15203831d35Sstevel }
15303831d35Sstevel 
15403831d35Sstevel int
_fini(void)15503831d35Sstevel _fini(void)
15603831d35Sstevel {
15703831d35Sstevel 	int e;
15803831d35Sstevel 
15903831d35Sstevel 	/*
16003831d35Sstevel 	 * Remove the module.
16103831d35Sstevel 	 */
16203831d35Sstevel 	e = mod_remove(&modlinkage);
16303831d35Sstevel 	if (e != 0)
16403831d35Sstevel 		return (e);
16503831d35Sstevel 
16603831d35Sstevel 	vmem_free(heap_arena, sbdp_shutdown_va, PAGESIZE);
16703831d35Sstevel 	sbdp_shutdown_va = NULL;
16803831d35Sstevel 	vmem_free(static_alloc_arena, (void *)sbdp_valp, sizeof (uint64_t));
16903831d35Sstevel 	sbdp_valp = NULL;
17003831d35Sstevel 
17103831d35Sstevel 	mutex_destroy(&sbdp_wnode_mutex);
17203831d35Sstevel 	return (e);
17303831d35Sstevel }
17403831d35Sstevel 
17503831d35Sstevel int
_info(struct modinfo * modinfop)17603831d35Sstevel _info(struct modinfo *modinfop)
17703831d35Sstevel {
17803831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
17903831d35Sstevel }
18003831d35Sstevel 
18103831d35Sstevel int
sbdp_get_bd_and_wnode_num(pnode_t nodeid,int * bd,int * wnode)18203831d35Sstevel sbdp_get_bd_and_wnode_num(pnode_t nodeid, int *bd, int *wnode)
18303831d35Sstevel {
18403831d35Sstevel 	int portid;
18503831d35Sstevel 	static fn_t	f = "sbdp_get_bd_and_wnode_num";
18603831d35Sstevel 	extern int	get_portid(pnode_t node, pnode_t *cmpp);
18703831d35Sstevel 
18803831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
18903831d35Sstevel 
19003831d35Sstevel 	if (sbdp_is_node_bad(nodeid))
19103831d35Sstevel 		return (-1);
19203831d35Sstevel 
19303831d35Sstevel 	if ((portid = get_portid(nodeid, NULL)) == -1)
19403831d35Sstevel 		return (-1);
19503831d35Sstevel 
19603831d35Sstevel 	/*
19703831d35Sstevel 	 * decode the board number
19803831d35Sstevel 	 */
19903831d35Sstevel 	*bd = SG_PORTID_TO_BOARD_NUM(portid);
20003831d35Sstevel 	*wnode = SG_PORTID_TO_NODEID(portid);
20103831d35Sstevel 
20203831d35Sstevel 	return (0);
20303831d35Sstevel }
20403831d35Sstevel 
20503831d35Sstevel int
sbdp_get_board_num(sbdp_handle_t * hp,dev_info_t * dip)20603831d35Sstevel sbdp_get_board_num(sbdp_handle_t *hp, dev_info_t *dip)
20703831d35Sstevel {
20803831d35Sstevel 	_NOTE(ARGUNUSED(hp))
20903831d35Sstevel 
21003831d35Sstevel 	pnode_t		nodeid;
21103831d35Sstevel 	int		bd, wnode;
21203831d35Sstevel 	static fn_t	f = "sbdp_get_board_num";
21303831d35Sstevel 
21403831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
21503831d35Sstevel 
21603831d35Sstevel 	if (dip == NULL)
21703831d35Sstevel 		return (-1);
21803831d35Sstevel 
21903831d35Sstevel 	nodeid = ddi_get_nodeid(dip);
22003831d35Sstevel 
22103831d35Sstevel 	/*
22203831d35Sstevel 	 * Portid has encoded the nodeid and the agent id.  The top
22303831d35Sstevel 	 * 4 bits are correspond to the wcnodeid and the lower 5 are the
22403831d35Sstevel 	 * agent id.
22503831d35Sstevel 	 * Each agent id represents a physical location hence we can
22603831d35Sstevel 	 * obtain the board number
22703831d35Sstevel 	 */
22803831d35Sstevel 	if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0)
22903831d35Sstevel 		return (-1);
23003831d35Sstevel 
23103831d35Sstevel 	return (bd);
23203831d35Sstevel }
23303831d35Sstevel 
23403831d35Sstevel 
23503831d35Sstevel sbd_devattr_t *
sbdp_get_devattr(void)23603831d35Sstevel sbdp_get_devattr(void)
23703831d35Sstevel {
23803831d35Sstevel 	return (&sbdp_devattr[0]);
23903831d35Sstevel }
24003831d35Sstevel 
24103831d35Sstevel int
sbdp_portid_to_cpu_unit(int cmp,int core)24203831d35Sstevel sbdp_portid_to_cpu_unit(int cmp, int core)
24303831d35Sstevel {
24403831d35Sstevel 	return (SG_PORTID_TO_CPU_UNIT(cmp, core));
24503831d35Sstevel }
24603831d35Sstevel 
24703831d35Sstevel int
sbdp_get_unit_num(sbdp_handle_t * hp,dev_info_t * dip)24803831d35Sstevel sbdp_get_unit_num(sbdp_handle_t *hp, dev_info_t *dip)
24903831d35Sstevel {
25003831d35Sstevel 	int		unit = -1;
25103831d35Sstevel 	int		portid;
25203831d35Sstevel 	processorid_t	cpuid;
25303831d35Sstevel 	sbd_comp_type_t	type;
25403831d35Sstevel 	char		dev_type[OBP_MAXPROPNAME];
25503831d35Sstevel 	int		i;
25603831d35Sstevel 	pnode_t		nodeid;
25703831d35Sstevel 	static fn_t	f = "sbdp_get_unit_num";
25803831d35Sstevel 
25903831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
26003831d35Sstevel 
26103831d35Sstevel 	if (dip == NULL)
26203831d35Sstevel 		return (-1);
26303831d35Sstevel 
26403831d35Sstevel 	nodeid = ddi_get_nodeid(dip);
26503831d35Sstevel 
26603831d35Sstevel 	if (sbdp_is_node_bad(nodeid))
26703831d35Sstevel 		return (-1);
26803831d35Sstevel 
26903831d35Sstevel 	if (prom_getprop(nodeid, "device_type", (caddr_t)dev_type) < 0) {
27003831d35Sstevel 		SBDP_DBG_MISC("%s: couldn't get device_type\n", f);
27103831d35Sstevel 		return (-1);
27203831d35Sstevel 	}
27303831d35Sstevel 
27403831d35Sstevel 	for (i = 0; SBDP_CT(i) != SBD_COMP_UNKNOWN; i++) {
27503831d35Sstevel 		if (strcmp(dev_type, SBDP_OTYPE(i)) != 0)
27603831d35Sstevel 			continue;
27703831d35Sstevel 		type = SBDP_CT(i);
27803831d35Sstevel 	}
27903831d35Sstevel 
28003831d35Sstevel 	switch (type) {
28103831d35Sstevel 	case SBD_COMP_CPU:
28203831d35Sstevel 		if ((cpuid = sbdp_get_cpuid(hp, dip)) != -1) {
28303831d35Sstevel 			unit = SG_CPUID_TO_CPU_UNIT(cpuid);
28403831d35Sstevel 		}
28503831d35Sstevel 		break;
28603831d35Sstevel 	case SBD_COMP_MEM:
28703831d35Sstevel 		unit = 0;
28803831d35Sstevel 		break;
28903831d35Sstevel 	case SBD_COMP_IO: {
29003831d35Sstevel 		regspace_t	regs[3];
29103831d35Sstevel 		int		len = 0;
29203831d35Sstevel 
29303831d35Sstevel 		/*
29403831d35Sstevel 		 * Check to see if this is a cpci node
29503831d35Sstevel 		 * cpci nodes are assign unit nums of 5 for now
29603831d35Sstevel 		 * So they don't conflict with the pci unit nums
29703831d35Sstevel 		 */
29803831d35Sstevel 
29903831d35Sstevel 		if (strcmp(dev_type, "sghsc") == 0) {
30003831d35Sstevel 			SBDP_DBG_MISC("it is a sghsc\n");
30103831d35Sstevel 			return (4);
30203831d35Sstevel 		}
30303831d35Sstevel 
30403831d35Sstevel 		if (prom_getprop(nodeid, "portid", (caddr_t)&portid) <= 0) {
30503831d35Sstevel 			SBDP_DBG_MISC("%s: couldn't get portid\n", f);
30603831d35Sstevel 			return (-1);
30703831d35Sstevel 		}
30803831d35Sstevel 
30903831d35Sstevel 		len = prom_getproplen(nodeid, "reg");
31003831d35Sstevel 		if (len <= 0) {
31103831d35Sstevel 			SBDP_DBG_MISC("%s: couldn't get length\n", f);
31203831d35Sstevel 			return (-1);
31303831d35Sstevel 		}
31403831d35Sstevel 
31503831d35Sstevel 		if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0) {
31603831d35Sstevel 			SBDP_DBG_MISC("%s: couldn't get registers\n", f);
31703831d35Sstevel 			return (-1);
31803831d35Sstevel 		}
31903831d35Sstevel 
32003831d35Sstevel 		if ((portid % 2) != 0)
32103831d35Sstevel 			if ((regs[0].regspec_addr_lo & 0x700000) ==
322*07d06da5SSurya Prakki 			    0x700000)
32303831d35Sstevel 				unit = 0;
32403831d35Sstevel 			else
32503831d35Sstevel 				unit = 1;
32603831d35Sstevel 		else
32703831d35Sstevel 			if ((regs[0].regspec_addr_lo & 0x700000) ==
32803831d35Sstevel 			    0x700000)
32903831d35Sstevel 				unit = 2;
33003831d35Sstevel 			else
33103831d35Sstevel 				unit = 3;
33203831d35Sstevel 
33303831d35Sstevel 		SBDP_DBG_MISC("unit is %d\n", unit);
33403831d35Sstevel 		break;
33503831d35Sstevel 	}
33603831d35Sstevel 	default:
33703831d35Sstevel 		break;
33803831d35Sstevel 
33903831d35Sstevel 	}
34003831d35Sstevel 
34103831d35Sstevel 	return (unit);
34203831d35Sstevel }
34303831d35Sstevel 
34403831d35Sstevel struct sbdp_mem_dip {
34503831d35Sstevel 	sbdp_bd_t	*bdp;
34603831d35Sstevel 	dev_info_t	*dip;
34703831d35Sstevel };
34803831d35Sstevel 
34903831d35Sstevel static int
sbdp_get_mem_dip(pnode_t node,void * arg,uint_t flags)35003831d35Sstevel sbdp_get_mem_dip(pnode_t node, void *arg, uint_t flags)
35103831d35Sstevel {
35203831d35Sstevel 	_NOTE(ARGUNUSED(flags))
35303831d35Sstevel 
35403831d35Sstevel 	struct sbdp_mem_dip	*smdp = (struct sbdp_mem_dip *)arg;
35503831d35Sstevel 	mem_op_t	mem = {0};
35603831d35Sstevel 
35703831d35Sstevel 	if (node == OBP_NONODE || node == OBP_BADNODE)
35803831d35Sstevel 		return (DDI_FAILURE);
35903831d35Sstevel 
36003831d35Sstevel 	mem.nodes = smdp->bdp->nodes;
36103831d35Sstevel 	mem.board = smdp->bdp->bd;
36203831d35Sstevel 	mem.nmem  = smdp->bdp->nnum;
36303831d35Sstevel 
36403831d35Sstevel 	(void) sbdp_is_mem(node, &mem);
36503831d35Sstevel 
36603831d35Sstevel 	/*
36703831d35Sstevel 	 * We need to find the dip only for the first nodeid
36803831d35Sstevel 	 */
36903831d35Sstevel 	if (smdp->bdp->nnum == 0 && mem.nmem == 1) {
37003831d35Sstevel 		ASSERT(smdp->dip == NULL);
37103831d35Sstevel 		smdp->dip = e_ddi_nodeid_to_dip(node);
37203831d35Sstevel 	}
37303831d35Sstevel 
37403831d35Sstevel 	smdp->bdp->nnum = mem.nmem;
37503831d35Sstevel 
37603831d35Sstevel 	return (DDI_SUCCESS);
37703831d35Sstevel }
37803831d35Sstevel 
37903831d35Sstevel 
38003831d35Sstevel /*
38103831d35Sstevel  * Update the board info.  Required after a copy rename
38203831d35Sstevel  */
38303831d35Sstevel void
sbdp_update_bd_info(sbdp_bd_t * bdp)38403831d35Sstevel sbdp_update_bd_info(sbdp_bd_t *bdp)
38503831d35Sstevel {
38603831d35Sstevel 	attach_pkt_t		apkt, *apktp = &apkt;
38703831d35Sstevel 	struct sbdp_mem_dip	smd = {0};
38803831d35Sstevel 	static fn_t	f = "sbdp_update_bd_info";
38903831d35Sstevel 
39003831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
39103831d35Sstevel 
39203831d35Sstevel 	if (bdp == NULL) {
39303831d35Sstevel 		return;
39403831d35Sstevel 	}
39503831d35Sstevel 	/*
39603831d35Sstevel 	 * Grab the lock
39703831d35Sstevel 	 */
39803831d35Sstevel 	mutex_enter(&bdp->bd_mutex);
39903831d35Sstevel 
40003831d35Sstevel 	/*
40103831d35Sstevel 	 * we get the top nodes here.  This will have a side effect of
40203831d35Sstevel 	 * updating the present bit for cpus
40303831d35Sstevel 	 */
40403831d35Sstevel 	apktp->node = bdp->wnode;
40503831d35Sstevel 	apktp->board = bdp->bd;
40603831d35Sstevel 	apktp->num_of_nodes = 0;
40703831d35Sstevel 	apktp->flags = 0;
40803831d35Sstevel 	sbdp_walk_prom_tree(prom_rootnode(), sbdp_select_top_nodes,
40903831d35Sstevel 	    (void *) apktp);
41003831d35Sstevel 
41103831d35Sstevel 	/*
41203831d35Sstevel 	 * We need to clear nnum since we are looking again for the
41303831d35Sstevel 	 * nodes
41403831d35Sstevel 	 */
41503831d35Sstevel 	bdp->nnum = 0;
41603831d35Sstevel 	smd.bdp = bdp;
41703831d35Sstevel 
41803831d35Sstevel 	/*
41903831d35Sstevel 	 * If a dip is found by sbdp_get_mem_dip(), it will be
42003831d35Sstevel 	 * returned held
42103831d35Sstevel 	 */
42203831d35Sstevel 	sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &smd);
42303831d35Sstevel 	if (smd.dip != NULL) {
42403831d35Sstevel 		sbdp_handle_t		*hp;
42503831d35Sstevel 
42603831d35Sstevel 		hp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP);
42703831d35Sstevel 		hp->h_board = bdp->bd;
42803831d35Sstevel 		hp->h_wnode = bdp->wnode;
42903831d35Sstevel 		hp->h_err = kmem_zalloc(sizeof (*hp->h_err), KM_SLEEP);
43003831d35Sstevel 		if (bdp->ml != NULL) {
431*07d06da5SSurya Prakki 			(void) sbdp_del_memlist(hp, bdp->ml);
43203831d35Sstevel 		}
43303831d35Sstevel 		bdp->ml = sbdp_get_memlist(hp, (dev_info_t *)NULL);
43403831d35Sstevel 		/*
43503831d35Sstevel 		 * if the board doesn't have banks initialize them,
43603831d35Sstevel 		 * otherwise we assume they have been updated if
43703831d35Sstevel 		 * necessary
43803831d35Sstevel 		 */
43903831d35Sstevel 		if (bdp->banks == NULL) {
44003831d35Sstevel 			sbdp_init_bd_banks(bdp);
44103831d35Sstevel 		}
44203831d35Sstevel #ifdef DEBUG
44303831d35Sstevel 		sbdp_print_bd_banks(bdp);
44403831d35Sstevel #endif
44503831d35Sstevel 
44603831d35Sstevel 		if (sbdphw_get_base_physaddr(hp, smd.dip, &bdp->bpa))
44703831d35Sstevel 			bdp->bpa = -1;
44803831d35Sstevel 		ddi_release_devi(smd.dip);
44903831d35Sstevel 		kmem_free(hp->h_err, sizeof (*hp->h_err));
45003831d35Sstevel 		kmem_free(hp, sizeof (sbdp_handle_t));
45103831d35Sstevel 	}
45203831d35Sstevel 	mutex_exit(&bdp->bd_mutex);
45303831d35Sstevel }
45403831d35Sstevel 
45503831d35Sstevel /*
45603831d35Sstevel  * Initialize the board struct.  This remains cached.  We update it
45703831d35Sstevel  * every time we have a successful show_board and after a copy-rename
45803831d35Sstevel  */
45903831d35Sstevel void
sbdp_bd_init(sbdp_bd_t * bdp,int bd,int wnode)46003831d35Sstevel sbdp_bd_init(sbdp_bd_t *bdp, int bd, int wnode)
46103831d35Sstevel {
46203831d35Sstevel 	static fn_t	f = "sbdp_bd_init";
46303831d35Sstevel 
46403831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
46503831d35Sstevel 
46603831d35Sstevel 	bdp->bd = bd;
46703831d35Sstevel 	bdp->wnode = wnode;
46803831d35Sstevel 
46903831d35Sstevel 	SBDP_UNSET_ALL_CPUS_IN_RESET(bdp);
47003831d35Sstevel 
47103831d35Sstevel 	bdp->cpus_present = 0;
47203831d35Sstevel 
47303831d35Sstevel 	sbdp_update_bd_info(bdp);
47403831d35Sstevel 
47503831d35Sstevel 	mutex_init(&bdp->bd_mutex, NULL, MUTEX_DRIVER, NULL);
47603831d35Sstevel 	bdp->bd_sc = (show_board_t *)kmem_zalloc(sizeof (show_board_t),
47703831d35Sstevel 	    KM_SLEEP);
47803831d35Sstevel 	bdp->valid_cp = -1;
47903831d35Sstevel }
48003831d35Sstevel 
48103831d35Sstevel /*
48203831d35Sstevel  * This entry is going away.  Clean up
48303831d35Sstevel  */
48403831d35Sstevel void
sbdp_bd_fini(sbdp_bd_t * bdp)48503831d35Sstevel sbdp_bd_fini(sbdp_bd_t *bdp)
48603831d35Sstevel {
48703831d35Sstevel 	static fn_t	f = "sbdp_bd_fini";
48803831d35Sstevel 
48903831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
49003831d35Sstevel 
49103831d35Sstevel 	sbdp_cleanup_bd(bdp->wnode, bdp->bd);
49203831d35Sstevel 	kmem_free(bdp->bd_sc, sizeof (show_board_t));
49303831d35Sstevel 	bdp->bd_sc = NULL;
49403831d35Sstevel 	mutex_destroy(&bdp->bd_mutex);
49503831d35Sstevel #ifdef DEBUG
49603831d35Sstevel 	sbdp_print_all_segs();
49703831d35Sstevel #endif
49803831d35Sstevel }
49903831d35Sstevel 
50003831d35Sstevel /*
50103831d35Sstevel  * A new wnode has arrived.  Initialize the struct and create
50203831d35Sstevel  * the board structures.
50303831d35Sstevel  */
50403831d35Sstevel void
sbdp_wnode_init(sbdp_wnode_t * wnodep,int wnode,int boards)50503831d35Sstevel sbdp_wnode_init(sbdp_wnode_t *wnodep, int wnode, int boards)
50603831d35Sstevel {
50703831d35Sstevel 	int		i;
50803831d35Sstevel 	static fn_t	f = "sbdp_wnode_init";
50903831d35Sstevel 
51003831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
51103831d35Sstevel 
51203831d35Sstevel 	wnodep->wnode = wnode;
51303831d35Sstevel 	wnodep->nbds = boards;
51403831d35Sstevel 	wnodep->bds = kmem_zalloc(sizeof (sbdp_bd_t) * boards, KM_SLEEP);
51503831d35Sstevel 	wnodep->next = wnodep->prev = NULL;
51603831d35Sstevel 
51703831d35Sstevel 	for (i = 0; i < boards; i++)
51803831d35Sstevel 		sbdp_bd_init(&wnodep->bds[i], i, wnode);
51903831d35Sstevel }
52003831d35Sstevel 
52103831d35Sstevel /*
52203831d35Sstevel  * Wnode got DRed out.  Clean up all the node stuff including the boards
52303831d35Sstevel  */
52403831d35Sstevel void
sbdp_wnode_fini(sbdp_wnode_t * wnodep)52503831d35Sstevel sbdp_wnode_fini(sbdp_wnode_t *wnodep)
52603831d35Sstevel {
52703831d35Sstevel 	int	boards;
52803831d35Sstevel 	int	i;
52903831d35Sstevel 	static fn_t	f = "sbdp_wnode_fini";
53003831d35Sstevel 
53103831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
53203831d35Sstevel 
53303831d35Sstevel 	boards = wnodep->nbds;
53403831d35Sstevel 
53503831d35Sstevel 	for (i = 0; i < boards; i++)
53603831d35Sstevel 		sbdp_bd_fini(&wnodep->bds[i]);
53703831d35Sstevel 
53803831d35Sstevel 	kmem_free(wnodep->bds, sizeof (sbdp_bd_t) * boards);
53903831d35Sstevel 	wnodep->next = wnodep->prev = NULL;
54003831d35Sstevel 	kmem_free(wnodep, sizeof (sbdp_wnode_t));
54103831d35Sstevel }
54203831d35Sstevel 
54303831d35Sstevel /*
54403831d35Sstevel  * Add all the necessary fields to this board's struct
54503831d35Sstevel  */
54603831d35Sstevel void
sbdp_add_new_bd_info(int wnode,int board)54703831d35Sstevel sbdp_add_new_bd_info(int wnode, int board)
54803831d35Sstevel {
54903831d35Sstevel 	sbdp_wnode_t	*cur;
55003831d35Sstevel 	static fn_t	f = "sbdp_add_new_bd_info";
55103831d35Sstevel 
55203831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
55303831d35Sstevel 
55403831d35Sstevel 	cur = sbdp_get_wnodep(wnode);
55503831d35Sstevel 
55603831d35Sstevel 	SBDP_DBG_MISC("adding new board info %d\n", board);
55703831d35Sstevel 
55803831d35Sstevel 	sbdp_update_bd_info(&cur->bds[board]);
55903831d35Sstevel 
56003831d35Sstevel }
56103831d35Sstevel 
56203831d35Sstevel /*
56303831d35Sstevel  * This board has gone away.  Clean the necessary fields
56403831d35Sstevel  */
56503831d35Sstevel void
sbdp_cleanup_bd(int wnode,int board)56603831d35Sstevel sbdp_cleanup_bd(int wnode, int board)
56703831d35Sstevel {
56803831d35Sstevel 	sbdp_wnode_t	*cur;
56903831d35Sstevel 	sbdp_handle_t	handle, *hp;
57003831d35Sstevel 	sbdp_bd_t	*bdp;
57103831d35Sstevel 	int		i;
57203831d35Sstevel 	static fn_t	f = "sbdp_cleanup_bd";
57303831d35Sstevel 
57403831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
57503831d35Sstevel 
57603831d35Sstevel 	cur = sbdp_get_wnodep(wnode);
57703831d35Sstevel 
57803831d35Sstevel 	SBDP_DBG_MISC("cleaning up bd info for bd %d\n", board);
57903831d35Sstevel 	if (cur == NULL) {
58003831d35Sstevel 		SBDP_DBG_MISC("cur is null\n");
58103831d35Sstevel 		return;
58203831d35Sstevel 	}
58303831d35Sstevel 
58403831d35Sstevel 	bdp = &cur->bds[board];
58503831d35Sstevel 
58603831d35Sstevel 	/*
58703831d35Sstevel 	 * Grab the lock
58803831d35Sstevel 	 */
58903831d35Sstevel 	mutex_enter(&bdp->bd_mutex);
59003831d35Sstevel 
59103831d35Sstevel 	for (i = 0; i < bdp->nnum; i++)
59203831d35Sstevel 		bdp->nodes[i] = (pnode_t)0;
59303831d35Sstevel 	bdp->nnum = 0;
59403831d35Sstevel 
59503831d35Sstevel 	sbdp_fini_bd_banks(bdp);
59603831d35Sstevel 
59703831d35Sstevel 	hp = &handle;
59803831d35Sstevel 	hp->h_board = bdp->bd;
59903831d35Sstevel 	hp->h_wnode = bdp->wnode;
60003831d35Sstevel 	if (bdp->ml) {
601*07d06da5SSurya Prakki 		(void) sbdp_del_memlist(hp, bdp->ml);
60203831d35Sstevel 	}
60303831d35Sstevel 
60403831d35Sstevel 	bdp->ml = NULL;
60503831d35Sstevel 
60603831d35Sstevel 	bdp->bpa = -1;
60703831d35Sstevel 
60803831d35Sstevel 	sbdp_cpu_in_reset(wnode, bdp->bd, SBDP_ALL_CPUS, 0);
60903831d35Sstevel 
61003831d35Sstevel 	bdp->cpus_present = 0;
61103831d35Sstevel 
61203831d35Sstevel 	mutex_exit(&bdp->bd_mutex);
61303831d35Sstevel }
61403831d35Sstevel 
61503831d35Sstevel /*
61603831d35Sstevel  *  Traverse the list looking for wnode. Return it when found
61703831d35Sstevel  */
61803831d35Sstevel sbdp_wnode_t *
sbdp_get_wnodep(int wnode)61903831d35Sstevel sbdp_get_wnodep(int wnode)
62003831d35Sstevel {
62103831d35Sstevel 	sbdp_wnode_t	*cur;
62203831d35Sstevel 	int		i;
62303831d35Sstevel 	static fn_t	f = "sbdp_get_wnodep";
62403831d35Sstevel 
62503831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
62603831d35Sstevel 
62703831d35Sstevel 	mutex_enter(&sbdp_wnode_mutex);
62803831d35Sstevel 	for (i = 0, cur = first_node; i < cur_num_wnodes; i++,
62903831d35Sstevel 	    cur = cur->next) {
63003831d35Sstevel 		if (cur->wnode == wnode) {
63103831d35Sstevel 			mutex_exit(&sbdp_wnode_mutex);
63203831d35Sstevel 			return (cur);
63303831d35Sstevel 		}
63403831d35Sstevel 	}
63503831d35Sstevel 	mutex_exit(&sbdp_wnode_mutex);
63603831d35Sstevel 
63703831d35Sstevel 	return (NULL);
63803831d35Sstevel }
63903831d35Sstevel 
64003831d35Sstevel /*
64103831d35Sstevel  * Insert this brand new node into our master list. It leaves it all
64203831d35Sstevel  * initialized
64303831d35Sstevel  */
64403831d35Sstevel void
sbdp_insert_wnode(int wnode,int max_boards)64503831d35Sstevel sbdp_insert_wnode(int wnode, int max_boards)
64603831d35Sstevel {
64703831d35Sstevel 	sbdp_wnode_t	*wnodep;
64803831d35Sstevel 	sbdp_wnode_t	*cur;
64903831d35Sstevel 	static fn_t	f = "sbdp_insert_wnode";
65003831d35Sstevel 
65103831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
65203831d35Sstevel 
65303831d35Sstevel 	wnodep = kmem_zalloc(sizeof (sbdp_wnode_t), KM_SLEEP);
65403831d35Sstevel 
65503831d35Sstevel 	mutex_enter(&sbdp_wnode_mutex);
65603831d35Sstevel 	if (first_node == NULL) {
65703831d35Sstevel 		first_node = wnodep;
65803831d35Sstevel 		cur_num_wnodes++;
65903831d35Sstevel 	} else {
66003831d35Sstevel 		cur = first_node + cur_num_wnodes++;
66103831d35Sstevel 		cur->next = wnodep;
66203831d35Sstevel 		wnodep->prev = cur;
66303831d35Sstevel 	}
66403831d35Sstevel 	mutex_exit(&sbdp_wnode_mutex);
66503831d35Sstevel 	sbdp_wnode_init(wnodep, wnode, max_boards);
66603831d35Sstevel }
66703831d35Sstevel 
66803831d35Sstevel /*
66903831d35Sstevel  * This node is gone.  Remove it from the list and also clean up
67003831d35Sstevel  */
67103831d35Sstevel void
sbdp_remove_wnode(sbdp_wnode_t * wnodep)67203831d35Sstevel sbdp_remove_wnode(sbdp_wnode_t *wnodep)
67303831d35Sstevel {
67403831d35Sstevel 	sbdp_wnode_t	*cur;
67503831d35Sstevel 	static fn_t	f = "sbdp_remove_wnode";
67603831d35Sstevel 
67703831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
67803831d35Sstevel 
67903831d35Sstevel 	if (wnodep != NULL) {
68003831d35Sstevel 		sbdp_wnode_fini(wnodep);
68103831d35Sstevel 		mutex_enter(&sbdp_wnode_mutex);
68203831d35Sstevel 
68303831d35Sstevel 		if (first_node == wnodep)
68403831d35Sstevel 			first_node = NULL;
68503831d35Sstevel 		else {
68603831d35Sstevel 			cur = wnodep->prev;
68703831d35Sstevel 			if (cur != NULL)
68803831d35Sstevel 				cur->next = wnodep->next;
68903831d35Sstevel 			if (wnodep->next != NULL)
69003831d35Sstevel 				wnodep->next->prev = cur;
69103831d35Sstevel 		}
69203831d35Sstevel 
69303831d35Sstevel 		cur_num_wnodes--;
69403831d35Sstevel 		mutex_exit(&sbdp_wnode_mutex);
69503831d35Sstevel 	}
69603831d35Sstevel }
69703831d35Sstevel 
69803831d35Sstevel /*
69903831d35Sstevel  * Entry point from sbd.  This is called when a new node is added.  We
70003831d35Sstevel  * create an entry in our inventory and initialize all the stuff that will be
70103831d35Sstevel  * needed
70203831d35Sstevel  */
70303831d35Sstevel int
sbdp_setup_instance(caddr_t arg)70403831d35Sstevel sbdp_setup_instance(caddr_t arg)
70503831d35Sstevel {
70603831d35Sstevel 	ssm_sbdp_info_t	*sbdp_info;
70703831d35Sstevel 	int		instance;
70803831d35Sstevel 	int		wnode;
70903831d35Sstevel 	int		max_boards;
71003831d35Sstevel 	static fn_t	f = "sbdp_setup_instance";
71103831d35Sstevel 
71203831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
71303831d35Sstevel 
71403831d35Sstevel 	/*
71503831d35Sstevel 	 * We get this directly from ssm
71603831d35Sstevel 	 */
71703831d35Sstevel 	sbdp_info = (ssm_sbdp_info_t *)arg;
71803831d35Sstevel 
71903831d35Sstevel 	instance = sbdp_info->instance;
72003831d35Sstevel 	wnode = sbdp_info->wnode;
72103831d35Sstevel 	max_boards = plat_max_boards();
72203831d35Sstevel 
72303831d35Sstevel 	SBDP_DBG_MISC("sbdp_setup_instance: instance %d wnode %d\n", instance,
72403831d35Sstevel 	    sbdp_info->wnode);
72503831d35Sstevel 
72603831d35Sstevel 	if (sbdp_get_wnodep(wnode) == NULL) {
72703831d35Sstevel 		/*
72803831d35Sstevel 		 * This node has not been instanstiated
72903831d35Sstevel 		 * create one
73003831d35Sstevel 		 */
73103831d35Sstevel 		sbdp_insert_wnode(wnode, max_boards);
73203831d35Sstevel 	}
73303831d35Sstevel 
73403831d35Sstevel 	return (DDI_SUCCESS);
73503831d35Sstevel }
73603831d35Sstevel 
73703831d35Sstevel /*
73803831d35Sstevel  * Entry point from sbd. This is called when a node has been removed (or is
73903831d35Sstevel  * going away. We do all the necessary cleanup
74003831d35Sstevel  */
74103831d35Sstevel int
sbdp_teardown_instance(caddr_t arg)74203831d35Sstevel sbdp_teardown_instance(caddr_t arg)
74303831d35Sstevel {
74403831d35Sstevel 	ssm_sbdp_info_t	*sbdp_info;
74503831d35Sstevel 	int		instance;
74603831d35Sstevel 	int		wnode;
74703831d35Sstevel 	sbdp_wnode_t	*wnodep;
74803831d35Sstevel 	static fn_t	f = "sbdp_teardown_instance";
74903831d35Sstevel 
75003831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
75103831d35Sstevel 
75203831d35Sstevel 	/*
75303831d35Sstevel 	 * ssm should have set this up
75403831d35Sstevel 	 */
75503831d35Sstevel 	sbdp_info = (ssm_sbdp_info_t *)arg;
75603831d35Sstevel 
75703831d35Sstevel 	instance = sbdp_info->instance;
75803831d35Sstevel 	wnode = sbdp_info->wnode;
75903831d35Sstevel 
76003831d35Sstevel 	SBDP_DBG_MISC("sbdp_teardown_instance: instance %d wnode %d\n",
76103831d35Sstevel 	    instance, wnode);
76203831d35Sstevel 
76303831d35Sstevel 	/*
76403831d35Sstevel 	 * Find this node and then remove it
76503831d35Sstevel 	 */
76603831d35Sstevel 	if ((wnodep = sbdp_get_wnodep(wnode)) != NULL) {
76703831d35Sstevel 		sbdp_remove_wnode(wnodep);
76803831d35Sstevel 	}
76903831d35Sstevel 	return (DDI_SUCCESS);
77003831d35Sstevel }
77103831d35Sstevel 
77203831d35Sstevel int
sbdp_disabled_component(sbdp_handle_t * hp)77303831d35Sstevel sbdp_disabled_component(sbdp_handle_t *hp)
77403831d35Sstevel {
77503831d35Sstevel #ifdef lint
77603831d35Sstevel 	hp = hp;
77703831d35Sstevel #endif
77803831d35Sstevel 	return (0);
77903831d35Sstevel }
78003831d35Sstevel 
78103831d35Sstevel /* ARGSUSED */
78203831d35Sstevel int
sbdp_release_component(sbdp_handle_t * hp,dev_info_t * dip)78303831d35Sstevel sbdp_release_component(sbdp_handle_t *hp, dev_info_t *dip)
78403831d35Sstevel {
78503831d35Sstevel 	return (0);
78603831d35Sstevel }
78703831d35Sstevel 
78803831d35Sstevel void
sbdp_set_err(sbd_error_t * ep,int ecode,char * rsc)78903831d35Sstevel sbdp_set_err(sbd_error_t *ep, int ecode, char *rsc)
79003831d35Sstevel {
79103831d35Sstevel 	static fn_t	f = "sbdp_set_err";
79203831d35Sstevel 
79303831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
79403831d35Sstevel 	ASSERT(ep != NULL);
79503831d35Sstevel 	ep->e_code = ecode;
79603831d35Sstevel 
79703831d35Sstevel 	if (rsc != NULL) {
79803831d35Sstevel 		(void) strcpy((caddr_t)(ep->e_rsc), (caddr_t)rsc);
79903831d35Sstevel 	}
80003831d35Sstevel }
80103831d35Sstevel 
80203831d35Sstevel /*
80303831d35Sstevel  * Serengeti DR passthrus are for debugging purposes only.
80403831d35Sstevel  */
80503831d35Sstevel static struct {
80603831d35Sstevel 	const char	*name;
80703831d35Sstevel 	int		(*handler)(sbdp_handle_t *, void *);
80803831d35Sstevel } sbdp_passthrus[] = {
80903831d35Sstevel #ifdef DEBUG
81003831d35Sstevel 	{ "readmem",		sbdp_passthru_readmem		},
81103831d35Sstevel 	{ "prep-script",	sbdp_passthru_prep_script	},
81203831d35Sstevel 	{ "test-quiesce",	sbdp_passthru_test_quiesce	},
81303831d35Sstevel 	{ "inject-error",	sbdp_passthru_inject_error	},
81403831d35Sstevel 	{ "reset-error",	sbdp_passthru_reset_error	},
81503831d35Sstevel #endif
81603831d35Sstevel 
81703831d35Sstevel 	/* the following line must always be last */
81803831d35Sstevel 	{ NULL,			NULL				}
81903831d35Sstevel };
82003831d35Sstevel 
82103831d35Sstevel 
82203831d35Sstevel /*ARGSUSED*/
82303831d35Sstevel int
sbdp_ioctl(sbdp_handle_t * hp,sbdp_ioctl_arg_t * sbdpi)82403831d35Sstevel sbdp_ioctl(sbdp_handle_t *hp, sbdp_ioctl_arg_t *sbdpi)
82503831d35Sstevel {
82603831d35Sstevel #ifdef DEBUG
82703831d35Sstevel 	char buf[512];
82803831d35Sstevel 	int rv;
82903831d35Sstevel 	sbd_ioctl_arg_t *sbdi   = (sbd_ioctl_arg_t *)sbdpi->h_iap;
83003831d35Sstevel 	int		i;
83103831d35Sstevel 	static fn_t	f = "sbdp_ioctl";
83203831d35Sstevel 
83303831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
83403831d35Sstevel 
83503831d35Sstevel 	if (sbdi->i_len >= sizeof (buf) ||
83603831d35Sstevel 	    ddi_copyin(sbdi->i_opts, buf, sbdi->i_len, sbdpi->h_mode)) {
83703831d35Sstevel 		sbdp_set_err(hp->h_err, ESBD_FAULT, NULL);
83803831d35Sstevel 		return (-1);
83903831d35Sstevel 	}
84003831d35Sstevel 
84103831d35Sstevel 	i = 0;
84203831d35Sstevel 	while (sbdp_passthrus[i].name != NULL) {
84303831d35Sstevel 		int	len;
84403831d35Sstevel 
84503831d35Sstevel 		len = strlen(sbdp_passthrus[i].name);
84603831d35Sstevel 		if (strncmp(sbdp_passthrus[i].name, buf, len) == 0)
84703831d35Sstevel 			break;
84803831d35Sstevel 		i++;
84903831d35Sstevel 	}
85003831d35Sstevel 
85103831d35Sstevel 	if (sbdp_passthrus[i].name == NULL) {
85203831d35Sstevel 		sbdp_set_err(hp->h_err, ESBD_INVAL, NULL);
85303831d35Sstevel 		rv = EIO;
85403831d35Sstevel 	} else {
85503831d35Sstevel 		rv = (*sbdp_passthrus[i].handler)(hp, buf);
85603831d35Sstevel 		if (rv != ESBD_NOERROR) {
85703831d35Sstevel 			sbdp_set_err(hp->h_err, rv, NULL);
85803831d35Sstevel 			rv = EIO;
85903831d35Sstevel 		}
86003831d35Sstevel 
86103831d35Sstevel 	}
86203831d35Sstevel 
86303831d35Sstevel 	return (rv);
86403831d35Sstevel #else
86503831d35Sstevel 	return (0);
86603831d35Sstevel #endif
86703831d35Sstevel }
86803831d35Sstevel 
86903831d35Sstevel /*
87003831d35Sstevel  * Check the dnode we obtained.  Need to find a better way to determine
87103831d35Sstevel  * if the node has the correct starting address
87203831d35Sstevel  */
87303831d35Sstevel int
sbdp_is_node_bad(pnode_t node)87403831d35Sstevel sbdp_is_node_bad(pnode_t node)
87503831d35Sstevel {
87603831d35Sstevel 	static fn_t	f = "sbdp_is_node_bad";
87703831d35Sstevel 
87803831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
87903831d35Sstevel 
88003831d35Sstevel 	return ((node == OBP_NONODE) || (node == OBP_BADNODE) ||
88103831d35Sstevel 	    ((node & 0x80000000u) != 0x80000000u));
88203831d35Sstevel }
88303831d35Sstevel 
88403831d35Sstevel /*
88503831d35Sstevel  * Retrieve the information we have on this board from
88603831d35Sstevel  * the inventory
88703831d35Sstevel  */
88803831d35Sstevel sbdp_bd_t *
sbdp_get_bd_info(int wnode,int board)88903831d35Sstevel sbdp_get_bd_info(int wnode, int board)
89003831d35Sstevel {
89103831d35Sstevel 	sbdp_wnode_t	*wnodep;
89203831d35Sstevel 	sbdp_bd_t	*bdp;
89303831d35Sstevel 	int		max_bds;
89403831d35Sstevel 	static fn_t	f = "sbdp_get_bd_info";
89503831d35Sstevel 
89603831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
89703831d35Sstevel 
89803831d35Sstevel 	wnodep = sbdp_get_wnodep(wnode);
89903831d35Sstevel 	max_bds = plat_max_boards();
90003831d35Sstevel 
90103831d35Sstevel 	if ((wnodep == NULL) || ((board < 0) && (board > max_bds))) {
90203831d35Sstevel 		return (NULL);
90303831d35Sstevel 	}
90403831d35Sstevel 
90503831d35Sstevel 	bdp = &wnodep->bds[board];
90603831d35Sstevel 
90703831d35Sstevel 	/*
90803831d35Sstevel 	 * We might not have the complete bd info.  With cheetah we
90903831d35Sstevel 	 * cannot access the memory decode registers when then cpu is
91003831d35Sstevel 	 * in reset. If the mem info is incomplete, then we try to gather it
91103831d35Sstevel 	 * here
91203831d35Sstevel 	 */
91303831d35Sstevel 	sbdp_update_bd_info(bdp);
91403831d35Sstevel 
91503831d35Sstevel 	return (bdp);
91603831d35Sstevel }
91703831d35Sstevel 
91803831d35Sstevel /*
91903831d35Sstevel  * There are certain cases where obp marks components as failed
92003831d35Sstevel  * If the status is ok the node won't have any status property. It
92103831d35Sstevel  * is only there if the status is other than ok.
92203831d35Sstevel  */
92303831d35Sstevel sbd_cond_t
sbdp_get_comp_status(pnode_t nodeid)92403831d35Sstevel sbdp_get_comp_status(pnode_t nodeid)
92503831d35Sstevel {
92603831d35Sstevel 	char			status_buf[OBP_MAXPROPNAME];
92703831d35Sstevel 	static const char	*status = "status";
92803831d35Sstevel 	static const char	*failed = "fail";
92903831d35Sstevel 	static const char	*disabled = "disabled";
93003831d35Sstevel 	static fn_t		f = "sbdp_get_comp_status";
93103831d35Sstevel 
93203831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
93303831d35Sstevel 
93403831d35Sstevel 	if (sbdp_is_node_bad(nodeid)) {
93503831d35Sstevel 		SBDP_DBG_STATE("node is not ok\n");
93603831d35Sstevel 		return (SBD_COND_UNKNOWN);
93703831d35Sstevel 	}
93803831d35Sstevel 
93903831d35Sstevel 	if (prom_getproplen(nodeid, (char *)status) <= 0) {
94003831d35Sstevel 		SBDP_DBG_STATE("status is ok\n");
94103831d35Sstevel 		return (SBD_COND_OK);
94203831d35Sstevel 	}
94303831d35Sstevel 
94403831d35Sstevel 	if (prom_getprop(nodeid, (char *)status, status_buf) < 0) {
94503831d35Sstevel 		SBDP_DBG_STATE("status is unknown\n");
94603831d35Sstevel 		return (SBD_COND_UNKNOWN);
94703831d35Sstevel 	}
94803831d35Sstevel 
94903831d35Sstevel 	if (strncmp(status_buf, failed, strlen(failed)) == 0) {
95003831d35Sstevel 		SBDP_DBG_STATE("status of failed\n");
95103831d35Sstevel 		return (SBD_COND_FAILED);
95203831d35Sstevel 	}
95303831d35Sstevel 
95403831d35Sstevel 	if (strcmp(status_buf, disabled) == 0) {
95503831d35Sstevel 		SBDP_DBG_STATE("status of unusable\n");
95603831d35Sstevel 		return (SBD_COND_UNUSABLE);
95703831d35Sstevel 	}
95803831d35Sstevel 
95903831d35Sstevel 	return (SBD_COND_OK);
96003831d35Sstevel }
96103831d35Sstevel 
96203831d35Sstevel void
sbdp_cpu_in_reset(int node,int bd,int unit,int reset)96303831d35Sstevel sbdp_cpu_in_reset(int node, int bd, int unit, int reset)
96403831d35Sstevel {
96503831d35Sstevel 	sbdp_wnode_t	*cur;
96603831d35Sstevel 	sbdp_bd_t	*bdp;
96703831d35Sstevel 	static fn_t	f = "sbdp_cpu_in_reset";
96803831d35Sstevel 
96903831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
97003831d35Sstevel 
97103831d35Sstevel 	if ((unit < -1) || (bd < 0) || (node < 0)) {
97203831d35Sstevel 		return;
97303831d35Sstevel 	}
97403831d35Sstevel 
97503831d35Sstevel 	cur = sbdp_get_wnodep(node);
97603831d35Sstevel 
97703831d35Sstevel 	SBDP_DBG_MISC("marking cpu %d %s for board %d\n", unit,
97803831d35Sstevel 	    (reset) ? "in reset" : "out of reset", bd);
97903831d35Sstevel 
98003831d35Sstevel 	if (cur == NULL) {
98103831d35Sstevel 		return;
98203831d35Sstevel 	}
98303831d35Sstevel 
98403831d35Sstevel 	bdp = &cur->bds[bd];
98503831d35Sstevel 
98603831d35Sstevel 	if (unit == SBDP_ALL_CPUS)
98703831d35Sstevel 		if (reset == 1)
98803831d35Sstevel 			SBDP_SET_ALL_CPUS_IN_RESET(bdp);
98903831d35Sstevel 		else
99003831d35Sstevel 			SBDP_UNSET_ALL_CPUS_IN_RESET(bdp);
99103831d35Sstevel 	else
99203831d35Sstevel 		if (reset == 1)
99303831d35Sstevel 			SBDP_SET_CPU_IN_RESET(bdp, unit);
99403831d35Sstevel 		else
99503831d35Sstevel 			SBDP_UNSET_CPU_IN_RESET(bdp, unit);
99603831d35Sstevel }
99703831d35Sstevel 
99803831d35Sstevel int
sbdp_set_cpu_present(int node,int bd,int unit)99903831d35Sstevel sbdp_set_cpu_present(int node, int bd, int unit)
100003831d35Sstevel {
100103831d35Sstevel 	sbdp_wnode_t	*cur;
100203831d35Sstevel 	sbdp_bd_t	*bdp;
100303831d35Sstevel 	static fn_t	f = "sbdp_set_cpu_present";
100403831d35Sstevel 
100503831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
100603831d35Sstevel 
100703831d35Sstevel 	if ((unit < 0) || (bd < 0) || (node < 0)) {
100803831d35Sstevel 		return (-1);
100903831d35Sstevel 	}
101003831d35Sstevel 
101103831d35Sstevel 	cur = sbdp_get_wnodep(node);
101203831d35Sstevel 	if (cur == NULL) {
101303831d35Sstevel 		return (-1);
101403831d35Sstevel 	}
101503831d35Sstevel 
101603831d35Sstevel 	bdp = &cur->bds[bd];
101703831d35Sstevel 
101803831d35Sstevel 	SBDP_SET_CPU_PRESENT(bdp, unit);
101903831d35Sstevel 
102003831d35Sstevel 	return (0);
102103831d35Sstevel }
102203831d35Sstevel 
102303831d35Sstevel int
sbdp_is_cpu_present(int node,int bd,int unit)102403831d35Sstevel sbdp_is_cpu_present(int node, int bd, int unit)
102503831d35Sstevel {
102603831d35Sstevel 	sbdp_wnode_t	*cur;
102703831d35Sstevel 	sbdp_bd_t	*bdp;
102803831d35Sstevel 	static fn_t	f = "sbdp_is_cpu_present";
102903831d35Sstevel 
103003831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
103103831d35Sstevel 
103203831d35Sstevel 	if ((unit < 0) || (bd < 0) || (node < 0)) {
103303831d35Sstevel 		return (-1);
103403831d35Sstevel 	}
103503831d35Sstevel 
103603831d35Sstevel 	cur = sbdp_get_wnodep(node);
103703831d35Sstevel 	if (cur == NULL) {
103803831d35Sstevel 		return (-1);
103903831d35Sstevel 	}
104003831d35Sstevel 
104103831d35Sstevel 	bdp = &cur->bds[bd];
104203831d35Sstevel 
104303831d35Sstevel 	return (SBDP_IS_CPU_PRESENT(bdp, unit));
104403831d35Sstevel }
104503831d35Sstevel 
104603831d35Sstevel int
sbdp_is_cpu_in_reset(int node,int bd,int unit)104703831d35Sstevel sbdp_is_cpu_in_reset(int node, int bd, int unit)
104803831d35Sstevel {
104903831d35Sstevel 	sbdp_wnode_t	*cur;
105003831d35Sstevel 	sbdp_bd_t	*bdp;
105103831d35Sstevel 	static fn_t	f = "sbdp_is_cpu_in_reset";
105203831d35Sstevel 
105303831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
105403831d35Sstevel 
105503831d35Sstevel 	if ((unit < 0) || (bd < 0) || (node < 0)) {
105603831d35Sstevel 		return (-1);
105703831d35Sstevel 	}
105803831d35Sstevel 
105903831d35Sstevel 	cur = sbdp_get_wnodep(node);
106003831d35Sstevel 
106103831d35Sstevel 	if (cur == NULL) {
106203831d35Sstevel 		return (-1);
106303831d35Sstevel 	}
106403831d35Sstevel 
106503831d35Sstevel 	bdp = &cur->bds[bd];
106603831d35Sstevel 
106703831d35Sstevel 	return (SBDP_IS_CPU_IN_RESET(bdp, unit));
106803831d35Sstevel }
106903831d35Sstevel 
107003831d35Sstevel int
sbdp_dr_avail(void)107103831d35Sstevel sbdp_dr_avail(void)
107203831d35Sstevel {
107303831d35Sstevel 	static fn_t	f = "sbdp_dr_avail";
107403831d35Sstevel 
107503831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
107603831d35Sstevel 
107703831d35Sstevel 	if (sbdp_dr_available)
107803831d35Sstevel 		if (sg_prom_sb_dr_check() == 0)
107903831d35Sstevel 			return (1);
108003831d35Sstevel 	return (0);
108103831d35Sstevel }
1082