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