xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4v/pri/io_dev_label.c (revision 5436:e2b8f7b9f1c5)
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