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