10d63ce2bSvenki /*
20d63ce2bSvenki * CDDL HEADER START
30d63ce2bSvenki *
40d63ce2bSvenki * The contents of this file are subject to the terms of the
50d63ce2bSvenki * Common Development and Distribution License (the "License").
60d63ce2bSvenki * You may not use this file except in compliance with the License.
70d63ce2bSvenki *
80d63ce2bSvenki * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90d63ce2bSvenki * or http://www.opensolaris.org/os/licensing.
100d63ce2bSvenki * See the License for the specific language governing permissions
110d63ce2bSvenki * and limitations under the License.
120d63ce2bSvenki *
130d63ce2bSvenki * When distributing Covered Code, include this CDDL HEADER in each
140d63ce2bSvenki * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150d63ce2bSvenki * If applicable, add the following below this CDDL HEADER, with the
160d63ce2bSvenki * fields enclosed by brackets "[]" replaced with your own identifying
170d63ce2bSvenki * information: Portions Copyright [yyyy] [name of copyright owner]
180d63ce2bSvenki *
190d63ce2bSvenki * CDDL HEADER END
200d63ce2bSvenki */
210d63ce2bSvenki
220d63ce2bSvenki /*
230d63ce2bSvenki * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
240d63ce2bSvenki * Use is subject to license terms.
250d63ce2bSvenki */
260d63ce2bSvenki
270d63ce2bSvenki #include "priplugin.h"
280d63ce2bSvenki
290d63ce2bSvenki static int
300d63ce2bSvenki find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
310d63ce2bSvenki const char *pval, picl_nodehdl_t *nodeh);
320d63ce2bSvenki static int
330d63ce2bSvenki compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
340d63ce2bSvenki const char *pval);
350d63ce2bSvenki
360d63ce2bSvenki /*
370d63ce2bSvenki * Gather IO device nodes from the PRI and use the info to
380d63ce2bSvenki * find the corresponding nodes in PICL's device tree, insert
390d63ce2bSvenki * a Label into the devtree containing the "nac" from the PRI,
400d63ce2bSvenki * and add a reference property to the corresponding fru tree node.
410d63ce2bSvenki */
420d63ce2bSvenki void
io_dev_addlabel(md_t * mdp)43a90d965dSfw io_dev_addlabel(md_t *mdp)
440d63ce2bSvenki {
450d63ce2bSvenki int status, substatus, i, node_count, component_count, busaddr_match;
460d63ce2bSvenki int type_size, nac_size;
470d63ce2bSvenki picl_nodehdl_t platnode, tpn;
480d63ce2bSvenki char busaddr[PICL_PROPNAMELEN_MAX], *p, *q;
49a90d965dSfw char path[PICL_PROPNAMELEN_MAX];
50d2b9c676Sfw mde_cookie_t *components, md_rootnode;
51a90d965dSfw char *type, *nac, *pri_path, *saved_path;
52a90d965dSfw
53a90d965dSfw if (mdp == NULL)
54a90d965dSfw return;
550d63ce2bSvenki
56d2b9c676Sfw md_rootnode = md_root_node(mdp);
57d2b9c676Sfw
580d63ce2bSvenki /*
590d63ce2bSvenki * Find and remember the roots of the /frutree and /platform trees.
600d63ce2bSvenki */
610d63ce2bSvenki if ((status = ptree_get_node_by_path(PLATFORM_PATH, &platnode)) !=
620d63ce2bSvenki PICL_SUCCESS) {
630d63ce2bSvenki pri_debug(LOG_NOTICE,
640d63ce2bSvenki "io_dev_label: can't find platform node: %s\n",
650d63ce2bSvenki picl_strerror(status));
660d63ce2bSvenki return;
670d63ce2bSvenki }
680d63ce2bSvenki
690d63ce2bSvenki node_count = md_node_count(mdp);
700d63ce2bSvenki if (node_count == 0) {
71f96bd410Sfw pri_debug(LOG_NOTICE, "io_dev_addlabel: no nodes to "
72f96bd410Sfw "process\n");
730d63ce2bSvenki return;
740d63ce2bSvenki }
75f96bd410Sfw components = (mde_cookie_t *)malloc(node_count *
76f96bd410Sfw sizeof (mde_cookie_t));
770d63ce2bSvenki if (components == NULL) {
780d63ce2bSvenki pri_debug(LOG_NOTICE,
790d63ce2bSvenki "io_dev_addlabel: can't get memory for IO nodes\n");
800d63ce2bSvenki return;
810d63ce2bSvenki }
820d63ce2bSvenki
83d2b9c676Sfw component_count = md_scan_dag(mdp, md_rootnode,
840d63ce2bSvenki md_find_name(mdp, "component"),
850d63ce2bSvenki md_find_name(mdp, "fwd"), components);
860d63ce2bSvenki
870d63ce2bSvenki for (i = 0; i < component_count; ++i) {
880d63ce2bSvenki tpn = platnode;
890d63ce2bSvenki
900d63ce2bSvenki /*
910d63ce2bSvenki * Try to fetch the "type" as a string or as "data" until we
920d63ce2bSvenki * can agree on what its tag type should be.
930d63ce2bSvenki */
94f96bd410Sfw if (md_get_prop_str(mdp, components[i], "type", &type) ==
95f96bd410Sfw -1) {
960d63ce2bSvenki if (md_get_prop_data(mdp, components[i], "type",
970d63ce2bSvenki (uint8_t **)&type, &type_size)) {
98f96bd410Sfw pri_debug(LOG_NOTICE, "io_add_devlabel: "
99f96bd410Sfw "can't get type for component %d\n", i);
1000d63ce2bSvenki continue;
1010d63ce2bSvenki }
1020d63ce2bSvenki }
1030d63ce2bSvenki
1040d63ce2bSvenki /*
1050d63ce2bSvenki * Isolate components of type "io".
1060d63ce2bSvenki */
1070d63ce2bSvenki if (strcmp((const char *)type, "io")) {
1080d63ce2bSvenki pri_debug(LOG_NOTICE,
1090d63ce2bSvenki "io_add_devlabel: skipping component %d with "
1100d63ce2bSvenki "type %s\n", i, type);
1110d63ce2bSvenki continue;
1120d63ce2bSvenki }
1130d63ce2bSvenki
1140d63ce2bSvenki /*
1150d63ce2bSvenki * Now get the nac and raw path from the PRI.
1160d63ce2bSvenki */
1170d63ce2bSvenki if (md_get_prop_str(mdp, components[i], "nac", &nac) == -1) {
1180d63ce2bSvenki pri_debug(LOG_NOTICE,
1190d63ce2bSvenki "io_add_devlabel: can't get nac value for device "
1200d63ce2bSvenki "<%s>\n", type);
1210d63ce2bSvenki continue;
1220d63ce2bSvenki } else
1230d63ce2bSvenki nac_size = strlen(nac) + 1;
1240d63ce2bSvenki
125a90d965dSfw if (md_get_prop_str(mdp, components[i], "path", &pri_path) ==
126f96bd410Sfw -1) {
1270d63ce2bSvenki pri_debug(LOG_NOTICE,
1280d63ce2bSvenki "io_add_devlabel: can't get path value for "
1290d63ce2bSvenki "device <%s>\n", type);
1300d63ce2bSvenki continue;
1310d63ce2bSvenki }
1320d63ce2bSvenki
133a90d965dSfw (void) strlcpy(path, pri_path, sizeof (path));
134a90d965dSfw
1350d63ce2bSvenki pri_debug(LOG_NOTICE, "io_add_devlabel: processing component "
1360d63ce2bSvenki "%d, type <%s>, nac <%s>, path <%s>\n", i, type, nac,
1370d63ce2bSvenki path);
1380d63ce2bSvenki
1390d63ce2bSvenki /*
1400d63ce2bSvenki * This loop visits each path component where those
1410d63ce2bSvenki * components are delimited with '/' and '@' characters.
1420d63ce2bSvenki * Each path component is a search key into the /platform
1430d63ce2bSvenki * tree; we're looking to match the bus-addr field of
1440d63ce2bSvenki * a node if that field is defined. If each path component
1450d63ce2bSvenki * matches up then we now have the corresponding device
1460d63ce2bSvenki * path for that IO device. Add a Label property to the
1470d63ce2bSvenki * leaf node.
1480d63ce2bSvenki */
1490d63ce2bSvenki for (busaddr_match = 1, p = q = (char *)path; q; p = q + 1) {
1500d63ce2bSvenki
1510d63ce2bSvenki /*
1520d63ce2bSvenki * Isolate the bus address for this node by skipping
1530d63ce2bSvenki * over the first delimiter if present and writing
1540d63ce2bSvenki * a NUL character over the next '/'.
1550d63ce2bSvenki */
1560d63ce2bSvenki if (*p == '/')
1570d63ce2bSvenki ++p;
1580d63ce2bSvenki if (*p == '@')
1590d63ce2bSvenki ++p;
1600d63ce2bSvenki if ((q = strchr((const char *)p, '/')) != NULL)
1610d63ce2bSvenki *q = '\0';
1620d63ce2bSvenki
1630d63ce2bSvenki /*
1640d63ce2bSvenki * See if there's a match, at this level only, in the
1650d63ce2bSvenki * device tree. We cannot skip generations in the
1660d63ce2bSvenki * device tree, which is why we're not doing a
1670d63ce2bSvenki * recursive search for bus-addr. bus-addr must
1680d63ce2bSvenki * be found at each node along the way. By doing
1690d63ce2bSvenki * this we'll stay in sync with the path components
1700d63ce2bSvenki * in the PRI.
1710d63ce2bSvenki */
1720d63ce2bSvenki if ((status = find_node_by_string_prop(tpn,
1730d63ce2bSvenki PICL_PROP_BUS_ADDR, (const char *)p, &tpn)) !=
1740d63ce2bSvenki PICL_SUCCESS) {
1750d63ce2bSvenki pri_debug(LOG_NOTICE,
1760d63ce2bSvenki "can't find %s property of <%s> "
1770d63ce2bSvenki "for nac %s: %s\n",
1780d63ce2bSvenki PICL_PROP_BUS_ADDR, p, nac,
1790d63ce2bSvenki picl_strerror(status));
1800d63ce2bSvenki busaddr_match = 0;
1810d63ce2bSvenki break;
1820d63ce2bSvenki }
1830d63ce2bSvenki
1840d63ce2bSvenki /*
1850d63ce2bSvenki * Note path component for the leaf so we can use
1860d63ce2bSvenki * it below.
1870d63ce2bSvenki */
1880d63ce2bSvenki saved_path = p;
1890d63ce2bSvenki }
1900d63ce2bSvenki
1910d63ce2bSvenki /*
1920d63ce2bSvenki * We could not drill down through the bus-addrs, so skip this
1930d63ce2bSvenki * device and move on to the next.
1940d63ce2bSvenki */
1950d63ce2bSvenki if (busaddr_match == 0) {
1960d63ce2bSvenki pri_debug(LOG_NOTICE, "io_add_devlabel: no matching "
1970d63ce2bSvenki "bus-addr path for this nac - skipping\n");
1980d63ce2bSvenki continue;
1990d63ce2bSvenki }
2000d63ce2bSvenki
2010d63ce2bSvenki nac_size = strlen((const char *)nac) + 1;
2020d63ce2bSvenki
2030d63ce2bSvenki /*
2040d63ce2bSvenki * This loop adds a Label property to all the functions
2050d63ce2bSvenki * on the device we matched from the PRI path.
2060d63ce2bSvenki */
2070d63ce2bSvenki for (status = PICL_SUCCESS; status == PICL_SUCCESS;
208a90d965dSfw status = ptree_get_propval_by_name(tpn,
209a90d965dSfw PICL_PROP_PEER, &tpn, sizeof (picl_nodehdl_t))) {
2100d63ce2bSvenki /*
2110d63ce2bSvenki * Add Labels to peers that have the same bus-addr
2120d63ce2bSvenki * value (ignoring the function numbers.)
2130d63ce2bSvenki */
2140d63ce2bSvenki if ((substatus = ptree_get_propval_by_name(tpn,
2150d63ce2bSvenki PICL_PROP_BUS_ADDR,
2160d63ce2bSvenki busaddr, sizeof (busaddr))) != PICL_SUCCESS) {
2170d63ce2bSvenki pri_debug(LOG_NOTICE,
2180d63ce2bSvenki "io_add_device: can't get %s "
2190d63ce2bSvenki "property from picl devtree: %s\n",
2200d63ce2bSvenki PICL_PROP_BUS_ADDR,
2210d63ce2bSvenki picl_strerror(substatus));
2220d63ce2bSvenki } else {
2230d63ce2bSvenki if (strncmp(busaddr, saved_path,
2240d63ce2bSvenki PICL_PROPNAMELEN_MAX) == 0) {
2250d63ce2bSvenki add_md_prop(tpn, nac_size,
2260d63ce2bSvenki PICL_PROP_LABEL, nac,
2270d63ce2bSvenki PICL_PTYPE_CHARSTRING);
2280d63ce2bSvenki }
2290d63ce2bSvenki }
2300d63ce2bSvenki }
2310d63ce2bSvenki }
232*dc6ca969Sfw free(components);
2330d63ce2bSvenki }
2340d63ce2bSvenki
2350d63ce2bSvenki /*
2360d63ce2bSvenki * These two functions shamelessly stolen from picldevtree.c
2370d63ce2bSvenki */
2380d63ce2bSvenki
2390d63ce2bSvenki /*
2400d63ce2bSvenki * Return 1 if this node has this property with the given value.
2410d63ce2bSvenki */
2420d63ce2bSvenki static int
compare_string_propval(picl_nodehdl_t nodeh,const char * pname,const char * pval)2430d63ce2bSvenki compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
2440d63ce2bSvenki const char *pval)
2450d63ce2bSvenki {
2460d63ce2bSvenki char *pvalbuf;
2470d63ce2bSvenki int err;
2480d63ce2bSvenki int len;
2490d63ce2bSvenki ptree_propinfo_t pinfo;
2500d63ce2bSvenki picl_prophdl_t proph;
2510d63ce2bSvenki
2520d63ce2bSvenki err = ptree_get_prop_by_name(nodeh, pname, &proph);
2530d63ce2bSvenki if (err != PICL_SUCCESS) /* prop doesn't exist */
2540d63ce2bSvenki return (0);
2550d63ce2bSvenki
2560d63ce2bSvenki err = ptree_get_propinfo(proph, &pinfo);
2570d63ce2bSvenki if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING)
2580d63ce2bSvenki return (0); /* not string prop */
2590d63ce2bSvenki
2600d63ce2bSvenki len = strlen(pval) + 1;
2610d63ce2bSvenki
2620d63ce2bSvenki pvalbuf = alloca(len);
2630d63ce2bSvenki if (pvalbuf == NULL)
2640d63ce2bSvenki return (0);
2650d63ce2bSvenki
2660d63ce2bSvenki err = ptree_get_propval(proph, pvalbuf, len);
2670d63ce2bSvenki if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0))
2680d63ce2bSvenki return (1); /* prop match */
2690d63ce2bSvenki
2700d63ce2bSvenki return (0);
2710d63ce2bSvenki }
2720d63ce2bSvenki
2730d63ce2bSvenki /*
2740d63ce2bSvenki * Search this node's children for the given property.
2750d63ce2bSvenki */
2760d63ce2bSvenki static int
find_node_by_string_prop(picl_nodehdl_t rooth,const char * pname,const char * pval,picl_nodehdl_t * nodeh)2770d63ce2bSvenki find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
2780d63ce2bSvenki const char *pval, picl_nodehdl_t *nodeh)
2790d63ce2bSvenki {
2800d63ce2bSvenki picl_nodehdl_t childh;
2810d63ce2bSvenki int err;
2820d63ce2bSvenki
2830d63ce2bSvenki for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
2840d63ce2bSvenki sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
285a90d965dSfw err = ptree_get_propval_by_name(childh, PICL_PROP_PEER,
286a90d965dSfw &childh, sizeof (picl_nodehdl_t))) {
2870d63ce2bSvenki if (err != PICL_SUCCESS)
2880d63ce2bSvenki return (err);
2890d63ce2bSvenki
2900d63ce2bSvenki if (compare_string_propval(childh, pname, pval)) {
2910d63ce2bSvenki *nodeh = childh;
2920d63ce2bSvenki return (PICL_SUCCESS);
2930d63ce2bSvenki }
2940d63ce2bSvenki }
2950d63ce2bSvenki return (PICL_ENDOFLIST);
2960d63ce2bSvenki }
297