xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4v/pri/io_dev_label.c (revision f48205be61a214698b763ff550ab9e657525104c)
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 2007 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 #include "priplugin.h"
30 
31 /*
32  * These 3 variable are defined and set in mdescplugin.c
33  */
34 extern picl_nodehdl_t	root_node;
35 extern md_t		*mdp;
36 extern mde_cookie_t	rootnode;
37 
38 static int
39 find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
40     const char *pval, picl_nodehdl_t *nodeh);
41 static int
42 compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
43     const char *pval);
44 
45 /*
46  * Gather IO device nodes from the PRI and use the info to
47  * find the corresponding nodes in PICL's device tree, insert
48  * a Label into the devtree containing the "nac" from the PRI,
49  * and add a reference property to the corresponding fru tree node.
50  */
51 void
52 io_dev_addlabel(void)
53 {
54 	int status, substatus, i, node_count, component_count, busaddr_match;
55 	int type_size, nac_size;
56 	picl_nodehdl_t platnode, tpn;
57 	char busaddr[PICL_PROPNAMELEN_MAX], *p, *q;
58 	mde_cookie_t *components;
59 	char *type, *nac, *path, *saved_path;
60 
61 	/*
62 	 * Find and remember the roots of the /frutree and /platform trees.
63 	 */
64 	if ((status = ptree_get_node_by_path(PLATFORM_PATH, &platnode)) !=
65 	    PICL_SUCCESS) {
66 		pri_debug(LOG_NOTICE,
67 		    "io_dev_label: can't find platform node: %s\n",
68 		    picl_strerror(status));
69 		return;
70 	}
71 
72 	node_count = md_node_count(mdp);
73 	if (node_count == 0) {
74 		pri_debug(LOG_NOTICE, "io_dev_addlabel: no nodes to "
75 		    "process\n");
76 		return;
77 	}
78 	components = (mde_cookie_t *)malloc(node_count *
79 	    sizeof (mde_cookie_t));
80 	if (components == NULL) {
81 		pri_debug(LOG_NOTICE,
82 		    "io_dev_addlabel: can't get memory for IO nodes\n");
83 		return;
84 	}
85 
86 	component_count = md_scan_dag(mdp, rootnode,
87 	    md_find_name(mdp, "component"),
88 	    md_find_name(mdp, "fwd"), components);
89 
90 	for (i = 0; i < component_count; ++i) {
91 		tpn = platnode;
92 
93 		/*
94 		 * Try to fetch the "type" as a string or as "data" until we
95 		 * can agree on what its tag type should be.
96 		 */
97 		if (md_get_prop_str(mdp, components[i], "type", &type) ==
98 		    -1) {
99 			if (md_get_prop_data(mdp, components[i], "type",
100 			    (uint8_t **)&type, &type_size)) {
101 				pri_debug(LOG_NOTICE, "io_add_devlabel: "
102 				    "can't get type for component %d\n", i);
103 			continue;
104 			}
105 		}
106 
107 		/*
108 		 * Isolate components of type "io".
109 		 */
110 		if (strcmp((const char *)type, "io")) {
111 			pri_debug(LOG_NOTICE,
112 			    "io_add_devlabel: skipping component %d with "
113 			    "type %s\n", i, type);
114 			continue;
115 		}
116 
117 		/*
118 		 * Now get the nac and raw path from the PRI.
119 		 */
120 		if (md_get_prop_str(mdp, components[i], "nac", &nac) == -1) {
121 			pri_debug(LOG_NOTICE,
122 			    "io_add_devlabel: can't get nac value for device "
123 			    "<%s>\n", type);
124 			continue;
125 		} else
126 			nac_size = strlen(nac) + 1;
127 
128 		if (md_get_prop_str(mdp, components[i], "path", &path) ==
129 		    -1) {
130 			pri_debug(LOG_NOTICE,
131 			    "io_add_devlabel: can't get path value for "
132 			    "device <%s>\n", type);
133 			continue;
134 		}
135 
136 		pri_debug(LOG_NOTICE, "io_add_devlabel: processing component "
137 		    "%d, type <%s>, nac <%s>, path <%s>\n", i, type, nac,
138 		    path);
139 
140 		/*
141 		 * This loop visits each path component where those
142 		 * components are delimited with '/' and '@' characters.
143 		 * Each path component is a search key into the /platform
144 		 * tree; we're looking to match the bus-addr field of
145 		 * a node if that field is defined.  If each path component
146 		 * matches up then we now have the corresponding device
147 		 * path for that IO device.  Add a Label property to the
148 		 * leaf node.
149 		 */
150 		for (busaddr_match = 1, p = q = (char *)path; q; p = q + 1) {
151 
152 			/*
153 			 * Isolate the bus address for this node by skipping
154 			 * over the first delimiter if present and writing
155 			 * a NUL character over the next '/'.
156 			 */
157 			if (*p == '/')
158 				++p;
159 			if (*p == '@')
160 				++p;
161 			if ((q = strchr((const char *)p, '/')) != NULL)
162 				*q = '\0';
163 
164 			/*
165 			 * See if there's a match, at this level only, in the
166 			 * device tree.  We cannot skip generations in the
167 			 * device tree, which is why we're not doing a
168 			 * recursive search for bus-addr.  bus-addr must
169 			 * be found at each node along the way.  By doing
170 			 * this we'll stay in sync with the path components
171 			 * in the PRI.
172 			 */
173 			if ((status = find_node_by_string_prop(tpn,
174 			    PICL_PROP_BUS_ADDR, (const char *)p, &tpn)) !=
175 			    PICL_SUCCESS) {
176 				pri_debug(LOG_NOTICE,
177 				    "can't find %s property of <%s> "
178 				    "for nac %s: %s\n",
179 				    PICL_PROP_BUS_ADDR, p, nac,
180 				    picl_strerror(status));
181 				busaddr_match = 0;
182 				break;
183 			}
184 
185 			/*
186 			 * Note path component for the leaf so we can use
187 			 * it below.
188 			 */
189 			saved_path = p;
190 		}
191 
192 		/*
193 		 * We could not drill down through the bus-addrs, so skip this
194 		 * device and move on to the next.
195 		 */
196 		if (busaddr_match == 0) {
197 			pri_debug(LOG_NOTICE, "io_add_devlabel: no matching "
198 			    "bus-addr path for this nac - skipping\n");
199 			continue;
200 		}
201 
202 		nac_size = strlen((const char *)nac) + 1;
203 
204 		/*
205 		 * This loop adds a Label property to all the functions
206 		 * on the device we matched from the PRI path.
207 		 */
208 		for (status = PICL_SUCCESS; status == PICL_SUCCESS;
209 			status = ptree_get_propval_by_name(tpn,
210 			    PICL_PROP_PEER, &tpn, sizeof (picl_nodehdl_t))) {
211 			/*
212 			 * Add Labels to peers that have the same bus-addr
213 			 * value (ignoring the function numbers.)
214 			 */
215 			if ((substatus = ptree_get_propval_by_name(tpn,
216 			    PICL_PROP_BUS_ADDR,
217 			    busaddr, sizeof (busaddr))) != PICL_SUCCESS) {
218 				pri_debug(LOG_NOTICE,
219 				    "io_add_device: can't get %s "
220 				    "property from picl devtree: %s\n",
221 				    PICL_PROP_BUS_ADDR,
222 				    picl_strerror(substatus));
223 			} else {
224 				/*
225 				 * If the PRI path doesn't include a specific
226 				 * function number then don't look for one
227 				 * in the bus-addr.  Devices on PCI-X bridges
228 				 * may have a function number in the path,
229 				 * so don't ignore that.
230 				 */
231 				if (strchr(saved_path, ',') == NULL) {
232 					if ((q = strchr(busaddr, ',')) !=
233 					    NULL) {
234 						*q = '\0';
235 					}
236 				}
237 				if (strncmp(busaddr, saved_path,
238 				    PICL_PROPNAMELEN_MAX) == 0) {
239 					add_md_prop(tpn, nac_size,
240 					    PICL_PROP_LABEL, nac,
241 					    PICL_PTYPE_CHARSTRING);
242 				}
243 			}
244 		}
245 	}
246 }
247 
248 /*
249  * These two functions shamelessly stolen from picldevtree.c
250  */
251 
252 /*
253  * Return 1 if this node has this property with the given value.
254  */
255 static int
256 compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
257     const char *pval)
258 {
259 	char *pvalbuf;
260 	int err;
261 	int len;
262 	ptree_propinfo_t pinfo;
263 	picl_prophdl_t proph;
264 
265 	err = ptree_get_prop_by_name(nodeh, pname, &proph);
266 	if (err != PICL_SUCCESS)	/* prop doesn't exist */
267 		return (0);
268 
269 	err = ptree_get_propinfo(proph, &pinfo);
270 	if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING)
271 		return (0);	/* not string prop */
272 
273 	len = strlen(pval) + 1;
274 
275 	pvalbuf = alloca(len);
276 	if (pvalbuf == NULL)
277 		return (0);
278 
279 	err = ptree_get_propval(proph, pvalbuf, len);
280 	if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0))
281 		return (1);	/* prop match */
282 
283 	return (0);
284 }
285 
286 /*
287  * Search this node's children for the given property.
288  */
289 static int
290 find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
291     const char *pval, picl_nodehdl_t *nodeh)
292 {
293 	picl_nodehdl_t childh;
294 	int err;
295 
296 	for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
297 	    sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
298 		err = ptree_get_propval_by_name(childh, PICL_PROP_PEER,
299 		    &childh, sizeof (picl_nodehdl_t))) {
300 		if (err != PICL_SUCCESS)
301 			return (err);
302 
303 		if (compare_string_propval(childh, pname, pval)) {
304 			*nodeh = childh;
305 			return (PICL_SUCCESS);
306 		}
307 	}
308 	return (PICL_ENDOFLIST);
309 }
310