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 * Main entry points for SUN4V Platform Independent topology enumerator
297205Ssd77468 */
307205Ssd77468 #include <sys/types.h>
317205Ssd77468 #include <strings.h>
327205Ssd77468 #include <fm/topo_mod.h>
337205Ssd77468 #include <fm/topo_hc.h>
347205Ssd77468 #include <sys/systeminfo.h>
357205Ssd77468 #include <pi_impl.h>
367205Ssd77468
377205Ssd77468 /*
387205Ssd77468 * Entry point called by libtopo when enumeration is required
397205Ssd77468 */
407205Ssd77468 static topo_enum_f pi_enum; /* libtopo enumeration entry point */
417205Ssd77468
427205Ssd77468
437205Ssd77468 /*
447205Ssd77468 * Declare the operations vector and information structure used during
457205Ssd77468 * module registration
467205Ssd77468 */
477205Ssd77468 static topo_modops_t pi_ops = {pi_enum, NULL};
487205Ssd77468 static topo_modinfo_t pi_modinfo = {
497205Ssd77468 SUN4VPI_DESC, SUN4VPI_SCHEME, SUN4VPI_VERSION, &pi_ops
507205Ssd77468 };
517205Ssd77468
527205Ssd77468 static int pi_enum_components(pi_enum_t *, tnode_t *, const char *,
537205Ssd77468 mde_cookie_t, mde_str_cookie_t, mde_str_cookie_t);
547205Ssd77468
557205Ssd77468
567205Ssd77468 /*
577205Ssd77468 * Called by libtopo when the topo module is loaded.
587205Ssd77468 */
597205Ssd77468 void
_topo_init(topo_mod_t * mod,topo_version_t version)607205Ssd77468 _topo_init(topo_mod_t *mod, topo_version_t version)
617205Ssd77468 {
627205Ssd77468 int result;
637205Ssd77468 char isa[MAXNAMELEN];
647205Ssd77468
657205Ssd77468 if (getenv("TOPOSUN4VPIDBG") != NULL) {
667205Ssd77468 /* Debugging is requested for this module */
677205Ssd77468 topo_mod_setdebug(mod);
687205Ssd77468 }
697205Ssd77468 topo_mod_dprintf(mod, "sun4vpi module initializing.\n");
707205Ssd77468
717205Ssd77468 if (version != TOPO_VERSION) {
72*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_VER_NEW);
737205Ssd77468 topo_mod_dprintf(mod, "incompatible topo version %d\n",
747205Ssd77468 version);
757205Ssd77468 return;
767205Ssd77468 }
777205Ssd77468
787205Ssd77468 /* Verify that this is a SUN4V architecture machine */
797205Ssd77468 (void) sysinfo(SI_MACHINE, isa, MAXNAMELEN);
807205Ssd77468 if (strncmp(isa, "sun4v", MAXNAMELEN) != 0) {
817205Ssd77468 topo_mod_dprintf(mod, "not sun4v architecture: %s\n", isa);
827205Ssd77468 return;
837205Ssd77468 }
847205Ssd77468
857205Ssd77468 result = topo_mod_register(mod, &pi_modinfo, TOPO_VERSION);
867205Ssd77468 if (result < 0) {
877205Ssd77468 topo_mod_dprintf(mod, "registration failed: %s\n",
887205Ssd77468 topo_mod_errmsg(mod));
897205Ssd77468
907205Ssd77468 /* module errno already set */
917205Ssd77468 return;
927205Ssd77468 }
937205Ssd77468 topo_mod_dprintf(mod, "module ready.\n");
947205Ssd77468 }
957205Ssd77468
967205Ssd77468
977205Ssd77468 /*
987205Ssd77468 * Clean up any data used by the module before it is unloaded.
997205Ssd77468 */
1007205Ssd77468 void
_topo_fini(topo_mod_t * mod)1017205Ssd77468 _topo_fini(topo_mod_t *mod)
1027205Ssd77468 {
1037205Ssd77468 topo_mod_dprintf(mod, "module finishing.\n");
1047205Ssd77468
1057205Ssd77468 /* Unregister from libtopo */
1067205Ssd77468 topo_mod_unregister(mod);
1077205Ssd77468 }
1087205Ssd77468
1097205Ssd77468
1107205Ssd77468 /*
1117205Ssd77468 * Enumeration entry point for the SUN4V topology enumerator
1127205Ssd77468 */
1137205Ssd77468 /* ARGSUSED */
1147205Ssd77468 static int
pi_enum(topo_mod_t * mod,tnode_t * t_parent,const char * name,topo_instance_t min,topo_instance_t max,void * pi_private,void * data)1157205Ssd77468 pi_enum(topo_mod_t *mod, tnode_t *t_parent, const char *name,
1167205Ssd77468 topo_instance_t min, topo_instance_t max, void *pi_private, void *data)
1177205Ssd77468 {
1187205Ssd77468 int result;
1197205Ssd77468 int idx;
1207205Ssd77468 int num_components;
1217205Ssd77468 size_t csize;
1227205Ssd77468 hrtime_t starttime;
1237205Ssd77468
1247205Ssd77468 pi_enum_t pi;
1257205Ssd77468
1267205Ssd77468 mde_cookie_t *components;
1277205Ssd77468 mde_str_cookie_t arc_cookie;
1287205Ssd77468 mde_str_cookie_t component_cookie;
1297205Ssd77468
1307205Ssd77468 /* Begin enumeration */
1317205Ssd77468 starttime = gethrtime();
1327205Ssd77468 topo_mod_dprintf(mod, "enumeration starting.\n");
1337205Ssd77468
1347205Ssd77468 /* Initialize the walker */
1357205Ssd77468 result = pi_walker_init(mod);
1367205Ssd77468 if (result != 0) {
137*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
1387205Ssd77468 return (-1);
1397205Ssd77468 }
1407205Ssd77468
1417205Ssd77468 /* Open a connection to the LDOM PRI */
1427205Ssd77468 bzero(&pi, sizeof (pi_enum_t));
1437205Ssd77468 result = pi_ldompri_open(mod, &pi);
1447205Ssd77468 if (result != 0) {
1457205Ssd77468 pi_walker_fini(mod);
1467205Ssd77468 topo_mod_dprintf(mod, "could not open LDOM PRI\n");
147*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
1487205Ssd77468 return (-1);
1497205Ssd77468 }
1507205Ssd77468 pi.mod = mod;
1517205Ssd77468
1527205Ssd77468 /*
1537205Ssd77468 * Find the top of the components graph in the PRI using the machine
1547205Ssd77468 * description library.
1557205Ssd77468 */
1567205Ssd77468 num_components = pi_find_mdenodes(mod, pi.mdp, MDE_INVAL_ELEM_COOKIE,
1577205Ssd77468 MD_STR_COMPONENTS, MD_STR_FWD, &components, &csize);
1587205Ssd77468 if (num_components < 0 || components == NULL) {
1597205Ssd77468 /* No nodes were found */
1607205Ssd77468 pi_walker_fini(mod);
1617205Ssd77468 topo_mod_dprintf(mod, "could not find components in PRI\n");
162*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
1637205Ssd77468 return (-1);
1647205Ssd77468 }
1657205Ssd77468
1667205Ssd77468 /*
1677205Ssd77468 * There should be a single components node. But scan all of the
1687205Ssd77468 * results just in case a future machine has multiple hierarchies
1697205Ssd77468 * for some unknown reason.
1707205Ssd77468 *
1717205Ssd77468 * We continue to walk components nodes until they are all exhausted
1727205Ssd77468 * and do not stop if a node cannot be enumerated. Instead, we
1737205Ssd77468 * enumerate what we can and return a partial-enumeration error if
1747205Ssd77468 * there is a problem.
1757205Ssd77468 */
1767205Ssd77468 topo_mod_dprintf(mod, "enumerating %d components hierarchies\n",
1777205Ssd77468 num_components);
1787205Ssd77468
1797205Ssd77468 component_cookie = md_find_name(pi.mdp, MD_STR_COMPONENT);
1807205Ssd77468 arc_cookie = md_find_name(pi.mdp, MD_STR_FWD);
1817205Ssd77468 result = 0;
1827205Ssd77468 for (idx = 0; idx < num_components; idx++) {
1837205Ssd77468 int skip;
1847205Ssd77468
1857205Ssd77468 /*
1867205Ssd77468 * We have found a component hierarchy to process. First,
1877205Ssd77468 * make sure we are not supposed to skip the graph.
1887205Ssd77468 */
1897205Ssd77468 skip = pi_skip_node(mod, pi.mdp, components[idx]);
1907205Ssd77468 if (skip == 0) {
1917205Ssd77468 /*
1927205Ssd77468 * We have found a components node. Find the top-
1937205Ssd77468 * level nodes and create a topology tree from them.
1947205Ssd77468 */
1957205Ssd77468 result = pi_enum_components(&pi, t_parent, name,
1967205Ssd77468 components[idx], component_cookie, arc_cookie);
1977205Ssd77468 }
1987205Ssd77468 }
1997205Ssd77468 topo_mod_free(mod, components, csize);
2007205Ssd77468
2017205Ssd77468 /* Close our connection to the PRI */
2027205Ssd77468 pi_ldompri_close(mod, &pi);
2037205Ssd77468
2047205Ssd77468 /* Clean up after the walker */
2057205Ssd77468 pi_walker_fini(mod);
2067205Ssd77468
2077205Ssd77468 /* Complete enumeration */
2087205Ssd77468 topo_mod_dprintf(mod, "enumeration complete in %lld ms.\n",
2097205Ssd77468 ((gethrtime() - starttime)/MICROSEC));
2107205Ssd77468
2117205Ssd77468 /* All done */
2127205Ssd77468 return (result);
2137205Ssd77468 }
2147205Ssd77468
2157205Ssd77468
2167205Ssd77468 /*
2177205Ssd77468 * This routined is called once for each mde node of type 'components'. It
2187205Ssd77468 * initiates enumeration of the graph starting with with this node.
2197205Ssd77468 */
2207205Ssd77468 static int
pi_enum_components(pi_enum_t * pip,tnode_t * t_parent,const char * hc_name,mde_cookie_t mde_node,mde_str_cookie_t component_cookie,mde_str_cookie_t arc_cookie)2217205Ssd77468 pi_enum_components(pi_enum_t *pip, tnode_t *t_parent, const char *hc_name,
2227205Ssd77468 mde_cookie_t mde_node, mde_str_cookie_t component_cookie,
2237205Ssd77468 mde_str_cookie_t arc_cookie)
2247205Ssd77468 {
2257205Ssd77468 int result;
2267205Ssd77468
2277205Ssd77468 int num_arcs;
2287205Ssd77468 mde_cookie_t *arcp;
2297205Ssd77468 size_t arcsize;
2307205Ssd77468 int arcidx;
2317205Ssd77468
2327205Ssd77468 topo_mod_t *mod = pip->mod;
2337205Ssd77468 md_t *mdp = pip->mdp;
2347205Ssd77468
2357205Ssd77468 if (t_parent == NULL) {
2367205Ssd77468 topo_mod_dprintf(mod,
2377205Ssd77468 "walker failed to create node range with a NULL parent\n");
238*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
2397205Ssd77468 return (-1);
2407205Ssd77468 }
2417205Ssd77468
2427205Ssd77468 /* Determine how many children the given node has */
2437205Ssd77468 num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, NULL, 0);
2447205Ssd77468 if (num_arcs == 0) {
2457205Ssd77468 /*
2467205Ssd77468 * This components node has no children and is not a topo
2477205Ssd77468 * node itself, so set partial enumeration and return.
2487205Ssd77468 */
249*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
2507205Ssd77468 return (0);
2517205Ssd77468 }
2527205Ssd77468 topo_mod_dprintf(mod, "node_0x%llx has %d children\n",
2537205Ssd77468 (uint64_t)mde_node, num_arcs);
2547205Ssd77468
2557205Ssd77468 /* Get the indexes for all the child nodes and put them in an array */
2567205Ssd77468 arcsize = sizeof (mde_cookie_t) * num_arcs;
2577205Ssd77468 arcp = topo_mod_zalloc(mod, arcsize);
2587205Ssd77468 if (arcp == NULL) {
2597205Ssd77468 topo_mod_dprintf(mod, "out of memory\n");
260*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_NOMEM);
2617205Ssd77468 return (-1);
2627205Ssd77468 }
2637205Ssd77468 num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, arcp,
2647205Ssd77468 arcsize);
2657205Ssd77468
2667205Ssd77468 result = 0;
2677205Ssd77468 for (arcidx = 0; arcidx < num_arcs; arcidx++) {
2687205Ssd77468 /*
2697205Ssd77468 * Initiate walking the PRI graph starting with the current
2707205Ssd77468 * child of the components node.
2717205Ssd77468 */
2727205Ssd77468 result = pi_walker(pip, t_parent, hc_name,
2737205Ssd77468 arcp[arcidx], component_cookie, arc_cookie);
2747205Ssd77468 if (result != 0) {
275*11583SSurya.Prakki@Sun.COM (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
2767205Ssd77468 }
2777205Ssd77468 }
2787205Ssd77468 topo_mod_free(mod, arcp, arcsize);
2797205Ssd77468
2807205Ssd77468 /*
2817205Ssd77468 * We have now walked the entire PRI graph. Execute any deferred
2827205Ssd77468 * enumeration routines that need all the nodes to be available.
2837205Ssd77468 */
2847205Ssd77468 result = pi_defer_exec(mod, mdp);
2857205Ssd77468
2867205Ssd77468 return (result);
2877205Ssd77468 }
288