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