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