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