1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
30*0Sstevel@tonic-gate #include <mdb/mdb_ks.h>
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/strsubr.h>
34*0Sstevel@tonic-gate #include <sys/stream.h>
35*0Sstevel@tonic-gate #include <sys/modctl.h>
36*0Sstevel@tonic-gate #include <sys/strft.h>
37*0Sstevel@tonic-gate #include <sys/strsun.h>
38*0Sstevel@tonic-gate #include <sys/sysmacros.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include "streams.h"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate typedef struct str_flags {
43*0Sstevel@tonic-gate 	uint_t strf_flag;
44*0Sstevel@tonic-gate 	const char *strf_name;
45*0Sstevel@tonic-gate 	const char *strf_descr;
46*0Sstevel@tonic-gate } strflags_t;
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate typedef struct str_types {
49*0Sstevel@tonic-gate 	const char *strt_name;
50*0Sstevel@tonic-gate 	int strt_value;
51*0Sstevel@tonic-gate 	const char *strt_descr;
52*0Sstevel@tonic-gate } strtypes_t;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate typedef struct ftblk_data {
55*0Sstevel@tonic-gate 	ftblk_t ft_data;	/* Copy of ftblk */
56*0Sstevel@tonic-gate 	int 	ft_ix;		/* Index in event list */
57*0Sstevel@tonic-gate 	boolean_t ft_in_evlist;	/* Iterating through evlist */
58*0Sstevel@tonic-gate } ftblkdata_t;
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate typedef void qprint_func(queue_t *, queue_t *);
61*0Sstevel@tonic-gate typedef void sdprint_func(stdata_t *, stdata_t *);
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate #define	SF(flag)	flag, #flag
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate /*
66*0Sstevel@tonic-gate  * Queue flags
67*0Sstevel@tonic-gate  */
68*0Sstevel@tonic-gate static const strflags_t qf[] = {
69*0Sstevel@tonic-gate 	{ SF(QENAB), 		"Queue is already enabled to run"	},
70*0Sstevel@tonic-gate 	{ SF(QWANTR),		"Someone wants to read Q"		},
71*0Sstevel@tonic-gate 	{ SF(QWANTW),		"Someone wants to write Q"		},
72*0Sstevel@tonic-gate 	{ SF(QFULL),		"Q is considered full"			},
73*0Sstevel@tonic-gate 	{ SF(QREADR),		"This is the reader (first) Q"		},
74*0Sstevel@tonic-gate 	{ SF(QUSE),		"This queue in use (allocation)"	},
75*0Sstevel@tonic-gate 	{ SF(QNOENB),		"Don't enable Q via putq"		},
76*0Sstevel@tonic-gate 	{ SF(QWANTRMQSYNC),	"Want to remove sync stream Q"		},
77*0Sstevel@tonic-gate 	{ SF(QBACK),		"queue has been back-enabled"		},
78*0Sstevel@tonic-gate 	{ SF(0x00000200),	"unused (was QHLIST)"			},
79*0Sstevel@tonic-gate 	{ SF(0x00000400),	"unused (was QUNSAFE)"			},
80*0Sstevel@tonic-gate 	{ SF(QPAIR),		"per queue-pair syncq"			},
81*0Sstevel@tonic-gate 	{ SF(QPERQ),		"per queue-instance syncq"		},
82*0Sstevel@tonic-gate 	{ SF(QPERMOD),		"per module syncq"			},
83*0Sstevel@tonic-gate 	{ SF(QMTSAFE),		"stream module is MT-safe"		},
84*0Sstevel@tonic-gate 	{ SF(QMTOUTPERIM),	"Has outer perimeter"			},
85*0Sstevel@tonic-gate 	{ SF(QINSERVICE),	"service routine executing"		},
86*0Sstevel@tonic-gate 	{ SF(QWCLOSE),		"will not be enabled"			},
87*0Sstevel@tonic-gate 	{ SF(QEND),		"last queue in stream"			},
88*0Sstevel@tonic-gate 	{ SF(QWANTWSYNC),	"Streamhead wants to write Q" 		},
89*0Sstevel@tonic-gate 	{ SF(QSYNCSTR),		"Q supports Synchronous STREAMS"	},
90*0Sstevel@tonic-gate 	{ SF(QISDRV),		"the Queue is attached to a driver"	},
91*0Sstevel@tonic-gate 	{ SF(0x00400000),	"unused (was QHOT)"			},
92*0Sstevel@tonic-gate 	{ SF(0x00800000),	"unused (was QNEXTHOT)"			},
93*0Sstevel@tonic-gate 	{ SF(0x01000000),	"unused (was _QNEXTLESS)"		},
94*0Sstevel@tonic-gate 	{ SF(0x02000000),	"unused"				},
95*0Sstevel@tonic-gate 	{ SF(_QINSERTING),	"module is inserted with _I_INSERT"	},
96*0Sstevel@tonic-gate 	{ SF(_QREMOVING)	"module is removed with _I_REMOVE"	},
97*0Sstevel@tonic-gate 	{ SF(_QASSOCIATED),	"queue is associated with a device"	},
98*0Sstevel@tonic-gate 	{ SF(0),		NULL }
99*0Sstevel@tonic-gate };
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate /*
102*0Sstevel@tonic-gate  * Syncq flags
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate static const struct str_flags sqf[] = {
105*0Sstevel@tonic-gate 	{ SF(SQ_EXCL),		"Exclusive access to inner perimeter"	},
106*0Sstevel@tonic-gate 	{ SF(SQ_BLOCKED),	"qprocsoff in progress"			},
107*0Sstevel@tonic-gate 	{ SF(SQ_FROZEN),	"freezestr in progress"			},
108*0Sstevel@tonic-gate 	{ SF(SQ_WRITER),	"qwriter(OUTER) pending or running"	},
109*0Sstevel@tonic-gate 	{ SF(SQ_MESSAGES),	"There are messages on syncq"		},
110*0Sstevel@tonic-gate 	{ SF(SQ_WANTWAKEUP)	"Thread waiting on sq_wait"		},
111*0Sstevel@tonic-gate 	{ SF(SQ_WANTEXWAKEUP),	"Thread waiting on sq_exwait"		},
112*0Sstevel@tonic-gate 	{ SF(SQ_EVENTS),	"There are events on syncq"		},
113*0Sstevel@tonic-gate 	{ SF(0),		NULL					}
114*0Sstevel@tonic-gate };
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate /*
117*0Sstevel@tonic-gate  * Syncq types
118*0Sstevel@tonic-gate  */
119*0Sstevel@tonic-gate static const struct str_flags sqt[] = {
120*0Sstevel@tonic-gate 	{ SF(SQ_CIPUT),		"Concurrent inner put procedure"	},
121*0Sstevel@tonic-gate 	{ SF(SQ_CISVC),		"Concurrent inner svc procedure"	},
122*0Sstevel@tonic-gate 	{ SF(SQ_CIOC),		"Concurrent inner open/close"		},
123*0Sstevel@tonic-gate 	{ SF(SQ_CICB),		"Concurrent inner callback"		},
124*0Sstevel@tonic-gate 	{ SF(SQ_COPUT),		"Concurrent outer put procedure"	},
125*0Sstevel@tonic-gate 	{ SF(SQ_COSVC),		"Concurrent outer svc procedure"	},
126*0Sstevel@tonic-gate 	{ SF(SQ_COOC),		"Concurrent outer open/close"		},
127*0Sstevel@tonic-gate 	{ SF(SQ_COCB),		"Concurrent outer callback"		},
128*0Sstevel@tonic-gate 	{ SF(0),		NULL					}
129*0Sstevel@tonic-gate };
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate /*
132*0Sstevel@tonic-gate  * Stdata flags
133*0Sstevel@tonic-gate  */
134*0Sstevel@tonic-gate static const struct str_flags stdf[] = {
135*0Sstevel@tonic-gate 	{ SF(IOCWAIT),		"someone is doing an ioctl"		},
136*0Sstevel@tonic-gate 	{ SF(RSLEEP),		"someone wants to read/recv msg"	},
137*0Sstevel@tonic-gate 	{ SF(WSLEEP),		"someone wants to write"		},
138*0Sstevel@tonic-gate 	{ SF(STRPRI),		"an M_PCPROTO is at stream head"	},
139*0Sstevel@tonic-gate 	{ SF(STRHUP),		"device has vanished"			},
140*0Sstevel@tonic-gate 	{ SF(STWOPEN),		"waiting for 1st open"			},
141*0Sstevel@tonic-gate 	{ SF(STPLEX),		"stream is being multiplexed"		},
142*0Sstevel@tonic-gate 	{ SF(STRISTTY),		"stream is a terminal"			},
143*0Sstevel@tonic-gate 	{ SF(STRGETINPROG),	"(k)strgetmsg is running"		},
144*0Sstevel@tonic-gate 	{ SF(IOCWAITNE),	"STR_NOERROR ioctl running"		},
145*0Sstevel@tonic-gate 	{ SF(STRDERR),		"fatal read error from M_ERROR"		},
146*0Sstevel@tonic-gate 	{ SF(STWRERR),		"fatal write error from M_ERROR"	},
147*0Sstevel@tonic-gate 	{ SF(STRDERRNONPERSIST), "nonpersistent read errors"		},
148*0Sstevel@tonic-gate 	{ SF(STWRERRNONPERSIST), "nonpersistent write errors"		},
149*0Sstevel@tonic-gate 	{ SF(STRCLOSE),		"wait for a close to complete"		},
150*0Sstevel@tonic-gate 	{ SF(SNDMREAD),		"used for read notification"		},
151*0Sstevel@tonic-gate 	{ SF(OLDNDELAY),	"use old NDELAY TTY semantics"		},
152*0Sstevel@tonic-gate 	{ SF(0x00020000),	"unused"				},
153*0Sstevel@tonic-gate 	{ SF(0x00040000),	"unused"				},
154*0Sstevel@tonic-gate 	{ SF(STRTOSTOP),	"block background writes"		},
155*0Sstevel@tonic-gate 	{ SF(0x00100000),	"unused"				},
156*0Sstevel@tonic-gate 	{ SF(0x00200000),	"unused"				},
157*0Sstevel@tonic-gate 	{ SF(STRMOUNT),		"stream is mounted"			},
158*0Sstevel@tonic-gate 	{ SF(STRNOTATMARK),	"Not at mark (when empty read q)"	},
159*0Sstevel@tonic-gate 	{ SF(STRDELIM),		"generate delimited messages"		},
160*0Sstevel@tonic-gate 	{ SF(STRATMARK),	"at mark (due to MSGMARKNEXT)"		},
161*0Sstevel@tonic-gate 	{ SF(STZCNOTIFY),	"wait for zerocopy mblk to be acked"	},
162*0Sstevel@tonic-gate 	{ SF(STRPLUMB),		"stream plumbing changes in progress"	},
163*0Sstevel@tonic-gate 	{ SF(STREOF),  		"End-of-file indication"		},
164*0Sstevel@tonic-gate 	{ SF(STREOPENFAIL),	"re-open has failed"			},
165*0Sstevel@tonic-gate 	{ SF(STRMATE),		"this stream is a mate"			},
166*0Sstevel@tonic-gate 	{ SF(STRHASLINKS),	"there are I_LINKs under this stream"	},
167*0Sstevel@tonic-gate 	{ SF(0),		NULL					}
168*0Sstevel@tonic-gate };
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate static const struct str_flags mbf[] = {
171*0Sstevel@tonic-gate 	{ SF(MSGMARK), 		"last byte of message is marked"	},
172*0Sstevel@tonic-gate 	{ SF(MSGNOLOOP),	"don't loop message to write side"	},
173*0Sstevel@tonic-gate 	{ SF(MSGDELIM),		"message is delimited"			},
174*0Sstevel@tonic-gate 	{ SF(0x08),		"unused"				},
175*0Sstevel@tonic-gate 	{ SF(MSGMARKNEXT), 	"Private: b_next's first byte marked"	},
176*0Sstevel@tonic-gate 	{ SF(MSGNOTMARKNEXT),	"Private: ... not marked"		},
177*0Sstevel@tonic-gate 	{ SF(MSGHASREF),	"Private: msg has reference to owner"	},
178*0Sstevel@tonic-gate 	{ SF(0),		NULL					}
179*0Sstevel@tonic-gate };
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate #define	M_DATA_T 0xff
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate static const strtypes_t mbt[] = {
184*0Sstevel@tonic-gate 	{ "M_DATA",	M_DATA_T,	"regular data"			},
185*0Sstevel@tonic-gate 	{ "M_PROTO",	M_PROTO,	"protocol control"		},
186*0Sstevel@tonic-gate 	{ "M_MULTIDATA", M_MULTIDATA,	"multidata"			},
187*0Sstevel@tonic-gate 	{ "M_BREAK",	M_BREAK,	"line break"			},
188*0Sstevel@tonic-gate 	{ "M_PASSFP",	M_PASSFP,	"pass file pointer"		},
189*0Sstevel@tonic-gate 	{ "M_EVENT",	M_EVENT,	"Obsoleted: do not use"		},
190*0Sstevel@tonic-gate 	{ "M_SIG",	M_SIG,		"generate process signal"	},
191*0Sstevel@tonic-gate 	{ "M_DELAY",	M_DELAY,	"real-time xmit delay"		},
192*0Sstevel@tonic-gate 	{ "M_CTL",	M_CTL,		"device-specific control message" },
193*0Sstevel@tonic-gate 	{ "M_IOCTL",	M_IOCTL,	"ioctl; set/get params"		},
194*0Sstevel@tonic-gate 	{ "M_SETOPTS",	M_SETOPTS,	"set stream head options"	},
195*0Sstevel@tonic-gate 	{ "M_RSE",	M_RSE,		"reserved for RSE use only"	},
196*0Sstevel@tonic-gate 	{ "M_IOCACK",	M_IOCACK,	"acknowledge ioctl"		},
197*0Sstevel@tonic-gate 	{ "M_IOCNAK",	M_IOCNAK,	"negative ioctl acknowledge"	},
198*0Sstevel@tonic-gate 	{ "M_PCPROTO",	M_PCPROTO,	"priority proto message"	},
199*0Sstevel@tonic-gate 	{ "M_PCSIG",	M_PCSIG,	"generate process signal"	},
200*0Sstevel@tonic-gate 	{ "M_READ",	M_READ,		"generate read notification"	},
201*0Sstevel@tonic-gate 	{ "M_FLUSH",	M_FLUSH,	"flush your queues"		},
202*0Sstevel@tonic-gate 	{ "M_STOP",	M_STOP,		"stop transmission immediately" },
203*0Sstevel@tonic-gate 	{ "M_START",	M_START,	"restart transmission after stop" },
204*0Sstevel@tonic-gate 	{ "M_HANGUP",	M_HANGUP,	"line disconnect"		},
205*0Sstevel@tonic-gate 	{ "M_ERROR",	M_ERROR,	"send error to stream head"	},
206*0Sstevel@tonic-gate 	{ "M_COPYIN",	M_COPYIN,	"request to copyin data"	},
207*0Sstevel@tonic-gate 	{ "M_COPYOUT",	M_COPYOUT,	"request to copyout data"	},
208*0Sstevel@tonic-gate 	{ "M_IOCDATA",	M_IOCDATA,	"response to M_COPYIN and M_COPYOUT" },
209*0Sstevel@tonic-gate 	{ "M_PCRSE",	M_PCRSE,	"reserved for RSE use only"	},
210*0Sstevel@tonic-gate 	{ "M_STOPI",	M_STOPI,	"stop reception immediately"	},
211*0Sstevel@tonic-gate 	{ "M_STARTI",	M_STARTI,	"restart reception after stop"	},
212*0Sstevel@tonic-gate 	{ "M_PCEVENT",	M_PCEVENT,	"Obsoleted: do not use"		},
213*0Sstevel@tonic-gate 	{ "M_UNHANGUP",	M_UNHANGUP,	"line reconnect"		},
214*0Sstevel@tonic-gate };
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate /* Allocation flow trace events, starting from 0 */
217*0Sstevel@tonic-gate static const char *ftev_alloc[] = {
218*0Sstevel@tonic-gate /* 0 */	":allocb",
219*0Sstevel@tonic-gate /* 1 */	":esballoc",
220*0Sstevel@tonic-gate /* 2 */	":desballoc",
221*0Sstevel@tonic-gate /* 3 */	":esballoca",
222*0Sstevel@tonic-gate /* 4 */	":desballoca",
223*0Sstevel@tonic-gate /* 5 */	":allocbig",
224*0Sstevel@tonic-gate /* 6 */	":allocbw",
225*0Sstevel@tonic-gate /* 7 */	":bcallocb",
226*0Sstevel@tonic-gate /* 8 */	":freeb",
227*0Sstevel@tonic-gate /* 9 */	":dupb",
228*0Sstevel@tonic-gate /* A */	":copyb",
229*0Sstevel@tonic-gate };
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate #define	FTEV_PROC_START FTEV_PUT
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate /* Procedures recorded by flow tracing, starting from 0x100 */
234*0Sstevel@tonic-gate static const char *ftev_proc[] = {
235*0Sstevel@tonic-gate /* 100 */	":put",
236*0Sstevel@tonic-gate /* 101 */	":undefined (0x101)",
237*0Sstevel@tonic-gate /* 102 */	":undefined (0x102)",
238*0Sstevel@tonic-gate /* 103 */	":undefined (0x103)",
239*0Sstevel@tonic-gate /* 104 */	":undefined (0x104)",
240*0Sstevel@tonic-gate /* 105 */	":putq",
241*0Sstevel@tonic-gate /* 106 */	":getq",
242*0Sstevel@tonic-gate /* 107 */	":rmvq",
243*0Sstevel@tonic-gate /* 108 */	":insq",
244*0Sstevel@tonic-gate /* 109 */	":putbq",
245*0Sstevel@tonic-gate /* 10A */	":flushq",
246*0Sstevel@tonic-gate /* 10B */	":undefined (0x10b)",
247*0Sstevel@tonic-gate /* 10C */ 	":undefined (0x10c)",
248*0Sstevel@tonic-gate /* 10D */	":putnext",
249*0Sstevel@tonic-gate /* 10E */	":rwnext",
250*0Sstevel@tonic-gate };
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate static const char *db_control_types[] = {
253*0Sstevel@tonic-gate /* 00 */	"data",
254*0Sstevel@tonic-gate /* 01 */	"proto",
255*0Sstevel@tonic-gate /* 02 */	"multidata",
256*0Sstevel@tonic-gate /* 03 */	"unused (0x03)",
257*0Sstevel@tonic-gate /* 04 */	"unused (0x04)",
258*0Sstevel@tonic-gate /* 05 */	"unused (0x05)",
259*0Sstevel@tonic-gate /* 06 */	"unused (0x06)",
260*0Sstevel@tonic-gate /* 07 */	"unused (0x07)",
261*0Sstevel@tonic-gate /* 08 */	"break",
262*0Sstevel@tonic-gate /* 09 */	"passfp",
263*0Sstevel@tonic-gate /* 0a */	"event",
264*0Sstevel@tonic-gate /* 0b */	"sig",
265*0Sstevel@tonic-gate /* 0c */	"delay",
266*0Sstevel@tonic-gate /* 0d */	"ctl",
267*0Sstevel@tonic-gate /* 0e */	"ioctl",
268*0Sstevel@tonic-gate /* 0f */	"unused",
269*0Sstevel@tonic-gate /* 10 */	"setopts",
270*0Sstevel@tonic-gate /* 11 */	"rse",
271*0Sstevel@tonic-gate };
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate static const char *db_control_hipri_types[] = {
274*0Sstevel@tonic-gate /* 81 */	"iocack",
275*0Sstevel@tonic-gate /* 82 */	"iocnak",
276*0Sstevel@tonic-gate /* 83 */	"pcproto",
277*0Sstevel@tonic-gate /* 84 */	"pcsig",
278*0Sstevel@tonic-gate /* 85 */	"read",
279*0Sstevel@tonic-gate /* 86 */	"flush",
280*0Sstevel@tonic-gate /* 87 */	"stop",
281*0Sstevel@tonic-gate /* 88 */	"start",
282*0Sstevel@tonic-gate /* 89 */	"hangup",
283*0Sstevel@tonic-gate /* 8a */	"error",
284*0Sstevel@tonic-gate /* 8b */	"copyin",
285*0Sstevel@tonic-gate /* 8c */	"copyout",
286*0Sstevel@tonic-gate /* 8d */	"iocdata",
287*0Sstevel@tonic-gate /* 8e */	"pcrse",
288*0Sstevel@tonic-gate /* 8f */	"stopi",
289*0Sstevel@tonic-gate /* 90 */	"starti",
290*0Sstevel@tonic-gate /* 91 */	"pcevent",
291*0Sstevel@tonic-gate /* 92 */	"unhangup",
292*0Sstevel@tonic-gate };
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate #define	A_SIZE(a) (sizeof (a) / sizeof (a[0]))
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate static void ft_printevent(ushort_t);
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate static int
300*0Sstevel@tonic-gate streams_parse_flag(const strflags_t ftable[], const char *arg, uint32_t *flag)
301*0Sstevel@tonic-gate {
302*0Sstevel@tonic-gate 	int i;
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	for (i = 0; ftable[i].strf_name != NULL; i++) {
305*0Sstevel@tonic-gate 		if (strcasecmp(arg, ftable[i].strf_name) == 0) {
306*0Sstevel@tonic-gate 			*flag |= (1 << i);
307*0Sstevel@tonic-gate 			return (0);
308*0Sstevel@tonic-gate 		}
309*0Sstevel@tonic-gate 	}
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	return (-1);
312*0Sstevel@tonic-gate }
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate static void
315*0Sstevel@tonic-gate streams_flag_usage(const strflags_t ftable[])
316*0Sstevel@tonic-gate {
317*0Sstevel@tonic-gate 	int i;
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	for (i = 0; ftable[i].strf_name != NULL; i++)
320*0Sstevel@tonic-gate 		mdb_printf("%-14s %s\n",
321*0Sstevel@tonic-gate 		    ftable[i].strf_name, ftable[i].strf_descr);
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate static int
325*0Sstevel@tonic-gate streams_parse_type(const strtypes_t ftable[], const char *arg, uint32_t *flag)
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate 	int i;
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	for (i = 0; ftable[i].strt_name != NULL; i++) {
330*0Sstevel@tonic-gate 		if (strcasecmp(arg, ftable[i].strt_name) == 0) {
331*0Sstevel@tonic-gate 			*flag = ftable[i].strt_value;
332*0Sstevel@tonic-gate 			return (0);
333*0Sstevel@tonic-gate 		}
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	return (-1);
337*0Sstevel@tonic-gate }
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate static void
340*0Sstevel@tonic-gate streams_type_usage(const strtypes_t ftable[])
341*0Sstevel@tonic-gate {
342*0Sstevel@tonic-gate 	int i;
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	for (i = 0; ftable[i].strt_name != NULL; i++)
345*0Sstevel@tonic-gate 		mdb_printf("%-12s %s\n",
346*0Sstevel@tonic-gate 		    ftable[i].strt_name, ftable[i].strt_descr);
347*0Sstevel@tonic-gate }
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate int
350*0Sstevel@tonic-gate queue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
351*0Sstevel@tonic-gate {
352*0Sstevel@tonic-gate 	const int QUEUE_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15);
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	char name[MODMAXNAMELEN];
355*0Sstevel@tonic-gate 	int nblks = 0;
356*0Sstevel@tonic-gate 	uintptr_t maddr;
357*0Sstevel@tonic-gate 	mblk_t mblk;
358*0Sstevel@tonic-gate 	queue_t q;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	const char *mod = NULL, *flag = NULL, *not_flag = NULL;
361*0Sstevel@tonic-gate 	uint_t quiet = FALSE;
362*0Sstevel@tonic-gate 	uint_t verbose = FALSE;
363*0Sstevel@tonic-gate 	uint32_t mask = 0, not_mask = 0;
364*0Sstevel@tonic-gate 	uintptr_t syncq = 0;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
367*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`queue_cache", "genunix`queue",
368*0Sstevel@tonic-gate 		    argc, argv) == -1) {
369*0Sstevel@tonic-gate 			mdb_warn("failed to walk queue cache");
370*0Sstevel@tonic-gate 			return (DCMD_ERR);
371*0Sstevel@tonic-gate 		}
372*0Sstevel@tonic-gate 		return (DCMD_OK);
373*0Sstevel@tonic-gate 	}
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
376*0Sstevel@tonic-gate 		quiet = TRUE;
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
379*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
380*0Sstevel@tonic-gate 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
381*0Sstevel@tonic-gate 	    'm', MDB_OPT_STR, &mod,
382*0Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &flag,
383*0Sstevel@tonic-gate 	    'F', MDB_OPT_STR, &not_flag,
384*0Sstevel@tonic-gate 	    's', MDB_OPT_UINTPTR, &syncq,
385*0Sstevel@tonic-gate 	    NULL) != argc)
386*0Sstevel@tonic-gate 		return (DCMD_USAGE);
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	/*
389*0Sstevel@tonic-gate 	 * If any of the filtering flags is specified, don't print anything
390*0Sstevel@tonic-gate 	 * except the matching pointer.
391*0Sstevel@tonic-gate 	 */
392*0Sstevel@tonic-gate 	if (flag != NULL || not_flag != NULL || mod != NULL || syncq != NULL)
393*0Sstevel@tonic-gate 		quiet = TRUE;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !quiet) {
396*0Sstevel@tonic-gate 		mdb_printf("%?s %-13s %6s %4s\n",
397*0Sstevel@tonic-gate 		    "ADDR", "MODULE", "FLAGS", "NBLK");
398*0Sstevel@tonic-gate 	}
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	if (flag != NULL && streams_parse_flag(qf, flag, &mask) == -1) {
401*0Sstevel@tonic-gate 		mdb_warn("unrecognized queue flag '%s'\n", flag);
402*0Sstevel@tonic-gate 		streams_flag_usage(qf);
403*0Sstevel@tonic-gate 		return (DCMD_USAGE);
404*0Sstevel@tonic-gate 	}
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	if (not_flag != NULL &&
407*0Sstevel@tonic-gate 	    streams_parse_flag(qf, not_flag, &not_mask) == -1) {
408*0Sstevel@tonic-gate 		mdb_warn("unrecognized queue flag '%s'\n", flag);
409*0Sstevel@tonic-gate 		streams_flag_usage(qf);
410*0Sstevel@tonic-gate 		return (DCMD_USAGE);
411*0Sstevel@tonic-gate 	}
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	if (mdb_vread(&q, sizeof (q), addr) == -1) {
414*0Sstevel@tonic-gate 		mdb_warn("couldn't read queue at %p", addr);
415*0Sstevel@tonic-gate 		return (DCMD_ERR);
416*0Sstevel@tonic-gate 	}
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	for (maddr = (uintptr_t)q.q_first; maddr != NULL; nblks++) {
419*0Sstevel@tonic-gate 		if (mdb_vread(&mblk, sizeof (mblk), maddr) == -1) {
420*0Sstevel@tonic-gate 			mdb_warn("couldn't read mblk %p for queue %p",
421*0Sstevel@tonic-gate 			    maddr, addr);
422*0Sstevel@tonic-gate 			break;
423*0Sstevel@tonic-gate 		}
424*0Sstevel@tonic-gate 		maddr = (uintptr_t)mblk.b_next;
425*0Sstevel@tonic-gate 	}
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 	(void) mdb_qname(&q, name, sizeof (name));
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	/*
430*0Sstevel@tonic-gate 	 * If queue doesn't pass filtering criteria, don't print anything and
431*0Sstevel@tonic-gate 	 * just return.
432*0Sstevel@tonic-gate 	 */
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	if (mod != NULL && strcmp(mod, name) != 0)
435*0Sstevel@tonic-gate 		return (DCMD_OK);
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	if (mask != 0 && !(q.q_flag & mask))
438*0Sstevel@tonic-gate 		return (DCMD_OK);
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	if (not_mask != 0 && (q.q_flag & not_mask))
441*0Sstevel@tonic-gate 		return (DCMD_OK);
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 	if (syncq != 0 && q.q_syncq != (syncq_t *)syncq)
444*0Sstevel@tonic-gate 		return (DCMD_OK);
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	/*
447*0Sstevel@tonic-gate 	 * Options are specified for filtering, so If any option is specified on
448*0Sstevel@tonic-gate 	 * the command line, just print address and exit.
449*0Sstevel@tonic-gate 	 */
450*0Sstevel@tonic-gate 	if (quiet) {
451*0Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
452*0Sstevel@tonic-gate 		return (DCMD_OK);
453*0Sstevel@tonic-gate 	}
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	mdb_printf("%0?p %-13s %06x %4d %0?p\n",
456*0Sstevel@tonic-gate 	    addr, name, q.q_flag, nblks, q.q_first);
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	if (verbose) {
459*0Sstevel@tonic-gate 		int i, arm = 0;
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 		for (i = 0; qf[i].strf_name != NULL; i++) {
462*0Sstevel@tonic-gate 			if (!(q.q_flag & (1 << i)))
463*0Sstevel@tonic-gate 				continue;
464*0Sstevel@tonic-gate 			if (!arm) {
465*0Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
466*0Sstevel@tonic-gate 				    QUEUE_FLGDELT, "", QUEUE_FLGDELT, "");
467*0Sstevel@tonic-gate 				arm = 1;
468*0Sstevel@tonic-gate 			} else
469*0Sstevel@tonic-gate 				mdb_printf("%*s      ", QUEUE_FLGDELT, "");
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
472*0Sstevel@tonic-gate 			    qf[i].strf_name, qf[i].strf_descr);
473*0Sstevel@tonic-gate 		}
474*0Sstevel@tonic-gate 	}
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	return (DCMD_OK);
477*0Sstevel@tonic-gate }
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate int
480*0Sstevel@tonic-gate syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
481*0Sstevel@tonic-gate {
482*0Sstevel@tonic-gate 	const int SYNC_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 1);
483*0Sstevel@tonic-gate 	const int SYNC_TYPDELT = (int)(sizeof (uintptr_t) * 2 + 5);
484*0Sstevel@tonic-gate 	syncq_t sq;
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	const char *flag = NULL, *not_flag = NULL;
487*0Sstevel@tonic-gate 	const char *typ = NULL, *not_typ = NULL;
488*0Sstevel@tonic-gate 	uint_t verbose = FALSE;
489*0Sstevel@tonic-gate 	uint_t quiet = FALSE;
490*0Sstevel@tonic-gate 	uint32_t mask = 0, not_mask = 0;
491*0Sstevel@tonic-gate 	uint32_t tmask = 0, not_tmask = 0;
492*0Sstevel@tonic-gate 	uint8_t sqtype = 0;
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
495*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`syncq_cache", "genunix`syncq",
496*0Sstevel@tonic-gate 		    argc, argv) == -1) {
497*0Sstevel@tonic-gate 			mdb_warn("failed to walk syncq cache");
498*0Sstevel@tonic-gate 			return (DCMD_ERR);
499*0Sstevel@tonic-gate 		}
500*0Sstevel@tonic-gate 		return (DCMD_OK);
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
504*0Sstevel@tonic-gate 		quiet = TRUE;
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
507*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
508*0Sstevel@tonic-gate 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
509*0Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &flag,
510*0Sstevel@tonic-gate 	    'F', MDB_OPT_STR, &not_flag,
511*0Sstevel@tonic-gate 	    't', MDB_OPT_STR, &typ,
512*0Sstevel@tonic-gate 	    'T', MDB_OPT_STR, &not_typ,
513*0Sstevel@tonic-gate 	    NULL) != argc)
514*0Sstevel@tonic-gate 		return (DCMD_USAGE);
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	/*
517*0Sstevel@tonic-gate 	 * If any of the filtering flags is specified, don't print anything
518*0Sstevel@tonic-gate 	 * except the matching pointer.
519*0Sstevel@tonic-gate 	 */
520*0Sstevel@tonic-gate 	if (flag != NULL || not_flag != NULL || typ != NULL || not_typ != NULL)
521*0Sstevel@tonic-gate 		quiet = TRUE;
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !quiet) {
524*0Sstevel@tonic-gate 		mdb_printf("%?s %s %s %s %s %?s %s %s\n",
525*0Sstevel@tonic-gate 		    "ADDR", "FLG", "TYP", "CNT", "NQS", "OUTER", "SF", "PRI");
526*0Sstevel@tonic-gate 	}
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	if (flag != NULL && streams_parse_flag(sqf, flag, &mask) == -1) {
529*0Sstevel@tonic-gate 		mdb_warn("unrecognized syncq flag '%s'\n", flag);
530*0Sstevel@tonic-gate 		streams_flag_usage(sqf);
531*0Sstevel@tonic-gate 		return (DCMD_USAGE);
532*0Sstevel@tonic-gate 	}
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	if (typ != NULL && streams_parse_flag(sqt, typ, &tmask) == -1) {
535*0Sstevel@tonic-gate 		mdb_warn("unrecognized syncq type '%s'\n", typ);
536*0Sstevel@tonic-gate 		streams_flag_usage(sqt);
537*0Sstevel@tonic-gate 		return (DCMD_USAGE);
538*0Sstevel@tonic-gate 	}
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	if (not_flag != NULL && streams_parse_flag(sqf, not_flag, &not_mask)
541*0Sstevel@tonic-gate 	    == -1) {
542*0Sstevel@tonic-gate 		mdb_warn("unrecognized syncq flag '%s'\n", not_flag);
543*0Sstevel@tonic-gate 		streams_flag_usage(sqf);
544*0Sstevel@tonic-gate 		return (DCMD_USAGE);
545*0Sstevel@tonic-gate 	}
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	if (not_typ != NULL && streams_parse_flag(sqt, not_typ, &not_tmask)
548*0Sstevel@tonic-gate 	    == -1) {
549*0Sstevel@tonic-gate 		mdb_warn("unrecognized syncq type '%s'\n", not_typ);
550*0Sstevel@tonic-gate 		streams_flag_usage(sqt);
551*0Sstevel@tonic-gate 		return (DCMD_USAGE);
552*0Sstevel@tonic-gate 	}
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate 	if (mdb_vread(&sq, sizeof (sq), addr) == -1) {
555*0Sstevel@tonic-gate 		mdb_warn("couldn't read syncq at %p", addr);
556*0Sstevel@tonic-gate 		return (DCMD_ERR);
557*0Sstevel@tonic-gate 	}
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	if (mask != 0 && !(sq.sq_flags & mask))
560*0Sstevel@tonic-gate 		return (DCMD_OK);
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	if (not_mask != 0 && (sq.sq_flags & not_mask))
563*0Sstevel@tonic-gate 		return (DCMD_OK);
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	sqtype = (sq.sq_type >> 8) & 0xff;
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	if (tmask != 0 && !(sqtype & tmask))
568*0Sstevel@tonic-gate 		return (DCMD_OK);
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	if (not_tmask != 0 && (sqtype & not_tmask))
571*0Sstevel@tonic-gate 		return (DCMD_OK);
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	/*
574*0Sstevel@tonic-gate 	 * Options are specified for filtering, so If any option is specified on
575*0Sstevel@tonic-gate 	 * the command line, just print address and exit.
576*0Sstevel@tonic-gate 	 */
577*0Sstevel@tonic-gate 	if (quiet) {
578*0Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
579*0Sstevel@tonic-gate 		return (DCMD_OK);
580*0Sstevel@tonic-gate 	}
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 	mdb_printf("%0?p %02x  %02x  %-3u %-3u %0?p  %1x %-3d\n",
583*0Sstevel@tonic-gate 	    addr, sq.sq_flags & 0xff, sqtype, sq.sq_count,
584*0Sstevel@tonic-gate 	    sq.sq_nqueues, sq.sq_outer, sq.sq_svcflags, sq.sq_pri);
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	if (verbose) {
587*0Sstevel@tonic-gate 		int i, arm = 0;
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		for (i = 0; sqf[i].strf_name != NULL; i++) {
590*0Sstevel@tonic-gate 			if (!(sq.sq_flags & (1 << i)))
591*0Sstevel@tonic-gate 				continue;
592*0Sstevel@tonic-gate 			if (!arm) {
593*0Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
594*0Sstevel@tonic-gate 				    SYNC_FLGDELT, "", SYNC_FLGDELT, "");
595*0Sstevel@tonic-gate 				arm = 1;
596*0Sstevel@tonic-gate 			} else
597*0Sstevel@tonic-gate 				mdb_printf("%*s      ", SYNC_FLGDELT, "");
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
600*0Sstevel@tonic-gate 			    sqf[i].strf_name, sqf[i].strf_descr);
601*0Sstevel@tonic-gate 		}
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 		for (i = 0; sqt[i].strf_name != NULL; i++) {
604*0Sstevel@tonic-gate 			if (!(sqtype & (1 << i)))
605*0Sstevel@tonic-gate 				continue;
606*0Sstevel@tonic-gate 			if (!arm) {
607*0Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
608*0Sstevel@tonic-gate 				    SYNC_TYPDELT, "", SYNC_TYPDELT, "");
609*0Sstevel@tonic-gate 				arm = 1;
610*0Sstevel@tonic-gate 			} else
611*0Sstevel@tonic-gate 				mdb_printf("%*s      ", SYNC_TYPDELT, "");
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
614*0Sstevel@tonic-gate 			    sqt[i].strf_name, sqt[i].strf_descr);
615*0Sstevel@tonic-gate 		}
616*0Sstevel@tonic-gate 	}
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	return (DCMD_OK);
619*0Sstevel@tonic-gate }
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate int
622*0Sstevel@tonic-gate stdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
623*0Sstevel@tonic-gate {
624*0Sstevel@tonic-gate 	const int STREAM_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 10);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	stdata_t  sd;
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	const char *flag = NULL, *not_flag = NULL;
629*0Sstevel@tonic-gate 	uint_t verbose = FALSE;
630*0Sstevel@tonic-gate 	uint_t quiet = FALSE;
631*0Sstevel@tonic-gate 	uint32_t mask = 0, not_mask = 0;
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
634*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`stream_head_cache",
635*0Sstevel@tonic-gate 		    "genunix`stdata", argc, argv) == -1) {
636*0Sstevel@tonic-gate 			mdb_warn("failed to walk stream head cache");
637*0Sstevel@tonic-gate 			return (DCMD_ERR);
638*0Sstevel@tonic-gate 		}
639*0Sstevel@tonic-gate 		return (DCMD_OK);
640*0Sstevel@tonic-gate 	}
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
643*0Sstevel@tonic-gate 		quiet = TRUE;
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
646*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
647*0Sstevel@tonic-gate 	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
648*0Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &flag,
649*0Sstevel@tonic-gate 	    'F', MDB_OPT_STR, &not_flag,
650*0Sstevel@tonic-gate 	    NULL) != argc)
651*0Sstevel@tonic-gate 		return (DCMD_USAGE);
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	/*
654*0Sstevel@tonic-gate 	 * If any of the filtering flags is specified, don't print anything
655*0Sstevel@tonic-gate 	 * except the matching pointer.
656*0Sstevel@tonic-gate 	 */
657*0Sstevel@tonic-gate 	if (flag != NULL || not_flag != NULL)
658*0Sstevel@tonic-gate 		quiet = TRUE;
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !quiet) {
661*0Sstevel@tonic-gate 		mdb_printf("%?s %?s %8s %?s %s %s\n",
662*0Sstevel@tonic-gate 		    "ADDR", "WRQ", "FLAGS", "VNODE", "N/A", "REF");
663*0Sstevel@tonic-gate 	}
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	if (flag != NULL && streams_parse_flag(stdf, flag, &mask) == -1) {
666*0Sstevel@tonic-gate 		mdb_warn("unrecognized stream flag '%s'\n", flag);
667*0Sstevel@tonic-gate 		streams_flag_usage(stdf);
668*0Sstevel@tonic-gate 		return (DCMD_USAGE);
669*0Sstevel@tonic-gate 	}
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	if (not_flag != NULL &&
672*0Sstevel@tonic-gate 	    streams_parse_flag(stdf, not_flag, &not_mask) == -1) {
673*0Sstevel@tonic-gate 		mdb_warn("unrecognized stream flag '%s'\n", flag);
674*0Sstevel@tonic-gate 		streams_flag_usage(stdf);
675*0Sstevel@tonic-gate 		return (DCMD_USAGE);
676*0Sstevel@tonic-gate 	}
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	if (mdb_vread(&sd, sizeof (sd), addr) == -1) {
679*0Sstevel@tonic-gate 		mdb_warn("couldn't read stdata at %p", addr);
680*0Sstevel@tonic-gate 		return (DCMD_ERR);
681*0Sstevel@tonic-gate 	}
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	/*
684*0Sstevel@tonic-gate 	 * If stream doesn't pass filtering criteria, don't print anything and
685*0Sstevel@tonic-gate 	 * just return.
686*0Sstevel@tonic-gate 	 */
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 	if (mask != 0 && !(sd.sd_flag & mask))
689*0Sstevel@tonic-gate 		return (DCMD_OK);
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 	if (not_mask != 0 && (sd.sd_flag & not_mask))
692*0Sstevel@tonic-gate 		return (DCMD_OK);
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	/*
695*0Sstevel@tonic-gate 	 * Options are specified for filtering, so If any option is specified on
696*0Sstevel@tonic-gate 	 * the command line, just print address and exit.
697*0Sstevel@tonic-gate 	 */
698*0Sstevel@tonic-gate 	if (quiet) {
699*0Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
700*0Sstevel@tonic-gate 		return (DCMD_OK);
701*0Sstevel@tonic-gate 	}
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %08x %0?p %d/%d %d\n",
704*0Sstevel@tonic-gate 	    addr, sd.sd_wrq, sd.sd_flag, sd.sd_vnode,
705*0Sstevel@tonic-gate 	    sd.sd_pushcnt, sd.sd_anchor, sd.sd_refcnt);
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	if (verbose) {
708*0Sstevel@tonic-gate 		int i, arm = 0;
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 		for (i = 0; stdf[i].strf_name != NULL; i++) {
711*0Sstevel@tonic-gate 			if (!(sd.sd_flag & (1 << i)))
712*0Sstevel@tonic-gate 				continue;
713*0Sstevel@tonic-gate 			if (!arm) {
714*0Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
715*0Sstevel@tonic-gate 				    STREAM_FLGDELT, "", STREAM_FLGDELT, "");
716*0Sstevel@tonic-gate 				arm = 1;
717*0Sstevel@tonic-gate 			} else
718*0Sstevel@tonic-gate 				mdb_printf("%*s      ", STREAM_FLGDELT, "");
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
721*0Sstevel@tonic-gate 			    stdf[i].strf_name, stdf[i].strf_descr);
722*0Sstevel@tonic-gate 		}
723*0Sstevel@tonic-gate 	}
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	return (DCMD_OK);
726*0Sstevel@tonic-gate }
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate /*ARGSUSED*/
729*0Sstevel@tonic-gate static void
730*0Sstevel@tonic-gate qprint_syncq(queue_t *addr, queue_t *q)
731*0Sstevel@tonic-gate {
732*0Sstevel@tonic-gate 	mdb_printf("%p\n", q->q_syncq);
733*0Sstevel@tonic-gate }
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate /*ARGSUSED*/
736*0Sstevel@tonic-gate static void
737*0Sstevel@tonic-gate qprint_stream(queue_t *addr, queue_t *q)
738*0Sstevel@tonic-gate {
739*0Sstevel@tonic-gate 	mdb_printf("%p\n", q->q_stream);
740*0Sstevel@tonic-gate }
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate static void
743*0Sstevel@tonic-gate qprint_wrq(queue_t *addr, queue_t *q)
744*0Sstevel@tonic-gate {
745*0Sstevel@tonic-gate 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)));
746*0Sstevel@tonic-gate }
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate static void
749*0Sstevel@tonic-gate qprint_rdq(queue_t *addr, queue_t *q)
750*0Sstevel@tonic-gate {
751*0Sstevel@tonic-gate 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr): (addr)-1));
752*0Sstevel@tonic-gate }
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate static void
755*0Sstevel@tonic-gate qprint_otherq(queue_t *addr, queue_t *q)
756*0Sstevel@tonic-gate {
757*0Sstevel@tonic-gate 	mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)-1));
758*0Sstevel@tonic-gate }
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate static int
761*0Sstevel@tonic-gate q2x(uintptr_t addr, int argc, qprint_func prfunc)
762*0Sstevel@tonic-gate {
763*0Sstevel@tonic-gate 	queue_t q;
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	if (argc != 0)
766*0Sstevel@tonic-gate 		return (DCMD_USAGE);
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	if (mdb_vread(&q, sizeof (q), addr) == -1) {
769*0Sstevel@tonic-gate 		mdb_warn("couldn't read queue at %p", addr);
770*0Sstevel@tonic-gate 		return (DCMD_ERR);
771*0Sstevel@tonic-gate 	}
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	prfunc((queue_t *)addr, &q);
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	return (DCMD_OK);
776*0Sstevel@tonic-gate }
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate /*ARGSUSED*/
780*0Sstevel@tonic-gate int
781*0Sstevel@tonic-gate q2syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
782*0Sstevel@tonic-gate {
783*0Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_syncq));
784*0Sstevel@tonic-gate }
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate /*ARGSUSED*/
787*0Sstevel@tonic-gate int
788*0Sstevel@tonic-gate q2stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
789*0Sstevel@tonic-gate {
790*0Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_stream));
791*0Sstevel@tonic-gate }
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate /*ARGSUSED*/
794*0Sstevel@tonic-gate int
795*0Sstevel@tonic-gate q2rdq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
796*0Sstevel@tonic-gate {
797*0Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_rdq));
798*0Sstevel@tonic-gate }
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate /*ARGSUSED*/
801*0Sstevel@tonic-gate int
802*0Sstevel@tonic-gate q2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
803*0Sstevel@tonic-gate {
804*0Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_wrq));
805*0Sstevel@tonic-gate }
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate /*ARGSUSED*/
808*0Sstevel@tonic-gate int
809*0Sstevel@tonic-gate q2otherq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
810*0Sstevel@tonic-gate {
811*0Sstevel@tonic-gate 	return (q2x(addr, argc, qprint_otherq));
812*0Sstevel@tonic-gate }
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate static int
815*0Sstevel@tonic-gate sd2x(uintptr_t addr, int argc, sdprint_func prfunc)
816*0Sstevel@tonic-gate {
817*0Sstevel@tonic-gate 	stdata_t sd;
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 	if (argc != 0)
820*0Sstevel@tonic-gate 		return (DCMD_USAGE);
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 	if (mdb_vread(&sd, sizeof (sd), addr) == -1) {
823*0Sstevel@tonic-gate 		mdb_warn("couldn't read stream head at %p", addr);
824*0Sstevel@tonic-gate 		return (DCMD_ERR);
825*0Sstevel@tonic-gate 	}
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 	prfunc((stdata_t *)addr, &sd);
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	return (DCMD_OK);
830*0Sstevel@tonic-gate }
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate /*ARGSUSED*/
833*0Sstevel@tonic-gate static void
834*0Sstevel@tonic-gate sdprint_wrq(stdata_t *addr, stdata_t *sd)
835*0Sstevel@tonic-gate {
836*0Sstevel@tonic-gate 	mdb_printf("%p\n", sd->sd_wrq);
837*0Sstevel@tonic-gate }
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate static void
840*0Sstevel@tonic-gate sdprint_mate(stdata_t *addr, stdata_t *sd)
841*0Sstevel@tonic-gate {
842*0Sstevel@tonic-gate 	mdb_printf("%p\n", sd->sd_mate ? sd->sd_mate : addr);
843*0Sstevel@tonic-gate }
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate /*ARGSUSED*/
846*0Sstevel@tonic-gate int
847*0Sstevel@tonic-gate str2mate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
848*0Sstevel@tonic-gate {
849*0Sstevel@tonic-gate 	return (sd2x(addr, argc, sdprint_mate));
850*0Sstevel@tonic-gate }
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate /*ARGSUSED*/
853*0Sstevel@tonic-gate int
854*0Sstevel@tonic-gate str2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
855*0Sstevel@tonic-gate {
856*0Sstevel@tonic-gate 	return (sd2x(addr, argc, sdprint_wrq));
857*0Sstevel@tonic-gate }
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate /*
861*0Sstevel@tonic-gate  * If this syncq is a part of the queue pair structure, find the queue for it.
862*0Sstevel@tonic-gate  */
863*0Sstevel@tonic-gate /*ARGSUSED*/
864*0Sstevel@tonic-gate int
865*0Sstevel@tonic-gate syncq2q(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
866*0Sstevel@tonic-gate {
867*0Sstevel@tonic-gate 	syncq_t sq;
868*0Sstevel@tonic-gate 	queue_t q;
869*0Sstevel@tonic-gate 	queue_t *qp;
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	if (argc != 0)
872*0Sstevel@tonic-gate 		return (DCMD_USAGE);
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	if (mdb_vread(&sq, sizeof (sq), addr) == -1) {
875*0Sstevel@tonic-gate 		mdb_warn("couldn't read syncq at %p", addr);
876*0Sstevel@tonic-gate 		return (DCMD_ERR);
877*0Sstevel@tonic-gate 	}
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 	/* Try to find its queue */
880*0Sstevel@tonic-gate 	qp = (queue_t *)addr - 2;
881*0Sstevel@tonic-gate 
882*0Sstevel@tonic-gate 	if ((mdb_vread(&q, sizeof (q), (uintptr_t)qp) == -1) ||
883*0Sstevel@tonic-gate 	    (q.q_syncq != (syncq_t *)addr)) {
884*0Sstevel@tonic-gate 		mdb_warn("syncq2q: %p is not part of any queue\n", addr);
885*0Sstevel@tonic-gate 		return (DCMD_ERR);
886*0Sstevel@tonic-gate 	} else
887*0Sstevel@tonic-gate 		mdb_printf("%p\n", qp);
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate 	return (DCMD_OK);
890*0Sstevel@tonic-gate }
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate int
894*0Sstevel@tonic-gate queue_walk_init(mdb_walk_state_t *wsp)
895*0Sstevel@tonic-gate {
896*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL &&
897*0Sstevel@tonic-gate 	    mdb_readvar(&wsp->walk_addr, "qhead") == -1) {
898*0Sstevel@tonic-gate 		mdb_warn("failed to read 'qhead'");
899*0Sstevel@tonic-gate 		return (WALK_ERR);
900*0Sstevel@tonic-gate 	}
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (queue_t), UM_SLEEP);
903*0Sstevel@tonic-gate 	return (WALK_NEXT);
904*0Sstevel@tonic-gate }
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate int
907*0Sstevel@tonic-gate queue_link_step(mdb_walk_state_t *wsp)
908*0Sstevel@tonic-gate {
909*0Sstevel@tonic-gate 	int status;
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
912*0Sstevel@tonic-gate 		return (WALK_DONE);
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) {
915*0Sstevel@tonic-gate 		mdb_warn("failed to read queue at %p", wsp->walk_addr);
916*0Sstevel@tonic-gate 		return (WALK_DONE);
917*0Sstevel@tonic-gate 	}
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
920*0Sstevel@tonic-gate 	    wsp->walk_cbdata);
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_link);
923*0Sstevel@tonic-gate 	return (status);
924*0Sstevel@tonic-gate }
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate int
927*0Sstevel@tonic-gate queue_next_step(mdb_walk_state_t *wsp)
928*0Sstevel@tonic-gate {
929*0Sstevel@tonic-gate 	int status;
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
932*0Sstevel@tonic-gate 		return (WALK_DONE);
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) {
935*0Sstevel@tonic-gate 		mdb_warn("failed to read queue at %p", wsp->walk_addr);
936*0Sstevel@tonic-gate 		return (WALK_DONE);
937*0Sstevel@tonic-gate 	}
938*0Sstevel@tonic-gate 
939*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
940*0Sstevel@tonic-gate 	    wsp->walk_cbdata);
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_next);
943*0Sstevel@tonic-gate 	return (status);
944*0Sstevel@tonic-gate }
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate void
947*0Sstevel@tonic-gate queue_walk_fini(mdb_walk_state_t *wsp)
948*0Sstevel@tonic-gate {
949*0Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (queue_t));
950*0Sstevel@tonic-gate }
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate int
953*0Sstevel@tonic-gate str_walk_init(mdb_walk_state_t *wsp)
954*0Sstevel@tonic-gate {
955*0Sstevel@tonic-gate 	stdata_t s;
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
958*0Sstevel@tonic-gate 		mdb_warn("walk must begin at address of stdata_t\n");
959*0Sstevel@tonic-gate 		return (WALK_ERR);
960*0Sstevel@tonic-gate 	}
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate 	if (mdb_vread(&s, sizeof (s), wsp->walk_addr) == -1) {
963*0Sstevel@tonic-gate 		mdb_warn("failed to read stdata at %p", wsp->walk_addr);
964*0Sstevel@tonic-gate 		return (WALK_ERR);
965*0Sstevel@tonic-gate 	}
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)s.sd_wrq;
968*0Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (queue_t) * 2, UM_SLEEP);
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 	return (WALK_NEXT);
971*0Sstevel@tonic-gate }
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate int
974*0Sstevel@tonic-gate strr_walk_step(mdb_walk_state_t *wsp)
975*0Sstevel@tonic-gate {
976*0Sstevel@tonic-gate 	queue_t *rq = wsp->walk_data, *wq = rq + 1;
977*0Sstevel@tonic-gate 	int status;
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
980*0Sstevel@tonic-gate 		return (WALK_DONE);
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2,
983*0Sstevel@tonic-gate 	    wsp->walk_addr - sizeof (queue_t)) == -1) {
984*0Sstevel@tonic-gate 		mdb_warn("failed to read queue pair at %p",
985*0Sstevel@tonic-gate 		    wsp->walk_addr - sizeof (queue_t));
986*0Sstevel@tonic-gate 		return (WALK_DONE);
987*0Sstevel@tonic-gate 	}
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr - sizeof (queue_t),
990*0Sstevel@tonic-gate 	    rq, wsp->walk_cbdata);
991*0Sstevel@tonic-gate 
992*0Sstevel@tonic-gate 	if (wq->q_next != NULL)
993*0Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)wq->q_next;
994*0Sstevel@tonic-gate 	else
995*0Sstevel@tonic-gate 		wsp->walk_addr = mdb_qwnext(wq);
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 	return (status);
998*0Sstevel@tonic-gate }
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate int
1001*0Sstevel@tonic-gate strw_walk_step(mdb_walk_state_t *wsp)
1002*0Sstevel@tonic-gate {
1003*0Sstevel@tonic-gate 	queue_t *rq = wsp->walk_data, *wq = rq + 1;
1004*0Sstevel@tonic-gate 	int status;
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
1007*0Sstevel@tonic-gate 		return (WALK_DONE);
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2,
1010*0Sstevel@tonic-gate 	    wsp->walk_addr - sizeof (queue_t)) == -1) {
1011*0Sstevel@tonic-gate 		mdb_warn("failed to read queue pair at %p",
1012*0Sstevel@tonic-gate 		    wsp->walk_addr - sizeof (queue_t));
1013*0Sstevel@tonic-gate 		return (WALK_DONE);
1014*0Sstevel@tonic-gate 	}
1015*0Sstevel@tonic-gate 
1016*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wq, wsp->walk_cbdata);
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	if (wq->q_next != NULL)
1019*0Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)wq->q_next;
1020*0Sstevel@tonic-gate 	else
1021*0Sstevel@tonic-gate 		wsp->walk_addr = mdb_qwnext(wq);
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	return (status);
1024*0Sstevel@tonic-gate }
1025*0Sstevel@tonic-gate 
1026*0Sstevel@tonic-gate void
1027*0Sstevel@tonic-gate str_walk_fini(mdb_walk_state_t *wsp)
1028*0Sstevel@tonic-gate {
1029*0Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (queue_t) * 2);
1030*0Sstevel@tonic-gate }
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate static int
1033*0Sstevel@tonic-gate print_qpair(uintptr_t addr, const queue_t *q, uint_t *depth)
1034*0Sstevel@tonic-gate {
1035*0Sstevel@tonic-gate 	static const char box_lid[] =
1036*0Sstevel@tonic-gate 	    "+-----------------------+-----------------------+\n";
1037*0Sstevel@tonic-gate 	static const char box_sep[] =
1038*0Sstevel@tonic-gate 	    "|                       |                       |\n";
1039*0Sstevel@tonic-gate 
1040*0Sstevel@tonic-gate 	char wname[32], rname[32], info1[256], *info2;
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate 	if (*depth != 0) {
1043*0Sstevel@tonic-gate 		mdb_printf("            |                       ^\n");
1044*0Sstevel@tonic-gate 		mdb_printf("            v                       |\n");
1045*0Sstevel@tonic-gate 	} else
1046*0Sstevel@tonic-gate 		mdb_printf("\n");
1047*0Sstevel@tonic-gate 
1048*0Sstevel@tonic-gate 	(void) mdb_qname(_WR(q), wname, sizeof (wname));
1049*0Sstevel@tonic-gate 	(void) mdb_qname(_RD(q), rname, sizeof (rname));
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate 	mdb_qinfo(_WR(q), info1, sizeof (info1));
1052*0Sstevel@tonic-gate 	if ((info2 = strchr(info1, '\n')) != NULL)
1053*0Sstevel@tonic-gate 		*info2++ = '\0';
1054*0Sstevel@tonic-gate 	else
1055*0Sstevel@tonic-gate 		info2 = "";
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	mdb_printf(box_lid);
1058*0Sstevel@tonic-gate 	mdb_printf("| 0x%-19p | 0x%-19p | %s\n",
1059*0Sstevel@tonic-gate 	    addr, addr - sizeof (queue_t), info1);
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	mdb_printf("| %<b>%-21s%</b> | %<b>%-21s%</b> |", wname, rname);
1062*0Sstevel@tonic-gate 	mdb_flush(); /* Account for buffered terminal sequences */
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 	mdb_printf(" %s\n", info2);
1065*0Sstevel@tonic-gate 	mdb_printf(box_sep);
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	mdb_qinfo(_RD(q), info1, sizeof (info1));
1068*0Sstevel@tonic-gate 	if ((info2 = strchr(info1, '\n')) != NULL)
1069*0Sstevel@tonic-gate 		*info2++ = '\0';
1070*0Sstevel@tonic-gate 	else
1071*0Sstevel@tonic-gate 		info2 = "";
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate 	mdb_printf("| cnt = 0t%-13lu | cnt = 0t%-13lu | %s\n",
1074*0Sstevel@tonic-gate 	    _WR(q)->q_count, _RD(q)->q_count, info1);
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 	mdb_printf("| flg = 0x%08x      | flg = 0x%08x      | %s\n",
1077*0Sstevel@tonic-gate 	    _WR(q)->q_flag, _RD(q)->q_flag, info2);
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate 	mdb_printf(box_lid);
1080*0Sstevel@tonic-gate 	*depth += 1;
1081*0Sstevel@tonic-gate 	return (0);
1082*0Sstevel@tonic-gate }
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate /*ARGSUSED*/
1085*0Sstevel@tonic-gate int
1086*0Sstevel@tonic-gate stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1087*0Sstevel@tonic-gate {
1088*0Sstevel@tonic-gate 	uint_t d = 0;	/* Depth counter for print_qpair */
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
1091*0Sstevel@tonic-gate 		return (DCMD_USAGE);
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 	if (mdb_pwalk("writeq", (mdb_walk_cb_t)print_qpair, &d, addr) == -1) {
1094*0Sstevel@tonic-gate 		mdb_warn("failed to walk writeq");
1095*0Sstevel@tonic-gate 		return (DCMD_ERR);
1096*0Sstevel@tonic-gate 	}
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	return (DCMD_OK);
1099*0Sstevel@tonic-gate }
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate int
1102*0Sstevel@tonic-gate mblk_walk_init(mdb_walk_state_t *wsp)
1103*0Sstevel@tonic-gate {
1104*0Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (mblk_t), UM_SLEEP);
1105*0Sstevel@tonic-gate 	return (WALK_NEXT);
1106*0Sstevel@tonic-gate }
1107*0Sstevel@tonic-gate 
1108*0Sstevel@tonic-gate int
1109*0Sstevel@tonic-gate b_cont_step(mdb_walk_state_t *wsp)
1110*0Sstevel@tonic-gate {
1111*0Sstevel@tonic-gate 	int status;
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
1114*0Sstevel@tonic-gate 		return (WALK_DONE);
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) {
1117*0Sstevel@tonic-gate 		mdb_warn("failed to read mblk at %p", wsp->walk_addr);
1118*0Sstevel@tonic-gate 		return (WALK_DONE);
1119*0Sstevel@tonic-gate 	}
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1122*0Sstevel@tonic-gate 	    wsp->walk_cbdata);
1123*0Sstevel@tonic-gate 
1124*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_cont);
1125*0Sstevel@tonic-gate 	return (status);
1126*0Sstevel@tonic-gate }
1127*0Sstevel@tonic-gate 
1128*0Sstevel@tonic-gate int
1129*0Sstevel@tonic-gate b_next_step(mdb_walk_state_t *wsp)
1130*0Sstevel@tonic-gate {
1131*0Sstevel@tonic-gate 	int status;
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
1134*0Sstevel@tonic-gate 		return (WALK_DONE);
1135*0Sstevel@tonic-gate 
1136*0Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) {
1137*0Sstevel@tonic-gate 		mdb_warn("failed to read mblk at %p", wsp->walk_addr);
1138*0Sstevel@tonic-gate 		return (WALK_DONE);
1139*0Sstevel@tonic-gate 	}
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1142*0Sstevel@tonic-gate 	    wsp->walk_cbdata);
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_next);
1145*0Sstevel@tonic-gate 	return (status);
1146*0Sstevel@tonic-gate }
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate void
1149*0Sstevel@tonic-gate mblk_walk_fini(mdb_walk_state_t *wsp)
1150*0Sstevel@tonic-gate {
1151*0Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (mblk_t));
1152*0Sstevel@tonic-gate }
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate /* ARGSUSED */
1155*0Sstevel@tonic-gate int
1156*0Sstevel@tonic-gate mblk2dblk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1157*0Sstevel@tonic-gate {
1158*0Sstevel@tonic-gate 	mblk_t mb;
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate 	if (argc != 0)
1161*0Sstevel@tonic-gate 		return (DCMD_USAGE);
1162*0Sstevel@tonic-gate 
1163*0Sstevel@tonic-gate 	if (mdb_vread(&mb, sizeof (mb), addr) == -1) {
1164*0Sstevel@tonic-gate 		mdb_warn("couldn't read mblk at %p", addr);
1165*0Sstevel@tonic-gate 		return (DCMD_ERR);
1166*0Sstevel@tonic-gate 	}
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 	mdb_printf("%p\n", mb.b_datap);
1169*0Sstevel@tonic-gate 	return (DCMD_OK);
1170*0Sstevel@tonic-gate }
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate 
1173*0Sstevel@tonic-gate static void
1174*0Sstevel@tonic-gate mblk_error(int *error, uintptr_t addr, char *message)
1175*0Sstevel@tonic-gate {
1176*0Sstevel@tonic-gate 	if (!*error)
1177*0Sstevel@tonic-gate 		mdb_printf("%?lx: ", addr);
1178*0Sstevel@tonic-gate 	else
1179*0Sstevel@tonic-gate 		mdb_printf(", ");
1180*0Sstevel@tonic-gate 	mdb_printf("%s", message);
1181*0Sstevel@tonic-gate 	*error = 1;
1182*0Sstevel@tonic-gate }
1183*0Sstevel@tonic-gate 
1184*0Sstevel@tonic-gate int
1185*0Sstevel@tonic-gate mblk_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1186*0Sstevel@tonic-gate {
1187*0Sstevel@tonic-gate 	mblk_t	mb;
1188*0Sstevel@tonic-gate 	dblk_t	db;
1189*0Sstevel@tonic-gate 	int	error = 0;
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
1192*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("streams_mblk", "mblk_verify", argc, argv) ==
1193*0Sstevel@tonic-gate 		    -1) {
1194*0Sstevel@tonic-gate 			mdb_warn("can't walk mblk cache");
1195*0Sstevel@tonic-gate 			return (DCMD_ERR);
1196*0Sstevel@tonic-gate 		}
1197*0Sstevel@tonic-gate 		return (DCMD_OK);
1198*0Sstevel@tonic-gate 	}
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate 	if (mdb_vread(&mb, sizeof (mblk_t), addr) == -1) {
1201*0Sstevel@tonic-gate 		mdb_warn("can't read mblk_t at 0x%lx", addr);
1202*0Sstevel@tonic-gate 		return (DCMD_ERR);
1203*0Sstevel@tonic-gate 	}
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate 	if (mdb_vread(&db, sizeof (dblk_t), (uintptr_t)mb.b_datap) == -1) {
1206*0Sstevel@tonic-gate 		mdb_warn("%?lx: invalid b_datap pointer\n", addr);
1207*0Sstevel@tonic-gate 		return (DCMD_ERR);
1208*0Sstevel@tonic-gate 	}
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 	if (mb.b_rptr < db.db_base || mb.b_rptr > db.db_lim)
1211*0Sstevel@tonic-gate 		mblk_error(&error, addr, "b_rptr out of range");
1212*0Sstevel@tonic-gate 
1213*0Sstevel@tonic-gate 	if (mb.b_wptr < db.db_base || mb.b_wptr > db.db_lim)
1214*0Sstevel@tonic-gate 		mblk_error(&error, addr, "b_wptr out of range");
1215*0Sstevel@tonic-gate 
1216*0Sstevel@tonic-gate 	if (error)
1217*0Sstevel@tonic-gate 		mdb_printf("\n");
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	return (error ? DCMD_ERR : DCMD_OK);
1220*0Sstevel@tonic-gate }
1221*0Sstevel@tonic-gate 
1222*0Sstevel@tonic-gate int
1223*0Sstevel@tonic-gate mblk_prt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1224*0Sstevel@tonic-gate {
1225*0Sstevel@tonic-gate 	const int MBLK_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15);
1226*0Sstevel@tonic-gate 	mblk_t mblk;
1227*0Sstevel@tonic-gate 	dblk_t dblk;
1228*0Sstevel@tonic-gate 	int b_flag;
1229*0Sstevel@tonic-gate 	int db_type;
1230*0Sstevel@tonic-gate 	int mblklen;
1231*0Sstevel@tonic-gate 	uint64_t len = ~0UL;
1232*0Sstevel@tonic-gate 	uint64_t glen = ~0UL;
1233*0Sstevel@tonic-gate 	uint64_t llen = ~0UL;
1234*0Sstevel@tonic-gate 	uint64_t blen = ~0UL;
1235*0Sstevel@tonic-gate 	const char *dbtype;
1236*0Sstevel@tonic-gate 	const char *flag = NULL, *not_flag = NULL;
1237*0Sstevel@tonic-gate 	const char *typ = NULL, *not_typ = NULL;
1238*0Sstevel@tonic-gate 	uintptr_t  dbaddr = 0;
1239*0Sstevel@tonic-gate 	uint32_t tmask = 0, not_tmask = 0;
1240*0Sstevel@tonic-gate 	uint32_t mask = 0, not_mask = 0;
1241*0Sstevel@tonic-gate 	uint_t quiet = FALSE;
1242*0Sstevel@tonic-gate 	uint_t verbose = FALSE;
1243*0Sstevel@tonic-gate 
1244*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
1245*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`streams_mblk", "genunix`mblk",
1246*0Sstevel@tonic-gate 		    argc, argv) == -1) {
1247*0Sstevel@tonic-gate 			mdb_warn("failed to walk mblk cache");
1248*0Sstevel@tonic-gate 			return (DCMD_ERR);
1249*0Sstevel@tonic-gate 		}
1250*0Sstevel@tonic-gate 		return (DCMD_OK);
1251*0Sstevel@tonic-gate 	}
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 	if (flags & DCMD_PIPE_OUT)
1254*0Sstevel@tonic-gate 		quiet = TRUE;
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
1257*0Sstevel@tonic-gate 		'v', MDB_OPT_SETBITS, TRUE, &verbose,
1258*0Sstevel@tonic-gate 		'q', MDB_OPT_SETBITS, TRUE, &quiet,
1259*0Sstevel@tonic-gate 		'f', MDB_OPT_STR, &flag,
1260*0Sstevel@tonic-gate 		'F', MDB_OPT_STR, &not_flag,
1261*0Sstevel@tonic-gate 		't', MDB_OPT_STR, &typ,
1262*0Sstevel@tonic-gate 		'T', MDB_OPT_STR, &not_typ,
1263*0Sstevel@tonic-gate 		'l', MDB_OPT_UINT64, &len,
1264*0Sstevel@tonic-gate 		'L', MDB_OPT_UINT64, &llen,
1265*0Sstevel@tonic-gate 		'G', MDB_OPT_UINT64, &glen,
1266*0Sstevel@tonic-gate 		'b', MDB_OPT_UINT64, &blen,
1267*0Sstevel@tonic-gate 		'd', MDB_OPT_UINTPTR, &dbaddr,
1268*0Sstevel@tonic-gate 	    NULL) != argc)
1269*0Sstevel@tonic-gate 		return (DCMD_USAGE);
1270*0Sstevel@tonic-gate 
1271*0Sstevel@tonic-gate 	/*
1272*0Sstevel@tonic-gate 	 * If any of the filtering flags is specified, don't print anything
1273*0Sstevel@tonic-gate 	 * except the matching pointer.
1274*0Sstevel@tonic-gate 	 */
1275*0Sstevel@tonic-gate 	if ((flag != NULL) || (not_flag != NULL) || (typ != NULL) ||
1276*0Sstevel@tonic-gate 	    (not_typ != NULL) || (len != ~0UL) || (glen != ~0UL) ||
1277*0Sstevel@tonic-gate 	    (llen != ~0UL) || (blen != ~0UL) || (dbaddr != 0))
1278*0Sstevel@tonic-gate 		quiet = TRUE;
1279*0Sstevel@tonic-gate 
1280*0Sstevel@tonic-gate 	if (flag != NULL && streams_parse_flag(mbf, flag, &mask) == -1) {
1281*0Sstevel@tonic-gate 		mdb_warn("unrecognized mblk flag '%s'\n", flag);
1282*0Sstevel@tonic-gate 		streams_flag_usage(mbf);
1283*0Sstevel@tonic-gate 		return (DCMD_USAGE);
1284*0Sstevel@tonic-gate 	}
1285*0Sstevel@tonic-gate 
1286*0Sstevel@tonic-gate 	if (not_flag != NULL &&
1287*0Sstevel@tonic-gate 	    streams_parse_flag(mbf, not_flag, &not_mask) == -1) {
1288*0Sstevel@tonic-gate 		mdb_warn("unrecognized mblk flag '%s'\n", flag);
1289*0Sstevel@tonic-gate 		streams_flag_usage(mbf);
1290*0Sstevel@tonic-gate 		return (DCMD_USAGE);
1291*0Sstevel@tonic-gate 	}
1292*0Sstevel@tonic-gate 
1293*0Sstevel@tonic-gate 	if (typ != NULL && streams_parse_type(mbt, typ, &tmask) == -1) {
1294*0Sstevel@tonic-gate 		mdb_warn("unrecognized dblk type '%s'\n", typ);
1295*0Sstevel@tonic-gate 		streams_type_usage(mbt);
1296*0Sstevel@tonic-gate 		return (DCMD_USAGE);
1297*0Sstevel@tonic-gate 	}
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate 	if (not_typ != NULL && streams_parse_type(mbt, not_typ, &not_tmask)
1300*0Sstevel@tonic-gate 	    == -1) {
1301*0Sstevel@tonic-gate 		mdb_warn("unrecognized dblk type '%s'\n", not_typ);
1302*0Sstevel@tonic-gate 		streams_type_usage(mbt);
1303*0Sstevel@tonic-gate 		return (DCMD_USAGE);
1304*0Sstevel@tonic-gate 	}
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !quiet) {
1307*0Sstevel@tonic-gate 		mdb_printf("%?s %2s %-7s %-5s %-5s %?s %?s\n",
1308*0Sstevel@tonic-gate 		    "ADDR", "FL", "TYPE", "LEN", "BLEN", "RPTR", "DBLK");
1309*0Sstevel@tonic-gate 	}
1310*0Sstevel@tonic-gate 
1311*0Sstevel@tonic-gate 	if (mdb_vread(&mblk, sizeof (mblk), addr) == -1) {
1312*0Sstevel@tonic-gate 		mdb_warn("couldn't read mblk at %p", addr);
1313*0Sstevel@tonic-gate 		return (DCMD_ERR);
1314*0Sstevel@tonic-gate 	}
1315*0Sstevel@tonic-gate 	b_flag = mblk.b_flag;
1316*0Sstevel@tonic-gate 
1317*0Sstevel@tonic-gate 	if (mask != 0 && !(b_flag & mask))
1318*0Sstevel@tonic-gate 		return (DCMD_OK);
1319*0Sstevel@tonic-gate 
1320*0Sstevel@tonic-gate 	if (not_mask != 0 && (b_flag & not_mask))
1321*0Sstevel@tonic-gate 		return (DCMD_OK);
1322*0Sstevel@tonic-gate 
1323*0Sstevel@tonic-gate 	if (mdb_vread(&dblk, sizeof (dblk), (uintptr_t)(mblk.b_datap)) == -1) {
1324*0Sstevel@tonic-gate 		mdb_warn("couldn't read dblk at %p/%p", addr, mblk.b_datap);
1325*0Sstevel@tonic-gate 		return (DCMD_ERR);
1326*0Sstevel@tonic-gate 	}
1327*0Sstevel@tonic-gate 	db_type = dblk.db_type;
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 	/* M_DATA is 0, so tmask has special value 0xff for it */
1330*0Sstevel@tonic-gate 	if ((tmask != 0) &&
1331*0Sstevel@tonic-gate 	    (((tmask == M_DATA_T) && (db_type != M_DATA)) ||
1332*0Sstevel@tonic-gate 		((tmask != M_DATA_T) && (db_type != tmask))))
1333*0Sstevel@tonic-gate 		return (DCMD_OK);
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 
1336*0Sstevel@tonic-gate 	if ((not_tmask != 0) &&
1337*0Sstevel@tonic-gate 	    (((not_tmask == M_DATA_T) && (db_type == M_DATA)) ||
1338*0Sstevel@tonic-gate 		(db_type == not_tmask)))
1339*0Sstevel@tonic-gate 		return (DCMD_OK);
1340*0Sstevel@tonic-gate 
1341*0Sstevel@tonic-gate 	if (dbaddr != 0 && (uintptr_t)mblk.b_datap != dbaddr)
1342*0Sstevel@tonic-gate 		return (DCMD_OK);
1343*0Sstevel@tonic-gate 
1344*0Sstevel@tonic-gate 	mblklen = MBLKL(&mblk);
1345*0Sstevel@tonic-gate 
1346*0Sstevel@tonic-gate 	if ((len != ~0UL) && (len != mblklen))
1347*0Sstevel@tonic-gate 		return (DCMD_OK);
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 	if ((llen != ~0Ul) && (mblklen > (int)llen))
1350*0Sstevel@tonic-gate 		return (DCMD_OK);
1351*0Sstevel@tonic-gate 
1352*0Sstevel@tonic-gate 	if ((glen != ~0Ul) && (mblklen < (int)glen))
1353*0Sstevel@tonic-gate 		return (DCMD_OK);
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 	if ((blen != ~0UL) && (blen != (dblk.db_lim - dblk.db_base)))
1356*0Sstevel@tonic-gate 		return (DCMD_OK);
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate 	/*
1359*0Sstevel@tonic-gate 	 * Options are specified for filtering, so If any option is specified on
1360*0Sstevel@tonic-gate 	 * the command line, just print address and exit.
1361*0Sstevel@tonic-gate 	 */
1362*0Sstevel@tonic-gate 	if (quiet) {
1363*0Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
1364*0Sstevel@tonic-gate 		return (DCMD_OK);
1365*0Sstevel@tonic-gate 	}
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	/* Figure out symbolic DB_TYPE */
1368*0Sstevel@tonic-gate 	if (db_type < A_SIZE(db_control_types)) {
1369*0Sstevel@tonic-gate 		dbtype = db_control_types[db_type];
1370*0Sstevel@tonic-gate 	} else {
1371*0Sstevel@tonic-gate 		/*
1372*0Sstevel@tonic-gate 		 * Must be a high-priority message -- adjust so that
1373*0Sstevel@tonic-gate 		 * "QPCTL + 1" corresponds to db_control_hipri_types[0]
1374*0Sstevel@tonic-gate 		 */
1375*0Sstevel@tonic-gate 		db_type -= (QPCTL + 1);
1376*0Sstevel@tonic-gate 		if (db_type >= 0 && db_type < A_SIZE(db_control_hipri_types))
1377*0Sstevel@tonic-gate 			dbtype = db_control_hipri_types[db_type];
1378*0Sstevel@tonic-gate 		else
1379*0Sstevel@tonic-gate 			dbtype = "UNKNOWN";
1380*0Sstevel@tonic-gate 	}
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 	mdb_printf("%0?p %-2x %-7s %-5d %-5d %0?p %0?p\n",
1383*0Sstevel@tonic-gate 	    addr, b_flag, dbtype, mblklen, dblk.db_lim - dblk.db_base,
1384*0Sstevel@tonic-gate 	    mblk.b_rptr, mblk.b_datap);
1385*0Sstevel@tonic-gate 
1386*0Sstevel@tonic-gate 	if (verbose) {
1387*0Sstevel@tonic-gate 		int i, arm = 0;
1388*0Sstevel@tonic-gate 
1389*0Sstevel@tonic-gate 		for (i = 0; mbf[i].strf_name != NULL; i++) {
1390*0Sstevel@tonic-gate 			if (!(b_flag & (1 << i)))
1391*0Sstevel@tonic-gate 				continue;
1392*0Sstevel@tonic-gate 			if (!arm) {
1393*0Sstevel@tonic-gate 				mdb_printf("%*s|\n%*s+-->  ",
1394*0Sstevel@tonic-gate 				    MBLK_FLGDELT, "", MBLK_FLGDELT, "");
1395*0Sstevel@tonic-gate 				arm = 1;
1396*0Sstevel@tonic-gate 			} else
1397*0Sstevel@tonic-gate 				mdb_printf("%*s      ", MBLK_FLGDELT, "");
1398*0Sstevel@tonic-gate 
1399*0Sstevel@tonic-gate 			mdb_printf("%-12s %s\n",
1400*0Sstevel@tonic-gate 			    mbf[i].strf_name, mbf[i].strf_descr);
1401*0Sstevel@tonic-gate 		}
1402*0Sstevel@tonic-gate 	}
1403*0Sstevel@tonic-gate 	return (DCMD_OK);
1404*0Sstevel@tonic-gate }
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate /*
1407*0Sstevel@tonic-gate  * Streams flow trace walkers.
1408*0Sstevel@tonic-gate  */
1409*0Sstevel@tonic-gate 
1410*0Sstevel@tonic-gate int
1411*0Sstevel@tonic-gate strftblk_walk_init(mdb_walk_state_t *wsp)
1412*0Sstevel@tonic-gate {
1413*0Sstevel@tonic-gate 	ftblkdata_t *ftd;
1414*0Sstevel@tonic-gate 	dblk_t	db;
1415*0Sstevel@tonic-gate 
1416*0Sstevel@tonic-gate 	/* Get the dblock from the address */
1417*0Sstevel@tonic-gate 	if (mdb_vread(&db, sizeof (dblk_t), wsp->walk_addr) == -1) {
1418*0Sstevel@tonic-gate 		mdb_warn("failed to read dblk at %p", wsp->walk_addr);
1419*0Sstevel@tonic-gate 		return (WALK_ERR);
1420*0Sstevel@tonic-gate 	}
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate 	/* Is there any flow trace data? */
1423*0Sstevel@tonic-gate 	if (db.db_fthdr == NULL) {
1424*0Sstevel@tonic-gate 		return (WALK_DONE);
1425*0Sstevel@tonic-gate 	}
1426*0Sstevel@tonic-gate 
1427*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)((char *)db.db_fthdr +
1428*0Sstevel@tonic-gate 	    offsetof(fthdr_t, first));
1429*0Sstevel@tonic-gate 
1430*0Sstevel@tonic-gate 	ftd = mdb_alloc(sizeof (ftblkdata_t), UM_SLEEP);
1431*0Sstevel@tonic-gate 	ftd->ft_ix = 0;
1432*0Sstevel@tonic-gate 	ftd->ft_in_evlist = B_FALSE;
1433*0Sstevel@tonic-gate 	wsp->walk_data = ftd;
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 	return (WALK_NEXT);
1436*0Sstevel@tonic-gate }
1437*0Sstevel@tonic-gate 
1438*0Sstevel@tonic-gate int
1439*0Sstevel@tonic-gate strftblk_step(mdb_walk_state_t *wsp)
1440*0Sstevel@tonic-gate {
1441*0Sstevel@tonic-gate 	ftblkdata_t *ftd;
1442*0Sstevel@tonic-gate 	ftblk_t *ftbp;
1443*0Sstevel@tonic-gate 	int status = WALK_NEXT;
1444*0Sstevel@tonic-gate 
1445*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
1446*0Sstevel@tonic-gate 		return (WALK_DONE);
1447*0Sstevel@tonic-gate 
1448*0Sstevel@tonic-gate 	ftd = (ftblkdata_t *)wsp->walk_data;
1449*0Sstevel@tonic-gate 	ftbp = &(ftd->ft_data);
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 	if (! ftd->ft_in_evlist) {
1452*0Sstevel@tonic-gate 		/* Read a new ft block */
1453*0Sstevel@tonic-gate 		if (mdb_vread(ftbp, sizeof (ftblk_t),
1454*0Sstevel@tonic-gate 		    wsp->walk_addr) == -1) {
1455*0Sstevel@tonic-gate 			mdb_warn("failed to read ftblk at %p", wsp->walk_addr);
1456*0Sstevel@tonic-gate 			return (WALK_ERR);
1457*0Sstevel@tonic-gate 		}
1458*0Sstevel@tonic-gate 		/*
1459*0Sstevel@tonic-gate 		 * Check correctness of the index field.
1460*0Sstevel@tonic-gate 		 */
1461*0Sstevel@tonic-gate 		if (ftbp->ix < 0 || ftbp->ix > FTBLK_EVNTS) {
1462*0Sstevel@tonic-gate 			mdb_warn("ftblk: incorrect index value %i\n", ftbp->ix);
1463*0Sstevel@tonic-gate 			return (WALK_ERR);
1464*0Sstevel@tonic-gate 		}
1465*0Sstevel@tonic-gate 		ftd->ft_ix = 1;
1466*0Sstevel@tonic-gate 		ftd->ft_in_evlist = B_TRUE;
1467*0Sstevel@tonic-gate 	}
1468*0Sstevel@tonic-gate 
1469*0Sstevel@tonic-gate 	if (ftd->ft_ix > ftbp->ix) {
1470*0Sstevel@tonic-gate 		ftd->ft_in_evlist = B_FALSE;
1471*0Sstevel@tonic-gate 		/* End of event list reached - move to the next event block */
1472*0Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)ftbp->nxt;
1473*0Sstevel@tonic-gate 	} else {
1474*0Sstevel@tonic-gate 		/* Print event address */
1475*0Sstevel@tonic-gate 		status = wsp->walk_callback((uintptr_t)((char *)wsp->walk_addr +
1476*0Sstevel@tonic-gate 		    offsetof(ftblk_t, ev) +
1477*0Sstevel@tonic-gate 		    (ftd->ft_ix - 1) * sizeof (struct ftevnt)),
1478*0Sstevel@tonic-gate 		    wsp->walk_data, wsp->walk_cbdata);
1479*0Sstevel@tonic-gate 		ftd->ft_ix++;
1480*0Sstevel@tonic-gate 	}
1481*0Sstevel@tonic-gate 
1482*0Sstevel@tonic-gate 	return (status);
1483*0Sstevel@tonic-gate }
1484*0Sstevel@tonic-gate 
1485*0Sstevel@tonic-gate 
1486*0Sstevel@tonic-gate void
1487*0Sstevel@tonic-gate strftblk_walk_fini(mdb_walk_state_t *wsp)
1488*0Sstevel@tonic-gate {
1489*0Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (ftblkdata_t));
1490*0Sstevel@tonic-gate }
1491*0Sstevel@tonic-gate 
1492*0Sstevel@tonic-gate /*ARGSUSED*/
1493*0Sstevel@tonic-gate int
1494*0Sstevel@tonic-gate strftevent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1495*0Sstevel@tonic-gate {
1496*0Sstevel@tonic-gate 	struct ftevnt ev;
1497*0Sstevel@tonic-gate 	char modname[MODMAXNAMELEN];
1498*0Sstevel@tonic-gate 
1499*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
1500*0Sstevel@tonic-gate 		return (DCMD_USAGE);
1501*0Sstevel@tonic-gate 
1502*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
1503*0Sstevel@tonic-gate 		mdb_printf("%?s %?s %s %s %-24s  %s\n",
1504*0Sstevel@tonic-gate 		    "ADDR", "MID", "EVNT", "DATA", "NAME", "EVENT");
1505*0Sstevel@tonic-gate 	}
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 	if (mdb_vread(&ev, sizeof (ev), addr) == -1) {
1508*0Sstevel@tonic-gate 		mdb_warn("couldn't read ft event at %p", addr);
1509*0Sstevel@tonic-gate 		return (DCMD_ERR);
1510*0Sstevel@tonic-gate 	}
1511*0Sstevel@tonic-gate 
1512*0Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %4x %4x",
1513*0Sstevel@tonic-gate 	    addr, ev.mid, ev.evnt, ev.data);
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate 	if (ev.evnt & FTEV_QMASK) {
1516*0Sstevel@tonic-gate 		if (mdb_readstr(modname, sizeof (modname),
1517*0Sstevel@tonic-gate 		    (uintptr_t)ev.mid) == -1)
1518*0Sstevel@tonic-gate 			mdb_warn("couldn't read module name at %p", ev.mid);
1519*0Sstevel@tonic-gate 		mdb_printf(" %-24s", modname);
1520*0Sstevel@tonic-gate 	} else
1521*0Sstevel@tonic-gate 		mdb_printf(" %-24a", ev.mid);
1522*0Sstevel@tonic-gate 
1523*0Sstevel@tonic-gate 	ft_printevent(ev.evnt);
1524*0Sstevel@tonic-gate 
1525*0Sstevel@tonic-gate 	mdb_printf("\n");
1526*0Sstevel@tonic-gate 
1527*0Sstevel@tonic-gate 	return (DCMD_OK);
1528*0Sstevel@tonic-gate }
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate static void
1531*0Sstevel@tonic-gate ft_printevent(ushort_t ev)
1532*0Sstevel@tonic-gate {
1533*0Sstevel@tonic-gate 	ushort_t proc_ev = (ev & (FTEV_PROC_START | 0xFF)) - FTEV_PROC_START;
1534*0Sstevel@tonic-gate 	ushort_t alloc_ev = ev & FTEV_CALLER;
1535*0Sstevel@tonic-gate 
1536*0Sstevel@tonic-gate 	/* Get event class first */
1537*0Sstevel@tonic-gate 	if (ev & FTEV_PROC_START) {
1538*0Sstevel@tonic-gate 		if (proc_ev >= A_SIZE(ftev_proc))
1539*0Sstevel@tonic-gate 			mdb_printf("  undefined");
1540*0Sstevel@tonic-gate 		else
1541*0Sstevel@tonic-gate 			mdb_printf("  %s", ftev_proc[proc_ev]);
1542*0Sstevel@tonic-gate 	} else if (alloc_ev >= A_SIZE(ftev_alloc))
1543*0Sstevel@tonic-gate 		mdb_printf("  undefined");
1544*0Sstevel@tonic-gate 	else
1545*0Sstevel@tonic-gate 		mdb_printf("  %s", ftev_alloc[alloc_ev]);
1546*0Sstevel@tonic-gate 
1547*0Sstevel@tonic-gate 	/* Print event modifiers, if any */
1548*0Sstevel@tonic-gate 
1549*0Sstevel@tonic-gate 	if (ev & FTEV_PS)
1550*0Sstevel@tonic-gate 		mdb_printf(" | PS");
1551*0Sstevel@tonic-gate 	if (ev & FTEV_CS)
1552*0Sstevel@tonic-gate 		mdb_printf(" | CS");
1553*0Sstevel@tonic-gate 	if (ev & FTEV_ISWR)
1554*0Sstevel@tonic-gate 		mdb_printf(" | ISWR");
1555*0Sstevel@tonic-gate }
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate /*
1558*0Sstevel@tonic-gate  * Help functions for STREAMS debugging facilities.
1559*0Sstevel@tonic-gate  */
1560*0Sstevel@tonic-gate void
1561*0Sstevel@tonic-gate queue_help(void)
1562*0Sstevel@tonic-gate {
1563*0Sstevel@tonic-gate 	mdb_printf("Print queue information for a given queue pointer.\n"
1564*0Sstevel@tonic-gate 	    "\nWithout the address of a \"queue_t\" structure given, print "
1565*0Sstevel@tonic-gate 	    "information about all\n"
1566*0Sstevel@tonic-gate 	    "queues in the \"queue_cache\".\n\n"
1567*0Sstevel@tonic-gate 	    "Options:\n"
1568*0Sstevel@tonic-gate 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
1569*0Sstevel@tonic-gate 	    "	-q:\t\tbe quiet - print queue pointer only\n"
1570*0Sstevel@tonic-gate 	    "	-f flag:\tprint only queues with flag set\n"
1571*0Sstevel@tonic-gate 	    "	-F flag:\tprint only queues with flag NOT set\n"
1572*0Sstevel@tonic-gate 	    "	-m modname:\tprint only queues with specified module name\n"
1573*0Sstevel@tonic-gate 	    "	-s syncq_addr:\tprint only queues which use specified syncq\n\n"
1574*0Sstevel@tonic-gate 	    "Available conversions:\n"
1575*0Sstevel@tonic-gate 	    "	q2rdq:		given a queue addr print read queue pointer\n"
1576*0Sstevel@tonic-gate 	    "	q2wrq:		given a queue addr print write queue pointer\n"
1577*0Sstevel@tonic-gate 	    "	q2otherq:	given a queue addr print other queue pointer\n"
1578*0Sstevel@tonic-gate 	    "	q2syncq:	given a queue addr print syncq pointer"
1579*0Sstevel@tonic-gate 		" (::help syncq)\n"
1580*0Sstevel@tonic-gate 	    "	q2stream:	given a queue addr print its stream pointer\n"
1581*0Sstevel@tonic-gate 		"\t\t(see ::help stream and ::help stdata)\n\n"
1582*0Sstevel@tonic-gate 	    "To walk q_next pointer of the queue use\n"
1583*0Sstevel@tonic-gate 	    "	queue_addr::walk qnext\n");
1584*0Sstevel@tonic-gate }
1585*0Sstevel@tonic-gate 
1586*0Sstevel@tonic-gate void
1587*0Sstevel@tonic-gate syncq_help(void)
1588*0Sstevel@tonic-gate {
1589*0Sstevel@tonic-gate 	mdb_printf("Print syncq information for a given syncq pointer.\n"
1590*0Sstevel@tonic-gate 	    "\nWithout the address of a \"syncq_t\" structure given, print "
1591*0Sstevel@tonic-gate 	    "information about all\n"
1592*0Sstevel@tonic-gate 	    "syncqs in the \"syncq_cache\".\n\n"
1593*0Sstevel@tonic-gate 	    "Options:\n"
1594*0Sstevel@tonic-gate 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
1595*0Sstevel@tonic-gate 	    "	-q:\t\tbe quiet - print syncq pointer only\n"
1596*0Sstevel@tonic-gate 	    "	-f flag:\tprint only syncqs with flag set\n"
1597*0Sstevel@tonic-gate 	    "	-F flag:\tprint only syncqs with flag NOT set\n"
1598*0Sstevel@tonic-gate 	    "	-t type:\tprint only syncqs with specified type\n"
1599*0Sstevel@tonic-gate 	    "	-T type:\tprint only syncqs with do NOT have specified type\n\n"
1600*0Sstevel@tonic-gate 	    "Available conversions:\n"
1601*0Sstevel@tonic-gate 	    "	syncq2q:\tgiven a syncq addr print queue address of the\n"
1602*0Sstevel@tonic-gate 	    "\t\t\tenclosing queue, if it is part of a queue\n\n"
1603*0Sstevel@tonic-gate 	    "See also: \"::help queue\" and \"::help stdata\"\n");
1604*0Sstevel@tonic-gate }
1605*0Sstevel@tonic-gate 
1606*0Sstevel@tonic-gate void
1607*0Sstevel@tonic-gate stdata_help(void)
1608*0Sstevel@tonic-gate {
1609*0Sstevel@tonic-gate 	mdb_printf("Print stdata information for a given stdata pointer.\n"
1610*0Sstevel@tonic-gate 	    "\nWithout the address of a \"stdata_t\" structure given, print "
1611*0Sstevel@tonic-gate 	    "information about all\n"
1612*0Sstevel@tonic-gate 	    "stream head pointers from the \"stream_head_cache\".\n\n"
1613*0Sstevel@tonic-gate 	    "Fields printed:\n"
1614*0Sstevel@tonic-gate 	    "	ADDR:\tstream head address\n"
1615*0Sstevel@tonic-gate 	    "	WRQ:\twrite queue pointer\n"
1616*0Sstevel@tonic-gate 	    "	FLAGS:\tstream head flags (use -v to show in symbolic form)\n"
1617*0Sstevel@tonic-gate 	    "	VNODE:\tstream vnode pointer\n"
1618*0Sstevel@tonic-gate 	    "	N/A:\tpushcount and anchor positions\n"
1619*0Sstevel@tonic-gate 	    "	REF:\tstream head reference counter\n\n"
1620*0Sstevel@tonic-gate 	    "Options:\n"
1621*0Sstevel@tonic-gate 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
1622*0Sstevel@tonic-gate 	    "	-q:\t\tbe quiet - print stdata pointer only\n"
1623*0Sstevel@tonic-gate 	    "	-f flag:\tprint only stdatas with flag set\n"
1624*0Sstevel@tonic-gate 	    "	-F flag:\tprint only stdatas with flag NOT set\n\n"
1625*0Sstevel@tonic-gate 	    "Available conversions:\n"
1626*0Sstevel@tonic-gate 	    "	str2mate:\tgiven a stream head addr print its mate\n"
1627*0Sstevel@tonic-gate 	    "	str2wrq:\tgiven a stream head addr print its write queue\n\n"
1628*0Sstevel@tonic-gate 	    "See also: \"::help queue\" and \"::help syncq\"\n");
1629*0Sstevel@tonic-gate }
1630*0Sstevel@tonic-gate 
1631*0Sstevel@tonic-gate void
1632*0Sstevel@tonic-gate mblk_help(void)
1633*0Sstevel@tonic-gate {
1634*0Sstevel@tonic-gate 	mdb_printf("Print mblock information for a given mblk pointer.\n"
1635*0Sstevel@tonic-gate 	    "Without the address, print information about all mblocks.\n\n"
1636*0Sstevel@tonic-gate 	    "Fields printed:\n"
1637*0Sstevel@tonic-gate 	    "	ADDR:\tmblk address\n"
1638*0Sstevel@tonic-gate 	    "	FL:\tFlags\n"
1639*0Sstevel@tonic-gate 	    "	TYPE:\tType of corresponding dblock\n"
1640*0Sstevel@tonic-gate 	    "	LEN:\tData length as b_wptr - b_rptr\n"
1641*0Sstevel@tonic-gate 	    "	BLEN:\tDblock space as db_lim - db_base\n"
1642*0Sstevel@tonic-gate 	    "	RPTR:\tRead pointer\n"
1643*0Sstevel@tonic-gate 	    "	DBLK:\tDblock pointer\n\n"
1644*0Sstevel@tonic-gate 	    "Options:\n"
1645*0Sstevel@tonic-gate 	    "	-v:\t\tbe verbose - print symbolic flags falues\n"
1646*0Sstevel@tonic-gate 	    "	-q:\t\tbe quiet - print mblk pointer only\n"
1647*0Sstevel@tonic-gate 	    "	-d dbaddr:\t\tprint mblks with specified dblk address\n"
1648*0Sstevel@tonic-gate 	    "	-f flag:\tprint only mblks with flag set\n"
1649*0Sstevel@tonic-gate 	    "	-F flag:\tprint only mblks with flag NOT set\n"
1650*0Sstevel@tonic-gate 	    "	-t type:\tprint only mblks of specified db_type\n"
1651*0Sstevel@tonic-gate 	    "	-T type:\tprint only mblks other then the specified db_type\n"
1652*0Sstevel@tonic-gate 	    "	-l len:\t\ttprint only mblks with MBLKL == len\n"
1653*0Sstevel@tonic-gate 	    "	-L len:\t\tprint only mblks with MBLKL <= len \n"
1654*0Sstevel@tonic-gate 	    "	-G len:\t\tprint only mblks with MBLKL >= len \n"
1655*0Sstevel@tonic-gate 	    "	-b len:\t\tprint only mblks with db_lim - db_base == len\n"
1656*0Sstevel@tonic-gate 	    "\n");
1657*0Sstevel@tonic-gate }
1658