17205Ssd77468 /*
27205Ssd77468 * CDDL HEADER START
37205Ssd77468 *
47205Ssd77468 * The contents of this file are subject to the terms of the
57205Ssd77468 * Common Development and Distribution License (the "License").
67205Ssd77468 * You may not use this file except in compliance with the License.
77205Ssd77468 *
87205Ssd77468 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97205Ssd77468 * or http://www.opensolaris.org/os/licensing.
107205Ssd77468 * See the License for the specific language governing permissions
117205Ssd77468 * and limitations under the License.
127205Ssd77468 *
137205Ssd77468 * When distributing Covered Code, include this CDDL HEADER in each
147205Ssd77468 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157205Ssd77468 * If applicable, add the following below this CDDL HEADER, with the
167205Ssd77468 * fields enclosed by brackets "[]" replaced with your own identifying
177205Ssd77468 * information: Portions Copyright [yyyy] [name of copyright owner]
187205Ssd77468 *
197205Ssd77468 * CDDL HEADER END
207205Ssd77468 */
217205Ssd77468
227205Ssd77468 /*
23*11583SSurya.Prakki@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
247205Ssd77468 * Use is subject to license terms.
257205Ssd77468 */
267205Ssd77468
277205Ssd77468 /*
287205Ssd77468 * Some topology creation routines may need to defer completing enumeration
297205Ssd77468 * until after the entire PRI graph has been visited. This file includes
307205Ssd77468 * the interfaces necessary to permit these routines to do this in a general
317205Ssd77468 * way.
327205Ssd77468 */
337205Ssd77468
347205Ssd77468 #include <sys/types.h>
357205Ssd77468 #include <sys/time.h>
367205Ssd77468 #include <stddef.h>
377205Ssd77468 #include <inttypes.h>
387205Ssd77468 #include <strings.h>
397205Ssd77468 #include <string.h>
407205Ssd77468 #include <libuutil.h>
417205Ssd77468 #include <libnvpair.h>
427205Ssd77468 #include <sys/mdesc.h>
437205Ssd77468 #include <fm/topo_mod.h>
447205Ssd77468 #include <fm/topo_hc.h>
457205Ssd77468 #include "pi_impl.h"
467205Ssd77468
4710665STom.Pothier@Sun.COM static uu_list_pool_t *defer_pool = NULL;
4810665STom.Pothier@Sun.COM static uu_list_t *defer_list = NULL;
497205Ssd77468
507205Ssd77468 struct pi_defernode_s {
517205Ssd77468 uu_list_node_t defer_node;
527205Ssd77468
537205Ssd77468 mde_cookie_t mde_node; /* MDE node index */
547205Ssd77468 tnode_t *t_parent; /* Parent topology node */
557205Ssd77468 tnode_t *t_node; /* Topo node associated with MDE node */
567205Ssd77468 void *private; /* Private data for defer routine */
577205Ssd77468
587205Ssd77468 pi_deferenum_fn_t *func; /* Defered enumeration routine */
597205Ssd77468 };
607205Ssd77468 typedef struct pi_defernode_s pi_defernode_t;
617205Ssd77468
627205Ssd77468 /* Routines to handle the list of topology parents and mde_nodes */
637205Ssd77468 static int pi_deferlist_create(topo_mod_t *);
647205Ssd77468 static int pi_deferlist_compare(const void *, const void *, void *);
657205Ssd77468
667205Ssd77468
677205Ssd77468 /*
687205Ssd77468 * Add a new routine to the list of deferred enumeration routines
697205Ssd77468 */
707205Ssd77468 int
pi_defer_add(topo_mod_t * mod,mde_cookie_t mde_node,tnode_t * t_parent,tnode_t * t_node,pi_deferenum_fn_t func,void * private)717205Ssd77468 pi_defer_add(topo_mod_t *mod, mde_cookie_t mde_node, tnode_t *t_parent,
727205Ssd77468 tnode_t *t_node, pi_deferenum_fn_t func, void *private)
737205Ssd77468 {
747205Ssd77468 int result;
757205Ssd77468 uu_list_index_t idx;
767205Ssd77468 pi_defernode_t *dnp;
777205Ssd77468
787205Ssd77468 if (defer_list == NULL) {
797205Ssd77468 result = pi_deferlist_create(mod);
807205Ssd77468 if (result != 0) {
817205Ssd77468 return (result);
827205Ssd77468 }
837205Ssd77468 }
847205Ssd77468
857205Ssd77468 /*
867205Ssd77468 * Create a data structure to store information about the node for
877205Ssd77468 * which to defer enumeration. The defer_pool is created by the
887205Ssd77468 * list creation routine, above.
897205Ssd77468 */
907205Ssd77468 dnp = topo_mod_zalloc(mod, sizeof (pi_defernode_t));
917205Ssd77468 if (dnp == NULL) {
92*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_NOMEM);
937205Ssd77468 return (-1);
947205Ssd77468 }
957205Ssd77468 uu_list_node_init(dnp, &(dnp->defer_node), defer_pool);
967205Ssd77468
977205Ssd77468 dnp->mde_node = mde_node;
987205Ssd77468 dnp->t_parent = t_parent;
997205Ssd77468 dnp->t_node = t_node;
1007205Ssd77468 dnp->private = private;
1017205Ssd77468 dnp->func = func;
1027205Ssd77468
1037205Ssd77468 (void) uu_list_find(defer_list, dnp, NULL, &idx);
1047205Ssd77468 uu_list_insert(defer_list, dnp, idx);
1057205Ssd77468
1067205Ssd77468 return (0);
1077205Ssd77468 }
1087205Ssd77468
1097205Ssd77468
1107205Ssd77468 /*
1117205Ssd77468 * Execute the list of deferred enumeration routines, destroying the list as
1127205Ssd77468 * we go.
1137205Ssd77468 */
1147205Ssd77468 int
pi_defer_exec(topo_mod_t * mod,md_t * mdp)1157205Ssd77468 pi_defer_exec(topo_mod_t *mod, md_t *mdp)
1167205Ssd77468 {
1177205Ssd77468 int result;
1187205Ssd77468
1197205Ssd77468 void *dvp;
1207205Ssd77468 pi_defernode_t *dp;
1217205Ssd77468 topo_instance_t inst;
1227205Ssd77468 mde_cookie_t mde_node;
1237205Ssd77468 tnode_t *t_parent;
1247205Ssd77468 tnode_t *t_node;
1257205Ssd77468 void *private;
1267205Ssd77468 char *hc_name;
1277205Ssd77468
1287205Ssd77468 pi_deferenum_fn_t *func;
1297205Ssd77468
1307205Ssd77468 topo_mod_dprintf(mod, "beginning deferred enumerator execution\n");
1317205Ssd77468 if (defer_list == NULL) {
1327205Ssd77468 topo_mod_dprintf(mod, "no deferred enumerators. done.\n");
1337205Ssd77468 return (0);
1347205Ssd77468 }
1357205Ssd77468
1367205Ssd77468 while ((dvp = uu_list_first(defer_list)) != NULL) {
1377205Ssd77468 /* Extract the necessary information from the defernode_t */
1387205Ssd77468 dp = (pi_defernode_t *)dvp;
1397205Ssd77468 mde_node = dp->mde_node;
1407205Ssd77468 t_parent = dp->t_parent;
1417205Ssd77468 t_node = dp->t_node;
1427205Ssd77468 private = dp->private;
1437205Ssd77468 func = dp->func;
1447205Ssd77468
1457205Ssd77468 /*
1467205Ssd77468 * Remove the element from the list. Once we are done calling
1477205Ssd77468 * the routine we do not need it any more.
1487205Ssd77468 */
1497205Ssd77468 uu_list_remove(defer_list, dvp);
1507205Ssd77468 uu_list_node_fini(dp, &(dp->defer_node), defer_pool);
1517205Ssd77468 topo_mod_free(mod, dp, sizeof (pi_defernode_t));
1527205Ssd77468
1537205Ssd77468 /* Get the instance value from the mde node */
1547205Ssd77468 if (pi_get_instance(mod, mdp, mde_node, &inst) != 0) {
1557205Ssd77468 topo_mod_dprintf(mod, "deferred node_0x%llx invalid\n",
1567205Ssd77468 (uint64_t)mde_node);
1577205Ssd77468
1587205Ssd77468 /* Move on to the next node */
159*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
1607205Ssd77468 continue;
1617205Ssd77468 }
1627205Ssd77468
1637205Ssd77468 /* Get the hc name from the mde node */
1647205Ssd77468 hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
1657205Ssd77468 if (hc_name == NULL) {
1667205Ssd77468 topo_mod_dprintf(mod,
1677205Ssd77468 "deferred node_0x%llx has invalid NULL hc_name\n",
1687205Ssd77468 (uint64_t)mde_node);
1697205Ssd77468
1707205Ssd77468 /* Move on to the next node */
171*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
1727205Ssd77468 continue;
1737205Ssd77468 }
1747205Ssd77468 topo_mod_dprintf(mod,
1757205Ssd77468 "calling deferred enumerator for node_0x%llx\n",
1767205Ssd77468 (uint64_t)mde_node);
1777205Ssd77468
1787205Ssd77468 /* Call the deferred enumeration function */
1797205Ssd77468 result = (func)(mod, mdp, mde_node, inst, t_parent, hc_name,
1807205Ssd77468 t_node, private);
1817205Ssd77468 if (result != 0) {
1827205Ssd77468 topo_mod_dprintf(mod,
1837205Ssd77468 "deferred enumeration for node_0x%llx failed\n",
1847205Ssd77468 (uint64_t)mde_node);
185*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
1867205Ssd77468 }
1877205Ssd77468
1887205Ssd77468 /* Clean up from the deferred call */
1897205Ssd77468 topo_mod_strfree(mod, hc_name);
1907205Ssd77468 }
1917205Ssd77468 topo_mod_dprintf(mod, "deferred enumeration completed.\n");
1927205Ssd77468
1937205Ssd77468 uu_list_destroy(defer_list);
1947205Ssd77468 uu_list_pool_destroy(defer_pool);
19510665STom.Pothier@Sun.COM defer_list = NULL;
19610665STom.Pothier@Sun.COM defer_pool = NULL;
1977205Ssd77468
1987205Ssd77468 return (0);
1997205Ssd77468 }
2007205Ssd77468
2017205Ssd77468
2027205Ssd77468 static int
pi_deferlist_create(topo_mod_t * mod)2037205Ssd77468 pi_deferlist_create(topo_mod_t *mod)
2047205Ssd77468 {
2057205Ssd77468 /* Initialize the uutil list structure */
2067205Ssd77468 defer_pool = uu_list_pool_create("pi_defer_pool",
2077205Ssd77468 sizeof (pi_defernode_t), offsetof(pi_defernode_t, defer_node),
2087205Ssd77468 pi_deferlist_compare, 0);
2097205Ssd77468 if (defer_pool == NULL) {
210*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_NOMEM);
2117205Ssd77468 return (-1);
2127205Ssd77468 }
2137205Ssd77468 defer_list = uu_list_create(defer_pool, NULL, 0);
2147205Ssd77468 if (defer_list == NULL) {
2157205Ssd77468 uu_list_pool_destroy(defer_pool);
21610665STom.Pothier@Sun.COM defer_pool = NULL;
217*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_NOMEM);
2187205Ssd77468 return (-1);
2197205Ssd77468 }
2207205Ssd77468
2217205Ssd77468 return (0);
2227205Ssd77468 }
2237205Ssd77468
2247205Ssd77468
2257205Ssd77468 /* ARGSUSED */
2267205Ssd77468 static int
pi_deferlist_compare(const void * l_arg,const void * r_arg,void * private)2277205Ssd77468 pi_deferlist_compare(const void *l_arg, const void *r_arg, void *private)
2287205Ssd77468 {
2297205Ssd77468 pi_defernode_t *lp = (pi_defernode_t *)l_arg;
2307205Ssd77468 pi_defernode_t *rp = (pi_defernode_t *)r_arg;
2317205Ssd77468
2327205Ssd77468 if (lp->func != rp->func) {
2337205Ssd77468 return (1);
2347205Ssd77468 }
2357205Ssd77468 if (lp->t_parent != rp->t_parent) {
2367205Ssd77468 return (-1);
2377205Ssd77468 }
2387205Ssd77468 return (0);
2397205Ssd77468 }
240