xref: /titanic_52/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c (revision 2eeaed14a5e2ed9bd811643ad5bffc3510ca0310)
19dd0f810Scindi /*
29dd0f810Scindi  * CDDL HEADER START
39dd0f810Scindi  *
49dd0f810Scindi  * The contents of this file are subject to the terms of the
59dd0f810Scindi  * Common Development and Distribution License (the "License").
69dd0f810Scindi  * You may not use this file except in compliance with the License.
79dd0f810Scindi  *
89dd0f810Scindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99dd0f810Scindi  * or http://www.opensolaris.org/os/licensing.
109dd0f810Scindi  * See the License for the specific language governing permissions
119dd0f810Scindi  * and limitations under the License.
129dd0f810Scindi  *
139dd0f810Scindi  * When distributing Covered Code, include this CDDL HEADER in each
149dd0f810Scindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159dd0f810Scindi  * If applicable, add the following below this CDDL HEADER, with the
169dd0f810Scindi  * fields enclosed by brackets "[]" replaced with your own identifying
179dd0f810Scindi  * information: Portions Copyright [yyyy] [name of copyright owner]
189dd0f810Scindi  *
199dd0f810Scindi  * CDDL HEADER END
209dd0f810Scindi  */
219dd0f810Scindi 
229dd0f810Scindi /*
23*2eeaed14Srobj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
249dd0f810Scindi  * Use is subject to license terms.
259dd0f810Scindi  */
269dd0f810Scindi #pragma ident	"%Z%%M%	%I%	%E% SMI"
279dd0f810Scindi 
289dd0f810Scindi #include <sys/mdb_modapi.h>
299dd0f810Scindi #include <libelf.h>
309dd0f810Scindi #include <sys/fm/protocol.h>
319dd0f810Scindi #include <topo_mod.h>
329dd0f810Scindi #include <topo_tree.h>
339dd0f810Scindi #include <topo_module.h>
3424db4641Seschrock #include <stddef.h>
359dd0f810Scindi 
369dd0f810Scindi 
379dd0f810Scindi /*
389dd0f810Scindi  * We use this to keep track of which bucket we're in while walking
399dd0f810Scindi  * the modhash and we also cache the length of the hash
409dd0f810Scindi  */
419dd0f810Scindi static topo_modhash_t tmh;
429dd0f810Scindi static uint_t hash_idx;
439dd0f810Scindi 
449dd0f810Scindi static uintptr_t curr_pg;
459dd0f810Scindi static uint_t is_root;
469dd0f810Scindi static uint_t verbose;
479dd0f810Scindi static char *pgrp;
489dd0f810Scindi static char *tgt_scheme;
499dd0f810Scindi static char parent[255];
509dd0f810Scindi 
519dd0f810Scindi /*
529dd0f810Scindi  * This structure is used by the topo_nodehash walker instances to
539dd0f810Scindi  * keep track of where they're at in the node hash
549dd0f810Scindi  */
559dd0f810Scindi typedef struct tnwalk_state {
569dd0f810Scindi 	uint_t hash_idx;
579dd0f810Scindi 	topo_nodehash_t hash;
589dd0f810Scindi 	topo_nodehash_t *curr_hash;
599dd0f810Scindi } tnwalk_state_t;
609dd0f810Scindi 
619dd0f810Scindi 
629dd0f810Scindi static char *stab_lvls[] = {"Internal", "", "Private", "Obsolete", "External",
639dd0f810Scindi 	"Unstable", "Evolving", "Stable", "Standard", "Max"};
649dd0f810Scindi 
659dd0f810Scindi /*ARGSUSED*/
669dd0f810Scindi static int
679dd0f810Scindi topo_handle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
689dd0f810Scindi {
699dd0f810Scindi 	char uuid[36], root[36], plat[36], isa[36], machine[36], product[36];
709dd0f810Scindi 	topo_hdl_t th;
719dd0f810Scindi 
729dd0f810Scindi 	/*
739dd0f810Scindi 	 * Read in the structure and then read in all of the string fields from
749dd0f810Scindi 	 * the target's addr space
759dd0f810Scindi 	 */
769dd0f810Scindi 	if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) {
779dd0f810Scindi 		mdb_warn("failed to read topo_hdl_t at %p", addr);
789dd0f810Scindi 		return (DCMD_ERR);
799dd0f810Scindi 	}
809dd0f810Scindi 
819dd0f810Scindi 	if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)th.th_uuid) < 0) {
829dd0f810Scindi 		(void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", th.th_uuid);
839dd0f810Scindi 	}
849dd0f810Scindi 	if (mdb_readstr(root, sizeof (root), (uintptr_t)th.th_rootdir) < 0) {
859dd0f810Scindi 		(void) mdb_snprintf(root, sizeof (root), "<%p>", th.th_rootdir);
869dd0f810Scindi 	}
879dd0f810Scindi 	if (mdb_readstr(plat, sizeof (plat), (uintptr_t)th.th_platform) < 0) {
889dd0f810Scindi 		(void) mdb_snprintf(plat, sizeof (plat), "<%p>",
899dd0f810Scindi 		    th.th_platform);
909dd0f810Scindi 	}
919dd0f810Scindi 	if (mdb_readstr(isa, sizeof (isa), (uintptr_t)th.th_isa) < 0) {
929dd0f810Scindi 		(void) mdb_snprintf(isa, sizeof (isa), "<%p>", th.th_isa);
939dd0f810Scindi 	}
949dd0f810Scindi 	if (mdb_readstr(machine, sizeof (machine), (uintptr_t)th.th_machine)
959dd0f810Scindi 	    < 0) {
969dd0f810Scindi 
979dd0f810Scindi 		(void) mdb_snprintf(machine, sizeof (machine), "<%p>",
989dd0f810Scindi 		    th.th_machine);
999dd0f810Scindi 	}
1009dd0f810Scindi 	if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product)
1019dd0f810Scindi 	    < 0) {
1029dd0f810Scindi 
1039dd0f810Scindi 		(void) mdb_snprintf(product, sizeof (product), "<%p>",
1049dd0f810Scindi 		    th.th_product);
1059dd0f810Scindi 	}
1069dd0f810Scindi 
1079dd0f810Scindi 	/*
1089dd0f810Scindi 	 * Dump it all out in a nice pretty format and keep it to 80 chars wide
1099dd0f810Scindi 	 */
1109dd0f810Scindi 	if (DCMD_HDRSPEC(flags)) {
1119dd0f810Scindi 		mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", "FIELD", "VALUE",
1129dd0f810Scindi 		    "DESCR");
1139dd0f810Scindi 	}
1144557a2a1Srobj 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_lock",
1154557a2a1Srobj 	    addr + offsetof(topo_hdl_t, th_lock),
1169dd0f810Scindi 	    "Mutex lock protecting handle");
1179dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_uuid", uuid,
1189dd0f810Scindi 	    "UUID of the topology snapshot");
1199dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_rootdir", root,
1209dd0f810Scindi 	    "Root directory of plugin paths");
1219dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_platform", plat, "Platform name");
1229dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_isa", isa, "ISA name");
1239dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_machine", machine,
1249dd0f810Scindi 	    "Machine name");
1259dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_product", product,
1269dd0f810Scindi 	    "Product name");
1279dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_di", th.th_di,
1289dd0f810Scindi 	    "Handle to the root of the devinfo tree");
1299dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_pi", th.th_pi,
1309dd0f810Scindi 	    "Handle to the root of the PROM tree");
1319dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_modhash", th.th_modhash,
1329dd0f810Scindi 	    "Module hash");
1339dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_trees", "",
1349dd0f810Scindi 	    "Scheme-specific topo tree list");
1359dd0f810Scindi 	mdb_printf("  %-12s 0x%-34p %-30s\n", "l_prev", th.th_trees.l_prev,
1369dd0f810Scindi 	    "");
1379dd0f810Scindi 	mdb_printf("  %-12s 0x%-34p %-30s\n", "l_next", th.th_trees.l_next,
1389dd0f810Scindi 	    "");
1399dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_alloc", th.th_alloc,
1409dd0f810Scindi 	    "Allocators");
1419dd0f810Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", th.th_errno, "errno");
1429dd0f810Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tm_debug", th.th_debug,
1439dd0f810Scindi 	    "Debug mask");
1449dd0f810Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tm_dbout", th.th_dbout,
1459dd0f810Scindi 	    "Debug channel");
1469dd0f810Scindi 
1479dd0f810Scindi 	return (DCMD_OK);
1489dd0f810Scindi }
1499dd0f810Scindi 
1509dd0f810Scindi 
1519dd0f810Scindi /*ARGSUSED*/
1529dd0f810Scindi static int
1539dd0f810Scindi topo_module(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1549dd0f810Scindi {
1559dd0f810Scindi 	char name[36], path[36], root[36];
1569dd0f810Scindi 	topo_mod_t tm;
1579dd0f810Scindi 
1589dd0f810Scindi 	/*
1599dd0f810Scindi 	 * Read in the structure and then read in all of the string fields from
1609dd0f810Scindi 	 * the target's addr space
1619dd0f810Scindi 	 */
1629dd0f810Scindi 	if (mdb_vread(&tm, sizeof (tm), addr) != sizeof (tm)) {
1639dd0f810Scindi 		mdb_warn("failed to read topo_mod_t at %p", addr);
1649dd0f810Scindi 		return (DCMD_ERR);
1659dd0f810Scindi 	}
1669dd0f810Scindi 
1679dd0f810Scindi 	if (mdb_readstr(name, sizeof (name), (uintptr_t)tm.tm_name) < 0) {
1689dd0f810Scindi 		(void) mdb_snprintf(name, sizeof (name), "<%p>", tm.tm_name);
1699dd0f810Scindi 	}
1709dd0f810Scindi 	if (mdb_readstr(path, sizeof (path), (uintptr_t)tm.tm_path) < 0) {
1719dd0f810Scindi 		(void) mdb_snprintf(path, sizeof (path), "<%p>", tm.tm_path);
1729dd0f810Scindi 	}
1739dd0f810Scindi 	if (mdb_readstr(root, sizeof (root), (uintptr_t)tm.tm_rootdir) < 0) {
1749dd0f810Scindi 		(void) mdb_snprintf(root, sizeof (root), "<%p>", tm.tm_rootdir);
1759dd0f810Scindi 	}
1769dd0f810Scindi 
1779dd0f810Scindi 	/*
1789dd0f810Scindi 	 * Dump it all out in a nice pretty format and keep it to 80 chars wide
1799dd0f810Scindi 	 */
1809dd0f810Scindi 	if (DCMD_HDRSPEC(flags)) {
1819dd0f810Scindi 		mdb_printf("%<u>%-12s %-36s %-30s%</u>\n",
1829dd0f810Scindi 		    "FIELD", "VALUE", "DESCR");
1839dd0f810Scindi 	}
1844557a2a1Srobj 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_lock",
1854557a2a1Srobj 	    addr + offsetof(topo_mod_t, tm_lock),
1869dd0f810Scindi 	    "Lock for tm_cv/owner/flags/refs");
1874557a2a1Srobj 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_cv",
1884557a2a1Srobj 	    addr + offsetof(topo_mod_t, tm_cv),
1899dd0f810Scindi 	    "Module condition variable");
190*2eeaed14Srobj 	if (tm.tm_busy)
191*2eeaed14Srobj 		mdb_printf("%-12s %-36s %-30s\n", "tm_busy", "TRUE",
1929dd0f810Scindi 		    "Busy indicator");
193*2eeaed14Srobj 	else
194*2eeaed14Srobj 		mdb_printf("%-12s %-36s %-30s\n", "tm_busy", "FALSE",
195*2eeaed14Srobj 		    "Busy indicator");
196*2eeaed14Srobj 
1979dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_next", tm.tm_next,
1989dd0f810Scindi 	    "Next module in hash chain");
1999dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_hdl", tm.tm_hdl,
2009dd0f810Scindi 	    "Topo handle for this module");
2019dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_alloc", tm.tm_alloc,
2029dd0f810Scindi 	    "Allocators");
2039dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tm_name", name,
2049dd0f810Scindi 	    "Basename of module");
2059dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tm_path", path,
2069dd0f810Scindi 	    "Full pathname of module");
2079dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tm_rootdir", root,
2089dd0f810Scindi 	    "Relative root directory of module");
2099dd0f810Scindi 	mdb_printf("%-12s %-36u %-30s\n", "tm_refs", tm.tm_refs,
2109dd0f810Scindi 	    "Module reference count");
2119dd0f810Scindi 	mdb_printf("%-12s %-36u %-30s\n", "tm_flags", tm.tm_flags,
2129dd0f810Scindi 	    "Module flags");
2139dd0f810Scindi 	if (TOPO_MOD_INIT & tm.tm_flags) {
2149dd0f810Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_INIT",
2159dd0f810Scindi 		    "Module init completed");
2169dd0f810Scindi 	}
2179dd0f810Scindi 	if (TOPO_MOD_FINI & tm.tm_flags) {
2189dd0f810Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_FINI",
2199dd0f810Scindi 		    "Module fini completed");
2209dd0f810Scindi 	}
2219dd0f810Scindi 	if (TOPO_MOD_REG & tm.tm_flags) {
2229dd0f810Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_REG",
2239dd0f810Scindi 		    "Module registered");
2249dd0f810Scindi 	}
2259dd0f810Scindi 	if (TOPO_MOD_UNREG & tm.tm_flags) {
2269dd0f810Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_UNREG",
2279dd0f810Scindi 		    "Module unregistered");
2289dd0f810Scindi 	}
2299dd0f810Scindi 
2309dd0f810Scindi 	mdb_printf("%-12s %-36u %-30s\n", "tm_debug", tm.tm_debug,
2319dd0f810Scindi 	    "Debug printf mask");
2329dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_data", tm.tm_data,
2339dd0f810Scindi 	    "Private rtld/builtin data");
2349dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_mops", tm.tm_mops,
2359dd0f810Scindi 	    "Module class ops vector");
2369dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_info", tm.tm_info,
2379dd0f810Scindi 	    "Module info registered with handle");
2389dd0f810Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", tm.tm_errno,
2399dd0f810Scindi 	    "Module errno");
2409dd0f810Scindi 
2419dd0f810Scindi 	return (DCMD_OK);
2429dd0f810Scindi }
2439dd0f810Scindi 
2449dd0f810Scindi 
2459dd0f810Scindi /*ARGSUSED*/
2469dd0f810Scindi static int
2479dd0f810Scindi topo_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2489dd0f810Scindi {
2499dd0f810Scindi 	char name[36];
2509dd0f810Scindi 	tnode_t tn;
2519dd0f810Scindi 
2529dd0f810Scindi 	if (!addr)
2539dd0f810Scindi 		return (DCMD_ERR);
2549dd0f810Scindi 
2559dd0f810Scindi 	/*
2569dd0f810Scindi 	 * Read in the structure and then read in all of the string fields from
2579dd0f810Scindi 	 * the target's addr space
2589dd0f810Scindi 	 */
2599dd0f810Scindi 	if (mdb_vread(&tn, sizeof (tn), addr) != sizeof (tn)) {
2609dd0f810Scindi 		mdb_warn("failed to read tnode_t at %p", addr);
2619dd0f810Scindi 		return (DCMD_ERR);
2629dd0f810Scindi 	}
2639dd0f810Scindi 
2649dd0f810Scindi 	if (mdb_readstr(name, sizeof (name), (uintptr_t)tn.tn_name) < 0) {
2659dd0f810Scindi 		(void) mdb_snprintf(name, sizeof (name), "<%p>", tn.tn_name);
2669dd0f810Scindi 	}
2679dd0f810Scindi 
2689dd0f810Scindi 	/*
2699dd0f810Scindi 	 * Dump it all out in a nice pretty format and keep it to 80 chars wide
2709dd0f810Scindi 	 */
2719dd0f810Scindi 	if (DCMD_HDRSPEC(flags)) {
2729dd0f810Scindi 		mdb_printf("%<u>%-12s %-36s %-30s%</u>\n",
2739dd0f810Scindi 		"FIELD", "VALUE", "DESCR");
2749dd0f810Scindi 	}
2759dd0f810Scindi 
27624db4641Seschrock 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_lock",
27724db4641Seschrock 	    addr + offsetof(tnode_t, tn_lock),
27824db4641Seschrock 	    "Lock protecting node members");
2799dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tn_name", name,
2809dd0f810Scindi 	    "Node name");
2819dd0f810Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tn_instance", tn.tn_instance,
2829dd0f810Scindi 	    "Node instance");
2839dd0f810Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tn_state", tn.tn_state,
2849dd0f810Scindi 	    "Node state");
2859dd0f810Scindi 	if (TOPO_NODE_INIT & tn.tn_state) {
2869dd0f810Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_INIT", "");
2879dd0f810Scindi 	}
2889dd0f810Scindi 	if (TOPO_NODE_ROOT & tn.tn_state) {
2899dd0f810Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_ROOT", "");
2909dd0f810Scindi 	}
2919dd0f810Scindi 	if (TOPO_NODE_BOUND & tn.tn_state) {
2929dd0f810Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_BOUND", "");
2939dd0f810Scindi 	}
2949dd0f810Scindi 	if (TOPO_NODE_LINKED & tn.tn_state) {
2959dd0f810Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_LINKED", "");
2969dd0f810Scindi 	}
2979dd0f810Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tn_fflags", tn.tn_fflags,
2989dd0f810Scindi 	    "FMRI flags");
2999dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_parent", tn.tn_parent,
3009dd0f810Scindi 	    "Node parent");
3019dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_phash", tn.tn_phash,
3029dd0f810Scindi 	    "Parent hash bucket");
3039dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_hdl", tn.tn_hdl,
3049dd0f810Scindi 	    "Topo handle");
3059dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_enum", tn.tn_enum,
3069dd0f810Scindi 	    "Enumerator module");
3079dd0f810Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tn_children", "",
3089dd0f810Scindi 	    "Hash table of child nodes");
30924db4641Seschrock 	mdb_printf("  %-12s 0x%-34p\n", "l_prev", tn.tn_children.l_prev);
31024db4641Seschrock 	mdb_printf("  %-12s 0x%-34p\n", "l_next", tn.tn_children.l_next);
3119dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_pgroups", &(tn.tn_pgroups),
3129dd0f810Scindi 	    "Property group list");
3139dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_methods", &(tn.tn_methods),
3149dd0f810Scindi 	    "Registered method list");
3159dd0f810Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_priv", tn.tn_priv,
3169dd0f810Scindi 	    "Private enumerator data");
3179dd0f810Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tn_refs", tn.tn_refs,
3189dd0f810Scindi 	    "Node reference count");
3199dd0f810Scindi 
3209dd0f810Scindi 	return (DCMD_OK);
3219dd0f810Scindi }
3229dd0f810Scindi 
3239dd0f810Scindi /*ARGSUSED*/
3249dd0f810Scindi static int
3259dd0f810Scindi find_tree_root(uintptr_t addr, const void *data, void *arg)
3269dd0f810Scindi {
3279dd0f810Scindi 	ttree_t *tree = (ttree_t *)data;
3289dd0f810Scindi 	char scheme[36];
3299dd0f810Scindi 
3309dd0f810Scindi 	if (mdb_readstr(scheme, sizeof (scheme), (uintptr_t)tree->tt_scheme)
3319dd0f810Scindi 	    < 0) {
3329dd0f810Scindi 		(void) mdb_snprintf(scheme, sizeof (scheme), "<%p>",
3339dd0f810Scindi 		    tree->tt_scheme);
3349dd0f810Scindi 	}
3359dd0f810Scindi 
3369dd0f810Scindi 	if (strncmp(tgt_scheme, scheme, 36) == 0) {
3379dd0f810Scindi 		*((tnode_t **)arg) = tree->tt_root;
3389dd0f810Scindi 		return (WALK_DONE);
3399dd0f810Scindi 	}
3409dd0f810Scindi 	return (WALK_NEXT);
3419dd0f810Scindi }
3429dd0f810Scindi 
343c40d7343Scindi static void
344c40d7343Scindi dump_propmethod(uintptr_t addr)
345c40d7343Scindi {
346c40d7343Scindi 	topo_propmethod_t pm;
347*2eeaed14Srobj 	char mname[32];
348c40d7343Scindi 
349c40d7343Scindi 	if (mdb_vread(&pm, sizeof (pm), addr) != sizeof (pm)) {
350c40d7343Scindi 		mdb_warn("failed to read topo_propmethod at %p", addr);
351c40d7343Scindi 		return;
352c40d7343Scindi 	}
353*2eeaed14Srobj 	if (mdb_readstr(mname, sizeof (mname), (uintptr_t)pm.tpm_name) < 0) {
354*2eeaed14Srobj 		(void) mdb_snprintf(mname, sizeof (mname), "<%p>", pm.tpm_name);
355*2eeaed14Srobj 	}
356c40d7343Scindi 
357*2eeaed14Srobj 	mdb_printf("       method: %-32s version: %-16d args: %p\n",
358*2eeaed14Srobj 	    mname, pm.tpm_version, pm.tpm_args);
359c40d7343Scindi }
3609dd0f810Scindi 
3619dd0f810Scindi /*
3629dd0f810Scindi  * Dump the given property value. For the actual property values
3639dd0f810Scindi  * we dump a pointer to the nvlist which can be decoded using the ::nvlist
3649dd0f810Scindi  * dcmd from the libnvpair MDB module
3659dd0f810Scindi  */
3669dd0f810Scindi /*ARGSUSED*/
3679dd0f810Scindi static int
3689dd0f810Scindi dump_propval(uintptr_t addr, const void *data, void *arg)
3699dd0f810Scindi {
3709dd0f810Scindi 	topo_proplist_t *plistp = (topo_proplist_t *)data;
3719dd0f810Scindi 	topo_propval_t pval;
3729dd0f810Scindi 	char name[32], *type;
3739dd0f810Scindi 
3749dd0f810Scindi 	if (mdb_vread(&pval, sizeof (pval), (uintptr_t)plistp->tp_pval)
3759dd0f810Scindi 	    != sizeof (pval)) {
3769dd0f810Scindi 
3779dd0f810Scindi 		mdb_warn("failed to read topo_propval_t at %p",
3789dd0f810Scindi 		    plistp->tp_pval);
3799dd0f810Scindi 		return (WALK_ERR);
3809dd0f810Scindi 	}
3819dd0f810Scindi 	if (mdb_readstr(name, sizeof (name), (uintptr_t)pval.tp_name) < 0) {
3829dd0f810Scindi 		(void) mdb_snprintf(name, sizeof (name), "<%p>", pval.tp_name);
3839dd0f810Scindi 	}
3849dd0f810Scindi 	switch (pval.tp_type) {
3859dd0f810Scindi 		case TOPO_TYPE_BOOLEAN: type = "boolean"; break;
3869dd0f810Scindi 		case TOPO_TYPE_INT32: type = "int32"; break;
3879dd0f810Scindi 		case TOPO_TYPE_UINT32: type = "uint32"; break;
3889dd0f810Scindi 		case TOPO_TYPE_INT64: type = "int64"; break;
3899dd0f810Scindi 		case TOPO_TYPE_UINT64: type = "uint64"; break;
3909dd0f810Scindi 		case TOPO_TYPE_STRING: type = "string"; break;
3919dd0f810Scindi 		case TOPO_TYPE_FMRI: type = "fmri"; break;
3929dd0f810Scindi 		case TOPO_TYPE_INT32_ARRAY: type = "int32[]"; break;
3939dd0f810Scindi 		case TOPO_TYPE_UINT32_ARRAY: type = "uint32[]"; break;
3949dd0f810Scindi 		case TOPO_TYPE_INT64_ARRAY: type = "int64[]"; break;
3959dd0f810Scindi 		case TOPO_TYPE_UINT64_ARRAY: type = "uint64[]"; break;
3969dd0f810Scindi 		case TOPO_TYPE_STRING_ARRAY: type = "string[]"; break;
3979dd0f810Scindi 		case TOPO_TYPE_FMRI_ARRAY: type = "fmri[]"; break;
3989dd0f810Scindi 		default: type = "unknown type";
3999dd0f810Scindi 	}
4009dd0f810Scindi 	mdb_printf("    %-32s %-16s value: %p\n", name, type, pval.tp_val);
401c40d7343Scindi 
402c40d7343Scindi 	if (pval.tp_method != NULL)
403c40d7343Scindi 		dump_propmethod((uintptr_t)pval.tp_method);
404c40d7343Scindi 
4059dd0f810Scindi 	return (WALK_NEXT);
4069dd0f810Scindi }
4079dd0f810Scindi 
4089dd0f810Scindi 
4099dd0f810Scindi /*
4109dd0f810Scindi  * Dumps the contents of the property group.
4119dd0f810Scindi  */
4129dd0f810Scindi /*ARGSUSED*/
4139dd0f810Scindi static int
4149dd0f810Scindi dump_pgroup(uintptr_t addr, const void *data, void *arg)
4159dd0f810Scindi {
4169dd0f810Scindi 	topo_pgroup_t *pgp = (topo_pgroup_t *)data;
4179dd0f810Scindi 	topo_ipgroup_info_t ipg;
4189dd0f810Scindi 	char buf[32];
4199dd0f810Scindi 
4209dd0f810Scindi 	if (mdb_vread(&ipg, sizeof (ipg), (uintptr_t)pgp->tpg_info)
4219dd0f810Scindi 	    != sizeof (ipg)) {
4229dd0f810Scindi 
4239dd0f810Scindi 		mdb_warn("failed to read topo_ipgroup_info_t at %p",
4249dd0f810Scindi 		    pgp->tpg_info);
4259dd0f810Scindi 		return (WALK_ERR);
4269dd0f810Scindi 	}
4279dd0f810Scindi 	if (mdb_readstr(buf, sizeof (buf), (uintptr_t)ipg.tpi_name) < 0) {
4289dd0f810Scindi 		mdb_warn("failed to read string at %p", ipg.tpi_name);
4299dd0f810Scindi 		return (WALK_ERR);
4309dd0f810Scindi 	}
4319dd0f810Scindi 	/*
4329dd0f810Scindi 	 * If this property group is the one we're interested in or if the user
4339dd0f810Scindi 	 * specified the "all" property group, we'll dump it
4349dd0f810Scindi 	 */
4359dd0f810Scindi 	if ((strncmp(pgrp, buf, sizeof (buf)) == 0) ||
4369dd0f810Scindi 	    (strncmp(pgrp, "all", sizeof (buf)) == 0)) {
4379dd0f810Scindi 
4389dd0f810Scindi 		mdb_printf("  group: %-32s version: %d, stability: %s/%s\n",
4399dd0f810Scindi 		    buf, ipg.tpi_version, stab_lvls[ipg.tpi_namestab],
4409dd0f810Scindi 		    stab_lvls[ipg.tpi_datastab]);
4419dd0f810Scindi 
4429dd0f810Scindi 		(void) mdb_pwalk("topo_proplist", dump_propval, NULL, curr_pg);
4439dd0f810Scindi 	}
4449dd0f810Scindi 	return (WALK_NEXT);
4459dd0f810Scindi }
4469dd0f810Scindi 
4479dd0f810Scindi 
4489dd0f810Scindi /*
4499dd0f810Scindi  * Recursive function to dump the specified node and all of it's children
4509dd0f810Scindi  */
4519dd0f810Scindi /*ARGSUSED*/
4529dd0f810Scindi static int
4539dd0f810Scindi dump_tnode(uintptr_t addr, const void *data, void *arg)
4549dd0f810Scindi {
4559dd0f810Scindi 	tnode_t node;
4569dd0f810Scindi 	char pname[255], buf[80], old_pname[255];
4579dd0f810Scindi 
4589dd0f810Scindi 	if (!addr) {
4599dd0f810Scindi 		return (WALK_NEXT);
4609dd0f810Scindi 	}
4619dd0f810Scindi 
4629dd0f810Scindi 	if (mdb_vread(&node, sizeof (node), addr) != sizeof (node)) {
4639dd0f810Scindi 		mdb_warn("failed to read tnode_t at %p", addr);
4649dd0f810Scindi 		return (WALK_ERR);
4659dd0f810Scindi 	}
4669dd0f810Scindi 	if (mdb_readstr(buf, sizeof (buf), (uintptr_t)node.tn_name) < 0) {
4679dd0f810Scindi 		(void) mdb_snprintf(buf, sizeof (buf), "<%p>",
4689dd0f810Scindi 		    node.tn_name);
4699dd0f810Scindi 	}
4709dd0f810Scindi 
4719dd0f810Scindi 	if (is_root) {
4729dd0f810Scindi 		mdb_snprintf(pname, sizeof (pname), "%s", parent);
4739dd0f810Scindi 		is_root = 0;
4749dd0f810Scindi 	} else {
4759dd0f810Scindi 		mdb_snprintf(pname, sizeof (pname), "%s/%s=%u",
4769dd0f810Scindi 		    parent, buf, node.tn_instance);
4779dd0f810Scindi 
4789dd0f810Scindi 		if (verbose)
4799dd0f810Scindi 			mdb_printf("%s\n  tnode_t: %p\n", pname, addr);
4809dd0f810Scindi 		else
4819dd0f810Scindi 			mdb_printf("%s\n", pname);
4829dd0f810Scindi 	}
4839dd0f810Scindi 	mdb_snprintf(old_pname, sizeof (old_pname), "%s", parent);
4849dd0f810Scindi 	mdb_snprintf(parent, sizeof (parent), "%s", pname);
4859dd0f810Scindi 
4869dd0f810Scindi 	if (pgrp)
4879dd0f810Scindi 		(void) mdb_pwalk("topo_pgroup", dump_pgroup, NULL, addr);
4889dd0f810Scindi 
4899dd0f810Scindi 	(void) mdb_pwalk("topo_nodehash", dump_tnode, NULL, addr);
4909dd0f810Scindi 	mdb_snprintf(parent, sizeof (parent), "%s", old_pname);
4919dd0f810Scindi 
4929dd0f810Scindi 	return (WALK_NEXT);
4939dd0f810Scindi }
4949dd0f810Scindi 
4959dd0f810Scindi 
4969dd0f810Scindi /*
4979dd0f810Scindi  * Given a topo_hdl_t *, the topo dcmd dumps the topo tree.  The format of the
4989dd0f810Scindi  * output is modeled after fmtopo.  Like fmtopo, by default, we'll dump the
4999dd0f810Scindi  * "hc" scheme tree.  The user can optionally specify a different tree via the
5009dd0f810Scindi  * "-s <scheme>" option.
5019dd0f810Scindi  *
5029dd0f810Scindi  * Specifying the "-v" option provides more verbose output.  Currently it
5039dd0f810Scindi  * outputs the tnode_t * addr for each node, which is useful if you want to
5049dd0f810Scindi  * dump it with the topo_node dcmd.
5059dd0f810Scindi  *
5069dd0f810Scindi  * The functionality of the "-P" option is similar to fmtopo.
5079dd0f810Scindi  */
5089dd0f810Scindi /*ARGSUSED*/
5099dd0f810Scindi static int
5109dd0f810Scindi fmtopo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5119dd0f810Scindi {
5129dd0f810Scindi 	char product[36], *opt_s = NULL, *opt_P = NULL;
5139dd0f810Scindi 	topo_hdl_t th;
5149dd0f810Scindi 	tnode_t *tree_root;
5159dd0f810Scindi 	uint_t opt_v = FALSE;
5169dd0f810Scindi 	char *def_scheme = "hc";
5179dd0f810Scindi 
5189dd0f810Scindi 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v,
5199dd0f810Scindi 	    's', MDB_OPT_STR, &opt_s, 'P', MDB_OPT_STR, &opt_P, NULL)
5209dd0f810Scindi 	    != argc) {
5219dd0f810Scindi 		return (DCMD_USAGE);
5229dd0f810Scindi 	}
5239dd0f810Scindi 
5249dd0f810Scindi 	if (opt_s) {
5259dd0f810Scindi 		tgt_scheme = opt_s;
5269dd0f810Scindi 	} else {
5279dd0f810Scindi 		tgt_scheme = def_scheme;
5289dd0f810Scindi 	}
5299dd0f810Scindi 
5309dd0f810Scindi 	pgrp = opt_P;
5319dd0f810Scindi 	verbose = opt_v;
5329dd0f810Scindi 	is_root = 1;
5339dd0f810Scindi 
5349dd0f810Scindi 	/*
5359dd0f810Scindi 	 * Read in the topo_handle and some of its string fields from
5369dd0f810Scindi 	 * the target's addr space
5379dd0f810Scindi 	 */
5389dd0f810Scindi 	if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) {
5399dd0f810Scindi 		mdb_warn("failed to read topo_hdl_t at %p", addr);
5409dd0f810Scindi 		return (DCMD_ERR);
5419dd0f810Scindi 	}
5429dd0f810Scindi 
5439dd0f810Scindi 	if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product)
5449dd0f810Scindi 	    < 0) {
5459dd0f810Scindi 
5469dd0f810Scindi 		(void) mdb_snprintf(product, sizeof (product), "<%p>",
5479dd0f810Scindi 		    th.th_product);
5489dd0f810Scindi 	}
5499dd0f810Scindi 
5509dd0f810Scindi 	mdb_snprintf(parent, sizeof (parent),
5519dd0f810Scindi 	    "%s://:product-id=%s", tgt_scheme, product);
5529dd0f810Scindi 
5539dd0f810Scindi 	/*
5549dd0f810Scindi 	 * Walk the list of topo trees, looking for the one that is for the
5559dd0f810Scindi 	 * scheme we're interested in.
5569dd0f810Scindi 	 */
5579dd0f810Scindi 	tree_root = NULL;
5589dd0f810Scindi 	mdb_pwalk("topo_tree", find_tree_root, &tree_root, addr);
5599dd0f810Scindi 
5609dd0f810Scindi 	if (! tree_root) {
5619dd0f810Scindi 		mdb_warn("failed to find a topo tree for scheme %s\n",
5629dd0f810Scindi 		    tgt_scheme);
5639dd0f810Scindi 		return (DCMD_ERR);
5649dd0f810Scindi 	}
5659dd0f810Scindi 
5669dd0f810Scindi 	return (dump_tnode((uintptr_t)tree_root, NULL, NULL));
5679dd0f810Scindi }
5689dd0f810Scindi 
5699dd0f810Scindi 
5709dd0f810Scindi static int
5719dd0f810Scindi ttree_walk_init(mdb_walk_state_t *wsp)
5729dd0f810Scindi {
5739dd0f810Scindi 	topo_hdl_t th;
5749dd0f810Scindi 
5759dd0f810Scindi 	if (wsp->walk_addr == NULL) {
5769dd0f810Scindi 		mdb_warn("NULL topo_hdl_t passed in");
5779dd0f810Scindi 		return (WALK_ERR);
5789dd0f810Scindi 	}
5799dd0f810Scindi 
5809dd0f810Scindi 	if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) {
5819dd0f810Scindi 		mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr);
5829dd0f810Scindi 		return (WALK_ERR);
5839dd0f810Scindi 	}
5849dd0f810Scindi 
5859dd0f810Scindi 	wsp->walk_addr = (uintptr_t)th.th_trees.l_next;
5869dd0f810Scindi 	wsp->walk_data = mdb_alloc(sizeof (ttree_t), UM_SLEEP);
5879dd0f810Scindi 
5889dd0f810Scindi 	return (WALK_NEXT);
5899dd0f810Scindi }
5909dd0f810Scindi 
5919dd0f810Scindi 
5929dd0f810Scindi static int
5939dd0f810Scindi ttree_walk_step(mdb_walk_state_t *wsp)
5949dd0f810Scindi {
5959dd0f810Scindi 	int rv;
5969dd0f810Scindi 	ttree_t *tree;
5979dd0f810Scindi 
5989dd0f810Scindi 	if (wsp->walk_addr == NULL)
5999dd0f810Scindi 		return (WALK_DONE);
6009dd0f810Scindi 
6019dd0f810Scindi 	if (mdb_vread(wsp->walk_data, sizeof (ttree_t), wsp->walk_addr)
6029dd0f810Scindi 	    != sizeof (ttree_t)) {
6039dd0f810Scindi 
6049dd0f810Scindi 		mdb_warn("failed to read ttree_t at %p", wsp->walk_addr);
6059dd0f810Scindi 		return (WALK_ERR);
6069dd0f810Scindi 	}
6079dd0f810Scindi 
6089dd0f810Scindi 	rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
6099dd0f810Scindi 	    wsp->walk_cbdata);
6109dd0f810Scindi 
6119dd0f810Scindi 	tree = (ttree_t *)wsp->walk_data;
6129dd0f810Scindi 	wsp->walk_addr = (uintptr_t)tree->tt_list.l_next;
6139dd0f810Scindi 
6149dd0f810Scindi 	return (rv);
6159dd0f810Scindi }
6169dd0f810Scindi 
6179dd0f810Scindi 
6189dd0f810Scindi static void
6199dd0f810Scindi ttree_walk_fini(mdb_walk_state_t *wsp)
6209dd0f810Scindi {
6219dd0f810Scindi 	mdb_free(wsp->walk_data, sizeof (ttree_t));
6229dd0f810Scindi }
6239dd0f810Scindi 
6249dd0f810Scindi 
6259dd0f810Scindi static int
6269dd0f810Scindi tmod_walk_init(mdb_walk_state_t *wsp)
6279dd0f810Scindi {
6289dd0f810Scindi 	topo_hdl_t th;
6299dd0f810Scindi 
6309dd0f810Scindi 	if (wsp->walk_addr == NULL) {
6319dd0f810Scindi 		mdb_warn("NULL topo_hdl_t passed in");
6329dd0f810Scindi 		return (WALK_ERR);
6339dd0f810Scindi 	}
6349dd0f810Scindi 
6359dd0f810Scindi 	if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) {
6369dd0f810Scindi 		mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr);
6379dd0f810Scindi 		return (WALK_ERR);
6389dd0f810Scindi 	}
6399dd0f810Scindi 
6409dd0f810Scindi 	if (mdb_vread(&tmh, sizeof (topo_modhash_t), (uintptr_t)th.th_modhash)
6419dd0f810Scindi 	    == -1) {
6429dd0f810Scindi 
6439dd0f810Scindi 		mdb_warn("failed to read topo_modhash_t at %p", wsp->walk_addr);
6449dd0f810Scindi 		return (WALK_DONE);
6459dd0f810Scindi 	}
6469dd0f810Scindi 
6479dd0f810Scindi 	hash_idx = 0;
6489dd0f810Scindi 
6499dd0f810Scindi 	if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *),
6509dd0f810Scindi 	    (uintptr_t)(tmh.mh_hash)) != sizeof (tnode_t *)) {
6519dd0f810Scindi 
6529dd0f810Scindi 		mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *),
6539dd0f810Scindi 		    tmh.mh_hash);
6549dd0f810Scindi 		return (WALK_ERR);
6559dd0f810Scindi 	}
6569dd0f810Scindi 
6579dd0f810Scindi 	wsp->walk_data = mdb_alloc(sizeof (topo_mod_t), UM_SLEEP);
6589dd0f810Scindi 
6599dd0f810Scindi 	return (WALK_NEXT);
6609dd0f810Scindi }
6619dd0f810Scindi 
6629dd0f810Scindi 
6639dd0f810Scindi static int
6649dd0f810Scindi tmod_walk_step(mdb_walk_state_t *wsp)
6659dd0f810Scindi {
6669dd0f810Scindi 	int rv;
6679dd0f810Scindi 	topo_mod_t *tm;
6689dd0f810Scindi 
6699dd0f810Scindi 	if (wsp->walk_addr == NULL)
6709dd0f810Scindi 		return (WALK_DONE);
6719dd0f810Scindi 
6729dd0f810Scindi 	if (mdb_vread(wsp->walk_data, sizeof (topo_mod_t), wsp->walk_addr)
6739dd0f810Scindi 	    == -1) {
6749dd0f810Scindi 
6759dd0f810Scindi 		mdb_warn("failed to read topo_mod_t at %p", wsp->walk_addr);
6769dd0f810Scindi 		return (WALK_DONE);
6779dd0f810Scindi 	}
6789dd0f810Scindi 
6799dd0f810Scindi 	rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
6809dd0f810Scindi 	    wsp->walk_cbdata);
6819dd0f810Scindi 
6829dd0f810Scindi 	tm = (topo_mod_t *)wsp->walk_data;
6839dd0f810Scindi 
6849dd0f810Scindi 	if (tm->tm_next)
6859dd0f810Scindi 		wsp->walk_addr = (uintptr_t)tm->tm_next;
6869dd0f810Scindi 	else if (++hash_idx < tmh.mh_hashlen)
6879dd0f810Scindi 		if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *),
6889dd0f810Scindi 		    (uintptr_t)(tmh.mh_hash+hash_idx)) != sizeof (tnode_t *)) {
6899dd0f810Scindi 
6909dd0f810Scindi 			mdb_warn("failed to read %u bytes at %p",
6919dd0f810Scindi 			    sizeof (tnode_t *), tmh.mh_hash+hash_idx);
6929dd0f810Scindi 			return (DCMD_ERR);
6939dd0f810Scindi 		}
6949dd0f810Scindi 	else
6959dd0f810Scindi 		wsp->walk_addr = NULL;
6969dd0f810Scindi 
6979dd0f810Scindi 	return (rv);
6989dd0f810Scindi }
6999dd0f810Scindi 
7009dd0f810Scindi static void
7019dd0f810Scindi tmod_walk_fini(mdb_walk_state_t *wsp)
7029dd0f810Scindi {
7039dd0f810Scindi 	mdb_free(wsp->walk_data, sizeof (topo_mod_t));
7049dd0f810Scindi }
7059dd0f810Scindi 
7069dd0f810Scindi 
7079dd0f810Scindi static int
7089dd0f810Scindi tpg_walk_init(mdb_walk_state_t *wsp)
7099dd0f810Scindi {
7109dd0f810Scindi 	tnode_t node;
7119dd0f810Scindi 
7129dd0f810Scindi 	if (wsp->walk_addr == NULL) {
7139dd0f810Scindi 		mdb_warn("NULL tnode_t passed in");
7149dd0f810Scindi 		return (WALK_ERR);
7159dd0f810Scindi 	}
7169dd0f810Scindi 
7179dd0f810Scindi 	if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) {
7189dd0f810Scindi 		mdb_warn("failed to read tnode_t at %p", wsp->walk_addr);
7199dd0f810Scindi 		return (WALK_ERR);
7209dd0f810Scindi 	}
7219dd0f810Scindi 
7229dd0f810Scindi 	wsp->walk_addr = (uintptr_t)node.tn_pgroups.l_next;
7239dd0f810Scindi 	wsp->walk_data = mdb_alloc(sizeof (topo_pgroup_t), UM_SLEEP);
7249dd0f810Scindi 
7259dd0f810Scindi 	return (WALK_NEXT);
7269dd0f810Scindi }
7279dd0f810Scindi 
7289dd0f810Scindi 
7299dd0f810Scindi static int
7309dd0f810Scindi tpg_walk_step(mdb_walk_state_t *wsp)
7319dd0f810Scindi {
7329dd0f810Scindi 	int rv;
7339dd0f810Scindi 	topo_pgroup_t *tpgp;
7349dd0f810Scindi 
7359dd0f810Scindi 	if (wsp->walk_addr == NULL)
7369dd0f810Scindi 		return (WALK_DONE);
7379dd0f810Scindi 
7389dd0f810Scindi 	if (mdb_vread(wsp->walk_data, sizeof (topo_pgroup_t), wsp->walk_addr)
7399dd0f810Scindi 	    == -1) {
7409dd0f810Scindi 
7419dd0f810Scindi 		mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr);
7429dd0f810Scindi 		return (WALK_DONE);
7439dd0f810Scindi 	}
7449dd0f810Scindi 
7459dd0f810Scindi 	curr_pg = wsp->walk_addr;
7469dd0f810Scindi 	rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
7479dd0f810Scindi 	    wsp->walk_cbdata);
7489dd0f810Scindi 
7499dd0f810Scindi 	tpgp = (topo_pgroup_t *)wsp->walk_data;
7509dd0f810Scindi 	wsp->walk_addr = (uintptr_t)tpgp->tpg_list.l_next;
7519dd0f810Scindi 
7529dd0f810Scindi 	return (rv);
7539dd0f810Scindi }
7549dd0f810Scindi 
7559dd0f810Scindi 
7569dd0f810Scindi static void
7579dd0f810Scindi tpg_walk_fini(mdb_walk_state_t *wsp)
7589dd0f810Scindi {
7599dd0f810Scindi 	mdb_free(wsp->walk_data, sizeof (topo_pgroup_t));
7609dd0f810Scindi }
7619dd0f810Scindi 
7629dd0f810Scindi 
7639dd0f810Scindi static int
7649dd0f810Scindi tpl_walk_init(mdb_walk_state_t *wsp)
7659dd0f810Scindi {
7669dd0f810Scindi 	topo_pgroup_t pg;
7679dd0f810Scindi 
7689dd0f810Scindi 	if (wsp->walk_addr == NULL) {
7699dd0f810Scindi 		mdb_warn("NULL topo_pgroup_t passed in");
7709dd0f810Scindi 		return (WALK_ERR);
7719dd0f810Scindi 	}
7729dd0f810Scindi 
7739dd0f810Scindi 	if (mdb_vread(&pg, sizeof (pg), wsp->walk_addr) != sizeof (pg)) {
7749dd0f810Scindi 		mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr);
7759dd0f810Scindi 		return (WALK_ERR);
7769dd0f810Scindi 	}
7779dd0f810Scindi 
7789dd0f810Scindi 	wsp->walk_addr = (uintptr_t)pg.tpg_pvals.l_next;
7799dd0f810Scindi 	wsp->walk_data = mdb_alloc(sizeof (topo_proplist_t), UM_SLEEP);
7809dd0f810Scindi 
7819dd0f810Scindi 	return (WALK_NEXT);
7829dd0f810Scindi }
7839dd0f810Scindi 
7849dd0f810Scindi 
7859dd0f810Scindi static int
7869dd0f810Scindi tpl_walk_step(mdb_walk_state_t *wsp)
7879dd0f810Scindi {
7889dd0f810Scindi 	int rv;
7899dd0f810Scindi 	topo_proplist_t *plp;
7909dd0f810Scindi 
7919dd0f810Scindi 	if (wsp->walk_addr == NULL)
7929dd0f810Scindi 		return (WALK_DONE);
7939dd0f810Scindi 
7949dd0f810Scindi 	if (mdb_vread(wsp->walk_data, sizeof (topo_proplist_t), wsp->walk_addr)
7959dd0f810Scindi 	    == -1) {
7969dd0f810Scindi 
7979dd0f810Scindi 		mdb_warn("failed to read topo_proplist_t at %p",
7989dd0f810Scindi 		    wsp->walk_addr);
7999dd0f810Scindi 		return (WALK_DONE);
8009dd0f810Scindi 	}
8019dd0f810Scindi 	plp = (topo_proplist_t *)wsp->walk_data;
8029dd0f810Scindi 
8039dd0f810Scindi 	rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
8049dd0f810Scindi 	    wsp->walk_cbdata);
8059dd0f810Scindi 
8069dd0f810Scindi 	wsp->walk_addr = (uintptr_t)plp->tp_list.l_next;
8079dd0f810Scindi 
8089dd0f810Scindi 	return (rv);
8099dd0f810Scindi }
8109dd0f810Scindi 
8119dd0f810Scindi 
8129dd0f810Scindi static void
8139dd0f810Scindi tpl_walk_fini(mdb_walk_state_t *wsp)
8149dd0f810Scindi {
8159dd0f810Scindi 	mdb_free(wsp->walk_data, sizeof (topo_proplist_t));
8169dd0f810Scindi }
8179dd0f810Scindi 
8189dd0f810Scindi 
8199dd0f810Scindi static int
8209dd0f810Scindi tnh_walk_init(mdb_walk_state_t *wsp)
8219dd0f810Scindi {
8229dd0f810Scindi 	tnode_t node;
8239dd0f810Scindi 	tnwalk_state_t *state;
8249dd0f810Scindi 
8259dd0f810Scindi 	if (wsp->walk_addr == NULL) {
8269dd0f810Scindi 		mdb_warn("NULL tnode_t passed in");
8279dd0f810Scindi 		return (WALK_ERR);
8289dd0f810Scindi 	}
8299dd0f810Scindi 
8309dd0f810Scindi 	if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) {
8319dd0f810Scindi 		mdb_warn("failed to read tnode_t at %p", wsp->walk_addr);
8329dd0f810Scindi 		return (WALK_ERR);
8339dd0f810Scindi 	}
8349dd0f810Scindi 
8359dd0f810Scindi 	state = mdb_zalloc(sizeof (tnwalk_state_t), UM_SLEEP);
8369dd0f810Scindi 
8379dd0f810Scindi 	state->curr_hash = (topo_nodehash_t *)node.tn_children.l_next;
8389dd0f810Scindi 	state->hash_idx = 0;
8399dd0f810Scindi 	wsp->walk_data = state;
8409dd0f810Scindi 
8419dd0f810Scindi 	return (WALK_NEXT);
8429dd0f810Scindi }
8439dd0f810Scindi 
8449dd0f810Scindi 
8459dd0f810Scindi static int
8469dd0f810Scindi tnh_walk_step(mdb_walk_state_t *wsp)
8479dd0f810Scindi {
8489dd0f810Scindi 	tnwalk_state_t *state = wsp->walk_data;
8499dd0f810Scindi 	int rv, i = state->hash_idx++;
8509dd0f810Scindi 	tnode_t *npp;
8519dd0f810Scindi 
8529dd0f810Scindi 	if (state->curr_hash == NULL)
8539dd0f810Scindi 		return (WALK_DONE);
8549dd0f810Scindi 
8559dd0f810Scindi 	if (mdb_vread(&(state->hash), sizeof (topo_nodehash_t),
8569dd0f810Scindi 	    (uintptr_t)state->curr_hash) != sizeof (topo_nodehash_t)) {
8579dd0f810Scindi 
8589dd0f810Scindi 		mdb_warn("failed to read topo_nodehash_t at %p",
8599dd0f810Scindi 		    (uintptr_t)state->curr_hash);
8609dd0f810Scindi 		return (WALK_ERR);
8619dd0f810Scindi 	}
8629dd0f810Scindi 
8639dd0f810Scindi 	if (mdb_vread(&npp, sizeof (tnode_t *),
8649dd0f810Scindi 	    (uintptr_t)(state->hash.th_nodearr+i)) != sizeof (tnode_t *)) {
8659dd0f810Scindi 
8669dd0f810Scindi 		mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *),
8679dd0f810Scindi 		    state->hash.th_nodearr+i);
8689dd0f810Scindi 		return (WALK_ERR);
8699dd0f810Scindi 	}
8709dd0f810Scindi 	wsp->walk_addr = (uintptr_t)npp;
8719dd0f810Scindi 
8729dd0f810Scindi 	rv = wsp->walk_callback(wsp->walk_addr, state, wsp->walk_cbdata);
8739dd0f810Scindi 
8749dd0f810Scindi 	if (state->hash_idx >= state->hash.th_arrlen) {
8759dd0f810Scindi 		/*
8769dd0f810Scindi 		 * move on to the next child hash bucket
8779dd0f810Scindi 		 */
8789dd0f810Scindi 		state->curr_hash =
8799dd0f810Scindi 		    (topo_nodehash_t *)(state->hash.th_list.l_next);
8809dd0f810Scindi 		state->hash_idx = 0;
8819dd0f810Scindi 	}
8829dd0f810Scindi 
8839dd0f810Scindi 	return (rv);
8849dd0f810Scindi }
8859dd0f810Scindi 
8869dd0f810Scindi 
8879dd0f810Scindi static void
8889dd0f810Scindi tnh_walk_fini(mdb_walk_state_t *wsp)
8899dd0f810Scindi {
8909dd0f810Scindi 	mdb_free(wsp->walk_data, sizeof (tnwalk_state_t));
8919dd0f810Scindi }
8929dd0f810Scindi 
8939dd0f810Scindi 
8949dd0f810Scindi static const mdb_dcmd_t dcmds[] = {
8959dd0f810Scindi 	{ "topo_handle", "", "print contents of a topo handle", topo_handle,
8969dd0f810Scindi 		NULL },
8979dd0f810Scindi 	{ "topo_module", "", "print contents of a topo module handle",
8989dd0f810Scindi 		topo_module, NULL },
8999dd0f810Scindi 	{ "topo_node", "", "print contents of a topo node", topo_node, NULL },
9009dd0f810Scindi 	{ "fmtopo", "[-P <pgroup>][-s <scheme>][-v]",
9019dd0f810Scindi 	    "print topology of the given handle", fmtopo, NULL },
9029dd0f810Scindi 	{ NULL }
9039dd0f810Scindi };
9049dd0f810Scindi 
9059dd0f810Scindi static const mdb_walker_t walkers[] = {
9069dd0f810Scindi 	{ "topo_tree", "walk the tree list for a given topo handle",
9079dd0f810Scindi 		ttree_walk_init, ttree_walk_step, ttree_walk_fini, NULL },
9089dd0f810Scindi 	{ "topo_module", "walk the module hash for a given topo handle",
9099dd0f810Scindi 		tmod_walk_init, tmod_walk_step, tmod_walk_fini, NULL },
9109dd0f810Scindi 	{ "topo_pgroup", "walk the property groups for a given topo node",
9119dd0f810Scindi 		tpg_walk_init, tpg_walk_step, tpg_walk_fini, NULL },
9129dd0f810Scindi 	{ "topo_proplist", "walk the property list for a given property group",
9139dd0f810Scindi 		tpl_walk_init, tpl_walk_step, tpl_walk_fini, NULL },
9149dd0f810Scindi 	{ "topo_nodehash", "walk the child nodehash for a given topo node",
9159dd0f810Scindi 		tnh_walk_init, tnh_walk_step, tnh_walk_fini, NULL },
9169dd0f810Scindi 	{ NULL }
9179dd0f810Scindi };
9189dd0f810Scindi 
9199dd0f810Scindi static const mdb_modinfo_t modinfo = {
9209dd0f810Scindi 	MDB_API_VERSION, dcmds, walkers
9219dd0f810Scindi };
9229dd0f810Scindi 
9239dd0f810Scindi const mdb_modinfo_t *
9249dd0f810Scindi _mdb_init(void)
9259dd0f810Scindi {
9269dd0f810Scindi 	return (&modinfo);
9279dd0f810Scindi }
928