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