xref: /onnv-gate/usr/src/cmd/mdb/common/modules/md/metastat.c (revision 8452:89d32dfdae6e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*8452SJohn.Wren.Kennedy@Sun.COM  * Common Development and Distribution License (the "License").
6*8452SJohn.Wren.Kennedy@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*8452SJohn.Wren.Kennedy@Sun.COM 
220Sstevel@tonic-gate /*
23*8452SJohn.Wren.Kennedy@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include "mdinclude.h"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate typedef struct	submirror_cb {
300Sstevel@tonic-gate 	minor_t		un_self_id;
310Sstevel@tonic-gate 	int		un_nsm;
320Sstevel@tonic-gate 	ushort_t	mm_un_nsm;
330Sstevel@tonic-gate }submirror_cb_t;
340Sstevel@tonic-gate 
350Sstevel@tonic-gate void
print_setname(int setno)360Sstevel@tonic-gate print_setname(int setno)
370Sstevel@tonic-gate {
380Sstevel@tonic-gate 	char		setname[1024];
390Sstevel@tonic-gate 
400Sstevel@tonic-gate 	if (setno != 0) {
410Sstevel@tonic-gate 		if (mdb_readstr(setname, 1024,
420Sstevel@tonic-gate 		    (uintptr_t)set_dbs[setno].s_setname) == -1) {
430Sstevel@tonic-gate 			mdb_warn("failed to read setname at 0x%p\n",
440Sstevel@tonic-gate 			    set_dbs[setno].s_setname);
450Sstevel@tonic-gate 		}
460Sstevel@tonic-gate 		mdb_printf("%s/", setname);
470Sstevel@tonic-gate 	}
480Sstevel@tonic-gate }
490Sstevel@tonic-gate 
500Sstevel@tonic-gate void
print_stripe(void * un_addr,void * mdcptr,uint_t verbose)510Sstevel@tonic-gate print_stripe(void *un_addr, void *mdcptr, uint_t verbose)
520Sstevel@tonic-gate {
530Sstevel@tonic-gate 	ms_unit_t	ms;
540Sstevel@tonic-gate 	int		setno;
550Sstevel@tonic-gate 	minor_t		un_self_id;
560Sstevel@tonic-gate 	md_parent_t	un_parent;
570Sstevel@tonic-gate 	diskaddr_t	un_total_blocks;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	/* read in the device */
600Sstevel@tonic-gate 	un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id;
610Sstevel@tonic-gate 	un_parent = ((mdc_unit_t *)mdcptr)->un_parent;
620Sstevel@tonic-gate 	un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks;
630Sstevel@tonic-gate 	if (mdb_vread(&ms, sizeof (ms_unit_t),
640Sstevel@tonic-gate 	    (uintptr_t)un_addr) == -1) {
650Sstevel@tonic-gate 		mdb_warn("failed to read ms_unit_t at %p\n", un_addr);
660Sstevel@tonic-gate 		return;
670Sstevel@tonic-gate 	}
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	setno = MD_MIN2SET(un_self_id);
700Sstevel@tonic-gate 	print_setname(setno);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	mdb_printf("d%u: ", MD_MIN2UNIT(un_self_id));
730Sstevel@tonic-gate 	if (un_parent == ((unit_t)-1)) {
740Sstevel@tonic-gate 		mdb_printf("Concat/Stripe");
750Sstevel@tonic-gate 	} else {
760Sstevel@tonic-gate 		mdb_printf("Subdevice of d%u", MD_MIN2UNIT(un_parent));
770Sstevel@tonic-gate 	}
780Sstevel@tonic-gate 	if (verbose) {
790Sstevel@tonic-gate 		mdb_printf("\t< %p::print ms_unit_t >\n", un_addr);
800Sstevel@tonic-gate 	} else {
810Sstevel@tonic-gate 		mdb_printf("\t< %p>\n", un_addr);
820Sstevel@tonic-gate 	}
830Sstevel@tonic-gate 	mdb_inc_indent(2);
840Sstevel@tonic-gate 	mdb_printf("Size: %llu blocks\n", un_total_blocks);
850Sstevel@tonic-gate 	mdb_printf("Rows: %u\n", ms.un_nrows);
860Sstevel@tonic-gate 	mdb_dec_indent(2);
870Sstevel@tonic-gate }
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /* ARGSUSED */
900Sstevel@tonic-gate int
print_submirror(uintptr_t addr,void * arg,submirror_cb_t * data)910Sstevel@tonic-gate print_submirror(uintptr_t addr, void *arg, submirror_cb_t *data)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate 	uintptr_t	un_addr;
940Sstevel@tonic-gate 	mdc_unit_t	mdc_sm;
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	if (mdb_vread(&un_addr, sizeof (void *), addr) == -1) {
970Sstevel@tonic-gate 		mdb_warn("failed to read submirror at %p\n", addr);
980Sstevel@tonic-gate 		return (WALK_ERR);
990Sstevel@tonic-gate 	}
1000Sstevel@tonic-gate 	if (un_addr != NULL) {
1010Sstevel@tonic-gate 		if (mdb_vread(&mdc_sm, sizeof (mdc_unit_t), un_addr) == -1) {
1020Sstevel@tonic-gate 			mdb_warn("failed to read mdc_unit_t at %p", un_addr);
1030Sstevel@tonic-gate 			return (WALK_ERR);
1040Sstevel@tonic-gate 		}
1050Sstevel@tonic-gate 		if (mdc_sm.un_parent == data->un_self_id) {
1060Sstevel@tonic-gate 		/* this is one of the sub mirrors */
1070Sstevel@tonic-gate 			mdb_printf("Submirror %u: d%u ",
1080Sstevel@tonic-gate 			    data->un_nsm, MD_MIN2UNIT(mdc_sm.un_self_id));
1090Sstevel@tonic-gate 			mdb_printf("Size: %llu\n", mdc_sm.un_total_blocks);
1100Sstevel@tonic-gate 			data->un_nsm++;
1110Sstevel@tonic-gate 			if (data->un_nsm == data->mm_un_nsm)
1120Sstevel@tonic-gate 				return (WALK_DONE);
1130Sstevel@tonic-gate 		}
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 	return (WALK_NEXT);
1160Sstevel@tonic-gate }
1170Sstevel@tonic-gate 
118*8452SJohn.Wren.Kennedy@Sun.COM /*
119*8452SJohn.Wren.Kennedy@Sun.COM  * Construct an RLE count for the number of 'cleared' bits in the given 'bm'
120*8452SJohn.Wren.Kennedy@Sun.COM  * Output the RLE count in form: [<set>.<cleared>.<set>.<cleared>...]
121*8452SJohn.Wren.Kennedy@Sun.COM  * RLE is Run Length Encoding, a method for compactly describing a bitmap
122*8452SJohn.Wren.Kennedy@Sun.COM  * as a series of numbers indicating the count of consecutive set or cleared
123*8452SJohn.Wren.Kennedy@Sun.COM  * bits.
124*8452SJohn.Wren.Kennedy@Sun.COM  *
125*8452SJohn.Wren.Kennedy@Sun.COM  * Input:
126*8452SJohn.Wren.Kennedy@Sun.COM  *	<bm>	bitmap to scan
127*8452SJohn.Wren.Kennedy@Sun.COM  *	<size>	length of bitmap (in bits)
128*8452SJohn.Wren.Kennedy@Sun.COM  *	<comp_bm>	RLE count array to be updated
129*8452SJohn.Wren.Kennedy@Sun.COM  *	<opstr>	Descriptive text for bitmap RLE count display
130*8452SJohn.Wren.Kennedy@Sun.COM  */
131*8452SJohn.Wren.Kennedy@Sun.COM static void
print_comp_bm(unsigned char * bm,uint_t size,ushort_t * comp_bm,char * opstr)132*8452SJohn.Wren.Kennedy@Sun.COM print_comp_bm(unsigned char *bm, uint_t size, ushort_t *comp_bm, char *opstr)
133*8452SJohn.Wren.Kennedy@Sun.COM {
134*8452SJohn.Wren.Kennedy@Sun.COM 	int	cnt_clean, tot_dirty, cur_idx;
135*8452SJohn.Wren.Kennedy@Sun.COM 	int	i, cur_clean, cur_dirty, printit, max_set_cnt, max_reset_cnt;
136*8452SJohn.Wren.Kennedy@Sun.COM 
137*8452SJohn.Wren.Kennedy@Sun.COM 	cnt_clean = 1;
138*8452SJohn.Wren.Kennedy@Sun.COM 	printit = 0;
139*8452SJohn.Wren.Kennedy@Sun.COM 	cur_clean = 0;
140*8452SJohn.Wren.Kennedy@Sun.COM 	cur_dirty = 0;
141*8452SJohn.Wren.Kennedy@Sun.COM 	cur_idx = 0;
142*8452SJohn.Wren.Kennedy@Sun.COM 	tot_dirty = 0;
143*8452SJohn.Wren.Kennedy@Sun.COM 	max_set_cnt = max_reset_cnt = 0;
144*8452SJohn.Wren.Kennedy@Sun.COM 	for (i = 0; i < size; i++) {
145*8452SJohn.Wren.Kennedy@Sun.COM 		if (isset(bm, i)) {
146*8452SJohn.Wren.Kennedy@Sun.COM 			/* If we're counting clean bits, flush the count out */
147*8452SJohn.Wren.Kennedy@Sun.COM 			if (cnt_clean) {
148*8452SJohn.Wren.Kennedy@Sun.COM 				cnt_clean = 0;
149*8452SJohn.Wren.Kennedy@Sun.COM 				comp_bm[cur_idx] = cur_clean;
150*8452SJohn.Wren.Kennedy@Sun.COM 				printit = 1;
151*8452SJohn.Wren.Kennedy@Sun.COM 				if (cur_clean > max_reset_cnt) {
152*8452SJohn.Wren.Kennedy@Sun.COM 					max_reset_cnt = cur_clean;
153*8452SJohn.Wren.Kennedy@Sun.COM 				}
154*8452SJohn.Wren.Kennedy@Sun.COM 			}
155*8452SJohn.Wren.Kennedy@Sun.COM 			cur_clean = 0;
156*8452SJohn.Wren.Kennedy@Sun.COM 			cur_dirty++;
157*8452SJohn.Wren.Kennedy@Sun.COM 			tot_dirty++;
158*8452SJohn.Wren.Kennedy@Sun.COM 		} else {
159*8452SJohn.Wren.Kennedy@Sun.COM 			if (!cnt_clean) {
160*8452SJohn.Wren.Kennedy@Sun.COM 				cnt_clean = 1;
161*8452SJohn.Wren.Kennedy@Sun.COM 				comp_bm[cur_idx] = cur_dirty;
162*8452SJohn.Wren.Kennedy@Sun.COM 				printit = 1;
163*8452SJohn.Wren.Kennedy@Sun.COM 				if (cur_dirty > max_set_cnt) {
164*8452SJohn.Wren.Kennedy@Sun.COM 					max_set_cnt = cur_dirty;
165*8452SJohn.Wren.Kennedy@Sun.COM 				}
166*8452SJohn.Wren.Kennedy@Sun.COM 			}
167*8452SJohn.Wren.Kennedy@Sun.COM 			cur_dirty = 0;
168*8452SJohn.Wren.Kennedy@Sun.COM 			cur_clean++;
169*8452SJohn.Wren.Kennedy@Sun.COM 		}
170*8452SJohn.Wren.Kennedy@Sun.COM 		if (printit) {
171*8452SJohn.Wren.Kennedy@Sun.COM 			mdb_printf("%u.", comp_bm[cur_idx++]);
172*8452SJohn.Wren.Kennedy@Sun.COM 			printit = 0;
173*8452SJohn.Wren.Kennedy@Sun.COM 		}
174*8452SJohn.Wren.Kennedy@Sun.COM 	}
175*8452SJohn.Wren.Kennedy@Sun.COM 
176*8452SJohn.Wren.Kennedy@Sun.COM 	mdb_printf("\nTotal %s bits = %lu\n", opstr, tot_dirty);
177*8452SJohn.Wren.Kennedy@Sun.COM 	mdb_printf("Total %s transactions = %lu\n", opstr, cur_idx);
178*8452SJohn.Wren.Kennedy@Sun.COM 	mdb_printf("Maximum %s set count = %lu, reset count = %lu\n", opstr,
179*8452SJohn.Wren.Kennedy@Sun.COM 	    max_set_cnt, max_reset_cnt);
180*8452SJohn.Wren.Kennedy@Sun.COM }
181*8452SJohn.Wren.Kennedy@Sun.COM 
1820Sstevel@tonic-gate void
print_mirror(void * un_addr,void * mdcptr,uint_t verbose)1830Sstevel@tonic-gate print_mirror(void *un_addr, void *mdcptr, uint_t verbose)
1840Sstevel@tonic-gate {
185*8452SJohn.Wren.Kennedy@Sun.COM 	mm_unit_t	mm, *mmp;
1860Sstevel@tonic-gate 	void		**ptr;
1870Sstevel@tonic-gate 	int		setno = 0;
1880Sstevel@tonic-gate 	minor_t		un_self_id;
1890Sstevel@tonic-gate 	diskaddr_t	un_total_blocks;
1900Sstevel@tonic-gate 	ushort_t	mm_un_nsm;
1910Sstevel@tonic-gate 	submirror_cb_t	data;
192*8452SJohn.Wren.Kennedy@Sun.COM 	uint_t		num_rr, rr_blksize;
193*8452SJohn.Wren.Kennedy@Sun.COM 	ushort_t	*comp_rr;
194*8452SJohn.Wren.Kennedy@Sun.COM 	unsigned char	*rr_dirty_bm, *rr_goingclean_bm;
195*8452SJohn.Wren.Kennedy@Sun.COM 	uintptr_t	un_dbm, un_gcbm;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	/* read in the device */
1980Sstevel@tonic-gate 	if (mdb_vread(&mm, sizeof (mm_unit_t),
1990Sstevel@tonic-gate 	    (uintptr_t)un_addr) == -1) {
2000Sstevel@tonic-gate 		mdb_warn("failed to read mm_unit_t at %p\n", un_addr);
2010Sstevel@tonic-gate 		return;
2020Sstevel@tonic-gate 	}
203*8452SJohn.Wren.Kennedy@Sun.COM 
204*8452SJohn.Wren.Kennedy@Sun.COM 	mmp = &mm;
205*8452SJohn.Wren.Kennedy@Sun.COM 
2060Sstevel@tonic-gate 	un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id;
2070Sstevel@tonic-gate 	un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks;
2080Sstevel@tonic-gate 	mm_un_nsm = mm.un_nsm;
2090Sstevel@tonic-gate 	setno = MD_MIN2SET(un_self_id);
2100Sstevel@tonic-gate 	print_setname(setno);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	mdb_printf("d%u: Mirror", MD_MIN2UNIT(un_self_id));
2130Sstevel@tonic-gate 	if (verbose) {
2140Sstevel@tonic-gate 		mdb_printf("\t< %p::print mm_unit_t >\n", un_addr);
2150Sstevel@tonic-gate 	} else {
2160Sstevel@tonic-gate 		mdb_printf("\t< %p >\n", un_addr);
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 	mdb_inc_indent(2);
2190Sstevel@tonic-gate 	mdb_printf("Size: %llu blocks\n", un_total_blocks);
220*8452SJohn.Wren.Kennedy@Sun.COM 
221*8452SJohn.Wren.Kennedy@Sun.COM 	/*
222*8452SJohn.Wren.Kennedy@Sun.COM 	 * Dump out the current un_dirty_bm together with its size
223*8452SJohn.Wren.Kennedy@Sun.COM 	 * Also, attempt to Run Length encode the bitmap to see if this
224*8452SJohn.Wren.Kennedy@Sun.COM 	 * is a viable option
225*8452SJohn.Wren.Kennedy@Sun.COM 	 */
226*8452SJohn.Wren.Kennedy@Sun.COM 	num_rr = mm.un_rrd_num;
227*8452SJohn.Wren.Kennedy@Sun.COM 	rr_blksize = mm.un_rrd_blksize;
228*8452SJohn.Wren.Kennedy@Sun.COM 
229*8452SJohn.Wren.Kennedy@Sun.COM 	un_dbm = (uintptr_t)mmp->un_dirty_bm;
230*8452SJohn.Wren.Kennedy@Sun.COM 	un_gcbm = (uintptr_t)mmp->un_goingclean_bm;
231*8452SJohn.Wren.Kennedy@Sun.COM 
232*8452SJohn.Wren.Kennedy@Sun.COM 	mdb_printf("RR size: %lu bits\n", num_rr);
233*8452SJohn.Wren.Kennedy@Sun.COM 	mdb_printf("RR block size: %lu blocks\n", rr_blksize);
234*8452SJohn.Wren.Kennedy@Sun.COM 
235*8452SJohn.Wren.Kennedy@Sun.COM 	rr_dirty_bm = (unsigned char *)mdb_alloc(num_rr, UM_SLEEP|UM_GC);
236*8452SJohn.Wren.Kennedy@Sun.COM 	rr_goingclean_bm = (unsigned char *)mdb_alloc(num_rr, UM_SLEEP|UM_GC);
237*8452SJohn.Wren.Kennedy@Sun.COM 	comp_rr = (ushort_t *)mdb_alloc(num_rr * sizeof (ushort_t),
238*8452SJohn.Wren.Kennedy@Sun.COM 	    UM_SLEEP|UM_GC);
239*8452SJohn.Wren.Kennedy@Sun.COM 
240*8452SJohn.Wren.Kennedy@Sun.COM 	if (mdb_vread(rr_dirty_bm, num_rr, un_dbm) == -1) {
241*8452SJohn.Wren.Kennedy@Sun.COM 		mdb_warn("failed to read un_dirty_bm at %p\n", un_dbm);
242*8452SJohn.Wren.Kennedy@Sun.COM 		return;
243*8452SJohn.Wren.Kennedy@Sun.COM 	}
244*8452SJohn.Wren.Kennedy@Sun.COM 	if (mdb_vread(rr_goingclean_bm, num_rr, un_gcbm) == -1) {
245*8452SJohn.Wren.Kennedy@Sun.COM 		mdb_warn("failed to read un_goingclean_bm at %p\n", un_gcbm);
246*8452SJohn.Wren.Kennedy@Sun.COM 		return;
247*8452SJohn.Wren.Kennedy@Sun.COM 	}
248*8452SJohn.Wren.Kennedy@Sun.COM 
249*8452SJohn.Wren.Kennedy@Sun.COM 	print_comp_bm(rr_dirty_bm, num_rr, comp_rr, "dirty");
250*8452SJohn.Wren.Kennedy@Sun.COM 
251*8452SJohn.Wren.Kennedy@Sun.COM 	print_comp_bm(rr_goingclean_bm, num_rr, comp_rr, "clean");
252*8452SJohn.Wren.Kennedy@Sun.COM 
2530Sstevel@tonic-gate 	/*
2540Sstevel@tonic-gate 	 * find the sub mirrors, search through each metadevice looking
2550Sstevel@tonic-gate 	 * at the un_parent.
2560Sstevel@tonic-gate 	 */
2570Sstevel@tonic-gate 	ptr = mdset[setno].s_un;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	data.un_self_id = un_self_id;
2600Sstevel@tonic-gate 	data.un_nsm = 0;
2610Sstevel@tonic-gate 	data.mm_un_nsm = mm_un_nsm;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	if (mdb_pwalk("md_units", (mdb_walk_cb_t)print_submirror, &data,
2640Sstevel@tonic-gate 	    (uintptr_t)ptr) == -1) {
2650Sstevel@tonic-gate 		mdb_warn("unable to walk units\n");
2660Sstevel@tonic-gate 		return;
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	mdb_dec_indent(2);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate void
print_raid(void * un_addr,void * mdcptr,uint_t verbose)2730Sstevel@tonic-gate print_raid(void *un_addr, void *mdcptr, uint_t verbose)
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate 	mr_unit_t	mr;
2760Sstevel@tonic-gate 	minor_t		un_self_id;
2770Sstevel@tonic-gate 	diskaddr_t	un_total_blocks;
2780Sstevel@tonic-gate 	mdc_unit_t	mdc_sc;
2790Sstevel@tonic-gate 	void		**ptr;
2800Sstevel@tonic-gate 	void		*addr;
2810Sstevel@tonic-gate 	int		setno = 0;
2820Sstevel@tonic-gate 	int		i;
2830Sstevel@tonic-gate 	minor_t		sc_un_self_id;
2840Sstevel@tonic-gate 	md_parent_t	sc_parent;
2850Sstevel@tonic-gate 	diskaddr_t	sc_total_blocks;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/* read in the device */
2880Sstevel@tonic-gate 	if (mdb_vread(&mr, sizeof (mr_unit_t), (uintptr_t)un_addr) == -1) {
2890Sstevel@tonic-gate 		mdb_warn("failed to read mr_unit_t at %p\n", un_addr);
2900Sstevel@tonic-gate 		return;
2910Sstevel@tonic-gate 	}
2920Sstevel@tonic-gate 	un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id;
2930Sstevel@tonic-gate 	un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks;
2940Sstevel@tonic-gate 	setno = MD_MIN2SET(un_self_id);
2950Sstevel@tonic-gate 	print_setname(setno);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	mdb_printf("d%u: Raid", MD_MIN2UNIT(un_self_id));
2980Sstevel@tonic-gate 	if (verbose) {
2990Sstevel@tonic-gate 		mdb_printf("\t< %p ::print mr_unit_t>\n", un_addr);
3000Sstevel@tonic-gate 	} else {
3010Sstevel@tonic-gate 		mdb_printf("\t< %p >\n", un_addr);
3020Sstevel@tonic-gate 	}
3030Sstevel@tonic-gate 	mdb_inc_indent(2);
3040Sstevel@tonic-gate 	mdb_printf("Size: %llu\n", un_total_blocks);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	/*
3070Sstevel@tonic-gate 	 * find the sub components if any, search through each metadevice
3080Sstevel@tonic-gate 	 * looking at the un_parent.
3090Sstevel@tonic-gate 	 */
3100Sstevel@tonic-gate 	ptr = mdset[setno].s_un;
3110Sstevel@tonic-gate 	for (i = 0; i < md_nunits; i++, ptr++) {
3120Sstevel@tonic-gate 		if (mdb_vread(&addr, sizeof (void *), (uintptr_t)ptr) == -1) {
3130Sstevel@tonic-gate 			mdb_warn("failed to read addr at %p\n", ptr);
3140Sstevel@tonic-gate 			continue;
3150Sstevel@tonic-gate 		}
3160Sstevel@tonic-gate 		if (addr != NULL) {
3170Sstevel@tonic-gate 			if (mdb_vread(&mdc_sc, sizeof (mdc_unit_t),
3180Sstevel@tonic-gate 			    (uintptr_t)addr) == -1) {
3190Sstevel@tonic-gate 				mdb_warn("failed to read mdc_unit_t at %p",
3200Sstevel@tonic-gate 				    un_addr);
3210Sstevel@tonic-gate 				continue;
3220Sstevel@tonic-gate 			}
3230Sstevel@tonic-gate 			sc_parent = mdc_sc.un_parent;
3240Sstevel@tonic-gate 			sc_un_self_id = mdc_sc.un_self_id;
3250Sstevel@tonic-gate 			sc_total_blocks = mdc_sc.un_total_blocks;
3260Sstevel@tonic-gate 			if (sc_parent == un_self_id) {
3270Sstevel@tonic-gate 				/* this is one of the sub components */
3280Sstevel@tonic-gate 				mdb_printf("Subdevice %u ",
3290Sstevel@tonic-gate 				    MD_MIN2UNIT(sc_un_self_id));
3300Sstevel@tonic-gate 				mdb_printf("Size: %llu\n", sc_total_blocks);
3310Sstevel@tonic-gate 			}
3320Sstevel@tonic-gate 		}
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 	mdb_dec_indent(2);
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate void
print_sp(void * un_addr,void * mdcptr,uint_t verbose)3380Sstevel@tonic-gate print_sp(void *un_addr, void *mdcptr, uint_t verbose)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	mp_unit_t	mp;
3410Sstevel@tonic-gate 	minor_t		un_self_id;
3420Sstevel@tonic-gate 	diskaddr_t	un_total_blocks;
3430Sstevel@tonic-gate 	int		setno = 0;
3440Sstevel@tonic-gate 	uintptr_t	extaddr;
3450Sstevel@tonic-gate 	int		i;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	/* read in the device */
3480Sstevel@tonic-gate 	if (mdb_vread(&mp, sizeof (mp_unit_t), (uintptr_t)un_addr) == -1) {
3490Sstevel@tonic-gate 		mdb_warn("failed to read mp_unit_t at %p\n", un_addr);
3500Sstevel@tonic-gate 		return;
3510Sstevel@tonic-gate 	}
3520Sstevel@tonic-gate 	un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id;
3530Sstevel@tonic-gate 	un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks;
3540Sstevel@tonic-gate 	setno = MD_MIN2SET(un_self_id);
3550Sstevel@tonic-gate 	print_setname(setno);
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	mdb_printf("d%u: Soft Partition", MD_MIN2UNIT(un_self_id));
3580Sstevel@tonic-gate 	if (verbose) {
3590Sstevel@tonic-gate 		mdb_printf("\t< %p ::print mp_unit_t >\n", un_addr);
3600Sstevel@tonic-gate 	} else {
3610Sstevel@tonic-gate 		mdb_printf("\t< %p >\n", un_addr);
3620Sstevel@tonic-gate 	}
3630Sstevel@tonic-gate 	mdb_inc_indent(2);
3640Sstevel@tonic-gate 	mdb_printf("Size: %llu\n", un_total_blocks);
3650Sstevel@tonic-gate 	mdb_inc_indent(2);
3660Sstevel@tonic-gate 	mdb_printf("Extent\tStart Block\tBlock count\n");
3670Sstevel@tonic-gate 	extaddr = (uintptr_t)un_addr + sizeof (mp_unit_t) - sizeof (mp_ext_t);
3680Sstevel@tonic-gate 	for (i = 0; i < mp.un_numexts; i++) {
3690Sstevel@tonic-gate 		mp_ext_t	mpext;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 		if (mdb_vread(&mpext, sizeof (mp_ext_t), extaddr) == -1) {
3720Sstevel@tonic-gate 			mdb_warn("failed to read mp_ext_t at %p\n", extaddr);
3730Sstevel@tonic-gate 			return;
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 		mdb_printf("   %d \t      %llu\t        %llu\n",
3760Sstevel@tonic-gate 		    i, mpext.un_poff, mpext.un_len);
3770Sstevel@tonic-gate 		extaddr += sizeof (mp_ext_t);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 	mdb_dec_indent(2);
3800Sstevel@tonic-gate 	mdb_dec_indent(2);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate void
print_trans(void * un_addr,void * mdcptr,uint_t verbose)3850Sstevel@tonic-gate print_trans(void *un_addr, void *mdcptr, uint_t verbose)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	mt_unit_t	mt;
3880Sstevel@tonic-gate 	minor_t		un_self_id;
3890Sstevel@tonic-gate 	int		setno = 0;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	/* read in the device */
3920Sstevel@tonic-gate 	if (mdb_vread(&mt, sizeof (mt_unit_t), (uintptr_t)un_addr) == -1) {
3930Sstevel@tonic-gate 		mdb_warn("failed to read mt_unit_t at %p\n", un_addr);
3940Sstevel@tonic-gate 		return;
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 	un_self_id = ((mdc_unit32_od_t *)mdcptr)->un_self_id;
3970Sstevel@tonic-gate 	setno = MD_MIN2SET(un_self_id);
3980Sstevel@tonic-gate 	print_setname(setno);
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	mdb_printf("d%u: Trans", MD_MIN2UNIT(un_self_id));
4010Sstevel@tonic-gate 	if (verbose) {
4020Sstevel@tonic-gate 		mdb_printf("\t< %p ::print mt_unit_t>\n", un_addr);
4030Sstevel@tonic-gate 	} else {
4040Sstevel@tonic-gate 		mdb_printf("\t< %p >\n", un_addr);
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate void
print_device(void * un_addr,void * mdcptr,uint_t verbose)4100Sstevel@tonic-gate print_device(void *un_addr, void *mdcptr, uint_t verbose)
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate 	u_longlong_t	un_type;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	un_type = ((mdc_unit_t *)mdcptr)->un_type;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	switch (un_type) {
4170Sstevel@tonic-gate 	case MD_DEVICE:		/* stripe/concat */
4180Sstevel@tonic-gate 		print_stripe(un_addr, mdcptr, verbose);
4190Sstevel@tonic-gate 		break;
4200Sstevel@tonic-gate 	case MD_METAMIRROR:
4210Sstevel@tonic-gate 		print_mirror(un_addr, mdcptr, verbose);
4220Sstevel@tonic-gate 		break;
4230Sstevel@tonic-gate 	case MD_METATRANS:
4240Sstevel@tonic-gate 		print_trans(un_addr, mdcptr, verbose);
4250Sstevel@tonic-gate 		break;
4260Sstevel@tonic-gate 	case MD_METARAID:
4270Sstevel@tonic-gate 		print_raid(un_addr, mdcptr, verbose);
4280Sstevel@tonic-gate 		break;
4290Sstevel@tonic-gate 	case MD_METASP:
4300Sstevel@tonic-gate 		print_sp(un_addr, mdcptr, verbose);
4310Sstevel@tonic-gate 		break;
4320Sstevel@tonic-gate 	case MD_UNDEFINED:
4330Sstevel@tonic-gate 		mdb_warn("undefined metadevice at %p\n", un_addr);
4340Sstevel@tonic-gate 		break;
4350Sstevel@tonic-gate 	default:
4360Sstevel@tonic-gate 		mdb_warn("invalid metadevice at %p\n", un_addr);
4370Sstevel@tonic-gate 		break;
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate /* ARGSUSED */
4420Sstevel@tonic-gate /*
4430Sstevel@tonic-gate  * usage:  ::metastat [-v]
4440Sstevel@tonic-gate  */
4450Sstevel@tonic-gate int
metastat(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4460Sstevel@tonic-gate metastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	mdc_unit_t	mdc;
4490Sstevel@tonic-gate 	uintptr_t	un_addr;
4500Sstevel@tonic-gate 	uint_t		verbose = FALSE;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	snarf_sets();
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL)
4550Sstevel@tonic-gate 	    != argc) {
4560Sstevel@tonic-gate 		return (DCMD_USAGE);
4570Sstevel@tonic-gate 	}
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
4600Sstevel@tonic-gate 		if (mdb_walk_dcmd("md_units", "metastat", argc,
4610Sstevel@tonic-gate 		    argv) == -1) {
4620Sstevel@tonic-gate 			mdb_warn("failed to walk units");
4630Sstevel@tonic-gate 			return (DCMD_ERR);
4640Sstevel@tonic-gate 		}
4650Sstevel@tonic-gate 		return (DCMD_OK);
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 	if (!(flags & DCMD_LOOP)) {
4680Sstevel@tonic-gate 		/* user passed set addr */
4690Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("md_units", "metastat", argc,
4700Sstevel@tonic-gate 		    argv, addr) == -1) {
4710Sstevel@tonic-gate 			mdb_warn("failed to walk units");
4720Sstevel@tonic-gate 			return (DCMD_ERR);
4730Sstevel@tonic-gate 		}
4740Sstevel@tonic-gate 		return (DCMD_OK);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	if (mdb_vread(&un_addr, sizeof (void *), addr) == -1) {
4780Sstevel@tonic-gate 		mdb_warn("failed to read un_addr at %p", addr);
4790Sstevel@tonic-gate 		return (DCMD_ERR);
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	if (un_addr != NULL) {
4830Sstevel@tonic-gate 		if (mdb_vread(&mdc, sizeof (mdc_unit_t), un_addr) == -1) {
4840Sstevel@tonic-gate 			mdb_warn("failed to read mdc_unit_t at %p", un_addr);
4850Sstevel@tonic-gate 			return (DCMD_ERR);
4860Sstevel@tonic-gate 		}
4870Sstevel@tonic-gate 		print_device((void *)un_addr, (void *)&mdc, verbose);
4880Sstevel@tonic-gate 		mdb_dec_indent(2);
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 	return (DCMD_OK);
4910Sstevel@tonic-gate }
492