1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include "mdinclude.h"
27
28/*
29 * Display an arbitrary bitmap by showing the set bits in the array.
30 * Output will be <start>-<end> for ranges or <position> for singleton bits.
31 */
32static void
33print_mm_bm(unsigned char *bm, uint_t size, char *bm_name)
34{
35	int	i;
36	int	first_set = -1;
37	int	need_comma = 0;
38
39	mdb_printf("%s set bits: ", bm_name);
40	for (i = 0; i < size; i++) {
41		if (isset(bm, i)) {
42			if (first_set == -1) {
43				first_set = i;
44			}
45		} else {
46			if (first_set != -1) {
47				if (first_set != (i-1)) {
48					mdb_printf("%s%u-%u",
49					    (need_comma ? "," : ""),
50					    first_set, (i-1));
51				} else {
52					mdb_printf("%s%u",
53					    (need_comma ? "," : ""), first_set);
54				}
55				need_comma = 1;
56				first_set = -1;
57			}
58		}
59	}
60	if (first_set != -1) {
61		mdb_printf("%s%u-%u", (need_comma ? "," : ""), first_set,
62		    size-1);
63	}
64	mdb_printf("\n");
65}
66
67/*
68 * Print uchar_t sized count fields (typically un_pernode_dirty_map entries)
69 */
70
71static void
72print_mm_cnt_c(unsigned char *bm, uint_t size, char *bm_name)
73{
74	int	i;
75	int	need_comma = 0;
76
77	mdb_printf("%s set counts: ", bm_name);
78	for (i = 0; i < size; i++) {
79		if (bm[i]) {
80			mdb_printf("%s(%d,%3d)", (need_comma ? "," : ""), i,
81			    (uint_t)bm[i]);
82			need_comma = 1;
83		}
84	}
85	mdb_printf("\n");
86}
87
88static void
89print_mm_cnt_w(unsigned short *bm, uint_t size, char *bm_name)
90{
91	int	i;
92	int	need_comma = 0;
93
94	mdb_printf("%s set counts: ", bm_name);
95	for (i = 0; i < size; i++) {
96		if (bm[i]) {
97			mdb_printf("%s(%d,%5d)", (need_comma ? "," : ""), i,
98			    (uint_t)bm[i]);
99			need_comma = 1;
100		}
101	}
102	mdb_printf("\n");
103}
104
105/*
106 * Print the associated bitmaps for the specified mm_unit_t
107 * These are:
108 *	un_pernode_dirty_bm
109 *	un_goingclean_bm
110 *	un_dirty_bm
111 *	un_goingdirty_bm
112 *	un_resync_bm
113 *
114 * Associated counts for unit:
115 *	un_pernode_dirty_sum[] 	(uchar_t)
116 *	un_outstanding_writes[]	(ushort_t)
117 *
118 */
119
120/* ARGSUSED */
121int
122printmmbm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
123{
124	mm_unit_t	mm, *mmp;
125	unsigned char	*rr_dirty_bm, *rr_goingclean_bm, *rr_goingdirty_bm;
126	unsigned char	*rr_resync_bm;
127	uintptr_t	un_dbm, un_gcbm, un_gdbm, un_rrbm, un_pnds, un_ow;
128	uint_t		num_rr, rr_bitmap_size;
129	int		i;
130	uintptr_t	un_pernode_bm;
131	unsigned char	*rr_pernode_dirty, *rr_pnds;
132	unsigned short	*rr_ow;
133	/* just enough for un_pernode_dirty_bm[] plus three digits */
134	char		pernode_str[25];
135
136	if (argc != 0)
137		return (DCMD_USAGE);
138
139	if (!(flags & DCMD_ADDRSPEC)) {
140		mdb_warn("No mm_unit_t address specified");
141		return (DCMD_ERR);
142	}
143
144	if (mdb_vread(&mm, sizeof (mm_unit_t), addr) == -1) {
145		mdb_warn("failed to read mm_unit_t at %p\n", addr);
146		return (DCMD_ERR);
147	}
148
149	mmp = &mm;
150
151	num_rr = mm.un_rrd_num;
152
153	un_dbm = (uintptr_t)mmp->un_dirty_bm;
154	un_gcbm = (uintptr_t)mmp->un_goingclean_bm;
155	un_gdbm = (uintptr_t)mmp->un_goingdirty_bm;
156	un_rrbm = (uintptr_t)mmp->un_resync_bm;
157	un_pnds = (uintptr_t)mmp->un_pernode_dirty_sum;
158	un_ow = (uintptr_t)mmp->un_outstanding_writes;
159
160	rr_bitmap_size = howmany(num_rr, NBBY);
161	rr_dirty_bm = (unsigned char *)mdb_alloc(rr_bitmap_size,
162	    UM_SLEEP|UM_GC);
163	rr_goingclean_bm = (unsigned char *)mdb_alloc(rr_bitmap_size,
164	    UM_SLEEP|UM_GC);
165	rr_goingdirty_bm = (unsigned char *)mdb_alloc(rr_bitmap_size,
166	    UM_SLEEP|UM_GC);
167	rr_resync_bm = (unsigned char *)mdb_alloc(rr_bitmap_size,
168	    UM_SLEEP|UM_GC);
169	rr_pnds = (unsigned char *)mdb_alloc(num_rr, UM_SLEEP|UM_GC);
170	rr_ow = (unsigned short *)mdb_alloc(num_rr * sizeof (unsigned short),
171	    UM_SLEEP|UM_GC);
172
173	if (mdb_vread(rr_dirty_bm, rr_bitmap_size, un_dbm) == -1) {
174		mdb_warn("failed to read un_dirty_bm at %p\n", un_dbm);
175		return (DCMD_ERR);
176	}
177	if (mdb_vread(rr_goingclean_bm, rr_bitmap_size, un_gcbm) == -1) {
178		mdb_warn("failed to read un_goingclean_bm at %p\n", un_gcbm);
179		return (DCMD_ERR);
180	}
181	if (mdb_vread(rr_goingdirty_bm, rr_bitmap_size, un_gdbm) == -1) {
182		mdb_warn("failed to read un_goingdirty_bm at %p\n", un_gdbm);
183		return (DCMD_ERR);
184	}
185	if (mdb_vread(rr_resync_bm, rr_bitmap_size, un_rrbm) == -1) {
186		mdb_warn("failed to read un_resync_bm at %p\n", un_rrbm);
187		return (DCMD_ERR);
188	}
189	if (mdb_vread(rr_pnds, num_rr, un_pnds) == -1) {
190		mdb_warn("failed to read un_pernode_dirty_sum at %p\n",
191		    un_pnds);
192		return (DCMD_ERR);
193	}
194	if (mdb_vread(rr_ow, num_rr * sizeof (unsigned short), un_ow) == -1) {
195		mdb_warn("failed to read un_outstanding_writes at %p\n", un_ow);
196		return (DCMD_ERR);
197	}
198
199	print_mm_bm(rr_dirty_bm, num_rr, "un_dirty_bm");
200	print_mm_bm(rr_goingclean_bm, num_rr, "un_goingclean_bm");
201	print_mm_bm(rr_goingdirty_bm, num_rr, "un_goingdirty_bm");
202	print_mm_bm(rr_resync_bm, num_rr, "un_resync_bm");
203
204	/*
205	 * Load all the un_pernode_bm[] entries and iterate through the non-
206	 * NULL entries
207	 */
208	rr_pernode_dirty = (unsigned char *)mdb_alloc(rr_bitmap_size,
209	    UM_SLEEP|UM_GC);
210
211	for (i = 0; i < 128; i++) {
212		un_pernode_bm = (uintptr_t)mmp->un_pernode_dirty_bm[i];
213		if (un_pernode_bm) {
214			mdb_snprintf(pernode_str, sizeof (pernode_str),
215			    "un_pernode_dirty_bm[%d]", i);
216			if (mdb_vread(rr_pernode_dirty, rr_bitmap_size,
217			    un_pernode_bm) == -1) {
218				mdb_warn("failed to read %s at %p\n",
219				    pernode_str, un_pernode_bm);
220				return (DCMD_ERR);
221			}
222			print_mm_bm(rr_pernode_dirty, num_rr, pernode_str);
223		}
224	}
225	print_mm_cnt_c(rr_pnds, num_rr, "un_pernode_dirty_sum");
226
227	print_mm_cnt_w(rr_ow, num_rr, "un_outstanding_writes");
228
229	return (DCMD_OK);
230}
231