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 Nodes
27 *
28 * Topology nodes, tnode_t, are data structures containing per-FMRI
29 * information and are linked together to form the topology tree.
30 * Nodes are created during the enumeration process of topo_snap_hold()
31 * and destroyed during topo_snap_rele(). For the most part, tnode_t data
32 * is read-only and no lock protection is required. Nodes are
33 * held in place during tree walk functions. Tree walk functions
34 * may access node data safely without locks. The exception to this rule
35 * is data associated with node properties (topo_prop.c). Properties
36 * may change at anytime and are protected by a per-property locking
37 * strategy.
38 *
39 * Enumerator plugin modules may also safely access topology nodes within their
40 * scope of operation: the parent node passed into the enumeration op or those
41 * nodes created by the enumerator. Enumeration occurs only during
42 * topo_snap_hold() where a per-topo_hdl_t lock prevents multi-threaded access
43 * to the topology trees.
44 *
45 * Enumerator method operation functions may safely access and change topology
46 * node property data, and contruct or destroy child nodes for the node
47 * on which the operation applies. The method may also be called to destroy
48 * the node for which the method operation is called. This permits
49 * dynamic topology tree snapshots and partial enumerations for branches that
50 * may not be needed right away.
51 *
52 * Node Interfaces
53 *
54 * Nodes are created when an enumerator calls topo_node_bind(). Prior to
55 * calling topo_node_bind(), the enumerator should have reserved a range of
56 * node instances with topo_node_range_create(). topo_node_range_create()
57 * does not allocate any node resources but creates the infrastruture
58 * required for a fully populated topology level. This allows enumerators
59 * reading from a <scheme>-topology.xml file to parse the file for a range
60 * of resources before confirming the existence of a resource via a helper
61 * plugin. Only when the resource has been confirmed to exist should
62 * the node be bound.
63 *
64 * Node range and node linkage and unlinkage is performed during enumeration and
65 * method operations when it is safe to change node hash lists. Nodes and node
66 * ranges are deallocated when all references to the node have been released:
67 * last walk completes and topo_snap_rele() is called.
68 *
69 * Node Hash/Ranges
70 *
71 * Each parent node may have one or more ranges of child nodes. Each range
72 * is uniquely named and serves as a hash list of like sibling nodes with
73 * different instance numbers. A parent may have more than one node hash
74 * (child range). If that is the case, the hash lists are strung together to
75 * form sibling relationships between ranges. Hash/Ranges are sparsely
76 * populated with only nodes that have represented resources in the system.
77 *
78 * _________________
79 * | |
80 * | tnode_t | -----------------------------
81 * | tn_phash ---> | topo_nodehash_t |
82 * | (children)| | th_nodearr (instances)|
83 * ----------------- | ------------------- |
84 * | ---| 0 | 1 | ...| N | |
85 * | | ------------------- | -------------------
86 * | | th_list (siblings) ----->| topo_nodehash_t |
87 * | | | -------------------
88 * ---|-------------------------
89 * |
90 * v
91 * -----------
92 * | tnode_t |
93 * -----------
94 *
95 * Facility Nodes
96 *
97 * Facility nodes are always leaf nodes in the topology and represent a FMRI
98 * sensor or indicator facility for the path to which it is connected.
99 * Facility nodes are bound to the topology with topo_node_facbind() and
100 * unbound with topo_node_unbind().
101 */
102
103 #include <assert.h>
104 #include <pthread.h>
105 #include <strings.h>
106 #include <sys/fm/protocol.h>
107 #include <topo_alloc.h>
108 #include <topo_error.h>
109 #include <topo_list.h>
110 #include <topo_method.h>
111 #include <topo_subr.h>
112 #include <topo_tree.h>
113
114 static topo_pgroup_info_t protocol_pgroup = {
115 TOPO_PGROUP_PROTOCOL,
116 TOPO_STABILITY_PRIVATE,
117 TOPO_STABILITY_PRIVATE,
118 1
119 };
120
121 static const topo_pgroup_info_t auth_pgroup = {
122 FM_FMRI_AUTHORITY,
123 TOPO_STABILITY_PRIVATE,
124 TOPO_STABILITY_PRIVATE,
125 1
126 };
127
128 static void
topo_node_destroy(tnode_t * node)129 topo_node_destroy(tnode_t *node)
130 {
131 int i;
132 tnode_t *pnode = node->tn_parent;
133 topo_nodehash_t *nhp;
134 topo_mod_t *hmod, *mod = node->tn_enum;
135
136 if (node == NULL)
137 return;
138
139 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "destroying node %s=%d\n",
140 topo_node_name(node), topo_node_instance(node));
141
142 assert(node->tn_refs == 0);
143
144 /*
145 * If not a root node, remove this node from the parent's node hash
146 */
147
148 if (!(node->tn_state & TOPO_NODE_ROOT)) {
149 topo_node_lock(pnode);
150
151 nhp = node->tn_phash;
152 for (i = 0; i < nhp->th_arrlen; i++) {
153 if (node == nhp->th_nodearr[i]) {
154 nhp->th_nodearr[i] = NULL;
155
156 /*
157 * Release hold on parent
158 */
159 --pnode->tn_refs;
160 if (pnode->tn_refs == 0)
161 topo_node_destroy(pnode);
162 }
163 }
164 topo_node_unlock(pnode);
165 }
166
167 topo_node_unlock(node);
168
169 /*
170 * Allow enumerator to clean-up private data and then release
171 * ref count
172 */
173 if (mod->tm_info->tmi_ops->tmo_release != NULL)
174 mod->tm_info->tmi_ops->tmo_release(mod, node);
175
176 topo_method_unregister_all(mod, node);
177
178 /*
179 * Destroy all node hash lists
180 */
181 while ((nhp = topo_list_next(&node->tn_children)) != NULL) {
182 for (i = 0; i < nhp->th_arrlen; i++) {
183 assert(nhp->th_nodearr[i] == NULL);
184 }
185 hmod = nhp->th_enum;
186 topo_mod_strfree(hmod, nhp->th_name);
187 topo_mod_free(hmod, nhp->th_nodearr,
188 nhp->th_arrlen * sizeof (tnode_t *));
189 topo_list_delete(&node->tn_children, nhp);
190 topo_mod_free(hmod, nhp, sizeof (topo_nodehash_t));
191 topo_mod_rele(hmod);
192 }
193
194 /*
195 * Destroy all property data structures, free the node and release
196 * the module that created it
197 */
198 topo_pgroup_destroy_all(node);
199 topo_mod_free(mod, node, sizeof (tnode_t));
200 topo_mod_rele(mod);
201 }
202
203 void
topo_node_lock(tnode_t * node)204 topo_node_lock(tnode_t *node)
205 {
206 (void) pthread_mutex_lock(&node->tn_lock);
207 }
208
209 void
topo_node_unlock(tnode_t * node)210 topo_node_unlock(tnode_t *node)
211 {
212 (void) pthread_mutex_unlock(&node->tn_lock);
213 }
214
215 void
topo_node_hold(tnode_t * node)216 topo_node_hold(tnode_t *node)
217 {
218 topo_node_lock(node);
219 ++node->tn_refs;
220 topo_node_unlock(node);
221 }
222
223 void
topo_node_rele(tnode_t * node)224 topo_node_rele(tnode_t *node)
225 {
226 topo_node_lock(node);
227 --node->tn_refs;
228
229 /*
230 * Ok to remove this node from the topo tree and destroy it
231 */
232 if (node->tn_refs == 0)
233 topo_node_destroy(node);
234 else
235 topo_node_unlock(node);
236 }
237
238 char *
topo_node_name(tnode_t * node)239 topo_node_name(tnode_t *node)
240 {
241 return (node->tn_name);
242 }
243
244 topo_instance_t
topo_node_instance(tnode_t * node)245 topo_node_instance(tnode_t *node)
246 {
247 return (node->tn_instance);
248 }
249
250 tnode_t *
topo_node_parent(tnode_t * node)251 topo_node_parent(tnode_t *node)
252 {
253 return (node->tn_parent);
254 }
255
256 int
topo_node_flags(tnode_t * node)257 topo_node_flags(tnode_t *node)
258 {
259 return (node->tn_fflags);
260 }
261
262 void
topo_node_setspecific(tnode_t * node,void * data)263 topo_node_setspecific(tnode_t *node, void *data)
264 {
265 node->tn_priv = data;
266 }
267
268 void *
topo_node_getspecific(tnode_t * node)269 topo_node_getspecific(tnode_t *node)
270 {
271 return (node->tn_priv);
272 }
273
274 static int
node_create_seterror(topo_mod_t * mod,tnode_t * pnode,topo_nodehash_t * nhp,int err)275 node_create_seterror(topo_mod_t *mod, tnode_t *pnode, topo_nodehash_t *nhp,
276 int err)
277 {
278 topo_node_unlock(pnode);
279
280 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to insert child:"
281 "%s\n", topo_strerror(err));
282
283 if (nhp != NULL) {
284 if (nhp->th_name != NULL)
285 topo_mod_strfree(mod, nhp->th_name);
286 if (nhp->th_nodearr != NULL) {
287 topo_mod_free(mod, nhp->th_nodearr,
288 nhp->th_arrlen * sizeof (tnode_t *));
289 }
290 topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
291 }
292
293 return (topo_mod_seterrno(mod, err));
294 }
295
296 int
topo_node_range_create(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max)297 topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
298 topo_instance_t min, topo_instance_t max)
299 {
300 topo_nodehash_t *nhp;
301
302 topo_node_lock(pnode);
303
304 assert((pnode->tn_state & TOPO_NODE_BOUND) ||
305 (pnode->tn_state & TOPO_NODE_ROOT));
306
307 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
308 nhp = topo_list_next(nhp)) {
309 if (strcmp(nhp->th_name, name) == 0)
310 return (node_create_seterror(mod, pnode, NULL,
311 EMOD_NODE_DUP));
312 }
313
314 if (min < 0 || max < min)
315 return (node_create_seterror(mod, pnode, NULL,
316 EMOD_NODE_RANGE));
317
318 if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL)
319 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM));
320
321 if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL)
322 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM));
323
324 nhp->th_arrlen = max - min + 1;
325
326 if ((nhp->th_nodearr = topo_mod_zalloc(mod,
327 nhp->th_arrlen * sizeof (tnode_t *))) == NULL)
328 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM));
329
330 nhp->th_range.tr_min = min;
331 nhp->th_range.tr_max = max;
332 nhp->th_enum = mod;
333 topo_mod_hold(mod);
334
335 /*
336 * Add these nodes to parent child list
337 */
338 topo_list_append(&pnode->tn_children, nhp);
339 topo_node_unlock(pnode);
340
341 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
342 "created node range %s[%d-%d]\n", name, min, max);
343
344 return (0);
345 }
346
347 void
topo_node_range_destroy(tnode_t * pnode,const char * name)348 topo_node_range_destroy(tnode_t *pnode, const char *name)
349 {
350 int i;
351 topo_nodehash_t *nhp;
352 topo_mod_t *mod;
353
354 topo_node_lock(pnode);
355 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
356 nhp = topo_list_next(nhp)) {
357 if (strcmp(nhp->th_name, name) == 0) {
358 break;
359 }
360 }
361
362 if (nhp == NULL) {
363 topo_node_unlock(pnode);
364 return;
365 }
366
367 for (i = 0; i < nhp->th_arrlen; i++)
368 assert(nhp->th_nodearr[i] == NULL);
369
370 topo_list_delete(&pnode->tn_children, nhp);
371 topo_node_unlock(pnode);
372
373 mod = nhp->th_enum;
374 if (nhp->th_name != NULL)
375 topo_mod_strfree(mod, nhp->th_name);
376 if (nhp->th_nodearr != NULL) {
377 topo_mod_free(mod, nhp->th_nodearr,
378 nhp->th_arrlen * sizeof (tnode_t *));
379 }
380 topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
381 topo_mod_rele(mod);
382
383 }
384
385 tnode_t *
topo_node_lookup(tnode_t * pnode,const char * name,topo_instance_t inst)386 topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst)
387 {
388 int h;
389 tnode_t *node;
390 topo_nodehash_t *nhp;
391
392 topo_dprintf(pnode->tn_hdl, TOPO_DBG_MODSVC,
393 "topo_node_lookup: looking for '%s' instance %d\n", name, inst);
394
395 topo_node_lock(pnode);
396 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
397 nhp = topo_list_next(nhp)) {
398 if (strcmp(nhp->th_name, name) == 0) {
399
400 if (inst > nhp->th_range.tr_max ||
401 inst < nhp->th_range.tr_min) {
402 topo_node_unlock(pnode);
403 return (NULL);
404 }
405
406 h = topo_node_hash(nhp, inst);
407 node = nhp->th_nodearr[h];
408 topo_node_unlock(pnode);
409 return (node);
410 }
411 }
412 topo_node_unlock(pnode);
413
414 return (NULL);
415 }
416
417 int
topo_node_hash(topo_nodehash_t * nhp,topo_instance_t inst)418 topo_node_hash(topo_nodehash_t *nhp, topo_instance_t inst)
419 {
420 return ((inst - nhp->th_range.tr_min) % nhp->th_arrlen);
421 }
422
423 static tnode_t *
node_bind_seterror(topo_mod_t * mod,tnode_t * pnode,tnode_t * node,boolean_t pnode_locked,int err)424 node_bind_seterror(topo_mod_t *mod, tnode_t *pnode, tnode_t *node,
425 boolean_t pnode_locked, int err)
426 {
427 if (pnode_locked)
428 topo_node_unlock(pnode);
429
430 (void) topo_mod_seterrno(mod, err);
431
432 if (node == NULL)
433 return (NULL);
434
435 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to bind %s=%d: "
436 "%s\n", (node->tn_name != NULL ? node->tn_name : "unknown"),
437 node->tn_instance, topo_strerror(err));
438
439 topo_node_lock(node); /* expected to be locked */
440 topo_node_destroy(node);
441
442 return (NULL);
443 }
444
445 tnode_t *
topo_node_bind(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t inst,nvlist_t * fmri)446 topo_node_bind(topo_mod_t *mod, tnode_t *pnode, const char *name,
447 topo_instance_t inst, nvlist_t *fmri)
448 {
449 int h, err;
450 tnode_t *node;
451 topo_nodehash_t *nhp;
452
453 topo_node_lock(pnode);
454 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
455 nhp = topo_list_next(nhp)) {
456 if (strcmp(nhp->th_name, name) == 0) {
457
458 if (inst > nhp->th_range.tr_max ||
459 inst < nhp->th_range.tr_min)
460 return (node_bind_seterror(mod, pnode, NULL,
461 B_TRUE, EMOD_NODE_RANGE));
462
463 h = topo_node_hash(nhp, inst);
464 if (nhp->th_nodearr[h] != NULL)
465 return (node_bind_seterror(mod, pnode, NULL,
466 B_TRUE, EMOD_NODE_BOUND));
467 else
468 break;
469
470 }
471 }
472
473 if (nhp == NULL)
474 return (node_bind_seterror(mod, pnode, NULL, B_TRUE,
475 EMOD_NODE_NOENT));
476
477 if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL)
478 return (node_bind_seterror(mod, pnode, NULL, B_TRUE,
479 EMOD_NOMEM));
480
481 (void) pthread_mutex_init(&node->tn_lock, NULL);
482
483 node->tn_enum = mod;
484 node->tn_hdl = mod->tm_hdl;
485 node->tn_parent = pnode;
486 node->tn_name = nhp->th_name;
487 node->tn_instance = inst;
488 node->tn_phash = nhp;
489 node->tn_refs = 0;
490
491 /* Ref count module that bound this node */
492 topo_mod_hold(mod);
493
494 if (fmri == NULL)
495 return (node_bind_seterror(mod, pnode, node, B_TRUE,
496 EMOD_NVL_INVAL));
497
498 if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0)
499 return (node_bind_seterror(mod, pnode, node, B_TRUE, err));
500
501 if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
502 TOPO_PROP_IMMUTABLE, fmri, &err) < 0)
503 return (node_bind_seterror(mod, pnode, node, B_TRUE, err));
504
505 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
506 "node bound %s=%d/%s=%d\n", topo_node_name(pnode),
507 topo_node_instance(pnode), node->tn_name, node->tn_instance);
508
509 node->tn_state |= TOPO_NODE_BOUND;
510
511 topo_node_hold(node);
512 nhp->th_nodearr[h] = node;
513 ++pnode->tn_refs;
514
515 topo_node_unlock(pnode);
516
517 if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) {
518 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
519 FM_FMRI_AUTH_PRODUCT, &err);
520 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
521 FM_FMRI_AUTH_PRODUCT_SN, &err);
522 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
523 FM_FMRI_AUTH_CHASSIS, &err);
524 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
525 FM_FMRI_AUTH_SERVER, &err);
526 }
527
528 return (node);
529 }
530
531 tnode_t *
topo_node_facbind(topo_mod_t * mod,tnode_t * pnode,const char * name,const char * type)532 topo_node_facbind(topo_mod_t *mod, tnode_t *pnode, const char *name,
533 const char *type)
534 {
535 int h, err;
536 tnode_t *node;
537 topo_nodehash_t *nhp;
538 topo_instance_t inst = 0;
539 nvlist_t *pfmri, *fnvl;
540
541 /*
542 * Create a single entry range for this facility
543 */
544 if (topo_node_range_create(mod, pnode, name, 0, 0) < 0)
545 return (NULL); /* mod errno set */
546
547 topo_node_hold(pnode);
548 topo_node_lock(pnode);
549 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
550 nhp = topo_list_next(nhp)) {
551 if (strcmp(nhp->th_name, name) == 0) {
552
553 if (inst > nhp->th_range.tr_max ||
554 inst < nhp->th_range.tr_min) {
555 topo_node_rele(pnode);
556 return (node_bind_seterror(mod, pnode, NULL,
557 B_TRUE, EMOD_NVL_INVAL));
558 }
559 h = topo_node_hash(nhp, inst);
560 if (nhp->th_nodearr[h] != NULL) {
561 topo_node_rele(pnode);
562 return (node_bind_seterror(mod, pnode, NULL,
563 B_TRUE, EMOD_NODE_BOUND));
564 } else
565 break;
566
567 }
568 }
569 topo_node_unlock(pnode);
570
571 if (nhp == NULL) {
572 topo_node_rele(pnode);
573 return (node_bind_seterror(mod, pnode, NULL, B_FALSE,
574 EMOD_NODE_NOENT));
575 }
576 if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) {
577 topo_node_rele(pnode);
578 return (node_bind_seterror(mod, pnode, NULL, B_FALSE,
579 EMOD_NOMEM));
580 }
581
582 (void) pthread_mutex_init(&node->tn_lock, NULL);
583
584 node->tn_enum = mod;
585 node->tn_hdl = mod->tm_hdl;
586 node->tn_parent = pnode;
587 node->tn_name = nhp->th_name;
588 node->tn_instance = inst;
589 node->tn_phash = nhp;
590 node->tn_refs = 0;
591 node->tn_fflags = TOPO_NODE_FACILITY;
592
593 /* Ref count module that bound this node */
594 topo_mod_hold(mod);
595
596 if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0) {
597 topo_node_rele(pnode);
598 return (node_bind_seterror(mod, pnode, node, B_FALSE, err));
599 }
600 if (topo_mod_nvalloc(mod, &fnvl, NV_UNIQUE_NAME) < 0) {
601 topo_node_rele(pnode);
602 return (node_bind_seterror(mod, pnode, node, B_FALSE,
603 EMOD_NOMEM));
604 }
605 if (nvlist_add_string(fnvl, FM_FMRI_FACILITY_NAME, name) != 0 ||
606 nvlist_add_string(fnvl, FM_FMRI_FACILITY_TYPE, type) != 0) {
607 nvlist_free(fnvl);
608 topo_node_rele(pnode);
609 return (node_bind_seterror(mod, pnode, node, B_FALSE,
610 EMOD_FMRI_NVL));
611 }
612
613 if (topo_node_resource(pnode, &pfmri, &err) < 0) {
614 nvlist_free(fnvl);
615 topo_node_rele(pnode);
616 return (node_bind_seterror(mod, pnode, node, B_FALSE, err));
617 }
618
619 if (nvlist_add_nvlist(pfmri, FM_FMRI_FACILITY, fnvl) != 0) {
620 nvlist_free(fnvl);
621 nvlist_free(pfmri);
622 topo_node_rele(pnode);
623 return (node_bind_seterror(mod, pnode, node, B_FALSE,
624 EMOD_FMRI_NVL));
625 }
626
627 nvlist_free(fnvl);
628
629 if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
630 TOPO_PROP_IMMUTABLE, pfmri, &err) < 0) {
631 nvlist_free(pfmri);
632 topo_node_rele(pnode);
633 return (node_bind_seterror(mod, pnode, node, B_FALSE, err));
634 }
635
636 nvlist_free(pfmri);
637
638 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
639 "facility node bound %s=%s\n", type, node->tn_name);
640
641 node->tn_state |= TOPO_NODE_BOUND;
642
643 topo_node_hold(node);
644 nhp->th_nodearr[h] = node;
645
646 topo_node_lock(pnode);
647 ++pnode->tn_refs;
648 topo_node_unlock(pnode);
649 topo_node_rele(pnode);
650
651 if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) {
652 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
653 FM_FMRI_AUTH_PRODUCT, &err);
654 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
655 FM_FMRI_AUTH_PRODUCT_SN, &err);
656 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
657 FM_FMRI_AUTH_CHASSIS, &err);
658 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
659 FM_FMRI_AUTH_SERVER, &err);
660 }
661
662 return (node);
663 }
664
665 int
topo_node_facility(topo_hdl_t * thp,tnode_t * node,const char * fac_type,uint32_t fac_subtype,topo_faclist_t * faclist,int * errp)666 topo_node_facility(topo_hdl_t *thp, tnode_t *node, const char *fac_type,
667 uint32_t fac_subtype, topo_faclist_t *faclist, int *errp)
668 {
669 tnode_t *tmp;
670 nvlist_t *rsrc, *fac;
671 char *tmp_factype;
672 uint32_t tmp_facsubtype;
673 boolean_t list_empty = 1;
674 topo_faclist_t *fac_ele;
675
676 bzero(faclist, sizeof (topo_faclist_t));
677 for (tmp = topo_child_first(node); tmp != NULL;
678 tmp = topo_child_next(node, tmp)) {
679
680 topo_node_hold(tmp);
681 /*
682 * If it's not a facility node, move on
683 */
684 if (topo_node_flags(tmp) != TOPO_NODE_FACILITY) {
685 topo_node_rele(tmp);
686 continue;
687 }
688
689 /*
690 * Lookup whether the fac type is sensor or indicator and if
691 * it's not the type we're looking for, move on
692 */
693 if (topo_node_resource(tmp, &rsrc, errp) != 0) {
694 topo_dprintf(thp, TOPO_DBG_ERR,
695 "Failed to get resource for node %s=%d (%s)\n",
696 topo_node_name(node), topo_node_instance(node),
697 topo_strerror(*errp));
698 topo_node_rele(tmp);
699 return (-1);
700 }
701 if ((nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0) ||
702 (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE,
703 &tmp_factype) != 0)) {
704
705 nvlist_free(rsrc);
706 topo_node_rele(tmp);
707 return (-1);
708 }
709
710 if (strcmp(fac_type, tmp_factype) != 0) {
711 topo_node_rele(tmp);
712 nvlist_free(rsrc);
713 continue;
714 }
715 nvlist_free(rsrc);
716
717 /*
718 * Finally, look up the subtype, which is a property in the
719 * facility propgroup. If it's a match return a pointer to the
720 * node. Otherwise, move on.
721 */
722 if (topo_prop_get_uint32(tmp, TOPO_PGROUP_FACILITY,
723 TOPO_FACILITY_TYPE, &tmp_facsubtype, errp) != 0) {
724 topo_node_rele(tmp);
725 return (-1);
726 }
727 if (fac_subtype == tmp_facsubtype ||
728 fac_subtype == TOPO_FAC_TYPE_ANY) {
729 if ((fac_ele = topo_mod_zalloc(tmp->tn_enum,
730 sizeof (topo_faclist_t))) == NULL) {
731 *errp = ETOPO_NOMEM;
732 topo_node_rele(tmp);
733 return (-1);
734 }
735 fac_ele->tf_node = tmp;
736 topo_list_append(&faclist->tf_list, fac_ele);
737 list_empty = 0;
738 }
739 topo_node_rele(tmp);
740 }
741
742 if (list_empty) {
743 *errp = ETOPO_FAC_NOENT;
744 return (-1);
745 }
746 return (0);
747 }
748
749 void
topo_node_unbind(tnode_t * node)750 topo_node_unbind(tnode_t *node)
751 {
752 if (node == NULL)
753 return;
754
755 topo_node_lock(node);
756 if (!(node->tn_state & TOPO_NODE_BOUND)) {
757 topo_node_unlock(node);
758 return;
759 }
760
761 node->tn_state &= ~TOPO_NODE_BOUND;
762 topo_node_unlock(node);
763
764 topo_dprintf(node->tn_hdl, TOPO_DBG_MODSVC,
765 "node unbound %s=%d/%s=%d refs = %d\n",
766 topo_node_name(node->tn_parent),
767 topo_node_instance(node->tn_parent), node->tn_name,
768 node->tn_instance, node->tn_refs);
769
770 topo_node_rele(node);
771 }
772
773 /*ARGSUSED*/
774 int
topo_node_present(tnode_t * node)775 topo_node_present(tnode_t *node)
776 {
777 return (0);
778 }
779
780 /*ARGSUSED*/
781 int
topo_node_contains(tnode_t * er,tnode_t * ee)782 topo_node_contains(tnode_t *er, tnode_t *ee)
783 {
784 return (0);
785 }
786
787 /*ARGSUSED*/
788 int
topo_node_unusable(tnode_t * node)789 topo_node_unusable(tnode_t *node)
790 {
791 return (0);
792 }
793
794 topo_walk_t *
topo_node_walk_init(topo_hdl_t * thp,topo_mod_t * mod,tnode_t * node,int (* cb_f)(),void * pdata,int * errp)795 topo_node_walk_init(topo_hdl_t *thp, topo_mod_t *mod, tnode_t *node,
796 int (*cb_f)(), void *pdata, int *errp)
797 {
798 tnode_t *child;
799 topo_walk_t *wp;
800
801 topo_node_hold(node);
802
803 if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) {
804 *errp = ETOPO_HDL_NOMEM;
805 topo_node_rele(node);
806 return (NULL);
807 }
808
809 /*
810 * If this is the root of the scheme tree, start with the first
811 * child
812 */
813 topo_node_lock(node);
814 if (node->tn_state & TOPO_NODE_ROOT) {
815 if ((child = topo_child_first(node)) == NULL) {
816 /* Nothing to walk */
817 *errp = ETOPO_WALK_EMPTY;
818 topo_node_unlock(node);
819 topo_node_rele(node);
820 topo_hdl_free(thp, wp, sizeof (topo_walk_t));
821 return (NULL);
822 }
823 topo_node_unlock(node);
824 topo_node_hold(child);
825 wp->tw_node = child;
826 } else {
827 topo_node_unlock(node);
828 topo_node_hold(node); /* rele at walk end */
829 wp->tw_node = node;
830 }
831
832 wp->tw_root = node;
833 wp->tw_cb = cb_f;
834 wp->tw_pdata = pdata;
835 wp->tw_thp = thp;
836 wp->tw_mod = mod;
837
838 return (wp);
839 }
840
841 /*
842 * Walk the direct children of the given node.
843 */
844 int
topo_node_child_walk(topo_hdl_t * thp,tnode_t * pnode,topo_walk_cb_t cb_f,void * arg,int * errp)845 topo_node_child_walk(topo_hdl_t *thp, tnode_t *pnode, topo_walk_cb_t cb_f,
846 void *arg, int *errp)
847 {
848 int ret = TOPO_WALK_TERMINATE;
849 tnode_t *cnode;
850
851 topo_node_hold(pnode);
852
853 /*
854 * First Child:
855 */
856 topo_node_lock(pnode);
857 cnode = topo_child_first(pnode);
858 topo_node_unlock(pnode);
859
860 if (cnode == NULL) {
861 *errp = ETOPO_WALK_EMPTY;
862 ret = TOPO_WALK_ERR;
863 goto out;
864 }
865
866 while (cnode != NULL) {
867 int iret;
868
869 /*
870 * Call the walker callback:
871 */
872 topo_node_hold(cnode);
873 iret = cb_f(thp, cnode, arg);
874 topo_node_rele(cnode);
875 if (iret != TOPO_WALK_NEXT) {
876 ret = iret;
877 break;
878 }
879
880 /*
881 * Next child:
882 */
883 topo_node_lock(pnode);
884 cnode = topo_child_next(pnode, cnode);
885 topo_node_unlock(pnode);
886 }
887
888 out:
889 topo_node_rele(pnode);
890 return (ret);
891 }
892