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