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 * Copyright 2023 Oxide Computer Company
25 */
26
27 /*
28 * Topology Plugin Modules
29 *
30 * Topology plugin modules are shared libraries that are dlopen'd and
31 * used to enumerate resources in the system and export per-node method
32 * operations.
33 *
34 * They are loaded by our builtin scheme-specific plugins, other modules or
35 * by processing a topo map XML file to enumerate and create nodes for
36 * resources that are present in the system. They may also export a set of
37 * topology node specific methods that can be invoked directly via
38 * topo_method_invoke() or indirectly via the
39 * topo_prop_get* family of functions to access dynamic property data.
40 *
41 * Module Plugin API
42 *
43 * Enumerators must provide entry points for initialization and clean-up
44 * (_topo_init() and _topo_fini()). In their _topo_init() function, an
45 * enumerator should register (topo_mod_register()) its enumeration callback
46 * and allocate resources required for a subsequent call to the callback.
47 * Optionally, methods may also be registered with topo_method_register().
48 *
49 * In its enumeration callback routine, the module should search for resources
50 * within its realm of responsibility and create any node ranges,
51 * topo_node_range_create() and nodes, topo_node_bind(). The Enumerator
52 * module is handed a node to which it may begin attaching additional
53 * topology nodes. The enumerator may only access those nodes within its
54 * current scope of operation: the node passed into its enumeration op and
55 * any nodes it creates during enumeration. If the enumerator requires walker-
56 * style access to these nodes, it must use
57 * topo_mod_walk_init()/topo_walk_step()/topo_walk_fini().
58 *
59 * If additional helper modules need to be loaded to complete the enumeration
60 * the module may do so by calling topo_mod_load(). Enumeration may then
61 * continue with the module handing off enumeration to its helper module
62 * by calling topo_mod_enumerate(). Similarly, a module may call
63 * topo_mod_enummap() to kick-off enumeration according to a given XML
64 * topology map file. A module *may* not cause re-entrance to itself
65 * via either of these interfaces. If re-entry is detected an error
66 * will be returned (ETOPO_ENUM_RECURS).
67 *
68 * If the module registers a release callback, it will be called on a node
69 * by node basis during topo_snap_rele(). Any private node data may be
70 * deallocated or methods unregistered at that time. Global module data
71 * should be cleaned up before or at the time that the module _topo_fini
72 * entry point is called.
73 *
74 * Module entry points and method invocations are guaranteed to be
75 * single-threaded for a given snapshot handle. Applications may have
76 * more than one topology snapshot open at a time. This means that the
77 * module operations and methods may be called for different module handles
78 * (topo_mod_t) asynchronously. The enumerator should not use static or
79 * global data structures that may become inconsistent in this situation.
80 * Method operations may be re-entrant if the module invokes one of its own
81 * methods directly or via dynamic property access. Caution should be
82 * exercised with method operations to insure that data remains consistent
83 * within the module and that deadlocks can not occur.
84 */
85
86 #include <pthread.h>
87 #include <assert.h>
88 #include <errno.h>
89 #include <dirent.h>
90 #include <limits.h>
91 #include <alloca.h>
92 #include <unistd.h>
93 #include <stdio.h>
94 #include <ctype.h>
95 #include <pcidb.h>
96 #include <sys/param.h>
97 #include <sys/utsname.h>
98 #include <sys/smbios.h>
99 #include <sys/fm/protocol.h>
100 #include <sys/types.h>
101 #include <sys/stat.h>
102 #include <fcntl.h>
103
104 #include <topo_alloc.h>
105 #include <topo_error.h>
106 #include <topo_file.h>
107 #include <topo_fmri.h>
108 #include <topo_module.h>
109 #include <topo_method.h>
110 #include <topo_string.h>
111 #include <topo_subr.h>
112 #include <topo_tree.h>
113
114 #if !defined(_ILP32)
115 #define PLUGIN_PATH "plugins/64"
116 #else
117 #define PLUGIN_PATH "plugins"
118 #endif
119 #define PLUGIN_PATH_LEN MAXNAMELEN + 5
120
121 topo_mod_t *
topo_mod_load(topo_mod_t * pmod,const char * name,topo_version_t version)122 topo_mod_load(topo_mod_t *pmod, const char *name,
123 topo_version_t version)
124 {
125 char *path;
126 char file[PLUGIN_PATH_LEN];
127 topo_mod_t *mod = NULL;
128 topo_hdl_t *thp;
129
130 thp = pmod->tm_hdl;
131
132 /*
133 * Already loaded, topo_mod_lookup will bump the ref count
134 */
135 if ((mod = topo_mod_lookup(thp, name, 1)) != NULL) {
136 if (mod->tm_info->tmi_version != version) {
137 topo_mod_rele(mod);
138 (void) topo_mod_seterrno(pmod, ETOPO_MOD_VER);
139 return (NULL);
140 }
141 return (mod);
142 }
143
144 (void) snprintf(file, PLUGIN_PATH_LEN, "%s/%s.so",
145 PLUGIN_PATH, name);
146 path = topo_search_path(pmod, thp->th_rootdir, (const char *)file);
147 if (path == NULL ||
148 (mod = topo_modhash_load(thp, name, path, &topo_rtld_ops, version))
149 == NULL) { /* returned with mod held */
150 topo_mod_strfree(pmod, path);
151 (void) topo_mod_seterrno(pmod, topo_hdl_errno(thp) ?
152 topo_hdl_errno(thp) : ETOPO_MOD_NOENT);
153 return (NULL);
154 }
155
156 topo_mod_strfree(pmod, path);
157
158 return (mod);
159 }
160
161 void
topo_mod_unload(topo_mod_t * mod)162 topo_mod_unload(topo_mod_t *mod)
163 {
164 topo_mod_rele(mod);
165 }
166
167 static int
set_register_error(topo_mod_t * mod,int err)168 set_register_error(topo_mod_t *mod, int err)
169 {
170 if (mod->tm_info != NULL)
171 topo_mod_unregister(mod);
172
173 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
174 "module registration failed for %s: %s\n",
175 mod->tm_name, topo_strerror(err));
176
177 return (topo_mod_seterrno(mod, err));
178 }
179
180 int
topo_mod_register(topo_mod_t * mod,const topo_modinfo_t * mip,topo_version_t version)181 topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip,
182 topo_version_t version)
183 {
184
185 assert(!(mod->tm_flags & TOPO_MOD_FINI ||
186 mod->tm_flags & TOPO_MOD_REG));
187
188 if (version != TOPO_VERSION)
189 return (set_register_error(mod, EMOD_VER_ABI));
190
191 if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t)))
192 == NULL)
193 return (set_register_error(mod, EMOD_NOMEM));
194 if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod,
195 sizeof (topo_modops_t))) == NULL)
196 return (set_register_error(mod, EMOD_NOMEM));
197
198 mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc);
199 if (mod->tm_info->tmi_desc == NULL)
200 return (set_register_error(mod, EMOD_NOMEM));
201
202 mod->tm_info->tmi_scheme = topo_mod_strdup(mod, mip->tmi_scheme);
203 if (mod->tm_info->tmi_scheme == NULL)
204 return (set_register_error(mod, EMOD_NOMEM));
205
206
207 mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version;
208 mod->tm_info->tmi_ops->tmo_enum = mip->tmi_ops->tmo_enum;
209 mod->tm_info->tmi_ops->tmo_release = mip->tmi_ops->tmo_release;
210
211 mod->tm_flags |= TOPO_MOD_REG;
212
213 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
214 "registration succeeded for %s\n", mod->tm_name);
215
216 return (0);
217 }
218
219 void
topo_mod_unregister(topo_mod_t * mod)220 topo_mod_unregister(topo_mod_t *mod)
221 {
222 if (mod->tm_info == NULL)
223 return;
224
225 assert(!(mod->tm_flags & TOPO_MOD_FINI));
226
227 mod->tm_flags &= ~TOPO_MOD_REG;
228
229 if (mod->tm_info == NULL)
230 return;
231
232 if (mod->tm_info->tmi_ops != NULL)
233 topo_mod_free(mod, mod->tm_info->tmi_ops,
234 sizeof (topo_modops_t));
235 if (mod->tm_info->tmi_desc != NULL)
236 topo_mod_strfree(mod, mod->tm_info->tmi_desc);
237 if (mod->tm_info->tmi_scheme != NULL)
238 topo_mod_strfree(mod, mod->tm_info->tmi_scheme);
239
240 topo_mod_free(mod, mod->tm_info, sizeof (topo_imodinfo_t));
241
242 mod->tm_info = NULL;
243 }
244
245 int
topo_mod_enumerate(topo_mod_t * mod,tnode_t * node,const char * enum_name,const char * name,topo_instance_t min,topo_instance_t max,void * data)246 topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name,
247 const char *name, topo_instance_t min, topo_instance_t max, void *data)
248 {
249 int err = 0;
250 topo_mod_t *enum_mod;
251
252 assert(mod->tm_flags & TOPO_MOD_REG);
253
254 if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name, 0)) == NULL)
255 return (topo_mod_seterrno(mod, EMOD_MOD_NOENT));
256
257 topo_node_hold(node);
258
259 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "module %s enumerating "
260 "node %s=%d\n", (char *)mod->tm_name, (char *)node->tn_name,
261 node->tn_instance);
262
263 topo_mod_enter(enum_mod);
264 err = enum_mod->tm_info->tmi_ops->tmo_enum(enum_mod, node, name, min,
265 max, enum_mod->tm_priv, data);
266 topo_mod_exit(enum_mod);
267
268 if (err != 0) {
269 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
270
271 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
272 "module %s failed enumeration for "
273 " node %s=%d\n", (char *)mod->tm_name,
274 (char *)node->tn_name, node->tn_instance);
275
276 topo_node_rele(node);
277 return (-1);
278 }
279
280 topo_node_rele(node);
281
282 return (0);
283 }
284
285 int
topo_mod_enummap(topo_mod_t * mod,tnode_t * node,const char * name,const char * scheme)286 topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name,
287 const char *scheme)
288 {
289 return (topo_file_load(mod, node, (char *)name, (char *)scheme, 0));
290 }
291
292 static nvlist_t *
set_fmri_err(topo_mod_t * mod,int err)293 set_fmri_err(topo_mod_t *mod, int err)
294 {
295 (void) topo_mod_seterrno(mod, err);
296 return (NULL);
297 }
298
299 nvlist_t *
topo_mod_hcfmri(topo_mod_t * mod,tnode_t * pnode,int version,const char * name,topo_instance_t inst,nvlist_t * hc_specific,nvlist_t * auth,const char * part,const char * rev,const char * serial)300 topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name,
301 topo_instance_t inst, nvlist_t *hc_specific, nvlist_t *auth,
302 const char *part, const char *rev, const char *serial)
303 {
304 int err;
305 nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL;
306 nvlist_t *nfp = NULL;
307 char *lpart, *lrev, *lserial;
308
309 if (version != FM_HC_SCHEME_VERSION)
310 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
311
312 /*
313 * Do we have any args to pass?
314 */
315 if (pnode != NULL || auth != NULL || part != NULL || rev != NULL ||
316 serial != NULL || hc_specific != NULL) {
317 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
318 return (set_fmri_err(mod, EMOD_FMRI_NVL));
319 }
320
321 if (pnode != NULL) {
322 if (topo_node_resource(pnode, &pfmri, &err) < 0) {
323 nvlist_free(args);
324 return (set_fmri_err(mod, EMOD_NVL_INVAL));
325 }
326
327 if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
328 pfmri) != 0) {
329 nvlist_free(pfmri);
330 nvlist_free(args);
331 return (set_fmri_err(mod, EMOD_FMRI_NVL));
332 }
333 nvlist_free(pfmri);
334 }
335
336 /*
337 * Add optional payload
338 */
339 if (auth != NULL)
340 (void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
341 if (part != NULL) {
342 lpart = topo_cleanup_auth_str(mod->tm_hdl, part);
343 if (lpart != NULL) {
344 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
345 lpart);
346 topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1);
347 } else {
348 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
349 "");
350 }
351 }
352 if (rev != NULL) {
353 lrev = topo_cleanup_auth_str(mod->tm_hdl, rev);
354 if (lrev != NULL) {
355 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
356 lrev);
357 topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1);
358 } else {
359 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
360 "");
361 }
362 }
363 if (serial != NULL) {
364 lserial = topo_cleanup_auth_str(mod->tm_hdl, serial);
365 if (lserial != NULL) {
366 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
367 lserial);
368 topo_hdl_free(mod->tm_hdl, lserial,
369 strlen(lserial) + 1);
370 } else {
371 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
372 "");
373 }
374 }
375 if (hc_specific != NULL)
376 (void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
377 hc_specific);
378
379 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
380 args, &err)) == NULL) {
381 nvlist_free(args);
382 return (set_fmri_err(mod, err));
383 }
384
385 nvlist_free(args);
386
387 (void) topo_mod_nvdup(mod, fmri, &nfp);
388 nvlist_free(fmri);
389
390 return (nfp);
391 }
392
393 nvlist_t *
topo_mod_hcfmri_extend(topo_mod_t * mod,nvlist_t * pfmri,int version,const char * name,topo_instance_t inst)394 topo_mod_hcfmri_extend(topo_mod_t *mod, nvlist_t *pfmri, int version,
395 const char *name, topo_instance_t inst)
396 {
397 nvlist_t *fmri = NULL, *args = NULL, *nfp = NULL;
398 int err;
399
400 if (version != FM_HC_SCHEME_VERSION)
401 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
402
403 if (pfmri == NULL)
404 return (set_fmri_err(mod, EMOD_NVL_INVAL));
405
406 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
407 return (set_fmri_err(mod, EMOD_FMRI_NVL));
408
409 if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, pfmri) != 0) {
410 nvlist_free(args);
411 return (set_fmri_err(mod, EMOD_FMRI_NVL));
412 }
413
414 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
415 args, &err)) == NULL) {
416 nvlist_free(args);
417 return (set_fmri_err(mod, err));
418 }
419 nvlist_free(args);
420
421 (void) topo_mod_nvdup(mod, fmri, &nfp);
422 nvlist_free(fmri);
423
424 return (nfp);
425 }
426
427 nvlist_t *
topo_mod_devfmri(topo_mod_t * mod,int version,const char * dev_path,const char * devid)428 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path,
429 const char *devid)
430 {
431 int err;
432 nvlist_t *fmri, *args;
433 nvlist_t *nfp = NULL;
434
435 if (version != FM_DEV_SCHEME_VERSION)
436 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
437
438 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
439 return (set_fmri_err(mod, EMOD_FMRI_NVL));
440
441 if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) {
442 nvlist_free(args);
443 return (set_fmri_err(mod, EMOD_FMRI_NVL));
444 }
445
446 (void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid);
447
448 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV,
449 FM_FMRI_SCHEME_DEV, 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 *
topo_mod_cpufmri(topo_mod_t * mod,int version,uint32_t cpu_id,uint8_t cpumask,const char * serial)463 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask,
464 const char *serial)
465 {
466 int err;
467 nvlist_t *fmri = NULL, *args = NULL;
468 nvlist_t *nfp = NULL;
469
470 if (version != FM_CPU_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 if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) {
477 nvlist_free(args);
478 return (set_fmri_err(mod, EMOD_FMRI_NVL));
479 }
480
481 /*
482 * Add optional payload
483 */
484 (void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask);
485 (void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial);
486
487 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
488 FM_FMRI_SCHEME_CPU, 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 nvlist_t *
topo_mod_memfmri(topo_mod_t * mod,int version,uint64_t pa,uint64_t offset,const char * unum,int flags)502 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset,
503 const char *unum, int flags)
504 {
505 int err;
506 nvlist_t *args = NULL, *fmri = NULL;
507 nvlist_t *nfp = NULL;
508
509 if (version != FM_MEM_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 err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum);
516 if (flags & TOPO_MEMFMRI_PA)
517 err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa);
518 if (flags & TOPO_MEMFMRI_OFFSET)
519 err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset);
520
521 if (err != 0) {
522 nvlist_free(args);
523 return (set_fmri_err(mod, EMOD_FMRI_NVL));
524 }
525
526 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM,
527 FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) {
528 nvlist_free(args);
529 return (set_fmri_err(mod, err));
530 }
531
532 nvlist_free(args);
533
534 (void) topo_mod_nvdup(mod, fmri, &nfp);
535 nvlist_free(fmri);
536
537 return (nfp);
538
539 }
540
541 nvlist_t *
topo_mod_pkgfmri(topo_mod_t * mod,int version,const char * path)542 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path)
543 {
544 int err;
545 nvlist_t *fmri = NULL, *args = NULL;
546 nvlist_t *nfp = NULL;
547
548 if (version != FM_PKG_SCHEME_VERSION)
549 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
550
551 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
552 return (set_fmri_err(mod, EMOD_FMRI_NVL));
553
554 if (nvlist_add_string(args, "path", path) != 0) {
555 nvlist_free(args);
556 return (set_fmri_err(mod, EMOD_FMRI_NVL));
557 }
558
559 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PKG,
560 FM_FMRI_SCHEME_PKG, 0, args, &err)) == NULL) {
561 nvlist_free(args);
562 return (set_fmri_err(mod, err));
563 }
564
565 nvlist_free(args);
566
567 (void) topo_mod_nvdup(mod, fmri, &nfp);
568 nvlist_free(fmri);
569
570 return (nfp);
571 }
572
573 nvlist_t *
topo_mod_pciefmri(topo_mod_t * mod,tnode_t * pnode,int version,const char * name,topo_instance_t inst,const nvlist_t * auth)574 topo_mod_pciefmri(topo_mod_t *mod, tnode_t *pnode, int version,
575 const char *name, topo_instance_t inst, const nvlist_t *auth)
576 {
577 nvlist_t *fmri = NULL;
578 nvlist_t *nfp = NULL;
579 nvlist_t *args = NULL;
580 int err;
581
582 if (version != FM_PCIE_SCHEME_VERSION)
583 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
584
585 if (pnode != NULL) {
586 nvlist_t *pfmri;
587
588 topo_mod_dprintf(mod, "pnode is set: %p %s=%" PRIu64,
589 pnode, pnode->tn_name, pnode->tn_instance);
590
591 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
592 return (set_fmri_err(mod, EMOD_FMRI_NVL));
593
594 if (topo_node_resource(pnode, &pfmri, &err) != 0) {
595 topo_mod_dprintf(mod, "failed to fetch pmfri: %s",
596 topo_strerror(err));
597 } else {
598 if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
599 pfmri) != 0) {
600 nvlist_free(pfmri);
601 nvlist_free(args);
602 return (set_fmri_err(mod, EMOD_FMRI_NVL));
603 }
604 nvlist_free(pfmri);
605 }
606
607 if (auth != NULL) {
608 if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH,
609 (nvlist_t *)auth) != 0) {
610 nvlist_free(args);
611 return (set_fmri_err(mod, EMOD_FMRI_NVL));
612 }
613 }
614 }
615
616 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PCIE,
617 name, inst, args, &err)) == NULL) {
618 nvlist_free(args);
619 return (set_fmri_err(mod, err));
620 }
621
622 nvlist_free(args);
623
624 if (topo_mod_nvdup(mod, fmri, &nfp) != 0) {
625 /*
626 * We don't get the failure reason back, but it is likely to be
627 * an allocation failure. 'nfp' will still be NULL if an error
628 * occurred.
629 */
630 (void) topo_mod_seterrno(mod, EMOD_NOMEM);
631 }
632 nvlist_free(fmri);
633
634 return (nfp);
635 }
636
637 nvlist_t *
topo_mod_modfmri(topo_mod_t * mod,int version,const char * driver)638 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
639 {
640 int err;
641 nvlist_t *fmri = NULL, *args = NULL;
642 nvlist_t *nfp = NULL;
643
644 if (version != FM_MOD_SCHEME_VERSION)
645 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
646
647 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
648 return (set_fmri_err(mod, EMOD_FMRI_NVL));
649
650 if (nvlist_add_string(args, "DRIVER", driver) != 0) {
651 nvlist_free(args);
652 return (set_fmri_err(mod, EMOD_FMRI_NVL));
653 }
654
655 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD,
656 FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) {
657 nvlist_free(args);
658 return (set_fmri_err(mod, err));
659 }
660
661 nvlist_free(args);
662
663 (void) topo_mod_nvdup(mod, fmri, &nfp);
664 nvlist_free(fmri);
665
666 return (nfp);
667 }
668
669 #define _SWFMRI_ADD_STRING(nvl, name, val) \
670 ((val) ? (nvlist_add_string(nvl, name, val) != 0) : 0)
671
672 nvlist_t *
topo_mod_swfmri(topo_mod_t * mod,int version,char * obj_path,char * obj_root,nvlist_t * obj_pkg,char * site_token,char * site_module,char * site_file,char * site_func,int64_t site_line,char * ctxt_origin,char * ctxt_execname,int64_t ctxt_pid,char * ctxt_zone,int64_t ctxt_ctid,char ** ctxt_stack,uint_t ctxt_stackdepth)673 topo_mod_swfmri(topo_mod_t *mod, int version,
674 char *obj_path, char *obj_root, nvlist_t *obj_pkg,
675 char *site_token, char *site_module, char *site_file, char *site_func,
676 int64_t site_line, char *ctxt_origin, char *ctxt_execname,
677 int64_t ctxt_pid, char *ctxt_zone, int64_t ctxt_ctid,
678 char **ctxt_stack, uint_t ctxt_stackdepth)
679 {
680 nvlist_t *fmri, *args;
681 nvlist_t *nfp = NULL;
682 int err;
683
684 if (version != FM_SW_SCHEME_VERSION)
685 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
686
687 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
688 return (set_fmri_err(mod, EMOD_FMRI_NVL));
689
690 err = 0;
691 err |= _SWFMRI_ADD_STRING(args, "obj_path", obj_path);
692 err |= _SWFMRI_ADD_STRING(args, "obj_root", obj_root);
693 if (obj_pkg)
694 err |= nvlist_add_nvlist(args, "obj_pkg", obj_pkg);
695
696 err |= _SWFMRI_ADD_STRING(args, "site_token", site_token);
697 err |= _SWFMRI_ADD_STRING(args, "site_module", site_module);
698 err |= _SWFMRI_ADD_STRING(args, "site_file", site_file);
699 err |= _SWFMRI_ADD_STRING(args, "site_func", site_func);
700 if (site_line != -1)
701 err |= nvlist_add_int64(args, "site_line", site_line);
702
703 err |= _SWFMRI_ADD_STRING(args, "ctxt_origin", ctxt_origin);
704 err |= _SWFMRI_ADD_STRING(args, "ctxt_execname", ctxt_execname);
705 if (ctxt_pid != -1)
706 err |= nvlist_add_int64(args, "ctxt_pid", ctxt_pid);
707 err |= _SWFMRI_ADD_STRING(args, "ctxt_zone", ctxt_zone);
708 if (ctxt_ctid != -1)
709 err |= nvlist_add_int64(args, "ctxt_ctid", ctxt_ctid);
710 if (ctxt_stack != NULL && ctxt_stackdepth != 0)
711 err |= nvlist_add_string_array(args, "stack", ctxt_stack,
712 ctxt_stackdepth);
713
714 if (err) {
715 nvlist_free(args);
716 return (set_fmri_err(mod, EMOD_FMRI_NVL));
717 }
718
719 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_SW,
720 FM_FMRI_SCHEME_SW, 0, args, &err)) == NULL) {
721 nvlist_free(args);
722 return (set_fmri_err(mod, err));
723 }
724
725 nvlist_free(args);
726
727 (void) topo_mod_nvdup(mod, fmri, &nfp);
728 nvlist_free(fmri);
729
730 return (nfp);
731 }
732
733 int
topo_mod_str2nvl(topo_mod_t * mod,const char * fmristr,nvlist_t ** fmri)734 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
735 {
736 int err;
737 nvlist_t *np = NULL;
738
739 if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
740 return (topo_mod_seterrno(mod, err));
741
742 if (topo_mod_nvdup(mod, np, fmri) < 0) {
743 nvlist_free(np);
744 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
745 }
746
747 nvlist_free(np);
748
749 return (0);
750 }
751
752 int
topo_mod_nvl2str(topo_mod_t * mod,nvlist_t * fmri,char ** fmristr)753 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
754 {
755 int err;
756 char *sp;
757
758 if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
759 return (topo_mod_seterrno(mod, err));
760
761 if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
762 topo_hdl_strfree(mod->tm_hdl, sp);
763 return (topo_mod_seterrno(mod, EMOD_NOMEM));
764 }
765
766 topo_hdl_strfree(mod->tm_hdl, sp);
767
768 return (0);
769 }
770
771 void *
topo_mod_getspecific(topo_mod_t * mod)772 topo_mod_getspecific(topo_mod_t *mod)
773 {
774 return (mod->tm_priv);
775 }
776
777 void
topo_mod_setspecific(topo_mod_t * mod,void * data)778 topo_mod_setspecific(topo_mod_t *mod, void *data)
779 {
780 mod->tm_priv = data;
781 }
782
783 void
topo_mod_setdebug(topo_mod_t * mod)784 topo_mod_setdebug(topo_mod_t *mod)
785 {
786 mod->tm_debug = 1;
787 }
788
789 ipmi_handle_t *
topo_mod_ipmi_hold(topo_mod_t * mod)790 topo_mod_ipmi_hold(topo_mod_t *mod)
791 {
792 topo_hdl_t *thp = mod->tm_hdl;
793 int err;
794 char *errmsg;
795
796 (void) pthread_mutex_lock(&thp->th_ipmi_lock);
797 if (thp->th_ipmi == NULL) {
798 if ((thp->th_ipmi = ipmi_open(&err, &errmsg, IPMI_TRANSPORT_BMC,
799 NULL)) == NULL) {
800 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
801 "ipmi_open() failed: %s (ipmi errno=%d)", errmsg,
802 err);
803 (void) pthread_mutex_unlock(&thp->th_ipmi_lock);
804 }
805 }
806
807
808 return (thp->th_ipmi);
809 }
810
811 void
topo_mod_ipmi_rele(topo_mod_t * mod)812 topo_mod_ipmi_rele(topo_mod_t *mod)
813 {
814 topo_hdl_t *thp = mod->tm_hdl;
815
816 (void) pthread_mutex_unlock(&thp->th_ipmi_lock);
817 }
818
819 di_node_t
topo_mod_devinfo(topo_mod_t * mod)820 topo_mod_devinfo(topo_mod_t *mod)
821 {
822 return (topo_hdl_devinfo(mod->tm_hdl));
823 }
824
825 smbios_hdl_t *
topo_mod_smbios(topo_mod_t * mod)826 topo_mod_smbios(topo_mod_t *mod)
827 {
828 topo_hdl_t *thp = mod->tm_hdl;
829
830 if (thp->th_smbios == NULL)
831 thp->th_smbios = smbios_open(NULL, SMB_VERSION, 0, NULL);
832
833 return (thp->th_smbios);
834 }
835
836 di_prom_handle_t
topo_mod_prominfo(topo_mod_t * mod)837 topo_mod_prominfo(topo_mod_t *mod)
838 {
839 return (topo_hdl_prominfo(mod->tm_hdl));
840 }
841
842 pcidb_hdl_t *
topo_mod_pcidb(topo_mod_t * mod)843 topo_mod_pcidb(topo_mod_t *mod)
844 {
845 topo_hdl_t *thp = mod->tm_hdl;
846
847 if (thp->th_pcidb == NULL)
848 thp->th_pcidb = pcidb_open(PCIDB_VERSION);
849
850 return (thp->th_pcidb);
851 }
852
853 void
topo_mod_clrdebug(topo_mod_t * mod)854 topo_mod_clrdebug(topo_mod_t *mod)
855 {
856 mod->tm_debug = 0;
857 }
858
859 /*PRINTFLIKE2*/
860 void
topo_mod_dprintf(topo_mod_t * mod,const char * format,...)861 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
862 {
863 topo_hdl_t *thp = mod->tm_hdl;
864 va_list alist;
865
866 if (mod->tm_debug == 0 || !(thp->th_debug & TOPO_DBG_MOD))
867 return;
868
869 va_start(alist, format);
870 topo_vdprintf(mod->tm_hdl, (const char *)mod->tm_name, format, alist);
871 va_end(alist);
872 }
873
874 char *
topo_mod_product(topo_mod_t * mod)875 topo_mod_product(topo_mod_t *mod)
876 {
877 return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
878 }
879
880 static char *
topo_mod_server(topo_mod_t * mod)881 topo_mod_server(topo_mod_t *mod)
882 {
883 static struct utsname uts;
884
885 (void) uname(&uts);
886 return (topo_mod_strdup(mod, uts.nodename));
887 }
888
889 static char *
topo_mod_psn(topo_mod_t * mod)890 topo_mod_psn(topo_mod_t *mod)
891 {
892 smbios_hdl_t *shp;
893 const char *psn;
894
895 if ((shp = topo_mod_smbios(mod)) == NULL ||
896 (psn = smbios_psn(shp)) == NULL)
897 return (NULL);
898
899 return (topo_cleanup_auth_str(mod->tm_hdl, psn));
900 }
901
902 static char *
topo_mod_csn(topo_mod_t * mod)903 topo_mod_csn(topo_mod_t *mod)
904 {
905 char csn[MAXNAMELEN];
906 smbios_hdl_t *shp;
907 di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
908 di_node_t rooth = DI_NODE_NIL;
909 const char *bufp;
910
911 if ((shp = topo_mod_smbios(mod)) != NULL) {
912 bufp = smbios_csn(shp);
913 if (bufp != NULL)
914 (void) strlcpy(csn, bufp, MAXNAMELEN);
915 else
916 return (NULL);
917 } else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
918 (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
919 if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
920 (unsigned char **)&bufp) != -1) {
921 (void) strlcpy(csn, bufp, MAXNAMELEN);
922 } else {
923 return (NULL);
924 }
925 } else {
926 return (NULL);
927 }
928
929 return (topo_cleanup_auth_str(mod->tm_hdl, csn));
930 }
931
932 nvlist_t *
topo_mod_auth(topo_mod_t * mod,tnode_t * pnode)933 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
934 {
935 int err;
936 char *prod = NULL;
937 char *csn = NULL;
938 char *psn = NULL;
939 char *server = NULL;
940 nvlist_t *auth;
941
942 if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
943 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
944 return (NULL);
945 }
946
947 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
948 FM_FMRI_AUTH_PRODUCT, &prod, &err);
949 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
950 FM_FMRI_AUTH_PRODUCT_SN, &psn, &err);
951 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
952 FM_FMRI_AUTH_CHASSIS, &csn, &err);
953 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
954 FM_FMRI_AUTH_SERVER, &server, &err);
955
956 /*
957 * Let's do this the hard way
958 */
959 if (prod == NULL)
960 prod = topo_mod_product(mod);
961 if (csn == NULL)
962 csn = topo_mod_csn(mod);
963 if (psn == NULL)
964 psn = topo_mod_psn(mod);
965 if (server == NULL) {
966 server = topo_mod_server(mod);
967 }
968
969 /*
970 * No luck, return NULL
971 */
972 if (!prod && !server && !csn && !psn) {
973 nvlist_free(auth);
974 return (NULL);
975 }
976
977 err = 0;
978 if (prod != NULL) {
979 err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
980 topo_mod_strfree(mod, prod);
981 }
982 if (psn != NULL) {
983 err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn);
984 topo_mod_strfree(mod, psn);
985 }
986 if (server != NULL) {
987 err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
988 topo_mod_strfree(mod, server);
989 }
990 if (csn != NULL) {
991 err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
992 topo_mod_strfree(mod, csn);
993 }
994
995 if (err != 0) {
996 nvlist_free(auth);
997 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
998 return (NULL);
999 }
1000
1001 return (auth);
1002 }
1003
1004 topo_walk_t *
topo_mod_walk_init(topo_mod_t * mod,tnode_t * node,topo_mod_walk_cb_t cb_f,void * pdata,int * errp)1005 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
1006 void *pdata, int *errp)
1007 {
1008 topo_walk_t *wp;
1009 topo_hdl_t *thp = mod->tm_hdl;
1010
1011 if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
1012 errp)) == NULL)
1013 return (NULL);
1014
1015 return (wp);
1016 }
1017
1018 char *
topo_mod_clean_str(topo_mod_t * mod,const char * str)1019 topo_mod_clean_str(topo_mod_t *mod, const char *str)
1020 {
1021 if (str == NULL)
1022 return (NULL);
1023
1024 return (topo_cleanup_strn(mod->tm_hdl, str, strlen(str)));
1025 }
1026
1027 char *
topo_mod_clean_strn(topo_mod_t * mod,const char * str,size_t len)1028 topo_mod_clean_strn(topo_mod_t *mod, const char *str, size_t len)
1029 {
1030 if (str == NULL)
1031 return (NULL);
1032
1033 return (topo_cleanup_strn(mod->tm_hdl, str, len));
1034 }
1035
1036 int
topo_mod_file_search(topo_mod_t * mod,const char * file,int oflags)1037 topo_mod_file_search(topo_mod_t *mod, const char *file, int oflags)
1038 {
1039 int ret;
1040 char *path;
1041 topo_hdl_t *thp = mod->tm_hdl;
1042
1043 path = topo_search_path(mod, thp->th_rootdir, file);
1044 if (path == NULL) {
1045 return (-1);
1046 }
1047
1048 ret = open(path, oflags);
1049 topo_mod_strfree(mod, path);
1050 return (ret);
1051 }
1052
1053 /*ARGSUSED*/
1054 int
topo_mod_hc_occupied(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1055 topo_mod_hc_occupied(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1056 nvlist_t *in, nvlist_t **out)
1057 {
1058 nvlist_t *nvl = NULL;
1059 tnode_t *cnp;
1060 boolean_t is_occupied = B_FALSE;
1061
1062 if (version > TOPO_METH_OCCUPIED_VERSION)
1063 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1064
1065 /*
1066 * Iterate though the child nodes. If there are no non-facility
1067 * node children then it is unoccupied.
1068 */
1069 for (cnp = topo_child_first(node); cnp != NULL;
1070 cnp = topo_child_next(node, cnp)) {
1071 if (topo_node_flags(cnp) != TOPO_NODE_FACILITY)
1072 is_occupied = B_TRUE;
1073 }
1074
1075 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1076 nvlist_add_boolean_value(nvl, TOPO_METH_OCCUPIED_RET,
1077 is_occupied) != 0) {
1078 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1079 nvlist_free(nvl);
1080 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1081 }
1082 *out = nvl;
1083
1084 return (0);
1085 }
1086
1087 /*
1088 * Convenience routine for creating a UFM slot node. This routine assumes
1089 * that the caller has already created the containing range via a call to
1090 * topo_node_range_create().
1091 */
1092 tnode_t *
topo_mod_create_ufm_slot(topo_mod_t * mod,tnode_t * ufmnode,topo_ufm_slot_info_t * slotinfo)1093 topo_mod_create_ufm_slot(topo_mod_t *mod, tnode_t *ufmnode,
1094 topo_ufm_slot_info_t *slotinfo)
1095 {
1096 nvlist_t *auth = NULL, *fmri = NULL;
1097 tnode_t *slotnode;
1098 topo_pgroup_info_t pgi;
1099 int err, rc;
1100
1101 if (slotinfo == NULL || slotinfo->usi_mode == 0) {
1102 topo_mod_dprintf(mod, "invalid slot info");
1103 (void) topo_mod_seterrno(mod, ETOPO_MOD_INVAL);
1104 return (NULL);
1105 }
1106 if ((auth = topo_mod_auth(mod, ufmnode)) == NULL) {
1107 topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
1108 topo_mod_errmsg(mod));
1109 /* errno set */
1110 return (NULL);
1111 }
1112
1113 if ((fmri = topo_mod_hcfmri(mod, ufmnode, FM_HC_SCHEME_VERSION,
1114 SLOT, slotinfo->usi_slotid, NULL, auth, NULL, NULL, NULL)) ==
1115 NULL) {
1116 nvlist_free(auth);
1117 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
1118 topo_mod_errmsg(mod));
1119 /* errno set */
1120 return (NULL);
1121 }
1122
1123 if ((slotnode = topo_node_bind(mod, ufmnode, SLOT,
1124 slotinfo->usi_slotid, fmri)) == NULL) {
1125 nvlist_free(auth);
1126 nvlist_free(fmri);
1127 topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
1128 topo_mod_errmsg(mod));
1129 /* errno set */
1130 return (NULL);
1131 }
1132
1133 /* Create authority and system pgroups */
1134 topo_pgroup_hcset(slotnode, auth);
1135 nvlist_free(auth);
1136 nvlist_free(fmri);
1137
1138 /* Just inherit the parent's FRU */
1139 if (topo_node_fru_set(slotnode, NULL, 0, &err) != 0) {
1140 topo_mod_dprintf(mod, "failed to set FRU on %s: %s", UFM,
1141 topo_strerror(err));
1142 (void) topo_mod_seterrno(mod, err);
1143 goto slotfail;
1144 }
1145
1146 pgi.tpi_name = TOPO_PGROUP_SLOT;
1147 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1148 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1149 pgi.tpi_version = TOPO_VERSION;
1150 rc = topo_pgroup_create(slotnode, &pgi, &err);
1151
1152 if (rc == 0)
1153 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_SLOT,
1154 TOPO_PROP_SLOT_TYPE, TOPO_PROP_IMMUTABLE,
1155 TOPO_SLOT_TYPE_UFM, &err);
1156
1157 pgi.tpi_name = TOPO_PGROUP_UFM_SLOT;
1158
1159 if (rc == 0)
1160 rc += topo_pgroup_create(slotnode, &pgi, &err);
1161
1162 if (rc == 0) {
1163 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_UFM_SLOT,
1164 TOPO_PROP_UFM_SLOT_MODE, TOPO_PROP_IMMUTABLE,
1165 slotinfo->usi_mode, &err);
1166 }
1167
1168 if (rc == 0) {
1169 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_UFM_SLOT,
1170 TOPO_PROP_UFM_SLOT_ACTIVE, TOPO_PROP_IMMUTABLE,
1171 (uint32_t)slotinfo->usi_active, &err);
1172 }
1173
1174 /*
1175 * We can have a NULL version for an empty slot.
1176 */
1177 if (rc == 0 && slotinfo->usi_version != NULL) {
1178 rc += topo_prop_set_string(slotnode, TOPO_PGROUP_UFM_SLOT,
1179 TOPO_PROP_UFM_SLOT_VERSION, TOPO_PROP_IMMUTABLE,
1180 slotinfo->usi_version, &err);
1181 }
1182
1183 if (rc == 0 && slotinfo->usi_extra != NULL) {
1184 nvpair_t *elem = NULL;
1185 char *pname, *pval;
1186
1187 while ((elem = nvlist_next_nvpair(slotinfo->usi_extra,
1188 elem)) != NULL) {
1189 if (nvpair_type(elem) != DATA_TYPE_STRING)
1190 continue;
1191
1192 pname = nvpair_name(elem);
1193 if ((rc -= nvpair_value_string(elem, &pval)) != 0)
1194 break;
1195
1196 rc += topo_prop_set_string(slotnode,
1197 TOPO_PGROUP_UFM_SLOT, pname, TOPO_PROP_IMMUTABLE,
1198 pval, &err);
1199
1200 if (rc != 0)
1201 break;
1202 }
1203 }
1204
1205 if (rc != 0) {
1206 topo_mod_dprintf(mod, "error setting properties on %s node",
1207 SLOT);
1208 (void) topo_mod_seterrno(mod, err);
1209 goto slotfail;
1210 }
1211 return (slotnode);
1212
1213 slotfail:
1214 topo_node_unbind(slotnode);
1215 return (NULL);
1216 }
1217
1218 /*
1219 * This is a convenience routine to allow enumerator modules to easily create
1220 * the necessary UFM node layout for the most common case, which will be a
1221 * single UFM with a single slot. This routine assumes that the caller has
1222 * already created the containing range via a call to topo_node_range_create().
1223 *
1224 * For more complex scenarios (like multiple slots per UFM), callers can set
1225 * the slotinfo param to NULL. In this case the ufm node will get created, but
1226 * it will skip creating the slot node - allowing the module to manually call
1227 * topo_mod_create_ufm_slot() to create custom UFM slots.
1228 */
1229 tnode_t *
topo_mod_create_ufm(topo_mod_t * mod,tnode_t * parent,topo_instance_t inst,const char * descr,topo_ufm_slot_info_t * slotinfo)1230 topo_mod_create_ufm(topo_mod_t *mod, tnode_t *parent, topo_instance_t inst,
1231 const char *descr, topo_ufm_slot_info_t *slotinfo)
1232 {
1233 nvlist_t *auth = NULL, *fmri = NULL;
1234 tnode_t *ufmnode, *slotnode;
1235 topo_pgroup_info_t pgi;
1236 int err, rc;
1237
1238 if ((auth = topo_mod_auth(mod, parent)) == NULL) {
1239 topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
1240 topo_mod_errmsg(mod));
1241 /* errno set */
1242 return (NULL);
1243 }
1244
1245 if ((fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION,
1246 UFM, inst, NULL, auth, NULL, NULL, NULL)) ==
1247 NULL) {
1248 nvlist_free(auth);
1249 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
1250 topo_mod_errmsg(mod));
1251 /* errno set */
1252 return (NULL);
1253 }
1254
1255 if ((ufmnode = topo_node_bind(mod, parent, UFM, inst, fmri)) == NULL) {
1256 nvlist_free(auth);
1257 nvlist_free(fmri);
1258 topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
1259 topo_mod_errmsg(mod));
1260 /* errno set */
1261 return (NULL);
1262 }
1263
1264 /* Create authority and system pgroups */
1265 topo_pgroup_hcset(ufmnode, auth);
1266 nvlist_free(auth);
1267 nvlist_free(fmri);
1268
1269 /* Just inherit the parent's FRU */
1270 if (topo_node_fru_set(ufmnode, NULL, 0, &err) != 0) {
1271 topo_mod_dprintf(mod, "failed to set FRU on %s: %s", UFM,
1272 topo_strerror(err));
1273 (void) topo_mod_seterrno(mod, err);
1274 goto ufmfail;
1275 }
1276
1277 pgi.tpi_name = TOPO_PGROUP_UFM;
1278 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1279 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1280 pgi.tpi_version = TOPO_VERSION;
1281 rc = topo_pgroup_create(ufmnode, &pgi, &err);
1282
1283 if (rc == 0)
1284 rc += topo_prop_set_string(ufmnode, TOPO_PGROUP_UFM,
1285 TOPO_PROP_UFM_DESCR, TOPO_PROP_IMMUTABLE, descr, &err);
1286
1287 if (rc != 0) {
1288 topo_mod_dprintf(mod, "error setting properties on %s node",
1289 UFM);
1290 (void) topo_mod_seterrno(mod, err);
1291 goto ufmfail;
1292 }
1293
1294 if (slotinfo != NULL) {
1295 if (topo_node_range_create(mod, ufmnode, SLOT, 0, 0) < 0) {
1296 topo_mod_dprintf(mod, "error creating %s range", SLOT);
1297 goto ufmfail;
1298 }
1299 slotnode = topo_mod_create_ufm_slot(mod, ufmnode, slotinfo);
1300
1301 if (slotnode == NULL)
1302 goto ufmfail;
1303 }
1304 return (ufmnode);
1305
1306 ufmfail:
1307 topo_node_unbind(ufmnode);
1308 return (NULL);
1309 }
1310