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