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