xref: /titanic_51/usr/src/cmd/mdb/common/modules/genunix/mmd.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Multidata dcmds and walkers, part of the genunix mdb module,
31*7c478bd9Sstevel@tonic-gate  * and operate on core Multidata structures.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
35*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_ks.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/strft.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #include <sys/multidata.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/multidata_impl.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/pattr.h>
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #include "mmd.h"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * Structure for passing internal variables.
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate typedef struct mmd_data_s {
55*7c478bd9Sstevel@tonic-gate 	uint_t	flags;		/* see flags values below */
56*7c478bd9Sstevel@tonic-gate 	uint_t	counter;	/* scratch counter */
57*7c478bd9Sstevel@tonic-gate } mmd_data_t;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #define	MMD_VERBOSE	0x1	/* multidata: provide more info */
60*7c478bd9Sstevel@tonic-gate #define	MMD_STATS	0x2	/* multidata: provide statistics */
61*7c478bd9Sstevel@tonic-gate #define	PD_HDR		0x4	/* pdesc: count header region */
62*7c478bd9Sstevel@tonic-gate #define	PD_PLD		0x8	/* pdesc: count payload region(s) */
63*7c478bd9Sstevel@tonic-gate #define	PD_ATTR		0x10	/* pdesc: count local attributes */
64*7c478bd9Sstevel@tonic-gate #define	PD_REM_NOCNT	0x20	/* pdesc: do not count removed pdesc */
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /*
67*7c478bd9Sstevel@tonic-gate  * Structure to support circular, doubly-linked list (ql_t) walker.
68*7c478bd9Sstevel@tonic-gate  */
69*7c478bd9Sstevel@tonic-gate typedef struct q_walk_s {
70*7c478bd9Sstevel@tonic-gate 	char *qw_name;		/* name of opaque list structure */
71*7c478bd9Sstevel@tonic-gate 	uintptr_t qw_head;	/* address of list head */
72*7c478bd9Sstevel@tonic-gate 	void *qw_data;		/* opaque data structure */
73*7c478bd9Sstevel@tonic-gate 	uint_t qw_sz;		/* size of opaque data structure */
74*7c478bd9Sstevel@tonic-gate 	uint_t qw_off;		/* ql_t offset in opaque data structure */
75*7c478bd9Sstevel@tonic-gate 	uint_t qw_step;		/* walk_step has been called */
76*7c478bd9Sstevel@tonic-gate 	uint_t qw_iprint;	/* initial print */
77*7c478bd9Sstevel@tonic-gate } q_walk_t;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate static int pdesc_slab_print(uintptr_t, q_walk_t *, mmd_data_t *);
80*7c478bd9Sstevel@tonic-gate static int pdesc_print(uintptr_t, q_walk_t *, mmd_data_t *);
81*7c478bd9Sstevel@tonic-gate static int pdesc_count(uintptr_t, q_walk_t *, mmd_data_t *);
82*7c478bd9Sstevel@tonic-gate static int pattr_print(uintptr_t, q_walk_t *, mmd_data_t *);
83*7c478bd9Sstevel@tonic-gate static int pattr_count(uintptr_t, q_walk_t *, mmd_data_t *);
84*7c478bd9Sstevel@tonic-gate static int multidata_stats(uintptr_t addr, multidata_t *);
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #define	VA_OFF(x, o)	(((uchar_t *)(x) + (o)))
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate /*
89*7c478bd9Sstevel@tonic-gate  * A dcmd which prints a summary of a multidata_t structure.
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
92*7c478bd9Sstevel@tonic-gate int
93*7c478bd9Sstevel@tonic-gate multidata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate 	mmd_data_t data;
96*7c478bd9Sstevel@tonic-gate 	multidata_t mmd;
97*7c478bd9Sstevel@tonic-gate 	char str[32] = "-";
98*7c478bd9Sstevel@tonic-gate 	int i = 0;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	bzero(&data, sizeof (data));
101*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
102*7c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, MMD_VERBOSE, &data.flags,
103*7c478bd9Sstevel@tonic-gate 	    's', MDB_OPT_SETBITS, MMD_STATS, &data.flags, NULL) != argc)
104*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&mmd, sizeof (mmd), addr) == -1) {
107*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read multidata_t structure at %p", addr);
108*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
109*7c478bd9Sstevel@tonic-gate 	}
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	if (mmd.mmd_magic != MULTIDATA_MAGIC)
112*7c478bd9Sstevel@tonic-gate 		mdb_printf("Incorrect Multidata magic number at %p\n",
113*7c478bd9Sstevel@tonic-gate 		    VA_OFF(addr, offsetof(multidata_t, mmd_magic)));
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
116*7c478bd9Sstevel@tonic-gate 	if (data.flags & MMD_STATS) {
117*7c478bd9Sstevel@tonic-gate 		if ((i = multidata_stats(addr, &mmd)) != DCMD_OK)
118*7c478bd9Sstevel@tonic-gate 			return (i);
119*7c478bd9Sstevel@tonic-gate 	}
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	mdb_printf("%<b>%-5s %-?s %-4s %-?s %-4s %-4s %-4s %-?s%</b>",
122*7c478bd9Sstevel@tonic-gate 	    "PDESC", "PATTBL", "HBUF", "HBUF", "PBUF", "PBUF", "PBUF", "PBUF");
123*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
124*7c478bd9Sstevel@tonic-gate 	mdb_printf("%<b>%<u>%-5s %-?s %-4s %-?s %-4s %-4s %-4s %-?s%</u>%</b>",
125*7c478bd9Sstevel@tonic-gate 	    "CNT", "ADDRESS", "REF", "ADDRESS", "REF", "CNT", "IDX",
126*7c478bd9Sstevel@tonic-gate 	    "ADDRESS(ES)");
127*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 	if (mmd.mmd_pattbl != 0)
130*7c478bd9Sstevel@tonic-gate 		mdb_snprintf(str, sizeof (str), "%016p", mmd.mmd_pattbl);
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	i = 0;
133*7c478bd9Sstevel@tonic-gate 	mdb_printf("%-5d %-16s %-4d %016p %-4d %-4d %-4d %016p\n",
134*7c478bd9Sstevel@tonic-gate 	    mmd.mmd_pd_cnt, str, mmd.mmd_hbuf_ref, mmd.mmd_hbuf,
135*7c478bd9Sstevel@tonic-gate 	    mmd.mmd_pbuf_ref, mmd.mmd_pbuf_cnt, i, mmd.mmd_pbuf[i]);
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	for (++i; i < mmd.mmd_pbuf_cnt; i++)
138*7c478bd9Sstevel@tonic-gate 		mdb_printf("%-54s %-4d %016p\n", "", i, mmd.mmd_pbuf[i]);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	if (!(data.flags & MMD_VERBOSE))
141*7c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/* Walk packet descriptor slab list */
144*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("pdesc_slab", (mdb_walk_cb_t)pdesc_slab_print,
145*7c478bd9Sstevel@tonic-gate 	    &data, (uintptr_t)VA_OFF(addr, offsetof(multidata_t,
146*7c478bd9Sstevel@tonic-gate 	    mmd_pd_slab_q))) == -1) {
147*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk pdesc_slab_t list");
148*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	/* Walk packet descriptor list */
152*7c478bd9Sstevel@tonic-gate 	data.counter = 0;
153*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_print,
154*7c478bd9Sstevel@tonic-gate 	    &data, (uintptr_t)VA_OFF(addr, offsetof(multidata_t,
155*7c478bd9Sstevel@tonic-gate 	    mmd_pd_q))) == -1) {
156*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk pdesc_t list");
157*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
161*7c478bd9Sstevel@tonic-gate }
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate /*
164*7c478bd9Sstevel@tonic-gate  * Print additional Multidata statistics
165*7c478bd9Sstevel@tonic-gate  */
166*7c478bd9Sstevel@tonic-gate static int
167*7c478bd9Sstevel@tonic-gate multidata_stats(uintptr_t addr, multidata_t *mmd)
168*7c478bd9Sstevel@tonic-gate {
169*7c478bd9Sstevel@tonic-gate 	mblk_t mp;
170*7c478bd9Sstevel@tonic-gate 	uint_t i = 0, j = 0, k = 0, sz = 0;
171*7c478bd9Sstevel@tonic-gate 	mmd_data_t data;
172*7c478bd9Sstevel@tonic-gate 	uintptr_t patbkt;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	bzero(&data, sizeof (data));
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	if (mmd->mmd_hbuf != 0) {
177*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&mp, sizeof (mp),
178*7c478bd9Sstevel@tonic-gate 		    (uintptr_t)mmd->mmd_hbuf) == -1) {
179*7c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't read mblk_t at %p", mmd->mmd_hbuf);
180*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
181*7c478bd9Sstevel@tonic-gate 		}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 		i++;
184*7c478bd9Sstevel@tonic-gate 		sz = MBLKL(&mp);
185*7c478bd9Sstevel@tonic-gate 	}
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	k += sz;	/* total bytes */
188*7c478bd9Sstevel@tonic-gate 	j += i;		/* total buffers */
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	mdb_printf("%<b>%<u>BUFFER STATS%</b>%</u>\n");
191*7c478bd9Sstevel@tonic-gate 	mdb_printf("Header:\t\t\t%-4d% buffer,\t%-12d bytes\n", i, sz);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	for (i = 0, sz = 0; i < mmd->mmd_pbuf_cnt; i++) {
194*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&mp, sizeof (mp),
195*7c478bd9Sstevel@tonic-gate 		    (uintptr_t)mmd->mmd_pbuf[i]) == -1) {
196*7c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't read mblk_t at %p",
197*7c478bd9Sstevel@tonic-gate 			    mmd->mmd_pbuf[i]);
198*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
199*7c478bd9Sstevel@tonic-gate 		}
200*7c478bd9Sstevel@tonic-gate 		sz += MBLKL(&mp);
201*7c478bd9Sstevel@tonic-gate 	}
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	k += sz;	/* total bytes */
204*7c478bd9Sstevel@tonic-gate 	j += i;		/* total buffers */
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	mdb_printf("%<u>Payload:\t\t%-4d buffers,\t%-12d bytes%</u>\n", i, sz);
207*7c478bd9Sstevel@tonic-gate 	mdb_printf("Total:\t\t\t%-4d buffers,\t%-12d bytes\n\n", j, k);
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	mdb_printf("%<b>%<u>PACKET DESCRIPTOR STATS%</u>%</b>\n");
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	/*
212*7c478bd9Sstevel@tonic-gate 	 * Total claimed packet descriptors
213*7c478bd9Sstevel@tonic-gate 	 */
214*7c478bd9Sstevel@tonic-gate 	data.flags = 0;
215*7c478bd9Sstevel@tonic-gate 	data.counter = 0;
216*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
217*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
218*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk pdesc_t list");
219*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 	i = data.counter;	/* claimed */
222*7c478bd9Sstevel@tonic-gate 	mdb_printf("Total claimed:\t\t%-4d", i);
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	/*
225*7c478bd9Sstevel@tonic-gate 	 * Total active header references
226*7c478bd9Sstevel@tonic-gate 	 */
227*7c478bd9Sstevel@tonic-gate 	data.flags = (PD_HDR | PD_REM_NOCNT);
228*7c478bd9Sstevel@tonic-gate 	data.counter = 0;
229*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
230*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
231*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk pdesc_t list");
232*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
233*7c478bd9Sstevel@tonic-gate 	}
234*7c478bd9Sstevel@tonic-gate 	mdb_printf("\tActive header refs:\t%-12d bytes\n", data.counter);
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	/*
237*7c478bd9Sstevel@tonic-gate 	 * Total active packet descriptors
238*7c478bd9Sstevel@tonic-gate 	 */
239*7c478bd9Sstevel@tonic-gate 	data.flags = PD_REM_NOCNT;
240*7c478bd9Sstevel@tonic-gate 	data.counter = 0;
241*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
242*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
243*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk pdesc_t list");
244*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 	k = data.counter;	/* active */
247*7c478bd9Sstevel@tonic-gate 	mdb_printf("Active:\t\t\t%-4d", data.counter);
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	/*
250*7c478bd9Sstevel@tonic-gate 	 * Total active payload references
251*7c478bd9Sstevel@tonic-gate 	 */
252*7c478bd9Sstevel@tonic-gate 	data.flags = (PD_PLD | PD_REM_NOCNT);
253*7c478bd9Sstevel@tonic-gate 	data.counter = 0;
254*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
255*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
256*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk pdesc_t list");
257*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate 	mdb_printf("\t%<u>Active payload refs:\t%-12d bytes%</u>\n",
260*7c478bd9Sstevel@tonic-gate 	    data.counter);
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	/*
263*7c478bd9Sstevel@tonic-gate 	 * Number of removed packet descriptors (claimed - active)
264*7c478bd9Sstevel@tonic-gate 	 */
265*7c478bd9Sstevel@tonic-gate 	mdb_printf("Removed:\t\t%-4d", i - k);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	/*
268*7c478bd9Sstevel@tonic-gate 	 * Total active header and payload references
269*7c478bd9Sstevel@tonic-gate 	 */
270*7c478bd9Sstevel@tonic-gate 	data.flags = (PD_PLD | PD_HDR | PD_REM_NOCNT);
271*7c478bd9Sstevel@tonic-gate 	data.counter = 0;
272*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
273*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
274*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk pdesc_t list");
275*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
276*7c478bd9Sstevel@tonic-gate 	}
277*7c478bd9Sstevel@tonic-gate 	mdb_printf("\tTotal:\t\t\t%-12d bytes\n\n", data.counter);
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	mdb_printf("%<b>%<u>ACTIVE ATTRIBUTE STATS%</u>%</b>\n");
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	/*
282*7c478bd9Sstevel@tonic-gate 	 * Count local attributes
283*7c478bd9Sstevel@tonic-gate 	 */
284*7c478bd9Sstevel@tonic-gate 	data.flags = (PD_ATTR | PD_REM_NOCNT);
285*7c478bd9Sstevel@tonic-gate 	data.counter = 0;
286*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
287*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
288*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk pdesc_t list");
289*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
290*7c478bd9Sstevel@tonic-gate 	}
291*7c478bd9Sstevel@tonic-gate 	mdb_printf("Local:\t\t\t%-4d", data.counter);
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	/*
294*7c478bd9Sstevel@tonic-gate 	 * Count global attributes
295*7c478bd9Sstevel@tonic-gate 	 */
296*7c478bd9Sstevel@tonic-gate 	data.counter = 0;
297*7c478bd9Sstevel@tonic-gate 	patbkt = (uintptr_t)mmd->mmd_pattbl;
298*7c478bd9Sstevel@tonic-gate 	if (patbkt != 0) {
299*7c478bd9Sstevel@tonic-gate 		uint_t pattbl_sz;
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 		/* Figure out the size of hash table */
302*7c478bd9Sstevel@tonic-gate 		mdb_readvar(&pattbl_sz, "pattbl_sz");
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 		/* Walk each bucket and count its contents */
305*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < (pattbl_sz * sizeof (patbkt_t));
306*7c478bd9Sstevel@tonic-gate 		    i += sizeof (patbkt_t)) {
307*7c478bd9Sstevel@tonic-gate 			if (mdb_pwalk("pattr",
308*7c478bd9Sstevel@tonic-gate 			    (mdb_walk_cb_t)pattr_count, &data,
309*7c478bd9Sstevel@tonic-gate 			    patbkt + i + offsetof(patbkt_t,
310*7c478bd9Sstevel@tonic-gate 			    pbkt_pattr_q)) == -1) {
311*7c478bd9Sstevel@tonic-gate 				mdb_warn("couldn't walk pattr_t list");
312*7c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
313*7c478bd9Sstevel@tonic-gate 			}
314*7c478bd9Sstevel@tonic-gate 		}
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 	mdb_printf("\tGlobal:\t\t\t%-4d\n", data.counter);
317*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
320*7c478bd9Sstevel@tonic-gate }
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate /*
323*7c478bd9Sstevel@tonic-gate  * Print the contents of a packet descriptor slab (pdesc_slab_t) structure.
324*7c478bd9Sstevel@tonic-gate  */
325*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
326*7c478bd9Sstevel@tonic-gate static int
327*7c478bd9Sstevel@tonic-gate pdesc_slab_print(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
328*7c478bd9Sstevel@tonic-gate {
329*7c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab;
330*7c478bd9Sstevel@tonic-gate 	uint_t pdslab_sz, slab_sz;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	/* Figure out how many descriptors in a slab */
333*7c478bd9Sstevel@tonic-gate 	mdb_readvar(&pdslab_sz, "pdslab_sz");
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	/* This shouldn't be true, unless something awful has happened */
336*7c478bd9Sstevel@tonic-gate 	if (pdslab_sz < 1) {
337*7c478bd9Sstevel@tonic-gate 		mdb_warn("incorrect pdslab_sz (0)");
338*7c478bd9Sstevel@tonic-gate 		pdslab_sz = 1;
339*7c478bd9Sstevel@tonic-gate 	}
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	/* Read in the entire slab chunk; may be of use one day */
342*7c478bd9Sstevel@tonic-gate 	slab_sz = PDESC_SLAB_SIZE(pdslab_sz);
343*7c478bd9Sstevel@tonic-gate 	slab = mdb_alloc(slab_sz, UM_SLEEP);
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(slab, slab_sz, addr) == -1) {
346*7c478bd9Sstevel@tonic-gate 		mdb_free(slab, slab_sz);
347*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read pdesc_slab_t at %p", addr);
348*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	if (!qwp->qw_step)
352*7c478bd9Sstevel@tonic-gate 		mdb_printf("\n%<b>%<u>%-?s %7s %7s%</u>%</b>\n",
353*7c478bd9Sstevel@tonic-gate 		    "PDESC SLAB ADDR", "SIZE", "CLAIMED");
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	mdb_printf("%016p %7d %7d\n", addr, slab->pds_sz, slab->pds_used);
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	mdb_free(slab, slab_sz);
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
360*7c478bd9Sstevel@tonic-gate }
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate /*
363*7c478bd9Sstevel@tonic-gate  * Generic packet descriptor (pdesc_t) counting routine.
364*7c478bd9Sstevel@tonic-gate  */
365*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
366*7c478bd9Sstevel@tonic-gate static int
367*7c478bd9Sstevel@tonic-gate pdesc_count(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
368*7c478bd9Sstevel@tonic-gate {
369*7c478bd9Sstevel@tonic-gate 	pdesc_t pd;
370*7c478bd9Sstevel@tonic-gate 	int i;
371*7c478bd9Sstevel@tonic-gate 	uint_t f = data->flags;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
374*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read pdesc_t at %p", addr);
375*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
376*7c478bd9Sstevel@tonic-gate 	}
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	if (pd.pd_magic != PDESC_MAGIC)
379*7c478bd9Sstevel@tonic-gate 		mdb_printf("Incorrect pdesc magic number at %p\n",
380*7c478bd9Sstevel@tonic-gate 		    VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	if (f == 0) {
383*7c478bd9Sstevel@tonic-gate 		/* No flags set, count all pdescs */
384*7c478bd9Sstevel@tonic-gate 		data->counter++;
385*7c478bd9Sstevel@tonic-gate 	} else if (f == PD_REM_NOCNT && !(pd.pd_pdi.flags & PDESC_REM_DEFER)) {
386*7c478bd9Sstevel@tonic-gate 		/* Count only active (skip removed) pdescs */
387*7c478bd9Sstevel@tonic-gate 		data->counter++;
388*7c478bd9Sstevel@tonic-gate 	} else if (f & PD_ATTR) {
389*7c478bd9Sstevel@tonic-gate 		uint_t pattbl_sz;
390*7c478bd9Sstevel@tonic-gate 		uintptr_t patbkt = (uintptr_t)pd.pd_pattbl;
391*7c478bd9Sstevel@tonic-gate 		mmd_data_t attr_data;
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 		/* Count local attributes */
394*7c478bd9Sstevel@tonic-gate 		if ((!(f & PD_REM_NOCNT) || ((f & PD_REM_NOCNT) &&
395*7c478bd9Sstevel@tonic-gate 		    !(pd.pd_pdi.flags & PDESC_REM_DEFER))) && patbkt != 0) {
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 			/* Figure out the size of hash table */
398*7c478bd9Sstevel@tonic-gate 			mdb_readvar(&pattbl_sz, "pattbl_sz");
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 			attr_data.counter = 0;
401*7c478bd9Sstevel@tonic-gate 			/* Walk each bucket and count its contents */
402*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < (pattbl_sz * sizeof (patbkt_t));
403*7c478bd9Sstevel@tonic-gate 			    i += sizeof (patbkt_t)) {
404*7c478bd9Sstevel@tonic-gate 				if (mdb_pwalk("pattr",
405*7c478bd9Sstevel@tonic-gate 				    (mdb_walk_cb_t)pattr_count, &attr_data,
406*7c478bd9Sstevel@tonic-gate 				    patbkt + i + offsetof(patbkt_t,
407*7c478bd9Sstevel@tonic-gate 				    pbkt_pattr_q)) == -1) {
408*7c478bd9Sstevel@tonic-gate 					mdb_warn("couldn't walk pattr_t list");
409*7c478bd9Sstevel@tonic-gate 					return (WALK_ERR);
410*7c478bd9Sstevel@tonic-gate 				}
411*7c478bd9Sstevel@tonic-gate 			}
412*7c478bd9Sstevel@tonic-gate 			data->counter += attr_data.counter;
413*7c478bd9Sstevel@tonic-gate 		}
414*7c478bd9Sstevel@tonic-gate 	} else {
415*7c478bd9Sstevel@tonic-gate 		if (f & PD_HDR) {
416*7c478bd9Sstevel@tonic-gate 			/* Count header span referenced by pdesc */
417*7c478bd9Sstevel@tonic-gate 			if (!(f & PD_REM_NOCNT) || ((f & PD_REM_NOCNT) &&
418*7c478bd9Sstevel@tonic-gate 			    !(pd.pd_pdi.flags & PDESC_REM_DEFER)))
419*7c478bd9Sstevel@tonic-gate 				data->counter += PDESC_HDRL(&pd.pd_pdi);
420*7c478bd9Sstevel@tonic-gate 		}
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 		if (f & PD_PLD) {
423*7c478bd9Sstevel@tonic-gate 			/* Count payload span referenced by pdesc */
424*7c478bd9Sstevel@tonic-gate 			if (!(f & PD_REM_NOCNT) || ((f & PD_REM_NOCNT) &&
425*7c478bd9Sstevel@tonic-gate 			    !(pd.pd_pdi.flags & PDESC_REM_DEFER))) {
426*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < pd.pd_pdi.pld_cnt; i++)
427*7c478bd9Sstevel@tonic-gate 					data->counter += PDESC_PLD_SPAN_SIZE(
428*7c478bd9Sstevel@tonic-gate 					    &pd.pd_pdi, i);
429*7c478bd9Sstevel@tonic-gate 			}
430*7c478bd9Sstevel@tonic-gate 		}
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
434*7c478bd9Sstevel@tonic-gate }
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate /*
437*7c478bd9Sstevel@tonic-gate  * Print the contents of a packet descriptor (pdesc_t) structure.
438*7c478bd9Sstevel@tonic-gate  */
439*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
440*7c478bd9Sstevel@tonic-gate static int
441*7c478bd9Sstevel@tonic-gate pdesc_print(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
442*7c478bd9Sstevel@tonic-gate {
443*7c478bd9Sstevel@tonic-gate 	pdesc_t pd;
444*7c478bd9Sstevel@tonic-gate 	int i = 0;
445*7c478bd9Sstevel@tonic-gate 	char str[32] = "-";
446*7c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t pd_flags_bits[] = {
447*7c478bd9Sstevel@tonic-gate 		{ "H", PDESC_HBUF_REF, PDESC_HBUF_REF },
448*7c478bd9Sstevel@tonic-gate 		{ "P", PDESC_PBUF_REF, PDESC_PBUF_REF },
449*7c478bd9Sstevel@tonic-gate 		{ "R", PDESC_REM_DEFER, PDESC_REM_DEFER },
450*7c478bd9Sstevel@tonic-gate 		{ NULL, 0, 0 }
451*7c478bd9Sstevel@tonic-gate 	};
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
454*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read pdesc_t at %p", addr);
455*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
456*7c478bd9Sstevel@tonic-gate 	}
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	if (pd.pd_magic != PDESC_MAGIC)
459*7c478bd9Sstevel@tonic-gate 		mdb_printf("Incorrect pdesc magic number at %p\n",
460*7c478bd9Sstevel@tonic-gate 		    VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	if (!qwp->qw_step) {
463*7c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
464*7c478bd9Sstevel@tonic-gate 		mdb_printf("%<b>%-3s %-16s %-16s %-4s %-4s %-4s %-4s %-4s %-4s "
465*7c478bd9Sstevel@tonic-gate 		    "%-4s %-6s%</b>",
466*7c478bd9Sstevel@tonic-gate 		    "", "PDESC", "PATTBL", "HDR", "HDR",
467*7c478bd9Sstevel@tonic-gate 		    "HDR", "HDR", "PLD", "PBUF", "PLD", "");
468*7c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
469*7c478bd9Sstevel@tonic-gate 		mdb_printf(
470*7c478bd9Sstevel@tonic-gate 		    "%<b>%<u>%-3s %-16s %-16s %-4s %-4s %-4s %-4s %-4s %-4s "
471*7c478bd9Sstevel@tonic-gate 		    "%-4s %-6s%</u>%</b>",
472*7c478bd9Sstevel@tonic-gate 		    "NO.", "ADDRESS", "ADDRESS", "SIZE", "HEAD",
473*7c478bd9Sstevel@tonic-gate 		    "LEN", "TAIL", "CNT", "IDX", "SIZE", "FLAGS");
474*7c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	if (pd.pd_pattbl != 0)
478*7c478bd9Sstevel@tonic-gate 		mdb_snprintf(str, sizeof (str), "%016p", pd.pd_pattbl);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	mdb_printf("%-3d %016p %-16s %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-6b\n",
481*7c478bd9Sstevel@tonic-gate 	    ++data->counter, addr, str,
482*7c478bd9Sstevel@tonic-gate 	    PDESC_HDRSIZE(&pd.pd_pdi), PDESC_HDRHEAD(&pd.pd_pdi),
483*7c478bd9Sstevel@tonic-gate 	    PDESC_HDRL(&pd.pd_pdi), PDESC_HDRTAIL(&pd.pd_pdi),
484*7c478bd9Sstevel@tonic-gate 	    pd.pd_pdi.pld_cnt, pd.pd_pdi.pld_ary[i].pld_pbuf_idx,
485*7c478bd9Sstevel@tonic-gate 	    PDESC_PLD_SPAN_SIZE(&pd.pd_pdi, i), pd.pd_pdi.flags, pd_flags_bits);
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	for (++i; i < pd.pd_pdi.pld_cnt; i++)
488*7c478bd9Sstevel@tonic-gate 		mdb_printf("%-62s %-4d %-4d\n",
489*7c478bd9Sstevel@tonic-gate 		    "", pd.pd_pdi.pld_ary[i].pld_pbuf_idx,
490*7c478bd9Sstevel@tonic-gate 		    PDESC_PLD_SPAN_SIZE(&pd.pd_pdi, i));
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
493*7c478bd9Sstevel@tonic-gate }
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate /*
496*7c478bd9Sstevel@tonic-gate  * General purpose ql_t walk_init routine.
497*7c478bd9Sstevel@tonic-gate  */
498*7c478bd9Sstevel@tonic-gate static int
499*7c478bd9Sstevel@tonic-gate mmdq_walk_init(mdb_walk_state_t *wsp, char *name, uintptr_t qh,
500*7c478bd9Sstevel@tonic-gate     uint_t sz, uint_t ql_off)
501*7c478bd9Sstevel@tonic-gate {
502*7c478bd9Sstevel@tonic-gate 	q_walk_t *qwp;
503*7c478bd9Sstevel@tonic-gate 	ql_t ql;
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	/* Caller must have supplied an address */
506*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
507*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	qwp = mdb_alloc(sizeof (*qwp), UM_SLEEP);
510*7c478bd9Sstevel@tonic-gate 	qwp->qw_name = name;
511*7c478bd9Sstevel@tonic-gate 	qwp->qw_head = qh;
512*7c478bd9Sstevel@tonic-gate 	qwp->qw_data = sz > 0 ? mdb_alloc(sz, UM_SLEEP) : NULL;
513*7c478bd9Sstevel@tonic-gate 	qwp->qw_sz = sz;
514*7c478bd9Sstevel@tonic-gate 	qwp->qw_off = ql_off;
515*7c478bd9Sstevel@tonic-gate 	qwp->qw_step = FALSE;
516*7c478bd9Sstevel@tonic-gate 	qwp->qw_iprint = TRUE;
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	wsp->walk_data = qwp;
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(qwp->qw_data, qwp->qw_sz, wsp->walk_addr) == -1) {
521*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read %s at %p", qwp->qw_name,
522*7c478bd9Sstevel@tonic-gate 		    wsp->walk_addr);
523*7c478bd9Sstevel@tonic-gate 		mmdq_walk_fini(wsp);
524*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
525*7c478bd9Sstevel@tonic-gate 	}
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 	bcopy((uchar_t *)qwp->qw_data + qwp->qw_off, &ql, sizeof (ql));
528*7c478bd9Sstevel@tonic-gate 	if (qh == (uintptr_t)ql.ql_next) {
529*7c478bd9Sstevel@tonic-gate 		mmdq_walk_fini(wsp);
530*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
531*7c478bd9Sstevel@tonic-gate 	}
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)ql.ql_next;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
536*7c478bd9Sstevel@tonic-gate }
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate /*
539*7c478bd9Sstevel@tonic-gate  * General purpose ql_t walk_step routine.
540*7c478bd9Sstevel@tonic-gate  */
541*7c478bd9Sstevel@tonic-gate int
542*7c478bd9Sstevel@tonic-gate mmdq_walk_step(mdb_walk_state_t *wsp)
543*7c478bd9Sstevel@tonic-gate {
544*7c478bd9Sstevel@tonic-gate 	q_walk_t *qwp = (q_walk_t *)wsp->walk_data;
545*7c478bd9Sstevel@tonic-gate 	int status = WALK_NEXT;
546*7c478bd9Sstevel@tonic-gate 	ql_t ql;
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	/* We've wrapped around the circular list */
549*7c478bd9Sstevel@tonic-gate 	if (qwp->qw_step && wsp->walk_addr == qwp->qw_head)
550*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
553*7c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(qwp->qw_data, qwp->qw_sz, wsp->walk_addr) == -1) {
556*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read %s at %p", qwp->qw_name,
557*7c478bd9Sstevel@tonic-gate 		    wsp->walk_addr);
558*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
559*7c478bd9Sstevel@tonic-gate 	}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	/* Go forward to the next one */
562*7c478bd9Sstevel@tonic-gate 	bcopy((uchar_t *)qwp->qw_data + qwp->qw_off, &ql, sizeof (ql));
563*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)ql.ql_next;
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	/* We've done the first walk */
566*7c478bd9Sstevel@tonic-gate 	qwp->qw_step = TRUE;
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	return (status);
569*7c478bd9Sstevel@tonic-gate }
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate /*
572*7c478bd9Sstevel@tonic-gate  * General purpose ql_t walk_fini routine.
573*7c478bd9Sstevel@tonic-gate  */
574*7c478bd9Sstevel@tonic-gate void
575*7c478bd9Sstevel@tonic-gate mmdq_walk_fini(mdb_walk_state_t *wsp)
576*7c478bd9Sstevel@tonic-gate {
577*7c478bd9Sstevel@tonic-gate 	q_walk_t *qwp = (q_walk_t *)wsp->walk_data;
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	if (qwp->qw_data != NULL)
580*7c478bd9Sstevel@tonic-gate 		mdb_free(qwp->qw_data, qwp->qw_sz);
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	mdb_free(qwp, sizeof (*qwp));
583*7c478bd9Sstevel@tonic-gate }
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate /*
586*7c478bd9Sstevel@tonic-gate  * Packet descriptor slab (pdesc_slab_t) walker initialization routine.
587*7c478bd9Sstevel@tonic-gate  */
588*7c478bd9Sstevel@tonic-gate int
589*7c478bd9Sstevel@tonic-gate pdesc_slab_walk_init(mdb_walk_state_t *wsp)
590*7c478bd9Sstevel@tonic-gate {
591*7c478bd9Sstevel@tonic-gate 	uintptr_t q_head;
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
594*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	/*
597*7c478bd9Sstevel@tonic-gate 	 * If we're called from multidata dcmd, then we're passed in
598*7c478bd9Sstevel@tonic-gate 	 * the address of ql_t head; otherwise we'd have to get the
599*7c478bd9Sstevel@tonic-gate 	 * address ourselves.
600*7c478bd9Sstevel@tonic-gate 	 */
601*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_cbdata == NULL) {
602*7c478bd9Sstevel@tonic-gate 		pdesc_slab_t slab;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 		/* Read in pdesc_slab_t */
605*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&slab, sizeof (slab), wsp->walk_addr) == -1) {
606*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read pdesc_slab_t at %p",
607*7c478bd9Sstevel@tonic-gate 			    wsp->walk_addr);
608*7c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
609*7c478bd9Sstevel@tonic-gate 		}
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 		/* pdesc_slab_t head is inside multidata_t */
612*7c478bd9Sstevel@tonic-gate 		q_head = (uintptr_t)VA_OFF(slab.pds_mmd,
613*7c478bd9Sstevel@tonic-gate 		    offsetof(multidata_t, mmd_pd_slab_q));
614*7c478bd9Sstevel@tonic-gate 	} else
615*7c478bd9Sstevel@tonic-gate 		q_head = wsp->walk_addr;
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	/* Pass it on to our generic ql_t walker init */
618*7c478bd9Sstevel@tonic-gate 	return (mmdq_walk_init(wsp, "pdesc_slab_t", q_head,
619*7c478bd9Sstevel@tonic-gate 	    sizeof (pdesc_slab_t), offsetof(pdesc_slab_t, pds_next)));
620*7c478bd9Sstevel@tonic-gate }
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate /*
623*7c478bd9Sstevel@tonic-gate  * A dcmd which returns a multidata_t pointer from a pdesc_slab_t structure.
624*7c478bd9Sstevel@tonic-gate  */
625*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
626*7c478bd9Sstevel@tonic-gate int
627*7c478bd9Sstevel@tonic-gate slab2multidata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
628*7c478bd9Sstevel@tonic-gate {
629*7c478bd9Sstevel@tonic-gate 	pdesc_slab_t slab;
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
632*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&slab, sizeof (slab), addr) == -1) {
635*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read pdesc_slab_t at %p", addr);
636*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
637*7c478bd9Sstevel@tonic-gate 	}
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	mdb_printf("%p\n", slab.pds_mmd);
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
642*7c478bd9Sstevel@tonic-gate }
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate /*
645*7c478bd9Sstevel@tonic-gate  * Packet descriptor (pdesc_t) walker initialization routine.
646*7c478bd9Sstevel@tonic-gate  */
647*7c478bd9Sstevel@tonic-gate int
648*7c478bd9Sstevel@tonic-gate pdesc_walk_init(mdb_walk_state_t *wsp)
649*7c478bd9Sstevel@tonic-gate {
650*7c478bd9Sstevel@tonic-gate 	uintptr_t q_head;
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
653*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	/*
656*7c478bd9Sstevel@tonic-gate 	 * If we're called from multidata dcmd, then we're passed in
657*7c478bd9Sstevel@tonic-gate 	 * the address of ql_t head; otherwise we'd have to get the
658*7c478bd9Sstevel@tonic-gate 	 * address ourselves.
659*7c478bd9Sstevel@tonic-gate 	 */
660*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_cbdata == NULL) {
661*7c478bd9Sstevel@tonic-gate 		pdesc_t pd;
662*7c478bd9Sstevel@tonic-gate 		pdesc_slab_t slab;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 		/* First we get pdsec_t */
665*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&pd, sizeof (pd), wsp->walk_addr) == -1) {
666*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read pdesc_t at %p",
667*7c478bd9Sstevel@tonic-gate 			    wsp->walk_addr);
668*7c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
669*7c478bd9Sstevel@tonic-gate 		}
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 		/* And then the pdesc_slab_t */
672*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&slab, sizeof (slab),
673*7c478bd9Sstevel@tonic-gate 		    (uintptr_t)pd.pd_slab) == -1) {
674*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read pdesc_slab_t at %p",
675*7c478bd9Sstevel@tonic-gate 			    (uintptr_t)pd.pd_slab);
676*7c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
677*7c478bd9Sstevel@tonic-gate 		}
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 		/* pdesc_t head is inside multidata_t */
680*7c478bd9Sstevel@tonic-gate 		q_head = (uintptr_t)VA_OFF(slab.pds_mmd,
681*7c478bd9Sstevel@tonic-gate 		    offsetof(multidata_t, mmd_pd_q));
682*7c478bd9Sstevel@tonic-gate 	} else
683*7c478bd9Sstevel@tonic-gate 		q_head = wsp->walk_addr;
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	/* Pass it on to our generic ql_t walker init */
686*7c478bd9Sstevel@tonic-gate 	return (mmdq_walk_init(wsp, "pdesc_t", q_head,
687*7c478bd9Sstevel@tonic-gate 	    sizeof (pdesc_t), offsetof(pdesc_t, pd_next)));
688*7c478bd9Sstevel@tonic-gate }
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate /*
691*7c478bd9Sstevel@tonic-gate  * A dcmd which prints the attribute hash table.
692*7c478bd9Sstevel@tonic-gate  */
693*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
694*7c478bd9Sstevel@tonic-gate int
695*7c478bd9Sstevel@tonic-gate pattbl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
696*7c478bd9Sstevel@tonic-gate {
697*7c478bd9Sstevel@tonic-gate 	mmd_data_t data;
698*7c478bd9Sstevel@tonic-gate 	uint_t pattbl_sz;
699*7c478bd9Sstevel@tonic-gate 	int i, j;
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	bzero(&data, sizeof (data));
702*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
703*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 	/* Figure out the size of hash table */
706*7c478bd9Sstevel@tonic-gate 	mdb_readvar(&pattbl_sz, "pattbl_sz");
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
709*7c478bd9Sstevel@tonic-gate 	mdb_printf("%<b>%<u>%-3s %-16s %-16s %-12s %-3s %-16s %-5s%</u>%</b>\n",
710*7c478bd9Sstevel@tonic-gate 	    "BKT", "PATBKT ADDR", "PATTR ADDR", "TYPE", "LEN", "BUF ADDR",
711*7c478bd9Sstevel@tonic-gate 	    "FLAGS");
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 	/* Walk each bucket and print its contents */
714*7c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < (pattbl_sz * sizeof (patbkt_t));
715*7c478bd9Sstevel@tonic-gate 	    i += sizeof (patbkt_t)) {
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 		mdb_printf("%-3d %016p ", j++, addr + i);
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 		if (mdb_pwalk("pattr", (mdb_walk_cb_t)pattr_print, &data,
720*7c478bd9Sstevel@tonic-gate 		    addr + i + offsetof(patbkt_t, pbkt_pattr_q)) == -1) {
721*7c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't walk pattr_t list");
722*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
723*7c478bd9Sstevel@tonic-gate 		}
724*7c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
725*7c478bd9Sstevel@tonic-gate 	}
726*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
729*7c478bd9Sstevel@tonic-gate }
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate typedef struct pattr_type_s {
732*7c478bd9Sstevel@tonic-gate 	char *name;	/* attribute name */
733*7c478bd9Sstevel@tonic-gate 	uint_t type;	/* attribute type value */
734*7c478bd9Sstevel@tonic-gate } pattr_type_t;
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate /*
737*7c478bd9Sstevel@tonic-gate  * Generic packet attribute (pattr_t) counting routine.
738*7c478bd9Sstevel@tonic-gate  */
739*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
740*7c478bd9Sstevel@tonic-gate static int
741*7c478bd9Sstevel@tonic-gate pattr_count(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
742*7c478bd9Sstevel@tonic-gate {
743*7c478bd9Sstevel@tonic-gate 	pattr_t pattr;
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&pattr, sizeof (pattr), addr) == -1) {
746*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read pattr_t at %p", addr);
747*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	if (pattr.pat_magic != PATTR_MAGIC)
751*7c478bd9Sstevel@tonic-gate 		mdb_printf("Incorrect pattr magic number at %p\n",
752*7c478bd9Sstevel@tonic-gate 		    VA_OFF(addr, offsetof(pattr_t, pat_magic)));
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	data->counter++;
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
757*7c478bd9Sstevel@tonic-gate }
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate /*
760*7c478bd9Sstevel@tonic-gate  * Print the contents of a packet attribute (pattr_t) structure.
761*7c478bd9Sstevel@tonic-gate  */
762*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
763*7c478bd9Sstevel@tonic-gate static int
764*7c478bd9Sstevel@tonic-gate pattr_print(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
765*7c478bd9Sstevel@tonic-gate {
766*7c478bd9Sstevel@tonic-gate 	pattr_t pattr;
767*7c478bd9Sstevel@tonic-gate 	int i;
768*7c478bd9Sstevel@tonic-gate 	char *pa_name = "UNKNOWN";
769*7c478bd9Sstevel@tonic-gate 	static const pattr_type_t pa_type[] = {
770*7c478bd9Sstevel@tonic-gate 		{ "DSTADDRSAP", PATTR_DSTADDRSAP },
771*7c478bd9Sstevel@tonic-gate 		{ "SRCADDRSAP", PATTR_SRCADDRSAP },
772*7c478bd9Sstevel@tonic-gate 		{ "HCKSUM", PATTR_HCKSUM }
773*7c478bd9Sstevel@tonic-gate 	};
774*7c478bd9Sstevel@tonic-gate 	static const mdb_bitmask_t pa_flags_bits[] = {
775*7c478bd9Sstevel@tonic-gate 		{ "R", PATTR_REM_DEFER, PATTR_REM_DEFER },
776*7c478bd9Sstevel@tonic-gate 		{ "P", PATTR_PERSIST, PATTR_PERSIST },
777*7c478bd9Sstevel@tonic-gate 		{ NULL, 0, 0 }
778*7c478bd9Sstevel@tonic-gate 	};
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&pattr, sizeof (pattr), addr) == -1) {
781*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read pattr_t at %p", addr);
782*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
783*7c478bd9Sstevel@tonic-gate 	}
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	if (pattr.pat_magic != PATTR_MAGIC)
786*7c478bd9Sstevel@tonic-gate 		mdb_printf("Incorrect pattr magic number at %p\n",
787*7c478bd9Sstevel@tonic-gate 		    VA_OFF(addr, offsetof(pattr_t, pat_magic)));
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	/* Find a matching string */
790*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (sizeof (pa_type) / sizeof (*pa_type)); i++) {
791*7c478bd9Sstevel@tonic-gate 		if (pa_type[i].type == pattr.pat_type)
792*7c478bd9Sstevel@tonic-gate 			pa_name = pa_type[i].name;
793*7c478bd9Sstevel@tonic-gate 	}
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 	if (!qwp->qw_iprint) {
796*7c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
797*7c478bd9Sstevel@tonic-gate 		mdb_inc_indent(21);
798*7c478bd9Sstevel@tonic-gate 	}
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	mdb_printf("%016p %x:%-10s %-3d %016p %-5b", addr, pattr.pat_type,
801*7c478bd9Sstevel@tonic-gate 	    pa_name, pattr.pat_buflen - sizeof (pattr), addr + sizeof (pattr),
802*7c478bd9Sstevel@tonic-gate 	    pattr.pat_flags, pa_flags_bits);
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	if (!qwp->qw_iprint)
805*7c478bd9Sstevel@tonic-gate 		mdb_dec_indent(21);
806*7c478bd9Sstevel@tonic-gate 	else
807*7c478bd9Sstevel@tonic-gate 		qwp->qw_iprint = FALSE;
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
810*7c478bd9Sstevel@tonic-gate }
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate /*
813*7c478bd9Sstevel@tonic-gate  * Packet attribute (pattr_t) walker initialization routine.
814*7c478bd9Sstevel@tonic-gate  */
815*7c478bd9Sstevel@tonic-gate int
816*7c478bd9Sstevel@tonic-gate pattr_walk_init(mdb_walk_state_t *wsp)
817*7c478bd9Sstevel@tonic-gate {
818*7c478bd9Sstevel@tonic-gate 	uintptr_t q_head;
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
821*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 	/*
824*7c478bd9Sstevel@tonic-gate 	 * If we're called from pattbl dcmd, then we're passed in
825*7c478bd9Sstevel@tonic-gate 	 * the address of ql_t head; otherwise we'd have to get the
826*7c478bd9Sstevel@tonic-gate 	 * address ourselves.
827*7c478bd9Sstevel@tonic-gate 	 */
828*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_cbdata == NULL) {
829*7c478bd9Sstevel@tonic-gate 		pattr_t pattr;
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&pattr, sizeof (pattr), wsp->walk_addr) == -1) {
832*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read pattr_t at %p",
833*7c478bd9Sstevel@tonic-gate 			    wsp->walk_addr);
834*7c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
835*7c478bd9Sstevel@tonic-gate 		}
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 		q_head = (uintptr_t)VA_OFF(pattr.pat_lock,
838*7c478bd9Sstevel@tonic-gate 		    -offsetof(patbkt_t, pbkt_lock)) +
839*7c478bd9Sstevel@tonic-gate 		    offsetof(patbkt_t, pbkt_pattr_q);
840*7c478bd9Sstevel@tonic-gate 	} else
841*7c478bd9Sstevel@tonic-gate 		q_head = wsp->walk_addr;
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	/* Pass it on to our generic ql_t walker init */
844*7c478bd9Sstevel@tonic-gate 	return (mmdq_walk_init(wsp, "pattr_t", q_head,
845*7c478bd9Sstevel@tonic-gate 	    sizeof (pattr_t), offsetof(pattr_t, pat_next)));
846*7c478bd9Sstevel@tonic-gate }
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate /*
849*7c478bd9Sstevel@tonic-gate  * A dcmd which returns a multidata_t pointer from a pattr_t.
850*7c478bd9Sstevel@tonic-gate  */
851*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
852*7c478bd9Sstevel@tonic-gate int
853*7c478bd9Sstevel@tonic-gate pattr2multidata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
854*7c478bd9Sstevel@tonic-gate {
855*7c478bd9Sstevel@tonic-gate 	pattr_t pattr;
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
858*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&pattr, sizeof (pattr), addr) == -1) {
861*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read pattr_t at %p", addr);
862*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
863*7c478bd9Sstevel@tonic-gate 	}
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 	if (pattr.pat_magic != PATTR_MAGIC) {
866*7c478bd9Sstevel@tonic-gate 		mdb_warn("Incorrect pattr magic number at %p",
867*7c478bd9Sstevel@tonic-gate 		    VA_OFF(addr, offsetof(pattr_t, pat_magic)));
868*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
869*7c478bd9Sstevel@tonic-gate 	}
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	mdb_printf("%p\n", pattr.pat_mmd);
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
874*7c478bd9Sstevel@tonic-gate }
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate /*
877*7c478bd9Sstevel@tonic-gate  * A dcmd which returns a pdesc_slab_t from a pdesc_t.
878*7c478bd9Sstevel@tonic-gate  */
879*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
880*7c478bd9Sstevel@tonic-gate int
881*7c478bd9Sstevel@tonic-gate pdesc2slab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
882*7c478bd9Sstevel@tonic-gate {
883*7c478bd9Sstevel@tonic-gate 	pdesc_t pd;
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
886*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
889*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read pdesc_t at %p", addr);
890*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
891*7c478bd9Sstevel@tonic-gate 	}
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 	if (pd.pd_magic != PDESC_MAGIC) {
894*7c478bd9Sstevel@tonic-gate 		mdb_warn("Incorrect pdesc magic number at %p",
895*7c478bd9Sstevel@tonic-gate 		    VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
896*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
897*7c478bd9Sstevel@tonic-gate 	}
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	mdb_printf("%p\n", pd.pd_slab);
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
902*7c478bd9Sstevel@tonic-gate }
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate /*
905*7c478bd9Sstevel@tonic-gate  * A dcmd which verifies the integrity of a pdesc_t.
906*7c478bd9Sstevel@tonic-gate  */
907*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
908*7c478bd9Sstevel@tonic-gate int
909*7c478bd9Sstevel@tonic-gate pdesc_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
910*7c478bd9Sstevel@tonic-gate {
911*7c478bd9Sstevel@tonic-gate 	multidata_t mmd;
912*7c478bd9Sstevel@tonic-gate 	pdesc_t pd;
913*7c478bd9Sstevel@tonic-gate 	pdescinfo_t *pdi = &pd.pd_pdi;
914*7c478bd9Sstevel@tonic-gate 	pdesc_slab_t slab;
915*7c478bd9Sstevel@tonic-gate 	mblk_t hbuf, pbuf[MULTIDATA_MAX_PBUFS];
916*7c478bd9Sstevel@tonic-gate 	uint_t i, idx;
917*7c478bd9Sstevel@tonic-gate 	boolean_t valid = B_TRUE;
918*7c478bd9Sstevel@tonic-gate 	struct pld_ary_s *pa;
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
921*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
924*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read pdesc_t at %p", addr);
925*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
926*7c478bd9Sstevel@tonic-gate 	}
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	if (pd.pd_magic != PDESC_MAGIC) {
929*7c478bd9Sstevel@tonic-gate 		mdb_warn("Incorrect pdesc magic number at %p\n",
930*7c478bd9Sstevel@tonic-gate 		    VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
931*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
932*7c478bd9Sstevel@tonic-gate 	}
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&slab, sizeof (slab), (uintptr_t)pd.pd_slab) == -1) {
935*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read pdesc_slab_t at %p", pd.pd_slab);
936*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
937*7c478bd9Sstevel@tonic-gate 	}
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&mmd, sizeof (mmd), (uintptr_t)slab.pds_mmd) == -1) {
940*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read multidata_t at %p", slab.pds_mmd);
941*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
942*7c478bd9Sstevel@tonic-gate 	}
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	if (mmd.mmd_magic != MULTIDATA_MAGIC)
945*7c478bd9Sstevel@tonic-gate 		mdb_printf("Incorrect Multidata magic number at %p\n",
946*7c478bd9Sstevel@tonic-gate 		    VA_OFF(slab.pds_mmd, offsetof(multidata_t, mmd_magic)));
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	if (mmd.mmd_hbuf != 0 &&
949*7c478bd9Sstevel@tonic-gate 	    mdb_vread(&hbuf, sizeof (hbuf), (uintptr_t)mmd.mmd_hbuf) == -1) {
950*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read mblk_t at %p", mmd.mmd_hbuf);
951*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
952*7c478bd9Sstevel@tonic-gate 	}
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 	if (mmd.mmd_pbuf_cnt > MULTIDATA_MAX_PBUFS) {
955*7c478bd9Sstevel@tonic-gate 		mdb_warn("Multidata pbuf count exceeds %d\n",
956*7c478bd9Sstevel@tonic-gate 		    MULTIDATA_MAX_PBUFS);
957*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
958*7c478bd9Sstevel@tonic-gate 	} else if (pdi->pld_cnt > mmd.mmd_pbuf_cnt) {
959*7c478bd9Sstevel@tonic-gate 		mdb_warn("descriptor pbuf count exceeds Multidata "
960*7c478bd9Sstevel@tonic-gate 		    "pbuf count %d\n", mmd.mmd_pbuf_cnt);
961*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	if (mmd.mmd_pbuf_cnt > 0) {
965*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < mmd.mmd_pbuf_cnt; i++) {
966*7c478bd9Sstevel@tonic-gate 			if (mdb_vread(&pbuf[i], sizeof (mblk_t),
967*7c478bd9Sstevel@tonic-gate 			    (uintptr_t)mmd.mmd_pbuf[i]) == -1) {
968*7c478bd9Sstevel@tonic-gate 				mdb_warn("couldn't read mblk_t at %p",
969*7c478bd9Sstevel@tonic-gate 				    mmd.mmd_pbuf[i]);
970*7c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
971*7c478bd9Sstevel@tonic-gate 			}
972*7c478bd9Sstevel@tonic-gate 		}
973*7c478bd9Sstevel@tonic-gate 	}
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 	/* It should have at least one buffer reference */
976*7c478bd9Sstevel@tonic-gate 	if (!(pdi->flags & PDESC_HAS_REF)) {
977*7c478bd9Sstevel@tonic-gate 		mdb_warn("descriptor has no buffer reference indicator "
978*7c478bd9Sstevel@tonic-gate 		    "in flags (0x%x)\n", pdi->flags);
979*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
980*7c478bd9Sstevel@tonic-gate 	} else if (!(pdi->flags & PDESC_PBUF_REF) && pdi->pld_cnt > 0) {
981*7c478bd9Sstevel@tonic-gate 		mdb_warn("descriptor has no pbuf reference indicator in "
982*7c478bd9Sstevel@tonic-gate 		    "flags (0x%x); but pld_cnt is %d\n", pdi->flags,
983*7c478bd9Sstevel@tonic-gate 		    pdi->pld_cnt);
984*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	/* Bounds check the header fragment, if any */
988*7c478bd9Sstevel@tonic-gate 	if (!((pdi->flags & PDESC_HBUF_REF) && pdi->hdr_rptr != 0 &&
989*7c478bd9Sstevel@tonic-gate 	    pdi->hdr_wptr != 0 && pdi->hdr_base != 0 &&
990*7c478bd9Sstevel@tonic-gate 	    pdi->hdr_lim != 0 && pdi->hdr_lim >= pdi->hdr_base &&
991*7c478bd9Sstevel@tonic-gate 	    pdi->hdr_wptr >= pdi->hdr_rptr && pdi->hdr_base <= pdi->hdr_rptr &&
992*7c478bd9Sstevel@tonic-gate 	    pdi->hdr_lim >= pdi->hdr_wptr && pdi->hdr_base >= hbuf.b_rptr &&
993*7c478bd9Sstevel@tonic-gate 	    MBLKIN(&hbuf, (pdi->hdr_base - hbuf.b_rptr),
994*7c478bd9Sstevel@tonic-gate 	    PDESC_HDRSIZE(pdi)))) {
995*7c478bd9Sstevel@tonic-gate 		mdb_warn("descriptor has invalid header fragment\n");
996*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
997*7c478bd9Sstevel@tonic-gate 	}
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	i = 0;
1000*7c478bd9Sstevel@tonic-gate 	pa = &pdi->pld_ary[0];
1001*7c478bd9Sstevel@tonic-gate 	/* Bounds check the payload fragment, if any */
1002*7c478bd9Sstevel@tonic-gate 	while (valid && i < pdi->pld_cnt) {
1003*7c478bd9Sstevel@tonic-gate 		valid = (((idx = pa->pld_pbuf_idx) < mmd.mmd_pbuf_cnt) &&
1004*7c478bd9Sstevel@tonic-gate 		    pa->pld_rptr != NULL && pa->pld_wptr != NULL &&
1005*7c478bd9Sstevel@tonic-gate 		    pa->pld_wptr >= pa->pld_rptr &&
1006*7c478bd9Sstevel@tonic-gate 		    pa->pld_rptr >= pbuf[idx].b_rptr &&
1007*7c478bd9Sstevel@tonic-gate 		    MBLKIN(&pbuf[idx], (pa->pld_rptr - pbuf[idx].b_rptr),
1008*7c478bd9Sstevel@tonic-gate 			PDESC_PLD_SPAN_SIZE(pdi, i)));
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 		if (!valid) {
1011*7c478bd9Sstevel@tonic-gate 			mdb_warn("descriptor has invalid payload fragment\n");
1012*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
1013*7c478bd9Sstevel@tonic-gate 		}
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 		/* advance to next entry */
1016*7c478bd9Sstevel@tonic-gate 		i++;
1017*7c478bd9Sstevel@tonic-gate 		pa++;
1018*7c478bd9Sstevel@tonic-gate 	}
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1021*7c478bd9Sstevel@tonic-gate }
1022