1*734Smw145384 /*
2*734Smw145384  * CDDL HEADER START
3*734Smw145384  *
4*734Smw145384  * The contents of this file are subject to the terms of the
5*734Smw145384  * Common Development and Distribution License, Version 1.0 only
6*734Smw145384  * (the "License").  You may not use this file except in compliance
7*734Smw145384  * with the License.
8*734Smw145384  *
9*734Smw145384  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*734Smw145384  * or http://www.opensolaris.org/os/licensing.
11*734Smw145384  * See the License for the specific language governing permissions
12*734Smw145384  * and limitations under the License.
13*734Smw145384  *
14*734Smw145384  * When distributing Covered Code, include this CDDL HEADER in each
15*734Smw145384  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*734Smw145384  * If applicable, add the following below this CDDL HEADER, with the
17*734Smw145384  * fields enclosed by brackets "[]" replaced with your own identifying
18*734Smw145384  * information: Portions Copyright [yyyy] [name of copyright owner]
19*734Smw145384  *
20*734Smw145384  * CDDL HEADER END
21*734Smw145384  */
22*734Smw145384 /*
23*734Smw145384  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*734Smw145384  * Use is subject to license terms.
25*734Smw145384  */
26*734Smw145384 
27*734Smw145384 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*734Smw145384 
29*734Smw145384 #include <meta.h>
30*734Smw145384 #include <assert.h>
31*734Smw145384 #include <ctype.h>
32*734Smw145384 #include <mdiox.h>
33*734Smw145384 #include <meta.h>
34*734Smw145384 #include <stdio.h>
35*734Smw145384 #include <stdlib.h>
36*734Smw145384 #include <strings.h>
37*734Smw145384 #include <sys/lvm/md_mddb.h>
38*734Smw145384 #include <sys/lvm/md_names.h>
39*734Smw145384 #include <sys/lvm/md_crc.h>
40*734Smw145384 #include <sys/lvm/md_convert.h>
41*734Smw145384 
42*734Smw145384 
43*734Smw145384 /*
44*734Smw145384  * Design Notes:
45*734Smw145384  *
46*734Smw145384  * All of the code in this file supports the addition of metastat -c output
47*734Smw145384  * for the verbose option of metaimport.  Some of this code is also used by
48*734Smw145384  * the command metastat for concise output(cmd/lvm/util/metastat.c).
49*734Smw145384  * The code is designed to produce the same output as metastat -c does for a
50*734Smw145384  * given diskset--with a couple exceptions.
51*734Smw145384  * The primary differences between the output for the metastat -c command and
52*734Smw145384  * metastat output for metaimport -v are:
53*734Smw145384  *  - the set name is not printed next to each metadevice
54*734Smw145384  *  - top-level state information is not printed for some metadevices
55*734Smw145384  *  - the percent that a disk has completed resyncing is not listed
56*734Smw145384  * in metaimport -v.
57*734Smw145384  *
58*734Smw145384  *
59*734Smw145384  * The general layout of this file is as follows:
60*734Smw145384  *
61*734Smw145384  *  - report_metastat_info()
62*734Smw145384  *	This is the primary entry point for the functions in this file, with
63*734Smw145384  *	the exception of several functions that are also called from
64*734Smw145384  *	cmd/io/lvm/util/metastat.c
65*734Smw145384  *	report_metastat_info() calls functions to read in all the the
66*734Smw145384  *	Directory blocks and Record blocks and then process the information
67*734Smw145384  *	needed to print out the metadevice records in the same format as
68*734Smw145384  *	metastat -c.
69*734Smw145384  *
70*734Smw145384  *  - read_all_mdrecords()
71*734Smw145384  *	Reads in all the Directory blocks in the diskset and verifies their
72*734Smw145384  *	validity.  For each Directly block, it loops through all Directory
73*734Smw145384  *	Entries and for each one that contains a metadevice record calls
74*734Smw145384  *	read_md_record().  Because the output is designed to imitate the
75*734Smw145384  *	output of metastat -c, we ignore metadevice records for
76*734Smw145384  *	optimized resync, changelog, and translog.
77*734Smw145384  *
78*734Smw145384  *  - read_md_record()
79*734Smw145384  *	Reads in a Directory Entry and its associated Record block.  The
80*734Smw145384  *	revision information for the Record block is checked and it is
81*734Smw145384  *	determined whether or not it is a 64bit Record block or a 32bit record
82*734Smw145384  *	block.  For each valid Record block, it allocates an md_im_rec_t
83*734Smw145384  *	structure and calls extract_mduser_data().
84*734Smw145384  *
85*734Smw145384  *  - extract_mduser_data()
86*734Smw145384  *	Populates the md_im_rec_t data structure with information about the
87*734Smw145384  *	record's associated metadevice.  Also, the name of the metadevice is
88*734Smw145384  *	either copied from the NM namespace(if it exists there) or is generated
89*734Smw145384  *	from the record's un_self_id.
90*734Smw145384  *
91*734Smw145384  *  - process_toplevel_devices()
92*734Smw145384  *	For a given metadevice type, searchs through the md_im_rec_t **mdimpp,
93*734Smw145384  *	list of all metadevices in the set, to find all records of the
94*734Smw145384  *	specified type that do not have a parent and puts them on a temp list.
95*734Smw145384  *	The temp list is then iterated through and the associated processing
96*734Smw145384  *	function is called.
97*734Smw145384  *
98*734Smw145384  *  - process_(trans, hotspare, hotspare_pool, soft_part, mirror, stripe, raid)
99*734Smw145384  *	These functions are called by using the dfunc field in the mdimpp list.
100*734Smw145384  *	Each process function only understands its own type of metadevice. Once
101*734Smw145384  *	it processes the metadevice it was called for, it then loops through
102*734Smw145384  *	all of the underlying metadevices.  After printing the name of the
103*734Smw145384  *	underlying metadevice, it puts in on a list to be processed.  If the
104*734Smw145384  *	underlying device is a physical device, then print_physical_device is
105*734Smw145384  *	called.
106*734Smw145384  *	Once all information about the original metadevice is processed, it
107*734Smw145384  *	loops through the list of underlying metadevices and calls the
108*734Smw145384  *	appropriate function to process them.
109*734Smw145384  *
110*734Smw145384  *  - process_toplevel_softparts()
111*734Smw145384  *	To match the output for metastat -c, all top-level softpartions
112*734Smw145384  *	are printed out in groups based on their underlying metadevice--so that
113*734Smw145384  *	the underlying metadevice only needs to be processed once.
114*734Smw145384  *
115*734Smw145384  *  - meta_get_(sm_state, raid_col_state, stripe_state, hs_state)
116*734Smw145384  *	These functions are used to retrieve the metadevice state information.
117*734Smw145384  *	They are also used by the metastat concise routines in
118*734Smw145384  *	cmd/lvm/util/metastat.c.
119*734Smw145384  *
120*734Smw145384  */
121*734Smw145384 
122*734Smw145384 
123*734Smw145384 /*
124*734Smw145384  * md_im_rec is a doubly linked list used to store the rb_data for each
125*734Smw145384  * directory entry that corresponds to a metadevice.
126*734Smw145384  * n_key: is set, if there is an associated entry in the NM namespace.
127*734Smw145384  * dfunc: is set to point to the function that processes the particular
128*734Smw145384  * metadevice associated with the record.
129*734Smw145384  * hs_record_id: is only set, if the metadevice is a hotspare.
130*734Smw145384  * un_self_id: is set for all other records. This is also used to generate
131*734Smw145384  * the name of the metadevice if there is no entry for the metadevice in
132*734Smw145384  * the NM namespace--n_key is not set.
133*734Smw145384  */
134*734Smw145384 typedef struct md_im_rec {
135*734Smw145384 	mdkey_t			n_key; /* NM namespace key */
136*734Smw145384 	struct md_im_rec 	*next;
137*734Smw145384 	struct md_im_rec 	*prev;
138*734Smw145384 	uint_t			md_type;
139*734Smw145384 	uint_t			has_parent; /* either 0(no parent) or 1 */
140*734Smw145384 	minor_t			un_self_id;
141*734Smw145384 	mddb_recid_t		hs_record_id; /* hotspare recid */
142*734Smw145384 	char 			*n_name;  /* name of metadevice */
143*734Smw145384 	void 			(*dfunc) ();
144*734Smw145384 	ushort_t		record_len;
145*734Smw145384 	/* pointer to the unit structure for the metadevice, e.g. rb_data[0] */
146*734Smw145384 	void			*record;
147*734Smw145384 } md_im_rec_t;
148*734Smw145384 
149*734Smw145384 /*
150*734Smw145384  * md_im_list is used to group toplevel metadevices by type and to group
151*734Smw145384  * the underlying devices for a particular metadevice.
152*734Smw145384  */
153*734Smw145384 typedef struct md_im_list {
154*734Smw145384 	struct md_im_list	*next;
155*734Smw145384 	struct md_im_rec 	*mdrec;
156*734Smw145384 } md_im_list_t;
157*734Smw145384 
158*734Smw145384 
159*734Smw145384 /*
160*734Smw145384  * MAXSIZEMDRECNAME is the value that has historically been used to allocate
161*734Smw145384  * space for the metadevice name
162*734Smw145384  */
163*734Smw145384 #define	MAXSIZEMDRECNAME	20
164*734Smw145384 #define	NAMEWIDTH		16
165*734Smw145384 #define	offsetof(s, m)	((size_t)(&(((s *)0)->m)))
166*734Smw145384 #define	NOT_PHYSICAL_DEV	0
167*734Smw145384 #define	PHYSICAL_DEV		1
168*734Smw145384 
169*734Smw145384 
170*734Smw145384 /*
171*734Smw145384  * strip_blacks()
172*734Smw145384  *
173*734Smw145384  * Strip blanks from string.  Used for size field in concise output.
174*734Smw145384  */
175*734Smw145384 static char *
176*734Smw145384 strip_blanks(char *s)
177*734Smw145384 {
178*734Smw145384 	char *p;
179*734Smw145384 
180*734Smw145384 	for (p = s; *p; ) {
181*734Smw145384 		if (*p == ' ') {
182*734Smw145384 			char *t;
183*734Smw145384 			for (t = p; *t; t++) {
184*734Smw145384 				*t = *(t + 1);
185*734Smw145384 			}
186*734Smw145384 		} else {
187*734Smw145384 			p++;
188*734Smw145384 		}
189*734Smw145384 	}
190*734Smw145384 
191*734Smw145384 	return (s);
192*734Smw145384 }
193*734Smw145384 
194*734Smw145384 
195*734Smw145384 /*
196*734Smw145384  * print_concise_entry()
197*734Smw145384  *
198*734Smw145384  * Print properly indented metadevice name, type and size for concise output.
199*734Smw145384  * This function is also called from: cmd/lvm/util/metastat.c.
200*734Smw145384  */
201*734Smw145384 void
202*734Smw145384 print_concise_entry(int indent, char *name, diskaddr_t size, char mtype)
203*734Smw145384 {
204*734Smw145384 	int	i;
205*734Smw145384 	int	width = NAMEWIDTH;	/* minumum field width for name */
206*734Smw145384 	char	in[MAXPATHLEN];
207*734Smw145384 	char	*sz;
208*734Smw145384 
209*734Smw145384 	in[0] = 0;
210*734Smw145384 	for (i = 0; i < indent; i++)
211*734Smw145384 		(void) strlcat(in, " ", sizeof (in));
212*734Smw145384 
213*734Smw145384 	/* set up minimum field width. negative for left justified */
214*734Smw145384 	width -= indent;
215*734Smw145384 	if (width < 0)
216*734Smw145384 		width = 0;	/* overflowed; no minimum field needed */
217*734Smw145384 	else
218*734Smw145384 		width = 0 - width; /* negative for left justification */
219*734Smw145384 
220*734Smw145384 	if (size == 0) {
221*734Smw145384 		sz = "-";
222*734Smw145384 	} else {
223*734Smw145384 		sz = strip_blanks(meta_number_to_string(size, DEV_BSIZE));
224*734Smw145384 	}
225*734Smw145384 
226*734Smw145384 	(void) printf("%s%*s %c %6s", in, width, name, mtype, sz);
227*734Smw145384 }
228*734Smw145384 
229*734Smw145384 
230*734Smw145384 /*
231*734Smw145384  * free_mdrec_list_entry()
232*734Smw145384  *
233*734Smw145384  * Removing entry from the list of metadevices in the diskset(mdimpp).
234*734Smw145384  * This function will not remove the dummy entry at the head of the
235*734Smw145384  * list, so we don't have to set mdrec equal to NULL.
236*734Smw145384  */
237*734Smw145384 static void
238*734Smw145384 free_mdrec_list_entry(md_im_rec_t  **mdrec)
239*734Smw145384 {
240*734Smw145384 	(*mdrec)->prev->next = (*mdrec)->next;
241*734Smw145384 	if ((*mdrec)->next != NULL) {
242*734Smw145384 		(*mdrec)->next->prev = (*mdrec)->prev;
243*734Smw145384 	}
244*734Smw145384 	Free((*mdrec)->record);
245*734Smw145384 	Free((*mdrec)->n_name);
246*734Smw145384 	Free(*mdrec);
247*734Smw145384 }
248*734Smw145384 
249*734Smw145384 
250*734Smw145384 /*
251*734Smw145384  * ucomponent_append()
252*734Smw145384  *
253*734Smw145384  * Appending entry to the underlying component list.  The list
254*734Smw145384  * is used to group all of the underlying devices before
255*734Smw145384  * processing them.
256*734Smw145384  */
257*734Smw145384 static void
258*734Smw145384 ucomponent_append(
259*734Smw145384 	md_im_list_t	**ucomp_head,
260*734Smw145384 	md_im_list_t	**ucomp_tail,
261*734Smw145384 	md_im_list_t	*ucomp
262*734Smw145384 )
263*734Smw145384 {
264*734Smw145384 	ucomp->next = NULL;
265*734Smw145384 	if (*ucomp_head == NULL) {
266*734Smw145384 		*ucomp_head = ucomp;
267*734Smw145384 		*ucomp_tail = ucomp;
268*734Smw145384 	} else {
269*734Smw145384 		(*ucomp_tail)->next = ucomp;
270*734Smw145384 		*ucomp_tail = (*ucomp_tail)->next;
271*734Smw145384 	}
272*734Smw145384 }
273*734Smw145384 
274*734Smw145384 
275*734Smw145384 /*
276*734Smw145384  * free_md_im_list_entries()
277*734Smw145384  *
278*734Smw145384  * Freeing entries on an md_im_list_t.  This list is used to group
279*734Smw145384  * underlying components for processing and to group top-level metadevices
280*734Smw145384  * by type.
281*734Smw145384  */
282*734Smw145384 static void
283*734Smw145384 free_md_im_list_entries(md_im_list_t **list_head)
284*734Smw145384 {
285*734Smw145384 	md_im_list_t	*tmp_list_entry = *list_head;
286*734Smw145384 	md_im_list_t	*rm_list_entry;
287*734Smw145384 
288*734Smw145384 	while (tmp_list_entry != NULL) {
289*734Smw145384 		rm_list_entry = tmp_list_entry;
290*734Smw145384 		tmp_list_entry = tmp_list_entry->next;
291*734Smw145384 		Free(rm_list_entry);
292*734Smw145384 	}
293*734Smw145384 }
294*734Smw145384 
295*734Smw145384 
296*734Smw145384 /*
297*734Smw145384  * print_physical_device()
298*734Smw145384  *
299*734Smw145384  * If a metadevice has an underlying component that is a physical
300*734Smw145384  * device, then this searches the pnm_rec_t list to match an entry's
301*734Smw145384  * n_key to the key for the underlying component.  The ctd name of the
302*734Smw145384  * physical device is printed on the same line as the metadevice.
303*734Smw145384  */
304*734Smw145384 static void
305*734Smw145384 print_physical_device(
306*734Smw145384 	pnm_rec_t	*phys_nm,
307*734Smw145384 	mdkey_t		key
308*734Smw145384 )
309*734Smw145384 {
310*734Smw145384 	pnm_rec_t	*tmpphys_nm;
311*734Smw145384 
312*734Smw145384 	for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
313*734Smw145384 	    tmpphys_nm = tmpphys_nm->next) {
314*734Smw145384 		if (tmpphys_nm->n_key == key) {
315*734Smw145384 			(void) printf(" %s", tmpphys_nm->n_name);
316*734Smw145384 			break;
317*734Smw145384 		}
318*734Smw145384 	}
319*734Smw145384 }
320*734Smw145384 
321*734Smw145384 
322*734Smw145384 /*
323*734Smw145384  * get_stripe_req_size()
324*734Smw145384  *
325*734Smw145384  * Given a 64bit stripe unit, compute the size of the stripe unit.
326*734Smw145384  * This function is a derivation of:
327*734Smw145384  *	common/lvm/md_convert.c:get_big_stripe_req_size()
328*734Smw145384  * and any changes made to either this function or get_big_stripe_req_size()
329*734Smw145384  * should be reviewed to make sure the functionality in both places is correct.
330*734Smw145384  *
331*734Smw145384  * Returns:
332*734Smw145384  *	total size of the 64bit stripe
333*734Smw145384  */
334*734Smw145384 size_t
335*734Smw145384 get_stripe_req_size(ms_unit_t *un)
336*734Smw145384 {
337*734Smw145384 	struct ms_row *mdr;
338*734Smw145384 	uint_t row;
339*734Smw145384 	uint_t ncomps = 0;
340*734Smw145384 	size_t mdsize = 0;
341*734Smw145384 	size_t first_comp = 0;
342*734Smw145384 
343*734Smw145384 
344*734Smw145384 	/* Compute the offset of the first component */
345*734Smw145384 	first_comp = sizeof (ms_unit_t) +
346*734Smw145384 	    sizeof (struct ms_row) * (un->un_nrows - 1);
347*734Smw145384 	first_comp = roundup(first_comp, sizeof (long long));
348*734Smw145384 
349*734Smw145384 	/*
350*734Smw145384 	 * Requestor wants to have the total size, add the sizes of
351*734Smw145384 	 * all components
352*734Smw145384 	 */
353*734Smw145384 	mdr = &un->un_row[0];
354*734Smw145384 	for (row = 0; (row < un->un_nrows); row++)
355*734Smw145384 	    ncomps += mdr[row].un_ncomp;
356*734Smw145384 	mdsize = first_comp + sizeof (ms_comp_t) * ncomps;
357*734Smw145384 	return (mdsize);
358*734Smw145384 }
359*734Smw145384 
360*734Smw145384 
361*734Smw145384 /*
362*734Smw145384  * meta_get_sm_state()
363*734Smw145384  *
364*734Smw145384  * Gets the state for the underlying components(submirrors) of a mirror.
365*734Smw145384  * This function is also called from: cmd/lvm/util/metastat.c.
366*734Smw145384  *
367*734Smw145384  * Returns:
368*734Smw145384  *	string for state of the sub-mirror
369*734Smw145384  */
370*734Smw145384 static char *
371*734Smw145384 meta_get_sm_state(
372*734Smw145384 	sm_state_t	state
373*734Smw145384 )
374*734Smw145384 {
375*734Smw145384 	/* all is well */
376*734Smw145384 	if (state & SMS_RUNNING) {
377*734Smw145384 		return (NULL);
378*734Smw145384 	}
379*734Smw145384 
380*734Smw145384 	/* resyncing, needs repair */
381*734Smw145384 	if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
382*734Smw145384 	    SMS_OFFLINE_RESYNC))) {
383*734Smw145384 		return (gettext("resyncing"));
384*734Smw145384 	}
385*734Smw145384 
386*734Smw145384 	/* needs repair */
387*734Smw145384 	if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE))
388*734Smw145384 		return (gettext("maint"));
389*734Smw145384 
390*734Smw145384 	/* unknown */
391*734Smw145384 	return (gettext("unknown"));
392*734Smw145384 }
393*734Smw145384 
394*734Smw145384 
395*734Smw145384 /*
396*734Smw145384  * meta_get_raid_col_state()
397*734Smw145384  *
398*734Smw145384  * Gets the state for the underlying components(columns) of a raid.
399*734Smw145384  * This function is also called from: cmd/lvm/util/metastat.c.
400*734Smw145384  *
401*734Smw145384  * Returns:
402*734Smw145384  *	string for state of the raid column
403*734Smw145384  *
404*734Smw145384  */
405*734Smw145384 char *
406*734Smw145384 meta_get_raid_col_state(
407*734Smw145384 	rcs_state_t	state
408*734Smw145384 )
409*734Smw145384 {
410*734Smw145384 	switch (state) {
411*734Smw145384 		case RCS_INIT:
412*734Smw145384 			return (gettext("initializing"));
413*734Smw145384 		case RCS_OKAY:
414*734Smw145384 			return (NULL);
415*734Smw145384 		case RCS_INIT_ERRED:
416*734Smw145384 			/*FALLTHROUGH*/
417*734Smw145384 		case RCS_ERRED:
418*734Smw145384 			return (gettext("maint"));
419*734Smw145384 		case RCS_LAST_ERRED:
420*734Smw145384 			return (gettext("last-erred"));
421*734Smw145384 		case RCS_RESYNC:
422*734Smw145384 			return (gettext("resyncing"));
423*734Smw145384 		default:
424*734Smw145384 			return (gettext("unknown"));
425*734Smw145384 	}
426*734Smw145384 }
427*734Smw145384 
428*734Smw145384 
429*734Smw145384 /*
430*734Smw145384  * meta_get_stripe_state()
431*734Smw145384  *
432*734Smw145384  * Gets the state for the underlying components of a stripe.
433*734Smw145384  * This function is also called from: cmd/lvm/util/metastat.c.
434*734Smw145384  *
435*734Smw145384  * Returns:
436*734Smw145384  *	string for state of the stripe
437*734Smw145384  *
438*734Smw145384  */
439*734Smw145384 char *
440*734Smw145384 meta_get_stripe_state(
441*734Smw145384 	comp_state_t	state
442*734Smw145384 )
443*734Smw145384 {
444*734Smw145384 	switch (state) {
445*734Smw145384 		case CS_OKAY:
446*734Smw145384 			return (NULL);
447*734Smw145384 		case CS_ERRED:
448*734Smw145384 			return (gettext("maint"));
449*734Smw145384 		case CS_LAST_ERRED:
450*734Smw145384 			return (gettext("last-erred"));
451*734Smw145384 		case CS_RESYNC:
452*734Smw145384 			return (gettext("resyncing"));
453*734Smw145384 		default:
454*734Smw145384 			return (gettext("invalid"));
455*734Smw145384 	}
456*734Smw145384 }
457*734Smw145384 
458*734Smw145384 
459*734Smw145384 /*
460*734Smw145384  * meta_get_hs_state()
461*734Smw145384  *
462*734Smw145384  * Gets the state for the underlying components(hotspares) of a hotspare pool.
463*734Smw145384  * This function is also called from: cmd/lvm/util/metastat.c.
464*734Smw145384  *
465*734Smw145384  * Returns:
466*734Smw145384  *	string for state of the hotspare
467*734Smw145384  *
468*734Smw145384  */
469*734Smw145384 char *
470*734Smw145384 meta_get_hs_state(
471*734Smw145384 	hotspare_states_t	state
472*734Smw145384 )
473*734Smw145384 {
474*734Smw145384 	switch (state) {
475*734Smw145384 		case HSS_AVAILABLE:
476*734Smw145384 			return (NULL);
477*734Smw145384 		case HSS_RESERVED:
478*734Smw145384 			return (gettext("in-use"));
479*734Smw145384 		case HSS_BROKEN:
480*734Smw145384 			return (gettext("broken"));
481*734Smw145384 		case HSS_UNUSED:
482*734Smw145384 			/* FALLTHROUGH */
483*734Smw145384 		default:
484*734Smw145384 			return (gettext("invalid"));
485*734Smw145384 	}
486*734Smw145384 }
487*734Smw145384 
488*734Smw145384 
489*734Smw145384 /*
490*734Smw145384  * process_trans()
491*734Smw145384  *
492*734Smw145384  * Prints unit information for a trans metadevice and calls the respective
493*734Smw145384  * functions to process the underlying metadevices.
494*734Smw145384  *
495*734Smw145384  */
496*734Smw145384 static void
497*734Smw145384 process_trans(
498*734Smw145384 	md_im_rec_t	**mdimpp,
499*734Smw145384 	int		indent,
500*734Smw145384 	pnm_rec_t	*phys_nm,
501*734Smw145384 	md_im_rec_t	*mdrec
502*734Smw145384 )
503*734Smw145384 {
504*734Smw145384 	mt_unit_t	*mt;
505*734Smw145384 	mdc_unit_t	uc;
506*734Smw145384 	md_im_rec_t	*tmpmdrec;
507*734Smw145384 	int		underlying_device = PHYSICAL_DEV;
508*734Smw145384 
509*734Smw145384 	mt = (mt_unit_t *)mdrec->record;
510*734Smw145384 	uc = mt->c;
511*734Smw145384 
512*734Smw145384 	/* Printing name, size, and type of metadevice */
513*734Smw145384 	print_concise_entry(indent, mdrec->n_name,
514*734Smw145384 	    uc.un_total_blocks, 't');
515*734Smw145384 
516*734Smw145384 	/*
517*734Smw145384 	 * Loops through md_im_rec_t **mdimpp list of all metadevices to find
518*734Smw145384 	 * record that matches the underlying device.
519*734Smw145384 	 * Trans devices can only have one underlying device, so once a
520*734Smw145384 	 * match is found, we are done.
521*734Smw145384 	 */
522*734Smw145384 	for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
523*734Smw145384 	    tmpmdrec = tmpmdrec->next) {
524*734Smw145384 		if (tmpmdrec->n_key == mt->un_m_key) {
525*734Smw145384 			/* Printing name of the underlying metadevice */
526*734Smw145384 			(void) printf(" %s", tmpmdrec->n_name);
527*734Smw145384 			underlying_device = NOT_PHYSICAL_DEV;
528*734Smw145384 			break;
529*734Smw145384 		}
530*734Smw145384 	}
531*734Smw145384 
532*734Smw145384 	/*
533*734Smw145384 	 * If a metadevice was not found, then the underlying device must be a
534*734Smw145384 	 * physical device.  Otherwise, call the functions to process the
535*734Smw145384 	 * underlying devices.
536*734Smw145384 	 */
537*734Smw145384 	if (underlying_device == PHYSICAL_DEV) {
538*734Smw145384 		print_physical_device(phys_nm, mt->un_m_key);
539*734Smw145384 		(void) printf("\n");
540*734Smw145384 	} else {
541*734Smw145384 		/* process underlying component */
542*734Smw145384 		(void) printf("\n");
543*734Smw145384 		indent += META_INDENT;
544*734Smw145384 		tmpmdrec->dfunc(mdimpp, indent, phys_nm, tmpmdrec);
545*734Smw145384 	}
546*734Smw145384 
547*734Smw145384 	/*
548*734Smw145384 	 * Removing the md_entry from the list
549*734Smw145384 	 * of all metadevices
550*734Smw145384 	 */
551*734Smw145384 	free_mdrec_list_entry(&mdrec);
552*734Smw145384 }
553*734Smw145384 
554*734Smw145384 
555*734Smw145384 /*
556*734Smw145384  * process_hotspare()
557*734Smw145384  *
558*734Smw145384  * Searches though list of physical devices to match hotspare record.
559*734Smw145384  * Prints physical device name and state of a hotspare unit.
560*734Smw145384  *
561*734Smw145384  */
562*734Smw145384 /*ARGSUSED*/
563*734Smw145384 static void
564*734Smw145384 process_hotspare(
565*734Smw145384 	md_im_rec_t	**mdimpp,
566*734Smw145384 	int		indent,
567*734Smw145384 	pnm_rec_t	*phys_nm,
568*734Smw145384 	md_im_rec_t	*mdrec
569*734Smw145384 )
570*734Smw145384 {
571*734Smw145384 	hot_spare_t	*hs;
572*734Smw145384 	pnm_rec_t	*tmpphys_nm;
573*734Smw145384 	char 		*state = NULL;
574*734Smw145384 
575*734Smw145384 	hs =  (hot_spare_t *)mdrec->record;
576*734Smw145384 
577*734Smw145384 	/*
578*734Smw145384 	 * Loops through physical namespace to find the device that matches
579*734Smw145384 	 * the hotspare entry.
580*734Smw145384 	 */
581*734Smw145384 	for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
582*734Smw145384 	    tmpphys_nm = tmpphys_nm->next) {
583*734Smw145384 		if (tmpphys_nm->n_key ==
584*734Smw145384 		    ((hot_spare_t *)hs)->hs_key) {
585*734Smw145384 			/* Printing name of hotspare device */
586*734Smw145384 			(void) printf(" %s", tmpphys_nm->n_name);
587*734Smw145384 			break;
588*734Smw145384 		}
589*734Smw145384 	}
590*734Smw145384 
591*734Smw145384 	state = meta_get_hs_state(hs->hs_state);
592*734Smw145384 	if (state != NULL)
593*734Smw145384 		(void) printf(" (%s)", state);
594*734Smw145384 
595*734Smw145384 	/* Not removing entry, because it can be processed more than once. */
596*734Smw145384 }
597*734Smw145384 
598*734Smw145384 
599*734Smw145384 /*
600*734Smw145384  * process_hotspare_pool()
601*734Smw145384  *
602*734Smw145384  * Prints concise unit information for a hotspare pool metadevice and calls a
603*734Smw145384  * function to process each attached hotspare device.
604*734Smw145384  *
605*734Smw145384  */
606*734Smw145384 static void
607*734Smw145384 process_hotspare_pool(
608*734Smw145384 	md_im_rec_t	**mdimpp,
609*734Smw145384 	int		indent,
610*734Smw145384 	pnm_rec_t	*phys_nm,
611*734Smw145384 	md_im_rec_t	*mdrec
612*734Smw145384 )
613*734Smw145384 {
614*734Smw145384 	hot_spare_pool_ond_t	*hsp;
615*734Smw145384 	int			i;
616*734Smw145384 	md_im_rec_t		*tmpmdrec;
617*734Smw145384 
618*734Smw145384 	hsp =  (hot_spare_pool_ond_t *)mdrec->record;
619*734Smw145384 
620*734Smw145384 	/*
621*734Smw145384 	 * Printing name, size, and type of metadevice. Setting size field to
622*734Smw145384 	 * 0, so that output is the as metastat -c.
623*734Smw145384 	 */
624*734Smw145384 	print_concise_entry(indent, mdrec->n_name,
625*734Smw145384 	    0, 'h');
626*734Smw145384 
627*734Smw145384 	/* Looping through list of attached hotspare devices. */
628*734Smw145384 	for (i = 0; i < hsp->hsp_nhotspares; i++) {
629*734Smw145384 		/* Looking for the matching record for the hotspare device. */
630*734Smw145384 		for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
631*734Smw145384 		    tmpmdrec = tmpmdrec->next) {
632*734Smw145384 			if (tmpmdrec->hs_record_id == hsp->hsp_hotspares[i]) {
633*734Smw145384 				/* Calling function to print name of hotspare */
634*734Smw145384 				tmpmdrec->dfunc(mdimpp, indent, phys_nm,
635*734Smw145384 				    tmpmdrec);
636*734Smw145384 			}
637*734Smw145384 		}
638*734Smw145384 	}
639*734Smw145384 	(void) printf("\n");
640*734Smw145384 
641*734Smw145384 	/*
642*734Smw145384 	 * Removing the md_entry from the list
643*734Smw145384 	 * of all metadevices
644*734Smw145384 	 */
645*734Smw145384 	free_mdrec_list_entry(&mdrec);
646*734Smw145384 }
647*734Smw145384 
648*734Smw145384 
649*734Smw145384 /*
650*734Smw145384  * process_raid()
651*734Smw145384  *
652*734Smw145384  * Prints concise unit information for a raid metadevice and calls the
653*734Smw145384  * respective functions to process the underlying metadevices.
654*734Smw145384  *
655*734Smw145384  */
656*734Smw145384 static void
657*734Smw145384 process_raid(
658*734Smw145384 	md_im_rec_t	**mdimpp,
659*734Smw145384 	int		indent,
660*734Smw145384 	pnm_rec_t	*phys_nm,
661*734Smw145384 	md_im_rec_t	*mdrec
662*734Smw145384 )
663*734Smw145384 {
664*734Smw145384 	mr_unit_t	*mr;
665*734Smw145384 	mr_column_t	*mc;
666*734Smw145384 	mdc_unit_t	uc;
667*734Smw145384 	int		i;
668*734Smw145384 	md_im_rec_t	*tmpmdrec;
669*734Smw145384 	md_im_rec_t	*hstmpmdrec;
670*734Smw145384 	md_im_list_t	*ucomp_head = NULL;
671*734Smw145384 	md_im_list_t	*ucomp_tail = NULL;
672*734Smw145384 	md_im_list_t	*ucomp = NULL;
673*734Smw145384 	pnm_rec_t	*tmpphys_nm;
674*734Smw145384 	int		underlying_device;
675*734Smw145384 
676*734Smw145384 	mr =  (mr_unit_t *)mdrec->record;
677*734Smw145384 	uc = mr->c;
678*734Smw145384 
679*734Smw145384 	/* Printing name, size, and type of metadevice */
680*734Smw145384 	print_concise_entry(indent, mdrec->n_name,
681*734Smw145384 	    uc.un_total_blocks, 'r');
682*734Smw145384 
683*734Smw145384 	/* Loops through raid columns to find underlying metadevices */
684*734Smw145384 	for (i = 0, mc = &mr->un_column[0];  i < mr->un_totalcolumncnt;
685*734Smw145384 	    i++, mc++) {
686*734Smw145384 		char	*state = NULL;
687*734Smw145384 		char	*hsname = NULL;
688*734Smw145384 
689*734Smw145384 		/*
690*734Smw145384 		 * Need to assume that underlying device is a physical device,
691*734Smw145384 		 * unless we find a matching metadevice record.
692*734Smw145384 		 */
693*734Smw145384 		underlying_device = PHYSICAL_DEV;
694*734Smw145384 
695*734Smw145384 		/*
696*734Smw145384 		 * Loops through list of metadevices to find record that matches
697*734Smw145384 		 * the underlying device.
698*734Smw145384 		 */
699*734Smw145384 		for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
700*734Smw145384 		    tmpmdrec = tmpmdrec->next) {
701*734Smw145384 			if (tmpmdrec->n_key == mc->un_orig_key) {
702*734Smw145384 				/* check if hotspare device enabled */
703*734Smw145384 				if (mc->un_hs_id !=  NULL) {
704*734Smw145384 					/*
705*734Smw145384 					 * Find matching metadevice record
706*734Smw145384 					 * for the hotspare device.
707*734Smw145384 					 */
708*734Smw145384 					for (hstmpmdrec = *mdimpp;
709*734Smw145384 					    hstmpmdrec != NULL;
710*734Smw145384 					    hstmpmdrec = hstmpmdrec->next) {
711*734Smw145384 						if (hstmpmdrec->hs_record_id ==
712*734Smw145384 						    mc->un_hs_id) {
713*734Smw145384 							/* print name of hs */
714*734Smw145384 							hstmpmdrec->dfunc(
715*734Smw145384 							    mdimpp, indent,
716*734Smw145384 							    phys_nm,
717*734Smw145384 							    hstmpmdrec);
718*734Smw145384 							break;
719*734Smw145384 						}
720*734Smw145384 					}
721*734Smw145384 				}
722*734Smw145384 				/* print name of underlying metadevice */
723*734Smw145384 				(void) printf(" %s", tmpmdrec->n_name);
724*734Smw145384 				underlying_device = NOT_PHYSICAL_DEV;
725*734Smw145384 				ucomp = Zalloc(sizeof (md_im_list_t));
726*734Smw145384 				ucomp->mdrec = tmpmdrec;
727*734Smw145384 				ucomponent_append(&ucomp_head, &ucomp_tail,
728*734Smw145384 				    ucomp);
729*734Smw145384 			}
730*734Smw145384 		}
731*734Smw145384 
732*734Smw145384 		if (underlying_device == PHYSICAL_DEV) {
733*734Smw145384 			print_physical_device(phys_nm, mc->un_orig_key);
734*734Smw145384 		}
735*734Smw145384 		state = meta_get_raid_col_state(mc->un_devstate);
736*734Smw145384 
737*734Smw145384 		/*
738*734Smw145384 		 * An underlying hotspare must be a physical device.
739*734Smw145384 		 * If support is ever added for soft-partitions under
740*734Smw145384 		 * hotspare pools, then this code should be updated to
741*734Smw145384 		 * include a search for underlying metadevices.
742*734Smw145384 		 */
743*734Smw145384 		if (mc->un_hs_id != 0) {
744*734Smw145384 			for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
745*734Smw145384 			    tmpphys_nm = tmpphys_nm->next) {
746*734Smw145384 				if (tmpphys_nm->n_key == mc->un_hs_key) {
747*734Smw145384 					hsname = tmpphys_nm->n_name;
748*734Smw145384 					break;
749*734Smw145384 				}
750*734Smw145384 			}
751*734Smw145384 		}
752*734Smw145384 
753*734Smw145384 		if (state != NULL) {
754*734Smw145384 			if (hsname != NULL)
755*734Smw145384 				(void) printf(" (%s-%s)", state,
756*734Smw145384 				    hsname);
757*734Smw145384 			else
758*734Smw145384 				(void) printf(" (%s)", state);
759*734Smw145384 		} else if (hsname != NULL) {
760*734Smw145384 			(void) printf(gettext(" (spared-%s)"), hsname);
761*734Smw145384 		}
762*734Smw145384 	}
763*734Smw145384 	(void) printf("\n");
764*734Smw145384 
765*734Smw145384 	/* process underlying components */
766*734Smw145384 	indent += META_INDENT;
767*734Smw145384 	for (ucomp = ucomp_head; ucomp != NULL;
768*734Smw145384 	    ucomp = ucomp->next) {
769*734Smw145384 		ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
770*734Smw145384 		    ucomp->mdrec);
771*734Smw145384 	}
772*734Smw145384 	free_md_im_list_entries(&ucomp_head);
773*734Smw145384 
774*734Smw145384 	/*
775*734Smw145384 	 * Removing the md_entry from the list
776*734Smw145384 	 * of all metadevices
777*734Smw145384 	 */
778*734Smw145384 	free_mdrec_list_entry(&mdrec);
779*734Smw145384 }
780*734Smw145384 
781*734Smw145384 
782*734Smw145384 /*
783*734Smw145384  * process_mirror()
784*734Smw145384  *
785*734Smw145384  * Prints concise unit information for a mirror metadevice and calls the
786*734Smw145384  * respective functions to process the underlying metadevices.
787*734Smw145384  *
788*734Smw145384  */
789*734Smw145384 static void
790*734Smw145384 process_mirror(
791*734Smw145384 	md_im_rec_t	**mdimpp,
792*734Smw145384 	int		indent,
793*734Smw145384 	pnm_rec_t	*phys_nm,
794*734Smw145384 	md_im_rec_t	*mdrec
795*734Smw145384 )
796*734Smw145384 {
797*734Smw145384 	mm_unit_t	*mm;
798*734Smw145384 	mm_submirror_t 	*sm;
799*734Smw145384 	mdc_unit_t	uc;
800*734Smw145384 	int		i;
801*734Smw145384 	md_im_rec_t	*tmpmdrec;
802*734Smw145384 	md_im_list_t	*ucomp_head = NULL;
803*734Smw145384 	md_im_list_t	*ucomp_tail = NULL;
804*734Smw145384 	md_im_list_t	*ucomp = NULL;
805*734Smw145384 
806*734Smw145384 	mm =  (mm_unit_t *)mdrec->record;
807*734Smw145384 	uc = mm->c;
808*734Smw145384 
809*734Smw145384 	/* Printing name, size, and type of metadevice */
810*734Smw145384 	print_concise_entry(indent, mdrec->n_name,
811*734Smw145384 	    uc.un_total_blocks, 'm');
812*734Smw145384 
813*734Smw145384 	/* Looping through sub-mirrors to find underlying devices */
814*734Smw145384 	for (i = 0, sm = &mm->un_sm[0]; i < mm->un_nsm; i++, sm++) {
815*734Smw145384 		char 	*state = NULL;
816*734Smw145384 
817*734Smw145384 		for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
818*734Smw145384 		    tmpmdrec = tmpmdrec->next) {
819*734Smw145384 			if (tmpmdrec->n_key == sm->sm_key) {
820*734Smw145384 				(void) printf(" %s", tmpmdrec->n_name);
821*734Smw145384 				ucomp = Zalloc(sizeof (md_im_list_t));
822*734Smw145384 				ucomp->mdrec = tmpmdrec;
823*734Smw145384 				ucomponent_append(&ucomp_head, &ucomp_tail,
824*734Smw145384 				    ucomp);
825*734Smw145384 			}
826*734Smw145384 		}
827*734Smw145384 
828*734Smw145384 		/*
829*734Smw145384 		 * It is not possible to have an underlying physical device
830*734Smw145384 		 * for a submirror, so there is no need to search the phys_nm
831*734Smw145384 		 * list.
832*734Smw145384 		 */
833*734Smw145384 
834*734Smw145384 		/* Printing the state for the submirror */
835*734Smw145384 		state = meta_get_sm_state(sm->sm_state);
836*734Smw145384 		if (state != NULL) {
837*734Smw145384 			(void) printf(" (%s)", state);
838*734Smw145384 		}
839*734Smw145384 	}
840*734Smw145384 	(void) printf("\n");
841*734Smw145384 
842*734Smw145384 	/* process underlying components */
843*734Smw145384 	indent += META_INDENT;
844*734Smw145384 	for (ucomp = ucomp_head; ucomp != NULL;
845*734Smw145384 	    ucomp = ucomp->next) {
846*734Smw145384 		ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
847*734Smw145384 		    ucomp->mdrec);
848*734Smw145384 	}
849*734Smw145384 	free_md_im_list_entries(&ucomp_head);
850*734Smw145384 
851*734Smw145384 	/*
852*734Smw145384 	 * Removing the md_entry from the list
853*734Smw145384 	 * of all metadevices
854*734Smw145384 	 */
855*734Smw145384 	free_mdrec_list_entry(&mdrec);
856*734Smw145384 }
857*734Smw145384 
858*734Smw145384 
859*734Smw145384 /*
860*734Smw145384  * process_stripe()
861*734Smw145384  *
862*734Smw145384  * Prints concise unit information for a stripe metadevice and calls the
863*734Smw145384  * respective functions to process the underlying metadevices.
864*734Smw145384  *
865*734Smw145384  */
866*734Smw145384 static void
867*734Smw145384 process_stripe(
868*734Smw145384 	md_im_rec_t	**mdimpp,
869*734Smw145384 	int		indent,
870*734Smw145384 	pnm_rec_t	*phys_nm,
871*734Smw145384 	md_im_rec_t	*mdrec
872*734Smw145384 )
873*734Smw145384 {
874*734Smw145384 	ms_unit_t	*ms;
875*734Smw145384 	mdc_unit_t	uc;
876*734Smw145384 	md_im_rec_t	*tmpmdrec;
877*734Smw145384 	md_im_list_t	*ucomp_head = NULL;
878*734Smw145384 	md_im_list_t	*ucomp_tail = NULL;
879*734Smw145384 	md_im_list_t	*ucomp = NULL;
880*734Smw145384 	pnm_rec_t	*tmpphys_nm;
881*734Smw145384 	int		underlying_device;
882*734Smw145384 	uint_t		row;
883*734Smw145384 
884*734Smw145384 	ms =  (ms_unit_t *)mdrec->record;
885*734Smw145384 	uc = ms->c;
886*734Smw145384 
887*734Smw145384 	/* Printing name, size, and type of metadevice */
888*734Smw145384 	print_concise_entry(indent, mdrec->n_name,
889*734Smw145384 	    uc.un_total_blocks, 's');
890*734Smw145384 
891*734Smw145384 	/* Looping through stripe rows */
892*734Smw145384 	for (row = 0; (row < ms->un_nrows); ++row) {
893*734Smw145384 		struct ms_row	*mdr = &ms->un_row[row];
894*734Smw145384 		ms_comp_t	*mdcomp = (void *)&((char *)ms)
895*734Smw145384 		    [ms->un_ocomp];
896*734Smw145384 		uint_t		comp, c;
897*734Smw145384 
898*734Smw145384 		/*
899*734Smw145384 		 * Looping through the components in each row to find the
900*734Smw145384 		 * underlying devices.
901*734Smw145384 		 */
902*734Smw145384 		for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp);
903*734Smw145384 		    ++comp, ++c) {
904*734Smw145384 			char		*state = NULL;
905*734Smw145384 			char		*hsname = NULL;
906*734Smw145384 			ms_comp_t	*mdc = &mdcomp[c];
907*734Smw145384 			md_m_shared_t 	*mdm = &mdc->un_mirror;
908*734Smw145384 
909*734Smw145384 			/*
910*734Smw145384 			 * Need to assume that underlying device is a
911*734Smw145384 			 * physical device, unless we find a matching
912*734Smw145384 			 * metadevice record.
913*734Smw145384 			 */
914*734Smw145384 			underlying_device = PHYSICAL_DEV;
915*734Smw145384 
916*734Smw145384 			for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
917*734Smw145384 			    tmpmdrec = tmpmdrec->next) {
918*734Smw145384 				if (tmpmdrec->n_key == mdc->un_key) {
919*734Smw145384 					(void) printf(" %s", tmpmdrec->n_name);
920*734Smw145384 					underlying_device = NOT_PHYSICAL_DEV;
921*734Smw145384 					ucomp = Zalloc(sizeof (md_im_list_t));
922*734Smw145384 					ucomp->mdrec = tmpmdrec;
923*734Smw145384 					ucomponent_append(&ucomp_head,
924*734Smw145384 					    &ucomp_tail, ucomp);
925*734Smw145384 				}
926*734Smw145384 			}
927*734Smw145384 			/* if an underlying metadevice was not found */
928*734Smw145384 			if (underlying_device == PHYSICAL_DEV) {
929*734Smw145384 				print_physical_device(phys_nm, mdc->un_key);
930*734Smw145384 			}
931*734Smw145384 			state = meta_get_stripe_state(mdm->ms_state);
932*734Smw145384 
933*734Smw145384 			/*
934*734Smw145384 			 * An underlying hotspare must be a physical device.
935*734Smw145384 			 * If support is ever added for soft-partitions under
936*734Smw145384 			 * hotspare pools, then this code should be updated to
937*734Smw145384 			 * include a search for underlying metadevices.
938*734Smw145384 			 */
939*734Smw145384 			if (mdm->ms_hs_key != 0) {
940*734Smw145384 				for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
941*734Smw145384 				    tmpphys_nm = tmpphys_nm->next) {
942*734Smw145384 					if (tmpphys_nm->n_key ==
943*734Smw145384 					    mdm->ms_hs_key) {
944*734Smw145384 						hsname = tmpphys_nm->n_name;
945*734Smw145384 						break;
946*734Smw145384 					}
947*734Smw145384 				}
948*734Smw145384 			}
949*734Smw145384 			if (state != NULL) {
950*734Smw145384 				if (hsname != NULL) {
951*734Smw145384 					(void) printf(" (%s-%s)", state,
952*734Smw145384 					    hsname);
953*734Smw145384 				} else {
954*734Smw145384 					(void) printf(" (%s)", state);
955*734Smw145384 				}
956*734Smw145384 			} else if (hsname != NULL) {
957*734Smw145384 				(void) printf(gettext(" (spared-%s)"), hsname);
958*734Smw145384 			}
959*734Smw145384 		}
960*734Smw145384 	}
961*734Smw145384 	(void) printf("\n");
962*734Smw145384 
963*734Smw145384 	/* Process underlying metadevices */
964*734Smw145384 	indent += META_INDENT;
965*734Smw145384 	for (ucomp = ucomp_head; ucomp != NULL;
966*734Smw145384 	    ucomp = ucomp->next) {
967*734Smw145384 		ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
968*734Smw145384 		    ucomp->mdrec);
969*734Smw145384 	}
970*734Smw145384 	free_md_im_list_entries(&ucomp_head);
971*734Smw145384 
972*734Smw145384 	/*
973*734Smw145384 	 * Removing the md_entry from the list
974*734Smw145384 	 * of all metadevices
975*734Smw145384 	 */
976*734Smw145384 	free_mdrec_list_entry(&mdrec);
977*734Smw145384 }
978*734Smw145384 
979*734Smw145384 
980*734Smw145384 /*
981*734Smw145384  * process_softpart()
982*734Smw145384  *
983*734Smw145384  * Prints concise unit information for a softpart metadevice and calls the
984*734Smw145384  * respective functions to process the underlying metadevices.
985*734Smw145384  *
986*734Smw145384  */
987*734Smw145384 static void
988*734Smw145384 process_softpart(
989*734Smw145384 	md_im_rec_t	**mdimpp,
990*734Smw145384 	int		indent,
991*734Smw145384 	pnm_rec_t	*phys_nm,
992*734Smw145384 	md_im_rec_t	*mdrec
993*734Smw145384 )
994*734Smw145384 {
995*734Smw145384 	mp_unit_t	*mp;
996*734Smw145384 	mdc_unit_t	uc;
997*734Smw145384 	md_im_rec_t	*tmpmdrec;
998*734Smw145384 	int		underlying_device = PHYSICAL_DEV;
999*734Smw145384 
1000*734Smw145384 	mp =  (mp_unit_t *)mdrec->record;
1001*734Smw145384 	uc = mp->c;
1002*734Smw145384 
1003*734Smw145384 	/* Printing name, size, and type of metadevice */
1004*734Smw145384 	print_concise_entry(indent, mdrec->n_name,
1005*734Smw145384 	    uc.un_total_blocks, 'p');
1006*734Smw145384 
1007*734Smw145384 	/*
1008*734Smw145384 	 * Loops through md_im_rec_t **mdimpp list of all metadevices to find
1009*734Smw145384 	 * record that matches the underlying device.
1010*734Smw145384 	 * Softpartitions can only have one underlying device, so once a
1011*734Smw145384 	 * match is found, we are done.
1012*734Smw145384 	 */
1013*734Smw145384 	for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
1014*734Smw145384 	    tmpmdrec = tmpmdrec->next) {
1015*734Smw145384 		if (tmpmdrec->n_key == mp->un_key) {
1016*734Smw145384 			/* Printing name of the underlying metadevice */
1017*734Smw145384 			(void) printf(" %s", tmpmdrec->n_name);
1018*734Smw145384 			underlying_device = NOT_PHYSICAL_DEV;
1019*734Smw145384 			break;
1020*734Smw145384 		}
1021*734Smw145384 	}
1022*734Smw145384 
1023*734Smw145384 	/* This is only executed if an underlying metadevice was not found */
1024*734Smw145384 	if (underlying_device == PHYSICAL_DEV) {
1025*734Smw145384 		print_physical_device(phys_nm, mp->un_key);
1026*734Smw145384 		(void) printf("\n");
1027*734Smw145384 	} else {
1028*734Smw145384 		/* Process underlying metadevice */
1029*734Smw145384 		(void) printf("\n");
1030*734Smw145384 		indent += META_INDENT;
1031*734Smw145384 		tmpmdrec->dfunc(mdimpp, indent, phys_nm,
1032*734Smw145384 		    tmpmdrec);
1033*734Smw145384 	}
1034*734Smw145384 
1035*734Smw145384 	/*
1036*734Smw145384 	 * Removing the md_entry from the list
1037*734Smw145384 	 * of all metadevices
1038*734Smw145384 	 */
1039*734Smw145384 	free_mdrec_list_entry(&mdrec);
1040*734Smw145384 }
1041*734Smw145384 
1042*734Smw145384 
1043*734Smw145384 /*
1044*734Smw145384  * process_toplevel_softparts()
1045*734Smw145384  *
1046*734Smw145384  * Toplevel softpartions need to be grouped so that their underlying devices
1047*734Smw145384  * can be printed just once.
1048*734Smw145384  */
1049*734Smw145384 static void
1050*734Smw145384 process_toplevel_softparts(
1051*734Smw145384 	md_im_rec_t	**mdimpp,
1052*734Smw145384 	int		indent,
1053*734Smw145384 	pnm_rec_t	*phys_nm
1054*734Smw145384 )
1055*734Smw145384 {
1056*734Smw145384 	mp_unit_t	*mp;
1057*734Smw145384 	mdc_unit_t	uc;
1058*734Smw145384 	md_im_rec_t	*mdrec;
1059*734Smw145384 	md_im_rec_t	*comp_mdrec; /* pntr to underlying component's record */
1060*734Smw145384 	md_im_rec_t	*tmp_mdrec, *rm_mdrec;
1061*734Smw145384 	mp_unit_t	*tmp_mp;
1062*734Smw145384 	int		underlying_device;
1063*734Smw145384 
1064*734Smw145384 	/*
1065*734Smw145384 	 * Loops through md_im_rec_t **mdimpp list of all metadevices to find
1066*734Smw145384 	 * all softpartions that are toplevel softpartitions(softparts w/out
1067*734Smw145384 	 * a parent). Groups output for these entries so that the function to
1068*734Smw145384 	 * process the underlying metadevice is only called once.
1069*734Smw145384 	 */
1070*734Smw145384 	for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) {
1071*734Smw145384 
1072*734Smw145384 		underlying_device = PHYSICAL_DEV;
1073*734Smw145384 		if ((mdrec->md_type == MDDB_F_SOFTPART) &&
1074*734Smw145384 		    (mdrec->has_parent == 0)) {
1075*734Smw145384 			mp =  (mp_unit_t *)mdrec->record;
1076*734Smw145384 			uc = mp->c;
1077*734Smw145384 			/* Printing name, size, and type of metadevice */
1078*734Smw145384 			print_concise_entry(indent, mdrec->n_name,
1079*734Smw145384 			    uc.un_total_blocks, 'p');
1080*734Smw145384 			/*
1081*734Smw145384 			 * Looking for record that matches underlying
1082*734Smw145384 			 * component.
1083*734Smw145384 			 */
1084*734Smw145384 			for (comp_mdrec = *mdimpp; comp_mdrec != NULL;
1085*734Smw145384 			    comp_mdrec = comp_mdrec->next) {
1086*734Smw145384 				if (comp_mdrec->n_key == mp->un_key) {
1087*734Smw145384 					/* Print name of underlying device */
1088*734Smw145384 					(void) printf(" %s",
1089*734Smw145384 					    comp_mdrec->n_name);
1090*734Smw145384 					underlying_device = NOT_PHYSICAL_DEV;
1091*734Smw145384 					break;
1092*734Smw145384 				}
1093*734Smw145384 			}
1094*734Smw145384 			if (underlying_device == PHYSICAL_DEV) {
1095*734Smw145384 				print_physical_device(phys_nm, mp->un_key);
1096*734Smw145384 			}
1097*734Smw145384 			(void) printf("\n");
1098*734Smw145384 
1099*734Smw145384 			/*
1100*734Smw145384 			 * Looking for any other toplevel softpartitions with
1101*734Smw145384 			 * same underlying device. We know that all other
1102*734Smw145384 			 * matching metadevices, that share the same underlying
1103*734Smw145384 			 * metadevice, are also soft-partitions.
1104*734Smw145384 			 */
1105*734Smw145384 			for (tmp_mdrec = mdrec->next; tmp_mdrec != NULL; ) {
1106*734Smw145384 				tmp_mp = (mp_unit_t *)tmp_mdrec->record;
1107*734Smw145384 				if ((tmp_mdrec->has_parent == 0) &&
1108*734Smw145384 				    (tmp_mp->un_key == mp->un_key)) {
1109*734Smw145384 					uc = tmp_mp->c;
1110*734Smw145384 					print_concise_entry(indent,
1111*734Smw145384 					    tmp_mdrec->n_name,
1112*734Smw145384 					    uc.un_total_blocks, 'p');
1113*734Smw145384 					if (underlying_device ==
1114*734Smw145384 					    NOT_PHYSICAL_DEV) {
1115*734Smw145384 						(void) printf(" %s",
1116*734Smw145384 						    comp_mdrec->n_name);
1117*734Smw145384 					} else {
1118*734Smw145384 						print_physical_device(
1119*734Smw145384 						    phys_nm, tmp_mp->un_key);
1120*734Smw145384 					}
1121*734Smw145384 					(void) printf("\n");
1122*734Smw145384 					/*
1123*734Smw145384 					 * Need to advance so that will not lose
1124*734Smw145384 					 * position after removing processed
1125*734Smw145384 					 * record.
1126*734Smw145384 					 */
1127*734Smw145384 					rm_mdrec = tmp_mdrec;
1128*734Smw145384 					tmp_mdrec = tmp_mdrec->next;
1129*734Smw145384 					/*
1130*734Smw145384 					 * Removing the md_entry from the list
1131*734Smw145384 					 * of all metadevices.
1132*734Smw145384 					 */
1133*734Smw145384 					free_mdrec_list_entry(&rm_mdrec);
1134*734Smw145384 				} else {
1135*734Smw145384 					tmp_mdrec = tmp_mdrec->next;
1136*734Smw145384 				}
1137*734Smw145384 			}
1138*734Smw145384 			/* Process the underlying device */
1139*734Smw145384 			if (underlying_device == NOT_PHYSICAL_DEV) {
1140*734Smw145384 				indent += META_INDENT;
1141*734Smw145384 				comp_mdrec->dfunc(mdimpp, indent, phys_nm,
1142*734Smw145384 				    comp_mdrec);
1143*734Smw145384 			}
1144*734Smw145384 		}
1145*734Smw145384 	}
1146*734Smw145384 }
1147*734Smw145384 
1148*734Smw145384 
1149*734Smw145384 /*
1150*734Smw145384  * process_toplevel_devices()
1151*734Smw145384  *
1152*734Smw145384  * Search through list of metadevices for metadevices of md_type that do not
1153*734Smw145384  * have a parent.
1154*734Smw145384  *
1155*734Smw145384  */
1156*734Smw145384 static void
1157*734Smw145384 process_toplevel_devices(
1158*734Smw145384 	md_im_rec_t	**mdimpp,
1159*734Smw145384 	pnm_rec_t	*pnm,
1160*734Smw145384 	uint_t		md_type
1161*734Smw145384 )
1162*734Smw145384 {
1163*734Smw145384 	md_im_rec_t	*mdrec;
1164*734Smw145384 	md_im_list_t	*mdrec_tl_tail = NULL;
1165*734Smw145384 	md_im_list_t	*mdrec_tl_head = NULL;
1166*734Smw145384 	md_im_list_t	*tmp_tl_list = NULL;
1167*734Smw145384 	int		indent = 0;
1168*734Smw145384 
1169*734Smw145384 	indent += META_INDENT;
1170*734Smw145384 
1171*734Smw145384 	/*
1172*734Smw145384 	 * Need to group soft partitions so that common underlying device
1173*734Smw145384 	 * are only processed once.
1174*734Smw145384 	 */
1175*734Smw145384 	if (md_type == MDDB_F_SOFTPART) {
1176*734Smw145384 		process_toplevel_softparts(mdimpp, indent, pnm);
1177*734Smw145384 		return;
1178*734Smw145384 	}
1179*734Smw145384 
1180*734Smw145384 	/*
1181*734Smw145384 	 * Search the list of metadevices to find all metadevices that match
1182*734Smw145384 	 * the type and don't have a parent.  Put them on a separate list
1183*734Smw145384 	 * that will be processed.
1184*734Smw145384 	 */
1185*734Smw145384 	for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) {
1186*734Smw145384 		if ((mdrec->md_type == md_type)&&(mdrec->has_parent == 0)) {
1187*734Smw145384 			tmp_tl_list = Zalloc(sizeof (md_im_list_t));
1188*734Smw145384 			tmp_tl_list->mdrec = mdrec;
1189*734Smw145384 			tmp_tl_list->next = NULL;
1190*734Smw145384 			if (mdrec_tl_tail == NULL) {
1191*734Smw145384 				mdrec_tl_tail = tmp_tl_list;
1192*734Smw145384 				mdrec_tl_head = mdrec_tl_tail;
1193*734Smw145384 			} else {
1194*734Smw145384 				mdrec_tl_tail->next = tmp_tl_list;
1195*734Smw145384 				mdrec_tl_tail = mdrec_tl_tail->next;
1196*734Smw145384 			}
1197*734Smw145384 		}
1198*734Smw145384 
1199*734Smw145384 	}
1200*734Smw145384 
1201*734Smw145384 	/*
1202*734Smw145384 	 * Loop through list and process all top-level metadevices of a
1203*734Smw145384 	 * given type.
1204*734Smw145384 	 */
1205*734Smw145384 	for (tmp_tl_list = mdrec_tl_head; tmp_tl_list != NULL;
1206*734Smw145384 	    tmp_tl_list = tmp_tl_list->next) {
1207*734Smw145384 		tmp_tl_list->mdrec->dfunc(mdimpp, indent, pnm,
1208*734Smw145384 		    tmp_tl_list->mdrec);
1209*734Smw145384 	}
1210*734Smw145384 
1211*734Smw145384 	free_md_im_list_entries(&mdrec_tl_head);
1212*734Smw145384 }
1213*734Smw145384 
1214*734Smw145384 
1215*734Smw145384 /*
1216*734Smw145384  * extract_mduser_data()
1217*734Smw145384  *
1218*734Smw145384  * Converts or copies the (mddb_rb_t->rb_data) metadevice record to a 64bit
1219*734Smw145384  * record.
1220*734Smw145384  * Sets the dfunc field to point to the appropriate function to process the
1221*734Smw145384  * metadevice.
1222*734Smw145384  * Sets the parent field for the metadevice.
1223*734Smw145384  * Extracts the name from the NM namespace if it is available, otherwise
1224*734Smw145384  * generates it from the metadevice's minor number.
1225*734Smw145384  *
1226*734Smw145384  * Returns:
1227*734Smw145384  *	< 0 for failure
1228*734Smw145384  *	  0 for success
1229*734Smw145384  *
1230*734Smw145384  */
1231*734Smw145384 static int
1232*734Smw145384 extract_mduser_data(
1233*734Smw145384 	mddb_rb_t		*nm,
1234*734Smw145384 	md_im_rec_t		*mdrec,
1235*734Smw145384 	void			*rbp,
1236*734Smw145384 	int 			is_32bit_record,
1237*734Smw145384 	md_error_t		*ep
1238*734Smw145384 )
1239*734Smw145384 {
1240*734Smw145384 	mdc_unit_t		uc;
1241*734Smw145384 	hot_spare_t 		*hs;
1242*734Smw145384 	hot_spare_pool_ond_t 	*hsp;
1243*734Smw145384 	size_t			newreqsize;
1244*734Smw145384 	mddb_rb_t		*rbp_nm = nm;
1245*734Smw145384 	struct nm_rec		*nm_record;
1246*734Smw145384 	struct nm_name		*nmname;
1247*734Smw145384 	char 			*uname = NULL;
1248*734Smw145384 
1249*734Smw145384 
1250*734Smw145384 	/*LINTED*/
1251*734Smw145384 	nm_record = (struct nm_rec *)((caddr_t)(&rbp_nm->rb_data));
1252*734Smw145384 
1253*734Smw145384 	/*
1254*734Smw145384 	 * Setting the un_self_id or the hs_self_id, in the case of hotspare
1255*734Smw145384 	 * records, for each metadevice entry. Also setting has_parent and
1256*734Smw145384 	 * setting dfunc so that it points to the correct function to process
1257*734Smw145384 	 * the record type.
1258*734Smw145384 	 * If the record was stored ondisk in 32bit format, then it is
1259*734Smw145384 	 * converted to the 64bits equivalent 64bit format and the memory
1260*734Smw145384 	 * for the 32bit pointer is freed.
1261*734Smw145384 	 */
1262*734Smw145384 	switch (mdrec->md_type) {
1263*734Smw145384 		case MDDB_F_SOFTPART:
1264*734Smw145384 			if (is_32bit_record) {
1265*734Smw145384 				mp_unit32_od_t	*small_un;
1266*734Smw145384 				mp_unit_t	*big_un;
1267*734Smw145384 
1268*734Smw145384 				small_un = (mp_unit32_od_t *)((uintptr_t)rbp +
1269*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1270*734Smw145384 				newreqsize = sizeof (mp_unit_t) +
1271*734Smw145384 				    ((small_un->un_numexts - 1) *
1272*734Smw145384 				    sizeof (struct mp_ext));
1273*734Smw145384 				big_un = (void *)Zalloc(newreqsize);
1274*734Smw145384 				softpart_convert((caddr_t)small_un,
1275*734Smw145384 				    (caddr_t)big_un, SMALL_2_BIG);
1276*734Smw145384 				mdrec->record = (void *)big_un;
1277*734Smw145384 			} else {
1278*734Smw145384 				mp_unit_t	*big_un;
1279*734Smw145384 
1280*734Smw145384 				big_un = (mp_unit_t *)((uintptr_t)rbp +
1281*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1282*734Smw145384 				newreqsize = sizeof (mp_unit_t) +
1283*734Smw145384 				    ((big_un->un_numexts - 1) *
1284*734Smw145384 				    sizeof (struct mp_ext));
1285*734Smw145384 				mdrec->record = (void *)Zalloc(newreqsize);
1286*734Smw145384 				bcopy(big_un, mdrec->record, newreqsize);
1287*734Smw145384 			}
1288*734Smw145384 			uc = ((mp_unit_t *)mdrec->record)->c;
1289*734Smw145384 			mdrec->dfunc = &process_softpart;
1290*734Smw145384 			mdrec->un_self_id = uc.un_self_id;
1291*734Smw145384 			mdrec->has_parent = MD_HAS_PARENT(
1292*734Smw145384 			    uc.un_parent);
1293*734Smw145384 			break;
1294*734Smw145384 		case MDDB_F_STRIPE:
1295*734Smw145384 			if (is_32bit_record) {
1296*734Smw145384 				ms_unit32_od_t	*small_un;
1297*734Smw145384 				ms_unit_t	*big_un;
1298*734Smw145384 
1299*734Smw145384 				small_un = (ms_unit32_od_t *)((uintptr_t)rbp +
1300*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1301*734Smw145384 				newreqsize = get_big_stripe_req_size(
1302*734Smw145384 				    small_un, COMPLETE_STRUCTURE);
1303*734Smw145384 				    big_un = (void *)Zalloc(newreqsize);
1304*734Smw145384 				stripe_convert((caddr_t)small_un,
1305*734Smw145384 				    (caddr_t)big_un, SMALL_2_BIG);
1306*734Smw145384 				mdrec->record = (void *)big_un;
1307*734Smw145384 			} else {
1308*734Smw145384 				ms_unit_t	*big_un;
1309*734Smw145384 
1310*734Smw145384 				big_un = (ms_unit_t *)((uintptr_t)rbp +
1311*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1312*734Smw145384 				newreqsize = get_stripe_req_size(big_un);
1313*734Smw145384 				mdrec->record = (void *)Zalloc(newreqsize);
1314*734Smw145384 				bcopy(big_un, mdrec->record, newreqsize);
1315*734Smw145384 			}
1316*734Smw145384 			uc = ((ms_unit_t *)mdrec->record)->c;
1317*734Smw145384 			mdrec->dfunc = &process_stripe;
1318*734Smw145384 			mdrec->un_self_id = uc.un_self_id;
1319*734Smw145384 			mdrec->has_parent = MD_HAS_PARENT(
1320*734Smw145384 			    uc.un_parent);
1321*734Smw145384 			break;
1322*734Smw145384 		case MDDB_F_MIRROR:
1323*734Smw145384 			if (is_32bit_record) {
1324*734Smw145384 				mm_unit32_od_t	*small_un;
1325*734Smw145384 				mm_unit_t	*big_un;
1326*734Smw145384 
1327*734Smw145384 				small_un = (mm_unit32_od_t *)((uintptr_t)rbp +
1328*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1329*734Smw145384 				newreqsize = sizeof (mm_unit_t);
1330*734Smw145384 				big_un = (void *)Zalloc(newreqsize);
1331*734Smw145384 				mirror_convert((caddr_t)small_un,
1332*734Smw145384 				    (caddr_t)big_un, SMALL_2_BIG);
1333*734Smw145384 				mdrec->record = (void *)big_un;
1334*734Smw145384 			} else {
1335*734Smw145384 				mm_unit_t	*big_un;
1336*734Smw145384 
1337*734Smw145384 				big_un = (mm_unit_t *)((uintptr_t)rbp +
1338*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1339*734Smw145384 				newreqsize = sizeof (mm_unit_t);
1340*734Smw145384 				mdrec->record = (void *)Zalloc(newreqsize);
1341*734Smw145384 				bcopy(big_un, mdrec->record, newreqsize);
1342*734Smw145384 			}
1343*734Smw145384 			uc = ((mm_unit_t *)mdrec->record)->c;
1344*734Smw145384 			mdrec->dfunc = &process_mirror;
1345*734Smw145384 			mdrec->un_self_id = uc.un_self_id;
1346*734Smw145384 			mdrec->has_parent = MD_HAS_PARENT(
1347*734Smw145384 			    uc.un_parent);
1348*734Smw145384 			break;
1349*734Smw145384 		case MDDB_F_RAID:
1350*734Smw145384 			if (is_32bit_record) {
1351*734Smw145384 				mr_unit32_od_t	*small_un;
1352*734Smw145384 				mr_unit_t	*big_un;
1353*734Smw145384 				uint_t		ncol;
1354*734Smw145384 
1355*734Smw145384 				small_un = (mr_unit32_od_t *)((uintptr_t)rbp +
1356*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1357*734Smw145384 				ncol = small_un->un_totalcolumncnt;
1358*734Smw145384 				newreqsize = sizeof (mr_unit_t) +
1359*734Smw145384 				    ((ncol - 1) * sizeof (mr_column_t));
1360*734Smw145384 				big_un = (void *)Zalloc(newreqsize);
1361*734Smw145384 				raid_convert((caddr_t)small_un,
1362*734Smw145384 				    (caddr_t)big_un, SMALL_2_BIG);
1363*734Smw145384 				mdrec->record = (void *)big_un;
1364*734Smw145384 			} else {
1365*734Smw145384 				mr_unit_t	*big_un;
1366*734Smw145384 				uint_t		ncol;
1367*734Smw145384 
1368*734Smw145384 				big_un = (mr_unit_t *)((uintptr_t)rbp +
1369*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1370*734Smw145384 				ncol = big_un->un_totalcolumncnt;
1371*734Smw145384 				newreqsize = sizeof (mr_unit_t) +
1372*734Smw145384 				    ((ncol - 1) * sizeof (mr_column_t));
1373*734Smw145384 				mdrec->record = (void *)Zalloc(newreqsize);
1374*734Smw145384 				bcopy(big_un, mdrec->record, newreqsize);
1375*734Smw145384 			}
1376*734Smw145384 			uc = ((mr_unit_t *)mdrec->record)->c;
1377*734Smw145384 			mdrec->dfunc = &process_raid;
1378*734Smw145384 			mdrec->un_self_id = uc.un_self_id;
1379*734Smw145384 			mdrec->has_parent = MD_HAS_PARENT(
1380*734Smw145384 			    uc.un_parent);
1381*734Smw145384 			break;
1382*734Smw145384 		case MDDB_F_TRANS_MASTER:
1383*734Smw145384 			if (is_32bit_record) {
1384*734Smw145384 				mt_unit32_od_t	*small_un;
1385*734Smw145384 				mt_unit_t	*big_un;
1386*734Smw145384 
1387*734Smw145384 				small_un = (mt_unit32_od_t *)((uintptr_t)rbp +
1388*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1389*734Smw145384 				newreqsize = sizeof (mt_unit_t);
1390*734Smw145384 				big_un = (void *)Zalloc(newreqsize);
1391*734Smw145384 				trans_master_convert((caddr_t)small_un,
1392*734Smw145384 				    (caddr_t)big_un, SMALL_2_BIG);
1393*734Smw145384 				mdrec->record = (void *)big_un;
1394*734Smw145384 			} else {
1395*734Smw145384 				mt_unit_t	*big_un;
1396*734Smw145384 
1397*734Smw145384 				big_un = (mt_unit_t *)((uintptr_t)rbp +
1398*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1399*734Smw145384 				newreqsize = sizeof (mt_unit_t);
1400*734Smw145384 				mdrec->record = (void *)Zalloc(newreqsize);
1401*734Smw145384 				bcopy(big_un, mdrec->record, newreqsize);
1402*734Smw145384 			}
1403*734Smw145384 			uc = ((mt_unit_t *)mdrec->record)->c;
1404*734Smw145384 			mdrec->dfunc = &process_trans;
1405*734Smw145384 			mdrec->un_self_id = uc.un_self_id;
1406*734Smw145384 			mdrec->has_parent = MD_HAS_PARENT(
1407*734Smw145384 			    uc.un_parent);
1408*734Smw145384 			break;
1409*734Smw145384 		case MDDB_F_HOTSPARE:
1410*734Smw145384 			if (is_32bit_record) {
1411*734Smw145384 				hot_spare32_od_t	*small_un;
1412*734Smw145384 				hot_spare_t		*big_un;
1413*734Smw145384 
1414*734Smw145384 				small_un = (hot_spare32_od_t *)((uintptr_t)rbp +
1415*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1416*734Smw145384 				newreqsize = sizeof (hot_spare_t);
1417*734Smw145384 				big_un = (void *)Zalloc(newreqsize);
1418*734Smw145384 				hs_convert((caddr_t)small_un,
1419*734Smw145384 				    (caddr_t)big_un, SMALL_2_BIG);
1420*734Smw145384 				mdrec->record = (void *)big_un;
1421*734Smw145384 			} else {
1422*734Smw145384 				hot_spare_t		*big_un;
1423*734Smw145384 
1424*734Smw145384 				big_un = (hot_spare_t *)((uintptr_t)rbp +
1425*734Smw145384 				    (sizeof (mddb_rb_t) - sizeof (int)));
1426*734Smw145384 				newreqsize = sizeof (hot_spare_t);
1427*734Smw145384 				mdrec->record = (void *)Zalloc(newreqsize);
1428*734Smw145384 				bcopy(big_un, mdrec->record, newreqsize);
1429*734Smw145384 			}
1430*734Smw145384 			hs = (hot_spare_t *)mdrec->record;
1431*734Smw145384 			mdrec->dfunc = &process_hotspare;
1432*734Smw145384 			mdrec->un_self_id = NULL;
1433*734Smw145384 			mdrec->hs_record_id = hs->hs_record_id;
1434*734Smw145384 			mdrec->has_parent = 1;
1435*734Smw145384 			break;
1436*734Smw145384 		case MDDB_F_HOTSPARE_POOL:
1437*734Smw145384 			/*
1438*734Smw145384 			 * Ondisk and incore records are always same size.
1439*734Smw145384 			 * Also, hotspare pools will always be toplevel
1440*734Smw145384 			 * metadevices, so we don't need to store a
1441*734Smw145384 			 * hsp_self_id.
1442*734Smw145384 			 */
1443*734Smw145384 			hsp = (hot_spare_pool_ond_t *)((uintptr_t)rbp +
1444*734Smw145384 			    (sizeof (mddb_rb_t) - sizeof (int)));
1445*734Smw145384 			newreqsize = sizeof (hot_spare_pool_ond_t) +
1446*734Smw145384 			    (sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
1447*734Smw145384 			mdrec->record = (void *)Zalloc(newreqsize);
1448*734Smw145384 			bcopy(hsp, mdrec->record, newreqsize);
1449*734Smw145384 			hsp = (hot_spare_pool_ond_t *)mdrec->record;
1450*734Smw145384 			mdrec->dfunc = &process_hotspare_pool;
1451*734Smw145384 			mdrec->un_self_id = NULL;
1452*734Smw145384 			mdrec->has_parent = 0;
1453*734Smw145384 			break;
1454*734Smw145384 		/* All valid cases have been dealt with */
1455*734Smw145384 		default:
1456*734Smw145384 			(void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1457*734Smw145384 			return (-1);
1458*734Smw145384 	}
1459*734Smw145384 
1460*734Smw145384 	/*
1461*734Smw145384 	 * If metadevice record has an entry in the NM namespace
1462*734Smw145384 	 * then it is copied into the mdrec->n_name field.
1463*734Smw145384 	 */
1464*734Smw145384 	if (mdrec->un_self_id != NULL) {
1465*734Smw145384 		for (nmname = &nm_record->r_name[0]; nmname->n_key != 0;
1466*734Smw145384 		/*LINTED*/
1467*734Smw145384 		    nmname = (struct nm_name *)((char *)nmname +
1468*734Smw145384 		    NAMSIZ(nmname))) {
1469*734Smw145384 			/*
1470*734Smw145384 			 * Matching the un_self_id for the record to the
1471*734Smw145384 			 * n_minor name in the NM record, to extract the
1472*734Smw145384 			 * metadevice name if it is in the namespace
1473*734Smw145384 			 */
1474*734Smw145384 			    if ((nmname->n_minor) == (uc.un_self_id)) {
1475*734Smw145384 				(*mdrec).n_key = nmname->n_key;
1476*734Smw145384 				uname = Strdup(nmname->n_name);
1477*734Smw145384 				mdrec->n_name = uname;
1478*734Smw145384 				break;
1479*734Smw145384 			}
1480*734Smw145384 		}
1481*734Smw145384 	}
1482*734Smw145384 
1483*734Smw145384 	/*
1484*734Smw145384 	 * If the metadevice name is not in the namespace, then
1485*734Smw145384 	 * then we will generate the name from the minor number
1486*734Smw145384 	 * for the metadevice.  In the case of records for a hotspare
1487*734Smw145384 	 * pool we use hsp_self_id, otherwise we use un_self_id.
1488*734Smw145384 	 */
1489*734Smw145384 	if (uname == NULL) {
1490*734Smw145384 		if (mdrec->md_type == MDDB_F_HOTSPARE_POOL) {
1491*734Smw145384 			uname = Malloc(MAXSIZEMDRECNAME);
1492*734Smw145384 			(void) sprintf(uname, "hsp%03u",
1493*734Smw145384 			    HSP_ID(hsp->hsp_self_id));
1494*734Smw145384 			mdrec->n_name = uname;
1495*734Smw145384 		} else if (mdrec->md_type != MDDB_F_HOTSPARE) {
1496*734Smw145384 			/*
1497*734Smw145384 			 * Generate the metadevice name for all other records
1498*734Smw145384 			 * (except for hotspares, because hotspares can only
1499*734Smw145384 			 * be physical devices.)
1500*734Smw145384 			 */
1501*734Smw145384 			uname = Malloc(MAXSIZEMDRECNAME);
1502*734Smw145384 			(void) sprintf(uname, "d%lu",
1503*734Smw145384 			    MD_MIN2UNIT(mdrec->un_self_id));
1504*734Smw145384 			mdrec->n_name = uname;
1505*734Smw145384 		}
1506*734Smw145384 	}
1507*734Smw145384 
1508*734Smw145384 	return (0);
1509*734Smw145384 }
1510*734Smw145384 
1511*734Smw145384 
1512*734Smw145384 /*
1513*734Smw145384  * read_mdrecord()
1514*734Smw145384  *
1515*734Smw145384  * Reads the mddb_rb32_od_t or mddb_rb_t and the associated metadevice record
1516*734Smw145384  * from the disk.  Runs magic, checksum, and revision checks on the record
1517*734Smw145384  * block.
1518*734Smw145384  *
1519*734Smw145384  * Returns:
1520*734Smw145384  *	< 0 for failure
1521*734Smw145384  *	  0 for success
1522*734Smw145384  *
1523*734Smw145384  */
1524*734Smw145384 static int
1525*734Smw145384 read_mdrecord(
1526*734Smw145384 	md_im_rec_t	**mdimpp,
1527*734Smw145384 	mddb_mb_t	*mbp,
1528*734Smw145384 	mddb_rb_t	*nm,
1529*734Smw145384 	mddb_de_t	*dep,
1530*734Smw145384 	char		*diskname,
1531*734Smw145384 	int 		fd,
1532*734Smw145384 	md_timeval32_t	*lastaccess,
1533*734Smw145384 	md_error_t 	*ep
1534*734Smw145384 )
1535*734Smw145384 {
1536*734Smw145384 	int		cnt, rval = 0;
1537*734Smw145384 	daddr_t		pblk;
1538*734Smw145384 	md_im_rec_t	*tmp_mdrec;
1539*734Smw145384 	void 		*rbp = NULL;
1540*734Smw145384 	char 		*rbp_tmp = NULL;
1541*734Smw145384 	mddb_rb32_t	*rbp_32;
1542*734Smw145384 	mddb_rb_t	*rbp_64;
1543*734Smw145384 	crc_skip_t	*skip = NULL;
1544*734Smw145384 	int		is_32bit_record = 0;
1545*734Smw145384 
1546*734Smw145384 	tmp_mdrec = Zalloc(sizeof (md_im_rec_t));
1547*734Smw145384 	rbp = (void *)Zalloc(dbtob(dep->de_blkcount));
1548*734Smw145384 	rbp_tmp = (char *)rbp;
1549*734Smw145384 
1550*734Smw145384 	/* Read in the appropriate record and return configurations */
1551*734Smw145384 	for (cnt = 0; cnt < dep->de_blkcount; cnt++) {
1552*734Smw145384 		if ((pblk = getphysblk(dep->de_blks[cnt], mbp)) < 0) {
1553*734Smw145384 			rval = mdmddberror(ep, MDE_DB_BLKRANGE,
1554*734Smw145384 			    NODEV32, MD_LOCAL_SET,
1555*734Smw145384 			    dep->de_blks[cnt], diskname);
1556*734Smw145384 			return (rval);
1557*734Smw145384 		}
1558*734Smw145384 
1559*734Smw145384 		if (lseek(fd, (off_t)dbtob(pblk), SEEK_SET) < 0) {
1560*734Smw145384 			rval = mdsyserror(ep, errno, diskname);
1561*734Smw145384 			return (rval);
1562*734Smw145384 		}
1563*734Smw145384 
1564*734Smw145384 		if (read(fd, rbp_tmp, DEV_BSIZE) != DEV_BSIZE) {
1565*734Smw145384 			rval = mdsyserror(ep, errno, diskname);
1566*734Smw145384 			return (rval);
1567*734Smw145384 		}
1568*734Smw145384 
1569*734Smw145384 		rbp_tmp += DEV_BSIZE;
1570*734Smw145384 	}
1571*734Smw145384 	tmp_mdrec->md_type = dep->de_flags;
1572*734Smw145384 
1573*734Smw145384 	/*
1574*734Smw145384 	 * The only place to discover whether or not the record is a
1575*734Smw145384 	 * 32bit or 64bit record is from the record's rb_revision field.
1576*734Smw145384 	 * The mddb_rb_t and mddb_rb32_t structures are identical for the
1577*734Smw145384 	 * following fields:
1578*734Smw145384 	 *	rb_magic, rb_revision, rb_checksum, and rb_checksum_fiddle.
1579*734Smw145384 	 * So we can assume that the record is a 32bit structure when we
1580*734Smw145384 	 * check the record's magic number and revision and when we calculate
1581*734Smw145384 	 * the records checksum.
1582*734Smw145384 	 */
1583*734Smw145384 	rbp_32 = (mddb_rb32_t *)rbp;
1584*734Smw145384 
1585*734Smw145384 	/*
1586*734Smw145384 	 * Checking the magic number for the record block.
1587*734Smw145384 	 */
1588*734Smw145384 	if (rbp_32->rb_magic != MDDB_MAGIC_RB) {
1589*734Smw145384 		rval = -1;
1590*734Smw145384 		(void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1591*734Smw145384 		goto out;
1592*734Smw145384 	}
1593*734Smw145384 
1594*734Smw145384 	/*
1595*734Smw145384 	 * Checking the revision for the record block. Must match either
1596*734Smw145384 	 * revision for the current 64bit or 32bit record block.  Also,
1597*734Smw145384 	 * setting the flag for whether or not it is a 32bit record.
1598*734Smw145384 	 */
1599*734Smw145384 	if (revchk(MDDB_REV_RB, rbp_32->rb_revision) == 0) {
1600*734Smw145384 		is_32bit_record = 1;
1601*734Smw145384 	} else if (revchk(MDDB_REV_RB64, rbp_32->rb_revision) != 0) {
1602*734Smw145384 		rval = -1;
1603*734Smw145384 		(void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1604*734Smw145384 		goto out;
1605*734Smw145384 	}
1606*734Smw145384 
1607*734Smw145384 	/*
1608*734Smw145384 	 * Calculating the checksum for this record block. Need
1609*734Smw145384 	 * to skip the rb's checksum fiddle.
1610*734Smw145384 	 */
1611*734Smw145384 	skip = (crc_skip_t *)Malloc(sizeof (crc_skip_t));
1612*734Smw145384 	skip->skip_next = NULL;
1613*734Smw145384 	skip->skip_offset = offsetof(mddb_rb_t, rb_checksum_fiddle);
1614*734Smw145384 	skip->skip_size = 3 * sizeof (uint_t);
1615*734Smw145384 	if (crcchk(rbp_32, &rbp_32->rb_checksum, dep->de_recsize, skip)) {
1616*734Smw145384 		rval = -1;
1617*734Smw145384 		(void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1618*734Smw145384 		goto out;
1619*734Smw145384 	}
1620*734Smw145384 
1621*734Smw145384 	/* mddb_rb_t and mddb_rb32_t differ before the rb_timestamp field */
1622*734Smw145384 	if (!is_32bit_record) {
1623*734Smw145384 		if ((*lastaccess).tv_sec < rbp_32->rb_timestamp.tv_sec) {
1624*734Smw145384 		    *lastaccess = rbp_32->rb_timestamp;
1625*734Smw145384 		} else if ((*lastaccess).tv_sec ==
1626*734Smw145384 		    rbp_32->rb_timestamp.tv_sec) {
1627*734Smw145384 			if ((*lastaccess).tv_usec <
1628*734Smw145384 			    rbp_32->rb_timestamp.tv_usec)
1629*734Smw145384 				*lastaccess = rbp_32->rb_timestamp;
1630*734Smw145384 		}
1631*734Smw145384 	} else {
1632*734Smw145384 		rbp_64 = (mddb_rb_t *)rbp;
1633*734Smw145384 		if ((*lastaccess).tv_sec < rbp_64->rb_timestamp.tv_sec) {
1634*734Smw145384 		    *lastaccess = rbp_64->rb_timestamp;
1635*734Smw145384 		} else if ((*lastaccess).tv_sec ==
1636*734Smw145384 		    rbp_64->rb_timestamp.tv_sec) {
1637*734Smw145384 			if ((*lastaccess).tv_usec <
1638*734Smw145384 			    rbp_64->rb_timestamp.tv_usec)
1639*734Smw145384 				*lastaccess = rbp_64->rb_timestamp;
1640*734Smw145384 		}
1641*734Smw145384 	}
1642*734Smw145384 
1643*734Smw145384 	/* Populates the fields in md_im_rec_t *tmp_mdrec. */
1644*734Smw145384 	rval = extract_mduser_data(nm, tmp_mdrec, rbp, is_32bit_record, ep);
1645*734Smw145384 	if (rval < 0)
1646*734Smw145384 		goto out;
1647*734Smw145384 
1648*734Smw145384 	/* Adding record to the head of the list of all metadevices. */
1649*734Smw145384 	tmp_mdrec->prev = NULL;
1650*734Smw145384 	if (*mdimpp == NULL) {
1651*734Smw145384 		tmp_mdrec->next = NULL;
1652*734Smw145384 		*mdimpp = tmp_mdrec;
1653*734Smw145384 	} else {
1654*734Smw145384 		(*mdimpp)->prev = tmp_mdrec;
1655*734Smw145384 		tmp_mdrec->next = *mdimpp;
1656*734Smw145384 		*mdimpp = tmp_mdrec;
1657*734Smw145384 	}
1658*734Smw145384 
1659*734Smw145384 out:
1660*734Smw145384 	/* Free the skip list */
1661*734Smw145384 	while (skip) {
1662*734Smw145384 		crc_skip_t	*skip_rm = skip;
1663*734Smw145384 
1664*734Smw145384 		skip = skip->skip_next;
1665*734Smw145384 		Free(skip_rm);
1666*734Smw145384 	}
1667*734Smw145384 
1668*734Smw145384 	if (rbp)
1669*734Smw145384 		Free(rbp);
1670*734Smw145384 
1671*734Smw145384 	return (rval);
1672*734Smw145384 }
1673*734Smw145384 
1674*734Smw145384 
1675*734Smw145384 /*
1676*734Smw145384  * read_all_mdrecords()
1677*734Smw145384  *
1678*734Smw145384  * Reads the directory block and directory entries.
1679*734Smw145384  * Runs magic, checksum, and revision checks on the directory block.
1680*734Smw145384  *
1681*734Smw145384  * Returns:
1682*734Smw145384  *	< 0 for failure
1683*734Smw145384  *	  0 for success
1684*734Smw145384  */
1685*734Smw145384 static int
1686*734Smw145384 read_all_mdrecords(
1687*734Smw145384 	md_im_rec_t	**mdimpp,
1688*734Smw145384 	mddb_mb_t	*mbp,
1689*734Smw145384 	mddb_lb_t	*lbp,
1690*734Smw145384 	mddb_rb_t	*nm,
1691*734Smw145384 	mdname_t	*rsp,
1692*734Smw145384 	int 		fd,
1693*734Smw145384 	md_timeval32_t	*lastaccess,
1694*734Smw145384 	md_error_t 	*ep
1695*734Smw145384 )
1696*734Smw145384 {
1697*734Smw145384 	int		dbblk, rval = 0;
1698*734Smw145384 	char		db[DEV_BSIZE];
1699*734Smw145384 	mddb_de_t	*dep;
1700*734Smw145384 	int		desize;
1701*734Smw145384 	/*LINTED*/
1702*734Smw145384 	mddb_db_t	*dbp = (mddb_db_t *)&db;
1703*734Smw145384 
1704*734Smw145384 	/* Read in all directory blocks */
1705*734Smw145384 	for (dbblk = lbp->lb_dbfirstblk;
1706*734Smw145384 	    dbblk != 0;
1707*734Smw145384 	    dbblk = dbp->db_nextblk) {
1708*734Smw145384 
1709*734Smw145384 		if ((rval = read_database_block(ep, fd, mbp, dbblk,
1710*734Smw145384 		    dbp, sizeof (db))) <= 0)
1711*734Smw145384 			goto out;
1712*734Smw145384 
1713*734Smw145384 		/*
1714*734Smw145384 		 * Set ep with error code for MDE_DB_NODB.  This is the
1715*734Smw145384 		 * error code used in the kernel when there is a problem
1716*734Smw145384 		 * with reading records in.  Checks the magic number, the
1717*734Smw145384 		 * revision, and the checksum for each directory block.
1718*734Smw145384 		 */
1719*734Smw145384 		if (dbp->db_magic != MDDB_MAGIC_DB) {
1720*734Smw145384 			rval = -1;
1721*734Smw145384 			(void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1722*734Smw145384 			goto out;
1723*734Smw145384 		}
1724*734Smw145384 
1725*734Smw145384 		if (revchk(MDDB_REV_DB, dbp->db_revision)) {
1726*734Smw145384 			rval = -1;
1727*734Smw145384 			(void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1728*734Smw145384 			goto out;
1729*734Smw145384 		}
1730*734Smw145384 
1731*734Smw145384 		if (crcchk(dbp, &dbp->db_checksum, MDDB_BSIZE, NULL)) {
1732*734Smw145384 			rval = -1;
1733*734Smw145384 			(void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1734*734Smw145384 			goto out;
1735*734Smw145384 		}
1736*734Smw145384 
1737*734Smw145384 		/*
1738*734Smw145384 		 * If db timestamp is more recent than the previously recorded
1739*734Smw145384 		 * last modified timestamp, then update last modified.
1740*734Smw145384 		 */
1741*734Smw145384 		if ((*lastaccess).tv_sec < dbp->db_timestamp.tv_sec) {
1742*734Smw145384 			*lastaccess = dbp->db_timestamp;
1743*734Smw145384 		} else if ((*lastaccess).tv_sec == dbp->db_timestamp.tv_sec) {
1744*734Smw145384 			if ((*lastaccess).tv_usec < dbp->db_timestamp.tv_usec)
1745*734Smw145384 				*lastaccess = dbp->db_timestamp;
1746*734Smw145384 		}
1747*734Smw145384 
1748*734Smw145384 		/* Creates dep list of all directory entries in the db */
1749*734Smw145384 		if (dbp->db_firstentry != NULL) {
1750*734Smw145384 			/* LINTED */
1751*734Smw145384 			dep = (mddb_de_t *)((caddr_t)(&dbp->db_firstentry)
1752*734Smw145384 			    + sizeof (dbp->db_firstentry));
1753*734Smw145384 			dbp->db_firstentry = dep;
1754*734Smw145384 			while (dep && dep->de_next) {
1755*734Smw145384 				desize = sizeof (*dep) -
1756*734Smw145384 				    sizeof (dep->de_blks) +
1757*734Smw145384 				    sizeof (daddr_t) * dep->de_blkcount;
1758*734Smw145384 				/* LINTED */
1759*734Smw145384 				dep->de_next = (mddb_de_t *)
1760*734Smw145384 				    ((caddr_t)dep + desize);
1761*734Smw145384 				dep = dep->de_next;
1762*734Smw145384 			}
1763*734Smw145384 		}
1764*734Smw145384 
1765*734Smw145384 		/*
1766*734Smw145384 		 * Process all directory entries in the directory block.
1767*734Smw145384 		 * For each directory entry, read_mdrec is called to read
1768*734Smw145384 		 * in the record data.
1769*734Smw145384 		 */
1770*734Smw145384 		for (dep = dbp->db_firstentry; dep != NULL;
1771*734Smw145384 		    dep = dep->de_next) {
1772*734Smw145384 
1773*734Smw145384 			/*
1774*734Smw145384 			 * de_flags is set to the type of metadevice.
1775*734Smw145384 			 * If directory entry does not correspond to a
1776*734Smw145384 			 * specific metadevice then it is set to zero.
1777*734Smw145384 			 * All namespace records(NM, SHR_NM, DID_SHR_NM) have a
1778*734Smw145384 			 * value of zero in their de_flags field.
1779*734Smw145384 			 */
1780*734Smw145384 			if ((dep->de_flags != 0)&&
1781*734Smw145384 			    (dep->de_flags != MDDB_F_OPT) &&
1782*734Smw145384 			    (dep->de_flags != MDDB_F_TRANS_LOG) &&
1783*734Smw145384 			    (dep->de_flags != MDDB_F_CHANGELOG)) {
1784*734Smw145384 				rval = read_mdrecord(mdimpp, mbp, nm, dep,
1785*734Smw145384 				    rsp->cname, fd, lastaccess, ep);
1786*734Smw145384 				if (rval < 0)
1787*734Smw145384 					goto out;
1788*734Smw145384 			}
1789*734Smw145384 		}
1790*734Smw145384 	}
1791*734Smw145384 
1792*734Smw145384 out:
1793*734Smw145384 	return (rval);
1794*734Smw145384 }
1795*734Smw145384 
1796*734Smw145384 
1797*734Smw145384 /*
1798*734Smw145384  * report_metastat_info()
1799*734Smw145384  *
1800*734Smw145384  * Generates the metastat -c output.  Also, updates the global variable
1801*734Smw145384  * for a last accessed timestamp.
1802*734Smw145384  *
1803*734Smw145384  * Returns:
1804*734Smw145384  *	< 0 for failure
1805*734Smw145384  *	  0 for success
1806*734Smw145384  *
1807*734Smw145384  */
1808*734Smw145384 int
1809*734Smw145384 report_metastat_info(
1810*734Smw145384 	mddb_mb_t		*mb,
1811*734Smw145384 	mddb_lb_t		*lbp,
1812*734Smw145384 	mddb_rb_t		*nm,
1813*734Smw145384 	pnm_rec_t		**pnm,
1814*734Smw145384 	mdname_t		*rsp,
1815*734Smw145384 	int			fd,
1816*734Smw145384 	md_timeval32_t		*lastaccess,
1817*734Smw145384 	md_error_t		*ep
1818*734Smw145384 )
1819*734Smw145384 {
1820*734Smw145384 	int rval = 0;
1821*734Smw145384 	/* list of all metadevices in diskset */
1822*734Smw145384 	md_im_rec_t	*mdimp = NULL;
1823*734Smw145384 	md_im_rec_t	*tmp_mdrec, *rm_mdrec;
1824*734Smw145384 
1825*734Smw145384 	/* Read in metadevice records and add entries to mdimp list. */
1826*734Smw145384 	rval = read_all_mdrecords(&mdimp, mb, lbp, nm, rsp, fd, lastaccess,
1827*734Smw145384 	    ep);
1828*734Smw145384 	if (rval < 0)
1829*734Smw145384 		goto out;
1830*734Smw145384 
1831*734Smw145384 	/* Adding a fake record to the head of the list of all metadevices. */
1832*734Smw145384 	if (mdimp != NULL) {
1833*734Smw145384 		tmp_mdrec = Zalloc(sizeof (md_im_rec_t));
1834*734Smw145384 		tmp_mdrec->prev = NULL;
1835*734Smw145384 		mdimp->prev = tmp_mdrec;
1836*734Smw145384 		tmp_mdrec->next = mdimp;
1837*734Smw145384 		mdimp = tmp_mdrec;
1838*734Smw145384 	}
1839*734Smw145384 
1840*734Smw145384 	/* Calling functions to process all metadevices on mdimp list */
1841*734Smw145384 	process_toplevel_devices(&mdimp, *pnm, MDDB_F_SOFTPART);
1842*734Smw145384 	process_toplevel_devices(&mdimp, *pnm, MDDB_F_TRANS_MASTER);
1843*734Smw145384 	process_toplevel_devices(&mdimp, *pnm, MDDB_F_MIRROR);
1844*734Smw145384 	process_toplevel_devices(&mdimp, *pnm, MDDB_F_RAID);
1845*734Smw145384 	process_toplevel_devices(&mdimp, *pnm, MDDB_F_STRIPE);
1846*734Smw145384 	process_toplevel_devices(&mdimp, *pnm, MDDB_F_HOTSPARE_POOL);
1847*734Smw145384 	(void) printf("\n");
1848*734Smw145384 
1849*734Smw145384 out:
1850*734Smw145384 	/*
1851*734Smw145384 	 * If mdreclist is not null, then this will walk through all
1852*734Smw145384 	 * elements and free them.
1853*734Smw145384 	 */
1854*734Smw145384 	tmp_mdrec = mdimp;
1855*734Smw145384 	while (tmp_mdrec != NULL) {
1856*734Smw145384 		rm_mdrec = tmp_mdrec;
1857*734Smw145384 		tmp_mdrec = tmp_mdrec->next;
1858*734Smw145384 		if (rm_mdrec->record != NULL)
1859*734Smw145384 			Free(rm_mdrec->record);
1860*734Smw145384 		if (rm_mdrec->n_name != NULL)
1861*734Smw145384 			Free(rm_mdrec->n_name);
1862*734Smw145384 		Free(rm_mdrec);
1863*734Smw145384 	}
1864*734Smw145384 
1865*734Smw145384 	free_pnm_rec_list(pnm);
1866*734Smw145384 	return (rval);
1867*734Smw145384 }
1868