Home | History | Annotate | Download | only in genunix
      1      0    stevel /*
      2      0    stevel  * CDDL HEADER START
      3      0    stevel  *
      4      0    stevel  * The contents of this file are subject to the terms of the
      5   1993     ramat  * Common Development and Distribution License (the "License").
      6   1993     ramat  * You may not use this file except in compliance with the License.
      7      0    stevel  *
      8      0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0    stevel  * or http://www.opensolaris.org/os/licensing.
     10      0    stevel  * See the License for the specific language governing permissions
     11      0    stevel  * and limitations under the License.
     12      0    stevel  *
     13      0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0    stevel  *
     19      0    stevel  * CDDL HEADER END
     20      0    stevel  */
     21      0    stevel /*
     22  10788     Cathy  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0    stevel  * Use is subject to license terms.
     24      0    stevel  */
     25      0    stevel 
     26      0    stevel #include <sys/types.h>
     27      0    stevel #include <sys/sysmacros.h>
     28      0    stevel #include <sys/dditypes.h>
     29      0    stevel #include <sys/ddi_impldefs.h>
     30      0    stevel #include <sys/ddifm.h>
     31      0    stevel #include <sys/ddipropdefs.h>
     32      0    stevel #include <sys/modctl.h>
     33      0    stevel #include <sys/hwconf.h>
     34      0    stevel #include <sys/stat.h>
     35      0    stevel #include <errno.h>
     36      0    stevel #include <sys/sunmdi.h>
     37      0    stevel #include <sys/mdi_impldefs.h>
     38      0    stevel 
     39      0    stevel #include <ctype.h>
     40      0    stevel #include <mdb/mdb_modapi.h>
     41      0    stevel #include <mdb/mdb_ks.h>
     42      0    stevel 
     43      0    stevel #include "nvpair.h"
     44  10923      Evan #include "devinfo.h"
     45      0    stevel 
     46      0    stevel #define	DEVINFO_TREE_INDENT	4	/* Indent for devs one down in tree */
     47      0    stevel #define	DEVINFO_PROP_INDENT	4	/* Indent for properties */
     48      0    stevel #define	DEVINFO_PROPLIST_INDENT	8	/* Indent for properties lists */
     49      0    stevel 
     50      0    stevel /*
     51      0    stevel  * devinfo node state map. Used by devinfo() and devinfo_audit().
     52      0    stevel  * Long words are deliberately truncated so that output
     53      0    stevel  * fits in 80 column with 64-bit addresses.
     54      0    stevel  */
     55      0    stevel static const char *const di_state[] = {
     56      0    stevel 	"DS_INVAL",
     57      0    stevel 	"DS_PROTO",
     58      0    stevel 	"DS_LINKED",
     59      0    stevel 	"DS_BOUND",
     60      0    stevel 	"DS_INITIA",
     61      0    stevel 	"DS_PROBED",
     62      0    stevel 	"DS_ATTACH",
     63      0    stevel 	"DS_READY",
     64      0    stevel 	"?"
     65      0    stevel };
     66      0    stevel 
     67      0    stevel #define	DI_STATE_MAX	((sizeof (di_state) / sizeof (char *)) - 1)
     68      0    stevel 
     69      0    stevel void
     70      0    stevel prtconf_help(void)
     71      0    stevel {
     72      0    stevel 	mdb_printf("Prints the devinfo tree from a given node.\n"
     73      0    stevel 	    "Without the address of a \"struct devinfo\" given, "
     74      0    stevel 	    "prints from the root;\n"
     75      0    stevel 	    "with an address, prints the parents of, "
     76      0    stevel 	    "and all children of, that address.\n\n"
     77      0    stevel 	    "Switches:\n"
     78      0    stevel 	    "  -v   be verbose - print device property lists\n"
     79      0    stevel 	    "  -p   only print the ancestors of the given node\n"
     80      0    stevel 	    "  -c   only print the children of the given node\n");
     81      0    stevel }
     82      0    stevel 
     83      0    stevel void
     84      0    stevel devinfo_help(void)
     85      0    stevel {
     86      0    stevel 	mdb_printf("Switches:\n"
     87      0    stevel 	    "  -q   be quiet - don't print device property lists\n"
     88      0    stevel 	    "  -s   print summary of dev_info structures\n");
     89      0    stevel }
     90      0    stevel 
     91      0    stevel 
     92      0    stevel /*
     93      0    stevel  * Devinfo walker.
     94      0    stevel  */
     95      0    stevel 
     96      0    stevel typedef struct {
     97      0    stevel 	/*
     98      0    stevel 	 * The "struct dev_info" must be the first thing in this structure.
     99      0    stevel 	 */
    100      0    stevel 	struct dev_info din_dev;
    101      0    stevel 
    102      0    stevel 	/*
    103      0    stevel 	 * This is for the benefit of prtconf().
    104      0    stevel 	 */
    105      0    stevel 	int din_depth;
    106      0    stevel } devinfo_node_t;
    107      0    stevel 
    108      0    stevel typedef struct devinfo_parents_walk_data {
    109      0    stevel 	devinfo_node_t dip_node;
    110      0    stevel #define	dip_dev dip_node.din_dev
    111      0    stevel #define	dip_depth dip_node.din_depth
    112      0    stevel 	struct dev_info *dip_end;
    113      0    stevel 
    114      0    stevel 	/*
    115      0    stevel 	 * The following three elements are for walking the parents of a node:
    116      0    stevel 	 * "dip_base_depth" is the depth of the given node from the root.
    117      0    stevel 	 *   This starts at 1 (if we're walking devinfo_root), because
    118      0    stevel 	 *   it's the size of the dip_parent_{nodes,addresses} arrays,
    119      0    stevel 	 *   and has to include the given node.
    120      0    stevel 	 * "dip_parent_nodes" is a collection of the parent node structures,
    121      0    stevel 	 *   already read in via mdb_vread().  dip_parent_nodes[0] is the
    122      0    stevel 	 *   root, dip_parent_nodes[1] is a child of the root, etc.
    123      0    stevel 	 * "dip_parent_addresses" holds the vaddrs of all the parent nodes.
    124      0    stevel 	 */
    125      0    stevel 	int dip_base_depth;
    126      0    stevel 	devinfo_node_t *dip_parent_nodes;
    127      0    stevel 	uintptr_t *dip_parent_addresses;
    128      0    stevel } devinfo_parents_walk_data_t;
    129      0    stevel 
    130      0    stevel int
    131      0    stevel devinfo_parents_walk_init(mdb_walk_state_t *wsp)
    132      0    stevel {
    133      0    stevel 	devinfo_parents_walk_data_t *dip;
    134      0    stevel 	uintptr_t addr;
    135   5839     dmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
    136      0    stevel 	int i;
    137   5839     dmick 
    138   5839     dmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
    139   5839     dmick 		mdb_warn("failed to read 'top_devinfo'");
    140   5839     dmick 		return (NULL);
    141   5839     dmick 	}
    142      0    stevel 
    143      0    stevel 	if (wsp->walk_addr == NULL)
    144      0    stevel 		wsp->walk_addr = devinfo_root;
    145      0    stevel 	addr = wsp->walk_addr;
    146      0    stevel 
    147      0    stevel 	dip = mdb_alloc(sizeof (devinfo_parents_walk_data_t), UM_SLEEP);
    148      0    stevel 	wsp->walk_data = dip;
    149      0    stevel 
    150      0    stevel 	dip->dip_end = (struct dev_info *)wsp->walk_addr;
    151      0    stevel 	dip->dip_depth = 0;
    152      0    stevel 	dip->dip_base_depth = 1;
    153      0    stevel 
    154      0    stevel 	do {
    155      0    stevel 		if (mdb_vread(&dip->dip_dev, sizeof (dip->dip_dev),
    156      0    stevel 		    addr) == -1) {
    157      0    stevel 			mdb_warn("failed to read devinfo at %p", addr);
    158      0    stevel 			mdb_free(dip, sizeof (devinfo_parents_walk_data_t));
    159      0    stevel 			wsp->walk_data = NULL;
    160      0    stevel 			return (WALK_ERR);
    161      0    stevel 		}
    162      0    stevel 		addr = (uintptr_t)dip->dip_dev.devi_parent;
    163      0    stevel 		if (addr != 0)
    164      0    stevel 			dip->dip_base_depth++;
    165      0    stevel 	} while (addr != 0);
    166      0    stevel 
    167      0    stevel 	addr = wsp->walk_addr;
    168      0    stevel 
    169      0    stevel 	dip->dip_parent_nodes = mdb_alloc(
    170      0    stevel 	    dip->dip_base_depth * sizeof (devinfo_node_t), UM_SLEEP);
    171      0    stevel 	dip->dip_parent_addresses = mdb_alloc(
    172      0    stevel 	    dip->dip_base_depth * sizeof (uintptr_t), UM_SLEEP);
    173      0    stevel 	for (i = dip->dip_base_depth - 1; i >= 0; i--) {
    174      0    stevel 		if (mdb_vread(&dip->dip_parent_nodes[i].din_dev,
    175      0    stevel 		    sizeof (struct dev_info), addr) == -1) {
    176      0    stevel 			mdb_warn("failed to read devinfo at %p", addr);
    177      0    stevel 			return (WALK_ERR);
    178      0    stevel 		}
    179      0    stevel 		dip->dip_parent_nodes[i].din_depth = i;
    180      0    stevel 		dip->dip_parent_addresses[i] = addr;
    181      0    stevel 		addr = (uintptr_t)
    182      0    stevel 		    dip->dip_parent_nodes[i].din_dev.devi_parent;
    183      0    stevel 	}
    184      0    stevel 
    185      0    stevel 	return (WALK_NEXT);
    186      0    stevel }
    187      0    stevel 
    188      0    stevel int
    189      0    stevel devinfo_parents_walk_step(mdb_walk_state_t *wsp)
    190      0    stevel {
    191      0    stevel 	devinfo_parents_walk_data_t *dip = wsp->walk_data;
    192      0    stevel 	int status;
    193      0    stevel 
    194      0    stevel 	if (dip->dip_depth == dip->dip_base_depth)
    195      0    stevel 		return (WALK_DONE);
    196      0    stevel 
    197      0    stevel 	status = wsp->walk_callback(
    198      0    stevel 	    dip->dip_parent_addresses[dip->dip_depth],
    199      0    stevel 	    &dip->dip_parent_nodes[dip->dip_depth],
    200      0    stevel 	    wsp->walk_cbdata);
    201      0    stevel 
    202      0    stevel 	dip->dip_depth++;
    203      0    stevel 	return (status);
    204      0    stevel }
    205      0    stevel 
    206      0    stevel void
    207      0    stevel devinfo_parents_walk_fini(mdb_walk_state_t *wsp)
    208      0    stevel {
    209      0    stevel 	devinfo_parents_walk_data_t *dip = wsp->walk_data;
    210      0    stevel 
    211      0    stevel 	mdb_free(dip->dip_parent_nodes,
    212      0    stevel 	    dip->dip_base_depth * sizeof (devinfo_node_t));
    213      0    stevel 	mdb_free(dip->dip_parent_addresses,
    214      0    stevel 	    dip->dip_base_depth * sizeof (uintptr_t));
    215      0    stevel 	mdb_free(wsp->walk_data, sizeof (devinfo_parents_walk_data_t));
    216      0    stevel }
    217      0    stevel 
    218      0    stevel 
    219      0    stevel typedef struct devinfo_children_walk_data {
    220      0    stevel 	devinfo_node_t dic_node;
    221      0    stevel #define	dic_dev dic_node.din_dev
    222      0    stevel #define	dic_depth dic_node.din_depth
    223      0    stevel 	struct dev_info *dic_end;
    224      0    stevel 	int dic_print_first_node;
    225      0    stevel } devinfo_children_walk_data_t;
    226      0    stevel 
    227      0    stevel int
    228      0    stevel devinfo_children_walk_init(mdb_walk_state_t *wsp)
    229      0    stevel {
    230      0    stevel 	devinfo_children_walk_data_t *dic;
    231   5839     dmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
    232   5839     dmick 
    233   5839     dmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
    234   5839     dmick 		mdb_warn("failed to read 'top_devinfo'");
    235   5839     dmick 		return (NULL);
    236   5839     dmick 	}
    237      0    stevel 
    238      0    stevel 	if (wsp->walk_addr == NULL)
    239      0    stevel 		wsp->walk_addr = devinfo_root;
    240      0    stevel 
    241      0    stevel 	dic = mdb_alloc(sizeof (devinfo_children_walk_data_t), UM_SLEEP);
    242      0    stevel 	wsp->walk_data = dic;
    243      0    stevel 	dic->dic_end = (struct dev_info *)wsp->walk_addr;
    244      0    stevel 
    245      0    stevel 	/*
    246      0    stevel 	 * This could be set by devinfo_walk_init().
    247      0    stevel 	 */
    248      0    stevel 	if (wsp->walk_arg != NULL) {
    249      0    stevel 		dic->dic_depth = (*(int *)wsp->walk_arg - 1);
    250      0    stevel 		dic->dic_print_first_node = 0;
    251      0    stevel 	} else {
    252      0    stevel 		dic->dic_depth = 0;
    253      0    stevel 		dic->dic_print_first_node = 1;
    254      0    stevel 	}
    255      0    stevel 
    256      0    stevel 	return (WALK_NEXT);
    257      0    stevel }
    258      0    stevel 
    259      0    stevel int
    260      0    stevel devinfo_children_walk_step(mdb_walk_state_t *wsp)
    261      0    stevel {
    262      0    stevel 	devinfo_children_walk_data_t *dic = wsp->walk_data;
    263      0    stevel 	struct dev_info *v;
    264      0    stevel 	devinfo_node_t *cur;
    265      0    stevel 	uintptr_t addr = wsp->walk_addr;
    266      0    stevel 	int status = WALK_NEXT;
    267      0    stevel 
    268      0    stevel 	if (wsp->walk_addr == NULL)
    269      0    stevel 		return (WALK_DONE);
    270      0    stevel 
    271      0    stevel 	if (mdb_vread(&dic->dic_dev, sizeof (dic->dic_dev), addr) == -1) {
    272      0    stevel 		mdb_warn("failed to read devinfo at %p", addr);
    273      0    stevel 		return (WALK_DONE);
    274      0    stevel 	}
    275      0    stevel 	cur = &dic->dic_node;
    276      0    stevel 
    277      0    stevel 	if (dic->dic_print_first_node == 0)
    278      0    stevel 		dic->dic_print_first_node = 1;
    279      0    stevel 	else
    280      0    stevel 		status = wsp->walk_callback(addr, cur, wsp->walk_cbdata);
    281      0    stevel 
    282      0    stevel 	/*
    283      0    stevel 	 * "v" is always a virtual address pointer,
    284      0    stevel 	 *  i.e. can't be deref'ed.
    285      0    stevel 	 */
    286      0    stevel 	v = (struct dev_info *)addr;
    287      0    stevel 
    288      0    stevel 	if (dic->dic_dev.devi_child != NULL) {
    289      0    stevel 		v = dic->dic_dev.devi_child;
    290      0    stevel 		dic->dic_depth++;
    291      0    stevel 	} else if (dic->dic_dev.devi_sibling != NULL && v != dic->dic_end) {
    292      0    stevel 		v = dic->dic_dev.devi_sibling;
    293      0    stevel 	} else {
    294      0    stevel 		while (v != NULL && v != dic->dic_end &&
    295      0    stevel 		    dic->dic_dev.devi_sibling == NULL) {
    296      0    stevel 			v = dic->dic_dev.devi_parent;
    297      0    stevel 			if (v == NULL)
    298      0    stevel 				break;
    299      0    stevel 
    300      0    stevel 			mdb_vread(&dic->dic_dev,
    301      0    stevel 			    sizeof (struct dev_info), (uintptr_t)v);
    302      0    stevel 			dic->dic_depth--;
    303      0    stevel 		}
    304      0    stevel 		if (v != NULL && v != dic->dic_end)
    305      0    stevel 			v = dic->dic_dev.devi_sibling;
    306      0    stevel 		if (v == dic->dic_end)
    307      0    stevel 			v = NULL;	/* Done */
    308      0    stevel 	}
    309      0    stevel 
    310      0    stevel 	wsp->walk_addr = (uintptr_t)v;
    311      0    stevel 	return (status);
    312      0    stevel }
    313      0    stevel 
    314      0    stevel void
    315      0    stevel devinfo_children_walk_fini(mdb_walk_state_t *wsp)
    316      0    stevel {
    317      0    stevel 	mdb_free(wsp->walk_data, sizeof (devinfo_children_walk_data_t));
    318      0    stevel }
    319      0    stevel 
    320      0    stevel typedef struct devinfo_walk_data {
    321      0    stevel 	mdb_walk_state_t diw_parent, diw_child;
    322      0    stevel 	enum { DIW_PARENT, DIW_CHILD, DIW_DONE } diw_mode;
    323      0    stevel } devinfo_walk_data_t;
    324      0    stevel 
    325      0    stevel int
    326      0    stevel devinfo_walk_init(mdb_walk_state_t *wsp)
    327      0    stevel {
    328      0    stevel 	devinfo_walk_data_t *diw;
    329      0    stevel 	devinfo_parents_walk_data_t *dip;
    330      0    stevel 
    331      0    stevel 	diw = mdb_alloc(sizeof (devinfo_walk_data_t), UM_SLEEP);
    332      0    stevel 	diw->diw_parent = *wsp;
    333      0    stevel 	diw->diw_child = *wsp;
    334      0    stevel 	wsp->walk_data = diw;
    335      0    stevel 
    336      0    stevel 	diw->diw_mode = DIW_PARENT;
    337      0    stevel 
    338      0    stevel 	if (devinfo_parents_walk_init(&diw->diw_parent) == -1) {
    339      0    stevel 		mdb_free(diw, sizeof (devinfo_walk_data_t));
    340      0    stevel 		return (WALK_ERR);
    341      0    stevel 	}
    342      0    stevel 
    343      0    stevel 	/*
    344      0    stevel 	 * This is why the "devinfo" walker needs to be marginally
    345      0    stevel 	 * complicated - the child walker needs this initialization
    346      0    stevel 	 * data, and the best way to get it is out of the parent walker.
    347      0    stevel 	 */
    348      0    stevel 	dip = diw->diw_parent.walk_data;
    349      0    stevel 	diw->diw_child.walk_arg = &dip->dip_base_depth;
    350      0    stevel 
    351      0    stevel 	if (devinfo_children_walk_init(&diw->diw_child) == -1) {
    352      0    stevel 		devinfo_parents_walk_fini(&diw->diw_parent);
    353      0    stevel 		mdb_free(diw, sizeof (devinfo_walk_data_t));
    354      0    stevel 		return (WALK_ERR);
    355      0    stevel 	}
    356      0    stevel 
    357      0    stevel 	return (WALK_NEXT);
    358      0    stevel }
    359      0    stevel 
    360      0    stevel int
    361      0    stevel devinfo_walk_step(mdb_walk_state_t *wsp)
    362      0    stevel {
    363      0    stevel 	devinfo_walk_data_t *diw = wsp->walk_data;
    364      0    stevel 	int status = WALK_NEXT;
    365      0    stevel 
    366      0    stevel 	if (diw->diw_mode == DIW_PARENT) {
    367      0    stevel 		status = devinfo_parents_walk_step(&diw->diw_parent);
    368      0    stevel 		if (status != WALK_NEXT) {
    369      0    stevel 			/*
    370      0    stevel 			 * Keep on going even if the parents walk hit an error.
    371      0    stevel 			 */
    372      0    stevel 			diw->diw_mode = DIW_CHILD;
    373      0    stevel 			status = WALK_NEXT;
    374      0    stevel 		}
    375      0    stevel 	} else if (diw->diw_mode == DIW_CHILD) {
    376      0    stevel 		status = devinfo_children_walk_step(&diw->diw_child);
    377      0    stevel 		if (status != WALK_NEXT) {
    378      0    stevel 			diw->diw_mode = DIW_DONE;
    379      0    stevel 			status = WALK_DONE;
    380      0    stevel 		}
    381      0    stevel 	} else
    382      0    stevel 		status = WALK_DONE;
    383      0    stevel 
    384      0    stevel 	return (status);
    385      0    stevel }
    386      0    stevel 
    387      0    stevel void
    388      0    stevel devinfo_walk_fini(mdb_walk_state_t *wsp)
    389      0    stevel {
    390      0    stevel 	devinfo_walk_data_t *diw = wsp->walk_data;
    391      0    stevel 
    392      0    stevel 	devinfo_children_walk_fini(&diw->diw_child);
    393      0    stevel 	devinfo_parents_walk_fini(&diw->diw_parent);
    394      0    stevel 	mdb_free(diw, sizeof (devinfo_walk_data_t));
    395      0    stevel }
    396      0    stevel 
    397      0    stevel /*
    398      0    stevel  * Given a devinfo pointer, figure out which driver is associated
    399      0    stevel  * with the node (by driver name, from the devnames array).
    400      0    stevel  */
    401      0    stevel /*ARGSUSED*/
    402      0    stevel int
    403      0    stevel devinfo2driver(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    404      0    stevel {
    405      0    stevel 	char dname[MODMAXNAMELEN + 1];
    406      0    stevel 	struct dev_info devi;
    407      0    stevel 
    408      0    stevel 
    409      0    stevel 	if (!(flags & DCMD_ADDRSPEC))
    410      0    stevel 		return (DCMD_USAGE);
    411      0    stevel 
    412      0    stevel 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
    413      0    stevel 		mdb_warn("failed to read devinfo struct at %p", addr);
    414      0    stevel 		return (DCMD_ERR);
    415      0    stevel 	}
    416      0    stevel 
    417   1125  eschrock 	if (devi.devi_node_state < DS_ATTACHED) {
    418      0    stevel 		/* No driver attached to this devinfo - nothing to do. */
    419      0    stevel 		mdb_warn("%p: No driver attached to this devinfo node\n", addr);
    420      0    stevel 		return (DCMD_ERR);
    421      0    stevel 	}
    422      0    stevel 
    423      0    stevel 	if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0) {
    424      0    stevel 		mdb_warn("failed to determine driver name");
    425      0    stevel 		return (DCMD_ERR);
    426      0    stevel 	}
    427      0    stevel 
    428      0    stevel 	mdb_printf("Driver '%s' is associated with devinfo %p.\n", dname, addr);
    429      0    stevel 
    430      0    stevel 	return (DCMD_OK);
    431      0    stevel }
    432      0    stevel 
    433      0    stevel 
    434      0    stevel typedef struct devnames_walk {
    435      0    stevel 	struct devnames *dnw_names;
    436      0    stevel 	int dnw_ndx;
    437      0    stevel 	int dnw_devcnt;
    438      0    stevel 	uintptr_t dnw_base;
    439      0    stevel 	uintptr_t dnw_size;
    440      0    stevel } devnames_walk_t;
    441      0    stevel 
    442      0    stevel int
    443      0    stevel devnames_walk_init(mdb_walk_state_t *wsp)
    444      0    stevel {
    445      0    stevel 	devnames_walk_t *dnw;
    446      0    stevel 	int devcnt;
    447      0    stevel 	uintptr_t devnamesp;
    448      0    stevel 
    449      0    stevel 	if (wsp->walk_addr != NULL) {
    450      0    stevel 		mdb_warn("devnames walker only supports global walks\n");
    451      0    stevel 		return (WALK_ERR);
    452      0    stevel 	}
    453      0    stevel 
    454      0    stevel 	if (mdb_readvar(&devcnt, "devcnt") == -1) {
    455      0    stevel 		mdb_warn("failed to read 'devcnt'");
    456      0    stevel 		return (WALK_ERR);
    457      0    stevel 	}
    458      0    stevel 
    459      0    stevel 	if (mdb_readvar(&devnamesp, "devnamesp") == -1) {
    460      0    stevel 		mdb_warn("failed to read 'devnamesp'");
    461      0    stevel 		return (WALK_ERR);
    462      0    stevel 	}
    463      0    stevel 
    464      0    stevel 	dnw = mdb_zalloc(sizeof (devnames_walk_t), UM_SLEEP);
    465      0    stevel 	dnw->dnw_size = sizeof (struct devnames) * devcnt;
    466      0    stevel 	dnw->dnw_devcnt = devcnt;
    467      0    stevel 	dnw->dnw_base = devnamesp;
    468      0    stevel 	dnw->dnw_names = mdb_alloc(dnw->dnw_size, UM_SLEEP);
    469      0    stevel 
    470      0    stevel 	if (mdb_vread(dnw->dnw_names, dnw->dnw_size, dnw->dnw_base) == -1) {
    471      0    stevel 		mdb_warn("couldn't read devnames array at %p", devnamesp);
    472      0    stevel 		return (WALK_ERR);
    473      0    stevel 	}
    474      0    stevel 
    475      0    stevel 	wsp->walk_data = dnw;
    476      0    stevel 	return (WALK_NEXT);
    477      0    stevel }
    478      0    stevel 
    479      0    stevel int
    480      0    stevel devnames_walk_step(mdb_walk_state_t *wsp)
    481      0    stevel {
    482      0    stevel 	devnames_walk_t *dnw = wsp->walk_data;
    483      0    stevel 	int status;
    484      0    stevel 
    485      0    stevel 	if (dnw->dnw_ndx == dnw->dnw_devcnt)
    486      0    stevel 		return (WALK_DONE);
    487      0    stevel 
    488      0    stevel 	status = wsp->walk_callback(dnw->dnw_ndx * sizeof (struct devnames) +
    489      0    stevel 	    dnw->dnw_base, &dnw->dnw_names[dnw->dnw_ndx], wsp->walk_cbdata);
    490      0    stevel 
    491      0    stevel 	dnw->dnw_ndx++;
    492      0    stevel 	return (status);
    493      0    stevel }
    494      0    stevel 
    495      0    stevel void
    496      0    stevel devnames_walk_fini(mdb_walk_state_t *wsp)
    497      0    stevel {
    498      0    stevel 	devnames_walk_t *dnw = wsp->walk_data;
    499      0    stevel 
    500      0    stevel 	mdb_free(dnw->dnw_names, dnw->dnw_size);
    501      0    stevel 	mdb_free(dnw, sizeof (devnames_walk_t));
    502      0    stevel }
    503      0    stevel 
    504      0    stevel int
    505      0    stevel devinfo_siblings_walk_init(mdb_walk_state_t *wsp)
    506      0    stevel {
    507      0    stevel 	struct dev_info di;
    508      0    stevel 	uintptr_t addr = wsp->walk_addr;
    509      0    stevel 
    510      0    stevel 	if (addr == NULL) {
    511      0    stevel 		mdb_warn("a dev_info struct address must be provided\n");
    512      0    stevel 		return (WALK_ERR);
    513      0    stevel 	}
    514      0    stevel 
    515      0    stevel 	if (mdb_vread(&di, sizeof (di), addr) == -1) {
    516      0    stevel 		mdb_warn("failed to read dev_info struct at %p", addr);
    517      0    stevel 		return (WALK_ERR);
    518      0    stevel 	}
    519      0    stevel 
    520      0    stevel 	if (di.devi_parent == NULL) {
    521      0    stevel 		mdb_warn("no parent for devinfo at %p", addr);
    522      0    stevel 		return (WALK_DONE);
    523      0    stevel 	}
    524      0    stevel 
    525      0    stevel 	if (mdb_vread(&di, sizeof (di), (uintptr_t)di.devi_parent) == -1) {
    526      0    stevel 		mdb_warn("failed to read parent dev_info struct at %p",
    527      0    stevel 		    (uintptr_t)di.devi_parent);
    528      0    stevel 		return (WALK_ERR);
    529      0    stevel 	}
    530      0    stevel 
    531      0    stevel 	wsp->walk_addr = (uintptr_t)di.devi_child;
    532      0    stevel 	return (WALK_NEXT);
    533      0    stevel }
    534      0    stevel 
    535      0    stevel int
    536      0    stevel devinfo_siblings_walk_step(mdb_walk_state_t *wsp)
    537      0    stevel {
    538      0    stevel 	struct dev_info di;
    539      0    stevel 	uintptr_t addr = wsp->walk_addr;
    540      0    stevel 
    541      0    stevel 	if (addr == NULL)
    542      0    stevel 		return (WALK_DONE);
    543      0    stevel 
    544      0    stevel 	if (mdb_vread(&di, sizeof (di), addr) == -1) {
    545      0    stevel 		mdb_warn("failed to read dev_info struct at %p", addr);
    546      0    stevel 		return (WALK_DONE);
    547      0    stevel 	}
    548      0    stevel 
    549      0    stevel 	wsp->walk_addr = (uintptr_t)di.devi_sibling;
    550      0    stevel 	return (wsp->walk_callback(addr, &di, wsp->walk_cbdata));
    551      0    stevel }
    552      0    stevel 
    553      0    stevel int
    554      0    stevel devi_next_walk_step(mdb_walk_state_t *wsp)
    555      0    stevel {
    556      0    stevel 	struct dev_info di;
    557      0    stevel 	int status;
    558      0    stevel 
    559      0    stevel 	if (wsp->walk_addr == NULL)
    560      0    stevel 		return (WALK_DONE);
    561      0    stevel 
    562      0    stevel 	if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1)
    563      0    stevel 		return (WALK_DONE);
    564      0    stevel 
    565      0    stevel 	status = wsp->walk_callback(wsp->walk_addr, &di, wsp->walk_cbdata);
    566      0    stevel 	wsp->walk_addr = (uintptr_t)di.devi_next;
    567      0    stevel 	return (status);
    568      0    stevel }
    569      0    stevel 
    570      0    stevel /*
    571      0    stevel  * Helper functions.
    572      0    stevel  */
    573      0    stevel 
    574      0    stevel static int
    575      0    stevel is_printable_string(unsigned char *prop_value)
    576      0    stevel {
    577      0    stevel 	while (*prop_value != 0)
    578      0    stevel 		if (!isprint(*prop_value++))
    579      0    stevel 			return (0);
    580      0    stevel 	return (1);
    581      0    stevel }
    582      0    stevel 
    583      0    stevel static void
    584      0    stevel devinfo_print_props_type(int type) {
    585      0    stevel 	char *type_str = NULL;
    586      0    stevel 
    587      0    stevel 	switch (type) {
    588      0    stevel 	case DDI_PROP_TYPE_ANY:
    589      0    stevel 		type_str = "any";
    590      0    stevel 		break;
    591      0    stevel 	case DDI_PROP_TYPE_COMPOSITE:
    592      0    stevel 		type_str = "composite";
    593      0    stevel 		break;
    594      0    stevel 	case DDI_PROP_TYPE_INT64:
    595      0    stevel 		type_str = "int64";
    596      0    stevel 		break;
    597      0    stevel 	case DDI_PROP_TYPE_INT:
    598      0    stevel 		type_str = "int";
    599      0    stevel 		break;
    600      0    stevel 	case DDI_PROP_TYPE_BYTE:
    601      0    stevel 		type_str = "byte";
    602      0    stevel 		break;
    603      0    stevel 	case DDI_PROP_TYPE_STRING:
    604      0    stevel 		type_str = "string";
    605      0    stevel 		break;
    606      0    stevel 	}
    607      0    stevel 
    608      0    stevel 	if (type_str != NULL)
    609      0    stevel 		mdb_printf("type=%s", type_str);
    610      0    stevel 	else
    611      0    stevel 		mdb_printf("type=0x%x", type);
    612      0    stevel }
    613      0    stevel 
    614      0    stevel static void
    615      0    stevel devinfo_print_props_value(int elem_size, int nelem,
    616      0    stevel 	unsigned char *prop_value, int prop_value_len)
    617      0    stevel {
    618      0    stevel 	int i;
    619      0    stevel 
    620      0    stevel 	mdb_printf("value=");
    621      0    stevel 
    622      0    stevel 	if (elem_size == 0) {
    623      0    stevel 		/* if elem_size == 0, then we are printing out string(s) */
    624      0    stevel 		char *p = (char *)prop_value;
    625      0    stevel 
    626      0    stevel 		for (i = 0; i < nelem - 1; i++) {
    627      0    stevel 			mdb_printf("'%s' + ", p);
    628      0    stevel 			p += strlen(p) + 1;
    629      0    stevel 		}
    630      0    stevel 		mdb_printf("'%s'", p);
    631      0    stevel 	} else {
    632      0    stevel 		/*
    633      0    stevel 		 * if elem_size != 0 then we are printing out an array
    634      0    stevel 		 * where each element is of elem_size
    635      0    stevel 		 */
    636      0    stevel 		mdb_nhconvert(prop_value, prop_value, elem_size);
    637      0    stevel 		mdb_printf("%02x", *prop_value);
    638      0    stevel 		for (i = 1; i < prop_value_len; i++) {
    639      0    stevel 			if ((i % elem_size) == 0) {
    640      0    stevel 				mdb_nhconvert(&prop_value[i],
    641      0    stevel 				    &prop_value[i], elem_size);
    642      0    stevel 				mdb_printf(".");
    643      0    stevel 			}
    644      0    stevel 
    645      0    stevel 			mdb_printf("%02x", prop_value[i]);
    646      0    stevel 		}
    647      0    stevel 	}
    648      0    stevel }
    649      0    stevel 
    650      0    stevel /*
    651      0    stevel  * devinfo_print_props_guess()
    652      0    stevel  * Guesses how to interpret the value of the property
    653      0    stevel  *
    654      0    stevel  * Params:
    655      0    stevel  * 	type      - Should be the type value of the property
    656      0    stevel  * 	prop_val  - Pointer to the property value data buffer
    657      0    stevel  * 	prop_len  - Length of the property value data buffer
    658      0    stevel  *
    659      0    stevel  * Return values:
    660      0    stevel  * 	nelem     - The number of elements stored in the property value
    661      0    stevel  * 			data buffer pointed to by prop_val.
    662      0    stevel  * 	elem_size - The size (in bytes) of the elements stored in the property
    663      0    stevel  * 			value data buffer pointed to by prop_val.
    664      0    stevel  * 			Upon return if elem_size == 0 and nelem != 0 then
    665      0    stevel  * 			the property value data buffer contains strings
    666      0    stevel  * 	len_err   - There was an error with the length of the data buffer.
    667      0    stevel  * 			Its size is not a multiple of the array value type.
    668      0    stevel  * 			It will be interpreted as an array of bytes.
    669      0    stevel  */
    670      0    stevel static void
    671      0    stevel devinfo_print_props_guess(int type, unsigned char *prop_val, int prop_len,
    672      0    stevel     int *elem_size, int *nelem, int *len_err)
    673      0    stevel {
    674      0    stevel 	*len_err = 0;
    675      0    stevel 	if (prop_len == NULL) {
    676      0    stevel 		*elem_size = 0;
    677      0    stevel 		*nelem = 0;
    678      0    stevel 		return;
    679      0    stevel 	}
    680      0    stevel 
    681      0    stevel 	/* by default, assume an array of bytes */
    682      0    stevel 	*elem_size = 1;
    683      0    stevel 	*nelem = prop_len;
    684      0    stevel 
    685      0    stevel 	switch (type) {
    686      0    stevel 	case DDI_PROP_TYPE_BYTE:
    687      0    stevel 		/* default case, that was easy */
    688      0    stevel 		break;
    689      0    stevel 	case DDI_PROP_TYPE_INT64:
    690      0    stevel 		if ((prop_len % sizeof (int64_t)) == 0) {
    691      0    stevel 			*elem_size = sizeof (int64_t);
    692      0    stevel 			*nelem = prop_len / *elem_size;
    693      0    stevel 		} else {
    694      0    stevel 			/* array is not a multiple of type size, error */
    695      0    stevel 			*len_err = 1;
    696      0    stevel 		}
    697      0    stevel 		break;
    698      0    stevel 	case DDI_PROP_TYPE_INT:
    699      0    stevel 		if ((prop_len % sizeof (int)) == 0) {
    700      0    stevel 			*elem_size = sizeof (int);
    701      0    stevel 			*nelem = prop_len / *elem_size;
    702      0    stevel 		} else {
    703      0    stevel 			/* array is not a multiple of type size, error */
    704      0    stevel 			*len_err = 1;
    705      0    stevel 		}
    706      0    stevel 		break;
    707      0    stevel 	case DDI_PROP_TYPE_STRING:
    708      0    stevel 	case DDI_PROP_TYPE_COMPOSITE:
    709      0    stevel 	case DDI_PROP_TYPE_ANY:
    710      0    stevel 	default:
    711      0    stevel 		/*
    712      0    stevel 		 * if we made it here the type is either unknown
    713      0    stevel 		 * or a string.  Try to interpret is as a string
    714      0    stevel 		 * and if that fails assume an array of bytes.
    715      0    stevel 		 */
    716      0    stevel 		if (prop_val[prop_len - 1] == '\0') {
    717      0    stevel 			unsigned char	*s = prop_val;
    718      0    stevel 			int		i;
    719      0    stevel 
    720      0    stevel 			/* assume an array of strings */
    721      0    stevel 			*elem_size = 0;
    722      0    stevel 			*nelem = 0;
    723      0    stevel 
    724      0    stevel 			for (i = 0; i < prop_len; i++) {
    725      0    stevel 				if (prop_val[i] != '\0')
    726      0    stevel 					continue;
    727      0    stevel 
    728      0    stevel 				/*
    729      0    stevel 				 * If the property is typed as a string
    730      0    stevel 				 * property, then interpret empty strings
    731      0    stevel 				 * as strings. Otherwise default to an
    732      0    stevel 				 * array of bytes. If there are unprintable
    733      0    stevel 				 * characters, always default to an array of
    734      0    stevel 				 * bytes.
    735      0    stevel 				 */
    736      0    stevel 				if ((*s == '\0' && type !=
    737      0    stevel 				    DDI_PROP_TYPE_STRING) ||
    738      0    stevel 				    !is_printable_string(s)) {
    739      0    stevel 					*elem_size = 1;
    740      0    stevel 					*nelem = prop_len;
    741      0    stevel 					break;
    742      0    stevel 				}
    743      0    stevel 
    744      0    stevel 				(*nelem)++;
    745      0    stevel 				s = &prop_val[i + 1];
    746      0    stevel 			}
    747      0    stevel 		}
    748      0    stevel 		break;
    749      0    stevel 	}
    750      0    stevel }
    751      0    stevel 
    752      0    stevel static void
    753      0    stevel devinfo_print_props(char *name, ddi_prop_t *p)
    754      0    stevel {
    755      0    stevel 	if (p == NULL)
    756      0    stevel 		return;
    757      0    stevel 
    758      0    stevel 	if (name != NULL)
    759      0    stevel 		mdb_printf("%s ", name);
    760      0    stevel 
    761      0    stevel 	mdb_printf("properties at %p:\n", p);
    762      0    stevel 	mdb_inc_indent(DEVINFO_PROP_INDENT);
    763      0    stevel 
    764      0    stevel 	while (p != NULL) {
    765      0    stevel 		ddi_prop_t	prop;
    766      0    stevel 		char		prop_name[128];
    767      0    stevel 		unsigned char	*prop_value;
    768      0    stevel 		int		type, elem_size, nelem, prop_len_error;
    769      0    stevel 
    770      0    stevel 		/* read in the property struct */
    771      0    stevel 		if (mdb_vread(&prop, sizeof (prop), (uintptr_t)p) == -1) {
    772      0    stevel 			mdb_warn("could not read property at 0x%p", p);
    773      0    stevel 			break;
    774      0    stevel 		}
    775      0    stevel 
    776      0    stevel 		/* print the property name */
    777      0    stevel 		if (mdb_readstr(prop_name, sizeof (prop_name),
    778      0    stevel 		    (uintptr_t)prop.prop_name) == -1) {
    779      0    stevel 			mdb_warn("could not read property name at 0x%p",
    780      0    stevel 			    prop.prop_name);
    781      0    stevel 			goto next;
    782      0    stevel 		}
    783      0    stevel 		mdb_printf("name='%s' ", prop_name);
    784      0    stevel 
    785      0    stevel 		/* get the property type and print it out */
    786      0    stevel 		type = (prop.prop_flags & DDI_PROP_TYPE_MASK);
    787      0    stevel 		devinfo_print_props_type(type);
    788      0    stevel 
    789      0    stevel 		/* get the property value */
    790      0    stevel 		if (prop.prop_len > 0) {
    791      0    stevel 			prop_value = mdb_alloc(prop.prop_len, UM_SLEEP|UM_GC);
    792      0    stevel 			if (mdb_vread(prop_value, prop.prop_len,
    793   5839     dmick 			    (uintptr_t)prop.prop_val) == -1) {
    794      0    stevel 				mdb_warn("could not read property value at "
    795      0    stevel 				    "0x%p", prop.prop_val);
    796      0    stevel 				goto next;
    797      0    stevel 			}
    798      0    stevel 		} else {
    799      0    stevel 			prop_value = NULL;
    800      0    stevel 		}
    801      0    stevel 
    802      0    stevel 		/* take a guess at interpreting the property value */
    803      0    stevel 		devinfo_print_props_guess(type, prop_value, prop.prop_len,
    804      0    stevel 		    &elem_size, &nelem, &prop_len_error);
    805      0    stevel 
    806      0    stevel 		/* print out the number ot items */
    807      0    stevel 		mdb_printf(" items=%d", nelem);
    808      0    stevel 
    809      0    stevel 		/* print out any associated device information */
    810      0    stevel 		if (prop.prop_dev != DDI_DEV_T_NONE) {
    811      0    stevel 			mdb_printf(" dev=");
    812      0    stevel 			if (prop.prop_dev == DDI_DEV_T_ANY)
    813      0    stevel 				mdb_printf("any");
    814      0    stevel 			else if (prop.prop_dev == DDI_MAJOR_T_UNKNOWN)
    815      0    stevel 				mdb_printf("unknown");
    816      0    stevel 			else
    817      0    stevel 				mdb_printf("(%u,%u)",
    818      0    stevel 				    getmajor(prop.prop_dev),
    819      0    stevel 				    getminor(prop.prop_dev));
    820      0    stevel 		}
    821      0    stevel 
    822      0    stevel 		/* print out the property value */
    823      0    stevel 		if (prop_value != NULL) {
    824      0    stevel 			mdb_printf("\n");
    825      0    stevel 			mdb_inc_indent(DEVINFO_PROP_INDENT);
    826      0    stevel 			if (prop_len_error)
    827      0    stevel 				mdb_printf("NOTE: prop length is not a "
    828      0    stevel 				    "multiple of element size\n");
    829      0    stevel 			devinfo_print_props_value(elem_size, nelem,
    830      0    stevel 			    prop_value, prop.prop_len);
    831      0    stevel 			mdb_dec_indent(DEVINFO_PROP_INDENT);
    832      0    stevel 		}
    833      0    stevel 
    834      0    stevel next:
    835      0    stevel 		mdb_printf("\n");
    836      0    stevel 		p = prop.prop_next;
    837      0    stevel 	}
    838      0    stevel 
    839      0    stevel 	mdb_dec_indent(DEVINFO_PROP_INDENT);
    840      0    stevel }
    841      0    stevel 
    842      0    stevel static void
    843      0    stevel devinfo_pathinfo_state(mdi_pathinfo_state_t state) {
    844      0    stevel 	char *type_str = NULL;
    845      0    stevel 
    846      0    stevel 	switch (state) {
    847      0    stevel 	case MDI_PATHINFO_STATE_INIT:
    848      0    stevel 		type_str = "init";
    849      0    stevel 		break;
    850      0    stevel 	case MDI_PATHINFO_STATE_ONLINE:
    851      0    stevel 		type_str = "online";
    852      0    stevel 		break;
    853      0    stevel 	case MDI_PATHINFO_STATE_STANDBY:
    854      0    stevel 		type_str = "standby";
    855      0    stevel 		break;
    856      0    stevel 	case MDI_PATHINFO_STATE_FAULT:
    857      0    stevel 		type_str = "fault";
    858      0    stevel 		break;
    859      0    stevel 	case MDI_PATHINFO_STATE_OFFLINE:
    860      0    stevel 		type_str = "offline";
    861      0    stevel 		break;
    862      0    stevel 	}
    863      0    stevel 	if (type_str != NULL)
    864      0    stevel 		mdb_printf("state=%s\n", type_str);
    865      0    stevel 	else
    866      0    stevel 		mdb_printf("state=0x%x\n", state);
    867      0    stevel }
    868      0    stevel 
    869      0    stevel static void
    870      0    stevel devinfo_print_pathing(int mdi_component, void *mdi_client) {
    871      0    stevel 	mdi_client_t		mdi_c;
    872      0    stevel 	struct mdi_pathinfo	*pip;
    873      0    stevel 
    874      0    stevel 	/* we only print out multipathing info for client nodes */
    875      0    stevel 	if ((mdi_component & MDI_COMPONENT_CLIENT) == 0)
    876      0    stevel 		return;
    877      0    stevel 
    878      0    stevel 	mdb_printf("Client multipath info at: 0x%p\n", mdi_client);
    879      0    stevel 	mdb_inc_indent(DEVINFO_PROP_INDENT);
    880      0    stevel 
    881      0    stevel 	/* read in the client multipathing info */
    882      0    stevel 	if (mdb_readstr((void*) &mdi_c, sizeof (mdi_c),
    883      0    stevel 	    (uintptr_t)mdi_client) == -1) {
    884      0    stevel 		mdb_warn("failed to read mdi_client at %p",
    885      0    stevel 		    (uintptr_t)mdi_client);
    886      0    stevel 		goto exit;
    887      0    stevel 	}
    888      0    stevel 
    889      0    stevel 	/*
    890      0    stevel 	 * walk through the clients list of pathinfo structures and print
    891      0    stevel 	 * out the properties for each path
    892      0    stevel 	 */
    893      0    stevel 	pip = (struct mdi_pathinfo *)mdi_c.ct_path_head;
    894      0    stevel 	while (pip != NULL) {
    895      0    stevel 		char			binding_name[128];
    896      0    stevel 		struct mdi_pathinfo	pi;
    897      0    stevel 		mdi_phci_t		ph;
    898      0    stevel 		struct dev_info		ph_di;
    899      0    stevel 
    900      0    stevel 		/* read in the pathinfo structure */
    901      0    stevel 		if (mdb_vread((void*)&pi, sizeof (pi),
    902      0    stevel 			    (uintptr_t)pip) == -1) {
    903      0    stevel 			mdb_warn("failed to read mdi_pathinfo at %p",
    904      0    stevel 			    (uintptr_t)pip);
    905      0    stevel 			goto exit;
    906      0    stevel 		}
    907      0    stevel 
    908      0    stevel 		/* read in the pchi (path host adapter) info */
    909      0    stevel 		if (mdb_vread((void*)&ph, sizeof (ph),
    910      0    stevel 			    (uintptr_t)pi.pi_phci) == -1) {
    911      0    stevel 			mdb_warn("failed to read mdi_pchi at %p",
    912      0    stevel 			    (uintptr_t)pi.pi_phci);
    913      0    stevel 			goto exit;
    914      0    stevel 		}
    915      0    stevel 
    916      0    stevel 		/* read in the dip of the phci so we can get it's name */
    917      0    stevel 		if (mdb_vread((void*)&ph_di, sizeof (ph_di),
    918      0    stevel 			    (uintptr_t)ph.ph_dip) == -1) {
    919      0    stevel 			mdb_warn("failed to read mdi_pchi at %p",
    920      0    stevel 			    (uintptr_t)ph.ph_dip);
    921      0    stevel 			goto exit;
    922      0    stevel 		}
    923      0    stevel 		if (mdb_vread(binding_name, sizeof (binding_name),
    924      0    stevel 			    (uintptr_t)ph_di.devi_binding_name) == -1) {
    925      0    stevel 			mdb_warn("failed to read binding_name at %p",
    926      0    stevel 			    (uintptr_t)ph_di.devi_binding_name);
    927      0    stevel 			goto exit;
    928      0    stevel 		}
    929      0    stevel 
    930      0    stevel 		mdb_printf("%s#%d, ", binding_name, ph_di.devi_instance);
    931      0    stevel 		devinfo_pathinfo_state(pi.pi_state);
    932      0    stevel 
    933      0    stevel 		/* print out the pathing info */
    934      0    stevel 		mdb_inc_indent(DEVINFO_PROP_INDENT);
    935      0    stevel 		if (mdb_pwalk_dcmd(NVPAIR_WALKER_FQNAME, NVPAIR_DCMD_FQNAME,
    936      0    stevel 			    0, NULL, (uintptr_t)pi.pi_prop) != 0) {
    937      0    stevel 			mdb_dec_indent(DEVINFO_PROP_INDENT);
    938      0    stevel 			goto exit;
    939      0    stevel 		}
    940      0    stevel 		mdb_dec_indent(DEVINFO_PROP_INDENT);
    941      0    stevel 		pip = pi.pi_client_link;
    942      0    stevel 	}
    943      0    stevel 
    944      0    stevel exit:
    945      0    stevel 	mdb_dec_indent(DEVINFO_PROP_INDENT);
    946      0    stevel }
    947      0    stevel 
    948      0    stevel static int
    949      0    stevel devinfo_print(uintptr_t addr, struct dev_info *dev, devinfo_cb_data_t *data)
    950      0    stevel {
    951      0    stevel 	/*
    952      0    stevel 	 * We know the walker passes us extra data after the dev_info.
    953      0    stevel 	 */
    954      0    stevel 	char		binding_name[128];
    955   1125  eschrock 	char		dname[MODMAXNAMELEN + 1];
    956      0    stevel 	devinfo_node_t	*din = (devinfo_node_t *)dev;
    957      0    stevel 	ddi_prop_t	*global_props = NULL;
    958      0    stevel 
    959      0    stevel 	if (mdb_readstr(binding_name, sizeof (binding_name),
    960      0    stevel 	    (uintptr_t)dev->devi_binding_name) == -1) {
    961      0    stevel 		mdb_warn("failed to read binding_name at %p",
    962      0    stevel 		    (uintptr_t)dev->devi_binding_name);
    963      0    stevel 		return (WALK_ERR);
    964      0    stevel 	}
    965      0    stevel 
    966      0    stevel 	/* if there are any global properties, get a pointer to them */
    967      0    stevel 	if (dev->devi_global_prop_list != NULL) {
    968      0    stevel 		ddi_prop_list_t	plist;
    969      0    stevel 		if (mdb_vread((void*)&plist, sizeof (plist),
    970   5839     dmick 		    (uintptr_t)dev->devi_global_prop_list) == -1) {
    971      0    stevel 			mdb_warn("failed to read global prop_list at %p",
    972      0    stevel 			    (uintptr_t)dev->devi_global_prop_list);
    973      0    stevel 			return (WALK_ERR);
    974      0    stevel 		}
    975      0    stevel 		global_props = plist.prop_list;
    976      0    stevel 	}
    977      0    stevel 
    978      0    stevel 	mdb_inc_indent(din->din_depth * DEVINFO_TREE_INDENT);
    979      0    stevel 	if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD))
    980      0    stevel 		mdb_printf("%<b>");
    981      0    stevel 	mdb_printf("%-0?p %s", addr, binding_name);
    982      0    stevel 	if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD))
    983      0    stevel 		mdb_printf("%</b>");
    984      0    stevel 	if (dev->devi_instance >= 0)
    985      0    stevel 		mdb_printf(", instance #%d", dev->devi_instance);
    986   1125  eschrock 
    987   1125  eschrock 	if (dev->devi_node_state < DS_ATTACHED)
    988      0    stevel 		mdb_printf(" (driver not attached)");
    989   1125  eschrock 	else if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0)
    990   1125  eschrock 		mdb_printf(" (could not determine driver name)");
    991   1125  eschrock 	else
    992   1125  eschrock 		mdb_printf(" (driver name: %s)", dname);
    993   1125  eschrock 
    994      0    stevel 	mdb_printf("\n");
    995      0    stevel 	if (data->di_flags & DEVINFO_VERBOSE) {
    996      0    stevel 		mdb_inc_indent(DEVINFO_PROPLIST_INDENT);
    997      0    stevel 		devinfo_print_props("System", dev->devi_sys_prop_ptr);
    998      0    stevel 		devinfo_print_props("Driver", dev->devi_drv_prop_ptr);
    999      0    stevel 		devinfo_print_props("Hardware", dev->devi_hw_prop_ptr);
   1000      0    stevel 		devinfo_print_props("Global", global_props);
   1001      0    stevel 
   1002      0    stevel 		devinfo_print_pathing(dev->devi_mdi_component,
   1003      0    stevel 		    dev->devi_mdi_client);
   1004      0    stevel 
   1005      0    stevel 		mdb_dec_indent(DEVINFO_PROPLIST_INDENT);
   1006      0    stevel 	}
   1007      0    stevel 
   1008      0    stevel 	mdb_dec_indent(din->din_depth * DEVINFO_TREE_INDENT);
   1009      0    stevel 	return (WALK_NEXT);
   1010      0    stevel }
   1011      0    stevel 
   1012      0    stevel /*ARGSUSED*/
   1013      0    stevel int
   1014      0    stevel prtconf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1015      0    stevel {
   1016      0    stevel 	devinfo_cb_data_t data;
   1017   5839     dmick 	uintptr_t devinfo_root;		/* Address of root of devinfo tree */
   1018      0    stevel 	int status;
   1019      0    stevel 
   1020      0    stevel 	data.di_flags = DEVINFO_PARENT | DEVINFO_CHILD;
   1021      0    stevel 
   1022      0    stevel 	if (mdb_getopts(argc, argv,
   1023      0    stevel 	    'v', MDB_OPT_SETBITS, DEVINFO_VERBOSE, &data.di_flags,
   1024      0    stevel 	    'p', MDB_OPT_CLRBITS, DEVINFO_CHILD, &data.di_flags,
   1025      0    stevel 	    'c', MDB_OPT_CLRBITS, DEVINFO_PARENT, &data.di_flags, NULL) != argc)
   1026      0    stevel 		return (DCMD_USAGE);
   1027   5839     dmick 
   1028   5839     dmick 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
   1029   5839     dmick 		mdb_warn("failed to read 'top_devinfo'");
   1030   5839     dmick 		return (NULL);
   1031   5839     dmick 	}
   1032      0    stevel 
   1033      0    stevel 	if ((flags & DCMD_ADDRSPEC) == 0) {
   1034      0    stevel 		addr = devinfo_root;
   1035      0    stevel 		if (data.di_flags & DEVINFO_VERBOSE)
   1036      0    stevel 			data.di_flags |= DEVINFO_ALLBOLD;
   1037      0    stevel 	}
   1038      0    stevel 
   1039      0    stevel 	data.di_base = addr;
   1040      0    stevel 	mdb_printf("%<u>%-?s %-50s%</u>\n", "DEVINFO", "NAME");
   1041      0    stevel 
   1042      0    stevel 	if ((data.di_flags & (DEVINFO_PARENT | DEVINFO_CHILD)) ==
   1043      0    stevel 	    (DEVINFO_PARENT | DEVINFO_CHILD)) {
   1044      0    stevel 		status = mdb_pwalk("devinfo",
   1045      0    stevel 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
   1046      0    stevel 	} else if (data.di_flags & DEVINFO_PARENT) {
   1047      0    stevel 		status = mdb_pwalk("devinfo_parents",
   1048      0    stevel 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
   1049      0    stevel 	} else if (data.di_flags & DEVINFO_CHILD) {
   1050      0    stevel 		status = mdb_pwalk("devinfo_children",
   1051      0    stevel 		    (mdb_walk_cb_t)devinfo_print, &data, addr);
   1052      0    stevel 	} else {
   1053      0    stevel 		devinfo_node_t din;
   1054      0    stevel 		if (mdb_vread(&din.din_dev, sizeof (din.din_dev), addr) == -1) {
   1055      0    stevel 			mdb_warn("failed to read device");
   1056      0    stevel 			return (DCMD_ERR);
   1057      0    stevel 		}
   1058      0    stevel 		din.din_depth = 0;
   1059      0    stevel 		return (devinfo_print(addr, (struct dev_info *)&din, &data));
   1060      0    stevel 	}
   1061      0    stevel 
   1062      0    stevel 	if (status == -1) {
   1063      0    stevel 		mdb_warn("couldn't walk devinfo tree");
   1064      0    stevel 		return (DCMD_ERR);
   1065      0    stevel 	}
   1066      0    stevel 
   1067      0    stevel 	return (DCMD_OK);
   1068      0    stevel }
   1069      0    stevel 
   1070      0    stevel /*ARGSUSED*/
   1071      0    stevel int
   1072      0    stevel devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1073      0    stevel {
   1074      0    stevel 	char tmpstr[MODMAXNAMELEN];
   1075      0    stevel 	char nodename[MODMAXNAMELEN];
   1076   4145       cth 	char bindname[MAXPATHLEN];
   1077      0    stevel 	int size, length;
   1078      0    stevel 	struct dev_info devi;
   1079      0    stevel 	devinfo_node_t din;
   1080      0    stevel 	devinfo_cb_data_t data;
   1081      0    stevel 
   1082      0    stevel 	static const mdb_bitmask_t devi_state_masks[] = {
   1083      0    stevel 	    { "DEVICE_OFFLINE",	DEVI_DEVICE_OFFLINE,	DEVI_DEVICE_OFFLINE },
   1084      0    stevel 	    { "DEVICE_DOWN",	DEVI_DEVICE_DOWN,	DEVI_DEVICE_DOWN },
   1085      0    stevel 	    { "DEVICE_DEGRADED", DEVI_DEVICE_DEGRADED,	DEVI_DEVICE_DEGRADED },
   1086   4145       cth 	    { "DEVICE_REMOVED", DEVI_DEVICE_REMOVED,	DEVI_DEVICE_REMOVED },
   1087      0    stevel 	    { "BUS_QUIESCED",	DEVI_BUS_QUIESCED,	DEVI_BUS_QUIESCED },
   1088      0    stevel 	    { "BUS_DOWN",	DEVI_BUS_DOWN,		DEVI_BUS_DOWN },
   1089      0    stevel 	    { "NDI_CONFIG",	DEVI_NDI_CONFIG,	DEVI_NDI_CONFIG	},
   1090      0    stevel 
   1091      0    stevel 	    { "S_ATTACHING",	DEVI_S_ATTACHING,	DEVI_S_ATTACHING },
   1092      0    stevel 	    { "S_DETACHING",	DEVI_S_DETACHING,	DEVI_S_DETACHING },
   1093      0    stevel 	    { "S_ONLINING",	DEVI_S_ONLINING,	DEVI_S_ONLINING },
   1094      0    stevel 	    { "S_OFFLINING",	DEVI_S_OFFLINING,	DEVI_S_OFFLINING },
   1095      0    stevel 	    { "S_INVOKING_DACF", DEVI_S_INVOKING_DACF,	DEVI_S_INVOKING_DACF },
   1096      0    stevel 	    { "S_UNBOUND",	DEVI_S_UNBOUND,		DEVI_S_UNBOUND },
   1097      0    stevel 	    { "S_REPORT",	DEVI_S_REPORT,		DEVI_S_REPORT },
   1098      0    stevel 	    { "S_EVADD",	DEVI_S_EVADD,		DEVI_S_EVADD },
   1099      0    stevel 	    { "S_EVREMOVE",	DEVI_S_EVREMOVE,	DEVI_S_EVREMOVE },
   1100   4145       cth 	    { "S_NEED_RESET",	DEVI_S_NEED_RESET,	DEVI_S_NEED_RESET },
   1101      0    stevel 	    { NULL,		0,			0 }
   1102      0    stevel 	};
   1103      0    stevel 
   1104      0    stevel 	static const mdb_bitmask_t devi_flags_masks[] = {
   1105      0    stevel 	    { "BUSY",		DEVI_BUSY,		DEVI_BUSY },
   1106      0    stevel 	    { "MADE_CHILDREN",	DEVI_MADE_CHILDREN,	DEVI_MADE_CHILDREN },
   1107      0    stevel 	    { "ATTACHED_CHILDREN",
   1108      0    stevel 				DEVI_ATTACHED_CHILDREN,	DEVI_ATTACHED_CHILDREN},
   1109      0    stevel 	    { "BRANCH_HELD",	DEVI_BRANCH_HELD,	DEVI_BRANCH_HELD },
   1110   4145       cth 	    { "NO_BIND",	DEVI_NO_BIND,		DEVI_NO_BIND },
   1111   4145       cth 	    { "DEVI_REGISTERED_DEVID",
   1112   4145       cth 				DEVI_REGISTERED_DEVID,	DEVI_REGISTERED_DEVID },
   1113   4145       cth 	    { "PHCI_SIGNALS_VHCI",
   1114   4145       cth 				DEVI_PHCI_SIGNALS_VHCI,
   1115   4145       cth 				DEVI_PHCI_SIGNALS_VHCI },
   1116   4145       cth 	    { "REBIND",		DEVI_REBIND,		DEVI_REBIND },
   1117      0    stevel 	    { NULL,		0,			0 }
   1118      0    stevel 	};
   1119      0    stevel 
   1120      0    stevel 	data.di_flags = DEVINFO_VERBOSE;
   1121      0    stevel 	data.di_base = addr;
   1122      0    stevel 
   1123      0    stevel 	if (mdb_getopts(argc, argv,
   1124      0    stevel 	    'q', MDB_OPT_CLRBITS, DEVINFO_VERBOSE, &data.di_flags,
   1125      0    stevel 	    's', MDB_OPT_SETBITS, DEVINFO_SUMMARY, &data.di_flags, NULL)
   1126      0    stevel 	    != argc)
   1127      0    stevel 		return (DCMD_USAGE);
   1128      0    stevel 
   1129      0    stevel 	if ((flags & DCMD_ADDRSPEC) == 0) {
   1130      0    stevel 		mdb_warn(
   1131      0    stevel 		    "devinfo doesn't give global information (try prtconf)\n");
   1132      0    stevel 		return (DCMD_ERR);
   1133      0    stevel 	}
   1134      0    stevel 
   1135      0    stevel 	if (DCMD_HDRSPEC(flags) && data.di_flags & DEVINFO_SUMMARY)
   1136      0    stevel 		mdb_printf(
   1137      0    stevel 		    "%-?s %5s %?s %-20s %-s\n"
   1138      0    stevel 		    "%-?s %5s %?s %-20s %-s\n"
   1139      0    stevel 		    "%<u>%-?s %5s %?s %-20s %-15s%</u>\n",
   1140      0    stevel 		    "DEVINFO", "MAJ",  "REFCNT",   "NODENAME", "NODESTATE",
   1141      0    stevel 		    "",        "INST", "CIRCULAR", "BINDNAME", "STATE",
   1142      0    stevel 		    "",        "",     "THREAD",   "",         "FLAGS");
   1143      0    stevel 
   1144      0    stevel 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
   1145      0    stevel 		mdb_warn("failed to read device");
   1146      0    stevel 		return (DCMD_ERR);
   1147      0    stevel 	}
   1148      0    stevel 
   1149      0    stevel 	if (data.di_flags & DEVINFO_SUMMARY) {
   1150      0    stevel 		*nodename = '\0';
   1151      0    stevel 		size = sizeof (nodename);
   1152      0    stevel 
   1153      0    stevel 		if ((length = mdb_readstr(tmpstr, size,
   1154      0    stevel 		    (uintptr_t)devi.devi_node_name)) > 0) {
   1155      0    stevel 			strcat(nodename, tmpstr);
   1156      0    stevel 			size -= length;
   1157      0    stevel 		}
   1158      0    stevel 
   1159      0    stevel 		if (devi.devi_addr != NULL && mdb_readstr(tmpstr, size - 1,
   1160      0    stevel 		    (uintptr_t)devi.devi_addr) > 0) {
   1161      0    stevel 			strcat(nodename, "@");
   1162      0    stevel 			strcat(nodename, tmpstr);
   1163      0    stevel 		}
   1164      0    stevel 
   1165      0    stevel 		if (mdb_readstr(bindname, sizeof (bindname),
   1166      0    stevel 		    (uintptr_t)devi.devi_binding_name) == -1)
   1167      0    stevel 			*bindname = '\0';
   1168      0    stevel 
   1169      0    stevel 		mdb_printf("%0?p %5d %?d %-20s %s\n",
   1170      0    stevel 		    addr, devi.devi_major, devi.devi_ref, nodename,
   1171      0    stevel 		    di_state[MIN(devi.devi_node_state + 1, DI_STATE_MAX)]);
   1172      0    stevel 		mdb_printf("%?s %5d %?d %-20s <%b>\n",
   1173      0    stevel 		    "", devi.devi_instance, devi.devi_circular, bindname,
   1174      0    stevel 		    devi.devi_state, devi_state_masks);
   1175      0    stevel 		mdb_printf("%?s %5s %?p %-20s <%b>\n\n",
   1176      0    stevel 		    "", "", devi.devi_busy_thread, "",
   1177      0    stevel 		    devi.devi_flags, devi_flags_masks);
   1178      0    stevel 
   1179      0    stevel 		return (DCMD_OK);
   1180      0    stevel 	} else {
   1181      0    stevel 		din.din_dev = devi;
   1182      0    stevel 		din.din_depth = 0;
   1183      0    stevel 		return (devinfo_print(addr, (struct dev_info *)&din, &data));
   1184      0    stevel 	}
   1185      0    stevel }
   1186      0    stevel 
   1187      0    stevel /*ARGSUSED*/
   1188      0    stevel int
   1189      0    stevel m2d_walk_dinfo(uintptr_t addr, struct dev_info *di, char *mod_name)
   1190      0    stevel {
   1191      0    stevel 	char name[MODMAXNAMELEN];
   1192      0    stevel 
   1193      0    stevel 	if (mdb_readstr(name, MODMAXNAMELEN,
   1194      0    stevel 	    (uintptr_t)di->devi_binding_name) == -1) {
   1195      0    stevel 		mdb_warn("couldn't read devi_binding_name at %p",
   1196      0    stevel 		    di->devi_binding_name);
   1197      0    stevel 		return (WALK_ERR);
   1198      0    stevel 	}
   1199      0    stevel 
   1200      0    stevel 	if (strcmp(name, mod_name) == 0)
   1201      0    stevel 		mdb_printf("%p\n", addr);
   1202      0    stevel 
   1203      0    stevel 	return (WALK_NEXT);
   1204      0    stevel }
   1205      0    stevel 
   1206      0    stevel /*ARGSUSED*/
   1207      0    stevel int
   1208      0    stevel modctl2devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1209      0    stevel {
   1210      0    stevel 	struct modctl modctl;
   1211      0    stevel 	char name[MODMAXNAMELEN];
   1212      0    stevel 
   1213      0    stevel 	if (!(flags & DCMD_ADDRSPEC))
   1214      0    stevel 		return (DCMD_USAGE);
   1215      0    stevel 
   1216      0    stevel 	if (mdb_vread(&modctl, sizeof (modctl), addr) == -1) {
   1217      0    stevel 		mdb_warn("couldn't read modctl at %p", addr);
   1218      0    stevel 		return (DCMD_ERR);
   1219      0    stevel 	}
   1220      0    stevel 
   1221      0    stevel 	if (mdb_readstr(name, MODMAXNAMELEN,
   1222      0    stevel 	    (uintptr_t)modctl.mod_modname) == -1) {
   1223      0    stevel 		mdb_warn("couldn't read modname at %p", modctl.mod_modname);
   1224      0    stevel 		return (DCMD_ERR);
   1225      0    stevel 	}
   1226      0    stevel 
   1227      0    stevel 	if (mdb_walk("devinfo", (mdb_walk_cb_t)m2d_walk_dinfo, name) == -1) {
   1228      0    stevel 		mdb_warn("couldn't walk devinfo");
   1229      0    stevel 		return (DCMD_ERR);
   1230      0    stevel 	}
   1231      0    stevel 
   1232      0    stevel 	return (DCMD_OK);
   1233      0    stevel }
   1234      0    stevel 
   1235      0    stevel static int
   1236      0    stevel major_to_addr(major_t major, uintptr_t *vaddr)
   1237      0    stevel {
   1238      0    stevel 	uint_t devcnt;
   1239      0    stevel 	uintptr_t devnamesp;
   1240      0    stevel 
   1241      0    stevel 	if (mdb_readvar(&devcnt, "devcnt") == -1) {
   1242      0    stevel 		mdb_warn("failed to read 'devcnt'");
   1243      0    stevel 		return (-1);
   1244      0    stevel 	}
   1245      0    stevel 
   1246      0    stevel 	if (mdb_readvar(&devnamesp, "devnamesp") == -1) {
   1247      0    stevel 		mdb_warn("failed to read 'devnamesp'");
   1248      0    stevel 		return (-1);
   1249      0    stevel 	}
   1250      0    stevel 
   1251      0    stevel 	if (major >= devcnt) {
   1252      0    stevel 		mdb_warn("%x is out of range [0x0-0x%x]\n", major, devcnt - 1);
   1253      0    stevel 		return (-1);
   1254      0    stevel 	}
   1255      0    stevel 
   1256      0    stevel 	*vaddr = devnamesp + (major * sizeof (struct devnames));
   1257      0    stevel 	return (0);
   1258      0    stevel }
   1259      0    stevel 
   1260      0    stevel /*ARGSUSED*/
   1261      0    stevel int
   1262      0    stevel devnames(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1263      0    stevel {
   1264      0    stevel 	static const mdb_bitmask_t dn_flag_bits[] = {
   1265      0    stevel 		{ "DN_CONF_PARSED",	DN_CONF_PARSED, DN_CONF_PARSED },
   1266      0    stevel 		{ "DN_DRIVER_BUSY",	DN_DRIVER_BUSY, DN_DRIVER_BUSY },
   1267      0    stevel 		{ "DN_DRIVER_HELD",	DN_DRIVER_HELD, DN_DRIVER_HELD },
   1268      0    stevel 		{ "DN_TAKEN_GETUDEV",	DN_TAKEN_GETUDEV, DN_TAKEN_GETUDEV },
   1269      0    stevel 		{ "DN_DRIVER_REMOVED",	DN_DRIVER_REMOVED, DN_DRIVER_REMOVED},
   1270      0    stevel 		{ "DN_FORCE_ATTACH",	DN_FORCE_ATTACH, DN_FORCE_ATTACH},
   1271      0    stevel 		{ "DN_LEAF_DRIVER",	DN_LEAF_DRIVER, DN_LEAF_DRIVER},
   1272      0    stevel 		{ "DN_NETWORK_DRIVER",	DN_NETWORK_DRIVER, DN_NETWORK_DRIVER},
   1273      0    stevel 		{ "DN_NO_AUTODETACH",	DN_NO_AUTODETACH, DN_NO_AUTODETACH },
   1274    385       cth 		{ "DN_GLDV3_DRIVER",	DN_GLDV3_DRIVER, DN_GLDV3_DRIVER},
   1275   1993     ramat 		{ "DN_PHCI_DRIVER",	DN_PHCI_DRIVER, DN_PHCI_DRIVER},
   1276   6640       cth 		{ "DN_OPEN_RETURNS_EINTR", \
   1277   6640       cth 				DN_OPEN_RETURNS_EINTR, DN_OPEN_RETURNS_EINTR},
   1278   6640       cth 		{ "DN_SCSI_SIZE_CLEAN",	DN_SCSI_SIZE_CLEAN, DN_SCSI_SIZE_CLEAN},
   1279  10788     Cathy 		{ "DN_NETWORK_PHYSDRIVER", \
   1280  10788     Cathy 				DN_NETWORK_PHYSDRIVER, DN_NETWORK_PHYSDRIVER},
   1281      0    stevel 		{ NULL, 0, 0 }
   1282      0    stevel 	};
   1283      0    stevel 
   1284      0    stevel 	const mdb_arg_t *argp = NULL;
   1285      0    stevel 	uint_t opt_v = FALSE, opt_m = FALSE;
   1286      0    stevel 	major_t major;
   1287      0    stevel 	size_t i;
   1288      0    stevel 
   1289      0    stevel 	char name[MODMAXNAMELEN + 1];
   1290      0    stevel 	struct devnames dn;
   1291      0    stevel 
   1292      0    stevel 	if ((i = mdb_getopts(argc, argv,
   1293      0    stevel 	    'm', MDB_OPT_SETBITS, TRUE, &opt_m,
   1294      0    stevel 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v,
   1295      0    stevel 	    NULL)) != argc) {
   1296      0    stevel 		if (argc - i > 1)
   1297      0    stevel 			return (DCMD_USAGE);
   1298      0    stevel 		argp = &argv[i];
   1299      0    stevel 	}
   1300      0    stevel 
   1301      0    stevel 	if (opt_m) {
   1302      0    stevel 		if (!(flags & DCMD_ADDRSPEC))
   1303      0    stevel 			return (DCMD_USAGE);
   1304      0    stevel 
   1305      0    stevel 		if (major_to_addr(addr, &addr) == -1)
   1306      0    stevel 			return (DCMD_ERR);
   1307      0    stevel 
   1308      0    stevel 	} else if (!(flags & DCMD_ADDRSPEC)) {
   1309      0    stevel 		if (argp == NULL) {
   1310      0    stevel 			if (mdb_walk_dcmd("devnames", "devnames", argc, argv)) {
   1311      0    stevel 				mdb_warn("failed to walk devnames");
   1312      0    stevel 				return (DCMD_ERR);
   1313      0    stevel 			}
   1314      0    stevel 			return (DCMD_OK);
   1315      0    stevel 		}
   1316      0    stevel 
   1317      0    stevel 		if (argp->a_type == MDB_TYPE_IMMEDIATE)
   1318      0    stevel 			major = (major_t)argp->a_un.a_val;
   1319      0    stevel 		else
   1320      0    stevel 			major = (major_t)mdb_strtoull(argp->a_un.a_str);
   1321      0    stevel 
   1322      0    stevel 		if (major_to_addr(major, &addr) == -1)
   1323      0    stevel 			return (DCMD_ERR);
   1324      0    stevel 	}
   1325      0    stevel 
   1326      0    stevel 	if (mdb_vread(&dn, sizeof (struct devnames), addr) == -1) {
   1327      0    stevel 		mdb_warn("failed to read devnames struct at %p", addr);
   1328      0    stevel 		return (DCMD_ERR);
   1329      0    stevel 	}
   1330      0    stevel 
   1331      0    stevel 	if (DCMD_HDRSPEC(flags)) {
   1332      0    stevel 		if (opt_v)
   1333      0    stevel 			mdb_printf("%<u>%-16s%</u>\n", "NAME");
   1334      0    stevel 		else
   1335      0    stevel 			mdb_printf("%<u>%-16s %-?s%</u>\n", "NAME", "DN_HEAD");
   1336      0    stevel 	}
   1337      0    stevel 
   1338      0    stevel 	if ((flags & DCMD_LOOP) && (dn.dn_name == NULL))
   1339      0    stevel 		return (DCMD_OK); /* Skip empty slots if we're printing table */
   1340      0    stevel 
   1341      0    stevel 	if (mdb_readstr(name, sizeof (name), (uintptr_t)dn.dn_name) == -1)
   1342      0    stevel 		(void) mdb_snprintf(name, sizeof (name), "0x%p", dn.dn_name);
   1343      0    stevel 
   1344      0    stevel 	if (opt_v) {
   1345      0    stevel 		ddi_prop_list_t prop_list;
   1346      0    stevel 		mdb_printf("%<b>%-16s%</b>\n", name);
   1347      0    stevel 		mdb_inc_indent(2);
   1348      0    stevel 
   1349      0    stevel 		mdb_printf("          flags %b\n", dn.dn_flags, dn_flag_bits);
   1350      0    stevel 		mdb_printf("             pl %p\n", (void *)dn.dn_pl);
   1351      0    stevel 		mdb_printf("           head %p\n", dn.dn_head);
   1352      0    stevel 		mdb_printf("       instance %d\n", dn.dn_instance);
   1353      0    stevel 		mdb_printf("         inlist %p\n", dn.dn_inlist);
   1354      0    stevel 		mdb_printf("global_prop_ptr %p\n", dn.dn_global_prop_ptr);
   1355      0    stevel 		if (mdb_vread(&prop_list, sizeof (ddi_prop_list_t),
   1356      0    stevel 		    (uintptr_t)dn.dn_global_prop_ptr) != -1) {
   1357      0    stevel 			devinfo_print_props(NULL, prop_list.prop_list);
   1358      0    stevel 		}
   1359      0    stevel 
   1360      0    stevel 		mdb_dec_indent(2);
   1361      0    stevel 	} else
   1362      0    stevel 		mdb_printf("%-16s %-?p\n", name, dn.dn_head);
   1363      0    stevel 
   1364      0    stevel 	return (DCMD_OK);
   1365      0    stevel }
   1366      0    stevel 
   1367      0    stevel /*ARGSUSED*/
   1368      0    stevel int
   1369      0    stevel name2major(uintptr_t vaddr, uint_t flags, int argc, const mdb_arg_t *argv)
   1370      0    stevel {
   1371      0    stevel 	major_t major;
   1372      0    stevel 
   1373      0    stevel 	if (flags & DCMD_ADDRSPEC)
   1374      0    stevel 		return (DCMD_USAGE);
   1375      0    stevel 
   1376      0    stevel 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
   1377      0    stevel 		return (DCMD_USAGE);
   1378      0    stevel 
   1379      0    stevel 	if (mdb_name_to_major(argv->a_un.a_str, &major) != 0) {
   1380      0    stevel 		mdb_warn("failed to convert name to major number\n");
   1381      0    stevel 		return (DCMD_ERR);
   1382      0    stevel 	}
   1383      0    stevel 
   1384      0    stevel 	mdb_printf("0x%x\n", major);
   1385      0    stevel 	return (DCMD_OK);
   1386      0    stevel }
   1387      0    stevel 
   1388      0    stevel /*
   1389      0    stevel  * Get a numerical argument of a dcmd from addr if an address is specified
   1390      0    stevel  * or from argv if no address is specified. Return the argument in ret.
   1391      0    stevel  */
   1392      0    stevel static int
   1393      0    stevel getarg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
   1394      0    stevel     uintptr_t *ret)
   1395      0    stevel {
   1396      0    stevel 	if (argc == 0 && (flags & DCMD_ADDRSPEC)) {
   1397      0    stevel 		*ret = addr;
   1398      0    stevel 
   1399      0    stevel 	} else if (argc == 1 && !(flags & DCMD_ADDRSPEC)) {
   1400      0    stevel 		*ret = (argv[0].a_type == MDB_TYPE_IMMEDIATE) ?
   1401      0    stevel 		    (uintptr_t)argv[0].a_un.a_val :
   1402      0    stevel 		    (uintptr_t)mdb_strtoull(argv->a_un.a_str);
   1403      0    stevel 
   1404      0    stevel 	} else {
   1405      0    stevel 		return (-1);
   1406      0    stevel 	}
   1407      0    stevel 
   1408      0    stevel 	return (0);
   1409      0    stevel }
   1410      0    stevel 
   1411      0    stevel /*ARGSUSED*/
   1412      0    stevel int
   1413      0    stevel major2name(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1414      0    stevel {
   1415      0    stevel 	uintptr_t major;
   1416      0    stevel 	const char *name;
   1417      0    stevel 
   1418      0    stevel 	if (getarg(addr, flags, argc, argv, &major) < 0)
   1419      0    stevel 		return (DCMD_USAGE);
   1420      0    stevel 
   1421      0    stevel 	if ((name = mdb_major_to_name((major_t)major)) == NULL) {
   1422      0    stevel 		mdb_warn("failed to convert major number to name\n");
   1423      0    stevel 		return (DCMD_ERR);
   1424      0    stevel 	}
   1425      0    stevel 
   1426      0    stevel 	mdb_printf("%s\n", name);
   1427      0    stevel 	return (DCMD_OK);
   1428      0    stevel }
   1429      0    stevel 
   1430      0    stevel /*ARGSUSED*/
   1431      0    stevel int
   1432      0    stevel dev2major(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1433      0    stevel {
   1434      0    stevel 	uintptr_t dev;
   1435      0    stevel 
   1436      0    stevel 	if (getarg(addr, flags, argc, argv, &dev) < 0)
   1437      0    stevel 		return (DCMD_USAGE);
   1438      0    stevel 
   1439      0    stevel 	if (flags & DCMD_PIPE_OUT)
   1440      0    stevel 		mdb_printf("%x\n", getmajor(dev));
   1441      0    stevel 	else
   1442      0    stevel 		mdb_printf("0x%x (0t%d)\n", getmajor(dev), getmajor(dev));
   1443      0    stevel 
   1444      0    stevel 	return (DCMD_OK);
   1445      0    stevel }
   1446      0    stevel 
   1447      0    stevel /*ARGSUSED*/
   1448      0    stevel int
   1449      0    stevel dev2minor(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1450      0    stevel {
   1451      0    stevel 	uintptr_t dev;
   1452      0    stevel 
   1453      0    stevel 	if (getarg(addr, flags, argc, argv, &dev) < 0)
   1454      0    stevel 		return (DCMD_USAGE);
   1455      0    stevel 
   1456      0    stevel 	if (flags & DCMD_PIPE_OUT)
   1457      0    stevel 		mdb_printf("%x\n", getminor(dev));
   1458      0    stevel 	else
   1459      0    stevel 		mdb_printf("0x%x (0t%d)\n", getminor(dev), getminor(dev));
   1460      0    stevel 
   1461      0    stevel 	return (DCMD_OK);
   1462      0    stevel }
   1463      0    stevel 
   1464      0    stevel /*ARGSUSED*/
   1465      0    stevel int
   1466      0    stevel devt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1467      0    stevel {
   1468      0    stevel 	uintptr_t dev;
   1469      0    stevel 
   1470      0    stevel 	if (getarg(addr, flags, argc, argv, &dev) < 0)
   1471      0    stevel 		return (DCMD_USAGE);
   1472      0    stevel 
   1473      0    stevel 	if (DCMD_HDRSPEC(flags)) {
   1474      0    stevel 		mdb_printf("%<u>%10s%</u>  %<u>%10s%</u>\n", "MAJOR",
   1475      0    stevel 		    "MINOR");
   1476      0    stevel 	}
   1477      0    stevel 
   1478      0    stevel 	mdb_printf("%10d  %10d\n", getmajor(dev), getminor(dev));
   1479      0    stevel 
   1480      0    stevel 	return (DCMD_OK);
   1481      0    stevel }
   1482      0    stevel 
   1483      0    stevel /*ARGSUSED*/
   1484      0    stevel int
   1485      0    stevel softstate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1486      0    stevel {
   1487      0    stevel 	uintptr_t statep;
   1488      0    stevel 	int instance;
   1489      0    stevel 
   1490      0    stevel 
   1491      0    stevel 	if (argc != 1) {
   1492      0    stevel 		return (DCMD_USAGE);
   1493      0    stevel 	}
   1494      0    stevel 
   1495      0    stevel 	if (argv[0].a_type == MDB_TYPE_IMMEDIATE)
   1496      0    stevel 		instance = argv[0].a_un.a_val;
   1497      0    stevel 	else
   1498      0    stevel 		instance = mdb_strtoull(argv->a_un.a_str);
   1499      0    stevel 
   1500      0    stevel 	if (mdb_get_soft_state_byaddr(addr, instance, &statep, NULL, 0) == -1) {
   1501      0    stevel 		if (errno == ENOENT) {
   1502      0    stevel 			mdb_warn("instance %d unused\n", instance);
   1503      0    stevel 		} else {
   1504      0    stevel 			mdb_warn("couldn't determine softstate for "
   1505      0    stevel 			    "instance %d", instance);
   1506      0    stevel 		}
   1507      0    stevel 
   1508      0    stevel 		return (DCMD_ERR);
   1509      0    stevel 	}
   1510      0    stevel 
   1511      0    stevel 	mdb_printf("%p\n", statep);
   1512      0    stevel 	return (DCMD_OK);
   1513      0    stevel }
   1514      0    stevel 
   1515      0    stevel /*
   1516      0    stevel  * Walker for all possible pointers to a driver state struct in an
   1517      0    stevel  * i_ddi_soft_state instance chain.  Returns all non-NULL pointers.
   1518      0    stevel  */
   1519      0    stevel typedef struct soft_state_walk {
   1520      0    stevel 	struct i_ddi_soft_state	ssw_ss;	/* Local copy of i_ddi_soft_state */
   1521      0    stevel 	void		**ssw_pointers;	/* to driver state structs */
   1522      0    stevel 	uint_t		ssw_index;	/* array entry we're using */
   1523      0    stevel } soft_state_walk_t;
   1524      0    stevel 
   1525      0    stevel int
   1526      0    stevel soft_state_walk_init(mdb_walk_state_t *wsp)
   1527      0    stevel {
   1528      0    stevel 	soft_state_walk_t *sst;
   1529      0    stevel 
   1530      0    stevel 
   1531      0    stevel 	if (wsp->walk_addr == NULL)
   1532      0    stevel 		return (WALK_DONE);
   1533      0    stevel 
   1534      0    stevel 	sst = mdb_zalloc(sizeof (soft_state_walk_t), UM_SLEEP|UM_GC);
   1535      0    stevel 	wsp->walk_data = sst;
   1536      0    stevel 
   1537      0    stevel 
   1538      0    stevel 	if (mdb_vread(&(sst->ssw_ss), sizeof (sst->ssw_ss), wsp->walk_addr) !=
   1539      0    stevel 	    sizeof (sst->ssw_ss)) {
   1540      0    stevel 		mdb_warn("failed to read i_ddi_soft_state at %p",
   1541      0    stevel 		    wsp->walk_addr);
   1542      0    stevel 		return (WALK_ERR);
   1543      0    stevel 	}
   1544      0    stevel 
   1545      0    stevel 
   1546      0    stevel 	/* Read array of pointers to state structs into local storage. */
   1547      0    stevel 	sst->ssw_pointers = mdb_alloc((sst->ssw_ss.n_items * sizeof (void *)),
   1548      0    stevel 	    UM_SLEEP|UM_GC);
   1549      0    stevel 
   1550      0    stevel 	if (mdb_vread(sst->ssw_pointers, (sst->ssw_ss.n_items *
   1551      0    stevel 	    sizeof (void *)), (uintptr_t)sst->ssw_ss.array) !=
   1552      0    stevel 	    (sst->ssw_ss.n_items * sizeof (void *))) {
   1553      0    stevel 		mdb_warn("failed to read i_ddi_soft_state at %p",
   1554      0    stevel 		    wsp->walk_addr);
   1555      0    stevel 		return (WALK_ERR);
   1556      0    stevel 	}
   1557      0    stevel 
   1558      0    stevel 	sst->ssw_index = 0;
   1559      0    stevel 
   1560      0    stevel 	return (WALK_NEXT);
   1561      0    stevel }
   1562      0    stevel 
   1563      0    stevel int
   1564      0    stevel soft_state_walk_step(mdb_walk_state_t *wsp)
   1565      0    stevel {
   1566      0    stevel 	soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data;
   1567      0    stevel 	int status = WALK_NEXT;
   1568      0    stevel 
   1569      0    stevel 
   1570      0    stevel 	/*
   1571      0    stevel 	 * If the entry indexed has a valid pointer to a soft state struct,
   1572      0    stevel 	 * invoke caller's callback func.
   1573      0    stevel 	 */
   1574      0    stevel 	if (sst->ssw_pointers[sst->ssw_index] != NULL) {
   1575      0    stevel 		status = wsp->walk_callback(
   1576      0    stevel 		    (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL,
   1577      0    stevel 		    wsp->walk_cbdata);
   1578      0    stevel 	}
   1579      0    stevel 
   1580      0    stevel 	sst->ssw_index += 1;
   1581      0    stevel 
   1582      0    stevel 	if (sst->ssw_index == sst->ssw_ss.n_items)
   1583      0    stevel 		return (WALK_DONE);
   1584      0    stevel 
   1585      0    stevel 	return (status);
   1586      0    stevel }
   1587      0    stevel 
   1588      0    stevel int
   1589      0    stevel soft_state_all_walk_step(mdb_walk_state_t *wsp)
   1590      0    stevel {
   1591      0    stevel 	soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data;
   1592      0    stevel 	int status = WALK_NEXT;
   1593      0    stevel 
   1594      0    stevel 
   1595      0    stevel 	status = wsp->walk_callback(
   1596      0    stevel 	    (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL,
   1597      0    stevel 	    wsp->walk_cbdata);
   1598      0    stevel 
   1599      0    stevel 	sst->ssw_index += 1;
   1600      0    stevel 
   1601      0    stevel 	if (sst->ssw_index == sst->ssw_ss.n_items)
   1602      0    stevel 		return (WALK_DONE);
   1603      0    stevel 
   1604      0    stevel 	return (status);
   1605      0    stevel }
   1606      0    stevel 
   1607      0    stevel /*ARGSUSED*/
   1608      0    stevel int
   1609      0    stevel devbindings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1610      0    stevel {
   1611      0    stevel 	const mdb_arg_t *arg;
   1612      0    stevel 	struct devnames dn;
   1613      0    stevel 	uintptr_t dn_addr;
   1614      0    stevel 	major_t major;
   1615      0    stevel 
   1616      0    stevel 	if (!(flags & DCMD_ADDRSPEC) && argc < 1)
   1617      0    stevel 		return (DCMD_USAGE);
   1618      0    stevel 
   1619      0    stevel 	if (flags & DCMD_ADDRSPEC) {
   1620      0    stevel 		/*
   1621      0    stevel 		 * If there's an address, then it's a major number
   1622      0    stevel 		 */
   1623      0    stevel 		major = addr;
   1624      0    stevel 	} else {
   1625      0    stevel 		/*
   1626      0    stevel 		 * We interpret the last argument. Any other arguments are
   1627      0    stevel 		 * forwarded to "devinfo"
   1628      0    stevel 		 */
   1629      0    stevel 		arg = &argv[argc - 1];
   1630      0    stevel 		argc--;
   1631      0    stevel 
   1632      0    stevel 		if (arg->a_type == MDB_TYPE_IMMEDIATE) {
   1633      0    stevel 			major = (uintptr_t)arg->a_un.a_val;
   1634      0    stevel 
   1635      0    stevel 		} else if (arg->a_un.a_str[0] == '-') {
   1636      0    stevel 			/* the argument shouldn't be an option */
   1637      0    stevel 			return (DCMD_USAGE);
   1638      0    stevel 
   1639      0    stevel 		} else if (isdigit(arg->a_un.a_str[0])) {
   1640      0    stevel 			major = (uintptr_t)mdb_strtoull(arg->a_un.a_str);
   1641      0    stevel 
   1642      0    stevel 		} else {
   1643      0    stevel 			if (mdb_name_to_major(arg->a_un.a_str, &major) != 0) {
   1644      0    stevel 				mdb_warn("failed to get major number for %s\n",
   1645      0    stevel 				    arg->a_un.a_str);
   1646      0    stevel 				return (DCMD_ERR);
   1647      0    stevel 			}
   1648      0    stevel 		}
   1649      0    stevel 	}
   1650      0    stevel 
   1651      0    stevel 	if (major_to_addr(major, &dn_addr) != 0)
   1652      0    stevel 		return (DCMD_ERR);
   1653      0    stevel 
   1654      0    stevel 	if (mdb_vread(&dn, sizeof (struct devnames), dn_addr) == -1) {
   1655      0    stevel 		mdb_warn("couldn't read devnames array at %p", dn_addr);
   1656      0    stevel 		return (DCMD_ERR);
   1657      0    stevel 	}
   1658      0    stevel 
   1659      0    stevel 	if (mdb_pwalk_dcmd("devi_next", "devinfo", argc, argv,
   1660      0    stevel 	    (uintptr_t)dn.dn_head) != 0) {
   1661      0    stevel 		mdb_warn("couldn't walk the devinfo chain at %p", dn.dn_head);
   1662      0    stevel 		return (DCMD_ERR);
   1663      0    stevel 	}
   1664      0    stevel 
   1665      0    stevel 	return (DCMD_OK);
   1666      0    stevel }
   1667      0    stevel 
   1668      0    stevel /*
   1669      0    stevel  * walk binding hashtable (as of of driver names (e.g., mb_hashtab))
   1670      0    stevel  */
   1671      0    stevel int
   1672      0    stevel binding_hash_walk_init(mdb_walk_state_t *wsp)
   1673      0    stevel {
   1674      0    stevel 	if (wsp->walk_addr == NULL)
   1675      0    stevel 		return (WALK_ERR);
   1676      0    stevel 
   1677      0    stevel 	wsp->walk_data = mdb_alloc(sizeof (void *) * MOD_BIND_HASHSIZE,
   1678      0    stevel 	    UM_SLEEP|UM_GC);
   1679      0    stevel 	if (mdb_vread(wsp->walk_data, sizeof (void *) * MOD_BIND_HASHSIZE,
   1680      0    stevel 	    wsp->walk_addr) == -1) {
   1681      0    stevel 		mdb_warn("failed to read mb_hashtab");
   1682      0    stevel 		return (WALK_ERR);
   1683      0    stevel 	}
   1684      0    stevel 
   1685      0    stevel 	wsp->walk_arg = 0;	/* index into mb_hashtab array to start */
   1686      0    stevel 
   1687      0    stevel 	return (WALK_NEXT);
   1688      0    stevel }
   1689      0    stevel 
   1690      0    stevel int
   1691      0    stevel binding_hash_walk_step(mdb_walk_state_t *wsp)
   1692      0    stevel {
   1693      0    stevel 	int		status;
   1694      0    stevel 	uintptr_t	bind_p;
   1695      0    stevel 	struct bind	bind;
   1696      0    stevel 
   1697      0    stevel 
   1698      0    stevel 	/*
   1699      0    stevel 	 * Walk the singly-linked list of struct bind
   1700      0    stevel 	 */
   1701      0    stevel 	bind_p = ((uintptr_t *)wsp->walk_data)[(ulong_t)wsp->walk_arg];
   1702      0    stevel 	while (bind_p != NULL) {
   1703      0    stevel 
   1704      0    stevel 		if (mdb_vread(&bind, sizeof (bind), bind_p) == -1) {
   1705      0    stevel 			mdb_warn("failed to read bind struct at %p",
   1706      0    stevel 			    wsp->walk_addr);
   1707      0    stevel 			return (WALK_ERR);
   1708      0    stevel 		}
   1709      0    stevel 
   1710      0    stevel 		if ((status = wsp->walk_callback(bind_p, &bind,
   1711      0    stevel 		    wsp->walk_cbdata)) != WALK_NEXT) {
   1712      0    stevel 			return (status);
   1713      0    stevel 		}
   1714      0    stevel 
   1715      0    stevel 		bind_p = (uintptr_t)bind.b_next;
   1716      0    stevel 	}
   1717      0    stevel 
   1718      0    stevel 	wsp->walk_arg = (void *)((char *)wsp->walk_arg + 1);
   1719      0    stevel 
   1720      0    stevel 	if (wsp->walk_arg == (void *)(MOD_BIND_HASHSIZE - 1))
   1721      0    stevel 		return (WALK_DONE);
   1722      0    stevel 
   1723      0    stevel 	return (WALK_NEXT);
   1724      0    stevel }
   1725      0    stevel 
   1726      0    stevel /*ARGSUSED*/
   1727      0    stevel int
   1728      0    stevel binding_hash_entry(uintptr_t addr, uint_t flags, int argc,
   1729      0    stevel     const mdb_arg_t *argv)
   1730      0    stevel {
   1731      0    stevel 	struct bind 	bind;
   1732      0    stevel 	/* Arbitrary lengths based on output format below */
   1733   4145       cth 	char name[MAXPATHLEN] = "???";
   1734   4145       cth 	char bind_name[MAXPATHLEN] = "<null>";
   1735      0    stevel 
   1736      0    stevel 	if ((flags & DCMD_ADDRSPEC) == NULL)
   1737      0    stevel 		return (DCMD_USAGE);
   1738      0    stevel 
   1739      0    stevel 	/* Allow null addresses to be passed (as from a walker) */
   1740      0    stevel 	if (addr == NULL)
   1741      0    stevel 		return (DCMD_OK);
   1742      0    stevel 
   1743      0    stevel 	if (mdb_vread(&bind, sizeof (bind), addr) == -1) {
   1744      0    stevel 		mdb_warn("failed to read struct bind at %p", addr);
   1745      0    stevel 		return (DCMD_ERR);
   1746      0    stevel 	}
   1747      0    stevel 
   1748      0    stevel 	if (DCMD_HDRSPEC(flags)) {
   1749   4145       cth 		mdb_printf("%<u>%?s% %-5s %s%</u>\n",
   1750   4145       cth 		    "NEXT", "MAJOR", "NAME(S)");
   1751      0    stevel 	}
   1752      0    stevel 
   1753      0    stevel 	if (mdb_readstr(name, sizeof (name), (uintptr_t)bind.b_name) == -1)
   1754      0    stevel 		mdb_warn("failed to read 'name'");
   1755      0    stevel 
   1756   4145       cth 	/* There may be bind_name, so this may fail */
   1757   4145       cth 	if (mdb_readstr(bind_name, sizeof (bind_name),
   1758   4145       cth 	    (uintptr_t)bind.b_bind_name) == -1) {
   1759   4145       cth 		mdb_printf("%?p %5d %s\n",
   1760   4145       cth 		    bind.b_next, bind.b_num, name);
   1761   4145       cth 	} else {
   1762   4145       cth 		mdb_printf("%?p %5d %s %s\n",
   1763   4145       cth 		    bind.b_next, bind.b_num, name, bind_name);
   1764   4145       cth 	}
   1765      0    stevel 
   1766      0    stevel 	return (DCMD_OK);
   1767      0    stevel }
   1768      0    stevel 
   1769      0    stevel typedef struct devinfo_audit_log_walk_data {
   1770      0    stevel 	devinfo_audit_t dil_buf;	/* buffer of last entry */
   1771      0    stevel 	uintptr_t dil_base;		/* starting address of log buffer */
   1772      0    stevel 	int dil_max;			/* maximum index */
   1773      0    stevel 	int dil_start;			/* starting index */
   1774      0    stevel 	int dil_index;			/* current walking index */
   1775      0    stevel } devinfo_audit_log_walk_data_t;
   1776      0    stevel 
   1777      0    stevel int
   1778      0    stevel devinfo_audit_log_walk_init(mdb_walk_state_t *wsp)
   1779      0    stevel {
   1780      0    stevel 	devinfo_log_header_t header;
   1781      0    stevel 	devinfo_audit_log_walk_data_t *dil;
   1782      0    stevel 	uintptr_t devinfo_audit_log;
   1783      0    stevel 
   1784      0    stevel 	/* read in devinfo_log_header structure */
   1785      0    stevel 	if (mdb_readvar(&devinfo_audit_log, "devinfo_audit_log") == -1) {
   1786      0    stevel 		mdb_warn("failed to read 'devinfo_audit_log'");
   1787      0    stevel 		return (WALK_ERR);
   1788      0    stevel 	}
   1789      0    stevel 
   1790      0    stevel 	if (mdb_vread(&header, sizeof (devinfo_log_header_t),
   1791      0    stevel 	    devinfo_audit_log) == -1) {
   1792      0    stevel 		mdb_warn("couldn't read devinfo_log_header at %p",
   1793      0    stevel 		    devinfo_audit_log);
   1794      0    stevel 		return (WALK_ERR);
   1795      0    stevel 	}
   1796      0    stevel 
   1797      0    stevel 	dil = mdb_zalloc(sizeof (devinfo_audit_log_walk_data_t), UM_SLEEP);
   1798      0    stevel 	wsp->walk_data = dil;
   1799      0    stevel 
   1800      0    stevel 	dil->dil_start = dil->dil_index = header.dh_curr;
   1801      0    stevel 	dil->dil_max = header.dh_max;
   1802      0    stevel 	if (dil->dil_start < 0)		/* no log entries */
   1803      0    stevel 		return (WALK_DONE);
   1804      0    stevel 
   1805      0    stevel 	dil->dil_base = devinfo_audit_log +
   1806      0    stevel 	    offsetof(devinfo_log_header_t, dh_entry);
   1807      0    stevel 	wsp->walk_addr = dil->dil_base +
   1808      0    stevel 	    dil->dil_index * sizeof (devinfo_audit_t);
   1809      0    stevel 
   1810      0    stevel 	return (WALK_NEXT);
   1811      0    stevel }
   1812      0    stevel 
   1813      0    stevel int
   1814      0    stevel devinfo_audit_log_walk_step(mdb_walk_state_t *wsp)
   1815      0    stevel {
   1816      0    stevel 	uintptr_t addr = wsp->walk_addr;
   1817      0    stevel 	devinfo_audit_log_walk_data_t *dil = wsp->walk_data;
   1818      0    stevel 	devinfo_audit_t *da = &dil->dil_buf;
   1819      0    stevel 	int status = WALK_NEXT;
   1820      0    stevel 
   1821      0    stevel 	/* read in current entry and invoke callback */
   1822      0    stevel 	if (addr == NULL)
   1823      0    stevel 		return (WALK_DONE);
   1824      0    stevel 
   1825      0    stevel 	if (mdb_vread(&dil->dil_buf, sizeof (devinfo_audit_t), addr) == -1) {
   1826      0    stevel 		mdb_warn("failed to read devinfo_audit at %p", addr);
   1827      0    stevel 		status = WALK_DONE;
   1828      0    stevel 	}
   1829      0    stevel 	status = wsp->walk_callback(wsp->walk_addr, da, wsp->walk_cbdata);
   1830      0    stevel 
   1831      0    stevel 	/* step to the previous log entry in time */
   1832      0    stevel 	if (--dil->dil_index < 0)
   1833      0    stevel 		dil->dil_index += dil->dil_max;
   1834      0    stevel 	if (dil->dil_index == dil->dil_start) {
   1835      0    stevel 		wsp->walk_addr = NULL;
   1836      0    stevel 		return (WALK_DONE);
   1837      0    stevel 	}
   1838      0    stevel 
   1839      0    stevel 	wsp->walk_addr = dil->dil_base +
   1840      0    stevel 	    dil->dil_index * sizeof (devinfo_audit_t);
   1841      0    stevel 	return (status);
   1842      0    stevel }
   1843      0    stevel 
   1844      0    stevel void
   1845      0    stevel devinfo_audit_log_walk_fini(mdb_walk_state_t *wsp)
   1846      0    stevel {
   1847      0    stevel 	mdb_free(wsp->walk_data, sizeof (devinfo_audit_log_walk_data_t));
   1848      0    stevel }
   1849      0    stevel 
   1850      0    stevel /*
   1851      0    stevel  * display devinfo_audit_t stack trace
   1852      0    stevel  */
   1853      0    stevel /*ARGSUSED*/
   1854      0    stevel int
   1855      0    stevel devinfo_audit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1856      0    stevel {
   1857      0    stevel 	uint_t verbose = FALSE;
   1858      0    stevel 	devinfo_audit_t da;
   1859      0    stevel 	int i, depth;
   1860      0    stevel 
   1861      0    stevel 	if ((flags & DCMD_ADDRSPEC) == 0)
   1862      0    stevel 		return (DCMD_USAGE);
   1863      0    stevel 
   1864      0    stevel 	if (mdb_getopts(argc, argv,
   1865      0    stevel 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
   1866      0    stevel 		return (DCMD_USAGE);
   1867      0    stevel 
   1868      0    stevel 	if (DCMD_HDRSPEC(flags)) {
   1869      0    stevel 		mdb_printf(" %-?s %16s %-?s %-?s %5s\n",
   1870      0    stevel 		    "AUDIT", "TIMESTAMP", "THREAD", "DEVINFO", "STATE");
   1871      0    stevel 	}
   1872      0    stevel 
   1873      0    stevel 	if (mdb_vread(&da, sizeof (da), addr) == -1) {
   1874      0    stevel 		mdb_warn("couldn't read devinfo_audit at %p", addr);
   1875      0    stevel 		return (DCMD_ERR);
   1876      0    stevel 	}
   1877      0    stevel 
   1878      0    stevel 	mdb_printf(" %0?p %16llx %0?p %0?p %s\n",
   1879      0    stevel 	    addr, da.da_timestamp, da.da_thread, da.da_devinfo,
   1880      0    stevel 	    di_state[MIN(da.da_node_state + 1, DI_STATE_MAX)]);
   1881      0    stevel 
   1882      0    stevel 	if (!verbose)
   1883      0    stevel 		return (DCMD_OK);
   1884      0    stevel 
   1885      0    stevel 	mdb_inc_indent(4);
   1886      0    stevel 
   1887      0    stevel 	/*
   1888      0    stevel 	 * Guard against bogus da_depth in case the devinfo_audit_t
   1889      0    stevel 	 * is corrupt or the address does not really refer to a
   1890      0    stevel 	 * devinfo_audit_t.
   1891      0    stevel 	 */
   1892      0    stevel 	depth = MIN(da.da_depth, DDI_STACK_DEPTH);
   1893      0    stevel 
   1894      0    stevel 	for (i = 0; i < depth; i++)
   1895      0    stevel 		mdb_printf("%a\n", da.da_stack[i]);
   1896      0    stevel 
   1897      0    stevel 	mdb_printf("\n");
   1898      0    stevel 	mdb_dec_indent(4);
   1899      0    stevel 
   1900      0    stevel 	return (DCMD_OK);
   1901      0    stevel }
   1902      0    stevel 
   1903      0    stevel int
   1904      0    stevel devinfo_audit_log(uintptr_t addr, uint_t flags, int argc,
   1905      0    stevel     const mdb_arg_t *argv)
   1906      0    stevel {
   1907      0    stevel 	if (flags & DCMD_ADDRSPEC)
   1908      0    stevel 		return (devinfo_audit(addr, flags, argc, argv));
   1909      0    stevel 
   1910      0    stevel 	(void) mdb_walk_dcmd("devinfo_audit_log", "devinfo_audit", argc, argv);
   1911      0    stevel 	return (DCMD_OK);
   1912      0    stevel }
   1913      0    stevel 
   1914      0    stevel typedef struct devinfo_audit_node_walk_data {
   1915      0    stevel 	devinfo_audit_t dih_buf;	/* buffer of last entry */
   1916      0    stevel 	uintptr_t dih_dip;		/* address of dev_info */
   1917      0    stevel 	int dih_on_devinfo;		/* devi_audit on dev_info struct */
   1918      0    stevel } devinfo_audit_node_walk_data_t;
   1919      0    stevel 
   1920      0    stevel int
   1921      0    stevel devinfo_audit_node_walk_init(mdb_walk_state_t *wsp)
   1922      0    stevel {
   1923      0    stevel 	devinfo_audit_node_walk_data_t *dih;
   1924      0    stevel 	devinfo_audit_t *da;
   1925      0    stevel 	struct dev_info devi;
   1926      0    stevel 	uintptr_t addr = wsp->walk_addr;
   1927      0    stevel 
   1928      0    stevel 	/* read in devinfo structure */
   1929      0    stevel 	if (mdb_vread(&devi, sizeof (struct dev_info), addr) == -1) {
   1930      0    stevel 		mdb_warn("couldn't read dev_info at %p", addr);
   1931      0    stevel 		return (WALK_ERR);
   1932      0    stevel 	}
   1933      0    stevel 
   1934      0    stevel 	dih = mdb_zalloc(sizeof (devinfo_audit_node_walk_data_t), UM_SLEEP);
   1935      0    stevel 	wsp->walk_data = dih;
   1936      0    stevel 	da = &dih->dih_buf;
   1937      0    stevel 
   1938      0    stevel 	/* read in devi_audit structure */
   1939      0    stevel 	if (mdb_vread(da, sizeof (devinfo_audit_t), (uintptr_t)devi.devi_audit)
   1940      0    stevel 	    == -1) {
   1941      0    stevel 		mdb_warn("couldn't read devi_audit at %p", devi.devi_audit);
   1942      0    stevel 		return (WALK_ERR);
   1943      0    stevel 	}
   1944      0    stevel 	dih->dih_dip = addr;
   1945      0    stevel 	dih->dih_on_devinfo = 1;
   1946      0    stevel 	wsp->walk_addr = (uintptr_t)devi.devi_audit;
   1947      0    stevel 
   1948      0    stevel 	return (WALK_NEXT);
   1949      0    stevel }
   1950      0    stevel 
   1951      0    stevel int
   1952      0    stevel devinfo_audit_node_walk_step(mdb_walk_state_t *wsp)
   1953      0    stevel {
   1954      0    stevel 	uintptr_t addr;
   1955      0    stevel 	devinfo_audit_node_walk_data_t *dih = wsp->walk_data;
   1956      0    stevel 	devinfo_audit_t *da = &dih->dih_buf;
   1957      0    stevel 
   1958      0    stevel 	if (wsp->walk_addr == NULL)
   1959      0    stevel 		return (WALK_DONE);
   1960      0    stevel 	(void) wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata);
   1961      0    stevel 
   1962      0    stevel skip:
   1963      0    stevel 	/* read in previous entry */
   1964      0    stevel 	if ((addr = (uintptr_t)da->da_lastlog) == 0)
   1965      0    stevel 		return (WALK_DONE);
   1966      0    stevel 
   1967      0    stevel 	if (mdb_vread(&dih->dih_buf, sizeof (devinfo_audit_t), addr) == -1) {
   1968      0    stevel 		mdb_warn("failed to read devinfo_audit at %p", addr);
   1969      0    stevel 		return (WALK_DONE);
   1970      0    stevel 	}
   1971      0    stevel 
   1972      0    stevel 	/* check if last log was over-written */
   1973      0    stevel 	if ((uintptr_t)da->da_devinfo != dih->dih_dip)
   1974      0    stevel 		return (WALK_DONE);
   1975      0    stevel 
   1976      0    stevel 	/*
   1977      0    stevel 	 * skip the first common log entry, which is a duplicate of
   1978      0    stevel 	 * the devi_audit buffer on the dev_info structure
   1979      0    stevel 	 */
   1980      0    stevel 	if (dih->dih_on_devinfo) {
   1981      0    stevel 		dih->dih_on_devinfo = 0;
   1982      0    stevel 		goto skip;
   1983      0    stevel 	}
   1984      0    stevel 	wsp->walk_addr = addr;
   1985      0    stevel 
   1986      0    stevel 	return (WALK_NEXT);
   1987      0    stevel }
   1988      0    stevel 
   1989      0    stevel void
   1990      0    stevel devinfo_audit_node_walk_fini(mdb_walk_state_t *wsp)
   1991      0    stevel {
   1992      0    stevel 	mdb_free(wsp->walk_data, sizeof (devinfo_audit_node_walk_data_t));
   1993      0    stevel }
   1994      0    stevel 
   1995      0    stevel int
   1996      0    stevel devinfo_audit_node(uintptr_t addr, uint_t flags, int argc,
   1997      0    stevel     const mdb_arg_t *argv)
   1998      0    stevel {
   1999      0    stevel 	if (!(flags & DCMD_ADDRSPEC))
   2000      0    stevel 		return (DCMD_USAGE);
   2001      0    stevel 
   2002      0    stevel 	(void) mdb_pwalk_dcmd("devinfo_audit_node", "devinfo_audit",
   2003      0    stevel 	    argc, argv, addr);
   2004      0    stevel 	return (DCMD_OK);
   2005      0    stevel }
   2006      0    stevel 
   2007      0    stevel /*
   2008      0    stevel  * mdb support for per-devinfo fault management data
   2009      0    stevel  */
   2010      0    stevel /*ARGSUSED*/
   2011      0    stevel int
   2012      0    stevel devinfo_fm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   2013      0    stevel {
   2014      0    stevel 	struct dev_info devi;
   2015      0    stevel 	struct i_ddi_fmhdl fhdl;
   2016      0    stevel 
   2017      0    stevel 	if ((flags & DCMD_ADDRSPEC) == 0)
   2018      0    stevel 		return (DCMD_USAGE);
   2019      0    stevel 
   2020      0    stevel 	if (DCMD_HDRSPEC(flags)) {
   2021   7931      Sean 		mdb_printf("%<u>%?s IPL CAPS DROP FMCFULL FMCMISS ACCERR "
   2022   7931      Sean 		    "DMAERR %?s %?s%</u>\n", "ADDR", "DMACACHE", "ACCCACHE");
   2023      0    stevel 	}
   2024      0    stevel 
   2025      0    stevel 	if (mdb_vread(&devi, sizeof (devi), addr) == -1) {
   2026      0    stevel 		mdb_warn("failed to read devinfo struct at %p", addr);
   2027      0    stevel 		return (DCMD_ERR);
   2028      0    stevel 	}
   2029      0    stevel 
   2030      0    stevel 	if (mdb_vread(&fhdl, sizeof (fhdl), (uintptr_t)devi.devi_fmhdl) == -1) {
   2031      0    stevel 		mdb_warn("failed to read devinfo fm struct at %p",
   2032      0    stevel 		    (uintptr_t)devi.devi_fmhdl);
   2033      0    stevel 		return (DCMD_ERR);
   2034      0    stevel 	}
   2035      0    stevel 
   2036   7931      Sean 	mdb_printf("%?p %3u %c%c%c%c %4llu %7llu %7llu %6llu %6llu %?p %?p\n",
   2037      0    stevel 	    (uintptr_t)devi.devi_fmhdl, fhdl.fh_ibc,
   2038      0    stevel 	    (DDI_FM_EREPORT_CAP(fhdl.fh_cap) ? 'E' : '-'),
   2039      0    stevel 	    (DDI_FM_ERRCB_CAP(fhdl.fh_cap) ? 'C' : '-'),
   2040      0    stevel 	    (DDI_FM_ACC_ERR_CAP(fhdl.fh_cap) ? 'A' : '-'),
   2041      0    stevel 	    (DDI_FM_DMA_ERR_CAP(fhdl.fh_cap) ? 'D' : '-'),
   2042      0    stevel 	    fhdl.fh_kstat.fek_erpt_dropped.value.ui64,
   2043      0    stevel 	    fhdl.fh_kstat.fek_fmc_full.value.ui64,
   2044   7931      Sean 	    fhdl.fh_kstat.fek_fmc_miss.value.ui64,
   2045      0    stevel 	    fhdl.fh_kstat.fek_acc_err.value.ui64,
   2046      0    stevel 	    fhdl.fh_kstat.fek_dma_err.value.ui64,
   2047      0    stevel 	    fhdl.fh_dma_cache, fhdl.fh_acc_cache);
   2048      0    stevel 
   2049      0    stevel 
   2050      0    stevel 	return (DCMD_OK);
   2051      0    stevel }
   2052      0    stevel 
   2053      0    stevel /*ARGSUSED*/
   2054      0    stevel int
   2055      0    stevel devinfo_fmce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   2056      0    stevel {
   2057      0    stevel 	struct i_ddi_fmc_entry fce;
   2058      0    stevel 
   2059      0    stevel 	if ((flags & DCMD_ADDRSPEC) == 0)
   2060      0    stevel 		return (DCMD_USAGE);
   2061      0    stevel 
   2062      0    stevel 	if (DCMD_HDRSPEC(flags)) {
   2063   7931      Sean 		mdb_printf("%<u>%?s %?s %?s%</u>\n", "ADDR",
   2064      0    stevel 		    "RESOURCE", "BUS_SPECIFIC");
   2065      0    stevel 	}
   2066      0    stevel 
   2067      0    stevel 	if (mdb_vread(&fce, sizeof (fce), addr) == -1) {
   2068      0    stevel 		mdb_warn("failed to read fm cache struct at %p", addr);
   2069      0    stevel 		return (DCMD_ERR);
   2070      0    stevel 	}
   2071      0    stevel 
   2072   7931      Sean 	mdb_printf("%?p %?p %?p\n",
   2073      0    stevel 	    (uintptr_t)addr, fce.fce_resource, fce.fce_bus_specific);
   2074      0    stevel 
   2075      0    stevel 
   2076      0    stevel 	return (DCMD_OK);
   2077      0    stevel }
   2078      0    stevel 
   2079      0    stevel int
   2080      0    stevel devinfo_fmc_walk_init(mdb_walk_state_t *wsp)
   2081      0    stevel {
   2082      0    stevel 	struct i_ddi_fmc fec;
   2083      0    stevel 
   2084      0    stevel 	if (wsp->walk_addr == NULL)
   2085      0    stevel 		return (WALK_ERR);
   2086      0    stevel 
   2087      0    stevel 	if (mdb_vread(&fec, sizeof (fec), wsp->walk_addr) == -1) {
   2088      0    stevel 		mdb_warn("failed to read fm cache at %p", wsp->walk_addr);
   2089      0    stevel 		return (WALK_ERR);
   2090      0    stevel 	}
   2091      0    stevel 
   2092   7931      Sean 	if (fec.fc_head == NULL)
   2093      0    stevel 		return (WALK_DONE);
   2094      0    stevel 
   2095   7931      Sean 	wsp->walk_addr = (uintptr_t)fec.fc_head;
   2096      0    stevel 	return (WALK_NEXT);
   2097      0    stevel }
   2098      0    stevel 
   2099      0    stevel int
   2100      0    stevel devinfo_fmc_walk_step(mdb_walk_state_t *wsp)
   2101      0    stevel {
   2102      0    stevel 	int status;
   2103      0    stevel 	struct i_ddi_fmc_entry fe;
   2104      0    stevel 
   2105      0    stevel 	if (mdb_vread(&fe, sizeof (fe), wsp->walk_addr) == -1) {
   2106      0    stevel 		mdb_warn("failed to read active fm cache entry at %p",
   2107      0    stevel 		    wsp->walk_addr);
   2108      0    stevel 		return (WALK_DONE);
   2109      0    stevel 	}
   2110      0    stevel 
   2111      0    stevel 	status = wsp->walk_callback(wsp->walk_addr, &fe, wsp->walk_cbdata);
   2112      0    stevel 
   2113      0    stevel 	if (fe.fce_next == NULL)
   2114      0    stevel 		return (WALK_DONE);
   2115      0    stevel 
   2116      0    stevel 	wsp->walk_addr = (uintptr_t)fe.fce_next;
   2117      0    stevel 	return (status);
   2118      0    stevel }
   2119      0    stevel 
   2120      0    stevel int
   2121      0    stevel minornode_walk_init(mdb_walk_state_t *wsp)
   2122      0    stevel {
   2123      0    stevel 	struct dev_info di;
   2124      0    stevel 	uintptr_t addr = wsp->walk_addr;
   2125      0    stevel 
   2126      0    stevel 	if (addr == NULL) {
   2127      0    stevel 		mdb_warn("a dev_info struct address must be provided\n");
   2128      0    stevel 		return (WALK_ERR);
   2129      0    stevel 	}
   2130      0    stevel 
   2131      0    stevel 	if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1) {
   2132      0    stevel 		mdb_warn("failed to read dev_info struct at %p", addr);
   2133      0    stevel 		return (WALK_ERR);
   2134      0    stevel 	}
   2135      0    stevel 
   2136      0    stevel 	wsp->walk_addr = (uintptr_t)di.devi_minor;
   2137      0    stevel 	return (WALK_NEXT);
   2138      0    stevel }
   2139      0    stevel 
   2140      0    stevel int
   2141      0    stevel minornode_walk_step(mdb_walk_state_t *wsp)
   2142      0    stevel {
   2143      0    stevel 	struct ddi_minor_data md;
   2144      0    stevel 	uintptr_t addr = wsp->walk_addr;
   2145      0    stevel 
   2146      0    stevel 	if (addr == NULL)
   2147      0    stevel 		return (WALK_DONE);
   2148      0    stevel 
   2149      0    stevel 	if (mdb_vread(&md, sizeof (md), addr) == -1) {
   2150      0    stevel 		mdb_warn("failed to read dev_info struct at %p", addr);
   2151      0    stevel 		return (WALK_DONE);
   2152      0    stevel 	}
   2153      0    stevel 
   2154      0    stevel 	wsp->walk_addr = (uintptr_t)md.next;
   2155      0    stevel 	return (wsp->walk_callback(addr, &md, wsp->walk_cbdata));
   2156      0    stevel }
   2157      0    stevel 
   2158      0    stevel static const char *const md_type[] = {
   2159      0    stevel 	"DDI_MINOR",
   2160      0    stevel 	"DDI_ALIAS",
   2161      0    stevel 	"DDI_DEFAULT",
   2162      0    stevel 	"DDI_I_PATH",
   2163      0    stevel 	"?"
   2164      0    stevel };
   2165      0    stevel 
   2166      0    stevel #define	MD_TYPE_MAX	((sizeof (md_type) / sizeof (char *)) - 1)
   2167      0    stevel 
   2168      0    stevel /*ARGSUSED*/
   2169      0    stevel static int
   2170      0    stevel print_minornode(uintptr_t addr, const void *arg, void *data)
   2171      0    stevel {
   2172      0    stevel 	char name[128];
   2173      0    stevel 	char nodetype[128];
   2174      0    stevel 	char *spectype;
   2175      0    stevel 	struct ddi_minor_data *mdp = (struct ddi_minor_data *)arg;
   2176      0    stevel 
   2177      0    stevel 	if (mdb_readstr(name, sizeof (name), (uintptr_t)mdp->ddm_name) == -1)
   2178      0    stevel 		*name = '\0';
   2179      0    stevel 
   2180      0    stevel 	if (mdb_readstr(nodetype, sizeof (nodetype),
   2181      0    stevel 	    (uintptr_t)mdp->ddm_node_type) == -1)
   2182      0    stevel 		*nodetype = '\0';
   2183      0    stevel 
   2184      0    stevel 	switch (mdp->ddm_spec_type) {
   2185      0    stevel 		case S_IFCHR:	spectype = "c";	break;
   2186      0    stevel 		case S_IFBLK:	spectype = "b";	break;
   2187      0    stevel 		default:	spectype = "?";	break;
   2188      0    stevel 	}
   2189      0    stevel 
   2190      0    stevel 	mdb_printf("%?p %16lx %-4s %-11s %-10s %s\n",
   2191      0    stevel 	    addr, mdp->ddm_dev, spectype, md_type[MIN(mdp->type, MD_TYPE_MAX)],
   2192      0    stevel 	    name, nodetype);
   2193      0    stevel 
   2194      0    stevel 	return (WALK_NEXT);
   2195      0    stevel }
   2196      0    stevel 
   2197      0    stevel /*ARGSUSED*/
   2198      0    stevel int
   2199      0    stevel minornodes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   2200      0    stevel {
   2201      0    stevel 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
   2202      0    stevel 		return (DCMD_USAGE);
   2203      0    stevel 
   2204      0    stevel 	if (DCMD_HDRSPEC(flags))
   2205      0    stevel 		mdb_printf("%<u>%?s %16s %-4s %-11s %-10s %-16s%</u>\n",
   2206      0    stevel 		    "ADDR", "DEV", "SPEC", "TYPE", "NAME", "NODETYPE");
   2207      0    stevel 
   2208      0    stevel 	if (mdb_pwalk("minornode", print_minornode, NULL, addr) == -1) {
   2209      0    stevel 		mdb_warn("can't walk minornode");
   2210      0    stevel 		return (DCMD_ERR);
   2211      0    stevel 	}
   2212      0    stevel 
   2213      0    stevel 	return (DCMD_OK);
   2214      0    stevel }
   2215