17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
558c0eeecScth * Common Development and Distribution License (the "License").
658c0eeecScth * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22524b24f9SJudy Chen * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
25abc79d9dSRobert Mustacchi /*
26abc79d9dSRobert Mustacchi * Copyright (c) 2012, Joyent, Inc. All rights reserved.
27abc79d9dSRobert Mustacchi */
2849ca4dd9SPeter Tribble /*
2949ca4dd9SPeter Tribble * Copyright (c) 2019 Peter Tribble.
302545779bSRobert Mustacchi * Copyright 2022 Oxide Computer Company
3149ca4dd9SPeter Tribble */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate * For machines that support the openprom, fetch and print the list
357c478bd9Sstevel@tonic-gate * of devices that the kernel has fetched from the prom or conjured up.
367c478bd9Sstevel@tonic-gate */
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <stdarg.h>
407c478bd9Sstevel@tonic-gate #include <stdlib.h>
417c478bd9Sstevel@tonic-gate #include <fcntl.h>
427c478bd9Sstevel@tonic-gate #include <ctype.h>
437c478bd9Sstevel@tonic-gate #include <strings.h>
447c478bd9Sstevel@tonic-gate #include <unistd.h>
457c478bd9Sstevel@tonic-gate #include <stropts.h>
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
487c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
497c478bd9Sstevel@tonic-gate #include <sys/openpromio.h>
507c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
517c478bd9Sstevel@tonic-gate #include <sys/stat.h>
527c478bd9Sstevel@tonic-gate #include <zone.h>
537c478bd9Sstevel@tonic-gate #include <libnvpair.h>
542545779bSRobert Mustacchi #include <err.h>
552545779bSRobert Mustacchi #include <upanic.h>
567c478bd9Sstevel@tonic-gate #include "prtconf.h"
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate typedef char *(*dump_propname_t)(void *);
607c478bd9Sstevel@tonic-gate typedef int (*dump_proptype_t)(void *);
617c478bd9Sstevel@tonic-gate typedef int (*dump_propints_t)(void *, int **);
627c478bd9Sstevel@tonic-gate typedef int (*dump_propint64_t)(void *, int64_t **);
637c478bd9Sstevel@tonic-gate typedef int (*dump_propstrings_t)(void *, char **);
647c478bd9Sstevel@tonic-gate typedef int (*dump_propbytes_t)(void *, uchar_t **);
657c478bd9Sstevel@tonic-gate typedef int (*dump_proprawdata_t)(void *, uchar_t **);
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate typedef struct dumpops_common {
687c478bd9Sstevel@tonic-gate dump_propname_t doc_propname;
697c478bd9Sstevel@tonic-gate dump_proptype_t doc_proptype;
707c478bd9Sstevel@tonic-gate dump_propints_t doc_propints;
717c478bd9Sstevel@tonic-gate dump_propint64_t doc_propint64;
727c478bd9Sstevel@tonic-gate dump_propstrings_t doc_propstrings;
737c478bd9Sstevel@tonic-gate dump_propbytes_t doc_propbytes;
747c478bd9Sstevel@tonic-gate dump_proprawdata_t doc_proprawdata;
757c478bd9Sstevel@tonic-gate } dumpops_common_t;
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate static const dumpops_common_t prop_dumpops = {
787c478bd9Sstevel@tonic-gate (dump_propname_t)di_prop_name,
797c478bd9Sstevel@tonic-gate (dump_proptype_t)di_prop_type,
807c478bd9Sstevel@tonic-gate (dump_propints_t)di_prop_ints,
817c478bd9Sstevel@tonic-gate (dump_propint64_t)di_prop_int64,
827c478bd9Sstevel@tonic-gate (dump_propstrings_t)di_prop_strings,
837c478bd9Sstevel@tonic-gate (dump_propbytes_t)di_prop_bytes,
847c478bd9Sstevel@tonic-gate (dump_proprawdata_t)di_prop_rawdata
857c478bd9Sstevel@tonic-gate }, pathprop_common_dumpops = {
867c478bd9Sstevel@tonic-gate (dump_propname_t)di_path_prop_name,
877c478bd9Sstevel@tonic-gate (dump_proptype_t)di_path_prop_type,
887c478bd9Sstevel@tonic-gate (dump_propints_t)di_path_prop_ints,
897c478bd9Sstevel@tonic-gate (dump_propint64_t)di_path_prop_int64s,
907c478bd9Sstevel@tonic-gate (dump_propstrings_t)di_path_prop_strings,
917c478bd9Sstevel@tonic-gate (dump_propbytes_t)di_path_prop_bytes,
927c478bd9Sstevel@tonic-gate (dump_proprawdata_t)di_path_prop_bytes
937c478bd9Sstevel@tonic-gate };
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate typedef void *(*dump_nextprop_t)(void *, void *);
967c478bd9Sstevel@tonic-gate typedef dev_t (*dump_propdevt_t)(void *);
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate typedef struct dumpops {
997c478bd9Sstevel@tonic-gate const dumpops_common_t *dop_common;
1007c478bd9Sstevel@tonic-gate dump_nextprop_t dop_nextprop;
1017c478bd9Sstevel@tonic-gate dump_propdevt_t dop_propdevt;
1027c478bd9Sstevel@tonic-gate } dumpops_t;
1037c478bd9Sstevel@tonic-gate
104524b24f9SJudy Chen typedef struct di_args {
105524b24f9SJudy Chen di_prom_handle_t prom_hdl;
106524b24f9SJudy Chen di_devlink_handle_t devlink_hdl;
107524b24f9SJudy Chen } di_arg_t;
108524b24f9SJudy Chen
1097c478bd9Sstevel@tonic-gate static const dumpops_t sysprop_dumpops = {
1107c478bd9Sstevel@tonic-gate &prop_dumpops,
1117c478bd9Sstevel@tonic-gate (dump_nextprop_t)di_prop_sys_next,
1127c478bd9Sstevel@tonic-gate NULL
1137c478bd9Sstevel@tonic-gate }, globprop_dumpops = {
1147c478bd9Sstevel@tonic-gate &prop_dumpops,
1157c478bd9Sstevel@tonic-gate (dump_nextprop_t)di_prop_global_next,
1167c478bd9Sstevel@tonic-gate NULL
1177c478bd9Sstevel@tonic-gate }, drvprop_dumpops = {
1187c478bd9Sstevel@tonic-gate &prop_dumpops,
1197c478bd9Sstevel@tonic-gate (dump_nextprop_t)di_prop_drv_next,
1207c478bd9Sstevel@tonic-gate (dump_propdevt_t)di_prop_devt
1217c478bd9Sstevel@tonic-gate }, hwprop_dumpops = {
1227c478bd9Sstevel@tonic-gate &prop_dumpops,
1237c478bd9Sstevel@tonic-gate (dump_nextprop_t)di_prop_hw_next,
1247c478bd9Sstevel@tonic-gate NULL
1257c478bd9Sstevel@tonic-gate }, pathprop_dumpops = {
1267c478bd9Sstevel@tonic-gate &pathprop_common_dumpops,
1277c478bd9Sstevel@tonic-gate (dump_nextprop_t)di_path_prop_next,
1287c478bd9Sstevel@tonic-gate NULL
1297c478bd9Sstevel@tonic-gate };
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate #define PROPNAME(ops) (ops->dop_common->doc_propname)
1327c478bd9Sstevel@tonic-gate #define PROPTYPE(ops) (ops->dop_common->doc_proptype)
1337c478bd9Sstevel@tonic-gate #define PROPINTS(ops) (ops->dop_common->doc_propints)
1347c478bd9Sstevel@tonic-gate #define PROPINT64(ops) (ops->dop_common->doc_propint64)
1357c478bd9Sstevel@tonic-gate #define PROPSTRINGS(ops) (ops->dop_common->doc_propstrings)
1367c478bd9Sstevel@tonic-gate #define PROPBYTES(ops) (ops->dop_common->doc_propbytes)
1377c478bd9Sstevel@tonic-gate #define PROPRAWDATA(ops) (ops->dop_common->doc_proprawdata)
1387c478bd9Sstevel@tonic-gate #define NEXTPROP(ops) (ops->dop_nextprop)
1397c478bd9Sstevel@tonic-gate #define PROPDEVT(ops) (ops->dop_propdevt)
1407c478bd9Sstevel@tonic-gate #define NUM_ELEMENTS(A) (sizeof (A) / sizeof (A[0]))
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate static int prop_type_guess(const dumpops_t *, void *, void **, int *);
143524b24f9SJudy Chen static void walk_driver(di_node_t, di_arg_t *);
1447c478bd9Sstevel@tonic-gate static int dump_devs(di_node_t, void *);
145b9ccdc5aScth static int dump_prop_list(const dumpops_t *, const char *,
146fa084259Scth int, void *, dev_t, int *);
1477c478bd9Sstevel@tonic-gate static int is_openprom();
1487c478bd9Sstevel@tonic-gate static void walk(uchar_t *, uint_t, int);
1497c478bd9Sstevel@tonic-gate static void dump_node(nvlist_t *, int);
1507c478bd9Sstevel@tonic-gate static void dump_prodinfo(di_prom_handle_t, di_node_t, const char **,
1517c478bd9Sstevel@tonic-gate char *, int);
1527c478bd9Sstevel@tonic-gate static di_node_t find_node_by_name(di_prom_handle_t, di_node_t, char *);
1537c478bd9Sstevel@tonic-gate static int get_propval_by_name(di_prom_handle_t, di_node_t,
1547c478bd9Sstevel@tonic-gate const char *, uchar_t **);
155fa084259Scth static int dump_compatible(char *, int, di_node_t);
1567c478bd9Sstevel@tonic-gate static void dump_pathing_data(int, di_node_t);
1577c478bd9Sstevel@tonic-gate static void dump_minor_data(int, di_node_t, di_devlink_handle_t);
1587c478bd9Sstevel@tonic-gate static void dump_link_data(int, di_node_t, di_devlink_handle_t);
1597c478bd9Sstevel@tonic-gate static int print_composite_string(const char *, char *, int);
1607c478bd9Sstevel@tonic-gate static void print_one(nvpair_t *, int);
1617c478bd9Sstevel@tonic-gate static int unprintable(char *, int);
1627c478bd9Sstevel@tonic-gate static int promopen(int);
1637c478bd9Sstevel@tonic-gate static void promclose();
1647c478bd9Sstevel@tonic-gate static di_node_t find_target_node(di_node_t);
165f772f0f8SToomas Soome static void node_display_private_set(di_node_t);
166f772f0f8SToomas Soome static int node_display_set(di_node_t, void *);
167*1c7f36ecSRobert Mustacchi static void dump_pciid(char *, int, di_node_t);
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate void
prtconf_devinfo(void)1707c478bd9Sstevel@tonic-gate prtconf_devinfo(void)
1717c478bd9Sstevel@tonic-gate {
1727c478bd9Sstevel@tonic-gate struct di_priv_data fetch;
173524b24f9SJudy Chen di_arg_t di_arg;
174524b24f9SJudy Chen di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL;
1757c478bd9Sstevel@tonic-gate di_devlink_handle_t devlink_hdl = NULL;
1767c478bd9Sstevel@tonic-gate di_node_t root_node;
1777c478bd9Sstevel@tonic-gate uint_t flag;
1787c478bd9Sstevel@tonic-gate char *rootpath;
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate dprintf("verbosemode %s\n", opts.o_verbose ? "on" : "off");
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate /* determine what info we need to get from kernel */
1837c478bd9Sstevel@tonic-gate flag = DINFOSUBTREE;
1847c478bd9Sstevel@tonic-gate rootpath = "/";
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate if (opts.o_target) {
1877c478bd9Sstevel@tonic-gate flag |= (DINFOMINOR | DINFOPATH);
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
190524b24f9SJudy Chen if (opts.o_pciid) {
191524b24f9SJudy Chen flag |= DINFOPROP;
192524b24f9SJudy Chen if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL)
1932545779bSRobert Mustacchi err(-1, "di_prom_init() failed.");
194524b24f9SJudy Chen }
195524b24f9SJudy Chen
1967c478bd9Sstevel@tonic-gate if (opts.o_forcecache) {
19758c0eeecScth if (dbg.d_forceload) {
1982545779bSRobert Mustacchi warnx("option combination not supported");
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate if (strcmp(rootpath, "/") != 0) {
2012545779bSRobert Mustacchi errx(-1, "invalid root path for option");
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate flag = DINFOCACHE;
20458c0eeecScth } else if (opts.o_verbose) {
20558c0eeecScth flag |= (DINFOPROP | DINFOMINOR |
20658c0eeecScth DINFOPRIVDATA | DINFOPATH | DINFOLYR);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate if (dbg.d_forceload) {
2107c478bd9Sstevel@tonic-gate flag |= DINFOFORCE;
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate if (opts.o_verbose) {
2147c478bd9Sstevel@tonic-gate init_priv_data(&fetch);
2157c478bd9Sstevel@tonic-gate root_node = di_init_impl(rootpath, flag, &fetch);
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate /* get devlink (aka aliases) data */
2187c478bd9Sstevel@tonic-gate if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL)
2192545779bSRobert Mustacchi err(-1, "di_devlink_init() failed.");
2207c478bd9Sstevel@tonic-gate } else
2217c478bd9Sstevel@tonic-gate root_node = di_init(rootpath, flag);
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate if (root_node == DI_NODE_NIL) {
2242545779bSRobert Mustacchi warnx("devinfo facility not available");
2257c478bd9Sstevel@tonic-gate /* not an error if this isn't the global zone */
2267c478bd9Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID)
2277c478bd9Sstevel@tonic-gate exit(-1);
2287c478bd9Sstevel@tonic-gate else
2297c478bd9Sstevel@tonic-gate exit(0);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
232524b24f9SJudy Chen di_arg.prom_hdl = prom_hdl;
233524b24f9SJudy Chen di_arg.devlink_hdl = devlink_hdl;
234524b24f9SJudy Chen
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate * ...and walk all nodes to report them out...
2377c478bd9Sstevel@tonic-gate */
2387c478bd9Sstevel@tonic-gate if (dbg.d_bydriver) {
2397c478bd9Sstevel@tonic-gate opts.o_target = 0;
240524b24f9SJudy Chen walk_driver(root_node, &di_arg);
241524b24f9SJudy Chen if (prom_hdl != DI_PROM_HANDLE_NIL)
242524b24f9SJudy Chen di_prom_fini(prom_hdl);
2437c478bd9Sstevel@tonic-gate if (devlink_hdl != NULL)
2447c478bd9Sstevel@tonic-gate (void) di_devlink_fini(&devlink_hdl);
2457c478bd9Sstevel@tonic-gate di_fini(root_node);
2467c478bd9Sstevel@tonic-gate return;
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate if (opts.o_target) {
2507c478bd9Sstevel@tonic-gate di_node_t target_node, node;
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate target_node = find_target_node(root_node);
2537c478bd9Sstevel@tonic-gate if (target_node == DI_NODE_NIL) {
2547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: "
25558c0eeecScth "invalid device path specified\n",
25658c0eeecScth opts.o_progname);
2577c478bd9Sstevel@tonic-gate exit(1);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate /* mark the target node so we display it */
261f772f0f8SToomas Soome node_display_private_set(target_node);
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate if (opts.o_ancestors) {
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate * mark the ancestors of this node so we display
2667c478bd9Sstevel@tonic-gate * them as well
2677c478bd9Sstevel@tonic-gate */
2687c478bd9Sstevel@tonic-gate node = target_node;
2692545779bSRobert Mustacchi while ((node = di_parent_node(node)) != DI_NODE_NIL)
270f772f0f8SToomas Soome node_display_private_set(node);
2717c478bd9Sstevel@tonic-gate } else {
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate * when we display device tree nodes the indentation
2747c478bd9Sstevel@tonic-gate * level is based off of tree depth.
2757c478bd9Sstevel@tonic-gate *
2767c478bd9Sstevel@tonic-gate * here we increment o_target to reflect the
2777c478bd9Sstevel@tonic-gate * depth of the target node in the tree. we do
2787c478bd9Sstevel@tonic-gate * this so that when we calculate the indentation
2797c478bd9Sstevel@tonic-gate * level we can subtract o_target so that the
2807c478bd9Sstevel@tonic-gate * target node starts with an indentation of zero.
2817c478bd9Sstevel@tonic-gate */
2827c478bd9Sstevel@tonic-gate node = target_node;
2832545779bSRobert Mustacchi while ((node = di_parent_node(node)) != DI_NODE_NIL)
2847c478bd9Sstevel@tonic-gate opts.o_target++;
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate if (opts.o_children) {
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate * mark the children of this node so we display
2907c478bd9Sstevel@tonic-gate * them as well
2917c478bd9Sstevel@tonic-gate */
2927c478bd9Sstevel@tonic-gate (void) di_walk_node(target_node, DI_WALK_CLDFIRST,
293f772f0f8SToomas Soome (void *)1, node_display_set);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate
297524b24f9SJudy Chen (void) di_walk_node(root_node, DI_WALK_CLDFIRST, &di_arg,
29858c0eeecScth dump_devs);
2997c478bd9Sstevel@tonic-gate
300524b24f9SJudy Chen if (prom_hdl != DI_PROM_HANDLE_NIL)
301524b24f9SJudy Chen di_prom_fini(prom_hdl);
3027c478bd9Sstevel@tonic-gate if (devlink_hdl != NULL)
3037c478bd9Sstevel@tonic-gate (void) di_devlink_fini(&devlink_hdl);
3047c478bd9Sstevel@tonic-gate di_fini(root_node);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate * utility routines
3097c478bd9Sstevel@tonic-gate */
3107c478bd9Sstevel@tonic-gate static int
i_find_target_node(di_node_t node,void * arg)3117c478bd9Sstevel@tonic-gate i_find_target_node(di_node_t node, void *arg)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate di_node_t *target = (di_node_t *)arg;
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate if (opts.o_devices_path != NULL) {
3167c478bd9Sstevel@tonic-gate char *path;
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate if ((path = di_devfs_path(node)) == NULL)
3192545779bSRobert Mustacchi err(-1, "failed to allocate memory");
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate if (strcmp(opts.o_devices_path, path) == 0) {
3227c478bd9Sstevel@tonic-gate di_devfs_path_free(path);
3237c478bd9Sstevel@tonic-gate *target = node;
3247c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate di_devfs_path_free(path);
3287c478bd9Sstevel@tonic-gate } else if (opts.o_devt != DDI_DEV_T_NONE) {
3297c478bd9Sstevel@tonic-gate di_minor_t minor = DI_MINOR_NIL;
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
3327c478bd9Sstevel@tonic-gate if (opts.o_devt == di_minor_devt(minor)) {
3337c478bd9Sstevel@tonic-gate *target = node;
3347c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate } else {
3387c478bd9Sstevel@tonic-gate /* we should never get here */
3392545779bSRobert Mustacchi const char *msg = "internal error";
3402545779bSRobert Mustacchi upanic(msg, strlen(msg));
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate static di_node_t
find_target_node(di_node_t root_node)3467c478bd9Sstevel@tonic-gate find_target_node(di_node_t root_node)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate di_node_t target = DI_NODE_NIL;
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate /* special case to allow displaying of the root node */
3517c478bd9Sstevel@tonic-gate if (opts.o_devices_path != NULL) {
3527c478bd9Sstevel@tonic-gate if (strlen(opts.o_devices_path) == 0)
3537c478bd9Sstevel@tonic-gate return (root_node);
3547c478bd9Sstevel@tonic-gate if (strcmp(opts.o_devices_path, ".") == 0)
3557c478bd9Sstevel@tonic-gate return (root_node);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate (void) di_walk_node(root_node, DI_WALK_CLDFIRST, &target,
35958c0eeecScth i_find_target_node);
3607c478bd9Sstevel@tonic-gate return (target);
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate #define NODE_DISPLAY (1<<0)
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate static long
node_display(di_node_t node)3667c478bd9Sstevel@tonic-gate node_display(di_node_t node)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate long data = (long)di_node_private_get(node);
3697c478bd9Sstevel@tonic-gate return (data & NODE_DISPLAY);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate static void
node_display_private_set(di_node_t node)373f772f0f8SToomas Soome node_display_private_set(di_node_t node)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate long data = (long)di_node_private_get(node);
3767c478bd9Sstevel@tonic-gate data |= NODE_DISPLAY;
3777c478bd9Sstevel@tonic-gate di_node_private_set(node, (void *)data);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
380f772f0f8SToomas Soome static int
node_display_set(di_node_t node,void * arg __unused)381f772f0f8SToomas Soome node_display_set(di_node_t node, void *arg __unused)
382f772f0f8SToomas Soome {
383f772f0f8SToomas Soome node_display_private_set(node);
384f772f0f8SToomas Soome return (0);
385f772f0f8SToomas Soome }
386f772f0f8SToomas Soome
3877c478bd9Sstevel@tonic-gate #define LNODE_DISPLAYED (1<<0)
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate static long
lnode_displayed(di_lnode_t lnode)3907c478bd9Sstevel@tonic-gate lnode_displayed(di_lnode_t lnode)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate long data = (long)di_lnode_private_get(lnode);
3937c478bd9Sstevel@tonic-gate return (data & LNODE_DISPLAYED);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate static void
lnode_displayed_set(di_lnode_t lnode)3977c478bd9Sstevel@tonic-gate lnode_displayed_set(di_lnode_t lnode)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate long data = (long)di_lnode_private_get(lnode);
4007c478bd9Sstevel@tonic-gate data |= LNODE_DISPLAYED;
4017c478bd9Sstevel@tonic-gate di_lnode_private_set(lnode, (void *)data);
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate static void
lnode_displayed_clear(di_lnode_t lnode)4057c478bd9Sstevel@tonic-gate lnode_displayed_clear(di_lnode_t lnode)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate long data = (long)di_lnode_private_get(lnode);
4087c478bd9Sstevel@tonic-gate data &= ~LNODE_DISPLAYED;
4097c478bd9Sstevel@tonic-gate di_lnode_private_set(lnode, (void *)data);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate #define MINOR_DISPLAYED (1<<0)
4137c478bd9Sstevel@tonic-gate #define MINOR_PTR (~(0x3))
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate static long
minor_displayed(di_minor_t minor)4167c478bd9Sstevel@tonic-gate minor_displayed(di_minor_t minor)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4197c478bd9Sstevel@tonic-gate return (data & MINOR_DISPLAYED);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate static void
minor_displayed_set(di_minor_t minor)4237c478bd9Sstevel@tonic-gate minor_displayed_set(di_minor_t minor)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4267c478bd9Sstevel@tonic-gate data |= MINOR_DISPLAYED;
4277c478bd9Sstevel@tonic-gate di_minor_private_set(minor, (void *)data);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate static void
minor_displayed_clear(di_minor_t minor)4317c478bd9Sstevel@tonic-gate minor_displayed_clear(di_minor_t minor)
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4347c478bd9Sstevel@tonic-gate data &= ~MINOR_DISPLAYED;
4357c478bd9Sstevel@tonic-gate di_minor_private_set(minor, (void *)data);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate static void *
minor_ptr(di_minor_t minor)4397c478bd9Sstevel@tonic-gate minor_ptr(di_minor_t minor)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4427c478bd9Sstevel@tonic-gate return ((void *)(data & MINOR_PTR));
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate static void
minor_ptr_set(di_minor_t minor,void * ptr)4467c478bd9Sstevel@tonic-gate minor_ptr_set(di_minor_t minor, void *ptr)
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate long data = (long)di_minor_private_get(minor);
4497c478bd9Sstevel@tonic-gate data = (data & ~MINOR_PTR) | (((long)ptr) & MINOR_PTR);
4507c478bd9Sstevel@tonic-gate di_minor_private_set(minor, (void *)data);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate * In this comment typed properties are those of type DI_PROP_TYPE_UNDEF_IT,
4557c478bd9Sstevel@tonic-gate * DI_PROP_TYPE_BOOLEAN, DI_PROP_TYPE_INT, DI_PROP_TYPE_INT64,
4567c478bd9Sstevel@tonic-gate * DI_PROP_TYPE_BYTE, and DI_PROP_TYPE_STRING.
4577c478bd9Sstevel@tonic-gate *
4587c478bd9Sstevel@tonic-gate * The guessing algorithm is:
4597c478bd9Sstevel@tonic-gate * 1. If the property is typed and the type is consistent with the value of
4607c478bd9Sstevel@tonic-gate * the property, then the property is of that type. If the type is not
4617c478bd9Sstevel@tonic-gate * consistent with value of the property, then the type is treated as
4627c478bd9Sstevel@tonic-gate * alien to prtconf.
4637c478bd9Sstevel@tonic-gate * 2. If the property is of type DI_PROP_TYPE_UNKNOWN the following steps
4647c478bd9Sstevel@tonic-gate * are carried out.
4657c478bd9Sstevel@tonic-gate * a. If the value of the property is consistent with a string property,
4667c478bd9Sstevel@tonic-gate * the type of the property is DI_PROP_TYPE_STRING.
4677c478bd9Sstevel@tonic-gate * b. Otherwise, if the value of the property is consistent with an integer
4687c478bd9Sstevel@tonic-gate * property, the type of the property is DI_PROP_TYPE_INT.
4697c478bd9Sstevel@tonic-gate * c. Otherwise, the property type is treated as alien to prtconf.
4707c478bd9Sstevel@tonic-gate * 3. If the property type is alien to prtconf, then the property value is
4717c478bd9Sstevel@tonic-gate * read by the appropriate routine for untyped properties and the following
4727c478bd9Sstevel@tonic-gate * steps are carried out.
4737c478bd9Sstevel@tonic-gate * a. If the length that the property routine returned is zero, the
4747c478bd9Sstevel@tonic-gate * property is of type DI_PROP_TYPE_BOOLEAN.
4757c478bd9Sstevel@tonic-gate * b. Otherwise, if the length that the property routine returned is
4767c478bd9Sstevel@tonic-gate * positive, then the property value is treated as raw data of type
4777c478bd9Sstevel@tonic-gate * DI_PROP_TYPE_UNKNOWN.
4787c478bd9Sstevel@tonic-gate * c. Otherwise, if the length that the property routine returned is
4797c478bd9Sstevel@tonic-gate * negative, then there is some internal inconsistency and this is
4807c478bd9Sstevel@tonic-gate * treated as an error and no type is determined.
4817c478bd9Sstevel@tonic-gate */
4827c478bd9Sstevel@tonic-gate static int
prop_type_guess(const dumpops_t * propops,void * prop,void ** prop_data,int * prop_type)4837c478bd9Sstevel@tonic-gate prop_type_guess(const dumpops_t *propops, void *prop, void **prop_data,
4847c478bd9Sstevel@tonic-gate int *prop_type)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate int len, type;
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate type = PROPTYPE(propops)(prop);
4897c478bd9Sstevel@tonic-gate switch (type) {
4907c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_UNDEF_IT:
4917c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_BOOLEAN:
4927c478bd9Sstevel@tonic-gate *prop_data = NULL;
4937c478bd9Sstevel@tonic-gate *prop_type = type;
4947c478bd9Sstevel@tonic-gate return (0);
4957c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_INT:
4967c478bd9Sstevel@tonic-gate len = PROPINTS(propops)(prop, (int **)prop_data);
4977c478bd9Sstevel@tonic-gate break;
4987c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_INT64:
4997c478bd9Sstevel@tonic-gate len = PROPINT64(propops)(prop, (int64_t **)prop_data);
5007c478bd9Sstevel@tonic-gate break;
5017c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_BYTE:
5027c478bd9Sstevel@tonic-gate len = PROPBYTES(propops)(prop, (uchar_t **)prop_data);
5037c478bd9Sstevel@tonic-gate break;
5047c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_STRING:
5057c478bd9Sstevel@tonic-gate len = PROPSTRINGS(propops)(prop, (char **)prop_data);
5067c478bd9Sstevel@tonic-gate break;
5077c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_UNKNOWN:
5087c478bd9Sstevel@tonic-gate len = PROPSTRINGS(propops)(prop, (char **)prop_data);
5097c478bd9Sstevel@tonic-gate if ((len > 0) && ((*(char **)prop_data)[0] != 0)) {
5107c478bd9Sstevel@tonic-gate *prop_type = DI_PROP_TYPE_STRING;
5117c478bd9Sstevel@tonic-gate return (len);
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate len = PROPINTS(propops)(prop, (int **)prop_data);
5157c478bd9Sstevel@tonic-gate type = DI_PROP_TYPE_INT;
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate break;
5187c478bd9Sstevel@tonic-gate default:
5197c478bd9Sstevel@tonic-gate len = -1;
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate if (len > 0) {
5237c478bd9Sstevel@tonic-gate *prop_type = type;
5247c478bd9Sstevel@tonic-gate return (len);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate len = PROPRAWDATA(propops)(prop, (uchar_t **)prop_data);
5287c478bd9Sstevel@tonic-gate if (len < 0) {
5297c478bd9Sstevel@tonic-gate return (-1);
5307c478bd9Sstevel@tonic-gate } else if (len == 0) {
5317c478bd9Sstevel@tonic-gate *prop_type = DI_PROP_TYPE_BOOLEAN;
5327c478bd9Sstevel@tonic-gate return (0);
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate *prop_type = DI_PROP_TYPE_UNKNOWN;
5367c478bd9Sstevel@tonic-gate return (len);
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate
539b9ccdc5aScth /*
540b9ccdc5aScth * Returns 0 if nothing is printed, 1 otherwise
541b9ccdc5aScth */
542b9ccdc5aScth static int
dump_prop_list(const dumpops_t * dumpops,const char * name,int ilev,void * node,dev_t dev,int * compat_printed)543b9ccdc5aScth dump_prop_list(const dumpops_t *dumpops, const char *name, int ilev,
544fa084259Scth void *node, dev_t dev, int *compat_printed)
5457c478bd9Sstevel@tonic-gate {
546b9ccdc5aScth void *prop = DI_PROP_NIL, *prop_data;
547b9ccdc5aScth di_minor_t minor;
548b9ccdc5aScth char *p;
549b9ccdc5aScth int i, prop_type, nitems;
5502545779bSRobert Mustacchi dev_t pdev = DDI_DEV_T_NONE;
551b9ccdc5aScth int nprop = 0;
5527c478bd9Sstevel@tonic-gate
553fa084259Scth if (compat_printed)
554fa084259Scth *compat_printed = 0;
555fa084259Scth
5567c478bd9Sstevel@tonic-gate while ((prop = NEXTPROP(dumpops)(node, prop)) != DI_PROP_NIL) {
557b9ccdc5aScth
558b9ccdc5aScth /* Skip properties a dev_t oriented caller is not requesting */
559b9ccdc5aScth if (PROPDEVT(dumpops)) {
560b9ccdc5aScth pdev = PROPDEVT(dumpops)(prop);
561b9ccdc5aScth
562b9ccdc5aScth if (dev == DDI_DEV_T_ANY) {
563b9ccdc5aScth /*
564b9ccdc5aScth * Caller requesting print all properties
565b9ccdc5aScth */
566b9ccdc5aScth goto print;
567b9ccdc5aScth } else if (dev == DDI_DEV_T_NONE) {
568b9ccdc5aScth /*
569b9ccdc5aScth * Caller requesting print of properties
570b9ccdc5aScth * associated with devinfo (not minor).
571b9ccdc5aScth */
572b9ccdc5aScth if ((pdev == DDI_DEV_T_ANY) ||
573b9ccdc5aScth (pdev == DDI_DEV_T_NONE))
574b9ccdc5aScth goto print;
575b9ccdc5aScth
576b9ccdc5aScth /*
577b9ccdc5aScth * Property has a minor association, see if
578b9ccdc5aScth * we have a minor with this dev_t. If there
579b9ccdc5aScth * is no such minor we print the property now
580b9ccdc5aScth * so it gets displayed.
581b9ccdc5aScth */
582b9ccdc5aScth minor = DI_MINOR_NIL;
583b9ccdc5aScth while ((minor = di_minor_next((di_node_t)node,
584b9ccdc5aScth minor)) != DI_MINOR_NIL) {
585b9ccdc5aScth if (di_minor_devt(minor) == pdev)
586b9ccdc5aScth break;
587b9ccdc5aScth }
588b9ccdc5aScth if (minor == DI_MINOR_NIL)
589b9ccdc5aScth goto print;
590b9ccdc5aScth } else if (dev == pdev) {
591b9ccdc5aScth /*
592b9ccdc5aScth * Caller requesting print of properties
593b9ccdc5aScth * associated with a specific matching minor
594b9ccdc5aScth * node.
595b9ccdc5aScth */
596b9ccdc5aScth goto print;
597b9ccdc5aScth }
598b9ccdc5aScth
599b9ccdc5aScth /* otherwise skip print */
600b9ccdc5aScth continue;
601b9ccdc5aScth }
602b9ccdc5aScth
603b9ccdc5aScth print: nitems = prop_type_guess(dumpops, prop, &prop_data, &prop_type);
6047c478bd9Sstevel@tonic-gate if (nitems < 0)
6057c478bd9Sstevel@tonic-gate continue;
6067c478bd9Sstevel@tonic-gate
607b9ccdc5aScth if (nprop == 0) {
608b9ccdc5aScth if (name) {
609b9ccdc5aScth indent_to_level(ilev);
610b9ccdc5aScth (void) printf("%s properties:\n", name);
611b9ccdc5aScth }
612b9ccdc5aScth ilev++;
613b9ccdc5aScth }
614b9ccdc5aScth nprop++;
615b9ccdc5aScth
6167c478bd9Sstevel@tonic-gate indent_to_level(ilev);
6177c478bd9Sstevel@tonic-gate (void) printf("name='%s' type=", PROPNAME(dumpops)(prop));
6187c478bd9Sstevel@tonic-gate
619fa084259Scth /* report 'compatible' as processed */
620fa084259Scth if (compat_printed &&
621fa084259Scth (strcmp(PROPNAME(dumpops)(prop), "compatible") == 0))
622fa084259Scth *compat_printed = 1;
623fa084259Scth
6247c478bd9Sstevel@tonic-gate switch (prop_type) {
6257c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_UNDEF_IT:
6267c478bd9Sstevel@tonic-gate (void) printf("undef");
6277c478bd9Sstevel@tonic-gate break;
6287c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_BOOLEAN:
6297c478bd9Sstevel@tonic-gate (void) printf("boolean");
6307c478bd9Sstevel@tonic-gate break;
6317c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_INT:
6327c478bd9Sstevel@tonic-gate (void) printf("int");
6337c478bd9Sstevel@tonic-gate break;
6347c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_INT64:
6357c478bd9Sstevel@tonic-gate (void) printf("int64");
6367c478bd9Sstevel@tonic-gate break;
6377c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_BYTE:
6387c478bd9Sstevel@tonic-gate (void) printf("byte");
6397c478bd9Sstevel@tonic-gate break;
6407c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_STRING:
6417c478bd9Sstevel@tonic-gate (void) printf("string");
6427c478bd9Sstevel@tonic-gate break;
6437c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_UNKNOWN:
6447c478bd9Sstevel@tonic-gate (void) printf("unknown");
6457c478bd9Sstevel@tonic-gate break;
6467c478bd9Sstevel@tonic-gate default:
6477c478bd9Sstevel@tonic-gate /* Should never be here */
6487c478bd9Sstevel@tonic-gate (void) printf("0x%x", prop_type);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate if (nitems != 0)
6527c478bd9Sstevel@tonic-gate (void) printf(" items=%i", nitems);
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate /* print the major and minor numbers for a device property */
655b9ccdc5aScth if (PROPDEVT(dumpops)) {
656b9ccdc5aScth if ((pdev == DDI_DEV_T_NONE) ||
657b9ccdc5aScth (pdev == DDI_DEV_T_ANY)) {
6587c478bd9Sstevel@tonic-gate (void) printf(" dev=none");
659b9ccdc5aScth } else {
660b9ccdc5aScth (void) printf(" dev=(%u,%u)",
661b9ccdc5aScth (uint_t)major(pdev), (uint_t)minor(pdev));
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate (void) putchar('\n');
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate if (nitems == 0)
6687c478bd9Sstevel@tonic-gate continue;
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate indent_to_level(ilev);
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate (void) printf(" value=");
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate switch (prop_type) {
6757c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_INT:
6767c478bd9Sstevel@tonic-gate for (i = 0; i < nitems - 1; i++)
6777c478bd9Sstevel@tonic-gate (void) printf("%8.8x.", ((int *)prop_data)[i]);
6787c478bd9Sstevel@tonic-gate (void) printf("%8.8x", ((int *)prop_data)[i]);
6797c478bd9Sstevel@tonic-gate break;
6807c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_INT64:
6817c478bd9Sstevel@tonic-gate for (i = 0; i < nitems - 1; i++)
6827c478bd9Sstevel@tonic-gate (void) printf("%16.16llx.",
6837c478bd9Sstevel@tonic-gate ((long long *)prop_data)[i]);
6847c478bd9Sstevel@tonic-gate (void) printf("%16.16llx", ((long long *)prop_data)[i]);
6857c478bd9Sstevel@tonic-gate break;
6867c478bd9Sstevel@tonic-gate case DI_PROP_TYPE_STRING:
6877c478bd9Sstevel@tonic-gate p = (char *)prop_data;
6887c478bd9Sstevel@tonic-gate for (i = 0; i < nitems - 1; i++) {
6897c478bd9Sstevel@tonic-gate (void) printf("'%s' + ", p);
6907c478bd9Sstevel@tonic-gate p += strlen(p) + 1;
6917c478bd9Sstevel@tonic-gate }
6927c478bd9Sstevel@tonic-gate (void) printf("'%s'", p);
6937c478bd9Sstevel@tonic-gate break;
6947c478bd9Sstevel@tonic-gate default:
6957c478bd9Sstevel@tonic-gate for (i = 0; i < nitems - 1; i++)
6967c478bd9Sstevel@tonic-gate (void) printf("%2.2x.",
6977c478bd9Sstevel@tonic-gate ((uint8_t *)prop_data)[i]);
6987c478bd9Sstevel@tonic-gate (void) printf("%2.2x", ((uint8_t *)prop_data)[i]);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate (void) putchar('\n');
7027c478bd9Sstevel@tonic-gate }
703b9ccdc5aScth
704b9ccdc5aScth return (nprop ? 1 : 0);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate /*
7087c478bd9Sstevel@tonic-gate * walk_driver is a debugging facility.
7097c478bd9Sstevel@tonic-gate */
7107c478bd9Sstevel@tonic-gate static void
walk_driver(di_node_t root,di_arg_t * di_arg)711524b24f9SJudy Chen walk_driver(di_node_t root, di_arg_t *di_arg)
7127c478bd9Sstevel@tonic-gate {
7137c478bd9Sstevel@tonic-gate di_node_t node;
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate node = di_drv_first_node(dbg.d_drivername, root);
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate while (node != DI_NODE_NIL) {
718524b24f9SJudy Chen (void) dump_devs(node, di_arg);
7197c478bd9Sstevel@tonic-gate node = di_drv_next_node(node);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate
723*1c7f36ecSRobert Mustacchi static const char *
devinfo_is_pci(di_node_t node)724*1c7f36ecSRobert Mustacchi devinfo_is_pci(di_node_t node)
725*1c7f36ecSRobert Mustacchi {
726*1c7f36ecSRobert Mustacchi char *t = NULL;
727*1c7f36ecSRobert Mustacchi di_node_t pnode = di_parent_node(node);
728*1c7f36ecSRobert Mustacchi
729*1c7f36ecSRobert Mustacchi if (di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
730*1c7f36ecSRobert Mustacchi "device_type", &t) <= 0)
731*1c7f36ecSRobert Mustacchi return (NULL);
732*1c7f36ecSRobert Mustacchi
733*1c7f36ecSRobert Mustacchi if (t == NULL || (strcmp(t, "pci") != 0 &&
734*1c7f36ecSRobert Mustacchi strcmp(t, "pciex") != 0))
735*1c7f36ecSRobert Mustacchi return (NULL);
736*1c7f36ecSRobert Mustacchi
737*1c7f36ecSRobert Mustacchi return (t);
738*1c7f36ecSRobert Mustacchi }
739*1c7f36ecSRobert Mustacchi
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate * print out information about this node, returns appropriate code.
7427c478bd9Sstevel@tonic-gate */
7437c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
7447c478bd9Sstevel@tonic-gate static int
dump_devs(di_node_t node,void * arg)7457c478bd9Sstevel@tonic-gate dump_devs(di_node_t node, void *arg)
7467c478bd9Sstevel@tonic-gate {
747524b24f9SJudy Chen di_arg_t *di_arg = arg;
748524b24f9SJudy Chen di_devlink_handle_t devlink_hdl = di_arg->devlink_hdl;
7497c478bd9Sstevel@tonic-gate int ilev = 0; /* indentation level */
7507c478bd9Sstevel@tonic-gate char *driver_name;
7517c478bd9Sstevel@tonic-gate di_node_t root_node, tmp;
752fa084259Scth int compat_printed;
753fa084259Scth int printed;
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate if (dbg.d_debug) {
7567c478bd9Sstevel@tonic-gate char *path = di_devfs_path(node);
7577c478bd9Sstevel@tonic-gate dprintf("Dump node %s\n", path);
7587c478bd9Sstevel@tonic-gate di_devfs_path_free(path);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate if (dbg.d_bydriver) {
7627c478bd9Sstevel@tonic-gate ilev = 1;
7637c478bd9Sstevel@tonic-gate } else {
7647c478bd9Sstevel@tonic-gate /* figure out indentation level */
7657c478bd9Sstevel@tonic-gate tmp = node;
7667c478bd9Sstevel@tonic-gate while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL)
7677c478bd9Sstevel@tonic-gate ilev++;
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate if (opts.o_target && !opts.o_ancestors) {
7707c478bd9Sstevel@tonic-gate ilev -= opts.o_target - 1;
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate if (opts.o_target && !node_display(node)) {
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate * if we're only displaying certain nodes and this one
7777c478bd9Sstevel@tonic-gate * isn't flagged, skip it.
7787c478bd9Sstevel@tonic-gate */
7797c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate
7827c478bd9Sstevel@tonic-gate indent_to_level(ilev);
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate (void) printf("%s", di_node_name(node));
785*1c7f36ecSRobert Mustacchi if (opts.o_pciid) {
786*1c7f36ecSRobert Mustacchi int *vid, *did;
787*1c7f36ecSRobert Mustacchi const char *dtype = devinfo_is_pci(node);
788*1c7f36ecSRobert Mustacchi
789*1c7f36ecSRobert Mustacchi if (dtype != NULL &&
790*1c7f36ecSRobert Mustacchi di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id",
791*1c7f36ecSRobert Mustacchi &vid) > 0 && vid[0] <= UINT16_MAX &&
792*1c7f36ecSRobert Mustacchi di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id",
793*1c7f36ecSRobert Mustacchi &did) > 0 && did[0] <= UINT16_MAX) {
794*1c7f36ecSRobert Mustacchi print_pciid(dtype, (uint16_t)vid[0], (uint16_t)did[0],
795*1c7f36ecSRobert Mustacchi opts.o_pcidb);
796*1c7f36ecSRobert Mustacchi }
797*1c7f36ecSRobert Mustacchi }
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate /*
8007c478bd9Sstevel@tonic-gate * if this node does not have an instance number or is the
8017c478bd9Sstevel@tonic-gate * root node (1229946), we don't print an instance number
8027c478bd9Sstevel@tonic-gate */
8037c478bd9Sstevel@tonic-gate root_node = tmp = node;
8047c478bd9Sstevel@tonic-gate while ((tmp = di_parent_node(tmp)) != DI_NODE_NIL)
8057c478bd9Sstevel@tonic-gate root_node = tmp;
8067c478bd9Sstevel@tonic-gate if ((di_instance(node) >= 0) && (node != root_node))
8077c478bd9Sstevel@tonic-gate (void) printf(", instance #%d", di_instance(node));
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate if (opts.o_drv_name) {
8107c478bd9Sstevel@tonic-gate driver_name = di_driver_name(node);
8117c478bd9Sstevel@tonic-gate if (driver_name != NULL)
8127c478bd9Sstevel@tonic-gate (void) printf(" (driver name: %s)", driver_name);
81325e8c5aaSvikram } else if (di_retired(node)) {
81425e8c5aaSvikram (void) printf(" (retired)");
8157c478bd9Sstevel@tonic-gate } else if (di_state(node) & DI_DRIVER_DETACHED)
8167c478bd9Sstevel@tonic-gate (void) printf(" (driver not attached)");
8177c478bd9Sstevel@tonic-gate (void) printf("\n");
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate if (opts.o_verbose) {
8207c478bd9Sstevel@tonic-gate if (dump_prop_list(&sysprop_dumpops, "System", ilev + 1,
821fa084259Scth node, DDI_DEV_T_ANY, NULL)) {
8227c478bd9Sstevel@tonic-gate (void) dump_prop_list(&globprop_dumpops, NULL, ilev + 1,
823fa084259Scth node, DDI_DEV_T_ANY, NULL);
8247c478bd9Sstevel@tonic-gate } else {
8257c478bd9Sstevel@tonic-gate (void) dump_prop_list(&globprop_dumpops,
826fa084259Scth "System software", ilev + 1,
827fa084259Scth node, DDI_DEV_T_ANY, NULL);
8287c478bd9Sstevel@tonic-gate }
8297c478bd9Sstevel@tonic-gate (void) dump_prop_list(&drvprop_dumpops, "Driver", ilev + 1,
830fa084259Scth node, DDI_DEV_T_NONE, NULL);
831fa084259Scth
832fa084259Scth printed = dump_prop_list(&hwprop_dumpops, "Hardware",
833fa084259Scth ilev + 1, node, DDI_DEV_T_ANY, &compat_printed);
834fa084259Scth
835fa084259Scth /* Ensure that 'compatible' is printed under Hardware header */
836fa084259Scth if (!compat_printed)
837abc79d9dSRobert Mustacchi printed |= dump_compatible(printed ? NULL : "Hardware",
838fa084259Scth ilev + 1, node);
839fa084259Scth
840abc79d9dSRobert Mustacchi /* Ensure that pci id information is printed under Hardware */
841*1c7f36ecSRobert Mustacchi dump_pciid(printed ? NULL : "Hardware", ilev + 1, node);
842abc79d9dSRobert Mustacchi
8437c478bd9Sstevel@tonic-gate dump_priv_data(ilev + 1, node);
8447c478bd9Sstevel@tonic-gate dump_pathing_data(ilev + 1, node);
8457c478bd9Sstevel@tonic-gate dump_link_data(ilev + 1, node, devlink_hdl);
8467c478bd9Sstevel@tonic-gate dump_minor_data(ilev + 1, node, devlink_hdl);
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate if (opts.o_target)
8507c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
8517c478bd9Sstevel@tonic-gate
8527c478bd9Sstevel@tonic-gate if (!opts.o_pseudodevs && (strcmp(di_node_name(node), "pseudo") == 0))
8537c478bd9Sstevel@tonic-gate return (DI_WALK_PRUNECHILD);
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate /*
8597c478bd9Sstevel@tonic-gate * The rest of the routines handle printing the raw prom devinfo (-p option).
8607c478bd9Sstevel@tonic-gate *
8617c478bd9Sstevel@tonic-gate * 128 is the size of the largest (currently) property name
8627c478bd9Sstevel@tonic-gate * 16k - MAXNAMESZ - sizeof (int) is the size of the largest
8637c478bd9Sstevel@tonic-gate * (currently) property value that is allowed.
8647c478bd9Sstevel@tonic-gate * the sizeof (uint_t) is from struct openpromio
8657c478bd9Sstevel@tonic-gate */
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate #define MAXNAMESZ 128
8687c478bd9Sstevel@tonic-gate #define MAXVALSIZE (16384 - MAXNAMESZ - sizeof (uint_t))
8697c478bd9Sstevel@tonic-gate #define BUFSIZE (MAXNAMESZ + MAXVALSIZE + sizeof (uint_t))
8707c478bd9Sstevel@tonic-gate typedef union {
8717c478bd9Sstevel@tonic-gate char buf[BUFSIZE];
8727c478bd9Sstevel@tonic-gate struct openpromio opp;
8737c478bd9Sstevel@tonic-gate } Oppbuf;
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate static int prom_fd;
8767c478bd9Sstevel@tonic-gate static uchar_t *prom_snapshot;
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate static int
is_openprom(void)8797c478bd9Sstevel@tonic-gate is_openprom(void)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate Oppbuf oppbuf;
8827c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
8837c478bd9Sstevel@tonic-gate unsigned int i;
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
8867c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
8872545779bSRobert Mustacchi err(-1, "OPROMGETCONS");
8887c478bd9Sstevel@tonic-gate
8897c478bd9Sstevel@tonic-gate i = (unsigned int)((unsigned char)opp->oprom_array[0]);
8907c478bd9Sstevel@tonic-gate return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
8917c478bd9Sstevel@tonic-gate }
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate int
do_prominfo(void)8947c478bd9Sstevel@tonic-gate do_prominfo(void)
8957c478bd9Sstevel@tonic-gate {
896*1c7f36ecSRobert Mustacchi uint_t arg = 0;
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate if (promopen(O_RDONLY)) {
8992545779bSRobert Mustacchi err(-1, "openeepr device open failed");
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate
9027c478bd9Sstevel@tonic-gate if (is_openprom() == 0) {
9037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "System architecture does not "
9047c478bd9Sstevel@tonic-gate "support this option of this command.\n");
9057c478bd9Sstevel@tonic-gate return (1);
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate
908*1c7f36ecSRobert Mustacchi /*
909*1c7f36ecSRobert Mustacchi * If we're eiher in verbose mode or asked to get device information,
910*1c7f36ecSRobert Mustacchi * then we need to actually ask for verbose information from the prom by
911*1c7f36ecSRobert Mustacchi * setting a non-zero value.
912*1c7f36ecSRobert Mustacchi */
913*1c7f36ecSRobert Mustacchi if (opts.o_verbose != 0 || opts.o_pciid != 0) {
914*1c7f36ecSRobert Mustacchi arg = 1;
915*1c7f36ecSRobert Mustacchi }
916*1c7f36ecSRobert Mustacchi
9177c478bd9Sstevel@tonic-gate /* OPROMSNAPSHOT returns size in arg */
9187c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMSNAPSHOT, &arg) < 0)
9192545779bSRobert Mustacchi err(-1, "OPROMSNAPSHOT");
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate if (arg == 0)
9227c478bd9Sstevel@tonic-gate return (1);
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate if ((prom_snapshot = malloc(arg)) == NULL)
9252545779bSRobert Mustacchi err(-1, "failed to allocate memory");
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate /* copy out the snapshot for printing */
9287c478bd9Sstevel@tonic-gate /*LINTED*/
9297c478bd9Sstevel@tonic-gate *(uint_t *)prom_snapshot = arg;
9307c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMCOPYOUT, prom_snapshot) < 0)
9312545779bSRobert Mustacchi err(-1, "OPROMCOPYOUT");
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate promclose();
9347c478bd9Sstevel@tonic-gate
9357c478bd9Sstevel@tonic-gate /* print out information */
9367c478bd9Sstevel@tonic-gate walk(prom_snapshot, arg, 0);
9377c478bd9Sstevel@tonic-gate free(prom_snapshot);
9387c478bd9Sstevel@tonic-gate
9397c478bd9Sstevel@tonic-gate return (0);
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate
9427c478bd9Sstevel@tonic-gate static void
walk(uchar_t * buf,uint_t size,int level)9437c478bd9Sstevel@tonic-gate walk(uchar_t *buf, uint_t size, int level)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate int error;
9467c478bd9Sstevel@tonic-gate nvlist_t *nvl, *cnvl;
9477c478bd9Sstevel@tonic-gate nvpair_t *child = NULL;
9487c478bd9Sstevel@tonic-gate uchar_t *cbuf = NULL;
9497c478bd9Sstevel@tonic-gate uint_t csize;
9507c478bd9Sstevel@tonic-gate
9517c478bd9Sstevel@tonic-gate /* Expand to an nvlist */
9527c478bd9Sstevel@tonic-gate if (nvlist_unpack((char *)buf, size, &nvl, 0))
9532545779bSRobert Mustacchi err(-1, "error processing snapshot");
9547c478bd9Sstevel@tonic-gate
9557c478bd9Sstevel@tonic-gate /* print current node */
9567c478bd9Sstevel@tonic-gate dump_node(nvl, level);
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate /* print children */
9597c478bd9Sstevel@tonic-gate error = nvlist_lookup_byte_array(nvl, "@child", &cbuf, &csize);
9607c478bd9Sstevel@tonic-gate if ((error == ENOENT) || (cbuf == NULL))
9617c478bd9Sstevel@tonic-gate return; /* no child exists */
9627c478bd9Sstevel@tonic-gate
9637c478bd9Sstevel@tonic-gate if (error || nvlist_unpack((char *)cbuf, csize, &cnvl, 0))
9642545779bSRobert Mustacchi err(-1, "error processing snapshot");
9657c478bd9Sstevel@tonic-gate
9662545779bSRobert Mustacchi while ((child = nvlist_next_nvpair(cnvl, child)) != NULL) {
9677c478bd9Sstevel@tonic-gate char *name = nvpair_name(child);
9687c478bd9Sstevel@tonic-gate data_type_t type = nvpair_type(child);
9697c478bd9Sstevel@tonic-gate uchar_t *nodebuf;
9707c478bd9Sstevel@tonic-gate uint_t nodesize;
9717c478bd9Sstevel@tonic-gate if (strcmp("node", name) != 0) {
9727c478bd9Sstevel@tonic-gate dprintf("unexpected nvpair name %s != name\n", name);
9737c478bd9Sstevel@tonic-gate continue;
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate if (type != DATA_TYPE_BYTE_ARRAY) {
9767c478bd9Sstevel@tonic-gate dprintf("unexpected nvpair type %d, not byte array \n",
9777c478bd9Sstevel@tonic-gate type);
9787c478bd9Sstevel@tonic-gate continue;
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate (void) nvpair_value_byte_array(child,
9827c478bd9Sstevel@tonic-gate (uchar_t **)&nodebuf, &nodesize);
9837c478bd9Sstevel@tonic-gate walk(nodebuf, nodesize, level + 1);
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate nvlist_free(nvl);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate /*
990*1c7f36ecSRobert Mustacchi * The encoding of the name property depends on whether we got verbose prom
991*1c7f36ecSRobert Mustacchi * information or not. If we didn't, it'll just be a string in the nvlist_t.
992*1c7f36ecSRobert Mustacchi * However, otherwise it'll end up being byte data that the kernel guarantees
993*1c7f36ecSRobert Mustacchi * for 'name' is actually a null terminated string.
994*1c7f36ecSRobert Mustacchi */
995*1c7f36ecSRobert Mustacchi static const char *
prom_node_name(nvlist_t * nvl)996*1c7f36ecSRobert Mustacchi prom_node_name(nvlist_t *nvl)
997*1c7f36ecSRobert Mustacchi {
998*1c7f36ecSRobert Mustacchi char *str;
999*1c7f36ecSRobert Mustacchi uchar_t *bval;
1000*1c7f36ecSRobert Mustacchi uint_t len;
1001*1c7f36ecSRobert Mustacchi
1002*1c7f36ecSRobert Mustacchi if (nvlist_lookup_string(nvl, "name", &str) == 0) {
1003*1c7f36ecSRobert Mustacchi return (str);
1004*1c7f36ecSRobert Mustacchi }
1005*1c7f36ecSRobert Mustacchi
1006*1c7f36ecSRobert Mustacchi if (nvlist_lookup_byte_array(nvl, "name", &bval, &len) == 0) {
1007*1c7f36ecSRobert Mustacchi if (bval[len - 1] == '\0')
1008*1c7f36ecSRobert Mustacchi return ((char *)bval);
1009*1c7f36ecSRobert Mustacchi }
1010*1c7f36ecSRobert Mustacchi
1011*1c7f36ecSRobert Mustacchi return ("data not available");
1012*1c7f36ecSRobert Mustacchi }
1013*1c7f36ecSRobert Mustacchi
1014*1c7f36ecSRobert Mustacchi /*
1015*1c7f36ecSRobert Mustacchi * Given a node at a given level, try to determine if this is a PCI device. We
1016*1c7f36ecSRobert Mustacchi * do this through a two step process mostly due to the fact that we don't have
1017*1c7f36ecSRobert Mustacchi * easy linkage to the parent here and not all nodes have everything we expect.
1018*1c7f36ecSRobert Mustacchi * This test is more similar to the pcieadm test than what we use for the normal
1019*1c7f36ecSRobert Mustacchi * devinfo part.
1020*1c7f36ecSRobert Mustacchi *
1021*1c7f36ecSRobert Mustacchi * 1. Check the node name to see if it starts with pci with another character
1022*1c7f36ecSRobert Mustacchi * (to avoid the synthetic pci instances).
1023*1c7f36ecSRobert Mustacchi * 2. Look at the compatible property for the class strings.
1024*1c7f36ecSRobert Mustacchi */
1025*1c7f36ecSRobert Mustacchi static boolean_t
prom_is_pci(nvlist_t * nvl,const char * name)1026*1c7f36ecSRobert Mustacchi prom_is_pci(nvlist_t *nvl, const char *name)
1027*1c7f36ecSRobert Mustacchi {
1028*1c7f36ecSRobert Mustacchi uchar_t *value;
1029*1c7f36ecSRobert Mustacchi uint_t len;
1030*1c7f36ecSRobert Mustacchi
1031*1c7f36ecSRobert Mustacchi if (strncmp("pci", name, 3) == 0 && name[3] != '\0') {
1032*1c7f36ecSRobert Mustacchi return (B_TRUE);
1033*1c7f36ecSRobert Mustacchi }
1034*1c7f36ecSRobert Mustacchi
1035*1c7f36ecSRobert Mustacchi /*
1036*1c7f36ecSRobert Mustacchi * This is a composite string. Unlike with devinfo, we just have the
1037*1c7f36ecSRobert Mustacchi * array of strings here and we have to manually make sure we don't
1038*1c7f36ecSRobert Mustacchi * exceed the size as we don't have the total number of entries.
1039*1c7f36ecSRobert Mustacchi */
1040*1c7f36ecSRobert Mustacchi if (nvlist_lookup_byte_array(nvl, "compatible", &value, &len) == 0) {
1041*1c7f36ecSRobert Mustacchi const char *str;
1042*1c7f36ecSRobert Mustacchi
1043*1c7f36ecSRobert Mustacchi /*
1044*1c7f36ecSRobert Mustacchi * Adjust by one to account or the extra NUL that the driver
1045*1c7f36ecSRobert Mustacchi * inserts.
1046*1c7f36ecSRobert Mustacchi */
1047*1c7f36ecSRobert Mustacchi len--;
1048*1c7f36ecSRobert Mustacchi for (str = (char *)value; str < ((char *)value + len);
1049*1c7f36ecSRobert Mustacchi str += strlen(str) + 1) {
1050*1c7f36ecSRobert Mustacchi if (strncmp("pciclass,", str,
1051*1c7f36ecSRobert Mustacchi sizeof ("pciclass,") - 1) == 0 ||
1052*1c7f36ecSRobert Mustacchi strncmp("pciexclass,", str,
1053*1c7f36ecSRobert Mustacchi sizeof ("pciexclass,") - 1) == 0) {
1054*1c7f36ecSRobert Mustacchi return (B_TRUE);
1055*1c7f36ecSRobert Mustacchi }
1056*1c7f36ecSRobert Mustacchi }
1057*1c7f36ecSRobert Mustacchi }
1058*1c7f36ecSRobert Mustacchi
1059*1c7f36ecSRobert Mustacchi return (B_FALSE);
1060*1c7f36ecSRobert Mustacchi }
1061*1c7f36ecSRobert Mustacchi
1062*1c7f36ecSRobert Mustacchi static boolean_t
prom_extract_u16(nvlist_t * nvl,const char * name,uint16_t * valp)1063*1c7f36ecSRobert Mustacchi prom_extract_u16(nvlist_t *nvl, const char *name, uint16_t *valp)
1064*1c7f36ecSRobert Mustacchi {
1065*1c7f36ecSRobert Mustacchi uchar_t *value;
1066*1c7f36ecSRobert Mustacchi uint_t len;
1067*1c7f36ecSRobert Mustacchi uint32_t u32;
1068*1c7f36ecSRobert Mustacchi
1069*1c7f36ecSRobert Mustacchi if (nvlist_lookup_byte_array(nvl, name, &value, &len) != 0) {
1070*1c7f36ecSRobert Mustacchi return (B_FALSE);
1071*1c7f36ecSRobert Mustacchi }
1072*1c7f36ecSRobert Mustacchi
1073*1c7f36ecSRobert Mustacchi /*
1074*1c7f36ecSRobert Mustacchi * A uint32_t will be encoded as a 4-byte value followed by a NUL
1075*1c7f36ecSRobert Mustacchi * regardless.
1076*1c7f36ecSRobert Mustacchi */
1077*1c7f36ecSRobert Mustacchi if (len != 5 || value[4] != '\0') {
1078*1c7f36ecSRobert Mustacchi return (B_FALSE);
1079*1c7f36ecSRobert Mustacchi }
1080*1c7f36ecSRobert Mustacchi
1081*1c7f36ecSRobert Mustacchi /*
1082*1c7f36ecSRobert Mustacchi * The current PROM code puts values in the native-endianness for x86
1083*1c7f36ecSRobert Mustacchi * and SPARC as opposed to always translating into what 1275 wants of
1084*1c7f36ecSRobert Mustacchi * big endian. It is unclear what'll happen for subsequent platforms.
1085*1c7f36ecSRobert Mustacchi */
1086*1c7f36ecSRobert Mustacchi #if !defined(__x86)
1087*1c7f36ecSRobert Mustacchi #error "determine endianness of the platform's openprom interface"
1088*1c7f36ecSRobert Mustacchi #endif
1089*1c7f36ecSRobert Mustacchi (void) memcpy(&u32, value, sizeof (u32));
1090*1c7f36ecSRobert Mustacchi if (u32 > UINT16_MAX) {
1091*1c7f36ecSRobert Mustacchi return (B_FALSE);
1092*1c7f36ecSRobert Mustacchi }
1093*1c7f36ecSRobert Mustacchi
1094*1c7f36ecSRobert Mustacchi *valp = (uint16_t)u32;
1095*1c7f36ecSRobert Mustacchi return (B_TRUE);
1096*1c7f36ecSRobert Mustacchi }
1097*1c7f36ecSRobert Mustacchi
1098*1c7f36ecSRobert Mustacchi /*
1099*1c7f36ecSRobert Mustacchi * Similar to the above, synthesize the device type as either pci or pciex based
1100*1c7f36ecSRobert Mustacchi * on the compatible array. A PCI Express device will have their first entry
1101*1c7f36ecSRobert Mustacchi * start with 'pciexXXXX,XXXX'. A device without that will just start with pci.
1102*1c7f36ecSRobert Mustacchi */
1103*1c7f36ecSRobert Mustacchi static const char *
prom_pci_device_type(nvlist_t * nvl)1104*1c7f36ecSRobert Mustacchi prom_pci_device_type(nvlist_t *nvl)
1105*1c7f36ecSRobert Mustacchi {
1106*1c7f36ecSRobert Mustacchi uchar_t *value;
1107*1c7f36ecSRobert Mustacchi uint_t len;
1108*1c7f36ecSRobert Mustacchi
1109*1c7f36ecSRobert Mustacchi if (nvlist_lookup_byte_array(nvl, "compatible", &value, &len) != 0) {
1110*1c7f36ecSRobert Mustacchi return (NULL);
1111*1c7f36ecSRobert Mustacchi }
1112*1c7f36ecSRobert Mustacchi
1113*1c7f36ecSRobert Mustacchi if (strncmp("pciex", (char *)value, 5) == 0 && value[5] != '\0') {
1114*1c7f36ecSRobert Mustacchi return ("pciex");
1115*1c7f36ecSRobert Mustacchi }
1116*1c7f36ecSRobert Mustacchi
1117*1c7f36ecSRobert Mustacchi if (strncmp("pci", (char *)value, 3) == 0 && value[3] != '\0') {
1118*1c7f36ecSRobert Mustacchi return ("pci");
1119*1c7f36ecSRobert Mustacchi }
1120*1c7f36ecSRobert Mustacchi
1121*1c7f36ecSRobert Mustacchi return (NULL);
1122*1c7f36ecSRobert Mustacchi }
1123*1c7f36ecSRobert Mustacchi
1124*1c7f36ecSRobert Mustacchi static void
dump_pcidb(int level,uint16_t vid,uint16_t did,boolean_t do_sub,uint16_t svid,uint16_t sdid)1125*1c7f36ecSRobert Mustacchi dump_pcidb(int level, uint16_t vid, uint16_t did, boolean_t do_sub,
1126*1c7f36ecSRobert Mustacchi uint16_t svid, uint16_t sdid)
1127*1c7f36ecSRobert Mustacchi {
1128*1c7f36ecSRobert Mustacchi const char *vstr = "unknown vendor";
1129*1c7f36ecSRobert Mustacchi const char *dstr = "unknown device";
1130*1c7f36ecSRobert Mustacchi const char *sstr = "unknown subsystem";
1131*1c7f36ecSRobert Mustacchi pcidb_vendor_t *pciv = NULL;
1132*1c7f36ecSRobert Mustacchi pcidb_device_t *pcid = NULL;
1133*1c7f36ecSRobert Mustacchi pcidb_subvd_t *pcis = NULL;
1134*1c7f36ecSRobert Mustacchi
1135*1c7f36ecSRobert Mustacchi if (opts.o_pcidb == NULL)
1136*1c7f36ecSRobert Mustacchi return;
1137*1c7f36ecSRobert Mustacchi
1138*1c7f36ecSRobert Mustacchi pciv = pcidb_lookup_vendor(opts.o_pcidb, vid);
1139*1c7f36ecSRobert Mustacchi if (pciv != NULL) {
1140*1c7f36ecSRobert Mustacchi vstr = pcidb_vendor_name(pciv);
1141*1c7f36ecSRobert Mustacchi pcid = pcidb_lookup_device_by_vendor(pciv, did);
1142*1c7f36ecSRobert Mustacchi if (pcid != NULL) {
1143*1c7f36ecSRobert Mustacchi dstr = pcidb_device_name(pcid);
1144*1c7f36ecSRobert Mustacchi }
1145*1c7f36ecSRobert Mustacchi }
1146*1c7f36ecSRobert Mustacchi
1147*1c7f36ecSRobert Mustacchi indent_to_level(level);
1148*1c7f36ecSRobert Mustacchi (void) printf("vendor-name: '%s'\n", vstr);
1149*1c7f36ecSRobert Mustacchi indent_to_level(level);
1150*1c7f36ecSRobert Mustacchi (void) printf("device-name: '%s'\n", dstr);
1151*1c7f36ecSRobert Mustacchi
1152*1c7f36ecSRobert Mustacchi if (!do_sub)
1153*1c7f36ecSRobert Mustacchi return;
1154*1c7f36ecSRobert Mustacchi
1155*1c7f36ecSRobert Mustacchi if (pciv != NULL && pcid != NULL) {
1156*1c7f36ecSRobert Mustacchi pcis = pcidb_lookup_subvd_by_device(pcid, svid, sdid);
1157*1c7f36ecSRobert Mustacchi if (pcis != NULL) {
1158*1c7f36ecSRobert Mustacchi sstr = pcidb_subvd_name(pcis);
1159*1c7f36ecSRobert Mustacchi }
1160*1c7f36ecSRobert Mustacchi }
1161*1c7f36ecSRobert Mustacchi
1162*1c7f36ecSRobert Mustacchi indent_to_level(level);
1163*1c7f36ecSRobert Mustacchi (void) printf("subsystem-name: '%s'\n", sstr);
1164*1c7f36ecSRobert Mustacchi }
1165*1c7f36ecSRobert Mustacchi
1166*1c7f36ecSRobert Mustacchi /*
1167*1c7f36ecSRobert Mustacchi * Print all properties and values. When o_verbose is specified then rather than
1168*1c7f36ecSRobert Mustacchi * printing the name of the node (and potentially the PCI ID and DB info), we
1169*1c7f36ecSRobert Mustacchi * print the node name and instead include all that information in properties.
1170*1c7f36ecSRobert Mustacchi * This mimics the behavior of the non-prom path.
11717c478bd9Sstevel@tonic-gate */
11727c478bd9Sstevel@tonic-gate static void
dump_node(nvlist_t * nvl,int level)11737c478bd9Sstevel@tonic-gate dump_node(nvlist_t *nvl, int level)
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate int id = 0;
1176*1c7f36ecSRobert Mustacchi const char *name;
11777c478bd9Sstevel@tonic-gate nvpair_t *nvp = NULL;
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate indent_to_level(level);
1180*1c7f36ecSRobert Mustacchi name = prom_node_name(nvl);
11817c478bd9Sstevel@tonic-gate (void) printf("Node");
11827c478bd9Sstevel@tonic-gate if (!opts.o_verbose) {
1183*1c7f36ecSRobert Mustacchi (void) printf(" '%s'", name);
1184*1c7f36ecSRobert Mustacchi
1185*1c7f36ecSRobert Mustacchi if (opts.o_pciid && prom_is_pci(nvl, name)) {
1186*1c7f36ecSRobert Mustacchi const char *dtype = prom_pci_device_type(nvl);
1187*1c7f36ecSRobert Mustacchi uint16_t vid, did;
1188*1c7f36ecSRobert Mustacchi
1189*1c7f36ecSRobert Mustacchi if (prom_extract_u16(nvl, "vendor-id", &vid) &&
1190*1c7f36ecSRobert Mustacchi prom_extract_u16(nvl, "device-id", &did) &&
1191*1c7f36ecSRobert Mustacchi dtype != NULL) {
1192*1c7f36ecSRobert Mustacchi print_pciid(dtype, vid, did, opts.o_pcidb);
1193*1c7f36ecSRobert Mustacchi }
1194*1c7f36ecSRobert Mustacchi
1195*1c7f36ecSRobert Mustacchi }
1196*1c7f36ecSRobert Mustacchi } else {
1197*1c7f36ecSRobert Mustacchi (void) nvlist_lookup_int32(nvl, "@nodeid", &id);
1198*1c7f36ecSRobert Mustacchi (void) printf(" %#08x\n", id);
1199*1c7f36ecSRobert Mustacchi }
1200*1c7f36ecSRobert Mustacchi
1201*1c7f36ecSRobert Mustacchi if (!opts.o_verbose) {
12027c478bd9Sstevel@tonic-gate (void) putchar('\n');
12037c478bd9Sstevel@tonic-gate return;
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate
12062545779bSRobert Mustacchi while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
12077c478bd9Sstevel@tonic-gate name = nvpair_name(nvp);
12087c478bd9Sstevel@tonic-gate if (name[0] == '@')
12097c478bd9Sstevel@tonic-gate continue;
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gate print_one(nvp, level + 1);
12127c478bd9Sstevel@tonic-gate }
1213*1c7f36ecSRobert Mustacchi
1214*1c7f36ecSRobert Mustacchi /*
1215*1c7f36ecSRobert Mustacchi * Go through and create synthetic properties for PCI devices like the
1216*1c7f36ecSRobert Mustacchi * normal device tree path.
1217*1c7f36ecSRobert Mustacchi */
1218*1c7f36ecSRobert Mustacchi if (prom_is_pci(nvl, name)) {
1219*1c7f36ecSRobert Mustacchi uint16_t vid = UINT16_MAX, did = UINT16_MAX;
1220*1c7f36ecSRobert Mustacchi uint16_t svid = UINT16_MAX, sdid = UINT16_MAX;
1221*1c7f36ecSRobert Mustacchi boolean_t valid_sub = B_FALSE;
1222*1c7f36ecSRobert Mustacchi
1223*1c7f36ecSRobert Mustacchi if (prom_extract_u16(nvl, "subsystem-vendor-id", &svid) &&
1224*1c7f36ecSRobert Mustacchi prom_extract_u16(nvl, "subsystem-id", &sdid)) {
1225*1c7f36ecSRobert Mustacchi valid_sub = B_TRUE;
1226*1c7f36ecSRobert Mustacchi }
1227*1c7f36ecSRobert Mustacchi
1228*1c7f36ecSRobert Mustacchi if (prom_extract_u16(nvl, "vendor-id", &vid) &&
1229*1c7f36ecSRobert Mustacchi prom_extract_u16(nvl, "device-id", &did)) {
1230*1c7f36ecSRobert Mustacchi dump_pcidb(level + 1, vid, did, valid_sub, svid, sdid);
1231*1c7f36ecSRobert Mustacchi }
1232*1c7f36ecSRobert Mustacchi }
1233*1c7f36ecSRobert Mustacchi
12347c478bd9Sstevel@tonic-gate (void) putchar('\n');
12357c478bd9Sstevel@tonic-gate }
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate static const char *
path_state_name(di_path_state_t st)12387c478bd9Sstevel@tonic-gate path_state_name(di_path_state_t st)
12397c478bd9Sstevel@tonic-gate {
12407c478bd9Sstevel@tonic-gate switch (st) {
12417c478bd9Sstevel@tonic-gate case DI_PATH_STATE_ONLINE:
12427c478bd9Sstevel@tonic-gate return ("online");
12437c478bd9Sstevel@tonic-gate case DI_PATH_STATE_STANDBY:
12447c478bd9Sstevel@tonic-gate return ("standby");
12457c478bd9Sstevel@tonic-gate case DI_PATH_STATE_OFFLINE:
12467c478bd9Sstevel@tonic-gate return ("offline");
12477c478bd9Sstevel@tonic-gate case DI_PATH_STATE_FAULT:
12487c478bd9Sstevel@tonic-gate return ("faulted");
12492545779bSRobert Mustacchi case DI_PATH_STATE_UNKNOWN:
12502545779bSRobert Mustacchi default:
12512545779bSRobert Mustacchi return ("unknown");
12527c478bd9Sstevel@tonic-gate }
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate
12557c478bd9Sstevel@tonic-gate /*
12567c478bd9Sstevel@tonic-gate * Print all phci's each client is connected to.
12577c478bd9Sstevel@tonic-gate */
12587c478bd9Sstevel@tonic-gate static void
dump_pathing_data(int ilev,di_node_t node)12597c478bd9Sstevel@tonic-gate dump_pathing_data(int ilev, di_node_t node)
12607c478bd9Sstevel@tonic-gate {
1261602ca9eaScth di_path_t pi = DI_PATH_NIL;
1262602ca9eaScth di_node_t phci_node;
1263602ca9eaScth char *phci_path;
1264602ca9eaScth int path_instance;
1265602ca9eaScth int firsttime = 1;
12667c478bd9Sstevel@tonic-gate
12677c478bd9Sstevel@tonic-gate if (node == DI_PATH_NIL)
12687c478bd9Sstevel@tonic-gate return;
12697c478bd9Sstevel@tonic-gate
1270602ca9eaScth while ((pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) {
12714c06356bSdh
12724c06356bSdh /* It is not really a path if we failed to capture the pHCI */
12734c06356bSdh phci_node = di_path_phci_node(pi);
12744c06356bSdh if (phci_node == DI_NODE_NIL)
12754c06356bSdh continue;
12764c06356bSdh
12774c06356bSdh /* Print header for the first path */
12787c478bd9Sstevel@tonic-gate if (firsttime) {
12797c478bd9Sstevel@tonic-gate indent_to_level(ilev);
12807c478bd9Sstevel@tonic-gate firsttime = 0;
12817c478bd9Sstevel@tonic-gate ilev++;
12827c478bd9Sstevel@tonic-gate (void) printf("Paths from multipath bus adapters:\n");
12837c478bd9Sstevel@tonic-gate }
12847c478bd9Sstevel@tonic-gate
1285602ca9eaScth /*
1286602ca9eaScth * Print the path instance and full "pathinfo" path, which is
1287602ca9eaScth * the same as the /devices devifo path had the device been
1288602ca9eaScth * enumerated under pHCI.
1289602ca9eaScth */
1290602ca9eaScth phci_path = di_devfs_path(phci_node);
1291602ca9eaScth if (phci_path) {
12924c06356bSdh path_instance = di_path_instance(pi);
1293602ca9eaScth if (path_instance > 0) {
1294602ca9eaScth indent_to_level(ilev);
1295602ca9eaScth (void) printf("Path %d: %s/%s@%s\n",
1296602ca9eaScth path_instance, phci_path,
1297602ca9eaScth di_node_name(node),
1298602ca9eaScth di_path_bus_addr(pi));
1299602ca9eaScth }
1300602ca9eaScth di_devfs_path_free(phci_path);
1301602ca9eaScth }
1302602ca9eaScth
1303602ca9eaScth /* print phci driver, instance, and path state information */
13047c478bd9Sstevel@tonic-gate indent_to_level(ilev);
13057c478bd9Sstevel@tonic-gate (void) printf("%s#%d (%s)\n", di_driver_name(phci_node),
13067c478bd9Sstevel@tonic-gate di_instance(phci_node), path_state_name(di_path_state(pi)));
13074c06356bSdh
1308b9ccdc5aScth (void) dump_prop_list(&pathprop_dumpops, NULL, ilev + 1,
1309fa084259Scth pi, DDI_DEV_T_ANY, NULL);
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate
13137c478bd9Sstevel@tonic-gate static int
dump_minor_data_links(di_devlink_t devlink,void * arg)13147c478bd9Sstevel@tonic-gate dump_minor_data_links(di_devlink_t devlink, void *arg)
13157c478bd9Sstevel@tonic-gate {
13167c478bd9Sstevel@tonic-gate int ilev = (intptr_t)arg;
13177c478bd9Sstevel@tonic-gate indent_to_level(ilev);
13187c478bd9Sstevel@tonic-gate (void) printf("dev_link=%s\n", di_devlink_path(devlink));
13197c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
13207c478bd9Sstevel@tonic-gate }
13217c478bd9Sstevel@tonic-gate
13227c478bd9Sstevel@tonic-gate static void
dump_minor_data_paths(int ilev,di_minor_t minor,di_devlink_handle_t devlink_hdl)13237c478bd9Sstevel@tonic-gate dump_minor_data_paths(int ilev, di_minor_t minor,
13247c478bd9Sstevel@tonic-gate di_devlink_handle_t devlink_hdl)
13257c478bd9Sstevel@tonic-gate {
13267c478bd9Sstevel@tonic-gate char *path, *type;
13277c478bd9Sstevel@tonic-gate int spec_type;
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate /* get the path to the device and the minor node name */
13307c478bd9Sstevel@tonic-gate if ((path = di_devfs_minor_path(minor)) == NULL)
13312545779bSRobert Mustacchi err(-1, "failed to allocate memory");
13327c478bd9Sstevel@tonic-gate
13337c478bd9Sstevel@tonic-gate /* display the path to this minor node */
13347c478bd9Sstevel@tonic-gate indent_to_level(ilev);
13357c478bd9Sstevel@tonic-gate (void) printf("dev_path=%s\n", path);
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate if (devlink_hdl != NULL) {
13387c478bd9Sstevel@tonic-gate
13397c478bd9Sstevel@tonic-gate /* get the device minor node information */
13407c478bd9Sstevel@tonic-gate spec_type = di_minor_spectype(minor);
13417c478bd9Sstevel@tonic-gate switch (di_minor_type(minor)) {
13427c478bd9Sstevel@tonic-gate case DDM_MINOR:
13437c478bd9Sstevel@tonic-gate type = "minor";
13447c478bd9Sstevel@tonic-gate break;
13457c478bd9Sstevel@tonic-gate case DDM_ALIAS:
13467c478bd9Sstevel@tonic-gate type = "alias";
13477c478bd9Sstevel@tonic-gate break;
13487c478bd9Sstevel@tonic-gate case DDM_DEFAULT:
13497c478bd9Sstevel@tonic-gate type = "default";
13507c478bd9Sstevel@tonic-gate break;
13517c478bd9Sstevel@tonic-gate case DDM_INTERNAL_PATH:
13527c478bd9Sstevel@tonic-gate type = "internal";
13537c478bd9Sstevel@tonic-gate break;
13547c478bd9Sstevel@tonic-gate default:
13557c478bd9Sstevel@tonic-gate type = "unknown";
13567c478bd9Sstevel@tonic-gate break;
13577c478bd9Sstevel@tonic-gate }
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate /* display the device minor node information */
13607c478bd9Sstevel@tonic-gate indent_to_level(ilev + 1);
13617c478bd9Sstevel@tonic-gate (void) printf("spectype=%s type=%s\n",
136258c0eeecScth (spec_type == S_IFBLK) ? "blk" : "chr", type);
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate /* display all the devlinks for this device minor node */
13657c478bd9Sstevel@tonic-gate (void) di_devlink_walk(devlink_hdl, NULL, path,
13667c478bd9Sstevel@tonic-gate 0, (void *)(intptr_t)(ilev + 1), dump_minor_data_links);
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate
13697c478bd9Sstevel@tonic-gate di_devfs_path_free(path);
13707c478bd9Sstevel@tonic-gate }
13717c478bd9Sstevel@tonic-gate
13727c478bd9Sstevel@tonic-gate static void
create_minor_list(di_node_t node)13737c478bd9Sstevel@tonic-gate create_minor_list(di_node_t node)
13747c478bd9Sstevel@tonic-gate {
13757c478bd9Sstevel@tonic-gate di_minor_t minor, minor_head, minor_tail, minor_prev, minor_walk;
13767c478bd9Sstevel@tonic-gate int major;
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate /* if there are no minor nodes, bail */
13797c478bd9Sstevel@tonic-gate if (di_minor_next(node, DI_MINOR_NIL) == DI_MINOR_NIL)
13807c478bd9Sstevel@tonic-gate return;
13817c478bd9Sstevel@tonic-gate
13827c478bd9Sstevel@tonic-gate /*
13837c478bd9Sstevel@tonic-gate * here we want to create lists of minor nodes with the same
13847c478bd9Sstevel@tonic-gate * dev_t. to do this we first sort all the minor nodes by devt.
13857c478bd9Sstevel@tonic-gate *
13867c478bd9Sstevel@tonic-gate * the algorithm used here is a bubble sort, so performance sucks.
13877c478bd9Sstevel@tonic-gate * but it's probably ok here because most device instances don't
13887c478bd9Sstevel@tonic-gate * have that many minor nodes. also we're doing this as we're
13897c478bd9Sstevel@tonic-gate * displaying each node so it doesn't look like we're pausing
13907c478bd9Sstevel@tonic-gate * output for a long time.
13917c478bd9Sstevel@tonic-gate */
13927c478bd9Sstevel@tonic-gate major = di_driver_major(node);
13937c478bd9Sstevel@tonic-gate minor_head = minor_tail = minor = DI_MINOR_NIL;
13947c478bd9Sstevel@tonic-gate while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
13957c478bd9Sstevel@tonic-gate dev_t dev = di_minor_devt(minor);
13967c478bd9Sstevel@tonic-gate
13977c478bd9Sstevel@tonic-gate /* skip /pseudo/clone@0 minor nodes */
13987c478bd9Sstevel@tonic-gate if (major != major(dev))
13997c478bd9Sstevel@tonic-gate continue;
14007c478bd9Sstevel@tonic-gate
14017c478bd9Sstevel@tonic-gate minor_ptr_set(minor, DI_MINOR_NIL);
14027c478bd9Sstevel@tonic-gate if (minor_head == DI_MINOR_NIL) {
14037c478bd9Sstevel@tonic-gate /* this is the first minor node we're looking at */
14047c478bd9Sstevel@tonic-gate minor_head = minor_tail = minor;
14057c478bd9Sstevel@tonic-gate continue;
14067c478bd9Sstevel@tonic-gate }
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate /*
14097c478bd9Sstevel@tonic-gate * if the new dev is less than the old dev, update minor_head
14107c478bd9Sstevel@tonic-gate * so it points to the beginning of the list. ie it points
14117c478bd9Sstevel@tonic-gate * to the node with the lowest dev value
14127c478bd9Sstevel@tonic-gate */
14137c478bd9Sstevel@tonic-gate if (dev <= di_minor_devt(minor_head)) {
14147c478bd9Sstevel@tonic-gate minor_ptr_set(minor, minor_head);
14157c478bd9Sstevel@tonic-gate minor_head = minor;
14167c478bd9Sstevel@tonic-gate continue;
14177c478bd9Sstevel@tonic-gate }
14187c478bd9Sstevel@tonic-gate
14197c478bd9Sstevel@tonic-gate minor_prev = minor_head;
14207c478bd9Sstevel@tonic-gate minor_walk = minor_ptr(minor_head);
14217c478bd9Sstevel@tonic-gate while ((minor_walk != DI_MINOR_NIL) &&
142258c0eeecScth (dev > di_minor_devt(minor_walk))) {
14237c478bd9Sstevel@tonic-gate minor_prev = minor_walk;
14247c478bd9Sstevel@tonic-gate minor_walk = minor_ptr(minor_walk);
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate minor_ptr_set(minor, minor_walk);
14277c478bd9Sstevel@tonic-gate minor_ptr_set(minor_prev, minor);
14287c478bd9Sstevel@tonic-gate if (minor_walk == NULL)
14297c478bd9Sstevel@tonic-gate minor_tail = minor;
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate /* check if there were any non /pseudo/clone@0 nodes. if not, bail */
14337c478bd9Sstevel@tonic-gate if (minor_head == DI_MINOR_NIL)
14347c478bd9Sstevel@tonic-gate return;
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate /*
14377c478bd9Sstevel@tonic-gate * now that we have a list of minor nodes sorted by devt
14387c478bd9Sstevel@tonic-gate * we walk through the list and break apart the entire list
14397c478bd9Sstevel@tonic-gate * to create circular lists of minor nodes with matching devts.
14407c478bd9Sstevel@tonic-gate */
14417c478bd9Sstevel@tonic-gate minor_prev = minor_head;
14427c478bd9Sstevel@tonic-gate minor_walk = minor_ptr(minor_head);
14437c478bd9Sstevel@tonic-gate while (minor_walk != DI_MINOR_NIL) {
14447c478bd9Sstevel@tonic-gate if (di_minor_devt(minor_prev) != di_minor_devt(minor_walk)) {
14457c478bd9Sstevel@tonic-gate minor_ptr_set(minor_prev, minor_head);
14467c478bd9Sstevel@tonic-gate minor_head = minor_walk;
14477c478bd9Sstevel@tonic-gate }
14487c478bd9Sstevel@tonic-gate minor_prev = minor_walk;
14497c478bd9Sstevel@tonic-gate minor_walk = minor_ptr(minor_walk);
14507c478bd9Sstevel@tonic-gate }
14517c478bd9Sstevel@tonic-gate minor_ptr_set(minor_tail, minor_head);
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate static void
link_lnode_disp(di_link_t link,uint_t endpoint,int ilev,di_devlink_handle_t devlink_hdl)14557c478bd9Sstevel@tonic-gate link_lnode_disp(di_link_t link, uint_t endpoint, int ilev,
14567c478bd9Sstevel@tonic-gate di_devlink_handle_t devlink_hdl)
14577c478bd9Sstevel@tonic-gate {
14587c478bd9Sstevel@tonic-gate di_lnode_t lnode;
14597c478bd9Sstevel@tonic-gate char *name, *path;
14607c478bd9Sstevel@tonic-gate int displayed_path, spec_type;
14617c478bd9Sstevel@tonic-gate di_node_t node = DI_NODE_NIL;
14627c478bd9Sstevel@tonic-gate dev_t devt = DDI_DEV_T_NONE;
14637c478bd9Sstevel@tonic-gate
14647c478bd9Sstevel@tonic-gate lnode = di_link_to_lnode(link, endpoint);
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate indent_to_level(ilev);
14677c478bd9Sstevel@tonic-gate name = di_lnode_name(lnode);
14687c478bd9Sstevel@tonic-gate spec_type = di_link_spectype(link);
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate (void) printf("mod=%s", name);
14717c478bd9Sstevel@tonic-gate
14727c478bd9Sstevel@tonic-gate /*
14737c478bd9Sstevel@tonic-gate * if we're displaying the source of a link, we should display
14747c478bd9Sstevel@tonic-gate * the target access mode. (either block or char.)
14757c478bd9Sstevel@tonic-gate */
14767c478bd9Sstevel@tonic-gate if (endpoint == DI_LINK_SRC)
14777c478bd9Sstevel@tonic-gate (void) printf(" accesstype=%s",
14787c478bd9Sstevel@tonic-gate (spec_type == S_IFBLK) ? "blk" : "chr");
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate /*
14817c478bd9Sstevel@tonic-gate * check if the lnode is bound to a specific device
14827c478bd9Sstevel@tonic-gate * minor node (i.e. if it's bound to a dev_t) and
14837c478bd9Sstevel@tonic-gate * if so display the dev_t value and any possible
14847c478bd9Sstevel@tonic-gate * minor node pathing information.
14857c478bd9Sstevel@tonic-gate */
14867c478bd9Sstevel@tonic-gate displayed_path = 0;
14877c478bd9Sstevel@tonic-gate if (di_lnode_devt(lnode, &devt) == 0) {
14887c478bd9Sstevel@tonic-gate di_minor_t minor = DI_MINOR_NIL;
14897c478bd9Sstevel@tonic-gate
14907c478bd9Sstevel@tonic-gate (void) printf(" dev=(%u,%u)\n",
14917c478bd9Sstevel@tonic-gate (uint_t)major(devt), (uint_t)minor(devt));
14927c478bd9Sstevel@tonic-gate
14937c478bd9Sstevel@tonic-gate /* display paths to the src devt minor node */
14942545779bSRobert Mustacchi while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
14957c478bd9Sstevel@tonic-gate if (devt != di_minor_devt(minor))
14967c478bd9Sstevel@tonic-gate continue;
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate if ((endpoint == DI_LINK_TGT) &&
14997c478bd9Sstevel@tonic-gate (spec_type != di_minor_spectype(minor)))
15007c478bd9Sstevel@tonic-gate continue;
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate dump_minor_data_paths(ilev + 1, minor, devlink_hdl);
15037c478bd9Sstevel@tonic-gate displayed_path = 1;
15047c478bd9Sstevel@tonic-gate }
15057c478bd9Sstevel@tonic-gate } else {
15067c478bd9Sstevel@tonic-gate (void) printf("\n");
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate
15097c478bd9Sstevel@tonic-gate if (displayed_path)
15107c478bd9Sstevel@tonic-gate return;
15117c478bd9Sstevel@tonic-gate
15127c478bd9Sstevel@tonic-gate /*
15137c478bd9Sstevel@tonic-gate * This device lnode is not did not have any minor node
15147c478bd9Sstevel@tonic-gate * pathing information so display the path to device node.
15157c478bd9Sstevel@tonic-gate */
15167c478bd9Sstevel@tonic-gate node = di_lnode_devinfo(lnode);
15177c478bd9Sstevel@tonic-gate if ((path = di_devfs_path(node)) == NULL)
15182545779bSRobert Mustacchi err(-1, "failed to allocate memory");
15197c478bd9Sstevel@tonic-gate
15207c478bd9Sstevel@tonic-gate indent_to_level(ilev + 1);
15217c478bd9Sstevel@tonic-gate (void) printf("dev_path=%s\n", path);
15227c478bd9Sstevel@tonic-gate di_devfs_path_free(path);
15237c478bd9Sstevel@tonic-gate }
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate static void
dump_minor_link_data(int ilev,di_node_t node,dev_t devt,di_devlink_handle_t devlink_hdl)15267c478bd9Sstevel@tonic-gate dump_minor_link_data(int ilev, di_node_t node, dev_t devt,
15277c478bd9Sstevel@tonic-gate di_devlink_handle_t devlink_hdl)
15287c478bd9Sstevel@tonic-gate {
15297c478bd9Sstevel@tonic-gate int first = 1;
15307c478bd9Sstevel@tonic-gate di_link_t link;
15317c478bd9Sstevel@tonic-gate
15327c478bd9Sstevel@tonic-gate link = DI_LINK_NIL;
15332545779bSRobert Mustacchi while ((link = di_link_next_by_node(node, link, DI_LINK_TGT)) !=
15342545779bSRobert Mustacchi DI_LINK_NIL) {
15357c478bd9Sstevel@tonic-gate di_lnode_t tgt_lnode;
15367c478bd9Sstevel@tonic-gate dev_t tgt_devt = DDI_DEV_T_NONE;
15377c478bd9Sstevel@tonic-gate
15387c478bd9Sstevel@tonic-gate tgt_lnode = di_link_to_lnode(link, DI_LINK_TGT);
15397c478bd9Sstevel@tonic-gate
15407c478bd9Sstevel@tonic-gate if (di_lnode_devt(tgt_lnode, &tgt_devt) != 0)
15417c478bd9Sstevel@tonic-gate continue;
15427c478bd9Sstevel@tonic-gate
15437c478bd9Sstevel@tonic-gate if (devt != tgt_devt)
15447c478bd9Sstevel@tonic-gate continue;
15457c478bd9Sstevel@tonic-gate
15467c478bd9Sstevel@tonic-gate if (first) {
15477c478bd9Sstevel@tonic-gate first = 0;
15487c478bd9Sstevel@tonic-gate indent_to_level(ilev);
15497c478bd9Sstevel@tonic-gate (void) printf("Device Minor Layered Under:\n");
15507c478bd9Sstevel@tonic-gate }
15517c478bd9Sstevel@tonic-gate
15527c478bd9Sstevel@tonic-gate /* displayed this lnode */
15537c478bd9Sstevel@tonic-gate lnode_displayed_set(tgt_lnode);
15547c478bd9Sstevel@tonic-gate link_lnode_disp(link, DI_LINK_SRC, ilev + 1, devlink_hdl);
15557c478bd9Sstevel@tonic-gate }
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate link = DI_LINK_NIL;
15582545779bSRobert Mustacchi while ((link = di_link_next_by_node(node, link, DI_LINK_SRC)) !=
15592545779bSRobert Mustacchi DI_LINK_NIL) {
15607c478bd9Sstevel@tonic-gate di_lnode_t src_lnode;
15617c478bd9Sstevel@tonic-gate dev_t src_devt = DDI_DEV_T_NONE;
15627c478bd9Sstevel@tonic-gate
15637c478bd9Sstevel@tonic-gate src_lnode = di_link_to_lnode(link, DI_LINK_SRC);
15647c478bd9Sstevel@tonic-gate
15657c478bd9Sstevel@tonic-gate if (di_lnode_devt(src_lnode, &src_devt) != 0)
15667c478bd9Sstevel@tonic-gate continue;
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate if (devt != src_devt)
15697c478bd9Sstevel@tonic-gate continue;
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate if (first) {
15727c478bd9Sstevel@tonic-gate first = 0;
15737c478bd9Sstevel@tonic-gate indent_to_level(ilev);
15747c478bd9Sstevel@tonic-gate (void) printf("Device Minor Layered Over:\n");
15757c478bd9Sstevel@tonic-gate }
15767c478bd9Sstevel@tonic-gate
15777c478bd9Sstevel@tonic-gate /* displayed this lnode */
15787c478bd9Sstevel@tonic-gate lnode_displayed_set(src_lnode);
15797c478bd9Sstevel@tonic-gate link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl);
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate
15837c478bd9Sstevel@tonic-gate static void
dump_minor_data(int ilev,di_node_t node,di_devlink_handle_t devlink_hdl)15847c478bd9Sstevel@tonic-gate dump_minor_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl)
15857c478bd9Sstevel@tonic-gate {
15867c478bd9Sstevel@tonic-gate di_minor_t minor, minor_next;
15877c478bd9Sstevel@tonic-gate di_lnode_t lnode;
15887c478bd9Sstevel@tonic-gate di_link_t link;
15897c478bd9Sstevel@tonic-gate int major, firstminor = 1;
15907c478bd9Sstevel@tonic-gate
15917c478bd9Sstevel@tonic-gate /*
15927c478bd9Sstevel@tonic-gate * first go through and mark all lnodes and minor nodes for this
15937c478bd9Sstevel@tonic-gate * node as undisplayed
15947c478bd9Sstevel@tonic-gate */
15957c478bd9Sstevel@tonic-gate lnode = DI_LNODE_NIL;
15962545779bSRobert Mustacchi while ((lnode = di_lnode_next(node, lnode)) != DI_LNODE_NIL)
15977c478bd9Sstevel@tonic-gate lnode_displayed_clear(lnode);
15987c478bd9Sstevel@tonic-gate minor = DI_MINOR_NIL;
15992545779bSRobert Mustacchi while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
16007c478bd9Sstevel@tonic-gate minor_displayed_clear(minor);
16017c478bd9Sstevel@tonic-gate }
16027c478bd9Sstevel@tonic-gate
16037c478bd9Sstevel@tonic-gate /*
16047c478bd9Sstevel@tonic-gate * when we display the minor nodes we want to coalesce nodes
16057c478bd9Sstevel@tonic-gate * that have the same dev_t. we do this by creating circular
16067c478bd9Sstevel@tonic-gate * lists of minor nodes with the same devt.
16077c478bd9Sstevel@tonic-gate */
16087c478bd9Sstevel@tonic-gate create_minor_list(node);
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate /* now we display the driver defined minor nodes */
16117c478bd9Sstevel@tonic-gate major = di_driver_major(node);
16127c478bd9Sstevel@tonic-gate minor = DI_MINOR_NIL;
16137c478bd9Sstevel@tonic-gate while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
16147c478bd9Sstevel@tonic-gate dev_t devt;
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate * skip /pseudo/clone@0 minor nodes.
16187c478bd9Sstevel@tonic-gate * these are only created for DLPIv2 network devices.
16197c478bd9Sstevel@tonic-gate * since these minor nodes are associated with a driver
16207c478bd9Sstevel@tonic-gate * and are only bound to a device instance after they
16217c478bd9Sstevel@tonic-gate * are opened and attached we don't print them out
16227c478bd9Sstevel@tonic-gate * here.
16237c478bd9Sstevel@tonic-gate */
16247c478bd9Sstevel@tonic-gate devt = di_minor_devt(minor);
16257c478bd9Sstevel@tonic-gate if (major != major(devt))
16267c478bd9Sstevel@tonic-gate continue;
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate /* skip nodes that may have already been displayed */
16297c478bd9Sstevel@tonic-gate if (minor_displayed(minor))
16307c478bd9Sstevel@tonic-gate continue;
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate if (firstminor) {
16337c478bd9Sstevel@tonic-gate firstminor = 0;
16347c478bd9Sstevel@tonic-gate indent_to_level(ilev++);
16357c478bd9Sstevel@tonic-gate (void) printf("Device Minor Nodes:\n");
16367c478bd9Sstevel@tonic-gate }
16377c478bd9Sstevel@tonic-gate
16387c478bd9Sstevel@tonic-gate /* display the device minor node information */
16397c478bd9Sstevel@tonic-gate indent_to_level(ilev);
16407c478bd9Sstevel@tonic-gate (void) printf("dev=(%u,%u)\n",
164158c0eeecScth (uint_t)major(devt), (uint_t)minor(devt));
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate minor_next = minor;
16447c478bd9Sstevel@tonic-gate do {
16457c478bd9Sstevel@tonic-gate /* display device minor node path info */
16467c478bd9Sstevel@tonic-gate minor_displayed_set(minor_next);
16477c478bd9Sstevel@tonic-gate dump_minor_data_paths(ilev + 1, minor_next,
164858c0eeecScth devlink_hdl);
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate /* get a pointer to the next node */
16517c478bd9Sstevel@tonic-gate minor_next = minor_ptr(minor_next);
16527c478bd9Sstevel@tonic-gate } while (minor_next != minor);
16537c478bd9Sstevel@tonic-gate
16547c478bd9Sstevel@tonic-gate /* display who has this device minor node open */
16557c478bd9Sstevel@tonic-gate dump_minor_link_data(ilev + 1, node, devt, devlink_hdl);
1656b9ccdc5aScth
1657b9ccdc5aScth /* display properties associated with this devt */
1658b9ccdc5aScth (void) dump_prop_list(&drvprop_dumpops, "Minor",
1659fa084259Scth ilev + 1, node, devt, NULL);
16607c478bd9Sstevel@tonic-gate }
16617c478bd9Sstevel@tonic-gate
16627c478bd9Sstevel@tonic-gate /*
16637c478bd9Sstevel@tonic-gate * now go through all the target lnodes for this node and
16647c478bd9Sstevel@tonic-gate * if they haven't yet been displayed, display them now.
16657c478bd9Sstevel@tonic-gate *
16667c478bd9Sstevel@tonic-gate * this happens in the case of clone opens when an "official"
16677c478bd9Sstevel@tonic-gate * minor node does not exist for the opened devt
16687c478bd9Sstevel@tonic-gate */
16697c478bd9Sstevel@tonic-gate link = DI_LINK_NIL;
16702545779bSRobert Mustacchi while ((link = di_link_next_by_node(node, link, DI_LINK_TGT)) !=
16712545779bSRobert Mustacchi DI_LINK_NIL) {
16727c478bd9Sstevel@tonic-gate dev_t devt;
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate lnode = di_link_to_lnode(link, DI_LINK_TGT);
16757c478bd9Sstevel@tonic-gate
16767c478bd9Sstevel@tonic-gate /* if we've already displayed this target lnode, skip it */
16777c478bd9Sstevel@tonic-gate if (lnode_displayed(lnode))
16787c478bd9Sstevel@tonic-gate continue;
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate if (firstminor) {
16817c478bd9Sstevel@tonic-gate firstminor = 0;
16827c478bd9Sstevel@tonic-gate indent_to_level(ilev++);
16837c478bd9Sstevel@tonic-gate (void) printf("Device Minor Nodes:\n");
16847c478bd9Sstevel@tonic-gate }
16857c478bd9Sstevel@tonic-gate
16867c478bd9Sstevel@tonic-gate /* display the device minor node information */
16877c478bd9Sstevel@tonic-gate indent_to_level(ilev);
16887c478bd9Sstevel@tonic-gate (void) di_lnode_devt(lnode, &devt);
16897c478bd9Sstevel@tonic-gate (void) printf("dev=(%u,%u)\n",
169058c0eeecScth (uint_t)major(devt), (uint_t)minor(devt));
16917c478bd9Sstevel@tonic-gate
16927c478bd9Sstevel@tonic-gate indent_to_level(ilev + 1);
16937c478bd9Sstevel@tonic-gate (void) printf("dev_path=<clone>\n");
16947c478bd9Sstevel@tonic-gate
16957c478bd9Sstevel@tonic-gate /* display who has this cloned device minor node open */
16967c478bd9Sstevel@tonic-gate dump_minor_link_data(ilev + 1, node, devt, devlink_hdl);
16977c478bd9Sstevel@tonic-gate
16987c478bd9Sstevel@tonic-gate /* mark node as displayed */
16997c478bd9Sstevel@tonic-gate lnode_displayed_set(lnode);
17007c478bd9Sstevel@tonic-gate }
17017c478bd9Sstevel@tonic-gate }
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate static void
dump_link_data(int ilev,di_node_t node,di_devlink_handle_t devlink_hdl)17047c478bd9Sstevel@tonic-gate dump_link_data(int ilev, di_node_t node, di_devlink_handle_t devlink_hdl)
17057c478bd9Sstevel@tonic-gate {
17067c478bd9Sstevel@tonic-gate int first = 1;
17077c478bd9Sstevel@tonic-gate di_link_t link;
17087c478bd9Sstevel@tonic-gate
17097c478bd9Sstevel@tonic-gate link = DI_LINK_NIL;
17102545779bSRobert Mustacchi while ((link = di_link_next_by_node(node, link, DI_LINK_SRC)) !=
17112545779bSRobert Mustacchi DI_LINK_NIL) {
17127c478bd9Sstevel@tonic-gate di_lnode_t src_lnode;
17137c478bd9Sstevel@tonic-gate dev_t src_devt = DDI_DEV_T_NONE;
17147c478bd9Sstevel@tonic-gate
17157c478bd9Sstevel@tonic-gate src_lnode = di_link_to_lnode(link, DI_LINK_SRC);
17167c478bd9Sstevel@tonic-gate
17177c478bd9Sstevel@tonic-gate /*
17187c478bd9Sstevel@tonic-gate * here we only want to print out layering information
17197c478bd9Sstevel@tonic-gate * if we are the source and our source lnode is not
17207c478bd9Sstevel@tonic-gate * associated with any particular dev_t. (which means
17217c478bd9Sstevel@tonic-gate * we won't display this link while dumping minor node
17227c478bd9Sstevel@tonic-gate * info.)
17237c478bd9Sstevel@tonic-gate */
17247c478bd9Sstevel@tonic-gate if (di_lnode_devt(src_lnode, &src_devt) != -1)
17257c478bd9Sstevel@tonic-gate continue;
17267c478bd9Sstevel@tonic-gate
17277c478bd9Sstevel@tonic-gate if (first) {
17287c478bd9Sstevel@tonic-gate first = 0;
17297c478bd9Sstevel@tonic-gate indent_to_level(ilev);
17307c478bd9Sstevel@tonic-gate (void) printf("Device Layered Over:\n");
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate
17337c478bd9Sstevel@tonic-gate /* displayed this lnode */
17347c478bd9Sstevel@tonic-gate link_lnode_disp(link, DI_LINK_TGT, ilev + 1, devlink_hdl);
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate }
17377c478bd9Sstevel@tonic-gate
17387c478bd9Sstevel@tonic-gate /*
17397c478bd9Sstevel@tonic-gate * certain 'known' property names may contain 'composite' strings.
17407c478bd9Sstevel@tonic-gate * Handle them here, and print them as 'string1' + 'string2' ...
17417c478bd9Sstevel@tonic-gate */
17427c478bd9Sstevel@tonic-gate static int
print_composite_string(const char * var,char * value,int size)17437c478bd9Sstevel@tonic-gate print_composite_string(const char *var, char *value, int size)
17447c478bd9Sstevel@tonic-gate {
17457c478bd9Sstevel@tonic-gate char *p, *q;
17467c478bd9Sstevel@tonic-gate char *firstp;
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate if ((strcmp(var, "version") != 0) &&
17497c478bd9Sstevel@tonic-gate (strcmp(var, "compatible") != 0))
17507c478bd9Sstevel@tonic-gate return (0); /* Not a known composite string */
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate /*
17537c478bd9Sstevel@tonic-gate * Verify that each string in the composite string is non-NULL,
17547c478bd9Sstevel@tonic-gate * is within the bounds of the property length, and contains
17557c478bd9Sstevel@tonic-gate * printable characters or white space. Otherwise let the
17567c478bd9Sstevel@tonic-gate * caller deal with it.
17577c478bd9Sstevel@tonic-gate */
17587c478bd9Sstevel@tonic-gate for (firstp = p = value; p < (value + size); p += strlen(p) + 1) {
17597c478bd9Sstevel@tonic-gate if (strlen(p) == 0)
17607c478bd9Sstevel@tonic-gate return (0); /* NULL string */
17617c478bd9Sstevel@tonic-gate for (q = p; *q; q++) {
17627c478bd9Sstevel@tonic-gate if (!(isascii(*q) && (isprint(*q) || isspace(*q))))
17637c478bd9Sstevel@tonic-gate return (0); /* Not printable or space */
17647c478bd9Sstevel@tonic-gate }
17657c478bd9Sstevel@tonic-gate if (q > (firstp + size))
17667c478bd9Sstevel@tonic-gate return (0); /* Out of bounds */
17677c478bd9Sstevel@tonic-gate }
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate for (firstp = p = value; p < (value + size); p += strlen(p) + 1) {
17707c478bd9Sstevel@tonic-gate if (p == firstp)
17717c478bd9Sstevel@tonic-gate (void) printf("'%s'", p);
17727c478bd9Sstevel@tonic-gate else
17737c478bd9Sstevel@tonic-gate (void) printf(" + '%s'", p);
17747c478bd9Sstevel@tonic-gate }
17757c478bd9Sstevel@tonic-gate (void) putchar('\n');
17767c478bd9Sstevel@tonic-gate return (1);
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate
17797c478bd9Sstevel@tonic-gate /*
17807c478bd9Sstevel@tonic-gate * Print one property and its value. Handle the verbose case.
17817c478bd9Sstevel@tonic-gate */
17827c478bd9Sstevel@tonic-gate static void
print_one(nvpair_t * nvp,int level)17837c478bd9Sstevel@tonic-gate print_one(nvpair_t *nvp, int level)
17847c478bd9Sstevel@tonic-gate {
17857c478bd9Sstevel@tonic-gate int i;
17867c478bd9Sstevel@tonic-gate int endswap = 0;
17877c478bd9Sstevel@tonic-gate uint_t valsize;
17887c478bd9Sstevel@tonic-gate char *value;
17897c478bd9Sstevel@tonic-gate char *var = nvpair_name(nvp);
17907c478bd9Sstevel@tonic-gate
17917c478bd9Sstevel@tonic-gate indent_to_level(level);
17927c478bd9Sstevel@tonic-gate (void) printf("%s: ", var);
17937c478bd9Sstevel@tonic-gate
17947c478bd9Sstevel@tonic-gate switch (nvpair_type(nvp)) {
17957c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
17967c478bd9Sstevel@tonic-gate (void) printf(" \n");
17977c478bd9Sstevel@tonic-gate return;
17987c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY:
17997c478bd9Sstevel@tonic-gate if (nvpair_value_byte_array(nvp, (uchar_t **)&value,
18007c478bd9Sstevel@tonic-gate &valsize)) {
18017c478bd9Sstevel@tonic-gate (void) printf("data not available.\n");
18027c478bd9Sstevel@tonic-gate return;
18037c478bd9Sstevel@tonic-gate }
18047c478bd9Sstevel@tonic-gate valsize--; /* take out null added by driver */
18057c478bd9Sstevel@tonic-gate
18067c478bd9Sstevel@tonic-gate /*
18077c478bd9Sstevel@tonic-gate * Do not print valsize > MAXVALSIZE, to be compatible
18087c478bd9Sstevel@tonic-gate * with old behavior. E.g. intel's eisa-nvram property
18097c478bd9Sstevel@tonic-gate * has a size of 65 K.
18107c478bd9Sstevel@tonic-gate */
18117c478bd9Sstevel@tonic-gate if (valsize > MAXVALSIZE) {
18127c478bd9Sstevel@tonic-gate (void) printf(" \n");
18137c478bd9Sstevel@tonic-gate return;
18147c478bd9Sstevel@tonic-gate }
18157c478bd9Sstevel@tonic-gate break;
18167c478bd9Sstevel@tonic-gate default:
18177c478bd9Sstevel@tonic-gate (void) printf("data type unexpected.\n");
18187c478bd9Sstevel@tonic-gate return;
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate
18217c478bd9Sstevel@tonic-gate /*
18227c478bd9Sstevel@tonic-gate * Handle printing verbosely
18237c478bd9Sstevel@tonic-gate */
18247c478bd9Sstevel@tonic-gate if (print_composite_string(var, value, valsize)) {
18257c478bd9Sstevel@tonic-gate return;
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate
18287c478bd9Sstevel@tonic-gate if (!unprintable(value, valsize)) {
18297c478bd9Sstevel@tonic-gate (void) printf(" '%s'\n", value);
18307c478bd9Sstevel@tonic-gate return;
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate (void) printf(" ");
18347c478bd9Sstevel@tonic-gate #ifdef __x86
18357c478bd9Sstevel@tonic-gate /*
18367c478bd9Sstevel@tonic-gate * Due to backwards compatibility constraints x86 int
18377c478bd9Sstevel@tonic-gate * properties are not in big-endian (ieee 1275) byte order.
18387c478bd9Sstevel@tonic-gate * If we have a property that is a multiple of 4 bytes,
18397c478bd9Sstevel@tonic-gate * let's assume it is an array of ints and print the bytes
18407c478bd9Sstevel@tonic-gate * in little endian order to make things look nicer for
18417c478bd9Sstevel@tonic-gate * the user.
18427c478bd9Sstevel@tonic-gate */
18437c478bd9Sstevel@tonic-gate endswap = (valsize % 4) == 0;
18447c478bd9Sstevel@tonic-gate #endif /* __x86 */
18457c478bd9Sstevel@tonic-gate for (i = 0; i < valsize; i++) {
18467c478bd9Sstevel@tonic-gate int out;
18477c478bd9Sstevel@tonic-gate if (i && (i % 4 == 0))
18487c478bd9Sstevel@tonic-gate (void) putchar('.');
18497c478bd9Sstevel@tonic-gate if (endswap)
18507c478bd9Sstevel@tonic-gate out = value[i + (3 - 2 * (i % 4))] & 0xff;
18517c478bd9Sstevel@tonic-gate else
18527c478bd9Sstevel@tonic-gate out = value[i] & 0xff;
18537c478bd9Sstevel@tonic-gate
18547c478bd9Sstevel@tonic-gate (void) printf("%02x", out);
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate (void) putchar('\n');
18577c478bd9Sstevel@tonic-gate }
18587c478bd9Sstevel@tonic-gate
18597c478bd9Sstevel@tonic-gate static int
unprintable(char * value,int size)18607c478bd9Sstevel@tonic-gate unprintable(char *value, int size)
18617c478bd9Sstevel@tonic-gate {
18627c478bd9Sstevel@tonic-gate int i;
18637c478bd9Sstevel@tonic-gate
18647c478bd9Sstevel@tonic-gate /*
18657c478bd9Sstevel@tonic-gate * Is this just a zero?
18667c478bd9Sstevel@tonic-gate */
18677c478bd9Sstevel@tonic-gate if (size == 0 || value[0] == '\0')
18687c478bd9Sstevel@tonic-gate return (1);
18697c478bd9Sstevel@tonic-gate /*
18707c478bd9Sstevel@tonic-gate * If any character is unprintable, or if a null appears
18717c478bd9Sstevel@tonic-gate * anywhere except at the end of a string, the whole
18727c478bd9Sstevel@tonic-gate * property is "unprintable".
18737c478bd9Sstevel@tonic-gate */
18747c478bd9Sstevel@tonic-gate for (i = 0; i < size; ++i) {
18757c478bd9Sstevel@tonic-gate if (value[i] == '\0')
18767c478bd9Sstevel@tonic-gate return (i != (size - 1));
18777c478bd9Sstevel@tonic-gate if (!isascii(value[i]) || iscntrl(value[i]))
18787c478bd9Sstevel@tonic-gate return (1);
18797c478bd9Sstevel@tonic-gate }
18807c478bd9Sstevel@tonic-gate return (0);
18817c478bd9Sstevel@tonic-gate }
18827c478bd9Sstevel@tonic-gate
18837c478bd9Sstevel@tonic-gate static int
promopen(int oflag)18847c478bd9Sstevel@tonic-gate promopen(int oflag)
18857c478bd9Sstevel@tonic-gate {
18867c478bd9Sstevel@tonic-gate for (;;) {
18877c478bd9Sstevel@tonic-gate if ((prom_fd = open(opts.o_promdev, oflag)) < 0) {
18887c478bd9Sstevel@tonic-gate if (errno == EAGAIN) {
18897c478bd9Sstevel@tonic-gate (void) sleep(5);
18907c478bd9Sstevel@tonic-gate continue;
18917c478bd9Sstevel@tonic-gate }
18927c478bd9Sstevel@tonic-gate if (errno == ENXIO)
18937c478bd9Sstevel@tonic-gate return (-1);
18947c478bd9Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) {
18952545779bSRobert Mustacchi err(-1, "cannot open %s", opts.o_promdev);
18967c478bd9Sstevel@tonic-gate }
18977c478bd9Sstevel@tonic-gate /* not an error if this isn't the global zone */
18982545779bSRobert Mustacchi warnx("openprom facility not available");
18997c478bd9Sstevel@tonic-gate exit(0);
19007c478bd9Sstevel@tonic-gate } else
19017c478bd9Sstevel@tonic-gate return (0);
19027c478bd9Sstevel@tonic-gate }
19037c478bd9Sstevel@tonic-gate }
19047c478bd9Sstevel@tonic-gate
19057c478bd9Sstevel@tonic-gate static void
promclose(void)19067c478bd9Sstevel@tonic-gate promclose(void)
19077c478bd9Sstevel@tonic-gate {
19087c478bd9Sstevel@tonic-gate if (close(prom_fd) < 0)
19092545779bSRobert Mustacchi err(-1, "close error on %s", opts.o_promdev);
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate
19127c478bd9Sstevel@tonic-gate /*
19137c478bd9Sstevel@tonic-gate * Get and print the name of the frame buffer device.
19147c478bd9Sstevel@tonic-gate */
19157c478bd9Sstevel@tonic-gate int
do_fbname(void)19167c478bd9Sstevel@tonic-gate do_fbname(void)
19177c478bd9Sstevel@tonic-gate {
19187c478bd9Sstevel@tonic-gate int retval;
19197c478bd9Sstevel@tonic-gate char fbuf_path[MAXPATHLEN];
19207c478bd9Sstevel@tonic-gate
19217c478bd9Sstevel@tonic-gate retval = modctl(MODGETFBNAME, (caddr_t)fbuf_path);
19227c478bd9Sstevel@tonic-gate
19237c478bd9Sstevel@tonic-gate if (retval == 0) {
19247c478bd9Sstevel@tonic-gate (void) printf("%s\n", fbuf_path);
19257c478bd9Sstevel@tonic-gate } else {
19267c478bd9Sstevel@tonic-gate if (retval == EFAULT) {
19277c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
19287c478bd9Sstevel@tonic-gate "Error copying fb path to userland\n");
19297c478bd9Sstevel@tonic-gate } else {
19307c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
19317c478bd9Sstevel@tonic-gate "Console output device is not a frame buffer\n");
19327c478bd9Sstevel@tonic-gate }
19337c478bd9Sstevel@tonic-gate return (1);
19347c478bd9Sstevel@tonic-gate }
19357c478bd9Sstevel@tonic-gate return (0);
19367c478bd9Sstevel@tonic-gate }
19377c478bd9Sstevel@tonic-gate
19387c478bd9Sstevel@tonic-gate /*
19397c478bd9Sstevel@tonic-gate * Get and print the PROM version.
19407c478bd9Sstevel@tonic-gate */
19417c478bd9Sstevel@tonic-gate int
do_promversion(void)19427c478bd9Sstevel@tonic-gate do_promversion(void)
19437c478bd9Sstevel@tonic-gate {
19447c478bd9Sstevel@tonic-gate Oppbuf oppbuf;
19457c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp);
19467c478bd9Sstevel@tonic-gate
19477c478bd9Sstevel@tonic-gate if (promopen(O_RDONLY)) {
19487c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Cannot open openprom device\n");
19497c478bd9Sstevel@tonic-gate return (1);
19507c478bd9Sstevel@tonic-gate }
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE;
19537c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETVERSION, opp) < 0)
19542545779bSRobert Mustacchi err(-1, "OPROMGETVERSION");
19557c478bd9Sstevel@tonic-gate
19567c478bd9Sstevel@tonic-gate (void) printf("%s\n", opp->oprom_array);
19577c478bd9Sstevel@tonic-gate promclose();
19587c478bd9Sstevel@tonic-gate return (0);
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate
19617c478bd9Sstevel@tonic-gate int
do_productinfo(void)19627c478bd9Sstevel@tonic-gate do_productinfo(void)
19637c478bd9Sstevel@tonic-gate {
19647c478bd9Sstevel@tonic-gate di_node_t root, next_node;
19657c478bd9Sstevel@tonic-gate di_prom_handle_t promh;
19667c478bd9Sstevel@tonic-gate static const char *root_prop[] = { "name", "model", "banner-name",
19677c478bd9Sstevel@tonic-gate "compatible" };
19687c478bd9Sstevel@tonic-gate static const char *root_propv[] = { "name", "model", "banner-name",
19697c478bd9Sstevel@tonic-gate "compatible", "idprom" };
19707c478bd9Sstevel@tonic-gate static const char *oprom_prop[] = { "model", "version" };
19717c478bd9Sstevel@tonic-gate
19727c478bd9Sstevel@tonic-gate
19737c478bd9Sstevel@tonic-gate root = di_init("/", DINFOCPYALL);
19747c478bd9Sstevel@tonic-gate
19757c478bd9Sstevel@tonic-gate if (root == DI_NODE_NIL) {
19767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_init() failed\n");
19777c478bd9Sstevel@tonic-gate return (1);
19787c478bd9Sstevel@tonic-gate }
19797c478bd9Sstevel@tonic-gate
19807c478bd9Sstevel@tonic-gate promh = di_prom_init();
19817c478bd9Sstevel@tonic-gate
19827c478bd9Sstevel@tonic-gate if (promh == DI_PROM_HANDLE_NIL) {
19837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_prom_init() failed\n");
19847c478bd9Sstevel@tonic-gate return (1);
19857c478bd9Sstevel@tonic-gate }
19867c478bd9Sstevel@tonic-gate
19877c478bd9Sstevel@tonic-gate if (opts.o_verbose) {
19887c478bd9Sstevel@tonic-gate dump_prodinfo(promh, root, root_propv, "root",
198958c0eeecScth NUM_ELEMENTS(root_propv));
19907c478bd9Sstevel@tonic-gate
19917c478bd9Sstevel@tonic-gate /* Get model and version properties under node "openprom" */
19927c478bd9Sstevel@tonic-gate next_node = find_node_by_name(promh, root, "openprom");
19937c478bd9Sstevel@tonic-gate if (next_node != DI_NODE_NIL)
19947c478bd9Sstevel@tonic-gate dump_prodinfo(promh, next_node, oprom_prop,
199558c0eeecScth "openprom", NUM_ELEMENTS(oprom_prop));
19967c478bd9Sstevel@tonic-gate
19977c478bd9Sstevel@tonic-gate } else
19987c478bd9Sstevel@tonic-gate dump_prodinfo(promh, root, root_prop, "root",
199958c0eeecScth NUM_ELEMENTS(root_prop));
20007c478bd9Sstevel@tonic-gate di_prom_fini(promh);
20017c478bd9Sstevel@tonic-gate di_fini(root);
20027c478bd9Sstevel@tonic-gate return (0);
20037c478bd9Sstevel@tonic-gate }
20047c478bd9Sstevel@tonic-gate
20057c478bd9Sstevel@tonic-gate di_node_t
find_node_by_name(di_prom_handle_t promh,di_node_t parent,char * node_name)20067c478bd9Sstevel@tonic-gate find_node_by_name(di_prom_handle_t promh, di_node_t parent,
200749ca4dd9SPeter Tribble char *node_name)
20087c478bd9Sstevel@tonic-gate {
20097c478bd9Sstevel@tonic-gate di_node_t next_node;
20107c478bd9Sstevel@tonic-gate uchar_t *prop_valp;
20117c478bd9Sstevel@tonic-gate
2012e7f0155eSvb for (next_node = di_child_node(parent); next_node != DI_NODE_NIL;
2013e7f0155eSvb next_node = di_sibling_node(next_node)) {
2014e7f0155eSvb int len;
2015e7f0155eSvb
2016e7f0155eSvb len = get_propval_by_name(promh, next_node, "name", &prop_valp);
2017e7f0155eSvb if ((len != -1) && (strcmp((char *)prop_valp, node_name) == 0))
20187c478bd9Sstevel@tonic-gate return (next_node);
20197c478bd9Sstevel@tonic-gate }
20207c478bd9Sstevel@tonic-gate return (DI_NODE_NIL);
20217c478bd9Sstevel@tonic-gate }
20227c478bd9Sstevel@tonic-gate
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate int
get_propval_by_name(di_prom_handle_t promh,di_node_t node,const char * name,uchar_t ** valp)20257c478bd9Sstevel@tonic-gate get_propval_by_name(di_prom_handle_t promh, di_node_t node, const char *name,
202649ca4dd9SPeter Tribble uchar_t **valp)
20277c478bd9Sstevel@tonic-gate {
20287c478bd9Sstevel@tonic-gate int len;
20297c478bd9Sstevel@tonic-gate uchar_t *bufp;
20307c478bd9Sstevel@tonic-gate
20317c478bd9Sstevel@tonic-gate len = di_prom_prop_lookup_bytes(promh, node, name,
203258c0eeecScth (uchar_t **)&bufp);
20337c478bd9Sstevel@tonic-gate if (len != -1) {
20347c478bd9Sstevel@tonic-gate *valp = (uchar_t *)malloc(len);
20357c478bd9Sstevel@tonic-gate (void) memcpy(*valp, bufp, len);
20367c478bd9Sstevel@tonic-gate }
20377c478bd9Sstevel@tonic-gate return (len);
20387c478bd9Sstevel@tonic-gate }
20397c478bd9Sstevel@tonic-gate
20407c478bd9Sstevel@tonic-gate
20417c478bd9Sstevel@tonic-gate static void
dump_prodinfo(di_prom_handle_t promh,di_node_t node,const char ** propstr,char * node_name,int num)20427c478bd9Sstevel@tonic-gate dump_prodinfo(di_prom_handle_t promh, di_node_t node, const char **propstr,
204349ca4dd9SPeter Tribble char *node_name, int num)
20447c478bd9Sstevel@tonic-gate {
20457c478bd9Sstevel@tonic-gate int out, len, index1, index, endswap = 0;
20467c478bd9Sstevel@tonic-gate uchar_t *prop_valp;
20477c478bd9Sstevel@tonic-gate
20487c478bd9Sstevel@tonic-gate for (index1 = 0; index1 < num; index1++) {
20497c478bd9Sstevel@tonic-gate len = get_propval_by_name(promh, node, propstr[index1],
205058c0eeecScth &prop_valp);
20517c478bd9Sstevel@tonic-gate if (len != -1) {
20527c478bd9Sstevel@tonic-gate if (strcmp(node_name, "root"))
20537c478bd9Sstevel@tonic-gate (void) printf("%s ", node_name);
20547c478bd9Sstevel@tonic-gate
20557c478bd9Sstevel@tonic-gate (void) printf("%s: ", propstr[index1]);
20567c478bd9Sstevel@tonic-gate
20577c478bd9Sstevel@tonic-gate if (print_composite_string((const char *)
205858c0eeecScth propstr[index1], (char *)prop_valp, len)) {
20597c478bd9Sstevel@tonic-gate free(prop_valp);
20607c478bd9Sstevel@tonic-gate continue;
20617c478bd9Sstevel@tonic-gate }
20627c478bd9Sstevel@tonic-gate
20637c478bd9Sstevel@tonic-gate if (!unprintable((char *)prop_valp, len)) {
20647c478bd9Sstevel@tonic-gate (void) printf(" %s\n", (char *)prop_valp);
20657c478bd9Sstevel@tonic-gate free(prop_valp);
20667c478bd9Sstevel@tonic-gate continue;
20677c478bd9Sstevel@tonic-gate }
20687c478bd9Sstevel@tonic-gate
20697c478bd9Sstevel@tonic-gate (void) printf(" ");
20707c478bd9Sstevel@tonic-gate #ifdef __x86
20717c478bd9Sstevel@tonic-gate endswap = (len % 4) == 0;
20727c478bd9Sstevel@tonic-gate #endif /* __x86 */
20737c478bd9Sstevel@tonic-gate for (index = 0; index < len; index++) {
20747c478bd9Sstevel@tonic-gate if (index && (index % 4 == 0))
20757c478bd9Sstevel@tonic-gate (void) putchar('.');
20767c478bd9Sstevel@tonic-gate if (endswap)
20777c478bd9Sstevel@tonic-gate out = prop_valp[index +
207858c0eeecScth (3 - 2 * (index % 4))] & 0xff;
20797c478bd9Sstevel@tonic-gate else
20807c478bd9Sstevel@tonic-gate out = prop_valp[index] & 0xff;
20817c478bd9Sstevel@tonic-gate (void) printf("%02x", out);
20827c478bd9Sstevel@tonic-gate }
20837c478bd9Sstevel@tonic-gate (void) putchar('\n');
20847c478bd9Sstevel@tonic-gate free(prop_valp);
20857c478bd9Sstevel@tonic-gate }
20867c478bd9Sstevel@tonic-gate }
20877c478bd9Sstevel@tonic-gate }
2088fa084259Scth
2089fa084259Scth static int
dump_compatible(char * name,int ilev,di_node_t node)2090fa084259Scth dump_compatible(char *name, int ilev, di_node_t node)
2091fa084259Scth {
2092fa084259Scth int ncompat;
2093fa084259Scth char *compat_array;
2094fa084259Scth char *p, *q;
2095fa084259Scth int i;
2096fa084259Scth
2097fa084259Scth if (node == DI_PATH_NIL)
2098fa084259Scth return (0);
2099fa084259Scth
2100fa084259Scth ncompat = di_compatible_names(node, &compat_array);
2101fa084259Scth if (ncompat <= 0)
2102fa084259Scth return (0); /* no 'compatible' available */
2103fa084259Scth
2104fa084259Scth /* verify integrety of compat_array */
2105fa084259Scth for (i = 0, p = compat_array; i < ncompat; i++, p += strlen(p) + 1) {
2106fa084259Scth if (strlen(p) == 0)
2107fa084259Scth return (0); /* NULL string */
2108fa084259Scth for (q = p; *q; q++) {
2109fa084259Scth if (!(isascii(*q) && (isprint(*q) || isspace(*q))))
2110fa084259Scth return (0); /* Not printable or space */
2111fa084259Scth }
2112fa084259Scth }
2113fa084259Scth
2114fa084259Scth /* If name is non-NULL, produce header */
2115fa084259Scth if (name) {
2116fa084259Scth indent_to_level(ilev);
2117fa084259Scth (void) printf("%s properties:\n", name);
2118fa084259Scth }
2119fa084259Scth ilev++;
2120fa084259Scth
2121fa084259Scth /* process like a string array property */
2122fa084259Scth indent_to_level(ilev);
2123fa084259Scth (void) printf("name='compatible' type=string items=%d\n", ncompat);
2124fa084259Scth indent_to_level(ilev);
2125fa084259Scth (void) printf(" value=");
2126fa084259Scth for (i = 0, p = compat_array; i < (ncompat - 1);
2127fa084259Scth i++, p += strlen(p) + 1)
2128fa084259Scth (void) printf("'%s' + ", p);
2129fa084259Scth (void) printf("'%s'", p);
2130fa084259Scth (void) putchar('\n');
2131fa084259Scth return (1);
2132fa084259Scth }
2133abc79d9dSRobert Mustacchi
2134*1c7f36ecSRobert Mustacchi static void
dump_pciid(char * name,int ilev,di_node_t node)2135*1c7f36ecSRobert Mustacchi dump_pciid(char *name, int ilev, di_node_t node)
2136abc79d9dSRobert Mustacchi {
2137abc79d9dSRobert Mustacchi int *vid, *did, *svid, *sdid;
2138abc79d9dSRobert Mustacchi const char *vname, *dname, *sname;
2139abc79d9dSRobert Mustacchi pcidb_vendor_t *pciv;
2140abc79d9dSRobert Mustacchi pcidb_device_t *pcid;
2141abc79d9dSRobert Mustacchi pcidb_subvd_t *pcis;
2142abc79d9dSRobert Mustacchi
2143abc79d9dSRobert Mustacchi const char *unov = "unknown vendor";
2144abc79d9dSRobert Mustacchi const char *unod = "unknown device";
2145abc79d9dSRobert Mustacchi const char *unos = "unknown subsystem";
2146abc79d9dSRobert Mustacchi
2147*1c7f36ecSRobert Mustacchi if (opts.o_pcidb == NULL)
2148*1c7f36ecSRobert Mustacchi return;
2149abc79d9dSRobert Mustacchi
2150abc79d9dSRobert Mustacchi vname = unov;
2151abc79d9dSRobert Mustacchi dname = unod;
2152abc79d9dSRobert Mustacchi sname = unos;
2153abc79d9dSRobert Mustacchi
2154*1c7f36ecSRobert Mustacchi if (devinfo_is_pci(node) == NULL) {
2155*1c7f36ecSRobert Mustacchi return;
2156*1c7f36ecSRobert Mustacchi }
2157abc79d9dSRobert Mustacchi
2158abc79d9dSRobert Mustacchi /*
2159abc79d9dSRobert Mustacchi * All devices should have a vendor and device id, if we fail to find
2160abc79d9dSRobert Mustacchi * one, then we're going to return right here and not print anything.
2161abc79d9dSRobert Mustacchi *
2162abc79d9dSRobert Mustacchi * We're going to also check for the subsystem-vendor-id and
2163abc79d9dSRobert Mustacchi * subsystem-id. If we don't find one of them, we're going to assume
2164abc79d9dSRobert Mustacchi * that this device does not have one. In that case, we will never
2165abc79d9dSRobert Mustacchi * attempt to try and print anything related to that. If it does have
2166abc79d9dSRobert Mustacchi * both, then we are going to look them up and print the appropriate
2167abc79d9dSRobert Mustacchi * string if we find it or not.
2168abc79d9dSRobert Mustacchi */
2169abc79d9dSRobert Mustacchi if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id", &vid) <= 0)
2170*1c7f36ecSRobert Mustacchi return;
2171abc79d9dSRobert Mustacchi
2172abc79d9dSRobert Mustacchi if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id", &did) <= 0)
2173*1c7f36ecSRobert Mustacchi return;
2174abc79d9dSRobert Mustacchi
2175abc79d9dSRobert Mustacchi if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "subsystem-vendor-id",
2176abc79d9dSRobert Mustacchi &svid) <= 0 || di_prop_lookup_ints(DDI_DEV_T_ANY, node,
2177abc79d9dSRobert Mustacchi "subsystem-id", &sdid) <= 0) {
2178abc79d9dSRobert Mustacchi svid = NULL;
2179abc79d9dSRobert Mustacchi sdid = NULL;
2180abc79d9dSRobert Mustacchi sname = NULL;
2181abc79d9dSRobert Mustacchi }
2182abc79d9dSRobert Mustacchi
2183*1c7f36ecSRobert Mustacchi pciv = pcidb_lookup_vendor(opts.o_pcidb, vid[0]);
2184abc79d9dSRobert Mustacchi if (pciv == NULL)
2185abc79d9dSRobert Mustacchi goto print;
2186abc79d9dSRobert Mustacchi vname = pcidb_vendor_name(pciv);
2187abc79d9dSRobert Mustacchi
2188abc79d9dSRobert Mustacchi pcid = pcidb_lookup_device_by_vendor(pciv, did[0]);
2189abc79d9dSRobert Mustacchi if (pcid == NULL)
2190abc79d9dSRobert Mustacchi goto print;
2191abc79d9dSRobert Mustacchi dname = pcidb_device_name(pcid);
2192abc79d9dSRobert Mustacchi
2193abc79d9dSRobert Mustacchi if (svid != NULL) {
2194abc79d9dSRobert Mustacchi pcis = pcidb_lookup_subvd_by_device(pcid, svid[0], sdid[0]);
2195abc79d9dSRobert Mustacchi if (pcis == NULL)
2196abc79d9dSRobert Mustacchi goto print;
2197abc79d9dSRobert Mustacchi sname = pcidb_subvd_name(pcis);
2198abc79d9dSRobert Mustacchi }
2199abc79d9dSRobert Mustacchi
2200abc79d9dSRobert Mustacchi print:
2201abc79d9dSRobert Mustacchi /* If name is non-NULL, produce header */
2202abc79d9dSRobert Mustacchi if (name) {
2203abc79d9dSRobert Mustacchi indent_to_level(ilev);
2204abc79d9dSRobert Mustacchi (void) printf("%s properties:\n", name);
2205abc79d9dSRobert Mustacchi }
2206abc79d9dSRobert Mustacchi ilev++;
2207abc79d9dSRobert Mustacchi
2208abc79d9dSRobert Mustacchi /* These are all going to be single string properties */
2209abc79d9dSRobert Mustacchi indent_to_level(ilev);
2210abc79d9dSRobert Mustacchi (void) printf("name='vendor-name' type=string items=1\n");
2211abc79d9dSRobert Mustacchi indent_to_level(ilev);
2212abc79d9dSRobert Mustacchi (void) printf(" value='%s'\n", vname);
2213abc79d9dSRobert Mustacchi
2214abc79d9dSRobert Mustacchi indent_to_level(ilev);
2215abc79d9dSRobert Mustacchi (void) printf("name='device-name' type=string items=1\n");
2216abc79d9dSRobert Mustacchi indent_to_level(ilev);
2217abc79d9dSRobert Mustacchi (void) printf(" value='%s'\n", dname);
2218abc79d9dSRobert Mustacchi
2219abc79d9dSRobert Mustacchi if (sname != NULL) {
2220abc79d9dSRobert Mustacchi indent_to_level(ilev);
2221abc79d9dSRobert Mustacchi (void) printf("name='subsystem-name' type=string items=1\n");
2222abc79d9dSRobert Mustacchi indent_to_level(ilev);
2223abc79d9dSRobert Mustacchi (void) printf(" value='%s'\n", sname);
2224abc79d9dSRobert Mustacchi }
2225abc79d9dSRobert Mustacchi }
2226