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