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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/sysmacros.h> 30 #include <sys/dditypes.h> 31 #include <sys/ddi_impldefs.h> 32 #include <sys/ddifm.h> 33 #include <sys/ddipropdefs.h> 34 #include <sys/modctl.h> 35 #include <sys/hwconf.h> 36 #include <sys/stat.h> 37 #include <errno.h> 38 #include <sys/sunmdi.h> 39 #include <sys/mdi_impldefs.h> 40 41 #include <ctype.h> 42 #include <mdb/mdb_modapi.h> 43 #include <mdb/mdb_ks.h> 44 45 #include "nvpair.h" 46 47 #define DEVINFO_TREE_INDENT 4 /* Indent for devs one down in tree */ 48 #define DEVINFO_PROP_INDENT 4 /* Indent for properties */ 49 #define DEVINFO_PROPLIST_INDENT 8 /* Indent for properties lists */ 50 51 52 /* 53 * Options for prtconf/devinfo dcmd. 54 */ 55 #define DEVINFO_VERBOSE 0x1 56 #define DEVINFO_PARENT 0x2 57 #define DEVINFO_CHILD 0x4 58 #define DEVINFO_ALLBOLD 0x8 59 #define DEVINFO_SUMMARY 0x10 60 61 /* 62 * devinfo node state map. Used by devinfo() and devinfo_audit(). 63 * Long words are deliberately truncated so that output 64 * fits in 80 column with 64-bit addresses. 65 */ 66 static const char *const di_state[] = { 67 "DS_INVAL", 68 "DS_PROTO", 69 "DS_LINKED", 70 "DS_BOUND", 71 "DS_INITIA", 72 "DS_PROBED", 73 "DS_ATTACH", 74 "DS_READY", 75 "?" 76 }; 77 78 #define DI_STATE_MAX ((sizeof (di_state) / sizeof (char *)) - 1) 79 80 void 81 prtconf_help(void) 82 { 83 mdb_printf("Prints the devinfo tree from a given node.\n" 84 "Without the address of a \"struct devinfo\" given, " 85 "prints from the root;\n" 86 "with an address, prints the parents of, " 87 "and all children of, that address.\n\n" 88 "Switches:\n" 89 " -v be verbose - print device property lists\n" 90 " -p only print the ancestors of the given node\n" 91 " -c only print the children of the given node\n"); 92 } 93 94 void 95 devinfo_help(void) 96 { 97 mdb_printf("Switches:\n" 98 " -q be quiet - don't print device property lists\n" 99 " -s print summary of dev_info structures\n"); 100 } 101 102 uintptr_t devinfo_root; /* Address of root of devinfo tree */ 103 104 /* 105 * Devinfo walker. 106 */ 107 108 typedef struct { 109 /* 110 * The "struct dev_info" must be the first thing in this structure. 111 */ 112 struct dev_info din_dev; 113 114 /* 115 * This is for the benefit of prtconf(). 116 */ 117 int din_depth; 118 } devinfo_node_t; 119 120 typedef struct devinfo_parents_walk_data { 121 devinfo_node_t dip_node; 122 #define dip_dev dip_node.din_dev 123 #define dip_depth dip_node.din_depth 124 struct dev_info *dip_end; 125 126 /* 127 * The following three elements are for walking the parents of a node: 128 * "dip_base_depth" is the depth of the given node from the root. 129 * This starts at 1 (if we're walking devinfo_root), because 130 * it's the size of the dip_parent_{nodes,addresses} arrays, 131 * and has to include the given node. 132 * "dip_parent_nodes" is a collection of the parent node structures, 133 * already read in via mdb_vread(). dip_parent_nodes[0] is the 134 * root, dip_parent_nodes[1] is a child of the root, etc. 135 * "dip_parent_addresses" holds the vaddrs of all the parent nodes. 136 */ 137 int dip_base_depth; 138 devinfo_node_t *dip_parent_nodes; 139 uintptr_t *dip_parent_addresses; 140 } devinfo_parents_walk_data_t; 141 142 int 143 devinfo_parents_walk_init(mdb_walk_state_t *wsp) 144 { 145 devinfo_parents_walk_data_t *dip; 146 uintptr_t addr; 147 int i; 148 149 if (wsp->walk_addr == NULL) 150 wsp->walk_addr = devinfo_root; 151 addr = wsp->walk_addr; 152 153 dip = mdb_alloc(sizeof (devinfo_parents_walk_data_t), UM_SLEEP); 154 wsp->walk_data = dip; 155 156 dip->dip_end = (struct dev_info *)wsp->walk_addr; 157 dip->dip_depth = 0; 158 dip->dip_base_depth = 1; 159 160 do { 161 if (mdb_vread(&dip->dip_dev, sizeof (dip->dip_dev), 162 addr) == -1) { 163 mdb_warn("failed to read devinfo at %p", addr); 164 mdb_free(dip, sizeof (devinfo_parents_walk_data_t)); 165 wsp->walk_data = NULL; 166 return (WALK_ERR); 167 } 168 addr = (uintptr_t)dip->dip_dev.devi_parent; 169 if (addr != 0) 170 dip->dip_base_depth++; 171 } while (addr != 0); 172 173 addr = wsp->walk_addr; 174 175 dip->dip_parent_nodes = mdb_alloc( 176 dip->dip_base_depth * sizeof (devinfo_node_t), UM_SLEEP); 177 dip->dip_parent_addresses = mdb_alloc( 178 dip->dip_base_depth * sizeof (uintptr_t), UM_SLEEP); 179 for (i = dip->dip_base_depth - 1; i >= 0; i--) { 180 if (mdb_vread(&dip->dip_parent_nodes[i].din_dev, 181 sizeof (struct dev_info), addr) == -1) { 182 mdb_warn("failed to read devinfo at %p", addr); 183 return (WALK_ERR); 184 } 185 dip->dip_parent_nodes[i].din_depth = i; 186 dip->dip_parent_addresses[i] = addr; 187 addr = (uintptr_t) 188 dip->dip_parent_nodes[i].din_dev.devi_parent; 189 } 190 191 return (WALK_NEXT); 192 } 193 194 int 195 devinfo_parents_walk_step(mdb_walk_state_t *wsp) 196 { 197 devinfo_parents_walk_data_t *dip = wsp->walk_data; 198 int status; 199 200 if (dip->dip_depth == dip->dip_base_depth) 201 return (WALK_DONE); 202 203 status = wsp->walk_callback( 204 dip->dip_parent_addresses[dip->dip_depth], 205 &dip->dip_parent_nodes[dip->dip_depth], 206 wsp->walk_cbdata); 207 208 dip->dip_depth++; 209 return (status); 210 } 211 212 void 213 devinfo_parents_walk_fini(mdb_walk_state_t *wsp) 214 { 215 devinfo_parents_walk_data_t *dip = wsp->walk_data; 216 217 mdb_free(dip->dip_parent_nodes, 218 dip->dip_base_depth * sizeof (devinfo_node_t)); 219 mdb_free(dip->dip_parent_addresses, 220 dip->dip_base_depth * sizeof (uintptr_t)); 221 mdb_free(wsp->walk_data, sizeof (devinfo_parents_walk_data_t)); 222 } 223 224 225 typedef struct devinfo_children_walk_data { 226 devinfo_node_t dic_node; 227 #define dic_dev dic_node.din_dev 228 #define dic_depth dic_node.din_depth 229 struct dev_info *dic_end; 230 int dic_print_first_node; 231 } devinfo_children_walk_data_t; 232 233 int 234 devinfo_children_walk_init(mdb_walk_state_t *wsp) 235 { 236 devinfo_children_walk_data_t *dic; 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 typedef struct devinfo_cb_data { 949 uintptr_t di_base; 950 uint_t di_flags; 951 } devinfo_cb_data_t; 952 953 static int 954 devinfo_print(uintptr_t addr, struct dev_info *dev, devinfo_cb_data_t *data) 955 { 956 /* 957 * We know the walker passes us extra data after the dev_info. 958 */ 959 char binding_name[128]; 960 char dname[MODMAXNAMELEN + 1]; 961 devinfo_node_t *din = (devinfo_node_t *)dev; 962 ddi_prop_t *global_props = NULL; 963 964 if (mdb_readstr(binding_name, sizeof (binding_name), 965 (uintptr_t)dev->devi_binding_name) == -1) { 966 mdb_warn("failed to read binding_name at %p", 967 (uintptr_t)dev->devi_binding_name); 968 return (WALK_ERR); 969 } 970 971 /* if there are any global properties, get a pointer to them */ 972 if (dev->devi_global_prop_list != NULL) { 973 ddi_prop_list_t plist; 974 if (mdb_vread((void*)&plist, sizeof (plist), 975 (uintptr_t)dev->devi_global_prop_list) == -1) { 976 mdb_warn("failed to read global prop_list at %p", 977 (uintptr_t)dev->devi_global_prop_list); 978 return (WALK_ERR); 979 } 980 global_props = plist.prop_list; 981 } 982 983 mdb_inc_indent(din->din_depth * DEVINFO_TREE_INDENT); 984 if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD)) 985 mdb_printf("%<b>"); 986 mdb_printf("%-0?p %s", addr, binding_name); 987 if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD)) 988 mdb_printf("%</b>"); 989 if (dev->devi_instance >= 0) 990 mdb_printf(", instance #%d", dev->devi_instance); 991 992 if (dev->devi_node_state < DS_ATTACHED) 993 mdb_printf(" (driver not attached)"); 994 else if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0) 995 mdb_printf(" (could not determine driver name)"); 996 else 997 mdb_printf(" (driver name: %s)", dname); 998 999 mdb_printf("\n"); 1000 if (data->di_flags & DEVINFO_VERBOSE) { 1001 mdb_inc_indent(DEVINFO_PROPLIST_INDENT); 1002 devinfo_print_props("System", dev->devi_sys_prop_ptr); 1003 devinfo_print_props("Driver", dev->devi_drv_prop_ptr); 1004 devinfo_print_props("Hardware", dev->devi_hw_prop_ptr); 1005 devinfo_print_props("Global", global_props); 1006 1007 devinfo_print_pathing(dev->devi_mdi_component, 1008 dev->devi_mdi_client); 1009 1010 mdb_dec_indent(DEVINFO_PROPLIST_INDENT); 1011 } 1012 1013 mdb_dec_indent(din->din_depth * DEVINFO_TREE_INDENT); 1014 return (WALK_NEXT); 1015 } 1016 1017 /*ARGSUSED*/ 1018 int 1019 prtconf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1020 { 1021 devinfo_cb_data_t data; 1022 int status; 1023 1024 data.di_flags = DEVINFO_PARENT | DEVINFO_CHILD; 1025 1026 if (mdb_getopts(argc, argv, 1027 'v', MDB_OPT_SETBITS, DEVINFO_VERBOSE, &data.di_flags, 1028 'p', MDB_OPT_CLRBITS, DEVINFO_CHILD, &data.di_flags, 1029 'c', MDB_OPT_CLRBITS, DEVINFO_PARENT, &data.di_flags, NULL) != argc) 1030 return (DCMD_USAGE); 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_MD_UPDATE", DEVI_S_MD_UPDATE, DEVI_S_MD_UPDATE }, 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 { NULL, 0, 0 } 1277 }; 1278 1279 const mdb_arg_t *argp = NULL; 1280 uint_t opt_v = FALSE, opt_m = FALSE; 1281 major_t major; 1282 size_t i; 1283 1284 char name[MODMAXNAMELEN + 1]; 1285 struct devnames dn; 1286 1287 if ((i = mdb_getopts(argc, argv, 1288 'm', MDB_OPT_SETBITS, TRUE, &opt_m, 1289 'v', MDB_OPT_SETBITS, TRUE, &opt_v, 1290 NULL)) != argc) { 1291 if (argc - i > 1) 1292 return (DCMD_USAGE); 1293 argp = &argv[i]; 1294 } 1295 1296 if (opt_m) { 1297 if (!(flags & DCMD_ADDRSPEC)) 1298 return (DCMD_USAGE); 1299 1300 if (major_to_addr(addr, &addr) == -1) 1301 return (DCMD_ERR); 1302 1303 } else if (!(flags & DCMD_ADDRSPEC)) { 1304 if (argp == NULL) { 1305 if (mdb_walk_dcmd("devnames", "devnames", argc, argv)) { 1306 mdb_warn("failed to walk devnames"); 1307 return (DCMD_ERR); 1308 } 1309 return (DCMD_OK); 1310 } 1311 1312 if (argp->a_type == MDB_TYPE_IMMEDIATE) 1313 major = (major_t)argp->a_un.a_val; 1314 else 1315 major = (major_t)mdb_strtoull(argp->a_un.a_str); 1316 1317 if (major_to_addr(major, &addr) == -1) 1318 return (DCMD_ERR); 1319 } 1320 1321 if (mdb_vread(&dn, sizeof (struct devnames), addr) == -1) { 1322 mdb_warn("failed to read devnames struct at %p", addr); 1323 return (DCMD_ERR); 1324 } 1325 1326 if (DCMD_HDRSPEC(flags)) { 1327 if (opt_v) 1328 mdb_printf("%<u>%-16s%</u>\n", "NAME"); 1329 else 1330 mdb_printf("%<u>%-16s %-?s%</u>\n", "NAME", "DN_HEAD"); 1331 } 1332 1333 if ((flags & DCMD_LOOP) && (dn.dn_name == NULL)) 1334 return (DCMD_OK); /* Skip empty slots if we're printing table */ 1335 1336 if (mdb_readstr(name, sizeof (name), (uintptr_t)dn.dn_name) == -1) 1337 (void) mdb_snprintf(name, sizeof (name), "0x%p", dn.dn_name); 1338 1339 if (opt_v) { 1340 ddi_prop_list_t prop_list; 1341 mdb_printf("%<b>%-16s%</b>\n", name); 1342 mdb_inc_indent(2); 1343 1344 mdb_printf(" flags %b\n", dn.dn_flags, dn_flag_bits); 1345 mdb_printf(" pl %p\n", (void *)dn.dn_pl); 1346 mdb_printf(" head %p\n", dn.dn_head); 1347 mdb_printf(" instance %d\n", dn.dn_instance); 1348 mdb_printf(" inlist %p\n", dn.dn_inlist); 1349 mdb_printf("global_prop_ptr %p\n", dn.dn_global_prop_ptr); 1350 if (mdb_vread(&prop_list, sizeof (ddi_prop_list_t), 1351 (uintptr_t)dn.dn_global_prop_ptr) != -1) { 1352 devinfo_print_props(NULL, prop_list.prop_list); 1353 } 1354 1355 mdb_dec_indent(2); 1356 } else 1357 mdb_printf("%-16s %-?p\n", name, dn.dn_head); 1358 1359 return (DCMD_OK); 1360 } 1361 1362 /*ARGSUSED*/ 1363 int 1364 name2major(uintptr_t vaddr, uint_t flags, int argc, const mdb_arg_t *argv) 1365 { 1366 major_t major; 1367 1368 if (flags & DCMD_ADDRSPEC) 1369 return (DCMD_USAGE); 1370 1371 if (argc != 1 || argv->a_type != MDB_TYPE_STRING) 1372 return (DCMD_USAGE); 1373 1374 if (mdb_name_to_major(argv->a_un.a_str, &major) != 0) { 1375 mdb_warn("failed to convert name to major number\n"); 1376 return (DCMD_ERR); 1377 } 1378 1379 mdb_printf("0x%x\n", major); 1380 return (DCMD_OK); 1381 } 1382 1383 /* 1384 * Get a numerical argument of a dcmd from addr if an address is specified 1385 * or from argv if no address is specified. Return the argument in ret. 1386 */ 1387 static int 1388 getarg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 1389 uintptr_t *ret) 1390 { 1391 if (argc == 0 && (flags & DCMD_ADDRSPEC)) { 1392 *ret = addr; 1393 1394 } else if (argc == 1 && !(flags & DCMD_ADDRSPEC)) { 1395 *ret = (argv[0].a_type == MDB_TYPE_IMMEDIATE) ? 1396 (uintptr_t)argv[0].a_un.a_val : 1397 (uintptr_t)mdb_strtoull(argv->a_un.a_str); 1398 1399 } else { 1400 return (-1); 1401 } 1402 1403 return (0); 1404 } 1405 1406 /*ARGSUSED*/ 1407 int 1408 major2name(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1409 { 1410 uintptr_t major; 1411 const char *name; 1412 1413 if (getarg(addr, flags, argc, argv, &major) < 0) 1414 return (DCMD_USAGE); 1415 1416 if ((name = mdb_major_to_name((major_t)major)) == NULL) { 1417 mdb_warn("failed to convert major number to name\n"); 1418 return (DCMD_ERR); 1419 } 1420 1421 mdb_printf("%s\n", name); 1422 return (DCMD_OK); 1423 } 1424 1425 /*ARGSUSED*/ 1426 int 1427 dev2major(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1428 { 1429 uintptr_t dev; 1430 1431 if (getarg(addr, flags, argc, argv, &dev) < 0) 1432 return (DCMD_USAGE); 1433 1434 if (flags & DCMD_PIPE_OUT) 1435 mdb_printf("%x\n", getmajor(dev)); 1436 else 1437 mdb_printf("0x%x (0t%d)\n", getmajor(dev), getmajor(dev)); 1438 1439 return (DCMD_OK); 1440 } 1441 1442 /*ARGSUSED*/ 1443 int 1444 dev2minor(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1445 { 1446 uintptr_t dev; 1447 1448 if (getarg(addr, flags, argc, argv, &dev) < 0) 1449 return (DCMD_USAGE); 1450 1451 if (flags & DCMD_PIPE_OUT) 1452 mdb_printf("%x\n", getminor(dev)); 1453 else 1454 mdb_printf("0x%x (0t%d)\n", getminor(dev), getminor(dev)); 1455 1456 return (DCMD_OK); 1457 } 1458 1459 /*ARGSUSED*/ 1460 int 1461 devt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1462 { 1463 uintptr_t dev; 1464 1465 if (getarg(addr, flags, argc, argv, &dev) < 0) 1466 return (DCMD_USAGE); 1467 1468 if (DCMD_HDRSPEC(flags)) { 1469 mdb_printf("%<u>%10s%</u> %<u>%10s%</u>\n", "MAJOR", 1470 "MINOR"); 1471 } 1472 1473 mdb_printf("%10d %10d\n", getmajor(dev), getminor(dev)); 1474 1475 return (DCMD_OK); 1476 } 1477 1478 /*ARGSUSED*/ 1479 int 1480 softstate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1481 { 1482 uintptr_t statep; 1483 int instance; 1484 1485 1486 if (argc != 1) { 1487 return (DCMD_USAGE); 1488 } 1489 1490 if (argv[0].a_type == MDB_TYPE_IMMEDIATE) 1491 instance = argv[0].a_un.a_val; 1492 else 1493 instance = mdb_strtoull(argv->a_un.a_str); 1494 1495 if (mdb_get_soft_state_byaddr(addr, instance, &statep, NULL, 0) == -1) { 1496 if (errno == ENOENT) { 1497 mdb_warn("instance %d unused\n", instance); 1498 } else { 1499 mdb_warn("couldn't determine softstate for " 1500 "instance %d", instance); 1501 } 1502 1503 return (DCMD_ERR); 1504 } 1505 1506 mdb_printf("%p\n", statep); 1507 return (DCMD_OK); 1508 } 1509 1510 /* 1511 * Walker for all possible pointers to a driver state struct in an 1512 * i_ddi_soft_state instance chain. Returns all non-NULL pointers. 1513 */ 1514 typedef struct soft_state_walk { 1515 struct i_ddi_soft_state ssw_ss; /* Local copy of i_ddi_soft_state */ 1516 void **ssw_pointers; /* to driver state structs */ 1517 uint_t ssw_index; /* array entry we're using */ 1518 } soft_state_walk_t; 1519 1520 int 1521 soft_state_walk_init(mdb_walk_state_t *wsp) 1522 { 1523 soft_state_walk_t *sst; 1524 1525 1526 if (wsp->walk_addr == NULL) 1527 return (WALK_DONE); 1528 1529 sst = mdb_zalloc(sizeof (soft_state_walk_t), UM_SLEEP|UM_GC); 1530 wsp->walk_data = sst; 1531 1532 1533 if (mdb_vread(&(sst->ssw_ss), sizeof (sst->ssw_ss), wsp->walk_addr) != 1534 sizeof (sst->ssw_ss)) { 1535 mdb_warn("failed to read i_ddi_soft_state at %p", 1536 wsp->walk_addr); 1537 return (WALK_ERR); 1538 } 1539 1540 1541 /* Read array of pointers to state structs into local storage. */ 1542 sst->ssw_pointers = mdb_alloc((sst->ssw_ss.n_items * sizeof (void *)), 1543 UM_SLEEP|UM_GC); 1544 1545 if (mdb_vread(sst->ssw_pointers, (sst->ssw_ss.n_items * 1546 sizeof (void *)), (uintptr_t)sst->ssw_ss.array) != 1547 (sst->ssw_ss.n_items * sizeof (void *))) { 1548 mdb_warn("failed to read i_ddi_soft_state at %p", 1549 wsp->walk_addr); 1550 return (WALK_ERR); 1551 } 1552 1553 sst->ssw_index = 0; 1554 1555 return (WALK_NEXT); 1556 } 1557 1558 int 1559 soft_state_walk_step(mdb_walk_state_t *wsp) 1560 { 1561 soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data; 1562 int status = WALK_NEXT; 1563 1564 1565 /* 1566 * If the entry indexed has a valid pointer to a soft state struct, 1567 * invoke caller's callback func. 1568 */ 1569 if (sst->ssw_pointers[sst->ssw_index] != NULL) { 1570 status = wsp->walk_callback( 1571 (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL, 1572 wsp->walk_cbdata); 1573 } 1574 1575 sst->ssw_index += 1; 1576 1577 if (sst->ssw_index == sst->ssw_ss.n_items) 1578 return (WALK_DONE); 1579 1580 return (status); 1581 } 1582 1583 int 1584 soft_state_all_walk_step(mdb_walk_state_t *wsp) 1585 { 1586 soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data; 1587 int status = WALK_NEXT; 1588 1589 1590 status = wsp->walk_callback( 1591 (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL, 1592 wsp->walk_cbdata); 1593 1594 sst->ssw_index += 1; 1595 1596 if (sst->ssw_index == sst->ssw_ss.n_items) 1597 return (WALK_DONE); 1598 1599 return (status); 1600 } 1601 1602 /*ARGSUSED*/ 1603 int 1604 devbindings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1605 { 1606 const mdb_arg_t *arg; 1607 struct devnames dn; 1608 uintptr_t dn_addr; 1609 major_t major; 1610 1611 if (!(flags & DCMD_ADDRSPEC) && argc < 1) 1612 return (DCMD_USAGE); 1613 1614 if (flags & DCMD_ADDRSPEC) { 1615 /* 1616 * If there's an address, then it's a major number 1617 */ 1618 major = addr; 1619 } else { 1620 /* 1621 * We interpret the last argument. Any other arguments are 1622 * forwarded to "devinfo" 1623 */ 1624 arg = &argv[argc - 1]; 1625 argc--; 1626 1627 if (arg->a_type == MDB_TYPE_IMMEDIATE) { 1628 major = (uintptr_t)arg->a_un.a_val; 1629 1630 } else if (arg->a_un.a_str[0] == '-') { 1631 /* the argument shouldn't be an option */ 1632 return (DCMD_USAGE); 1633 1634 } else if (isdigit(arg->a_un.a_str[0])) { 1635 major = (uintptr_t)mdb_strtoull(arg->a_un.a_str); 1636 1637 } else { 1638 if (mdb_name_to_major(arg->a_un.a_str, &major) != 0) { 1639 mdb_warn("failed to get major number for %s\n", 1640 arg->a_un.a_str); 1641 return (DCMD_ERR); 1642 } 1643 } 1644 } 1645 1646 if (major_to_addr(major, &dn_addr) != 0) 1647 return (DCMD_ERR); 1648 1649 if (mdb_vread(&dn, sizeof (struct devnames), dn_addr) == -1) { 1650 mdb_warn("couldn't read devnames array at %p", dn_addr); 1651 return (DCMD_ERR); 1652 } 1653 1654 if (mdb_pwalk_dcmd("devi_next", "devinfo", argc, argv, 1655 (uintptr_t)dn.dn_head) != 0) { 1656 mdb_warn("couldn't walk the devinfo chain at %p", dn.dn_head); 1657 return (DCMD_ERR); 1658 } 1659 1660 return (DCMD_OK); 1661 } 1662 1663 /* 1664 * walk binding hashtable (as of of driver names (e.g., mb_hashtab)) 1665 */ 1666 int 1667 binding_hash_walk_init(mdb_walk_state_t *wsp) 1668 { 1669 if (wsp->walk_addr == NULL) 1670 return (WALK_ERR); 1671 1672 wsp->walk_data = mdb_alloc(sizeof (void *) * MOD_BIND_HASHSIZE, 1673 UM_SLEEP|UM_GC); 1674 if (mdb_vread(wsp->walk_data, sizeof (void *) * MOD_BIND_HASHSIZE, 1675 wsp->walk_addr) == -1) { 1676 mdb_warn("failed to read mb_hashtab"); 1677 return (WALK_ERR); 1678 } 1679 1680 wsp->walk_arg = 0; /* index into mb_hashtab array to start */ 1681 1682 return (WALK_NEXT); 1683 } 1684 1685 int 1686 binding_hash_walk_step(mdb_walk_state_t *wsp) 1687 { 1688 int status; 1689 uintptr_t bind_p; 1690 struct bind bind; 1691 1692 1693 /* 1694 * Walk the singly-linked list of struct bind 1695 */ 1696 bind_p = ((uintptr_t *)wsp->walk_data)[(ulong_t)wsp->walk_arg]; 1697 while (bind_p != NULL) { 1698 1699 if (mdb_vread(&bind, sizeof (bind), bind_p) == -1) { 1700 mdb_warn("failed to read bind struct at %p", 1701 wsp->walk_addr); 1702 return (WALK_ERR); 1703 } 1704 1705 if ((status = wsp->walk_callback(bind_p, &bind, 1706 wsp->walk_cbdata)) != WALK_NEXT) { 1707 return (status); 1708 } 1709 1710 bind_p = (uintptr_t)bind.b_next; 1711 } 1712 1713 wsp->walk_arg = (void *)((char *)wsp->walk_arg + 1); 1714 1715 if (wsp->walk_arg == (void *)(MOD_BIND_HASHSIZE - 1)) 1716 return (WALK_DONE); 1717 1718 return (WALK_NEXT); 1719 } 1720 1721 /*ARGSUSED*/ 1722 int 1723 binding_hash_entry(uintptr_t addr, uint_t flags, int argc, 1724 const mdb_arg_t *argv) 1725 { 1726 struct bind bind; 1727 /* Arbitrary lengths based on output format below */ 1728 char name[MAXPATHLEN] = "???"; 1729 char bind_name[MAXPATHLEN] = "<null>"; 1730 1731 if ((flags & DCMD_ADDRSPEC) == NULL) 1732 return (DCMD_USAGE); 1733 1734 /* Allow null addresses to be passed (as from a walker) */ 1735 if (addr == NULL) 1736 return (DCMD_OK); 1737 1738 if (mdb_vread(&bind, sizeof (bind), addr) == -1) { 1739 mdb_warn("failed to read struct bind at %p", addr); 1740 return (DCMD_ERR); 1741 } 1742 1743 if (DCMD_HDRSPEC(flags)) { 1744 mdb_printf("%<u>%?s% %-5s %s%</u>\n", 1745 "NEXT", "MAJOR", "NAME(S)"); 1746 } 1747 1748 if (mdb_readstr(name, sizeof (name), (uintptr_t)bind.b_name) == -1) 1749 mdb_warn("failed to read 'name'"); 1750 1751 /* There may be bind_name, so this may fail */ 1752 if (mdb_readstr(bind_name, sizeof (bind_name), 1753 (uintptr_t)bind.b_bind_name) == -1) { 1754 mdb_printf("%?p %5d %s\n", 1755 bind.b_next, bind.b_num, name); 1756 } else { 1757 mdb_printf("%?p %5d %s %s\n", 1758 bind.b_next, bind.b_num, name, bind_name); 1759 } 1760 1761 return (DCMD_OK); 1762 } 1763 1764 typedef struct devinfo_audit_log_walk_data { 1765 devinfo_audit_t dil_buf; /* buffer of last entry */ 1766 uintptr_t dil_base; /* starting address of log buffer */ 1767 int dil_max; /* maximum index */ 1768 int dil_start; /* starting index */ 1769 int dil_index; /* current walking index */ 1770 } devinfo_audit_log_walk_data_t; 1771 1772 int 1773 devinfo_audit_log_walk_init(mdb_walk_state_t *wsp) 1774 { 1775 devinfo_log_header_t header; 1776 devinfo_audit_log_walk_data_t *dil; 1777 uintptr_t devinfo_audit_log; 1778 1779 /* read in devinfo_log_header structure */ 1780 if (mdb_readvar(&devinfo_audit_log, "devinfo_audit_log") == -1) { 1781 mdb_warn("failed to read 'devinfo_audit_log'"); 1782 return (WALK_ERR); 1783 } 1784 1785 if (mdb_vread(&header, sizeof (devinfo_log_header_t), 1786 devinfo_audit_log) == -1) { 1787 mdb_warn("couldn't read devinfo_log_header at %p", 1788 devinfo_audit_log); 1789 return (WALK_ERR); 1790 } 1791 1792 dil = mdb_zalloc(sizeof (devinfo_audit_log_walk_data_t), UM_SLEEP); 1793 wsp->walk_data = dil; 1794 1795 dil->dil_start = dil->dil_index = header.dh_curr; 1796 dil->dil_max = header.dh_max; 1797 if (dil->dil_start < 0) /* no log entries */ 1798 return (WALK_DONE); 1799 1800 dil->dil_base = devinfo_audit_log + 1801 offsetof(devinfo_log_header_t, dh_entry); 1802 wsp->walk_addr = dil->dil_base + 1803 dil->dil_index * sizeof (devinfo_audit_t); 1804 1805 return (WALK_NEXT); 1806 } 1807 1808 int 1809 devinfo_audit_log_walk_step(mdb_walk_state_t *wsp) 1810 { 1811 uintptr_t addr = wsp->walk_addr; 1812 devinfo_audit_log_walk_data_t *dil = wsp->walk_data; 1813 devinfo_audit_t *da = &dil->dil_buf; 1814 int status = WALK_NEXT; 1815 1816 /* read in current entry and invoke callback */ 1817 if (addr == NULL) 1818 return (WALK_DONE); 1819 1820 if (mdb_vread(&dil->dil_buf, sizeof (devinfo_audit_t), addr) == -1) { 1821 mdb_warn("failed to read devinfo_audit at %p", addr); 1822 status = WALK_DONE; 1823 } 1824 status = wsp->walk_callback(wsp->walk_addr, da, wsp->walk_cbdata); 1825 1826 /* step to the previous log entry in time */ 1827 if (--dil->dil_index < 0) 1828 dil->dil_index += dil->dil_max; 1829 if (dil->dil_index == dil->dil_start) { 1830 wsp->walk_addr = NULL; 1831 return (WALK_DONE); 1832 } 1833 1834 wsp->walk_addr = dil->dil_base + 1835 dil->dil_index * sizeof (devinfo_audit_t); 1836 return (status); 1837 } 1838 1839 void 1840 devinfo_audit_log_walk_fini(mdb_walk_state_t *wsp) 1841 { 1842 mdb_free(wsp->walk_data, sizeof (devinfo_audit_log_walk_data_t)); 1843 } 1844 1845 /* 1846 * display devinfo_audit_t stack trace 1847 */ 1848 /*ARGSUSED*/ 1849 int 1850 devinfo_audit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1851 { 1852 uint_t verbose = FALSE; 1853 devinfo_audit_t da; 1854 int i, depth; 1855 1856 if ((flags & DCMD_ADDRSPEC) == 0) 1857 return (DCMD_USAGE); 1858 1859 if (mdb_getopts(argc, argv, 1860 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) 1861 return (DCMD_USAGE); 1862 1863 if (DCMD_HDRSPEC(flags)) { 1864 mdb_printf(" %-?s %16s %-?s %-?s %5s\n", 1865 "AUDIT", "TIMESTAMP", "THREAD", "DEVINFO", "STATE"); 1866 } 1867 1868 if (mdb_vread(&da, sizeof (da), addr) == -1) { 1869 mdb_warn("couldn't read devinfo_audit at %p", addr); 1870 return (DCMD_ERR); 1871 } 1872 1873 mdb_printf(" %0?p %16llx %0?p %0?p %s\n", 1874 addr, da.da_timestamp, da.da_thread, da.da_devinfo, 1875 di_state[MIN(da.da_node_state + 1, DI_STATE_MAX)]); 1876 1877 if (!verbose) 1878 return (DCMD_OK); 1879 1880 mdb_inc_indent(4); 1881 1882 /* 1883 * Guard against bogus da_depth in case the devinfo_audit_t 1884 * is corrupt or the address does not really refer to a 1885 * devinfo_audit_t. 1886 */ 1887 depth = MIN(da.da_depth, DDI_STACK_DEPTH); 1888 1889 for (i = 0; i < depth; i++) 1890 mdb_printf("%a\n", da.da_stack[i]); 1891 1892 mdb_printf("\n"); 1893 mdb_dec_indent(4); 1894 1895 return (DCMD_OK); 1896 } 1897 1898 int 1899 devinfo_audit_log(uintptr_t addr, uint_t flags, int argc, 1900 const mdb_arg_t *argv) 1901 { 1902 if (flags & DCMD_ADDRSPEC) 1903 return (devinfo_audit(addr, flags, argc, argv)); 1904 1905 (void) mdb_walk_dcmd("devinfo_audit_log", "devinfo_audit", argc, argv); 1906 return (DCMD_OK); 1907 } 1908 1909 typedef struct devinfo_audit_node_walk_data { 1910 devinfo_audit_t dih_buf; /* buffer of last entry */ 1911 uintptr_t dih_dip; /* address of dev_info */ 1912 int dih_on_devinfo; /* devi_audit on dev_info struct */ 1913 } devinfo_audit_node_walk_data_t; 1914 1915 int 1916 devinfo_audit_node_walk_init(mdb_walk_state_t *wsp) 1917 { 1918 devinfo_audit_node_walk_data_t *dih; 1919 devinfo_audit_t *da; 1920 struct dev_info devi; 1921 uintptr_t addr = wsp->walk_addr; 1922 1923 /* read in devinfo structure */ 1924 if (mdb_vread(&devi, sizeof (struct dev_info), addr) == -1) { 1925 mdb_warn("couldn't read dev_info at %p", addr); 1926 return (WALK_ERR); 1927 } 1928 1929 dih = mdb_zalloc(sizeof (devinfo_audit_node_walk_data_t), UM_SLEEP); 1930 wsp->walk_data = dih; 1931 da = &dih->dih_buf; 1932 1933 /* read in devi_audit structure */ 1934 if (mdb_vread(da, sizeof (devinfo_audit_t), (uintptr_t)devi.devi_audit) 1935 == -1) { 1936 mdb_warn("couldn't read devi_audit at %p", devi.devi_audit); 1937 return (WALK_ERR); 1938 } 1939 dih->dih_dip = addr; 1940 dih->dih_on_devinfo = 1; 1941 wsp->walk_addr = (uintptr_t)devi.devi_audit; 1942 1943 return (WALK_NEXT); 1944 } 1945 1946 int 1947 devinfo_audit_node_walk_step(mdb_walk_state_t *wsp) 1948 { 1949 uintptr_t addr; 1950 devinfo_audit_node_walk_data_t *dih = wsp->walk_data; 1951 devinfo_audit_t *da = &dih->dih_buf; 1952 1953 if (wsp->walk_addr == NULL) 1954 return (WALK_DONE); 1955 (void) wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata); 1956 1957 skip: 1958 /* read in previous entry */ 1959 if ((addr = (uintptr_t)da->da_lastlog) == 0) 1960 return (WALK_DONE); 1961 1962 if (mdb_vread(&dih->dih_buf, sizeof (devinfo_audit_t), addr) == -1) { 1963 mdb_warn("failed to read devinfo_audit at %p", addr); 1964 return (WALK_DONE); 1965 } 1966 1967 /* check if last log was over-written */ 1968 if ((uintptr_t)da->da_devinfo != dih->dih_dip) 1969 return (WALK_DONE); 1970 1971 /* 1972 * skip the first common log entry, which is a duplicate of 1973 * the devi_audit buffer on the dev_info structure 1974 */ 1975 if (dih->dih_on_devinfo) { 1976 dih->dih_on_devinfo = 0; 1977 goto skip; 1978 } 1979 wsp->walk_addr = addr; 1980 1981 return (WALK_NEXT); 1982 } 1983 1984 void 1985 devinfo_audit_node_walk_fini(mdb_walk_state_t *wsp) 1986 { 1987 mdb_free(wsp->walk_data, sizeof (devinfo_audit_node_walk_data_t)); 1988 } 1989 1990 int 1991 devinfo_audit_node(uintptr_t addr, uint_t flags, int argc, 1992 const mdb_arg_t *argv) 1993 { 1994 if (!(flags & DCMD_ADDRSPEC)) 1995 return (DCMD_USAGE); 1996 1997 (void) mdb_pwalk_dcmd("devinfo_audit_node", "devinfo_audit", 1998 argc, argv, addr); 1999 return (DCMD_OK); 2000 } 2001 2002 /* 2003 * mdb support for per-devinfo fault management data 2004 */ 2005 /*ARGSUSED*/ 2006 int 2007 devinfo_fm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2008 { 2009 struct dev_info devi; 2010 struct i_ddi_fmhdl fhdl; 2011 2012 if ((flags & DCMD_ADDRSPEC) == 0) 2013 return (DCMD_USAGE); 2014 2015 if (DCMD_HDRSPEC(flags)) { 2016 mdb_printf("%<u>%-11s IPL CAPS DROP FMCFULL FMCGREW ACCERR " 2017 "DMAERR %11s %11s%</u>\n", "ADDR", "DMACACHE", "ACCCACHE"); 2018 } 2019 2020 if (mdb_vread(&devi, sizeof (devi), addr) == -1) { 2021 mdb_warn("failed to read devinfo struct at %p", addr); 2022 return (DCMD_ERR); 2023 } 2024 2025 if (mdb_vread(&fhdl, sizeof (fhdl), (uintptr_t)devi.devi_fmhdl) == -1) { 2026 mdb_warn("failed to read devinfo fm struct at %p", 2027 (uintptr_t)devi.devi_fmhdl); 2028 return (DCMD_ERR); 2029 } 2030 2031 mdb_printf("%-11p %3u %c%c%c%c %4llu %7llu %7llu %6llu %6llu %11p " 2032 "%11p\n", 2033 (uintptr_t)devi.devi_fmhdl, fhdl.fh_ibc, 2034 (DDI_FM_EREPORT_CAP(fhdl.fh_cap) ? 'E' : '-'), 2035 (DDI_FM_ERRCB_CAP(fhdl.fh_cap) ? 'C' : '-'), 2036 (DDI_FM_ACC_ERR_CAP(fhdl.fh_cap) ? 'A' : '-'), 2037 (DDI_FM_DMA_ERR_CAP(fhdl.fh_cap) ? 'D' : '-'), 2038 fhdl.fh_kstat.fek_erpt_dropped.value.ui64, 2039 fhdl.fh_kstat.fek_fmc_full.value.ui64, 2040 fhdl.fh_kstat.fek_fmc_grew.value.ui64, 2041 fhdl.fh_kstat.fek_acc_err.value.ui64, 2042 fhdl.fh_kstat.fek_dma_err.value.ui64, 2043 fhdl.fh_dma_cache, fhdl.fh_acc_cache); 2044 2045 2046 return (DCMD_OK); 2047 } 2048 2049 /*ARGSUSED*/ 2050 int 2051 devinfo_fmce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2052 { 2053 struct i_ddi_fmc_entry fce; 2054 2055 if ((flags & DCMD_ADDRSPEC) == 0) 2056 return (DCMD_USAGE); 2057 2058 if (DCMD_HDRSPEC(flags)) { 2059 mdb_printf("%<u>%-11s %11s %11s%</u>\n", "ADDR", 2060 "RESOURCE", "BUS_SPECIFIC"); 2061 } 2062 2063 if (mdb_vread(&fce, sizeof (fce), addr) == -1) { 2064 mdb_warn("failed to read fm cache struct at %p", addr); 2065 return (DCMD_ERR); 2066 } 2067 2068 mdb_printf("%-11p %11p %11p\n", 2069 (uintptr_t)addr, fce.fce_resource, fce.fce_bus_specific); 2070 2071 2072 return (DCMD_OK); 2073 } 2074 2075 int 2076 devinfo_fmc_walk_init(mdb_walk_state_t *wsp) 2077 { 2078 struct i_ddi_fmc fec; 2079 struct i_ddi_fmc_entry fe; 2080 2081 if (wsp->walk_addr == NULL) 2082 return (WALK_ERR); 2083 2084 if (mdb_vread(&fec, sizeof (fec), wsp->walk_addr) == -1) { 2085 mdb_warn("failed to read fm cache at %p", wsp->walk_addr); 2086 return (WALK_ERR); 2087 } 2088 2089 if (fec.fc_active == NULL) 2090 return (WALK_DONE); 2091 2092 if (mdb_vread(&fe, sizeof (fe), (uintptr_t)fec.fc_active) == -1) { 2093 mdb_warn("failed to read active fm cache list at %p", 2094 fec.fc_active); 2095 return (WALK_ERR); 2096 } 2097 2098 wsp->walk_data = fe.fce_next; 2099 wsp->walk_addr = (uintptr_t)fe.fce_next; 2100 return (WALK_NEXT); 2101 } 2102 2103 int 2104 devinfo_fmc_walk_step(mdb_walk_state_t *wsp) 2105 { 2106 int status; 2107 struct i_ddi_fmc_entry fe; 2108 2109 if (mdb_vread(&fe, sizeof (fe), wsp->walk_addr) == -1) { 2110 mdb_warn("failed to read active fm cache entry at %p", 2111 wsp->walk_addr); 2112 return (WALK_DONE); 2113 } 2114 2115 status = wsp->walk_callback(wsp->walk_addr, &fe, wsp->walk_cbdata); 2116 2117 if (fe.fce_next == NULL) 2118 return (WALK_DONE); 2119 2120 wsp->walk_addr = (uintptr_t)fe.fce_next; 2121 return (status); 2122 } 2123 2124 int 2125 minornode_walk_init(mdb_walk_state_t *wsp) 2126 { 2127 struct dev_info di; 2128 uintptr_t addr = wsp->walk_addr; 2129 2130 if (addr == NULL) { 2131 mdb_warn("a dev_info struct address must be provided\n"); 2132 return (WALK_ERR); 2133 } 2134 2135 if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1) { 2136 mdb_warn("failed to read dev_info struct at %p", addr); 2137 return (WALK_ERR); 2138 } 2139 2140 wsp->walk_addr = (uintptr_t)di.devi_minor; 2141 return (WALK_NEXT); 2142 } 2143 2144 int 2145 minornode_walk_step(mdb_walk_state_t *wsp) 2146 { 2147 struct ddi_minor_data md; 2148 uintptr_t addr = wsp->walk_addr; 2149 2150 if (addr == NULL) 2151 return (WALK_DONE); 2152 2153 if (mdb_vread(&md, sizeof (md), addr) == -1) { 2154 mdb_warn("failed to read dev_info struct at %p", addr); 2155 return (WALK_DONE); 2156 } 2157 2158 wsp->walk_addr = (uintptr_t)md.next; 2159 return (wsp->walk_callback(addr, &md, wsp->walk_cbdata)); 2160 } 2161 2162 static const char *const md_type[] = { 2163 "DDI_MINOR", 2164 "DDI_ALIAS", 2165 "DDI_DEFAULT", 2166 "DDI_I_PATH", 2167 "?" 2168 }; 2169 2170 #define MD_TYPE_MAX ((sizeof (md_type) / sizeof (char *)) - 1) 2171 2172 /*ARGSUSED*/ 2173 static int 2174 print_minornode(uintptr_t addr, const void *arg, void *data) 2175 { 2176 char name[128]; 2177 char nodetype[128]; 2178 char *spectype; 2179 struct ddi_minor_data *mdp = (struct ddi_minor_data *)arg; 2180 2181 if (mdb_readstr(name, sizeof (name), (uintptr_t)mdp->ddm_name) == -1) 2182 *name = '\0'; 2183 2184 if (mdb_readstr(nodetype, sizeof (nodetype), 2185 (uintptr_t)mdp->ddm_node_type) == -1) 2186 *nodetype = '\0'; 2187 2188 switch (mdp->ddm_spec_type) { 2189 case S_IFCHR: spectype = "c"; break; 2190 case S_IFBLK: spectype = "b"; break; 2191 default: spectype = "?"; break; 2192 } 2193 2194 mdb_printf("%?p %16lx %-4s %-11s %-10s %s\n", 2195 addr, mdp->ddm_dev, spectype, md_type[MIN(mdp->type, MD_TYPE_MAX)], 2196 name, nodetype); 2197 2198 return (WALK_NEXT); 2199 } 2200 2201 /*ARGSUSED*/ 2202 int 2203 minornodes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2204 { 2205 if (!(flags & DCMD_ADDRSPEC) || argc != 0) 2206 return (DCMD_USAGE); 2207 2208 if (DCMD_HDRSPEC(flags)) 2209 mdb_printf("%<u>%?s %16s %-4s %-11s %-10s %-16s%</u>\n", 2210 "ADDR", "DEV", "SPEC", "TYPE", "NAME", "NODETYPE"); 2211 2212 if (mdb_pwalk("minornode", print_minornode, NULL, addr) == -1) { 2213 mdb_warn("can't walk minornode"); 2214 return (DCMD_ERR); 2215 } 2216 2217 return (DCMD_OK); 2218 } 2219