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