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