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