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