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