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