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