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 4453 cth * Common Development and Distribution License (the "License"). 6 4453 cth * 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 9074 Judy * 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 /* 27 0 stevel * For machines that support the openprom, fetch and print the list 28 0 stevel * of devices that the kernel has fetched from the prom or conjured up. 29 0 stevel */ 30 0 stevel 31 0 stevel #include <stdio.h> 32 0 stevel #include <stdarg.h> 33 0 stevel #include <stdlib.h> 34 0 stevel #include <fcntl.h> 35 0 stevel #include <ctype.h> 36 0 stevel #include <strings.h> 37 0 stevel #include <unistd.h> 38 0 stevel #include <stropts.h> 39 0 stevel #include <sys/types.h> 40 0 stevel #include <sys/mkdev.h> 41 0 stevel #include <sys/sunddi.h> 42 0 stevel #include <sys/openpromio.h> 43 0 stevel #include <sys/modctl.h> 44 0 stevel #include <sys/stat.h> 45 0 stevel #include <zone.h> 46 0 stevel #include <libnvpair.h> 47 0 stevel #include "prtconf.h" 48 0 stevel 49 0 stevel 50 0 stevel typedef char *(*dump_propname_t)(void *); 51 0 stevel typedef int (*dump_proptype_t)(void *); 52 0 stevel typedef int (*dump_propints_t)(void *, int **); 53 0 stevel typedef int (*dump_propint64_t)(void *, int64_t **); 54 0 stevel typedef int (*dump_propstrings_t)(void *, char **); 55 0 stevel typedef int (*dump_propbytes_t)(void *, uchar_t **); 56 0 stevel typedef int (*dump_proprawdata_t)(void *, uchar_t **); 57 0 stevel 58 0 stevel typedef struct dumpops_common { 59 0 stevel dump_propname_t doc_propname; 60 0 stevel dump_proptype_t doc_proptype; 61 0 stevel dump_propints_t doc_propints; 62 0 stevel dump_propint64_t doc_propint64; 63 0 stevel dump_propstrings_t doc_propstrings; 64 0 stevel dump_propbytes_t doc_propbytes; 65 0 stevel dump_proprawdata_t doc_proprawdata; 66 0 stevel } dumpops_common_t; 67 0 stevel 68 0 stevel static const dumpops_common_t prop_dumpops = { 69 0 stevel (dump_propname_t)di_prop_name, 70 0 stevel (dump_proptype_t)di_prop_type, 71 0 stevel (dump_propints_t)di_prop_ints, 72 0 stevel (dump_propint64_t)di_prop_int64, 73 0 stevel (dump_propstrings_t)di_prop_strings, 74 0 stevel (dump_propbytes_t)di_prop_bytes, 75 0 stevel (dump_proprawdata_t)di_prop_rawdata 76 0 stevel }, pathprop_common_dumpops = { 77 0 stevel (dump_propname_t)di_path_prop_name, 78 0 stevel (dump_proptype_t)di_path_prop_type, 79 0 stevel (dump_propints_t)di_path_prop_ints, 80 0 stevel (dump_propint64_t)di_path_prop_int64s, 81 0 stevel (dump_propstrings_t)di_path_prop_strings, 82 0 stevel (dump_propbytes_t)di_path_prop_bytes, 83 0 stevel (dump_proprawdata_t)di_path_prop_bytes 84 0 stevel }; 85 0 stevel 86 0 stevel typedef void *(*dump_nextprop_t)(void *, void *); 87 0 stevel typedef dev_t (*dump_propdevt_t)(void *); 88 0 stevel 89 0 stevel typedef struct dumpops { 90 0 stevel const dumpops_common_t *dop_common; 91 0 stevel dump_nextprop_t dop_nextprop; 92 0 stevel dump_propdevt_t dop_propdevt; 93 0 stevel } dumpops_t; 94 0 stevel 95 9074 Judy typedef struct di_args { 96 9074 Judy di_prom_handle_t prom_hdl; 97 9074 Judy di_devlink_handle_t devlink_hdl; 98 9074 Judy } di_arg_t; 99 9074 Judy 100 0 stevel static const dumpops_t sysprop_dumpops = { 101 0 stevel &prop_dumpops, 102 0 stevel (dump_nextprop_t)di_prop_sys_next, 103 0 stevel NULL 104 0 stevel }, globprop_dumpops = { 105 0 stevel &prop_dumpops, 106 0 stevel (dump_nextprop_t)di_prop_global_next, 107 0 stevel NULL 108 0 stevel }, drvprop_dumpops = { 109 0 stevel &prop_dumpops, 110 0 stevel (dump_nextprop_t)di_prop_drv_next, 111 0 stevel (dump_propdevt_t)di_prop_devt 112 0 stevel }, hwprop_dumpops = { 113 0 stevel &prop_dumpops, 114 0 stevel (dump_nextprop_t)di_prop_hw_next, 115 0 stevel NULL 116 0 stevel }, pathprop_dumpops = { 117 0 stevel &pathprop_common_dumpops, 118 0 stevel (dump_nextprop_t)di_path_prop_next, 119 0 stevel NULL 120 0 stevel }; 121 0 stevel 122 0 stevel #define PROPNAME(ops) (ops->dop_common->doc_propname) 123 0 stevel #define PROPTYPE(ops) (ops->dop_common->doc_proptype) 124 0 stevel #define PROPINTS(ops) (ops->dop_common->doc_propints) 125 0 stevel #define PROPINT64(ops) (ops->dop_common->doc_propint64) 126 0 stevel #define PROPSTRINGS(ops) (ops->dop_common->doc_propstrings) 127 0 stevel #define PROPBYTES(ops) (ops->dop_common->doc_propbytes) 128 0 stevel #define PROPRAWDATA(ops) (ops->dop_common->doc_proprawdata) 129 0 stevel #define NEXTPROP(ops) (ops->dop_nextprop) 130 0 stevel #define PROPDEVT(ops) (ops->dop_propdevt) 131 0 stevel #define NUM_ELEMENTS(A) (sizeof (A) / sizeof (A[0])) 132 0 stevel 133 0 stevel static int prop_type_guess(const dumpops_t *, void *, void **, int *); 134 9074 Judy static void walk_driver(di_node_t, di_arg_t *); 135 0 stevel static int dump_devs(di_node_t, void *); 136 7224 cth static int dump_prop_list(const dumpops_t *, const char *, 137 7261 cth int, void *, dev_t, int *); 138 0 stevel static int _error(const char *, ...); 139 0 stevel static int is_openprom(); 140 0 stevel static void walk(uchar_t *, uint_t, int); 141 0 stevel static void dump_node(nvlist_t *, int); 142 0 stevel static void dump_prodinfo(di_prom_handle_t, di_node_t, const char **, 143 0 stevel char *, int); 144 0 stevel static di_node_t find_node_by_name(di_prom_handle_t, di_node_t, char *); 145 0 stevel static int get_propval_by_name(di_prom_handle_t, di_node_t, 146 0 stevel const char *, uchar_t **); 147 7261 cth static int dump_compatible(char *, int, di_node_t); 148 0 stevel static void dump_pathing_data(int, di_node_t); 149 0 stevel static void dump_minor_data(int, di_node_t, di_devlink_handle_t); 150 0 stevel static void dump_link_data(int, di_node_t, di_devlink_handle_t); 151 0 stevel static int print_composite_string(const char *, char *, int); 152 0 stevel static void print_one(nvpair_t *, int); 153 0 stevel static int unprintable(char *, int); 154 0 stevel static int promopen(int); 155 0 stevel static void promclose(); 156 0 stevel static di_node_t find_target_node(di_node_t); 157 0 stevel static void node_display_set(di_node_t); 158 0 stevel 159 0 stevel void 160 0 stevel prtconf_devinfo(void) 161 0 stevel { 162 0 stevel struct di_priv_data fetch; 163 9074 Judy di_arg_t di_arg; 164 9074 Judy di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL; 165 0 stevel di_devlink_handle_t devlink_hdl = NULL; 166 0 stevel di_node_t root_node; 167 0 stevel uint_t flag; 168 0 stevel char *rootpath; 169 0 stevel 170 0 stevel dprintf("verbosemode %s\n", opts.o_verbose ? "on" : "off"); 171 0 stevel 172 0 stevel /* determine what info we need to get from kernel */ 173 0 stevel flag = DINFOSUBTREE; 174 0 stevel rootpath = "/"; 175 0 stevel 176 0 stevel if (opts.o_target) { 177 0 stevel flag |= (DINFOMINOR | DINFOPATH); 178 9074 Judy } 179 9074 Judy 180 9074 Judy if (opts.o_pciid) { 181 9074 Judy flag |= DINFOPROP; 182 9074 Judy if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL) 183 9074 Judy exit(_error("di_prom_init() failed.")); 184 0 stevel } 185 0 stevel 186 0 stevel if (opts.o_forcecache) { 187 4453 cth if (dbg.d_forceload) { 188 0 stevel exit(_error(NULL, "option combination not supported")); 189 0 stevel } 190 0 stevel if (strcmp(rootpath, "/") != 0) { 191 0 stevel exit(_error(NULL, "invalid root path for option")); 192 0 stevel } 193 0 stevel flag = DINFOCACHE; 194 4453 cth } else if (opts.o_verbose) { 195 4453 cth flag |= (DINFOPROP | DINFOMINOR | 196 4453 cth DINFOPRIVDATA | DINFOPATH | DINFOLYR); 197 0 stevel } 198 0 stevel 199 0 stevel if (dbg.d_forceload) { 200 0 stevel flag |= DINFOFORCE; 201 0 stevel } 202 0 stevel 203 0 stevel if (opts.o_verbose) { 204 0 stevel init_priv_data(&fetch); 205 0 stevel root_node = di_init_impl(rootpath, flag, &fetch); 206 0 stevel 207 0 stevel /* get devlink (aka aliases) data */ 208 0 stevel if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) 209 0 stevel exit(_error("di_devlink_init() failed.")); 210 0 stevel } else 211 0 stevel root_node = di_init(rootpath, flag); 212 0 stevel 213 0 stevel if (root_node == DI_NODE_NIL) { 214 0 stevel (void) _error(NULL, "devinfo facility not available"); 215 0 stevel /* not an error if this isn't the global zone */ 216 0 stevel if (getzoneid() == GLOBAL_ZONEID) 217 0 stevel exit(-1); 218 0 stevel else 219 0 stevel exit(0); 220 0 stevel } 221 0 stevel 222 9074 Judy di_arg.prom_hdl = prom_hdl; 223 9074 Judy di_arg.devlink_hdl = devlink_hdl; 224 9074 Judy 225 0 stevel /* 226 0 stevel * ...and walk all nodes to report them out... 227 0 stevel */ 228 0 stevel if (dbg.d_bydriver) { 229 0 stevel opts.o_target = 0; 230 9074 Judy walk_driver(root_node, &di_arg); 231 9074 Judy if (prom_hdl != DI_PROM_HANDLE_NIL) 232 9074 Judy di_prom_fini(prom_hdl); 233 0 stevel if (devlink_hdl != NULL) 234 0 stevel (void) di_devlink_fini(&devlink_hdl); 235 0 stevel di_fini(root_node); 236 0 stevel return; 237 0 stevel } 238 0 stevel 239 0 stevel if (opts.o_target) { 240 0 stevel di_node_t target_node, node; 241 0 stevel 242 0 stevel target_node = find_target_node(root_node); 243 0 stevel if (target_node == DI_NODE_NIL) { 244 0 stevel (void) fprintf(stderr, "%s: " 245 4453 cth "invalid device path specified\n", 246 4453 cth opts.o_progname); 247 0 stevel exit(1); 248 0 stevel } 249 0 stevel 250 0 stevel /* mark the target node so we display it */ 251 0 stevel node_display_set(target_node); 252 0 stevel 253 0 stevel if (opts.o_ancestors) { 254 0 stevel /* 255 0 stevel * mark the ancestors of this node so we display 256 0 stevel * them as well 257 0 stevel */ 258 0 stevel node = target_node; 259 0 stevel while (node = di_parent_node(node)) 260 0 stevel node_display_set(node); 261 0 stevel } else { 262 0 stevel /* 263 0 stevel * when we display device tree nodes the indentation 264 0 stevel * level is based off of tree depth. 265 0 stevel * 266 0 stevel * here we increment o_target to reflect the 267 0 stevel * depth of the target node in the tree. we do 268 0 stevel * this so that when we calculate the indentation 269 0 stevel * level we can subtract o_target so that the 270 0 stevel * target node starts with an indentation of zero. 271 0 stevel */ 272 0 stevel node = target_node; 273 0 stevel while (node = di_parent_node(node)) 274 0 stevel opts.o_target++; 275 0 stevel } 276 0 stevel 277 0 stevel if (opts.o_children) { 278 0 stevel /* 279 0 stevel * mark the children of this node so we display 280 0 stevel * them as well 281 0 stevel */ 282 0 stevel (void) di_walk_node(target_node, DI_WALK_CLDFIRST, 283 4453 cth (void *)1, 284 4453 cth (int (*)(di_node_t, void *)) 285 4453 cth node_display_set); 286 0 stevel } 287 0 stevel } 288 0 stevel 289 9074 Judy (void) di_walk_node(root_node, DI_WALK_CLDFIRST, &di_arg, 290 4453 cth dump_devs); 291 0 stevel 292 9074 Judy if (prom_hdl != DI_PROM_HANDLE_NIL) 293 9074 Judy di_prom_fini(prom_hdl); 294 0 stevel if (devlink_hdl != NULL) 295 0 stevel (void) di_devlink_fini(&devlink_hdl); 296 0 stevel di_fini(root_node); 297 0 stevel } 298 0 stevel 299 0 stevel /* 300 0 stevel * utility routines 301 0 stevel */ 302 0 stevel static int 303 0 stevel i_find_target_node(di_node_t node, void *arg) 304 0 stevel { 305 0 stevel di_node_t *target = (di_node_t *)arg; 306 0 stevel 307 0 stevel if (opts.o_devices_path != NULL) { 308 0 stevel char *path; 309 0 stevel 310 0 stevel if ((path = di_devfs_path(node)) == NULL) 311 0 stevel exit(_error("failed to allocate memory")); 312 0 stevel 313 0 stevel if (strcmp(opts.o_devices_path, path) == 0) { 314 0 stevel di_devfs_path_free(path); 315 0 stevel *target = node; 316 0 stevel return (DI_WALK_TERMINATE); 317 0 stevel } 318 0 stevel 319 0 stevel di_devfs_path_free(path); 320 0 stevel } else if (opts.o_devt != DDI_DEV_T_NONE) { 321 0 stevel di_minor_t minor = DI_MINOR_NIL; 322 0 stevel 323 0 stevel while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 324 0 stevel if (opts.o_devt == di_minor_devt(minor)) { 325 0 stevel *target = node; 326 0 stevel return (DI_WALK_TERMINATE); 327 0 stevel } 328 0 stevel } 329 0 stevel } else { 330 0 stevel /* we should never get here */ 331 0 stevel exit(_error(NULL, "internal error")); 332 0 stevel } 333 0 stevel return (DI_WALK_CONTINUE); 334 0 stevel } 335 0 stevel 336 0 stevel static di_node_t 337 0 stevel find_target_node(di_node_t root_node) 338 0 stevel { 339 0 stevel di_node_t target = DI_NODE_NIL; 340 0 stevel 341 0 stevel /* special case to allow displaying of the root node */ 342 0 stevel if (opts.o_devices_path != NULL) { 343 0 stevel if (strlen(opts.o_devices_path) == 0) 344 0 stevel return (root_node); 345 0 stevel if (strcmp(opts.o_devices_path, ".") == 0) 346 0 stevel return (root_node); 347 0 stevel } 348 0 stevel 349 0 stevel (void) di_walk_node(root_node, DI_WALK_CLDFIRST, &target, 350 4453 cth i_find_target_node); 351 0 stevel return (target); 352 0 stevel } 353 0 stevel 354 0 stevel #define NODE_DISPLAY (1<<0) 355 0 stevel 356 0 stevel static long 357 0 stevel node_display(di_node_t node) 358 0 stevel { 359 0 stevel long data = (long)di_node_private_get(node); 360 0 stevel return (data & NODE_DISPLAY); 361 0 stevel } 362 0 stevel 363 0 stevel static void 364 0 stevel node_display_set(di_node_t node) 365 0 stevel { 366 0 stevel long data = (long)di_node_private_get(node); 367 0 stevel data |= NODE_DISPLAY; 368 0 stevel di_node_private_set(node, (void *)data); 369 0 stevel } 370 0 stevel 371 0 stevel #define LNODE_DISPLAYED (1<<0) 372 0 stevel 373 0 stevel static long 374 0 stevel lnode_displayed(di_lnode_t lnode) 375 0 stevel { 376 0 stevel long data = (long)di_lnode_private_get(lnode); 377 0 stevel return (data & LNODE_DISPLAYED); 378 0 stevel } 379 0 stevel 380 0 stevel static void 381 0 stevel lnode_displayed_set(di_lnode_t lnode) 382 0 stevel { 383 0 stevel long data = (long)di_lnode_private_get(lnode); 384 0 stevel data |= LNODE_DISPLAYED; 385 0 stevel di_lnode_private_set(lnode, (void *)data); 386 0 stevel } 387 0 stevel 388 0 stevel static void 389 0 stevel lnode_displayed_clear(di_lnode_t lnode) 390 0 stevel { 391 0 stevel long data = (long)di_lnode_private_get(lnode); 392 0 stevel data &= ~LNODE_DISPLAYED; 393 0 stevel di_lnode_private_set(lnode, (void *)data); 394 0 stevel } 395 0 stevel 396 0 stevel #define MINOR_DISPLAYED (1<<0) 397 0 stevel #define MINOR_PTR (~(0x3)) 398 0 stevel 399 0 stevel static long 400 0 stevel minor_displayed(di_minor_t minor) 401 0 stevel { 402 0 stevel long data = (long)di_minor_private_get(minor); 403 0 stevel return (data & MINOR_DISPLAYED); 404 0 stevel } 405 0 stevel 406 0 stevel static void 407 0 stevel minor_displayed_set(di_minor_t minor) 408 0 stevel { 409 0 stevel long data = (long)di_minor_private_get(minor); 410 0 stevel data |= MINOR_DISPLAYED; 411 0 stevel di_minor_private_set(minor, (void *)data); 412 0 stevel } 413 0 stevel 414 0 stevel static void 415 0 stevel minor_displayed_clear(di_minor_t minor) 416 0 stevel { 417 0 stevel long data = (long)di_minor_private_get(minor); 418 0 stevel data &= ~MINOR_DISPLAYED; 419 0 stevel di_minor_private_set(minor, (void *)data); 420 0 stevel } 421 0 stevel 422 0 stevel static void * 423 0 stevel minor_ptr(di_minor_t minor) 424 0 stevel { 425 0 stevel long data = (long)di_minor_private_get(minor); 426 0 stevel return ((void *)(data & MINOR_PTR)); 427 0 stevel } 428 0 stevel 429 0 stevel static void 430 0 stevel minor_ptr_set(di_minor_t minor, void *ptr) 431 0 stevel { 432 0 stevel long data = (long)di_minor_private_get(minor); 433 0 stevel data = (data & ~MINOR_PTR) | (((long)ptr) & MINOR_PTR); 434 0 stevel di_minor_private_set(minor, (void *)data); 435 0 stevel } 436 0 stevel 437 0 stevel /* 438 0 stevel * In this comment typed properties are those of type DI_PROP_TYPE_UNDEF_IT, 439 0 stevel * DI_PROP_TYPE_BOOLEAN, DI_PROP_TYPE_INT, DI_PROP_TYPE_INT64, 440 0 stevel * DI_PROP_TYPE_BYTE, and DI_PROP_TYPE_STRING. 441 0 stevel * 442 0 stevel * The guessing algorithm is: 443 0 stevel * 1. If the property is typed and the type is consistent with the value of 444 0 stevel * the property, then the property is of that type. If the type is not 445 0 stevel * consistent with value of the property, then the type is treated as 446 0 stevel * alien to prtconf. 447 0 stevel * 2. If the property is of type DI_PROP_TYPE_UNKNOWN the following steps 448 0 stevel * are carried out. 449 0 stevel * a. If the value of the property is consistent with a string property, 450 0 stevel * the type of the property is DI_PROP_TYPE_STRING. 451 0 stevel * b. Otherwise, if the value of the property is consistent with an integer 452 0 stevel * property, the type of the property is DI_PROP_TYPE_INT. 453 0 stevel * c. Otherwise, the property type is treated as alien to prtconf. 454 0 stevel * 3. If the property type is alien to prtconf, then the property value is 455 0 stevel * read by the appropriate routine for untyped properties and the following 456 0 stevel * steps are carried out. 457 0 stevel * a. If the length that the property routine returned is zero, the 458 0 stevel * property is of type DI_PROP_TYPE_BOOLEAN. 459 0 stevel * b. Otherwise, if the length that the property routine returned is 460 0 stevel * positive, then the property value is treated as raw data of type 461 0 stevel * DI_PROP_TYPE_UNKNOWN. 462 0 stevel * c. Otherwise, if the length that the property routine returned is 463 0 stevel * negative, then there is some internal inconsistency and this is 464 0 stevel * treated as an error and no type is determined. 465 0 stevel */ 466 0 stevel static int 467 0 stevel prop_type_guess(const dumpops_t *propops, void *prop, void **prop_data, 468 0 stevel int *prop_type) 469 0 stevel { 470 0 stevel int len, type; 471 0 stevel 472 0 stevel type = PROPTYPE(propops)(prop); 473 0 stevel switch (type) { 474 0 stevel case DI_PROP_TYPE_UNDEF_IT: 475 0 stevel case DI_PROP_TYPE_BOOLEAN: 476 0 stevel *prop_data = NULL; 477 0 stevel *prop_type = type; 478 0 stevel return (0); 479 0 stevel case DI_PROP_TYPE_INT: 480 0 stevel len = PROPINTS(propops)(prop, (int **)prop_data); 481 0 stevel break; 482 0 stevel case DI_PROP_TYPE_INT64: 483 0 stevel len = PROPINT64(propops)(prop, (int64_t **)prop_data); 484 0 stevel break; 485 0 stevel case DI_PROP_TYPE_BYTE: 486 0 stevel len = PROPBYTES(propops)(prop, (uchar_t **)prop_data); 487 0 stevel break; 488 0 stevel case DI_PROP_TYPE_STRING: 489 0 stevel len = PROPSTRINGS(propops)(prop, (char **)prop_data); 490 0 stevel break; 491 0 stevel case DI_PROP_TYPE_UNKNOWN: 492 0 stevel len = PROPSTRINGS(propops)(prop, (char **)prop_data); 493 0 stevel if ((len > 0) && ((*(char **)prop_data)[0] != 0)) { 494 0 stevel *prop_type = DI_PROP_TYPE_STRING; 495 0 stevel return (len); 496 0 stevel } 497 0 stevel 498 0 stevel len = PROPINTS(propops)(prop, (int **)prop_data); 499 0 stevel type = DI_PROP_TYPE_INT; 500 0 stevel 501 0 stevel break; 502 0 stevel default: 503 0 stevel len = -1; 504 0 stevel } 505 0 stevel 506 0 stevel if (len > 0) { 507 0 stevel *prop_type = type; 508 0 stevel return (len); 509 0 stevel } 510 0 stevel 511 0 stevel len = PROPRAWDATA(propops)(prop, (uchar_t **)prop_data); 512 0 stevel if (len < 0) { 513 0 stevel return (-1); 514 0 stevel } else if (len == 0) { 515 0 stevel *prop_type = DI_PROP_TYPE_BOOLEAN; 516 0 stevel return (0); 517 0 stevel } 518 0 stevel 519 0 stevel *prop_type = DI_PROP_TYPE_UNKNOWN; 520 0 stevel return (len); 521 0 stevel } 522 0 stevel 523 7224 cth /* 524 7224 cth * Returns 0 if nothing is printed, 1 otherwise 525 7224 cth */ 526 7224 cth static int 527 7224 cth dump_prop_list(const dumpops_t *dumpops, const char *name, int ilev, 528 7261 cth void *node, dev_t dev, int *compat_printed) 529 0 stevel { 530 7224 cth void *prop = DI_PROP_NIL, *prop_data; 531 7224 cth di_minor_t minor; 532 7224 cth char *p; 533 7224 cth int i, prop_type, nitems; 534 7224 cth dev_t pdev; 535 7224 cth int nprop = 0; 536 7261 cth 537 7261 cth if (compat_printed) 538 7261 cth *compat_printed = 0; 539 0 stevel 540 0 stevel while ((prop = NEXTPROP(dumpops)(node, prop)) != DI_PROP_NIL) { 541 7224 cth 542 7224 cth /* Skip properties a dev_t oriented caller is not requesting */ 543 7224 cth if (PROPDEVT(dumpops)) { 544 7224 cth pdev = PROPDEVT(dumpops)(prop); 545 7224 cth 546 7224 cth if (dev == DDI_DEV_T_ANY) { 547 7224 cth /* 548 7224 cth * Caller requesting print all properties 549 7224 cth */ 550 7224 cth goto print; 551 7224 cth } else if (dev == DDI_DEV_T_NONE) { 552 7224 cth /* 553 7224 cth * Caller requesting print of properties 554 7224 cth * associated with devinfo (not minor). 555 7224 cth */ 556 7224 cth if ((pdev == DDI_DEV_T_ANY) || 557 7224 cth (pdev == DDI_DEV_T_NONE)) 558 7224 cth goto print; 559 7224 cth 560 7224 cth /* 561 7224 cth * Property has a minor association, see if 562 7224 cth * we have a minor with this dev_t. If there 563 7224 cth * is no such minor we print the property now 564 7224 cth * so it gets displayed. 565 7224 cth */ 566 7224 cth minor = DI_MINOR_NIL; 567 7224 cth while ((minor = di_minor_next((di_node_t)node, 568 7224 cth minor)) != DI_MINOR_NIL) { 569 7224 cth if (di_minor_devt(minor) == pdev) 570 7224 cth break; 571 7224 cth } 572 7224 cth if (minor == DI_MINOR_NIL) 573 7224 cth goto print; 574 7224 cth } else if (dev == pdev) { 575 7224 cth /* 576 7224 cth * Caller requesting print of properties 577 7224 cth * associated with a specific matching minor 578 7224 cth * node. 579 7224 cth */ 580 7224 cth goto print; 581 7224 cth } 582 7224 cth 583 7224 cth /* otherwise skip print */ 584 7224 cth continue; 585 7224 cth } 586 7224 cth 587 7224 cth print: nitems = prop_type_guess(dumpops, prop, &prop_data, &prop_type); 588 0 stevel if (nitems < 0) 589 0 stevel continue; 590 7224 cth 591 7224 cth if (nprop == 0) { 592 7224 cth if (name) { 593 7224 cth indent_to_level(ilev); 594 7224 cth (void) printf("%s properties:\n", name); 595 7224 cth } 596 7224 cth ilev++; 597 7224 cth } 598 7224 cth nprop++; 599 0 stevel 600 0 stevel indent_to_level(ilev); 601 0 stevel (void) printf("name='%s' type=", PROPNAME(dumpops)(prop)); 602 7261 cth 603 7261 cth /* report 'compatible' as processed */ 604 7261 cth if (compat_printed && 605 7261 cth (strcmp(PROPNAME(dumpops)(prop), "compatible") == 0)) 606 7261 cth *compat_printed = 1; 607 0 stevel 608 0 stevel switch (prop_type) { 609 0 stevel case DI_PROP_TYPE_UNDEF_IT: 610 0 stevel (void) printf("undef"); 611 0 stevel break; 612 0 stevel case DI_PROP_TYPE_BOOLEAN: 613 0 stevel (void) printf("boolean"); 614 0 stevel break; 615 0 stevel case DI_PROP_TYPE_INT: 616 0 stevel (void) printf("int"); 617 0 stevel break; 618 0 stevel case DI_PROP_TYPE_INT64: 619 0 stevel (void) printf("int64"); 620 0 stevel break; 621 0 stevel case DI_PROP_TYPE_BYTE: 622 0 stevel (void) printf("byte"); 623 0 stevel break; 624 0 stevel case DI_PROP_TYPE_STRING: 625 0 stevel (void) printf("string"); 626 0 stevel break; 627 0 stevel case DI_PROP_TYPE_UNKNOWN: 628 0 stevel (void) printf("unknown"); 629 0 stevel break; 630 0 stevel default: 631 0 stevel /* Should never be here */ 632 0 stevel (void) printf("0x%x", prop_type); 633 0 stevel } 634 0 stevel 635 0 stevel if (nitems != 0) 636 0 stevel (void) printf(" items=%i", nitems); 637 0 stevel 638 0 stevel /* print the major and minor numbers for a device property */ 639 7224 cth if (PROPDEVT(dumpops)) { 640 7224 cth if ((pdev == DDI_DEV_T_NONE) || 641 7224 cth (pdev == DDI_DEV_T_ANY)) { 642 7224 cth (void) printf(" dev=none"); 643 7224 cth } else { 644 0 stevel (void) printf(" dev=(%u,%u)", 645 7224 cth (uint_t)major(pdev), (uint_t)minor(pdev)); 646 0 stevel } 647 0 stevel } 648 0 stevel 649 0 stevel (void) putchar('\n'); 650 0 stevel 651 0 stevel if (nitems == 0) 652 0 stevel continue; 653 0 stevel 654 0 stevel indent_to_level(ilev); 655 0 stevel 656 0 stevel (void) printf(" value="); 657 0 stevel 658 0 stevel switch (prop_type) { 659 0 stevel case DI_PROP_TYPE_INT: 660 0 stevel for (i = 0; i < nitems - 1; i++) 661 0 stevel (void) printf("%8.8x.", ((int *)prop_data)[i]); 662 0 stevel (void) printf("%8.8x", ((int *)prop_data)[i]); 663 0 stevel break; 664 0 stevel case DI_PROP_TYPE_INT64: 665 0 stevel for (i = 0; i < nitems - 1; i++) 666 0 stevel (void) printf("%16.16llx.", 667 0 stevel ((long long *)prop_data)[i]); 668 0 stevel (void) printf("%16.16llx", ((long long *)prop_data)[i]); 669 0 stevel break; 670 0 stevel case DI_PROP_TYPE_STRING: 671 0 stevel p = (char *)prop_data; 672 0 stevel for (i = 0; i < nitems - 1; i++) { 673 0 stevel (void) printf("'%s' + ", p); 674 0 stevel p += strlen(p) + 1; 675 0 stevel } 676 0 stevel (void) printf("'%s'", p); 677 0 stevel break; 678 0 stevel default: 679 0 stevel for (i = 0; i < nitems - 1; i++) 680 0 stevel (void) printf("%2.2x.", 681 0 stevel ((uint8_t *)prop_data)[i]); 682 0 stevel (void) printf("%2.2x", ((uint8_t *)prop_data)[i]); 683 0 stevel } 684 0 stevel 685 0 stevel (void) putchar('\n'); 686 0 stevel } 687 7224 cth 688 7224 cth return (nprop ? 1 : 0); 689 0 stevel } 690 0 stevel 691 0 stevel /* 692 0 stevel * walk_driver is a debugging facility. 693 0 stevel */ 694 0 stevel static void 695 9074 Judy walk_driver(di_node_t root, di_arg_t *di_arg) 696 0 stevel { 697 0 stevel di_node_t node; 698 0 stevel 699 0 stevel node = di_drv_first_node(dbg.d_drivername, root); 700 0 stevel 701 0 stevel while (node != DI_NODE_NIL) { 702 9074 Judy (void) dump_devs(node, di_arg); 703 0 stevel node = di_drv_next_node(node); 704 0 stevel } 705 0 stevel } 706 0 stevel 707 0 stevel /* 708 0 stevel * print out information about this node, returns appropriate code. 709 0 stevel */ 710 0 stevel /*ARGSUSED1*/ 711 0 stevel static int 712 0 stevel dump_devs(di_node_t node, void *arg) 713 0 stevel { 714 9074 Judy di_arg_t *di_arg = arg; 715 9074 Judy di_devlink_handle_t devlink_hdl = di_arg->devlink_hdl; 716 0 stevel int ilev = 0; /* indentation level */ 717 0 stevel char *driver_name; 718 0 stevel di_node_t root_node, tmp; 719 7261 cth int compat_printed; 720 7261 cth int printed; 721 0 stevel 722 0 stevel if (dbg.d_debug) { 723 0 stevel char *path = di_devfs_path(node); 724 0 stevel dprintf("Dump node %s\n", path); 725 0 stevel di_devfs_path_free(path); 726 0 stevel } 727 0 stevel 728 0 stevel if (dbg.d_bydriver) { 729 0 stevel ilev = 1; 730 0 stevel } else { 731 0 stevel /* figure out indentation level */ 732 0 stevel tmp = node; 733 0 stevel while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL) 734 0 stevel ilev++; 735 0 stevel 736 0 stevel if (opts.o_target && !opts.o_ancestors) { 737 0 stevel ilev -= opts.o_target - 1; 738 0 stevel } 739 0 stevel } 740 0 stevel 741 0 stevel if (opts.o_target && !node_display(node)) { 742 0 stevel /* 743 0 stevel * if we're only displaying certain nodes and this one 744 0 stevel * isn't flagged, skip it. 745 0 stevel */ 746 0 stevel return (DI_WALK_CONTINUE); 747 0 stevel } 748 0 stevel 749 0 stevel indent_to_level(ilev); 750 0 stevel 751 0 stevel (void) printf("%s", di_node_name(node)); 752 9074 Judy if (opts.o_pciid) 753 9074 Judy (void) print_pciid(node, di_arg->prom_hdl); 754 0 stevel 755 0 stevel /* 756 0 stevel * if this node does not have an instance number or is the 757 0 stevel * root node (1229946), we don't print an instance number 758 0 stevel */ 759 0 stevel root_node = tmp = node; 760 0 stevel while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL) 761 0 stevel root_node = tmp; 762 0 stevel if ((di_instance(node) >= 0) && (node != root_node)) 763 0 stevel (void) printf(", instance #%d", di_instance(node)); 764 0 stevel 765 0 stevel if (opts.o_drv_name) { 766 0 stevel driver_name = di_driver_name(node); 767 0 stevel if (driver_name != NULL) 768 0 stevel (void) printf(" (driver name: %s)", driver_name); 769 4845 vikram } else if (di_retired(node)) { 770 4845 vikram (void) printf(" (retired)"); 771 0 stevel } else if (di_state(node) & DI_DRIVER_DETACHED) 772 0 stevel (void) printf(" (driver not attached)"); 773 0 stevel (void) printf("\n"); 774 0 stevel 775 0 stevel if (opts.o_verbose) { 776 0 stevel if (dump_prop_list(&sysprop_dumpops, "System", ilev + 1, 777 7261 cth node, DDI_DEV_T_ANY, NULL)) { 778 0 stevel (void) dump_prop_list(&globprop_dumpops, NULL, ilev + 1, 779 7261 cth node, DDI_DEV_T_ANY, NULL); 780 0 stevel } else { 781 0 stevel (void) dump_prop_list(&globprop_dumpops, 782 7261 cth "System software", ilev + 1, 783 7261 cth node, DDI_DEV_T_ANY, NULL); 784 0 stevel } 785 0 stevel (void) dump_prop_list(&drvprop_dumpops, "Driver", ilev + 1, 786 7261 cth node, DDI_DEV_T_NONE, NULL); 787 7261 cth 788 7261 cth printed = dump_prop_list(&hwprop_dumpops, "Hardware", 789 7261 cth ilev + 1, node, DDI_DEV_T_ANY, &compat_printed); 790 7261 cth 791 7261 cth /* Ensure that 'compatible' is printed under Hardware header */ 792 7261 cth if (!compat_printed) 793 7261 cth (void) dump_compatible(printed ? NULL : "Hardware", 794 7261 cth ilev + 1, node); 795 7261 cth 796 0 stevel dump_priv_data(ilev + 1, node); 797 0 stevel dump_pathing_data(ilev + 1, node); 798 0 stevel dump_link_data(ilev + 1, node, devlink_hdl); 799 0 stevel dump_minor_data(ilev + 1, node, devlink_hdl); 800 0 stevel } 801 0 stevel 802 0 stevel if (opts.o_target) 803 0 stevel return (DI_WALK_CONTINUE); 804 0 stevel 805 0 stevel if (!opts.o_pseudodevs && (strcmp(di_node_name(node), "pseudo") == 0)) 806 0 stevel return (DI_WALK_PRUNECHILD); 807 0 stevel 808 0 stevel return (DI_WALK_CONTINUE); 809 0 stevel } 810 0 stevel 811 0 stevel /* _error([no_perror, ] fmt [, arg ...]) */ 812 0 stevel static int 813 0 stevel _error(const char *opt_noperror, ...) 814 0 stevel { 815 0 stevel int saved_errno; 816 0 stevel va_list ap; 817 0 stevel int no_perror = 0; 818 0 stevel const char *fmt; 819 0 stevel 820 0 stevel saved_errno = errno; 821 0 stevel 822 0 stevel (void) fprintf(stderr, "%s: ", opts.o_progname); 823 0 stevel 824 0 stevel va_start(ap, opt_noperror); 825 0 stevel if (opt_noperror == NULL) { 826 0 stevel no_perror = 1; 827 0 stevel fmt = va_arg(ap, char *); 828 0 stevel } else 829 0 stevel fmt = opt_noperror; 830 0 stevel (void) vfprintf(stderr, fmt, ap); 831 0 stevel va_end(ap); 832 0 stevel 833 0 stevel if (no_perror) 834 0 stevel (void) fprintf(stderr, "\n"); 835 0 stevel else { 836 0 stevel (void) fprintf(stderr, ": "); 837 0 stevel errno = saved_errno; 838 0 stevel perror(""); 839 0 stevel } 840 0 stevel 841 0 stevel return (-1); 842 0 stevel } 843 0 stevel 844 0 stevel 845 0 stevel /* 846 0 stevel * The rest of the routines handle printing the raw prom devinfo (-p option). 847 0 stevel * 848 0 stevel * 128 is the size of the largest (currently) property name 849 0 stevel * 16k - MAXNAMESZ - sizeof (int) is the size of the largest 850 0 stevel * (currently) property value that is allowed. 851 0 stevel * the sizeof (uint_t) is from struct openpromio 852 0 stevel */ 853 0 stevel 854 0 stevel #define MAXNAMESZ 128 855 0 stevel #define MAXVALSIZE (16384 - MAXNAMESZ - sizeof (uint_t)) 856 0 stevel #define BUFSIZE (MAXNAMESZ + MAXVALSIZE + sizeof (uint_t)) 857 0 stevel typedef union { 858 0 stevel char buf[BUFSIZE]; 859 0 stevel struct openpromio opp; 860 0 stevel } Oppbuf; 861 0 stevel 862 0 stevel static int prom_fd; 863 0 stevel static uchar_t *prom_snapshot; 864 0 stevel 865 0 stevel static int 866 0 stevel is_openprom(void) 867 0 stevel { 868 0 stevel Oppbuf oppbuf; 869 0 stevel struct openpromio *opp = &(oppbuf.opp); 870 0 stevel unsigned int i; 871 0 stevel 872 0 stevel opp->oprom_size = MAXVALSIZE; 873 0 stevel if (ioctl(prom_fd, OPROMGETCONS, opp) < 0) 874 0 stevel exit(_error("OPROMGETCONS")); 875 0 stevel 876 0 stevel i = (unsigned int)((unsigned char)opp->oprom_array[0]); 877 0 stevel return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM); 878 0 stevel } 879 0 stevel 880 0 stevel int 881 0 stevel do_prominfo(void) 882 0 stevel { 883 0 stevel uint_t arg = opts.o_verbose; 884 0 stevel 885 0 stevel if (promopen(O_RDONLY)) { 886 0 stevel exit(_error("openeepr device open failed")); 887 0 stevel } 888 0 stevel 889 0 stevel if (is_openprom() == 0) { 890 0 stevel (void) fprintf(stderr, "System architecture does not " 891 0 stevel "support this option of this command.\n"); 892 0 stevel return (1); 893 0 stevel } 894 0 stevel 895 0 stevel /* OPROMSNAPSHOT returns size in arg */ 896 0 stevel if (ioctl(prom_fd, OPROMSNAPSHOT, &arg) < 0) 897 0 stevel exit(_error("OPROMSNAPSHOT")); 898 0 stevel 899 0 stevel if (arg == 0) 900 0 stevel return (1); 901 0 stevel 902 0 stevel if ((prom_snapshot = malloc(arg)) == NULL) 903 0 stevel exit(_error("failed to allocate memory")); 904 0 stevel 905 0 stevel /* copy out the snapshot for printing */ 906 0 stevel /*LINTED*/ 907 0 stevel *(uint_t *)prom_snapshot = arg; 908 0 stevel if (ioctl(prom_fd, OPROMCOPYOUT, prom_snapshot) < 0) 909 0 stevel exit(_error("OPROMCOPYOUT")); 910 0 stevel 911 0 stevel promclose(); 912 0 stevel 913 0 stevel /* print out information */ 914 0 stevel walk(prom_snapshot, arg, 0); 915 0 stevel free(prom_snapshot); 916 0 stevel 917 0 stevel return (0); 918 0 stevel } 919 0 stevel 920 0 stevel static void 921 0 stevel walk(uchar_t *buf, uint_t size, int level) 922 0 stevel { 923 0 stevel int error; 924 0 stevel nvlist_t *nvl, *cnvl; 925 0 stevel nvpair_t *child = NULL; 926 0 stevel uchar_t *cbuf = NULL; 927 0 stevel uint_t csize; 928 0 stevel 929 0 stevel /* Expand to an nvlist */ 930 0 stevel if (nvlist_unpack((char *)buf, size, &nvl, 0)) 931 0 stevel exit(_error("error processing snapshot")); 932 0 stevel 933 0 stevel /* print current node */ 934 0 stevel dump_node(nvl, level); 935 0 stevel 936 0 stevel /* print children */ 937 0 stevel error = nvlist_lookup_byte_array(nvl, "@child", &cbuf, &csize); 938 0 stevel if ((error == ENOENT) || (cbuf == NULL)) 939 0 stevel return; /* no child exists */ 940 0 stevel 941 0 stevel if (error || nvlist_unpack((char *)cbuf, csize, &cnvl, 0)) 942 0 stevel exit(_error("error processing snapshot")); 943 0 stevel 944 0 stevel while (child = nvlist_next_nvpair(cnvl, child)) { 945 0 stevel char *name = nvpair_name(child); 946 0 stevel data_type_t type = nvpair_type(child); 947 0 stevel uchar_t *nodebuf; 948 0 stevel uint_t nodesize; 949 0 stevel if (strcmp("node", name) != 0) { 950 0 stevel dprintf("unexpected nvpair name %s != name\n", name); 951 0 stevel continue; 952 0 stevel } 953 0 stevel if (type != DATA_TYPE_BYTE_ARRAY) { 954 0 stevel dprintf("unexpected nvpair type %d, not byte array \n", 955 0 stevel type); 956 0 stevel continue; 957 0 stevel } 958 0 stevel 959 0 stevel (void) nvpair_value_byte_array(child, 960 0 stevel (uchar_t **)&nodebuf, &nodesize); 961 0 stevel walk(nodebuf, nodesize, level + 1); 962 0 stevel } 963 0 stevel 964 0 stevel nvlist_free(nvl); 965 0 stevel } 966 0 stevel 967 0 stevel /* 968 0 stevel * Print all properties and values 969 0 stevel */ 970 0 stevel static void 971 0 stevel dump_node(nvlist_t *nvl, int level) 972 0 stevel { 973 0 stevel int id = 0; 974 0 stevel char *name = NULL; 975 0 stevel nvpair_t *nvp = NULL; 976 0 stevel 977 0 stevel indent_to_level(level); 978 0 stevel (void) printf("Node"); 979 0 stevel if (!opts.o_verbose) { 980 0 stevel if (nvlist_lookup_string(nvl, "name", &name)) 981 0 stevel (void) printf("data not available"); 982 0 stevel else 983 0 stevel (void) printf(" '%s'", name); 984 0 stevel (void) putchar('\n'); 985 0 stevel return; 986 0 stevel } 987 0 stevel (void) nvlist_lookup_int32(nvl, "@nodeid", &id); 988 0 stevel (void) printf(" %#08x\n", id); 989 0 stevel 990 0 stevel while (nvp = nvlist_next_nvpair(nvl, nvp)) { 991 0 stevel name = nvpair_name(nvp); 992 0 stevel if (name[0] == '@') 993 0 stevel continue; 994 0 stevel 995 0 stevel print_one(nvp, level + 1); 996 0 stevel } 997 0 stevel (void) putchar('\n'); 998 0 stevel } 999 0 stevel 1000 0 stevel static const char * 1001 0 stevel path_state_name(di_path_state_t st) 1002 0 stevel { 1003 0 stevel switch (st) { 1004 0 stevel case DI_PATH_STATE_ONLINE: 1005 0 stevel return ("online"); 1006 0 stevel case DI_PATH_STATE_STANDBY: 1007 0 stevel return ("standby"); 1008 0 stevel case DI_PATH_STATE_OFFLINE: 1009 0 stevel return ("offline"); 1010 0 stevel case DI_PATH_STATE_FAULT: 1011 0 stevel return ("faulted"); 1012 0 stevel } 1013 0 stevel return ("unknown"); 1014 0 stevel } 1015 0 stevel 1016 0 stevel /* 1017 0 stevel * Print all phci's each client is connected to. 1018 0 stevel */ 1019 0 stevel static void 1020 0 stevel dump_pathing_data(int ilev, di_node_t node) 1021 0 stevel { 1022 6640 cth di_path_t pi = DI_PATH_NIL; 1023 6640 cth di_node_t phci_node; 1024 6640 cth char *phci_path; 1025 6640 cth int path_instance; 1026 6640 cth int firsttime = 1; 1027 0 stevel 1028 0 stevel if (node == DI_PATH_NIL) 1029 0 stevel return; 1030 0 stevel 1031 6640 cth while ((pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) { 1032 10696 David 1033 10696 David /* It is not really a path if we failed to capture the pHCI */ 1034 10696 David phci_node = di_path_phci_node(pi); 1035 10696 David if (phci_node == DI_NODE_NIL) 1036 10696 David continue; 1037 10696 David 1038 10696 David /* Print header for the first path */ 1039 0 stevel if (firsttime) { 1040 0 stevel indent_to_level(ilev); 1041 0 stevel firsttime = 0; 1042 0 stevel ilev++; 1043 0 stevel (void) printf("Paths from multipath bus adapters:\n"); 1044 0 stevel } 1045 0 stevel 1046 6640 cth /* 1047 6640 cth * Print the path instance and full "pathinfo" path, which is 1048 6640 cth * the same as the /devices devifo path had the device been 1049 6640 cth * enumerated under pHCI. 1050 6640 cth */ 1051 6640 cth phci_path = di_devfs_path(phci_node); 1052 6640 cth if (phci_path) { 1053 10696 David path_instance = di_path_instance(pi); 1054 6640 cth if (path_instance > 0) { 1055 6640 cth indent_to_level(ilev); 1056 6640 cth (void) printf("Path %d: %s/%s@%s\n", 1057 6640 cth path_instance, phci_path, 1058 6640 cth di_node_name(node), 1059 6640 cth di_path_bus_addr(pi)); 1060 6640 cth } 1061 6640 cth di_devfs_path_free(phci_path); 1062 6640 cth } 1063 6640 cth 1064 6640 cth /* print phci driver, instance, and path state information */ 1065 0 stevel indent_to_level(ilev); 1066 0 stevel (void) printf("%s#%d (%s)\n", di_driver_name(phci_node), 1067 0 stevel di_instance(phci_node), path_state_name(di_path_state(pi))); 1068 10696 David 1069 7224 cth (void) dump_prop_list(&pathprop_dumpops, NULL, ilev + 1, 1070 7261 cth pi, DDI_DEV_T_ANY, NULL); 1071 0 stevel } 1072 0 stevel } 1073 0 stevel 1074 0 stevel static int 1075 0 stevel dump_minor_data_links(di_devlink_t devlink, void *arg) 1076 0 stevel { 1077 0 stevel int ilev = (intptr_t)arg; 1078 0 stevel indent_to_level(ilev); 1079 0 stevel (void) printf("dev_link=%s\n", di_devlink_path(devlink)); 1080 0 stevel return (DI_WALK_CONTINUE); 1081 0 stevel } 1082 0 stevel 1083 0 stevel static void 1084 0 stevel dump_minor_data_paths(int ilev, di_minor_t minor, 1085 0 stevel di_devlink_handle_t devlink_hdl) 1086 0 stevel { 1087 0 stevel char *path, *type; 1088 0 stevel int spec_type; 1089 0 stevel 1090 0 stevel /* get the path to the device and the minor node name */ 1091 0 stevel if ((path = di_devfs_minor_path(minor)) == NULL) 1092 0 stevel exit(_error("failed to allocate memory")); 1093 0 stevel 1094 0 stevel /* display the path to this minor node */ 1095 0 stevel indent_to_level(ilev); 1096 0 stevel (void) printf("dev_path=%s\n", path); 1097 0 stevel 1098 0 stevel if (devlink_hdl != NULL) { 1099 0 stevel 1100 0 stevel /* get the device minor node information */ 1101 0 stevel spec_type = di_minor_spectype(minor); 1102 0 stevel switch (di_minor_type(minor)) { 1103 0 stevel case DDM_MINOR: 1104 0 stevel type = "minor"; 1105 0 stevel break; 1106 0 stevel case DDM_ALIAS: 1107 0 stevel type = "alias"; 1108 0 stevel break; 1109 0 stevel case DDM_DEFAULT: 1110 0 stevel type = "default"; 1111 0 stevel break; 1112 0 stevel case DDM_INTERNAL_PATH: 1113 0 stevel type = "internal"; 1114 0 stevel break; 1115 0 stevel default: 1116 0 stevel type = "unknown"; 1117 0 stevel break; 1118 0 stevel } 1119 0 stevel 1120 0 stevel /* display the device minor node information */ 1121 0 stevel indent_to_level(ilev + 1); 1122 0 stevel (void) printf("spectype=%s type=%s\n", 1123 4453 cth (spec_type == S_IFBLK) ? "blk" : "chr", type); 1124 0 stevel 1125 0 stevel /* display all the devlinks for this device minor node */ 1126 0 stevel (void) di_devlink_walk(devlink_hdl, NULL, path, 1127 0 stevel 0, (void *)(intptr_t)(ilev + 1), dump_minor_data_links); 1128 0 stevel } 1129 0 stevel 1130 0 stevel di_devfs_path_free(path); 1131 0 stevel } 1132 0 stevel 1133 0 stevel static void 1134 0 stevel create_minor_list(di_node_t node) 1135 0 stevel { 1136 0 stevel di_minor_t minor, minor_head, minor_tail, minor_prev, minor_walk; 1137 0 stevel int major; 1138 0 stevel 1139 0 stevel /* if there are no minor nodes, bail */ 1140 0 stevel if (di_minor_next(node, DI_MINOR_NIL) == DI_MINOR_NIL) 1141 0 stevel return; 1142 0 stevel 1143 0 stevel /* 1144 0 stevel * here we want to create lists of minor nodes with the same 1145 0 stevel * dev_t. to do this we first sort all the minor nodes by devt. 1146 0 stevel * 1147 0 stevel * the algorithm used here is a bubble sort, so performance sucks. 1148 0 stevel * but it's probably ok here because most device instances don't 1149 0 stevel * have that many minor nodes. also we're doing this as we're 1150 0 stevel * displaying each node so it doesn't look like we're pausing 1151 0 stevel * output for a long time. 1152 0 stevel */ 1153 0 stevel major = di_driver_major(node); 1154 0 stevel minor_head = minor_tail = minor = DI_MINOR_NIL; 1155 0 stevel while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 1156 0 stevel dev_t dev = di_minor_devt(minor); 1157 0 stevel 1158 0 stevel /* skip /pseudo/clone@0 minor nodes */ 1159 0 stevel if (major != major(dev)) 1160 0 stevel continue; 1161 0 stevel 1162 0 stevel minor_ptr_set(minor, DI_MINOR_NIL); 1163 0 stevel if (minor_head == DI_MINOR_NIL) { 1164 0 stevel /* this is the first minor node we're looking at */ 1165 0 stevel minor_head = minor_tail = minor; 1166 0 stevel continue; 1167 0 stevel } 1168 0 stevel 1169 0 stevel /* 1170 0 stevel * if the new dev is less than the old dev, update minor_head 1171 0 stevel * so it points to the beginning of the list. ie it points 1172 0 stevel * to the node with the lowest dev value 1173 0 stevel */ 1174 0 stevel if (dev <= di_minor_devt(minor_head)) { 1175 0 stevel minor_ptr_set(minor, minor_head); 1176 0 stevel minor_head = minor; 1177 0 stevel continue; 1178 0 stevel } 1179 0 stevel 1180 0 stevel minor_prev = minor_head; 1181 0 stevel minor_walk = minor_ptr(minor_head); 1182 0 stevel while ((minor_walk != DI_MINOR_NIL) && 1183 4453 cth (dev > di_minor_devt(minor_walk))) { 1184 0 stevel minor_prev = minor_walk; 1185 0 stevel minor_walk = minor_ptr(minor_walk); 1186 0 stevel } 1187 0 stevel minor_ptr_set(minor, minor_walk); 1188 0 stevel minor_ptr_set(minor_prev, minor); 1189 0 stevel if (minor_walk == NULL) 1190 0 stevel minor_tail = minor; 1191 0 stevel } 1192 0 stevel 1193 0 stevel /* check if there were any non /pseudo/clone@0 nodes. if not, bail */ 1194 0 stevel if (minor_head == DI_MINOR_NIL) 1195 0 stevel return; 1196 0 stevel 1197 0 stevel /* 1198 0 stevel * now that we have a list of minor nodes sorted by devt 1199 0 stevel * we walk through the list and break apart the entire list 1200 0 stevel * to create circular lists of minor nodes with matching devts. 1201 0 stevel */ 1202 0 stevel minor_prev = minor_head; 1203 0 stevel minor_walk = minor_ptr(minor_head); 1204 0 stevel while (minor_walk != DI_MINOR_NIL) { 1205 0 stevel if (di_minor_devt(minor_prev) != di_minor_devt(minor_walk)) { 1206 0 stevel minor_ptr_set(minor_prev, minor_head); 1207 0 stevel minor_head = minor_walk; 1208 0 stevel } 1209 0 stevel minor_prev = minor_walk; 1210 0 stevel minor_walk = minor_ptr(minor_walk); 1211 0 stevel } 1212 0 stevel minor_ptr_set(minor_tail, minor_head); 1213 0 stevel } 1214 0 stevel 1215 0 stevel static void 1216 0 stevel link_lnode_disp(di_link_t link, uint_t endpoint, int ilev, 1217 0 stevel di_devlink_handle_t devlink_hdl) 1218 0 stevel { 1219 0 stevel di_lnode_t lnode; 1220 0 stevel char *name, *path; 1221 0 stevel int displayed_path, spec_type; 1222 0 stevel di_node_t node = DI_NODE_NIL; 1223 0 stevel dev_t devt = DDI_DEV_T_NONE; 1224 0 stevel 1225 0 stevel lnode = di_link_to_lnode(link, endpoint); 1226 0 stevel 1227 0 stevel indent_to_level(ilev); 1228 0 stevel name = di_lnode_name(lnode); 1229 0 stevel spec_type = di_link_spectype(link); 1230 0 stevel 1231 0 stevel (void) printf("mod=%s", name); 1232 0 stevel 1233 0 stevel /* 1234 0 stevel * if we're displaying the source of a link, we should display 1235 0 stevel * the target access mode. (either block or char.) 1236 0 stevel */ 1237 0 stevel if (endpoint == DI_LINK_SRC) 1238 0 stevel (void) printf(" accesstype=%s", 1239 0 stevel (spec_type == S_IFBLK) ? "blk" : "chr"); 1240 0 stevel 1241 0 stevel /* 1242 0 stevel * check if the lnode is bound to a specific device 1243 0 stevel * minor node (i.e. if it's bound to a dev_t) and 1244 0 stevel * if so display the dev_t value and any possible 1245 0 stevel * minor node pathing information. 1246 0 stevel */ 1247 0 stevel displayed_path = 0; 1248 0 stevel if (di_lnode_devt(lnode, &devt) == 0) { 1249 0 stevel di_minor_t minor = DI_MINOR_NIL; 1250 0 stevel 1251 0 stevel (void) printf(" dev=(%u,%u)\n", 1252 0 stevel (uint_t)major(devt), (uint_t)minor(devt)); 1253 0 stevel 1254 0 stevel /* display paths to the src devt minor node */ 1255 0 stevel while (minor = di_minor_next(node, minor)) { 1256 0 stevel if (devt != di_minor_devt(minor)) 1257 0 stevel continue; 1258 0 stevel 1259 0 stevel if ((endpoint == DI_LINK_TGT) && 1260 0 stevel (spec_type != di_minor_spectype(minor))) 1261 0 stevel continue; 1262 0 stevel 1263 0 stevel dump_minor_data_paths(ilev + 1, minor, devlink_hdl); 1264 0 stevel displayed_path = 1; 1265 0 stevel } 1266 0 stevel } else { 1267 0 stevel (void) printf("\n"); 1268 0 stevel } 1269 0 stevel 1270 0 stevel if (displayed_path) 1271 0 stevel return; 1272 0 stevel 1273 0 stevel /* 1274 0 stevel * This device lnode is not did not have any minor node 1275 0 stevel * pathing information so display the path to device node. 1276 0 stevel */ 1277 0 stevel node = di_lnode_devinfo(lnode); 1278 0 stevel if ((path = di_devfs_path(node)) == NULL) 1279 0 stevel exit(_error("failed to allocate memory")); 1280 0 stevel 1281 0 stevel indent_to_level(ilev + 1); 1282 0 stevel (void) printf("dev_path=%s\n", path); 1283 0 stevel di_devfs_path_free(path); 1284 0 stevel } 1285 0 stevel 1286 0 stevel static void 1287 0 stevel dump_minor_link_data(int ilev, di_node_t node, dev_t devt, 1288 0 stevel di_devlink_handle_t devlink_hdl) 1289 0 stevel { 1290 0 stevel int first = 1; 1291 0 stevel di_link_t link; 1292 0 stevel 1293 0 stevel link = DI_LINK_NIL; 1294 0 stevel while (link = di_link_next_by_node(node, link, DI_LINK_TGT)) { 1295 0 stevel di_lnode_t tgt_lnode; 1296 0 stevel dev_t tgt_devt = DDI_DEV_T_NONE; 1297 0 stevel 1298 0 stevel tgt_lnode = di_link_to_lnode(link, DI_LINK_TGT); 1299 0 stevel 1300 0 stevel if (di_lnode_devt(tgt_lnode, &tgt_devt) != 0) 1301 0 stevel continue; 1302 0 stevel 1303 0 stevel if (devt != tgt_devt) 1304 0 stevel continue; 1305 0 stevel 1306 0 stevel if (first) { 1307 0 stevel first = 0; 1308 0 stevel indent_to_level(ilev); 1309 0 stevel (void) printf("Device Minor Layered Under:\n"); 1310 0 stevel } 1311 0 stevel 1312 0 stevel /* displayed this lnode */ 1313 0 stevel lnode_displayed_set(tgt_lnode); 1314 0 stevel link_lnode_disp(link, DI_LINK_SRC, ilev + 1, devlink_hdl); 1315 0 stevel } 1316 0 stevel 1317 0 stevel link = DI_LINK_NIL; 1318 0 stevel while (link = di_link_next_by_node(node, link, DI_LINK_SRC)) { 1319 0 stevel di_lnode_t src_lnode; 1320 0 stevel dev_t src_devt = DDI_DEV_T_NONE; 1321 0 stevel 1322 0 stevel src_lnode = di_link_to_lnode(link, DI_LINK_SRC); 1323 0 stevel 1324 0 stevel if (di_lnode_devt(src_lnode, &src_devt) != 0) 1325 0 stevel continue; 1326 0 stevel 1327 0 stevel if (devt != src_devt) 1328 0 stevel continue; 1329 0 stevel 1330 0 stevel if (first) { 1331 0 stevel first = 0; 1332 0 stevel indent_to_level(ilev); 1333 0 stevel (void) printf("Device Minor Layered Over:\n"); 1334 0 stevel } 1335 0 stevel 1336 0 stevel /* displayed this lnode */ 1337 0 stevel lnode_displayed_set(src_lnode); 1338 0 stevel link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl); 1339 0 stevel } 1340 0 stevel } 1341 0 stevel 1342 0 stevel static void 1343 0 stevel dump_minor_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl) 1344 0 stevel { 1345 0 stevel di_minor_t minor, minor_next; 1346 0 stevel di_lnode_t lnode; 1347 0 stevel di_link_t link; 1348 0 stevel int major, firstminor = 1; 1349 0 stevel 1350 0 stevel /* 1351 0 stevel * first go through and mark all lnodes and minor nodes for this 1352 0 stevel * node as undisplayed 1353 0 stevel */ 1354 0 stevel lnode = DI_LNODE_NIL; 1355 0 stevel while (lnode = di_lnode_next(node, lnode)) 1356 0 stevel lnode_displayed_clear(lnode); 1357 0 stevel minor = DI_MINOR_NIL; 1358 0 stevel while (minor = di_minor_next(node, minor)) { 1359 0 stevel minor_displayed_clear(minor); 1360 0 stevel } 1361 0 stevel 1362 0 stevel /* 1363 0 stevel * when we display the minor nodes we want to coalesce nodes 1364 0 stevel * that have the same dev_t. we do this by creating circular 1365 0 stevel * lists of minor nodes with the same devt. 1366 0 stevel */ 1367 0 stevel create_minor_list(node); 1368 0 stevel 1369 0 stevel /* now we display the driver defined minor nodes */ 1370 0 stevel major = di_driver_major(node); 1371 0 stevel minor = DI_MINOR_NIL; 1372 0 stevel while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 1373 0 stevel dev_t devt; 1374 0 stevel 1375 0 stevel /* 1376 0 stevel * skip /pseudo/clone@0 minor nodes. 1377 0 stevel * these are only created for DLPIv2 network devices. 1378 0 stevel * since these minor nodes are associated with a driver 1379 0 stevel * and are only bound to a device instance after they 1380 0 stevel * are opened and attached we don't print them out 1381 0 stevel * here. 1382 0 stevel */ 1383 0 stevel devt = di_minor_devt(minor); 1384 0 stevel if (major != major(devt)) 1385 0 stevel continue; 1386 0 stevel 1387 0 stevel /* skip nodes that may have already been displayed */ 1388 0 stevel if (minor_displayed(minor)) 1389 0 stevel continue; 1390 0 stevel 1391 0 stevel if (firstminor) { 1392 0 stevel firstminor = 0; 1393 0 stevel indent_to_level(ilev++); 1394 0 stevel (void) printf("Device Minor Nodes:\n"); 1395 0 stevel } 1396 0 stevel 1397 0 stevel /* display the device minor node information */ 1398 0 stevel indent_to_level(ilev); 1399 0 stevel (void) printf("dev=(%u,%u)\n", 1400 4453 cth (uint_t)major(devt), (uint_t)minor(devt)); 1401 0 stevel 1402 0 stevel minor_next = minor; 1403 0 stevel do { 1404 0 stevel /* display device minor node path info */ 1405 0 stevel minor_displayed_set(minor_next); 1406 0 stevel dump_minor_data_paths(ilev + 1, minor_next, 1407 4453 cth devlink_hdl); 1408 0 stevel 1409 0 stevel /* get a pointer to the next node */ 1410 0 stevel minor_next = minor_ptr(minor_next); 1411 0 stevel } while (minor_next != minor); 1412 0 stevel 1413 0 stevel /* display who has this device minor node open */ 1414 0 stevel dump_minor_link_data(ilev + 1, node, devt, devlink_hdl); 1415 7224 cth 1416 7224 cth /* display properties associated with this devt */ 1417 7224 cth (void) dump_prop_list(&drvprop_dumpops, "Minor", 1418 7261 cth ilev + 1, node, devt, NULL); 1419 0 stevel } 1420 0 stevel 1421 0 stevel /* 1422 0 stevel * now go through all the target lnodes for this node and 1423 0 stevel * if they haven't yet been displayed, display them now. 1424 0 stevel * 1425 0 stevel * this happens in the case of clone opens when an "official" 1426 0 stevel * minor node does not exist for the opened devt 1427 0 stevel */ 1428 0 stevel link = DI_LINK_NIL; 1429 0 stevel while (link = di_link_next_by_node(node, link, DI_LINK_TGT)) { 1430 0 stevel dev_t devt; 1431 0 stevel 1432 0 stevel lnode = di_link_to_lnode(link, DI_LINK_TGT); 1433 0 stevel 1434 0 stevel /* if we've already displayed this target lnode, skip it */ 1435 0 stevel if (lnode_displayed(lnode)) 1436 0 stevel continue; 1437 0 stevel 1438 0 stevel if (firstminor) { 1439 0 stevel firstminor = 0; 1440 0 stevel indent_to_level(ilev++); 1441 0 stevel (void) printf("Device Minor Nodes:\n"); 1442 0 stevel } 1443 0 stevel 1444 0 stevel /* display the device minor node information */ 1445 0 stevel indent_to_level(ilev); 1446 0 stevel (void) di_lnode_devt(lnode, &devt); 1447 0 stevel (void) printf("dev=(%u,%u)\n", 1448 4453 cth (uint_t)major(devt), (uint_t)minor(devt)); 1449 0 stevel 1450 0 stevel indent_to_level(ilev + 1); 1451 0 stevel (void) printf("dev_path=<clone>\n"); 1452 0 stevel 1453 0 stevel /* display who has this cloned device minor node open */ 1454 0 stevel dump_minor_link_data(ilev + 1, node, devt, devlink_hdl); 1455 0 stevel 1456 0 stevel /* mark node as displayed */ 1457 0 stevel lnode_displayed_set(lnode); 1458 0 stevel } 1459 0 stevel } 1460 0 stevel 1461 0 stevel static void 1462 0 stevel dump_link_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl) 1463 0 stevel { 1464 0 stevel int first = 1; 1465 0 stevel di_link_t link; 1466 0 stevel 1467 0 stevel link = DI_LINK_NIL; 1468 0 stevel while (link = di_link_next_by_node(node, link, DI_LINK_SRC)) { 1469 0 stevel di_lnode_t src_lnode; 1470 0 stevel dev_t src_devt = DDI_DEV_T_NONE; 1471 0 stevel 1472 0 stevel src_lnode = di_link_to_lnode(link, DI_LINK_SRC); 1473 0 stevel 1474 0 stevel /* 1475 0 stevel * here we only want to print out layering information 1476 0 stevel * if we are the source and our source lnode is not 1477 0 stevel * associated with any particular dev_t. (which means 1478 0 stevel * we won't display this link while dumping minor node 1479 0 stevel * info.) 1480 0 stevel */ 1481 0 stevel if (di_lnode_devt(src_lnode, &src_devt) != -1) 1482 0 stevel continue; 1483 0 stevel 1484 0 stevel if (first) { 1485 0 stevel first = 0; 1486 0 stevel indent_to_level(ilev); 1487 0 stevel (void) printf("Device Layered Over:\n"); 1488 0 stevel } 1489 0 stevel 1490 0 stevel /* displayed this lnode */ 1491 0 stevel link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl); 1492 0 stevel } 1493 0 stevel } 1494 0 stevel 1495 0 stevel /* 1496 0 stevel * certain 'known' property names may contain 'composite' strings. 1497 0 stevel * Handle them here, and print them as 'string1' + 'string2' ... 1498 0 stevel */ 1499 0 stevel static int 1500 0 stevel print_composite_string(const char *var, char *value, int size) 1501 0 stevel { 1502 0 stevel char *p, *q; 1503 0 stevel char *firstp; 1504 0 stevel 1505 0 stevel if ((strcmp(var, "version") != 0) && 1506 0 stevel (strcmp(var, "compatible") != 0)) 1507 0 stevel return (0); /* Not a known composite string */ 1508 0 stevel 1509 0 stevel /* 1510 0 stevel * Verify that each string in the composite string is non-NULL, 1511 0 stevel * is within the bounds of the property length, and contains 1512 0 stevel * printable characters or white space. Otherwise let the 1513 0 stevel * caller deal with it. 1514 0 stevel */ 1515 0 stevel for (firstp = p = value; p < (value + size); p += strlen(p) + 1) { 1516 0 stevel if (strlen(p) == 0) 1517 0 stevel return (0); /* NULL string */ 1518 0 stevel for (q = p; *q; q++) { 1519 0 stevel if (!(isascii(*q) && (isprint(*q) || isspace(*q)))) 1520 0 stevel return (0); /* Not printable or space */ 1521 0 stevel } 1522 0 stevel if (q > (firstp + size)) 1523 0 stevel return (0); /* Out of bounds */ 1524 0 stevel } 1525 0 stevel 1526 0 stevel for (firstp = p = value; p < (value + size); p += strlen(p) + 1) { 1527 0 stevel if (p == firstp) 1528 0 stevel (void) printf("'%s'", p); 1529 0 stevel else 1530 0 stevel (void) printf(" + '%s'", p); 1531 0 stevel } 1532 0 stevel (void) putchar('\n'); 1533 0 stevel return (1); 1534 0 stevel } 1535 0 stevel 1536 0 stevel /* 1537 0 stevel * Print one property and its value. Handle the verbose case. 1538 0 stevel */ 1539 0 stevel static void 1540 0 stevel print_one(nvpair_t *nvp, int level) 1541 0 stevel { 1542 0 stevel int i; 1543 0 stevel int endswap = 0; 1544 0 stevel uint_t valsize; 1545 0 stevel char *value; 1546 0 stevel char *var = nvpair_name(nvp); 1547 0 stevel 1548 0 stevel indent_to_level(level); 1549 0 stevel (void) printf("%s: ", var); 1550 0 stevel 1551 0 stevel switch (nvpair_type(nvp)) { 1552 0 stevel case DATA_TYPE_BOOLEAN: 1553 0 stevel (void) printf(" \n"); 1554 0 stevel return; 1555 0 stevel case DATA_TYPE_BYTE_ARRAY: 1556 0 stevel if (nvpair_value_byte_array(nvp, (uchar_t **)&value, 1557 0 stevel &valsize)) { 1558 0 stevel (void) printf("data not available.\n"); 1559 0 stevel return; 1560 0 stevel } 1561 0 stevel valsize--; /* take out null added by driver */ 1562 0 stevel 1563 0 stevel /* 1564 0 stevel * Do not print valsize > MAXVALSIZE, to be compatible 1565 0 stevel * with old behavior. E.g. intel's eisa-nvram property 1566 0 stevel * has a size of 65 K. 1567 0 stevel */ 1568 0 stevel if (valsize > MAXVALSIZE) { 1569 0 stevel (void) printf(" \n"); 1570 0 stevel return; 1571 0 stevel } 1572 0 stevel break; 1573 0 stevel default: 1574 0 stevel (void) printf("data type unexpected.\n"); 1575 0 stevel return; 1576 0 stevel } 1577 0 stevel 1578 0 stevel /* 1579 0 stevel * Handle printing verbosely 1580 0 stevel */ 1581 0 stevel if (print_composite_string(var, value, valsize)) { 1582 0 stevel return; 1583 0 stevel } 1584 0 stevel 1585 0 stevel if (!unprintable(value, valsize)) { 1586 0 stevel (void) printf(" '%s'\n", value); 1587 0 stevel return; 1588 0 stevel } 1589 0 stevel 1590 0 stevel (void) printf(" "); 1591 0 stevel #ifdef __x86 1592 0 stevel /* 1593 0 stevel * Due to backwards compatibility constraints x86 int 1594 0 stevel * properties are not in big-endian (ieee 1275) byte order. 1595 0 stevel * If we have a property that is a multiple of 4 bytes, 1596 0 stevel * let's assume it is an array of ints and print the bytes 1597 0 stevel * in little endian order to make things look nicer for 1598 0 stevel * the user. 1599 0 stevel */ 1600 0 stevel endswap = (valsize % 4) == 0; 1601 0 stevel #endif /* __x86 */ 1602 0 stevel for (i = 0; i < valsize; i++) { 1603 0 stevel int out; 1604 0 stevel if (i && (i % 4 == 0)) 1605 0 stevel (void) putchar('.'); 1606 0 stevel if (endswap) 1607 0 stevel out = value[i + (3 - 2 * (i % 4))] & 0xff; 1608 0 stevel else 1609 0 stevel out = value[i] & 0xff; 1610 0 stevel 1611 0 stevel (void) printf("%02x", out); 1612 0 stevel } 1613 0 stevel (void) putchar('\n'); 1614 0 stevel } 1615 0 stevel 1616 0 stevel static int 1617 0 stevel unprintable(char *value, int size) 1618 0 stevel { 1619 0 stevel int i; 1620 0 stevel 1621 0 stevel /* 1622 0 stevel * Is this just a zero? 1623 0 stevel */ 1624 0 stevel if (size == 0 || value[0] == '\0') 1625 0 stevel return (1); 1626 0 stevel /* 1627 0 stevel * If any character is unprintable, or if a null appears 1628 0 stevel * anywhere except at the end of a string, the whole 1629 0 stevel * property is "unprintable". 1630 0 stevel */ 1631 0 stevel for (i = 0; i < size; ++i) { 1632 0 stevel if (value[i] == '\0') 1633 0 stevel return (i != (size - 1)); 1634 0 stevel if (!isascii(value[i]) || iscntrl(value[i])) 1635 0 stevel return (1); 1636 0 stevel } 1637 0 stevel return (0); 1638 0 stevel } 1639 0 stevel 1640 0 stevel static int 1641 0 stevel promopen(int oflag) 1642 0 stevel { 1643 0 stevel for (;;) { 1644 0 stevel if ((prom_fd = open(opts.o_promdev, oflag)) < 0) { 1645 0 stevel if (errno == EAGAIN) { 1646 0 stevel (void) sleep(5); 1647 0 stevel continue; 1648 0 stevel } 1649 0 stevel if (errno == ENXIO) 1650 0 stevel return (-1); 1651 0 stevel if (getzoneid() == GLOBAL_ZONEID) { 1652 0 stevel _exit(_error("cannot open %s", 1653 0 stevel opts.o_promdev)); 1654 0 stevel } 1655 0 stevel /* not an error if this isn't the global zone */ 1656 0 stevel (void) _error(NULL, "openprom facility not available"); 1657 0 stevel exit(0); 1658 0 stevel } else 1659 0 stevel return (0); 1660 0 stevel } 1661 0 stevel } 1662 0 stevel 1663 0 stevel static void 1664 0 stevel promclose(void) 1665 0 stevel { 1666 0 stevel if (close(prom_fd) < 0) 1667 0 stevel exit(_error("close error on %s", opts.o_promdev)); 1668 0 stevel } 1669 0 stevel 1670 0 stevel /* 1671 0 stevel * Get and print the name of the frame buffer device. 1672 0 stevel */ 1673 0 stevel int 1674 0 stevel do_fbname(void) 1675 0 stevel { 1676 0 stevel int retval; 1677 0 stevel char fbuf_path[MAXPATHLEN]; 1678 0 stevel 1679 0 stevel retval = modctl(MODGETFBNAME, (caddr_t)fbuf_path); 1680 0 stevel 1681 0 stevel if (retval == 0) { 1682 0 stevel (void) printf("%s\n", fbuf_path); 1683 0 stevel } else { 1684 0 stevel if (retval == EFAULT) { 1685 0 stevel (void) fprintf(stderr, 1686 0 stevel "Error copying fb path to userland\n"); 1687 0 stevel } else { 1688 0 stevel (void) fprintf(stderr, 1689 0 stevel "Console output device is not a frame buffer\n"); 1690 0 stevel } 1691 0 stevel return (1); 1692 0 stevel } 1693 0 stevel return (0); 1694 0 stevel } 1695 0 stevel 1696 0 stevel /* 1697 0 stevel * Get and print the PROM version. 1698 0 stevel */ 1699 0 stevel int 1700 0 stevel do_promversion(void) 1701 0 stevel { 1702 0 stevel Oppbuf oppbuf; 1703 0 stevel struct openpromio *opp = &(oppbuf.opp); 1704 0 stevel 1705 0 stevel if (promopen(O_RDONLY)) { 1706 0 stevel (void) fprintf(stderr, "Cannot open openprom device\n"); 1707 0 stevel return (1); 1708 0 stevel } 1709 0 stevel 1710 0 stevel opp->oprom_size = MAXVALSIZE; 1711 0 stevel if (ioctl(prom_fd, OPROMGETVERSION, opp) < 0) 1712 0 stevel exit(_error("OPROMGETVERSION")); 1713 0 stevel 1714 0 stevel (void) printf("%s\n", opp->oprom_array); 1715 0 stevel promclose(); 1716 0 stevel return (0); 1717 0 stevel } 1718 0 stevel 1719 0 stevel int 1720 0 stevel do_prom_version64(void) 1721 0 stevel { 1722 0 stevel #ifdef sparc 1723 0 stevel Oppbuf oppbuf; 1724 0 stevel struct openpromio *opp = &(oppbuf.opp); 1725 0 stevel /*LINTED*/ 1726 0 stevel struct openprom_opr64 *opr = (struct openprom_opr64 *)opp->oprom_array; 1727 0 stevel 1728 0 stevel static const char msg[] = 1729 4453 cth "NOTICE: The firmware on this system does not support the " 1730 4453 cth "64-bit OS.\n" 1731 4453 cth "\tPlease upgrade to at least the following version:\n" 1732 4453 cth "\t\t%s\n\n"; 1733 0 stevel 1734 0 stevel if (promopen(O_RDONLY)) { 1735 0 stevel (void) fprintf(stderr, "Cannot open openprom device\n"); 1736 0 stevel return (-1); 1737 0 stevel } 1738 0 stevel 1739 0 stevel opp->oprom_size = MAXVALSIZE; 1740 0 stevel if (ioctl(prom_fd, OPROMREADY64, opp) < 0) 1741 0 stevel exit(_error("OPROMREADY64")); 1742 0 stevel 1743 0 stevel if (opr->return_code == 0) 1744 0 stevel return (0); 1745 0 stevel 1746 0 stevel (void) printf(msg, opr->message); 1747 0 stevel 1748 0 stevel promclose(); 1749 0 stevel return (opr->return_code); 1750 0 stevel #else 1751 0 stevel return (0); 1752 0 stevel #endif 1753 0 stevel } 1754 0 stevel 1755 0 stevel int 1756 0 stevel do_productinfo(void) 1757 0 stevel { 1758 0 stevel di_node_t root, next_node; 1759 0 stevel di_prom_handle_t promh; 1760 0 stevel static const char *root_prop[] = { "name", "model", "banner-name", 1761 0 stevel "compatible" }; 1762 0 stevel static const char *root_propv[] = { "name", "model", "banner-name", 1763 0 stevel "compatible", "idprom" }; 1764 0 stevel static const char *oprom_prop[] = { "model", "version" }; 1765 0 stevel 1766 0 stevel 1767 0 stevel root = di_init("/", DINFOCPYALL); 1768 0 stevel 1769 0 stevel if (root == DI_NODE_NIL) { 1770 0 stevel (void) fprintf(stderr, "di_init() failed\n"); 1771 0 stevel return (1); 1772 0 stevel } 1773 0 stevel 1774 0 stevel promh = di_prom_init(); 1775 0 stevel 1776 0 stevel if (promh == DI_PROM_HANDLE_NIL) { 1777 0 stevel (void) fprintf(stderr, "di_prom_init() failed\n"); 1778 0 stevel return (1); 1779 0 stevel } 1780 0 stevel 1781 0 stevel if (opts.o_verbose) { 1782 0 stevel dump_prodinfo(promh, root, root_propv, "root", 1783 4453 cth NUM_ELEMENTS(root_propv)); 1784 0 stevel 1785 0 stevel /* Get model and version properties under node "openprom" */ 1786 0 stevel next_node = find_node_by_name(promh, root, "openprom"); 1787 0 stevel if (next_node != DI_NODE_NIL) 1788 0 stevel dump_prodinfo(promh, next_node, oprom_prop, 1789 4453 cth "openprom", NUM_ELEMENTS(oprom_prop)); 1790 0 stevel 1791 0 stevel } else 1792 0 stevel dump_prodinfo(promh, root, root_prop, "root", 1793 4453 cth NUM_ELEMENTS(root_prop)); 1794 0 stevel di_prom_fini(promh); 1795 0 stevel di_fini(root); 1796 0 stevel return (0); 1797 0 stevel } 1798 0 stevel 1799 0 stevel di_node_t 1800 0 stevel find_node_by_name(di_prom_handle_t promh, di_node_t parent, 1801 0 stevel char *node_name) 1802 0 stevel { 1803 0 stevel di_node_t next_node; 1804 0 stevel uchar_t *prop_valp; 1805 0 stevel 1806 4900 vb160487 for (next_node = di_child_node(parent); next_node != DI_NODE_NIL; 1807 4900 vb160487 next_node = di_sibling_node(next_node)) { 1808 4900 vb160487 int len; 1809 4900 vb160487 1810 4900 vb160487 len = get_propval_by_name(promh, next_node, "name", &prop_valp); 1811 4900 vb160487 if ((len != -1) && (strcmp((char *)prop_valp, node_name) == 0)) 1812 0 stevel return (next_node); 1813 0 stevel } 1814 0 stevel return (DI_NODE_NIL); 1815 0 stevel } 1816 0 stevel 1817 0 stevel 1818 0 stevel int 1819 0 stevel get_propval_by_name(di_prom_handle_t promh, di_node_t node, const char *name, 1820 0 stevel uchar_t **valp) 1821 0 stevel { 1822 0 stevel int len; 1823 0 stevel uchar_t *bufp; 1824 0 stevel 1825 0 stevel len = di_prom_prop_lookup_bytes(promh, node, name, 1826 4453 cth (uchar_t **)&bufp); 1827 0 stevel if (len != -1) { 1828 0 stevel *valp = (uchar_t *)malloc(len); 1829 0 stevel (void) memcpy(*valp, bufp, len); 1830 0 stevel } 1831 0 stevel return (len); 1832 0 stevel } 1833 0 stevel 1834 0 stevel 1835 0 stevel static void 1836 0 stevel dump_prodinfo(di_prom_handle_t promh, di_node_t node, const char **propstr, 1837 0 stevel char *node_name, int num) 1838 0 stevel { 1839 0 stevel int out, len, index1, index, endswap = 0; 1840 0 stevel uchar_t *prop_valp; 1841 0 stevel 1842 0 stevel for (index1 = 0; index1 < num; index1++) { 1843 0 stevel len = get_propval_by_name(promh, node, propstr[index1], 1844 4453 cth &prop_valp); 1845 0 stevel if (len != -1) { 1846 0 stevel if (strcmp(node_name, "root")) 1847 0 stevel (void) printf("%s ", node_name); 1848 0 stevel 1849 0 stevel (void) printf("%s: ", propstr[index1]); 1850 0 stevel 1851 0 stevel if (print_composite_string((const char *) 1852 4453 cth propstr[index1], (char *)prop_valp, len)) { 1853 0 stevel free(prop_valp); 1854 0 stevel continue; 1855 0 stevel } 1856 0 stevel 1857 0 stevel if (!unprintable((char *)prop_valp, len)) { 1858 0 stevel (void) printf(" %s\n", (char *)prop_valp); 1859 0 stevel free(prop_valp); 1860 0 stevel continue; 1861 0 stevel } 1862 0 stevel 1863 0 stevel (void) printf(" "); 1864 0 stevel #ifdef __x86 1865 0 stevel endswap = (len % 4) == 0; 1866 0 stevel #endif /* __x86 */ 1867 0 stevel for (index = 0; index < len; index++) { 1868 0 stevel if (index && (index % 4 == 0)) 1869 0 stevel (void) putchar('.'); 1870 0 stevel if (endswap) 1871 0 stevel out = prop_valp[index + 1872 4453 cth (3 - 2 * (index % 4))] & 0xff; 1873 0 stevel else 1874 0 stevel out = prop_valp[index] & 0xff; 1875 0 stevel (void) printf("%02x", out); 1876 0 stevel } 1877 0 stevel (void) putchar('\n'); 1878 0 stevel free(prop_valp); 1879 0 stevel } 1880 0 stevel } 1881 0 stevel } 1882 7261 cth 1883 7261 cth static int 1884 7261 cth dump_compatible(char *name, int ilev, di_node_t node) 1885 7261 cth { 1886 7261 cth int ncompat; 1887 7261 cth char *compat_array; 1888 7261 cth char *p, *q; 1889 7261 cth int i; 1890 7261 cth 1891 7261 cth if (node == DI_PATH_NIL) 1892 7261 cth return (0); 1893 7261 cth 1894 7261 cth ncompat = di_compatible_names(node, &compat_array); 1895 7261 cth if (ncompat <= 0) 1896 7261 cth return (0); /* no 'compatible' available */ 1897 7261 cth 1898 7261 cth /* verify integrety of compat_array */ 1899 7261 cth for (i = 0, p = compat_array; i < ncompat; i++, p += strlen(p) + 1) { 1900 7261 cth if (strlen(p) == 0) 1901 7261 cth return (0); /* NULL string */ 1902 7261 cth for (q = p; *q; q++) { 1903 7261 cth if (!(isascii(*q) && (isprint(*q) || isspace(*q)))) 1904 7261 cth return (0); /* Not printable or space */ 1905 7261 cth } 1906 7261 cth } 1907 7261 cth 1908 7261 cth /* If name is non-NULL, produce header */ 1909 7261 cth if (name) { 1910 7261 cth indent_to_level(ilev); 1911 7261 cth (void) printf("%s properties:\n", name); 1912 7261 cth } 1913 7261 cth ilev++; 1914 7261 cth 1915 7261 cth /* process like a string array property */ 1916 7261 cth indent_to_level(ilev); 1917 7261 cth (void) printf("name='compatible' type=string items=%d\n", ncompat); 1918 7261 cth indent_to_level(ilev); 1919 7261 cth (void) printf(" value="); 1920 7261 cth for (i = 0, p = compat_array; i < (ncompat - 1); 1921 7261 cth i++, p += strlen(p) + 1) 1922 7261 cth (void) printf("'%s' + ", p); 1923 7261 cth (void) printf("'%s'", p); 1924 7261 cth (void) putchar('\n'); 1925 7261 cth return (1); 1926 7261 cth } 1927