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 2019 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 #include <sys/types.h> 100 #include <sys/stat.h> 101 #include <fcntl.h> 102 103 #include <topo_alloc.h> 104 #include <topo_error.h> 105 #include <topo_file.h> 106 #include <topo_fmri.h> 107 #include <topo_module.h> 108 #include <topo_method.h> 109 #include <topo_string.h> 110 #include <topo_subr.h> 111 #include <topo_tree.h> 112 113 #define PLUGIN_PATH "plugins" 114 #define PLUGIN_PATH_LEN MAXNAMELEN + 5 115 116 topo_mod_t * 117 topo_mod_load(topo_mod_t *pmod, const char *name, 118 topo_version_t version) 119 { 120 char *path; 121 char file[PLUGIN_PATH_LEN]; 122 topo_mod_t *mod = NULL; 123 topo_hdl_t *thp; 124 125 thp = pmod->tm_hdl; 126 127 /* 128 * Already loaded, topo_mod_lookup will bump the ref count 129 */ 130 if ((mod = topo_mod_lookup(thp, name, 1)) != NULL) { 131 if (mod->tm_info->tmi_version != version) { 132 topo_mod_rele(mod); 133 (void) topo_mod_seterrno(pmod, ETOPO_MOD_VER); 134 return (NULL); 135 } 136 return (mod); 137 } 138 139 (void) snprintf(file, PLUGIN_PATH_LEN, "%s/%s.so", 140 PLUGIN_PATH, name); 141 path = topo_search_path(pmod, thp->th_rootdir, (const char *)file); 142 if (path == NULL || 143 (mod = topo_modhash_load(thp, name, path, &topo_rtld_ops, version)) 144 == NULL) { /* returned with mod held */ 145 topo_mod_strfree(pmod, path); 146 (void) topo_mod_seterrno(pmod, topo_hdl_errno(thp) ? 147 topo_hdl_errno(thp) : ETOPO_MOD_NOENT); 148 return (NULL); 149 } 150 151 topo_mod_strfree(pmod, path); 152 153 return (mod); 154 } 155 156 void 157 topo_mod_unload(topo_mod_t *mod) 158 { 159 topo_mod_rele(mod); 160 } 161 162 static int 163 set_register_error(topo_mod_t *mod, int err) 164 { 165 if (mod->tm_info != NULL) 166 topo_mod_unregister(mod); 167 168 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, 169 "module registration failed for %s: %s\n", 170 mod->tm_name, topo_strerror(err)); 171 172 return (topo_mod_seterrno(mod, err)); 173 } 174 175 int 176 topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip, 177 topo_version_t version) 178 { 179 180 assert(!(mod->tm_flags & TOPO_MOD_FINI || 181 mod->tm_flags & TOPO_MOD_REG)); 182 183 if (version != TOPO_VERSION) 184 return (set_register_error(mod, EMOD_VER_ABI)); 185 186 if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t))) 187 == NULL) 188 return (set_register_error(mod, EMOD_NOMEM)); 189 if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod, 190 sizeof (topo_modops_t))) == NULL) 191 return (set_register_error(mod, EMOD_NOMEM)); 192 193 mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc); 194 if (mod->tm_info->tmi_desc == NULL) 195 return (set_register_error(mod, EMOD_NOMEM)); 196 197 mod->tm_info->tmi_scheme = topo_mod_strdup(mod, mip->tmi_scheme); 198 if (mod->tm_info->tmi_scheme == NULL) 199 return (set_register_error(mod, EMOD_NOMEM)); 200 201 202 mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version; 203 mod->tm_info->tmi_ops->tmo_enum = mip->tmi_ops->tmo_enum; 204 mod->tm_info->tmi_ops->tmo_release = mip->tmi_ops->tmo_release; 205 206 mod->tm_flags |= TOPO_MOD_REG; 207 208 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 209 "registration succeeded for %s\n", mod->tm_name); 210 211 return (0); 212 } 213 214 void 215 topo_mod_unregister(topo_mod_t *mod) 216 { 217 if (mod->tm_info == NULL) 218 return; 219 220 assert(!(mod->tm_flags & TOPO_MOD_FINI)); 221 222 mod->tm_flags &= ~TOPO_MOD_REG; 223 224 if (mod->tm_info == NULL) 225 return; 226 227 if (mod->tm_info->tmi_ops != NULL) 228 topo_mod_free(mod, mod->tm_info->tmi_ops, 229 sizeof (topo_modops_t)); 230 if (mod->tm_info->tmi_desc != NULL) 231 topo_mod_strfree(mod, mod->tm_info->tmi_desc); 232 if (mod->tm_info->tmi_scheme != NULL) 233 topo_mod_strfree(mod, mod->tm_info->tmi_scheme); 234 235 topo_mod_free(mod, mod->tm_info, sizeof (topo_imodinfo_t)); 236 237 mod->tm_info = NULL; 238 } 239 240 int 241 topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name, 242 const char *name, topo_instance_t min, topo_instance_t max, void *data) 243 { 244 int err = 0; 245 topo_mod_t *enum_mod; 246 247 assert(mod->tm_flags & TOPO_MOD_REG); 248 249 if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name, 0)) == NULL) 250 return (topo_mod_seterrno(mod, EMOD_MOD_NOENT)); 251 252 topo_node_hold(node); 253 254 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "module %s enumerating " 255 "node %s=%d\n", (char *)mod->tm_name, (char *)node->tn_name, 256 node->tn_instance); 257 258 topo_mod_enter(enum_mod); 259 err = enum_mod->tm_info->tmi_ops->tmo_enum(enum_mod, node, name, min, 260 max, enum_mod->tm_priv, data); 261 topo_mod_exit(enum_mod); 262 263 if (err != 0) { 264 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); 265 266 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, 267 "module %s failed enumeration for " 268 " node %s=%d\n", (char *)mod->tm_name, 269 (char *)node->tn_name, node->tn_instance); 270 271 topo_node_rele(node); 272 return (-1); 273 } 274 275 topo_node_rele(node); 276 277 return (0); 278 } 279 280 int 281 topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name, 282 const char *scheme) 283 { 284 return (topo_file_load(mod, node, (char *)name, (char *)scheme, 0)); 285 } 286 287 static nvlist_t * 288 set_fmri_err(topo_mod_t *mod, int err) 289 { 290 (void) topo_mod_seterrno(mod, err); 291 return (NULL); 292 } 293 294 nvlist_t * 295 topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name, 296 topo_instance_t inst, nvlist_t *hc_specific, nvlist_t *auth, 297 const char *part, const char *rev, const char *serial) 298 { 299 int err; 300 nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL; 301 nvlist_t *nfp = NULL; 302 char *lpart, *lrev, *lserial; 303 304 if (version != FM_HC_SCHEME_VERSION) 305 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 306 307 /* 308 * Do we have any args to pass? 309 */ 310 if (pnode != NULL || auth != NULL || part != NULL || rev != NULL || 311 serial != NULL || hc_specific != NULL) { 312 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 313 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 314 } 315 316 if (pnode != NULL) { 317 if (topo_node_resource(pnode, &pfmri, &err) < 0) { 318 nvlist_free(args); 319 return (set_fmri_err(mod, EMOD_NVL_INVAL)); 320 } 321 322 if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, 323 pfmri) != 0) { 324 nvlist_free(pfmri); 325 nvlist_free(args); 326 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 327 } 328 nvlist_free(pfmri); 329 } 330 331 /* 332 * Add optional payload 333 */ 334 if (auth != NULL) 335 (void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth); 336 if (part != NULL) { 337 lpart = topo_cleanup_auth_str(mod->tm_hdl, part); 338 if (lpart != NULL) { 339 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART, 340 lpart); 341 topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1); 342 } else { 343 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART, 344 ""); 345 } 346 } 347 if (rev != NULL) { 348 lrev = topo_cleanup_auth_str(mod->tm_hdl, rev); 349 if (lrev != NULL) { 350 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV, 351 lrev); 352 topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1); 353 } else { 354 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV, 355 ""); 356 } 357 } 358 if (serial != NULL) { 359 lserial = topo_cleanup_auth_str(mod->tm_hdl, serial); 360 if (lserial != NULL) { 361 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER, 362 lserial); 363 topo_hdl_free(mod->tm_hdl, lserial, 364 strlen(lserial) + 1); 365 } else { 366 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER, 367 ""); 368 } 369 } 370 if (hc_specific != NULL) 371 (void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS, 372 hc_specific); 373 374 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst, 375 args, &err)) == NULL) { 376 nvlist_free(args); 377 return (set_fmri_err(mod, err)); 378 } 379 380 nvlist_free(args); 381 382 (void) topo_mod_nvdup(mod, fmri, &nfp); 383 nvlist_free(fmri); 384 385 return (nfp); 386 } 387 388 nvlist_t * 389 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path, 390 const char *devid) 391 { 392 int err; 393 nvlist_t *fmri, *args; 394 nvlist_t *nfp = NULL; 395 396 if (version != FM_DEV_SCHEME_VERSION) 397 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 398 399 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 400 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 401 402 if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) { 403 nvlist_free(args); 404 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 405 } 406 407 (void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid); 408 409 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV, 410 FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) { 411 nvlist_free(args); 412 return (set_fmri_err(mod, err)); 413 } 414 415 nvlist_free(args); 416 417 (void) topo_mod_nvdup(mod, fmri, &nfp); 418 nvlist_free(fmri); 419 420 return (nfp); 421 } 422 423 nvlist_t * 424 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask, 425 const char *serial) 426 { 427 int err; 428 nvlist_t *fmri = NULL, *args = NULL; 429 nvlist_t *nfp = NULL; 430 431 if (version != FM_CPU_SCHEME_VERSION) 432 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 433 434 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 435 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 436 437 if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) { 438 nvlist_free(args); 439 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 440 } 441 442 /* 443 * Add optional payload 444 */ 445 (void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask); 446 (void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial); 447 448 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU, 449 FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) { 450 nvlist_free(args); 451 return (set_fmri_err(mod, err)); 452 } 453 454 nvlist_free(args); 455 456 (void) topo_mod_nvdup(mod, fmri, &nfp); 457 nvlist_free(fmri); 458 459 return (nfp); 460 } 461 462 nvlist_t * 463 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset, 464 const char *unum, int flags) 465 { 466 int err; 467 nvlist_t *args = NULL, *fmri = NULL; 468 nvlist_t *nfp = NULL; 469 470 if (version != FM_MEM_SCHEME_VERSION) 471 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 472 473 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 474 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 475 476 err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum); 477 if (flags & TOPO_MEMFMRI_PA) 478 err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa); 479 if (flags & TOPO_MEMFMRI_OFFSET) 480 err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset); 481 482 if (err != 0) { 483 nvlist_free(args); 484 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 485 } 486 487 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM, 488 FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) { 489 nvlist_free(args); 490 return (set_fmri_err(mod, err)); 491 } 492 493 nvlist_free(args); 494 495 (void) topo_mod_nvdup(mod, fmri, &nfp); 496 nvlist_free(fmri); 497 498 return (nfp); 499 500 } 501 502 nvlist_t * 503 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path) 504 { 505 int err; 506 nvlist_t *fmri = NULL, *args = NULL; 507 nvlist_t *nfp = NULL; 508 509 if (version != FM_PKG_SCHEME_VERSION) 510 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 511 512 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 513 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 514 515 if (nvlist_add_string(args, "path", path) != 0) { 516 nvlist_free(args); 517 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 518 } 519 520 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PKG, 521 FM_FMRI_SCHEME_PKG, 0, args, &err)) == NULL) { 522 nvlist_free(args); 523 return (set_fmri_err(mod, err)); 524 } 525 526 nvlist_free(args); 527 528 (void) topo_mod_nvdup(mod, fmri, &nfp); 529 nvlist_free(fmri); 530 531 return (nfp); 532 } 533 534 nvlist_t * 535 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver) 536 { 537 int err; 538 nvlist_t *fmri = NULL, *args = NULL; 539 nvlist_t *nfp = NULL; 540 541 if (version != FM_MOD_SCHEME_VERSION) 542 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 543 544 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 545 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 546 547 if (nvlist_add_string(args, "DRIVER", driver) != 0) { 548 nvlist_free(args); 549 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 550 } 551 552 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD, 553 FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) { 554 nvlist_free(args); 555 return (set_fmri_err(mod, err)); 556 } 557 558 nvlist_free(args); 559 560 (void) topo_mod_nvdup(mod, fmri, &nfp); 561 nvlist_free(fmri); 562 563 return (nfp); 564 } 565 566 #define _SWFMRI_ADD_STRING(nvl, name, val) \ 567 ((val) ? (nvlist_add_string(nvl, name, val) != 0) : 0) 568 569 nvlist_t * 570 topo_mod_swfmri(topo_mod_t *mod, int version, 571 char *obj_path, char *obj_root, nvlist_t *obj_pkg, 572 char *site_token, char *site_module, char *site_file, char *site_func, 573 int64_t site_line, char *ctxt_origin, char *ctxt_execname, 574 int64_t ctxt_pid, char *ctxt_zone, int64_t ctxt_ctid, 575 char **ctxt_stack, uint_t ctxt_stackdepth) 576 { 577 nvlist_t *fmri, *args; 578 nvlist_t *nfp = NULL; 579 int err; 580 581 if (version != FM_SW_SCHEME_VERSION) 582 return (set_fmri_err(mod, EMOD_FMRI_VERSION)); 583 584 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0) 585 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 586 587 err = 0; 588 err |= _SWFMRI_ADD_STRING(args, "obj_path", obj_path); 589 err |= _SWFMRI_ADD_STRING(args, "obj_root", obj_root); 590 if (obj_pkg) 591 err |= nvlist_add_nvlist(args, "obj_pkg", obj_pkg); 592 593 err |= _SWFMRI_ADD_STRING(args, "site_token", site_token); 594 err |= _SWFMRI_ADD_STRING(args, "site_module", site_module); 595 err |= _SWFMRI_ADD_STRING(args, "site_file", site_file); 596 err |= _SWFMRI_ADD_STRING(args, "site_func", site_func); 597 if (site_line != -1) 598 err |= nvlist_add_int64(args, "site_line", site_line); 599 600 err |= _SWFMRI_ADD_STRING(args, "ctxt_origin", ctxt_origin); 601 err |= _SWFMRI_ADD_STRING(args, "ctxt_execname", ctxt_execname); 602 if (ctxt_pid != -1) 603 err |= nvlist_add_int64(args, "ctxt_pid", ctxt_pid); 604 err |= _SWFMRI_ADD_STRING(args, "ctxt_zone", ctxt_zone); 605 if (ctxt_ctid != -1) 606 err |= nvlist_add_int64(args, "ctxt_ctid", ctxt_ctid); 607 if (ctxt_stack != NULL && ctxt_stackdepth != 0) 608 err |= nvlist_add_string_array(args, "stack", ctxt_stack, 609 ctxt_stackdepth); 610 611 if (err) { 612 nvlist_free(args); 613 return (set_fmri_err(mod, EMOD_FMRI_NVL)); 614 } 615 616 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_SW, 617 FM_FMRI_SCHEME_SW, 0, args, &err)) == NULL) { 618 nvlist_free(args); 619 return (set_fmri_err(mod, err)); 620 } 621 622 nvlist_free(args); 623 624 (void) topo_mod_nvdup(mod, fmri, &nfp); 625 nvlist_free(fmri); 626 627 return (nfp); 628 } 629 630 int 631 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri) 632 { 633 int err; 634 nvlist_t *np = NULL; 635 636 if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0) 637 return (topo_mod_seterrno(mod, err)); 638 639 if (topo_mod_nvdup(mod, np, fmri) < 0) { 640 nvlist_free(np); 641 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 642 } 643 644 nvlist_free(np); 645 646 return (0); 647 } 648 649 int 650 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr) 651 { 652 int err; 653 char *sp; 654 655 if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0) 656 return (topo_mod_seterrno(mod, err)); 657 658 if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) { 659 topo_hdl_strfree(mod->tm_hdl, sp); 660 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 661 } 662 663 topo_hdl_strfree(mod->tm_hdl, sp); 664 665 return (0); 666 } 667 668 void * 669 topo_mod_getspecific(topo_mod_t *mod) 670 { 671 return (mod->tm_priv); 672 } 673 674 void 675 topo_mod_setspecific(topo_mod_t *mod, void *data) 676 { 677 mod->tm_priv = data; 678 } 679 680 void 681 topo_mod_setdebug(topo_mod_t *mod) 682 { 683 mod->tm_debug = 1; 684 } 685 686 ipmi_handle_t * 687 topo_mod_ipmi_hold(topo_mod_t *mod) 688 { 689 topo_hdl_t *thp = mod->tm_hdl; 690 int err; 691 char *errmsg; 692 693 (void) pthread_mutex_lock(&thp->th_ipmi_lock); 694 if (thp->th_ipmi == NULL) { 695 if ((thp->th_ipmi = ipmi_open(&err, &errmsg, IPMI_TRANSPORT_BMC, 696 NULL)) == NULL) { 697 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, 698 "ipmi_open() failed: %s (ipmi errno=%d)", errmsg, 699 err); 700 (void) pthread_mutex_unlock(&thp->th_ipmi_lock); 701 } 702 } 703 704 705 return (thp->th_ipmi); 706 } 707 708 void 709 topo_mod_ipmi_rele(topo_mod_t *mod) 710 { 711 topo_hdl_t *thp = mod->tm_hdl; 712 713 (void) pthread_mutex_unlock(&thp->th_ipmi_lock); 714 } 715 716 di_node_t 717 topo_mod_devinfo(topo_mod_t *mod) 718 { 719 return (topo_hdl_devinfo(mod->tm_hdl)); 720 } 721 722 smbios_hdl_t * 723 topo_mod_smbios(topo_mod_t *mod) 724 { 725 topo_hdl_t *thp = mod->tm_hdl; 726 727 if (thp->th_smbios == NULL) 728 thp->th_smbios = smbios_open(NULL, SMB_VERSION, 0, NULL); 729 730 return (thp->th_smbios); 731 } 732 733 di_prom_handle_t 734 topo_mod_prominfo(topo_mod_t *mod) 735 { 736 return (topo_hdl_prominfo(mod->tm_hdl)); 737 } 738 739 pcidb_hdl_t * 740 topo_mod_pcidb(topo_mod_t *mod) 741 { 742 topo_hdl_t *thp = mod->tm_hdl; 743 744 if (thp->th_pcidb == NULL) 745 thp->th_pcidb = pcidb_open(PCIDB_VERSION); 746 747 return (thp->th_pcidb); 748 } 749 750 void 751 topo_mod_clrdebug(topo_mod_t *mod) 752 { 753 mod->tm_debug = 0; 754 } 755 756 /*PRINTFLIKE2*/ 757 void 758 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...) 759 { 760 topo_hdl_t *thp = mod->tm_hdl; 761 va_list alist; 762 763 if (mod->tm_debug == 0 || !(thp->th_debug & TOPO_DBG_MOD)) 764 return; 765 766 va_start(alist, format); 767 topo_vdprintf(mod->tm_hdl, (const char *)mod->tm_name, format, alist); 768 va_end(alist); 769 } 770 771 static char * 772 topo_mod_product(topo_mod_t *mod) 773 { 774 return (topo_mod_strdup(mod, mod->tm_hdl->th_product)); 775 } 776 777 static char * 778 topo_mod_server(topo_mod_t *mod) 779 { 780 static struct utsname uts; 781 782 (void) uname(&uts); 783 return (topo_mod_strdup(mod, uts.nodename)); 784 } 785 786 static char * 787 topo_mod_psn(topo_mod_t *mod) 788 { 789 smbios_hdl_t *shp; 790 const char *psn; 791 792 if ((shp = topo_mod_smbios(mod)) == NULL || 793 (psn = smbios_psn(shp)) == NULL) 794 return (NULL); 795 796 return (topo_cleanup_auth_str(mod->tm_hdl, psn)); 797 } 798 799 static char * 800 topo_mod_csn(topo_mod_t *mod) 801 { 802 char csn[MAXNAMELEN]; 803 smbios_hdl_t *shp; 804 di_prom_handle_t promh = DI_PROM_HANDLE_NIL; 805 di_node_t rooth = DI_NODE_NIL; 806 const char *bufp; 807 808 if ((shp = topo_mod_smbios(mod)) != NULL) { 809 bufp = smbios_csn(shp); 810 if (bufp != NULL) 811 (void) strlcpy(csn, bufp, MAXNAMELEN); 812 else 813 return (NULL); 814 } else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL && 815 (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) { 816 if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn", 817 (unsigned char **)&bufp) != -1) { 818 (void) strlcpy(csn, bufp, MAXNAMELEN); 819 } else { 820 return (NULL); 821 } 822 } else { 823 return (NULL); 824 } 825 826 return (topo_cleanup_auth_str(mod->tm_hdl, csn)); 827 } 828 829 nvlist_t * 830 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode) 831 { 832 int err; 833 char *prod = NULL; 834 char *csn = NULL; 835 char *psn = NULL; 836 char *server = NULL; 837 nvlist_t *auth; 838 839 if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) { 840 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); 841 return (NULL); 842 } 843 844 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY, 845 FM_FMRI_AUTH_PRODUCT, &prod, &err); 846 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY, 847 FM_FMRI_AUTH_PRODUCT_SN, &psn, &err); 848 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY, 849 FM_FMRI_AUTH_CHASSIS, &csn, &err); 850 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY, 851 FM_FMRI_AUTH_SERVER, &server, &err); 852 853 /* 854 * Let's do this the hard way 855 */ 856 if (prod == NULL) 857 prod = topo_mod_product(mod); 858 if (csn == NULL) 859 csn = topo_mod_csn(mod); 860 if (psn == NULL) 861 psn = topo_mod_psn(mod); 862 if (server == NULL) { 863 server = topo_mod_server(mod); 864 } 865 866 /* 867 * No luck, return NULL 868 */ 869 if (!prod && !server && !csn && !psn) { 870 nvlist_free(auth); 871 return (NULL); 872 } 873 874 err = 0; 875 if (prod != NULL) { 876 err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod); 877 topo_mod_strfree(mod, prod); 878 } 879 if (psn != NULL) { 880 err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn); 881 topo_mod_strfree(mod, psn); 882 } 883 if (server != NULL) { 884 err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server); 885 topo_mod_strfree(mod, server); 886 } 887 if (csn != NULL) { 888 err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn); 889 topo_mod_strfree(mod, csn); 890 } 891 892 if (err != 0) { 893 nvlist_free(auth); 894 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 895 return (NULL); 896 } 897 898 return (auth); 899 } 900 901 topo_walk_t * 902 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f, 903 void *pdata, int *errp) 904 { 905 topo_walk_t *wp; 906 topo_hdl_t *thp = mod->tm_hdl; 907 908 if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata, 909 errp)) == NULL) 910 return (NULL); 911 912 return (wp); 913 } 914 915 char * 916 topo_mod_clean_str(topo_mod_t *mod, const char *str) 917 { 918 if (str == NULL) 919 return (NULL); 920 921 return (topo_cleanup_auth_str(mod->tm_hdl, str)); 922 } 923 924 int 925 topo_mod_file_search(topo_mod_t *mod, const char *file, int oflags) 926 { 927 int ret; 928 char *path; 929 topo_hdl_t *thp = mod->tm_hdl; 930 931 path = topo_search_path(mod, thp->th_rootdir, file); 932 if (path == NULL) { 933 return (-1); 934 } 935 936 ret = open(path, oflags); 937 topo_mod_strfree(mod, path); 938 return (ret); 939 } 940 941 /*ARGSUSED*/ 942 int 943 topo_mod_hc_occupied(topo_mod_t *mod, tnode_t *node, topo_version_t version, 944 nvlist_t *in, nvlist_t **out) 945 { 946 nvlist_t *nvl = NULL; 947 tnode_t *cnp; 948 boolean_t is_occupied = B_FALSE; 949 950 if (version > TOPO_METH_OCCUPIED_VERSION) 951 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 952 953 /* 954 * Iterate though the child nodes. If there are no non-facility 955 * node children then it is unoccupied. 956 */ 957 for (cnp = topo_child_first(node); cnp != NULL; 958 cnp = topo_child_next(node, cnp)) { 959 if (topo_node_flags(cnp) != TOPO_NODE_FACILITY) 960 is_occupied = B_TRUE; 961 } 962 963 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 || 964 nvlist_add_boolean_value(nvl, TOPO_METH_OCCUPIED_RET, 965 is_occupied) != 0) { 966 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n"); 967 nvlist_free(nvl); 968 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 969 } 970 *out = nvl; 971 972 return (0); 973 } 974 975 /* 976 * Convenience routine for creating a UFM slot node. This routine assumes 977 * that the caller has already created the containing range via a call to 978 * topo_node_range_create(). 979 */ 980 tnode_t * 981 topo_mod_create_ufm_slot(topo_mod_t *mod, tnode_t *ufmnode, 982 topo_ufm_slot_info_t *slotinfo) 983 { 984 nvlist_t *auth = NULL, *fmri = NULL; 985 tnode_t *slotnode; 986 topo_pgroup_info_t pgi; 987 int err, rc; 988 989 if (slotinfo == NULL || slotinfo->usi_version == NULL || 990 slotinfo->usi_mode == 0) { 991 topo_mod_dprintf(mod, "invalid slot info"); 992 (void) topo_mod_seterrno(mod, ETOPO_MOD_INVAL); 993 return (NULL); 994 } 995 if ((auth = topo_mod_auth(mod, ufmnode)) == NULL) { 996 topo_mod_dprintf(mod, "topo_mod_auth() failed: %s", 997 topo_mod_errmsg(mod)); 998 /* errno set */ 999 return (NULL); 1000 } 1001 1002 if ((fmri = topo_mod_hcfmri(mod, ufmnode, FM_HC_SCHEME_VERSION, 1003 SLOT, slotinfo->usi_slotid, NULL, auth, NULL, NULL, NULL)) == 1004 NULL) { 1005 nvlist_free(auth); 1006 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s", 1007 topo_mod_errmsg(mod)); 1008 /* errno set */ 1009 return (NULL); 1010 } 1011 1012 if ((slotnode = topo_node_bind(mod, ufmnode, SLOT, 1013 slotinfo->usi_slotid, fmri)) == NULL) { 1014 nvlist_free(auth); 1015 nvlist_free(fmri); 1016 topo_mod_dprintf(mod, "topo_node_bind() failed: %s", 1017 topo_mod_errmsg(mod)); 1018 /* errno set */ 1019 return (NULL); 1020 } 1021 1022 /* Create authority and system pgroups */ 1023 topo_pgroup_hcset(slotnode, auth); 1024 nvlist_free(auth); 1025 nvlist_free(fmri); 1026 1027 /* Just inherit the parent's FRU */ 1028 if (topo_node_fru_set(slotnode, NULL, 0, &err) != 0) { 1029 topo_mod_dprintf(mod, "failed to set FRU on %s: %s", UFM, 1030 topo_strerror(err)); 1031 (void) topo_mod_seterrno(mod, err); 1032 goto slotfail; 1033 } 1034 1035 pgi.tpi_name = TOPO_PGROUP_SLOT; 1036 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 1037 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 1038 pgi.tpi_version = TOPO_VERSION; 1039 rc = topo_pgroup_create(slotnode, &pgi, &err); 1040 1041 if (rc == 0) 1042 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_SLOT, 1043 TOPO_PROP_SLOT_TYPE, TOPO_PROP_IMMUTABLE, 1044 TOPO_SLOT_TYPE_UFM, &err); 1045 1046 pgi.tpi_name = TOPO_PGROUP_UFM_SLOT; 1047 1048 if (rc == 0) 1049 rc += topo_pgroup_create(slotnode, &pgi, &err); 1050 1051 if (rc == 0) { 1052 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_UFM_SLOT, 1053 TOPO_PROP_UFM_SLOT_MODE, TOPO_PROP_IMMUTABLE, 1054 slotinfo->usi_mode, &err); 1055 } 1056 1057 if (rc == 0) { 1058 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_UFM_SLOT, 1059 TOPO_PROP_UFM_SLOT_ACTIVE, TOPO_PROP_IMMUTABLE, 1060 (uint32_t)slotinfo->usi_active, &err); 1061 } 1062 1063 if (rc == 0) { 1064 rc += topo_prop_set_string(slotnode, TOPO_PGROUP_UFM_SLOT, 1065 TOPO_PROP_UFM_SLOT_VERSION, TOPO_PROP_IMMUTABLE, 1066 slotinfo->usi_version, &err); 1067 } 1068 1069 if (rc == 0 && slotinfo->usi_extra != NULL) { 1070 nvpair_t *elem = NULL; 1071 char *pname, *pval; 1072 1073 while ((elem = nvlist_next_nvpair(slotinfo->usi_extra, 1074 elem)) != NULL) { 1075 if (nvpair_type(elem) != DATA_TYPE_STRING) 1076 continue; 1077 1078 pname = nvpair_name(elem); 1079 if ((rc -= nvpair_value_string(elem, &pval)) != 0) 1080 break; 1081 1082 rc += topo_prop_set_string(slotnode, 1083 TOPO_PGROUP_UFM_SLOT, pname, TOPO_PROP_IMMUTABLE, 1084 pval, &err); 1085 1086 if (rc != 0) 1087 break; 1088 } 1089 } 1090 1091 if (rc != 0) { 1092 topo_mod_dprintf(mod, "error setting properties on %s node", 1093 SLOT); 1094 (void) topo_mod_seterrno(mod, err); 1095 goto slotfail; 1096 } 1097 return (slotnode); 1098 1099 slotfail: 1100 topo_node_unbind(slotnode); 1101 return (NULL); 1102 } 1103 1104 /* 1105 * This is a convenience routine to allow enumerator modules to easily create 1106 * the necessary UFM node layout for the most common case, which will be a 1107 * single UFM with a single slot. This routine assumes that the caller has 1108 * already created the containing range via a call to topo_node_range_create(). 1109 * 1110 * For more complex scenarios (like multiple slots per UFM), callers can set 1111 * the slotinfo param to NULL. In this case the ufm node will get created, but 1112 * it will skip creating the slot node - allowing the module to manually call 1113 * topo_mod_create_ufm_slot() to create custom UFM slots. 1114 */ 1115 tnode_t * 1116 topo_mod_create_ufm(topo_mod_t *mod, tnode_t *parent, const char *descr, 1117 topo_ufm_slot_info_t *slotinfo) 1118 { 1119 nvlist_t *auth = NULL, *fmri = NULL; 1120 tnode_t *ufmnode, *slotnode; 1121 topo_pgroup_info_t pgi; 1122 int err, rc; 1123 1124 if ((auth = topo_mod_auth(mod, parent)) == NULL) { 1125 topo_mod_dprintf(mod, "topo_mod_auth() failed: %s", 1126 topo_mod_errmsg(mod)); 1127 /* errno set */ 1128 return (NULL); 1129 } 1130 1131 if ((fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, 1132 UFM, 0, NULL, auth, NULL, NULL, NULL)) == 1133 NULL) { 1134 nvlist_free(auth); 1135 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s", 1136 topo_mod_errmsg(mod)); 1137 /* errno set */ 1138 return (NULL); 1139 } 1140 1141 if ((ufmnode = topo_node_bind(mod, parent, UFM, 0, fmri)) == NULL) { 1142 nvlist_free(auth); 1143 nvlist_free(fmri); 1144 topo_mod_dprintf(mod, "topo_node_bind() failed: %s", 1145 topo_mod_errmsg(mod)); 1146 /* errno set */ 1147 return (NULL); 1148 } 1149 1150 /* Create authority and system pgroups */ 1151 topo_pgroup_hcset(ufmnode, auth); 1152 nvlist_free(auth); 1153 nvlist_free(fmri); 1154 1155 /* Just inherit the parent's FRU */ 1156 if (topo_node_fru_set(ufmnode, NULL, 0, &err) != 0) { 1157 topo_mod_dprintf(mod, "failed to set FRU on %s: %s", UFM, 1158 topo_strerror(err)); 1159 (void) topo_mod_seterrno(mod, err); 1160 goto ufmfail; 1161 } 1162 1163 pgi.tpi_name = TOPO_PGROUP_UFM; 1164 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 1165 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 1166 pgi.tpi_version = TOPO_VERSION; 1167 rc = topo_pgroup_create(ufmnode, &pgi, &err); 1168 1169 if (rc == 0) 1170 rc += topo_prop_set_string(ufmnode, TOPO_PGROUP_UFM, 1171 TOPO_PROP_UFM_DESCR, TOPO_PROP_IMMUTABLE, descr, &err); 1172 1173 if (rc != 0) { 1174 topo_mod_dprintf(mod, "error setting properties on %s node", 1175 UFM); 1176 (void) topo_mod_seterrno(mod, err); 1177 goto ufmfail; 1178 } 1179 1180 if (slotinfo != NULL) { 1181 if (topo_node_range_create(mod, ufmnode, SLOT, 0, 0) < 0) { 1182 topo_mod_dprintf(mod, "error creating %s range", SLOT); 1183 goto ufmfail; 1184 } 1185 slotnode = topo_mod_create_ufm_slot(mod, ufmnode, slotinfo); 1186 1187 if (slotnode == NULL) 1188 goto ufmfail; 1189 } 1190 return (ufmnode); 1191 1192 ufmfail: 1193 topo_node_unbind(ufmnode); 1194 return (NULL); 1195 } 1196