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