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