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 /*
228451e9c3SGavin Maltby  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23*e386d4ddSRobert Mustacchi  * Copyright 2019, Joyent, Inc.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
287c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
297c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
307c478bd9Sstevel@tonic-gate #include <sys/ddifm.h>
317c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h>
327c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
337c478bd9Sstevel@tonic-gate #include <sys/hwconf.h>
347c478bd9Sstevel@tonic-gate #include <sys/stat.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h>
377c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <ctype.h>
407c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
417c478bd9Sstevel@tonic-gate #include <mdb/mdb_ks.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include "nvpair.h"
44*e386d4ddSRobert Mustacchi #include "pci.h"
4526947304SEvan Yan #include "devinfo.h"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	DEVINFO_TREE_INDENT	4	/* Indent for devs one down in tree */
487c478bd9Sstevel@tonic-gate #define	DEVINFO_PROP_INDENT	4	/* Indent for properties */
497c478bd9Sstevel@tonic-gate #define	DEVINFO_PROPLIST_INDENT	8	/* Indent for properties lists */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * devinfo node state map. Used by devinfo() and devinfo_audit().
537c478bd9Sstevel@tonic-gate  * Long words are deliberately truncated so that output
547c478bd9Sstevel@tonic-gate  * fits in 80 column with 64-bit addresses.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate static const char *const di_state[] = {
577c478bd9Sstevel@tonic-gate 	"DS_INVAL",
587c478bd9Sstevel@tonic-gate 	"DS_PROTO",
597c478bd9Sstevel@tonic-gate 	"DS_LINKED",
607c478bd9Sstevel@tonic-gate 	"DS_BOUND",
617c478bd9Sstevel@tonic-gate 	"DS_INITIA",
627c478bd9Sstevel@tonic-gate 	"DS_PROBED",
637c478bd9Sstevel@tonic-gate 	"DS_ATTACH",
647c478bd9Sstevel@tonic-gate 	"DS_READY",
657c478bd9Sstevel@tonic-gate 	"?"
667c478bd9Sstevel@tonic-gate };
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	DI_STATE_MAX	((sizeof (di_state) / sizeof (char *)) - 1)
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate void
prtconf_help(void)717c478bd9Sstevel@tonic-gate prtconf_help(void)
727c478bd9Sstevel@tonic-gate {
737c478bd9Sstevel@tonic-gate 	mdb_printf("Prints the devinfo tree from a given node.\n"
747c478bd9Sstevel@tonic-gate 	    "Without the address of a \"struct devinfo\" given, "
757c478bd9Sstevel@tonic-gate 	    "prints from the root;\n"
767c478bd9Sstevel@tonic-gate 	    "with an address, prints the parents of, "
777c478bd9Sstevel@tonic-gate 	    "and all children of, that address.\n\n"
787c478bd9Sstevel@tonic-gate 	    "Switches:\n"
7920c06695SRobert Mustacchi 	    "  -v          be verbose - print device property lists\n"
8020c06695SRobert Mustacchi 	    "  -p          only print the ancestors of the given node\n"
8120c06695SRobert Mustacchi 	    "  -c          only print the children of the given node\n"
82*e386d4ddSRobert Mustacchi 	    "  -d driver   only print instances of driver\n"
83*e386d4ddSRobert Mustacchi 	    "  -i inst     only print if the driver instance number is inst\n");
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate void
devinfo_help(void)877c478bd9Sstevel@tonic-gate devinfo_help(void)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	mdb_printf("Switches:\n"
90*e386d4ddSRobert Mustacchi 	    "  -b type     print bus of device if it matches type\n"
91*e386d4ddSRobert Mustacchi 	    "  -d          print device private data\n"
92*e386d4ddSRobert Mustacchi 	    "  -q          be quiet - don't print device property lists\n"
93*e386d4ddSRobert Mustacchi 	    "  -s          print summary of dev_info structures\n"
94*e386d4ddSRobert Mustacchi 	    "\n"
95*e386d4ddSRobert Mustacchi 	    "The following types are supported for -b:\n"
96*e386d4ddSRobert Mustacchi 	    "\n"
97*e386d4ddSRobert Mustacchi 	    "  * pcie      print the PCI Express bus (pcie_bus_t)\n");
987c478bd9Sstevel@tonic-gate }
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * Devinfo walker.
1037c478bd9Sstevel@tonic-gate  */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate typedef struct {
1067c478bd9Sstevel@tonic-gate 	/*
1077c478bd9Sstevel@tonic-gate 	 * The "struct dev_info" must be the first thing in this structure.
1087c478bd9Sstevel@tonic-gate 	 */
1097c478bd9Sstevel@tonic-gate 	struct dev_info din_dev;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	/*
1127c478bd9Sstevel@tonic-gate 	 * This is for the benefit of prtconf().
1137c478bd9Sstevel@tonic-gate 	 */
1147c478bd9Sstevel@tonic-gate 	int din_depth;
1157c478bd9Sstevel@tonic-gate } devinfo_node_t;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate typedef struct devinfo_parents_walk_data {
1187c478bd9Sstevel@tonic-gate 	devinfo_node_t dip_node;
1197c478bd9Sstevel@tonic-gate #define	dip_dev dip_node.din_dev
1207c478bd9Sstevel@tonic-gate #define	dip_depth dip_node.din_depth
1217c478bd9Sstevel@tonic-gate 	struct dev_info *dip_end;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * The following three elements are for walking the parents of a node:
1257c478bd9Sstevel@tonic-gate 	 * "dip_base_depth" is the depth of the given node from the root.
1267c478bd9Sstevel@tonic-gate 	 *   This starts at 1 (if we're walking devinfo_root), because
1277c478bd9Sstevel@tonic-gate 	 *   it's the size of the dip_parent_{nodes,addresses} arrays,
1287c478bd9Sstevel@tonic-gate 	 *   and has to include the given node.
1297c478bd9Sstevel@tonic-gate 	 * "dip_parent_nodes" is a collection of the parent node structures,
1307c478bd9Sstevel@tonic-gate 	 *   already read in via mdb_vread().  dip_parent_nodes[0] is the
1317c478bd9Sstevel@tonic-gate 	 *   root, dip_parent_nodes[1] is a child of the root, etc.
1327c478bd9Sstevel@tonic-gate 	 * "dip_parent_addresses" holds the vaddrs of all the parent nodes.
1337c478bd9Sstevel@tonic-gate 	 */
1347c478bd9Sstevel@tonic-gate 	int dip_base_depth;
1357c478bd9Sstevel@tonic-gate 	devinfo_node_t *dip_parent_nodes;
1367c478bd9Sstevel@tonic-gate 	uintptr_t *dip_parent_addresses;
1377c478bd9Sstevel@tonic-gate } devinfo_parents_walk_data_t;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate int
devinfo_parents_walk_init(mdb_walk_state_t * wsp)1407c478bd9Sstevel@tonic-gate devinfo_parents_walk_init(mdb_walk_state_t *wsp)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_data_t *dip;
1437c478bd9Sstevel@tonic-gate 	uintptr_t addr;
14414ef2b2fSdmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
1457c478bd9Sstevel@tonic-gate 	int i;
1467c478bd9Sstevel@tonic-gate 
14714ef2b2fSdmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
14814ef2b2fSdmick 		mdb_warn("failed to read 'top_devinfo'");
149892ad162SToomas Soome 		return (0);
15014ef2b2fSdmick 	}
15114ef2b2fSdmick 
152892ad162SToomas Soome 	if (wsp->walk_addr == 0)
1537c478bd9Sstevel@tonic-gate 		wsp->walk_addr = devinfo_root;
1547c478bd9Sstevel@tonic-gate 	addr = wsp->walk_addr;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	dip = mdb_alloc(sizeof (devinfo_parents_walk_data_t), UM_SLEEP);
1577c478bd9Sstevel@tonic-gate 	wsp->walk_data = dip;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	dip->dip_end = (struct dev_info *)wsp->walk_addr;
1607c478bd9Sstevel@tonic-gate 	dip->dip_depth = 0;
1617c478bd9Sstevel@tonic-gate 	dip->dip_base_depth = 1;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	do {
1647c478bd9Sstevel@tonic-gate 		if (mdb_vread(&dip->dip_dev, sizeof (dip->dip_dev),
1657c478bd9Sstevel@tonic-gate 		    addr) == -1) {
1667c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read devinfo at %p", addr);
1677c478bd9Sstevel@tonic-gate 			mdb_free(dip, sizeof (devinfo_parents_walk_data_t));
1687c478bd9Sstevel@tonic-gate 			wsp->walk_data = NULL;
1697c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 		addr = (uintptr_t)dip->dip_dev.devi_parent;
1727c478bd9Sstevel@tonic-gate 		if (addr != 0)
1737c478bd9Sstevel@tonic-gate 			dip->dip_base_depth++;
1747c478bd9Sstevel@tonic-gate 	} while (addr != 0);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	addr = wsp->walk_addr;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	dip->dip_parent_nodes = mdb_alloc(
1797c478bd9Sstevel@tonic-gate 	    dip->dip_base_depth * sizeof (devinfo_node_t), UM_SLEEP);
1807c478bd9Sstevel@tonic-gate 	dip->dip_parent_addresses = mdb_alloc(
1817c478bd9Sstevel@tonic-gate 	    dip->dip_base_depth * sizeof (uintptr_t), UM_SLEEP);
1827c478bd9Sstevel@tonic-gate 	for (i = dip->dip_base_depth - 1; i >= 0; i--) {
1837c478bd9Sstevel@tonic-gate 		if (mdb_vread(&dip->dip_parent_nodes[i].din_dev,
1847c478bd9Sstevel@tonic-gate 		    sizeof (struct dev_info), addr) == -1) {
1857c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read devinfo at %p", addr);
1867c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 		dip->dip_parent_nodes[i].din_depth = i;
1897c478bd9Sstevel@tonic-gate 		dip->dip_parent_addresses[i] = addr;
1907c478bd9Sstevel@tonic-gate 		addr = (uintptr_t)
1917c478bd9Sstevel@tonic-gate 		    dip->dip_parent_nodes[i].din_dev.devi_parent;
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate int
devinfo_parents_walk_step(mdb_walk_state_t * wsp)1987c478bd9Sstevel@tonic-gate devinfo_parents_walk_step(mdb_walk_state_t *wsp)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_data_t *dip = wsp->walk_data;
2017c478bd9Sstevel@tonic-gate 	int status;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	if (dip->dip_depth == dip->dip_base_depth)
2047c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(
2077c478bd9Sstevel@tonic-gate 	    dip->dip_parent_addresses[dip->dip_depth],
2087c478bd9Sstevel@tonic-gate 	    &dip->dip_parent_nodes[dip->dip_depth],
2097c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	dip->dip_depth++;
2127c478bd9Sstevel@tonic-gate 	return (status);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate void
devinfo_parents_walk_fini(mdb_walk_state_t * wsp)2167c478bd9Sstevel@tonic-gate devinfo_parents_walk_fini(mdb_walk_state_t *wsp)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_data_t *dip = wsp->walk_data;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	mdb_free(dip->dip_parent_nodes,
2217c478bd9Sstevel@tonic-gate 	    dip->dip_base_depth * sizeof (devinfo_node_t));
2227c478bd9Sstevel@tonic-gate 	mdb_free(dip->dip_parent_addresses,
2237c478bd9Sstevel@tonic-gate 	    dip->dip_base_depth * sizeof (uintptr_t));
2247c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (devinfo_parents_walk_data_t));
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate typedef struct devinfo_children_walk_data {
2297c478bd9Sstevel@tonic-gate 	devinfo_node_t dic_node;
2307c478bd9Sstevel@tonic-gate #define	dic_dev dic_node.din_dev
2317c478bd9Sstevel@tonic-gate #define	dic_depth dic_node.din_depth
2327c478bd9Sstevel@tonic-gate 	struct dev_info *dic_end;
2337c478bd9Sstevel@tonic-gate 	int dic_print_first_node;
2347c478bd9Sstevel@tonic-gate } devinfo_children_walk_data_t;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate int
devinfo_children_walk_init(mdb_walk_state_t * wsp)2377c478bd9Sstevel@tonic-gate devinfo_children_walk_init(mdb_walk_state_t *wsp)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	devinfo_children_walk_data_t *dic;
24014ef2b2fSdmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
24114ef2b2fSdmick 
24214ef2b2fSdmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
24314ef2b2fSdmick 		mdb_warn("failed to read 'top_devinfo'");
244892ad162SToomas Soome 		return (0);
24514ef2b2fSdmick 	}
2467c478bd9Sstevel@tonic-gate 
247892ad162SToomas Soome 	if (wsp->walk_addr == 0)
2487c478bd9Sstevel@tonic-gate 		wsp->walk_addr = devinfo_root;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	dic = mdb_alloc(sizeof (devinfo_children_walk_data_t), UM_SLEEP);
2517c478bd9Sstevel@tonic-gate 	wsp->walk_data = dic;
2527c478bd9Sstevel@tonic-gate 	dic->dic_end = (struct dev_info *)wsp->walk_addr;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	/*
2557c478bd9Sstevel@tonic-gate 	 * This could be set by devinfo_walk_init().
2567c478bd9Sstevel@tonic-gate 	 */
2577c478bd9Sstevel@tonic-gate 	if (wsp->walk_arg != NULL) {
2587c478bd9Sstevel@tonic-gate 		dic->dic_depth = (*(int *)wsp->walk_arg - 1);
2597c478bd9Sstevel@tonic-gate 		dic->dic_print_first_node = 0;
2607c478bd9Sstevel@tonic-gate 	} else {
2617c478bd9Sstevel@tonic-gate 		dic->dic_depth = 0;
2627c478bd9Sstevel@tonic-gate 		dic->dic_print_first_node = 1;
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate int
devinfo_children_walk_step(mdb_walk_state_t * wsp)2697c478bd9Sstevel@tonic-gate devinfo_children_walk_step(mdb_walk_state_t *wsp)
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate 	devinfo_children_walk_data_t *dic = wsp->walk_data;
2727c478bd9Sstevel@tonic-gate 	struct dev_info *v;
2737c478bd9Sstevel@tonic-gate 	devinfo_node_t *cur;
2747c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
2757c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
2767c478bd9Sstevel@tonic-gate 
277892ad162SToomas Soome 	if (wsp->walk_addr == 0)
2787c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dic->dic_dev, sizeof (dic->dic_dev), addr) == -1) {
2817c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo at %p", addr);
2827c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 	cur = &dic->dic_node;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	if (dic->dic_print_first_node == 0)
2877c478bd9Sstevel@tonic-gate 		dic->dic_print_first_node = 1;
2887c478bd9Sstevel@tonic-gate 	else
2897c478bd9Sstevel@tonic-gate 		status = wsp->walk_callback(addr, cur, wsp->walk_cbdata);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	/*
2927c478bd9Sstevel@tonic-gate 	 * "v" is always a virtual address pointer,
2937c478bd9Sstevel@tonic-gate 	 *  i.e. can't be deref'ed.
2947c478bd9Sstevel@tonic-gate 	 */
2957c478bd9Sstevel@tonic-gate 	v = (struct dev_info *)addr;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	if (dic->dic_dev.devi_child != NULL) {
2987c478bd9Sstevel@tonic-gate 		v = dic->dic_dev.devi_child;
2997c478bd9Sstevel@tonic-gate 		dic->dic_depth++;
3007c478bd9Sstevel@tonic-gate 	} else if (dic->dic_dev.devi_sibling != NULL && v != dic->dic_end) {
3017c478bd9Sstevel@tonic-gate 		v = dic->dic_dev.devi_sibling;
3027c478bd9Sstevel@tonic-gate 	} else {
3037c478bd9Sstevel@tonic-gate 		while (v != NULL && v != dic->dic_end &&
3047c478bd9Sstevel@tonic-gate 		    dic->dic_dev.devi_sibling == NULL) {
3057c478bd9Sstevel@tonic-gate 			v = dic->dic_dev.devi_parent;
3067c478bd9Sstevel@tonic-gate 			if (v == NULL)
3077c478bd9Sstevel@tonic-gate 				break;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 			mdb_vread(&dic->dic_dev,
3107c478bd9Sstevel@tonic-gate 			    sizeof (struct dev_info), (uintptr_t)v);
3117c478bd9Sstevel@tonic-gate 			dic->dic_depth--;
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 		if (v != NULL && v != dic->dic_end)
3147c478bd9Sstevel@tonic-gate 			v = dic->dic_dev.devi_sibling;
3157c478bd9Sstevel@tonic-gate 		if (v == dic->dic_end)
3167c478bd9Sstevel@tonic-gate 			v = NULL;	/* Done */
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)v;
3207c478bd9Sstevel@tonic-gate 	return (status);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate void
devinfo_children_walk_fini(mdb_walk_state_t * wsp)3247c478bd9Sstevel@tonic-gate devinfo_children_walk_fini(mdb_walk_state_t *wsp)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (devinfo_children_walk_data_t));
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate typedef struct devinfo_walk_data {
3307c478bd9Sstevel@tonic-gate 	mdb_walk_state_t diw_parent, diw_child;
3317c478bd9Sstevel@tonic-gate 	enum { DIW_PARENT, DIW_CHILD, DIW_DONE } diw_mode;
3327c478bd9Sstevel@tonic-gate } devinfo_walk_data_t;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate int
devinfo_walk_init(mdb_walk_state_t * wsp)3357c478bd9Sstevel@tonic-gate devinfo_walk_init(mdb_walk_state_t *wsp)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate 	devinfo_walk_data_t *diw;
3387c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_data_t *dip;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	diw = mdb_alloc(sizeof (devinfo_walk_data_t), UM_SLEEP);
3417c478bd9Sstevel@tonic-gate 	diw->diw_parent = *wsp;
3427c478bd9Sstevel@tonic-gate 	diw->diw_child = *wsp;
3437c478bd9Sstevel@tonic-gate 	wsp->walk_data = diw;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	diw->diw_mode = DIW_PARENT;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	if (devinfo_parents_walk_init(&diw->diw_parent) == -1) {
3487c478bd9Sstevel@tonic-gate 		mdb_free(diw, sizeof (devinfo_walk_data_t));
3497c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/*
3537c478bd9Sstevel@tonic-gate 	 * This is why the "devinfo" walker needs to be marginally
3547c478bd9Sstevel@tonic-gate 	 * complicated - the child walker needs this initialization
3557c478bd9Sstevel@tonic-gate 	 * data, and the best way to get it is out of the parent walker.
3567c478bd9Sstevel@tonic-gate 	 */
3577c478bd9Sstevel@tonic-gate 	dip = diw->diw_parent.walk_data;
3587c478bd9Sstevel@tonic-gate 	diw->diw_child.walk_arg = &dip->dip_base_depth;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	if (devinfo_children_walk_init(&diw->diw_child) == -1) {
3617c478bd9Sstevel@tonic-gate 		devinfo_parents_walk_fini(&diw->diw_parent);
3627c478bd9Sstevel@tonic-gate 		mdb_free(diw, sizeof (devinfo_walk_data_t));
3637c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate int
devinfo_walk_step(mdb_walk_state_t * wsp)3707c478bd9Sstevel@tonic-gate devinfo_walk_step(mdb_walk_state_t *wsp)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	devinfo_walk_data_t *diw = wsp->walk_data;
3737c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	if (diw->diw_mode == DIW_PARENT) {
3767c478bd9Sstevel@tonic-gate 		status = devinfo_parents_walk_step(&diw->diw_parent);
3777c478bd9Sstevel@tonic-gate 		if (status != WALK_NEXT) {
3787c478bd9Sstevel@tonic-gate 			/*
3797c478bd9Sstevel@tonic-gate 			 * Keep on going even if the parents walk hit an error.
3807c478bd9Sstevel@tonic-gate 			 */
3817c478bd9Sstevel@tonic-gate 			diw->diw_mode = DIW_CHILD;
3827c478bd9Sstevel@tonic-gate 			status = WALK_NEXT;
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 	} else if (diw->diw_mode == DIW_CHILD) {
3857c478bd9Sstevel@tonic-gate 		status = devinfo_children_walk_step(&diw->diw_child);
3867c478bd9Sstevel@tonic-gate 		if (status != WALK_NEXT) {
3877c478bd9Sstevel@tonic-gate 			diw->diw_mode = DIW_DONE;
3887c478bd9Sstevel@tonic-gate 			status = WALK_DONE;
3897c478bd9Sstevel@tonic-gate 		}
3907c478bd9Sstevel@tonic-gate 	} else
3917c478bd9Sstevel@tonic-gate 		status = WALK_DONE;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	return (status);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate void
devinfo_walk_fini(mdb_walk_state_t * wsp)3977c478bd9Sstevel@tonic-gate devinfo_walk_fini(mdb_walk_state_t *wsp)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	devinfo_walk_data_t *diw = wsp->walk_data;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	devinfo_children_walk_fini(&diw->diw_child);
4027c478bd9Sstevel@tonic-gate 	devinfo_parents_walk_fini(&diw->diw_parent);
4037c478bd9Sstevel@tonic-gate 	mdb_free(diw, sizeof (devinfo_walk_data_t));
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate  * Given a devinfo pointer, figure out which driver is associated
4087c478bd9Sstevel@tonic-gate  * with the node (by driver name, from the devnames array).
4097c478bd9Sstevel@tonic-gate  */
4107c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4117c478bd9Sstevel@tonic-gate int
devinfo2driver(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4127c478bd9Sstevel@tonic-gate devinfo2driver(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	char dname[MODMAXNAMELEN + 1];
4157c478bd9Sstevel@tonic-gate 	struct dev_info devi;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
4197c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
4227c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo struct at %p", addr);
4237c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
426f723faa1Seschrock 	if (devi.devi_node_state < DS_ATTACHED) {
4277c478bd9Sstevel@tonic-gate 		/* No driver attached to this devinfo - nothing to do. */
4287c478bd9Sstevel@tonic-gate 		mdb_warn("%p: No driver attached to this devinfo node\n", addr);
4297c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0) {
4337c478bd9Sstevel@tonic-gate 		mdb_warn("failed to determine driver name");
4347c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	mdb_printf("Driver '%s' is associated with devinfo %p.\n", dname, addr);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate typedef struct devnames_walk {
4447c478bd9Sstevel@tonic-gate 	struct devnames *dnw_names;
4457c478bd9Sstevel@tonic-gate 	int dnw_ndx;
4467c478bd9Sstevel@tonic-gate 	int dnw_devcnt;
4477c478bd9Sstevel@tonic-gate 	uintptr_t dnw_base;
4487c478bd9Sstevel@tonic-gate 	uintptr_t dnw_size;
4497c478bd9Sstevel@tonic-gate } devnames_walk_t;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate int
devnames_walk_init(mdb_walk_state_t * wsp)4527c478bd9Sstevel@tonic-gate devnames_walk_init(mdb_walk_state_t *wsp)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	devnames_walk_t *dnw;
4557c478bd9Sstevel@tonic-gate 	int devcnt;
4567c478bd9Sstevel@tonic-gate 	uintptr_t devnamesp;
4577c478bd9Sstevel@tonic-gate 
458892ad162SToomas Soome 	if (wsp->walk_addr != 0) {
4597c478bd9Sstevel@tonic-gate 		mdb_warn("devnames walker only supports global walks\n");
4607c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devcnt, "devcnt") == -1) {
4647c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devcnt'");
4657c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devnamesp, "devnamesp") == -1) {
4697c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devnamesp'");
4707c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	dnw = mdb_zalloc(sizeof (devnames_walk_t), UM_SLEEP);
4747c478bd9Sstevel@tonic-gate 	dnw->dnw_size = sizeof (struct devnames) * devcnt;
4757c478bd9Sstevel@tonic-gate 	dnw->dnw_devcnt = devcnt;
4767c478bd9Sstevel@tonic-gate 	dnw->dnw_base = devnamesp;
4777c478bd9Sstevel@tonic-gate 	dnw->dnw_names = mdb_alloc(dnw->dnw_size, UM_SLEEP);
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	if (mdb_vread(dnw->dnw_names, dnw->dnw_size, dnw->dnw_base) == -1) {
4807c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devnames array at %p", devnamesp);
4817c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	wsp->walk_data = dnw;
4857c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate int
devnames_walk_step(mdb_walk_state_t * wsp)4897c478bd9Sstevel@tonic-gate devnames_walk_step(mdb_walk_state_t *wsp)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	devnames_walk_t *dnw = wsp->walk_data;
4927c478bd9Sstevel@tonic-gate 	int status;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	if (dnw->dnw_ndx == dnw->dnw_devcnt)
4957c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(dnw->dnw_ndx * sizeof (struct devnames) +
4987c478bd9Sstevel@tonic-gate 	    dnw->dnw_base, &dnw->dnw_names[dnw->dnw_ndx], wsp->walk_cbdata);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	dnw->dnw_ndx++;
5017c478bd9Sstevel@tonic-gate 	return (status);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate void
devnames_walk_fini(mdb_walk_state_t * wsp)5057c478bd9Sstevel@tonic-gate devnames_walk_fini(mdb_walk_state_t *wsp)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	devnames_walk_t *dnw = wsp->walk_data;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	mdb_free(dnw->dnw_names, dnw->dnw_size);
5107c478bd9Sstevel@tonic-gate 	mdb_free(dnw, sizeof (devnames_walk_t));
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate int
devinfo_siblings_walk_init(mdb_walk_state_t * wsp)5147c478bd9Sstevel@tonic-gate devinfo_siblings_walk_init(mdb_walk_state_t *wsp)
5157c478bd9Sstevel@tonic-gate {
5167c478bd9Sstevel@tonic-gate 	struct dev_info di;
5177c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
5187c478bd9Sstevel@tonic-gate 
519892ad162SToomas Soome 	if (addr == 0) {
5207c478bd9Sstevel@tonic-gate 		mdb_warn("a dev_info struct address must be provided\n");
5217c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), addr) == -1) {
5257c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dev_info struct at %p", addr);
5267c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	if (di.devi_parent == NULL) {
5307c478bd9Sstevel@tonic-gate 		mdb_warn("no parent for devinfo at %p", addr);
5317c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5327c478bd9Sstevel@tonic-gate 	}
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), (uintptr_t)di.devi_parent) == -1) {
5357c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read parent dev_info struct at %p",
5367c478bd9Sstevel@tonic-gate 		    (uintptr_t)di.devi_parent);
5377c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)di.devi_child;
5417c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate int
devinfo_siblings_walk_step(mdb_walk_state_t * wsp)5457c478bd9Sstevel@tonic-gate devinfo_siblings_walk_step(mdb_walk_state_t *wsp)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	struct dev_info di;
5487c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
5497c478bd9Sstevel@tonic-gate 
550892ad162SToomas Soome 	if (addr == 0)
5517c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), addr) == -1) {
5547c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dev_info struct at %p", addr);
5557c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)di.devi_sibling;
5597c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &di, wsp->walk_cbdata));
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate int
devi_next_walk_step(mdb_walk_state_t * wsp)5637c478bd9Sstevel@tonic-gate devi_next_walk_step(mdb_walk_state_t *wsp)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	struct dev_info di;
5667c478bd9Sstevel@tonic-gate 	int status;
5677c478bd9Sstevel@tonic-gate 
568892ad162SToomas Soome 	if (wsp->walk_addr == 0)
5697c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1)
5727c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &di, wsp->walk_cbdata);
5757c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)di.devi_next;
5767c478bd9Sstevel@tonic-gate 	return (status);
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate  * Helper functions.
5817c478bd9Sstevel@tonic-gate  */
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate static int
is_printable_string(unsigned char * prop_value)5847c478bd9Sstevel@tonic-gate is_printable_string(unsigned char *prop_value)
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate 	while (*prop_value != 0)
5877c478bd9Sstevel@tonic-gate 		if (!isprint(*prop_value++))
5887c478bd9Sstevel@tonic-gate 			return (0);
5897c478bd9Sstevel@tonic-gate 	return (1);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate static void
devinfo_print_props_type(int type)59320c06695SRobert Mustacchi devinfo_print_props_type(int type)
59420c06695SRobert Mustacchi {
5957c478bd9Sstevel@tonic-gate 	char *type_str = NULL;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	switch (type) {
5987c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_ANY:
5997c478bd9Sstevel@tonic-gate 		type_str = "any";
6007c478bd9Sstevel@tonic-gate 		break;
6017c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_COMPOSITE:
6027c478bd9Sstevel@tonic-gate 		type_str = "composite";
6037c478bd9Sstevel@tonic-gate 		break;
6047c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_INT64:
6057c478bd9Sstevel@tonic-gate 		type_str = "int64";
6067c478bd9Sstevel@tonic-gate 		break;
6077c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_INT:
6087c478bd9Sstevel@tonic-gate 		type_str = "int";
6097c478bd9Sstevel@tonic-gate 		break;
6107c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_BYTE:
6117c478bd9Sstevel@tonic-gate 		type_str = "byte";
6127c478bd9Sstevel@tonic-gate 		break;
6137c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_STRING:
6147c478bd9Sstevel@tonic-gate 		type_str = "string";
6157c478bd9Sstevel@tonic-gate 		break;
6167c478bd9Sstevel@tonic-gate 	}
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	if (type_str != NULL)
6197c478bd9Sstevel@tonic-gate 		mdb_printf("type=%s", type_str);
6207c478bd9Sstevel@tonic-gate 	else
6217c478bd9Sstevel@tonic-gate 		mdb_printf("type=0x%x", type);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate static void
devinfo_print_props_value(int elem_size,int nelem,unsigned char * prop_value,int prop_value_len)6257c478bd9Sstevel@tonic-gate devinfo_print_props_value(int elem_size, int nelem,
62620c06695SRobert Mustacchi     unsigned char *prop_value, int prop_value_len)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate 	int i;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	mdb_printf("value=");
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	if (elem_size == 0) {
6337c478bd9Sstevel@tonic-gate 		/* if elem_size == 0, then we are printing out string(s) */
6347c478bd9Sstevel@tonic-gate 		char *p = (char *)prop_value;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem - 1; i++) {
6377c478bd9Sstevel@tonic-gate 			mdb_printf("'%s' + ", p);
6387c478bd9Sstevel@tonic-gate 			p += strlen(p) + 1;
6397c478bd9Sstevel@tonic-gate 		}
6407c478bd9Sstevel@tonic-gate 		mdb_printf("'%s'", p);
6417c478bd9Sstevel@tonic-gate 	} else {
6427c478bd9Sstevel@tonic-gate 		/*
6437c478bd9Sstevel@tonic-gate 		 * if elem_size != 0 then we are printing out an array
6447c478bd9Sstevel@tonic-gate 		 * where each element is of elem_size
6457c478bd9Sstevel@tonic-gate 		 */
6467c478bd9Sstevel@tonic-gate 		mdb_nhconvert(prop_value, prop_value, elem_size);
6477c478bd9Sstevel@tonic-gate 		mdb_printf("%02x", *prop_value);
6487c478bd9Sstevel@tonic-gate 		for (i = 1; i < prop_value_len; i++) {
6497c478bd9Sstevel@tonic-gate 			if ((i % elem_size) == 0) {
6507c478bd9Sstevel@tonic-gate 				mdb_nhconvert(&prop_value[i],
6517c478bd9Sstevel@tonic-gate 				    &prop_value[i], elem_size);
6527c478bd9Sstevel@tonic-gate 				mdb_printf(".");
6537c478bd9Sstevel@tonic-gate 			}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 			mdb_printf("%02x", prop_value[i]);
6567c478bd9Sstevel@tonic-gate 		}
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate  * devinfo_print_props_guess()
6627c478bd9Sstevel@tonic-gate  * Guesses how to interpret the value of the property
6637c478bd9Sstevel@tonic-gate  *
6647c478bd9Sstevel@tonic-gate  * Params:
665892ad162SToomas Soome  *	type      - Should be the type value of the property
666892ad162SToomas Soome  *	prop_val  - Pointer to the property value data buffer
667892ad162SToomas Soome  *	prop_len  - Length of the property value data buffer
6687c478bd9Sstevel@tonic-gate  *
6697c478bd9Sstevel@tonic-gate  * Return values:
670892ad162SToomas Soome  *	nelem     - The number of elements stored in the property value
671892ad162SToomas Soome  *			data buffer pointed to by prop_val.
672892ad162SToomas Soome  *	elem_size - The size (in bytes) of the elements stored in the property
673892ad162SToomas Soome  *			value data buffer pointed to by prop_val.
674892ad162SToomas Soome  *			Upon return if elem_size == 0 and nelem != 0 then
675892ad162SToomas Soome  *			the property value data buffer contains strings
676892ad162SToomas Soome  *	len_err   - There was an error with the length of the data buffer.
677892ad162SToomas Soome  *			Its size is not a multiple of the array value type.
678892ad162SToomas Soome  *			It will be interpreted as an array of bytes.
6797c478bd9Sstevel@tonic-gate  */
6807c478bd9Sstevel@tonic-gate static void
devinfo_print_props_guess(int type,unsigned char * prop_val,int prop_len,int * elem_size,int * nelem,int * len_err)6817c478bd9Sstevel@tonic-gate devinfo_print_props_guess(int type, unsigned char *prop_val, int prop_len,
6827c478bd9Sstevel@tonic-gate     int *elem_size, int *nelem, int *len_err)
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate 	*len_err = 0;
685892ad162SToomas Soome 	if (prop_len == 0) {
6867c478bd9Sstevel@tonic-gate 		*elem_size = 0;
6877c478bd9Sstevel@tonic-gate 		*nelem = 0;
6887c478bd9Sstevel@tonic-gate 		return;
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/* by default, assume an array of bytes */
6927c478bd9Sstevel@tonic-gate 	*elem_size = 1;
6937c478bd9Sstevel@tonic-gate 	*nelem = prop_len;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	switch (type) {
6967c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_BYTE:
6977c478bd9Sstevel@tonic-gate 		/* default case, that was easy */
6987c478bd9Sstevel@tonic-gate 		break;
6997c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_INT64:
7007c478bd9Sstevel@tonic-gate 		if ((prop_len % sizeof (int64_t)) == 0) {
7017c478bd9Sstevel@tonic-gate 			*elem_size = sizeof (int64_t);
7027c478bd9Sstevel@tonic-gate 			*nelem = prop_len / *elem_size;
7037c478bd9Sstevel@tonic-gate 		} else {
7047c478bd9Sstevel@tonic-gate 			/* array is not a multiple of type size, error */
7057c478bd9Sstevel@tonic-gate 			*len_err = 1;
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 		break;
7087c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_INT:
7097c478bd9Sstevel@tonic-gate 		if ((prop_len % sizeof (int)) == 0) {
7107c478bd9Sstevel@tonic-gate 			*elem_size = sizeof (int);
7117c478bd9Sstevel@tonic-gate 			*nelem = prop_len / *elem_size;
7127c478bd9Sstevel@tonic-gate 		} else {
7137c478bd9Sstevel@tonic-gate 			/* array is not a multiple of type size, error */
7147c478bd9Sstevel@tonic-gate 			*len_err = 1;
7157c478bd9Sstevel@tonic-gate 		}
7167c478bd9Sstevel@tonic-gate 		break;
7177c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_STRING:
7187c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_COMPOSITE:
7197c478bd9Sstevel@tonic-gate 	case DDI_PROP_TYPE_ANY:
7207c478bd9Sstevel@tonic-gate 	default:
7217c478bd9Sstevel@tonic-gate 		/*
7227c478bd9Sstevel@tonic-gate 		 * if we made it here the type is either unknown
7237c478bd9Sstevel@tonic-gate 		 * or a string.  Try to interpret is as a string
7247c478bd9Sstevel@tonic-gate 		 * and if that fails assume an array of bytes.
7257c478bd9Sstevel@tonic-gate 		 */
7267c478bd9Sstevel@tonic-gate 		if (prop_val[prop_len - 1] == '\0') {
7277c478bd9Sstevel@tonic-gate 			unsigned char	*s = prop_val;
7287c478bd9Sstevel@tonic-gate 			int		i;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 			/* assume an array of strings */
7317c478bd9Sstevel@tonic-gate 			*elem_size = 0;
7327c478bd9Sstevel@tonic-gate 			*nelem = 0;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 			for (i = 0; i < prop_len; i++) {
7357c478bd9Sstevel@tonic-gate 				if (prop_val[i] != '\0')
7367c478bd9Sstevel@tonic-gate 					continue;
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 				/*
7397c478bd9Sstevel@tonic-gate 				 * If the property is typed as a string
7407c478bd9Sstevel@tonic-gate 				 * property, then interpret empty strings
7417c478bd9Sstevel@tonic-gate 				 * as strings. Otherwise default to an
7427c478bd9Sstevel@tonic-gate 				 * array of bytes. If there are unprintable
7437c478bd9Sstevel@tonic-gate 				 * characters, always default to an array of
7447c478bd9Sstevel@tonic-gate 				 * bytes.
7457c478bd9Sstevel@tonic-gate 				 */
7467c478bd9Sstevel@tonic-gate 				if ((*s == '\0' && type !=
7477c478bd9Sstevel@tonic-gate 				    DDI_PROP_TYPE_STRING) ||
7487c478bd9Sstevel@tonic-gate 				    !is_printable_string(s)) {
7497c478bd9Sstevel@tonic-gate 					*elem_size = 1;
7507c478bd9Sstevel@tonic-gate 					*nelem = prop_len;
7517c478bd9Sstevel@tonic-gate 					break;
7527c478bd9Sstevel@tonic-gate 				}
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 				(*nelem)++;
7557c478bd9Sstevel@tonic-gate 				s = &prop_val[i + 1];
7567c478bd9Sstevel@tonic-gate 			}
7577c478bd9Sstevel@tonic-gate 		}
7587c478bd9Sstevel@tonic-gate 		break;
7597c478bd9Sstevel@tonic-gate 	}
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate static void
devinfo_print_props(char * name,ddi_prop_t * p)7637c478bd9Sstevel@tonic-gate devinfo_print_props(char *name, ddi_prop_t *p)
7647c478bd9Sstevel@tonic-gate {
7657c478bd9Sstevel@tonic-gate 	if (p == NULL)
7667c478bd9Sstevel@tonic-gate 		return;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	if (name != NULL)
7697c478bd9Sstevel@tonic-gate 		mdb_printf("%s ", name);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	mdb_printf("properties at %p:\n", p);
7727c478bd9Sstevel@tonic-gate 	mdb_inc_indent(DEVINFO_PROP_INDENT);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	while (p != NULL) {
7757c478bd9Sstevel@tonic-gate 		ddi_prop_t	prop;
7767c478bd9Sstevel@tonic-gate 		char		prop_name[128];
7777c478bd9Sstevel@tonic-gate 		unsigned char	*prop_value;
7787c478bd9Sstevel@tonic-gate 		int		type, elem_size, nelem, prop_len_error;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		/* read in the property struct */
7817c478bd9Sstevel@tonic-gate 		if (mdb_vread(&prop, sizeof (prop), (uintptr_t)p) == -1) {
7827c478bd9Sstevel@tonic-gate 			mdb_warn("could not read property at 0x%p", p);
7837c478bd9Sstevel@tonic-gate 			break;
7847c478bd9Sstevel@tonic-gate 		}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 		/* print the property name */
7877c478bd9Sstevel@tonic-gate 		if (mdb_readstr(prop_name, sizeof (prop_name),
7887c478bd9Sstevel@tonic-gate 		    (uintptr_t)prop.prop_name) == -1) {
7897c478bd9Sstevel@tonic-gate 			mdb_warn("could not read property name at 0x%p",
7907c478bd9Sstevel@tonic-gate 			    prop.prop_name);
7917c478bd9Sstevel@tonic-gate 			goto next;
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 		mdb_printf("name='%s' ", prop_name);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 		/* get the property type and print it out */
7967c478bd9Sstevel@tonic-gate 		type = (prop.prop_flags & DDI_PROP_TYPE_MASK);
7977c478bd9Sstevel@tonic-gate 		devinfo_print_props_type(type);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		/* get the property value */
8007c478bd9Sstevel@tonic-gate 		if (prop.prop_len > 0) {
8017c478bd9Sstevel@tonic-gate 			prop_value = mdb_alloc(prop.prop_len, UM_SLEEP|UM_GC);
8027c478bd9Sstevel@tonic-gate 			if (mdb_vread(prop_value, prop.prop_len,
80314ef2b2fSdmick 			    (uintptr_t)prop.prop_val) == -1) {
8047c478bd9Sstevel@tonic-gate 				mdb_warn("could not read property value at "
8057c478bd9Sstevel@tonic-gate 				    "0x%p", prop.prop_val);
8067c478bd9Sstevel@tonic-gate 				goto next;
8077c478bd9Sstevel@tonic-gate 			}
8087c478bd9Sstevel@tonic-gate 		} else {
8097c478bd9Sstevel@tonic-gate 			prop_value = NULL;
8107c478bd9Sstevel@tonic-gate 		}
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 		/* take a guess at interpreting the property value */
8137c478bd9Sstevel@tonic-gate 		devinfo_print_props_guess(type, prop_value, prop.prop_len,
8147c478bd9Sstevel@tonic-gate 		    &elem_size, &nelem, &prop_len_error);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 		/* print out the number ot items */
8177c478bd9Sstevel@tonic-gate 		mdb_printf(" items=%d", nelem);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 		/* print out any associated device information */
8207c478bd9Sstevel@tonic-gate 		if (prop.prop_dev != DDI_DEV_T_NONE) {
8217c478bd9Sstevel@tonic-gate 			mdb_printf(" dev=");
8227c478bd9Sstevel@tonic-gate 			if (prop.prop_dev == DDI_DEV_T_ANY)
8237c478bd9Sstevel@tonic-gate 				mdb_printf("any");
8247c478bd9Sstevel@tonic-gate 			else if (prop.prop_dev == DDI_MAJOR_T_UNKNOWN)
8257c478bd9Sstevel@tonic-gate 				mdb_printf("unknown");
8267c478bd9Sstevel@tonic-gate 			else
8277c478bd9Sstevel@tonic-gate 				mdb_printf("(%u,%u)",
8287c478bd9Sstevel@tonic-gate 				    getmajor(prop.prop_dev),
8297c478bd9Sstevel@tonic-gate 				    getminor(prop.prop_dev));
8307c478bd9Sstevel@tonic-gate 		}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 		/* print out the property value */
8337c478bd9Sstevel@tonic-gate 		if (prop_value != NULL) {
8347c478bd9Sstevel@tonic-gate 			mdb_printf("\n");
8357c478bd9Sstevel@tonic-gate 			mdb_inc_indent(DEVINFO_PROP_INDENT);
8367c478bd9Sstevel@tonic-gate 			if (prop_len_error)
8377c478bd9Sstevel@tonic-gate 				mdb_printf("NOTE: prop length is not a "
8387c478bd9Sstevel@tonic-gate 				    "multiple of element size\n");
8397c478bd9Sstevel@tonic-gate 			devinfo_print_props_value(elem_size, nelem,
8407c478bd9Sstevel@tonic-gate 			    prop_value, prop.prop_len);
8417c478bd9Sstevel@tonic-gate 			mdb_dec_indent(DEVINFO_PROP_INDENT);
8427c478bd9Sstevel@tonic-gate 		}
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate next:
8457c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
8467c478bd9Sstevel@tonic-gate 		p = prop.prop_next;
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	mdb_dec_indent(DEVINFO_PROP_INDENT);
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate static void
devinfo_pathinfo_state(mdi_pathinfo_state_t state)85320c06695SRobert Mustacchi devinfo_pathinfo_state(mdi_pathinfo_state_t state)
85420c06695SRobert Mustacchi {
8557c478bd9Sstevel@tonic-gate 	char *type_str = NULL;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	switch (state) {
8587c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_INIT:
8597c478bd9Sstevel@tonic-gate 		type_str = "init";
8607c478bd9Sstevel@tonic-gate 		break;
8617c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_ONLINE:
8627c478bd9Sstevel@tonic-gate 		type_str = "online";
8637c478bd9Sstevel@tonic-gate 		break;
8647c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_STANDBY:
8657c478bd9Sstevel@tonic-gate 		type_str = "standby";
8667c478bd9Sstevel@tonic-gate 		break;
8677c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_FAULT:
8687c478bd9Sstevel@tonic-gate 		type_str = "fault";
8697c478bd9Sstevel@tonic-gate 		break;
8707c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_OFFLINE:
8717c478bd9Sstevel@tonic-gate 		type_str = "offline";
8727c478bd9Sstevel@tonic-gate 		break;
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 	if (type_str != NULL)
8757c478bd9Sstevel@tonic-gate 		mdb_printf("state=%s\n", type_str);
8767c478bd9Sstevel@tonic-gate 	else
8777c478bd9Sstevel@tonic-gate 		mdb_printf("state=0x%x\n", state);
8787c478bd9Sstevel@tonic-gate }
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate static void
devinfo_print_pathing(int mdi_component,void * mdi_client)88120c06695SRobert Mustacchi devinfo_print_pathing(int mdi_component, void *mdi_client)
88220c06695SRobert Mustacchi {
8837c478bd9Sstevel@tonic-gate 	mdi_client_t		mdi_c;
8847c478bd9Sstevel@tonic-gate 	struct mdi_pathinfo	*pip;
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	/* we only print out multipathing info for client nodes */
8877c478bd9Sstevel@tonic-gate 	if ((mdi_component & MDI_COMPONENT_CLIENT) == 0)
8887c478bd9Sstevel@tonic-gate 		return;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	mdb_printf("Client multipath info at: 0x%p\n", mdi_client);
8917c478bd9Sstevel@tonic-gate 	mdb_inc_indent(DEVINFO_PROP_INDENT);
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	/* read in the client multipathing info */
8947c478bd9Sstevel@tonic-gate 	if (mdb_readstr((void*) &mdi_c, sizeof (mdi_c),
8957c478bd9Sstevel@tonic-gate 	    (uintptr_t)mdi_client) == -1) {
8967c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read mdi_client at %p",
8977c478bd9Sstevel@tonic-gate 		    (uintptr_t)mdi_client);
8987c478bd9Sstevel@tonic-gate 		goto exit;
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	/*
9027c478bd9Sstevel@tonic-gate 	 * walk through the clients list of pathinfo structures and print
9037c478bd9Sstevel@tonic-gate 	 * out the properties for each path
9047c478bd9Sstevel@tonic-gate 	 */
9057c478bd9Sstevel@tonic-gate 	pip = (struct mdi_pathinfo *)mdi_c.ct_path_head;
9067c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
9077c478bd9Sstevel@tonic-gate 		char			binding_name[128];
9087c478bd9Sstevel@tonic-gate 		struct mdi_pathinfo	pi;
9097c478bd9Sstevel@tonic-gate 		mdi_phci_t		ph;
9107c478bd9Sstevel@tonic-gate 		struct dev_info		ph_di;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 		/* read in the pathinfo structure */
9137c478bd9Sstevel@tonic-gate 		if (mdb_vread((void*)&pi, sizeof (pi),
91420c06695SRobert Mustacchi 		    (uintptr_t)pip) == -1) {
9157c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read mdi_pathinfo at %p",
9167c478bd9Sstevel@tonic-gate 			    (uintptr_t)pip);
9177c478bd9Sstevel@tonic-gate 			goto exit;
9187c478bd9Sstevel@tonic-gate 		}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		/* read in the pchi (path host adapter) info */
9217c478bd9Sstevel@tonic-gate 		if (mdb_vread((void*)&ph, sizeof (ph),
92220c06695SRobert Mustacchi 		    (uintptr_t)pi.pi_phci) == -1) {
9237c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read mdi_pchi at %p",
9247c478bd9Sstevel@tonic-gate 			    (uintptr_t)pi.pi_phci);
9257c478bd9Sstevel@tonic-gate 			goto exit;
9267c478bd9Sstevel@tonic-gate 		}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 		/* read in the dip of the phci so we can get it's name */
9297c478bd9Sstevel@tonic-gate 		if (mdb_vread((void*)&ph_di, sizeof (ph_di),
93020c06695SRobert Mustacchi 		    (uintptr_t)ph.ph_dip) == -1) {
9317c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read mdi_pchi at %p",
9327c478bd9Sstevel@tonic-gate 			    (uintptr_t)ph.ph_dip);
9337c478bd9Sstevel@tonic-gate 			goto exit;
9347c478bd9Sstevel@tonic-gate 		}
9357c478bd9Sstevel@tonic-gate 		if (mdb_vread(binding_name, sizeof (binding_name),
93620c06695SRobert Mustacchi 		    (uintptr_t)ph_di.devi_binding_name) == -1) {
9377c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read binding_name at %p",
9387c478bd9Sstevel@tonic-gate 			    (uintptr_t)ph_di.devi_binding_name);
9397c478bd9Sstevel@tonic-gate 			goto exit;
9407c478bd9Sstevel@tonic-gate 		}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 		mdb_printf("%s#%d, ", binding_name, ph_di.devi_instance);
9437c478bd9Sstevel@tonic-gate 		devinfo_pathinfo_state(pi.pi_state);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 		/* print out the pathing info */
9467c478bd9Sstevel@tonic-gate 		mdb_inc_indent(DEVINFO_PROP_INDENT);
9477c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd(NVPAIR_WALKER_FQNAME, NVPAIR_DCMD_FQNAME,
94820c06695SRobert Mustacchi 		    0, NULL, (uintptr_t)pi.pi_prop) != 0) {
9497c478bd9Sstevel@tonic-gate 			mdb_dec_indent(DEVINFO_PROP_INDENT);
9507c478bd9Sstevel@tonic-gate 			goto exit;
9517c478bd9Sstevel@tonic-gate 		}
9527c478bd9Sstevel@tonic-gate 		mdb_dec_indent(DEVINFO_PROP_INDENT);
9537c478bd9Sstevel@tonic-gate 		pip = pi.pi_client_link;
9547c478bd9Sstevel@tonic-gate 	}
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate exit:
9577c478bd9Sstevel@tonic-gate 	mdb_dec_indent(DEVINFO_PROP_INDENT);
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate static int
devinfo_print(uintptr_t addr,struct dev_info * dev,devinfo_cb_data_t * data)9617c478bd9Sstevel@tonic-gate devinfo_print(uintptr_t addr, struct dev_info *dev, devinfo_cb_data_t *data)
9627c478bd9Sstevel@tonic-gate {
9637c478bd9Sstevel@tonic-gate 	/*
9647c478bd9Sstevel@tonic-gate 	 * We know the walker passes us extra data after the dev_info.
9657c478bd9Sstevel@tonic-gate 	 */
9667c478bd9Sstevel@tonic-gate 	char		binding_name[128];
967f723faa1Seschrock 	char		dname[MODMAXNAMELEN + 1];
9687c478bd9Sstevel@tonic-gate 	devinfo_node_t	*din = (devinfo_node_t *)dev;
9697c478bd9Sstevel@tonic-gate 	ddi_prop_t	*global_props = NULL;
97020c06695SRobert Mustacchi 	boolean_t	hdname = B_FALSE;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	if (mdb_readstr(binding_name, sizeof (binding_name),
9737c478bd9Sstevel@tonic-gate 	    (uintptr_t)dev->devi_binding_name) == -1) {
9747c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read binding_name at %p",
9757c478bd9Sstevel@tonic-gate 		    (uintptr_t)dev->devi_binding_name);
9767c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/* if there are any global properties, get a pointer to them */
9807c478bd9Sstevel@tonic-gate 	if (dev->devi_global_prop_list != NULL) {
9817c478bd9Sstevel@tonic-gate 		ddi_prop_list_t	plist;
9827c478bd9Sstevel@tonic-gate 		if (mdb_vread((void*)&plist, sizeof (plist),
98314ef2b2fSdmick 		    (uintptr_t)dev->devi_global_prop_list) == -1) {
9847c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read global prop_list at %p",
9857c478bd9Sstevel@tonic-gate 			    (uintptr_t)dev->devi_global_prop_list);
9867c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
9877c478bd9Sstevel@tonic-gate 		}
9887c478bd9Sstevel@tonic-gate 		global_props = plist.prop_list;
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 
99120c06695SRobert Mustacchi 	if (dev->devi_node_state > DS_ATTACHED) {
99220c06695SRobert Mustacchi 		if (mdb_devinfo2driver(addr, dname, sizeof (dname)) == 0)
99320c06695SRobert Mustacchi 			hdname = B_TRUE;
99420c06695SRobert Mustacchi 	}
99520c06695SRobert Mustacchi 
99620c06695SRobert Mustacchi 	/*
99720c06695SRobert Mustacchi 	 * If a filter is installed and we don't have the driver's name, we
99820c06695SRobert Mustacchi 	 * always skip it. Also if the filter doesn't match, then we'll also
99920c06695SRobert Mustacchi 	 * skip the driver.
100020c06695SRobert Mustacchi 	 */
100120c06695SRobert Mustacchi 	if (data->di_filter != NULL &&
100220c06695SRobert Mustacchi 	    (!hdname || strcmp(data->di_filter, dname) != 0)) {
100320c06695SRobert Mustacchi 		return (WALK_NEXT);
100420c06695SRobert Mustacchi 	}
100520c06695SRobert Mustacchi 
1006*e386d4ddSRobert Mustacchi 	if (data->di_instance != UINT64_MAX &&
1007*e386d4ddSRobert Mustacchi 	    data->di_instance != (uint64_t)dev->devi_instance) {
1008*e386d4ddSRobert Mustacchi 		return (WALK_NEXT);
1009*e386d4ddSRobert Mustacchi 	}
1010*e386d4ddSRobert Mustacchi 
101120c06695SRobert Mustacchi 	/*
101220c06695SRobert Mustacchi 	 * If we are output to a pipe, we only print the address of the
101320c06695SRobert Mustacchi 	 * devinfo_t.
101420c06695SRobert Mustacchi 	 */
101520c06695SRobert Mustacchi 	if (data->di_flags & DEVINFO_PIPE) {
101620c06695SRobert Mustacchi 		mdb_printf("%-0?p\n", addr);
101720c06695SRobert Mustacchi 		return (WALK_NEXT);
101820c06695SRobert Mustacchi 	}
101920c06695SRobert Mustacchi 
10207c478bd9Sstevel@tonic-gate 	mdb_inc_indent(din->din_depth * DEVINFO_TREE_INDENT);
10217c478bd9Sstevel@tonic-gate 	if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD))
10227c478bd9Sstevel@tonic-gate 		mdb_printf("%<b>");
10237c478bd9Sstevel@tonic-gate 	mdb_printf("%-0?p %s", addr, binding_name);
10247c478bd9Sstevel@tonic-gate 	if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD))
10257c478bd9Sstevel@tonic-gate 		mdb_printf("%</b>");
10267c478bd9Sstevel@tonic-gate 	if (dev->devi_instance >= 0)
10277c478bd9Sstevel@tonic-gate 		mdb_printf(", instance #%d", dev->devi_instance);
1028f723faa1Seschrock 
1029f723faa1Seschrock 	if (dev->devi_node_state < DS_ATTACHED)
10307c478bd9Sstevel@tonic-gate 		mdb_printf(" (driver not attached)");
103120c06695SRobert Mustacchi 	else if (hdname == B_FALSE)
1032f723faa1Seschrock 		mdb_printf(" (could not determine driver name)");
1033f723faa1Seschrock 	else
1034f723faa1Seschrock 		mdb_printf(" (driver name: %s)", dname);
1035f723faa1Seschrock 
10367c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
10377c478bd9Sstevel@tonic-gate 	if (data->di_flags & DEVINFO_VERBOSE) {
10387c478bd9Sstevel@tonic-gate 		mdb_inc_indent(DEVINFO_PROPLIST_INDENT);
10397c478bd9Sstevel@tonic-gate 		devinfo_print_props("System", dev->devi_sys_prop_ptr);
10407c478bd9Sstevel@tonic-gate 		devinfo_print_props("Driver", dev->devi_drv_prop_ptr);
10417c478bd9Sstevel@tonic-gate 		devinfo_print_props("Hardware", dev->devi_hw_prop_ptr);
10427c478bd9Sstevel@tonic-gate 		devinfo_print_props("Global", global_props);
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 		devinfo_print_pathing(dev->devi_mdi_component,
10457c478bd9Sstevel@tonic-gate 		    dev->devi_mdi_client);
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 		mdb_dec_indent(DEVINFO_PROPLIST_INDENT);
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	mdb_dec_indent(din->din_depth * DEVINFO_TREE_INDENT);
10517c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
10527c478bd9Sstevel@tonic-gate }
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10557c478bd9Sstevel@tonic-gate int
prtconf(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)10567c478bd9Sstevel@tonic-gate prtconf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
10577c478bd9Sstevel@tonic-gate {
10587c478bd9Sstevel@tonic-gate 	devinfo_cb_data_t data;
105914ef2b2fSdmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
10607c478bd9Sstevel@tonic-gate 	int status;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	data.di_flags = DEVINFO_PARENT | DEVINFO_CHILD;
106320c06695SRobert Mustacchi 	data.di_filter = NULL;
1064*e386d4ddSRobert Mustacchi 	data.di_instance = UINT64_MAX;
106520c06695SRobert Mustacchi 
106620c06695SRobert Mustacchi 	if (flags & DCMD_PIPE_OUT)
106720c06695SRobert Mustacchi 		data.di_flags |= DEVINFO_PIPE;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
107020c06695SRobert Mustacchi 	    'd', MDB_OPT_STR, &data.di_filter,
1071*e386d4ddSRobert Mustacchi 	    'i', MDB_OPT_UINT64, &data.di_instance,
10727c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, DEVINFO_VERBOSE, &data.di_flags,
10737c478bd9Sstevel@tonic-gate 	    'p', MDB_OPT_CLRBITS, DEVINFO_CHILD, &data.di_flags,
10747c478bd9Sstevel@tonic-gate 	    'c', MDB_OPT_CLRBITS, DEVINFO_PARENT, &data.di_flags, NULL) != argc)
10757c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
10767c478bd9Sstevel@tonic-gate 
107714ef2b2fSdmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
107814ef2b2fSdmick 		mdb_warn("failed to read 'top_devinfo'");
1079892ad162SToomas Soome 		return (0);
108014ef2b2fSdmick 	}
108114ef2b2fSdmick 
10827c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
10837c478bd9Sstevel@tonic-gate 		addr = devinfo_root;
10847c478bd9Sstevel@tonic-gate 		if (data.di_flags & DEVINFO_VERBOSE)
10857c478bd9Sstevel@tonic-gate 			data.di_flags |= DEVINFO_ALLBOLD;
10867c478bd9Sstevel@tonic-gate 	}
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	data.di_base = addr;
108920c06695SRobert Mustacchi 	if (!(flags & DCMD_PIPE_OUT))
109020c06695SRobert Mustacchi 		mdb_printf("%<u>%-?s %-50s%</u>\n", "DEVINFO", "NAME");
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	if ((data.di_flags & (DEVINFO_PARENT | DEVINFO_CHILD)) ==
10937c478bd9Sstevel@tonic-gate 	    (DEVINFO_PARENT | DEVINFO_CHILD)) {
10947c478bd9Sstevel@tonic-gate 		status = mdb_pwalk("devinfo",
10957c478bd9Sstevel@tonic-gate 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
10967c478bd9Sstevel@tonic-gate 	} else if (data.di_flags & DEVINFO_PARENT) {
10977c478bd9Sstevel@tonic-gate 		status = mdb_pwalk("devinfo_parents",
10987c478bd9Sstevel@tonic-gate 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
10997c478bd9Sstevel@tonic-gate 	} else if (data.di_flags & DEVINFO_CHILD) {
11007c478bd9Sstevel@tonic-gate 		status = mdb_pwalk("devinfo_children",
11017c478bd9Sstevel@tonic-gate 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
11027c478bd9Sstevel@tonic-gate 	} else {
11037c478bd9Sstevel@tonic-gate 		devinfo_node_t din;
11047c478bd9Sstevel@tonic-gate 		if (mdb_vread(&din.din_dev, sizeof (din.din_dev), addr) == -1) {
11057c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read device");
11067c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
11077c478bd9Sstevel@tonic-gate 		}
11087c478bd9Sstevel@tonic-gate 		din.din_depth = 0;
11097c478bd9Sstevel@tonic-gate 		return (devinfo_print(addr, (struct dev_info *)&din, &data));
11107c478bd9Sstevel@tonic-gate 	}
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	if (status == -1) {
11137c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk devinfo tree");
11147c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
11157c478bd9Sstevel@tonic-gate 	}
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11217c478bd9Sstevel@tonic-gate int
devinfo(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)11227c478bd9Sstevel@tonic-gate devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
11237c478bd9Sstevel@tonic-gate {
11247c478bd9Sstevel@tonic-gate 	char tmpstr[MODMAXNAMELEN];
11257c478bd9Sstevel@tonic-gate 	char nodename[MODMAXNAMELEN];
1126f4da9be0Scth 	char bindname[MAXPATHLEN];
11277c478bd9Sstevel@tonic-gate 	int size, length;
11287c478bd9Sstevel@tonic-gate 	struct dev_info devi;
11297c478bd9Sstevel@tonic-gate 	devinfo_node_t din;
11307c478bd9Sstevel@tonic-gate 	devinfo_cb_data_t data;
1131*e386d4ddSRobert Mustacchi 	char *bus = NULL;
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t devi_state_masks[] = {
11347c478bd9Sstevel@tonic-gate 	    { "DEVICE_OFFLINE",	DEVI_DEVICE_OFFLINE,	DEVI_DEVICE_OFFLINE },
11357c478bd9Sstevel@tonic-gate 	    { "DEVICE_DOWN",	DEVI_DEVICE_DOWN,	DEVI_DEVICE_DOWN },
11367c478bd9Sstevel@tonic-gate 	    { "DEVICE_DEGRADED", DEVI_DEVICE_DEGRADED,	DEVI_DEVICE_DEGRADED },
1137f4da9be0Scth 	    { "DEVICE_REMOVED", DEVI_DEVICE_REMOVED,	DEVI_DEVICE_REMOVED },
11387c478bd9Sstevel@tonic-gate 	    { "BUS_QUIESCED",	DEVI_BUS_QUIESCED,	DEVI_BUS_QUIESCED },
11397c478bd9Sstevel@tonic-gate 	    { "BUS_DOWN",	DEVI_BUS_DOWN,		DEVI_BUS_DOWN },
11407c478bd9Sstevel@tonic-gate 	    { "NDI_CONFIG",	DEVI_NDI_CONFIG,	DEVI_NDI_CONFIG	},
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	    { "S_ATTACHING",	DEVI_S_ATTACHING,	DEVI_S_ATTACHING },
11437c478bd9Sstevel@tonic-gate 	    { "S_DETACHING",	DEVI_S_DETACHING,	DEVI_S_DETACHING },
11447c478bd9Sstevel@tonic-gate 	    { "S_ONLINING",	DEVI_S_ONLINING,	DEVI_S_ONLINING },
11457c478bd9Sstevel@tonic-gate 	    { "S_OFFLINING",	DEVI_S_OFFLINING,	DEVI_S_OFFLINING },
11467c478bd9Sstevel@tonic-gate 	    { "S_INVOKING_DACF", DEVI_S_INVOKING_DACF,	DEVI_S_INVOKING_DACF },
11477c478bd9Sstevel@tonic-gate 	    { "S_UNBOUND",	DEVI_S_UNBOUND,		DEVI_S_UNBOUND },
11487c478bd9Sstevel@tonic-gate 	    { "S_REPORT",	DEVI_S_REPORT,		DEVI_S_REPORT },
11497c478bd9Sstevel@tonic-gate 	    { "S_EVADD",	DEVI_S_EVADD,		DEVI_S_EVADD },
11507c478bd9Sstevel@tonic-gate 	    { "S_EVREMOVE",	DEVI_S_EVREMOVE,	DEVI_S_EVREMOVE },
1151f4da9be0Scth 	    { "S_NEED_RESET",	DEVI_S_NEED_RESET,	DEVI_S_NEED_RESET },
11527c478bd9Sstevel@tonic-gate 	    { NULL,		0,			0 }
11537c478bd9Sstevel@tonic-gate 	};
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t devi_flags_masks[] = {
11567c478bd9Sstevel@tonic-gate 	    { "BUSY",		DEVI_BUSY,		DEVI_BUSY },
11577c478bd9Sstevel@tonic-gate 	    { "MADE_CHILDREN",	DEVI_MADE_CHILDREN,	DEVI_MADE_CHILDREN },
11587c478bd9Sstevel@tonic-gate 	    { "ATTACHED_CHILDREN",
11597c478bd9Sstevel@tonic-gate 				DEVI_ATTACHED_CHILDREN,	DEVI_ATTACHED_CHILDREN},
11607c478bd9Sstevel@tonic-gate 	    { "BRANCH_HELD",	DEVI_BRANCH_HELD,	DEVI_BRANCH_HELD },
1161f4da9be0Scth 	    { "NO_BIND",	DEVI_NO_BIND,		DEVI_NO_BIND },
11628451e9c3SGavin Maltby 	    { "DEVI_CACHED_DEVID",
11638451e9c3SGavin Maltby 				DEVI_CACHED_DEVID,	DEVI_CACHED_DEVID },
1164f4da9be0Scth 	    { "PHCI_SIGNALS_VHCI",
1165f4da9be0Scth 				DEVI_PHCI_SIGNALS_VHCI,
1166f4da9be0Scth 				DEVI_PHCI_SIGNALS_VHCI },
1167f4da9be0Scth 	    { "REBIND",		DEVI_REBIND,		DEVI_REBIND },
11687c478bd9Sstevel@tonic-gate 	    { NULL,		0,			0 }
11697c478bd9Sstevel@tonic-gate 	};
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	data.di_flags = DEVINFO_VERBOSE;
11727c478bd9Sstevel@tonic-gate 	data.di_base = addr;
117320c06695SRobert Mustacchi 	data.di_filter = NULL;
1174*e386d4ddSRobert Mustacchi 	data.di_instance = UINT64_MAX;
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
1177*e386d4ddSRobert Mustacchi 	    'b', MDB_OPT_STR, &bus,
1178*e386d4ddSRobert Mustacchi 	    'd', MDB_OPT_SETBITS, DEVINFO_DRIVER, &data.di_flags,
11797c478bd9Sstevel@tonic-gate 	    'q', MDB_OPT_CLRBITS, DEVINFO_VERBOSE, &data.di_flags,
11807c478bd9Sstevel@tonic-gate 	    's', MDB_OPT_SETBITS, DEVINFO_SUMMARY, &data.di_flags, NULL)
11817c478bd9Sstevel@tonic-gate 	    != argc)
11827c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
11837c478bd9Sstevel@tonic-gate 
1184*e386d4ddSRobert Mustacchi 	if (bus != NULL && data.di_flags != DEVINFO_VERBOSE) {
1185*e386d4ddSRobert Mustacchi 		mdb_warn("the -b option cannot be used with other options\n");
1186*e386d4ddSRobert Mustacchi 		return (DCMD_USAGE);
1187*e386d4ddSRobert Mustacchi 	}
1188*e386d4ddSRobert Mustacchi 
1189*e386d4ddSRobert Mustacchi 	if ((data.di_flags & DEVINFO_DRIVER) != 0 &&
1190*e386d4ddSRobert Mustacchi 	    data.di_flags != (DEVINFO_DRIVER | DEVINFO_VERBOSE)) {
1191*e386d4ddSRobert Mustacchi 		mdb_warn("the -d option cannot be used with other options\n");
1192*e386d4ddSRobert Mustacchi 		return (DCMD_USAGE);
1193*e386d4ddSRobert Mustacchi 	}
1194*e386d4ddSRobert Mustacchi 
11957c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
11967c478bd9Sstevel@tonic-gate 		mdb_warn(
11977c478bd9Sstevel@tonic-gate 		    "devinfo doesn't give global information (try prtconf)\n");
11987c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate 
1201*e386d4ddSRobert Mustacchi 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
1202*e386d4ddSRobert Mustacchi 		mdb_warn("failed to read device");
1203*e386d4ddSRobert Mustacchi 		return (DCMD_ERR);
1204*e386d4ddSRobert Mustacchi 	}
1205*e386d4ddSRobert Mustacchi 
1206*e386d4ddSRobert Mustacchi 	if (bus != NULL) {
1207*e386d4ddSRobert Mustacchi 		if (strcmp(bus, "pcie") == 0) {
1208*e386d4ddSRobert Mustacchi 			uintptr_t bus_addr;
1209*e386d4ddSRobert Mustacchi 			if (pcie_bus_match(&devi, &bus_addr)) {
1210*e386d4ddSRobert Mustacchi 				mdb_printf("%p\n", bus_addr);
1211*e386d4ddSRobert Mustacchi 				return (DCMD_OK);
1212*e386d4ddSRobert Mustacchi 			} else {
1213*e386d4ddSRobert Mustacchi 				mdb_warn("%p does not have a PCIe bus\n",
1214*e386d4ddSRobert Mustacchi 				    addr);
1215*e386d4ddSRobert Mustacchi 			}
1216*e386d4ddSRobert Mustacchi 		}
1217*e386d4ddSRobert Mustacchi 
1218*e386d4ddSRobert Mustacchi 		mdb_warn("unknown bus type: %s\n", bus);
1219*e386d4ddSRobert Mustacchi 		return (DCMD_ERR);
1220*e386d4ddSRobert Mustacchi 	}
1221*e386d4ddSRobert Mustacchi 
1222*e386d4ddSRobert Mustacchi 	if ((data.di_flags & DEVINFO_DRIVER) != 0) {
1223*e386d4ddSRobert Mustacchi 		if ((flags & DCMD_PIPE_OUT) != 0 &&
1224*e386d4ddSRobert Mustacchi 		    devi.devi_driver_data == NULL) {
1225*e386d4ddSRobert Mustacchi 			return (DCMD_OK);
1226*e386d4ddSRobert Mustacchi 		}
1227*e386d4ddSRobert Mustacchi 		mdb_printf("%p\n", devi.devi_driver_data);
1228*e386d4ddSRobert Mustacchi 		return (DCMD_OK);
1229*e386d4ddSRobert Mustacchi 	}
1230*e386d4ddSRobert Mustacchi 
1231*e386d4ddSRobert Mustacchi 	if (DCMD_HDRSPEC(flags) && data.di_flags & DEVINFO_SUMMARY) {
12327c478bd9Sstevel@tonic-gate 		mdb_printf(
12337c478bd9Sstevel@tonic-gate 		    "%-?s %5s %?s %-20s %-s\n"
12347c478bd9Sstevel@tonic-gate 		    "%-?s %5s %?s %-20s %-s\n"
12357c478bd9Sstevel@tonic-gate 		    "%<u>%-?s %5s %?s %-20s %-15s%</u>\n",
12367c478bd9Sstevel@tonic-gate 		    "DEVINFO", "MAJ",  "REFCNT",   "NODENAME", "NODESTATE",
12377c478bd9Sstevel@tonic-gate 		    "",        "INST", "CIRCULAR", "BINDNAME", "STATE",
12387c478bd9Sstevel@tonic-gate 		    "",        "",     "THREAD",   "",         "FLAGS");
12397c478bd9Sstevel@tonic-gate 	}
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	if (data.di_flags & DEVINFO_SUMMARY) {
12427c478bd9Sstevel@tonic-gate 		*nodename = '\0';
12437c478bd9Sstevel@tonic-gate 		size = sizeof (nodename);
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 		if ((length = mdb_readstr(tmpstr, size,
12467c478bd9Sstevel@tonic-gate 		    (uintptr_t)devi.devi_node_name)) > 0) {
12477c478bd9Sstevel@tonic-gate 			strcat(nodename, tmpstr);
12487c478bd9Sstevel@tonic-gate 			size -= length;
12497c478bd9Sstevel@tonic-gate 		}
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 		if (devi.devi_addr != NULL && mdb_readstr(tmpstr, size - 1,
12527c478bd9Sstevel@tonic-gate 		    (uintptr_t)devi.devi_addr) > 0) {
12537c478bd9Sstevel@tonic-gate 			strcat(nodename, "@");
12547c478bd9Sstevel@tonic-gate 			strcat(nodename, tmpstr);
12557c478bd9Sstevel@tonic-gate 		}
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 		if (mdb_readstr(bindname, sizeof (bindname),
12587c478bd9Sstevel@tonic-gate 		    (uintptr_t)devi.devi_binding_name) == -1)
12597c478bd9Sstevel@tonic-gate 			*bindname = '\0';
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 		mdb_printf("%0?p %5d %?d %-20s %s\n",
12627c478bd9Sstevel@tonic-gate 		    addr, devi.devi_major, devi.devi_ref, nodename,
12637c478bd9Sstevel@tonic-gate 		    di_state[MIN(devi.devi_node_state + 1, DI_STATE_MAX)]);
12647c478bd9Sstevel@tonic-gate 		mdb_printf("%?s %5d %?d %-20s <%b>\n",
12657c478bd9Sstevel@tonic-gate 		    "", devi.devi_instance, devi.devi_circular, bindname,
12667c478bd9Sstevel@tonic-gate 		    devi.devi_state, devi_state_masks);
12677c478bd9Sstevel@tonic-gate 		mdb_printf("%?s %5s %?p %-20s <%b>\n\n",
12687c478bd9Sstevel@tonic-gate 		    "", "", devi.devi_busy_thread, "",
12697c478bd9Sstevel@tonic-gate 		    devi.devi_flags, devi_flags_masks);
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
12727c478bd9Sstevel@tonic-gate 	} else {
12737c478bd9Sstevel@tonic-gate 		din.din_dev = devi;
12747c478bd9Sstevel@tonic-gate 		din.din_depth = 0;
12757c478bd9Sstevel@tonic-gate 		return (devinfo_print(addr, (struct dev_info *)&din, &data));
12767c478bd9Sstevel@tonic-gate 	}
12777c478bd9Sstevel@tonic-gate }
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12807c478bd9Sstevel@tonic-gate int
m2d_walk_dinfo(uintptr_t addr,struct dev_info * di,char * mod_name)12817c478bd9Sstevel@tonic-gate m2d_walk_dinfo(uintptr_t addr, struct dev_info *di, char *mod_name)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate 	char name[MODMAXNAMELEN];
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, MODMAXNAMELEN,
12867c478bd9Sstevel@tonic-gate 	    (uintptr_t)di->devi_binding_name) == -1) {
12877c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devi_binding_name at %p",
12887c478bd9Sstevel@tonic-gate 		    di->devi_binding_name);
12897c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
12907c478bd9Sstevel@tonic-gate 	}
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	if (strcmp(name, mod_name) == 0)
12937c478bd9Sstevel@tonic-gate 		mdb_printf("%p\n", addr);
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12997c478bd9Sstevel@tonic-gate int
modctl2devinfo(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)13007c478bd9Sstevel@tonic-gate modctl2devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
13017c478bd9Sstevel@tonic-gate {
13027c478bd9Sstevel@tonic-gate 	struct modctl modctl;
13037c478bd9Sstevel@tonic-gate 	char name[MODMAXNAMELEN];
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
13067c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	if (mdb_vread(&modctl, sizeof (modctl), addr) == -1) {
13097c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read modctl at %p", addr);
13107c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
13117c478bd9Sstevel@tonic-gate 	}
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, MODMAXNAMELEN,
13147c478bd9Sstevel@tonic-gate 	    (uintptr_t)modctl.mod_modname) == -1) {
13157c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read modname at %p", modctl.mod_modname);
13167c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
13177c478bd9Sstevel@tonic-gate 	}
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	if (mdb_walk("devinfo", (mdb_walk_cb_t)m2d_walk_dinfo, name) == -1) {
13207c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk devinfo");
13217c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate static int
major_to_addr(major_t major,uintptr_t * vaddr)13287c478bd9Sstevel@tonic-gate major_to_addr(major_t major, uintptr_t *vaddr)
13297c478bd9Sstevel@tonic-gate {
13307c478bd9Sstevel@tonic-gate 	uint_t devcnt;
13317c478bd9Sstevel@tonic-gate 	uintptr_t devnamesp;
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devcnt, "devcnt") == -1) {
13347c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devcnt'");
13357c478bd9Sstevel@tonic-gate 		return (-1);
13367c478bd9Sstevel@tonic-gate 	}
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devnamesp, "devnamesp") == -1) {
13397c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devnamesp'");
13407c478bd9Sstevel@tonic-gate 		return (-1);
13417c478bd9Sstevel@tonic-gate 	}
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	if (major >= devcnt) {
13447c478bd9Sstevel@tonic-gate 		mdb_warn("%x is out of range [0x0-0x%x]\n", major, devcnt - 1);
13457c478bd9Sstevel@tonic-gate 		return (-1);
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	*vaddr = devnamesp + (major * sizeof (struct devnames));
13497c478bd9Sstevel@tonic-gate 	return (0);
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
13537c478bd9Sstevel@tonic-gate int
devnames(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)13547c478bd9Sstevel@tonic-gate devnames(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
13557c478bd9Sstevel@tonic-gate {
13567c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t dn_flag_bits[] = {
13577c478bd9Sstevel@tonic-gate 		{ "DN_CONF_PARSED",	DN_CONF_PARSED, DN_CONF_PARSED },
13587c478bd9Sstevel@tonic-gate 		{ "DN_DRIVER_BUSY",	DN_DRIVER_BUSY, DN_DRIVER_BUSY },
13597c478bd9Sstevel@tonic-gate 		{ "DN_DRIVER_HELD",	DN_DRIVER_HELD, DN_DRIVER_HELD },
13607c478bd9Sstevel@tonic-gate 		{ "DN_TAKEN_GETUDEV",	DN_TAKEN_GETUDEV, DN_TAKEN_GETUDEV },
13617c478bd9Sstevel@tonic-gate 		{ "DN_DRIVER_REMOVED",	DN_DRIVER_REMOVED, DN_DRIVER_REMOVED},
13627c478bd9Sstevel@tonic-gate 		{ "DN_FORCE_ATTACH",	DN_FORCE_ATTACH, DN_FORCE_ATTACH},
13637c478bd9Sstevel@tonic-gate 		{ "DN_LEAF_DRIVER",	DN_LEAF_DRIVER, DN_LEAF_DRIVER},
13647c478bd9Sstevel@tonic-gate 		{ "DN_NETWORK_DRIVER",	DN_NETWORK_DRIVER, DN_NETWORK_DRIVER},
13657c478bd9Sstevel@tonic-gate 		{ "DN_NO_AUTODETACH",	DN_NO_AUTODETACH, DN_NO_AUTODETACH },
13666e13b8c3Scth 		{ "DN_GLDV3_DRIVER",	DN_GLDV3_DRIVER, DN_GLDV3_DRIVER},
136752cac543Sramat 		{ "DN_PHCI_DRIVER",	DN_PHCI_DRIVER, DN_PHCI_DRIVER},
1368602ca9eaScth 		{ "DN_OPEN_RETURNS_EINTR", \
1369602ca9eaScth 				DN_OPEN_RETURNS_EINTR, DN_OPEN_RETURNS_EINTR},
1370602ca9eaScth 		{ "DN_SCSI_SIZE_CLEAN",	DN_SCSI_SIZE_CLEAN, DN_SCSI_SIZE_CLEAN},
1371095be824SCathy Zhou 		{ "DN_NETWORK_PHYSDRIVER", \
1372095be824SCathy Zhou 				DN_NETWORK_PHYSDRIVER, DN_NETWORK_PHYSDRIVER},
13737c478bd9Sstevel@tonic-gate 		{ NULL, 0, 0 }
13747c478bd9Sstevel@tonic-gate 	};
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	const mdb_arg_t *argp = NULL;
13777c478bd9Sstevel@tonic-gate 	uint_t opt_v = FALSE, opt_m = FALSE;
13787c478bd9Sstevel@tonic-gate 	major_t major;
13797c478bd9Sstevel@tonic-gate 	size_t i;
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	char name[MODMAXNAMELEN + 1];
13827c478bd9Sstevel@tonic-gate 	struct devnames dn;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	if ((i = mdb_getopts(argc, argv,
13857c478bd9Sstevel@tonic-gate 	    'm', MDB_OPT_SETBITS, TRUE, &opt_m,
13867c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v,
13877c478bd9Sstevel@tonic-gate 	    NULL)) != argc) {
13887c478bd9Sstevel@tonic-gate 		if (argc - i > 1)
13897c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
13907c478bd9Sstevel@tonic-gate 		argp = &argv[i];
13917c478bd9Sstevel@tonic-gate 	}
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	if (opt_m) {
13947c478bd9Sstevel@tonic-gate 		if (!(flags & DCMD_ADDRSPEC))
13957c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 		if (major_to_addr(addr, &addr) == -1)
13987c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	} else if (!(flags & DCMD_ADDRSPEC)) {
14017c478bd9Sstevel@tonic-gate 		if (argp == NULL) {
14027c478bd9Sstevel@tonic-gate 			if (mdb_walk_dcmd("devnames", "devnames", argc, argv)) {
14037c478bd9Sstevel@tonic-gate 				mdb_warn("failed to walk devnames");
14047c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
14057c478bd9Sstevel@tonic-gate 			}
14067c478bd9Sstevel@tonic-gate 			return (DCMD_OK);
14077c478bd9Sstevel@tonic-gate 		}
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
14107c478bd9Sstevel@tonic-gate 			major = (major_t)argp->a_un.a_val;
14117c478bd9Sstevel@tonic-gate 		else
14127c478bd9Sstevel@tonic-gate 			major = (major_t)mdb_strtoull(argp->a_un.a_str);
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 		if (major_to_addr(major, &addr) == -1)
14157c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
14167c478bd9Sstevel@tonic-gate 	}
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dn, sizeof (struct devnames), addr) == -1) {
14197c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devnames struct at %p", addr);
14207c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
14217c478bd9Sstevel@tonic-gate 	}
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
14247c478bd9Sstevel@tonic-gate 		if (opt_v)
14257c478bd9Sstevel@tonic-gate 			mdb_printf("%<u>%-16s%</u>\n", "NAME");
14267c478bd9Sstevel@tonic-gate 		else
14277c478bd9Sstevel@tonic-gate 			mdb_printf("%<u>%-16s %-?s%</u>\n", "NAME", "DN_HEAD");
14287c478bd9Sstevel@tonic-gate 	}
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_LOOP) && (dn.dn_name == NULL))
14317c478bd9Sstevel@tonic-gate 		return (DCMD_OK); /* Skip empty slots if we're printing table */
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, sizeof (name), (uintptr_t)dn.dn_name) == -1)
14347c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(name, sizeof (name), "0x%p", dn.dn_name);
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	if (opt_v) {
14377c478bd9Sstevel@tonic-gate 		ddi_prop_list_t prop_list;
14387c478bd9Sstevel@tonic-gate 		mdb_printf("%<b>%-16s%</b>\n", name);
14397c478bd9Sstevel@tonic-gate 		mdb_inc_indent(2);
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 		mdb_printf("          flags %b\n", dn.dn_flags, dn_flag_bits);
14427c478bd9Sstevel@tonic-gate 		mdb_printf("             pl %p\n", (void *)dn.dn_pl);
14437c478bd9Sstevel@tonic-gate 		mdb_printf("           head %p\n", dn.dn_head);
14447c478bd9Sstevel@tonic-gate 		mdb_printf("       instance %d\n", dn.dn_instance);
14457c478bd9Sstevel@tonic-gate 		mdb_printf("         inlist %p\n", dn.dn_inlist);
14467c478bd9Sstevel@tonic-gate 		mdb_printf("global_prop_ptr %p\n", dn.dn_global_prop_ptr);
14477c478bd9Sstevel@tonic-gate 		if (mdb_vread(&prop_list, sizeof (ddi_prop_list_t),
14487c478bd9Sstevel@tonic-gate 		    (uintptr_t)dn.dn_global_prop_ptr) != -1) {
14497c478bd9Sstevel@tonic-gate 			devinfo_print_props(NULL, prop_list.prop_list);
14507c478bd9Sstevel@tonic-gate 		}
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 		mdb_dec_indent(2);
14537c478bd9Sstevel@tonic-gate 	} else
14547c478bd9Sstevel@tonic-gate 		mdb_printf("%-16s %-?p\n", name, dn.dn_head);
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14607c478bd9Sstevel@tonic-gate int
name2major(uintptr_t vaddr,uint_t flags,int argc,const mdb_arg_t * argv)14617c478bd9Sstevel@tonic-gate name2major(uintptr_t vaddr, uint_t flags, int argc, const mdb_arg_t *argv)
14627c478bd9Sstevel@tonic-gate {
14637c478bd9Sstevel@tonic-gate 	major_t major;
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC)
14667c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
14697c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	if (mdb_name_to_major(argv->a_un.a_str, &major) != 0) {
14727c478bd9Sstevel@tonic-gate 		mdb_warn("failed to convert name to major number\n");
14737c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
14747c478bd9Sstevel@tonic-gate 	}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	mdb_printf("0x%x\n", major);
14777c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate /*
14817c478bd9Sstevel@tonic-gate  * Get a numerical argument of a dcmd from addr if an address is specified
14827c478bd9Sstevel@tonic-gate  * or from argv if no address is specified. Return the argument in ret.
14837c478bd9Sstevel@tonic-gate  */
14847c478bd9Sstevel@tonic-gate static int
getarg(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,uintptr_t * ret)14857c478bd9Sstevel@tonic-gate getarg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
14867c478bd9Sstevel@tonic-gate     uintptr_t *ret)
14877c478bd9Sstevel@tonic-gate {
14887c478bd9Sstevel@tonic-gate 	if (argc == 0 && (flags & DCMD_ADDRSPEC)) {
14897c478bd9Sstevel@tonic-gate 		*ret = addr;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	} else if (argc == 1 && !(flags & DCMD_ADDRSPEC)) {
14927c478bd9Sstevel@tonic-gate 		*ret = (argv[0].a_type == MDB_TYPE_IMMEDIATE) ?
14937c478bd9Sstevel@tonic-gate 		    (uintptr_t)argv[0].a_un.a_val :
14947c478bd9Sstevel@tonic-gate 		    (uintptr_t)mdb_strtoull(argv->a_un.a_str);
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	} else {
14977c478bd9Sstevel@tonic-gate 		return (-1);
14987c478bd9Sstevel@tonic-gate 	}
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	return (0);
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15047c478bd9Sstevel@tonic-gate int
major2name(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)15057c478bd9Sstevel@tonic-gate major2name(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
15067c478bd9Sstevel@tonic-gate {
15077c478bd9Sstevel@tonic-gate 	uintptr_t major;
15087c478bd9Sstevel@tonic-gate 	const char *name;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	if (getarg(addr, flags, argc, argv, &major) < 0)
15117c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 	if ((name = mdb_major_to_name((major_t)major)) == NULL) {
15147c478bd9Sstevel@tonic-gate 		mdb_warn("failed to convert major number to name\n");
15157c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
15167c478bd9Sstevel@tonic-gate 	}
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	mdb_printf("%s\n", name);
15197c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15237c478bd9Sstevel@tonic-gate int
dev2major(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)15247c478bd9Sstevel@tonic-gate dev2major(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate 	uintptr_t dev;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	if (getarg(addr, flags, argc, argv, &dev) < 0)
15297c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
15327c478bd9Sstevel@tonic-gate 		mdb_printf("%x\n", getmajor(dev));
15337c478bd9Sstevel@tonic-gate 	else
15347c478bd9Sstevel@tonic-gate 		mdb_printf("0x%x (0t%d)\n", getmajor(dev), getmajor(dev));
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
15377c478bd9Sstevel@tonic-gate }
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15407c478bd9Sstevel@tonic-gate int
dev2minor(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)15417c478bd9Sstevel@tonic-gate dev2minor(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
15427c478bd9Sstevel@tonic-gate {
15437c478bd9Sstevel@tonic-gate 	uintptr_t dev;
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	if (getarg(addr, flags, argc, argv, &dev) < 0)
15467c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
15497c478bd9Sstevel@tonic-gate 		mdb_printf("%x\n", getminor(dev));
15507c478bd9Sstevel@tonic-gate 	else
15517c478bd9Sstevel@tonic-gate 		mdb_printf("0x%x (0t%d)\n", getminor(dev), getminor(dev));
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
15547c478bd9Sstevel@tonic-gate }
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15577c478bd9Sstevel@tonic-gate int
devt(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)15587c478bd9Sstevel@tonic-gate devt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
15597c478bd9Sstevel@tonic-gate {
15607c478bd9Sstevel@tonic-gate 	uintptr_t dev;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	if (getarg(addr, flags, argc, argv, &dev) < 0)
15637c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
15667c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%10s%</u>  %<u>%10s%</u>\n", "MAJOR",
15677c478bd9Sstevel@tonic-gate 		    "MINOR");
15687c478bd9Sstevel@tonic-gate 	}
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	mdb_printf("%10d  %10d\n", getmajor(dev), getminor(dev));
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
15737c478bd9Sstevel@tonic-gate }
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15767c478bd9Sstevel@tonic-gate int
softstate(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)15777c478bd9Sstevel@tonic-gate softstate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
15787c478bd9Sstevel@tonic-gate {
15797c478bd9Sstevel@tonic-gate 	uintptr_t statep;
15807c478bd9Sstevel@tonic-gate 	int instance;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	if (argc != 1) {
15847c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
15857c478bd9Sstevel@tonic-gate 	}
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 	if (argv[0].a_type == MDB_TYPE_IMMEDIATE)
15887c478bd9Sstevel@tonic-gate 		instance = argv[0].a_un.a_val;
15897c478bd9Sstevel@tonic-gate 	else
15907c478bd9Sstevel@tonic-gate 		instance = mdb_strtoull(argv->a_un.a_str);
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	if (mdb_get_soft_state_byaddr(addr, instance, &statep, NULL, 0) == -1) {
15937c478bd9Sstevel@tonic-gate 		if (errno == ENOENT) {
15947c478bd9Sstevel@tonic-gate 			mdb_warn("instance %d unused\n", instance);
15957c478bd9Sstevel@tonic-gate 		} else {
15967c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't determine softstate for "
15977c478bd9Sstevel@tonic-gate 			    "instance %d", instance);
15987c478bd9Sstevel@tonic-gate 		}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
16017c478bd9Sstevel@tonic-gate 	}
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	mdb_printf("%p\n", statep);
16047c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
16057c478bd9Sstevel@tonic-gate }
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate /*
16087c478bd9Sstevel@tonic-gate  * Walker for all possible pointers to a driver state struct in an
16097c478bd9Sstevel@tonic-gate  * i_ddi_soft_state instance chain.  Returns all non-NULL pointers.
16107c478bd9Sstevel@tonic-gate  */
16117c478bd9Sstevel@tonic-gate typedef struct soft_state_walk {
16127c478bd9Sstevel@tonic-gate 	struct i_ddi_soft_state	ssw_ss;	/* Local copy of i_ddi_soft_state */
16137c478bd9Sstevel@tonic-gate 	void		**ssw_pointers;	/* to driver state structs */
16147c478bd9Sstevel@tonic-gate 	uint_t		ssw_index;	/* array entry we're using */
16157c478bd9Sstevel@tonic-gate } soft_state_walk_t;
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate int
soft_state_walk_init(mdb_walk_state_t * wsp)16187c478bd9Sstevel@tonic-gate soft_state_walk_init(mdb_walk_state_t *wsp)
16197c478bd9Sstevel@tonic-gate {
16207c478bd9Sstevel@tonic-gate 	soft_state_walk_t *sst;
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 
1623892ad162SToomas Soome 	if (wsp->walk_addr == 0)
16247c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	sst = mdb_zalloc(sizeof (soft_state_walk_t), UM_SLEEP|UM_GC);
16277c478bd9Sstevel@tonic-gate 	wsp->walk_data = sst;
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	if (mdb_vread(&(sst->ssw_ss), sizeof (sst->ssw_ss), wsp->walk_addr) !=
16317c478bd9Sstevel@tonic-gate 	    sizeof (sst->ssw_ss)) {
16327c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read i_ddi_soft_state at %p",
16337c478bd9Sstevel@tonic-gate 		    wsp->walk_addr);
16347c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
16357c478bd9Sstevel@tonic-gate 	}
16367c478bd9Sstevel@tonic-gate 
1637b73314f0SRobert Mustacchi 	if (sst->ssw_ss.size == 0) {
1638b73314f0SRobert Mustacchi 		mdb_warn("read invalid softstate: softstate item size is "
1639b73314f0SRobert Mustacchi 		    "zero\n");
1640b73314f0SRobert Mustacchi 		return (WALK_ERR);
1641b73314f0SRobert Mustacchi 	}
1642b73314f0SRobert Mustacchi 
1643b73314f0SRobert Mustacchi 	if (sst->ssw_ss.n_items == 0) {
1644b73314f0SRobert Mustacchi 		mdb_warn("read invalid softstate: softstate has no entries\n");
1645b73314f0SRobert Mustacchi 		return (WALK_ERR);
1646b73314f0SRobert Mustacchi 	}
1647b73314f0SRobert Mustacchi 
1648b73314f0SRobert Mustacchi 	/*
1649b73314f0SRobert Mustacchi 	 * Try and pick arbitrary bounds to try and catch an illegal soft state
1650b73314f0SRobert Mustacchi 	 * structure. While these may be larger than we expect, we also don't
1651b73314f0SRobert Mustacchi 	 * want to throw off a valid use.
1652b73314f0SRobert Mustacchi 	 */
1653b73314f0SRobert Mustacchi 	if (sst->ssw_ss.size >= 1024 * 1024 * 1024) {
1654b73314f0SRobert Mustacchi 		mdb_warn("softstate size is larger than 1 GiB (0x%lx), invalid "
1655b73314f0SRobert Mustacchi 		    "softstate?\n", sst->ssw_ss.size);
1656b73314f0SRobert Mustacchi 		return (WALK_ERR);
1657b73314f0SRobert Mustacchi 	}
1658b73314f0SRobert Mustacchi 
1659b73314f0SRobert Mustacchi 	if (sst->ssw_ss.n_items >= INT_MAX / 1024) {
1660b73314f0SRobert Mustacchi 		mdb_warn("softstate item count seems too large: found %ld "
1661b73314f0SRobert Mustacchi 		    "items\n", sst->ssw_ss.n_items);
1662b73314f0SRobert Mustacchi 		return (WALK_ERR);
1663b73314f0SRobert Mustacchi 	}
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 	/* Read array of pointers to state structs into local storage. */
16667c478bd9Sstevel@tonic-gate 	sst->ssw_pointers = mdb_alloc((sst->ssw_ss.n_items * sizeof (void *)),
16677c478bd9Sstevel@tonic-gate 	    UM_SLEEP|UM_GC);
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	if (mdb_vread(sst->ssw_pointers, (sst->ssw_ss.n_items *
16707c478bd9Sstevel@tonic-gate 	    sizeof (void *)), (uintptr_t)sst->ssw_ss.array) !=
16717c478bd9Sstevel@tonic-gate 	    (sst->ssw_ss.n_items * sizeof (void *))) {
16727c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read i_ddi_soft_state at %p",
16737c478bd9Sstevel@tonic-gate 		    wsp->walk_addr);
16747c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
16757c478bd9Sstevel@tonic-gate 	}
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	sst->ssw_index = 0;
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
16807c478bd9Sstevel@tonic-gate }
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate int
soft_state_walk_step(mdb_walk_state_t * wsp)16837c478bd9Sstevel@tonic-gate soft_state_walk_step(mdb_walk_state_t *wsp)
16847c478bd9Sstevel@tonic-gate {
16857c478bd9Sstevel@tonic-gate 	soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data;
16867c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 	/*
16907c478bd9Sstevel@tonic-gate 	 * If the entry indexed has a valid pointer to a soft state struct,
16917c478bd9Sstevel@tonic-gate 	 * invoke caller's callback func.
16927c478bd9Sstevel@tonic-gate 	 */
16937c478bd9Sstevel@tonic-gate 	if (sst->ssw_pointers[sst->ssw_index] != NULL) {
16947c478bd9Sstevel@tonic-gate 		status = wsp->walk_callback(
16957c478bd9Sstevel@tonic-gate 		    (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL,
16967c478bd9Sstevel@tonic-gate 		    wsp->walk_cbdata);
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	sst->ssw_index += 1;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	if (sst->ssw_index == sst->ssw_ss.n_items)
17027c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	return (status);
17057c478bd9Sstevel@tonic-gate }
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate int
soft_state_all_walk_step(mdb_walk_state_t * wsp)17087c478bd9Sstevel@tonic-gate soft_state_all_walk_step(mdb_walk_state_t *wsp)
17097c478bd9Sstevel@tonic-gate {
17107c478bd9Sstevel@tonic-gate 	soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data;
17117c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(
17157c478bd9Sstevel@tonic-gate 	    (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL,
17167c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	sst->ssw_index += 1;
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	if (sst->ssw_index == sst->ssw_ss.n_items)
17217c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	return (status);
17247c478bd9Sstevel@tonic-gate }
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17277c478bd9Sstevel@tonic-gate int
devbindings(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)17287c478bd9Sstevel@tonic-gate devbindings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
17297c478bd9Sstevel@tonic-gate {
17307c478bd9Sstevel@tonic-gate 	const mdb_arg_t *arg;
17317c478bd9Sstevel@tonic-gate 	struct devnames dn;
17327c478bd9Sstevel@tonic-gate 	uintptr_t dn_addr;
17337c478bd9Sstevel@tonic-gate 	major_t major;
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) && argc < 1)
17367c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
17397c478bd9Sstevel@tonic-gate 		/*
17407c478bd9Sstevel@tonic-gate 		 * If there's an address, then it's a major number
17417c478bd9Sstevel@tonic-gate 		 */
17427c478bd9Sstevel@tonic-gate 		major = addr;
17437c478bd9Sstevel@tonic-gate 	} else {
17447c478bd9Sstevel@tonic-gate 		/*
17457c478bd9Sstevel@tonic-gate 		 * We interpret the last argument. Any other arguments are
17467c478bd9Sstevel@tonic-gate 		 * forwarded to "devinfo"
17477c478bd9Sstevel@tonic-gate 		 */
17487c478bd9Sstevel@tonic-gate 		arg = &argv[argc - 1];
17497c478bd9Sstevel@tonic-gate 		argc--;
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 		if (arg->a_type == MDB_TYPE_IMMEDIATE) {
17527c478bd9Sstevel@tonic-gate 			major = (uintptr_t)arg->a_un.a_val;
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 		} else if (arg->a_un.a_str[0] == '-') {
17557c478bd9Sstevel@tonic-gate 			/* the argument shouldn't be an option */
17567c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 		} else if (isdigit(arg->a_un.a_str[0])) {
17597c478bd9Sstevel@tonic-gate 			major = (uintptr_t)mdb_strtoull(arg->a_un.a_str);
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 		} else {
17627c478bd9Sstevel@tonic-gate 			if (mdb_name_to_major(arg->a_un.a_str, &major) != 0) {
17637c478bd9Sstevel@tonic-gate 				mdb_warn("failed to get major number for %s\n",
17647c478bd9Sstevel@tonic-gate 				    arg->a_un.a_str);
17657c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
17667c478bd9Sstevel@tonic-gate 			}
17677c478bd9Sstevel@tonic-gate 		}
17687c478bd9Sstevel@tonic-gate 	}
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	if (major_to_addr(major, &dn_addr) != 0)
17717c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dn, sizeof (struct devnames), dn_addr) == -1) {
17747c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devnames array at %p", dn_addr);
17757c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
17767c478bd9Sstevel@tonic-gate 	}
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 	if (mdb_pwalk_dcmd("devi_next", "devinfo", argc, argv,
17797c478bd9Sstevel@tonic-gate 	    (uintptr_t)dn.dn_head) != 0) {
17807c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk the devinfo chain at %p", dn.dn_head);
17817c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
17827c478bd9Sstevel@tonic-gate 	}
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
17857c478bd9Sstevel@tonic-gate }
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate /*
17887c478bd9Sstevel@tonic-gate  * walk binding hashtable (as of of driver names (e.g., mb_hashtab))
17897c478bd9Sstevel@tonic-gate  */
17907c478bd9Sstevel@tonic-gate int
binding_hash_walk_init(mdb_walk_state_t * wsp)17917c478bd9Sstevel@tonic-gate binding_hash_walk_init(mdb_walk_state_t *wsp)
17927c478bd9Sstevel@tonic-gate {
1793892ad162SToomas Soome 	if (wsp->walk_addr == 0)
17947c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (void *) * MOD_BIND_HASHSIZE,
17977c478bd9Sstevel@tonic-gate 	    UM_SLEEP|UM_GC);
17987c478bd9Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (void *) * MOD_BIND_HASHSIZE,
17997c478bd9Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
18007c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read mb_hashtab");
18017c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
18027c478bd9Sstevel@tonic-gate 	}
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 	wsp->walk_arg = 0;	/* index into mb_hashtab array to start */
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
18077c478bd9Sstevel@tonic-gate }
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate int
binding_hash_walk_step(mdb_walk_state_t * wsp)18107c478bd9Sstevel@tonic-gate binding_hash_walk_step(mdb_walk_state_t *wsp)
18117c478bd9Sstevel@tonic-gate {
18127c478bd9Sstevel@tonic-gate 	int		status;
18137c478bd9Sstevel@tonic-gate 	uintptr_t	bind_p;
18147c478bd9Sstevel@tonic-gate 	struct bind	bind;
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	/*
18187c478bd9Sstevel@tonic-gate 	 * Walk the singly-linked list of struct bind
18197c478bd9Sstevel@tonic-gate 	 */
18207c478bd9Sstevel@tonic-gate 	bind_p = ((uintptr_t *)wsp->walk_data)[(ulong_t)wsp->walk_arg];
1821892ad162SToomas Soome 	while (bind_p != 0) {
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 		if (mdb_vread(&bind, sizeof (bind), bind_p) == -1) {
18247c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read bind struct at %p",
18257c478bd9Sstevel@tonic-gate 			    wsp->walk_addr);
18267c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
18277c478bd9Sstevel@tonic-gate 		}
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 		if ((status = wsp->walk_callback(bind_p, &bind,
18307c478bd9Sstevel@tonic-gate 		    wsp->walk_cbdata)) != WALK_NEXT) {
18317c478bd9Sstevel@tonic-gate 			return (status);
18327c478bd9Sstevel@tonic-gate 		}
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 		bind_p = (uintptr_t)bind.b_next;
18357c478bd9Sstevel@tonic-gate 	}
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	wsp->walk_arg = (void *)((char *)wsp->walk_arg + 1);
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 	if (wsp->walk_arg == (void *)(MOD_BIND_HASHSIZE - 1))
18407c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18467c478bd9Sstevel@tonic-gate int
binding_hash_entry(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)18477c478bd9Sstevel@tonic-gate binding_hash_entry(uintptr_t addr, uint_t flags, int argc,
18487c478bd9Sstevel@tonic-gate     const mdb_arg_t *argv)
18497c478bd9Sstevel@tonic-gate {
1850892ad162SToomas Soome 	struct bind	bind;
18517c478bd9Sstevel@tonic-gate 	/* Arbitrary lengths based on output format below */
1852f4da9be0Scth 	char name[MAXPATHLEN] = "???";
1853f4da9be0Scth 	char bind_name[MAXPATHLEN] = "<null>";
18547c478bd9Sstevel@tonic-gate 
1855892ad162SToomas Soome 	if ((flags & DCMD_ADDRSPEC) == 0)
18567c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	/* Allow null addresses to be passed (as from a walker) */
1859892ad162SToomas Soome 	if (addr == 0)
18607c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 	if (mdb_vread(&bind, sizeof (bind), addr) == -1) {
18637c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read struct bind at %p", addr);
18647c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
18657c478bd9Sstevel@tonic-gate 	}
18667c478bd9Sstevel@tonic-gate 
18677c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
1868f4da9be0Scth 		mdb_printf("%<u>%?s% %-5s %s%</u>\n",
1869f4da9be0Scth 		    "NEXT", "MAJOR", "NAME(S)");
18707c478bd9Sstevel@tonic-gate 	}
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, sizeof (name), (uintptr_t)bind.b_name) == -1)
18737c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'name'");
18747c478bd9Sstevel@tonic-gate 
1875f4da9be0Scth 	/* There may be bind_name, so this may fail */
1876f4da9be0Scth 	if (mdb_readstr(bind_name, sizeof (bind_name),
1877f4da9be0Scth 	    (uintptr_t)bind.b_bind_name) == -1) {
1878f4da9be0Scth 		mdb_printf("%?p %5d %s\n",
1879f4da9be0Scth 		    bind.b_next, bind.b_num, name);
1880f4da9be0Scth 	} else {
1881f4da9be0Scth 		mdb_printf("%?p %5d %s %s\n",
1882f4da9be0Scth 		    bind.b_next, bind.b_num, name, bind_name);
1883f4da9be0Scth 	}
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate typedef struct devinfo_audit_log_walk_data {
18897c478bd9Sstevel@tonic-gate 	devinfo_audit_t dil_buf;	/* buffer of last entry */
18907c478bd9Sstevel@tonic-gate 	uintptr_t dil_base;		/* starting address of log buffer */
18917c478bd9Sstevel@tonic-gate 	int dil_max;			/* maximum index */
18927c478bd9Sstevel@tonic-gate 	int dil_start;			/* starting index */
18937c478bd9Sstevel@tonic-gate 	int dil_index;			/* current walking index */
18947c478bd9Sstevel@tonic-gate } devinfo_audit_log_walk_data_t;
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate int
devinfo_audit_log_walk_init(mdb_walk_state_t * wsp)18977c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_init(mdb_walk_state_t *wsp)
18987c478bd9Sstevel@tonic-gate {
18997c478bd9Sstevel@tonic-gate 	devinfo_log_header_t header;
19007c478bd9Sstevel@tonic-gate 	devinfo_audit_log_walk_data_t *dil;
19017c478bd9Sstevel@tonic-gate 	uintptr_t devinfo_audit_log;
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	/* read in devinfo_log_header structure */
19047c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&devinfo_audit_log, "devinfo_audit_log") == -1) {
19057c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'devinfo_audit_log'");
19067c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
19077c478bd9Sstevel@tonic-gate 	}
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	if (mdb_vread(&header, sizeof (devinfo_log_header_t),
19107c478bd9Sstevel@tonic-gate 	    devinfo_audit_log) == -1) {
19117c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devinfo_log_header at %p",
19127c478bd9Sstevel@tonic-gate 		    devinfo_audit_log);
19137c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
19147c478bd9Sstevel@tonic-gate 	}
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 	dil = mdb_zalloc(sizeof (devinfo_audit_log_walk_data_t), UM_SLEEP);
19177c478bd9Sstevel@tonic-gate 	wsp->walk_data = dil;
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	dil->dil_start = dil->dil_index = header.dh_curr;
19207c478bd9Sstevel@tonic-gate 	dil->dil_max = header.dh_max;
19217c478bd9Sstevel@tonic-gate 	if (dil->dil_start < 0)		/* no log entries */
19227c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 	dil->dil_base = devinfo_audit_log +
19257c478bd9Sstevel@tonic-gate 	    offsetof(devinfo_log_header_t, dh_entry);
19267c478bd9Sstevel@tonic-gate 	wsp->walk_addr = dil->dil_base +
19277c478bd9Sstevel@tonic-gate 	    dil->dil_index * sizeof (devinfo_audit_t);
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
19307c478bd9Sstevel@tonic-gate }
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate int
devinfo_audit_log_walk_step(mdb_walk_state_t * wsp)19337c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_step(mdb_walk_state_t *wsp)
19347c478bd9Sstevel@tonic-gate {
19357c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
19367c478bd9Sstevel@tonic-gate 	devinfo_audit_log_walk_data_t *dil = wsp->walk_data;
19377c478bd9Sstevel@tonic-gate 	devinfo_audit_t *da = &dil->dil_buf;
19387c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 	/* read in current entry and invoke callback */
1941892ad162SToomas Soome 	if (addr == 0)
19427c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dil->dil_buf, sizeof (devinfo_audit_t), addr) == -1) {
19457c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo_audit at %p", addr);
19467c478bd9Sstevel@tonic-gate 		status = WALK_DONE;
19477c478bd9Sstevel@tonic-gate 	}
19487c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, da, wsp->walk_cbdata);
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	/* step to the previous log entry in time */
19517c478bd9Sstevel@tonic-gate 	if (--dil->dil_index < 0)
19527c478bd9Sstevel@tonic-gate 		dil->dil_index += dil->dil_max;
19537c478bd9Sstevel@tonic-gate 	if (dil->dil_index == dil->dil_start) {
1954892ad162SToomas Soome 		wsp->walk_addr = 0;
19557c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
19567c478bd9Sstevel@tonic-gate 	}
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 	wsp->walk_addr = dil->dil_base +
19597c478bd9Sstevel@tonic-gate 	    dil->dil_index * sizeof (devinfo_audit_t);
19607c478bd9Sstevel@tonic-gate 	return (status);
19617c478bd9Sstevel@tonic-gate }
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate void
devinfo_audit_log_walk_fini(mdb_walk_state_t * wsp)19647c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_fini(mdb_walk_state_t *wsp)
19657c478bd9Sstevel@tonic-gate {
19667c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (devinfo_audit_log_walk_data_t));
19677c478bd9Sstevel@tonic-gate }
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate /*
19707c478bd9Sstevel@tonic-gate  * display devinfo_audit_t stack trace
19717c478bd9Sstevel@tonic-gate  */
19727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19737c478bd9Sstevel@tonic-gate int
devinfo_audit(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)19747c478bd9Sstevel@tonic-gate devinfo_audit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
19757c478bd9Sstevel@tonic-gate {
19767c478bd9Sstevel@tonic-gate 	uint_t verbose = FALSE;
19777c478bd9Sstevel@tonic-gate 	devinfo_audit_t da;
19787c478bd9Sstevel@tonic-gate 	int i, depth;
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
19817c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
19847c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
19857c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
19887c478bd9Sstevel@tonic-gate 		mdb_printf(" %-?s %16s %-?s %-?s %5s\n",
19897c478bd9Sstevel@tonic-gate 		    "AUDIT", "TIMESTAMP", "THREAD", "DEVINFO", "STATE");
19907c478bd9Sstevel@tonic-gate 	}
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 	if (mdb_vread(&da, sizeof (da), addr) == -1) {
19937c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devinfo_audit at %p", addr);
19947c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
19957c478bd9Sstevel@tonic-gate 	}
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	mdb_printf(" %0?p %16llx %0?p %0?p %s\n",
19987c478bd9Sstevel@tonic-gate 	    addr, da.da_timestamp, da.da_thread, da.da_devinfo,
19997c478bd9Sstevel@tonic-gate 	    di_state[MIN(da.da_node_state + 1, DI_STATE_MAX)]);
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 	if (!verbose)
20027c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate 	mdb_inc_indent(4);
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	/*
20077c478bd9Sstevel@tonic-gate 	 * Guard against bogus da_depth in case the devinfo_audit_t
20087c478bd9Sstevel@tonic-gate 	 * is corrupt or the address does not really refer to a
20097c478bd9Sstevel@tonic-gate 	 * devinfo_audit_t.
20107c478bd9Sstevel@tonic-gate 	 */
20117c478bd9Sstevel@tonic-gate 	depth = MIN(da.da_depth, DDI_STACK_DEPTH);
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
20147c478bd9Sstevel@tonic-gate 		mdb_printf("%a\n", da.da_stack[i]);
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
20177c478bd9Sstevel@tonic-gate 	mdb_dec_indent(4);
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
20207c478bd9Sstevel@tonic-gate }
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate int
devinfo_audit_log(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)20237c478bd9Sstevel@tonic-gate devinfo_audit_log(uintptr_t addr, uint_t flags, int argc,
20247c478bd9Sstevel@tonic-gate     const mdb_arg_t *argv)
20257c478bd9Sstevel@tonic-gate {
20267c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC)
20277c478bd9Sstevel@tonic-gate 		return (devinfo_audit(addr, flags, argc, argv));
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate 	(void) mdb_walk_dcmd("devinfo_audit_log", "devinfo_audit", argc, argv);
20307c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
20317c478bd9Sstevel@tonic-gate }
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate typedef struct devinfo_audit_node_walk_data {
20347c478bd9Sstevel@tonic-gate 	devinfo_audit_t dih_buf;	/* buffer of last entry */
20357c478bd9Sstevel@tonic-gate 	uintptr_t dih_dip;		/* address of dev_info */
20367c478bd9Sstevel@tonic-gate 	int dih_on_devinfo;		/* devi_audit on dev_info struct */
20377c478bd9Sstevel@tonic-gate } devinfo_audit_node_walk_data_t;
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate int
devinfo_audit_node_walk_init(mdb_walk_state_t * wsp)20407c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_init(mdb_walk_state_t *wsp)
20417c478bd9Sstevel@tonic-gate {
20427c478bd9Sstevel@tonic-gate 	devinfo_audit_node_walk_data_t *dih;
20437c478bd9Sstevel@tonic-gate 	devinfo_audit_t *da;
20447c478bd9Sstevel@tonic-gate 	struct dev_info devi;
20457c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	/* read in devinfo structure */
20487c478bd9Sstevel@tonic-gate 	if (mdb_vread(&devi, sizeof (struct dev_info), addr) == -1) {
20497c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read dev_info at %p", addr);
20507c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
20517c478bd9Sstevel@tonic-gate 	}
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	dih = mdb_zalloc(sizeof (devinfo_audit_node_walk_data_t), UM_SLEEP);
20547c478bd9Sstevel@tonic-gate 	wsp->walk_data = dih;
20557c478bd9Sstevel@tonic-gate 	da = &dih->dih_buf;
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	/* read in devi_audit structure */
20587c478bd9Sstevel@tonic-gate 	if (mdb_vread(da, sizeof (devinfo_audit_t), (uintptr_t)devi.devi_audit)
20597c478bd9Sstevel@tonic-gate 	    == -1) {
20607c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read devi_audit at %p", devi.devi_audit);
20617c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
20627c478bd9Sstevel@tonic-gate 	}
20637c478bd9Sstevel@tonic-gate 	dih->dih_dip = addr;
20647c478bd9Sstevel@tonic-gate 	dih->dih_on_devinfo = 1;
20657c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)devi.devi_audit;
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
20687c478bd9Sstevel@tonic-gate }
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate int
devinfo_audit_node_walk_step(mdb_walk_state_t * wsp)20717c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_step(mdb_walk_state_t *wsp)
20727c478bd9Sstevel@tonic-gate {
20737c478bd9Sstevel@tonic-gate 	uintptr_t addr;
20747c478bd9Sstevel@tonic-gate 	devinfo_audit_node_walk_data_t *dih = wsp->walk_data;
20757c478bd9Sstevel@tonic-gate 	devinfo_audit_t *da = &dih->dih_buf;
20767c478bd9Sstevel@tonic-gate 
2077892ad162SToomas Soome 	if (wsp->walk_addr == 0)
20787c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
20797c478bd9Sstevel@tonic-gate 	(void) wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata);
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate skip:
20827c478bd9Sstevel@tonic-gate 	/* read in previous entry */
20837c478bd9Sstevel@tonic-gate 	if ((addr = (uintptr_t)da->da_lastlog) == 0)
20847c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	if (mdb_vread(&dih->dih_buf, sizeof (devinfo_audit_t), addr) == -1) {
20877c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo_audit at %p", addr);
20887c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
20897c478bd9Sstevel@tonic-gate 	}
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 	/* check if last log was over-written */
20927c478bd9Sstevel@tonic-gate 	if ((uintptr_t)da->da_devinfo != dih->dih_dip)
20937c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 	/*
20967c478bd9Sstevel@tonic-gate 	 * skip the first common log entry, which is a duplicate of
20977c478bd9Sstevel@tonic-gate 	 * the devi_audit buffer on the dev_info structure
20987c478bd9Sstevel@tonic-gate 	 */
20997c478bd9Sstevel@tonic-gate 	if (dih->dih_on_devinfo) {
21007c478bd9Sstevel@tonic-gate 		dih->dih_on_devinfo = 0;
21017c478bd9Sstevel@tonic-gate 		goto skip;
21027c478bd9Sstevel@tonic-gate 	}
21037c478bd9Sstevel@tonic-gate 	wsp->walk_addr = addr;
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
21067c478bd9Sstevel@tonic-gate }
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate void
devinfo_audit_node_walk_fini(mdb_walk_state_t * wsp)21097c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_fini(mdb_walk_state_t *wsp)
21107c478bd9Sstevel@tonic-gate {
21117c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (devinfo_audit_node_walk_data_t));
21127c478bd9Sstevel@tonic-gate }
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate int
devinfo_audit_node(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)21157c478bd9Sstevel@tonic-gate devinfo_audit_node(uintptr_t addr, uint_t flags, int argc,
21167c478bd9Sstevel@tonic-gate     const mdb_arg_t *argv)
21177c478bd9Sstevel@tonic-gate {
21187c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
21197c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	(void) mdb_pwalk_dcmd("devinfo_audit_node", "devinfo_audit",
21227c478bd9Sstevel@tonic-gate 	    argc, argv, addr);
21237c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
21247c478bd9Sstevel@tonic-gate }
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate /*
21277c478bd9Sstevel@tonic-gate  * mdb support for per-devinfo fault management data
21287c478bd9Sstevel@tonic-gate  */
21297c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21307c478bd9Sstevel@tonic-gate int
devinfo_fm(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)21317c478bd9Sstevel@tonic-gate devinfo_fm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
21327c478bd9Sstevel@tonic-gate {
21337c478bd9Sstevel@tonic-gate 	struct dev_info devi;
21347c478bd9Sstevel@tonic-gate 	struct i_ddi_fmhdl fhdl;
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
21377c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
2140a5667d81SCheng Sean Ye 		mdb_printf("%<u>%?s IPL CAPS DROP FMCFULL FMCMISS ACCERR "
2141a5667d81SCheng Sean Ye 		    "DMAERR %?s %?s%</u>\n", "ADDR", "DMACACHE", "ACCCACHE");
21427c478bd9Sstevel@tonic-gate 	}
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
21457c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo struct at %p", addr);
21467c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
21477c478bd9Sstevel@tonic-gate 	}
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	if (mdb_vread(&fhdl, sizeof (fhdl), (uintptr_t)devi.devi_fmhdl) == -1) {
21507c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read devinfo fm struct at %p",
21517c478bd9Sstevel@tonic-gate 		    (uintptr_t)devi.devi_fmhdl);
21527c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
21537c478bd9Sstevel@tonic-gate 	}
21547c478bd9Sstevel@tonic-gate 
2155a5667d81SCheng Sean Ye 	mdb_printf("%?p %3u %c%c%c%c %4llu %7llu %7llu %6llu %6llu %?p %?p\n",
21567c478bd9Sstevel@tonic-gate 	    (uintptr_t)devi.devi_fmhdl, fhdl.fh_ibc,
21577c478bd9Sstevel@tonic-gate 	    (DDI_FM_EREPORT_CAP(fhdl.fh_cap) ? 'E' : '-'),
21587c478bd9Sstevel@tonic-gate 	    (DDI_FM_ERRCB_CAP(fhdl.fh_cap) ? 'C' : '-'),
21597c478bd9Sstevel@tonic-gate 	    (DDI_FM_ACC_ERR_CAP(fhdl.fh_cap) ? 'A' : '-'),
21607c478bd9Sstevel@tonic-gate 	    (DDI_FM_DMA_ERR_CAP(fhdl.fh_cap) ? 'D' : '-'),
21617c478bd9Sstevel@tonic-gate 	    fhdl.fh_kstat.fek_erpt_dropped.value.ui64,
21627c478bd9Sstevel@tonic-gate 	    fhdl.fh_kstat.fek_fmc_full.value.ui64,
2163a5667d81SCheng Sean Ye 	    fhdl.fh_kstat.fek_fmc_miss.value.ui64,
21647c478bd9Sstevel@tonic-gate 	    fhdl.fh_kstat.fek_acc_err.value.ui64,
21657c478bd9Sstevel@tonic-gate 	    fhdl.fh_kstat.fek_dma_err.value.ui64,
21667c478bd9Sstevel@tonic-gate 	    fhdl.fh_dma_cache, fhdl.fh_acc_cache);
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
21707c478bd9Sstevel@tonic-gate }
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21737c478bd9Sstevel@tonic-gate int
devinfo_fmce(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)21747c478bd9Sstevel@tonic-gate devinfo_fmce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
21757c478bd9Sstevel@tonic-gate {
21767c478bd9Sstevel@tonic-gate 	struct i_ddi_fmc_entry fce;
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
21797c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
2182a5667d81SCheng Sean Ye 		mdb_printf("%<u>%?s %?s %?s%</u>\n", "ADDR",
21837c478bd9Sstevel@tonic-gate 		    "RESOURCE", "BUS_SPECIFIC");
21847c478bd9Sstevel@tonic-gate 	}
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	if (mdb_vread(&fce, sizeof (fce), addr) == -1) {
21877c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read fm cache struct at %p", addr);
21887c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
21897c478bd9Sstevel@tonic-gate 	}
21907c478bd9Sstevel@tonic-gate 
2191a5667d81SCheng Sean Ye 	mdb_printf("%?p %?p %?p\n",
21927c478bd9Sstevel@tonic-gate 	    (uintptr_t)addr, fce.fce_resource, fce.fce_bus_specific);
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
21967c478bd9Sstevel@tonic-gate }
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate int
devinfo_fmc_walk_init(mdb_walk_state_t * wsp)21997c478bd9Sstevel@tonic-gate devinfo_fmc_walk_init(mdb_walk_state_t *wsp)
22007c478bd9Sstevel@tonic-gate {
22017c478bd9Sstevel@tonic-gate 	struct i_ddi_fmc fec;
22027c478bd9Sstevel@tonic-gate 
2203892ad162SToomas Soome 	if (wsp->walk_addr == 0)
22047c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	if (mdb_vread(&fec, sizeof (fec), wsp->walk_addr) == -1) {
22077c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read fm cache at %p", wsp->walk_addr);
22087c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
22097c478bd9Sstevel@tonic-gate 	}
22107c478bd9Sstevel@tonic-gate 
2211a5667d81SCheng Sean Ye 	if (fec.fc_head == NULL)
22127c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
22137c478bd9Sstevel@tonic-gate 
2214a5667d81SCheng Sean Ye 	wsp->walk_addr = (uintptr_t)fec.fc_head;
22157c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
22167c478bd9Sstevel@tonic-gate }
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate int
devinfo_fmc_walk_step(mdb_walk_state_t * wsp)22197c478bd9Sstevel@tonic-gate devinfo_fmc_walk_step(mdb_walk_state_t *wsp)
22207c478bd9Sstevel@tonic-gate {
22217c478bd9Sstevel@tonic-gate 	int status;
22227c478bd9Sstevel@tonic-gate 	struct i_ddi_fmc_entry fe;
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 	if (mdb_vread(&fe, sizeof (fe), wsp->walk_addr) == -1) {
22257c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read active fm cache entry at %p",
22267c478bd9Sstevel@tonic-gate 		    wsp->walk_addr);
22277c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
22287c478bd9Sstevel@tonic-gate 	}
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &fe, wsp->walk_cbdata);
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 	if (fe.fce_next == NULL)
22337c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)fe.fce_next;
22367c478bd9Sstevel@tonic-gate 	return (status);
22377c478bd9Sstevel@tonic-gate }
22387c478bd9Sstevel@tonic-gate 
22397c478bd9Sstevel@tonic-gate int
minornode_walk_init(mdb_walk_state_t * wsp)22407c478bd9Sstevel@tonic-gate minornode_walk_init(mdb_walk_state_t *wsp)
22417c478bd9Sstevel@tonic-gate {
22427c478bd9Sstevel@tonic-gate 	struct dev_info di;
22437c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
22447c478bd9Sstevel@tonic-gate 
2245892ad162SToomas Soome 	if (addr == 0) {
22467c478bd9Sstevel@tonic-gate 		mdb_warn("a dev_info struct address must be provided\n");
22477c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
22487c478bd9Sstevel@tonic-gate 	}
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 	if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1) {
22517c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dev_info struct at %p", addr);
22527c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
22537c478bd9Sstevel@tonic-gate 	}
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)di.devi_minor;
22567c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
22577c478bd9Sstevel@tonic-gate }
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate int
minornode_walk_step(mdb_walk_state_t * wsp)22607c478bd9Sstevel@tonic-gate minornode_walk_step(mdb_walk_state_t *wsp)
22617c478bd9Sstevel@tonic-gate {
22627c478bd9Sstevel@tonic-gate 	struct ddi_minor_data md;
22637c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
22647c478bd9Sstevel@tonic-gate 
2265892ad162SToomas Soome 	if (addr == 0)
22667c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	if (mdb_vread(&md, sizeof (md), addr) == -1) {
22697c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read dev_info struct at %p", addr);
22707c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
22717c478bd9Sstevel@tonic-gate 	}
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)md.next;
22747c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &md, wsp->walk_cbdata));
22757c478bd9Sstevel@tonic-gate }
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate static const char *const md_type[] = {
22787c478bd9Sstevel@tonic-gate 	"DDI_MINOR",
22797c478bd9Sstevel@tonic-gate 	"DDI_ALIAS",
22807c478bd9Sstevel@tonic-gate 	"DDI_DEFAULT",
22817c478bd9Sstevel@tonic-gate 	"DDI_I_PATH",
22827c478bd9Sstevel@tonic-gate 	"?"
22837c478bd9Sstevel@tonic-gate };
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate #define	MD_TYPE_MAX	((sizeof (md_type) / sizeof (char *)) - 1)
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22887c478bd9Sstevel@tonic-gate static int
print_minornode(uintptr_t addr,const void * arg,void * data)22897c478bd9Sstevel@tonic-gate print_minornode(uintptr_t addr, const void *arg, void *data)
22907c478bd9Sstevel@tonic-gate {
22917c478bd9Sstevel@tonic-gate 	char name[128];
22927c478bd9Sstevel@tonic-gate 	char nodetype[128];
22937c478bd9Sstevel@tonic-gate 	char *spectype;
22947c478bd9Sstevel@tonic-gate 	struct ddi_minor_data *mdp = (struct ddi_minor_data *)arg;
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	if (mdb_readstr(name, sizeof (name), (uintptr_t)mdp->ddm_name) == -1)
22977c478bd9Sstevel@tonic-gate 		*name = '\0';
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 	if (mdb_readstr(nodetype, sizeof (nodetype),
23007c478bd9Sstevel@tonic-gate 	    (uintptr_t)mdp->ddm_node_type) == -1)
23017c478bd9Sstevel@tonic-gate 		*nodetype = '\0';
23027c478bd9Sstevel@tonic-gate 
23037c478bd9Sstevel@tonic-gate 	switch (mdp->ddm_spec_type) {
23047c478bd9Sstevel@tonic-gate 		case S_IFCHR:	spectype = "c";	break;
23057c478bd9Sstevel@tonic-gate 		case S_IFBLK:	spectype = "b";	break;
23067c478bd9Sstevel@tonic-gate 		default:	spectype = "?";	break;
23077c478bd9Sstevel@tonic-gate 	}
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 	mdb_printf("%?p %16lx %-4s %-11s %-10s %s\n",
23107c478bd9Sstevel@tonic-gate 	    addr, mdp->ddm_dev, spectype, md_type[MIN(mdp->type, MD_TYPE_MAX)],
23117c478bd9Sstevel@tonic-gate 	    name, nodetype);
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
23147c478bd9Sstevel@tonic-gate }
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate /*ARGSUSED*/
23177c478bd9Sstevel@tonic-gate int
minornodes(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)23187c478bd9Sstevel@tonic-gate minornodes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
23197c478bd9Sstevel@tonic-gate {
23207c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
23217c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
23247c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%?s %16s %-4s %-11s %-10s %-16s%</u>\n",
23257c478bd9Sstevel@tonic-gate 		    "ADDR", "DEV", "SPEC", "TYPE", "NAME", "NODETYPE");
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("minornode", print_minornode, NULL, addr) == -1) {
23287c478bd9Sstevel@tonic-gate 		mdb_warn("can't walk minornode");
23297c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
23307c478bd9Sstevel@tonic-gate 	}
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
23337c478bd9Sstevel@tonic-gate }
2334