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