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