xref: /onnv-gate/usr/src/cmd/mdb/common/modules/nca/nca.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*11066Srafael.vanoni@sun.com  * Common Development and Distribution License (the "License").
6*11066Srafael.vanoni@sun.com  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * NCA mdb module.  Provides a collection of dcmds and walkers that
280Sstevel@tonic-gate  * operate on core NCA data structures.  Dependencies on NCA internals
290Sstevel@tonic-gate  * are described in $SRC/uts/common/inet/nca/nca.h.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
330Sstevel@tonic-gate #include <mdb/mdb_ks.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/sunddi.h>
380Sstevel@tonic-gate #include <sys/processor.h>
390Sstevel@tonic-gate #include <netinet/in.h>
400Sstevel@tonic-gate #include <netinet/ip6.h>	/* must come before common.h */
410Sstevel@tonic-gate #include <inet/common.h>	/* must come before led.h */
420Sstevel@tonic-gate #include <inet/led.h>		/* must come before ip.h */
430Sstevel@tonic-gate #include <inet/ip.h>		/* must come before tcp.h */
440Sstevel@tonic-gate #include <inet/tcp.h>		/* must come before nca/nca.h */
450Sstevel@tonic-gate #include <inet/nca/nca.h>
460Sstevel@tonic-gate #include <inet/nca/ncadoorhdr.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	NCA_WALK_PLRU	(void *)1
490Sstevel@tonic-gate #define	NCA_WALK_VLRU	(void *)2
500Sstevel@tonic-gate #define	NCA_ADDR_WIDTH	11	/* kernel addresses *shouldn't* be wider */
510Sstevel@tonic-gate #define	YESNO(bool)	((bool) ? 'Y' : 'n')
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * Structure for assigning a name to a region of memory.
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate typedef struct {
570Sstevel@tonic-gate 	const char	*nm_name;	/* name of region */
580Sstevel@tonic-gate 	int		nm_len;		/* length to region */
590Sstevel@tonic-gate 	uintptr_t	nm_addr;	/* starting address of region */
600Sstevel@tonic-gate } namedmem_t;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate  * Structure for giving a name to a constant.
640Sstevel@tonic-gate  */
650Sstevel@tonic-gate typedef struct {
660Sstevel@tonic-gate 	const char *const_name;  /* name of constant */
670Sstevel@tonic-gate 	int	    const_value; /* constant itself */
680Sstevel@tonic-gate } constname_t;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * Structure for mapping a bit to a name and a description.  Instances
720Sstevel@tonic-gate  * of this datatype should always be arrays which decode bits in a
730Sstevel@tonic-gate  * number, and the index into the array should contain the description
740Sstevel@tonic-gate  * of a bit at position "index" in the number being decoded.  The list
750Sstevel@tonic-gate  * must be terminated by an entry with a NULL `bit_name'.
760Sstevel@tonic-gate  */
770Sstevel@tonic-gate typedef struct {
780Sstevel@tonic-gate 	const char *bit_name;	/* name of bit */
790Sstevel@tonic-gate 	const char *bit_descr;	/* description of bit's purpose */
800Sstevel@tonic-gate } bitname_t;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate  * Note: These should be defined in upside down order to their
840Sstevel@tonic-gate  * definitions in nca.h
850Sstevel@tonic-gate  * (Assumes that current ordering convention in nca.h will
860Sstevel@tonic-gate  * prevail for future additions)
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate static const bitname_t node_refs[] = {
890Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000001" },
900Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000002" },
910Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000004" },
920Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000008" },
930Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000010" },
940Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000020" },
950Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000040" },
960Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000080" },
970Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000100" },
980Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000200" },
990Sstevel@tonic-gate 	{ "REF_UNUSED",		"0x00000400" },
1000Sstevel@tonic-gate 	{ "REF_SEGMAP",		"segmapped (PHYS|VIRT)" },
1010Sstevel@tonic-gate 	{ "REF_NCAFS",		"NCAfs required" },
1020Sstevel@tonic-gate 	{ "REF_VNODE",		"vnode hashed" },
1030Sstevel@tonic-gate 	{ "REF_ERROR",		"errored" },
1040Sstevel@tonic-gate 	{ "REF_OWNED",		"owned (won't be freed)" },
1050Sstevel@tonic-gate 	{ "REF_UPCALL",		"upcall not completed yet" },
1060Sstevel@tonic-gate 	{ "REF_CTAG",		"CTAG hashed" },
1070Sstevel@tonic-gate 	{ "REF_PREEMPT",	"processing preempted" },
1080Sstevel@tonic-gate 	{ "REF_ONVLRU",		"on virtual memory LRU list" },
1090Sstevel@tonic-gate 	{ "REF_ONPLRU",		"on physical memory LRU list" },
1100Sstevel@tonic-gate 	{ "REF_MISS",		"in miss processing" },
1110Sstevel@tonic-gate 	{ "REF_NOLRU",		"not safe for LRU reclaim" },
1120Sstevel@tonic-gate 	{ "REF_RESP",		"done parsing response header" },
1130Sstevel@tonic-gate 	{ "REF_FILE",		"reachable through filename hash" },
1140Sstevel@tonic-gate 	{ "REF_SAFED",		"not safe for use" },
1150Sstevel@tonic-gate 	{ "REF_DONE",		"done with miss processing" },
1160Sstevel@tonic-gate 	{ "REF_KMEM",		"content-backed via kmem_alloc()" },
1170Sstevel@tonic-gate 	{ "REF_CKSUM",		"checksum mapping in-use" },
1180Sstevel@tonic-gate 	{ "REF_VIRT",		"virtually mapped (data valid)" },
1190Sstevel@tonic-gate 	{ "REF_PHYS",		"physically mapped (pp valid)" },
1200Sstevel@tonic-gate 	{ "REF_URI",		"reachable through URI hash" },
1210Sstevel@tonic-gate 	{ NULL }
1220Sstevel@tonic-gate };
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate static const bitname_t advise_types[] = {
1250Sstevel@tonic-gate 	{ "ADVISE",		"" },
1260Sstevel@tonic-gate 	{ "ADVISE_REPLACE",	"replace cached object with provided object" },
1270Sstevel@tonic-gate 	{ "ADVISE_FLUSH",	"flush cached object" },
1280Sstevel@tonic-gate 	{ "ADVISE_TEMP",	"return this object; keep cached object" },
1290Sstevel@tonic-gate 	{ NULL }
1300Sstevel@tonic-gate };
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate /*
1330Sstevel@tonic-gate  * Print `len' bytes of buffer `buf'.  Handle nonprintable characters
1340Sstevel@tonic-gate  * specially.
1350Sstevel@tonic-gate  */
1360Sstevel@tonic-gate static void
printbuf(uint8_t * buf,size_t len)1370Sstevel@tonic-gate printbuf(uint8_t *buf, size_t len)
1380Sstevel@tonic-gate {
1390Sstevel@tonic-gate 	size_t	i;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/*
1420Sstevel@tonic-gate 	 * TODO: display octal form of unprintable characters in dim mode
1430Sstevel@tonic-gate 	 *	 once mdb pager bug is fixed.
1440Sstevel@tonic-gate 	 */
1450Sstevel@tonic-gate 	for (i = 0; i < len; i++)
1460Sstevel@tonic-gate 		mdb_printf(isgraph(buf[i]) ? "%c" : "\\%#o", buf[i]);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	mdb_printf("\n");
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate /*
1520Sstevel@tonic-gate  * Convert HTTP method operation `method' to a name.
1530Sstevel@tonic-gate  */
1540Sstevel@tonic-gate static const char *
method2name(unsigned int method)1550Sstevel@tonic-gate method2name(unsigned int method)
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate 	unsigned int i;
1580Sstevel@tonic-gate 	static constname_t http_methods[] = {
1590Sstevel@tonic-gate 		{ "NCA_UNKNOWN", NCA_UNKNOWN	},
1600Sstevel@tonic-gate 		{ "NCA_OPTIONS", NCA_OPTIONS	},
1610Sstevel@tonic-gate 		{ "NCA_GET",	 NCA_GET	},
1620Sstevel@tonic-gate 		{ "NCA_HEAD",	 NCA_HEAD	},
1630Sstevel@tonic-gate 		{ "NCA_POST",	 NCA_POST	},
1640Sstevel@tonic-gate 		{ "NCA_PUT",	 NCA_PUT	},
1650Sstevel@tonic-gate 		{ "NCA_DELETE",  NCA_DELETE	},
1660Sstevel@tonic-gate 		{ "NCA_TRACE",	 NCA_TRACE	},
1670Sstevel@tonic-gate 		{ "NCA_RAW",	 NCA_RAW	},
1680Sstevel@tonic-gate 		{ NULL }
1690Sstevel@tonic-gate 	};
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	for (i = 0; http_methods[i].const_name != NULL; i++) {
1720Sstevel@tonic-gate 		if (method == http_methods[i].const_value)
1730Sstevel@tonic-gate 			return (http_methods[i].const_name);
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return ("<unknown>");
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * Convert TCP state `state' to a name.
1810Sstevel@tonic-gate  */
1820Sstevel@tonic-gate static const char *
state2name(int state)1830Sstevel@tonic-gate state2name(int state)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate 	unsigned int i;
1860Sstevel@tonic-gate 	static constname_t tcp_states[] = {
1870Sstevel@tonic-gate 		{ "CLOSED",	 TCPS_CLOSED		},
1880Sstevel@tonic-gate 		{ "IDLE",	 TCPS_IDLE		},
1890Sstevel@tonic-gate 		{ "BOUND",	 TCPS_BOUND		},
1900Sstevel@tonic-gate 		{ "LISTEN",	 TCPS_LISTEN		},
1910Sstevel@tonic-gate 		{ "SYN_SENT",	 TCPS_SYN_SENT		},
1920Sstevel@tonic-gate 		{ "SYN_RCVD",	 TCPS_SYN_RCVD		},
1930Sstevel@tonic-gate 		{ "ESTABLISHED", TCPS_ESTABLISHED 	},
1940Sstevel@tonic-gate 		{ "CLOSE_WAIT",	 TCPS_CLOSE_WAIT	},
1950Sstevel@tonic-gate 		{ "FIN_WAIT1",	 TCPS_FIN_WAIT_1	},
1960Sstevel@tonic-gate 		{ "FIN_WAIT2",	 TCPS_FIN_WAIT_2	},
1970Sstevel@tonic-gate 		{ "CLOSING",	 TCPS_CLOSING		},
1980Sstevel@tonic-gate 		{ "LAST_ACK",	 TCPS_LAST_ACK 		},
1990Sstevel@tonic-gate 		{ "TIME_WAIT",	 TCPS_TIME_WAIT		},
2000Sstevel@tonic-gate 		{ NULL }
2010Sstevel@tonic-gate 	};
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	for (i = 0; tcp_states[i].const_name != NULL; i++) {
2040Sstevel@tonic-gate 		if (state == tcp_states[i].const_value)
2050Sstevel@tonic-gate 			return (tcp_states[i].const_name);
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	return ("<unknown>");
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate /*
2120Sstevel@tonic-gate  * Convert an nca_io2_t direct_type into a name.
2130Sstevel@tonic-gate  */
2140Sstevel@tonic-gate static const char *
direct2name(unsigned int type)2150Sstevel@tonic-gate direct2name(unsigned int type)
2160Sstevel@tonic-gate {
2170Sstevel@tonic-gate 	unsigned int i;
2180Sstevel@tonic-gate 	static const constname_t direct_types[] = {
2190Sstevel@tonic-gate 		{ "DIRECT_NONE",	NCA_IO_DIRECT_NONE	},
2200Sstevel@tonic-gate 		{ "DIRECT_FILENAME",	NCA_IO_DIRECT_FILENAME	},
2210Sstevel@tonic-gate 		{ "DIRECT_SHMSEG",	NCA_IO_DIRECT_SHMSEG	},
2220Sstevel@tonic-gate 		{ "DIRECT_FILEDESC",	NCA_IO_DIRECT_FILEDESC	},
2230Sstevel@tonic-gate 		{ "DIRECT_CTAG",	NCA_IO_DIRECT_CTAG	},
2240Sstevel@tonic-gate 		{ "DIRECT_SPLICE",	NCA_IO_DIRECT_SPLICE	},
2250Sstevel@tonic-gate 		{ "DIRECT_TEE",		NCA_IO_DIRECT_TEE 	},
2260Sstevel@tonic-gate 		{ "DIRECT_FILE_FD",	NCA_IO_DIRECT_FILE_FD 	},
2270Sstevel@tonic-gate 		{ NULL,			0			}
2280Sstevel@tonic-gate 	};
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	for (i = 0; direct_types[i].const_name != NULL; i++) {
2310Sstevel@tonic-gate 		if (type == direct_types[i].const_value)
2320Sstevel@tonic-gate 			return (direct_types[i].const_name);
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	return ("<unknown>");
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate  * Convert an nca_io2_t operation into a name.
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate static const char *
op2name(nca_op_t op)2420Sstevel@tonic-gate op2name(nca_op_t op)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	unsigned int i;
2450Sstevel@tonic-gate 	static const constname_t op_types[] = {
2460Sstevel@tonic-gate 		{ "http",		http_op		},
2470Sstevel@tonic-gate 		{ "error",		error_op	},
2480Sstevel@tonic-gate 		{ "error_retry",	error_retry_op	},
2490Sstevel@tonic-gate 		{ "resource",		resource_op	},
2500Sstevel@tonic-gate 		{ "timeout",		timeout_op	},
2510Sstevel@tonic-gate 		{ "door_attach",	door_attach_op	},
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 		{ "log",		log_op		},
2540Sstevel@tonic-gate 		{ "log_ok",		log_ok_op	},
2550Sstevel@tonic-gate 		{ "log_error",		log_error_op	},
2560Sstevel@tonic-gate 		{ "log_op_fiov",	log_op_fiov	},
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 		{ NULL,			0		}
2590Sstevel@tonic-gate 	};
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	for (i = 0; op_types[i].const_name != NULL; i++) {
2620Sstevel@tonic-gate 		if (op == op_types[i].const_value)
2630Sstevel@tonic-gate 			return (op_types[i].const_name);
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	return ("<unknown>");
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate  * Convert from ticks to milliseconds.
2710Sstevel@tonic-gate  */
2720Sstevel@tonic-gate static uint64_t
tick2msec(uint64_t tick)2730Sstevel@tonic-gate tick2msec(uint64_t tick)
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate 	static int tick_per_msec;
2760Sstevel@tonic-gate 	static int msec_per_tick;
2770Sstevel@tonic-gate 	static int once;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	if (once == 0) {
2800Sstevel@tonic-gate 		if (mdb_readvar(&tick_per_msec, "tick_per_msec") == -1) {
2810Sstevel@tonic-gate 			mdb_warn("cannot read symbol tick_per_msec");
2820Sstevel@tonic-gate 			return (0);
2830Sstevel@tonic-gate 		}
2840Sstevel@tonic-gate 		if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) {
2850Sstevel@tonic-gate 			mdb_warn("cannot read symbol msec_per_tick");
2860Sstevel@tonic-gate 			return (0);
2870Sstevel@tonic-gate 		}
2880Sstevel@tonic-gate 		once++;
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	return (tick_per_msec ? tick / tick_per_msec : tick * msec_per_tick);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate /*
2950Sstevel@tonic-gate  * Print the core fields in an nca_io2_t.  With the "-v" argument,
2960Sstevel@tonic-gate  * provide more verbose output.  With the "-p" argument, print payload
2970Sstevel@tonic-gate  * information.
2980Sstevel@tonic-gate  */
2990Sstevel@tonic-gate static int
nca_io2(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3000Sstevel@tonic-gate nca_io2(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	unsigned int	i;
3030Sstevel@tonic-gate 	unsigned int	payload_len;
3040Sstevel@tonic-gate 	uint64_t	payload_output_max = 0;
3050Sstevel@tonic-gate 	unsigned int	verbose = FALSE;
3060Sstevel@tonic-gate 	const int	IO2_ADVDELT = NCA_ADDR_WIDTH + 1;
3070Sstevel@tonic-gate 	boolean_t	arm;
3080Sstevel@tonic-gate 	nca_io2_t	io2;
3090Sstevel@tonic-gate 	uint8_t		*buf;
3100Sstevel@tonic-gate 	namedmem_t	area[3];
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
3130Sstevel@tonic-gate 		return (DCMD_USAGE);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose,
3160Sstevel@tonic-gate 	    'p', MDB_OPT_UINT64, &payload_output_max, NULL) != argc)
3170Sstevel@tonic-gate 		return (DCMD_USAGE);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	if (!DCMD_HDRSPEC(flags) && verbose)
3200Sstevel@tonic-gate 		mdb_printf("\n\n");
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) || verbose) {
3230Sstevel@tonic-gate 		mdb_printf("%<u>%-*s %2s %4s %8s %*s %8s %16s %-12s%</u>\n",
3240Sstevel@tonic-gate 		    NCA_ADDR_WIDTH, "ADDR", "AV", "MFNP", "TID",
3250Sstevel@tonic-gate 		    NCA_ADDR_WIDTH, "CONN", "CONN_TAG", "CACHE_TAG",
3260Sstevel@tonic-gate 		    "OPERATION");
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	if (mdb_vread(&io2, sizeof (nca_io2_t), addr) == -1) {
3300Sstevel@tonic-gate 		mdb_warn("cannot read nca_io2_t at %p", addr);
3310Sstevel@tonic-gate 		return (DCMD_ERR);
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	if (io2.version != NCA_HTTP_VERSION2)
3350Sstevel@tonic-gate 		mdb_warn("nca_io2_t at %p has incorrect version `%u'\n", addr,
3360Sstevel@tonic-gate 		    io2.version);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	mdb_printf("%0*p %02x %c%c%c%c %08x %0*llx %08x %016llx %s\n",
3390Sstevel@tonic-gate 	    NCA_ADDR_WIDTH, addr, io2.advisory, YESNO(io2.more),
3400Sstevel@tonic-gate 	    YESNO(io2.first), YESNO(io2.nocache), YESNO(io2.preempt),
3410Sstevel@tonic-gate 	    (uint32_t)io2.tid, NCA_ADDR_WIDTH, io2.cid, io2.tag, io2.ctag,
3420Sstevel@tonic-gate 	    op2name(io2.op));
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	if (verbose) {
3450Sstevel@tonic-gate 		arm = B_TRUE;
3460Sstevel@tonic-gate 		for (i = 0; advise_types[i].bit_name != NULL; i++) {
3470Sstevel@tonic-gate 			if ((io2.advisory & (1 << i)) == 0)
3480Sstevel@tonic-gate 				continue;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 			if (arm) {
3510Sstevel@tonic-gate 				mdb_printf("%*s|\n", IO2_ADVDELT, "");
3520Sstevel@tonic-gate 				mdb_printf("%*s+-->  ", IO2_ADVDELT, "");
3530Sstevel@tonic-gate 				arm = B_FALSE;
3540Sstevel@tonic-gate 			} else
3550Sstevel@tonic-gate 				mdb_printf("%*s      ", IO2_ADVDELT, "");
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 			mdb_printf("%-15s %s\n", advise_types[i].bit_name,
3580Sstevel@tonic-gate 			    advise_types[i].bit_descr);
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	payload_len = io2.data_len + io2.direct_len + io2.trailer_len;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	if (payload_output_max == 0 || payload_len == 0)
3650Sstevel@tonic-gate 		return (DCMD_OK);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	mdb_inc_indent(4);
3680Sstevel@tonic-gate 	mdb_printf("\n%u byte payload consists of:\n", payload_len);
3690Sstevel@tonic-gate 	mdb_inc_indent(4);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	buf = mdb_alloc(payload_output_max, UM_SLEEP);
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	area[0].nm_name = "data";
3740Sstevel@tonic-gate 	area[0].nm_addr = addr + io2.data;
3750Sstevel@tonic-gate 	area[0].nm_len  = io2.data_len;
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	area[1].nm_name = direct2name(io2.direct_type);
3780Sstevel@tonic-gate 	area[1].nm_addr = addr + io2.direct;
3790Sstevel@tonic-gate 	area[1].nm_len  = io2.direct_len;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	area[2].nm_name = "trailer";
3820Sstevel@tonic-gate 	area[2].nm_addr = addr + io2.trailer;
3830Sstevel@tonic-gate 	area[2].nm_len  = io2.trailer_len;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	for (i = 0; i < sizeof (area) / sizeof (area[0]); i++) {
3860Sstevel@tonic-gate 		if (area[i].nm_len <= 0)
3870Sstevel@tonic-gate 			continue;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 		mdb_printf("%d byte %s area at %p (", area[i].nm_len,
3900Sstevel@tonic-gate 		    area[i].nm_name, area[i].nm_addr);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 		if (area[i].nm_len > payload_output_max) {
3930Sstevel@tonic-gate 			mdb_printf("first");
3940Sstevel@tonic-gate 			area[i].nm_len = (int)payload_output_max;
3950Sstevel@tonic-gate 		} else
3960Sstevel@tonic-gate 			mdb_printf("all");
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		mdb_printf(" %u bytes follow):\n", area[i].nm_len);
3990Sstevel@tonic-gate 		if (mdb_vread(buf, area[i].nm_len, area[i].nm_addr) == -1)
4000Sstevel@tonic-gate 			mdb_warn("cannot read %s area at %p", area[i].nm_name,
4010Sstevel@tonic-gate 			    area[i].nm_addr);
4020Sstevel@tonic-gate 		else {
4030Sstevel@tonic-gate 			mdb_inc_indent(4);
4040Sstevel@tonic-gate 			printbuf(buf, area[i].nm_len);
4050Sstevel@tonic-gate 			mdb_dec_indent(4);
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 	mdb_dec_indent(4);
4090Sstevel@tonic-gate 	mdb_dec_indent(4);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	mdb_free(buf, payload_output_max);
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	return (DCMD_OK);
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate static void
nca_io2_help(void)4170Sstevel@tonic-gate nca_io2_help(void)
4180Sstevel@tonic-gate {
4190Sstevel@tonic-gate 	mdb_printf("Print the core information for a given NCA nca_io2_t.\n");
4200Sstevel@tonic-gate 	mdb_printf("Options:\n");
4210Sstevel@tonic-gate 	mdb_printf("\t-p N\tshow up to N bytes of payload information from\n");
4220Sstevel@tonic-gate 	mdb_printf("\t\teach payload area\n");
4230Sstevel@tonic-gate 	mdb_printf("\t\t(reminder: default radix is %<b>hex%</b>)\n");
4240Sstevel@tonic-gate 	mdb_printf("\t-v\tbe verbose (more descriptive)\n");
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate  * Print the core fields for one or all NCA timers.  If no address is
4290Sstevel@tonic-gate  * specified, all NCA timers are printed; otherwise the specified timer
4300Sstevel@tonic-gate  * list is printed.  With the "-e" argument, the "encapsulated" pointer
4310Sstevel@tonic-gate  * for each te_t in a given tb_t is shown in parentheses.
4320Sstevel@tonic-gate  */
4330Sstevel@tonic-gate static int
nca_timer(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4340Sstevel@tonic-gate nca_timer(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	unsigned int	show_encap = FALSE;
4370Sstevel@tonic-gate 	void		*tb_addr, *te_addr;
4380Sstevel@tonic-gate 	clock_t		lbolt, first_exec = 0;
4390Sstevel@tonic-gate 	ti_t		ti;
4400Sstevel@tonic-gate 	tb_t		tb;
4410Sstevel@tonic-gate 	te_t		te;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
4440Sstevel@tonic-gate 		if (mdb_walk_dcmd("nca_timer", "nca_timer", argc, argv) == -1) {
4450Sstevel@tonic-gate 			mdb_warn("cannot walk timer list");
4460Sstevel@tonic-gate 			return (DCMD_ERR);
4470Sstevel@tonic-gate 		}
4480Sstevel@tonic-gate 		return (DCMD_OK);
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 'e', MDB_OPT_SETBITS, TRUE, &show_encap,
4520Sstevel@tonic-gate 	    NULL) != argc)
4530Sstevel@tonic-gate 		return (DCMD_USAGE);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
4560Sstevel@tonic-gate 		mdb_printf("%<u>%-*s %-*s %-55s%</u>\n", NCA_ADDR_WIDTH, "TI",
4570Sstevel@tonic-gate 		    NCA_ADDR_WIDTH, "SQUEUE", "FIRELIST +MSEC");
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (mdb_vread(&ti, sizeof (ti_t), addr) == -1) {
4610Sstevel@tonic-gate 		mdb_warn("cannot read ti_t at %p", addr);
4620Sstevel@tonic-gate 		return (DCMD_ERR);
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
465*11066Srafael.vanoni@sun.com 	if ((lbolt = (clock_t)mdb_get_lbolt()) == -1)
4660Sstevel@tonic-gate 		return (DCMD_ERR);
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	mdb_printf("%0*p %0*p", NCA_ADDR_WIDTH, addr, NCA_ADDR_WIDTH, ti.ep);
4690Sstevel@tonic-gate 	mdb_inc_indent(24);
4700Sstevel@tonic-gate 	for (tb_addr = ti.head; tb_addr != NULL; tb_addr = tb.next) {
4710Sstevel@tonic-gate 		if (mdb_vread(&tb, sizeof (tb_t), (uintptr_t)tb_addr) == -1) {
4720Sstevel@tonic-gate 			mdb_warn("cannot read tb_t at %p", tb_addr);
4730Sstevel@tonic-gate 			return (DCMD_ERR);
4740Sstevel@tonic-gate 		}
4750Sstevel@tonic-gate 		if (first_exec == 0) {
4760Sstevel@tonic-gate 			mdb_printf(" %ld", tick2msec(tb.exec - lbolt));
4770Sstevel@tonic-gate 			first_exec = tb.exec;
4780Sstevel@tonic-gate 		} else
4790Sstevel@tonic-gate 			mdb_printf(" %+lld", tick2msec(tb.exec - first_exec));
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 		if (!show_encap || tb.head == NULL)
4820Sstevel@tonic-gate 			continue;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 		mdb_printf("(");
4850Sstevel@tonic-gate 		for (te_addr = tb.head; te_addr != NULL; te_addr = te.next) {
4860Sstevel@tonic-gate 			if (mdb_vread(&te, sizeof (te_t), (uintptr_t)te_addr)
4870Sstevel@tonic-gate 			    == -1) {
4880Sstevel@tonic-gate 				mdb_warn("cannot read te_t at %p", te_addr);
4890Sstevel@tonic-gate 				return (DCMD_ERR);
4900Sstevel@tonic-gate 			}
4910Sstevel@tonic-gate 			mdb_printf("%0p%s", te.ep, te.next == NULL ? "" : " ");
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate 		mdb_printf(")");
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 	mdb_printf("\n");
4960Sstevel@tonic-gate 	mdb_dec_indent(24);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	return (DCMD_OK);
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate static void
nca_timer_help(void)5020Sstevel@tonic-gate nca_timer_help(void)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate 	mdb_printf("Print the core information for one or all NCA timer\n");
5050Sstevel@tonic-gate 	mdb_printf("lists.  If no timer list is given, then all timer lists\n");
5060Sstevel@tonic-gate 	mdb_printf("are shown.  For each timer list, the list of timers to\n");
5070Sstevel@tonic-gate 	mdb_printf("fire on that list are shown, the first in absolute\n");
5080Sstevel@tonic-gate 	mdb_printf("ticks and the rest in ticks relative to the first.\n\n");
5090Sstevel@tonic-gate 	mdb_printf("Options:\n");
5100Sstevel@tonic-gate 	mdb_printf("\t-e\tshow the encapsulating pointer for each event ");
5110Sstevel@tonic-gate 	mdb_printf("at each fire time\n");
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate /*
5150Sstevel@tonic-gate  * Print the core fields in an NCA node_t.  With the "-r" argument,
5160Sstevel@tonic-gate  * provide additional information about the request; with "-v",
5170Sstevel@tonic-gate  * provide more verbose output.
5180Sstevel@tonic-gate  */
5190Sstevel@tonic-gate static int
nca_node(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5200Sstevel@tonic-gate nca_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate 	unsigned int	i, max;
5230Sstevel@tonic-gate 	unsigned int	verbose = FALSE;
5240Sstevel@tonic-gate 	unsigned int	request = FALSE;
5250Sstevel@tonic-gate 	const int	NODE_REFDELT = NCA_ADDR_WIDTH + 4 + 2;
5260Sstevel@tonic-gate 	boolean_t	arm;
5270Sstevel@tonic-gate 	node_t		node;
5280Sstevel@tonic-gate 	char		*buf;
5290Sstevel@tonic-gate 	namedmem_t	hdr[4];
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
5320Sstevel@tonic-gate 		return (DCMD_USAGE);
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose,
535*11066Srafael.vanoni@sun.com 	    'r', MDB_OPT_SETBITS, TRUE, &request, 'p', NULL) != argc)
5360Sstevel@tonic-gate 		return (DCMD_USAGE);
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	if (!DCMD_HDRSPEC(flags) && verbose)
5390Sstevel@tonic-gate 		mdb_printf("\n\n");
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) || verbose) {
5420Sstevel@tonic-gate 		mdb_printf("%<u>%-*s %4s %5s %8s %-*s %-*s %-*s %-*s%</u>\n",
543*11066Srafael.vanoni@sun.com 		    NCA_ADDR_WIDTH, "ADDR", "REF", "STATE", "DATASIZE",
544*11066Srafael.vanoni@sun.com 		    NCA_ADDR_WIDTH, "SQUEUE", NCA_ADDR_WIDTH, "REQUEST",
545*11066Srafael.vanoni@sun.com 		    NCA_ADDR_WIDTH, "PLRUN", NCA_ADDR_WIDTH, "VLRUN");
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if (mdb_vread(&node, sizeof (node_t), addr) == -1) {
5490Sstevel@tonic-gate 		mdb_warn("cannot read node_t at %p", addr);
5500Sstevel@tonic-gate 		return (DCMD_ERR);
5510Sstevel@tonic-gate 	}
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	mdb_printf("%0*p %4d %05x %8d %0*p %0*p %0*p %0*p\n",
5540Sstevel@tonic-gate 	    NCA_ADDR_WIDTH, addr, node.cnt, node.ref,
5550Sstevel@tonic-gate 	    node.datasz, NCA_ADDR_WIDTH, node.sqp, NCA_ADDR_WIDTH,
5560Sstevel@tonic-gate 	    node.req, NCA_ADDR_WIDTH, node.plrunn, NCA_ADDR_WIDTH, node.vlrunn);
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	if (verbose) {
5590Sstevel@tonic-gate 		arm = B_TRUE;
5600Sstevel@tonic-gate 		for (i = 0; node_refs[i].bit_name != NULL; i++) {
5610Sstevel@tonic-gate 			if ((node.ref & (1 << i)) == 0)
5620Sstevel@tonic-gate 				continue;
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 			if (arm) {
5650Sstevel@tonic-gate 				mdb_printf("%*s|\n", NODE_REFDELT, "");
5660Sstevel@tonic-gate 				mdb_printf("%*s+-->  ", NODE_REFDELT, "");
5670Sstevel@tonic-gate 				arm = B_FALSE;
5680Sstevel@tonic-gate 			} else
5690Sstevel@tonic-gate 				mdb_printf("%*s      ", NODE_REFDELT, "");
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 			mdb_printf("%-12s %s\n", node_refs[i].bit_name,
5720Sstevel@tonic-gate 			    node_refs[i].bit_descr);
5730Sstevel@tonic-gate 		}
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	if (!request || node.req == NULL)
5770Sstevel@tonic-gate 		return (DCMD_OK);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	mdb_inc_indent(4);
5800Sstevel@tonic-gate 	mdb_printf("\n%u byte HTTP/%u.%u %s request (%u bytes in header, "
5810Sstevel@tonic-gate 	    "%u in content)\n", node.reqsz, node.version >> 16,
5820Sstevel@tonic-gate 	    node.version & 0xff, method2name(node.method), node.reqhdrsz,
5830Sstevel@tonic-gate 	    node.reqcontl);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	hdr[0].nm_name = "URI";
5860Sstevel@tonic-gate 	hdr[0].nm_addr = (uintptr_t)node.path;
5870Sstevel@tonic-gate 	hdr[0].nm_len  = node.pathsz;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	hdr[1].nm_name = "Accept";
5900Sstevel@tonic-gate 	hdr[1].nm_addr = (uintptr_t)node.reqaccept;
5910Sstevel@tonic-gate 	hdr[1].nm_len  = node.reqacceptsz;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	hdr[2].nm_name = "Accept-Language";
5940Sstevel@tonic-gate 	hdr[2].nm_addr = (uintptr_t)node.reqacceptl;
5950Sstevel@tonic-gate 	hdr[2].nm_len  = node.reqacceptlsz;
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	hdr[3].nm_name = "Host";
5980Sstevel@tonic-gate 	hdr[3].nm_addr = (uintptr_t)node.reqhost;
5990Sstevel@tonic-gate 	hdr[3].nm_len  = node.reqhostsz;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	/*
6020Sstevel@tonic-gate 	 * A little optimization.  Allocate all of the necessary memory here,
6030Sstevel@tonic-gate 	 * so we don't have to allocate on each loop iteration.
6040Sstevel@tonic-gate 	 */
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	max = node.reqhdrsz;
6070Sstevel@tonic-gate 	for (i = 0; i < 4; i++)
6080Sstevel@tonic-gate 		max = MAX(max, hdr[i].nm_len);
6090Sstevel@tonic-gate 	max++;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	buf = mdb_alloc(max, UM_SLEEP);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	mdb_inc_indent(4);
6140Sstevel@tonic-gate 	for (i = 0; i < sizeof (hdr) / sizeof (hdr[0]); i++) {
6150Sstevel@tonic-gate 		if (hdr[i].nm_len <= 0)
6160Sstevel@tonic-gate 			continue;
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 		if (mdb_vread(buf, hdr[i].nm_len, hdr[i].nm_addr) == -1) {
6190Sstevel@tonic-gate 			mdb_warn("cannot read \"%s\" header field at %p",
6200Sstevel@tonic-gate 			    hdr[i].nm_name, hdr[i].nm_addr);
6210Sstevel@tonic-gate 			continue;
6220Sstevel@tonic-gate 		}
6230Sstevel@tonic-gate 		buf[hdr[i].nm_len] = '\0';
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 		mdb_printf("%s: ", hdr[i].nm_name);
6260Sstevel@tonic-gate 		mdb_inc_indent(4);
6270Sstevel@tonic-gate 		mdb_printf("%s\n", buf);
6280Sstevel@tonic-gate 		mdb_dec_indent(4);
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (node.reqhdrsz > 0 && verbose) {
6320Sstevel@tonic-gate 		if (mdb_vread(buf, node.reqhdrsz, (uintptr_t)node.reqhdr) == -1)
6330Sstevel@tonic-gate 			mdb_warn("cannot read header at %p", node.reqhdr);
6340Sstevel@tonic-gate 		else {
6350Sstevel@tonic-gate 			mdb_printf("Raw header: ");
6360Sstevel@tonic-gate 			mdb_inc_indent(4);
6370Sstevel@tonic-gate 			printbuf((uint8_t *)buf, node.reqhdrsz);
6380Sstevel@tonic-gate 			mdb_dec_indent(4);
6390Sstevel@tonic-gate 		}
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate 	mdb_dec_indent(4);
6420Sstevel@tonic-gate 	mdb_dec_indent(4);
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	mdb_free(buf, max);
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	return (DCMD_OK);
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate static void
nca_node_help(void)6500Sstevel@tonic-gate nca_node_help(void)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate 	mdb_printf("Print the core information for a given NCA node_t.\n\n");
6530Sstevel@tonic-gate 	mdb_printf("Options:\n");
6540Sstevel@tonic-gate 	mdb_printf("\t-r\tdisplay HTTP request information\n");
6550Sstevel@tonic-gate 	mdb_printf("\t-v\tbe verbose (more descriptive)\n");
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate /*
6590Sstevel@tonic-gate  * Print the core fields in an NCA nca_conn_t.  With the "-t" argument, skip
6600Sstevel@tonic-gate  * all nca_conn_t's that are in the TIME_WAIT state.  With the "-x" argument,
6610Sstevel@tonic-gate  * show the xmit data.
6620Sstevel@tonic-gate  */
6630Sstevel@tonic-gate static int
nca_conn(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6640Sstevel@tonic-gate nca_conn(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6650Sstevel@tonic-gate {
6660Sstevel@tonic-gate 	unsigned int	i;
6670Sstevel@tonic-gate 	nca_conn_t 		conn;
6680Sstevel@tonic-gate 	unsigned int	show_timewait = TRUE;
6690Sstevel@tonic-gate 	unsigned int	show_xmit = FALSE;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
6720Sstevel@tonic-gate 		return (DCMD_USAGE);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 'x', MDB_OPT_SETBITS, TRUE, &show_xmit,
6750Sstevel@tonic-gate 	    't', MDB_OPT_CLRBITS, TRUE, &show_timewait, NULL) != argc)
6760Sstevel@tonic-gate 		return (DCMD_USAGE);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
6790Sstevel@tonic-gate 		mdb_printf("%<u>%-*s %3s %8s %15s %15s %-*s %-10s%</u>\n",
6800Sstevel@tonic-gate 		    NCA_ADDR_WIDTH, "ADDR", "REF", "CREATE", "LOCAL_ADDR",
6810Sstevel@tonic-gate 		    "REMOTE_ADDR", NCA_ADDR_WIDTH,  "NODE", "STATE");
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	if (mdb_vread(&conn, sizeof (nca_conn_t), addr) == -1) {
6850Sstevel@tonic-gate 		mdb_warn("cannot read nca_conn_t at %p", addr);
6860Sstevel@tonic-gate 		return (DCMD_ERR);
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (!show_timewait && conn.tcp_state == TCPS_TIME_WAIT)
6900Sstevel@tonic-gate 		return (DCMD_OK);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	mdb_printf("%0*p %3d %8lx %15I %15I %0*p %s\n", NCA_ADDR_WIDTH, addr,
6930Sstevel@tonic-gate 	    conn.ref, conn.create, conn.laddr, conn.faddr, NCA_ADDR_WIDTH,
6940Sstevel@tonic-gate 	    conn.req_np, state2name(conn.tcp_state));
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	if (show_xmit) {
6970Sstevel@tonic-gate 		mdb_inc_indent(4);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 		for (i = 0; i < TCP_XMIT_MAX_IX; i++) {
7000Sstevel@tonic-gate 			mdb_printf("xmit[%d]\n", i);
7010Sstevel@tonic-gate 			mdb_printf("\tref pointer\t\t%p\n", conn.xmit[i].np);
7020Sstevel@tonic-gate 			mdb_printf("\tdata pointer\t\t%p\n", conn.xmit[i].dp);
7030Sstevel@tonic-gate 			mdb_printf("\tcksum array\t\t%p\n", conn.xmit[i].cp);
7040Sstevel@tonic-gate 			mdb_printf("\tremaining xmit data\t%d\n",
7050Sstevel@tonic-gate 			    conn.xmit[i].sz);
7060Sstevel@tonic-gate 			mdb_printf("\tref to node_t\t\t%p\n",
7070Sstevel@tonic-gate 			    conn.xmit[i].refed);
7080Sstevel@tonic-gate 			mdb_printf("\tremaining segment data\t%d\n",
7090Sstevel@tonic-gate 			    conn.xmit[i].dsz);
7100Sstevel@tonic-gate 			mdb_printf("\tvirtual pointer\t\t%p\n",
7110Sstevel@tonic-gate 			    conn.xmit[i].dvp);
7120Sstevel@tonic-gate 		}
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 		mdb_dec_indent(4);
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	return (DCMD_OK);
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate static void
nca_conn_help(void)7210Sstevel@tonic-gate nca_conn_help(void)
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate 	mdb_printf("Print the core information for a given NCA "
7240Sstevel@tonic-gate 	    "nca_conn_t.\n\n");
7250Sstevel@tonic-gate 	mdb_printf("Options:\n");
7260Sstevel@tonic-gate 	mdb_printf("\t-t\tskip connections in the TIME_WAIT state\n");
7270Sstevel@tonic-gate 	mdb_printf("\t-x\tshow TCP XMIT information\n");
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate /*
7310Sstevel@tonic-gate  * Print the core TCP-related fields in an NCA nca_conn_t.  With the "-t"
7320Sstevel@tonic-gate  * argument, skips all nca_conn_t's that are in the TIME_WAIT state.
7330Sstevel@tonic-gate  */
7340Sstevel@tonic-gate static int
nca_tcpconn(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)7350Sstevel@tonic-gate nca_tcpconn(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7360Sstevel@tonic-gate {
7370Sstevel@tonic-gate 	nca_conn_t		conn;
7380Sstevel@tonic-gate 	unsigned int	show_timewait = TRUE;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
7410Sstevel@tonic-gate 		return (DCMD_USAGE);
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 't', MDB_OPT_CLRBITS, TRUE, &show_timewait,
7440Sstevel@tonic-gate 	    NULL) != argc)
7450Sstevel@tonic-gate 		return (DCMD_USAGE);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
7480Sstevel@tonic-gate 		mdb_printf("%<u>%-*s %21s %5s %8s %5s %8s %5s %-9s%</u>\n",
7490Sstevel@tonic-gate 		    NCA_ADDR_WIDTH, "ADDR", "REMOTE_ADDR", "SWIND", "SUNASEQ",
7500Sstevel@tonic-gate 		    "SNSEQ", "RACKSEQ", "RNSEQ", "STATE");
7510Sstevel@tonic-gate 	}
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	if (mdb_vread(&conn, sizeof (nca_conn_t), addr) == -1) {
7540Sstevel@tonic-gate 		mdb_warn("cannot read nca_conn_t at %p", addr);
7550Sstevel@tonic-gate 		return (DCMD_ERR);
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	if (!show_timewait && conn.tcp_state == TCPS_TIME_WAIT)
7590Sstevel@tonic-gate 		return (DCMD_OK);
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	mdb_nhconvert(&conn.conn_fport, &conn.conn_fport, sizeof (in_port_t));
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	mdb_printf("%0*p %15I:%05hu %5u %08x %+5d %08x %+5d %-9s\n",
7640Sstevel@tonic-gate 	    NCA_ADDR_WIDTH, addr, conn.faddr, conn.conn_fport, conn.tcp_swnd,
7650Sstevel@tonic-gate 	    conn.tcp_suna, conn.tcp_snxt - conn.tcp_suna, conn.tcp_rack,
7660Sstevel@tonic-gate 	    conn.tcp_rnxt - conn.tcp_rack, state2name(conn.tcp_state));
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	return (DCMD_OK);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate static void
nca_tcpconn_help(void)7720Sstevel@tonic-gate nca_tcpconn_help(void)
7730Sstevel@tonic-gate {
7740Sstevel@tonic-gate 	mdb_printf("Print the core TCP-related information for a given ");
7750Sstevel@tonic-gate 	mdb_printf("NCA nca_conn_t.\n\n");
7760Sstevel@tonic-gate 	mdb_printf("Options:\n");
7770Sstevel@tonic-gate 	mdb_printf("\t-t\tskip connections in the TIME_WAIT state\n");
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate /*
7810Sstevel@tonic-gate  * Initialize a walk for the NCA connection fanout table.  Note that
7820Sstevel@tonic-gate  * local walks are not supported since they're more trouble than
7830Sstevel@tonic-gate  * they're worth.
7840Sstevel@tonic-gate  */
7850Sstevel@tonic-gate static int
nca_connf_walk_init(mdb_walk_state_t * wsp)7860Sstevel@tonic-gate nca_connf_walk_init(mdb_walk_state_t *wsp)
7870Sstevel@tonic-gate {
7880Sstevel@tonic-gate 	int	fanout_size;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	if (wsp->walk_addr != 0) {
7910Sstevel@tonic-gate 		mdb_warn("nca_connf_walk does not support local walks\n");
7920Sstevel@tonic-gate 		return (WALK_DONE);
7930Sstevel@tonic-gate 	}
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "nca_conn_fanout") == -1) {
7960Sstevel@tonic-gate 		mdb_warn("cannot read symbol nca_conn_fanout");
7970Sstevel@tonic-gate 		return (WALK_ERR);
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (mdb_readvar(&fanout_size, "nca_conn_fanout_size") == -1) {
8010Sstevel@tonic-gate 		mdb_warn("cannot read symbol nca_conn_fanout_size");
8020Sstevel@tonic-gate 		return (WALK_ERR);
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	wsp->walk_data = (void *)(uintptr_t)fanout_size;
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	return (WALK_NEXT);
8080Sstevel@tonic-gate }
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate /*
8110Sstevel@tonic-gate  * Walk the NCA connection fanout table; `wsp->walk_data' is used to keep
8120Sstevel@tonic-gate  * track of the number of indicies that are left to walk so we know when
8130Sstevel@tonic-gate  * to stop.
8140Sstevel@tonic-gate  */
8150Sstevel@tonic-gate static int
nca_connf_walk_step(mdb_walk_state_t * wsp)8160Sstevel@tonic-gate nca_connf_walk_step(mdb_walk_state_t *wsp)
8170Sstevel@tonic-gate {
8180Sstevel@tonic-gate 	connf_t		connf;
8190Sstevel@tonic-gate 	nca_conn_t		conn;
8200Sstevel@tonic-gate 	int		status;
8210Sstevel@tonic-gate 	intptr_t	i = (intptr_t)wsp->walk_data;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	if (i-- <= 0)
8240Sstevel@tonic-gate 		return (WALK_DONE);
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	if (mdb_vread(&connf, sizeof (connf_t), wsp->walk_addr) == -1) {
8270Sstevel@tonic-gate 		mdb_warn("cannot read connf_t at %p", wsp->walk_addr);
8280Sstevel@tonic-gate 		return (WALK_ERR);
8290Sstevel@tonic-gate 	}
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	/*
8320Sstevel@tonic-gate 	 * No point in walking the fanout if there are no
8330Sstevel@tonic-gate 	 * connections in it.
8340Sstevel@tonic-gate 	 */
8350Sstevel@tonic-gate 	if (connf.head != NULL) {
8360Sstevel@tonic-gate 		/*
8370Sstevel@tonic-gate 		 * Point to the nca_conn_t instead of the connf_t so that output
8380Sstevel@tonic-gate 		 * can be piped to ::nca_conn dcmd.
8390Sstevel@tonic-gate 		 */
8400Sstevel@tonic-gate 		if (mdb_vread(&conn, sizeof (nca_conn_t),
8410Sstevel@tonic-gate 		    (uintptr_t)connf.head) == -1) {
8420Sstevel@tonic-gate 			mdb_warn("cannot read nca_conn_t at %p", connf.head);
8430Sstevel@tonic-gate 			return (WALK_ERR);
8440Sstevel@tonic-gate 		}
8450Sstevel@tonic-gate 		status = wsp->walk_callback((uintptr_t)connf.head, &conn,
8460Sstevel@tonic-gate 		    wsp->walk_cbdata);
8470Sstevel@tonic-gate 	} else {
8480Sstevel@tonic-gate 		status = WALK_NEXT;
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	wsp->walk_data = (void *)i;
8520Sstevel@tonic-gate 	wsp->walk_addr += sizeof (connf_t);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	return (status);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate /*
8580Sstevel@tonic-gate  * Initialize a walk for the NCA node fanout tables.  Note that local
8590Sstevel@tonic-gate  * walks are not supported since they're more trouble than they're
8600Sstevel@tonic-gate  * worth.
8610Sstevel@tonic-gate  */
8620Sstevel@tonic-gate static int
nca_nodef_walk_init(mdb_walk_state_t * wsp)8630Sstevel@tonic-gate nca_nodef_walk_init(mdb_walk_state_t *wsp)
8640Sstevel@tonic-gate {
8650Sstevel@tonic-gate 	char		varname[256];
8660Sstevel@tonic-gate 	uint32_t	size;
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	if (wsp->walk_addr != 0) {
8690Sstevel@tonic-gate 		mdb_warn("nca_nodef_walk does not support local walks\n");
8700Sstevel@tonic-gate 		return (WALK_DONE);
8710Sstevel@tonic-gate 	}
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, wsp->walk_arg) == -1) {
8740Sstevel@tonic-gate 		mdb_warn("cannot read symbol %s", wsp->walk_arg);
8750Sstevel@tonic-gate 		return (WALK_ERR);
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	mdb_snprintf(varname, sizeof (varname), "%s_sz", wsp->walk_arg);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	if (mdb_readvar(&size, varname) == -1) {
8810Sstevel@tonic-gate 		mdb_warn("cannot read symbol %s", varname);
8820Sstevel@tonic-gate 		return (WALK_ERR);
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	wsp->walk_data = (void *)(uintptr_t)size;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	return (WALK_NEXT);
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate /*
8910Sstevel@tonic-gate  * Walk the NCA node fanout table; `wsp->walk_data' is used to keep
8920Sstevel@tonic-gate  * track of the number of indicies that are left to walk so we know
8930Sstevel@tonic-gate  * when to stop.
8940Sstevel@tonic-gate  */
8950Sstevel@tonic-gate static int
nca_nodef_walk_step(mdb_walk_state_t * wsp)8960Sstevel@tonic-gate nca_nodef_walk_step(mdb_walk_state_t *wsp)
8970Sstevel@tonic-gate {
8980Sstevel@tonic-gate 	nodef_t		nodef;
8990Sstevel@tonic-gate 	node_t		node;
9000Sstevel@tonic-gate 	int		status;
9010Sstevel@tonic-gate 	intptr_t	i = (intptr_t)wsp->walk_data;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	if (i-- <= 0)
9040Sstevel@tonic-gate 		return (WALK_DONE);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	if (mdb_vread(&nodef, sizeof (nodef_t), wsp->walk_addr) == -1) {
9070Sstevel@tonic-gate 		mdb_warn("cannot read nodef_t at %p", wsp->walk_addr);
9080Sstevel@tonic-gate 		return (WALK_ERR);
9090Sstevel@tonic-gate 	}
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &nodef, wsp->walk_cbdata);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	wsp->walk_data = (void *)i;
9140Sstevel@tonic-gate 	wsp->walk_addr += sizeof (nodef_t);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	if (nodef.head != NULL) {
9170Sstevel@tonic-gate 		/*
9180Sstevel@tonic-gate 		 * Point to the node_t instead of the nodef_t so that output
9190Sstevel@tonic-gate 		 * can be piped to ::nca_node dcmd.
9200Sstevel@tonic-gate 		 */
9210Sstevel@tonic-gate 		if (mdb_vread(&node, sizeof (node),
9220Sstevel@tonic-gate 		    (uintptr_t)nodef.head) == -1) {
9230Sstevel@tonic-gate 			mdb_warn("cannot read node_t at %p", nodef.head);
9240Sstevel@tonic-gate 			return (WALK_ERR);
9250Sstevel@tonic-gate 		}
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 		status = wsp->walk_callback((uintptr_t)nodef.head,
9280Sstevel@tonic-gate 		    &node, wsp->walk_cbdata);
9290Sstevel@tonic-gate 	} else {
9300Sstevel@tonic-gate 		status = WALK_NEXT;
9310Sstevel@tonic-gate 	}
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	return (status);
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate  * Initialize a walk for the NCA CPU table.  Note that local walks
9380Sstevel@tonic-gate  * are not supported since they're more trouble than they're worth.
9390Sstevel@tonic-gate  */
9400Sstevel@tonic-gate static int
nca_cpu_walk_init(mdb_walk_state_t * wsp)9410Sstevel@tonic-gate nca_cpu_walk_init(mdb_walk_state_t *wsp)
9420Sstevel@tonic-gate {
9430Sstevel@tonic-gate 	int	ncpus;
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	if (wsp->walk_addr != 0) {
9460Sstevel@tonic-gate 		mdb_warn("nca_cpu_walk does not support local walks\n");
9470Sstevel@tonic-gate 		return (WALK_DONE);
9480Sstevel@tonic-gate 	}
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "nca_gv") == -1) {
9510Sstevel@tonic-gate 		mdb_warn("cannot read symbol nca_gv");
9520Sstevel@tonic-gate 		return (WALK_ERR);
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	if (mdb_readvar(&ncpus, "ncpus") == -1) {
9560Sstevel@tonic-gate 		mdb_warn("cannot read symbol ncpus");
9570Sstevel@tonic-gate 		return (WALK_ERR);
9580Sstevel@tonic-gate 	}
9590Sstevel@tonic-gate 	wsp->walk_data = (void *)(uintptr_t)ncpus;
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	return (WALK_NEXT);
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate /*
9650Sstevel@tonic-gate  * Walk the NCA CPU table; `wsp->walk_data' is used to keep track of the
9660Sstevel@tonic-gate  * number of CPUs that are left to walk so we know when to stop.
9670Sstevel@tonic-gate  */
9680Sstevel@tonic-gate static int
nca_cpu_walk_step(mdb_walk_state_t * wsp)9690Sstevel@tonic-gate nca_cpu_walk_step(mdb_walk_state_t *wsp)
9700Sstevel@tonic-gate {
9710Sstevel@tonic-gate 	nca_cpu_t	cpu;
9720Sstevel@tonic-gate 	int		status;
9730Sstevel@tonic-gate 	intptr_t	curcpu = (intptr_t)wsp->walk_data;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	if (curcpu-- <= 0)
9760Sstevel@tonic-gate 		return (WALK_DONE);
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	if (mdb_vread(&cpu, sizeof (nca_cpu_t), wsp->walk_addr) == -1) {
9790Sstevel@tonic-gate 		mdb_warn("cannot read nca_cpu_t at %p", wsp->walk_addr);
9800Sstevel@tonic-gate 		return (WALK_ERR);
9810Sstevel@tonic-gate 	}
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &cpu, wsp->walk_cbdata);
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	wsp->walk_data = (void *)curcpu;
9860Sstevel@tonic-gate 	wsp->walk_addr += sizeof (nca_cpu_t);
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	return (status);
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate /*
9920Sstevel@tonic-gate  * Initialize a walk for the NCA timer list.  Note that local walks
9930Sstevel@tonic-gate  * are not supported since this walk is layered on top of "nca_cpu"
9940Sstevel@tonic-gate  * which doesn't support them (and they're not too useful here anyway).
9950Sstevel@tonic-gate  */
9960Sstevel@tonic-gate static int
nca_timer_walk_init(mdb_walk_state_t * wsp)9970Sstevel@tonic-gate nca_timer_walk_init(mdb_walk_state_t *wsp)
9980Sstevel@tonic-gate {
9990Sstevel@tonic-gate 	if (wsp->walk_addr != 0) {
10000Sstevel@tonic-gate 		mdb_warn("nca_timer_walk does not support local walks\n");
10010Sstevel@tonic-gate 		return (WALK_DONE);
10020Sstevel@tonic-gate 	}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	if (mdb_layered_walk("nca_cpu", wsp) == -1) {
10050Sstevel@tonic-gate 		mdb_warn("cannot walk nca_cpu");
10060Sstevel@tonic-gate 		return (WALK_ERR);
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	return (WALK_NEXT);
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate /*
10130Sstevel@tonic-gate  * Walk the NCA timer list; done as a layered walk on top of "nca_cpu".
10140Sstevel@tonic-gate  */
10150Sstevel@tonic-gate static int
nca_timer_walk_step(mdb_walk_state_t * wsp)10160Sstevel@tonic-gate nca_timer_walk_step(mdb_walk_state_t *wsp)
10170Sstevel@tonic-gate {
10180Sstevel@tonic-gate 	const nca_cpu_t	*nca_cpu = wsp->walk_layer;
10190Sstevel@tonic-gate 	ti_t		ti;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	/*
10220Sstevel@tonic-gate 	 * Just skip CPUs that don't have any timers running.
10230Sstevel@tonic-gate 	 */
10240Sstevel@tonic-gate 	if (nca_cpu->tcp_ti == NULL)
10250Sstevel@tonic-gate 		return (WALK_NEXT);
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	if (mdb_vread(&ti, sizeof (ti_t), (uintptr_t)nca_cpu->tcp_ti) == -1) {
10280Sstevel@tonic-gate 		mdb_warn("cannot read ti_t at %p", nca_cpu->tcp_ti);
10290Sstevel@tonic-gate 		return (WALK_ERR);
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	return (wsp->walk_callback((uintptr_t)nca_cpu->tcp_ti, &ti,
10330Sstevel@tonic-gate 	    wsp->walk_cbdata));
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate /*
10370Sstevel@tonic-gate  * Initialize a walk for NCA node LRUs; the type of LRU to walk should
10380Sstevel@tonic-gate  * be specified through `wsp->walk_arg'.  If no starting location for
10390Sstevel@tonic-gate  * the walk is given, `wsp->walk_addr' is set to the head of the
10400Sstevel@tonic-gate  * appropriate LRU.
10410Sstevel@tonic-gate  */
10420Sstevel@tonic-gate static int
nca_node_lru_walk_init(mdb_walk_state_t * wsp)10430Sstevel@tonic-gate nca_node_lru_walk_init(mdb_walk_state_t *wsp)
10440Sstevel@tonic-gate {
10450Sstevel@tonic-gate 	GElf_Sym	sym;
10460Sstevel@tonic-gate 	lru_t		lru;
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	if (wsp->walk_addr != 0)
10490Sstevel@tonic-gate 		return (WALK_NEXT);
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/*
10520Sstevel@tonic-gate 	 * We do this instead of mdb_readvar() so that we catch changes
10530Sstevel@tonic-gate 	 * in the size of the lru_t structure.
10540Sstevel@tonic-gate 	 */
10550Sstevel@tonic-gate 	if (mdb_lookup_by_name("nca_lru", &sym) == -1) {
10560Sstevel@tonic-gate 		mdb_warn("cannot lookup symbol nca_lru");
10570Sstevel@tonic-gate 		return (WALK_ERR);
10580Sstevel@tonic-gate 	}
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	if (sym.st_size != sizeof (lru)) {
10610Sstevel@tonic-gate 		mdb_warn("nca_lru object size mismatch\n");
10620Sstevel@tonic-gate 		return (WALK_ERR);
10630Sstevel@tonic-gate 	}
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	if (mdb_vread(&lru, sym.st_size, (uintptr_t)sym.st_value) == -1) {
10660Sstevel@tonic-gate 		mdb_warn("cannot read nca_lru at %p", sym.st_value);
10670Sstevel@tonic-gate 		return (WALK_ERR);
10680Sstevel@tonic-gate 	}
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	if (wsp->walk_arg == NCA_WALK_PLRU)
10710Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)lru.phead;
10720Sstevel@tonic-gate 	else
10730Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)lru.vhead;
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	return (WALK_NEXT);
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate /*
10790Sstevel@tonic-gate  * Walk the NCA node LRUs; the type of LRU to walk should be specified
10800Sstevel@tonic-gate  * through `wsp->walk_arg'.
10810Sstevel@tonic-gate  */
10820Sstevel@tonic-gate static int
nca_node_lru_walk_step(mdb_walk_state_t * wsp)10830Sstevel@tonic-gate nca_node_lru_walk_step(mdb_walk_state_t *wsp)
10840Sstevel@tonic-gate {
10850Sstevel@tonic-gate 	node_t		node;
10860Sstevel@tonic-gate 	int		status;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	if (wsp->walk_addr == 0)
10890Sstevel@tonic-gate 		return (WALK_DONE);
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	if (mdb_vread(&node, sizeof (node_t), wsp->walk_addr) == -1) {
10920Sstevel@tonic-gate 		mdb_warn("cannot read node_t at %p", wsp->walk_addr);
10930Sstevel@tonic-gate 		return (WALK_ERR);
10940Sstevel@tonic-gate 	}
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &node, wsp->walk_cbdata);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	if (wsp->walk_arg == NCA_WALK_PLRU)
10990Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)node.plrunn;
11000Sstevel@tonic-gate 	else
11010Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)node.vlrunn;
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	return (status);
11040Sstevel@tonic-gate }
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate /*
11070Sstevel@tonic-gate  * Walk the NCA node structures; follows node_t next pointers from a
11080Sstevel@tonic-gate  * given offset, specified through `wsp->walk_arg'.
11090Sstevel@tonic-gate  */
11100Sstevel@tonic-gate static int
nca_node_walk_step(mdb_walk_state_t * wsp)11110Sstevel@tonic-gate nca_node_walk_step(mdb_walk_state_t *wsp)
11120Sstevel@tonic-gate {
11130Sstevel@tonic-gate 	node_t		node;
11140Sstevel@tonic-gate 	int		status;
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
11170Sstevel@tonic-gate 		mdb_warn("nca_node_walk does not support global walks\n");
11180Sstevel@tonic-gate 		return (WALK_DONE);
11190Sstevel@tonic-gate 	}
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	if (mdb_vread(&node, sizeof (node_t), wsp->walk_addr) == -1) {
11220Sstevel@tonic-gate 		mdb_warn("cannot read node_t at %p", wsp->walk_addr);
11230Sstevel@tonic-gate 		return (WALK_ERR);
11240Sstevel@tonic-gate 	}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &node, wsp->walk_cbdata);
11270Sstevel@tonic-gate 	if (status != WALK_NEXT)
11280Sstevel@tonic-gate 		return (status);
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	/* LINTED */
11310Sstevel@tonic-gate 	wsp->walk_addr = *(uintptr_t *)((caddr_t)&node +
11320Sstevel@tonic-gate 	    (uint_t)(uintptr_t)wsp->walk_arg);
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	if (wsp->walk_addr == 0)
11350Sstevel@tonic-gate 		return (WALK_DONE);
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	return (WALK_NEXT);
11380Sstevel@tonic-gate }
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate /*
11410Sstevel@tonic-gate  * Walk the NCA connection structures; follows nca_conn_t next pointers
11420Sstevel@tonic-gate  * from a given offset, specified through `wsp->walk_arg'.
11430Sstevel@tonic-gate  */
11440Sstevel@tonic-gate static int
nca_conn_walk_step(mdb_walk_state_t * wsp)11450Sstevel@tonic-gate nca_conn_walk_step(mdb_walk_state_t *wsp)
11460Sstevel@tonic-gate {
11470Sstevel@tonic-gate 	nca_conn_t		conn;
11480Sstevel@tonic-gate 	int		status;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
11510Sstevel@tonic-gate 		mdb_warn("nca_conn_walk does not support global walks\n");
11520Sstevel@tonic-gate 		return (WALK_DONE);
11530Sstevel@tonic-gate 	}
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	if (mdb_vread(&conn, sizeof (nca_conn_t), wsp->walk_addr) == -1) {
11560Sstevel@tonic-gate 		mdb_warn("cannot read nca_conn_t at %p", wsp->walk_addr);
11570Sstevel@tonic-gate 		return (WALK_ERR);
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, &conn, wsp->walk_cbdata);
11610Sstevel@tonic-gate 	if (status != WALK_NEXT)
11620Sstevel@tonic-gate 		return (status);
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	/* LINTED */
11650Sstevel@tonic-gate 	wsp->walk_addr = *(uintptr_t *)((caddr_t)&conn +
11660Sstevel@tonic-gate 	    (uint_t)(uintptr_t)wsp->walk_arg);
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	if (wsp->walk_addr == 0)
11690Sstevel@tonic-gate 		return (WALK_DONE);
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	return (WALK_NEXT);
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
11750Sstevel@tonic-gate 	{ "nca_conn",	":[-tx]", "print core NCA nca_conn_t info",   nca_conn,
11760Sstevel@tonic-gate 	    nca_conn_help },
11770Sstevel@tonic-gate 	{ "nca_tcpconn", ":[-t]", "print TCP NCA nca_conn_t info",
11780Sstevel@tonic-gate 	    nca_tcpconn, nca_tcpconn_help },
11790Sstevel@tonic-gate 	{ "nca_io2",	":[-pv]", "print core NCA io2_t info",    nca_io2,
11800Sstevel@tonic-gate 	    nca_io2_help },
11810Sstevel@tonic-gate 	{ "nca_node",	":[-rv]", "print core NCA node_t info",   nca_node,
11820Sstevel@tonic-gate 	    nca_node_help },
11830Sstevel@tonic-gate 	{ "nca_timer",	"?[-e]",  "print core NCA timer info",    nca_timer,
11840Sstevel@tonic-gate 	    nca_timer_help },
11850Sstevel@tonic-gate 	{ NULL }
11860Sstevel@tonic-gate };
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
11890Sstevel@tonic-gate 	{ "nca_conn_hash",	"walk the NCA connection hash chain", 0,
11900Sstevel@tonic-gate 	    nca_conn_walk_step, 0, (void *)OFFSETOF(nca_conn_t, hashnext) },
11910Sstevel@tonic-gate 	{ "nca_conn_bind",	"walk the NCA connection bind chain", 0,
11920Sstevel@tonic-gate 	    nca_conn_walk_step, 0, (void *)OFFSETOF(nca_conn_t, bindnext) },
11930Sstevel@tonic-gate 	{ "nca_conn_miss",	"walk the NCA connection miss chain", 0,
11940Sstevel@tonic-gate 	    nca_conn_walk_step, 0, (void *)OFFSETOF(nca_conn_t, nodenext) },
11950Sstevel@tonic-gate 	{ "nca_conn_tw",	"walk the NCA connection TIME_WAIT chain", 0,
11960Sstevel@tonic-gate 	    nca_conn_walk_step, 0, (void *)OFFSETOF(nca_conn_t, twnext) },
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	{ "nca_node_file",	"walk the NCA node file chain", 0,
11990Sstevel@tonic-gate 	    nca_node_walk_step, 0, (void *)OFFSETOF(node_t, filenext) },
12000Sstevel@tonic-gate 	{ "nca_node_hash",	"walk the NCA node hash chain", 0,
12010Sstevel@tonic-gate 	    nca_node_walk_step, 0, (void *)OFFSETOF(node_t, hashnext) },
12020Sstevel@tonic-gate 	{ "nca_node_chunk",	"walk the NCA node chunk chain", 0,
12030Sstevel@tonic-gate 	    nca_node_walk_step, 0, (void *)OFFSETOF(node_t, next) },
12040Sstevel@tonic-gate 	{ "nca_node_ctag",	"walk the NCA node ctag chain", 0,
12050Sstevel@tonic-gate 	    nca_node_walk_step, 0, (void *)OFFSETOF(node_t, ctagnext) },
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	{ "nca_node_plru",	"walk the NCA node physical LRU chain",
12080Sstevel@tonic-gate 	    nca_node_lru_walk_init, nca_node_lru_walk_step, 0, NCA_WALK_PLRU },
12090Sstevel@tonic-gate 	{ "nca_node_vlru",	"walk the NCA node virtual LRU chain",
12100Sstevel@tonic-gate 	    nca_node_lru_walk_init, nca_node_lru_walk_step, 0, NCA_WALK_VLRU },
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	{ "nca_uri_hash",	"walk the NCA URI node hash table",
12130Sstevel@tonic-gate 	    nca_nodef_walk_init, nca_nodef_walk_step, 0, "ncaurihash" },
12140Sstevel@tonic-gate 	{ "nca_file_hash",	"walk the NCA file node hash table",
12150Sstevel@tonic-gate 	    nca_nodef_walk_init, nca_nodef_walk_step, 0, "ncafilehash" },
12160Sstevel@tonic-gate 	{ "nca_ctag_hash",	"walk the NCA ctag node hash table",
12170Sstevel@tonic-gate 	    nca_nodef_walk_init, nca_nodef_walk_step, 0, "ncactaghash" },
12180Sstevel@tonic-gate 	{ "nca_vnode_hash",	"walk the NCA vnode node hash table",
12190Sstevel@tonic-gate 	    nca_nodef_walk_init, nca_nodef_walk_step, 0, "ncavnodehash" },
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	{ "nca_cpu",		"walk the NCA CPU table",
12220Sstevel@tonic-gate 	    nca_cpu_walk_init,   nca_cpu_walk_step },
12230Sstevel@tonic-gate 	{ "nca_timer",		"walk the NCA timer table",
12240Sstevel@tonic-gate 	    nca_timer_walk_init, nca_timer_walk_step },
12250Sstevel@tonic-gate 	{ "nca_connf",		"walk the NCA connection fanout",
12260Sstevel@tonic-gate 	    nca_connf_walk_init, nca_connf_walk_step },
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	{ NULL }
12290Sstevel@tonic-gate };
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate const mdb_modinfo_t *
_mdb_init(void)12340Sstevel@tonic-gate _mdb_init(void)
12350Sstevel@tonic-gate {
12360Sstevel@tonic-gate 	return (&modinfo);
12370Sstevel@tonic-gate }
1238