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 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27#include <stdio.h>
28#include <errno.h>
29#include <unistd.h>
30#include <string.h>
31
32#include <meta.h>
33#include <sys/lvm/md_mddb.h>
34#include <sdssc.h>
35
36/*
37 * print metadevice status
38 */
39
40
41#define	MD_PROBE_OPEN_T "probe open test"
42
43/* used to keep track of the softparts on the same underlying device */
44struct sp_base_list {
45	struct sp_base_list	*next;
46	char			*base;
47};
48
49/*
50 * Function prototypes
51 */
52static void probe_all_devs(mdsetname_t *sp);
53
54static int print_devid(mdsetname_t *sp, mdnamelist_t *nlp, FILE *fp,
55    md_error_t   *ep);
56
57static md_common_t	*get_concise_unit(mdsetname_t *sp, mdname_t *np,
58			    md_error_t *ep);
59static void	print_all_sets(mdprtopts_t options, int concise_flag,
60		    int quiet_flg);
61static void	print_specific_set(mdsetname_t *sp, mdprtopts_t options,
62		    int concise_flag, int quiet_flg);
63static void	print_concise_diskset(mdsetname_t *sp);
64static void	print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl,
65		    char mtype);
66static void	print_concise_md(int indent, mdsetname_t *sp, mdname_t *np);
67static void	print_concise_mirror(int indent, mdsetname_t *sp,
68		    md_mirror_t *mirror);
69static void	print_concise_raid(int indent, mdsetname_t *sp,
70		    md_raid_t *raid);
71static void	print_concise_stripe(int indent, mdsetname_t *sp,
72		    md_stripe_t *stripe);
73static void	print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part);
74static void	print_concise_trans(int indent, mdsetname_t *sp,
75		    md_trans_t *trans);
76static void	free_names(mdnamelist_t **nlp);
77static char	*get_sm_state(md_mirror_t *mirror, int i,
78		    md_status_t mirror_status, uint_t tstate);
79static char	*get_raid_col_state(md_raidcol_t *colp, uint_t tstate);
80static char	*get_stripe_state(md_comp_t *mdcp, uint_t tstate);
81static char	*get_hs_state(md_hs_t *hsp);
82static struct sp_base_list *sp_add_done(md_sp_t *part, struct sp_base_list *lp);
83static int	sp_done(md_sp_t *part, struct sp_base_list *lp);
84static int	sp_match(md_sp_t *part, struct sp_base_list *lp);
85static void	sp_free_list(struct sp_base_list *lp);
86
87
88/*
89 * print named hotspare pool or metadevice
90 */
91static int
92print_name(
93	mdsetname_t	**spp,
94	char		*uname,
95	mdnamelist_t	**nlistpp,
96	char		*fname,
97	FILE		*fp,
98	mdprtopts_t	options,
99	int		*meta_print_trans_msgp,
100	mdnamelist_t	**lognlpp,
101	md_error_t	*ep
102)
103{
104	mdname_t	*namep;
105	char		*miscname;
106
107	/* recurse */
108	options |= PRINT_SUBDEVS;
109
110	/* hotspare pool */
111	if (is_existing_hsp(*spp, uname)) {
112		mdhspname_t	*hspnamep;
113
114		/* get hotsparepool */
115		if ((hspnamep = metahspname(spp, uname, ep)) == NULL)
116			return (-1);
117
118		/* check for ownership */
119		assert(*spp != NULL);
120		if (meta_check_ownership(*spp, ep) != 0)
121			return (-1);
122
123		/* print hotspare pool */
124		return (meta_hsp_print(*spp, hspnamep, lognlpp, fname, fp,
125		    options, ep));
126	}
127
128	/* get metadevice */
129	if (((namep = metaname(spp, uname, META_DEVICE, ep)) == NULL) ||
130	    (metachkmeta(namep, ep) != 0))
131		return (-1);
132
133	/* check for ownership */
134	assert(*spp != NULL);
135	if (meta_check_ownership(*spp, ep) != 0)
136		return (-1);
137
138	if ((miscname = metagetmiscname(namep, ep)) != NULL) {
139		if (strcmp(miscname, MD_TRANS) == 0) {
140			*meta_print_trans_msgp = 1;
141		}
142	}
143
144	/* print metadevice */
145	return (meta_print_name(*spp, namep, nlistpp, fname, fp, options,
146	    lognlpp, ep));
147}
148
149/*
150 * print the per set flags
151 */
152/*ARGSUSED*/
153static int
154print_setstat(
155	mdsetname_t		**spp,
156	char			*fname,
157	FILE			*fp,
158	mdprtopts_t		options,
159	md_error_t		*ep
160)
161{
162	int			rval = -1;
163	char			*cname = NULL;
164	char			*cp = NULL;
165	md_gs_stat_parm_t	gsp;
166
167
168	if (fname != NULL && strchr(fname, '/') != NULL) {
169		/* get the canonical name */
170		cname = meta_name_getname(spp, fname, META_DEVICE, ep);
171		if (cname == NULL)
172			return (-1);
173		Free(cname);
174	}
175
176	if ((cp = getenv("MD_DEBUG")) == NULL)
177		return (0);
178
179	if (strstr(cp, "SETINFO") == NULL)
180		return (0);
181
182	(void) memset(&gsp, '\0', sizeof (md_gs_stat_parm_t));
183	gsp.gs_setno = (*spp)->setno;
184
185	if (metaioctl(MD_GET_SETSTAT, &gsp, &gsp.gs_mde, NULL) != 0)
186		return (mdstealerror(ep, &gsp.gs_mde));
187
188	if (fprintf(fp, "Status for set %d = ", gsp.gs_setno) == EOF)
189		goto out;
190
191	if (meta_prbits(fp, NULL, gsp.gs_status, MD_SET_STAT_BITS) == EOF)
192		goto out;
193
194
195	if (fprintf(fp, "\n") == EOF)
196		goto out;
197
198	/* success */
199	rval = 0;
200
201	/* cleanup, return error */
202out:
203	if (rval != 0)
204		(void) mdsyserror(ep, errno, fname);
205
206	return (rval);
207}
208
209/*
210 * check_replica_state:
211 * 	If the replica state is stale or the set has been halted
212 * 	this routine returns an error.
213 */
214static int
215check_replica_state(mdsetname_t *sp, md_error_t *ep)
216{
217	mddb_config_t	c;
218
219	(void) memset(&c, 0, sizeof (c));
220	c.c_id = 0;
221	c.c_setno = sp->setno;
222
223	if (metaioctl(MD_DB_GETDEV, &c, &c.c_mde, NULL) != 0) {
224		if (mdismddberror(&c.c_mde, MDE_DB_INVALID))
225			(void) mdstealerror(ep, &c.c_mde);
226		return (-1);
227	}
228
229	if (c.c_flags & MDDB_C_STALE) {
230		return (mdmddberror(ep, MDE_DB_STALE, NODEV32, sp->setno,
231		    0, NULL));
232	} else
233		return (0);
234}
235
236static void
237print_trans_msg(mdprtopts_t	options, int	meta_print_trans_msg)
238{
239	if (meta_print_trans_msg != 0) {
240		(void) fprintf(stderr, "\n\n");
241		if (options & PRINT_SHORT) {
242			(void) fprintf(stderr, gettext(MD_SHORT_EOF_TRANS_MSG));
243			(void) fprintf(stderr,
244			    gettext(MD_SHORT_EOF_TRANS_WARNING));
245		} else {
246			(void) fprintf(stderr, gettext(MD_EOF_TRANS_MSG));
247			(void) fprintf(stderr, gettext(MD_EOF_TRANS_WARNING));
248		}
249	}
250}
251
252/*
253 * print usage message
254 *
255 */
256static void
257usage(
258	mdsetname_t	*sp,
259	int		eval
260)
261{
262	(void) fprintf(stderr, gettext("\
263usage:	%s [-s setname] [-a][-c][-B][-D][-r][-i][-p] [-t] [metadevice...]\n"),
264	    myname);
265	md_exit(sp, eval);
266}
267
268/*
269 * mainline. crack command line arguments.
270 */
271int
272main(
273	int	argc,
274	char	*argv[]
275)
276{
277	char		*sname = MD_LOCAL_NAME;
278	mdsetname_t	*sp = NULL;
279	mdprtopts_t	options = PRINT_HEADER | PRINT_DEVID | PRINT_FAST;
280	int		c;
281	char		*p;
282	md_error_t	status = mdnullerror;
283	md_error_t	*ep = &status;
284	int		eval = 0;
285	int		inquire = 0;
286	int		quiet_flg = 0;
287	int		set_flg = 0;
288	int		error;
289	int		all_sets_flag = 0;
290	int		concise_flag = 0;
291	mdnamelist_t	*nlistp = NULL;
292	mdname_t		*namep;
293	int		devcnt = 0;
294	mdnamelist_t	*lognlp = NULL;
295	uint_t hsi;
296	int		meta_print_trans_msg = 0;
297
298	/*
299	 * Get the locale set up before calling any other routines
300	 * with messages to ouput.  Just in case we're not in a build
301	 * environment, make sure that TEXT_DOMAIN gets set to
302	 * something.
303	 */
304#if !defined(TEXT_DOMAIN)
305#define	TEXT_DOMAIN "SYS_TEST"
306#endif
307	(void) setlocale(LC_ALL, "");
308	(void) textdomain(TEXT_DOMAIN);
309
310	if (sdssc_bind_library() == SDSSC_OKAY)
311		if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
312		    &error) == SDSSC_PROXY_DONE)
313			exit(error);
314
315	/* initialize */
316	if (md_init(argc, argv, 0, 1, ep) != 0) {
317		mde_perror(ep, "");
318		md_exit(sp, 1);
319	}
320
321	/* parse arguments */
322	optind = 1;
323	opterr = 1;
324	while ((c = getopt(argc, argv, "acSs:hpBDrtiq?")) != -1) {
325		switch (c) {
326		case 'a':
327			all_sets_flag++;
328			break;
329
330		case 'c':
331			concise_flag++;
332			quiet_flg++;
333			break;
334
335		case 'S':
336			options |= PRINT_SETSTAT_ONLY;
337			break;
338
339		case 's':
340			sname = optarg;
341			set_flg++;
342			break;
343
344		case 'h':
345			usage(sp, 0);
346			break;
347
348		case 'p':
349			options |= PRINT_SHORT;
350			options &= ~PRINT_DEVID;
351			break;
352
353		case 't':
354			options |= PRINT_TIMES;
355			break;
356
357		case 'i':
358			inquire++;
359			break;
360
361		case 'B':
362			options |= PRINT_LARGEDEVICES;
363			break;
364		case 'D':
365			options |= PRINT_FN;
366			break;
367		case 'r':		/* defunct option */
368			break;
369		case 'q':
370			quiet_flg++;
371			break;
372		case '?':
373			if (optopt == '?')
374				usage(sp, 0);
375			/*FALLTHROUGH*/
376		default:
377			usage(sp, 1);
378			break;
379		}
380	}
381	argc -= optind;
382	argv += optind;
383
384	if (all_sets_flag && set_flg) {
385		(void) fprintf(stderr, gettext("metastat: "
386		    "incompatible options: -a and -s\n"));
387		usage(sp, 1);
388	}
389
390	/* get set context */
391	if ((sp = metasetname(sname, ep)) == NULL) {
392		mde_perror(ep, "");
393		md_exit(sp, 1);
394	}
395
396	/* make sure that the mddb is not stale. Else print a warning */
397
398	if (check_replica_state(sp, ep)) {
399		if (mdismddberror(ep, MDE_DB_STALE)) {
400			(void) fprintf(stdout, gettext(
401			    "****\nWARNING: Stale "
402			    "state database replicas. Metastat output "
403			    "may be inaccurate.\n****\n\n"));
404		}
405	}
406
407	/* if inquire is set. We probe first */
408	if (inquire) {
409		if (geteuid() != 0) {
410			(void) fprintf(stderr, gettext("metastat: -i "
411			    "option requires super-user privilages\n"));
412			md_exit(sp, 1);
413		}
414		probe_all_devs(sp);
415	}
416	/* print debug stuff */
417	if (((p = getenv("MD_DEBUG")) != NULL) &&
418	    (strstr(p, "STAT") != NULL)) {
419		options |= (PRINT_SETSTAT | PRINT_DEBUG | PRINT_TIMES);
420	}
421
422	if ((options & PRINT_SETSTAT) || (options & PRINT_SETSTAT_ONLY)) {
423		if (print_setstat(&sp, argv[0], stdout, options, ep)) {
424			mde_perror(ep, "");
425			md_exit(sp, 1);
426		}
427		if (options & PRINT_SETSTAT_ONLY)
428			md_exit(sp, 0);
429	}
430
431	/* status all devices */
432	if (argc == 0) {
433		if (all_sets_flag) {
434			print_all_sets(options, concise_flag, quiet_flg);
435		} else {
436			print_specific_set(sp, options, concise_flag,
437			    quiet_flg);
438		}
439
440		if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
441			mde_perror(ep, "");
442			md_exit(sp, 1);
443		}
444
445		/* success */
446		md_exit(sp, 0);
447	}
448	/* print named device types */
449	while (devcnt < argc) {
450		char	*uname = argv[devcnt];
451		char	*cname = NULL;
452
453		/* get the canonical name */
454		cname = meta_name_getname(&sp, uname, META_DEVICE, ep);
455		if (cname == NULL) {
456			/* already printed the error */
457			mdclrerror(ep);
458			eval = 1;
459			++devcnt;
460			continue;
461		}
462
463		if (concise_flag) {
464			mdname_t *np;
465
466			np = metaname(&sp, cname, META_DEVICE, ep);
467			if (np == NULL) {
468				mde_perror(ep, "");
469				mdclrerror(ep);
470				eval = 1;
471			} else {
472				print_concise_md(0, sp, np);
473			}
474
475		} else {
476			if (print_name(&sp, cname, &nlistp, NULL, stdout,
477			    options, &meta_print_trans_msg, &lognlp, ep) != 0) {
478				mde_perror(ep, "");
479				mdclrerror(ep);
480				eval = 1;
481			}
482		}
483		Free(cname);
484		++devcnt;
485	}
486
487	/* print metadevice & relocation device id */
488	if ((options & PRINT_DEVID) && (eval != 1) && !quiet_flg) {
489		devcnt = 0;
490
491		while (devcnt < argc) {
492			char	*uname = argv[devcnt];
493			char	*cname = NULL;
494
495			/* get the canonical name */
496			cname = meta_name_getname(&sp, uname, META_DEVICE, ep);
497			if (cname == NULL) {
498				mde_perror(ep, "");
499				mdclrerror(ep);
500				++devcnt;
501				continue;
502			}
503
504			/* hotspare pools */
505			if (is_existing_hsp(sp, cname)) {
506				mdhspname_t	*hspnamep;
507				md_hsp_t	*hsp;
508
509				/* get hotsparepool */
510				if ((hspnamep = metahspname(&sp, cname,
511				    ep)) == NULL)
512					eval = 1;
513
514				if ((hsp = meta_get_hsp(sp, hspnamep,
515				    ep)) == NULL)
516					eval = 1;
517
518				for (hsi = 0;
519				    hsi < hsp->hotspares.hotspares_len;
520				    hsi++) {
521
522					namep = hsp->hotspares.
523					    hotspares_val[hsi].hsnamep;
524
525					if (!(options &
526					    (PRINT_LARGEDEVICES | PRINT_FN))) {
527						/* meta_getdevs populates the */
528						/* nlistp structure for use   */
529						if (meta_getdevs(sp, namep,
530						    &nlistp, ep) != 0)
531							eval =  1;
532					}
533
534				}
535
536			} else {
537
538				/* get metadevice */
539				if (((namep = metaname(&sp, cname,
540				    META_DEVICE, ep)) == NULL) ||
541				    (metachkmeta(namep, ep) != 0))
542					eval = 1;
543
544				if (!(options &
545				    (PRINT_LARGEDEVICES | PRINT_FN))) {
546					/* meta_getdevs populates the	*/
547					/* nlistp structure for use 	*/
548					if (meta_getdevs(sp, namep, &nlistp, ep)
549					    != 0)
550						eval =  1;
551				}
552			}
553			Free(cname);
554			++devcnt;
555		}
556		if (print_devid(sp, nlistp, stdout, ep) != 0)
557			eval =  1;
558
559
560	}
561
562	print_trans_msg(options, meta_print_trans_msg);
563
564	if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
565		mde_perror(ep, "");
566		md_exit(sp, 1);
567	}
568
569	/* return success */
570	md_exit(sp, eval);
571	/*NOTREACHED*/
572	return (eval);
573}
574
575static void
576print_all_sets(mdprtopts_t options, int concise_flag, int quiet_flg)
577{
578	uint_t		max_sets;
579	md_error_t	error = mdnullerror;
580	int		i;
581
582	if ((max_sets = get_max_sets(&error)) == 0) {
583		return;
584	}
585
586	if (!mdisok(&error)) {
587		mdclrerror(&error);
588		return;
589	}
590
591	/* for each possible set number, see if we really have a diskset */
592	for (i = 0; i < max_sets; i++) {
593		mdsetname_t		*sp;
594
595		if ((sp = metasetnosetname(i, &error)) == NULL) {
596			if (!mdisok(&error) &&
597			    mdisrpcerror(&error, RPC_PROGNOTREGISTERED)) {
598			/* metad rpc program not registered - no metasets */
599				break;
600			}
601
602			mdclrerror(&error);
603			continue;
604		}
605		mdclrerror(&error);
606
607		if (meta_check_ownership(sp, &error) == 0) {
608			/* we own the set, so we can print the metadevices */
609			print_specific_set(sp, options, concise_flag,
610			    quiet_flg);
611			(void) printf("\n");
612		}
613
614		metaflushsetname(sp);
615	}
616}
617
618static void
619print_specific_set(mdsetname_t *sp, mdprtopts_t options, int concise_flag,
620	int quiet_flg)
621{
622	md_error_t	status = mdnullerror;
623	md_error_t	*ep = &status;
624	int		meta_print_trans_msg = 0;
625
626	/* check for ownership */
627	assert(sp != NULL);
628	if (meta_check_ownership(sp, ep) != 0) {
629		mde_perror(ep, "");
630		md_exit(sp, 1);
631	}
632
633	if (concise_flag) {
634		print_concise_diskset(sp);
635
636	} else {
637		mdnamelist_t	*nlistp = NULL;
638
639		/* status devices */
640		if (meta_print_all(sp, NULL, &nlistp, stdout, options,
641		    &meta_print_trans_msg, ep) != 0) {
642			mde_perror(ep, "");
643			md_exit(sp, 1);
644		}
645
646		/* print relocation device id on all dev's */
647		if ((options & PRINT_DEVID) && !quiet_flg) {
648			/*
649			 * Ignore return value from meta_getalldevs since
650			 * it will return a failure if even one device cannot
651			 * be found - which could occur in the case of device
652			 * failure or a device being powered off during
653			 * upgrade.  Even if meta_getalldevs fails, the
654			 * data in nlistp is still valid.
655			 */
656			if (!(options & (PRINT_LARGEDEVICES | PRINT_FN))) {
657				(void) meta_getalldevs(sp, &nlistp, 0, ep);
658			}
659			if (nlistp != NULL) {
660				if (print_devid(sp, nlistp, stdout, ep) != 0) {
661					mde_perror(ep, "");
662					md_exit(sp, 1);
663				}
664			}
665		}
666	}
667
668	print_trans_msg(options, meta_print_trans_msg);
669}
670
671/*
672 * print_devid prints out cxtxdx and devid for devices passed in a
673 * mdnamelist_t structure
674 */
675static int
676print_devid(
677	mdsetname_t  *sp,
678	mdnamelist_t *nlp,
679	FILE		 *fp,
680	md_error_t   *ep
681)
682{
683	int 			retval = 0;
684	mdnamelist_t		*onlp = NULL;
685	mddevid_t 		*ldevidp = NULL;
686	mddevid_t		*nextp;
687
688	/* make a non-duplicate list of nlp */
689	for (onlp = nlp; (onlp != NULL); onlp = onlp->next) {
690		meta_create_non_dup_list(onlp->namep, &ldevidp);
691	}
692
693	retval = meta_print_devid(sp, fp, ldevidp, ep);
694
695	/* cleanup */
696	for (nextp = ldevidp; nextp != NULL; ldevidp = nextp) {
697		Free(ldevidp->ctdname);
698		nextp = ldevidp->next;
699		Free(ldevidp);
700	}
701
702	return (retval);
703}
704
705/*
706 * probedev issues ioctls for all the metadevices
707 */
708
709
710
711
712/*
713 * Failure return's a 1
714 */
715int
716hotspare_ok(char *bname)
717{
718	int fd;
719	char buf[512];
720
721	if ((fd = open(bname, O_RDONLY)) < 0)
722		return (0);
723	if (read(fd, buf, sizeof (buf)) < 0) {
724		(void) close(fd);
725		return (0);
726	}
727	(void) close(fd);
728	return (1);
729}
730
731void
732delete_hotspares_impl(mdsetname_t *sp, mdhspname_t *hspnp, md_hsp_t *hspp)
733{
734	md_hs_t *hsp;
735	uint_t		hsi;
736	char    *bname;
737	md_error_t e = mdnullerror;
738	int deleted_hs = 0;
739
740	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
741		mdnamelist_t *nlp;
742
743		hsp = &hspp->hotspares.hotspares_val[hsi];
744		bname = hsp->hsnamep->bname;
745		nlp = NULL;
746		(void) metanamelist_append(&nlp, hsp->hsnamep);
747		/* print hotspare */
748		if (hsp->state == HSS_AVAILABLE) {
749			if (hotspare_ok(bname))
750				continue;
751
752			(void) fprintf(stderr,
753			    "NOTICE: Hotspare %s in %s has failed.\n"
754			    "\tDeleting %s since it not in use\n\n",
755			    bname, hspnp->hspname, bname);
756
757			if (meta_hs_delete(sp, hspnp, nlp, 0, &e) != NULL) {
758				mde_perror(&e, "");
759				mdclrerror(&e);
760			} else {
761				deleted_hs++;
762			}
763		}
764	}
765}
766
767
768
769/*
770 * Generic routine to issue ioctls
771 */
772
773void
774md_setprobetest(md_probedev_t *iocp)
775{
776	(void) strcpy(iocp->test_name, MD_PROBE_OPEN_T);
777}
778
779int
780md_probe_ioctl(mdsetname_t *sp, mdnamelist_t *nlp, int ndevs, char *drvname)
781{
782	mdnamelist_t	*p;
783	mdname_t	*np;
784	md_probedev_t	probe_ioc, *iocp;
785	int		i, retval = 0;
786	/*
787	 * Allocate space for all the metadevices and fill in
788	 * the minor numbers.
789	 */
790
791	(void) memset(&probe_ioc, 0, sizeof (probe_ioc));
792	iocp = &probe_ioc;
793
794	if ((iocp->mnum_list = (uintptr_t)calloc(ndevs, sizeof (minor_t)))
795	    == 0) {
796		perror("md_probe_ioctl: calloc");
797		return (-1);
798	}
799
800	MD_SETDRIVERNAME(iocp, drvname, sp->setno);
801	md_setprobetest(iocp);
802
803	iocp->nmdevs = ndevs;
804
805	for (p = nlp, i = 0; p; p = p->next, i++) {
806		np = p->namep;
807		((minor_t *)(uintptr_t)iocp->mnum_list)[i] =
808		    meta_getminor(np->dev);
809	}
810
811
812	if (metaioctl(MD_IOCPROBE_DEV, iocp, &(iocp->mde), NULL) != 0)
813			retval = -1;
814	Free((void *)(uintptr_t)iocp->mnum_list);
815	return (retval);
816}
817/*
818 *
819 *  - remove p from nlp list
820 *  - put it on the toplp list.
821 *  - update the p to the next element
822 */
823
824void
825add_to_list(mdnamelist_t **curpp, mdnamelist_t **prevpp, mdnamelist_t **newlpp)
826{
827	mdnamelist_t	*p, *prevp, *nlp;
828
829	p = *curpp;
830	prevp = *prevpp;
831	nlp = *newlpp;
832
833	if (prevp == p) {
834		/* if first element reset prevp */
835			prevp = p->next;
836			p->next = nlp;
837			nlp = p;
838			p = prevp;
839	} else {
840		prevp->next = p->next;
841		p->next = nlp;
842		nlp = p;
843		p = prevp->next;
844	}
845	*curpp = p;
846	*prevpp = prevp;
847	*newlpp = nlp;
848}
849/*
850 * Scans the given list of metadeivces and returns a list of top level
851 * metadevices.
852 * Note: The orignal list is not valid at the end and is set to NULL.
853 */
854
855int
856get_toplevel_mds(mdsetname_t *sp, mdnamelist_t **lpp,
857			mdnamelist_t **top_pp)
858{
859	mdnamelist_t	*p, *prevp, *toplp;
860	int		ntopmd;
861	md_common_t	*mdp;
862	md_error_t	e = mdnullerror;
863
864	ntopmd = 0;
865	prevp = p = *lpp;
866	toplp = NULL;
867
868	while (p) {
869		if ((mdp = meta_get_unit(sp, p->namep, &e)) == NULL) {
870				prevp = p;
871				p = p->next;
872				continue;
873		}
874
875		if (mdp->parent == MD_NO_PARENT) {
876			/* increment the top level md count. */
877			ntopmd++;
878			add_to_list(&p, &prevp, &toplp);
879		} else {
880			prevp = p;
881			p = p->next;
882		}
883	}
884	*lpp = NULL;
885	*top_pp = toplp;
886
887	return (ntopmd);
888}
889
890int
891get_namelist(mdnamelist_t **transdevlist, mdnamelist_t **devlist,
892					char *dev_type)
893{
894	mdnamelist_t *np, *prevp;
895	md_error_t	e = mdnullerror;
896	char		*type_name;
897	int		i = 0;
898
899	prevp = np = *transdevlist;
900	while (np) {
901		if ((type_name = metagetmiscname(np->namep, &e)) == NULL) {
902			*devlist = NULL;
903			return (-1);
904		}
905		if (strcmp(type_name, dev_type) == 0) {
906			/* move it to the devlist */
907			add_to_list(&np, &prevp, devlist);
908			i++;
909		} else {
910			prevp = np;
911			np = np->next;
912		}
913	}
914	return (i);
915}
916
917
918mdnamelist_t *
919create_nlp(mdsetname_t *sp)
920{
921	mdnamelist_t *np;
922	md_error_t   e = mdnullerror;
923
924	if (np = (mdnamelist_t *)malloc(sizeof (mdnamelist_t))) {
925		np->next = NULL;
926		return (np);
927	} else {
928		/* error condition below */
929		mde_perror(&e, "create_nlp: malloc failed\n");
930		md_exit(sp, 1);
931	}
932	return (0);
933}
934
935/*
936 * Create a list of metadevices associated with trans. top_pp points to
937 * this list. The number of components in the list are also returned.
938 */
939int
940create_trans_compslist(mdsetname_t *sp, mdnamelist_t **lpp,
941				mdnamelist_t **top_pp)
942{
943	mdnamelist_t	*p, *tailp, *toplp, *newlp;
944	int		ntoptrans;
945	md_error_t	e = mdnullerror;
946	md_trans_t	*tp;
947
948	ntoptrans = 0;
949	p = *lpp;
950	tailp = toplp = NULL;
951	/*
952	 * Scan the current list of trans devices. From that
953	 * extract all the lower level metadevices and put them on
954	 * toplp list.
955	 */
956
957	while (p) {
958		if (tp = meta_get_trans(sp, p->namep, &e)) {
959			/*
960			 * Check the master and log devices to see if they
961			 * are metadevices
962			 */
963			if (metaismeta(tp->masternamep)) {
964				/* get a mdnamelist_t. */
965				newlp = create_nlp(sp);
966				newlp->namep = tp->masternamep;
967				if (toplp == NULL) {
968					toplp = tailp = newlp;
969				} else {
970					tailp->next = newlp;
971					tailp = newlp;
972				}
973				ntoptrans++;
974			}
975
976			if (tp->lognamep && metaismeta(tp->lognamep)) {
977				newlp = create_nlp(sp);
978				newlp->namep = tp->lognamep;
979				if (toplp == NULL) {
980					toplp = tailp = newlp;
981				} else {
982					tailp->next = newlp;
983					tailp = newlp;
984				}
985				ntoptrans++;
986			}
987			p = p->next;
988		}
989	}
990	*top_pp = toplp;
991	return (ntoptrans);
992}
993
994void
995probe_mirror_devs(mdsetname_t *sp)
996{
997	mdnamelist_t	*nlp, *toplp;
998	int		cnt;
999	md_error_t	e = mdnullerror;
1000
1001	nlp = toplp = NULL;
1002
1003	if (meta_get_mirror_names(sp, &nlp, 0, &e) > 0) {
1004		/*
1005		 * We have some mirrors to probe
1006		 * get a list of top-level mirrors
1007		 */
1008
1009		cnt = get_toplevel_mds(sp, &nlp, &toplp);
1010		if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_MIRROR) < 0))
1011				perror("MD_IOCPROBE_DEV");
1012	} else {
1013		mdclrerror(&e);
1014	}
1015	metafreenamelist(nlp);
1016	metafreenamelist(toplp);
1017
1018}
1019
1020void
1021probe_raid_devs(mdsetname_t *sp)
1022{
1023	mdnamelist_t	*nlp, *toplp;
1024	int		cnt;
1025	md_error_t	e = mdnullerror;
1026
1027	nlp = toplp = NULL;
1028
1029	if (meta_get_raid_names(sp, &nlp, 0, &e) > 0) {
1030		/*
1031		 * We have some mirrors to probe
1032		 * get a list of top-level mirrors
1033		 */
1034
1035		cnt = get_toplevel_mds(sp, &nlp, &toplp);
1036
1037		if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_RAID) < 0))
1038			perror("MD_IOCPROBE_DEV");
1039	} else {
1040		mdclrerror(&e);
1041	}
1042	metafreenamelist(nlp);
1043	metafreenamelist(toplp);
1044}
1045
1046/*
1047 * Trans probes are diffenent. -- so whats new.
1048 * we separate out the master and log device and then issue the
1049 * probe calls.
1050 * Since the underlying device could be disk, stripe, RAID or miror,
1051 * we have to sort them out and then call the ioctl for each.
1052 */
1053
1054void
1055probe_trans_devs(mdsetname_t *sp)
1056{
1057	mdnamelist_t	*nlp, *toplp;
1058	mdnamelist_t	*trans_raidlp, *trans_mmlp, *trans_stripelp;
1059	int		cnt;
1060	md_error_t	e = mdnullerror;
1061
1062	nlp = toplp = NULL;
1063	trans_raidlp = trans_mmlp = trans_stripelp = NULL;
1064
1065	if (meta_get_trans_names(sp, &nlp, 0, &e) > 0) {
1066		/*
1067		 * get a list of master and log metadevices.
1068		 */
1069
1070		cnt = create_trans_compslist(sp, &nlp, &toplp);
1071
1072		/* underlying RAID-5 components */
1073
1074		cnt = get_namelist(&toplp, &trans_raidlp, MD_RAID);
1075		if ((cnt > 0) && (md_probe_ioctl(sp, trans_raidlp, cnt,
1076		    MD_RAID) < 0))
1077			perror("MD_IOCPROBE_DEV");
1078
1079		metafreenamelist(trans_raidlp);
1080
1081		/* underlying mirror components */
1082
1083		cnt = get_namelist(&toplp, &trans_mmlp, MD_MIRROR);
1084
1085		if ((cnt > 0) && (md_probe_ioctl(sp, trans_mmlp, cnt,
1086		    MD_MIRROR) < 0))
1087			perror("MD_IOCPROBE_DEV");
1088
1089		metafreenamelist(trans_mmlp);
1090
1091		/* underlying stripe components */
1092
1093		cnt = get_namelist(&toplp, &trans_stripelp, MD_STRIPE);
1094		if ((cnt > 0) && (md_probe_ioctl(sp, trans_stripelp, cnt,
1095		    MD_STRIPE) < 0))
1096			perror("MD_IOCPROBE_DEV");
1097		metafreenamelist(trans_stripelp);
1098		metafreenamelist(nlp);
1099	} else {
1100		mdclrerror(&e);
1101	}
1102}
1103
1104/*
1105 * probe hot spares. This is differs from other approaches since
1106 * there are no read/write routines through md. We check at the physical
1107 * component level and then delete it if its bad.
1108 */
1109
1110void
1111probe_hotspare_devs(mdsetname_t *sp)
1112{
1113	mdhspnamelist_t *hspnlp = NULL;
1114	mdhspnamelist_t	*p;
1115	md_hsp_t	*hspp;
1116	md_error_t	e = mdnullerror;
1117
1118	if (meta_get_hsp_names(sp, &hspnlp, 0, &e) <= 0) {
1119		mdclrerror(&e);
1120		return;
1121	}
1122	for (p = hspnlp; (p != NULL); p = p->next) {
1123		mdhspname_t	*hspnp = p->hspnamep;
1124
1125		if ((hspp = meta_get_hsp(sp, hspnp, &e)) == NULL)
1126			continue;
1127
1128		if (hspp->hotspares.hotspares_len != 0) {
1129			delete_hotspares_impl(sp, hspnp, hspp);
1130		}
1131	}
1132	metafreehspnamelist(hspnlp);
1133	mdclrerror(&e);
1134}
1135
1136static void
1137probe_all_devs(mdsetname_t *sp)
1138{
1139	probe_hotspare_devs(sp);
1140	probe_mirror_devs(sp);
1141	probe_raid_devs(sp);
1142	probe_trans_devs(sp);
1143}
1144
1145/*
1146 * The following functions are used to print the concise output
1147 * of the metastat coommand (-c option).
1148 *
1149 * Normally the output for metastat is performed within libmeta via
1150 * the *_report functions within each of the metadevice specific files in
1151 * libmeta.  However, it is usually bad architecture for a library to
1152 * perform output since there are so many different ways that an application
1153 * can choose to do output (e.g. GUI, CLI, CIM, SNMP, etc.).  So, for the
1154 * concise output option we have moved the CLI output to the metastat
1155 * code and just use libmeta as the source of data to be printed.
1156 *
1157 * This function gets all of the different top-level metadevices in the set
1158 * and prints them.  It calls the print_concise_md() function to recursively
1159 * print the metadevices that underly the top-level metadevices.  It does
1160 * special handling for soft partitions so that all of the SPs on the
1161 * same underlying device are grouped and then that underlying device
1162 * is only printed once.
1163 */
1164static void
1165print_concise_diskset(mdsetname_t *sp)
1166{
1167	md_error_t		error = mdnullerror;
1168	mdnamelist_t		*nl = NULL;
1169	mdhspnamelist_t		*hsp_list = NULL;
1170
1171	/*
1172	 * We do extra handling for soft parts since we want to find
1173	 * all of the SPs on the same underlying device, group them and
1174	 * print them together before printing the underlying device just
1175	 * once.  This logic doesn't apply to any other metadevice type.
1176	 */
1177	if (meta_get_sp_names(sp, &nl, 0, &error) >= 0) {
1178		mdnamelist_t	*nlp;
1179		/* keep track of the softparts on the same underlying device */
1180		struct sp_base_list	*base_list = NULL;
1181
1182		for (nlp = nl; nlp != NULL; nlp = nlp->next) {
1183			mdname_t	*mdn;
1184			md_sp_t		*soft_part;
1185			mdnamelist_t	*tnlp;
1186
1187			mdn = metaname(&sp, nlp->namep->cname,
1188			    META_DEVICE, &error);
1189			mdclrerror(&error);
1190			if (mdn == NULL) {
1191				print_concise_entry(0, nlp->namep->cname,
1192				    0, 'p');
1193				(void) printf("\n");
1194				continue;
1195			}
1196
1197			soft_part = meta_get_sp_common(sp, mdn, 1, &error);
1198			mdclrerror(&error);
1199
1200			if (soft_part == NULL ||
1201			    MD_HAS_PARENT(soft_part->common.parent) ||
1202			    sp_done(soft_part, base_list))
1203				continue;
1204
1205			/* print this soft part */
1206			print_concise_entry(0, soft_part->common.namep->cname,
1207			    soft_part->common.size, 'p');
1208			(void) printf(" %s\n", soft_part->compnamep->cname);
1209
1210			/*
1211			 * keep track of the underlying device of
1212			 * this soft part
1213			 */
1214			base_list = sp_add_done(soft_part, base_list);
1215
1216			/*
1217			 * now print all of the other soft parts on the same
1218			 * underlying device
1219			 */
1220			for (tnlp = nlp->next; tnlp != NULL; tnlp =
1221			    tnlp->next) {
1222				md_sp_t		*part;
1223
1224				mdn = metaname(&sp, tnlp->namep->cname,
1225				    META_DEVICE, &error);
1226
1227				mdclrerror(&error);
1228				if (mdn == NULL)
1229					continue;
1230
1231				part = meta_get_sp_common(sp, mdn, 1, &error);
1232				mdclrerror(&error);
1233
1234				if (part == NULL || MD_HAS_PARENT(
1235				    part->common.parent) ||
1236				    ! sp_match(part, base_list))
1237					continue;
1238
1239				/* on the same base so print this soft part */
1240				print_concise_entry(0,
1241				    part->common.namep->cname,
1242				    part->common.size, 'p');
1243				(void) printf(" %s\n", part->compnamep->cname);
1244			}
1245
1246			/*
1247			 * print the common metadevice hierarchy
1248			 * under these soft parts
1249			 */
1250			print_concise_md(META_INDENT, sp, soft_part->compnamep);
1251		}
1252
1253		free_names(&nl);
1254		sp_free_list(base_list);
1255	}
1256	mdclrerror(&error);
1257
1258	if (meta_get_trans_names(sp, &nl, 0, &error) >= 0)
1259		print_concise_namelist(sp, &nl, 't');
1260	mdclrerror(&error);
1261
1262	if (meta_get_mirror_names(sp, &nl, 0, &error) >= 0)
1263		print_concise_namelist(sp, &nl, 'm');
1264	mdclrerror(&error);
1265
1266	if (meta_get_raid_names(sp, &nl, 0, &error) >= 0)
1267		print_concise_namelist(sp, &nl, 'r');
1268	mdclrerror(&error);
1269
1270	if (meta_get_stripe_names(sp, &nl, 0, &error) >= 0)
1271		print_concise_namelist(sp, &nl, 's');
1272	mdclrerror(&error);
1273
1274	if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) {
1275		mdhspnamelist_t *nlp;
1276
1277	for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) {
1278		md_hsp_t	*hsp;
1279
1280		print_concise_entry(0, nlp->hspnamep->hspname, 0, 'h');
1281
1282		hsp = meta_get_hsp_common(sp, nlp->hspnamep, 1, &error);
1283		mdclrerror(&error);
1284		if (hsp != NULL) {
1285			int	i;
1286
1287			for (i = 0; i < hsp->hotspares.hotspares_len; i++) {
1288				md_hs_t	*hs;
1289				char	*state;
1290
1291				hs = &hsp->hotspares.hotspares_val[i];
1292
1293				(void) printf(" %s", hs->hsnamep->cname);
1294
1295				state = get_hs_state(hs);
1296				if (state != NULL)
1297					(void) printf(" (%s)", state);
1298			}
1299		}
1300
1301		(void) printf("\n");
1302	}
1303
1304	mdclrerror(&error);
1305	metafreehspnamelist(hsp_list);
1306	}
1307}
1308
1309/*
1310 * Print the top-level metadevices in the name list for concise output.
1311 */
1312static void
1313print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl, char mtype)
1314{
1315	mdnamelist_t	*nlp;
1316	md_error_t	error = mdnullerror;
1317
1318	for (nlp = *nl; nlp != NULL; nlp = nlp->next) {
1319		mdname_t	*mdn;
1320		md_common_t	*u;
1321
1322		mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
1323		mdclrerror(&error);
1324		if (mdn == NULL) {
1325			print_concise_entry(0, nlp->namep->cname, 0, mtype);
1326			(void) printf("\n");
1327			continue;
1328		}
1329
1330		u = get_concise_unit(sp, mdn, &error);
1331		mdclrerror(&error);
1332
1333		if (u != NULL && !MD_HAS_PARENT(u->parent))
1334			print_concise_md(0, sp, mdn);
1335	}
1336
1337	free_names(nl);
1338}
1339
1340/*
1341 * Concise mirror output.
1342 */
1343static void
1344print_concise_mirror(int indent, mdsetname_t *sp, md_mirror_t *mirror)
1345{
1346	md_error_t	error = mdnullerror;
1347	int		i;
1348	md_status_t	status = mirror->common.state;
1349
1350	if (mirror == NULL)
1351		return;
1352
1353	print_concise_entry(indent, mirror->common.namep->cname,
1354	    mirror->common.size, 'm');
1355
1356	for (i = 0; i < NMIRROR; i++) {
1357		uint_t	tstate = 0;
1358		char	*state;
1359
1360		if (mirror->submirrors[i].submirnamep == NULL)
1361			continue;
1362		(void) printf(" %s", mirror->submirrors[i].submirnamep->cname);
1363
1364		if (mirror->submirrors[i].state & SMS_OFFLINE) {
1365			(void) printf(gettext(" (offline)"));
1366			continue;
1367		}
1368
1369		if (metaismeta(mirror->submirrors[i].submirnamep))
1370			(void) meta_get_tstate(
1371			    mirror->submirrors[i].submirnamep->dev,
1372			    &tstate, &error);
1373
1374		mdclrerror(&error);
1375		state = get_sm_state(mirror, i, status, tstate);
1376		if (state != NULL)
1377			(void) printf(" (%s)", state);
1378	}
1379
1380	(void) printf("\n");
1381
1382	indent += META_INDENT;
1383	for (i = 0; i < NMIRROR; i++) {
1384		if (mirror->submirrors[i].submirnamep == NULL)
1385			continue;
1386
1387		print_concise_md(indent, sp, mirror->submirrors[i].submirnamep);
1388	}
1389}
1390
1391/*
1392 * Concise raid output.
1393 */
1394static void
1395print_concise_raid(int indent, mdsetname_t *sp, md_raid_t *raid)
1396{
1397	md_error_t	error = mdnullerror;
1398	int		i;
1399	uint_t		tstate = 0;
1400
1401	if (raid == NULL)
1402		return;
1403
1404	print_concise_entry(indent, raid->common.namep->cname,
1405	    raid->common.size, 'r');
1406
1407	if (metaismeta(raid->common.namep))
1408		(void) meta_get_tstate(raid->common.namep->dev,
1409		    &tstate, &error);
1410
1411	for (i = 0; i < raid->cols.cols_len; i++) {
1412		md_raidcol_t	*colp = &raid->cols.cols_val[i];
1413		mdname_t	*namep = ((colp->hsnamep != NULL) ?
1414		    colp->hsnamep : colp->colnamep);
1415		char	*hsname = ((colp->hsnamep != NULL) ?
1416		    colp->hsnamep->cname : NULL);
1417		char	*col_state = NULL;
1418
1419		(void) printf(" %s", colp->colnamep->cname);
1420
1421		if (metaismeta(namep)) {
1422			uint_t tstate = 0;
1423
1424			(void) meta_get_tstate(namep->dev, &tstate, &error);
1425			mdclrerror(&error);
1426			col_state = get_raid_col_state(colp, tstate);
1427
1428		} else {
1429			if (tstate != 0)
1430				col_state = "-";
1431			else
1432				col_state = get_raid_col_state(colp, tstate);
1433		}
1434
1435		if (col_state != NULL) {
1436			if (hsname != NULL)
1437				(void) printf(" (%s-%s)", col_state, hsname);
1438			else
1439				(void) printf(" (%s)", col_state);
1440
1441		} else if (hsname != NULL) {
1442			(void) printf(gettext(" (spared-%s)"), hsname);
1443		}
1444	}
1445
1446	(void) printf("\n");
1447
1448	indent += META_INDENT;
1449	for (i = 0; i < raid->cols.cols_len; i++) {
1450		print_concise_md(indent, sp, raid->cols.cols_val[i].colnamep);
1451	}
1452}
1453
1454/*
1455 * Concise stripe output.
1456 */
1457static void
1458print_concise_stripe(int indent, mdsetname_t *sp, md_stripe_t *stripe)
1459{
1460	md_error_t	error = mdnullerror;
1461	int		i;
1462	uint_t		top_tstate = 0;
1463
1464	if (stripe == NULL)
1465		return;
1466
1467	print_concise_entry(indent, stripe->common.namep->cname,
1468	    stripe->common.size, 's');
1469
1470	if (metaismeta(stripe->common.namep))
1471		(void) meta_get_tstate(stripe->common.namep->dev, &top_tstate,
1472		    &error);
1473	mdclrerror(&error);
1474
1475	for (i = 0; i < stripe->rows.rows_len; i++) {
1476		md_row_t	*rowp;
1477		int		j;
1478
1479		rowp = &stripe->rows.rows_val[i];
1480
1481		for (j = 0; j < rowp->comps.comps_len; j++) {
1482			md_comp_t	*comp;
1483			uint_t		tstate = 0;
1484			char		*comp_state = NULL;
1485			char		*hsname;
1486
1487			comp = &rowp->comps.comps_val[j];
1488			(void) printf(" %s", comp->compnamep->cname);
1489
1490			if (metaismeta(comp->compnamep)) {
1491				uint_t tstate = 0;
1492				(void) meta_get_tstate(comp->compnamep->dev,
1493				    &tstate, &error);
1494				mdclrerror(&error);
1495				comp_state = get_stripe_state(comp, tstate);
1496			} else {
1497			if (top_tstate != 0)
1498				comp_state = "-";
1499			else
1500				comp_state = get_stripe_state(comp, tstate);
1501			}
1502
1503			hsname = ((comp->hsnamep != NULL) ?
1504			    comp->hsnamep->cname : NULL);
1505
1506			if (comp_state != NULL) {
1507				if (hsname != NULL)
1508					(void) printf(" (%s-%s)",
1509					    comp_state, hsname);
1510				else
1511					(void) printf(" (%s)", comp_state);
1512
1513			} else if (hsname != NULL) {
1514				(void) printf(gettext(" (spared-%s)"), hsname);
1515			}
1516		}
1517	}
1518
1519	(void) printf("\n");
1520
1521	indent += META_INDENT;
1522	for (i = 0; i < stripe->rows.rows_len; i++) {
1523		md_row_t	*rowp;
1524		int		j;
1525
1526		rowp = &stripe->rows.rows_val[i];
1527
1528		for (j = 0; j < rowp->comps.comps_len; j++) {
1529			print_concise_md(indent, sp,
1530			    rowp->comps.comps_val[j].compnamep);
1531		}
1532	}
1533}
1534
1535/*
1536 * Concise soft partition output.
1537 */
1538static void
1539print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part)
1540{
1541	if (part == NULL)
1542	return;
1543
1544	print_concise_entry(indent, part->common.namep->cname,
1545	    part->common.size, 'p');
1546
1547	(void) printf(" %s\n", part->compnamep->cname);
1548
1549	print_concise_md(indent + META_INDENT, sp, part->compnamep);
1550}
1551
1552/*
1553 * Concise trans output.
1554 */
1555static void
1556print_concise_trans(int indent, mdsetname_t *sp, md_trans_t *trans)
1557{
1558	if (trans == NULL)
1559		return;
1560
1561	print_concise_entry(indent, trans->common.namep->cname,
1562	    trans->common.size, 't');
1563
1564	if (trans->masternamep != NULL)
1565		(void) printf(" %s", trans->masternamep->cname);
1566
1567	if (trans->lognamep != NULL)
1568		(void) printf(" %s", trans->lognamep->cname);
1569
1570	(void) printf("\n");
1571
1572	indent += META_INDENT;
1573
1574	print_concise_md(indent, sp, trans->masternamep);
1575
1576	print_concise_md(indent, sp, trans->lognamep);
1577}
1578
1579/*
1580 * Recursive function for concise metadevice nested output.
1581 */
1582static void
1583print_concise_md(int indent, mdsetname_t *sp, mdname_t *np)
1584{
1585	md_error_t	error = mdnullerror;
1586	md_unit_t	*u;
1587	md_mirror_t	*mirror;
1588	md_raid_t	*raid;
1589	md_sp_t		*soft_part;
1590	md_stripe_t	*stripe;
1591	md_trans_t	*trans;
1592
1593	if (np == NULL || !metaismeta(np))
1594		return;
1595
1596	if ((u = meta_get_mdunit(sp, np, &error)) == NULL) {
1597		mdclrerror(&error);
1598		return;
1599	}
1600
1601	switch (u->c.un_type) {
1602		case MD_DEVICE:
1603			stripe = meta_get_stripe_common(sp, np, 1, &error);
1604			print_concise_stripe(indent, sp, stripe);
1605			break;
1606
1607		case MD_METAMIRROR:
1608			mirror = meta_get_mirror(sp, np, &error);
1609			print_concise_mirror(indent, sp, mirror);
1610			break;
1611
1612		case MD_METATRANS:
1613			trans = meta_get_trans_common(sp, np, 1, &error);
1614			print_concise_trans(indent, sp, trans);
1615			break;
1616
1617		case MD_METARAID:
1618			raid = meta_get_raid_common(sp, np, 1, &error);
1619			print_concise_raid(indent, sp, raid);
1620			break;
1621
1622		case MD_METASP:
1623			soft_part = meta_get_sp_common(sp, np, 1, &error);
1624			print_concise_sp(indent, sp, soft_part);
1625			break;
1626
1627		default:
1628			return;
1629	}
1630	mdclrerror(&error);
1631}
1632
1633/*
1634 * Given a name get the unit for use in concise output.  We use the *_common
1635 * routines in libmeta which allow us to specify the "fast" flag, thereby
1636 * avoiding the DKIOCGGEOM ioctl that normally happens.
1637 */
1638static md_common_t *
1639get_concise_unit(mdsetname_t *sp, mdname_t *np, md_error_t *ep)
1640{
1641	char		*miscname;
1642
1643	/* short circuit */
1644	if (np->drivenamep->unitp != NULL)
1645		return (np->drivenamep->unitp);
1646	if (metachkmeta(np, ep) != 0)
1647		return (NULL);
1648
1649	/* dispatch */
1650	if ((miscname = metagetmiscname(np, ep)) == NULL)
1651		return (NULL);
1652	else if (strcmp(miscname, MD_STRIPE) == 0)
1653		return ((md_common_t *)meta_get_stripe_common(sp, np, 1, ep));
1654	else if (strcmp(miscname, MD_MIRROR) == 0)
1655		return ((md_common_t *)meta_get_mirror(sp, np, ep));
1656	else if (strcmp(miscname, MD_TRANS) == 0)
1657		return ((md_common_t *)meta_get_trans_common(sp, np, 1, ep));
1658	else if (strcmp(miscname, MD_RAID) == 0)
1659		return ((md_common_t *)meta_get_raid_common(sp, np, 1, ep));
1660	else if (strcmp(miscname, MD_SP) == 0)
1661		return ((md_common_t *)meta_get_sp_common(sp, np, 1, ep));
1662	else {
1663		(void) mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(np->dev),
1664		    np->cname);
1665		return (NULL);
1666	}
1667}
1668
1669static void
1670free_names(mdnamelist_t **nlp)
1671{
1672	mdnamelist_t *p;
1673
1674	for (p = *nlp; p != NULL; p = p->next) {
1675		meta_invalidate_name(p->namep);
1676		p->namep = NULL;
1677	}
1678	metafreenamelist(*nlp);
1679	*nlp = NULL;
1680}
1681
1682/*
1683 * Submirror state for concise output.
1684 */
1685static char *
1686get_sm_state(md_mirror_t *mirror, int i, md_status_t mirror_status,
1687	uint_t tstate)
1688{
1689	sm_state_t	state = mirror->submirrors[i].state;
1690	uint_t	is_target =
1691	    mirror->submirrors[i].flags & MD_SM_RESYNC_TARGET;
1692
1693	/*
1694	 * Only return Unavailable if there is no flagged error on the
1695	 * submirror. If the mirror has received any writes since the submirror
1696	 * went into Unavailable state a resync is required. To alert the
1697	 * administrator to this we return a 'Needs maintenance' message.
1698	 */
1699	if ((tstate != 0) && (state & SMS_RUNNING))
1700		return (gettext("unavail"));
1701
1702	/* all is well */
1703	if (state & SMS_RUNNING) {
1704		if (!(mirror_status & MD_UN_OPT_NOT_DONE) ||
1705		    ((mirror_status & MD_UN_OPT_NOT_DONE) && !is_target))
1706			return (NULL);
1707	}
1708
1709	/* resyncing, needs repair */
1710	if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
1711	    SMS_OFFLINE_RESYNC)) || (mirror_status & MD_UN_OPT_NOT_DONE)) {
1712		static char buf[MAXPATHLEN];
1713
1714		if (mirror_status & MD_UN_RESYNC_ACTIVE) {
1715
1716			if (mirror->common.revision & MD_64BIT_META_DEV) {
1717				(void) snprintf(buf, sizeof (buf),
1718				    gettext("resync-%2d.%1d%%"),
1719				    mirror->percent_done / 10,
1720				    mirror->percent_done % 10);
1721			} else {
1722				(void) snprintf(buf, sizeof (buf),
1723				gettext("resync-%d%%"), mirror->percent_done);
1724			}
1725			return (buf);
1726		}
1727		return (gettext("maint"));
1728	}
1729
1730	/* needs repair */
1731	if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE))
1732		return (gettext("maint"));
1733
1734	/* unknown */
1735	return (gettext("unknown"));
1736}
1737
1738/*
1739 * Raid component state for concise output.
1740 */
1741static char *
1742get_raid_col_state(md_raidcol_t *colp, uint_t tstate)
1743{
1744	if (tstate != 0)
1745		return (gettext("unavail"));
1746
1747	return (meta_get_raid_col_state(colp->state));
1748}
1749
1750/*
1751 * Stripe state for concise output.
1752 */
1753static char *
1754get_stripe_state(md_comp_t *mdcp, uint_t tstate)
1755{
1756	comp_state_t	state = mdcp->state;
1757
1758	if (tstate != 0)
1759		return ("unavail");
1760
1761	return (meta_get_stripe_state(state));
1762}
1763
1764/*
1765 * Hostspare state for concise output.
1766 */
1767static char *
1768get_hs_state(md_hs_t *hsp)
1769{
1770	hotspare_states_t	state = hsp->state;
1771
1772	return (meta_get_hs_state(state));
1773}
1774
1775
1776/*
1777 * Keep track of printed soft partitions for concise output.
1778 */
1779static struct sp_base_list *
1780sp_add_done(md_sp_t *part, struct sp_base_list *lp)
1781{
1782	struct sp_base_list *n;
1783
1784	n = (struct sp_base_list *)malloc(sizeof (struct sp_base_list));
1785	if (n == NULL)
1786		return (lp);
1787
1788	if ((n->base = strdup(part->compnamep->cname)) == NULL) {
1789		free(n);
1790		return (lp);
1791	}
1792
1793	n->next = lp;
1794
1795	return (n);
1796}
1797
1798/*
1799 * Keep track of printed soft partitions for concise output.
1800 */
1801static int
1802sp_done(md_sp_t *part, struct sp_base_list *lp)
1803{
1804	for (; lp != NULL; lp = lp->next) {
1805		if (strcmp(lp->base, part->compnamep->cname) == 0)
1806			return (1);
1807	}
1808
1809	return (0);
1810}
1811
1812/*
1813 * Check the first element for a match.
1814 */
1815static int
1816sp_match(md_sp_t *part, struct sp_base_list *lp)
1817{
1818	if (lp != NULL && strcmp(lp->base, part->compnamep->cname) == 0)
1819		return (1);
1820
1821	return (0);
1822}
1823
1824/*
1825 * Free memory used for soft partition printed status in concise output.
1826 */
1827static void
1828sp_free_list(struct sp_base_list *lp)
1829{
1830	struct sp_base_list *n;
1831
1832	for (; lp != NULL; lp = n) {
1833		n = lp->next;
1834		free(lp->base);
1835		free(lp);
1836	}
1837}
1838