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