xref: /titanic_41/usr/src/cmd/lvm/util/metastat.c (revision 264a6e7478846334593be7663fb6b1a8f37784a0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <string.h>
32 
33 #include <meta.h>
34 #include <sys/lvm/md_mddb.h>
35 #include <sdssc.h>
36 
37 /*
38  * print metadevice status
39  */
40 
41 
42 #define	MD_PROBE_OPEN_T "probe open test"
43 
44 /* used to keep track of the softparts on the same underlying device */
45 struct sp_base_list {
46 	struct sp_base_list	*next;
47 	char			*base;
48 };
49 
50 /*
51  * Function prototypes
52  */
53 static void probe_all_devs(mdsetname_t *sp);
54 
55 static int print_devid(mdsetname_t *sp, mdnamelist_t *nlp, FILE *fp,
56     md_error_t   *ep);
57 
58 static md_common_t	*get_concise_unit(mdsetname_t *sp, mdname_t *np,
59 			    md_error_t *ep);
60 static void	print_all_sets(mdprtopts_t options, int concise_flag,
61 		    int quiet_flg);
62 static void	print_specific_set(mdsetname_t *sp, mdprtopts_t options,
63 		    int concise_flag, int quiet_flg);
64 static void	print_concise_diskset(mdsetname_t *sp);
65 static void	print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl,
66 		    char mtype);
67 static void	print_concise_md(int indent, mdsetname_t *sp, mdname_t *np);
68 static void	print_concise_mirror(int indent, mdsetname_t *sp,
69 		    md_mirror_t *mirror);
70 static void	print_concise_raid(int indent, mdsetname_t *sp,
71 		    md_raid_t *raid);
72 static void	print_concise_stripe(int indent, mdsetname_t *sp,
73 		    md_stripe_t *stripe);
74 static void	print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part);
75 static void	print_concise_trans(int indent, mdsetname_t *sp,
76 		    md_trans_t *trans);
77 static void	free_names(mdnamelist_t **nlp);
78 static char	*get_sm_state(md_mirror_t *mirror, int i,
79 		    md_status_t mirror_status, uint_t tstate);
80 static char	*get_raid_col_state(md_raidcol_t *colp, uint_t tstate);
81 static char	*get_stripe_state(md_comp_t *mdcp, uint_t tstate);
82 static char	*get_hs_state(md_hs_t *hsp);
83 static struct sp_base_list *sp_add_done(md_sp_t *part, struct sp_base_list *lp);
84 static int	sp_done(md_sp_t *part, struct sp_base_list *lp);
85 static int	sp_match(md_sp_t *part, struct sp_base_list *lp);
86 static void	sp_free_list(struct sp_base_list *lp);
87 
88 
89 /*
90  * print named hotspare pool or metadevice
91  */
92 static int
93 print_name(
94 	mdsetname_t	**spp,
95 	char		*uname,
96 	mdnamelist_t	**nlistpp,
97 	char		*fname,
98 	FILE		*fp,
99 	mdprtopts_t	options,
100 	int		*meta_print_trans_msgp,
101 	mdnamelist_t	**lognlpp,
102 	md_error_t	*ep
103 )
104 {
105 	mdname_t	*namep;
106 	char		*miscname;
107 
108 	/* recurse */
109 	options |= PRINT_SUBDEVS;
110 
111 	/* hotspare pool */
112 	if (is_existing_hsp(*spp, uname)) {
113 		mdhspname_t	*hspnamep;
114 
115 		/* get hotsparepool */
116 		if ((hspnamep = metahspname(spp, uname, ep)) == NULL)
117 			return (-1);
118 
119 		/* check for ownership */
120 		assert(*spp != NULL);
121 		if (meta_check_ownership(*spp, ep) != 0)
122 			return (-1);
123 
124 		/* print hotspare pool */
125 		return (meta_hsp_print(*spp, hspnamep, lognlpp, fname, fp,
126 		    options, ep));
127 	}
128 
129 	/* get metadevice */
130 	if (((namep = metaname(spp, uname, META_DEVICE, ep)) == NULL) ||
131 	    (metachkmeta(namep, ep) != 0))
132 		return (-1);
133 
134 	/* check for ownership */
135 	assert(*spp != NULL);
136 	if (meta_check_ownership(*spp, ep) != 0)
137 		return (-1);
138 
139 	if ((miscname = metagetmiscname(namep, ep)) != NULL) {
140 		if (strcmp(miscname, MD_TRANS) == 0) {
141 			*meta_print_trans_msgp = 1;
142 		}
143 	}
144 
145 	/* print metadevice */
146 	return (meta_print_name(*spp, namep, nlistpp, fname, fp, options,
147 	    lognlpp, ep));
148 }
149 
150 /*
151  * print the per set flags
152  */
153 /*ARGSUSED*/
154 static int
155 print_setstat(
156 	mdsetname_t		**spp,
157 	char			*fname,
158 	FILE			*fp,
159 	mdprtopts_t		options,
160 	md_error_t		*ep
161 )
162 {
163 	int			rval = -1;
164 	char			*cname = NULL;
165 	char			*cp = NULL;
166 	md_gs_stat_parm_t	gsp;
167 
168 
169 	if (fname != NULL && strchr(fname, '/') != NULL) {
170 		/* get the canonical name */
171 		cname = meta_name_getname(spp, fname, META_DEVICE, ep);
172 		if (cname == NULL)
173 			return (-1);
174 		Free(cname);
175 	}
176 
177 	if ((cp = getenv("MD_DEBUG")) == NULL)
178 		return (0);
179 
180 	if (strstr(cp, "SETINFO") == NULL)
181 		return (0);
182 
183 	(void) memset(&gsp, '\0', sizeof (md_gs_stat_parm_t));
184 	gsp.gs_setno = (*spp)->setno;
185 
186 	if (metaioctl(MD_GET_SETSTAT, &gsp, &gsp.gs_mde, NULL) != 0)
187 		return (mdstealerror(ep, &gsp.gs_mde));
188 
189 	if (fprintf(fp, "Status for set %d = ", gsp.gs_setno) == EOF)
190 		goto out;
191 
192 	if (meta_prbits(fp, NULL, gsp.gs_status, MD_SET_STAT_BITS) == EOF)
193 		goto out;
194 
195 
196 	if (fprintf(fp, "\n") == EOF)
197 		goto out;
198 
199 	/* success */
200 	rval = 0;
201 
202 	/* cleanup, return error */
203 out:
204 	if (rval != 0)
205 		(void) mdsyserror(ep, errno, fname);
206 
207 	return (rval);
208 }
209 
210 /*
211  * check_replica_state:
212  * 	If the replica state is stale or the set has been halted
213  * 	this routine returns an error.
214  */
215 static int
216 check_replica_state(mdsetname_t *sp, md_error_t *ep)
217 {
218 	mddb_config_t	c;
219 
220 	(void) memset(&c, 0, sizeof (c));
221 	c.c_id = 0;
222 	c.c_setno = sp->setno;
223 
224 	if (metaioctl(MD_DB_GETDEV, &c, &c.c_mde, NULL) != 0) {
225 		if (mdismddberror(&c.c_mde, MDE_DB_INVALID))
226 			mdstealerror(ep, &c.c_mde);
227 		return (-1);
228 	}
229 
230 	if (c.c_flags & MDDB_C_STALE) {
231 		return (mdmddberror(ep, MDE_DB_STALE, NODEV32, sp->setno,
232 			0, NULL));
233 	} else
234 		return (0);
235 }
236 
237 static void
238 print_trans_msg(mdprtopts_t	options, int	meta_print_trans_msg)
239 {
240 	if (meta_print_trans_msg != 0) {
241 		fprintf(stderr, "\n\n");
242 		if (options & PRINT_SHORT) {
243 			fprintf(stderr, gettext(MD_SHORT_EOF_TRANS_MSG));
244 			fprintf(stderr, gettext(MD_SHORT_EOF_TRANS_WARNING));
245 		} else {
246 			fprintf(stderr, gettext(MD_EOF_TRANS_MSG));
247 			fprintf(stderr, gettext(MD_EOF_TRANS_WARNING));
248 		}
249 	}
250 }
251 
252 /*
253  * print usage message
254  *
255  */
256 static void
257 usage(
258 	mdsetname_t	*sp,
259 	int		eval
260 )
261 {
262 	(void) fprintf(stderr, gettext("\
263 usage:	%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  */
271 int
272 main(
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 		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 			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 			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, 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, options,
476 			&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, quiet_flg);
609 		(void) printf("\n");
610 	    }
611 
612 	    metaflushsetname(sp);
613 	}
614 }
615 
616 static void
617 print_specific_set(mdsetname_t *sp, mdprtopts_t options, int concise_flag,
618 	int quiet_flg)
619 {
620 	md_error_t	status = mdnullerror;
621 	md_error_t	*ep = &status;
622 	int		meta_print_trans_msg = 0;
623 
624 	/* check for ownership */
625 	assert(sp != NULL);
626 	if (meta_check_ownership(sp, ep) != 0) {
627 	    mde_perror(ep, "");
628 	    md_exit(sp, 1);
629 	}
630 
631 	if (concise_flag) {
632 	    print_concise_diskset(sp);
633 
634 	} else {
635 	    mdnamelist_t	*nlistp = NULL;
636 
637 	    /* status devices */
638 	    if (meta_print_all(sp, NULL, &nlistp, stdout, options,
639 		&meta_print_trans_msg, ep) != 0) {
640 		mde_perror(ep, "");
641 		md_exit(sp, 1);
642 	    }
643 
644 	    /* print relocation device id on all dev's */
645 	    if ((options & PRINT_DEVID) && !quiet_flg) {
646 		/*
647 		 * Ignore return value from meta_getalldevs since
648 		 * it will return a failure if even one device cannot
649 		 * be found - which could occur in the case of device
650 		 * failure or a device being powered off during
651 		 * upgrade.  Even if meta_getalldevs fails, the
652 		 * data in nlistp is still valid.
653 		 */
654 		if (!(options & (PRINT_LARGEDEVICES | PRINT_FN))) {
655 		    (void) meta_getalldevs(sp, &nlistp, 0, ep);
656 		}
657 		if (nlistp != NULL) {
658 		    if (print_devid(sp, nlistp, stdout, ep) != 0) {
659 			mde_perror(ep, "");
660 			md_exit(sp, 1);
661 		    }
662 		}
663 	    }
664 	}
665 
666 	print_trans_msg(options, meta_print_trans_msg);
667 }
668 
669 /*
670  * print_devid prints out cxtxdx and devid for devices passed in a
671  * mdnamelist_t structure
672  */
673 static int
674 print_devid(
675 	mdsetname_t  *sp,
676 	mdnamelist_t *nlp,
677 	FILE		 *fp,
678 	md_error_t   *ep
679 )
680 {
681 	int 			retval = 0;
682 	mdnamelist_t		*onlp = NULL;
683 	mddevid_t 		*ldevidp = NULL;
684 	mddevid_t		*nextp;
685 
686 	/* make a non-duplicate list of nlp */
687 	for (onlp = nlp; (onlp != NULL); onlp = onlp->next) {
688 		meta_create_non_dup_list(onlp->namep, &ldevidp);
689 	}
690 
691 	retval = meta_print_devid(sp, fp, ldevidp, ep);
692 
693 	/* cleanup */
694 	for (nextp = ldevidp; nextp != NULL; ldevidp = nextp) {
695 		Free(ldevidp->ctdname);
696 		nextp = ldevidp->next;
697 		Free(ldevidp);
698 	}
699 
700 	return (retval);
701 }
702 
703 /*
704  * probedev issues ioctls for all the metadevices
705  */
706 
707 
708 
709 
710 /*
711  * Failure return's a 1
712  */
713 int
714 hotspare_ok(char *bname)
715 {
716 	int fd;
717 	char buf[512];
718 
719 	if ((fd = open(bname, O_RDONLY)) < 0)
720 		return (0);
721 	if (read(fd, buf, sizeof (buf)) < 0)
722 		return (0);
723 	return (1);
724 }
725 
726 void
727 delete_hotspares_impl(mdsetname_t *sp, mdhspname_t *hspnp, md_hsp_t *hspp)
728 {
729 	md_hs_t *hsp;
730 	uint_t		hsi;
731 	char    *bname;
732 	md_error_t e = mdnullerror;
733 	int deleted_hs = 0;
734 
735 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
736 		mdnamelist_t *nlp;
737 
738 		hsp = &hspp->hotspares.hotspares_val[hsi];
739 		bname = hsp->hsnamep->bname;
740 		nlp = NULL;
741 		metanamelist_append(&nlp, hsp->hsnamep);
742 		/* print hotspare */
743 		if (hsp->state == HSS_AVAILABLE) {
744 			if (hotspare_ok(bname))
745 				continue;
746 
747 			fprintf(stderr,
748 				"NOTICE: Hotspare %s in %s has failed.\n"
749 				"\tDeleting %s since it not in use\n\n",
750 				bname, hspnp->hspname, bname);
751 
752 			if (meta_hs_delete(sp, hspnp, nlp, 0, &e) != NULL) {
753 				mde_perror(&e, "");
754 			} else {
755 				deleted_hs++;
756 			}
757 		}
758 	}
759 }
760 
761 
762 
763 /*
764  * Generic routine to issue ioctls
765  */
766 
767 void
768 md_setprobetest(md_probedev_t *iocp)
769 {
770 	(void) strcpy(iocp->test_name, MD_PROBE_OPEN_T);
771 }
772 
773 int
774 md_probe_ioctl(mdsetname_t *sp, mdnamelist_t *nlp, int ndevs, char *drvname)
775 {
776 	mdnamelist_t	*p;
777 	mdname_t	*np;
778 	md_probedev_t	probe_ioc,
779 			*iocp;
780 	int		i,
781 			retval = 0;
782 	/*
783 	 * Allocate space for all the metadevices and fill in
784 	 * the minor numbers.
785 	 */
786 
787 	memset(&probe_ioc, 0, sizeof (probe_ioc));
788 	iocp = &probe_ioc;
789 
790 	if ((iocp->mnum_list = (uintptr_t)calloc(ndevs, sizeof (minor_t)))
791 	    == 0) {
792 		perror("md_probe_ioctl: calloc");
793 		return (-1);
794 	}
795 
796 	MD_SETDRIVERNAME(iocp, drvname, sp->setno);
797 	md_setprobetest(iocp);
798 
799 	iocp->nmdevs = ndevs;
800 
801 	for (p = nlp, i = 0; p; p = p->next, i++) {
802 		np = p->namep;
803 		((minor_t *)(uintptr_t)iocp->mnum_list)[i] =
804 		    meta_getminor(np->dev);
805 	}
806 
807 
808 	if (metaioctl(MD_IOCPROBE_DEV, iocp, &(iocp->mde), NULL) != 0)
809 			retval = -1;
810 	return (retval);
811 }
812 /*
813  *
814  *  - remove p from nlp list
815  *  - put it on the toplp list.
816  *  - update the p to the next element
817  */
818 
819 void
820 add_to_list(mdnamelist_t **curpp, mdnamelist_t **prevpp, mdnamelist_t **newlpp)
821 {
822 	mdnamelist_t	*p, *prevp, *nlp;
823 
824 	p = *curpp;
825 	prevp = *prevpp;
826 	nlp = *newlpp;
827 
828 	if (prevp == p) {
829 		/* if first element reset prevp */
830 			prevp = p->next;
831 			p->next = nlp;
832 			nlp = p;
833 			p = prevp;
834 	} else {
835 		prevp->next = p->next;
836 		p->next = nlp;
837 		nlp = p;
838 		p = prevp->next;
839 	}
840 	*curpp = p;
841 	*prevpp = prevp;
842 	*newlpp = nlp;
843 }
844 /*
845  * Scans the given list of metadeivces and returns a list of top level
846  * metadevices.
847  * Note: The orignal list is not valid at the end and is set to NULL.
848  */
849 
850 int
851 get_toplevel_mds(mdsetname_t *sp, mdnamelist_t **lpp,
852 			mdnamelist_t **top_pp)
853 {
854 	mdnamelist_t	*p, *prevp, *toplp;
855 	int		ntopmd;
856 	md_common_t	*mdp;
857 	md_error_t	e = mdnullerror;
858 
859 	ntopmd = 0;
860 	prevp = p = *lpp;
861 	toplp = NULL;
862 
863 	while (p) {
864 		if ((mdp = meta_get_unit(sp, p->namep, &e)) == NULL) {
865 				prevp = p;
866 				p = p->next;
867 				continue;
868 		}
869 
870 		if (mdp->parent == MD_NO_PARENT) {
871 			/* increment the top level md count. */
872 			ntopmd++;
873 			add_to_list(&p, &prevp, &toplp);
874 		} else {
875 			prevp = p;
876 			p = p->next;
877 		}
878 	}
879 	*lpp = NULL;
880 	*top_pp = toplp;
881 
882 	return (ntopmd);
883 }
884 
885 int
886 get_namelist(mdnamelist_t **transdevlist, mdnamelist_t **devlist,
887 					char *dev_type)
888 {
889 	mdnamelist_t *np, *prevp;
890 	md_error_t	e = mdnullerror;
891 	char		*type_name;
892 	int		i = 0;
893 
894 	prevp = np = *transdevlist;
895 	while (np) {
896 		if ((type_name = metagetmiscname(np->namep, &e)) == NULL) {
897 			*devlist = NULL;
898 			return (-1);
899 		}
900 		if (strcmp(type_name, dev_type) == 0) {
901 			/* move it to the devlist */
902 			add_to_list(&np, &prevp, devlist);
903 			i++;
904 		} else {
905 			prevp = np;
906 			np = np->next;
907 		}
908 	}
909 	return (i);
910 }
911 
912 
913 mdnamelist_t *
914 create_nlp(mdsetname_t *sp)
915 {
916 	mdnamelist_t *np;
917 	md_error_t   e = mdnullerror;
918 
919 	if (np = (mdnamelist_t *)malloc(sizeof (mdnamelist_t))) {
920 		np->next = NULL;
921 		return (np);
922 	} else {
923 		/* error condition below */
924 		mde_perror(&e, "create_nlp: malloc failed\n");
925 		md_exit(sp, 1);
926 	}
927 	return (0);
928 }
929 
930 /*
931  * Create a list of metadevices associated with trans. top_pp points to
932  * this list. The number of components in the list are also returned.
933  */
934 int
935 create_trans_compslist(mdsetname_t *sp, mdnamelist_t **lpp,
936 				mdnamelist_t **top_pp)
937 {
938 	mdnamelist_t	*p, *tailp, *toplp, *newlp;
939 	int		ntoptrans;
940 	md_error_t	e = mdnullerror;
941 	md_trans_t	*tp;
942 
943 	ntoptrans = 0;
944 	p = *lpp;
945 	tailp = toplp = NULL;
946 	/*
947 	 * Scan the current list of trans devices. From that
948 	 * extract all the lower level metadevices and put them on
949 	 * toplp list.
950 	 */
951 
952 	while (p) {
953 		if (tp = meta_get_trans(sp, p->namep, &e)) {
954 			/*
955 			 * Check the master and log devices to see if they
956 			 * are metadevices
957 			 */
958 			if (metaismeta(tp->masternamep)) {
959 				/* get a mdnamelist_t. */
960 				newlp = create_nlp(sp);
961 				newlp->namep = tp->masternamep;
962 				if (toplp == NULL) {
963 					toplp = tailp = newlp;
964 				} else {
965 					tailp->next = newlp;
966 					tailp = newlp;
967 				}
968 				ntoptrans++;
969 			}
970 
971 			if (tp->lognamep && metaismeta(tp->lognamep)) {
972 				newlp = create_nlp(sp);
973 				newlp->namep = tp->lognamep;
974 				if (toplp == NULL) {
975 					toplp = tailp = newlp;
976 				} else {
977 					tailp->next = newlp;
978 					tailp = newlp;
979 				}
980 				ntoptrans++;
981 			}
982 			p = p->next;
983 		}
984 	}
985 	*top_pp = toplp;
986 	return (ntoptrans);
987 }
988 
989 void
990 probe_mirror_devs(mdsetname_t *sp)
991 {
992 	mdnamelist_t	*nlp, *toplp;
993 	int		cnt;
994 	md_error_t	e = mdnullerror;
995 
996 	nlp = toplp = NULL;
997 
998 	if (meta_get_mirror_names(sp, &nlp, 0, &e) > 0) {
999 		/*
1000 		 * We have some mirrors to probe
1001 		 * get a list of top-level mirrors
1002 		 */
1003 
1004 		cnt = get_toplevel_mds(sp, &nlp, &toplp);
1005 		if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_MIRROR) < 0))
1006 				perror("MD_IOCPROBE_DEV");
1007 	}
1008 	metafreenamelist(nlp);
1009 	metafreenamelist(toplp);
1010 
1011 }
1012 
1013 void
1014 probe_raid_devs(mdsetname_t *sp)
1015 {
1016 	mdnamelist_t	*nlp, *toplp;
1017 	int		cnt;
1018 	md_error_t	e = mdnullerror;
1019 
1020 	nlp = toplp = NULL;
1021 
1022 	if (meta_get_raid_names(sp, &nlp, 0, &e) > 0) {
1023 		/*
1024 		 * We have some mirrors to probe
1025 		 * get a list of top-level mirrors
1026 		 */
1027 
1028 		cnt = get_toplevel_mds(sp, &nlp, &toplp);
1029 
1030 		if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_RAID) < 0))
1031 			perror("MD_IOCPROBE_DEV");
1032 	}
1033 	metafreenamelist(nlp);
1034 	metafreenamelist(toplp);
1035 }
1036 
1037 /*
1038  * Trans probes are diffenent. -- so whats new.
1039  * we separate out the master and log device and then issue the
1040  * probe calls.
1041  * Since the underlying device could be disk, stripe, RAID or miror,
1042  * we have to sort them out and then call the ioctl for each.
1043  */
1044 
1045 void
1046 probe_trans_devs(mdsetname_t *sp)
1047 {
1048 	mdnamelist_t	*nlp, *toplp;
1049 	mdnamelist_t	*trans_raidlp, *trans_mmlp, *trans_stripelp;
1050 	int		cnt;
1051 	md_error_t	e = mdnullerror;
1052 
1053 	nlp = toplp = NULL;
1054 	trans_raidlp = trans_mmlp = trans_stripelp = NULL;
1055 
1056 	if (meta_get_trans_names(sp, &nlp, 0, &e) > 0) {
1057 		/*
1058 		 * get a list of master and log metadevices.
1059 		 */
1060 
1061 		cnt = create_trans_compslist(sp, &nlp, &toplp);
1062 
1063 		/* underlying RAID-5 components */
1064 
1065 		cnt = get_namelist(&toplp, &trans_raidlp, MD_RAID);
1066 		if ((cnt > 0) && (md_probe_ioctl(sp, trans_raidlp, cnt,
1067 		    MD_RAID) < 0))
1068 			perror("MD_IOCPROBE_DEV");
1069 
1070 		metafreenamelist(trans_raidlp);
1071 
1072 		/* underlying mirror components */
1073 
1074 		cnt = get_namelist(&toplp, &trans_mmlp, MD_MIRROR);
1075 
1076 		if ((cnt > 0) && (md_probe_ioctl(sp, trans_mmlp, cnt,
1077 		    MD_MIRROR) < 0))
1078 			perror("MD_IOCPROBE_DEV");
1079 
1080 		metafreenamelist(trans_mmlp);
1081 
1082 		/* underlying stripe components */
1083 
1084 		cnt = get_namelist(&toplp, &trans_stripelp, MD_STRIPE);
1085 		if ((cnt > 0) && (md_probe_ioctl(sp, trans_stripelp, cnt,
1086 		    MD_STRIPE) < 0))
1087 			perror("MD_IOCPROBE_DEV");
1088 		metafreenamelist(trans_stripelp);
1089 		metafreenamelist(nlp);
1090 	}
1091 }
1092 
1093 /*
1094  * probe hot spares. This is differs from other approaches since
1095  * there are no read/write routines through md. We check at the physical
1096  * component level and then delete it if its bad.
1097  */
1098 
1099 void
1100 probe_hotspare_devs(mdsetname_t *sp)
1101 {
1102 	mdhspnamelist_t *hspnlp = NULL;
1103 	int		cnt;
1104 	mdhspnamelist_t	*p;
1105 	md_hsp_t	*hspp;
1106 	md_error_t	e = mdnullerror;
1107 
1108 	if ((cnt = meta_get_hsp_names(sp, &hspnlp, 0, &e)) < 0) {
1109 		mderror(&e, MDE_UNIT_NOT_FOUND, NULL);
1110 		return;
1111 	} else if (cnt == 0) {
1112 		mderror(&e, MDE_NO_HSPS, NULL);
1113 		return;
1114 	}
1115 	for (p = hspnlp; (p != NULL); p = p->next) {
1116 		mdhspname_t	*hspnp = p->hspnamep;
1117 
1118 
1119 		if ((hspp = meta_get_hsp(sp, hspnp, &e)) == NULL)
1120 			continue;
1121 
1122 		if (hspp->hotspares.hotspares_len != 0) {
1123 			delete_hotspares_impl(sp, hspnp, hspp);
1124 		}
1125 	}
1126 	metafreehspnamelist(hspnlp);
1127 }
1128 
1129 static void
1130 probe_all_devs(mdsetname_t *sp)
1131 {
1132 	probe_hotspare_devs(sp);
1133 	probe_mirror_devs(sp);
1134 	probe_raid_devs(sp);
1135 	probe_trans_devs(sp);
1136 }
1137 
1138 /*
1139  * The following functions are used to print the concise output
1140  * of the metastat coommand (-c option).
1141  *
1142  * Normally the output for metastat is performed within libmeta via
1143  * the *_report functions within each of the metadevice specific files in
1144  * libmeta.  However, it is usually bad architecture for a library to
1145  * perform output since there are so many different ways that an application
1146  * can choose to do output (e.g. GUI, CLI, CIM, SNMP, etc.).  So, for the
1147  * concise output option we have moved the CLI output to the metastat
1148  * code and just use libmeta as the source of data to be printed.
1149  *
1150  * This function gets all of the different top-level metadevices in the set
1151  * and prints them.  It calls the print_concise_md() function to recursively
1152  * print the metadevices that underly the top-level metadevices.  It does
1153  * special handling for soft partitions so that all of the SPs on the
1154  * same underlying device are grouped and then that underlying device
1155  * is only printed once.
1156  */
1157 static void
1158 print_concise_diskset(mdsetname_t *sp)
1159 {
1160 	md_error_t		error = mdnullerror;
1161 	mdnamelist_t		*nl = NULL;
1162 	mdhspnamelist_t		*hsp_list = NULL;
1163 
1164 	/*
1165 	 * We do extra handling for soft parts since we want to find
1166 	 * all of the SPs on the same underlying device, group them and
1167 	 * print them together before printing the underlying device just
1168 	 * once.  This logic doesn't apply to any other metadevice type.
1169 	 */
1170 	if (meta_get_sp_names(sp, &nl, 0, &error) >= 0) {
1171 	    mdnamelist_t	*nlp;
1172 	    /* keep track of the softparts on the same underlying device */
1173 	    struct sp_base_list	*base_list = NULL;
1174 
1175 	    for (nlp = nl; nlp != NULL; nlp = nlp->next) {
1176 		mdname_t	*mdn;
1177 		md_sp_t		*soft_part;
1178 		mdnamelist_t	*tnlp;
1179 
1180 		mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
1181 		mdclrerror(&error);
1182 		if (mdn == NULL) {
1183 		    print_concise_entry(0, nlp->namep->cname, 0, 'p');
1184 		    printf("\n");
1185 		    continue;
1186 		}
1187 
1188 		soft_part = meta_get_sp_common(sp, mdn, 1, &error);
1189 		mdclrerror(&error);
1190 
1191 		if (soft_part == NULL ||
1192 		    MD_HAS_PARENT(soft_part->common.parent) ||
1193 		    sp_done(soft_part, base_list))
1194 		    continue;
1195 
1196 		/* print this soft part */
1197 		print_concise_entry(0, soft_part->common.namep->cname,
1198 		    soft_part->common.size, 'p');
1199 		(void) printf(" %s\n", soft_part->compnamep->cname);
1200 
1201 		/* keep track of the underlying device of this soft part */
1202 		base_list = sp_add_done(soft_part, base_list);
1203 
1204 		/*
1205 		 * now print all of the other soft parts on the same
1206 		 * underlying device
1207 		 */
1208 		for (tnlp = nlp->next; tnlp != NULL; tnlp = tnlp->next) {
1209 		    md_sp_t		*part;
1210 
1211 		    mdn = metaname(&sp, tnlp->namep->cname,
1212 		    META_DEVICE, &error);
1213 
1214 		    mdclrerror(&error);
1215 		    if (mdn == NULL)
1216 			continue;
1217 
1218 		    part = meta_get_sp_common(sp, mdn, 1, &error);
1219 		    mdclrerror(&error);
1220 
1221 		    if (part == NULL || MD_HAS_PARENT(part->common.parent) ||
1222 			! sp_match(part, base_list))
1223 			continue;
1224 
1225 		    /* on the same base so print this soft part */
1226 		    print_concise_entry(0, part->common.namep->cname,
1227 			part->common.size, 'p');
1228 		    (void) printf(" %s\n", part->compnamep->cname);
1229 		}
1230 
1231 		/*
1232 		 * print the common metadevice hierarchy under these soft parts
1233 		 */
1234 		print_concise_md(META_INDENT, sp, soft_part->compnamep);
1235 	    }
1236 
1237 	    free_names(&nl);
1238 	    sp_free_list(base_list);
1239 	}
1240 	mdclrerror(&error);
1241 
1242 	if (meta_get_trans_names(sp, &nl, 0, &error) >= 0)
1243 	    print_concise_namelist(sp, &nl, 't');
1244 	mdclrerror(&error);
1245 
1246 	if (meta_get_mirror_names(sp, &nl, 0, &error) >= 0)
1247 	    print_concise_namelist(sp, &nl, 'm');
1248 	mdclrerror(&error);
1249 
1250 	if (meta_get_raid_names(sp, &nl, 0, &error) >= 0)
1251 	    print_concise_namelist(sp, &nl, 'r');
1252 	mdclrerror(&error);
1253 
1254 	if (meta_get_stripe_names(sp, &nl, 0, &error) >= 0)
1255 	    print_concise_namelist(sp, &nl, 's');
1256 	mdclrerror(&error);
1257 
1258 	if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) {
1259 	    mdhspnamelist_t *nlp;
1260 
1261 	    for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) {
1262 		md_hsp_t	*hsp;
1263 
1264 		print_concise_entry(0, nlp->hspnamep->hspname, 0, 'h');
1265 
1266 		hsp = meta_get_hsp_common(sp, nlp->hspnamep, 1, &error);
1267 		mdclrerror(&error);
1268 		if (hsp != NULL) {
1269 		    int	i;
1270 
1271 		    for (i = 0; i < hsp->hotspares.hotspares_len; i++) {
1272 			md_hs_t	*hs;
1273 			char	*state;
1274 
1275 			hs = &hsp->hotspares.hotspares_val[i];
1276 
1277 			(void) printf(" %s", hs->hsnamep->cname);
1278 
1279 			state = get_hs_state(hs);
1280 			if (state != NULL)
1281 			    (void) printf(" (%s)", state);
1282 		    }
1283 		}
1284 
1285 		(void) printf("\n");
1286 	    }
1287 
1288 	    metafreehspnamelist(hsp_list);
1289 	}
1290 }
1291 
1292 /*
1293  * Print the top-level metadevices in the name list for concise output.
1294  */
1295 static void
1296 print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl, char mtype)
1297 {
1298 	mdnamelist_t	*nlp;
1299 	md_error_t	error = mdnullerror;
1300 
1301 	for (nlp = *nl; nlp != NULL; nlp = nlp->next) {
1302 	    mdname_t	*mdn;
1303 	    md_common_t	*u;
1304 
1305 	    mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error);
1306 	    mdclrerror(&error);
1307 	    if (mdn == NULL) {
1308 		print_concise_entry(0, nlp->namep->cname, 0, mtype);
1309 		printf("\n");
1310 		continue;
1311 	    }
1312 
1313 	    u = get_concise_unit(sp, mdn, &error);
1314 	    mdclrerror(&error);
1315 
1316 	    if (u != NULL && !MD_HAS_PARENT(u->parent))
1317 		print_concise_md(0, sp, mdn);
1318 	}
1319 
1320 	free_names(nl);
1321 }
1322 
1323 /*
1324  * Concise mirror output.
1325  */
1326 static void
1327 print_concise_mirror(int indent, mdsetname_t *sp, md_mirror_t *mirror)
1328 {
1329 	md_error_t	error = mdnullerror;
1330 	int		i;
1331 	md_status_t	status = mirror->common.state;
1332 
1333 	if (mirror == NULL)
1334 	    return;
1335 
1336 	print_concise_entry(indent, mirror->common.namep->cname,
1337 	    mirror->common.size, 'm');
1338 
1339 	for (i = 0; i < NMIRROR; i++) {
1340 	    uint_t	tstate = 0;
1341 	    char	*state;
1342 
1343 	    if (mirror->submirrors[i].submirnamep == NULL)
1344 		continue;
1345 	    (void) printf(" %s", mirror->submirrors[i].submirnamep->cname);
1346 
1347 	    if (mirror->submirrors[i].state & SMS_OFFLINE) {
1348 		(void) printf(gettext(" (offline)"));
1349 		continue;
1350 	    }
1351 
1352 	    if (metaismeta(mirror->submirrors[i].submirnamep))
1353 		(void) meta_get_tstate(mirror->submirrors[i].submirnamep->dev,
1354 		    &tstate, &error);
1355 
1356 	    state = get_sm_state(mirror, i, status, tstate);
1357 	    if (state != NULL)
1358 		(void) printf(" (%s)", state);
1359 	}
1360 
1361 	(void) printf("\n");
1362 
1363 	indent += META_INDENT;
1364 	for (i = 0; i < NMIRROR; i++) {
1365 	    if (mirror->submirrors[i].submirnamep == NULL)
1366 		continue;
1367 
1368 	    print_concise_md(indent, sp, mirror->submirrors[i].submirnamep);
1369 	}
1370 }
1371 
1372 /*
1373  * Concise raid output.
1374  */
1375 static void
1376 print_concise_raid(int indent, mdsetname_t *sp, md_raid_t *raid)
1377 {
1378 	md_error_t	error = mdnullerror;
1379 	int		i;
1380 	uint_t		tstate = 0;
1381 
1382 	if (raid == NULL)
1383 	    return;
1384 
1385 	print_concise_entry(indent, raid->common.namep->cname,
1386 	    raid->common.size, 'r');
1387 
1388 	if (metaismeta(raid->common.namep))
1389 	    (void) meta_get_tstate(raid->common.namep->dev, &tstate, &error);
1390 
1391 	for (i = 0; i < raid->cols.cols_len; i++) {
1392 	    md_raidcol_t	*colp = &raid->cols.cols_val[i];
1393 	    mdname_t		*namep = ((colp->hsnamep != NULL) ?
1394 				    colp->hsnamep : colp->colnamep);
1395 	    char		*hsname = ((colp->hsnamep != NULL) ?
1396 				    colp->hsnamep->cname : NULL);
1397 	    char		*col_state = NULL;
1398 
1399 	    (void) printf(" %s", colp->colnamep->cname);
1400 
1401 	    if (metaismeta(namep)) {
1402 		uint_t tstate = 0;
1403 
1404 		(void) meta_get_tstate(namep->dev, &tstate, &error);
1405 		col_state = get_raid_col_state(colp, tstate);
1406 
1407 	    } else {
1408 		if (tstate != 0)
1409 		    col_state = "-";
1410 		else
1411 		    col_state = get_raid_col_state(colp, tstate);
1412 	    }
1413 
1414 	    if (col_state != NULL) {
1415 		if (hsname != NULL)
1416 		    (void) printf(" (%s-%s)", col_state, hsname);
1417 		else
1418 		    (void) printf(" (%s)", col_state);
1419 
1420 	    } else if (hsname != NULL) {
1421 		(void) printf(gettext(" (spared-%s)"), hsname);
1422 	    }
1423 	}
1424 
1425 	(void) printf("\n");
1426 
1427 	indent += META_INDENT;
1428 	for (i = 0; i < raid->cols.cols_len; i++) {
1429 	    print_concise_md(indent, sp, raid->cols.cols_val[i].colnamep);
1430 	}
1431 }
1432 
1433 /*
1434  * Concise stripe output.
1435  */
1436 static void
1437 print_concise_stripe(int indent, mdsetname_t *sp, md_stripe_t *stripe)
1438 {
1439 	md_error_t	error = mdnullerror;
1440 	int		i;
1441 	uint_t		top_tstate = 0;
1442 
1443 	if (stripe == NULL)
1444 	    return;
1445 
1446 	print_concise_entry(indent, stripe->common.namep->cname,
1447 	    stripe->common.size, 's');
1448 
1449 	if (metaismeta(stripe->common.namep))
1450 	    (void) meta_get_tstate(stripe->common.namep->dev, &top_tstate,
1451 		&error);
1452 	mdclrerror(&error);
1453 
1454 	for (i = 0; i < stripe->rows.rows_len; i++) {
1455 	    md_row_t	*rowp;
1456 	    int		j;
1457 
1458 	    rowp = &stripe->rows.rows_val[i];
1459 
1460 	    for (j = 0; j < rowp->comps.comps_len; j++) {
1461 		md_comp_t	*comp;
1462 		uint_t		tstate = 0;
1463 		char		*comp_state = NULL;
1464 		char		*hsname;
1465 
1466 		comp = &rowp->comps.comps_val[j];
1467 		(void) printf(" %s", comp->compnamep->cname);
1468 
1469 		if (metaismeta(comp->compnamep)) {
1470 		    uint_t tstate = 0;
1471 		    (void) meta_get_tstate(comp->compnamep->dev, &tstate,
1472 			&error);
1473 		    comp_state = get_stripe_state(comp, tstate);
1474 		} else {
1475 		    if (top_tstate != 0)
1476 			comp_state = "-";
1477 		    else
1478 			comp_state = get_stripe_state(comp, tstate);
1479 		}
1480 
1481 		hsname = ((comp->hsnamep != NULL) ?
1482 		    comp->hsnamep->cname : NULL);
1483 
1484 		if (comp_state != NULL) {
1485 		    if (hsname != NULL)
1486 			(void) printf(" (%s-%s)", comp_state, hsname);
1487 		    else
1488 			(void) printf(" (%s)", comp_state);
1489 
1490 		} else if (hsname != NULL) {
1491 		    (void) printf(gettext(" (spared-%s)"), hsname);
1492 		}
1493 	    }
1494 	}
1495 
1496 	(void) printf("\n");
1497 
1498 	indent += META_INDENT;
1499 	for (i = 0; i < stripe->rows.rows_len; i++) {
1500 	    md_row_t	*rowp;
1501 	    int		j;
1502 
1503 	    rowp = &stripe->rows.rows_val[i];
1504 
1505 	    for (j = 0; j < rowp->comps.comps_len; j++) {
1506 		print_concise_md(indent, sp,
1507 		    rowp->comps.comps_val[j].compnamep);
1508 	    }
1509 	}
1510 }
1511 
1512 /*
1513  * Concise soft partition output.
1514  */
1515 static void
1516 print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part)
1517 {
1518 	if (part == NULL)
1519 	    return;
1520 
1521 	print_concise_entry(indent, part->common.namep->cname,
1522 	    part->common.size, 'p');
1523 
1524 	(void) printf(" %s\n", part->compnamep->cname);
1525 
1526 	print_concise_md(indent + META_INDENT, sp, part->compnamep);
1527 }
1528 
1529 /*
1530  * Concise trans output.
1531  */
1532 static void
1533 print_concise_trans(int indent, mdsetname_t *sp, md_trans_t *trans)
1534 {
1535 	if (trans == NULL)
1536 	    return;
1537 
1538 	print_concise_entry(indent, trans->common.namep->cname,
1539 	    trans->common.size, 't');
1540 
1541 	if (trans->masternamep != NULL)
1542 	    (void) printf(" %s", trans->masternamep->cname);
1543 
1544 	if (trans->lognamep != NULL)
1545 	    (void) printf(" %s", trans->lognamep->cname);
1546 
1547 	(void) printf("\n");
1548 
1549 	indent += META_INDENT;
1550 
1551 	print_concise_md(indent, sp, trans->masternamep);
1552 
1553 	print_concise_md(indent, sp, trans->lognamep);
1554 }
1555 
1556 /*
1557  * Recursive function for concise metadevice nested output.
1558  */
1559 static void
1560 print_concise_md(int indent, mdsetname_t *sp, mdname_t *np)
1561 {
1562 	md_error_t	error = mdnullerror;
1563 	md_unit_t	*u;
1564 	md_mirror_t	*mirror;
1565 	md_raid_t	*raid;
1566 	md_sp_t		*soft_part;
1567 	md_stripe_t	*stripe;
1568 	md_trans_t	*trans;
1569 
1570 	if (np == NULL || !metaismeta(np))
1571 	    return;
1572 
1573 	if ((u = meta_get_mdunit(sp, np, &error)) == NULL)
1574 	    return;
1575 
1576 	switch (u->c.un_type) {
1577 	case MD_DEVICE:
1578 	    stripe = meta_get_stripe_common(sp, np, 1, &error);
1579 	    print_concise_stripe(indent, sp, stripe);
1580 	    break;
1581 
1582 	case MD_METAMIRROR:
1583 	    mirror = meta_get_mirror(sp, np, &error);
1584 	    print_concise_mirror(indent, sp, mirror);
1585 	    break;
1586 
1587 	case MD_METATRANS:
1588 	    trans = meta_get_trans_common(sp, np, 1, &error);
1589 	    print_concise_trans(indent, sp, trans);
1590 	    break;
1591 
1592 	case MD_METARAID:
1593 	    raid = meta_get_raid_common(sp, np, 1, &error);
1594 	    print_concise_raid(indent, sp, raid);
1595 	    break;
1596 
1597 	case MD_METASP:
1598 	    soft_part = meta_get_sp_common(sp, np, 1, &error);
1599 	    print_concise_sp(indent, sp, soft_part);
1600 	    break;
1601 
1602 	default:
1603 	    return;
1604 	}
1605 }
1606 
1607 /*
1608  * Given a name get the unit for use in concise output.  We use the *_common
1609  * routines in libmeta which allow us to specify the "fast" flag, thereby
1610  * avoiding the DKIOCGGEOM ioctl that normally happens.
1611  */
1612 static md_common_t *
1613 get_concise_unit(mdsetname_t *sp, mdname_t *np, md_error_t *ep)
1614 {
1615 	char		*miscname;
1616 
1617 	/* short circuit */
1618 	if (np->drivenamep->unitp != NULL)
1619 		return (np->drivenamep->unitp);
1620 	if (metachkmeta(np, ep) != 0)
1621 		return (NULL);
1622 
1623 	/* dispatch */
1624 	if ((miscname = metagetmiscname(np, ep)) == NULL)
1625 		return (NULL);
1626 	else if (strcmp(miscname, MD_STRIPE) == 0)
1627 		return ((md_common_t *)meta_get_stripe_common(sp, np, 1, ep));
1628 	else if (strcmp(miscname, MD_MIRROR) == 0)
1629 		return ((md_common_t *)meta_get_mirror(sp, np, ep));
1630 	else if (strcmp(miscname, MD_TRANS) == 0)
1631 		return ((md_common_t *)meta_get_trans_common(sp, np, 1, ep));
1632 	else if (strcmp(miscname, MD_RAID) == 0)
1633 		return ((md_common_t *)meta_get_raid_common(sp, np, 1, ep));
1634 	else if (strcmp(miscname, MD_SP) == 0)
1635 		return ((md_common_t *)meta_get_sp_common(sp, np, 1, ep));
1636 	else {
1637 		(void) mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(np->dev),
1638 		    np->cname);
1639 		return (NULL);
1640 	}
1641 }
1642 
1643 static void
1644 free_names(mdnamelist_t **nlp)
1645 {
1646 	mdnamelist_t *p;
1647 
1648 	for (p = *nlp; p != NULL; p = p->next) {
1649 	    meta_invalidate_name(p->namep);
1650 	    p->namep = NULL;
1651 	}
1652 	metafreenamelist(*nlp);
1653 	*nlp = NULL;
1654 }
1655 
1656 /*
1657  * Submirror state for concise output.
1658  */
1659 static char *
1660 get_sm_state(md_mirror_t *mirror, int i, md_status_t mirror_status,
1661 	uint_t tstate)
1662 {
1663 	sm_state_t	state = mirror->submirrors[i].state;
1664 	uint_t		is_target =
1665 			    mirror->submirrors[i].flags & MD_SM_RESYNC_TARGET;
1666 
1667 	/*
1668 	 * Only return Unavailable if there is no flagged error on the
1669 	 * submirror. If the mirror has received any writes since the submirror
1670 	 * went into Unavailable state a resync is required. To alert the
1671 	 * administrator to this we return a 'Needs maintenance' message.
1672 	 */
1673 	if ((tstate != 0) && (state & SMS_RUNNING))
1674 		return (gettext("unavail"));
1675 
1676 	/* all is well */
1677 	if (state & SMS_RUNNING) {
1678 		if (!(mirror_status & MD_UN_OPT_NOT_DONE) ||
1679 		    ((mirror_status & MD_UN_OPT_NOT_DONE) && !is_target))
1680 			return (NULL);
1681 	}
1682 
1683 	/* resyncing, needs repair */
1684 	if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
1685 	    SMS_OFFLINE_RESYNC)) || (mirror_status & MD_UN_OPT_NOT_DONE)) {
1686 		static char buf[MAXPATHLEN];
1687 
1688 		if (mirror_status & MD_UN_RESYNC_ACTIVE) {
1689 
1690 		    if (mirror->common.revision & MD_64BIT_META_DEV) {
1691 			(void) snprintf(buf, sizeof (buf),
1692 			    gettext("resync-%2d.%1d%%"),
1693 			    mirror->percent_done / 10,
1694 			    mirror->percent_done % 10);
1695 		    } else {
1696 			(void) snprintf(buf, sizeof (buf),
1697 			    gettext("resync-%d%%"), mirror->percent_done);
1698 		    }
1699 		    return (buf);
1700 		}
1701 		return (gettext("maint"));
1702 	}
1703 
1704 	/* needs repair */
1705 	if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE))
1706 		return (gettext("maint"));
1707 
1708 	/* unknown */
1709 	return (gettext("unknown"));
1710 }
1711 
1712 /*
1713  * Raid component state for concise output.
1714  */
1715 static char *
1716 get_raid_col_state(md_raidcol_t *colp, uint_t tstate)
1717 {
1718 	if (tstate != 0)
1719 	    return (gettext("unavail"));
1720 
1721 	return (meta_get_raid_col_state(colp->state));
1722 }
1723 
1724 /*
1725  * Stripe state for concise output.
1726  */
1727 static char *
1728 get_stripe_state(md_comp_t *mdcp, uint_t tstate)
1729 {
1730 	comp_state_t	state = mdcp->state;
1731 
1732 	if (tstate != 0)
1733 	    return ("unavail");
1734 
1735 	return (meta_get_stripe_state(state));
1736 }
1737 
1738 /*
1739  * Hostspare state for concise output.
1740  */
1741 static char *
1742 get_hs_state(md_hs_t *hsp)
1743 {
1744 	hotspare_states_t	state = hsp->state;
1745 
1746 	return (meta_get_hs_state(state));
1747 }
1748 
1749 
1750 /*
1751  * Keep track of printed soft partitions for concise output.
1752  */
1753 static struct sp_base_list *
1754 sp_add_done(md_sp_t *part, struct sp_base_list *lp)
1755 {
1756 	struct sp_base_list *n;
1757 
1758 	n = (struct sp_base_list *)malloc(sizeof (struct sp_base_list));
1759 	if (n == NULL)
1760 	    return (lp);
1761 
1762 	if ((n->base = strdup(part->compnamep->cname)) == NULL) {
1763 	    free(n);
1764 	    return (lp);
1765 	}
1766 
1767 	n->next = lp;
1768 
1769 	return (n);
1770 }
1771 
1772 /*
1773  * Keep track of printed soft partitions for concise output.
1774  */
1775 static int
1776 sp_done(md_sp_t *part, struct sp_base_list *lp)
1777 {
1778 	for (; lp != NULL; lp = lp->next) {
1779 	    if (strcmp(lp->base, part->compnamep->cname) == 0)
1780 		return (1);
1781 	}
1782 
1783 	return (0);
1784 }
1785 
1786 /*
1787  * Check the first element for a match.
1788  */
1789 static int
1790 sp_match(md_sp_t *part, struct sp_base_list *lp)
1791 {
1792 	if (lp != NULL && strcmp(lp->base, part->compnamep->cname) == 0)
1793 	    return (1);
1794 
1795 	return (0);
1796 }
1797 
1798 /*
1799  * Free memory used for soft partition printed status in concise output.
1800  */
1801 static void
1802 sp_free_list(struct sp_base_list *lp)
1803 {
1804 	struct sp_base_list *n;
1805 
1806 	for (; lp != NULL; lp = n) {
1807 	    n = lp->next;
1808 	    free(lp->base);
1809 	    free(lp);
1810 	}
1811 }
1812