xref: /illumos-gate/usr/src/cmd/raidctl/raidctl.c (revision bb0ade0978a02d3fe0b0165cd4725fdcb593fbfb)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * raidctl.c is the entry file of RAID configuration utility.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <ctype.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <langinfo.h>
35 #include <regex.h>
36 #include <locale.h>
37 #include <libintl.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <unistd.h>
43 #include <errno.h>
44 #include <libgen.h>
45 #include <raidcfg.h>
46 
47 
48 #define	TRUE		1
49 #define	FALSE		0
50 
51 #ifndef TEXT_DOMAIN
52 #define	TEXT_DOMAIN "SYS_TEST"
53 #endif
54 
55 /*
56  * Return value of command
57  */
58 #define	SUCCESS		0
59 #define	INVALID_ARG	1
60 #define	FAILURE		2
61 
62 /*
63  * Initial value of variables
64  */
65 #define	INIT_HANDLE_VALUE	-3
66 #define	MAX64BIT		0xffffffffffffffffull
67 #define	MAX32BIT		0xfffffffful
68 
69 /*
70  * Flag of set or unset HSP
71  */
72 #define	HSP_SET		1
73 #define	HSP_UNSET	0
74 
75 /*
76  * Operate codes of command
77  */
78 #define	DO_HW_RAID_NOP		-1
79 #define	DO_HW_RAID_HELP		0
80 #define	DO_HW_RAID_CREATEO	1
81 #define	DO_HW_RAID_CREATEN	2
82 #define	DO_HW_RAID_DELETE	3
83 #define	DO_HW_RAID_LIST		4
84 #define	DO_HW_RAID_FLASH	5
85 #define	DO_HW_RAID_HSP		6
86 #define	DO_HW_RAID_SET_ATTR	7
87 #define	DO_HW_RAID_SNAPSHOT	8
88 
89 #define	LOWER_H	(1 << 0)
90 #define	LOWER_C	(1 << 1)
91 #define	LOWER_D	(1 << 2)
92 #define	LOWER_L	(1 << 3)
93 #define	LOWER_R	(1 << 4)
94 #define	LOWER_Z	(1 << 5)
95 #define	LOWER_G	(1 << 6)
96 #define	LOWER_A	(1 << 7)
97 #define	LOWER_S	(1 << 8)
98 #define	LOWER_P	(1 << 9)
99 #define	LOWER_F	(1 << 10)
100 #define	UPPER_S	(1 << 11)
101 #define	UPPER_C	(1 << 12)
102 #define	UPPER_F	(1 << 13)
103 
104 /* Add a ARRAY state (temporary) */
105 #define	ARRAY_STATE_SYNC	100
106 
107 /*
108  * Function and strings to properly localize our prompt.
109  * So for example in German it would ask (ja/nein) or (yes/no) in
110  * english.
111  */
112 #ifndef SCHAR_MAX
113 #define	SCHAR_MAX	10
114 #endif
115 
116 #define	RAIDCTL_LOCKF "/var/run/lockf_raidctl"
117 
118 /* Locale setting */
119 static int	yes(void);
120 static int	rpmatch(char *s);
121 static char	*yesstr = NULL;
122 static char	*nostr = NULL;
123 static char	*yesexpr = NULL;
124 
125 static char	*default_yesexpr = "^[yY]";
126 static char	*default_yesstr = "yes";
127 static char	*default_nostr = "no";
128 
129 static regex_t	re;
130 
131 #define	SET_DEFAULT_STRS \
132 	regfree(&re); \
133 	free(yesexpr); \
134 	free(yesstr); \
135 	free(nostr); \
136 	yesexpr = default_yesexpr; \
137 	yesstr = default_yesstr; \
138 	nostr = default_nostr;
139 
140 #define	FREE_STRS \
141 	if (yesexpr != default_yesexpr) \
142 		free(yesexpr); \
143 	if (yesstr != default_yesstr) \
144 		free(yesstr); \
145 	if (nostr != default_nostr) \
146 		free(nostr);
147 
148 /* program name */
149 static char	*prog_namep;
150 
151 
152 /*
153  * Functions declaration
154  */
155 static void helpinfo(char *prog_namep);
156 static int do_create_cidl(char *raid_levelp, char *capacityp, char *disk_argp,
157     char *stripe_sizep, uint32_t f_flag, char **argv, uint32_t optind);
158 static int do_create_ctd(char *raid_levelp, char **disks_argpp,
159     uint32_t disks_num, uint32_t argindex, uint32_t f_flag);
160 static int do_list(char *disk_argp, char **argv, uint32_t optind,
161     uint8_t is_snapshot);
162 static int do_delete(uint32_t f_flag, char **argv, uint32_t optind);
163 static int do_flash(uint8_t f_flag, char *filep, char **ctls_argpp,
164     uint32_t index, uint32_t ctl_num);
165 static int do_set_hsp(char *a_argp, char *disk_argp, char **argv,
166     uint32_t optind);
167 static int do_set_array_attr(uint32_t f_flag, char *p_argp, char **argv,
168     uint32_t optind);
169 static int snapshot_raidsystem(uint8_t recursive, uint8_t indent,
170     uint8_t is_snapshot);
171 static int snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive,
172     uint8_t indent, uint8_t is_snapshot);
173 static int snapshot_array(raid_obj_handle_t array_handle,
174     uint8_t indent, uint8_t is_sub, uint8_t is_snapshot);
175 static int snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle,
176     uint8_t indent, uint8_t is_snapshot);
177 static int print_ctl_table(raid_obj_handle_t ctl_handle);
178 static int print_array_table(raid_obj_handle_t ctl_handle,
179     raid_obj_handle_t array_handle);
180 static int print_disk_table(raid_obj_handle_t ctl_handle,
181     raid_obj_handle_t disk_handle);
182 static int print_ctl_attr(raidcfg_controller_t *attrp);
183 static int print_array_attr(raidcfg_array_t *attrp);
184 static int print_arraypart_attr(raidcfg_arraypart_t *attrp);
185 static int print_disk_attr(raid_obj_handle_t ctl_handle,
186     raid_obj_handle_t disk_handle, raidcfg_disk_t *attrp);
187 static void print_indent(uint8_t indent);
188 static int get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp,
189     int *comps_nump, raid_obj_handle_t **handlespp);
190 static int get_disk_handle_ctd(int disks_num, char **disks_argpp,
191     uint32_t *ctl_tagp, raid_obj_handle_t *disks_handlep);
192 static int get_ctl_tag(char *argp, uint32_t *ctl_tagp);
193 static int get_array_tag(char *argp, uint32_t *ctl_tagp,
194     array_tag_t *array_tagp);
195 static int get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp,
196     uint32_t *controller_id);
197 static int get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp);
198 static int calc_size(char *sizep, uint64_t *valp);
199 static int is_fully_numeric(char *strp);
200 static int size_to_string(uint64_t size, char *string, int len);
201 static int enter_raidctl_lock(int *fd);
202 static void exit_raidctl_lock(int fd);
203 
204 /*
205  * Entry function of raidctl command
206  */
207 int
208 main(int argc, char **argv)
209 {
210 	/* operation index */
211 	int8_t findex = DO_HW_RAID_NOP;
212 
213 	/* argument pointers */
214 	char *r_argp = NULL;
215 	char *z_argp = NULL;
216 	char *g_argp = NULL;
217 	char *a_argp = NULL;
218 	char *s_argp = NULL;
219 	char *p_argp = NULL;
220 	char *F_argp = NULL;
221 	char *C_argp = NULL;
222 
223 	/*
224 	 * operation flags.
225 	 */
226 	uint8_t r_flag = FALSE;
227 	uint8_t f_flag = FALSE;
228 	uint8_t action = FALSE;
229 	uint64_t options = 0;
230 
231 	/* index and temporary variables */
232 	int ret;
233 	int status;
234 	char c = '\0';
235 
236 	/* fd for the filelock */
237 	int fd;
238 
239 	if (enter_raidctl_lock(&fd) != SUCCESS) {
240 		return (FAILURE);
241 	}
242 
243 	(void) setlocale(LC_ALL, "");
244 	(void) textdomain(TEXT_DOMAIN);
245 
246 	/* parse command line, and get program name */
247 	if ((prog_namep = strrchr(argv[0], '/')) == NULL) {
248 		prog_namep = argv[0];
249 	} else {
250 		prog_namep++;
251 	}
252 
253 	/* close error option messages from getopt */
254 	opterr = 0;
255 
256 	/* get yes expression according to current locale */
257 	yesexpr = strdup(nl_langinfo(YESEXPR));
258 	yesstr = strdup(nl_langinfo(YESSTR));
259 	nostr = strdup(nl_langinfo(NOSTR));
260 	if (yesexpr == NULL || yesstr == NULL || nostr == NULL) {
261 		return (FAILURE);
262 	}
263 
264 	/*
265 	 * If the was no expression or if there is a compile error
266 	 * use default yes expression.
267 	 */
268 	status = regcomp(&re, yesexpr, REG_EXTENDED | REG_NOSUB);
269 	if ((*yesexpr == (char)NULL) ||
270 	    (*yesstr == (char)NULL) ||
271 	    (*nostr == (char)NULL) ||
272 	    (status != 0)) {
273 		SET_DEFAULT_STRS;
274 		if (regcomp(&re, default_yesexpr,
275 		    REG_EXTENDED | REG_NOSUB) != 0) {
276 			return (FALSE);
277 		}
278 	}
279 
280 	while ((c = getopt(argc, argv,
281 	    "?hC:cdlF:r:z:g:a:s:p:fS")) != EOF) {
282 		switch (c) {
283 		case 'h':
284 		case '?':
285 			if (action == FALSE) {
286 				findex = DO_HW_RAID_HELP;
287 				action = TRUE;
288 				options |= LOWER_H;
289 			} else {
290 				findex = DO_HW_RAID_NOP;
291 			}
292 			break;
293 		case 'C':
294 			if (action == FALSE) {
295 				findex = DO_HW_RAID_CREATEN;
296 				C_argp = optarg;
297 				action = TRUE;
298 				options |= UPPER_C;
299 			} else {
300 				findex = DO_HW_RAID_NOP;
301 			}
302 			break;
303 		case 'c':
304 			if (action == FALSE) {
305 				findex = DO_HW_RAID_CREATEO;
306 				action = TRUE;
307 				options |= LOWER_C;
308 			} else {
309 				findex = DO_HW_RAID_NOP;
310 			}
311 			break;
312 		case 'd':
313 			if (action == FALSE) {
314 				findex = DO_HW_RAID_DELETE;
315 				action = TRUE;
316 				options |= LOWER_D;
317 			} else {
318 				findex = DO_HW_RAID_NOP;
319 			}
320 			break;
321 		case 'l':
322 			if (action == FALSE) {
323 				findex = DO_HW_RAID_LIST;
324 				action = TRUE;
325 				options |= LOWER_L;
326 			} else {
327 				findex = DO_HW_RAID_NOP;
328 			}
329 			break;
330 		case 'F':
331 			if (action == FALSE) {
332 				findex = DO_HW_RAID_FLASH;
333 				F_argp = optarg;
334 				action = TRUE;
335 				options |= UPPER_F;
336 			} else {
337 				findex = DO_HW_RAID_NOP;
338 			}
339 			break;
340 		case 'a':
341 			if (action == FALSE) {
342 				findex = DO_HW_RAID_HSP;
343 				a_argp = optarg;
344 				action = TRUE;
345 				options |= LOWER_A;
346 			} else {
347 				findex = DO_HW_RAID_NOP;
348 			}
349 			break;
350 		case 'p':
351 			if (action == FALSE) {
352 				findex = DO_HW_RAID_SET_ATTR;
353 				p_argp = optarg;
354 				action = TRUE;
355 				options |= LOWER_P;
356 			} else {
357 				findex = DO_HW_RAID_NOP;
358 			}
359 			break;
360 		case 'r':
361 			r_argp = optarg;
362 			r_flag = TRUE;
363 			options |= LOWER_R;
364 			break;
365 		case 'z':
366 			z_argp = optarg;
367 			options |= LOWER_Z;
368 			break;
369 		case 'g':
370 			g_argp = optarg;
371 			options |= LOWER_G;
372 			break;
373 		case 's':
374 			s_argp = optarg;
375 			options |= LOWER_S;
376 			break;
377 		case 'f':
378 			f_flag = TRUE;
379 			options |= LOWER_F;
380 			break;
381 		case 'S':
382 			if (action == FALSE) {
383 				findex = DO_HW_RAID_SNAPSHOT;
384 				action = TRUE;
385 				options |= UPPER_S;
386 			} else {
387 				findex = DO_HW_RAID_NOP;
388 			}
389 			break;
390 		default:
391 			(void) fprintf(stderr,
392 			    gettext("Invalid argument(s).\n"));
393 			exit_raidctl_lock(fd);
394 			FREE_STRS;
395 			regfree(&re);
396 			return (INVALID_ARG);
397 		}
398 	}
399 
400 	/* parse options */
401 	switch (findex) {
402 	case DO_HW_RAID_HELP:
403 		if ((options & ~(LOWER_H)) != 0) {
404 			ret = INVALID_ARG;
405 		} else {
406 			helpinfo(prog_namep);
407 			ret = SUCCESS;
408 		}
409 		break;
410 	case DO_HW_RAID_CREATEO:
411 		if ((options & ~(LOWER_F | LOWER_C | LOWER_R)) != 0) {
412 			ret = INVALID_ARG;
413 		} else {
414 			if (r_flag != FALSE && f_flag == FALSE) {
415 				ret = do_create_ctd(r_argp, argv, argc - 4,
416 				    optind, f_flag);
417 			} else if (r_flag == FALSE && f_flag == FALSE) {
418 				ret = do_create_ctd(NULL, argv, argc - 2,
419 				    optind, f_flag);
420 			} else if (r_flag != FALSE && f_flag != FALSE) {
421 				ret = do_create_ctd(r_argp, argv, argc - 5,
422 				    optind, f_flag);
423 			} else {
424 				ret = do_create_ctd(NULL, argv, argc - 3,
425 				    optind, f_flag);
426 			}
427 		}
428 		break;
429 	case DO_HW_RAID_CREATEN:
430 		if ((options & ~(LOWER_F | UPPER_C | LOWER_R | LOWER_Z |
431 		    LOWER_S)) != 0) {
432 			ret = INVALID_ARG;
433 		} else {
434 			ret = do_create_cidl(r_argp, z_argp, C_argp, s_argp,
435 			    f_flag, argv, optind);
436 		}
437 		break;
438 	case DO_HW_RAID_DELETE:
439 		if ((options & ~(LOWER_F | LOWER_D)) != 0) {
440 			ret = INVALID_ARG;
441 		} else {
442 			ret = do_delete(f_flag, argv, optind);
443 		}
444 		break;
445 	case DO_HW_RAID_LIST:
446 		if ((options & ~(LOWER_L | LOWER_G)) != 0) {
447 			ret = INVALID_ARG;
448 		} else {
449 			ret = do_list(g_argp, argv, optind, FALSE);
450 		}
451 		break;
452 	case DO_HW_RAID_SNAPSHOT:
453 		if ((options & ~(UPPER_S | LOWER_G)) != 0) {
454 			ret = INVALID_ARG;
455 		} else {
456 			ret = do_list(g_argp, argv, optind, TRUE);
457 		}
458 		break;
459 	case DO_HW_RAID_FLASH:
460 		if ((options & ~(LOWER_F | UPPER_F)) != 0) {
461 			ret = INVALID_ARG;
462 		} else {
463 			if (f_flag == FALSE) {
464 				ret = do_flash(f_flag, F_argp, argv, optind,
465 				    argc - 3);
466 			} else {
467 				ret = do_flash(f_flag, F_argp, argv, optind,
468 				    argc - 4);
469 			}
470 		}
471 		break;
472 	case DO_HW_RAID_HSP:
473 		if ((options & ~(LOWER_A | LOWER_G)) != 0) {
474 			ret = INVALID_ARG;
475 		} else {
476 			ret = do_set_hsp(a_argp, g_argp, argv, optind);
477 		}
478 		break;
479 	case DO_HW_RAID_SET_ATTR:
480 		if ((options & ~(LOWER_F | LOWER_P)) != 0) {
481 			ret = INVALID_ARG;
482 		} else {
483 			ret = do_set_array_attr(f_flag, p_argp, argv, optind);
484 		}
485 		break;
486 	case DO_HW_RAID_NOP:
487 		if (argc == 1) {
488 			ret = do_list(g_argp, argv, optind, FALSE);
489 		} else {
490 			ret = INVALID_ARG;
491 		}
492 		break;
493 	default:
494 		ret = INVALID_ARG;
495 		break;
496 	}
497 
498 	if (ret == INVALID_ARG) {
499 		(void) fprintf(stderr,
500 		    gettext("Invalid argument(s).\n"));
501 	}
502 	exit_raidctl_lock(fd);
503 
504 	FREE_STRS;
505 	regfree(&re);
506 	return (ret);
507 }
508 
509 /*
510  * helpinfo(prog_namep)
511  * This function prints help informations for usrs.
512  */
513 static void
514 helpinfo(char *prog_namep)
515 {
516 	char quote = '"';
517 
518 	(void) printf(gettext("%s [-f] -C %c<disks>%c [-r <raid_level>] "
519 	    "[-z <capacity>] [-s <stripe_size>] <controller>\n"), prog_namep,
520 	    quote, quote);
521 
522 	(void) printf(gettext("%s [-f] -d <volume>\n"), prog_namep);
523 
524 	(void) printf(gettext("%s [-f] -F <filename> <controller1> "
525 	    "[<controller2> ...]\n"), prog_namep);
526 
527 	(void) printf(gettext("%s [-f] -p %c<param>=<value>%c <volume>\n"),
528 	    prog_namep, quote, quote);
529 
530 	(void) printf(gettext("%s [-f] -c [-r <raid_level>] <disk1> <disk2> "
531 	    "[<disk3> ...]\n"), prog_namep);
532 
533 	(void) printf(gettext("%s [-l]\n"), prog_namep);
534 
535 	(void) printf(gettext("%s -l -g <disk> <controller>\n"), prog_namep);
536 
537 	(void) printf(gettext("%s -l <volume>\n"), prog_namep);
538 
539 	(void) printf(gettext("%s -l <controller1> [<controller2> ...]\n"),
540 	    prog_namep);
541 
542 	(void) printf(gettext("%s -a {set | unset} -g <disk> "
543 	    "{<volume> | <controller>}\n"), prog_namep);
544 
545 	(void) printf(gettext("%s -S [<volume> | <controller>]\n"), prog_namep);
546 
547 	(void) printf(gettext("%s -S -g <disk> <controller>\n"), prog_namep);
548 
549 	(void) printf(gettext("%s -h\n"), prog_namep);
550 }
551 
552 /*
553  * do_create_cidl(raid_levelp, capacityp, disks_argp, stripe_sizep,
554  * f_flag, argv, optind)
555  * This function creates a new RAID volume with specified arguments,
556  * and returns result as SUCCESS, INVALID_ARG or FAILURE.
557  * The "c.id.l" is used to express single physical disk. 'c' expresses
558  * bus number, 'id' expresses target number, and 'l' expresses lun.
559  * The physical disks represented by c.id.l may be invisible to OS, which
560  * means physical disks attached to controllers are not accessible by
561  * OS directly. The disks should be organized as a logical volume, and
562  * the logical volume is exported to OS as a single unit. Some hardware
563  * RAID controllers also support physical disks accessed by OS directly,
564  * for example LSI1068. In this case, it's both OK to express physical
565  * disk by c.id.l format or canonical ctd format.
566  */
567 static int
568 do_create_cidl(char *raid_levelp, char *capacityp, char *disks_argp,
569 	char *stripe_sizep, uint32_t f_flag, char **argv, uint32_t optind)
570 {
571 	uint32_t ctl_tag = MAX32BIT;
572 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
573 	uint32_t raid_level = RAID_LEVEL_1;
574 	uint64_t capacity = 0;
575 	uint64_t stripe_size = (uint64_t)OBJ_ATTR_NONE;
576 	raid_obj_handle_t *disk_handlesp = NULL;
577 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
578 	raidcfg_controller_t ctl_attr;
579 	int comps_num = 0;
580 	int ret = 0;
581 
582 	raidcfg_array_t array_attr;
583 
584 	if (argv[optind] == NULL || argv[optind + 1] != NULL) {
585 		return (INVALID_ARG);
586 	}
587 
588 	if (disks_argp == NULL) {
589 		return (INVALID_ARG);
590 	}
591 
592 	/* Check controller tag */
593 	if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) {
594 		return (INVALID_ARG);
595 	}
596 
597 	ctl_handle = raidcfg_get_controller(ctl_tag);
598 	if (ctl_handle <= 0) {
599 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
600 		return (FAILURE);
601 	}
602 
603 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
604 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
605 		return (FAILURE);
606 	}
607 
608 	/* Get raid level */
609 	if (raid_levelp != NULL) {
610 		if (*raid_levelp == '1' &&
611 		    (*(raid_levelp + 1) == 'E' || *(raid_levelp + 1) == 'e')) {
612 			raid_level = RAID_LEVEL_1E;
613 		} else {
614 			if (is_fully_numeric(raid_levelp) == FALSE) {
615 				return (INVALID_ARG);
616 			}
617 
618 			switch (atoi(raid_levelp)) {
619 			case 0:
620 				raid_level = RAID_LEVEL_0;
621 				break;
622 			case 1:
623 				raid_level = RAID_LEVEL_1;
624 				break;
625 			case 5:
626 				raid_level = RAID_LEVEL_5;
627 				break;
628 			case 10:
629 				raid_level = RAID_LEVEL_10;
630 				break;
631 			case 50:
632 				raid_level = RAID_LEVEL_50;
633 				break;
634 			default:
635 				return (INVALID_ARG);
636 			}
637 		}
638 	}
639 
640 	/*
641 	 * The rang check of capacity and stripe size is performed in library,
642 	 * and it relates to hardware feature.
643 	 */
644 
645 	/* Capacity in bytes. Capacity 0 means max available space. */
646 	if (capacityp != NULL) {
647 		if (*capacityp == '-' ||
648 		    calc_size(capacityp, &capacity) != SUCCESS) {
649 			return (INVALID_ARG);
650 		}
651 	}
652 
653 	/* Stripe size in bytes */
654 	if (stripe_sizep != NULL) {
655 		if (calc_size(stripe_sizep, &stripe_size) != SUCCESS ||
656 		    *stripe_sizep == '-') {
657 			return (INVALID_ARG);
658 		}
659 	}
660 
661 	/* Open controller before accessing its object */
662 	if ((ret = raidcfg_open_controller(ctl_handle, NULL)) < 0) {
663 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
664 		return (FAILURE);
665 	}
666 
667 	/* Get disks' handles */
668 	if ((ret = get_disk_handle_cidl(ctl_tag, disks_argp, &comps_num,
669 	    &disk_handlesp)) != SUCCESS) {
670 		(void) raidcfg_close_controller(ctl_handle, NULL);
671 		return (ret);
672 	}
673 
674 	if (f_flag == FALSE) {
675 		(void) fprintf(stdout, gettext("Creating RAID volume "
676 		    "will destroy all data on spare space of member disks, "
677 		    "proceed (%s/%s)? "), yesstr, nostr);
678 		if (!yes()) {
679 			(void) fprintf(stdout, gettext("RAID volume "
680 			    "not created.\n\n"));
681 			(void) raidcfg_close_controller(ctl_handle, NULL);
682 			free(disk_handlesp);
683 			return (SUCCESS);
684 		}
685 	}
686 
687 	/* Create array */
688 	array_handle = raidcfg_create_array(comps_num,
689 	    disk_handlesp, raid_level, capacity, stripe_size, NULL);
690 
691 	if (array_handle <= 0) {
692 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
693 		free(disk_handlesp);
694 		(void) raidcfg_close_controller(ctl_handle, NULL);
695 		return (FAILURE);
696 	}
697 
698 	/* Get attribute of the new created array */
699 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
700 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
701 		free(disk_handlesp);
702 		(void) raidcfg_close_controller(ctl_handle, NULL);
703 		return (FAILURE);
704 	}
705 
706 	(void) fprintf(stdout, gettext("Volume c%ut%llud%llu is created "
707 	    "successfully!\n"), ctl_tag, array_attr.tag.idl.target_id,
708 	    array_attr.tag.idl.lun);
709 
710 	/* Print attribute of array */
711 	(void) print_array_table(ctl_handle, array_handle);
712 
713 	/* Close controller */
714 	(void) raidcfg_close_controller(ctl_handle, NULL);
715 
716 	free(disk_handlesp);
717 	return (SUCCESS);
718 }
719 
720 /*
721  * do_create_ctd(raid_levelp, disks_argpp, disks_num, argindex, f_flag)
722  * This function creates array with specified arguments, and return result
723  * as SUCCESS, FAILURE, or INVALID_ARG. It only supports LSI MPT controller
724  * to be compatible with old raidctl. The capacity and stripe size can't
725  * be specified for LSI MPT controller, and they use zero and default value.
726  * The "ctd" is the canonical expression of physical disks which are
727  * accessible by OS.
728  */
729 static int
730 do_create_ctd(char *raid_levelp, char **disks_argpp, uint32_t disks_num,
731 	uint32_t argindex, uint32_t f_flag)
732 {
733 	uint32_t ctl_tag = MAX32BIT;
734 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
735 	uint32_t raid_level = RAID_LEVEL_1;
736 	uint64_t capacity = 0;
737 	uint32_t stripe_size = (uint32_t)OBJ_ATTR_NONE;
738 	raid_obj_handle_t *disk_handlesp = NULL;
739 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
740 	raidcfg_controller_t ctl_attr;
741 	int ret;
742 
743 	raidcfg_array_t array_attr;
744 	int i, j;
745 
746 	/* Check disks parameter */
747 	if (disks_argpp == NULL || disks_num < 2) {
748 		return (INVALID_ARG);
749 	}
750 
751 	for (i = 0, j = argindex; i < disks_num; i++, j++) {
752 		if (disks_argpp[j] == NULL) {
753 			return (INVALID_ARG);
754 		}
755 	}
756 
757 	/*
758 	 * We need check if the raid_level string is fully numeric. If user
759 	 * input string with unsupported letters, such as "s10", atoi() will
760 	 * return zero because it is an illegal string, but it doesn't mean
761 	 * RAID_LEVEL_0.
762 	 */
763 	if (raid_levelp != NULL) {
764 		if (*raid_levelp == '1' &&
765 		    (*(raid_levelp + 1) == 'E' || *(raid_levelp + 1) == 'e')) {
766 			raid_level = RAID_LEVEL_1E;
767 		} else {
768 			if (is_fully_numeric(raid_levelp) == FALSE) {
769 				return (INVALID_ARG);
770 			}
771 
772 			switch (atoi(raid_levelp)) {
773 			case 0:
774 				raid_level = RAID_LEVEL_0;
775 				break;
776 			case 1:
777 				raid_level = RAID_LEVEL_1;
778 				break;
779 			case 5:
780 				raid_level = RAID_LEVEL_5;
781 				break;
782 			default:
783 				return (INVALID_ARG);
784 			}
785 		}
786 	}
787 
788 	/* Get disks tag and controller tag */
789 	disk_handlesp = (raid_obj_handle_t *)calloc(disks_num + 2,
790 	    sizeof (raid_obj_handle_t));
791 	if (disk_handlesp == NULL) {
792 		return (FAILURE);
793 	}
794 
795 	disk_handlesp[0] = OBJ_SEPARATOR_BEGIN;
796 	disk_handlesp[disks_num + 1] = OBJ_SEPARATOR_END;
797 
798 	if ((ret = get_disk_handle_ctd(disks_num, &disks_argpp[argindex],
799 	    &ctl_tag, &disk_handlesp[1])) != SUCCESS) {
800 		free(disk_handlesp);
801 		return (ret);
802 	}
803 
804 	/* LIB API should check whether all disks here belong to one ctl. */
805 	/* get_disk_handle_ctd has opened controller. */
806 	ctl_handle = raidcfg_get_controller(ctl_tag);
807 
808 	if (ctl_handle <= 0) {
809 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
810 		(void) raidcfg_close_controller(ctl_handle, NULL);
811 		free(disk_handlesp);
812 		return (FAILURE);
813 	}
814 
815 	/* Check if the controller is host raid type */
816 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
817 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
818 		(void) raidcfg_close_controller(ctl_handle, NULL);
819 		free(disk_handlesp);
820 		return (FAILURE);
821 	}
822 
823 	if ((ctl_attr.capability & RAID_CAP_DISK_TRANS) == 0) {
824 		/* -c only support host raid controller, return failure here */
825 		(void) fprintf(stderr,
826 		    gettext("Option -c only supports host raid controller.\n"));
827 		(void) raidcfg_close_controller(ctl_handle, NULL);
828 		free(disk_handlesp);
829 		return (FAILURE);
830 	}
831 
832 	if (f_flag == FALSE) {
833 		(void) fprintf(stdout, gettext("Creating RAID volume "
834 		    "will destroy all data on spare space of member disks, "
835 		    "proceed (%s/%s)? "), yesstr, nostr);
836 		if (!yes()) {
837 			(void) fprintf(stdout, gettext("RAID volume "
838 			    "not created.\n\n"));
839 			free(disk_handlesp);
840 			(void) raidcfg_close_controller(ctl_handle, NULL);
841 			return (SUCCESS);
842 		}
843 	}
844 
845 	/*
846 	 * For old raidctl, capacity is 0, which means to creates
847 	 * max possible capacity of array.
848 	 */
849 
850 	array_handle = raidcfg_create_array(disks_num + 2,
851 	    disk_handlesp, raid_level, capacity, stripe_size, NULL);
852 
853 	if (array_handle <= 0) {
854 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
855 		free(disk_handlesp);
856 		(void) raidcfg_close_controller(ctl_handle, NULL);
857 		return (FAILURE);
858 	}
859 
860 	/* Get attribute of array */
861 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
862 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
863 		free(disk_handlesp);
864 		(void) raidcfg_close_controller(ctl_handle, NULL);
865 		return (FAILURE);
866 	}
867 
868 	/* Close controller */
869 	(void) raidcfg_close_controller(ctl_handle, NULL);
870 
871 	/* Print feedback for user */
872 	(void) fprintf(stdout,
873 	    gettext("Volume c%ut%llud%llu is created successfully!\n"),
874 	    ctl_tag, array_attr.tag.idl.target_id,
875 	    array_attr.tag.idl.lun);
876 	free(disk_handlesp);
877 	return (SUCCESS);
878 }
879 
880 /*
881  * do_list(disk_arg, argv, optind, is_snapshot)
882  * This function lists RAID's system configuration. It supports various RAID
883  * controller. The return value can be SUCCESS, FAILURE, or INVALID_ARG.
884  */
885 static int
886 do_list(char *disk_argp, char **argv, uint32_t optind, uint8_t is_snapshot)
887 {
888 	uint32_t ctl_tag = MAX32BIT;
889 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
890 	raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE;
891 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
892 	disk_tag_t disk_tag;
893 	array_tag_t array_tag;
894 
895 	int ret;
896 
897 	/* print RAID system */
898 	if (disk_argp == NULL) {
899 		if (argv[optind] == NULL) {
900 			ret = snapshot_raidsystem(TRUE, 0, is_snapshot);
901 			return (ret);
902 		} else {
903 			if (is_fully_numeric(argv[optind]) == TRUE) {
904 				while (argv[optind] != NULL) {
905 					if (get_ctl_tag(argv[optind], &ctl_tag)
906 					    != SUCCESS) {
907 						ret = INVALID_ARG;
908 						optind++;
909 						continue;
910 					}
911 					ctl_handle =
912 					    raidcfg_get_controller(ctl_tag);
913 					if (ctl_handle <= 0) {
914 						(void) fprintf(stderr, "%s\n",
915 						    raidcfg_errstr(ctl_handle));
916 						ret = FAILURE;
917 						optind++;
918 						continue;
919 					}
920 					ret =
921 					    raidcfg_open_controller(ctl_handle,
922 					    NULL);
923 					if (ret < 0) {
924 						(void) fprintf(stderr, "%s\n",
925 						    raidcfg_errstr(ret));
926 						ret = FAILURE;
927 						optind++;
928 						continue;
929 					}
930 					if (is_snapshot == FALSE) {
931 						ret =
932 						    print_ctl_table(ctl_handle);
933 					} else {
934 						ret =
935 						    snapshot_ctl(ctl_handle,
936 						    FALSE, 0, is_snapshot);
937 					}
938 					(void) raidcfg_close_controller(
939 					    ctl_handle, NULL);
940 					optind++;
941 				}
942 			} else {
943 				if (get_array_tag(argv[optind],
944 				    &ctl_tag, &array_tag) != SUCCESS) {
945 					return (INVALID_ARG);
946 				}
947 				ctl_handle = raidcfg_get_controller(ctl_tag);
948 				if (ctl_handle <= 0) {
949 					(void) fprintf(stderr, "%s\n",
950 					    raidcfg_errstr(ctl_handle));
951 					return (FAILURE);
952 				}
953 
954 				ret = raidcfg_open_controller(ctl_handle, NULL);
955 				if (ret < 0) {
956 					(void) fprintf(stderr, "%s\n",
957 					    raidcfg_errstr(ret));
958 					return (FAILURE);
959 				}
960 
961 				array_handle = raidcfg_get_array(ctl_handle,
962 				    array_tag.idl.target_id, array_tag.idl.lun);
963 				if (array_handle <= 0) {
964 					(void) fprintf(stderr, "%s\n",
965 					    raidcfg_errstr(array_handle));
966 					(void) raidcfg_close_controller(
967 					    ctl_handle, NULL);
968 					return (FAILURE);
969 				}
970 				if (is_snapshot == FALSE) {
971 					ret = print_array_table(ctl_handle,
972 					    array_handle);
973 				} else {
974 					ret = snapshot_array(array_handle, 0,
975 					    FALSE, is_snapshot);
976 				}
977 				(void) raidcfg_close_controller(
978 				    ctl_handle, NULL);
979 			}
980 		}
981 	} else {
982 		if (argv[optind + 1] != NULL) {
983 			return (INVALID_ARG);
984 		}
985 
986 		if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) {
987 			return (INVALID_ARG);
988 		}
989 
990 		ctl_handle = raidcfg_get_controller(ctl_tag);
991 		if (ctl_handle <= 0) {
992 			(void) fprintf(stderr, "%s\n",
993 			    raidcfg_errstr(ctl_handle));
994 			return (FAILURE);
995 		}
996 
997 		if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) {
998 			return (INVALID_ARG);
999 		}
1000 
1001 		ret = raidcfg_open_controller(ctl_handle, NULL);
1002 		if (ret < 0) {
1003 			(void) fprintf(stderr, "%s\n",
1004 			    raidcfg_errstr(ret));
1005 			return (FAILURE);
1006 		}
1007 
1008 		disk_handle = raidcfg_get_disk(ctl_handle, disk_tag);
1009 		if (disk_handle <= 0) {
1010 			(void) fprintf(stderr, "%s\n",
1011 			    raidcfg_errstr(disk_handle));
1012 			(void) raidcfg_close_controller(ctl_handle, NULL);
1013 			return (FAILURE);
1014 		}
1015 
1016 		if (is_snapshot == FALSE) {
1017 			ret = print_disk_table(ctl_handle, disk_handle);
1018 		} else {
1019 			ret = snapshot_disk(ctl_tag, disk_handle, 0,
1020 			    is_snapshot);
1021 		}
1022 		(void) raidcfg_close_controller(ctl_handle, NULL);
1023 	}
1024 	return (ret);
1025 }
1026 
1027 /*
1028  * do_delete(f_flag, argv, optind)
1029  * This function deletes a specified array, and return result as SUCCESS,
1030  * FAILURE or INVALID_ARG.
1031  */
1032 static int
1033 do_delete(uint32_t f_flag, char **argv, uint32_t optind)
1034 {
1035 	uint32_t ctl_tag;
1036 	char *array_argp;
1037 	array_tag_t array_tag;
1038 	raid_obj_handle_t ctl_handle;
1039 	raid_obj_handle_t array_handle;
1040 	int ret;
1041 
1042 	array_argp = argv[optind];
1043 	if (array_argp == NULL || argv[optind + 1] != NULL) {
1044 		return (INVALID_ARG);
1045 	}
1046 
1047 	if (get_array_tag(array_argp, &ctl_tag, &array_tag) != SUCCESS) {
1048 		return (INVALID_ARG);
1049 	}
1050 
1051 	ctl_handle = raidcfg_get_controller(ctl_tag);
1052 	if (ctl_handle <= 0) {
1053 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
1054 		return (INVALID_ARG);
1055 	}
1056 
1057 	ret = raidcfg_open_controller(ctl_handle, NULL);
1058 	if (ret < 0) {
1059 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1060 		return (FAILURE);
1061 	}
1062 
1063 	array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id,
1064 	    array_tag.idl.lun);
1065 	if (array_handle <= 0) {
1066 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
1067 		(void) raidcfg_close_controller(ctl_handle, NULL);
1068 		return (FAILURE);
1069 	}
1070 
1071 	if (f_flag == FALSE) {
1072 		(void) fprintf(stdout, gettext("Deleting RAID volume "
1073 		    "%s will destroy all data it contains, "
1074 		    "proceed (%s/%s)? "), array_argp, yesstr, nostr);
1075 		if (!yes()) {
1076 			(void) fprintf(stdout, gettext("RAID Volume "
1077 			    "%s not deleted.\n\n"), array_argp);
1078 			(void) raidcfg_close_controller(ctl_handle, NULL);
1079 			return (SUCCESS);
1080 		}
1081 	}
1082 
1083 
1084 	if ((ret = raidcfg_delete_array(array_handle, NULL)) < 0) {
1085 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1086 		(void) raidcfg_close_controller(ctl_handle, NULL);
1087 		return (FAILURE);
1088 	}
1089 
1090 	(void) fprintf(stdout, gettext("Volume %s is deleted successfully!\n"),
1091 	    array_argp);
1092 	(void) raidcfg_close_controller(ctl_handle, NULL);
1093 
1094 	return (SUCCESS);
1095 }
1096 
1097 /*
1098  * do_flash(f_flag, filep, ctls_argpp, index, ctl_num)
1099  * This function downloads and updates firmware for specified controller, and
1100  * return result as SUCCESS, FAILURE or INVALID_ARG.
1101  */
1102 static int
1103 do_flash(uint8_t f_flag, char *filep, char **ctls_argpp,
1104 	uint32_t index, uint32_t ctl_num)
1105 {
1106 	uint32_t ctl_tag = MAX32BIT;
1107 	char *ctl_argp = NULL;
1108 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1109 	int ret;
1110 	int i, j;
1111 
1112 	if (ctl_num == 0)
1113 		return (INVALID_ARG);
1114 
1115 	for (i = 0, j = index; i < ctl_num; i++, j++) {
1116 		ctl_argp = ctls_argpp[j];
1117 		if (get_ctl_tag(ctl_argp, &ctl_tag) != SUCCESS) {
1118 			return (INVALID_ARG);
1119 		}
1120 
1121 		/* Ask user to confirm operation. */
1122 		if (f_flag == FALSE) {
1123 			(void) fprintf(stdout, gettext("Update flash image on "
1124 			    "controller %d (%s/%s)? "), ctl_tag, yesstr, nostr);
1125 			if (!yes()) {
1126 				(void) fprintf(stdout,
1127 				    gettext("Controller %d not "
1128 				    "flashed.\n\n"), ctl_tag);
1129 				return (SUCCESS);
1130 			}
1131 		}
1132 
1133 		if ((ctl_handle = raidcfg_get_controller(ctl_tag)) < 0) {
1134 			(void) fprintf(stderr, "%s\n",
1135 			    raidcfg_errstr(ctl_handle));
1136 			return (FAILURE);
1137 		}
1138 
1139 		ret = raidcfg_open_controller(ctl_handle, NULL);
1140 		if (ret < 0) {
1141 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1142 			return (FAILURE);
1143 		}
1144 
1145 		(void) fprintf(stdout, gettext("Start updating controller "
1146 		    "c%u firmware....\n"), ctl_tag);
1147 
1148 		if ((ret = raidcfg_update_fw(ctl_handle, filep, NULL)) < 0) {
1149 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1150 			(void) raidcfg_close_controller(ctl_handle, NULL);
1151 			return (FAILURE);
1152 		}
1153 
1154 		(void) fprintf(stdout, gettext("Update controller "
1155 		    "c%u firmware successfully.\n"), ctl_tag);
1156 
1157 		(void) raidcfg_close_controller(ctl_handle, NULL);
1158 	}
1159 
1160 	return (SUCCESS);
1161 }
1162 
1163 /*
1164  * do_set_hsp(a_argp, disk_argp, argv, optind)
1165  * This function set or unset HSP relationship between disk and controller/
1166  * array, and return result as SUCCESS, FAILURE or INVALID_ARG.
1167  */
1168 static int
1169 do_set_hsp(char *a_argp, char *disk_argp, char **argv, uint32_t optind)
1170 {
1171 	uint32_t flag = MAX32BIT;
1172 	uint32_t ctl_tag = MAX32BIT;
1173 	array_tag_t array_tag;
1174 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1175 	raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE;
1176 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
1177 	raidcfg_controller_t ctl_attr;
1178 	disk_tag_t disk_tag;
1179 
1180 	int ret;
1181 	int hsp_type;
1182 	raidcfg_hsp_relation_t hsp_relation;
1183 
1184 	(void) memset(&hsp_relation, 0, sizeof (raidcfg_hsp_relation_t));
1185 
1186 	if (a_argp == NULL) {
1187 		return (INVALID_ARG);
1188 	}
1189 
1190 	if (strcmp(a_argp, "set") == 0) {
1191 		flag = HSP_SET;
1192 	} else if (strcmp(a_argp, "unset") == 0) {
1193 		flag = HSP_UNSET;
1194 	} else {
1195 		return (INVALID_ARG);
1196 	}
1197 
1198 	if (disk_argp == NULL) {
1199 		return (INVALID_ARG);
1200 	}
1201 
1202 	if (argv[optind] == NULL || argv[optind + 1] != NULL) {
1203 		return (INVALID_ARG);
1204 	} else if (is_fully_numeric(argv[optind]) == TRUE) {
1205 		/* Global HSP */
1206 		hsp_type = 0;
1207 		if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) {
1208 			return (INVALID_ARG);
1209 		}
1210 
1211 		if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) {
1212 			return (INVALID_ARG);
1213 		}
1214 
1215 		ctl_handle = raidcfg_get_controller(ctl_tag);
1216 		if (ctl_handle <= 0) {
1217 			(void) fprintf(stderr, "%s\n",
1218 			    raidcfg_errstr(ctl_handle));
1219 			return (FAILURE);
1220 		}
1221 
1222 		ret = raidcfg_open_controller(ctl_handle, NULL);
1223 		if (ret < 0) {
1224 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1225 			return (FAILURE);
1226 		}
1227 
1228 		disk_handle = raidcfg_get_disk(ctl_handle, disk_tag);
1229 		if (disk_handle <= 0) {
1230 			(void) fprintf(stderr, "%s\n",
1231 			    raidcfg_errstr(disk_handle));
1232 			(void) raidcfg_close_controller(ctl_handle, NULL);
1233 			return (FAILURE);
1234 		}
1235 	} else {
1236 		/* Local HSP */
1237 		hsp_type = 1;
1238 		if (get_array_tag(argv[optind], &ctl_tag, &array_tag) !=
1239 		    SUCCESS) {
1240 			return (INVALID_ARG);
1241 		}
1242 
1243 		/* Open controller */
1244 		ctl_handle = raidcfg_get_controller(ctl_tag);
1245 		if (ctl_handle <= 0) {
1246 			(void) fprintf(stderr, "%s\n",
1247 			    raidcfg_errstr(ctl_handle));
1248 			return (FAILURE);
1249 		}
1250 
1251 		ret = raidcfg_open_controller(ctl_handle, NULL);
1252 		if (ret < 0) {
1253 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1254 			return (FAILURE);
1255 		}
1256 
1257 		/* Get controller's attribute */
1258 		if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1259 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1260 			(void) raidcfg_close_controller(ctl_handle, NULL);
1261 			return (FAILURE);
1262 		}
1263 
1264 		if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) {
1265 			(void) raidcfg_close_controller(ctl_handle, NULL);
1266 			return (INVALID_ARG);
1267 		}
1268 
1269 		/* Get disk handle */
1270 		disk_handle = raidcfg_get_disk(ctl_handle, disk_tag);
1271 		if (disk_handle <= 0) {
1272 			(void) fprintf(stderr, "%s\n",
1273 			    raidcfg_errstr(disk_handle));
1274 			(void) raidcfg_close_controller(ctl_handle, NULL);
1275 			return (FAILURE);
1276 		}
1277 
1278 		/* Get array handle */
1279 		array_handle = raidcfg_get_array(ctl_handle,
1280 		    array_tag.idl.target_id, array_tag.idl.lun);
1281 		if (array_handle <= 0) {
1282 			(void) fprintf(stderr, "%s\n",
1283 			    raidcfg_errstr(array_handle));
1284 			(void) raidcfg_close_controller(ctl_handle, NULL);
1285 			return (FAILURE);
1286 		}
1287 	}
1288 
1289 	hsp_relation.disk_handle = disk_handle;
1290 	if (hsp_type) {
1291 		/* Set or unset local HSP */
1292 		hsp_relation.array_handle = array_handle;
1293 	} else {
1294 		/* Set or unset global HSP */
1295 		hsp_relation.array_handle = OBJ_ATTR_NONE;
1296 	}
1297 
1298 	/* Perform operation of set or unset */
1299 	if (flag == HSP_SET) {
1300 		if ((ret = raidcfg_set_hsp(1, &hsp_relation, NULL)) < 0) {
1301 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1302 			(void) raidcfg_close_controller(ctl_handle, NULL);
1303 			return (FAILURE);
1304 		}
1305 
1306 		if (hsp_type) {
1307 			(void) printf(gettext("Set local HSP between disk %s "
1308 			    "and RAID volume %s successfully.\n"),
1309 			    disk_argp, argv[optind]);
1310 		} else {
1311 			(void) printf(gettext("Set global HSP between disk %s "
1312 			    "and controller %s successfully.\n"),
1313 			    disk_argp, argv[optind]);
1314 		}
1315 	} else {
1316 		if ((ret = raidcfg_unset_hsp(1, &hsp_relation, NULL)) < 0) {
1317 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1318 			(void) raidcfg_close_controller(ctl_handle, NULL);
1319 			return (FAILURE);
1320 		}
1321 
1322 		if (hsp_type) {
1323 			(void) printf(gettext("Unset local HSP between "
1324 			    "disk %s and RAID volume %s successfully.\n"),
1325 			    disk_argp, argv[optind]);
1326 		} else {
1327 			(void) printf(gettext("Unset global HSP between "
1328 			    "disk %s and controller %s successfully.\n"),
1329 			    disk_argp, argv[optind]);
1330 		}
1331 	}
1332 	(void) raidcfg_close_controller(ctl_handle, NULL);
1333 	return (SUCCESS);
1334 }
1335 
1336 /*
1337  * do_set_array_attr(f_flag, p_argp, argv, optind)
1338  * This function changes array's attribute when array is running.
1339  * The changeable attribute is up to controller's feature.
1340  * The return value can be SUCCESS, FAILURE or INVALID_ARG.
1341  */
1342 static int
1343 do_set_array_attr(uint32_t f_flag, char *p_argp, char **argv, uint32_t optind)
1344 {
1345 	uint32_t ctl_tag = MAX32BIT;
1346 	array_tag_t array_tag;
1347 	uint32_t type = MAX32BIT;
1348 	uint32_t value = MAX32BIT;
1349 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1350 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
1351 
1352 	char *param, *op = "=";
1353 
1354 	int ret;
1355 
1356 	if (argv[optind] == NULL || argv[optind + 1] != NULL) {
1357 		return (INVALID_ARG);
1358 	}
1359 
1360 	if (p_argp != NULL) {
1361 		param = strtok(p_argp, op);
1362 		if (strcmp(param, "wp") == 0) {
1363 			type = SET_CACHE_WR_PLY;
1364 			param = strtok(NULL, op);
1365 			if (strcmp(param, "on") == 0) {
1366 				value = CACHE_WR_ON;
1367 			} else if (strcmp(param, "off") == 0) {
1368 				value = CACHE_WR_OFF;
1369 			} else {
1370 				return (INVALID_ARG);
1371 			}
1372 		} else if (strcmp(param, "state") == 0) {
1373 			type = SET_ACTIVATION_PLY;
1374 			param = strtok(NULL, op);
1375 			if (strcmp(param, "activate") == 0) {
1376 				value = ARRAY_ACT_ACTIVATE;
1377 			} else {
1378 				return (INVALID_ARG);
1379 			}
1380 		} else {
1381 			return (INVALID_ARG);
1382 		}
1383 	} else {
1384 		return (INVALID_ARG);
1385 	}
1386 
1387 	if (get_array_tag(argv[optind], &ctl_tag, &array_tag) != SUCCESS) {
1388 		return (INVALID_ARG);
1389 	}
1390 
1391 	ctl_handle = raidcfg_get_controller(ctl_tag);
1392 	if (ctl_handle <= 0) {
1393 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
1394 		return (FAILURE);
1395 	}
1396 
1397 	ret = raidcfg_open_controller(ctl_handle, NULL);
1398 	if (ret < 0) {
1399 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1400 		return (FAILURE);
1401 	}
1402 
1403 	array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id,
1404 	    array_tag.idl.lun);
1405 	if (array_handle <= 0) {
1406 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
1407 		return (FAILURE);
1408 	}
1409 
1410 	/* Ask user to confirm operation. */
1411 	if (f_flag == FALSE) {
1412 		(void) fprintf(stdout, gettext("Update attribute of "
1413 		    "array %s (%s/%s)? "), argv[optind], yesstr, nostr);
1414 		if (!yes()) {
1415 			(void) fprintf(stdout,
1416 			    gettext("Array %s not "
1417 			    "changed.\n\n"), argv[optind]);
1418 			(void) raidcfg_close_controller(ctl_handle, NULL);
1419 			return (SUCCESS);
1420 		}
1421 	}
1422 
1423 	if ((ret = raidcfg_set_attr(array_handle, type, &value, NULL)) < 0) {
1424 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1425 		(void) raidcfg_close_controller(ctl_handle, NULL);
1426 		return (FAILURE);
1427 	}
1428 
1429 	(void) printf(gettext("Set attribute of RAID volume %s "
1430 	    "successfully.\n"), argv[optind]);
1431 	(void) raidcfg_close_controller(ctl_handle, NULL);
1432 
1433 	return (SUCCESS);
1434 }
1435 
1436 /*
1437  * snapshot_raidsystem(recursive, indent, is_snapshot)
1438  * This function prints the snapshot of whole RAID's system configuration,
1439  * and return result as SUCCESS or FAILURE.
1440  */
1441 static int
1442 snapshot_raidsystem(uint8_t recursive, uint8_t indent, uint8_t is_snapshot)
1443 {
1444 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1445 	int ret;
1446 
1447 	ctl_handle = raidcfg_list_head(OBJ_SYSTEM, OBJ_TYPE_CONTROLLER);
1448 	while (ctl_handle > 0) {
1449 		ret = raidcfg_open_controller(ctl_handle, NULL);
1450 		if (ret == 0) {
1451 			if (snapshot_ctl(ctl_handle, recursive, indent,
1452 			    is_snapshot) == FAILURE) {
1453 				(void) raidcfg_close_controller(ctl_handle,
1454 				    NULL);
1455 			}
1456 		}
1457 		ctl_handle = raidcfg_list_next(ctl_handle);
1458 	}
1459 	return (SUCCESS);
1460 }
1461 
1462 /*
1463  * snapshot_ctl(ctl_handle, recursive, indent, is_snapshot)
1464  * This function prints snapshot of specified controller's configuration,
1465  * and return result as SUCCESS or FAILURE.
1466  */
1467 static int
1468 snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive, uint8_t indent,
1469     uint8_t is_snapshot)
1470 {
1471 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
1472 	raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE;
1473 	raidcfg_controller_t ctl_attr;
1474 	uint32_t ctl_tag;
1475 	char ctlbuf[256];
1476 	int ret;
1477 
1478 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1479 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1480 		return (FAILURE);
1481 	}
1482 
1483 	ctl_tag = ctl_attr.controller_id;
1484 	if (is_snapshot == FALSE) {
1485 		print_indent(indent);
1486 		(void) fprintf(stdout, gettext("Controller: %u\n"), ctl_tag);
1487 	} else {
1488 		(void) snprintf(ctlbuf, sizeof (ctlbuf), "%u \"%s\"",
1489 		    ctl_tag, ctl_attr.controller_type);
1490 		(void) fprintf(stdout, "%s", ctlbuf);
1491 
1492 		(void) fprintf(stdout, "\n");
1493 	}
1494 
1495 	if (recursive == TRUE) {
1496 		array_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_ARRAY);
1497 		while (array_handle > 0) {
1498 			if (snapshot_array(array_handle,
1499 			    indent + 1, FALSE, is_snapshot) == FAILURE) {
1500 				return (FAILURE);
1501 			}
1502 
1503 			array_handle = raidcfg_list_next(array_handle);
1504 		}
1505 
1506 		disk_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_DISK);
1507 		while (disk_handle > 0) {
1508 			if (snapshot_disk(ctl_tag, disk_handle,
1509 			    indent + 1, is_snapshot) == FAILURE) {
1510 				return (FAILURE);
1511 			}
1512 
1513 			disk_handle = raidcfg_list_next(disk_handle);
1514 		}
1515 	}
1516 	return (SUCCESS);
1517 }
1518 
1519 
1520 /*
1521  * snapshot_array(array_handle, indent, is_sub, is_snapshot)
1522  * This function prints snapshot of specified array's configuration,
1523  * and return result as SUCCESS or FAILURE.
1524  */
1525 static int
1526 snapshot_array(raid_obj_handle_t array_handle, uint8_t indent, uint8_t is_sub,
1527     uint8_t is_snapshot)
1528 {
1529 	raid_obj_handle_t ctl_handle;
1530 	raid_obj_handle_t subarray_handle;
1531 	raid_obj_handle_t arraypart_handle;
1532 	raid_obj_handle_t task_handle;
1533 
1534 	raidcfg_controller_t ctl_attr;
1535 	raidcfg_array_t array_attr;
1536 	raidcfg_arraypart_t arraypart_attr;
1537 	raidcfg_task_t task_attr;
1538 
1539 	char arraybuf[256] = "\0";
1540 	char diskbuf[256] = "\0";
1541 	char tempbuf[256] = "\0";
1542 	int disknum = 0;
1543 
1544 	uint32_t ctl_tag;
1545 	int ret;
1546 
1547 	ctl_handle = raidcfg_get_container(array_handle);
1548 	ret = raidcfg_get_attr(ctl_handle, &ctl_attr);
1549 	if (ret < 0) {
1550 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1551 		return (FAILURE);
1552 	}
1553 	ctl_tag = ctl_attr.controller_id;
1554 
1555 	/* Print array attribute */
1556 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
1557 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1558 		return (FAILURE);
1559 	}
1560 
1561 	if (is_snapshot == FALSE) {
1562 		print_indent(indent);
1563 		if (is_sub == FALSE) {
1564 			(void) fprintf(stdout, gettext("Volume:"
1565 			    "c%ut%llud%llu\n"),
1566 			    ctl_tag, array_attr.tag.idl.target_id,
1567 			    array_attr.tag.idl.lun);
1568 		} else {
1569 			(void) fprintf(stdout, gettext("Sub-Volume\n"));
1570 		}
1571 	} else {
1572 		(void) snprintf(arraybuf, sizeof (arraybuf), "c%ut%llud%llu ",
1573 		    ctl_tag, array_attr.tag.idl.target_id,
1574 		    array_attr.tag.idl.lun);
1575 
1576 		/* Check if array is in sync state */
1577 		task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK);
1578 		if (task_handle > 0) {
1579 			(void) raidcfg_get_attr(task_handle, &task_attr);
1580 			if (task_attr.task_func == TASK_FUNC_BUILD) {
1581 				array_attr.state = ARRAY_STATE_SYNC;
1582 			}
1583 		} else {
1584 			subarray_handle = raidcfg_list_head(array_handle,
1585 			    OBJ_TYPE_ARRAY);
1586 			while (subarray_handle > 0) {
1587 				task_handle = raidcfg_list_head(subarray_handle,
1588 				    OBJ_TYPE_TASK);
1589 				if (task_handle > 0) {
1590 					(void) raidcfg_get_attr(task_handle,
1591 					    &task_attr);
1592 					if (task_attr.task_func ==
1593 					    TASK_FUNC_BUILD) {
1594 						array_attr.state =
1595 						    ARRAY_STATE_SYNC;
1596 					}
1597 					break;
1598 				}
1599 				subarray_handle =
1600 				    raidcfg_list_next(subarray_handle);
1601 			}
1602 		}
1603 
1604 		/* Print sub array */
1605 		subarray_handle = raidcfg_list_head(array_handle,
1606 		    OBJ_TYPE_ARRAY);
1607 		while (subarray_handle > 0) {
1608 			/* print subarraypart */
1609 			arraypart_handle = raidcfg_list_head(subarray_handle,
1610 			    OBJ_TYPE_ARRAY_PART);
1611 			while (arraypart_handle > 0) {
1612 				if ((ret = raidcfg_get_attr(arraypart_handle,
1613 				    &arraypart_attr)) < 0) {
1614 					(void) fprintf(stderr, "%s\n",
1615 					    raidcfg_errstr(ret));
1616 					return (FAILURE);
1617 				}
1618 
1619 				if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1620 					(void) snprintf(tempbuf,
1621 					    sizeof (tempbuf),
1622 					    gettext("N/A"));
1623 				} else {
1624 					(void) snprintf(tempbuf,
1625 					    sizeof (tempbuf),
1626 					    "%llu.%llu.%llu",
1627 					    arraypart_attr.tag.cidl.bus,
1628 					    arraypart_attr.tag.cidl.target_id,
1629 					    arraypart_attr.tag.cidl.lun);
1630 				}
1631 				(void) strcat(diskbuf, tempbuf);
1632 				(void) strcat(diskbuf, " ");
1633 				disknum++;
1634 				arraypart_handle =
1635 				    raidcfg_list_next(arraypart_handle);
1636 			}
1637 			subarray_handle = raidcfg_list_next(subarray_handle);
1638 		}
1639 
1640 		/* Print arraypart */
1641 		arraypart_handle = raidcfg_list_head(array_handle,
1642 		    OBJ_TYPE_ARRAY_PART);
1643 		while (arraypart_handle > 0) {
1644 			if ((ret = raidcfg_get_attr(arraypart_handle,
1645 			    &arraypart_attr)) < 0) {
1646 				(void) fprintf(stderr, "%s\n",
1647 				    raidcfg_errstr(ret));
1648 				return (FAILURE);
1649 			}
1650 
1651 			if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1652 				(void) snprintf(tempbuf, sizeof (tempbuf),
1653 				    gettext("N/A"));
1654 			} else {
1655 				(void) snprintf(tempbuf, sizeof (tempbuf),
1656 				    "%llu.%llu.%llu",
1657 				    arraypart_attr.tag.cidl.bus,
1658 				    arraypart_attr.tag.cidl.target_id,
1659 				    arraypart_attr.tag.cidl.lun);
1660 			}
1661 			(void) strcat(diskbuf, tempbuf);
1662 			(void) strcat(diskbuf, " ");
1663 			disknum++;
1664 			arraypart_handle = raidcfg_list_next(arraypart_handle);
1665 		}
1666 		(void) snprintf(tempbuf, sizeof (tempbuf), "%u ", disknum);
1667 		(void) strcat(arraybuf, tempbuf);
1668 		(void) strcat(arraybuf, diskbuf);
1669 
1670 		switch (array_attr.raid_level) {
1671 		case RAID_LEVEL_0:
1672 			(void) sprintf(tempbuf, "0");
1673 			break;
1674 		case RAID_LEVEL_1:
1675 			(void) sprintf(tempbuf, "1");
1676 			break;
1677 		case RAID_LEVEL_1E:
1678 			(void) sprintf(tempbuf, "1E");
1679 			break;
1680 		case RAID_LEVEL_5:
1681 			(void) sprintf(tempbuf, "5");
1682 			break;
1683 		case RAID_LEVEL_10:
1684 			(void) sprintf(tempbuf, "10");
1685 			break;
1686 		case RAID_LEVEL_50:
1687 			(void) sprintf(tempbuf, "50");
1688 			break;
1689 		default:
1690 			(void) snprintf(tempbuf, sizeof (tempbuf),
1691 			    gettext("N/A"));
1692 			break;
1693 		}
1694 		(void) strcat(arraybuf, tempbuf);
1695 		(void) fprintf(stdout, "%s ", arraybuf);
1696 
1697 		switch (array_attr.state) {
1698 		case ARRAY_STATE_OPTIMAL:
1699 			(void) fprintf(stdout, gettext("OPTIMAL"));
1700 			break;
1701 		case ARRAY_STATE_DEGRADED:
1702 			(void) fprintf(stdout, gettext("DEGRADED"));
1703 			break;
1704 		case ARRAY_STATE_FAILED:
1705 			(void) fprintf(stdout, gettext("FAILED"));
1706 			break;
1707 		case ARRAY_STATE_SYNC:
1708 			(void) fprintf(stdout, gettext("SYNC"));
1709 			break;
1710 		case ARRAY_STATE_MISSING:
1711 			(void) fprintf(stdout, gettext("MISSING"));
1712 			break;
1713 		default:
1714 			(void) fprintf(stdout, gettext("N/A"));
1715 			break;
1716 		}
1717 		(void) fprintf(stdout, "\n");
1718 	}
1719 
1720 	return (SUCCESS);
1721 }
1722 
1723 /*
1724  * snapshot_disk(ctl_tag, disk_handle, indent, is_snapshot)
1725  * This function prints snapshot of specified disk's configuration, and return
1726  * result as SUCCESS or FAILURE.
1727  */
1728 static int
1729 snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle, uint8_t indent,
1730     uint8_t is_snapshot)
1731 {
1732 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1733 	raid_obj_handle_t hsp_handle;
1734 
1735 	raidcfg_controller_t ctl_attr;
1736 	raidcfg_disk_t disk_attr;
1737 	char diskbuf[256] = "";
1738 	char tempbuf[256] = "";
1739 
1740 	int ret;
1741 
1742 	ctl_handle = raidcfg_get_controller(ctl_tag);
1743 	ret = raidcfg_get_attr(ctl_handle, &ctl_attr);
1744 	if (ret < 0) {
1745 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1746 		return (FAILURE);
1747 	}
1748 
1749 	/* Print attribute of disk */
1750 	if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) {
1751 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1752 		return (FAILURE);
1753 	}
1754 
1755 	if (is_snapshot == FALSE) {
1756 		print_indent(indent);
1757 
1758 		hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
1759 
1760 		if (disk_attr.tag.cidl.bus == MAX64BIT) {
1761 			(void) fprintf(stdout, gettext("Disk: N/A"));
1762 		} else {
1763 			(void) fprintf(stdout, gettext("Disk: %llu.%llu.%llu"),
1764 			    disk_attr.tag.cidl.bus,
1765 			    disk_attr.tag.cidl.target_id,
1766 			    disk_attr.tag.cidl.lun);
1767 		}
1768 		if (hsp_handle > 0) {
1769 			(void) fprintf(stdout, "(HSP)");
1770 		}
1771 		(void) fprintf(stdout, "\n");
1772 	} else {
1773 		if (disk_attr.tag.cidl.bus == MAX64BIT) {
1774 			(void) fprintf(stdout, gettext("N/A"));
1775 		} else {
1776 			(void) snprintf(diskbuf, sizeof (diskbuf),
1777 			    "%llu.%llu.%llu ",
1778 			    disk_attr.tag.cidl.bus,
1779 			    disk_attr.tag.cidl.target_id,
1780 			    disk_attr.tag.cidl.lun);
1781 		}
1782 		hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
1783 		if (hsp_handle > 0) {
1784 			(void) snprintf(tempbuf, sizeof (tempbuf),
1785 			    gettext("HSP"));
1786 		} else if (disk_attr.state == DISK_STATE_GOOD) {
1787 			(void) snprintf(tempbuf, sizeof (tempbuf),
1788 			    gettext("GOOD"));
1789 		} else if (disk_attr.state == DISK_STATE_FAILED) {
1790 			(void) snprintf(tempbuf, sizeof (tempbuf),
1791 			    gettext("FAILED"));
1792 		} else {
1793 			(void) snprintf(tempbuf, sizeof (tempbuf),
1794 			    gettext("N/A"));
1795 		}
1796 
1797 		(void) strcat(diskbuf, tempbuf);
1798 		(void) fprintf(stdout, "%s\n", diskbuf);
1799 	}
1800 
1801 	return (SUCCESS);
1802 }
1803 
1804 static int
1805 print_ctl_table(raid_obj_handle_t ctl_handle)
1806 {
1807 	raidcfg_controller_t ctl_attr;
1808 	char controller[8];
1809 	int ret;
1810 
1811 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1812 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1813 		return (FAILURE);
1814 	}
1815 
1816 	(void) fprintf(stdout, gettext("Controller\tType\t\tVersion"));
1817 	(void) fprintf(stdout, "\n");
1818 	(void) fprintf(stdout, "--------------------------------");
1819 	(void) fprintf(stdout, "--------------------------------");
1820 	(void) fprintf(stdout, "\n");
1821 
1822 	(void) snprintf(controller, sizeof (controller), "%u",
1823 	    ctl_attr.controller_id);
1824 	(void) printf("c%s\t\t", controller);
1825 
1826 	(void) print_ctl_attr(&ctl_attr);
1827 	(void) fprintf(stdout, "\n");
1828 
1829 	return (SUCCESS);
1830 }
1831 
1832 static int
1833 print_array_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t array_handle)
1834 {
1835 	raidcfg_controller_t ctl_attr;
1836 	raidcfg_array_t array_attr;
1837 	raidcfg_array_t subarray_attr;
1838 	raidcfg_arraypart_t arraypart_attr;
1839 	raidcfg_task_t task_attr;
1840 
1841 	raid_obj_handle_t subarray_handle;
1842 	raid_obj_handle_t arraypart_handle;
1843 	raid_obj_handle_t task_handle;
1844 
1845 	char array[16];
1846 	char arraypart[8];
1847 	int ret;
1848 	int i;
1849 
1850 	/* Controller attribute */
1851 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1852 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1853 		return (FAILURE);
1854 	}
1855 
1856 	/* Array attribute */
1857 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
1858 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1859 		return (FAILURE);
1860 	}
1861 
1862 	/* print header */
1863 	(void) fprintf(stdout, gettext("Volume\t\t\tSize\tStripe\tStatus\t"
1864 	    " Cache\tRAID"));
1865 	(void) fprintf(stdout, "\n");
1866 	(void) fprintf(stdout, gettext("\tSub\t\t\tSize\t\t\tLevel"));
1867 	(void) fprintf(stdout, "\n");
1868 	(void) fprintf(stdout, gettext("\t\tDisk\t\t\t\t\t"));
1869 	(void) fprintf(stdout, "\n");
1870 	(void) fprintf(stdout, "--------------------------------");
1871 	(void) fprintf(stdout, "--------------------------------");
1872 	(void) fprintf(stdout, "\n");
1873 
1874 	/* print array */
1875 	(void) snprintf(array, sizeof (array), "c%ut%llud%llu",
1876 	    ctl_attr.controller_id, array_attr.tag.idl.target_id,
1877 	    array_attr.tag.idl.lun);
1878 	(void) fprintf(stdout, "%s\t\t", array);
1879 	if (strlen(array) < 8)
1880 		(void) fprintf(stdout, "\t");
1881 
1882 
1883 	/* check if array is in sync state */
1884 	task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK);
1885 	if (task_handle > 0) {
1886 		(void) raidcfg_get_attr(task_handle, &task_attr);
1887 		if (task_attr.task_func == TASK_FUNC_BUILD) {
1888 			array_attr.state = ARRAY_STATE_SYNC;
1889 		}
1890 	} else {
1891 		subarray_handle = raidcfg_list_head(array_handle,
1892 		    OBJ_TYPE_ARRAY);
1893 		while (subarray_handle > 0) {
1894 			task_handle = raidcfg_list_head(subarray_handle,
1895 			    OBJ_TYPE_TASK);
1896 			if (task_handle > 0) {
1897 				(void) raidcfg_get_attr(task_handle,
1898 				    &task_attr);
1899 				if (task_attr.task_func == TASK_FUNC_BUILD) {
1900 					array_attr.state = ARRAY_STATE_SYNC;
1901 				}
1902 				break;
1903 			}
1904 			subarray_handle = raidcfg_list_next(subarray_handle);
1905 		}
1906 	}
1907 
1908 	(void) print_array_attr(&array_attr);
1909 	(void) fprintf(stdout, "\n");
1910 
1911 	/* Print sub array */
1912 	i = 0;			/* Count sub array number */
1913 	subarray_handle = raidcfg_list_head(array_handle, OBJ_TYPE_ARRAY);
1914 	while (subarray_handle > 0) {
1915 		if ((ret = raidcfg_get_attr(subarray_handle,
1916 		    &subarray_attr)) < 0) {
1917 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1918 			return (FAILURE);
1919 		}
1920 
1921 		/* Use sub0/sub1 here, not cxtxd0 for subarray */
1922 		(void) snprintf(array, sizeof (array), "sub%u", i++);
1923 		(void) fprintf(stdout, "\t%s\t\t", array);
1924 
1925 		/* Check if array is in sync */
1926 		task_handle = raidcfg_list_head(subarray_handle, OBJ_TYPE_TASK);
1927 		if (task_handle > 0) {
1928 			(void) raidcfg_get_attr(task_handle, &task_attr);
1929 			if (task_attr.task_func == TASK_FUNC_BUILD) {
1930 				subarray_attr.state = ARRAY_STATE_SYNC;
1931 			}
1932 		}
1933 
1934 		(void) print_array_attr(&subarray_attr);
1935 		(void) fprintf(stdout, "\n");
1936 
1937 		/* Print subarraypart */
1938 		arraypart_handle = raidcfg_list_head(subarray_handle,
1939 		    OBJ_TYPE_ARRAY_PART);
1940 		while (arraypart_handle > 0) {
1941 			if ((ret = raidcfg_get_attr(arraypart_handle,
1942 			    &arraypart_attr)) < 0) {
1943 				(void) fprintf(stderr, "%s\n",
1944 				    raidcfg_errstr(ret));
1945 				return (FAILURE);
1946 			}
1947 
1948 			if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1949 				(void) snprintf(arraypart, sizeof (arraypart),
1950 				    gettext("N/A"));
1951 			} else {
1952 				(void) snprintf(arraypart, sizeof (arraypart),
1953 				    "%llu.%llu.%llu",
1954 				    arraypart_attr.tag.cidl.bus,
1955 				    arraypart_attr.tag.cidl.target_id,
1956 				    arraypart_attr.tag.cidl.lun);
1957 			}
1958 
1959 			(void) fprintf(stdout, "\t\t%s\t", arraypart);
1960 			(void) print_arraypart_attr(&arraypart_attr);
1961 			(void) fprintf(stdout, "\n");
1962 			arraypart_handle = raidcfg_list_next(arraypart_handle);
1963 		}
1964 		subarray_handle = raidcfg_list_next(subarray_handle);
1965 	}
1966 
1967 	/* Print arraypart */
1968 	arraypart_handle = raidcfg_list_head(array_handle,
1969 	    OBJ_TYPE_ARRAY_PART);
1970 	while (arraypart_handle > 0) {
1971 		if ((ret = raidcfg_get_attr(arraypart_handle,
1972 		    &arraypart_attr)) < 0) {
1973 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1974 			return (FAILURE);
1975 		}
1976 
1977 		if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1978 			(void) snprintf(arraypart, sizeof (arraypart),
1979 			    gettext("N/A"));
1980 		} else {
1981 			(void) snprintf(arraypart, sizeof (arraypart),
1982 			    "%llu.%llu.%llu",
1983 			    arraypart_attr.tag.cidl.bus,
1984 			    arraypart_attr.tag.cidl.target_id,
1985 			    arraypart_attr.tag.cidl.lun);
1986 		}
1987 
1988 		(void) fprintf(stdout, "\t\t%s\t", arraypart);
1989 		(void) print_arraypart_attr(&arraypart_attr);
1990 		(void) fprintf(stdout, "\n");
1991 		arraypart_handle = raidcfg_list_next(arraypart_handle);
1992 	}
1993 
1994 	return (SUCCESS);
1995 }
1996 
1997 static int
1998 print_disk_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle)
1999 {
2000 	raidcfg_controller_t ctl_attr;
2001 	raidcfg_disk_t disk_attr;
2002 	raidcfg_prop_t *prop_attr, *prop_attr2;
2003 	raid_obj_handle_t prop_handle;
2004 	char disk[8];
2005 	int ret;
2006 
2007 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
2008 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2009 		return (FAILURE);
2010 	}
2011 
2012 	if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) {
2013 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2014 		return (FAILURE);
2015 	}
2016 
2017 	/* Print header */
2018 	(void) fprintf(stdout, gettext("Disk\tVendor\tProduct\t\tFirmware\t"
2019 	    "Capacity\tStatus\tHSP"));
2020 	(void) fprintf(stdout, "\n");
2021 	(void) fprintf(stdout, "--------------------------------------");
2022 	(void) fprintf(stdout, "--------------------------------------");
2023 	(void) fprintf(stdout, "\n");
2024 
2025 
2026 	(void) snprintf(disk, sizeof (disk), "%llu.%llu.%llu",
2027 	    disk_attr.tag.cidl.bus,
2028 	    disk_attr.tag.cidl.target_id,
2029 	    disk_attr.tag.cidl.lun);
2030 
2031 	(void) fprintf(stdout, "%s\t", disk);
2032 
2033 	(void) print_disk_attr(ctl_handle, disk_handle, &disk_attr);
2034 
2035 	prop_attr = calloc(1, sizeof (raidcfg_prop_t));
2036 	if (prop_attr == NULL) {
2037 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ERR_NOMEM));
2038 		return (FAILURE);
2039 	}
2040 
2041 	prop_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_PROP);
2042 	if (prop_handle == 0) {
2043 		free(prop_attr);
2044 		return (SUCCESS);
2045 	}
2046 
2047 	do {
2048 		prop_attr->prop_size = 0;
2049 		if ((ret = raidcfg_get_attr(prop_handle, prop_attr)) < 0) {
2050 			free(prop_attr);
2051 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2052 			return (FAILURE);
2053 		}
2054 		if (prop_attr->prop_type == PROP_GUID)
2055 			break;
2056 	} while (prop_handle != 0);
2057 
2058 	prop_attr2 = realloc(prop_attr,
2059 	    sizeof (raidcfg_prop_t) + prop_attr->prop_size);
2060 	free(prop_attr);
2061 	if (prop_attr2 == NULL) {
2062 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ERR_NOMEM));
2063 		return (FAILURE);
2064 	}
2065 
2066 	if ((ret = raidcfg_get_attr(prop_handle, prop_attr2)) < 0) {
2067 		free(prop_attr2);
2068 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2069 		return (FAILURE);
2070 	}
2071 
2072 	(void) fprintf(stdout, "GUID:%s\n", prop_attr2->prop);
2073 
2074 	free(prop_attr2);
2075 	return (SUCCESS);
2076 }
2077 
2078 /*
2079  * print_ctl_attr(attrp)
2080  * This function prints attribute of specified controller, and return
2081  * result as SUCCESS or FAILURE.
2082  */
2083 static int
2084 print_ctl_attr(raidcfg_controller_t *attrp)
2085 {
2086 	char type[CONTROLLER_TYPE_LEN];
2087 	char version[CONTROLLER_FW_LEN];
2088 
2089 	if (attrp == NULL) {
2090 		return (FAILURE);
2091 	}
2092 
2093 	(void) snprintf(type, sizeof (type), "%s", attrp->controller_type);
2094 	(void) fprintf(stdout, "%-16s", type);
2095 
2096 	(void) snprintf(version, sizeof (version), "%s", attrp->fw_version);
2097 	(void) fprintf(stdout, "%s", version);
2098 
2099 	return (SUCCESS);
2100 }
2101 
2102 /*
2103  * print_array_attr(attrp)
2104  * This function prints attribute of specified array, and return
2105  * result as SUCCESS or FAILURE.
2106  */
2107 static int
2108 print_array_attr(raidcfg_array_t *attrp)
2109 {
2110 	char capacity[8];
2111 	char stripe_size[8];
2112 	char raid_level[8];
2113 
2114 	if (attrp == NULL) {
2115 		return (FAILURE);
2116 	}
2117 
2118 	if (attrp->capacity != MAX64BIT) {
2119 		if (size_to_string(attrp->capacity, capacity, 8) != SUCCESS) {
2120 			return (FAILURE);
2121 		}
2122 		(void) printf("%s\t", capacity);
2123 	} else {
2124 		(void) printf(gettext("N/A\t"));
2125 	}
2126 
2127 	if (attrp->stripe_size != MAX32BIT) {
2128 		(void) snprintf(stripe_size, sizeof (stripe_size), "%uK",
2129 		    attrp->stripe_size / 1024);
2130 		(void) printf("%s\t", stripe_size);
2131 	} else {
2132 		(void) printf(gettext("N/A\t"));
2133 	}
2134 
2135 	if (attrp->state & ARRAY_STATE_INACTIVATE)
2136 		(void) printf("%-8s", gettext("INACTIVE"));
2137 	else {
2138 		switch (attrp->state) {
2139 		case ARRAY_STATE_OPTIMAL:
2140 			(void) printf("%-8s", gettext("OPTIMAL"));
2141 			break;
2142 		case ARRAY_STATE_DEGRADED:
2143 			(void) printf("%-8s", gettext("DEGRADED"));
2144 			break;
2145 		case ARRAY_STATE_FAILED:
2146 			(void) printf("%-8s", gettext("FAILED"));
2147 			break;
2148 		case ARRAY_STATE_SYNC:
2149 			(void) printf("%-8s", gettext("SYNC"));
2150 			break;
2151 		case ARRAY_STATE_MISSING:
2152 			(void) printf("%-8s", gettext("MISSING"));
2153 			break;
2154 		default:
2155 			(void) printf("%-8s", gettext("N/A"));
2156 			break;
2157 		}
2158 	}
2159 	(void) printf(" ");
2160 
2161 	if (attrp->write_policy == CACHE_WR_OFF) {
2162 		(void) printf(gettext("OFF"));
2163 	} else if (attrp->write_policy == CACHE_WR_ON) {
2164 		(void) printf(gettext("ON"));
2165 	} else {
2166 		(void) printf(gettext("N/A"));
2167 	}
2168 	(void) printf("\t");
2169 
2170 	switch (attrp->raid_level) {
2171 	case RAID_LEVEL_0:
2172 		(void) sprintf(raid_level, "RAID0");
2173 		break;
2174 	case RAID_LEVEL_1:
2175 		(void) sprintf(raid_level, "RAID1");
2176 		break;
2177 	case RAID_LEVEL_1E:
2178 		(void) sprintf(raid_level, "RAID1E");
2179 		break;
2180 	case RAID_LEVEL_5:
2181 		(void) sprintf(raid_level, "RAID5");
2182 		break;
2183 	case RAID_LEVEL_10:
2184 		(void) sprintf(raid_level, "RAID10");
2185 		break;
2186 	case RAID_LEVEL_50:
2187 		(void) sprintf(raid_level, "RAID50");
2188 		break;
2189 	default:
2190 		(void) snprintf(raid_level, sizeof (raid_level),
2191 		    gettext("N/A"));
2192 		break;
2193 	}
2194 	(void) printf("%s", raid_level);
2195 
2196 	return (SUCCESS);
2197 }
2198 
2199 /*
2200  * print_arraypart_attr(attrp)
2201  * This function print attribute of specified arraypart, and return
2202  * result as SUCCESS or FAILURE.
2203  */
2204 static int
2205 print_arraypart_attr(raidcfg_arraypart_t *attrp)
2206 {
2207 	char size[8];
2208 
2209 	if (attrp == NULL) {
2210 		return (FAILURE);
2211 	}
2212 
2213 	if (attrp->size != MAX64BIT) {
2214 		if (size_to_string(attrp->size, size, 8) != SUCCESS) {
2215 			return (FAILURE);
2216 		}
2217 		(void) printf("%s\t", size);
2218 	} else {
2219 		(void) printf(gettext("N/A\t"));
2220 	}
2221 
2222 	(void) printf("\t");
2223 
2224 	if (attrp->state == DISK_STATE_GOOD) {
2225 		(void) printf(gettext("GOOD"));
2226 	} else if (attrp->state == DISK_STATE_FAILED) {
2227 		(void) printf(gettext("FAILED"));
2228 	} else {
2229 		(void) printf(gettext("N/A"));
2230 	}
2231 	(void) printf("\t");
2232 
2233 	return (SUCCESS);
2234 }
2235 
2236 /*
2237  * print_disk_attr(ctl_handle, disk_handle, attrp)
2238  * This function prints attribute of specified disk, and return
2239  * result as SUCCESS or FAILURE.
2240  */
2241 static int
2242 print_disk_attr(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle,
2243 	raidcfg_disk_t *attrp)
2244 {
2245 	char vendor[DISK_VENDER_LEN];
2246 	char product[DISK_PRODUCT_LEN];
2247 	char revision[DISK_REV_LEN + 1];
2248 	char capacity[16];
2249 	char hsp[16];
2250 
2251 	raid_obj_handle_t hsp_handle;
2252 	raidcfg_hsp_t hsp_attr;
2253 	raidcfg_controller_t ctl_attr;
2254 	int ret;
2255 	char is_indent;
2256 
2257 	if (attrp == NULL) {
2258 		return (FAILURE);
2259 	}
2260 
2261 	(void) snprintf(vendor, sizeof (vendor), "%s", attrp->vendorid);
2262 	(void) printf("%s\t", vendor);
2263 
2264 	(void) snprintf(product, sizeof (product), "%s", attrp->productid);
2265 	(void) printf("%s\t", product);
2266 
2267 	(void) snprintf(revision, sizeof (revision), "%s", attrp->revision);
2268 	(void) printf("%s\t\t", revision);
2269 
2270 	if (attrp->capacity != MAX64BIT) {
2271 		if (size_to_string(attrp->capacity, capacity, 16) != SUCCESS) {
2272 			return (FAILURE);
2273 		}
2274 		(void) printf("%s\t\t", capacity);
2275 	} else {
2276 		(void) printf(gettext("N/A"));
2277 	}
2278 
2279 	if (attrp->state == DISK_STATE_GOOD) {
2280 		(void) printf(gettext("GOOD"));
2281 	} else if (attrp->state == DISK_STATE_FAILED) {
2282 		(void) printf(gettext("FAILED"));
2283 	} else {
2284 		(void) printf(gettext("N/A"));
2285 	}
2286 	(void) printf("\t");
2287 
2288 	/* Controller attribute */
2289 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
2290 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2291 		return (FAILURE);
2292 	}
2293 
2294 	hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
2295 	if (hsp_handle == 0) {
2296 		(void) printf(gettext("N/A\n"));
2297 	} else {
2298 		is_indent = FALSE;
2299 		while (hsp_handle > 0) {
2300 			if ((ret = raidcfg_get_attr(hsp_handle,
2301 			    &hsp_attr)) < 0) {
2302 				(void) fprintf(stderr, "%s\n",
2303 				    raidcfg_errstr(ret));
2304 				return (FAILURE);
2305 			}
2306 
2307 			if (is_indent == TRUE) {
2308 				(void) printf("\t\t\t\t\t\t\t");
2309 			} else {
2310 				is_indent = TRUE;
2311 			}
2312 
2313 			if (hsp_attr.type == HSP_TYPE_LOCAL) {
2314 				(void) snprintf(hsp, sizeof (hsp),
2315 				    "c%ut%llud%llu",
2316 				    ctl_attr.controller_id,
2317 				    hsp_attr.tag.idl.target_id,
2318 				    hsp_attr.tag.idl.lun);
2319 				(void) printf("%s\n", hsp);
2320 			} else if (hsp_attr.type == HSP_TYPE_GLOBAL) {
2321 				(void) printf(gettext("Global\n"));
2322 			} else {
2323 				return (FAILURE);
2324 			}
2325 
2326 			hsp_handle = raidcfg_list_next(hsp_handle);
2327 		}
2328 	}
2329 	return (SUCCESS);
2330 }
2331 
2332 
2333 /*
2334  * print_indent(indent)
2335  * This function prints specified number of tab characters. It's used to
2336  * format layout.
2337  */
2338 static void
2339 print_indent(uint8_t indent)
2340 {
2341 	uint32_t i;
2342 	for (i = 0; i < indent; i++) {
2343 		(void) fprintf(stdout, "\t");
2344 	}
2345 }
2346 
2347 /*
2348  * get_disk_handle_cidl(ctl_tag, disks_argp, comps_num, handlespp)
2349  * This function parses the string of disk argument, and gets the disks tag
2350  * and separators from the string. Then it translates the tag to handle, and
2351  * stores handles and separators to new buffer pointed by parameter handlespp.
2352  * The format of disk_arg must be C:ID:L, for example, it is 0.1.0. The first
2353  * "0" is channel number, and the second "1" is target number, and the third
2354  * "0" is LUN number. The disk tags are separated by comma and parenthesis.
2355  * Function returns SUCCESS or FAILURE.
2356  */
2357 static int
2358 get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, int *comps_nump,
2359 	raid_obj_handle_t **handlespp)
2360 {
2361 	int len = 0;
2362 	int i = 0, j = 0;
2363 	char *p, *t;
2364 	char *delimit = " ";
2365 	char *disks_str;
2366 	disk_tag_t disk_tag;
2367 
2368 	if (disks_argp == NULL || comps_nump == NULL) {
2369 		return (FAILURE);
2370 	}
2371 
2372 	p = disks_argp;
2373 	len = strlen(disks_argp);
2374 
2375 	if ((disks_str = (char *)malloc(3 * len + 4)) == NULL) {
2376 		return (FAILURE);
2377 	}
2378 
2379 	/* Insert whitespace between disk tags, '(' , and ')' */
2380 	disks_str[j ++] = '(';
2381 	disks_str[j ++] = ' ';
2382 
2383 	while (p[i] != '\0') {
2384 		if (p[i] == ')' || p[i] == '(') {
2385 			disks_str[j ++] = ' ';
2386 			disks_str[j ++] = p[i];
2387 			disks_str[j ++] = ' ';
2388 		} else
2389 			disks_str[j ++] = p[i];
2390 		i ++;
2391 	}
2392 	disks_str[j ++] = ' ';
2393 	disks_str[j ++] = ')';
2394 	disks_str[j] = '\0';
2395 
2396 	len = strlen(disks_str) + 1;
2397 
2398 	if ((t = (char *)malloc(len)) == NULL) {
2399 		return (FAILURE);
2400 	}
2401 	(void) memcpy(t, disks_str, len);
2402 	p = strtok(t, delimit);
2403 	while (p != NULL) {
2404 		(*comps_nump)++;
2405 		p = strtok(NULL, delimit);
2406 	}
2407 	free(t);
2408 
2409 	*handlespp = calloc(*comps_nump, sizeof (raid_obj_handle_t));
2410 	if (*handlespp == NULL) {
2411 		return (FAILURE);
2412 	}
2413 
2414 	for (i = 0; i < *comps_nump; i++)
2415 		(*handlespp)[i] = INIT_HANDLE_VALUE;
2416 
2417 	i = 0;
2418 	p = strtok(disks_str, delimit);
2419 	while (p != NULL) {
2420 		if (*p == '(') {
2421 			(*handlespp)[i] = OBJ_SEPARATOR_BEGIN;
2422 		} else if (*p == ')') {
2423 			(*handlespp)[i] = OBJ_SEPARATOR_END;
2424 		} else {
2425 			if (get_disk_tag_cidl(p, &disk_tag) != SUCCESS) {
2426 				free(*handlespp);
2427 				free(disks_str);
2428 				return (INVALID_ARG);
2429 			}
2430 			(*handlespp)[i] =
2431 			    raidcfg_get_disk(raidcfg_get_controller(ctl_tag),
2432 			    disk_tag);
2433 			if ((*handlespp)[i] <= 0) {
2434 				(void) fprintf(stderr, "%s\n",
2435 				    raidcfg_errstr((*handlespp)[i]));
2436 				free(*handlespp);
2437 				free(disks_str);
2438 				return (FAILURE);
2439 			}
2440 		}
2441 		p = strtok(NULL, delimit);
2442 		i++;
2443 	}
2444 
2445 	free(disks_str);
2446 	return (SUCCESS);
2447 }
2448 
2449 /*
2450  * get_disk_handle_ctd(disks_num, disks_argpp, ctl_tagp, disks_handlep)
2451  * This function parses string of single disk with "ctd" format, for example,
2452  * c0t0d0, and translates it to controller tag and disk tag.
2453  * Then it calls lib api and get disk handle. The controller tag and disk
2454  * handle are both returned by out parameters.
2455  * The return value is SUCCESS or FAILURE.
2456  */
2457 static int
2458 get_disk_handle_ctd(int disks_num, char **disks_argpp, uint32_t *ctl_tagp,
2459 	raid_obj_handle_t *disks_handlep)
2460 {
2461 	raid_obj_handle_t ctl_handle;
2462 	disk_tag_t disk_tag;
2463 	uint32_t ctl_id;
2464 	int i;
2465 	int ret;
2466 
2467 	if (disks_handlep == NULL) {
2468 		return (FAILURE);
2469 	}
2470 
2471 	for (i = 0; i < disks_num; i++) {
2472 		if (get_disk_tag_ctd(disks_argpp[i], &disk_tag, &ctl_id) !=
2473 		    SUCCESS) {
2474 			return (INVALID_ARG);
2475 		}
2476 
2477 		*ctl_tagp = ctl_id;
2478 
2479 		if (i == 0) {
2480 			ctl_handle = raidcfg_get_controller(*ctl_tagp);
2481 			if (ctl_handle <= 0) {
2482 				(void) fprintf(stderr, "%s\n",
2483 				    raidcfg_errstr(ctl_handle));
2484 				return (FAILURE);
2485 			}
2486 			ret = raidcfg_open_controller(ctl_handle, NULL);
2487 			if (ret < 0) {
2488 				(void) fprintf(stderr, "%s\n",
2489 				    raidcfg_errstr(ret));
2490 				return (FAILURE);
2491 			}
2492 		}
2493 
2494 		if ((disks_handlep[i] =
2495 		    raidcfg_get_disk(ctl_handle, disk_tag)) < 0) {
2496 			(void) fprintf(stderr, "%s\n",
2497 			    raidcfg_errstr(disks_handlep[i]));
2498 			(void) raidcfg_close_controller(ctl_handle, NULL);
2499 			return (FAILURE);
2500 		}
2501 	}
2502 
2503 	return (SUCCESS);
2504 }
2505 
2506 /*
2507  * get_ctl_tag(argp)
2508  * This function translates controller string to tag. The return value is
2509  * SUCCESS if the string has legal format and is parsed successfully,
2510  * or FAILURE if it fails.
2511  */
2512 static int
2513 get_ctl_tag(char *argp, uint32_t *ctl_tagp)
2514 {
2515 	if (argp == NULL || is_fully_numeric(argp) == FALSE ||
2516 	    ctl_tagp == NULL) {
2517 		return (FAILURE);
2518 	}
2519 	*ctl_tagp = (atoi(argp));
2520 	return (SUCCESS);
2521 }
2522 
2523 /*
2524  * get_array_tag(argp, ctl_tagp, array_tagp)
2525  * This function parses array string to get array tag and controller tag.
2526  * The return value is SUCCESS if the string has legal format, or
2527  * FAILURE if it fails.
2528  */
2529 static int
2530 get_array_tag(char *argp, uint32_t *ctl_tagp, array_tag_t *array_tagp)
2531 {
2532 	char *t = NULL;
2533 	char *cp = NULL;
2534 	char *tp = NULL;
2535 	char *dp = NULL;
2536 
2537 	uint32_t value_c = MAX32BIT;
2538 	uint32_t value_t = MAX32BIT;
2539 	uint32_t value_d = MAX32BIT;
2540 
2541 	int len = 0;
2542 
2543 	if (argp == NULL || (len = strlen(argp)) == 0 ||
2544 	    array_tagp == NULL) {
2545 		return (FAILURE);
2546 	}
2547 
2548 	t = (char *)malloc(len + 1);
2549 	if (t == NULL) {
2550 		return (FAILURE);
2551 	}
2552 
2553 	(void) memcpy(t, argp, len + 1);
2554 
2555 	/* Now remmber to release t memory if exception occurs */
2556 	if (((dp = strchr(t, 'd')) == NULL) ||
2557 	    ((tp = strchr(t, 't')) == NULL) ||
2558 	    ((cp = strchr(t, 'c')) == NULL)) {
2559 		free(t);
2560 		return (FAILURE);
2561 	}
2562 	cp = t;
2563 
2564 	*dp = '\0';
2565 	dp++;
2566 	*tp = '\0';
2567 	tp++;
2568 	cp++;
2569 
2570 	if (is_fully_numeric(dp) == FALSE ||
2571 	    is_fully_numeric(tp) == FALSE ||
2572 	    is_fully_numeric(cp) == FALSE) {
2573 		free(t);
2574 		return (FAILURE);
2575 	}
2576 
2577 	value_c = atoi(cp);
2578 	value_t = atoi(tp);
2579 	value_d = atoi(dp);
2580 
2581 	array_tagp->idl.target_id = value_t;
2582 	array_tagp->idl.lun = value_d;
2583 
2584 	if (ctl_tagp != NULL) {
2585 		*ctl_tagp = value_c;
2586 	}
2587 
2588 	free(t);
2589 	return (SUCCESS);
2590 }
2591 
2592 /*
2593  * get_disk_tag_ctd(argp, disk_tagp)
2594  * This function parses disk string of ctd format, and translates it to
2595  * disk tag and controller tag. The tags is returned by out parameters.
2596  * The return value is SUCCESS if the string has legal format, or FAILURE
2597  * if it fails.
2598  */
2599 static int
2600 get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, uint32_t *ctl_tag)
2601 {
2602 	char *t = NULL;
2603 	char *cp = NULL;
2604 	char *tp = NULL;
2605 	char *dp = NULL;
2606 
2607 	uint32_t value_c = MAX32BIT;
2608 	uint32_t value_t = MAX32BIT;
2609 	uint32_t value_d = MAX32BIT;
2610 
2611 	int len = 0;
2612 
2613 	if (argp == NULL || (len = strlen(argp)) == 0 ||
2614 	    disk_tagp == NULL) {
2615 		return (FAILURE);
2616 	}
2617 
2618 	t = (char *)malloc(len + 1);
2619 	if (t == NULL) {
2620 		return (FAILURE);
2621 	}
2622 
2623 	(void) memcpy(t, argp, len + 1);
2624 
2625 	/* Now remmber to release t memory if exception occurs */
2626 	if (((dp = strchr(t, 'd')) == NULL) ||
2627 	    ((tp = strchr(t, 't')) == NULL) ||
2628 	    ((cp = strchr(t, 'c')) == NULL)) {
2629 		free(t);
2630 		return (FAILURE);
2631 	}
2632 	cp = t;
2633 
2634 	*dp = '\0';
2635 	dp++;
2636 	*tp = '\0';
2637 	tp++;
2638 	cp++;
2639 
2640 	if (is_fully_numeric(dp) == FALSE ||
2641 	    is_fully_numeric(tp) == FALSE ||
2642 	    is_fully_numeric(cp) == FALSE) {
2643 		free(t);
2644 		return (FAILURE);
2645 	}
2646 
2647 	value_c = atoi(cp);
2648 	value_t = atoi(tp);
2649 	value_d = atoi(dp);
2650 
2651 	disk_tagp->cidl.bus = 0;
2652 	disk_tagp->cidl.target_id = value_t;
2653 	disk_tagp->cidl.lun = value_d;
2654 	*ctl_tag = value_c;
2655 
2656 	free(t);
2657 	return (SUCCESS);
2658 }
2659 
2660 /*
2661  * get_disk_tag_cidl(argp, disk_tagp)
2662  * This function parses disk string of cidl format and translates it to tag.
2663  * The return value is disk tag if the string has legal format, or FAILURE
2664  * if it fails.
2665  */
2666 static int
2667 get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp)
2668 {
2669 	int len = 0;
2670 	char *p = NULL;
2671 	char *t = NULL;
2672 	char *dot1p = NULL;
2673 	char *dot2p = NULL;
2674 
2675 	if (argp == NULL || (len = strlen(argp)) == 0) {
2676 		return (FAILURE);
2677 	}
2678 
2679 	if (disk_tagp == NULL) {
2680 		return (FAILURE);
2681 	}
2682 
2683 	t = (char *)malloc(len + 1);
2684 	if (t == NULL) {
2685 		return (FAILURE);
2686 	}
2687 
2688 	(void) memcpy(t, argp, len + 1);
2689 	p = t;
2690 
2691 	dot2p = strrchr(p, '.');
2692 	if (dot2p == NULL) {
2693 		free(t);
2694 		return (FAILURE);
2695 	}
2696 	*dot2p = '\0';
2697 	dot2p++;
2698 
2699 	dot1p = strrchr(p, '.');
2700 	if (dot1p == NULL) {
2701 		free(t);
2702 		return (FAILURE);
2703 	}
2704 	*dot1p = '\0';
2705 	dot1p++;
2706 
2707 	/* Assert only 2 dots in this string */
2708 	if (strrchr(p, '.') != NULL) {
2709 		free(t);
2710 		return (FAILURE);
2711 	}
2712 
2713 	while (*p == ' ')
2714 		p++;
2715 
2716 	if (is_fully_numeric(p) == FALSE ||
2717 	    is_fully_numeric(dot1p) == FALSE ||
2718 	    is_fully_numeric(dot2p) == FALSE) {
2719 		free(t);
2720 		return (FAILURE);
2721 	}
2722 
2723 	disk_tagp->cidl.bus = atoi(p);
2724 	disk_tagp->cidl.target_id = atoi(dot1p);
2725 	disk_tagp->cidl.lun = atoi(dot2p);
2726 
2727 	free(t);
2728 	return (SUCCESS);
2729 }
2730 
2731 /*
2732  * calc_size(sizep, valp)
2733  * This function calculates the value represented by string sizep.
2734  * The string sizep can be decomposed into three parts: an initial,
2735  * possibly empty, sequence of white-space characters; a subject digital
2736  * sequence interpreted as an integer with unit k/K/m/M/g/G/t/T; and a
2737  * final string of one or more unrecognized characters or white-sapce
2738  * characters, including the terminating null. If unrecognized character
2739  * exists or overflow happens, the conversion must fail and return
2740  * INVALID_ARG. If the conversion is performed successfully, result will
2741  * be saved into valp and function returns SUCCESS. It returns FAILURE
2742  * when memory allocation fails.
2743  */
2744 static int
2745 calc_size(char *sizep, uint64_t *valp)
2746 {
2747 	int len;
2748 	uint64_t size;
2749 	uint64_t unit;
2750 	char *t = NULL;
2751 	char *tailp = NULL;
2752 
2753 	if (sizep == NULL || valp == NULL) {
2754 		return (INVALID_ARG);
2755 	}
2756 
2757 	if (is_fully_numeric(sizep) == TRUE) {
2758 		*valp = atoi(sizep);
2759 		return (SUCCESS);
2760 	}
2761 
2762 	len = strlen(sizep);
2763 	if (len == 0) {
2764 		return (INVALID_ARG);
2765 	}
2766 
2767 	t = (char *)malloc(len + 1);
2768 	if (t == NULL) {
2769 		return (FAILURE);
2770 	}
2771 
2772 	(void) memcpy(t, sizep, len + 1);
2773 
2774 	switch (*(t + len - 1)) {
2775 	case 'k':
2776 	case 'K':
2777 		unit = 1024ull;
2778 		errno = 0;
2779 		size = strtoll(t, &tailp, 0);
2780 		break;
2781 	case 'm':
2782 	case 'M':
2783 		unit = 1024ull * 1024ull;
2784 		errno = 0;
2785 		size = strtoll(t, &tailp, 0);
2786 		break;
2787 	case 'g':
2788 	case 'G':
2789 		unit = 1024ull * 1024ull * 1024ull;
2790 		errno = 0;
2791 		size = strtoll(t, &tailp, 0);
2792 		break;
2793 	case 't':
2794 	case 'T':
2795 		unit = 1024ull * 1024ull * 1024ull * 1024ull;
2796 		errno = 0;
2797 		size = strtoll(t, &tailp, 0);
2798 		break;
2799 	default:
2800 		/* The unit must be kilobyte at least. */
2801 		free(t);
2802 		return (INVALID_ARG);
2803 	}
2804 
2805 	*(t + len - 1) = '\0';
2806 	if (is_fully_numeric(t) != TRUE) {
2807 		free(t);
2808 		return (INVALID_ARG);
2809 	}
2810 
2811 	errno = 0;
2812 	size = strtoll(t, &tailp, 0);
2813 
2814 	/* Check overflow condition */
2815 	if (errno == ERANGE || (size > (MAX64BIT / unit))) {
2816 		free(t);
2817 		return (INVALID_ARG);
2818 	}
2819 
2820 	*valp = size * unit;
2821 	free(t);
2822 	return (SUCCESS);
2823 }
2824 
2825 /*
2826  * is_fully_numeric(str)
2827  * This function checks if the string are legal numeric string. The beginning
2828  * or ending characters can be white spaces.
2829  * Return value is TRUE if the string are legal numeric string, or FALSE
2830  * otherwise.
2831  */
2832 static int
2833 is_fully_numeric(char *strp)
2834 {
2835 	uint32_t len;
2836 	uint32_t i;
2837 
2838 	if (strp == NULL) {
2839 		return (FALSE);
2840 	}
2841 
2842 	len = strlen(strp);
2843 	if (len == 0) {
2844 		return (FALSE);
2845 	}
2846 
2847 	/* Skip whitespace characters */
2848 	for (i = 0; i < len; i++) {
2849 		if (strp[i] != ' ') {
2850 			break;
2851 		}
2852 	}
2853 
2854 	/* if strp points all space characters */
2855 	if (i == len) {
2856 		return (FALSE);
2857 	}
2858 
2859 	/* Check the digitals in string */
2860 	for (; i < len; i++) {
2861 		if (!isdigit(strp[i])) {
2862 			break;
2863 		}
2864 	}
2865 
2866 	/* Check the ending string */
2867 	for (; i < len; i++) {
2868 		if (strp[i] != ' ') {
2869 			return (FALSE);
2870 		}
2871 	}
2872 
2873 	return (TRUE);
2874 }
2875 
2876 static int
2877 yes(void)
2878 {
2879 	int	i, b;
2880 	char    ans[SCHAR_MAX + 1];
2881 
2882 	for (i = 0; ; i++) {
2883 		b = getchar();
2884 		if (b == '\n' || b == '\0' || b == EOF) {
2885 			ans[i] = 0;
2886 			break;
2887 		}
2888 		if (i < SCHAR_MAX) {
2889 			ans[i] = b;
2890 		}
2891 	}
2892 	if (i >= SCHAR_MAX) {
2893 		i = SCHAR_MAX;
2894 		ans[SCHAR_MAX] = 0;
2895 	}
2896 
2897 	return (rpmatch(ans));
2898 }
2899 
2900 /*
2901  * Function: int rpmatch(char *)
2902  *
2903  * Description:
2904  *
2905  *	Internationalized get yes / no answer.
2906  *
2907  * Inputs:
2908  *	s	-> Pointer to answer to compare against.
2909  *
2910  * Returns:
2911  *	TRUE	-> Answer was affirmative
2912  *	FALSE	-> Answer was negative
2913  */
2914 
2915 static int
2916 rpmatch(char *s)
2917 {
2918 	int	status;
2919 
2920 	/* match yesexpr */
2921 	status = regexec(&re, s, (size_t)0, NULL, 0);
2922 	if (status != 0) {
2923 		return (FALSE);
2924 	}
2925 	return (TRUE);
2926 }
2927 
2928 static int
2929 size_to_string(uint64_t size, char *string, int len)
2930 {
2931 	int i = 0;
2932 	uint32_t remainder;
2933 	char unit[][2] = {" ", "K", "M", "G", "T"};
2934 
2935 	if (string == NULL) {
2936 		return (FAILURE);
2937 	}
2938 	while (size > 1023) {
2939 		remainder = size % 1024;
2940 		size /= 1024;
2941 		i++;
2942 	}
2943 
2944 	if (i > 4) {
2945 		return (FAILURE);
2946 	}
2947 
2948 	remainder /= 103;
2949 	if (remainder == 0) {
2950 		(void) snprintf(string, len, "%llu", size);
2951 	} else {
2952 		(void) snprintf(string, len, "%llu.%1u", size,
2953 		    remainder);
2954 	}
2955 
2956 	/* make sure there is one byte for unit */
2957 	if ((strlen(string) + 1) >=  len) {
2958 		return (FAILURE);
2959 	}
2960 	(void) strcat(string, unit[i]);
2961 
2962 	return (SUCCESS);
2963 }
2964 
2965 /*
2966  * Only one raidctl is running at one time.
2967  */
2968 static int
2969 enter_raidctl_lock(int *fd)
2970 {
2971 	int fd0 = -1;
2972 	struct flock lock;
2973 
2974 	fd0 = open(RAIDCTL_LOCKF, O_CREAT|O_WRONLY, 0600);
2975 	if (fd0 < 0) {
2976 		if (errno == EACCES) {
2977 			(void) fprintf(stderr,
2978 			    gettext("raidctl:must be root to run raidctl"
2979 			    ": %s\n"), strerror(errno));
2980 		} else {
2981 			(void) fprintf(stderr,
2982 			    gettext("raidctl:failed to open lockfile"
2983 			    " '"RAIDCTL_LOCKF"': %s\n"), strerror(errno));
2984 		}
2985 		return (FAILURE);
2986 	}
2987 
2988 	*fd = fd0;
2989 	lock.l_type = F_WRLCK;
2990 	lock.l_whence = SEEK_SET;
2991 	lock.l_start = 0;
2992 	lock.l_len = 0;
2993 
2994 	if ((fcntl(fd0, F_SETLK, &lock) == -1) &&
2995 	    (errno == EAGAIN || errno == EDEADLK)) {
2996 		if (fcntl(fd0, F_GETLK, &lock) == -1) {
2997 			(void) fprintf(stderr,
2998 			    gettext("raidctl:enter_filelock error\n"));
2999 			return (FAILURE);
3000 		}
3001 		(void) fprintf(stderr, gettext("raidctl:"
3002 		    "enter_filelock:filelock is owned "
3003 		    "by 'process %d'\n"), lock.l_pid);
3004 		return (FAILURE);
3005 	}
3006 
3007 	return (SUCCESS);
3008 }
3009 
3010 static void
3011 exit_raidctl_lock(int fd)
3012 {
3013 	struct flock lock;
3014 
3015 	lock.l_type = F_UNLCK;
3016 	lock.l_whence = SEEK_SET;
3017 	lock.l_start = 0;
3018 	lock.l_len = 0;
3019 	if (fcntl(fd, F_SETLK, &lock) == -1) {
3020 		(void) fprintf(stderr, gettext("raidctl: failed to"
3021 		    " exit_filelock: %s\n"),
3022 		    strerror(errno));
3023 	}
3024 	(void) close(fd);
3025 }
3026