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