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