13323Scindi /*
23323Scindi * CDDL HEADER START
33323Scindi *
43323Scindi * The contents of this file are subject to the terms of the
53323Scindi * Common Development and Distribution License (the "License").
63323Scindi * You may not use this file except in compliance with the License.
73323Scindi *
83323Scindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93323Scindi * or http://www.opensolaris.org/os/licensing.
103323Scindi * See the License for the specific language governing permissions
113323Scindi * and limitations under the License.
123323Scindi *
133323Scindi * When distributing Covered Code, include this CDDL HEADER in each
143323Scindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153323Scindi * If applicable, add the following below this CDDL HEADER, with the
163323Scindi * fields enclosed by brackets "[]" replaced with your own identifying
173323Scindi * information: Portions Copyright [yyyy] [name of copyright owner]
183323Scindi *
193323Scindi * CDDL HEADER END
203323Scindi */
213323Scindi
223323Scindi /*
23*6070Srobj * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
243323Scindi * Use is subject to license terms.
253323Scindi */
263323Scindi #pragma ident "%Z%%M% %I% %E% SMI"
273323Scindi
283323Scindi #include <sys/mdb_modapi.h>
293323Scindi #include <libelf.h>
303323Scindi #include <sys/fm/protocol.h>
313323Scindi #include <topo_mod.h>
323323Scindi #include <topo_tree.h>
333323Scindi #include <topo_module.h>
344198Seschrock #include <stddef.h>
353323Scindi
363323Scindi
373323Scindi /*
383323Scindi * We use this to keep track of which bucket we're in while walking
393323Scindi * the modhash and we also cache the length of the hash
403323Scindi */
413323Scindi static topo_modhash_t tmh;
423323Scindi static uint_t hash_idx;
433323Scindi
443323Scindi static uintptr_t curr_pg;
453323Scindi static uint_t is_root;
463323Scindi static uint_t verbose;
473323Scindi static char *pgrp;
483323Scindi static char *tgt_scheme;
493323Scindi static char parent[255];
503323Scindi
513323Scindi /*
523323Scindi * This structure is used by the topo_nodehash walker instances to
533323Scindi * keep track of where they're at in the node hash
543323Scindi */
553323Scindi typedef struct tnwalk_state {
563323Scindi uint_t hash_idx;
573323Scindi topo_nodehash_t hash;
583323Scindi topo_nodehash_t *curr_hash;
593323Scindi } tnwalk_state_t;
603323Scindi
613323Scindi
623323Scindi static char *stab_lvls[] = {"Internal", "", "Private", "Obsolete", "External",
633323Scindi "Unstable", "Evolving", "Stable", "Standard", "Max"};
643323Scindi
653323Scindi /*ARGSUSED*/
663323Scindi static int
topo_handle(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)673323Scindi topo_handle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
683323Scindi {
693323Scindi char uuid[36], root[36], plat[36], isa[36], machine[36], product[36];
703323Scindi topo_hdl_t th;
713323Scindi
723323Scindi /*
733323Scindi * Read in the structure and then read in all of the string fields from
743323Scindi * the target's addr space
753323Scindi */
763323Scindi if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) {
773323Scindi mdb_warn("failed to read topo_hdl_t at %p", addr);
783323Scindi return (DCMD_ERR);
793323Scindi }
803323Scindi
813323Scindi if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)th.th_uuid) < 0) {
823323Scindi (void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", th.th_uuid);
833323Scindi }
843323Scindi if (mdb_readstr(root, sizeof (root), (uintptr_t)th.th_rootdir) < 0) {
853323Scindi (void) mdb_snprintf(root, sizeof (root), "<%p>", th.th_rootdir);
863323Scindi }
873323Scindi if (mdb_readstr(plat, sizeof (plat), (uintptr_t)th.th_platform) < 0) {
883323Scindi (void) mdb_snprintf(plat, sizeof (plat), "<%p>",
893323Scindi th.th_platform);
903323Scindi }
913323Scindi if (mdb_readstr(isa, sizeof (isa), (uintptr_t)th.th_isa) < 0) {
923323Scindi (void) mdb_snprintf(isa, sizeof (isa), "<%p>", th.th_isa);
933323Scindi }
943323Scindi if (mdb_readstr(machine, sizeof (machine), (uintptr_t)th.th_machine)
953323Scindi < 0) {
963323Scindi
973323Scindi (void) mdb_snprintf(machine, sizeof (machine), "<%p>",
983323Scindi th.th_machine);
993323Scindi }
1003323Scindi if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product)
1013323Scindi < 0) {
1023323Scindi
1033323Scindi (void) mdb_snprintf(product, sizeof (product), "<%p>",
1043323Scindi th.th_product);
1053323Scindi }
1063323Scindi
1073323Scindi /*
1083323Scindi * Dump it all out in a nice pretty format and keep it to 80 chars wide
1093323Scindi */
1103323Scindi if (DCMD_HDRSPEC(flags)) {
1113323Scindi mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", "FIELD", "VALUE",
1123323Scindi "DESCR");
1133323Scindi }
1145068Srobj mdb_printf("%-12s 0x%-34p %-30s\n", "th_lock",
1155068Srobj addr + offsetof(topo_hdl_t, th_lock),
1163323Scindi "Mutex lock protecting handle");
1173323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_uuid", uuid,
1183323Scindi "UUID of the topology snapshot");
1193323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_rootdir", root,
1203323Scindi "Root directory of plugin paths");
1213323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_platform", plat, "Platform name");
1223323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_isa", isa, "ISA name");
1233323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_machine", machine,
1243323Scindi "Machine name");
1253323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_product", product,
1263323Scindi "Product name");
1273323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_di", th.th_di,
1283323Scindi "Handle to the root of the devinfo tree");
1293323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_pi", th.th_pi,
1303323Scindi "Handle to the root of the PROM tree");
1313323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_modhash", th.th_modhash,
1323323Scindi "Module hash");
1333323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_trees", "",
1343323Scindi "Scheme-specific topo tree list");
1353323Scindi mdb_printf(" %-12s 0x%-34p %-30s\n", "l_prev", th.th_trees.l_prev,
1364198Seschrock "");
1373323Scindi mdb_printf(" %-12s 0x%-34p %-30s\n", "l_next", th.th_trees.l_next,
1384198Seschrock "");
1393323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_alloc", th.th_alloc,
1403323Scindi "Allocators");
1413323Scindi mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", th.th_errno, "errno");
1423323Scindi mdb_printf("%-12s %-36d %-30s\n", "tm_debug", th.th_debug,
1433323Scindi "Debug mask");
1443323Scindi mdb_printf("%-12s %-36d %-30s\n", "tm_dbout", th.th_dbout,
1453323Scindi "Debug channel");
1463323Scindi
1473323Scindi return (DCMD_OK);
1483323Scindi }
1493323Scindi
1503323Scindi
1513323Scindi /*ARGSUSED*/
1523323Scindi static int
topo_module(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1533323Scindi topo_module(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1543323Scindi {
1553323Scindi char name[36], path[36], root[36];
1563323Scindi topo_mod_t tm;
1573323Scindi
1583323Scindi /*
1593323Scindi * Read in the structure and then read in all of the string fields from
1603323Scindi * the target's addr space
1613323Scindi */
1623323Scindi if (mdb_vread(&tm, sizeof (tm), addr) != sizeof (tm)) {
1633323Scindi mdb_warn("failed to read topo_mod_t at %p", addr);
1643323Scindi return (DCMD_ERR);
1653323Scindi }
1663323Scindi
1673323Scindi if (mdb_readstr(name, sizeof (name), (uintptr_t)tm.tm_name) < 0) {
1683323Scindi (void) mdb_snprintf(name, sizeof (name), "<%p>", tm.tm_name);
1693323Scindi }
1703323Scindi if (mdb_readstr(path, sizeof (path), (uintptr_t)tm.tm_path) < 0) {
1713323Scindi (void) mdb_snprintf(path, sizeof (path), "<%p>", tm.tm_path);
1723323Scindi }
1733323Scindi if (mdb_readstr(root, sizeof (root), (uintptr_t)tm.tm_rootdir) < 0) {
1743323Scindi (void) mdb_snprintf(root, sizeof (root), "<%p>", tm.tm_rootdir);
1753323Scindi }
1763323Scindi
1773323Scindi /*
1783323Scindi * Dump it all out in a nice pretty format and keep it to 80 chars wide
1793323Scindi */
1803323Scindi if (DCMD_HDRSPEC(flags)) {
1813323Scindi mdb_printf("%<u>%-12s %-36s %-30s%</u>\n",
1824198Seschrock "FIELD", "VALUE", "DESCR");
1833323Scindi }
1845068Srobj mdb_printf("%-12s 0x%-34p %-30s\n", "tm_lock",
1855068Srobj addr + offsetof(topo_mod_t, tm_lock),
1864198Seschrock "Lock for tm_cv/owner/flags/refs");
1875068Srobj mdb_printf("%-12s 0x%-34p %-30s\n", "tm_cv",
1885068Srobj addr + offsetof(topo_mod_t, tm_cv),
1894198Seschrock "Module condition variable");
190*6070Srobj if (tm.tm_busy)
191*6070Srobj mdb_printf("%-12s %-36s %-30s\n", "tm_busy", "TRUE",
192*6070Srobj "Busy indicator");
193*6070Srobj else
194*6070Srobj mdb_printf("%-12s %-36s %-30s\n", "tm_busy", "FALSE",
195*6070Srobj "Busy indicator");
196*6070Srobj
1973323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_next", tm.tm_next,
1984198Seschrock "Next module in hash chain");
1993323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_hdl", tm.tm_hdl,
2004198Seschrock "Topo handle for this module");
2013323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_alloc", tm.tm_alloc,
2024198Seschrock "Allocators");
2033323Scindi mdb_printf("%-12s %-36s %-30s\n", "tm_name", name,
2044198Seschrock "Basename of module");
2053323Scindi mdb_printf("%-12s %-36s %-30s\n", "tm_path", path,
2064198Seschrock "Full pathname of module");
2073323Scindi mdb_printf("%-12s %-36s %-30s\n", "tm_rootdir", root,
2084198Seschrock "Relative root directory of module");
2093323Scindi mdb_printf("%-12s %-36u %-30s\n", "tm_refs", tm.tm_refs,
2104198Seschrock "Module reference count");
2113323Scindi mdb_printf("%-12s %-36u %-30s\n", "tm_flags", tm.tm_flags,
2124198Seschrock "Module flags");
2133323Scindi if (TOPO_MOD_INIT & tm.tm_flags) {
2143323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_INIT",
2154198Seschrock "Module init completed");
2163323Scindi }
2173323Scindi if (TOPO_MOD_FINI & tm.tm_flags) {
2183323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_FINI",
2194198Seschrock "Module fini completed");
2203323Scindi }
2213323Scindi if (TOPO_MOD_REG & tm.tm_flags) {
2223323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_REG",
2234198Seschrock "Module registered");
2243323Scindi }
2253323Scindi if (TOPO_MOD_UNREG & tm.tm_flags) {
2263323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_UNREG",
2274198Seschrock "Module unregistered");
2283323Scindi }
2293323Scindi
2303323Scindi mdb_printf("%-12s %-36u %-30s\n", "tm_debug", tm.tm_debug,
2314198Seschrock "Debug printf mask");
2323323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_data", tm.tm_data,
2334198Seschrock "Private rtld/builtin data");
2343323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_mops", tm.tm_mops,
2354198Seschrock "Module class ops vector");
2363323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_info", tm.tm_info,
2374198Seschrock "Module info registered with handle");
2383323Scindi mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", tm.tm_errno,
2394198Seschrock "Module errno");
2403323Scindi
2413323Scindi return (DCMD_OK);
2423323Scindi }
2433323Scindi
2443323Scindi
2453323Scindi /*ARGSUSED*/
2463323Scindi static int
topo_node(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2473323Scindi topo_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2483323Scindi {
2493323Scindi char name[36];
2503323Scindi tnode_t tn;
2513323Scindi
2523323Scindi if (!addr)
2533323Scindi return (DCMD_ERR);
2543323Scindi
2553323Scindi /*
2563323Scindi * Read in the structure and then read in all of the string fields from
2573323Scindi * the target's addr space
2583323Scindi */
2593323Scindi if (mdb_vread(&tn, sizeof (tn), addr) != sizeof (tn)) {
2603323Scindi mdb_warn("failed to read tnode_t at %p", addr);
2613323Scindi return (DCMD_ERR);
2623323Scindi }
2633323Scindi
2643323Scindi if (mdb_readstr(name, sizeof (name), (uintptr_t)tn.tn_name) < 0) {
2653323Scindi (void) mdb_snprintf(name, sizeof (name), "<%p>", tn.tn_name);
2663323Scindi }
2673323Scindi
2683323Scindi /*
2693323Scindi * Dump it all out in a nice pretty format and keep it to 80 chars wide
2703323Scindi */
2713323Scindi if (DCMD_HDRSPEC(flags)) {
2723323Scindi mdb_printf("%<u>%-12s %-36s %-30s%</u>\n",
2733323Scindi "FIELD", "VALUE", "DESCR");
2743323Scindi }
2753323Scindi
2764198Seschrock mdb_printf("%-12s 0x%-34p %-30s\n", "tn_lock",
2774198Seschrock addr + offsetof(tnode_t, tn_lock),
2784198Seschrock "Lock protecting node members");
2793323Scindi mdb_printf("%-12s %-36s %-30s\n", "tn_name", name,
2804198Seschrock "Node name");
2813323Scindi mdb_printf("%-12s %-36d %-30s\n", "tn_instance", tn.tn_instance,
2824198Seschrock "Node instance");
2833323Scindi mdb_printf("%-12s %-36d %-30s\n", "tn_state", tn.tn_state,
2844198Seschrock "Node state");
2853323Scindi if (TOPO_NODE_INIT & tn.tn_state) {
2863323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_INIT", "");
2873323Scindi }
2883323Scindi if (TOPO_NODE_ROOT & tn.tn_state) {
2893323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_ROOT", "");
2903323Scindi }
2913323Scindi if (TOPO_NODE_BOUND & tn.tn_state) {
2923323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_BOUND", "");
2933323Scindi }
2943323Scindi if (TOPO_NODE_LINKED & tn.tn_state) {
2953323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_LINKED", "");
2963323Scindi }
2973323Scindi mdb_printf("%-12s %-36d %-30s\n", "tn_fflags", tn.tn_fflags,
2984198Seschrock "FMRI flags");
2993323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_parent", tn.tn_parent,
3004198Seschrock "Node parent");
3013323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_phash", tn.tn_phash,
3024198Seschrock "Parent hash bucket");
3033323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_hdl", tn.tn_hdl,
3044198Seschrock "Topo handle");
3053323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_enum", tn.tn_enum,
3064198Seschrock "Enumerator module");
3073323Scindi mdb_printf("%-12s %-36s %-30s\n", "tn_children", "",
3084198Seschrock "Hash table of child nodes");
3094198Seschrock mdb_printf(" %-12s 0x%-34p\n", "l_prev", tn.tn_children.l_prev);
3104198Seschrock mdb_printf(" %-12s 0x%-34p\n", "l_next", tn.tn_children.l_next);
3113323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_pgroups", &(tn.tn_pgroups),
3124198Seschrock "Property group list");
3133323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_methods", &(tn.tn_methods),
3144198Seschrock "Registered method list");
3153323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_priv", tn.tn_priv,
3164198Seschrock "Private enumerator data");
3173323Scindi mdb_printf("%-12s %-36d %-30s\n", "tn_refs", tn.tn_refs,
3184198Seschrock "Node reference count");
3193323Scindi
3203323Scindi return (DCMD_OK);
3213323Scindi }
3223323Scindi
3233323Scindi /*ARGSUSED*/
3243323Scindi static int
find_tree_root(uintptr_t addr,const void * data,void * arg)3253323Scindi find_tree_root(uintptr_t addr, const void *data, void *arg)
3263323Scindi {
3273323Scindi ttree_t *tree = (ttree_t *)data;
3283323Scindi char scheme[36];
3293323Scindi
3303323Scindi if (mdb_readstr(scheme, sizeof (scheme), (uintptr_t)tree->tt_scheme)
3313323Scindi < 0) {
3323323Scindi (void) mdb_snprintf(scheme, sizeof (scheme), "<%p>",
3333323Scindi tree->tt_scheme);
3343323Scindi }
3353323Scindi
3363323Scindi if (strncmp(tgt_scheme, scheme, 36) == 0) {
3373323Scindi *((tnode_t **)arg) = tree->tt_root;
3383323Scindi return (WALK_DONE);
3393323Scindi }
3403323Scindi return (WALK_NEXT);
3413323Scindi }
3423323Scindi
3434087Scindi static void
dump_propmethod(uintptr_t addr)3444087Scindi dump_propmethod(uintptr_t addr)
3454087Scindi {
3464087Scindi topo_propmethod_t pm;
347*6070Srobj char mname[32];
3484087Scindi
3494087Scindi if (mdb_vread(&pm, sizeof (pm), addr) != sizeof (pm)) {
3504087Scindi mdb_warn("failed to read topo_propmethod at %p", addr);
3514087Scindi return;
3524087Scindi }
353*6070Srobj if (mdb_readstr(mname, sizeof (mname), (uintptr_t)pm.tpm_name) < 0) {
354*6070Srobj (void) mdb_snprintf(mname, sizeof (mname), "<%p>", pm.tpm_name);
355*6070Srobj }
3564087Scindi
357*6070Srobj mdb_printf(" method: %-32s version: %-16d args: %p\n",
358*6070Srobj mname, pm.tpm_version, pm.tpm_args);
3594087Scindi }
3603323Scindi
3613323Scindi /*
3623323Scindi * Dump the given property value. For the actual property values
3633323Scindi * we dump a pointer to the nvlist which can be decoded using the ::nvlist
3643323Scindi * dcmd from the libnvpair MDB module
3653323Scindi */
3663323Scindi /*ARGSUSED*/
3673323Scindi static int
dump_propval(uintptr_t addr,const void * data,void * arg)3683323Scindi dump_propval(uintptr_t addr, const void *data, void *arg)
3693323Scindi {
3703323Scindi topo_proplist_t *plistp = (topo_proplist_t *)data;
3713323Scindi topo_propval_t pval;
3723323Scindi char name[32], *type;
3733323Scindi
3743323Scindi if (mdb_vread(&pval, sizeof (pval), (uintptr_t)plistp->tp_pval)
3753323Scindi != sizeof (pval)) {
3763323Scindi
3773323Scindi mdb_warn("failed to read topo_propval_t at %p",
3783323Scindi plistp->tp_pval);
3793323Scindi return (WALK_ERR);
3803323Scindi }
3813323Scindi if (mdb_readstr(name, sizeof (name), (uintptr_t)pval.tp_name) < 0) {
3823323Scindi (void) mdb_snprintf(name, sizeof (name), "<%p>", pval.tp_name);
3833323Scindi }
3843323Scindi switch (pval.tp_type) {
3853323Scindi case TOPO_TYPE_BOOLEAN: type = "boolean"; break;
3863323Scindi case TOPO_TYPE_INT32: type = "int32"; break;
3873323Scindi case TOPO_TYPE_UINT32: type = "uint32"; break;
3883323Scindi case TOPO_TYPE_INT64: type = "int64"; break;
3893323Scindi case TOPO_TYPE_UINT64: type = "uint64"; break;
3903323Scindi case TOPO_TYPE_STRING: type = "string"; break;
3913323Scindi case TOPO_TYPE_FMRI: type = "fmri"; break;
3923323Scindi case TOPO_TYPE_INT32_ARRAY: type = "int32[]"; break;
3933323Scindi case TOPO_TYPE_UINT32_ARRAY: type = "uint32[]"; break;
3943323Scindi case TOPO_TYPE_INT64_ARRAY: type = "int64[]"; break;
3953323Scindi case TOPO_TYPE_UINT64_ARRAY: type = "uint64[]"; break;
3963323Scindi case TOPO_TYPE_STRING_ARRAY: type = "string[]"; break;
3973323Scindi case TOPO_TYPE_FMRI_ARRAY: type = "fmri[]"; break;
3983323Scindi default: type = "unknown type";
3993323Scindi }
4003323Scindi mdb_printf(" %-32s %-16s value: %p\n", name, type, pval.tp_val);
4014087Scindi
4024087Scindi if (pval.tp_method != NULL)
4034087Scindi dump_propmethod((uintptr_t)pval.tp_method);
4044087Scindi
4053323Scindi return (WALK_NEXT);
4063323Scindi }
4073323Scindi
4083323Scindi
4093323Scindi /*
4103323Scindi * Dumps the contents of the property group.
4113323Scindi */
4123323Scindi /*ARGSUSED*/
4133323Scindi static int
dump_pgroup(uintptr_t addr,const void * data,void * arg)4143323Scindi dump_pgroup(uintptr_t addr, const void *data, void *arg)
4153323Scindi {
4163323Scindi topo_pgroup_t *pgp = (topo_pgroup_t *)data;
4173323Scindi topo_ipgroup_info_t ipg;
4183323Scindi char buf[32];
4193323Scindi
4203323Scindi if (mdb_vread(&ipg, sizeof (ipg), (uintptr_t)pgp->tpg_info)
4213323Scindi != sizeof (ipg)) {
4223323Scindi
4233323Scindi mdb_warn("failed to read topo_ipgroup_info_t at %p",
4243323Scindi pgp->tpg_info);
4253323Scindi return (WALK_ERR);
4263323Scindi }
4273323Scindi if (mdb_readstr(buf, sizeof (buf), (uintptr_t)ipg.tpi_name) < 0) {
4283323Scindi mdb_warn("failed to read string at %p", ipg.tpi_name);
4293323Scindi return (WALK_ERR);
4303323Scindi }
4313323Scindi /*
4323323Scindi * If this property group is the one we're interested in or if the user
4333323Scindi * specified the "all" property group, we'll dump it
4343323Scindi */
4353323Scindi if ((strncmp(pgrp, buf, sizeof (buf)) == 0) ||
4363323Scindi (strncmp(pgrp, "all", sizeof (buf)) == 0)) {
4373323Scindi
4383323Scindi mdb_printf(" group: %-32s version: %d, stability: %s/%s\n",
4393323Scindi buf, ipg.tpi_version, stab_lvls[ipg.tpi_namestab],
4403323Scindi stab_lvls[ipg.tpi_datastab]);
4413323Scindi
4423323Scindi (void) mdb_pwalk("topo_proplist", dump_propval, NULL, curr_pg);
4433323Scindi }
4443323Scindi return (WALK_NEXT);
4453323Scindi }
4463323Scindi
4473323Scindi
4483323Scindi /*
4493323Scindi * Recursive function to dump the specified node and all of it's children
4503323Scindi */
4513323Scindi /*ARGSUSED*/
4523323Scindi static int
dump_tnode(uintptr_t addr,const void * data,void * arg)4533323Scindi dump_tnode(uintptr_t addr, const void *data, void *arg)
4543323Scindi {
4553323Scindi tnode_t node;
4563323Scindi char pname[255], buf[80], old_pname[255];
4573323Scindi
4583323Scindi if (!addr) {
4593323Scindi return (WALK_NEXT);
4603323Scindi }
4613323Scindi
4623323Scindi if (mdb_vread(&node, sizeof (node), addr) != sizeof (node)) {
4633323Scindi mdb_warn("failed to read tnode_t at %p", addr);
4643323Scindi return (WALK_ERR);
4653323Scindi }
4663323Scindi if (mdb_readstr(buf, sizeof (buf), (uintptr_t)node.tn_name) < 0) {
4673323Scindi (void) mdb_snprintf(buf, sizeof (buf), "<%p>",
4683323Scindi node.tn_name);
4693323Scindi }
4703323Scindi
4713323Scindi if (is_root) {
4723323Scindi mdb_snprintf(pname, sizeof (pname), "%s", parent);
4733323Scindi is_root = 0;
4743323Scindi } else {
4753323Scindi mdb_snprintf(pname, sizeof (pname), "%s/%s=%u",
4763323Scindi parent, buf, node.tn_instance);
4773323Scindi
4783323Scindi if (verbose)
4793323Scindi mdb_printf("%s\n tnode_t: %p\n", pname, addr);
4803323Scindi else
4813323Scindi mdb_printf("%s\n", pname);
4823323Scindi }
4833323Scindi mdb_snprintf(old_pname, sizeof (old_pname), "%s", parent);
4843323Scindi mdb_snprintf(parent, sizeof (parent), "%s", pname);
4853323Scindi
4863323Scindi if (pgrp)
4873323Scindi (void) mdb_pwalk("topo_pgroup", dump_pgroup, NULL, addr);
4883323Scindi
4893323Scindi (void) mdb_pwalk("topo_nodehash", dump_tnode, NULL, addr);
4903323Scindi mdb_snprintf(parent, sizeof (parent), "%s", old_pname);
4913323Scindi
4923323Scindi return (WALK_NEXT);
4933323Scindi }
4943323Scindi
4953323Scindi
4963323Scindi /*
4973323Scindi * Given a topo_hdl_t *, the topo dcmd dumps the topo tree. The format of the
4983323Scindi * output is modeled after fmtopo. Like fmtopo, by default, we'll dump the
4993323Scindi * "hc" scheme tree. The user can optionally specify a different tree via the
5003323Scindi * "-s <scheme>" option.
5013323Scindi *
5023323Scindi * Specifying the "-v" option provides more verbose output. Currently it
5033323Scindi * outputs the tnode_t * addr for each node, which is useful if you want to
5043323Scindi * dump it with the topo_node dcmd.
5053323Scindi *
5063323Scindi * The functionality of the "-P" option is similar to fmtopo.
5073323Scindi */
5083323Scindi /*ARGSUSED*/
5093323Scindi static int
fmtopo(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5103323Scindi fmtopo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5113323Scindi {
5123323Scindi char product[36], *opt_s = NULL, *opt_P = NULL;
5133323Scindi topo_hdl_t th;
5143323Scindi tnode_t *tree_root;
5153323Scindi uint_t opt_v = FALSE;
5163323Scindi char *def_scheme = "hc";
5173323Scindi
5183323Scindi if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v,
5193323Scindi 's', MDB_OPT_STR, &opt_s, 'P', MDB_OPT_STR, &opt_P, NULL)
5203323Scindi != argc) {
5213323Scindi return (DCMD_USAGE);
5223323Scindi }
5233323Scindi
5243323Scindi if (opt_s) {
5253323Scindi tgt_scheme = opt_s;
5263323Scindi } else {
5273323Scindi tgt_scheme = def_scheme;
5283323Scindi }
5293323Scindi
5303323Scindi pgrp = opt_P;
5313323Scindi verbose = opt_v;
5323323Scindi is_root = 1;
5333323Scindi
5343323Scindi /*
5353323Scindi * Read in the topo_handle and some of its string fields from
5363323Scindi * the target's addr space
5373323Scindi */
5383323Scindi if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) {
5393323Scindi mdb_warn("failed to read topo_hdl_t at %p", addr);
5403323Scindi return (DCMD_ERR);
5413323Scindi }
5423323Scindi
5433323Scindi if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product)
5443323Scindi < 0) {
5453323Scindi
5463323Scindi (void) mdb_snprintf(product, sizeof (product), "<%p>",
5473323Scindi th.th_product);
5483323Scindi }
5493323Scindi
5503323Scindi mdb_snprintf(parent, sizeof (parent),
5513323Scindi "%s://:product-id=%s", tgt_scheme, product);
5523323Scindi
5533323Scindi /*
5543323Scindi * Walk the list of topo trees, looking for the one that is for the
5553323Scindi * scheme we're interested in.
5563323Scindi */
5573323Scindi tree_root = NULL;
5583323Scindi mdb_pwalk("topo_tree", find_tree_root, &tree_root, addr);
5593323Scindi
5603323Scindi if (! tree_root) {
5613323Scindi mdb_warn("failed to find a topo tree for scheme %s\n",
5623323Scindi tgt_scheme);
5633323Scindi return (DCMD_ERR);
5643323Scindi }
5653323Scindi
5663323Scindi return (dump_tnode((uintptr_t)tree_root, NULL, NULL));
5673323Scindi }
5683323Scindi
5693323Scindi
5703323Scindi static int
ttree_walk_init(mdb_walk_state_t * wsp)5713323Scindi ttree_walk_init(mdb_walk_state_t *wsp)
5723323Scindi {
5733323Scindi topo_hdl_t th;
5743323Scindi
5753323Scindi if (wsp->walk_addr == NULL) {
5763323Scindi mdb_warn("NULL topo_hdl_t passed in");
5773323Scindi return (WALK_ERR);
5783323Scindi }
5793323Scindi
5803323Scindi if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) {
5813323Scindi mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr);
5823323Scindi return (WALK_ERR);
5833323Scindi }
5843323Scindi
5853323Scindi wsp->walk_addr = (uintptr_t)th.th_trees.l_next;
5863323Scindi wsp->walk_data = mdb_alloc(sizeof (ttree_t), UM_SLEEP);
5873323Scindi
5883323Scindi return (WALK_NEXT);
5893323Scindi }
5903323Scindi
5913323Scindi
5923323Scindi static int
ttree_walk_step(mdb_walk_state_t * wsp)5933323Scindi ttree_walk_step(mdb_walk_state_t *wsp)
5943323Scindi {
5953323Scindi int rv;
5963323Scindi ttree_t *tree;
5973323Scindi
5983323Scindi if (wsp->walk_addr == NULL)
5993323Scindi return (WALK_DONE);
6003323Scindi
6013323Scindi if (mdb_vread(wsp->walk_data, sizeof (ttree_t), wsp->walk_addr)
6023323Scindi != sizeof (ttree_t)) {
6033323Scindi
6043323Scindi mdb_warn("failed to read ttree_t at %p", wsp->walk_addr);
6053323Scindi return (WALK_ERR);
6063323Scindi }
6073323Scindi
6083323Scindi rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
6093323Scindi wsp->walk_cbdata);
6103323Scindi
6113323Scindi tree = (ttree_t *)wsp->walk_data;
6123323Scindi wsp->walk_addr = (uintptr_t)tree->tt_list.l_next;
6133323Scindi
6143323Scindi return (rv);
6153323Scindi }
6163323Scindi
6173323Scindi
6183323Scindi static void
ttree_walk_fini(mdb_walk_state_t * wsp)6193323Scindi ttree_walk_fini(mdb_walk_state_t *wsp)
6203323Scindi {
6213323Scindi mdb_free(wsp->walk_data, sizeof (ttree_t));
6223323Scindi }
6233323Scindi
6243323Scindi
6253323Scindi static int
tmod_walk_init(mdb_walk_state_t * wsp)6263323Scindi tmod_walk_init(mdb_walk_state_t *wsp)
6273323Scindi {
6283323Scindi topo_hdl_t th;
6293323Scindi
6303323Scindi if (wsp->walk_addr == NULL) {
6313323Scindi mdb_warn("NULL topo_hdl_t passed in");
6323323Scindi return (WALK_ERR);
6333323Scindi }
6343323Scindi
6353323Scindi if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) {
6363323Scindi mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr);
6373323Scindi return (WALK_ERR);
6383323Scindi }
6393323Scindi
6403323Scindi if (mdb_vread(&tmh, sizeof (topo_modhash_t), (uintptr_t)th.th_modhash)
6413323Scindi == -1) {
6423323Scindi
6433323Scindi mdb_warn("failed to read topo_modhash_t at %p", wsp->walk_addr);
6443323Scindi return (WALK_DONE);
6453323Scindi }
6463323Scindi
6473323Scindi hash_idx = 0;
6483323Scindi
6493323Scindi if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *),
6503323Scindi (uintptr_t)(tmh.mh_hash)) != sizeof (tnode_t *)) {
6513323Scindi
6523323Scindi mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *),
6533323Scindi tmh.mh_hash);
6543323Scindi return (WALK_ERR);
6553323Scindi }
6563323Scindi
6573323Scindi wsp->walk_data = mdb_alloc(sizeof (topo_mod_t), UM_SLEEP);
6583323Scindi
6593323Scindi return (WALK_NEXT);
6603323Scindi }
6613323Scindi
6623323Scindi
6633323Scindi static int
tmod_walk_step(mdb_walk_state_t * wsp)6643323Scindi tmod_walk_step(mdb_walk_state_t *wsp)
6653323Scindi {
6663323Scindi int rv;
6673323Scindi topo_mod_t *tm;
6683323Scindi
6693323Scindi if (wsp->walk_addr == NULL)
6703323Scindi return (WALK_DONE);
6713323Scindi
6723323Scindi if (mdb_vread(wsp->walk_data, sizeof (topo_mod_t), wsp->walk_addr)
6733323Scindi == -1) {
6743323Scindi
6753323Scindi mdb_warn("failed to read topo_mod_t at %p", wsp->walk_addr);
6763323Scindi return (WALK_DONE);
6773323Scindi }
6783323Scindi
6793323Scindi rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
6803323Scindi wsp->walk_cbdata);
6813323Scindi
6823323Scindi tm = (topo_mod_t *)wsp->walk_data;
6833323Scindi
6843323Scindi if (tm->tm_next)
6853323Scindi wsp->walk_addr = (uintptr_t)tm->tm_next;
6863323Scindi else if (++hash_idx < tmh.mh_hashlen)
6873323Scindi if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *),
6883323Scindi (uintptr_t)(tmh.mh_hash+hash_idx)) != sizeof (tnode_t *)) {
6893323Scindi
6903323Scindi mdb_warn("failed to read %u bytes at %p",
6913323Scindi sizeof (tnode_t *), tmh.mh_hash+hash_idx);
6923323Scindi return (DCMD_ERR);
6933323Scindi }
6943323Scindi else
6953323Scindi wsp->walk_addr = NULL;
6963323Scindi
6973323Scindi return (rv);
6983323Scindi }
6993323Scindi
7003323Scindi static void
tmod_walk_fini(mdb_walk_state_t * wsp)7013323Scindi tmod_walk_fini(mdb_walk_state_t *wsp)
7023323Scindi {
7033323Scindi mdb_free(wsp->walk_data, sizeof (topo_mod_t));
7043323Scindi }
7053323Scindi
7063323Scindi
7073323Scindi static int
tpg_walk_init(mdb_walk_state_t * wsp)7083323Scindi tpg_walk_init(mdb_walk_state_t *wsp)
7093323Scindi {
7103323Scindi tnode_t node;
7113323Scindi
7123323Scindi if (wsp->walk_addr == NULL) {
7133323Scindi mdb_warn("NULL tnode_t passed in");
7143323Scindi return (WALK_ERR);
7153323Scindi }
7163323Scindi
7173323Scindi if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) {
7183323Scindi mdb_warn("failed to read tnode_t at %p", wsp->walk_addr);
7193323Scindi return (WALK_ERR);
7203323Scindi }
7213323Scindi
7223323Scindi wsp->walk_addr = (uintptr_t)node.tn_pgroups.l_next;
7233323Scindi wsp->walk_data = mdb_alloc(sizeof (topo_pgroup_t), UM_SLEEP);
7243323Scindi
7253323Scindi return (WALK_NEXT);
7263323Scindi }
7273323Scindi
7283323Scindi
7293323Scindi static int
tpg_walk_step(mdb_walk_state_t * wsp)7303323Scindi tpg_walk_step(mdb_walk_state_t *wsp)
7313323Scindi {
7323323Scindi int rv;
7333323Scindi topo_pgroup_t *tpgp;
7343323Scindi
7353323Scindi if (wsp->walk_addr == NULL)
7363323Scindi return (WALK_DONE);
7373323Scindi
7383323Scindi if (mdb_vread(wsp->walk_data, sizeof (topo_pgroup_t), wsp->walk_addr)
7393323Scindi == -1) {
7403323Scindi
7413323Scindi mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr);
7423323Scindi return (WALK_DONE);
7433323Scindi }
7443323Scindi
7453323Scindi curr_pg = wsp->walk_addr;
7463323Scindi rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
7473323Scindi wsp->walk_cbdata);
7483323Scindi
7493323Scindi tpgp = (topo_pgroup_t *)wsp->walk_data;
7503323Scindi wsp->walk_addr = (uintptr_t)tpgp->tpg_list.l_next;
7513323Scindi
7523323Scindi return (rv);
7533323Scindi }
7543323Scindi
7553323Scindi
7563323Scindi static void
tpg_walk_fini(mdb_walk_state_t * wsp)7573323Scindi tpg_walk_fini(mdb_walk_state_t *wsp)
7583323Scindi {
7593323Scindi mdb_free(wsp->walk_data, sizeof (topo_pgroup_t));
7603323Scindi }
7613323Scindi
7623323Scindi
7633323Scindi static int
tpl_walk_init(mdb_walk_state_t * wsp)7643323Scindi tpl_walk_init(mdb_walk_state_t *wsp)
7653323Scindi {
7663323Scindi topo_pgroup_t pg;
7673323Scindi
7683323Scindi if (wsp->walk_addr == NULL) {
7693323Scindi mdb_warn("NULL topo_pgroup_t passed in");
7703323Scindi return (WALK_ERR);
7713323Scindi }
7723323Scindi
7733323Scindi if (mdb_vread(&pg, sizeof (pg), wsp->walk_addr) != sizeof (pg)) {
7743323Scindi mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr);
7753323Scindi return (WALK_ERR);
7763323Scindi }
7773323Scindi
7783323Scindi wsp->walk_addr = (uintptr_t)pg.tpg_pvals.l_next;
7793323Scindi wsp->walk_data = mdb_alloc(sizeof (topo_proplist_t), UM_SLEEP);
7803323Scindi
7813323Scindi return (WALK_NEXT);
7823323Scindi }
7833323Scindi
7843323Scindi
7853323Scindi static int
tpl_walk_step(mdb_walk_state_t * wsp)7863323Scindi tpl_walk_step(mdb_walk_state_t *wsp)
7873323Scindi {
7883323Scindi int rv;
7893323Scindi topo_proplist_t *plp;
7903323Scindi
7913323Scindi if (wsp->walk_addr == NULL)
7923323Scindi return (WALK_DONE);
7933323Scindi
7943323Scindi if (mdb_vread(wsp->walk_data, sizeof (topo_proplist_t), wsp->walk_addr)
7953323Scindi == -1) {
7963323Scindi
7973323Scindi mdb_warn("failed to read topo_proplist_t at %p",
7983323Scindi wsp->walk_addr);
7993323Scindi return (WALK_DONE);
8003323Scindi }
8013323Scindi plp = (topo_proplist_t *)wsp->walk_data;
8023323Scindi
8033323Scindi rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
8043323Scindi wsp->walk_cbdata);
8053323Scindi
8063323Scindi wsp->walk_addr = (uintptr_t)plp->tp_list.l_next;
8073323Scindi
8083323Scindi return (rv);
8093323Scindi }
8103323Scindi
8113323Scindi
8123323Scindi static void
tpl_walk_fini(mdb_walk_state_t * wsp)8133323Scindi tpl_walk_fini(mdb_walk_state_t *wsp)
8143323Scindi {
8153323Scindi mdb_free(wsp->walk_data, sizeof (topo_proplist_t));
8163323Scindi }
8173323Scindi
8183323Scindi
8193323Scindi static int
tnh_walk_init(mdb_walk_state_t * wsp)8203323Scindi tnh_walk_init(mdb_walk_state_t *wsp)
8213323Scindi {
8223323Scindi tnode_t node;
8233323Scindi tnwalk_state_t *state;
8243323Scindi
8253323Scindi if (wsp->walk_addr == NULL) {
8263323Scindi mdb_warn("NULL tnode_t passed in");
8273323Scindi return (WALK_ERR);
8283323Scindi }
8293323Scindi
8303323Scindi if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) {
8313323Scindi mdb_warn("failed to read tnode_t at %p", wsp->walk_addr);
8323323Scindi return (WALK_ERR);
8333323Scindi }
8343323Scindi
8353323Scindi state = mdb_zalloc(sizeof (tnwalk_state_t), UM_SLEEP);
8363323Scindi
8373323Scindi state->curr_hash = (topo_nodehash_t *)node.tn_children.l_next;
8383323Scindi state->hash_idx = 0;
8393323Scindi wsp->walk_data = state;
8403323Scindi
8413323Scindi return (WALK_NEXT);
8423323Scindi }
8433323Scindi
8443323Scindi
8453323Scindi static int
tnh_walk_step(mdb_walk_state_t * wsp)8463323Scindi tnh_walk_step(mdb_walk_state_t *wsp)
8473323Scindi {
8483323Scindi tnwalk_state_t *state = wsp->walk_data;
8493323Scindi int rv, i = state->hash_idx++;
8503323Scindi tnode_t *npp;
8513323Scindi
8523323Scindi if (state->curr_hash == NULL)
8533323Scindi return (WALK_DONE);
8543323Scindi
8553323Scindi if (mdb_vread(&(state->hash), sizeof (topo_nodehash_t),
8563323Scindi (uintptr_t)state->curr_hash) != sizeof (topo_nodehash_t)) {
8573323Scindi
8583323Scindi mdb_warn("failed to read topo_nodehash_t at %p",
8593323Scindi (uintptr_t)state->curr_hash);
8603323Scindi return (WALK_ERR);
8613323Scindi }
8623323Scindi
8633323Scindi if (mdb_vread(&npp, sizeof (tnode_t *),
8643323Scindi (uintptr_t)(state->hash.th_nodearr+i)) != sizeof (tnode_t *)) {
8653323Scindi
8663323Scindi mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *),
8673323Scindi state->hash.th_nodearr+i);
8683323Scindi return (WALK_ERR);
8693323Scindi }
8703323Scindi wsp->walk_addr = (uintptr_t)npp;
8713323Scindi
8723323Scindi rv = wsp->walk_callback(wsp->walk_addr, state, wsp->walk_cbdata);
8733323Scindi
8743323Scindi if (state->hash_idx >= state->hash.th_arrlen) {
8753323Scindi /*
8763323Scindi * move on to the next child hash bucket
8773323Scindi */
8783323Scindi state->curr_hash =
8793323Scindi (topo_nodehash_t *)(state->hash.th_list.l_next);
8803323Scindi state->hash_idx = 0;
8813323Scindi }
8823323Scindi
8833323Scindi return (rv);
8843323Scindi }
8853323Scindi
8863323Scindi
8873323Scindi static void
tnh_walk_fini(mdb_walk_state_t * wsp)8883323Scindi tnh_walk_fini(mdb_walk_state_t *wsp)
8893323Scindi {
8903323Scindi mdb_free(wsp->walk_data, sizeof (tnwalk_state_t));
8913323Scindi }
8923323Scindi
8933323Scindi
8943323Scindi static const mdb_dcmd_t dcmds[] = {
8953323Scindi { "topo_handle", "", "print contents of a topo handle", topo_handle,
8963323Scindi NULL },
8973323Scindi { "topo_module", "", "print contents of a topo module handle",
8983323Scindi topo_module, NULL },
8993323Scindi { "topo_node", "", "print contents of a topo node", topo_node, NULL },
9003323Scindi { "fmtopo", "[-P <pgroup>][-s <scheme>][-v]",
9013323Scindi "print topology of the given handle", fmtopo, NULL },
9023323Scindi { NULL }
9033323Scindi };
9043323Scindi
9053323Scindi static const mdb_walker_t walkers[] = {
9063323Scindi { "topo_tree", "walk the tree list for a given topo handle",
9073323Scindi ttree_walk_init, ttree_walk_step, ttree_walk_fini, NULL },
9083323Scindi { "topo_module", "walk the module hash for a given topo handle",
9093323Scindi tmod_walk_init, tmod_walk_step, tmod_walk_fini, NULL },
9103323Scindi { "topo_pgroup", "walk the property groups for a given topo node",
9113323Scindi tpg_walk_init, tpg_walk_step, tpg_walk_fini, NULL },
9123323Scindi { "topo_proplist", "walk the property list for a given property group",
9133323Scindi tpl_walk_init, tpl_walk_step, tpl_walk_fini, NULL },
9143323Scindi { "topo_nodehash", "walk the child nodehash for a given topo node",
9153323Scindi tnh_walk_init, tnh_walk_step, tnh_walk_fini, NULL },
9163323Scindi { NULL }
9173323Scindi };
9183323Scindi
9193323Scindi static const mdb_modinfo_t modinfo = {
9203323Scindi MDB_API_VERSION, dcmds, walkers
9213323Scindi };
9223323Scindi
9233323Scindi const mdb_modinfo_t *
_mdb_init(void)9243323Scindi _mdb_init(void)
9253323Scindi {
9263323Scindi return (&modinfo);
9273323Scindi }
928