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