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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <alloca.h> 28 #include <assert.h> 29 #include <fm/topo_mod.h> 30 #include <libnvpair.h> 31 #include <string.h> 32 #include <sys/fm/protocol.h> 33 34 #include <did.h> 35 #include <pcibus.h> 36 #include <pcibus_labels.h> 37 38 extern slotnm_rewrite_t *Slot_Rewrites; 39 extern physlot_names_t *Physlot_Names; 40 extern missing_names_t *Missing_Names; 41 42 /* 43 * Do a platform specific label lookup based on physical slot number. 44 */ 45 static const char * 46 pci_label_physlot_lookup(topo_mod_t *mod, char *platform, did_t *dp) 47 { 48 const char *rlabel = NULL; 49 int n, p, i; 50 51 if ((n = did_physlot(dp)) < 0 || Physlot_Names == NULL || 52 platform == NULL) 53 return (NULL); 54 55 for (p = 0; p < Physlot_Names->psn_nplats; p++) { 56 if (strcmp(Physlot_Names->psn_names[p].pnm_platform, 57 platform) != 0) 58 continue; 59 for (i = 0; i < Physlot_Names->psn_names[p].pnm_nnames; i++) { 60 physnm_t ps; 61 ps = Physlot_Names->psn_names[p].pnm_names[i]; 62 if (ps.ps_num == n) { 63 rlabel = ps.ps_label; 64 break; 65 } 66 } 67 break; 68 } 69 if (rlabel != NULL) { 70 topo_mod_dprintf(mod, "pci_label_physlot_lookup: " 71 "label=%s\n", rlabel); 72 } 73 return (rlabel); 74 } 75 76 /* 77 * Do a platform specific label lookup based on slot name. 78 */ 79 static const char * 80 pci_label_slotname_lookup(topo_mod_t *mod, char *platform, const char *label) 81 { 82 const char *rlabel = label; 83 int s, i; 84 85 if (Slot_Rewrites == NULL) 86 return (rlabel); 87 88 for (s = 0; s < Slot_Rewrites->srw_nplats; s++) { 89 if (strcmp(Slot_Rewrites->srw_platrewrites[s].prw_platform, 90 platform) != 0) 91 continue; 92 for (i = 0; 93 i < Slot_Rewrites->srw_platrewrites[s].prw_nrewrites; 94 i++) { 95 slot_rwd_t rw; 96 rw = Slot_Rewrites->srw_platrewrites[s].prw_rewrites[i]; 97 if (strcmp(rw.srw_obp, label) == 0) { 98 rlabel = rw.srw_new; 99 break; 100 } 101 } 102 break; 103 } 104 assert(rlabel != NULL); 105 topo_mod_dprintf(mod, "pci_label_slotname_lookup: label=%s\n", rlabel); 106 return (rlabel); 107 } 108 109 /* 110 * Do a platform specific label lookup based on bus, dev, etc. 111 */ 112 static const char * 113 pci_label_missing_lookup(topo_mod_t *mod, char *platform, did_t *dp) 114 { 115 const char *rlabel = NULL; 116 int board, bridge, rc, bus, dev; 117 int p, i; 118 119 if (Missing_Names == NULL) 120 return (NULL); 121 bridge = did_bridge(dp); 122 board = did_board(dp); 123 rc = did_rc(dp); 124 did_BDF(dp, &bus, &dev, NULL); 125 126 topo_mod_dprintf(mod, "Missing a name for %d, %d, %d, %d, %d ?\n", 127 board, bridge, rc, bus, dev); 128 129 for (p = 0; p < Missing_Names->mn_nplats; p++) { 130 if (strcmp(Missing_Names->mn_names[p].pdl_platform, 131 platform) != 0) 132 continue; 133 for (i = 0; i < Missing_Names->mn_names[p].pdl_nnames; i++) { 134 devlab_t m; 135 m = Missing_Names->mn_names[p].pdl_names[i]; 136 if (m.dl_board == board && m.dl_bridge == bridge && 137 m.dl_rc == rc && m.dl_bus == bus && 138 m.dl_dev == dev) { 139 rlabel = m.dl_label; 140 break; 141 } 142 } 143 break; 144 } 145 if (rlabel != NULL) { 146 topo_mod_dprintf(mod, "pci_label_missing_lookup: " 147 "label=%s\n", rlabel); 148 } 149 return (rlabel); 150 } 151 152 /* 153 * Do an overall slot label lookup for the device node. 154 */ 155 char * 156 pci_slot_label_lookup(topo_mod_t *mod, tnode_t *node, did_t *dp, did_t *pdp) 157 { 158 tnode_t *anode, *apnode; 159 did_t *adp, *apdp; 160 char *plat, *pp, *l, *ancestor_l = NULL, *new_l = NULL; 161 int err, b, d, f, done = 0; 162 size_t len; 163 164 did_BDF(dp, &b, &d, &f); 165 topo_mod_dprintf(mod, "pci_slot_label_lookup: entry: node=%p: " 166 "node_name=%s[%d], dp=%p, dp_bdf=%d/%d/%d, pdp=%p \n", node, 167 topo_node_name(node), topo_node_instance(node), dp, b, d, f, pdp); 168 169 /* 170 * If this device has a physical slot number then check if 171 * an ancestor also has a slot label. 172 * 173 * If an ancestor has a slot label, then this node's label 174 * is generated by concatenating a default label onto the 175 * ancestor's label. 176 * 177 * We grab pairs of ancestors (parent and child) as we go up 178 * the tree because the parent is checked for the presence 179 * of a slot while the child contains the label. 180 * 181 * Note that this algorithm only applies to nodes which have 182 * a physcal slot number. (i.e. PCIE devices or PCI/PCIX 183 * devices off of a PCIE to PCIX switch) 184 */ 185 if (did_physlot(pdp) >= 0) { 186 187 topo_mod_dprintf(mod, "pci_slot_label_lookup: node=%p: " 188 "node has a physical slot=%d, checking ancestors " 189 "for slots\n", node, did_physlot(pdp)); 190 191 /* 192 * Get this device's physical slot name. 193 */ 194 l = (char *)did_physlot_name(pdp, d); 195 196 anode = topo_node_parent(node); 197 198 /* 199 * Check ancestors for a slot label until we 200 * either find one or hit a non-pci device. 201 */ 202 while (!done) { 203 204 /* 205 * Get next ancestor node and data pointers. 206 */ 207 anode = topo_node_parent(anode); 208 if (anode != NULL) { 209 adp = did_find(mod, 210 topo_node_getspecific(anode)); 211 apnode = topo_node_parent(anode); 212 if (apnode != NULL) 213 apdp = did_find(mod, 214 topo_node_getspecific(apnode)); 215 else 216 apdp = NULL; 217 } else { 218 apnode = NULL; 219 apdp = adp = NULL; 220 } 221 222 topo_mod_dprintf(mod, "pci_slot_label_lookup: " 223 "node=%p: checking next two ancestors: anode=%p, " 224 "adp=%p apnode=%p, apdp=%p\n", 225 node, anode, adp, apnode, apdp); 226 if ((anode != NULL) && (adp != NULL)) { 227 did_BDF(adp, &b, &d, &f); 228 topo_mod_dprintf(mod, "pci_slot_label_lookup: " 229 "node=%p: anode_name=%s[%d] " 230 "anode_bdf=%d/%d/%d\n", 231 node, topo_node_name(anode), 232 topo_node_instance(anode), b, d, f); 233 } 234 if ((apnode != NULL) && (apdp != NULL)) { 235 did_BDF(apdp, &b, &d, &f); 236 topo_mod_dprintf(mod, "pci_slot_label_lookup: " 237 "node=%p: apnode_name=%s[%d] " 238 "apnode_bdf=%d/%d/%d\n", 239 node, topo_node_name(apnode), 240 topo_node_instance(apnode), b, d, f); 241 } 242 243 /* 244 * If the ancestors do not exist or are not pci 245 * devices then we're done searching. 246 * 247 * Otherwise, if the ancestor has a physical slot, 248 * and it is a different slot than the one we 249 * started with then lookup the ancestor label, 250 * and we're done. 251 */ 252 if ((anode == NULL) || (adp == NULL) || 253 (apnode == NULL) || (apdp == NULL)) { 254 done++; 255 } else if (did_physlot_exists(apdp) && 256 (apdp != pdp)) { 257 if (topo_node_label(anode, &ancestor_l, 258 &err) != 0) { 259 topo_mod_dprintf(mod, 260 "pci_slot_label_lookup: " 261 "node=%p: topo_node_label() " 262 "FAILED!", node); 263 (void) topo_mod_seterrno(mod, err); 264 return (NULL); 265 } 266 done++; 267 topo_mod_dprintf(mod, 268 "pci_slot_label_lookup: node=%p: " 269 "found ancestor with a slot, " 270 "label=%s ", node, ancestor_l); 271 } 272 } 273 if (ancestor_l == NULL) { 274 topo_mod_dprintf(mod, "pci_slot_label_lookup: " 275 "node=%p: no ancestor slot found\n", node); 276 } 277 } 278 279 /* 280 * If we found an ancestor with a slot label, and this node has 281 * a physical slot number label then concatenate the two to form 282 * this node's label. Otherwise, do a full slot label lookup. 283 */ 284 if (ancestor_l && l) { 285 topo_mod_dprintf(mod, "pci_slot_label_lookup: node=%p: " 286 "will concatenate: ancestor_l=%s and l=%s\n", 287 node, ancestor_l, l); 288 len = strlen(ancestor_l) + strlen(l) + 2; 289 new_l = alloca(len); 290 (void) snprintf(new_l, len, "%s/%s", ancestor_l, l); 291 l = new_l; 292 } else { 293 /* 294 * Get platform name used for lookups. 295 */ 296 if (topo_prop_get_string(node, FM_FMRI_AUTHORITY, 297 FM_FMRI_AUTH_PRODUCT, &plat, &err) < 0) { 298 (void) topo_mod_seterrno(mod, err); 299 return (NULL); 300 } 301 /* 302 * Trim SUNW, from the platform name 303 */ 304 pp = strchr(plat, ','); 305 if (pp == NULL) 306 pp = plat; 307 else 308 ++pp; 309 /* 310 * Get device number used for lookup. 311 */ 312 did_BDF(dp, NULL, &d, NULL); 313 314 /* 315 * The slot label is determined in the following order: 316 * - Platform specific lookup based on physical slot #. 317 * - Platform specific lookup based on default label string. 318 * - Platform specific lookup based on device number. 319 * - Default label. 320 * The default label is based on the slot names property 321 * if it exists, else it is a generic name derived from 322 * the slot #. 323 */ 324 if ((l = (char *)pci_label_physlot_lookup(mod, pp, pdp)) 325 == NULL) { 326 if ((l = (char *)did_physlot_name(pdp, d)) != NULL) { 327 l = (char *) 328 pci_label_slotname_lookup(mod, pp, l); 329 } else { 330 l = (char *) 331 pci_label_missing_lookup(mod, pp, dp); 332 } 333 } 334 topo_mod_strfree(mod, plat); 335 } 336 337 /* 338 * If we calculated a slot label, then save it in the 339 * node's data structure so we can free it later. 340 */ 341 if (l) { 342 if (did_slot_label_get(dp) != NULL) 343 topo_mod_strfree(mod, did_slot_label_get(dp)); 344 l = topo_mod_strdup(mod, l); 345 did_slot_label_set(dp, l); 346 } 347 348 topo_mod_dprintf(mod, "pci_slot_label_lookup: exit: " 349 "node=%p: label=%s\n", node, (l ? l : "NULL")); 350 351 return (l); 352 } 353 354 int 355 pci_label_cmn(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out) 356 { 357 uint64_t ptr; 358 char *l; 359 did_t *dp, *pdp; 360 tnode_t *pnode; 361 char *nm; 362 int err; 363 364 /* 365 * If it's not a device or a PCI-express bus (which could potentially 366 * represent a slot, and therefore we might need to capture its slot 367 * name information), just inherit any label from our parent 368 */ 369 *out = NULL; 370 nm = topo_node_name(node); 371 if (strcmp(nm, PCI_DEVICE) != 0 && strcmp(nm, PCIEX_DEVICE) != 0 && 372 strcmp(nm, PCIEX_BUS) != 0) { 373 if (topo_node_label_set(node, NULL, &err) < 0) 374 if (err != ETOPO_PROP_NOENT) 375 return (topo_mod_seterrno(mod, err)); 376 return (0); 377 } 378 379 if (nvlist_lookup_uint64(in, TOPO_METH_LABEL_ARG_NVL, &ptr) != 0) { 380 topo_mod_dprintf(mod, 381 "label method argument not found.\n"); 382 return (-1); 383 } 384 dp = (did_t *)(uintptr_t)ptr; 385 pnode = did_gettnode(dp); 386 pdp = did_find(mod, topo_node_getspecific(pnode)); 387 388 /* 389 * Is there a slot label associated with the device? 390 */ 391 if ((l = pci_slot_label_lookup(mod, node, dp, pdp)) != NULL) { 392 nvlist_t *rnvl; 393 394 if (topo_mod_nvalloc(mod, &rnvl, NV_UNIQUE_NAME) != 0 || 395 nvlist_add_string(rnvl, TOPO_METH_LABEL_RET_STR, l) != 0) 396 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 397 *out = rnvl; 398 return (0); 399 } else { 400 if (topo_node_label_set(node, NULL, &err) < 0) 401 if (err != ETOPO_PROP_NOENT) 402 return (topo_mod_seterrno(mod, err)); 403 return (0); 404 } 405 } 406 407 int 408 pci_fru_cmn(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out) 409 { 410 int err = 0; 411 uint64_t ptr; 412 did_t *dp, *pdp; 413 tnode_t *pnode; 414 char *nm; 415 416 *out = NULL; 417 nm = topo_node_name(node); 418 if (strcmp(nm, PCI_DEVICE) != 0 && strcmp(nm, PCIEX_DEVICE) != 0 && 419 strcmp(nm, PCIEX_BUS) != 0) 420 return (0); 421 422 if (nvlist_lookup_uint64(in, "nv1", &ptr) != 0) { 423 topo_mod_dprintf(mod, 424 "label method argument not found.\n"); 425 return (-1); 426 } 427 dp = (did_t *)(uintptr_t)ptr; 428 pnode = did_gettnode(dp); 429 pdp = did_find(mod, topo_node_getspecific(pnode)); 430 431 /* 432 * Is there a slot label associated with the device? 433 */ 434 if (pci_slot_label_lookup(mod, pnode, dp, pdp) != NULL) { 435 nvlist_t *rnvl; 436 437 if (topo_node_resource(node, &rnvl, &err) < 0 || rnvl == NULL) { 438 topo_mod_dprintf(mod, "pci_fru_compute error: %s\n", 439 topo_strerror(topo_mod_errno(mod))); 440 return (topo_mod_seterrno(mod, err)); 441 } 442 *out = rnvl; 443 } 444 return (0); 445 } 446