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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <assert.h> 28 #include <alloca.h> 29 #include <string.h> 30 #include <strings.h> 31 #include <limits.h> 32 #include <sys/types.h> 33 #include <sys/pci.h> 34 #include <sys/pcie.h> 35 #include <sys/fm/protocol.h> 36 #include <fm/topo_mod.h> 37 #include <fm/topo_hc.h> 38 #include <libdevinfo.h> 39 #include <hostbridge.h> 40 #include <pcibus.h> 41 #include <did.h> 42 #include <did_props.h> 43 #include <fm/libtopo.h> 44 45 static int ASRU_set(tnode_t *, did_t *, 46 const char *, const char *, const char *); 47 static int FRU_set(tnode_t *, did_t *, 48 const char *, const char *, const char *); 49 static int DEVprop_set(tnode_t *, did_t *, 50 const char *, const char *, const char *); 51 static int DRIVERprop_set(tnode_t *, did_t *, 52 const char *, const char *, const char *); 53 static int MODULEprop_set(tnode_t *, did_t *, 54 const char *, const char *, const char *); 55 static int EXCAP_set(tnode_t *, did_t *, 56 const char *, const char *, const char *); 57 static int BDF_set(tnode_t *, did_t *, 58 const char *, const char *, const char *); 59 static int label_set(tnode_t *, did_t *, 60 const char *, const char *, const char *); 61 static int maybe_di_chars_copy(tnode_t *, did_t *, 62 const char *, const char *, const char *); 63 static int maybe_di_uint_to_str(tnode_t *, did_t *, 64 const char *, const char *, const char *); 65 static int AADDR_set(tnode_t *, did_t *, 66 const char *, const char *, const char *); 67 68 /* 69 * Arrays of "property translation routines" to set the properties a 70 * given type of topology node should have. 71 * 72 * Note that the label_set translation *MUST COME BEFORE* the FRU 73 * translation. For the near term we're setting the FRU fmri to 74 * be a legacy-hc style FMRI based on the label, so the label needs 75 * to have been set before we do the FRU translation. 76 * 77 */ 78 79 static const topo_pgroup_info_t io_pgroup = 80 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 81 static const topo_pgroup_info_t pci_pgroup = 82 { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 83 84 static const topo_pgroup_info_t protocol_pgroup = { 85 TOPO_PGROUP_PROTOCOL, 86 TOPO_STABILITY_PRIVATE, 87 TOPO_STABILITY_PRIVATE, 88 1 89 }; /* Request to create protocol will be ignored by libtopo */ 90 91 txprop_t Fn_common_props[] = { 92 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 93 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 94 { DI_DEVIDPROP, &pci_pgroup, TOPO_PCI_DEVID, maybe_di_uint_to_str }, 95 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 96 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 97 { "serd_io_device_nonfatal_n", &io_pgroup, "serd_io_device_nonfatal_n", 98 maybe_di_uint_to_str }, 99 { "serd_io_device_nonfatal_t", &io_pgroup, "serd_io_device_nonfatal_t", 100 maybe_di_uint_to_str }, 101 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set }, 102 { DI_CLASSPROP, &pci_pgroup, TOPO_PCI_CLASS, maybe_di_uint_to_str }, 103 { DI_VENDIDPROP, &pci_pgroup, TOPO_PCI_VENDID, maybe_di_uint_to_str }, 104 { DI_AADDRPROP, &pci_pgroup, TOPO_PCI_AADDR, AADDR_set }, 105 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 106 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 107 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 108 }; 109 110 txprop_t Dev_common_props[] = { 111 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 112 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 113 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 114 }; 115 116 txprop_t Bus_common_props[] = { 117 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 118 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 119 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 120 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 121 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 122 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 123 }; 124 125 txprop_t RC_common_props[] = { 126 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 127 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 128 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 129 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 130 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set }, 131 { NULL, &pci_pgroup, TOPO_PCI_BDF, BDF_set }, 132 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 133 /* 134 * These props need to be put at the end of table. x86pi has its 135 * own way to set them. 136 */ 137 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 138 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 139 }; 140 141 txprop_t ExHB_common_props[] = { 142 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 143 /* 144 * These props need to be put at the end of table. x86pi has its 145 * own way to set them. 146 */ 147 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 148 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 149 }; 150 151 txprop_t IOB_common_props[] = { 152 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 153 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 154 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 155 }; 156 157 txprop_t HB_common_props[] = { 158 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 159 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 160 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 161 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 162 /* 163 * These props need to be put at the end of table. x86pi has its 164 * own way to set them. 165 */ 166 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 167 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 168 }; 169 170 int Bus_propcnt = sizeof (Bus_common_props) / sizeof (txprop_t); 171 int Dev_propcnt = sizeof (Dev_common_props) / sizeof (txprop_t); 172 int ExHB_propcnt = sizeof (ExHB_common_props) / sizeof (txprop_t); 173 int HB_propcnt = sizeof (HB_common_props) / sizeof (txprop_t); 174 int IOB_propcnt = sizeof (IOB_common_props) / sizeof (txprop_t); 175 int RC_propcnt = sizeof (RC_common_props) / sizeof (txprop_t); 176 int Fn_propcnt = sizeof (Fn_common_props) / sizeof (txprop_t); 177 178 /* 179 * If this devinfo node came originally from OBP data, we'll have prom 180 * properties associated with the node where we can find properties of 181 * interest. We ignore anything after the the first four bytes of the 182 * property, and interpet those first four bytes as our unsigned 183 * integer. If we don't find the property or it's not large enough, 184 * 'val' will remained unchanged and we'll return -1. Otherwise 'val' 185 * gets updated with the property value and we return 0. 186 */ 187 static int 188 promprop2uint(topo_mod_t *mod, di_node_t n, const char *propnm, uint_t *val) 189 { 190 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 191 di_prom_prop_t pp = DI_PROM_PROP_NIL; 192 uchar_t *buf; 193 194 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL) 195 return (-1); 196 197 while ((pp = di_prom_prop_next(ptp, n, pp)) != DI_PROM_PROP_NIL) { 198 if (strcmp(di_prom_prop_name(pp), propnm) == 0) { 199 if (di_prom_prop_data(pp, &buf) < sizeof (uint_t)) 200 continue; 201 bcopy(buf, val, sizeof (uint_t)); 202 return (0); 203 } 204 } 205 return (-1); 206 } 207 208 /* 209 * If this devinfo node was added by the PCI hotplug framework it 210 * doesn't have the PROM properties, but hopefully has the properties 211 * we're looking for attached directly to the devinfo node. We only 212 * care about the first four bytes of the property, which we read as 213 * our unsigned integer. The remaining bytes are ignored. If we 214 * don't find the property we're looking for, or can't get its value, 215 * 'val' remains unchanged and we return -1. Otherwise 'val' gets the 216 * property value and we return 0. 217 */ 218 static int 219 hwprop2uint(di_node_t n, const char *propnm, uint_t *val) 220 { 221 di_prop_t hp = DI_PROP_NIL; 222 uchar_t *buf; 223 224 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { 225 if (strcmp(di_prop_name(hp), propnm) == 0) { 226 if (di_prop_bytes(hp, &buf) < sizeof (uint_t)) 227 continue; 228 bcopy(buf, val, sizeof (uint_t)); 229 return (0); 230 } 231 } 232 return (-1); 233 } 234 235 int 236 di_uintprop_get(topo_mod_t *mod, di_node_t n, const char *pnm, uint_t *pv) 237 { 238 if (hwprop2uint(n, pnm, pv) < 0) 239 if (promprop2uint(mod, n, pnm, pv) < 0) 240 return (-1); 241 return (0); 242 } 243 244 int 245 di_bytes_get(topo_mod_t *mod, di_node_t n, const char *pnm, int *sz, 246 uchar_t **db) 247 { 248 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 249 di_prom_prop_t pp = DI_PROM_PROP_NIL; 250 di_prop_t hp = DI_PROP_NIL; 251 252 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL) 253 return (-1); 254 255 *sz = -1; 256 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { 257 if (strcmp(di_prop_name(hp), pnm) == 0) { 258 if ((*sz = di_prop_bytes(hp, db)) < 0) 259 continue; 260 break; 261 } 262 } 263 if (*sz < 0) { 264 while ((pp = di_prom_prop_next(ptp, n, pp)) != 265 DI_PROM_PROP_NIL) { 266 if (strcmp(di_prom_prop_name(pp), pnm) == 0) { 267 *sz = di_prom_prop_data(pp, db); 268 if (*sz < 0) 269 continue; 270 break; 271 } 272 } 273 } 274 275 if (*sz < 0) 276 return (-1); 277 return (0); 278 } 279 280 /* 281 * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole 282 * story, leaving off the device and function number. Chances are if 283 * devfs doesn't put these on then we'll never see this device as an 284 * error detector called out in an ereport. Unfortunately, there are 285 * races and we sometimes do get ereports from devices that devfs 286 * decides aren't there. For example, the error injector card seems 287 * to bounce in and out of existence according to devfs. We tack on 288 * the missing dev and fn here so that the DEV property used to look 289 * up the topology node is correct. 290 */ 291 static char * 292 dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno) 293 { 294 char *lastslash; 295 char *newpath; 296 int need; 297 298 /* 299 * We only care about the last component of the dev path. If 300 * we don't find a slash, something is weird. 301 */ 302 lastslash = strrchr(path, '/'); 303 assert(lastslash != NULL); 304 305 /* 306 * If an @ sign is present in the last component, the 307 * di_devfs_path() result had the device,fn unit-address. 308 * In that case there's nothing we need do. 309 */ 310 if (strchr(lastslash, '@') != NULL) 311 return (path); 312 313 if (fnno == 0) 314 need = snprintf(NULL, 0, "%s@%x", path, devno); 315 else 316 need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno); 317 need++; 318 319 if ((newpath = topo_mod_alloc(mp, need)) == NULL) { 320 topo_mod_strfree(mp, path); 321 return (NULL); 322 } 323 324 if (fnno == 0) 325 (void) snprintf(newpath, need, "%s@%x", path, devno); 326 else 327 (void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno); 328 329 topo_mod_strfree(mp, path); 330 return (newpath); 331 } 332 333 /* 334 * dev_for_hostbridge() -- For hostbridges we truncate the devfs path 335 * after the first element in the bus address. 336 */ 337 static char * 338 dev_for_hostbridge(topo_mod_t *mp, char *path) 339 { 340 char *lastslash; 341 char *newpath; 342 char *comma; 343 int plen; 344 345 plen = strlen(path) + 1; 346 347 /* 348 * We only care about the last component of the dev path. If 349 * we don't find a slash, something is weird. 350 */ 351 lastslash = strrchr(path, '/'); 352 assert(lastslash != NULL); 353 354 /* 355 * Find the comma in the last component component@x,y, and 356 * truncate the comma and any following number. 357 */ 358 comma = strchr(lastslash, ','); 359 assert(comma != NULL); 360 361 *comma = '\0'; 362 if ((newpath = topo_mod_strdup(mp, path)) == NULL) { 363 topo_mod_free(mp, path, plen); 364 return (NULL); 365 } 366 367 *comma = ','; 368 topo_mod_free(mp, path, plen); 369 return (newpath); 370 } 371 372 /*ARGSUSED*/ 373 static int 374 ASRU_set(tnode_t *tn, did_t *pd, 375 const char *dpnm, const char *tpgrp, const char *tpnm) 376 { 377 topo_mod_t *mp; 378 nvlist_t *fmri; 379 char *dnpath, *path, *fpath, *nm; 380 int d, e, f; 381 382 /* 383 * If this topology node represents a function of device, 384 * set the ASRU to a dev scheme FMRI based on the value of 385 * di_devfs_path(). If that path is NULL, set the ASRU to 386 * be the resource describing this topology node. If this 387 * isn't a function, inherit any ASRU from the parent. 388 */ 389 mp = did_mod(pd); 390 nm = topo_node_name(tn); 391 if ((strcmp(nm, PCI_BUS) == 0 && did_gettnode(pd) && 392 strcmp(topo_node_name(did_gettnode(pd)), HOSTBRIDGE) == 0) || 393 strcmp(nm, PCI_FUNCTION) == 0 || strcmp(nm, PCIEX_FUNCTION) == 0 || 394 strcmp(nm, PCIEX_ROOT) == 0) { 395 if ((dnpath = di_devfs_path(did_dinode(pd))) != NULL) { 396 /* 397 * Dup the path, dev_path_fix() may replace it and 398 * dev_path_fix() wouldn't know to use 399 * di_devfs_path_free() 400 */ 401 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 402 di_devfs_path_free(dnpath); 403 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 404 } 405 di_devfs_path_free(dnpath); 406 did_BDF(pd, NULL, &d, &f); 407 if ((fpath = dev_path_fix(mp, path, d, f)) == NULL) 408 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 409 410 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION, 411 fpath, NULL); 412 if (fmri == NULL) { 413 topo_mod_dprintf(mp, 414 "dev:///%s fmri creation failed.\n", fpath); 415 topo_mod_strfree(mp, fpath); 416 return (-1); 417 } 418 topo_mod_strfree(mp, fpath); 419 } else { 420 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 421 if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL, 422 TOPO_PROP_RESOURCE, &fmri, &e) < 0) 423 return (topo_mod_seterrno(mp, e)); 424 } 425 if (topo_node_asru_set(tn, fmri, 0, &e) < 0) { 426 nvlist_free(fmri); 427 return (topo_mod_seterrno(mp, e)); 428 } 429 nvlist_free(fmri); 430 return (0); 431 } 432 (void) topo_node_asru_set(tn, NULL, 0, &e); 433 434 return (0); 435 } 436 437 /* 438 * Set the FRU property to the hc fmri of this tnode 439 */ 440 int 441 FRU_fmri_set(topo_mod_t *mp, tnode_t *tn) 442 { 443 nvlist_t *fmri; 444 int err, e; 445 446 if (topo_node_resource(tn, &fmri, &err) < 0 || 447 fmri == NULL) { 448 topo_mod_dprintf(mp, "FRU_fmri_set error: %s\n", 449 topo_strerror(topo_mod_errno(mp))); 450 return (topo_mod_seterrno(mp, err)); 451 } 452 e = topo_node_fru_set(tn, fmri, 0, &err); 453 nvlist_free(fmri); 454 if (e < 0) 455 return (topo_mod_seterrno(mp, err)); 456 return (0); 457 } 458 459 tnode_t * 460 find_predecessor(tnode_t *tn, char *mod_name) 461 { 462 tnode_t *pnode = topo_node_parent(tn); 463 464 while (pnode && (strcmp(topo_node_name(pnode), mod_name) != 0)) { 465 pnode = topo_node_parent(pnode); 466 } 467 return (pnode); 468 } 469 470 static int 471 use_predecessor_fru(tnode_t *tn, char *mod_name) 472 { 473 tnode_t *pnode = NULL; 474 nvlist_t *fru = NULL; 475 int err = 0; 476 477 if ((pnode = find_predecessor(tn, mod_name)) == NULL) 478 return (-1); 479 if ((pnode = topo_node_parent(pnode)) == NULL) 480 return (-1); 481 if (topo_node_fru(pnode, &fru, NULL, &err) != 0) 482 return (-1); 483 484 (void) topo_node_fru_set(tn, fru, 0, &err); 485 nvlist_free(fru); 486 487 return (0); 488 } 489 490 static int 491 use_predecessor_label(topo_mod_t *mod, tnode_t *tn, char *mod_name) 492 { 493 tnode_t *pnode = NULL; 494 int err = 0; 495 char *plabel = NULL; 496 497 if ((pnode = find_predecessor(tn, mod_name)) == NULL) 498 return (-1); 499 if ((pnode = topo_node_parent(pnode)) == NULL) 500 return (-1); 501 if (topo_node_label(pnode, &plabel, &err) != 0 || plabel == NULL) 502 return (-1); 503 504 (void) topo_node_label_set(tn, plabel, &err); 505 506 topo_mod_strfree(mod, plabel); 507 508 return (0); 509 } 510 511 512 /*ARGSUSED*/ 513 static int 514 FRU_set(tnode_t *tn, did_t *pd, 515 const char *dpnm, const char *tpgrp, const char *tpnm) 516 { 517 topo_mod_t *mp; 518 char *nm; 519 int e = 0, err = 0; 520 521 nm = topo_node_name(tn); 522 mp = did_mod(pd); 523 524 /* 525 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT, 526 * check for a CPUBOARD predecessor. If found, inherit its 527 * parent's FRU. Otherwise, continue with FRU set. 528 */ 529 if ((strcmp(nm, PCIEX_BUS) == 0) && 530 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) { 531 532 if (use_predecessor_fru(tn, CPUBOARD) == 0) 533 return (0); 534 } 535 /* 536 * If this topology node represents something other than an 537 * ioboard or a device that implements a slot, inherit the 538 * parent's FRU value. If there is no label, inherit our 539 * parent's FRU value. Otherwise, munge up an fmri based on 540 * the label. 541 */ 542 if (strcmp(nm, IOBOARD) != 0 && strcmp(nm, PCI_DEVICE) != 0 && 543 strcmp(nm, PCIEX_DEVICE) != 0 && strcmp(nm, PCIEX_BUS) != 0) { 544 (void) topo_node_fru_set(tn, NULL, 0, &e); 545 return (0); 546 } 547 548 /* 549 * If ioboard, set fru fmri to hc fmri 550 */ 551 if (strcmp(nm, IOBOARD) == 0) { 552 e = FRU_fmri_set(mp, tn); 553 return (e); 554 } else if (strcmp(nm, PCI_DEVICE) == 0 || 555 strcmp(nm, PCIEX_DEVICE) == 0 || strcmp(nm, PCIEX_BUS) == 0) { 556 nvlist_t *in, *out; 557 558 mp = did_mod(pd); 559 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) 560 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 561 if (nvlist_add_uint64(in, "nv1", (uintptr_t)pd) != 0) { 562 nvlist_free(in); 563 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 564 } 565 if (topo_method_invoke(tn, 566 TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_VERSION, 567 in, &out, &err) != 0) { 568 nvlist_free(in); 569 return (topo_mod_seterrno(mp, err)); 570 } 571 nvlist_free(in); 572 (void) topo_node_fru_set(tn, out, 0, &err); 573 if (out != NULL) 574 nvlist_free(out); 575 } else 576 (void) topo_node_fru_set(tn, NULL, 0, &err); 577 578 return (0); 579 } 580 581 /*ARGSUSED*/ 582 static int 583 label_set(tnode_t *tn, did_t *pd, 584 const char *dpnm, const char *tpgrp, const char *tpnm) 585 { 586 topo_mod_t *mp; 587 nvlist_t *in, *out; 588 char *label; 589 int err; 590 591 mp = did_mod(pd); 592 /* 593 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT, 594 * check for a CPUBOARD predecessor. If found, inherit its 595 * parent's Label. Otherwise, continue with label set. 596 */ 597 if ((strcmp(topo_node_name(tn), PCIEX_BUS) == 0) && 598 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) { 599 600 if (use_predecessor_label(mp, tn, CPUBOARD) == 0) 601 return (0); 602 } 603 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) 604 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 605 if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uintptr_t)pd) != 606 0) { 607 nvlist_free(in); 608 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 609 } 610 if (topo_method_invoke(tn, 611 TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) { 612 nvlist_free(in); 613 return (topo_mod_seterrno(mp, err)); 614 } 615 nvlist_free(in); 616 if (out != NULL && 617 nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) { 618 if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL, 619 TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, &err) != 0) { 620 nvlist_free(out); 621 return (topo_mod_seterrno(mp, err)); 622 } 623 nvlist_free(out); 624 } 625 return (0); 626 } 627 628 /*ARGSUSED*/ 629 static int 630 EXCAP_set(tnode_t *tn, did_t *pd, 631 const char *dpnm, const char *tpgrp, const char *tpnm) 632 { 633 int excap = did_excap(pd); 634 int err; 635 int e = 0; 636 637 switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) { 638 case PCIE_PCIECAP_DEV_TYPE_ROOT: 639 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 640 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err); 641 break; 642 case PCIE_PCIECAP_DEV_TYPE_UP: 643 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 644 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWUP, &err); 645 break; 646 case PCIE_PCIECAP_DEV_TYPE_DOWN: 647 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 648 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWDWN, &err); 649 break; 650 case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE: 651 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 652 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_BUS, &err); 653 break; 654 case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: 655 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 656 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCI_BUS, &err); 657 break; 658 case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: 659 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 660 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_DEVICE, &err); 661 break; 662 } 663 if (e != 0) 664 return (topo_mod_seterrno(did_mod(pd), err)); 665 return (0); 666 } 667 668 /*ARGSUSED*/ 669 static int 670 DEVprop_set(tnode_t *tn, did_t *pd, 671 const char *dpnm, const char *tpgrp, const char *tpnm) 672 { 673 topo_mod_t *mp; 674 char *dnpath; 675 char *path, *fpath; 676 int d, f; 677 int err, e; 678 679 mp = did_mod(pd); 680 if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) { 681 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 682 return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT)); 683 } 684 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 685 di_devfs_path_free(dnpath); 686 return (-1); 687 } 688 di_devfs_path_free(dnpath); 689 690 /* The DEV path is modified for hostbridges */ 691 if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) { 692 fpath = dev_for_hostbridge(did_mod(pd), path); 693 } else { 694 did_BDF(pd, NULL, &d, &f); 695 fpath = dev_path_fix(mp, path, d, f); 696 } 697 if (fpath == NULL) 698 return (-1); 699 e = topo_prop_set_string(tn, 700 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, fpath, &err); 701 topo_mod_strfree(mp, fpath); 702 if (e != 0) 703 return (topo_mod_seterrno(mp, err)); 704 return (0); 705 } 706 707 /*ARGSUSED*/ 708 static int 709 DRIVERprop_set(tnode_t *tn, did_t *pd, 710 const char *dpnm, const char *tpgrp, const char *tpnm) 711 { 712 char *dnm; 713 int err; 714 715 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 716 return (0); 717 if (topo_prop_set_string(tn, 718 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0) 719 return (topo_mod_seterrno(did_mod(pd), err)); 720 721 return (0); 722 } 723 724 /*ARGSUSED*/ 725 static int 726 MODULEprop_set(tnode_t *tn, did_t *pd, 727 const char *dpnm, const char *tpgrp, const char *tpnm) 728 { 729 nvlist_t *mod; 730 topo_mod_t *mp; 731 char *dnm; 732 int err; 733 734 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 735 return (0); 736 737 mp = did_mod(pd); 738 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, dnm)) == NULL) 739 return (0); /* driver maybe detached, return success */ 740 741 if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, mod, 742 &err) < 0) { 743 nvlist_free(mod); 744 return (topo_mod_seterrno(mp, err)); 745 } 746 nvlist_free(mod); 747 748 return (0); 749 } 750 751 /*ARGSUSED*/ 752 static int 753 maybe_di_chars_copy(tnode_t *tn, did_t *pd, 754 const char *dpnm, const char *tpgrp, const char *tpnm) 755 { 756 topo_mod_t *mp; 757 uchar_t *typbuf; 758 char *tmpbuf; 759 int sz = -1; 760 int err, e; 761 762 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 763 return (0); 764 mp = did_mod(pd); 765 766 if ((tmpbuf = topo_mod_alloc(mp, sz + 1)) == NULL) 767 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 768 769 bcopy(typbuf, tmpbuf, sz); 770 tmpbuf[sz] = 0; 771 e = topo_prop_set_string(tn, 772 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err); 773 topo_mod_free(mp, tmpbuf, sz + 1); 774 if (e != 0) 775 return (topo_mod_seterrno(mp, err)); 776 return (0); 777 } 778 779 static int 780 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, 781 const char *tpgrp, const char *tpnm) 782 { 783 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 784 int e; 785 786 (void) snprintf(str, 21, "%x", v); 787 if (topo_prop_set_string(tn, 788 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 789 return (topo_mod_seterrno(mp, e)); 790 return (0); 791 } 792 793 static int 794 maybe_di_uint_to_str(tnode_t *tn, did_t *pd, 795 const char *dpnm, const char *tpgrp, const char *tpnm) 796 { 797 uint_t v; 798 799 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0) 800 return (0); 801 802 return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); 803 } 804 805 static int 806 AADDR_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 807 const char *tpnm) 808 { 809 topo_mod_t *mp; 810 uchar_t *typbuf; 811 int sz = -1; 812 int err, e; 813 814 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 815 return (0); 816 817 mp = did_mod(pd); 818 819 e = topo_prop_set_uint32_array(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, 820 /*LINTED*/ 821 (uint32_t *)typbuf, sz/4, &err); 822 823 if (e != 0) 824 return (topo_mod_seterrno(mp, err)); 825 return (0); 826 } 827 828 /*ARGSUSED*/ 829 static int 830 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 831 const char *tpnm) 832 { 833 int bdf; 834 char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */ 835 int e; 836 837 if ((bdf = did_bdf(pd)) <= 0) 838 return (0); 839 840 (void) snprintf(str, 23, "0x%x", bdf); 841 if (topo_prop_set_string(tn, 842 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 843 return (topo_mod_seterrno(did_mod(pd), e)); 844 return (0); 845 } 846 847 int 848 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum) 849 { 850 topo_mod_t *mp; 851 int i, r, e; 852 853 mp = did_mod(pd); 854 for (i = 0; i < txnum; i++) { 855 /* 856 * Ensure the property group has been created. 857 */ 858 if (txarray[i].tx_tpgroup != NULL) { 859 if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, &e) 860 < 0) { 861 if (e != ETOPO_PROP_DEFD) 862 return (topo_mod_seterrno(mp, e)); 863 } 864 } 865 866 topo_mod_dprintf(mp, 867 "Setting property %s in group %s.\n", 868 txarray[i].tx_tprop, txarray[i].tx_tpgroup->tpi_name); 869 r = txarray[i].tx_xlate(tn, pd, 870 txarray[i].tx_diprop, txarray[i].tx_tpgroup->tpi_name, 871 txarray[i].tx_tprop); 872 if (r != 0) { 873 topo_mod_dprintf(mp, "failed.\n"); 874 topo_mod_dprintf(mp, "Error was %s.\n", 875 topo_strerror(topo_mod_errno(mp))); 876 return (-1); 877 } 878 topo_mod_dprintf(mp, "succeeded.\n"); 879 } 880 return (0); 881 } 882