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