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 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2018, Joyent, Inc. 24 */ 25 26 /* 27 * Topology Plugin Modules 28 * 29 * Topology plugin modules are shared libraries that are dlopen'd and 30 * used to enumerate resources in the system and export per-node method 31 * operations. 32 * 33 * They are loaded by our builtin scheme-specific plugins, other modules or 34 * by processing a topo map XML file to enumerate and create nodes for 35 * resources that are present in the system. They may also export a set of 36 * topology node specific methods that can be invoked directly via 37 * topo_method_invoke() or indirectly via the 38 * topo_prop_get* family of functions to access dynamic property data. 39 * 40 * Module Plugin API 41 * 42 * Enumerators must provide entry points for initialization and clean-up 43 * (_topo_init() and _topo_fini()). In their _topo_init() function, an 44 * enumerator should register (topo_mod_register()) its enumeration callback 45 * and allocate resources required for a subsequent call to the callback. 46 * Optionally, methods may also be registered with topo_method_register(). 47 * 48 * In its enumeration callback routine, the module should search for resources 49 * within its realm of responsibility and create any node ranges, 50 * topo_node_range_create() and nodes, topo_node_bind(). The Enumerator 51 * module is handed a node to which it may begin attaching additional 52 * topology nodes. The enumerator may only access those nodes within its 53 * current scope of operation: the node passed into its enumeration op and 54 * any nodes it creates during enumeration. If the enumerator requires walker- 55 * style access to these nodes, it must use 56 * topo_mod_walk_init()/topo_walk_step()/topo_walk_fini(). 57 * 58 * If additional helper modules need to be loaded to complete the enumeration 59 * the module may do so by calling topo_mod_load(). Enumeration may then 60 * continue with the module handing off enumeration to its helper module 61 * by calling topo_mod_enumerate(). Similarly, a module may call 62 * topo_mod_enummap() to kick-off enumeration according to a given XML 63 * topology map file. A module *may* not cause re-entrance to itself 64 * via either of these interfaces. If re-entry is detected an error 65 * will be returned (ETOPO_ENUM_RECURS). 66 * 67 * If the module registers a release callback, it will be called on a node 68 * by node basis during topo_snap_rele(). Any private node data may be 69 * deallocated or methods unregistered at that time. Global module data 70 * should be cleaned up before or at the time that the module _topo_fini 71 * entry point is called. 72 * 73 * Module entry points and method invocations are guaranteed to be 74 * single-threaded for a given snapshot handle. Applications may have 75 * more than one topology snapshot open at a time. This means that the 76 * module operations and methods may be called for different module handles 77 * (topo_mod_t) asynchronously. The enumerator should not use static or 78 * global data structures that may become inconsistent in this situation. 79 * Method operations may be re-entrant if the module invokes one of its own 80 * methods directly or via dynamic property access. Caution should be 81 * exercised with method operations to insure that data remains consistent 82 * within the module and that deadlocks can not occur. 83 */ 84 85 #include <pthread.h> 86 #include <assert.h> 87 #include <errno.h> 88 #include <dirent.h> 89 #include <limits.h> 90 #include <alloca.h> 91 #include <unistd.h> 92 #include <stdio.h> 93 #include <ctype.h> 94 #include <pcidb.h> 95 #include <sys/param.h> 96 #include <sys/utsname.h> 97 #include <sys/smbios.h> 98 #include <sys/fm/protocol.h> 99 100 #include <topo_alloc.h> 101 #include <topo_error.h> 102 #include <topo_file.h> 103 #include <topo_fmri.h> 104 #include <topo_module.h> 105 #include <topo_method.h> 106 #include <topo_string.h> 107 #include <topo_subr.h> 108 #include <topo_tree.h> 109 110 #define PLUGIN_PATH "plugins" 111 #define PLUGIN_PATH_LEN MAXNAMELEN + 5 112 113 topo_mod_t * 114 topo_mod_load(topo_mod_t *pmod, const char *name, 115 topo_version_t version) 116 { 117 char *path; 118 char file[PLUGIN_PATH_LEN]; 119 topo_mod_t *mod = NULL; 120 topo_hdl_t *thp; 121 122 thp = pmod->tm_hdl; 123 124 /* 125 * Already loaded, topo_mod_lookup will bump the ref count 126 */ 127 if ((mod = topo_mod_lookup(thp, name, 1)) != NULL) { 128 if (mod->tm_info->tmi_version != version) { 129 topo_mod_rele(mod); 130 (void) topo_mod_seterrno(pmod, ETOPO_MOD_VER); 131 return (NULL); 132 } 133 return (mod); 134 } 135 136 (void) snprintf(file, PLUGIN_PATH_LEN, "%s/%s.so", 137 PLUGIN_PATH, name); 138 path = topo_search_path(pmod, thp->th_rootdir, (const char *)file); 139 if (path == NULL || 140 (mod = topo_modhash_load(thp, name, path, &topo_rtld_ops, version)) 141 == NULL) { /* returned with mod held */ 142 topo_mod_strfree(pmod, path); 143 (void) topo_mod_seterrno(pmod, topo_hdl_errno(thp) ? 144 topo_hdl_errno(thp) : ETOPO_MOD_NOENT); 145 return (NULL); 146 } 147 148 topo_mod_strfree(pmod, path); 149 150 return (mod); 151 } 152 153 void 154 topo_mod_unload(topo_mod_t *mod) 155 { 156 topo_mod_rele(mod); 157 } 158 159 static int 160 set_register_error(topo_mod_t *mod, int err) 161 { 162 if (mod->tm_info != NULL) 163 topo_mod_unregister(mod); 164 165 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, 166 "module registration failed for %s: %s\n", 167 mod->tm_name, topo_strerror(err)); 168 169 return (topo_mod_seterrno(mod, err)); 170 } 171 172 int 173 topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip, 174 topo_version_t version) 175 { 176 177 assert(!(mod->tm_flags & TOPO_MOD_FINI || 178 mod->tm_flags & TOPO_MOD_REG)); 179 180 if (version != TOPO_VERSION) 181 return (set_register_error(mod, EMOD_VER_ABI)); 182 183 if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t))) 184 == NULL) 185 return (set_register_error(mod, EMOD_NOMEM)); 186 if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod, 187 sizeof (topo_modops_t))) == NULL) 188 return (set_register_error(mod, EMOD_NOMEM)); 189 190 mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc); 191 if (mod->tm_info->tmi_desc == NULL) 192 return (set_register_error(mod, EMOD_NOMEM)); 193 194 mod->tm_info->tmi_scheme = topo_mod_strdup(mod, mip->tmi_scheme); 195 if (mod->tm_info->tmi_scheme == NULL) 196 return (set_register_error(mod, EMOD_NOMEM)); 197 198 199 mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version; 200 mod->tm_info->tmi_ops->tmo_enum = mip->tmi_ops->tmo_enum; 201 mod->tm_info->tmi_ops->tmo_release = mip->tmi_ops->tmo_release; 202 203 mod->tm_flags |= TOPO_MOD_REG; 204 205 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 206 "registration succeeded for %s\n", mod->tm_name); 207 208 return (0); 209 } 210 211 void 212 topo_mod_unregister(topo_mod_t *mod) 213 { 214 if (mod->tm_info == NULL) 215 return; 216 217 assert(!(mod->tm_flags & TOPO_MOD_FINI)); 218 219 mod->tm_flags &= ~TOPO_MOD_REG; 220 221 if (mod->tm_info == NULL) 222 return; 223 224 if (mod->tm_info->tmi_ops != NULL) 225 topo_mod_free(mod, mod->tm_info->tmi_ops, 226 sizeof (topo_modops_t)); 227 if (mod->tm_info->tmi_desc != NULL) 228 topo_mod_strfree(mod, mod->tm_info->tmi_desc); 229 if (mod->tm_info->tmi_scheme != NULL) 230 topo_mod_strfree(mod, mod->tm_info->tmi_scheme); 231 232 topo_mod_free(mod, mod->tm_info, sizeof (topo_imodinfo_t)); 233 234 mod->tm_info = NULL; 235 } 236 237 int 238 topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name, 239 const char *name, topo_instance_t min, topo_instance_t max, void *data) 240 { 241 int err = 0; 242 topo_mod_t *enum_mod; 243 244 assert(mod->tm_flags & TOPO_MOD_REG); 245 246 if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name, 0)) == NULL) 247 return (topo_mod_seterrno(mod, EMOD_MOD_NOENT)); 248 249 topo_node_hold(node); 250 251 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "module %s enumerating " 252 "node %s=%d\n", (char *)mod->tm_name, (char *)node->tn_name, 253 node->tn_instance); 254 255 topo_mod_enter(enum_mod); 256 err = enum_mod->tm_info->tmi_ops->tmo_enum(enum_mod, node, name, min, 257 max, enum_mod->tm_priv, data); 258 topo_mod_exit(enum_mod); 259 260 if (err != 0) { 261 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 262 263 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, 264 "module %s failed enumeration for " 265 " node %s=%d\n", (char *)mod->tm_name, 266 (char *)node->tn_name, node->tn_instance); 267 268 topo_node_rele(node); 269 return (-1); 270 } 271 272 topo_node_rele(node); 273 274 return (0); 275 } 276 277 int 278 topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name, 279 const char *scheme) 280 { 281 return (topo_file_load(mod, node, (char *)name, (char *)scheme, 0)); 282 } 283 284 static nvlist_t * 285 set_fmri_err(topo_mod_t *mod, int err) 286 { 287 (void) topo_mod_seterrno(mod, err); 288 return (NULL); 289 } 290 291 nvlist_t * 292 topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name, 293 topo_instance_t inst, nvlist_t *hc_specific, nvlist_t *auth, 294 const char *part, const char *rev, const char *serial) 295 { 296 int err; 297 nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL; 298 nvlist_t *nfp = NULL; 299 char *lpart, *lrev, *lserial; 300 301 if (version != FM_HC_SCHEME_VERSION) 302 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 303 304 /* 305 * Do we have any args to pass? 306 */ 307 if (pnode != NULL || auth != NULL || part != NULL || rev != NULL || 308 serial != NULL || hc_specific != NULL) { 309 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 310 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 311 } 312 313 if (pnode != NULL) { 314 if (topo_node_resource(pnode, &pfmri, &err) < 0) { 315 nvlist_free(args); 316 return (set_fmri_err(mod, EMOD_NVL_INVAL)); 317 } 318 319 if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, 320 pfmri) != 0) { 321 nvlist_free(pfmri); 322 nvlist_free(args); 323 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 324 } 325 nvlist_free(pfmri); 326 } 327 328 /* 329 * Add optional payload 330 */ 331 if (auth != NULL) 332 (void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth); 333 if (part != NULL) { 334 lpart = topo_cleanup_auth_str(mod->tm_hdl, part); 335 if (lpart != NULL) { 336 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART, 337 lpart); 338 topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1); 339 } else { 340 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART, 341 ""); 342 } 343 } 344 if (rev != NULL) { 345 lrev = topo_cleanup_auth_str(mod->tm_hdl, rev); 346 if (lrev != NULL) { 347 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV, 348 lrev); 349 topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1); 350 } else { 351 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV, 352 ""); 353 } 354 } 355 if (serial != NULL) { 356 lserial = topo_cleanup_auth_str(mod->tm_hdl, serial); 357 if (lserial != NULL) { 358 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER, 359 lserial); 360 topo_hdl_free(mod->tm_hdl, lserial, 361 strlen(lserial) + 1); 362 } else { 363 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER, 364 ""); 365 } 366 } 367 if (hc_specific != NULL) 368 (void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS, 369 hc_specific); 370 371 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst, 372 args, &err)) == NULL) { 373 nvlist_free(args); 374 return (set_fmri_err(mod, err)); 375 } 376 377 nvlist_free(args); 378 379 (void) topo_mod_nvdup(mod, fmri, &nfp); 380 nvlist_free(fmri); 381 382 return (nfp); 383 } 384 385 nvlist_t * 386 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path, 387 const char *devid) 388 { 389 int err; 390 nvlist_t *fmri, *args; 391 nvlist_t *nfp = NULL; 392 393 if (version != FM_DEV_SCHEME_VERSION) 394 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 395 396 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 397 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 398 399 if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) { 400 nvlist_free(args); 401 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 402 } 403 404 (void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid); 405 406 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV, 407 FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) { 408 nvlist_free(args); 409 return (set_fmri_err(mod, err)); 410 } 411 412 nvlist_free(args); 413 414 (void) topo_mod_nvdup(mod, fmri, &nfp); 415 nvlist_free(fmri); 416 417 return (nfp); 418 } 419 420 nvlist_t * 421 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask, 422 const char *serial) 423 { 424 int err; 425 nvlist_t *fmri = NULL, *args = NULL; 426 nvlist_t *nfp = NULL; 427 428 if (version != FM_CPU_SCHEME_VERSION) 429 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 430 431 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 432 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 433 434 if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) { 435 nvlist_free(args); 436 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 437 } 438 439 /* 440 * Add optional payload 441 */ 442 (void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask); 443 (void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial); 444 445 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU, 446 FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) { 447 nvlist_free(args); 448 return (set_fmri_err(mod, err)); 449 } 450 451 nvlist_free(args); 452 453 (void) topo_mod_nvdup(mod, fmri, &nfp); 454 nvlist_free(fmri); 455 456 return (nfp); 457 } 458 459 nvlist_t * 460 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset, 461 const char *unum, int flags) 462 { 463 int err; 464 nvlist_t *args = NULL, *fmri = NULL; 465 nvlist_t *nfp = NULL; 466 467 if (version != FM_MEM_SCHEME_VERSION) 468 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 469 470 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 471 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 472 473 err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum); 474 nvlist_free(args); 475 if (flags & TOPO_MEMFMRI_PA) 476 err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa); 477 if (flags & TOPO_MEMFMRI_OFFSET) 478 err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset); 479 480 if (err != 0) { 481 nvlist_free(args); 482 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 483 } 484 485 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM, 486 FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) { 487 nvlist_free(args); 488 return (set_fmri_err(mod, err)); 489 } 490 491 nvlist_free(args); 492 493 (void) topo_mod_nvdup(mod, fmri, &nfp); 494 nvlist_free(fmri); 495 496 return (nfp); 497 498 } 499 500 nvlist_t * 501 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path) 502 { 503 int err; 504 nvlist_t *fmri = NULL, *args = NULL; 505 nvlist_t *nfp = NULL; 506 507 if (version != FM_PKG_SCHEME_VERSION) 508 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 509 510 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 511 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 512 513 if (nvlist_add_string(args, "path", path) != 0) { 514 nvlist_free(args); 515 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 516 } 517 518 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PKG, 519 FM_FMRI_SCHEME_PKG, 0, args, &err)) == NULL) { 520 nvlist_free(args); 521 return (set_fmri_err(mod, err)); 522 } 523 524 nvlist_free(args); 525 526 (void) topo_mod_nvdup(mod, fmri, &nfp); 527 nvlist_free(fmri); 528 529 return (nfp); 530 } 531 532 nvlist_t * 533 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver) 534 { 535 int err; 536 nvlist_t *fmri = NULL, *args = NULL; 537 nvlist_t *nfp = NULL; 538 539 if (version != FM_MOD_SCHEME_VERSION) 540 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 541 542 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 543 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 544 545 if (nvlist_add_string(args, "DRIVER", driver) != 0) { 546 nvlist_free(args); 547 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 548 } 549 550 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD, 551 FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) { 552 nvlist_free(args); 553 return (set_fmri_err(mod, err)); 554 } 555 556 nvlist_free(args); 557 558 (void) topo_mod_nvdup(mod, fmri, &nfp); 559 nvlist_free(fmri); 560 561 return (nfp); 562 } 563 564 #define _SWFMRI_ADD_STRING(nvl, name, val) \ 565 ((val) ? (nvlist_add_string(nvl, name, val) != 0) : 0) 566 567 nvlist_t * 568 topo_mod_swfmri(topo_mod_t *mod, int version, 569 char *obj_path, char *obj_root, nvlist_t *obj_pkg, 570 char *site_token, char *site_module, char *site_file, char *site_func, 571 int64_t site_line, char *ctxt_origin, char *ctxt_execname, 572 int64_t ctxt_pid, char *ctxt_zone, int64_t ctxt_ctid, 573 char **ctxt_stack, uint_t ctxt_stackdepth) 574 { 575 nvlist_t *fmri, *args; 576 nvlist_t *nfp = NULL; 577 int err; 578 579 if (version != FM_SW_SCHEME_VERSION) 580 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 581 582 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 583 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 584 585 err = 0; 586 err |= _SWFMRI_ADD_STRING(args, "obj_path", obj_path); 587 err |= _SWFMRI_ADD_STRING(args, "obj_root", obj_root); 588 if (obj_pkg) 589 err |= nvlist_add_nvlist(args, "obj_pkg", obj_pkg); 590 591 err |= _SWFMRI_ADD_STRING(args, "site_token", site_token); 592 err |= _SWFMRI_ADD_STRING(args, "site_module", site_module); 593 err |= _SWFMRI_ADD_STRING(args, "site_file", site_file); 594 err |= _SWFMRI_ADD_STRING(args, "site_func", site_func); 595 if (site_line != -1) 596 err |= nvlist_add_int64(args, "site_line", site_line); 597 598 err |= _SWFMRI_ADD_STRING(args, "ctxt_origin", ctxt_origin); 599 err |= _SWFMRI_ADD_STRING(args, "ctxt_execname", ctxt_execname); 600 if (ctxt_pid != -1) 601 err |= nvlist_add_int64(args, "ctxt_pid", ctxt_pid); 602 err |= _SWFMRI_ADD_STRING(args, "ctxt_zone", ctxt_zone); 603 if (ctxt_ctid != -1) 604 err |= nvlist_add_int64(args, "ctxt_ctid", ctxt_ctid); 605 if (ctxt_stack != NULL && ctxt_stackdepth != 0) 606 err |= nvlist_add_string_array(args, "stack", ctxt_stack, 607 ctxt_stackdepth); 608 609 if (err) { 610 nvlist_free(args); 611 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 612 } 613 614 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_SW, 615 FM_FMRI_SCHEME_SW, 0, args, &err)) == NULL) { 616 nvlist_free(args); 617 return (set_fmri_err(mod, err)); 618 } 619 620 nvlist_free(args); 621 622 (void) topo_mod_nvdup(mod, fmri, &nfp); 623 nvlist_free(fmri); 624 625 return (nfp); 626 } 627 628 int 629 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri) 630 { 631 int err; 632 nvlist_t *np = NULL; 633 634 if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0) 635 return (topo_mod_seterrno(mod, err)); 636 637 if (topo_mod_nvdup(mod, np, fmri) < 0) { 638 nvlist_free(np); 639 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 640 } 641 642 nvlist_free(np); 643 644 return (0); 645 } 646 647 int 648 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr) 649 { 650 int err; 651 char *sp; 652 653 if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0) 654 return (topo_mod_seterrno(mod, err)); 655 656 if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) { 657 topo_hdl_strfree(mod->tm_hdl, sp); 658 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 659 } 660 661 topo_hdl_strfree(mod->tm_hdl, sp); 662 663 return (0); 664 } 665 666 void * 667 topo_mod_getspecific(topo_mod_t *mod) 668 { 669 return (mod->tm_priv); 670 } 671 672 void 673 topo_mod_setspecific(topo_mod_t *mod, void *data) 674 { 675 mod->tm_priv = data; 676 } 677 678 void 679 topo_mod_setdebug(topo_mod_t *mod) 680 { 681 mod->tm_debug = 1; 682 } 683 684 ipmi_handle_t * 685 topo_mod_ipmi_hold(topo_mod_t *mod) 686 { 687 topo_hdl_t *thp = mod->tm_hdl; 688 int err; 689 char *errmsg; 690 691 (void) pthread_mutex_lock(&thp->th_ipmi_lock); 692 if (thp->th_ipmi == NULL) { 693 if ((thp->th_ipmi = ipmi_open(&err, &errmsg, IPMI_TRANSPORT_BMC, 694 NULL)) == NULL) { 695 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, 696 "ipmi_open() failed: %s (ipmi errno=%d)", errmsg, 697 err); 698 (void) pthread_mutex_unlock(&thp->th_ipmi_lock); 699 } 700 } 701 702 703 return (thp->th_ipmi); 704 } 705 706 void 707 topo_mod_ipmi_rele(topo_mod_t *mod) 708 { 709 topo_hdl_t *thp = mod->tm_hdl; 710 711 (void) pthread_mutex_unlock(&thp->th_ipmi_lock); 712 } 713 714 di_node_t 715 topo_mod_devinfo(topo_mod_t *mod) 716 { 717 return (topo_hdl_devinfo(mod->tm_hdl)); 718 } 719 720 smbios_hdl_t * 721 topo_mod_smbios(topo_mod_t *mod) 722 { 723 topo_hdl_t *thp = mod->tm_hdl; 724 725 if (thp->th_smbios == NULL) 726 thp->th_smbios = smbios_open(NULL, SMB_VERSION, 0, NULL); 727 728 return (thp->th_smbios); 729 } 730 731 di_prom_handle_t 732 topo_mod_prominfo(topo_mod_t *mod) 733 { 734 return (topo_hdl_prominfo(mod->tm_hdl)); 735 } 736 737 pcidb_hdl_t * 738 topo_mod_pcidb(topo_mod_t *mod) 739 { 740 topo_hdl_t *thp = mod->tm_hdl; 741 742 if (thp->th_pcidb == NULL) 743 thp->th_pcidb = pcidb_open(PCIDB_VERSION); 744 745 return (thp->th_pcidb); 746 } 747 748 void 749 topo_mod_clrdebug(topo_mod_t *mod) 750 { 751 mod->tm_debug = 0; 752 } 753 754 /*PRINTFLIKE2*/ 755 void 756 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...) 757 { 758 va_list alist; 759 760 if (mod->tm_debug == 0) 761 return; 762 763 va_start(alist, format); 764 topo_vdprintf(mod->tm_hdl, TOPO_DBG_MOD, (const char *)mod->tm_name, 765 format, alist); 766 va_end(alist); 767 } 768 769 static char * 770 topo_mod_product(topo_mod_t *mod) 771 { 772 return (topo_mod_strdup(mod, mod->tm_hdl->th_product)); 773 } 774 775 static char * 776 topo_mod_server(topo_mod_t *mod) 777 { 778 static struct utsname uts; 779 780 (void) uname(&uts); 781 return (topo_mod_strdup(mod, uts.nodename)); 782 } 783 784 static char * 785 topo_mod_psn(topo_mod_t *mod) 786 { 787 smbios_hdl_t *shp; 788 const char *psn; 789 790 if ((shp = topo_mod_smbios(mod)) == NULL || 791 (psn = smbios_psn(shp)) == NULL) 792 return (NULL); 793 794 return (topo_cleanup_auth_str(mod->tm_hdl, psn)); 795 } 796 797 static char * 798 topo_mod_csn(topo_mod_t *mod) 799 { 800 char csn[MAXNAMELEN]; 801 smbios_hdl_t *shp; 802 di_prom_handle_t promh = DI_PROM_HANDLE_NIL; 803 di_node_t rooth = DI_NODE_NIL; 804 const char *bufp; 805 806 if ((shp = topo_mod_smbios(mod)) != NULL) { 807 bufp = smbios_csn(shp); 808 if (bufp != NULL) 809 (void) strlcpy(csn, bufp, MAXNAMELEN); 810 else 811 return (NULL); 812 } else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL && 813 (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) { 814 if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn", 815 (unsigned char **)&bufp) != -1) { 816 (void) strlcpy(csn, bufp, MAXNAMELEN); 817 } else { 818 return (NULL); 819 } 820 } else { 821 return (NULL); 822 } 823 824 return (topo_cleanup_auth_str(mod->tm_hdl, csn)); 825 } 826 827 nvlist_t * 828 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode) 829 { 830 int err; 831 char *prod = NULL; 832 char *csn = NULL; 833 char *psn = NULL; 834 char *server = NULL; 835 nvlist_t *auth; 836 837 if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) { 838 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); 839 return (NULL); 840 } 841 842 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY, 843 FM_FMRI_AUTH_PRODUCT, &prod, &err); 844 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY, 845 FM_FMRI_AUTH_PRODUCT_SN, &psn, &err); 846 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY, 847 FM_FMRI_AUTH_CHASSIS, &csn, &err); 848 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY, 849 FM_FMRI_AUTH_SERVER, &server, &err); 850 851 /* 852 * Let's do this the hard way 853 */ 854 if (prod == NULL) 855 prod = topo_mod_product(mod); 856 if (csn == NULL) 857 csn = topo_mod_csn(mod); 858 if (psn == NULL) 859 psn = topo_mod_psn(mod); 860 if (server == NULL) { 861 server = topo_mod_server(mod); 862 } 863 864 /* 865 * No luck, return NULL 866 */ 867 if (!prod && !server && !csn && !psn) { 868 nvlist_free(auth); 869 return (NULL); 870 } 871 872 err = 0; 873 if (prod != NULL) { 874 err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod); 875 topo_mod_strfree(mod, prod); 876 } 877 if (psn != NULL) { 878 err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn); 879 topo_mod_strfree(mod, psn); 880 } 881 if (server != NULL) { 882 err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server); 883 topo_mod_strfree(mod, server); 884 } 885 if (csn != NULL) { 886 err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn); 887 topo_mod_strfree(mod, csn); 888 } 889 890 if (err != 0) { 891 nvlist_free(auth); 892 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 893 return (NULL); 894 } 895 896 return (auth); 897 } 898 899 topo_walk_t * 900 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f, 901 void *pdata, int *errp) 902 { 903 topo_walk_t *wp; 904 topo_hdl_t *thp = mod->tm_hdl; 905 906 if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata, 907 errp)) == NULL) 908 return (NULL); 909 910 return (wp); 911 } 912 913 char * 914 topo_mod_clean_str(topo_mod_t *mod, const char *str) 915 { 916 if (str == NULL) 917 return (NULL); 918 919 return (topo_cleanup_auth_str(mod->tm_hdl, str)); 920 } 921