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