1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * SUNW,Sun-Fire platform ioboard topology enumerator
31  */
32 
33 #include <string.h>
34 #include <libdevinfo.h>
35 #include <fm/topo_mod.h>
36 #include <fm/topo_hc.h>
37 
38 #include <did.h>
39 #include <hostbridge.h>
40 #include <ioboard.h>
41 #include <util.h>
42 
43 /*ARGSUSED*/
44 int
platform_iob_label(topo_mod_t * mod,tnode_t * node,nvlist_t * ignored,nvlist_t ** out)45 platform_iob_label(topo_mod_t *mod, tnode_t *node, nvlist_t *ignored,
46     nvlist_t **out)
47 {
48 	/*
49 	 * For SUNW,Sun-Fire the label is simply N0.IBXX where XX is the
50 	 * instance number of the ioboard.
51 	 */
52 	char buf[13];	/* up to a million I/O boards :-) */
53 
54 	*out = NULL;
55 	(void) snprintf(buf, 10, "N0.IB%d", topo_node_instance(node));
56 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) == 0 &&
57 	    nvlist_add_string(*out, TOPO_METH_LABEL_RET_STR, buf) == 0)
58 		return (0);
59 	nvlist_free(*out);
60 	*out = NULL;
61 	return (-1);
62 }
63 
64 #define	IOB_BASEADDR	0x18
65 #define	BUS_ADDRDIST	0x2
66 
67 /*ARGSUSED*/
68 int
platform_iob_enum(topo_mod_t * mod,tnode_t * parent,topo_instance_t imin,topo_instance_t imax)69 platform_iob_enum(topo_mod_t *mod, tnode_t *parent, topo_instance_t imin,
70     topo_instance_t imax)
71 {
72 	/*
73 	 * A SUNW,Sun-Fire and its successors may have up to 4 I/O boards,
74 	 * numbered 6 through 9.  Each board has two hostbridges, and
75 	 * there are a pair of PCI buses under each hostbridge.  We can
76 	 * discover the existence of a board by the presence of
77 	 * devinfo nodes for those hostbridges.  We let the hostbridge
78 	 * enumerator actually create nodes for the hostbridges,
79 	 * passing them the did_t's for all the hostbridge nodes we
80 	 * know indicate that the ioboard exists.
81 	 */
82 	di_node_t devtree;
83 	di_node_t pnode;
84 	did_t *iobs[18][2][2];
85 	int brd, br, bus, i;
86 
87 	devtree = topo_mod_devinfo(mod);
88 	if (devtree == DI_NODE_NIL) {
89 		topo_mod_dprintf(mod, "devinfo init failed.");
90 		return (-1);
91 	}
92 
93 	for (i = 6; i <= 9; i++) {
94 		iobs[i][0][0] = iobs[i][0][1] = NULL;
95 		iobs[i][1][0] = iobs[i][1][1] = NULL;
96 	}
97 
98 	pnode = di_drv_first_node(SCHIZO, devtree);
99 	while (pnode != DI_NODE_NIL) {
100 		did_t *d;
101 
102 		d = split_bus_address(mod,
103 		    pnode, IOB_BASEADDR, BUS_ADDRDIST, 6, 9, &brd, &br, &bus);
104 		if (d == NULL) {
105 			pnode = di_drv_next_node(pnode);
106 			continue;
107 		}
108 		iobs[brd][br][bus] = d;
109 		pnode = di_drv_next_node(pnode);
110 	}
111 
112 	for (i = 6; i < 9; i++) {
113 		tnode_t *ion;
114 		/*
115 		 * Make sure we found all the buses and bridges
116 		 */
117 		if (iobs[i][0][0] == NULL || iobs[i][0][1] == NULL ||
118 		    iobs[i][1][0] == NULL || iobs[i][1][1] == NULL)
119 			continue;
120 		did_did_link_set(iobs[i][0][0], iobs[i][0][1]);
121 		did_did_link_set(iobs[i][1][0], iobs[i][1][1]);
122 		did_did_chain_set(iobs[i][0][0], iobs[i][1][0]);
123 		if ((ion = ioboard_declare(mod, parent, i, iobs[i][0][0]))
124 		    == NULL) {
125 			topo_mod_dprintf(mod,
126 			    "Creation of tnode for %s%d failed.\n", IOBOARD, i);
127 			continue;
128 		}
129 		if (topo_mod_enumerate(mod,
130 		    ion, HOSTBRIDGE, HOSTBRIDGE, 0, 0, iobs[i][0][0]) < 0) {
131 			topo_mod_dprintf(mod,
132 			    "Enumeration of %s%d/%s%d failed.\n",
133 			    IOBOARD, i, HOSTBRIDGE, 0);
134 			continue;
135 		}
136 		if (topo_mod_enumerate(mod,
137 		    ion, HOSTBRIDGE, HOSTBRIDGE, 1, 1, iobs[i][0][0]) < 0) {
138 			topo_mod_dprintf(mod,
139 			    "Enumeration of %s%d/%s%d failed.\n",
140 			    IOBOARD, i, HOSTBRIDGE, 1);
141 			continue;
142 		}
143 	}
144 	return (0);
145 }
146