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