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 2006 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 42 #include <hostbridge.h> 43 #include <pcibus.h> 44 #include <did.h> 45 #include <did_props.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 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 66 /* 67 * Arrays of "property translation routines" to set the properties a 68 * given type of topology node should have. 69 * 70 * Note that the label_set translation *MUST COME BEFORE* the FRU 71 * translation. For the near term we're setting the FRU fmri to 72 * be a legacy-hc style FMRI based on the label, so the label needs 73 * to have been set before we do the FRU translation. 74 * 75 */ 76 77 static const topo_pgroup_info_t io_pgroup = 78 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 79 static const topo_pgroup_info_t pci_pgroup = 80 { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 81 82 static const topo_pgroup_info_t protocol_pgroup = { 83 TOPO_PGROUP_PROTOCOL, 84 TOPO_STABILITY_PRIVATE, 85 TOPO_STABILITY_PRIVATE, 86 1 87 }; /* Request to create protocol will be ignored by libtopo */ 88 89 txprop_t Fn_common_props[] = { 90 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 91 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 92 { DI_DEVIDPROP, &pci_pgroup, TOPO_PCI_DEVID, maybe_di_uint_to_str }, 93 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 94 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set }, 95 { DI_CLASSPROP, &pci_pgroup, TOPO_PCI_CLASS, maybe_di_uint_to_str }, 96 { DI_VENDIDPROP, &pci_pgroup, TOPO_PCI_VENDID, maybe_di_uint_to_str }, 97 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 98 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 99 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 100 }; 101 102 txprop_t Dev_common_props[] = { 103 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 104 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 105 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 106 }; 107 108 txprop_t Bus_common_props[] = { 109 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 110 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 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 RC_common_props[] = { 117 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 118 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 119 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 120 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set }, 121 { NULL, &pci_pgroup, TOPO_PCI_BDF, BDF_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 ExHB_common_props[] = { 128 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 129 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 130 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 131 }; 132 133 txprop_t IOB_common_props[] = { 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 HB_common_props[] = { 140 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 141 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 142 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 143 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 144 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 145 }; 146 147 int Bus_propcnt = sizeof (Bus_common_props) / sizeof (txprop_t); 148 int Dev_propcnt = sizeof (Dev_common_props) / sizeof (txprop_t); 149 int ExHB_propcnt = sizeof (ExHB_common_props) / sizeof (txprop_t); 150 int HB_propcnt = sizeof (HB_common_props) / sizeof (txprop_t); 151 int IOB_propcnt = sizeof (IOB_common_props) / sizeof (txprop_t); 152 int RC_propcnt = sizeof (RC_common_props) / sizeof (txprop_t); 153 int Fn_propcnt = sizeof (Fn_common_props) / sizeof (txprop_t); 154 155 /* 156 * If this devinfo node came originally from OBP data, we'll have prom 157 * properties associated with the node where we can find properties of 158 * interest. We ignore anything after the the first four bytes of the 159 * property, and interpet those first four bytes as our unsigned 160 * integer. If we don't find the property or it's not large enough, 161 * 'val' will remained unchanged and we'll return -1. Otherwise 'val' 162 * gets updated with the property value and we return 0. 163 */ 164 static int 165 promprop2uint(topo_mod_t *mod, di_node_t n, const char *propnm, uint_t *val) 166 { 167 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 168 di_prom_prop_t pp = DI_PROM_PROP_NIL; 169 uchar_t *buf; 170 171 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL) 172 return (-1); 173 174 while ((pp = di_prom_prop_next(ptp, n, pp)) != DI_PROM_PROP_NIL) { 175 if (strcmp(di_prom_prop_name(pp), propnm) == 0) { 176 if (di_prom_prop_data(pp, &buf) < sizeof (uint_t)) 177 continue; 178 bcopy(buf, val, sizeof (uint_t)); 179 return (0); 180 } 181 } 182 return (-1); 183 } 184 185 /* 186 * If this devinfo node was added by the PCI hotplug framework it 187 * doesn't have the PROM properties, but hopefully has the properties 188 * we're looking for attached directly to the devinfo node. We only 189 * care about the first four bytes of the property, which we read as 190 * our unsigned integer. The remaining bytes are ignored. If we 191 * don't find the property we're looking for, or can't get its value, 192 * 'val' remains unchanged and we return -1. Otherwise 'val' gets the 193 * property value and we return 0. 194 */ 195 static int 196 hwprop2uint(di_node_t n, const char *propnm, uint_t *val) 197 { 198 di_prop_t hp = DI_PROP_NIL; 199 uchar_t *buf; 200 201 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { 202 if (strcmp(di_prop_name(hp), propnm) == 0) { 203 if (di_prop_bytes(hp, &buf) < sizeof (uint_t)) 204 continue; 205 bcopy(buf, val, sizeof (uint_t)); 206 return (0); 207 } 208 } 209 return (-1); 210 } 211 212 int 213 di_uintprop_get(topo_mod_t *mod, di_node_t n, const char *pnm, uint_t *pv) 214 { 215 if (hwprop2uint(n, pnm, pv) < 0) 216 if (promprop2uint(mod, n, pnm, pv) < 0) 217 return (-1); 218 return (0); 219 } 220 221 int 222 di_bytes_get(topo_mod_t *mod, di_node_t n, const char *pnm, int *sz, 223 uchar_t **db) 224 { 225 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 226 di_prom_prop_t pp = DI_PROM_PROP_NIL; 227 di_prop_t hp = DI_PROP_NIL; 228 229 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL) 230 return (-1); 231 232 *sz = -1; 233 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { 234 if (strcmp(di_prop_name(hp), pnm) == 0) { 235 if ((*sz = di_prop_bytes(hp, db)) < 0) 236 continue; 237 break; 238 } 239 } 240 if (*sz < 0) { 241 while ((pp = di_prom_prop_next(ptp, n, pp)) != 242 DI_PROM_PROP_NIL) { 243 if (strcmp(di_prom_prop_name(pp), pnm) == 0) { 244 *sz = di_prom_prop_data(pp, db); 245 if (*sz < 0) 246 continue; 247 break; 248 } 249 } 250 } 251 252 if (*sz < 0) 253 return (-1); 254 return (0); 255 } 256 257 /* 258 * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole 259 * story, leaving off the device and function number. Chances are if 260 * devfs doesn't put these on then we'll never see this device as an 261 * error detector called out in an ereport. Unfortunately, there are 262 * races and we sometimes do get ereports from devices that devfs 263 * decides aren't there. For example, the error injector card seems 264 * to bounce in and out of existence according to devfs. We tack on 265 * the missing dev and fn here so that the DEV property used to look 266 * up the topology node is correct. 267 */ 268 static char * 269 dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno) 270 { 271 char *lastslash; 272 char *newpath; 273 int need; 274 275 /* 276 * We only care about the last component of the dev path. If 277 * we don't find a slash, something is weird. 278 */ 279 lastslash = strrchr(path, '/'); 280 assert(lastslash != NULL); 281 282 /* 283 * If an @ sign is present in the last component, the 284 * di_devfs_path() result had the device,fn unit-address. 285 * In that case there's nothing we need do. 286 */ 287 if (strchr(lastslash, '@') != NULL) 288 return (path); 289 290 if (fnno == 0) 291 need = snprintf(NULL, 0, "%s@%x", path, devno); 292 else 293 need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno); 294 need++; 295 296 if ((newpath = topo_mod_alloc(mp, need)) == NULL) { 297 topo_mod_strfree(mp, path); 298 return (NULL); 299 } 300 301 if (fnno == 0) 302 (void) snprintf(newpath, need, "%s@%x", path, devno); 303 else 304 (void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno); 305 306 topo_mod_strfree(mp, path); 307 return (newpath); 308 } 309 310 /* 311 * dev_for_hostbridge() -- For hostbridges we truncate the devfs path 312 * after the first element in the bus address. 313 */ 314 static char * 315 dev_for_hostbridge(topo_mod_t *mp, char *path) 316 { 317 char *lastslash; 318 char *newpath; 319 char *comma; 320 321 /* 322 * We only care about the last component of the dev path. If 323 * we don't find a slash, something is weird. 324 */ 325 lastslash = strrchr(path, '/'); 326 assert(lastslash != NULL); 327 328 /* 329 * Find the comma in the last component component@x,y, and 330 * truncate the comma and any following number. 331 */ 332 comma = strchr(lastslash, ','); 333 assert(comma != NULL); 334 335 *comma = '\0'; 336 if ((newpath = topo_mod_strdup(mp, path)) == NULL) 337 return (path); 338 *comma = ','; 339 topo_mod_strfree(mp, path); 340 return (newpath); 341 } 342 343 /*ARGSUSED*/ 344 static int 345 ASRU_set(tnode_t *tn, did_t *pd, 346 const char *dpnm, const char *tpgrp, const char *tpnm) 347 { 348 topo_mod_t *mp; 349 nvlist_t *fmri; 350 char *dnpath, *path, *fpath, *nm; 351 int d, e, f; 352 353 /* 354 * If this topology node represents a function of device, 355 * set the ASRU to a dev scheme FMRI based on the value of 356 * di_devfs_path(). If that path is NULL, set the ASRU to 357 * be the resource describing this topology node. If this 358 * isn't a function, inherit any ASRU from the parent. 359 */ 360 mp = did_mod(pd); 361 nm = topo_node_name(tn); 362 if (strcmp(nm, PCI_FUNCTION) == 0 || strcmp(nm, PCIEX_FUNCTION) == 0 || 363 strcmp(nm, PCIEX_ROOT) == 0) { 364 if ((dnpath = di_devfs_path(did_dinode(pd))) != NULL) { 365 /* 366 * Dup the path, dev_path_fix() may replace it and 367 * dev_path_fix() wouldn't know to use 368 * di_devfs_path_free() 369 */ 370 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 371 di_devfs_path_free(dnpath); 372 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 373 } 374 di_devfs_path_free(dnpath); 375 did_BDF(pd, NULL, &d, &f); 376 if ((fpath = dev_path_fix(mp, path, d, f)) == NULL) 377 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 378 379 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION, 380 fpath, NULL); 381 if (fmri == NULL) { 382 topo_mod_dprintf(mp, 383 "dev:///%s fmri creation failed.\n", fpath); 384 topo_mod_strfree(mp, fpath); 385 return (-1); 386 } 387 topo_mod_strfree(mp, fpath); 388 } else { 389 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 390 if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL, 391 TOPO_PROP_RESOURCE, &fmri, &e) < 0) 392 return (topo_mod_seterrno(mp, e)); 393 } 394 if (topo_node_asru_set(tn, fmri, 0, &e) < 0) { 395 nvlist_free(fmri); 396 return (topo_mod_seterrno(mp, e)); 397 } 398 nvlist_free(fmri); 399 return (0); 400 } 401 (void) topo_node_asru_set(tn, NULL, 0, &e); 402 403 return (0); 404 } 405 406 /* 407 * Hopefully this hack routine goes away when fmdump can print the labels. 408 */ 409 static int 410 FRU_fmri_hack(topo_mod_t *mp, tnode_t *tn, const char *label) 411 { 412 char buf[PATH_MAX]; 413 nvlist_t *fmri; 414 int err, e; 415 416 417 (void) snprintf(buf, PATH_MAX, "hc:///component=%s", label); 418 if (topo_mod_str2nvl(mp, buf, &fmri) < 0) 419 return (-1); 420 421 e = topo_node_fru_set(tn, fmri, 0, &err); 422 nvlist_free(fmri); 423 if (e < 0) 424 return (topo_mod_seterrno(mp, err)); 425 return (0); 426 } 427 428 /*ARGSUSED*/ 429 static int 430 FRU_set(tnode_t *tn, did_t *pd, 431 const char *dpnm, const char *tpgrp, const char *tpnm) 432 { 433 topo_mod_t *mp; 434 char *label, *nm; 435 int e; 436 437 nm = topo_node_name(tn); 438 mp = did_mod(pd); 439 440 /* 441 * If this topology node represents something other than an 442 * ioboard or a device that implements a slot, inherit the 443 * parent's FRU value. If there is no label, inherit our 444 * parent's FRU value. Otherwise, munge up an fmri based on 445 * the label. 446 */ 447 if (strcmp(nm, "ioboard") != 0 && strcmp(nm, PCI_DEVICE) != 0 && 448 strcmp(nm, PCIEX_DEVICE) != 0) { 449 (void) topo_node_fru_set(tn, NULL, 0, &e); 450 return (0); 451 } 452 453 if (topo_prop_get_string(tn, 454 TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, &label, &e) < 0) { 455 if (e != ETOPO_PROP_NOENT) 456 return (topo_mod_seterrno(mp, e)); 457 (void) topo_node_fru_set(tn, NULL, 0, &e); 458 return (0); 459 } 460 e = FRU_fmri_hack(mp, tn, label); 461 topo_mod_strfree(mp, label); 462 return (e); 463 } 464 465 /*ARGSUSED*/ 466 static int 467 label_set(tnode_t *tn, did_t *pd, 468 const char *dpnm, const char *tpgrp, const char *tpnm) 469 { 470 topo_mod_t *mp; 471 nvlist_t *in, *out; 472 char *label; 473 int err; 474 475 mp = did_mod(pd); 476 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) 477 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 478 if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uintptr_t)pd) != 479 0) { 480 nvlist_free(in); 481 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 482 } 483 if (topo_method_invoke(tn, 484 TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) { 485 nvlist_free(in); 486 return (topo_mod_seterrno(mp, err)); 487 } 488 nvlist_free(in); 489 if (out != NULL && 490 nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) { 491 if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL, 492 TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, &err) != 0) { 493 nvlist_free(out); 494 return (topo_mod_seterrno(mp, err)); 495 } 496 nvlist_free(out); 497 } 498 return (0); 499 } 500 501 /*ARGSUSED*/ 502 static int 503 EXCAP_set(tnode_t *tn, did_t *pd, 504 const char *dpnm, const char *tpgrp, const char *tpnm) 505 { 506 int excap; 507 int err; 508 int e = 0; 509 510 if ((excap = did_excap(pd)) <= 0) 511 return (0); 512 513 switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) { 514 case PCIE_PCIECAP_DEV_TYPE_ROOT: 515 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 516 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err); 517 break; 518 case PCIE_PCIECAP_DEV_TYPE_UP: 519 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 520 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWUP, &err); 521 break; 522 case PCIE_PCIECAP_DEV_TYPE_DOWN: 523 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 524 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWDWN, &err); 525 break; 526 case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE: 527 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 528 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_BUS, &err); 529 break; 530 case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: 531 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 532 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCI_BUS, &err); 533 break; 534 case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: 535 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 536 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_DEVICE, &err); 537 break; 538 } 539 if (e != 0) 540 return (topo_mod_seterrno(did_mod(pd), err)); 541 return (0); 542 } 543 544 /*ARGSUSED*/ 545 static int 546 DEVprop_set(tnode_t *tn, did_t *pd, 547 const char *dpnm, const char *tpgrp, const char *tpnm) 548 { 549 topo_mod_t *mp; 550 char *dnpath; 551 char *path, *fpath; 552 int d, f; 553 int err, e; 554 555 mp = did_mod(pd); 556 if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) { 557 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 558 return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT)); 559 } 560 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 561 di_devfs_path_free(dnpath); 562 return (-1); 563 } 564 di_devfs_path_free(dnpath); 565 566 /* The DEV path is modified for hostbridges */ 567 if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) { 568 fpath = dev_for_hostbridge(did_mod(pd), path); 569 } else { 570 did_BDF(pd, NULL, &d, &f); 571 fpath = dev_path_fix(mp, path, d, f); 572 } 573 if (fpath == NULL) 574 return (-1); 575 e = topo_prop_set_string(tn, 576 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, fpath, &err); 577 topo_mod_strfree(mp, fpath); 578 if (e != 0) 579 return (topo_mod_seterrno(mp, err)); 580 return (0); 581 } 582 583 /*ARGSUSED*/ 584 static int 585 DRIVERprop_set(tnode_t *tn, did_t *pd, 586 const char *dpnm, const char *tpgrp, const char *tpnm) 587 { 588 char *dnm; 589 int err; 590 591 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 592 return (0); 593 if (topo_prop_set_string(tn, 594 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0) 595 return (topo_mod_seterrno(did_mod(pd), err)); 596 597 return (0); 598 } 599 600 /*ARGSUSED*/ 601 static int 602 maybe_di_chars_copy(tnode_t *tn, did_t *pd, 603 const char *dpnm, const char *tpgrp, const char *tpnm) 604 { 605 topo_mod_t *mp; 606 uchar_t *typbuf; 607 char *tmpbuf; 608 int sz = -1; 609 int err, e; 610 611 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 612 return (0); 613 mp = did_mod(pd); 614 tmpbuf = topo_mod_alloc(mp, sz + 1); 615 bcopy(typbuf, tmpbuf, sz); 616 tmpbuf[sz] = 0; 617 e = topo_prop_set_string(tn, 618 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err); 619 topo_mod_free(mp, tmpbuf, sz + 1); 620 if (e != 0) 621 return (topo_mod_seterrno(mp, err)); 622 return (0); 623 } 624 625 static int 626 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, 627 const char *tpgrp, const char *tpnm) 628 { 629 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 630 int e; 631 632 (void) snprintf(str, 21, "%x", v); 633 if (topo_prop_set_string(tn, 634 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 635 return (topo_mod_seterrno(mp, e)); 636 return (0); 637 } 638 639 static int 640 maybe_di_uint_to_str(tnode_t *tn, did_t *pd, 641 const char *dpnm, const char *tpgrp, const char *tpnm) 642 { 643 uint_t v; 644 645 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0) 646 return (0); 647 648 return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); 649 } 650 651 /*ARGSUSED*/ 652 static int 653 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 654 const char *tpnm) 655 { 656 int bdf; 657 char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */ 658 int e; 659 660 if ((bdf = did_bdf(pd)) <= 0) 661 return (0); 662 663 (void) snprintf(str, 23, "0x%x", bdf); 664 if (topo_prop_set_string(tn, 665 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 666 return (topo_mod_seterrno(did_mod(pd), e)); 667 return (0); 668 } 669 670 int 671 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum) 672 { 673 topo_mod_t *mp; 674 int i, r, e; 675 676 mp = did_mod(pd); 677 for (i = 0; i < txnum; i++) { 678 /* 679 * Ensure the property group has been created. 680 */ 681 if (txarray[i].tx_tpgroup != NULL) { 682 if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, &e) 683 < 0) { 684 if (e != ETOPO_PROP_DEFD) 685 return (topo_mod_seterrno(mp, e)); 686 } 687 } 688 689 topo_mod_dprintf(mp, 690 "Setting property %s in group %s.\n", 691 txarray[i].tx_tprop, txarray[i].tx_tpgroup->tpi_name); 692 r = txarray[i].tx_xlate(tn, pd, 693 txarray[i].tx_diprop, txarray[i].tx_tpgroup->tpi_name, 694 txarray[i].tx_tprop); 695 if (r != 0) { 696 topo_mod_dprintf(mp, "failed.\n"); 697 topo_mod_dprintf(mp, "Error was %s.\n", 698 topo_strerror(topo_mod_errno(mp))); 699 return (-1); 700 } 701 topo_mod_dprintf(mp, "succeeded.\n"); 702 } 703 return (0); 704 } 705