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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
300Sstevel@tonic-gate #include <mdb/mdb_ks.h>
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/strsubr.h>
340Sstevel@tonic-gate #include <sys/stream.h>
350Sstevel@tonic-gate #include <sys/modctl.h>
360Sstevel@tonic-gate #include <sys/strft.h>
370Sstevel@tonic-gate #include <sys/strsun.h>
380Sstevel@tonic-gate #include <sys/sysmacros.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include "streams.h"
410Sstevel@tonic-gate 
420Sstevel@tonic-gate typedef struct str_flags {
430Sstevel@tonic-gate 	uint_t strf_flag;
440Sstevel@tonic-gate 	const char *strf_name;
450Sstevel@tonic-gate 	const char *strf_descr;
460Sstevel@tonic-gate } strflags_t;
470Sstevel@tonic-gate 
480Sstevel@tonic-gate typedef struct str_types {
490Sstevel@tonic-gate 	const char *strt_name;
500Sstevel@tonic-gate 	int strt_value;
510Sstevel@tonic-gate 	const char *strt_descr;
520Sstevel@tonic-gate } strtypes_t;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate typedef struct ftblk_data {
550Sstevel@tonic-gate 	ftblk_t ft_data;	/* Copy of ftblk */
560Sstevel@tonic-gate 	int 	ft_ix;		/* Index in event list */
570Sstevel@tonic-gate 	boolean_t ft_in_evlist;	/* Iterating through evlist */
580Sstevel@tonic-gate } ftblkdata_t;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate typedef void qprint_func(queue_t *, queue_t *);
610Sstevel@tonic-gate typedef void sdprint_func(stdata_t *, stdata_t *);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #define	SF(flag)	flag, #flag
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate  * Queue flags
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate static const strflags_t qf[] = {
690Sstevel@tonic-gate 	{ SF(QENAB), 		"Queue is already enabled to run"	},
700Sstevel@tonic-gate 	{ SF(QWANTR),		"Someone wants to read Q"		},
710Sstevel@tonic-gate 	{ SF(QWANTW),		"Someone wants to write Q"		},
720Sstevel@tonic-gate 	{ SF(QFULL),		"Q is considered full"			},
730Sstevel@tonic-gate 	{ SF(QREADR),		"This is the reader (first) Q"		},
740Sstevel@tonic-gate 	{ SF(QUSE),		"This queue in use (allocation)"	},
750Sstevel@tonic-gate 	{ SF(QNOENB),		"Don't enable Q via putq"		},
760Sstevel@tonic-gate 	{ SF(QWANTRMQSYNC),	"Want to remove sync stream Q"		},
770Sstevel@tonic-gate 	{ SF(QBACK),		"queue has been back-enabled"		},
780Sstevel@tonic-gate 	{ SF(0x00000200),	"unused (was QHLIST)"			},
790Sstevel@tonic-gate 	{ SF(0x00000400),	"unused (was QUNSAFE)"			},
800Sstevel@tonic-gate 	{ SF(QPAIR),		"per queue-pair syncq"			},
810Sstevel@tonic-gate 	{ SF(QPERQ),		"per queue-instance syncq"		},
820Sstevel@tonic-gate 	{ SF(QPERMOD),		"per module syncq"			},
830Sstevel@tonic-gate 	{ SF(QMTSAFE),		"stream module is MT-safe"		},
840Sstevel@tonic-gate 	{ SF(QMTOUTPERIM),	"Has outer perimeter"			},
850Sstevel@tonic-gate 	{ SF(QINSERVICE),	"service routine executing"		},
860Sstevel@tonic-gate 	{ SF(QWCLOSE),		"will not be enabled"			},
870Sstevel@tonic-gate 	{ SF(QEND),		"last queue in stream"			},
880Sstevel@tonic-gate 	{ SF(QWANTWSYNC),	"Streamhead wants to write Q" 		},
890Sstevel@tonic-gate 	{ SF(QSYNCSTR),		"Q supports Synchronous STREAMS"	},
900Sstevel@tonic-gate 	{ SF(QISDRV),		"the Queue is attached to a driver"	},
910Sstevel@tonic-gate 	{ SF(0x00400000),	"unused (was QHOT)"			},
920Sstevel@tonic-gate 	{ SF(0x00800000),	"unused (was QNEXTHOT)"			},
930Sstevel@tonic-gate 	{ SF(0x01000000),	"unused (was _QNEXTLESS)"		},
940Sstevel@tonic-gate 	{ SF(0x02000000),	"unused"				},
950Sstevel@tonic-gate 	{ SF(_QINSERTING),	"module is inserted with _I_INSERT"	},
960Sstevel@tonic-gate 	{ SF(_QREMOVING)	"module is removed with _I_REMOVE"	},
970Sstevel@tonic-gate 	{ SF(_QASSOCIATED),	"queue is associated with a device"	},
98*761Smeem 	{ 0, NULL,		NULL					}
990Sstevel@tonic-gate };
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * Syncq flags
1030Sstevel@tonic-gate  */
1040Sstevel@tonic-gate static const struct str_flags sqf[] = {
1050Sstevel@tonic-gate 	{ SF(SQ_EXCL),		"Exclusive access to inner perimeter"	},
1060Sstevel@tonic-gate 	{ SF(SQ_BLOCKED),	"qprocsoff in progress"			},
1070Sstevel@tonic-gate 	{ SF(SQ_FROZEN),	"freezestr in progress"			},
1080Sstevel@tonic-gate 	{ SF(SQ_WRITER),	"qwriter(OUTER) pending or running"	},
1090Sstevel@tonic-gate 	{ SF(SQ_MESSAGES),	"There are messages on syncq"		},
1100Sstevel@tonic-gate 	{ SF(SQ_WANTWAKEUP)	"Thread waiting on sq_wait"		},
1110Sstevel@tonic-gate 	{ SF(SQ_WANTEXWAKEUP),	"Thread waiting on sq_exwait"		},
1120Sstevel@tonic-gate 	{ SF(SQ_EVENTS),	"There are events on syncq"		},
113*761Smeem 	{ 0, NULL,		NULL					}
1140Sstevel@tonic-gate };
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /*
1170Sstevel@tonic-gate  * Syncq types
1180Sstevel@tonic-gate  */
1190Sstevel@tonic-gate static const struct str_flags sqt[] = {
1200Sstevel@tonic-gate 	{ SF(SQ_CIPUT),		"Concurrent inner put procedure"	},
1210Sstevel@tonic-gate 	{ SF(SQ_CISVC),		"Concurrent inner svc procedure"	},
1220Sstevel@tonic-gate 	{ SF(SQ_CIOC),		"Concurrent inner open/close"		},
1230Sstevel@tonic-gate 	{ SF(SQ_CICB),		"Concurrent inner callback"		},
1240Sstevel@tonic-gate 	{ SF(SQ_COPUT),		"Concurrent outer put procedure"	},
1250Sstevel@tonic-gate 	{ SF(SQ_COSVC),		"Concurrent outer svc procedure"	},
1260Sstevel@tonic-gate 	{ SF(SQ_COOC),		"Concurrent outer open/close"		},
1270Sstevel@tonic-gate 	{ SF(SQ_COCB),		"Concurrent outer callback"		},
128*761Smeem 	{ 0, NULL,		NULL					}
1290Sstevel@tonic-gate };
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /*
1320Sstevel@tonic-gate  * Stdata flags
1330Sstevel@tonic-gate  */
1340Sstevel@tonic-gate static const struct str_flags stdf[] = {
1350Sstevel@tonic-gate 	{ SF(IOCWAIT),		"someone is doing an ioctl"		},
1360Sstevel@tonic-gate 	{ SF(RSLEEP),		"someone wants to read/recv msg"	},
1370Sstevel@tonic-gate 	{ SF(WSLEEP),		"someone wants to write"		},
1380Sstevel@tonic-gate 	{ SF(STRPRI),		"an M_PCPROTO is at stream head"	},
1390Sstevel@tonic-gate 	{ SF(STRHUP),		"device has vanished"			},
1400Sstevel@tonic-gate 	{ SF(STWOPEN),		"waiting for 1st open"			},
1410Sstevel@tonic-gate 	{ SF(STPLEX),		"stream is being multiplexed"		},
1420Sstevel@tonic-gate 	{ SF(STRISTTY),		"stream is a terminal"			},
1430Sstevel@tonic-gate 	{ SF(STRGETINPROG),	"(k)strgetmsg is running"		},
1440Sstevel@tonic-gate 	{ SF(IOCWAITNE),	"STR_NOERROR ioctl running"		},
1450Sstevel@tonic-gate 	{ SF(STRDERR),		"fatal read error from M_ERROR"		},
1460Sstevel@tonic-gate 	{ SF(STWRERR),		"fatal write error from M_ERROR"	},
1470Sstevel@tonic-gate 	{ SF(STRDERRNONPERSIST), "nonpersistent read errors"		},
1480Sstevel@tonic-gate 	{ SF(STWRERRNONPERSIST), "nonpersistent write errors"		},
1490Sstevel@tonic-gate 	{ SF(STRCLOSE),		"wait for a close to complete"		},
1500Sstevel@tonic-gate 	{ SF(SNDMREAD),		"used for read notification"		},
1510Sstevel@tonic-gate 	{ SF(OLDNDELAY),	"use old NDELAY TTY semantics"		},
1520Sstevel@tonic-gate 	{ SF(0x00020000),	"unused"				},
1530Sstevel@tonic-gate 	{ SF(0x00040000),	"unused"				},
1540Sstevel@tonic-gate 	{ SF(STRTOSTOP),	"block background writes"		},
1550Sstevel@tonic-gate 	{ SF(0x00100000),	"unused"				},
1560Sstevel@tonic-gate 	{ SF(0x00200000),	"unused"				},
1570Sstevel@tonic-gate 	{ SF(STRMOUNT),		"stream is mounted"			},
1580Sstevel@tonic-gate 	{ SF(STRNOTATMARK),	"Not at mark (when empty read q)"	},
1590Sstevel@tonic-gate 	{ SF(STRDELIM),		"generate delimited messages"		},
1600Sstevel@tonic-gate 	{ SF(STRATMARK),	"at mark (due to MSGMARKNEXT)"		},
1610Sstevel@tonic-gate 	{ SF(STZCNOTIFY),	"wait for zerocopy mblk to be acked"	},
1620Sstevel@tonic-gate 	{ SF(STRPLUMB),		"stream plumbing changes in progress"	},
1630Sstevel@tonic-gate 	{ SF(STREOF),  		"End-of-file indication"		},
1640Sstevel@tonic-gate 	{ SF(STREOPENFAIL),	"re-open has failed"			},
1650Sstevel@tonic-gate 	{ SF(STRMATE),		"this stream is a mate"			},
1660Sstevel@tonic-gate 	{ SF(STRHASLINKS),	"there are I_LINKs under this stream"	},
167*761Smeem 	{ 0, NULL,		NULL					}
1680Sstevel@tonic-gate };
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate static const struct str_flags mbf[] = {
1710Sstevel@tonic-gate 	{ SF(MSGMARK), 		"last byte of message is marked"	},
1720Sstevel@tonic-gate 	{ SF(MSGNOLOOP),	"don't loop message to write side"	},
1730Sstevel@tonic-gate 	{ SF(MSGDELIM),		"message is delimited"			},
1740Sstevel@tonic-gate 	{ SF(0x08),		"unused"				},
1750Sstevel@tonic-gate 	{ SF(MSGMARKNEXT), 	"Private: b_next's first byte marked"	},
1760Sstevel@tonic-gate 	{ SF(MSGNOTMARKNEXT),	"Private: ... not marked"		},
1770Sstevel@tonic-gate 	{ SF(MSGHASREF),	"Private: msg has reference to owner"	},
178*761Smeem 	{ 0, NULL,		NULL					}
1790Sstevel@tonic-gate };
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate #define	M_DATA_T 0xff
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate static const strtypes_t mbt[] = {
1840Sstevel@tonic-gate 	{ "M_DATA",	M_DATA_T,	"regular data"			},
1850Sstevel@tonic-gate 	{ "M_PROTO",	M_PROTO,	"protocol control"		},
1860Sstevel@tonic-gate 	{ "M_MULTIDATA", M_MULTIDATA,	"multidata"			},
1870Sstevel@tonic-gate 	{ "M_BREAK",	M_BREAK,	"line break"			},
1880Sstevel@tonic-gate 	{ "M_PASSFP",	M_PASSFP,	"pass file pointer"		},
1890Sstevel@tonic-gate 	{ "M_EVENT",	M_EVENT,	"Obsoleted: do not use"		},
1900Sstevel@tonic-gate 	{ "M_SIG",	M_SIG,		"generate process signal"	},
1910Sstevel@tonic-gate 	{ "M_DELAY",	M_DELAY,	"real-time xmit delay"		},
1920Sstevel@tonic-gate 	{ "M_CTL",	M_CTL,		"device-specific control message" },
1930Sstevel@tonic-gate 	{ "M_IOCTL",	M_IOCTL,	"ioctl; set/get params"		},
1940Sstevel@tonic-gate 	{ "M_SETOPTS",	M_SETOPTS,	"set stream head options"	},
1950Sstevel@tonic-gate 	{ "M_RSE",	M_RSE,		"reserved for RSE use only"	},
1960Sstevel@tonic-gate 	{ "M_IOCACK",	M_IOCACK,	"acknowledge ioctl"		},
1970Sstevel@tonic-gate 	{ "M_IOCNAK",	M_IOCNAK,	"negative ioctl acknowledge"	},
1980Sstevel@tonic-gate 	{ "M_PCPROTO",	M_PCPROTO,	"priority proto message"	},
1990Sstevel@tonic-gate 	{ "M_PCSIG",	M_PCSIG,	"generate process signal"	},
2000Sstevel@tonic-gate 	{ "M_READ",	M_READ,		"generate read notification"	},
2010Sstevel@tonic-gate 	{ "M_FLUSH",	M_FLUSH,	"flush your queues"		},
2020Sstevel@tonic-gate 	{ "M_STOP",	M_STOP,		"stop transmission immediately" },
2030Sstevel@tonic-gate 	{ "M_START",	M_START,	"restart transmission after stop" },
2040Sstevel@tonic-gate 	{ "M_HANGUP",	M_HANGUP,	"line disconnect"		},
2050Sstevel@tonic-gate 	{ "M_ERROR",	M_ERROR,	"send error to stream head"	},
2060Sstevel@tonic-gate 	{ "M_COPYIN",	M_COPYIN,	"request to copyin data"	},
2070Sstevel@tonic-gate 	{ "M_COPYOUT",	M_COPYOUT,	"request to copyout data"	},
2080Sstevel@tonic-gate 	{ "M_IOCDATA",	M_IOCDATA,	"response to M_COPYIN and M_COPYOUT" },
2090Sstevel@tonic-gate 	{ "M_PCRSE",	M_PCRSE,	"reserved for RSE use only"	},
2100Sstevel@tonic-gate 	{ "M_STOPI",	M_STOPI,	"stop reception immediately"	},
2110Sstevel@tonic-gate 	{ "M_STARTI",	M_STARTI,	"restart reception after stop"	},
2120Sstevel@tonic-gate 	{ "M_PCEVENT",	M_PCEVENT,	"Obsoleted: do not use"		},
2130Sstevel@tonic-gate 	{ "M_UNHANGUP",	M_UNHANGUP,	"line reconnect"		},
214*761Smeem 	{ NULL,		0,		NULL 				}
2150Sstevel@tonic-gate };
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate /* Allocation flow trace events, starting from 0 */
2180Sstevel@tonic-gate static const char *ftev_alloc[] = {
2190Sstevel@tonic-gate /* 0 */	":allocb",
2200Sstevel@tonic-gate /* 1 */	":esballoc",
2210Sstevel@tonic-gate /* 2 */	":desballoc",
2220Sstevel@tonic-gate /* 3 */	":esballoca",
2230Sstevel@tonic-gate /* 4 */	":desballoca",
2240Sstevel@tonic-gate /* 5 */	":allocbig",
2250Sstevel@tonic-gate /* 6 */	":allocbw",
2260Sstevel@tonic-gate /* 7 */	":bcallocb",
2270Sstevel@tonic-gate /* 8 */	":freeb",
2280Sstevel@tonic-gate /* 9 */	":dupb",
2290Sstevel@tonic-gate /* A */	":copyb",
2300Sstevel@tonic-gate };
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate #define	FTEV_PROC_START FTEV_PUT
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate /* Procedures recorded by flow tracing, starting from 0x100 */
2350Sstevel@tonic-gate static const char *ftev_proc[] = {
2360Sstevel@tonic-gate /* 100 */	":put",
2370Sstevel@tonic-gate /* 101 */	":undefined (0x101)",
2380Sstevel@tonic-gate /* 102 */	":undefined (0x102)",
2390Sstevel@tonic-gate /* 103 */	":undefined (0x103)",
2400Sstevel@tonic-gate /* 104 */	":undefined (0x104)",
2410Sstevel@tonic-gate /* 105 */	":putq",
2420Sstevel@tonic-gate /* 106 */	":getq",
2430Sstevel@tonic-gate /* 107 */	":rmvq",
2440Sstevel@tonic-gate /* 108 */	":insq",
2450Sstevel@tonic-gate /* 109 */	":putbq",
2460Sstevel@tonic-gate /* 10A */	":flushq",
2470Sstevel@tonic-gate /* 10B */	":undefined (0x10b)",
2480Sstevel@tonic-gate /* 10C */ 	":undefined (0x10c)",
2490Sstevel@tonic-gate /* 10D */	":putnext",
2500Sstevel@tonic-gate /* 10E */	":rwnext",
2510Sstevel@tonic-gate };
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate static const char *db_control_types[] = {
2540Sstevel@tonic-gate /* 00 */	"data",
2550Sstevel@tonic-gate /* 01 */	"proto",
2560Sstevel@tonic-gate /* 02 */	"multidata",
2570Sstevel@tonic-gate /* 03 */	"unused (0x03)",
2580Sstevel@tonic-gate /* 04 */	"unused (0x04)",
2590Sstevel@tonic-gate /* 05 */	"unused (0x05)",
2600Sstevel@tonic-gate /* 06 */	"unused (0x06)",
2610Sstevel@tonic-gate /* 07 */	"unused (0x07)",
2620Sstevel@tonic-gate /* 08 */	"break",
2630Sstevel@tonic-gate /* 09 */	"passfp",
2640Sstevel@tonic-gate /* 0a */	"event",
2650Sstevel@tonic-gate /* 0b */	"sig",
2660Sstevel@tonic-gate /* 0c */	"delay",
2670Sstevel@tonic-gate /* 0d */	"ctl",
2680Sstevel@tonic-gate /* 0e */	"ioctl",
2690Sstevel@tonic-gate /* 0f */	"unused",
2700Sstevel@tonic-gate /* 10 */	"setopts",
2710Sstevel@tonic-gate /* 11 */	"rse",
2720Sstevel@tonic-gate };
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate static const char *db_control_hipri_types[] = {
2750Sstevel@tonic-gate /* 81 */	"iocack",
2760Sstevel@tonic-gate /* 82 */	"iocnak",
2770Sstevel@tonic-gate /* 83 */	"pcproto",
2780Sstevel@tonic-gate /* 84 */	"pcsig",
2790Sstevel@tonic-gate /* 85 */	"read",
2800Sstevel@tonic-gate /* 86 */	"flush",
2810Sstevel@tonic-gate /* 87 */	"stop",
2820Sstevel@tonic-gate /* 88 */	"start",
2830Sstevel@tonic-gate /* 89 */	"hangup",
2840Sstevel@tonic-gate /* 8a */	"error",
2850Sstevel@tonic-gate /* 8b */	"copyin",
2860Sstevel@tonic-gate /* 8c */	"copyout",
2870Sstevel@tonic-gate /* 8d */	"iocdata",
2880Sstevel@tonic-gate /* 8e */	"pcrse",
2890Sstevel@tonic-gate /* 8f */	"stopi",
2900Sstevel@tonic-gate /* 90 */	"starti",
2910Sstevel@tonic-gate /* 91 */	"pcevent",
2920Sstevel@tonic-gate /* 92 */	"unhangup",
2930Sstevel@tonic-gate };
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate #define	A_SIZE(a) (sizeof (a) / sizeof (a[0]))
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate static void ft_printevent(ushort_t);
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate static int
3010Sstevel@tonic-gate streams_parse_flag(const strflags_t ftable[], const char *arg, uint32_t *flag)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate 	int i;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	for (i = 0; ftable[i].strf_name != NULL; i++) {
3060Sstevel@tonic-gate 		if (strcasecmp(arg, ftable[i].strf_name) == 0) {
3070Sstevel@tonic-gate 			*flag |= (1 << i);
3080Sstevel@tonic-gate 			return (0);
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	return (-1);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate static void
3160Sstevel@tonic-gate streams_flag_usage(const strflags_t ftable[])
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate 	int i;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	for (i = 0; ftable[i].strf_name != NULL; i++)
3210Sstevel@tonic-gate 		mdb_printf("%-14s %s\n",
3220Sstevel@tonic-gate 		    ftable[i].strf_name, ftable[i].strf_descr);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate static int
3260Sstevel@tonic-gate streams_parse_type(const strtypes_t ftable[], const char *arg, uint32_t *flag)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate 	int i;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	for (i = 0; ftable[i].strt_name != NULL; i++) {
3310Sstevel@tonic-gate 		if (strcasecmp(arg, ftable[i].strt_name) == 0) {
3320Sstevel@tonic-gate 			*flag = ftable[i].strt_value;
3330Sstevel@tonic-gate 			return (0);
3340Sstevel@tonic-gate 		}
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	return (-1);
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate static void
3410Sstevel@tonic-gate streams_type_usage(const strtypes_t ftable[])
3420Sstevel@tonic-gate {
3430Sstevel@tonic-gate 	int i;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	for (i = 0; ftable[i].strt_name != NULL; i++)
3460Sstevel@tonic-gate 		mdb_printf("%-12s %s\n",
3470Sstevel@tonic-gate 		    ftable[i].strt_name, ftable[i].strt_descr);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate int
3510Sstevel@tonic-gate queue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	const int QUEUE_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	char name[MODMAXNAMELEN];
3560Sstevel@tonic-gate 	int nblks = 0;
3570Sstevel@tonic-gate 	uintptr_t maddr;
3580Sstevel@tonic-gate 	mblk_t mblk;
3590Sstevel@tonic-gate 	queue_t q;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	const char *mod = NULL, *flag = NULL, *not_flag = NULL;
3620Sstevel@tonic-gate 	uint_t quiet = FALSE;
3630Sstevel@tonic-gate 	uint_t verbose = FALSE;
3640Sstevel@tonic-gate 	uint32_t mask = 0, not_mask = 0;
3650Sstevel@tonic-gate 	uintptr_t syncq = 0;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
3680Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`queue_cache", "genunix`queue",
3690Sstevel@tonic-gate 		    argc, argv) == -1) {
3700Sstevel@tonic-gate 			mdb_warn("failed to walk queue cache");
3710Sstevel@tonic-gate 			return (DCMD_ERR);
3720Sstevel@tonic-gate 		}
3730Sstevel@tonic-gate 		return (DCMD_OK);
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
3770Sstevel@tonic-gate 		quiet = TRUE;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
3800Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
3810Sstevel@tonic-gate 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
3820Sstevel@tonic-gate 	    'm', MDB_OPT_STR, &mod,
3830Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &flag,
3840Sstevel@tonic-gate 	    'F', MDB_OPT_STR, &not_flag,
3850Sstevel@tonic-gate 	    's', MDB_OPT_UINTPTR, &syncq,
3860Sstevel@tonic-gate 	    NULL) != argc)
3870Sstevel@tonic-gate 		return (DCMD_USAGE);
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/*
3900Sstevel@tonic-gate 	 * If any of the filtering flags is specified, don't print anything
3910Sstevel@tonic-gate 	 * except the matching pointer.
3920Sstevel@tonic-gate 	 */
3930Sstevel@tonic-gate 	if (flag != NULL || not_flag != NULL || mod != NULL || syncq != NULL)
3940Sstevel@tonic-gate 		quiet = TRUE;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !quiet) {
3970Sstevel@tonic-gate 		mdb_printf("%?s %-13s %6s %4s\n",
3980Sstevel@tonic-gate 		    "ADDR", "MODULE", "FLAGS", "NBLK");
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	if (flag != NULL && streams_parse_flag(qf, flag, &mask) == -1) {
4020Sstevel@tonic-gate 		mdb_warn("unrecognized queue flag '%s'\n", flag);
4030Sstevel@tonic-gate 		streams_flag_usage(qf);
4040Sstevel@tonic-gate 		return (DCMD_USAGE);
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	if (not_flag != NULL &&
4080Sstevel@tonic-gate 	    streams_parse_flag(qf, not_flag, &not_mask) == -1) {
4090Sstevel@tonic-gate 		mdb_warn("unrecognized queue flag '%s'\n", flag);
4100Sstevel@tonic-gate 		streams_flag_usage(qf);
4110Sstevel@tonic-gate 		return (DCMD_USAGE);
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if (mdb_vread(&q, sizeof (q), addr) == -1) {
4150Sstevel@tonic-gate 		mdb_warn("couldn't read queue at %p", addr);
4160Sstevel@tonic-gate 		return (DCMD_ERR);
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	for (maddr = (uintptr_t)q.q_first; maddr != NULL; nblks++) {
4200Sstevel@tonic-gate 		if (mdb_vread(&mblk, sizeof (mblk), maddr) == -1) {
4210Sstevel@tonic-gate 			mdb_warn("couldn't read mblk %p for queue %p",
4220Sstevel@tonic-gate 			    maddr, addr);
4230Sstevel@tonic-gate 			break;
4240Sstevel@tonic-gate 		}
4250Sstevel@tonic-gate 		maddr = (uintptr_t)mblk.b_next;
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	(void) mdb_qname(&q, name, sizeof (name));
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/*
4310Sstevel@tonic-gate 	 * If queue doesn't pass filtering criteria, don't print anything and
4320Sstevel@tonic-gate 	 * just return.
4330Sstevel@tonic-gate 	 */
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if (mod != NULL && strcmp(mod, name) != 0)
4360Sstevel@tonic-gate 		return (DCMD_OK);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	if (mask != 0 && !(q.q_flag & mask))
4390Sstevel@tonic-gate 		return (DCMD_OK);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if (not_mask != 0 && (q.q_flag & not_mask))
4420Sstevel@tonic-gate 		return (DCMD_OK);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if (syncq != 0 && q.q_syncq != (syncq_t *)syncq)
4450Sstevel@tonic-gate 		return (DCMD_OK);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/*
4480Sstevel@tonic-gate 	 * Options are specified for filtering, so If any option is specified on
4490Sstevel@tonic-gate 	 * the command line, just print address and exit.
4500Sstevel@tonic-gate 	 */
4510Sstevel@tonic-gate 	if (quiet) {
4520Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
4530Sstevel@tonic-gate 		return (DCMD_OK);
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	mdb_printf("%0?p %-13s %06x %4d %0?p\n",
4570Sstevel@tonic-gate 	    addr, name, q.q_flag, nblks, q.q_first);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	if (verbose) {
4600Sstevel@tonic-gate 		int i, arm = 0;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		for (i = 0; qf[i].strf_name != NULL; i++) {
4630Sstevel@tonic-gate 			if (!(q.q_flag & (1 << i)))
4640Sstevel@tonic-gate 				continue;
4650Sstevel@tonic-gate 			if (!arm) {
4660Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
4670Sstevel@tonic-gate 				    QUEUE_FLGDELT, "", QUEUE_FLGDELT, "");
4680Sstevel@tonic-gate 				arm = 1;
4690Sstevel@tonic-gate 			} else
4700Sstevel@tonic-gate 				mdb_printf("%*s      ", QUEUE_FLGDELT, "");
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
4730Sstevel@tonic-gate 			    qf[i].strf_name, qf[i].strf_descr);
4740Sstevel@tonic-gate 		}
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	return (DCMD_OK);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate int
4810Sstevel@tonic-gate syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	const int SYNC_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 1);
4840Sstevel@tonic-gate 	const int SYNC_TYPDELT = (int)(sizeof (uintptr_t) * 2 + 5);
4850Sstevel@tonic-gate 	syncq_t sq;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	const char *flag = NULL, *not_flag = NULL;
4880Sstevel@tonic-gate 	const char *typ = NULL, *not_typ = NULL;
4890Sstevel@tonic-gate 	uint_t verbose = FALSE;
4900Sstevel@tonic-gate 	uint_t quiet = FALSE;
4910Sstevel@tonic-gate 	uint32_t mask = 0, not_mask = 0;
4920Sstevel@tonic-gate 	uint32_t tmask = 0, not_tmask = 0;
4930Sstevel@tonic-gate 	uint8_t sqtype = 0;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
4960Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`syncq_cache", "genunix`syncq",
4970Sstevel@tonic-gate 		    argc, argv) == -1) {
4980Sstevel@tonic-gate 			mdb_warn("failed to walk syncq cache");
4990Sstevel@tonic-gate 			return (DCMD_ERR);
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 		return (DCMD_OK);
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
5050Sstevel@tonic-gate 		quiet = TRUE;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5080Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
5090Sstevel@tonic-gate 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
5100Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &flag,
5110Sstevel@tonic-gate 	    'F', MDB_OPT_STR, &not_flag,
5120Sstevel@tonic-gate 	    't', MDB_OPT_STR, &typ,
5130Sstevel@tonic-gate 	    'T', MDB_OPT_STR, &not_typ,
5140Sstevel@tonic-gate 	    NULL) != argc)
5150Sstevel@tonic-gate 		return (DCMD_USAGE);
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	/*
5180Sstevel@tonic-gate 	 * If any of the filtering flags is specified, don't print anything
5190Sstevel@tonic-gate 	 * except the matching pointer.
5200Sstevel@tonic-gate 	 */
5210Sstevel@tonic-gate 	if (flag != NULL || not_flag != NULL || typ != NULL || not_typ != NULL)
5220Sstevel@tonic-gate 		quiet = TRUE;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !quiet) {
5250Sstevel@tonic-gate 		mdb_printf("%?s %s %s %s %s %?s %s %s\n",
5260Sstevel@tonic-gate 		    "ADDR", "FLG", "TYP", "CNT", "NQS", "OUTER", "SF", "PRI");
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if (flag != NULL && streams_parse_flag(sqf, flag, &mask) == -1) {
5300Sstevel@tonic-gate 		mdb_warn("unrecognized syncq flag '%s'\n", flag);
5310Sstevel@tonic-gate 		streams_flag_usage(sqf);
5320Sstevel@tonic-gate 		return (DCMD_USAGE);
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if (typ != NULL && streams_parse_flag(sqt, typ, &tmask) == -1) {
5360Sstevel@tonic-gate 		mdb_warn("unrecognized syncq type '%s'\n", typ);
5370Sstevel@tonic-gate 		streams_flag_usage(sqt);
5380Sstevel@tonic-gate 		return (DCMD_USAGE);
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	if (not_flag != NULL && streams_parse_flag(sqf, not_flag, &not_mask)
5420Sstevel@tonic-gate 	    == -1) {
5430Sstevel@tonic-gate 		mdb_warn("unrecognized syncq flag '%s'\n", not_flag);
5440Sstevel@tonic-gate 		streams_flag_usage(sqf);
5450Sstevel@tonic-gate 		return (DCMD_USAGE);
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if (not_typ != NULL && streams_parse_flag(sqt, not_typ, &not_tmask)
5490Sstevel@tonic-gate 	    == -1) {
5500Sstevel@tonic-gate 		mdb_warn("unrecognized syncq type '%s'\n", not_typ);
5510Sstevel@tonic-gate 		streams_flag_usage(sqt);
5520Sstevel@tonic-gate 		return (DCMD_USAGE);
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	if (mdb_vread(&sq, sizeof (sq), addr) == -1) {
5560Sstevel@tonic-gate 		mdb_warn("couldn't read syncq at %p", addr);
5570Sstevel@tonic-gate 		return (DCMD_ERR);
5580Sstevel@tonic-gate 	}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	if (mask != 0 && !(sq.sq_flags & mask))
5610Sstevel@tonic-gate 		return (DCMD_OK);
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	if (not_mask != 0 && (sq.sq_flags & not_mask))
5640Sstevel@tonic-gate 		return (DCMD_OK);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	sqtype = (sq.sq_type >> 8) & 0xff;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	if (tmask != 0 && !(sqtype & tmask))
5690Sstevel@tonic-gate 		return (DCMD_OK);
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	if (not_tmask != 0 && (sqtype & not_tmask))
5720Sstevel@tonic-gate 		return (DCMD_OK);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	/*
5750Sstevel@tonic-gate 	 * Options are specified for filtering, so If any option is specified on
5760Sstevel@tonic-gate 	 * the command line, just print address and exit.
5770Sstevel@tonic-gate 	 */
5780Sstevel@tonic-gate 	if (quiet) {
5790Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
5800Sstevel@tonic-gate 		return (DCMD_OK);
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	mdb_printf("%0?p %02x  %02x  %-3u %-3u %0?p  %1x %-3d\n",
5840Sstevel@tonic-gate 	    addr, sq.sq_flags & 0xff, sqtype, sq.sq_count,
5850Sstevel@tonic-gate 	    sq.sq_nqueues, sq.sq_outer, sq.sq_svcflags, sq.sq_pri);
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	if (verbose) {
5880Sstevel@tonic-gate 		int i, arm = 0;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		for (i = 0; sqf[i].strf_name != NULL; i++) {
5910Sstevel@tonic-gate 			if (!(sq.sq_flags & (1 << i)))
5920Sstevel@tonic-gate 				continue;
5930Sstevel@tonic-gate 			if (!arm) {
5940Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
5950Sstevel@tonic-gate 				    SYNC_FLGDELT, "", SYNC_FLGDELT, "");
5960Sstevel@tonic-gate 				arm = 1;
5970Sstevel@tonic-gate 			} else
5980Sstevel@tonic-gate 				mdb_printf("%*s      ", SYNC_FLGDELT, "");
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
6010Sstevel@tonic-gate 			    sqf[i].strf_name, sqf[i].strf_descr);
6020Sstevel@tonic-gate 		}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 		for (i = 0; sqt[i].strf_name != NULL; i++) {
6050Sstevel@tonic-gate 			if (!(sqtype & (1 << i)))
6060Sstevel@tonic-gate 				continue;
6070Sstevel@tonic-gate 			if (!arm) {
6080Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
6090Sstevel@tonic-gate 				    SYNC_TYPDELT, "", SYNC_TYPDELT, "");
6100Sstevel@tonic-gate 				arm = 1;
6110Sstevel@tonic-gate 			} else
6120Sstevel@tonic-gate 				mdb_printf("%*s      ", SYNC_TYPDELT, "");
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
6150Sstevel@tonic-gate 			    sqt[i].strf_name, sqt[i].strf_descr);
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	return (DCMD_OK);
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate int
6230Sstevel@tonic-gate stdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6240Sstevel@tonic-gate {
6250Sstevel@tonic-gate 	const int STREAM_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 10);
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	stdata_t  sd;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	const char *flag = NULL, *not_flag = NULL;
6300Sstevel@tonic-gate 	uint_t verbose = FALSE;
6310Sstevel@tonic-gate 	uint_t quiet = FALSE;
6320Sstevel@tonic-gate 	uint32_t mask = 0, not_mask = 0;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
6350Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`stream_head_cache",
6360Sstevel@tonic-gate 		    "genunix`stdata", argc, argv) == -1) {
6370Sstevel@tonic-gate 			mdb_warn("failed to walk stream head cache");
6380Sstevel@tonic-gate 			return (DCMD_ERR);
6390Sstevel@tonic-gate 		}
6400Sstevel@tonic-gate 		return (DCMD_OK);
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
6440Sstevel@tonic-gate 		quiet = TRUE;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
6470Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
6480Sstevel@tonic-gate 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
6490Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &flag,
6500Sstevel@tonic-gate 	    'F', MDB_OPT_STR, &not_flag,
6510Sstevel@tonic-gate 	    NULL) != argc)
6520Sstevel@tonic-gate 		return (DCMD_USAGE);
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/*
6550Sstevel@tonic-gate 	 * If any of the filtering flags is specified, don't print anything
6560Sstevel@tonic-gate 	 * except the matching pointer.
6570Sstevel@tonic-gate 	 */
6580Sstevel@tonic-gate 	if (flag != NULL || not_flag != NULL)
6590Sstevel@tonic-gate 		quiet = TRUE;
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !quiet) {
6620Sstevel@tonic-gate 		mdb_printf("%?s %?s %8s %?s %s %s\n",
6630Sstevel@tonic-gate 		    "ADDR", "WRQ", "FLAGS", "VNODE", "N/A", "REF");
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	if (flag != NULL && streams_parse_flag(stdf, flag, &mask) == -1) {
6670Sstevel@tonic-gate 		mdb_warn("unrecognized stream flag '%s'\n", flag);
6680Sstevel@tonic-gate 		streams_flag_usage(stdf);
6690Sstevel@tonic-gate 		return (DCMD_USAGE);
6700Sstevel@tonic-gate 	}
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	if (not_flag != NULL &&
6730Sstevel@tonic-gate 	    streams_parse_flag(stdf, not_flag, &not_mask) == -1) {
6740Sstevel@tonic-gate 		mdb_warn("unrecognized stream flag '%s'\n", flag);
6750Sstevel@tonic-gate 		streams_flag_usage(stdf);
6760Sstevel@tonic-gate 		return (DCMD_USAGE);
6770Sstevel@tonic-gate 	}
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	if (mdb_vread(&sd, sizeof (sd), addr) == -1) {
6800Sstevel@tonic-gate 		mdb_warn("couldn't read stdata at %p", addr);
6810Sstevel@tonic-gate 		return (DCMD_ERR);
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	/*
6850Sstevel@tonic-gate 	 * If stream doesn't pass filtering criteria, don't print anything and
6860Sstevel@tonic-gate 	 * just return.
6870Sstevel@tonic-gate 	 */
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (mask != 0 && !(sd.sd_flag & mask))
6900Sstevel@tonic-gate 		return (DCMD_OK);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	if (not_mask != 0 && (sd.sd_flag & not_mask))
6930Sstevel@tonic-gate 		return (DCMD_OK);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/*
6960Sstevel@tonic-gate 	 * Options are specified for filtering, so If any option is specified on
6970Sstevel@tonic-gate 	 * the command line, just print address and exit.
6980Sstevel@tonic-gate 	 */
6990Sstevel@tonic-gate 	if (quiet) {
7000Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
7010Sstevel@tonic-gate 		return (DCMD_OK);
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %08x %0?p %d/%d %d\n",
7050Sstevel@tonic-gate 	    addr, sd.sd_wrq, sd.sd_flag, sd.sd_vnode,
7060Sstevel@tonic-gate 	    sd.sd_pushcnt, sd.sd_anchor, sd.sd_refcnt);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	if (verbose) {
7090Sstevel@tonic-gate 		int i, arm = 0;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 		for (i = 0; stdf[i].strf_name != NULL; i++) {
7120Sstevel@tonic-gate 			if (!(sd.sd_flag & (1 << i)))
7130Sstevel@tonic-gate 				continue;
7140Sstevel@tonic-gate 			if (!arm) {
7150Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
7160Sstevel@tonic-gate 				    STREAM_FLGDELT, "", STREAM_FLGDELT, "");
7170Sstevel@tonic-gate 				arm = 1;
7180Sstevel@tonic-gate 			} else
7190Sstevel@tonic-gate 				mdb_printf("%*s      ", STREAM_FLGDELT, "");
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
7220Sstevel@tonic-gate 			    stdf[i].strf_name, stdf[i].strf_descr);
7230Sstevel@tonic-gate 		}
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	return (DCMD_OK);
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate /*ARGSUSED*/
7300Sstevel@tonic-gate static void
7310Sstevel@tonic-gate qprint_syncq(queue_t *addr, queue_t *q)
7320Sstevel@tonic-gate {
7330Sstevel@tonic-gate 	mdb_printf("%p\n", q->q_syncq);
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate /*ARGSUSED*/
7370Sstevel@tonic-gate static void
7380Sstevel@tonic-gate qprint_stream(queue_t *addr, queue_t *q)
7390Sstevel@tonic-gate {
7400Sstevel@tonic-gate 	mdb_printf("%p\n", q->q_stream);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate static void
7440Sstevel@tonic-gate qprint_wrq(queue_t *addr, queue_t *q)
7450Sstevel@tonic-gate {
7460Sstevel@tonic-gate 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)));
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate static void
7500Sstevel@tonic-gate qprint_rdq(queue_t *addr, queue_t *q)
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr): (addr)-1));
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate static void
7560Sstevel@tonic-gate qprint_otherq(queue_t *addr, queue_t *q)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)-1));
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate static int
7620Sstevel@tonic-gate q2x(uintptr_t addr, int argc, qprint_func prfunc)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate 	queue_t q;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	if (argc != 0)
7670Sstevel@tonic-gate 		return (DCMD_USAGE);
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	if (mdb_vread(&q, sizeof (q), addr) == -1) {
7700Sstevel@tonic-gate 		mdb_warn("couldn't read queue at %p", addr);
7710Sstevel@tonic-gate 		return (DCMD_ERR);
7720Sstevel@tonic-gate 	}
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	prfunc((queue_t *)addr, &q);
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	return (DCMD_OK);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate /*ARGSUSED*/
7810Sstevel@tonic-gate int
7820Sstevel@tonic-gate q2syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_syncq));
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate /*ARGSUSED*/
7880Sstevel@tonic-gate int
7890Sstevel@tonic-gate q2stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7900Sstevel@tonic-gate {
7910Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_stream));
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate /*ARGSUSED*/
7950Sstevel@tonic-gate int
7960Sstevel@tonic-gate q2rdq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7970Sstevel@tonic-gate {
7980Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_rdq));
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate /*ARGSUSED*/
8020Sstevel@tonic-gate int
8030Sstevel@tonic-gate q2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_wrq));
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate /*ARGSUSED*/
8090Sstevel@tonic-gate int
8100Sstevel@tonic-gate q2otherq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8110Sstevel@tonic-gate {
8120Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_otherq));
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate static int
8160Sstevel@tonic-gate sd2x(uintptr_t addr, int argc, sdprint_func prfunc)
8170Sstevel@tonic-gate {
8180Sstevel@tonic-gate 	stdata_t sd;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	if (argc != 0)
8210Sstevel@tonic-gate 		return (DCMD_USAGE);
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	if (mdb_vread(&sd, sizeof (sd), addr) == -1) {
8240Sstevel@tonic-gate 		mdb_warn("couldn't read stream head at %p", addr);
8250Sstevel@tonic-gate 		return (DCMD_ERR);
8260Sstevel@tonic-gate 	}
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	prfunc((stdata_t *)addr, &sd);
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	return (DCMD_OK);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate /*ARGSUSED*/
8340Sstevel@tonic-gate static void
8350Sstevel@tonic-gate sdprint_wrq(stdata_t *addr, stdata_t *sd)
8360Sstevel@tonic-gate {
8370Sstevel@tonic-gate 	mdb_printf("%p\n", sd->sd_wrq);
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate static void
8410Sstevel@tonic-gate sdprint_mate(stdata_t *addr, stdata_t *sd)
8420Sstevel@tonic-gate {
8430Sstevel@tonic-gate 	mdb_printf("%p\n", sd->sd_mate ? sd->sd_mate : addr);
8440Sstevel@tonic-gate }
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate /*ARGSUSED*/
8470Sstevel@tonic-gate int
8480Sstevel@tonic-gate str2mate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8490Sstevel@tonic-gate {
8500Sstevel@tonic-gate 	return (sd2x(addr, argc, sdprint_mate));
8510Sstevel@tonic-gate }
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate /*ARGSUSED*/
8540Sstevel@tonic-gate int
8550Sstevel@tonic-gate str2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8560Sstevel@tonic-gate {
8570Sstevel@tonic-gate 	return (sd2x(addr, argc, sdprint_wrq));
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate /*
8620Sstevel@tonic-gate  * If this syncq is a part of the queue pair structure, find the queue for it.
8630Sstevel@tonic-gate  */
8640Sstevel@tonic-gate /*ARGSUSED*/
8650Sstevel@tonic-gate int
8660Sstevel@tonic-gate syncq2q(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate 	syncq_t sq;
8690Sstevel@tonic-gate 	queue_t q;
8700Sstevel@tonic-gate 	queue_t *qp;
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	if (argc != 0)
8730Sstevel@tonic-gate 		return (DCMD_USAGE);
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	if (mdb_vread(&sq, sizeof (sq), addr) == -1) {
8760Sstevel@tonic-gate 		mdb_warn("couldn't read syncq at %p", addr);
8770Sstevel@tonic-gate 		return (DCMD_ERR);
8780Sstevel@tonic-gate 	}
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	/* Try to find its queue */
8810Sstevel@tonic-gate 	qp = (queue_t *)addr - 2;
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	if ((mdb_vread(&q, sizeof (q), (uintptr_t)qp) == -1) ||
8840Sstevel@tonic-gate 	    (q.q_syncq != (syncq_t *)addr)) {
8850Sstevel@tonic-gate 		mdb_warn("syncq2q: %p is not part of any queue\n", addr);
8860Sstevel@tonic-gate 		return (DCMD_ERR);
8870Sstevel@tonic-gate 	} else
8880Sstevel@tonic-gate 		mdb_printf("%p\n", qp);
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	return (DCMD_OK);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate int
8950Sstevel@tonic-gate queue_walk_init(mdb_walk_state_t *wsp)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate 	if (wsp->walk_addr == NULL &&
8980Sstevel@tonic-gate 	    mdb_readvar(&wsp->walk_addr, "qhead") == -1) {
8990Sstevel@tonic-gate 		mdb_warn("failed to read 'qhead'");
9000Sstevel@tonic-gate 		return (WALK_ERR);
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (queue_t), UM_SLEEP);
9040Sstevel@tonic-gate 	return (WALK_NEXT);
9050Sstevel@tonic-gate }
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate int
9080Sstevel@tonic-gate queue_link_step(mdb_walk_state_t *wsp)
9090Sstevel@tonic-gate {
9100Sstevel@tonic-gate 	int status;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
9130Sstevel@tonic-gate 		return (WALK_DONE);
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) {
9160Sstevel@tonic-gate 		mdb_warn("failed to read queue at %p", wsp->walk_addr);
9170Sstevel@tonic-gate 		return (WALK_DONE);
9180Sstevel@tonic-gate 	}
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
9210Sstevel@tonic-gate 	    wsp->walk_cbdata);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_link);
9240Sstevel@tonic-gate 	return (status);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate int
9280Sstevel@tonic-gate queue_next_step(mdb_walk_state_t *wsp)
9290Sstevel@tonic-gate {
9300Sstevel@tonic-gate 	int status;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
9330Sstevel@tonic-gate 		return (WALK_DONE);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) {
9360Sstevel@tonic-gate 		mdb_warn("failed to read queue at %p", wsp->walk_addr);
9370Sstevel@tonic-gate 		return (WALK_DONE);
9380Sstevel@tonic-gate 	}
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
9410Sstevel@tonic-gate 	    wsp->walk_cbdata);
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_next);
9440Sstevel@tonic-gate 	return (status);
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate void
9480Sstevel@tonic-gate queue_walk_fini(mdb_walk_state_t *wsp)
9490Sstevel@tonic-gate {
9500Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (queue_t));
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate int
9540Sstevel@tonic-gate str_walk_init(mdb_walk_state_t *wsp)
9550Sstevel@tonic-gate {
9560Sstevel@tonic-gate 	stdata_t s;
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
9590Sstevel@tonic-gate 		mdb_warn("walk must begin at address of stdata_t\n");
9600Sstevel@tonic-gate 		return (WALK_ERR);
9610Sstevel@tonic-gate 	}
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 	if (mdb_vread(&s, sizeof (s), wsp->walk_addr) == -1) {
9640Sstevel@tonic-gate 		mdb_warn("failed to read stdata at %p", wsp->walk_addr);
9650Sstevel@tonic-gate 		return (WALK_ERR);
9660Sstevel@tonic-gate 	}
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)s.sd_wrq;
9690Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (queue_t) * 2, UM_SLEEP);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	return (WALK_NEXT);
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate int
9750Sstevel@tonic-gate strr_walk_step(mdb_walk_state_t *wsp)
9760Sstevel@tonic-gate {
9770Sstevel@tonic-gate 	queue_t *rq = wsp->walk_data, *wq = rq + 1;
9780Sstevel@tonic-gate 	int status;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
9810Sstevel@tonic-gate 		return (WALK_DONE);
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2,
9840Sstevel@tonic-gate 	    wsp->walk_addr - sizeof (queue_t)) == -1) {
9850Sstevel@tonic-gate 		mdb_warn("failed to read queue pair at %p",
9860Sstevel@tonic-gate 		    wsp->walk_addr - sizeof (queue_t));
9870Sstevel@tonic-gate 		return (WALK_DONE);
9880Sstevel@tonic-gate 	}
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr - sizeof (queue_t),
9910Sstevel@tonic-gate 	    rq, wsp->walk_cbdata);
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	if (wq->q_next != NULL)
9940Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)wq->q_next;
9950Sstevel@tonic-gate 	else
9960Sstevel@tonic-gate 		wsp->walk_addr = mdb_qwnext(wq);
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	return (status);
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate int
10020Sstevel@tonic-gate strw_walk_step(mdb_walk_state_t *wsp)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate 	queue_t *rq = wsp->walk_data, *wq = rq + 1;
10050Sstevel@tonic-gate 	int status;
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
10080Sstevel@tonic-gate 		return (WALK_DONE);
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2,
10110Sstevel@tonic-gate 	    wsp->walk_addr - sizeof (queue_t)) == -1) {
10120Sstevel@tonic-gate 		mdb_warn("failed to read queue pair at %p",
10130Sstevel@tonic-gate 		    wsp->walk_addr - sizeof (queue_t));
10140Sstevel@tonic-gate 		return (WALK_DONE);
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wq, wsp->walk_cbdata);
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	if (wq->q_next != NULL)
10200Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)wq->q_next;
10210Sstevel@tonic-gate 	else
10220Sstevel@tonic-gate 		wsp->walk_addr = mdb_qwnext(wq);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	return (status);
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate void
10280Sstevel@tonic-gate str_walk_fini(mdb_walk_state_t *wsp)
10290Sstevel@tonic-gate {
10300Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (queue_t) * 2);
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate static int
10340Sstevel@tonic-gate print_qpair(uintptr_t addr, const queue_t *q, uint_t *depth)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate 	static const char box_lid[] =
10370Sstevel@tonic-gate 	    "+-----------------------+-----------------------+\n";
10380Sstevel@tonic-gate 	static const char box_sep[] =
10390Sstevel@tonic-gate 	    "|                       |                       |\n";
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	char wname[32], rname[32], info1[256], *info2;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	if (*depth != 0) {
10440Sstevel@tonic-gate 		mdb_printf("            |                       ^\n");
10450Sstevel@tonic-gate 		mdb_printf("            v                       |\n");
10460Sstevel@tonic-gate 	} else
10470Sstevel@tonic-gate 		mdb_printf("\n");
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	(void) mdb_qname(_WR(q), wname, sizeof (wname));
10500Sstevel@tonic-gate 	(void) mdb_qname(_RD(q), rname, sizeof (rname));
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	mdb_qinfo(_WR(q), info1, sizeof (info1));
10530Sstevel@tonic-gate 	if ((info2 = strchr(info1, '\n')) != NULL)
10540Sstevel@tonic-gate 		*info2++ = '\0';
10550Sstevel@tonic-gate 	else
10560Sstevel@tonic-gate 		info2 = "";
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	mdb_printf(box_lid);
10590Sstevel@tonic-gate 	mdb_printf("| 0x%-19p | 0x%-19p | %s\n",
10600Sstevel@tonic-gate 	    addr, addr - sizeof (queue_t), info1);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	mdb_printf("| %<b>%-21s%</b> | %<b>%-21s%</b> |", wname, rname);
10630Sstevel@tonic-gate 	mdb_flush(); /* Account for buffered terminal sequences */
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	mdb_printf(" %s\n", info2);
10660Sstevel@tonic-gate 	mdb_printf(box_sep);
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	mdb_qinfo(_RD(q), info1, sizeof (info1));
10690Sstevel@tonic-gate 	if ((info2 = strchr(info1, '\n')) != NULL)
10700Sstevel@tonic-gate 		*info2++ = '\0';
10710Sstevel@tonic-gate 	else
10720Sstevel@tonic-gate 		info2 = "";
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	mdb_printf("| cnt = 0t%-13lu | cnt = 0t%-13lu | %s\n",
10750Sstevel@tonic-gate 	    _WR(q)->q_count, _RD(q)->q_count, info1);
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	mdb_printf("| flg = 0x%08x      | flg = 0x%08x      | %s\n",
10780Sstevel@tonic-gate 	    _WR(q)->q_flag, _RD(q)->q_flag, info2);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	mdb_printf(box_lid);
10810Sstevel@tonic-gate 	*depth += 1;
10820Sstevel@tonic-gate 	return (0);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate /*ARGSUSED*/
10860Sstevel@tonic-gate int
10870Sstevel@tonic-gate stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	uint_t d = 0;	/* Depth counter for print_qpair */
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
10920Sstevel@tonic-gate 		return (DCMD_USAGE);
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	if (mdb_pwalk("writeq", (mdb_walk_cb_t)print_qpair, &d, addr) == -1) {
10950Sstevel@tonic-gate 		mdb_warn("failed to walk writeq");
10960Sstevel@tonic-gate 		return (DCMD_ERR);
10970Sstevel@tonic-gate 	}
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	return (DCMD_OK);
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate int
11030Sstevel@tonic-gate mblk_walk_init(mdb_walk_state_t *wsp)
11040Sstevel@tonic-gate {
11050Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (mblk_t), UM_SLEEP);
11060Sstevel@tonic-gate 	return (WALK_NEXT);
11070Sstevel@tonic-gate }
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate int
11100Sstevel@tonic-gate b_cont_step(mdb_walk_state_t *wsp)
11110Sstevel@tonic-gate {
11120Sstevel@tonic-gate 	int status;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
11150Sstevel@tonic-gate 		return (WALK_DONE);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) {
11180Sstevel@tonic-gate 		mdb_warn("failed to read mblk at %p", wsp->walk_addr);
11190Sstevel@tonic-gate 		return (WALK_DONE);
11200Sstevel@tonic-gate 	}
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
11230Sstevel@tonic-gate 	    wsp->walk_cbdata);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_cont);
11260Sstevel@tonic-gate 	return (status);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate int
11300Sstevel@tonic-gate b_next_step(mdb_walk_state_t *wsp)
11310Sstevel@tonic-gate {
11320Sstevel@tonic-gate 	int status;
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
11350Sstevel@tonic-gate 		return (WALK_DONE);
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) {
11380Sstevel@tonic-gate 		mdb_warn("failed to read mblk at %p", wsp->walk_addr);
11390Sstevel@tonic-gate 		return (WALK_DONE);
11400Sstevel@tonic-gate 	}
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
11430Sstevel@tonic-gate 	    wsp->walk_cbdata);
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_next);
11460Sstevel@tonic-gate 	return (status);
11470Sstevel@tonic-gate }
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate void
11500Sstevel@tonic-gate mblk_walk_fini(mdb_walk_state_t *wsp)
11510Sstevel@tonic-gate {
11520Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (mblk_t));
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate /* ARGSUSED */
11560Sstevel@tonic-gate int
11570Sstevel@tonic-gate mblk2dblk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
11580Sstevel@tonic-gate {
11590Sstevel@tonic-gate 	mblk_t mb;
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	if (argc != 0)
11620Sstevel@tonic-gate 		return (DCMD_USAGE);
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	if (mdb_vread(&mb, sizeof (mb), addr) == -1) {
11650Sstevel@tonic-gate 		mdb_warn("couldn't read mblk at %p", addr);
11660Sstevel@tonic-gate 		return (DCMD_ERR);
11670Sstevel@tonic-gate 	}
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	mdb_printf("%p\n", mb.b_datap);
11700Sstevel@tonic-gate 	return (DCMD_OK);
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate static void
11750Sstevel@tonic-gate mblk_error(int *error, uintptr_t addr, char *message)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate 	if (!*error)
11780Sstevel@tonic-gate 		mdb_printf("%?lx: ", addr);
11790Sstevel@tonic-gate 	else
11800Sstevel@tonic-gate 		mdb_printf(", ");
11810Sstevel@tonic-gate 	mdb_printf("%s", message);
11820Sstevel@tonic-gate 	*error = 1;
11830Sstevel@tonic-gate }
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate int
11860Sstevel@tonic-gate mblk_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
11870Sstevel@tonic-gate {
11880Sstevel@tonic-gate 	mblk_t	mb;
11890Sstevel@tonic-gate 	dblk_t	db;
11900Sstevel@tonic-gate 	int	error = 0;
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
11930Sstevel@tonic-gate 		if (mdb_walk_dcmd("streams_mblk", "mblk_verify", argc, argv) ==
11940Sstevel@tonic-gate 		    -1) {
11950Sstevel@tonic-gate 			mdb_warn("can't walk mblk cache");
11960Sstevel@tonic-gate 			return (DCMD_ERR);
11970Sstevel@tonic-gate 		}
11980Sstevel@tonic-gate 		return (DCMD_OK);
11990Sstevel@tonic-gate 	}
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	if (mdb_vread(&mb, sizeof (mblk_t), addr) == -1) {
12020Sstevel@tonic-gate 		mdb_warn("can't read mblk_t at 0x%lx", addr);
12030Sstevel@tonic-gate 		return (DCMD_ERR);
12040Sstevel@tonic-gate 	}
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	if (mdb_vread(&db, sizeof (dblk_t), (uintptr_t)mb.b_datap) == -1) {
12070Sstevel@tonic-gate 		mdb_warn("%?lx: invalid b_datap pointer\n", addr);
12080Sstevel@tonic-gate 		return (DCMD_ERR);
12090Sstevel@tonic-gate 	}
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	if (mb.b_rptr < db.db_base || mb.b_rptr > db.db_lim)
12120Sstevel@tonic-gate 		mblk_error(&error, addr, "b_rptr out of range");
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	if (mb.b_wptr < db.db_base || mb.b_wptr > db.db_lim)
12150Sstevel@tonic-gate 		mblk_error(&error, addr, "b_wptr out of range");
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	if (error)
12180Sstevel@tonic-gate 		mdb_printf("\n");
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	return (error ? DCMD_ERR : DCMD_OK);
12210Sstevel@tonic-gate }
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate int
12240Sstevel@tonic-gate mblk_prt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
12250Sstevel@tonic-gate {
12260Sstevel@tonic-gate 	const int MBLK_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15);
12270Sstevel@tonic-gate 	mblk_t mblk;
12280Sstevel@tonic-gate 	dblk_t dblk;
12290Sstevel@tonic-gate 	int b_flag;
12300Sstevel@tonic-gate 	int db_type;
12310Sstevel@tonic-gate 	int mblklen;
12320Sstevel@tonic-gate 	uint64_t len = ~0UL;
12330Sstevel@tonic-gate 	uint64_t glen = ~0UL;
12340Sstevel@tonic-gate 	uint64_t llen = ~0UL;
12350Sstevel@tonic-gate 	uint64_t blen = ~0UL;
12360Sstevel@tonic-gate 	const char *dbtype;
12370Sstevel@tonic-gate 	const char *flag = NULL, *not_flag = NULL;
12380Sstevel@tonic-gate 	const char *typ = NULL, *not_typ = NULL;
12390Sstevel@tonic-gate 	uintptr_t  dbaddr = 0;
12400Sstevel@tonic-gate 	uint32_t tmask = 0, not_tmask = 0;
12410Sstevel@tonic-gate 	uint32_t mask = 0, not_mask = 0;
12420Sstevel@tonic-gate 	uint_t quiet = FALSE;
12430Sstevel@tonic-gate 	uint_t verbose = FALSE;
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
12460Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`streams_mblk", "genunix`mblk",
12470Sstevel@tonic-gate 		    argc, argv) == -1) {
12480Sstevel@tonic-gate 			mdb_warn("failed to walk mblk cache");
12490Sstevel@tonic-gate 			return (DCMD_ERR);
12500Sstevel@tonic-gate 		}
12510Sstevel@tonic-gate 		return (DCMD_OK);
12520Sstevel@tonic-gate 	}
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
12550Sstevel@tonic-gate 		quiet = TRUE;
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
12580Sstevel@tonic-gate 		'v', MDB_OPT_SETBITS, TRUE, &verbose,
12590Sstevel@tonic-gate 		'q', MDB_OPT_SETBITS, TRUE, &quiet,
12600Sstevel@tonic-gate 		'f', MDB_OPT_STR, &flag,
12610Sstevel@tonic-gate 		'F', MDB_OPT_STR, &not_flag,
12620Sstevel@tonic-gate 		't', MDB_OPT_STR, &typ,
12630Sstevel@tonic-gate 		'T', MDB_OPT_STR, &not_typ,
12640Sstevel@tonic-gate 		'l', MDB_OPT_UINT64, &len,
12650Sstevel@tonic-gate 		'L', MDB_OPT_UINT64, &llen,
12660Sstevel@tonic-gate 		'G', MDB_OPT_UINT64, &glen,
12670Sstevel@tonic-gate 		'b', MDB_OPT_UINT64, &blen,
12680Sstevel@tonic-gate 		'd', MDB_OPT_UINTPTR, &dbaddr,
12690Sstevel@tonic-gate 	    NULL) != argc)
12700Sstevel@tonic-gate 		return (DCMD_USAGE);
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	/*
12730Sstevel@tonic-gate 	 * If any of the filtering flags is specified, don't print anything
12740Sstevel@tonic-gate 	 * except the matching pointer.
12750Sstevel@tonic-gate 	 */
12760Sstevel@tonic-gate 	if ((flag != NULL) || (not_flag != NULL) || (typ != NULL) ||
12770Sstevel@tonic-gate 	    (not_typ != NULL) || (len != ~0UL) || (glen != ~0UL) ||
12780Sstevel@tonic-gate 	    (llen != ~0UL) || (blen != ~0UL) || (dbaddr != 0))
12790Sstevel@tonic-gate 		quiet = TRUE;
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	if (flag != NULL && streams_parse_flag(mbf, flag, &mask) == -1) {
12820Sstevel@tonic-gate 		mdb_warn("unrecognized mblk flag '%s'\n", flag);
12830Sstevel@tonic-gate 		streams_flag_usage(mbf);
12840Sstevel@tonic-gate 		return (DCMD_USAGE);
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	if (not_flag != NULL &&
12880Sstevel@tonic-gate 	    streams_parse_flag(mbf, not_flag, &not_mask) == -1) {
12890Sstevel@tonic-gate 		mdb_warn("unrecognized mblk flag '%s'\n", flag);
12900Sstevel@tonic-gate 		streams_flag_usage(mbf);
12910Sstevel@tonic-gate 		return (DCMD_USAGE);
12920Sstevel@tonic-gate 	}
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	if (typ != NULL && streams_parse_type(mbt, typ, &tmask) == -1) {
12950Sstevel@tonic-gate 		mdb_warn("unrecognized dblk type '%s'\n", typ);
12960Sstevel@tonic-gate 		streams_type_usage(mbt);
12970Sstevel@tonic-gate 		return (DCMD_USAGE);
12980Sstevel@tonic-gate 	}
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	if (not_typ != NULL && streams_parse_type(mbt, not_typ, &not_tmask)
13010Sstevel@tonic-gate 	    == -1) {
13020Sstevel@tonic-gate 		mdb_warn("unrecognized dblk type '%s'\n", not_typ);
13030Sstevel@tonic-gate 		streams_type_usage(mbt);
13040Sstevel@tonic-gate 		return (DCMD_USAGE);
13050Sstevel@tonic-gate 	}
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !quiet) {
13080Sstevel@tonic-gate 		mdb_printf("%?s %2s %-7s %-5s %-5s %?s %?s\n",
13090Sstevel@tonic-gate 		    "ADDR", "FL", "TYPE", "LEN", "BLEN", "RPTR", "DBLK");
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	if (mdb_vread(&mblk, sizeof (mblk), addr) == -1) {
13130Sstevel@tonic-gate 		mdb_warn("couldn't read mblk at %p", addr);
13140Sstevel@tonic-gate 		return (DCMD_ERR);
13150Sstevel@tonic-gate 	}
13160Sstevel@tonic-gate 	b_flag = mblk.b_flag;
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	if (mask != 0 && !(b_flag & mask))
13190Sstevel@tonic-gate 		return (DCMD_OK);
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	if (not_mask != 0 && (b_flag & not_mask))
13220Sstevel@tonic-gate 		return (DCMD_OK);
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	if (mdb_vread(&dblk, sizeof (dblk), (uintptr_t)(mblk.b_datap)) == -1) {
13250Sstevel@tonic-gate 		mdb_warn("couldn't read dblk at %p/%p", addr, mblk.b_datap);
13260Sstevel@tonic-gate 		return (DCMD_ERR);
13270Sstevel@tonic-gate 	}
13280Sstevel@tonic-gate 	db_type = dblk.db_type;
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	/* M_DATA is 0, so tmask has special value 0xff for it */
13310Sstevel@tonic-gate 	if ((tmask != 0) &&
13320Sstevel@tonic-gate 	    (((tmask == M_DATA_T) && (db_type != M_DATA)) ||
13330Sstevel@tonic-gate 		((tmask != M_DATA_T) && (db_type != tmask))))
13340Sstevel@tonic-gate 		return (DCMD_OK);
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	if ((not_tmask != 0) &&
13380Sstevel@tonic-gate 	    (((not_tmask == M_DATA_T) && (db_type == M_DATA)) ||
13390Sstevel@tonic-gate 		(db_type == not_tmask)))
13400Sstevel@tonic-gate 		return (DCMD_OK);
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	if (dbaddr != 0 && (uintptr_t)mblk.b_datap != dbaddr)
13430Sstevel@tonic-gate 		return (DCMD_OK);
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	mblklen = MBLKL(&mblk);
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	if ((len != ~0UL) && (len != mblklen))
13480Sstevel@tonic-gate 		return (DCMD_OK);
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	if ((llen != ~0Ul) && (mblklen > (int)llen))
13510Sstevel@tonic-gate 		return (DCMD_OK);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	if ((glen != ~0Ul) && (mblklen < (int)glen))
13540Sstevel@tonic-gate 		return (DCMD_OK);
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	if ((blen != ~0UL) && (blen != (dblk.db_lim - dblk.db_base)))
13570Sstevel@tonic-gate 		return (DCMD_OK);
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	/*
13600Sstevel@tonic-gate 	 * Options are specified for filtering, so If any option is specified on
13610Sstevel@tonic-gate 	 * the command line, just print address and exit.
13620Sstevel@tonic-gate 	 */
13630Sstevel@tonic-gate 	if (quiet) {
13640Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
13650Sstevel@tonic-gate 		return (DCMD_OK);
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	/* Figure out symbolic DB_TYPE */
13690Sstevel@tonic-gate 	if (db_type < A_SIZE(db_control_types)) {
13700Sstevel@tonic-gate 		dbtype = db_control_types[db_type];
13710Sstevel@tonic-gate 	} else {
13720Sstevel@tonic-gate 		/*
13730Sstevel@tonic-gate 		 * Must be a high-priority message -- adjust so that
13740Sstevel@tonic-gate 		 * "QPCTL + 1" corresponds to db_control_hipri_types[0]
13750Sstevel@tonic-gate 		 */
13760Sstevel@tonic-gate 		db_type -= (QPCTL + 1);
13770Sstevel@tonic-gate 		if (db_type >= 0 && db_type < A_SIZE(db_control_hipri_types))
13780Sstevel@tonic-gate 			dbtype = db_control_hipri_types[db_type];
13790Sstevel@tonic-gate 		else
13800Sstevel@tonic-gate 			dbtype = "UNKNOWN";
13810Sstevel@tonic-gate 	}
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	mdb_printf("%0?p %-2x %-7s %-5d %-5d %0?p %0?p\n",
13840Sstevel@tonic-gate 	    addr, b_flag, dbtype, mblklen, dblk.db_lim - dblk.db_base,
13850Sstevel@tonic-gate 	    mblk.b_rptr, mblk.b_datap);
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	if (verbose) {
13880Sstevel@tonic-gate 		int i, arm = 0;
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 		for (i = 0; mbf[i].strf_name != NULL; i++) {
13910Sstevel@tonic-gate 			if (!(b_flag & (1 << i)))
13920Sstevel@tonic-gate 				continue;
13930Sstevel@tonic-gate 			if (!arm) {
13940Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
13950Sstevel@tonic-gate 				    MBLK_FLGDELT, "", MBLK_FLGDELT, "");
13960Sstevel@tonic-gate 				arm = 1;
13970Sstevel@tonic-gate 			} else
13980Sstevel@tonic-gate 				mdb_printf("%*s      ", MBLK_FLGDELT, "");
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
14010Sstevel@tonic-gate 			    mbf[i].strf_name, mbf[i].strf_descr);
14020Sstevel@tonic-gate 		}
14030Sstevel@tonic-gate 	}
14040Sstevel@tonic-gate 	return (DCMD_OK);
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate /*
14080Sstevel@tonic-gate  * Streams flow trace walkers.
14090Sstevel@tonic-gate  */
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate int
14120Sstevel@tonic-gate strftblk_walk_init(mdb_walk_state_t *wsp)
14130Sstevel@tonic-gate {
14140Sstevel@tonic-gate 	ftblkdata_t *ftd;
14150Sstevel@tonic-gate 	dblk_t	db;
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	/* Get the dblock from the address */
14180Sstevel@tonic-gate 	if (mdb_vread(&db, sizeof (dblk_t), wsp->walk_addr) == -1) {
14190Sstevel@tonic-gate 		mdb_warn("failed to read dblk at %p", wsp->walk_addr);
14200Sstevel@tonic-gate 		return (WALK_ERR);
14210Sstevel@tonic-gate 	}
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	/* Is there any flow trace data? */
14240Sstevel@tonic-gate 	if (db.db_fthdr == NULL) {
14250Sstevel@tonic-gate 		return (WALK_DONE);
14260Sstevel@tonic-gate 	}
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)((char *)db.db_fthdr +
14290Sstevel@tonic-gate 	    offsetof(fthdr_t, first));
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	ftd = mdb_alloc(sizeof (ftblkdata_t), UM_SLEEP);
14320Sstevel@tonic-gate 	ftd->ft_ix = 0;
14330Sstevel@tonic-gate 	ftd->ft_in_evlist = B_FALSE;
14340Sstevel@tonic-gate 	wsp->walk_data = ftd;
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	return (WALK_NEXT);
14370Sstevel@tonic-gate }
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate int
14400Sstevel@tonic-gate strftblk_step(mdb_walk_state_t *wsp)
14410Sstevel@tonic-gate {
14420Sstevel@tonic-gate 	ftblkdata_t *ftd;
14430Sstevel@tonic-gate 	ftblk_t *ftbp;
14440Sstevel@tonic-gate 	int status = WALK_NEXT;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
14470Sstevel@tonic-gate 		return (WALK_DONE);
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	ftd = (ftblkdata_t *)wsp->walk_data;
14500Sstevel@tonic-gate 	ftbp = &(ftd->ft_data);
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 	if (! ftd->ft_in_evlist) {
14530Sstevel@tonic-gate 		/* Read a new ft block */
14540Sstevel@tonic-gate 		if (mdb_vread(ftbp, sizeof (ftblk_t),
14550Sstevel@tonic-gate 		    wsp->walk_addr) == -1) {
14560Sstevel@tonic-gate 			mdb_warn("failed to read ftblk at %p", wsp->walk_addr);
14570Sstevel@tonic-gate 			return (WALK_ERR);
14580Sstevel@tonic-gate 		}
14590Sstevel@tonic-gate 		/*
14600Sstevel@tonic-gate 		 * Check correctness of the index field.
14610Sstevel@tonic-gate 		 */
14620Sstevel@tonic-gate 		if (ftbp->ix < 0 || ftbp->ix > FTBLK_EVNTS) {
14630Sstevel@tonic-gate 			mdb_warn("ftblk: incorrect index value %i\n", ftbp->ix);
14640Sstevel@tonic-gate 			return (WALK_ERR);
14650Sstevel@tonic-gate 		}
14660Sstevel@tonic-gate 		ftd->ft_ix = 1;
14670Sstevel@tonic-gate 		ftd->ft_in_evlist = B_TRUE;
14680Sstevel@tonic-gate 	}
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	if (ftd->ft_ix > ftbp->ix) {
14710Sstevel@tonic-gate 		ftd->ft_in_evlist = B_FALSE;
14720Sstevel@tonic-gate 		/* End of event list reached - move to the next event block */
14730Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)ftbp->nxt;
14740Sstevel@tonic-gate 	} else {
14750Sstevel@tonic-gate 		/* Print event address */
14760Sstevel@tonic-gate 		status = wsp->walk_callback((uintptr_t)((char *)wsp->walk_addr +
14770Sstevel@tonic-gate 		    offsetof(ftblk_t, ev) +
14780Sstevel@tonic-gate 		    (ftd->ft_ix - 1) * sizeof (struct ftevnt)),
14790Sstevel@tonic-gate 		    wsp->walk_data, wsp->walk_cbdata);
14800Sstevel@tonic-gate 		ftd->ft_ix++;
14810Sstevel@tonic-gate 	}
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	return (status);
14840Sstevel@tonic-gate }
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate void
14880Sstevel@tonic-gate strftblk_walk_fini(mdb_walk_state_t *wsp)
14890Sstevel@tonic-gate {
14900Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (ftblkdata_t));
14910Sstevel@tonic-gate }
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate /*ARGSUSED*/
14940Sstevel@tonic-gate int
14950Sstevel@tonic-gate strftevent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
14960Sstevel@tonic-gate {
14970Sstevel@tonic-gate 	struct ftevnt ev;
14980Sstevel@tonic-gate 	char modname[MODMAXNAMELEN];
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
15010Sstevel@tonic-gate 		return (DCMD_USAGE);
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
15040Sstevel@tonic-gate 		mdb_printf("%?s %?s %s %s %-24s  %s\n",
15050Sstevel@tonic-gate 		    "ADDR", "MID", "EVNT", "DATA", "NAME", "EVENT");
15060Sstevel@tonic-gate 	}
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate 	if (mdb_vread(&ev, sizeof (ev), addr) == -1) {
15090Sstevel@tonic-gate 		mdb_warn("couldn't read ft event at %p", addr);
15100Sstevel@tonic-gate 		return (DCMD_ERR);
15110Sstevel@tonic-gate 	}
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %4x %4x",
15140Sstevel@tonic-gate 	    addr, ev.mid, ev.evnt, ev.data);
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	if (ev.evnt & FTEV_QMASK) {
15170Sstevel@tonic-gate 		if (mdb_readstr(modname, sizeof (modname),
15180Sstevel@tonic-gate 		    (uintptr_t)ev.mid) == -1)
15190Sstevel@tonic-gate 			mdb_warn("couldn't read module name at %p", ev.mid);
15200Sstevel@tonic-gate 		mdb_printf(" %-24s", modname);
15210Sstevel@tonic-gate 	} else
15220Sstevel@tonic-gate 		mdb_printf(" %-24a", ev.mid);
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	ft_printevent(ev.evnt);
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	mdb_printf("\n");
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 	return (DCMD_OK);
15290Sstevel@tonic-gate }
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate static void
15320Sstevel@tonic-gate ft_printevent(ushort_t ev)
15330Sstevel@tonic-gate {
15340Sstevel@tonic-gate 	ushort_t proc_ev = (ev & (FTEV_PROC_START | 0xFF)) - FTEV_PROC_START;
15350Sstevel@tonic-gate 	ushort_t alloc_ev = ev & FTEV_CALLER;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	/* Get event class first */
15380Sstevel@tonic-gate 	if (ev & FTEV_PROC_START) {
15390Sstevel@tonic-gate 		if (proc_ev >= A_SIZE(ftev_proc))
15400Sstevel@tonic-gate 			mdb_printf("  undefined");
15410Sstevel@tonic-gate 		else
15420Sstevel@tonic-gate 			mdb_printf("  %s", ftev_proc[proc_ev]);
15430Sstevel@tonic-gate 	} else if (alloc_ev >= A_SIZE(ftev_alloc))
15440Sstevel@tonic-gate 		mdb_printf("  undefined");
15450Sstevel@tonic-gate 	else
15460Sstevel@tonic-gate 		mdb_printf("  %s", ftev_alloc[alloc_ev]);
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	/* Print event modifiers, if any */
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	if (ev & FTEV_PS)
15510Sstevel@tonic-gate 		mdb_printf(" | PS");
15520Sstevel@tonic-gate 	if (ev & FTEV_CS)
15530Sstevel@tonic-gate 		mdb_printf(" | CS");
15540Sstevel@tonic-gate 	if (ev & FTEV_ISWR)
15550Sstevel@tonic-gate 		mdb_printf(" | ISWR");
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate /*
15590Sstevel@tonic-gate  * Help functions for STREAMS debugging facilities.
15600Sstevel@tonic-gate  */
15610Sstevel@tonic-gate void
15620Sstevel@tonic-gate queue_help(void)
15630Sstevel@tonic-gate {
15640Sstevel@tonic-gate 	mdb_printf("Print queue information for a given queue pointer.\n"
15650Sstevel@tonic-gate 	    "\nWithout the address of a \"queue_t\" structure given, print "
15660Sstevel@tonic-gate 	    "information about all\n"
15670Sstevel@tonic-gate 	    "queues in the \"queue_cache\".\n\n"
15680Sstevel@tonic-gate 	    "Options:\n"
15690Sstevel@tonic-gate 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
15700Sstevel@tonic-gate 	    "	-q:\t\tbe quiet - print queue pointer only\n"
15710Sstevel@tonic-gate 	    "	-f flag:\tprint only queues with flag set\n"
15720Sstevel@tonic-gate 	    "	-F flag:\tprint only queues with flag NOT set\n"
15730Sstevel@tonic-gate 	    "	-m modname:\tprint only queues with specified module name\n"
15740Sstevel@tonic-gate 	    "	-s syncq_addr:\tprint only queues which use specified syncq\n\n"
15750Sstevel@tonic-gate 	    "Available conversions:\n"
15760Sstevel@tonic-gate 	    "	q2rdq:		given a queue addr print read queue pointer\n"
15770Sstevel@tonic-gate 	    "	q2wrq:		given a queue addr print write queue pointer\n"
15780Sstevel@tonic-gate 	    "	q2otherq:	given a queue addr print other queue pointer\n"
15790Sstevel@tonic-gate 	    "	q2syncq:	given a queue addr print syncq pointer"
15800Sstevel@tonic-gate 		" (::help syncq)\n"
15810Sstevel@tonic-gate 	    "	q2stream:	given a queue addr print its stream pointer\n"
15820Sstevel@tonic-gate 		"\t\t(see ::help stream and ::help stdata)\n\n"
15830Sstevel@tonic-gate 	    "To walk q_next pointer of the queue use\n"
15840Sstevel@tonic-gate 	    "	queue_addr::walk qnext\n");
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate void
15880Sstevel@tonic-gate syncq_help(void)
15890Sstevel@tonic-gate {
15900Sstevel@tonic-gate 	mdb_printf("Print syncq information for a given syncq pointer.\n"
15910Sstevel@tonic-gate 	    "\nWithout the address of a \"syncq_t\" structure given, print "
15920Sstevel@tonic-gate 	    "information about all\n"
15930Sstevel@tonic-gate 	    "syncqs in the \"syncq_cache\".\n\n"
15940Sstevel@tonic-gate 	    "Options:\n"
15950Sstevel@tonic-gate 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
15960Sstevel@tonic-gate 	    "	-q:\t\tbe quiet - print syncq pointer only\n"
15970Sstevel@tonic-gate 	    "	-f flag:\tprint only syncqs with flag set\n"
15980Sstevel@tonic-gate 	    "	-F flag:\tprint only syncqs with flag NOT set\n"
15990Sstevel@tonic-gate 	    "	-t type:\tprint only syncqs with specified type\n"
16000Sstevel@tonic-gate 	    "	-T type:\tprint only syncqs with do NOT have specified type\n\n"
16010Sstevel@tonic-gate 	    "Available conversions:\n"
16020Sstevel@tonic-gate 	    "	syncq2q:\tgiven a syncq addr print queue address of the\n"
16030Sstevel@tonic-gate 	    "\t\t\tenclosing queue, if it is part of a queue\n\n"
16040Sstevel@tonic-gate 	    "See also: \"::help queue\" and \"::help stdata\"\n");
16050Sstevel@tonic-gate }
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate void
16080Sstevel@tonic-gate stdata_help(void)
16090Sstevel@tonic-gate {
16100Sstevel@tonic-gate 	mdb_printf("Print stdata information for a given stdata pointer.\n"
16110Sstevel@tonic-gate 	    "\nWithout the address of a \"stdata_t\" structure given, print "
16120Sstevel@tonic-gate 	    "information about all\n"
16130Sstevel@tonic-gate 	    "stream head pointers from the \"stream_head_cache\".\n\n"
16140Sstevel@tonic-gate 	    "Fields printed:\n"
16150Sstevel@tonic-gate 	    "	ADDR:\tstream head address\n"
16160Sstevel@tonic-gate 	    "	WRQ:\twrite queue pointer\n"
16170Sstevel@tonic-gate 	    "	FLAGS:\tstream head flags (use -v to show in symbolic form)\n"
16180Sstevel@tonic-gate 	    "	VNODE:\tstream vnode pointer\n"
16190Sstevel@tonic-gate 	    "	N/A:\tpushcount and anchor positions\n"
16200Sstevel@tonic-gate 	    "	REF:\tstream head reference counter\n\n"
16210Sstevel@tonic-gate 	    "Options:\n"
16220Sstevel@tonic-gate 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
16230Sstevel@tonic-gate 	    "	-q:\t\tbe quiet - print stdata pointer only\n"
16240Sstevel@tonic-gate 	    "	-f flag:\tprint only stdatas with flag set\n"
16250Sstevel@tonic-gate 	    "	-F flag:\tprint only stdatas with flag NOT set\n\n"
16260Sstevel@tonic-gate 	    "Available conversions:\n"
16270Sstevel@tonic-gate 	    "	str2mate:\tgiven a stream head addr print its mate\n"
16280Sstevel@tonic-gate 	    "	str2wrq:\tgiven a stream head addr print its write queue\n\n"
16290Sstevel@tonic-gate 	    "See also: \"::help queue\" and \"::help syncq\"\n");
16300Sstevel@tonic-gate }
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate void
16330Sstevel@tonic-gate mblk_help(void)
16340Sstevel@tonic-gate {
16350Sstevel@tonic-gate 	mdb_printf("Print mblock information for a given mblk pointer.\n"
16360Sstevel@tonic-gate 	    "Without the address, print information about all mblocks.\n\n"
16370Sstevel@tonic-gate 	    "Fields printed:\n"
16380Sstevel@tonic-gate 	    "	ADDR:\tmblk address\n"
16390Sstevel@tonic-gate 	    "	FL:\tFlags\n"
16400Sstevel@tonic-gate 	    "	TYPE:\tType of corresponding dblock\n"
16410Sstevel@tonic-gate 	    "	LEN:\tData length as b_wptr - b_rptr\n"
16420Sstevel@tonic-gate 	    "	BLEN:\tDblock space as db_lim - db_base\n"
16430Sstevel@tonic-gate 	    "	RPTR:\tRead pointer\n"
16440Sstevel@tonic-gate 	    "	DBLK:\tDblock pointer\n\n"
16450Sstevel@tonic-gate 	    "Options:\n"
16460Sstevel@tonic-gate 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
16470Sstevel@tonic-gate 	    "	-q:\t\tbe quiet - print mblk pointer only\n"
16480Sstevel@tonic-gate 	    "	-d dbaddr:\t\tprint mblks with specified dblk address\n"
16490Sstevel@tonic-gate 	    "	-f flag:\tprint only mblks with flag set\n"
16500Sstevel@tonic-gate 	    "	-F flag:\tprint only mblks with flag NOT set\n"
16510Sstevel@tonic-gate 	    "	-t type:\tprint only mblks of specified db_type\n"
16520Sstevel@tonic-gate 	    "	-T type:\tprint only mblks other then the specified db_type\n"
16530Sstevel@tonic-gate 	    "	-l len:\t\ttprint only mblks with MBLKL == len\n"
16540Sstevel@tonic-gate 	    "	-L len:\t\tprint only mblks with MBLKL <= len \n"
16550Sstevel@tonic-gate 	    "	-G len:\t\tprint only mblks with MBLKL >= len \n"
16560Sstevel@tonic-gate 	    "	-b len:\t\tprint only mblks with db_lim - db_base == len\n"
16570Sstevel@tonic-gate 	    "\n");
16580Sstevel@tonic-gate }
1659