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