13941Svenki /*
23941Svenki * CDDL HEADER START
33941Svenki *
43941Svenki * The contents of this file are subject to the terms of the
53941Svenki * Common Development and Distribution License (the "License").
63941Svenki * You may not use this file except in compliance with the License.
73941Svenki *
83941Svenki * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93941Svenki * or http://www.opensolaris.org/os/licensing.
103941Svenki * See the License for the specific language governing permissions
113941Svenki * and limitations under the License.
123941Svenki *
133941Svenki * When distributing Covered Code, include this CDDL HEADER in each
143941Svenki * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153941Svenki * If applicable, add the following below this CDDL HEADER, with the
163941Svenki * fields enclosed by brackets "[]" replaced with your own identifying
173941Svenki * information: Portions Copyright [yyyy] [name of copyright owner]
183941Svenki *
193941Svenki * CDDL HEADER END
203941Svenki */
213941Svenki
223941Svenki /*
233941Svenki * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
243941Svenki * Use is subject to license terms.
253941Svenki */
263941Svenki
273941Svenki #pragma ident "%Z%%M% %I% %E% SMI"
283941Svenki
293941Svenki #include "priplugin.h"
303941Svenki
313941Svenki static int
323941Svenki find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
333941Svenki const char *pval, picl_nodehdl_t *nodeh);
343941Svenki static int
353941Svenki compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
363941Svenki const char *pval);
373941Svenki
383941Svenki /*
393941Svenki * Gather IO device nodes from the PRI and use the info to
403941Svenki * find the corresponding nodes in PICL's device tree, insert
413941Svenki * a Label into the devtree containing the "nac" from the PRI,
423941Svenki * and add a reference property to the corresponding fru tree node.
433941Svenki */
443941Svenki void
io_dev_addlabel(md_t * mdp)454669Sfw157321 io_dev_addlabel(md_t *mdp)
463941Svenki {
473941Svenki int status, substatus, i, node_count, component_count, busaddr_match;
483941Svenki int type_size, nac_size;
493941Svenki picl_nodehdl_t platnode, tpn;
503941Svenki char busaddr[PICL_PROPNAMELEN_MAX], *p, *q;
514669Sfw157321 char path[PICL_PROPNAMELEN_MAX];
525029Sfw157321 mde_cookie_t *components, md_rootnode;
534669Sfw157321 char *type, *nac, *pri_path, *saved_path;
544669Sfw157321
554669Sfw157321 if (mdp == NULL)
564669Sfw157321 return;
573941Svenki
585029Sfw157321 md_rootnode = md_root_node(mdp);
595029Sfw157321
603941Svenki /*
613941Svenki * Find and remember the roots of the /frutree and /platform trees.
623941Svenki */
633941Svenki if ((status = ptree_get_node_by_path(PLATFORM_PATH, &platnode)) !=
643941Svenki PICL_SUCCESS) {
653941Svenki pri_debug(LOG_NOTICE,
663941Svenki "io_dev_label: can't find platform node: %s\n",
673941Svenki picl_strerror(status));
683941Svenki return;
693941Svenki }
703941Svenki
713941Svenki node_count = md_node_count(mdp);
723941Svenki if (node_count == 0) {
734209Sfw157321 pri_debug(LOG_NOTICE, "io_dev_addlabel: no nodes to "
744209Sfw157321 "process\n");
753941Svenki return;
763941Svenki }
774209Sfw157321 components = (mde_cookie_t *)malloc(node_count *
784209Sfw157321 sizeof (mde_cookie_t));
793941Svenki if (components == NULL) {
803941Svenki pri_debug(LOG_NOTICE,
813941Svenki "io_dev_addlabel: can't get memory for IO nodes\n");
823941Svenki return;
833941Svenki }
843941Svenki
855029Sfw157321 component_count = md_scan_dag(mdp, md_rootnode,
863941Svenki md_find_name(mdp, "component"),
873941Svenki md_find_name(mdp, "fwd"), components);
883941Svenki
893941Svenki for (i = 0; i < component_count; ++i) {
903941Svenki tpn = platnode;
913941Svenki
923941Svenki /*
933941Svenki * Try to fetch the "type" as a string or as "data" until we
943941Svenki * can agree on what its tag type should be.
953941Svenki */
964209Sfw157321 if (md_get_prop_str(mdp, components[i], "type", &type) ==
974209Sfw157321 -1) {
983941Svenki if (md_get_prop_data(mdp, components[i], "type",
993941Svenki (uint8_t **)&type, &type_size)) {
1004209Sfw157321 pri_debug(LOG_NOTICE, "io_add_devlabel: "
1014209Sfw157321 "can't get type for component %d\n", i);
1023941Svenki continue;
1033941Svenki }
1043941Svenki }
1053941Svenki
1063941Svenki /*
1073941Svenki * Isolate components of type "io".
1083941Svenki */
1093941Svenki if (strcmp((const char *)type, "io")) {
1103941Svenki pri_debug(LOG_NOTICE,
1113941Svenki "io_add_devlabel: skipping component %d with "
1123941Svenki "type %s\n", i, type);
1133941Svenki continue;
1143941Svenki }
1153941Svenki
1163941Svenki /*
1173941Svenki * Now get the nac and raw path from the PRI.
1183941Svenki */
1193941Svenki if (md_get_prop_str(mdp, components[i], "nac", &nac) == -1) {
1203941Svenki pri_debug(LOG_NOTICE,
1213941Svenki "io_add_devlabel: can't get nac value for device "
1223941Svenki "<%s>\n", type);
1233941Svenki continue;
1243941Svenki } else
1253941Svenki nac_size = strlen(nac) + 1;
1263941Svenki
1274669Sfw157321 if (md_get_prop_str(mdp, components[i], "path", &pri_path) ==
1284209Sfw157321 -1) {
1293941Svenki pri_debug(LOG_NOTICE,
1303941Svenki "io_add_devlabel: can't get path value for "
1313941Svenki "device <%s>\n", type);
1323941Svenki continue;
1333941Svenki }
1343941Svenki
1354669Sfw157321 (void) strlcpy(path, pri_path, sizeof (path));
1364669Sfw157321
1373941Svenki pri_debug(LOG_NOTICE, "io_add_devlabel: processing component "
1383941Svenki "%d, type <%s>, nac <%s>, path <%s>\n", i, type, nac,
1393941Svenki path);
1403941Svenki
1413941Svenki /*
1423941Svenki * This loop visits each path component where those
1433941Svenki * components are delimited with '/' and '@' characters.
1443941Svenki * Each path component is a search key into the /platform
1453941Svenki * tree; we're looking to match the bus-addr field of
1463941Svenki * a node if that field is defined. If each path component
1473941Svenki * matches up then we now have the corresponding device
1483941Svenki * path for that IO device. Add a Label property to the
1493941Svenki * leaf node.
1503941Svenki */
1513941Svenki for (busaddr_match = 1, p = q = (char *)path; q; p = q + 1) {
1523941Svenki
1533941Svenki /*
1543941Svenki * Isolate the bus address for this node by skipping
1553941Svenki * over the first delimiter if present and writing
1563941Svenki * a NUL character over the next '/'.
1573941Svenki */
1583941Svenki if (*p == '/')
1593941Svenki ++p;
1603941Svenki if (*p == '@')
1613941Svenki ++p;
1623941Svenki if ((q = strchr((const char *)p, '/')) != NULL)
1633941Svenki *q = '\0';
1643941Svenki
1653941Svenki /*
1663941Svenki * See if there's a match, at this level only, in the
1673941Svenki * device tree. We cannot skip generations in the
1683941Svenki * device tree, which is why we're not doing a
1693941Svenki * recursive search for bus-addr. bus-addr must
1703941Svenki * be found at each node along the way. By doing
1713941Svenki * this we'll stay in sync with the path components
1723941Svenki * in the PRI.
1733941Svenki */
1743941Svenki if ((status = find_node_by_string_prop(tpn,
1753941Svenki PICL_PROP_BUS_ADDR, (const char *)p, &tpn)) !=
1763941Svenki PICL_SUCCESS) {
1773941Svenki pri_debug(LOG_NOTICE,
1783941Svenki "can't find %s property of <%s> "
1793941Svenki "for nac %s: %s\n",
1803941Svenki PICL_PROP_BUS_ADDR, p, nac,
1813941Svenki picl_strerror(status));
1823941Svenki busaddr_match = 0;
1833941Svenki break;
1843941Svenki }
1853941Svenki
1863941Svenki /*
1873941Svenki * Note path component for the leaf so we can use
1883941Svenki * it below.
1893941Svenki */
1903941Svenki saved_path = p;
1913941Svenki }
1923941Svenki
1933941Svenki /*
1943941Svenki * We could not drill down through the bus-addrs, so skip this
1953941Svenki * device and move on to the next.
1963941Svenki */
1973941Svenki if (busaddr_match == 0) {
1983941Svenki pri_debug(LOG_NOTICE, "io_add_devlabel: no matching "
1993941Svenki "bus-addr path for this nac - skipping\n");
2003941Svenki continue;
2013941Svenki }
2023941Svenki
2033941Svenki nac_size = strlen((const char *)nac) + 1;
2043941Svenki
2053941Svenki /*
2063941Svenki * This loop adds a Label property to all the functions
2073941Svenki * on the device we matched from the PRI path.
2083941Svenki */
2093941Svenki for (status = PICL_SUCCESS; status == PICL_SUCCESS;
2104669Sfw157321 status = ptree_get_propval_by_name(tpn,
2114669Sfw157321 PICL_PROP_PEER, &tpn, sizeof (picl_nodehdl_t))) {
2123941Svenki /*
2133941Svenki * Add Labels to peers that have the same bus-addr
2143941Svenki * value (ignoring the function numbers.)
2153941Svenki */
2163941Svenki if ((substatus = ptree_get_propval_by_name(tpn,
2173941Svenki PICL_PROP_BUS_ADDR,
2183941Svenki busaddr, sizeof (busaddr))) != PICL_SUCCESS) {
2193941Svenki pri_debug(LOG_NOTICE,
2203941Svenki "io_add_device: can't get %s "
2213941Svenki "property from picl devtree: %s\n",
2223941Svenki PICL_PROP_BUS_ADDR,
2233941Svenki picl_strerror(substatus));
2243941Svenki } else {
2253941Svenki if (strncmp(busaddr, saved_path,
2263941Svenki PICL_PROPNAMELEN_MAX) == 0) {
2273941Svenki add_md_prop(tpn, nac_size,
2283941Svenki PICL_PROP_LABEL, nac,
2293941Svenki PICL_PTYPE_CHARSTRING);
2303941Svenki }
2313941Svenki }
2323941Svenki }
2333941Svenki }
234*5436Sfw157321 free(components);
2353941Svenki }
2363941Svenki
2373941Svenki /*
2383941Svenki * These two functions shamelessly stolen from picldevtree.c
2393941Svenki */
2403941Svenki
2413941Svenki /*
2423941Svenki * Return 1 if this node has this property with the given value.
2433941Svenki */
2443941Svenki static int
compare_string_propval(picl_nodehdl_t nodeh,const char * pname,const char * pval)2453941Svenki compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
2463941Svenki const char *pval)
2473941Svenki {
2483941Svenki char *pvalbuf;
2493941Svenki int err;
2503941Svenki int len;
2513941Svenki ptree_propinfo_t pinfo;
2523941Svenki picl_prophdl_t proph;
2533941Svenki
2543941Svenki err = ptree_get_prop_by_name(nodeh, pname, &proph);
2553941Svenki if (err != PICL_SUCCESS) /* prop doesn't exist */
2563941Svenki return (0);
2573941Svenki
2583941Svenki err = ptree_get_propinfo(proph, &pinfo);
2593941Svenki if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING)
2603941Svenki return (0); /* not string prop */
2613941Svenki
2623941Svenki len = strlen(pval) + 1;
2633941Svenki
2643941Svenki pvalbuf = alloca(len);
2653941Svenki if (pvalbuf == NULL)
2663941Svenki return (0);
2673941Svenki
2683941Svenki err = ptree_get_propval(proph, pvalbuf, len);
2693941Svenki if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0))
2703941Svenki return (1); /* prop match */
2713941Svenki
2723941Svenki return (0);
2733941Svenki }
2743941Svenki
2753941Svenki /*
2763941Svenki * Search this node's children for the given property.
2773941Svenki */
2783941Svenki static int
find_node_by_string_prop(picl_nodehdl_t rooth,const char * pname,const char * pval,picl_nodehdl_t * nodeh)2793941Svenki find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
2803941Svenki const char *pval, picl_nodehdl_t *nodeh)
2813941Svenki {
2823941Svenki picl_nodehdl_t childh;
2833941Svenki int err;
2843941Svenki
2853941Svenki for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
2863941Svenki sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2874669Sfw157321 err = ptree_get_propval_by_name(childh, PICL_PROP_PEER,
2884669Sfw157321 &childh, sizeof (picl_nodehdl_t))) {
2893941Svenki if (err != PICL_SUCCESS)
2903941Svenki return (err);
2913941Svenki
2923941Svenki if (compare_string_propval(childh, pname, pval)) {
2933941Svenki *nodeh = childh;
2943941Svenki return (PICL_SUCCESS);
2953941Svenki }
2963941Svenki }
2973941Svenki return (PICL_ENDOFLIST);
2983941Svenki }
299