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