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