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