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/autoconf.h>
3103831d35Sstevel #include <sys/systm.h>
3203831d35Sstevel #include <sys/modctl.h>
3303831d35Sstevel #include <sys/ddi.h>
3403831d35Sstevel #include <sys/sunddi.h>
3503831d35Sstevel #include <sys/sunndi.h>
3603831d35Sstevel #include <sys/ndi_impldefs.h>
3703831d35Sstevel #include <sys/ddi_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/sgsbbc_mailbox.h>
4503831d35Sstevel #include <sys/cpuvar.h>
4603831d35Sstevel #include <vm/seg_kmem.h>
4703831d35Sstevel #include <sys/prom_plat.h>
4803831d35Sstevel #include <sys/machsystm.h>
4903831d35Sstevel #include <sys/cheetahregs.h>
5003831d35Sstevel 
5103831d35Sstevel #include <sys/sbd_ioctl.h>
5203831d35Sstevel #include <sys/sbd.h>
5303831d35Sstevel #include <sys/sbdp_priv.h>
5403831d35Sstevel 
5503831d35Sstevel static int sbdp_detach_nodes(attach_pkt_t *);
5603831d35Sstevel static void
sbdp_walk_prom_tree_worker(pnode_t node,int (* f)(pnode_t,void *,uint_t),void * arg)5703831d35Sstevel sbdp_walk_prom_tree_worker(
5803831d35Sstevel 	pnode_t node,
5903831d35Sstevel 	int(*f)(pnode_t, void *, uint_t),
6003831d35Sstevel 	void *arg)
6103831d35Sstevel {
6203831d35Sstevel 	/*
6303831d35Sstevel 	 * Ignore return value from callback. Return value from callback
6403831d35Sstevel 	 * does NOT indicate subsequent walk behavior.
6503831d35Sstevel 	 */
6603831d35Sstevel 	(void) (*f)(node, arg, 0);
6703831d35Sstevel 
6803831d35Sstevel 	if (node != OBP_NONODE) {
6903831d35Sstevel 		sbdp_walk_prom_tree_worker(prom_childnode(node), f, arg);
7003831d35Sstevel 		sbdp_walk_prom_tree_worker(prom_nextnode(node), f, arg);
7103831d35Sstevel 	}
7203831d35Sstevel }
7303831d35Sstevel 
7403831d35Sstevel struct sbdp_walk_prom_tree_args {
7503831d35Sstevel 	pnode_t	node;
7603831d35Sstevel 	int	(*f)(pnode_t, void *, uint_t);
7703831d35Sstevel 	void	*arg;
7803831d35Sstevel };
7903831d35Sstevel 
8003831d35Sstevel /*ARGSUSED*/
8103831d35Sstevel static int
sbdp_walk_prom_tree_start(void * arg,int has_changed)8203831d35Sstevel sbdp_walk_prom_tree_start(void *arg, int has_changed)
8303831d35Sstevel {
8403831d35Sstevel 	struct sbdp_walk_prom_tree_args *argbp = arg;
8503831d35Sstevel 
8603831d35Sstevel 	sbdp_walk_prom_tree_worker(argbp->node, argbp->f, argbp->arg);
8703831d35Sstevel 	return (0);
8803831d35Sstevel }
8903831d35Sstevel 
9003831d35Sstevel void
sbdp_walk_prom_tree(pnode_t node,int (* f)(pnode_t,void *,uint_t),void * arg)9103831d35Sstevel sbdp_walk_prom_tree(pnode_t node, int(*f)(pnode_t, void *, uint_t), void *arg)
9203831d35Sstevel {
9303831d35Sstevel 	struct sbdp_walk_prom_tree_args arg_block;
9403831d35Sstevel 
9503831d35Sstevel 	arg_block.node = node;
9603831d35Sstevel 	arg_block.f = f;
9703831d35Sstevel 	arg_block.arg = arg;
98*07d06da5SSurya Prakki 	(void) prom_tree_access(sbdp_walk_prom_tree_start, &arg_block, NULL);
9903831d35Sstevel }
10003831d35Sstevel 
10103831d35Sstevel static void
sbdp_attach_branch(dev_info_t * pdip,pnode_t node,void * arg)10203831d35Sstevel sbdp_attach_branch(dev_info_t *pdip, pnode_t node, void *arg)
10303831d35Sstevel {
10403831d35Sstevel 	attach_pkt_t	*apktp = (attach_pkt_t *)arg;
10503831d35Sstevel 	pnode_t		child;
10603831d35Sstevel 	dev_info_t	*dip = NULL;
10703831d35Sstevel 	static int	err = 0;
10803831d35Sstevel 	static int	len = 0;
10903831d35Sstevel 	char		name[OBP_MAXDRVNAME];
11003831d35Sstevel #if OBP_MAXDRVNAME == OBP_MAXPROPNAME
11103831d35Sstevel #define	buf	name
11203831d35Sstevel #else
11303831d35Sstevel 	char		buf[OBP_MAXPROPNAME];
11403831d35Sstevel #endif
11503831d35Sstevel 	static fn_t	f = "sbdp_attach_branch";
11603831d35Sstevel 
11703831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
11803831d35Sstevel 
11903831d35Sstevel 	if (node == OBP_NONODE)
12003831d35Sstevel 		return;
12103831d35Sstevel 
12203831d35Sstevel 	/*
12303831d35Sstevel 	 * Get the status for this node
12403831d35Sstevel 	 * If it has failed we imitate boot by not creating a node
12503831d35Sstevel 	 * in solaris. We just warn the user
12603831d35Sstevel 	 */
12703831d35Sstevel 	if (check_status(node, buf, pdip) != DDI_SUCCESS) {
12803831d35Sstevel 		SBDP_DBG_STATE("status failed skipping this node\n");
12903831d35Sstevel 		return;
13003831d35Sstevel 	}
13103831d35Sstevel 
13203831d35Sstevel 	len = prom_getproplen(node, OBP_REG);
13303831d35Sstevel 	if (len <= 0) {
13403831d35Sstevel 		return;
13503831d35Sstevel 	}
13603831d35Sstevel 
13703831d35Sstevel 	(void) prom_getprop(node, OBP_NAME, (caddr_t)name);
13803831d35Sstevel 	err = ndi_devi_alloc(pdip, name, node, &dip);
13903831d35Sstevel 	if (err != NDI_SUCCESS) {
14003831d35Sstevel 		return;
14103831d35Sstevel 	}
14203831d35Sstevel 	SBDP_DBG_STATE("attaching %s\n", name);
14303831d35Sstevel 	err = ndi_devi_online(dip, NDI_DEVI_BIND);
14403831d35Sstevel 	if (err != NDI_SUCCESS) {
145*07d06da5SSurya Prakki 		(void) ndi_devi_free(dip);
14603831d35Sstevel 		return;
14703831d35Sstevel 	}
14803831d35Sstevel 	child = prom_childnode(node);
14903831d35Sstevel 	if (child != OBP_NONODE) {
15003831d35Sstevel 		for (; child != OBP_NONODE;
15103831d35Sstevel 		    child = prom_nextnode(child)) {
15203831d35Sstevel 			sbdp_attach_branch(dip, child, (void *)apktp);
15303831d35Sstevel 		}
15403831d35Sstevel 	}
15503831d35Sstevel #undef buf
15603831d35Sstevel }
15703831d35Sstevel 
15803831d35Sstevel static int
sbdp_find_ssm_dip(dev_info_t * dip,void * arg)15903831d35Sstevel sbdp_find_ssm_dip(dev_info_t *dip, void *arg)
16003831d35Sstevel {
16103831d35Sstevel 	attach_pkt_t	*apktp;
16203831d35Sstevel 	int		node;
16303831d35Sstevel 	static fn_t	f = "sbdp_find_ssm_dip";
16403831d35Sstevel 
16503831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
16603831d35Sstevel 
16703831d35Sstevel 	apktp = (attach_pkt_t *)arg;
16803831d35Sstevel 
16903831d35Sstevel 	if (apktp == NULL) {
17003831d35Sstevel 		SBDP_DBG_STATE("error on the argument\n");
17103831d35Sstevel 		return (DDI_WALK_CONTINUE);
17203831d35Sstevel 	}
17303831d35Sstevel 
17403831d35Sstevel 	if ((node = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
17503831d35Sstevel 	    "nodeid", -1)) == -1)
17603831d35Sstevel 		return (DDI_WALK_CONTINUE);
17703831d35Sstevel 
17803831d35Sstevel 	if (node == apktp->node) {
17903831d35Sstevel 		ndi_hold_devi(dip);
18003831d35Sstevel 		apktp->top_node = dip;
18103831d35Sstevel 		return (DDI_WALK_TERMINATE);
18203831d35Sstevel 	}
18303831d35Sstevel 	return (DDI_WALK_CONTINUE);
18403831d35Sstevel }
18503831d35Sstevel 
18603831d35Sstevel /*ARGSUSED*/
18703831d35Sstevel int
sbdp_select_top_nodes(pnode_t node,void * arg,uint_t flags)18803831d35Sstevel sbdp_select_top_nodes(pnode_t node, void *arg, uint_t flags)
18903831d35Sstevel {
19003831d35Sstevel 	int		board, bd;
19103831d35Sstevel 	attach_pkt_t    *apktp = (attach_pkt_t *)arg;
19203831d35Sstevel 	char		devtype[OBP_MAXDRVNAME];
19303831d35Sstevel 	char		devname[OBP_MAXDRVNAME];
19403831d35Sstevel 	int		i;
19503831d35Sstevel 	sbd_devattr_t	*sbdp_top_nodes;
19603831d35Sstevel 	int		wnode;
19703831d35Sstevel 	static fn_t	f = "sbdp_select_top_nodes";
19803831d35Sstevel 
19903831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
20003831d35Sstevel 
20103831d35Sstevel 	if (apktp == NULL) {
20203831d35Sstevel 		SBDP_DBG_STATE("error on the argument\n");
20303831d35Sstevel 		return (DDI_FAILURE);
20403831d35Sstevel 	}
20503831d35Sstevel 
20603831d35Sstevel 	board = apktp->board;
20703831d35Sstevel 	sbdp_top_nodes = sbdp_get_devattr();
20803831d35Sstevel 
20903831d35Sstevel 	if (sbdp_get_bd_and_wnode_num(node, &bd, &wnode) < 0)
21003831d35Sstevel 		return (DDI_FAILURE);
21103831d35Sstevel 
21203831d35Sstevel 	if (bd != board)
21303831d35Sstevel 		return (DDI_FAILURE);
21403831d35Sstevel 
21503831d35Sstevel 	SBDP_DBG_MISC("%s: board is %d\n", f, bd);
21603831d35Sstevel 
21703831d35Sstevel 	(void) prom_getprop(node, OBP_DEVICETYPE, (caddr_t)devtype);
21803831d35Sstevel 	(void) prom_getprop(node, OBP_NAME, (caddr_t)devname);
21903831d35Sstevel 
22003831d35Sstevel 	if (strcmp(devname, "cmp") == 0) {
22103831d35Sstevel 		apktp->nodes[apktp->num_of_nodes] = node;
22203831d35Sstevel 		apktp->num_of_nodes++;
22303831d35Sstevel 
22403831d35Sstevel 		/* We want this node */
22503831d35Sstevel 		return (DDI_SUCCESS);
22603831d35Sstevel 	}
22703831d35Sstevel 
22803831d35Sstevel 	for (i = 0; sbdp_top_nodes[i].s_obp_type != NULL; i++) {
22903831d35Sstevel 		if (strcmp(devtype, sbdp_top_nodes[i].s_obp_type) == 0) {
23003831d35Sstevel 			if (strcmp(devtype, "cpu") == 0) {
23103831d35Sstevel 				int		cpuid;
23203831d35Sstevel 				int		impl;
23303831d35Sstevel 
23403831d35Sstevel 				/*
23503831d35Sstevel 				 * Check the status of the cpu
23603831d35Sstevel 				 * If it is failed ignore it
23703831d35Sstevel 				 */
23803831d35Sstevel 				if (sbdp_get_comp_status(node) != SBD_COND_OK)
23903831d35Sstevel 					return (DDI_FAILURE);
24003831d35Sstevel 
24103831d35Sstevel 				if (prom_getprop(node, "cpuid",
24203831d35Sstevel 				    (caddr_t)&cpuid) == -1) {
24303831d35Sstevel 
24403831d35Sstevel 					if (prom_getprop(node, "portid",
24503831d35Sstevel 					    (caddr_t)&cpuid) == -1) {
24603831d35Sstevel 
24703831d35Sstevel 						return (DDI_WALK_TERMINATE);
24803831d35Sstevel 					}
24903831d35Sstevel 				}
25003831d35Sstevel 
25103831d35Sstevel 				if (sbdp_set_cpu_present(wnode, bd,
25203831d35Sstevel 				    SG_CPUID_TO_CPU_UNIT(cpuid)) == -1)
25303831d35Sstevel 					return (DDI_WALK_TERMINATE);
25403831d35Sstevel 
25503831d35Sstevel 				(void) prom_getprop(node, "implementation#",
256*07d06da5SSurya Prakki 				    (caddr_t)&impl);
25703831d35Sstevel 				/*
25803831d35Sstevel 				 * If it is a CPU under CMP, don't save
25903831d35Sstevel 				 * the node as we will be saving the CMP
26003831d35Sstevel 				 * node.
26103831d35Sstevel 				 */
26203831d35Sstevel 				if (CPU_IMPL_IS_CMP(impl))
26303831d35Sstevel 					return (DDI_FAILURE);
26403831d35Sstevel 			}
26503831d35Sstevel 
26603831d35Sstevel 			/*
26703831d35Sstevel 			 * Check to make sure we haven't run out of bounds
26803831d35Sstevel 			 */
26903831d35Sstevel 			if (apktp->num_of_nodes >= SBDP_MAX_NODES)
27003831d35Sstevel 				return (DDI_FAILURE);
27103831d35Sstevel 
27203831d35Sstevel 			/* Save node */
27303831d35Sstevel 			apktp->nodes[apktp->num_of_nodes] = node;
27403831d35Sstevel 			apktp->num_of_nodes++;
275