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