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