17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 552cac543Sramat * Common Development and Distribution License (the "License"). 652cac543Sramat * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*8451e9c3SGavin Maltby * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #include <sys/types.h> 267c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 277c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 287c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 297c478bd9Sstevel@tonic-gate #include <sys/ddifm.h> 307c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 317c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 327c478bd9Sstevel@tonic-gate #include <sys/hwconf.h> 337c478bd9Sstevel@tonic-gate #include <sys/stat.h> 347c478bd9Sstevel@tonic-gate #include <errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 367c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <ctype.h> 397c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 407c478bd9Sstevel@tonic-gate #include <mdb/mdb_ks.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include "nvpair.h" 4326947304SEvan Yan #include "devinfo.h" 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #define DEVINFO_TREE_INDENT 4 /* Indent for devs one down in tree */ 467c478bd9Sstevel@tonic-gate #define DEVINFO_PROP_INDENT 4 /* Indent for properties */ 477c478bd9Sstevel@tonic-gate #define DEVINFO_PROPLIST_INDENT 8 /* Indent for properties lists */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * devinfo node state map. Used by devinfo() and devinfo_audit(). 517c478bd9Sstevel@tonic-gate * Long words are deliberately truncated so that output 527c478bd9Sstevel@tonic-gate * fits in 80 column with 64-bit addresses. 537c478bd9Sstevel@tonic-gate */ 547c478bd9Sstevel@tonic-gate static const char *const di_state[] = { 557c478bd9Sstevel@tonic-gate "DS_INVAL", 567c478bd9Sstevel@tonic-gate "DS_PROTO", 577c478bd9Sstevel@tonic-gate "DS_LINKED", 587c478bd9Sstevel@tonic-gate "DS_BOUND", 597c478bd9Sstevel@tonic-gate "DS_INITIA", 607c478bd9Sstevel@tonic-gate "DS_PROBED", 617c478bd9Sstevel@tonic-gate "DS_ATTACH", 627c478bd9Sstevel@tonic-gate "DS_READY", 637c478bd9Sstevel@tonic-gate "?" 647c478bd9Sstevel@tonic-gate }; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #define DI_STATE_MAX ((sizeof (di_state) / sizeof (char *)) - 1) 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate void 697c478bd9Sstevel@tonic-gate prtconf_help(void) 707c478bd9Sstevel@tonic-gate { 717c478bd9Sstevel@tonic-gate mdb_printf("Prints the devinfo tree from a given node.\n" 727c478bd9Sstevel@tonic-gate "Without the address of a \"struct devinfo\" given, " 737c478bd9Sstevel@tonic-gate "prints from the root;\n" 747c478bd9Sstevel@tonic-gate "with an address, prints the parents of, " 757c478bd9Sstevel@tonic-gate "and all children of, that address.\n\n" 767c478bd9Sstevel@tonic-gate "Switches:\n" 777c478bd9Sstevel@tonic-gate " -v be verbose - print device property lists\n" 787c478bd9Sstevel@tonic-gate " -p only print the ancestors of the given node\n" 797c478bd9Sstevel@tonic-gate " -c only print the children of the given node\n"); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate void 837c478bd9Sstevel@tonic-gate devinfo_help(void) 847c478bd9Sstevel@tonic-gate { 857c478bd9Sstevel@tonic-gate mdb_printf("Switches:\n" 867c478bd9Sstevel@tonic-gate " -q be quiet - don't print device property lists\n" 877c478bd9Sstevel@tonic-gate " -s print summary of dev_info structures\n"); 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * Devinfo walker. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate typedef struct { 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * The "struct dev_info" must be the first thing in this structure. 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate struct dev_info din_dev; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * This is for the benefit of prtconf(). 1037c478bd9Sstevel@tonic-gate */ 1047c478bd9Sstevel@tonic-gate int din_depth; 1057c478bd9Sstevel@tonic-gate } devinfo_node_t; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate typedef struct devinfo_parents_walk_data { 1087c478bd9Sstevel@tonic-gate devinfo_node_t dip_node; 1097c478bd9Sstevel@tonic-gate #define dip_dev dip_node.din_dev 1107c478bd9Sstevel@tonic-gate #define dip_depth dip_node.din_depth 1117c478bd9Sstevel@tonic-gate struct dev_info *dip_end; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * The following three elements are for walking the parents of a node: 1157c478bd9Sstevel@tonic-gate * "dip_base_depth" is the depth of the given node from the root. 1167c478bd9Sstevel@tonic-gate * This starts at 1 (if we're walking devinfo_root), because 1177c478bd9Sstevel@tonic-gate * it's the size of the dip_parent_{nodes,addresses} arrays, 1187c478bd9Sstevel@tonic-gate * and has to include the given node. 1197c478bd9Sstevel@tonic-gate * "dip_parent_nodes" is a collection of the parent node structures, 1207c478bd9Sstevel@tonic-gate * already read in via mdb_vread(). dip_parent_nodes[0] is the 1217c478bd9Sstevel@tonic-gate * root, dip_parent_nodes[1] is a child of the root, etc. 1227c478bd9Sstevel@tonic-gate * "dip_parent_addresses" holds the vaddrs of all the parent nodes. 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate int dip_base_depth; 1257c478bd9Sstevel@tonic-gate devinfo_node_t *dip_parent_nodes; 1267c478bd9Sstevel@tonic-gate uintptr_t *dip_parent_addresses; 1277c478bd9Sstevel@tonic-gate } devinfo_parents_walk_data_t; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate int 1307c478bd9Sstevel@tonic-gate devinfo_parents_walk_init(mdb_walk_state_t *wsp) 1317c478bd9Sstevel@tonic-gate { 1327c478bd9Sstevel@tonic-gate devinfo_parents_walk_data_t *dip; 1337c478bd9Sstevel@tonic-gate uintptr_t addr; 13414ef2b2fSdmick uintptr_t devinfo_root; /* Address of root of devinfo tree */ 1357c478bd9Sstevel@tonic-gate int i; 1367c478bd9Sstevel@tonic-gate 13714ef2b2fSdmick if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) { 13814ef2b2fSdmick mdb_warn("failed to read 'top_devinfo'"); 13914ef2b2fSdmick return (NULL); 14014ef2b2fSdmick } 14114ef2b2fSdmick 1427c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 1437c478bd9Sstevel@tonic-gate wsp->walk_addr = devinfo_root; 1447c478bd9Sstevel@tonic-gate addr = wsp->walk_addr; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate dip = mdb_alloc(sizeof (devinfo_parents_walk_data_t), UM_SLEEP); 1477c478bd9Sstevel@tonic-gate wsp->walk_data = dip; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate dip->dip_end = (struct dev_info *)wsp->walk_addr; 1507c478bd9Sstevel@tonic-gate dip->dip_depth = 0; 1517c478bd9Sstevel@tonic-gate dip->dip_base_depth = 1; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate do { 1547c478bd9Sstevel@tonic-gate if (mdb_vread(&dip->dip_dev, sizeof (dip->dip_dev), 1557c478bd9Sstevel@tonic-gate addr) == -1) { 1567c478bd9Sstevel@tonic-gate mdb_warn("failed to read devinfo at %p", addr); 1577c478bd9Sstevel@tonic-gate mdb_free(dip, sizeof (devinfo_parents_walk_data_t)); 1587c478bd9Sstevel@tonic-gate wsp->walk_data = NULL; 1597c478bd9Sstevel@tonic-gate return (WALK_ERR); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate addr = (uintptr_t)dip->dip_dev.devi_parent; 1627c478bd9Sstevel@tonic-gate if (addr != 0) 1637c478bd9Sstevel@tonic-gate dip->dip_base_depth++; 1647c478bd9Sstevel@tonic-gate } while (addr != 0); 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate addr = wsp->walk_addr; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate dip->dip_parent_nodes = mdb_alloc( 1697c478bd9Sstevel@tonic-gate dip->dip_base_depth * sizeof (devinfo_node_t), UM_SLEEP); 1707c478bd9Sstevel@tonic-gate dip->dip_parent_addresses = mdb_alloc( 1717c478bd9Sstevel@tonic-gate dip->dip_base_depth * sizeof (uintptr_t), UM_SLEEP); 1727c478bd9Sstevel@tonic-gate for (i = dip->dip_base_depth - 1; i >= 0; i--) { 1737c478bd9Sstevel@tonic-gate if (mdb_vread(&dip->dip_parent_nodes[i].din_dev, 1747c478bd9Sstevel@tonic-gate sizeof (struct dev_info), addr) == -1) { 1757c478bd9Sstevel@tonic-gate mdb_warn("failed to read devinfo at %p", addr); 1767c478bd9Sstevel@tonic-gate return (WALK_ERR); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate dip->dip_parent_nodes[i].din_depth = i; 1797c478bd9Sstevel@tonic-gate dip->dip_parent_addresses[i] = addr; 1807c478bd9Sstevel@tonic-gate addr = (uintptr_t) 1817c478bd9Sstevel@tonic-gate dip->dip_parent_nodes[i].din_dev.devi_parent; 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate return (WALK_NEXT); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate int 1887c478bd9Sstevel@tonic-gate devinfo_parents_walk_step(mdb_walk_state_t *wsp) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate devinfo_parents_walk_data_t *dip = wsp->walk_data; 1917c478bd9Sstevel@tonic-gate int status; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate if (dip->dip_depth == dip->dip_base_depth) 1947c478bd9Sstevel@tonic-gate return (WALK_DONE); 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate status = wsp->walk_callback( 1977c478bd9Sstevel@tonic-gate dip->dip_parent_addresses[dip->dip_depth], 1987c478bd9Sstevel@tonic-gate &dip->dip_parent_nodes[dip->dip_depth], 1997c478bd9Sstevel@tonic-gate wsp->walk_cbdata); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate dip->dip_depth++; 2027c478bd9Sstevel@tonic-gate return (status); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate void 2067c478bd9Sstevel@tonic-gate devinfo_parents_walk_fini(mdb_walk_state_t *wsp) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate devinfo_parents_walk_data_t *dip = wsp->walk_data; 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate mdb_free(dip->dip_parent_nodes, 2117c478bd9Sstevel@tonic-gate dip->dip_base_depth * sizeof (devinfo_node_t)); 2127c478bd9Sstevel@tonic-gate mdb_free(dip->dip_parent_addresses, 2137c478bd9Sstevel@tonic-gate dip->dip_base_depth * sizeof (uintptr_t)); 2147c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (devinfo_parents_walk_data_t)); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate typedef struct devinfo_children_walk_data { 2197c478bd9Sstevel@tonic-gate devinfo_node_t dic_node; 2207c478bd9Sstevel@tonic-gate #define dic_dev dic_node.din_dev 2217c478bd9Sstevel@tonic-gate #define dic_depth dic_node.din_depth 2227c478bd9Sstevel@tonic-gate struct dev_info *dic_end; 2237c478bd9Sstevel@tonic-gate int dic_print_first_node; 2247c478bd9Sstevel@tonic-gate } devinfo_children_walk_data_t; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate int 2277c478bd9Sstevel@tonic-gate devinfo_children_walk_init(mdb_walk_state_t *wsp) 2287c478bd9Sstevel@tonic-gate { 2297c478bd9Sstevel@tonic-gate devinfo_children_walk_data_t *dic; 23014ef2b2fSdmick uintptr_t devinfo_root; /* Address of root of devinfo tree */ 23114ef2b2fSdmick 23214ef2b2fSdmick if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) { 23314ef2b2fSdmick mdb_warn("failed to read 'top_devinfo'"); 23414ef2b2fSdmick return (NULL); 23514ef2b2fSdmick } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 2387c478bd9Sstevel@tonic-gate wsp->walk_addr = devinfo_root; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate dic = mdb_alloc(sizeof (devinfo_children_walk_data_t), UM_SLEEP); 2417c478bd9Sstevel@tonic-gate wsp->walk_data = dic; 2427c478bd9Sstevel@tonic-gate dic->dic_end = (struct dev_info *)wsp->walk_addr; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* 2457c478bd9Sstevel@tonic-gate * This could be set by devinfo_walk_init(). 2467c478bd9Sstevel@tonic-gate */ 2477c478bd9Sstevel@tonic-gate if (wsp->walk_arg != NULL) { 2487c478bd9Sstevel@tonic-gate dic->dic_depth = (*(int *)wsp->walk_arg - 1); 2497c478bd9Sstevel@tonic-gate dic->dic_print_first_node = 0; 2507c478bd9Sstevel@tonic-gate } else { 2517c478bd9Sstevel@tonic-gate dic->dic_depth = 0; 2527c478bd9Sstevel@tonic-gate dic->dic_print_first_node = 1; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate return (WALK_NEXT); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate int 2597c478bd9Sstevel@tonic-gate devinfo_children_walk_step(mdb_walk_state_t *wsp) 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate devinfo_children_walk_data_t *dic = wsp->walk_data; 2627c478bd9Sstevel@tonic-gate struct dev_info *v; 2637c478bd9Sstevel@tonic-gate devinfo_node_t *cur; 2647c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 2657c478bd9Sstevel@tonic-gate int status = WALK_NEXT; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 2687c478bd9Sstevel@tonic-gate return (WALK_DONE); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate if (mdb_vread(&dic->dic_dev, sizeof (dic->dic_dev), addr) == -1) { 2717c478bd9Sstevel@tonic-gate mdb_warn("failed to read devinfo at %p", addr); 2727c478bd9Sstevel@tonic-gate return (WALK_DONE); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate cur = &dic->dic_node; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate if (dic->dic_print_first_node == 0) 2777c478bd9Sstevel@tonic-gate dic->dic_print_first_node = 1; 2787c478bd9Sstevel@tonic-gate else 2797c478bd9Sstevel@tonic-gate status = wsp->walk_callback(addr, cur, wsp->walk_cbdata); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * "v" is always a virtual address pointer, 2837c478bd9Sstevel@tonic-gate * i.e. can't be deref'ed. 2847c478bd9Sstevel@tonic-gate */ 2857c478bd9Sstevel@tonic-gate v = (struct dev_info *)addr; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate if (dic->dic_dev.devi_child != NULL) { 2887c478bd9Sstevel@tonic-gate v = dic->dic_dev.devi_child; 2897c478bd9Sstevel@tonic-gate dic->dic_depth++; 2907c478bd9Sstevel@tonic-gate } else if (dic->dic_dev.devi_sibling != NULL && v != dic->dic_end) { 2917c478bd9Sstevel@tonic-gate v = dic->dic_dev.devi_sibling; 2927c478bd9Sstevel@tonic-gate } else { 2937c478bd9Sstevel@tonic-gate while (v != NULL && v != dic->dic_end && 2947c478bd9Sstevel@tonic-gate dic->dic_dev.devi_sibling == NULL) { 2957c478bd9Sstevel@tonic-gate v = dic->dic_dev.devi_parent; 2967c478bd9Sstevel@tonic-gate if (v == NULL) 2977c478bd9Sstevel@tonic-gate break; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate mdb_vread(&dic->dic_dev, 3007c478bd9Sstevel@tonic-gate sizeof (struct dev_info), (uintptr_t)v); 3017c478bd9Sstevel@tonic-gate dic->dic_depth--; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate if (v != NULL && v != dic->dic_end) 3047c478bd9Sstevel@tonic-gate v = dic->dic_dev.devi_sibling; 3057c478bd9Sstevel@tonic-gate if (v == dic->dic_end) 3067c478bd9Sstevel@tonic-gate v = NULL; /* Done */ 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)v; 3107c478bd9Sstevel@tonic-gate return (status); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate void 3147c478bd9Sstevel@tonic-gate devinfo_children_walk_fini(mdb_walk_state_t *wsp) 3157c478bd9Sstevel@tonic-gate { 3167c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (devinfo_children_walk_data_t)); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate typedef struct devinfo_walk_data { 3207c478bd9Sstevel@tonic-gate mdb_walk_state_t diw_parent, diw_child; 3217c478bd9Sstevel@tonic-gate enum { DIW_PARENT, DIW_CHILD, DIW_DONE } diw_mode; 3227c478bd9Sstevel@tonic-gate } devinfo_walk_data_t; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate int 3257c478bd9Sstevel@tonic-gate devinfo_walk_init(mdb_walk_state_t *wsp) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate devinfo_walk_data_t *diw; 3287c478bd9Sstevel@tonic-gate devinfo_parents_walk_data_t *dip; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate diw = mdb_alloc(sizeof (devinfo_walk_data_t), UM_SLEEP); 3317c478bd9Sstevel@tonic-gate diw->diw_parent = *wsp; 3327c478bd9Sstevel@tonic-gate diw->diw_child = *wsp; 3337c478bd9Sstevel@tonic-gate wsp->walk_data = diw; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate diw->diw_mode = DIW_PARENT; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (devinfo_parents_walk_init(&diw->diw_parent) == -1) { 3387c478bd9Sstevel@tonic-gate mdb_free(diw, sizeof (devinfo_walk_data_t)); 3397c478bd9Sstevel@tonic-gate return (WALK_ERR); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * This is why the "devinfo" walker needs to be marginally 3447c478bd9Sstevel@tonic-gate * complicated - the child walker needs this initialization 3457c478bd9Sstevel@tonic-gate * data, and the best way to get it is out of the parent walker. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate dip = diw->diw_parent.walk_data; 3487c478bd9Sstevel@tonic-gate diw->diw_child.walk_arg = &dip->dip_base_depth; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate if (devinfo_children_walk_init(&diw->diw_child) == -1) { 3517c478bd9Sstevel@tonic-gate devinfo_parents_walk_fini(&diw->diw_parent); 3527c478bd9Sstevel@tonic-gate mdb_free(diw, sizeof (devinfo_walk_data_t)); 3537c478bd9Sstevel@tonic-gate return (WALK_ERR); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate return (WALK_NEXT); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate int 3607c478bd9Sstevel@tonic-gate devinfo_walk_step(mdb_walk_state_t *wsp) 3617c478bd9Sstevel@tonic-gate { 3627c478bd9Sstevel@tonic-gate devinfo_walk_data_t *diw = wsp->walk_data; 3637c478bd9Sstevel@tonic-gate int status = WALK_NEXT; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if (diw->diw_mode == DIW_PARENT) { 3667c478bd9Sstevel@tonic-gate status = devinfo_parents_walk_step(&diw->diw_parent); 3677c478bd9Sstevel@tonic-gate if (status != WALK_NEXT) { 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Keep on going even if the parents walk hit an error. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate diw->diw_mode = DIW_CHILD; 3727c478bd9Sstevel@tonic-gate status = WALK_NEXT; 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate } else if (diw->diw_mode == DIW_CHILD) { 3757c478bd9Sstevel@tonic-gate status = devinfo_children_walk_step(&diw->diw_child); 3767c478bd9Sstevel@tonic-gate if (status != WALK_NEXT) { 3777c478bd9Sstevel@tonic-gate diw->diw_mode = DIW_DONE; 3787c478bd9Sstevel@tonic-gate status = WALK_DONE; 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate } else 3817c478bd9Sstevel@tonic-gate status = WALK_DONE; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate return (status); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate void 3877c478bd9Sstevel@tonic-gate devinfo_walk_fini(mdb_walk_state_t *wsp) 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate devinfo_walk_data_t *diw = wsp->walk_data; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate devinfo_children_walk_fini(&diw->diw_child); 3927c478bd9Sstevel@tonic-gate devinfo_parents_walk_fini(&diw->diw_parent); 3937c478bd9Sstevel@tonic-gate mdb_free(diw, sizeof (devinfo_walk_data_t)); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * Given a devinfo pointer, figure out which driver is associated 3987c478bd9Sstevel@tonic-gate * with the node (by driver name, from the devnames array). 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4017c478bd9Sstevel@tonic-gate int 4027c478bd9Sstevel@tonic-gate devinfo2driver(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate char dname[MODMAXNAMELEN + 1]; 4057c478bd9Sstevel@tonic-gate struct dev_info devi; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 4097c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (mdb_vread(&devi, sizeof (devi), addr) == -1) { 4127c478bd9Sstevel@tonic-gate mdb_warn("failed to read devinfo struct at %p", addr); 4137c478bd9Sstevel@tonic-gate return (DCMD_ERR); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 416f723faa1Seschrock if (devi.devi_node_state < DS_ATTACHED) { 4177c478bd9Sstevel@tonic-gate /* No driver attached to this devinfo - nothing to do. */ 4187c478bd9Sstevel@tonic-gate mdb_warn("%p: No driver attached to this devinfo node\n", addr); 4197c478bd9Sstevel@tonic-gate return (DCMD_ERR); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0) { 4237c478bd9Sstevel@tonic-gate mdb_warn("failed to determine driver name"); 4247c478bd9Sstevel@tonic-gate return (DCMD_ERR); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate mdb_printf("Driver '%s' is associated with devinfo %p.\n", dname, addr); 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate return (DCMD_OK); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate typedef struct devnames_walk { 4347c478bd9Sstevel@tonic-gate struct devnames *dnw_names; 4357c478bd9Sstevel@tonic-gate int dnw_ndx; 4367c478bd9Sstevel@tonic-gate int dnw_devcnt; 4377c478bd9Sstevel@tonic-gate uintptr_t dnw_base; 4387c478bd9Sstevel@tonic-gate uintptr_t dnw_size; 4397c478bd9Sstevel@tonic-gate } devnames_walk_t; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate int 4427c478bd9Sstevel@tonic-gate devnames_walk_init(mdb_walk_state_t *wsp) 4437c478bd9Sstevel@tonic-gate { 4447c478bd9Sstevel@tonic-gate devnames_walk_t *dnw; 4457c478bd9Sstevel@tonic-gate int devcnt; 4467c478bd9Sstevel@tonic-gate uintptr_t devnamesp; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate if (wsp->walk_addr != NULL) { 4497c478bd9Sstevel@tonic-gate mdb_warn("devnames walker only supports global walks\n"); 4507c478bd9Sstevel@tonic-gate return (WALK_ERR); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate if (mdb_readvar(&devcnt, "devcnt") == -1) { 4547c478bd9Sstevel@tonic-gate mdb_warn("failed to read 'devcnt'"); 4557c478bd9Sstevel@tonic-gate return (WALK_ERR); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate if (mdb_readvar(&devnamesp, "devnamesp") == -1) { 4597c478bd9Sstevel@tonic-gate mdb_warn("failed to read 'devnamesp'"); 4607c478bd9Sstevel@tonic-gate return (WALK_ERR); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate dnw = mdb_zalloc(sizeof (devnames_walk_t), UM_SLEEP); 4647c478bd9Sstevel@tonic-gate dnw->dnw_size = sizeof (struct devnames) * devcnt; 4657c478bd9Sstevel@tonic-gate dnw->dnw_devcnt = devcnt; 4667c478bd9Sstevel@tonic-gate dnw->dnw_base = devnamesp; 4677c478bd9Sstevel@tonic-gate dnw->dnw_names = mdb_alloc(dnw->dnw_size, UM_SLEEP); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (mdb_vread(dnw->dnw_names, dnw->dnw_size, dnw->dnw_base) == -1) { 4707c478bd9Sstevel@tonic-gate mdb_warn("couldn't read devnames array at %p", devnamesp); 4717c478bd9Sstevel@tonic-gate return (WALK_ERR); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate wsp->walk_data = dnw; 4757c478bd9Sstevel@tonic-gate return (WALK_NEXT); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate int 4797c478bd9Sstevel@tonic-gate devnames_walk_step(mdb_walk_state_t *wsp) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate devnames_walk_t *dnw = wsp->walk_data; 4827c478bd9Sstevel@tonic-gate int status; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate if (dnw->dnw_ndx == dnw->dnw_devcnt) 4857c478bd9Sstevel@tonic-gate return (WALK_DONE); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate status = wsp->walk_callback(dnw->dnw_ndx * sizeof (struct devnames) + 4887c478bd9Sstevel@tonic-gate dnw->dnw_base, &dnw->dnw_names[dnw->dnw_ndx], wsp->walk_cbdata); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate dnw->dnw_ndx++; 4917c478bd9Sstevel@tonic-gate return (status); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate void 4957c478bd9Sstevel@tonic-gate devnames_walk_fini(mdb_walk_state_t *wsp) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate devnames_walk_t *dnw = wsp->walk_data; 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate mdb_free(dnw->dnw_names, dnw->dnw_size); 5007c478bd9Sstevel@tonic-gate mdb_free(dnw, sizeof (devnames_walk_t)); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate int 5047c478bd9Sstevel@tonic-gate devinfo_siblings_walk_init(mdb_walk_state_t *wsp) 5057c478bd9Sstevel@tonic-gate { 5067c478bd9Sstevel@tonic-gate struct dev_info di; 5077c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if (addr == NULL) { 5107c478bd9Sstevel@tonic-gate mdb_warn("a dev_info struct address must be provided\n"); 5117c478bd9Sstevel@tonic-gate return (WALK_ERR); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate if (mdb_vread(&di, sizeof (di), addr) == -1) { 5157c478bd9Sstevel@tonic-gate mdb_warn("failed to read dev_info struct at %p", addr); 5167c478bd9Sstevel@tonic-gate return (WALK_ERR); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate if (di.devi_parent == NULL) { 5207c478bd9Sstevel@tonic-gate mdb_warn("no parent for devinfo at %p", addr); 5217c478bd9Sstevel@tonic-gate return (WALK_DONE); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate if (mdb_vread(&di, sizeof (di), (uintptr_t)di.devi_parent) == -1) { 5257c478bd9Sstevel@tonic-gate mdb_warn("failed to read parent dev_info struct at %p", 5267c478bd9Sstevel@tonic-gate (uintptr_t)di.devi_parent); 5277c478bd9Sstevel@tonic-gate return (WALK_ERR); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)di.devi_child; 5317c478bd9Sstevel@tonic-gate return (WALK_NEXT); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate int 5357c478bd9Sstevel@tonic-gate devinfo_siblings_walk_step(mdb_walk_state_t *wsp) 5367c478bd9Sstevel@tonic-gate { 5377c478bd9Sstevel@tonic-gate struct dev_info di; 5387c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate if (addr == NULL) 5417c478bd9Sstevel@tonic-gate return (WALK_DONE); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate if (mdb_vread(&di, sizeof (di), addr) == -1) { 5447c478bd9Sstevel@tonic-gate mdb_warn("failed to read dev_info struct at %p", addr); 5457c478bd9Sstevel@tonic-gate return (WALK_DONE); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)di.devi_sibling; 5497c478bd9Sstevel@tonic-gate return (wsp->walk_callback(addr, &di, wsp->walk_cbdata)); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate int 5537c478bd9Sstevel@tonic-gate devi_next_walk_step(mdb_walk_state_t *wsp) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate struct dev_info di; 5567c478bd9Sstevel@tonic-gate int status; 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 5597c478bd9Sstevel@tonic-gate return (WALK_DONE); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1) 5627c478bd9Sstevel@tonic-gate return (WALK_DONE); 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &di, wsp->walk_cbdata); 5657c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)di.devi_next; 5667c478bd9Sstevel@tonic-gate return (status); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * Helper functions. 5717c478bd9Sstevel@tonic-gate */ 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate static int 5747c478bd9Sstevel@tonic-gate is_printable_string(unsigned char *prop_value) 5757c478bd9Sstevel@tonic-gate { 5767c478bd9Sstevel@tonic-gate while (*prop_value != 0) 5777c478bd9Sstevel@tonic-gate if (!isprint(*prop_value++)) 5787c478bd9Sstevel@tonic-gate return (0); 5797c478bd9Sstevel@tonic-gate return (1); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate static void 5837c478bd9Sstevel@tonic-gate devinfo_print_props_type(int type) { 5847c478bd9Sstevel@tonic-gate char *type_str = NULL; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate switch (type) { 5877c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_ANY: 5887c478bd9Sstevel@tonic-gate type_str = "any"; 5897c478bd9Sstevel@tonic-gate break; 5907c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_COMPOSITE: 5917c478bd9Sstevel@tonic-gate type_str = "composite"; 5927c478bd9Sstevel@tonic-gate break; 5937c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_INT64: 5947c478bd9Sstevel@tonic-gate type_str = "int64"; 5957c478bd9Sstevel@tonic-gate break; 5967c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_INT: 5977c478bd9Sstevel@tonic-gate type_str = "int"; 5987c478bd9Sstevel@tonic-gate break; 5997c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_BYTE: 6007c478bd9Sstevel@tonic-gate type_str = "byte"; 6017c478bd9Sstevel@tonic-gate break; 6027c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_STRING: 6037c478bd9Sstevel@tonic-gate type_str = "string"; 6047c478bd9Sstevel@tonic-gate break; 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate if (type_str != NULL) 6087c478bd9Sstevel@tonic-gate mdb_printf("type=%s", type_str); 6097c478bd9Sstevel@tonic-gate else 6107c478bd9Sstevel@tonic-gate mdb_printf("type=0x%x", type); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate static void 6147c478bd9Sstevel@tonic-gate devinfo_print_props_value(int elem_size, int nelem, 6157c478bd9Sstevel@tonic-gate unsigned char *prop_value, int prop_value_len) 6167c478bd9Sstevel@tonic-gate { 6177c478bd9Sstevel@tonic-gate int i; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate mdb_printf("value="); 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate if (elem_size == 0) { 6227c478bd9Sstevel@tonic-gate /* if elem_size == 0, then we are printing out string(s) */ 6237c478bd9Sstevel@tonic-gate char *p = (char *)prop_value; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate for (i = 0; i < nelem - 1; i++) { 6267c478bd9Sstevel@tonic-gate mdb_printf("'%s' + ", p); 6277c478bd9Sstevel@tonic-gate p += strlen(p) + 1; 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate mdb_printf("'%s'", p); 6307c478bd9Sstevel@tonic-gate } else { 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * if elem_size != 0 then we are printing out an array 6337c478bd9Sstevel@tonic-gate * where each element is of elem_size 6347c478bd9Sstevel@tonic-gate */ 6357c478bd9Sstevel@tonic-gate mdb_nhconvert(prop_value, prop_value, elem_size); 6367c478bd9Sstevel@tonic-gate mdb_printf("%02x", *prop_value); 6377c478bd9Sstevel@tonic-gate for (i = 1; i < prop_value_len; i++) { 6387c478bd9Sstevel@tonic-gate if ((i % elem_size) == 0) { 6397c478bd9Sstevel@tonic-gate mdb_nhconvert(&prop_value[i], 6407c478bd9Sstevel@tonic-gate &prop_value[i], elem_size); 6417c478bd9Sstevel@tonic-gate mdb_printf("."); 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate mdb_printf("%02x", prop_value[i]); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * devinfo_print_props_guess() 6517c478bd9Sstevel@tonic-gate * Guesses how to interpret the value of the property 6527c478bd9Sstevel@tonic-gate * 6537c478bd9Sstevel@tonic-gate * Params: 6547c478bd9Sstevel@tonic-gate * type - Should be the type value of the property 6557c478bd9Sstevel@tonic-gate * prop_val - Pointer to the property value data buffer 6567c478bd9Sstevel@tonic-gate * prop_len - Length of the property value data buffer 6577c478bd9Sstevel@tonic-gate * 6587c478bd9Sstevel@tonic-gate * Return values: 6597c478bd9Sstevel@tonic-gate * nelem - The number of elements stored in the property value 6607c478bd9Sstevel@tonic-gate * data buffer pointed to by prop_val. 6617c478bd9Sstevel@tonic-gate * elem_size - The size (in bytes) of the elements stored in the property 6627c478bd9Sstevel@tonic-gate * value data buffer pointed to by prop_val. 6637c478bd9Sstevel@tonic-gate * Upon return if elem_size == 0 and nelem != 0 then 6647c478bd9Sstevel@tonic-gate * the property value data buffer contains strings 6657c478bd9Sstevel@tonic-gate * len_err - There was an error with the length of the data buffer. 6667c478bd9Sstevel@tonic-gate * Its size is not a multiple of the array value type. 6677c478bd9Sstevel@tonic-gate * It will be interpreted as an array of bytes. 6687c478bd9Sstevel@tonic-gate */ 6697c478bd9Sstevel@tonic-gate static void 6707c478bd9Sstevel@tonic-gate devinfo_print_props_guess(int type, unsigned char *prop_val, int prop_len, 6717c478bd9Sstevel@tonic-gate int *elem_size, int *nelem, int *len_err) 6727c478bd9Sstevel@tonic-gate { 6737c478bd9Sstevel@tonic-gate *len_err = 0; 6747c478bd9Sstevel@tonic-gate if (prop_len == NULL) { 6757c478bd9Sstevel@tonic-gate *elem_size = 0; 6767c478bd9Sstevel@tonic-gate *nelem = 0; 6777c478bd9Sstevel@tonic-gate return; 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* by default, assume an array of bytes */ 6817c478bd9Sstevel@tonic-gate *elem_size = 1; 6827c478bd9Sstevel@tonic-gate *nelem = prop_len; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate switch (type) { 6857c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_BYTE: 6867c478bd9Sstevel@tonic-gate /* default case, that was easy */ 6877c478bd9Sstevel@tonic-gate break; 6887c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_INT64: 6897c478bd9Sstevel@tonic-gate if ((prop_len % sizeof (int64_t)) == 0) { 6907c478bd9Sstevel@tonic-gate *elem_size = sizeof (int64_t); 6917c478bd9Sstevel@tonic-gate *nelem = prop_len / *elem_size; 6927c478bd9Sstevel@tonic-gate } else { 6937c478bd9Sstevel@tonic-gate /* array is not a multiple of type size, error */ 6947c478bd9Sstevel@tonic-gate *len_err = 1; 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate break; 6977c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_INT: 6987c478bd9Sstevel@tonic-gate if ((prop_len % sizeof (int)) == 0) { 6997c478bd9Sstevel@tonic-gate *elem_size = sizeof (int); 7007c478bd9Sstevel@tonic-gate *nelem = prop_len / *elem_size; 7017c478bd9Sstevel@tonic-gate } else { 7027c478bd9Sstevel@tonic-gate /* array is not a multiple of type size, error */ 7037c478bd9Sstevel@tonic-gate *len_err = 1; 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate break; 7067c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_STRING: 7077c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_COMPOSITE: 7087c478bd9Sstevel@tonic-gate case DDI_PROP_TYPE_ANY: 7097c478bd9Sstevel@tonic-gate default: 7107c478bd9Sstevel@tonic-gate /* 7117c478bd9Sstevel@tonic-gate * if we made it here the type is either unknown 7127c478bd9Sstevel@tonic-gate * or a string. Try to interpret is as a string 7137c478bd9Sstevel@tonic-gate * and if that fails assume an array of bytes. 7147c478bd9Sstevel@tonic-gate */ 7157c478bd9Sstevel@tonic-gate if (prop_val[prop_len - 1] == '\0') { 7167c478bd9Sstevel@tonic-gate unsigned char *s = prop_val; 7177c478bd9Sstevel@tonic-gate int i; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* assume an array of strings */ 7207c478bd9Sstevel@tonic-gate *elem_size = 0; 7217c478bd9Sstevel@tonic-gate *nelem = 0; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate for (i = 0; i < prop_len; i++) { 7247c478bd9Sstevel@tonic-gate if (prop_val[i] != '\0') 7257c478bd9Sstevel@tonic-gate continue; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* 7287c478bd9Sstevel@tonic-gate * If the property is typed as a string 7297c478bd9Sstevel@tonic-gate * property, then interpret empty strings 7307c478bd9Sstevel@tonic-gate * as strings. Otherwise default to an 7317c478bd9Sstevel@tonic-gate * array of bytes. If there are unprintable 7327c478bd9Sstevel@tonic-gate * characters, always default to an array of 7337c478bd9Sstevel@tonic-gate * bytes. 7347c478bd9Sstevel@tonic-gate */ 7357c478bd9Sstevel@tonic-gate if ((*s == '\0' && type != 7367c478bd9Sstevel@tonic-gate DDI_PROP_TYPE_STRING) || 7377c478bd9Sstevel@tonic-gate !is_printable_string(s)) { 7387c478bd9Sstevel@tonic-gate *elem_size = 1; 7397c478bd9Sstevel@tonic-gate *nelem = prop_len; 7407c478bd9Sstevel@tonic-gate break; 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate (*nelem)++; 7447c478bd9Sstevel@tonic-gate s = &prop_val[i + 1]; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate break; 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate static void 7527c478bd9Sstevel@tonic-gate devinfo_print_props(char *name, ddi_prop_t *p) 7537c478bd9Sstevel@tonic-gate { 7547c478bd9Sstevel@tonic-gate if (p == NULL) 7557c478bd9Sstevel@tonic-gate return; 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate if (name != NULL) 7587c478bd9Sstevel@tonic-gate mdb_printf("%s ", name); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate mdb_printf("properties at %p:\n", p); 7617c478bd9Sstevel@tonic-gate mdb_inc_indent(DEVINFO_PROP_INDENT); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate while (p != NULL) { 7647c478bd9Sstevel@tonic-gate ddi_prop_t prop; 7657c478bd9Sstevel@tonic-gate char prop_name[128]; 7667c478bd9Sstevel@tonic-gate unsigned char *prop_value; 7677c478bd9Sstevel@tonic-gate int type, elem_size, nelem, prop_len_error; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate /* read in the property struct */ 7707c478bd9Sstevel@tonic-gate if (mdb_vread(&prop, sizeof (prop), (uintptr_t)p) == -1) { 7717c478bd9Sstevel@tonic-gate mdb_warn("could not read property at 0x%p", p); 7727c478bd9Sstevel@tonic-gate break; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate /* print the property name */ 7767c478bd9Sstevel@tonic-gate if (mdb_readstr(prop_name, sizeof (prop_name), 7777c478bd9Sstevel@tonic-gate (uintptr_t)prop.prop_name) == -1) { 7787c478bd9Sstevel@tonic-gate mdb_warn("could not read property name at 0x%p", 7797c478bd9Sstevel@tonic-gate prop.prop_name); 7807c478bd9Sstevel@tonic-gate goto next; 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate mdb_printf("name='%s' ", prop_name); 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate /* get the property type and print it out */ 7857c478bd9Sstevel@tonic-gate type = (prop.prop_flags & DDI_PROP_TYPE_MASK); 7867c478bd9Sstevel@tonic-gate devinfo_print_props_type(type); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* get the property value */ 7897c478bd9Sstevel@tonic-gate if (prop.prop_len > 0) { 7907c478bd9Sstevel@tonic-gate prop_value = mdb_alloc(prop.prop_len, UM_SLEEP|UM_GC); 7917c478bd9Sstevel@tonic-gate if (mdb_vread(prop_value, prop.prop_len, 7927c478bd9Sstevel@tonic-gate (uintptr_t)prop.prop_val) == -1) { 7937c478bd9Sstevel@tonic-gate mdb_warn("could not read property value at " 7947c478bd9Sstevel@tonic-gate "0x%p", prop.prop_val); 7957c478bd9Sstevel@tonic-gate goto next; 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate } else { 7987c478bd9Sstevel@tonic-gate prop_value = NULL; 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* take a guess at interpreting the property value */ 8027c478bd9Sstevel@tonic-gate devinfo_print_props_guess(type, prop_value, prop.prop_len, 8037c478bd9Sstevel@tonic-gate &elem_size, &nelem, &prop_len_error); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* print out the number ot items */ 8067c478bd9Sstevel@tonic-gate mdb_printf(" items=%d", nelem); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate /* print out any associated device information */ 8097c478bd9Sstevel@tonic-gate if (prop.prop_dev != DDI_DEV_T_NONE) { 8107c478bd9Sstevel@tonic-gate mdb_printf(" dev="); 8117c478bd9Sstevel@tonic-gate if (prop.prop_dev == DDI_DEV_T_ANY) 8127c478bd9Sstevel@tonic-gate mdb_printf("any"); 8137c478bd9Sstevel@tonic-gate else if (prop.prop_dev == DDI_MAJOR_T_UNKNOWN) 8147c478bd9Sstevel@tonic-gate mdb_printf("unknown"); 8157c478bd9Sstevel@tonic-gate else 8167c478bd9Sstevel@tonic-gate mdb_printf("(%u,%u)", 8177c478bd9Sstevel@tonic-gate getmajor(prop.prop_dev), 8187c478bd9Sstevel@tonic-gate getminor(prop.prop_dev)); 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate /* print out the property value */ 8227c478bd9Sstevel@tonic-gate if (prop_value != NULL) { 8237c478bd9Sstevel@tonic-gate mdb_printf("\n"); 8247c478bd9Sstevel@tonic-gate mdb_inc_indent(DEVINFO_PROP_INDENT); 8257c478bd9Sstevel@tonic-gate if (prop_len_error) 8267c478bd9Sstevel@tonic-gate mdb_printf("NOTE: prop length is not a " 8277c478bd9Sstevel@tonic-gate "multiple of element size\n"); 8287c478bd9Sstevel@tonic-gate devinfo_print_props_value(elem_size, nelem, 8297c478bd9Sstevel@tonic-gate prop_value, prop.prop_len); 8307c478bd9Sstevel@tonic-gate mdb_dec_indent(DEVINFO_PROP_INDENT); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate next: 8347c478bd9Sstevel@tonic-gate mdb_printf("\n"); 8357c478bd9Sstevel@tonic-gate p = prop.prop_next; 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate mdb_dec_indent(DEVINFO_PROP_INDENT); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate static void 8427c478bd9Sstevel@tonic-gate devinfo_pathinfo_state(mdi_pathinfo_state_t state) { 8437c478bd9Sstevel@tonic-gate char *type_str = NULL; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate switch (state) { 8467c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_INIT: 8477c478bd9Sstevel@tonic-gate type_str = "init"; 8487c478bd9Sstevel@tonic-gate break; 8497c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_ONLINE: 8507c478bd9Sstevel@tonic-gate type_str = "online"; 8517c478bd9Sstevel@tonic-gate break; 8527c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_STANDBY: 8537c478bd9Sstevel@tonic-gate type_str = "standby"; 8547c478bd9Sstevel@tonic-gate break; 8557c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_FAULT: 8567c478bd9Sstevel@tonic-gate type_str = "fault"; 8577c478bd9Sstevel@tonic-gate break; 8587c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_OFFLINE: 8597c478bd9Sstevel@tonic-gate type_str = "offline"; 8607c478bd9Sstevel@tonic-gate break; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate if (type_str != NULL) 8637c478bd9Sstevel@tonic-gate mdb_printf("state=%s\n", type_str); 8647c478bd9Sstevel@tonic-gate else 8657c478bd9Sstevel@tonic-gate mdb_printf("state=0x%x\n", state); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate static void 8697c478bd9Sstevel@tonic-gate devinfo_print_pathing(int mdi_component, void *mdi_client) { 8707c478bd9Sstevel@tonic-gate mdi_client_t mdi_c; 8717c478bd9Sstevel@tonic-gate struct mdi_pathinfo *pip; 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate /* we only print out multipathing info for client nodes */ 8747c478bd9Sstevel@tonic-gate if ((mdi_component & MDI_COMPONENT_CLIENT) == 0) 8757c478bd9Sstevel@tonic-gate return; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate mdb_printf("Client multipath info at: 0x%p\n", mdi_client); 8787c478bd9Sstevel@tonic-gate mdb_inc_indent(DEVINFO_PROP_INDENT); 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate /* read in the client multipathing info */ 8817c478bd9Sstevel@tonic-gate if (mdb_readstr((void*) &mdi_c, sizeof (mdi_c), 8827c478bd9Sstevel@tonic-gate (uintptr_t)mdi_client) == -1) { 8837c478bd9Sstevel@tonic-gate mdb_warn("failed to read mdi_client at %p", 8847c478bd9Sstevel@tonic-gate (uintptr_t)mdi_client); 8857c478bd9Sstevel@tonic-gate goto exit; 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate /* 8897c478bd9Sstevel@tonic-gate * walk through the clients list of pathinfo structures and print 8907c478bd9Sstevel@tonic-gate * out the properties for each path 8917c478bd9Sstevel@tonic-gate */ 8927c478bd9Sstevel@tonic-gate pip = (struct mdi_pathinfo *)mdi_c.ct_path_head; 8937c478bd9Sstevel@tonic-gate while (pip != NULL) { 8947c478bd9Sstevel@tonic-gate char binding_name[128]; 8957c478bd9Sstevel@tonic-gate struct mdi_pathinfo pi; 8967c478bd9Sstevel@tonic-gate mdi_phci_t ph; 8977c478bd9Sstevel@tonic-gate struct dev_info ph_di; 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate /* read in the pathinfo structure */ 9007c478bd9Sstevel@tonic-gate if (mdb_vread((void*)&pi, sizeof (pi), 9017c478bd9Sstevel@tonic-gate (uintptr_t)pip) == -1) { 9027c478bd9Sstevel@tonic-gate mdb_warn("failed to read mdi_pathinfo at %p", 9037c478bd9Sstevel@tonic-gate (uintptr_t)pip); 9047c478bd9Sstevel@tonic-gate goto exit; 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* read in the pchi (path host adapter) info */ 9087c478bd9Sstevel@tonic-gate if (mdb_vread((void*)&ph, sizeof (ph), 9097c478bd9Sstevel@tonic-gate (uintptr_t)pi.pi_phci) == -1) { 9107c478bd9Sstevel@tonic-gate mdb_warn("failed to read mdi_pchi at %p", 9117c478bd9Sstevel@tonic-gate (uintptr_t)pi.pi_phci); 9127c478bd9Sstevel@tonic-gate goto exit; 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate /* read in the dip of the phci so we can get it's name */ 9167c478bd9Sstevel@tonic-gate if (mdb_vread((void*)&ph_di, sizeof (ph_di), 9177c478bd9Sstevel@tonic-gate (uintptr_t)ph.ph_dip) == -1) { 9187c478bd9Sstevel@tonic-gate mdb_warn("failed to read mdi_pchi at %p", 9197c478bd9Sstevel@tonic-gate (uintptr_t)ph.ph_dip); 9207c478bd9Sstevel@tonic-gate goto exit; 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate if (mdb_vread(binding_name, sizeof (binding_name), 9237c478bd9Sstevel@tonic-gate (uintptr_t)ph_di.devi_binding_name) == -1) { 9247c478bd9Sstevel@tonic-gate mdb_warn("failed to read binding_name at %p", 9257c478bd9Sstevel@tonic-gate (uintptr_t)ph_di.devi_binding_name); 9267c478bd9Sstevel@tonic-gate goto exit; 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate mdb_printf("%s#%d, ", binding_name, ph_di.devi_instance); 9307c478bd9Sstevel@tonic-gate devinfo_pathinfo_state(pi.pi_state); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate /* print out the pathing info */ 9337c478bd9Sstevel@tonic-gate mdb_inc_indent(DEVINFO_PROP_INDENT); 9347c478bd9Sstevel@tonic-gate if (mdb_pwalk_dcmd(NVPAIR_WALKER_FQNAME, NVPAIR_DCMD_FQNAME, 9357c478bd9Sstevel@tonic-gate 0, NULL, (uintptr_t)pi.pi_prop) != 0) { 9367c478bd9Sstevel@tonic-gate mdb_dec_indent(DEVINFO_PROP_INDENT); 9377c478bd9Sstevel@tonic-gate goto exit; 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate mdb_dec_indent(DEVINFO_PROP_INDENT); 9407c478bd9Sstevel@tonic-gate pip = pi.pi_client_link; 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate exit: 9447c478bd9Sstevel@tonic-gate mdb_dec_indent(DEVINFO_PROP_INDENT); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate static int 9487c478bd9Sstevel@tonic-gate devinfo_print(uintptr_t addr, struct dev_info *dev, devinfo_cb_data_t *data) 9497c478bd9Sstevel@tonic-gate { 9507c478bd9Sstevel@tonic-gate /* 9517c478bd9Sstevel@tonic-gate * We know the walker passes us extra data after the dev_info. 9527c478bd9Sstevel@tonic-gate */ 9537c478bd9Sstevel@tonic-gate char binding_name[128]; 954f723faa1Seschrock char dname[MODMAXNAMELEN + 1]; 9557c478bd9Sstevel@tonic-gate devinfo_node_t *din = (devinfo_node_t *)dev; 9567c478bd9Sstevel@tonic-gate ddi_prop_t *global_props = NULL; 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (mdb_readstr(binding_name, sizeof (binding_name), 9597c478bd9Sstevel@tonic-gate (uintptr_t)dev->devi_binding_name) == -1) { 9607c478bd9Sstevel@tonic-gate mdb_warn("failed to read binding_name at %p", 9617c478bd9Sstevel@tonic-gate (uintptr_t)dev->devi_binding_name); 9627c478bd9Sstevel@tonic-gate return (WALK_ERR); 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* if there are any global properties, get a pointer to them */ 9667c478bd9Sstevel@tonic-gate if (dev->devi_global_prop_list != NULL) { 9677c478bd9Sstevel@tonic-gate ddi_prop_list_t plist; 9687c478bd9Sstevel@tonic-gate if (mdb_vread((void*)&plist, sizeof (plist), 9697c478bd9Sstevel@tonic-gate (uintptr_t)dev->devi_global_prop_list) == -1) { 9707c478bd9Sstevel@tonic-gate mdb_warn("failed to read global prop_list at %p", 9717c478bd9Sstevel@tonic-gate (uintptr_t)dev->devi_global_prop_list); 9727c478bd9Sstevel@tonic-gate return (WALK_ERR); 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate global_props = plist.prop_list; 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate mdb_inc_indent(din->din_depth * DEVINFO_TREE_INDENT); 9787c478bd9Sstevel@tonic-gate if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD)) 9797c478bd9Sstevel@tonic-gate mdb_printf("%<b>"); 9807c478bd9Sstevel@tonic-gate mdb_printf("%-0?p %s", addr, binding_name); 9817c478bd9Sstevel@tonic-gate if ((addr == data->di_base) || (data->di_flags & DEVINFO_ALLBOLD)) 9827c478bd9Sstevel@tonic-gate mdb_printf("%</b>"); 9837c478bd9Sstevel@tonic-gate if (dev->devi_instance >= 0) 9847c478bd9Sstevel@tonic-gate mdb_printf(", instance #%d", dev->devi_instance); 985f723faa1Seschrock 986f723faa1Seschrock if (dev->devi_node_state < DS_ATTACHED) 9877c478bd9Sstevel@tonic-gate mdb_printf(" (driver not attached)"); 988f723faa1Seschrock else if (mdb_devinfo2driver(addr, dname, sizeof (dname)) != 0) 989f723faa1Seschrock mdb_printf(" (could not determine driver name)"); 990f723faa1Seschrock else 991f723faa1Seschrock mdb_printf(" (driver name: %s)", dname); 992f723faa1Seschrock 9937c478bd9Sstevel@tonic-gate mdb_printf("\n"); 9947c478bd9Sstevel@tonic-gate if (data->di_flags & DEVINFO_VERBOSE) { 9957c478bd9Sstevel@tonic-gate mdb_inc_indent(DEVINFO_PROPLIST_INDENT); 9967c478bd9Sstevel@tonic-gate devinfo_print_props("System", dev->devi_sys_prop_ptr); 9977c478bd9Sstevel@tonic-gate devinfo_print_props("Driver", dev->devi_drv_prop_ptr); 9987c478bd9Sstevel@tonic-gate devinfo_print_props("Hardware", dev->devi_hw_prop_ptr); 9997c478bd9Sstevel@tonic-gate devinfo_print_props("Global", global_props); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate devinfo_print_pathing(dev->devi_mdi_component, 10027c478bd9Sstevel@tonic-gate dev->devi_mdi_client); 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate mdb_dec_indent(DEVINFO_PROPLIST_INDENT); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate mdb_dec_indent(din->din_depth * DEVINFO_TREE_INDENT); 10087c478bd9Sstevel@tonic-gate return (WALK_NEXT); 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10127c478bd9Sstevel@tonic-gate int 10137c478bd9Sstevel@tonic-gate prtconf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 10147c478bd9Sstevel@tonic-gate { 10157c478bd9Sstevel@tonic-gate devinfo_cb_data_t data; 101614ef2b2fSdmick uintptr_t devinfo_root; /* Address of root of devinfo tree */ 10177c478bd9Sstevel@tonic-gate int status; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate data.di_flags = DEVINFO_PARENT | DEVINFO_CHILD; 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 10227c478bd9Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, DEVINFO_VERBOSE, &data.di_flags, 10237c478bd9Sstevel@tonic-gate 'p', MDB_OPT_CLRBITS, DEVINFO_CHILD, &data.di_flags, 10247c478bd9Sstevel@tonic-gate 'c', MDB_OPT_CLRBITS, DEVINFO_PARENT, &data.di_flags, NULL) != argc) 10257c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 10267c478bd9Sstevel@tonic-gate 102714ef2b2fSdmick if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) { 102814ef2b2fSdmick mdb_warn("failed to read 'top_devinfo'"); 102914ef2b2fSdmick return (NULL); 103014ef2b2fSdmick } 103114ef2b2fSdmick 10327c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) { 10337c478bd9Sstevel@tonic-gate addr = devinfo_root; 10347c478bd9Sstevel@tonic-gate if (data.di_flags & DEVINFO_VERBOSE) 10357c478bd9Sstevel@tonic-gate data.di_flags |= DEVINFO_ALLBOLD; 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate data.di_base = addr; 10397c478bd9Sstevel@tonic-gate mdb_printf("%<u>%-?s %-50s%</u>\n", "DEVINFO", "NAME"); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate if ((data.di_flags & (DEVINFO_PARENT | DEVINFO_CHILD)) == 10427c478bd9Sstevel@tonic-gate (DEVINFO_PARENT | DEVINFO_CHILD)) { 10437c478bd9Sstevel@tonic-gate status = mdb_pwalk("devinfo", 10447c478bd9Sstevel@tonic-gate (mdb_walk_cb_t)devinfo_print, &data, addr); 10457c478bd9Sstevel@tonic-gate } else if (data.di_flags & DEVINFO_PARENT) { 10467c478bd9Sstevel@tonic-gate status = mdb_pwalk("devinfo_parents", 10477c478bd9Sstevel@tonic-gate (mdb_walk_cb_t)devinfo_print, &data, addr); 10487c478bd9Sstevel@tonic-gate } else if (data.di_flags & DEVINFO_CHILD) { 10497c478bd9Sstevel@tonic-gate status = mdb_pwalk("devinfo_children", 10507c478bd9Sstevel@tonic-gate (mdb_walk_cb_t)devinfo_print, &data, addr); 10517c478bd9Sstevel@tonic-gate } else { 10527c478bd9Sstevel@tonic-gate devinfo_node_t din; 10537c478bd9Sstevel@tonic-gate if (mdb_vread(&din.din_dev, sizeof (din.din_dev), addr) == -1) { 10547c478bd9Sstevel@tonic-gate mdb_warn("failed to read device"); 10557c478bd9Sstevel@tonic-gate return (DCMD_ERR); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate din.din_depth = 0; 10587c478bd9Sstevel@tonic-gate return (devinfo_print(addr, (struct dev_info *)&din, &data)); 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate if (status == -1) { 10627c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk devinfo tree"); 10637c478bd9Sstevel@tonic-gate return (DCMD_ERR); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate return (DCMD_OK); 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10707c478bd9Sstevel@tonic-gate int 10717c478bd9Sstevel@tonic-gate devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 10727c478bd9Sstevel@tonic-gate { 10737c478bd9Sstevel@tonic-gate char tmpstr[MODMAXNAMELEN]; 10747c478bd9Sstevel@tonic-gate char nodename[MODMAXNAMELEN]; 1075f4da9be0Scth char bindname[MAXPATHLEN]; 10767c478bd9Sstevel@tonic-gate int size, length; 10777c478bd9Sstevel@tonic-gate struct dev_info devi; 10787c478bd9Sstevel@tonic-gate devinfo_node_t din; 10797c478bd9Sstevel@tonic-gate devinfo_cb_data_t data; 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate static const mdb_bitmask_t devi_state_masks[] = { 10827c478bd9Sstevel@tonic-gate { "DEVICE_OFFLINE", DEVI_DEVICE_OFFLINE, DEVI_DEVICE_OFFLINE }, 10837c478bd9Sstevel@tonic-gate { "DEVICE_DOWN", DEVI_DEVICE_DOWN, DEVI_DEVICE_DOWN }, 10847c478bd9Sstevel@tonic-gate { "DEVICE_DEGRADED", DEVI_DEVICE_DEGRADED, DEVI_DEVICE_DEGRADED }, 1085f4da9be0Scth { "DEVICE_REMOVED", DEVI_DEVICE_REMOVED, DEVI_DEVICE_REMOVED }, 10867c478bd9Sstevel@tonic-gate { "BUS_QUIESCED", DEVI_BUS_QUIESCED, DEVI_BUS_QUIESCED }, 10877c478bd9Sstevel@tonic-gate { "BUS_DOWN", DEVI_BUS_DOWN, DEVI_BUS_DOWN }, 10887c478bd9Sstevel@tonic-gate { "NDI_CONFIG", DEVI_NDI_CONFIG, DEVI_NDI_CONFIG }, 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate { "S_ATTACHING", DEVI_S_ATTACHING, DEVI_S_ATTACHING }, 10917c478bd9Sstevel@tonic-gate { "S_DETACHING", DEVI_S_DETACHING, DEVI_S_DETACHING }, 10927c478bd9Sstevel@tonic-gate { "S_ONLINING", DEVI_S_ONLINING, DEVI_S_ONLINING }, 10937c478bd9Sstevel@tonic-gate { "S_OFFLINING", DEVI_S_OFFLINING, DEVI_S_OFFLINING }, 10947c478bd9Sstevel@tonic-gate { "S_INVOKING_DACF", DEVI_S_INVOKING_DACF, DEVI_S_INVOKING_DACF }, 10957c478bd9Sstevel@tonic-gate { "S_UNBOUND", DEVI_S_UNBOUND, DEVI_S_UNBOUND }, 10967c478bd9Sstevel@tonic-gate { "S_REPORT", DEVI_S_REPORT, DEVI_S_REPORT }, 10977c478bd9Sstevel@tonic-gate { "S_EVADD", DEVI_S_EVADD, DEVI_S_EVADD }, 10987c478bd9Sstevel@tonic-gate { "S_EVREMOVE", DEVI_S_EVREMOVE, DEVI_S_EVREMOVE }, 1099f4da9be0Scth { "S_NEED_RESET", DEVI_S_NEED_RESET, DEVI_S_NEED_RESET }, 11007c478bd9Sstevel@tonic-gate { NULL, 0, 0 } 11017c478bd9Sstevel@tonic-gate }; 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate static const mdb_bitmask_t devi_flags_masks[] = { 11047c478bd9Sstevel@tonic-gate { "BUSY", DEVI_BUSY, DEVI_BUSY }, 11057c478bd9Sstevel@tonic-gate { "MADE_CHILDREN", DEVI_MADE_CHILDREN, DEVI_MADE_CHILDREN }, 11067c478bd9Sstevel@tonic-gate { "ATTACHED_CHILDREN", 11077c478bd9Sstevel@tonic-gate DEVI_ATTACHED_CHILDREN, DEVI_ATTACHED_CHILDREN}, 11087c478bd9Sstevel@tonic-gate { "BRANCH_HELD", DEVI_BRANCH_HELD, DEVI_BRANCH_HELD }, 1109f4da9be0Scth { "NO_BIND", DEVI_NO_BIND, DEVI_NO_BIND }, 1110*8451e9c3SGavin Maltby { "DEVI_CACHED_DEVID", 1111*8451e9c3SGavin Maltby DEVI_CACHED_DEVID, DEVI_CACHED_DEVID }, 1112f4da9be0Scth { "PHCI_SIGNALS_VHCI", 1113f4da9be0Scth DEVI_PHCI_SIGNALS_VHCI, 1114f4da9be0Scth DEVI_PHCI_SIGNALS_VHCI }, 1115f4da9be0Scth { "REBIND", DEVI_REBIND, DEVI_REBIND }, 11167c478bd9Sstevel@tonic-gate { NULL, 0, 0 } 11177c478bd9Sstevel@tonic-gate }; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate data.di_flags = DEVINFO_VERBOSE; 11207c478bd9Sstevel@tonic-gate data.di_base = addr; 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 11237c478bd9Sstevel@tonic-gate 'q', MDB_OPT_CLRBITS, DEVINFO_VERBOSE, &data.di_flags, 11247c478bd9Sstevel@tonic-gate 's', MDB_OPT_SETBITS, DEVINFO_SUMMARY, &data.di_flags, NULL) 11257c478bd9Sstevel@tonic-gate != argc) 11267c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) { 11297c478bd9Sstevel@tonic-gate mdb_warn( 11307c478bd9Sstevel@tonic-gate "devinfo doesn't give global information (try prtconf)\n"); 11317c478bd9Sstevel@tonic-gate return (DCMD_ERR); 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags) && data.di_flags & DEVINFO_SUMMARY) 11357c478bd9Sstevel@tonic-gate mdb_printf( 11367c478bd9Sstevel@tonic-gate "%-?s %5s %?s %-20s %-s\n" 11377c478bd9Sstevel@tonic-gate "%-?s %5s %?s %-20s %-s\n" 11387c478bd9Sstevel@tonic-gate "%<u>%-?s %5s %?s %-20s %-15s%</u>\n", 11397c478bd9Sstevel@tonic-gate "DEVINFO", "MAJ", "REFCNT", "NODENAME", "NODESTATE", 11407c478bd9Sstevel@tonic-gate "", "INST", "CIRCULAR", "BINDNAME", "STATE", 11417c478bd9Sstevel@tonic-gate "", "", "THREAD", "", "FLAGS"); 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate if (mdb_vread(&devi, sizeof (devi), addr) == -1) { 11447c478bd9Sstevel@tonic-gate mdb_warn("failed to read device"); 11457c478bd9Sstevel@tonic-gate return (DCMD_ERR); 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate if (data.di_flags & DEVINFO_SUMMARY) { 11497c478bd9Sstevel@tonic-gate *nodename = '\0'; 11507c478bd9Sstevel@tonic-gate size = sizeof (nodename); 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate if ((length = mdb_readstr(tmpstr, size, 11537c478bd9Sstevel@tonic-gate (uintptr_t)devi.devi_node_name)) > 0) { 11547c478bd9Sstevel@tonic-gate strcat(nodename, tmpstr); 11557c478bd9Sstevel@tonic-gate size -= length; 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate if (devi.devi_addr != NULL && mdb_readstr(tmpstr, size - 1, 11597c478bd9Sstevel@tonic-gate (uintptr_t)devi.devi_addr) > 0) { 11607c478bd9Sstevel@tonic-gate strcat(nodename, "@"); 11617c478bd9Sstevel@tonic-gate strcat(nodename, tmpstr); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate if (mdb_readstr(bindname, sizeof (bindname), 11657c478bd9Sstevel@tonic-gate (uintptr_t)devi.devi_binding_name) == -1) 11667c478bd9Sstevel@tonic-gate *bindname = '\0'; 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate mdb_printf("%0?p %5d %?d %-20s %s\n", 11697c478bd9Sstevel@tonic-gate addr, devi.devi_major, devi.devi_ref, nodename, 11707c478bd9Sstevel@tonic-gate di_state[MIN(devi.devi_node_state + 1, DI_STATE_MAX)]); 11717c478bd9Sstevel@tonic-gate mdb_printf("%?s %5d %?d %-20s <%b>\n", 11727c478bd9Sstevel@tonic-gate "", devi.devi_instance, devi.devi_circular, bindname, 11737c478bd9Sstevel@tonic-gate devi.devi_state, devi_state_masks); 11747c478bd9Sstevel@tonic-gate mdb_printf("%?s %5s %?p %-20s <%b>\n\n", 11757c478bd9Sstevel@tonic-gate "", "", devi.devi_busy_thread, "", 11767c478bd9Sstevel@tonic-gate devi.devi_flags, devi_flags_masks); 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate return (DCMD_OK); 11797c478bd9Sstevel@tonic-gate } else { 11807c478bd9Sstevel@tonic-gate din.din_dev = devi; 11817c478bd9Sstevel@tonic-gate din.din_depth = 0; 11827c478bd9Sstevel@tonic-gate return (devinfo_print(addr, (struct dev_info *)&din, &data)); 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11877c478bd9Sstevel@tonic-gate int 11887c478bd9Sstevel@tonic-gate m2d_walk_dinfo(uintptr_t addr, struct dev_info *di, char *mod_name) 11897c478bd9Sstevel@tonic-gate { 11907c478bd9Sstevel@tonic-gate char name[MODMAXNAMELEN]; 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate if (mdb_readstr(name, MODMAXNAMELEN, 11937c478bd9Sstevel@tonic-gate (uintptr_t)di->devi_binding_name) == -1) { 11947c478bd9Sstevel@tonic-gate mdb_warn("couldn't read devi_binding_name at %p", 11957c478bd9Sstevel@tonic-gate di->devi_binding_name); 11967c478bd9Sstevel@tonic-gate return (WALK_ERR); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate if (strcmp(name, mod_name) == 0) 12007c478bd9Sstevel@tonic-gate mdb_printf("%p\n", addr); 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate return (WALK_NEXT); 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12067c478bd9Sstevel@tonic-gate int 12077c478bd9Sstevel@tonic-gate modctl2devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 12087c478bd9Sstevel@tonic-gate { 12097c478bd9Sstevel@tonic-gate struct modctl modctl; 12107c478bd9Sstevel@tonic-gate char name[MODMAXNAMELEN]; 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 12137c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate if (mdb_vread(&modctl, sizeof (modctl), addr) == -1) { 12167c478bd9Sstevel@tonic-gate mdb_warn("couldn't read modctl at %p", addr); 12177c478bd9Sstevel@tonic-gate return (DCMD_ERR); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate if (mdb_readstr(name, MODMAXNAMELEN, 12217c478bd9Sstevel@tonic-gate (uintptr_t)modctl.mod_modname) == -1) { 12227c478bd9Sstevel@tonic-gate mdb_warn("couldn't read modname at %p", modctl.mod_modname); 12237c478bd9Sstevel@tonic-gate return (DCMD_ERR); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate if (mdb_walk("devinfo", (mdb_walk_cb_t)m2d_walk_dinfo, name) == -1) { 12277c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk devinfo"); 12287c478bd9Sstevel@tonic-gate return (DCMD_ERR); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate return (DCMD_OK); 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate static int 12357c478bd9Sstevel@tonic-gate major_to_addr(major_t major, uintptr_t *vaddr) 12367c478bd9Sstevel@tonic-gate { 12377c478bd9Sstevel@tonic-gate uint_t devcnt; 12387c478bd9Sstevel@tonic-gate uintptr_t devnamesp; 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate if (mdb_readvar(&devcnt, "devcnt") == -1) { 12417c478bd9Sstevel@tonic-gate mdb_warn("failed to read 'devcnt'"); 12427c478bd9Sstevel@tonic-gate return (-1); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate if (mdb_readvar(&devnamesp, "devnamesp") == -1) { 12467c478bd9Sstevel@tonic-gate mdb_warn("failed to read 'devnamesp'"); 12477c478bd9Sstevel@tonic-gate return (-1); 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate if (major >= devcnt) { 12517c478bd9Sstevel@tonic-gate mdb_warn("%x is out of range [0x0-0x%x]\n", major, devcnt - 1); 12527c478bd9Sstevel@tonic-gate return (-1); 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate *vaddr = devnamesp + (major * sizeof (struct devnames)); 12567c478bd9Sstevel@tonic-gate return (0); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12607c478bd9Sstevel@tonic-gate int 12617c478bd9Sstevel@tonic-gate devnames(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 12627c478bd9Sstevel@tonic-gate { 12637c478bd9Sstevel@tonic-gate static const mdb_bitmask_t dn_flag_bits[] = { 12647c478bd9Sstevel@tonic-gate { "DN_CONF_PARSED", DN_CONF_PARSED, DN_CONF_PARSED }, 12657c478bd9Sstevel@tonic-gate { "DN_DRIVER_BUSY", DN_DRIVER_BUSY, DN_DRIVER_BUSY }, 12667c478bd9Sstevel@tonic-gate { "DN_DRIVER_HELD", DN_DRIVER_HELD, DN_DRIVER_HELD }, 12677c478bd9Sstevel@tonic-gate { "DN_TAKEN_GETUDEV", DN_TAKEN_GETUDEV, DN_TAKEN_GETUDEV }, 12687c478bd9Sstevel@tonic-gate { "DN_DRIVER_REMOVED", DN_DRIVER_REMOVED, DN_DRIVER_REMOVED}, 12697c478bd9Sstevel@tonic-gate { "DN_FORCE_ATTACH", DN_FORCE_ATTACH, DN_FORCE_ATTACH}, 12707c478bd9Sstevel@tonic-gate { "DN_LEAF_DRIVER", DN_LEAF_DRIVER, DN_LEAF_DRIVER}, 12717c478bd9Sstevel@tonic-gate { "DN_NETWORK_DRIVER", DN_NETWORK_DRIVER, DN_NETWORK_DRIVER}, 12727c478bd9Sstevel@tonic-gate { "DN_NO_AUTODETACH", DN_NO_AUTODETACH, DN_NO_AUTODETACH }, 12736e13b8c3Scth { "DN_GLDV3_DRIVER", DN_GLDV3_DRIVER, DN_GLDV3_DRIVER}, 127452cac543Sramat { "DN_PHCI_DRIVER", DN_PHCI_DRIVER, DN_PHCI_DRIVER}, 1275602ca9eaScth { "DN_OPEN_RETURNS_EINTR", \ 1276602ca9eaScth DN_OPEN_RETURNS_EINTR, DN_OPEN_RETURNS_EINTR}, 1277602ca9eaScth { "DN_SCSI_SIZE_CLEAN", DN_SCSI_SIZE_CLEAN, DN_SCSI_SIZE_CLEAN}, 1278095be824SCathy Zhou { "DN_NETWORK_PHYSDRIVER", \ 1279095be824SCathy Zhou DN_NETWORK_PHYSDRIVER, DN_NETWORK_PHYSDRIVER}, 12807c478bd9Sstevel@tonic-gate { NULL, 0, 0 } 12817c478bd9Sstevel@tonic-gate }; 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate const mdb_arg_t *argp = NULL; 12847c478bd9Sstevel@tonic-gate uint_t opt_v = FALSE, opt_m = FALSE; 12857c478bd9Sstevel@tonic-gate major_t major; 12867c478bd9Sstevel@tonic-gate size_t i; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate char name[MODMAXNAMELEN + 1]; 12897c478bd9Sstevel@tonic-gate struct devnames dn; 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate if ((i = mdb_getopts(argc, argv, 12927c478bd9Sstevel@tonic-gate 'm', MDB_OPT_SETBITS, TRUE, &opt_m, 12937c478bd9Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, TRUE, &opt_v, 12947c478bd9Sstevel@tonic-gate NULL)) != argc) { 12957c478bd9Sstevel@tonic-gate if (argc - i > 1) 12967c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 12977c478bd9Sstevel@tonic-gate argp = &argv[i]; 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate if (opt_m) { 13017c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 13027c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate if (major_to_addr(addr, &addr) == -1) 13057c478bd9Sstevel@tonic-gate return (DCMD_ERR); 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate } else if (!(flags & DCMD_ADDRSPEC)) { 13087c478bd9Sstevel@tonic-gate if (argp == NULL) { 13097c478bd9Sstevel@tonic-gate if (mdb_walk_dcmd("devnames", "devnames", argc, argv)) { 13107c478bd9Sstevel@tonic-gate mdb_warn("failed to walk devnames"); 13117c478bd9Sstevel@tonic-gate return (DCMD_ERR); 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate return (DCMD_OK); 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate if (argp->a_type == MDB_TYPE_IMMEDIATE) 13177c478bd9Sstevel@tonic-gate major = (major_t)argp->a_un.a_val; 13187c478bd9Sstevel@tonic-gate else 13197c478bd9Sstevel@tonic-gate major = (major_t)mdb_strtoull(argp->a_un.a_str); 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate if (major_to_addr(major, &addr) == -1) 13227c478bd9Sstevel@tonic-gate return (DCMD_ERR); 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate if (mdb_vread(&dn, sizeof (struct devnames), addr) == -1) { 13267c478bd9Sstevel@tonic-gate mdb_warn("failed to read devnames struct at %p", addr); 13277c478bd9Sstevel@tonic-gate return (DCMD_ERR); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 13317c478bd9Sstevel@tonic-gate if (opt_v) 13327c478bd9Sstevel@tonic-gate mdb_printf("%<u>%-16s%</u>\n", "NAME"); 13337c478bd9Sstevel@tonic-gate else 13347c478bd9Sstevel@tonic-gate mdb_printf("%<u>%-16s %-?s%</u>\n", "NAME", "DN_HEAD"); 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate if ((flags & DCMD_LOOP) && (dn.dn_name == NULL)) 13387c478bd9Sstevel@tonic-gate return (DCMD_OK); /* Skip empty slots if we're printing table */ 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate if (mdb_readstr(name, sizeof (name), (uintptr_t)dn.dn_name) == -1) 13417c478bd9Sstevel@tonic-gate (void) mdb_snprintf(name, sizeof (name), "0x%p", dn.dn_name); 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate if (opt_v) { 13447c478bd9Sstevel@tonic-gate ddi_prop_list_t prop_list; 13457c478bd9Sstevel@tonic-gate mdb_printf("%<b>%-16s%</b>\n", name); 13467c478bd9Sstevel@tonic-gate mdb_inc_indent(2); 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate mdb_printf(" flags %b\n", dn.dn_flags, dn_flag_bits); 13497c478bd9Sstevel@tonic-gate mdb_printf(" pl %p\n", (void *)dn.dn_pl); 13507c478bd9Sstevel@tonic-gate mdb_printf(" head %p\n", dn.dn_head); 13517c478bd9Sstevel@tonic-gate mdb_printf(" instance %d\n", dn.dn_instance); 13527c478bd9Sstevel@tonic-gate mdb_printf(" inlist %p\n", dn.dn_inlist); 13537c478bd9Sstevel@tonic-gate mdb_printf("global_prop_ptr %p\n", dn.dn_global_prop_ptr); 13547c478bd9Sstevel@tonic-gate if (mdb_vread(&prop_list, sizeof (ddi_prop_list_t), 13557c478bd9Sstevel@tonic-gate (uintptr_t)dn.dn_global_prop_ptr) != -1) { 13567c478bd9Sstevel@tonic-gate devinfo_print_props(NULL, prop_list.prop_list); 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate mdb_dec_indent(2); 13607c478bd9Sstevel@tonic-gate } else 13617c478bd9Sstevel@tonic-gate mdb_printf("%-16s %-?p\n", name, dn.dn_head); 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate return (DCMD_OK); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13677c478bd9Sstevel@tonic-gate int 13687c478bd9Sstevel@tonic-gate name2major(uintptr_t vaddr, uint_t flags, int argc, const mdb_arg_t *argv) 13697c478bd9Sstevel@tonic-gate { 13707c478bd9Sstevel@tonic-gate major_t major; 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) 13737c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate if (argc != 1 || argv->a_type != MDB_TYPE_STRING) 13767c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate if (mdb_name_to_major(argv->a_un.a_str, &major) != 0) { 13797c478bd9Sstevel@tonic-gate mdb_warn("failed to convert name to major number\n"); 13807c478bd9Sstevel@tonic-gate return (DCMD_ERR); 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate mdb_printf("0x%x\n", major); 13847c478bd9Sstevel@tonic-gate return (DCMD_OK); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate /* 13887c478bd9Sstevel@tonic-gate * Get a numerical argument of a dcmd from addr if an address is specified 13897c478bd9Sstevel@tonic-gate * or from argv if no address is specified. Return the argument in ret. 13907c478bd9Sstevel@tonic-gate */ 13917c478bd9Sstevel@tonic-gate static int 13927c478bd9Sstevel@tonic-gate getarg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 13937c478bd9Sstevel@tonic-gate uintptr_t *ret) 13947c478bd9Sstevel@tonic-gate { 13957c478bd9Sstevel@tonic-gate if (argc == 0 && (flags & DCMD_ADDRSPEC)) { 13967c478bd9Sstevel@tonic-gate *ret = addr; 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate } else if (argc == 1 && !(flags & DCMD_ADDRSPEC)) { 13997c478bd9Sstevel@tonic-gate *ret = (argv[0].a_type == MDB_TYPE_IMMEDIATE) ? 14007c478bd9Sstevel@tonic-gate (uintptr_t)argv[0].a_un.a_val : 14017c478bd9Sstevel@tonic-gate (uintptr_t)mdb_strtoull(argv->a_un.a_str); 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate } else { 14047c478bd9Sstevel@tonic-gate return (-1); 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate return (0); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14117c478bd9Sstevel@tonic-gate int 14127c478bd9Sstevel@tonic-gate major2name(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 14137c478bd9Sstevel@tonic-gate { 14147c478bd9Sstevel@tonic-gate uintptr_t major; 14157c478bd9Sstevel@tonic-gate const char *name; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate if (getarg(addr, flags, argc, argv, &major) < 0) 14187c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate if ((name = mdb_major_to_name((major_t)major)) == NULL) { 14217c478bd9Sstevel@tonic-gate mdb_warn("failed to convert major number to name\n"); 14227c478bd9Sstevel@tonic-gate return (DCMD_ERR); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate mdb_printf("%s\n", name); 14267c478bd9Sstevel@tonic-gate return (DCMD_OK); 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14307c478bd9Sstevel@tonic-gate int 14317c478bd9Sstevel@tonic-gate dev2major(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 14327c478bd9Sstevel@tonic-gate { 14337c478bd9Sstevel@tonic-gate uintptr_t dev; 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate if (getarg(addr, flags, argc, argv, &dev) < 0) 14367c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate if (flags & DCMD_PIPE_OUT) 14397c478bd9Sstevel@tonic-gate mdb_printf("%x\n", getmajor(dev)); 14407c478bd9Sstevel@tonic-gate else 14417c478bd9Sstevel@tonic-gate mdb_printf("0x%x (0t%d)\n", getmajor(dev), getmajor(dev)); 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate return (DCMD_OK); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14477c478bd9Sstevel@tonic-gate int 14487c478bd9Sstevel@tonic-gate dev2minor(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 14497c478bd9Sstevel@tonic-gate { 14507c478bd9Sstevel@tonic-gate uintptr_t dev; 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate if (getarg(addr, flags, argc, argv, &dev) < 0) 14537c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate if (flags & DCMD_PIPE_OUT) 14567c478bd9Sstevel@tonic-gate mdb_printf("%x\n", getminor(dev)); 14577c478bd9Sstevel@tonic-gate else 14587c478bd9Sstevel@tonic-gate mdb_printf("0x%x (0t%d)\n", getminor(dev), getminor(dev)); 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate return (DCMD_OK); 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14647c478bd9Sstevel@tonic-gate int 14657c478bd9Sstevel@tonic-gate devt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 14667c478bd9Sstevel@tonic-gate { 14677c478bd9Sstevel@tonic-gate uintptr_t dev; 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate if (getarg(addr, flags, argc, argv, &dev) < 0) 14707c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 14737c478bd9Sstevel@tonic-gate mdb_printf("%<u>%10s%</u> %<u>%10s%</u>\n", "MAJOR", 14747c478bd9Sstevel@tonic-gate "MINOR"); 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate mdb_printf("%10d %10d\n", getmajor(dev), getminor(dev)); 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate return (DCMD_OK); 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14837c478bd9Sstevel@tonic-gate int 14847c478bd9Sstevel@tonic-gate softstate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 14857c478bd9Sstevel@tonic-gate { 14867c478bd9Sstevel@tonic-gate uintptr_t statep; 14877c478bd9Sstevel@tonic-gate int instance; 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate if (argc != 1) { 14917c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 14927c478bd9Sstevel@tonic-gate } 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate if (argv[0].a_type == MDB_TYPE_IMMEDIATE) 14957c478bd9Sstevel@tonic-gate instance = argv[0].a_un.a_val; 14967c478bd9Sstevel@tonic-gate else 14977c478bd9Sstevel@tonic-gate instance = mdb_strtoull(argv->a_un.a_str); 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate if (mdb_get_soft_state_byaddr(addr, instance, &statep, NULL, 0) == -1) { 15007c478bd9Sstevel@tonic-gate if (errno == ENOENT) { 15017c478bd9Sstevel@tonic-gate mdb_warn("instance %d unused\n", instance); 15027c478bd9Sstevel@tonic-gate } else { 15037c478bd9Sstevel@tonic-gate mdb_warn("couldn't determine softstate for " 15047c478bd9Sstevel@tonic-gate "instance %d", instance); 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate return (DCMD_ERR); 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate mdb_printf("%p\n", statep); 15117c478bd9Sstevel@tonic-gate return (DCMD_OK); 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate /* 15157c478bd9Sstevel@tonic-gate * Walker for all possible pointers to a driver state struct in an 15167c478bd9Sstevel@tonic-gate * i_ddi_soft_state instance chain. Returns all non-NULL pointers. 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate typedef struct soft_state_walk { 15197c478bd9Sstevel@tonic-gate struct i_ddi_soft_state ssw_ss; /* Local copy of i_ddi_soft_state */ 15207c478bd9Sstevel@tonic-gate void **ssw_pointers; /* to driver state structs */ 15217c478bd9Sstevel@tonic-gate uint_t ssw_index; /* array entry we're using */ 15227c478bd9Sstevel@tonic-gate } soft_state_walk_t; 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate int 15257c478bd9Sstevel@tonic-gate soft_state_walk_init(mdb_walk_state_t *wsp) 15267c478bd9Sstevel@tonic-gate { 15277c478bd9Sstevel@tonic-gate soft_state_walk_t *sst; 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 15317c478bd9Sstevel@tonic-gate return (WALK_DONE); 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate sst = mdb_zalloc(sizeof (soft_state_walk_t), UM_SLEEP|UM_GC); 15347c478bd9Sstevel@tonic-gate wsp->walk_data = sst; 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate if (mdb_vread(&(sst->ssw_ss), sizeof (sst->ssw_ss), wsp->walk_addr) != 15387c478bd9Sstevel@tonic-gate sizeof (sst->ssw_ss)) { 15397c478bd9Sstevel@tonic-gate mdb_warn("failed to read i_ddi_soft_state at %p", 15407c478bd9Sstevel@tonic-gate wsp->walk_addr); 15417c478bd9Sstevel@tonic-gate return (WALK_ERR); 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate /* Read array of pointers to state structs into local storage. */ 15467c478bd9Sstevel@tonic-gate sst->ssw_pointers = mdb_alloc((sst->ssw_ss.n_items * sizeof (void *)), 15477c478bd9Sstevel@tonic-gate UM_SLEEP|UM_GC); 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate if (mdb_vread(sst->ssw_pointers, (sst->ssw_ss.n_items * 15507c478bd9Sstevel@tonic-gate sizeof (void *)), (uintptr_t)sst->ssw_ss.array) != 15517c478bd9Sstevel@tonic-gate (sst->ssw_ss.n_items * sizeof (void *))) { 15527c478bd9Sstevel@tonic-gate mdb_warn("failed to read i_ddi_soft_state at %p", 15537c478bd9Sstevel@tonic-gate wsp->walk_addr); 15547c478bd9Sstevel@tonic-gate return (WALK_ERR); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate sst->ssw_index = 0; 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate return (WALK_NEXT); 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate int 15637c478bd9Sstevel@tonic-gate soft_state_walk_step(mdb_walk_state_t *wsp) 15647c478bd9Sstevel@tonic-gate { 15657c478bd9Sstevel@tonic-gate soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data; 15667c478bd9Sstevel@tonic-gate int status = WALK_NEXT; 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate * If the entry indexed has a valid pointer to a soft state struct, 15717c478bd9Sstevel@tonic-gate * invoke caller's callback func. 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate if (sst->ssw_pointers[sst->ssw_index] != NULL) { 15747c478bd9Sstevel@tonic-gate status = wsp->walk_callback( 15757c478bd9Sstevel@tonic-gate (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL, 15767c478bd9Sstevel@tonic-gate wsp->walk_cbdata); 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate sst->ssw_index += 1; 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate if (sst->ssw_index == sst->ssw_ss.n_items) 15827c478bd9Sstevel@tonic-gate return (WALK_DONE); 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate return (status); 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate int 15887c478bd9Sstevel@tonic-gate soft_state_all_walk_step(mdb_walk_state_t *wsp) 15897c478bd9Sstevel@tonic-gate { 15907c478bd9Sstevel@tonic-gate soft_state_walk_t *sst = (soft_state_walk_t *)wsp->walk_data; 15917c478bd9Sstevel@tonic-gate int status = WALK_NEXT; 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate status = wsp->walk_callback( 15957c478bd9Sstevel@tonic-gate (uintptr_t)(sst->ssw_pointers[sst->ssw_index]), NULL, 15967c478bd9Sstevel@tonic-gate wsp->walk_cbdata); 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate sst->ssw_index += 1; 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate if (sst->ssw_index == sst->ssw_ss.n_items) 16017c478bd9Sstevel@tonic-gate return (WALK_DONE); 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate return (status); 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16077c478bd9Sstevel@tonic-gate int 16087c478bd9Sstevel@tonic-gate devbindings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 16097c478bd9Sstevel@tonic-gate { 16107c478bd9Sstevel@tonic-gate const mdb_arg_t *arg; 16117c478bd9Sstevel@tonic-gate struct devnames dn; 16127c478bd9Sstevel@tonic-gate uintptr_t dn_addr; 16137c478bd9Sstevel@tonic-gate major_t major; 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) && argc < 1) 16167c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 16197c478bd9Sstevel@tonic-gate /* 16207c478bd9Sstevel@tonic-gate * If there's an address, then it's a major number 16217c478bd9Sstevel@tonic-gate */ 16227c478bd9Sstevel@tonic-gate major = addr; 16237c478bd9Sstevel@tonic-gate } else { 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * We interpret the last argument. Any other arguments are 16267c478bd9Sstevel@tonic-gate * forwarded to "devinfo" 16277c478bd9Sstevel@tonic-gate */ 16287c478bd9Sstevel@tonic-gate arg = &argv[argc - 1]; 16297c478bd9Sstevel@tonic-gate argc--; 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate if (arg->a_type == MDB_TYPE_IMMEDIATE) { 16327c478bd9Sstevel@tonic-gate major = (uintptr_t)arg->a_un.a_val; 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate } else if (arg->a_un.a_str[0] == '-') { 16357c478bd9Sstevel@tonic-gate /* the argument shouldn't be an option */ 16367c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate } else if (isdigit(arg->a_un.a_str[0])) { 16397c478bd9Sstevel@tonic-gate major = (uintptr_t)mdb_strtoull(arg->a_un.a_str); 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate } else { 16427c478bd9Sstevel@tonic-gate if (mdb_name_to_major(arg->a_un.a_str, &major) != 0) { 16437c478bd9Sstevel@tonic-gate mdb_warn("failed to get major number for %s\n", 16447c478bd9Sstevel@tonic-gate arg->a_un.a_str); 16457c478bd9Sstevel@tonic-gate return (DCMD_ERR); 16467c478bd9Sstevel@tonic-gate } 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate if (major_to_addr(major, &dn_addr) != 0) 16517c478bd9Sstevel@tonic-gate return (DCMD_ERR); 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate if (mdb_vread(&dn, sizeof (struct devnames), dn_addr) == -1) { 16547c478bd9Sstevel@tonic-gate mdb_warn("couldn't read devnames array at %p", dn_addr); 16557c478bd9Sstevel@tonic-gate return (DCMD_ERR); 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate if (mdb_pwalk_dcmd("devi_next", "devinfo", argc, argv, 16597c478bd9Sstevel@tonic-gate (uintptr_t)dn.dn_head) != 0) { 16607c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk the devinfo chain at %p", dn.dn_head); 16617c478bd9Sstevel@tonic-gate return (DCMD_ERR); 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate 16647c478bd9Sstevel@tonic-gate return (DCMD_OK); 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate /* 16687c478bd9Sstevel@tonic-gate * walk binding hashtable (as of of driver names (e.g., mb_hashtab)) 16697c478bd9Sstevel@tonic-gate */ 16707c478bd9Sstevel@tonic-gate int 16717c478bd9Sstevel@tonic-gate binding_hash_walk_init(mdb_walk_state_t *wsp) 16727c478bd9Sstevel@tonic-gate { 16737c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 16747c478bd9Sstevel@tonic-gate return (WALK_ERR); 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate wsp->walk_data = mdb_alloc(sizeof (void *) * MOD_BIND_HASHSIZE, 16777c478bd9Sstevel@tonic-gate UM_SLEEP|UM_GC); 16787c478bd9Sstevel@tonic-gate if (mdb_vread(wsp->walk_data, sizeof (void *) * MOD_BIND_HASHSIZE, 16797c478bd9Sstevel@tonic-gate wsp->walk_addr) == -1) { 16807c478bd9Sstevel@tonic-gate mdb_warn("failed to read mb_hashtab"); 16817c478bd9Sstevel@tonic-gate return (WALK_ERR); 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate wsp->walk_arg = 0; /* index into mb_hashtab array to start */ 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate return (WALK_NEXT); 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate int 16907c478bd9Sstevel@tonic-gate binding_hash_walk_step(mdb_walk_state_t *wsp) 16917c478bd9Sstevel@tonic-gate { 16927c478bd9Sstevel@tonic-gate int status; 16937c478bd9Sstevel@tonic-gate uintptr_t bind_p; 16947c478bd9Sstevel@tonic-gate struct bind bind; 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate /* 16987c478bd9Sstevel@tonic-gate * Walk the singly-linked list of struct bind 16997c478bd9Sstevel@tonic-gate */ 17007c478bd9Sstevel@tonic-gate bind_p = ((uintptr_t *)wsp->walk_data)[(ulong_t)wsp->walk_arg]; 17017c478bd9Sstevel@tonic-gate while (bind_p != NULL) { 17027c478bd9Sstevel@tonic-gate 17037c478bd9Sstevel@tonic-gate if (mdb_vread(&bind, sizeof (bind), bind_p) == -1) { 17047c478bd9Sstevel@tonic-gate mdb_warn("failed to read bind struct at %p", 17057c478bd9Sstevel@tonic-gate wsp->walk_addr); 17067c478bd9Sstevel@tonic-gate return (WALK_ERR); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate if ((status = wsp->walk_callback(bind_p, &bind, 17107c478bd9Sstevel@tonic-gate wsp->walk_cbdata)) != WALK_NEXT) { 17117c478bd9Sstevel@tonic-gate return (status); 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate bind_p = (uintptr_t)bind.b_next; 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate wsp->walk_arg = (void *)((char *)wsp->walk_arg + 1); 17187c478bd9Sstevel@tonic-gate 17197c478bd9Sstevel@tonic-gate if (wsp->walk_arg == (void *)(MOD_BIND_HASHSIZE - 1)) 17207c478bd9Sstevel@tonic-gate return (WALK_DONE); 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate return (WALK_NEXT); 17237c478bd9Sstevel@tonic-gate } 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17267c478bd9Sstevel@tonic-gate int 17277c478bd9Sstevel@tonic-gate binding_hash_entry(uintptr_t addr, uint_t flags, int argc, 17287c478bd9Sstevel@tonic-gate const mdb_arg_t *argv) 17297c478bd9Sstevel@tonic-gate { 17307c478bd9Sstevel@tonic-gate struct bind bind; 17317c478bd9Sstevel@tonic-gate /* Arbitrary lengths based on output format below */ 1732f4da9be0Scth char name[MAXPATHLEN] = "???"; 1733f4da9be0Scth char bind_name[MAXPATHLEN] = "<null>"; 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == NULL) 17367c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate /* Allow null addresses to be passed (as from a walker) */ 17397c478bd9Sstevel@tonic-gate if (addr == NULL) 17407c478bd9Sstevel@tonic-gate return (DCMD_OK); 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate if (mdb_vread(&bind, sizeof (bind), addr) == -1) { 17437c478bd9Sstevel@tonic-gate mdb_warn("failed to read struct bind at %p", addr); 17447c478bd9Sstevel@tonic-gate return (DCMD_ERR); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 1748f4da9be0Scth mdb_printf("%<u>%?s% %-5s %s%</u>\n", 1749f4da9be0Scth "NEXT", "MAJOR", "NAME(S)"); 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate if (mdb_readstr(name, sizeof (name), (uintptr_t)bind.b_name) == -1) 17537c478bd9Sstevel@tonic-gate mdb_warn("failed to read 'name'"); 17547c478bd9Sstevel@tonic-gate 1755f4da9be0Scth /* There may be bind_name, so this may fail */ 1756f4da9be0Scth if (mdb_readstr(bind_name, sizeof (bind_name), 1757f4da9be0Scth (uintptr_t)bind.b_bind_name) == -1) { 1758f4da9be0Scth mdb_printf("%?p %5d %s\n", 1759f4da9be0Scth bind.b_next, bind.b_num, name); 1760f4da9be0Scth } else { 1761f4da9be0Scth mdb_printf("%?p %5d %s %s\n", 1762f4da9be0Scth bind.b_next, bind.b_num, name, bind_name); 1763f4da9be0Scth } 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate return (DCMD_OK); 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate typedef struct devinfo_audit_log_walk_data { 17697c478bd9Sstevel@tonic-gate devinfo_audit_t dil_buf; /* buffer of last entry */ 17707c478bd9Sstevel@tonic-gate uintptr_t dil_base; /* starting address of log buffer */ 17717c478bd9Sstevel@tonic-gate int dil_max; /* maximum index */ 17727c478bd9Sstevel@tonic-gate int dil_start; /* starting index */ 17737c478bd9Sstevel@tonic-gate int dil_index; /* current walking index */ 17747c478bd9Sstevel@tonic-gate } devinfo_audit_log_walk_data_t; 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate int 17777c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_init(mdb_walk_state_t *wsp) 17787c478bd9Sstevel@tonic-gate { 17797c478bd9Sstevel@tonic-gate devinfo_log_header_t header; 17807c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_data_t *dil; 17817c478bd9Sstevel@tonic-gate uintptr_t devinfo_audit_log; 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate /* read in devinfo_log_header structure */ 17847c478bd9Sstevel@tonic-gate if (mdb_readvar(&devinfo_audit_log, "devinfo_audit_log") == -1) { 17857c478bd9Sstevel@tonic-gate mdb_warn("failed to read 'devinfo_audit_log'"); 17867c478bd9Sstevel@tonic-gate return (WALK_ERR); 17877c478bd9Sstevel@tonic-gate } 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate if (mdb_vread(&header, sizeof (devinfo_log_header_t), 17907c478bd9Sstevel@tonic-gate devinfo_audit_log) == -1) { 17917c478bd9Sstevel@tonic-gate mdb_warn("couldn't read devinfo_log_header at %p", 17927c478bd9Sstevel@tonic-gate devinfo_audit_log); 17937c478bd9Sstevel@tonic-gate return (WALK_ERR); 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate dil = mdb_zalloc(sizeof (devinfo_audit_log_walk_data_t), UM_SLEEP); 17977c478bd9Sstevel@tonic-gate wsp->walk_data = dil; 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate dil->dil_start = dil->dil_index = header.dh_curr; 18007c478bd9Sstevel@tonic-gate dil->dil_max = header.dh_max; 18017c478bd9Sstevel@tonic-gate if (dil->dil_start < 0) /* no log entries */ 18027c478bd9Sstevel@tonic-gate return (WALK_DONE); 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate dil->dil_base = devinfo_audit_log + 18057c478bd9Sstevel@tonic-gate offsetof(devinfo_log_header_t, dh_entry); 18067c478bd9Sstevel@tonic-gate wsp->walk_addr = dil->dil_base + 18077c478bd9Sstevel@tonic-gate dil->dil_index * sizeof (devinfo_audit_t); 18087c478bd9Sstevel@tonic-gate 18097c478bd9Sstevel@tonic-gate return (WALK_NEXT); 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate int 18137c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_step(mdb_walk_state_t *wsp) 18147c478bd9Sstevel@tonic-gate { 18157c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 18167c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_data_t *dil = wsp->walk_data; 18177c478bd9Sstevel@tonic-gate devinfo_audit_t *da = &dil->dil_buf; 18187c478bd9Sstevel@tonic-gate int status = WALK_NEXT; 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate /* read in current entry and invoke callback */ 18217c478bd9Sstevel@tonic-gate if (addr == NULL) 18227c478bd9Sstevel@tonic-gate return (WALK_DONE); 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate if (mdb_vread(&dil->dil_buf, sizeof (devinfo_audit_t), addr) == -1) { 18257c478bd9Sstevel@tonic-gate mdb_warn("failed to read devinfo_audit at %p", addr); 18267c478bd9Sstevel@tonic-gate status = WALK_DONE; 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, da, wsp->walk_cbdata); 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate /* step to the previous log entry in time */ 18317c478bd9Sstevel@tonic-gate if (--dil->dil_index < 0) 18327c478bd9Sstevel@tonic-gate dil->dil_index += dil->dil_max; 18337c478bd9Sstevel@tonic-gate if (dil->dil_index == dil->dil_start) { 18347c478bd9Sstevel@tonic-gate wsp->walk_addr = NULL; 18357c478bd9Sstevel@tonic-gate return (WALK_DONE); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate wsp->walk_addr = dil->dil_base + 18397c478bd9Sstevel@tonic-gate dil->dil_index * sizeof (devinfo_audit_t); 18407c478bd9Sstevel@tonic-gate return (status); 18417c478bd9Sstevel@tonic-gate } 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate void 18447c478bd9Sstevel@tonic-gate devinfo_audit_log_walk_fini(mdb_walk_state_t *wsp) 18457c478bd9Sstevel@tonic-gate { 18467c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (devinfo_audit_log_walk_data_t)); 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate /* 18507c478bd9Sstevel@tonic-gate * display devinfo_audit_t stack trace 18517c478bd9Sstevel@tonic-gate */ 18527c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18537c478bd9Sstevel@tonic-gate int 18547c478bd9Sstevel@tonic-gate devinfo_audit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 18557c478bd9Sstevel@tonic-gate { 18567c478bd9Sstevel@tonic-gate uint_t verbose = FALSE; 18577c478bd9Sstevel@tonic-gate devinfo_audit_t da; 18587c478bd9Sstevel@tonic-gate int i, depth; 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 18617c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 18647c478bd9Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) 18657c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 18687c478bd9Sstevel@tonic-gate mdb_printf(" %-?s %16s %-?s %-?s %5s\n", 18697c478bd9Sstevel@tonic-gate "AUDIT", "TIMESTAMP", "THREAD", "DEVINFO", "STATE"); 18707c478bd9Sstevel@tonic-gate } 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate if (mdb_vread(&da, sizeof (da), addr) == -1) { 18737c478bd9Sstevel@tonic-gate mdb_warn("couldn't read devinfo_audit at %p", addr); 18747c478bd9Sstevel@tonic-gate return (DCMD_ERR); 18757c478bd9Sstevel@tonic-gate } 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate mdb_printf(" %0?p %16llx %0?p %0?p %s\n", 18787c478bd9Sstevel@tonic-gate addr, da.da_timestamp, da.da_thread, da.da_devinfo, 18797c478bd9Sstevel@tonic-gate di_state[MIN(da.da_node_state + 1, DI_STATE_MAX)]); 18807c478bd9Sstevel@tonic-gate 18817c478bd9Sstevel@tonic-gate if (!verbose) 18827c478bd9Sstevel@tonic-gate return (DCMD_OK); 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate mdb_inc_indent(4); 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate /* 18877c478bd9Sstevel@tonic-gate * Guard against bogus da_depth in case the devinfo_audit_t 18887c478bd9Sstevel@tonic-gate * is corrupt or the address does not really refer to a 18897c478bd9Sstevel@tonic-gate * devinfo_audit_t. 18907c478bd9Sstevel@tonic-gate */ 18917c478bd9Sstevel@tonic-gate depth = MIN(da.da_depth, DDI_STACK_DEPTH); 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) 18947c478bd9Sstevel@tonic-gate mdb_printf("%a\n", da.da_stack[i]); 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate mdb_printf("\n"); 18977c478bd9Sstevel@tonic-gate mdb_dec_indent(4); 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate return (DCMD_OK); 19007c478bd9Sstevel@tonic-gate } 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate int 19037c478bd9Sstevel@tonic-gate devinfo_audit_log(uintptr_t addr, uint_t flags, int argc, 19047c478bd9Sstevel@tonic-gate const mdb_arg_t *argv) 19057c478bd9Sstevel@tonic-gate { 19067c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) 19077c478bd9Sstevel@tonic-gate return (devinfo_audit(addr, flags, argc, argv)); 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate (void) mdb_walk_dcmd("devinfo_audit_log", "devinfo_audit", argc, argv); 19107c478bd9Sstevel@tonic-gate return (DCMD_OK); 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate typedef struct devinfo_audit_node_walk_data { 19147c478bd9Sstevel@tonic-gate devinfo_audit_t dih_buf; /* buffer of last entry */ 19157c478bd9Sstevel@tonic-gate uintptr_t dih_dip; /* address of dev_info */ 19167c478bd9Sstevel@tonic-gate int dih_on_devinfo; /* devi_audit on dev_info struct */ 19177c478bd9Sstevel@tonic-gate } devinfo_audit_node_walk_data_t; 19187c478bd9Sstevel@tonic-gate 19197c478bd9Sstevel@tonic-gate int 19207c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_init(mdb_walk_state_t *wsp) 19217c478bd9Sstevel@tonic-gate { 19227c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_data_t *dih; 19237c478bd9Sstevel@tonic-gate devinfo_audit_t *da; 19247c478bd9Sstevel@tonic-gate struct dev_info devi; 19257c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 19267c478bd9Sstevel@tonic-gate 19277c478bd9Sstevel@tonic-gate /* read in devinfo structure */ 19287c478bd9Sstevel@tonic-gate if (mdb_vread(&devi, sizeof (struct dev_info), addr) == -1) { 19297c478bd9Sstevel@tonic-gate mdb_warn("couldn't read dev_info at %p", addr); 19307c478bd9Sstevel@tonic-gate return (WALK_ERR); 19317c478bd9Sstevel@tonic-gate } 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate dih = mdb_zalloc(sizeof (devinfo_audit_node_walk_data_t), UM_SLEEP); 19347c478bd9Sstevel@tonic-gate wsp->walk_data = dih; 19357c478bd9Sstevel@tonic-gate da = &dih->dih_buf; 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate /* read in devi_audit structure */ 19387c478bd9Sstevel@tonic-gate if (mdb_vread(da, sizeof (devinfo_audit_t), (uintptr_t)devi.devi_audit) 19397c478bd9Sstevel@tonic-gate == -1) { 19407c478bd9Sstevel@tonic-gate mdb_warn("couldn't read devi_audit at %p", devi.devi_audit); 19417c478bd9Sstevel@tonic-gate return (WALK_ERR); 19427c478bd9Sstevel@tonic-gate } 19437c478bd9Sstevel@tonic-gate dih->dih_dip = addr; 19447c478bd9Sstevel@tonic-gate dih->dih_on_devinfo = 1; 19457c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)devi.devi_audit; 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate return (WALK_NEXT); 19487c478bd9Sstevel@tonic-gate } 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate int 19517c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_step(mdb_walk_state_t *wsp) 19527c478bd9Sstevel@tonic-gate { 19537c478bd9Sstevel@tonic-gate uintptr_t addr; 19547c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_data_t *dih = wsp->walk_data; 19557c478bd9Sstevel@tonic-gate devinfo_audit_t *da = &dih->dih_buf; 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 19587c478bd9Sstevel@tonic-gate return (WALK_DONE); 19597c478bd9Sstevel@tonic-gate (void) wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata); 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate skip: 19627c478bd9Sstevel@tonic-gate /* read in previous entry */ 19637c478bd9Sstevel@tonic-gate if ((addr = (uintptr_t)da->da_lastlog) == 0) 19647c478bd9Sstevel@tonic-gate return (WALK_DONE); 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate if (mdb_vread(&dih->dih_buf, sizeof (devinfo_audit_t), addr) == -1) { 19677c478bd9Sstevel@tonic-gate mdb_warn("failed to read devinfo_audit at %p", addr); 19687c478bd9Sstevel@tonic-gate return (WALK_DONE); 19697c478bd9Sstevel@tonic-gate } 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate /* check if last log was over-written */ 19727c478bd9Sstevel@tonic-gate if ((uintptr_t)da->da_devinfo != dih->dih_dip) 19737c478bd9Sstevel@tonic-gate return (WALK_DONE); 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate /* 19767c478bd9Sstevel@tonic-gate * skip the first common log entry, which is a duplicate of 19777c478bd9Sstevel@tonic-gate * the devi_audit buffer on the dev_info structure 19787c478bd9Sstevel@tonic-gate */ 19797c478bd9Sstevel@tonic-gate if (dih->dih_on_devinfo) { 19807c478bd9Sstevel@tonic-gate dih->dih_on_devinfo = 0; 19817c478bd9Sstevel@tonic-gate goto skip; 19827c478bd9Sstevel@tonic-gate } 19837c478bd9Sstevel@tonic-gate wsp->walk_addr = addr; 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate return (WALK_NEXT); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate void 19897c478bd9Sstevel@tonic-gate devinfo_audit_node_walk_fini(mdb_walk_state_t *wsp) 19907c478bd9Sstevel@tonic-gate { 19917c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (devinfo_audit_node_walk_data_t)); 19927c478bd9Sstevel@tonic-gate } 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate int 19957c478bd9Sstevel@tonic-gate devinfo_audit_node(uintptr_t addr, uint_t flags, int argc, 19967c478bd9Sstevel@tonic-gate const mdb_arg_t *argv) 19977c478bd9Sstevel@tonic-gate { 19987c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 19997c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate (void) mdb_pwalk_dcmd("devinfo_audit_node", "devinfo_audit", 20027c478bd9Sstevel@tonic-gate argc, argv, addr); 20037c478bd9Sstevel@tonic-gate return (DCMD_OK); 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate /* 20077c478bd9Sstevel@tonic-gate * mdb support for per-devinfo fault management data 20087c478bd9Sstevel@tonic-gate */ 20097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20107c478bd9Sstevel@tonic-gate int 20117c478bd9Sstevel@tonic-gate devinfo_fm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 20127c478bd9Sstevel@tonic-gate { 20137c478bd9Sstevel@tonic-gate struct dev_info devi; 20147c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl fhdl; 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 20177c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 2020a5667d81SCheng Sean Ye mdb_printf("%<u>%?s IPL CAPS DROP FMCFULL FMCMISS ACCERR " 2021a5667d81SCheng Sean Ye "DMAERR %?s %?s%</u>\n", "ADDR", "DMACACHE", "ACCCACHE"); 20227c478bd9Sstevel@tonic-gate } 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate if (mdb_vread(&devi, sizeof (devi), addr) == -1) { 20257c478bd9Sstevel@tonic-gate mdb_warn("failed to read devinfo struct at %p", addr); 20267c478bd9Sstevel@tonic-gate return (DCMD_ERR); 20277c478bd9Sstevel@tonic-gate } 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate if (mdb_vread(&fhdl, sizeof (fhdl), (uintptr_t)devi.devi_fmhdl) == -1) { 20307c478bd9Sstevel@tonic-gate mdb_warn("failed to read devinfo fm struct at %p", 20317c478bd9Sstevel@tonic-gate (uintptr_t)devi.devi_fmhdl); 20327c478bd9Sstevel@tonic-gate return (DCMD_ERR); 20337c478bd9Sstevel@tonic-gate } 20347c478bd9Sstevel@tonic-gate 2035a5667d81SCheng Sean Ye mdb_printf("%?p %3u %c%c%c%c %4llu %7llu %7llu %6llu %6llu %?p %?p\n", 20367c478bd9Sstevel@tonic-gate (uintptr_t)devi.devi_fmhdl, fhdl.fh_ibc, 20377c478bd9Sstevel@tonic-gate (DDI_FM_EREPORT_CAP(fhdl.fh_cap) ? 'E' : '-'), 20387c478bd9Sstevel@tonic-gate (DDI_FM_ERRCB_CAP(fhdl.fh_cap) ? 'C' : '-'), 20397c478bd9Sstevel@tonic-gate (DDI_FM_ACC_ERR_CAP(fhdl.fh_cap) ? 'A' : '-'), 20407c478bd9Sstevel@tonic-gate (DDI_FM_DMA_ERR_CAP(fhdl.fh_cap) ? 'D' : '-'), 20417c478bd9Sstevel@tonic-gate fhdl.fh_kstat.fek_erpt_dropped.value.ui64, 20427c478bd9Sstevel@tonic-gate fhdl.fh_kstat.fek_fmc_full.value.ui64, 2043a5667d81SCheng Sean Ye fhdl.fh_kstat.fek_fmc_miss.value.ui64, 20447c478bd9Sstevel@tonic-gate fhdl.fh_kstat.fek_acc_err.value.ui64, 20457c478bd9Sstevel@tonic-gate fhdl.fh_kstat.fek_dma_err.value.ui64, 20467c478bd9Sstevel@tonic-gate fhdl.fh_dma_cache, fhdl.fh_acc_cache); 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate return (DCMD_OK); 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20537c478bd9Sstevel@tonic-gate int 20547c478bd9Sstevel@tonic-gate devinfo_fmce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 20557c478bd9Sstevel@tonic-gate { 20567c478bd9Sstevel@tonic-gate struct i_ddi_fmc_entry fce; 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 20597c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 2062a5667d81SCheng Sean Ye mdb_printf("%<u>%?s %?s %?s%</u>\n", "ADDR", 20637c478bd9Sstevel@tonic-gate "RESOURCE", "BUS_SPECIFIC"); 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate if (mdb_vread(&fce, sizeof (fce), addr) == -1) { 20677c478bd9Sstevel@tonic-gate mdb_warn("failed to read fm cache struct at %p", addr); 20687c478bd9Sstevel@tonic-gate return (DCMD_ERR); 20697c478bd9Sstevel@tonic-gate } 20707c478bd9Sstevel@tonic-gate 2071a5667d81SCheng Sean Ye mdb_printf("%?p %?p %?p\n", 20727c478bd9Sstevel@tonic-gate (uintptr_t)addr, fce.fce_resource, fce.fce_bus_specific); 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate return (DCMD_OK); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate int 20797c478bd9Sstevel@tonic-gate devinfo_fmc_walk_init(mdb_walk_state_t *wsp) 20807c478bd9Sstevel@tonic-gate { 20817c478bd9Sstevel@tonic-gate struct i_ddi_fmc fec; 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) 20847c478bd9Sstevel@tonic-gate return (WALK_ERR); 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate if (mdb_vread(&fec, sizeof (fec), wsp->walk_addr) == -1) { 20877c478bd9Sstevel@tonic-gate mdb_warn("failed to read fm cache at %p", wsp->walk_addr); 20887c478bd9Sstevel@tonic-gate return (WALK_ERR); 20897c478bd9Sstevel@tonic-gate } 20907c478bd9Sstevel@tonic-gate 2091a5667d81SCheng Sean Ye if (fec.fc_head == NULL) 20927c478bd9Sstevel@tonic-gate return (WALK_DONE); 20937c478bd9Sstevel@tonic-gate 2094a5667d81SCheng Sean Ye wsp->walk_addr = (uintptr_t)fec.fc_head; 20957c478bd9Sstevel@tonic-gate return (WALK_NEXT); 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate 20987c478bd9Sstevel@tonic-gate int 20997c478bd9Sstevel@tonic-gate devinfo_fmc_walk_step(mdb_walk_state_t *wsp) 21007c478bd9Sstevel@tonic-gate { 21017c478bd9Sstevel@tonic-gate int status; 21027c478bd9Sstevel@tonic-gate struct i_ddi_fmc_entry fe; 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate if (mdb_vread(&fe, sizeof (fe), wsp->walk_addr) == -1) { 21057c478bd9Sstevel@tonic-gate mdb_warn("failed to read active fm cache entry at %p", 21067c478bd9Sstevel@tonic-gate wsp->walk_addr); 21077c478bd9Sstevel@tonic-gate return (WALK_DONE); 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, &fe, wsp->walk_cbdata); 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate if (fe.fce_next == NULL) 21137c478bd9Sstevel@tonic-gate return (WALK_DONE); 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)fe.fce_next; 21167c478bd9Sstevel@tonic-gate return (status); 21177c478bd9Sstevel@tonic-gate } 21187c478bd9Sstevel@tonic-gate 21197c478bd9Sstevel@tonic-gate int 21207c478bd9Sstevel@tonic-gate minornode_walk_init(mdb_walk_state_t *wsp) 21217c478bd9Sstevel@tonic-gate { 21227c478bd9Sstevel@tonic-gate struct dev_info di; 21237c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate if (addr == NULL) { 21267c478bd9Sstevel@tonic-gate mdb_warn("a dev_info struct address must be provided\n"); 21277c478bd9Sstevel@tonic-gate return (WALK_ERR); 21287c478bd9Sstevel@tonic-gate } 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate if (mdb_vread(&di, sizeof (di), wsp->walk_addr) == -1) { 21317c478bd9Sstevel@tonic-gate mdb_warn("failed to read dev_info struct at %p", addr); 21327c478bd9Sstevel@tonic-gate return (WALK_ERR); 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)di.devi_minor; 21367c478bd9Sstevel@tonic-gate return (WALK_NEXT); 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate int 21407c478bd9Sstevel@tonic-gate minornode_walk_step(mdb_walk_state_t *wsp) 21417c478bd9Sstevel@tonic-gate { 21427c478bd9Sstevel@tonic-gate struct ddi_minor_data md; 21437c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 21447c478bd9Sstevel@tonic-gate 21457c478bd9Sstevel@tonic-gate if (addr == NULL) 21467c478bd9Sstevel@tonic-gate return (WALK_DONE); 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate if (mdb_vread(&md, sizeof (md), addr) == -1) { 21497c478bd9Sstevel@tonic-gate mdb_warn("failed to read dev_info struct at %p", addr); 21507c478bd9Sstevel@tonic-gate return (WALK_DONE); 21517c478bd9Sstevel@tonic-gate } 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)md.next; 21547c478bd9Sstevel@tonic-gate return (wsp->walk_callback(addr, &md, wsp->walk_cbdata)); 21557c478bd9Sstevel@tonic-gate } 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate static const char *const md_type[] = { 21587c478bd9Sstevel@tonic-gate "DDI_MINOR", 21597c478bd9Sstevel@tonic-gate "DDI_ALIAS", 21607c478bd9Sstevel@tonic-gate "DDI_DEFAULT", 21617c478bd9Sstevel@tonic-gate "DDI_I_PATH", 21627c478bd9Sstevel@tonic-gate "?" 21637c478bd9Sstevel@tonic-gate }; 21647c478bd9Sstevel@tonic-gate 21657c478bd9Sstevel@tonic-gate #define MD_TYPE_MAX ((sizeof (md_type) / sizeof (char *)) - 1) 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 21687c478bd9Sstevel@tonic-gate static int 21697c478bd9Sstevel@tonic-gate print_minornode(uintptr_t addr, const void *arg, void *data) 21707c478bd9Sstevel@tonic-gate { 21717c478bd9Sstevel@tonic-gate char name[128]; 21727c478bd9Sstevel@tonic-gate char nodetype[128]; 21737c478bd9Sstevel@tonic-gate char *spectype; 21747c478bd9Sstevel@tonic-gate struct ddi_minor_data *mdp = (struct ddi_minor_data *)arg; 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate if (mdb_readstr(name, sizeof (name), (uintptr_t)mdp->ddm_name) == -1) 21777c478bd9Sstevel@tonic-gate *name = '\0'; 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate if (mdb_readstr(nodetype, sizeof (nodetype), 21807c478bd9Sstevel@tonic-gate (uintptr_t)mdp->ddm_node_type) == -1) 21817c478bd9Sstevel@tonic-gate *nodetype = '\0'; 21827c478bd9Sstevel@tonic-gate 21837c478bd9Sstevel@tonic-gate switch (mdp->ddm_spec_type) { 21847c478bd9Sstevel@tonic-gate case S_IFCHR: spectype = "c"; break; 21857c478bd9Sstevel@tonic-gate case S_IFBLK: spectype = "b"; break; 21867c478bd9Sstevel@tonic-gate default: spectype = "?"; break; 21877c478bd9Sstevel@tonic-gate } 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate mdb_printf("%?p %16lx %-4s %-11s %-10s %s\n", 21907c478bd9Sstevel@tonic-gate addr, mdp->ddm_dev, spectype, md_type[MIN(mdp->type, MD_TYPE_MAX)], 21917c478bd9Sstevel@tonic-gate name, nodetype); 21927c478bd9Sstevel@tonic-gate 21937c478bd9Sstevel@tonic-gate return (WALK_NEXT); 21947c478bd9Sstevel@tonic-gate } 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 21977c478bd9Sstevel@tonic-gate int 21987c478bd9Sstevel@tonic-gate minornodes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 21997c478bd9Sstevel@tonic-gate { 22007c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc != 0) 22017c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) 22047c478bd9Sstevel@tonic-gate mdb_printf("%<u>%?s %16s %-4s %-11s %-10s %-16s%</u>\n", 22057c478bd9Sstevel@tonic-gate "ADDR", "DEV", "SPEC", "TYPE", "NAME", "NODETYPE"); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate if (mdb_pwalk("minornode", print_minornode, NULL, addr) == -1) { 22087c478bd9Sstevel@tonic-gate mdb_warn("can't walk minornode"); 22097c478bd9Sstevel@tonic-gate return (DCMD_ERR); 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate return (DCMD_OK); 22137c478bd9Sstevel@tonic-gate } 2214