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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 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 45 #define DEVINFO_TREE_INDENT 4 /* Indent for devs one down in tree */ 46 #define DEVINFO_PROP_INDENT 4 /* Indent for properties */ 47 #define DEVINFO_PROPLIST_INDENT 8 /* Indent for properties lists */ 48 49 50 /* 51 * Options for prtconf/devinfo dcmd. 52 */ 53 #define DEVINFO_VERBOSE 0x1 54 #define DEVINFO_PARENT 0x2 55 #define DEVINFO_CHILD 0x4 56 #define DEVINFO_ALLBOLD 0x8 57 #define DEVINFO_SUMMARY 0x10 58 59 /* 60 * devinfo node state map. Used by devinfo() and devinfo_audit(). 61 * Long words are deliberately truncated so that output 62 * fits in 80 column with 64-bit addresses. 63 */ 64 static const char *const di_state[] = { 65 "DS_INVAL", 66 "DS_PROTO", 67 "DS_LINKED", 68 "DS_BOUND", 69 "DS_INITIA", 70 "DS_PROBED", 71 "DS_ATTACH", 72 "DS_READY", 73 "?" 74 }; 75 76 #define DI_STATE_MAX ((sizeof (di_state) / sizeof (char *)) - 1) 77 78 void 79 prtconf_help(void) 80 { 81 mdb_printf("Prints the devinfo tree from a given node.\n" 82 "Without the address of a \"struct devinfo\" given, " 83 "prints from the root;\n" 84 "with an address, prints the parents of, " 85 "and all children of, that address.\n\n" 86 "Switches:\n" 87 " -v be verbose - print device property lists\n" 88 " -p only print the ancestors of the given node\n" 89 " -c only print the children of the given node\n"); 90 } 91 92 void 93 devinfo_help(void) 94 { 95 mdb_printf("Switches:\n" 96 " -q be quiet - don't print device property lists\n" 97 " -s print summary of dev_info structures\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 (NULL); 150 } 151 152 if (wsp->walk_addr == NULL) 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 (NULL); 245 } 246 247 if (wsp->walk_addr == NULL) 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 == NULL) 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 != NULL) { 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 == NULL) { 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 == NULL) 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 == NULL) 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 char *type_str = NULL; 595 596 switch (type) { 597 case DDI_PROP_TYPE_ANY: 598 type_str = "any"; 599 break; 600 case DDI_PROP_TYPE_COMPOSITE: 601 type_str = "composite"; 602 break; 603 case DDI_PROP_TYPE_INT64: 604 type_str = "int64"; 605 break; 606 case DDI_PROP_TYPE_INT: 607 type_str = "int"; 608 break; 609 case DDI_PROP_TYPE_BYTE: 610 type_str = "byte"; 611 break; 612 case DDI_PROP_TYPE_STRING: 613 type_str = "string"; 614 break; 615 } 616 617 if (type_str != NULL) 618 mdb_printf("type=%s", type_str); 619 else 620 mdb_printf("type=0x%x", type); 621 } 622 623 static void 624 devinfo_print_props_value(int elem_size, int nelem, 625 unsigned char *prop_value, int prop_value_len) 626 { 627 int i; 628 629 mdb_printf("value="); 630 631 if (elem_size == 0) { 632 /* if elem_size == 0, then we are printing out string(s) */ 633 char *p = (char *)prop_value; 634 635 for (i = 0; i < nelem - 1; i++) { 636 mdb_printf("'%s' + ", p); 637 p += strlen(p) + 1; 638 } 639 mdb_printf("'%s'", p); 640 } else { 641 /* 642 * if elem_size != 0 then we are printing out an array 643 * where each element is of elem_size 644 */ 645 mdb_nhconvert(prop_value, prop_value, elem_size); 646 mdb_printf("%02x", *prop_value); 647 for (i = 1; i < prop_value_len; i++) { 648 if ((i % elem_size) == 0) { 649 mdb_nhconvert(&prop_value[i], 650 &prop_value[i], elem_size); 651 mdb_printf("."); 652 } 653 654 mdb_printf("%02x", prop_value[i]); 655 } 656 } 657 } 658 659 /* 660 * devinfo_print_props_guess() 661 * Guesses how to interpret the value of the property 662 * 663 * Params: 664 * type - Should be the type value of the property 665 * prop_val - Pointer to the property value data buffer 666 * prop_len - Length of the property value data buffer 667 * 668 * Return values: 669 * nelem - The number of elements stored in the property value 670 * data buffer pointed to by prop_val. 671 * elem_size - The size (in bytes) of the elements stored in the property 672 * value data buffer pointed to by prop_val. 673 * Upon return if elem_size == 0 and nelem != 0 then 674 * the property value data buffer contains strings 675 * len_err - There was an error with the length of the data buffer. 676 * Its size is not a multiple of the array value type. 677 * It will be interpreted as an array of bytes. 678 */ 679 static void 680 devinfo_print_props_guess(int type, unsigned char *prop_val, int prop_len, 681 int *elem_size, int *nelem, int *len_err) 682 { 683 *len_err = 0; 684 if (prop_len == NULL) { 685 *elem_size = 0; 686 *nelem = 0; 687 return; 688 } 689 690 /* by default, assume an array of bytes */ 691 *elem_size = 1; 692 *nelem = prop_len; 693 694 switch (type) { 695 case DDI_PROP_TYPE_BYTE: 696 /* default case, that was easy */ 697 break; 698 case DDI_PROP_TYPE_INT64: 699 if ((prop_len % sizeof (int64_t)) == 0) { 700 *elem_size = sizeof (int64_t); 701 *nelem = prop_len / *elem_size; 702 } else { 703 /* array is not a multiple of type size, error */ 704 *len_err = 1; 705 } 706 break; 707 case DDI_PROP_TYPE_INT: 708 if ((prop_len % sizeof (int)) == 0) { 709 *elem_size = sizeof (int); 710 *nelem = prop_len / *elem_size; 711 } else { 712 /* array is not a multiple of type size, error */ 713 *len_err = 1; 714 } 715 break; 716 case DDI_PROP_TYPE_STRING: 717 case DDI_PROP_TYPE_COMPOSITE: 718 case DDI_PROP_TYPE_ANY: 719 default: 720 /* 721 * if we made it here the type is either unknown 722 * or a string. Try to interpret is as a string 723 * and if that fails assume an array of bytes. 724 */ 725 if (prop_val[prop_len - 1] == '\0') { 726 unsigned char *s = prop_val; 727 int i; 728 729 /* assume an array of strings */ 730 *elem_size = 0; 731 *nelem = 0; 732 733 for (i = 0; i < prop_len; i++) { 734 if (prop_val[i] != '\0') 735 continue; 736 737 /* 738 * If the property is typed as a string 739 * property, then interpret empty strings 740 * as strings. Otherwise default to an 741 * array of bytes. If there are unprintable 742 * characters, always default to an array of 743 * bytes. 744 */ 745 if ((*s == '\0' && type != 746 DDI_PROP_TYPE_STRING) || 747 !is_printable_string(s)) { 748 *elem_size = 1; 749 *nelem = prop_len; 750 break; 751 } 752 753 (*nelem)++; 754 s = &prop_val[i + 1]; 755 } 756 } 757 break; 758 } 759 } 760 761 static void 762 devinfo_print_props(char *name, ddi_prop_t *p) 763 { 764 if (p == NULL) 765 return; 766 767 if (name != NULL) 768 mdb_printf("%s ", name); 769 770 mdb_printf("properties at %p:\n", p); 771 mdb_inc_indent(DEVINFO_PROP_INDENT); 772 773 while (p != NULL) { 774 ddi_prop_t prop; 775 char prop_name[128]; 776 unsigned char *prop_value; 777 int type, elem_size, nelem, prop_len_error; 778 779 /* read in the property struct */ 780 if (mdb_vread(&prop, sizeof (prop), (uintptr_t)p) == -1) { 781 mdb_warn("could not read property at 0x%p", p); 782 break; 783 } 784 785 /* print the property name */ 786 if (mdb_readstr(prop_name, sizeof (prop_name), 787 (uintptr_t)prop.prop_name) == -1) { 788 mdb_warn("could not read property name at 0x%p", 789 prop.prop_name); 790 goto next; 791 } 792 mdb_printf("name='%s' ", prop_name); 793 794 /* get the property type and print it out */ 795 type = (prop.prop_flags & DDI_PROP_TYPE_MASK); 796 devinfo_print_props_type(type); 797 798 /* get the property value */ 799 if (prop.prop_len > 0) { 800 prop_value = mdb_alloc(prop.prop_len, UM_SLEEP|UM_GC); 801 if (mdb_vread(prop_value, prop.prop_len, 802 (uintptr_t)prop.prop_val) == -1) { 803 mdb_warn("could not read property value at " 804 "0x%p", prop.prop_val); 805 goto next; 806 } 807 } else { 808 prop_value = NULL; 809 } 810 811 /* take a guess at interpreting the property value */ 812 devinfo_print_props_guess(type, prop_value, prop.prop_len, 813 &elem_size, &nelem, &prop_len_error); 814 815 /* print out the number ot items */ 816 mdb_printf(" items=%d", nelem); 817 818 /* print out any associated device information */ 819 if (prop.prop_dev != DDI_DEV_T_NONE) { 820 mdb_printf(" dev="); 821 if (prop.prop_dev == DDI_DEV_T_ANY) 822 mdb_printf("any"); 823 else if (prop.prop_dev == DDI_MAJOR_T_UNKNOWN) 824 mdb_printf("unknown"); 825 else 826 mdb_printf("(%u,%u)", 827 getmajor(prop.prop_dev), 828 getminor(prop.prop_dev)); 829 } 830 831 /* print out the property value */ 832 if (prop_value != NULL) { 833 mdb_printf("\n"); 834 mdb_inc_indent(DEVINFO_PROP_INDENT); 835 if (prop_len_error) 836 mdb_printf("NOTE: prop length is not a " 837 "multiple of element size\n"); 838 devinfo_print_props_value(elem_size, nelem, 839 prop_value, prop.prop_len); 840 mdb_dec_indent(DEVINFO_PROP_INDENT); 841 } 842 843 next: 844 mdb_printf("\n"); 845 p = prop.prop_next; 846 } 847 848 mdb_dec_indent(DEVINFO_PROP_INDENT); 849 } 850 851 static void 852 devinfo_pathinfo_state(mdi_pathinfo_state_t state) { 853 char *type_str = NULL; 854 855 switch (state) { 856 case MDI_PATHINFO_STATE_INIT: 857 type_str = "init"; 858 break; 859 case MDI_PATHINFO_STATE_ONLINE: 860 type_str = "online"; 861 break; 862 case MDI_PATHINFO_STATE_STANDBY: 863 type_str = "standby"; 864 break; 865 case MDI_PATHINFO_STATE_FAULT: 866 type_str = "fault"; 867 break; 868 case MDI_PATHINFO_STATE_OFFLINE: 869 type_str = "offline"; 870 break; 871 } 872 if (type_str != NULL) 873 mdb_printf("state=%s\n", type_str); 874 else 875 mdb_printf("state=0x%x\n", state); 876 } 877 878 static void 879 devinfo_print_pathing(int mdi_component, void *mdi_client) { 880 mdi_client_t mdi_c; 881 struct mdi_pathinfo *pip; 882 883 /* we only print out multipathing info for client nodes */ 884 if ((mdi_component & MDI_COMPONENT_CLIENT) == 0) 885 return; 886 887 mdb_printf("Client multipath info at: 0x%p\n", mdi_client); 888 mdb_inc_indent(DEVINFO_PROP_INDENT); 889 890 /* read in the client multipathing info */ 891 if (mdb_readstr((void*) &mdi_c, sizeof (mdi_c), 892 (uintptr_t)mdi_client) == -1) { 893 mdb_warn("failed to read mdi_client at %p", 894 (uintptr_t)mdi_client); 895 goto exit; 896 } 897 898 /* 899 * walk through the clients list of pathinfo structures and print 900 * out the properties for each path 901 */ 902 pip = (struct mdi_pathinfo *)mdi_c.ct_path_head; 903 while (pip != NULL) { 904 char binding_name[128]; 905 struct mdi_pathinfo pi; 906 mdi_phci_t ph; 907 struct dev_info ph_di; 908 909 /* read in the pathinfo structure */ 910 if (mdb_vread((void*)&pi, sizeof (pi), 911 (uintptr_t)pip) == -1) { 912 mdb_warn("failed to read mdi_pathinfo at %p", 913 (uintptr_t)pip); 914 goto exit; 915 } 916 917 /* read in the pchi (path host adapter) info */ 918 if (mdb_vread((void*)&ph, sizeof (ph), 919 (uintptr_t)pi.pi_phci) == -1) { 920 mdb_warn("failed to read mdi_pchi at %p", 921 (uintptr_t)pi.pi_phci); 922 goto exit; 923 } 924 925 /* read in the dip of the phci so we can get it's name */ 926 if (mdb_vread((void*)&ph_di, sizeof (ph_di), 927 (uintptr_t)ph.ph_dip) == -1) { 928 mdb_warn("failed to read mdi_pchi at %p", 929 (uintptr_t)ph.ph_dip); 930 goto exit; 931 } 932 if (mdb_vread(binding_name, sizeof (binding_name), 933 (uintptr_t)ph_di.devi_binding_name) == -1) { 934 mdb_warn("failed to read binding_name at %p", 935 (uintptr_t)ph_di.devi_binding_name); 936 goto exit; 937 } 938 939 mdb_printf("%s#%d, ", binding_name, ph_di.devi_instance); 940 devinfo_pathinfo_state(pi.pi_state); 941 942 /* print out the pathing info */ 943 mdb_inc_indent(DEVINFO_PROP_INDENT); 944 if (mdb_pwalk_dcmd(NVPAIR_WALKER_FQNAME, NVPAIR_DCMD_FQNAME, 945 0, NULL, (uintptr_t)pi.pi_prop) != 0) { 946 mdb_dec_indent(DEVINFO_PROP_INDENT); 947 goto exit; 948 } 949 mdb_dec_indent(DEVINFO_PROP_INDENT); 950 pip = pi.pi_client_link; 951 } 952 953 exit: 954 mdb_dec_indent(DEVINFO_PROP_INDENT); 955 } 956 957 typedef struct devinfo_cb_data { 958 uintptr_t di_base; 959 uint_t di_flags; 960 } devinfo_cb_data_t; 961 962 static int 963 devinfo_print(uintptr_t addr, struct dev_info *dev, devinfo_cb_data_t *data) 964 { 965 /* 966 * We know the walker passes us extra data after the dev_info. 967 */ 968 char binding_name[128]; 969 char dname[MODMAXNAMELEN + 1]; 970 devinfo_node_t *din = (devinfo_node_t *)dev; 971 ddi_prop_t *global_props = NULL; 972 973 if (mdb_readstr(binding_name, sizeof (binding_name), 974 (uintptr_t)dev->devi_binding_name) == -1) { 975 mdb_warn("failed to read binding_name at %p", 976 (uintptr_t)dev->devi_binding_name); 977 return (WALK_ERR); 978 } 979 980 /* if there are any global properties, get a pointer to them */ 981 if (dev->devi_global_prop_list != NULL) { 982 ddi_prop_list_t plist; 983 if (mdb_vread((void*)&plist, sizeof (plist), 984 (uintptr_t)dev->devi_global_prop_list) == -1) { 985 mdb_warn("failed to read global prop_list at %p", 986 (uintptr_t)dev->devi_global_prop_list); 987 return (WALK_ERR); 988 } 989 global_props = plist.prop_list; 990 } 991 992 mdb_inc_indent(din->din_depth * DEVINFO_TREE_INDENT); 993 if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD)) 994 mdb_printf("%<b>"); 995 mdb_printf("%-0?p %s", addr, binding_name); 996 if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD)) 997 mdb_printf("%</b>"); 998 if (dev->devi_instance >= 0) 999 mdb_printf(", instance #%d", dev->devi_instance); 1000 1001 if (dev->devi_node_state < DS_ATTACHED) 1002 mdb_printf(" (driver not attached)"); 1003 else if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0) 1004 mdb_printf(" (could not determine driver name)"); 1005 else 1006 mdb_printf(" (driver name: %s)", dname); 1007 1008 mdb_printf("\n"); 1009 if (data->di_flags & DEVINFO_VERBOSE) { 1010 mdb_inc_indent(DEVINFO_PROPLIST_INDENT); 1011 devinfo_print_props("System", dev->devi_sys_prop_ptr); 1012 devinfo_print_props("Driver", dev->devi_drv_prop_ptr); 1013 devinfo_print_props("Hardware", dev->devi_hw_prop_ptr); 1014 devinfo_print_props("Global", global_props); 1015 1016 devinfo_print_pathing(dev->devi_mdi_component, 1017 dev->devi_mdi_client); 1018 1019 mdb_dec_indent(DEVINFO_PROPLIST_INDENT); 1020 } 1021 1022 mdb_dec_indent(din->din_depth * DEVINFO_TREE_INDENT); 1023 return (WALK_NEXT); 1024 } 1025 1026 /*ARGSUSED*/ 1027 int 1028 prtconf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1029 { 1030 devinfo_cb_data_t data; 1031 uintptr_t devinfo_root; /* Address of root of devinfo tree */ 1032 int status; 1033 1034 data.di_flags = DEVINFO_PARENT | DEVINFO_CHILD; 1035 1036 if (mdb_getopts(argc, argv, 1037 'v', MDB_OPT_SETBITS, DEVINFO_VERBOSE, &data.di_flags, 1038 'p', MDB_OPT_CLRBITS, DEVINFO_CHILD, &data.di_flags, 1039 'c', MDB_OPT_CLRBITS, DEVINFO_PARENT, &data.di_flags, NULL) != argc) 1040 return (DCMD_USAGE); 1041 1042 if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) { 1043 mdb_warn("failed to read 'top_devinfo'"); 1044 return (NULL); 1045 } 1046 1047 if ((flags & DCMD_ADDRSPEC) == 0) { 1048 addr = devinfo_root; 1049 if (data.di_flags & DEVINFO_VERBOSE) 1050 data.di_flags |= DEVINFO_ALLBOLD; 1051 } 1052 1053 data.di_base = addr; 1054 mdb_printf("%<u>%-?s %-50s%</u>\n", "DEVINFO", "NAME"); 1055 1056 if ((data.di_flags & (DEVINFO_PARENT | DEVINFO_CHILD)) == 1057 (DEVINFO_PARENT | DEVINFO_CHILD)) { 1058 status = mdb_pwalk("devinfo", 1059 (mdb_walk_cb_t)devinfo_print, &data, addr); 1060 } else if (data.di_flags & DEVINFO_PARENT) { 1061 status = mdb_pwalk("devinfo_parents", 1062 (mdb_walk_cb_t)devinfo_print, &data, addr); 1063 } else if (data.di_flags & DEVINFO_CHILD) { 1064 status = mdb_pwalk("devinfo_children", 1065 (mdb_walk_cb_t)devinfo_print, &data, addr); 1066 } else { 1067 devinfo_node_t din; 1068 if (mdb_vread(&din.din_dev, sizeof (din.din_dev), addr) == -1) { 1069 mdb_warn("failed to read device"); 1070 return (DCMD_ERR); 1071 } 1072 din.din_depth = 0; 1073 return (devinfo_print(addr, (struct dev_info *)&din, &data)); 1074 } 1075 1076 if (status == -1) { 1077 mdb_warn("couldn't walk devinfo tree"); 1078 return (DCMD_ERR); 1079 } 1080 1081 return (DCMD_OK); 1082 } 1083 1084 /*ARGSUSED*/ 1085 int 1086 devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1087 { 1088 char tmpstr[MODMAXNAMELEN]; 1089 char nodename[MODMAXNAMELEN]; 1090 char bindname[MAXPATHLEN]; 1091 int size, length; 1092 struct dev_info devi; 1093 devinfo_node_t din; 1094 devinfo_cb_data_t data; 1095 1096 static const mdb_bitmask_t devi_state_masks[] = { 1097 { "DEVICE_OFFLINE", DEVI_DEVICE_OFFLINE, DEVI_DEVICE_OFFLINE }, 1098 { "DEVICE_DOWN", DEVI_DEVICE_DOWN, DEVI_DEVICE_DOWN }, 1099 { "DEVICE_DEGRADED", DEVI_DEVICE_DEGRADED, DEVI_DEVICE_DEGRADED }, 1100 { "DEVICE_REMOVED", DEVI_DEVICE_REMOVED, DEVI_DEVICE_REMOVED }, 1101 { "BUS_QUIESCED", DEVI_BUS_QUIESCED, DEVI_BUS_QUIESCED }, 1102 { "BUS_DOWN", DEVI_BUS_DOWN, DEVI_BUS_DOWN }, 1103 { "NDI_CONFIG", DEVI_NDI_CONFIG, DEVI_NDI_CONFIG }, 1104 1105 { "S_ATTACHING", DEVI_S_ATTACHING, DEVI_S_ATTACHING }, 1106 { "S_DETACHING", DEVI_S_DETACHING, DEVI_S_DETACHING }, 1107 { "S_ONLINING", DEVI_S_ONLINING, DEVI_S_ONLINING }, 1108 { "S_OFFLINING", DEVI_S_OFFLINING, DEVI_S_OFFLINING }, 1109 { "S_INVOKING_DACF", DEVI_S_INVOKING_DACF, DEVI_S_INVOKING_DACF }, 1110 { "S_UNBOUND", DEVI_S_UNBOUND, DEVI_S_UNBOUND }, 1111 { "S_REPORT", DEVI_S_REPORT, DEVI_S_REPORT }, 1112 { "S_EVADD", DEVI_S_EVADD, DEVI_S_EVADD }, 1113 { "S_EVREMOVE", DEVI_S_EVREMOVE, DEVI_S_EVREMOVE }, 1114 { "S_NEED_RESET", DEVI_S_NEED_RESET, DEVI_S_NEED_RESET }, 1115 { NULL, 0, 0 } 1116 }; 1117 1118 static const mdb_bitmask_t devi_flags_masks[] = { 1119 { "BUSY", DEVI_BUSY, DEVI_BUSY }, 1120 { "MADE_CHILDREN", DEVI_MADE_CHILDREN, DEVI_MADE_CHILDREN }, 1121 { "ATTACHED_CHILDREN", 1122 DEVI_ATTACHED_CHILDREN, DEVI_ATTACHED_CHILDREN}, 1123 { "BRANCH_HELD", DEVI_BRANCH_HELD, DEVI_BRANCH_HELD }, 1124 { "NO_BIND", DEVI_NO_BIND, DEVI_NO_BIND }, 1125 { "DEVI_REGISTERED_DEVID", 1126 DEVI_REGISTERED_DEVID, DEVI_REGISTERED_DEVID }, 1127 { "PHCI_SIGNALS_VHCI", 1128 DEVI_PHCI_SIGNALS_VHCI, 1129 DEVI_PHCI_SIGNALS_VHCI }, 1130 { "REBIND", DEVI_REBIND, DEVI_REBIND }, 1131 { NULL, 0, 0 } 1132 }; 1133 1134 data.di_flags = DEVINFO_VERBOSE; 1135 data.di_base = addr; 1136 1137 if (mdb_getopts(argc, argv, 1138 'q', MDB_OPT_CLRBITS, DEVINFO_VERBOSE, &data.di_flags, 1139 's', MDB_OPT_SETBITS, DEVINFO_SUMMARY, &data.di_flags, NULL) 1140 != argc) 1141 return (DCMD_USAGE); 1142 1143 if ((flags & DCMD_ADDRSPEC) == 0) { 1144 mdb_warn( 1145 "devinfo doesn't give global information (try prtconf)\n"); 1146 return (DCMD_ERR); 1147 } 1148 1149 if (DCMD_HDRSPEC(flags) && data.di_flags & DEVINFO_SUMMARY) 1150 mdb_printf( 1151 "%-?s %5s %?s %-20s %-s\n" 1152 "%-?s %5s %?s %-20s %-s\n" 1153 "%<u>%-?s %5s %?s %-20s %-15s%</u>\n", 1154 "DEVINFO", "MAJ", "REFCNT", "NODENAME", "NODESTATE", 1155 "", "INST", "CIRCULAR", "BINDNAME", "STATE", 1156 "", "", "THREAD", "", "FLAGS"); 1157 1158 if (mdb_vread(&devi, sizeof (devi), addr) == -1) { 1159 mdb_warn("failed to read device"); 1160 return (DCMD_ERR); 1161 } 1162 1163 if (data.di_flags & DEVINFO_SUMMARY) { 1164 *nodename = '\0'; 1165 size = sizeof (nodename); 1166 1167 if ((length = mdb_readstr(tmpstr, size, 1168 (uintptr_t)devi.devi_node_name)) > 0) { 1169 strcat(nodename, tmpstr); 1170 size -= length; 1171 } 1172 1173 if (devi.devi_addr != NULL && mdb_readstr(tmpstr, size - 1, 1174 (uintptr_t)devi.devi_addr) > 0) { 1175 strcat(nodename, "@"); 1176 strcat(nodename, tmpstr); 1177 } 1178 1179 if (mdb_readstr(bindname, sizeof (bindname), 1180 (uintptr_t)devi.devi_binding_name) == -1) 1181 *bindname = '\0'; 1182 1183 mdb_printf("%0?p %5d %?d %-20s %s\n", 1184 addr, devi.devi_major, devi.devi_ref, nodename, 1185 di_state[MIN(devi.devi_node_state + 1, DI_STATE_MAX)]); 1186 mdb_printf("%?s %5d %?d %-20s <%b>\n", 1187 "", devi.devi_instance, devi.devi_circular, bindname, 1188 devi.devi_state, devi_state_masks); 1189 mdb_printf("%?s %5s %?p %-20s <%b>\n\n", 1190 "", "", devi.devi_busy_thread, "", 1191 devi.devi_flags, devi_flags_masks); 1192 1193 return (DCMD_OK); 1194 } else { 1195 din.din_dev = devi; 1196 din.din_depth = 0; 1197 return (devinfo_print(addr, (struct dev_info *)&din, &data)); 1198 } 1199 } 1200 1201 /*ARGSUSED*/ 1202 int 1203 m2d_walk_dinfo(uintptr_t addr, struct dev_info *di, char *mod_name) 1204 { 1205 char name[MODMAXNAMELEN]; 1206 1207 if (mdb_readstr(name, MODMAXNAMELEN, 1208 (uintptr_t)di->devi_binding_name) == -1) { 1209 mdb_warn("couldn't read devi_binding_name at %p", 1210 di->devi_binding_name); 1211 return (WALK_ERR); 1212 } 1213 1214 if (strcmp(name, mod_name) == 0) 1215 mdb_printf("%p\n", addr); 1216 1217 return (WALK_NEXT); 1218 } 1219 1220 /*ARGSUSED*/ 1221 int 1222 modctl2devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1223 { 1224 struct modctl modctl; 1225 char name[MODMAXNAMELEN]; 1226 1227 if (!(flags & DCMD_ADDRSPEC)) 1228 return (DCMD_USAGE); 1229 1230 if (mdb_vread(&modctl, sizeof (modctl), addr) == -1) { 1231 mdb_warn("couldn't read modctl at %p", addr); 1232 return (DCMD_ERR); 1233 } 1234 1235 if (mdb_readstr(name, MODMAXNAMELEN, 1236 (uintptr_t)modctl.mod_modname) == -1) { 1237 mdb_warn("couldn't read modname at %p", modctl.mod_modname); 1238 return (DCMD_ERR); 1239 } 1240 1241 if (mdb_walk("devinfo", (mdb_walk_cb_t)m2d_walk_dinfo, name) == -1) { 1242 mdb_warn("couldn't walk devinfo"); 1243 return (DCMD_ERR); 1244 } 1245 1246 return (DCMD_OK); 1247 } 1248 1249 static int 1250 major_to_addr(major_t major, uintptr_t *vaddr) 1251 { 1252 uint_t devcnt; 1253 uintptr_t devnamesp; 1254 1255 if (mdb_readvar(&devcnt, "devcnt") == -1) { 1256 mdb_warn("failed to read 'devcnt'"); 1257 return (-1); 1258 } 1259 1260 if (mdb_readvar(&devnamesp, "devnamesp") == -1) { 1261 mdb_warn("failed to read 'devnamesp'"); 1262 return (-1); 1263 } 1264 1265 if (major >= devcnt) { 1266 mdb_warn("%x is out of range [0x0-0x%x]\n", major, devcnt - 1); 1267 return (-1); 1268 } 1269 1270 *vaddr = devnamesp + (major * sizeof (struct devnames)); 1271 return (0); 1272 } 1273 1274 /*ARGSUSED*/ 1275 int 1276 devnames(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1277 { 1278 static const mdb_bitmask_t dn_flag_bits[] = { 1279 { "DN_CONF_PARSED", DN_CONF_PARSED, DN_CONF_PARSED }, 1280 { "DN_DRIVER_BUSY", DN_DRIVER_BUSY, DN_DRIVER_BUSY }, 1281 { "DN_DRIVER_HELD", DN_DRIVER_HELD, DN_DRIVER_HELD }, 1282 { "DN_TAKEN_GETUDEV", DN_TAKEN_GETUDEV, DN_TAKEN_GETUDEV }, 1283 { "DN_DRIVER_REMOVED", DN_DRIVER_REMOVED, DN_DRIVER_REMOVED}, 1284 { "DN_FORCE_ATTACH", DN_FORCE_ATTACH, DN_FORCE_ATTACH}, 1285 { "DN_LEAF_DRIVER", DN_LEAF_DRIVER, DN_LEAF_DRIVER}, 1286 { "DN_NETWORK_DRIVER", DN_NETWORK_DRIVER, DN_NETWORK_DRIVER}, 1287 { "DN_NO_AUTODETACH", DN_NO_AUTODETACH, DN_NO_AUTODETACH }, 1288 { "DN_GLDV3_DRIVER", DN_GLDV3_DRIVER, DN_GLDV3_DRIVER}, 1289 { "DN_PHCI_DRIVER", DN_PHCI_DRIVER, DN_PHCI_DRIVER}, 1290 { "DN_OPEN_RETURNS_EINTR", \ 1291 DN_OPEN_RETURNS_EINTR, DN_OPEN_RETURNS_EINTR}, 1292 { "DN_SCSI_SIZE_CLEAN", DN_SCSI_SIZE_CLEAN, DN_SCSI_SIZE_CLEAN}, 1293 { "DN_NETWORK_PHYSDRIVER", \ 1294 DN_NETWORK_PHYSDRIVER, DN_NETWORK_PHYSDRIVER}, 1295 { NULL, 0, 0 } 1296 }; 1297 1298 const mdb_arg_t *argp = NULL; 1299 uint_t opt_v = FALSE, opt_m = FALSE; 1300 major_t major; 1301 size_t i; 1302 1303 char name[MODMAXNAMELEN + 1]; 1304 struct devnames dn; 1305 1306 if ((i = mdb_getopts(argc, argv, 1307 'm', MDB_OPT_SETBITS, TRUE, &opt_m, 1308 'v', MDB_OPT_SETBITS, TRUE, &opt_v, 1309 NULL)) != argc) { 1310 if (argc - i > 1) 1311 return (DCMD_USAGE); 1312 argp = &argv[i]; 1313 } 1314 1315 if (opt_m) { 1316 if (!(flags & DCMD_ADDRSPEC)) 1317 return (DCMD_USAGE); 1318 1319 if (major_to_addr(addr, &addr) == -1) 1320 return (DCMD_ERR); 1321 1322 } else if (!(flags & DCMD_ADDRSPEC)) { 1323 if (argp == NULL) { 1324 if (mdb_walk_dcmd("devnames", "devnames", argc, argv)) { 1325 mdb_warn("failed to walk devnames"); 1326 return (DCMD_ERR); 1327 } 1328 return (DCMD_OK); 1329 } 1330 1331 if (argp->a_type == MDB_TYPE_IMMEDIATE) 1332 major = (major_t)argp->a_un.a_val; 1333 else 1334 major = (major_t)mdb_strtoull(argp->a_un.a_str); 1335 1336 if (major_to_addr(major, &addr) == -1) 1337 return (DCMD_ERR); 1338 } 1339 1340 if (mdb_vread(&dn, sizeof (struct devnames), addr) == -1) { 1341 mdb_warn("failed to read devnames struct at %p", addr); 1342 return (DCMD_ERR); 1343 } 1344 1345 if (DCMD_HDRSPEC(flags)) { 1346 if (opt_v) 1347 mdb_printf("%<u>%-16s%</u>\n", "NAME"); 1348 else 1349 mdb_printf("%<u>%-16s %-?s%</u>\n", "NAME", "DN_HEAD"); 1350 } 1351 1352 if ((flags & DCMD_LOOP) && (dn.dn_name == NULL)) 1353 return (DCMD_OK); /* Skip empty slots if we're printing table */ 1354 1355 if (mdb_readstr(name, sizeof (name), (uintptr_t)dn.dn_name) == -1) 1356 (void) mdb_snprintf(name, sizeof (name), "0x%p", dn.dn_name); 1357 1358 if (opt_v) { 1359 ddi_prop_list_t prop_list; 1360 mdb_printf("%<b>%-16s%</b>\n", name); 1361 mdb_inc_indent(2); 1362 1363 mdb_printf(" flags %b\n", dn.dn_flags, dn_flag_bits); 1364 mdb_printf(" pl %p\n", (void *)dn.dn_pl); 1365 mdb_printf(" head %p\n", dn.dn_head); 1366 mdb_printf(" instance %d\n", dn.dn_instance); 1367 mdb_printf(" inlist %p\n", dn.dn_inlist); 1368 mdb_printf("global_prop_ptr %p\n", dn.dn_global_prop_ptr); 1369 if (mdb_vread(&prop_list, sizeof (ddi_prop_list_t), 1370 (uintptr_t)dn.dn_global_prop_ptr) != -1) { 1371 devinfo_print_props(NULL, prop_list.prop_list); 1372 } 1373 1374 mdb_dec_indent(2); 1375 } else 1376 mdb_printf("%-16s %-?p\n", name, dn.dn_head); 1377 1378 return (DCMD_OK); 1379 } 1380 1381 /*ARGSUSED*/ 1382 int 1383 name2major(uintptr_t vaddr, uint_t flags, int argc, const mdb_arg_t *argv) 1384 { 1385 major_t major; 1386 1387 if (flags & DCMD_ADDRSPEC) 1388 return (DCMD_USAGE); 1389 1390 if (argc != 1 || argv->a_type != MDB_TYPE_STRING) 1391 return (DCMD_USAGE); 1392 1393 if (mdb_name_to_major(argv->a_un.a_str, &major) != 0) { 1394 mdb_warn("failed to convert name to major number\n"); 1395 return (DCMD_ERR); 1396 } 1397 1398 mdb_printf("0x%x\n", major); 1399 return (DCMD_OK); 1400 } 1401 1402 /* 1403 * Get a numerical argument of a dcmd from addr if an address is specified 1404 * or from argv if no address is specified. Return the argument in ret. 1405 */ 1406 static int 1407 getarg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 1408 uintptr_t *ret) 1409 { 1410 if (argc == 0 && (flags & DCMD_ADDRSPEC)) { 1411 *ret = addr; 1412 1413 } else if (argc == 1 && !(flags & DCMD_ADDRSPEC)) { 1414 *ret = (argv[0].a_type == MDB_TYPE_IMMEDIATE) ? 1415 (uintptr_t)argv[0].a_un.a_val : 1416 (uintptr_t)mdb_strtoull(argv->a_un.a_str); 1417 1418 } else { 1419 return (-1); 1420 } 1421 1422 return (0); 1423 } 1424 1425 /*ARGSUSED*/ 1426 int 1427 major2name(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1428 { 1429 uintptr_t major; 1430 const char *name; 1431 1432 if (getarg(addr, flags, argc, argv, &major) < 0) 1433 return (DCMD_USAGE); 1434 1435 if ((name = mdb_major_to_name((major_t)major)) == NULL) { 1436 mdb_warn("failed to convert major number to name\n"); 1437 return (DCMD_ERR); 1438 } 1439 1440 mdb_printf("%s\n", name); 1441 return (DCMD_OK); 1442 } 1443 1444 /*ARGSUSED*/ 1445 int 1446 dev2major(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1447 { 1448 uintptr_t dev; 1449 1450 if (getarg(addr, flags, argc, argv, &dev) < 0) 1451 return (DCMD_USAGE); 1452 1453 if (flags & DCMD_PIPE_OUT) 1454 mdb_printf("%x\n", getmajor(dev)); 1455 else 1456 mdb_printf("0x%x (0t%d)\n", getmajor(dev), getmajor(dev)); 1457 1458 return (DCMD_OK); 1459 } 1460 1461 /*ARGSUSED*/ 1462 int 1463 dev2minor(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1464 { 1465 uintptr_t dev; 1466 1467 if (getarg(addr, flags, argc, argv, &dev) < 0) 1468 return (DCMD_USAGE); 1469 1470 if (flags & DCMD_PIPE_OUT) 1471 mdb_printf("%x\n", getminor(dev)); 1472 else 1473 mdb_printf("0x%x (0t%d)\n", getminor(dev), getminor(dev)); 1474 1475 return (DCMD_OK); 1476 } 1477 1478 /*ARGSUSED*/ 1479 int 1480 devt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1481 { 1482 uintptr_t dev; 1483 1484 if (getarg(addr, flags, argc, argv, &dev) < 0) 1485 return (DCMD_USAGE); 1486 1487 if (DCMD_HDRSPEC(flags)) { 1488 mdb_printf("%<u>%10s%</u> %<u>%10s%</u>\n", "MAJOR", 1489 "MINOR"); 1490 } 1491 1492 mdb_printf("%10d %10d\n", getmajor(dev), getminor(dev)); 1493 1494 return (DCMD_OK); 1495 } 1496 1497 /*ARGSUSED*/ 1498 int 1499 softstate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1500 { 1501 uintptr_t statep; 1502 int instance; 1503 1504 1505 if (argc != 1) { 1506 return (DCMD_USAGE); 1507 } 1508 1509 if (argv[0].a_type == MDB_TYPE_IMMEDIATE) 1510 instance = argv[0].a_un.a_val; 1511 else 1512 instance = mdb_strtoull(argv->a_un.a_str); 1513 1514 if (mdb_get_soft_state_byaddr(addr, instance, &statep, NULL, 0) == -1) { 1515 if (errno == ENOENT) { 1516 mdb_warn("instance %d unused\n", instance); 1517 } else { 1518 mdb_warn("couldn't determine softstate for " 1519 "instance %d", instance); 1520 } 1521 1522 return (DCMD_ERR); 1523 } 1524 1525 mdb_printf("%p\n", statep); 1526 return (DCMD_OK); 1527 } 1528 1529 /* 1530 * Walker for all possible pointers to a driver state struct in an 1531 * i_ddi_soft_state instance chain. Returns all non-NULL pointers. 1532 */ 1533 typedef struct soft_state_walk { 1534 struct i_ddi_soft_state ssw_ss; /* Local copy of i_ddi_soft_state */ 1535 void **ssw_pointers; /* to driver state structs */ 1536 uint_t ssw_index; /* array entry we're using */ 1537 } soft_state_walk_t; 1538 1539 int 1540 soft_state_walk_init(mdb_walk_state_t *wsp) 1541 { 1542 soft_state_walk_t *sst; 1543 1544 1545 if (wsp->walk_addr == NULL) 1546 return (WALK_DONE); 1547 1548 sst = mdb_zalloc(sizeof (soft_state_walk_t), UM_SLEEP|UM_GC); 1549 wsp->walk_data = sst; 1550 1551 1552 if (mdb_vread(&(sst->ssw_ss), sizeof (sst->ssw_ss), wsp->walk_addr) != 1553 sizeof (sst->ssw_ss)) { 1554 mdb_warn("failed to read i_ddi_soft_state at %p", 1555 wsp->walk_addr); 1556 return (WALK_ERR); 1557 } 1558 1559 1560 /* Read array of pointers to state structs into local storage. */ 1561 sst->ssw_pointers = mdb_alloc((sst->ssw_ss.n_items * sizeof (void *)), 1562 UM_SLEEP|UM_GC); 1563 1564 if (mdb_vread(sst->ssw_pointers, (sst->ssw_ss.n_items * 1565 sizeof (void *)), (uintptr_t)sst->ssw_ss.array) != 1566 (sst->ssw_ss.n_items * sizeof (void *))) { 1567 mdb_warn("failed to read i_ddi_soft_state at %p", 1568 wsp->walk_addr); 1569 return (WALK_ERR); 1570 } 1571 1572 sst->ssw_index = 0; 1573 1574 return (WALK_NEXT); 1575 } 1576 1577 int 1578 soft_state_walk_step(mdb_walk_state_t *wsp) 1579 { 1580 soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data; 1581 int status = WALK_NEXT; 1582 1583 1584 /* 1585 * If the entry indexed has a valid pointer to a soft state struct, 1586 * invoke caller's callback func. 1587 */ 1588 if (sst->ssw_pointers[sst->ssw_index] != NULL) { 1589 status = wsp->walk_callback( 1590 (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL, 1591 wsp->walk_cbdata); 1592 } 1593 1594 sst->ssw_index += 1; 1595 1596 if (sst->ssw_index == sst->ssw_ss.n_items) 1597 return (WALK_DONE); 1598 1599 return (status); 1600 } 1601 1602 int 1603 soft_state_all_walk_step(mdb_walk_state_t *wsp) 1604 { 1605 soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data; 1606 int status = WALK_NEXT; 1607 1608 1609 status = wsp->walk_callback( 1610 (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL, 1611 wsp->walk_cbdata); 1612 1613 sst->ssw_index += 1; 1614 1615 if (sst->ssw_index == sst->ssw_ss.n_items) 1616 return (WALK_DONE); 1617 1618 return (status); 1619 } 1620 1621 /*ARGSUSED*/ 1622 int 1623 devbindings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1624 { 1625 const mdb_arg_t *arg; 1626 struct devnames dn; 1627 uintptr_t dn_addr; 1628 major_t major; 1629 1630 if (!(flags & DCMD_ADDRSPEC) && argc < 1) 1631 return (DCMD_USAGE); 1632 1633 if (flags & DCMD_ADDRSPEC) { 1634 /* 1635 * If there's an address, then it's a major number 1636 */ 1637 major = addr; 1638 } else { 1639 /* 1640 * We interpret the last argument. Any other arguments are 1641 * forwarded to "devinfo" 1642 */ 1643 arg = &argv[argc - 1]; 1644 argc--; 1645 1646 if (arg->a_type == MDB_TYPE_IMMEDIATE) { 1647 major = (uintptr_t)arg->a_un.a_val; 1648 1649 } else if (arg->a_un.a_str[0] == '-') { 1650 /* the argument shouldn't be an option */ 1651 return (DCMD_USAGE); 1652 1653 } else if (isdigit(arg->a_un.a_str[0])) { 1654 major = (uintptr_t)mdb_strtoull(arg->a_un.a_str); 1655 1656 } else { 1657 if (mdb_name_to_major(arg->a_un.a_str, &major) != 0) { 1658 mdb_warn("failed to get major number for %s\n", 1659 arg->a_un.a_str); 1660 return (DCMD_ERR); 1661 } 1662 } 1663 } 1664 1665 if (major_to_addr(major, &dn_addr) != 0) 1666 return (DCMD_ERR); 1667 1668 if (mdb_vread(&dn, sizeof (struct devnames), dn_addr) == -1) { 1669 mdb_warn("couldn't read devnames array at %p", dn_addr); 1670 return (DCMD_ERR); 1671 } 1672 1673 if (mdb_pwalk_dcmd("devi_next", "devinfo", argc, argv, 1674 (uintptr_t)dn.dn_head) != 0) { 1675 mdb_warn("couldn't walk the devinfo chain at %p", dn.dn_head); 1676 return (DCMD_ERR); 1677 } 1678 1679 return (DCMD_OK); 1680 } 1681 1682 /* 1683 * walk binding hashtable (as of of driver names (e.g., mb_hashtab)) 1684 */ 1685 int 1686 binding_hash_walk_init(mdb_walk_state_t *wsp) 1687 { 1688 if (wsp->walk_addr == NULL) 1689 return (WALK_ERR); 1690 1691 wsp->walk_data = mdb_alloc(sizeof (void *) * MOD_BIND_HASHSIZE, 1692 UM_SLEEP|UM_GC); 1693 if (mdb_vread(wsp->walk_data, sizeof (void *) * MOD_BIND_HASHSIZE, 1694 wsp->walk_addr) == -1) { 1695 mdb_warn("failed to read mb_hashtab"); 1696 return (WALK_ERR); 1697 } 1698 1699 wsp->walk_arg = 0; /* index into mb_hashtab array to start */ 1700 1701 return (WALK_NEXT); 1702 } 1703 1704 int 1705 binding_hash_walk_step(mdb_walk_state_t *wsp) 1706 { 1707 int status; 1708 uintptr_t bind_p; 1709 struct bind bind; 1710 1711 1712 /* 1713 * Walk the singly-linked list of struct bind 1714 */ 1715 bind_p = ((uintptr_t *)wsp->walk_data)[(ulong_t)wsp->walk_arg]; 1716 while (bind_p != NULL) { 1717 1718 if (mdb_vread(&bind, sizeof (bind), bind_p) == -1) { 1719 mdb_warn("failed to read bind struct at %p", 1720 wsp->walk_addr); 1721 return (WALK_ERR); 1722 } 1723 1724 if ((status = wsp->walk_callback(bind_p, &bind, 1725 wsp->walk_cbdata)) != WALK_NEXT) { 1726 return (status); 1727 } 1728 1729 bind_p = (uintptr_t)bind.b_next; 1730 } 1731 1732 wsp->walk_arg = (void *)((char *)wsp->walk_arg + 1); 1733 1734 if (wsp->walk_arg == (void *)(MOD_BIND_HASHSIZE - 1)) 1735 return (WALK_DONE); 1736 1737 return (WALK_NEXT); 1738 } 1739 1740 /*ARGSUSED*/ 1741 int 1742 binding_hash_entry(uintptr_t addr, uint_t flags, int argc, 1743 const mdb_arg_t *argv) 1744 { 1745 struct bind bind; 1746 /* Arbitrary lengths based on output format below */ 1747 char name[MAXPATHLEN] = "???"; 1748 char bind_name[MAXPATHLEN] = "<null>"; 1749 1750 if ((flags & DCMD_ADDRSPEC) == NULL) 1751 return (DCMD_USAGE); 1752 1753 /* Allow null addresses to be passed (as from a walker) */ 1754 if (addr == NULL) 1755 return (DCMD_OK); 1756 1757 if (mdb_vread(&bind, sizeof (bind), addr) == -1) { 1758 mdb_warn("failed to read struct bind at %p", addr); 1759 return (DCMD_ERR); 1760 } 1761 1762 if (DCMD_HDRSPEC(flags)) { 1763 mdb_printf("%<u>%?s% %-5s %s%</u>\n", 1764 "NEXT", "MAJOR", "NAME(S)"); 1765 } 1766 1767 if (mdb_readstr(name, sizeof (name), (uintptr_t)bind.b_name) == -1) 1768 mdb_warn("failed to read 'name'"); 1769 1770 /* There may be bind_name, so this may fail */ 1771 if (mdb_readstr(bind_name, sizeof (bind_name), 1772 (uintptr_t)bind.b_bind_name) == -1) { 1773 mdb_printf("%?p %5d %s\n", 1774 bind.b_next, bind.b_num, name); 1775 } else { 1776 mdb_printf("%?p %5d %s %s\n", 1777 bind.b_next, bind.b_num, name, bind_name); 1778 } 1779 1780 return (DCMD_OK); 1781 } 1782 1783 typedef struct devinfo_audit_log_walk_data { 1784 devinfo_audit_t dil_buf; /* buffer of last entry */ 1785 uintptr_t dil_base; /* starting address of log buffer */ 1786 int dil_max; /* maximum index */ 1787 int dil_start; /* starting index */ 1788 int dil_index; /* current walking index */ 1789 } devinfo_audit_log_walk_data_t; 1790 1791 int 1792 devinfo_audit_log_walk_init(mdb_walk_state_t *wsp) 1793 { 1794 devinfo_log_header_t header; 1795 devinfo_audit_log_walk_data_t *dil; 1796 uintptr_t devinfo_audit_log; 1797 1798 /* read in devinfo_log_header structure */ 1799 if (mdb_readvar(&devinfo_audit_log, "devinfo_audit_log") == -1) { 1800 mdb_warn("failed to read 'devinfo_audit_log'"); 1801 return (WALK_ERR); 1802 } 1803 1804 if (mdb_vread(&header, sizeof (devinfo_log_header_t), 1805 devinfo_audit_log) == -1) { 1806 mdb_warn("couldn't read devinfo_log_header at %p", 1807 devinfo_audit_log); 1808 return (WALK_ERR); 1809 } 1810 1811 dil = mdb_zalloc(sizeof (devinfo_audit_log_walk_data_t), UM_SLEEP); 1812 wsp->walk_data = dil; 1813 1814 dil->dil_start = dil->dil_index = header.dh_curr; 1815 dil->dil_max = header.dh_max; 1816 if (dil->dil_start < 0) /* no log entries */ 1817 return (WALK_DONE); 1818 1819 dil->dil_base = devinfo_audit_log + 1820 offsetof(devinfo_log_header_t, dh_entry); 1821 wsp->walk_addr = dil->dil_base + 1822 dil->dil_index * sizeof (devinfo_audit_t); 1823 1824 return (WALK_NEXT); 1825 } 1826 1827 int 1828 devinfo_audit_log_walk_step(mdb_walk_state_t *wsp) 1829 { 1830 uintptr_t addr = wsp->walk_addr; 1831 devinfo_audit_log_walk_data_t *dil = wsp->walk_data; 1832 devinfo_audit_t *da = &dil->dil_buf; 1833 int status = WALK_NEXT; 1834 1835 /* read in current entry and invoke callback */ 1836 if (addr == NULL) 1837 return (WALK_DONE); 1838 1839 if (mdb_vread(&dil->dil_buf, sizeof (devinfo_audit_t), addr) == -1) { 1840 mdb_warn("failed to read devinfo_audit at %p", addr); 1841 status = WALK_DONE; 1842 } 1843 status = wsp->walk_callback(wsp->walk_addr, da, wsp->walk_cbdata); 1844 1845 /* step to the previous log entry in time */ 1846 if (--dil->dil_index < 0) 1847 dil->dil_index += dil->dil_max; 1848 if (dil->dil_index == dil->dil_start) { 1849 wsp->walk_addr = NULL; 1850 return (WALK_DONE); 1851 } 1852 1853 wsp->walk_addr = dil->dil_base + 1854 dil->dil_index * sizeof (devinfo_audit_t); 1855 return (status); 1856 } 1857 1858 void 1859 devinfo_audit_log_walk_fini(mdb_walk_state_t *wsp) 1860 { 1861 mdb_free(wsp->walk_data, sizeof (devinfo_audit_log_walk_data_t)); 1862 } 1863 1864 /* 1865 * display devinfo_audit_t stack trace 1866 */ 1867 /*ARGSUSED*/ 1868 int 1869 devinfo_audit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1870 { 1871 uint_t verbose = FALSE; 1872 devinfo_audit_t da; 1873 int i, depth; 1874 1875 if ((flags & DCMD_ADDRSPEC) == 0) 1876 return (DCMD_USAGE); 1877 1878 if (mdb_getopts(argc, argv, 1879 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) 1880 return (DCMD_USAGE); 1881 1882 if (DCMD_HDRSPEC(flags)) { 1883 mdb_printf(" %-?s %16s %-?s %-?s %5s\n", 1884 "AUDIT", "TIMESTAMP", "THREAD", "DEVINFO", "STATE"); 1885 } 1886 1887 if (mdb_vread(&da, sizeof (da), addr) == -1) { 1888 mdb_warn("couldn't read devinfo_audit at %p", addr); 1889 return (DCMD_ERR); 1890 } 1891 1892 mdb_printf(" %0?p %16llx %0?p %0?p %s\n", 1893 addr, da.da_timestamp, da.da_thread, da.da_devinfo, 1894 di_state[MIN(da.da_node_state + 1, DI_STATE_MAX)]); 1895 1896 if (!verbose) 1897 return (DCMD_OK); 1898 1899 mdb_inc_indent(4); 1900 1901 /* 1902 * Guard against bogus da_depth in case the devinfo_audit_t 1903 * is corrupt or the address does not really refer to a 1904 * devinfo_audit_t. 1905 */ 1906 depth = MIN(da.da_depth, DDI_STACK_DEPTH); 1907 1908 for (i = 0; i < depth; i++) 1909 mdb_printf("%a\n", da.da_stack[i]); 1910 1911 mdb_printf("\n"); 1912 mdb_dec_indent(4); 1913 1914 return (DCMD_OK); 1915 } 1916 1917 int 1918 devinfo_audit_log(uintptr_t addr, uint_t flags, int argc, 1919 const mdb_arg_t *argv) 1920 { 1921 if (flags & DCMD_ADDRSPEC) 1922 return (devinfo_audit(addr, flags, argc, argv)); 1923 1924 (void) mdb_walk_dcmd("devinfo_audit_log", "devinfo_audit", argc, argv); 1925 return (DCMD_OK); 1926 } 1927 1928 typedef struct devinfo_audit_node_walk_data { 1929 devinfo_audit_t dih_buf; /* buffer of last entry */ 1930 uintptr_t dih_dip; /* address of dev_info */ 1931 int dih_on_devinfo; /* devi_audit on dev_info struct */ 1932 } devinfo_audit_node_walk_data_t; 1933 1934 int 1935 devinfo_audit_node_walk_init(mdb_walk_state_t *wsp) 1936 { 1937 devinfo_audit_node_walk_data_t *dih; 1938 devinfo_audit_t *da; 1939 struct dev_info devi; 1940 uintptr_t addr = wsp->walk_addr; 1941 1942 /* read in devinfo structure */ 1943 if (mdb_vread(&devi, sizeof (struct dev_info), addr) == -1) { 1944 mdb_warn("couldn't read dev_info at %p", addr); 1945 return (WALK_ERR); 1946 } 1947 1948 dih = mdb_zalloc(sizeof (devinfo_audit_node_walk_data_t), UM_SLEEP); 1949 wsp->walk_data = dih; 1950 da = &dih->dih_buf; 1951 1952 /* read in devi_audit structure */ 1953 if (mdb_vread(da, sizeof (devinfo_audit_t), (uintptr_t)devi.devi_audit) 1954 == -1) { 1955 mdb_warn("couldn't read devi_audit at %p", devi.devi_audit); 1956 return (WALK_ERR); 1957 } 1958 dih->dih_dip = addr; 1959 dih->dih_on_devinfo = 1; 1960 wsp->walk_addr = (uintptr_t)devi.devi_audit; 1961 1962 return (WALK_NEXT); 1963 } 1964 1965 int 1966 devinfo_audit_node_walk_step(mdb_walk_state_t *wsp) 1967 { 1968 uintptr_t addr; 1969 devinfo_audit_node_walk_data_t *dih = wsp->walk_data; 1970 devinfo_audit_t *da = &dih->dih_buf; 1971 1972 if (wsp->walk_addr == NULL) 1973 return (WALK_DONE); 1974 (void) wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata); 1975 1976 skip: 1977 /* read in previous entry */ 1978 if ((addr = (uintptr_t)da->da_lastlog) == 0) 1979 return (WALK_DONE); 1980 1981 if (mdb_vread(&dih->dih_buf, sizeof (devinfo_audit_t), addr) == -1) { 1982 mdb_warn("failed to read devinfo_audit at %p", addr); 1983 return (WALK_DONE); 1984 } 1985 1986 /* check if last log was over-written */ 1987 if ((uintptr_t)da->da_devinfo != dih->dih_dip) 1988 return (WALK_DONE); 1989 1990 /* 1991 * skip the first common log entry, which is a duplicate of 1992 * the devi_audit buffer on the dev_info structure 1993 */ 1994 if (dih->dih_on_devinfo) { 1995 dih->dih_on_devinfo = 0; 1996 goto skip; 1997 } 1998 wsp->walk_addr = addr; 1999 2000 return (WALK_NEXT); 2001 } 2002 2003 void 2004 devinfo_audit_node_walk_fini(mdb_walk_state_t *wsp) 2005 { 2006 mdb_free(wsp->walk_data, sizeof (devinfo_audit_node_walk_data_t)); 2007 } 2008 2009 int 2010 devinfo_audit_node(uintptr_t addr, uint_t flags, int argc, 2011 const mdb_arg_t *argv) 2012 { 2013 if (!(flags & DCMD_ADDRSPEC)) 2014 return (DCMD_USAGE); 2015 2016 (void) mdb_pwalk_dcmd("devinfo_audit_node", "devinfo_audit", 2017 argc, argv, addr); 2018 return (DCMD_OK); 2019 } 2020 2021 /* 2022 * mdb support for per-devinfo fault management data 2023 */ 2024 /*ARGSUSED*/ 2025 int 2026 devinfo_fm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2027 { 2028 struct dev_info devi; 2029 struct i_ddi_fmhdl fhdl; 2030 2031 if ((flags & DCMD_ADDRSPEC) == 0) 2032 return (DCMD_USAGE); 2033 2034 if (DCMD_HDRSPEC(flags)) { 2035 mdb_printf("%<u>%?s IPL CAPS DROP FMCFULL FMCMISS ACCERR " 2036 "DMAERR %?s %?s%</u>\n", "ADDR", "DMACACHE", "ACCCACHE"); 2037 } 2038 2039 if (mdb_vread(&devi, sizeof (devi), addr) == -1) { 2040 mdb_warn("failed to read devinfo struct at %p", addr); 2041 return (DCMD_ERR); 2042 } 2043 2044 if (mdb_vread(&fhdl, sizeof (fhdl), (uintptr_t)devi.devi_fmhdl) == -1) { 2045 mdb_warn("failed to read devinfo fm struct at %p", 2046 (uintptr_t)devi.devi_fmhdl); 2047 return (DCMD_ERR); 2048 } 2049 2050 mdb_printf("%?p %3u %c%c%c%c %4llu %7llu %7llu %6llu %6llu %?p %?p\n", 2051 (uintptr_t)devi.devi_fmhdl, fhdl.fh_ibc, 2052 (DDI_FM_EREPORT_CAP(fhdl.fh_cap) ? 'E' : '-'), 2053 (DDI_FM_ERRCB_CAP(fhdl.fh_cap) ? 'C' : '-'), 2054 (DDI_FM_ACC_ERR_CAP(fhdl.fh_cap) ? 'A' : '-'), 2055 (DDI_FM_DMA_ERR_CAP(fhdl.fh_cap) ? 'D' : '-'), 2056 fhdl.fh_kstat.fek_erpt_dropped.value.ui64, 2057 fhdl.fh_kstat.fek_fmc_full.value.ui64, 2058 fhdl.fh_kstat.fek_fmc_miss.value.ui64, 2059 fhdl.fh_kstat.fek_acc_err.value.ui64, 2060 fhdl.fh_kstat.fek_dma_err.value.ui64, 2061 fhdl.fh_dma_cache, fhdl.fh_acc_cache); 2062 2063 2064 return (DCMD_OK); 2065 } 2066 2067 /*ARGSUSED*/ 2068 int 2069 devinfo_fmce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2070 { 2071 struct i_ddi_fmc_entry fce; 2072 2073 if ((flags & DCMD_ADDRSPEC) == 0) 2074 return (DCMD_USAGE); 2075 2076 if (DCMD_HDRSPEC(flags)) { 2077 mdb_printf("%<u>%?s %?s %?s%</u>\n", "ADDR", 2078 "RESOURCE", "BUS_SPECIFIC"); 2079 } 2080 2081 if (mdb_vread(&fce, sizeof (fce), addr) == -1) { 2082 mdb_warn("failed to read fm cache struct at %p", addr); 2083 return (DCMD_ERR); 2084 } 2085 2086 mdb_printf("%?p %?p %?p\n", 2087 (uintptr_t)addr, fce.fce_resource, fce.fce_bus_specific); 2088 2089 2090 return (DCMD_OK); 2091 } 2092 2093 int 2094 devinfo_fmc_walk_init(mdb_walk_state_t *wsp) 2095 { 2096 struct i_ddi_fmc fec; 2097 2098 if (wsp->walk_addr == NULL) 2099 return (WALK_ERR); 2100 2101 if (mdb_vread(&fec, sizeof (fec), wsp->walk_addr) == -1) { 2102 mdb_warn("failed to read fm cache at %p", wsp->walk_addr); 2103 return (WALK_ERR); 2104 } 2105 2106 if (fec.fc_head == NULL) 2107 return (WALK_DONE); 2108 2109 wsp->walk_addr = (uintptr_t)fec.fc_head; 2110 return (WALK_NEXT); 2111 } 2112 2113 int 2114 devinfo_fmc_walk_step(mdb_walk_state_t *wsp) 2115 { 2116 int status; 2117 struct i_ddi_fmc_entry fe; 2118 2119 if (mdb_vread(&fe, sizeof (fe), wsp->walk_addr) == -1) { 2120 mdb_warn("failed to read active fm cache entry at %p", 2121 wsp->walk_addr); 2122 return (WALK_DONE); 2123 } 2124 2125 status = wsp->walk_callback(wsp->walk_addr, &fe, wsp->walk_cbdata); 2126 2127 if (fe.fce_next == NULL) 2128 return (WALK_DONE); 2129 2130 wsp->walk_addr = (uintptr_t)fe.fce_next; 2131 return (status); 2132 } 2133 2134 int 2135 minornode_walk_init(mdb_walk_state_t *wsp) 2136 { 2137 struct dev_info di; 2138 uintptr_t addr = wsp->walk_addr; 2139 2140 if (addr == NULL) { 2141 mdb_warn("a dev_info struct address must be provided\n"); 2142 return (WALK_ERR); 2143 } 2144 2145 if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1) { 2146 mdb_warn("failed to read dev_info struct at %p", addr); 2147 return (WALK_ERR); 2148 } 2149 2150 wsp->walk_addr = (uintptr_t)di.devi_minor; 2151 return (WALK_NEXT); 2152 } 2153 2154 int 2155 minornode_walk_step(mdb_walk_state_t *wsp) 2156 { 2157 struct ddi_minor_data md; 2158 uintptr_t addr = wsp->walk_addr; 2159 2160 if (addr == NULL) 2161 return (WALK_DONE); 2162 2163 if (mdb_vread(&md, sizeof (md), addr) == -1) { 2164 mdb_warn("failed to read dev_info struct at %p", addr); 2165 return (WALK_DONE); 2166 } 2167 2168 wsp->walk_addr = (uintptr_t)md.next; 2169 return (wsp->walk_callback(addr, &md, wsp->walk_cbdata)); 2170 } 2171 2172 static const char *const md_type[] = { 2173 "DDI_MINOR", 2174 "DDI_ALIAS", 2175 "DDI_DEFAULT", 2176 "DDI_I_PATH", 2177 "?" 2178 }; 2179 2180 #define MD_TYPE_MAX ((sizeof (md_type) / sizeof (char *)) - 1) 2181 2182 /*ARGSUSED*/ 2183 static int 2184 print_minornode(uintptr_t addr, const void *arg, void *data) 2185 { 2186 char name[128]; 2187 char nodetype[128]; 2188 char *spectype; 2189 struct ddi_minor_data *mdp = (struct ddi_minor_data *)arg; 2190 2191 if (mdb_readstr(name, sizeof (name), (uintptr_t)mdp->ddm_name) == -1) 2192 *name = '\0'; 2193 2194 if (mdb_readstr(nodetype, sizeof (nodetype), 2195 (uintptr_t)mdp->ddm_node_type) == -1) 2196 *nodetype = '\0'; 2197 2198 switch (mdp->ddm_spec_type) { 2199 case S_IFCHR: spectype = "c"; break; 2200 case S_IFBLK: spectype = "b"; break; 2201 default: spectype = "?"; break; 2202 } 2203 2204 mdb_printf("%?p %16lx %-4s %-11s %-10s %s\n", 2205 addr, mdp->ddm_dev, spectype, md_type[MIN(mdp->type, MD_TYPE_MAX)], 2206 name, nodetype); 2207 2208 return (WALK_NEXT); 2209 } 2210 2211 /*ARGSUSED*/ 2212 int 2213 minornodes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2214 { 2215 if (!(flags & DCMD_ADDRSPEC) || argc != 0) 2216 return (DCMD_USAGE); 2217 2218 if (DCMD_HDRSPEC(flags)) 2219 mdb_printf("%<u>%?s %16s %-4s %-11s %-10s %-16s%</u>\n", 2220 "ADDR", "DEV", "SPEC", "TYPE", "NAME", "NODETYPE"); 2221 2222 if (mdb_pwalk("minornode", print_minornode, NULL, addr) == -1) { 2223 mdb_warn("can't walk minornode"); 2224 return (DCMD_ERR); 2225 } 2226 2227 return (DCMD_OK); 2228 } 2229