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