xref: /titanic_52/usr/src/cmd/mdb/common/modules/genunix/devinfo.c (revision 8451e9c37239e5d7cf9ac8607c6fc24c260f633d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
552cac543Sramat  * Common Development and Distribution License (the "License").
652cac543Sramat  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*8451e9c3SGavin Maltby  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
277c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
287c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
297c478bd9Sstevel@tonic-gate #include <sys/ddifm.h>
307c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h>
317c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
327c478bd9Sstevel@tonic-gate #include <sys/hwconf.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h>
367c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <ctype.h>
397c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
407c478bd9Sstevel@tonic-gate #include <mdb/mdb_ks.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include "nvpair.h"
4326947304SEvan Yan #include "devinfo.h"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #define	DEVINFO_TREE_INDENT	4	/* Indent for devs one down in tree */
467c478bd9Sstevel@tonic-gate #define	DEVINFO_PROP_INDENT	4	/* Indent for properties */
477c478bd9Sstevel@tonic-gate #define	DEVINFO_PROPLIST_INDENT	8	/* Indent for properties lists */
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * devinfo node state map. Used by devinfo() and devinfo_audit().
517c478bd9Sstevel@tonic-gate  * Long words are deliberately truncated so that output
527c478bd9Sstevel@tonic-gate  * fits in 80 column with 64-bit addresses.
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate static const char *const di_state[] = {
557c478bd9Sstevel@tonic-gate 	"DS_INVAL",
567c478bd9Sstevel@tonic-gate 	"DS_PROTO",
577c478bd9Sstevel@tonic-gate 	"DS_LINKED",
587c478bd9Sstevel@tonic-gate 	"DS_BOUND",
597c478bd9Sstevel@tonic-gate 	"DS_INITIA",
607c478bd9Sstevel@tonic-gate 	"DS_PROBED",
617c478bd9Sstevel@tonic-gate 	"DS_ATTACH",
627c478bd9Sstevel@tonic-gate 	"DS_READY",
637c478bd9Sstevel@tonic-gate 	"?"
647c478bd9Sstevel@tonic-gate };
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	DI_STATE_MAX	((sizeof (di_state) / sizeof (char *)) - 1)
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate void
697c478bd9Sstevel@tonic-gate prtconf_help(void)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	mdb_printf("Prints the devinfo tree from a given node.\n"
727c478bd9Sstevel@tonic-gate 	    "Without the address of a \"struct devinfo\" given, "
737c478bd9Sstevel@tonic-gate 	    "prints from the root;\n"
747c478bd9Sstevel@tonic-gate 	    "with an address, prints the parents of, "
757c478bd9Sstevel@tonic-gate 	    "and all children of, that address.\n\n"
767c478bd9Sstevel@tonic-gate 	    "Switches:\n"
777c478bd9Sstevel@tonic-gate 	    "  -v   be verbose - print device property lists\n"
787c478bd9Sstevel@tonic-gate 	    "  -p   only print the ancestors of the given node\n"
797c478bd9Sstevel@tonic-gate 	    "  -c   only print the children of the given node\n");
807c478bd9Sstevel@tonic-gate }
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate void
837c478bd9Sstevel@tonic-gate devinfo_help(void)
847c478bd9Sstevel@tonic-gate {
857c478bd9Sstevel@tonic-gate 	mdb_printf("Switches:\n"
867c478bd9Sstevel@tonic-gate 	    "  -q   be quiet - don't print device property lists\n"
877c478bd9Sstevel@tonic-gate 	    "  -s   print summary of dev_info structures\n");
887c478bd9Sstevel@tonic-gate }
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  * Devinfo walker.
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate typedef struct {
967c478bd9Sstevel@tonic-gate 	/*
977c478bd9Sstevel@tonic-gate 	 * The "struct dev_info" must be the first thing in this structure.
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	struct dev_info din_dev;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	/*
1027c478bd9Sstevel@tonic-gate 	 * This is for the benefit of prtconf().
1037c478bd9Sstevel@tonic-gate 	 */
1047c478bd9Sstevel@tonic-gate 	int din_depth;
1057c478bd9Sstevel@tonic-gate } devinfo_node_t;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate typedef struct devinfo_parents_walk_data {
1087c478bd9Sstevel@tonic-gate 	devinfo_node_t dip_node;
1097c478bd9Sstevel@tonic-gate #define	dip_dev dip_node.din_dev
1107c478bd9Sstevel@tonic-gate #define	dip_depth dip_node.din_depth
1117c478bd9Sstevel@tonic-gate 	struct dev_info *dip_end;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/*
1147c478bd9Sstevel@tonic-gate 	 * The following three elements are for walking the parents of a node:
1157c478bd9Sstevel@tonic-gate 	 * "dip_base_depth" is the depth of the given node from the root.
1167c478bd9Sstevel@tonic-gate 	 *   This starts at 1 (if we're walking devinfo_root), because
1177c478bd9Sstevel@tonic-gate 	 *   it's the size of the dip_parent_{nodes,addresses} arrays,
1187c478bd9Sstevel@tonic-gate 	 *   and has to include the given node.
1197c478bd9Sstevel@tonic-gate 	 * "dip_parent_nodes" is a collection of the parent node structures,
1207c478bd9Sstevel@tonic-gate 	 *   already read in via mdb_vread().  dip_parent_nodes[0] is the
1217c478bd9Sstevel@tonic-gate 	 *   root, dip_parent_nodes[1] is a child of the root, etc.
1227c478bd9Sstevel@tonic-gate 	 * "dip_parent_addresses" holds the vaddrs of all the parent nodes.
1237c478bd9Sstevel@tonic-gate 	 */
1247c478bd9Sstevel@tonic-gate 	int dip_base_depth;
1257c478bd9Sstevel@tonic-gate 	devinfo_node_t *dip_parent_nodes;
1267c478bd9Sstevel@tonic-gate 	uintptr_t *dip_parent_addresses;
1277c478bd9Sstevel@tonic-gate } devinfo_parents_walk_data_t;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate int
1307c478bd9Sstevel@tonic-gate devinfo_parents_walk_init(mdb_walk_state_t *wsp)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_data_t *dip;
1337c478bd9Sstevel@tonic-gate 	uintptr_t addr;
13414ef2b2fSdmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
1357c478bd9Sstevel@tonic-gate 	int i;
1367c478bd9Sstevel@tonic-gate 
13714ef2b2fSdmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
13814ef2b2fSdmick 		mdb_warn("failed to read 'top_devinfo'");
13914ef2b2fSdmick 		return (NULL);
14014ef2b2fSdmick 	}
14114ef2b2fSdmick 
1427c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
1437c478bd9Sstevel@tonic-gate 		wsp->walk_addr = devinfo_root;
1447c478bd9Sstevel@tonic-gate 	addr = wsp->walk_addr;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	dip = mdb_alloc(sizeof (devinfo_parents_walk_data_t), UM_SLEEP);
1477c478bd9Sstevel@tonic-gate 	wsp->walk_data = dip;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	dip->dip_end = (struct dev_info *)wsp->walk_addr;
1507c478bd9Sstevel@tonic-gate 	dip->dip_depth = 0;
1517c478bd9Sstevel@tonic-gate 	dip->dip_base_depth = 1;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	do {
1547c478bd9Sstevel@tonic-gate 		if (mdb_vread(&dip->dip_dev, sizeof (dip->dip_dev),
1557c478bd9Sstevel@tonic-gate 		    addr) == -1) {
1567c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read devinfo at %p", addr);
1577c478bd9Sstevel@tonic-gate 			mdb_free(dip, sizeof (devinfo_parents_walk_data_t));
1587c478bd9Sstevel@tonic-gate 			wsp->walk_data = NULL;
1597c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 		addr = (uintptr_t)dip->dip_dev.devi_parent;
1627c478bd9Sstevel@tonic-gate 		if (addr != 0)
1637c478bd9Sstevel@tonic-gate 			dip->dip_base_depth++;
1647c478bd9Sstevel@tonic-gate 	} while (addr != 0);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	addr = wsp->walk_addr;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	dip->dip_parent_nodes = mdb_alloc(
1697c478bd9Sstevel@tonic-gate 	    dip->dip_base_depth * sizeof (devinfo_node_t), UM_SLEEP);
1707c478bd9Sstevel@tonic-gate 	dip->dip_parent_addresses = mdb_alloc(
1717c478bd9Sstevel@tonic-gate 	    dip->dip_base_depth * sizeof (uintptr_t), UM_SLEEP);
1727c478bd9Sstevel@tonic-gate 	for (i = dip->dip_base_depth - 1; i >= 0; i--) {
1737c478bd9Sstevel@tonic-gate 		if (mdb_vread(&dip->dip_parent_nodes[i].din_dev,
1747c478bd9Sstevel@tonic-gate 		    sizeof (struct dev_info), addr) == -1) {
1757c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read devinfo at %p", addr);
1767c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 		dip->dip_parent_nodes[i].din_depth = i;
1797c478bd9Sstevel@tonic-gate 		dip->dip_parent_addresses[i] = addr;
1807c478bd9Sstevel@tonic-gate 		addr = (uintptr_t)
1817c478bd9Sstevel@tonic-gate 		    dip->dip_parent_nodes[i].din_dev.devi_parent;
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate int
1887c478bd9Sstevel@tonic-gate devinfo_parents_walk_step(mdb_walk_state_t *wsp)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_data_t *dip = wsp->walk_data;
1917c478bd9Sstevel@tonic-gate 	int status;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if (dip->dip_depth == dip->dip_base_depth)
1947c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(
1977c478bd9Sstevel@tonic-gate 	    dip->dip_parent_addresses[dip->dip_depth],
1987c478bd9Sstevel@tonic-gate 	    &dip->dip_parent_nodes[dip->dip_depth],
1997c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	dip->dip_depth++;
2027c478bd9Sstevel@tonic-gate 	return (status);
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate void
2067c478bd9Sstevel@tonic-gate devinfo_parents_walk_fini(mdb_walk_state_t *wsp)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_data_t *dip = wsp->walk_data;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	mdb_free(dip->dip_parent_nodes,
2117c478bd9Sstevel@tonic-gate 	    dip->dip_base_depth * sizeof (devinfo_node_t));
2127c478bd9Sstevel@tonic-gate 	mdb_free(dip->dip_parent_addresses,
2137c478bd9Sstevel@tonic-gate 	    dip->dip_base_depth * sizeof (uintptr_t));
2147c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (devinfo_parents_walk_data_t));
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate typedef struct devinfo_children_walk_data {
2197c478bd9Sstevel@tonic-gate 	devinfo_node_t dic_node;
2207c478bd9Sstevel@tonic-gate #define	dic_dev dic_node.din_dev
2217c478bd9Sstevel@tonic-gate #define	dic_depth dic_node.din_depth
2227c478bd9Sstevel@tonic-gate 	struct dev_info *dic_end;
2237c478bd9Sstevel@tonic-gate 	int dic_print_first_node;
2247c478bd9Sstevel@tonic-gate } devinfo_children_walk_data_t;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate int
2277c478bd9Sstevel@tonic-gate devinfo_children_walk_init(mdb_walk_state_t *wsp)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate 	devinfo_children_walk_data_t *dic;
23014ef2b2fSdmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
23114ef2b2fSdmick 
23214ef2b2fSdmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
23314ef2b2fSdmick 		mdb_warn("failed to read 'top_devinfo'");
23414ef2b2fSdmick 		return (NULL);
23514ef2b2fSdmick 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
2387c478bd9Sstevel@tonic-gate 		wsp->walk_addr = devinfo_root;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	dic = mdb_alloc(sizeof (devinfo_children_walk_data_t), UM_SLEEP);
2417c478bd9Sstevel@tonic-gate 	wsp->walk_data = dic;
2427c478bd9Sstevel@tonic-gate 	dic->dic_end = (struct dev_info *)wsp->walk_addr;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	/*
2457c478bd9Sstevel@tonic-gate 	 * This could be set by devinfo_walk_init().
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	if (wsp->walk_arg != NULL) {
2487c478bd9Sstevel@tonic-gate 		dic->dic_depth = (*(int *)wsp->walk_arg - 1);
2497c478bd9Sstevel@tonic-gate 		dic->dic_print_first_node = 0;
2507c478bd9Sstevel@tonic-gate 	} else {
2517c478bd9Sstevel@tonic-gate 		dic->dic_depth = 0;
2527c478bd9Sstevel@tonic-gate 		dic->dic_print_first_node = 1;
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate int
2597c478bd9Sstevel@tonic-gate devinfo_children_walk_step(mdb_walk_state_t *wsp)
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	devinfo_children_walk_data_t *dic = wsp->walk_data;
2627c478bd9Sstevel@tonic-gate 	struct dev_info *v;
2637c478bd9Sstevel@tonic-gate 	devinfo_node_t *cur;
2647c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
2657c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
2687c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dic->dic_dev, sizeof (dic->dic_dev), addr) == -1) {
2717c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo at %p", addr);
2727c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	cur = &dic->dic_node;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (dic->dic_print_first_node == 0)
2777c478bd9Sstevel@tonic-gate 		dic->dic_print_first_node = 1;
2787c478bd9Sstevel@tonic-gate 	else
2797c478bd9Sstevel@tonic-gate 		status = wsp->walk_callback(addr, cur, wsp->walk_cbdata);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/*
2827c478bd9Sstevel@tonic-gate 	 * "v" is always a virtual address pointer,
2837c478bd9Sstevel@tonic-gate 	 *  i.e. can't be deref'ed.
2847c478bd9Sstevel@tonic-gate 	 */
2857c478bd9Sstevel@tonic-gate 	v = (struct dev_info *)addr;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	if (dic->dic_dev.devi_child != NULL) {
2887c478bd9Sstevel@tonic-gate 		v = dic->dic_dev.devi_child;
2897c478bd9Sstevel@tonic-gate 		dic->dic_depth++;
2907c478bd9Sstevel@tonic-gate 	} else if (dic->dic_dev.devi_sibling != NULL && v != dic->dic_end) {
2917c478bd9Sstevel@tonic-gate 		v = dic->dic_dev.devi_sibling;
2927c478bd9Sstevel@tonic-gate 	} else {
2937c478bd9Sstevel@tonic-gate 		while (v != NULL && v != dic->dic_end &&
2947c478bd9Sstevel@tonic-gate 		    dic->dic_dev.devi_sibling == NULL) {
2957c478bd9Sstevel@tonic-gate 			v = dic->dic_dev.devi_parent;
2967c478bd9Sstevel@tonic-gate 			if (v == NULL)
2977c478bd9Sstevel@tonic-gate 				break;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 			mdb_vread(&dic->dic_dev,
3007c478bd9Sstevel@tonic-gate 			    sizeof (struct dev_info), (uintptr_t)v);
3017c478bd9Sstevel@tonic-gate 			dic->dic_depth--;
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 		if (v != NULL && v != dic->dic_end)
3047c478bd9Sstevel@tonic-gate 			v = dic->dic_dev.devi_sibling;
3057c478bd9Sstevel@tonic-gate 		if (v == dic->dic_end)
3067c478bd9Sstevel@tonic-gate 			v = NULL;	/* Done */
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)v;
3107c478bd9Sstevel@tonic-gate 	return (status);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate void
3147c478bd9Sstevel@tonic-gate devinfo_children_walk_fini(mdb_walk_state_t *wsp)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (devinfo_children_walk_data_t));
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate typedef struct devinfo_walk_data {
3207c478bd9Sstevel@tonic-gate 	mdb_walk_state_t diw_parent, diw_child;
3217c478bd9Sstevel@tonic-gate 	enum { DIW_PARENT, DIW_CHILD, DIW_DONE } diw_mode;
3227c478bd9Sstevel@tonic-gate } devinfo_walk_data_t;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate int
3257c478bd9Sstevel@tonic-gate devinfo_walk_init(mdb_walk_state_t *wsp)
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate 	devinfo_walk_data_t *diw;
3287c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_data_t *dip;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	diw = mdb_alloc(sizeof (devinfo_walk_data_t), UM_SLEEP);
3317c478bd9Sstevel@tonic-gate 	diw->diw_parent = *wsp;
3327c478bd9Sstevel@tonic-gate 	diw->diw_child = *wsp;
3337c478bd9Sstevel@tonic-gate 	wsp->walk_data = diw;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	diw->diw_mode = DIW_PARENT;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	if (devinfo_parents_walk_init(&diw->diw_parent) == -1) {
3387c478bd9Sstevel@tonic-gate 		mdb_free(diw, sizeof (devinfo_walk_data_t));
3397c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
3437c478bd9Sstevel@tonic-gate 	 * This is why the "devinfo" walker needs to be marginally
3447c478bd9Sstevel@tonic-gate 	 * complicated - the child walker needs this initialization
3457c478bd9Sstevel@tonic-gate 	 * data, and the best way to get it is out of the parent walker.
3467c478bd9Sstevel@tonic-gate 	 */
3477c478bd9Sstevel@tonic-gate 	dip = diw->diw_parent.walk_data;
3487c478bd9Sstevel@tonic-gate 	diw->diw_child.walk_arg = &dip->dip_base_depth;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (devinfo_children_walk_init(&diw->diw_child) == -1) {
3517c478bd9Sstevel@tonic-gate 		devinfo_parents_walk_fini(&diw->diw_parent);
3527c478bd9Sstevel@tonic-gate 		mdb_free(diw, sizeof (devinfo_walk_data_t));
3537c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate int
3607c478bd9Sstevel@tonic-gate devinfo_walk_step(mdb_walk_state_t *wsp)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	devinfo_walk_data_t *diw = wsp->walk_data;
3637c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (diw->diw_mode == DIW_PARENT) {
3667c478bd9Sstevel@tonic-gate 		status = devinfo_parents_walk_step(&diw->diw_parent);
3677c478bd9Sstevel@tonic-gate 		if (status != WALK_NEXT) {
3687c478bd9Sstevel@tonic-gate 			/*
3697c478bd9Sstevel@tonic-gate 			 * Keep on going even if the parents walk hit an error.
3707c478bd9Sstevel@tonic-gate 			 */
3717c478bd9Sstevel@tonic-gate 			diw->diw_mode = DIW_CHILD;
3727c478bd9Sstevel@tonic-gate 			status = WALK_NEXT;
3737c478bd9Sstevel@tonic-gate 		}
3747c478bd9Sstevel@tonic-gate 	} else if (diw->diw_mode == DIW_CHILD) {
3757c478bd9Sstevel@tonic-gate 		status = devinfo_children_walk_step(&diw->diw_child);
3767c478bd9Sstevel@tonic-gate 		if (status != WALK_NEXT) {
3777c478bd9Sstevel@tonic-gate 			diw->diw_mode = DIW_DONE;
3787c478bd9Sstevel@tonic-gate 			status = WALK_DONE;
3797c478bd9Sstevel@tonic-gate 		}
3807c478bd9Sstevel@tonic-gate 	} else
3817c478bd9Sstevel@tonic-gate 		status = WALK_DONE;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	return (status);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate void
3877c478bd9Sstevel@tonic-gate devinfo_walk_fini(mdb_walk_state_t *wsp)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	devinfo_walk_data_t *diw = wsp->walk_data;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	devinfo_children_walk_fini(&diw->diw_child);
3927c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_fini(&diw->diw_parent);
3937c478bd9Sstevel@tonic-gate 	mdb_free(diw, sizeof (devinfo_walk_data_t));
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate  * Given a devinfo pointer, figure out which driver is associated
3987c478bd9Sstevel@tonic-gate  * with the node (by driver name, from the devnames array).
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4017c478bd9Sstevel@tonic-gate int
4027c478bd9Sstevel@tonic-gate devinfo2driver(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	char dname[MODMAXNAMELEN + 1];
4057c478bd9Sstevel@tonic-gate 	struct dev_info devi;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
4097c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
4127c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo struct at %p", addr);
4137c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 
416f723faa1Seschrock 	if (devi.devi_node_state < DS_ATTACHED) {
4177c478bd9Sstevel@tonic-gate 		/* No driver attached to this devinfo - nothing to do. */
4187c478bd9Sstevel@tonic-gate 		mdb_warn("%p: No driver attached to this devinfo node\n", addr);
4197c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0) {
4237c478bd9Sstevel@tonic-gate 		mdb_warn("failed to determine driver name");
4247c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	mdb_printf("Driver '%s' is associated with devinfo %p.\n", dname, addr);
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate typedef struct devnames_walk {
4347c478bd9Sstevel@tonic-gate 	struct devnames *dnw_names;
4357c478bd9Sstevel@tonic-gate 	int dnw_ndx;
4367c478bd9Sstevel@tonic-gate 	int dnw_devcnt;
4377c478bd9Sstevel@tonic-gate 	uintptr_t dnw_base;
4387c478bd9Sstevel@tonic-gate 	uintptr_t dnw_size;
4397c478bd9Sstevel@tonic-gate } devnames_walk_t;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate int
4427c478bd9Sstevel@tonic-gate devnames_walk_init(mdb_walk_state_t *wsp)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	devnames_walk_t *dnw;
4457c478bd9Sstevel@tonic-gate 	int devcnt;
4467c478bd9Sstevel@tonic-gate 	uintptr_t devnamesp;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
4497c478bd9Sstevel@tonic-gate 		mdb_warn("devnames walker only supports global walks\n");
4507c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devcnt, "devcnt") == -1) {
4547c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devcnt'");
4557c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devnamesp, "devnamesp") == -1) {
4597c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devnamesp'");
4607c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	dnw = mdb_zalloc(sizeof (devnames_walk_t), UM_SLEEP);
4647c478bd9Sstevel@tonic-gate 	dnw->dnw_size = sizeof (struct devnames) * devcnt;
4657c478bd9Sstevel@tonic-gate 	dnw->dnw_devcnt = devcnt;
4667c478bd9Sstevel@tonic-gate 	dnw->dnw_base = devnamesp;
4677c478bd9Sstevel@tonic-gate 	dnw->dnw_names = mdb_alloc(dnw->dnw_size, UM_SLEEP);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (mdb_vread(dnw->dnw_names, dnw->dnw_size, dnw->dnw_base) == -1) {
4707c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devnames array at %p", devnamesp);
4717c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	wsp->walk_data = dnw;
4757c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate int
4797c478bd9Sstevel@tonic-gate devnames_walk_step(mdb_walk_state_t *wsp)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	devnames_walk_t *dnw = wsp->walk_data;
4827c478bd9Sstevel@tonic-gate 	int status;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if (dnw->dnw_ndx == dnw->dnw_devcnt)
4857c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(dnw->dnw_ndx * sizeof (struct devnames) +
4887c478bd9Sstevel@tonic-gate 	    dnw->dnw_base, &dnw->dnw_names[dnw->dnw_ndx], wsp->walk_cbdata);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	dnw->dnw_ndx++;
4917c478bd9Sstevel@tonic-gate 	return (status);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate void
4957c478bd9Sstevel@tonic-gate devnames_walk_fini(mdb_walk_state_t *wsp)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	devnames_walk_t *dnw = wsp->walk_data;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	mdb_free(dnw->dnw_names, dnw->dnw_size);
5007c478bd9Sstevel@tonic-gate 	mdb_free(dnw, sizeof (devnames_walk_t));
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate int
5047c478bd9Sstevel@tonic-gate devinfo_siblings_walk_init(mdb_walk_state_t *wsp)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	struct dev_info di;
5077c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	if (addr == NULL) {
5107c478bd9Sstevel@tonic-gate 		mdb_warn("a dev_info struct address must be provided\n");
5117c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), addr) == -1) {
5157c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dev_info struct at %p", addr);
5167c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5177c478bd9Sstevel@tonic-gate 	}
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	if (di.devi_parent == NULL) {
5207c478bd9Sstevel@tonic-gate 		mdb_warn("no parent for devinfo at %p", addr);
5217c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), (uintptr_t)di.devi_parent) == -1) {
5257c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read parent dev_info struct at %p",
5267c478bd9Sstevel@tonic-gate 		    (uintptr_t)di.devi_parent);
5277c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)di.devi_child;
5317c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate int
5357c478bd9Sstevel@tonic-gate devinfo_siblings_walk_step(mdb_walk_state_t *wsp)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	struct dev_info di;
5387c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	if (addr == NULL)
5417c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), addr) == -1) {
5447c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dev_info struct at %p", addr);
5457c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)di.devi_sibling;
5497c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &di, wsp->walk_cbdata));
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate int
5537c478bd9Sstevel@tonic-gate devi_next_walk_step(mdb_walk_state_t *wsp)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 	struct dev_info di;
5567c478bd9Sstevel@tonic-gate 	int status;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
5597c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1)
5627c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &di, wsp->walk_cbdata);
5657c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)di.devi_next;
5667c478bd9Sstevel@tonic-gate 	return (status);
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate /*
5707c478bd9Sstevel@tonic-gate  * Helper functions.
5717c478bd9Sstevel@tonic-gate  */
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate static int
5747c478bd9Sstevel@tonic-gate is_printable_string(unsigned char *prop_value)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate 	while (*prop_value != 0)
5777c478bd9Sstevel@tonic-gate 		if (!isprint(*prop_value++))
5787c478bd9Sstevel@tonic-gate 			return (0);
5797c478bd9Sstevel@tonic-gate 	return (1);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate static void
5837c478bd9Sstevel@tonic-gate devinfo_print_props_type(int type) {
5847c478bd9Sstevel@tonic-gate 	char *type_str = NULL;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	switch (type) {
5877c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_ANY:
5887c478bd9Sstevel@tonic-gate 		type_str = "any";
5897c478bd9Sstevel@tonic-gate 		break;
5907c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_COMPOSITE:
5917c478bd9Sstevel@tonic-gate 		type_str = "composite";
5927c478bd9Sstevel@tonic-gate 		break;
5937c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_INT64:
5947c478bd9Sstevel@tonic-gate 		type_str = "int64";
5957c478bd9Sstevel@tonic-gate 		break;
5967c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_INT:
5977c478bd9Sstevel@tonic-gate 		type_str = "int";
5987c478bd9Sstevel@tonic-gate 		break;
5997c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_BYTE:
6007c478bd9Sstevel@tonic-gate 		type_str = "byte";
6017c478bd9Sstevel@tonic-gate 		break;
6027c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_STRING:
6037c478bd9Sstevel@tonic-gate 		type_str = "string";
6047c478bd9Sstevel@tonic-gate 		break;
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (type_str != NULL)
6087c478bd9Sstevel@tonic-gate 		mdb_printf("type=%s", type_str);
6097c478bd9Sstevel@tonic-gate 	else
6107c478bd9Sstevel@tonic-gate 		mdb_printf("type=0x%x", type);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate static void
6147c478bd9Sstevel@tonic-gate devinfo_print_props_value(int elem_size, int nelem,
6157c478bd9Sstevel@tonic-gate 	unsigned char *prop_value, int prop_value_len)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	int i;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	mdb_printf("value=");
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	if (elem_size == 0) {
6227c478bd9Sstevel@tonic-gate 		/* if elem_size == 0, then we are printing out string(s) */
6237c478bd9Sstevel@tonic-gate 		char *p = (char *)prop_value;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem - 1; i++) {
6267c478bd9Sstevel@tonic-gate 			mdb_printf("'%s' + ", p);
6277c478bd9Sstevel@tonic-gate 			p += strlen(p) + 1;
6287c478bd9Sstevel@tonic-gate 		}
6297c478bd9Sstevel@tonic-gate 		mdb_printf("'%s'", p);
6307c478bd9Sstevel@tonic-gate 	} else {
6317c478bd9Sstevel@tonic-gate 		/*
6327c478bd9Sstevel@tonic-gate 		 * if elem_size != 0 then we are printing out an array
6337c478bd9Sstevel@tonic-gate 		 * where each element is of elem_size
6347c478bd9Sstevel@tonic-gate 		 */
6357c478bd9Sstevel@tonic-gate 		mdb_nhconvert(prop_value, prop_value, elem_size);
6367c478bd9Sstevel@tonic-gate 		mdb_printf("%02x", *prop_value);
6377c478bd9Sstevel@tonic-gate 		for (i = 1; i < prop_value_len; i++) {
6387c478bd9Sstevel@tonic-gate 			if ((i % elem_size) == 0) {
6397c478bd9Sstevel@tonic-gate 				mdb_nhconvert(&prop_value[i],
6407c478bd9Sstevel@tonic-gate 				    &prop_value[i], elem_size);
6417c478bd9Sstevel@tonic-gate 				mdb_printf(".");
6427c478bd9Sstevel@tonic-gate 			}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 			mdb_printf("%02x", prop_value[i]);
6457c478bd9Sstevel@tonic-gate 		}
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate }
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate /*
6507c478bd9Sstevel@tonic-gate  * devinfo_print_props_guess()
6517c478bd9Sstevel@tonic-gate  * Guesses how to interpret the value of the property
6527c478bd9Sstevel@tonic-gate  *
6537c478bd9Sstevel@tonic-gate  * Params:
6547c478bd9Sstevel@tonic-gate  * 	type      - Should be the type value of the property
6557c478bd9Sstevel@tonic-gate  * 	prop_val  - Pointer to the property value data buffer
6567c478bd9Sstevel@tonic-gate  * 	prop_len  - Length of the property value data buffer
6577c478bd9Sstevel@tonic-gate  *
6587c478bd9Sstevel@tonic-gate  * Return values:
6597c478bd9Sstevel@tonic-gate  * 	nelem     - The number of elements stored in the property value
6607c478bd9Sstevel@tonic-gate  * 			data buffer pointed to by prop_val.
6617c478bd9Sstevel@tonic-gate  * 	elem_size - The size (in bytes) of the elements stored in the property
6627c478bd9Sstevel@tonic-gate  * 			value data buffer pointed to by prop_val.
6637c478bd9Sstevel@tonic-gate  * 			Upon return if elem_size == 0 and nelem != 0 then
6647c478bd9Sstevel@tonic-gate  * 			the property value data buffer contains strings
6657c478bd9Sstevel@tonic-gate  * 	len_err   - There was an error with the length of the data buffer.
6667c478bd9Sstevel@tonic-gate  * 			Its size is not a multiple of the array value type.
6677c478bd9Sstevel@tonic-gate  * 			It will be interpreted as an array of bytes.
6687c478bd9Sstevel@tonic-gate  */
6697c478bd9Sstevel@tonic-gate static void
6707c478bd9Sstevel@tonic-gate devinfo_print_props_guess(int type, unsigned char *prop_val, int prop_len,
6717c478bd9Sstevel@tonic-gate     int *elem_size, int *nelem, int *len_err)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate 	*len_err = 0;
6747c478bd9Sstevel@tonic-gate 	if (prop_len == NULL) {
6757c478bd9Sstevel@tonic-gate 		*elem_size = 0;
6767c478bd9Sstevel@tonic-gate 		*nelem = 0;
6777c478bd9Sstevel@tonic-gate 		return;
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	/* by default, assume an array of bytes */
6817c478bd9Sstevel@tonic-gate 	*elem_size = 1;
6827c478bd9Sstevel@tonic-gate 	*nelem = prop_len;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	switch (type) {
6857c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_BYTE:
6867c478bd9Sstevel@tonic-gate 		/* default case, that was easy */
6877c478bd9Sstevel@tonic-gate 		break;
6887c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_INT64:
6897c478bd9Sstevel@tonic-gate 		if ((prop_len % sizeof (int64_t)) == 0) {
6907c478bd9Sstevel@tonic-gate 			*elem_size = sizeof (int64_t);
6917c478bd9Sstevel@tonic-gate 			*nelem = prop_len / *elem_size;
6927c478bd9Sstevel@tonic-gate 		} else {
6937c478bd9Sstevel@tonic-gate 			/* array is not a multiple of type size, error */
6947c478bd9Sstevel@tonic-gate 			*len_err = 1;
6957c478bd9Sstevel@tonic-gate 		}
6967c478bd9Sstevel@tonic-gate 		break;
6977c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_INT:
6987c478bd9Sstevel@tonic-gate 		if ((prop_len % sizeof (int)) == 0) {
6997c478bd9Sstevel@tonic-gate 			*elem_size = sizeof (int);
7007c478bd9Sstevel@tonic-gate 			*nelem = prop_len / *elem_size;
7017c478bd9Sstevel@tonic-gate 		} else {
7027c478bd9Sstevel@tonic-gate 			/* array is not a multiple of type size, error */
7037c478bd9Sstevel@tonic-gate 			*len_err = 1;
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 		break;
7067c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_STRING:
7077c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_COMPOSITE:
7087c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_ANY:
7097c478bd9Sstevel@tonic-gate 	default:
7107c478bd9Sstevel@tonic-gate 		/*
7117c478bd9Sstevel@tonic-gate 		 * if we made it here the type is either unknown
7127c478bd9Sstevel@tonic-gate 		 * or a string.  Try to interpret is as a string
7137c478bd9Sstevel@tonic-gate 		 * and if that fails assume an array of bytes.
7147c478bd9Sstevel@tonic-gate 		 */
7157c478bd9Sstevel@tonic-gate 		if (prop_val[prop_len - 1] == '\0') {
7167c478bd9Sstevel@tonic-gate 			unsigned char	*s = prop_val;
7177c478bd9Sstevel@tonic-gate 			int		i;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 			/* assume an array of strings */
7207c478bd9Sstevel@tonic-gate 			*elem_size = 0;
7217c478bd9Sstevel@tonic-gate 			*nelem = 0;
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 			for (i = 0; i < prop_len; i++) {
7247c478bd9Sstevel@tonic-gate 				if (prop_val[i] != '\0')
7257c478bd9Sstevel@tonic-gate 					continue;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 				/*
7287c478bd9Sstevel@tonic-gate 				 * If the property is typed as a string
7297c478bd9Sstevel@tonic-gate 				 * property, then interpret empty strings
7307c478bd9Sstevel@tonic-gate 				 * as strings. Otherwise default to an
7317c478bd9Sstevel@tonic-gate 				 * array of bytes. If there are unprintable
7327c478bd9Sstevel@tonic-gate 				 * characters, always default to an array of
7337c478bd9Sstevel@tonic-gate 				 * bytes.
7347c478bd9Sstevel@tonic-gate 				 */
7357c478bd9Sstevel@tonic-gate 				if ((*s == '\0' && type !=
7367c478bd9Sstevel@tonic-gate 				    DDI_PROP_TYPE_STRING) ||
7377c478bd9Sstevel@tonic-gate 				    !is_printable_string(s)) {
7387c478bd9Sstevel@tonic-gate 					*elem_size = 1;
7397c478bd9Sstevel@tonic-gate 					*nelem = prop_len;
7407c478bd9Sstevel@tonic-gate 					break;
7417c478bd9Sstevel@tonic-gate 				}
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 				(*nelem)++;
7447c478bd9Sstevel@tonic-gate 				s = &prop_val[i + 1];
7457c478bd9Sstevel@tonic-gate 			}
7467c478bd9Sstevel@tonic-gate 		}
7477c478bd9Sstevel@tonic-gate 		break;
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate static void
7527c478bd9Sstevel@tonic-gate devinfo_print_props(char *name, ddi_prop_t *p)
7537c478bd9Sstevel@tonic-gate {
7547c478bd9Sstevel@tonic-gate 	if (p == NULL)
7557c478bd9Sstevel@tonic-gate 		return;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (name != NULL)
7587c478bd9Sstevel@tonic-gate 		mdb_printf("%s ", name);
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	mdb_printf("properties at %p:\n", p);
7617c478bd9Sstevel@tonic-gate 	mdb_inc_indent(DEVINFO_PROP_INDENT);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	while (p != NULL) {
7647c478bd9Sstevel@tonic-gate 		ddi_prop_t	prop;
7657c478bd9Sstevel@tonic-gate 		char		prop_name[128];
7667c478bd9Sstevel@tonic-gate 		unsigned char	*prop_value;
7677c478bd9Sstevel@tonic-gate 		int		type, elem_size, nelem, prop_len_error;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 		/* read in the property struct */
7707c478bd9Sstevel@tonic-gate 		if (mdb_vread(&prop, sizeof (prop), (uintptr_t)p) == -1) {
7717c478bd9Sstevel@tonic-gate 			mdb_warn("could not read property at 0x%p", p);
7727c478bd9Sstevel@tonic-gate 			break;
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		/* print the property name */
7767c478bd9Sstevel@tonic-gate 		if (mdb_readstr(prop_name, sizeof (prop_name),
7777c478bd9Sstevel@tonic-gate 		    (uintptr_t)prop.prop_name) == -1) {
7787c478bd9Sstevel@tonic-gate 			mdb_warn("could not read property name at 0x%p",
7797c478bd9Sstevel@tonic-gate 			    prop.prop_name);
7807c478bd9Sstevel@tonic-gate 			goto next;
7817c478bd9Sstevel@tonic-gate 		}
7827c478bd9Sstevel@tonic-gate 		mdb_printf("name='%s' ", prop_name);
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 		/* get the property type and print it out */
7857c478bd9Sstevel@tonic-gate 		type = (prop.prop_flags & DDI_PROP_TYPE_MASK);
7867c478bd9Sstevel@tonic-gate 		devinfo_print_props_type(type);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 		/* get the property value */
7897c478bd9Sstevel@tonic-gate 		if (prop.prop_len > 0) {
7907c478bd9Sstevel@tonic-gate 			prop_value = mdb_alloc(prop.prop_len, UM_SLEEP|UM_GC);
7917c478bd9Sstevel@tonic-gate 			if (mdb_vread(prop_value, prop.prop_len,
7927c478bd9Sstevel@tonic-gate 			    (uintptr_t)prop.prop_val) == -1) {
7937c478bd9Sstevel@tonic-gate 				mdb_warn("could not read property value at "
7947c478bd9Sstevel@tonic-gate 				    "0x%p", prop.prop_val);
7957c478bd9Sstevel@tonic-gate 				goto next;
7967c478bd9Sstevel@tonic-gate 			}
7977c478bd9Sstevel@tonic-gate 		} else {
7987c478bd9Sstevel@tonic-gate 			prop_value = NULL;
7997c478bd9Sstevel@tonic-gate 		}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 		/* take a guess at interpreting the property value */
8027c478bd9Sstevel@tonic-gate 		devinfo_print_props_guess(type, prop_value, prop.prop_len,
8037c478bd9Sstevel@tonic-gate 		    &elem_size, &nelem, &prop_len_error);
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 		/* print out the number ot items */
8067c478bd9Sstevel@tonic-gate 		mdb_printf(" items=%d", nelem);
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		/* print out any associated device information */
8097c478bd9Sstevel@tonic-gate 		if (prop.prop_dev != DDI_DEV_T_NONE) {
8107c478bd9Sstevel@tonic-gate 			mdb_printf(" dev=");
8117c478bd9Sstevel@tonic-gate 			if (prop.prop_dev == DDI_DEV_T_ANY)
8127c478bd9Sstevel@tonic-gate 				mdb_printf("any");
8137c478bd9Sstevel@tonic-gate 			else if (prop.prop_dev == DDI_MAJOR_T_UNKNOWN)
8147c478bd9Sstevel@tonic-gate 				mdb_printf("unknown");
8157c478bd9Sstevel@tonic-gate 			else
8167c478bd9Sstevel@tonic-gate 				mdb_printf("(%u,%u)",
8177c478bd9Sstevel@tonic-gate 				    getmajor(prop.prop_dev),
8187c478bd9Sstevel@tonic-gate 				    getminor(prop.prop_dev));
8197c478bd9Sstevel@tonic-gate 		}
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 		/* print out the property value */
8227c478bd9Sstevel@tonic-gate 		if (prop_value != NULL) {
8237c478bd9Sstevel@tonic-gate 			mdb_printf("\n");
8247c478bd9Sstevel@tonic-gate 			mdb_inc_indent(DEVINFO_PROP_INDENT);
8257c478bd9Sstevel@tonic-gate 			if (prop_len_error)
8267c478bd9Sstevel@tonic-gate 				mdb_printf("NOTE: prop length is not a "
8277c478bd9Sstevel@tonic-gate 				    "multiple of element size\n");
8287c478bd9Sstevel@tonic-gate 			devinfo_print_props_value(elem_size, nelem,
8297c478bd9Sstevel@tonic-gate 			    prop_value, prop.prop_len);
8307c478bd9Sstevel@tonic-gate 			mdb_dec_indent(DEVINFO_PROP_INDENT);
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate next:
8347c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
8357c478bd9Sstevel@tonic-gate 		p = prop.prop_next;
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	mdb_dec_indent(DEVINFO_PROP_INDENT);
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate static void
8427c478bd9Sstevel@tonic-gate devinfo_pathinfo_state(mdi_pathinfo_state_t state) {
8437c478bd9Sstevel@tonic-gate 	char *type_str = NULL;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	switch (state) {
8467c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_INIT:
8477c478bd9Sstevel@tonic-gate 		type_str = "init";
8487c478bd9Sstevel@tonic-gate 		break;
8497c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_ONLINE:
8507c478bd9Sstevel@tonic-gate 		type_str = "online";
8517c478bd9Sstevel@tonic-gate 		break;
8527c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_STANDBY:
8537c478bd9Sstevel@tonic-gate 		type_str = "standby";
8547c478bd9Sstevel@tonic-gate 		break;
8557c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_FAULT:
8567c478bd9Sstevel@tonic-gate 		type_str = "fault";
8577c478bd9Sstevel@tonic-gate 		break;
8587c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_OFFLINE:
8597c478bd9Sstevel@tonic-gate 		type_str = "offline";
8607c478bd9Sstevel@tonic-gate 		break;
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 	if (type_str != NULL)
8637c478bd9Sstevel@tonic-gate 		mdb_printf("state=%s\n", type_str);
8647c478bd9Sstevel@tonic-gate 	else
8657c478bd9Sstevel@tonic-gate 		mdb_printf("state=0x%x\n", state);
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate static void
8697c478bd9Sstevel@tonic-gate devinfo_print_pathing(int mdi_component, void *mdi_client) {
8707c478bd9Sstevel@tonic-gate 	mdi_client_t		mdi_c;
8717c478bd9Sstevel@tonic-gate 	struct mdi_pathinfo	*pip;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	/* we only print out multipathing info for client nodes */
8747c478bd9Sstevel@tonic-gate 	if ((mdi_component & MDI_COMPONENT_CLIENT) == 0)
8757c478bd9Sstevel@tonic-gate 		return;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	mdb_printf("Client multipath info at: 0x%p\n", mdi_client);
8787c478bd9Sstevel@tonic-gate 	mdb_inc_indent(DEVINFO_PROP_INDENT);
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	/* read in the client multipathing info */
8817c478bd9Sstevel@tonic-gate 	if (mdb_readstr((void*) &mdi_c, sizeof (mdi_c),
8827c478bd9Sstevel@tonic-gate 	    (uintptr_t)mdi_client) == -1) {
8837c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read mdi_client at %p",
8847c478bd9Sstevel@tonic-gate 		    (uintptr_t)mdi_client);
8857c478bd9Sstevel@tonic-gate 		goto exit;
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	/*
8897c478bd9Sstevel@tonic-gate 	 * walk through the clients list of pathinfo structures and print
8907c478bd9Sstevel@tonic-gate 	 * out the properties for each path
8917c478bd9Sstevel@tonic-gate 	 */
8927c478bd9Sstevel@tonic-gate 	pip = (struct mdi_pathinfo *)mdi_c.ct_path_head;
8937c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
8947c478bd9Sstevel@tonic-gate 		char			binding_name[128];
8957c478bd9Sstevel@tonic-gate 		struct mdi_pathinfo	pi;
8967c478bd9Sstevel@tonic-gate 		mdi_phci_t		ph;
8977c478bd9Sstevel@tonic-gate 		struct dev_info		ph_di;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 		/* read in the pathinfo structure */
9007c478bd9Sstevel@tonic-gate 		if (mdb_vread((void*)&pi, sizeof (pi),
9017c478bd9Sstevel@tonic-gate 			    (uintptr_t)pip) == -1) {
9027c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read mdi_pathinfo at %p",
9037c478bd9Sstevel@tonic-gate 			    (uintptr_t)pip);
9047c478bd9Sstevel@tonic-gate 			goto exit;
9057c478bd9Sstevel@tonic-gate 		}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		/* read in the pchi (path host adapter) info */
9087c478bd9Sstevel@tonic-gate 		if (mdb_vread((void*)&ph, sizeof (ph),
9097c478bd9Sstevel@tonic-gate 			    (uintptr_t)pi.pi_phci) == -1) {
9107c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read mdi_pchi at %p",
9117c478bd9Sstevel@tonic-gate 			    (uintptr_t)pi.pi_phci);
9127c478bd9Sstevel@tonic-gate 			goto exit;
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 		/* read in the dip of the phci so we can get it's name */
9167c478bd9Sstevel@tonic-gate 		if (mdb_vread((void*)&ph_di, sizeof (ph_di),
9177c478bd9Sstevel@tonic-gate 			    (uintptr_t)ph.ph_dip) == -1) {
9187c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read mdi_pchi at %p",
9197c478bd9Sstevel@tonic-gate 			    (uintptr_t)ph.ph_dip);
9207c478bd9Sstevel@tonic-gate 			goto exit;
9217c478bd9Sstevel@tonic-gate 		}
9227c478bd9Sstevel@tonic-gate 		if (mdb_vread(binding_name, sizeof (binding_name),
9237c478bd9Sstevel@tonic-gate 			    (uintptr_t)ph_di.devi_binding_name) == -1) {
9247c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read binding_name at %p",
9257c478bd9Sstevel@tonic-gate 			    (uintptr_t)ph_di.devi_binding_name);
9267c478bd9Sstevel@tonic-gate 			goto exit;
9277c478bd9Sstevel@tonic-gate 		}
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 		mdb_printf("%s#%d, ", binding_name, ph_di.devi_instance);
9307c478bd9Sstevel@tonic-gate 		devinfo_pathinfo_state(pi.pi_state);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 		/* print out the pathing info */
9337c478bd9Sstevel@tonic-gate 		mdb_inc_indent(DEVINFO_PROP_INDENT);
9347c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd(NVPAIR_WALKER_FQNAME, NVPAIR_DCMD_FQNAME,
9357c478bd9Sstevel@tonic-gate 			    0, NULL, (uintptr_t)pi.pi_prop) != 0) {
9367c478bd9Sstevel@tonic-gate 			mdb_dec_indent(DEVINFO_PROP_INDENT);
9377c478bd9Sstevel@tonic-gate 			goto exit;
9387c478bd9Sstevel@tonic-gate 		}
9397c478bd9Sstevel@tonic-gate 		mdb_dec_indent(DEVINFO_PROP_INDENT);
9407c478bd9Sstevel@tonic-gate 		pip = pi.pi_client_link;
9417c478bd9Sstevel@tonic-gate 	}
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate exit:
9447c478bd9Sstevel@tonic-gate 	mdb_dec_indent(DEVINFO_PROP_INDENT);
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate static int
9487c478bd9Sstevel@tonic-gate devinfo_print(uintptr_t addr, struct dev_info *dev, devinfo_cb_data_t *data)
9497c478bd9Sstevel@tonic-gate {
9507c478bd9Sstevel@tonic-gate 	/*
9517c478bd9Sstevel@tonic-gate 	 * We know the walker passes us extra data after the dev_info.
9527c478bd9Sstevel@tonic-gate 	 */
9537c478bd9Sstevel@tonic-gate 	char		binding_name[128];
954f723faa1Seschrock 	char		dname[MODMAXNAMELEN + 1];
9557c478bd9Sstevel@tonic-gate 	devinfo_node_t	*din = (devinfo_node_t *)dev;
9567c478bd9Sstevel@tonic-gate 	ddi_prop_t	*global_props = NULL;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	if (mdb_readstr(binding_name, sizeof (binding_name),
9597c478bd9Sstevel@tonic-gate 	    (uintptr_t)dev->devi_binding_name) == -1) {
9607c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read binding_name at %p",
9617c478bd9Sstevel@tonic-gate 		    (uintptr_t)dev->devi_binding_name);
9627c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	/* if there are any global properties, get a pointer to them */
9667c478bd9Sstevel@tonic-gate 	if (dev->devi_global_prop_list != NULL) {
9677c478bd9Sstevel@tonic-gate 		ddi_prop_list_t	plist;
9687c478bd9Sstevel@tonic-gate 		if (mdb_vread((void*)&plist, sizeof (plist),
9697c478bd9Sstevel@tonic-gate 		    (uintptr_t)dev->devi_global_prop_list) == -1) {
9707c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read global prop_list at %p",
9717c478bd9Sstevel@tonic-gate 			    (uintptr_t)dev->devi_global_prop_list);
9727c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
9737c478bd9Sstevel@tonic-gate 		}
9747c478bd9Sstevel@tonic-gate 		global_props = plist.prop_list;
9757c478bd9Sstevel@tonic-gate 	}
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	mdb_inc_indent(din->din_depth * DEVINFO_TREE_INDENT);
9787c478bd9Sstevel@tonic-gate 	if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD))
9797c478bd9Sstevel@tonic-gate 		mdb_printf("%<b>");
9807c478bd9Sstevel@tonic-gate 	mdb_printf("%-0?p %s", addr, binding_name);
9817c478bd9Sstevel@tonic-gate 	if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD))
9827c478bd9Sstevel@tonic-gate 		mdb_printf("%</b>");
9837c478bd9Sstevel@tonic-gate 	if (dev->devi_instance >= 0)
9847c478bd9Sstevel@tonic-gate 		mdb_printf(", instance #%d", dev->devi_instance);
985f723faa1Seschrock 
986f723faa1Seschrock 	if (dev->devi_node_state < DS_ATTACHED)
9877c478bd9Sstevel@tonic-gate 		mdb_printf(" (driver not attached)");
988f723faa1Seschrock 	else if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0)
989f723faa1Seschrock 		mdb_printf(" (could not determine driver name)");
990f723faa1Seschrock 	else
991f723faa1Seschrock 		mdb_printf(" (driver name: %s)", dname);
992f723faa1Seschrock 
9937c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
9947c478bd9Sstevel@tonic-gate 	if (data->di_flags & DEVINFO_VERBOSE) {
9957c478bd9Sstevel@tonic-gate 		mdb_inc_indent(DEVINFO_PROPLIST_INDENT);
9967c478bd9Sstevel@tonic-gate 		devinfo_print_props("System", dev->devi_sys_prop_ptr);
9977c478bd9Sstevel@tonic-gate 		devinfo_print_props("Driver", dev->devi_drv_prop_ptr);
9987c478bd9Sstevel@tonic-gate 		devinfo_print_props("Hardware", dev->devi_hw_prop_ptr);
9997c478bd9Sstevel@tonic-gate 		devinfo_print_props("Global", global_props);
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		devinfo_print_pathing(dev->devi_mdi_component,
10027c478bd9Sstevel@tonic-gate 		    dev->devi_mdi_client);
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 		mdb_dec_indent(DEVINFO_PROPLIST_INDENT);
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	mdb_dec_indent(din->din_depth * DEVINFO_TREE_INDENT);
10087c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10127c478bd9Sstevel@tonic-gate int
10137c478bd9Sstevel@tonic-gate prtconf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
10147c478bd9Sstevel@tonic-gate {
10157c478bd9Sstevel@tonic-gate 	devinfo_cb_data_t data;
101614ef2b2fSdmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
10177c478bd9Sstevel@tonic-gate 	int status;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	data.di_flags = DEVINFO_PARENT | DEVINFO_CHILD;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
10227c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, DEVINFO_VERBOSE, &data.di_flags,
10237c478bd9Sstevel@tonic-gate 	    'p', MDB_OPT_CLRBITS, DEVINFO_CHILD, &data.di_flags,
10247c478bd9Sstevel@tonic-gate 	    'c', MDB_OPT_CLRBITS, DEVINFO_PARENT, &data.di_flags, NULL) != argc)
10257c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
10267c478bd9Sstevel@tonic-gate 
102714ef2b2fSdmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
102814ef2b2fSdmick 		mdb_warn("failed to read 'top_devinfo'");
102914ef2b2fSdmick 		return (NULL);
103014ef2b2fSdmick 	}
103114ef2b2fSdmick 
10327c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
10337c478bd9Sstevel@tonic-gate 		addr = devinfo_root;
10347c478bd9Sstevel@tonic-gate 		if (data.di_flags & DEVINFO_VERBOSE)
10357c478bd9Sstevel@tonic-gate 			data.di_flags |= DEVINFO_ALLBOLD;
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	data.di_base = addr;
10397c478bd9Sstevel@tonic-gate 	mdb_printf("%<u>%-?s %-50s%</u>\n", "DEVINFO", "NAME");
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	if ((data.di_flags & (DEVINFO_PARENT | DEVINFO_CHILD)) ==
10427c478bd9Sstevel@tonic-gate 	    (DEVINFO_PARENT | DEVINFO_CHILD)) {
10437c478bd9Sstevel@tonic-gate 		status = mdb_pwalk("devinfo",
10447c478bd9Sstevel@tonic-gate 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
10457c478bd9Sstevel@tonic-gate 	} else if (data.di_flags & DEVINFO_PARENT) {
10467c478bd9Sstevel@tonic-gate 		status = mdb_pwalk("devinfo_parents",
10477c478bd9Sstevel@tonic-gate 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
10487c478bd9Sstevel@tonic-gate 	} else if (data.di_flags & DEVINFO_CHILD) {
10497c478bd9Sstevel@tonic-gate 		status = mdb_pwalk("devinfo_children",
10507c478bd9Sstevel@tonic-gate 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
10517c478bd9Sstevel@tonic-gate 	} else {
10527c478bd9Sstevel@tonic-gate 		devinfo_node_t din;
10537c478bd9Sstevel@tonic-gate 		if (mdb_vread(&din.din_dev, sizeof (din.din_dev), addr) == -1) {
10547c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read device");
10557c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
10567c478bd9Sstevel@tonic-gate 		}
10577c478bd9Sstevel@tonic-gate 		din.din_depth = 0;
10587c478bd9Sstevel@tonic-gate 		return (devinfo_print(addr, (struct dev_info *)&din, &data));
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	if (status == -1) {
10627c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk devinfo tree");
10637c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10707c478bd9Sstevel@tonic-gate int
10717c478bd9Sstevel@tonic-gate devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
10727c478bd9Sstevel@tonic-gate {
10737c478bd9Sstevel@tonic-gate 	char tmpstr[MODMAXNAMELEN];
10747c478bd9Sstevel@tonic-gate 	char nodename[MODMAXNAMELEN];
1075f4da9be0Scth 	char bindname[MAXPATHLEN];
10767c478bd9Sstevel@tonic-gate 	int size, length;
10777c478bd9Sstevel@tonic-gate 	struct dev_info devi;
10787c478bd9Sstevel@tonic-gate 	devinfo_node_t din;
10797c478bd9Sstevel@tonic-gate 	devinfo_cb_data_t data;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t devi_state_masks[] = {
10827c478bd9Sstevel@tonic-gate 	    { "DEVICE_OFFLINE",	DEVI_DEVICE_OFFLINE,	DEVI_DEVICE_OFFLINE },
10837c478bd9Sstevel@tonic-gate 	    { "DEVICE_DOWN",	DEVI_DEVICE_DOWN,	DEVI_DEVICE_DOWN },
10847c478bd9Sstevel@tonic-gate 	    { "DEVICE_DEGRADED", DEVI_DEVICE_DEGRADED,	DEVI_DEVICE_DEGRADED },
1085f4da9be0Scth 	    { "DEVICE_REMOVED", DEVI_DEVICE_REMOVED,	DEVI_DEVICE_REMOVED },
10867c478bd9Sstevel@tonic-gate 	    { "BUS_QUIESCED",	DEVI_BUS_QUIESCED,	DEVI_BUS_QUIESCED },
10877c478bd9Sstevel@tonic-gate 	    { "BUS_DOWN",	DEVI_BUS_DOWN,		DEVI_BUS_DOWN },
10887c478bd9Sstevel@tonic-gate 	    { "NDI_CONFIG",	DEVI_NDI_CONFIG,	DEVI_NDI_CONFIG	},
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	    { "S_ATTACHING",	DEVI_S_ATTACHING,	DEVI_S_ATTACHING },
10917c478bd9Sstevel@tonic-gate 	    { "S_DETACHING",	DEVI_S_DETACHING,	DEVI_S_DETACHING },
10927c478bd9Sstevel@tonic-gate 	    { "S_ONLINING",	DEVI_S_ONLINING,	DEVI_S_ONLINING },
10937c478bd9Sstevel@tonic-gate 	    { "S_OFFLINING",	DEVI_S_OFFLINING,	DEVI_S_OFFLINING },
10947c478bd9Sstevel@tonic-gate 	    { "S_INVOKING_DACF", DEVI_S_INVOKING_DACF,	DEVI_S_INVOKING_DACF },
10957c478bd9Sstevel@tonic-gate 	    { "S_UNBOUND",	DEVI_S_UNBOUND,		DEVI_S_UNBOUND },
10967c478bd9Sstevel@tonic-gate 	    { "S_REPORT",	DEVI_S_REPORT,		DEVI_S_REPORT },
10977c478bd9Sstevel@tonic-gate 	    { "S_EVADD",	DEVI_S_EVADD,		DEVI_S_EVADD },
10987c478bd9Sstevel@tonic-gate 	    { "S_EVREMOVE",	DEVI_S_EVREMOVE,	DEVI_S_EVREMOVE },
1099f4da9be0Scth 	    { "S_NEED_RESET",	DEVI_S_NEED_RESET,	DEVI_S_NEED_RESET },
11007c478bd9Sstevel@tonic-gate 	    { NULL,		0,			0 }
11017c478bd9Sstevel@tonic-gate 	};
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t devi_flags_masks[] = {
11047c478bd9Sstevel@tonic-gate 	    { "BUSY",		DEVI_BUSY,		DEVI_BUSY },
11057c478bd9Sstevel@tonic-gate 	    { "MADE_CHILDREN",	DEVI_MADE_CHILDREN,	DEVI_MADE_CHILDREN },
11067c478bd9Sstevel@tonic-gate 	    { "ATTACHED_CHILDREN",
11077c478bd9Sstevel@tonic-gate 				DEVI_ATTACHED_CHILDREN,	DEVI_ATTACHED_CHILDREN},
11087c478bd9Sstevel@tonic-gate 	    { "BRANCH_HELD",	DEVI_BRANCH_HELD,	DEVI_BRANCH_HELD },
1109f4da9be0Scth 	    { "NO_BIND",	DEVI_NO_BIND,		DEVI_NO_BIND },
1110*8451e9c3SGavin Maltby 	    { "DEVI_CACHED_DEVID",
1111*8451e9c3SGavin Maltby 				DEVI_CACHED_DEVID,	DEVI_CACHED_DEVID },
1112f4da9be0Scth 	    { "PHCI_SIGNALS_VHCI",
1113f4da9be0Scth 				DEVI_PHCI_SIGNALS_VHCI,
1114f4da9be0Scth 				DEVI_PHCI_SIGNALS_VHCI },
1115f4da9be0Scth 	    { "REBIND",		DEVI_REBIND,		DEVI_REBIND },
11167c478bd9Sstevel@tonic-gate 	    { NULL,		0,			0 }
11177c478bd9Sstevel@tonic-gate 	};
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	data.di_flags = DEVINFO_VERBOSE;
11207c478bd9Sstevel@tonic-gate 	data.di_base = addr;
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
11237c478bd9Sstevel@tonic-gate 	    'q', MDB_OPT_CLRBITS, DEVINFO_VERBOSE, &data.di_flags,
11247c478bd9Sstevel@tonic-gate 	    's', MDB_OPT_SETBITS, DEVINFO_SUMMARY, &data.di_flags, NULL)
11257c478bd9Sstevel@tonic-gate 	    != argc)
11267c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
11297c478bd9Sstevel@tonic-gate 		mdb_warn(
11307c478bd9Sstevel@tonic-gate 		    "devinfo doesn't give global information (try prtconf)\n");
11317c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
11327c478bd9Sstevel@tonic-gate 	}
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && data.di_flags & DEVINFO_SUMMARY)
11357c478bd9Sstevel@tonic-gate 		mdb_printf(
11367c478bd9Sstevel@tonic-gate 		    "%-?s %5s %?s %-20s %-s\n"
11377c478bd9Sstevel@tonic-gate 		    "%-?s %5s %?s %-20s %-s\n"
11387c478bd9Sstevel@tonic-gate 		    "%<u>%-?s %5s %?s %-20s %-15s%</u>\n",
11397c478bd9Sstevel@tonic-gate 		    "DEVINFO", "MAJ",  "REFCNT",   "NODENAME", "NODESTATE",
11407c478bd9Sstevel@tonic-gate 		    "",        "INST", "CIRCULAR", "BINDNAME", "STATE",
11417c478bd9Sstevel@tonic-gate 		    "",        "",     "THREAD",   "",         "FLAGS");
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
11447c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read device");
11457c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	if (data.di_flags & DEVINFO_SUMMARY) {
11497c478bd9Sstevel@tonic-gate 		*nodename = '\0';
11507c478bd9Sstevel@tonic-gate 		size = sizeof (nodename);
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 		if ((length = mdb_readstr(tmpstr, size,
11537c478bd9Sstevel@tonic-gate 		    (uintptr_t)devi.devi_node_name)) > 0) {
11547c478bd9Sstevel@tonic-gate 			strcat(nodename, tmpstr);
11557c478bd9Sstevel@tonic-gate 			size -= length;
11567c478bd9Sstevel@tonic-gate 		}
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 		if (devi.devi_addr != NULL && mdb_readstr(tmpstr, size - 1,
11597c478bd9Sstevel@tonic-gate 		    (uintptr_t)devi.devi_addr) > 0) {
11607c478bd9Sstevel@tonic-gate 			strcat(nodename, "@");
11617c478bd9Sstevel@tonic-gate 			strcat(nodename, tmpstr);
11627c478bd9Sstevel@tonic-gate 		}
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 		if (mdb_readstr(bindname, sizeof (bindname),
11657c478bd9Sstevel@tonic-gate 		    (uintptr_t)devi.devi_binding_name) == -1)
11667c478bd9Sstevel@tonic-gate 			*bindname = '\0';
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 		mdb_printf("%0?p %5d %?d %-20s %s\n",
11697c478bd9Sstevel@tonic-gate 		    addr, devi.devi_major, devi.devi_ref, nodename,
11707c478bd9Sstevel@tonic-gate 		    di_state[MIN(devi.devi_node_state + 1, DI_STATE_MAX)]);
11717c478bd9Sstevel@tonic-gate 		mdb_printf("%?s %5d %?d %-20s <%b>\n",
11727c478bd9Sstevel@tonic-gate 		    "", devi.devi_instance, devi.devi_circular, bindname,
11737c478bd9Sstevel@tonic-gate 		    devi.devi_state, devi_state_masks);
11747c478bd9Sstevel@tonic-gate 		mdb_printf("%?s %5s %?p %-20s <%b>\n\n",
11757c478bd9Sstevel@tonic-gate 		    "", "", devi.devi_busy_thread, "",
11767c478bd9Sstevel@tonic-gate 		    devi.devi_flags, devi_flags_masks);
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
11797c478bd9Sstevel@tonic-gate 	} else {
11807c478bd9Sstevel@tonic-gate 		din.din_dev = devi;
11817c478bd9Sstevel@tonic-gate 		din.din_depth = 0;
11827c478bd9Sstevel@tonic-gate 		return (devinfo_print(addr, (struct dev_info *)&din, &data));
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11877c478bd9Sstevel@tonic-gate int
11887c478bd9Sstevel@tonic-gate m2d_walk_dinfo(uintptr_t addr, struct dev_info *di, char *mod_name)
11897c478bd9Sstevel@tonic-gate {
11907c478bd9Sstevel@tonic-gate 	char name[MODMAXNAMELEN];
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, MODMAXNAMELEN,
11937c478bd9Sstevel@tonic-gate 	    (uintptr_t)di->devi_binding_name) == -1) {
11947c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devi_binding_name at %p",
11957c478bd9Sstevel@tonic-gate 		    di->devi_binding_name);
11967c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
11977c478bd9Sstevel@tonic-gate 	}
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	if (strcmp(name, mod_name) == 0)
12007c478bd9Sstevel@tonic-gate 		mdb_printf("%p\n", addr);
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
12037c478bd9Sstevel@tonic-gate }
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12067c478bd9Sstevel@tonic-gate int
12077c478bd9Sstevel@tonic-gate modctl2devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
12087c478bd9Sstevel@tonic-gate {
12097c478bd9Sstevel@tonic-gate 	struct modctl modctl;
12107c478bd9Sstevel@tonic-gate 	char name[MODMAXNAMELEN];
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
12137c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	if (mdb_vread(&modctl, sizeof (modctl), addr) == -1) {
12167c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read modctl at %p", addr);
12177c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
12187c478bd9Sstevel@tonic-gate 	}
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, MODMAXNAMELEN,
12217c478bd9Sstevel@tonic-gate 	    (uintptr_t)modctl.mod_modname) == -1) {
12227c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read modname at %p", modctl.mod_modname);
12237c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
12247c478bd9Sstevel@tonic-gate 	}
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	if (mdb_walk("devinfo", (mdb_walk_cb_t)m2d_walk_dinfo, name) == -1) {
12277c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk devinfo");
12287c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate static int
12357c478bd9Sstevel@tonic-gate major_to_addr(major_t major, uintptr_t *vaddr)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	uint_t devcnt;
12387c478bd9Sstevel@tonic-gate 	uintptr_t devnamesp;
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devcnt, "devcnt") == -1) {
12417c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devcnt'");
12427c478bd9Sstevel@tonic-gate 		return (-1);
12437c478bd9Sstevel@tonic-gate 	}
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devnamesp, "devnamesp") == -1) {
12467c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devnamesp'");
12477c478bd9Sstevel@tonic-gate 		return (-1);
12487c478bd9Sstevel@tonic-gate 	}
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	if (major >= devcnt) {
12517c478bd9Sstevel@tonic-gate 		mdb_warn("%x is out of range [0x0-0x%x]\n", major, devcnt - 1);
12527c478bd9Sstevel@tonic-gate 		return (-1);
12537c478bd9Sstevel@tonic-gate 	}
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	*vaddr = devnamesp + (major * sizeof (struct devnames));
12567c478bd9Sstevel@tonic-gate 	return (0);
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12607c478bd9Sstevel@tonic-gate int
12617c478bd9Sstevel@tonic-gate devnames(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
12627c478bd9Sstevel@tonic-gate {
12637c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t dn_flag_bits[] = {
12647c478bd9Sstevel@tonic-gate 		{ "DN_CONF_PARSED",	DN_CONF_PARSED, DN_CONF_PARSED },
12657c478bd9Sstevel@tonic-gate 		{ "DN_DRIVER_BUSY",	DN_DRIVER_BUSY, DN_DRIVER_BUSY },
12667c478bd9Sstevel@tonic-gate 		{ "DN_DRIVER_HELD",	DN_DRIVER_HELD, DN_DRIVER_HELD },
12677c478bd9Sstevel@tonic-gate 		{ "DN_TAKEN_GETUDEV",	DN_TAKEN_GETUDEV, DN_TAKEN_GETUDEV },
12687c478bd9Sstevel@tonic-gate 		{ "DN_DRIVER_REMOVED",	DN_DRIVER_REMOVED, DN_DRIVER_REMOVED},
12697c478bd9Sstevel@tonic-gate 		{ "DN_FORCE_ATTACH",	DN_FORCE_ATTACH, DN_FORCE_ATTACH},
12707c478bd9Sstevel@tonic-gate 		{ "DN_LEAF_DRIVER",	DN_LEAF_DRIVER, DN_LEAF_DRIVER},
12717c478bd9Sstevel@tonic-gate 		{ "DN_NETWORK_DRIVER",	DN_NETWORK_DRIVER, DN_NETWORK_DRIVER},
12727c478bd9Sstevel@tonic-gate 		{ "DN_NO_AUTODETACH",	DN_NO_AUTODETACH, DN_NO_AUTODETACH },
12736e13b8c3Scth 		{ "DN_GLDV3_DRIVER",	DN_GLDV3_DRIVER, DN_GLDV3_DRIVER},
127452cac543Sramat 		{ "DN_PHCI_DRIVER",	DN_PHCI_DRIVER, DN_PHCI_DRIVER},
1275602ca9eaScth 		{ "DN_OPEN_RETURNS_EINTR", \
1276602ca9eaScth 				DN_OPEN_RETURNS_EINTR, DN_OPEN_RETURNS_EINTR},
1277602ca9eaScth 		{ "DN_SCSI_SIZE_CLEAN",	DN_SCSI_SIZE_CLEAN, DN_SCSI_SIZE_CLEAN},
1278095be824SCathy Zhou 		{ "DN_NETWORK_PHYSDRIVER", \
1279095be824SCathy Zhou 				DN_NETWORK_PHYSDRIVER, DN_NETWORK_PHYSDRIVER},
12807c478bd9Sstevel@tonic-gate 		{ NULL, 0, 0 }
12817c478bd9Sstevel@tonic-gate 	};
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	const mdb_arg_t *argp = NULL;
12847c478bd9Sstevel@tonic-gate 	uint_t opt_v = FALSE, opt_m = FALSE;
12857c478bd9Sstevel@tonic-gate 	major_t major;
12867c478bd9Sstevel@tonic-gate 	size_t i;
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	char name[MODMAXNAMELEN + 1];
12897c478bd9Sstevel@tonic-gate 	struct devnames dn;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	if ((i = mdb_getopts(argc, argv,
12927c478bd9Sstevel@tonic-gate 	    'm', MDB_OPT_SETBITS, TRUE, &opt_m,
12937c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v,
12947c478bd9Sstevel@tonic-gate 	    NULL)) != argc) {
12957c478bd9Sstevel@tonic-gate 		if (argc - i > 1)
12967c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
12977c478bd9Sstevel@tonic-gate 		argp = &argv[i];
12987c478bd9Sstevel@tonic-gate 	}
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	if (opt_m) {
13017c478bd9Sstevel@tonic-gate 		if (!(flags & DCMD_ADDRSPEC))
13027c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 		if (major_to_addr(addr, &addr) == -1)
13057c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	} else if (!(flags & DCMD_ADDRSPEC)) {
13087c478bd9Sstevel@tonic-gate 		if (argp == NULL) {
13097c478bd9Sstevel@tonic-gate 			if (mdb_walk_dcmd("devnames", "devnames", argc, argv)) {
13107c478bd9Sstevel@tonic-gate 				mdb_warn("failed to walk devnames");
13117c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
13127c478bd9Sstevel@tonic-gate 			}
13137c478bd9Sstevel@tonic-gate 			return (DCMD_OK);
13147c478bd9Sstevel@tonic-gate 		}
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
13177c478bd9Sstevel@tonic-gate 			major = (major_t)argp->a_un.a_val;
13187c478bd9Sstevel@tonic-gate 		else
13197c478bd9Sstevel@tonic-gate 			major = (major_t)mdb_strtoull(argp->a_un.a_str);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 		if (major_to_addr(major, &addr) == -1)
13227c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
13237c478bd9Sstevel@tonic-gate 	}
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dn, sizeof (struct devnames), addr) == -1) {
13267c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devnames struct at %p", addr);
13277c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
13287c478bd9Sstevel@tonic-gate 	}
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
13317c478bd9Sstevel@tonic-gate 		if (opt_v)
13327c478bd9Sstevel@tonic-gate 			mdb_printf("%<u>%-16s%</u>\n", "NAME");
13337c478bd9Sstevel@tonic-gate 		else
13347c478bd9Sstevel@tonic-gate 			mdb_printf("%<u>%-16s %-?s%</u>\n", "NAME", "DN_HEAD");
13357c478bd9Sstevel@tonic-gate 	}
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_LOOP) && (dn.dn_name == NULL))
13387c478bd9Sstevel@tonic-gate 		return (DCMD_OK); /* Skip empty slots if we're printing table */
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, sizeof (name), (uintptr_t)dn.dn_name) == -1)
13417c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(name, sizeof (name), "0x%p", dn.dn_name);
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	if (opt_v) {
13447c478bd9Sstevel@tonic-gate 		ddi_prop_list_t prop_list;
13457c478bd9Sstevel@tonic-gate 		mdb_printf("%<b>%-16s%</b>\n", name);
13467c478bd9Sstevel@tonic-gate 		mdb_inc_indent(2);
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 		mdb_printf("          flags %b\n", dn.dn_flags, dn_flag_bits);
13497c478bd9Sstevel@tonic-gate 		mdb_printf("             pl %p\n", (void *)dn.dn_pl);
13507c478bd9Sstevel@tonic-gate 		mdb_printf("           head %p\n", dn.dn_head);
13517c478bd9Sstevel@tonic-gate 		mdb_printf("       instance %d\n", dn.dn_instance);
13527c478bd9Sstevel@tonic-gate 		mdb_printf("         inlist %p\n", dn.dn_inlist);
13537c478bd9Sstevel@tonic-gate 		mdb_printf("global_prop_ptr %p\n", dn.dn_global_prop_ptr);
13547c478bd9Sstevel@tonic-gate 		if (mdb_vread(&prop_list, sizeof (ddi_prop_list_t),
13557c478bd9Sstevel@tonic-gate 		    (uintptr_t)dn.dn_global_prop_ptr) != -1) {
13567c478bd9Sstevel@tonic-gate 			devinfo_print_props(NULL, prop_list.prop_list);
13577c478bd9Sstevel@tonic-gate 		}
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 		mdb_dec_indent(2);
13607c478bd9Sstevel@tonic-gate 	} else
13617c478bd9Sstevel@tonic-gate 		mdb_printf("%-16s %-?p\n", name, dn.dn_head);
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
13647c478bd9Sstevel@tonic-gate }
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate /*ARGSUSED*/
13677c478bd9Sstevel@tonic-gate int
13687c478bd9Sstevel@tonic-gate name2major(uintptr_t vaddr, uint_t flags, int argc, const mdb_arg_t *argv)
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate 	major_t major;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC)
13737c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
13767c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	if (mdb_name_to_major(argv->a_un.a_str, &major) != 0) {
13797c478bd9Sstevel@tonic-gate 		mdb_warn("failed to convert name to major number\n");
13807c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
13817c478bd9Sstevel@tonic-gate 	}
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	mdb_printf("0x%x\n", major);
13847c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate /*
13887c478bd9Sstevel@tonic-gate  * Get a numerical argument of a dcmd from addr if an address is specified
13897c478bd9Sstevel@tonic-gate  * or from argv if no address is specified. Return the argument in ret.
13907c478bd9Sstevel@tonic-gate  */
13917c478bd9Sstevel@tonic-gate static int
13927c478bd9Sstevel@tonic-gate getarg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
13937c478bd9Sstevel@tonic-gate     uintptr_t *ret)
13947c478bd9Sstevel@tonic-gate {
13957c478bd9Sstevel@tonic-gate 	if (argc == 0 && (flags & DCMD_ADDRSPEC)) {
13967c478bd9Sstevel@tonic-gate 		*ret = addr;
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	} else if (argc == 1 && !(flags & DCMD_ADDRSPEC)) {
13997c478bd9Sstevel@tonic-gate 		*ret = (argv[0].a_type == MDB_TYPE_IMMEDIATE) ?
14007c478bd9Sstevel@tonic-gate 		    (uintptr_t)argv[0].a_un.a_val :
14017c478bd9Sstevel@tonic-gate 		    (uintptr_t)mdb_strtoull(argv->a_un.a_str);
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	} else {
14047c478bd9Sstevel@tonic-gate 		return (-1);
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	return (0);
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14117c478bd9Sstevel@tonic-gate int
14127c478bd9Sstevel@tonic-gate major2name(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
14137c478bd9Sstevel@tonic-gate {
14147c478bd9Sstevel@tonic-gate 	uintptr_t major;
14157c478bd9Sstevel@tonic-gate 	const char *name;
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	if (getarg(addr, flags, argc, argv, &major) < 0)
14187c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	if ((name = mdb_major_to_name((major_t)major)) == NULL) {
14217c478bd9Sstevel@tonic-gate 		mdb_warn("failed to convert major number to name\n");
14227c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
14237c478bd9Sstevel@tonic-gate 	}
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	mdb_printf("%s\n", name);
14267c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
14277c478bd9Sstevel@tonic-gate }
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14307c478bd9Sstevel@tonic-gate int
14317c478bd9Sstevel@tonic-gate dev2major(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
14327c478bd9Sstevel@tonic-gate {
14337c478bd9Sstevel@tonic-gate 	uintptr_t dev;
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	if (getarg(addr, flags, argc, argv, &dev) < 0)
14367c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
14397c478bd9Sstevel@tonic-gate 		mdb_printf("%x\n", getmajor(dev));
14407c478bd9Sstevel@tonic-gate 	else
14417c478bd9Sstevel@tonic-gate 		mdb_printf("0x%x (0t%d)\n", getmajor(dev), getmajor(dev));
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
14447c478bd9Sstevel@tonic-gate }
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14477c478bd9Sstevel@tonic-gate int
14487c478bd9Sstevel@tonic-gate dev2minor(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
14497c478bd9Sstevel@tonic-gate {
14507c478bd9Sstevel@tonic-gate 	uintptr_t dev;
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 	if (getarg(addr, flags, argc, argv, &dev) < 0)
14537c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
14567c478bd9Sstevel@tonic-gate 		mdb_printf("%x\n", getminor(dev));
14577c478bd9Sstevel@tonic-gate 	else
14587c478bd9Sstevel@tonic-gate 		mdb_printf("0x%x (0t%d)\n", getminor(dev), getminor(dev));
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14647c478bd9Sstevel@tonic-gate int
14657c478bd9Sstevel@tonic-gate devt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
14667c478bd9Sstevel@tonic-gate {
14677c478bd9Sstevel@tonic-gate 	uintptr_t dev;
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	if (getarg(addr, flags, argc, argv, &dev) < 0)
14707c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
14737c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%10s%</u>  %<u>%10s%</u>\n", "MAJOR",
14747c478bd9Sstevel@tonic-gate 		    "MINOR");
14757c478bd9Sstevel@tonic-gate 	}
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	mdb_printf("%10d  %10d\n", getmajor(dev), getminor(dev));
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
14807c478bd9Sstevel@tonic-gate }
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14837c478bd9Sstevel@tonic-gate int
14847c478bd9Sstevel@tonic-gate softstate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate 	uintptr_t statep;
14877c478bd9Sstevel@tonic-gate 	int instance;
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	if (argc != 1) {
14917c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
14927c478bd9Sstevel@tonic-gate 	}
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	if (argv[0].a_type == MDB_TYPE_IMMEDIATE)
14957c478bd9Sstevel@tonic-gate 		instance = argv[0].a_un.a_val;
14967c478bd9Sstevel@tonic-gate 	else
14977c478bd9Sstevel@tonic-gate 		instance = mdb_strtoull(argv->a_un.a_str);
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	if (mdb_get_soft_state_byaddr(addr, instance, &statep, NULL, 0) == -1) {
15007c478bd9Sstevel@tonic-gate 		if (errno == ENOENT) {
15017c478bd9Sstevel@tonic-gate 			mdb_warn("instance %d unused\n", instance);
15027c478bd9Sstevel@tonic-gate 		} else {
15037c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't determine softstate for "
15047c478bd9Sstevel@tonic-gate 			    "instance %d", instance);
15057c478bd9Sstevel@tonic-gate 		}
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
15087c478bd9Sstevel@tonic-gate 	}
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	mdb_printf("%p\n", statep);
15117c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate /*
15157c478bd9Sstevel@tonic-gate  * Walker for all possible pointers to a driver state struct in an
15167c478bd9Sstevel@tonic-gate  * i_ddi_soft_state instance chain.  Returns all non-NULL pointers.
15177c478bd9Sstevel@tonic-gate  */
15187c478bd9Sstevel@tonic-gate typedef struct soft_state_walk {
15197c478bd9Sstevel@tonic-gate 	struct i_ddi_soft_state	ssw_ss;	/* Local copy of i_ddi_soft_state */
15207c478bd9Sstevel@tonic-gate 	void		**ssw_pointers;	/* to driver state structs */
15217c478bd9Sstevel@tonic-gate 	uint_t		ssw_index;	/* array entry we're using */
15227c478bd9Sstevel@tonic-gate } soft_state_walk_t;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate int
15257c478bd9Sstevel@tonic-gate soft_state_walk_init(mdb_walk_state_t *wsp)
15267c478bd9Sstevel@tonic-gate {
15277c478bd9Sstevel@tonic-gate 	soft_state_walk_t *sst;
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
15317c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	sst = mdb_zalloc(sizeof (soft_state_walk_t), UM_SLEEP|UM_GC);
15347c478bd9Sstevel@tonic-gate 	wsp->walk_data = sst;
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	if (mdb_vread(&(sst->ssw_ss), sizeof (sst->ssw_ss), wsp->walk_addr) !=
15387c478bd9Sstevel@tonic-gate 	    sizeof (sst->ssw_ss)) {
15397c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read i_ddi_soft_state at %p",
15407c478bd9Sstevel@tonic-gate 		    wsp->walk_addr);
15417c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
15427c478bd9Sstevel@tonic-gate 	}
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	/* Read array of pointers to state structs into local storage. */
15467c478bd9Sstevel@tonic-gate 	sst->ssw_pointers = mdb_alloc((sst->ssw_ss.n_items * sizeof (void *)),
15477c478bd9Sstevel@tonic-gate 	    UM_SLEEP|UM_GC);
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	if (mdb_vread(sst->ssw_pointers, (sst->ssw_ss.n_items *
15507c478bd9Sstevel@tonic-gate 	    sizeof (void *)), (uintptr_t)sst->ssw_ss.array) !=
15517c478bd9Sstevel@tonic-gate 	    (sst->ssw_ss.n_items * sizeof (void *))) {
15527c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read i_ddi_soft_state at %p",
15537c478bd9Sstevel@tonic-gate 		    wsp->walk_addr);
15547c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
15557c478bd9Sstevel@tonic-gate 	}
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	sst->ssw_index = 0;
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
15607c478bd9Sstevel@tonic-gate }
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate int
15637c478bd9Sstevel@tonic-gate soft_state_walk_step(mdb_walk_state_t *wsp)
15647c478bd9Sstevel@tonic-gate {
15657c478bd9Sstevel@tonic-gate 	soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data;
15667c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	/*
15707c478bd9Sstevel@tonic-gate 	 * If the entry indexed has a valid pointer to a soft state struct,
15717c478bd9Sstevel@tonic-gate 	 * invoke caller's callback func.
15727c478bd9Sstevel@tonic-gate 	 */
15737c478bd9Sstevel@tonic-gate 	if (sst->ssw_pointers[sst->ssw_index] != NULL) {
15747c478bd9Sstevel@tonic-gate 		status = wsp->walk_callback(
15757c478bd9Sstevel@tonic-gate 		    (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL,
15767c478bd9Sstevel@tonic-gate 		    wsp->walk_cbdata);
15777c478bd9Sstevel@tonic-gate 	}
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	sst->ssw_index += 1;
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	if (sst->ssw_index == sst->ssw_ss.n_items)
15827c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	return (status);
15857c478bd9Sstevel@tonic-gate }
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate int
15887c478bd9Sstevel@tonic-gate soft_state_all_walk_step(mdb_walk_state_t *wsp)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate 	soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data;
15917c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(
15957c478bd9Sstevel@tonic-gate 	    (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL,
15967c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	sst->ssw_index += 1;
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	if (sst->ssw_index == sst->ssw_ss.n_items)
16017c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	return (status);
16047c478bd9Sstevel@tonic-gate }
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16077c478bd9Sstevel@tonic-gate int
16087c478bd9Sstevel@tonic-gate devbindings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
16097c478bd9Sstevel@tonic-gate {
16107c478bd9Sstevel@tonic-gate 	const mdb_arg_t *arg;
16117c478bd9Sstevel@tonic-gate 	struct devnames dn;
16127c478bd9Sstevel@tonic-gate 	uintptr_t dn_addr;
16137c478bd9Sstevel@tonic-gate 	major_t major;
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) && argc < 1)
16167c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
16197c478bd9Sstevel@tonic-gate 		/*
16207c478bd9Sstevel@tonic-gate 		 * If there's an address, then it's a major number
16217c478bd9Sstevel@tonic-gate 		 */
16227c478bd9Sstevel@tonic-gate 		major = addr;
16237c478bd9Sstevel@tonic-gate 	} else {
16247c478bd9Sstevel@tonic-gate 		/*
16257c478bd9Sstevel@tonic-gate 		 * We interpret the last argument. Any other arguments are
16267c478bd9Sstevel@tonic-gate 		 * forwarded to "devinfo"
16277c478bd9Sstevel@tonic-gate 		 */
16287c478bd9Sstevel@tonic-gate 		arg = &argv[argc - 1];
16297c478bd9Sstevel@tonic-gate 		argc--;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 		if (arg->a_type == MDB_TYPE_IMMEDIATE) {
16327c478bd9Sstevel@tonic-gate 			major = (uintptr_t)arg->a_un.a_val;
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 		} else if (arg->a_un.a_str[0] == '-') {
16357c478bd9Sstevel@tonic-gate 			/* the argument shouldn't be an option */
16367c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 		} else if (isdigit(arg->a_un.a_str[0])) {
16397c478bd9Sstevel@tonic-gate 			major = (uintptr_t)mdb_strtoull(arg->a_un.a_str);
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 		} else {
16427c478bd9Sstevel@tonic-gate 			if (mdb_name_to_major(arg->a_un.a_str, &major) != 0) {
16437c478bd9Sstevel@tonic-gate 				mdb_warn("failed to get major number for %s\n",
16447c478bd9Sstevel@tonic-gate 				    arg->a_un.a_str);
16457c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
16467c478bd9Sstevel@tonic-gate 			}
16477c478bd9Sstevel@tonic-gate 		}
16487c478bd9Sstevel@tonic-gate 	}
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	if (major_to_addr(major, &dn_addr) != 0)
16517c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dn, sizeof (struct devnames), dn_addr) == -1) {
16547c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devnames array at %p", dn_addr);
16557c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
16567c478bd9Sstevel@tonic-gate 	}
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	if (mdb_pwalk_dcmd("devi_next", "devinfo", argc, argv,
16597c478bd9Sstevel@tonic-gate 	    (uintptr_t)dn.dn_head) != 0) {
16607c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk the devinfo chain at %p", dn.dn_head);
16617c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
16627c478bd9Sstevel@tonic-gate 	}
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
16657c478bd9Sstevel@tonic-gate }
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate /*
16687c478bd9Sstevel@tonic-gate  * walk binding hashtable (as of of driver names (e.g., mb_hashtab))
16697c478bd9Sstevel@tonic-gate  */
16707c478bd9Sstevel@tonic-gate int
16717c478bd9Sstevel@tonic-gate binding_hash_walk_init(mdb_walk_state_t *wsp)
16727c478bd9Sstevel@tonic-gate {
16737c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
16747c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (void *) * MOD_BIND_HASHSIZE,
16777c478bd9Sstevel@tonic-gate 	    UM_SLEEP|UM_GC);
16787c478bd9Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (void *) * MOD_BIND_HASHSIZE,
16797c478bd9Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
16807c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read mb_hashtab");
16817c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
16827c478bd9Sstevel@tonic-gate 	}
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	wsp->walk_arg = 0;	/* index into mb_hashtab array to start */
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
16877c478bd9Sstevel@tonic-gate }
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate int
16907c478bd9Sstevel@tonic-gate binding_hash_walk_step(mdb_walk_state_t *wsp)
16917c478bd9Sstevel@tonic-gate {
16927c478bd9Sstevel@tonic-gate 	int		status;
16937c478bd9Sstevel@tonic-gate 	uintptr_t	bind_p;
16947c478bd9Sstevel@tonic-gate 	struct bind	bind;
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	/*
16987c478bd9Sstevel@tonic-gate 	 * Walk the singly-linked list of struct bind
16997c478bd9Sstevel@tonic-gate 	 */
17007c478bd9Sstevel@tonic-gate 	bind_p = ((uintptr_t *)wsp->walk_data)[(ulong_t)wsp->walk_arg];
17017c478bd9Sstevel@tonic-gate 	while (bind_p != NULL) {
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate 		if (mdb_vread(&bind, sizeof (bind), bind_p) == -1) {
17047c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read bind struct at %p",
17057c478bd9Sstevel@tonic-gate 			    wsp->walk_addr);
17067c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
17077c478bd9Sstevel@tonic-gate 		}
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 		if ((status = wsp->walk_callback(bind_p, &bind,
17107c478bd9Sstevel@tonic-gate 		    wsp->walk_cbdata)) != WALK_NEXT) {
17117c478bd9Sstevel@tonic-gate 			return (status);
17127c478bd9Sstevel@tonic-gate 		}
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 		bind_p = (uintptr_t)bind.b_next;
17157c478bd9Sstevel@tonic-gate 	}
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 	wsp->walk_arg = (void *)((char *)wsp->walk_arg + 1);
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	if (wsp->walk_arg == (void *)(MOD_BIND_HASHSIZE - 1))
17207c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
17237c478bd9Sstevel@tonic-gate }
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17267c478bd9Sstevel@tonic-gate int
17277c478bd9Sstevel@tonic-gate binding_hash_entry(uintptr_t addr, uint_t flags, int argc,
17287c478bd9Sstevel@tonic-gate     const mdb_arg_t *argv)
17297c478bd9Sstevel@tonic-gate {
17307c478bd9Sstevel@tonic-gate 	struct bind 	bind;
17317c478bd9Sstevel@tonic-gate 	/* Arbitrary lengths based on output format below */
1732f4da9be0Scth 	char name[MAXPATHLEN] = "???";
1733f4da9be0Scth 	char bind_name[MAXPATHLEN] = "<null>";
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == NULL)
17367c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	/* Allow null addresses to be passed (as from a walker) */
17397c478bd9Sstevel@tonic-gate 	if (addr == NULL)
17407c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 	if (mdb_vread(&bind, sizeof (bind), addr) == -1) {
17437c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read struct bind at %p", addr);
17447c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
17457c478bd9Sstevel@tonic-gate 	}
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
1748f4da9be0Scth 		mdb_printf("%<u>%?s% %-5s %s%</u>\n",
1749f4da9be0Scth 		    "NEXT", "MAJOR", "NAME(S)");
17507c478bd9Sstevel@tonic-gate 	}
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, sizeof (name), (uintptr_t)bind.b_name) == -1)
17537c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'name'");
17547c478bd9Sstevel@tonic-gate 
1755f4da9be0Scth 	/* There may be bind_name, so this may fail */
1756f4da9be0Scth 	if (mdb_readstr(bind_name, sizeof (bind_name),
1757f4da9be0Scth 	    (uintptr_t)bind.b_bind_name) == -1) {
1758f4da9be0Scth 		mdb_printf("%?p %5d %s\n",
1759f4da9be0Scth 		    bind.b_next, bind.b_num, name);
1760f4da9be0Scth 	} else {
1761f4da9be0Scth 		mdb_printf("%?p %5d %s %s\n",
1762f4da9be0Scth 		    bind.b_next, bind.b_num, name, bind_name);
1763f4da9be0Scth 	}
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
17667c478bd9Sstevel@tonic-gate }
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate typedef struct devinfo_audit_log_walk_data {
17697c478bd9Sstevel@tonic-gate 	devinfo_audit_t dil_buf;	/* buffer of last entry */
17707c478bd9Sstevel@tonic-gate 	uintptr_t dil_base;		/* starting address of log buffer */
17717c478bd9Sstevel@tonic-gate 	int dil_max;			/* maximum index */
17727c478bd9Sstevel@tonic-gate 	int dil_start;			/* starting index */
17737c478bd9Sstevel@tonic-gate 	int dil_index;			/* current walking index */
17747c478bd9Sstevel@tonic-gate } devinfo_audit_log_walk_data_t;
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate int
17777c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_init(mdb_walk_state_t *wsp)
17787c478bd9Sstevel@tonic-gate {
17797c478bd9Sstevel@tonic-gate 	devinfo_log_header_t header;
17807c478bd9Sstevel@tonic-gate 	devinfo_audit_log_walk_data_t *dil;
17817c478bd9Sstevel@tonic-gate 	uintptr_t devinfo_audit_log;
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 	/* read in devinfo_log_header structure */
17847c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devinfo_audit_log, "devinfo_audit_log") == -1) {
17857c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devinfo_audit_log'");
17867c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
17877c478bd9Sstevel@tonic-gate 	}
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	if (mdb_vread(&header, sizeof (devinfo_log_header_t),
17907c478bd9Sstevel@tonic-gate 	    devinfo_audit_log) == -1) {
17917c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devinfo_log_header at %p",
17927c478bd9Sstevel@tonic-gate 		    devinfo_audit_log);
17937c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
17947c478bd9Sstevel@tonic-gate 	}
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 	dil = mdb_zalloc(sizeof (devinfo_audit_log_walk_data_t), UM_SLEEP);
17977c478bd9Sstevel@tonic-gate 	wsp->walk_data = dil;
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	dil->dil_start = dil->dil_index = header.dh_curr;
18007c478bd9Sstevel@tonic-gate 	dil->dil_max = header.dh_max;
18017c478bd9Sstevel@tonic-gate 	if (dil->dil_start < 0)		/* no log entries */
18027c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 	dil->dil_base = devinfo_audit_log +
18057c478bd9Sstevel@tonic-gate 	    offsetof(devinfo_log_header_t, dh_entry);
18067c478bd9Sstevel@tonic-gate 	wsp->walk_addr = dil->dil_base +
18077c478bd9Sstevel@tonic-gate 	    dil->dil_index * sizeof (devinfo_audit_t);
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
18107c478bd9Sstevel@tonic-gate }
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate int
18137c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_step(mdb_walk_state_t *wsp)
18147c478bd9Sstevel@tonic-gate {
18157c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
18167c478bd9Sstevel@tonic-gate 	devinfo_audit_log_walk_data_t *dil = wsp->walk_data;
18177c478bd9Sstevel@tonic-gate 	devinfo_audit_t *da = &dil->dil_buf;
18187c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	/* read in current entry and invoke callback */
18217c478bd9Sstevel@tonic-gate 	if (addr == NULL)
18227c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dil->dil_buf, sizeof (devinfo_audit_t), addr) == -1) {
18257c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo_audit at %p", addr);
18267c478bd9Sstevel@tonic-gate 		status = WALK_DONE;
18277c478bd9Sstevel@tonic-gate 	}
18287c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, da, wsp->walk_cbdata);
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	/* step to the previous log entry in time */
18317c478bd9Sstevel@tonic-gate 	if (--dil->dil_index < 0)
18327c478bd9Sstevel@tonic-gate 		dil->dil_index += dil->dil_max;
18337c478bd9Sstevel@tonic-gate 	if (dil->dil_index == dil->dil_start) {
18347c478bd9Sstevel@tonic-gate 		wsp->walk_addr = NULL;
18357c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
18367c478bd9Sstevel@tonic-gate 	}
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	wsp->walk_addr = dil->dil_base +
18397c478bd9Sstevel@tonic-gate 	    dil->dil_index * sizeof (devinfo_audit_t);
18407c478bd9Sstevel@tonic-gate 	return (status);
18417c478bd9Sstevel@tonic-gate }
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate void
18447c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_fini(mdb_walk_state_t *wsp)
18457c478bd9Sstevel@tonic-gate {
18467c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (devinfo_audit_log_walk_data_t));
18477c478bd9Sstevel@tonic-gate }
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate /*
18507c478bd9Sstevel@tonic-gate  * display devinfo_audit_t stack trace
18517c478bd9Sstevel@tonic-gate  */
18527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18537c478bd9Sstevel@tonic-gate int
18547c478bd9Sstevel@tonic-gate devinfo_audit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
18557c478bd9Sstevel@tonic-gate {
18567c478bd9Sstevel@tonic-gate 	uint_t verbose = FALSE;
18577c478bd9Sstevel@tonic-gate 	devinfo_audit_t da;
18587c478bd9Sstevel@tonic-gate 	int i, depth;
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
18617c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
18647c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
18657c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
18667c478bd9Sstevel@tonic-gate 
18677c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
18687c478bd9Sstevel@tonic-gate 		mdb_printf(" %-?s %16s %-?s %-?s %5s\n",
18697c478bd9Sstevel@tonic-gate 		    "AUDIT", "TIMESTAMP", "THREAD", "DEVINFO", "STATE");
18707c478bd9Sstevel@tonic-gate 	}
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	if (mdb_vread(&da, sizeof (da), addr) == -1) {
18737c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devinfo_audit at %p", addr);
18747c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
18757c478bd9Sstevel@tonic-gate 	}
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	mdb_printf(" %0?p %16llx %0?p %0?p %s\n",
18787c478bd9Sstevel@tonic-gate 	    addr, da.da_timestamp, da.da_thread, da.da_devinfo,
18797c478bd9Sstevel@tonic-gate 	    di_state[MIN(da.da_node_state + 1, DI_STATE_MAX)]);
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	if (!verbose)
18827c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	mdb_inc_indent(4);
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 	/*
18877c478bd9Sstevel@tonic-gate 	 * Guard against bogus da_depth in case the devinfo_audit_t
18887c478bd9Sstevel@tonic-gate 	 * is corrupt or the address does not really refer to a
18897c478bd9Sstevel@tonic-gate 	 * devinfo_audit_t.
18907c478bd9Sstevel@tonic-gate 	 */
18917c478bd9Sstevel@tonic-gate 	depth = MIN(da.da_depth, DDI_STACK_DEPTH);
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
18947c478bd9Sstevel@tonic-gate 		mdb_printf("%a\n", da.da_stack[i]);
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
18977c478bd9Sstevel@tonic-gate 	mdb_dec_indent(4);
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
19007c478bd9Sstevel@tonic-gate }
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate int
19037c478bd9Sstevel@tonic-gate devinfo_audit_log(uintptr_t addr, uint_t flags, int argc,
19047c478bd9Sstevel@tonic-gate     const mdb_arg_t *argv)
19057c478bd9Sstevel@tonic-gate {
19067c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC)
19077c478bd9Sstevel@tonic-gate 		return (devinfo_audit(addr, flags, argc, argv));
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	(void) mdb_walk_dcmd("devinfo_audit_log", "devinfo_audit", argc, argv);
19107c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
19117c478bd9Sstevel@tonic-gate }
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate typedef struct devinfo_audit_node_walk_data {
19147c478bd9Sstevel@tonic-gate 	devinfo_audit_t dih_buf;	/* buffer of last entry */
19157c478bd9Sstevel@tonic-gate 	uintptr_t dih_dip;		/* address of dev_info */
19167c478bd9Sstevel@tonic-gate 	int dih_on_devinfo;		/* devi_audit on dev_info struct */
19177c478bd9Sstevel@tonic-gate } devinfo_audit_node_walk_data_t;
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate int
19207c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_init(mdb_walk_state_t *wsp)
19217c478bd9Sstevel@tonic-gate {
19227c478bd9Sstevel@tonic-gate 	devinfo_audit_node_walk_data_t *dih;
19237c478bd9Sstevel@tonic-gate 	devinfo_audit_t *da;
19247c478bd9Sstevel@tonic-gate 	struct dev_info devi;
19257c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 	/* read in devinfo structure */
19287c478bd9Sstevel@tonic-gate 	if (mdb_vread(&devi, sizeof (struct dev_info), addr) == -1) {
19297c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read dev_info at %p", addr);
19307c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
19317c478bd9Sstevel@tonic-gate 	}
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	dih = mdb_zalloc(sizeof (devinfo_audit_node_walk_data_t), UM_SLEEP);
19347c478bd9Sstevel@tonic-gate 	wsp->walk_data = dih;
19357c478bd9Sstevel@tonic-gate 	da = &dih->dih_buf;
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 	/* read in devi_audit structure */
19387c478bd9Sstevel@tonic-gate 	if (mdb_vread(da, sizeof (devinfo_audit_t), (uintptr_t)devi.devi_audit)
19397c478bd9Sstevel@tonic-gate 	    == -1) {
19407c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devi_audit at %p", devi.devi_audit);
19417c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
19427c478bd9Sstevel@tonic-gate 	}
19437c478bd9Sstevel@tonic-gate 	dih->dih_dip = addr;
19447c478bd9Sstevel@tonic-gate 	dih->dih_on_devinfo = 1;
19457c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)devi.devi_audit;
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
19487c478bd9Sstevel@tonic-gate }
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate int
19517c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_step(mdb_walk_state_t *wsp)
19527c478bd9Sstevel@tonic-gate {
19537c478bd9Sstevel@tonic-gate 	uintptr_t addr;
19547c478bd9Sstevel@tonic-gate 	devinfo_audit_node_walk_data_t *dih = wsp->walk_data;
19557c478bd9Sstevel@tonic-gate 	devinfo_audit_t *da = &dih->dih_buf;
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
19587c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
19597c478bd9Sstevel@tonic-gate 	(void) wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata);
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate skip:
19627c478bd9Sstevel@tonic-gate 	/* read in previous entry */
19637c478bd9Sstevel@tonic-gate 	if ((addr = (uintptr_t)da->da_lastlog) == 0)
19647c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dih->dih_buf, sizeof (devinfo_audit_t), addr) == -1) {
19677c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo_audit at %p", addr);
19687c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
19697c478bd9Sstevel@tonic-gate 	}
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	/* check if last log was over-written */
19727c478bd9Sstevel@tonic-gate 	if ((uintptr_t)da->da_devinfo != dih->dih_dip)
19737c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate 	/*
19767c478bd9Sstevel@tonic-gate 	 * skip the first common log entry, which is a duplicate of
19777c478bd9Sstevel@tonic-gate 	 * the devi_audit buffer on the dev_info structure
19787c478bd9Sstevel@tonic-gate 	 */
19797c478bd9Sstevel@tonic-gate 	if (dih->dih_on_devinfo) {
19807c478bd9Sstevel@tonic-gate 		dih->dih_on_devinfo = 0;
19817c478bd9Sstevel@tonic-gate 		goto skip;
19827c478bd9Sstevel@tonic-gate 	}
19837c478bd9Sstevel@tonic-gate 	wsp->walk_addr = addr;
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
19867c478bd9Sstevel@tonic-gate }
19877c478bd9Sstevel@tonic-gate 
19887c478bd9Sstevel@tonic-gate void
19897c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_fini(mdb_walk_state_t *wsp)
19907c478bd9Sstevel@tonic-gate {
19917c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (devinfo_audit_node_walk_data_t));
19927c478bd9Sstevel@tonic-gate }
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate int
19957c478bd9Sstevel@tonic-gate devinfo_audit_node(uintptr_t addr, uint_t flags, int argc,
19967c478bd9Sstevel@tonic-gate     const mdb_arg_t *argv)
19977c478bd9Sstevel@tonic-gate {
19987c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
19997c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 	(void) mdb_pwalk_dcmd("devinfo_audit_node", "devinfo_audit",
20027c478bd9Sstevel@tonic-gate 	    argc, argv, addr);
20037c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
20047c478bd9Sstevel@tonic-gate }
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate /*
20077c478bd9Sstevel@tonic-gate  * mdb support for per-devinfo fault management data
20087c478bd9Sstevel@tonic-gate  */
20097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20107c478bd9Sstevel@tonic-gate int
20117c478bd9Sstevel@tonic-gate devinfo_fm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
20127c478bd9Sstevel@tonic-gate {
20137c478bd9Sstevel@tonic-gate 	struct dev_info devi;
20147c478bd9Sstevel@tonic-gate 	struct i_ddi_fmhdl fhdl;
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
20177c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
2020a5667d81SCheng Sean Ye 		mdb_printf("%<u>%?s IPL CAPS DROP FMCFULL FMCMISS ACCERR "
2021a5667d81SCheng Sean Ye 		    "DMAERR %?s %?s%</u>\n", "ADDR", "DMACACHE", "ACCCACHE");
20227c478bd9Sstevel@tonic-gate 	}
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
20257c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo struct at %p", addr);
20267c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
20277c478bd9Sstevel@tonic-gate 	}
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate 	if (mdb_vread(&fhdl, sizeof (fhdl), (uintptr_t)devi.devi_fmhdl) == -1) {
20307c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo fm struct at %p",
20317c478bd9Sstevel@tonic-gate 		    (uintptr_t)devi.devi_fmhdl);
20327c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
20337c478bd9Sstevel@tonic-gate 	}
20347c478bd9Sstevel@tonic-gate 
2035a5667d81SCheng Sean Ye 	mdb_printf("%?p %3u %c%c%c%c %4llu %7llu %7llu %6llu %6llu %?p %?p\n",
20367c478bd9Sstevel@tonic-gate 	    (uintptr_t)devi.devi_fmhdl, fhdl.fh_ibc,
20377c478bd9Sstevel@tonic-gate 	    (DDI_FM_EREPORT_CAP(fhdl.fh_cap) ? 'E' : '-'),
20387c478bd9Sstevel@tonic-gate 	    (DDI_FM_ERRCB_CAP(fhdl.fh_cap) ? 'C' : '-'),
20397c478bd9Sstevel@tonic-gate 	    (DDI_FM_ACC_ERR_CAP(fhdl.fh_cap) ? 'A' : '-'),
20407c478bd9Sstevel@tonic-gate 	    (DDI_FM_DMA_ERR_CAP(fhdl.fh_cap) ? 'D' : '-'),
20417c478bd9Sstevel@tonic-gate 	    fhdl.fh_kstat.fek_erpt_dropped.value.ui64,
20427c478bd9Sstevel@tonic-gate 	    fhdl.fh_kstat.fek_fmc_full.value.ui64,
2043a5667d81SCheng Sean Ye 	    fhdl.fh_kstat.fek_fmc_miss.value.ui64,
20447c478bd9Sstevel@tonic-gate 	    fhdl.fh_kstat.fek_acc_err.value.ui64,
20457c478bd9Sstevel@tonic-gate 	    fhdl.fh_kstat.fek_dma_err.value.ui64,
20467c478bd9Sstevel@tonic-gate 	    fhdl.fh_dma_cache, fhdl.fh_acc_cache);
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
20507c478bd9Sstevel@tonic-gate }
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20537c478bd9Sstevel@tonic-gate int
20547c478bd9Sstevel@tonic-gate devinfo_fmce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
20557c478bd9Sstevel@tonic-gate {
20567c478bd9Sstevel@tonic-gate 	struct i_ddi_fmc_entry fce;
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
20597c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
2062a5667d81SCheng Sean Ye 		mdb_printf("%<u>%?s %?s %?s%</u>\n", "ADDR",
20637c478bd9Sstevel@tonic-gate 		    "RESOURCE", "BUS_SPECIFIC");
20647c478bd9Sstevel@tonic-gate 	}
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 	if (mdb_vread(&fce, sizeof (fce), addr) == -1) {
20677c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read fm cache struct at %p", addr);
20687c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
20697c478bd9Sstevel@tonic-gate 	}
20707c478bd9Sstevel@tonic-gate 
2071a5667d81SCheng Sean Ye 	mdb_printf("%?p %?p %?p\n",
20727c478bd9Sstevel@tonic-gate 	    (uintptr_t)addr, fce.fce_resource, fce.fce_bus_specific);
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
20767c478bd9Sstevel@tonic-gate }
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate int
20797c478bd9Sstevel@tonic-gate devinfo_fmc_walk_init(mdb_walk_state_t *wsp)
20807c478bd9Sstevel@tonic-gate {
20817c478bd9Sstevel@tonic-gate 	struct i_ddi_fmc fec;
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
20847c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	if (mdb_vread(&fec, sizeof (fec), wsp->walk_addr) == -1) {
20877c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read fm cache at %p", wsp->walk_addr);
20887c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
20897c478bd9Sstevel@tonic-gate 	}
20907c478bd9Sstevel@tonic-gate 
2091a5667d81SCheng Sean Ye 	if (fec.fc_head == NULL)
20927c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
20937c478bd9Sstevel@tonic-gate 
2094a5667d81SCheng Sean Ye 	wsp->walk_addr = (uintptr_t)fec.fc_head;
20957c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
20967c478bd9Sstevel@tonic-gate }
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate int
20997c478bd9Sstevel@tonic-gate devinfo_fmc_walk_step(mdb_walk_state_t *wsp)
21007c478bd9Sstevel@tonic-gate {
21017c478bd9Sstevel@tonic-gate 	int status;
21027c478bd9Sstevel@tonic-gate 	struct i_ddi_fmc_entry fe;
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	if (mdb_vread(&fe, sizeof (fe), wsp->walk_addr) == -1) {
21057c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read active fm cache entry at %p",
21067c478bd9Sstevel@tonic-gate 		    wsp->walk_addr);
21077c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
21087c478bd9Sstevel@tonic-gate 	}
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &fe, wsp->walk_cbdata);
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 	if (fe.fce_next == NULL)
21137c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)fe.fce_next;
21167c478bd9Sstevel@tonic-gate 	return (status);
21177c478bd9Sstevel@tonic-gate }
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate int
21207c478bd9Sstevel@tonic-gate minornode_walk_init(mdb_walk_state_t *wsp)
21217c478bd9Sstevel@tonic-gate {
21227c478bd9Sstevel@tonic-gate 	struct dev_info di;
21237c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	if (addr == NULL) {
21267c478bd9Sstevel@tonic-gate 		mdb_warn("a dev_info struct address must be provided\n");
21277c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
21287c478bd9Sstevel@tonic-gate 	}
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1) {
21317c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dev_info struct at %p", addr);
21327c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
21337c478bd9Sstevel@tonic-gate 	}
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)di.devi_minor;
21367c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate int
21407c478bd9Sstevel@tonic-gate minornode_walk_step(mdb_walk_state_t *wsp)
21417c478bd9Sstevel@tonic-gate {
21427c478bd9Sstevel@tonic-gate 	struct ddi_minor_data md;
21437c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 	if (addr == NULL)
21467c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	if (mdb_vread(&md, sizeof (md), addr) == -1) {
21497c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dev_info struct at %p", addr);
21507c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
21517c478bd9Sstevel@tonic-gate 	}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)md.next;
21547c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &md, wsp->walk_cbdata));
21557c478bd9Sstevel@tonic-gate }
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate static const char *const md_type[] = {
21587c478bd9Sstevel@tonic-gate 	"DDI_MINOR",
21597c478bd9Sstevel@tonic-gate 	"DDI_ALIAS",
21607c478bd9Sstevel@tonic-gate 	"DDI_DEFAULT",
21617c478bd9Sstevel@tonic-gate 	"DDI_I_PATH",
21627c478bd9Sstevel@tonic-gate 	"?"
21637c478bd9Sstevel@tonic-gate };
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate #define	MD_TYPE_MAX	((sizeof (md_type) / sizeof (char *)) - 1)
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21687c478bd9Sstevel@tonic-gate static int
21697c478bd9Sstevel@tonic-gate print_minornode(uintptr_t addr, const void *arg, void *data)
21707c478bd9Sstevel@tonic-gate {
21717c478bd9Sstevel@tonic-gate 	char name[128];
21727c478bd9Sstevel@tonic-gate 	char nodetype[128];
21737c478bd9Sstevel@tonic-gate 	char *spectype;
21747c478bd9Sstevel@tonic-gate 	struct ddi_minor_data *mdp = (struct ddi_minor_data *)arg;
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, sizeof (name), (uintptr_t)mdp->ddm_name) == -1)
21777c478bd9Sstevel@tonic-gate 		*name = '\0';
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	if (mdb_readstr(nodetype, sizeof (nodetype),
21807c478bd9Sstevel@tonic-gate 	    (uintptr_t)mdp->ddm_node_type) == -1)
21817c478bd9Sstevel@tonic-gate 		*nodetype = '\0';
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	switch (mdp->ddm_spec_type) {
21847c478bd9Sstevel@tonic-gate 		case S_IFCHR:	spectype = "c";	break;
21857c478bd9Sstevel@tonic-gate 		case S_IFBLK:	spectype = "b";	break;
21867c478bd9Sstevel@tonic-gate 		default:	spectype = "?";	break;
21877c478bd9Sstevel@tonic-gate 	}
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 	mdb_printf("%?p %16lx %-4s %-11s %-10s %s\n",
21907c478bd9Sstevel@tonic-gate 	    addr, mdp->ddm_dev, spectype, md_type[MIN(mdp->type, MD_TYPE_MAX)],
21917c478bd9Sstevel@tonic-gate 	    name, nodetype);
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
21947c478bd9Sstevel@tonic-gate }
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21977c478bd9Sstevel@tonic-gate int
21987c478bd9Sstevel@tonic-gate minornodes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
21997c478bd9Sstevel@tonic-gate {
22007c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
22017c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
22047c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%?s %16s %-4s %-11s %-10s %-16s%</u>\n",
22057c478bd9Sstevel@tonic-gate 		    "ADDR", "DEV", "SPEC", "TYPE", "NAME", "NODETYPE");
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("minornode", print_minornode, NULL, addr) == -1) {
22087c478bd9Sstevel@tonic-gate 		mdb_warn("can't walk minornode");
22097c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
22107c478bd9Sstevel@tonic-gate 	}
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
22137c478bd9Sstevel@tonic-gate }
2214