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