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